Compare commits

...
41 Commits
Author SHA1 Message Date
horoli 83ea191ca2 Refactor: Slim down BattleProvider and extract logic services. Restore original animations and positioning. 2026-04-28 08:41:46 +09:00
horoli 0e0748540e feat: add subweapon support, weapon type logic, and compact item card UI options 2026-04-28 01:39:39 +09:00
horoli 0420e23939 update 2026-02-15 15:47:39 +09:00
horoli adb6c2d20b update 2026-02-04 12:00:38 +09:00
horoli cb48d0db48 update 2026-02-04 01:44:57 +09:00
horoli 3b9fa47f0a update 2026-02-04 01:44:38 +09:00
horoli e020e44d8f update 2026-02-04 01:11:32 +09:00
horoli 5cdb6217ed update : assets 2026-02-03 23:34:11 +09:00
horoli 3c47a1a3a2 update : assets 2026-02-03 23:32:37 +09:00
horoli 7abb01ed5b aa 2026-01-28 23:16:37 +09:00
horoli 8297ce980f aa 2026-01-26 00:53:04 +09:00
horoli 14c99305c4 update : player image path 2026-01-07 14:40:49 +09:00
horoli a18f2504af adjust difficult balance 2025-12-16 17:14:17 +09:00
horoli f5a7eb2db9 update 2025-12-16 02:13:31 +09:00
horoli c029cd1e10 update 2025-12-10 23:47:40 +09:00
horoli 2de58a6525 update 2025-12-10 16:17:41 +09:00
horoli 09d8fdcfe9 update
- consumable items
2025-12-10 16:05:42 +09:00
horoli 8f72b9a812 update 2025-12-10 01:35:09 +09:00
horoli 5b1ce14ed4 update 2025-12-09 16:24:52 +09:00
horoli f57714b22c test enemy images 2025-12-09 15:16:23 +09:00
horoli bb3b34c9b1 refactoring : barrel pattern 2025-12-09 14:40:25 +09:00
horoli ac4df02654 update
- adjust risky animation offset
 - show inventory in shop
