Compare commits

..

10 Commits

5 changed files with 368 additions and 117 deletions

View File

@@ -39,7 +39,7 @@ class Slots(Enum):
OffHand = auto() OffHand = auto()
TwoHanded = auto() TwoHanded = auto()
Helm = auto() Helm = auto()
Chest = auto() Armor = auto()
Wrists = auto() Wrists = auto()
Feet = auto() Feet = auto()
Neck = auto() Neck = auto()

View File

@@ -11,13 +11,95 @@ from job_list import Barbarian, Cleric, Wizard
def wait(): def wait():
input("Press enter to continue...") input("Press enter to continue...")
pre_generated_characters = {
"1": {
"name": "Arion", # Example Name
"gender": "Male",
"age": 25,
"race": Elf,
"job": Wizard, # Based on the High Elf sheet
"alignment": "lawful good",
"description": "A scholarly High Elf skilled in the arcane arts.",
"stats": {
"Strength": 10, "Dexterity": 16, "Constitution": 12,
"Intelligence": 16, "Wisdom": 13, "Charisma": 8
},
"armor_class": "13 or 16 (mage armor)",
"hit_points": "7 (Hit Dice 1d6 + Con modifier)",
"speed": "30 ft.",
"proficiencies": {
"bonus": "+2",
"saving_throws": {"Int": "+5", "Wis": "+3"},
"advantage_on_saves": ["charmed"],
"skills": {"Arcana": "+5", "History": "+5", "Investigation": "+5", "Perception": "+3", "Persuasion": "+1"},
"armor": [], # None listed, just "None"
"weapons": ["Daggers", "darts", "slings", "quarterstaffs", "longswords", "shortswords", "shortbows", "longbows"],
"tools": []
}
},
"2": {
"name": "Brundle", # Example Name
"gender": "Female",
"age": 35,
"race": Human,
"job": Barbarian, # Based on the Human sheet
"alignment": "chaotic good",
"description": "A robust Human warrior, charging into battle.",
"stats": {
"Strength": 16, "Dexterity": 9, "Constitution": 15,
"Intelligence": 13, "Wisdom": 11, "Charisma": 14
},
"armor_class": "18",
"hit_points": "12 (Hit Dice 1d10 + Con modifier))",
"speed": "30 ft.",
"proficiencies": {
"bonus": "+2",
"saving_throws": {"Str": "+5", "Con": "+4"},
"skills": {"Athletics": "+5", "History": "+3", "Intimidation": "+4", "Perception": "+2"},
"armor": ["All", "shields"],
"weapons": ["Simple", "martial"],
"tools": ["Gaming dice", "vehicles (land)"],
"senses": {"Passive Perception": "12"},
"languages": ["Common", "Orc"]
}
},
"3": {
"name": "Drok", # Example Name
"gender": "Other",
"age": 75, # Dwarves live longer
"race": Dwarf,
"job": Cleric, # Based on the Hill Dwarf sheet (Life Domain implied by "healing" focus)
"alignment": "lawful good",
"description": "A stout Hill Dwarf cleric, a pillar of his community.",
"stats": {
"Strength": 14, "Dexterity": 8, "Constitution": 15,
"Intelligence": 10, "Wisdom": 16, "Charisma": 12
},
"armor_class": "18 (chain mail, shield)",
"hit_points": "10 (Hit Dice 1d8 + Con modifier))",
"speed": "25 ft.",
"proficiencies": {
"bonus": "+2",
"saving_throws": {"Wis": "+5", "Cha": "+3"},
"advantage_on_saves": ["poisoned"],
"skills": {"Insight": "+5", "Medicine": "+5", "Persuasion": "+3", "Religion": "+2"},
"armor": ["all armor", "shields"],
"weapons": ["battleaxe", "simple weapons", "warhammer"],
"tools": ["brewer's supplies", "jeweler's tools"],
"damage_resistances": ["poison"],
"senses": {"darkvision": "60 ft.", "passive_perception": "13"},
"languages": ["Common", "Dwarvish", "Giant"]
}
}
}
def startGame(): def startGame():
print("Welcome stranger, to the world of Kanjin!.") print("Welcome stranger, to the world of Kanjin!.")
# Loop for initial choice: Create or Pre-generated # Loop for initial choice: Create or Pre-generated
while True: while True:
start = input("Would you like to create your own character or use pre-generated stats?" start = input("Would you like to create your own character or use pre-generated stats?"
"\n 1) Create a new character\n 2) Pre-generated\n >> ") "\n 1) Create a new character\n 2) Quick Setup\n 3) Pre-Gen Character\n >> ")
if start in ("1", "Create"): if start in ("1", "Create"):
# --- Character Basic Info (Name, Gender, Age) --- # --- Character Basic Info (Name, Gender, Age) ---
name, gender, age = None, None, None # Initialize name, gender, age = None, None, None # Initialize
@@ -134,7 +216,7 @@ def startGame():
break # Break out of this inner loop to restart the outer race/job loop break # Break out of this inner loop to restart the outer race/job loop
correct = input(f"\n{name}, you are a {race.name_adjective} {job.name}.\nIs this correct? Y/N\n >> ") correct = input(f"\n{name}, you are a {race.name_adjective} {job.name}.\nIs this correct? Y/N\n >> ")
if correct.lower() in ['y', 'yes']: if correct.lower() in ['y', 'yes']:
return name, gender, age, race, job # All confirmed, return values return name, gender, age, race, job, None# All confirmed, return values
elif correct.lower() in ['n', 'no']: elif correct.lower() in ['n', 'no']:
# If not correct, break this loop to re-enter race/job selection # If not correct, break this loop to re-enter race/job selection
break break
@@ -142,13 +224,13 @@ def startGame():
print("Sorry, I didn't catch that. Please try again.\n") print("Sorry, I didn't catch that. Please try again.\n")
continue continue
elif start in ("2", "pre-generated"): elif start in ("2", "Quick Setup"):
print("Please be prepared to enter a name, gender, age, race, and class, from those available in the game." print("Please be prepared to enter a name, gender, age, race, and class, from those available in the game."
"\nIf you are unsure what the options are, please go back and create a new character.") "\nIf you are unsure what the options are, please go back and create a new character.")
create = input("Do you wish to continue? Y/N\n >> ").lower() create = input("Do you wish to continue? Y/N\n >> ").lower()
if create in ("y", "yes"): if create in ("y", "yes"):
name = input("Name: ") name = input("Name: ")
gender = input("Gender: ") gender = input("Gender (Male, Female, Other): ")
age = int(input("Age: ")) age = int(input("Age: "))
race_str = input("Race (Elf, Dwarf, Human): ") race_str = input("Race (Elf, Dwarf, Human): ")
job_str = input("Job (Barbarian, Cleric, Wizard): ") job_str = input("Job (Barbarian, Cleric, Wizard): ")
@@ -161,31 +243,120 @@ def startGame():
actual_job = job_map.get(job_str.lower()) actual_job = job_map.get(job_str.lower())
if actual_race and actual_job: if actual_race and actual_job:
return name, gender, age, actual_race, actual_job return name, gender, age, actual_race, actual_job, None
else: else:
print("Invalid race or job entered for pre-generated character. Please try again.") print("Invalid race or job entered for pre-generated character. Please try again.")
# Force restart to character creation choice by setting 'start' to '1'
# and then continue the outermost loop.
start = "1" start = "1"
continue continue
return None
elif create in ("n", "no"): elif create in ("n", "no"):
# If 'n', re-prompt the initial choice. # If 'n', re-prompt the initial choice.
start = input("Would you like to create your own character or use pre-generated stats?" start = input("Would you like to create your own character or use pre-generated stats?"
"\n 1) Create a new character\n 2) Pre-generated\n >> ") "\n 1) Create a new character\n 2) Quick Setup\n 3) Pre-Gen Character\n >> ")
continue continue
return None
else: else:
print("Invalid input. Please enter Y or N.") print("Invalid input. Please enter Y or N.")
# If invalid, re-prompt the initial choice. # If invalid, re-prompt the initial choice.
start = input("Would you like to create your own character or use pre-generated stats?" start = input("Would you like to create your own character or use pre-generated stats?"
"\n 1) Create a new character\n 2) Pre-generated\n >> ") "\n 1) Create a new character\n 2) Quick Setup\n 3) Pre-Gen Character\n >> ")
continue continue
else: return None
print("Invalid input. Please select '1' or '2'.") elif start in ("3", "Pre-generated Character"):
# Re-prompt the initial choice. while True:
start = input("Would you like to create your own character or use pre-generated stats?" print("Who would you like to to play?")
"\n 1) Create a new character\n 2) Pre-generated\n >> ") for key, char_data in pre_generated_characters.items():
print(
f"{key}) {char_data['name']} ({char_data['race'].name_adjective} {char_data['job'].name}, {char_data['alignment']})")
print("Type 'back' to return to character creation options.")
char_choice = input(">> ").strip().lower()
if char_choice == "back":
break
if char_choice in pre_generated_characters:
selected_char_data = pre_generated_characters[char_choice]
# --- Display Character Details for Confirmation ---
print(f"\n--- {selected_char_data['name']}'s Details ---")
print(f"Name: {selected_char_data['name']}")
print(f"Gender: {selected_char_data['gender']}")
print(f"Age: {selected_char_data['age']}")
print(f"Race: {selected_char_data['race'].name_adjective}")
print(f"Class: {selected_char_data['job'].name}")
print(f"Alignment: {selected_char_data['alignment']}")
print(f"Description: {selected_char_data['description']}")
print(f"Age: {selected_char_data['age']}")
print(f"\nArmor Class: {selected_char_data['armor_class']}")
print(f"Hit Points: {selected_char_data['hit_points']}")
print(f"Speed: {selected_char_data['speed']}")
print("\n--- Stats ---")
for stat_name, value in selected_char_data['stats'].items():
# Calculate modifier for display (assuming standard D&D rules)
modifier = (value - 10) // 2
modifier_sign = "+" if modifier >= 0 else ""
print(f"{stat_name}: {value} ({modifier_sign}{modifier})")
print("\n--- Proficiencies & Abilities ---")
print(f"Proficiency Bonus: {selected_char_data['proficiencies']['bonus']}")
print(
f"Saving Throws: {', '.join([f'{stat} {val}' for stat, val in selected_char_data['proficiencies']['saving_throws'].items()])}")
if selected_char_data['proficiencies'].get('advantage_on_saves'):
print(
f" Advantage on saves against: {', '.join(selected_char_data['proficiencies']['advantage_on_saves'])}")
print(
f"Skills: {', '.join([f'{skill} {val}' for skill, val in selected_char_data['proficiencies']['skills'].items()])}")
if selected_char_data['proficiencies'].get('armor'):
print(f"Armor Proficiencies: {', '.join(selected_char_data['proficiencies']['armor'])}")
if selected_char_data['proficiencies'].get('weapons'):
print(f"Weapon Proficiencies: {', '.join(selected_char_data['proficiencies']['weapons'])}")
if selected_char_data['proficiencies'].get('tools'):
print(f"Tool Proficiencies: {', '.join(selected_char_data['proficiencies']['tools'])}")
if selected_char_data['proficiencies'].get('damage_resistances'):
print(
f"Damage Resistances: {', '.join(selected_char_data['proficiencies']['damage_resistances'])}")
if selected_char_data['proficiencies'].get('senses'):
senses_str = []
if 'darkvision' in selected_char_data['proficiencies']['senses']:
senses_str.append(
f"Darkvision {selected_char_data['proficiencies']['senses']['darkvision']}")
if 'passive_perception' in selected_char_data['proficiencies']['senses']:
senses_str.append(
f"Passive Perception {selected_char_data['proficiencies']['senses']['passive_perception']}")
print(f"Senses: {', '.join(senses_str)}")
if selected_char_data['proficiencies'].get('languages'):
print(f"Languages: {', '.join(selected_char_data['proficiencies']['languages'])}")
while True:
print("\nDo you want to select this character?")
print("1) Yes, select this character")
print("2) No, go back to character selection")
confirm_choice = input(">> ").strip().lower()
if confirm_choice in ("1", "yes"):
name = selected_char_data['name']
gender = selected_char_data['gender']
age = selected_char_data['age']
race = selected_char_data['race']
job = selected_char_data['job']
pre_allocated_stats = selected_char_data['stats']
print(f"\nYou have selected: {name}, a {age} year old {race.name_adjective} {job.name}.")
return name, gender, age, race, job, pre_allocated_stats # Exit all loops and function
elif confirm_choice in ("2", "no"):
print("\nReturning to pre-generated character selection.")
break # Break out of confirmation loop, go back to char_choice loop
else:
print("Invalid choice. Please enter '1', '2', 'yes', or 'no'.")
else:
print("Invalid selection. Please choose a number from the list or 'back'.")
continue continue
def query_equip(player: Player): def query_equip(player: Player):
"""Allows the player to view or change equipped items.""" """Allows the player to view or change equipped items."""
while True: while True:
@@ -255,7 +426,7 @@ def change_equip(player: Player):
itemlist = [item_obj for item_obj, item_data in player.inventory.items.items() itemlist = [item_obj for item_obj, item_data in player.inventory.items.items()
if item_data["object"] == ItemType.Armor and if item_data["object"] == ItemType.Armor and
item_obj not in [player.inventory.equipped_items[Slots.Helm], item_obj not in [player.inventory.equipped_items[Slots.Helm],
player.inventory.equipped_items[Slots.Chest], player.inventory.equipped_items[Slots.Armor],
player.inventory.equipped_items[Slots.Wrists], player.inventory.equipped_items[Slots.Wrists],
player.inventory.equipped_items[Slots.Feet]]] player.inventory.equipped_items[Slots.Feet]]]
itemlist.append("Return") itemlist.append("Return")
@@ -280,8 +451,8 @@ def change_equip(player: Player):
# Logic for equipping armor based on its intended slot # Logic for equipping armor based on its intended slot
if chosen_item.slot == Slots.Helm: if chosen_item.slot == Slots.Helm:
player.inventory.equip_item(chosen_item, Slots.Helm) player.inventory.equip_item(chosen_item, Slots.Helm)
elif chosen_item.slot == Slots.Chest: elif chosen_item.slot == Slots.Armor:
player.inventory.equip_item(chosen_item, Slots.Chest) player.inventory.equip_item(chosen_item, Slots.Armor)
elif chosen_item.slot == Slots.Wrists: elif chosen_item.slot == Slots.Wrists:
player.inventory.equip_item(chosen_item, Slots.Wrists) player.inventory.equip_item(chosen_item, Slots.Wrists)
elif chosen_item.slot == Slots.Feet: elif chosen_item.slot == Slots.Feet:
@@ -347,14 +518,23 @@ def change_equip(player: Player):
def get_instructions(): def get_instructions():
descrip1 = ("There are certain commands that will be available almost anytime you are able to type,\n" descrip1 = ("There are certain commands that will be available almost anytime you are able to type\n"
"such as viewing your inventory, checking your equipped items, and also changing them.\n" "such as viewing your inventory, checking your equipped items, and also changing them.\n"
"You can also view your stats including your current and max hp.\n") "You can also view your stats including your current and max hp.\n")
descrip2 = ("Some examples are: 'Check inventory', 'Check equipment', and 'View stats'.\n" descrip2 = ("Help - Prints this help message.\n"
"To travel to a new area, just type 'Go north' or 'enter cave' etc.\n" "Check inventory | bag | backpack - Lists items you are carrying.\n"
"To replay the description of the current area, type 'location'.") " Can also just enter 'inventory | bag | backpack\n"
"Check equipment | equipped | items - Lists items you have equipped\n"
" Can also just enter 'equipment | equipped | items\n"
"Check stats or Check hitpoints | hp | health - Shows your stat block or current health details\n"
" Can also just enter 'stats | health | hitpoints | hp\n"
"Go *direction* - Each scene will give you available directions i.e North\n"
"Enter cave | house | room - maybe... TBC\n"
"Scene or Location - Replays the current area's details\n"
"Look around - lists the available items in your scene without displaying the scene description.\n"
"Examine | Open | Loot *object* - Provides details of an item, opens a container, or takes an object.")
print(descrip1) print(descrip1)
time.sleep(1) # Reduced sleep for faster testing time.sleep(3) # Reduced sleep for faster testing
print(descrip2) print(descrip2)
@@ -376,7 +556,7 @@ def parse(input_text):
if words[0] == "check" and words[1] in ("inventory", "bag", "backpack"): if words[0] == "check" and words[1] in ("inventory", "bag", "backpack"):
command = "inventory" command = "inventory"
return command, object1 return command, object1
elif words[0] == "check" and words[1] in ("equipment", "equip", "items"): elif words[0] == "check" and words[1] in ("equipment", "equipped", "items"):
command = "equipment" command = "equipment"
return command, object1 return command, object1
elif words[0] == "check" and words[1] == "stats": elif words[0] == "check" and words[1] == "stats":
@@ -385,7 +565,7 @@ def parse(input_text):
elif words[0] == "check" and words[1] in ("hp", "hitpoints", "health"): elif words[0] == "check" and words[1] in ("hp", "hitpoints", "health"):
command = "hp" command = "hp"
return command, object1 return command, object1
elif words[0] == "go": elif words[0] in ("go", "enter", "exit"):
command = "go" command = "go"
object1 = " ".join(words[1:]) # The rest of the words are the direction object1 = " ".join(words[1:]) # The rest of the words are the direction
return command, object1 return command, object1
@@ -393,15 +573,22 @@ def parse(input_text):
command = "take" command = "take"
object1 = " ".join(words[2:]) object1 = " ".join(words[2:])
return command, object1 return command, object1
elif words[0] == "look" and words[1] == "around" and len(words) == 2:
command = "look_around"
return command, object1
elif words[0] == "exit" and words[1] == "tutorial" and len(words) == 2:
command = "go"
object1 = " ".join(words[1:])
return command, object1
# Single-word commands # Single-word commands
if words[0] == "help": if words[0] == "help":
command = "help" command = "help"
elif words[0] == "scene" or words[0] == "location": # Added 'location' as an alias elif words[0] in ("scene", "location"):
command = "scene" command = "scene"
elif words[0] in ("inventory", "bag", "backpack"): elif words[0] in ("inventory", "bag", "backpack"):
command = "inventory" command = "inventory"
elif words[0] in ("equip", "equipment"): elif words[0] in ("equipped", "equipment"):
command = "equipment" command = "equipment"
elif words[0] == "stats": elif words[0] == "stats":
command = "stats" command = "stats"
@@ -428,6 +615,13 @@ def parse(input_text):
else: else:
command = "loot" # User needs to specify what to loot command = "loot" # User needs to specify what to loot
object1 = None object1 = None
elif words[0] == "open":
if len(words) > 1:
command = "open"
object1 = " ".join(words[1:])
else:
command = "open" # User needs to specify what to open
object1 = None
elif words[0] == "drop": elif words[0] == "drop":
if len(words) > 1: if len(words) > 1:
command = "drop" command = "drop"
@@ -435,6 +629,7 @@ def parse(input_text):
else: else:
command = "drop" # User needs to specify what to drop command = "drop" # User needs to specify what to drop
object1 = None object1 = None
elif words[0] == "quit": elif words[0] == "quit":
command = "quit" command = "quit"
else: else:

