def find_in_bounds_orthogonal(self, point: Point, delta: int = 1) -> Point: if delta == 1: to_check = point.neighbors for check in to_check: try: if self.floor.contains_point(check): return check except CellOutOfBoundsError: continue else: to_check = [ Point(0, -delta), Point(delta, 0), Point(0, delta), Point(-delta, 0) ] for check in to_check: try: if self.floor.contains_point(point + check): return point + check except CellOutOfBoundsError: continue # Don't return None, just in case return point
def draw(self, ctx): color_fg = '#ffffff' color_bg = '#000000' if self.is_first_responder: color_fg = '#000000' color_bg = '#ffffff' ctx.color(color_fg) ctx.bkcolor(color_bg) ctx.print(Point(self.bounds.width, 2), '↑') ctx.print(Point(self.bounds.width, self.bounds.height), '↓')
def draw(self, ctx): color_fg = '#ffffff' color_bg = '#000000' if self.is_first_responder: color_fg = '#000000' color_bg = '#ffffff' ctx.color(color_fg) ctx.bkcolor(color_bg) ctx.print(Point(0, 0), '← ') ctx.print(Point(self.bounds.width - 2, 0), ' →')
def update_pos(self): self.unblock() if self.delta_pos != Point(0, 0): self._pos += self.delta_pos bearlib.clear(self._pos.x, self._pos.y, 1, 1) self._visible_points = get_visible_points( self.position, self.map.get_allows_light, max_distance=self._range) self.update_block() self.delta_pos = Point(0, 0)
def draw(self, ctx): color_fg = self.color_selected_fg if self.is_first_responder else self.color_unselected_fg color_bg = self.color_selected_bg if self.is_first_responder else self.color_unselected_bg ctx.color(color_fg) ctx.bkcolor(color_bg) ctx.print(Point(0, 0), self.text) text_len = len(self.text) if self.bounds.width > text_len: ctx.print(Point(text_len, 0), '_' * (self.bounds.width - text_len)) if self.is_first_responder and int(time() * 1.2) % 2 == 0: ctx.put(Point(text_len, 0), '▒')
def diagonals(self, point: Point, delta: int = 2) -> List[Tile]: to_check = [neighbor for neighbor in point.diagonal_neighbors] to_check.extend([ Point(-delta, -delta), Point(delta, delta), Point(delta, -delta), Point(-delta, delta) ]) safe = [] for check in to_check: try: safe.append(self.floor.cell(point + check)) except CellOutOfBoundsError: pass return safe
def layout_subviews(self): for i in range(len(self.labels)): is_in_view = self.get_is_in_view(i) if is_in_view: y = 1 + self.frame.y + i - self.min_row self.labels[i].frame = Rect( Point(self.frame.x + 1, y), Size(self.frame.width - self.value_column_width - 2, 1)) self.values[i].frame = Rect( Point( self.frame.x + 1 + self.frame.width - self.value_column_width - 2, y), Size(self.value_column_width, 1)) self.labels[i].is_hidden = not is_in_view self.values[i].is_hidden = not is_in_view
def __init__(self, tile: Tile, map: 'Map', scene: 'GameScene'): super().__init__(tile, map, scene) self.name = self.NAME self.description = self.DESCRIPTION self._hp = self.BASE_HP self._max_hp = self.BASE_HP self._tp = self.BASE_TP self._max_tp = self.BASE_TP self._xp = 0 self._bump_damage = 1 self._range = self.RANGE self.frozen = 0 self.state = ActorState.ALIVE # Ephemeral deltas self.delta_hp = 0 self.delta_tp = 0 self.delta_pos = Point(0, 0) self.delta_xp = 0 self._states = {} self._visible_points = get_visible_points(self.position, self.map.get_allows_light, max_distance=self._range)
def draw(self, ctx): ctx.color(self.color_fg) ctx.bkcolor(self.color_bg or '#000000') if self.clear: ctx.clear_area(self.bounds) x = 0 if self.align_horz == 'center': x = self.bounds.width / 2 - self.intrinsic_size.width / 2 elif self.align_horz == 'right': x = self.bounds.width - self.intrinsic_size.width y = 0 if self.align_vert == 'center': y = self.bounds.height / 2 - self.intrinsic_size.height / 2 elif self.align_vert == 'bottom': y = self.bounds.height - self.intrinsic_size.height if self.intrinsic_size.width > self.bounds.width and self.wrap: # if width exceeds bounds - wrap words w = self.bounds.width else: w = 0 ctx.print(Point(x, y).floored, self.text, w) ctx.color('#ffffff') ctx.bkcolor( '#000000' ) # because sometimes bkcolor i used to draw something else...
def bounds(self, new_value): if new_value.origin != Point(0, 0): raise ValueError("Bounds is always anchored at (0, 0)") if new_value == self._bounds: return self._bounds = new_value self._frame = self._frame.with_size(new_value.size) self.set_needs_layout(True)
def __init__(self): super().__init__() self.area = None self.level = None self._local_x = 0 self._local_y = 0 self.region = None self.world_x = 0 self.world_y = 0 self.point = Point(self._local_x, self._local_y)
def __init__(self, scene: 'GameScene'): self.__floors = {} self._floor_size = self.FLOOR_SIZE self._origin = self.ORIGIN self._center = Point(int(self._floor_size.width / 2), int(self._floor_size.height / 2)) self._view_size = self.VIEW_SIZE self._view_rect = Rect(self._origin, self._view_size) self._view_center = Point(int(self._view_size.width / 2), int(self._view_size.height / 2)) self._current_floor = 0 self.scene = scene for i in range(0, self.FLOORS): self.__floors[i] = Floor(self._origin, self._floor_size) self.populate_floor(self.__floors[i]) for index in self.__floors: floor = self.__floors.get(index + 1) if floor: self.place_stairs(index, index + 1) for floor in self.__floors.values(): if floor.stairs_down and floor.stairs_up: floor.connect_tiles(floor.stairs_down, floor.stairs_up) player_start_tile = self.floor.cell( self.floor.stairs_up.point.get_farthest_point( [tile.point for tile in self.floor.get_open_tiles()])) self.player = Player(player_start_tile, self, self.scene) self.floor.connect_tiles(player_start_tile, self.floor.stairs_up) last_floor = self.get_floor(self.FLOORS - 1) chronotherium_start_tile = last_floor.cell( last_floor.find_open_point()) Chronotherium(chronotherium_start_tile, self, self.scene) last_floor.connect_tiles(chronotherium_start_tile, last_floor.stairs_down)
def draw_displays(self, viewer_fov, ctx): current_level = self.camera.location.level for priority in sorted(current_level.displays.keys(), key=lambda k: k.value): for game_object in current_level.displays[priority]: x, y = game_object.location.get_local_coords() if (x, y) in viewer_fov: relative_point = self.camera.transform(Point(x, y)) if relative_point is not None: ctx.printf(relative_point, game_object.display.get_draw_info())
def engrave_bsp_divisions(tilemap, node): """ Debugging method. Sets the debug_character on the cells on the dividing lines between the 4 difficulty quadrants. """ if node.level > 1: return if node.value: if node.is_horz: x = node.rect.x + node.value for y in range(node.rect.y, node.rect.y2 + 1): tilemap.cell(Point(x, y)).debug_character = '|' else: y = node.rect.y + node.value for x in range(node.rect.x, node.rect.x2 + 1): tilemap.cell(Point(x, y)).debug_character = '-' if node.child_a: engrave_bsp_divisions(tilemap, node.child_a) if node.child_b: engrave_bsp_divisions(tilemap, node.child_b)
def generate_and_engrave_corridors(tilemap, root): """ Rooms have already been engraved, so add corridors. Rules for corridors: * There is one corridor between each pair of siblings in the BSP tree. If that statement doesn't make sense to you, then please go read more Wikipedia. * There is an exception to that rule: the sole ancestor for each quadrant (remember the blog post!) does not have a corridor to its sibling. Instead, explicitly draw corridors between specific rooms in each quadrant. """ # generate corridors between rooms WITHIN a quadrant sibling_pairs = [(a, b) for (a, b) in root.sibling_pairs if a.level > 2 and b.level > 2] for (a, b) in sibling_pairs: engrave_corridor_between_rooms(tilemap, a.leftmost_leaf.data['room'], b.leftmost_leaf.data['room']) # generate corridors between quadrants (the glowing ones) room_aa_bottom = get_room_nearest( root.get_node_at_path('aa').leaves, Point(0, tilemap.size.height / 2)) room_ab_top = get_room_nearest( root.get_node_at_path('ab').leaves, room_aa_bottom.rect.center) engrave_corridor_between_rooms(tilemap, room_aa_bottom, room_ab_top, 'transition-1-2') room_ab_right = get_room_nearest( root.get_node_at_path('ab').leaves, Point(tilemap.size.width / 2, tilemap.size.height)) room_bb_left = get_room_nearest( root.get_node_at_path('bb').leaves, room_ab_right.rect.center) engrave_corridor_between_rooms(tilemap, room_ab_right, room_bb_left, 'transition-2-3') room_bb_top = get_room_nearest( root.get_node_at_path('bb').leaves, Point(tilemap.size.width, tilemap.size.height / 2)) room_ba_bottom = get_room_nearest( root.get_node_at_path('ba').leaves, room_bb_top.rect.center) engrave_corridor_between_rooms(tilemap, room_bb_top, room_ba_bottom, 'transition-3-4')
def draw_tiles(self, viewer_fov, ctx): current_level = self.camera.location.level for x, y in viewer_fov: tile = current_level.get_tile((x, y)) if not tile: continue relative_point = self.camera.transform(Point(x, y)) if relative_point is None: continue ctx.printf(relative_point, tile.display.get_draw_info())
def __init__(self, game, selection, executor): self.game = game self.action_mapping = game.action_mapping views = game.game_scene.view.subviews.copy() self.label = LabelView("") self.cursor_view = CursorView(game, self) views.append(self.label) views.append(self.cursor_view) super().__init__(views=views) self.executor = executor self.selection = selection self.cursor_position = Point(*executor.location.get_local_coords())
def layout_subviews(self): self.rect_view.apply_springs_and_struts_layout_in_superview() if self.scroll_fraction >= 0: self.scroll_indicator_view.frame = Rect( Point(self.bounds.width - 1, 1 + floor(self.inner_height * self.scroll_fraction)), Size(1, 1)) for i in range(len(self.labels)): is_in_view = self.get_is_in_view(i) if is_in_view: y = 1 + self.bounds.y + i - self.min_row self.labels[i].frame = Rect( Point(self.bounds.x + 1, y), Size(self.bounds.width - self.value_column_width - 2, 1)) self.values[i].frame = Rect( Point(self.bounds.x + 1 + self.bounds.width - self.value_column_width - 2, y), Size(self.value_column_width, 1)) self.labels[i].is_hidden = not is_in_view self.values[i].is_hidden = not is_in_view
def __init__(self): self.window = Window() self.message_log = [] self.gutter = [] self.gutter_size = Size( self.window.width - MAP_SIZE.width + MAP_ORIGIN.x, self.window.height - MAP_ORIGIN.y) self.gutter_rect = Rect( Point(self.window.width - self.gutter_size.width, self.window.height - self.gutter_size.height), self.gutter_size) self.log_height = LOG_HEIGHT super().__init__()
def __init__(self, path): self._image = load_xp_file(path) self.size = Size(self._image['width'], self._image['height']) self.num_layers = self._image['layer_count'] self._draw_calls_by_layer = [] for layer_i, layer in enumerate(self._image['layer_data']): calls = [] for x, col in enumerate(layer['cells']): for y, cell in enumerate(col): fg = _read_color(cell, 'fore_r', 'fore_g', 'fore_b') bg = self._read_bg_color(layer_i, x, y) calls.append((Point(x, y), cell['keycode'], fg, bg)) self._draw_calls_by_layer.append(calls)
def __init__(self, frame=None, subviews=None, scene=None, layout_options=None, clear=False): if isinstance(layout_options, dict): # have pity on the user's imports opts = LayoutOptions()._asdict() opts.update(layout_options) layout_options = LayoutOptions(**opts) self.clear = clear self._scene = scene self._superview_weakref = lambda: None self.needs_layout = True self._frame = frame or ZERO_RECT self._bounds = self.frame.with_origin(Point(0, 0)) self.subviews = [] self.add_subviews(subviews or []) self.is_first_responder = False self.is_hidden = False self.layout_spec = frame self.layout_options = layout_options or LayoutOptions()
def draw(self, ctx): ctx.color(self.color_fg) ctx.bkcolor(self.color_bg or '#000000') if self.clear: ctx.clear_area(self.bounds) x = 0 if self.align_horz == 'center': x = self.bounds.width / 2 - self.intrinsic_size.width / 2 elif self.align_horz == 'right': x = self.bounds.width - self.intrinsic_size.width y = 0 if self.align_vert == 'center': y = self.bounds.height / 2 - self.intrinsic_size.height / 2 elif self.align_vert == 'bottom': y = self.bounds.height - self.intrinsic_size.height ctx.print(Point(x, y).floored, self.text)
def _cast_light(los_cache, get_allows_light, cx, cy, row, start, end, radius, xx, xy, yx, yy): if start < end: return radius_squared = radius * radius for j in range(row, radius + 1): dx, dy = -j - 1, -j blocked = False while dx <= 0: dx += 1 # Translate the dx, dy coordinates into map coordinates: X, Y = cx + dx * xx + dy * xy, cy + dx * yx + dy * yy point = Point(X, Y) # l_slope and r_slope store the slopes of the left and right # extremities of the square we're considering: l_slope, r_slope = (dx - 0.5) / (dy + 0.5), (dx + 0.5) / (dy - 0.5) if start < r_slope: continue elif end > l_slope: break else: # Our light beam is touching this square; light it: if dx * dx + dy * dy < radius_squared: los_cache.add(point) if blocked: # we're scanning a row of blocked squares: if not get_allows_light(point): new_start = r_slope continue else: blocked = False start = new_start else: if not get_allows_light(point) and j < radius: # This is a blocking square, start a child scan: blocked = True _cast_light(los_cache, get_allows_light, cx, cy, j + 1, start, l_slope, radius, xx, xy, yx, yy) new_start = r_slope # Row is scanned; do next row unless last square was blocked: if blocked: break
def main(): terminal.open() tilemap = TileMap(Size(80, 24)) player_pos = Point(0, 0) for y, row in enumerate(dungeon): for x, char in enumerate(row): cell = tilemap[Point(x, y)] if char == '.': cell.terrain = 0 elif char == '#': cell.terrain = 1 elif char == '@': player_pos = Point(x, y) else: raise ValueError(char) terminal.refresh() terminal.clear() draw(tilemap, player_pos) try: while True: terminal.clear() draw(tilemap, player_pos) terminal.refresh() if terminal.has_input(): char = terminal.read() if char == terminal.TK_Q: break if char == terminal.TK_UP: player_pos = player_pos + Point(0, -1) if char == terminal.TK_DOWN: player_pos = player_pos + Point(0, 1) if char == terminal.TK_LEFT: player_pos = player_pos + Point(-1, 0) if char == terminal.TK_RIGHT: player_pos = player_pos + Point(1, 0) except KeyboardInterrupt: pass finally: terminal.close()
def generate_dungeon(size): """ Tie it all together. Returns a fully populated RogueBasementTilemap of the given size. """ # Make a blank tilemap tilemap = RogueBasementTileMap(size) # Make a BSP tree where the minimum room size is 4 and the random-split # function is the helper defined just above this function generator = RandomBSPTree(tilemap.size, 4, randrange_func=_bsp_randrange) # key is difficulty (int). # values are the topmost ancestor for all nodes of that difficulty. A node # knows what difficulty it is based on which ancestor it has. difficulty_map = { # This 'aa', 'ab' notation is just a quicker, less error-prone way of # saying node.child_a.child_b and such. 0: generator.root.get_node_at_path('aa'), 1: generator.root.get_node_at_path('ab'), 2: generator.root.get_node_at_path('bb'), 3: generator.root.get_node_at_path('ba'), } # Create a room in each leaf rooms = [ generate_room(leaf, difficulty_map) for leaf in generator.root.leaves ] # Set the cell terrain values engrave_rooms(tilemap, rooms) # Make corridors generate_and_engrave_corridors(tilemap, generator.root) # Place stairs up (no game value, just a marker) stairs_up_room = get_room_nearest( generator.root.get_node_at_path('aa').leaves, Point(tilemap.size.width / 2, tilemap.size.height / 4)) stairs_up = stairs_up_room.rect.with_inset(1).get_random_point() tilemap.points_of_interest['stairs_up'] = stairs_up tilemap.occupied_cells.add(stairs_up) tilemap.cell(tilemap.points_of_interest['stairs_up'] ).feature = EnumFeature.STAIRS_UP # Place stairs down stairs_down_room = get_room_nearest( generator.root.get_node_at_path('ba').leaves, Point(tilemap.size.width / 2, tilemap.size.height / 2)) stairs_down = stairs_down_room.rect.with_inset(1).get_random_point() tilemap.points_of_interest['stairs_down'] = stairs_down tilemap.occupied_cells.add(stairs_down) tilemap.cell(tilemap.points_of_interest['stairs_down'] ).feature = EnumFeature.STAIRS_DOWN # Tell all the cells how difficult they are (you know, for the music) engrave_difficulty(generator.root) # Figure out where the monsters and items go place_monsters(tilemap) place_items(tilemap) #engrave_bsp_divisions(tilemap, generator.root) return tilemap
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.offset = Point(0, 0)
def intrinsic_size(self): return Point(0, 0)
def _apply_springs_and_struts_layout_to_view(view): options = view.layout_options spec = view.layout_spec superview_bounds = view.superview.bounds fields = [ ('left', 'right', 'x', 'width'), ('top', 'bottom', 'y', 'height'), ] final_frame = Rect(Point(-1000, -1000), Size(-1000, -1000)) for field_start, field_end, field_coord, field_size in fields: debug_string = options.get_debug_string_for_keys( [field_start, field_size, field_end]) matches = (options.get_is_defined(field_start), options.get_is_defined(field_size), options.get_is_defined(field_end)) if matches == (True, True, True): raise ValueError( "Invalid spring/strut definition: {}".format(debug_string)) if matches == (False, False, False): raise ValueError( "Invalid spring/strut definition: {}".format(debug_string)) elif matches == (True, False, False): setattr(final_frame, field_coord, options.get_value(field_start, view)) # pretend that size is constant from frame setattr(final_frame, field_size, getattr(spec, field_size)) elif matches == (True, True, False): setattr(final_frame, field_coord, options.get_value(field_start, view)) setattr(final_frame, field_size, options.get_value(field_size, view)) elif matches == (False, True, False): # magical centering! size_val = options.get_value(field_size, view) setattr(final_frame, field_size, size_val) setattr(final_frame, field_coord, getattr(superview_bounds, field_size) / 2 - size_val / 2) elif matches == (False, True, True): size_val = options.get_value(field_size, view) setattr( final_frame, field_coord, getattr(superview_bounds, field_size) - options.get_value(field_end, view) - size_val) setattr(final_frame, field_size, size_val) elif matches == (False, False, True): setattr( final_frame, field_coord, getattr(superview_bounds, field_size) - options.get_value(field_end, view)) # pretend that size is constant from frame setattr(final_frame, field_size, getattr(spec, field_size)) elif matches == (True, False, True): start_val = options.get_value(field_start, view) end_val = options.get_value(field_end, view) setattr(final_frame, field_coord, start_val) setattr( final_frame, field_size, getattr(superview_bounds, field_size) - start_val - end_val) else: raise ValueError("Unhandled case: {}".format(debug_string)) assert (final_frame.x != -1000) assert (final_frame.y != -1000) assert (final_frame.width != -1000) assert (final_frame.height != -1000) view.frame = final_frame.floored
import weakref from collections import namedtuple from numbers import Real from clubsandwich.geom import Point, Rect, Size from clubsandwich.blt.context import BearLibTerminalContext from .layout_options import LayoutOptions ZERO_RECT = Rect(Point(0, 0), Size(0, 0)) class View: def __init__(self, frame=None, subviews=None, scene=None, layout_options=None): if isinstance(layout_options, dict): # have pity on the user's imports opts = LayoutOptions()._asdict() opts.update(layout_options) layout_options = LayoutOptions(**opts) self._scene = scene self._superview_weakref = lambda: None self.needs_layout = True self._frame = frame or ZERO_RECT self._bounds = self.frame.with_origin(Point(0, 0)) self.subviews = [] self.add_subviews(subviews or []) self.is_first_responder = False self.is_hidden = False
def frame(self, new_value): if new_value == self._frame: return self._frame = new_value self._bounds = new_value.with_origin(Point(0, 0)) self.set_needs_layout(True)