update
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
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<String> battleLogs = [];
|
||||
bool isPlayerTurn = true;
|
||||
|
||||
int stage = 1;
|
||||
List<Item> 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<void> _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<ItemTemplate> 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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user