def main(): # Size of the SCREEN!!! IT'S THE SCREEN, JERRY! THE SCREEN! screen_width = 80 screen_height = 50 # Size of the map map_width = 80 map_height = 43 # size of the BARS!!!!!!! bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height # MESSAGES!!!!! message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 # Some variables for the rooms in the map room_max_size = 10 room_min_size = 6 max_rooms = 30 # MONSTERS max_monsters_per_room = 3 max_items_per_room = 2 fov_algorithm = 0 fov_light_walls = True fov_radius = 10 # reg colors 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) } # debug colors 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) } # Components and Entities 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, vsync=True, renderer=libtcod.RENDERER_SDL2) con = libtcod.console.Console(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) print("{}: {}".format("Rooms", len(game_map.rooms))) 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 # can't get this code to work the way it's supposed to, so whateves # while not tcod.event.get() == 'QUIT': 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) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key) move = action.get('move') pickup = action.get('pickup') exit = action.get('exit') # command = action.get('command') 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 here to pick up.', 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: # player's result loop 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: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: # enemy results loop 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(): window_title: str = 'Bearlibterm/TCOD Roguelike' screen_width: int = 40 screen_height: int = 20 map_width: int = 80 map_height: int = 40 room_max_size: int = 10 room_min_size: int = 6 max_rooms: int = 100 fov_algorithm: int = 0 fov_light_walls: bool = True fov_radius: int = 10 max_monsters_per_room: int = 3 colors = { 'dark_wall': terminal.color_from_argb(0, 0, 0, 100), 'dark_ground': terminal.color_from_argb(0, 50, 50, 150), 'light_wall': terminal.color_from_argb(0, 255, 255, 255), 'light_ground': terminal.color_from_argb(0, 255, 255, 255) } game_running: bool = True fov_recompute: bool = True player: Entity = Entity(x=0, y=0, char='@', color=terminal.color_from_argb(0, 255, 255, 255), name='Player', blocks=True) entities = [player] game_map: GameMap = GameMap(width=map_width, height=map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room) camera = Camera(x=0, y=0, width=screen_width, height=screen_height, map_width=map_width, map_height=map_height) camera.update(player) game_state: GameStates = GameStates.PLAYERS_TURN terminal.open() terminal.set( f'window: size={screen_width}x{screen_height}, title="{window_title}";' ) while game_running: if fov_recompute: game_map.compute_fov(x=player.x, y=player.y, radius=fov_radius, light_walls=fov_light_walls, algorithm=fov_algorithm) render_all(entities=entities, game_map=game_map, colors=colors, camera=camera) fov_recompute = False terminal.refresh() if terminal.has_input(): terminal_input: int = terminal.read() action = handle_keys(terminal_input) escape = action.get('escape') movement = action.get('movement') if escape: game_running = False if movement and game_state == GameStates.PLAYERS_TURN: dx, dy = movement destination_x: int = player.x + dx destination_y: int = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target: Entity = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: print( f'You kick the {target.name} in the shins, much to its annoyance!' ) else: player.move(dx, dy) print(f'player map coords: {player.x}, {player.y}') shift_x = -player.x + int(screen_width / 2) shift_y = -player.y + int(screen_height / 2) print(f'shift coords: {shift_x}, {shift_y}') camera.update(player) print(f'camera coords: {camera.x}, {camera.y}') fov_recompute = True game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity != player: print( f'The {entity.name} ponders the meaning of its existence.' ) game_state = GameStates.PLAYERS_TURN terminal.clear() terminal.close()
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) } player = Entity(0, 0, '@', libtcod.red, 'Player', blocks=True) 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, 'ROUGE', 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.PLAYER_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) render_all(con, entities, game_map, fov_map, fov_recompute, screen_width, screen_height, colors) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') if move and game_state == GameStates.PLAYER_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: print('You kick the ' + target.name + ' in the shines, much to its annoyance!') 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()) if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity != player: print('The ' + entity.name + ' ponders the meaning of its existence...') game_state = GameStates.PLAYER_TURN
def main(): # screen constants screen_width = 80 screen_height = 50 # UI Stuff 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 stuff map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 max_monsters_per_room = 4 # FOV constants fov_algorithm = 0 fov_light_walls = True fov_radius = 10 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('assets/consolas12x12_gs_tc.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) # libtcod.console_set_custom_font('assets/arial10x10.png' , libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False, renderer=libtcod.RENDERER_SDL2, vsync=False) con = libtcod.console.Console(screen_width, screen_height) # main console panel = libtcod.console.Console(screen_width, panel_height) # ui panel message_log = MessageLog(message_x, message_width, message_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) turn_count = 0 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) 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) fov_recompute = False 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: 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: turn_count += 1 for entity in entities: time_based_results = entity.processTimeBasedEffects(turn_count) for tb_result in time_based_results: message = tb_result.get('message') if message: message_log.add_message(message) 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, 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("Nothing 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("Equipped {0}.".format(equipped.name))) if dequipped: message_log.add_message( Message("Removed {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("{0} experience gained.".format(xp))) if leveled_up: #todo take another shot at the level up message message_log.add_message( Message( "Your effort pays off, and you reach 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(): 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, fighter=fighter_component, render_order=RenderOrder.ACTOR, 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, 'Game', 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 prev_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') 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('Nothing here to pick up', libtcod.yellow)) if show_inventory: fov_recompute = True prev_game_state = game_state game_state = GameStates.SHOW_INVENTORY if inventory_index is not None and prev_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)) if exit: if game_state == GameStates.SHOW_INVENTORY: game_state = prev_game_state fov_recompute = 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') 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 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: fov_recompute = True break else: game_state = GameStates.PLAYERS_TURN fov_recompute = True
def main(): # set main game window size screen_width = 80 screen_height = 60 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 = 53 room_max_size = 10 room_min_size = 6 max_rooms = 30 fov_algorithm = 'PERMISSIVE' fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 colors = { 'dark_wall': (26, 26, 26), 'dark_ground': (51, 51, 51), 'light_wall': (26, 20, 13), 'light_ground': (51, 41, 26), 'desaturated_green': (63, 127, 63), 'darker_green': (0, 127, 0), 'dark_red': (191, 0, 0), 'white': (255, 255, 255), 'black': (0, 0, 0), 'red': (255, 0, 0), 'orange': (255, 127, 0), 'light_red': (255, 114, 114), 'darker_red': (127, 0, 0) } fighter_component = Fighter(hp=30, defence=2, power=5) player = Entity(0, 0, '@', (128, 102, 64), 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component) entities = [player] # Font differs from one in tutorial as I use this ti work in REXpaint tdl.set_font('cp437_12x12.png', greyscale=True, altLayout=False) # Main game window root_console = tdl.init(screen_width, screen_height, title='MFRL revised tutorial') con = tdl.Console(screen_width, screen_height) panel = tdl.Console(screen_width, panel_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 message_log = MessageLog(message_x, message_width, message_height) mouse_coordinates = (0, 0) 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, panel, entities, player, game_map, fov_recompute, root_console, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse_coordinates, colors) # And draw it all 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 else: user_input = None ''' As in tutorial: Python has a lesser-known feature where you can put an 'else' statement after a for loop, and that else statement only executes if we didn't break out of the loop! So in this scenario, if we didn't encounter any 'KEYDOWN' event, then we set user_input to None by default. ''' if not user_input: continue action = handle_keys(user_input) move = action.get('move') exit_game = 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 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 exit_game: return True # Exit main loop and the game 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: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity, colors) else: message = kill_monster(dead_entity, colors) 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, 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, colors) else: message = kill_monster(dead_entity, 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 hunt_target(curr_actor, entities, game_map) -> list or str: astar = pathfind.AStar(game_map) enemies = [] closest_coords = [] closest_dist = None path = None command = {'End Turn': 'End Turn'} for entity in entities: if entity is not curr_actor: if (entity.x, entity.y) in curr_actor.fighter.fov_visible: if global_vars.debug: print(entity.name + ' is visible') enemies.append(entity) if len(enemies) != 0: for enemy in enemies: dist = sum( ((abs(enemy.x - curr_actor.x)), (abs(enemy.y - curr_actor.y)))) if closest_dist is None or dist < closest_dist: closest_dist = dist closest_coords = [enemy.x, enemy.y] closest_enemy = enemy else: #See if there's a known loc for an enemy in history if len(curr_actor.fighter.ai.target_memory) > 0: for entry in curr_actor.fighter.ai.target_memory: x, y = entry.get('last_loc') dist = sum(((abs(x - curr_actor.x)), (abs(y - curr_actor.y)))) if closest_dist is None or dist < closest_dist: closest_dist = dist closest_coords = [x, y] closest_enemy = entry.get('target') else: command = random_hunt(curr_actor, entities, game_map) if closest_dist is not None: path = astar.get_path(curr_actor.x, curr_actor.y, closest_coords[0], closest_coords[1]) if len(path) == 0: #What to do if you reached the last known loc? if (closest_enemy.x, closest_enemy.y) in curr_actor.fighter.fov_visible: path = astar.get_path(curr_actor.x, curr_actor.y, closest_enemy.x, closest_enemy.y) else: for entry in curr_actor.fighter.ai.target_memory: if entry.get('target') == closest_enemy: curr_actor.fighter.ai.target_memory.remove(entry) command = random_hunt(curr_actor, entities, game_map) try: if len(path) > 1: y_dir = None x_dir = None x, y = path[0] x_mod = x - curr_actor.x y_mod = y - curr_actor.y if y_mod == -1: y_dir = 'n' if y_mod == 1: y_dir = 's' if x_mod == -1: x_dir = 'w' if x_mod == 1: x_dir = 'e' if x_dir is not None and y_dir is not None: mv_dir = str(y_dir + x_dir) elif y_dir is not None: mv_dir = y_dir else: mv_dir = x_dir command = {'move': mv_dir} elif len(path) == 1: if get_blocking_entities_at_location( entities, closest_coords[0], closest_coords[1]) is not None: #Spin to closest enemy if len(curr_actor.fighter.targets) == 0: angle = entity_angle(closest_enemy, curr_actor) if angle <= 180: command = {'spin': 'ccw'} else: command = {'spin': 'cw'} except: pass return command
def main(): screen_width = 80 screen_height = 50 map_width = screen_width map_height = screen_height - 5 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, 500), } player = Entity(screen_width // 2, screen_height // 2, '@', libtcod.white, 'Player', blocks=True) entities = [player] libtcod.console_set_custom_font( 'dejavu10x10_gs_tc.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() 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, game_map, fov_map, fov_recompute, screen_width, screen_height, colors) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') if move: 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: print( 'You kick the {} in the shins, much to its cansternation!' .format(target.name)) else: player.move(dx, dy) fov_recompute = True if exit: return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants, priority_queue, global_variables, world): fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() # Variables used to make decisions during the game. targeting_item = None previous_game_state = game_state # Turn on camera. camera = Camera(constants['camera_width'], constants['camera_height'], player.x, player.y, constants['map_width'], constants['map_height']) # Actviate cursor. cursor = Cursor() 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']) # Only render and recompute FOV while on the player's turn. if not game_state == GameStates.ENEMY_TURN: 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, camera, cursor) fov_recompute = False libtcod.console_flush() # The console is cleared, but it will only be flushed on the player's turn. clear_all(con, entities, camera.x, camera.y, cursor) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) enemy = None # If it's not the player's turn, it's _this_ enemy's turn. # Decide the entity's turn. if not priority_queue.empty() and game_state == GameStates.ENEMY_TURN: queue_ID = priority_queue.get_ID() # This removes the topmost ID from the queue. for entity in entities: if queue_ID == entity.ID and not entity.is_dead(): # If the entity is dead, do nothing. It has already been removed from the queue. if entity.ai == None: #it's the player # The player gets reinserted into the queue after their action. game_state = GameStates.PLAYERS_TURN break else: # The enemy gets reinserted into the queue after their action. enemy = entity break """ List of possible actions taken by the player. TODO: Cut things up via GameState more clearly. """ 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') exit = action.get('exit') fullscreen = action.get('fullscreen') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') show_extract_materia_menu = action.get('show_extract_materia_menu') # Prompt the player to extra materia from creature. extraction_index = action.get('extraction_index') # Select this entry from the extraction menu. look = action.get('look') # Enter the LOOK GameState. select = action.get('select') # A target has been selected via keyboard. 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: # TODO: Prevent player from moving outside the map. 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: # Check to see if the player is lined up with the center. # If so, move the camera with the player. camera_x, camera_y = camera.absolute_center() if player.x == camera_x: camera.move(dx, 0) if player.y == camera_y: camera.move(0, dy) player.move(dx, dy) fov_recompute = True priority_queue.put(player.fighter.speed, player.ID) # The player spends their turn to move/attack. game_state = GameStates.ENEMY_TURN elif move and game_state == GameStates.LOOK: # Move the cursor. dx, dy = move cursor.move(dx, dy, constants['camera_width'], constants['camera_height'], camera.x, camera.y) elif wait and game_state == GameStates.PLAYERS_TURN: # Puts the player second in queue. priority_queue.put_next(player.ID) 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) priority_queue.put(player.fighter.speed, player.ID) # The player spends their turn picking up stuff. game_state = GameStates.ENEMY_TURN break else: message_log.add_message(Message('There is nothing here to pick up.', libtcod.yellow)) if show_inventory and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory and game_state == GameStates.PLAYERS_TURN: 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 game_state == GameStates.TARGETING: # Mouse targeting if left_click: target_x, target_y = left_click target_x += camera.x target_y += camera.y 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}) # Keyboard targeting if move: # Move the cursor. dx, dy = move cursor.move(dx, dy, constants['camera_width'], constants['camera_height'], camera.x, camera.y) if select: # Hit the chosen target. target_x, target_y = cursor.x, cursor.y 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) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.MATERIA_SCREEN, GameStates.LOOK): 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, priority_queue, global_variables, world) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) 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 and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_extract_materia_menu and game_state == GameStates.PLAYERS_TURN: previous_game_state = game_state game_state = GameStates.MATERIA_SCREEN if extraction_index is not None and previous_game_state != GameStates.PLAYER_DEAD: # Create the list of items that have materia item_list = player.inventory.item_list_with_property('materia') # Check to see the index is inside this list if extraction_index < len(item_list): # Create an item called "type Materia (lvl n)" extracting_item = item_list[extraction_index] # This is the pokeball entity. materia_type = extracting_item.item.caught_entity.materia[0] materia_level = extracting_item.item.caught_entity.materia[1] materia_name = materia_type.capitalize() + ' Materia (lvl ' + str(materia_level) + ')' item_component = Item(use_function=item_functions.materia, type=materia_type, level=materia_level) materia_item = Entity(0, 0, '*', libtcod.white, materia_name, global_variables.get_new_ID(), RenderOrder.ITEM, item=item_component) # Add it to the inventory player.inventory.add_item(materia_item) entities.append(materia_item) # Remove the entity from which it came from the parent entity holding it extracting_item.item.caught_entity = None # Return the pokeball to a "catch" mode instead of release. # TODO: There are now two instances of switching the pokeball from one function to another. Consider moving this inside the Item class. extracting_item.item.swap_messages() extracting_item.item.use_function = item_functions.catch if look: previous_game_state = game_state cursor.x, cursor.y = player.x, player.y game_state = GameStates.LOOK """ List of possible results from actions taken by the player. """ 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') thrown = player_turn_result.get('thrown') # This item was thrown. Returns the item entity. catch = player_turn_result.get('catch') # This item catches pokemon. Returns the caught entity. release = player_turn_result.get('release') # This item released pokemon. Returns the released entity. 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) if item_consumed: # Removed from inventory in inventory.py pass if item_dropped: entities.append(item_dropped) if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING cursor.x, cursor.y = player.x, player.y 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 thrown: # Removed from inventory in inventory.py thrown.x, thrown.y = player_turn_result.get('target_xy') entities.append(thrown) game_state = GameStates.PLAYERS_TURN if catch: entities.remove(catch) if release: release.x, release.y = player_turn_result.get('target_xy') entities.append(release) priority_queue.put(release.fighter.speed, release.ID) 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 and enemy: enemy_turn_results = enemy.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 elif not enemy.ai == None: priority_queue.put(enemy.fighter.speed, enemy.ID)
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 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') 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 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 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') 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.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 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: 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.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
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants, camera): fov_recompute = True fov_map = initalize_fov(game_map) camera.update(player) key = libtcod.Key() mouse = libtcod.Mouse() previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], mouse, constants['colors'], game_state, camera) fov_recompute = False libtcod.console_flush() clear_all(con, entities, camera) 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') fullscreen_console = action.get('fullscreen_console') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') wheel_up = mouse_action.get('wheel_up') wheel_down = mouse_action.get('wheel_down') player_turn_results = [] if wheel_up: message_log.scroll_up() if wheel_down: message_log.scroll_down() 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) camera.update(player) 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.usable 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 fumble around on the ground but find nothing.', 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 = initalize_fov(game_map) camera.update(player) 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 # TODO: Consider putting these in constants player.fighter.hp += 20 elif level_up == 'str': player.fighter.base_power += 1 elif level_up == 'def': player.fighter.base_defense += 1 elif level_up == 'speed': player.fighter.base_speed -= 10 # game_state = previous_game_state # This is the only way I found that the level up book doesn't lock game_state = GameStates.PLAYERS_TURN # the game, hopefully it's fine but it may give an extra turn on lvl up if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if fullscreen_console: previous_game_state = game_state game_state = GameStates.FULLSCREEN_CONSOLE 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_map.dungeon_level == -1: # Testing arena case needs no save file return True elif game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.FULLSCREEN_CONSOLE): 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')) if xp: leveled_up = player.level.add_xp(xp) message_log.add_message(Message('You gain {0} xp.'.format(xp))) if leveled_up: message_log.add_message( Message( 'You have honed your skills to reach level {0}.'. format(player.level.current_level), libtcod.cyan)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message( targeting_item.usable.targeting_message) 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 item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: current_moves = entity.fighter.current_moves current_moves -= player.fighter.base_speed while (current_moves <= 0): 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 # Break game loop if game_state == GameStates.PLAYER_DEAD: break # Break game loop current_moves += entity.fighter.speed entity.fighter.current_moves = current_moves else: game_state = GameStates.PLAYERS_TURN
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 = 30 room_min_size = 6 max_rooms = 30 fov_algorithm = 2 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) } til = Tile(False) fighter_component = Fighter(30, defense=2, power=5) player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True, fighter=fighter_component, render_order=RenderOrder.ACTOR) 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) map = GameMap(map_width, map_height) 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(map) message_log = MessageLog(message_x, message_width, message_height) 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 | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) entities_in_render_order = sorted(entities, key=lambda x: x.render_order.value) render_all(con, panel, entities_in_render_order, player, 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() 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 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 else: message_log.add_message(Message('stuck')) if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) if exit: 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_in_render_order: if entity != player and entity.ai != None: enemy_turn_results = entity.ai.take_turn( fov_map, player, 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 game_state = GameStates.PLAYERS_TURN
def main(): # console props screen_width = 80 screen_height = 50 # UI settings bar_width = 20 ui_panel_height = 7 ui_panel_y = screen_height - ui_panel_height ## Message system message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = ui_panel_height - 1 message_log = MessageLog(message_x, message_width, message_height) # map props map_width = 80 map_height = 43 room_max_size = 10 room_min_size = 6 max_rooms = 30 max_monsters_per_room = 3 max_items_per_room = 4 # FOV settings fov_algorithm = 0 fov_light_walls = True fov_radius = 10 fov_recompute = True # we don't need to recompute FOV everytime (wait, fight, use item) # Colors dictionary 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) } # Entities setup player_fighter_comp = Fighter(30, 2, 5) player_inventory_comp = Inventory(12) player = Entity(0, 0, '@', libtcod.white, 'Player', True, RenderOrder.ACTOR, player_fighter_comp, inventory=player_inventory_comp) entities = [player] game_state = GameStates.PLAYERS_TURN previous_game_state = game_state # Consoles setup libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GRAYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'First Shem RL. Thanks Tutorial', False) con = libtcod.console.Console(screen_width, screen_height) ui_panel = libtcod.console.Console(screen_width, ui_panel_height) # Gamemap setup game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, player, entities, max_monsters_per_room, max_items_per_room) fov_map = initialize_fov(game_map) # Input setup key = libtcod.Key() mouse = libtcod.Mouse() targeting_item = None # WARN Check tcod.event for QUIT events 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, entities, player, game_map, fov_map, fov_recompute, screen_width, screen_height, ui_panel, bar_width, ui_panel_height, ui_panel_y, message_log, mouse, game_state, colors) fov_recompute = False libtcod.console_flush() clear_all(con, entities) # Input handling action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') exit = action.get('exit') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] # Movement handling 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 # Pickup handling 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)) # Menus display handling 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 # Items usage handling if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len(player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend(player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen) # Print turn results for p_t_result in player_turn_results: message = p_t_result.get('message') dead_entity = p_t_result.get('dead') item_added =p_t_result.get('item_added') item_consumed = p_t_result.get('item_consumed') item_dropped = p_t_result.get('item_dropped') targeting = p_t_result.get('targeting') targeting_cancelled = p_t_result.get('targeting_cancelled') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN # ENEMIES 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 e_t_result in enemy_turn_results: message = e_t_result.get('message') dead_entity = e_t_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.CHARACTER_CREATION previous_game_state = game_state targeting_item = None targeting_skill = None ggender = Gender.male 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(player, key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') wait = action.get('wait') pickup = action.get('pickup') use_skills = action.get('use_skills') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') skill_index = action.get('skill_index') take_stairs = action.get('take_stairs') take_upstairs = action.get('take_upstairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') character_creation = action.get('character_creation') job = action.get('job') gender = action.get('gender') skill_selection = action.get('skill_selection') 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: #The starvation variable increases or decreases as the player gets more psyche and gets hungrier. libtcod.console_flush() starvation_variable = 1 player.fighter.nutrition -= 1 dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if player.fighter.nutrition <= 0: kill_player(player) game_state = GameStates.PLAYER_DEAD message_log.add_message( Message('You have starved to death.', libtcod.red)) if player.fighter.starvation_bonus >= 20 and player.fighter.psyche <= 5 or player.fighter.psyche == 5: starvation_variable = 0 elif player.fighter.starvation_bonus >= 40 and player.fighter.psyche <= 10 or player.fighter.psyche == 10: starvation_variable = 0 if player.fighter.nutrition <= 100: player.fighter.starvation_bonus += starvation_variable elif player.fighter.nutrition >= 100: player.fighter.starvation_bonus += 0 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 gender == Gender.male: player.fighter.gender = 1 elif gender == Gender.female: player.fighter.gender = 2 elif gender == Gender.agender: player.fighter.gender = 3 elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if (entity.item or 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 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 use_skills: previous_game_state = game_state game_state = GameStates.SHOW_SKILL_MENU 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)) libtcod.console_flush() libtcod.console_clear(con) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) libtcod.console_flush() libtcod.console_clear(con) if skill_index is not None and previous_game_state != GameStates.PLAYER_DEAD and skill_index < len( player.skills.skill_list): skill = player.skills.skill_list[skill_index] if game_state == GameStates.SHOW_SKILL_MENU: player_turn_results.extend( player.skills.use(skill, entities=entities, fov_map=fov_map)) libtcod.console_flush() libtcod.console_clear(con) 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 take_upstairs 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.previous_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 += 10 player.fighter.hp += 10 elif level_up == 'str': player.fighter.base_power += 1 elif level_up == 'def': player.fighter.base_defense += 1 libtcod.console_flush() libtcod.console_clear(con) game_state = GameStates.JOB_SELECTION #For some reason the skil menu is linked here. I wonder why? if job: if job == 'pri': player.fighter.base_max_hp += 20 player.fighter.hp += 20 player.fighter.job += 1 player.fighter.priest_level += 1 skill_component = Skill(use_function=prayer, amount=40, mana_cost=5) bandage = Entity(0, 0, '?', libtcod.yellow, 'Cure Light Wounds', skill=skill_component) player.skills.add_skill(bandage) elif job == 'fig': player.fighter.base_power += 2 player.fighter.base_defense += 1 player.fighter.job += 2 player.fighter.fighter_level += 1 elif job == 'thi': skill_component = Skill(use_function=hide) tornado = Entity(0, 0, '?', libtcod.yellow, 'Hide', skill=skill_component) player.fighter.base_defense += 2 player.fighter.base_power += 1 player.fighter.base_agility += 0.5 player.fighter.job += 3 player.fighter.thief_level += 1 player.skills.add_skill(tornado) elif job == 'wiz': skill_component = Skill( use_function=cast_spell_fireball, mana_cost=10, skill_targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', libtcod.light_cyan), damage=25, radius=3) x = entity.x y = entity.y fireball = Entity(x, y, '?', libtcod.red, 'Fireball', skill=skill_component) player.skills.add_skill(fireball) elif job == 'psy': skill_component = Charm() charm = SkillEntity(' ', libtcod.yellow, 'Charm', skill=skill_component) player.fighter.base_psyche += 3 player.fighter.job = 5 skill_component = Skill(use_function=cast_mind_lightning, maximum_range=5, hunger_cost=40 + player.fighter.psyche / 2) psybolt = Entity(0, 0, ' ', libtcod.yellow, 'PsyBolt', skill=skill_component) player.skills.add_skill(psybolt) player.skills.add_skill(charm) libtcod.console_flush() libtcod.console_clear(con) game_state = GameStates.PLAYERS_TURN if character_creation: if character_creation == 'mern': player.fighter.base_max_hp += 20 player.fighter.hp += 20 player.fighter.race += 1 elif character_creation == 'avis': player.fighter.base_power += 1 player.fighter.race += 2 elif character_creation == 'lepra': player.fighter.base_defense += 1 player.fighter.race += 3 elif character_creation == 'giant': player.fighter.base_agility -= 5 player.fighter.base_power += 6 player.fighter.hp += 60 player.fighter.base_max_hp += 60 player.fighter.race += 4 elif character_creation == 'change': player.fighter.base_agility += 2 player.fighter.race += 5 elif character_creation == 'fae': player.fighter.base_agility += 10 player.fighter.hp -= 75 player.fighter.base_max_hp -= 75 player.fighter.race += 6 libtcod.console_flush() libtcod.console_clear(con) game_state = GameStates.GENDER_SELECTION # damn son thats a lot of menus # like a lot if gender: if gender == 'm': player.fighter.base_max_hp += 10 player.fighter.hp += 10 player.fighter.gender += 1 elif gender == 'f': player.fighter.base_power += 5 player.fighter.base_max_hp -= 20 player.fighter.hp -= 20 player.fighter.gender += 2 elif gender == 'a': player.fighter.gender += 3 libtcod.console_flush() libtcod.console_clear(con) game_state = GameStates.PLAYERS_TURN 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) libtcod.console_flush() libtcod.console_clear(con) elif right_click: player_turn_results.append({'targeting_cancelled': True}) libtcod.console_flush() libtcod.console_clear(con) if game_state == GameStates.SKILL_TARGETING: if left_click: target_x, target_y = left_click skill_use_results = player.skills.use(targeting_skill, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(skill_use_results) libtcod.console_flush() elif right_click: player_turn_results.append({'targeting_cancelled': True}) libtcod.console_flush() libtcod.console_clear(con) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): game_state = previous_game_state elif game_state == GameStates.SHOW_SKILL_MENU: game_state = GameStates.PLAYERS_TURN elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) elif game_state == GameStates.SKILL_TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state) libtcod.console_flush() libtcod.console_clear(panel) libtcod.console_clear(con) 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') skill_added = player_turn_result.get('skill_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') skill_targeting = player_turn_result.get('skill_targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') xp = player_turn_result.get('xp') skill_used = player_turn_result.get('used') 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 skill_added: game_state = GameStates.ENEMY_TURN if skill_used: 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 skill_targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.SKILL_TARGETING targeting_skill = skill_targeting message_log.add_message( targeting_skill.skill.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: if player.fighter.nutrition <= 0: kill_player(player) game_state = GameStates.PLAYER_DEAD message_log.add_message( Message('You have starved to death.', libtcod.red)) if player.fighter.nutrition <= 100 and player.fighter.stealthed == 1: player.fighter.stealthed = 0 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(): # Console Parameters screen_width = 80 screen_height = 50 # GUI Parameters bar_width = 20 panel_height = 7 panel_y = screen_height - panel_height # Message Parameters message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 # Map Parameters map_width = 80 map_height = 43 # Room Parameters room_max_size = 10 room_min_size = 6 max_rooms = 30 # Field of View Parameters fov_algorithm = 0 fov_light_walls = True fov_radius = 10 # Spawn parameters max_monsters_per_room = 3 max_items_per_room = 2 # Tile Colors 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) } # Entity Variables 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] # Map Generator game_map = GameMap( # defines the game map dimensions, calling GameMap class map_width, map_height ) game_map.make_map( # generates the 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) # Console & GUI libtcod.console_set_custom_font('assets/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) message_log = MessageLog(message_x, message_width, message_height) # Input Functions key = libtcod.Key() mouse = libtcod.Mouse() # Game States game_state = GameStates.PLAYERS_TURN previous_game_state = game_state ############################################################# # MAIN GAME LOOP # ############################################################# # So long as the window is open, do... while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) # TRUE on Move, trigger recompute if fov_recompute: recompute_fov( fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm ) # Render the frame 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 ) # Recompute FOV only on player move fov_recompute = False # Clean up the screen libtcod.console_flush() clear_all( con, entities ) # INPUT HANDLERS 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') # Entity Turn Logics # PLAYER TURN # Combat Results player_turn_results = [] # 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_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 # PASS TURN game_state = GameStates.ENEMY_TURN # Pickup 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: # If item x,y == player x,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)) # Show Inventory if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY # Drop Inventory if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY # Inventory Index 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)) # ESC Key Logic if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state else: return True # Fullscreen if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) # Handling end of player turn 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 # ENEMY TURN # Handling the 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 # Pass turn back to Player else: game_state = GameStates.PLAYERS_TURN
def main(): # some initializations, main console title = 'NOIGUE L.C.' tcod.sys_set_fps(LIMIT_FPS) tcod.console_set_custom_font( "arial10x10.png", tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD,) tcod.console_init_root(SCREEN_WIDTH, SCREEN_HEIGHT, title, renderer=tcod.RENDERER_SDL2, order="F") con = tcod.console.Console(MAP_WIDTH, MAP_HEIGHT) con.default_fg = tcod.white game_state = GameStates.INTRO_SCREEN # inputs key = tcod.Key() mouse = tcod.Mouse() while not tcod.console_is_window_closed(): tcod.sys_check_for_event( tcod.EVENT_KEY_PRESS, key, mouse) if game_state == GameStates.INTRO_SCREEN: game_state = start_screen(con, game_state, key, title) elif game_state == GameStates.EXIT: break elif game_state == GameStates.CLASS_CHOICE: game_state = class_choice(con, game_state, key, title) elif game_state == GameStates.PLAYERS_TURN: # start pyo server pyo_server = Server(duplex=0).boot() pyo_server.start() # create player player = Entity(0, 0, '@', tcod.white, 'Player', blocks=True, type=Noiseur(sound=Noise()), inventory=Inventory(26), render=RenderOrder.ENTITY) player.type.sound_out() entities = [player] previous_game_state = game_state # create sub-panels panels = [] panel = Panel(0, CAMERA_HEIGHT, SCREEN_WIDTH, SCREEN_HEIGHT-CAMERA_HEIGHT, "log") panels.append(panel) panel = Panel(CAMERA_WIDTH, 0, SCREEN_WIDTH - CAMERA_WIDTH, CAMERA_HEIGHT, "sidebar") panels.append(panel) message_log = MessageLog( 2, SCREEN_WIDTH-4, SCREEN_HEIGHT-CAMERA_HEIGHT-2) # create game map and place entities, fov camera = Camera() game_map = GameMap() game_map.make_map(player, entities) fov = FOV(game_map) # compute fov fov.recompute_fov(player) # main loop targeting_item = None while not tcod.console_is_window_closed(): # get events tcod.sys_check_for_event( tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse) # render everything render_all(con, panels, entities, player, game_map, fov, message_log, game_state, camera) tcod.console_flush() clear_all(con, panels, entities, camera) # get action from keyboard 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') if show_inventory: previous_game_state = game_state game_state=GameStates.SHOW_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') # deal with actions player_turn_results = [] if game_state == GameStates.PLAYERS_TURN: if move: 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 not target: player.move(dx, dy) fov.recompute = True game_state = GameStates.ENEMY_TURN elif pickup : 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)) if game_state == GameStates.SHOW_INVENTORY: if inventory_index is not None and inventory_index < len(player.inventory.items): item = player.inventory.items[inventory_index] player_turn_results.extend(player.inventory.use(item, entities=entities, fov_map=fov.map)) 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=int(target_x+camera.x), target_y=int(target_y+camera.y)) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) for player_turn_result in player_turn_results: message = player_turn_result.get('message') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') if message: message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, entity, fov, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') if message: message_log.add_message(message) else: game_state = GameStates.PLAYERS_TURN if exit: if game_state == GameStates.SHOW_INVENTORY: game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: pyo_server.stop() return True if fullscreen: tcod.console_set_fullscreen( not tcod.console_is_fullscreen())
def main(): # Game and map constants screen_width = 80 screen_height = 50 # HP Bar paramters bar_width = 20 # Panel for bars panel_height = 7 panel_y = screen_height - panel_height # Message bar message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 # Map size map_width = 80 map_height = 43 # Room parameters room_max_size = 10 room_min_size = 6 max_rooms = 30 # FoV Variables fov_algoritm = 0 fov_light_walls = True fov_radius = 10 # Entity limits max_monsters_per_room = 3 max_items_per_room = 2 colors = { '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) } fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', tcod.white, 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] tcod.console_set_custom_font( 'Bisasam_24x24.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_CP437) tcod.console_init_root(screen_width, screen_height, 'tcodtutorial revised', False, renderer=tcod.RENDERER_SDL2) con = tcod.console.Console(screen_width, screen_height) panel = tcod.console.Console(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 = tcod.Key() mouse = tcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state 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) 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 tcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) move = action.get('move') pickup = action.get('pickup') exit = action.get('exit') fullscreen = action.get('fullscreen') show_inventory = action.get('show_inventory') inventory_index = action.get('inventory_index') player_turn_results = [] # Move and/or attack action 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 # Picking up an item elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message('There is nothing here to pick up.', tcod.yellow)) # Open inventory if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] print(item.name) # Exit game if exit: if game_state == GameStates.SHOW_INVENTORY: # Escape from inventory menu back to game game_state = previous_game_state else: return True # Set to fullscreen if fullscreen: tcod.console_set_fullscreen((not tcod.console_is_fullscreen())) ## PROCESS PLAYER'S TURN 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 has 'ai', i.e. can move or attack etc, get 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) mouse = libtcod.Mouse() key = libtcod.Key() game_state = GameStates.RACE_SELECTION 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') see_skills = action.get('see_skills') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') skills_index = action.get('skill_index') take_stairs = action.get('take_stairs') level_up = action.get('level_up') job = action.get('job') show_character_screen = action.get('show_character_screen') race = action.get('race') exit = action.get('exit') fullscreen = action.get('fullscreen') job_menu = action.get('job_menu') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] print(game_state) if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if player.fighter.status_effects.grace == True: player.fighter.nutrition -= 50 else: player.fighter.nutrition -= 1 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 job_menu: game_state = GameStates.JOB_MENU if see_skills: previous_game_state = game_state game_state = GameStates.SKILL_SELECTION 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 skills_index is not None and previous_game_state != GameStates.PLAYER_DEAD and skills_index < len( player.skills.skills): item = player.skills.skills[skills_index] if game_state == GameStates.SKILL_SELECTION: player_turn_results.extend( player.skills.use(item, entities=entities, fov_map=fov_map)) if take_stairs and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.stairs and entity.x == player.x and entity.y == player.y: entities = game_map.next_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True libtcod.console_clear(con) break elif entity.upstairs and entity.x == player.x and entity.y == player.y: entities = game_map.previous_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 = GameStates.CLASS_SELECTION if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if job: if job == 'cleric': player.fighter.job.cleric_level += 1 elif job == 'fighter': player.fighter.job.fighter_level += 1 elif job == 'thief': player.fighter.job.thief_level += 1 elif job == 'wizard': player.fighter.job.wizard_level += 1 game_state = previous_game_state if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click if targeting_item.skill: item_use_results = player.skills.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) else: 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 == GameStates.JOB_MENU: game_state = GameStates.CHARACTER_SCREEN elif game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN, GameStates.SKILL_SELECTION): 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') skill_targeting = player_turn_result.get('skill_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 skill_targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = skill_targeting message_log.add_message(targeting_item.skill.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 race: if race == 'mern': player.fighter.race = 'Human' player.fighter.levels_quickly = True elif race == 'elf': player.fighter.race = 'Elf' player.fighter.base_defense += 2 player.fighter.base_constitution -= 2 elif race == 'dwarf': player.fighter.race = 'Dwarf' player.fighter.base_defense -= 2 player.fighter.base_constitution += 2 elif race == 'halfling': player.fighter.race = 'Halfling' player.fighter.base_defense += 4 player.fighter.base_power -= 3 player.fighter.base_constitution -= 1 elif race == 'gnome': player.fighter.race = 'Gnome' player.fighter.base_constitution += 2 player.fighter.base_willpower += 2 player.fighter.base_power -= 4 elif race == 'draconian': player.fighter.race = 'Draconian' player.fighter.large = True player.fighter.base_constitution += 3 player.fighter.base_defense -= 4 player.fighter.base_power += 3 elif race == 'orc': player.fighter.race = 'Orc' player.fighter.base_constitution += 1 player.fighter.base_defense -= 3 player.fighter.base_power += 2 elif race == 'goblin': player.fighter.race = 'Goblin' player.fighter.base_constitution += 1 player.fighter.base_defense -= 3 player.fighter.base_power += 2 elif race == 'fairy': player.fighter.race = 'Fairy' player.fighter.base_constitution -= 6 player.fighter.base_defense += 6 player.fighter.base_power -= 6 skill_component = Skill(use_function=become_accurate) skill = Skill_Entity('Faerie Dance', skill=skill_component) player.skills.add_skill(skill) elif race == 'turtle': player.fighter.race = 'Giant Turtle' player.fighter.base_constitution += 8 player.fighter.base_defense -= 12 player.fighter.base_power += 3 player.fighter.large = True player.fighter.cant_wear_armour = True elif race == 'lizard': player.fighter.race = 'Lizardperson' skill_component = Skill( use_function=acid_spit, targeting=True, targeting_message=Message( 'Left-click a target tile for the spit, or right-click to cancel.', libtcod.light_cyan), damage=25) skill = Skill_Entity('Acid Spit', skill=skill_component) player.skills.add_skill(skill) player.fighter.base_defense -= 2 player.fighter.base_power += 3 elif race == 'frog': player.fighter.race = 'Frogperson' player.fighter.base_defense += 3 player.fighter.base_power -= 2 skill_component = Skill(use_function=become_graceful) skill = Skill_Entity('Slimy Skin', skill=skill_component) player.skills.add_skill(skill) elif race == 'giant': player.fighter.race = 'Giant' player.fighter.base_defense -= 7 player.fighter.base_power += 5 player.fighter.base_constitution += 5 player.fighter.large = True elif race == 'troll': player.fighter.race = 'Troll' player.fighter.base_defense -= 7 player.fighter.base_power += 4 player.fighter.base_constitution += 2 player.fighter.large = True player.fighter.carnivore = True player.fighter.sharp_claws = True elif race == 'skeleton': player.fighter.race = 'Skeleton' player.fighter.base_power += 1 player.fighter.base_constitution += 1 player.fighter.base_defense -= 4 elif race == 'biter': player.fighter.race = 'Biter' player.fighter.base_constitution -= 2 player.fighter.base_defense += 4 player.player.fighter.sharp_claws = True elif race == 'kobold': player.fighter.race = 'Kobold' player.fighter.base_power -= 3 player.fighter.base_defense += 3 player.fighter.large = True elif race == 'chaosling': player.fighter.race = 'chaosling' player.fighter.base_power += 2 player.fighter.base_defense += 2 player.fighter.base_constitution += 2 player.fighter.base_willpower -= 6 player.fighter.hates_law = True elif race == 'reaper': player.fighter.race = 'Reaper' player.fighter.base_power += 4 player.fighter.base_constitution += 2 player.fighter.base_willpower -= 10 player.fighter.bloodthirsty = True elif race == 'nymph': player.fighter.race = 'Nymph' player.fighter.base_power -= 5 player.fighter.base_defense += 5 elif race == 'octopode': player.fighter.race = 'Octopode' player.fighter.base_defense += 3 player.fighter.eight_arms = True player.fighter.cant_wear_armour = True elif race == 'cat': player.fighter.race = 'Housecat' player.fighter.base_defense += 6 player.fighter.base_constitution -= 3 elif race == 'merfolk': player.fighter.race = 'Merfolk' player.fighter.swimmer = True player.fighter.base_defense += 3 player.fighter.base_constitution += 3 player.fighter.base_power -= 4 elif race == 'mud': player.fighter.race = 'Mud Man' skill_component = Skill( use_function=throw_mudball, targeting=True, targeting_message=Message( 'Left-click a target tile for the ball, or right-click to cancel.', libtcod.light_cyan), damage=25) skill = Skill_Entity('Throw Mudball', skill=skill_component) player.skills.add_skill(skill) player.fighter.base_defense += 3 player.fighter.base_constitution -= 3 elif race == 'dryad': player.fighter.race = 'Dryad' player.fighter.one_with_nature = True player.fighter.base_power += 4 player.fighter.base_defence -= 4 elif race == 'naga': player.fighter.race = 'Naga' skill_component = Skill( use_function=poison_bite, targeting=True, targeting_message=Message( 'Left-click a target tile for the bite, or right-click to cancel.', libtcod.light_cyan), damage=25) skill = Skill_Entity('Naga Bite', skill=skill_component) player.skills.add_skill(skill) player.fighter.base_defense += 4 player.fighter.base_power -= 4 player.fighter.no_legs = True elif race == 'golem': player.fighter.race = 'Rogue Golem' player.fighter.golem = True player.fighter.base_defense += 10 player.fighter.base_power += 10 player.fighter.base_willpower += 13 elif race == 'tengu': player.fighter.race = 'Tengu' player.fighter.base_defense += 4 player.fighter.base_power -= 2 player.fighter.base_constitution -= 3 libtcod.console_flush() game_state = GameStates.PLAYERS_TURN if game_state == GameStates.ENEMY_TURN: if player.fighter.nutrition < 1: game_state = GameStates.PLAYER_DEAD kill_player(player) 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, root_console, panel, hp_bar, xp_bar, constants): root_console.clear(fg=(255, 255, 255)) fov_map = initialize_fov(game_map) fov_recompute = True key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN turn_number = 0 turns_passed = 0 start_turn = 0 previous_game_state = game_state targeting_item = None exploring = False resting = False to_down_stairs = False while True: 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( root_console, panel, hp_bar, xp_bar, entities, player, game_map, fov_map, message_log, constants['root_width'], constants['root_height'], constants['game_window_width'], constants['game_window_height'], constants['panel_width'], constants['panel_height'], constants['stat_bar_width'], constants['stat_bar_height'], constants['fx_panel_width'], constants['fx_panel_height'], constants['camera_width'], constants['camera_height'], game_state, turn_number) fov_recompute = False custrender.clear((0, 0, 0)) custrender.accumulate( root_console, custrender.get_viewport(root_console, True, True)) custrender.present() clear_all(root_console, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') wait = action.get('wait') rest = action.get('rest') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') show_loadout = action.get('show_loadout') look = action.get('look') inventory_index = action.get('inventory_index') loadout_index = action.get('loadout_index') take_stairs = action.get('take_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') show_ability_screen = action.get('show_ability_screen') esc_menu = action.get('esc_menu') help = action.get('help') exit = action.get('exit') quit = action.get('quit') fullscreen = action.get('fullscreen') auto_explore = action.get('auto_explore') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') target_x = player.x target_y = player.y player_turn_results = [] # For all actions that do not return to the main menu, recompute fov (prevents off-screen window drawing errors) if action != quit and action != fullscreen and not resting: fov_recompute = True root_console.clear(fg=(255, 255, 255)) if move and game_state == GameStates.PLAYERS_TURN: if exploring: exploring = False previous_game_state = game_state message_log.add_message( Message('Autoexploration cancelled.', libtcod.yellow)) elif resting: resting = False previous_game_state = game_state message_log.add_message( Message('You stop resting.', libtcod.yellow)) elif to_down_stairs: to_down_stairs = False previous_game_state = game_state message_log.add_message( Message('You stop heading towards the stairs.', libtcod.yellow)) 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, game_map) game_state = GameStates.ENEMY_TURN if auto_explore and game_state == GameStates.PLAYERS_TURN: if entities_in_fov(entities, fov_map, message_log): game_state = GameStates.PLAYERS_TURN elif GameMap.explore(game_map, player, message_log) is True: game_state = GameStates.ENEMY_TURN exploring = True else: exploring = False if exploring and game_state == GameStates.PLAYERS_TURN: if entities_in_fov(entities, fov_map, message_log): game_state = GameStates.PLAYERS_TURN exploring = False elif GameMap.explore(game_map, player, message_log) is True: game_state = GameStates.ENEMY_TURN exploring = True else: exploring = False elif wait: game_state = GameStates.ENEMY_TURN elif rest and game_state == GameStates.PLAYERS_TURN: if player.fighter.current_hp == player.fighter.base_max_hp: message_log.add_message( Message('You are already at full health.', libtcod.yellow)) elif entity_in_fov(entities, fov_map): message_log.add_message( Message('You cannot rest when enemies are nearby.', libtcod.yellow)) elif player.fighter.current_hp < player.fighter.base_max_hp: game_state = GameStates.ENEMY_TURN resting = True start_turn = turn_number else: resting = False if resting and game_state == GameStates.PLAYERS_TURN: if player.fighter.current_hp == player.fighter.base_max_hp: resting = False message_log.add_message( Message( 'You rest for {0} turns, returning to max HP.'.format( turns_passed), libtcod.yellow)) elif entities_in_fov(entities, fov_map, message_log): message_log.add_message( Message( 'You rested for a total of {0} turns.'.format( turns_passed), libtcod.yellow)) resting = False fov_recompute = True else: turns_passed = turn_number - start_turn 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.pick_up(player, entity) entities.remove(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.inv_items): item = player.inventory.inv_items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(player, item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend( player.inventory.drop_item(player, item)) if show_loadout: previous_game_state = game_state game_state = GameStates.SHOW_LOADOUT if loadout_index is not None and previous_game_state != GameStates.PLAYER_DEAD and loadout_index < len( player.inventory.equip_items): item = player.inventory.equip_items[loadout_index] if game_state == GameStates.SHOW_LOADOUT: player_turn_results.extend( player.inventory.dequip(player, item)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend( player.inventory.drop_item(player, item)) if look: previous_game_state = game_state game_state = GameStates.LOOK 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) fov_map = initialize_fov(game_map) message_log.add_message( Message( f'You descend to level {game_map.dungeon_level} of the ' f'SludgeWorks...', libtcod.yellow)) break else: if entities_in_fov(entities, fov_map, message_log): game_state = GameStates.PLAYERS_TURN elif GameMap.to_down_stairs(game_map, player, entities, message_log) is True: game_state = GameStates.ENEMY_TURN to_down_stairs = True if to_down_stairs and game_state == GameStates.PLAYERS_TURN: if entities_in_fov(entities, fov_map, message_log): game_state = GameStates.PLAYERS_TURN to_down_stairs = False elif GameMap.to_down_stairs(game_map, player, entities, message_log) is True: game_state = GameStates.ENEMY_TURN else: to_down_stairs = False if level_up: hit_dice = roll_dice(1, 8) player.fighter.level += 1 player.fighter.base_max_hp += roll_dice( 1, hit_dice + player.fighter.vitality_modifier) if level_up == 'str': player.fighter.base_strength += 1 elif level_up == 'agi': player.fighter.base_dexterity += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_ability_screen: previous_game_state = game_state game_state = GameStates.ABILITY_SCREEN if game_state == GameStates.TARGETING: libtcod.console_wait_for_keypress(True) target_overlay(root_console, constants['game_window_width'], constants['game_window_height'], target_x, target_y) if move: dx, dy = move target_x += dx target_y += dy if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(player, 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 esc_menu: if exploring: exploring = False previous_game_state = game_state message_log.add_message( Message('Autoexploration cancelled.', libtcod.yellow)) elif resting: resting = False previous_game_state = game_state message_log.add_message( Message('You stop resting.', libtcod.yellow)) elif to_down_stairs: to_down_stairs = False previous_game_state = game_state message_log.add_message( Message('You stop heading towards the stairs.', libtcod.yellow)) else: previous_game_state = game_state game_state = GameStates.ESC_MENU if help: game_state = GameStates.HELP_MENU if exit: if game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) return True else: game_state = previous_game_state if quit and not game_state == GameStates.PLAYER_DEAD: save_game(player, entities, game_map, message_log, game_state) return True elif quit: delete_char_save() 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') equipped = player_turn_result.get('equipped') dequipped = player_turn_result.get('dequipped') 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, entities) message_log.add_message(message) if item_added or item_consumed or equipped or dequipped: 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( 'You level up! You are now 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.name == 'Phosphorescent Dahlia' and entity_in_fov( entities, fov_map): # Cycle through colours for the phosphorescent dahlia dahlia_colour = [ libtcod.light_azure, libtcod.azure, libtcod.dark_azure ] entity.colour = choice(dahlia_colour) if entity.ai: if entity.regenerates: # Heal-over time effect for enemies that regenerate if turn_number % 4 == 0: if entity.fighter.current_hp < entity.fighter.base_max_hp: entity.fighter.current_hp += 1 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, entities) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: # Heal-over time effect for the player if turn_number % 4 == 0: if player.fighter.current_hp < player.fighter.base_max_hp: player.fighter.current_hp += 1 turn_number += 1 game_state = GameStates.PLAYERS_TURN
def target_with_accuracy(owner, target_x, target_y, accuracy, game_map, entities): blocked = False acc_roll = libtcod.random_get_int(0, 0, 100) if DEBUG: print('DEBUG {} actual target: {}, {}'.format(owner.name, target_x, target_y)) print('DEBUG {} roll: {}, accuracy: {}'.format(owner.name, acc_roll, accuracy)) if acc_roll < accuracy: # hit! return target newtarget_x = target_x newtarget_y = target_y hit = 'yes' else: # miss! continue the line a bit longer to allow the projectile to keep moving xoff = libtcod.random_get_int(0, 1, 1) yoff = libtcod.random_get_int(0, 1, 1) pos_or_neg = libtcod.random_get_int(0, 0, 1) if pos_or_neg: target_x = target_x + xoff else: target_x = target_x - xoff pos_or_neg = libtcod.random_get_int(0, 0, 1) if pos_or_neg: target_y = target_y + yoff else: target_y = target_y - yoff # build new line extending out much further newtarget_x = 2 * target_x - 1 * owner.x newtarget_y = 2 * target_y - 1 * owner.y # make sure its in the game map if newtarget_x <= 0: newtarget_y = newtarget_y - newtarget_x newtarget_x = 0 if DEBUG: print('DEBUG {} out_of_map, using {}, {}'.format( owner.name, newtarget_x, newtarget_y)) elif newtarget_x >= game_map.width - 1: newtarget_y = newtarget_y - (newtarget_x - game_map.width - 1) newtarget_x = game_map.width - 1 if DEBUG: print('DEBUG {} out_of_map, using {}, {}'.format( owner.name, newtarget_x, newtarget_y)) if newtarget_y <= 0: newtarget_x = newtarget_x - newtarget_y newtarget_y = 0 if DEBUG: print('DEBUG {} out_of_map, using {}, {}'.format( owner.name, newtarget_x, newtarget_y)) elif newtarget_y >= game_map.height - 1: newtarget_x = newtarget_x - (newtarget_y - game_map.height - 1) newtarget_y = game_map.height - 1 if DEBUG: print('DEBUG {} out_of_map, using {}, {}'.format( owner.name, newtarget_x, newtarget_y)) for pts in libtcod.line_iter(owner.x, owner.y, newtarget_x, newtarget_y): if game_map.is_blocked( pts[0], pts[1]) or get_blocking_entities_at_location( entities, pts[0], pts[1]): if (pts[0], pts[1]) != (owner.x, owner.y): if DEBUG: print('DEBUG {} blocked'.format(owner.name)) newtarget_x = pts[0] newtarget_y = pts[1] break hit = 'no' if DEBUG: print('DEBUG {} failed roll, new target: {}, {}, player: {}, {}'. format(owner.name, newtarget_x, newtarget_y, owner.x, owner.y)) if game_map.is_blocked(newtarget_x, newtarget_y): blocked = True return hit, blocked, newtarget_x, newtarget_y
def main(): screen_width = 80 screen_height = 50 bar_width = 20 panel_height = 7 paney_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 = 1 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_wall': libtcod.Color(175, 170, 135), 'light_ground': libtcod.Color(200, 180, 50) #'light_ground': libtcod.Color(235, 220, 170) } 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] # sets font for console libtcod.console_set_custom_font( 'arial12x12.png', libtcod.FONT_TYPE_GRAYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial', False) con = libtcod.console.Console(screen_width, screen_height) panel = libtcod.console.Console(screen_width, panel_height) # initialize the 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) 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 = GamesStates.PLAYERS_TURN while not libtcod.console_is_window_closed(): # captures new events 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, paney_y, mouse, colors) fov_recompute = False 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 == GamesStates.PLAYERS_TURN: dx, dy = move destinaiton_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destinaiton_x, destination_y): target = get_blocking_entities_at_location( entities, destinaiton_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 = GamesStates.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: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GamesStates.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 == GamesStates.PLAYER_DEAD: break if game_state == GamesStates.PLAYER_DEAD: break else: game_state = GamesStates.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.PLAYER_TURN previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], mouse, constants['colors'], game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if move and game_state == GameStates.PLAYER_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYER_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message('There is nothing here to pick up.', libtcod.yellow)) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.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 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 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 = 'BASIC' fov_light_walls = True fov_radius = 10 max_monsters_per_room = 3 max_items_per_room = 2 colors = { 'dark_wall': (0, 0, 100), 'dark_ground': (50, 50, 150), 'light_wall': (130, 110, 50), 'light_ground': (200, 180, 50), 'desaturated_green': (63, 127, 63), 'darker_green': (0, 127, 0), 'dark_red': (191, 0, 0), 'white': (255, 255, 255), 'black': (0, 0, 0), 'red': (255, 0, 0), 'orange': (255, 127, 0), 'light_red': (255, 114, 114), 'darker_red': (127, 0, 0), 'violet': (127, 0, 255), 'yellow': (255, 255, 0), 'blue': (0, 0, 255), 'green': (0, 255, 0), 'light_cyan': (114, 255, 255), 'light_pink': (255, 114, 184) } fighter_component = Fighter(hp=30, defense=2, power=5) inventory_component = Inventory(26) player = Entity(0, 0, '@', (255, 255, 255), 'Player', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, inventory=inventory_component) entities = [player] tdl.set_font('arial10x10.png', greyscale=True, altLayout=True) root_console = tdl.init(screen_width, screen_height, title='Roguelike Tutorial Revised') con = tdl.Console(screen_width, screen_height) panel = tdl.Console(screen_width, panel_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, max_items_per_room, colors) fov_recompute = True message_log = MessageLog(message_x, message_width, message_height) mouse_coordinates = (0, 0) game_state = GameStates.PLAYERS_TURN previous_game_state = game_state 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, panel, entities, player, game_map, fov_recompute, root_console, message_log, screen_width, screen_height, bar_width, panel_height, panel_y, mouse_coordinates, 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') 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 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 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, colors) player_turn_results.extend(pickup_results) break else: message_log.add_message(Message('There is nothing here to pick up.', 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, colors, entities=entities, game_map=game_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item, colors)) if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, 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): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: 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') 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, colors) else: message = kill_monster(dead_entity, 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 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, 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, colors) else: message = kill_monster(dead_entity, 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(): 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'], constants['window_title'], False) con = libtcod.console_new(constants['screen_width'], constants['screen_height']) panel = libtcod.console_new(constants['screen_width'], constants['panel_height']) player, entities, game_map, message_log, game_state = get_game_variables( constants) fov_recompute = True # used to tell algo when to change field of view, i.e. only when moving not when standing still/attacking fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() previous_game_state = game_state # Used to not skip a players turn if they do something like pick up an item targeting_item = None while not libtcod.console_is_window_closed( ): # a loop that won't end until the game window is closed libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse ) # this captures user input and updates the key/mouse variables above if fov_recompute: recompute_fov( fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) # coming from fov_functions 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 ) # con is the current console, entities is drawn in render_functions fov_recompute = False libtcod.console_flush() # this presents everything on screen clear_all( con, entities ) # put a blank below our character so it doesn't leave a trail, see render_functions.py """Action Handling""" action = handle_keys( key, game_state ) # calls our handle keys function from the input_handlers file, using our key variable, to result in a dictionary called action mouse_action = handle_mouse(mouse) move = action.get( 'move' ) # uses the action dictionary created above to return move, exit, pickup or fullscreen from handle_keys function pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: # i.e. does something to the target blocking the way attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) # gets move function from entity class fov_recompute = True # sets fov to True (i.e. to change) when we move game_state = GameStates.ENEMY_TURN # switches it to the enemies turn after moving 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 # ref'd at top, stops it skipping to enemies turn game_state = GameStates.SHOW_INVENTORY # switching to this game state with different keys if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state # now the Esc key just exits the inventory menu, rather than the whole game 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 = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: # note, the player and items etc won't have an AI component, so this skips them enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities ) # take turn managed in ai file, tells it to move towards or attack player 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, panel_bg, info, info_bg, player_con, player_con_bg, constants, permanent_cooldown_counter): 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 targeting_feat = None game_turn_counter = 0 cooldown_counter = permanent_cooldown_counter while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: fov_map = initialize_fov(game_map) recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, panel, panel_bg, info, info_bg, player_con, player_con_bg, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['map_width'], constants['map_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], constants['info_width'], constants['info_x'], constants['player_con_width'], constants['player_con_x'], constants['player_con_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') show_abilities = action.get('show_abilities') use = action.get('use') drop = action.get('drop') inventory_index = action.get('inventory_index') ability_index = action.get('ability_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 if game_map.is_door(destination_x, player.y): message_log.add_message( Message('The door creaks open.', libtcod.yellow)) 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 inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item_index = inventory_index item = player.inventory.items[inventory_index][0] item.selected = True game_state = GameStates.ITEM_MENU if use: player_turn_results.extend( player.inventory.use(item, item_index, entities=entities, fov_map=fov_map)) game_state = GameStates.SHOW_INVENTORY if game_state != GameStates.TARGETING: item.selected = False else: item.selected = True elif drop: player_turn_results.extend( player.inventory.drop_item(item, item_index)) item.selected = False if show_abilities: previous_game_state = game_state game_state = GameStates.SHOW_ABILITIES if ability_index is not None and previous_game_state != GameStates.PLAYER_DEAD and ability_index < len( player.abilities.feats): feat = player.abilities.feats[ability_index] if feat.turn_performed is None or ( cooldown_counter - feat.turn_performed > feat.cooldown): player_turn_results.extend( player.abilities.perform( feat, turn_performed=cooldown_counter, entities=entities, fov_map=fov_map, ability_power=player.fighter.ability_power)) else: message_log.add_message( Message('That ability is on cooldown.', libtcod.white)) 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_strength += 1 elif level_up == 'def': player.fighter.base_defense += 1 elif level_up == 'dog': player.fighter.base_dodge += 3 elif level_up == 'ap': player.fighter.base_ability_power += 2 elif level_up == 'crit': player.fighter.base_crit_chance += 5 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 if hasattr(targeting, 'item'): item_use_results = player.inventory.use(targeting_item, item_index, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) item.selected = False else: if feat.turn_performed is None or game_state == GameStates.TARGETING or ( cooldown_counter - feat.turn_performed > feat.cooldown): feat_use_results = player.abilities.perform( targeting_feat, turn_performed=cooldown_counter, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y, ability_power=player.fighter.ability_power) player_turn_results.extend(feat_use_results) else: message_log.add_message( Message('That ability is on cooldown.', libtcod.white)) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.SHOW_ABILITIES, GameStates.CHARACTER_SCREEN): game_state = previous_game_state for item in player.inventory.items: if hasattr(item[0], 'selected') and item[0].selected: item[0].selected = False elif game_state == GameStates.ITEM_MENU: for item in player.inventory.items: if hasattr(item[0], 'selected') and item[0].selected: item[0].selected = False game_state = GameStates.SHOW_INVENTORY elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) for item in player.inventory.items: if hasattr(item[0], 'selected') and item[0].selected: item[0].selected = False else: save_game(player, entities, game_map, message_log, game_state, cooldown_counter) 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') feat_performed = player_turn_result.get('performed') item_dropped = player_turn_result.get('item_dropped') enemy_item_dropped = player_turn_result.get('enemy_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, loot = kill_monster(dead_entity) if loot is not None: player_turn_results.extend( dead_entity.inventory.drop_item( loot[0], dead_entity.inventory.items.index(loot))) 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 feat_performed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if enemy_item_dropped: entities.append(enemy_item_dropped) if equip: equip_results = player.equipment.toggle_equip(equip) for equip_result in equip_results: equipped = equip_result.get('equipped') unequipped = equip_result.get('unequipped') 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 if hasattr(targeting, 'item'): targeting_item = targeting message_log.add_message( targeting_item.item.targeting_message) else: targeting_feat = targeting message_log.add_message(targeting_feat.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( 'You have faced enough horrors and grow stronger, you reach level {0}' .format(player.level.curr_level) + '!', libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if game_state == GameStates.ENEMY_TURN: game_turn_counter += 1 cooldown_counter += 1 for feat in player.abilities.feats: if feat.turn_performed is not None: if ((cooldown_counter - 1) - feat.turn_performed) < feat.cooldown: feat.turn_ready = str(feat.cooldown - (cooldown_counter - feat.turn_performed) + 1) else: feat.turn_ready = "Ready!" for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities, game_turn_counter) 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, loot = 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(): #Set the initial variables constants = get_constants() color_palette = Palette() kolors = color_palette.get_colors() mod_key = 'none' mouse = 'none' #Build and initialize the random monster rosters cr = RosterLists() cr.build_roster_lists() cr.build_monster_manual() current_roster = cr.get_roster_lists() current_mm = cr.get_monster_manual() #Set the font file and settings tcod.console_set_custom_font( constants['font_file'], tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) tcod.console_map_ascii_codes_to_font(256, 32, 0, 1) #map all characters in 2nd row tcod.console_map_ascii_codes_to_font(256 + 32, 32, 0, 2) #map all characters in 3rd row #Create the screen, the root console root_con = tcod.console_init_root( constants['screen_width'], constants['screen_height'], constants['screen_title'], constants['screen_fullscreen'], constants['screen_renderer'], constants['screen_order'], constants['screen_vsync']) #Create another console where we'll draw before overlaying it on the root main_con = tcod.console.Console(constants['screen_width'], constants['screen_height'], constants['screen_order']) #Create panel console for the hp bar and message log panel_con = tcod.console.Console(constants['screen_width'], constants['panel_height'], constants['screen_order']) #Initialize player, entities, game_map player, entities, game_map, indoors, message_log, game_state = get_game_variables( constants, kolors, current_roster, current_mm) interface_skin = 'Tutorial' #Choices: Graph, Tutorial if interface_skin == 'Graph': color_palette.set_color('dark_wall', 70, 130, 180) color_palette.set_color('dark_ground', 70, 130, 180) #Initialize FOV and calculate on start fov_recompute = True fov_map = initialize_fov(game_map) game_type = 'normal' #choices normal, viewer #Initialize the message log # message_log = MessageLog(constants['message_x'], constants['message_width'], constants['message_height']) #Initialize main loop # game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None end_game = False while not end_game: #Recomput FOV if necessary if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) #Render all entities & tiles on main console and blit them to the root console render_all(main_con, root_con, panel_con, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], kolors, game_type, interface_skin, indoors, constants['hp_bar_width'], constants['panel_height'], constants['panel_y'], mouse, game_state) #Reset FOV check fov_recompute = False #Update the console with our changes tcod.console_flush() #Erase all entities on main console so they won't smear on next update clear_all(main_con, entities) #initialize loop variables action = {'none': True} mouse_action = {'none': True} #Detect and handle events for event in tcod.event.get(): if event.type == "QUIT": #Window was closed action = {'exit': True} elif event.type == "KEYUP" and event.sym == 1073742049: mod_key = 'none' elif event.type == "KEYDOWN": #A key was depressed if event.mod == True and event.sym == 1073742049: mod_key = 'l_shift' action = handle_keys(event, mod_key, game_state) elif event.type == "MOUSEMOTION": #Mouse was moved mouse = event.tile elif event.type == "MOUSEBUTTONDOWN": mouse = event.tile mouse_action = handle_mouse(mouse, event.button) #else: #print(event) #Get action type 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') error = action.get('error') wait = action.get('wait') vision = action.get('vision') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') #List to store the results of damage player_turn_results = [] #Process player actions if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy #If no terrain is blocking then try to move the player if not game_map.is_blocked(destination_x, destination_y): #If no entity is blocking then move the player 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) #Recalculate FOV if player moves 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.', tcod.yellow)) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if 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 exit == 'menu' and game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: if exit == True: end_game = True if error: error_text = error print("Error detected", error_text) if vision and game_state == GameStates.PLAYERS_TURN: if vision == 'third eye': if interface_skin == 'Tutorial': interface_skin = third_eye('open_eye', color_palette, indoors) elif interface_skin == 'Graph': interface_skin = third_eye('close_eye', color_palette, indoors) #Recalculate FOV fov_recompute = True game_state = GameStates.ENEMY_TURN if wait and game_state == GameStates.PLAYERS_TURN: if game_type == 'viewer': entities = game_map.next_map(player, map_type, constants, entities, kolors, current_roster, current_mm) fov_map = initialize_fov(game_map) fov_recompute = True main_con.clear(fg=(0, 0, 0)) else: game_state = GameStates.ENEMY_TURN #Process player turn results for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') targeting = player_turn_result.get('targeting') 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 = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN #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: 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, world_map, message_log, game_state, current_enemy, con, panel, constants): # print("entities: ") # for entity in entities: # print(entity.name) current_map = world_map.maps[world_map.x][world_map.y] # entities = current_map.entities # print("entities: ") # for entity in entities: # print(entity.name) fov_recompute = True fov_map = initialize_fov(current_map) key = tcod.Key() mouse = tcod.Mouse() previous_game_state = game_state targeting_item = None player_target = Target(0,0) #main game loop while not tcod.console_is_window_closed(): #updates the key and mouse variables with any key or mouse events tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS, key, mouse) if fov_recompute: fov_map = initialize_fov(current_map) recompute_fov(fov_map, player, constants['fov_radius'], entities, constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, panel, entities, player, current_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, current_enemy, player_target) tcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) move = action.get('move') exit = action.get('exit') fullscreen = action.get('fullscreen') pickup = action.get('pickup') show_inventory = action.get('show_inventory') inventory_index = action.get('inventory_index') drop_inventory = action.get('drop_inventory') look = action.get('look') move_target = action.get('move_target') target_selected = action.get('target_selected') player_turn_results = [] #Current errors: # (FIXED) x and y are being set to default make_map values in opposite moves # diagonal moves off the edge of the map cause a crash # !!!FOCUS!!! entity lists are not attached to maps, so buildings remain while entities refresh # Need to readd player to returning maps #!!!!!!!!! #WHEN A USER SAVES AND LOADS ON A GAME_MAP, A PERMANENT "DUMB" COPY OF #THEIR BODY IS LEFT AT THE POSITION THEY SAVED AND LOADED #UPON SUBSEQUENT RETURNS TO THE MAP # #THE GLITCH ONLY OCCURS WHEN THE USER LEAVES THE MAP #SOMEHOW, PLAYER IS KEPT IN ENTITIES OVER TRANSITIONS #Each gamemap needs a copy of player? (maybe) #If you save and load multiple times on one map before leaving it, the #dumb copy spawns at the first position you saved and loaded at. #!!!!!!!!! if move and game_state == GameStates.PLAYER_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if destination_x == current_map.width: if world_map.x < 9: world_map.move_to(world_map.x+1, world_map.y, constants, player) current_map = world_map.maps[world_map.x][world_map.y] entities = current_map.entities destination_x = 0 dx = 0 player.x = 0 player.y = destination_y else: destination_x = player.x destination_y = player.y message_log.add_message(Message('You can\'t go that way', tcod.blue)) print(str(world_map.x)+" ,"+str(world_map.y)) elif destination_y == current_map.height: if world_map.y > 0: world_map.move_to(world_map.x, world_map.y-1, constants, player) current_map = world_map.maps[world_map.x][world_map.y] entities = current_map.entities destination_y = 0 dy = 0 player.y = 0 player.x = destination_x else: destination_x = player.x destination_y = player.y message_log.add_message(Message('You can\'t go that way', tcod.blue)) print(str(world_map.x)+" ,"+str(world_map.y)) elif destination_x == -1: if world_map.x > 0: world_map.move_to(world_map.x-1, world_map.y, constants, player) current_map = world_map.maps[world_map.x][world_map.y] entities = current_map.entities destination_x = current_map.width-1 dx = 0 player.x = current_map.width-1 player.y = destination_y else: destination_x = player.x destination_y = player.y message_log.add_message(Message('You can\'t go that way', tcod.blue)) print(str(world_map.x)+" ,"+str(world_map.y)) elif destination_y == -1: if world_map.y < 9: world_map.move_to(world_map.x, world_map.y+1, constants, player) current_map = world_map.maps[world_map.x][world_map.y] entities = current_map.entities destination_y = current_map.height-1 dy = 0 player.y = current_map.height-1 player.x = destination_x else: destination_x = player.x destination_y = player.y message_log.add_message(Message('You can\'t go that way', tcod.blue)) print(str(world_map.x)+" ,"+str(world_map.y)) if not current_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location(entities, destination_x, destination_y) if target: if target.fighter and target != player: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) elif target.breakable: 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.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)) 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 look: previous_game_state = game_state player_target.set(player.x, player.y) game_state = GameStates.LOOKING 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 exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.LOOKING): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, world_map, message_log, game_state, current_enemy) return True if fullscreen: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) if game_state == GameStates.TARGETING: if move_target: dx, dy = move_target player_target.move(dx, dy) if target_selected: item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=player_target.x, target_y=player_target.y) player_turn_results.extend(item_use_results) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') destroyed_entity = player_turn_result.get('destroyed') 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 destroyed_entity: message = destroy_object(destroyed_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYER_TURN game_state = GameStates.TARGETING player_target.set(player.x, player.y) 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, current_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 if game_state == GameStates.LOOKING and move_target: dx, dy = move_target player_target.move(dx, dy)
def play_game(player, entities, game_map, message_log, game_state, con, panel, constants): fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): libtcod.sys_check_for_event(libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) render_all(con, panel, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['bar_width'], constants['panel_height'], constants['panel_y'], mouse, constants['colors'], game_state) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse) move = action.get('move') wait = action.get('wait') pickup = action.get('pickup') show_inventory = action.get('show_inventory') drop_inventory = action.get('drop_inventory') inventory_index = action.get('inventory_index') take_stairs = action.get('take_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location(entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message(Message('There is nothing here to pick up.', libtcod.yellow)) if show_inventory: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY if drop_inventory: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( player.inventory.items): item = player.inventory.items[inventory_index] if game_state == GameStates.SHOW_INVENTORY: player_turn_results.extend(player.inventory.use(item, entities=entities, fov_map=fov_map)) elif game_state == GameStates.DROP_INVENTORY: player_turn_results.extend(player.inventory.drop_item(item)) if take_stairs and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.stairs and entity.x == player.x and entity.y == player.y: entities = game_map.next_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True libtcod.console_clear(con) break else: message_log.add_message(Message('There are no stairs here.', libtcod.yellow)) if level_up: if level_up == 'hp': player.fighter.max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.power += 1 elif level_up == 'def': player.fighter.defense += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) elif right_click: player_turn_results.append({'targeting_cancelled': True}) if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') xp = player_turn_result.get('xp') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) if xp: leveled_up = player.level.add_xp(xp) message_log.add_message(Message('You gain {0} experience points.'.format(xp))) if leveled_up: message_log.add_message(Message( 'Your battle skills grow stronger! You reached level {0}'.format( player.level.current_level) + '!', libtcod.yellow)) previous_game_state = game_state game_state = GameStates.LEVEL_UP if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn(player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN
def play_game(player, entities, game_map, message_log, game_state, root_console, con, panel, lexicon, constants): tdl.set_font('resources/arial10x10.png', greyscale=True, altLayout=True) fov_recompute = True fov_radius = 2 if player.body.l_eye.state.name != 'LOST': fov_radius += 9 if player.body.r_eye.state.name != 'LOST': fov_radius += 9 mouse_coordinates = (0, 0) previous_game_state = game_state #game_state = GameStates.HELP_SCREEN targeting_item = None invisible_turns = 0 verse = '' reading_scroll = None message_log.add_message(Message("Press '?' for Help Screen")) #uncomment the next line to facilitate manual testing of new spells print(lexicon) while not tdl.event.is_window_closed(): if fov_recompute: fov_radius = 2 if player.body.l_eye.state.name != 'LOST': fov_radius += 4 if player.body.r_eye.state.name != 'LOST': fov_radius += 4 game_map.compute_fov(player.x, player.y, fov=constants['fov_algorithm'], radius=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, reading_scroll) 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_down_stairs = action.get('take_down_stairs') take_up_stairs = action.get('take_up_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') show_body_screen = action.get('show_body_screen') show_help_screen = action.get('show_help_screen') look_around = action.get('look_around') cast_spell = action.get('cast_spell') letter = action.get('letter') exit = action.get('exit') fullscreen = action.get('fullscreen') make_visible = False 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: if not player.fighter.visible: invisible_turns -= 1 if invisible_turns <= 0: make_visible = True 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) if not player.fighter.visible: player.fighter.make_visible() message_log.add_message( Message('You are visible again!')) else: player.move(dx, dy) fov_recompute = True game_state = GameStates.ENEMY_TURN elif wait and game_state == GameStates.PLAYERS_TURN: player.body.pump_blood() for entity in entities: if entity.fountain and entity.x == player.x and entity.y == player.y: if entity.fountain.water: entity.fountain.drink(player) message_log.add_message( Message('You drink and feel refreshed.', constants['colors'].get('blue'))) else: message_log.add_message( Message('The fountain is dry.', constants['colors'].get('yellow'))) 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 and game_state != GameStates.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: if item.name.split()[0] == 'Scroll': game_state = GameStates.READ_SCROLL reading_scroll = item else: 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 look_around: if game_state != GameStates.UNDERWORLD: seen = ', '.join([ entity.name for entity in entities if game_map.fov[entity.x, entity.y] and entity is not player and not entity.ghost ]) message_log.add_message( Message('You see: {0}.'.format(seen), constants['colors'].get('white'))) else: seen = ', '.join([ entity.name for entity in entities if game_map.fov[entity.x, entity.y] and entity is not player and entity.ghost ]) message_log.add_message( Message('You see: {0}.'.format(seen), constants['colors'].get('white'))) if cast_spell: message_log.add_message( Message('You begin a magic spell incantation.', constants['colors'].get('white'))) previous_game_state = game_state game_state = GameStates.CASTING_SPELL if letter: if letter == '.': magic_verse = [] for i in verse.split(): if player.caster.mana > 0 and player.caster.focus > 0: player.caster.mana -= 1 player.caster.focus -= 1 magic_verse.append(i) verse = ' '.join(translate(magic_verse, lexicon)) message_log.add_message( Message(verse, constants['colors'].get('white'))) spell_results = player.caster.cast_spell( verse.split(), game_map, entities, constants['colors']) verse = '' player_turn_results.extend(spell_results) else: verse += letter if take_down_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.stairs.direction == 'down': save_floor(player, entities, game_map) game_map, entities = next_floor( player, message_log, entity.stairs.floor, constants, lexicon, 'down') fov_recompute = True con.clear() break else: message_log.add_message( Message('These are not down stairs.', constants['colors'].get('yellow'))) break else: message_log.add_message( Message('There are no stairs here.', constants['colors'].get('yellow'))) if take_up_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.stairs.direction == 'up': save_floor(player, entities, game_map) game_map, entities = next_floor( player, message_log, entity.stairs.floor, constants, lexicon, 'up') fov_recompute = True con.clear() break else: message_log.add_message( Message('These are not up stairs.', constants['colors'].get('yellow'))) 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 += 2 elif level_up == 'def': player.fighter.base_defense += 1 elif level_up == 'mp': player.caster.base_max_mana += 2 player.caster.mana += 2 elif level_up == 'fcs': player.caster.base_max_focus += 1 player.caster.focus += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if show_body_screen: previous_game_state = game_state game_state = GameStates.BODY_SCREEN if show_help_screen: previous_game_state = game_state game_state = GameStates.HELP_SCREEN if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(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, GameStates.HELP_SCREEN, GameStates.BODY_SCREEN): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) elif game_state == GameStates.READ_SCROLL: game_state = GameStates.PLAYERS_TURN else: save_game(player, entities, game_map, message_log, game_state, lexicon) return True if fullscreen: tdl.set_fullscreen(not tdl.get_fullscreen()) if make_visible: player.fighter.make_visible() make_visible = False message_log.add_message(Message('You are visible again!')) game_state = GameStates.ENEMY_TURN 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') magic_xp = player_turn_result.get('magic_xp') invisible = player_turn_result.get('invisible') spell_cast = player_turn_result.get('spell_cast') spell_failed = player_turn_result.get('spell_failed') if invisible: invisible_turns = player_turn_result.get('invisible_turns') game_state = GameStates.ENEMY_TURN if make_visible: player.fighter.make_visible() make_visible = False message_log.add_message(Message('You are visible again!')) game_state = GameStates.ENEMY_TURN 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, constants['colors']) else: message = kill_monster(dead_entity, entities, constants['colors']) message_log.add_message(message) if item_added: if not player.fighter.visible: invisible_turns -= 1 if invisible_turns <= 0: make_visible = True entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: if not player.fighter.visible: invisible_turns -= 1 if invisible_turns <= 0: make_visible = True game_state = GameStates.ENEMY_TURN if item_dropped: if not player.fighter.visible: invisible_turns -= 1 if invisible_turns <= 0: make_visible = True entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if spell_cast: if not player.fighter.visible: invisible_turns -= 1 if invisible_turns <= 0: make_visible = True game_state = GameStates.ENEMY_TURN if spell_failed: if not player.fighter.visible: invisible_turns -= 1 if invisible_turns <= 0: make_visible = True 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_stat = 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 xp: leveled_up = player.level.add_fighter_xp(xp) message_log.add_message( Message('You gain {0} experience points.'.format(xp))) if leveled_up: message_log.add_message( Message( 'Your fighting skills improve! You reach combat level {0}' .format(player.level.fighter_level) + '!', constants['colors'].get('yellow'))) previous_game_state = game_state game_state = GameStates.LEVEL_UP if magic_xp: magic_leveled_up = player.level.add_caster_xp(magic_xp) message_log.add_message( Message('You gain {0} magic experience points.'.format( magic_xp))) if magic_leveled_up: message_log.add_message( Message( 'Your casting skills improve! You reach magic level {0}' .format(player.level.caster_level) + '!', constants['colors'].get('yellow'))) previous_game_state = game_state game_state = GameStates.MAGIC_LEVEL_UP if game_state == GameStates.ENEMY_TURN: if player.caster.focus < player.caster.max_focus: player.caster.focus += player.caster.regeneration for entity in entities: if entity.body and entity.body.alive: body_turn_results = entity.body.take_turn() for result in body_turn_results: dead_entity = result.get('dead') message = result.get('message') if dead_entity: if dead_entity == player: message, game_state = kill_player( dead_entity, constants['colors']) else: message = kill_monster(dead_entity, entities, constants['colors']) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if message: message_log.add_message(message) if entity.ai and entity.body.animated: 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') xp = enemy_turn_result.get('xp') if message: message_log.add_message(message) if xp: leveled_up = player.level.add_fighter_xp(xp) if leveled_up: message_log.add_message( Message( 'Your fighting skills improve! You reach combat level {0}' .format(player.level.fighter_level) + '!', constants['colors'].get('yellow'))) previous_game_state = game_state game_state = GameStates.LEVEL_UP if dead_entity: if dead_entity == player: message, game_state = kill_player( dead_entity, constants['colors']) else: message = kill_monster(dead_entity, entities, constants['colors']) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: if game_state == GameStates.LEVEL_UP: previous_game_state = GameStates.PLAYERS_TURN else: game_state = GameStates.PLAYERS_TURN