2025-12-09 11:47:37 +09:00
horoli d544f46766 update 2025-12-09 01:04:14 +09:00
horoli f49902c067 update 2025-12-08 18:57:17 +09:00
horoli eab99eee6f update 2025-12-08 03:00:45 +09:00
horoli 9540dd22a3 update 2025-12-08 03:00:36 +09:00
horoli 135bf26332 Docs: Consolidate prompts 61-76 into summary and update context 2025-12-07 22:06:51 +09:00
horoli 59ebb7cd98 Fix: Correct item name interpolation 2025-12-07 21:47:51 +09:00
horoli e1b000772e Fix: Prevent enemy preemptive defense on first turn 2025-12-07 21:36:40 +09:00
horoli fef803d064 Fix: Delay Enemy Intent generation to allow attack animation to finish 2025-12-07 21:28:33 +09:00
horoli 0b48aea16d Fix: Revert buffer delay, unify player/enemy logic 2025-12-07 19:50:56 +09:00
horoli cb7e75064f Fix: Remove redundant animation wrapper for enemy 2025-12-07 19:45:16 +09:00
horoli 3030c09d55 Fix: Add buffer delay to Enemy Turn for animation sync 2025-12-07 19:37:17 +09:00
horoli 1720725826 Fix: Sync Enemy Attack Animation with Damage Calculation 2025-12-07 19:25:26 +09:00
horoli e6facc41f8 Feat: Add SettingsProvider and Toggle for Enemy Animations 2025-12-07 19:20:43 +09:00
horoli 78267b7e47 Feat: Implement Enemy Attack Animation 2025-12-07 19:18:40 +09:00
horoli 9a7498af35 Docs: Update project context with i18n convention 2025-12-07 19:10:03 +09:00
horoli c570d61563 Refactor: Introduce AppStrings for soft i18n 2025-12-07 18:58:44 +09:00
horoli 9a9022356a Refactor: Centralize Constants and Configuration 2025-12-07 18:49:07 +09:00
horoli 32c77dd20a Refactor Item Creation: Introduce LootGenerator 2025-12-07 18:47:36 +09:00
horoli 46658b22c8 Refactor BattleProvider: Introduce CombatCalculator and BattleLogManager 2025-12-07 18:45:33 +09:00
191 changed files with 7957 additions and 3168 deletions
+256
View File
@@ -0,0 +1,256 @@
# 프로젝트 개요
작성일: 2026-04-27
## 한 줄 요약
`Colosseum's Choice`는 Flutter로 만든 콜로세움 테마의 턴제 로그라이트 전투 게임입니다. 플레이어는 전투, 상점, 휴식 스테이지를 반복하며 장비와 소모품을 얻고, 위험도 선택 기반의 공격/방어 액션으로 더 높은 스테이지를 진행합니다.
## 기본 정보
- 앱 타이틀: `Colosseum's Choice`
- Flutter 패키지명: `game_test`
- 주요 기술: Flutter, Dart, Provider, SharedPreferences
- 지원 플랫폼 폴더: `android/`, `ios/`, `web/`, `macos/`, `linux/`, `windows/`
- 주요 소스 루트: `lib/`
- 주요 데이터 루트: `assets/data/`
## 실행 흐름
1. `lib/main.dart`
- Flutter 바인딩을 초기화합니다.
- `ItemTable.load()`, `EnemyTable.load()`, `PlayerTable.load()`로 JSON 데이터를 먼저 로드합니다.
- `MultiProvider`로 `SettingsProvider`, `ShopProvider`, `BattleProvider`를 등록합니다.
- `MainMenuScreen`을 첫 화면으로 띄웁니다.
2. 메인 메뉴
- 저장 데이터가 있으면 `Continue`가 노출됩니다.
- 이어하기는 `SaveManager.loadGame()` 결과를 `BattleProvider.loadFromSave()`로 복원합니다.
- 새 게임은 `CharacterSelectionScreen`으로 이동합니다.
3. 새 게임 시작
- `CharacterSelectionScreen`에서 전사를 선택합니다.
- `BattleProvider.initializeBattle()`로 플레이어와 1스테이지를 초기화합니다.
- `StoryScreen`을 거쳐 `MainWrapper`로 진입합니다.
4. 실제 플레이 화면
- `MainWrapper`는 하단 탭 구조입니다.
- 첫 탭은 현재 스테이지 타입에 따라 `Battle`, `Shop`, `Rest`로 표시됩니다.
- 나머지 탭은 `Inventory`, `Settings`입니다.
## 핵심 게임 루프
- 스테이지 타입은 `BattleProvider._prepareNextStage()`에서 결정됩니다.
- 우선순위는 `elite -> shop -> rest -> battle`입니다.
- 현재 설정 기준:
- 엘리트: 12스테이지마다
- 상점: 5스테이지마다
- 휴식: 8스테이지마다
- 티어 1: 1-12 스테이지
- 티어 2: 13-24 스테이지
- 티어 3: 25 스테이지 이후
전투에서 승리하면 골드와 보상 선택지가 지급되고, 보상을 선택하거나 스킵하면 체력을 일부 회복한 뒤 다음 스테이지로 넘어갑니다. 상점/휴식 스테이지는 별도 UI를 거쳐 다음 스테이지로 진행합니다.
## 전투 시스템
전투는 `BattleProvider`와 `CombatCalculator`가 중심입니다.
- 플레이어 액션: `attack`, `defend`
- 위험도: `safe`, `normal`, `risky`
- 공격은 `totalAtk`, 방어는 `totalDefense`를 기반으로 계산됩니다.
- 위험도는 성공 확률과 효율 배율을 함께 바꿉니다.
- 운(`luck`)은 성공 확률에 더해지고 최대 100%로 제한됩니다.
- 적은 매 턴 `EnemyIntent`를 생성해 다음 행동과 위험도를 미리 보여줍니다.
현재 전투 수치 설정은 `lib/game/config/battle_config.dart`에 있습니다.
- Safe: 성공률 100%, 공격 50%, 방어 100%
- Normal: 성공률 80%, 공격 100%, 방어 200%
- Risky: 성공률 40%, 공격 200%, 방어 300%
- 적 행동 비율: 공격 70%, 방어 30%
피해 계산은 방어도와 상태 이상을 반영합니다.
- 방어도는 HP 피해보다 먼저 피해를 흡수합니다.
- `vulnerable` 상태면 받는 피해가 `GameConfig.vulnerableDamageMultiplier`만큼 증가합니다.
- 회피(`dodge`)가 성공하면 공격 피해가 들어가지 않습니다.
- 현재 방어도 감소율은 `GameConfig.armorDecayRate`로 관리됩니다.
## 상태 이상
상태 이상 타입은 `lib/game/enums.dart`의 `StatusEffectType`에 정의되어 있습니다.
- `stun`: 해당 턴 행동 불가
- `vulnerable`: 받는 피해 증가
- `bleed`: 턴 시작 시 고정 피해
- `defenseForbidden`: 방어 액션 사용 불가
- `disarmed`: 공격력 감소
- `attackUp`: 공격력 증가 버프
아이템 효과는 `ItemEffect`로 표현되며, 공격 성공 후 `CombatCalculator.getAppliedEffects()`와 `BattleProvider._tryApplyStatusEffects()`를 통해 대상에게 적용됩니다.
## 보상, 아이템, 장비
아이템 데이터는 `assets/data/items.json`에서 로드되고 `ItemTable`이 관리합니다.
- 슬롯: weapon, armor, shield, accessory, consumable
- 희귀도: normal, magic, rare, legendary, unique
- 티어: tier1, tier2, tier3
- 장비 스탯: 공격력, HP, 방어도, 회피, 운
- 소모품: 즉시 회복, 방어도 증가, 버프 적용 등에 사용됩니다.
아이템 생성은 `LootGenerator`가 담당합니다.
- Normal 등급은 가중치 기반 접두어로 기본 스탯 변형을 받을 수 있습니다.
- Magic 등급은 접두어를 통해 하나 이상의 스탯 보너스를 받을 수 있습니다.
- Rare 등급은 별도 이름 생성과 강한 스탯 변형을 받을 수 있습니다.
- Legendary/Unique는 기본 템플릿 성격을 유지합니다.
인벤토리는 `Character.inventory`에 보관되고, 최대 크기는 `GameConfig.maxInventorySize`입니다. 장비 장착/해제 시 최대 HP 변화로 인한 체력 악용을 막기 위해 현재 HP 비율을 유지합니다.
## 경제와 상점
상점 로직은 `ShopProvider`와 `widgets/stage/shop_ui.dart`가 담당합니다.
- 상점 스테이지에서 장비 4개와 소모품 2개를 생성합니다.
- 아이템 구매는 골드와 인벤토리 여유 공간을 검사합니다.
- 재입고 비용은 `GameConfig.shopRerollCost`입니다.
- 판매 가격은 `item.price * GameConfig.sellPriceMultiplier`를 내림 처리합니다.
전투 승리 골드는 다음 공식으로 지급됩니다.
```text
baseGoldReward + stage * goldRewardPerStage + random(0..goldRewardVariance - 1)
```
## 저장 시스템
저장은 `lib/game/save_manager.dart`가 담당하며 `shared_preferences`를 사용합니다.
- 저장 키: `GameConfig.saveKey`
- 저장 시점: 새 스테이지 준비 시점
- 저장 내용: 스테이지, 턴 수, 플레이어 JSON, 저장 시각
- 패배 시 저장 데이터가 삭제됩니다.
현재 저장 구조는 아이템의 `id`를 중심으로 복원합니다. 따라서 런타임에 생성된 접두어, 이름, 세부 스탯 변형을 완전히 보존하려면 `Item.toJson()`/`Item.fromJson()` 형태의 상세 저장 구조가 필요합니다.
## 주요 폴더 구조
```text
lib/
main.dart 앱 진입점, 데이터 선로딩, Provider 등록
game/
model/ Character, Item, Stage, StatusEffect 등 도메인 모델
data/ JSON 로더, 아이템/적/플레이어 테이블, 이름/접두어 데이터
logic/ 전투 계산, 전리품 생성, 전투 로그 관리
config/ 게임 밸런스, 전투 수치, 테마, 문구 상수
enums.dart 게임 전반에서 쓰는 enum 정의
save_manager.dart SharedPreferences 저장/불러오기
providers/ BattleProvider, ShopProvider, SettingsProvider
screens/ 메인 메뉴, 캐릭터 선택, 스토리, 전투, 인벤토리, 설정
widgets/
battle/ 전투 UI, 애니메이션, 피드백 텍스트, 로그, 컨트롤
inventory/ 캐릭터 스탯, 장비, 인벤토리 그리드
stage/ 상점, 휴식 스테이지 UI
common/ 공통 버튼, 아이콘, 아이템 카드
utils/ 수학, 아이템, 토스트 유틸
```
```text
assets/
data/
items.json 아이템 템플릿
enemies.json 적 템플릿
players.json 플레이어 템플릿
icon/ 레거시 아이콘 데이터
images/
character/ 플레이어 캐릭터 이미지와 공격 프레임
enemies/ 적 이미지
background/ 배경 이미지
icons/ 장비, 포션, 테두리 등 UI 아이콘
```
## 화면 구성
- `MainMenuScreen`: 시작 화면, 저장 데이터 확인, 이어하기/새 게임
- `CharacterSelectionScreen`: 플레이어 템플릿 선택
- `StoryScreen`: 전투 시작 전 스토리 화면
- `MainWrapper`: 하단 탭과 현재 스테이지 화면 전환
- `BattleScreen`: 전투 UI, 이펙트 스트림 구독, 애니메이션 처리
- `InventoryScreen`: 캐릭터 능력치, 장착 장비, 인벤토리
- `SettingsScreen`: 애니메이션, 흔들림 옵션, 재시작, 메인 메뉴 복귀
## 이벤트와 UI 동기화
전투 로직과 UI 애니메이션은 이벤트 스트림으로 느슨하게 연결되어 있습니다.
- `DamageEvent`: 실제 HP 피해 텍스트 표시
- `EffectEvent`: 공격/방어/실패/회피 등 시각 효과와 충돌 타이밍 전달
- `BattleScreen`은 두 스트림을 구독하고, 애니메이션이 끝나는 시점에 `BattleProvider.handleImpact()`를 호출해 실제 피해/방어도 변화를 적용합니다.
이 구조 덕분에 계산 로직과 화면 효과가 분리되어 있지만, 턴 전환은 애니메이션 완료 콜백에 의존하는 부분이 있으므로 전투 UI 수정 시 `handleImpact()` 호출 흐름을 함께 확인해야 합니다.
## 설정과 밸런스 조정 위치
- 스테이지, 경제, 저장, 회복, 피해 배율: `lib/game/config/game_config.dart`
- 전투 성공률, 효율, 이펙트 크기/색상: `lib/game/config/battle_config.dart`
- 아이템 희귀도 가중치, 접두어 확률: `lib/game/config/item_config.dart`
- 앱 문구: `lib/game/config/app_strings.dart`
- 색상, 폰트 크기, UI 상수: `lib/game/config/theme_config.dart`
## 테스트
테스트는 `test/` 아래에 있습니다.
- 아이템 로딩과 랜덤 선택
- 아이템 희귀도/티어
- 적 데이터 로딩
- 캐릭터 장비와 HP 비율 처리
- 전투 Provider의 방어도 초기화
- 적 의도 생성/실행
- disarm 상태 효과
주요 명령:
```bash
flutter pub get
flutter test
flutter run
```
웹으로 실행하려면 보통 다음 명령을 사용합니다.
```bash
flutter run -d chrome
```
## 확장 작업 가이드
새 아이템을 추가할 때:
1. `assets/data/items.json`에 템플릿을 추가합니다.
2. 이미지가 필요하면 `assets/images/icons/...` 아래에 추가합니다.
3. 새 폴더를 추가했다면 `pubspec.yaml`의 `flutter.assets`에 등록합니다.
4. 로딩 테스트나 랜덤 선택 테스트를 확인합니다.
새 적을 추가할 때:
1. `assets/data/enemies.json`의 `normal` 또는 `elite`에 템플릿을 추가합니다.
2. 이미지가 필요하면 `assets/images/enemies/`에 추가합니다.
3. 티어와 장비 ID가 실제 아이템 데이터와 맞는지 확인합니다.
전투 밸런스를 조정할 때:
1. 위험도별 성공률/효율은 `BattleConfig`를 수정합니다.
2. 스테이지 보상, 상점 주기, 회복량은 `GameConfig`를 수정합니다.
3. 장비 드롭 희귀도는 `ItemConfig.defaultRarityWeights`를 수정합니다.
## 현재 눈여겨볼 점
- `pubspec.yaml`의 패키지 설명은 아직 Flutter 기본 문구입니다.
- 앱 타이틀은 `Colosseum's Choice`지만 패키지명은 `game_test`입니다.
- `StoryScreen`은 아직 플레이스홀더 이미지와 텍스트를 사용합니다.
- `initializeBattle()`에서 테스트용 아이템과 포션을 기본 지급하고 있습니다.
- 저장은 아이템 ID 중심이라 생성된 접두어/세부 스탯 보존이 제한적입니다.
- 자산 폴더를 새로 추가할 때는 `pubspec.yaml` 등록 여부를 반드시 확인해야 합니다.
+2 -1
View File
@@ -1,5 +1,6 @@
#Tue Mar 31 23:58:22 KST 2026
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
+357 -65
View File
@@ -1,96 +1,388 @@
{
"normal": [
{
"name": "Goblin",
"baseHp": 20,
"name": "Scrawny Piso",
"baseHp": 30,
"baseAtk": 6,
"baseDefense": 0,
"image": "assets/images/enemies/Orc.png",
"equipment": [
"pot_lid"
],
"tier": 1
},
{
"name": "Nervous Darius",
"baseHp": 25,
"baseAtk": 5,
"baseDefense": 0,
"baseDodge": 10,
"image": "assets/images/enemies/nervous_gladiator.png",
"equipment": [],
"tier": 1
},
{
"name": "Clumsy Linus",
"baseHp": 35,
"baseAtk": 4,
"baseDefense": 1,
"image": "assets/images/enemies/clumsy_gladiator.png",
"equipment": [
"simple_rags"
],
"tier": 1
},
{
"name": "Desperate Felix",
"baseHp": 28,
"baseAtk": 7,
"baseDefense": 1,
"image": "assets/images/enemies/desperate_gladiator.png",
"equipment": [
"gladius"
],
"tier": 1
},
{
"name": "Untrained Milo",
"baseHp": 32,
"baseAtk": 6,
"baseDefense": 3,
"image": "assets/images/enemies/untrained_gladiator.png",
"equipment": [
"wooden_buckler"
],
"tier": 1
},
{
"name": "Wild Leo",
"baseHp": 30,
"baseAtk": 8,
"baseDefense": 1,
"image": "assets/images/enemies/wild_gladiator.png",
"equipment": [],
"tier": 1
},
{
"name": "Chain-gang Cassius",
"baseHp": 40,
"baseAtk": 5,
"baseDefense": 5,
"image": "assets/images/enemies/goblin.png",
"equipment": ["rusty_dagger"],
"image": "assets/images/enemies/chained_gladiator.png",
"equipment": [
"flail"
],
"tier": 1
},
{
"name": "Slime",
"baseHp": 30,
"baseAtk": 3,
"baseDefense": 5,
"image": "assets/images/enemies/slime.png",
"equipment": ["rusty_dagger"],
"tier": 1
},
{
"name": "Wolf",
"baseHp": 25,
"baseAtk": 7,
"baseDefense": 5,
"image": "assets/images/enemies/wolf.png",
"equipment": ["rusty_dagger"],
"tier": 1
},
{
"name": "Bandit",
"name": "Retiarius Drusus",
"baseHp": 35,
"baseAtk": 6,
"baseDefense": 5,
"image": "assets/images/enemies/bandit.png",
"equipment": ["rusty_dagger"],
"tier": 2
},
{
"name": "Skeleton",
"baseHp": 15,
"baseAtk": 8,
"baseDefense": 5,
"image": "assets/images/enemies/skeleton.png",
"equipment": ["rusty_dagger"],
"baseDefense": 3,
"image": "assets/images/enemies/retiarius.png",
"equipment": [
"trident"
],
"tier": 1
},
{
"name": "One-eyed Marcus",
"baseHp": 65,
"baseAtk": 15,
"baseDefense": 4,
"image": "assets/images/enemies/one_eyed_gladiator.png",
"equipment": [
"scimitar"
],
"tier": 2
},
{
"name": "Shadow Assassin",
"baseHp": 40,
"name": "Brutal Varro",
"baseHp": 75,
"baseAtk": 18,
"baseDefense": 5,
"image": "assets/images/enemies/brutal_gladiator.png",
"equipment": [
"war_axe"
],
"tier": 2
},
{
"name": "Veteran Hector",
"baseHp": 60,
"baseAtk": 15,
"baseDefense": 10,
"image": "assets/images/enemies/veteran_gladiator.png",
"equipment": [
"gladius",
"leather_vest"
],
"tier": 2
},
{
"name": "Swift Castus",
"baseHp": 55,
"baseAtk": 13,
"baseDefense": 7,
"baseDodge": 15,
"image": "assets/images/enemies/swift_gladiator.png",
"equipment": [
"scimitar"
],
"tier": 2
},
{
"name": "Cunning Flaccus",
"baseHp": 60,
"baseAtk": 12,
"baseDefense": 8,
"luck": 10,
"image": "assets/images/enemies/cunning_gladiator.png",
"equipment": [
"flail",
"tarnished_ring"
],
"tier": 2
},
{
"name": "Hoplomachus Severus",
"baseHp": 70,
"baseAtk": 15,
"baseDefense": 12,
"image": "assets/images/enemies/hoplomachus.png",
"equipment": [
"trident",
"kite_shield",
"chainmail"
],
"tier": 2
},
{
"name": "Drunken Titus",
"baseHp": 80,
"baseAtk": 18,
"baseDefense": 5,
"baseDodge": -5,
"image": "assets/images/enemies/drunken_gladiator.png",
"equipment": [
"war_axe"
],
"tier": 2
},
{
"name": "The Wall Aethel",
"baseHp": 100,
"baseAtk": 10,
"baseDefense": 2,
"image": "assets/images/enemies/shadow_assassin.png",
"equipment": ["jagged_dagger"],
"baseDefense": 12,
"image": "assets/images/enemies/the_wall.png",
"equipment": [
"tower_shield",
"chainmail"
],
"tier": 2
},
{
"name": "Champion Gannicus",
"baseHp": 200,
"baseAtk": 25,
"baseDefense": 12,
"image": "assets/images/enemies/champion_gannicus.png",
"equipment": [
"steel_greatsword",
"steel_plate"
],
"tier": 3
},
{
"name": "Armored Bear",
"baseHp": 60,
"baseAtk": 8,
"baseDefense": 8,
"image": "assets/images/enemies/armored_bear.png",
"equipment": ["iron_sword"],
"name": "The Giant Ursus",
"baseHp": 300,
"baseAtk": 30,
"baseDefense": 10,
"image": "assets/images/enemies/the_giant.png",
"equipment": [
"war_hammer"
],
"tier": 3
},
{
"name": "Bloody Flamma",
"baseHp": 100,
"baseAtk": 25,
"baseDefense": 14,
"image": "assets/images/enemies/bloody_flamma.png",
"equipment": [
"barbed_net"
],
"tier": 3
},
{
"name": "Legendary Oenomaus",
"baseHp": 130,
"baseAtk": 24,
"baseDefense": 20,
"image": "assets/images/enemies/legendary_oenomaus.png",
"equipment": [
"scimitar",
"steel_shield"
],
"tier": 3
},
{
"name": "The Unseen Lyra",
"baseHp": 90,
"baseAtk": 22,
"baseDefense": 12,
"baseDodge": 30,
"image": "assets/images/enemies/the_unseen.png",
"equipment": [
"hooked_spear"
],
"tier": 3
},
{
"name": "Executioner Balbus",
"baseHp": 140,
"baseAtk": 35,
"baseDefense": 15,
"image": "assets/images/enemies/executioner.png",
"equipment": [
"executioners_axe"
],
"tier": 3
},
{
"name": "Vengeful Spartacus",
"baseHp": 120,
"baseAtk": 35,
"baseDefense": 16,
"image": "assets/images/enemies/vengeful_spartacus.png",
"equipment": [
"gladius"
],
"tier": 3
},
{
"name": "Praetorian Guard",
"baseHp": 150,
"baseAtk": 28,
"baseDefense": 25,
"image": "assets/images/enemies/praetorian_guard.png",
"equipment": [
"steel_greatsword",
"steel_plate",
"tower_shield"
],
"tier": 3
}
],
"elite": [
{
"name": "Orc Warrior",
"baseHp": 60,
"baseAtk": 12,
"baseDefense": 3,
"image": "assets/images/enemies/orc_warrior.png",
"equipment": ["battle_axe", "leather_vest"],
"name": "Crixus 'The Gaul'",
"baseHp": 120,
"baseAtk": 14,
"baseDefense": 5,
"image": "assets/images/enemies/crixus_the_gaul.png",
"equipment": [
"long_sword",
"kite_shield"
],
"tier": 1
},
{
"name": "Giant Spider",
"baseHp": 50,
"baseAtk": 15,
"baseDefense": 2,
"image": "assets/images/enemies/giant_spider.png",
"equipment": ["jagged_dagger"],
"name": "Theokoles 'Shadow of Death'",
"baseHp": 160,
"baseAtk": 28,
"baseDefense": 8,
"image": "assets/images/enemies/theokoles.png",
"equipment": [
"war_axe"
],
"tier": 1
},
{
"name": "Isidorus 'The Butcher'",
"baseHp": 140,
"baseAtk": 22,
"baseDefense": 10,
"image": "assets/images/enemies/isidorus_the_butcher.png",
"equipment": [
"trident"
],
"tier": 1
},
{
"name": "Vitallion 'The Lion'",
"baseHp": 250,
"baseAtk": 22,
"baseDefense": 10,
"luck": 15,
"image": "assets/images/enemies/vitallion_the_lion.png",
"equipment": [
"war_hammer",
"chainmail",
"engraved_amulet"
],
"tier": 2
},
{
"name": "Dark Knight",
"baseHp": 80,
"baseAtk": 10,
"baseDefense": 5,
"image": "assets/images/enemies/dark_knight.png",
"equipment": ["stunning_hammer", "kite_shield"],
"name": "Arcas 'The Serpent'",
"baseHp": 180,
"baseAtk": 28,
"baseDefense": 15,
"baseDodge": 15,
"image": "assets/images/enemies/arcas_the_serpent.png",
"equipment": [
"hooked_spear"
],
"tier": 2
},
{
"name": "Verus 'The Undefeated'",
"baseHp": 280,
"baseAtk": 30,
"baseDefense": 20,
"image": "assets/images/enemies/verus_the_undefeated.png",
"equipment": [
"steel_greatsword",
"steel_shield"
],
"tier": 2
},
{
"name": "Magistratus Maxentius",
"baseHp": 350,
"baseAtk": 38,
"baseDefense": 30,
"image": "assets/images/enemies/magistratus_maxentius.png",
"equipment": [
"executioners_axe",
"steel_plate",
"champions_badge"
],
"tier": 3
},
{
"name": "Aurelia 'The Crimson Blade'",
"baseHp": 500,
"baseAtk": 35,
"baseDefense": 15,
"baseDodge": 20,
"image": "assets/images/enemies/aurelia_crimson_blade.png",
"equipment": [
"scimitar"
],
"tier": 3
},
{
"name": "Gaius 'The Chimera'",
"baseHp": 400,
"baseAtk": 40,
"baseDefense": 18,
"image": "assets/images/enemies/chimera.png",
"equipment": [
"sunderer_axe"
],
"tier": 3
}
]
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB

+227 -111
View File
@@ -1,68 +1,76 @@
{
"weapons": [
{
"id": "short_bow",
"name": "Short Bow",
"description": "A basic bow for beginners.",
"baseAtk": 2,
"slot": "weapon",
"price": 15,
"image": "assets/images/items/short_bow.png",
"rarity": "normal",
"tier": "tier1"
},
{
"id": "long_sword",
"name": "Long Sword",
"description": "A versatile blade.",
"baseAtk": 6,
"slot": "weapon",
"price": 50,
"image": "assets/images/items/long_sword.png",
"rarity": "normal",
"tier": "tier2"
},
{
"id": "rusty_dagger",
"name": "Rusty Dagger",
"description": "Old and rusty, but better than nothing.",
"baseAtk": 3,
"slot": "weapon",
"price": 30,
"image": "assets/images/items/rusty_dagger.png",
"rarity": "magic",
"tier": "tier1"
},
{
"id": "iron_sword",
"name": "Iron Sword",
"description": "A standard soldier's sword.",
"id": "gladius",
"name": "Gladius",
"description": "A standard short sword used by gladiators.",
"baseAtk": 8,
"slot": "weapon",
"price": 80,
"image": "assets/images/items/iron_sword.png",
"rarity": "magic",
"tier": "tier2"
"price": 30,
"image": "assets/images/items/gladius.png",
"rarity": "normal",
"tier": "tier1",
"weaponType": "oneHanded"
},
{
"id": "battle_axe",
"name": "Battle Axe",
"description": "Heavy but powerful.",
"baseAtk": 12,
"id": "flail",
"name": "Flail",
"description": "A spiked ball attached to a chain. Hard to predict.",
"baseAtk": 5,
"luck": 5,
"slot": "weapon",
"price": 45,
"image": "assets/images/items/flail.png",
"rarity": "magic",
"tier": "tier1",
"weaponType": "oneHanded"
},
{
"id": "trident",
"name": "Trident",
"description": "A three-pronged spear. Offers good reach.",
"baseAtk": 9,
"baseHp": 5,
"slot": "weapon",
"price": 70,
"image": "assets/images/items/trident.png",
"rarity": "normal",
"tier": "tier2",
"weaponType": "twoHanded"
},
{
"id": "scimitar",
"name": "Scimitar",
"description": "A curved blade, known for swift cuts.",
"baseAtk": 13,
"dodge": 3,
"slot": "weapon",
"price": 90,
"image": "assets/images/items/scimitar.png",
"rarity": "magic",
"tier": "tier2",
"weaponType": "oneHanded"
},
{
"id": "war_axe",
"name": "War Axe",
"description": "Heavy and powerful, designed to break shields.",
"baseAtk": 16,
"slot": "weapon",
"price": 120,
"image": "assets/images/items/battle_axe.png",
"image": "assets/images/items/war_axe.png",
"rarity": "magic",
"tier": "tier2"
"tier": "tier2",
"weaponType": "twoHanded"
},
{
"id": "stunning_hammer",
"name": "Stunning Hammer",
"description": "A heavy hammer that can stun foes.",
"baseAtk": 10,
"id": "war_hammer",
"name": "War Hammer",
"description": "A heavy hammer that can daze foes.",
"baseAtk": 14,
"slot": "weapon",
"price": 150,
"image": "assets/images/items/stunning_hammer.png",
"image": "assets/images/items/war_hammer.png",
"effects": [
{
"type": "stun",
@@ -71,35 +79,68 @@
}
],
"rarity": "rare",
"tier": "tier2"
"tier": "tier2",
"weaponType": "twoHanded"
},
{
"id": "jagged_dagger",
"name": "Jagged Dagger",
"description": "A cruel dagger that causes bleeding.",
"baseAtk": 7,
"id": "barbed_net",
"name": "Barbed Net",
"description": "A weighted net to ensnare and wound opponents.",
"baseAtk": 4,
"slot": "weapon",
"price": 130,
"image": "assets/images/items/jagged_dagger.png",
"image": "assets/images/items/barbed_net.png",
"effects": [
{
"type": "bleed",
"probability": 100,
"duration": 3,
"value": 30
"value": 5
}
],
"rarity": "rare",
"tier": "tier1"
"tier": "tier1",
"weaponType": "oneHanded"
},
{
"id": "sunderer_axe",
"name": "Sunderer Axe",
"description": "An axe that exposes enemy weaknesses.",
"baseAtk": 11,
"id": "steel_greatsword",
"name": "Steel Greatsword",
"description": "A massive, well-crafted steel sword.",
"baseAtk": 24,
"slot": "weapon",
"price": 160,
"image": "assets/images/items/sunderer_axe.png",
"price": 180,
"image": "assets/images/items/steel_greatsword.png",
"rarity": "magic",
"tier": "tier3",
"weaponType": "twoHanded"
},
{
"id": "hooked_spear",
"name": "Hooked Spear",
"description": "A spear with a hook to pull enemies off balance.",
"baseAtk": 15,
"slot": "weapon",
"price": 250,
"image": "assets/images/items/hooked_spear.png",
"effects": [
{
"type": "disarmed",
"probability": 30,
"duration": 1
}
],
"rarity": "rare",
"tier": "tier3",
"weaponType": "twoHanded"
},
{
"id": "executioners_axe",
"name": "Executioner's Axe",
"description": "A terrifying axe that exposes enemy weaknesses.",
"baseAtk": 28,
"slot": "weapon",
"price": 300,
"image": "assets/images/items/executioners_axe.png",
"effects": [
{
"type": "vulnerable",
@@ -108,19 +149,20 @@
}
],
"rarity": "legendary",
"tier": "tier3"
"tier": "tier3",
"weaponType": "twoHanded"
}
],
"armors": [
{
"id": "torn_tunic",
"name": "Torn Tunic",
"description": "Offers minimal protection.",
"baseHp": 10,
"id": "simple_rags",
"name": "Simple Rags",
"description": "Better than nothing.",
"baseHp": 15,
"slot": "armor",
"price": 20,
"image": "assets/images/items/torn_tunic.png",
"rarity": "magic",
"price": 15,
"image": "assets/images/items/simple_rags.png",
"rarity": "normal",
"tier": "tier1"
},
{
@@ -132,17 +174,40 @@
"price": 60,
"image": "assets/images/items/leather_vest.png",
"rarity": "magic",
"tier": "tier2"
"tier": "tier1"
},
{
"id": "chainmail",
"name": "Chainmail",
"description": "Reliable protection against cuts.",
"baseHp": 60,
"baseHp": 70,
"slot": "armor",
"price": 120,
"image": "assets/images/items/chainmail.png",
"rarity": "magic",
"tier": "tier2"
},
{
"id": "steel_plate",
"name": "Steel Plate",
"description": "Solid, heavy protection.",
"baseHp": 120,
"slot": "armor",
"price": 200,
"image": "assets/images/items/steel_plate.png",
"rarity": "magic",
"tier": "tier3"
},
{
"id": "reinforced_leather",
"name": "Reinforced Leather",
"description": "Remarkably light and durable.",
"baseHp": 70,
"dodge": 5,
"slot": "armor",
"price": 280,
"image": "assets/images/items/reinforced_leather.png",
"rarity": "rare",
"tier": "tier3"
}
],
@@ -151,28 +216,28 @@
"id": "pot_lid",
"name": "Pot Lid",
"description": "It was used for cooking.",
"baseArmor": 1,
"baseArmor": 2,
"slot": "shield",
"price": 10,
"image": "assets/images/items/pot_lid.png",
"rarity": "magic",
"rarity": "normal",
"tier": "tier1"
},
{
"id": "wooden_shield",
"name": "Wooden Shield",
"description": "Sturdy oak wood.",
"id": "wooden_buckler",
"name": "Wooden Buckler",
"description": "A small, agile shield.",
"baseArmor": 3,
"slot": "shield",
"price": 40,
"image": "assets/images/items/wooden_shield.png",
"image": "assets/images/items/wooden_buckler.png",
"rarity": "magic",
"tier": "tier1"
},
{
"id": "kite_shield",
"name": "Kite Shield",
"description": "Used by knights.",
"description": "Used by professional soldiers.",
"baseArmor": 6,
"slot": "shield",
"price": 100,
@@ -180,6 +245,28 @@
"rarity": "magic",
"tier": "tier2"
},
{
"id": "steel_shield",
"name": "Steel Shield",
"description": "A heavy, durable shield.",
"baseArmor": 9,
"slot": "shield",
"price": 180,
"image": "assets/images/items/steel_shield.png",
"rarity": "magic",
"tier": "tier3"
},
{
"id": "tower_shield",
"name": "Tower Shield",
"description": "Almost like a small wall.",
"baseArmor": 18,
"slot": "shield",
"price": 260,
"image": "assets/images/items/tower_shield.png",
"rarity": "rare",
"tier": "tier3"
},
{
"id": "cursed_shield",
"name": "Cursed Shield",
@@ -201,70 +288,99 @@
],
"accessories": [
{
"id": "old_ring",
"name": "Old Ring",
"description": "A tarnished ring. Might bring a little luck.",
"id": "tarnished_ring",
"name": "Tarnished Ring",
"description": "A simple ring. Might bring a little luck.",
"baseAtk": 1,
"baseHp": 5,
"slot": "accessory",
"price": 25,
"image": "assets/images/items/old_ring.png",
"image": "assets/images/items/tarnished_ring.png",
"luck": 5,
"rarity": "magic",
"tier": "tier1"
},
{
"id": "copper_ring",
"name": "Copper Ring",
"description": "A simple ring.",
"baseAtk": 1,
"baseHp": 5,
"slot": "accessory",
"price": 25,
"image": "assets/images/items/copper_ring.png",
"luck": 3,
"rarity": "magic",
"tier": "tier1"
},
{
"id": "ruby_amulet",
"name": "Ruby Amulet",
"description": "Glows with a faint red light.",
"id": "engraved_amulet",
"name": "Engraved Amulet",
"description": "Glows with a faint inner light.",
"baseAtk": 3,
"baseHp": 15,
"slot": "accessory",
"price": 80,
"image": "assets/images/items/ruby_amulet.png",
"image": "assets/images/items/engraved_amulet.png",
"luck": 7,
"rarity": "rare",
"tier": "tier2"
},
{
"id": "heros_badge",
"name": "Hero's Badge",
"description": "A badge of honor.",
"id": "champions_badge",
"name": "Champion's Badge",
"description": "A badge of honor, earned with blood.",
"baseAtk": 5,
"baseHp": 25,
"baseArmor": 1,
"slot": "accessory",
"price": 150,
"image": "assets/images/items/heros_badge.png",
"image": "assets/images/items/champions_badge.png",
"luck": 10,
"rarity": "legendary",
"tier": "tier3"
},
{
"id": "lucky_charm",
"name": "Lucky Charm",
"description": "A four-leaf clover encased in amber.",
"id": "worn_talisman",
"name": "Worn Talisman",
"description": "A strange charm that seems to bend fate.",
"baseAtk": 0,
"baseHp": 10,
"slot": "accessory",
"price": 200,
"image": "assets/images/items/lucky_charm.png",
"image": "assets/images/items/worn_talisman.png",
"luck": 25,
"rarity": "unique",
"tier": "tier3"
}
],
"consumables": [
{
"id": "potion_heal_small",
"name": "Healing Potion",
"description": "Restores 20 HP instantly.",
"slot": "consumable",
"hpBonus": 20,
"price": 15,
"rarity": "normal",
"tier": "tier1",
"image": "assets/images/items/potion.png"
},
{
"id": "potion_armor_small",
"name": "Iron Skin Potion",
"description": "Grants +10 Armor instantly.",
"slot": "consumable",
"armorBonus": 10,
"price": 20,
"rarity": "normal",
"tier": "tier1",
"image": "assets/images/items/potion.png"
},
{
"id": "potion_strength_small",
"name": "Strength Potion",
"description": "Increases Attack Power for 1 turn.",
"slot": "consumable",
"effects": [
{
"type": "attackUp",
"probability": 100,
"duration": 1,
"value": 5
}
],
"price": 25,
"rarity": "magic",
"tier": "tier1",
"image": "assets/images/items/potion.png"
}
]
}
+12 -1
View File
@@ -6,6 +6,17 @@
"baseHp": 50,
"baseAtk": 5,
"baseDefense": 5,
"image": "assets/images/players/warrior.png"
"baseDodge": 2,
"image": "assets/images/character/Knight-Idle.png"
},
{
"id": "rogue",
"name": "Rogue",
"description": "A swift shadow with high evasion but lower health.",
"baseHp": 40,
"baseAtk": 7,
"baseDefense": 2,
"baseDodge": 15,
"image": "assets/images/character/rogue.png"
}
]
Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 556 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 559 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 668 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 547 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 603 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 626 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 609 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 529 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 495 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 524 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 489 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 615 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 493 B