193
main.py
View File

@@ -1,11 +1,8 @@
import sys import sys
# Add the current directory to sys.path to allow imports from sibling files # Add the current directory to sys.path to allow imports from sibling files
sys.path.append('.') sys.path.append('.')
# Import classes and functions from your existing files from player import Player
from player import Player, Inventory from function_list import startGame, parse, error_message, get_instructions, wait
from function_list import startGame, parse, error_message, get_instructions
from job_list import Barbarian, Cleric, Wizard
from race_list import Elf, Dwarf, Human
from scene import * from scene import *
@@ -15,7 +12,7 @@ class Engine:
""" """
def __init__(self): def __init__(self):
self.player = None # Will be initialized after character creation self.player = None # Will be initialized after character creation
self.current_scene = starting_clearing # Start the game in the starting clearing self.current_scene = tutorial # Start the game in the tutorial
self.seed = self.current_scene.name # String representation of current scene name self.seed = self.current_scene.name # String representation of current scene name
def set_player(self, player_obj): def set_player(self, player_obj):
@@ -38,7 +35,24 @@ class Engine:
print(f" - {item_obj.name} (x{count})") print(f" - {item_obj.name} (x{count})")
# Display lootable containers # Display lootable containers
if self.current_scene.lootable_items: if self.current_scene.lootable_items:
print("\nYou also notice some containers:") 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
print(f" - {container_name.title()}")
def look_around(self):
if self.current_scene.exits:
exit_directions = ", ".join(self.current_scene.exits.keys()).title()
print(f"Exits: {exit_directions}")
# Display available items
if self.current_scene.available_items:
print("\nAround you, you see:")
for item_obj, count in self.current_scene.available_items.items():
if count > 0:
print(f" - {item_obj.name} (x{count})")
# 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(): 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 if any(count > 0 for count in items_in_container.values()): # Check if container has any items left
print(f" - {container_name.title()}") print(f" - {container_name.title()}")
@@ -93,7 +107,7 @@ class Engine:
elif isinstance(item_obj, Armor): elif isinstance(item_obj, Armor):
print(f"AC: {item_obj.ac}") print(f"AC: {item_obj.ac}")
print(f"Grade: {item_obj.grade}") print(f"Grade: {item_obj.grade}")
print(f"Value: {item_obj.value if item_obj.value is not None else 'N/A'}") print(f"Value: {item_obj.value if item_obj.value is not None else 'No value'}")
print(f"Magical: {item_obj.magical}") print(f"Magical: {item_obj.magical}")
print(f"Attunement: {'Required' if item_obj.attunement else 'Not Required'}") print(f"Attunement: {'Required' if item_obj.attunement else 'Not Required'}")
found_in_scene = True found_in_scene = True
@@ -169,72 +183,85 @@ class Engine:
else: else:
print("You don't see any of those lying around to take.") print("You don't see any of those lying around to take.")
def loot_container(self, container_name): def loot_container(self, container_name):
""" """Allows the player to loot items from a specified container."""
Attempts to loot items from a container in the current scene. container_found = False
:param container_name: The name of the container to loot. for current_container_name, items_in_container in list(self.current_scene.lootable_items.items()):
""" if current_container_name.lower() == container_name.lower():
found_container = False container_found = True
container_items = {} if not items_in_container:
for c_name, items_in_c in self.current_scene.lootable_items.items(): print(f"The {container_name} is empty.")
if container_name.lower() in c_name.lower(): return
container_items = items_in_c
found_container = True
break
if found_container: print(f"You look inside the {container_name}. You see:")
if not container_items or all(count == 0 for count in container_items.values()): loot_list = list(items_in_container.items())
print(f"The {container_name} is empty.")
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
print(f"{take_all_option}) Take all")
print(f"{leave_option}) Leave")
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()):
self.player.inventory.add_item(item_obj, count)
print(f"- Took {count} {item_obj.name}")
del items_in_container[item_obj]
print(f"The {container_name} is now empty.")
return
elif choice == "leave" or (choice.isdigit() and int(choice) == leave_option):
print(f"You leave the {container_name} untouched.")
return
else:
try:
selection_index = int(choice) - 1
if 0 <= selection_index < len(loot_list):
item_obj, current_count = loot_list[selection_index]
take_count_input = input(
f"How many {item_obj.name} will you take? (enter 'all' or a number)\n>> ").lower().strip()
if take_count_input == "all":
take_count = current_count
else:
try:
take_count = int(take_count_input)
except ValueError:
print("Invalid amount. Please enter 'all' or a number.")
continue
if 0 < take_count <= current_count:
self.player.inventory.add_item(item_obj, take_count)
items_in_container[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 not items_in_container:
print(f"The {container_name} is now empty.")
return
elif not loot_list:
print(f"The {container_name} is now empty.")
return
else:
print("Invalid amount or not enough items.")
else:
print("Invalid selection. Please choose a valid item number, 'take all', or 'leave'.")
except ValueError:
print("Invalid selection. Please enter a number, 'take all', or 'leave'.")
return return
print(f"You look inside the {container_name}. You see:") if not container_found:
loot_options = [] print(f"You don't see a '{container_name}' here to loot.")
for i, (item_obj, count) in enumerate(container_items.items()):
if count > 0:
print(f"{i+1}) {item_obj.name} (x{count})")
loot_options.append((item_obj, count))
print(f"{len(loot_options) + 1}) Take all")
print(f"{len(loot_options) + 2}) Leave")
while True:
try:
choice = input("What would you like to take? (number or 'take all'/'leave')\n>> ").lower()
if choice == "leave":
print("You close the container.")
break
elif choice == "take all":
for item_obj, count in loot_options:
self.player.inventory.add_item(item_obj, count)
self.current_scene.remove_lootable_item(container_name, item_obj, count)
print(f"You took everything from the {container_name}.")
break
elif choice.isdigit():
index = int(choice) - 1
if 0 <= index < len(loot_options):
item_obj, count = loot_options[index]
self.player.inventory.add_item(item_obj, count)
self.current_scene.remove_lootable_item(container_name, item_obj, count)
print(f"You took the {item_obj.name}.")
# Re-display options if there's still loot
if any(c > 0 for c in container_items.values()):
print(f"Remaining items in {container_name}:")
for i, (item_obj, count) in enumerate(container_items.items()):
if count > 0:
print(f"{i+1}) {item_obj.name} (x{count})")
print(f"{len(loot_options) + 1}) Take all")
print(f"{len(loot_options) + 2}) Leave")
else:
print(f"The {container_name} is now empty.")
break
else:
print("Invalid selection.")
else:
print("Invalid input. Please enter a number, 'take all', or 'leave'.")
except ValueError:
print("Invalid input. Please enter a number, 'take all', or 'leave'.")
else:
print("You don't see a container like that here to loot.")
# Initialize the game engine # Initialize the game engine
@@ -245,15 +272,29 @@ def main_game_loop():
The main loop for the game, handling character creation and continuous gameplay. The main loop for the game, handling character creation and continuous gameplay.
""" """
# Character Creation # Character Creation
name, gender, age, race, job = startGame() name, gender, age, race, job, pre_allocated_stats = startGame()
# Create player instance # Create player instance
player = Player(name, gender, age, race, job) player = Player(name, gender, age, race, job)
game_engine.set_player(player) # Set the player in the game engine game_engine.set_player(player) # Set the player in the game engine
# Display initial character summary # Display initial character summary
player.new_char() # This calls allocation, which is interactive. if pre_allocated_stats is None:
# For 'Create New Character' or 'Quick Set Up'
game_engine.player.new_char()
else:
# 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.current_stats() # Display stats after setting them
print(' ')
game_engine.player.inventory.current_equipment()
print(' ')
game_engine.player.inventory.current_inventory()
print(' ')
wait()
print("\nYour adventure begins...") print("\nYour adventure begins...")
game_engine.display_current_scene() # Display the starting scene game_engine.display_current_scene() # Display the starting scene
@@ -266,10 +307,12 @@ def main_game_loop():
get_instructions() get_instructions()
elif command == "scene": elif command == "scene":
game_engine.display_current_scene() game_engine.display_current_scene()
elif command == "look_around":
game_engine.look_around()
elif command == "inventory": elif command == "inventory":
game_engine.player.inventory.current_inventory() game_engine.player.inventory.current_inventory()
elif command == "equipment": elif command == "equipment":
Inventory.current_equipment() # This is a static method on Inventory class game_engine.player.inventory.current_equipment()
elif command == "stats": elif command == "stats":
game_engine.player.current_stats() game_engine.player.current_stats()
elif command == "hp": elif command == "hp":
@@ -294,8 +337,8 @@ def main_game_loop():
game_engine.player.drop_item(obj1) game_engine.player.drop_item(obj1)
else: else:
print("What would you like to drop?") print("What would you like to drop?")
elif command.startswith("go "): elif command == "go":
direction = command.split(" ", 1)[1] direction = obj1
game_engine.move_to_scene(direction) game_engine.move_to_scene(direction)
elif command == "quit": elif command == "quit":
print("Thanks for playing!") print("Thanks for playing!")

View File

@@ -1,5 +1,5 @@
from random import randint from random import randint
from enum_list import DamageType, DamageMod, ItemType, Slots # Import specific enums from enum_list import DamageType, DamageMod, ItemType, Slots
# Define Item classes here, as they are fundamental building blocks # Define Item classes here, as they are fundamental building blocks
class Item: class Item:
@@ -15,6 +15,7 @@ class Item:
def __repr__(self): def __repr__(self):
return f"{self.name}\n=====\n{self.description}\nValue: {self.value}\n" return f"{self.name}\n=====\n{self.description}\nValue: {self.value}\n"
class Money(Item): class Money(Item):
"""The currency item used in the world of Kanjin""" """The currency item used in the world of Kanjin"""
def __init__(self, name, amt, magical, ItemType): def __init__(self, name, amt, magical, ItemType):
@@ -30,14 +31,17 @@ class Money(Item):
itemType=ItemType.Money, itemType=ItemType.Money,
attunement=False) attunement=False)
class Weapon(Item): class Weapon(Item):
"""The base class for all weapons""" """The base class for all weapons"""
def __init__(self, name, description, value, slot, damage1H, damage2H, versatiledmg, def __init__(self, name, description, value, slot, damage1H, damage2H, versatiledmg, light, finesse,
dmgType, dmgMod, versatile, thrown, ItemType, magical, attunement): dmgType, dmgMod, versatile, thrown, ItemType, magical, attunement):
self.slot = slot self.slot = slot
self.damage1H = damage1H self.damage1H = damage1H
self.damage2H = damage2H self.damage2H = damage2H
self.versatiledmg = versatiledmg self.versatiledmg = versatiledmg
self.light = light
self.finesse = finesse
self.dmgType = dmgType self.dmgType = dmgType
self.dmgMod = dmgMod self.dmgMod = dmgMod
self.versatile = versatile self.versatile = versatile
@@ -77,6 +81,7 @@ class Weapon(Item):
f"Magical: {self.magical}\n" \ f"Magical: {self.magical}\n" \
f"Attunement: {'Required' if self.attunement else 'Not Required'}" f"Attunement: {'Required' if self.attunement else 'Not Required'}"
class Armor(Item): class Armor(Item):
"""The base class for all armor""" """The base class for all armor"""
def __init__(self, name, description, value, slot, grade, ac, disadvantage, dmgRes, ItemType, magical, attunement): def __init__(self, name, description, value, slot, grade, ac, disadvantage, dmgRes, ItemType, magical, attunement):
@@ -116,7 +121,7 @@ class Inventory:
Slots.OffHand: None, Slots.OffHand: None,
Slots.TwoHanded: None, Slots.TwoHanded: None,
Slots.Helm: None, Slots.Helm: None,
Slots.Chest: None, Slots.Armor: None,
Slots.Wrists: None, Slots.Wrists: None,
Slots.Feet: None, Slots.Feet: None,
Slots.Neck: None, Slots.Neck: None,
@@ -310,26 +315,30 @@ rock = Weapon(
damage1H='1d6', damage1H='1d6',
damage2H=None, damage2H=None,
versatiledmg=None, versatiledmg=None,
light=True,
finesse=False,
dmgType=DamageType.Bludgeoning, dmgType=DamageType.Bludgeoning,
dmgMod=DamageMod.Strength, dmgMod=DamageMod.Strength,
versatile=False, versatile=False,
thrown=True, thrown=True,
magical=False, magical=False,
ItemType=ItemType.Weapon, ItemType=ItemType.Weapon,
attunement=False # Rocks typically aren't attuned attunement=False
) )
dagger = Weapon( dagger = Weapon(
name="Dagger", name="Dagger",
description="Pointy stabby-stab", description="Pointy stabby-stab",
value=None, value=None,
slot=Slots.MainHand, # Can be main hand or off hand slot=Slots.MainHand,
damage1H='1d4', # Daggers are usually 1d4 damage1H='1d4',
damage2H=None, damage2H=None,
versatiledmg=None, # Daggers are not versatile in the D&D sense (they are light, finesse) versatiledmg=None,
dmgType=DamageType.Piercing, # Changed to piercing light=True,
finesse=True,
dmgType=DamageType.Piercing,
dmgMod=DamageMod.Dexterity, dmgMod=DamageMod.Dexterity,
versatile=False, # Changed to False, as D&D versatile means 1H or 2H damage versatile=False,
thrown=True, thrown=True,
magical=False, magical=False,
ItemType=ItemType.Weapon, ItemType=ItemType.Weapon,
@@ -344,6 +353,8 @@ polearm = Weapon(
damage1H=None, damage1H=None,
damage2H="1d10", # Polearms are typically 1d10 damage2H="1d10", # Polearms are typically 1d10
versatiledmg=None, versatiledmg=None,
light=False,
finesse=False,
dmgType=DamageType.Piercing, dmgType=DamageType.Piercing,
dmgMod=DamageMod.Strength, dmgMod=DamageMod.Strength,
versatile=False, versatile=False,
@@ -357,7 +368,7 @@ tornRags = Armor(
name="Torn Rags", name="Torn Rags",
description="A ripped and worn-out outfit.", description="A ripped and worn-out outfit.",
value=None, value=None,
slot=Slots.Chest, slot=Slots.Armor,
grade="Light", grade="Light",
ac=10, # Base AC for light armor without proficiency is 10 + Dex mod ac=10, # Base AC for light armor without proficiency is 10 + Dex mod
disadvantage=False, # Light armor usually doesn't give disadvantage disadvantage=False, # Light armor usually doesn't give disadvantage
@@ -430,9 +441,10 @@ class Player:
# Initial items and equipment (now with silent=True) # Initial items and equipment (now with silent=True)
self.inventory.add_item(rock, 1, silent=True) self.inventory.add_item(rock, 1, silent=True)
self.inventory.add_item(tornRags, 1, silent=True) self.inventory.add_item(tornRags, 1, silent=True)
# Equip initial items (using the inventory's equip method) # Equip initial items (using the inventory's equip method)
self.inventory.equip_item(rock, Slots.MainHand, silent=True) self.inventory.equip_item(rock, Slots.MainHand, silent=True)
self.inventory.equip_item(tornRags, Slots.Chest, silent=True) self.inventory.equip_item(tornRags, Slots.Armor, silent=True)
def getModifier(self): def getModifier(self):

View File

@@ -93,9 +93,8 @@ class Scene:
# Scene 0: Tutorial # Scene 0: Tutorial
tutorial = Scene( tutorial = Scene(
name="Tutorial", name="Tutorial",
description="Welcome to Kanjin Text RPG!" description="Welcome to Kanjin Text RPG!\n\n"
"This is a very simple tutorial to show you the basics of issuing commands.\n" "This is a very simple tutorial to show you the basics of issuing commands.\n"
"You can return at anytime where you are asked 'What do you want to do?' by typing 'Enter tutorial'.\n"
"Important commands you'll want to know can be found by typing 'Help'.\n\n" "Important commands you'll want to know can be found by typing 'Help'.\n\n"
"These are the available commands:\n" "These are the available commands:\n"
"Help - Prints this help message.\n" "Help - Prints this help message.\n"
@@ -109,7 +108,7 @@ tutorial = Scene(
"Enter cave | house | room - maybe... TBC\n" "Enter cave | house | room - maybe... TBC\n"
"Scene or Location - Replays the current area's details\n" "Scene or Location - Replays the current area's details\n"
"Look around - lists the available items in your scene without displaying the scene description.\n" "Look around - lists the available items in your scene without displaying the scene description.\n"
"Examine | Open | Loot *object* - Provides details of an item, opens a container, or takes an object.\n" "Examine | Open | Loot *object* - Provides details of an item, opens a container, or takes an object."
) )
tutorial.add_available_item(rock, 1) tutorial.add_available_item(rock, 1)
tutorial.add_available_item(paper, 2) tutorial.add_available_item(paper, 2)
@@ -153,6 +152,8 @@ dark_cave_entrance.add_available_item(polearm, 1) # A polearm leaning against th
# Link the scenes together # Link the scenes together
tutorial.add_exit("tutorial", starting_clearing)
starting_clearing.add_exit("north", forest_path) starting_clearing.add_exit("north", forest_path)
starting_clearing.add_exit("east", dark_cave_entrance) starting_clearing.add_exit("east", dark_cave_entrance)