Docs: Consolidate prompts 61-76 into summary and update context

This commit is contained in:
Horoli 2025-12-07 22:06:51 +09:00
parent 59ebb7cd98
commit 135bf26332
20 changed files with 155 additions and 490 deletions

View File

@ -36,7 +36,7 @@ class LootGenerator {
if (selectedModifier != null) {
if (selectedModifier.prefix.isNotEmpty) {
finalName = "${selectedModifier.prefix} $template.name";
finalName = "${selectedModifier.prefix} ${template.name}";
}
double mult = selectedModifier.multiplier;
@ -49,10 +49,12 @@ class LootGenerator {
}
// 1. Magic Rarity: 50% chance to get a Magic Prefix (1 stat change)
else if (template.rarity == ItemRarity.magic) {
if (_random.nextDouble() < ItemConfig.magicPrefixChance) { // Use constant
if (_random.nextDouble() < ItemConfig.magicPrefixChance) {
// Use constant
// Filter valid prefixes for this slot
final validPrefixes = ItemPrefixTable.magicPrefixes.where((p) {
return p.allowedSlots == null || p.allowedSlots!.contains(template.slot);
return p.allowedSlots == null ||
p.allowedSlots!.contains(template.slot);
}).toList();
if (validPrefixes.isNotEmpty) {
@ -61,10 +63,18 @@ class LootGenerator {
modifier.statChanges.forEach((stat, value) {
switch (stat) {
case StatType.atk: finalAtk += value; break;
case StatType.maxHp: finalHp += value; break;
case StatType.defense: finalArmor += value; break;
case StatType.luck: finalLuck += value; break;
case StatType.atk:
finalAtk += value;
break;
case StatType.maxHp:
finalHp += value;
break;
case StatType.defense:
finalArmor += value;
break;
case StatType.luck:
finalLuck += value;
break;
}
});
}
@ -80,7 +90,8 @@ class LootGenerator {
// Filter valid prefixes for this slot
final validPrefixes = ItemPrefixTable.rarePrefixes.where((p) {
return p.allowedSlots == null || p.allowedSlots!.contains(template.slot);
return p.allowedSlots == null ||
p.allowedSlots!.contains(template.slot);
}).toList();
if (validPrefixes.isNotEmpty) {
@ -94,10 +105,18 @@ class LootGenerator {
modifier.statChanges.forEach((stat, value) {
switch (stat) {
case StatType.atk: finalAtk += value; break;
case StatType.maxHp: finalHp += value; break;
case StatType.defense: finalArmor += value; break;
case StatType.luck: finalLuck += value; break;
case StatType.atk:
finalAtk += value;
break;
case StatType.maxHp:
finalHp += value;
break;
case StatType.defense:
finalArmor += value;
break;
case StatType.luck:
finalLuck += value;
break;
}
});
}

View File

@ -48,9 +48,7 @@ class Character {
'baseDefense': baseDefense,
'gold': gold,
'image': image,
'equipment': equipment.map(
(key, value) => MapEntry(key.name, value.id),
),
'equipment': equipment.map((key, value) => MapEntry(key.name, value.id)),
'inventory': inventory.map((e) => e.id).toList(),
'statusEffects': statusEffects.map((e) => e.toJson()).toList(),
'permanentModifiers': permanentModifiers.map((e) => e.toJson()).toList(),

View File

@ -370,13 +370,11 @@ class BattleProvider with ChangeNotifier {
}
// Now check for enemy death (if applicable from bleed, or previous impacts)
if (enemy.isDead) {
// Check enemy death after player's action
_onVictory();
return;
}
// Removed redundant `if (enemy.isDead)` check as it's handled in `_processAttackImpact`
_endPlayerTurn();
}
void _endPlayerTurn() {
@ -630,6 +628,7 @@ class BattleProvider with ChangeNotifier {
stage++;
showRewardPopup = false;
rewardOptions.clear(); // Clear options to prevent flash on next victory
_prepareNextStage();

View File

@ -7,161 +7,84 @@
- **프로젝트명:** Colosseum's Choice
- **플랫폼:** Flutter (Android/iOS/Web/Desktop)
- **장르:** 텍스트 기반의 턴제 RPG + GUI (로그라이크 요소 포함)
- **상태:** 프로토타입 단계 (전투 시각화, 데이터 주도 시스템, 반응형 UI 구현 완료)
- **상태:** 핵심 시스템 구현 완료 및 안정화 (i18n 구조 적용, 애니메이션 동기화 완료)
## 2. 현재 구현된 핵심 기능 (Feature Status)
### A. 게임 흐름 (Game Flow)
1. **메인 메뉴 (`MainMenuScreen`):** 게임 시작 버튼.
2. **캐릭터 선택 (`CharacterSelectionScreen`):** 'Warrior' 직업 구현.
3. **메인 게임 (`MainWrapper`):** 하단 탭 네비게이션 (Battle / Inventory).
4. **반응형 레이아웃 (Responsive UI):**
- `ResponsiveContainer` 위젯을 통해 최대 너비(600px) 및 높이(1000px) 제한.
- 웹/태블릿 환경에서도 모바일 앱처럼 중앙 정렬된 화면 제공.
- **Battle UI Layout:** 플레이어(좌측 하단) vs 적(우측 상단) 대각선 구도 배치 및 캐릭터 임시 아이콘 적용.
- **Widget Refactoring:** `BattleScreen`의 주요 UI 컴포넌트(`CharacterStatusCard`, `BattleLogOverlay` 등)를 `lib/widgets/battle/`로 분리하여 모듈화.
1. **메인 메뉴 (`MainMenuScreen`):** 게임 시작, 이어하기(저장된 데이터 있을 시), 설정 버튼.
2. **캐릭터 선택 (`CharacterSelectionScreen`):** 'Warrior' 직업 구현 (스탯 확인 후 시작).
3. **메인 게임 (`MainWrapper`):** 하단 탭 네비게이션 (Battle / Inventory / Settings).
4. **설정 (`SettingsScreen`):**
- 적 애니메이션 활성화/비활성화 토글 (`SettingsProvider` 연동).
- 게임 재시작, 메인 메뉴로 돌아가기 기능.
5. **반응형 레이아웃 (Responsive UI):**
- `ResponsiveContainer`를 통해 다양한 화면 크기 대응 (최대 너비/높이 제한).
- Battle UI: 플레이어(좌하단) vs 적(우상단) 대각선 구도.
### B. 전투 시스템 (`BattleProvider`)
- **턴제 전투:** 플레이어 턴 -> 적 턴.
- **행동 선택:** 공격(Attack) / 방어(Defend).
- **리스크 시스템 (Risk System):** Safe(100%/50%), Normal(80%/100%), Risky(40%/200%) 선택.
- **리스크 시스템 (Risk System):**
- **Safe:** 성공률 100%+, 효율 50%.
- **Normal:** 성공률 80%+, 효율 100%.
- **Risky:** 성공률 40%+, 효율 200% (성공 시 강력한 이펙트).
- **Luck 보정:** `totalLuck` 1당 성공률 +1%.
- **적 인공지능 (Enemy AI & Intent):**
- **Intent UI:** 적의 다음 행동(공격/방어, 리스크)을 미리 표시.
- **선제 방어 (Pre-emptive Defense):** 적이 방어를 선택하면 턴 시작 전에 즉시 방어도가 적용됨.
- **Defense Restriction:** `DefenseForbidden` 상태 시 방어 행동 선택 불가.
- **Variance Removed:** 적의 공격/방어 수치 계산 시 랜덤 분산(Variance) 제거 (고정 수치).
- **적 장비 시스템 (Enemy Equipment):**
- 적에게 아이템 장착 가능 (`enemies.json`의 `equipment` 필드).
- 장착된 아이템의 스탯 및 특수 효과(상태이상 등)가 전투 시 적용됨.
- **시각 효과 (Visual Effects):**
- **Floating Text:** 데미지 발생 시 캐릭터 위에 데미지 수치가 떠오름 (일반: 빨강, 출혈: 보라, 취약: 주황).
- **Action Feedback:** 공격 빗나감(MISS - 적 위치/회색) 및 방어 실패(FAILED - 내 위치/빨강) 텍스트 오버레이.
- **Effect Icons:** 공격/방어 및 리스크 레벨에 따른 아이콘 애니메이션 출력.
- **Advanced Animations:**
- **Risk-Based:** Safe(Wobble), Normal(Dash), Risky(Scale Up + Heavy Dash + Shake + Explosion).
- **Icon-Only:** 공격 시 캐릭터 아이콘만 이동하며, 스탯 정보(HP/Armor)는 일시적으로 숨김 처리.
- **Impact Sync:** 타격 이펙트와 데미지 텍스트가 애니메이션 타격 시점에 정확히 동기화됨.
- **Intent UI:** 적의 다음 행동(공격/방어, 데미지/방어도) 미리 표시.
- **동기화된 애니메이션:** 적 행동 결정(`_generateEnemyIntent`)은 이전 애니메이션이 완전히 끝난 후 이루어짐.
- **선제 방어:** 적이 방어 행동을 선택하면 턴 시작 시 즉시 방어도가 적용됨.
- **애니메이션 및 타격감 (Visuals & Impact):**
- **UI 주도 Impact 처리:** 애니메이션 타격 시점(`onImpact`)에 정확히 데미지가 적용되고 텍스트가 뜸 (완벽한 동기화).
- **적 돌진:** 적도 공격 시 플레이어 위치로 돌진함 (설정에서 끄기 가능).
- **이펙트:** 타격 아이콘, 데미지 텍스트(Floating Text), 화면 흔들림(`ShakeWidget`), 폭발(`ExplosionWidget`).
- **상태이상:** `Stun`, `Bleed`, `Vulnerable`, `DefenseForbidden`.
- **행운 시스템 (Luck System):**
- 아이템 옵션으로 `luck` 스탯 제공.
- `totalLuck` 수치만큼 행동(공격/방어) 성공 확률 증가 (1 Luck = +1%).
- 성공 확률은 최대 100%로 제한됨.
- **UI:** 인벤토리에서 Luck 수치 확인 가능, 전투 시 Risk 선택 창에서 보정된 확률 표시.
### C. 데이터 주도 설계 (Data-Driven Design)
### C. 데이터 및 로직 (Architecture)
- **JSON 데이터:** `assets/data/items.json` (ID 포함), `assets/data/enemies.json` (장비 포함).
- **데이터 로더:** `ItemTable` (ID 조회 지원), `EnemyTable` (장비 장착 지원).
- **Data-Driven:** `items.json`, `enemies.json`, `players.json`.
- **Logic 분리:**
- `BattleProvider`: UI 상태 관리 및 이벤트 스트림(`damageStream`, `effectStream`) 발송.
- `CombatCalculator`: 데미지 공식, 확률 계산, 상태이상 로직 순수 함수화.
- `BattleLogManager`: 전투 로그 관리.
- `LootGenerator`: 아이템 생성, 접두사(Prefix) 부여, 랜덤 스탯 로직.
- `SettingsProvider`: 전역 설정(애니메이션 on/off 등) 관리 및 영구 저장.
- **Soft i18n:** UI 텍스트는 `lib/game/config/app_strings.dart`에서 통합 관리.
- **Config:** `GameConfig`, `BattleConfig`, `ItemConfig` 등 설정 값 중앙화.
### D. 아이템 및 경제 (`Item`, `Inventory`)
### D. 아이템 및 경제
- **장비:** 무기, 방어구, 방패, 장신구.
- **아이콘 및 색상 (`ItemUtils`):**
- 무기: 빨강 삼각형 (`Icons.change_history`)
- 방패: 파랑 방패 (`Icons.shield`)
- 갑옷: 파랑 옷 (`Icons.checkroom`)
- 장신구: 보라 다이아몬드 (`Icons.diamond`)
- **가격:** JSON 고정 가격 사용. 판매 시 60% (`GameMath.floor`) 획득.
- **인벤토리:** 장착 슬롯 및 가방(Bag) 그리드 UI 구현.
- **아이템 시스템 (Item System):**
- **Rarity (희귀도):** Common, Rare, Epic, Legendary. (드랍 확률 관여)
- **Tier (티어):** 1티어(초반), 2티어(중반), 3티어(후반). (라운드 진행도에 따라 등장 제한)
- **획득 로직:** 현재 라운드(Tier)에 맞는 아이템 풀 내에서 Rarity 확률에 따라 결정.
- **시스템:**
- **Rarity:** Common ~ Unique.
- **Tier:** 라운드 진행도에 따라 상위 티어 아이템 등장.
- **Prefix:** Rarity에 따라 접두사가 붙으며 스탯이 변형됨 (예: "Sharp Wooden Sword").
- **상점 (`ShopProvider`):** 아이템 구매/판매, 리롤(Reroll), 인벤토리 관리.
### E. 스테이지 시스템 (`StageModel`)
### E. 저장 및 진행 (Persistence)
- **타입:** Battle, Shop, Rest, Elite.
- **적 등장 테이블 (Enemy Pool):** 적 조우 시, 현재 스테이지(라운드)에 따라 등장 가능한 적 목록(`enemy_table_pool`)을 설정하여 해당 범위 내에서 적을 랜덤 생성해야 함.
- **게임 구조 (Game Structure):**
- **총 3라운드 (3 Rounds):** 각 라운드는 12개의 스테이지로 구성 (12/12/12).
- **라운드 구성:**
1. **1라운드:** 지하 불법 투기장 (Underground Illegal Arena)
2. **2라운드:** 콜로세움 (Colosseum)
3. **3라운드:** 왕의 투기장 (King's Arena) - 최종 보스(Final Boss) 등장.
- **자동 저장:** 스테이지 클리어 시 `SaveManager`를 통해 자동 저장.
- **Permadeath:** 패배 시 저장 데이터 삭제 (로그라이크 요소).
### F. 시스템 및 설정 (System & Settings)
## 3. 작업 컨벤션 (Working Conventions)
- **설정 페이지 (Settings Screen):**
- 게임 재시작 (Restart Game) 및 메인 메뉴로 돌아가기 (Return to Main Menu) 기능.
- 하단 네비게이션 바(BottomNavigationBar)에 설정 탭 추가.
- **로컬 저장 (Local Storage):**
- `shared_preferences`를 사용하여 스테이지 클리어 시 자동 저장.
- 메인 메뉴에서 '이어하기 (CONTINUE)' 버튼을 통해 저장된 시점부터 게임 재개 가능.
- 저장 데이터: 스테이지 진행도, 턴 수, 플레이어 상태(체력, 장비, 인벤토리 등).
## 3. 핵심 파일 및 아키텍처
- **`lib/providers/battle_provider.dart`:**
- **Core Logic:** 상태 관리, 전투 루프.
- **Streams:** `damageStream`, `effectStream`을 통해 UI(`BattleScreen`)에 비동기 이벤트 전달.
- **`lib/game/enums.dart`:** 프로젝트 전반의 Enum 통합 관리 (`ActionType`, `RiskLevel`, `StageType` 등).
- **`lib/utils/item_utils.dart`:** 아이템 타입별 아이콘 및 색상 로직 중앙화.
- **`lib/widgets/battle/`:** `BattleScreen`에서 분리된 재사용 가능한 위젯들.
- **UI Components:** `CharacterStatusCard`, `BattleLogOverlay`, `FloatingBattleTexts`, `StageUI`.
- **Effects:** `BattleAnimationWidget` (공격 애니메이션), `ExplosionWidget` (파티클), `ShakeWidget` (화면 흔들림).
- **`lib/widgets/responsive_container.dart`:** 반응형 레이아웃 컨테이너.
- **`lib/game/model/`:**
- `damage_event.dart`, `effect_event.dart`: 이벤트 모델.
- `entity.dart`: `Character` (Player/Enemy).
- `item.dart`: `Item` (ID 필드 포함).
- **`lib/screens/battle_screen.dart`:**
- `StreamSubscription`을 통해 이펙트 이벤트 수신 및 `Overlay` 애니메이션 렌더링.
- `Stack``Positioned` 기반의 정교한 레이아웃.
## 4. 작업 컨벤션 (Working Conventions)
- **Prompt Driven Development:** `prompt/XX_description.md` 유지.
- **유사 작업 통합:** 작업 내용이 이전 프롬프트와 유사한 경우 새로운 프롬프트를 생성하지 않고 기존 프롬프트에 내용을 추가합니다.
- **Language:** **모든 프롬프트 파일(prompt/XX\_...)은 반드시 한국어(Korean)로 작성해야 합니다.**
- **Config Management:** 하드코딩되는 값들은 `config` 폴더 내 파일들(`lib/game/config/` 등)에서 통합 관리할 수 있도록 작성해야 합니다.
- **Prompt Driven Development:** `prompt/XX_description.md` 유지. (유사 작업 통합 및 인덱스 정리 권장)
- **i18n Strategy (Soft i18n):** UI에 표시되는 문자열은 하드코딩하지 않고 `lib/game/config/app_strings.dart`의 상수를 사용해야 합니다. (전투 로그 등 동적 문자열 제외)
- **State Management:** `Provider` + `Stream` (이벤트성 데이터).- **Data:** JSON 기반.
- **Config Management:** 하드코딩되는 값들은 `config` 폴더 내 파일들(`lib/game/config/` 등)에서 통합 관리할 수 있도록 작성해야 합니다.
- **State Management:** `Provider` (UI 상태) + `Stream` (이벤트성 데이터).
- **Data:** JSON 기반 + `Table` 클래스로 로드.
## 5. 다음 단계 작업 (Next Steps)
## 4. 최근 주요 변경 사항 (Change Log)
1. **아이템 시스템 고도화:** `items.json``rarity`, `tier` 필드 추가 및 `ItemTable` 로직 수정.
2. **[x] 상점 구매 기능:** `Shop` 스테이지 구매 UI 구현 (Tier/Rarity 기반 목록 생성).
3. **적 등장 테이블 구현:** 스테이지별 등장 가능한 적 목록(`enemy_table_pool`) 설정 및 적용.
4. **이미지 리소스 적용:** JSON 경로에 맞는 실제 이미지 파일 추가 및 UI 표시.
5. **밸런싱 및 콘텐츠 확장:** 아이템/적 데이터 추가 및 밸런스 조정.
- **[Refactor] BattleProvider:** `CombatCalculator`, `BattleLogManager`, `LootGenerator` 분리로 코드 다이어트.
- **[Refactor] Animation Sync:** `Future.delayed` 예측 방식을 버리고, UI 애니메이션 콜백(`onImpact`)을 통해 로직을 트리거하는 방식으로 변경하여 타격감 동기화 해결.
- **[Refactor] Settings:** `SettingsProvider` 도입 및 적 애니메이션 토글 기능 추가.
- **[Fix] Bugs:** 아이템 이름 생성 오류 수정, 리워드 팝업 깜빡임 및 중복 생성 수정, 앱 크래시(Null Safety) 수정.
## 6. 장기 목표 (Future Roadmap / TODO)
## 5. 다음 단계 (Next Steps)
- [ ] **출혈 상태 이상 조건 변경:** 공격 시 상대방의 방어도에 의해 공격이 완전히 막힐 경우, 출혈 상태 이상이 적용되지 않도록 로직 변경.
- [ ] **장비 분해 시스템 (적 장비):** 플레이어 장비의 옵션으로 상대방의 장비를 분해하여 '언암드' 상태로 만들 수 있는 시스템 구현.
- [ ] **플레이어 공격 데미지 분산(Variance) 적용 여부 검토:** 현재 적에게만 적용된 +/- 20% 데미지 분산을 플레이어에게도 적용할지 결정.
- [x] **애니메이션 및 타격감 고도화:**
- 캐릭터별 이미지 추가 및 하스스톤 스타일의 공격 모션(대상에게 돌진 후 타격) 구현 완료 (Icon-Only Animation).
- **Risky 공격:** 하스스톤의 7데미지 이상 타격감(화면 흔들림, 강렬한 파티클 및 임팩트) 구현 완료.
- [ ] **체력 조건부 특수 능력:** 캐릭터의 체력이 30% 미만일 때 발동 가능한 특수 능력 시스템 구현.
- [ ] **영구 스탯 수정자 로직 적용 (필수):**
- 현재 `Character` 클래스에 `permanentModifiers` 필드만 선언되어 있음.
- 추후 `totalAtk`, `totalDefense`, `totalMaxHp` 계산 시 이 수정자들을 반드시 반영해야 함.
- [ ] **Google OAuth 로그인 및 계정 연동:**
- Firebase Auth 등을 활용한 구글 로그인 구현.
- Firestore 또는 Realtime Database에 유저 계정 정보(진행 상황, 재화 등) 저장 및 불러오기 기능 추가.
- _Note: 이 기능은 게임의 핵심 로직이 안정화된 후, 완전 나중에 진행할 예정입니다._
- [ ] **설정 페이지 (Settings Page) 구현 (Priority: Very Low):**
- **이펙트 강도 조절 (Effect Intensity):** 1 ~ 999 범위로 설정 가능.
- **Easter Egg:** 강도를 999로 설정하고 Risky 공격 성공 시, "심각한 오류로 프로세스가 종료되었습니다" 같은 페이크 시스템 팝업 출력.
---
**이 프롬프트를 읽은 AI 에이전트는 위 내용을 바탕으로 즉시 개발을 이어가십시오.**
## 7. 프롬프트 히스토리 (Prompt History)
- [x] 45_config_refactoring.md
- [x] 46_shop_refactoring.md
- [x] 47_inventory_full_handling.md
- [x] 48_refactor_stage_ui.md
- [x] 49_implement_item_icons.md
- [x] 50_expand_item_pool.md
- [x] 51_refactor_prefix_table.md
- [x] 52_round_based_enemy_pool.md
- [x] 53_refine_stage_rewards.md
- [x] 54_fix_shop_logic.md
- [x] 55_fix_shop_ui_sync.md
- [x] 56_permadeath_implementation.md
1. **밸런싱:** 현재 몬스터 및 아이템 스탯 미세 조정.
2. **콘텐츠 확장:** 더 많은 아이템, 적, 스킬 패턴 추가.
3. **튜토리얼:** 신규 유저를 위한 가이드 추가.

View File

@ -1,16 +0,0 @@
# 60. Introduce AppStrings for Soft i18n
## 1. 목표 (Goal)
- UI 텍스트 하드코딩을 방지하고 추후 본격적인 i18n 적용을 대비하기 위해 `AppStrings` 상수 클래스를 도입합니다.
- 자주 사용되는 UI 텍스트(메뉴, 스탯, 행동 등)를 한 곳에서 관리합니다.
## 2. 구현 계획 (Implementation Plan)
1. **`lib/game/config/app_strings.dart` 생성:**
- `actionAttack`, `actionDefend`, `statHp`, `statAtk` 등 카테고리별로 정적 상수를 정의합니다.
2. **UI 코드 수정:**
- `BattleScreen`, `InventoryScreen`, `MainMenuScreen` 등에서 하드코딩된 문자열을 `AppStrings.xxx`로 교체합니다.
- *Note:* 전투 로그와 같이 동적으로 생성되는 복잡한 문장은 이번 단계에서 제외합니다.
## 3. 기대 효과 (Expected Outcome)
- 텍스트 변경 시 `AppStrings`만 수정하면 되므로 유지보수성 향상.
- 추후 다국어 지원 라이브러리 도입 시 마이그레이션이 매우 쉬워짐.

View File

@ -0,0 +1,27 @@
# 61. System Stabilization & Refactoring (Summary)
## 1. 개요
이 문서는 프로젝트 안정화 및 리팩토링 과정에서 진행된 61번부터 76번까지의 작업 내용을 요약 및 통합한 것입니다.
## 2. 주요 변경 사항
### A. 구조 개선 및 리팩토링
- **i18n 적용 (Soft i18n):** `AppStrings.dart`를 도입하여 UI 텍스트를 중앙화했습니다.
- **설정 시스템 (`SettingsProvider`):** 적 애니메이션 On/Off 등 게임 설정을 관리하고 영구 저장하는 시스템을 구축했습니다.
- **전투 로직 동기화 (UI-Driven Impact):**
- 기존 `Future.delayed` 기반의 불안정한 타이밍 로직을 제거했습니다.
- UI(`BattleScreen`)의 애니메이션 타격 시점(`onImpact`)에 `BattleProvider`의 데미지 로직(`handleImpact`)을 호출하는 구조로 변경하여 시각 효과와 데이터 처리를 완벽하게 동기화했습니다.
- **적 Intent 생성 지연:** 적의 공격 애니메이션이 완전히 끝난 후 다음 행동을 결정하도록 하여, 시각적 혼란(공격 중 방어 이펙트 출력 등)을 방지했습니다.
### B. 버그 수정
- **Null Safety Crash:** 공격 실패 시 `EffectEvent`의 null 값을 참조하여 앱이 종료되는 문제를 수정했습니다.
- **리워드 시스템:**
- 리워드 팝업이 깜빡이거나 이전 데이터를 보여주는 문제 수정.
- 승리 시 리워드가 중복 생성(두 번 호출)되는 문제 수정.
- **아이템 이름:** `LootGenerator`의 문자열 보간 오류로 인해 "Instance of..."가 출력되던 문제를 수정했습니다.
- **애니메이션 중복:** 적 캐릭터 카드에 애니메이션 위젯이 중복 적용되어 발생하던 이상 현상을 수정했습니다.
### C. 기능 추가
- **적 공격 애니메이션:** 플레이어와 마찬가지로 적도 공격 시 대상을 향해 돌진하는 애니메이션을 추가했습니다.
이 작업들을 통해 게임의 안정성, 코드의 유지보수성, 그리고 플레이어의 시각적 경험이 크게 향상되었습니다.

View File

@ -1,11 +0,0 @@
# 61. Convention Update (Soft i18n)
## 1. 목표 (Goal)
- 프로젝트 컨텍스트 복구용 파일(`00_project_context_restore.md`)에 최근 도입한 `AppStrings` 사용 규칙(Soft i18n)을 명시하여, 향후 개발 시 일관성을 유지합니다.
## 2. 변경 내용 (Changes)
- `4. 작업 컨벤션 (Working Conventions)` 섹션에 `i18n Strategy` 항목 추가.
- "UI에 표시되는 문자열은 하드코딩하지 않고 `lib/game/config/app_strings.dart`의 상수를 사용해야 합니다." 라는 지침 명시.
## 3. 기대 효과 (Expected Outcome)
- 이후 AI 세션이나 다른 개발자가 프로젝트에 참여할 때, UI 텍스트 작성 규칙을 즉시 인지하고 따를 수 있음.

View File

@ -1,17 +0,0 @@
# 62. Implement Enemy Attack Animation
## 1. 목표 (Goal)
- 플레이어뿐만 아니라 적(Enemy)이 공격할 때도 플레이어 쪽으로 돌진하는 애니메이션을 추가하여 전투의 역동성을 높입니다.
## 2. 구현 계획 (Implementation Plan)
1. **`BattleScreen` 수정:**
- `GlobalKey<BattleAnimationWidgetState> _enemyAnimKey`를 추가합니다.
- 적 캐릭터 UI(`CharacterStatusCard`)를 `BattleAnimationWidget`으로 감쌉니다.
2. **애니메이션 트리거 로직 (`_addFloatingEffect`):**
- 기존 플레이어 공격 감지 로직과 유사하게, `event.type == ActionType.attack`이고 `event.target == EffectTarget.player`인 경우를 감지합니다.
- 적 위치에서 플레이어 위치로의 오프셋(`playerPos - enemyPos`)을 계산하여 `_enemyAnimKey`로 애니메이션을 실행합니다.
- 공격 모션 중에는 적의 스탯 정보(HP바 등)를 일시적으로 숨기는 로직(`_isEnemyAttacking`)도 추가합니다.
## 3. 기대 효과 (Expected Outcome)
- 적의 턴에도 시각적인 움직임이 발생하여 전투가 더 생동감 있게 느껴짐.
- 플레이어와 적의 상호작용이 명확해짐.

View File

@ -1,22 +0,0 @@
# 63. Implement Settings Provider and Enemy Animation Toggle
## 1. 목표 (Goal)
- 적 공격 애니메이션을 기본적으로 비활성화하고, 설정 화면에서 유저가 선택적으로 활성화할 수 있도록 합니다.
- 전역 설정을 관리하는 `SettingsProvider`를 도입합니다.
## 2. 구현 계획 (Implementation Plan)
1. **`SettingsProvider` 구현:**
- `lib/providers/settings_provider.dart` 생성.
- `enableEnemyAnimations` boolean 상태 관리 (기본값 false).
- `SharedPreferences`를 이용한 영구 저장(`settings_enemy_anim`).
2. **`main.dart` 등록:**
- `MultiProvider``SettingsProvider` 추가.
3. **`SettingsScreen` UI:**
- `AppStrings`에 관련 텍스트 추가.
- SwitchListTile 위젯을 사용하여 설정 변경 UI 구현.
4. **`BattleScreen` 로직:**
- `_addFloatingEffect` 메서드 내에서 적 애니메이션 실행 전 `context.read<SettingsProvider>().enableEnemyAnimations` 확인.
## 3. 기대 효과 (Expected Outcome)
- 유저가 게임의 연출 빈도를 제어할 수 있음.
- 설정 관리의 기반이 마련됨.

View File

@ -1,14 +0,0 @@
# 64. Fix Enemy Animation Sync
## 1. 목표 (Goal)
- 적 공격 시, 애니메이션이 끝나기 전에 데미지가 먼저 들어가는 동기화 문제를 해결합니다.
## 2. 원인 (Cause)
- `BattleProvider``_enemyTurn` 메서드에서 `EffectEvent`를 보낸 후, 애니메이션 재생 시간만큼 기다리지 않고 즉시 데미지 로직을 수행하고 있습니다.
## 3. 해결 방안 (Solution)
- `_enemyTurn` 메서드 내에서 공격 성공 시, `EffectEvent`를 전송한 직후에 `Future.delayed`를 추가하여 애니메이션이 재생될 시간을 확보합니다.
- 대기 시간은 `GameConfig`에 정의된 `animDelaySafe`, `animDelayNormal`, `animDelayRisky` 상수를 사용합니다.
## 4. 기대 효과 (Expected Outcome)
- 적이 플레이어에게 돌진하여 타격하는 시점에 정확히 데미지 텍스트가 뜨고 HP가 감소합니다.

View File

@ -1,13 +0,0 @@
# 65. Fix Floating Text Timing
## 1. 목표 (Goal)
- 적이 플레이어에게 도착하기도 전에 데미지 텍스트가 먼저 뜨는 문제를 해결합니다.
## 2. 원인 (Cause)
- `BattleProvider`에서 주는 `Future.delayed` 시간이 실제 UI 상의 '적 돌진 애니메이션 소요 시간'보다 짧거나 비슷하여, 미세한 차이로 `DamageEvent`가 먼저 처리됨.
## 3. 해결 방안 (Solution)
- `BattleProvider``_enemyTurn` 메서드에서 사용하는 딜레이 시간에 **여유분(+300ms)**을 추가하여, 확실하게 애니메이션이 타격 지점에 도달한 후에 데미지 이벤트가 발생하도록 조정합니다.
## 4. 기대 효과 (Expected Outcome)
- 적이 돌진 -> 타격(Impact) -> 그 순간에 데미지 텍스트 출력 순서가 자연스럽게 맞음.

View File

@ -1,15 +0,0 @@
# 66. Fix Double Animation Wrapper
## 1. 목표 (Goal)
- 적 공격 애니메이션 시 타격 이펙트가 이상하게 동작하거나 중복되는 문제를 해결합니다.
## 2. 원인 (Cause)
- `CharacterStatusCard`는 내부적으로 이미 `BattleAnimationWidget`을 포함하고 있습니다.
- 그러나 `BattleScreen`에서 적 카드를 또다시 `BattleAnimationWidget`으로 감싸는 실수를 범하여 위젯이 중복되었습니다.
## 3. 해결 방안 (Solution)
- `BattleScreen`에서 적 카드를 감싸고 있는 `BattleAnimationWidget`을 제거합니다.
- 대신 `CharacterStatusCard``animationKey` 파라미터에 `_enemyAnimKey`를 직접 전달합니다 (플레이어와 동일한 방식).
## 4. 기대 효과 (Expected Outcome)
- 위젯 구조가 단순화되고 애니메이션 제어가 정상적으로 동작합니다.

View File

@ -1,12 +0,0 @@
# 67. Revert Enemy Turn Delay Buffer
## 1. 목표 (Goal)
- `BattleProvider``_enemyTurn` 로직을 `playerAction`과 완전히 동일하게 만듭니다. (임시로 추가했던 `+300ms` 버퍼 제거)
## 2. 이유 (Reason)
- 이전 단계에서 적 애니메이션 위젯이 중복 생성되어 타이밍 이슈가 발생했던 것으로 파악되었습니다.
- 위젯 중복 문제가 해결되었으므로, 이제 인위적인 딜레이 없이도 정상 동작할 것으로 예상됩니다.
- 사용자의 요구("데미지 계산 자체가 플레이어와 동일해야 한다")를 충족시키기 위해 코드를 통일합니다.
## 3. 작업 내용 (Action)
- `BattleProvider.dart``_enemyTurn` 메서드의 `Future.delayed`에서 `+ 300` 제거.

View File

@ -1,20 +0,0 @@
# 68. Global Animation Delay Adjustment
## 1. 목표 (Goal)
- 플레이어와 적 모두에게 적용되는 애니메이션 딜레이 설정(`GameConfig`)을 조정하여, 데미지 텍스트가 애니메이션 타격(Impact)보다 먼저 뜨는 현상을 근본적으로 해결합니다.
## 2. 원인 (Cause)
- `GameConfig`의 대기 시간이 `BattleAnimationWidget`의 재생 시간과 **완벽하게 동일(ms 단위)**하게 설정되어 있습니다.
- 코드 실행 컨텍스트 차이로 인해 `Timer`(로직 대기)가 `Animation`(UI 렌더링)보다 미세하게 먼저 완료될 수 있어, 텍스트가 먼저 뜨는 "경쟁 상태(Race Condition)"가 발생합니다.
## 3. 해결 방안 (Solution)
- `GameConfig``animDelay...` 값들을 기존 값에서 **+100ms** 증가시킵니다.
- 이는 플레이어와 적 모두에게 동일하게 적용되므로 로직의 일관성을 해치지 않으면서, 시각적으로 "타격 후 텍스트"라는 자연스러운 순서를 보장합니다.
## 4. 변경 값
- Safe: 500 -> 600
- Normal: 400 -> 500
- Risky: 1100 -> 1200
## 5. 기대 효과 (Expected Outcome)
- 플레이어와 적 모두 공격 시 애니메이션이 목표에 도달한 직후 데미지 텍스트가 표시됨.

View File

@ -1,29 +0,0 @@
# 69. Sync Damage to Animation Impact (UI-Driven)
## 1. 목표 (Goal)
- 플레이어와 적 모두의 공격 시 데미지 텍스트 출력이 애니메이션 타격(Impact) 순간과 완벽하게 동기화되도록 수정합니다.
## 2. 문제점 (Problem)
- 기존에는 `BattleProvider``Future.delayed`로 애니메이션 시간을 예측했으나, 이는 UI의 실제 Impact 시점과 미묘하게 어긋나 데미지 텍스트가 먼저 뜨는 현상이 발생했습니다.
## 3. 해결 방안 (Solution)
- **UI (BattleScreen)가 애니메이션 Impact 시점을 `BattleProvider`에게 직접 알려주어 데미지 처리를 트리거**하는 "UI 주도 Impact 처리" 방식으로 전환합니다.
## 4. 구현 계획 (Implementation Plan)
### A. `EffectEvent` 데이터 확장 (`lib/game/model/effect_event.dart`)
- `EffectEvent``attacker`, `target` (Character 객체), `damage`, `risk`, `isSuccess` 등 Impact 시점에 필요한 모든 정보를 담습니다.
### B. `BattleProvider` 수정 (`lib/providers/battle_provider.dart`)
1. **`Future.delayed` 제거:** `playerAction``_enemyTurn`의 공격 로직에서 `await Future.delayed(...)`를 제거합니다.
2. **데미지 처리 로직 추출:** 공격 Impact 시점에 발생해야 할 모든 로직(HP 감소, `DamageEvent` 전송, 로그 기록, 상태이상 적용)을 `_processAttackImpact`라는 `private` 또는 `public` 메서드로 추출합니다.
3. **새로운 `public` 메서드 추가:** `BattleProvider.handleAttackImpact(String eventId, Character attacker, Character target, int damage, RiskLevel risk, bool isSuccess)`와 같은 메서드를 만들어, `BattleScreen`에서 Impact 시점에 호출하도록 합니다.
### C. `BattleScreen` 수정 (`lib/screens/battle_screen.dart`)
1. `_addFloatingEffect` 메서드 내에서 `animateAttack`를 호출할 때:
- `onImpact` 콜백 내에서 `context.read<BattleProvider>().handleAttackImpact(...)`를 호출합니다.
- `EffectEvent`에 담긴 정보를 기반으로 `handleAttackImpact`에 인자를 전달합니다.
## 5. 기대 효과 (Expected Outcome)
- 애니메이션과 데미지 텍스트 출력이 완벽하게 동기화되어, 게임의 타격감이 대폭 향상됩니다.
- 로직과 UI 간의 역할 분리가 명확해집니다.

View File

@ -1,16 +0,0 @@
# 70. Fix Player Action Crash and Double Damage
## 1. 문제 (Problem)
- **Crash:** `BattleProvider.playerAction`에서 생성하는 `EffectEvent``attacker`, `targetEntity`, `damageValue` 등이 누락되어 있어, UI가 `handleImpact`를 호출할 때 `event.attacker!` 등에서 Null Pointer Exception이 발생함.
- **Double Damage:** `playerAction` 메서드 내부에 구버전의 데미지 적용 로직이 남아 있어, 이를 수정하지 않으면 데미지가 두 번 들어감.
## 2. 해결 방안 (Solution)
- `playerAction` 메서드를 대대적으로 수정하여 `_enemyTurn`과 동일한 패턴을 적용합니다.
- **즉시 데미지 적용 로직 삭제:** HP/Armor 감소 로직을 제거합니다.
- **`EffectEvent` 완전체 생성:** `attacker`, `targetEntity`, `damageValue` 등을 모두 채워서 이벤트를 생성합니다.
- **위임:** 모든 데미지 처리는 `EffectEvent`를 통해 `handleImpact` -> `_processAttackImpact`로 위임됩니다.
## 3. 기대 효과 (Expected Outcome)
- 앱 크래시 해결.
- 플레이어 공격 시 애니메이션과 데미지 적용 시점이 정확히 일치.
- 데미지 중복 적용 방지.

View File

@ -1,12 +0,0 @@
# 71. Fix Null Pointer Exception on Failed Actions
## 1. 문제 (Problem)
- `BattleProvider`에서 공격 실패(`Miss`) 또는 방어(`Defend`) 시 `_processAttackImpact`를 직접 호출하고 있음.
- `_processAttackImpact``damageValue!`와 같이 강제 언래핑을 수행하므로, 실패한 공격(`damageValue`가 null)일 경우 앱이 크래시됨(`Unexpected null value`).
## 2. 해결 방안 (Solution)
- `playerAction``_enemyTurn` 메서드에서 `_processAttackImpact` 직접 호출을 모두 `handleImpact(event)` 호출로 변경합니다.
- `handleImpact` 메서드 내부에 있는 `if (!event.isSuccess!) return;` 안전 장치를 활용하여 크래시를 방지합니다.
## 3. 기대 효과 (Expected Outcome)
- 공격 실패 시에도 앱이 정상적으로 동작하며, 로그만 출력되고 데미지 로직은 스킵됨.

View File

@ -1,11 +0,0 @@
# 72. Delay Enemy Intent Generation
## 1. 문제 (Problem)
- 적이 공격하는 도중에 `_generateEnemyIntent()`가 호출되어, 다음 턴 행동(예: 방어)이 미리 실행되고 이펙트가 겹쳐 보이는 현상 발생.
## 2. 해결 방안 (Solution)
- `BattleProvider._enemyTurn` 메서드에서 `_generateEnemyIntent()` 호출 전에 **충분한 대기 시간(`GameConfig.animDelayEnemyTurn` 또는 공격 애니메이션 시간)**을 둡니다.
- 이를 통해 적의 현재 행동 연출이 완전히 끝난 뒤에 다음 행동을 준비하도록 순서를 정리합니다.
## 3. 기대 효과 (Expected Outcome)
- 적 공격 -> 복귀 -> (잠시 후) -> 다음 턴 방어 준비(이펙트) 순서로 자연스럽게 진행됨.

View File

@ -1,81 +0,0 @@
# 73. Prevent Pre-emptive Defense on First Turn
## 1. 문제 (Problem)
- 현재 시스템은 `_generateEnemyIntent`가 호출되면, 적의 행동이 `Defend`일 경우 **즉시 방어도를 증가**시킵니다(Pre-emptive Defense).
- 스테이지 시작(`_prepareNextStage`) 시에도 `_generateEnemyIntent`를 호출하므로, 첫 턴부터 적이 방어도를 가지고 시작하는 경우가 발생합니다.
- 사용자는 첫 턴에는 적의 방어도가 적용되지 않은 상태로 플레이어가 선공할 수 있기를 원합니다.
## 2. 해결 방안 (Solution)
- `_generateEnemyIntent` 메서드에 `applyImmediateEffect` (기본값 `true`) 파라미터를 추가합니다.
- `_prepareNextStage`에서 첫 Intent를 생성할 때는 `applyImmediateEffect: false`로 호출하여, 의도(Intent)는 생성하되 **방어도 증가 효과는 적용하지 않도록** 합니다.
- 단, 이렇게 하면 적이 "방어하겠다"고 표시만 하고 실제로는 방어도가 0인 상태가 됩니다.
- 만약 "첫 턴에는 적이 아예 행동하지 않음"을 원한다면 Intent 자체를 생성하지 않아야 하지만, 로그라이크 특성상 "적의 다음 행동"은 보여줘야 합니다.
- 따라서 **"첫 턴의 방어 Intent는 방어도를 올리지 않는다"** 보다는 **"첫 턴 Intent 생성 시에는 방어 행동을 제외하거나, 방어도가 턴 시작 시(적 턴)에 올라가도록"** 해야 할 수도 있습니다.
- 하지만 사용자의 요청은 "첫 턴에 방어도가 적용되는 중"인 것을 막는 것이므로, **첫 Intent 생성 시에는 방어도 적용을 스킵**하는 것이 가장 직관적입니다.
## 3. 수정 계획
1. `_generateEnemyIntent({bool applyDefense = true})` 로 시그니처 변경.
2. `_prepareNextStage`에서는 `applyDefense: false`로 호출.
3. 나머지 `_enemyTurn` 등에서는 `applyDefense: true`로 호출.
**주의:** 이렇게 하면 적의 첫 행동이 `Defend`일 때, UI에는 "Defends for 10"이라고 뜨지만 실제 방어도는 0입니다. 플레이어가 공격하면 0인 상태로 맞습니다. 그리고 적 턴이 되면? 적은 `Defend` 행동을 했으므로 (이미 했다고 치고) 아무것도 안 하거나, 그때 방어도를 올릴까요?
현재 로직: `_enemyTurn`에서 `Defend`면 "Enemy maintains defensive stance" 로그만 띄우고 끝납니다.
즉, **첫 턴에 방어도를 안 올리면, 적은 첫 턴에 아무것도 안 하는 바보가 됩니다.**
**재해석:**
"첫 턴에는 무조건 플레이어가 행동하는 걸로 해야 해" -> **"적은 첫 턴에 방어 행동(선제 방어)을 하지 말아야 한다."**
즉, **첫 턴 Intent 생성 시에는 `Defend`가 나오지 않도록 강제**하거나, **첫 턴에는 Intent를 생성하되 방어 효과는 적 턴 시작 시점에 발동하도록 유예**해야 합니다.
하지만 `Slay the Spire` 같은 게임을 보면, 첫 턴에 적이 방어 자세를 취할 수도 있습니다. 사용자가 원하는 건 **"전투 시작하자마자 적이 단단해져 있는 게 싫다"**는 것입니다.
**결론:**
`_prepareNextStage`에서 Intent를 생성할 때, **방어 행동이 당첨되더라도 방어도를 즉시 적용하지 않고, 적 턴이 시작될 때 적용**하도록 로직을 분산시켜야 합니다.
하지만 현재 구조상 `Intent`는 "이미 적용됨"을 가정합니다.
**가장 깔끔한 방법:**
**첫 턴(`_prepareNextStage`)에서는 `_generateEnemyIntent`를 호출하지 않습니다.**
대신 `null`로 두거나, **"대기(Wait/Stunned)"** 상태로 둡니다.
하지만 적이 뭘 할지 모르면 전략을 짤 수 없습니다.
**사용자의 의도:** "첫 턴에는 무조건 플레이어가 행동" -> 플레이어 선공 보장.
현재도 플레이어 선공입니다. 단지 적이 "방어 버프"를 두르고 있을 뿐.
**수정 제안:**
`_prepareNextStage`에서 생성하는 첫 Intent는 **`applyDefense: false`**로 생성합니다.
그리고 `_enemyTurn`에서 **"만약 현재 Intent가 Defend이고 방어도가 아직 적용 안 됐다면(혹은 첫 턴이라면), 이때 방어도를 적용한다"**는 로직을 추가해야 합니다.
하지만 코드가 복잡해집니다.
더 쉬운 방법: **첫 턴 Intent 생성 시, 아예 `Defend` 선택지를 배제합니다.** (첫 턴은 무조건 공격만 하도록).
이게 밸런스상으론 더 공격적일 수 있지만, "방어도가 적용되는 문제"는 확실히 해결됩니다.
**사용자 멘트 재확인:** "스테이지 첫번째 enemyIntent 생성 시... isFirst 플래그를 추가해서 첫턴에는 무조건 플레이어가 행동하는걸로 해야해."
-> 이 말은 **"적이 아무런 선제 액션(방어)도 취하지 않은 상태여야 한다"**는 뜻입니다.
**전략:**
`BattleProvider``isFirstTurn` 플래그를 추가하는 것이 아니라, `_generateEnemyIntent` 메서드에 `isFirstTurn` 파라미터를 추가합니다.
그리고 `isFirstTurn``true`이면, **`Defend` 확률을 0으로 만들거나, `Defend`가 선택되어도 방어도를 적용하지 않고 넘깁니다.**
후자가 낫습니다. UI에는 "방어 예정"이라고 뜨고, 적 턴이 되었을 때 방어도가 올라가는 것이 가장 자연스럽습니다.
**구현:**
1. `_generateEnemyIntent({bool applyImmediate = true})`
2. `_prepareNextStage` -> `_generateEnemyIntent(applyImmediate: false)`
3. `_enemyTurn` -> 만약 `currentEnemyIntent``Defend`인데 방어도가 0이라면? (이미 깎였을 수도 있음).
-> **Flag 필요:** `bool _isPreemptiveDefenseApplied` 같은 변수가 필요할 수도 있습니다.
아니면 단순히 **`_prepareNextStage`에서는 `Defend`가 안 나오게 막는 것**이 제일 깔끔합니다. (첫 턴은 공격만 함).
하지만 사용자가 "첫턴에는 무조건 플레이어가 행동"이라고 했지 "적은 공격만 해"라고 하진 않았습니다.
**가장 적절한 구현:**
`_prepareNextStage`에서 Intent 생성 시 `applyImmediate: false`로 설정.
그리고 `_enemyTurn` 로직을 수정하여, **"Defend Intent인 경우, 기존에는 '이미 적용됨'이라 넘어갔지만, 이제는 '적용 안 됐으면 지금 적용'하도록"** 변경.
어떻게 '적용 안 됐음'을 알까요?
`EnemyIntent` 클래스에 `bool applied` 필드를 추가하면 됩니다!
**계획:**
1. `EnemyIntent` 클래스에 `bool isApplied` 필드 추가 (기본 false).
2. `_generateEnemyIntent`에서 `applyImmediate`가 true면 방어도 올리고 `isApplied = true`.
3. `_prepareNextStage`에서는 `applyImmediate: false`로 호출 -> `isApplied = false`.
4. `_enemyTurn`에서 `Intent``Defend`일 때, `!isApplied`라면 방어도 적용하고 이펙트 띄움.
이 방식이 완벽합니다.

View File

@ -1,12 +0,0 @@
# 74. Fix Item Name Interpolation
## 1. 문제 (Problem)
- 아이템 이름 생성 시 `Instance of 'ItemTemplate'.name` 형태의 잘못된 문자열이 출력됨.
- 원인은 Dart의 문자열 보간 문법 오류: `"$template.name"`은 객체를 문자열로 변환함.
## 2. 해결 방안 (Solution)
- `lib/game/logic/loot_generator.dart` 파일 내의 문자열 보간 코드를 수정.
- `"${selectedModifier.prefix} $template.name"` -> `"${selectedModifier.prefix} ${template.name}"`
## 3. 기대 효과 (Expected Outcome)
- 아이템 이름이 "Sharp Wooden Sword" 처럼 정상적으로 출력됨.