Binary file not shown.
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
#include "Generated.xcconfig"
+1
View File
@@ -1 +1,2 @@
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
#include "Generated.xcconfig"
+43
View File
@@ -0,0 +1,43 @@
# Uncomment this line to define a global platform for your project
# platform :ios, '13.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
project 'Runner', {
'Debug' => :debug,
'Profile' => :release,
'Release' => :release,
}
def flutter_root
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
unless File.exist?(generated_xcode_build_settings_path)
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
end
File.foreach(generated_xcode_build_settings_path) do |line|
matches = line.match(/FLUTTER_ROOT\=(.*)/)
return matches[1].strip if matches
end
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
end
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
flutter_ios_podfile_setup
target 'Runner' do
use_frameworks!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'RunnerTests' do
inherit! :search_paths
end
end
post_install do |installer|
installer.pods_project.targets.each do |target|
flutter_additional_ios_build_settings(target)
end
end
+6
View File
@@ -0,0 +1,6 @@
export 'config/animation_config.dart';
export 'config/app_strings.dart';
export 'config/battle_config.dart';
export 'config/game_config.dart';
export 'config/item_config.dart';
export 'config/theme_config.dart';
+2 -2
View File
@@ -8,7 +8,7 @@ class AnimationConfig {
static const Duration fadeDuration = Duration(milliseconds: 200);
// Attack Animations
static const Duration attackSafe = Duration(milliseconds: 200);
static const Duration attackSafe = Duration(milliseconds: 500);
static const Duration attackNormal = Duration(milliseconds: 400);
static const Duration attackRiskyTotal = Duration(milliseconds: 1100);
static const Duration attackRiskyScale = Duration(milliseconds: 600);
@@ -17,7 +17,7 @@ class AnimationConfig {
// Curves
static const Curve floatingTextCurve = Curves.easeOut;
static const Curve floatingEffectScaleCurve = Curves.elasticOut;
static const Curve attackSafeCurve = Curves.elasticIn;
static const Curve attackSafeCurve = Curves.easeOutQuad;
static const Curve attackNormalCurve = Curves.easeOutQuad;
static const Curve attackRiskyDashCurve = Curves.easeInExpo;
+65
View File
@@ -0,0 +1,65 @@
class AppStrings {
// Main Menu
static const String gameTitle = "Colosseum's Choice";
static const String startGame = "Start Game";
static const String continueGame = "Continue";
static const String exitGame = "Exit Game";
static const String credits = "Credits";
// Common Actions
static const String confirm = "Confirm";
static const String cancel = "Cancel";
static const String back = "Back";
static const String close = "Close";
static const String equip = "Equip";
static const String unequip = "Unequip";
static const String discard = "Discard";
static const String sell = "Sell";
static const String buy = "Buy";
// Stats
static const String hp = "HP";
static const String atk = "ATK";
static const String def = "DEF";
static const String armor = "Armor";
static const String luck = "Luck";
static const String gold = "Gold";
// Battle
static const String attack = "Attack";
static const String defend = "Defend";
static const String turn = "Turn";
static const String playerTurn = "Player's Turn";
static const String enemyTurn = "Enemy's Turn";
static const String victory = "Victory!";
static const String defeat = "Defeat";
static const String reward = "Reward";
static const String chooseReward = "Choose a Reward";
static const String skip = "Skip";
static const String nextStage = "Next Stage";
static const String returnToMenu = "Return to Menu";
static const String restart = "Restart";
// Inventory
static const String inventory = "Inventory";
static const String equipment = "Equipment";
static const String bag = "Bag";
static const String emptySlot = "Empty";
static const String noItems = "No items in inventory";
// Shop
static const String shopTitle = "Merchant";
static const String shopWelcome = "Welcome, traveler!";
static const String refreshShop = "Restock";
static const String notEnoughGold = "Not enough gold!";
static const String inventoryFull = "Inventory is full!";
// Risk Levels
static const String riskSafe = "Safe";
static const String riskNormal = "Normal";
static const String riskRisky = "Risky";
// Settings
static const String settings = "Settings";
static const String enemyAnimations = "Enemy Animations";
}
+59 -1
View File
@@ -11,15 +11,51 @@ class BattleConfig {
static const Color normalColor = Colors.white;
static const Color safeColor = Colors.grey;
// Layout & Animation
static const int feedbackCooldownMs = 300;
static const double damageTextOffsetY = -20.0;
static const double damageTextOffsetX = -20.0;
// Effect Offsets (Relative to Card Size)
static const double effectEnemyOffsetX = 0.1; // 10%
static const double effectEnemyOffsetY = 0.8; // 80%
static const double effectPlayerOffsetX = 0.8; // 80%
static const double effectPlayerOffsetY = 0.2; // 20%
// Logs
static const double logsOverlayHeight = 150.0;
static const Color defendRiskyColor = Colors.deepPurpleAccent;
static const Color defendNormalColor = Colors.blueAccent;
static const Color defendSafeColor = Colors.greenAccent;
// Sizes
static const double sizeRisky = 80.0; // User increased this in previous edit
static const double sizeRisky = 80.0;
static const double sizeNormal = 60.0;
static const double sizeSafe = 40.0;
// Damage Text Scale
static const double damageScaleNormal = 1.0;
static const double damageScaleHigh = 3.0;
static const int highDamageThreshold = 15;
// Logic Constants
// Safe
static const double safeBaseChance = 1.0; // 100%
static const double attackSafeEfficiency = 0.5; // 50%
static const double defendSafeEfficiency = 1.0; // 100%
// Normal
static const double normalBaseChance = 0.8; // 80%
static const double attackNormalEfficiency = 1.0; // 100%
static const double defendNormalEfficiency = 2.0; // 150%
// Risky
static const double riskyBaseChance = 0.4; // 40%
static const double attackRiskyEfficiency = 2.0; // 200%
static const double defendRiskyEfficiency = 3.0; // 300%
// Enemy Logic
static const double enemyAttackChance = 0.7; // 70% Attack, 30% Defend
static IconData getIcon(ActionType type) {
switch (type) {
case ActionType.attack:
@@ -61,4 +97,26 @@ class BattleConfig {
return sizeSafe;
}
}
static String getFeedbackText(BattleFeedbackType type) {
switch (type) {
case BattleFeedbackType.miss:
return "MISS";
case BattleFeedbackType.failed:
return "FAILED";
case BattleFeedbackType.dodge:
return "DODGE";
}
}
static Color getFeedbackColor(BattleFeedbackType type) {
switch (type) {
case BattleFeedbackType.miss:
return Colors.redAccent; // Or use ThemeConfig.missText if preferred
case BattleFeedbackType.failed:
return Colors.orangeAccent; // Or use ThemeConfig.failedText
case BattleFeedbackType.dodge:
return Colors.greenAccent; // Or use ThemeConfig.statLuckColor
}
}
}
+14 -6
View File
@@ -1,6 +1,6 @@
class GameConfig {
// Inventory
static const int maxInventorySize = 5;
static const int maxInventorySize = 8;
// Economy
static const int startingGold = 50;
@@ -8,21 +8,29 @@ class GameConfig {
static const int shopRerollCost = 50;
// Stages
static const int eliteStageInterval = 10;
static const int eliteStageInterval = 12;
static const int shopStageInterval = 5;
static const int restStageInterval = 8;
static const int tier1StageMax = 12;
static const int tier2StageMax = 24;
static const int maxStage = 36;
// Battle
static const double stageHealRatio = 0.1;
static const double vulnerableDamageMultiplier = 1.5;
static const double armorDecayRate = 0.5;
static const double armorDecayRate = 1.0;
static const double disarmedDamageMultiplier =
0.2; // New: Reduces ATK to 10% when disarmed
// Rewards
static const int baseGoldReward = 10;
static const int goldRewardPerStage = 5;
static const int goldRewardVariance = 10;
// Animations (Duration in milliseconds)
static const int animDelaySafe = 500;
static const int animDelayNormal = 400;
static const int animDelayRisky = 1100;
static const int animDelaySafe = 600; // 500 + 100 buffer
static const int animDelayNormal = 500; // 400 + 100 buffer
static const int animDelayRisky = 1200; // 1100 + 100 buffer
static const int animDelayEnemyTurn = 1000;
// Save System
+3
View File
@@ -11,4 +11,7 @@ class ItemConfig {
ItemRarity.legendary: 4,
ItemRarity.unique: 1,
};
// Loot Generation
static const double magicPrefixChance = 1.0; // 100%
}
+21
View File
@@ -66,6 +66,16 @@ class ThemeConfig {
static const Color enemyIntentBorder = Colors.redAccent;
static final Color? selectionCardBg = Colors.blueGrey[800];
static const Color selectionIconColor = Colors.blue;
static final Color toggleBtnBg = Colors.grey[800]!;
static final Color rewardItemBg = Colors.blueGrey[700]!;
static const Color snackBarErrorBg = Colors.red;
static const Color iconColorWhite = Colors.white;
static const Color menuButtonBg = Color(0xFF424242); // Grey 800
static const double itemIconSizeSmall = 18.0;
static const double itemIconSizeMedium = 24.0;
static const double letterSpacingHeader = 4.0;
static const double paddingBtnHorizontal = 32.0;
static const double paddingBtnVertical = 16.0;
// Feedback Colors
static const Color damageTextDefault = Colors.red;
@@ -79,6 +89,8 @@ class ThemeConfig {
// Status Effect Colors
static const Color effectBg = Colors.deepOrange;
static const Color effectBuffBg = Colors.green; // New: Buff
static const Color effectDebuffBg = Colors.deepOrange; // New: Debuff
static const Color effectText = Colors.white;
// Rarity Colors
@@ -93,4 +105,13 @@ class ThemeConfig {
static const Color riskSafe = Colors.green;
static const Color riskNormal = Colors.blue;
static const Color riskRisky = Colors.red;
// Character Status Card
static const double characterIconSize = 60.0;
static const double playerImageSize = 200.0;
static const double enemyImageSize = 200.0;
static const Color playerImageBgColor = Colors.lightBlue;
static const double statusEffectFontSize = 10.0;
static const double intentFontSize = 12.0;
static const double intentIconSize = 16.0;
}

Some files were not shown because too many files have changed in this diff Show More