Lemontropia-Suite/core/armor_decay.py

224 lines
6.7 KiB
Python

"""
Armor Decay Calculator for Lemontropia Suite
Implements the official VU 15.15 armor decay formula.
"""
from decimal import Decimal
from typing import Dict, Optional
from dataclasses import dataclass
# Armor durability database (from official guide)
ARMOR_DURABILITY: Dict[str, int] = {
# Unlimited Armors
"Ghost": 2000,
"Gremlin": 2950,
"Adjusted Nemesis": 3400,
"Angel": 4000,
"Hero": 3500,
"Dragon": 3000,
"Gorgon": 4500,
"Shogun": 2800,
"Viking": 3200,
"Titan": 3800,
"Demon": 4200,
"Shadow": 3600,
"Warrior": 3100,
"Guardian": 3300,
"Sentinel": 3900,
"Pirate": 2700,
"Swamp": 2600,
"Desert": 2900,
"Arctic": 3400,
"Jungle": 2500,
"Mountain": 3700,
"Forest": 2400,
"Urban": 3500,
"Combat": 4100,
"Assault": 4300,
"Recon": 2300,
"Spec Ops": 4400,
# Limited Armors
"Martial (L)": 13000,
"Mayhem (L)": 13300,
"Angel (L)": 14000,
"Perseus (L)": 15000,
"Moonshine (L)": 15400,
"Eon (L)": 12000,
"Hermes (L)": 12500,
"Tiger (L)": 11000,
"Spartacus (L)": 11500,
"Vain (L)": 11800,
}
# Default durability for unknown armors
DEFAULT_DURABILITY = 2000 # Same as Ghost
def calculate_armor_decay(damage_absorbed: Decimal, durability: int) -> Decimal:
"""Calculate armor decay in PED.
Formula: Decay = damage * 0.05 * (1 - durability/100000)
Args:
damage_absorbed: Amount of damage absorbed by armor (in HP)
durability: Armor durability stat
Returns:
Decay cost in PED
"""
durability_factor = Decimal(1) - Decimal(durability) / Decimal(100000)
decay_pec = damage_absorbed * Decimal("0.05") * durability_factor
return decay_pec / Decimal(100) # Convert PEC to PED
def calculate_hp_per_pec(durability: int) -> Decimal:
"""Calculate armor economy in hp/pec.
Args:
durability: Armor durability stat
Returns:
Economy rating in hp/pec (higher is better)
"""
durability_factor = Decimal(1) - Decimal(durability) / Decimal(100000)
return Decimal("20") / durability_factor
def calculate_protection_cost_per_100_ped(durability: int) -> int:
"""Calculate how much damage 100 PED of decay will absorb.
Args:
durability: Armor durability stat
Returns:
Damage absorbed per 100 PED decay
"""
hp_per_pec = calculate_hp_per_pec(durability)
return int(hp_per_pec * 10000) # 100 PED = 10,000 PEC
@dataclass
class ArmorPiece:
"""Represents a single armor piece."""
name: str
slot: str # 'head', 'chest', 'arms', 'hands', 'legs', 'feet'
durability: int
protection_impact: Decimal = Decimal("0")
protection_cut: Decimal = Decimal("0")
protection_stab: Decimal = Decimal("0")
protection_burn: Decimal = Decimal("0")
protection_cold: Decimal = Decimal("0")
protection_acid: Decimal = Decimal("0")
protection_electric: Decimal = Decimal("0")
def calculate_decay(self, damage_absorbed: Decimal) -> Decimal:
"""Calculate decay for this piece."""
return calculate_armor_decay(damage_absorbed, self.durability)
def get_economy(self) -> Decimal:
"""Get hp/pec economy rating."""
return calculate_hp_per_pec(self.durability)
@dataclass
class ArmorSet:
"""Represents a complete armor set (7 pieces)."""
name: str
head: Optional[ArmorPiece] = None
chest: Optional[ArmorPiece] = None
left_arm: Optional[ArmorPiece] = None
right_arm: Optional[ArmorPiece] = None
left_hand: Optional[ArmorPiece] = None
right_hand: Optional[ArmorPiece] = None
legs: Optional[ArmorPiece] = None
feet: Optional[ArmorPiece] = None
def get_all_pieces(self) -> list:
"""Get list of all equipped pieces."""
pieces = []
for piece in [self.head, self.chest, self.left_arm, self.right_arm,
self.left_hand, self.right_hand, self.legs, self.feet]:
if piece:
pieces.append(piece)
return pieces
def get_total_protection(self, damage_type: str = "impact") -> Decimal:
"""Get total protection for a damage type."""
total = Decimal("0")
for piece in self.get_all_pieces():
protection = getattr(piece, f"protection_{damage_type}", Decimal("0"))
total += protection
return total
def calculate_total_decay(self, damage_per_piece: Dict[str, Decimal]) -> Decimal:
"""Calculate total decay for all pieces.
Args:
damage_per_piece: Dict mapping slot names to damage absorbed
Returns:
Total decay in PED
"""
total_decay = Decimal("0")
for piece in self.get_all_pieces():
if piece.slot in damage_per_piece:
damage = damage_per_piece[piece.slot]
total_decay += piece.calculate_decay(damage)
return total_decay
def get_armor_durability(armor_name: str) -> int:
"""Get durability for an armor by name.
Args:
armor_name: Name of the armor
Returns:
Durability value (defaults to 2000 if unknown)
"""
return ARMOR_DURABILITY.get(armor_name, DEFAULT_DURABILITY)
def compare_armor_economy(armor_names: list) -> list:
"""Compare economy of multiple armors.
Args:
armor_names: List of armor names to compare
Returns:
List of tuples (name, durability, hp_per_pec, dmg_per_100ped)
"""
results = []
for name in armor_names:
durability = get_armor_durability(name)
hp_per_pec = calculate_hp_per_pec(durability)
dmg_per_100 = calculate_protection_cost_per_100_ped(durability)
results.append((name, durability, hp_per_pec, dmg_per_100))
# Sort by economy (hp/pec) descending
results.sort(key=lambda x: x[2], reverse=True)
return results
# Example usage
if __name__ == "__main__":
# Compare popular armors
armors = ["Ghost", "Gremlin", "Adjusted Nemesis", "Angel",
"Martial (L)", "Angel (L)", "Perseus (L)"]
print("Armor Economy Comparison:")
print("-" * 70)
print(f"{'Armor':<25} {'Dur':<8} {'hp/pec':<12} {'dmg/100PED':<12}")
print("-" * 70)
for name, durability, hp_per_pec, dmg_per_100 in compare_armor_economy(armors):
print(f"{name:<25} {durability:<8} {hp_per_pec:<12.2f} {dmg_per_100:<12,}")
# Example decay calculation
print("\n\nDecay Example (15 damage absorbed):")
print("-" * 50)
for armor in ["Ghost", "Angel", "Martial (L)"]:
durability = get_armor_durability(armor)
decay = calculate_armor_decay(Decimal("15"), durability)
print(f"{armor:<20} {decay:.5f} PED")