예제 #1
0
 def hit_wall(x, y):
     return (
         state.board.outside(x, y)
         or is_wall(state.board.get(x, y))
         or dist(state.player.pos, (x, y)) > state.max_range
         or is_door(state.board.get(x, y))
     )
예제 #2
0
    def update(self, state, end_fn):
        enemies = sorted(
            [
                e
                for e in state.enemies
                if e.square in state.visible
                and dist(state.player.pos, e.pos) < 5
            ],
            key=lambda e: dist(e.pos, state.player.pos),
        )
        if not enemies:
            state.text_box = misc.TextBox(
                "thunder", "There is no one in range"
            )
            target = None
        else:
            target = random.choice(enemies)

        state.active_tool = None
        if target:
            state.player.thunder(state, state.player, target, end_fn)
예제 #3
0
def rwalk(a, b):
    d = int(dist(a, b) / CELL_SIZE) + 2
    path = list(tween.tween(a, b, d))

    def _distort(p):
        x, y = p
        delta = random.gauss(0, CELL_SIZE / 3)
        nx, ny = normalize((y, -x))
        dx = nx * delta
        dy = ny * delta

        return x + dx, y + dy

    return [_distort(p) for p in path[:-1]] + [path[-1]]
예제 #4
0
        def _apply_damage(source, delay):
            damage = 1
            e2.hurt(damage, DType.THUNDER)
            ppos = state.to_pixel(e2.pos, CELL_SIZE)
            state.particles.append(DamageText(f"-{damage}", ppos, 12))
            pyxel.play(2, 50)

            near = [
                e for e in state.enemies
                if dist(e.pos, e2.pos) < 3 and e not in touched
            ]
            nt = touched | set(e for e in near)
            for n in near:
                self.thunder(state, e2, n, end_fn, nt)

            if not near:
                self.wait(delay, end_fn)
예제 #5
0
    def take_action(self, state: State, end_turn_fn) -> ActionReport:
        self.state_ref = state
        if not self.square in state.visible:
            return self.wait(1, end_turn_fn)
        elif not self.met_already:
            pyxel.playm(1, loop=True)
            self.met_already = True

        skels = [e for e in state.enemies if e.parent == self]
        can_invoke = not skels and self.cooldown_spawn < 1

        if not skels:
            self.sprite.stop()
            self.cooldown_spawn -= 1
        elif not self.should_tp:
            return self.wait(1, end_turn_fn)

        self.cooldown_shoot -= 1

        if self.should_tp:
            pos = state.player.pos
            while dist(pos, state.player.pos) < 4:
                pos = self.pick_free_spot(state)
            for _ in range(50):
                state.particles.append(
                    BossMolecule(_center(self.pos), _center(pos), TPV))
            self.sprite = self._teleport_sprite
            self.should_tp = False
            return self.move(*pos, end_turn_fn, TPV)

        elif can_invoke:
            self.cooldown_spawn = 4
            self.sprite = self._invoke_sprite
            self.sprite.play()
            pyxel.play(3, 3)
            return self.wait(16, partial(self._do_spawn,
                                         state,
                                         end=end_turn_fn))

        elif self.cooldown_shoot < 1:
            self.cooldown_shoot = 2
            return self.shoot(state, state.player, end_turn_fn)

        return random_move(state, self, end_turn_fn)
예제 #6
0
def straight_line(state: State, e: AIActor, end_turn) -> ActionReport:
    possible = [
        n for n in state.board.neighbours(*e.pos)
        if can_walk(state.board, *n) and n not in state.occupied
    ]
    if e.square in state.visible and possible:
        possible = sorted(possible, key=lambda x: dist(x, state.player.square))
        if possible[0] == state.player.square:
            return e.attack(state.player, end_turn)
        else:
            x, y = possible[0]
            e.move(x, y, end_turn)
            return x, y
    else:
        if possible:
            x, y = random.choice(possible)
            e.move(x, y, end_turn, 1)
            return x, y
        else:
            e.wait(10, end_turn)
    return None
예제 #7
0
 def __init__(self, start, end, callback=None):
     speed = 1 / 15
     d = dist(start, end)
     self._path = list(tween.tween(start, end, int(speed * d * FPS)))
     self._callback = callback
예제 #8
0
def update(state: State) -> State:
    x, y = state.player.pos

    deads_enemies = []
    for e in state.enemies:
        e.update(state)
        if e.pv < 1:
            deads_enemies.append(e)
    for d in deads_enemies:
        state.enemies.remove(d)

    if state.text_box is not None:
        state.text_box.update(state)
        return
    elif state.player_turn:
        player_action(state)
    else:
        game_turn(state)

    state.player.update(state)

    # if state.player.pv < 1:
    #     state.text_box = misc.TextBox("skull", "You are dead...")

    # Move camera if needed
    px, py = state.player.pos
    cx, cy = state.camera
    lthreshold = 6
    rthreshold = 9
    cx = px - lthreshold if px - cx < lthreshold else cx
    cx = px - rthreshold if px - cx > rthreshold else cx
    cy = py - lthreshold if py - cy < lthreshold else cy
    cy = py - rthreshold if py - cy > rthreshold else cy
    state.camera = cx, cy

    deads_particles = []
    for p in state.particles:
        p.update(state)
        if not p.living():
            deads_particles.append(p)
    for dp in deads_particles:
        state.particles.remove(dp)

    # store in-range block indices
    max_range = state.max_range
    state.in_range = set()
    for i in range(len(state.board)):
        x, y = index_to_pos(i, state.board.side)
        center = x + 0.5, y + 0.5
        if dist(center, state.player.pos) < max_range * 2:
            state.in_range.add(i)

    # for i in range(3):
    #     state.particles.append(Glitter(state.player.pos))

    def ray_dirs(i):
        px, py = state.player.pos
        c, r = index_to_pos(i, state.board.side)
        return [
            (x - px, y - py)
            for x, y in [
                (c + 0.5, r),
                (c + 1, r + 0.5),
                (c + 0.5, r + 1),
                (c, r + 0.5),
            ]
            if x - px and y - py
        ]

    def hit_wall(x, y):
        return (
            state.board.outside(x, y)
            or is_wall(state.board.get(x, y))
            or dist(state.player.pos, (x, y)) > state.max_range
            or is_door(state.board.get(x, y))
        )

    rays: List[VecF] = sum([ray_dirs(i) for i in state.in_range], [])
    state.visible = set()
    for r in rays:
        trav, hit, _ = cast_ray((px + 0.5, py + 0.5), r, hit_wall)
        state.visible.update(trav)
        if not state.board.outside(*hit):
            state.visible.add(hit)
    state.visited |= state.visible

    return state