def process(self): tcod.sys_wait_for_event(mask=tcod.EVENT_ANY, k=self.key, m=self.mouse, flush=False) if self.key.vk == tcod.KEY_ESCAPE: self.scene.action = {'exit': True} else: self.scene.action = {}
def get_input(self): tcod.sys_wait_for_event(tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse, False) if key.vk and key.vk not in (tcod.KEY_TEXT, tcod.KEY_CHAR): return Input(InputType.KEY, key.vk, key) if key.vk and key.vk == tcod.KEY_TEXT: return Input(InputType.CHAR, key.text, key) if key.vk and key.vk == tcod.KEY_CHAR and (key.lctrl or key.rctrl): return Input(InputType.CHAR, chr(key.c), key) if mouse: return Input(InputType.MOUSE, mouse, key) return None
def process(self): tcod.sys_wait_for_event(mask=tcod.EVENT_ANY, k=self.key, m=self.mouse, flush=False) x, y = self.mouse.cx, self.mouse.cy if self.key.vk == tcod.KEY_ESCAPE: self.scene.action = {'exit': True} if self.mouse.lbutton_pressed: self.scene.action['left_click'] = (x, y) if self.mouse.rbutton_pressed: self.scene.action['right_click'] = (x, y) self.scene.mouse = self.mouse
def wait_for_event(self, mask): event_type = tcod.sys_wait_for_event(mask, self.current_key_event, self.current_mouse_event) self.current_event = events.event_from(event_type, self.current_key_event, self.current_mouse_event) return self.current_event
def process(self): tcod.sys_wait_for_event(mask=tcod.EVENT_ANY, k=self.key, m=self.mouse, flush=False) if tcod.EVENT_KEY_PRESS and self.key.pressed: index = self.key.c - ord('a') if index >= 0: self.scene.action = {'inventory_index': str(index)} elif self.key.vk == tcod.KEY_ENTER and self.key.lalt: self.scene.action = {'fullscreen': True} elif self.key.vk == tcod.KEY_ESCAPE: self.scene.action = {'exit': True} else: self.scene.action = {}
def process(self): tcod.sys_wait_for_event(mask=tcod.EVENT_ANY, k=self.key, m=self.mouse, flush=False) if tcod.EVENT_KEY_PRESS and self.key.pressed: if self.key.c == ord('a'): self.scene.action = {'level_up': 'hp'} elif self.key.c == ord('b'): self.scene.action = {'level_up': 'str'} elif self.key.c == ord('c'): self.scene.action = {'level_up': 'def'} elif self.key.vk == tcod.KEY_ENTER and self.key.lalt: self.scene.action = {'fullscreen': True} else: self.scene.action = {}
def process(self): tcod.sys_wait_for_event(mask=tcod.EVENT_ANY, k=self.key, m=self.mouse, flush=False) if tcod.EVENT_KEY_PRESS and self.key.pressed: if self.key.c == ord('a'): self.scene.action = {'new_game': True} elif self.key.c == ord('b'): self.scene.action = {'load_game': True} elif self.key.vk == tcod.KEY_ENTER and self.key.lalt: self.scene.action = {'fullscreen': True} elif self.key.c == ord('c') or self.key.vk == tcod.KEY_ESCAPE: self.scene.action = {'exit': True} else: self.scene.action = {}
def menu_loop(wait_for=None, cancel_with_escape=True, sort_by: Union[int, str] = 'string'): """ The loop waits for a key input. If wait_for is an integer, it waits for a key that corresponds to an integer in range of (0, wait_for) If wait_for is a list of characters or tcod key codes it waits for a key that corresponds to one of the characters or key codes. :param wait_for: :type wait_for: int or list :return: :rtype: int or str """ key = tcod.Key() while True: tcod.sys_wait_for_event(tcod.EVENT_KEY_PRESS, key, '', False) char = chr(key.c) if key.vk == tcod.KEY_ESCAPE and cancel_with_escape: return None # elif type(wait_for) is dict: # if char.lower() in wait_for.keys(): # return wait_for[char] elif key.vk == tcod.KEY_KPENTER: return None elif isinstance(wait_for, int): # If menu is waiting to receive an index if isinstance(sort_by, str): index = ord(char) - ord('a') if 0 <= index < wait_for: return index elif isinstance(sort_by, int): index = int(key.c - ord('1')) if 0 <= index < wait_for: return index elif isinstance(wait_for, list): # If menu is waiting for a specific key input if char.lower() in wait_for: return char if key.vk in wait_for: return key.vk
def process(self): # tcod.sys_check_for_event( tcod.sys_wait_for_event(mask=tcod.EVENT_ANY, k=self.key, m=self.mouse, flush=False) user_input = Key( vk=self.key.vk, ch=chr(self.key.c), alt=(self.key.lalt or self.key.ralt), ctrl=(self.key.lctrl or self.key.lctrl), meta=(self.key.lmeta or self.key.rmeta), shift=self.key.shift, pressed=self.key.pressed, ) if tcod.EVENT_KEY_PRESS and user_input in self.key_code: self.scene.action = self.key_code[user_input] else: self.scene.action = {} self.scene.mouse = self.mouse
def main(): screen_width = 80 screen_height = 80 libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'Image', fullscreen=False) con = libtcod.console_new(screen_width, screen_height) n = 20 backgr = 0.7 im = Image.open( 'D:\\(un)important\\python\\3year\\project\\other\\test4.png') rgbim = im.convert('RGB') rgbim.thumbnail((n, n), Image.ANTIALIAS) for x in range(rgbim.size[0]): for y in range(rgbim.size[1]): r, g, b = rgbim.getpixel((x, y)) backcolor = libtcod.Color(int(r * backgr), int(g * backgr), int(b * backgr)) libtcod.console_set_char_background(con, x, y, backcolor, libtcod.BKGND_SET) ch = get_char(x, y, rgbim) libtcod.console_set_default_foreground( con, libtcod.Color(int(r), int(g), int(b))) libtcod.console_put_char(con, x, y, ch, libtcod.BKGND_NONE) libtcod.console_blit(con, 0, 0, screen_width, screen_height, 0, 0, 0) libtcod.console_flush() key = libtcod.Key() mouse = libtcod.Mouse() libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True)
def get_action(self, g, key, mouse): # Capture new user input # Deprecated since version 9.3: Use the tcod.event.get function to check for events. # tcod.sys_check_for_event( # mask=tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, # k=key, # m=mouse # ) # Flush False - returns 2 key events # tcod.Key(pressed=True, vk=tcod.KEY_CHAR, c=ord('h')) # tcod.Key(pressed=True, vk=tcod.KEY_TEXT, text='h') # Flush True: returns just this # tcod.Key(pressed=True, vk=tcod.KEY_CHAR, c=ord('h')) # Nothing is waiting in the action queue - collect more actions tcod.sys_wait_for_event( mask=tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, k=key, m=mouse, flush=True ) # Get keyboard/mouse input key_char = input_handling.process_tcod_input(key) action = input_handling.handle_keys(g.state, key_char) mouse_action = input_handling.handle_mouse(g.state, mouse) if mouse_action: # Mouse action will take priority over keys (for now) # log.debug('mouse_action: {}'.format(mouse_action)) action = mouse_action return action
#!/usr/bin/env python3 import tcod WIDTH, HEIGHT = 80, 60 key = tcod.Key() mouse = tcod.Mouse() with tcod.console_init_root(WIDTH, HEIGHT, 'tcod events example', renderer=tcod.RENDERER_SDL) as console: tcod.sys_set_fps(24) while not tcod.console_is_window_closed(): ev = tcod.sys_wait_for_event(tcod.EVENT_ANY, key, mouse, False) if ev & tcod.EVENT_KEY: console.blit(console, 0, 0, 0, 1, WIDTH, HEIGHT - 2) console.print_(0, HEIGHT - 3, repr(key)) print(key) if ev & tcod.EVENT_MOUSE_MOVE: console.rect(0, HEIGHT - 1, WIDTH, 1, True) console.print_(0, HEIGHT - 1, repr(mouse)) print(mouse) elif ev & tcod.EVENT_MOUSE: console.blit(console, 0, 0, 0, 1, WIDTH, HEIGHT - 2) console.print_(0, HEIGHT - 3, repr(mouse)) print(mouse) tcod.console_flush()
# Initialize the root console in a context. with tcod.console_init_root(WIDTH, HEIGHT, 'tcod-test', False) as root_console: MM = MonsterManager(root_console) tcod.sys_set_fps(24) state = 'main' # set back to a main menu when we get there. while not tcod.console_is_window_closed(): tcod.console_clear(root_console) # clear screen between frames. # if state is 'start' blit the opening screen asking the player to start a new game. if(state == 'start'): tcod.console_flush() ev = tcod.sys_wait_for_event(tcod.EVENT_ANY, key, None, True) if ev & tcod.EVENT_KEY: state = 'main' # if state is 'main' blit the map and the player on the screen as well as the noise level. elif(state == 'main'): # figure out what level we are on and use that data to display. try: _level = full_dungeon_stack[current_level] except KeyError: full_dungeon_stack[current_level] = dungeon_level(current_level) _level = full_dungeon_stack[current_level] _map = _level.map _creatures = _level.creatures _objects = _level.objects
def main_loop(root_con, key, mouse, current_view, game_world, player, game_map, entities, close_entities, mlog): render_args = None game_state = GameStates.PLAYER_TURN while not tcod.console_is_window_closed(): tcod.sys_wait_for_event(tcod.EVENT_KEY_PRESS, key, mouse, True) action = handle_keys(key, movement_settings) if game_state == GameStates.PLAYER_TURN: action_move = action.get('move') action_exit = action.get('exit') action_fullscreen = action.get('fullscreen') action_pass = action.get('pass') action_save = action.get('save') if action_save: print("Saving...") return { 'save': (game_world, game_map, player, entities, close_entities, mlog) } player_turn_results = [] if action_move: dx, dy = action_move """ Check if player entered new chunk """ pos_in_chunk_x, pos_in_chunk_y = utils.get_pos_in_chunk( player.x, player.y) if utils.enter_new_chunk(pos_in_chunk_x + dx, pos_in_chunk_y + dy): """ Here is code for changing chunks. If player.x, player.y + direction from action_move goes beyond the chunk area, he is changing chunks. We don't have to calculate in which way he went, because get_chunk_pos_from_player_pos does that automatically. We don't have to calculate on what place in the next chunk he will appear, because in the render_functions file and draw entity function, his position is calculated from world pos (0...WORLD_HEIGHT or _WIDTH) to (0...CHUNK_HEIGHT or _WIDTH). Next, we create two sets - close_entities and all_entities. Then, we exclude close entities from all, and add those that are close, to final entities list. Offloaded entities are those who are far and won't chase the player. We are storing them in chunk.objects list. """ old_chunk_x, old_chunk_y = game_world.get_chunk_pos_from_player_pos( player.x, player.y) player.x += dx player.y += dy chunk_pos_x, chunk_pos_y = game_world.get_chunk_pos_from_player_pos( player.x, player.y) if game_world.chunks[chunk_pos_x][ chunk_pos_y].property == ChunkProperty.END: print("END") # process only these, which are far. close_entities = set([ e for e in entities if e.distance_to(player) < constants.DISTANCE_TO_PROCESS_ENTITY and e != player ]) all_entities = set([e for e in entities if e != player]) to_offload = list(all_entities.difference(close_entities)) game_map.offload_chunk( game_world.chunks[old_chunk_x][old_chunk_y], player, list(to_offload)) entities = game_map.remove_entities(player, entities) entities += list(close_entities) print(chunk_pos_x, chunk_pos_y) print( game_world.chunks[chunk_pos_x][chunk_pos_y].discovered) # print( # f"CLOSE ENTITIES: {len(close_entities)}\nALL ENTITIES: {len(all_entities)}\nENTITIES TO OFFLOAD: {len(to_offload)}") # # Make new map game_map = GameMap( constants.MAP_WIDTH, constants.MAP_HEIGHT, game_world.chunks[chunk_pos_x][chunk_pos_y]) if not game_world.chunks[chunk_pos_x][ chunk_pos_y].discovered: game_map.randomize_sand(chunk_pos_x, chunk_pos_y, game_world) else: # here we should randomize... new_entities = game_map.restore_chunk( chunk_pos_x, chunk_pos_y, entities, player, game_world) entities = new_entities + list(close_entities) ## else: if not game_map.is_blocked(player.x + dx, player.y + dy): target = get_blocking_entities_at_location( entities, player.x + dx, player.y + dy) if target: # do damage etc. attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) game_state = GameStates.ENEMY_TURN for player_turn_result in player_turn_results: received_msg = player_turn_result.get('message') received_dead_entity = player_turn_result.get('dead') if received_msg: msg = Message(received_msg, (255, 255, 255)) mlog.add_msg(msg) if received_dead_entity: received_dead_entity.fighter.die() msg = Message( f"{received_dead_entity.name.capitalize()} is dead.", constants.COLOR_DARK_RED) mlog.add_msg(msg) if action_exit: raise SystemExit() if action_fullscreen: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) if action_pass: game_state = GameStates.ENEMY_TURN current_view.consoles['view_MAP']['args'] = (player, entities, game_map) if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, game_map, entities) for enemy_turn_result in enemy_turn_results: received_message = enemy_turn_result.get('message') received_dead_entity = enemy_turn_result.get('dead') if received_message: msg = Message(received_message, (255, 255, 255)) mlog.add_msg(msg) if received_dead_entity: game_state = GameStates.PLAYER_DEATH # player is dead mlog.add_msg( f"{received_dead_entity.name} is dead.", (255, 255, 255)) entity.fighter.die() if game_state != GameStates.PLAYER_DEATH: game_state = GameStates.PLAYER_TURN if game_state == GameStates.PLAYER_DEATH: death_console = tcod.console.Console(constants.SCREEN_WIDTH, constants.SCREEN_HEIGHT, order="F") action = handle_keys(key, movement_settings) if action.get('exit'): raise SystemExit() current_view = view.View("death_screen", death_console, render_functions.render_death_screen, root_con) current_view.render() tcod.console_flush() tcod.sys_set_fps(60)
def start(debug=False): SETTINGS = SettingsObject("res/settings.json") # Start setting up the screens/panels # Sets the window dimensions window_width = SETTINGS.getSetting("WindowWidth") window_height = SETTINGS.getSetting("WindowHeight") screen_names = SETTINGS.getSetting("Screens") # Initiate the Display display = DisplayObject() # Puts all screen settings into a dictionary for screen_name in screen_names: screen_data = SETTINGS.getSetting(screen_name) display.panelInfo[screen_name] = screen_data # Create the displays: map_console = libtcod.console_new( display.panelInfo["MapScreen"]["ScreenWidth"], display.panelInfo["MapScreen"]["ScreenHeight"]) hud_console = libtcod.console_new( display.panelInfo["HUDScreen"]["ScreenWidth"], display.panelInfo["HUDScreen"]["ScreenHeight"]) quest_console = libtcod.console_new( display.panelInfo["QuestScreen"]["ScreenWidth"], display.panelInfo["QuestScreen"]["ScreenHeight"]) toast_console = libtcod.console_new( display.panelInfo["ToastScreen"]["ScreenWidth"], display.panelInfo["ToastScreen"]["ScreenHeight"]) # Set the font libtcod.console_set_custom_font( SETTINGS.getResource("FontFile"), libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) # Initialize display libtcod.console_init_root(window_width, window_height, 'Roguelike Me', False) # Create the game object: Game = GameObject(SETTINGS, debug) # # MAIN LOOP # key = libtcod.Key() mouse = libtcod.Mouse() while not libtcod.console_is_window_closed(): # Turn key press into an action, otherwise return None action = processKeyPress(key) # Process action if not None if action != None: if action[0] == 'fullscreen': libtcod.console_set_fullscreen( not libtcod.console_is_fullscreen()) elif action[0] == 'quit' and action[1] == True: return True else: # If the action is meant for the game itself instead of the program, # send it forward to the game to update later Game.addActionToBacklog(action) # Process backlog after keypress if the action did something. Game.processBacklog() # Get all draw updates from the Game toDraw = Game.getToDraw(map_console, hud_console, quest_console, toast_console) # Forward all draw updates to the display display.setDrawOrders(toDraw) # Print to Panels display.drawToPanels(True) display.renderPanels(map_console, hud_console, quest_console, toast_console) # Wait for Keypress libtcod.sys_wait_for_event(libtcod.EVENT_KEY_PRESS, key, mouse, True)
def game_loop(game): player = game.player targeting_item = None debug_spawn = None fov_reset = False fov_recompute = True new_turn = True final_turn_results = {} key = tcod.Key() # mouse = tcod.Mouse() game.fov_map = initialize_fov(game) recompute_fov(game, player.x, player.y) render_all(game, game.fov_map, debug=game.debug['reveal_map']) if game.turn == 1 and not game.debug['no_intro']: play_intro(game) game.state = GameState.PLAYER_ACTIVE game.previous_state = game.state # TODO new tcod.event system # action = False # for event in tcod.event.wait(): # if event.type == "QUIT": # exit() # elif event.type == "KEYDOWN": # action = handle_keys(event, game.state) while not tcod.console_is_window_closed( ): # todo deprecated -> replace with new tcod-system if fov_reset: game.fov_map = initialize_fov(game) if fov_recompute or fov_reset: recompute_fov(game, player.x, player.y) fov_recompute = False render_all(game, game.fov_map, debug=game.debug['reveal_map']) if new_turn: game.turn += 1 for ent in game.entities: ent.proc_every_turn(game, start=True) new_turn = False tcod.sys_wait_for_event(tcod.EVENT_KEY_PRESS, key, None, True) # todo deprecated action = handle_keys_legacy(key, game.state) # mouse_action = handle_mouse(mouse) if action: logging.debug( f'Processing {action}, last turn results: {final_turn_results}' ) # Process player input into turn results # # TODO ideally game state should be set in engine.py, not in the lower-level functions player_turn_results = process_player_input( action, game, last_turn_results=final_turn_results) logging.debug( f'Loop starts with turn {game.turn}, player results: {player_turn_results}' ) # The game exits if player turn results returns False # if player_turn_results is False: break # Process turn results # # TODO ideally game state should be set in engine.py, not in the lower-level functions processed_turn_results = process_turn_results( player_turn_results, game, game.fov_map) logging.debug( f'Turn {game.turn}. State: {game.state}. Processed results: {player_turn_results}' ) fov_recompute = processed_turn_results.get('fov_recompute', False) fov_reset = processed_turn_results.get('fov_reset', False) level_change = processed_turn_results.get('level_change') if targeting_item is None: targeting_item = processed_turn_results.get('targeting_item') if debug_spawn is None: debug_spawn = processed_turn_results.get('debug_spawn') # NPCs take turns # if game.npc_active: new_turn = True for ent in game.entities: ent.proc_every_turn(game, start=False) game.state = process_npc_actions( game ) # set game state to either player turn or player dead new_turn = True # Level Change # if level_change is not None and game.player_active: # player_active prevents level_change if player was killed while trying to change the level initialize_level(level_change, game) # Resets variables used for targeting/cursor manipulation # if game.player_active: targeting_item = None debug_spawn = None final_turn_results = { 'targeting_item': targeting_item, 'debug_spawn': debug_spawn } # carry over turn results to next loop run logging.debug( f'Ending loop at turn {game.turn}. State: {game.state}. FOV Reset/Recompute: {fov_reset}/{fov_recompute}' )
def play_game( console, panel, bar_width, message_log, options, viewing_map=False ): color_scheme = get_scheme(options.get("color_scheme"), ColorSchemes) input_scheme = get_scheme(options.get("input_scheme"), InputSchemes) game_map = GameMap(1) start_tile = LEVEL_CONFIGURATIONS.get(1).get("start_tile") if viewing_map: player_tile = (int(game_map.width / 2), int(game_map.height / 2)) else: player_tile = game_map.find_open_tile(tile_type=start_tile) player_char = "@" if not viewing_map else " " player_sight = Sight() player_fighter = Fighter(hp=20, defense=1, attack=1, damage=2) player_slots = Slots() player_container = Container(20) player = Entity( *player_tile, player_char, tcod.white, "player", render_order=RenderOrder.PLAYER, components={ "sight": player_sight, "fighter": player_fighter, "slots": player_slots, "container": player_container, }, ) game_map.entities.append(player) recompute_fov = True fov_map = game_map.generate_fov_map() memory = [ [False for y in range(game_map.height)] for x in range(game_map.width) ] key = tcod.Key() mouse = tcod.Mouse() game_state = GameStates.PLAYER_TURN previous_game_state = game_state previous_max_hp = player.fighter.max_hp key_cursor = (0, 0) menu_selection = 0 inventory_options = None looking = False combining = None throwing = None exit_queued = False while not tcod.console_is_window_closed(): if recompute_fov: player.sight.get_fov(fov_map, memory) render_all( console, panel, bar_width, message_log, game_map, player, fov_map, memory, color_scheme.value, game_state, mouse, menu_selection, key_cursor if game_state is GameStates.TARGETING else None, inventory_options, viewing_map, ) tcod.console_flush() tcod.sys_wait_for_event( tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse, True ) clear_all(console, game_map.entities, player) recompute_fov = False mouse_action = handle_mouse(mouse) action = input_scheme.value.handle_key(key, game_state) left_click = mouse_action.get("left_click") right_click = mouse_action.get("right_click") direction = action.get("direction") inventory = action.get("inventory") index = action.get("index") select = action.get("select") pickup = action.get("pickup") drop = action.get("drop") use = action.get("use") combine = action.get("combine") throw = action.get("throw") look = action.get("look") wait = action.get("wait") restart = action.get("restart") exit_action = action.get("exit") fullscreen = action.get("fullscreen") color_scheme_input = action.get("color_scheme") input_scheme_input = action.get("input_scheme") player_results = {} player_acted = False do_use = False combine_target = None do_target = False if left_click and game_state is GameStates.TARGETING: key_cursor = get_mouse_tile( tcod.console_get_width(console), tcod.console_get_height(console), player.x, player.y, *left_click, ) do_target = True if right_click: if game_state is GameStates.TARGETING: game_state = previous_game_state throwing = None looking = False else: mouse_tile = get_mouse_tile( tcod.console_get_width(console), tcod.console_get_height(console), player.x, player.y, *right_click, ) look_message = get_look_message( *mouse_tile, game_map, fov_map, player ) if look_message: message_log.add_message(look_message) if direction: if game_state is GameStates.PLAYER_TURN: move = action.get("move") # face = action.get('face') dx, dy = direction # moved = False if move: if player.move(dx, dy, game_map, face=False): player_acted = True recompute_fov = True entities_at_tile = game_map.get_entities_at_tile( player.x, player.y ) entities_at_tile.remove(player) if entities_at_tile: entity_str = join_list( [ entity.indefinite_name for entity in entities_at_tile ] ) message_log.add_message( Message( f"You see {entity_str}.", tcod.light_gray, ) ) # moved = True else: blocking_entities = game_map.get_entities_at_tile( player.x + dx, player.y + dy, True ) if blocking_entities: target = blocking_entities[0] attack_results = player.fighter.attack_entity( target.fighter, is_player=True ) player_results.update(attack_results) player_acted = True # moved = True elif ( game_map.get_tile( player.x + dx, player.y + dy, raw=True ) is STAIRS ): dungeon_level = game_map.dungeon_level + 1 configuration = LEVEL_CONFIGURATIONS.get( dungeon_level ) if not configuration: game_state = GameStates.VICTORY else: game_map = GameMap(game_map.dungeon_level + 1) # player.fighter.base_max_hp += 10 player.fighter.hp = player.fighter.max_hp start_tile = configuration.get("start_tile") if start_tile: ( player.x, player.y, ) = game_map.find_open_tile( tile_type=start_tile ) else: ( player.x, player.y, ) = game_map.find_open_tile() game_map.entities.append(player) recompute_fov = True fov_map = game_map.generate_fov_map() memory = [ [False for y in range(game_map.height)] for x in range(game_map.width) ] player_acted = False tcod.console_clear(console) # In the event that the player moves into a wall, do not adjust # facing # if face and (not move or moved): # player.sight.face(atan2(dy, dx)) # player_acted = True # recompute_fov = True elif game_state is GameStates.INVENTORY: dy = direction[1] menu_selection += dy if menu_selection < 0: menu_selection = len(inventory_options) - 1 elif menu_selection >= len(inventory_options): menu_selection = 0 elif game_state is GameStates.TARGETING: # Moves the key_cursor in the given direction key_cursor = move_cursor(key_cursor, *direction) if inventory: menu_selection = 0 inventory_options = construct_inventory_options(player) if game_state is GameStates.INVENTORY: game_state = previous_game_state elif game_state is GameStates.PLAYER_TURN: previous_game_state = game_state game_state = GameStates.INVENTORY # is not None check is required since 0 evaluates to False if index is not None: if game_state is GameStates.INVENTORY: menu_selection = max(0, min(len(inventory_options) - 1, index)) if combining and len(inventory_options): combine_target = player.container.get_item( inventory_options[menu_selection] ) if select: if game_state is GameStates.INVENTORY: if combining and menu_selection < len(inventory_options): combine_target = player.container.get_item( inventory_options[menu_selection] ) else: do_use = True elif game_state is GameStates.TARGETING: do_target = True if pickup and game_state is GameStates.PLAYER_TURN: entities_at_tile = game_map.get_entities_at_tile( player.x, player.y ) for entity in entities_at_tile: if entity.item: player_results.update(player.container.add_item(entity)) player_acted = True break else: message_log.add_message( Message("There is nothing here to pick up.", tcod.yellow) ) if drop and game_state is GameStates.INVENTORY: if menu_selection < len(inventory_options): item = player.container.get_item( inventory_options[menu_selection] ) player.container.items.remove(item) if player.slots.is_equipped(item): player.slots.toggle_equip(item) item.x = player.x item.y = player.y game_map.entities.append(item) message_log.add_message( Message( f"You drop {item.definite_name}.", tcod.light_blue, ) ) player_acted = True if use and game_state is GameStates.INVENTORY: do_use = True if combine and game_state is GameStates.INVENTORY: if menu_selection < len(inventory_options): selected_item = player.container.get_item( inventory_options[menu_selection] ) if not combining: combining = selected_item else: combine_target = selected_item previous_game_state = GameStates.PLAYER_TURN if throw and game_state is GameStates.INVENTORY: if menu_selection < len(inventory_options): throwing = player.container.get_item( inventory_options[menu_selection] ) previous_game_state = GameStates.PLAYER_TURN game_state = GameStates.TARGETING key_cursor = (player.x, player.y) message_log.add_message( Message( "Left-click or navigate to a tile to throw. " "Right-click or escape to cancel.", tcod.light_gray, ) ) if look and game_state is not GameStates.TARGETING: previous_game_state = game_state game_state = GameStates.TARGETING looking = True key_cursor = (player.x, player.y) message_log.add_message( Message( "Select a tile to look at. Escape to cancel.", tcod.light_gray, ) ) if wait and game_state is GameStates.PLAYER_TURN: if viewing_map: game_map = GameMap(game_map.dungeon_level + 1) player.x = int(game_map.width / 2) player.y = int(game_map.height / 2) else: player_acted = True if restart and game_state is GameStates.PLAYER_DEAD: return True if exit_action: if game_state is GameStates.INVENTORY: game_state = previous_game_state combining = None elif game_state is GameStates.TARGETING: game_state = previous_game_state throwing = None looking = False elif exit_queued: return False else: exit_queued = True message_log.add_message( Message( "Press escape again to quit the game.", tcod.light_gray ) ) if fullscreen: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) if color_scheme_input: color_scheme = cycle_scheme( color_scheme, ColorSchemes, color_scheme_input ) options["color_scheme"] = color_scheme.value.name message_log.add_message( Message( "Color Scheme: " + color_scheme.value.name, tcod.light_gray ) ) if input_scheme_input: input_scheme = cycle_scheme( input_scheme, InputSchemes, input_scheme_input ) options["input_scheme"] = input_scheme.value.name message_log.add_message( Message( "Input Scheme: " + input_scheme.value.name, tcod.light_gray ) ) # Process actions with multiple triggers if do_use: if menu_selection < len(inventory_options): use_results = player.container.get_item( inventory_options[menu_selection] ).item.use(player, game_map) player_results.update(use_results) player_acted = True if combine_target: if combining is combine_target: message_log.add_message( Message( "An item cannot be combined with itself.", tcod.yellow ) ) else: result = None if combining.item.combine_function: result = combining.item.use( player, game_map, combining=True, combine_target=combine_target, ) if result: player_results.update(result) player_acted = True else: if combining.item.combine_function: result = combining.item.use( player, game_map, combining=True, combine_target=combining, ) if result: player_results.update(result) player_acted = True else: message_log.add_message( Message( "These items cannot be combined.", tcod.yellow ) ) combining = None game_state = previous_game_state if do_target: if looking: look_message = get_look_message( *key_cursor, game_map, fov_map, player ) if look_message: message_log.add_message(look_message) game_state = previous_game_state looking = False elif ( throwing and (player.x, player.y) != key_cursor and tcod.map_is_in_fov(fov_map, *key_cursor) and game_map.is_tile_open(*key_cursor, check_entities=False) ): if player.slots.is_equipped(throwing): player.slots.toggle_equip(throwing) throw_results = throwing.item.use( player, game_map, throwing=True, target_x=key_cursor[0], target_y=key_cursor[1], ) player_results.update(throw_results) game_state = previous_game_state throwing = None player_acted = True if player_acted: player_results.update(player.update_status_effects()) if player.fighter.max_hp < previous_max_hp: player.fighter.hp = max( 1, player.fighter.hp - (previous_max_hp - player.fighter.max_hp), ) previous_max_hp = player.fighter.max_hp exit_queued = False # Process player turn results attack_message = player_results.get("attack_message") pickup_message = player_results.get("pickup_message") use_message = player_results.get("use_message") effect_message = player_results.get("effect_message") new_messages = [ attack_message, pickup_message, use_message, effect_message, ] recompute_fov = recompute_fov or player_results.get("recompute_fov") update_fov_map = player_results.get("update_fov_map") dead_entities = player_results.get("dead") next_level = player_results.get("next_level") item_obtained = player_results.get("item_obtained") item_moved = player_results.get("item_moved") item_consumed = player_results.get("item_consumed") or item_moved for message in new_messages: if message: message_log.add_message(message) if update_fov_map: fov_map = game_map.generate_fov_map() if dead_entities: for dead_entity in dead_entities: if dead_entity == player: message = player.kill(is_player=True) previous_game_state = GameStates.PLAYER_DEAD game_state = GameStates.PLAYER_DEAD else: message = dead_entity.kill() message_log.add_message(message) if next_level: # Partially copied from code under "direction" game_map = GameMap(game_map.dungeon_level + 1) player.x, player.y = game_map.find_open_tile() game_map.entities.append(player) recompute_fov = True fov_map = game_map.generate_fov_map() memory = [ [False for y in range(game_map.height)] for x in range(game_map.width) ] tcod.console_clear(console) if item_obtained and item_obtained in game_map.entities: game_map.entities.remove(item_obtained) if item_consumed or item_moved: if isinstance(item_consumed, list): for item in item_consumed: player.container.items.remove(item) if player.slots.is_equipped(item): player.slots.toggle_equip(item) else: player.container.items.remove(item_consumed) if player.slots.is_equipped(item_consumed): player.slots.toggle_equip(item_consumed) if item_moved: item_moved.x = player_results.get("item_x") item_moved.y = player_results.get("item_y") if item_moved not in game_map.entities: game_map.entities.append(item_moved) if player_acted: game_state = GameStates.ENEMY_TURN if game_state is GameStates.ENEMY_TURN: enemy_fov_map = game_map.generate_fov_map_with_entities() for entity in game_map.entities: if entity.ai: enemy_results = entity.ai.act( game_map, player, enemy_fov_map, tcod.map_is_in_fov(fov_map, entity.x, entity.y), ) # Process enemy turn results attack_message = enemy_results.get("attack_message") dead_entities = enemy_results.get("dead") if attack_message: message_log.add_message(attack_message) if dead_entities: for dead_entity in dead_entities: if dead_entity == player: message = player.kill(is_player=True) message_log.add_message(message) game_state = GameStates.PLAYER_DEAD break message = dead_entity.kill() message_log.add_message(message) if game_state is GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYER_TURN