parent
d3fca333cb
commit
8771f2c1af
|
|
@ -0,0 +1,30 @@
|
||||||
|
class GameConfig {
|
||||||
|
// Inventory
|
||||||
|
static const int maxInventorySize = 5;
|
||||||
|
|
||||||
|
// Economy
|
||||||
|
static const int startingGold = 50;
|
||||||
|
static const double sellPriceMultiplier = 0.6;
|
||||||
|
static const int shopRerollCost = 50;
|
||||||
|
|
||||||
|
// Stages
|
||||||
|
static const int eliteStageInterval = 10;
|
||||||
|
static const int shopStageInterval = 5;
|
||||||
|
static const int restStageInterval = 8;
|
||||||
|
static const int tier1StageMax = 12;
|
||||||
|
static const int tier2StageMax = 24;
|
||||||
|
|
||||||
|
// Battle
|
||||||
|
static const double stageHealRatio = 0.1;
|
||||||
|
static const double vulnerableDamageMultiplier = 1.5;
|
||||||
|
static const double armorDecayRate = 0.5;
|
||||||
|
|
||||||
|
// Animations (Duration in milliseconds)
|
||||||
|
static const int animDelaySafe = 500;
|
||||||
|
static const int animDelayNormal = 400;
|
||||||
|
static const int animDelayRisky = 1100;
|
||||||
|
static const int animDelayEnemyTurn = 1000;
|
||||||
|
|
||||||
|
// Save System
|
||||||
|
static const String saveKey = 'game_save_data';
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,43 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class ThemeConfig {
|
class ThemeConfig {
|
||||||
|
// Font Sizes
|
||||||
|
static const double fontSizeTiny = 8.0;
|
||||||
|
static const double fontSizeSmall = 10.0;
|
||||||
|
static const double fontSizeMedium = 12.0;
|
||||||
|
static const double fontSizeBody = 14.0;
|
||||||
|
static const double fontSizeLarge = 16.0;
|
||||||
|
static const double fontSizeHeader = 18.0;
|
||||||
|
static const double fontSizeXLarge = 20.0;
|
||||||
|
static const double fontSizeTitle = 24.0;
|
||||||
|
static const double fontSizeHero = 32.0;
|
||||||
|
static const double fontSizeHuge = 48.0;
|
||||||
|
|
||||||
|
// Font Weights
|
||||||
|
static const FontWeight fontWeightNormal = FontWeight.normal;
|
||||||
|
static const FontWeight fontWeightBold = FontWeight.bold;
|
||||||
|
|
||||||
|
// Main Menu Colors
|
||||||
|
static const Color mainMenuBgTop = Colors.black;
|
||||||
|
static final Color mainMenuBgBottom = Colors.blueGrey[900]!;
|
||||||
|
static const Color mainTitleColor = Colors.white;
|
||||||
|
static const Color subTitleColor = Colors.grey;
|
||||||
|
static const Color mainIconColor = Colors.amber;
|
||||||
|
|
||||||
|
// Button Colors
|
||||||
|
static const Color btnNewGameBg = Color(0xFFFFA000); // Colors.amber[700]
|
||||||
|
static const Color btnNewGameText = Colors.black;
|
||||||
|
static const Color btnContinueBg = Colors.blueAccent;
|
||||||
|
static const Color btnContinueText = Colors.white;
|
||||||
|
static const Color btnRestBg = Colors.blue;
|
||||||
|
static const Color btnLeaveBg = Colors.redAccent;
|
||||||
|
static const Color btnRerollBg = Colors.blueGrey;
|
||||||
|
static const Color btnActionActive = Colors.redAccent; // Attack
|
||||||
|
static const Color btnDefendActive = Colors.blueAccent; // Defend
|
||||||
|
static const Color btnDisabled = Colors.grey;
|
||||||
|
static const Color btnRestartBg = Colors.orange;
|
||||||
|
static const Color btnReturnMenuBg = Colors.red;
|
||||||
|
|
||||||
// Stat Colors
|
// Stat Colors
|
||||||
static const Color statHpColor = Colors.red;
|
static const Color statHpColor = Colors.red;
|
||||||
static const Color statHpPlayerColor = Colors.green;
|
static const Color statHpPlayerColor = Colors.green;
|
||||||
|
|
@ -22,6 +59,13 @@ class ThemeConfig {
|
||||||
0xFF546E7A,
|
0xFF546E7A,
|
||||||
); // Colors.blueGrey[600]
|
); // Colors.blueGrey[600]
|
||||||
static const Color emptySlotBg = Color(0xFF424242); // Colors.grey[800]
|
static const Color emptySlotBg = Color(0xFF424242); // Colors.grey[800]
|
||||||
|
static const Color battleBg = Colors.black87;
|
||||||
|
static const Color shopBg = Colors.black87;
|
||||||
|
static final Color? shopItemCardBg = Colors.blueGrey[800];
|
||||||
|
static const Color enemyIntentBg = Colors.black54;
|
||||||
|
static const Color enemyIntentBorder = Colors.redAccent;
|
||||||
|
static final Color? selectionCardBg = Colors.blueGrey[800];
|
||||||
|
static const Color selectionIconColor = Colors.blue;
|
||||||
|
|
||||||
// Feedback Colors
|
// Feedback Colors
|
||||||
static const Color damageTextDefault = Colors.red;
|
static const Color damageTextDefault = Colors.red;
|
||||||
|
|
@ -29,6 +73,9 @@ class ThemeConfig {
|
||||||
static const Color missText = Colors.grey;
|
static const Color missText = Colors.grey;
|
||||||
static const Color failedText = Colors.redAccent;
|
static const Color failedText = Colors.redAccent;
|
||||||
static const Color feedbackShadow = Colors.black;
|
static const Color feedbackShadow = Colors.black;
|
||||||
|
static const Color statDiffPositive = Colors.green;
|
||||||
|
static const Color statDiffNegative = Colors.red;
|
||||||
|
static const Color statDiffNeutral = Colors.grey;
|
||||||
|
|
||||||
// Status Effect Colors
|
// Status Effect Colors
|
||||||
static const Color effectBg = Colors.deepOrange;
|
static const Color effectBg = Colors.deepOrange;
|
||||||
|
|
@ -39,4 +86,10 @@ class ThemeConfig {
|
||||||
static const Color rarityRare = Colors.yellow;
|
static const Color rarityRare = Colors.yellow;
|
||||||
static const Color rarityLegendary = Colors.orange;
|
static const Color rarityLegendary = Colors.orange;
|
||||||
static const Color rarityUnique = Colors.purple;
|
static const Color rarityUnique = Colors.purple;
|
||||||
|
static const Color rarityCommon = Colors.grey;
|
||||||
|
|
||||||
|
// Risk Colors (from BattleScreen Dialog)
|
||||||
|
static const Color riskSafe = Colors.green;
|
||||||
|
static const Color riskNormal = Colors.blue;
|
||||||
|
static const Color riskRisky = Colors.red;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'status_effect.dart';
|
||||||
import 'stat_modifier.dart';
|
import 'stat_modifier.dart';
|
||||||
import '../enums.dart';
|
import '../enums.dart';
|
||||||
import '../data/item_table.dart';
|
import '../data/item_table.dart';
|
||||||
|
import '../config/game_config.dart';
|
||||||
|
|
||||||
class Character {
|
class Character {
|
||||||
String name;
|
String name;
|
||||||
|
|
@ -16,7 +17,7 @@ class Character {
|
||||||
String? image; // New: Image path
|
String? image; // New: Image path
|
||||||
Map<EquipmentSlot, Item> equipment = {};
|
Map<EquipmentSlot, Item> equipment = {};
|
||||||
List<Item> inventory = [];
|
List<Item> inventory = [];
|
||||||
final int maxInventorySize = 16;
|
final int maxInventorySize = GameConfig.maxInventorySize;
|
||||||
|
|
||||||
// Active status effects
|
// Active status effects
|
||||||
List<StatusEffect> statusEffects = [];
|
List<StatusEffect> statusEffects = [];
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,10 @@ import 'dart:convert';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import '../providers/battle_provider.dart';
|
import '../providers/battle_provider.dart';
|
||||||
import 'model/entity.dart';
|
import 'model/entity.dart';
|
||||||
|
import 'config/game_config.dart';
|
||||||
|
|
||||||
class SaveManager {
|
class SaveManager {
|
||||||
static const String _saveKey = 'game_save_data';
|
static const String _saveKey = GameConfig.saveKey;
|
||||||
|
|
||||||
static Future<void> saveGame(BattleProvider provider) async {
|
static Future<void> saveGame(BattleProvider provider) async {
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import '../game/model/damage_event.dart'; // DamageEvent import
|
||||||
import '../game/model/effect_event.dart'; // EffectEvent import
|
import '../game/model/effect_event.dart'; // EffectEvent import
|
||||||
|
|
||||||
import '../game/save_manager.dart';
|
import '../game/save_manager.dart';
|
||||||
|
import '../game/config/game_config.dart';
|
||||||
|
|
||||||
class EnemyIntent {
|
class EnemyIntent {
|
||||||
final EnemyActionType type;
|
final EnemyActionType type;
|
||||||
|
|
@ -104,7 +105,7 @@ class BattleProvider with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Give test gold
|
// Give test gold
|
||||||
player.gold = 50;
|
player.gold = GameConfig.startingGold;
|
||||||
|
|
||||||
// Provide starter equipment
|
// Provide starter equipment
|
||||||
final starterSword = Item(
|
final starterSword = Item(
|
||||||
|
|
@ -172,11 +173,11 @@ class BattleProvider with ChangeNotifier {
|
||||||
StageType type;
|
StageType type;
|
||||||
|
|
||||||
// Stage Type Logic
|
// Stage Type Logic
|
||||||
if (stage % 10 == 0) {
|
if (stage % GameConfig.eliteStageInterval == 0) {
|
||||||
type = StageType.elite; // Every 10th stage is a Boss/Elite
|
type = StageType.elite; // Every 10th stage is a Boss/Elite
|
||||||
} else if (stage % 5 == 0) {
|
} else if (stage % GameConfig.shopStageInterval == 0) {
|
||||||
type = StageType.shop; // Every 5th stage is a Shop (except 10, 20...)
|
type = StageType.shop; // Every 5th stage is a Shop (except 10, 20...)
|
||||||
} else if (stage % 8 == 0) {
|
} else if (stage % GameConfig.restStageInterval == 0) {
|
||||||
type = StageType.rest; // Every 8th stage is a Rest
|
type = StageType.rest; // Every 8th stage is a Rest
|
||||||
} else {
|
} else {
|
||||||
type = StageType.battle;
|
type = StageType.battle;
|
||||||
|
|
@ -255,9 +256,9 @@ class BattleProvider with ChangeNotifier {
|
||||||
/// Generate 4 random items for the shop based on current stage tier
|
/// Generate 4 random items for the shop based on current stage tier
|
||||||
List<Item> _generateShopItems() {
|
List<Item> _generateShopItems() {
|
||||||
ItemTier currentTier = ItemTier.tier1;
|
ItemTier currentTier = ItemTier.tier1;
|
||||||
if (stage > 24)
|
if (stage > GameConfig.tier2StageMax)
|
||||||
currentTier = ItemTier.tier3;
|
currentTier = ItemTier.tier3;
|
||||||
else if (stage > 12)
|
else if (stage > GameConfig.tier1StageMax)
|
||||||
currentTier = ItemTier.tier2;
|
currentTier = ItemTier.tier2;
|
||||||
|
|
||||||
List<Item> items = [];
|
List<Item> items = [];
|
||||||
|
|
@ -271,7 +272,7 @@ class BattleProvider with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rerollShopItems() {
|
void rerollShopItems() {
|
||||||
const int rerollCost = 50;
|
const int rerollCost = GameConfig.shopRerollCost;
|
||||||
if (player.gold >= rerollCost) {
|
if (player.gold >= rerollCost) {
|
||||||
player.gold -= rerollCost;
|
player.gold -= rerollCost;
|
||||||
// Modify the existing list because shopItems is final
|
// Modify the existing list because shopItems is final
|
||||||
|
|
@ -381,11 +382,11 @@ class BattleProvider with ChangeNotifier {
|
||||||
|
|
||||||
// Animation Delays to sync with Impact
|
// Animation Delays to sync with Impact
|
||||||
if (risk == RiskLevel.safe) {
|
if (risk == RiskLevel.safe) {
|
||||||
await Future.delayed(const Duration(milliseconds: 500));
|
await Future.delayed(const Duration(milliseconds: GameConfig.animDelaySafe));
|
||||||
} else if (risk == RiskLevel.normal) {
|
} else if (risk == RiskLevel.normal) {
|
||||||
await Future.delayed(const Duration(milliseconds: 400));
|
await Future.delayed(const Duration(milliseconds: GameConfig.animDelayNormal));
|
||||||
} else if (risk == RiskLevel.risky) {
|
} else if (risk == RiskLevel.risky) {
|
||||||
await Future.delayed(const Duration(milliseconds: 1100));
|
await Future.delayed(const Duration(milliseconds: GameConfig.animDelayRisky));
|
||||||
}
|
}
|
||||||
|
|
||||||
int damageToHp = 0;
|
int damageToHp = 0;
|
||||||
|
|
@ -477,19 +478,19 @@ class BattleProvider with ChangeNotifier {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future.delayed(const Duration(seconds: 1), () => _enemyTurn());
|
Future.delayed(const Duration(milliseconds: GameConfig.animDelayEnemyTurn), () => _enemyTurn());
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _enemyTurn() async {
|
Future<void> _enemyTurn() async {
|
||||||
if (!isPlayerTurn && (player.isDead || enemy.isDead)) return;
|
if (!isPlayerTurn && (player.isDead || enemy.isDead)) return;
|
||||||
|
|
||||||
_addLog("Enemy's turn...");
|
_addLog("Enemy's turn...");
|
||||||
await Future.delayed(const Duration(seconds: 1));
|
await Future.delayed(const Duration(milliseconds: GameConfig.animDelayEnemyTurn));
|
||||||
|
|
||||||
// Enemy Turn Start Logic
|
// Enemy Turn Start Logic
|
||||||
// Armor decay
|
// Armor decay
|
||||||
if (enemy.armor > 0) {
|
if (enemy.armor > 0) {
|
||||||
enemy.armor = (enemy.armor * 0.5).toInt();
|
enemy.armor = (enemy.armor * GameConfig.armorDecayRate).toInt();
|
||||||
_addLog("Enemy's armor decayed to ${enemy.armor}.");
|
_addLog("Enemy's armor decayed to ${enemy.armor}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -578,7 +579,7 @@ class BattleProvider with ChangeNotifier {
|
||||||
// Player Turn Start Logic
|
// Player Turn Start Logic
|
||||||
// Armor decay
|
// Armor decay
|
||||||
if (player.armor > 0) {
|
if (player.armor > 0) {
|
||||||
player.armor = (player.armor * 0.5).toInt();
|
player.armor = (player.armor * GameConfig.armorDecayRate).toInt();
|
||||||
_addLog("Player's armor decayed to ${player.armor}.");
|
_addLog("Player's armor decayed to ${player.armor}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -665,7 +666,7 @@ class BattleProvider with ChangeNotifier {
|
||||||
}) {
|
}) {
|
||||||
// Check Vulnerable
|
// Check Vulnerable
|
||||||
if (target.hasStatus(StatusEffectType.vulnerable)) {
|
if (target.hasStatus(StatusEffectType.vulnerable)) {
|
||||||
damage = (damage * 1.5).toInt();
|
damage = (damage * GameConfig.vulnerableDamageMultiplier).toInt();
|
||||||
_addLog("Vulnerable! Damage increased to $damage.");
|
_addLog("Vulnerable! Damage increased to $damage.");
|
||||||
type = DamageType.vulnerable;
|
type = DamageType.vulnerable;
|
||||||
}
|
}
|
||||||
|
|
@ -704,9 +705,9 @@ class BattleProvider with ChangeNotifier {
|
||||||
// Since we just refactored ItemTable, let's use getRandomItem!
|
// Since we just refactored ItemTable, let's use getRandomItem!
|
||||||
|
|
||||||
ItemTier currentTier = ItemTier.tier1;
|
ItemTier currentTier = ItemTier.tier1;
|
||||||
if (stage > 24)
|
if (stage > GameConfig.tier2StageMax)
|
||||||
currentTier = ItemTier.tier3;
|
currentTier = ItemTier.tier3;
|
||||||
else if (stage > 12)
|
else if (stage > GameConfig.tier1StageMax)
|
||||||
currentTier = ItemTier.tier2;
|
currentTier = ItemTier.tier2;
|
||||||
|
|
||||||
rewardOptions = [];
|
rewardOptions = [];
|
||||||
|
|
@ -749,7 +750,7 @@ class BattleProvider with ChangeNotifier {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heal player after selecting reward
|
// Heal player after selecting reward
|
||||||
int healAmount = GameMath.floor(player.totalMaxHp * 0.1);
|
int healAmount = GameMath.floor(player.totalMaxHp * GameConfig.stageHealRatio);
|
||||||
player.heal(healAmount);
|
player.heal(healAmount);
|
||||||
_addLog("Stage Cleared! Recovered $healAmount HP.");
|
_addLog("Stage Cleared! Recovered $healAmount HP.");
|
||||||
|
|
||||||
|
|
@ -793,7 +794,7 @@ class BattleProvider with ChangeNotifier {
|
||||||
|
|
||||||
void sellItem(Item item) {
|
void sellItem(Item item) {
|
||||||
if (player.inventory.remove(item)) {
|
if (player.inventory.remove(item)) {
|
||||||
int sellPrice = GameMath.floor(item.price * 0.6);
|
int sellPrice = GameMath.floor(item.price * GameConfig.sellPriceMultiplier);
|
||||||
player.gold += sellPrice;
|
player.gold += sellPrice;
|
||||||
_addLog("Sold ${item.name} for $sellPrice G.");
|
_addLog("Sold ${item.name} for $sellPrice G.");
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import '../widgets/battle/battle_animation_widget.dart';
|
||||||
import '../widgets/battle/explosion_widget.dart';
|
import '../widgets/battle/explosion_widget.dart';
|
||||||
import 'main_menu_screen.dart';
|
import 'main_menu_screen.dart';
|
||||||
import '../game/config/battle_config.dart';
|
import '../game/config/battle_config.dart';
|
||||||
|
import '../game/config/theme_config.dart';
|
||||||
|
|
||||||
class BattleScreen extends StatefulWidget {
|
class BattleScreen extends StatefulWidget {
|
||||||
const BattleScreen({super.key});
|
const BattleScreen({super.key});
|
||||||
|
|
@ -162,15 +163,15 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
switch (event.feedbackType) {
|
switch (event.feedbackType) {
|
||||||
case BattleFeedbackType.miss:
|
case BattleFeedbackType.miss:
|
||||||
feedbackText = "MISS";
|
feedbackText = "MISS";
|
||||||
feedbackColor = Colors.grey;
|
feedbackColor = ThemeConfig.missText;
|
||||||
break;
|
break;
|
||||||
case BattleFeedbackType.failed:
|
case BattleFeedbackType.failed:
|
||||||
feedbackText = "FAILED";
|
feedbackText = "FAILED";
|
||||||
feedbackColor = Colors.redAccent;
|
feedbackColor = ThemeConfig.failedText;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
feedbackText = ""; // Should not happen with current enums
|
feedbackText = ""; // Should not happen with current enums
|
||||||
feedbackColor = Colors.white;
|
feedbackColor = ThemeConfig.textColorWhite;
|
||||||
}
|
}
|
||||||
|
|
||||||
final String id = UniqueKey().toString();
|
final String id = UniqueKey().toString();
|
||||||
|
|
@ -311,15 +312,15 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
switch (risk) {
|
switch (risk) {
|
||||||
case RiskLevel.safe:
|
case RiskLevel.safe:
|
||||||
efficiency = 0.5;
|
efficiency = 0.5;
|
||||||
infoColor = Colors.green;
|
infoColor = ThemeConfig.riskSafe;
|
||||||
break;
|
break;
|
||||||
case RiskLevel.normal:
|
case RiskLevel.normal:
|
||||||
efficiency = 1.0;
|
efficiency = 1.0;
|
||||||
infoColor = Colors.blue;
|
infoColor = ThemeConfig.riskNormal;
|
||||||
break;
|
break;
|
||||||
case RiskLevel.risky:
|
case RiskLevel.risky:
|
||||||
efficiency = 2.0;
|
efficiency = 2.0;
|
||||||
infoColor = Colors.red;
|
infoColor = ThemeConfig.riskRisky;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -391,7 +392,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
key: _stackKey,
|
key: _stackKey,
|
||||||
children: [
|
children: [
|
||||||
// 1. Background (Black)
|
// 1. Background (Black)
|
||||||
Container(color: Colors.black87),
|
Container(color: ThemeConfig.battleBg),
|
||||||
|
|
||||||
// 2. Battle Content (Top Bar + Characters)
|
// 2. Battle Content (Top Bar + Characters)
|
||||||
Column(
|
Column(
|
||||||
|
|
@ -408,9 +409,9 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
child: Text(
|
child: Text(
|
||||||
"Stage ${battleProvider.stage}",
|
"Stage ${battleProvider.stage}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
fontSize: 18,
|
fontSize: ThemeConfig.fontSizeHeader,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -421,8 +422,8 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
child: Text(
|
child: Text(
|
||||||
"Turn ${battleProvider.turnCount}",
|
"Turn ${battleProvider.turnCount}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
fontSize: 18,
|
fontSize: ThemeConfig.fontSizeHeader,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -489,7 +490,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
context,
|
context,
|
||||||
"ATK",
|
"ATK",
|
||||||
Icons.whatshot,
|
Icons.whatshot,
|
||||||
Colors.redAccent,
|
ThemeConfig.btnActionActive,
|
||||||
ActionType.attack,
|
ActionType.attack,
|
||||||
battleProvider.isPlayerTurn &&
|
battleProvider.isPlayerTurn &&
|
||||||
!battleProvider.player.isDead &&
|
!battleProvider.player.isDead &&
|
||||||
|
|
@ -501,7 +502,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
context,
|
context,
|
||||||
"DEF",
|
"DEF",
|
||||||
Icons.shield,
|
Icons.shield,
|
||||||
Colors.blueAccent,
|
ThemeConfig.btnDefendActive,
|
||||||
ActionType.defend,
|
ActionType.defend,
|
||||||
battleProvider.isPlayerTurn &&
|
battleProvider.isPlayerTurn &&
|
||||||
!battleProvider.player.isDead &&
|
!battleProvider.player.isDead &&
|
||||||
|
|
@ -527,7 +528,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
},
|
},
|
||||||
child: Icon(
|
child: Icon(
|
||||||
_showLogs ? Icons.visibility_off : Icons.visibility,
|
_showLogs ? Icons.visibility_off : Icons.visibility,
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -535,7 +536,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
// Reward Popup
|
// Reward Popup
|
||||||
if (battleProvider.showRewardPopup)
|
if (battleProvider.showRewardPopup)
|
||||||
Container(
|
Container(
|
||||||
color: Colors.black54,
|
color: ThemeConfig.cardBgColor,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: SimpleDialog(
|
child: SimpleDialog(
|
||||||
title: Row(
|
title: Row(
|
||||||
|
|
@ -545,14 +546,14 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.monetization_on, color: Colors.amber, size: 18),
|
Icon(Icons.monetization_on, color: ThemeConfig.statGoldColor, size: 18),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
"${battleProvider.lastGoldReward} G",
|
"${battleProvider.lastGoldReward} G",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.amber,
|
color: ThemeConfig.statGoldColor,
|
||||||
fontSize: 14,
|
fontSize: ThemeConfig.fontSizeBody,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -583,7 +584,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
? ItemUtils.getRarityColor(
|
? ItemUtils.getRarityColor(
|
||||||
item.rarity,
|
item.rarity,
|
||||||
)
|
)
|
||||||
: Colors.grey,
|
: ThemeConfig.rarityCommon,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
|
|
@ -596,10 +597,10 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
Text(
|
Text(
|
||||||
item.name,
|
item.name,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
fontSize: 16,
|
fontSize: ThemeConfig.fontSizeLarge,
|
||||||
color: isSkip
|
color: isSkip
|
||||||
? Colors.grey
|
? ThemeConfig.textColorGrey
|
||||||
: ItemUtils.getRarityColor(
|
: ItemUtils.getRarityColor(
|
||||||
item.rarity),
|
item.rarity),
|
||||||
),
|
),
|
||||||
|
|
@ -610,8 +611,8 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
Text(
|
Text(
|
||||||
item.description,
|
item.description,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: ThemeConfig.fontSizeMedium,
|
||||||
color: Colors.grey,
|
color: ThemeConfig.textColorGrey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -633,7 +634,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
// Game Over Overlay
|
// Game Over Overlay
|
||||||
if (battleProvider.player.isDead)
|
if (battleProvider.player.isDead)
|
||||||
Container(
|
Container(
|
||||||
color: Colors.black87,
|
color: ThemeConfig.battleBg,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
|
@ -641,9 +642,9 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
const Text(
|
const Text(
|
||||||
"DEFEAT",
|
"DEFEAT",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.red,
|
color: ThemeConfig.statHpColor,
|
||||||
fontSize: 48,
|
fontSize: ThemeConfig.fontSizeHuge,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
letterSpacing: 4.0,
|
letterSpacing: 4.0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -667,8 +668,8 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"Return to Main Menu",
|
"Return to Main Menu",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
fontSize: 18,
|
fontSize: ThemeConfig.fontSizeHeader,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -703,7 +704,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
padding: const EdgeInsets.only(top: 4.0, bottom: 4.0),
|
padding: const EdgeInsets.only(top: 4.0, bottom: 4.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
stats.join(", "),
|
stats.join(", "),
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.blueAccent),
|
style: const TextStyle(fontSize: ThemeConfig.fontSizeMedium, color: ThemeConfig.statAtkColor),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (effectTexts.isNotEmpty)
|
if (effectTexts.isNotEmpty)
|
||||||
|
|
@ -711,7 +712,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
padding: const EdgeInsets.only(bottom: 4.0),
|
padding: const EdgeInsets.only(bottom: 4.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
effectTexts.join(", "),
|
effectTexts.join(", "),
|
||||||
style: const TextStyle(fontSize: 11, color: Colors.orangeAccent),
|
style: const TextStyle(fontSize: 11, color: ThemeConfig.rarityLegendary), // 11 is custom, keep or change? Let's use Small
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -731,7 +732,7 @@ class _BattleScreenState extends State<BattleScreen> {
|
||||||
onPressed: isEnabled
|
onPressed: isEnabled
|
||||||
? () => _showRiskLevelSelection(context, actionType)
|
? () => _showRiskLevelSelection(context, actionType)
|
||||||
: null,
|
: null,
|
||||||
backgroundColor: isEnabled ? color : Colors.grey,
|
backgroundColor: isEnabled ? color : ThemeConfig.btnDisabled,
|
||||||
child: Icon(icon),
|
child: Icon(icon),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import '../providers/battle_provider.dart';
|
||||||
import '../game/data/player_table.dart';
|
import '../game/data/player_table.dart';
|
||||||
import 'main_wrapper.dart';
|
import 'main_wrapper.dart';
|
||||||
import '../widgets/responsive_container.dart';
|
import '../widgets/responsive_container.dart';
|
||||||
|
import '../game/config/theme_config.dart';
|
||||||
|
|
||||||
class CharacterSelectionScreen extends StatelessWidget {
|
class CharacterSelectionScreen extends StatelessWidget {
|
||||||
const CharacterSelectionScreen({super.key});
|
const CharacterSelectionScreen({super.key});
|
||||||
|
|
@ -20,7 +21,7 @@ class CharacterSelectionScreen extends StatelessWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.black, // Outer background
|
backgroundColor: ThemeConfig.mainMenuBgTop, // Outer background
|
||||||
body: Center(
|
body: Center(
|
||||||
child: ResponsiveContainer(
|
child: ResponsiveContainer(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
|
@ -47,7 +48,7 @@ class CharacterSelectionScreen extends StatelessWidget {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Card(
|
child: Card(
|
||||||
color: Colors.blueGrey[800],
|
color: ThemeConfig.selectionCardBg,
|
||||||
elevation: 8,
|
elevation: 8,
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 300,
|
width: 300,
|
||||||
|
|
@ -58,22 +59,22 @@ class CharacterSelectionScreen extends StatelessWidget {
|
||||||
const Icon(
|
const Icon(
|
||||||
Icons.shield,
|
Icons.shield,
|
||||||
size: 80,
|
size: 80,
|
||||||
color: Colors.blue,
|
color: ThemeConfig.selectionIconColor,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
warrior.name,
|
warrior.name,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 24,
|
fontSize: ThemeConfig.fontSizeTitle,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
Text(
|
Text(
|
||||||
warrior.description,
|
warrior.description,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(color: Colors.grey),
|
style: const TextStyle(color: ThemeConfig.textColorGrey),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const Divider(),
|
const Divider(),
|
||||||
|
|
@ -84,19 +85,19 @@ class CharacterSelectionScreen extends StatelessWidget {
|
||||||
Text(
|
Text(
|
||||||
"HP: ${warrior.baseHp}",
|
"HP: ${warrior.baseHp}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"ATK: ${warrior.baseAtk}",
|
"ATK: ${warrior.baseAtk}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
"DEF: ${warrior.baseDefense}",
|
"DEF: ${warrior.baseDefense}",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import '../providers/battle_provider.dart';
|
||||||
import '../game/model/item.dart';
|
import '../game/model/item.dart';
|
||||||
import '../game/enums.dart';
|
import '../game/enums.dart';
|
||||||
import '../utils/item_utils.dart';
|
import '../utils/item_utils.dart';
|
||||||
|
import '../game/config/theme_config.dart';
|
||||||
|
|
||||||
class InventoryScreen extends StatelessWidget {
|
class InventoryScreen extends StatelessWidget {
|
||||||
const InventoryScreen({super.key});
|
const InventoryScreen({super.key});
|
||||||
|
|
@ -45,12 +46,12 @@ class InventoryScreen extends StatelessWidget {
|
||||||
_buildStatItem(
|
_buildStatItem(
|
||||||
"Gold",
|
"Gold",
|
||||||
"${player.gold} G",
|
"${player.gold} G",
|
||||||
color: Colors.amber,
|
color: ThemeConfig.statGoldColor,
|
||||||
),
|
),
|
||||||
_buildStatItem(
|
_buildStatItem(
|
||||||
"Luck",
|
"Luck",
|
||||||
"${player.totalLuck}",
|
"${player.totalLuck}",
|
||||||
color: Colors.green,
|
color: ThemeConfig.statLuckColor,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
@ -71,8 +72,8 @@ class InventoryScreen extends StatelessWidget {
|
||||||
const Text(
|
const Text(
|
||||||
"Equipped Items",
|
"Equipped Items",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 18,
|
fontSize: ThemeConfig.fontSizeHeader,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
@ -91,8 +92,8 @@ class InventoryScreen extends StatelessWidget {
|
||||||
: null,
|
: null,
|
||||||
child: Card(
|
child: Card(
|
||||||
color: item != null
|
color: item != null
|
||||||
? Colors.blueGrey[600]
|
? ThemeConfig.equipmentCardBg
|
||||||
: Colors.grey[800],
|
: ThemeConfig.emptySlotBg,
|
||||||
shape: item != null &&
|
shape: item != null &&
|
||||||
item.rarity != ItemRarity.magic
|
item.rarity != ItemRarity.magic
|
||||||
? RoundedRectangleBorder(
|
? RoundedRectangleBorder(
|
||||||
|
|
@ -113,8 +114,8 @@ class InventoryScreen extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
slot.name.toUpperCase(),
|
slot.name.toUpperCase(),
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 8,
|
fontSize: ThemeConfig.fontSizeTiny,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
color: Colors.white30,
|
color: Colors.white30,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -130,7 +131,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
size: 40,
|
size: 40,
|
||||||
color: item != null
|
color: item != null
|
||||||
? ItemUtils.getColor(slot)
|
? ItemUtils.getColor(slot)
|
||||||
: Colors.grey,
|
: ThemeConfig.textColorGrey,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -151,13 +152,13 @@ class InventoryScreen extends StatelessWidget {
|
||||||
item?.name ?? "Empty",
|
item?.name ?? "Empty",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: ThemeConfig.fontSizeSmall,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
color: item != null
|
color: item != null
|
||||||
? ItemUtils.getRarityColor(
|
? ItemUtils.getRarityColor(
|
||||||
item.rarity,
|
item.rarity,
|
||||||
)
|
)
|
||||||
: Colors.grey,
|
: ThemeConfig.textColorGrey,
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|
@ -194,8 +195,8 @@ class InventoryScreen extends StatelessWidget {
|
||||||
child: Text(
|
child: Text(
|
||||||
"Bag (${player.inventory.length}/${player.maxInventorySize})",
|
"Bag (${player.inventory.length}/${player.maxInventorySize})",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 18,
|
fontSize: ThemeConfig.fontSizeHeader,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -218,7 +219,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
_showItemActionDialog(context, battleProvider, item);
|
_showItemActionDialog(context, battleProvider, item);
|
||||||
},
|
},
|
||||||
child: Card(
|
child: Card(
|
||||||
color: Colors.blueGrey[700],
|
color: ThemeConfig.inventoryCardBg,
|
||||||
shape: item.rarity != ItemRarity.magic
|
shape: item.rarity != ItemRarity.magic
|
||||||
? RoundedRectangleBorder(
|
? RoundedRectangleBorder(
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
|
|
@ -258,8 +259,8 @@ class InventoryScreen extends StatelessWidget {
|
||||||
item.name,
|
item.name,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: ThemeConfig.fontSizeSmall,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
color: ItemUtils.getRarityColor(
|
color: ItemUtils.getRarityColor(
|
||||||
item.rarity,
|
item.rarity,
|
||||||
),
|
),
|
||||||
|
|
@ -284,11 +285,11 @@ class InventoryScreen extends StatelessWidget {
|
||||||
// Empty slot
|
// Empty slot
|
||||||
return Container(
|
return Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: Colors.grey),
|
border: Border.all(color: ThemeConfig.textColorGrey),
|
||||||
color: Colors.grey[800],
|
color: ThemeConfig.emptySlotBg,
|
||||||
),
|
),
|
||||||
child: const Center(
|
child: const Center(
|
||||||
child: Icon(Icons.add_box, color: Colors.grey),
|
child: Icon(Icons.add_box, color: ThemeConfig.textColorGrey),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -305,11 +306,11 @@ class InventoryScreen extends StatelessWidget {
|
||||||
Widget _buildStatItem(String label, String value, {Color? color}) {
|
Widget _buildStatItem(String label, String value, {Color? color}) {
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Text(label, style: const TextStyle(color: Colors.grey, fontSize: 12)),
|
Text(label, style: const TextStyle(color: ThemeConfig.textColorGrey, fontSize: 12)),
|
||||||
Text(
|
Text(
|
||||||
value,
|
value,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
color: color,
|
color: color,
|
||||||
),
|
),
|
||||||
|
|
@ -340,7 +341,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.shield, color: Colors.blue),
|
Icon(Icons.shield, color: ThemeConfig.btnDefendActive),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text("Equip"),
|
Text("Equip"),
|
||||||
],
|
],
|
||||||
|
|
@ -357,7 +358,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.attach_money, color: Colors.amber),
|
const Icon(Icons.attach_money, color: ThemeConfig.statGoldColor),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text("Sell (${item.price} G)"),
|
Text("Sell (${item.price} G)"),
|
||||||
],
|
],
|
||||||
|
|
@ -373,7 +374,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.delete, color: Colors.red),
|
Icon(Icons.delete, color: ThemeConfig.btnActionActive),
|
||||||
SizedBox(width: 10),
|
SizedBox(width: 10),
|
||||||
Text("Discard"),
|
Text("Discard"),
|
||||||
],
|
],
|
||||||
|
|
@ -401,7 +402,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
child: const Text("Cancel"),
|
child: const Text("Cancel"),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.amber),
|
style: ElevatedButton.styleFrom(backgroundColor: ThemeConfig.statGoldColor),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
provider.sellItem(item);
|
provider.sellItem(item);
|
||||||
Navigator.pop(ctx);
|
Navigator.pop(ctx);
|
||||||
|
|
@ -429,7 +430,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
child: const Text("Cancel"),
|
child: const Text("Cancel"),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
|
style: ElevatedButton.styleFrom(backgroundColor: ThemeConfig.btnActionActive),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
provider.discardItem(item);
|
provider.discardItem(item);
|
||||||
Navigator.pop(ctx);
|
Navigator.pop(ctx);
|
||||||
|
|
@ -475,12 +476,12 @@ class InventoryScreen extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Equip ${newItem.name}?",
|
"Equip ${newItem.name}?",
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: ThemeConfig.fontWeightBold),
|
||||||
),
|
),
|
||||||
if (oldItem != null)
|
if (oldItem != null)
|
||||||
Text(
|
Text(
|
||||||
"Replaces ${oldItem.name}",
|
"Replaces ${oldItem.name}",
|
||||||
style: const TextStyle(fontSize: 12, color: Colors.grey),
|
style: const TextStyle(fontSize: 12, color: ThemeConfig.textColorGrey),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildStatChangeRow("Max HP", currentMaxHp, newMaxHp),
|
_buildStatChangeRow("Max HP", currentMaxHp, newMaxHp),
|
||||||
|
|
@ -544,7 +545,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Unequip ${itemToUnequip.name}?",
|
"Unequip ${itemToUnequip.name}?",
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: ThemeConfig.fontWeightBold),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildStatChangeRow("Max HP", currentMaxHp, newMaxHp),
|
_buildStatChangeRow("Max HP", currentMaxHp, newMaxHp),
|
||||||
|
|
@ -573,8 +574,8 @@ class InventoryScreen extends StatelessWidget {
|
||||||
Widget _buildStatChangeRow(String label, int oldVal, int newVal) {
|
Widget _buildStatChangeRow(String label, int oldVal, int newVal) {
|
||||||
int diff = newVal - oldVal;
|
int diff = newVal - oldVal;
|
||||||
Color color = diff > 0
|
Color color = diff > 0
|
||||||
? Colors.green
|
? ThemeConfig.statDiffPositive
|
||||||
: (diff < 0 ? Colors.red : Colors.grey);
|
: (diff < 0 ? ThemeConfig.statDiffNegative : ThemeConfig.statDiffNeutral);
|
||||||
String diffText = diff > 0 ? "(+$diff)" : (diff < 0 ? "($diff)" : "");
|
String diffText = diff > 0 ? "(+$diff)" : (diff < 0 ? "($diff)" : "");
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
|
|
@ -585,11 +586,11 @@ class InventoryScreen extends StatelessWidget {
|
||||||
Text(label),
|
Text(label),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Text("$oldVal", style: const TextStyle(color: Colors.grey)),
|
Text("$oldVal", style: const TextStyle(color: ThemeConfig.textColorGrey)),
|
||||||
const Icon(Icons.arrow_right, size: 16, color: Colors.grey),
|
const Icon(Icons.arrow_right, size: 16, color: ThemeConfig.textColorGrey),
|
||||||
Text(
|
Text(
|
||||||
"$newVal",
|
"$newVal",
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
style: const TextStyle(fontWeight: ThemeConfig.fontWeightBold),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -597,7 +598,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: color,
|
color: color,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -626,7 +627,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
padding: const EdgeInsets.only(top: 2.0, bottom: 2.0),
|
padding: const EdgeInsets.only(top: 2.0, bottom: 2.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
stats.join(", "),
|
stats.join(", "),
|
||||||
style: const TextStyle(fontSize: 10, color: Colors.blueAccent),
|
style: const TextStyle(fontSize: ThemeConfig.fontSizeSmall, color: ThemeConfig.statAtkColor),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -635,8 +636,7 @@ class InventoryScreen extends StatelessWidget {
|
||||||
padding: const EdgeInsets.only(bottom: 2.0),
|
padding: const EdgeInsets.only(bottom: 2.0),
|
||||||
child: Text(
|
child: Text(
|
||||||
effectTexts.join("\n"),
|
effectTexts.join("\n"),
|
||||||
style: const TextStyle(fontSize: 9, color: Colors.orangeAccent),
|
style: const TextStyle(fontSize: ThemeConfig.fontSizeTiny, color: ThemeConfig.rarityLegendary),
|
||||||
textAlign: TextAlign.center,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'main_wrapper.dart';
|
||||||
import '../widgets/responsive_container.dart';
|
import '../widgets/responsive_container.dart';
|
||||||
import '../game/save_manager.dart';
|
import '../game/save_manager.dart';
|
||||||
import '../providers/battle_provider.dart';
|
import '../providers/battle_provider.dart';
|
||||||
|
import '../game/config/theme_config.dart';
|
||||||
|
|
||||||
class MainMenuScreen extends StatefulWidget {
|
class MainMenuScreen extends StatefulWidget {
|
||||||
const MainMenuScreen({super.key});
|
const MainMenuScreen({super.key});
|
||||||
|
|
@ -58,7 +59,10 @@ class _MainMenuScreenState extends State<MainMenuScreen> {
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
end: Alignment.bottomCenter,
|
end: Alignment.bottomCenter,
|
||||||
colors: [Colors.black, Colors.blueGrey[900]!],
|
colors: [
|
||||||
|
ThemeConfig.mainMenuBgTop,
|
||||||
|
ThemeConfig.mainMenuBgBottom,
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: ResponsiveContainer(
|
child: ResponsiveContainer(
|
||||||
|
|
@ -67,23 +71,27 @@ class _MainMenuScreenState extends State<MainMenuScreen> {
|
||||||
: Column(
|
: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.gavel, size: 100, color: Colors.amber),
|
const Icon(
|
||||||
|
Icons.gavel,
|
||||||
|
size: 100,
|
||||||
|
color: ThemeConfig.mainIconColor,
|
||||||
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Text(
|
const Text(
|
||||||
"COLOSSEUM'S CHOICE",
|
"COLOSSEUM'S CHOICE",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 32,
|
fontSize: ThemeConfig.fontSizeHero,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
letterSpacing: 2.0,
|
letterSpacing: 2.0,
|
||||||
color: Colors.white,
|
color: ThemeConfig.mainTitleColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
const Text(
|
const Text(
|
||||||
"Rise as a Legend",
|
"Rise as a Legend",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 16,
|
fontSize: ThemeConfig.fontSizeLarge,
|
||||||
color: Colors.grey,
|
color: ThemeConfig.subTitleColor,
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -96,11 +104,11 @@ class _MainMenuScreenState extends State<MainMenuScreen> {
|
||||||
horizontal: 50,
|
horizontal: 50,
|
||||||
vertical: 15,
|
vertical: 15,
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.blueAccent,
|
backgroundColor: ThemeConfig.btnContinueBg,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: ThemeConfig.btnContinueText,
|
||||||
textStyle: const TextStyle(
|
textStyle: const TextStyle(
|
||||||
fontSize: 20,
|
fontSize: ThemeConfig.fontSizeXLarge,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: const Text("CONTINUE"),
|
child: const Text("CONTINUE"),
|
||||||
|
|
@ -123,11 +131,11 @@ class _MainMenuScreenState extends State<MainMenuScreen> {
|
||||||
horizontal: 50,
|
horizontal: 50,
|
||||||
vertical: 15,
|
vertical: 15,
|
||||||
),
|
),
|
||||||
backgroundColor: Colors.amber[700],
|
backgroundColor: ThemeConfig.btnNewGameBg,
|
||||||
foregroundColor: Colors.black,
|
foregroundColor: ThemeConfig.btnNewGameText,
|
||||||
textStyle: const TextStyle(
|
textStyle: const TextStyle(
|
||||||
fontSize: 20,
|
fontSize: ThemeConfig.fontSizeXLarge,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: const Text("NEW GAME"),
|
child: const Text("NEW GAME"),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import 'battle_screen.dart';
|
||||||
import 'inventory_screen.dart';
|
import 'inventory_screen.dart';
|
||||||
import 'settings_screen.dart';
|
import 'settings_screen.dart';
|
||||||
import '../widgets/responsive_container.dart';
|
import '../widgets/responsive_container.dart';
|
||||||
|
import '../game/config/theme_config.dart';
|
||||||
|
|
||||||
class MainWrapper extends StatefulWidget {
|
class MainWrapper extends StatefulWidget {
|
||||||
const MainWrapper({super.key});
|
const MainWrapper({super.key});
|
||||||
|
|
@ -23,7 +24,7 @@ class _MainWrapperState extends State<MainWrapper> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Colors.black, // Outer background for web
|
backgroundColor: ThemeConfig.mainMenuBgTop, // Outer background for web
|
||||||
body: Center(
|
body: Center(
|
||||||
child: ResponsiveContainer(
|
child: ResponsiveContainer(
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import '../providers/battle_provider.dart';
|
import '../providers/battle_provider.dart';
|
||||||
import 'main_menu_screen.dart';
|
import 'main_menu_screen.dart';
|
||||||
|
import '../game/config/theme_config.dart';
|
||||||
|
|
||||||
class SettingsScreen extends StatelessWidget {
|
class SettingsScreen extends StatelessWidget {
|
||||||
const SettingsScreen({super.key});
|
const SettingsScreen({super.key});
|
||||||
|
|
@ -15,28 +16,28 @@ class SettingsScreen extends StatelessWidget {
|
||||||
const Text(
|
const Text(
|
||||||
'Settings',
|
'Settings',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: ThemeConfig.fontSizeTitle,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: ThemeConfig.fontWeightBold,
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
// Placeholder for future settings
|
// Placeholder for future settings
|
||||||
const Text(
|
const Text(
|
||||||
'Effect Intensity: Normal',
|
'Effect Intensity: Normal',
|
||||||
style: TextStyle(color: Colors.white70),
|
style: TextStyle(color: ThemeConfig.textColorWhite),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
const Text(
|
const Text(
|
||||||
'Volume: 100%',
|
'Volume: 100%',
|
||||||
style: TextStyle(color: Colors.white70),
|
style: TextStyle(color: ThemeConfig.textColorWhite),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 40),
|
const SizedBox(height: 40),
|
||||||
|
|
||||||
// Restart Button
|
// Restart Button
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.orange,
|
backgroundColor: ThemeConfig.btnRestartBg,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
@ -63,7 +64,7 @@ class SettingsScreen extends StatelessWidget {
|
||||||
// Return to Main Menu Button
|
// Return to Main Menu Button
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.red,
|
backgroundColor: ThemeConfig.btnReturnMenuBg,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 32, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,9 @@ class CharacterStatusCard extends StatelessWidget {
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text("ATK: ${character.totalAtk}"),
|
Text("ATK: ${character.totalAtk}", style: const TextStyle(color: ThemeConfig.textColorWhite)),
|
||||||
Text("DEF: ${character.totalDefense}"),
|
Text("DEF: ${character.totalDefense}", style: const TextStyle(color: ThemeConfig.textColorWhite)),
|
||||||
Text("LUCK: ${character.totalLuck}"),
|
Text("LUCK: ${character.totalLuck}", style: const TextStyle(color: ThemeConfig.textColorWhite)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -135,16 +135,16 @@ class CharacterStatusCard extends StatelessWidget {
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.black54,
|
color: ThemeConfig.enemyIntentBg,
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
border: Border.all(color: Colors.redAccent),
|
border: Border.all(color: ThemeConfig.enemyIntentBorder),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"INTENT",
|
"INTENT",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.redAccent,
|
color: ThemeConfig.enemyIntentBorder,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
|
@ -156,14 +156,14 @@ class CharacterStatusCard extends StatelessWidget {
|
||||||
intent.type == EnemyActionType.attack
|
intent.type == EnemyActionType.attack
|
||||||
? Icons.flash_on
|
? Icons.flash_on
|
||||||
: Icons.shield,
|
: Icons.shield,
|
||||||
color: Colors.yellow,
|
color: ThemeConfig.rarityRare, // Yellow
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
intent.description,
|
intent.description,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: ThemeConfig.textColorWhite,
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import '../../providers/battle_provider.dart';
|
||||||
import '../../game/model/item.dart';
|
import '../../game/model/item.dart';
|
||||||
import '../../utils/item_utils.dart';
|
import '../../utils/item_utils.dart';
|
||||||
import '../../game/enums.dart';
|
import '../../game/enums.dart';
|
||||||
|
import '../../game/config/theme_config.dart';
|
||||||
|
|
||||||
class ShopUI extends StatelessWidget {
|
class ShopUI extends StatelessWidget {
|
||||||
final BattleProvider battleProvider;
|
final BattleProvider battleProvider;
|
||||||
|
|
@ -15,7 +16,7 @@ class ShopUI extends StatelessWidget {
|
||||||
final shopItems = battleProvider.currentStage.shopItems;
|
final shopItems = battleProvider.currentStage.shopItems;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.black87,
|
color: ThemeConfig.shopBg,
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: const EdgeInsets.all(16.0),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -25,22 +26,22 @@ class ShopUI extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
const Row(
|
const Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.store, size: 32, color: Colors.amber),
|
Icon(Icons.store, size: 32, color: ThemeConfig.mainIconColor),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
"Merchant",
|
"Merchant",
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: Colors.white),
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold, color: ThemeConfig.textColorWhite),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.monetization_on, color: Colors.amber),
|
const Icon(Icons.monetization_on, color: ThemeConfig.statGoldColor),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Text(
|
Text(
|
||||||
"${player.gold} G",
|
"${player.gold} G",
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.amber,
|
color: ThemeConfig.statGoldColor,
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
|
|
@ -49,7 +50,7 @@ class ShopUI extends StatelessWidget {
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Divider(color: Colors.grey),
|
const Divider(color: ThemeConfig.textColorGrey),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|
||||||
// Shop Items Grid
|
// Shop Items Grid
|
||||||
|
|
@ -58,7 +59,7 @@ class ShopUI extends StatelessWidget {
|
||||||
? const Center(
|
? const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Sold Out",
|
"Sold Out",
|
||||||
style: TextStyle(color: Colors.grey, fontSize: 24),
|
style: TextStyle(color: ThemeConfig.textColorGrey, fontSize: 24),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: GridView.builder(
|
: GridView.builder(
|
||||||
|
|
@ -76,7 +77,7 @@ class ShopUI extends StatelessWidget {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: () => _showBuyConfirmation(context, item),
|
onTap: () => _showBuyConfirmation(context, item),
|
||||||
child: Card(
|
child: Card(
|
||||||
color: Colors.blueGrey[800],
|
color: ThemeConfig.shopItemCardBg,
|
||||||
shape: item.rarity != ItemRarity.magic
|
shape: item.rarity != ItemRarity.magic
|
||||||
? RoundedRectangleBorder(
|
? RoundedRectangleBorder(
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
|
|
@ -129,7 +130,7 @@ class ShopUI extends StatelessWidget {
|
||||||
height: 32,
|
height: 32,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: canBuy ? Colors.amber : Colors.grey,
|
backgroundColor: canBuy ? ThemeConfig.statGoldColor : ThemeConfig.btnDisabled,
|
||||||
foregroundColor: Colors.black,
|
foregroundColor: Colors.black,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
),
|
),
|
||||||
|
|
@ -159,28 +160,28 @@ class ShopUI extends StatelessWidget {
|
||||||
children: [
|
children: [
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.blueGrey,
|
backgroundColor: ThemeConfig.btnRerollBg,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: player.gold >= 50
|
onPressed: player.gold >= 50
|
||||||
? () => battleProvider.rerollShopItems()
|
? () => battleProvider.rerollShopItems()
|
||||||
: null,
|
: null,
|
||||||
icon: const Icon(Icons.refresh, color: Colors.white),
|
icon: const Icon(Icons.refresh, color: ThemeConfig.textColorWhite),
|
||||||
label: const Text(
|
label: const Text(
|
||||||
"Reroll (50 G)",
|
"Reroll (50 G)",
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: ThemeConfig.textColorWhite),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
ElevatedButton.icon(
|
ElevatedButton.icon(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.redAccent,
|
backgroundColor: ThemeConfig.btnLeaveBg,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () => battleProvider.proceedToNextStage(),
|
onPressed: () => battleProvider.proceedToNextStage(),
|
||||||
icon: const Icon(Icons.exit_to_app, color: Colors.white),
|
icon: const Icon(Icons.exit_to_app, color: ThemeConfig.textColorWhite),
|
||||||
label: const Text(
|
label: const Text(
|
||||||
"Leave Shop",
|
"Leave Shop",
|
||||||
style: TextStyle(color: Colors.white),
|
style: TextStyle(color: ThemeConfig.textColorWhite),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -204,7 +205,7 @@ class ShopUI extends StatelessWidget {
|
||||||
child: const Text("Cancel"),
|
child: const Text("Cancel"),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.amber),
|
style: ElevatedButton.styleFrom(backgroundColor: ThemeConfig.statGoldColor),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
battleProvider.buyItem(item);
|
battleProvider.buyItem(item);
|
||||||
Navigator.pop(ctx);
|
Navigator.pop(ctx);
|
||||||
|
|
@ -237,7 +238,7 @@ class ShopUI extends StatelessWidget {
|
||||||
if (item.effects.isNotEmpty)
|
if (item.effects.isNotEmpty)
|
||||||
Text(
|
Text(
|
||||||
item.effects.first.type.name.toUpperCase(),
|
item.effects.first.type.name.toUpperCase(),
|
||||||
style: const TextStyle(fontSize: 9, color: Colors.orangeAccent),
|
style: const TextStyle(fontSize: 9, color: ThemeConfig.rarityLegendary),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
@ -256,11 +257,11 @@ class RestUI extends StatelessWidget {
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.local_hotel, size: 64, color: Colors.blue),
|
const Icon(Icons.local_hotel, size: 64, color: ThemeConfig.btnRestBg),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
const Text("Rest Area", style: TextStyle(fontSize: 24)),
|
const Text("Rest Area", style: TextStyle(fontSize: 24, color: ThemeConfig.textColorWhite)),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
const Text("Take a breath and heal."),
|
const Text("Take a breath and heal.", style: TextStyle(color: ThemeConfig.textColorWhite)),
|
||||||
const SizedBox(height: 32),
|
const SizedBox(height: 32),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
|
|
|
||||||
|
|
@ -115,6 +115,7 @@
|
||||||
|
|
||||||
- **Prompt Driven Development:** `prompt/XX_description.md` 유지.
|
- **Prompt Driven Development:** `prompt/XX_description.md` 유지.
|
||||||
- **Language:** **모든 프롬프트 파일(prompt/XX_...)은 반드시 한국어(Korean)로 작성해야 합니다.**
|
- **Language:** **모든 프롬프트 파일(prompt/XX_...)은 반드시 한국어(Korean)로 작성해야 합니다.**
|
||||||
|
- **Config Management:** 하드코딩되는 값들은 `config` 폴더 내 파일들(`lib/game/config/` 등)에서 통합 관리할 수 있도록 작성해야 합니다.
|
||||||
- **State Management:** `Provider` + `Stream` (이벤트성 데이터).
|
- **State Management:** `Provider` + `Stream` (이벤트성 데이터).
|
||||||
- **Data:** JSON 기반.
|
- **Data:** JSON 기반.
|
||||||
|
|
||||||
|
|
@ -158,3 +159,4 @@
|
||||||
- [x] 42_item_rarity_and_tier.md
|
- [x] 42_item_rarity_and_tier.md
|
||||||
- [x] 43_shop_system.md
|
- [x] 43_shop_system.md
|
||||||
- [x] 44_settings_and_local_storage.md
|
- [x] 44_settings_and_local_storage.md
|
||||||
|
- [x] 45_config_refactoring.md
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# 45. Config & UI 전면 리팩토링 (Config & UI Refactoring)
|
||||||
|
|
||||||
|
## 1. 목표 (Goal)
|
||||||
|
- 프로젝트 전반에 산재된 하드코딩된 값(정적 상수, 색상, 폰트)을 설정 파일(`GameConfig`, `ThemeConfig`)로 통합 관리합니다.
|
||||||
|
- 모든 화면(`MainMenu`, `Battle`, `Inventory`, `Settings`, `CharacterSelection`)의 UI 스타일을 통일합니다.
|
||||||
|
|
||||||
|
## 2. 구현 상세 (Implementation Details)
|
||||||
|
|
||||||
|
### A. 게임 밸런스 설정 (`GameConfig`)
|
||||||
|
- **파일:** `lib/game/config/game_config.dart`
|
||||||
|
- **내용:**
|
||||||
|
- **인벤토리/경제:** 최대 크기, 시작 골드, 상점 비용 및 리롤 등.
|
||||||
|
- **스테이지:** 구간별 설정, 티어 분포.
|
||||||
|
- **전투:** 회복율, 데미지 배율, 방어도 감소, 애니메이션 딜레이 등.
|
||||||
|
- **시스템:** 저장 키 (`saveKey`).
|
||||||
|
- **적용:** `BattleProvider`, `Entity`, `SaveManager`의 매직 넘버 제거.
|
||||||
|
|
||||||
|
### B. 테마 및 스타일 설정 (`ThemeConfig`)
|
||||||
|
- **파일:** `lib/game/config/theme_config.dart`
|
||||||
|
- **색상 (Colors):**
|
||||||
|
- 메인 메뉴(배경, 버튼), 전투 화면(배경, UI, 리스크), 상점/휴식 화면, 아이템 등급 등 모든 색상 정의.
|
||||||
|
- **폰트 (Fonts):**
|
||||||
|
- **Size:** `Tiny`(8.0) ~ `Huge`(48.0) 등 10단계 정의.
|
||||||
|
- **Weight:** `Normal`, `Bold` 정의.
|
||||||
|
|
||||||
|
### C. 화면별 리팩토링 (Screen Refactoring)
|
||||||
|
- **`lib/screens/` 및 `lib/widgets/` 전체:**
|
||||||
|
- **`BattleScreen` & Widgets:** 로그, 리스크 다이얼로그, 캐릭터 카드, 게임 오버, 보상 팝업 등.
|
||||||
|
- **`MainMenuScreen`:** 타이틀, 버튼, 배경.
|
||||||
|
- **`InventoryScreen`:** 슬롯, 스탯 텍스트, 팝업.
|
||||||
|
- **`CharacterSelectionScreen`:** 카드, 텍스트 스타일.
|
||||||
|
- **`SettingsScreen`:** 텍스트, 버튼.
|
||||||
|
- **`MainWrapper`:** 공통 배경색 적용.
|
||||||
|
|
||||||
|
## 3. 결과 (Result)
|
||||||
|
- **중앙 관리:** 게임의 수치 밸런스와 디자인 테마를 각각 `GameConfig`와 `ThemeConfig`에서 손쉽게 수정 가능해졌습니다.
|
||||||
|
- **일관성:** 모든 화면에서 통일된 색상 팔레트와 폰트 스케일을 사용하여 UI 완성도가 향상되었습니다.
|
||||||
|
- **유지보수:** 하드코딩된 값들이 제거되어 코드 가독성 및 유지보수성이 대폭 개선되었습니다.
|
||||||
Loading…
Reference in New Issue