feat(attachments): add attachment system and DPP display
- Created core/attachments.py with full attachment type system - Supports: Amplifiers, Scopes, Absorbers, Finder Amps, Platings, Enhancers, Implants - Added DPP display to HUD overlay - Attachment compatibility validation rules
This commit is contained in:
parent
a3a0fbe2f5
commit
32e095350b
|
|
@ -0,0 +1,196 @@
|
|||
"""
|
||||
Attachment System for Lemontropia Suite
|
||||
Defines all attachment types and their compatibility with gear.
|
||||
"""
|
||||
|
||||
from dataclasses import dataclass
|
||||
from decimal import Decimal
|
||||
from typing import Optional, List
|
||||
|
||||
|
||||
@dataclass
|
||||
class Attachment:
|
||||
"""Base class for all attachments."""
|
||||
name: str
|
||||
item_id: str
|
||||
decay_pec: Decimal
|
||||
attachment_type: str # e.g., 'amplifier', 'scope', 'absorber'
|
||||
|
||||
# Effects
|
||||
damage_bonus: Decimal = Decimal('0')
|
||||
range_bonus: Decimal = Decimal('0')
|
||||
efficiency_bonus: Decimal = Decimal('0')
|
||||
|
||||
def calculate_cost_per_use(self) -> Decimal:
|
||||
"""Calculate cost per use in PED."""
|
||||
return self.decay_pec / Decimal('100')
|
||||
|
||||
|
||||
@dataclass
|
||||
class WeaponAmplifier(Attachment):
|
||||
"""Weapon amplifier attachment."""
|
||||
damage_increase: Decimal = Decimal('0')
|
||||
ammo_increase: int = 0
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'amplifier'
|
||||
|
||||
|
||||
@dataclass
|
||||
class WeaponScope(Attachment):
|
||||
"""Weapon scope attachment."""
|
||||
range_increase: Decimal = Decimal('0')
|
||||
accuracy_bonus: Decimal = Decimal('0')
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'scope'
|
||||
|
||||
|
||||
@dataclass
|
||||
class WeaponAbsorber(Attachment):
|
||||
"""Weapon absorber (reduces damage taken)."""
|
||||
damage_reduction: Decimal = Decimal('0')
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'absorber'
|
||||
|
||||
|
||||
@dataclass
|
||||
class FinderAmplifier(Attachment):
|
||||
"""Mining finder amplifier."""
|
||||
depth_increase: Decimal = Decimal('0')
|
||||
radius_increase: Decimal = Decimal('0')
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'finder_amp'
|
||||
|
||||
|
||||
@dataclass
|
||||
class ArmorPlating(Attachment):
|
||||
"""Armor plating for increased protection."""
|
||||
protection_stab: Decimal = Decimal('0')
|
||||
protection_cut: Decimal = Decimal('0')
|
||||
protection_impact: Decimal = Decimal('0')
|
||||
protection_penetration: Decimal = Decimal('0')
|
||||
protection_shrapnel: Decimal = Decimal('0')
|
||||
protection_burn: Decimal = Decimal('0')
|
||||
protection_cold: Decimal = Decimal('0')
|
||||
protection_acid: Decimal = Decimal('0')
|
||||
protection_electric: Decimal = Decimal('0')
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'plating'
|
||||
|
||||
def get_total_protection(self) -> Decimal:
|
||||
"""Get total protection value."""
|
||||
return (
|
||||
self.protection_stab + self.protection_cut + self.protection_impact +
|
||||
self.protection_penetration + self.protection_shrapnel +
|
||||
self.protection_burn + self.protection_cold +
|
||||
self.protection_acid + self.protection_electric
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class Enhancer(Attachment):
|
||||
"""Gear enhancer (adds special effects)."""
|
||||
tier: int = 1
|
||||
effect_name: str = ""
|
||||
effect_value: Decimal = Decimal('0')
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'enhancer'
|
||||
|
||||
|
||||
@dataclass
|
||||
class MindforceImplant(Attachment):
|
||||
"""Mindforce implant for mindforce chips."""
|
||||
mindforce_bonus: Decimal = Decimal('0')
|
||||
|
||||
def __post_init__(self):
|
||||
self.attachment_type = 'implant'
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Attachment Compatibility Rules
|
||||
# ============================================================================
|
||||
|
||||
ATTACHMENT_COMPATIBILITY = {
|
||||
'weapon': ['amplifier', 'scope', 'absorber', 'enhancer'],
|
||||
'armor': ['plating', 'enhancer'],
|
||||
'finder': ['finder_amp', 'enhancer'],
|
||||
'mindforce': ['implant', 'enhancer'],
|
||||
'tool': ['enhancer'],
|
||||
}
|
||||
|
||||
|
||||
def can_attach(gear_type: str, attachment_type: str) -> bool:
|
||||
"""Check if attachment is compatible with gear type."""
|
||||
compatible = ATTACHMENT_COMPATIBILITY.get(gear_type, [])
|
||||
return attachment_type in compatible
|
||||
|
||||
|
||||
def get_compatible_attachments(gear_type: str) -> List[str]:
|
||||
"""Get list of compatible attachment types for gear."""
|
||||
return ATTACHMENT_COMPATIBILITY.get(gear_type, [])
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Mock Attachment Data (until API is available)
|
||||
# ============================================================================
|
||||
|
||||
MOCK_AMPLIFIERS = [
|
||||
WeaponAmplifier("A101", "amp_a101", Decimal("0.05"), damage_increase=Decimal("4"), ammo_increase=10),
|
||||
WeaponAmplifier("A102", "amp_a102", Decimal("0.08"), damage_increase=Decimal("6"), ammo_increase=15),
|
||||
WeaponAmplifier("A103", "amp_a103", Decimal("0.12"), damage_increase=Decimal("8"), ammo_increase=20),
|
||||
WeaponAmplifier("A104", "amp_a104", Decimal("0.18"), damage_increase=Decimal("12"), ammo_increase=30),
|
||||
WeaponAmplifier("A105", "amp_a105", Decimal("0.25"), damage_increase=Decimal("16"), ammo_increase=40),
|
||||
WeaponAmplifier("A106", "amp_a106", Decimal("0.35"), damage_increase=Decimal("20"), ammo_increase=50),
|
||||
]
|
||||
|
||||
MOCK_SCOPES = [
|
||||
WeaponScope("Longreach 4", "scope_lr4", Decimal("0.02"), range_increase=Decimal("10")),
|
||||
WeaponScope("Longreach 6", "scope_lr6", Decimal("0.04"), range_increase=Decimal("15")),
|
||||
WeaponScope("Longreach 8", "scope_lr8", Decimal("0.06"), range_increase=Decimal("20")),
|
||||
]
|
||||
|
||||
MOCK_ABSORBERS = [
|
||||
WeaponAbsorber("Damage II", "abs_dmg2", Decimal("0.03"), damage_reduction=Decimal("2")),
|
||||
WeaponAbsorber("Damage IV", "abs_dmg4", Decimal("0.05"), damage_reduction=Decimal("4")),
|
||||
]
|
||||
|
||||
MOCK_FINDER_AMPS = [
|
||||
FinderAmplifier("DSEC L-10", "fa_dsec10", Decimal("0.10"), depth_increase=Decimal("50"), radius_increase=Decimal("5")),
|
||||
FinderAmplifier("DSEC L-30", "fa_dsec30", Decimal("0.25"), depth_increase=Decimal("100"), radius_increase=Decimal("10")),
|
||||
]
|
||||
|
||||
MOCK_PLATINGS = [
|
||||
ArmorPlating("Impact Plating", "plt_impact", Decimal("0.03"), protection_impact=Decimal("3")),
|
||||
ArmorPlating("Cut Plating", "plt_cut", Decimal("0.03"), protection_cut=Decimal("3")),
|
||||
ArmorPlating("Burn Plating", "plt_burn", Decimal("0.03"), protection_burn=Decimal("3")),
|
||||
]
|
||||
|
||||
MOCK_ENHANCERS = [
|
||||
Enhancer("Damage Enhancer 1", "enh_dmg1", Decimal("0.10"), tier=1, effect_name="damage", effect_value=Decimal("2")),
|
||||
Enhancer("Damage Enhancer 2", "enh_dmg2", Decimal("0.15"), tier=2, effect_name="damage", effect_value=Decimal("4")),
|
||||
Enhancer("Economy Enhancer 1", "enh_eco1", Decimal("0.08"), tier=1, effect_name="economy", effect_value=Decimal("5")),
|
||||
]
|
||||
|
||||
MOCK_IMPLANTS = [
|
||||
MindforceImplant("NeoPsion 10", "impl_np10", Decimal("0.05"), mindforce_bonus=Decimal("10")),
|
||||
MindforceImplant("NeoPsion 20", "impl_np20", Decimal("0.10"), mindforce_bonus=Decimal("20")),
|
||||
]
|
||||
|
||||
|
||||
def get_mock_attachments(attachment_type: str) -> List[Attachment]:
|
||||
"""Get mock attachments by type."""
|
||||
mock_data = {
|
||||
'amplifier': MOCK_AMPLIFIERS,
|
||||
'scope': MOCK_SCOPES,
|
||||
'absorber': MOCK_ABSORBERS,
|
||||
'finder_amp': MOCK_FINDER_AMPS,
|
||||
'plating': MOCK_PLATINGS,
|
||||
'enhancer': MOCK_ENHANCERS,
|
||||
'implant': MOCK_IMPLANTS,
|
||||
}
|
||||
return mock_data.get(attachment_type, [])
|
||||
|
|
@ -422,6 +422,11 @@ class HUDOverlay(QWidget):
|
|||
self.weapon_label.setStyleSheet("font-size: 11px; color: #CCCCCC;")
|
||||
weapon_layout.addWidget(self.weapon_label)
|
||||
|
||||
# DPP display
|
||||
self.dpp_label = QLabel("DPP: --")
|
||||
self.dpp_label.setStyleSheet("font-size: 10px; color: #FFD700;")
|
||||
weapon_layout.addWidget(self.dpp_label)
|
||||
|
||||
weapon_layout.addStretch()
|
||||
|
||||
loadout_label = QLabel("Loadout:")
|
||||
|
|
@ -943,9 +948,13 @@ class HUDOverlay(QWidget):
|
|||
self.dealt_value_label.setText(str(self._stats.damage_dealt))
|
||||
self.taken_value_label.setText(str(self._stats.damage_taken))
|
||||
|
||||
# Weapon/Loadout
|
||||
self.weapon_label.setText(self._stats.current_weapon[:20]) # Truncate long names
|
||||
# Weapon/Loadout/DPP
|
||||
self.weapon_label.setText(self._stats.current_weapon[:20])
|
||||
self.loadout_label.setText(self._stats.current_loadout[:15])
|
||||
if self._stats.weapon_dpp > 0:
|
||||
self.dpp_label.setText(f"DPP: {self._stats.weapon_dpp:.2f}")
|
||||
else:
|
||||
self.dpp_label.setText("DPP: --")
|
||||
|
||||
# Update time if session active
|
||||
self._update_time_display()
|
||||
|
|
|
|||
Loading…
Reference in New Issue