botany/plant.py

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