def ask_direction(action): #Ask the player in which direction they want to perform an action. render.info('Which direction do you want to ' + action + '?') x = data.player.x y = data.player.y choice_made = False while not libtcod.console_is_window_closed() and x == data.player.x and y == data.player.y : libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: y -= 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: y += 1 elif key.vk == libtcod.KEY_LEFT or key.vk == libtcod.KEY_KP4: x -= 1 elif key.vk == libtcod.KEY_RIGHT or key.vk == libtcod.KEY_KP6: x += 1 elif key.vk == libtcod.KEY_KP7: x -= 1 y -= 1 elif key.vk == libtcod.KEY_KP9: x += 1 y -= 1 elif key.vk == libtcod.KEY_KP1: x -= 1 y += 1 elif key.vk == libtcod.KEY_KP3: x += 1 y += 1 elif key.vk == libtcod.KEY_ESCAPE: render.message('No direction selected') break return (x, y)
def multi_objects_menu(header, options, width): #The player is presented with some options and makes a choice based on graphics choice = 0 new_choice = 0 selection = [] #Calculate total height for header (after auto-wrap) and one line per option header_height = libtcod.console_get_height_rect(render.mapcon, 0, 0, width, SCREEN_HEIGHT, header) height = len(options) + header_height #Create the virtual console to write the menu on window = libtcod.console_new(width, height) while True: #Clear the console ready to draw libtcod.console_clear(window) #Draw the header libtcod.console_set_default_foreground(window, libtcod.white) libtcod.console_print_rect_ex(window, 0, 0, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) #Iterate through and print the options, highlighting the current selection. y = header_height for index, option in enumerate(options): libtcod.console_set_default_foreground(window, libtcod.white) if index == choice: libtcod.console_set_default_foreground(window, MENU_HILIGHT) libtcod.console_print_ex(window, 0, y, libtcod.BKGND_NONE, libtcod.LEFT, '>') if option in selection: libtcod.console_set_default_foreground(window, MENU_SELECTED) libtcod.console_print_ex(window, 1, y, libtcod.BKGND_NONE, libtcod.LEFT, option.name) y += 1 #Blit the window to the root and flush to render everything. libtcod.console_blit(window, 0, 0, width, height, 0, SCREEN_WIDTH/2 - width/2, SCREEN_HEIGHT/2 - height/2) libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if key.vk == libtcod.KEY_ENTER: return selection if key.vk == libtcod.KEY_SPACE: if options[choice] in selection: selection.remove(options[choice]) else: selection.append(options[choice]) if key.vk == libtcod.KEY_ESCAPE: return None #Up and down arrows change selection elif key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: new_choice = choice - 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: new_choice = choice + 1 #Check that we're not selecting outside the boundary if 0 <= new_choice < len(options): choice = new_choice
def save_game(): util.render_map() libtcod.console_print(0, game.MAP_X, game.MAP_Y, 'Do you want to save (and quit) the game? (y/n)') libtcod.console_flush() key = libtcod.Key() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) if chr(key.c) == 'y' or chr(key.c) == 'Y': return True return False
def menu(header, options, width): global key global mouse 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 = libtcod.console_get_height_rect(con, 0, 0, width, SCREEN_HEIGHT, header) if header == '': header_height = 0 height = len(options) + header_height # Create an off-screen console that represents the menu's window window = libtcod.console_new(width, height) # Print the header, with auto-wrap libtcod.console_set_default_foreground(window, libtcod.white) libtcod.console_set_alignment(window, libtcod.LEFT) libtcod.console_set_default_background(window, libtcod.BKGND_NONE) libtcod.console_print_rect(window, 0, 0, width, height, header) # Print all the options y = header_height letter_index = ord('a') for option_text in options: text = '({}) {}'.format(chr(letter_index), option_text) libtcod.console_print(window, 0, y, text) y += 1 letter_index += 1 # Blit the contents of "window" to the root console x = int(round(SCREEN_WIDTH / 2 - width / 2)) y = int(round(SCREEN_HEIGHT / 2 - height / 2)) libtcod.console_blit(window, 0, 0, width, height, 0, x, y, 1.0, 0.7) # Present the root console to the player and wait for a key-press libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, False) if key.vk == libtcod.KEY_ENTER and key.lalt: #(special case) Alt+Enter: toggle fullscreen libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Convert the ASCII code to an index; if it corresponds to an # option, return it index = key.c - ord('a') if index >= 0 and index < len(options): return index return None
def menu(header, options, width, highlighted=[]): """Basic, general-purpose menu. Allows the user to choose from up to 26 text options.""" 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 if header == "": header_height = 0 else: header_height = tcod.console_get_height_rect(0, 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_new(width, height) # print the header, with auto-wrap tcod.console_set_default_foreground(window, tcod.white) tcod.console_print_rect(window, 0, 0, width, height, header) # print all the options y = header_height letter_index = ord("a") for option_text in options: text = "(" + chr(letter_index) + ") " + option_text tcod.console_print(window, 0, y, text) y += 1 letter_index += 1 for index in highlighted: w = len(options[index]) + 4 tcod.console_set_default_background(window, tcod.grey) y = index + header_height tcod.console_rect(window, 0, y, w, 1, False, flag=tcod.BKGND_SET) # blit the contents of "window" to the root console x = SCREEN_WIDTH // 2 - width // 2 y = SCREEN_HEIGHT // 2 - height // 2 tcod.console_blit(window, 0, 0, width, height, 0, x, y, 1.0, 0.7) # present the root console to the player and wait for a key-press tcod.console_flush() tcod.sys_wait_for_event(tcod.EVENT_KEY_PRESS, key, mouse, True) # special case: changing to/from fullscreen if key.vk == tcod.KEY_F11: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) elif key.vk == tcod.KEY_ESCAPE: return "escape" else: # convert the ASCII code to an index; if it corresponds to an option, # return it index = key.c - ord("a") if index >= 0 and index < len(options): return index return None
def interact(self, world): """Handles key input.""" key = libtcod.Key() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) try: func, val = self.key_map[key.vk] if val is None: val = key if func == self.move: func(val, world) else: func(val) except KeyError: pass
def main(): # load background image imgbg = tl.image_load('main_menu_bg.png') # prepare menu # header = tc.parse('{{yellow}}Choose an option{{stop}}.\n') +\ # ' Navigate up/down and press\n' +\ # ' Enter or press index key.' # opts = ['option "%c"'%x for x in 'ABCDEFGHI'] ### sample opts = ['new game', 'continue', 'options'] opts.append('exit') m = Menu(TITLE, opts, anim=True) # main menu event loop while not tl.console_is_window_closed(): if WAIT: # wait for user's choice and return valid choice index, or None tl.sys_wait_for_event(tl.EVENT_KEY_PRESS|tl.EVENT_MOUSE, key, mouse, True) else: tl.sys_check_for_event(tl.EVENT_KEY_PRESS|tl.EVENT_MOUSE, key, mouse) # blit the background image to screen tl.image_blit_2x(imgbg, 0, 0, 0) # show some credits! tl.console_set_default_background(0, tl.black) tl.console_set_default_foreground(0, tl.darker_red) tl.console_print_ex(0, 1, SCREEN_H-2, tl.BKGND_NONE, tl.LEFT, 'by %s (2013)'%GAME_AUTHOR) tl.console_print_ex(0, SCREEN_W-2, SCREEN_H-2, tl.BKGND_NONE, tl.RIGHT, GAME_VERSION) if m.isAnimated: m.update_animation() m.render(False, False, 'center') tl.console_flush() # for obj in objects: # obj.clear() action = m.handle() print action # debug message log to console if action == 'new game': new_game() if action == 'continue': load_game() if action == 'exit': break print 'Thank you for playing%s\nGoodbye!'%GAME_TITLE
def close_door(): game.message.new('Close door in which direction?', game.turns) libtcod.console_flush() dx, dy = 0, 0 key = libtcod.Key() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) dx, dy = key_check(key, dx, dy) if game.current_map.tile[game.char.x + dx][game.char.y + dy]['name'] == 'opened door': game.current_map.set_tile_values('door', game.char.x + dx, game.char.y + dy) game.message.new('You close the door.', game.turns) game.fov_recompute = True game.player_move = True elif game.current_map.tile[game.char.x + dx][game.char.y + dy]['name'] in ['door', 'locked door']: game.message.new('That door is already closed!', game.turns) elif dx != 0 or dy != 0: game.message.new('There is no door in that direction!', game.turns)
def handle_keys(player): global fov_recompute GET_KEY = 'g' INVENTORY_KEY = 'i' """ Handle all keypresses through libtcodpy. Turn based game, so it waits here. """ """ console_wait_for_keypress causes a double-press in this release of libtcod. """ #key = libtcod.console_wait_for_keypress(True) key = libtcod.Key() mouse = libtcod.Mouse() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) """ Exit the game. "Boss key". """ if key.vk == libtcod.KEY_ESCAPE: return "exit" """ Go down a stairway """ if key.vk == libtcod.KEY_ENTER and key.shift: return "down_stairs" if libtcod.console_is_key_pressed(libtcod.KEY_UP): player_move(0, -1, player) fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_DOWN): player_move(0, 1, player) fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_LEFT): player_move(-1, 0, player) fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_RIGHT): player_move(1, 0, player) fov_recompute = True if key.vk == libtcod.KEY_CHAR: if key.c == ord(GET_KEY): player_pickup_item(player) elif key.c == ord(INVENTORY_KEY): header = "Press the key next to an item to use it or any other to cancel.\n" inventory_manager.inventory_menu(header, player.inventory)
def box(header, footer, startx, starty, width, height, contents, default=0, input=True, color=libtcod.green, align=libtcod.LEFT, nokeypress=False, inv=False, step=1, mouse_exit=False, scrollbar=True): box = libtcod.console_new(width, height) if startx == 'center_screenx': startx = (game.SCREEN_WIDTH - (len(max(contents, key=len)) + 16)) / 2 if startx == 'center_mapx': startx = game.PLAYER_STATS_WIDTH + ((game.MAP_WIDTH - (width - 4)) / 2) if starty == 'center_screeny': starty = (game.SCREEN_HEIGHT - (len(contents) + 4)) / 2 if starty == 'center_mapy': starty = ((game.MAP_HEIGHT + 2) - height) / 2 if color is not None: box_gui(box, 0, 0, width, height, color) if header is not None: libtcod.console_set_default_foreground(box, libtcod.black) libtcod.console_set_default_background(box, color) libtcod.console_print_ex(box, width / 2, 0, libtcod.BKGND_SET, libtcod.CENTER, ' ' + header + ' ') libtcod.console_set_default_foreground(box, color) libtcod.console_set_default_background(box, libtcod.black) if footer is not None: libtcod.console_print_ex(box, width / 2, height - 1, libtcod.BKGND_SET, libtcod.CENTER, '[ ' + footer + ' ]') if mouse_exit: libtcod.console_print_ex(box, width - 5, 0, libtcod.BKGND_SET, libtcod.LEFT, '[x]') libtcod.console_set_default_foreground(box, libtcod.white) if input: choice = box_options(box, startx, starty, width - 2, height - 2, contents, default, inv, step, mouse_exit, align, scrollbar) else: for i, line in enumerate(contents): if align == libtcod.LEFT: libtcod.console_print_ex(box, 2, 2 + i, libtcod.BKGND_SET, libtcod.LEFT, line) if align == libtcod.RIGHT: libtcod.console_print_ex(box, width - 2, 2 + i, libtcod.BKGND_SET, libtcod.RIGHT, line) if align == libtcod.CENTER: libtcod.console_print_ex(box, width / 2, 2 + i, libtcod.BKGND_SET, libtcod.CENTER, line) libtcod.console_blit(box, 0, 0, width, height, 0, startx, starty, 1.0, 0.9) libtcod.console_flush() if not nokeypress: libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, libtcod.Key(), libtcod.Mouse(), True) choice = default libtcod.console_delete(box) return choice
def pick_direction(): (w, h) = (20, 2) window = tcod.console_new(w, h) tcod.console_set_default_foreground(window, tcod.white) text = "Pick a direction." tcod.console_print_rect(window, 0, 0, w, h, text) x = SCREEN_WIDTH // 2 - w // 2 y = SCREEN_HEIGHT // 2 - h // 2 tcod.console_blit(window, 0, 0, w, h, 0, x, y, 1.0, 0.7) tcod.console_flush() global key tcod.sys_wait_for_event(tcod.EVENT_KEY_PRESS, key, mouse, True) # special case: changing to/from fullscreen if key.vk == tcod.KEY_F11: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) else: key_pressed = game.get_key(key) if key_pressed in direction_keys: return direction_keys[key_pressed] elif key_pressed == tcod.KEY_ESCAPE or tcod.console_is_window_closed(): return None
def menu(self, header, options, width, back_color=libtcod.black, fore_color=libtcod.white): if self.con is None: self.con = 0 if len(options) > 26: raise ValueError('too many items') con = self.con header_height = libtcod.console_get_height_rect(con, 0,0, width, self.SCREEN_HEIGHT, header) height = len(options) + header_height window = libtcod.console_new(width, height) print 'window id is:', window print libtcod.console_set_default_foreground(window, fore_color) libtcod.console_print_rect(window, 0,0, width,height, header) y = header_height for option_text in zip('abcdefghijklmnopqrstuvwxyz', options): text = '(%s) %s' % option_text libtcod.console_print(window, 0, y, text) y += 1 x = self.SCREEN_WIDTH/2 - width/2 y = self.SCREEN_HEIGHT/2 - height/2 libtcod.console_blit(window, 0,0, width,height, 0, x,y, 1.0, 0.9) key = libtcod.Key() mouse = libtcod.Mouse() libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.KEY_PRESSED, key, mouse, True) libtcod.console_clear(window) libtcod.console_blit(window, 0,0, width,height, 0, x,y, 1.0, 0.9) libtcod.console_delete(window) libtcod.console_flush() index = key.c - ord('a') if index >= 0 and index < len(options): return index return None
def menu(header, options, width): if len(options) > 26: raise ValueError('A 27 option menu? You *must* be joking.') #Calculate the height of the menu header_height = libtcod.console_get_height_rect(con, 0, 0, width, SCREEN_HEIGHT, header) if header == '': header_height = 0 height = len(options) + header_height #Make a new console and print the header window = libtcod.console_new(width, height) libtcod.console_set_default_foreground(window, libtcod.white) libtcod.console_print_rect_ex(window, 0, 0, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) #Print the options y = header_height letter_index = ord('a') for option_text in options: text = chr(letter_index)+' - '+option_text libtcod.console_print_ex(window, 0, y, libtcod.BKGND_NONE, libtcod.LEFT, text) y += 1 letter_index += 1 x = SCREEN_WIDTH/2 - width/2 y = SCREEN_HEIGHT/2 - height/2 libtcod.console_blit(window, 0, 0, width, height, 0, x, y, 1.0, 0.7) libtcod.console_flush() key = libtcod.Key() mouse = libtcod.Mouse() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if key.vk == libtcod.KEY_ENTER and key.lalt: #(special case) Alt+Enter: toggle fullscreen libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) index = key.c - ord('a') if index >= 0 and index < len(options): return index return None
def open_door(x=None, y=None): dx, dy = 0, 0 if x is None: game.message.new('Open door in which direction?', game.turns) libtcod.console_flush() key = libtcod.Key() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) dx, dy = key_check(key, dx, dy) else: dx, dy = x, y if game.current_map.tile[game.char.x + dx][game.char.y + dy]['name'] == 'door': game.current_map.set_tile_values('opened door', game.char.x + dx, game.char.y + dy) game.message.new('You open the door.', game.turns) game.fov_recompute = True game.player_move = True elif game.current_map.tile[game.char.x + dx][game.char.y + dy]['name'] == 'opened door': game.message.new('That door is already opened!', game.turns) elif game.current_map.tile[game.char.x + dx][game.char.y + dy]['name'] == 'locked door': game.message.new('The door is locked!', game.turns) elif dx != 0 or dy != 0: game.message.new('There is no door in that direction!', game.turns)
def input(typ, con, posx, posy, min=0, max=100): command = '' x = 0 done = False key = libtcod.Key() while done is False: libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) if key.vk == libtcod.KEY_BACKSPACE and x > 0: libtcod.console_set_char(con, x + posx - 1, posy, chr(95)) libtcod.console_set_char_foreground(con, x + posx - 1, posy, libtcod.white) libtcod.console_set_char(con, x + posx, posy, ' ') command = command[:-1] x -= 1 elif key.vk == libtcod.KEY_ENTER: if not len(command) in range(min, max): libtcod.console_set_default_foreground(0, libtcod.dark_red) libtcod.console_print(con, 2, posy + 2, 'Player name must be between ' + str(min) + ' to ' + str(max - 1) + ' characters!') elif typ == 'chargen': if command.lower() in game.savefiles: libtcod.console_set_default_foreground(0, libtcod.dark_red) libtcod.console_rect(con, 2, posy + 2, 50, 1, True) libtcod.console_print(con, 2, posy + 2, 'That name already exist!') else: done = True else: done = True elif key.c in range(32, 127) and len(command) < 20: libtcod.console_set_char(con, x + posx, posy, chr(key.c)) # print new character at appropriate position on screen libtcod.console_set_char_foreground(con, x + posx, posy, libtcod.light_red) libtcod.console_set_char(con, x + posx + 1, posy, chr(95)) libtcod.console_set_char_foreground(con, x + posx + 1, posy, libtcod.white) command += chr(key.c) # add to the string x += 1 libtcod.console_blit(con, 0, 0, game.SCREEN_WIDTH, game.SCREEN_HEIGHT, 0, 0, 0) libtcod.console_flush() return command
def menu(self, header, options, width): """ Display a menu on the screen. header - title of the menu options - menu options width - width of the screen that appears """ if len(options) > 10: raise ValueError("Error: Menu too long. >10") header_height = libtcod.console_get_height_rect(self.console, 0, 0, width, self.screen_height, header) height = len(options) + header_height window = libtcod.console_new(width, height) libtcod.console_set_default_foreground(window, libtcod.white) libtcod.console_print_rect_ex(window, 0, 0, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) y = header_height letter_index = ord('a') for option_text in options: text = '(' + chr(letter_index) + ') ' + option_text libtcod.console_print_ex(window, 0, y, libtcod.BKGND_NONE, libtcod.LEFT, text) y += 1 letter_index += 1 x = self.screen_width / 2 - width / 2 y = self.screen_height / 2 - height / 2 opaque = 1.0 transluscent = 0.7 libtcod.console_blit(window, 0, 0, width, height, 0, x, y, opaque, transluscent) libtcod.console_flush() key = libtcod.Key() mouse = libtcod.Mouse() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) return key
def run(self): while not libtcod.console_is_window_closed(): self.render() libtcod.console_flush() key = libtcod.Key() mouse = libtcod.Mouse() event = libtcod.sys_wait_for_event(1, key, mouse, True) if key.vk == libtcod.KEY_ENTER and key.lalt: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) else: action = self.screens[-1].handle_keys(key.vk) if action == 'exit': return action
def ask_direction(action): #Ask the player in which direction they want to perform an action. render.info('Which direction do you want to ' + action + '?') x = data.player.x y = data.player.y choice_made = False while not libtcod.console_is_window_closed( ) and x == data.player.x and y == data.player.y: libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: y -= 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: y += 1 elif key.vk == libtcod.KEY_LEFT or key.vk == libtcod.KEY_KP4: x -= 1 elif key.vk == libtcod.KEY_RIGHT or key.vk == libtcod.KEY_KP6: x += 1 elif key.vk == libtcod.KEY_KP7: x -= 1 y -= 1 elif key.vk == libtcod.KEY_KP9: x += 1 y -= 1 elif key.vk == libtcod.KEY_KP1: x -= 1 y += 1 elif key.vk == libtcod.KEY_KP3: x += 1 y += 1 elif key.vk == libtcod.KEY_ESCAPE: render.message('No direction selected') break return (x, y)
def main(): the_game = ARL() the_game.initialize() key = libtcod.Key() mouse = libtcod.Mouse() can_quit = False while not libtcod.console_is_window_closed() and not can_quit: the_game.draw() while libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True): if key.vk == libtcod.KEY_ESCAPE: can_quit = True else: the_game.update(key) the_game.update_monsters()
def target_adjacent(relative=False): """ | Target an adjacent tile, | e.g. for using doors | Returns absolute coordinates | or the relative direction, if relative flag is set """ x = 0 y = 0 key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if not key_pressed: return if key.vk == libtcod.KEY_KP4 or key.vk == libtcod.KEY_LEFT: x -= 1 elif key.vk == libtcod.KEY_KP8 or key.vk == libtcod.KEY_UP: y -= 1 elif key.vk == libtcod.KEY_KP6 or key.vk == libtcod.KEY_RIGHT: x += 1 elif key.vk == libtcod.KEY_KP2 or key.vk == libtcod.KEY_DOWN: y += 1 elif key.vk == libtcod.KEY_KP7: x -= 1 y -= 1 elif key.vk == libtcod.KEY_KP9: x += 1 y -= 1 elif key.vk == libtcod.KEY_KP3: x += 1 y += 1 elif key.vk == libtcod.KEY_KP1: x -= 1 y += 1 elif key.vk == libtcod.KEY_KP5: pass if relative: return (x, y) else: return (gvar.game.player.x + x, gvar.game.player.y + y)
def target_adjacent(relative=False): """ | Target an adjacent tile, | e.g. for using doors | Returns absolute coordinates | or the relative direction, if relative flag is set """ x = 0 y = 0 key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS,key,mouse,True) if not key_pressed: return if key.vk == libtcod.KEY_KP4 or key.vk == libtcod.KEY_LEFT: x -= 1 elif key.vk == libtcod.KEY_KP8 or key.vk == libtcod.KEY_UP: y -= 1 elif key.vk == libtcod.KEY_KP6 or key.vk == libtcod.KEY_RIGHT: x += 1 elif key.vk == libtcod.KEY_KP2 or key.vk == libtcod.KEY_DOWN: y += 1 elif key.vk == libtcod.KEY_KP7: x -= 1 y -= 1 elif key.vk == libtcod.KEY_KP9: x += 1 y -= 1 elif key.vk == libtcod.KEY_KP3: x += 1 y += 1 elif key.vk == libtcod.KEY_KP1: x -= 1 y += 1 elif key.vk == libtcod.KEY_KP5: pass if relative: return (x, y) else: return (gvar.game.player.x + x, gvar.game.player.y + y)
def handle_keys(self): """Gets and interprets a keypress. Possible return values: True: player took turn, proceed as normal False: player didn't take turn 'exit': exit game """ libtcod.console_flush() libtcod.sys_check_for_event( libtcod.EVENT_MOUSE | libtcod.EVENT_KEY_PRESS, g.key_event_structure, g.mouse_event_structure ) if g.key_event_structure.vk == libtcod.KEY_ENTER \ and g.key_event_structure.lalt: # Alt+Enter: toggle fullscreen libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) elif g.key_event_structure.vk == libtcod.KEY_ESCAPE: return 'exit' # exit game def switch_key(keys): return g.key_event_structure.vk in keys if g.game_state is not 'dead': # movement keys up = [libtcod.KEY_UP, libtcod.KEY_KP8] upleft = [libtcod.KEY_KP7] left = [libtcod.KEY_LEFT, libtcod.KEY_KP4] downleft = [libtcod.KEY_KP1] down = [libtcod.KEY_DOWN, libtcod.KEY_KP2] downright = [libtcod.KEY_KP3] right = [libtcod.KEY_RIGHT, libtcod.KEY_KP6] upright = [libtcod.KEY_KP9] # other keys pickup_key = ['g', ','] inventory_key = ['I'] spellbook_key = ['B'] skill_key = ['a'] drop_key = ['d'] char_screen_key = ['c'] movement_keys = up + upleft + left + downleft + \ down + downright + right + upright if switch_key(movement_keys): # player tries to move if self.held: print "You're held in place; you can't move." # trying to move shouldn't take a turn if it fails return False if switch_key(up): return self.move_or_attack( 0, -1) elif switch_key(upleft): return self.move_or_attack(-1, -1) elif switch_key(left): return self.move_or_attack(-1, 0) elif switch_key(downleft): return self.move_or_attack(-1, 1) elif switch_key(down): return self.move_or_attack( 0, 1) elif switch_key(downright): return self.move_or_attack( 1, 1) elif switch_key(right): return self.move_or_attack( 1, 0) elif switch_key(upright): return self.move_or_attack( 1, -1) else: # test for other keys key_char = chr(g.key_event_structure.c) if key_char in pickup_key: # pick up an item for item in g.items: # look for an item in the player's tile if item.x == self.x and item.y == self.y: item.pick_up(self) break if key_char in inventory_key: # show the inventory; if an item is selected, use it chosen_item = self.inventory.choice_menu(key_char) if chosen_item is not None: if chosen_item.use(): return True if key_char in spellbook_key: # show the list of spells. If a spell is selected, use it. chosen_spell = self.caster.spellbook.choice_menu() if chosen_spell is not None: if (self.caster.mp - chosen_spell.mp_cost) < 0: display.message( "You don't have enough MP to cast that spell.", libtcod.pink) else: if self.caster.cast_spell(chosen_spell): return True if key_char in skill_key: chosen_skill = self.skills.choice_menu() if chosen_skill is not None: if chosen_skill.use(): return True if key_char in drop_key: # show the inventory; if an item is selected, drop it chosen_item = self.inventory.choice_menu(key_char) if chosen_item is not None: chosen_item.drop() if key_char in char_screen_key: # show the character screen display.char_info_window(self) # wait for keypress libtcod.sys_wait_for_event(libtcod.KEY_PRESSED, g.key_event_structure, g.mouse_event_structure, True) return False
def menu(header, options, width, color=None, text_color=libtcod.white, alpha=1, center=False, additional_line=0, option_descriptions=None, flush=True, hidden=False, xOffset=0, yOffset=0): """ | Render a Full-Screen menu, overwriting the console. | @TODO Add multi-page support """ if len(options) > 26: raise ValueError('Cannot have a menu with more than 26 options.') header_height = libtcod.console_get_height_rect(gvar.con, 0, 0, width, gvar.SCREEN_HEIGHT, header)+1 height = gvar.SCREEN_HEIGHT if flush == True: gvar.window = libtcod.console_new(gvar.SCREEN_WIDTH, gvar.SCREEN_HEIGHT) if not hidden: #print the background libtcod.console_set_default_foreground(gvar.window, text_color) if color is not None: libtcod.console_set_default_background(gvar.window, color) libtcod.console_rect(gvar.window, 1, 1, gvar.SCREEN_WIDTH-2, height-2, False, libtcod.BKGND_SET) #print the header with separating line if header != '': libtcod.console_print_rect_ex(gvar.window, 2, 2, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) libtcod.console_hline(gvar.window,1,header_height+1,gvar.SCREEN_WIDTH-2,libtcod.BKGND_NONE) #print options y = header_height+2 letter_index = ord('a') for option_text in options: index = options.index(option_text) if index == additional_line and additional_line != 0: libtcod.console_hline(gvar.window,1,y,gvar.SCREEN_WIDTH-2,libtcod.BKGND_NONE) y+= 1 text = chr(letter_index).upper() + ' - ' + option_text libtcod.console_print_ex(gvar.window, 2, y, libtcod.BKGND_NONE, libtcod.LEFT, text) if option_descriptions is not None: libtcod.console_print_ex(gvar.window, 25, y, libtcod.BKGND_NONE, libtcod.LEFT, option_descriptions[index]) y += 1 letter_index += 1 #blit the contents of "window" to the root console if center == True: x = (gvar.SCREEN_WIDTH/2 - width/2)-2 y = (gvar.SCREEN_HEIGHT/2 - height/2)-2 else: x=0 y=0 libtcod.console_blit(gvar.window, 0, 0, width, height, 0, xOffset+x, yOffset+y, 1.0, alpha) #present the root console to the player and wait for a key-press libtcod.console_flush() key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS,key,mouse,True) if not key_pressed: return None if key.vk == libtcod.KEY_F10: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) if key.vk == libtcod.KEY_ESCAPE: return 'exit' #convert the ASCII code to an index; if it corresponds to an option, return it index = key.c - ord('a') if index >= 0 and index < len(options): return index return None
def handle_keys(): """ | The player's main input method | Returns a speed value as an integer """ from mechanics import distribute_exp, player_move_or_attack from render import inventory_menu, stat_menu, menu, admin_menu from nightcaste import next_level from utils import sort_inventory speed = 0 key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS,key,mouse,True) if not key_pressed: return # Fullscreen if key.vk == libtcod.KEY_F10: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Exit elif key.vk == libtcod.KEY_ESCAPE: return 'exit' # Movement if gvar.game.game_state == 'playing': if libtcod.console_is_key_pressed(libtcod.KEY_UP) or libtcod.console_is_key_pressed(libtcod.KEY_KP8): speed = player_move_or_attack(0, -1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_DOWN) or libtcod.console_is_key_pressed(libtcod.KEY_KP2): speed = player_move_or_attack(0, 1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_LEFT) or libtcod.console_is_key_pressed(libtcod.KEY_KP4): speed = player_move_or_attack(-1, 0) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_RIGHT) or libtcod.console_is_key_pressed(libtcod.KEY_KP6): speed = player_move_or_attack(1, 0) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP7): speed = player_move_or_attack(-1, -1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP9): speed = player_move_or_attack(1, -1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP3): speed = player_move_or_attack(1, 1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP1): speed = player_move_or_attack(-1, 1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP5): speed = 1 elif libtcod.console_is_key_pressed(libtcod.KEY_F11): admin_menu() else: key_char = chr(key.c) if key_char == 'y': # Pick up an item for object in gvar.game.player.currentmap().objects: if object.x == gvar.game.player.x and object.y == gvar.game.player.y and object.item: object.item.pick_up() break if key_char == 'i': # Show the inventory; if an item is selected, use it sort_inventory() chosen_item = inventory_menu('Inventory\nPress the key next to an item to use it, or any other to cancel.\n') if chosen_item is not None: chosen_item.use() if key_char == 'd': # Show character information chosen_item = inventory_menu('Press the key next to an item to drop it.\n') if chosen_item is not None: chosen_item.drop() if key_char == 'c': # Show character information choice = stat_menu() if choice == 0: distribute_exp() if key_char == 'e': # Use a map tile (doors, stairs, etc.) x, y = target_adjacent() if gvar.game.player.currentmap().map[x][y].use_function is not None: gvar.game.player.currentmap().map[x][y].use_function(x, y) for object in gvar.game.player.currentmap().objects: if object.x == x and object.y == y: object.use() if key_char == 's': # Ranged Attack speed = gvar.game.player.fighter.ranged_attack() if key_char == ' ': # Jump direction = target_adjacent(True) speed = gvar.game.player.jump(direction) gvar.fov_recompute = True if speed == 'cancelled': return 'didnt-take-turn' else: return speed
testconsole = libtcod.console_new(80,50) libtcod.console_map_ascii_code_to_font(157,4,5) # Deciduous libtcod.console_map_ascii_code_to_font(156,1,5) # Shrubland libtcod.console_map_ascii_code_to_font(154,2,5) # Cacti libtcod.console_map_ascii_code_to_font(153,3,5) # Heathland libtcod.console_map_ascii_code_to_font(151,0,5) # Broadleaf libtcod.console_map_ascii_code_to_font(150,5,5) # Mixed Forest libtcod.console_map_ascii_code_to_font(149,0,2) # Coniferous libtcod.console_map_ascii_code_to_font(148,6,5) # Evergreen libtcod.console_map_ascii_code_to_font(147,7,5) # Caves libtcod.console_map_ascii_code_to_font(146,8,5) # Tropical Forest key=libtcod.Key() mouse=libtcod.Mouse() while not libtcod.console_is_window_closed(): libtcod.console_clear(None) libtcod.console_print_ex(testconsole,10,40,libtcod.BKGND_NONE,libtcod.LEFT,'@') libtcod.console_print_ex(testconsole,11,40,libtcod.BKGND_NONE,libtcod.LEFT,chr(146)) libtcod.console_put_char(testconsole,12,40,147) libtcod.console_put_char(testconsole,13,40,148) libtcod.console_put_char(testconsole,14,40,149) libtcod.console_put_char(testconsole,15,40,150) libtcod.console_put_char(testconsole,16,40,151) libtcod.console_put_char(testconsole,17,40,153) libtcod.console_put_char(testconsole,18,40,154) libtcod.console_put_char(testconsole,19,40,156) libtcod.console_print_ex(testconsole,20,40,libtcod.BKGND_NONE,libtcod.LEFT,'C') libtcod.console_blit(testconsole,0,0,80,50,0,0,0) libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS,key,mouse,True)
def main(): """The main program. Initializes data, then runs through the main loop until user quits.""" previous_game_state = 'NONE' game_state = 'INIT' entities = [] tiles = [] for y in range(init.map_height): for x in range(init.map_width): tiles.append({ 'Name': 'wall', 'Position': { 'x': x, 'y': y, 'z': 0 }, 'Char': '#', 'Color': colors.dark_wall, 'Size': 1, 'Opacity': 1, 'Solid': 1, 'Seen': False, 'Health': 100, 'Map': True, 'Defense': 0, 'ZOrder': 0, 'A*Highlight': False }) player = { 'Name': 'player', 'Player': True, 'Color': colors.white, 'Char': '@', 'Movement': { 'x': 0, 'y': 0, 'z': 0 }, 'Position': { 'x': 0, 'y': 0, 'z': 1 }, 'Opacity': 1, 'Compressability': 0, 'Size': 0.85, 'Solid': 1, 'Health': 20, 'MaxHealth': 20, 'Attack': 3, 'Defense': 0, 'Alive': True, 'ZOrder': 2, # above items / bodies 'Inventory': { 'capacity': 20, 'items': [] }, 'Action': '' } monsters = [] number_of_monsters = randint(init.min_monsters, init.max_monsters) for i in range(number_of_monsters): if randint(0, 100) < 50: # add an orc monsters.append({ 'Name': 'orc', 'Color': colors.desaturated_green, 'Char': 'o', 'Movement': { 'x': 0, 'y': 0, 'z': 0 }, 'Position': { 'x': 0, 'y': 0, 'z': 1 }, 'Opacity': 1, 'Size': 0.85, 'Solid': 0.85, 'Health': 6, 'Attack': 1, 'Defense': 0, 'Goal': None, 'Alive': True, 'ZOrder': 2, 'Inventory': { 'capacity': 3, 'items': [] }, 'Action': '' }) else: # Add a troll monsters.append({ 'Name': 'troll', 'Color': colors.darker_green, 'Char': 'T', 'Movement': { 'x': 0, 'y': 0, 'z': 0 }, 'Position': { 'x': 0, 'y': 0, 'z': 1 }, 'Opacity': 1, 'Size': 0.85, 'Solid': 0.85, 'Health': 9, 'Attack': 2, 'Defense': 0, 'Goal': None, 'Alive': True, 'ZOrder': 2, 'Inventory': { 'capacity': 3, 'items': [] }, 'Action': '' }) items = [] number_of_items = randint(init.min_items, init.max_items) for i in range(number_of_items): items.append({ 'Name': 'healing potion', 'Color': colors.violet, 'Char': '!', 'Position': { 'x': 0, 'y': 0, 'z': 0 }, 'Opacity': 1, 'Size': 0.2, 'Solid': 1, 'Healing': 5, 'ZOrder': 1 }) # mutating the tiles into a map, returning the corners of the rooms rooms = game_map.make_map(tiles) # add stuff to rooms, randomly for thing in [player] + monsters + items: place_in_random_room(thing, rooms) # note we are giving initialize_fov tiles, not rooms fov_map = make_fov_map(tiles) # add everything into the entities list for processing entities = [player] + monsters + items + tiles # notifications are the game messages displayed for the player to read notifications = [] keyb = libtcod.Key() mouse = libtcod.Mouse() while True: ###################### Here is the main loop... do the processing ################### # TODO: drop cool-downs until someone is at 0 # take that turn for that entity # if not player's turn, continue looping # if player's turn, get input actions = [] if game_state == 'INIT': actions += processAllEntities(process_tick, player, entities, fov_map, mouse) game_state = 'DEFAULT' if game_state == 'DEFAULT': if not keyb.vk == libtcod.KEY_NONE: # process all entities [tick] actions += processAllEntities(process_tick, player, entities, fov_map, mouse) if mouse.x: # process all entities [mousing] actions += processAllEntities(process_mouse_move, player, entities, fov_map, mouse) if mouse.lbutton_pressed or mouse.rbutton_pressed: # process all entities [clicking] actions += processAllEntities(process_click, player, entities, fov_map, mouse) ############################# The Rendering ################################ # render all entitites in z order entities_in_render_order = sorted(entities, key=lambda x: x['ZOrder']) for entity in entities_in_render_order: process_all_rendering(entity, fov_map) # render everything libtcod.console_blit(init.con, 0, 0, init.screen_width, init.screen_height, 0, 0, 0) # render the UI libtcod.console_set_default_background(init.panel, libtcod.black) libtcod.console_clear(init.panel) # render any notifications or identify imperitives for action in actions: notification = action.get('notification') identify = action.get('identify') pickupables = action.get('pickupables') if notification: # get notifications ready to render (wrapping, scrolling, etc...) add_notification(notifications, notification) if identify: # render the coords render_to_panel(init.panel, 10, 6 - identify['z'], identify['text']) if pickupables: print('pickupables: ', pickupables) # render the game messages, one line at a time y = 1 for notification in notifications: libtcod.console_set_default_foreground(init.panel, notification['color']) libtcod.console_print_ex(init.panel, init.message_x, y, libtcod.BKGND_NONE, libtcod.LEFT, notification['text']) y += 1 # render the health bar render_bar(init.panel, 1, 1, init.bar_width, 'HP', player['Health'], player['MaxHealth'], libtcod.light_red, libtcod.darker_red) # render the coords # render_to_panel(init.panel, 6, 5, 'X: {0} Y: {1}'.format(player['Position']['x'], player['Position']['y'])) libtcod.console_blit(init.panel, 0, 0, init.screen_width, init.panel_height, 0, 0, init.panel_y) # maybe render the inventory? if game_state == 'SHOW_INVENTORY': if player['Action'] == 'USE': render_inventory_menu( 'Press the key next to an item to use it, or Esc to cancel.\n', player['Inventory']['items'], 50) if player['Action'] == 'DROP': render_inventory_menu( 'Press the key next to an item to drop it, or Esc to cancel.\n', player['Inventory']['items'], 50) # flush it all to the screen libtcod.console_flush() ###################### That's it. Now wait for the player's next action ################### # now, get the keyboard input # key = libtcod.console_wait_for_keypress(True) # 0000001 event mask 1 == key down # 0000010 event mask 2 == key up # 0000100 event mask 4 == mouse move # 0001000 event mask 16 == mouse click # 0001101 mouse move & click, key down == 21 evt = libtcod.sys_wait_for_event(21, keyb, mouse, True) # # NOTE: replace above with this to go real-time # libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, keyb, mouse # map keypress to action action = handle_keys(keyb, game_state) move = action.get('move') pickup = action.get('pickup') drop = action.get('drop') exit = action.get('exit') attack = action.get('action') fullscreen = action.get('fullscreen') use = action.get('use') inventory_index = action.get('inventory_index') close_inventory = action.get('close_inventory') player_dead = action.get('player_dead') ################################# handle keyboard input ################################### if 'Movement' in player: if move: # if user wants to move, set the Movement component, then let the processors handle the rest (follow this pattern with any action?) dx, dy = move player['Movement']['x'] = dx player['Movement']['y'] = dy else: player['Movement']['x'] = 0 player['Movement']['y'] = 0 if pickup: player['Action'] = 'PICKUP' if drop: print('player wants to drop something') player['Action'] = 'DROP' previous_game_state = game_state game_state = 'SHOW_INVENTORY' if use: print('player wants to use something') player['Action'] = 'USE' previous_game_state = game_state game_state = 'SHOW_INVENTORY' if player_dead: print('player dead game state') game_state = 'PLAYER_DEAD' if inventory_index is not None and game_state != 'PLAYER_DEAD' and inventory_index < len( player['Inventory']['items']): item = player['Inventory']['items'][inventory_index] if player['Action'] == 'USE': print('going to try to use ', item['Name']) game_state = previous_game_state item['Using'] = True # trigger the use of the item if player['Action'] == 'DROP': print('going to try to drop ', item['Name'], ' contained by ', item['ContainedBy']['Name']) game_state = previous_game_state item['Dropping'] = True # trigger dropping the item if close_inventory: game_state = previous_game_state if exit: print('we hit escape') if game_state == 'SHOW_INVENTORY': # TODO: if we exit the inventory menu without selecting anything # monsters will have an extra turn! game_state = previous_game_state else: return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())
def play_game(self): global wm, player_action, draw_gui, player_move wm = libtcod.console_new(game.WORLDMAP_WIDTH, game.WORLDMAP_HEIGHT) game.worldmap.create_map_legend(wm, 3) libtcod.console_clear(0) util.initialize_fov() player_action = '' while not libtcod.console_is_window_closed(): if draw_gui: util.render_gui(libtcod.Color(70, 80, 90)) util.render_message_panel() util.render_player_stats_panel() draw_gui = False util.render_map() libtcod.console_flush() # player movement if not player.is_disabled() and not ('overburdened' in player.flags and turns % 3 == 0): player_action = commands.keyboard_commands() else: player_move = True if player_action == 'save': IO.save_game() break if player_action == 'quit': death.death_screen(True) break if player_action == 'exit': break # let monsters take their turn if player_move: for obj in reversed(current_map.objects): if game_state != 'death': if obj.item: if obj.item.is_active(): obj.delete() if obj.item.is_expired() or ((turns >= (obj.first_appearance + obj.item.expiration)) and obj.item.expiration > 0): obj.delete() if obj.entity: if not obj.entity.is_disabled(): obj.x, obj.y = obj.entity.take_turn(obj.x, obj.y) if current_map.tile[obj.x][obj.y]['type'] == 'trap' and not obj.entity.is_above_ground() and obj.entity.can_move(obj.x, obj.y): if current_map.tile_is_invisible(obj.x, obj.y): util.trigger_trap(obj.x, obj.y, obj.entity.article.capitalize() + obj.entity.get_name()) elif libtcod.map_is_in_fov(fov_map, obj.x, obj.y): message.new('The ' + obj.entity.get_name() + ' sidestep the ' + current_map.tile[obj.x][obj.y]['name'] + '.', turns) obj.entity.check_condition(obj.x, obj.y) if obj.entity.is_dead(): if libtcod.map_is_in_fov(fov_map, obj.x, obj.y): message.new('The ' + obj.entity.get_name() + ' dies!', turns, libtcod.light_orange) else: message.new('You hear a dying scream.', turns) obj.entity.loot(obj.x, obj.y) obj.delete() if game_state != 'death': monsters.spawn() effects.check_active_effects() util.add_turn() player_move = False # death screen summary if game_state == 'death': key = libtcod.Key() util.render_map() libtcod.console_flush() while not key.vk == libtcod.KEY_SPACE: libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) death.death_screen() player_action = 'exit' break
def wait_for_event(mask=libtcod.EVENT_KEY_PRESS|libtcod.EVENT_MOUSE, flush=False): libtcod.sys_wait_for_event(mask, key, mouse, flush) return (key, mouse)
def target_tile(max_range=None, radius=0): """ | Target a distant tile | For Ranged Attacks, like Archery, Thrown | Also Fireballs or similar projectiles with Radius """ from components import Object from mapcreation import Circle from render import render_all # Spawn a Target Object that can be moved with arrow Keys (x, y) = (gvar.game.player.x, gvar.game.player.y) target = Object(x, y, 'X', color=libtcod.red, name='target', blocks=False) gvar.game.objects.append(target) while True: target.send_to_front() render_all() #Render Splash libtcod.console_clear(gvar.overlay) if radius > 0: target.splash = Circle(target.x, target.y, radius) for point in target.splash.circle: libtcod.console_set_char_background(gvar.overlay, point[0], point[1], libtcod.yellow) libtcod.console_blit(gvar.overlay, 0, 0, gvar.SCREEN_WIDTH, gvar.SCREEN_HEIGHT, 0, 0, 0, 1.0, 0.5) libtcod.console_flush() #Move the Target around key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if not key_pressed: return 'cancelled' if key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: if libtcod.map_is_in_fov(gvar.fov_map, target.x, target.y - 1): target.y -= 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: if libtcod.map_is_in_fov(gvar.fov_map, target.x, target.y + 1): target.y += 1 elif key.vk == libtcod.KEY_LEFT or key.vk == libtcod.KEY_KP4: if libtcod.map_is_in_fov(gvar.fov_map, target.x - 1, target.y): target.x -= 1 elif key.vk == libtcod.KEY_RIGHT or key.vk == libtcod.KEY_KP6: if libtcod.map_is_in_fov(gvar.fov_map, target.x + 1, target.y): target.x += 1 elif key.vk == libtcod.KEY_KP7: if libtcod.map_is_in_fov(gvar.fov_map, target.x - 1, target.y - 1): target.x -= 1 target.y -= 1 elif key.vk == libtcod.KEY_KP9: if libtcod.map_is_in_fov(gvar.fov_map, target.x + 1, target.y - 1): target.x += 1 target.y -= 1 elif key.vk == libtcod.KEY_KP3: if libtcod.map_is_in_fov(gvar.fov_map, target.x + 1, target.y + 1): target.x += 1 target.y += 1 elif key.vk == libtcod.KEY_KP1: if libtcod.map_is_in_fov(gvar.fov_map, target.x - 1, target.y + 1): target.x -= 1 target.y += 1 elif key.vk == libtcod.KEY_ENTER: gvar.game.objects.remove(target) return target break elif key.vk == libtcod.KEY_ESCAPE: gvar.game.objects.remove(target) return 'cancelled' break elif chr(key.c) == 's': # Returns String 'closest' for further evaluation by the calling function, e.g. for targeting the closest mob gvar.game.objects.remove(target) return 'closest' break
def look(): game.message.new('Looking... (Arrow keys to move cursor, ESC to exit)', game.turns) util.render_map() dx = game.char.x - game.curx dy = game.char.y - game.cury key = libtcod.Key() while not libtcod.console_is_window_closed(): libtcod.console_set_default_background(0, libtcod.white) libtcod.console_rect(0, game.MAP_X + dx, dy + 1, 1, 1, False, libtcod.BKGND_SET) libtcod.console_flush() text = "" libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) dx, dy = key_check(key, dx, dy) if key.vk == libtcod.KEY_ESCAPE: del game.message.log[len(game.message.log) - 1] util.render_message_panel() break if dx < 0: dx = 0 if dy < 0: dy = 0 if dx == game.MAP_WIDTH: dx -= 1 if dy == game.MAP_HEIGHT: dy -= 1 px = dx + game.curx py = dy + game.cury # create a list with the names of all objects at the cursor coordinates if dx in range(game.MAP_WIDTH - 1) and dy in range(game.MAP_HEIGHT - 1) and game.current_map.tile_is_explored(px, py): names = [obj for obj in game.current_map.objects if obj.x == px and obj.y == py] prefix = 'you see ' if not libtcod.map_is_in_fov(game.fov_map, px, py): prefix = 'you remember seeing ' for i in range(len(names) - 1, -1, -1): if names[i].entity is not None: names.pop(i) if (px, py) == (game.char.x, game.char.y): text = 'you see yourself' elif names == []: if game.current_map.tile_is_invisible(px, py): text = prefix + 'a floor' else: text = prefix + game.current_map.tile[px][py]['article'] + game.current_map.tile[px][py]['name'] elif len(names) > 1: text = prefix for i in range(len(names)): if i == len(names) - 1: text += ' and ' elif i > 0: text += ', ' if names[i].item is not None: text += names[i].item.get_name(True) if names[i].entity is not None: text += names[i].entity.get_name(True) else: if names[0].item is not None: text = prefix + names[0].item.get_name(True) if names[0].entity is not None: text = prefix + names[0].entity.get_name(True) libtcod.console_set_default_foreground(game.con, libtcod.light_yellow) libtcod.console_rect(game.con, 0, 0, game.MAP_WIDTH, 2, True, libtcod.BKGND_NONE) libtcod.console_print_rect(game.con, 0, 0, game.MAP_WIDTH - 18, game.MAP_HEIGHT, text) libtcod.console_blit(game.con, 0, 0, game.MAP_WIDTH, game.MAP_HEIGHT, 0, game.MAP_X, game.MAP_Y) game.draw_map = True
def attack(): game.message.new('Attack... (Arrow keys to move cursor, TAB to cycle targets, ENTER to attack, ESC to exit)', game.turns) util.render_map() key = libtcod.Key() dx = game.char.x - game.curx dy = game.char.y - game.cury possible_targets = [obj for obj in game.current_map.objects if libtcod.map_is_in_fov(game.fov_map, obj.x, obj.y) and obj.entity] target = None ranged = False pt = 0 while not libtcod.console_is_window_closed(): libtcod.console_set_default_background(0, libtcod.white) libtcod.console_rect(0, game.MAP_X + dx, dy + 1, 1, 1, False, libtcod.BKGND_SET) libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, libtcod.Mouse(), True) dx, dy = key_check(key, dx, dy) if key.vk == libtcod.KEY_ESCAPE: del game.message.log[len(game.message.log) - 1] del game.message.log[len(game.message.log) - 1] util.render_message_panel() break if dx < 0: dx = 0 if dy < 0: dy = 0 if dx == game.MAP_WIDTH: dx -= 1 if dy == game.MAP_HEIGHT: dy -= 1 px = dx + game.curx py = dy + game.cury if key.vk == libtcod.KEY_ENTER: if not game.current_map.tile_is_explored(px, py): game.message.new("You can't fight darkness.", game.turns) else: target = [obj for obj in game.current_map.objects if obj.y == py and obj.x == px and obj.entity] if not target: game.message.new('There is no one here.', game.turns) elif abs(px - game.char.x) > 1 or abs(py - game.char.y) > 1: if (abs(px - game.char.x) == 2 and abs(py - game.char.y) <= 2) or (abs(py - game.char.y) == 2 and abs(px - game.char.x) <= 2) and game.player.skills[game.player.find_weapon_type()].name == 'Polearm': break elif game.player.skills[game.player.find_weapon_type()].name not in ['Bow', 'Missile']: game.message.new('Target is out of range.', game.turns) target = [] else: ranged = True break if key.vk == libtcod.KEY_TAB: if possible_targets: pt += 1 if pt == len(possible_targets): pt = 0 dx = possible_targets[pt].x - game.curx dy = possible_targets[pt].y - game.cury libtcod.console_set_default_foreground(game.con, libtcod.white) libtcod.console_set_default_background(game.con, libtcod.black) libtcod.console_rect(game.con, 0, 0, game.MAP_WIDTH, 1, True, libtcod.BKGND_SET) libtcod.console_blit(game.con, 0, 0, game.MAP_WIDTH, game.MAP_HEIGHT, 0, game.MAP_X, game.MAP_Y) if target: game.player.attack(target[0], ranged)
def handle_keys(): """ | The player's main input method | Returns a speed value as an integer """ from mechanics import distribute_exp, player_move_or_attack from render import inventory_menu, stat_menu, menu, admin_menu from nightcaste import next_level from utils import sort_inventory speed = 0 key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if not key_pressed: return # Fullscreen if key.vk == libtcod.KEY_F10: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Exit elif key.vk == libtcod.KEY_ESCAPE: return 'exit' # Movement if gvar.game.game_state == 'playing': if libtcod.console_is_key_pressed( libtcod.KEY_UP) or libtcod.console_is_key_pressed( libtcod.KEY_KP8): speed = player_move_or_attack(0, -1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed( libtcod.KEY_DOWN) or libtcod.console_is_key_pressed( libtcod.KEY_KP2): speed = player_move_or_attack(0, 1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed( libtcod.KEY_LEFT) or libtcod.console_is_key_pressed( libtcod.KEY_KP4): speed = player_move_or_attack(-1, 0) gvar.fov_recompute = True elif libtcod.console_is_key_pressed( libtcod.KEY_RIGHT) or libtcod.console_is_key_pressed( libtcod.KEY_KP6): speed = player_move_or_attack(1, 0) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP7): speed = player_move_or_attack(-1, -1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP9): speed = player_move_or_attack(1, -1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP3): speed = player_move_or_attack(1, 1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP1): speed = player_move_or_attack(-1, 1) gvar.fov_recompute = True elif libtcod.console_is_key_pressed(libtcod.KEY_KP5): speed = 1 elif libtcod.console_is_key_pressed(libtcod.KEY_F11): admin_menu() else: key_char = chr(key.c) if key_char == 'y': # Pick up an item for object in gvar.game.player.currentmap().objects: if object.x == gvar.game.player.x and object.y == gvar.game.player.y and object.item: object.item.pick_up() break if key_char == 'i': # Show the inventory; if an item is selected, use it sort_inventory() chosen_item = inventory_menu( 'Inventory\nPress the key next to an item to use it, or any other to cancel.\n' ) if chosen_item is not None: chosen_item.use() if key_char == 'd': # Show character information chosen_item = inventory_menu( 'Press the key next to an item to drop it.\n') if chosen_item is not None: chosen_item.drop() if key_char == 'c': # Show character information choice = stat_menu() if choice == 0: distribute_exp() if key_char == 'e': # Use a map tile (doors, stairs, etc.) x, y = target_adjacent() if gvar.game.player.currentmap( ).map[x][y].use_function is not None: gvar.game.player.currentmap().map[x][y].use_function(x, y) for object in gvar.game.player.currentmap().objects: if object.x == x and object.y == y: object.use() if key_char == 's': # Ranged Attack speed = gvar.game.player.fighter.ranged_attack() if key_char == ' ': # Jump direction = target_adjacent(True) speed = gvar.game.player.jump(direction) gvar.fov_recompute = True if speed == 'cancelled': return 'didnt-take-turn' else: return speed
def character_sheet(screen=0): width, height = 62, 21 pick_skill, modify_skill = 0, 0 exit = False key = libtcod.Key() stats = libtcod.console_new(width, height) pool = game.player.skill_points while exit is False: if screen == 0: character_sheet_attributes(stats, width, height) elif screen == 1: pool = character_sheet_skills(stats, width, height, pick_skill, modify_skill, pool) elif screen == 2: character_sheet_equipment(stats, width, height) elif screen == 3: character_sheet_inventory(stats, width, height) modify_skill = 0 libtcod.console_set_default_foreground(stats, libtcod.black) libtcod.console_set_default_background(stats, libtcod.green) libtcod.console_print_ex(stats, width / 2, height - 1, libtcod.BKGND_SET, libtcod.CENTER, ' [ Arrow keys to change page, +/- to change skill pts ] ') libtcod.console_blit(stats, 0, 0, width, height, 0, ((game.MAP_WIDTH - width) / 2) + game.MAP_X, ((game.MAP_HEIGHT - height) / 2) + 1, 1.0, 1.0) libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, game.mouse, True) key_char = chr(key.c) if screen == 1: if key.vk == libtcod.KEY_UP: pick_skill -= 1 if pick_skill < 1: pick_skill = 1 elif key.vk == libtcod.KEY_DOWN: pick_skill += 1 if pick_skill > len(game.player.skills): pick_skill = len(game.player.skills) elif key_char == '+': if pick_skill in range(1, len(game.player.skills)) and pool > 0: modify_skill = 1 elif key_char == '-': if pick_skill in range(1, len(game.player.skills)) and (pool > 0 or (pool == 0 and game.player.skill_points > 0)): modify_skill = -1 if key.vk == libtcod.KEY_LEFT: screen -= 1 if screen < 0: screen = 3 elif key.vk == libtcod.KEY_RIGHT: screen += 1 if screen > 3: screen = 0 elif key.vk == libtcod.KEY_ESCAPE: exit = True for i in range(len(game.player.skills)): if game.player.skills[i].temp > 0: game.player.skill_points -= game.player.skills[i].temp game.player.skills[i].base_level += game.player.skills[i].temp game.player.skills[i].level += game.player.skills[i].temp game.player.skills[i].temp = 0 libtcod.console_delete(stats) game.draw_gui = True
def debounce(): key = libtcod.Key() mouse = libtcod.Mouse() # Can't pass None for mouse even if we are only waiting for a key release. libtcod.sys_wait_for_event(libtcod.EVENT_KEY_RELEASE, key, mouse, True)
def menu(header, options, width, color=None, text_color=libtcod.white, alpha=1, center=False, additional_line=0, option_descriptions=None, flush=True, hidden=False, xOffset=0, yOffset=0): """ | Render a Full-Screen menu, overwriting the console. | @TODO Add multi-page support """ if len(options) > 26: raise ValueError('Cannot have a menu with more than 26 options.') header_height = libtcod.console_get_height_rect( gvar.con, 0, 0, width, gvar.SCREEN_HEIGHT, header) + 1 height = gvar.SCREEN_HEIGHT if flush == True: gvar.window = libtcod.console_new(gvar.SCREEN_WIDTH, gvar.SCREEN_HEIGHT) if not hidden: #print the background libtcod.console_set_default_foreground(gvar.window, text_color) if color is not None: libtcod.console_set_default_background(gvar.window, color) libtcod.console_rect(gvar.window, 1, 1, gvar.SCREEN_WIDTH - 2, height - 2, False, libtcod.BKGND_SET) #print the header with separating line if header != '': libtcod.console_print_rect_ex(gvar.window, 2, 2, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) libtcod.console_hline(gvar.window, 1, header_height + 1, gvar.SCREEN_WIDTH - 2, libtcod.BKGND_NONE) #print options y = header_height + 2 letter_index = ord('a') for option_text in options: index = options.index(option_text) if index == additional_line and additional_line != 0: libtcod.console_hline(gvar.window, 1, y, gvar.SCREEN_WIDTH - 2, libtcod.BKGND_NONE) y += 1 text = chr(letter_index).upper() + ' - ' + option_text libtcod.console_print_ex(gvar.window, 2, y, libtcod.BKGND_NONE, libtcod.LEFT, text) if option_descriptions is not None: libtcod.console_print_ex(gvar.window, 25, y, libtcod.BKGND_NONE, libtcod.LEFT, option_descriptions[index]) y += 1 letter_index += 1 #blit the contents of "window" to the root console if center == True: x = (gvar.SCREEN_WIDTH / 2 - width / 2) - 2 y = (gvar.SCREEN_HEIGHT / 2 - height / 2) - 2 else: x = 0 y = 0 libtcod.console_blit(gvar.window, 0, 0, width, height, 0, xOffset + x, yOffset + y, 1.0, alpha) #present the root console to the player and wait for a key-press libtcod.console_flush() key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if not key_pressed: return None if key.vk == libtcod.KEY_F10: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) if key.vk == libtcod.KEY_ESCAPE: return 'exit' #convert the ASCII code to an index; if it corresponds to an option, return it index = key.c - ord('a') if index >= 0 and index < len(options): return index return None
def multi_objects_menu(header, options, width): #The player is presented with some options and makes a choice based on graphics choice = 0 new_choice = 0 selection = [] #Calculate total height for header (after auto-wrap) and one line per option header_height = libtcod.console_get_height_rect(render.mapcon, 0, 0, width, SCREEN_HEIGHT, header) height = len(options) + header_height #Create the virtual console to write the menu on window = libtcod.console_new(width, height) while True: #Clear the console ready to draw libtcod.console_clear(window) #Draw the header libtcod.console_set_default_foreground(window, libtcod.white) libtcod.console_print_rect_ex(window, 0, 0, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) #Iterate through and print the options, highlighting the current selection. y = header_height for index, option in enumerate(options): libtcod.console_set_default_foreground(window, libtcod.white) if index == choice: libtcod.console_set_default_foreground(window, MENU_HILIGHT) libtcod.console_print_ex(window, 0, y, libtcod.BKGND_NONE, libtcod.LEFT, '>') if option in selection: libtcod.console_set_default_foreground(window, MENU_SELECTED) libtcod.console_print_ex(window, 1, y, libtcod.BKGND_NONE, libtcod.LEFT, option.name) y += 1 #Blit the window to the root and flush to render everything. libtcod.console_blit(window, 0, 0, width, height, 0, SCREEN_WIDTH / 2 - width / 2, SCREEN_HEIGHT / 2 - height / 2) libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if key.vk == libtcod.KEY_ENTER: return selection if key.vk == libtcod.KEY_SPACE: if options[choice] in selection: selection.remove(options[choice]) else: selection.append(options[choice]) if key.vk == libtcod.KEY_ESCAPE: return None #Up and down arrows change selection elif key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: new_choice = choice - 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: new_choice = choice + 1 #Check that we're not selecting outside the boundary if 0 <= new_choice < len(options): choice = new_choice
def wait_for_event(mask=libtcod.EVENT_KEY_PRESS|libtcod.EVENT_MOUSE, flush=False): key, mouse = (libtcod.Key(), libtcod.Mouse()) libtcod.sys_wait_for_event(mask, key, mouse, flush) return (key, mouse)
def handle_input(entity, input_type, delayed_action): """Wait for an input - a keypress or a mouse action, and process it. Arguments: input_type - one of the InputType enum. Ie, the context that the input is processed in. delayed_action - in the case of non-immediate input_type, the action that should be returned to be performed. Returns: A list containing the action to perform and a zero-or-greater number of arguments for that action. TODO: toggles for control keys, eg shift. Need to catch shift, ctrl, alt, etc and modify key input based on this. """ key = libtcod.Key() mouse = libtcod.Mouse() # We currently ignore mouse events. event_type = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) # Do we want to toggle fullscreen? if key.vk == libtcod.KEY_ENTER and key.lalt: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) return [pa.action_none, input_type, delayed_action] if input_type == InputType.IMMEDIATE: if key.vk == libtcod.KEY_ESCAPE: return [pa.action_exit] # exit program # # Movement actions # elif key.vk in (libtcod.KEY_UP, libtcod.KEY_KP8): return [pa.action_move, 0, -1] elif key.vk in (libtcod.KEY_DOWN, libtcod.KEY_KP2): return [pa.action_move, 0, 1] elif key.vk in (libtcod.KEY_LEFT, libtcod.KEY_KP4): return [pa.action_move, -1, 0] elif key.vk in (libtcod.KEY_RIGHT, libtcod.KEY_KP6): return [pa.action_move, 1, 0] elif key.vk == libtcod.KEY_KP7: return [pa.action_move, -1, -1] elif key.vk == libtcod.KEY_KP9: return [pa.action_move, 1, -1] elif key.vk == libtcod.KEY_KP3: return [pa.action_move, 1, 1] elif key.vk == libtcod.KEY_KP1: return [pa.action_move, -1, 1] # # World interaction actions # elif key.c == ord('c') and key.lctrl: return [pa.action_close] elif key.c == ord('o') and key.lctrl: return [pa.action_open] elif key.c == ord('g'): return [pa.action_get] # # Inventory actions # elif key.c == ord('i'): return [pa.action_show_inventory, None] elif key.c == ord('d'): return [pa.action_show_inventory, "drop"] elif key.c == ord('t'): return [pa.action_show_inventory, "throw"] elif key.c == ord('u'): return [pa.action_show_inventory, "use"] elif key.c == ord('c'): return [pa.action_show_inventory, "consume"] elif key.c == ord('w'): return [pa.action_show_inventory, "wear"] elif key.c == ord('e'): return [pa.action_show_inventory, "equip"] elif input_type == InputType.DIRECTIONAL: if key.vk == libtcod.KEY_ESCAPE: return [ pa.action_cancel ] # cancel a multi-stage action we are in the processing of performing elif key.vk in (libtcod.KEY_UP, libtcod.KEY_KP8): return [delayed_action, 0, -1] elif key.vk in (libtcod.KEY_DOWN, libtcod.KEY_KP2): return [delayed_action, 0, 1] elif key.vk in (libtcod.KEY_LEFT, libtcod.KEY_KP4): return [delayed_action, -1, 0] elif key.vk in (libtcod.KEY_RIGHT, libtcod.KEY_KP6): return [delayed_action, 1, 0] elif key.vk == libtcod.KEY_KP7: return [delayed_action, -1, -1] elif key.vk == libtcod.KEY_KP9: return [delayed_action, 1, -1] elif key.vk == libtcod.KEY_KP3: return [delayed_action, 1, 1] elif key.vk == libtcod.KEY_KP1: return [delayed_action, -1, 1] else: return [pa.action_none, input_type, delayed_action] elif input_type == InputType.INVENTORY_SCREEN: return handle_inventory_input(entity, key) # If we get here somehow, return the 'null' action. return [pa.action_none, input_type, None]
def target_tile(max_range=None, radius=0): """ | Target a distant tile | For Ranged Attacks, like Archery, Thrown | Also Fireballs or similar projectiles with Radius """ from components import Object from mapcreation import Circle from render import render_all # Spawn a Target Object that can be moved with arrow Keys (x, y) = (gvar.game.player.x, gvar.game.player.y) target = Object(x, y, 'X', color=libtcod.red, name='target', blocks=False) gvar.game.objects.append(target) while True: target.send_to_front() render_all() #Render Splash libtcod.console_clear(gvar.overlay) if radius > 0: target.splash = Circle(target.x, target.y, radius) for point in target.splash.circle: libtcod.console_set_char_background(gvar.overlay, point[0], point[1], libtcod.yellow) libtcod.console_blit(gvar.overlay, 0, 0, gvar.SCREEN_WIDTH, gvar.SCREEN_HEIGHT, 0, 0, 0, 1.0, 0.5) libtcod.console_flush() #Move the Target around key = libtcod.Key() mouse = libtcod.Mouse() key_pressed = libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS,key,mouse,True) if not key_pressed: return 'cancelled' if key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: if libtcod.map_is_in_fov(gvar.fov_map, target.x, target.y-1): target.y -= 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: if libtcod.map_is_in_fov(gvar.fov_map, target.x, target.y+1): target.y += 1 elif key.vk == libtcod.KEY_LEFT or key.vk == libtcod.KEY_KP4: if libtcod.map_is_in_fov(gvar.fov_map, target.x-1, target.y): target.x -= 1 elif key.vk == libtcod.KEY_RIGHT or key.vk == libtcod.KEY_KP6: if libtcod.map_is_in_fov(gvar.fov_map, target.x+1, target.y): target.x += 1 elif key.vk == libtcod.KEY_KP7: if libtcod.map_is_in_fov(gvar.fov_map, target.x-1, target.y-1): target.x -= 1 target.y -= 1 elif key.vk == libtcod.KEY_KP9: if libtcod.map_is_in_fov(gvar.fov_map, target.x+1, target.y-1): target.x += 1 target.y -= 1 elif key.vk == libtcod.KEY_KP3: if libtcod.map_is_in_fov(gvar.fov_map, target.x+1, target.y+1): target.x += 1 target.y += 1 elif key.vk == libtcod.KEY_KP1: if libtcod.map_is_in_fov(gvar.fov_map, target.x-1, target.y+1): target.x -= 1 target.y += 1 elif key.vk == libtcod.KEY_ENTER: gvar.game.objects.remove(target) return target break elif key.vk == libtcod.KEY_ESCAPE: gvar.game.objects.remove(target) return 'cancelled' break elif chr(key.c) == 's': # Returns String 'closest' for further evaluation by the calling function, e.g. for targeting the closest mob gvar.game.objects.remove(target) return 'closest' break
def menu(header, options, width=30, talk=False): #The player is presented with some options and makes a choice based on graphics choice = 0 new_choice = 0 #Calculate total height for header (after auto-wrap) and one line per option header_height = libtcod.console_get_height_rect(mapcon, 0, 0, width, SCREEN_HEIGHT, header) height = len(options) + header_height if talk: width = 50 x = 0 y = SCREEN_HEIGHT - height else: x = SCREEN_WIDTH / 2 - width / 2 y = SCREEN_HEIGHT / 2 - height / 2 #Create the virtual console to write the menu on window = libtcod.console_new(width, height) while not libtcod.console_is_window_closed(): #Clear the console ready to draw libtcod.console_clear(window) #Draw the header libtcod.console_set_default_foreground(window, libtcod.white) libtcod.console_print_rect_ex(window, 0, 0, width, height, libtcod.BKGND_NONE, libtcod.LEFT, header) #Iterate through and print the options, highlighting the current selection. i = header_height for index, option in enumerate(options): libtcod.console_set_default_foreground(window, libtcod.white) if index == choice: #Draw an arrow and hilight the option. libtcod.console_set_default_foreground(window, MENU_HILIGHT) libtcod.console_print_ex(window, 0, i, libtcod.BKGND_NONE, libtcod.LEFT, '>') libtcod.console_print_ex(window, 1, i, libtcod.BKGND_NONE, libtcod.LEFT, option) i += 1 #Blit the window to the root and flush to render everything. libtcod.console_blit(window, 0, 0, width, height, 0, x, y) libtcod.console_flush() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True) if key.vk == libtcod.KEY_ENTER: return choice if key.vk == libtcod.KEY_ESCAPE: return None #Up and down arrows change selection elif key.vk == libtcod.KEY_UP or key.vk == libtcod.KEY_KP8: new_choice = choice - 1 elif key.vk == libtcod.KEY_DOWN or key.vk == libtcod.KEY_KP2: new_choice = choice + 1 #Check that we're not selecting outside the boundary if 0 <= new_choice < len(options): choice = new_choice
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], mouse, constants['colors'], game_state) fov_recompute = False clear_all(con, entities) libtcod.console_flush() libtcod.sys_wait_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse, True) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') wait = action.get('wait') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') take_stairs = action.get('take_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message('There is nothing here to pick up.', libtcod.yellow)) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if take_stairs and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.stairs and entity.x == player.x and entity.y == player.y: entities = game_map.next_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True libtcod.console_clear(con) break else: message_log.add_message( Message('There are no stairs here.', libtcod.yellow)) if level_up: if level_up == 'hp': player.fighter.base_max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.base_power += 1 elif level_up == 'def': player.fighter.base_defense += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') equip = player_turn_result.get('equip') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') xp = player_turn_result.get('xp') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if equip: equip_results = player.equipment.toggle_equip(equip) for equip_result in equip_results: equipped = equip_result.get('equipped') dequipped = equip_result.get('dequipped') if equipped: message_log.add_message( Message('You equipped the {0}'.format( equipped.name))) if dequipped: message_log.add_message( Message('You dequipped the {0}'.format( dequipped.name))) game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if xp: leveled_up = player.level.add_xp(xp) message_log.add_message( Message('You gain {0} experience points.'.format(xp))) if leveled_up: previous_game_state = game_state game_state = GameStates.LEVEL_UP if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN