Spaces:
Running
Running
File size: 5,615 Bytes
c02cd3b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | from __future__ import annotations
import random
from dataclasses import dataclass
from typing import Dict, List, Tuple
import pygame
from config import constants
ItemType = str
@dataclass
class ItemSpec:
color: Tuple[int, int, int]
label: str
ITEM_SPECS: Dict[ItemType, ItemSpec] = {
# Metals (asteroids)
"steel_scrap": ItemSpec((160, 160, 160), "Stl"),
"aluminum_sheet": ItemSpec((180, 200, 220), "Al"),
"copper_wire": ItemSpec((200, 140, 90), "Cu"),
# Enemy drops
"lithium_battery": ItemSpec((140, 200, 255), "Li"),
"circuit_board": ItemSpec((90, 200, 120), "PCB"),
"rare_earth_element": ItemSpec((200, 160, 255), "REE"),
"pet_plastic": ItemSpec((200, 200, 220), "PET"),
"carbon_fiber": ItemSpec((80, 80, 90), "CF"),
"titanium_alloy": ItemSpec((170, 170, 190), "Ti"),
"power_core": ItemSpec((255, 100, 80), "Core"),
"crystal_capacitor": ItemSpec((180, 220, 255), "Cap"),
"exotic_isotope": ItemSpec((255, 180, 80), "Iso"),
# Health
"repair_nanites": ItemSpec((90, 240, 140), "Heal"),
"bio_gel": ItemSpec((90, 200, 90), "Gel"),
# Power-ups (enemy drops)
"powerup_magnet": ItemSpec((90, 200, 255), "Mag"),
"powerup_super_magnet": ItemSpec((110, 220, 255), "SMag"),
"powerup_weapon_missile": ItemSpec((255, 190, 80), "MSL"),
"powerup_weapon_plasma": ItemSpec((120, 200, 255), "PLS"),
"powerup_weapon_ray": ItemSpec((255, 120, 200), "RAY"),
"powerup_shieldgen": ItemSpec((140, 220, 255), "SHD"),
"powerup_rapidfire": ItemSpec((255, 220, 90), "RF"),
"powerup_damage": ItemSpec((255, 120, 120), "Dmg"),
"powerup_shield": ItemSpec((120, 180, 255), "Shd"),
"powerup_regen": ItemSpec((90, 240, 140), "Regen"),
"powerup_slow": ItemSpec((120, 180, 255), "Slow"),
"powerup_multishot": ItemSpec((255, 160, 255), "2x"),
}
def random_metal_drop() -> ItemType:
r = random.random()
cumulative = 0.0
table = constants.ASTEROID_METAL_DROP_TABLE
for name, prob in table:
cumulative += prob
if r <= cumulative:
return name
return table[-1][0]
def random_enemy_drop() -> ItemType:
table = constants.ENEMY_DROP_TABLE
total = sum(weight for _, weight in table)
r = random.uniform(0, total)
cumulative = 0.0
for name, weight in table:
cumulative += weight
if r <= cumulative:
return name
return table[-1][0]
def random_powerup_drop() -> ItemType:
table = constants.POWERUP_DROP_TABLE
total = sum(weight for _, weight in table)
r = random.uniform(0, total)
cumulative = 0.0
for name, weight in table:
cumulative += weight
if r <= cumulative:
return name
return table[-1][0]
class Item(pygame.sprite.Sprite):
"""Collectible item dropped from asteroids or enemies."""
ICONS: Dict[str, pygame.Surface] = {}
def __init__(self, item_type: ItemType, pos: Tuple[float, float]):
super().__init__()
spec = ITEM_SPECS.get(item_type, ItemSpec((200, 200, 200), item_type))
self.item_type = item_type
icon = self.ICONS.get(item_type)
if icon:
self.image = pygame.transform.scale(icon, (18, 18))
else:
self.image = pygame.Surface((14, 14), pygame.SRCALPHA)
self.image.fill(spec.color)
font = pygame.font.Font(None, 12)
text = font.render(spec.label, True, (0, 0, 0))
text_rect = text.get_rect(center=(7, 7))
self.image.blit(text, text_rect)
self.rect = self.image.get_rect(center=pos)
self.pos = pygame.Vector2(pos)
self.vel = pygame.Vector2(-80, random.uniform(-20, 20)) # drift left with slight variation
def update(self, dt: float):
self.pos += self.vel * dt
self.rect.center = (int(self.pos.x), int(self.pos.y))
class Inventory:
"""Simple inventory with capacity counting total items."""
def __init__(self, capacity: int = constants.INVENTORY_LIMIT):
self.capacity = capacity
self.counts: Dict[ItemType, int] = {}
self.weapons: Dict[str, int] = {}
self.upgrades: Dict[str, int] = {}
self.owned_ships = {"salvager_one"}
self.current_ship = "salvager_one"
@property
def total(self) -> int:
return sum(self.counts.values())
def can_pick(self, amount: int = 1) -> bool:
return True # unlimited inventory
def add(self, item_type: ItemType, amount: int = 1) -> bool:
if not self.can_pick(amount):
return False
self.counts[item_type] = self.counts.get(item_type, 0) + amount
return True
def get(self, item_type: ItemType) -> int:
# Allow checking crafted weapons using snake_case keys for recipes
weapon_key_map = {
"laser_cannon": "Laser Cannon",
"missile_launcher": "Missile Launcher",
"shield_generator": "Shield Generator",
"plasma_weapon": "Plasma Weapon",
"destruction_ray": "Destruction Ray",
}
if item_type in weapon_key_map:
return self.weapons.get(weapon_key_map[item_type], 0)
return self.counts.get(item_type, 0)
def add_weapon(self, weapon_name: str):
self.weapons[weapon_name] = self.weapons.get(weapon_name, 0) + 1
def remove_weapon(self, weapon_name: str):
if weapon_name not in self.weapons:
return
self.weapons[weapon_name] = max(0, self.weapons.get(weapon_name, 0) - 1)
if self.weapons[weapon_name] <= 0:
del self.weapons[weapon_name]
|