Skip to content

Commit

Permalink
Merge pull request #10 from Yochien/npc-split
Browse files Browse the repository at this point in the history
Splits NPCs into two types, those for the bestiary and those for combat encounters. Focuses on differentiating between descriptive NPCs and interactable NPCs.
  • Loading branch information
Yochien committed Aug 15, 2023
2 parents 6c103b4 + 1fb4136 commit f34ef53
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 126 deletions.
11 changes: 9 additions & 2 deletions bestiary.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@ Wolf:
Fox:
hp: 3
ac: 12
comment: this note will be ignored
comment: This note will be ignored.
Spider:
hp: 1
ac: 12
description: A tiny creepy crawley creature
description: A tiny creepy crawley creature.

# Fantasy
Skeleton:
hp: 13
ac: 13
description: >
An undead creature, once a zombie
all of its living flesh has rotted away.
Zombie:
hp: 16
ac: 15
description: >
A creature reanimated from the dead
by some sinister magic.
Dragon:
hp: 150
ac: 18
Expand All @@ -31,3 +37,4 @@ Townsfolk:
Guard:
hp: 25
ac: 13
description: A town's foot soldier.
79 changes: 52 additions & 27 deletions src/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import yaml

from src.npc import NPC, NPCList, findList
from src.npc import NPC, BookNPC, CombatNPC, NPCList, findList


class Command(ABC):
Expand Down Expand Up @@ -55,9 +55,9 @@ def execute(self, args = []):
print("Selected bestiary file could not be found.")
if len(self.bestiary) == 0:
print("Loading placeholder bestiary.")
self.bestiary.data.append(NPC("Human", 5, 12))
self.bestiary.data.append(NPC("Animal", 3, 10))
self.bestiary.data.append(NPC("Enemy", 10, 13))
self.bestiary.data.append(BookNPC("Human", 5, 12, "Common townsfolk."))
self.bestiary.data.append(BookNPC("Animal", 3, 10))
self.bestiary.data.append(BookNPC("Enemy", 10, 13))
else:
self.bestiary.data.clear()
num_npc_loaded = 0
Expand All @@ -74,7 +74,11 @@ def execute(self, args = []):
try:
hp = int(attributes["hp"])
ac = int(attributes["ac"])
npc = NPC(name, hp, ac)
try:
description = attributes["description"]
except KeyError:
description = None
npc = BookNPC(name, hp, ac, description)
except KeyError as key:
print(f"NPC \"{name}\" is missing the {key} attribute!")
except TypeError:
Expand Down Expand Up @@ -189,10 +193,10 @@ def isValidInt(selector: str, referencList: NPCList) -> bool:
return True


def copyNPC(bestiary: NPCList, index: int, other: NPCList) -> None:
def copyNPC(bestiary: NPCList, index: int, encounter: NPCList) -> None:
npc = bestiary.data[index]
copy = NPC(npc.name, npc.maxHP, npc.ac)
other.data.append(copy)
npc_instance = CombatNPC(npc.name, npc.maxHP, npc.ac)
encounter.data.append(npc_instance)


class addNPC(Command):
Expand Down Expand Up @@ -289,8 +293,7 @@ def execute(self, args = []):
return

selected = args[0].split(",")
# Remove duplicates and reverse sort the input
selected = sorted(list(set(selected)), reverse = True)
selected = sorted(list(set(selected)), reverse = True) # Remove duplicates and reverse sort the input

for index in selected:
self.encounter.data.pop(int(index) - 1)
Expand All @@ -299,10 +302,7 @@ def execute(self, args = []):


def areAllDefeated(encounter: NPCList):
for npc in encounter.data:
if npc.currentHP > 0:
return False
return True
return all(npc.currentHP > 0 for npc in encounter.data)


class attack(Command):
Expand Down Expand Up @@ -463,14 +463,13 @@ def execute(self, args = []):
npc.currentHP = 0
npc.currentRank = 0
else:
if not isValidInt(args[0], self.encounter):
Command.OOBSelection(self.encounter)
return

selected = args[0].split(",")
selected = list(set(selected)) # Remove duplicates from the selection

for index in selected:
if not isValidInt(args[0], self.encounter):
Command.OOBSelection(self.encounter)
return

for index in selected:
npc = self.encounter.data[int(index) - 1]
if npc.currentHP <= 0:
Expand Down Expand Up @@ -498,6 +497,9 @@ def __init__(self, encounter):
self.usageStr = "heal <encounter_index,...> <amount>"

