Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion src/location/bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,47 @@ def __init__(
"I've worked at this bank for fifteen years and I take pride in keeping everyone's money safe. "
"My grandmother taught me the value of saving, and I've helped many fishermen in this village "
"secure their futures. A penny saved is a penny earned, as they say!",
[
{
"question": "Tell me about yourself.",
"response": "I've worked at this bank for fifteen years and I take pride in keeping everyone's money safe. "
"My grandmother taught me the value of saving, and I've helped many fishermen in this village "
"secure their futures. A penny saved is a penny earned, as they say!"
},
{
"question": "How does the bank work?",
"response": "The bank is simple and safe! You can deposit money when you have some on hand, "
"and withdraw it whenever you need. We keep your money secure - "
"no risk of losing it to gambling or spending it accidentally! "
"Plus, your savings earn interest over time. The more you save, the more you earn. "
"It's the smart way to grow your wealth!"
},
{
"question": "Tell me about interest rates.",
"response": "Ah yes, interest! Every day that passes, your savings grow by a small percentage. "
"It might not seem like much at first, but over time it really adds up! "
"The interest is automatically added to your bank account. "
"Think of it as the bank paying you for keeping your money with us. "
"The more you save, the more interest you earn!"
},
{
"question": "Should I save or spend my money?",
"response": "That's the eternal question, isn't it? Here's my advice: "
"Keep some money on hand for daily needs - buying bait, paying for drinks, gambling if you must. "
"But save the rest in the bank! Your savings will grow with interest, "
"and you'll have a nice cushion for the future. "
"Many fishermen spend everything they earn and have nothing to show for it. "
"Be smarter than that!"
},
{
"question": "What's the most important financial advice?",
"response": "Save regularly, even if it's just a little bit. Every coin counts! "
"Don't gamble away your hard-earned money - the odds are rarely in your favor. "
"Invest in good bait to improve your catches, but save the profits. "
"And remember: it's not about how much you earn, it's about how much you keep. "
"That's the secret to real wealth!"
}
]
)

def run(self):
Expand Down Expand Up @@ -113,4 +154,4 @@ def withdraw(self):
break

def talkToNPC(self):
self.userInterface.showDialogue(self.npc.introduce())
self.userInterface.showInteractiveDialogue(self.npc)
43 changes: 42 additions & 1 deletion src/location/docks.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,47 @@ def __init__(
"My pa was a fisherman, and his pa before him. I help maintain the boats and docks, "
"and I've learned a thing or two about fishing over the years. "
"The sea provides for those who respect her!",
[
{
"question": "Tell me about yourself.",
"response": "Been working these docks since I was knee-high to a grasshopper. "
"My pa was a fisherman, and his pa before him. I help maintain the boats and docks, "
"and I've learned a thing or two about fishing over the years. "
"The sea provides for those who respect her!"
},
{
"question": "How do I fish at the docks?",
"response": "Fishing is what this village is all about! You need at least 10 energy to fish. "
"When you cast your line, you'll spend several random hours (1-10) fishing. "
"Each hour uses 10 energy. When a fish bites, press Enter fast - within 2 seconds! "
"Your reaction time matters. The more successful catches, the more fish you'll get. "
"Don't worry if you miss a few - you'll still catch at least one fish if you tried!"
},
{
"question": "What other locations can I visit?",
"response": "From the docks, you can get to anywhere in the village! "
"There's your home - that's where you sleep to restore energy. "
"Gilbert's shop is where you sell fish and buy better bait. "
"The tavern is run by Old Tom - gambling and drinks there. "
"And the bank, where Margaret will keep your money safe and even give you interest!"
},
{
"question": "Tell me about energy and rest.",
"response": "Energy is your lifeblood as a fisherman! You start each day with it, "
"and fishing uses it up - 10 energy per hour of fishing. "
"When you're running low, head home and sleep. That'll restore you for the next day. "
"The game keeps track of time - each action moves the clock forward. "
"Plan your day wisely!"
},
{
"question": "What makes a good fisherman?",
"response": "Patience and quick reflexes! When that fish bites, you gotta be ready. "
"Invest in better bait from Gilbert - it makes a huge difference. "
"Fish when you have energy, sell regularly, and save your money. "
"The sea has its rhythms - you'll learn them in time. "
"And remember: it's not just about catching fish, it's about enjoying the life!"
}
]
)

