def draw(self, camera): x, y = camera.to_camera_coordinates(self.x, self.y) if self.projectile: terminal.put_ext(x * 4, y * 2, self.projectile.x_offset, self.projectile.y_offset, self.icon) else: terminal.put(x * 4, y * 2, self.icon)
def draw(self): x = self.top frame_height = self.height scrollbar_height = self.scrollbar_height frame_offset = self.offset messages_len = self.contents.total_height cell_height = blt.state(blt.TK_CELL_HEIGHT) blt.color(self.color) self.scrollbar_column = self.left + self.width self.scrollbar_offset = int( (x + (frame_height - scrollbar_height) * (1 - frame_offset / (messages_len - frame_height + 1))) * cell_height) # top line for i in range(self.left - 1, self.left + self.width + 2): blt.put(i, self.top - 1, '+') # bottom line for i in range(self.left - 1, self.left + self.width + 2): blt.put(i, self.top + self.height, '+') # left line for i in range(self.top - 1, self.top + self.height + 1): blt.put(self.left - 1, i, '+') # right line for i in range(self.top - 1, self.top + self.height + 1): blt.put(self.left + self.width + 1, i, '+') # scrollbar for i in range(self.scrollbar_height): blt.put_ext(self.scrollbar_column, i, 0, self.scrollbar_offset, 0x2588)
def pprint(self, x: int, y: int, string: str): """ Pretty prints a string starting at (x,y). :param x: x coordinate :param y: y coordinate :param string: String to print to screen """ bearlib.layer(1) bearlib.composition(bearlib.TK_ON) pos = x cell_size, _ = self.window.cell_size.split('x') cell_width = int(cell_size) for c in string: if pos >= self.window.width - x - 1: pos = pos + 1 offset = (pos - x) * (cell_width / 2) bearlib.put_ext(x, y, int(offset), 0, c) else: pos = pos + 1 offset = 0 - pos * (cell_width / 2) bearlib.put_ext(pos, y, int(offset), 0, c) bearlib.layer(0) bearlib.composition(bearlib.TK_OFF)
def pprint_center(self, text: List[str]): """ Prints a string or list of strings in the center of the window :param text: List of strings to be printed """ height = self.window.height width = self.window.width cellsize, _ = self.window.cell_size.split('x') cell_width = int(cellsize) center = int(width / 2) bearlib.clear() bearlib.layer(1) bearlib.composition("TK_ON") y = int(height / 2 - len(text) / 2) for i, s in enumerate(text): middle_char = int(len(s) / 2) x = int(center - middle_char) pos = 0 for c in s: offset = (center - x) * (cell_width / 2) bearlib.put_ext(x, y + i, int(offset), 0, c) x = x + 1 pos = pos + 1 bearlib.composition("TK_OFF") bearlib.layer(0) bearlib.refresh()
def clear_entity(ent, camera): # Clear an entity display on the terminal. prev_layer = terminal.state(terminal.TK_LAYER) terminal.layer(RenderLayer.ENTITIES.value) (term_x, term_y) = camera.to_camera_coordinates(ent.x, ent.y) terminal.put_ext(term_x, term_y, 0, 0, ' ', None) terminal.layer(prev_layer)
def draw(self): is_visible = libtcod.map_is_in_fov(FOV_MAP, self.x, self.y) if is_visible: tile_x, tile_y = draw_iso(self.x, self.y) # draw our entity's ASCII symbol at an offset # blt.put_ext(tile_x, tile_y, 0, blt.state(blt.TK_CELL_HEIGHT), self.char) # draw the tile at different offset because size of a tile is much different than the size of an ASCII letter blt.put_ext(tile_x, tile_y, 0, 2, self.char)
def render(self, x, y, symbol, layer, bkcolor=None): """Render the given symbol. May modify the state of terminal.color or terminal.bkcolor.""" # Set terminal blt.layer(layer) if bkcolor is not None: blt.bkcolor(bkcolor) blt.color(symbol.color) draw_x, draw_y = x + self.x_offset, y + self.y_offset blt.put_ext(draw_x, draw_y, symbol.dx, symbol.dy, symbol.char, None)
def draw_char_ex(dest, x, y, dx, dy, char, color=None, flag=None, alpha=255): # LIBTCOD # libtcod.console_put_char_ex(dest, x, y, char, color, flag) # BEARLIB terminal.layer(dest) # TODO: CONVERT COLORS ON THEME IMPORT, INSTEAD OF INLINE (all render func) if color is not None: #color = Utils.convert_color(color, alpha) terminal.color(color) terminal.put_ext(x, y, dx, dy, char, None)
def draw(self): # Frame background blt.layer(0) blt.bkcolor("darkest gray") blt.clear_area(self.left, self.top, self.width, self.height) # Scroll bar blt.bkcolor("darker gray") blt.clear_area(self.left + self.width, self.top, 1, self.height) blt.bkcolor("none") blt.color("dark orange") self.scrollbar_column = self.left + self.width self.scrollbar_offset = int( (self.top + (self.height - self.scrollbar_height) * (self.offset / (self.contents.total_height - self.height))) * blt.state(blt.TK_CELL_HEIGHT)) for i in range(self.scrollbar_height): blt.put_ext(self.scrollbar_column, i, 0, self.scrollbar_offset, 0x2588)
def render(self): if not self.messages: return self.update_geometry() terminal.layer = 0 terminal.clear_area(self.padding_left, self.padding_top, self.frame_width, self.frame_height) index: int = 0 first_line: int = 0 while index < self.total_messages_height: message = self.messages[index] _, message_height = terminal.measuref(message) if first_line + message_height >= self.frame_offset: break first_line += message_height + 1 index += 1 delta: int = int(first_line - self.frame_offset) terminal.layer = 1 while index < len(self.messages) and delta <= self.frame_height: message = self.messages[index] terminal.puts(self.padding_left, self.padding_top + delta, message, self.frame_width, 0, terminal.state(terminal.TK_ALIGN_DEFAULT)) _, message_height = terminal.measuref(message) delta += message_height index += 1 terminal.layer = 0 terminal.clear_area(self.padding_left + self.frame_width, self.padding_top, 1, self.frame_height) scrollbar_column: int = self.padding_left + self.frame_width scrollbar_offset = (self.padding_top + (self.frame_height - self.scrollbar_height) * (self.frame_offset / self.total_messages_height)) * terminal.state(terminal.TK_CELL_HEIGHT) for i in range(self.scrollbar_height): terminal.put_ext(scrollbar_column, i, 0, int(scrollbar_offset), 0x2588)
def draw(self, entity, x, y): if entity.hidden: return player = self.owner.player game_map = self.owner.levels.current_map # Draw the entity to the screen blt.layer(entity.layer) blt.color(entity.color) c = blt.color_from_name(entity.color) if not entity.cursor: light_map = player.player.lightmap argb = argb_from_color(c) a = argb[0] r = min(int(argb[1] * light_map[entity.y][entity.x]), 255) g = min(int(argb[2] * light_map[entity.y][entity.x]), 255) b = min(int(argb[3] * light_map[entity.y][entity.x]), 255) blt.color(blt.color_from_argb(a, r, g, b)) if not (player.light_source.fov_map.fov[entity.y, entity.x] and game_map.tiles[entity.x][entity.y].explored): blt.color("dark gray") # Cursor needs some offset in ascii if self.owner.options.gfx == "ascii" and entity.name == "cursor": blt.put_ext(x * self.owner.options.tile_offset_x, y * self.owner.options.tile_offset_y, -3 * self.owner.options.tile_offset_x, -5 * self.owner.options.tile_offset_y, entity.char) else: if entity.boss and not entity.fighter: blt.put((x - 1) * self.owner.options.tile_offset_x, (y - 1) * self.owner.options.tile_offset_y, entity.char) else: blt.put(x * self.owner.options.tile_offset_x, y * self.owner.options.tile_offset_y, entity.char)
def draw_side_panel_content(self): game_map = self.owner.levels.current_map player = self.owner.player side_panel = self.owner.ui.side_panel # Draw side panel content blt.layer(1) blt.color(None) x_margin = self.owner.ui.side_panel.x_margin map_title = fill(game_map.title, 21) blt.clear_area(side_panel.offset_x + x_margin, side_panel.offset_y + 20, side_panel.offset_w - x_margin, side_panel.offset_h - 40) blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + 21, "Location: " + map_title, 0, 0, blt.TK_ALIGN_LEFT) blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + 24 + map_title.count('\n'), "World tendency: " + str(self.owner.levels.world_tendency), 0, 0, blt.TK_ALIGN_LEFT) # Fetch player skills and draw icons weapon = [] attack = [] utility = [] for skill in player.abilities.items: if skill.skill_type == "weapon": weapon.append(skill) elif skill.skill_type == "attack": attack.append(skill) elif skill.skill_type == "utility": utility.append(skill) blt.color(None) # Weapon skills y_margin = 0 first_heading_y = 30 fill_chars = 32 for i, wpn in enumerate(weapon): if wpn.name == player.player.sel_weapon.name: # heading title = "Weapon (Switch: 'W')" blt.color("lighter yellow") blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + first_heading_y, fill(title, fill_chars), 0, 0, blt.TK_ALIGN_LEFT) # name of the selected skill blt.color(None) skill_str = "{0}, {1}+{2} dmg".format(wpn.name.capitalize(), wpn.damage[wpn.rank], player.fighter.str_bonus) blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + first_heading_y + 2, fill(skill_str, fill_chars), 0, 0, blt.TK_ALIGN_LEFT) # highlight icon of the selected skill blt.color("dark amber") y_margin += skill_str.count('\n') if i > 4: y_margin += 3 i = 0 blt.put(side_panel.offset_x + x_margin + 1 + i * 6, side_panel.offset_y + first_heading_y + 4, wpn.icon) blt.color(None) second_heading_y = first_heading_y + 9 # Attack skills for i, atk in enumerate(attack): if player.player.sel_attack and atk.name == player.player.sel_attack.name: # heading title = "Skills (Switch: 'A', Use: 'TAB')" blt.color("lighter green") blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + second_heading_y + y_margin, fill(title, fill_chars), 0, 0, blt.TK_ALIGN_LEFT) blt.color(None) skill_str = "{0}: ".format(atk.name) chance_str, atk_str, effect_str, duration_str = "", "", "", "" if atk.chance: # chance_str = str(int(1 / atk.chance[atk.rank])) + "% chance of " chance_str = "100% chance of " if atk.effect: effect_str = ", ".join(atk.effect) + ", " if atk.duration: duration_str = atk.duration[atk.rank] + " turns" if atk.damage: atk_str = ", " + atk.damage[atk.rank] + "+" + str(player.fighter.str_bonus) + " dmg" if duration_str \ else atk.damage[atk.rank] + "+" + str(player.fighter.str_bonus) + " dmg" skill_str += chance_str + effect_str + duration_str + atk_str blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + second_heading_y + 2 + y_margin, fill(skill_str.capitalize(), fill_chars), 0, 0, blt.TK_ALIGN_LEFT) # highlight icon of the selected skill blt.color("dark amber") y_margin += skill_str.count('\n') if i > 4: y_margin += 3 i = 0 blt.put(side_panel.offset_x + x_margin + 1 + i * 6, side_panel.offset_y + second_heading_y + 5 + y_margin, atk.icon) blt.color(None) third_heading_y = second_heading_y + 10 # Utility skills for i, utl in enumerate(utility): if player.player.sel_utility and utl.name == player.player.sel_utility.name: title = "Utility (Use: 'Z')" blt.color("lighter blue") blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + third_heading_y + y_margin, fill(title, fill_chars), 0, 0, blt.TK_ALIGN_LEFT) # name of the selected skill blt.color(None) skill_str = utl.name blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + third_heading_y + 2 + y_margin, fill(skill_str.capitalize(), fill_chars), 0, 0, blt.TK_ALIGN_LEFT) y_margin += skill_str.count('\n') blt.puts(side_panel.offset_x + x_margin, side_panel.offset_y + third_heading_y + 8 + y_margin, fill(utl.description.capitalize(), fill_chars), 46 + y_margin, 0, blt.TK_ALIGN_LEFT) # highlight icon of the selected skill blt.color("dark amber") if i > 4: y_margin += 3 i = 0 blt.put(side_panel.offset_x + x_margin + 1 + i * 6, side_panel.offset_y + third_heading_y + 5 + y_margin, utl.icon) blt.layer(0) blt.put_ext(side_panel.offset_x + x_margin + i * 6, side_panel.offset_y + third_heading_y + 5 + y_margin, -2, -14, str(i + 1)) blt.layer(1) blt.color(None)
def draw(self, xy: vec, layer: int = 0) -> None: blt.color(self.fg_colour.blt_colour()) if self.bg_colour is not None: blt.bkcolor(self.bg_colour.blt_colour()) xy = xy + self.xy blt.put_ext(xy.x, xy.y, self.dxy.x, self.dxy.y, self.char)
def test_extended_smooth_scroll(): random.seed() blt.set("window.title='Omni: extended output / smooth scroll'") blt.set("input.filter={keyboard+}") blt.composition(True) # Load resources blt.set("U+E000: ../Media/Tiles.png, size=32x32, alignment=top-left") screen_width = blt.state(blt.TK_WIDTH) * blt.state(blt.TK_CELL_WIDTH) screen_height = blt.state(blt.TK_HEIGHT) * blt.state(blt.TK_CELL_HEIGHT) hspeed = vspeed = 0 hoffset = voffset = 0 map_ = [[0] * map_size for _ in range(map_size)] for _ in range(map_size * map_size // 10): x = random.randrange(map_size) y = random.randrange(map_size) map_[y][x] = random.randrange(8) while True: hoffset -= hspeed voffset -= vspeed blt.clear() tx = hoffset % tile_size ty = voffset % tile_size ix = (hoffset - tx) // tile_size iy = (voffset - ty) // tile_size jx = (-ix) % map_size if ix < 0 else map_size - (ix % map_size) jy = (-iy) % map_size if iy < 0 else map_size - (iy % map_size) hc = (screen_width + 2 * tile_size - tx - 1) // tile_size vc = (screen_height + 2 * tile_size - ty - 1) // tile_size blt.puts(2, 1, "speed: %d, %d" % (hspeed, vspeed)) blt.puts(2, 2, "offset: %d/%d, %d/%d" % (ix, jx, iy, jy)) for y in range(vc + 1): my = (jy + y) % map_size for x in range(hc + 1): mx = (jx + x) % map_size c = map_[my][mx] blt.put_ext(0, 0, (x - 1) * tile_size + tx, (y - 1) * tile_size + ty, 0xE000 + c) blt.refresh() if blt.has_input(): key = blt.read() if key in (blt.TK_CLOSE, blt.TK_ESCAPE): break if blt.state(blt.TK_LEFT): if hspeed > -speed_cap: hspeed -= 1 elif blt.state(blt.TK_RIGHT): if hspeed < speed_cap: hspeed += 1 else: hspeed -= sgn(hspeed) if blt.state(blt.TK_UP): if vspeed > -speed_cap: vspeed -= 1 elif blt.state(blt.TK_DOWN): if vspeed < speed_cap: vspeed += 1 else: vspeed -= sgn(vspeed) blt.delay(1000 // fps) blt.set("U+E000: none") blt.set("input.filter={keyboard}") blt.composition(False)
def test_tilesets(): blt.set("window.title='Omni: tilesets'") blt.composition(True) # Load tilesets blt.set("U+E100: ./Images/Runic.png, size=8x16") blt.set("U+E200: ./Images/Tiles.png, size=32x32, align=top-left") blt.set("U+E400: ./Images/test_tiles.png, size=16x16, align=top-left") blt.set( "U+E300: ./Fonts/fontawesome-webfont.ttf, size=24x24, spacing=3x2, codepage=./Fonts/fontawesome-codepage.txt" ) blt.set( "zodiac font: ./Fonts/Zodiac-S.ttf, size=24x36, spacing=3x3, codepage=437" ) blt.clear() blt.color("white") blt.print_( 2, 1, "[color=orange]1.[/color] Of course, there is default font tileset.") blt.print_( 2, 3, "[color=orange]2.[/color] You can load some arbitrary tiles and use them as glyphs:" ) blt.print_( 2 + 3, 4, "Fire rune ([color=red][U+E102][/color]), " "water rune ([color=lighter blue][U+E103][/color]), " "earth rune ([color=darker green][U+E104][/color])") blt.print_( 2, 6, "[color=orange]3.[/color] Tiles are not required to be of the same size as font symbols:" ) blt.put(2 + 3 + 0, 7, 0xE200 + 7) blt.put(2 + 3 + 5, 7, 0xE200 + 8) blt.put(2 + 3 + 10, 7, 0xE200 + 9) blt.print_( 2, 10, "[color=orange]4.[/color] Like font characters, tiles may be freely colored and combined:" ) blt.put_ext(2 + 3 + 0, 11, 0, 0, tiles['stone_wall'], [ blt.color_from_name("red"), blt.color_from_name("red"), blt.color_from_name("blue"), blt.color_from_name("red") ]) blt.put_ext(2 + 3 + 2, 11, 0, 0, tiles['stone_wall'], [ blt.color_from_name("red"), blt.color_from_name("blue"), blt.color_from_name("red"), blt.color_from_name("red") ]) blt.put_ext(2 + 3 + 0, 13, 0, 0, tiles['stone_wall'], [ blt.color_from_name("red"), blt.color_from_name("red"), blt.color_from_name("blue"), blt.color_from_name("blue") ]) blt.put_ext(2 + 3 + 2, 13, 0, 0, tiles['stone_wall'], [ blt.color_from_name("blue"), blt.color_from_name("blue"), blt.color_from_name("red"), blt.color_from_name("red") ]) blt.put_ext(2 + 3 + 0 + 5, 11, 0, 0, '#', [ blt.color_from_name("yellow"), blt.color_from_name("black"), blt.color_from_name("black"), blt.color_from_name("black") ]) blt.put_ext(2 + 3 + 1 + 5, 11, 0, 0, 'A', [ blt.color_from_name("black"), blt.color_from_name("yellow"), blt.color_from_name("yellow"), blt.color_from_name("black") ]) blt.put_ext(2 + 3 + 0 + 5, 12, 0, 0, 'A', [ blt.color_from_name("black"), blt.color_from_name("black"), blt.color_from_name("yellow"), blt.color_from_name("yellow") ]) blt.put_ext(2 + 3 + 1 + 5, 12, 0, 0, '@', [ blt.color_from_name("dark yellow"), blt.color_from_name("dark yellow"), blt.color_from_name("dark yellow"), blt.color_from_name("dark yellow") ]) blt.put_ext(2 + 3 + 0 + 7, 11, 0, 0, 'A', [ blt.color_from_name("black"), blt.color_from_name("yellow"), blt.color_from_name("black"), blt.color_from_name("black") ]) blt.put_ext(2 + 3 + 0 + 7, 12, 0, 0, 'A', [ blt.color_from_name("yellow"), blt.color_from_name("yellow"), blt.color_from_name("black"), blt.color_from_name("black") ]) ''' # blt.color("lightest red") blt.put(2+3+4, 11,tiles['stairs']) # blt.color("purple") blt.put(2+3+8, 11, tiles['gold']) #blt.color("darkest red") blt.put(17, 11, 0xE400+0) blt.put(18, 11, 0xE400+0) blt.put(19, 11, 0xE400+1) blt.put(20, 11, 0xE400 + 0) blt.put(20, 11, 0xE400 + 2) blt.put(17, 12, 0xE400 + 10) blt.put(18, 12, 0xE400 + 10) blt.put(19, 12, 0xE400 + 11) blt.put(20, 12, 0xE400 + 10) blt.put(20, 12, 0xE400 + 12) ''' blt.put(21, 11, 0xE400 + 0) blt.color("blue") blt.put(18, 11, '@') blt.color("white") order = [11, 10, 14, 12, 13] for i in range(len(order)): blt.put(30 + i * 4, 11, 0xE200 + order[i]) blt.put(30 + (len(order) + 1) * 4, 11, 0xE200 + order[i]) blt.put(30 + len(order) * 4, 11, 0xE200 + 15) blt.print_( 2, 15, "[color=orange]5.[/color] And tiles can even come from TrueType fonts like this:" ) for i in range(6): blt.put(5 + i * 5, 15, 0xE300 + i) blt.print_(5, 18, "...or like this:\n[font=zodiac]D F G S C") blt.refresh() key = None while key not in (blt.TK_CLOSE, blt.TK_ESCAPE): key = blt.read() # Clean up blt.set("U+E100: none; U+E200: none; U+E300: none; zodiac font: none") blt.composition(False)
def draw(self): for draw_args in self.draw_iter(): blt.put_ext(*draw_args)
def print_state(matrix, colors): for index, cell in np.ndenumerate(matrix): terminal.put_ext(index[1] + 1, index[0] + 1, 0, 0, 0x2588, colors[int(cell)])
def render(self): # No need to render endlessly # EDIT: Actually now I need it # if not self.re_render: # return blt.clear() self.render_frames() # Gameboard related stuff blt.layer(0) # Coloring the different panels if DEBUG: for y in range(MESSAGE_PANEL.y, MESSAGE_PANEL.y + MESSAGE_PANEL.h): for x in range(MESSAGE_PANEL.x, MESSAGE_PANEL.x + MESSAGE_PANEL.w): blt.bkcolor('green') blt.put(x, y, ' ') for y in range(STATS_PANEL.y, STATS_PANEL.y + STATS_PANEL.h): for x in range(STATS_PANEL.x, STATS_PANEL.x + STATS_PANEL.w): blt.bkcolor('blue') blt.put(x, y, ' ') for y in range(STATS_ENEMY_PANEL.y, STATS_ENEMY_PANEL.y + STATS_ENEMY_PANEL.h): for x in range(STATS_ENEMY_PANEL.x, STATS_ENEMY_PANEL.x + STATS_ENEMY_PANEL.w): blt.bkcolor('red') blt.put(x, y, ' ') for y in range(BUTTONS_PANEL.y, BUTTONS_PANEL.y + BUTTONS_PANEL.h): for x in range(BUTTONS_PANEL.x, BUTTONS_PANEL.x + BUTTONS_PANEL.w): blt.bkcolor('violet') blt.put(x, y, ' ') # Board drawing for y, row in enumerate(self.gamemap.terrain): for x, tile in enumerate(row): blt.bkcolor(tile.color) blt.puts((x + self.map_offset.x) * TERRAIN_SCALE_X, (y + self.map_offset.y) * TERRAIN_SCALE_Y, '[font=terrain] [/font]') blt.layer(0) # Legal moves for current actors self.highlighted_cases = self.get_possible_movement(self.unit_turn) for highlight in self.highlighted_cases: color = 'turquoise' if highlight['valid'] == 'enemy': color = 'red' if highlight['valid'] == 'false': color = 'amber' blt.bkcolor(color) blt.puts((highlight['mov'].x + self.map_offset.x) * TERRAIN_SCALE_X, (highlight['mov'].y + self.map_offset.y) * TERRAIN_SCALE_Y, '[font=terrain] [/font]') # Coordinates blt.bkcolor('black') # for y in range(10): # blt.puts(0, (y + offset.y) * TERRAIN_SCALE_Y, f'[font=terrain]{str(y)}[/font]') # blt.puts((self.gamemap.h + 1) * TERRAIN_SCALE_X, (y + offset.y) * TERRAIN_SCALE_Y, f'[font=terrain]{str(y)}[/font]') # blt.puts((y + 1) * TERRAIN_SCALE_X, (offset.y - 1) * TERRAIN_SCALE_Y, f'[font=terrain]{chr(65 + y)}[/font]') # blt.puts((y + 1) * TERRAIN_SCALE_X, (offset.y + self.gamemap.h) * TERRAIN_SCALE_Y, f'[font=terrain]{chr(65 + y)}[/font]') # actors blt.layer(2) # First, the daed actors, so that they are below the living ones # for actor in [a for a in self.actors if a.dead]: # blt.color(actor.color) # blt.puts((actor.x + self.map_offset.x) * TERRAIN_SCALE_X, # (actor.y + self.map_offset.y) * TERRAIN_SCALE_Y, actor.charac) # Then the living ones for actor in [a for a in self.actors if not a.dead]: if actor.sprite: blt.put_ext((actor.x + self.map_offset.x) * TERRAIN_SCALE_X, (actor.y + self.map_offset.y) * TERRAIN_SCALE_Y, 0, 0, actor.sprite) else: blt.color(actor.color) blt.puts(((actor.x + self.map_offset.x) * TERRAIN_SCALE_X), (actor.y + self.map_offset.y) * TERRAIN_SCALE_Y, f'[offset={TERMINAL_CELL_SIZE_X/2},0]{actor.charac}[/offset]') # Text blt.layer(3) off_x = (self.gamemap.w + self.map_offset.x) * TERRAIN_SCALE_X off_y = (self.gamemap.h + self.map_offset.y) * TERRAIN_SCALE_Y blt.color('white') blt.bkcolor('black') self.render_stats(STATS_PANEL.x, STATS_PANEL.y, self.unit_turn) if self.under_mouse: self.render_stats(STATS_ENEMY_PANEL.x, STATS_ENEMY_PANEL.y, self.under_mouse) blt.puts(BUTTONS_PANEL.top_right.x - 8, BUTTONS_PANEL.top_right.y, 'End turn') if self.message_queue: blt.puts(MESSAGE_PANEL.x, MESSAGE_PANEL.y, self.message_queue[-1], MESSAGE_PANEL.w, MESSAGE_PANEL.h, blt.TK_ALIGN_LEFT) self.re_render = False
def draw_entity(entity, fov_map): if libtcod.map_is_in_fov(fov_map, entity.x, entity.y): blt.color(blt.color_from_name(entity.color)) blt.bkcolor(blt.color_from_name("transparent")) blt.put_ext(entity.x, entity.y, 0, -2, entity.char, None)
def test_tilesets(): blt.set("window.title='Omni: tilesets'") blt.composition(True) # Load tilesets blt.set("U+E100: ./Images/Runic.png, size=8x16") blt.set("U+E200: ./Images/Tiles.png, size=32x32, align=top-left") blt.set("U+E400: ./Images/test_tiles.png, size=16x16, align=top-left") blt.set("U+E300: ./Fonts/fontawesome-webfont.ttf, size=24x24, spacing=3x2, codepage=./Fonts/fontawesome-codepage.txt") blt.set("zodiac font: ./Fonts/Zodiac-S.ttf, size=24x36, spacing=3x3, codepage=437") blt.clear() blt.color("white") blt.print_(2, 1, "[color=orange]1.[/color] Of course, there is default font tileset.") blt.print_(2, 3, "[color=orange]2.[/color] You can load some arbitrary tiles and use them as glyphs:") blt.print_(2+3, 4, "Fire rune ([color=red][U+E102][/color]), " "water rune ([color=lighter blue][U+E103][/color]), " "earth rune ([color=darker green][U+E104][/color])") blt.print_(2, 6, "[color=orange]3.[/color] Tiles are not required to be of the same size as font symbols:") blt.put(2+3+0, 7, 0xE200+7) blt.put(2+3+5, 7, 0xE200+8) blt.put(2+3+10, 7, 0xE200+9) blt.print_(2, 10, "[color=orange]4.[/color] Like font characters, tiles may be freely colored and combined:") blt.put_ext(2+3+0, 11, 0, 0, tiles['stone_wall'], [blt.color_from_name("red"), blt.color_from_name("red"), blt.color_from_name("blue"), blt.color_from_name("red")]) blt.put_ext(2 + 3 + 2, 11, 0, 0, tiles['stone_wall'], [blt.color_from_name("red"), blt.color_from_name("blue"), blt.color_from_name("red"), blt.color_from_name("red")]) blt.put_ext(2 + 3 + 0, 13, 0, 0, tiles['stone_wall'], [blt.color_from_name("red"), blt.color_from_name("red"), blt.color_from_name("blue"), blt.color_from_name("blue")]) blt.put_ext(2 + 3 + 2, 13, 0, 0, tiles['stone_wall'], [blt.color_from_name("blue"), blt.color_from_name("blue"), blt.color_from_name("red"), blt.color_from_name("red")]) blt.put_ext(2 + 3 + 0 + 5, 11, 0, 0, '#', [blt.color_from_name("yellow"), blt.color_from_name("black"), blt.color_from_name("black"), blt.color_from_name("black")]) blt.put_ext(2 + 3 + 1 + 5, 11, 0, 0, 'A', [blt.color_from_name("black"), blt.color_from_name("yellow"), blt.color_from_name("yellow"), blt.color_from_name("black")]) blt.put_ext(2 + 3 + 0 + 5, 12, 0, 0, 'A', [blt.color_from_name("black"), blt.color_from_name("black"), blt.color_from_name("yellow"), blt.color_from_name("yellow")]) blt.put_ext(2 + 3 + 1 + 5, 12, 0, 0,'@', [blt.color_from_name("dark yellow"), blt.color_from_name("dark yellow"), blt.color_from_name("dark yellow"), blt.color_from_name("dark yellow")]) blt.put_ext(2 + 3 + 0 + 7, 11, 0, 0, 'A', [blt.color_from_name("black"), blt.color_from_name("yellow"), blt.color_from_name("black"), blt.color_from_name("black")]) blt.put_ext(2 + 3 + 0 + 7, 12, 0, 0, 'A', [blt.color_from_name("yellow"), blt.color_from_name("yellow"), blt.color_from_name("black"), blt.color_from_name("black")]) ''' # blt.color("lightest red") blt.put(2+3+4, 11,tiles['stairs']) # blt.color("purple") blt.put(2+3+8, 11, tiles['gold']) #blt.color("darkest red") blt.put(17, 11, 0xE400+0) blt.put(18, 11, 0xE400+0) blt.put(19, 11, 0xE400+1) blt.put(20, 11, 0xE400 + 0) blt.put(20, 11, 0xE400 + 2) blt.put(17, 12, 0xE400 + 10) blt.put(18, 12, 0xE400 + 10) blt.put(19, 12, 0xE400 + 11) blt.put(20, 12, 0xE400 + 10) blt.put(20, 12, 0xE400 + 12) ''' blt.put(21, 11, 0xE400+0) blt.color("blue") blt.put(18, 11, '@') blt.color("white") order = [11, 10, 14, 12, 13] for i in range(len(order)): blt.put(30 + i * 4, 11, 0xE200 + order[i]); blt.put(30 + (len(order)+1) * 4, 11, 0xE200 + order[i]) blt.put(30 + len(order) * 4, 11, 0xE200 + 15) blt.print_(2, 15, "[color=orange]5.[/color] And tiles can even come from TrueType fonts like this:") for i in range(6): blt.put(5 + i * 5, 15, 0xE300 + i) blt.print_(5, 18, "...or like this:\n[font=zodiac]D F G S C") blt.refresh() key = None while key not in (blt.TK_CLOSE, blt.TK_ESCAPE): key = blt.read() # Clean up blt.set("U+E100: none; U+E200: none; U+E300: none; zodiac font: none") blt.composition(False)
def test_extended_basics(): # Setup blt.set("window.title='Omni: extended output / basics'") blt.set("0xE000: ../Media/Tiles.png, size=32x32, align=top-left") blt.composition(True) cx, cy = 10, 5 n_symbols = 10 radius = 5 angle = 0.0 fps = 25 transparent, opaque = 0x00FFFFFF, 0xFFFFFFFF m00 = [0xFFFF0000, 0xFF00FF00, 0xFF0000FF, 0xFFFFFF00] m01 = [opaque, opaque, transparent, transparent] m11 = [transparent, transparent, opaque, transparent] m12 = [transparent, opaque, transparent, transparent] m21 = [transparent, transparent, transparent, opaque] m22 = [opaque, transparent, transparent, transparent] while True: blt.clear() blt.color("white") blt.puts( 2, 1, "[color=orange]1.[/color] put_ext(x, y, [color=orange]dx[/color], [color=orange]dy[/color], code)" ) for i in range(n_symbols): angle_delta = 2 * pi / n_symbols dx = cos(angle + i * angle_delta) * radius * blt.state( blt.TK_CELL_WIDTH) dy = sin(angle + i * angle_delta) * radius * blt.state( blt.TK_CELL_WIDTH) - 4 blt.color("white" if i > 0 else "orange") blt.put_ext(cx, cy, int(dx), int(dy), ord('a') + i) angle += 2 * pi / (2 * fps) blt.puts( 2, 9, "[color=orange]2.[/color] put_ext(x, y, dx, dy, code, [color=orange]corners[/color])" ) blt.put_ext(5, 11, 0, 0, 0xE000 + 19, m00) blt.put_ext(10, 11, 0, 0, 0xE000 + 19, m01) blt.puts(2, 14, "[color=orange]3.[/color] put_ext + composition") x1 = 5 y1 = 16 blt.put(x1 + 0, y1 + 0, 0xE000 + 19) blt.put(x1 + 0, y1 + 2, 0xE000 + 8) blt.put(x1 + 5, y1 + 0, 0xE000 + 19) blt.put(x1 + 9, y1 + 0, 0xE000 + 19) blt.put(x1 + 5, y1 + 2, 0xE000 + 19) blt.put(x1 + 9, y1 + 2, 0xE000 + 19) blt.put_ext(x1 + 5, y1 + 0, 0, 0, 0xE000 + 8, m11) blt.put_ext(x1 + 9, y1 + 0, 0, 0, 0xE000 + 8, m12) blt.put_ext(x1 + 5, y1 + 2, 0, 0, 0xE000 + 8, m21) blt.put_ext(x1 + 9, y1 + 2, 0, 0, 0xE000 + 8, m22) blt.refresh() if blt.has_input(): key = blt.read() if key in (blt.TK_CLOSE, blt.TK_ESCAPE): break blt.delay(1000 // fps) # Clean up blt.composition(False) blt.set("0xE000: none")
def main(): terminal.open() terminal.set("output.vsync=true") terminal.set( "window: title='Plasma Rain', resizeable=true, minimum-size=16x12") terminal.set("window: size={}x{}; font: ".format(INITIAL_SCREEN_WIDTH, INITIAL_SCREEN_LENGTH) + os.path.join(DIR_PATH, '../data/media/lucida.ttf') + ", size={}x{}".format(TILE_WIDTH, TILE_LENGTH)) terminal.set("input.filter= [keyboard+, mouse_move]" ) # Only key release and mouse move trigger state updates terminal.composition(terminal.TK_ON) terminal.bkcolor(terminal.color_from_name("gray")) # grey (or gray), red, flame, orange, amber, yellow, lime, # chartreuse, green, sea, turquoise, cyan, sky, azure, blue, # han, violet, purple, fuchsia, magenta, pink, crimson, transparent terminal.color(terminal.color_from_name("black")) x_speed, y_speed, text_offset = (0, ) * 3 # initialize blank tile_map tile_map: [[[Tile]]] = [[[EMPTY_TILE for _ in range(MAP_WIDTH)] for _ in range(MAP_LENGTH)] for _ in range(MAP_DEPTH)] unit_map: [[[Optional[Unit]]]] = [[[None for _ in range(MAP_WIDTH)] for _ in range(MAP_LENGTH)] for _ in range(MAP_DEPTH)] blueprints = build_blueprints( load_json(os.path.join(mods_dir, "vanilla/blueprints/"), pickle=False)) unit_map[0][0][0] = Unit(blueprint=blueprints['unit']['Human'], armor=blueprints['armor']['Suit'], current_stats=[0, 0, 0, 0, 0], overlay_stats=[0, 0, 0, 0, 0]) zone = load_zone(os.path.join(DIR_PATH, '../data/placeholder/map2.json'), blueprints) paste_zone(zone, tile_map, z=0, y=0) prev_frame_time = time.perf_counter() iterations = 0 # tile_map will only render to screen inside the display, generally set to not overlap with UI # tile_map will only be scrollable between the offset bounds # coordinates are down-right = positive, "opposite" for the offset # set offset_leniency to 1 and you will only be allowed to scroll 1 more tile than enough to see every tile # in general the coordinate system is z, y, x: depth, length, width. No height because it's ambiguous. screen_width, screen_length, display_min_y, display_max_y, display_min_x, display_max_x, \ min_y_offset, max_y_offset, min_x_offset, max_x_offset, x_scroll_leniency, y_scroll_leniency = (0,) * 12 """ Adjusts the bounds defined above, to be called when opening and resizing """ def reset_bounds(): # nonlocal allows modification of outer function's variables nonlocal screen_width, screen_length, display_min_y, display_max_y, display_min_x, display_max_x, \ min_y_offset, max_y_offset, min_x_offset, max_x_offset, y_scroll_leniency, x_scroll_leniency screen_length = terminal.state(terminal.TK_HEIGHT) * TILE_LENGTH screen_width = terminal.state(terminal.TK_WIDTH) * TILE_WIDTH y_scroll_leniency = int(screen_length * SCROLL_LENIENCY) x_scroll_leniency = int(screen_length * SCROLL_LENIENCY) display_min_y = 0 + MARGIN_TOP * TILE_LENGTH display_max_y = screen_length - MARGIN_BOTTOM * TILE_LENGTH display_min_x = 0 + MARGIN_LEFT * TILE_WIDTH display_max_x = screen_width - MARGIN_RIGHT * TILE_WIDTH # TODO convert offsets into actual tile offsets, exclude the complex GUI stuff min_y_offset = min(0, -y_scroll_leniency) max_y_offset = max( 0, -screen_length + MAP_WIDTH * TILE_LENGTH + y_scroll_leniency) min_x_offset = min(0, -x_scroll_leniency) max_x_offset = max( 0, -screen_width + MAP_WIDTH * TILE_WIDTH + x_scroll_leniency) def get_highest_object_if_exists(start_z: int, tile_y: int, tile_x: int, include_tiles: bool = True, include_units: bool = False) -> \ Union[None, Tile, Unit]: if tile_y not in range(0, MAP_WIDTH) or tile_x not in range( 0, MAP_LENGTH): return None for zi in range(start_z, -1, -1): if include_units and unit_map[zi][tile_y][tile_x] is not None: return unit_map[zi][tile_y][tile_x] elif include_tiles and tile_map[zi][tile_y][tile_x] != EMPTY_TILE: return tile_map[zi][tile_y][tile_x] return None reset_bounds() y_offset, x_offset = max(display_min_y, 0), max(0, display_min_x) camera_height = 0 proceed = True while proceed: # t = partial-tile offset in pixels # i = full-tile offset in tiles # c = number of tiles to render ty = y_offset % TILE_LENGTH tx = x_offset % TILE_WIDTH iy = y_offset // TILE_LENGTH ix = x_offset // TILE_WIDTH # vc = screen_length // TILE_SIZE + 1 # hc = screen_width // TILE_SIZE + 1 mouse_x = terminal.state( terminal.TK_MOUSE_X) - x_offset - display_min_x // TILE_WIDTH mouse_y = terminal.state( terminal.TK_MOUSE_Y) - y_offset - display_min_y // TILE_LENGTH x_offset = clamp(x_offset + x_speed, min_x_offset, max_x_offset) y_offset = clamp(y_offset + y_speed, min_y_offset, max_y_offset) terminal.clear() mouse_over_tile = get_highest_object_if_exists(camera_height, mouse_y, mouse_x) mouse_over_tile = mouse_over_tile.blueprint.name if mouse_over_tile is not None else "Empty" mouse_over_unit = get_highest_object_if_exists(camera_height, mouse_y, mouse_x, include_units=True, include_tiles=False) mouse_over_unit = mouse_over_unit.blueprint.name if mouse_over_unit else "Empty" terminal.print(2, 0, "speed: {}, {}".format(x_speed, y_speed)) terminal.print( 2, 1, "offset: {}, {}, height : {}".format(ix, iy, camera_height)) terminal.print( 2, 2, "tile at ({}, {}): {}".format(mouse_x, mouse_y, mouse_over_tile)) terminal.print(2, 3, "unit: {}".format(mouse_over_unit)) higher_tile_already_rendered: [[bool] ] = [[False for _ in range(MAP_WIDTH)] for _ in range(MAP_LENGTH)] # print scrollable map for z in range(camera_height, -1, -1): # top has higher render priority for y in range(0, MAP_LENGTH): for x in range(0, MAP_WIDTH): # s = final coords in pixels sx = (x + ix) * TILE_WIDTH + tx + display_min_x sy = (y + iy) * TILE_LENGTH + ty + display_min_y # render only on-screen tiles if (display_min_y <= sy <= display_max_y and display_min_x <= sx <= display_max_x and not higher_tile_already_rendered[y][x] and (tile_map[z][y][x] != EMPTY_TILE or unit_map[z][y][x] is not None)): if unit_map[z][y][x] is not None: terminal.put_ext(0, 0, sx, sy, unit_map[z][y][x].blueprint.icon) higher_tile_already_rendered[y][x] = True # TODO why is it printing two chars? else: if z < camera_height and tile_map[z][y][ x] != EMPTY_TILE: terminal.put_ext( 0, 0, sx, sy, 0x2588, (terminal.color_from_name('yellow'), terminal.color_from_name('red')) * 4) terminal.put_ext(0, 0, sx, sy, tile_map[z][y][x].blueprint.icon) higher_tile_already_rendered[y][x] = True terminal.refresh() while proceed and terminal.has_input(): key = terminal.read() if key == terminal.TK_CLOSE or key == terminal.TK_ESCAPE: proceed = False elif key == terminal.TK_RESIZED: reset_bounds() elif key == terminal.TK_KP_PLUS: camera_height = clamp(camera_height + 1, 0, MAP_DEPTH - 1) elif key == terminal.TK_KP_MINUS: camera_height = clamp(camera_height - 1, 0, MAP_DEPTH - 1) if terminal.state(terminal.TK_LEFT): if x_speed < SPEED_CAP: x_speed += SPEED_ACCELERATION else: x_speed = SPEED_CAP elif terminal.state(terminal.TK_RIGHT): if x_speed > -SPEED_CAP: x_speed -= SPEED_ACCELERATION else: x_speed = -SPEED_CAP else: x_speed -= sgn(x_speed) if terminal.state(terminal.TK_UP): if y_speed < SPEED_CAP: y_speed += SPEED_ACCELERATION else: y_speed = SPEED_CAP elif terminal.state(terminal.TK_DOWN): if y_speed > -SPEED_CAP: y_speed -= SPEED_ACCELERATION else: y_speed = -SPEED_CAP else: y_speed -= sgn(y_speed) current_time = time.perf_counter() # If twice as slow as desirable warn us, check once every 10 seconds if iterations % ( 10 * FPS ) == 0 and iterations > 0 and current_time - prev_frame_time > 2 / FPS: print( "Lag detected. Desired frame_time: {}; actual frame_time: {}". format(1 / FPS, current_time - prev_frame_time)) prev_frame_time = current_time iterations += 1 terminal.delay(1000 // FPS) terminal.close()
def put_ext(self, *args): if isinstance(args[0], Point): return _terminal.put_ext(args[0].x, args[0].y, args[1].x, args[1].y, *args[2:]) else: return _terminal.put_ext(*args)
def clear_entity(entity): # erase the character that represents this object blt.bkcolor(blt.color_from_name("transparent")) blt.put_ext(entity.x, entity.y, 0, 0, ' ', None)
def test_dynamic_sprites(): blt.set("window.title='Omni: dynamic sprites'") blt.set("U+E000: ../Media/Tiles.png, size=32x32, align=top-left") map_width = len(map_[0]) map_height = len(map_) x0 = y0 = 0 view_height, view_width = 10, 14 minimap_scale = 4 panel_width = (blt.state(blt.TK_WIDTH) - view_width * 4 - 1) * blt.state( blt.TK_CELL_WIDTH) margin = (panel_width - map_width * minimap_scale) // 2 def draw_map(): blt.color("white") for y in range(y0, y0 + view_height): for x in range(x0, x0 + view_width): code = map_[y][x] if code in palette: s = palette[code] blt.put((x - x0) * 4, (y - y0) * 2, 0xE000 + s.tile) def argb_from_color(col): return (col & 0xFF000000) >> 24, (col & 0xFF0000) >> 16, ( col & 0xFF00) >> 8, col & 0xFF def blend_colors(one, two): a1, r1, g1, b1 = argb_from_color(one) a2, r2, g2, b2 = argb_from_color(two) f = a2 / 255 r = int(r1 * (1 - f) + r2 * f) g = int(g1 * (1 - f) + g2 * f) b = int(b1 * (1 - f) + b2 * f) return blt.color_from_argb(a1, r, g, b) def make_minimap(): minimap = [ palette[code].color if code in palette else 0xFF000000 for row in map_ for code in row ] for y in range(y0, y0 + view_height): for x in range(x0, x0 + view_width): minimap[y * map_width + x] = blend_colors( minimap[y * map_width + x], 0x60FFFFFF) minimap = (c_uint32 * len(minimap))(*minimap) blt.set( "U+E100: %d, raw-size=%dx%d, resize=%dx%d, resize-filter=nearest" % (addressof(minimap), map_width, map_height, map_width * 4, map_height * 4)) while True: blt.clear() draw_map() blt.color("light gray") for x in range(80): blt.put(x, view_height * 2, 0x2580) for y in range(view_height * 2): blt.put(view_width * 4, y, 0x2588) make_minimap() blt.color("white") blt.put_ext(view_width * 4 + 1, 0, margin, margin, 0xE100) blt.puts( 1, view_height * 2 + 1, "[color=orange]Tip:[/color] use arrow keys to move viewport over the map" ) blt.refresh() key = blt.read() if key in (blt.TK_CLOSE, blt.TK_ESCAPE): break elif key == blt.TK_RIGHT and x0 < map_width - view_width: x0 += 1 elif key == blt.TK_LEFT and x0 > 0: x0 -= 1 elif key == blt.TK_DOWN and y0 < map_height - view_height: y0 += 1 elif key == blt.TK_UP and y0 > 0: y0 -= 1 blt.set("U+E000: none; U+E100: none;")