mirror of https://github.com/tilde-team/botany
346 lines
15 KiB
Python
346 lines
15 KiB
Python
import getpass
|
|
import random
|
|
import threading
|
|
import time
|
|
import uuid
|
|
|
|
import consts
|
|
|
|
|
|
class Plant(object):
|
|
# This is your plant!
|
|
def __init__(self, this_filename, generation=1):
|
|
# Constructor
|
|
self.time_delta_watered = 0
|
|
self.plant_id = str(uuid.uuid4())
|
|
self.life_stages = (3600 * 24, (3600 * 24) * 3, (3600 * 24) * 10, (3600 * 24) * 20, (3600 * 24) * 30)
|
|
# self.life_stages = (2, 4, 6, 8, 10) # debug mode
|
|
self.stage = 0
|
|
self.mutation = 0
|
|
self.species = random.randint(0, len(consts.species) - 1)
|
|
self.color = random.randint(0, len(consts.colors) - 1)
|
|
self.rarity = self.rarity_check()
|
|
self.ticks = 0
|
|
self.age_formatted = "0"
|
|
self.generation = generation
|
|
self.dead = False
|
|
self.write_lock = False
|
|
self.owner = getpass.getuser()
|
|
self.file_name = this_filename
|
|
self.start_time = int(time.time())
|
|
self.last_time = int(time.time())
|
|
# must water plant first day
|
|
self.watered_timestamp = int(time.time()) - (24 * 3600) - 1
|
|
self.watered_24h = False
|
|
self.visitors = []
|
|
|
|
def migrate_properties(self):
|
|
# Migrates old data files to new
|
|
if not hasattr(self, 'generation'):
|
|
self.generation = 1
|
|
if not hasattr(self, 'visitors'):
|
|
self.visitors = []
|
|
|
|
def parse_plant(self):
|
|
# Converts plant data to human-readable format
|
|
output = ""
|
|
if self.stage >= 3:
|
|
output += consts.rarities[self.rarity] + " "
|
|
if self.mutation != 0:
|
|
output += consts.mutations[self.mutation] + " "
|
|
if self.stage >= 4:
|
|
output += consts.colors[self.color] + " "
|
|
output += consts.stages[self.stage] + " "
|
|
if self.stage >= 2:
|
|
output += consts.species[self.species] + " "
|
|
return output.strip()
|
|
|
|
@staticmethod
|
|
def rarity_check():
|
|
# Generate plant rarity
|
|
rare_seed = random.randint(1, int(consts.RARITY_MAX))
|
|
common_range = round((2.0 / 3) * consts.RARITY_MAX)
|
|
uncommon_range = round((2.0 / 3) * (consts.RARITY_MAX - common_range))
|
|
rare_range = round((2.0 / 3) * (consts.RARITY_MAX - common_range - uncommon_range))
|
|
legendary_range = round((2.0 / 3) * (consts.RARITY_MAX - common_range - uncommon_range - rare_range))
|
|
|
|
common_max = common_range
|
|
uncommon_max = common_max + uncommon_range
|
|
rare_max = uncommon_max + rare_range
|
|
legendary_max = rare_max + legendary_range
|
|
godly_max = consts.RARITY_MAX
|
|
|
|
rarity = 0
|
|
if 0 <= rare_seed <= common_max:
|
|
rarity = 0
|
|
elif common_max < rare_seed <= uncommon_max:
|
|
rarity = 1
|
|
elif uncommon_max < rare_seed <= rare_max:
|
|
rarity = 2
|
|
elif rare_max < rare_seed <= legendary_max:
|
|
rarity = 3
|
|
elif legendary_max < rare_seed <= godly_max:
|
|
rarity = 4
|
|
return rarity
|
|
|
|
def dead_check(self):
|
|
# if it has been >5 days since watering, sorry plant is dead :(
|
|
time_delta_watered = int(time.time()) - self.watered_timestamp
|
|
if time_delta_watered > (5 * (24 * 3600)):
|
|
self.dead = True
|
|
return self.dead
|
|
|
|
def guest_check(self, data_manager):
|
|
guest_timestamps = data_manager.load_visitors(self)
|
|
|
|
if not guest_timestamps:
|
|
return self.watered_timestamp
|
|
|
|
all_timestamps = [self.watered_timestamp] + guest_timestamps
|
|
all_timestamps.sort()
|
|
|
|
# calculate # of days between each guest watering
|
|
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
|
|
# gap of 5 days
|
|
# 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
|
|
# from 24h after each watered timestamp
|
|
|
|
last_valid_element = next((x for x in timestamp_diffs if x > 5), None)
|
|
if not last_valid_element:
|
|
# all timestamps are within a 5-day range, can just use the latest one
|
|
return all_timestamps[-1]
|
|
|
|
last_valid_index = timestamp_diffs.index(last_valid_element)
|
|
# slice list to only include up until a >5 day gap
|
|
valid_timestamps = all_timestamps[:last_valid_index + 1]
|
|
return valid_timestamps[-1]
|
|
|
|
def water_check(self, data_manager):
|
|
self.watered_timestamp = self.guest_check(data_manager)
|
|
self.time_delta_watered = int(time.time()) - self.watered_timestamp
|
|
if self.time_delta_watered <= (24 * 3600):
|
|
if not self.watered_24h:
|
|
self.watered_24h = True
|
|
return True
|
|
else:
|
|
self.watered_24h = False
|
|
return False
|
|
|
|
def mutate_check(self):
|
|
# Create plant mutation
|
|
# Increase this # to make mutation rarer (chance 1 out of x each second)
|
|
mutation_seed = random.randint(1, consts.MUTATION_RARITY)
|
|
if mutation_seed == consts.MUTATION_RARITY:
|
|
# mutation gained!
|
|
mutation = random.randint(0, len(consts.mutations) - 1)
|
|
if self.mutation == 0:
|
|
self.mutation = mutation
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def growth(self):
|
|
# Increase plant growth stage
|
|
if self.stage < (len(consts.stages) - 1):
|
|
self.stage += 1
|
|
|
|
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):
|
|
# After plant reaches final stage, given option to restart
|
|
# increment generation only if previous stage is final stage and plant
|
|
# is alive
|
|
if not self.dead:
|
|
next_generation = self.generation + 1
|
|
else:
|
|
# Should this reset to 1? Seems unfair… for now generations will
|
|
# persist through death.
|
|
next_generation = self.generation
|
|
self.write_lock = True
|
|
self.kill_plant()
|
|
while self.write_lock:
|
|
# Wait for garden writer to unlock
|
|
# garden db needs to update before allowing the user to reset
|
|
pass
|
|
if not self.write_lock:
|
|
self.__init__(self.file_name, next_generation)
|
|
|
|
def kill_plant(self):
|
|
self.dead = True
|
|
|
|
def unlock_new_creation(self):
|
|
self.write_lock = False
|
|
|
|
def start_life(self, data_manager):
|
|
# runs life on a thread
|
|
thread = threading.Thread(target=self.life, args=(data_manager,))
|
|
thread.daemon = True
|
|
thread.start()
|
|
|
|
def life(self, data_manager):
|
|
# I've created life :)
|
|
while True:
|
|
if not self.dead:
|
|
if self.watered_24h:
|
|
self.ticks += 1
|
|
if self.stage < len(consts.stages) - 1:
|
|
if self.ticks >= self.life_stages[self.stage]:
|
|
self.growth()
|
|
if self.mutate_check():
|
|
pass
|
|
if self.water_check(data_manager):
|
|
# Do something
|
|
pass
|
|
if self.dead_check():
|
|
# Do something else
|
|
pass
|
|
# TODO: event check
|
|
generation_bonus = 0.2 * (self.generation - 1)
|
|
adjusted_sleep_time = 1 / (1 + generation_bonus)
|
|
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
|