def handle_exit_input(player, game_state, previous_game_state, player_turn_results, entities, game_map, message_log): exit_pressed = False if game_state in (get_inventory_states()): 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) exit_pressed = True return game_state, player_turn_results, exit_pressed
def handle_exit_input(player,game_state,previous_game_state,player_turn_results,entities,game_map,message_log): exit_pressed = False if game_state in (GameStates.SHOW_INVENTORY, GameStates.SHOW_WEAPON_INVENTORY, GameStates.SHOW_SCROLL_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) exit_pressed = True return game_state, player_turn_results, exit_pressed
def do_action_exit_current_screen(self): should_quit_game = False if self.game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): self.game_state = self.previous_game_state elif self.game_state == GameStates.TARGETING: self.player_turn_results.append({'targeting_cancelled': True}) else: save_game(self.player, self.entities, self.game_map, self.message_log, self.game_state) should_quit_game = True return should_quit_game
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() if not game_state == GameStates.PLAYER_DEAD: game_state = GameStates.PLAYERS_TURN begin_player_turn = True previous_game_state = game_state targeting_item = None if not game_state == GameStates.PLAYER_DEAD: PLAYERDEADSTATE = False else: PLAYERDEADSTATE = True while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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'], constants['kill_count'], game_state, constants['wall_tile'], constants['floor_tile']) fov_recompute = False libtcod.console_flush() clear_all(con, entities) 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') drop_equipment = action.get('drop_equipment') show_equipment_inventory = action.get('show_equipment_inventory') show_bag = action.get('show_bag') inventory_index = action.get('inventory_index') equipment_inventory_index = action.get('equipment_inventory_index') take_stairs = action.get('take_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') show_help_menu = action.get('show_help_menu') exit = action.get('exit') exit_quit_menu = action.get('exit_quit_menu') fullscreen = action.get('fullscreen') cast_magic_wand = action.get('cast_magic_wand') shoot_bow = action.get('shoot_bow') drop_menu = action.get('drop_menu') sell_menu = action.get('sell_menu') sell_equipment_menu = action.get('sell_equipment_menu') buy_menu = action.get('buy_menu') buy_equipment_menu = action.get('buy_equipment_menu') shop_menu = action.get('shop_menu') shop_menu_index = action.get('shop_menu_index') shop_equipment_menu_index = action.get('shop_equipment_menu_index') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if begin_player_turn and game_state == GameStates.PLAYERS_TURN: begin_player_turn = False if player.fighter.status: player_turn_results.extend(player.fighter.status.update()) 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, constants, entities=entities) #playsound('sounds/attack.m4a', block=False) 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 ( not entity.equippable ) and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break elif entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.equipment_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 show_equipment_inventory: previous_game_state = game_state game_state = GameStates.SHOW_EQUIPMENT_INVENTORY if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if drop_equipment: previous_game_state = game_state game_state = GameStates.DROP_EQUIPMENT if show_bag: previous_game_state = game_state game_state = GameStates.SHOW_BAG if drop_menu: previous_game_state = game_state game_state = GameStates.DROP_MENU 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)) elif game_state == GameStates.SELL_MENU: player_turn_results.extend( player.inventory.sell(item, game_state)) if equipment_inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and equipment_inventory_index < len( player.equipment_inventory.items): equip_item = player.equipment_inventory.items[ equipment_inventory_index] if game_state == GameStates.SHOW_EQUIPMENT_INVENTORY: player_turn_results.extend( player.equipment_inventory.use(equip_item)) elif game_state == GameStates.DROP_EQUIPMENT: player_turn_results.extend( player.equipment_inventory.drop_item(equip_item)) elif game_state == GameStates.SELL_EQUIPMENT_MENU: player_turn_results.extend( player.equipment_inventory.sell(equip_item, game_state)) if shop_menu_index is not None and previous_game_state != GameStates.PLAYER_DEAD: item = game_map.shop_items[shop_menu_index] if game_state == GameStates.BUY_MENU: player_turn_results.extend( player.inventory.buy(item, game_state)) if shop_equipment_menu_index is not None and previous_game_state != GameStates.PLAYER_DEAD: item = game_map.shop_equipment_items[shop_equipment_menu_index] if game_state == GameStates.BUY_EQUIPMENT_MENU: player_turn_results.extend( player.equipment_inventory.buy(item, game_state)) 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 cast_magic_wand and game_state == GameStates.PLAYERS_TURN: wand = player.inventory.search("Magic Wand") staff = player.inventory.search("Wizard Staff") if wand is None and staff is None: message_log.add_message( Message("You cannot cast magic without a magic item!", libtcod.orange)) else: player_turn_results.extend( player.inventory.use(wand, entities=entities, fov_map=fov_map)) game_state = GameStates.ENEMY_TURN if shoot_bow and game_state == GameStates.PLAYERS_TURN: bow = player.inventory.search("Long Bow") arrow = player.inventory.search("Arrow") if bow is None and arrow is None: message_log.add_message( Message( "You don't have anything to shoot with at this time!", libtcod.orange)) elif bow is None and arrow is not None: message_log.add_message( Message("You cannot shoot an arrow without a bow!", libtcod.orange)) elif bow is not None and arrow is None: message_log.add_message( Message("You need arrows to use your bow", libtcod.orange)) else: player_turn_results.extend( player.inventory.use(bow, entities=entities, fov_map=fov_map)) game_state = GameStates.ENEMY_TURN if level_up: if level_up == 'hp': player.fighter.base_max_hp += 20 player.fighter.hp += 20 message_log.add_message( Message("You leveled up your HP!", libtcod.light_cyan)) elif level_up == 'str': player.fighter.base_power += 1 message_log.add_message( Message("You leveled up your ATTACK!", libtcod.light_cyan)) elif level_up == 'def': player.fighter.base_defense += 1 message_log.add_message( Message("You leveled up your DEFENSE!", libtcod.light_cyan)) elif level_up == 'mgk': player.fighter.base_magic += 1 message_log.add_message( Message("You leveled up your MAGIC!", libtcod.light_cyan)) elif level_up == 'mgk_def': player.fighter.base_magic_defense += 1 message_log.add_message( Message("You leveled up your MAGIC RESISTANCE!", libtcod.light_cyan)) game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_help_menu: previous_game_state = game_state game_state = GameStates.HELP_MENU if sell_menu: previous_game_state = game_state game_state = GameStates.SELL_MENU if sell_equipment_menu: previous_game_state = game_state game_state = GameStates.SELL_EQUIPMENT_MENU if buy_menu: previous_game_state = game_state game_state = GameStates.BUY_MENU if buy_equipment_menu: previous_game_state = game_state game_state = GameStates.BUY_EQUIPMENT_MENU if shop_menu: previous_game_state = game_state game_state = GameStates.SHOP_MENU 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.DROP_EQUIPMENT, GameStates.CHARACTER_SCREEN, GameStates.HELP_MENU, GameStates.SHOW_EQUIPMENT_INVENTORY, GameStates.SELL_MENU, GameStates.BUY_MENU, GameStates.SELL_EQUIPMENT_MENU, GameStates.BUY_EQUIPMENT_MENU): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) elif game_state == GameStates.SHOW_BAG: if PLAYERDEADSTATE == True: game_state = GameStates.PLAYER_DEAD else: game_state = GameStates.PLAYERS_TURN elif game_state == GameStates.SHOP_MENU: if PLAYERDEADSTATE == True: game_state = GameStates.PLAYER_DEAD else: game_state = GameStates.PLAYERS_TURN elif game_state == GameStates.PLAYERS_TURN: game_state = GameStates.QUIT_MENU elif game_state == GameStates.DROP_MENU: game_state = GameStates.PLAYERS_TURN else: save_game(player, entities, game_map, message_log, game_state) return True if exit_quit_menu: if game_state == GameStates.QUIT_MENU: game_state = previous_game_state 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') equipment_item_added = player_turn_result.get( 'equipment_item_added') item_consumed = player_turn_result.get('consumed') equipment_consumed = player_turn_result.get('equipment_consumed') item_dropped = player_turn_result.get('item_dropped') loot_dropped = player_turn_result.get('loot_dropped') staff_used = player_turn_result.get('staff_used') 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') item_bought = player_turn_result.get('item_bought') equipment_bought = player_turn_result.get('equipment_bought') end_turn = player_turn_result.get('end_turn') if message: message_log.add_message(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: message_log.add_message( Message( "Your battle prowess grows stronger! You reached level {0}!" .format(player.level.current_level), libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if dead_entity: if dead_entity == player: PLAYERDEADSTATE = True message, game_state = kill_player(dead_entity, constants) message_log.add_message(message) else: monster_name = '' monster_name = dead_entity.name message = kill_monster(dead_entity, player, constants) constants['kill_count'] += 1 message_log.add_message(message) while dead_entity.equipment_inventory.items: item = dead_entity.equipment_inventory.items[0] dead_entity.equipment_inventory.loot_item(item) entities.append(item) message_log.add_message( Message( "The {0} dropped the {1}.".format( monster_name, item.name), libtcod.yellow)) while dead_entity.inventory.items: item = dead_entity.inventory.items[0] dead_entity.inventory.loot_item(item) entities.append(item) message_log.add_message( Message( "The {0} dropped the {1}.".format( monster_name, item.name), libtcod.yellow)) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if equipment_item_added: entities.remove(equipment_item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if item_bought: game_map.shop_items.remove(item_bought) game_state = GameStates.ENEMY_TURN if equipment_bought: game_map.shop_equipment_items.remove(equipment_bought) game_state = GameStates.ENEMY_TURN if equipment_consumed: game_state = GameStates.ENEMY_TURN if staff_used: game_state = GameStates.ENEMY_TURN if end_turn: 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 item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if loot_dropped: entities.append(loot_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 game_state == GameStates.ENEMY_TURN: fov_recompute = True for entity in entities: if entity.ai: if entity.fighter.status: entity.fighter.status.update() enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities, constants) 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: PLAYERDEADSTATE = True message, game_state = kill_player( dead_entity, constants) message_log.add_message(message) else: monster_name = '' monster_name = dead_entity.name message = kill_monster(dead_entity, player, constants) constants['kill_count'] += 1 message_log.add_message(message) while dead_entity.equipment_inventory.items: item = dead_entity.equipment_inventory.items[ 0] dead_entity.equipment_inventory.loot_item( item) entities.append(item) message_log.add_message( Message( "The {0} dropped the {1}.".format( monster_name, item.name), libtcod.yellow)) while dead_entity.inventory.items: item = dead_entity.inventory.items[0] dead_entity.inventory.loot_item(item) entities.append(item) message_log.add_message( Message( "The {0} dropped the {1}.".format( monster_name, item.name), libtcod.yellow)) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN begin_player_turn = True
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): # bool to store whether we update fov or not fov_recompute = True fov_map = initialize_fov(game_map) # key and mouse to capture input key = libtcod.Key() mouse = libtcod.Mouse() mouse_pos = 0 # set game state game_state = GameStates.PLAYERS_TURN previous_game_state = game_state # make sure set to none targeting_item = None #-------GAME LOOP------- while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # This is will update the mouse when it is moved. if mouse.x != mouse_pos: fov_recompute = True mouse_pos = mouse.x #if player doesn't move fov won't update. if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) #update everything 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 libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) #----ACTIONS----- move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') inventory_index = action.get('inventory_index') drop_inventory = action.get('drop_inventory') 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 fov_recompute = True 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 #after player's turn set to enemy turn game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: fov_recompute = True 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: fov_recompute = True previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory: fov_recompute = True 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): fov_recompute = True 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 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): game_state = previous_game_state fov_recompute = True elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_canclled': True}) else: # save when the game is exited save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) ##-----PLAYER TURN RESULTS 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') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') 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) fov_recompute = True 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 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 game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: #if an entity object has an ai, it gets a turn. 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: #after all the enemies move, players turn game_state = GameStates.PLAYERS_TURN
def play_game(player, entities, game_map, message_log, game_state, constants, con, panel): fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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["colours"], game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) 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") inventory_index = action.get("inventory_index") drop_inventory = action.get("drop_inventory") 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.ENEMIES_TURN elif wait: game_state = GameStates.ENEMIES_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 to pick up here!", libtcod.yellow)) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOWING_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.SHOWING_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROPPING_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if drop_inventory: previous_game_state = game_state game_state = GameStates.DROPPING_INVENTORY 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.SHOWING_INVENTORY, GameStates.DROPPING_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("equipped") 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.ENEMIES_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMIES_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.ENEMIES_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 item_consumed: game_state = GameStates.ENEMIES_TURN if xp: leveled_up = player.level.add_xp(xp) message_log.add_message( Message("You gain {0} experience points.".format(xp))) if leveled_up: message_log.add_message( Message( "You leveled up to level {0}".format( player.level.current_level) + "!", libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVELED_UP if game_state == GameStates.ENEMIES_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) if enemy_turn_results: 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
def play_game(con, player, entities, animator: Animator, turn_count: int, game_map: GameMap, message_log, game_state, panel, constants): target_x, target_y = player.x, player.y targeting_item = None target_entity = None while True: fov_algorithm = 2 fov_light_walls = True fov_radius = 20 fov_recompute = True fov_map = initialize_fov(game_map) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, animator, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], game_state, target_x, target_y, target_entity, turn_count) tcod.console_flush() clear_all(con, entities) player_turn_results = [] animator.advance_frame() # Handle Game State if game_state == GameStates.ENEMY_TURN: turn_count += 1 # Generate path map with all static tiles (ignore entities for now) path_map = generate_path_map(game_map, entities=None, player=player) for entity in entities: if entity.ai and entity.ai != Player: recompute_walkable(fov_map, game_map, entities, entity) entity_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities, path_map) for entity_turn_result in entity_turn_results: message = entity_turn_result.get('message') dead_entity = entity_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(player) else: message = kill_entity(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.PLAYER_TURN # Handle Events for event in tcod.event.wait(): if event.type == "QUIT": save_game(player, entities, animator, turn_count, game_map, message_log, game_state) raise SystemExit() if event.type == "KEYDOWN": action: [Action, None] = handle_keys(event.sym, game_state) if action is None: continue action_type: ActionType = action.action_type if action_type == ActionType.EXECUTE: if game_state == GameStates.TARGETING: item_use_results = player.body.use_selected_appendage( entities=entities, fov_map=fov_map, game_map=game_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) game_state = GameStates.ENEMY_TURN elif game_state == GameStates.LOOKING: look_results = [] looked_at_entities = get_entities_at_location( entities, target_x, target_y) if tcod.map_is_in_fov(fov_map, target_x, target_y): if looked_at_entities: for entity in looked_at_entities: look_results.extend( entity.get_description()) target_entity = entity else: if game_map.tiles[target_x][target_y].blocked: look_results.append({ 'message': Message("You stare at the wall.") }) else: look_results.append({ 'message': Message("You stare into empty space.") }) else: look_results.append({ 'message': Message("You can't see that far.") }) game_state = GameStates.PLAYER_TURN player_turn_results.extend(look_results) if action_type == ActionType.MOVEMENT: dx: int = action.kwargs.get("dx", 0) dy: int = action.kwargs.get("dy", 0) # Player Movement if game_state == GameStates.PLAYER_TURN: destination_x = player.x + dx destination_y = player.y + dy tile_results = game_map.tiles[destination_x][ destination_y].overlap_entity(player) player_turn_results.extend(tile_results) if not game_map.is_blocked(destination_x, destination_y): target_appendage = get_blocking_entities_at_location( entities, destination_x, destination_y) if target_appendage: if target_appendage.body: player_fighter = player.body.selected_appendage.fighter if player_fighter: target_entity = target_appendage game_state = GameStates.TARGET_APPENDAGE else: player_turn_results.append({ 'message': Message( "You cannot attack with your {0}." .format( player.body. selected_appendage.name), tcod.yellow) }) elif target_appendage.structure: structure_interact_results = target_appendage.structure.interact( player) player_turn_results.extend( structure_interact_results) else: player.move(dx, dy) else: player_turn_results.append({ 'message': Message("You slam yourself into the wall!", tcod.orange) }) if game_state != GameStates.TARGET_APPENDAGE: game_state = GameStates.ENEMY_TURN # Targeting elif game_state in (GameStates.TARGETING, GameStates.LOOKING): new_x = target_x + dx new_y = target_y + dy if player.distance(new_x, new_y) < targeting_radius: target_x = new_x target_y = new_y elif action_type == ActionType.GRAB: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_result = player.body.grab_entity(entity) player_turn_results.extend(pickup_result) break else: player_turn_results.append({ 'message': Message('You grab at the air', tcod.yellow) }) game_state = GameStates.ENEMY_TURN elif action_type == ActionType.LOOK: game_state = GameStates.LOOKING target_x, target_y = player.x, player.y targeting_radius = 100 elif action_type == ActionType.WAIT: player_turn_results.append({ 'message': Message('You stare blankly into space', tcod.yellow) }) game_state = GameStates.ENEMY_TURN elif action_type == ActionType.CHOOSE_OPTION: option_index = action.kwargs.get("option_index", None) if game_state == GameStates.SWAP_APPENDAGE: if option_index < len(player.body.appendages): item = player.body.appendages[option_index] swap_results = player.body.select_appendage(item) player_turn_results.extend(swap_results) game_state = GameStates.PLAYER_TURN elif game_state == GameStates.TARGET_APPENDAGE: if option_index < len(target_entity.body.appendages): target_appendage = target_entity.body.appendages[ option_index] attack_results = player.body.selected_appendage.fighter.attack_appendage( target_appendage) player_turn_results.extend(attack_results) game_state = GameStates.ENEMY_TURN elif action_type == ActionType.INTERACT: for entity in entities: if entity.structure and entity.x == player.x and entity.y == player.y: interact_results = entity.structure.interact( player) player_turn_results.extend(interact_results) break else: if game_state == GameStates.PLAYER_TURN: activate_item_results = player.body.use_selected_appendage( fov_map=fov_map, game_map=game_map, entities=entities) if activate_item_results: player_turn_results.extend( activate_item_results) game_state = GameStates.ENEMY_TURN elif action_type == ActionType.DROP_INVENTORY_ITEM: grabber = player.body.selected_appendage.grabber if grabber: player_turn_results.extend(grabber.drop()) # game_state = GameStates.DROP_INVENTORY elif action_type == ActionType.SWAP_APPENDAGE: game_state = GameStates.SWAP_APPENDAGE elif action_type == ActionType.ESCAPE: if game_state == GameStates.TARGETING: game_state = GameStates.PLAYER_TURN elif game_state == GameStates.PLAYER_TURN: save_game(player, entities, animator, turn_count, game_map, message_log, game_state) main() elif action_type == ActionType.RESTART: main() # Process player turn results 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') targeting = player_turn_result.get('targeting') next_floor = player_turn_result.get('next_floor') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(player) else: message_log.add_message(kill_entity(dead_entity)) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if targeting: game_state = GameStates.TARGETING targeting_item = targeting targeting_radius = targeting.item.targeting_radius target_x = player.x target_y = player.y message_log.add_message( Message("You begin aiming the {0}.".format( targeting.name))) # TODO: Replace occurrences of add_message with player_turn_result approach # player_turn_results.append({'message': Message("You begin aiming the {0}.".format(targeting.name))}) if next_floor: entities = game_map.next_floor(player, constants) fov_map = initialize_fov(game_map) tcod.console_clear(con)
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): # Intialize FOV map. fov_recompute = True # Recompute FOV after the player moves fov_map = initialize_fov(game_map) target_fov_map = initialize_fov(game_map) fov_map_no_walls = initialize_fov(game_map) # Capture keyboard and mouse input key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state # Store the item that the player used to enter targeting mode (ie lightning scroll). This is so that we know what item we need to remove from inventory etc. targeting_item = None cursor_radius = 1 # For showing object descriptions description_recompute = True description_list = [] description_index = 0 prev_mouse_y = None prev_mouse_x = None # Start music mixer.init() mixer.music.load(os.path.join(definitions.ROOT_DIR, 'data', 'music', 'bgm2.mp3')) #mixer.music.play(loops=-1) #Our main loop while not libtcod.console_is_window_closed(): # Check for input libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) for animator in Animator.animators: animator.update() if Animator.blocking > 0: if not game_state == GameStates.BLOCKING_ANIMATION: previous_game_state = game_state game_state = GameStates.BLOCKING_ANIMATION if Animator.blocking == 0 and game_state == GameStates.BLOCKING_ANIMATION: game_state = previous_game_state # Recompute FOV if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) recompute_fov(fov_map_no_walls, player.x, player.y, constants['fov_radius'], light_walls=False, algorithm=constants['fov_algorithm']) # Show object descriptions if description_recompute == True: for entity in entities: if (prev_mouse_x != mouse.cx) or (prev_mouse_y != mouse.cy): description_list = [] description_index = 0 if entity.x == mouse.cx and entity.y == mouse.cy: description_list.append(entity) prev_mouse_x = mouse.cx prev_mouse_y = mouse.cy if len(description_list) > 0: description_recompute = False # We need to check to see if the mouse position changed and then clear our description list if it did, otherwise it will keep growing if (prev_mouse_x != mouse.cx) or (prev_mouse_y != mouse.cy): description_list = [] description_index = 0 description_recompute = True if mouse.lbutton_pressed: description_index += 1 if description_index > (len(description_list) - 1): description_index = 0 # Draw our scene render_all(con, panel, mouse, 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'], constants['colors'], game_state, description_list, description_index, cursor_radius, target_fov_map, fov_map_no_walls) fov_recompute = False libtcod.console_flush() # Clear our 'drawing consoles' so we dont leave a trail on the main console screen clear_all(con, entities) # Store input results action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) key = libtcod.Key() mouse = libtcod.Mouse() move = action.get('move') 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') ability_1 = action.get('ability_1') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') #Instatiate our message queue for the players turn player_turn_results = [] # Player Actions # Move if move and game_state == GameStates.PLAYERS_TURN: if not move == 'wait': dx, dy = move destination_x = player.x + dx destination_y = player.y + dy # Check to see if the location we want to move to is blocked by a wall or inhabited by a creature if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location(entities, destination_x, destination_y) # If blocked by a creature, attack if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) # Otherwise, move. else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN else: 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)) #Ability complete checks: for ability in player.abilities: if player.animator.caller == ability and player.animator.complete: player_turn_results.extend(ability.use(complete=True)) player.animator.caller = None player.animator.complete = None if ability_1: player_turn_results.extend(player.abilities[0].use()) if show_inventory: if game_state != GameStates.SHOW_INVENTORY: previous_game_state = game_state player.inventory.sort_items() game_state = GameStates.SHOW_INVENTORY if drop_inventory: if game_state != GameStates.DROP_INVENTORY: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY #Use or drop item in 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) target_fov_map = initialize_fov(game_map) fov_map_no_walls = 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.con += 1 message_log.add_message(Message('Your Constitution has increased by 1!', libtcod.yellow)) elif level_up == 'str': player.fighter.base_power += 1 message_log.add_message(Message('Your Strength has increased by 1!', libtcod.yellow)) elif level_up == 'def': player.fighter.base_defense += 1 message_log.add_message(Message('Your Defense has increased by 1!', libtcod.yellow)) hp_increase = randint(player.fighter.hitdie[0], player.fighter.hitdie[1]) + int((player.fighter.con - 10) / 2) player.fighter.base_max_hp += hp_increase player.fighter.hp += hp_increase message_log.add_message(Message('Your HP has increased by {0}'.format(hp_increase) + '!', libtcod.yellow)) game_state = previous_game_state if show_character_screen: if not game_state == GameStates.CHARACTER_SCREEN: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if game_state == GameStates.TARGETING: if hasattr(targeting_item, 'item'): cursor_radius = targeting_item.item.function_kwargs.get('radius') else: cursor_radius = targeting_item.function_kwargs.get('radius') if left_click: target_x, target_y = left_click if hasattr(targeting_item, 'item'): item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_fov_map=target_fov_map,target_x=target_x, target_y=target_y) else: item_use_results = targeting_item.use(entities=entities, fov_map=fov_map, target_fov_map=target_fov_map,target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) cursor_radius = 1 elif right_click: player_turn_results.append({'targeting_cancelled': True}) cursor_radius = 1 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}) cursor_radius = 1 else: save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Check player message queue and react accordingly 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') ability_used = player_turn_result.get("ability_used") xp = player_turn_result.get('xp') if message: message_log.add_message(message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) 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 targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting if hasattr(targeting_item, 'item'): message_log.add_message(targeting_item.item.targeting_message) else: message_log.add_message(targeting_item.targeting_message) if ability_used: if Animator.blocking == 0: 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 removed the {0}'.format(dequipped.name))) game_state = GameStates.ENEMY_TURN if xp: leveled_up = player.level.add_xp(xp) message_log.add_message(Message('You gain {0} experience points.'.format(xp))) if leveled_up: message_log.add_message(Message('Your battle skills grow stronger! You reached level {0}'.format( player.level.current_level) + '!', libtcod.yellow)) if (player.level.current_level % 2) == 0: previous_game_state = game_state game_state = GameStates.LEVEL_UP else: hp_increase = randint(player.fighter.hitdie[0], player.fighter.hitdie[1]) + int((player.fighter.con - 10) / 2) player.fighter.base_max_hp += hp_increase player.fighter.hp += hp_increase message_log.add_message(Message('Your HP has increased by {0}'.format(hp_increase) + '!', libtcod.yellow)) # Enemy Turn 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) # Capture enemy turn message queue, analyze and react accordingly. 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
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 # game loop while not libtcod.console_is_window_closed(): # captures user input - will update the key and mouse variables with what the user inputs libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) # draw the entities and blit the changes to the screen - only render the item inventory when the game state is in the inventory state 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 # present everything on the screen libtcod.console_flush() # clear entities after drawing to screen - this makes it so that when entities move, they do not leave a trail behind clear_all(con, entities) # gives a way to gracefully exit program by hitting the ESC key # gets any keyboard input to the program and stores in the key variable 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 = [] # move the player only on the players turn if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy # check if there is something at the destination that would block the player - if not, move the player there 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 # change to enemy's turn after player's move game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN # if the player did not move and performed the pickup action by pressing the key 'g'... elif pickup and game_state == GameStates.PLAYERS_TURN: # loop through each entity on the map, check if it is an item and occupies the same space as the player for entity in entities: # if the entity is an item and in the same position as the player if entity.item and entity.x == player.x and entity.y == player.y: # add the item to the inventory and append the results to player_turn_results pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break # makes it so the player only picks up one item at a time 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 # take the index selected, use the item selected 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.max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.power += 1 elif level_up == 'def': player.fighter.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}) # checks if the key pressed was the Esc key - if it was, then exit the loop 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') 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_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if item_consumed: 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: message_log.add_message( Message( 'Your battle skills grow stronger! You reached level {0}' .format(player.level.current_level) + '!', libtcod.yellow)) 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 # note that this is a for-else statement; without a break statement, this else will always happen else: game_state = GameStates.PLAYERS_TURN
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): fov_recompute = True fov_map = initialize_fov(game_map) previous_game_state = game_state targeting_item = None message_log.add_message( Message(f'You are a ghost. You have nothing.', libtcod.white)) message_log.add_message( Message(f'Use the arrow keys to move', libtcod.white)) message_log.add_message( Message(f'Press \'p\' to possess a creature and gain its abilities...', libtcod.white)) message_log.add_message( Message(f'(Mouse over symbols for more information)', libtcod.white)) first_body = True first_inventory = True mouse_event = None while True: key_event = None left_click = None right_click = None exit_game = False for event in libtcod.event.get(): #print(f"Got Event: {event.type}") if event.type in ("QUIT"): print("QUIT event: Exiting") raise SystemExit() if event.type == "KEYDOWN": if event.sym == libtcod.event.K_ESCAPE: print(f"{event.type} K_ESCAPE: Exiting") exit_game = True else: key_event = event #print(f"Got Event: {event.type}: {key}") if event.type == "MOUSEMOTION": mouse_event = event if event.state & libtcod.event.BUTTON_LMASK: left_click = mouse_event if event.state & libtcod.event.BUTTON_RMASK: right_click = mouse_event if exit_game: break fov_radius = player.fighter.fov( ) if player.fighter else Constants.min_fov_radius if fov_recompute: recompute_fov(fov_map, player.x, player.y, 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_event, Constants.colors, game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key_event, game_state) 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') possession = action.get('possession') #start_test_mode = action.get('start_test_mode') restart = action.get('restart') player_turn_results = [] if False: # start_test_mode: fighter_component = Fighter(hp=30, defense=2, power=8, body='god mode', xp=100, will_power=4) player.fighter = fighter_component player.fighter.owner = player player.inventory = Inventory(26) player.equipment = Equipment() player.inventory.owner = player player.equipment.owner = player equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=1) item = Entity(player.x, player.y, '/', libtcod.red, 'Small Dagger', equippable=equippable_component) entities.append(item) if restart: player, entities, game_map, message_log, game_state = get_game_variables( Constants) game_state = GameStates.PLAYERS_TURN fov_map = initialize_fov(game_map) fov_recompute = True con.clear() if possession: if not player.fighter: for entity in entities: if entity.fighter and entity.x == player.x and entity.y == player.y: if player.level.current_level >= entity.fighter.will_power: message_log.add_message( Message( f"You take control of the {entity.name}'s body...", libtcod.white)) if first_body: message_log.add_message( Message(f'(Press p to release it)', libtcod.gray)) first_body = False if entity.inventory and first_inventory: message_log.add_message( Message( f'(Press g to Get items, i for Inventory)', libtcod.gray)) first_inventory = False player.fighter = entity.fighter player.inventory = entity.inventory player.equipment = entity.equipment player.possessed_entity = entity player.fighter.owner = player player.char = entity.char player.render_order = entity.render_order player.name = f'Ghost/{entity.name}' entities.remove(entity) else: message_log.add_message( Message( f'The {entity.name} is too powerful for you to possess!', libtcod.yellow)) else: message_log.add_message( Message( f'You cast your spirit out of the {player.possessed_entity.name}, leaving a shambling husk behind...', libtcod.red)) ai_component = SlowMonster() zombie_name = f'Zombie {player.possessed_entity.name}' zombie_char = player.possessed_entity.char zombie = Entity(player.x, player.y, zombie_char, libtcod.desaturated_green, zombie_name, blocks=True, render_order=RenderOrder.ACTOR, fighter=player.fighter, ai=ai_component, inventory=player.inventory, equipment=player.equipment) zombie.fighter.xp = 5 zombie.fighter.owner = zombie entities.append(zombie) player.fighter = None player.inventory = None player.equipment = None player.char = ' ' player.render_order = RenderOrder.GHOST player.name = 'Ghost' 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 and player.fighter: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True over_entities = [ e for e in entities if e.x == player.x and e.y == player.y and e != player ] if over_entities: over_fighters = [e for e in over_entities if e.fighter] over_items = [ e for e in over_entities if not e.fighter ] if over_fighters: over_fighter = over_fighters[0] message_log.add_message( Message( f'Your shadow falls over the {over_fighter.name}...', libtcod.white)) elif over_items: if len(over_items) == 1: over_items_list = f'{over_items[0].name}' elif len(over_items) == 2: over_items_list = f'{over_items[1].name} and a {over_items[0].name}' else: over_items_list = [ n.name for n in over_items[:-1] ].join(', a ') over_items_list += "and a {over_items[-1].name}" message_log.add_message( Message(f'There is a {over_items_list} here.', libtcod.white)) if 'Staircase' in [e.name for e in over_items ] and player.fighter: message_log.add_message( Message( f'(Press enter/return to use stairs)', libtcod.gray)) game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: if player.inventory: 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)) elif player.fighter: message_log.add_message( Message('This creature cannot carry items.', libtcod.yellow)) else: message_log.add_message( Message( "You can't pick up items without a body of some kind...", libtcod.yellow)) if show_inventory: if player.inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY elif player.fighter: message_log.add_message( Message('This creature cannot carry items.', libtcod.yellow)) else: message_log.add_message( Message('You lack a body to carry items...', libtcod.yellow)) if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and player.inventory 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 player.fighter: 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 targeting_cancelled: game_state = previous_game_state message_log.add_message( Message('Targeting cancelled', libtcod.yellow)) if dead_entity: if dead_entity.fighter == player.fighter: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if xp: leveled_up = player.level.add_xp(xp) fighter_leveled_up = player.fighter.level.add_xp(xp) message_log.add_message( Message('You gain {0} experience points.'.format(xp), libtcod.white)) if leveled_up: message_log.add_message( Message( 'You grow stronger! You reached level {0}'.format( player.level.current_level) + '!', libtcod.green)) message_log.add_message( Message('You can now possess larger creatures...', libtcod.red)) if fighter_leveled_up: previous_game_state = game_state game_state = GameStates.LEVEL_UP 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 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.fighter == player.fighter: 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
def play_game(player, entities, game_map, message_log, con, panel, tooltip, messages_pane, inventory_pane, constants, cam_x, cam_y, anim_frame, anim_time, log_scroll, log_height, inv_scroll, inv_height, inv_selected): 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(): anim_frame, anim_time = animation(anim_frame, anim_time) libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) log_height, inv_height = update_panels_heights( player, constants['panel_height']) render_all(con, panel, tooltip, messages_pane, inventory_pane, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['map_width'], constants['map_height'], constants['panel_width'], constants['panel_height'], constants['panel_x'], mouse, colors, cam_x, cam_y, anim_frame, game_state, targeting_item, log_scroll, log_height, inv_scroll, inv_height, inv_selected) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse, cam_x, cam_y) move = action.get('move') wait = action.get('wait') pickup = action.get('pickup') # show_inventory = action.get('show_inventory') prev_inventory = action.get('prev_inventory') next_inventory = action.get('next_inventory') use_inventory = action.get('use_inventory') drop_inventory = action.get('drop_inventory') # inventory_index = action.get('inventory_index') # toggle_log = action.get('toggle_log') 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 = [] #inventory highlight for mouse use if mouse.cx > constants['screen_width'] - constants[ 'panel_width'] and mouse.cy >= constants[ 'panel_height'] - 1 - inv_height and mouse.cy < constants[ 'panel_height'] - 1: inv_selected = mouse.cy - (constants['panel_height'] - 1 - inv_height) if left_click: #move if mouse.cx < player.x * 3 - cam_x and mouse.cx > player.x * 3 - cam_x - 6 and mouse.cy <= player.y * 2 - cam_y + 1 and mouse.cy >= player.y * 2 - cam_y: #move left move = (-1, 0) if mouse.cx > player.x * 3 - cam_x + 2 and mouse.cx < player.x * 3 - cam_x + 9 and mouse.cy <= player.y * 2 - cam_y + 1 and mouse.cy >= player.y * 2 - cam_y: #move right move = (1, 0) if mouse.cx >= player.x * 3 - cam_x and mouse.cx <= player.x * 3 - cam_x + 2 and mouse.cy < player.y * 2 - cam_y and mouse.cy > player.y * 2 - cam_y - 4: #move up move = (0, -1) if mouse.cx >= player.x * 3 - cam_x and mouse.cx <= player.x * 3 - cam_x + 2 and mouse.cy > player.y * 2 - cam_y + 1 and mouse.cy < player.y * 2 - cam_y + 6: #move down move = (0, 1) #use inventory item if mouse.cx > constants['screen_width'] - constants[ 'panel_width'] and mouse.cy >= constants[ 'panel_height'] - 1 - inv_height and mouse.cy < constants[ 'panel_height'] - 1: item = player.inventory.items[mouse.cy - (constants['panel_height'] - 1 - inv_height)] player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 #scroll log if mouse.cx == constants[ 'screen_width'] - 1 or mouse.cx == constants[ 'screen_width'] - 2 or mouse.cx == constants[ 'screen_width'] - 3: if mouse.cy == 4: #scroll message log up log_scroll += 1 if log_scroll > len(message_log.messages) - log_height: log_scroll = len(message_log.messages) - log_height elif mouse.cy == 4 + log_height and log_scroll > 0: # scroll message log down log_scroll -= 1 if right_click: #drop inventory item if mouse.cx > constants['screen_width'] - constants[ 'panel_width'] and mouse.cy >= constants[ 'panel_height'] - 1 - inv_height and mouse.cy < constants[ 'panel_height'] - 1 and len( player.inventory.items) > 0: item = player.inventory.items[mouse.cy - (constants['panel_height'] - 1 - inv_height)] player_turn_results.extend(player.inventory.drop_item(item)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 if next_inventory and inv_selected < len(player.inventory.items) - 1: inv_selected += 1 if prev_inventory and inv_selected > 0: inv_selected -= 1 if use_inventory and game_state != GameStates.PLAYER_DEAD: item = player.inventory.items[inv_selected] player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 if drop_inventory and game_state != GameStates.PLAYER_DEAD: item = player.inventory.items[inv_selected] player_turn_results.extend(player.inventory.drop_item(item)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 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) cam_x, cam_y = update_cam(player, constants) fov_recompute = True else: message_log.add_message( Message('You stupidly walk into the wall. Ouch.')) 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.')) # if show_inventory: # previous_game_state = game_state # game_state = GameStates.SHOW_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 toggle_log: # if constants['panel_height'] == constants['screen_height']: # constants['panel_height'] = 5 # else: # constants['panel_height'] = constants['screen_height'] 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) cam_x, cam_y = update_cam(player, constants) break else: message_log.add_message( Message('There are no stairs here.', colors.get('red'))) 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) fov_recompute = True elif right_click: player_turn_results.append({'targeting_cancelled': True}) fov_recompute = 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 targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) fov_recompute = True 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 targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) 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 unquipped the {0}'.format( dequipped.name))) game_state = GameStates.ENEMY_TURN if xp: leveled_up = player.level.add_xp(xp) message_log.add_message( Message('You gain {0} experience points.'.format(xp))) if leveled_up: message_log.add_message( Message( 'You reached level {0}'.format( player.level.current_level) + '!', colors.get('green'))) 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
def play_game(player, world, message_log, game_state, con, panel, constants): fov_recompute = True fov_map = initialize_fov(world.current_floor) key = libtcod.Key() mouse = libtcod.Mouse() previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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, player, world.current_floor, 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, targeting_item) fov_recompute = False libtcod.console_flush() clear_all(con, world.current_floor.entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') take_exit = action.get('take_exit') exit = action.get('exit') fullscreen = action.get('fullscreen') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') wait = action.get('wait') 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 world.current_floor.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( world.current_floor.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: message_log.add_message(Message('You wait.')) game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in world.current_floor.entities: if entity.try_component( '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=world.current_floor.entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if take_exit and game_state == GameStates.PLAYERS_TURN: for entity in world.current_floor.entities: if entity.try_component( 'exit' ) and entity.x == player.x and entity.y == player.y: world.change_room(player, entity, message_log) fov_map = initialize_fov(world.current_floor) fov_recompute = True con.clear(fg=(63, 127, 63)) game_state = GameStates.ENEMY_TURN break else: message_log.add_message( Message('There are no stairs here.', libtcod.yellow)) if level_up: player.fighter.base_max_hp += 20 player.fighter.hp += 20 if level_up == 'str': player.fighter.hit += 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=world.current_floor.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, world, 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') won_game = player_turn_result.get('won_game') if won_game: message_log.add_message(Message("You win!")) game_state = GameStates.WON_GAME 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: world.current_floor.entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: 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: message_log.add_message( Message( 'Your battle skills grow stronger! You reached level {0}' .format(player.level.current_level) + '!', libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if item_dropped: world.current_floor.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 game_state == GameStates.ENEMY_TURN: # I don't love this hack. May have to add a new game state for status effects. status_effect_results = player.status_effects.process_statuses() for result in status_effect_results: if 'message' in result: message_log.add_message(result['message']) if 'dead' in result: message, game_state = kill_player(player) message_log.add_message(message) continue # jumps back to main game loop, skipping the ai processing for entity in world.current_floor.entities: if entity.try_component('ai'): enemy_turn_results = entity.ai.take_turn( player, fov_map, world.current_floor) 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
def play_game(constants, root_console, panel_ui, panel_map, debug_f, omnivision, in_handle, mouse_x, mouse_y, player, entities, controlled_entity, curr_entity, game_state, prev_state, message_log, game_map, timeq, next_turn, render_update, targeting_item): # always update rendering upon entry render_update = True # main game loop while True: # refresh graphics for entity in entities: if entity.fov_map and entity.fov_recompute: render_update = True recompute_fov(game_map, entity, constants["fov_radius"], constants["fov_light_walls"], constants["fov_algorithm"]) entity.fov_recompute = False if render_update: if debug_f: print("RENDER UPDATE") render_all(root_console, panel_ui, panel_map, entities, game_map, controlled_entity, constants, omnivision, message_log, mouse_x, mouse_y, game_state) tcod.console_flush() render_update = False # run an entity's turn actions = {} results = [] # if it's the controlled entity's turn if curr_entity is controlled_entity: # get the actions the player wants to take next_turn = False # get user input in_handle.set_game_state(game_state) for event in tcod.event.get(): in_handle.dispatch(event) user_in = in_handle.get_user_input() if debug_f and user_in: print(user_in) input_r = parse_input(panel_map, in_handle, user_in, curr_entity, entities, game_map, mouse_x, mouse_y, game_state, prev_state, targeting_item) actions, mouse_x, mouse_y = input_r # process any player-only actions act_r = handle_player_actions(actions, in_handle, entities, game_map, root_console, panel_ui, panel_map, curr_entity, controlled_entity, player, omnivision, message_log, mouse_x, mouse_y, timeq, game_state, prev_state, constants, debug_f) (next_turn, curr_entity, controlled_entity, entities, player, timeq, omnivision, render_update_p, want_exit, game_state, prev_state) = act_r # if it's not the controlled entity's turn elif curr_entity.ai: # get the actions the entity wants to take actions = curr_entity.ai.take_turn(player, game_map, entities) if debug_f and actions: print(f"{curr_entity.name} - {curr_entity}: {actions}") # process turn actions, modify game state, and get results act_r = handle_entity_actions(actions, in_handle, entities, timeq, game_map, root_console, message_log, controlled_entity, player, game_state, prev_state, targeting_item, debug_f) (action_cost, next_turn, controlled_entity, render_update_e, game_state, prev_state, targeting_item) = act_r render_update = render_update_p or render_update_e # process turn results if want_exit: save_game(player, entities, controlled_entity, curr_entity, game_state, prev_state, message_log, game_map, timeq, next_turn, render_update, targeting_item) return True if debug_f and results: print(results) # TODO: check for and handle failure states if ((not player.fighter or player.fighter.hp <= 0) and game_state != GameStates.FAIL_STATE): message_log.add_message(Message("Oh no you lose!", tcod.red)) game_state = GameStates.FAIL_STATE render_update = True # put current entity back in time queue and get the next one if next_turn: # we do not reinsert entities with 0 speed if curr_entity.speed != 0: curr_entity.time_to_act = action_cost // curr_entity.speed # future: action_cost / curr_entity.speed for index, entity in enumerate(timeq): if entity.time_to_act > curr_entity.time_to_act: timeq.insert(index, curr_entity) break else: timeq.append(curr_entity) # get our next entity curr_entity = timeq.popleft() # count down everyone's time to act time_tick = curr_entity.time_to_act for entity in timeq: entity.time_to_act -= time_tick if entity.time_to_act < 0: entity.time_to_act = 0
def main(): constants = get_constants() libtcod.console_set_custom_font( 'arial12x12.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(constants['screen_width'], constants['screen_height'], constants['window_title'], False) con = libtcod.console_new(constants['screen_width'], constants['screen_height']) panel = libtcod.console_new(constants['screen_width'], constants['panel_height']) player = None entities = [] game_map = None message_log = None game_state = None show_main_menu = True show_load_error_message = False main_menu_background_image = libtcod.image_load('menu_background.png') key = libtcod.Key() mouse = libtcod.Mouse() while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if show_main_menu: main_menu(con, main_menu_background_image, constants['screen_width'], constants['screen_height']) if show_load_error_message: message_box(con, 'No save game to load', 50, constants['screen_width'], constants['screen_height']) libtcod.console_flush() action = handle_main_menu(key) new_game = action.get('new_game') load_saved_game = action.get('load_game') save_game_menu = action.get('save_game') exit_game = action.get('exit') if show_load_error_message and (new_game or load_saved_game or exit_game): show_load_error_message = False elif new_game: player, entities, game_map, message_log, game_state = get_game_variables( constants) game_state = GameStates.PLAYERS_TURN show_main_menu = False elif save_game_menu: save_game(player, entities, game_map, message_log, game_state) print('save success') elif load_saved_game: try: player, entities, game_map, message_log, game_state = load_game( ) show_main_menu = False except FileNotFoundError: show_load_error_message = True elif exit_game: break else: libtcod.console_clear(con) play_game(player, entities, game_map, message_log, game_state, con, panel, constants) show_main_menu = True
def play_game(player, entities, game_map, message_log, game_state, console, panel, constants): """ Initialize game and handle actions via game state and player events """ fov_recompute = True fov_map = initialize_fov(game_map) key = tcod.Key() mouse = tcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None while not tcod.console_is_window_closed(): tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov( fov_map, player.x_pos, player.y_pos, constants["fov_radius"], constants["fov_light_walls"], constants["fov_algorithm"], ) render_all( console, 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 tcod.console_flush() clear_all(console, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get("move") 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') exit_game = 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: d_x, d_y = move destination_x = player.x_pos + d_x destination_y = player.y_pos + d_y 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(d_x, d_y) fov_recompute = True game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if (entity.item and entity.x_pos == player.x_pos and entity.y_pos == player.y_pos): 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.", tcod.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_pos == player.x_pos and entity.y_pos == player.y_pos): entities = game_map.next_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True tcod.console_clear(console) break else: message_log.add_message( Message('There are no stairs here.', tcod.yellow)) if level_up: if level_up == 'hp': player.fighter.max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.power += 1 elif level_up == 'def': player.fighter.defense += 1 game_state = previous_game_state if game_state == GameStates.TARGETING: if left_click: target_x_pos, target_y_pos = left_click print(left_click) item_use_results = player.inventory.use( targeting_item, entities=entities, fov_map=fov_map, target_x_pos=target_x_pos, target_y_pos=target_y_pos, ) player_turn_results.extend(item_use_results) elif right_click: print(right_click) player_turn_results.append({"targeting_cancelled": True}) if exit_game: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): 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: tcod.console_set_fullscreen(not tcod.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") 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 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(f'You gain {xp} experience points')) if leveled_up: message_log.add_message( Message( f'Your battle skills grow stronger! You reached level {player.level.current_level}!', tcod.yellow)) 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
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): fov_recompute = True fov_map = initialize_fov(game_map) key = tc.Key() mouse = tc.Mouse() targeting_item = None visible_enemies = [] room_enemies_index = 0 room_enemies_length = 0 event = tc.event.get() while event != "QUIT": # while not tc.console_is_window_closed(): tc.sys_check_for_event(tc.EVENT_KEY_PRESS | tc.EVENT_MOUSE, key, mouse) 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 tc.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) mouse_teleport_action = handle_mouse_teleport(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') ranged_index = action.get('ranged_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') god_mode = action.get('god_mode') show_help_menu = action.get('show_help_menu') close_help_menu = action.get('close_help_menu') cycle_target = action.get('cycle_target') cycle_target_right = action.get('right_target') cycle_target_left = action.get('left_target') poisoned = action.get('poisoned') burning = action.get('burning') reveal_map = action.get('reveal_map') decrease_limb_damage = action.get('decrease_limb_damage') increase_limb_damage = action.get('increase_limb_damage') teleport = action.get('teleport') mouse_teleport = mouse_teleport_action.get('mouse_teleport') ranged = action.get('ranged') spawn_enemy_at = action.get('spawn_enemy_at') 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 if player.fighter.turns_since_special <= 5: player.fighter.turns_since_special += 1 game_state = GameStates.ENEMY_TURN elif wait: if player.fighter.turns_since_special <= 5: player.fighter.turns_since_special += 1 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.', tc.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 show_help_menu: previous_game_state = game_state game_state = GameStates.SHOW_HELP_MENU 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 ranged_index is not None and previous_game_state != GameStates.PLAYER_DEAD and ranged_index < len( player.inventory.items): item = player.inventory.items[ranged_index] if game_state == GameStates.RANGED: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) 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 and entity.stairs.direction == 'down': entities = game_map.next_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() break elif entity.stairs and entity.x == player.x and entity.y == player.y and entity.stairs.direction == 'up': entities = game_map.previous_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() break elif entity.area and entity.x == player.x and entity.y == player.y: entities = game_map.load_area(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() break else: message_log.add_message( Message('There are no stairs here.', tc.yellow)) if cycle_target: previous_game_state = game_state game_state = GameStates.CYCLE_TARGET visible_enemies.clear() for entity in entities: if entity.ai != None: if tc.map_is_in_fov(fov_map, entity.x, entity.y): visible_enemies.append([ cycle_target_distance_to(player, entity), entity.x, entity.y, entity.name ]) if len(visible_enemies) != 0: con.default_fg = tc.black con.default_fg = tc.white con.print( int(constants['screen_width'] / 2), 1, 'Press RIGHT arrow or LEFT arrow key to cycle targets or ESCAPE to cancel targeting' .format(), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) tc.console_blit(con, 0, 0, constants['screen_width'], constants['screen_height'], 0, 0, 0) visible_enemies.sort() room_enemies_length = len(visible_enemies) else: con.print( int(constants['screen_width'] / 2), 1, 'There are no enemies present! Press ESCAPE to cancel targeting' .format(), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) if cycle_target_right: if len(visible_enemies) != 0: fov_recompute = True con.clear() con.default_fg = tc.black con.default_fg = tc.white con.print( int(constants['screen_width'] / 2), 1, 'Press RIGHT arrow or LEFT arrow key to cycle targets or ESCAPE to cancel targeting' .format(), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) tc.console_blit(con, 0, 0, constants['screen_width'], constants['screen_height'], 0, 0, 0) con.draw_frame((visible_enemies[room_enemies_index][1]) - 1, (visible_enemies[room_enemies_index][2]) - 1, 3, 3, "", True, fg=tc.white, bg=tc.black) con.print((visible_enemies[room_enemies_index][1]) + 1, (visible_enemies[room_enemies_index][2]) - 2, '{0}'.format(visible_enemies[room_enemies_index][3]), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) for entity in entities: if tc.map_is_in_fov(fov_map, entity.x, entity.y): if visible_enemies[room_enemies_index][ 3] == entity.name: names = entity.name names = names + ' ' + Mage.get_stats( entity) + Fighter.get_stats(entity) con.print( (visible_enemies[room_enemies_index][1]) + 1, (visible_enemies[room_enemies_index][2]) - 2, '{0}'.format(names, tc.white), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) if room_enemies_index == room_enemies_length - 1: room_enemies_index = 0 else: room_enemies_index += 1 if cycle_target_left: if len(visible_enemies) != 0: fov_recompute = True con.clear() con.default_fg = tc.black con.default_fg = tc.white con.print( int(constants['screen_width'] / 2), 1, 'Press RIGHT arrow or LEFT arrow key to cycle targets or ESCAPE to cancel targeting' .format(), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) tc.console_blit(con, 0, 0, constants['screen_width'], constants['screen_height'], 0, 0, 0) con.draw_frame((visible_enemies[room_enemies_index][1]) - 1, (visible_enemies[room_enemies_index][2]) - 1, 3, 3, "", True, fg=tc.white, bg=tc.black) con.print((visible_enemies[room_enemies_index][1]) + 1, (visible_enemies[room_enemies_index][2]) - 2, '{0}'.format(visible_enemies[room_enemies_index][3]), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) for entity in entities: if tc.map_is_in_fov(fov_map, entity.x, entity.y): if visible_enemies[room_enemies_index][ 3] == entity.name: names = entity.name names = names + ' ' + Mage.get_stats( entity) + Fighter.get_stats(entity) con.print( (visible_enemies[room_enemies_index][1]) + 1, (visible_enemies[room_enemies_index][2]) - 2, '{0}'.format(names, tc.white), (255, 255, 255), (0, 0, 0), 1, tc.CENTER) if room_enemies_index == 0: room_enemies_index = room_enemies_length - 1 else: room_enemies_index -= 1 if god_mode: player.fighter.hp = 2500 if poisoned: if player.fighter.is_poisoned == False: player.fighter.is_poisoned = True player.fighter.poison_turns_remaining = 5 player.color = tc.green if burning: if player.fighter.is_burning == False: player.fighter.is_burning = True player.fighter.burning_turns_remaining = 5 player.color = tc.red if reveal_map: if constants['fov_radius'] == 8: constants['fov_radius'] = 250 for i in range(len(game_map.tiles)): for j in range(len(game_map.tiles[i])): if not game_map.tiles[i][j].blocked: game_map.tiles[i][j].explored = True game_map.tiles[i][j].block_sight = False fov_map = initialize_fov(game_map) fov_recompute = True con.default_fg = tc.black con.default_fg = tc.white for entity in entities: #ALL ENTITIES # con.draw_frame(entity.x - 1, entity.y - 1 , 3, 3, "", False, fg=tc.black, bg=tc.black) #ENEMIES ONLY if entity.ai != None: #ENEMY SEEING POWER con.draw_frame(entity.x - 1, entity.y - 1, 3, 3, "", False, fg=tc.black, bg=tc.black) elif constants['fov_radius'] != 8: constants['fov_radius'] = 8 fov_recompute = True con.clear() if spawn_enemy_at: mouse_x = mouse.cx mouse_y = mouse.cy spawn_enemy(mouse_x, mouse_y, entities, game_map.dungeon_level) if increase_limb_damage: player.fighter.take_limb_damge(randint(1, 12)) if decrease_limb_damage: player.fighter.heal(randint(1, 12)) if teleport: for entity in entities: if entity.name == "Stairs Down": player.x = entity.x player.y = entity.y + 1 if mouse_teleport: player.x = mouse.cx player.y = mouse.cy if ranged: previous_game_state = game_state game_state = GameStates.RANGED if level_up: if level_up == 'hp': player.fighter.base_max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.base_strength += 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, GameStates.RANGED, GameStates.TARGETING, GameStates.SHOW_TUTORIAL, GameStates.SHOW_HELP_MENU): game_state = previous_game_state elif game_state == GameStates.CYCLE_TARGET: game_state = previous_game_state con.clear() clear_all(con, entities) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() elif game_state == GameStates.TARGETING: game_state = previous_game_state player_turn_results.append({'targeting_cancelled': True}) con.clear() clear_all(con, entities) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() else: save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: tc.console_set_fullscreen(not tc.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') god_mode = player_turn_result.get('god_mode') 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) last_index = len(entities) pre_dead_name = dead_entity.name.replace('remains of ', '') if dead_entity.inventory != None: for items in dead_entity.inventory.items: items.x = dead_entity.x items.y = dead_entity.y entities.insert(last_index, items) message_log.add_message( Message('{0}'.format(pre_dead_name) + ' dropped' + ' {0}'.format(items.name))) message_log.add_message(message) if item_added: entities.remove(item_added) if item_consumed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) if equip: equip_results = player.equipment.toggle_equip(equip) for equip_result in equip_results: equipped = equip_result.get('equipped') unequipped = equip_result.get('unequipped') failed = equip_result.get('failed') if equipped: message_log.add_message( Message('You equipped the {0}'.format( equipped.name))) if unequipped: message_log.add_message( Message('You unequipped the {0}'.format( unequipped.name))) if failed: message_log.add_message( Message( 'You failed to equip the {0} due to your injuries' .format(failed.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: # #TRACK ENEMY SPECIAL TURNS # if tc.map_is_in_fov(fov_map, entity.x, entity.y): # print(entity.name + ":" + " " + str(entity.fighter.turns_since_special)) enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) if entity.fighter.is_poisoned == True: message = entity.fighter.take_poison_damage() message_log.add_message(message) elif entity.fighter.is_burning == True: message = entity.fighter.take_burning_damage() message_log.add_message(message) 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: if player.fighter.is_poisoned == True: message = player.fighter.take_poison_damage() message_log.add_message(message) elif player.fighter.is_burning == True: message = player.fighter.take_burning_damage() message_log.add_message(message) game_state = GameStates.PLAYERS_TURN if game_state == GameStates.SHOW_TUTORIAL: action = handle_tutorial_menu(key) close_tutorial = action.get('close_tutorial') if close_tutorial: con.clear() clear_all(con, entities) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() game_state = GameStates.PLAYERS_TURN if game_state == GameStates.SHOW_HELP_MENU: action = handle_help_menu(key) close_help_menu = action.get('close_help_menu') if close_help_menu: con.clear() clear_all(con, entities) fov_map = initialize_fov(game_map) fov_recompute = True con.clear() game_state = GameStates.PLAYERS_TURN
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(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse ) 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 libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get("move") pickup = action.get("pickup") show_inventory = action.get("show_inventory") drop_inventory = action.get("drop_inventory") inventory_index = action.get("inventory_index") 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 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 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): 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") targeting = player_turn_result.get("targeting") targeting_cancelled = player_turn_result.get("targeting_cancelled") 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 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 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
def main(): """ L'une des deux fonctions principales du jeu, elle est appelée une seule et unique fois : au démarrage du jeu. Elle a la charge de gérer le choix d'affichage des menus et les réactions aux inputs du joueur. Lorsque le joueur quitte un menu pour retourner en jeu, elle appelle la deuxième fonction de ce module : play_game Parametres: ---------- Aucun Renvoi: ------- Aucun """ # Initialise le jeu en commencant par afficher le menu principal constants = get_constants() # The font has 32 chars in a row, and there's a total of 10 rows. Increase the "10" when you add new rows to the sample font file libtcod.console_set_custom_font('textures.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD, 32, 10) load_customfont() libtcod.console_init_root(constants['screen_width'], constants['screen_height'], "Rogue doesn't like", False) con = libtcod.console_new(constants['screen_width'], constants['screen_height']) panel = libtcod.console_new(constants['screen_width'], constants['panel_height']) player = None entities = [] game_map = None message_log = None game_state = None show_main_menu = True show_load_error_message = False show_command_menu = False show_scores = False main_menu_background_image = libtcod.image_load('menu_background.png') play_bg_music = False bg_music = sm.choose_sound(constants.get('sound').get('background_music')) key = libtcod.Key() mouse = libtcod.Mouse() score = (1, 0) while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # Si le menu principal est affiche : if show_main_menu: main_menu(con, main_menu_background_image, constants['screen_width'], constants['screen_height']) if show_load_error_message: message_box(con, 'Rien a charger', 70, constants['screen_width'], constants['screen_height']) libtcod.console_flush() action = handle_main_menu(key) new_game = action.get('new_game') load_saved_game = action.get('load_game') exit_game = action.get('exit') sound = action.get('sound') command = action.get('command') back_to_game = action.get('back_to_game') scores = action.get('scores') if show_load_error_message and (new_game or load_saved_game or exit_game): show_load_error_message = False # Cree une nouvelle partie elif new_game: if score != (1, 0): save_score(score) player, entities, game_map, message_log, game_state = get_game_variables(constants) game_state = GameStates.PLAYERS_TURN show_main_menu = False # Charge une partie existante, si possible elif load_saved_game: try: player, entities, game_map, message_log, game_state, score = load_game() show_main_menu = False except FileNotFoundError: show_load_error_message = True elif exit_game: if score != (1, 0): save_game(player, entities, game_map, message_log, game_state, score) sm.close_sound() break # Lit ou arrete la musique de fond elif sound: play_bg_music = not play_bg_music bg_music.playpause() elif command: show_command_menu = True show_main_menu = False elif back_to_game and show_main_menu and game_state != GameStates.PLAYER_DEAD: show_main_menu = False elif scores: show_main_menu = False show_scores = True # Affiche le menu des commandes elif show_command_menu: action = handle_main_menu(key) command_menu(con, main_menu_background_image, constants['screen_width'], constants['screen_height']) libtcod.console_flush() back_to_game = action.get('back_to_game') if back_to_game: show_main_menu = True show_command_menu = False libtcod.console_clear(con) # Affiche les trois meilleurs scores et le dernier elif show_scores: action = handle_main_menu(key) scores_menu(con, main_menu_background_image, constants['screen_width'], constants['screen_height']) libtcod.console_flush() back_to_game = action.get('back_to_game') if back_to_game: show_main_menu = True show_scores = False libtcod.console_clear(con) # Lance une partie else: libtcod.console_clear(con) player, entities, game_map, message_log, game_state, bg_music, play_bg_music, score = play_game(player, entities, game_map, message_log, game_state, con, panel, constants, bg_music, play_bg_music, score) if game_state == GameStates.PLAYER_DEAD: show_scores = True else: show_main_menu = True
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): fov_recompute = True #bool so that we only update fov when we need to fov_map = initalize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() previous_game_state = game_state targeting_item = None ######## GAME LOOP STARTS HERE ####################################################################################################################################################### while not libtcod.console_is_window_closed( ): # while the console window is....open??? MAIN GAME LOOP libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm'] ) # this is where we do the FOV stuff! 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['colours'], game_state) fov_recompute = False libtcod.console_flush( ) # this is what actually tells the window to draw I guess clear_all(con, entities) ##### Action handler ##### action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') 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 = [ ] ## this is the container for the results of the players action during their turn ######################################################################################################################################## if move and game_state == GameStates.PLAYER_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 # recalculate feild of view whenver the player moves game_state = GameStates.ENEMY_TURN ########################## elif pickup and game_state == GameStates.PLAYER_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 to pick up.', libtcod.amber)) #################################################################################### 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 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_result.append({'targeting_canceled': True}) #################################################################################### if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_canceled': 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') targeting = player_turn_result.get('targeting') targeting_canceled = player_turn_result.get('targeting canceled') if message: message_log.add_message(message) if targeting_canceled: game_state = previous_game_state message_log.add_message(Message('Targeting canceled')) 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 targeting: previous_game_state = GameStates.PLAYER_TURN #prev is set ot player turn so that canceling targeting doesnt put you bakc into the inventory game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN ###################################################################################################### 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.PLAYER_TURN
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants, root_con): tcod.console_set_custom_font( "arial10x10.png", tcod.FONT_LAYOUT_TCOD | tcod.FONT_TYPE_GREYSCALE) fov_recompute = True fov_map = initialize_fov(game_map) previous_game_state = game_state targeting_item = None while True: 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_y"], constants["colors"], root_con, game_state) tcod.console_flush() clear_all(con, entities) for event in tcod.event.get(): move = None pickup = None look_enemy = None left_click = None right_click = None show_inventory = None drop_inventory = None inventory_index = None take_stairs = None leave = None fullscreen = None show_character_screen = None player_turn_results = [] if isinstance(event, tcod.event.KeyDown): action = handle_keys(event, game_state) move = action.get("move") pickup = action.get("pickup") look_enemy = action.get("look_enemy") show_inventory = action.get("show_inventory") drop_inventory = action.get("drop_inventory") inventory_index = action.get("inventory_index") take_stairs = action.get('take_stairs') leave = action.get("leave") fullscreen = action.get("fullscreen") show_character_screen = action.get('show_character_screen') if isinstance(event, tcod.event.MouseButtonDown): mouse_action = handle_mouse(event) left_click = mouse_action.get("left_click") right_click = mouse_action.get("right_click") if look_enemy and game_state == GameStates.PLAYER_TURN: game_state = GameStates.LOOK_ENEMY player_turn_results.extend([{ 'message': Message('You are in the looking mode', tcod.green) }]) elif look_enemy and game_state == GameStates.LOOK_ENEMY: game_state = GameStates.PLAYER_TURN player_turn_results.extend([{ 'message': Message('You left the looking mode', tcod.green) }]) elif left_click and game_state == GameStates.LOOK_ENEMY: entities_at_location = check_entity_at_location( entities, left_click[0], left_click[1]) player_turn_results.extend(entities_at_location) elif pickup and game_state == GameStates.PLAYER_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.', tcod.yellow)) elif show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY MenuState.menu_state = 0 elif drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY elif 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)) elif game_state == GameStates.TARGETING: if left_click and targeting_item: 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}) elif move and game_state == GameStates.PLAYER_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.melee_attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif take_stairs and game_state == GameStates.PLAYER_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 con.clear(fg=(63, 127, 63)) break else: message_log.add_message( Message('There are no stairs here.', tcod.yellow)) elif game_state == GameStates.LEVEL_UP: player.fighter.max_hp += DiceRoll("1d8").roll_dice() game_state = previous_game_state elif show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if leave: 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: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') entity_identified = player_turn_result.get("entity_identified") item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') 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 entity_identified: game_state = GameStates.PLAYER_TURN if targeting: previous_game_state = GameStates.PLAYER_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: message_log.add_message( Message( 'Your battle skills grow stronger! You reached level {0}' .format(player.level.current_level) + '!', tcod.yellow)) player.fighter.cr = str(player.level.current_level / 4) 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.PLAYER_TURN
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): # Whether to recompute the fov (Would be false if the player didn't move that turn). # True by default because we have to compute it when the game starts. fov_recompute = True # Computes the fov_map fov_map = initialise_fov(game_map) # Stores the keyboard and mouse input. This will be updated throughout the game loop. key = libtcod.Key() mouse = libtcod.Mouse() # Stores the previous game state. Used for changing gamestate and reverting without wasting a turn. # e.g when opening the inventory. previous_game_state = game_state # Stores which item requires targeting. targeting_item = None ############################################################ # GAME LOOP ############################################################ while not libtcod.console_is_window_closed(): # Captures input - will update key and mouse variables with the input. libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # Recomputes the FOV if necessary. if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants["fov_radius"], constants["fov_light_walls"], constants["fov_algorithm"]) # Draws all entities to the off-screen console and blits the console to the root. 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) # Don't recompute the fov/repaint the tiles until after the player moves. fov_recompute = False # Flushes/draws the screen. libtcod.console_flush() # Erases all characters on the off-screen console. clear_all(con, entities) ##### REACTS TO A KEY PRESS OR A MOUSE CLICK ##### action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) # Stores the value/s returned from dictionary key. # Performs an action if one of the variables is not empty. # Key presses: move = action.get("move") wait = action.get("wait") pickup = action.get("pickup") show_inventory = action.get("show_inventory") drop_inventory = action.get( "drop_inventory" ) # An inventory screen where you can only drop items. 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") # Mouse clicks: left_click = mouse_action.get("left_click") right_click = mouse_action.get("right_click") ########## PLAYER'S TURN ########## # Stores the results from the player's turn. # Each index defines what action should be taken. player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: # Stores the coordinates to move to. dx, dy = move destination_x = player.x + dx destination_y = player.y + dy # Alters the player's position by dx/dy amount if the destination is not a blocked tile. if not game_map.is_blocked(destination_x, destination_y): # Stores the blocking entity if the destination if there is one. target = get_blocking_entities_at_location( entities, destination_x, destination_y) # If there is a blocking entity: if target: # Stores the attack results. attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) # If there is no blocking entity the player will move. else: player.move(dx, dy) # Recomputes the FOV map now the player has moved. fov_recompute = True # Sets the game state to the enemy's turn. game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN # Skips the player's turn. # If the pickup button was pressed (g). elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: # If the overlapping entity can be picked up. if entity.item and entity.x == player.x and entity.y == player.y: # Adds the item to the inventory and results the results. # Results include a Message and the grabbed Item object. pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) # Breaks so we can only pickup one item at a time. break else: message_log.add_message( Message("There is nothing here to pick up", libtcod.yellow)) # If 'i' was pressed for inventory it changes the gamestate while storing the previous state. if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY # If 'd' was pressed for the drop inventory. if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY # Selects an item in the inventory using the index value of the item. 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 the SHOW_INVENTORY state, the item will be used. if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) # If the DROP_INVENTORY state, the item will be dropped. elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) # If the player has attempted to move down some stairs. if take_stairs and game_state == GameStates.PLAYERS_TURN: for entity in entities: # If the player IS on the same tile as the stairs. if entity.stairs and entity.x == player.x and entity.y == player.y: # Creates a new dungeon floor and returns and stores a new set of entities for the new floor. entities = game_map.next_floor(player, message_log, constants) # Initialises the fov mapf or the new floor. fov_map = initialise_fov(game_map) fov_recompute = True # Clears the console of the old game map. libtcod.console_clear(con) # Prevents other entities from being checked. break else: message_log.add_message( Message("There are no stairs here.", libtcod.yellow)) # Upgrades one of the player's stats on level up then return to previous game state. if level_up: if level_up == "hp": player.fighter.base_max_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 the game state has bene set to tarrgeting mode it will check if any left or right clicks have been made # Left clicks use the item stored in 'targeting_item' and will extend the results to player_turn_results. # Right click appends 'targeting_cancelled'. to the player results. 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}) # Exits the game. UNLESS a menu is open then it just closes the menu. if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): game_state = previous_game_state # If the user is targeting ESC only exist the targeting game state. elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) # Saves the game and exits the game. else: save_game(player, entities, game_map, message_log, game_state) return True # Fullscreen. if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) ### Acts on player's turn results including adding to message log. ### 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 the dead entity is the player. # Gamestate will be set to PLAYER_DEAD if dead_entity == player: message, game_state = kill_player(dead_entity) # If the dead entity is not the player it will be killed. else: message = kill_monster(dead_entity) # Prints one of the messages. message_log.add_message(message) # If an item was picked up it removes it from the entity list and sets the game state to enemy turn. # (The entity is no longer on the map so it is removed) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN # Consuming an item triggers the enemy turn. if item_consumed: game_state = GameStates.ENEMY_TURN # Switches the game state to TARGETING, stores the targeting item and adds the targeting message to the log. if targeting: # Changes the previous game state to PLAYERS_TURN rather than INVENTORY so that cancelling the targeting # mode (with ESC) returns the playher back to the main console rather than the inventory screen. previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) # If the user cancelled targeting the previous state will be reverted. if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message("Targeting cancelled")) if xp: leveled_up = player.level.add_xp( xp) # Will be True if the player leveled up. message_log.add_message( Message("You gain {0} experience points".format(xp))) if leveled_up: message_log.add_message( Message( "Your experience enhances your abilities - you reached level {0}!" .format(player.level.current_level), libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP 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_results.get("equipped") dequipped = equip_result.get("dequipped") if equipped: message_log.add_message( Message("You equipped the {}".format( equipped.name))) if dequipped: message_log.add_message( Message("You dequipped the {}".format( dequipped.name))) game_state = GameStates.ENEMY_TURN # Equipping or dequipping uses a turn. ########## ENEMY's TURN ########## if game_state == GameStates.ENEMY_TURN: for entity in entities: # If the entity has the ai component. 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 the dead entity is the player. # Gamestate will be set to PLAYER_DEAD if dead_entity == player: message, game_state = kill_player(dead_entity) # If the monster killed another monster. else: message = kill_monster(dead_entity) # Prints one of the death messages. message_log.add_message(message) # Prevents the else/player's turn from occurring again by breaking the for loop. if game_state == GameStates.PLAYER_DEAD: break # Prevents the else/player's turn from occurring again by breaking the for loop. if game_state == GameStates.PLAYER_DEAD: break # If break wasn't called do this: else: # Sets the game state to the player's turn. game_state = GameStates.PLAYERS_TURN
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): fov_recompute = True fov_map = initialize_fov(game_map) game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None mouse = libtcod.Mouse() key = libtcod.Key() render_update = True # main game loop while True: libtcod.sys_check_for_event(libtcod.EVENT_MOUSE, key, mouse) rendering_proc(player, entities, game_map, message_log, game_state, con, panel, constants, fov_map, mouse, fov_recompute) move, wait, doexit, pickup, fullscreen, show_inventory, drop_inventory, inventory_index, take_stairs, level_up, show_character_screen, in_target, mousemotion, left_click, right_click = check_actions( game_state) player_turn_results = [] if mousemotion: render_update = True if render_update: 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'], constants['colors'], game_state, mouse) tcod.console_flush() render_update = False game_state, fov_recompute, fov_map, con, entities = action_check_player_actions( game_state, move, player, game_map, entities, player_turn_results, wait, message_log, take_stairs, level_up, previous_game_state, constants, con, fov_recompute, fov_map) player_turn_results, previous_game_state, game_state = action_check_inventory( pickup, drop_inventory, game_state, entities, player, player_turn_results, message_log, show_inventory, fov_map, inventory_index, 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 doexit: 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()) game_state, message_log, targeting_item = action_turn_results( player_turn_results, message_log, player, con, game_map, in_target, entities, game_state, previous_game_state, targeting_item) game_state, message_log = action_enemy_turn(game_state, entities, player, fov_map, game_map, message_log)
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants, turns, poison_turns, burned_turns, frozen_turns): fov_recompute = True pet = 0 boss = None for entity in entities: if entity.name == 'Pet': pet = entity break for entity in entities: if entity.name == 'Dragonlord': boss = entity break 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 arrow_targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) if game_map.biome == 'The Dungeon': colors = { 'dark_wall': libtcod.darkest_grey, 'dark_ground': libtcod.darker_grey, 'light_wall': libtcod.grey, 'light_ground': libtcod.white, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } elif game_map.biome == 'The Icebleak Cavern': colors = { 'dark_wall': libtcod.darkest_cyan, 'dark_ground': libtcod.darker_cyan, 'light_wall': libtcod.dark_cyan, 'light_ground': libtcod.white, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } elif game_map.biome == 'The Underglade': colors = { 'dark_wall': libtcod.darker_green, 'dark_ground': libtcod.darkest_green, 'light_wall': libtcod.desaturated_green, 'light_ground': libtcod.brass, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } elif game_map.biome == 'The Hadalrealm': colors = { 'dark_wall': libtcod.darkest_red, 'dark_ground': libtcod.darker_red, 'light_wall': libtcod.dark_red, 'light_ground': libtcod.white, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } elif game_map.biome == 'Dragonroost': colors = { 'dark_wall': libtcod.darkest_grey, 'dark_ground': libtcod.darker_grey, 'light_wall': libtcod.dark_grey, 'light_ground': libtcod.grey, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } elif game_map.biome == 'Oblivion\'s Gate': colors = { 'dark_wall': libtcod.darkest_grey, 'dark_ground': libtcod.darker_grey, 'light_wall': libtcod.dark_grey, 'light_ground': libtcod.white, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } elif game_map.biome == 'The Vault': colors = { 'dark_wall': libtcod.darker_yellow, 'dark_ground': libtcod.dark_yellow, 'light_wall': libtcod.yellow, 'light_ground': libtcod.white, 'dark_water': libtcod.blue, 'light_water': libtcod.light_blue } render_all(turns, 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, colors, game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) player.sound = 0 Scent.set_scent(game_map, player.x, player.y, turns) move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') exit = action.get('exit') fullscreen = action.get('fullscreen') wait = action.get('wait') take_up_stairs = action.get('take_up_stairs') take_down_stairs = action.get('take_down_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') show_help_screen = action.get('show_help_screen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') up = action.get('up') down = action.get('down') left = action.get('left') right = action.get('right') player_turn_results = [] if player.frozen and frozen_turns > 0: game_state = GameStates.ENEMY_TURN if player.frozen == False: frozen_turns = -42 if player.burned == False: burned_turns = -42 if player.poisoned == False: poison_turns = -42 if poison_turns == 0: player_turn_results.append({ 'message': Message('You feel a lot better', libtcod.light_cyan) }) poison_turns = -42 player.poisoned = False if burned_turns == 0: player_turn_results.append({ 'message': Message('Your burn feels a lot better', libtcod.light_cyan) }) burned_turns = -42 player.burned = False if frozen_turns == 0: player_turn_results.append( {'message': Message('You defrost', libtcod.light_cyan)}) frozen_turns = -42 player.frozen = False if wait: game_state = GameStates.ENEMY_TURN d = randint(0, 100) if d < 25: message_log.add_message( Message('You stand around doing nothing', libtcod.brass)) elif d < 50: message_log.add_message( Message('You lean on your sword', libtcod.brass)) elif d < 75: message_log.add_message( Message('You stand around looking like a lemon', libtcod.brass)) else: message_log.add_message( Message('You examine your surroundings intensely', libtcod.light_amber)) 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: if target.name == 'Pet': target = None if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: if game_map.tiles[player.x][player.y].water == True: if randint(0, 10) == 1: game_map.tiles[destination_x][ destination_y].water = True player_turn_results.append({ 'message': Message( 'You splash water all over the dry bit of floor', libtcod.cyan) }) player.move(dx, dy) player.sound = 10 if turns % randint(9, 11) == 0: player.fighter.heal(1) levelup = player.level.add_con_xp(1) if levelup: player.fighter.hp += 20 player.fighter.base_max_hp += 20 player_turn_results.append({ 'message': Message( 'You feel healthy, you must have been very active', libtcod.fuchsia) }) fov_recompute = True game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: here = 0 for entity in entities: if entity.name != 'Player' and not entity.stairs and not entity.monster_class == '(Pet)': if (entity.item or entity.equippable ) and entity.x == player.x and entity.y == player.y: here = 1 player.sound = 5 pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) else: if here == 0: 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 player.sound = 5 game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.items): item = player.items[inventory_index] if type(item) != str: if game_state == GameStates.SHOW_INVENTORY: success = True if item.item_class == '(Scroll)': difficulty = randint(0, 10) if difficulty > player.fighter.intelligence: success = False else: levelup = player.level.add_int_xp(1) if levelup: message_log.add_message( Message( 'Your reading grows more accurate!', libtcod.fuchsia)) player.fighter.base_intelligence += 1 player_turn_results.extend( player.inventory.use(success, item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend( player.inventory.drop_item(item)) else: message_log.add_message( Message('You can\'t use Headers', libtcod.yellow)) if take_up_stairs and game_state == GameStates.PLAYERS_TURN and not boss: for entity in entities: if entity.stairs and entity.x == player.x and entity.y == player.y: pet, entities = game_map.next_floor( player, message_log, constants, entities, 'up') fov_map = initialize_fov(game_map) fov_recompute = True player.sound = 10 libtcod.console_clear(con) break else: message_log.add_message( Message('You can\'t go up here.', libtcod.yellow)) if take_down_stairs and game_state == GameStates.PLAYERS_TURN and not boss: for entity in entities: if entity.stairs and entity.x == player.x and entity.y == player.y: pet, entities = game_map.next_floor( player, message_log, constants, entities, 'down') fov_map = initialize_fov(game_map) fov_recompute = True player.sound = 10 libtcod.console_clear(con) break else: message_log.add_message( Message('You can\'t go down 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_defence += 1 elif level_up == 'int': player.fighter.base_intelligence += 1 elif level_up == 'dex': player.fighter.base_dexterity += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_help_screen: previous_game_state = game_state game_state = GameStates.HELP_SCREEN if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(success, 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 game_state == GameStates.ARROW_TARGETING: direction = None if up: direction = 'up' elif down: direction = 'down' elif left: direction = 'left' elif right: direction = 'right' if direction: item_use_results = player.inventory.use(success, arrow_targeting_item, entities=entities, fov_map=fov_map, direction=direction) player_turn_results.extend(item_use_results) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.HELP_SCREEN): game_state = previous_game_state elif game_state == GameStates.TARGETING or game_state == GameStates.ARROW_TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state, poison_turns, turns, burned_turns, frozen_turns) 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') arrow_consumed = player_turn_result.get('arrow_consumed') item_dropped = player_turn_result.get('item_dropped') equip = player_turn_result.get('equip') targeting = player_turn_result.get('targeting') arrow_targeting = player_turn_result.get('arrow_targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') player_burned = player_turn_result.get('burned') enemy_turn = player_turn_result.get('pass') if enemy_turn: game_state = GameStates.ENEMY_TURN if player_burned: player_turn_results.append( {'message': Message('You get Burned', libtcod.flame)}) burned_turns = randint(5, 10) message = player_turn_result.get('message') 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, game_map, entities) arrows = 0 for i in range(0, dead_entity.arrows): arrow_break = randint(0, 1) if not arrow_break: item_component = Item(use_function=None) arrow = Entity(dead_entity.x, dead_entity.y, '|', libtcod.sepia, 'Arrow', item=item_component, item_class='(Arrow)') entities.append(arrow) else: arrows += 1 if arrows == 1: MessageLog.add_message( self=message_log, message=Message( 'The arrow stuck in the {0} breaks as it falls over' .format(dead_entity.name), libtcod.red)) elif arrows: MessageLog.add_message( self=message_log, message=Message( 'The {0} arrows stuck in the {1} breaks as it falls over' .format(arrows, dead_entity.name), libtcod.red)) 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 arrow_consumed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if equip: player.sound = 10 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 arrow_targeting: player.sound = 5 previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.ARROW_TARGETING arrow_targeting_item = arrow_targeting message_log.add_message( arrow_targeting_item.item.targeting_message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if game_state == GameStates.ENEMY_TURN: if turns % int( (300 - (game_map.dungeon_level * 2)) / 2) == 0 and turns != 0: game_map.add_entity(message_log, entities, fov_map) if burned_turns >= 0 and player.burned: dead_entity = False burned_results = player.fighter.take_damage(4) for burned_result in burned_results: dead_entity = burned_result.get('dead') if dead_entity: if dead_entity.name == 'Player': message, game_state = kill_player(dead_entity) message_log.add_message(message) burned_turns -= 1 if poison_turns >= 0 and player.poisoned: dead_entity = False poison_results = player.fighter.take_damage(1) for poison_result in poison_results: dead_entity = poison_result.get('dead') if dead_entity: if dead_entity.name == 'Player': message, game_state = kill_player(dead_entity) message_log.add_message(message) poison_turns -= 1 if frozen_turns >= 0 and player.frozen: frozen_turns -= 1 if frozen_turns == 0: player.frozen = False for entity in entities: if entity.ai: pet_there = 0 if pet: if entity.distance_to(player) >= entity.distance_to( pet) and entity.name != 'Pet': pet_there = 1 enemy_turn_results = entity.ai.take_turn( pet, fov_map, game_map, entities, turns) else: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities, turns) else: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities, turns) for enemy_turn_result in enemy_turn_results: if burned_turns >= 0: burned_results = entity.fighter.take_damage(4) for burned_result in burned_results: dead_entity = burned_result.get('dead') if dead_entity.name == 'Player': message, game_state = kill_player( dead_entity) message_log.add_message(message) burned_turns -= 1 poisoned, player_burned, frozen = False, False, False if not player.fighter.poison_resistance and not pet_there: poisoned = enemy_turn_result.get('poisoned') if not player.fighter.fire_resistance and not pet_there: player_burned = enemy_turn_result.get('burned') if not player.fighter.poison_resistance and not pet_there: frozen = enemy_turn_result.get('frozen') if player_burned: enemy_turn_results.append({ 'message': Message('You get Burned', libtcod.flame) }) burned_turns = randint(5, 10) player.burned = True if poisoned: enemy_turn_results.append({ 'message': Message('you start to feel ill', libtcod.green) }) poison_turns = randint(20, 50) player.poisoned = True if frozen: enemy_turn_results.append({ 'message': Message('you stop being able to move!', libtcod.light_blue) }) frozen_turns = randint(2, 5) player.frozen = True 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) elif dead_entity == pet: pet = 0 message = kill_pet(dead_entity) elif dead_entity == boss: game_state = GameStates.WINNING message = kill_boss(dead_entity) else: message = kill_monster(dead_entity, pet, game_map) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: turns += 1 game_state = GameStates.PLAYERS_TURN
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(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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 libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') aim_weapon = action.get('aim_weapon') 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') show_character_screen = action.get('show_character_screen') exit = action.get('exit') level_up = action.get('level_up') fullscreen = action.get('fullscreen') exit_menu = action.get('exit_menu') 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 dx == 0 and dy == 0: player.move(dx, dy) fov_recompute = True elif target: # ATTACK! if player.equipment.power_bonus == 4: attack_results = player.fighter.basic_bow_attack( target) player_turn_results.extend(attack_results) else: 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 aim_weapon and game_state == GameStates.PLAYERS_TURN: # ALSO ATTACK! Working on this at the moment if player.equipment.power_bonus == 4 and game_state == GameStates.PLAYERS_TURN: message_log.add_message( Message( 'Left click a tile to fire at it or right click to cancel!', libtcod.yellow)) game_state = GameStates.AIMING else: message_log.add_message( Message('You do not have a ranged weapon equipped!', libtcod.yellow)) 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 game_state == GameStates.AIMING: if left_click: target_x, target_y = left_click coordinates = target_x, target_y # OKAY NOW WHAT THE F**K I DONT UNDESTAND WHY THIS WORKS OR HOW THE # VARIABLES GET FROM HERE TO THE FUNCTION I NEED THEM I MEAN JESUS CHRIST I JUST WOUND UP WITH THIS # ARRANGEMENT BY F*****G AROUND I MEAN IT WORKS BUT SERIOUSLY I DONT UNDERSTAND WHY THIS WORKS player_turn_results.append({'fire_weapon': True}) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit_menu: 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}) if exit: 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') fire_weapon = player_turn_result.get('fire_weapon') 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 fire_weapon: destination_x, destination_y = coordinates target = get_blocking_entities_at_location( entities, destination_x, destination_y) try: if target == player: message_log.add_message( Message( 'No hitting yourself. Targeting cancelled.', libtcod.yellow)) game_state = previous_game_state elif target.ai and libtcod.map_is_in_fov( fov_map, target.x, target.y): attack_results = player.fighter.basic_bow_attack( target) player_turn_results.extend(attack_results) game_state = GameStates.ENEMY_TURN elif target.ai and not libtcod.map_is_in_fov( fov_map, target.x, target.y): message_log.add_message( Message( 'That cannot be targeted. Targeting cancelled.', libtcod.yellow)) game_state = previous_game_state except: message_log.add_message( Message( 'That cannot be targeted. Targeting cancelled.', libtcod.yellow)) game_state = previous_game_state 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 config.win == True: game_state = GameStates.PLAYER_DEAD if game_state == GameStates.PLAYER_DEAD: break 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: message_log.add_message( Message( 'Your battle skills grow stronger! You reached level {0}' .format(player.level.current_level) + '!', libtcod.yellow)) 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
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(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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 libtcod.console_flush() clear_all(con, entities) 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.max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.power += 1 elif level_up == 'def': player.fighter.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') 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 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: message_log.add_message(Message( 'Your battle skills grow stronger! You reached level {0}'.format( player.level.current_level) + '!', libtcod.yellow)) 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
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(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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 libtcod.console_flush() clear_all(con, entities) 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
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): ''' Main engine and executor of code ''' 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 game_map.dungeon_level == 51: end_game(player) libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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 libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) # checks for actions 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') show_rules_screen = action.get('show_rules_screen') shop = action.get('shop') shop_sell = action.get('shop_sell') shop_buy = action.get('shop_buy') sell_index = action.get('sell_index') buy_index = action.get('buy_index') 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 = [] # player moving 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 # player waiting elif wait: game_state = GameStates.ENEMY_TURN # player tries to pick up item 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)) # player shows inventory menu if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY # player shows inventory menu if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY # player selects object from 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)) # player tries to take stairs 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)) # player levels up 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 # player opens character screen if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN # player opens rules screen if show_rules_screen: previous_game_state = game_state game_state = GameStates.RULES # player tries to target 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}) # player tries to enter shop if shop and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.shopkeep and entity.x == player.x and entity.y == player.y: previous_game_state = game_state game_state = GameStates.ENTER_SHOP break else: message_log.add_message(Message('There is no shopkeeper here.', libtcod.yellow)) # player tries to sell if shop_sell: game_state = GameStates.SELLING # player tries to sell item at shop if sell_index is not None and previous_game_state != GameStates.PLAYER_DEAD and\ game_state == GameStates.SELLING and sell_index < len(player.inventory.items): for entity in entities: if entity.shopkeep: item_cost = player.inventory.items[sell_index].cashable.coin player.fighter.coin += (item_cost // 10) message_log.add_message(Message('You sell {0}for {1} coins.'\ .format(player.inventory.items[sell_index].name.split('(')[0], (item_cost // 10)), libtcod.blue)) player.inventory.remove_item(player.inventory.items[sell_index]) break # player tries to buy if shop_buy: game_state = GameStates.BUYING # player tries to buy item at shop if buy_index is not None and previous_game_state != GameStates.PLAYER_DEAD and\ game_state == GameStates.BUYING and buy_index < 25: for entity in entities: if entity.shopkeep: player_coin = player.fighter.coin item_cost = entity.inventory.items[buy_index].cashable.coin if player_coin >= item_cost: player.inventory.add_item(entity.inventory.items[buy_index]) player.fighter.coin -= item_cost message_log.add_message(Message('You buy {0}for {1} coins.'\ .format(entity.inventory.items[buy_index].name.split('(')[0], item_cost), libtcod.blue)) else: message_log.add_message(Message('Not enough coins!', libtcod.yellow)) break # exit menu or game if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.RULES): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) elif game_state == GameStates.ENTER_SHOP: game_state = GameStates.PLAYERS_TURN elif game_state in (GameStates.SELLING, GameStates.BUYING): game_state = GameStates.ENTER_SHOP else: save_game(player, entities, game_map, message_log, game_state) return True # toggle fullscreen if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # player turn results 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') coin = player_turn_result.get('coin') # adds message to log if message: message_log.add_message(message) # deals with dead entity 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) # item picked up if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN # item used if item_consumed: game_state = GameStates.ENEMY_TURN # item dropped if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN # item equip toggled 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.split('(')[0]))) if dequipped: message_log.add_message(Message('You dequipped the {0}'\ .format(dequipped.name.split('(')[0]))) game_state = GameStates.ENEMY_TURN # something targeted if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) # targeting cancelled if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) # gained xp if xp: leveled_up = player.level.add_xp(xp) message_log.add_message(Message('You gain {0} experience points.'\ .format(xp), libtcod.orange)) if leveled_up: message_log.add_message(Message( 'Your battle skills grow stronger! You reached level {0}'\ .format(player.level.current_level) + '!', libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP # gained coins if coin: player.fighter.add_coin(coin) message_log.add_message(Message('You gain {0} coins.'\ .format(coin), libtcod.orange)) # enemy takes turn 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') # adds message to log if message: message_log.add_message(message) # checks for dead entity 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 player is dead, we're done if game_state == GameStates.PLAYER_DEAD: break # if player is dead, we're done if game_state == GameStates.PLAYER_DEAD: break # player's turn again else: game_state = GameStates.PLAYERS_TURN
def play_game(player, entities, game_map, message_log, game_state, root_console, con, panel, constants): tdl.set_font('arial10x10.png', greyscale=True, altLayout=True) fov_recompute = True mouse_coordinates = (0, 0) previous_game_state = game_state targeting_item = None while not tdl.event.is_window_closed(): if fov_recompute: game_map.compute_fov(player.x, player.y, fov=constants['fov_algorithm'], radius=constants['fov_radius'], light_walls=constants['fov_light_walls']) render_all(con, panel, entities, player, game_map, fov_recompute, root_console, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], mouse_coordinates, constants['colors'], game_state) tdl.flush() clear_all(con, entities) fov_recompute = False for event in tdl.event.get(): if event.type == 'KEYDOWN': user_input = event break elif event.type == 'MOUSEMOTION': mouse_coordinates = event.cell elif event.type == 'MOUSEDOWN': user_mouse_input = event break else: user_input = None user_mouse_input = None if not (user_input or user_mouse_input): continue action = handle_keys(user_input, game_state) mouse_action = handle_mouse(user_mouse_input) 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 game_map.walkable[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, constants['colors']) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message('There is nothing here to pick up.', constants['colors'].get('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, constants['colors'], entities=entities, game_map=game_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend( player.inventory.drop_item(item, constants['colors'])) 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: game_map, entities = next_floor(player, message_log, entity.stairs.floor, constants) fov_recompute = True con.clear() break else: message_log.add_message( Message('There are no stairs here.', constants['colors'].get('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, constants['colors'], entities=entities, game_map=game_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: tdl.set_fullscreen(not tdl.get_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, constants['colors']) else: message = kill_monster(dead_entity, constants['colors']) 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(f'You equipped the {equipped.name}')) if dequipped: message_log.add_message( Message(f'You dequipped the {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: message_log.add_message( Message( 'Your battle skills grow stronger! You reached level {0}' .format(player.level.current_level) + '!', constants['colors'].get('yellow'))) 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, 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, constants['colors']) else: message = kill_monster(dead_entity, constants['colors']) 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
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 wait_timer = 0 while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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 libtcod.console_flush() clear_all(con, entities) 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_trail = action.get('take_trail') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') checkpoint = action.get('checkpoint') 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 player.fighter.max_hp < player.fighter.hp: player.fighter.hp = player.fighter.max_hp if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if wait_timer > 0: if randint(0, 7) == 7: wait_timer = wait_timer - 5 passive_regen = randint(0, 20) if passive_regen == 20 and player.fighter.hp < player.fighter.max_hp: if player.fighter.hp >= player.fighter.max_hp - round( (player.fighter.max_hp / 150)): player.fighter.hp = player.fighter.max_hp message_log.add_message( Message('Your wounds are completely healed!', libtcod.green)) else: player.fighter.hp = player.fighter.hp + round( (player.fighter.max_hp / 150)) 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: if wait_timer <= 55: wait_timer = wait_timer + 5 if player.fighter.hp < player.fighter.max_hp: if player.fighter.hp >= player.fighter.max_hp - round( (player.fighter.max_hp / 50)): player.fighter.hp = player.fighter.max_hp message_log.add_message( Message( 'You rest for a moment. Your wounds are completely healed!', libtcod.green)) game_state = GameStates.ENEMY_TURN else: player.fighter.hp = player.fighter.hp + round( (player.fighter.max_hp / 50)) message_log.add_message( Message( 'You rest for a moment. Your wounds are beginning to feel slightly better.', libtcod.green)) game_state = GameStates.ENEMY_TURN else: message_log.add_message( Message('You rest for a moment.', libtcod.yellow)) game_state = GameStates.ENEMY_TURN elif wait_timer >= 56: if player.fighter.hp >= 501: player.fighter.hp = player.fighter.hp - 500 message_log.add_message( Message( 'You begin to rest, but the Dropbear drops down on your back and begins feasting on your flesh!', libtcod.dark_red)) game_state = GameStates.ENEMY_TURN elif player.fighter.hp <= 500: player.fighter.hp = player.fighter.hp - 500 message_log.add_message( Message( 'You begin to rest, but the Dropbear drops down on your back and feasts on your flesh!', libtcod.dark_red)) player.char = 180 player.color = libtcod.dark_red if not os.path.isfile('savegame.dat'): pass else: os.remove('savegame.dat') message_log.add_message(Message('You died!', libtcod.red)) game_state = GameStates.PLAYER_DEAD 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)) game_state = GameStates.ENEMY_TURN elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if take_trail and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.trail 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 con.clear() break else: message_log.add_message( Message('There is no trail here.', libtcod.yellow)) if level_up: if player.fighter.hp <= player.fighter.max_hp - round( (player.fighter.max_hp / 7)): player.fighter.hp = player.fighter.hp + round( (player.fighter.max_hp / 7)) else: player.fighter.hp = player.fighter.max_hp if level_up == 'hp': player.fighter.base_max_hp += 250 player.fighter.hp += 250 elif level_up == 'str': player.fighter.base_power += 12 elif level_up == 'def': player.fighter.base_defense += 12 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 checkpoint: save_game(player, entities, game_map, message_log, game_state) message_log.add_message( Message('Your game has been saved.', libtcod.green)) 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, gamestate = 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 unequipped 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: message_log.add_message( Message( 'Your battle skills grow stronger! Welcome to level {0}' .format(player.level.current_level) + '!', libtcod.yellow)) 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
def play_game(player, entities, game_map, message_log, game_state, con, message_panel, char_info_panel, area_info_panel, under_mouse_panel, constants, floor_index, original_entity_index, entity_index, fov_index): 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 mouse_x = mouse.cx old_mouse_x = mouse_x mouse_y = mouse.cy old_mouse_y = mouse_y #attack_animation_x = 0 #attack_animation_y = 0 clean_map = False #attacked = False #animation_time = 200 #animation_distance = 0 targeting_item = None equipment_choice = 0 npc = None item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) """ if animation_time == 0: if attacked: animation_distance += 1 animation_time = 200 if animation_distance == 5: animation_distance = 0 attacked = False """ if clean_map == True: fov_recompute = True clean_map = False if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, message_panel, char_info_panel, area_info_panel, under_mouse_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['tiles'], constants['colors'], game_state, npc, targeting_item, item, equipment_choice) fov_recompute = False libtcod.console_flush() clear_all(con, entities, fov_map, game_map) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) ############################################ if game_state == GameStates.EQUIPMENT_SCREEN and not action.get( 'exit'): for equipment in action: if equipment: equipment_choice = equipment break ############################################ move = action.get('move') ranged_attack = action.get('ranged_attack') interact = action.get('interact') inspect_item = action.get('inspect_item') 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') show_equipment_screen = action.get('show_equipment_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 and not target.invulnerable: attack_results = player.combat_class.attack(target) player_turn_results.extend(attack_results) clean_map = True elif not target: player.move(dx, dy) if player.combat_class.turns_until_rest == 0: pass else: player.combat_class.turns_until_rest -= 1 fov_recompute = True game_state = GameStates.ENEMY_TURN elif move and game_state == GameStates.INTERACT: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): blocking_target = get_blocking_entities_at_location( entities, destination_x, destination_y) non_blocking_target = get_non_blocking_entities_at_location( entities, destination_x, destination_y) if blocking_target: try: if blocking_target.dialogue.dialogue: npc = blocking_target except (AttributeError): pass if blocking_target.bonfire is not None: message_log.add_message( Message( 'You see a mysterious bonfire. You cannot resist touching it', libtcod.light_violet)) entity_index = blocking_target.bonfire.reset_entities( game_map, original_entity_index, entity_index) game_state = GameStates.PLAYERS_TURN else: message_log.add_message( Message('You see {0}'.format(blocking_target.name), libtcod.white)) elif non_blocking_target: message_log.add_message( Message('You see {0}'.format(non_blocking_target.name), libtcod.white)) else: message_log.add_message( Message('There is nothing to inspect here.', libtcod.white)) elif wait: if player.combat_class.turns_until_rest == 0: pass else: player.combat_class.turns_until_rest -= 1 message = player.combat_class.rest() message_log.add_message(Message(message, libtcod.green)) 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.white)) 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 interact: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.INTERACT message_log.add_message(Message('You begin to look around.')) if ranged_attack: if player.equipment.main_hand.equippable.ranged: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING message_log.add_message(Message('Choose a target to attack.')) else: message_log.add_message( Message('This weapon cannot attack at range.')) 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)) elif game_state == GameStates.CHOOSE_ITEM_TO_INSPECT: previous_game_state = GameStates.CHOOSE_ITEM_TO_INSPECT game_state = GameStates.INSPECT_ITEM message_log.add_message( Message('You inspect the {0}.'.format(item.name))) 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: if entity.name == 'Stairs Down': if len(floor_index) == game_map.dungeon_level: entities = game_map.new_floor( player, message_log, constants) fov_map = initialize_fov(game_map) floor_index.append(game_map.tiles) entity_index.append(entities) original_entity_index.append(entities) fov_index.append(fov_map) fov_recompute = True libtcod.console_clear(con) break elif len(floor_index) > game_map.dungeon_level: # Update the entity index with the floors NEW entity list entity_index[game_map.dungeon_level - 1] = entities entities, player, fov_map = game_map.next_floor( player, entity_index, floor_index, fov_index, message_log, constants) fov_recompute = True libtcod.console_clear(con) break elif entity.name == 'Stairs Up': entity_index[game_map.dungeon_level - 1] = entities entities, player, fov_map = game_map.previous_floor( player, entity_index, floor_index, fov_index, message_log, constants) 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 == 'str': player.combat_class.base_strength += 1 elif level_up == 'dex': player.combat_class.base_dexterity += 1 elif level_up == 'sta': player.combat_class.base_stamina += 1 elif level_up == 'int': player.combat_class.base_intelligence += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_equipment_screen: previous_game_state = game_state game_state = GameStates.EQUIPMENT_SCREEN if game_state == GameStates.TARGETING: mouse_x = mouse.cx mouse_y = mouse.cy if (old_mouse_y != mouse_y or old_mouse_x != mouse_x) and libtcod.map_is_in_fov( fov_map, mouse_x, mouse_y): fov_recompute = True elif libtcod.map_is_in_fov( fov_map, old_mouse_x, old_mouse_y) and not libtcod.map_is_in_fov( fov_map, mouse_x, mouse_y): clean_map = True old_mouse_x = mouse_x old_mouse_y = mouse_y if left_click and targeting_item != None: 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) fov_recompute = True elif right_click: player_turn_results.append({'targeting_cancelled': True}) fov_recompute = True elif left_click and targeting_item == None: target_x, target_y = left_click if not game_map.tiles[target_x][target_y].blocked: target = get_blocking_entities_at_location( entities, target_x, target_y) else: message_log.add_message( Message('You can\'t attack that.', libtcod.yellow)) if target and not target.invulnerable: attack_results = player.combat_class.attack(target) player_turn_results.extend(attack_results) fov_recompute = True game_state = GameStates.ENEMY_TURN if game_state == GameStates.SHOW_INVENTORY: if inspect_item: previous_game_state = game_state game_state = GameStates.CHOOSE_ITEM_TO_INSPECT message_log.add_message( Message('Choose an item to inspect.', libtcod.yellow)) if game_state == GameStates.EQUIPMENT_SCREEN: if equipment_choice: previous_game_state = game_state game_state = GameStates.EQUIPMENT_DETAILS if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.INTERACT): if game_state == (GameStates.INTERACT): player_turn_results.append({'interacting_cancelled': True}) game_state = previous_game_state npc = None else: game_state = previous_game_state elif game_state == GameStates.CHOOSE_ITEM_TO_INSPECT: game_state = GameStates.SHOW_INVENTORY previous_game_state = GameStates.PLAYERS_TURN message_log.add_message( Message('Item inspection cancelled.', libtcod.yellow)) elif game_state == GameStates.INSPECT_ITEM: game_state = previous_game_state elif game_state == GameStates.EQUIPMENT_SCREEN: game_state = GameStates.PLAYERS_TURN elif game_state == GameStates.EQUIPMENT_DETAILS: game_state = previous_game_state equipment_choice = False elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) game_state = previous_game_state fov_recompute = True else: libtcod.console_clear(0) save_game(player, entities, game_map, message_log, game_state, floor_index, original_entity_index, entity_index, fov_index) 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') interacting_cancelled = player_turn_result.get( 'interacting_cancelled') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: dead_entity.alive = False 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 equip: equip_results = player.equipment.toggle_equip(equip) for equip_result in equip_results: equipped = equip_result.get('equipped') unequipped = equip_result.get('unequipped') if equipped: message_log.add_message( Message('You equipped the {0}.'.format( equipped.name))) if unequipped: message_log.add_message( Message('You unequipped the {0}.'.format( unequipped.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 interacting_cancelled: game_state = previous_game_state message_log.add_message(Message('You stop looking around.')) if xp: leveled_up = player.level.add_xp(xp) message_log.add_message( Message('You gain {0} experience points.'.format(xp), libtcod.lighter_yellow)) if leveled_up: message_log.add_message( Message( 'Your skills grow more honed. You reach level {0}'. format(player.level.current_level) + "!", libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: if wait: enemy_turn_results = entity.ai.approach_player_on_wait( player, fov_map, game_map, entities) else: 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
def play_game(player, entities, game_map, message_log, game_state, con, panel, cursor, constants): colors = constants['colors'] fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYER_TURN previous_game_state = game_state # Keep track of targeting item targeting_item = None # === MAIN GAME LOOP === while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) 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, cursor, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_width'], constants['panel_x'], mouse, constants['colors'], game_state, targeting_item, key) fov_recompute = False libtcod.console_flush() clear_all(con, entities) # === PLAYER TURN === # Handle player action 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') show_equipment = action.get('show_equipment') 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 = [] # Check what player did this turn if move and game_state == GameStates.PLAYER_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy # Check if tile is passable 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.take_step(dx, dy, game_map) # Recompute FOV everytime the player moves fov_recompute = True game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYER_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.', colors['text_warning'])) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if show_equipment: previous_game_state = game_state game_state = GameStates.SHOW_EQUIPMENT 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.SHOW_EQUIPMENT: item = player.equipment.equipped[inventory_index] 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.PLAYER_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) libtcod.console_clear(con) break else: message_log.add_message( Message('There are no stairs here.', colors['text_warning'])) 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 select_target: # current_x, current_y = player.x, player.y # dx, dy = select_target # new_x, new_y = current_x + dx, current_y + dy 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.SHOW_EQUIPMENT, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN }: game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) elif game_state == GameStates.PLAYER_DEAD: # Delete save file if player exits after dying if os.path.isfile('savegame.dat'): os.remove('savegame.dat') return 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()) # toggle on/off # At the end of the player's turn, evaluate results and print messages to log 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 targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) 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: # Remove item from map (now in inventory) entities.remove(item_added) # Takes a turn game_state = GameStates.ENEMY_TURN if item_consumed: 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), colors['text_equip'])) if dequipped: message_log.add_message( Message( 'You dequipped the {0}'.format(dequipped.name), colors['text_unequip'])) game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYER_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if xp: leveled_up = player.level.add_xp(xp) message_log.add_message( Message('You gain {0} experience'.format(xp))) if leveled_up: message_log.add_message( Message( 'Your battle skills grow stronger! You reached level {0}!' .format(player.level.current_level), libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP # === MONSTER TURN === 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.PLAYER_TURN