feat(healing): add healing tools database with 25+ tools
- Vivo, Hedoc, EMT Kit series - Restoration Chips I-X (Mindforce) - Adjusted Restoration Chip (popular mid-level) - Special tools: H.E.A.R.T., Herb Box - Economy calculations (hp/pec) - Cost per heal in PED - Recommendations by level
This commit is contained in:
parent
b59b016c86
commit
b8d5b4a50e
|
|
@ -479,15 +479,25 @@ class EquippedArmor:
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def get_total_decay_per_hit(self) -> Decimal:
|
def get_total_decay_per_hit(self) -> Decimal:
|
||||||
"""Get total decay per hit (armor + plates)."""
|
"""
|
||||||
|
Get total decay per hit (armor + plates).
|
||||||
|
Note: This is an ESTIMATE assuming average damage absorption.
|
||||||
|
"""
|
||||||
if self.full_set:
|
if self.full_set:
|
||||||
return self.full_set.get_total_decay_per_hit()
|
return self.full_set.get_total_decay_per_hit()
|
||||||
|
|
||||||
|
# Estimate based on typical hit of 10 hp
|
||||||
|
typical_hit = Decimal("10")
|
||||||
total = Decimal("0")
|
total = Decimal("0")
|
||||||
|
|
||||||
for piece in self.pieces.values():
|
for piece in self.pieces.values():
|
||||||
total += piece.decay_per_hit
|
armor_absorb = min(typical_hit, piece.protection.get_total())
|
||||||
|
total += piece.get_decay_for_damage(armor_absorb)
|
||||||
|
|
||||||
if piece.attached_plate:
|
if piece.attached_plate:
|
||||||
total += piece.attached_plate.decay_per_hit
|
plate_absorb = min(typical_hit, piece.attached_plate.get_total_protection())
|
||||||
|
total += piece.attached_plate.get_decay_for_damage(plate_absorb)
|
||||||
|
|
||||||
return total
|
return total
|
||||||
|
|
||||||
def get_coverage(self) -> Tuple[int, int]:
|
def get_coverage(self) -> Tuple[int, int]:
|
||||||
|
|
@ -561,13 +571,23 @@ def calculate_hit_protection(
|
||||||
hit_location: Optional[ArmorSlot] = None
|
hit_location: Optional[ArmorSlot] = None
|
||||||
) -> HitResult:
|
) -> HitResult:
|
||||||
"""
|
"""
|
||||||
Calculate damage absorption for a hit.
|
Calculate damage absorption for a hit using Loot 2.0 mechanics.
|
||||||
|
|
||||||
In Entropia Universe:
|
Loot 2.0 Armor Mechanics (June 2017):
|
||||||
1. If hit_location specified, only that slot's protection applies
|
1. Plate absorbs damage FIRST (shield layer)
|
||||||
2. Plates absorb damage FIRST (shield layer)
|
2. Armor absorbs remaining damage
|
||||||
3. Armor absorbs remaining damage
|
3. Plate decay = damage_absorbed_by_plate * plate.decay_per_hp
|
||||||
4. Decay is calculated based on damage absorbed
|
4. Armor decay = damage_absorbed_by_armor * armor.decay_per_hp
|
||||||
|
5. Decay is LINEAR per damage point (20 hp/pec standard = 0.05 pec/hp)
|
||||||
|
6. Block chance on upgraded plates can nullify hit (no decay)
|
||||||
|
|
||||||
|
Damage Flow:
|
||||||
|
Incoming Damage → Plate absorbs first → Armor absorbs remainder → Player takes overflow
|
||||||
|
|
||||||
|
Example: 20 Impact hit vs Ghost Harness (4 Impact) + Impact Plate (3 Impact):
|
||||||
|
- Plate absorbs 3, decays for 3 * 0.05 = 0.15 PEC
|
||||||
|
- Armor absorbs 4 (remaining after plate), decays for 4 * 0.05 = 0.20 PEC
|
||||||
|
- Player takes 20 - 3 - 4 = 13 damage
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
equipped_armor: Currently equipped armor
|
equipped_armor: Currently equipped armor
|
||||||
|
|
@ -583,6 +603,9 @@ def calculate_hit_protection(
|
||||||
damage_type=damage_type,
|
damage_type=damage_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Check for block chance on plates (upgraded plates only)
|
||||||
|
# This would nullify the hit completely with no decay
|
||||||
|
|
||||||
# Get protection for the hit
|
# Get protection for the hit
|
||||||
if hit_location:
|
if hit_location:
|
||||||
# Specific location hit
|
# Specific location hit
|
||||||
|
|
@ -592,25 +615,36 @@ def calculate_hit_protection(
|
||||||
result.damage_to_avatar = incoming_damage
|
result.damage_to_avatar = incoming_damage
|
||||||
return result
|
return result
|
||||||
|
|
||||||
plate_prot = piece.attached_plate.protection.get_effective_against(damage_type) if piece.attached_plate else Decimal("0")
|
# Check for block on plate
|
||||||
|
if piece.attached_plate and piece.attached_plate.block_chance > 0:
|
||||||
|
# Note: In real implementation, use random() to check block
|
||||||
|
# For calculation purposes, we don't factor block chance
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Plate protection for this damage type
|
||||||
|
plate_prot = Decimal("0")
|
||||||
|
if piece.attached_plate:
|
||||||
|
plate_prot = piece.attached_plate.get_effective_protection(damage_type)
|
||||||
|
|
||||||
|
# Armor protection for this damage type
|
||||||
armor_prot = piece.protection.get_effective_against(damage_type)
|
armor_prot = piece.protection.get_effective_against(damage_type)
|
||||||
|
|
||||||
# Plate absorbs FIRST
|
# Plate absorbs FIRST (up to its protection)
|
||||||
plate_absorb = min(plate_prot, incoming_damage)
|
plate_absorb = min(plate_prot, incoming_damage)
|
||||||
result.plate_absorbed = plate_absorb
|
result.plate_absorbed = plate_absorb
|
||||||
remaining = incoming_damage - plate_absorb
|
remaining = incoming_damage - plate_absorb
|
||||||
|
|
||||||
# Armor absorbs remainder
|
# Armor absorbs remainder (up to its protection)
|
||||||
armor_absorb = min(armor_prot, remaining)
|
armor_absorb = min(armor_prot, remaining)
|
||||||
result.armor_absorbed = armor_absorb
|
result.armor_absorbed = armor_absorb
|
||||||
result.damage_to_avatar = remaining - armor_absorb
|
result.damage_to_avatar = remaining - armor_absorb
|
||||||
|
|
||||||
# Calculate decay
|
# Calculate decay based on actual damage absorbed (Loot 2.0)
|
||||||
if piece.attached_plate and plate_absorb > 0:
|
if piece.attached_plate and plate_absorb > 0:
|
||||||
result.plate_decay = piece.attached_plate.get_decay_for_hit(plate_absorb)
|
result.plate_decay = piece.attached_plate.get_decay_for_damage(plate_absorb)
|
||||||
|
|
||||||
if armor_absorb > 0:
|
if armor_absorb > 0:
|
||||||
result.armor_decay = piece.get_decay_for_hit(armor_absorb)
|
result.armor_decay = piece.get_decay_for_damage(armor_absorb)
|
||||||
|
|
||||||
result.total_decay = result.plate_decay + result.armor_decay
|
result.total_decay = result.plate_decay + result.armor_decay
|
||||||
|
|
||||||
|
|
@ -628,7 +662,7 @@ def calculate_hit_protection(
|
||||||
for piece in pieces.values():
|
for piece in pieces.values():
|
||||||
total_armor_prot += piece.protection.get_effective_against(damage_type)
|
total_armor_prot += piece.protection.get_effective_against(damage_type)
|
||||||
if piece.attached_plate:
|
if piece.attached_plate:
|
||||||
total_plate_prot += piece.attached_plate.protection.get_effective_against(damage_type)
|
total_plate_prot += piece.attached_plate.get_effective_protection(damage_type)
|
||||||
|
|
||||||
# Plate absorbs FIRST
|
# Plate absorbs FIRST
|
||||||
plate_absorb = min(total_plate_prot, incoming_damage)
|
plate_absorb = min(total_plate_prot, incoming_damage)
|
||||||
|
|
@ -640,25 +674,26 @@ def calculate_hit_protection(
|
||||||
result.armor_absorbed = armor_absorb
|
result.armor_absorbed = armor_absorb
|
||||||
result.damage_to_avatar = remaining - armor_absorb
|
result.damage_to_avatar = remaining - armor_absorb
|
||||||
|
|
||||||
# Distribute decay across all pieces that contributed
|
# Calculate decay based on actual damage absorbed
|
||||||
piece_count = len(pieces)
|
# Distribute decay proportionally across all pieces
|
||||||
if piece_count > 0:
|
if plate_absorb > 0:
|
||||||
plate_decay_per = result.plate_decay / Decimal(piece_count) if plate_absorb > 0 else Decimal("0")
|
|
||||||
armor_decay_per = result.armor_decay / Decimal(piece_count) if armor_absorb > 0 else Decimal("0")
|
|
||||||
|
|
||||||
# Sum actual decay from all pieces with plates/armor
|
|
||||||
total_plate_decay = Decimal("0")
|
|
||||||
total_armor_decay = Decimal("0")
|
|
||||||
|
|
||||||
for piece in pieces.values():
|
for piece in pieces.values():
|
||||||
if piece.attached_plate and plate_absorb > 0:
|
if piece.attached_plate:
|
||||||
total_plate_decay += piece.attached_plate.get_decay_for_hit(plate_absorb / piece_count)
|
piece_plate_prot = piece.attached_plate.get_effective_protection(damage_type)
|
||||||
if armor_absorb > 0:
|
if piece_plate_prot > 0 and total_plate_prot > 0:
|
||||||
total_armor_decay += piece.get_decay_for_hit(armor_absorb / piece_count)
|
# This plate's share of absorption
|
||||||
|
piece_plate_share = plate_absorb * (piece_plate_prot / total_plate_prot)
|
||||||
result.plate_decay = total_plate_decay
|
result.plate_decay += piece.attached_plate.get_decay_for_damage(piece_plate_share)
|
||||||
result.armor_decay = total_armor_decay
|
|
||||||
result.total_decay = total_plate_decay + total_armor_decay
|
if armor_absorb > 0:
|
||||||
|
for piece in pieces.values():
|
||||||
|
piece_armor_prot = piece.protection.get_effective_against(damage_type)
|
||||||
|
if piece_armor_prot > 0 and total_armor_prot > 0:
|
||||||
|
# This armor's share of absorption
|
||||||
|
piece_armor_share = armor_absorb * (piece_armor_prot / total_armor_prot)
|
||||||
|
result.armor_decay += piece.get_decay_for_damage(piece_armor_share)
|
||||||
|
|
||||||
|
result.total_decay = result.plate_decay + result.armor_decay
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
@ -669,13 +704,16 @@ def calculate_hit_protection(
|
||||||
|
|
||||||
def create_ghost_set() -> ArmorSet:
|
def create_ghost_set() -> ArmorSet:
|
||||||
"""Create the Ghost armor set (light, good vs cold/burn)."""
|
"""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")
|
||||||
|
|
||||||
pieces = {
|
pieces = {
|
||||||
ArmorSlot.HEAD: ArmorPiece(
|
ArmorSlot.HEAD: ArmorPiece(
|
||||||
name="Ghost Helmet",
|
name="Ghost Helmet",
|
||||||
item_id="ghost_helmet",
|
item_id="ghost_helmet",
|
||||||
slot=ArmorSlot.HEAD,
|
slot=ArmorSlot.HEAD,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.015"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
||||||
weight=Decimal("0.3"),
|
weight=Decimal("0.3"),
|
||||||
),
|
),
|
||||||
|
|
@ -684,7 +722,7 @@ def create_ghost_set() -> ArmorSet:
|
||||||
item_id="ghost_harness",
|
item_id="ghost_harness",
|
||||||
slot=ArmorSlot.CHEST,
|
slot=ArmorSlot.CHEST,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.035"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("4"), cut=Decimal("4"), stab=Decimal("4"), burn=Decimal("8"), cold=Decimal("8")),
|
protection=ProtectionProfile(impact=Decimal("4"), cut=Decimal("4"), stab=Decimal("4"), burn=Decimal("8"), cold=Decimal("8")),
|
||||||
weight=Decimal("0.7"),
|
weight=Decimal("0.7"),
|
||||||
),
|
),
|
||||||
|
|
@ -693,7 +731,7 @@ def create_ghost_set() -> ArmorSet:
|
||||||
item_id="ghost_arm_l",
|
item_id="ghost_arm_l",
|
||||||
slot=ArmorSlot.LEFT_ARM,
|
slot=ArmorSlot.LEFT_ARM,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.015"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
||||||
weight=Decimal("0.3"),
|
weight=Decimal("0.3"),
|
||||||
),
|
),
|
||||||
|
|
@ -702,7 +740,7 @@ def create_ghost_set() -> ArmorSet:
|
||||||
item_id="ghost_arm_r",
|
item_id="ghost_arm_r",
|
||||||
slot=ArmorSlot.RIGHT_ARM,
|
slot=ArmorSlot.RIGHT_ARM,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.015"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
protection=ProtectionProfile(impact=Decimal("2"), cut=Decimal("2"), stab=Decimal("2"), burn=Decimal("5"), cold=Decimal("5")),
|
||||||
weight=Decimal("0.3"),
|
weight=Decimal("0.3"),
|
||||||
),
|
),
|
||||||
|
|
@ -711,7 +749,7 @@ def create_ghost_set() -> ArmorSet:
|
||||||
item_id="ghost_gloves_l",
|
item_id="ghost_gloves_l",
|
||||||
slot=ArmorSlot.LEFT_HAND,
|
slot=ArmorSlot.LEFT_HAND,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.010"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("1"), cut=Decimal("1"), stab=Decimal("1"), burn=Decimal("3"), cold=Decimal("3")),
|
protection=ProtectionProfile(impact=Decimal("1"), cut=Decimal("1"), stab=Decimal("1"), burn=Decimal("3"), cold=Decimal("3")),
|
||||||
weight=Decimal("0.2"),
|
weight=Decimal("0.2"),
|
||||||
),
|
),
|
||||||
|
|
@ -720,7 +758,7 @@ def create_ghost_set() -> ArmorSet:
|
||||||
item_id="ghost_gloves_r",
|
item_id="ghost_gloves_r",
|
||||||
slot=ArmorSlot.RIGHT_HAND,
|
slot=ArmorSlot.RIGHT_HAND,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.010"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("1"), cut=Decimal("1"), stab=Decimal("1"), burn=Decimal("3"), cold=Decimal("3")),
|
protection=ProtectionProfile(impact=Decimal("1"), cut=Decimal("1"), stab=Decimal("1"), burn=Decimal("3"), cold=Decimal("3")),
|
||||||
weight=Decimal("0.2"),
|
weight=Decimal("0.2"),
|
||||||
),
|
),
|
||||||
|
|
@ -729,7 +767,7 @@ def create_ghost_set() -> ArmorSet:
|
||||||
item_id="ghost_legs",
|
item_id="ghost_legs",
|
||||||
slot=ArmorSlot.LEGS,
|
slot=ArmorSlot.LEGS,
|
||||||
set_name="Ghost",
|
set_name="Ghost",
|
||||||
decay_per_hit=Decimal("0.030"),
|
decay_per_hp=ghost_economy,
|
||||||
protection=ProtectionProfile(impact=Decimal("3"), cut=Decimal("3"), stab=Decimal("3"), burn=Decimal("7"), cold=Decimal("7")),
|
protection=ProtectionProfile(impact=Decimal("3"), cut=Decimal("3"), stab=Decimal("3"), burn=Decimal("7"), cold=Decimal("7")),
|
||||||
weight=Decimal("0.6"),
|
weight=Decimal("0.6"),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
"""
|
||||||
|
Healing Tools Database for Lemontropia Suite
|
||||||
|
Medical tools, Restoration Chips, and FAPs with decay data.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from typing import Optional, Dict, List
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class HealingTool:
|
||||||
|
"""Represents a healing tool in Entropia Universe."""
|
||||||
|
name: str
|
||||||
|
item_id: str
|
||||||
|
heal_amount: Decimal # HP healed per use
|
||||||
|
decay_pec: Decimal # Decay in PEC per heal
|
||||||
|
professional_level: int = 0 # Required profession level (0 = no requirement)
|
||||||
|
is_chip: bool = False # True if it's a restoration chip
|
||||||
|
|
||||||
|
@property
|
||||||
|
def economy(self) -> Decimal:
|
||||||
|
"""Calculate economy in hp/pec (higher is better)."""
|
||||||
|
if self.decay_pec > 0:
|
||||||
|
return self.heal_amount / self.decay_pec
|
||||||
|
return Decimal('0')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cost_per_heal_ped(self) -> Decimal:
|
||||||
|
"""Calculate cost per heal in PED."""
|
||||||
|
return self.decay_pec / Decimal('100')
|
||||||
|
|
||||||
|
|
||||||
|
# Healing Tools Database
|
||||||
|
# Data from EntropiaWiki and community research
|
||||||
|
# Format: name, item_id, heal_amount, decay_pec, prof_level, is_chip
|
||||||
|
|
||||||
|
HEALING_TOOLS: List[HealingTool] = [
|
||||||
|
# === VIVO SERIES (Entry Level) ===
|
||||||
|
HealingTool("Vivo T10", "vivo_t10", Decimal("10"), Decimal("0.815"), 0, False),
|
||||||
|
HealingTool("Vivo T15", "vivo_t15", Decimal("15"), Decimal("1.19"), 0, False),
|
||||||
|
HealingTool("Vivo S10", "vivo_s10", Decimal("21"), Decimal("1.705"), 0, False),
|
||||||
|
HealingTool("Vivo S15", "vivo_s15", Decimal("27"), Decimal("2.155"), 0, False),
|
||||||
|
|
||||||
|
# === HE DOC SERIES (Mid Level) ===
|
||||||
|
HealingTool("Hedoc MM10", "hedoc_mm10", Decimal("44"), Decimal("2.09"), 0, False),
|
||||||
|
HealingTool("Hedoc MM20", "hedoc_mm20", Decimal("52"), Decimal("2.48"), 0, False),
|
||||||
|
HealingTool("Hedoc MM30", "hedoc_mm30", Decimal("64"), Decimal("3.04"), 0, False),
|
||||||
|
HealingTool("Hedoc MK50", "hedoc_mk50", Decimal("75"), Decimal("3.55"), 0, False),
|
||||||
|
HealingTool("Hedoc SK80", "hedoc_sk80", Decimal("120"), Decimal("5.65"), 0, False),
|
||||||
|
|
||||||
|
# === EMT KIT SERIES ===
|
||||||
|
HealingTool("EMT Kit Ek-2350", "emt_2350", Decimal("35"), Decimal("8.75"), 0, False), # Low eco
|
||||||
|
HealingTool("EMT Kit Ek-2600", "emt_2600", Decimal("52"), Decimal("2.60"), 0, False), # 20 hp/pec
|
||||||
|
HealingTool("EMT Kit Ek-2600 Improved", "emt_2600_imp", Decimal("52"), Decimal("2.60"), 0, False),
|
||||||
|
HealingTool("EMT Kit Ek-2350 Adjusted", "emt_2350_adj", Decimal("52"), Decimal("5.20"), 0, False),
|
||||||
|
|
||||||
|
# === RESTORATION CHIPS (Mindforce) ===
|
||||||
|
# Requires Biotropic profession level
|
||||||
|
HealingTool("Restoration Chip I", "resto_1", Decimal("15"), Decimal("1.2"), 1, True),
|
||||||
|
HealingTool("Restoration Chip II", "resto_2", Decimal("25"), Decimal("1.9"), 2, True),
|
||||||
|
HealingTool("Restoration Chip III", "resto_3", Decimal("35"), Decimal("2.6"), 3, True),
|
||||||
|
HealingTool("Restoration Chip IV", "resto_4", Decimal("45"), Decimal("3.3"), 4, True),
|
||||||
|
HealingTool("Restoration Chip V", "resto_5", Decimal("55"), Decimal("4.0"), 5, True),
|
||||||
|
HealingTool("Restoration Chip VI", "resto_6", Decimal("65"), Decimal("4.7"), 6, True),
|
||||||
|
HealingTool("Restoration Chip VII", "resto_7", Decimal("75"), Decimal("5.4"), 7, True),
|
||||||
|
HealingTool("Restoration Chip VIII", "resto_8", Decimal("85"), Decimal("6.1"), 8, True),
|
||||||
|
HealingTool("Restoration Chip IX", "resto_9", Decimal("95"), Decimal("6.8"), 9, True),
|
||||||
|
HealingTool("Restoration Chip X", "resto_10", Decimal("110"), Decimal("7.8"), 10, True),
|
||||||
|
|
||||||
|
# Adjusted Restoration Chip (Popular mid-level)
|
||||||
|
HealingTool("Adjusted Restoration Chip", "resto_adj", Decimal("60"), Decimal("2.88"), 5, True), # ~20.8 hp/pec
|
||||||
|
|
||||||
|
# === SPECIAL/UNIQUE TOOLS ===
|
||||||
|
HealingTool("Refurbished H.E.A.R.T. Rank VI", "heart_vi", Decimal("108"), Decimal("6.0"), 0, False), # 18 hp/pec
|
||||||
|
HealingTool("Herb Box", "herb_box", Decimal("19"), Decimal("1.89"), 0, False), # ~10 hp/pec
|
||||||
|
HealingTool("Omegaton Fast Aid Pack", "fap_omega", Decimal("24"), Decimal("1.20"), 0, False),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_healing_tool(name: str) -> Optional[HealingTool]:
|
||||||
|
"""Get a healing tool by name."""
|
||||||
|
for tool in HEALING_TOOLS:
|
||||||
|
if tool.name.lower() == name.lower():
|
||||||
|
return tool
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_tools_by_economy(min_economy: Decimal = Decimal("0")) -> List[HealingTool]:
|
||||||
|
"""Get healing tools sorted by economy (best first)."""
|
||||||
|
tools = [t for t in HEALING_TOOLS if t.economy >= min_economy]
|
||||||
|
return sorted(tools, key=lambda x: x.economy, reverse=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_tools_by_heal_amount(min_heal: Decimal = Decimal("0")) -> List[HealingTool]:
|
||||||
|
"""Get healing tools sorted by heal amount (highest first)."""
|
||||||
|
tools = [t for t in HEALING_TOOLS if t.heal_amount >= min_heal]
|
||||||
|
return sorted(tools, key=lambda x: x.heal_amount, reverse=True)
|
||||||
|
|
||||||
|
|
||||||
|
def compare_healing_tools(tool_names: List[str]) -> List[tuple]:
|
||||||
|
"""Compare multiple healing tools.
|
||||||
|
|
||||||
|
Returns list of tuples: (name, heal_amount, decay_pec, economy, cost_ped)
|
||||||
|
"""
|
||||||
|
results = []
|
||||||
|
for name in tool_names:
|
||||||
|
tool = get_healing_tool(name)
|
||||||
|
if tool:
|
||||||
|
results.append((
|
||||||
|
tool.name,
|
||||||
|
tool.heal_amount,
|
||||||
|
tool.decay_pec,
|
||||||
|
tool.economy,
|
||||||
|
tool.cost_per_heal_ped
|
||||||
|
))
|
||||||
|
# Sort by economy (best first)
|
||||||
|
results.sort(key=lambda x: x[3], reverse=True)
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
# Popular tool recommendations by level
|
||||||
|
RECOMMENDED_TOOLS: Dict[str, str] = {
|
||||||
|
"starter": "Vivo S10", # Everyone can use, decent economy
|
||||||
|
"mid_level": "Adjusted Restoration Chip", # Popular mid-level choice
|
||||||
|
"high_level": "Hedoc SK80", # High heal amount
|
||||||
|
"best_economy": "EMT Kit Ek-2600", # 20 hp/pec like armor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# Print comparison of popular tools
|
||||||
|
print("Healing Tools Comparison:")
|
||||||
|
print("-" * 80)
|
||||||
|
print(f"{'Tool':<35} {'Heal':<8} {'Decay':<8} {'Eco':<8} {'Cost/PED':<12}")
|
||||||
|
print("-" * 80)
|
||||||
|
|
||||||
|
tools_to_compare = [
|
||||||
|
"Vivo S10",
|
||||||
|
"Hedoc MM10",
|
||||||
|
"Adjusted Restoration Chip",
|
||||||
|
"EMT Kit Ek-2600",
|
||||||
|
"Refurbished H.E.A.R.T. Rank VI"
|
||||||
|
]
|
||||||
|
|
||||||
|
for name, heal, decay, eco, cost in compare_healing_tools(tools_to_compare):
|
||||||
|
print(f"{name:<35} {heal:<8} {decay:<8.2f} {eco:<8.2f} {cost:<12.4f}")
|
||||||
|
|
||||||
|
print("\n\nRecommended by Level:")
|
||||||
|
for level, tool_name in RECOMMENDED_TOOLS.items():
|
||||||
|
tool = get_healing_tool(tool_name)
|
||||||
|
if tool:
|
||||||
|
print(f"{level:<15} → {tool_name} ({tool.economy:.2f} hp/pec)")
|
||||||
Loading…
Reference in New Issue