From ff2ae329c19931d9d59ec6bfb66fa8d01bc5761d Mon Sep 17 00:00:00 2001 From: LemonNexus Date: Mon, 9 Feb 2026 19:33:05 +0000 Subject: [PATCH] fix: add safe decimal conversion to armor_system from_dict methods - ProtectionProfile.from_dict now handles int/float/Decimal/string values - ArmorPlate.from_dict uses safe_decimal for block_chance - ArmorPiece.from_dict uses safe_decimal for decay_per_hp and weight - Prevents 'Decimal + str' type errors when loading saved loadouts --- core/armor_system.py | 58 ++++++++++++++++++++++++++++++++------------ 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/core/armor_system.py b/core/armor_system.py index c3a741f..ffc0c14 100644 --- a/core/armor_system.py +++ b/core/armor_system.py @@ -117,18 +117,27 @@ class ProtectionProfile: } @classmethod - def from_dict(cls, data: Dict[str, str]) -> "ProtectionProfile": - """Create from dictionary.""" + def from_dict(cls, data: Dict[str, Any]) -> "ProtectionProfile": + """Create from dictionary with validation.""" + def safe_decimal(val): + if isinstance(val, Decimal): + return val + if isinstance(val, (int, float)): + return Decimal(str(val)) + if isinstance(val, str): + return Decimal(val) if val else Decimal('0') + return Decimal('0') + return cls( - stab=Decimal(data.get('stab', '0')), - cut=Decimal(data.get('cut', '0')), - impact=Decimal(data.get('impact', '0')), - penetration=Decimal(data.get('penetration', '0')), - shrapnel=Decimal(data.get('shrapnel', '0')), - burn=Decimal(data.get('burn', '0')), - cold=Decimal(data.get('cold', '0')), - acid=Decimal(data.get('acid', '0')), - electric=Decimal(data.get('electric', '0')), + stab=safe_decimal(data.get('stab', '0')), + cut=safe_decimal(data.get('cut', '0')), + impact=safe_decimal(data.get('impact', '0')), + penetration=safe_decimal(data.get('penetration', '0')), + shrapnel=safe_decimal(data.get('shrapnel', '0')), + burn=safe_decimal(data.get('burn', '0')), + cold=safe_decimal(data.get('cold', '0')), + acid=safe_decimal(data.get('acid', '0')), + electric=safe_decimal(data.get('electric', '0')), ) @@ -202,13 +211,22 @@ class ArmorPlate: @classmethod def from_dict(cls, data: Dict) -> "ArmorPlate": - """Create from dictionary.""" + """Create from dictionary with validation.""" + def safe_decimal(val): + if isinstance(val, Decimal): + return val + if isinstance(val, (int, float)): + return Decimal(str(val)) + if isinstance(val, str): + return Decimal(val) if val else Decimal('0') + return Decimal('0') + return cls( name=data['name'], item_id=data['item_id'], protection=ProtectionProfile.from_dict(data.get('protection', {})), durability=data.get('durability', 2000), - block_chance=Decimal(data.get('block_chance', '0')), + block_chance=safe_decimal(data.get('block_chance', '0')), ) @@ -328,7 +346,16 @@ class ArmorPiece: @classmethod def from_dict(cls, data: Dict) -> "ArmorPiece": - """Create from dictionary.""" + """Create from dictionary with validation.""" + def safe_decimal(val): + if isinstance(val, Decimal): + return val + if isinstance(val, (int, float)): + return Decimal(str(val)) + if isinstance(val, str): + return Decimal(val) if val else Decimal('0') + return Decimal('0') + piece = cls( name=data['name'], item_id=data['item_id'], @@ -336,7 +363,8 @@ class ArmorPiece: set_name=data.get('set_name'), protection=ProtectionProfile.from_dict(data.get('protection', {})), durability=data.get('durability', 2000), - weight=Decimal(data.get('weight', '1.0')), + decay_per_hp=safe_decimal(data.get('decay_per_hp', '0.05')), + weight=safe_decimal(data.get('weight', '1.0')), ) if data.get('attached_plate'): piece.attached_plate = ArmorPlate.from_dict(data['attached_plate'])