Paginate garden
parent
2fcdb01577
commit
8f99063b5b
|
@ -48,11 +48,13 @@ If your plant goes 5 days without water, it will die!
|
||||||
* ASCII art only shows first stage of growth - more coming soon!
|
* ASCII art only shows first stage of growth - more coming soon!
|
||||||
|
|
||||||
### to-dos
|
### to-dos
|
||||||
* Add day/night ASCII art
|
* Finish garden feature
|
||||||
* Finish garden display ('garden' function)
|
* Switch to database instead of .dat file
|
||||||
* Allows you to water neighbor's plants
|
* Allows you to water neighbor's plants
|
||||||
* Plant end of life (seeding/pollination)
|
* Harvest plant at end of life (gather seeds)
|
||||||
|
* Create harvest file with a log of all previous plants
|
||||||
* Plant pollination - cross-breed with neighbor plants to unlock second-gen plants
|
* Plant pollination - cross-breed with neighbor plants to unlock second-gen plants
|
||||||
|
* Share seeds with other users
|
||||||
* Global events
|
* Global events
|
||||||
* Server API to have rain storms, heat waves, insects
|
* Server API to have rain storms, heat waves, insects
|
||||||
* Name your plant
|
* Name your plant
|
||||||
|
|
44
botany.py
44
botany.py
|
@ -224,7 +224,7 @@ class Plant(object):
|
||||||
# Create plant mutation
|
# Create plant mutation
|
||||||
# TODO: when out of debug this needs to be set to high number
|
# TODO: when out of debug this needs to be set to high number
|
||||||
# Increase this # to make mutation rarer (chance 1 out of x each second)
|
# Increase this # to make mutation rarer (chance 1 out of x each second)
|
||||||
CONST_MUTATION_RARITY = 3000
|
CONST_MUTATION_RARITY = 5000
|
||||||
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!
|
||||||
|
@ -281,7 +281,6 @@ class Plant(object):
|
||||||
def life(self):
|
def life(self):
|
||||||
# I've created life :)
|
# I've created life :)
|
||||||
while True:
|
while True:
|
||||||
time.sleep(1)
|
|
||||||
if not self.dead:
|
if not self.dead:
|
||||||
if self.watered_24h:
|
if self.watered_24h:
|
||||||
self.ticks += 1
|
self.ticks += 1
|
||||||
|
@ -297,8 +296,11 @@ class Plant(object):
|
||||||
# Do something else
|
# Do something else
|
||||||
pass
|
pass
|
||||||
# TODO: event check
|
# TODO: event check
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
class DataManager(object):
|
class DataManager(object):
|
||||||
|
# TODO: garden file stuff has a race condition - need to find and
|
||||||
|
# eliminate it.
|
||||||
# handles user data, puts a .botany dir in user's home dir (OSX/Linux)
|
# handles user data, puts a .botany dir in user's home dir (OSX/Linux)
|
||||||
user_dir = os.path.expanduser("~")
|
user_dir = os.path.expanduser("~")
|
||||||
botany_dir = os.path.join(user_dir,'.botany')
|
botany_dir = os.path.join(user_dir,'.botany')
|
||||||
|
@ -309,6 +311,8 @@ class DataManager(object):
|
||||||
savefile_path = os.path.join(botany_dir, savefile_name)
|
savefile_path = os.path.join(botany_dir, savefile_name)
|
||||||
garden_file_path = os.path.join(game_dir, 'garden_file.dat')
|
garden_file_path = os.path.join(game_dir, 'garden_file.dat')
|
||||||
garden_json_path = os.path.join(game_dir, 'garden_file.json')
|
garden_json_path = os.path.join(game_dir, 'garden_file.json')
|
||||||
|
harvest_file_path = os.path.join(botany_dir, 'harvest_file.dat')
|
||||||
|
harvest_json_path = os.path.join(botany_dir, 'harvest_file.json')
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.this_user = getpass.getuser()
|
self.this_user = getpass.getuser()
|
||||||
|
@ -346,17 +350,16 @@ 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)
|
||||||
|
self.harvest_plant(this_plant)
|
||||||
this_plant.unlock_new_creation()
|
this_plant.unlock_new_creation()
|
||||||
time.sleep(.1)
|
time.sleep(.1)
|
||||||
|
|
||||||
def autosave(self, this_plant):
|
def autosave(self, this_plant):
|
||||||
# running on thread
|
# running on thread, saves plant every 5s
|
||||||
while True:
|
while True:
|
||||||
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)
|
||||||
# TODO: change after debug
|
|
||||||
#time.sleep(60)
|
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
def load_plant(self):
|
def load_plant(self):
|
||||||
|
@ -377,7 +380,6 @@ class DataManager(object):
|
||||||
else:
|
else:
|
||||||
ticks_to_add = 0
|
ticks_to_add = 0
|
||||||
this_plant.ticks += ticks_to_add
|
this_plant.ticks += ticks_to_add
|
||||||
|
|
||||||
return this_plant
|
return this_plant
|
||||||
|
|
||||||
def plant_age_convert(self,this_plant):
|
def plant_age_convert(self,this_plant):
|
||||||
|
@ -462,6 +464,35 @@ 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)
|
||||||
|
|
||||||
|
def harvest_plant(self, this_plant):
|
||||||
|
# harvest is a dict of dicts
|
||||||
|
# harvest contains one entry for each plant id
|
||||||
|
age_formatted = self.plant_age_convert(this_plant)
|
||||||
|
this_plant_id = this_plant.plant_id
|
||||||
|
plant_info = {
|
||||||
|
"description":this_plant.parse_plant(),
|
||||||
|
"age":age_formatted,
|
||||||
|
"score":this_plant.ticks,
|
||||||
|
}
|
||||||
|
if os.path.isfile(self.harvest_file_path):
|
||||||
|
# harvest file exists: load data
|
||||||
|
with open(self.harvest_file_path, 'rb') as f:
|
||||||
|
this_harvest = pickle.load(f)
|
||||||
|
new_file_check = False
|
||||||
|
else:
|
||||||
|
this_harvest = {}
|
||||||
|
new_file_check = True
|
||||||
|
this_harvest[this_plant_id] = plant_info
|
||||||
|
|
||||||
|
# dump harvest file
|
||||||
|
with open(self.harvest_file_path, 'wb') as f:
|
||||||
|
pickle.dump(this_harvest, f, protocol=2)
|
||||||
|
# dump json file
|
||||||
|
with open(self.harvest_json_path, 'w') as outfile:
|
||||||
|
json.dump(this_harvest, outfile)
|
||||||
|
|
||||||
|
return new_file_check
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
my_data = DataManager()
|
my_data = DataManager()
|
||||||
# if plant save file exists
|
# if plant save file exists
|
||||||
|
@ -474,6 +505,7 @@ if __name__ == '__main__':
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -45,16 +45,15 @@ 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 "start over" not in self.options:
|
if "harvest" not in self.options:
|
||||||
self.options.insert(-1,"start over")
|
self.options.insert(-1,"harvest")
|
||||||
else:
|
else:
|
||||||
# TODO: remove after debug or bury in settings
|
|
||||||
if self.plant.stage == 5:
|
if self.plant.stage == 5:
|
||||||
if "start over" not in self.options:
|
if "harvest" not in self.options:
|
||||||
self.options.insert(-1,"start over")
|
self.options.insert(-1,"harvest")
|
||||||
else:
|
else:
|
||||||
if "start over" in self.options:
|
if "harvest" in self.options:
|
||||||
self.options.remove("start over")
|
self.options.remove("harvest")
|
||||||
|
|
||||||
def set_options(self, options):
|
def set_options(self, options):
|
||||||
# Validates that the last option is "exit"
|
# Validates that the last option is "exit"
|
||||||
|
@ -228,7 +227,7 @@ class CursedMenu(object):
|
||||||
return
|
return
|
||||||
|
|
||||||
def format_garden_data(self,this_garden):
|
def format_garden_data(self,this_garden):
|
||||||
|
# Returns list of lists (pages) of garden entries
|
||||||
plant_table = ""
|
plant_table = ""
|
||||||
for plant_id in this_garden:
|
for plant_id in this_garden:
|
||||||
if this_garden[plant_id]:
|
if this_garden[plant_id]:
|
||||||
|
@ -238,7 +237,11 @@ class CursedMenu(object):
|
||||||
plant_table += this_plant["age"] + " - "
|
plant_table += this_plant["age"] + " - "
|
||||||
plant_table += str(this_plant["score"]) + "p - "
|
plant_table += str(this_plant["score"]) + "p - "
|
||||||
plant_table += this_plant["description"] + "\n"
|
plant_table += this_plant["description"] + "\n"
|
||||||
return plant_table
|
# build list of n entries per page
|
||||||
|
entries_per_page = self.maxy - 16
|
||||||
|
garden_list = plant_table.splitlines()
|
||||||
|
paginated_list = [garden_list[i:i+entries_per_page] for i in range(0,len(garden_list),entries_per_page)]
|
||||||
|
return paginated_list
|
||||||
|
|
||||||
def draw_garden(self):
|
def draw_garden(self):
|
||||||
# draws neighborhood
|
# draws neighborhood
|
||||||
|
@ -249,22 +252,47 @@ class CursedMenu(object):
|
||||||
with open(self.garden_file_path, 'rb') as f:
|
with open(self.garden_file_path, 'rb') as f:
|
||||||
this_garden = pickle.load(f)
|
this_garden = pickle.load(f)
|
||||||
# format data
|
# format data
|
||||||
|
plant_table_pages = []
|
||||||
if self.infotoggle != 2:
|
if self.infotoggle != 2:
|
||||||
|
# if infotoggle isn't 2, the screen currently displays other stuff
|
||||||
|
# we want to prep the screen for showing the garden
|
||||||
|
# Clear text area of other text (look info, etc) first
|
||||||
for y, line in enumerate(clear_block.splitlines(), 2):
|
for y, line in enumerate(clear_block.splitlines(), 2):
|
||||||
self.screen.addstr(y+12, 2, line)
|
self.screen.addstr(y+12, 2, line)
|
||||||
self.screen.refresh()
|
self.screen.refresh()
|
||||||
plant_table_formatted = self.format_garden_data(this_garden)
|
plant_table_pages = self.format_garden_data(this_garden)
|
||||||
self.infotoggle = 2
|
self.infotoggle = 2
|
||||||
else:
|
else:
|
||||||
plant_table_formatted = clear_bar
|
# the screen IS currently showing the garden (1 page), make the
|
||||||
for plant in this_garden:
|
# text a bunch of blanks to clear it out
|
||||||
if not this_garden[plant]["dead"]:
|
big_clear_block = clear_bar * (self.maxy - 14)
|
||||||
plant_table_formatted += clear_bar
|
plant_table_pages.append(big_clear_block.splitlines())
|
||||||
self.infotoggle = 0
|
self.infotoggle = 0
|
||||||
|
|
||||||
for y, line in enumerate(plant_table_formatted.splitlines(), 2):
|
# print garden information OR clear it
|
||||||
self.screen.addstr(y+12, 2, line)
|
for page_num, page in enumerate(plant_table_pages, 1):
|
||||||
self.screen.refresh()
|
# Print page text
|
||||||
|
for y, line in enumerate(page, 2):
|
||||||
|
self.screen.addstr(y+12, 2, line)
|
||||||
|
if len(plant_table_pages) > 1:
|
||||||
|
# Multiple pages, paginate and require keypress
|
||||||
|
page_text = " --- press any key --- (%d/%d)" % (page_num, len(plant_table_pages))
|
||||||
|
self.screen.addstr(self.maxy-2, 2, page_text)
|
||||||
|
self.screen.getch()
|
||||||
|
self.screen.refresh()
|
||||||
|
# Clear page before drawing next
|
||||||
|
for y, line in enumerate(range(self.maxy-16), 2):
|
||||||
|
self.screen.addstr(y+12, 2, clear_bar)
|
||||||
|
self.infotoggle = 0
|
||||||
|
self.screen.refresh()
|
||||||
|
else:
|
||||||
|
self.screen.refresh()
|
||||||
|
# self.screen.getch()
|
||||||
|
# for y, line in enumerate(range(self.maxy-16), 2):
|
||||||
|
# self.screen.addstr(y+12, 2, clear_bar)
|
||||||
|
# self.screen.refresh()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_plant_description(self, this_plant):
|
def get_plant_description(self, this_plant):
|
||||||
output_text = ""
|
output_text = ""
|
||||||
|
@ -281,6 +309,8 @@ class CursedMenu(object):
|
||||||
"You wish your seed could tell you what it needs.",
|
"You wish your seed could tell you what it needs.",
|
||||||
"You can feel the spirit inside your seed.",
|
"You can feel the spirit inside your seed.",
|
||||||
"These pretzels are making you thirsty.",
|
"These pretzels are making you thirsty.",
|
||||||
|
"Way to plant, Ann!",
|
||||||
|
"'To see things in the seed, that is genius' - Lao Tzu",
|
||||||
],
|
],
|
||||||
1:[
|
1:[
|
||||||
"The seedling fills you with hope.",
|
"The seedling fills you with hope.",
|
||||||
|
@ -308,7 +338,7 @@ class CursedMenu(object):
|
||||||
"You're proud of the dedication it took to grow your " + this_species + ".",
|
"You're proud of the dedication it took to grow your " + this_species + ".",
|
||||||
"The " + this_species + " looks good.",
|
"The " + this_species + " looks good.",
|
||||||
"You think about how good this " + this_species + " will look.",
|
"You think about how good this " + this_species + " will look.",
|
||||||
"The buds of your " + this_species + " are about to bloom.",
|
"The buds of your " + this_species + " might bloom soon.",
|
||||||
"You play your favorite song for your " + this_species + ".",
|
"You play your favorite song for your " + this_species + ".",
|
||||||
],
|
],
|
||||||
4:[
|
4:[
|
||||||
|
@ -386,9 +416,6 @@ class CursedMenu(object):
|
||||||
# load data
|
# load data
|
||||||
# format data
|
# format data
|
||||||
if self.infotoggle != 1:
|
if self.infotoggle != 1:
|
||||||
# TODO: when garden grows this won't clear everything.
|
|
||||||
# for example if there are 9 people in garden it won't clear all
|
|
||||||
# of them
|
|
||||||
output_string = clear_bar * (self.maxy - 15)
|
output_string = clear_bar * (self.maxy - 15)
|
||||||
for y, line in enumerate(output_string.splitlines(), 2):
|
for y, line in enumerate(output_string.splitlines(), 2):
|
||||||
self.screen.addstr(y+12, 2, line)
|
self.screen.addstr(y+12, 2, line)
|
||||||
|
@ -431,7 +458,7 @@ 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 == "start over":
|
if request == "harvest":
|
||||||
self.plant.start_over()
|
self.plant.start_over()
|
||||||
if request == "water":
|
if request == "water":
|
||||||
self.plant.water()
|
self.plant.water()
|
||||||
|
|
Loading…
Reference in New Issue