Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83ea191ca2 | ||
|
|
0e0748540e | ||
|
|
0420e23939 | ||
|
|
adb6c2d20b | ||
|
|
cb48d0db48 | ||
|
|
3b9fa47f0a | ||
|
|
e020e44d8f | ||
|
|
5cdb6217ed | ||
|
|
3c47a1a3a2 | ||
|
|
7abb01ed5b | ||
|
|
8297ce980f | ||
|
|
14c99305c4 | ||
|
|
a18f2504af | ||
|
|
f5a7eb2db9 | ||
|
|
c029cd1e10 | ||
|
|
2de58a6525 | ||
|
|
09d8fdcfe9 | ||
|
|
8f72b9a812 | ||
|
|
5b1ce14ed4 | ||
|
|
f57714b22c | ||
|
|
bb3b34c9b1 | ||
|
|
ac4df02654 | ||
|
|
d544f46766 | ||
|
|
f49902c067 | ||
|
|
eab99eee6f | ||
|
|
9540dd22a3 | ||
|
|
135bf26332 | ||
|
|
59ebb7cd98 | ||
|
|
e1b000772e | ||
|
|
fef803d064 | ||
|
|
0b48aea16d | ||
|
|
cb7e75064f | ||
|
|
3030c09d55 | ||
|
|
1720725826 | ||
|
|
e6facc41f8 | ||
|
|
78267b7e47 | ||
|
|
9a7498af35 | ||
|
|
c570d61563 | ||
|
|
9a9022356a | ||
|
|
32c77dd20a | ||
|
|
46658b22c8 |
@@ -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` 등록 여부를 반드시 확인해야 합니다.
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 407 KiB |
|
After Width: | Height: | Size: 408 KiB |
|
After Width: | Height: | Size: 603 B |
|
After Width: | Height: | Size: 477 KiB |
|
After Width: | Height: | Size: 293 KiB |
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
|
||||
|
After Width: | Height: | Size: 168 KiB |
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 933 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 54 KiB |
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 556 B |
|
After Width: | Height: | Size: 465 B |
|
After Width: | Height: | Size: 556 B |
|
After Width: | Height: | Size: 559 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 559 B |
|
After Width: | Height: | Size: 618 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 582 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 668 B |
|
After Width: | Height: | Size: 509 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 570 B |
|
After Width: | Height: | Size: 547 B |
|
After Width: | Height: | Size: 494 B |
|
After Width: | Height: | Size: 554 B |
|
After Width: | Height: | Size: 507 B |
|
After Width: | Height: | Size: 547 B |
|
After Width: | Height: | Size: 527 B |
|
After Width: | Height: | Size: 603 B |
|
After Width: | Height: | Size: 604 B |
|
After Width: | Height: | Size: 626 B |
|
After Width: | Height: | Size: 609 B |
|
After Width: | Height: | Size: 539 B |
|
After Width: | Height: | Size: 525 B |
|
After Width: | Height: | Size: 529 B |
|
After Width: | Height: | Size: 543 B |
|
After Width: | Height: | Size: 633 B |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 573 B |
|
After Width: | Height: | Size: 434 B |
|
After Width: | Height: | Size: 478 B |
|
After Width: | Height: | Size: 515 B |
|
After Width: | Height: | Size: 442 B |
|
After Width: | Height: | Size: 495 B |
|
After Width: | Height: | Size: 510 B |
|
After Width: | Height: | Size: 543 B |
|
After Width: | Height: | Size: 524 B |
|
After Width: | Height: | Size: 489 B |
|
After Width: | Height: | Size: 615 B |
|
After Width: | Height: | Size: 493 B |
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
@@ -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
|
||||
@@ -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';
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,4 +11,7 @@ class ItemConfig {
|
||||
ItemRarity.legendary: 4,
|
||||
ItemRarity.unique: 1,
|
||||
};
|
||||
|
||||
// Loot Generation
|
||||
static const double magicPrefixChance = 1.0; // 100%
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||