def __init__(self, window, map, startp, endp): self.window = window self.bg = retro.Stage(asset(map)) self.ui = UI(self.window) self.spawner = Spawner(self.window, self.bg, startp) self.exit = retro.Sprite.from_path(asset("sortie.png")) self.exit.rect.topleft = endp
class Mine: ICON = retro.Image(asset("ui_mine.png")) def __init__(self, lemming): self.lemming = lemming def start(self): self.enabled = False return self def run(self): if not self.enabled: self.lemming.start_animation("MINE") self.enabled = True if not self.lemming.animations.finished: return self.lemming.bg.original.draw_circle( color=retro.BLACK, center=self.lemming.rect.center, radius=18, ) dx = self.lemming.actions.walk.dx self.lemming.rect.move_ip(3 * dx, 3) self.lemming.start_animation("MINE")
class Bomb: ICON = retro.Image(asset("ui_bomb.png")) def __init__(self, lemming): self.lemming = lemming def start(self): self.ticker = retro.Ticker(end=135) self.explode = False return self def run(self): if not self.explode: self.lemming.start_animation("BOMB") self.explode = True self.lemming.bg.original.draw_circle( color=retro.BLACK, center=self.lemming.bounding_rect.midbottom, radius=20, ) elif self.lemming.animations.finished: self.lemming.kill() def draw_ticker(self): if self.explode: return window = self.lemming.window ticker_surface = retro.Sprite(window.fonts[0].render( text=f"{self.ticker.remaining}", color=retro.WHITE, )) ticker_surface.rect.midbottom = self.lemming.bounding_rect.midtop ticker_surface.draw(window)
class Build: ICON = retro.Image(asset("ui_build.png")) def __init__(self, lemming): self.lemming = lemming self.count = 0 @property def finished(self): return (self.count >= 12) def start(self): self.lemming.start_animation("BUILD") return self def run(self): if not self.lemming.animations.finished: return dx = self.lemming.actions.walk.dx rect = self.lemming.rect.copy() rect.size = (15, 3) rect.top = self.lemming.rect.bottom - rect.height if (dx > 0): rect.left = self.lemming.rect.right - (rect.width // 2) elif (dx < 0): rect.left -= rect.width // 2 self.lemming.bg.original.draw_rect(retro.GREY, rect) self.lemming.rect.move_ip(dx * rect.width // 2, -rect.height) self.count += 1 self.lemming.start_animation("BUILD")
class Stop: ICON = retro.Image(asset("ui_stop.png")) def __init__(self, lemming): self.lemming = lemming def start(self): self.lemming.start_animation("STOP") return self def run(self): pass
class Float: ICON = retro.Image(asset("ui_float.png")) def __init__(self, lemming): self.lemming = lemming def start(self): self.enabled = False return self def run(self): if not self.enabled: self.lemming.start_animation("FLOAT") self.enabled = True self.lemming.rect.move_ip(0, 1)
class DigV: ICON = retro.Image(asset("ui_digv.png")) def __init__(self, lemming): self.lemming = lemming def start(self): self.lemming.start_animation("DIGV") return self def run(self): dx = self.lemming.actions.walk.dx rect = self.lemming.rect.copy() rect.top = rect.bottom - 1 rect.left += 10 if dx > 0 else 0 rect.size = (20, 2) self.lemming.bg.original.draw_rect(retro.BLACK, rect) self.lemming.rect.move_ip(0, 1)
class DigH: ICON = retro.Image(asset("ui_digh.png")) def __init__(self, lemming): self.lemming = lemming def start(self): self.enabled = False return self def run(self): if not self.enabled: self.lemming.start_animation("DIGH") self.enabled = True dx = self.lemming.actions.walk.dx rect = self.lemming.rect.copy() rect.left = rect.right - 15 if dx > 0 else rect.left - 1 rect.width = 16 self.lemming.bg.original.draw_rect(retro.BLACK, rect) self.lemming.rect.move_ip(dx, 0)
class Lemming(retro.Sprite): IMG = retro.Image(asset("lemming.png")) def __init__(self, window, bg, position): self.window = window self.bg = bg revrange = lambda start, end: range(end - 1, start - 1, -1) retro.Sprite.__init__( self=self, image=self.IMG, animations=retro.Animations( frame_size=(30, 30), period=4, WALK_L=(range(0, 8), 0), WALK_R=(revrange(0, 8), 12), WALKA_L=(range(0, 8), 11), WALKA_R=(revrange(0, 8), 23), FALL_L=(range(0, 4), 1), FALL_R=(revrange(0, 4), 13), FLOAT_L=(range(0, 6), 3), FLOAT_R=(revrange(0, 6), 15), STOP_L=(range(0, 16), 4), STOP_R=(revrange(0, 16), 16), BOMB_L=(range(0, 14), 5), BOMB_R=(revrange(0, 14), 17), BUILD_L=(range(0, 16), 6), BUILD_R=(revrange(0, 16), 18), DIGV_L=(range(0, 16), 7), DIGV_R=(revrange(0, 16), 19), DIGH_L=(range(0, 12), 8), DIGH_R=(revrange(0, 12), 20), MINE_L=(range(0, 17), 9), MINE_R=(revrange(0, 17), 21), DEAD_L=(range(0, 16), 10), DEAD_R=(revrange(0, 16), 22), ), ) self.rect.topleft = position self.actions = Actions(self) self.state = None @property def bounding_rect(self): dx = self.actions.walk.dx rect = self.rect.copy() rect.width //= 2 if dx > 0: rect.left += rect.width return rect def set_animation(self, name): dx = self.actions.walk.dx if dx < 0: self.animations.set(f"{name}_L") elif dx > 0: self.animations.set(f"{name}_R") else: self.animations.set("NONE") def start_animation(self, name): dx = self.actions.walk.dx if dx < 0: self.animations.start(f"{name}_L") elif dx > 0: self.animations.start(f"{name}_R") else: self.animations.start("NONE") def collisions(self, surface): directions = retro.Collisions.pixel_mid(surface, self.bounding_rect, retro.BLACK).invert() outside = (None in directions) directions.replace(None, True) fall = not directions.down dx = self.actions.walk.dx side = (directions.vec[0] == dx) return types.SimpleNamespace( outside=outside, fall=fall, side=side, ) def update(self, new_action): collisions_all = self.collisions(self.bg.image) collisions_bg = self.collisions(self.bg.original) if self.state is None: self.state = self.actions.fall.start() elif self.state == self.actions.walk: if collisions_all.fall: self.state = self.actions.fall.start() elif new_action: self.state = self.actions.from_class(new_action).start() else: self.actions.walk.run(collisions_all) elif self.state == self.actions.fall: if collisions_all.fall: self.actions.fall.run() elif self.actions.fall.dead: self.state = self.actions.dead.start() else: self.actions.fall.clamp() self.state = self.actions.walk.start() elif self.state == self.actions.float: if collisions_all.fall: self.actions.float.run() elif self.actions.float.enabled: self.state = self.actions.walk.start() else: self.actions.walk.run(collisions_all, pending_action=True) elif self.state == self.actions.stop: self.actions.stop.run() elif self.state == self.actions.bomb: if self.actions.bomb.ticker.finished or collisions_all.fall: self.actions.bomb.run() else: self.actions.walk.run(collisions_all, pending_action=True) elif self.state == self.actions.build: if self.actions.build.finished or collisions_bg.side: self.state = self.actions.walk.start() else: self.actions.build.run() elif self.state == self.actions.digv: if (not collisions_bg.fall) and (not collisions_bg.outside): self.actions.digv.run() else: self.state = self.actions.walk.start() elif self.state == self.actions.digh: if (collisions_bg.side and (not collisions_bg.fall) and (not collisions_bg.outside)): self.actions.digh.run() elif collisions_all.fall or self.actions.digh.enabled: self.state = self.actions.walk.start() else: self.actions.walk.run(collisions_all, pending_action=True) elif self.state == self.actions.mine: if (collisions_bg.side and (not collisions_bg.fall) and (not collisions_bg.outside)): self.actions.mine.run() elif collisions_all.fall or self.actions.mine.enabled: self.state = self.actions.walk.start() else: self.actions.walk.run(collisions_all, pending_action=True) elif self.state == self.actions.dead: self.actions.dead.run() def draw_bg(self): if self.state == self.actions.stop: retro.Sprite.draw(self, self.bg.image) def draw_screen(self): if self.state == self.actions.stop: return elif self.state == self.actions.bomb: self.actions.bomb.draw_ticker() retro.Sprite.draw(self, self.window)