def run(self):
Expand Down Expand Up @@ -148,4 +189,4 @@ def fish(self):
)

def talkToNPC(self):
self.userInterface.showDialogue(self.npc.introduce())
self.userInterface.showInteractiveDialogue(self.npc)
40 changes: 39 additions & 1 deletion src/location/shop.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,44 @@ def __init__(
"I've been running this shop for thirty years, ever since I inherited it from my father. "
"I've seen many fishermen come and go, but the best ones always come back for quality bait. "
"I may not fish much anymore, but I know good gear when I see it!",
[
{
"question": "Tell me about yourself.",
"response": "I've been running this shop for thirty years, ever since I inherited it from my father. "
"I've seen many fishermen come and go, but the best ones always come back for quality bait. "
"I may not fish much anymore, but I know good gear when I see it!"
},
{
"question": "What do you sell here?",
"response": "I deal in all things fishing! I'll buy any fish you catch - the price varies, "
"but you can expect $3 to $5 per fish. I also sell better bait that'll help you catch more fish. "
"The price goes up each time you upgrade, but trust me, it's worth it! "
"Better bait means more fish, and more fish means more money!"
},
{
"question": "How does fishing work?",
"response": "Ah, fishing! Head down to the docks when you've got some energy. "
"You'll spend a few hours out there, and each hour costs 10 energy. "
"When a fish bites, you need to press Enter quickly - within 2 seconds! "
"Your success rate determines how many fish you catch. "
"Better bait from my shop will multiply your catch!"
},
{
"question": "Tell me about the bait upgrades.",
"response": "Starting bait is decent, but my premium bait? That's where the magic happens! "
"Each upgrade increases your fish multiplier by 1. So if you normally catch 5 fish, "
"with a 2x multiplier you'll catch 10! The bait gets more expensive each time - "
"starts at one price then increases by 25% with each purchase. "
"But serious fishermen know it's the best investment you can make!"
},
{
"question": "Any tips for selling fish?",
"response": "Well, the price per fish is random between $3 and $5, so sometimes you get lucky! "
"I'd say don't hoard your fish too long - sell regularly to keep money flowing. "
"Use that money to buy better bait, which helps you catch more, which means more money! "
"It's a beautiful cycle, really. And don't forget to save some money at the bank!"
}
]
)

def run(self):
Expand Down Expand Up @@ -74,4 +112,4 @@ def buyBetterBait(self):
self.currentPrompt.text = "You bought some better bait!"

