Add Container class with lock/trap detection, corpse drops, and numbered duplicate corpses

This commit is contained in:
KansaiGaijin
2026-07-07 12:13:43 +12:00
parent db4b5cb543
commit 221cb71410
32 changed files with 938 additions and 160 deletions

View File

@@ -5,6 +5,36 @@ sys.path.append('.')
from player import Item, Weapon, Armor, rock, dagger, polearm, tornRags, paper, GP1, SP1, CP1
from enum_list import *
class Container:
def __init__(self, name, description, lock_dc=None, trap_dc=None):
self.name = name
self.description = description
self.lock_dc = lock_dc
self.trap_dc = trap_dc
self.trap_disarmed = False
self.contents = {}
@property
def is_locked(self):
return self.lock_dc is not None
@property
def is_trapped(self):
return self.trap_dc is not None
def add_item(self, item_obj, count=1):
self.contents[item_obj] = self.contents.get(item_obj, 0) + count
def remove_item(self, item_obj, count=1):
if item_obj in self.contents:
self.contents[item_obj] -= count
if self.contents[item_obj] <= 0:
del self.contents[item_obj]
def has_items(self):
return bool(self.contents)
class Scene:
"""
Represents a single location or area in the game.
@@ -45,15 +75,12 @@ class Scene:
return self.exits.get(direction.lower())
def add_lootable_item(self, container_name, item_obj, count=1):
"""
Adds an item to a lootable container within the scene.
:param container_name: The name of the container (e.g., "chest", "goblin corpse").
:param item_obj: The Item object to add.
:param count: The quantity of the item.
"""
if container_name not in self.lootable_items:
self.lootable_items[container_name] = {}
self.lootable_items[container_name][item_obj] = self.lootable_items[container_name].get(item_obj, 0) + count
self.lootable_items[container_name] = Container(container_name, "")
self.lootable_items[container_name].add_item(item_obj, count)
def add_container(self, container):
self.lootable_items[container.name] = container
def add_available_item(self, item_obj, count=1):
"""
@@ -75,18 +102,31 @@ class Scene:
del self.available_items[item_obj]
def remove_lootable_item(self, container_name, item_obj, count=1):
if container_name in self.lootable_items:
self.lootable_items[container_name].remove_item(item_obj, count)
if not self.lootable_items[container_name].has_items():
del self.lootable_items[container_name]
def add_corpse(self, enemy_name, items):
"""Creates a lootable corpse from a defeated enemy.
Multiple corpses of the same enemy are numbered: 'spider corpse', 'spider corpse 2', etc.
items: dict of {item_obj: count} or iterable of (item_obj, count) pairs.
"""
Removes a specified count of an item from a lootable container in the scene.
:param container_name: The name of the container.
:param item_obj: The Item object to remove.
:param count: The quantity to remove.
"""
if container_name in self.lootable_items and item_obj in self.lootable_items[container_name]:
self.lootable_items[container_name][item_obj] -= count
if self.lootable_items[container_name][item_obj] <= 0:
del self.lootable_items[container_name][item_obj]
if not self.lootable_items[container_name]: # If container is empty, remove it
del self.lootable_items[container_name]
base_name = f"{enemy_name.lower()} corpse"
name = base_name
counter = 1
while name in self.lootable_items:
counter += 1
name = f"{base_name} {counter}"
corpse = Container(name, f"The lifeless body of a {enemy_name}.")
if isinstance(items, dict):
for item_obj, count in items.items():
corpse.add_item(item_obj, count)
else:
for item_obj, count in items:
corpse.add_item(item_obj, count)
self.lootable_items[name] = corpse
# --- Default Scenes ---
@@ -112,9 +152,9 @@ tutorial = Scene(
)
tutorial.add_available_item(rock, 1)
tutorial.add_available_item(paper, 2)
tutorial.add_lootable_item("suspicious tree trunk", Item("Test Item",
"This is for testing purposes", None,
False, ItemType.Item, False), 1)
tutorial_trunk = Container("suspicious tree trunk", "A hollow tree trunk with a small gap in the bark.")
tutorial_trunk.add_item(Item("Test Item", "This is for testing purposes", None, False, ItemType.Item, False), 1)
tutorial.add_container(tutorial_trunk)
# Scene 1: Starting Clearing
starting_clearing = Scene(
@@ -125,8 +165,10 @@ starting_clearing = Scene(
"You notice a small, weathered wooden chest near a fallen log."
)
starting_clearing.add_available_item(rock, 3) # Rocks lying on the ground
starting_clearing.add_lootable_item("small wooden chest", GP1, 15)
starting_clearing.add_lootable_item("small wooden chest", SP1, 20)
starting_clearing_chest = Container("small wooden chest", "A small, weathered wooden chest with rusty iron bands.")
starting_clearing_chest.add_item(GP1, 15)
starting_clearing_chest.add_item(SP1, 20)
starting_clearing.add_container(starting_clearing_chest)
# Scene 2: Forest Path