Files
BlockSeasons/docs/superpowers/specs/2026-06-18-boosters-daily-reward-design.md
T
airkjw 9f1e0d2cd5 docs(spec): boosters & daily reward design
Brainstormed design for a lightweight booster economy (hammer/shuffle/
line-bomb) earned via a 7-day login calendar and rewarded ads, used in
a stage via a booster bar. Boosters mutate the grid only — no move cost,
no score/combo, no objective credit — so stage balance is preserved
while they can rescue a dead board. Approved by owner; next: impl plan.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 11:50:54 +09:00

7.4 KiB
Raw Blame History

부스터 & 데일리 보상 — 설계 (Boosters & Daily Reward)

작성일: 2026-06-18 · 상태: 승인됨(오너) → 구현 계획 단계로

목표 / 맥락

광고 수익형 퍼즐게임 Block Seasons의 리텐션(복귀) + 광고 노출을 동시에 키우는 키스톤 기능. 현재 게임엔 플레이어에게 줄 "보상 대상"이 없어 데일리 보상·보상형 광고를 붙일 곳이 없었음 → 가벼운 부스터(파워업) 경제를 도입해 둘 다 해금한다.

사업자등록이 없어 IAP는 막혀 있으므로 재화/상점 없이 부스터를 직접 주고받는다.

확정된 결정 (브레인스토밍)

  1. 부스터 3종: 🔨해머 / 🔀셔플 / 💥줄폭탄
  2. 획득: 재화 없음 — 데일리 보상 + 보상형 광고로 부스터를 직접 받아 비축
  3. 데일리: 7일 출석 캘린더 (점증, Day7 잭팟) + "광고 보고 2배"
  4. 사용: 게임 중 부스터 바 → 대상 지정

부스터 규칙 (밸런스, 오너 승인)

  • 이동 수 미소모 — 부스터는 보조라 무브 카운터를 깎지 않는다.
  • 점수·콤보 미부여, 목표 미반영 — 그리드만 직접 바꾸고 점수/목표 이벤트 파이프라인을 타지 않는다. 줄폭탄으로 "줄 N개" 목표를 깨거나 해머로 보석을 제거해 "보석 N개" 목표를 달성할 수 없다(스테이지 난이도 보존). 콤보 상태도 건드리지 않는다(전진·리셋 둘 다 없음).
  • 막힌 보드 되살리기 허용 — 부스터 사용 후 phase를 재평가(_checkStuck)해, 죽은 판 (boardDead)을 다시 playing으로 되돌릴 수 있다 → 보상형 '컨티뉴'의 대안.
  • 사용 가능 시점 — phase가 playing 또는 stuck일 때만. won/lost 후엔 불가.
  • 사용 한도 — 별도 횟수 제한 없음. 보유량이 곧 한도(가진 만큼만 사용).
  • 엔드리스 모드 포함 — 엔드리스에서도 사용 가능.

부스터별 동작

부스터 동작 대상
🔨 해머 채워진 칸 1개를 비움 칸 1개 탭
🔀 셔플 현재 트레이(3조각)를 새로 교체 즉시(대상 없음)
💥 줄폭탄 가로 또는 세로 한 줄 전체를 비움 줄(행/열) 선택

아키텍처 (기존 레이어 준수: ui → state → game|data|services)

1) 엔진 (순수 Dart, lib/game/engine/game_engine.dart)

세 메서드 추가. 성공 시 true, 잘못된 대상/시점이면 false(보유량 차감 안 하도록).

bool useHammer(int x, int y)         // (x,y)가 채워진 칸이면 비움
bool useShuffle()                    // 트레이 재추첨
bool useLineBomb({int? row, int? col}) // row 또는 col 중 하나의 줄을 비움

공통: 이동/점수/콤보/목표 불변, 마지막에 _checkStuck() 호출. playing/stuck에서만 허용. 줄폭탄은 rowcol 중 정확히 하나만 지정(둘 다/둘 다 없음이면 false).

2) 모델 (순수 Dart, lib/game/models/booster.dart)

enum BoosterType { hammer, shuffle, lineBomb }

3) 저장 (lib/data/save_repository.dart, JSON blob 확장)

  • 보유량: int boosterCount(BoosterType), Future<void> grantBooster(BoosterType, [int n = 1]), Future<bool> consumeBooster(BoosterType)(0이면 false).
  • 데일리: String? dailyLastClaimedYmd, int dailyCalendarDay(1~7), Future<void> recordDailyClaim(String ymd, int day).
  • JSON에 boosters: {hammer, shuffle, lineBomb}daily: {lastYmd, day} 추가 (기존 streak의 ymd 유틸 재사용).

