update
This commit is contained in:
@@ -57,6 +57,10 @@ class BattleProvider with ChangeNotifier {
|
||||
List<String> get logs => battleLogs;
|
||||
int get lastGoldReward => _lastGoldReward;
|
||||
|
||||
void refreshUI() {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
// Damage Event Stream
|
||||
final _damageEventController = StreamController<DamageEvent>.broadcast();
|
||||
Stream<DamageEvent> get damageStream => _damageEventController.stream;
|
||||
@@ -83,10 +87,10 @@ class BattleProvider with ChangeNotifier {
|
||||
stage = data['stage'];
|
||||
turnCount = data['turnCount'];
|
||||
player = Character.fromJson(data['player']);
|
||||
|
||||
|
||||
battleLogs.clear();
|
||||
_addLog("Game Loaded! Resuming Stage $stage");
|
||||
|
||||
|
||||
_prepareNextStage();
|
||||
notifyListeners();
|
||||
}
|
||||
@@ -113,51 +117,51 @@ class BattleProvider with ChangeNotifier {
|
||||
player.gold = GameConfig.startingGold;
|
||||
|
||||
// Provide starter equipment
|
||||
final starterSword = Item(
|
||||
id: "starter_sword",
|
||||
name: "Wooden Sword",
|
||||
description: "A basic sword",
|
||||
atkBonus: 5,
|
||||
hpBonus: 0,
|
||||
slot: EquipmentSlot.weapon,
|
||||
);
|
||||
final starterArmor = Item(
|
||||
id: "starter_armor",
|
||||
name: "Leather Armor",
|
||||
description: "Basic protection",
|
||||
atkBonus: 0,
|
||||
hpBonus: 20,
|
||||
slot: EquipmentSlot.armor,
|
||||
);
|
||||
final starterShield = Item(
|
||||
id: "starter_shield",
|
||||
name: "Wooden Shield",
|
||||
description: "A small shield",
|
||||
atkBonus: 0,
|
||||
hpBonus: 0,
|
||||
armorBonus: 3,
|
||||
slot: EquipmentSlot.shield,
|
||||
);
|
||||
final starterRing = Item(
|
||||
id: "starter_ring",
|
||||
name: "Copper Ring",
|
||||
description: "A simple ring",
|
||||
atkBonus: 1,
|
||||
hpBonus: 5,
|
||||
slot: EquipmentSlot.accessory,
|
||||
);
|
||||
// final starterSword = Item(
|
||||
// id: "starter_sword",
|
||||
// name: "Wooden Sword",
|
||||
// description: "A basic sword",
|
||||
// atkBonus: 5,
|
||||
// hpBonus: 0,
|
||||
// slot: EquipmentSlot.weapon,
|
||||
// );
|
||||
// final starterArmor = Item(
|
||||
// id: "starter_armor",
|
||||
// name: "Leather Armor",
|
||||
// description: "Basic protection",
|
||||
// atkBonus: 0,
|
||||
// hpBonus: 20,
|
||||
// slot: EquipmentSlot.armor,
|
||||
// );
|
||||
// final starterShield = Item(
|
||||
// id: "starter_shield",
|
||||
// name: "Wooden Shield",
|
||||
// description: "A small shield",
|
||||
// atkBonus: 0,
|
||||
// hpBonus: 0,
|
||||
// armorBonus: 3,
|
||||
// slot: EquipmentSlot.shield,
|
||||
// );
|
||||
// final starterRing = Item(
|
||||
// id: "starter_ring",
|
||||
// name: "Copper Ring",
|
||||
// description: "A simple ring",
|
||||
// atkBonus: 1,
|
||||
// hpBonus: 5,
|
||||
// slot: EquipmentSlot.accessory,
|
||||
// );
|
||||
|
||||
player.addToInventory(starterSword);
|
||||
player.equip(starterSword);
|
||||
// player.addToInventory(starterSword);
|
||||
// player.equip(starterSword);
|
||||
|
||||
player.addToInventory(starterArmor);
|
||||
player.equip(starterArmor);
|
||||
// player.addToInventory(starterArmor);
|
||||
// player.equip(starterArmor);
|
||||
|
||||
player.addToInventory(starterShield);
|
||||
player.equip(starterShield);
|
||||
// player.addToInventory(starterShield);
|
||||
// player.equip(starterShield);
|
||||
|
||||
player.addToInventory(starterRing);
|
||||
player.equip(starterRing);
|
||||
// player.addToInventory(starterRing);
|
||||
// player.equip(starterRing);
|
||||
|
||||
// Add new status effect items for testing
|
||||
player.addToInventory(ItemTable.weapons[3].createItem()); // Stunning Hammer
|
||||
@@ -194,36 +198,8 @@ class BattleProvider with ChangeNotifier {
|
||||
|
||||
if (type == StageType.battle || type == StageType.elite) {
|
||||
bool isElite = type == StageType.elite;
|
||||
// Select random enemy template
|
||||
final random = Random();
|
||||
EnemyTemplate template;
|
||||
if (isElite) {
|
||||
if (EnemyTable.eliteEnemies.isNotEmpty) {
|
||||
template = EnemyTable
|
||||
.eliteEnemies[random.nextInt(EnemyTable.eliteEnemies.length)];
|
||||
} else {
|
||||
// Fallback if no elite enemies loaded
|
||||
template = const EnemyTemplate(
|
||||
name: "Elite Guardian",
|
||||
baseHp: 50,
|
||||
baseAtk: 10,
|
||||
baseDefense: 2,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (EnemyTable.normalEnemies.isNotEmpty) {
|
||||
template = EnemyTable
|
||||
.normalEnemies[random.nextInt(EnemyTable.normalEnemies.length)];
|
||||
} else {
|
||||
// Fallback
|
||||
template = const EnemyTemplate(
|
||||
name: "Enemy",
|
||||
baseHp: 20,
|
||||
baseAtk: 5,
|
||||
baseDefense: 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
EnemyTemplate template = EnemyTable.getRandomEnemy(stage: stage, isElite: isElite);
|
||||
|
||||
newEnemy = template.createCharacter(stage: stage);
|
||||
|
||||
@@ -264,6 +240,12 @@ class BattleProvider with ChangeNotifier {
|
||||
// Replaces _spawnEnemy
|
||||
// void _spawnEnemy() { ... } - Removed
|
||||
|
||||
Future<void> _onDefeat() async {
|
||||
_addLog("Player defeated! Enemy wins!");
|
||||
await SaveManager.clearSaveData();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Handle player's action choice
|
||||
|
||||
Future<void> playerAction(ActionType type, RiskLevel risk) async {
|
||||
@@ -287,6 +269,12 @@ class BattleProvider with ChangeNotifier {
|
||||
|
||||
// 2. Process Start-of-Turn Effects (Stun, Bleed)
|
||||
bool canAct = _processStartTurnEffects(player);
|
||||
|
||||
if (player.isDead) {
|
||||
await _onDefeat();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!canAct) {
|
||||
_endPlayerTurn(); // Skip turn if stunned
|
||||
return;
|
||||
@@ -341,11 +329,17 @@ class BattleProvider with ChangeNotifier {
|
||||
|
||||
// Animation Delays to sync with Impact
|
||||
if (risk == RiskLevel.safe) {
|
||||
await Future.delayed(const Duration(milliseconds: GameConfig.animDelaySafe));
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: GameConfig.animDelaySafe),
|
||||
);
|
||||
} else if (risk == RiskLevel.normal) {
|
||||
await Future.delayed(const Duration(milliseconds: GameConfig.animDelayNormal));
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: GameConfig.animDelayNormal),
|
||||
);
|
||||
} else if (risk == RiskLevel.risky) {
|
||||
await Future.delayed(const Duration(milliseconds: GameConfig.animDelayRisky));
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: GameConfig.animDelayRisky),
|
||||
);
|
||||
}
|
||||
|
||||
int damageToHp = 0;
|
||||
@@ -437,14 +431,19 @@ class BattleProvider with ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
Future.delayed(const Duration(milliseconds: GameConfig.animDelayEnemyTurn), () => _enemyTurn());
|
||||
Future.delayed(
|
||||
const Duration(milliseconds: GameConfig.animDelayEnemyTurn),
|
||||
() => _enemyTurn(),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _enemyTurn() async {
|
||||
if (!isPlayerTurn && (player.isDead || enemy.isDead)) return;
|
||||
|
||||
_addLog("Enemy's turn...");
|
||||
await Future.delayed(const Duration(milliseconds: GameConfig.animDelayEnemyTurn));
|
||||
await Future.delayed(
|
||||
const Duration(milliseconds: GameConfig.animDelayEnemyTurn),
|
||||
);
|
||||
|
||||
// Enemy Turn Start Logic
|
||||
// Armor decay
|
||||
@@ -543,7 +542,8 @@ class BattleProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
if (player.isDead) {
|
||||
_addLog("Player defeated! Enemy wins!");
|
||||
await _onDefeat();
|
||||
return;
|
||||
}
|
||||
|
||||
isPlayerTurn = true;
|
||||
@@ -654,15 +654,6 @@ class BattleProvider with ChangeNotifier {
|
||||
_addLog("Enemy defeated! Gained $goldReward Gold.");
|
||||
_addLog("Choose a reward.");
|
||||
|
||||
List<ItemTemplate> allTemplates = List.from(ItemTable.allItems);
|
||||
allTemplates.shuffle(random); // Shuffle to randomize selection
|
||||
|
||||
// Item Rewards
|
||||
// Logic: Get random items based on current round tier? For now just random.
|
||||
// Ideally should use ItemTable.getRandomItem() with Tier logic.
|
||||
// Let's use our new weighted random logic if available, or fallback to simple shuffle for now to keep it simple.
|
||||
// Since we just refactored ItemTable, let's use getRandomItem!
|
||||
|
||||
ItemTier currentTier = ItemTier.tier1;
|
||||
if (stage > GameConfig.tier2StageMax)
|
||||
currentTier = ItemTier.tier3;
|
||||
@@ -670,9 +661,42 @@ class BattleProvider with ChangeNotifier {
|
||||
currentTier = ItemTier.tier2;
|
||||
|
||||
rewardOptions = [];
|
||||
// Get 3 distinct items if possible
|
||||
|
||||
bool isElite = currentStage.type == StageType.elite;
|
||||
bool isTier1 = currentTier == ItemTier.tier1;
|
||||
|
||||
// Get 3 distinct items
|
||||
for (int i = 0; i < 3; i++) {
|
||||
ItemTemplate? item = ItemTable.getRandomItem(tier: currentTier);
|
||||
ItemRarity? minRarity;
|
||||
ItemRarity? maxRarity;
|
||||
|
||||
// 1. Elite Reward Logic (First Item only)
|
||||
if (isElite && i == 0) {
|
||||
if (isTier1) {
|
||||
// Tier 1 Elite: Guaranteed Rare
|
||||
minRarity = ItemRarity.rare;
|
||||
maxRarity = ItemRarity.rare; // Or allow higher? Request said "Guaranteed Rare 1 drop". Let's fix to Rare.
|
||||
} else {
|
||||
// Tier 2/3 Elite: Guaranteed Legendary
|
||||
minRarity = ItemRarity.legendary;
|
||||
// maxRarity = ItemRarity.legendary; // Optional, but let's allow Unique too if weights permit, or fix to Legendary. Request said "Guaranteed Legendary".
|
||||
}
|
||||
}
|
||||
// 2. Standard Reward Logic (Others)
|
||||
else {
|
||||
if (isTier1) {
|
||||
// Tier 1 Normal/Other Rewards: Max Magic (No Rare+)
|
||||
maxRarity = ItemRarity.magic;
|
||||
}
|
||||
// Tier 2/3 Normal: No extra restrictions
|
||||
}
|
||||
|
||||
ItemTemplate? item = ItemTable.getRandomItem(
|
||||
tier: currentTier,
|
||||
minRarity: minRarity,
|
||||
maxRarity: maxRarity
|
||||
);
|
||||
|
||||
if (item != null) {
|
||||
rewardOptions.add(item.createItem(stage: stage));
|
||||
}
|
||||
@@ -716,7 +740,9 @@ class BattleProvider with ChangeNotifier {
|
||||
|
||||
void _completeStage() {
|
||||
// Heal player after selecting reward
|
||||
int healAmount = GameMath.floor(player.totalMaxHp * GameConfig.stageHealRatio);
|
||||
int healAmount = GameMath.floor(
|
||||
player.totalMaxHp * GameConfig.stageHealRatio,
|
||||
);
|
||||
player.heal(healAmount);
|
||||
_addLog("Stage Cleared! Recovered $healAmount HP.");
|
||||
|
||||
@@ -760,7 +786,9 @@ class BattleProvider with ChangeNotifier {
|
||||
|
||||
void sellItem(Item item) {
|
||||
if (player.inventory.remove(item)) {
|
||||
int sellPrice = GameMath.floor(item.price * GameConfig.sellPriceMultiplier);
|
||||
int sellPrice = GameMath.floor(
|
||||
item.price * GameConfig.sellPriceMultiplier,
|
||||
);
|
||||
player.gold += sellPrice;
|
||||
_addLog("Sold ${item.name} for $sellPrice G.");
|
||||
notifyListeners();
|
||||
|
||||
Reference in New Issue
Block a user