Compare commits
No commits in common. "cb48d0db48e1d6e67e03bc92d6bfbd1c439ebcda" and "e020e44d8f20c60e7a4ac6977f02840808dc70d2" have entirely different histories.
cb48d0db48
...
e020e44d8f
Binary file not shown.
|
Before Width: | Height: | Size: 465 B |
Binary file not shown.
|
Before Width: | Height: | Size: 556 B |
|
|
@ -15,13 +15,6 @@ import 'shop_provider.dart';
|
|||
|
||||
import '../game/logic.dart';
|
||||
|
||||
class TurnEffectResult {
|
||||
final bool canAct;
|
||||
final bool effectTriggered;
|
||||
|
||||
TurnEffectResult({required this.canAct, required this.effectTriggered});
|
||||
}
|
||||
|
||||
class EnemyIntent {
|
||||
final EnemyActionType type;
|
||||
final int value;
|
||||
|
|
@ -232,9 +225,8 @@ class BattleProvider with ChangeNotifier {
|
|||
|
||||
/// Handle player's action choice
|
||||
Future<void> playerAction(ActionType type, RiskLevel risk) async {
|
||||
if (!isPlayerTurn || player.isDead || enemy.isDead || showRewardPopup) {
|
||||
if (!isPlayerTurn || player.isDead || enemy.isDead || showRewardPopup)
|
||||
return;
|
||||
}
|
||||
|
||||
// 0. Ensure Pre-emptive Enemy Defense is applied (if not already via animation)
|
||||
applyPendingEnemyDefense();
|
||||
|
|
@ -253,19 +245,14 @@ class BattleProvider with ChangeNotifier {
|
|||
notifyListeners();
|
||||
|
||||
// 2. Process Start-of-Turn Effects (Stun, Bleed)
|
||||
TurnEffectResult turnEffect = _processStartTurnEffects(player);
|
||||
bool canAct = _processStartTurnEffects(player);
|
||||
|
||||
if (player.isDead) {
|
||||
await _onDefeat();
|
||||
return;
|
||||
}
|
||||
|
||||
// If a visual effect occurred (bleed, stun), wait a bit before action
|
||||
if (turnEffect.effectTriggered) {
|
||||
await Future.delayed(const Duration(milliseconds: 800));
|
||||
}
|
||||
|
||||
if (!turnEffect.canAct) {
|
||||
if (!canAct) {
|
||||
_endPlayerTurn(); // Skip turn if stunned
|
||||
return;
|
||||
}
|
||||
|
|
@ -487,12 +474,11 @@ class BattleProvider with ChangeNotifier {
|
|||
}
|
||||
|
||||
/// Check Status Effects at Start of Turn
|
||||
TurnEffectResult _processStartTurnEffects(Character character) {
|
||||
bool _processStartTurnEffects(Character character) {
|
||||
final result = CombatCalculator.processStartTurnEffects(character);
|
||||
|
||||
int totalBleed = result['bleedDamage'];
|
||||
bool isStunned = result['isStunned'];
|
||||
bool effectTriggered = false;
|
||||
|
||||
// 1. Bleed Damage
|
||||
if (totalBleed > 0) {
|
||||
|
|
@ -510,19 +496,14 @@ class BattleProvider with ChangeNotifier {
|
|||
type: DamageType.bleed,
|
||||
),
|
||||
);
|
||||
effectTriggered = true;
|
||||
}
|
||||
|
||||
// 2. Stun Check
|
||||
if (isStunned) {
|
||||
_addLog("${character.name} is stunned!");
|
||||
effectTriggered = true;
|
||||
}
|
||||
|
||||
return TurnEffectResult(
|
||||
canAct: !isStunned,
|
||||
effectTriggered: effectTriggered,
|
||||
);
|
||||
return !isStunned;
|
||||
}
|
||||
|
||||
// --- Turn Management Phases ---
|
||||
|
|
@ -541,19 +522,14 @@ class BattleProvider with ChangeNotifier {
|
|||
}
|
||||
|
||||
// Process Start-of-Turn Effects
|
||||
TurnEffectResult turnEffect = _processStartTurnEffects(enemy);
|
||||
bool canAct = _processStartTurnEffects(enemy);
|
||||
|
||||
if (enemy.isDead) {
|
||||
_onVictory();
|
||||
return;
|
||||
}
|
||||
|
||||
// If a visual effect occurred (bleed, stun), wait a bit before action
|
||||
if (turnEffect.effectTriggered) {
|
||||
await Future.delayed(const Duration(milliseconds: 800));
|
||||
}
|
||||
|
||||
if (turnEffect.canAct && currentEnemyIntent != null) {
|
||||
if (canAct && currentEnemyIntent != null) {
|
||||
final intent = currentEnemyIntent!;
|
||||
|
||||
if (intent.type == EnemyActionType.defend) {
|
||||
|
|
@ -641,7 +617,7 @@ class BattleProvider with ChangeNotifier {
|
|||
return;
|
||||
}
|
||||
}
|
||||
} else if (!turnEffect.canAct) {
|
||||
} else if (!canAct) {
|
||||
// If cannot act (stunned)
|
||||
_addLog("Enemy is stunned and cannot act!");
|
||||
int tid = _turnTransactionId;
|
||||
|
|
@ -698,11 +674,10 @@ class BattleProvider with ChangeNotifier {
|
|||
_addLog("Choose a reward.");
|
||||
|
||||
ItemTier currentTier = ItemTier.tier1;
|
||||
if (stage > GameConfig.tier2StageMax) {
|
||||
if (stage > GameConfig.tier2StageMax)
|
||||
currentTier = ItemTier.tier3;
|
||||
} else if (stage > GameConfig.tier1StageMax) {
|
||||
else if (stage > GameConfig.tier1StageMax)
|
||||
currentTier = ItemTier.tier2;
|
||||
}
|
||||
|
||||
rewardOptions = [];
|
||||
|
||||
|
|
@ -935,12 +910,16 @@ class BattleProvider with ChangeNotifier {
|
|||
if (canAttack && canDefend) {
|
||||
// Both options available: Use configured probability
|
||||
isAttack = _random.nextDouble() < BattleConfig.enemyAttackChance;
|
||||
} else if (canAttack) {
|
||||
// Must attack
|
||||
isAttack = true;
|
||||
} else if (canDefend) {
|
||||
// Must defend
|
||||
isAttack = false;
|
||||
} else {
|
||||
// Must attack (default) or both forbidden (defaults to attack currently)
|
||||
isAttack = true;
|
||||
// Both forbidden (Rare case, effectively stunned but not via Stun status)
|
||||
// Default to Defend as a fallback, outcomes will be handled by stats/luck
|
||||
isAttack = false;
|
||||
}
|
||||
|
||||
// Decide Risk Level
|
||||
|
|
@ -1134,11 +1113,7 @@ class BattleProvider with ChangeNotifier {
|
|||
}
|
||||
|
||||
/// Tries to applyStatus effects from attacker's equipment to the target.
|
||||
void _tryApplyStatusEffects(
|
||||
Character attacker,
|
||||
Character target,
|
||||
int damageToHp,
|
||||
) {
|
||||
void _tryApplyStatusEffects(Character attacker, Character target, int damageToHp) {
|
||||
List<StatusEffect> effectsToApply = CombatCalculator.getAppliedEffects(
|
||||
attacker,
|
||||
random: _random, // Pass injected random
|
||||
|
|
|
|||
|
|
@ -21,15 +21,15 @@ class ItemUtils {
|
|||
static String getIconPath(EquipmentSlot slot) {
|
||||
switch (slot) {
|
||||
case EquipmentSlot.weapon:
|
||||
return 'assets/images/icons/weapons/sword_02.png';
|
||||
return 'assets/data/icon/icon_weapon.png';
|
||||
case EquipmentSlot.shield:
|
||||
return 'assets/images/icons/subweapons/shield_01.png';
|
||||
return 'assets/data/icon/icon_shield.png';
|
||||
case EquipmentSlot.armor:
|
||||
return 'assets/images/icons/armors/armor_02.png';
|
||||
return 'assets/data/icon/icon_armor.png';
|
||||
case EquipmentSlot.accessory:
|
||||
return 'assets/images/icons/accessories/ring_02.png';
|
||||
return 'assets/data/icon/icon_accessory.png';
|
||||
case EquipmentSlot.consumable:
|
||||
return 'assets/images/icons/potions/potion_blue.png';
|
||||
return 'assets/data/icon/icon_accessory.png'; // Todo: Add potion icon
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../common/custom_icon_button.dart';
|
||||
import '../../game/config.dart';
|
||||
|
||||
class BattleControls extends StatelessWidget {
|
||||
final bool isAttackEnabled;
|
||||
|
|
@ -18,30 +18,57 @@ class BattleControls extends StatelessWidget {
|
|||
required this.onItemPressed, // New
|
||||
});
|
||||
|
||||
Widget _buildFloatingActionButton({
|
||||
required String label,
|
||||
required Color color,
|
||||
required String iconPath, // Changed from ActionType to String
|
||||
required bool isEnabled,
|
||||
required VoidCallback onPressed,
|
||||
}) {
|
||||
return FloatingActionButton(
|
||||
heroTag: label,
|
||||
onPressed: isEnabled ? onPressed : null,
|
||||
backgroundColor: isEnabled ? color : ThemeConfig.btnDisabled,
|
||||
child: Image.asset(
|
||||
iconPath,
|
||||
width: 32,
|
||||
height: 32,
|
||||
color: ThemeConfig.textColorWhite, // Tint icon white
|
||||
fit: BoxFit.contain,
|
||||
filterQuality: FilterQuality.high,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
CustomIconButton(
|
||||
iconPath: 'assets/images/icons/weapons/sword_02.png',
|
||||
_buildFloatingActionButton(
|
||||
label: "ATK",
|
||||
color: ThemeConfig.btnActionActive,
|
||||
iconPath: 'assets/data/icon/icon_weapon.png',
|
||||
isEnabled: isAttackEnabled,
|
||||
onTap: onAttackPressed,
|
||||
iconColor: Colors.white,
|
||||
onPressed: onAttackPressed,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
CustomIconButton(
|
||||
iconPath: 'assets/images/icons/subweapons/shield_01.png',
|
||||
_buildFloatingActionButton(
|
||||
label: "DEF",
|
||||
color: ThemeConfig.btnDefendActive,
|
||||
iconPath: 'assets/data/icon/icon_shield.png',
|
||||
isEnabled: isDefendEnabled,
|
||||
onTap: onDefendPressed,
|
||||
iconColor: Colors.white,
|
||||
onPressed: onDefendPressed,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
CustomIconButton(
|
||||
iconPath: 'assets/images/icons/potions/potion_blue.png',
|
||||
isEnabled: isAttackEnabled, // Enabled when it's player turn
|
||||
onTap: onItemPressed,
|
||||
iconColor: Colors.white,
|
||||
_buildFloatingActionButton(
|
||||
label: "ITEM",
|
||||
color: Colors.indigoAccent, // Distinct color for Item
|
||||
iconPath:
|
||||
'assets/data/icon/icon_accessory.png', // Placeholder for Bag
|
||||
isEnabled:
|
||||
isAttackEnabled, // Enabled when it's player turn (same as attack)
|
||||
onPressed: onItemPressed,
|
||||
),
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class ItemCardWidget extends StatelessWidget {
|
|||
onTap: onTap,
|
||||
child: Card(
|
||||
color: ThemeConfig.shopItemCardBg, // Configurable if needed
|
||||
shape: item.rarity != ItemRarity.normal
|
||||
shape: item.rarity != ItemRarity.magic
|
||||
? RoundedRectangleBorder(
|
||||
side: BorderSide(
|
||||
color: ItemUtils.getRarityColor(item.rarity),
|
||||
|
|
@ -33,66 +33,44 @@ class ItemCardWidget extends StatelessWidget {
|
|||
borderRadius: BorderRadius.circular(8.0),
|
||||
)
|
||||
: null,
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// Background Watermark/Silhouette Icon (Top-Left)
|
||||
Positioned(
|
||||
left: 8,
|
||||
top: 8,
|
||||
child: Image.asset(
|
||||
ItemUtils.getIconPath(item.slot),
|
||||
width: 32,
|
||||
height: 32,
|
||||
fit: BoxFit.contain,
|
||||
color: Colors.black12, // Shadow silhouette
|
||||
),
|
||||
),
|
||||
// Main Content (Centered)
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
item.name,
|
||||
maxLines: 1,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ItemUtils.getRarityColor(item.rarity),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
// Show Item Stats
|
||||
FittedBox(
|
||||
fit: BoxFit.scaleDown,
|
||||
child: _buildItemStatText(item),
|
||||
),
|
||||
if (showPrice) ...[
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
"${item.price} G",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: canBuy
|
||||
? ThemeConfig.statGoldColor
|
||||
: ThemeConfig.textColorGrey,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4.0),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Image.asset(
|
||||
ItemUtils.getIconPath(item.slot),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Text(
|
||||
item.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ItemUtils.getRarityColor(item.rarity),
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
// Show Item Stats (Fixed to show negative values)
|
||||
FittedBox(fit: BoxFit.scaleDown, child: _buildItemStatText(item)),
|
||||
if (showPrice) ...[
|
||||
const Spacer(),
|
||||
Text(
|
||||
"${item.price} G",
|
||||
style: TextStyle(
|
||||
color: canBuy
|
||||
? ThemeConfig.statGoldColor
|
||||
: ThemeConfig.textColorGrey,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -30,9 +30,3 @@ flutter:
|
|||
- assets/images/enemies/
|
||||
- assets/images/background/
|
||||
- assets/images/character/
|
||||
- assets/images/icons/borders/
|
||||
- assets/images/icons/weapons/
|
||||
- assets/images/icons/subweapons/
|
||||
- assets/images/icons/accessories/
|
||||
- assets/images/icons/potions/
|
||||
- assets/images/icons/armors/
|
||||
|
|
|
|||
Loading…
Reference in New Issue