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

139
main.py
View File

@@ -1,4 +1,5 @@
import sys
from random import randint
# Add the current directory to sys.path to allow imports from sibling files
sys.path.append('.')
from player import Player
@@ -36,8 +37,8 @@ class Engine:
# Display lootable containers
if self.current_scene.lootable_items:
print("\nYou also notice:")
for container_name, items_in_container in self.current_scene.lootable_items.items():
if any(count > 0 for count in items_in_container.values()): # Check if container has any items left
for container_name, container in self.current_scene.lootable_items.items():
if container.has_items():
print(f" - {container_name.title()}")
def look_around(self):
@@ -53,8 +54,8 @@ class Engine:
# Display lootable containers
if self.current_scene.lootable_items:
print("\nYou also notice:")
for container_name, items_in_container in self.current_scene.lootable_items.items():
if any(count > 0 for count in items_in_container.values()): # Check if container has any items left
for container_name, container in self.current_scene.lootable_items.items():
if container.has_items():
print(f" - {container_name.title()}")
@@ -116,19 +117,45 @@ class Engine:
if not found_in_scene:
# Check lootable containers in the current scene
found_in_loot = False
for container_name, items_in_container in self.current_scene.lootable_items.items():
if object_name.lower() in container_name.lower(): # If user tries to examine the container itself
print(f"\nYou examine the {container_name}. Inside, you see:")
if items_in_container:
for item_obj, count in items_in_container.items():
if count > 0:
print(f" - {item_obj.name} (x{count})")
else:
print("It appears to be empty.")
found_in_loot = True
break # Exit after examining the container
for container_name, container in self.current_scene.lootable_items.items():
if object_name.lower() in container_name.lower():
print(f"\n--- {container.name.title()} ---")
print(container.description)
for item_obj, count in items_in_container.items():
int_mod = self.player.mods["Intelligence"]
noticed_something = False
if container.lock_dc:
roll = randint(1, 20) + int_mod
print(f"\nInvestigation check: 1d20{int_mod:+} = {roll} vs DC {container.lock_dc}")
if roll >= container.lock_dc:
print("It appears to be locked.")
noticed_something = True
elif not container.trap_dc:
print("You don't notice anything unusual about it.")
if container.trap_dc:
roll = randint(1, 20) + int_mod
print(f"\nInvestigation check: 1d20{int_mod:+} = {roll} vs DC {container.trap_dc}")
if roll >= container.trap_dc:
print("You notice a trap mechanism on it.")
container.trap_detected = True
noticed_something = True
elif not container.lock_dc and not noticed_something:
print("You don't notice anything unusual about it.")
if not container.is_locked:
if container.contents:
print("\nInside, you see:")
for item_obj, count in container.contents.items():
if count > 0:
print(f" - {item_obj.name} (x{count})")
else:
print("It appears to be empty.")
found_in_loot = True
break
for item_obj, count in container.contents.items():
if object_name.lower() in item_obj.name.lower() and count > 0:
print(f"\n--- {item_obj.name} ---")
print(item_obj.description)
@@ -185,22 +212,32 @@ class Engine:
def loot_container(self, container_name):
"""Allows the player to loot items from a specified container."""
container_found = False
for current_container_name, items_in_container in list(self.current_scene.lootable_items.items()):
if current_container_name.lower() == container_name.lower():
container_found = True
if not items_in_container:
for current_name, container in list(self.current_scene.lootable_items.items()):
if current_name.lower() == container_name.lower():
if container.is_locked:
print(f"The {container_name} is locked.")
return
if container.is_trapped and not container.trap_disarmed:
if container.trap_detected:
print(f"The {container_name} is trapped. You'll need to disable the trap first.")
return
else:
print(f"You open the {container_name}. A trap is triggered!")
# TODO: trap damage/effects
return
if not container.contents:
print(f"The {container_name} is empty.")
return
print(f"You look inside the {container_name}. You see:")
loot_list = list(items_in_container.items())
loot_list = list(container.contents.items())
while True:
for i, (item_obj, count) in enumerate(loot_list, 1):
print(f"{i}) {item_obj.name} (x{count})")
take_all_option = len(loot_list) + 1
leave_option = len(loot_list) + 2
@@ -209,13 +246,14 @@ class Engine:
choice = input("What would you like to take? (number or 'take all'/'leave')\n>> ").lower().strip()
if choice == "take all" or (choice.isdigit() and int(choice) == take_all_option):
for item_obj, count in list(items_in_container.items()):
for item_obj, count in list(container.contents.items()):
self.player.inventory.add_item(item_obj, count)
print(f"- Took {count} {item_obj.name}")
del items_in_container[item_obj]
container.remove_item(item_obj, count)
print(f"The {container_name} is now empty.")
if not container.has_items():
del self.current_scene.lootable_items[current_name]
return
elif choice == "leave" or (choice.isdigit() and int(choice) == leave_option):
print(f"You leave the {container_name} untouched.")
@@ -239,18 +277,16 @@ class Engine:
if 0 < take_count <= current_count:
self.player.inventory.add_item(item_obj, take_count)
items_in_container[item_obj] -= take_count
container.remove_item(item_obj, take_count)
print(f"You took {take_count} {item_obj.name}.")
if items_in_container[item_obj] <= 0:
del items_in_container[item_obj]
loot_list = list(items_in_container.items())
if item_obj not in container.contents:
loot_list = list(container.contents.items())
if not items_in_container:
print(f"The {container_name} is now empty.")
return
elif not loot_list:
if not container.contents:
print(f"The {container_name} is now empty.")
if not container.has_items():
del self.current_scene.lootable_items[current_name]
return
else:
print("Invalid amount or not enough items.")
@@ -260,8 +296,7 @@ class Engine:
print("Invalid selection. Please enter a number, 'take all', or 'leave'.")
return
if not container_found:
print(f"You don't see a '{container_name}' here to loot.")
print(f"You don't see a '{container_name}' here to loot.")
# Initialize the game engine
@@ -272,10 +307,10 @@ def main_game_loop():
The main loop for the game, handling character creation and continuous gameplay.
"""
# Character Creation
name, gender, age, race, job, pre_allocated_stats = startGame()
name, gender, age, race, class_, pre_allocated_stats = startGame()
# Create player instance
player = Player(name, gender, age, race, job)
player = Player(name, gender, age, race, class_)
game_engine.set_player(player) # Set the player in the game engine
# Display initial character summary
@@ -286,13 +321,16 @@ def main_game_loop():
# For 'Pre-generated Character'
game_engine.player.stats = pre_allocated_stats
game_engine.player.getModifier()
game_engine.player.set_stats_job() # Still need to set HP based on job and Con modifier
game_engine.player.set_stats_class() # Still need to set HP based on class and Con modifier
game_engine.player.current_stats() # Display stats after setting them
print(' ')
game_engine.player.inventory.current_equipment()
print(' ')
game_engine.player.inventory.current_inventory()
print(' ')
if game_engine.player.class_.is_caster:
game_engine.player.print_spellbook()
print(' ')
wait()
print("\nYour adventure begins...")
@@ -340,6 +378,29 @@ def main_game_loop():
elif command == "go":
direction = obj1
game_engine.move_to_scene(direction)
elif command == "spells":
game_engine.player.print_spellbook()
elif command == "cast":
if obj1:
game_engine.player.cast_spell(obj1)
else:
print("What would you like to cast?")
elif command == "prepare":
if obj1:
game_engine.player.prepare_spell(obj1)
else:
print("What would you like to prepare?")
elif command == "unprepare":
if obj1:
game_engine.player.unprepare_spell(obj1)
else:
print("What would you like to unprepare?")
elif command == "rest":
game_engine.player.long_rest()
elif command == "weight":
game_engine.player.carry_report()
elif command == "currency":
game_engine.player.currency_report()
elif command == "quit":
print("Thanks for playing!")
break