game/lib/game/model/entity.dart

167 lines
4.6 KiB
Dart

import 'item.dart';
import 'status_effect.dart';
class Character {
String name;
int hp;
int baseMaxHp;
int armor; // Current temporary shield/armor points in battle
int baseAtk;
int baseDefense; // Base defense stat
int gold; // New: Currency
String? image; // New: Image path
Map<EquipmentSlot, Item> equipment = {};
List<Item> inventory = [];
final int maxInventorySize = 16;
// Active status effects
List<StatusEffect> statusEffects = [];
Character({
required this.name,
int? hp,
required int maxHp,
required this.armor,
required int atk,
this.baseDefense = 0,
this.gold = 0,
this.image,
}) : baseMaxHp = maxHp,
baseAtk = atk,
hp = hp ?? maxHp;
/// Adds a status effect. If it already exists, it refreshes duration or stacks based on logic.
/// For now, we'll implement a simple refresh/overwrite logic.
void addStatusEffect(StatusEffect newEffect) {
// Check if effect exists
var existing = statusEffects
.where((e) => e.type == newEffect.type)
.firstOrNull;
if (existing != null) {
// Refresh duration if the new one is longer, or just reset it?
// Let's max the duration for now.
if (newEffect.duration > existing.duration) {
existing.duration = newEffect.duration;
}
// Logic for 'value' (stacking bleed?) can be added here.
} else {
statusEffects.add(newEffect);
}
}
/// Decrements duration of all effects and removes expired ones.
/// Returns a list of expired effects if needed for UI logs.
void updateStatusEffects() {
// Remove effects with 0 or less duration first (safety cleanup)
statusEffects.removeWhere((e) => e.duration <= 0);
for (var effect in statusEffects) {
effect.duration--;
}
// Remove effects that just expired (duration went to 0 or -1)
statusEffects.removeWhere((e) => e.duration <= 0);
}
/// Helper to check if character has a specific status
bool hasStatus(StatusEffectType type) {
return statusEffects.any((e) => e.type == type);
}
int get totalMaxHp {
int bonus = equipment.values.fold(0, (sum, item) => sum + item.hpBonus);
return baseMaxHp + bonus;
}
int get totalAtk {
int bonus = equipment.values.fold(0, (sum, item) => sum + item.atkBonus);
return baseAtk + bonus;
}
int get totalDefense {
int bonus = equipment.values.fold(0, (sum, item) => sum + item.armorBonus);
return baseDefense + bonus;
}
bool get isDead => hp <= 0;
// Adds an item to inventory, returns true if successful, false if inventory is full
bool addToInventory(Item item) {
if (inventory.length < maxInventorySize) {
inventory.add(item);
return true;
}
return false;
}
// Equips an item (swapping if necessary)
// Returns true if successful
bool equip(Item newItem) {
if (!inventory.contains(newItem)) return false;
// 1. Calculate current HP ratio before any changes
double hpRatio = totalMaxHp > 0
? hp / totalMaxHp
: 0.0; // Avoid division by zero
// 2. Handle Swap: If slot is occupied, unequip the old item first
if (equipment.containsKey(newItem.slot)) {
Item oldItem = equipment[newItem.slot]!;
equipment.remove(newItem.slot);
inventory.add(oldItem);
}
// 3. Move new item: Inventory -> Equipment
inventory.remove(newItem);
equipment[newItem.slot] = newItem;
// 4. Update current HP based on the new totalMaxHp and previous ratio
hp = (totalMaxHp * hpRatio).toInt();
if (hp < 0) hp = 0; // Ensure HP does not go below zero
if (hp > totalMaxHp) {
hp =
totalMaxHp; // Final Safety Clamp, though hpRatio <= 1.0 should prevent this
}
return true;
}
// Unequips an item
// Returns true if successful (inventory has space)
bool unequip(Item item) {
if (!equipment.containsValue(item)) return false;
// 1. Calculate current HP ratio before any changes
double hpRatio = totalMaxHp > 0
? hp / totalMaxHp
: 0.0; // Avoid division by zero
if (inventory.length < maxInventorySize) {
equipment.remove(item.slot);
inventory.add(item);
// 2. Update current HP based on the new totalMaxHp and previous ratio
hp = (totalMaxHp * hpRatio).toInt();
if (hp < 0) hp = 0; // Ensure HP does not go below zero
if (hp > totalMaxHp) {
hp =
totalMaxHp; // Final Safety Clamp, though hpRatio <= 1.0 should prevent this
}
return true;
}
return false;
}
void heal(int amount) {
if (isDead) return; // Cannot heal if dead
hp += amount;
if (hp > totalMaxHp) {
hp = totalMaxHp;
}
}
}