Compare commits

...

11 Commits

Author SHA1 Message Date
6b44022022 depression+sick+inventory+pain 2026-06-26 19:30:30 -04:00
7e85543c21 oops 2026-06-25 17:05:35 -04:00
f1ea9a1de5 stuff 2026-06-25 16:56:33 -04:00
0b0ae5db73 fix 2026-06-25 16:37:40 -04:00
23b1b83bdd oops 2026-06-25 16:37:02 -04:00
19d7c76374 stuff 2026-06-25 16:36:44 -04:00
96b5ab2069 fix 2026-06-25 16:34:26 -04:00
188c1be7bf inventory and feed 2026-06-25 16:32:40 -04:00
f61889195c work! 2026-06-25 16:02:01 -04:00
c1a5361255 shop2 2026-06-25 15:40:45 -04:00
988ddf1ebf shop 2026-06-25 15:40:40 -04:00
10 changed files with 347 additions and 16 deletions

View File

@@ -62,10 +62,11 @@ def test_decay_and_replenish():
last_updated=0, last_updated=0,
), ),
) )
cat.player.inventory["food"] = 1
rules.reconcile(cat.cat, 3600 * 2) rules.reconcile(cat.cat, 3600 * 2)
assert cat.cat.happiness < 98 assert cat.cat.happiness < 98
assert cat.cat.fullness < 98 assert cat.cat.fullness < 98
rules.feed(cat.cat) rules.feed(cat.player, cat.cat)
assert cat.cat.fullness == pytest.approx(100) assert cat.cat.fullness == pytest.approx(100)
rules.reconcile(cat.cat, 7200 + 20 * 3600) rules.reconcile(cat.cat, 7200 + 20 * 3600)
assert cat.cat.happiness < 96 - (content.BASE_HAPPINESS_DECAY_PER_HOUR * 20) assert cat.cat.happiness < 96 - (content.BASE_HAPPINESS_DECAY_PER_HOUR * 20)

View File

