mirror of https://github.com/tilde-team/botany
move all data stuff to data_manager.py
This commit is contained in:
parent
700e5b764c
commit
10817164e7
|
@ -7,6 +7,7 @@ from plant import Plant
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
my_data = DataManager()
|
my_data = DataManager()
|
||||||
|
my_data.init_database()
|
||||||
# if plant save file exists
|
# if plant save file exists
|
||||||
if my_data.check_plant():
|
if my_data.check_plant():
|
||||||
my_plant = my_data.load_plant()
|
my_plant = my_data.load_plant()
|
||||||
|
@ -15,7 +16,7 @@ if __name__ == '__main__':
|
||||||
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 is either a fresh plant or an existing plant at this point
|
# my_plant is either a fresh plant or an existing plant at this point
|
||||||
my_plant.start_life()
|
my_plant.start_life(my_data)
|
||||||
my_data.start_threads(my_plant)
|
my_data.start_threads(my_plant)
|
||||||
try:
|
try:
|
||||||
botany_menu = CursedMenu(my_plant, my_data)
|
botany_menu = CursedMenu(my_plant, my_data)
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
import os
|
#!/usr/bin/env python3
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
game_dir = os.path.dirname(os.path.realpath(__file__))
|
from data_manager import DataManager
|
||||||
garden_db_path = os.path.join(game_dir, 'sqlite/garden_db.sqlite')
|
|
||||||
conn = sqlite3.connect(garden_db_path)
|
d = DataManager()
|
||||||
c = conn.cursor()
|
d.clear_weekly_visitors()
|
||||||
c.execute("DELETE FROM visitors")
|
|
||||||
print("Cleared weekly users")
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
180
cursed_menu.py
180
cursed_menu.py
|
@ -4,9 +4,7 @@ import getpass
|
||||||
import json
|
import json
|
||||||
import math
|
import math
|
||||||
import os
|
import os
|
||||||
import random
|
|
||||||
import re
|
import re
|
||||||
import sqlite3
|
|
||||||
import string
|
import string
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
@ -258,7 +256,7 @@ class CursedMenu(object):
|
||||||
self.screen.refresh()
|
self.screen.refresh()
|
||||||
|
|
||||||
# enter, exit, and Q Keys are special cases
|
# enter, exit, and Q Keys are special cases
|
||||||
if user_in == 10:
|
if user_in == 13:
|
||||||
return self.options[self.selected]
|
return self.options[self.selected]
|
||||||
if user_in == 27:
|
if user_in == 27:
|
||||||
return self.options[-1]
|
return self.options[-1]
|
||||||
|
@ -421,148 +419,12 @@ class CursedMenu(object):
|
||||||
self.clear_info_pane()
|
self.clear_info_pane()
|
||||||
self.clear_info_pane()
|
self.clear_info_pane()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_plant_description(this_plant):
|
|
||||||
output_text = ""
|
|
||||||
this_species = this_plant.species_list[this_plant.species]
|
|
||||||
this_color = this_plant.color_list[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.",
|
|
||||||
"You can feel the spirit inside your seed.",
|
|
||||||
"These pretzels are making you thirsty.",
|
|
||||||
"Way to plant, Ann!",
|
|
||||||
"'To see things in the seed, that is genius' - Lao Tzu",
|
|
||||||
],
|
|
||||||
1: [
|
|
||||||
"The seedling fills you with hope.",
|
|
||||||
"The seedling shakes in the wind.",
|
|
||||||
"You can make out a tiny leaf - or is that a thorn?",
|
|
||||||
"You can feel the seedling looking back at you.",
|
|
||||||
"You blow a kiss to your seedling.",
|
|
||||||
"You think about all the seedlings who came before it.",
|
|
||||||
"You and your seedling make a great team.",
|
|
||||||
"Your seedling grows slowly and quietly.",
|
|
||||||
"You meditate on the paths your plant's life could take.",
|
|
||||||
],
|
|
||||||
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 + ".",
|
|
||||||
"You play piano to your " + this_species + ".",
|
|
||||||
"You play rap music to your " + this_species + ".",
|
|
||||||
"You whistle a tune to your " + this_species + ".",
|
|
||||||
"You read a poem to your " + this_species + ".",
|
|
||||||
"You tell a secret to your " + this_species + ".",
|
|
||||||
"You play your favorite record for your " + this_species + ".",
|
|
||||||
],
|
|
||||||
3: [
|
|
||||||
"Your " + this_species + " is growing nicely!",
|
|
||||||
"You're proud of the dedication it took to grow your " + this_species + ".",
|
|
||||||
"You take a deep breath with your " + this_species + ".",
|
|
||||||
"You think of all the words that rhyme with " + this_species + ".",
|
|
||||||
"The " + this_species + " looks full of life.",
|
|
||||||
"The " + this_species + " inspires you.",
|
|
||||||
"Your " + this_species + " makes you forget about your problems.",
|
|
||||||
"Your " + this_species + " gives you a reason to keep going.",
|
|
||||||
"Looking at your " + this_species + " helps you focus on what matters.",
|
|
||||||
"You think about how nice this " + this_species + " looks here.",
|
|
||||||
"The buds of your " + this_species + " might bloom soon.",
|
|
||||||
],
|
|
||||||
4: [
|
|
||||||
"The " + this_color + " flowers look nice on your " + this_species + "!",
|
|
||||||
"The " + this_color + " flowers have bloomed and fill you with positivity.",
|
|
||||||
"The " + this_color + " flowers remind you of your childhood.",
|
|
||||||
"The " + this_color + " flowers remind you of spring mornings.",
|
|
||||||
"The " + this_color + " flowers remind you of a forgotten memory.",
|
|
||||||
"The " + this_color + " flowers remind you of your happy place.",
|
|
||||||
"The aroma of the " + this_color + " flowers energize you.",
|
|
||||||
"The " + this_species + " has grown beautiful " + this_color + " flowers.",
|
|
||||||
"The " + this_color + " petals remind you of that favorite shirt you lost.",
|
|
||||||
"The " + this_color + " flowers remind you of your crush.",
|
|
||||||
"You smell the " + this_color + " flowers and are filled with peace.",
|
|
||||||
],
|
|
||||||
5: [
|
|
||||||
"You fondly remember the time you spent caring for your " + this_species + ".",
|
|
||||||
"Seed pods have grown on your " + this_species + ".",
|
|
||||||
"You feel like your " + this_species + " appreciates your care.",
|
|
||||||
"The " + this_species + " fills you with love.",
|
|
||||||
"You're ready for whatever comes after your " + this_species + ".",
|
|
||||||
"You're excited to start growing your next plant.",
|
|
||||||
"You reflect on when your " + this_species + " was just a seedling.",
|
|
||||||
"You grow nostalgic about the early days with your " + this_species + ".",
|
|
||||||
],
|
|
||||||
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 this_plant.dead:
|
|
||||||
this_stage = 99
|
|
||||||
|
|
||||||
this_stage_descriptions = stage_descriptions[this_stage]
|
|
||||||
description_num = random.randint(0, len(this_stage_descriptions) - 1)
|
|
||||||
# If not fully grown
|
|
||||||
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"
|
|
||||||
|
|
||||||
# if seedling
|
|
||||||
if this_stage == 1:
|
|
||||||
species_options = [this_plant.species_list[this_plant.species],
|
|
||||||
this_plant.species_list[(this_plant.species + 3) % len(this_plant.species_list)],
|
|
||||||
this_plant.species_list[(this_plant.species - 3) % len(this_plant.species_list)]]
|
|
||||||
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 young plant
|
|
||||||
if this_stage == 2:
|
|
||||||
if this_plant.rarity >= 2:
|
|
||||||
rarity_hint = "You feel like your plant is special."
|
|
||||||
output_text += rarity_hint + ".\n"
|
|
||||||
|
|
||||||
# if mature plant
|
|
||||||
if this_stage == 3:
|
|
||||||
color_options = [this_plant.color_list[this_plant.color],
|
|
||||||
this_plant.color_list[(this_plant.color + 3) % len(this_plant.color_list)],
|
|
||||||
this_plant.color_list[(this_plant.color - 3) % len(this_plant.color_list)]]
|
|
||||||
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):
|
def draw_plant_description(self, this_plant):
|
||||||
# If menu is currently showing something other than the description
|
# If menu is currently showing something other than the description
|
||||||
self.clear_info_pane()
|
self.clear_info_pane()
|
||||||
if self.infotoggle != 1:
|
if self.infotoggle != 1:
|
||||||
# get plant description before printing
|
# get plant description before printing
|
||||||
output_string = self.get_plant_description(this_plant)
|
output_string = this_plant.get_plant_description()
|
||||||
growth_multiplier = 1 + (0.2 * (this_plant.generation - 1))
|
growth_multiplier = 1 + (0.2 * (this_plant.generation - 1))
|
||||||
output_string += "Generation: {}\nGrowth rate: {}x".format(self.plant.generation, growth_multiplier)
|
output_string += "Generation: {}\nGrowth rate: {}x".format(self.plant.generation, growth_multiplier)
|
||||||
self.draw_info_text(output_string)
|
self.draw_info_text(output_string)
|
||||||
|
@ -662,30 +524,6 @@ class CursedMenu(object):
|
||||||
visitor_line += visitor + ' '
|
visitor_line += visitor + ' '
|
||||||
return [visitor_line]
|
return [visitor_line]
|
||||||
|
|
||||||
def get_weekly_visitors(self):
|
|
||||||
game_dir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
garden_db_path = os.path.join(game_dir, 'sqlite/garden_db.sqlite')
|
|
||||||
conn = sqlite3.connect(garden_db_path)
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute("SELECT * FROM visitors WHERE garden_name = ? ORDER BY weekly_visits", self.plant.owner)
|
|
||||||
visitor_data = c.fetchall()
|
|
||||||
conn.close()
|
|
||||||
visitor_block = ""
|
|
||||||
visitor_line = ""
|
|
||||||
if visitor_data:
|
|
||||||
for visitor in visitor_data:
|
|
||||||
visitor_name = visitor[2]
|
|
||||||
weekly_visits = visitor[3]
|
|
||||||
this_visitor_string = "{}({}) ".format(visitor_name, weekly_visits)
|
|
||||||
if len(visitor_line + this_visitor_string) > self.maxx - 3:
|
|
||||||
visitor_block += '\n'
|
|
||||||
visitor_line = ""
|
|
||||||
visitor_block += this_visitor_string
|
|
||||||
visitor_line += this_visitor_string
|
|
||||||
else:
|
|
||||||
visitor_block = 'nobody :('
|
|
||||||
return visitor_block
|
|
||||||
|
|
||||||
def get_user_string(self, xpos=3, ypos=15, filterfunc=str.isalnum, completer=None):
|
def get_user_string(self, xpos=3, ypos=15, filterfunc=str.isalnum, completer=None):
|
||||||
# filter allowed characters using filterfunc, alphanumeric by default
|
# filter allowed characters using filterfunc, alphanumeric by default
|
||||||
user_string = ""
|
user_string = ""
|
||||||
|
@ -727,7 +565,7 @@ class CursedMenu(object):
|
||||||
self.draw_info_text("since last time, you were visited by: ", 3)
|
self.draw_info_text("since last time, you were visited by: ", 3)
|
||||||
self.draw_info_text(latest_visitor_string, 4)
|
self.draw_info_text(latest_visitor_string, 4)
|
||||||
self.plant.visitors = []
|
self.plant.visitors = []
|
||||||
weekly_visitor_text = self.get_weekly_visitors()
|
weekly_visitor_text = self.user_data.get_weekly_visitors(self.plant, self.maxx)
|
||||||
self.draw_info_text("this week you've been visited by: ", 6)
|
self.draw_info_text("this week you've been visited by: ", 6)
|
||||||
self.draw_info_text(weekly_visitor_text, 7)
|
self.draw_info_text(weekly_visitor_text, 7)
|
||||||
guest_garden = self.get_user_string(completer=completer.LoginCompleter)
|
guest_garden = self.get_user_string(completer=completer.LoginCompleter)
|
||||||
|
@ -740,25 +578,25 @@ class CursedMenu(object):
|
||||||
self.clear_info_pane()
|
self.clear_info_pane()
|
||||||
return None
|
return None
|
||||||
home_folder = os.path.dirname(os.path.expanduser("~"))
|
home_folder = os.path.dirname(os.path.expanduser("~"))
|
||||||
guest_json = home_folder + "/{}/.botany/{}_plant_data.json".format(guest_garden, guest_garden)
|
guest_json = home_folder + f"/{guest_garden}/.botany/{guest_garden}_plant_data.json"
|
||||||
guest_plant_description = ""
|
guest_plant_description = ""
|
||||||
if os.path.isfile(guest_json):
|
if os.path.isfile(guest_json):
|
||||||
with open(guest_json) as f:
|
with open(guest_json) as f:
|
||||||
visitor_data = json.load(f)
|
visitor_data = json.load(f)
|
||||||
guest_plant_description = visitor_data['description']
|
guest_plant_description = visitor_data['description']
|
||||||
self.visited_plant = self.get_visited_plant(visitor_data)
|
self.visited_plant = self.get_visited_plant(visitor_data)
|
||||||
guest_visitor_file = home_folder + "/{}/.botany/visitors.json".format(guest_garden, guest_garden)
|
guest_visitor_file = home_folder + f"/{guest_garden}/.botany/visitors.json"
|
||||||
if os.path.isfile(guest_visitor_file):
|
if os.path.isfile(guest_visitor_file):
|
||||||
water_success = self.water_on_visit(guest_visitor_file)
|
water_success = self.water_on_visit(guest_visitor_file)
|
||||||
if water_success:
|
if water_success:
|
||||||
self.screen.addstr(16, 2,
|
self.screen.addstr(16, 2,
|
||||||
"...you watered ~{}'s {}...".format(str(guest_garden), guest_plant_description))
|
f"...you watered ~{str(guest_garden)}'s {guest_plant_description}...")
|
||||||
if self.visited_plant:
|
if self.visited_plant:
|
||||||
self.draw_plant_ascii(self.visited_plant)
|
self.draw_plant_ascii(self.visited_plant)
|
||||||
else:
|
else:
|
||||||
self.screen.addstr(16, 2, "{}'s garden is locked, but you can see in...".format(guest_garden))
|
self.screen.addstr(16, 2, f"{guest_garden}'s garden is locked, but you can see in...")
|
||||||
else:
|
else:
|
||||||
self.screen.addstr(16, 2, "i can't seem to find directions to {}...".format(guest_garden))
|
self.screen.addstr(16, 2, f"i can't seem to find directions to {guest_garden}...")
|
||||||
try:
|
try:
|
||||||
self.screen.getch()
|
self.screen.getch()
|
||||||
self.clear_info_pane()
|
self.clear_info_pane()
|
||||||
|
@ -819,6 +657,8 @@ class CursedMenu(object):
|
||||||
self.harvest_confirmation()
|
self.harvest_confirmation()
|
||||||
if request == "water":
|
if request == "water":
|
||||||
self.plant.water()
|
self.plant.water()
|
||||||
|
self.user_data.save_plant(self.plant)
|
||||||
|
self.user_data.update_garden_db(self.plant)
|
||||||
if request == "look":
|
if request == "look":
|
||||||
try:
|
try:
|
||||||
self.draw_plant_description(self.plant)
|
self.draw_plant_description(self.plant)
|
||||||
|
|
110
data_manager.py
110
data_manager.py
|
@ -6,6 +6,7 @@ import pickle
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
import consts
|
import consts
|
||||||
|
|
||||||
|
@ -79,7 +80,7 @@ class DataManager(object):
|
||||||
this_plant.migrate_properties()
|
this_plant.migrate_properties()
|
||||||
|
|
||||||
# get status since last login
|
# get status since last login
|
||||||
is_watered = this_plant.water_check()
|
is_watered = this_plant.water_check(self)
|
||||||
is_dead = this_plant.dead_check()
|
is_dead = this_plant.dead_check()
|
||||||
|
|
||||||
if not is_dead:
|
if not is_dead:
|
||||||
|
@ -109,37 +110,37 @@ class DataManager(object):
|
||||||
if not os.path.exists(sqlite_dir_path):
|
if not os.path.exists(sqlite_dir_path):
|
||||||
os.makedirs(sqlite_dir_path, mode=0o777)
|
os.makedirs(sqlite_dir_path, mode=0o777)
|
||||||
|
|
||||||
for schema in ['garden', 'visitors']:
|
for schema in glob(os.path.join(sqlite_dir_path, 'main', '*.sql')):
|
||||||
with open(os.path.join(sqlite_dir_path, 'main', f'{schema}.sql')) as schema_file:
|
with open(schema) as schema_file:
|
||||||
self.cursor.execute(schema_file.read())
|
self.cursor.execute(schema_file.read())
|
||||||
|
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
# init only, creates and sets permissions for garden db and json
|
# init only, creates and sets permissions for garden db and json
|
||||||
if os.stat(self.garden_db_path).st_uid == os.getuid():
|
if os.name == "posix":
|
||||||
os.chmod(self.garden_db_path, 0o666)
|
if os.stat(self.garden_db_path).st_uid == os.getuid():
|
||||||
open(self.garden_json_path, 'a').close()
|
os.chmod(self.garden_db_path, 0o666)
|
||||||
os.chmod(self.garden_json_path, 0o666)
|
open(self.garden_json_path, 'a').close()
|
||||||
|
os.chmod(self.garden_json_path, 0o666)
|
||||||
|
|
||||||
def update_garden_db(self, this_plant):
|
def update_garden_db(self, this_plant):
|
||||||
# insert or update this plant id's entry in DB
|
# insert or update this plant id's entry in DB
|
||||||
# TODO: make sure other instances of user are deleted
|
# TODO: make sure other instances of user are deleted
|
||||||
# Could create a clean db function
|
# Could create a clean db function
|
||||||
self.init_database()
|
|
||||||
age_formatted = self.plant_age_convert(this_plant)
|
age_formatted = self.plant_age_convert(this_plant)
|
||||||
# try to insert or replace
|
# try to insert or replace
|
||||||
update_query = """INSERT OR REPLACE INTO garden (
|
self.cursor.execute(
|
||||||
plant_id, owner, description, age, score, is_dead
|
"""INSERT OR REPLACE INTO garden (
|
||||||
) VALUES (
|
plant_id, owner, description, age, score, is_dead
|
||||||
:pid, :owner, :description, :page, :score, :dead
|
) VALUES (
|
||||||
)"""
|
:pid, :owner, :description, :page, :score, :dead
|
||||||
|
)""",
|
||||||
self.cursor.execute(update_query, {"pid": this_plant.plant_id,
|
{"pid": this_plant.plant_id,
|
||||||
"owner": this_plant.owner,
|
"owner": this_plant.owner,
|
||||||
"description": this_plant.parse_plant(),
|
"description": this_plant.parse_plant(),
|
||||||
"page": age_formatted,
|
"page": age_formatted,
|
||||||
"score": str(this_plant.ticks),
|
"score": str(this_plant.ticks),
|
||||||
"dead": int(this_plant.dead)})
|
"dead": int(this_plant.dead)})
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
|
||||||
def retrieve_garden_from_db(self):
|
def retrieve_garden_from_db(self):
|
||||||
|
@ -163,7 +164,6 @@ class DataManager(object):
|
||||||
def update_garden_json(self):
|
def update_garden_json(self):
|
||||||
with open(self.garden_json_path, 'w') as outfile:
|
with open(self.garden_json_path, 'w') as outfile:
|
||||||
json.dump(self.retrieve_garden_from_db(), outfile)
|
json.dump(self.retrieve_garden_from_db(), outfile)
|
||||||
pass
|
|
||||||
|
|
||||||
def save_plant(self, this_plant):
|
def save_plant(self, this_plant):
|
||||||
# create savefile
|
# create savefile
|
||||||
|
@ -171,7 +171,7 @@ class DataManager(object):
|
||||||
temp_path = self.savefile_path + ".temp"
|
temp_path = self.savefile_path + ".temp"
|
||||||
with open(temp_path, 'wb') as f:
|
with open(temp_path, 'wb') as f:
|
||||||
pickle.dump(this_plant, f, protocol=2)
|
pickle.dump(this_plant, f, protocol=2)
|
||||||
os.rename(temp_path, self.savefile_path)
|
os.replace(temp_path, self.savefile_path)
|
||||||
|
|
||||||
def data_write_json(self, this_plant):
|
def data_write_json(self, this_plant):
|
||||||
# create personal json file for user to use outside the game (website?)
|
# create personal json file for user to use outside the game (website?)
|
||||||
|
@ -234,3 +234,69 @@ class DataManager(object):
|
||||||
json.dump(this_harvest, outfile)
|
json.dump(this_harvest, outfile)
|
||||||
|
|
||||||
return new_file_check
|
return new_file_check
|
||||||
|
|
||||||
|
def get_weekly_visitors(self, plant, maxx):
|
||||||
|
self.cursor.execute("SELECT * FROM visitors WHERE garden_name = ? ORDER BY weekly_visits", plant.owner)
|
||||||
|
visitor_data = self.cursor.fetchall()
|
||||||
|
visitor_block = ""
|
||||||
|
visitor_line = ""
|
||||||
|
if visitor_data:
|
||||||
|
for visitor in visitor_data:
|
||||||
|
visitor_name = visitor[2]
|
||||||
|
weekly_visits = visitor[3]
|
||||||
|
this_visitor_string = "{}({}) ".format(visitor_name, weekly_visits)
|
||||||
|
if len(visitor_line + this_visitor_string) > maxx - 3:
|
||||||
|
visitor_block += '\n'
|
||||||
|
visitor_line = ""
|
||||||
|
visitor_block += this_visitor_string
|
||||||
|
visitor_line += this_visitor_string
|
||||||
|
else:
|
||||||
|
visitor_block = 'nobody :('
|
||||||
|
return visitor_block
|
||||||
|
|
||||||
|
def update_visitor_db(self, visitor_names, owner_name):
|
||||||
|
for name in visitor_names:
|
||||||
|
self.cursor.execute(
|
||||||
|
"SELECT * FROM visitors WHERE garden_name = ? AND visitor_name = ?", (owner_name, name))
|
||||||
|
data = self.cursor.fetchone()
|
||||||
|
if data is None:
|
||||||
|
self.cursor.execute(" INSERT INTO visitors (garden_name,visitor_name,weekly_visits) VALUES(?, ?, 1)",
|
||||||
|
(owner_name, name))
|
||||||
|
else:
|
||||||
|
self.cursor.execute(
|
||||||
|
"UPDATE visitors SET weekly_visits = weekly_visits + 1 WHERE garden_name = ? AND visitor_name = ?",
|
||||||
|
(owner_name, name))
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
def clear_weekly_visitors(self):
|
||||||
|
self.cursor.execute("DELETE FROM visitors")
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
def load_visitors(self, plant):
|
||||||
|
visitor_filepath = os.path.join(os.path.join(os.path.expanduser("~"), '.botany'), 'visitors.json')
|
||||||
|
guest_timestamps = []
|
||||||
|
visitors_this_check = []
|
||||||
|
if os.path.isfile(visitor_filepath):
|
||||||
|
with open(visitor_filepath, 'r') as visit:
|
||||||
|
data = json.load(visit)
|
||||||
|
if data:
|
||||||
|
for element in data:
|
||||||
|
if element['user'] not in plant.visitors:
|
||||||
|
plant.visitors.append(element['user'])
|
||||||
|
if element['user'] not in visitors_this_check:
|
||||||
|
visitors_this_check.append(element['user'])
|
||||||
|
# prevent users from manually setting watered_time in the future
|
||||||
|
if int(time.time()) >= element['timestamp'] >= plant.watered_timestamp:
|
||||||
|
guest_timestamps.append(element['timestamp'])
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.update_visitor_db(visitors_this_check, plant.owner)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
with open(visitor_filepath, 'w') as visitor:
|
||||||
|
visitor.write('[]')
|
||||||
|
else:
|
||||||
|
with open(visitor_filepath, 'w') as f:
|
||||||
|
json.dump([], f)
|
||||||
|
os.chmod(visitor_filepath, 0o666)
|
||||||
|
return guest_timestamps
|
||||||
|
|
206
plant.py
206
plant.py
|
@ -1,8 +1,5 @@
|
||||||
import getpass
|
import getpass
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import random
|
import random
|
||||||
import sqlite3
|
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
@ -93,57 +90,15 @@ class Plant(object):
|
||||||
self.dead = True
|
self.dead = True
|
||||||
return self.dead
|
return self.dead
|
||||||
|
|
||||||
def update_visitor_db(self, visitor_names):
|
def guest_check(self, data_manager):
|
||||||
game_dir = os.path.dirname(os.path.realpath(__file__))
|
guest_timestamps = data_manager.load_visitors(self)
|
||||||
garden_db_path = os.path.join(game_dir, 'sqlite/garden_db.sqlite')
|
|
||||||
conn = sqlite3.connect(garden_db_path)
|
|
||||||
for name in visitor_names:
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute(
|
|
||||||
"SELECT * FROM visitors WHERE garden_name = ? AND visitor_name = ?", (self.owner, name))
|
|
||||||
data = c.fetchone()
|
|
||||||
if data is None:
|
|
||||||
c.execute(" INSERT INTO visitors (garden_name,visitor_name,weekly_visits) VALUES(?, ?, 1)",
|
|
||||||
(self.owner, name))
|
|
||||||
else:
|
|
||||||
c.execute(
|
|
||||||
"UPDATE visitors SET weekly_visits = weekly_visits + 1 WHERE garden_name = ? AND visitor_name = ?",
|
|
||||||
(self.owner, name))
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
def guest_check(self):
|
|
||||||
user_dir = os.path.expanduser("~")
|
|
||||||
botany_dir = os.path.join(user_dir, '.botany')
|
|
||||||
visitor_filepath = os.path.join(botany_dir, 'visitors.json')
|
|
||||||
guest_timestamps = []
|
|
||||||
visitors_this_check = []
|
|
||||||
if os.path.isfile(visitor_filepath):
|
|
||||||
with open(visitor_filepath, 'r') as visit:
|
|
||||||
data = json.load(visit)
|
|
||||||
if data:
|
|
||||||
for element in data:
|
|
||||||
if element['user'] not in self.visitors:
|
|
||||||
self.visitors.append(element['user'])
|
|
||||||
if element['user'] not in visitors_this_check:
|
|
||||||
visitors_this_check.append(element['user'])
|
|
||||||
# prevent users from manually setting watered_time in the future
|
|
||||||
if int(time.time()) >= element['timestamp'] >= self.watered_timestamp:
|
|
||||||
guest_timestamps.append(element['timestamp'])
|
|
||||||
try:
|
|
||||||
self.update_visitor_db(visitors_this_check)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
with open(visitor_filepath, 'w') as visitor:
|
|
||||||
visitor.write('[]')
|
|
||||||
else:
|
|
||||||
with open(visitor_filepath, 'w') as f:
|
|
||||||
json.dump([], f)
|
|
||||||
os.chmod(visitor_filepath, 0o666)
|
|
||||||
if not guest_timestamps:
|
if not guest_timestamps:
|
||||||
return self.watered_timestamp
|
return self.watered_timestamp
|
||||||
|
|
||||||
all_timestamps = [self.watered_timestamp] + guest_timestamps
|
all_timestamps = [self.watered_timestamp] + guest_timestamps
|
||||||
all_timestamps.sort()
|
all_timestamps.sort()
|
||||||
|
|
||||||
# calculate # of days between each guest watering
|
# calculate # of days between each guest watering
|
||||||
timestamp_diffs = [(j - i) / 86400.0 for i, j in zip(all_timestamps[:-1], all_timestamps[1:])]
|
timestamp_diffs = [(j - i) / 86400.0 for i, j in zip(all_timestamps[:-1], all_timestamps[1:])]
|
||||||
# plant's latest timestamp should be set to last timestamp before a
|
# plant's latest timestamp should be set to last timestamp before a
|
||||||
|
@ -151,17 +106,19 @@ class Plant(object):
|
||||||
# TODO: this considers a plant watered only on day 1 and day 4 to be
|
# TODO: this considers a plant watered only on day 1 and day 4 to be
|
||||||
# watered for all 4 days - need to figure out how to only add score
|
# watered for all 4 days - need to figure out how to only add score
|
||||||
# from 24h after each watered timestamp
|
# from 24h after each watered timestamp
|
||||||
|
|
||||||
last_valid_element = next((x for x in timestamp_diffs if x > 5), None)
|
last_valid_element = next((x for x in timestamp_diffs if x > 5), None)
|
||||||
if not last_valid_element:
|
if not last_valid_element:
|
||||||
# all timestamps are within a 5-day range, can just use the latest one
|
# all timestamps are within a 5-day range, can just use the latest one
|
||||||
return all_timestamps[-1]
|
return all_timestamps[-1]
|
||||||
|
|
||||||
last_valid_index = timestamp_diffs.index(last_valid_element)
|
last_valid_index = timestamp_diffs.index(last_valid_element)
|
||||||
# slice list to only include up until a >5 day gap
|
# slice list to only include up until a >5 day gap
|
||||||
valid_timestamps = all_timestamps[:last_valid_index + 1]
|
valid_timestamps = all_timestamps[:last_valid_index + 1]
|
||||||
return valid_timestamps[-1]
|
return valid_timestamps[-1]
|
||||||
|
|
||||||
def water_check(self):
|
def water_check(self, data_manager):
|
||||||
self.watered_timestamp = self.guest_check()
|
self.watered_timestamp = self.guest_check(data_manager)
|
||||||
self.time_delta_watered = int(time.time()) - self.watered_timestamp
|
self.time_delta_watered = int(time.time()) - self.watered_timestamp
|
||||||
if self.time_delta_watered <= (24 * 3600):
|
if self.time_delta_watered <= (24 * 3600):
|
||||||
if not self.watered_24h:
|
if not self.watered_24h:
|
||||||
|
@ -220,13 +177,13 @@ class Plant(object):
|
||||||
def unlock_new_creation(self):
|
def unlock_new_creation(self):
|
||||||
self.write_lock = False
|
self.write_lock = False
|
||||||
|
|
||||||
def start_life(self):
|
def start_life(self, data_manager):
|
||||||
# runs life on a thread
|
# runs life on a thread
|
||||||
thread = threading.Thread(target=self.life, args=())
|
thread = threading.Thread(target=self.life, args=(data_manager,))
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
||||||
def life(self):
|
def life(self, data_manager):
|
||||||
# I've created life :)
|
# I've created life :)
|
||||||
while True:
|
while True:
|
||||||
if not self.dead:
|
if not self.dead:
|
||||||
|
@ -237,7 +194,7 @@ class Plant(object):
|
||||||
self.growth()
|
self.growth()
|
||||||
if self.mutate_check():
|
if self.mutate_check():
|
||||||
pass
|
pass
|
||||||
if self.water_check():
|
if self.water_check(data_manager):
|
||||||
# Do something
|
# Do something
|
||||||
pass
|
pass
|
||||||
if self.dead_check():
|
if self.dead_check():
|
||||||
|
@ -247,3 +204,142 @@ class Plant(object):
|
||||||
generation_bonus = 0.2 * (self.generation - 1)
|
generation_bonus = 0.2 * (self.generation - 1)
|
||||||
adjusted_sleep_time = 1 / (1 + generation_bonus)
|
adjusted_sleep_time = 1 / (1 + generation_bonus)
|
||||||
time.sleep(adjusted_sleep_time)
|
time.sleep(adjusted_sleep_time)
|
||||||
|
|
||||||
|
def get_plant_description(self):
|
||||||
|
output_text = ""
|
||||||
|
this_species = consts.species[self.species]
|
||||||
|
this_color = consts.colors[self.color]
|
||||||
|
this_stage = self.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.",
|
||||||
|
"You can feel the spirit inside your seed.",
|
||||||
|
"These pretzels are making you thirsty.",
|
||||||
|
"Way to plant, Ann!",
|
||||||
|
"'To see things in the seed, that is genius' - Lao Tzu",
|
||||||
|
],
|
||||||
|
1: [
|
||||||
|
"The seedling fills you with hope.",
|
||||||
|
"The seedling shakes in the wind.",
|
||||||
|
"You can make out a tiny leaf - or is that a thorn?",
|
||||||
|
"You can feel the seedling looking back at you.",
|
||||||
|
"You blow a kiss to your seedling.",
|
||||||
|
"You think about all the seedlings who came before it.",
|
||||||
|
"You and your seedling make a great team.",
|
||||||
|
"Your seedling grows slowly and quietly.",
|
||||||
|
"You meditate on the paths your plant's life could take.",
|
||||||
|
],
|
||||||
|
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 + ".",
|
||||||
|
"You play piano to your " + this_species + ".",
|
||||||
|
"You play rap music to your " + this_species + ".",
|
||||||
|
"You whistle a tune to your " + this_species + ".",
|
||||||
|
"You read a poem to your " + this_species + ".",
|
||||||
|
"You tell a secret to your " + this_species + ".",
|
||||||
|
"You play your favorite record for your " + this_species + ".",
|
||||||
|
],
|
||||||
|
3: [
|
||||||
|
"Your " + this_species + " is growing nicely!",
|
||||||
|
"You're proud of the dedication it took to grow your " + this_species + ".",
|
||||||
|
"You take a deep breath with your " + this_species + ".",
|
||||||
|
"You think of all the words that rhyme with " + this_species + ".",
|
||||||
|
"The " + this_species + " looks full of life.",
|
||||||
|
"The " + this_species + " inspires you.",
|
||||||
|
"Your " + this_species + " makes you forget about your problems.",
|
||||||
|
"Your " + this_species + " gives you a reason to keep going.",
|
||||||
|
"Looking at your " + this_species + " helps you focus on what matters.",
|
||||||
|
"You think about how nice this " + this_species + " looks here.",
|
||||||
|
"The buds of your " + this_species + " might bloom soon.",
|
||||||
|
],
|
||||||
|
4: [
|
||||||
|
"The " + this_color + " flowers look nice on your " + this_species + "!",
|
||||||
|
"The " + this_color + " flowers have bloomed and fill you with positivity.",
|
||||||
|
"The " + this_color + " flowers remind you of your childhood.",
|
||||||
|
"The " + this_color + " flowers remind you of spring mornings.",
|
||||||
|
"The " + this_color + " flowers remind you of a forgotten memory.",
|
||||||
|
"The " + this_color + " flowers remind you of your happy place.",
|
||||||
|
"The aroma of the " + this_color + " flowers energize you.",
|
||||||
|
"The " + this_species + " has grown beautiful " + this_color + " flowers.",
|
||||||
|
"The " + this_color + " petals remind you of that favorite shirt you lost.",
|
||||||
|
"The " + this_color + " flowers remind you of your crush.",
|
||||||
|
"You smell the " + this_color + " flowers and are filled with peace.",
|
||||||
|
],
|
||||||
|
5: [
|
||||||
|
"You fondly remember the time you spent caring for your " + this_species + ".",
|
||||||
|
"Seed pods have grown on your " + this_species + ".",
|
||||||
|
"You feel like your " + this_species + " appreciates your care.",
|
||||||
|
"The " + this_species + " fills you with love.",
|
||||||
|
"You're ready for whatever comes after your " + this_species + ".",
|
||||||
|
"You're excited to start growing your next plant.",
|
||||||
|
"You reflect on when your " + this_species + " was just a seedling.",
|
||||||
|
"You grow nostalgic about the early days with your " + this_species + ".",
|
||||||
|
],
|
||||||
|
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 self.dead:
|
||||||
|
this_stage = 99
|
||||||
|
|
||||||
|
this_stage_descriptions = stage_descriptions[this_stage]
|
||||||
|
description_num = random.randint(0, len(this_stage_descriptions) - 1)
|
||||||
|
# If not fully grown
|
||||||
|
if this_stage <= 4:
|
||||||
|
# Growth hint
|
||||||
|
if this_stage >= 1:
|
||||||
|
last_growth_at = self.life_stages[this_stage - 1]
|
||||||
|
else:
|
||||||
|
last_growth_at = 0
|
||||||
|
ticks_since_last = self.ticks - last_growth_at
|
||||||
|
ticks_between_stage = self.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"
|
||||||
|
|
||||||
|
# if seedling
|
||||||
|
if this_stage == 1:
|
||||||
|
num_species = len(consts.species)
|
||||||
|
|
||||||
|
species_options = [consts.species[self.species],
|
||||||
|
consts.species[(self.species + 3) % num_species],
|
||||||
|
consts.species[(self.species - 3) % num_species]]
|
||||||
|
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 young plant
|
||||||
|
if this_stage == 2:
|
||||||
|
if self.rarity >= 2:
|
||||||
|
rarity_hint = "You feel like your plant is special."
|
||||||
|
output_text += rarity_hint + ".\n"
|
||||||
|
|
||||||
|
# if mature plant
|
||||||
|
if this_stage == 3:
|
||||||
|
num_colors = len(consts.colors)
|
||||||
|
|
||||||
|
color_options = [consts.colors[self.color],
|
||||||
|
consts.colors[(self.color + 3) % num_colors],
|
||||||
|
consts.colors[(self.color - 3) % num_colors]]
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in New Issue