167 lines
4.6 KiB
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;
|
|
}
|
|
}
|
|
}
|