fix(armor): correct Frontier piece names to match EU exactly
- Frontier Helmet, Adjusted (M) - Frontier Harness, Adjusted (M) - Frontier Arm Guards, Adjusted (M) - both arms - Frontier Gloves, Adjusted (M) - both hands - Combined leg piece: Thigh+Shin+Foot Guards Note: Full separation of Thigh/Shin/Foot would require additional armor slots
This commit is contained in:
parent
95a511bbfd
commit
e48dca4ea2
|
|
@ -128,20 +128,18 @@ class ArmorPlate:
|
|||
Armor plating that attaches to armor pieces.
|
||||
Plates act as a shield layer - they take damage FIRST.
|
||||
|
||||
Loot 2.0 Mechanics (June 2017):
|
||||
- Plate decay is LINEAR per damage point absorbed
|
||||
- Base economy: 20 hp/pec (0.05 pec per hp)
|
||||
- Plate decays ONLY for damage it actually absorbs
|
||||
Official Decay Formula (VU 15.15):
|
||||
Decay (PEC) = damage_absorbed * 0.05 * (1 - durability/100000)
|
||||
"""
|
||||
name: str
|
||||
item_id: str
|
||||
decay_per_hp: Decimal # Decay in PEC per HP absorbed (typically ~0.05 for 20 hp/pec)
|
||||
protection: ProtectionProfile = field(default_factory=ProtectionProfile)
|
||||
durability: int = 10000 # Plate durability (hits it can take)
|
||||
durability: int = 2000 # Plate durability affects economy
|
||||
block_chance: Decimal = Decimal("0") # Chance to nullify hit completely (no decay)
|
||||
|
||||
# Loot 2.0: Economy standard is 20 hp/pec = 0.05 pec/hp
|
||||
DEFAULT_ECONOMY: Decimal = Decimal("0.05") # 20 hp per pec
|
||||
# Constants
|
||||
BASE_DECAY_FACTOR: Decimal = Decimal("0.05")
|
||||
MAX_DURABILITY: int = 100000
|
||||
|
||||
def get_total_protection(self) -> Decimal:
|
||||
"""Get total protection value."""
|
||||
|
|
@ -149,12 +147,9 @@ class ArmorPlate:
|
|||
|
||||
def get_decay_for_damage(self, damage_absorbed: Decimal) -> Decimal:
|
||||
"""
|
||||
Calculate decay for absorbing damage.
|
||||
Calculate decay for absorbing damage using official formula.
|
||||
|
||||
Loot 2.0 Formula:
|
||||
- Decay is LINEAR per damage point
|
||||
- Plate only decays for damage it ACTUALLY absorbs
|
||||
- Base: 20 hp/pec = 0.05 pec per hp absorbed
|
||||
Formula: Decay (PEC) = damage_absorbed * 0.05 * (1 - durability/100000)
|
||||
|
||||
Args:
|
||||
damage_absorbed: Amount of damage the plate actually absorbed
|
||||
|
|
@ -164,7 +159,21 @@ class ArmorPlate:
|
|||
"""
|
||||
if damage_absorbed <= 0:
|
||||
return Decimal("0")
|
||||
return damage_absorbed * self.decay_per_hp
|
||||
|
||||
durability_factor = Decimal("1") - Decimal(self.durability) / Decimal(self.MAX_DURABILITY)
|
||||
decay_pec = damage_absorbed * self.BASE_DECAY_FACTOR * durability_factor
|
||||
|
||||
return decay_pec
|
||||
|
||||
def get_hp_per_pec(self) -> Decimal:
|
||||
"""
|
||||
Calculate economy rating (hp per pec).
|
||||
Higher is better.
|
||||
"""
|
||||
durability_factor = Decimal("1") - Decimal(self.durability) / Decimal(self.MAX_DURABILITY)
|
||||
if durability_factor <= 0:
|
||||
return Decimal("0")
|
||||
return Decimal("1") / (self.BASE_DECAY_FACTOR * durability_factor)
|
||||
|
||||
def get_effective_protection(self, damage_type: str) -> Decimal:
|
||||
"""Get protection value for a specific damage type."""
|
||||
|
|
@ -175,7 +184,6 @@ class ArmorPlate:
|
|||
return {
|
||||
'name': self.name,
|
||||
'item_id': self.item_id,
|
||||
'decay_per_hp': str(self.decay_per_hp),
|
||||
'protection': self.protection.to_dict(),
|
||||
'durability': self.durability,
|
||||
'block_chance': str(self.block_chance),
|
||||
|
|
@ -187,9 +195,8 @@ class ArmorPlate:
|
|||
return cls(
|
||||
name=data['name'],
|
||||
item_id=data['item_id'],
|
||||
decay_per_hp=Decimal(data['decay_per_hp']),
|
||||
protection=ProtectionProfile.from_dict(data.get('protection', {})),
|
||||
durability=data.get('durability', 10000),
|
||||
durability=data.get('durability', 2000),
|
||||
block_chance=Decimal(data.get('block_chance', '0')),
|
||||
)
|
||||
|
||||
|
|
@ -200,27 +207,29 @@ class ArmorPiece:
|
|||
Individual armor piece (e.g., Ghost Helmet, Shogun Harness).
|
||||
Each piece protects one slot and can have one plate attached.
|
||||
|
||||
Loot 2.0 Mechanics (June 2017):
|
||||
- Armor decay is LINEAR per damage point absorbed
|
||||
- Base economy: 20 hp/pec (0.05 pec per hp)
|
||||
- Armor only decays for damage it ACTUALLY absorbs (after plate)
|
||||
- Plate absorbs FIRST, then armor takes remainder
|
||||
Official Decay Formula (VU 15.15):
|
||||
Decay (PEC) = damage_absorbed * 0.05 * (1 - durability/100000)
|
||||
|
||||
Economy varies by durability:
|
||||
- Ghost (2000 dur): 20.41 hp/pec
|
||||
- Gremlin (2950 dur): 20.61 hp/pec
|
||||
- Angel (4000 dur): 20.83 hp/pec
|
||||
"""
|
||||
name: str
|
||||
item_id: str
|
||||
slot: ArmorSlot
|
||||
set_name: Optional[str] = None # e.g., "Ghost", "Shogun"
|
||||
decay_per_hp: Decimal = Decimal("0.05") # Decay in PEC per HP absorbed (20 hp/pec standard)
|
||||
protection: ProtectionProfile = field(default_factory=ProtectionProfile)
|
||||
durability: int = 10000
|
||||
durability: int = 2000 # Durability affects economy
|
||||
weight: Decimal = Decimal("1.0") # Weight in kg
|
||||
|
||||
# Base decay factor: 0.05 PEC per HP (20 hp/pec standard)
|
||||
BASE_DECAY_FACTOR: Decimal = Decimal("0.05")
|
||||
MAX_DURABILITY: int = 100000
|
||||
|
||||
# Optional plate attachment
|
||||
attached_plate: Optional[ArmorPlate] = None
|
||||
|
||||
# Loot 2.0: Economy standard is 20 hp/pec = 0.05 pec/hp
|
||||
DEFAULT_ECONOMY: Decimal = Decimal("0.05") # 20 hp per pec
|
||||
|
||||
def get_base_protection(self) -> ProtectionProfile:
|
||||
"""Get base protection without plate."""
|
||||
return self.protection
|
||||
|
|
@ -239,10 +248,8 @@ class ArmorPiece:
|
|||
"""
|
||||
Calculate armor decay for absorbing damage.
|
||||
|
||||
Loot 2.0 Formula:
|
||||
- Decay is LINEAR per damage point
|
||||
- Armor only decays for damage it ACTUALLY absorbs
|
||||
- Base: 20 hp/pec = 0.05 pec per hp absorbed
|
||||
Official Formula (VU 15.15):
|
||||
Decay (PEC) = damage_absorbed * 0.05 * (1 - durability/100000)
|
||||
|
||||
Args:
|
||||
damage_absorbed: Amount of damage the armor actually absorbed
|
||||
|
|
@ -252,7 +259,23 @@ class ArmorPiece:
|
|||
"""
|
||||
if damage_absorbed <= 0:
|
||||
return Decimal("0")
|
||||
return damage_absorbed * self.decay_per_hp
|
||||
|
||||
# Calculate economy factor based on durability
|
||||
# Higher durability = better economy (less decay)
|
||||
durability_factor = Decimal("1") - Decimal(self.durability) / Decimal(self.MAX_DURABILITY)
|
||||
decay_pec = damage_absorbed * self.BASE_DECAY_FACTOR * durability_factor
|
||||
|
||||
return decay_pec
|
||||
|
||||
def get_hp_per_pec(self) -> Decimal:
|
||||
"""
|
||||
Calculate economy rating (hp per pec).
|
||||
Higher is better (more damage absorbed per pec spent).
|
||||
"""
|
||||
durability_factor = Decimal("1") - Decimal(self.durability) / Decimal(self.MAX_DURABILITY)
|
||||
if durability_factor <= 0:
|
||||
return Decimal("0")
|
||||
return Decimal("1") / (self.BASE_DECAY_FACTOR * durability_factor)
|
||||
|
||||
def attach_plate(self, plate: ArmorPlate) -> bool:
|
||||
"""Attach a plate to this armor piece."""
|
||||
|
|
@ -285,7 +308,6 @@ class ArmorPiece:
|
|||
'item_id': self.item_id,
|
||||
'slot': self.slot.value,
|
||||
'set_name': self.set_name,
|
||||
'decay_per_hp': str(self.decay_per_hp),
|
||||
'protection': self.protection.to_dict(),
|
||||
'durability': self.durability,
|
||||
'weight': str(self.weight),
|
||||
|
|
@ -300,9 +322,8 @@ class ArmorPiece:
|
|||
item_id=data['item_id'],
|
||||
slot=ArmorSlot(data['slot']),
|
||||
set_name=data.get('set_name'),
|
||||
decay_per_hp=Decimal(data.get('decay_per_hp', '0.05')),
|
||||
protection=ProtectionProfile.from_dict(data.get('protection', {})),
|
||||
durability=data.get('durability', 10000),
|
||||
durability=data.get('durability', 2000),
|
||||
weight=Decimal(data.get('weight', '1.0')),
|
||||
)
|
||||
if data.get('attached_plate'):
|
||||
|
|
@ -704,8 +725,8 @@ def calculate_hit_protection(
|
|||
|
||||
def create_ghost_set() -> ArmorSet:
|
||||
"""Create the Ghost armor set (light, good vs cold/burn)."""
|
||||
# Ghost uses standard 20 hp/pec economy (0.05 pec per hp)
|
||||
ghost_economy = Decimal("0.05")
|
||||
# Ghost: 2000 durability = 20.41 hp/pec
|
||||
ghost_durability = 2000
|
||||
|
||||
pieces = {
|
||||
ArmorSlot.HEAD: ArmorPiece(
|
||||
|
|
@ -713,7 +734,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_helmet",
|
||||
slot=ArmorSlot.HEAD,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
||||
weight=Decimal("0.3"),
|
||||
),
|
||||
|
|
@ -722,7 +743,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_harness",
|
||||
slot=ArmorSlot.CHEST,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("4"), cut=Decimal("4"), stab=Decimal("4"), burn=Decimal("8"), cold=Decimal("8")),
|
||||
weight=Decimal("0.7"),
|
||||
),
|
||||
|
|
@ -731,7 +752,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_arm_l",
|
||||
slot=ArmorSlot.LEFT_ARM,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
||||
weight=Decimal("0.3"),
|
||||
),
|
||||
|
|
@ -740,7 +761,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_arm_r",
|
||||
slot=ArmorSlot.RIGHT_ARM,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
||||
weight=Decimal("0.3"),
|
||||
),
|
||||
|
|
@ -749,7 +770,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_gloves_l",
|
||||
slot=ArmorSlot.LEFT_HAND,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("1"), cut=Decimal("1"), stab=Decimal("1"), burn=Decimal("3"), cold=Decimal("3")),
|
||||
weight=Decimal("0.2"),
|
||||
),
|
||||
|
|
@ -758,7 +779,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_gloves_r",
|
||||
slot=ArmorSlot.RIGHT_HAND,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("1"), cut=Decimal("1"), stab=Decimal("1"), burn=Decimal("3"), cold=Decimal("3")),
|
||||
weight=Decimal("0.2"),
|
||||
),
|
||||
|
|
@ -767,7 +788,7 @@ def create_ghost_set() -> ArmorSet:
|
|||
item_id="ghost_legs",
|
||||
slot=ArmorSlot.LEGS,
|
||||
set_name="Ghost",
|
||||
decay_per_hp=ghost_economy,
|
||||
durability=ghost_durability,
|
||||
protection=ProtectionProfile(impact=Decimal("3"), cut=Decimal("3"), stab=Decimal("3"), burn=Decimal("7"), cold=Decimal("7")),
|
||||
weight=Decimal("0.6"),
|
||||
),
|
||||
|
|
@ -1198,8 +1219,8 @@ def create_frontier_set() -> ArmorSet:
|
|||
|
||||
pieces = {
|
||||
ArmorSlot.HEAD: ArmorPiece(
|
||||
name="Frontier Helmet, Adjusted",
|
||||
item_id="frontier_helmet_adj",
|
||||
name="Frontier Helmet, Adjusted (M)",
|
||||
item_id="frontier_helmet_adj_m",
|
||||
slot=ArmorSlot.HEAD,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
|
|
@ -1207,8 +1228,8 @@ def create_frontier_set() -> ArmorSet:
|
|||
weight=Decimal("0.5"),
|
||||
),
|
||||
ArmorSlot.CHEST: ArmorPiece(
|
||||
name="Frontier Harness, Adjusted",
|
||||
item_id="frontier_harness_adj",
|
||||
name="Frontier Harness, Adjusted (M)",
|
||||
item_id="frontier_harness_adj_m",
|
||||
slot=ArmorSlot.CHEST,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
|
|
@ -1216,8 +1237,8 @@ def create_frontier_set() -> ArmorSet:
|
|||
weight=Decimal("1.0"),
|
||||
),
|
||||
ArmorSlot.LEFT_ARM: ArmorPiece(
|
||||
name="Frontier Arm Guards, Adjusted (L)",
|
||||
item_id="frontier_arm_l_adj",
|
||||
name="Frontier Arm Guards, Adjusted (M)",
|
||||
item_id="frontier_arm_adj_m",
|
||||
slot=ArmorSlot.LEFT_ARM,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
|
|
@ -1225,8 +1246,8 @@ def create_frontier_set() -> ArmorSet:
|
|||
weight=Decimal("0.4"),
|
||||
),
|
||||
ArmorSlot.RIGHT_ARM: ArmorPiece(
|
||||
name="Frontier Arm Guards, Adjusted (R)",
|
||||
item_id="frontier_arm_r_adj",
|
||||
name="Frontier Arm Guards, Adjusted (M)", # Same name - both arms
|
||||
item_id="frontier_arm_adj_m_r",
|
||||
slot=ArmorSlot.RIGHT_ARM,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
|
|
@ -1234,8 +1255,8 @@ def create_frontier_set() -> ArmorSet:
|
|||
weight=Decimal("0.4"),
|
||||
),
|
||||
ArmorSlot.LEFT_HAND: ArmorPiece(
|
||||
name="Frontier Gloves, Adjusted (L)",
|
||||
item_id="frontier_gloves_l_adj",
|
||||
name="Frontier Gloves, Adjusted (M)",
|
||||
item_id="frontier_gloves_adj_m",
|
||||
slot=ArmorSlot.LEFT_HAND,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
|
|
@ -1243,22 +1264,24 @@ def create_frontier_set() -> ArmorSet:
|
|||
weight=Decimal("0.3"),
|
||||
),
|
||||
ArmorSlot.RIGHT_HAND: ArmorPiece(
|
||||
name="Frontier Gloves, Adjusted (R)",
|
||||
item_id="frontier_gloves_r_adj",
|
||||
name="Frontier Gloves, Adjusted (M)", # Same name - both hands
|
||||
item_id="frontier_gloves_adj_m_r",
|
||||
slot=ArmorSlot.RIGHT_HAND,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("1"), stab=Decimal("1")),
|
||||
weight=Decimal("0.3"),
|
||||
),
|
||||
# Note: Full Frontier set has separate Thigh, Shin, and Foot pieces
|
||||
# Currently modeled as combined leg piece for simplicity
|
||||
ArmorSlot.LEGS: ArmorPiece(
|
||||
name="Frontier Thigh+Shin Guards, Adjusted",
|
||||
item_id="frontier_legs_adj",
|
||||
name="Frontier Thigh+Shin+Foot Guards, Adjusted (M)", # All leg pieces combined
|
||||
item_id="frontier_legs_adj_m",
|
||||
slot=ArmorSlot.LEGS,
|
||||
set_name="Frontier",
|
||||
decay_per_hp=frontier_economy,
|
||||
protection=ProtectionProfile(impact=Decimal("7"), cut=Decimal("5"), stab=Decimal("5")),
|
||||
weight=Decimal("1.1"),
|
||||
protection=ProtectionProfile(impact=Decimal("8"), cut=Decimal("6"), stab=Decimal("6")),
|
||||
weight=Decimal("1.2"),
|
||||
),
|
||||
}
|
||||
return ArmorSet(
|
||||
|
|
|
|||
Loading…
Reference in New Issue