async def run_bouncing_bits(self): self.set_timeout(10.0) pos1 = self.bullet_board.get_coords_at(-1, -1) speed1 = Vector(200, 100) pos2 = self.bullet_board.get_coords_at(-1, 10) speed2 = Vector(-200, 100) t = 0.0 while True: await self.sleep_for(0.3) t += 0.3 k = (t * math.sin(t*4) + 1) / 2 r = 100.0 offset = Vector(0, -r*k) self.spawn( BouncingBit( bullet_board = self.bullet_board, texture = self.bullet_board.fight_script.textures[f'bit{rd.choice("01")}'], pos = copy(pos1) + offset, speed = copy(speed1), damage = 1, ) ) self.spawn( BouncingBit( bullet_board = self.bullet_board, texture = self.bullet_board.fight_script.textures[f'bit{rd.choice("01")}'], pos = copy(pos2) + offset, speed = copy(speed2), damage = 1, ) )
def _spawn_strike(self, row, col, **kwargs): self.spawn( Strike( bullet_board=self.bullet_board, pos=Vector(0, 0), speed=Vector(0, 0), location=self.bullet_board.get_coords_at(row, col), **kwargs, ), )
def _random_diameter(self): rect = self.bullet_board.get_rect() r = 0.5 * math.sqrt(rect.width ** 2 + rect.height ** 2) + 20.0 angle = random_between(0.0, math.pi * 2) offset = Vector(math.cos(angle), math.sin(angle)) * r center = Vector(*rect.center) first = center + offset second = center - offset return first, second
def move(self, delta: Vector): if self.are_controls_scripted() or self._can_move(delta): self._move_unchecked(delta) return eps = 1e-9 if abs(delta.x) > eps and abs(delta.y) > eps: if self._can_move(Vector(delta.x, 0.0)): self._move_unchecked(Vector(delta.x, 0.0)) elif self._can_move(Vector(0.0, delta.y)): self._move_unchecked(Vector(0.0, delta.y))
def _spawn_line(self, start, end): self.spawn( Line( bullet_board = self.bullet_board, pos = Vector(0, 0), speed = Vector(0, 0), damage = 4, start = start, end = end, thickness = 20, displayed_thickness = 8, ), unrestricted = True, )
def does_hit_at(self, pos): if self.is_in_warning_phase(): return False return any([ collide_beam_and_point( (self.location - Vector(5000, 0), self.location + Vector(5000, 0), self.thickness), pos, ), collide_beam_and_point( (self.location - Vector(0, 5000), self.location + Vector(0, 5000), self.thickness), pos, ), ])
def _draw_strike_phase(self, destination): thickness = self._get_current_displayed_thickness() pg.draw.line( destination, (255, 255, 255), (self.location - Vector(5000, 0)).ints(), (self.location + Vector(5000, 0)).ints(), thickness, ) pg.draw.line( destination, (255, 255, 255), (self.location - Vector(0, 5000)).ints(), (self.location + Vector(0, 5000)).ints(), thickness, )
def _spawn_line(self, r1, c1, r2, c2): start = self.bullet_board.get_coords_at(r1, c1) end = self.bullet_board.get_coords_at(r2, c2) self.spawn( Line( bullet_board=self.bullet_board, pos=Vector(0, 0), speed=Vector(0, 0), damage=4, start=start, end=end, thickness=20, displayed_thickness=8, ), unrestricted=True, )
class Animator(Sprite): def __init__(self, sprite): super().__init__(Sprite) self.sprite = sprite self.orig_pos = sprite.pos self.elapsed_time = 0.0 async def animate(self): get_game().current_game_mode.spawn(self) await wait_for_event('hit_animation_finished') self.sprite.pos = self.orig_pos def calculate_new_pos(self): tanh3 = math.tanh(3) t = self.elapsed_time / self.length k = 0.5 * (tanh3 - math.tanh(6 * t - 4)) * math.sin(80 * t) / tanh3 offset = self.half_amplitude * k return self.orig_pos + offset def draw(self, destination): del destination def update(self, time_delta): self.elapsed_time += time_delta new_pos = self.calculate_new_pos() self.sprite.pos = new_pos def is_alive(self): return self.elapsed_time < self.length def on_kill(self): get_event_manager().raise_event('hit_animation_finished') length = 0.8 half_amplitude = Vector(20.0, 3.0)
async def process_enemy_attack(self): await super().process_enemy_attack() self._num_attacks += 1 if self._num_attacks == 3: flate_texture = AnimatedTexture( [ load_texture(Path('.') / 'assets' / 'textures' / 'flate' / 'fight.png', scale=4), ], fps=1, ) flate = TexturedWalkingSprite( pos=Vector(-100, 100), left=flate_texture, right=flate_texture, front=flate_texture, back=flate_texture, speed=200.0, ) self.spawn(flate) await flate.walk_x(300.0) await display_text( load_text('fight/lyceum/literallia/flate_intervention')) await flate.walk_x(-300.0) flate.kill() give(get_inventory(), 'nonsense')
async def main(*args, root, **kwargs): game = get_game() room = game.overworld.room game.overworld.freeze() room.named_objects['grumpylook'].kill() texture = AnimatedTexture( [load_texture(root / 'grumpylook' / 'overworld.png')], fps=1) grumpy = TexturedWalkingSprite( pos=Vector(840, 360), left=texture, right=texture, front=texture, back=texture, speed=200.0, ) room.spawn(grumpy) await display_text(load_text('overworld/lyceum_hall/grumpylook/wait/1')) await grumpy.walk_x(-620) await display_text(load_text('overworld/lyceum_hall/grumpylook/wait/2')) await grumpy.walk_x(-240) grumpy.kill() get_state()['grumpylook_met'] = True game.overworld.unfreeze()
def __init__(self, pages: List[TextPage], on_finish: Callable = lambda: None): super().__init__(Vector(0, 0)) # TODO: get rid of `game` as an argument (and property) and use get_game() instead self.pages = pages self.page_index = -1 self.on_finish_callback = on_finish
def update(self, time_delta): delta = Vector(self.moving_x, self.moving_y) * (self.speed * time_delta) self.move(delta) if self._is_walking() and self._should_stop(): assert self._stop_event is not None get_event_manager().raise_event(self._stop_event, None) self._stop_event = None
def random_momentum(self): speed = self.random_between(250.0, 300.0) angle_range = math.pi / 12.0 angle = self.random_between(math.pi / 2.0 - angle_range, math.pi / 2.0 + angle_range) direction = Vector(math.cos(angle), -math.sin(angle)) momentum = direction * speed return momentum
def _spawn_triangle(self): pi3 = math.pi / 3 angle = rd.choice([0, pi3, 2 * pi3, 3 * pi3, 4 * pi3, 5 * pi3]) direction = Vector(math.cos(angle), math.sin(angle)) angle_margin = 1.0 spawn_angle = rd.uniform(angle - angle_margin, angle + angle_margin) spawn_radius = 300 coords = Vector(*self.bullet_board.get_rect().center) spawn_pos = coords - Vector(math.cos(spawn_angle), math.sin(spawn_angle)) * spawn_radius velocity = 200 self.spawn( Triangle( bullet_board=self.bullet_board, pos=spawn_pos, speed=direction * velocity, damage=3, texture=self.bullet_board.fight_script.textures['triangle'], ))
async def run_book(self): self.spawn( Book( bullet_board=self.bullet_board, pos=self.bullet_board.get_coords_at(-1, 8), speed=Vector(rd.randint(160, 220), rd.randint(160, 220)) * 1.3, damage=6, texture=self.bullet_board.fight_script.textures['book_bullet'], ), ) await self.wait_until_timeout()
async def main(*, root, script, **kwargs): global DEBUG_SKIP get_game().overworld.freeze() if not DEBUG_SKIP: await display_text( load_text('overworld/lyceum_entrance/flate-interact/1-crying')) await sleep(2) if not DEBUG_SKIP: await display_text( load_text( 'overworld/lyceum_entrance/flate-interact/2-flate-speech')) animation = load_animated_once_texture(root / 'flate' / 'disappear', scale=2) flate = get_game().overworld.room.named_objects['flate'] flate.texture = animation event_id, callback = make_callback() animation.on_finish = callback await wait_for_event(event_id) flate.kill() cariel_overworld = TexturedWalkingSprite( pos=Vector(400, -170), left=load_animated_texture(root / 'cariel' / 'left', scale=2), right=load_animated_texture(root / 'cariel' / 'right', scale=2), front=load_animated_texture(root / 'cariel' / 'front', scale=2), back=load_animated_texture(root / 'cariel' / 'back', scale=2), speed=120.0, ) get_game().overworld.room.spawn(cariel_overworld) await cariel_overworld.walk_y(260) if not DEBUG_SKIP: await display_text( load_text( 'overworld/lyceum_entrance/flate-interact/3-cariel-pre-fight')) await fight(load_enemy_battle_by_name('itt_test_cariel_tutorial')) if not DEBUG_SKIP: if get_state()['itt_test_tutorial'] == 'dead': await display_text( load_text( 'overworld/lyceum_entrance/flate-interact/4-cariel-post-fight-kill' )) else: await display_text( load_text( 'overworld/lyceum_entrance/flate-interact/4-cariel-post-fight-spare' )) await cariel_overworld.walk_y(-260) cariel_overworld.kill() get_game().overworld.unfreeze()
def _spawn_cariel_sprite(self): texture = AnimatedTexture([self.textures['cariel']], fps=1) self.cariel_sprite = TexturedWalkingSprite( pos = Vector(200, 200), left = texture, right = texture, front = texture, back = texture, speed = 200, ) self.spawn(self.cariel_sprite)
def _draw_warning_phase(self, destination): t = self.get_elapsed_time() % self.warning_blink_duration if t < self.warning_blink_duration / 2: color = (255, 0, 0) else: color = (255, 255, 0) pg.draw.line( destination, color, (self.location - Vector(5000, 0)).ints(), (self.location + Vector(5000, 0)).ints(), self.warning_thickness, ) pg.draw.line( destination, color, (self.location - Vector(0, 5000)).ints(), (self.location + Vector(0, 5000)).ints(), self.warning_thickness, )
async def run_basketballs(self): for r, c, vx, vy in [(2, 4, -150, 180), (5, 9, 200, -170), (8, 1, 160, 160)]: self.spawn( Ball( bullet_board = self.bullet_board, pos = self.bullet_board.get_coords_at(r, c), speed = Vector(vx, vy) * 1.5, damage = 3, texture = self.bullet_board.fight_script.textures['ball'], ), ) await self.wait_until_timeout()
async def walk(self, delta: Vector): assert self._target is None self._target = self.pos + delta direction = delta.normalized() self.set_moving(direction.x, direction.y) self._stop_event = get_event_manager().unique_id() await wait_for_event(self._stop_event) self.set_moving(0, 0) self.pos = self._target self._target = None
def _spawn_horizontal_bit(self): row = rd.randrange(0, 10) col = rd.choice([-1, 10]) pos = self.bullet_board.get_coords_at(row, col) self.spawn( Bit( bullet_board = self.bullet_board, texture = self.bullet_board.fight_script.textures[f'bit{rd.choice("01")}'], pos = pos, speed = Vector(200 if col == -1 else -200, 0), damage = 3, ) )
async def run_xs(self): while True: await self.sleep_for(0.2) row = -1 col = rd.randrange(0, 10) pos = self.bullet_board.get_coords_at(row, col) self.spawn( EquationBullet( bullet_board=self.bullet_board, texture=self.bullet_board.fight_script. textures['equation_bullet'], pos=pos, speed=Vector(0, 150), damage=3, ))
async def run_lambdas(self): while True: await self.sleep_for(0.15) row = rd.randrange(-5, 7) col = rd.choice([-1, 10]) pos = self.bullet_board.get_coords_at(row, col) self.spawn( EquationBullet( bullet_board=self.bullet_board, texture=self.bullet_board.fight_script. textures['lambda_bullet'], pos=pos, speed=Vector(150 if col == -1 else -150, 150), damage=2, ))
async def run_chaotic_lines(self): while True: await self.sleep_for(0.4) if rd.randint(0, 1) == 0: row = rd.randrange(0, 10) start = self.bullet_board.get_coords_at(row, -1) end = self.bullet_board.get_coords_at(row, 10) else: col = rd.randrange(0, 10) start = self.bullet_board.get_coords_at(-1, col) end = self.bullet_board.get_coords_at(10, col) self.spawn( Line( bullet_board=self.bullet_board, pos=Vector(0, 0), speed=Vector(0, 0), damage=5, start=start, end=end, thickness=20, displayed_thickness=8, ), unrestricted=True, )
async def run_letters(self): while True: await self.sleep_for(0.2) row = rd.randrange(0, 10) pos = self.bullet_board.get_coords_at(row, 10) self.spawn( LetterBullet( bullet_board=self.bullet_board, pos=pos, speed=Vector(-180, rd.randint(0, 150) - 15 * row), damage=4, texture=self.bullet_board.fight_script. textures['letter_bullet'], ), )
async def main(*, root, **kwargs): overworld = get_game().overworld if get_state()['lyceum_elevator_used']: overworld.freeze() await display_text(load_text('overworld/lyceum_5_right/elevator_1')) overworld.unfreeze() return overworld.freeze() elevator_open_texture = load_texture(root / 'elevator_open.png') elevator_open_sprite = TexturedSprite(pos=Vector(619, 126), texture=elevator_open_texture) overworld.room.spawn(elevator_open_sprite) await sleep(1) await display_text(load_text('overworld/lyceum_5_right/elevator_enter')) get_state()['lyceum_elevator_used'] = True overworld.load_room('lyceum_1_right') overworld.unfreeze()
def load(game: 'Game'): logger.info('Loading file {}', SAVE_PATH) state: dict = {} state.update(DEFAULTS) set_state(state) try: with SAVE_PATH.open('r') as f: data = json.load(f) state.update(data['state']) set_state(state) game.overworld = Overworld( game, data['overworld']['room'], Vector(*data['overworld']['player_pos']), ) except FileNotFoundError: logger.info('File does not exist, loading an empty save') except json.decoder.JSONDecodeError: logger.error( 'Save file is corrupt. Loading an empty save, but not overwriting the old file' ) game.current_game_mode = game.overworld
async def main(**kwargs): manager = madecs.SpawnerManager() manager.add_spawner(position=Vector(1105, 179), speed=Vector(-120, 120), interval=1.5) manager.add_spawner(position=Vector(-101, 894), speed=Vector(130, -140), interval=1.0) manager.add_spawner(position=Vector(969, 1012), speed=Vector(-200, -200), interval=0.7) await madecs.setup(manager)
def get_coords_at(self, row: int, col: int) -> Vector: x, y = self.get_rect_at(row, col).center return Vector(x, y)