feat(core): 장비 시스템 및 게임 상태 모델 확장

- Equipment 클래스를 11개 슬롯으로 확장 (원본 Main.dfm 충실)
- TaskInfo에 몬스터 정보(baseName, part) 추가
- Stats에 현재 HP/MP 필드 추가
- 히스토리 기능 구현 (plotHistory, questHistory)
- pq_logic winEquip/winStatIndex 원본 로직 개선
- 퀘스트 몬스터 처리 로직 구현
- SaveData 직렬화 확장
This commit is contained in:
JiWoong Sul
2025-12-09 22:30:37 +09:00
parent b512fde1fb
commit b450bf2600
12 changed files with 571 additions and 208 deletions

View File

@@ -35,9 +35,7 @@ void main() {
),
inventory: const Inventory(
gold: 5,
items: [
InventoryEntry(name: 'Rock', count: 3),
],
items: [InventoryEntry(name: 'Rock', count: 3)],
),
progress: const ProgressState(
task: ProgressBarState(position: 0, max: 80),

View File

@@ -1,4 +1,3 @@
import 'package:askiineverdie/src/core/model/equipment_slot.dart';
import 'package:askiineverdie/src/core/model/game_state.dart';
import 'package:askiineverdie/src/core/model/pq_config.dart';
import 'package:askiineverdie/src/core/util/deterministic_random.dart';
@@ -65,7 +64,7 @@ void main() {
config,
DeterministicRandom(12),
5,
EquipmentSlot.weapon,
0, // weapon slot
),
'Baselard',
);
@@ -74,7 +73,7 @@ void main() {
config,
DeterministicRandom(15),
2,
EquipmentSlot.armor,
2, // helm slot (armor category)
),
'-2 Canvas',
);
@@ -86,18 +85,35 @@ void main() {
});
test('monsterTask picks level-appropriate monsters with modifiers', () {
expect(
pq_logic.monsterTask(config, DeterministicRandom(99), 5, null, null),
'an underage Rakshasa',
final result1 = pq_logic.monsterTask(
config,
DeterministicRandom(99),
5,
null,
null,
);
expect(
pq_logic.monsterTask(config, DeterministicRandom(7), 10, null, null),
'a greater Sphinx',
expect(result1.displayName, 'an underage Rakshasa');
expect(result1.baseName, 'Rakshasa');
expect(result1.part, isNotEmpty);
final result2 = pq_logic.monsterTask(
config,
DeterministicRandom(7),
10,
null,
null,
);
expect(
pq_logic.monsterTask(config, DeterministicRandom(5), 6, 'Goblin|3', 3),
'a Barbed Devil',
expect(result2.displayName, 'a greater Sphinx');
expect(result2.baseName, 'Sphinx');
final result3 = pq_logic.monsterTask(
config,
DeterministicRandom(5),
6,
'Goblin|3|ear',
3,
);
expect(result3.displayName, 'a Barbed Devil');
});
test('completeQuest and completeAct return deterministic results', () {

View File

@@ -7,7 +7,6 @@ library;
import 'package:askiineverdie/src/core/engine/game_mutations.dart';
import 'package:askiineverdie/src/core/engine/progress_service.dart';
import 'package:askiineverdie/src/core/engine/reward_service.dart';
import 'package:askiineverdie/src/core/model/equipment_slot.dart';
import 'package:askiineverdie/src/core/model/game_state.dart';
import 'package:askiineverdie/src/core/model/pq_config.dart';
import 'package:askiineverdie/src/core/util/deterministic_random.dart';
@@ -41,71 +40,59 @@ void main() {
test('monsterTask produces consistent monster names', () {
// 시드 42, 레벨 5에서의 몬스터 이름
expect(
pq_logic.monsterTask(
config,
DeterministicRandom(testSeed),
5,
null,
null,
),
pq_logic
.monsterTask(config, DeterministicRandom(testSeed), 5, null, null)
.displayName,
'an underage Su-monster',
);
// 시드 42, 레벨 10에서의 몬스터 이름
expect(
pq_logic.monsterTask(
config,
DeterministicRandom(testSeed),
10,
null,
null,
),
pq_logic
.monsterTask(config, DeterministicRandom(testSeed), 10, null, null)
.displayName,
'a cursed Troll',
);
// 시드 42, 레벨 1에서의 몬스터 이름
expect(
pq_logic.monsterTask(
config,
DeterministicRandom(testSeed),
1,
null,
null,
),
pq_logic
.monsterTask(config, DeterministicRandom(testSeed), 1, null, null)
.displayName,
'a greater Crayfish',
);
});
test('winEquip produces consistent equipment', () {
// 시드 42에서 무기 획득
// 시드 42에서 무기 획득 (슬롯 0)
expect(
pq_logic.winEquip(
config,
DeterministicRandom(testSeed),
5,
EquipmentSlot.weapon,
0, // weapon slot
),
'Longiron',
);
// 시드 42에서 방어구 획득
// 시드 42에서 방어구 획득 (슬롯 2 = helm, armor 카테고리)
expect(
pq_logic.winEquip(
config,
DeterministicRandom(testSeed),
5,
EquipmentSlot.armor,
2, // helm slot (armor category)
),
'-1 Holey Mildewed Bearskin',
);
// 시드 42에서 방패 획득
// 시드 42에서 방패 획득 (슬롯 1)
expect(
pq_logic.winEquip(
config,
DeterministicRandom(testSeed),
5,
EquipmentSlot.shield,
1, // shield slot
),
'Round Shield',
);