def __healNPC(self, npc: NPC, amount: int) -> int:
if not isinstance(npc, CombatNPC):
raise TypeError()

originalHP = npc.currentHP
npc.currentHP = originalHP + amount
npc.currentHP = min(npc.maxHP, npc.currentHP)
Expand Down Expand Up @@ -557,7 +559,7 @@ def execute(self, args = []):
if args[0].lower() == "all":
print("Status:")
for npc in self.encounter.data:
print(npc.combatStatus())
print(npc.detailedInfo())
elif isValidInt(args[0], self.encounter):
selected = args[0].split(",")
selected = list(set(selected))
Expand All @@ -566,7 +568,7 @@ def execute(self, args = []):
for index in selected:
npc = self.encounter.data[int(index) - 1]

print(npc.combatStatus())
print(npc.detailedInfo())
else:
Command.OOBSelection(self.encounter)
else:
Expand All @@ -582,12 +584,31 @@ def __init__(self, bestiary):
self.usageStr = "info <index>"

def execute(self, args = []):
if len(args) == 1 and isInt(args[0]):
if isValidInt(args[0], self.bestiary):
if len(args) == 1:
if isInt(args[0]):
if isValidInt(args[0], self.bestiary):
print("INFO:")
print(self.bestiary.data[int(args[0]) - 1].detailedInfo())
else:
Command.OOBSelection(self.bestiary)
elif args[0].lower() == "all":
print("INFO:")
print(self.bestiary.data[int(args[0]) - 1].detailedInfo())
for entry in self.bestiary.data[:-1]:
print(entry.detailedInfo() + "\n")
print(self.bestiary.data[-1].detailedInfo())
else:
Command.OOBSelection(self.bestiary)
if not isValidInt(args[0], self.bestiary):
Command.OOBSelection(self.bestiary)
return

selected = args[0].split(",")
selected = sorted(list(set(selected)))

print("INFO:")
for index in selected[:-1]:
entry = self.bestiary.data[int(index) - 1]
print(entry.detailedInfo() + "\n")
print(self.bestiary.data[int(selected[-1]) - 1].detailedInfo())
else:
self.usage()

Expand All @@ -605,8 +626,9 @@ def __init__(self, bestiary):
self.usageStr = "make <name> <max hp> <armor class>"

def execute(self, args=[]) -> None:
if len(args) == 3 and not args[0].isnumeric() and isInt(args[1]) and isInt(args[2]):
self.bestiary.data.append(NPC(args[0], int(args[1]), int(args[2])))
if len(args) >= 3 and not args[0].isnumeric() and isInt(args[1]) and isInt(args[2]):
description = " ".join(args[3:]) if (len(args) > 3) else None
self.bestiary.data.append(BookNPC(args[0], int(args[1]), int(args[2]), description))
else:
self.usage()

Expand Down Expand Up @@ -744,6 +766,9 @@ def execute(self, args=[]) -> None:
if len(args) == 2 and isValidInt(args[0], self.encounter) and isInt(args[1]):
rank = max(int(args[1]), 0)
npc = self.encounter.data[int(args[0]) - 1]
if not isinstance(npc, CombatNPC):
raise TypeError()

if npc.currentHP > 0:
npc.currentRank = rank
npc.maxRank = rank
Expand Down
8 changes: 4 additions & 4 deletions src/encounter.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import src.commands as cmd
from src.npc import NPCList
from src.npc import BookNPC, CombatNPC, NPCList


def initialize_commands(encounter: NPCList) -> list[cmd.Command]:
bestiary = NPCList(["bestiary", "book", "b"])
bestiary = NPCList(["bestiary", "book", "b"], BookNPC)
referenceLists = [bestiary, encounter]

commands = []
Expand All @@ -28,7 +28,7 @@ def initialize_commands(encounter: NPCList) -> list[cmd.Command]:


def main():
encounter = NPCList(["encounter", "e", "combat", "c"])
encounter = NPCList(["encounter", "e", "combat", "c"], CombatNPC)
commands = initialize_commands(encounter)

for command in commands:
Expand All @@ -40,7 +40,7 @@ def main():
print("Type help or ? to get a list of availible commands.")

while True:
encounter.data.sort(reverse = True)
encounter.data.sort(key = lambda npc: npc.currentRank, reverse = True)

userInput = input(prompt).strip().split(" ")
userInput = [token for token in userInput if not token.isspace() and token != ""]
Expand Down
Loading

0 comments on commit f34ef53

Please sign in to comment.