def evaluate_dead_entity(self, dead_entity): if not dead_entity: return if dead_entity == self.player: message, self.game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) self.message_log.add_message(message)
def process_turn(player, enemy_turn_results, message_log): 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
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 main(): screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 max_items_per_room = 2 colors = { 'dark_wall' : libtcod.Color(0, 0, 100), 'dark_ground' : libtcod.Color(50, 50, 150), 'light_wall' : libtcod.Color(130, 110, 50), 'light_ground' : libtcod.Color(200, 180, 50) } fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False) con = libtcod.console_new(screen_width, screen_height) panel = libtcod.console_new(screen_width, panel_height) game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room) fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state 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, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors, game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) 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') 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 to pickup here.', 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)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state else: 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') 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 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 main(): screen_width = 80 screen_height = 50 cardtable_width = 18 cardtable_height = screen_height cardtable_x = screen_width - cardtable_width panel_height = 10 panel_y = screen_height - panel_height panel_width = screen_width - cardtable_width map_width = screen_width - cardtable_width map_height = screen_height - panel_height message_x = 2 message_width = panel_width - 2 message_height = panel_height - 1 message_log = MessageLog(message_x, message_width, message_height) panel = tcod.console.Console(panel_width, panel_height) mapcon = tcod.console.Console(map_width, map_height) cardtable = tcod.console.Console(cardtable_width, cardtable_height) # number of dice, sideness of dice. values used taken from gunslinger pregen, pg88 player_charactersheet = Character() print(player_charactersheet) player = Entity(int(screen_width / 2), int(screen_height / 2), '@', tcod.white, 'Player', True, RenderOrder.ACTOR, Fighter(6)) entities = [player] game_map = tcod.map.Map(map_width, map_height) generate_map(game_map, player, entities) fov_recompute = True fate_pot = Counter({'white': 50, 'red': 25, 'blue':10}) player_fate = Counter() player_fate.update(sample(list(fate_pot.elements()), 3)) fate_pot.subtract(player_fate) # FIXME: Currently, this does not include Jokers, which are required # for decks used in Deadlands. The class can be instantiated to # use jokers, but its use of jokers does not differentiate between # red and black jokers (as required in Deadlands) so the issue of # jokers is left to another day. # Also probably the suit hierarchy is not the same as Deadlands; that should be easy # to fix when I get to it. marshal_deck = pydealer.Deck() posse_deck = pydealer.Deck() marshal_deck.shuffle() posse_deck.shuffle() player_hand = pydealer.Stack() # pydealer.Stack() marshal_hand = pydealer.Stack() player_hand.sort() posse_discard = pydealer.Stack() marshal_discard = pydealer.Stack() tcod.console_set_custom_font('cp437_10x10.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_CP437) root_console = tcod.console_init_root(screen_width, screen_height, 'Deadlands Duel', False, tcod.RENDERER_SDL2, vsync=True) player_round_movement_budget = player_charactersheet.get_movement_budget() move_this_action = 0 active_card = pydealer.Stack() # posse_deck.deal(1) colt_army = {'shots': 6, 'max_shots': 6, 'range': 10, 'damage': {'number_of_dice': 3, 'sideness_of_dice': 6}} game_state = GameStates.PLAYERS_TURN # FIXME: There's probably an elegant solution to be found in generalizing this # list to include the player, and sorting it by action cards, or something. enemy_combatants = [] while True: if fov_recompute: game_map.compute_fov(player.x, player.y, algorithm=tcod.FOV_PERMISSIVE(5)) if game_state ==GameStates.PLAYERS_TURN: for entity in entities: if entity.name == 'Bandit' and game_map.fov[entity.y, entity.x]: game_state = GameStates.BEGIN_DETAILED_COMBAT_ROUND break if game_state ==GameStates.ROUNDS_PLAYERS_ACTION: enemies_in_view = False for entity in entities: if entity.name == 'Bandit' and game_map.fov[entity.y, entity.x]: enemies_in_view = True if enemies_in_view == False: message_log.add_message(Message("All visible bandits dead, leaving combat rounds...")) posse_discard.add(active_card.deal(active_card.size)) posse_discard.add(player_hand.deal(player_hand.size)) game_state =GameStates.PLAYERS_TURN enemy_combatants = [] if game_state == GameStates.ENEMY_TURN: for entity in entities: if (entity.name == 'Bandit') and (not game_map.fov[entity.y, entity.x]): if entity.fighter.shots < 6: # When the player ducks behind a wall to reload their revolver, # the bandits also take advantage of the opportunity! entity.fighter.shots += 1 game_state = GameStates.PLAYERS_TURN if game_state == GameStates.BEGIN_DETAILED_COMBAT_ROUND: # Let the player know what's going on message_log.add_message(Message("Beginning of combat round!")) # Deal the player a hand from the posse deck and calc their movement player_round_movement_budget = player_charactersheet.get_movement_budget() roll_new_round(player_hand, player_charactersheet, posse_deck, posse_discard, message_log) # We *should* deal the enemies an action hand, and calc their movement. # FIXME: Currently, we use the ultra-simple shortcut for enemies # from the Marshal Tricks section of the rules, dealing them a single card. # This combat really isn't on a scale where that is justified, at least not until # more enemies are clued in to the combat via sound or a vague awareness metric. # Also, enemy movement is not yet implemented, so we don't calc their move rate. for entity in entities: if entity.name == 'Bandit' and game_map.fov[entity.y, entity.x]: entity.fighter.action_hand = marshal_deck.deal(1) enemy_combatants.append(entity) game_state = GameStates.MEDIATE_COMBAT_ROUNDS if game_state == GameStates.MEDIATE_COMBAT_ROUNDS: # FIXME: Should we keep track of a list of combat activated enemies? # As a quick hack, right now it's just FOV. # (calculated in BEGIN_DETAILED_COMBAT_ROUNDS conditional above) remaining_enemy_cards = False for combatant in enemy_combatants: if combatant.fighter.action_hand.size > 0: # print(combatant.fighter.action_hand.size) remaining_enemy_cards = True if remaining_enemy_cards or (player_hand.size > 0): # and (active_card.size > 0)): highest_player = None if player_hand.size > 0: highest_player = player_hand[player_hand.size - 1] # print("highest player card " + str(highest_player)) highest_combatant = None highest_comb_card = None if remaining_enemy_cards: for combatant in enemy_combatants: print("combatant card: " + str(combatant.fighter.action_hand[combatant.fighter.action_hand.size - 1])) if highest_comb_card == None: highest_combatant = combatant highest_comb_card = combatant.fighter.action_hand[combatant.fighter.action_hand.size - 1] elif combatant.fighter.action_hand[combatant.fighter.action_hand.size - 1] > highest_comb_card: highest_combatant = combatant highest_comb_card = combatant.fighter.action_hand[combatant.fighter.action_hand.size - 1] # print("highest combatant card " + str(highest_comb_card)) if remaining_enemy_cards and ((highest_combatant) and ((highest_player == None)) or (highest_comb_card > highest_player)): # Enemy turn, in combat rounds. Placeholder. message_log.add_message(Message("The " + highest_combatant.name + " acts on a " + str(highest_comb_card) + "!", tcod.orange)) if highest_combatant.fighter.shots > 0: tn = 5 modifier = 0 - highest_combatant.fighter.get_most_severe_wound()[1] range_increments = (highest_combatant.distance_to(player) / 3) // colt_army['range'] tn += range_increments shootin_roll = skill_roll(2, 8, tn, modifier) success = shootin_roll.get('success') if success: vital_hit = False body_part = None hitlocation = unexploding_roll(20) if (hitlocation == 20): vital_hit = True body_part = 'head' elif 15 <= hitlocation <= 19: body_part = 'guts' #upper elif 11 <= hitlocation <= 14: body_part = '_arm' if unexploding_roll(2) == 1: body_part = 'left' + body_part else: body_part = 'right' + body_part elif hitlocation == 10: vital_hit = True body_part = 'guts' #gizzards elif 5 <= hitlocation <= 9: body_part = 'guts' #lower else: body_part = '_leg' if unexploding_roll(2) == 1: body_part = 'left' + body_part else: body_part = 'right' + body_part message_log.add_message(Message("The bandit takes aim and shoots, hitting you in the " + body_part + "!", tcod.red)) dmg = ranged_weapon_damage_roll(colt_army['damage']['sideness_of_dice'], colt_army['damage']['number_of_dice'], vital_bonus = vital_hit) message_log.add_message(player.fighter.take_positional_damage(dmg, body_part, fate_pot, player_fate)) if (player.fighter.body_wounds['guts'] >= 5) or (player.fighter.body_wounds['head'] >= 5): message_log.add_message(kill_monster(player)) game_state = GameStates.PLAYER_DEAD else: message_log.add_message(Message("The bandit takes aim and shoots! The bullet whizzes past you!", tcod.orange)) highest_combatant.fighter.shots -= 1 else: message_log.add_message(Message("The bandit loads his revolver...")) highest_combatant.fighter.shots += 1 marshal_discard.add(highest_combatant.fighter.action_hand.deal(1)) enemy_combatants.remove(highest_combatant) else: # FIXME: This erroneously includes tied situations, which the rules say # should result in simultaneous actions. # Player's turn, in combat rounds. game_state = GameStates.ROUNDS_PLAYERS_ACTION else: game_state = GameStates.BEGIN_DETAILED_COMBAT_ROUND if game_state == GameStates.ROUNDS_ENEMY_ACTION: print("Shouldn't be possible???") render_all(root_console, entities, mapcon, game_map, cardtable, cardtable_x, player_hand, active_card, player_fate, panel, panel_y, message_log, player.fighter.body_wounds) tcod.console_flush() action = handle_events() move = action.get('move') activate_card = action.get('activate_card') shoot = action.get('shoot') pass_turn = action.get('pass_turn') reload = action.get('reload') if move and (game_state == GameStates.PLAYERS_TURN): dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if (0 <= destination_x < game_map.width) and (0 <= destination_y < game_map.height): if game_map.walkable[destination_y, destination_x]: target = get_blocking_entities_at_location(entities, destination_x, destination_y) if target: message_log.add_message(Message('You kick the ' + target.name + ' in the shins, much to its annoyance!')) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN if pass_turn and (game_state == GameStates.ROUNDS_PLAYERS_ACTION): # pass action would be more accurate, for how i have modified this since creating it # if active_card.size == 0: # posse_discard.add(player_hand.deal(player_hand.size)) # # player_round_movement_budget = player_charactersheet.get_movement_budget() # roll_new_round(player_hand, player_charactersheet, posse_deck, posse_discard, message_log) #elif if active_card.size > 0: posse_discard.add(active_card.deal(active_card.size)) game_state = GameStates.MEDIATE_COMBAT_ROUNDS # The following should be covered by the MEDIATE_COMBAT_ROUNDS # if player_hand.size == 0: # posse_discard.add(player_hand.deal(player_hand.size)) # # player_round_movement_budget = player_charactersheet.get_movement_budget() # roll_new_round(player_hand, player_charactersheet, posse_deck, posse_discard, message_log) if activate_card and (active_card.size == 0) and (game_state == GameStates.ROUNDS_PLAYERS_ACTION): #nominate new active card. (test-only terminiology) if activate_card == -1: move_this_action = 0 if player_hand.size > 0: active_card.add(player_hand.deal(1, 'top')) # player_hand.sort() if reload and ((game_state == GameStates.ROUNDS_PLAYERS_ACTION) or (game_state ==GameStates.PLAYERS_TURN)): if colt_army['shots'] == colt_army['max_shots']: message_log.add_message(Message("Your revolver is fully loaded.", tcod.blue)) elif (game_state ==GameStates.PLAYERS_TURN) or ((game_state == GameStates.ROUNDS_PLAYERS_ACTION) and (active_card.size > 0)): colt_army['shots'] += 1 message_log.add_message(Message("You load a bullet into your revolver.", tcod.green)) if (game_state ==GameStates.ROUNDS_PLAYERS_ACTION): posse_discard.add(active_card.deal(active_card.size)) game_state = GameStates.MEDIATE_COMBAT_ROUNDS # if player_hand.size == 0: # player_round_movement_budget = player_charactersheet.get_movement_budget() # roll_new_round(player_hand, player_charactersheet, posse_deck, posse_discard, message_log) if shoot and (game_state == GameStates.ROUNDS_PLAYERS_ACTION): if (active_card.size > 0) and (colt_army['shots'] == 0): message_log.add_message(Message("You need to reload!", tcod.red)) elif (active_card.size > 0) and (colt_army['shots'] > 0): # Shoot is currently the only "real" action that uses up the active card. modifier = 0 if move_this_action > ((player_charactersheet.pace * 3) // 5): message_log.add_message(Message("You attempt to draw a bead while running...", tcod.orange)) modifier = -4 elif move_this_action > 0: message_log.add_message(Message("You fire while walking...", tcod.yellow)) modifier = -2 wound_modifier = 0 - player.fighter.get_most_severe_wound()[1] modifier += wound_modifier nearest_target = None nearest_distance = 999 for entity in entities: if game_map.fov[entity.y, entity.x]: if entity.fighter: if not entity.name is 'Player': new_distance = entity.distance_to(player) if new_distance < nearest_distance: nearest_distance = new_distance nearest_target = entity tn = 5 range_increments = (nearest_distance / 3) // colt_army['range'] tn += range_increments shootin_roll = skill_roll(player_charactersheet.shootin_pistol['trait'], player_charactersheet.shootin_pistol['aptitude'], tn, modifier) bust = shootin_roll.get('bust') failure = shootin_roll.get('failure') success = shootin_roll.get('success') message_log.add_message(Message("BANG!!", tcod.brass)) colt_army['shots'] -= 1 if colt_army['shots'] == 0: message_log.add_message(Message("That was your last loaded bullet!", tcod.red)) if bust: message_log.add_message(Message("You went bust, and narrowly avoided shooting your own foot!", tcod.red)) else: if not nearest_target: if failure: message_log.add_message(Message("You shoot the broad side of a barn!")) elif success: if success == 1: message_log.add_message(Message("You shoot some bottles for target practice!", tcod.green)) else: message_log.add_message(Message("You put a bullet hole in the forehead of a Wanted poster!", tcod.blue)) else: if failure: message_log.add_message(Message("The bullet whizzes past your target!")) elif success: vital_hit = False hitlocation = unexploding_roll(20) if (hitlocation == 20) or (hitlocation == 10): vital_hit = True if success == 1: message_log.add_message(Message("You manage to hit your target!", tcod.green)) else: if ((20 - hitlocation) <= success) or (0 < (10 - hitlocation) <= success) or (0 < (hitlocation - 10) <= success): vital_hit = True message_log.add_message(Message("You accurately shoot your target!", tcod.blue)) dmg = ranged_weapon_damage_roll(colt_army['damage']['sideness_of_dice'], colt_army['damage']['number_of_dice'], vital_bonus = vital_hit) message_log.add_message(nearest_target.fighter.take_simple_damage(dmg)) if nearest_target.fighter.get_most_severe_wound()[1] >= 5: message_log.add_message(kill_monster(nearest_target)) marshal_discard.add(nearest_target.fighter.action_hand.deal(nearest_target.fighter.action_hand.size)) posse_discard.add(active_card.deal(1)) game_state = GameStates.MEDIATE_COMBAT_ROUNDS # if player_hand.size == 0: # player_round_movement_budget = player_charactersheet.get_movement_budget() # roll_new_round(player_hand, player_charactersheet, posse_deck, posse_discard, message_log) # FIXME: As currently written, this lets you move both before and after an action card. # First, the game lets you move a partial movement, # then, you can use your single card to initate a "new" action and reset the # tracking of movements per action, # which lets you evade potential running penalties in some situations (penalty not implemented yet) if (move and (player_round_movement_budget > 0) and (active_card.size > 0) and (game_state ==GameStates.ROUNDS_PLAYERS_ACTION)): dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if (0 <= destination_x < game_map.width) and (0 <= destination_y < game_map.height): if game_map.walkable[destination_y, destination_x]: target = get_blocking_entities_at_location(entities, destination_x, destination_y) if target: message_log.add_message(Message('You kick the ' + target.name + ' in the shins, much to its annoyance!')) else: player.move(dx, dy) player_round_movement_budget -= 1 # We track our movement taking place in this action card. # We can move up to twice our pace the whole round spread across all our actions. # We incur a running penalty on an action where we have also moved more than our pace; # ie, more than half our full movement budget # (which is calculated to a maximum with running in mind) move_this_action += 1 # pace in yards. yds->ft ft->squares if move_this_action > ((player_charactersheet.pace * 3) // 5): message_log.add_message(Message("Running!!!", tcod.orange)) else: message_log.add_message(Message("Walking...", tcod.yellow)) fov_recompute = True
def main(): screen_width = 80 screen_height = 50 map_width = 80 map_height = 45 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'dark_wall': libtcod.Color(0, 0, 100), 'dark_ground': libtcod.Color(50, 50, 150), 'light_wall': libtcod.Color(130, 110, 50), 'light_ground': libtcod.Color(200, 180, 50) } fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', libtcod.white, "Player", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False) con = libtcod.console_new(screen_width, screen_height) game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room) fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, entities, player, game_map, fov_map, fov_recompute, screen_width, screen_height, colors) libtcod.console_flush() clear_all(con, entities) action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') 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 if exit: 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') if message: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) print(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: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) print(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN
def main(): # map vars map_width = 40 map_height = 60 room_min_size = 6 room_max_size = 10 max_rooms = 50 max_monsters_per_room = 3 max_items_per_room = 2 # screen vars viewport_width = 80 viewport_height = 60 rerender_viewport = True map_x = viewport_width map_y = 0 screen_width = viewport_width + map_width # stats panel vars bar_width = 20 panel_width = screen_width panel_height = 8 panel_x = 0 panel_y = viewport_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 screen_height = viewport_height + panel_height # fov vars fov_algorithm = 12 fov_light_walls = True fov_radius = 10 fov_recompute = True # game vars game_state = GameStates.PLAYER_TURN previous_game_state = game_state colours = { 'dark_wall': tcod.Color(0, 0, 100), 'dark_ground': tcod.Color(50, 50, 150), 'light_wall': tcod.Color(130, 110, 50), 'light_ground': tcod.Color(200, 180, 50) } # init player fighter_component = Fighter(30, 2, 5) inventory_component = Inventory(26) player = Entity(0, 0, '@', tcod.white, 'Player', render_order=RenderOrder.ACTOR, blocks=True, fighter=fighter_component, inventory=inventory_component) player_rot = 0.0 entities = [player] # load assets wall_texture = Image.open('assets/wall_vines0.png') orc_texture = Image.open('assets/orc.png') troll_texture = Image.open('assets/troll.png') potion_texture = Image.open('assets/ruby.png') # init game map game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room, orc_texture, troll_texture, potion_texture) game_map.recompute_fov(player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # init message log message_log = MessageLog(message_x, message_width, message_height) tcod.console_set_custom_font( 'arial10x10.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) with tcod.console_init_root(screen_width, screen_height, 'firstpersonroguelike', vsync=True) as root_console: viewport_console = tcod.console.Console(viewport_width, viewport_height) map_console = tcod.console.Console(map_width, map_height) panel_console = tcod.console.Console(panel_width, panel_height) mouse = (0, 0) time_start = perf_counter() # game loop begin while True: for event in tcod.event.wait(): tcod.console_flush() player_turn_results = [] # handle inputs if event.type == "QUIT": raise SystemExit() elif event.type == "MOUSEMOTION": # record the new mouse position, render_all will take care of the rest mouse = event.tile # player keyboard interaction elif event.type == "KEYDOWN": action = handle_keys(event, game_state) if len(action) == 0: continue elif action.get('exit'): if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state else: raise SystemExit() elif action.get( 'pickup') and game_state is 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( 'You inspect the empty ground below you. Looks pretty dirty', tcod.yellow)) game_state = GameStates.ENEMIES_TURN elif action.get('show_inventory' ) and game_state is GameStates.PLAYER_TURN: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY elif action.get('drop_inventory' ) and game_state is GameStates.PLAYER_TURN: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY elif action.get( 'inventory_index' ) is not None and previous_game_state is not GameStates.PLAYER_DEAD: inventory_index = action.get('inventory_index') if inventory_index < len(player.inventory.items): item = player.inventory.items[inventory_index] if game_state is GameStates.SHOW_INVENTORY: message_log.add_message( Message('Used ' + item.name)) player_turn_results.extend( player.inventory.use_item(item)) elif game_state is GameStates.DROP_INVENTORY: message_log.add_message( Message('Dropped ' + item.name)) player_turn_results.extend( player.inventory.drop_item(item)) game_state = GameStates.ENEMIES_TURN elif action.get( 'move') and game_state is GameStates.PLAYER_TURN: dx, dy = action.get('move') to_x, to_y = player.x + dx, player.y + dy if game_map.walkable(to_x, to_y): target = get_blocking_entities_at_location( entities, to_x, to_y) if target: player_turn_results.extend( player.fighter.attack(target)) else: player.move(dx, dy) fov_recompute = True # end our turn game_state = GameStates.ENEMIES_TURN elif action.get( 'move2') and game_state is GameStates.PLAYER_TURN: to_x = player.x to_y = player.y if action.get('move2') == 'forward': to_x += int(math.sin(player_rot) * 1.5) to_y += int(math.cos(player_rot) * 1.5) elif action.get('move2') == 'rearward': to_x -= int(math.sin(player_rot) * 1.5) to_y -= int(math.cos(player_rot) * 1.5) if game_map.walkable(to_x, to_y): target = get_blocking_entities_at_location( entities, to_x, to_y) if target: player_turn_results.extend( player.fighter.attack(target)) else: player.x = to_x player.y = to_y fov_recompute = True # end our turn game_state = GameStates.ENEMIES_TURN elif action.get( 'turn') and game_state is GameStates.PLAYER_TURN: dir = action.get('turn') if dir == 'left': player_rot += math.pi / 4.0 elif dir == 'right': player_rot -= math.pi / 4.0 rerender_viewport = True # end_switch event.type # process player's turn results for ptr in player_turn_results: message = ptr.get('message') dead_entity = ptr.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_monster(dead_entity) message_log.add_message(message) if ptr.get('item_added'): entities.remove(ptr.get('item_added')) if ptr.get('item_dropped'): entities.append(ptr.get('item_dropped')) # end_for player_turn_results # run the enemy turn if game_state is GameStates.ENEMIES_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, game_map, entities) for etr in enemy_turn_results: message = etr.get('message') dead_entity = etr.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity is player: message, game_state = kill_player( player) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state is GameStates.PLAYER_DEAD: break if game_state is GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYER_TURN # endif enemy turn if fov_recompute: game_map.recompute_fov(player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # draw each part of the screen render_viewport( root_console, viewport_console, 0, 0, viewport_width, viewport_height, game_map, entities, colours, player.x, player.y, player_rot, fov_radius, rerender_viewport or game_state is GameStates.ENEMIES_TURN, wall_texture) render_map(root_console, map_console, game_map, entities, map_x, map_y, colours, fov_recompute) # TODO: extend render_menu to accept a top-left co-ordinate (start_x, start_y) render_menu(root_console, player, screen_width, screen_height, game_state) fps = 1.0 / (perf_counter() - time_start) render_panel(root_console, panel_console, entities, player, game_map, message_log, bar_width, panel_width, panel_height, panel_x, panel_y, mouse, fps) time_start = perf_counter() tcod.console_flush() clear_all(map_console, entities) fov_recompute = False
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) 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 main(): SCREEN_WIDTH = 80 SCREEN_HEIGHT = 50 MAP_WIDTH = 80 MAP_HEIGHT = 45 ROOM_MAX_SIZE = 10 ROOM_MIN_SIZE = 6 MAX_ROOMS = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 5 max_monsters_per_room = 3 colors = { 'dark_wall': libtcod.Color(0, 0, 100), 'dark_ground': libtcod.Color(50, 50, 150), 'light_wall': libtcod.Color(130, 110, 50), 'light_ground': libtcod.Color(200, 180, 50) } fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(SCREEN_WIDTH, SCREEN_HEIGHT, 'libtcod tutorial revised', False) con = libtcod.console_new(SCREEN_WIDTH, SCREEN_HEIGHT) game_map = GameMap(MAP_WIDTH, MAP_HEIGHT) game_map.make_map(MAX_ROOMS, ROOM_MIN_SIZE, ROOM_MAX_SIZE, MAP_WIDTH, MAP_HEIGHT, player, entities, max_monsters_per_room) fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN # gameplay loop while not libtcod.console_is_window_closed(): # this function captures new "events" - user input libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, entities, player, game_map, fov_map, fov_recompute, SCREEN_WIDTH, SCREEN_HEIGHT, colors) fov_recompute = False libtcod.console_flush() # presents everything to screen clear_all(con, entities) action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') 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 if exit: 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') if message: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) print(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: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) print(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN
def play_game(game: Game): game.fov_map: tcod.map.Map = initialize_fov(game.game_map) game.game_state: GameStates = GameStates.PLAYER_TURN game.previous_state: GameStates = game.game_state game.camera: Camera = Camera(player=game.player, width=CONSTANTS.camera_width, height=CONSTANTS.camera_height) game.camera.fov_update: bool = True targeting_item: Optional[Entity] = None mouse_position: Point = Point(x=blt.state(blt.TK_MOUSE_X) // 2, y=blt.state(blt.TK_MOUSE_Y) // 2) while game.game_running: if game.camera.fov_update: recompute_fov( fov_map=game.fov_map, point=game.player.position, radius=CONSTANTS.fov_radius, light_walls=CONSTANTS.fov_light_walls, algorithm=CONSTANTS.fov_algorithm, ) render_all( entities=game.entities, player=game.player, game_map=game.game_map, fov_map=game.fov_map, camera=game.camera, message_log=game.message_log, ui_panel=CONSTANTS.ui_panel, bar_width=CONSTANTS.bar_width, mouse_position=mouse_position, game_state=game.game_state, ) game.camera.fov_update = False if blt.has_input(): terminal_input: int = blt.read() mouse_position: Point = Point(x=blt.state(blt.TK_MOUSE_X) // 2, y=blt.state(blt.TK_MOUSE_Y) // 2) action: dict = handle_keys(key=terminal_input, game_state=game.game_state) mouse_action: dict = handle_mouse(key=terminal_input) movement: Optional[Point] = action.get("move") wait: bool = action.get("wait", False) pickup: bool = action.get("pickup", False) show_inventory: bool = action.get("show_inventory", False) drop_inventory: bool = action.get("drop_inventory", False) inventory_index: Optional[int] = action.get("inventory_index") take_stairs: bool = action.get("take_stairs", False) level_up: str = action.get("level_up") show_character_screen: bool = action.get("show_character_screen", False) exit_action: bool = action.get("exit", False) left_click: Point = mouse_action.get("left_click") right_click: Point = mouse_action.get("right_click") player_turn_results: List = [] if movement and game.game_state == GameStates.PLAYER_TURN: destination = game.player.position + movement if not game.game_map.is_blocked(destination): target = get_blocking_entities_at_location( entities=game.entities, destination=destination) if target: attack_results = game.player.fighter.attack( target=target) player_turn_results.extend(attack_results) else: game.player.move(movement) game.camera.recenter() game.change_state(GameStates.ENEMY_TURN) elif wait: game.change_state(GameStates.ENEMY_TURN) elif pickup and game.game_state == GameStates.PLAYER_TURN: for entity in game.entities: if entity.item and entity.position == game.player.position: pickup_results = game.player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: game.message_log.add_message( Message("There is nothing here to pick up.")) if show_inventory: game.change_state(GameStates.SHOW_INVENTORY) if drop_inventory: game.change_state(GameStates.DROP_INVENTORY) if (inventory_index is not None and game.previous_state != GameStates.PLAYER_DEAD and inventory_index < len(game.player.inventory.items)): item = game.player.inventory.items[inventory_index] if game.game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( game.player.inventory.use(item, entities=game.entities, fov_map=game.fov_map)) elif game.game_state == GameStates.DROP_INVENTORY: player_turn_results.extend( game.player.inventory.drop_item(item)) if take_stairs and game.game_state == GameStates.PLAYER_TURN: for entity in game.entities: if entity.stairs and entity.position == game.player.position: game.next_floor() game.fov_map = initialize_fov(game.game_map) game.camera.fov_update = True break else: game.message_log.add_message( Message("There are no stairs here.", Colors.YELLOW)) if level_up: if level_up == "hp": game.player.fighter.base_max_hp += 20 game.player.fighter.hp += 20 elif level_up == "str": game.player.fighter.base_power += 1 elif level_up == "dex": game.player.fighter.base_defense += 1 game.change_state(game.previous_state) if show_character_screen: game.change_state(GameStates.CHARACTER_SCREEN) if game.game_state == GameStates.TARGETING: if left_click: target_position: Point = game.camera.map_point(left_click) item_use_results = game.player.inventory.use( targeting_item, entities=game.entities, fov_map=game.fov_map, target_position=target_position, ) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({"targeting_cancelled": True}) if exit_action: if game.game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): game.change_state(GameStates.PLAYER_TURN) elif game.game_state == GameStates.TARGETING: player_turn_results.append({"targeting_cancelled": True}) else: game.save_game() game.game_running = False for player_turn_result in player_turn_results: message: Optional[Message] = player_turn_result.get("message") dead_entity: Optional[Entity] = player_turn_result.get("dead") item_added: Optional[Entity] = player_turn_result.get( "item_added") item_consumed: Optional[Entity] = player_turn_result.get( "consumed") item_dropped: Optional[Entity] = player_turn_result.get( "item_dropped") equip: Optional[Entity] = player_turn_result.get("equip") targeting: Optional[Entity] = player_turn_result.get( "targeting") xp: Optional[int] = player_turn_result.get("xp") targeting_cancelled: bool = player_turn_result.get( "targeting_cancelled", False) if message: game.message_log.add_message(message) if targeting_cancelled: game.game_state = game.previous_state game.message_log.add_message( Message("Targeting cancelled")) if xp: leveled_up = game.player.level.add_xp(xp=xp) game.message_log.add_message( Message(f"You gain {xp} experience points.")) if leveled_up: game.message_log.add_message( Message( f"Your battle skills grow stronger! You reached level {game.player.level.current_level}!", Colors.YELLOW)) game.change_state(GameStates.LEVEL_UP) if dead_entity: if dead_entity == game.player: message = kill_player(player=dead_entity) game.change_state(GameStates.PLAYER_DEAD) else: message = kill_monster(monster=dead_entity) game.message_log.add_message(message) if item_added: game.entities.remove(item_added) game.change_state(GameStates.ENEMY_TURN) game.camera.fov_update = True if item_consumed: game.change_state(GameStates.ENEMY_TURN) if targeting: game.change_state(GameStates.TARGETING) targeting_item: Entity = targeting game.message_log.add_message( targeting_item.item.targeting_message) if item_dropped: game.entities.append(item_dropped) game.change_state(GameStates.ENEMY_TURN) if equip: equip_results = game.player.equipment.toggle_equip(equip) for equip_result in equip_results: equipped: Optional[Entity] = equip_result.get( "equipped") dequipped: Optional[Entity] = equip_result.get( "dequipped") if equipped: game.message_log.add_message( Message(f"You equipped the {equipped.name}")) if dequipped: game.message_log.add_message( Message(f"You dequipped the {dequipped.name}")) game.change_state(GameStates.ENEMY_TURN) if game.game_state == GameStates.ENEMY_TURN: for entity in game.entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( target=game.player, fov_map=game.fov_map, game_map=game.game_map, entities=game.entities, ) for enemy_turn_result in enemy_turn_results: message: Optional[Message] = enemy_turn_result.get( "message") dead_entity = enemy_turn_result.get("dead") if message: game.message_log.add_message(message) if dead_entity: if dead_entity == game.player: message = kill_player(player=dead_entity) game.change_state(GameStates.PLAYER_DEAD) else: message = kill_monster(monster=dead_entity) game.message_log.add_message(message) if game.game_state == GameStates.PLAYER_DEAD: break else: game.change_state(GameStates.PLAYER_TURN)
def main(): # Adding the main function for Python 3 compatibility # Setting constants and global variables screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height # Adding variables Message log display to show events. message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 brown_color = libtcod.flame * libtcod.light_blue colors = { 'dark_wall': brown_color, # Color(0, 0, 100), 'dark_ground': libtcod.desaturated_orange, # Color(50, 50, 150) 'light_wall': libtcod.dark_flame, 'light_ground': libtcod.light_orange } # Coloring our tiles # LIMIT_FPS = 20 # Unused for now # Setting player coordinate starting point at center of console fighter_component = Fighter(hp=30, defense=2, power=5) # Setting player attributes player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] # Initializing the library font libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) # Now creating the window with size constants, title, and whether fullscreen libtcod.console_init_root(screen_width, screen_height, 'python/libtcod tutorial', False) con = libtcod.console_new( screen_width, screen_height) # Allows the ability to create new consoles panel = libtcod.console_new( screen_width, panel_height) # New console to hold HP and Messages game_map = GameMap(map_width, map_height) # Initialize the game map game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room) fov_recompute = True # Whether to reset the Field of View, True for start of game fov_map = initialize_fov(game_map) #Initialize the Field of View message_log = MessageLog(message_x, message_width, message_height) key = libtcod.Key() # Setting keyboard variable for input mouse = libtcod.Mouse() # Setting mouse variable for input game_state = GameStates.PLAYERS_TURN # Sets initial game_state to players turn # Next is the main game loop. We basically print the @ character to the screen in white while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) #libtcod.console_set_default_foreground(0, libtcod.white) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # Changing the way the console is initialized so we can reference different consoles later render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors) fov_recompute = False libtcod.console_flush( ) # Flush the console which writes any changes to the screen clear_all(con, entities) # New setup to call handle_keys() function from input_handlers.py action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') player_turn_results = [] # new dictionary 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: # Are you running into a monster? attack_results = player.fighter.attack( target) # Attack monster player_turn_results.extend( attack_results) # Get results of attack else: player.move(dx, dy) fov_recompute = True # Recompute the FOV upon movement game_state = GameStates.ENEMY_TURN # Sets state to players turn. if exit: return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Iterate through the results # Player Results Loop for player_turn_result in player_turn_results: message = player_turn_result.get('message') # Get the message part dead_entity = player_turn_result.get( 'dead') # Get the part as to whether dead or not if message: message_log.add_message( message) # Prints any messages for the player turn if dead_entity: # Check is something dead this turn if dead_entity == player: # Is the dead thing the player? message, game_state = kill_player( dead_entity) # Run kill_player function else: message = kill_monster( dead_entity) # Run kill_monster function message_log.add_message(message) # Enemy Results Loop if game_state == GameStates.ENEMY_TURN: # Checks to see if enemy turn for entity in entities: # Cycles through entities looking for monsters if entity.ai: # If entity is not the player and has ai. # Set a list that calls the take_turn function for the ai enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: # Iterate through the list message = enemy_turn_result.get( 'message') # Gather any messages for that ai dead_entity = enemy_turn_result.get( 'dead') # get and dead comments if message: message_log.add_message( message ) # Print any messages for the turn of the ai if dead_entity: # Check if dead entity this turn if dead_entity == player: # Is it the player? message, game_state = kill_player( dead_entity ) # If yes then run kill_player and show message from results else: message = kill_monster( dead_entity ) # If it's the monster, then kill it. message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: # Did the player die? break # If dead player then end game. if game_state == GameStates.PLAYER_DEAD: break # Ends game if player dies and monster has died at same time. else: # Set the game_state back to players turn game_state = GameStates.PLAYERS_TURN
def main(): #initilize main variables screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 max_items_per_room = 2 #define color palette colors = { 'dark_wall': libtcod.Color(55, 50, 45), 'dark_ground': libtcod.Color(15, 15, 15), 'light_wall': libtcod.Color(70, 55, 40), 'light_ground': libtcod.Color(30, 20, 15) } #Create Player fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] player_won = False #set up screen libtcod.console_set_custom_font( 'arial12x12.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'SimpleRogue', False) con = libtcod.console_new(screen_width, screen_height) panel = libtcod.console_new(screen_width, panel_height) key = libtcod.Key() mouse = libtcod.Mouse() #Generate map with entities game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room) fov_recompute = True fov_map = initializ_fov(game_map) game_state = GameStates.PLAYERS_TURN previous_game_state = game_state message_log = MessageLog(message_x, message_width, message_height) # main game loop while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) #Update Display if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors, game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) #Define possible actions action = handle_keys(key, game_state) move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') inventory_index = action.get('inventory_index') exit = action.get('exit') fullscreen = action.get('fullscreen') #Clear the last set of results from actions player_turn_results = [] #Handle actions #move the player 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: player.fighter.attack(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 #try to pick up something 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)) #display the inventory screen if show_inventory: if game_state != GameStates.SHOW_INVENTORY: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY #use an item in the 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] player_turn_results.extend(player.inventory.use(item)) #exit screen or close game if exit: if game_state == GameStates.SHOW_INVENTORY: game_state = previous_game_state else: return True #toggle full screen view if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) #Display results of player actions 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') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_states = 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 #check for win (player killed everything) fighter_count = 0 for entity in entities: if entity.fighter is not None and entity.name != 'Player': fighter_count += 1 if fighter_count == 0 and player_won != True: player_won = True message_log.add_message( Message("I hope you're proud of yourself...", libtcod.yellow)) message_log.add_message(Message("You monster!", libtcod.red)) #Handle enemy actions and display results 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 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 main(): screen_width = 80 # /4 = 20 screen_height = 50 # /4 ~= 12 # Map panel parameters map_width = 45 map_height = 40 fov_algorithm = libtcod.FOV_SHADOW fov_light_walls = True fov_radius = 9 # Health/Stats panel parameters bar_x = 4 bar_width = 24 panel_height = screen_height - map_height - 1 panel_y = screen_height - panel_height # Message panel parameters message_x = bar_width + bar_x + 2 message_width = screen_width - bar_width - bar_x - 2 message_height = panel_height - 2 message_log = MessageLog(message_x, message_width, message_height) # set up player entity and active entity list # TODO: Allow player to assign stats when starting to play fighter_component = Fighter( hp=30, defense=5, spdefense=5, attack=5, spattack=5, speed=5) player = Entity(int(screen_width / 2), int(screen_height / 2), '@', libtcod.white, 'Player', render_order=RenderOrder.ACTOR, blocks=True, fighter=fighter_component) entities = [] # set up console libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False, libtcod.RENDERER_SDL2, vsync=True) # set up all panels con = libtcod.console.Console(screen_width, screen_height) panel = libtcod.console.Console(screen_width, panel_height) # load map, entities and player game_world = GameWorld(map_width, map_height) game_world.loadfirstfloor(player, entities) # player field of vision variables fov_recompute = True fov_map = initialize_fov(game_world.currmap) # input variables key = libtcod.Key() mouse = libtcod.Mouse() # state variables game_state = GameState.PLAYERS_TURN while not libtcod.console_is_window_closed(): # poll input libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # compute field of vision if fov_recompute: if game_world.currmap.islair: current_fov_radius = 20 else: current_fov_radius = fov_radius recompute_fov(fov_map, player.x, player.y, current_fov_radius, fov_light_walls, fov_algorithm) # draw screen render_all(con, panel, entities, player, game_world.currmap, message_log, fov_map, fov_recompute, screen_width, screen_height, bar_x, bar_width, panel_height, panel_y, mouse) fov_recompute = False libtcod.console_flush() # erase previous player position clear_all(con, entities) # parse input action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') confirm = action.get('confirm') cancel = action.get('cancel') wait = action.get('wait') player_turn_results = [] # update if move and game_state == GameState.PLAYERS_TURN: dx, dy = move # saves dx and dy outside of the while loop too dest_x = player.x + dx dest_y = player.y + dy if not game_world.currmap.tileblocked(dest_x, dest_y): target = get_blocking_entities_at_location( entities, dest_x, dest_y) if target: if target.door: game_world.movetonextroom(player, entities, target.door.direction) fov_map = initialize_fov(game_world.currmap) fov_recompute = True con.clear(fg=(0, 0, 0)) elif target.stairs: game_world.movetonextfloor(player, entities) fov_map = initialize_fov(game_world.currmap) fov_recompute = True con.clear(fg=(0, 0, 0)) elif target.fighter: attack_results = player.fighter.attacktarget( target, player.fighter.attacks[0]) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True if (game_state == GameState.PLAYERS_TURN): game_state = GameState.ENEMY_TURN if wait and game_state == GameState.PLAYERS_TURN: game_state = GameState.ENEMY_TURN if exit: 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') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: if (dead_entity.char == '@'): # dead boss, spawn stairs, update world game_world.bosses_cleared[game_world.current_floor] = True entities.extend( game_world.currmap.spawnstairsdown()) message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameState.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( game_world.currmap, 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: if (dead_entity.char == '@'): # dead boss, spawn stairs, update world game_world.bosses_cleared[game_world.current_floor] = True entities.extend( game_world.currmap.spawnstairsdown()) message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameState.PLAYER_DEAD: break if game_state == GameState.PLAYER_DEAD: break else: game_state = GameState.PLAYERS_TURN
def main(): # Initiate important variables screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 max_items_per_room = 2 colors = { 'dark_wall': libtcod.Color(0, 0, 100), 'dark_ground': libtcod.Color(50, 50, 150), 'light_wall': libtcod.Color(130, 110, 50), 'light_ground': libtcod.Color(200, 180, 50), } # Initiate the objects that will be important in rendering and the map fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'Cardinal Code', False) #boolean is fullscreen or not con = libtcod.console_new(screen_width, screen_height) panel = libtcod.console_new(screen_width, panel_height) game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room) fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN # Main game loop while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # fov_recompute tells if the render function should recompute the FOV # recompute_fov will recompute the FOV from render_functions.py based on the initialized variables if(fov_recompute): recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # Renders the map and the screens render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors) libtcod.console_flush() # Clears entities whose position changed clear_all(con, entities) # Get what key was pressed, from sets of dictionaries action = handle_keys(key) # Then get the action from the sets of dictionaries established in input_handlers.py move = action.get('move') pickup = action.get('pickup') exit = action.get('exit') fullscreen = action.get('fullscreen') player_turn_results = [] # If move has a value and the game_state is the player's state if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy # If the player's destination is not blocked, do something if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location(entities, destination_x, destination_y) # If there is an entity at the destination, do this if target: player.fighter.attack(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 pickup.', libtcod.yellow)) if exit: 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') 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 game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: entity.ai.take_turn(player, fov_map, game_map, entities) 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(): screen_width = 80 screen_height = 80 bar_width = 20 panel_height = 10 panel_y = screen_height - panel_height map_width = 80 map_height = 80 - panel_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 fov_recompute = True colors = 0 entities = [] items = [] effects = [] libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'Project Magic Circle', False) con = libtcod.console_new(screen_width, screen_height) panel = libtcod.console_new(screen_width, panel_height) seed = 1000 map = GameMap(map_width, map_height) map.create_map(seed) fov_map = initialize_fov(map) nav_map = initialize_fov(map) nav_map_recompute = False message_log = MessageLog(message_x, message_width, message_height) map.place_entities(entities, 5, 5) player = entities[0] key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.STANDART realtime = False action_buffer = None message = Message('To get help press "?"', libtcod.white) message_log.add_message(message) targeting_item = None danger_level = 1 while not libtcod.console_is_window_closed(): if nav_map_recompute: fov_map = initialize_fov(map) nav_map = initialize_fov(map) fov_recompute = True nav_map_recompute = False if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, effects, map, fov_map, fov_radius, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors, game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities + effects) for entity in entities: try: entity.give_energy(int(entity.speed / 5)) except: pass for entity in entities: if entity == player: if action_buffer == None: if realtime: libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS or libtcod.EVENT_MOUSE, key, mouse) else: while True: libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS or libtcod.EVENT_MOUSE, key, mouse) render_all(con, panel, entities, effects, map, fov_map, fov_radius, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse, colors, game_state) libtcod.console_flush() clear_all(con, entities) if is_valid_input(key, mouse): break keys_action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse, game_state) action_buffer = (keys_action, mouse_action) if game_state != GameStates.TARGETING: targeting_item = None turn_results = entity.ai.take_action(action_buffer[0], action_buffer[1], map, fov_map, entities, game_state, targeting_item) if turn_results: for turn_result in turn_results: message = turn_result.get('message') dead_entity = turn_result.get('dead') fov_recompute = turn_result.get('fov_recompute') energy = turn_result.get('not_enough_energy') exit = turn_result.get('exit') fullscreen = turn_result.get('fullscreen') effect = turn_result.get('create effect') item_added = turn_result.get('item_added') item_dropped = turn_result.get('item_dropped') show_inventory = turn_result.get('show_inventory') drop_inventory = turn_result.get('drop_inventory') targeting = turn_result.get('targeting') show_help = turn_result.get('show_help') toggle_realtime = turn_result.get('toggle_realtime') go_deeper = turn_result.get('go_deeper') if message: message = Message(message, libtcod.white) message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) message = Message(message, libtcod.red) else: message = kill_monster(dead_entity) message = Message(message, libtcod.white) message_log.add_message(message) if effect: superimpose_effect(effect, effects) if energy == None: action_buffer = None if fov_recompute == None: fov_recompute = False if item_added: entities.remove(item_added) 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 item_dropped: entities.append(item_dropped) if targeting: targeting_item = targeting message = Message( targeting_item.item_aspect.targeting_message, libtcod.yellow) message_log.add_message(message) previous_game_state = GameStates.STANDART game_state = GameStates.TARGETING if exit: if game_state in { GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.TARGETING, GameStates.HELP }: if game_state == GameStates.TARGETING: message = Message('Exited targeting', libtcod.yellow) message_log.add_message(message) game_state = previous_game_state else: return True if fullscreen: libtcod.console_set_fullscreen( not libtcod.console_is_fullscreen()) if show_help: previous_game_state = game_state game_state = GameStates.HELP if toggle_realtime: message = Message('Gamemode changed', libtcod.green) message_log.add_message(message) realtime = not realtime if go_deeper: '''clear_all(con, entities) items = [] effects = [] map = GameMap(map_width, map_height) map.initialize_tiles() map.create_map(seed+danger_level) fov_map = initialize_fov(map) nav_map = initialize_fov(map) map.place_entities(entities, 5+danger_level, 5+danger_level, player = player) player = entities[0] danger_level += 2''' pass else: action_buffer = None else: if entity.ai: turn_results = entity.ai.take_action( nav_map, entities, game_state) if turn_results: for turn_result in turn_results: message = turn_result.get('message') dead_entity = turn_result.get('dead') exit = turn_result.get('exit') fullscreen = turn_result.get('fullscreen') effect = turn_result.get('create effect') if message: message = Message(message, libtcod.white) message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player( dead_entity) message = Message(message, libtcod.red) else: message = kill_monster(dead_entity) message = Message(message, libtcod.white) message_log.add_message(message) if effect: superimpose_effect(effect, effects) if game_state == GameStates.PLAYER_DEAD: break
def main(): name = "pythonRL" screenWidth = 80 screenHeight = 50 bar_width = 20 panel_height = 7 panel_y = screenHeight - panel_height message_x = bar_width + 2 message_width = screenWidth - bar_width - 1 message_height = panel_height - 1 mapWidth = 80 mapHeight = 43 room_min_size = 6 room_max_size = 10 max_rooms = 30 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'dark_wall': tcod.Color(61, 31, 0), 'dark_ground': tcod.Color(41, 21, 0), 'light_wall': tcod.Color(77, 38, 0), 'light_ground': tcod.Color(56, 28, 0), 'nothing': tcod.Color(0, 0, 0) } fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, "@", tcod.white, "Player", blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] tcod.console_set_custom_font( 'arial10x10.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) tcod.console_init_root(screenWidth, screenHeight, name, False, tcod.RENDERER_SDL2, "F", True) con = tcod.console.Console(screenWidth, screenHeight, "F") panel = tcod.console.Console(screenWidth, panel_height) game_map = GameMap(mapWidth, mapHeight) game_map.make_map(max_rooms, room_min_size, room_max_size, mapWidth, mapHeight, player, entities, max_monsters_per_room) fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = tcod.Key() mouse = tcod.Mouse() game_state = GameStates.PLAYERS_TURN 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, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, screenWidth, screenHeight, bar_width, panel_height, panel_y, mouse, colors) fov_recompute = False tcod.console_flush() clear_all(con, entities) action = handle_keys(key) move = action.get("move") exit = action.get("exit") fullscreen = action.get("fullscreen") generate = action.get("gen") player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move dest_x = player.x + dx dest_y = player.y + dy if not game_map.is_blocked(dest_x, dest_y): target = get_blocking_entities_at_location( entities, dest_x, dest_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 if exit: 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") 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.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 if generate: game_map.clear() game_map.make_map(max_rooms, room_min_size, room_max_size, mapWidth, mapHeight, player) fov_map = initialize_fov(game_map) fov_recompute = True
def main(): screen_width = 80 screen_height = 50 map_width = 80 map_height = 45 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 'BASIC' fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'dark_wall': (0, 0, 100), 'dark_ground': (50, 50, 150), 'light_wall': (130, 110, 50), 'light_ground': (200, 150, 50), 'desaturated_green': (63, 127, 63), 'darker_green': (0, 127, 0), 'dark_red': (191, 0, 0) } fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', (255, 255, 255), 'Player', \ blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] player_x = int(screen_width / 2) player_y = int(screen_height / 2) tdl.set_font('arial12x12.png', greyscale=True, altLayout=True) root_console = tdl.init(screen_width, screen_height, title='Roguelike Tutorial Revised', \ renderer='GLSL') con = tdl.Console(screen_width, screen_height) game_map = GameMap(map_width, map_height) make_map(game_map, max_rooms, room_min_size, room_max_size, map_width, map_height, player, \ entities, max_monsters_per_room, colors) fov_recompute = True game_state = GameStates.PLAYERS_TURN while not tdl.event.is_window_closed(): if fov_recompute: game_map.compute_fov(player.x, player.y, fov=fov_algorithm, radius=fov_radius, light_walls=fov_light_walls) render_all(con, entities, player, game_map, fov_recompute, root_console, screen_width, screen_height, colors) tdl.flush() clear_all(con, entities) fov_recompute = False for event in tdl.event.get(): if event.type == 'KEYDOWN': user_input = event break else: user_input = None if not user_input: continue action = handle_keys(user_input) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') screenshot = action.get('screenshot') 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 if screenshot: tdl.screenshot() if exit: 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') if message: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity, colors) else: message = kill_monster(dead_entity, colors) print(message) 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: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player( dead_entity, colors) else: message = kill_monster(dead_entity, colors) print(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, bg_music, play_bg_music, score): """ Cette fonction est le squelette du jeu. Elle utilise, directement ou indirectement, tous les autres modules de ce projet. Elle est chargée de l'éxécution des commandes du joueur lorsqu'il est en jeu. Elle est constituée d'une boucle while infinie (tant que la fenêtre est ouverte) qui teste tous les cas possibles à chaque itération. Parametres: ---------- player : Entity Le joueur entities : list Liste des entités présentes (visibiles ou non) à ce niveau game_map : GameMap Plateau de jeu message_log : MessageLog Boîte de dialogue, feedback au joueur game_state : int Désormais inutilisé dans cette fonction con : tcod.console Console du jeu panel : tcod.console Console interface constants : dict Dictionnaire contenant toutes les constantes du jeu bg_music : fichier .wav Musique de fond play_bg_music : bool Faut-il jouer la musique de fond ? score : int Score actuel du joueur (visible qu'à sa mort) Renvoi: ------- player : Entity Le joueur entities : list Liste des entités présentes (visibiles ou non) à ce niveau game_map : GameMap Plateau de jeu message_log : MessageLog Boîte de dialogue, feedback au joueur game_state : int Désormais inutilisé dans cette fonction bg_music : fichier .wav Musique de fond play_bg_music : bool Faut-il jouer la musique de fond ? score : int Score actuel du joueur (visible qu'à sa mort) """ sword_sounds = constants.get('sound').get('sword') hurt_sound = sm.Son(constants.get('sound').get('hurt')[0]) clean_stage_sound = sm.Son(constants.get('sound').get('clean_stage')[0]) 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 play_boss_music = False play_stage_music = False 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']) # Affiche la carte generee 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, constants.get('graphics')) # Gere la lecture aleatoire de la musique de fond dans les differents stages if pygame.mixer.get_busy() == 0 and play_bg_music: if game_map.dungeon_level % 5 == 0: bg_music.playpause() bg_music = sm.choose_sound(constants.get('sound').get('boss_fight')) bg_music.playpause() else: bg_music.playpause() bg_music = sm.choose_sound(constants.get('sound').get('background_music')) bg_music.playpause() if play_boss_music: play_boss_music = not play_boss_music if play_bg_music: bg_music.playpause() bg_music = sm.choose_sound(constants.get('sound').get('boss_fight')) bg_music.playpause() else: bg_music = sm.choose_sound(constants.get('sound').get('boss_fight')) if play_stage_music: play_stage_music = not play_stage_music if play_bg_music: bg_music.playpause() bg_music = sm.choose_sound(constants.get('sound').get('background_music')) bg_music.playpause() else: bg_music = sm.choose_sound(constants.get('sound').get('background_music')) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) # Lit les touches pressees pour en deduire quoi faire # Depend du gamestate 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 = [] hp80 = 0.80*player.fighter.max_hp hp60 = 0.60*player.fighter.max_hp hp40 = 0.40*player.fighter.max_hp hp20 = 0.20*player.fighter.max_hp # Si c'est au joueur et qu'il presse une touche de deplacement 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) sword = sm.choose_sound(sword_sounds) sword.playpause() player_turn_results.extend(attack_results) for entity in entities: if entity.stairs: entity.visible = True else: player.move(dx, dy) game_state = GameStates.ENEMY_TURN fov_recompute = True # Si le joueur passe son tour elif wait: fov_recompute = True game_state = GameStates.ENEMY_TURN # Si le joueur ramasse un objet 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('Rien a ramasser', libtcod.yellow)) # Si le joueur consulte son inventaire if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY # Si le joueur souhaite jeter un item if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY # Si le joueur est dans son inventaire : que faire pour utiliser ou jetter un 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 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)) # Passage au niveau suivant 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, play_boss_music, play_stage_music = game_map.next_floor(player, message_log, constants, constants.get('graphics')) fov_map = initialize_fov(game_map) fov_recompute = True libtcod.console_clear(con) score = (score[0] + 1, score[1]) break else: message_log.add_message(Message("Il n'y a pas d'escaliers ici.", 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 player.inventory.add_capacity(2) game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN # Si le joueur est en train de cibler avec un parchemin 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.MENU_SCREEN): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: return player, entities, game_map, message_log, game_state, bg_music, play_bg_music, score if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Execute tous les resultats precedent # Qui ne sont pas None 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) if all_dead(entities): leveled_up = player.level.add_xp(0.1 * player.level.level_up_base) clean_stage_sound.playpause() message_log.add_message(Message('Plus de monstres, bonus 10% XP', libtcod.yellow)) if leveled_up: message_log.add_message(Message('Level UP : niveau {0} atteint !'.format( player.level.current_level), libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP 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('{0} equipe(e)'.format(equipped.name))) if dequipped: message_log.add_message(Message('{0} desequippe(e)'.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('Ciblage annule')) if xp: leveled_up = player.level.add_xp(xp) score = (score[0], score[1] + xp) message_log.add_message(Message('+{0} XP'.format(xp))) if leveled_up: message_log.add_message(Message('Level UP : niveau {0} atteint !'.format( player.level.current_level), libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP # Gere le tour des enemis : parcours toutes les entites et fait jouer les fighter ai if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: hp_before_attack = player.fighter.hp enemy_turn_results = entity.ai.take_turn(player, fov_map, game_map, entities) if (player.fighter.hp <= hp80 < hp_before_attack) \ or (player.fighter.hp <= hp60 < hp_before_attack) \ or (player.fighter.hp <= hp40 < hp_before_attack) \ or (player.fighter.hp <= hp20 < hp_before_attack): hurt_sound.playpause() 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) save_score(score) delete_save() 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 return player, entities, game_map, message_log, game_state, bg_music, play_bg_music, score
def main(): """ Main game function """ fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(0, 0, '@', tcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] # Import font tcod.console_set_custom_font( FONT, tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) # Console initialization tcod.console_init_root(screen_width, screen_height, 'Pilferer %s' % VERSION, False, vsync=False) con = tcod.console.Console(screen_width, screen_height) # Mapping game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room) # FOV fov_recompute = True fov_map = initialize_fov(game_map) # Variables for holding input key = tcod.Key() mouse = tcod.Mouse() # Game state game_state = GameStates.PLAYERS_TURN # Main game loop while not tcod.console_is_window_closed(): # FOV if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # Draw render_all(con, entities, player, game_map, fov_map, fov_recompute, screen_width, screen_height, colors) fov_recompute = False tcod.console_flush() clear_all(con, entities) # INDPUT HANDLING tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS, key, mouse) action = handle_keys(key) # Command move player_turn_results = [] move = action.get('move') 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_entity_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 # Command exit exit = action.get('exit') if exit: return True # Command Fullscreen fullscreen = action.get('fullscreen') if fullscreen: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) # Results for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') if message: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) print(message) # Monster turns 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: print(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) print(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN game_state = GameStates.PLAYERS_TURN
def main(): screen_width: int = 80 screen_height: int = 35 bar_width: int = 20 panel_height: int = 7 panel_y: int = screen_height - panel_height ui_layer = 10 message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 map_width = 80 map_height = 28 max_monsters_per_room = 3 con = Console(x=0, y=0, width=screen_width, height=screen_height) panel = Console(0, panel_y, screen_width, panel_height, layer=ui_layer) title = "Rogue Alchemist" font = "mplus-1p-regular.ttf" fighter_component = Fighter(hp=30, defense=2, power=5) player = Entity(x=0, y=0, char='@', color=Color.BLACK, name='Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] game_map = GameMap(map_width, map_height) game_map.generate_dungeon(player, entities, max_monsters_per_room) # game_map.generate_dungeon(map_width, map_height, cave=True) start_room = game_map.dungeon.rooms[0] fov_algorithm = 0 fov_light_walls = True fov_radius = 10 colors = { "dark_wall": Color.DARK_SLATE_GRAY, "dark_ground": Color.DIM_GRAY, "light_wall": Color.LIGHT_SLATE_GRAY, "light_ground": Color.LIGHT_GRAY, "dark_door": Color.SADDLE_BROWN, "light_door": Color.BROWN, "test": Color.GOLD, } fov_recompute = True fov_map = initialize_fov(game_map) message_log = MessageLog(message_x, message_width, message_height) key = None blt.open() # initializes BearLib Terminal instance with default parameters terminal_options = f"window: title={title}, size={str(screen_width)}x{str(screen_height)}; font:{font}, size=12" blt.set(terminal_options) game_state = GameStates.PLAYERS_TURN while True: if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, colors) blt.refresh() fov_recompute = False # remove player's previous position clear_all(entities) if blt.has_input(): # if no inputs, don't wait key = blt.read() action = handle_keys(key) key = None movement = action.get("move") exit_game = action.get("exit") player_turn_results = [] if movement and game_state == GameStates.PLAYERS_TURN: dx, dy = movement 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(*movement) fov_recompute = True game_state = GameStates.ENEMY_TURN if exit_game: blt.close() return True for player_turn_result in player_turn_results: message = player_turn_result.get("message") dead_entity = player_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.ENEMY_TURN: for entity in entities: visible = libtcod.map_is_in_fov(fov_map, entity.x, entity.y) 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 game_state = GameStates.PLAYERS_TURN
def main(): constants = get_constants() libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(constants['screen_width'], constants['screen_height'], 'rogue', False) con = libtcod.console_new(constants['screen_width'], constants['screen_height']) panel = libtcod.console_new(constants['screen_width'], constants['panel_height']) player, entities, game_map, message_log, game_state = get_game_variables( constants) fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() previous_game_state = game_state 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'], constants['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(player.x + dx, player.y + dy): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: player.fighter.attack(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.append(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (game_state.SHOW_INVENTORY, game_state.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: 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 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 = game_state.ENEMY_TURN if item_consumed: game_state.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 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 # 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): # 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, 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, 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 main(): """ 사전 준비 작업 """ SYS_LOG = init_data() player, entities = init_player_and_entities(SYS_LOG['player_name']) game_map, fov_map, fov_radius, \ fov_algorithm, fov_recompute, light_recompute, camera = init_game_map(player, entities) message_log, game_state, previous_game_state, targeting_item = init_message_and_states( ) root, console, panel, animation, context = init_console() debug, mouse, keyboard = init_others() quit = False """ 메인 루프 """ while not quit: #root = tcod.Console(*context.recommended_console_size()) """ 화면 표시 """ if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) if light_recompute: light_map = initialize_light(game_map, fov_map, entities) render_all( game_state, root, console, panel, entities, player, mouse, game_map, fov_map, light_map, camera, message_log, fov_recompute, ) context.present(root, keep_aspect=True, align=(0.5, 0.5)) # integer_scaling=True align=(0.5,1)) #print(*context.recommended_console_size()) clear_all_entities(console, entities, camera) fov_recompute = False light_recompute = False """ 입력에 대한 상호작용 """ action = handle_input_per_state(keyboard, mouse, context, game_state) #print(f'Mx:{mouse.x} My:{mouse.y} Clk:{mouse.click}') #Ridiculous failsafe if action == None: action = {} move = action.get('move') rest = action.get('rest') pickup = action.get('pickup') show_inventory = action.get('show_inventory') inventory_index = action.get('inventory_index') drop_inventory = action.get('drop_inventory') show_character_screen = action.get('show_character_screen') toggle_light = action.get('toggle_light') create_luminary = action.get('create_light') toggle_wall = action.get('toggle_wall') exit = action.get('exit') quit = action.get('quit') #print(action) player_turn_results = [] 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: pass # 최대화면이 True일 시, 전체화면이 아니라면 콘솔을 전체화면으로 전환함 if action.get('fullscreen'): toggle_fullscreen(context) #print(f'center x{CENTER_X},y{CENTER_Y}') """ 플레이어 차례에 플레이어가 할 수 있는 행동들 """ # move변수에 대입된 값이 있을 시 이동 if move and game_state == GameStates.PLAYERS_TURN: dx, dy = action.get('move') destix = player.x + dx destiy = player.y + dy if debug.passwall == False: # 가려는 곳이 지형으로 안 막혀있으면 if not game_map.is_blocked(destix, destiy): # 거기에 이미 엔티티가 있나 확인 target = get_blocking_entities_at_location( entities, destix, destiy) if target: battle = target._Fighter if target.name == "메리": pass elif battle: attack_results = player._Fighter.attack(target) player_turn_results.extend(attack_results) else: """ 다음 층으로 """ if target._Portal: entities = game_map.next_depth( player, message_log) fov_map = initialize_fov(game_map) fov_recompute = True light_recompute = True console.clear() else: print( "This is the weirdest bug I've ever seen") else: player.move(dx, dy) camera.update(player) fov_recompute = True light_recompute = True game_state = GameStates.ENEMY_TURN else: if game_map.is_blocked(player.x + dx, player.y + dy): debug.dbg_msg("You magically pass through solid wall.") player.move(dx, dy) camera.update(player) 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.log( Message(SYS_LOG['cannot_get_item'], tcod.yellow)) if toggle_light: if player._Luminary.luminosity: player._Luminary.luminosity = 0 fov_radius = 1 fov_algorithm = fov_algorithm_dark else: player._Luminary.luminosity = player._Luminary.init_luminosity fov_radius = max_fov_radius fov_algorithm = fov_algorithm_lit fov_recompute = True light_recompute = True game_state = GameStates.ENEMY_TURN 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, camera=camera, entities=entities, animation=animation, root=root, context=context, fov_map=fov_map, game_map=game_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player._Inventory.drop_item(item)) if game_state == GameStates.TARGETING: if mouse.click == "L": target_x = mouse.x - camera.x - CENTER_X target_y = mouse.y - camera.y - CENTER_Y #print(f"타게팅 x,y: {target_x},{target_y}") item_use_results = player._Inventory.use(targeting_item, entities=entities, fov_map=fov_map, camera=camera, animation=animation, root=root, context=context, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif mouse.click == "R": player_turn_results.append({'targeting_cancelled': True}) if rest: game_state = GameStates.ENEMY_TURN if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if player._Fighter.sanity <= 0: message, game_state = insane_player(player) message_log.log(message) for r in player_turn_results: message = r.get('message') dead_entity = r.get('dead') equip = r.get('equip') item_added = r.get('item_added') item_consumed = r.get('consumed') item_used = r.get('used') item_dropped = r.get('item_dropped') targeting = r.get('targeting') targeting_cancelled = r.get('targeting_cancelled') if message: message_log.log(message) if targeting_cancelled: game_state = previous_game_state message_log.log(Message('Targeting cancelled')) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity, game_map) message_log.log(message) 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') equip_log = SYS_LOG['equip_log'] if equipped: way = equipped._Equippable.slot.name msg = cout(equip_log, equip_log['ways_to_wear'][way], 받침(equipped.name, 1)) message_log.log(Message(msg)) if dequipped: way = dequipped._Equippable.slot.name msg = cout(equip_log, equip_log['ways_to_unwear'][way], 받침(dequipped.name, 1)) message_log.log(Message(msg)) game_state = GameStates.ENEMY_TURN if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed or item_used: 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.log(targeting_item._Item.targeting_message) """ 적의 차례에 적이 할 수 있는 행동들 """ if game_state == GameStates.ENEMY_TURN: # 정신력 고갈 기능. 따로 변수로 넣던가 Gamemap에 넣어야 하나. if not game_map.monsters == 0: clear_message_shown = False """ 정신력 피해 계산 """ sanity_damage = random.randint( int(-30 / math.sqrt(game_map.depth)), game_map.monsters) s_resist_percent = int( (100 + 3 * (fov_radius - 1) + player._Equipment.total_sanity_resist) / 100) sanity_resistance = random.randint(0, int(10 * s_resist_percent)) sanity_damage -= sanity_resistance #광기저항을 계산 안 했네 if sanity_damage < 0: sanity_damage = 0 else: sanity_damage = int(math.sqrt(sanity_damage)) player._Fighter.heal_sanity(-sanity_damage) if sanity_damage > 3: log = SYS_LOG['enemies_exist'] message_log.log( Message(log[random.randint(0, len(log) - 1)], tcod.dark_chartreuse)) else: if not clear_message_shown: clear_message_shown = True message_log.log( Message(SYS_LOG['enemies_nonexistant'], tcod.green)) for entity in entities: if entity.name == 'light source': pass #message_log.log(f"The {entity.name} is glowing") elif entity._Ai: enemy_turn_results = entity._Ai.take_turn( player, fov_map, game_map, entities) for er in enemy_turn_results: message = er.get('message') dead_entity = er.get('dead') game_won = er.get('game_won') if game_won: message_log.log( Message(SYS_LOG['found_mary_log'], tcod.green)) message_log.log( Message(SYS_LOG['game_won_log'], tcod.green)) game_state = GameStates.GOOD_ENDING if message: message_log.log(message) if player._Fighter.sanity <= 0: message, game_state = insane_player(player) message_log.log(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) game_map.monsters -= 1 message_log.log(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: if not game_state == GameStates.GOOD_ENDING: game_state = GameStates.PLAYERS_TURN """ 디버그 기능들 """ # 플레이어 위치 표시 if debug.showpos: debug.show_pos(player, 'player') # 벽 설치 if toggle_wall: game_map.toggle_wall(player.x, player.y) # 지형이 변했으니 새로 지형 맵을 짜야 함 fov_map = initialize_fov(game_map) light_recompute = True if create_luminary: game_map.create_luminary(entities, player.x, player.y, 15) # 광원이 새로 생겼으니 다시 계산 light_recompute = True
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, 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