def pick_final_rooms(level: Level) -> List[int]: rooms = [] for i, room in enumerate(level.rooms): n = count_neighbours(level.matrix, i) if n > 1: continue x, y = index_to_pos(i, M_SIZE) w, h = room[0] if x < M_SIZE - 1 and w >= MAX_ROOM_SIZE: continue if y < M_SIZE - 1 and h >= MAX_ROOM_SIZE: continue left = pos_to_index(x - 1, y, M_SIZE) top = pos_to_index(x, y - 1, M_SIZE) left_size = level.rooms[left][0] if x > 0 else None top_size = level.rooms[top][0] if y > 0 else None if left_size and left_size[0] >= MAX_ROOM_SIZE: continue if top_size and top_size[1] >= MAX_ROOM_SIZE: continue if w > 5 and h > 5: rooms.append(i) return rooms
def draw_debug(state: State, *extras): pyxel.cls(0) for i in range(len(state.board)): x, y = index_to_pos(i, state.board.side) v = state.board[i] if is_wall(v): col = 0 elif is_door(v): if is_locked(v): col = 8 else: col = 13 elif 40 <= v < 45: col = 1 elif state.board.entrance == i: col = 12 else: col = 7 pyxel.rect(x * U + OFF, y * U + OFF, U, U, col) # if i in extras[0]: # pyxel.pix(x * U + 1 + OFF, y * U + 1 + OFF, 9) for i in state.level.items: x, y = i.square pyxel.rect(x * U + OFF, y * U + 1 + OFF, U, U, 9) outline_room(state, state.level.start_room, 12) outline_room(state, state.level.final_rooms[0], 14) for fr in state.level.final_rooms[1:]: outline_room(state, fr, 3)
def matrix_neighbours(index: int) -> List[int]: col, row = index_to_pos(index, M_SIZE) return [ r * M_SIZE + c for r, c in [ (row, col + 1), (row + 1, col), (row, col - 1), (row - 1, col), ] if r < M_SIZE and c < M_SIZE and r >= 0 and c >= 0 ]
def encode_wall(board: Board, index: int) -> int: val = 0b10000 x, y = index_to_pos(index, board.side) neighs = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)] for i, (x_, y_) in enumerate(neighs): if board.outside(x_, y_) or is_wall(board.get(x_, y_)): val = val | (1 << i) return int("{0:b}".format(val))
def outline_room(state, room_index, color): x, y = index_to_pos(room_index, M_SIZE) size = state.level.rooms[room_index][0] pyxel.rectb( x * U * MAX_ROOM_SIZE + OFF, y * U * MAX_ROOM_SIZE + OFF, size[0] * U, size[1] * U, color, ) pass
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 encode_door(board: Board, index: int) -> int: x, y = index_to_pos(index, board.side) top = x, y - 1 top_val = board.get(*top) if board.outside(*top): return 22 elif is_wall(top_val): bin_str = str(top_val) if bin_str[4] == "0" and bin_str[2] == "1": return 21 elif bin_str[4] == "1" and bin_str[2] == "1": return 22 elif bin_str[2] == "0": return 23 return 20
def populate_enemies(level: Level, stock, empty): board = level.board enemies = [] for i in range(len(board)): if not is_empty(board[i]): continue if any(index_in_room(level, r, i) for r in level.final_rooms): continue if any(board.to_index(*k.square) == i for k in level.items): continue if is_active_tile(board[i]): continue r = random.randint(0, 100) if r >= empty: enemy_cls = random.choice(stock) e = enemy_cls(index_to_pos(i, board.side)) e.sprite.play() enemies.append(e) return enemies
def encode_floor(board: Board, index: int) -> int: x, y = index_to_pos(index, board.side) top = x, y - 1 top_val = board.get(*top) if board.outside(*top): return 32 elif is_wall(top_val): bin_str = str(top_val) if bin_str[4] == "0" and bin_str[2] == "1": return 31 elif bin_str[4] == "1" and bin_str[2] == "1": return 32 elif bin_str[4] == "1" and bin_str[2] == "0": return 33 elif bin_str[4] == "0" and bin_str[2] == "0": return 34 elif top_val == 20: # front door return 35 return 30
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