def find_valid_spaces(self) -> list: tiles = {(position.x, position.y) for _, position, visible in join_drop_key( self.engine.tiles, self.engine.positions, self.engine.visibilities) if visible.level < 2 and not position.blocks} units = {(position.x, position.y) for _, position in join_drop_key(self.engine.inputs, self.engine.positions)} return tiles - units
def go_up(engine, entity): """Check if entity position is on stairs. If true go up""" went_up = False position = engine.positions.find(entity) tilemap = engine.tilemaps.find(position.map_id) g = join_drop_key(engine.tiles, engine.positions, engine.renders) for _, tile_position, render in g: if (tile_position.map_id == engine.world.id and tile_position == position and render.char == '<'): break else: tile_position = None if not tile_position: engine.logger.add('Could not go up since not on stairs') return went_up old_id = engine.world.id up = engine.world.go_up() if old_id != engine.world.id: engine.map_system.regenerate_map(old_id) else: engine.logger.add('no parent node.') for _, (_, tile_position, render) in join(engine.tiles, engine.positions, engine.renders): if (tile_position.map_id == engine.world.id and render.char == '>'): break position = tile_position.copy(movement_type=position.movement_type, blocks=position.blocks) engine.positions.remove(engine.player) engine.positions.add(engine.player, position) return True
def check_tile_info(engine, position): describeables = list() for p, i in join_drop_key(engine.positions, engine.infos): if (position.x == p.x and position.y == p.y and i.name is not 'floor'): describeables.append(i.name) if describeables: engine.logger.add(', '.join(describeables))
def move(engine, entity, movement) -> bool: # if entity has no position component return early position = engine.positions.find(entity) if not position or not movement: return False # save temp positions for collision checking x, y = position.x + movement.x, position.y + movement.y # check map out-of-bounds collisions tilemap = engine.tilemaps.find(eid=position.map_id) if not (0 <= x < tilemap.width and 0 <= y < tilemap.height): return collide(engine, entity, -1) # check unit collisions for specific movment types if position.movement_type == Position.MovementType.GROUND: # check unit collisions for entity_id, entity_position in engine.positions: if (entity_position.x == x and entity_position.y == y and entity_position.map_id == engine.world.id and entity_id != entity and entity_position.blocks is True): # if door is an unlocked door, open door and move positions entity_openable = engine.openables.find(entity_id) if entity_openable: # replace info engine.infos.add(entity_id, engine.infos.shared['opened door']) engine.renders.add( entity_id, random.choice(engine.renders.shared['opened door'])) entity_openable = True entity_position.blocks = False position.x += movement.x position.y += movement.y engine.logger.add( "You open the door and enter the doorway") return True return collide(engine, entity, entity_id) if position.movement_type == Position.MovementType.VISIBLE: g = join_drop_key(engine.positions, engine.visibilities) for entity_position, visible in g: if (entity_position.x == x and entity_position.y == y and entity_position.map_id == engine.world.id and visible.level < 2): return False # no collisions. move to the new position position.x += movement.x position.y += movement.y # check if entity == engine.player: check_for_floor_items(engine, position) elif entity == engine.cursor: check_tile_info(engine, position) return False return True
def find_unlit_spaces(self) -> set: return { (position.x, position.y) for (_, position, visible) in join_drop_key(self.engine.tiles, self.engine. positions, self.engine.visibilities) if visible.level > 1 and not position.blocks }
def pathfind(engine, start, end, pathfinder=astar): """Wrapper for ecs engine to use astar""" tiles = { (position.x, position.y) for _, position in join_drop_key(engine.tiles, engine.positions) if not position.blocks } path = pathfinder(tiles, start, end) return path
def test_manager(): m = ComponentManager(Render) n = ComponentManager(Position) render = Render() position = Position() m.add(0, render) n.add(0, position) for r, p in join_drop_key(m, n): assert r == render assert p == position
def on_move(self, event): """ if out-of-bounds, environment or unit blocked: returns Collision result else: moves entity """ self.logger.add(f"Move {self.engine.turns}") # if entity has no position component return early position = self.engine.positions.find(entity) if not position or not movement: return False # save temp positions for collision checking x, y = position.x + movement.x, position.y + movement.y # check map out-of-bounds collisions tilemap = self.engine.tilemaps.find(eid=position.map_id) if not (0 <= x < tilemap.width and 0 <= y < tilemap.height): return self.collide(entity, Collision(-1)) # check unit collisions for specific movment types if position.movement_type == Position.MovementType.GROUND: # check unit collisions for entity_id, entity_position in self.engine.positions: if (entity_position.x == x and entity_position.y == y and entity_position.map_id == self.engine.world.id and entity_id != entity and entity_position.blocks is True): return self.collide(entity, Collision(entity_id)) if position.movement_type == Position.MovementType.VISIBLE: g = join_drop_key(self.engine.positions, self.engine.visibilities) for entity_position, visible in g: if (entity_position.x == x and entity_position.y == y and entity_position.map_id == self.engine.world.id and visible.level < 2): return False # no collisions. move to the new position position.x += movement.x position.y += movement.y # check if entity == self.engine.player: self.check_for_floor_items(position) elif entity == self.engine.cursor: self.check_tile_info(position) return False return True
def go_down(engine, entity): """Check if entity position is on stairs. If true go down""" went_down = False position = engine.positions.find(entity) tilemap = engine.tilemaps.find(eid=position.map_id) # should only return 1 tile/render pair g = join_drop_key(engine.tiles, engine.positions, engine.renders) for _, tile_position, render in g: # tile from current map / same map position as entity / is down stairs if (tile_position.map_id == engine.world.id and tile_position == position and render.char == '>'): break else: tile_position = None if not tile_position: engine.logger.add('Could not go down since not on stairs') return went_down old_id = engine.world.id engine.world.go_down() if old_id == engine.world.id: # TODO: generate child map to go down. For now return False # engine.logger.add('Could not go down since no child map') # return went_down engine.map_system.generate_map(MapType.CAVE) engine.world.go_down() else: engine.map_system.regenerate_map(old_id) for _, (_, tile_position, render) in join(engine.tiles, engine.positions, engine.renders): # tile from current map / is up stairs if (tile_position.map_id == engine.world.id and render.char == '<'): break if not tile_position: engine.logger.add('Could not go down since child map has no up stairs') return went_down # send entity to the position of stairs on child map position = tile_position.copy(movement_type=position.movement_type, blocks=position.blocks) engine.positions.remove(engine.player) engine.positions.add(engine.player, position) return True
def cast_light2(engine, x0, x1, y0, y1, raycaster=raycast2): """Wrapper for raycast so that engine is not a parameter to raycast""" player = engine.positions.find(engine.player) tilemap = engine.tilemaps.find(engine.world.id) if not tilemap: no_tilemap_error(engine.world.id, engine.tilemaps.components.keys()) exit(0) tiles = dict() blocked = set() for v, p in join_drop_key(engine.visibilities, engine.positions): if (p.map_id == engine.world.id and x0 <= p.x < x1 and y0 <= p.y < y1): v.level = max(0, min(v.level, 1)) tiles[(p.x, p.y)] = v if p.blocks: blocked.add((p.x, p.y)) raycaster(tiles, blocked, tilemap.width, tilemap.height, player)
def find_empty_spaces(self) -> list: return {(position.x, position.y) for _, position in join_drop_key(self.engine.tiles, self.engine.positions) if not position.blocks}
def get_tiles(engine, x0, x1, y0, y1) -> list: tiles = [] for v, p in join_drop_key(engine.visibilities, engine.positions): if (p.map_id == engine.world.id and x0 <= p.x < x1 and y0 <= p.y < y1): tiles.append((v, p)) return tiles
t = time.time() caster( engine, off_x, 57 + off_x, off_y, 17 + off_y, raycaster=raycaster ) s = time.time() # save the timing result recorder.append(s - t) # edit the map buffer with seen positions and player position for p, v in join_drop_key(engine.positions, engine.visibilities): m[p.y][p.x] = ' ' if v.level == 0 else n[p.y][p.x] p = engine.positions.find(engine.player) m[p.y][p.x] = '@' # render print(string(m)) try: c = input().strip() except KeyboardInterrupt: break p = engine.positions.find(engine.player) if c == 'w' and n[p.y-1][p.x] == '.': m[p.y][p.x] = '.'
def render(self): player = self.engine.positions.find(self.engine.player) tilemap = self.engine.tilemaps.find(player.map_id) # calculate camera bounds on scrolling map if tilemap.width < self.width: self.cam_x = 0 else: self.cam_x = scroll(player.x, self.width, tilemap.width) x0, x1 = self.cam_x, self.width + self.cam_x if tilemap.height < self.height: self.cam_y = 0 else: self.cam_y = scroll(player.y, self.height, tilemap.height) y0, y1 = self.cam_y, self.height + self.cam_y # do line of sight calculations cast_light(self.engine, x0, x1, y0, y1) start = time.time() # draw map first, then items, then units for visibility, position, render in join_drop_key( self.engine.visibilities, self.engine.positions, self.engine.renders): if (visibility.level > 0 and player.map_id == position.map_id and x0 <= position.x < x1 and y0 <= position.y < y1): c = render.color if visibility.level > 1 else "darkest grey" self.add_string(position.x - self.cam_x, position.y - self.cam_y, render.char, c) self.engine.entities_in_view.clear() for eid, (health, position, render, info) in join(self.engine.healths, self.engine.positions, self.engine.renders, self.engine.infos): if (position.map_id == self.engine.world.id and (position.x, position.y) in self.engine.tiles_in_view and x0 <= position.x < x1 and y0 <= position.y < y1): if self.engine.player != eid: self.engine.entities_in_view.add(eid) self.add_string(position.x - self.cam_x, position.y - self.cam_y, render.char, render.color) # # draw items # self.render_items(visible_tiles, player.map_id, cam_x, cam_y, x0, x1, y0, y1) # while True: # # draw units # self.render_units(visible_tiles, player.map_id, cam_x, cam_y, x0, x1, y0, y1) # if not self.engine.effects.components: # break # if time.time() - start > (1 / 23): # self.engine.effects.components.clear() # break # # draw effects # self.render_effects(tiles, player.map_id, cam_x, cam_y, x0, x1, y0, y1) # self.update_effects() if self.engine.mode is not GameMode.NORMAL: # self.render_cursor(visible_tiles, player.map_id, cam_x, cam_y, x0, x1, y0, y1) position = self.engine.positions.find(self.engine.cursor) if self.engine.mode in (GameMode.LOOKING, GameMode.DEBUG): self.add_string(position.x - self.cam_x, position.y - self.cam_y, 'X') elif self.engine.mode == GameMode.MAGIC: cursor = self.engine.cursors.find(self.engine.cursor) spellname = Spell.identify[cursor.using] render = self.engine.renders.shared[spellname][0] if spellname == 'fireball': for xx, yy in diamond(): x = position.x + xx y = position.y + yy if (x, y) not in self.engine.tiles_in_view: continue self.add_string(x - cam_x, y - cam_y, render.char, render.color)