class UIInteractiveElement: def __init__(self): self.name = None self.assigned_item = None self.box = None self.select_timer = ActionTimer("Click", 0.2) self.animations = {} self.anim = 0 self.selected = False self.already_over = False self.draw_x, self.draw_y = 0, 0 def update(self, mpos, mpress, at_mouse, can, le): self.select_timer.update() for a in self.animations.values(): a.update() x, y = mpos x, y = x - self.draw_x, y - self.draw_y mouseover = False curr_select = False if self.box.collidepoint((x, y)): if mpress[0] == 0: self.already_over = True mouseover = True if self.select_timer.ticked and mpress[0] == 1 and self.already_over and (can or le): curr_select = True self.selected = True - self.selected self.select_timer.reset() self.already_over = False else: self.already_over = False if self.selected: self.anim = self.animations["sel"] else: self.anim = self.animations["desel"] select = False if curr_select and self.selected == True: select = True return mouseover, select def get_frame(self): return self.anim.get_frame()
class Collar: def __init__(self, spawn_pos, bub_json): self.pos = spawn_pos self.frames = {"0": 292, "1": 293} self.bubbles_paths = bub_json["Farmhouse"]["Collar"] self.load_bubble_images() self.bubble_frame = 0 self.bubble_timer = ActionTimer("", 1.5) self.should_draw_bub = False self.type = "collar" def load_bubble_images(self): self.bubbles_imgs = {} for k, e in self.bubbles_paths.items(): i = pygame.image.load("speech/bubbles/{0}".format(e)) self.bubbles_imgs[k] = i def get_frame(self): return self.frames["0"] def get_bubble_frame(self): return self.bubbles_imgs[str(self.bubble_frame)] def update(self, g_obj, mpos, mpress, ui): self.bubble_timer.update() if in_range(self.pos, g_obj.mc.pos, 2): if self.should_draw_bub == False: self.bubble_timer.reset() self.bubble_frame = 0 self.should_draw_bub = True else: self.should_draw_bub = False if self.bubble_timer.ticked: self.bubble_timer.reset() self.bubble_frame += 1 if self.bubble_frame >= len(self.bubbles_imgs.keys()): self.bubble_frame = 0
class Menu: def __init__(self, g_obj): self.menu_items = [] # instantiate buttons self.menu_items.append(NewGameButton()) self.menu_items.append(ContinueButton()) self.menu_items.append(ExitButton()) self.menu_items.reverse() self.timer = ActionTimer("", 0.25) def update(self, mpos, mpress, ui): self.timer.update() if mpress[0] == 0 or not ui.get_selected()=="in game menu": return for mi in self.menu_items: if mi.rect == None: continue if mi.rect.collidepoint(mpos) and self.timer.ticked: mi.on_mouse_click() self.timer.reset()
class Music: # plays music according to stage. # doesn't always play something; # think Minecraft - it only plays # a song occasionally def __init__(self): self.songs = {} self.song_playing = False self.intermezzo = False self.intermezzo_range = (10, 60) self.timer = ActionTimer("silence timer", 10) self.fade_timer = ActionTimer("fade", 10) self.current_stage = None self.stage_conversion = {0: "farm", 1: "bubbas", 2: "cave", 3: "park"} self.rel = None self.fade_type = None self.muted = False def play_new_song(self): stage_actual = self.stage_conversion[self.current_stage] song = choice(self.songs[stage_actual]) pygame.mixer.music.load(self.rel + song) pygame.mixer.music.play() def update(self): self.timer.update() self.fade_timer.update() if self.intermezzo: if self.timer.ticked: self.intermezzo = False else: if self.song_playing == False: self.play_new_song() self.song_playing = True pygame.mixer.music.set_volume(0) self.fade_timer.reset() self.fade_type = 1 else: if not pygame.mixer.music.get_busy(): self.song_playing = False self.intermezzo = True intermezzo_time = randint(*self.intermezzo_range) self.timer.dt = intermezzo_time self.timer.reset() else: if not self.fade_timer.ticked: if self.fade_type == 1: volume = self.fade_timer.get_progress() elif self.fade_type == -1: volume = 1 - self.fade_timer.get_progress() pygame.mixer.music.set_volume(volume) else: if pygame.mixer.music.get_volume() != 1: pygame.mixer.music.set_volume(1) song_pos_secs = pygame.mixer.music.get_pos() / 1000 if 90 - self.fade_timer.dt <= song_pos_secs: self.fade_timer.reset() self.fade_type = -1 if self.muted: pygame.mixer.music.set_volume(0)
class Controller: def __init__(self): self.state = "idling" self.last_action = "wait" self.last_dest_pos = None self.action_delay = ActionTimer("", 0.05) self.controller_type = None self.unit = None self.spot_range = 15 self.con_act = {"do": "nothing"} self.l_con_act = None self.l_move_con_act = None def action(self, c_ap, c_hp_self, m_hp_self, c_pos_enemy, c_hp_enemy, u_state, c_state, l_action, c_type): if u_state in ("dying", "dead") or u_state != "idle": return "wait", c_state, {} flee_per = 0.3 if c_hp_self / m_hp_self < flee_per: c_state = "fleeing" else: pass if c_ap < 1 and c_state != "fleeing": return "pass", c_state, {} if c_state == "fleeing": available_abis = get_available_abis( self.unit, c_ap, ["heal", "buff"]) # returns a list of cast-able abilities if len(available_abis) == 0: return "walk", c_state, {"walk_command": "away_from_enemy"} else: abi_choice = choice(available_abis) return "cast", c_state, {"cast_ability": abi_choice} pass # check if we have heal/buff available, then go into that state # otherwise stay in this state and keep running away. elif c_state == "idling": if in_range(self.unit.pos, c_pos_enemy, self.spot_range): c_state = "approaching" return "wait", c_state, {} else: return "pass", c_state, {} pass # check if enemy is within range, if so- go out of idle state. elif c_state == "approaching": cur_max_range_self = get_max_range_of(self.unit) if in_range(self.unit.pos, c_pos_enemy, cur_max_range_self): c_state = "attacking" return "wait", c_state, {} else: return "walk", c_state, {"walk_command": "toward_enemy"} pass # if you're too far away from enemy to attack - approach; walk toward # otherwise; go into attack state. elif c_state == "kiting": pass # if you're ranged and your range is greater than the enemies, then # move a little back, otherwise go into a state of attacking. elif c_state == "attacking": available_abis = get_available_abis(self.unit, c_ap, ["ranged", "melee"]) in_range_abis = get_in_range_abis(available_abis, self.unit, c_pos_enemy) in_range_attacks = get_in_range_atks(self.unit, c_pos_enemy) if len(in_range_abis) != 0 and False: # ignore abilites for now use_abi = choice(in_range_abis) return "cast", c_state, {"use_ability": use_abi} elif len(in_range_attacks) != 0: use_weapon = choice(in_range_attacks) return "smack", c_state, {"use_weapon": use_weapon} else: c_state = "approaching" return "wait", c_state, {} pass # here we can use a ranged or melee ability, or ranged or melee basic attack. return "wait", c_state, {} def update(self, g_obj, mc, mpos, mpress, ui, fighting): self.action_delay.update() con_act = {"do": "nothing"} if self.unit.end_turn == True: return elif self.action_delay.ticked: c_ap = self.unit.ap.get_ap() m_hp_self = self.unit.get_health() dmg = self.unit.damage_taken c_hp_self = m_hp_self - dmg c_hp_enemy = mc.get_health() u_state = self.unit.state c_state = self.state l_action = self.last_action c_type = self.controller_type c_pos_enemy = mc.pos action, c_state, commands = self.action(c_ap, c_hp_self, m_hp_self, c_pos_enemy, \ c_hp_enemy, u_state, c_state, l_action, c_type) self.state = c_state self.l_action = action if action == "pass": self.unit.end_turn = True elif action == "wait": pass elif action == "walk": con_act["do"] = "walk" w_comm = commands["walk_command"] if w_comm == "away_from_enemy": dest_pos = get_walkable_pos(mc.pos, self.unit, g_obj, eval_func=max) elif w_comm == "toward_enemy": dest_pos = get_walkable_pos(mc.pos, self.unit, g_obj, eval_func=min) con_act["dest"] = dest_pos #self.state = "attacking" if dest_pos == self.last_dest_pos and w_comm == "away_from_enemy": self.unit.end_turn = True #self.con_act = {"do": "nothing"} self.last_dest_pos = dest_pos self.action_delay.reset() self.l_move_con_act = con_act elif action == "cast": pass elif action == "smack": con_act["do"] = "smack" weapon = commands["use_weapon"] dest_pos = c_pos_enemy con_act["dest"] = dest_pos con_act["weapon"] = weapon con_act["at_mouse"] = {} con_act["at_mouse"]["unit"] = mc con_act["at_mouse"]["units"] = get_units_list_at( g_obj.units, dest_pos) con_act["at_mouse"]["mapped"] = dest_pos self.action_delay.reset() self.con_act = con_act else: self.con_act = {"do": "nothing"} # 5 action types # smack; use attack - ranged / melee; depending on its weapon, range to enemy, and cds, it will try to attack # cast; use ability (4 ability categories) # - heal # - buff # - ranged # - melee # walk; move somewhere, either toward player (melee attack / ranged attack but too far) or away from player (kiting / fleeing) # wait; wait until unit finishes its' current action, or enemy is in sight # pass; end turn # state types # idle # approaching # kiting # attacking # heal/buff # fleeing
class Bed: def __init__(self, room, rw, rh, sound): self.room = room self.rw, self.rh = rw, rh self.pos = None, None self.set_pos() self.has_used = False self.done_resting = False self.sound = sound self.rest_timer = ActionTimer("", 2) def set_pos(self): cox, coy = 13, 4 cw, ch = 6, 6 room = self.room gx, gy = room.grid_pos ox, oy = gx * self.rw, gy * self.rh self.pos = ox + cox + cw // 2 - 0.5, oy + coy + ch // 2 - 0.5 def close_to_bed(self, g_obj, mpos): return in_range(self.pos, g_obj.mc.pos, 2) def update(self, g_obj, mpos, mpress, ui, fighting): if fighting: return self.rest_timer.update() # if not fighting: # return #if not self.open_timer.ticked: # return #if not ui.get_selected() == None: # return if self.has_used and self.rest_timer.ticked and not self.done_resting: self.done_resting = True g_obj.mc.labels.add_label("Rested", g_obj.mc.pos[0], g_obj.mc.pos[1], delay=0) g_obj.mc.heal("percentage", 1, delay=0.5) am = ui.at_mouse """ m = am["mapped"] if self.check_mouseover(g_obj, mpos): if self.is_closed == True: self.is_closed = False self.sound.play_sound_now("door open") elif self.is_closed == False: self.is_closed = True self.sound.play_sound_now("door close") self.open_timer.reset() """ m = am["mapped"] if self.close_to_bed(g_obj, mpos) and not self.has_used: g_obj.mc.current_bed = self g_obj.mc.state = "resting" self.sound.play_sound_now("rest") self.has_used = True self.rest_timer.reset()