all repos — groupgardenbot @ 8434ee64d0634a3230ff2c7ae8cc3f4eb9d50f47

An extension of the game "botany", originally designed for unix-based systems, to the Telegram Bot API.

Gardening.py (view raw)

  1import random, time, math, datetime, os
  2from Constants import *
  3
  4water_duration = 3600 # * 24
  5stage_factors = (1, 3, 10, 20, 30)
  6
  7class Plant(object):
  8    # This is your plant!
  9    def __init__(self, owner, generation=1):
 10        # Constructor
 11        self.points = 0 # one point per second
 12        self.life_stages = tuple(st * water_duration for st in stage_factors)
 13        self.stage = 0
 14        self.mutation = 0
 15        self.species = random.randint(0,len(species_list)-1)
 16        self.color = random.randint(0,len(color_list)-1)
 17        self.rarity = self.rarity_check()
 18        self.ticks = 0
 19        self.age_formatted = "0"
 20        self.generation = generation
 21        self.generation_bonus = 1 + (0.2 * (generation - 1))
 22        self.dead = False
 23        self.owner = owner
 24        self.start_time = int(time.time())
 25        self.last_time = int(time.time())
 26        self.last_update = int(time.time())
 27        # must water plant first day
 28        #self.last_water = int(time.time())-(24*3600)-1
 29        self.last_water = int(time.time())
 30        self.watered_24h = True
 31        self.visitors = []
 32
 33    def update(self):
 34        
 35        # find out stage:
 36        self.water_check()
 37        if self.dead_check(): # updates self.time_delta_watered
 38            return
 39
 40        self.stage = find_stage(self)
 41        
 42    def parse_plant(self):
 43        # Converts plant data to human-readable format
 44        output = ""
 45        if self.stage >= 3:
 46            output += rarity_list[self.rarity] + " "
 47        if self.mutation != 0:
 48            output += mutation_list[self.mutation] + " "
 49        if self.stage >= 4:
 50            output += color_list[self.color] + " "
 51        output += stage_list[self.stage] + " "
 52        if self.stage >= 2:
 53            output += species_list[self.species] + " "
 54        return output.strip()
 55
 56    def rarity_check(self):
 57        # Generate plant rarity
 58        CONST_RARITY_MAX = 256.0
 59        rare_seed = random.randint(1,CONST_RARITY_MAX)
 60        common_range =    round((2.0/3)*CONST_RARITY_MAX)
 61        uncommon_range =  round((2.0/3)*(CONST_RARITY_MAX-common_range))
 62        rare_range =      round((2.0/3)*(CONST_RARITY_MAX-common_range-uncommon_range))
 63        legendary_range = round((2.0/3)*(CONST_RARITY_MAX-common_range-uncommon_range-rare_range))
 64
 65        common_max = common_range
 66        uncommon_max = common_max + uncommon_range
 67        rare_max = uncommon_max + rare_range
 68        legendary_max = rare_max + legendary_range
 69        godly_max = CONST_RARITY_MAX
 70
 71        if 0 <= rare_seed <= common_max:
 72            return 0
 73        elif common_max < rare_seed <= uncommon_max:
 74            return 1
 75        elif uncommon_max < rare_seed <= rare_max:
 76            return 2
 77        elif rare_max < rare_seed <= legendary_max:
 78            return 3
 79        elif legendary_max < rare_seed <= godly_max:
 80            return 4
 81
 82    def dead_check(self):
 83        # if it has been >5 days since watering, sorry plant is dead :(
 84        self.time_delta_watered = int(time.time()) - self.last_water
 85        if self.time_delta_watered > (5 * water_duration):
 86            self.dead = True
 87        return self.dead
 88
 89    def water_check(self):
 90        self.time_delta_watered = int(time.time()) - self.last_water
 91        if self.time_delta_watered <= (water_duration):
 92            if not self.watered_24h:
 93                self.watered_24h = True
 94            return True
 95        else:
 96            self.watered_24h = False
 97            return False
 98
 99    def mutate_check(self):
