This commit is contained in:
2025-12-03 17:28:49 +09:00
parent 36f93ccbcc
commit 526377bb73
18 changed files with 926 additions and 448 deletions
+150 -115
View File
@@ -18,12 +18,16 @@ class EnemyIntent {
final int value;
final RiskLevel risk;
final String description;
final bool isSuccess;
final int finalValue;
EnemyIntent({
required this.type,
required this.value,
required this.risk,
required this.description,
required this.isSuccess,
required this.finalValue,
});
}
@@ -38,9 +42,12 @@ class BattleProvider with ChangeNotifier {
bool isPlayerTurn = true;
int stage = 1;
int turnCount = 1;
List<Item> rewardOptions = [];
bool showRewardPopup = false;
List<String> get logs => battleLogs;
// Damage Event Stream
final _damageEventController = StreamController<DamageEvent>.broadcast();
Stream<DamageEvent> get damageStream => _damageEventController.stream;
@@ -62,11 +69,12 @@ class BattleProvider with ChangeNotifier {
void initializeBattle() {
stage = 1;
turnCount = 1;
player = Character(
name: "Player",
maxHp: 100,
maxHp: 80,
armor: 0,
atk: 10,
atk: 5,
baseDefense: 5,
);
@@ -213,6 +221,7 @@ class BattleProvider with ChangeNotifier {
enemy: newEnemy,
shopItems: shopItems,
);
turnCount = 1;
notifyListeners();
}
@@ -267,61 +276,63 @@ class BattleProvider with ChangeNotifier {
break;
}
if (success) {
if (success) {
if (type == ActionType.attack) {
int damage = (player.totalAtk * efficiency).toInt();
if (type == ActionType.attack) {
_effectEventController.sink.add(
EffectEvent(
type: ActionType.attack,
int damage = (player.totalAtk * efficiency).toInt();
risk: risk,
_effectEventController.sink.add(EffectEvent(
type: ActionType.attack,
risk: risk,
target: EffectTarget.enemy,
));
_applyDamage(enemy, damage, targetType: DamageTarget.enemy); // Add targetType
_addLog("Player dealt $damage damage to Enemy.");
// Try applying status effects from items
_tryApplyStatusEffects(player, enemy);
target: EffectTarget.enemy,
),
);
int damageToHp = 0;
if (enemy.armor > 0) {
if (enemy.armor >= damage) {
enemy.armor -= damage;
damageToHp = 0;
_addLog("Enemy's armor absorbed all $damage damage.");
} else {
_effectEventController.sink.add(EffectEvent(
type: ActionType.defend,
risk: risk,
target: EffectTarget.player,
));
int armorGained = (player.totalDefense * efficiency).toInt();
player.armor += armorGained;
_addLog("Player gained $armorGained armor.");
damageToHp = damage - enemy.armor;
_addLog("Enemy's armor absorbed ${enemy.armor} damage.");
enemy.armor = 0;
}
} else {
damageToHp = damage;
}
else {
if (damageToHp > 0) {
_applyDamage(enemy, damageToHp, targetType: DamageTarget.enemy);
_addLog("Player dealt $damageToHp damage to Enemy.");
} else {
_addLog("Player's attack was fully blocked by armor.");
}
// Try applying status effects from items
_tryApplyStatusEffects(player, enemy);
} else {
_effectEventController.sink.add(
EffectEvent(
type: ActionType.defend,
risk: risk,
target: EffectTarget.player,
),
);
int armorGained = (player.totalDefense * efficiency).toInt();
player.armor += armorGained;
_addLog("Player gained $armorGained armor.");
}
} else {
_addLog("Player's action missed!");
}
@@ -352,6 +363,13 @@ class BattleProvider with ChangeNotifier {
_addLog("Enemy's turn...");
await Future.delayed(const Duration(seconds: 1));
// Enemy Turn Start Logic
// Armor decay
if (enemy.armor > 0) {
enemy.armor = (enemy.armor * 0.5).toInt();
_addLog("Enemy's armor decayed to ${enemy.armor}.");
}
// 1. Process Start-of-Turn Effects for Enemy
bool canAct = _processStartTurnEffects(enemy);
@@ -370,28 +388,16 @@ class BattleProvider with ChangeNotifier {
_addLog("Enemy maintains defensive stance.");
} else {
// Attack Logic
final random = Random();
bool success = false;
switch (intent.risk) {
case RiskLevel.safe:
success = random.nextDouble() < 1.0;
break;
case RiskLevel.normal:
success = random.nextDouble() < 0.8;
break;
case RiskLevel.risky:
success = random.nextDouble() < 0.4;
break;
}
if (intent.isSuccess) {
_effectEventController.sink.add(
EffectEvent(
type: ActionType.attack,
risk: intent.risk,
target: EffectTarget.player,
),
);
if (success) {
_effectEventController.sink.add(EffectEvent(
type: ActionType.attack,
risk: intent.risk,
target: EffectTarget.player,
));
int incomingDamage = intent.value;
int incomingDamage = intent.finalValue;
int damageToHp = 0;
// Handle Player Armor
@@ -440,6 +446,7 @@ class BattleProvider with ChangeNotifier {
}
isPlayerTurn = true;
turnCount++;
notifyListeners();
}
@@ -461,17 +468,21 @@ class BattleProvider with ChangeNotifier {
// Emit DamageEvent for bleed
if (character == player) {
_damageEventController.sink.add(DamageEvent(
damage: totalBleed,
target: DamageTarget.player,
color: Colors.purpleAccent, // Bleed damage color
));
_damageEventController.sink.add(
DamageEvent(
damage: totalBleed,
target: DamageTarget.player,
type: DamageType.bleed,
),
);
} else if (character == enemy) {
_damageEventController.sink.add(DamageEvent(
damage: totalBleed,
target: DamageTarget.enemy,
color: Colors.purpleAccent, // Bleed damage color
));
_damageEventController.sink.add(
DamageEvent(
damage: totalBleed,
target: DamageTarget.enemy,
type: DamageType.bleed,
),
);
}
}
@@ -505,22 +516,25 @@ class BattleProvider with ChangeNotifier {
}
}
void _applyDamage(Character target, int damage, {required DamageTarget targetType, Color color = Colors.red}) {
void _applyDamage(
Character target,
int damage, {
required DamageTarget targetType,
DamageType type = DamageType.normal,
}) {
// Check Vulnerable
if (target.hasStatus(StatusEffectType.vulnerable)) {
damage = (damage * 1.5).toInt();
_addLog("Vulnerable! Damage increased to $damage.");
color = Colors.orange; // Vulnerable damage color
type = DamageType.vulnerable;
}
target.hp -= damage;
if (target.hp < 0) target.hp = 0;
_damageEventController.sink.add(DamageEvent(
damage: damage,
target: targetType,
color: color,
));
_damageEventController.sink.add(
DamageEvent(damage: damage, target: targetType, type: type),
);
}
void _addLog(String message) {
@@ -554,7 +568,7 @@ class BattleProvider with ChangeNotifier {
}
// Heal player after selecting reward
int healAmount = GameMath.floor(player.totalMaxHp * 0.5);
int healAmount = GameMath.floor(player.totalMaxHp * 0.1);
player.heal(healAmount);
_addLog("Stage Cleared! Recovered $healAmount HP.");
@@ -653,27 +667,7 @@ class BattleProvider with ChangeNotifier {
int damage = (enemy.totalAtk * efficiency * variance).toInt();
if (damage < 1) damage = 1;
currentEnemyIntent = EnemyIntent(
type: EnemyActionType.attack,
value: damage,
risk: risk,
description: "Attacks for $damage (${risk.name})",
);
} else {
// Defend Intent
int baseDef = enemy.totalDefense;
// Variance
double variance = 0.8 + random.nextDouble() * 0.4;
int armor = (baseDef * 2 * efficiency * variance).toInt();
currentEnemyIntent = EnemyIntent(
type: EnemyActionType.defend,
value: armor,
risk: risk,
description: "Defends for $armor (${risk.name})",
);
// [Changed] Apply defense immediately for pre-emptive defense
// Calculate success immediately
bool success = false;
switch (risk) {
case RiskLevel.safe:
@@ -687,18 +681,59 @@ class BattleProvider with ChangeNotifier {
break;
}
currentEnemyIntent = EnemyIntent(
type: EnemyActionType.attack,
value: damage,
risk: risk,
description: "Attacks for $damage (${risk.name})",
isSuccess: success,
finalValue: damage,
);
} else {
// Defend Intent
int baseDef = enemy.totalDefense;
// Variance
double variance = 0.8 + random.nextDouble() * 0.4;
int armor = (baseDef * 2 * efficiency * variance).toInt();
// Calculate success immediately
bool success = false;
switch (risk) {
case RiskLevel.safe:
success = random.nextDouble() < 1.0;
break;
case RiskLevel.normal:
success = random.nextDouble() < 0.8;
break;
case RiskLevel.risky:
success = random.nextDouble() < 0.4;
break;
}
currentEnemyIntent = EnemyIntent(
type: EnemyActionType.defend,
value: armor,
risk: risk,
description: "Defends for $armor (${risk.name})",
isSuccess: success,
finalValue: armor,
);
// Apply defense immediately if successful
if (success) {
enemy.armor += armor;
_addLog("Enemy prepares defense! (+$armor Armor)");
_effectEventController.sink.add(EffectEvent(
type: ActionType.defend,
risk: risk,
target: EffectTarget.enemy,
));
_effectEventController.sink.add(
EffectEvent(
type: ActionType.defend,
risk: risk,
target: EffectTarget.enemy,
),
);
} else {
_addLog("Enemy tried to defend but fumbled!");
}
}
notifyListeners();
}
}
}