Fix race conditions, add look feature
parent
138a981c3f
commit
bd56dd38a4
134
botany.py
134
botany.py
|
@ -3,7 +3,8 @@ import time
|
||||||
import pickle
|
import pickle
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
import os.path
|
import sys
|
||||||
|
import os
|
||||||
import random
|
import random
|
||||||
import getpass
|
import getpass
|
||||||
import threading
|
import threading
|
||||||
|
@ -15,16 +16,11 @@ from menu_screen import *
|
||||||
# development plan
|
# development plan
|
||||||
|
|
||||||
# build plant lifecycle just stepping through
|
# build plant lifecycle just stepping through
|
||||||
# - What else should it do during life? growth alone is not all that
|
|
||||||
# interesting.
|
|
||||||
# - how long should each stage last ? thinking realistic lmao
|
# - how long should each stage last ? thinking realistic lmao
|
||||||
# seed -> seedling -> sprout -> young plant -> mature plant -> flower ->
|
# seed -> seedling -> sprout -> young plant -> mature plant -> flower ->
|
||||||
# pollination -> fruit -> seeds
|
# pollination -> fruit -> seeds
|
||||||
# - TODO: pollination and end of life
|
# - TODO: pollination and end of life
|
||||||
#
|
#
|
||||||
# interaction
|
|
||||||
# - look at plant, how do you feel? (also gets rid of pests)
|
|
||||||
#
|
|
||||||
# events
|
# events
|
||||||
# - heatwave
|
# - heatwave
|
||||||
# - rain
|
# - rain
|
||||||
|
@ -39,11 +35,11 @@ from menu_screen import *
|
||||||
# - create rarer species by diff gens
|
# - create rarer species by diff gens
|
||||||
# - if neighbor plant dies, node will be removed from list
|
# - if neighbor plant dies, node will be removed from list
|
||||||
#
|
#
|
||||||
# garden system
|
|
||||||
# - can plant your plant in the garden to start a new plant
|
|
||||||
|
|
||||||
# build ascii trees
|
# build ascii trees
|
||||||
|
|
||||||
|
# Make it fun to keep growing after seed level (what is reward for continuing
|
||||||
|
# instead of starting over?
|
||||||
|
# Reward for bringing plant to full life - second gen plant w/ more variety
|
||||||
|
|
||||||
class Plant(object):
|
class Plant(object):
|
||||||
# This is your plant!
|
# This is your plant!
|
||||||
|
@ -140,6 +136,9 @@ class Plant(object):
|
||||||
def __init__(self, this_filename):
|
def __init__(self, this_filename):
|
||||||
# Constructor
|
# Constructor
|
||||||
self.plant_id = str(uuid.uuid4())
|
self.plant_id = str(uuid.uuid4())
|
||||||
|
# TODO: change from debug
|
||||||
|
self.life_stages = (10, 20, 30, 40, 50)
|
||||||
|
# self.life_stages = (3600, (3600*24)*3, (3600*24)*10, (3600*24)*20, (3600*24)*30)
|
||||||
self.stage = 0
|
self.stage = 0
|
||||||
self.mutation = 0
|
self.mutation = 0
|
||||||
self.species = random.randint(0,len(self.species_dict)-1)
|
self.species = random.randint(0,len(self.species_dict)-1)
|
||||||
|
@ -148,6 +147,7 @@ class Plant(object):
|
||||||
self.ticks = 0
|
self.ticks = 0
|
||||||
self.age_formatted = "0"
|
self.age_formatted = "0"
|
||||||
self.dead = False
|
self.dead = False
|
||||||
|
self.write_lock = False
|
||||||
self.owner = getpass.getuser()
|
self.owner = getpass.getuser()
|
||||||
self.file_name = this_filename
|
self.file_name = this_filename
|
||||||
self.start_time = int(time.time())
|
self.start_time = int(time.time())
|
||||||
|
@ -157,9 +157,20 @@ class Plant(object):
|
||||||
# self.watered_timestamp = int(time.time()) # debug
|
# self.watered_timestamp = int(time.time()) # debug
|
||||||
self.watered_24h = False
|
self.watered_24h = False
|
||||||
|
|
||||||
def new_seed(self,this_filename):
|
def parse_plant(self):
|
||||||
# Creates life after death
|
# reads plant info (maybe want to reorg this into a different class
|
||||||
self.__init__(this_filename)
|
# with the reader dicts...)
|
||||||
|
output = ""
|
||||||
|
if self.stage >= 3:
|
||||||
|
output += self.rarity_dict[self.rarity] + " "
|
||||||
|
if self.mutation != 0:
|
||||||
|
output += self.mutation_dict[self.mutation] + " "
|
||||||
|
if self.stage >= 4:
|
||||||
|
output += self.color_dict[self.color] + " "
|
||||||
|
output += self.stage_dict[self.stage] + " "
|
||||||
|
if self.stage >= 2:
|
||||||
|
output += self.species_dict[self.species] + " "
|
||||||
|
return output.strip()
|
||||||
|
|
||||||
def rarity_check(self):
|
def rarity_check(self):
|
||||||
# Generate plant rarity
|
# Generate plant rarity
|
||||||
|
@ -189,23 +200,6 @@ class Plant(object):
|
||||||
rarity = 4
|
rarity = 4
|
||||||
return rarity
|
return rarity
|
||||||
|
|
||||||
def growth(self):
|
|
||||||
# Increase plant growth stage
|
|
||||||
if self.stage < (len(self.stage_dict)-1):
|
|
||||||
self.stage += 1
|
|
||||||
# do stage growth stuff
|
|
||||||
else:
|
|
||||||
# do stage 5 stuff (after fruiting)
|
|
||||||
1==1
|
|
||||||
|
|
||||||
def water(self):
|
|
||||||
# Increase plant growth stage
|
|
||||||
# TODO: overwatering? if more than once a day it dies?
|
|
||||||
if not self.dead:
|
|
||||||
self.watered_timestamp = int(time.time())
|
|
||||||
self.watered_24h = True
|
|
||||||
|
|
||||||
|
|
||||||
def dead_check(self):
|
def dead_check(self):
|
||||||
time_delta_watered = int(time.time()) - self.watered_timestamp
|
time_delta_watered = int(time.time()) - self.watered_timestamp
|
||||||
# if it has been >5 days since watering, sorry plant is dead :(
|
# if it has been >5 days since watering, sorry plant is dead :(
|
||||||
|
@ -213,9 +207,6 @@ class Plant(object):
|
||||||
self.dead = True
|
self.dead = True
|
||||||
return self.dead
|
return self.dead
|
||||||
|
|
||||||
def kill_plant(self):
|
|
||||||
self.dead = True
|
|
||||||
|
|
||||||
def water_check(self):
|
def water_check(self):
|
||||||
# if plant has been watered in 24h then it keeps growing
|
# if plant has been watered in 24h then it keeps growing
|
||||||
# time_delta_watered is difference from now to last watered
|
# time_delta_watered is difference from now to last watered
|
||||||
|
@ -230,7 +221,7 @@ class Plant(object):
|
||||||
# Create plant mutation
|
# Create plant mutation
|
||||||
# TODO: when out of debug this needs to be set to high number (1000
|
# TODO: when out of debug this needs to be set to high number (1000
|
||||||
# even maybe)
|
# even maybe)
|
||||||
CONST_MUTATION_RARITY = 10 # Increase this # to make mutation rarer (chance 1 out of x)
|
CONST_MUTATION_RARITY = 2000 # Increase this # to make mutation rarer (chance 1 out of x)
|
||||||
mutation_seed = random.randint(1,CONST_MUTATION_RARITY)
|
mutation_seed = random.randint(1,CONST_MUTATION_RARITY)
|
||||||
if mutation_seed == CONST_MUTATION_RARITY:
|
if mutation_seed == CONST_MUTATION_RARITY:
|
||||||
# mutation gained!
|
# mutation gained!
|
||||||
|
@ -241,20 +232,39 @@ class Plant(object):
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def parse_plant(self):
|
def new_seed(self,this_filename):
|
||||||
# reads plant info (maybe want to reorg this into a different class
|
# Creates life after death
|
||||||
# with the reader dicts...)
|
self.__init__(this_filename)
|
||||||
output = ""
|
|
||||||
if self.stage >= 3:
|
def growth(self):
|
||||||
output += self.rarity_dict[self.rarity] + " "
|
# Increase plant growth stage
|
||||||
if self.mutation != 0:
|
if self.stage < (len(self.stage_dict)-1):
|
||||||
output += self.mutation_dict[self.mutation] + " "
|
self.stage += 1
|
||||||
if self.stage >= 4:
|
# do stage growth stuff
|
||||||
output += self.color_dict[self.color] + " "
|
else:
|
||||||
output += self.stage_dict[self.stage] + " "
|
# do stage 5 stuff (after fruiting)
|
||||||
if self.stage >= 2:
|
1==1
|
||||||
output += self.species_dict[self.species] + " "
|
|
||||||
return output.strip()
|
def water(self):
|
||||||
|
# Increase plant growth stage
|
||||||
|
if not self.dead:
|
||||||
|
self.watered_timestamp = int(time.time())
|
||||||
|
self.watered_24h = True
|
||||||
|
|
||||||
|
def start_over(self):
|
||||||
|
self.write_lock = True
|
||||||
|
self.kill_plant()
|
||||||
|
while self.write_lock:
|
||||||
|
# Wait for garden writer to unlock
|
||||||
|
1==1
|
||||||
|
if not self.write_lock:
|
||||||
|
self.new_seed(self.file_name)
|
||||||
|
|
||||||
|
def kill_plant(self):
|
||||||
|
self.dead = True
|
||||||
|
|
||||||
|
def unlock_new_creation(self):
|
||||||
|
self.write_lock = False
|
||||||
|
|
||||||
def start_life(self):
|
def start_life(self):
|
||||||
# runs life on a thread
|
# runs life on a thread
|
||||||
|
@ -265,7 +275,7 @@ class Plant(object):
|
||||||
def life(self):
|
def life(self):
|
||||||
# I've created life :)
|
# I've created life :)
|
||||||
# TODO: change out of debug
|
# TODO: change out of debug
|
||||||
life_stages = (5, 15, 30, 45, 60)
|
# TODO: variable stages of life
|
||||||
# day = 3600*24
|
# day = 3600*24
|
||||||
# life_stages = (1*day, 2*day, 3*day, 4*day, 5*day)
|
# life_stages = (1*day, 2*day, 3*day, 4*day, 5*day)
|
||||||
# leave this untouched bc it works for now
|
# leave this untouched bc it works for now
|
||||||
|
@ -275,7 +285,7 @@ class Plant(object):
|
||||||
if self.watered_24h:
|
if self.watered_24h:
|
||||||
self.ticks += 1
|
self.ticks += 1
|
||||||
if self.stage < len(self.stage_dict)-1:
|
if self.stage < len(self.stage_dict)-1:
|
||||||
if self.ticks >= life_stages[self.stage]:
|
if self.ticks >= self.life_stages[self.stage]:
|
||||||
self.growth()
|
self.growth()
|
||||||
if self.mutate_check():
|
if self.mutate_check():
|
||||||
1==1
|
1==1
|
||||||
|
@ -299,6 +309,8 @@ class DataManager(object):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.this_user = getpass.getuser()
|
self.this_user = getpass.getuser()
|
||||||
|
# check if instance is already running
|
||||||
|
self.lock_file()
|
||||||
# check for .botany dir in home
|
# check for .botany dir in home
|
||||||
try:
|
try:
|
||||||
os.makedirs(self.botany_dir)
|
os.makedirs(self.botany_dir)
|
||||||
|
@ -307,6 +319,19 @@ class DataManager(object):
|
||||||
raise
|
raise
|
||||||
self.savefile_name = self.this_user + '_plant.dat'
|
self.savefile_name = self.this_user + '_plant.dat'
|
||||||
|
|
||||||
|
def lock_file(self):
|
||||||
|
# Only allow one instance of game
|
||||||
|
pid = str(os.getpid())
|
||||||
|
this_filename = "instance.lock"
|
||||||
|
self.pid_file_path = os.path.join(self.botany_dir,this_filename)
|
||||||
|
if os.path.isfile(self.pid_file_path):
|
||||||
|
print "botany already running, exiting. (pid %s)" % pid
|
||||||
|
sys.exit()
|
||||||
|
file(self.pid_file_path, 'w').write(pid)
|
||||||
|
|
||||||
|
def clear_lock(self):
|
||||||
|
os.unlink(self.pid_file_path)
|
||||||
|
|
||||||
def check_plant(self):
|
def check_plant(self):
|
||||||
# check for existing save file
|
# check for existing save file
|
||||||
if os.path.isfile(self.savefile_path):
|
if os.path.isfile(self.savefile_path):
|
||||||
|
@ -333,6 +358,7 @@ class DataManager(object):
|
||||||
self.save_plant(this_plant)
|
self.save_plant(this_plant)
|
||||||
self.data_write_json(this_plant)
|
self.data_write_json(this_plant)
|
||||||
self.garden_update(this_plant)
|
self.garden_update(this_plant)
|
||||||
|
this_plant.unlock_new_creation()
|
||||||
time.sleep(.1)
|
time.sleep(.1)
|
||||||
|
|
||||||
def autosave(self, this_plant):
|
def autosave(self, this_plant):
|
||||||
|
@ -379,7 +405,6 @@ class DataManager(object):
|
||||||
def garden_update(self, this_plant):
|
def garden_update(self, this_plant):
|
||||||
# garden is a dict of dicts
|
# garden is a dict of dicts
|
||||||
# garden contains one entry for each plant id
|
# garden contains one entry for each plant id
|
||||||
|
|
||||||
age_formatted = self.plant_age_convert(this_plant)
|
age_formatted = self.plant_age_convert(this_plant)
|
||||||
this_plant_id = this_plant.plant_id
|
this_plant_id = this_plant.plant_id
|
||||||
plant_info = {
|
plant_info = {
|
||||||
|
@ -408,7 +433,7 @@ class DataManager(object):
|
||||||
# if plant ticks for id is greater than current ticks of plant id
|
# if plant ticks for id is greater than current ticks of plant id
|
||||||
else:
|
else:
|
||||||
current_plant_ticks = this_garden[this_plant_id]["score"]
|
current_plant_ticks = this_garden[this_plant_id]["score"]
|
||||||
if this_plant.ticks > current_plant_ticks:
|
if this_plant.ticks >= current_plant_ticks:
|
||||||
this_garden[this_plant_id] = plant_info
|
this_garden[this_plant_id] = plant_info
|
||||||
with open(self.garden_file_path, 'wb') as f:
|
with open(self.garden_file_path, 'wb') as f:
|
||||||
pickle.dump(this_garden, f, protocol=2)
|
pickle.dump(this_garden, f, protocol=2)
|
||||||
|
@ -444,9 +469,6 @@ class DataManager(object):
|
||||||
with open(json_file, 'w') as outfile:
|
with open(json_file, 'w') as outfile:
|
||||||
json.dump(plant_info, outfile)
|
json.dump(plant_info, outfile)
|
||||||
|
|
||||||
# update leaderboard 'garden' for display in game
|
|
||||||
# also should be a pickle file bc... let's be honest ppl want to cheat
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
my_data = DataManager()
|
my_data = DataManager()
|
||||||
# if plant save file exists
|
# if plant save file exists
|
||||||
|
@ -454,13 +476,13 @@ if __name__ == '__main__':
|
||||||
my_plant = my_data.load_plant()
|
my_plant = my_data.load_plant()
|
||||||
# otherwise create new plant
|
# otherwise create new plant
|
||||||
else:
|
else:
|
||||||
#TODO: onboarding, select seed, select whatever else
|
|
||||||
my_plant = Plant(my_data.savefile_path)
|
my_plant = Plant(my_data.savefile_path)
|
||||||
my_data.data_write_json(my_plant)
|
my_data.data_write_json(my_plant)
|
||||||
my_plant.start_life()
|
my_plant.start_life()
|
||||||
my_data.start_threads(my_plant)
|
my_data.start_threads(my_plant)
|
||||||
botany_menu = CursedMenu(my_plant,my_data.garden_file_path)
|
botany_menu = CursedMenu(my_plant,my_data.garden_file_path)
|
||||||
botany_menu.show(["water","look","garden","instructions"], title=' botany ', subtitle='options')
|
botany_menu.show(["water","look","garden","instructions"], title=' botany ', subtitle='options')
|
||||||
my_data.save_plant(my_plant)
|
my_data.save_plant(my_plant)
|
||||||
my_data.data_write_json(my_plant)
|
my_data.data_write_json(my_plant)
|
||||||
my_data.garden_update(my_plant)
|
my_data.garden_update(my_plant)
|
||||||
|
my_data.clear_lock()
|
||||||
|
|
274
menu_screen.py
274
menu_screen.py
|
@ -1,7 +1,8 @@
|
||||||
import curses, os, traceback, threading, time, datetime, pickle
|
import curses, os, traceback, threading, time, datetime, pickle, operator, random
|
||||||
|
|
||||||
class CursedMenu(object):
|
class CursedMenu(object):
|
||||||
#TODO: create a side panel with log of events..?
|
#TODO: create a side panel with log of events..?
|
||||||
|
#TODO: name your plant
|
||||||
'''A class which abstracts the horrors of building a curses-based menu system'''
|
'''A class which abstracts the horrors of building a curses-based menu system'''
|
||||||
def __init__(self, this_plant, this_garden_file_path):
|
def __init__(self, this_plant, this_garden_file_path):
|
||||||
'''Initialization'''
|
'''Initialization'''
|
||||||
|
@ -18,14 +19,14 @@ class CursedMenu(object):
|
||||||
self.plant_ticks = str(self.plant.ticks)
|
self.plant_ticks = str(self.plant.ticks)
|
||||||
self.exit = False
|
self.exit = False
|
||||||
self.instructiontoggle = False
|
self.instructiontoggle = False
|
||||||
#TODO: debugging
|
|
||||||
# self.gardenmenutoggle = True
|
|
||||||
self.gardenmenutoggle = False
|
self.gardenmenutoggle = False
|
||||||
|
self.looktoggle = False
|
||||||
self.maxy, self.maxx = self.screen.getmaxyx()
|
self.maxy, self.maxx = self.screen.getmaxyx()
|
||||||
# Highlighted and Normal line definitions
|
# Highlighted and Normal line definitions
|
||||||
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE)
|
||||||
self.highlighted = curses.color_pair(1)
|
self.highlighted = curses.color_pair(1)
|
||||||
self.normal = curses.A_NORMAL
|
self.normal = curses.A_NORMAL
|
||||||
|
# Threaded screen update for live changes
|
||||||
screen_thread = threading.Thread(target=self.update_plant_live, args=())
|
screen_thread = threading.Thread(target=self.update_plant_live, args=())
|
||||||
screen_thread.daemon = True
|
screen_thread.daemon = True
|
||||||
screen_thread.start()
|
screen_thread.start()
|
||||||
|
@ -44,16 +45,18 @@ class CursedMenu(object):
|
||||||
def update_options(self):
|
def update_options(self):
|
||||||
# Makes sure you can get a new plant if it dies
|
# Makes sure you can get a new plant if it dies
|
||||||
if self.plant.dead:
|
if self.plant.dead:
|
||||||
if "kill" in self.options:
|
# if "start over" in self.options:
|
||||||
self.options.remove("kill")
|
# self.options.remove("start over")
|
||||||
if "new" not in self.options:
|
if "start over" not in self.options:
|
||||||
self.options.insert(-1,"new")
|
self.options.insert(-1,"start over")
|
||||||
else:
|
else:
|
||||||
# TODO: remove after debug or bury in settings
|
# TODO: remove after debug or bury in settings
|
||||||
if "new" in self.options:
|
if self.plant.stage == 5:
|
||||||
self.options.remove("new")
|
if "start over" not in self.options:
|
||||||
if "kill" not in self.options:
|
self.options.insert(-1,"start over")
|
||||||
self.options.insert(-1,"kill")
|
else:
|
||||||
|
if "start over" in self.options:
|
||||||
|
self.options.remove("start over")
|
||||||
|
|
||||||
def set_options(self, options):
|
def set_options(self, options):
|
||||||
# Validates that the last option is "exit"
|
# Validates that the last option is "exit"
|
||||||
|
@ -61,6 +64,22 @@ class CursedMenu(object):
|
||||||
options.append('exit')
|
options.append('exit')
|
||||||
self.options = options
|
self.options = options
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
# Draw the menu and lines
|
||||||
|
# TODO: this needs to either display the default menu screen or the
|
||||||
|
# garden/leaderboard thing based on self.gardenmenutoggle
|
||||||
|
# TODO: display refresh is hacky. Could be more precise
|
||||||
|
self.screen.refresh()
|
||||||
|
self.screen.border(0)
|
||||||
|
try:
|
||||||
|
self.draw_default()
|
||||||
|
self.screen.refresh()
|
||||||
|
except Exception as exception:
|
||||||
|
# Makes sure data is saved in event of a crash due to window resizing
|
||||||
|
self.screen.addstr(0,0,"Enlarge terminal!")
|
||||||
|
self.__exit__()
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
def draw_menu(self):
|
def draw_menu(self):
|
||||||
# Actually draws the menu and handles branching
|
# Actually draws the menu and handles branching
|
||||||
request = ""
|
request = ""
|
||||||
|
@ -81,6 +100,9 @@ class CursedMenu(object):
|
||||||
clear_bar = " " * (int(self.maxx*2/3))
|
clear_bar = " " * (int(self.maxx*2/3))
|
||||||
self.screen.addstr(2,2, self.title, curses.A_STANDOUT) # Title for this menu
|
self.screen.addstr(2,2, self.title, curses.A_STANDOUT) # Title for this menu
|
||||||
self.screen.addstr(4,2, self.subtitle, curses.A_BOLD) #Subtitle for this menu
|
self.screen.addstr(4,2, self.subtitle, curses.A_BOLD) #Subtitle for this menu
|
||||||
|
# Clear menu on screen
|
||||||
|
for index in range(len(self.options)+1):
|
||||||
|
self.screen.addstr(5+index,4, clear_bar, curses.A_NORMAL)
|
||||||
# Display all the menu items, showing the 'pos' item highlighted
|
# Display all the menu items, showing the 'pos' item highlighted
|
||||||
for index in range(len(self.options)):
|
for index in range(len(self.options)):
|
||||||
textstyle = self.normal
|
textstyle = self.normal
|
||||||
|
@ -104,62 +126,6 @@ class CursedMenu(object):
|
||||||
self.screen.addstr(5,13, clear_bar, curses.A_NORMAL)
|
self.screen.addstr(5,13, clear_bar, curses.A_NORMAL)
|
||||||
self.screen.addstr(5,13, " - you can't water a dead plant :(", curses.A_NORMAL)
|
self.screen.addstr(5,13, " - you can't water a dead plant :(", curses.A_NORMAL)
|
||||||
|
|
||||||
def format_garden_data(self,this_garden):
|
|
||||||
plant_table = ""
|
|
||||||
# TODO: include only live plants maybe
|
|
||||||
for plant_id in this_garden:
|
|
||||||
if this_garden[plant_id]:
|
|
||||||
if not this_garden[plant_id]["dead"]:
|
|
||||||
this_plant = this_garden[plant_id]
|
|
||||||
plant_table += this_plant["owner"] + " - "
|
|
||||||
plant_table += this_plant["age"] + " - "
|
|
||||||
plant_table += this_plant["description"] + " - "
|
|
||||||
plant_table += str(this_plant["score"]) + "\n"
|
|
||||||
return plant_table
|
|
||||||
|
|
||||||
def draw_garden(self):
|
|
||||||
# Draws neighborhood
|
|
||||||
clear_bar = " " * (self.maxx-2) + "\n"
|
|
||||||
control_keys = [curses.KEY_UP, curses.KEY_DOWN, curses.KEY_LEFT, curses.KEY_RIGHT]
|
|
||||||
# load data
|
|
||||||
with open(self.garden_file_path, 'rb') as f:
|
|
||||||
this_garden = pickle.load(f)
|
|
||||||
# format data
|
|
||||||
if not self.gardenmenutoggle:
|
|
||||||
plant_table_formatted = self.format_garden_data(this_garden)
|
|
||||||
self.gardenmenutoggle = not self.gardenmenutoggle
|
|
||||||
else:
|
|
||||||
plant_table_formatted = ""
|
|
||||||
for plant in this_garden:
|
|
||||||
if not this_garden[plant]["dead"]:
|
|
||||||
plant_table_formatted += clear_bar
|
|
||||||
self.gardenmenutoggle = not self.gardenmenutoggle
|
|
||||||
|
|
||||||
for y, line in enumerate(plant_table_formatted.splitlines(), 2):
|
|
||||||
self.screen.addstr(y+12, 2, line)
|
|
||||||
self.screen.refresh()
|
|
||||||
|
|
||||||
def draw(self):
|
|
||||||
# Draw the menu and lines
|
|
||||||
# TODO: this needs to either display the default menu screen or the
|
|
||||||
# garden/leaderboard thing based on self.gardenmenutoggle
|
|
||||||
# TODO: display refresh is hacky. Could be more precise
|
|
||||||
self.screen.refresh()
|
|
||||||
self.screen.border(0)
|
|
||||||
# TODO: separate screen for garden menu, interactive
|
|
||||||
# if self.gardenmenutoggle:
|
|
||||||
# self.draw_garden()
|
|
||||||
# else:
|
|
||||||
# self.draw_default()
|
|
||||||
try:
|
|
||||||
self.draw_default()
|
|
||||||
self.screen.refresh()
|
|
||||||
except Exception as exception:
|
|
||||||
# Makes sure data is saved in event of a crash due to window resizing
|
|
||||||
self.screen.addstr(0,0,"Enlarge terminal!")
|
|
||||||
self.__exit__()
|
|
||||||
traceback.print_exc()
|
|
||||||
|
|
||||||
def update_plant_live(self):
|
def update_plant_live(self):
|
||||||
# Updates plant data on menu screen, live!
|
# Updates plant data on menu screen, live!
|
||||||
# Will eventually use this to display ascii art...
|
# Will eventually use this to display ascii art...
|
||||||
|
@ -194,6 +160,167 @@ class CursedMenu(object):
|
||||||
self.selected = self.selected % len(self.options)
|
self.selected = self.selected % len(self.options)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def format_garden_data(self,this_garden):
|
||||||
|
|
||||||
|
plant_table = ""
|
||||||
|
for plant_id in this_garden:
|
||||||
|
if this_garden[plant_id]:
|
||||||
|
if not this_garden[plant_id]["dead"]:
|
||||||
|
this_plant = this_garden[plant_id]
|
||||||
|
plant_table += this_plant["owner"] + " - "
|
||||||
|
plant_table += this_plant["age"] + " - "
|
||||||
|
plant_table += str(this_plant["score"]) + " points - "
|
||||||
|
plant_table += this_plant["description"] + "\n"
|
||||||
|
return plant_table
|
||||||
|
|
||||||
|
def draw_garden(self):
|
||||||
|
# Draws neighborhood
|
||||||
|
clear_bar = " " * (self.maxx-2) + "\n"
|
||||||
|
control_keys = [curses.KEY_UP, curses.KEY_DOWN, curses.KEY_LEFT, curses.KEY_RIGHT]
|
||||||
|
# load data
|
||||||
|
with open(self.garden_file_path, 'rb') as f:
|
||||||
|
this_garden = pickle.load(f)
|
||||||
|
# format data
|
||||||
|
if not self.gardenmenutoggle:
|
||||||
|
plant_table_formatted = self.format_garden_data(this_garden)
|
||||||
|
self.gardenmenutoggle = not self.gardenmenutoggle
|
||||||
|
else:
|
||||||
|
plant_table_formatted = clear_bar
|
||||||
|
for plant in this_garden:
|
||||||
|
if not this_garden[plant]["dead"]:
|
||||||
|
plant_table_formatted += clear_bar
|
||||||
|
self.gardenmenutoggle = not self.gardenmenutoggle
|
||||||
|
|
||||||
|
for y, line in enumerate(plant_table_formatted.splitlines(), 2):
|
||||||
|
self.screen.addstr(y+17, 2, line)
|
||||||
|
self.screen.refresh()
|
||||||
|
|
||||||
|
def get_plant_description(self, this_plant):
|
||||||
|
1==1
|
||||||
|
output_text = ""
|
||||||
|
this_species = this_plant.species_dict[this_plant.species]
|
||||||
|
this_color = this_plant.color_dict[this_plant.color]
|
||||||
|
this_stage = this_plant.stage
|
||||||
|
|
||||||
|
stage_descriptions = {
|
||||||
|
0:[
|
||||||
|
"You're excited about your new seed.",
|
||||||
|
"You wonder what kind of plant your seed will grow into.",
|
||||||
|
"You're ready for a new start with this plant.",
|
||||||
|
"You're tired of waiting for your seed to grow.",
|
||||||
|
"You wish your seed could tell you what it needs.",
|
||||||
|
],
|
||||||
|
1:[
|
||||||
|
"The seedling fills you with hope.",
|
||||||
|
"You can make out a tiny leaf - or is that a thorn?",
|
||||||
|
"You can feel the seedling looking back at you.",
|
||||||
|
"You kiss your seedling good night.",
|
||||||
|
"You think about all the seedlings who came before it.",
|
||||||
|
"You and your seedling make a great team.",
|
||||||
|
],
|
||||||
|
2:[
|
||||||
|
"The " + this_species + " makes you feel relaxed.",
|
||||||
|
"You sing a song to your " + this_species + ".",
|
||||||
|
"You quietly sit with your " + this_species + " for a few minutes.",
|
||||||
|
"Your " + this_species + " looks pretty good.",
|
||||||
|
"You play loud techno to your " + this_species + ".",
|
||||||
|
],
|
||||||
|
3:[
|
||||||
|
"Your " + this_species + " is growing nicely!",
|
||||||
|
"You're proud of the dedication it took to grow your " + this_species + ".",
|
||||||
|
"The " + this_species + " looks good.",
|
||||||
|
"You think how good this " + this_species + " would look on steroids.",
|
||||||
|
"The buds of your " + this_species + " are about to bloom.",
|
||||||
|
],
|
||||||
|
4:[
|
||||||
|
"The " + this_color + " flowers look nice on your " + this_species +"!",
|
||||||
|
"The " + this_color + " flowers have bloomed and fill you with desire.",
|
||||||
|
"The " + this_color + " flowers of your " + this_species + " remind you of your childhood.",
|
||||||
|
"The " + this_species + " has grown beautiful " + this_color + " flowers.",
|
||||||
|
"The " + this_color + " petals remind you of your favorite shirt.",
|
||||||
|
],
|
||||||
|
5:[
|
||||||
|
"You fondly remember all of the time you spent caring for your " + this_species + ".",
|
||||||
|
"Your " + this_species + " looks old and wise.",
|
||||||
|
"Seed pods have grown on your " + this_species + ".",
|
||||||
|
"The " + this_species + " fills you with love.",
|
||||||
|
"The " + this_species + " reminds you of your first crush.",
|
||||||
|
],
|
||||||
|
99:[
|
||||||
|
"You wish you had taken better care of your plant.",
|
||||||
|
"If only you had watered your plant more often..",
|
||||||
|
"Your plant is dead, there's always next time.",
|
||||||
|
"You cry over the withered leaves of your plant.",
|
||||||
|
"Your plant died. Maybe you need a fresh start.",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
# self.life_stages is tuple containing length of each stage
|
||||||
|
# (seed, seedling, young, mature, flowering)
|
||||||
|
# if stage == 0 == seed
|
||||||
|
if this_plant.dead:
|
||||||
|
this_stage = 99
|
||||||
|
|
||||||
|
this_stage_descriptions = stage_descriptions[this_stage]
|
||||||
|
description_num = random.randint(0,len(this_stage_descriptions) - 1)
|
||||||
|
if this_stage <= 4:
|
||||||
|
# Growth hint
|
||||||
|
if this_stage >= 1:
|
||||||
|
last_growth_at = this_plant.life_stages[this_stage - 1]
|
||||||
|
else:
|
||||||
|
last_growth_at = 0
|
||||||
|
ticks_since_last = this_plant.ticks - last_growth_at
|
||||||
|
ticks_between_stage = this_plant.life_stages[this_stage] - last_growth_at
|
||||||
|
if ticks_since_last >= ticks_between_stage * 0.8:
|
||||||
|
output_text += "You notice your plant looks different.\n"
|
||||||
|
|
||||||
|
output_text += this_stage_descriptions[description_num] + "\n"
|
||||||
|
|
||||||
|
# issue 1 - referencing anything past 4 on life stages breaks
|
||||||
|
# issue 2 - 80% using plant ticks doesn't really work since it shifts
|
||||||
|
# each time. need to use the difference between 2 stages, and then
|
||||||
|
# plant ticks minus last stage
|
||||||
|
|
||||||
|
if this_stage == 1:
|
||||||
|
species_options = [this_plant.species_dict[this_plant.species],
|
||||||
|
this_plant.species_dict[(this_plant.species+3) % len(this_plant.species_dict)],
|
||||||
|
this_plant.species_dict[(this_plant.species-3) % len(this_plant.species_dict)]]
|
||||||
|
random.shuffle(species_options)
|
||||||
|
plant_hint = "It could be a(n) " + species_options[0] + ", " + species_options[1] + ", or " + species_options[2]
|
||||||
|
output_text += plant_hint + ".\n"
|
||||||
|
|
||||||
|
if this_stage == 2:
|
||||||
|
# TODO: more descriptive rarity
|
||||||
|
if this_plant.rarity >= 2:
|
||||||
|
rarity_hint = "You feel like your plant is special."
|
||||||
|
output_text += rarity_hint + ".\n"
|
||||||
|
|
||||||
|
if this_stage == 3:
|
||||||
|
color_options = [this_plant.color_dict[this_plant.color],
|
||||||
|
this_plant.color_dict[(this_plant.color+3) % len(this_plant.color_dict)],
|
||||||
|
this_plant.color_dict[(this_plant.color-3) % len(this_plant.color_dict)]]
|
||||||
|
random.shuffle(color_options)
|
||||||
|
plant_hint = "You can see the first hints of " + color_options[0] + ", " + color_options[1] + ", or " + color_options[2]
|
||||||
|
output_text += plant_hint + ".\n"
|
||||||
|
|
||||||
|
return output_text
|
||||||
|
|
||||||
|
def draw_plant_description(self, this_plant):
|
||||||
|
clear_bar = " " * (self.maxx-2) + "\n"
|
||||||
|
control_keys = [curses.KEY_UP, curses.KEY_DOWN, curses.KEY_LEFT, curses.KEY_RIGHT]
|
||||||
|
# load data
|
||||||
|
# format data
|
||||||
|
if not self.looktoggle:
|
||||||
|
output_string = self.get_plant_description(this_plant)
|
||||||
|
self.looktoggle = not self.looktoggle
|
||||||
|
else:
|
||||||
|
output_string = clear_bar
|
||||||
|
output_string += clear_bar*3
|
||||||
|
self.looktoggle = not self.looktoggle
|
||||||
|
|
||||||
|
for y, line in enumerate(output_string.splitlines(), 2):
|
||||||
|
self.screen.addstr(y+12, 2, line)
|
||||||
|
self.screen.refresh()
|
||||||
|
|
||||||
def draw_instructions(self):
|
def draw_instructions(self):
|
||||||
if not self.instructiontoggle:
|
if not self.instructiontoggle:
|
||||||
instructions_txt = """welcome to botany. you've been given a seed
|
instructions_txt = """welcome to botany. you've been given a seed
|
||||||
|
@ -222,12 +349,17 @@ available in the readme :)
|
||||||
def handle_request(self, request):
|
def handle_request(self, request):
|
||||||
'''This is where you do things with the request'''
|
'''This is where you do things with the request'''
|
||||||
if request == None: return
|
if request == None: return
|
||||||
if request == "kill":
|
if request == "start over":
|
||||||
self.plant.kill_plant()
|
self.plant.start_over()
|
||||||
if request == "new":
|
|
||||||
self.plant.new_seed(self.plant.file_name)
|
|
||||||
if request == "water":
|
if request == "water":
|
||||||
self.plant.water()
|
self.plant.water()
|
||||||
|
if request == "look":
|
||||||
|
# try:
|
||||||
|
self.draw_plant_description(self.plant)
|
||||||
|
# except Exception as exception:
|
||||||
|
# self.screen.addstr(0,0,"Enlarge terminal!")
|
||||||
|
# self.__exit__()
|
||||||
|
# traceback.print_exc()
|
||||||
if request == "instructions":
|
if request == "instructions":
|
||||||
try:
|
try:
|
||||||
self.draw_instructions()
|
self.draw_instructions()
|
||||||
|
|
Loading…
Reference in New Issue