100        # Create plant mutation
101        # Increase this # to make mutation rarer (chance 1 out of x each second)
102        CONST_MUTATION_RARITY = 20000
103        mutation_seed = random.randint(1,CONST_MUTATION_RARITY)
104        if mutation_seed == CONST_MUTATION_RARITY:
105            # mutation gained!
106            mutation = random.randint(0,len(self.mutation_list)-1)
107            if self.mutation == 0:
108                self.mutation = mutation
109                return True
110        else:
111            return False
112
113    def growth(self):
114        # Increase plant growth stage
115        if self.stage < (len(stage_list)-1):
116            self.stage += 1
117
118    def water(self):
119        # Increase plant growth stage
120        if not self.dead:
121            self.last_water = int(time.time())
122            self.watered_24h = True
123
124    def start_over(self):
125        # After plant reaches final stage, given option to restart
126        # increment generation only if previous stage is final stage and plant
127        # is alive
128        if not self.dead:
129            next_generation = self.generation + 1
130        else:
131            # Should this reset to 1? Seems unfair.. for now generations will
132            # persist through death.
133            next_generation = self.generation
134        self.kill_plant()
135        
136        self.__init__(self.owner, next_generation)
137
138    def kill_plant(self):
139        self.dead = True
140
141def find_stage(plant: Plant):
142    now = int(time.time())
143    
144    res1 = min(now - plant.last_water, water_duration)
145    res2 = min(plant.last_update - plant.last_water, water_duration)
146    
147    plant.points += max(0, res1 - res2) # max() not necessary but just in case
148    
149    print("generation bonus: ", plant.generation_bonus, ". increase: ", res1 - res2, "max: ", water_duration)
150    plant.last_update = now
151    
152    stages = tuple(ti / plant.generation_bonus for ti in plant.life_stages) # bonus is applied to stage thresholds
153    count = 0
154    closest = None
155    delta = plant.points
156    
157    for n in stages:
158        if (n <= delta and (closest is None or (delta - n) < (delta - closest))):
159            closest = n
160            count += 1
161            
162    print("plant is in stage", count, "because it passed", closest, "seconds of life")
163    return count
164    
165def get_plant_water(plant: Plant):
166    water_delta = time.time() - plant.last_water
167    water_left_pct = max(0, 1 - (water_delta/water_duration)) # 24h
168    water_left = int(math.ceil(water_left_pct * 10))
169    return f"{water_left * '🟦'}{'⬛' * (10 - water_left)} {str(int(water_left_pct * 100))}% "
170
171def get_plant_description(plant: Plant):
172    output_text = ""
173    this_species = species_list[plant.species]
174    this_color = color_list[plant.color]
175    this_stage = plant.stage
176    
177    if plant.dead:
178            this_stage = 99
179    try:
180        description_num = random.randint(0,len(stage_descriptions[this_stage]) - 1)
181    except KeyError as e:
182        print(e)
183        description_num = 0
184    # If not fully grown
185    if this_stage <= 4:
186        # Growth hint
187        if this_stage >= 1:
188            last_growth_at = plant.life_stages[this_stage - 1]
189        else:
190            last_growth_at = 0
191        ticks_since_last = plant.ticks - last_growth_at
192        ticks_between_stage = plant.life_stages[this_stage] - last_growth_at
193        if ticks_since_last >= ticks_between_stage * 0.8:
194            output_text += "You notice your plant looks different.\n"
195
196    output_text += get_stage_description(this_stage, description_num, this_species, this_color) + "\n"
197
198    # if seedling
199    if this_stage == 1:
200        species_options = [species_list[plant.species],
201                species_list[(plant.species+3) % len(species_list)],
202                species_list[(plant.species-3) % len(species_list)]]
203        random.shuffle(species_options)
204        plant_hint = "It could be a(n) " + species_options[0] + ", " + species_options[1] + ", or " + species_options[2]
205        output_text += plant_hint + ".\n"
206
207    # if young plant
208    if this_stage == 2:
209        if plant.rarity >= 2:
210            rarity_hint = "You feel like your plant is special."
211            output_text += rarity_hint + ".\n"
212
213    # if mature plant
214    if this_stage == 3:
215        color_options = [color_list[plant.color],
216                color_list[(plant.color+3) % len(color_list)],
217                color_list[(plant.color-3) % len(color_list)]]
218        random.shuffle(color_options)
219        return "You can see the first hints of " + color_options[0] + ", " + color_options[1] + ", or " + color_options[2]
220
221    return output_text
222
223def get_plant_art(plant: Plant):
224    
225    if plant.dead == True:
226        filename = 'rip.txt'
227    elif datetime.date.today().month == 10 and datetime.date.today().day == 31:
228        filename = 'jackolantern.txt'
229    elif plant.stage == 0:
230        filename = 'seed.txt'
231    elif plant.stage == 1:
232        filename = 'seedling.txt'
233    elif plant.stage == 2:
234        filename = plant_art_list[plant.species]+'1.txt'
235    elif plant.stage == 3 or plant.stage == 5:
236        filename = plant_art_list[plant.species]+'2.txt'
237    elif plant.stage == 4:
238        filename = plant_art_list[plant.species]+'3.txt'
239
240    # Prints ASCII art from file at given coordinates
241    this_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "art")
242    this_filename = os.path.join(this_dir, filename)
243    this_file = open(this_filename,"r")
244    this_string = this_file.read()
245    this_file.close()
246    return this_string
247
248def get_plant_info(plant: Plant):
249    
250    return f'''
251{get_plant_description(plant)}
252```{get_plant_art(plant)}```
253{plant.parse_plant()}
254
255{get_plant_water(plant)}
256
257Points: {plant.points}
258Bonus: x{plant.generation_bonus - 1}
259'''