def draw_stats(root_console: tcod.console.Console) -> None: root_console.default_fg = tcod.grey root_console.print_( ROOT_WIDTH - 1, ROOT_HEIGHT - 1, ' last frame : %3d ms (%3d fps)' % ( tcod.sys_get_last_frame_length() * 1000.0, tcod.sys_get_fps(), ), tcod.BKGND_NONE, tcod.RIGHT)
def draw_entity(con: tcod.console.Console, entity, fov_map, game_map): if fov_map.fov[entity.pos.y][entity.pos.x] or ( entity.stairs and game_map.tiles[entity.pos.x][entity.pos.y].explored): con.default_fg = entity.render.color con.put_char(entity.pos.x, entity.pos.y, ord(entity.render.char), tcod.BKGND_NONE)
def render(self, console: tcod.console.Console) -> None: """Render this maps contents onto a console.""" cam_x, cam_y = self.get_camera_pos(console) # Get the screen and world view slices. screen_view, world_view = self.get_camera_views(console) # Draw the console based on visible or explored areas. console.tiles_rgb[screen_view] = np.select( (self.visible[world_view], self.explored[world_view]), (self.tiles["light"][world_view], self.tiles["dark"][world_view]), self.DARKNESS, ) # Collect and filter the various entity objects. visible_objs: Dict[Tuple[int, int], List[Graphic]] = defaultdict(list) for obj in self.actors: obj_x, obj_y = obj.location.x - cam_x, obj.location.y - cam_y if not (0 <= obj_x < console.width and 0 <= obj_y < console.height): continue if not self.visible[obj.location.ij]: continue visible_objs[obj_y, obj_x].append(obj.fighter) for (item_x, item_y), items in self.items.items(): obj_x, obj_y = item_x - cam_x, item_y - cam_y if not (0 <= obj_x < console.width and 0 <= obj_y < console.height): continue if not self.visible[item_y, item_x]: continue visible_objs[obj_y, obj_x].extend(items) # Draw the visible entities. for ij, graphics in visible_objs.items(): graphic = min(graphics) console.tiles_rgb[["ch", "fg"]][ij] = graphic.char, graphic.color
def render(self, console: tcod.console.Console) -> None: console.tiles['ch'][:self.width, :self.height] = ord(' ') dark = np.where(self.tiles[..., np.newaxis], self.COLORS['dark_ground'], self.COLORS['dark_wall']) light = np.where(self.tiles[..., np.newaxis], self.COLORS['light_ground'], self.COLORS['light_wall']) # conditions, pick_from_if_true, default console.tiles['bg'][:self.width, :self.height, :3] = np.select( (self.visible[..., np.newaxis], self.explored[..., np.newaxis]), (light, dark), (0, 0, 0)) for obj in self.entities: if Sprite not in obj: continue if Fighter in obj and obj[Fighter].is_dead: continue x, y = xy = obj[Location].xy if not (0 <= x < console.width and 0 <= y < console.height): continue if not self.visible[xy]: continue console.tiles['ch'][xy] = obj[Sprite].char console.tiles['fg'][x, y, :3] = obj[Sprite].color
def draw_status( root_console: libtcod.console.Console, status_y: Coordinates, player_hp: int ) -> None: msg = f'HP: {player_hp:2}' root_console.print(x=0, y=status_y, string=msg, fg=libtcod.blue)
def draw_map( root_console: libtcod.console.Console, map_tiles: List[List[str]], exit_coords: Coordinates, player_coords: Coordinates, mobs_coords: List[Coordinates] ) -> None: y = 0 for row in map_tiles: x = 0 for tile in row: color = libtcod.white if x == player_coords.x and y == player_coords.y: tile = '@' color = libtcod.yellow elif Coordinates(x, y) in mobs_coords: tile = 'o' color = libtcod.red elif x == exit_coords.x and y == exit_coords.y: tile = '<' color = libtcod.green root_console.draw_rect(x=x, y=y, width=1, height=1, ch=ord(tile), fg=color, bg_blend=libtcod.BKGND_NONE) x += 1 y += 1
def render_main(console: tcod.console.Console, visible_callbacks: Iterable[Layer] = ()) -> None: """Rendeer the main view. With the world tiles, any objects, and the UI.""" # Render map view. console_shape = (console.width - UI_SIZE[0], console.height - UI_SIZE[1]) screen_view, world_view = g.world.map.camera.get_views(g.world.map.tiles.shape, console_shape) console.tiles_rgb[: console_shape[0], : console_shape[1]] = SHROUD console.tiles_rgb[screen_view] = render_map( g.world.map, world_view, fullbright=g.debug_fullbright, visible_callbacks=visible_callbacks ) render_slots(console) STATUS_WIDTH = 20 console.tiles_rgb[: -UI_SIZE[0], -UI_SIZE[1]] = 0x2592, BORDER_COLOR, BLACK # Bar along the lower end of the map. console.tiles_rgb[-UI_SIZE[0] - STATUS_WIDTH - 1, -UI_SIZE[1] :] = (0x2592, BORDER_COLOR, BLACK) # log/status bar. log_console = tcod.Console(console.width - UI_SIZE[0] - STATUS_WIDTH - 1, UI_SIZE[1] - 1) render_log(log_console) log_console.blit(console, 0, console.height - UI_SIZE[1] + 1) status_console = tcod.Console(STATUS_WIDTH, UI_SIZE[1] - 1) status_console.print(0, 0, f"Status - {g.world.player.x},{g.world.player.y}") status_console.print(0, 1, f"HP {g.world.player.hp}") status_console.print(0, status_console.height - 1, f"Dungeon level {g.world.map.level}") status_console.blit(console, console.width - UI_SIZE[0] - STATUS_WIDTH, console.height - UI_SIZE[1] + 1)
def render_log(log_console: tcod.console.Console) -> None: """Render the log to a dedicated console.""" y = log_console.height for message in reversed(g.world.log): y -= tcod.console.get_height_rect(log_console.width, message) if y < 0: break log_console.print_box(0, y, 0, 0, message, fg=TEXT_COLOR, bg=BG)
def on_draw(self, console: tcod.console.Console) -> None: """Draw inventory menu over the previous state.""" inventory_ = self.model.player.inventory rendering.draw_main_view(self.model, console) style: Any = {"fg": (255, 255, 255), "bg": (0, 0, 0)} console.print(0, 0, self.desc, **style) for i, item in enumerate(inventory_.contents): sym = inventory_.symbols[i] console.print(0, 2 + i, f"{sym}: {item.name}", **style)
def blit_and_flush( from_console: tcod.console.Console, to_console: tcod.console.Console ) -> None: from_console.blit( to_console, width=from_console.width, height=from_console.height ) tcod.console_flush()
def render(self, console: tcod.console.Console) -> None: """Render this maps contents onto a console.""" # Get the view size from the window size or world size, # whichever is smaller. view_width = min(self.width, console.width) view_height = min(self.height, console.height) # Get the upper left camera position, assuming camera_xy is the center. cam_x = self.camera_xy[0] - view_width // 2 cam_y = self.camera_xy[1] - view_height // 2 cam_x = max(0, min(cam_x, self.width - view_width)) cam_y = max(0, min(cam_y, self.height - view_height)) # Get the screen and world view slices. screen_view = np.s_[:view_width, :view_height] world_view = np.s_[cam_x:cam_x + view_width, cam_y:cam_y + view_height] enemy_fov = np.zeros((view_width, view_height), dtype=bool) for actor in self.actors: if actor is self.player: continue enemy_fov |= actor.fov[world_view] enemy_fov &= self.visible[world_view] # Draw the console based on visible or explored areas. console.tiles_rgb[screen_view] = np.select( (enemy_fov, self.visible[world_view], self.explored[world_view]), ( self.tiles["light"][world_view], self.tiles["dark"][world_view], self.tiles["memory"][world_view], ), self.DARKNESS, ) # Collect and filter the various entity objects. visible_objs: Dict[Tuple[int, int], List[Graphic]] = defaultdict(list) for obj in self.actors: obj_x, obj_y = obj.location.x - cam_x, obj.location.y - cam_y if not (0 <= obj_x < view_width and 0 <= obj_y < view_height): continue if not self.visible[obj.location.xy]: continue visible_objs[obj_x, obj_y].append(obj.fighter) for (item_x, item_y), items in self.items.items(): obj_x, obj_y = item_x - cam_x, item_y - cam_y if not (0 <= obj_x < view_width and 0 <= obj_y < view_height): continue if not self.visible[item_x, item_y]: continue visible_objs[obj_x, obj_y].extend(items) # Draw the visible entities. for xy, graphics in visible_objs.items(): graphic = min(graphics) console.tiles_rgb[["ch", "fg"]][xy] = graphic.char, graphic.color
def on_draw(self, console: tcod.console.Console) -> None: super().on_draw(console) style: Any = {"fg": (255, 255, 255), "bg": (0, 0, 0)} console.print(0, 0, self.desc, **style) cam_x, cam_y = self.model.active_map.camera.get_left_top_pos( (console.width, console.height)) x = self.cursor_xy[0] - cam_x y = self.cursor_xy[1] - cam_y if 0 <= x < console.width and 0 <= y < console.height: console.tiles_rgb.T[["fg", "bg"]][x, y] = (0, 0, 0), (255, 255, 255)
def printStatus(self, inConsole: tcod.console.Console): ''' Draws status on console. ''' inConsole.print_(0, MAP_HEIGHT, self.lstStatus[0]) if self.bHasShield: inConsole.print_(0, MAP_HEIGHT + 1, self.lstStatus[1]) if self.bHasMelee: inConsole.print_(0, MAP_HEIGHT + 2, self.lstStatus[2]) if self.bHasRanged: inConsole.print_(0, MAP_HEIGHT + 3, self.lstStatus[3]) inConsole.print_(0, MAP_HEIGHT + 4, self.lstStatus[4])
def on_draw(self, console: tcod.console.Console) -> None: console.clear() width, height = 60, 32 console.print_box( (console.width - width) // 2, (console.height - height) // 2, width, height, WIN_TEXT, fg=engine.rendering.TEXT_COLOR, bg=None, )
def render_bar(panel: tcod.console.Console, x: int, y: int, total_width: int, name: str, value: int, maximum: int, bar_color: Tuple[int, int, int], back_color: Tuple[int, int, int]): bar_width = int(float(value) / maximum * total_width) panel.bg[x:x + total_width, y] = back_color if bar_width > 0: panel.bg[x:x + bar_width, y] = bar_color bar_str = f"{name}: {value}/{maximum}" px = x + ((total_width // 2) - (len(bar_str) // 2)) panel.print(px, y, bar_str, fg=(255, 255, 255))
def on_draw(self, console: tcod.console.Console) -> None: engine.rendering.render_main(console) console.tiles_rgb["fg"] //= 12 console.tiles_rgb["bg"] //= 12 width, height = 30, 8 left = (console.width - width) // 2 top = (console.height - height) // 2 for i, (text, _) in enumerate(self.menu): fg = engine.rendering.TEXT_COLOR bg = None if i == self.cursor: bg = engine.rendering.TEXT_COLOR fg = engine.rendering.BLACK console.print(left, top + i, text, fg=fg, bg=bg)
def draw_entity(offscreen_console: tcod.console.Console, entity: Entity, game_map: GameMap, camera: "Camera"): x, y = camera.to_camera_coordinates(entity.x, entity.y) if tcod.map_is_in_fov(game_map.fov_map, entity.x, entity.y) or ( entity.stairs and game_map.explored[entity.x, entity.y]): if x is not None and y is not None: offscreen_console.tiles2[x, y] = (entity.glyph, entity.fg, game_map.tile_map.default_bg) if entity.stairs and not tcod.map_is_in_fov(game_map.fov_map, entity.x, entity.y): if x is not None and y is not None: offscreen_console.bg[x, y] = np.multiply( game_map.tile_map.default_bg, 0.50).astype(np.int)
def on_draw(self, console: tcod.console.Console) -> None: engine.rendering.render_main(console) console.tiles_rgb["fg"] //= 16 console.tiles_rgb["bg"] //= 16 width, height = 60, 32 console.print_box( (console.width - width) // 2, (console.height - height) // 2, width, height, HELP_TEXT, fg=engine.rendering.TEXT_COLOR, bg=None, )
def clear_all(viewport_console: tcod.console.Console, entities: List, camera: "Camera"): for entity in entities: x, y = camera.to_camera_coordinates(entity.x, entity.y) # print(x, y) if x is not None and y is not None: viewport_console.ch[x, y] = 0
def menu(root: tcod.console.Console, header: str, options: list, width: int, screen_width: int, screen_height: int): if len(options) > 26: raise ValueError('Cannot have a menu with more than 26 options') # calculate total height for header (after auto-wrap) and one line per option header_height = root.get_height_rect(0, 0, width, screen_height, header) height = len(options) + header_height # create an off-screen console that represents the menu's window window = tcod.console.Console(width, height) window.default_bg = tcod.black # print the header, with auto-wrap window.default_fg = tcod.white window.print_rect(0, 0, width, height, header, tcod.BKGND_NONE, tcod.LEFT) # print all the options y = header_height letter_index = ord('a') for option in options: text = '(' + chr(letter_index) + ') ' + option window.print_(0, y, text, tcod.BKGND_NONE, tcod.LEFT) y += 1 letter_index += 1 # blit the contents of 'window' to the root console x = int(screen_width / 2 - width / 2) y = int(screen_height / 2 - height / 2) window.blit(root, x, y, 0, 0, width, height, 1.0, 0.7)
def printLog(self, inConsole: tcod.console.Console): #take most recent string. how long? split according to intWidth, count # of resulting lines. #print from bottom up, I guess. y = 0 for i in range(self.lstMessageLog.__len__()): # tcod.console_print(inConsole, MAP_WIDTH - MESSAGE_WIDTH, MAP_HEIGHT + y, self.lstMessageLog[i]) # inConsole.default_bg = BLACK # inConsole.default_fg = WHITE # tcod.console_set_default_foreground(inConsole, RED_DARK) # tcod.console_print_ex(inConsole, MAP_WIDTH - MESSAGE_WIDTH, MAP_HEIGHT + y, tcod.BKGND_NONE, tcod.LEFT, self.lstMessageLog[i]) # inConsole.print_(MAP_WIDTH - MESSAGE_WIDTH, MAP_HEIGHT + y, self.lstMessageLog[i], tcod.BKGND_NONE, tcod.LEFT) inConsole.print_(MAP_WIDTH - MESSAGE_WIDTH, MAP_HEIGHT + y, self.lstMessageLog[i]) y += 1 # console, 0, MAP_HEIGHT, tcod.BKGND_NONE, tcod.LEFT, "(" + str(mouse.cx) + "," + str(mouse.cy) + "): " + map1.alstObject[mouse.cx][mouse.cy][map1.top(mouse.cx, mouse.cy)].getName() + " ") # print("message log:", MAP_WIDTH, MAP_HEIGHT, MESSAGE_WIDTH, MESSAGE_HEIGHT, self.alstMessageLog[i])
def main_menu(root_console: tcod.console.Console, background_image: tcod.image.Image, screen_width: int, screen_height: int) -> None: background_image.blit_2x(root_console, 0, 0) root_console.print(screen_width // 2, screen_height // 2 - 4, "TOMBS OF THE ANCIENT KINGS", fg=cast_to_color(tcod.light_yellow), bg_blend=tcod.BKGND_NONE, alignment=tcod.CENTER) root_console.print(screen_width // 2, screen_height - 2, "By Marius Gedminas (but not really)", fg=cast_to_color(tcod.light_yellow), bg_blend=tcod.BKGND_NONE, alignment=tcod.CENTER) menu(root_console, '', ['Play a new game', 'Continue last game', 'Quit'], 24, screen_width, screen_height)
def render_map(root_console: tcod.console.Console, map_console: tcod.console.Console, game_map: GameMap, entities: list, start_x: int, start_y: int, colours: dict, fov_recompute: bool): # render map tiles only when a change has occurred if fov_recompute: for y in range(game_map.height): for x in range(game_map.width): visible = game_map.fov(x, y) wall = not game_map.walkable(x, y) # if tile can be seen now, light it up if visible: if wall: tcod.console_set_char_background( map_console, x, y, colours.get('light_wall'), tcod.BKGND_SET) else: tcod.console_set_char_background( map_console, x, y, colours.get('light_ground'), tcod.BKGND_SET) # if we've previously seen this tile elif game_map.explored(x, y): if wall: tcod.console_set_char_background( map_console, x, y, colours.get('dark_wall'), tcod.BKGND_SET) else: tcod.console_set_char_background( map_console, x, y, colours.get('dark_ground'), tcod.BKGND_SET) # render entities onto map entities_in_render_order = sorted(entities, key=lambda e: e.render_order.value) for entity in entities_in_render_order: draw_entity(map_console, entity, game_map) # copy to the actual screen map_console.blit(root_console, start_x, start_y, 0, 0, game_map.width, game_map.height) return
def render_bar(panel: tcod.console.Console, x: int, y: int, total_width: int, name: str, value: int, maximum: int, bar_colour: tcod.color.Color, back_colour: tcod.color.Color): bar_width = int(float(value) / maximum * total_width) panel.default_bg = back_colour panel.rect(x, y, total_width, 1, False, tcod.BKGND_SCREEN) panel.default_bg = bar_colour if bar_width > 0: tcod.console_rect(panel, x, y, bar_width, 1, False, tcod.BKGND_SCREEN) panel.rect(x, y, bar_width, 1, False, tcod.BKGND_SCREEN) panel.default_fg = tcod.white panel.print_(int(x + total_width / 2), y, '{0}: {1}/{2}'.format(name, value, maximum), tcod.BKGND_NONE, tcod.CENTER) return
def render_all(root_con: tcod.console.Console, con: tcod.console.Console, panel: tcod.console.Console, entities, player, game_map, fov_map, fov_recompute: bool, message_log, bar_width, panel_y: int, mouse_pos, colors, game_state: GameStates): """Render characters on the console screen""" render_main_map(con, entities, player, game_map, fov_map, fov_recompute, colors) con.blit(root_con) render_panel(panel, message_log, bar_width, player, mouse_pos, entities, fov_map, game_map.dungeon_level) panel.blit(root_con, 0, panel_y) if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): if game_state == GameStates.SHOW_INVENTORY: inventory_title = 'Press the key next to an item to use it, or Esc to cancel.\n' else: inventory_title = 'Press the key next to an item to drop it, or Esc to cancel.\n' inventory_menu(root_con, inventory_title, player, 50) elif game_state == GameStates.LEVEL_UP: level_up_menu(root_con, 'Level up! Choose a stat to raise:', player, 40) elif game_state == GameStates.CHARACTER_SCREEN: character_screen(root_con, player, 30, 10)
def render_slots(console: tcod.console.Console) -> None: """Render the spell slots UI.""" x = console.width - UI_SIZE[0] + 1 console.tiles_rgb[x - 1, :] = ord("▒"), BORDER_COLOR, BLACK for i, spell in enumerate(g.world.spell_slots): if spell is None: continue # Skip drawing this slot. spell_name = "--------" if spell is None else spell.name spell_console = tcod.console.Console(UI_SIZE[0] - 1, 6, order="F") spell_console.print(0, 0, f"{i+1:2d}. {spell_name}", fg=TEXT_COLOR, bg=BG) if spell is not None: spell_console.print(0, 1, f"Cooldown: {spell.cooldown_left}/{spell.cooldown_length}", fg=TEXT_COLOR, bg=BG) spell_console.print_box(0, 2, 0, 0, spell.desc, fg=TEXT_UNIMPORTANT, bg=BG) spell_console.blit(console, x, i * 6)
def render_bar(panel: tcod.console.Console, x: int, y: int, total_width: int, name, value, maximum, bar_color, back_color): bar_width = int(float(value) / maximum * total_width) panel.draw_rect(x, y, total_width, 1, 0, None, back_color) if bar_width > 0: panel.draw_rect(x, y, bar_width, 1, 0, None, bar_color) panel.print(int(x + total_width / 2), y, '{0}: {1}/{2}'.format(name, value, maximum), tcod.white, None, 1, tcod.CENTER)
def menu(root_console: tcod.console.Console, header: str, options: List[str], width: int, screen_width: int, screen_height: int) -> None: if len(options) > 26: raise ValueError('Cannot have a menu with more than 26 options.') # calculate total height for the header (after auto-wrap) and one line per # option header_height = root_console.get_height_rect(0, 0, width, screen_height, header) height = len(options) + header_height # create an off-screen console that represents the menu's window window = tcod.console.Console(width, height, order='F') # print the header, with auto-wrap window.print_box(0, 0, width, height, header, fg=cast_to_color(tcod.white), bg_blend=tcod.BKGND_NONE, alignment=tcod.LEFT) # print all the options y = header_height letter_index = ord('a') for option_text in options: text = f'({chr(letter_index)}) {option_text}' window.print(0, y, text, fg=cast_to_color(tcod.white), bg_blend=tcod.BKGND_NONE, alignment=tcod.LEFT) y += 1 letter_index += 1 # blit the contents of "window" to the root console x = (screen_width - width) // 2 y = (screen_height - height) // 2 window.blit(root_console, x, y, 0, 0, width, height, 1.0, 0.7)
def render_bar(panel: tcod.console.Console, x: int, y: int, total_width: int, name: str, value: int, maximum: int, bar_color: tcod.Color, back_color: tcod.Color) -> None: bar_width = value * total_width // maximum panel.draw_rect(x, y, total_width, 1, ch=0, bg=cast_to_color(back_color), bg_blend=tcod.BKGND_SCREEN) if bar_width > 0: panel.draw_rect(x, y, bar_width, 1, ch=0, bg=cast_to_color(bar_color), bg_blend=tcod.BKGND_SCREEN) panel.print(x + total_width // 2, y, f"{name}: {value}/{maximum}", fg=cast_to_color(tcod.white), bg_blend=tcod.BKGND_NONE, alignment=tcod.CENTER)
def draw_border(console: tcod.console.Console, style: Style) -> None: if style.border != Border.NONE: ch = ch = (ord(' '), ) * 6 if style.border == Border.SOLID: ch = (196, 179, 218, 191, 192, 217) elif style.border == Border.DOUBLE: ch = (205, 186, 201, 187, 200, 188) elif style.border == Border.EMPTY: ch = (ord(' '), ) * 6 elif style.border == Border.DOTTED: ch = (ord('.'), ) * 6 elif style.border == Border.DASHED: ch = (ord('-'), ord('|')) + (ord('+'), ) * 4 elif style.border == Border.PATTERN1: ch = (176, ) * 6 elif style.border == Border.PATTERN2: ch = (177, ) * 6 elif style.border == Border.PATTERN3: ch = (178, ) * 6 h, v, tl, tr, bl, br = ch bg = style.bg_color if style.border_bg_color is None \ else style.border_bg_color fg = style.fg_color if style.border_fg_color is None \ else style.border_fg_color console.ch[[0, -1], :] = h console.ch[:, [0, -1]] = v console.ch[[[0, -1], [-1, 0]], [0, -1]] = [[tl, br], [bl, tr]] console.bg[[0, -1], :] = bg console.bg[:, [0, -1]] = bg console.fg[[0, -1], :] = fg console.fg[:, [0, -1]] = fg