class Archer(Unit): teamed_body_frames = images.load_teamed_anim("archer_body", 2) teamed_arm_frames = images.load_teamed_anim("archer_arm", 3) def __init__(self, pos, team): set_actor_skin(self, team) self.lap_time = 360 self.fight_windup_time = 360 + 180 # Exactly Golem regen speed super().__init__(pos, team) def get_locs_in_range(self): ret = [] # Firstly, target anyone adjacent. # This is almost elegant, a list of angles offsets, as from MeleeUnit. for x in [0, -1, 1, -2, 2, -3]: angle = (6 + x * self.bias_flip + self.bias_angle) % 6 ret.append(vec.add(self.pos, vec.units[angle])) # Next, target people at range 2. # This should favor the space "ahead" of us (according to bias_angle) # and work back (in even pairs, resolving by bias_flip); # unfortuately, I can't tink of an elegant way to do this :( range_2_vecs = [(2, 0), (1, 1), (2, -1), (0, 2), (2, -2), (-1, 2), (1, -2), (-2, 2), (0, -2), (-2, 1), (-1, -1), (-2, 0)] for v in range_2_vecs: ret.append( vec.add(self.pos, vec.transform(v, self.bias_flip, self.bias_angle))) return ret
class Sword(MeleeUnit): teamed_body_frames = images.load_teamed_anim("sword_body", 2) teamed_arm_frames = images.load_teamed_anim("sword_arm", 3) def __init__(self, pos, team): set_actor_skin(self, team) self.lap_time = 360 self.fight_windup_time = 180 super().__init__(pos, team)
class Golem(MeleeUnit): teamed_torso_frames = images.load_teamed_anim("golem_torso", 2) teamed_arm_frames = images.load_teamed_anim("golem_arm", 3) teamed_toes = images.load_teamed("units", "golem_toes.png") def __init__(self, pos, team): self.torso_frames = self.teamed_torso_frames[team] self.arm_frames = self.teamed_arm_frames[team] self.toes = self.teamed_toes[team] self.lap_time = 450 # Base x1.25 self.fight_windup_time = 180 self.recover_time = 360 + 180 # Exactly archer reload speed self.wounded = False super().__init__(pos, team) def draw(self, pos): # Might make this the standard drawing function at some pt frame = int(not self.wounded) self._draw(pos, self.torso_frames[frame]) if 0 == self.cooldowns[cd_move]: self._draw(pos, self.toes) frame = (self.fight_windup_time - self.cooldowns[cd_fight]) * 2 // self.fight_windup_time self._draw(pos, self.arm_frames[frame]) def should_chill(self): if self.wounded: if not self.charge(cd_recover): return True # Most other things happen in a custom task, but heck, # it's not like this is racing any other conditions # or needs to be exclusive with anything else self.wounded = False self.dirty() self.cooldowns[cd_recover] = self.recover_time self.charge(cd_fight) and self.charge(cd_move) return True def take_hit(self): if self.wounded: tasks.Die(self) else: self.dirty() self.wounded = True self.ai.queue_immediately() def move(self, pos): super().move(pos) self.cooldowns[cd_recover] = self.recover_time def fight(self, target): super().fight(target) self.cooldowns[cd_recover] = self.recover_time
class Berserk(MeleeUnit): teamed_body_frames = images.load_teamed_anim("berserk_body", 2) teamed_arm_frames = images.load_teamed_anim("berserk_arm", 3) def __init__(self, pos, team): set_actor_skin(self, team) # 80% of base cooldown times self.lap_time = 288 self.fight_windup_time = 144 self.dying = False super().__init__(pos, team) def fight(self, target): self.has_task(tasks.Hit(target)) self.has_task(tasks.Hit(target)) def take_hit(self): if self.dying: return self.dying = True tasks.Die(self, self.fight_windup_time, tasks.SLOW_PATIENCE)
class Exploder(Unit): teamed_toes = images.load_teamed("units", "exploder_toes.png") teamed_torso_frames = images.load_teamed_anim("exploder_torso", 2) def __init__(self, pos, team): self.torso_frames = self.teamed_torso_frames[team] self.toes = self.teamed_toes[team] # Same move speed as Berserker self.lap_time = 288 self.fight_windup_time = 0 self.dying = False super().__init__(pos, team) def draw(self, pos): frame = int(not self.dying) self._draw(pos, self.torso_frames[frame]) if 0 == self.cooldowns[cd_move]: self._draw(pos, self.toes) def take_hit(self): if self.dying: return self.dying = True self.dirty() tasks.Die(self, self.lap_time, tasks.SLOW_PATIENCE) def die(self): if self.dead: # This is possible if we entered a castle while dying, # which immediately disintegrates us. # Usually this isn't a problem, but explode() assumes # a not-None position. Of course, I could check that # directly, but I'd rather it fail loudly if the # assumption that living Entities have a position is # violated. return corpse = ExploderCorpse(self.pos, self.team) tasks.schedule(tasks.Move(corpse, None), 90) pos = self.pos tasks.Lambda(lambda: explode(pos), 60, tasks.THINK_PATIENCE) self.disintegrate() def get_locs_in_range(self): return []