def talkToNPC(self):
self.userInterface.showDialogue(self.npc.introduce())
self.userInterface.showInteractiveDialogue(self.npc)
39 changes: 38 additions & 1 deletion src/location/tavern.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,43 @@ def __init__(
"I sailed the seven seas for forty years before settling down here. "
"Lost my leg to a shark near the Caribbean, but I got plenty of stories to make up for it. "
"These days I pour drinks and listen to folks' troubles. Best job I ever had!",
[
{
"question": "Tell me about yourself.",
"response": "I sailed the seven seas for forty years before settling down here. "
"Lost my leg to a shark near the Caribbean, but I got plenty of stories to make up for it. "
"These days I pour drinks and listen to folks' troubles. Best job I ever had!"
},
{
"question": "How do I make money in this village?",
"response": "Well now, there's a few ways to fill your pockets around here! "
"The most reliable is fishing at the docks - catch some fish and sell 'em at Gilbert's shop. "
"You can also try your luck at gambling right here in the tavern, but be warned - "
"the dice don't always roll in your favor! And if you're patient, the bank offers "
"interest on your savings."
},
{
"question": "What can I do at the tavern?",
"response": "Ah, the tavern! This is the place to unwind after a long day. "
"You can get yourself drunk for $10 - though you'll wake up at home with a headache the next day! "
"Or if you're feeling lucky, you can gamble with the dice. Place a bet, pick a number from 1 to 6, "
"and if the dice matches your choice, you'll double your money!"
},
{
"question": "Tell me about the other villagers.",
"response": "Let me see... There's Gilbert the shopkeeper - been running that shop for thirty years. "
"He'll buy your fish and sell you better bait. Then there's Sam down at the docks, "
"knows everything about fishing. Margaret at the bank will keep your money safe. "
"All good folk, they are!"
},
{
"question": "Any advice for a newcomer?",
"response": "Aye, I've seen many fishermen come through these doors. Here's what I tell 'em all: "
"Start small, fish when you have energy, and sell your catch regularly. "
"Don't gamble away all your coin - save some at the bank. "
"And remember, better bait means better catches. Take your time and enjoy the village!"
}
]
)

def run(self):
Expand Down Expand Up @@ -151,4 +188,4 @@ def changeBet(self, prompt):
)

def talkToNPC(self):
self.userInterface.showDialogue(self.npc.introduce())
self.userInterface.showInteractiveDialogue(self.npc)
16 changes: 15 additions & 1 deletion src/npc/npc.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
# @author Daniel McCoy Stephenson
class NPC:
def __init__(self, name: str, backstory: str):
def __init__(self, name: str, backstory: str, dialogue_options: list = None):
self.name = name
self.backstory = backstory
if dialogue_options is None:
self.dialogue_options = []
else:
self.dialogue_options = dialogue_options

def introduce(self):
"""Returns the NPC's introduction text"""
return f"{self.name}: {self.backstory}"

def get_dialogue_options(self):
"""Returns list of available dialogue options"""
return self.dialogue_options

def get_dialogue_response(self, option_index: int):
"""Returns the response for a specific dialogue option"""
if 0 <= option_index < len(self.dialogue_options):
return self.dialogue_options[option_index].get("response", "")
return ""
49 changes: 49 additions & 0 deletions src/ui/userInterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,52 @@ def showDialogue(self, text):
self.divider()
input(" [ CONTINUE ]")
self.currentPrompt.text = "What would you like to do?"

def showInteractiveDialogue(self, npc):
"""Shows an interactive dialogue menu with the NPC"""
while True:
self.lotsOfSpace()
self.divider()
Comment on lines +90 to +94
Copy link

Copilot AI Feb 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showInteractiveDialogue introduces new interactive control flow and input handling, but there’s no automated test coverage for it while UserInterface already has tests for showDialogue/showOptions (see tests/ui/test_userInterface.py). Adding tests that mock input to select an option and then [Back] would help prevent regressions.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit c4d40d8. Added three tests for showInteractiveDialogue: no options fallback, valid option selection, and invalid input handling.

print(f" Talking with {npc.name}")
self.divider()

# Show dialogue options
dialogue_options = npc.get_dialogue_options()
if not dialogue_options:
# Fallback to simple introduction if no options
print(npc.introduce())
self.divider()
input(" [ CONTINUE ]")
self.currentPrompt.text = "What would you like to do?"
break

print(" What would you like to ask?\n")
option_list = []
for i, option in enumerate(dialogue_options):
question = option.get("question", f"Option {i+1}")
print(f" [{i+1}] {question}")
option_list.append(str(i+1))

print(f" [{len(option_list)+1}] [Back]")
option_list.append(str(len(option_list)+1))

choice = input("\n> ")

if choice in option_list:
choice_idx = int(choice) - 1

# Check if user chose to go back
if choice_idx == len(dialogue_options):
self.currentPrompt.text = "What would you like to do?"
break

