update
This commit is contained in:
@@ -1,19 +1,17 @@
|
||||
import 'dart:async'; // StreamController 사용을 위해 import
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../game/model/entity.dart';
|
||||
import '../game/model/item.dart';
|
||||
import '../game/model/status_effect.dart';
|
||||
import '../game/model/stage.dart'; // Import StageModel
|
||||
import '../game/model/stage.dart';
|
||||
import '../game/data/item_table.dart';
|
||||
import '../game/data/enemy_table.dart';
|
||||
import '../utils/game_math.dart';
|
||||
|
||||
enum ActionType { attack, defend }
|
||||
|
||||
enum RiskLevel { safe, normal, risky }
|
||||
|
||||
enum EnemyActionType { attack, defend }
|
||||
import '../game/enums.dart';
|
||||
import '../game/model/damage_event.dart'; // DamageEvent import
|
||||
import '../game/model/effect_event.dart'; // EffectEvent import
|
||||
|
||||
class EnemyIntent {
|
||||
final EnemyActionType type;
|
||||
@@ -43,10 +41,25 @@ class BattleProvider with ChangeNotifier {
|
||||
List<Item> rewardOptions = [];
|
||||
bool showRewardPopup = false;
|
||||
|
||||
// Damage Event Stream
|
||||
final _damageEventController = StreamController<DamageEvent>.broadcast();
|
||||
Stream<DamageEvent> get damageStream => _damageEventController.stream;
|
||||
|
||||
// Effect Event Stream
|
||||
final _effectEventController = StreamController<EffectEvent>.broadcast();
|
||||
Stream<EffectEvent> get effectStream => _effectEventController.stream;
|
||||
|
||||
BattleProvider() {
|
||||
// initializeBattle(); // Do not auto-start logic
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_damageEventController.close(); // StreamController 닫기
|
||||
_effectEventController.close();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void initializeBattle() {
|
||||
stage = 1;
|
||||
player = Character(
|
||||
@@ -254,20 +267,61 @@ class BattleProvider with ChangeNotifier {
|
||||
break;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
if (type == ActionType.attack) {
|
||||
int damage = (player.totalAtk * efficiency).toInt();
|
||||
_applyDamage(enemy, damage);
|
||||
_addLog("Player dealt $damage damage to Enemy.");
|
||||
if (success) {
|
||||
|
||||
// Try applying status effects from items
|
||||
_tryApplyStatusEffects(player, enemy);
|
||||
} else {
|
||||
int armorGained = (player.totalDefense * efficiency).toInt();
|
||||
player.armor += armorGained;
|
||||
_addLog("Player gained $armorGained armor.");
|
||||
}
|
||||
} else {
|
||||
if (type == ActionType.attack) {
|
||||
|
||||
int damage = (player.totalAtk * efficiency).toInt();
|
||||
|
||||
|
||||
|
||||
_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);
|
||||
|
||||
} 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!");
|
||||
}
|
||||
|
||||
@@ -305,28 +359,38 @@ class BattleProvider with ChangeNotifier {
|
||||
if (enemy.isDead) {
|
||||
_onVictory();
|
||||
return;
|
||||
// return; // Already handled by _processStartTurnEffects if damage applied
|
||||
}
|
||||
|
||||
if (canAct && currentEnemyIntent != null) {
|
||||
final intent = currentEnemyIntent!;
|
||||
|
||||
// Check Success Rate based on Risk
|
||||
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.type == EnemyActionType.defend) {
|
||||
// Already handled in _generateEnemyIntent
|
||||
_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 (success) {
|
||||
_effectEventController.sink.add(EffectEvent(
|
||||
type: ActionType.attack,
|
||||
risk: intent.risk,
|
||||
target: EffectTarget.player,
|
||||
));
|
||||
|
||||
if (success) {
|
||||
if (intent.type == EnemyActionType.attack) {
|
||||
int incomingDamage = intent.value;
|
||||
int damageToHp = 0;
|
||||
|
||||
@@ -346,16 +410,12 @@ class BattleProvider with ChangeNotifier {
|
||||
}
|
||||
|
||||
if (damageToHp > 0) {
|
||||
_applyDamage(player, damageToHp);
|
||||
_applyDamage(player, damageToHp, targetType: DamageTarget.player);
|
||||
_addLog("Enemy dealt $damageToHp damage to Player HP.");
|
||||
}
|
||||
} else if (intent.type == EnemyActionType.defend) {
|
||||
int armorGained = intent.value;
|
||||
enemy.armor += armorGained;
|
||||
_addLog("Enemy gained $armorGained armor.");
|
||||
} else {
|
||||
_addLog("Enemy's ${intent.risk.name} attack missed!");
|
||||
}
|
||||
} else {
|
||||
_addLog("Enemy's ${intent.risk.name} action missed!");
|
||||
}
|
||||
} else if (!canAct) {
|
||||
_addLog("Enemy is stunned and cannot act!");
|
||||
@@ -394,9 +454,25 @@ class BattleProvider with ChangeNotifier {
|
||||
.toList();
|
||||
if (bleedEffects.isNotEmpty) {
|
||||
int totalBleed = bleedEffects.fold(0, (sum, e) => sum + e.value);
|
||||
int previousHp = character.hp; // Record HP before damage
|
||||
character.hp -= totalBleed;
|
||||
if (character.hp < 0) character.hp = 0;
|
||||
_addLog("${character.name} takes $totalBleed bleed damage!");
|
||||
|
||||
// Emit DamageEvent for bleed
|
||||
if (character == player) {
|
||||
_damageEventController.sink.add(DamageEvent(
|
||||
damage: totalBleed,
|
||||
target: DamageTarget.player,
|
||||
color: Colors.purpleAccent, // Bleed damage color
|
||||
));
|
||||
} else if (character == enemy) {
|
||||
_damageEventController.sink.add(DamageEvent(
|
||||
damage: totalBleed,
|
||||
target: DamageTarget.enemy,
|
||||
color: Colors.purpleAccent, // Bleed damage color
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Stun Check
|
||||
@@ -429,15 +505,22 @@ class BattleProvider with ChangeNotifier {
|
||||
}
|
||||
}
|
||||
|
||||
void _applyDamage(Character target, int damage) {
|
||||
void _applyDamage(Character target, int damage, {required DamageTarget targetType, Color color = Colors.red}) {
|
||||
// Check Vulnerable
|
||||
if (target.hasStatus(StatusEffectType.vulnerable)) {
|
||||
damage = (damage * 1.5).toInt();
|
||||
_addLog("Vulnerable! Damage increased to $damage.");
|
||||
color = Colors.orange; // Vulnerable damage color
|
||||
}
|
||||
|
||||
target.hp -= damage;
|
||||
if (target.hp < 0) target.hp = 0;
|
||||
|
||||
_damageEventController.sink.add(DamageEvent(
|
||||
damage: damage,
|
||||
target: targetType,
|
||||
color: color,
|
||||
));
|
||||
}
|
||||
|
||||
void _addLog(String message) {
|
||||
@@ -589,7 +672,33 @@ class BattleProvider with ChangeNotifier {
|
||||
risk: risk,
|
||||
description: "Defends for $armor (${risk.name})",
|
||||
);
|
||||
|
||||
// [Changed] Apply defense immediately for pre-emptive defense
|
||||
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;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
enemy.armor += armor;
|
||||
_addLog("Enemy prepares defense! (+$armor Armor)");
|
||||
_effectEventController.sink.add(EffectEvent(
|
||||
type: ActionType.defend,
|
||||
risk: risk,
|
||||
target: EffectTarget.enemy,
|
||||
));
|
||||
} else {
|
||||
_addLog("Enemy tried to defend but fumbled!");
|
||||
}
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user