import 'dart:math'; import 'package:flutter/foundation.dart'; import '../game/model/entity.dart'; import '../game/model/item.dart'; import '../game/data/item_table.dart'; // Import ItemTable import '../utils/game_math.dart'; // Import GameMath enum ActionType { attack, defend } enum RiskLevel { safe, normal, risky } class BattleProvider with ChangeNotifier { late Character player; late Character enemy; List battleLogs = []; bool isPlayerTurn = true; int stage = 1; List rewardOptions = []; bool showRewardPopup = false; BattleProvider() { initializeBattle(); } void initializeBattle() { stage = 1; player = Character(name: "Player", maxHp: 100, armor: 0, atk: 10, baseDefense: 5); // Added baseDefense 5 // Provide starter equipment final starterSword = Item(name: "Wooden Sword", description: "A basic sword", atkBonus: 5, hpBonus: 0, slot: EquipmentSlot.weapon); final starterArmor = Item(name: "Leather Armor", description: "Basic protection", atkBonus: 0, hpBonus: 20, slot: EquipmentSlot.armor); final starterShield = Item(name: "Wooden Shield", description: "A small shield", atkBonus: 0, hpBonus: 0, armorBonus: 3, slot: EquipmentSlot.shield); final starterRing = Item(name: "Copper Ring", description: "A simple ring", atkBonus: 1, hpBonus: 5, slot: EquipmentSlot.accessory); player.addToInventory(starterSword); player.equip(starterSword); player.addToInventory(starterArmor); player.equip(starterArmor); player.addToInventory(starterShield); player.equip(starterShield); player.addToInventory(starterRing); player.equip(starterRing); _spawnEnemy(); battleLogs.clear(); _addLog("Battle started! Stage $stage"); isPlayerTurn = true; showRewardPopup = false; notifyListeners(); } void _spawnEnemy() { int enemyHp = 5 + (stage - 1) * 20; int enemyAtk = 8 + (stage - 1) * 2; enemy = Character(name: "Enemy", maxHp: enemyHp, armor: 0, atk: enemyAtk); } void playerAction(ActionType type, RiskLevel risk) { if (!isPlayerTurn || player.isDead || enemy.isDead || showRewardPopup) return; isPlayerTurn = false; notifyListeners(); _addLog("Player chose to ${type.name} with ${risk.name} risk."); final random = Random(); bool success = false; double efficiency = 1.0; switch (risk) { case RiskLevel.safe: success = random.nextDouble() < 1.0; // 100% efficiency = 0.5; // 50% break; case RiskLevel.normal: success = random.nextDouble() < 0.8; // 80% efficiency = 1.0; // 100% break; case RiskLevel.risky: success = random.nextDouble() < 0.4; // 40% efficiency = 2.0; // 200% break; } if (success) { if (type == ActionType.attack) { int damage = (player.totalAtk * efficiency).toInt(); _applyDamage(enemy, damage); _addLog("Player dealt $damage damage to Enemy."); } else { int armorGained = (player.totalDefense * efficiency).toInt(); // Changed to totalDefense player.armor += armorGained; _addLog("Player gained $armorGained armor."); } } else { _addLog("Player's action missed!"); } if (enemy.isDead) { _onVictory(); return; } Future.delayed(const Duration(seconds: 1), () => _enemyTurn()); } Future _enemyTurn() async { if (!isPlayerTurn && (player.isDead || enemy.isDead)) return; // Check if it's the enemy's turn and battle is over _addLog("Enemy's turn..."); // Enemy attacks player await Future.delayed(const Duration(seconds: 1)); // Simulating thinking time int incomingDamage = enemy.totalAtk; int damageToHp = 0; if (player.armor > 0) { if (player.armor >= incomingDamage) { player.armor -= incomingDamage; damageToHp = 0; _addLog("Armor absorbed all $incomingDamage damage."); } else { damageToHp = incomingDamage - player.armor; _addLog("Armor absorbed ${player.armor} damage."); player.armor = 0; } } else { damageToHp = incomingDamage; } if (damageToHp > 0) { _applyDamage(player, damageToHp); _addLog("Enemy dealt $damageToHp damage to Player HP."); } // Player's turn starts, armor decays if (player.armor > 0) { player.armor = (player.armor * 0.5).toInt(); _addLog("Player's armor decayed to ${player.armor}."); } if (player.isDead) { _addLog("Player defeated! Enemy wins!"); } isPlayerTurn = true; notifyListeners(); } void _applyDamage(Character target, int damage) { target.hp -= damage; if (target.hp < 0) target.hp = 0; } void _addLog(String message) { battleLogs.add(message); notifyListeners(); } void _onVictory() { _addLog("Enemy defeated! Choose a reward."); final random = Random(); List allTemplates = List.from(ItemTable.allItems); allTemplates.shuffle(random); // Shuffle to randomize selection // Take first 3 items (ensure distinct templates if possible, though list is small now) int count = min(3, allTemplates.length); rewardOptions = allTemplates.sublist(0, count).map((template) { return template.createItem(stage: stage); }).toList(); showRewardPopup = true; notifyListeners(); } void selectReward(Item item) { bool added = player.addToInventory(item); if (added) { _addLog("Added ${item.name} to inventory."); } else { _addLog("Inventory is full! ${item.name} discarded."); } // Heal player after selecting reward int healAmount = GameMath.floor(player.totalMaxHp * 0.5); player.heal(healAmount); _addLog("Stage Cleared! Recovered $healAmount HP."); stage++; showRewardPopup = false; _spawnEnemy(); _addLog("Stage $stage started! A wild ${enemy.name} appeared."); isPlayerTurn = true; notifyListeners(); } void equipItem(Item item) { if (player.equip(item)) { _addLog("Equipped ${item.name}."); } else { _addLog("Failed to equip ${item.name}."); // Should not happen if logic is correct } notifyListeners(); } void unequipItem(Item item) { if (player.unequip(item)) { _addLog("Unequipped ${item.name}."); } else { _addLog("Failed to unequip ${item.name} (Inventory might be full)."); } notifyListeners(); } }