# Show the response
response = npc.get_dialogue_response(choice_idx)
self.lotsOfSpace()
self.divider()
print(f" {npc.name}: {response}")
self.divider()
input(" [ CONTINUE ]")
else:
print(" Invalid choice. Try again!")
input(" [ CONTINUE ]")
10 changes: 5 additions & 5 deletions tests/location/test_bank.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,16 +120,16 @@ def test_run_talk_to_npc_action():
def test_talkToNPC():
# prepare
bankInstance = createBank()
bankInstance.userInterface.showDialogue = MagicMock()
bankInstance.userInterface.showInteractiveDialogue = MagicMock()

# call
bankInstance.talkToNPC()

# check
bankInstance.userInterface.showDialogue.assert_called_once()
call_args = bankInstance.userInterface.showDialogue.call_args[0][0]
assert "Margaret the Teller" in call_args
assert len(call_args) > 0
bankInstance.userInterface.showInteractiveDialogue.assert_called_once()
call_args = bankInstance.userInterface.showInteractiveDialogue.call_args[0][0]
assert call_args.name == "Margaret the Teller"
assert len(call_args.get_dialogue_options()) > 0


def test_deposit_success():
Expand Down
10 changes: 5 additions & 5 deletions tests/location/test_docks.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,16 @@ def test_run_talk_to_npc_action():
def test_talkToNPC():
# prepare
docksInstance = createDocks()
docksInstance.userInterface.showDialogue = MagicMock()
docksInstance.userInterface.showInteractiveDialogue = MagicMock()

# call
docksInstance.talkToNPC()

# check
docksInstance.userInterface.showDialogue.assert_called_once()
call_args = docksInstance.userInterface.showDialogue.call_args[0][0]
assert "Sam the Dock Worker" in call_args
assert len(call_args) > 0
docksInstance.userInterface.showInteractiveDialogue.assert_called_once()
call_args = docksInstance.userInterface.showInteractiveDialogue.call_args[0][0]
assert call_args.name == "Sam the Dock Worker"
assert len(call_args.get_dialogue_options()) > 0


def test_run_go_to_shop_action():
Expand Down
10 changes: 5 additions & 5 deletions tests/location/test_shop.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@ def test_run_talk_to_npc_action():
def test_talkToNPC():
# prepare
shopInstance = createShop()
shopInstance.userInterface.showDialogue = MagicMock()
shopInstance.userInterface.showInteractiveDialogue = MagicMock()

# call
shopInstance.talkToNPC()

# check
shopInstance.userInterface.showDialogue.assert_called_once()
call_args = shopInstance.userInterface.showDialogue.call_args[0][0]
assert "Gilbert the Shopkeeper" in call_args
assert len(call_args) > 0
shopInstance.userInterface.showInteractiveDialogue.assert_called_once()
call_args = shopInstance.userInterface.showInteractiveDialogue.call_args[0][0]
assert call_args.name == "Gilbert the Shopkeeper"
assert len(call_args.get_dialogue_options()) > 0


def test_sellFish():
Expand Down
10 changes: 5 additions & 5 deletions tests/location/test_tavern.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,16 +105,16 @@ def test_run_talk_to_npc_action():
def test_talkToNPC():
# prepare
tavernInstance = createTavern()
tavernInstance.userInterface.showDialogue = MagicMock()
tavernInstance.userInterface.showInteractiveDialogue = MagicMock()

# call
tavernInstance.talkToNPC()

# check
tavernInstance.userInterface.showDialogue.assert_called_once()
call_args = tavernInstance.userInterface.showDialogue.call_args[0][0]
assert "Old Tom the Barkeep" in call_args
assert len(call_args) > 0
tavernInstance.userInterface.showInteractiveDialogue.assert_called_once()
call_args = tavernInstance.userInterface.showInteractiveDialogue.call_args[0][0]
assert call_args.name == "Old Tom the Barkeep"
assert len(call_args.get_dialogue_options()) > 0


def test_getDrunk():
Expand Down
Loading