@@ -8,7 +8,16 @@ BASE_HAPPINESS_DECAY_PER_HOUR = 2
HUNGER_SADNESS_THRESHOLD = 30 HUNGER_SADNESS_THRESHOLD = 30
HUNGER_SADNESS_PENALTY_PER_HOUR = 5 HUNGER_SADNESS_PENALTY_PER_HOUR = 5
BASE_INVENTORY = {"food": 0, "medicine": 0, "catnip": 0} ITEMS = {"food": 3, "medicine": 5, "catnip": 5}
BASE_INVENTORY = {item: 0 for item in ITEMS}
WORK_START_LETTERS = 2
WORK_EARN_PER_ROUND = 3
FOOD_RESTORE = 30
CATNIP_RESTORE = 20
MEDICINE_RESTORE = 20
CAT_COLORS = [ CAT_COLORS = [
"orange tabby", "orange tabby",

View File

@@ -41,14 +41,52 @@ def reconcile(cat: model.Cat, now):
cat.happiness -= content.HUNGER_SADNESS_PENALTY_PER_HOUR * elapsed_hours cat.happiness -= content.HUNGER_SADNESS_PENALTY_PER_HOUR * elapsed_hours
cat.happiness = _clamp(cat.happiness) cat.happiness = _clamp(cat.happiness)
if cat.happiness == 0:
cat.depressed = True
if cat.fullness == 0:
cat.sick = True
cat.last_updated = now cat.last_updated = now
def feed(cat, amount=100): def feed(player, cat, amount=content.FOOD_RESTORE):
cat.fullness += amount if player.inventory["food"] <= 0:
cat.fullness = _clamp(cat.fullness) return False
player.inventory["food"] -= 1
cat.fullness = _clamp(cat.fullness + amount)
return True
def cure_sick(save, restore=content.MEDICINE_RESTORE):
if save.player.inventory["medicine"] <= 0:
return False
save.cat.fullness = restore
save.cat.sick = False
save.player.inventory["medicine"] -= 1
return True
def cure_depressed(save, restore=content.CATNIP_RESTORE):
if save.player.inventory["catnip"] <= 0:
return False
save.cat.happiness = restore
save.cat.depressed = False
save.player.inventory["catnip"] -= 1
return True
def excite(cat, amount=100): def excite(cat, amount=100):
cat.happiness += amount cat.happiness += amount
cat.happiness = _clamp(cat.happiness) cat.happiness = _clamp(cat.happiness)
def buy(player, item, price):
if price > player.money:
return False
player.money -= price
player.inventory[item] += 1
return True
def earn(player, amount):
player.money += amount

View File

@@ -1,4 +1,5 @@
from untitled import ui from untitled import ui
from untitled.screens import shop, work
def options(): def options():
@@ -10,3 +11,11 @@ def options():
return "save" return "save"
case "Save and quit": case "Save and quit":
return "savequit" return "savequit"
def go_to(save):
match ui.select("Where do you want to go?", ["The shop", "Work", "Back"]):
case "The shop":
shop.shop(save)
case "Work":
work.work(save)

View File

@@ -1,29 +1,63 @@
import time import time
from untitled import generation, model, persistence, rules, ui from untitled import generation, model, persistence, rules, ui
from untitled.screens.common import options from untitled.screens import inventory, pet
from untitled.screens.common import go_to, options
def house(save: model.Save): def house(save: model.Save):
print("Welcome to your house!") print("Welcome to your house!")
if save.cat.sick or save.cat.depressed:
print(
f"Your cat is {"sick" if save.cat.sick else ""}{" and " if save.cat.sick and save.cat.depressed else ""}{"depressed" if save.cat.depressed else ""}. "
)
while True: while True:
match ui.select( match ui.select(
"What do you want to do?", "What do you want to do?",
["Check on your cat", "Feed your cat", "Pet your cat", "Menu"], [
"Check on your cat",
"View your inventory",
"Feed your cat",
"Pet your cat",
"Go to...",
"Menu",
],
): ):
case "Check on your cat": case "Check on your cat":
rules.reconcile(save.cat, time.time()) rules.reconcile(save.cat, time.time())
print( if save.cat.sick or save.cat.depressed:
f"{save.cat.name}, {generation.generate_trait_sentence(save.cat.traits).lower()}\nFullness: {round(save.cat.fullness,1)}\nHappiness: {round(save.cat.happiness,1)}" print(
) f"{save.cat.name}: a {"sick" if save.cat.sick else ""}{" and " if save.cat.sick and save.cat.depressed else ""}{"depressed" if save.cat.depressed else ""} cat."
)
else:
print(
f"{save.cat.name}, {generation.generate_trait_sentence(save.cat.traits).lower()}.\nFullness: {round(save.cat.fullness,1)}\nHappiness: {round(save.cat.happiness,1)}"
)
case "View your inventory":
print(f"Money: {save.player.money}")
if any(amount > 0 for amount in save.player.inventory.values()):
inventory.inventory(save)
else:
print("You have no items!")
case "Feed your cat": case "Feed your cat":
rules.reconcile(save.cat, time.time()) if not save.cat.sick:
rules.feed(save.cat) rules.reconcile(save.cat, time.time())
print(f"You feed {save.cat.name}, {save.cat.name} is now full.") if rules.feed(save.player, save.cat):
print(
f"You feed {save.cat.name}, {save.cat.name} is now {round(save.cat.fullness,1)}% full."
)
else:
print("You don't have any food!")
else:
print(f"{save.cat.name} is sick!")
case "Pet your cat": case "Pet your cat":
rules.reconcile(save.cat, time.time()) if not save.cat.depressed:
rules.excite(save.cat) rules.reconcile(save.cat, time.time())
print(f"You pet {save.cat.name}, {save.cat.name} is now happy.") pet.pet(save.cat)
else:
print(f"{save.cat.name} is depressed!")
case "Go to...":
go_to(save)
case "Menu": case "Menu":
result = options() result = options()
match result: match result:

View File

@@ -0,0 +1,77 @@
import time
from untitled import rules, ui
def use_medicine(save):
match ui.select(
"What do you want to do with the medicine?",
[f"Give to {save.cat.name}", "Back"],
):
case "Back":
return True # keep in inventory menu
case give if give == f"Give to {save.cat.name}":
if save.cat.sick:
rules.reconcile(save.cat, time.time())
if save.player.inventory["medicine"] > 0:
rules.cure_sick(save)
print(
f"You give {save.cat.name} the medicine. They start to feel better. You should probably still feed them."
)
else:
print(
"You don't have any medicine! (what?) (you shouldn't see this)"
)
return False
else:
print(f"{save.cat.name} isn't sick!")
return False
return False
def use_catnip(save):
match ui.select(
"What do you want to do with the catnip?",
[f"Give to {save.cat.name}", "Back"],
):
case "Back":
return True # keep in inventory menu
case give if give == f"Give to {save.cat.name}":
if save.cat.depressed:
rules.reconcile(save.cat, time.time())
if save.player.inventory["catnip"] > 0:
rules.cure_depressed(save)
print(
f"You give {save.cat.name} the catnip. They begin to feel happier. You should probably still pet them."
)
else:
print("You don't have any catnip! (what?) (you shouldn't see this)")
return False
else:
print(f"{save.cat.name} isn't depressed!")
return False
return False
def inventory(save):
while True:
item = ui.select(
"Please choose an item:",
[
item.capitalize()
for item in save.player.inventory
if save.player.inventory[item] > 0 and item != "food" # in main program
]
+ ["Cancel"],
)
if item == "Cancel":
return
match item:
case "Medicine":
stay = use_medicine(save)
case "Catnip":
stay = use_catnip(save)
case _:
stay = False
if not stay:
break

64
untitled/screens/pet.py Normal file
View File

@@ -0,0 +1,64 @@
from untitled import rules, ui
def pet(cat):
if cat.happiness == 100:
print("Your cat is already fully happy! They don't want any more pets.")
return
original_happiness = cat.happiness
print(f"Mash keys to pet {cat.name}, press enter when you're done.")
count = 0
last = None
print("\rPets: 0", end="", flush=True)
while True:
if count < 100000:
key = ui.getch()
if key in ("\r", "\n"):
print()
break
if key != last:
count += 1
last = key
print(f"\rPets: {count}", end="", flush=True)
else:
rules.excite(cat, -5)
print(f"\n{cat.name} ran away to protect your hands")
print(
f"You lost 5% happiness due to stressing your cat. Before petting, your cat was {round(original_happiness,1)}% happy. You lost {round(original_happiness-cat.happiness,1)}% happiness. Your cat is now {round(cat.happiness,1)}% happy."
)
return
add_happiness = 0
if count == 0:
print("You didn't pet your cat at all.")
return
elif count < 50:
add_happiness = 5
print(f"You didn't pet your cat enough, {cat.name} wants more pets.")
elif count <= 200:
add_happiness = 15
print(f"You pet {cat.name} a lot, {cat.name} is happy.")
elif count <= 500:
add_happiness = 20
print(f"You pet {cat.name} a lot. {cat.name} is very happy.")
elif count <= 1000:
add_happiness = 20
print(f"You pet {cat.name} an absurd amount of times.")
elif count <= 10000:
add_happiness = 15
print(f"{cat.name} has had enough pets.")
elif count <= 20000:
add_happiness = 10
print("What are you even doing at this point?")
elif count <= 50000:
add_happiness = 5
print("You should probably stop now.")
elif count <= 75000:
add_happiness = 2
print("Seriously. Stop.")
else:
add_happiness = 1
print(f"{cat.name} is getting extremely worried about your hands.")
rules.excite(cat, add_happiness)
print(
f"Your cat is now {round(cat.happiness,1)}% happy. Before petting, your cat was {round(original_happiness,1)}% happy. You gained {round(cat.happiness-original_happiness,1)}% happiness."
)

29
untitled/screens/shop.py Normal file
View File

@@ -0,0 +1,29 @@
from untitled import content, model, rules, ui
def shop(save: model.Save):
print("Welcome to the shop!")
while True:
match ui.select("What do you want to do?", ["Buy items", "Leave"]):
case "Buy items":
while True:
print(f"You have ${save.player.money}.")
item = ui.select(
"Please choose an item to buy:",
[
ui.Choice(f"{item.capitalize()}: ${price}", (item, price))
for item, price in content.ITEMS.items()
]
+ ["Back"],
)
if item == "Back":
break
if ui.confirm(
f"Are you sure you want to buy {item[0]} for ${item[1]}?"
):
if rules.buy(save.player, item[0], item[1]):
print("Done!")
else:
print("You don't have enough money!")
case "Leave":
break

51
untitled/screens/work.py Normal file
View File

@@ -0,0 +1,51 @@
import random
import string
import time
from untitled import content, rules, ui
def work(save):
length = content.WORK_START_LETTERS
total_earned = 0
lost = False
print("Welcome to work!")
print("The rules:")
print(
"Each round, a string of letters will appear, when it says go, type them from memory. If you miss one, you lose, each round gets more money."
)
if not ui.confirm("Would you like to start?"):
return
for i in range(3, 0, -1):
print(i)
time.sleep(1)
ui.clear()
print("Start!")
while not lost:
seconds = 1 + (length * 0.5)
letters = random.choices(string.ascii_lowercase, k=length)
print(f"Round {len(letters)-1}")
print("Memorize:", " ".join(letters))
for i in range(round(seconds), 0, -1):
print(i)
time.sleep(1)
ui.clear()
print(f"Round {len(letters)-1}")
print("Type!")
for letter in letters:
key = ui.getch().lower()
print(key, end=" ", flush=True)
if key != letter:
print(f"\nThe correct key was: {letter}")
lost = True
break
if not lost:
total_earned += content.WORK_EARN_PER_ROUND
print("\nCorrect!")
time.sleep(1)
ui.clear()
length += 1
rules.earn(save.player, total_earned)
print(
f"Game finished! You earned ${total_earned}, you now have ${save.player.money}!"
)

View File

@@ -1,3 +1,4 @@
import sys
import time import time
import questionary import questionary
@@ -46,3 +47,21 @@ def text(title, default):
def confirm(title): def confirm(title):
return questionary.confirm(title).ask() return questionary.confirm(title).ask()
def getch():
if sys.platform == "win32":
import msvcrt
return msvcrt.getwch()
else:
import termios
import tty
fd = sys.stdin.fileno()
old = termios.tcgetattr(fd)
try:
tty.setcbreak(fd)
return sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old)