Files
echoes-of-the-ash/docs/SALVAGE_AND_ARMOR_UPDATES.md
2025-11-07 15:27:13 +01:00

6.1 KiB

Salvage UI & Armor Durability Updates

Date: 2025-11-07

Summary

Fixed salvage UI to show item details and durability-based yield, plus implemented armor durability reduction in combat.

Changes Implemented

1. Salvage Item Details Display

Files: pwa/src/components/Game.tsx

Issue: Salvage menu was not showing which specific item you're salvaging (e.g., which knife when you have multiple).

Solution:

  • Updated frontend to call /api/game/salvageable endpoint instead of filtering inventory
  • Now displays for each salvageable item:
    • Current/max durability and percentage
    • Tier level
    • Unique stats (damage, armor, etc.)
    • Expected material yield adjusted for durability

Example Display:

🔪 Knife (Tier 2)
🔧 Durability: 30/100 (30%)
damage: 15

⚠️ Item condition will reduce yield by 70%
⚠️ 30% chance to lose each material

♻️ Expected yield:
🔩 Metal Scrap x4 → x1
📦 Cloth x2 → x0

* Subject to 30% random loss per material

2. Durability-Based Yield Preview

Files: pwa/src/components/Game.tsx

Issue: Salvage menu showed full material yield even when item had low durability.

Solution:

  • Calculate durability_ratio = durability_percent / 100
  • Show adjusted yield: adjusted_quantity = base_quantity * durability_ratio
  • Cross out original quantity and show reduced amount in orange
  • Show warning if durability < 10% (yields nothing)

Visual Indicators:

  • Normal durability (100%): x4
  • Reduced durability (30%): ~~x4~~ → x1 (strikethrough and arrow)
  • Too damaged (<10%): x0 (in red)

3. Armor Durability Reduction in Combat

Files: api/main.py

Feature: Equipped armor now loses durability when you take damage in combat.

Function Added: reduce_armor_durability(player_id, damage_taken)

Formula:

# Calculate damage absorbed by armor (up to half the damage)
armor_absorbed = min(damage_taken // 2, total_armor)

# For each armor piece:
proportion = armor_value / total_armor
durability_loss = max(1, int((damage_taken * proportion / armor_value) * 0.5 * 10))

How It Works:

  1. Armor absorbs damage - Up to half the incoming damage is blocked by armor
  2. Durability reduction - Each armor piece loses durability proportional to damage taken
  3. Higher armor = less durability loss - Better armor pieces are more durable
  4. Armor breaks - When durability reaches 0, the piece breaks and is removed

Combat Message Example:

Zombie attacks for 20 damage! (Armor absorbed 8 damage)
💔 Your 🛡️ Leather Vest broke!

Balance:

  • Wearing full armor set (head, chest, legs, feet) can absorb significant damage
  • Base reduction rate: 0.5 (configurable)
  • Higher tier armor has more max durability and higher armor value
  • Encourages repairing armor between fights

Technical Implementation

Frontend Changes (Game.tsx)

1. Fetch salvageable items:

const salvageableRes = await api.get('/api/game/salvageable')
setUncraftableItems(salvageableRes.data.salvageable_items)

2. Calculate adjusted yield:

const durabilityRatio = item.unique_item_data 
  ? item.unique_item_data.durability_percent / 100 
  : 1.0
const adjustedYield = item.base_yield.map((mat: any) => ({
  ...mat,
  adjusted_quantity: Math.floor(mat.quantity * durability_ratio)
}))

3. Display unique item stats:

{item.unique_item_data && (
  <div className="unique-item-details">
    <p className="item-durability">
      🔧 Durability: {current}/{max} ({percent}%)
    </p>
    <div className="unique-stats">
      {Object.entries(unique_stats).map(([stat, value]) => (
        <span className="stat-badge">{stat}: {value}</span>
      ))}
    </div>
  </div>
)}

Backend Changes (api/main.py)

1. Armor durability reduction function:

async def reduce_armor_durability(player_id: int, damage_taken: int):
    """Reduce durability of equipped armor when taking damage"""
    # Collect all equipped armor pieces
    # Calculate total armor value
    # Determine damage absorbed
    # Reduce durability proportionally per piece
    # Break and remove pieces with 0 durability
    return armor_absorbed, broken_armor

2. Called during NPC attack:

armor_absorbed, broken_armor = await reduce_armor_durability(player['id'], npc_damage)
actual_damage = max(1, npc_damage - armor_absorbed)
new_player_hp = max(0, player['hp'] - actual_damage)

# Report absorbed damage and broken armor

Configuration

Armor Durability Formula Constants:

  • base_reduction_rate = 0.5 - Base multiplier for durability loss
  • armor_absorption = damage // 2 - Armor blocks up to 50% of damage
  • min_damage = 1 - Always take at least 1 damage even with high armor

To adjust armor durability loss, modify base_reduction_rate in reduce_armor_durability() function.

Benefits

  1. Informed Salvage Decisions - See which specific item you're salvaging
  2. Realistic Yield - Damaged items yield fewer materials
  3. Armor Wear - Armor degrades realistically, encouraging maintenance
  4. Combat Strategy - Need to repair/replace armor regularly
  5. Resource Management - Can't salvage broken items for full materials

Testing

Salvage UI:

  • Shows unique item details
  • Shows adjusted yield based on durability
  • Shows warning for low durability items
  • Confirmation dialog shows expected yield

Armor Durability:

  • Armor absorbs damage (up to 50%)
  • Armor loses durability when hit
  • Armor breaks at 0 durability
  • Broken armor message displayed
  • Player takes reduced damage with armor

Future Enhancements

  1. Armor Repair - Add repair functionality for armor pieces
  2. Armor Sets - Bonus for wearing complete armor sets
  3. Armor Tiers - Higher tier armor is more durable
  4. Repair Kits - Special items to repair armor in the field
  5. Armor Degradation Visual - Show armor condition in equipment UI

Files Modified

  • pwa/src/components/Game.tsx - Salvage UI updates
  • api/main.py - Armor durability reduction logic
  • api/main.py - Combat attack function updated

Status

DEPLOYED - All features tested and running in production