This commit is contained in:
2025-12-04 18:59:25 +09:00
parent 0dccab9eec
commit d3fd9680c2
11 changed files with 206 additions and 43 deletions
+32 -36
View File
@@ -7,74 +7,70 @@ class ItemTemplate {
final String id;
final String name;
final String description;
final int baseAtk;
final int baseHp;
final int baseArmor;
final int atkBonus;
final int hpBonus;
final int armorBonus;
final EquipmentSlot slot;
final List<ItemEffect> effects;
final int price;
final String? image;
final int luck;
const ItemTemplate({
required this.id,
required this.name,
required this.description,
this.baseAtk = 0,
this.baseHp = 0,
this.baseArmor = 0,
required this.atkBonus,
required this.hpBonus,
required this.armorBonus,
required this.slot,
this.effects = const [],
this.price = 0,
required this.effects,
required this.price,
this.image,
this.luck = 0,
});
factory ItemTemplate.fromJson(Map<String, dynamic> json) {
var effectsList = <ItemEffect>[];
if (json['effects'] != null) {
effectsList = (json['effects'] as List)
.map((e) => ItemEffect.fromJson(e))
.toList();
}
return ItemTemplate(
id:
json['id'] ??
json['name'], // Fallback to name if id is missing (for backward compatibility during dev)
id: json['id'],
name: json['name'],
description: json['description'],
baseAtk: json['baseAtk'] ?? 0,
baseHp: json['baseHp'] ?? 0,
baseArmor: json['baseArmor'] ?? 0,
atkBonus: json['atkBonus'] ?? 0,
hpBonus: json['hpBonus'] ?? 0,
armorBonus: json['armorBonus'] ?? 0,
slot: EquipmentSlot.values.firstWhere((e) => e.name == json['slot']),
effects:
(json['effects'] as List<dynamic>?)
?.map((e) => ItemEffect.fromJson(e))
.toList() ??
[],
price: json['price'] ?? 0,
effects: effectsList,
price: json['price'] ?? 10,
image: json['image'],
luck: json['luck'] ?? 0,
);
}
// Create an instance of Item based on this template, optionally scaling with stage
Item createItem({int stage = 1}) {
// Simple scaling logic: add stage-1 to relevant stats
// You can make this more complex (multiplier, tiering, etc.)
int scaledAtk = baseAtk > 0 ? baseAtk + (stage - 1) : 0;
int scaledHp = baseHp > 0 ? baseHp + (stage - 1) * 5 : 0;
int scaledArmor = baseArmor > 0 ? baseArmor + (stage - 1) : 0;
// Use fixed price from template
int finalPrice = price;
// Optional: Increase price if stage > 1 (e.g. +10% per stage)
if (stage > 1) {
finalPrice = (price * (1 + (stage - 1) * 0.1)).toInt();
}
// Scale stats based on stage
int scaledAtk = (atkBonus * (1 + (stage - 1) * 0.1)).toInt();
int scaledHp = (hpBonus * (1 + (stage - 1) * 0.1)).toInt();
int scaledArmor = (armorBonus * (1 + (stage - 1) * 0.1)).toInt();
return Item(
id: id,
name: "$name${stage > 1 ? ' +${stage - 1}' : ''}", // Append +1, +2 etc.
name: "$name${stage > 1 ? ' +${stage - 1}' : ''}",
description: description,
atkBonus: scaledAtk,
hpBonus: scaledHp,
armorBonus: scaledArmor,
slot: slot,
effects: effects, // Pass the effects to the Item
price: finalPrice,
effects: effects,
price: price,
image: image,
luck: luck,
);
}
}
+1
View File
@@ -33,3 +33,4 @@ enum EquipmentSlot { weapon, armor, shield, accessory }
enum DamageType { normal, bleed, vulnerable }
enum StatType { maxHp, atk, defense }
+16
View File
@@ -1,5 +1,6 @@
import 'item.dart';
import 'status_effect.dart';
import 'stat_modifier.dart';
import '../enums.dart';
class Character {
@@ -19,6 +20,9 @@ class Character {
// Active status effects
List<StatusEffect> statusEffects = [];
// Permanent stat modifiers (e.g. Ascension, Potions)
List<PermanentStatModifier> permanentModifiers = [];
Character({
required this.name,
int? hp,
@@ -66,6 +70,14 @@ class Character {
statusEffects.removeWhere((e) => e.duration <= 0);
}
void addPermanentModifier(PermanentStatModifier modifier) {
permanentModifiers.add(modifier);
}
void removePermanentModifier(String id) {
permanentModifiers.removeWhere((m) => m.id == id);
}
/// Helper to check if character has a specific status
bool hasStatus(StatusEffectType type) {
return statusEffects.any((e) => e.type == type);
@@ -86,6 +98,10 @@ class Character {
return baseDefense + bonus;
}
int get totalLuck {
return equipment.values.fold(0, (sum, item) => sum + item.luck);
}
bool get isDead => hp <= 0;
// Adds an item to inventory, returns true if successful, false if inventory is full
+3 -1
View File
@@ -46,8 +46,9 @@ class Item {
final List<ItemEffect> effects; // Status effects this item can inflict
final int price; // New: Sell/Buy value
final String? image; // New: Image path
final int luck; // Success rate bonus (e.g. 5 = 5%)
Item({
const Item({
required this.id,
required this.name,
required this.description,
@@ -58,6 +59,7 @@ class Item {
this.effects = const [], // Default to no effects
this.price = 0,
this.image,
this.luck = 0,
});
String get typeName {
+41
View File
@@ -0,0 +1,41 @@
import '../enums.dart';
class PermanentStatModifier {
final String id;
final String name;
final String description;
final StatType statType;
final ModifierType type;
final double value;
const PermanentStatModifier({
required this.id,
required this.name,
required this.description,
required this.statType,
required this.type,
required this.value,
});
factory PermanentStatModifier.fromJson(Map<String, dynamic> json) {
return PermanentStatModifier(
id: json['id'],
name: json['name'],
description: json['description'],
statType: StatType.values.firstWhere((e) => e.name == json['statType']),
type: ModifierType.values.firstWhere((e) => e.name == json['type']),
value: json['value'].toDouble(),
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'description': description,
'statType': statType.name,
'type': type.name,
'value': value,
};
}
}
+12 -3
View File
@@ -277,15 +277,24 @@ class BattleProvider with ChangeNotifier {
switch (risk) {
case RiskLevel.safe:
success = random.nextDouble() < 1.0; // 100%
// Safe: 100% base chance + luck
double chance = 1.0 + (player.totalLuck / 100.0);
if (chance > 1.0) chance = 1.0;
success = random.nextDouble() < chance;
efficiency = 0.5; // 50%
break;
case RiskLevel.normal:
success = random.nextDouble() < 0.8; // 80%
// Normal: 80% base chance + luck
double chance = 0.8 + (player.totalLuck / 100.0);
if (chance > 1.0) chance = 1.0;
success = random.nextDouble() < chance;
efficiency = 1.0; // 100%
break;
case RiskLevel.risky:
success = random.nextDouble() < 0.4; // 40%
// Risky: 40% base chance + luck
double chance = 0.4 + (player.totalLuck / 100.0);
if (chance > 1.0) chance = 1.0;
success = random.nextDouble() < chance;
efficiency = 2.0; // 200%
break;
}
+8 -3
View File
@@ -274,18 +274,23 @@ class _BattleScreenState extends State<BattleScreen> {
: "Armor";
String successRate = "";
double baseChance = 0.0;
switch (risk) {
case RiskLevel.safe:
successRate = "100%";
baseChance = 1.0;
break;
case RiskLevel.normal:
successRate = "80%";
baseChance = 0.8;
break;
case RiskLevel.risky:
successRate = "40%";
baseChance = 0.4;
break;
}
double finalChance = baseChance + (player.totalLuck / 100.0);
if (finalChance > 1.0) finalChance = 1.0;
successRate = "${(finalChance * 100).toInt()}%";
infoText =
"Success: $successRate, Eff: ${(efficiency * 100).toInt()}% ($expectedValue $valueUnit)";
+6
View File
@@ -47,6 +47,11 @@ class InventoryScreen extends StatelessWidget {
"${player.gold} G",
color: Colors.amber,
),
_buildStatItem(
"Luck",
"${player.totalLuck}",
color: Colors.green,
),
],
),
],
@@ -575,6 +580,7 @@ class InventoryScreen extends StatelessWidget {
if (item.atkBonus > 0) stats.add("+${item.atkBonus} ATK");
if (item.hpBonus > 0) stats.add("+${item.hpBonus} HP");
if (item.armorBonus > 0) stats.add("+${item.armorBonus} DEF");
if (item.luck > 0) stats.add("+${item.luck} Luck");
// Include effects
List<String> effectTexts = item.effects.map((e) => e.description).toList();