4) 상태 (Riverpod, lib/state/)

  • BoosterInventoryNotifier — 보유량 노출 + grant/consume.
  • DailyRewardNotifier — 오늘 받을 수 있는지 + 캘린더 day 계산 + claim.
  • GameSessionNotifier에 사용 메서드 추가: useHammer(x,y) / useShuffle() / useLineBomb(...). 흐름: 엔진 먼저 호출 → 성공 시에만 인벤토리 차감 → 뷰 갱신. 보유 0이면 호출하지 않음(UI가 광고 제안).
  • GameViewState에 grid가 이미 있어 부스터 후 UI 재렌더 가능.

5) 데일리 캘린더 로직 (순수, 테스트 가능)

  • 오늘 ymd 계산. lastClaimedYmd == 오늘 → 이미 받음(비활성).
  • 받을 수 있는 경우의 day:
    • lastClaimedYmd == 어제day = (이전 day % 7) + 1(연속, 7→1 순환).
    • 그 외(하루 이상 빠짐/최초) → day = 1(리셋).
  • claim 시 해당 day 보상 지급 + lastClaimedYmd = 오늘, calendarDay = day 저장.
  • 보상표(제안, 튜닝 가능):
    Day 보상
    1 🔨×1
    2 🔀×1
    3 💥×1
    4 🔨×1 🔀×1
    5 🔀×1 💥×1
    6 🔨×1 💥×1
    7 🔨×2 🔀×2 💥×2 (잭팟)
  • 시작 보유량: 각 1개(최초 1회).

6) UI (lib/ui/)

  • 부스터 바 위젯 — 보드 아래 3버튼(아이콘+개수). 탭 시 타겟팅 모드 진입.
    • 해머: 채워진 칸 탭 → 제거.
    • 줄폭탄: 보드 가장자리에 행/열 핸들 표시 → 핸들 탭으로 줄 선택(가장 명확한 UX, 구현 중 세부 조정 가능).
    • 셔플: 즉시 적용.
    • 개수 0인 버튼 탭 → "광고 보고 1개 받기" 다이얼로그.
  • 데일리 팝업 — 홈 화면 진입 시 받을 수 있으면 표시. 7칸(과거=체크/딤, 오늘=하이라이트, 미래=잠금) + [받기] + [광고 보고 2배].

7) 광고 (lib/services/ad_service.dart 재사용)

  • 부스터 0개 → 보상형 광고 → 성공 시 해당 부스터 +1.
  • 데일리 2배 → 보상형 광고 → 성공 시 보상 2배 지급.
  • showRewarded()는 광고 미로드 시에도 true(기존 플레이어 친화 폴백) → 부스터는 지급됨.

8) 분석 (lib/services/analytics_service.dart)

  • booster_used {type}
  • booster_granted {type, count, source: start|daily|ad}
  • daily_reward_claimed {day, doubled}

9) l10n (lib/l10n/)

  • 부스터 이름·설명, 데일리 보상 UI, "광고 보고 받기/2배" CTA — EN/KO.

테스트 전략 (TDD)

  • 엔진: 해머(칸 제거·이동/점수/목표 불변·빈 칸이면 false·죽은 판 되살림), 셔플(새 트레이·불변·재stuck), 줄폭탄(행/열 제거·불변·재stuck·row^col 검증), won/lost 후 사용 차단.
  • 저장: grant/consume/영속, 0에서 consume=false, 데일리 ymd/day 영속.
  • 데일리 로직: 연속 시 day+1, 빠짐 시 리셋, 같은 날 재수령 불가, 보상표 지급, 2배.
  • 세션 노티파이어: 성공 시 차감, 잘못된 대상/0개면 미차감.
  • 위젯: 부스터 바 개수 렌더·타겟팅, 데일리 팝업 상태.

구현 단계 (계획에서 상세화)

  1. 엔진 부스터 3종 (TDD, 순수)
  2. BoosterType + SaveRepository 인벤토리 (TDD)
  3. 인벤토리/세션 노티파이어 + 사용 흐름 (TDD)
  4. 부스터 바 UI + 타겟팅 (위젯 테스트)
  5. 데일리 캘린더 로직 + 노티파이어 (TDD)
  6. 데일리 팝업 UI
  7. 보상형 광고 지급(0-상태 + 데일리 2배)
  8. 분석 + l10n
  9. 통합 + 전체 테스트 그린

비목표 (YAGNI)

  • 코인/재화/상점, 부스터 회전·되돌리기, IAP 부스터 판매, 부스터 합성/업그레이드.

리스크 / 메모

  • 부스터가 점수·목표에 반영되지 않으므로 기존 스테이지 밸런스는 그대로 유효.
  • 보상형 광고 미로드 시에도 부스터를 지급(폴백) → 신규 앱 no-fill 기간에도 게임 흐름 유지.
  • 새 빌드 필요(부스터·데일리는 다음 릴리스부터). 빌드는 오너 명령 시에만.