def get_random_passable_position(level): pos = Pos(-1, -1) while level.is_blocked(pos): x = random.randint(1, level.width - 1) y = random.randint(1, level.height - 1) pos = Pos(x, y) return pos
def init(self, game_data, gfx_data): # first items self.consumable_markers = [] x = self.pos.x + 30 y = self.pos.y + 30 for idx, item in enumerate(game_data.inventory.items): cm = ConsumableMarker(item, idx, pos=Pos(x, y), size=Size(self.slot_width, 50), parent=self) self.consumable_markers.append(cm) x += 150 if idx % self.items_per_row == 0: y += 60 x = self.pos.x + 30 # then quickslots self.quickslot_markers = [] x = self.pos.x + 10 y = 410 for qs in range(self.num_quickslots): qm = QuickslotMarker(qs, pos=Pos(x, y), size=Size(self.slot_width, 50), parent=self) self.quickslot_markers.append(qm) x += self.slot_width + 20
def make_map( constants, level, monster_chances, key_ratio, ingredient_count={}, consumable_count={}, ): retr = GameMap(constants.map_size, level) retr.chunks = TowerMapGenerator.chunkify(retr) TowerMapGenerator.cleanup_walls(retr) TowerMapGenerator.make_doors(retr, retr.chunks) TowerMapGenerator.place_monsters(retr, retr.chunks, monster_chances, level) TowerMapGenerator.place_stairs(retr, retr.chunks) TowerMapGenerator.place_decorations(retr, retr.chunks) TowerMapGenerator.place_lights(retr, retr.chunks) if config.conf.keys: TowerMapGenerator.place_keys(retr, retr.chunks, key_ratio) if config.conf.pickup: TowerMapGenerator.place_ingredients(retr, retr.chunks, ingredient_count) if config.conf.consumables: TowerMapGenerator.place_consumables(retr, retr.chunks, consumable_count) retr.set_tile_info(retr.tiles) px = retr.chunks[0].x + retr.chunks[0].width // 2 py = retr.chunks[0].y + retr.chunks[0].height // 2 retr.player_pos = Pos(px, py) retr.orig_player_pos = Pos(px, py) # print_map(retr) return retr
def handle_targeting(left_click, right_click, turn_results): player_action = None if left_click: targetx, targety = left_click.cx, left_click.cy distance = (self.pos - Vec(targetx, targety)).length() if game_data.targeting_formula: alternate = left_click.alternate if alternate and config.conf.trapcast: game_data.targeting_formula.trap = True game_data.targeting_formula.set_texts() if distance > game_data.targeting_formula.distance: turn_results.append({ "target_out_of_range": True, "targeting_formula": game_data.targeting_formula, }) else: player_action = ThrowVialAction( self, game_data.targeting_formula, targetpos=(Pos(targetx, targety)), ) # gfx_data.visuals.add_temporary(self.pos, Pos(targetx, targety), lifespan=distance * 0.1, gfx_data.visuals.add_temporary( self.pos, Pos(targetx, targety), lifespan=0.2, asset=gfx_data.assets.throwing_bottle, ) game_data.state = game_data.prev_state.pop() game_data.targeting_formula_idx = None elif game_data.targeting_consumable: if distance > game_data.targeting_consumable.distance: turn_results.append({ "target_out_of_range": True, "targeting_consumable": game_data.targeting_consumable, }) else: player_action = UseConsumableAction( self, game_data.targeting_consumable, targetpos=(Pos(targetx, targety)), ) gfx_data.visuals.add_temporary( self.pos, Pos(targetx, targety), lifespan=0.2, asset=gfx_data.assets.throwing_bottle, ) game_data.state = game_data.prev_state.pop() game_data.targeting_consumable = None elif right_click: turn_results.append({"targeting_cancelled": True}) return player_action, turn_results
def get_children(node): check = [] if node.x > 0: check.append(Pos(node.x - 1, node.y)) if node.x < map.width - 1: check.append(Pos(node.x + 1, node.y)) if node.y > 0: check.append(Pos(node.x, node.y - 1)) if node.y < map.height - 1: check.append(Pos(node.x, node.y + 1)) clean = [] for c in check: if map.tiles[c.x][c.y].room != -1: continue if map.tiles[c.x][c.y].wall: continue queued = False for o in origins: q = queues[o] if c in q: queued = True break if not queued: # print("{}: {} is clean".format(o, c)) clean.append(c) return clean
def setup_slots(self): self.input_slots = [] for idx in range(self.slot_count): self.input_slots.append( CraftingSlot(Pos(100, 100 + idx * 40), index=idx)) self.output_slot = CraftingSlot(Pos(400, 100 + ((40 * idx) // 2)))
def main(): w = 3 h = 6 r = 8 w = 40 h = 40 m = Map(w, h, r, 3) # m = make_circular(m) rooms = random.randint(2, 4) min_dist = (w + h) / 4 origins = [] attempts = 0 while len(origins) < rooms: attempts += 1 if attempts > 100: break x = random.randint(0, w - 1) y = random.randint(0, h - 1) newpos = Pos(x, y) too_close = False for current in origins: if dist(newpos, current) < min_dist: too_close = True if too_close: continue origins.append(Pos(x, y)) print("origins {}".format(origins)) # m = make_improved_recursive_division(m) # r1 = Region(Pos(0, 0), m, 1) # r2 = Region(Pos(1, 3), m, 2) # run = True # while run: # if not r1.expand() and not r2.expand(): # run = False # test(1, 2) # test(2, 1) # test(16.5, 4.2) # origins = [Pos(10, 6), Pos(10, 14)] # origins = [Pos(1, 1), Pos(1, 4)] # origins = [Pos(1, 0), Pos(1,3)] BFS(origins, m) # print("clear") # print_map(m) paths = [] for p in get_pairs(origins): p1, p2 = p path = check_path(m, p1, p2) paths.append(path) make_walls(m) print("walled") print_map(m) print("doored") make_doors(m, origins, paths) # for x in range(m.width): # m.tiles[x][1].wall = True # print(check_path(m, Pos(0, 0), Pos(2, 4))) print_map(m) room_centers = get_centers(m, 4)
def handle_move(move, turn_results): player_action = None dx, dy = move destx = self.pos.x + dx desty = self.pos.y + dy if self.godmode: self.pos = Pos(destx, desty) gfx_data.camera.center_on(destx, desty) game_data.stats.move_player(Pos(destx, desty)) player_action = MoveToPositionAction(self, targetpos=Pos( destx, desty)) elif not game_data.map.is_blocked(destx, desty): target = get_blocking_entites_at_location( game_data.map.entities, destx, desty) if target and target.fighter: player_action = AttackAction(self, target=target) else: gfx_data.camera.center_on(destx, desty) game_data.stats.move_player(Pos(destx, desty)) player_action = MoveToPositionAction(self, targetpos=Pos( destx, desty)) return player_action, turn_results
def redraw_level(self, memory, vision): self.clear() map_offset = self.get_map_pos(Pos(0, 0)) for x in range(0, self.width): for y in range(0, self.height): window_pos = Pos(x, y) map_pos = window_pos + map_offset self.draw_tile(map_pos, memory, vision, window_pos=window_pos)
def test_mobs(self): level = Level(25, 25) level.up_stairs_pos = Pos(1, 1) world = World([level]) mob = level.mobs[2, 2] = Mob(Pos(2, 2), 0, mobinfo['orc']) mob.move_to(Pos(3, 3)) self.assertNotIn((2, 2), level.mobs) self.assertEquals(mob, level.mobs.get((3, 3))) self.assertEquals(level.mobs.get(world.levels[0].up_stairs_pos), world.player)
def show_on_hit(self, dmg): above = Pos(self.owner.pos.x, self.owner.pos.y - 1) text_surface = [Assets.get().font_title.render(str(dmg), True, colors.RED)] VisualEffectSystem.get().add_temporary( self.owner.pos, above, lifespan=0.3, asset=text_surface, color=colors.RED )
def draw_mouse_over_info(self, game_data, gfx_data, main): info_surface = pygame.Surface(game_data.constants.window_size.tuple(), pygame.SRCALPHA) pos = pygame.mouse.get_pos() px, py = pos map_screen_pos = self.global_screen_pos_to_map_screen_pos( px, py, game_data) tile_x, tile_y = self.map_screen_pos_to_tile(map_screen_pos[0], map_screen_pos[1], gfx_data) tile_pos = Pos(tile_x, tile_y) names = [] for e in game_data.map.entities: if e.pos == tile_pos and tcod.map_is_in_fov( game_data.fov_map, tile_pos.x, tile_pos.y): names.append(e.raw_name) if not names: return text = ", ".join(names) display_text( info_surface, text, gfx_data.assets.font_message, (px - self.pos.x + 20, py), text_color=colors.WHITE, bg_color=colors.BACKGROUND, ) main.blit(info_surface, (0, 0))
def update_formula_markers(self, player, start_y): y = start_y self.formula_markers.clear() for idx, _ in enumerate(player.caster.formulas): marker = FormulaMarker(Pos(20, y), idx, player) self.formula_markers.append(marker) y += 40
def setup_consumables(self, count): self.consumable_markers = [] y = 650 for idx in range(count): pos = Pos(10, y) self.consumable_markers.append(ConsumableMarker(pos, idx)) y += 40
def cast_light(start_pos, start_y, start_slope, end_slope, radius, quad, level): if start_slope > end_slope: return prev_blocked = False for y in range(start_y, radius + 1): dy = y for dx in range(y + 1): trans = QUAD_TRANSFORMATIONS[quad] pos = start_pos + Pos(dx * trans[0] + dy * trans[1], dx * trans[2] + dy * trans[3]) left_slope = (dx - .5) / (dy + .5) right_slope = (dx + .5) / (dy - .5) if start_slope > right_slope or end_slope < left_slope: continue yield pos if level[pos].opaque: if prev_blocked: new_start = right_slope else: # end of row of see-through tiles prev_blocked = True for pos in cast_light(start_pos, y + 1, start_slope, left_slope, radius, quad, level): yield pos new_start = right_slope elif prev_blocked: # end of series of walls prev_blocked = False start_slope = new_start if prev_blocked: break
def place_consumables(m, chunks, consumable_count): def has_consumables_left(): for val in consumable_count.values(): if val > 0: return True def get_consumable(): while True: itemtype = random.choice(list(consumable_count.keys())) if consumable_count[itemtype] > 0: consumable_count[itemtype] -= 1 return itemtype() placed_consumables = [] # not two consumables in the same square while has_consumables_left(): c = random.choice(chunks) occupied = True while occupied: x = random.randint(c.x + 1, c.x + c.width - 2) y = random.randint(c.y + 1, c.y + c.height - 2) occupied = False for ent in m.entities: if ent.pos == Pos(x, y): occupied = True if (x, y) in placed_consumables: occupied = True placed_consumables.append((x, y)) drawable_component = Drawable(Assets.get().consumable) consumable_component = get_consumable() name = consumable_component.name.capitalize() consumable = Entity( x, y, name, render_order=RenderOrder.ITEM, drawable=drawable_component, consumable=consumable_component, ) m.entities.append(consumable)
def make_improved_recursive_division(map): region = [] for x in range(map.width): for y in range(map.height): region.append(Pos(x, y)) def get_point_in_region(region): while True: x = random.randint(0, map.width) y = random.randint(0, map.height) if (x, y) in region: return Pos(x, y) def flood(region, points): def has_unfilled_cells(region): for p in region: if p.room == -1: return True return False # clear point room assignments for p in region: p.room = -1 while region.expand(): pass p1 = get_point_in_region(region) p2 = get_point_in_region(region) map.tiles[p1.x][p1.y].symbol = "1" map.tiles[p2.x][p2.y].symbol = "2" return map
def __init__(self, constants, visible=False): super().__init__( constants.helper_window_pos, constants.helper_window_size, visible, click_mode=ClickMode.LEFT, ) self.title = Label(Pos(200, 25), "Inventory") self.quickslots_label = Label(Pos(240, 390), "Quickslots") self.bottomlabel = Label(Pos(180, 560), "Press Tab for help, Space to close") self.selected = 0 self.items_per_row = 2 self.num_quickslots = constants.num_quickslots self.slot_width = 140 self.consumable_markers = [] self.quickslot_markers = []
def parse_raw(self, raw_event): mouse_pos = Pos(pygame.mouse.get_pos()[0], pygame.mouse.get_pos()[1]) return attrdict.AttrDict({ "type": InputType.MOUSE.name, "x": mouse_pos.x, "y": mouse_pos.y, "button": raw_event.button })
def __init__(self, constants, visible=False, parent=None): super().__init__( Pos(constants.right_panel_size.width, 0), constants.game_window_size, visible, parent=parent, ) self.show_all = False self.drawing_priority = 2
def draw_crafted_ingredient_list(self, surface, game_data, gfx_data): counts = game_data.ingredient_storage.remaining(game_data.formula_builder) x = 450 y = 120 self.ingredient_markers = [] self.ingredient_markers.append(IngredientMarker(Pos(x, y), "Empty", Ingredient.EMPTY, parent=self)) y += 40 for ing, count in counts.items(): if count <= 0: continue text = "{}, {} left".format(ing.name.capitalize(), count) self.ingredient_markers.append(IngredientMarker(Pos(x, y), text, ing, parent=self)) y += 40 for im in self.ingredient_markers: im.draw(surface, game_data, gfx_data)
def examine(self, memory): self.clear() if memory is None: return if memory.mob: drawables[memory.mob.info['name']].draw(self.console, Pos(1, 1)) tcod.console_print(self.console, 3, 1, get_short_mob_description(memory.mob)) tcod.console_set_default_foreground(self.console, tcod.red) tcod.console_print(self.console, 3, 2, str(memory.mob.hp)) tcod.console_set_default_foreground(self.console, tcod.white) tcod.console_print(self.console, 4 + len(str(memory.mob.hp)), 2, "hp") if DEBUG: tcod.console_print(self.console, 3, 3, str(memory.mob.pos)) tcod.console_print(self.console, 3, 4, str(memory.mob.target)) else: drawables[memory.tile_name].draw(self.console, Pos(1, 1)) tcod.console_print(self.console, 3, 1, memory.tile_name)
def get_constants(): window_title = "Formula" map_size = Size(40, 30) camera_size = Size(25, 20) game_window_size = Size((camera_size.width + 1) * CELL_WIDTH, (camera_size.height + 1) * CELL_HEIGHT) window_size = Size(150 + game_window_size.width, 900) right_panel_size = Size(150, window_size.height) message_log_size = Size( window_size.width - right_panel_size.width, window_size.height - game_window_size.height, ) message_log_text_size = Size( message_log_size.width - 2 * CELL_WIDTH, message_log_size.height - 2 * CELL_HEIGHT, ) helper_window_size = Size(800, 600) helper_window_pos = Pos(100, 100) num_consumables = 5 num_quickslots = 3 room_max_size = 15 room_min_size = 6 max_rooms = 5 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 retr = AttrDict({ "window_title": window_title, "window_size": window_size, "game_window_size": game_window_size, "camera_size": camera_size, "map_size": map_size, "right_panel_size": right_panel_size, "message_log_size": message_log_size, "message_log_text_size": message_log_text_size, "helper_window_size": helper_window_size, "helper_window_pos": helper_window_pos, "room_max_size": room_max_size, "room_min_size": room_min_size, "max_rooms": max_rooms, "fov_algorithm": fov_algorithm, "fov_light_walls": fov_light_walls, "fov_radius": fov_radius, "num_consumables": num_consumables, "num_quickslots": num_quickslots, }) return retr
def __init__(self, constants, parent): super().__init__( Pos(constants.right_panel_size.width, constants.game_window_size.height), constants.message_log_size, visible=False, parent=parent, ) self.offset = 0 self.num_messages = 9 self.drawing_priority = 2
def apply(self, game_data, gfx_data, target): explored_tiles = [] for x in range(game_data.map.width): for y in range(game_data.map.height): if game_data.map.tiles[x][y].explored and not game_data.map.tiles[x][y].blocked: explored_tiles.append((x, y)) x, y = random.choice(explored_tiles) game_data.player.pos = Pos(x, y) results = [{"message": Message("Teleported to a previously explored location")}] return results
def get_neighbours(p, queue, visited): retr = [] if p.x > 0: retr.append(Pos(p.x - 1, p.y)) if p.x < m.width - 1: retr.append(Pos(p.x + 1, p.y)) if p.y > 0: retr.append(Pos(p.x, p.y - 1)) if p.y < m.height - 1: retr.append(Pos(p.x, p.y + 1)) clean = [] for r in retr: if m.tiles[r.x][r.y].wall: continue if r in queue: continue if r in visited: continue clean.append(r) return clean
def get_tiles_within(map, distance, target): import math from util import Pos retr = [] for x in range(math.ceil(target.x - distance), math.ceil(target.x + distance),): for y in range(math.ceil(target.y - distance), math.ceil(target.y + distance),): dist = math.sqrt((x - target.x) ** 2 + (y - target.y) ** 2) if dist < distance: retr.append(Pos(x, y)) return retr
class MapWindow(Window): center_pos = Pos(0, 0) def __init__(self, *args, **kwargs): self.center_pos = Pos(0, 0) super().__init__(*args, **kwargs) def draw_cursor(self, map_pos): x, y = self.get_window_pos(map_pos) tcod.console_set_char_background(self.console, x, y, tcod.light_grey) def draw_cursor_at_center(self): self.draw_cursor(self.center_pos) def move(self, direction): self.center_pos += direction def center(self, pos): self.center_pos = pos def get_window_pos(self, map_pos): return map_pos - self.center_pos + \ Pos(self.width, self.height) // 2 def get_map_pos(self, world_pos): return world_pos + self.center_pos - \ Pos(self.width, self.height) // 2 def redraw_level(self, memory, vision): self.clear() map_offset = self.get_map_pos(Pos(0, 0)) for x in range(0, self.width): for y in range(0, self.height): window_pos = Pos(x, y) map_pos = window_pos + map_offset self.draw_tile(map_pos, memory, vision, window_pos=window_pos) def draw_tile(self, map_pos, memory, vision, window_pos=None): memory = memory.get(map_pos, None) if memory: if window_pos is None: window_pos = self.get_window_pos(map_pos) tile_drawable = drawables[memory.tile_name] mob_drawable = drawables[memory.mob.info['name']] if memory.mob \ else None visible = map_pos in vision tile_drawable.draw(self.console, window_pos, not visible) if mob_drawable: mob_drawable.draw(self.console, window_pos, not visible)
def draw_terrain(self, game_data, gfx_data, main): surface = pygame.Surface(game_data.constants.game_window_size.tuple(), pygame.SRCALPHA) surface.fill(colors.BACKGROUND) for x in range(gfx_data.camera.x1, gfx_data.camera.x2): for y in range(gfx_data.camera.y1, gfx_data.camera.y2): visible = tcod.map_is_in_fov(game_data.fov_map, x, y) asset = game_data.map.tiles[x][y].get_drawable(self.show_all or visible) if visible: game_data.map.tiles[x][y].explored = True if asset: distance = (game_data.player.pos - Pos(x, y)).length() if visible: if distance < 3.5: # 1 range darken = 20 elif distance < 5.5: # 2 range darken = 40 elif distance < 7.5: # 3 range darken = 60 else: darken = 80 else: darken = 80 # if visible: darken -= game_data.map.tiles[x][y].light darken = max(0, min(255, darken)) drawable = Drawable(asset) drawable.colorize((darken, darken, darken), pygame.BLEND_RGBA_SUB) sx, sy = gfx_data.camera.map_to_screen(x, y) surface.blit(drawable.asset, (sx * CELL_WIDTH, sy * CELL_HEIGHT)) if game_data.map.tiles[x][y].decor: for decor_drawable in game_data.map.tiles[x][y].decor: drawable = Drawable(decor_drawable.asset) drawable.colorize((darken, darken, darken), pygame.BLEND_RGB_SUB) surface.blit(drawable.asset, (sx * CELL_WIDTH, sy * CELL_HEIGHT)) if game_data.map.tiles[x][y].trap: drawable = Drawable(gfx_data.assets.trap) drawable.colorize((darken, darken, darken), pygame.BLEND_RGB_SUB) surface.blit(drawable.asset, (sx * CELL_WIDTH, sy * CELL_HEIGHT)) main.blit(surface, (0, 0))
def place_monsters(m, chunks, monster_chances, level): entities = [] chance_any = monster_chances["any"] del monster_chances["any"] max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], level + 1) for idx, c in enumerate(chunks): c.monsters = [] rval = random.randint(0, 100) if rval > chance_any: continue if idx == 0: num_monsters = 1 # don't overwhelm in the first room else: num_monsters = random.randint(1, max_monsters_per_room) room_center = Pos(c.x + c.width // 2, c.y + c.height // 2) skip_room = False for _ in range(num_monsters): x = random.randint(c.x + 1, c.x + c.width - 1) y = random.randint(c.y + 1, c.y + c.height - 1) if idx == 0: # first room, don't spawn right next to player attempts = 0 while Pos(x, y).distance_to(room_center) < 4: x = random.randint(c.x + 1, c.x + c.width - 2) y = random.randint(c.y + 1, c.y + c.height - 2) attempts += 1 if attempts > 100: skip_room = True if skip_room: continue already_there = [entity for entity in entities if entity.pos.x == x and entity.pos.y == y] if not any(already_there) and not m.tiles[x][y].blocked: monster_choice = random_choice_from_dict(monster_chances) monster_data = get_monster(x, y, m, c, monster_choice, entities) entities.extend(monster_data) c.monsters.extend(monster_data) m.entities = entities