def main(): # map vars map_width = 40 map_height = 60 room_min_size = 6 room_max_size = 10 max_rooms = 50 max_monsters_per_room = 3 max_items_per_room = 2 # screen vars viewport_width = 80 viewport_height = 60 rerender_viewport = True map_x = viewport_width map_y = 0 screen_width = viewport_width + map_width # stats panel vars bar_width = 20 panel_width = screen_width panel_height = 8 panel_x = 0 panel_y = viewport_height message_x = bar_width + 2 message_width = screen_width - bar_width - 2 message_height = panel_height - 1 screen_height = viewport_height + panel_height # fov vars fov_algorithm = 12 fov_light_walls = True fov_radius = 10 fov_recompute = True # game vars game_state = GameStates.PLAYER_TURN previous_game_state = game_state colours = { 'dark_wall': tcod.Color(0, 0, 100), 'dark_ground': tcod.Color(50, 50, 150), 'light_wall': tcod.Color(130, 110, 50), 'light_ground': tcod.Color(200, 180, 50) } # init player fighter_component = Fighter(30, 2, 5) inventory_component = Inventory(26) player = Entity(0, 0, '@', tcod.white, 'Player', render_order=RenderOrder.ACTOR, blocks=True, fighter=fighter_component, inventory=inventory_component) player_rot = 0.0 entities = [player] # load assets wall_texture = Image.open('assets/wall_vines0.png') orc_texture = Image.open('assets/orc.png') troll_texture = Image.open('assets/troll.png') potion_texture = Image.open('assets/ruby.png') # init game map game_map = GameMap(map_width, map_height) game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room, max_items_per_room, orc_texture, troll_texture, potion_texture) game_map.recompute_fov(player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # init message log message_log = MessageLog(message_x, message_width, message_height) tcod.console_set_custom_font( 'arial10x10.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) with tcod.console_init_root(screen_width, screen_height, 'firstpersonroguelike', vsync=True) as root_console: viewport_console = tcod.console.Console(viewport_width, viewport_height) map_console = tcod.console.Console(map_width, map_height) panel_console = tcod.console.Console(panel_width, panel_height) mouse = (0, 0) time_start = perf_counter() # game loop begin while True: for event in tcod.event.wait(): tcod.console_flush() player_turn_results = [] # handle inputs if event.type == "QUIT": raise SystemExit() elif event.type == "MOUSEMOTION": # record the new mouse position, render_all will take care of the rest mouse = event.tile # player keyboard interaction elif event.type == "KEYDOWN": action = handle_keys(event, game_state) if len(action) == 0: continue elif action.get('exit'): if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): game_state = previous_game_state else: raise SystemExit() elif action.get( 'pickup') and game_state is GameStates.PLAYER_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item( entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message( 'You inspect the empty ground below you. Looks pretty dirty', tcod.yellow)) game_state = GameStates.ENEMIES_TURN elif action.get('show_inventory' ) and game_state is GameStates.PLAYER_TURN: previous_game_state = game_state game_state = GameStates.SHOW_INVENTORY elif action.get('drop_inventory' ) and game_state is GameStates.PLAYER_TURN: previous_game_state = game_state game_state = GameStates.DROP_INVENTORY elif action.get( 'inventory_index' ) is not None and previous_game_state is not GameStates.PLAYER_DEAD: inventory_index = action.get('inventory_index') if inventory_index < len(player.inventory.items): item = player.inventory.items[inventory_index] if game_state is GameStates.SHOW_INVENTORY: message_log.add_message( Message('Used ' + item.name)) player_turn_results.extend( player.inventory.use_item(item)) elif game_state is GameStates.DROP_INVENTORY: message_log.add_message( Message('Dropped ' + item.name)) player_turn_results.extend( player.inventory.drop_item(item)) game_state = GameStates.ENEMIES_TURN elif action.get( 'move') and game_state is GameStates.PLAYER_TURN: dx, dy = action.get('move') to_x, to_y = player.x + dx, player.y + dy if game_map.walkable(to_x, to_y): target = get_blocking_entities_at_location( entities, to_x, to_y) if target: player_turn_results.extend( player.fighter.attack(target)) else: player.move(dx, dy) fov_recompute = True # end our turn game_state = GameStates.ENEMIES_TURN elif action.get( 'move2') and game_state is GameStates.PLAYER_TURN: to_x = player.x to_y = player.y if action.get('move2') == 'forward': to_x += int(math.sin(player_rot) * 1.5) to_y += int(math.cos(player_rot) * 1.5) elif action.get('move2') == 'rearward': to_x -= int(math.sin(player_rot) * 1.5) to_y -= int(math.cos(player_rot) * 1.5) if game_map.walkable(to_x, to_y): target = get_blocking_entities_at_location( entities, to_x, to_y) if target: player_turn_results.extend( player.fighter.attack(target)) else: player.x = to_x player.y = to_y fov_recompute = True # end our turn game_state = GameStates.ENEMIES_TURN elif action.get( 'turn') and game_state is GameStates.PLAYER_TURN: dir = action.get('turn') if dir == 'left': player_rot += math.pi / 4.0 elif dir == 'right': player_rot -= math.pi / 4.0 rerender_viewport = True # end_switch event.type # process player's turn results for ptr in player_turn_results: message = ptr.get('message') dead_entity = ptr.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(player) else: message = kill_monster(dead_entity) message_log.add_message(message) if ptr.get('item_added'): entities.remove(ptr.get('item_added')) if ptr.get('item_dropped'): entities.append(ptr.get('item_dropped')) # end_for player_turn_results # run the enemy turn if game_state is GameStates.ENEMIES_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, game_map, entities) for etr in enemy_turn_results: message = etr.get('message') dead_entity = etr.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity is player: message, game_state = kill_player( player) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state is GameStates.PLAYER_DEAD: break if game_state is GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYER_TURN # endif enemy turn if fov_recompute: game_map.recompute_fov(player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # draw each part of the screen render_viewport( root_console, viewport_console, 0, 0, viewport_width, viewport_height, game_map, entities, colours, player.x, player.y, player_rot, fov_radius, rerender_viewport or game_state is GameStates.ENEMIES_TURN, wall_texture) render_map(root_console, map_console, game_map, entities, map_x, map_y, colours, fov_recompute) # TODO: extend render_menu to accept a top-left co-ordinate (start_x, start_y) render_menu(root_console, player, screen_width, screen_height, game_state) fps = 1.0 / (perf_counter() - time_start) render_panel(root_console, panel_console, entities, player, game_map, message_log, bar_width, panel_width, panel_height, panel_x, panel_y, mouse, fps) time_start = perf_counter() tcod.console_flush() clear_all(map_console, entities) fov_recompute = False
def main(): # Importing data from config with open('data/config.json') as cfg: data=json.load(cfg) terminal_width=data['terminal_width'] terminal_height=data['terminal_height'] map_width=data['map_width'] map_height=data['map_height'] fov_algorithm=data['fov_algorithm'] fov_light_walls=data['fov_light_walls'] fov_radius=data['fov_radius'] # Init root console tcod.console_set_custom_font('gfx/fonts/terminal12x16_gs_ro.png', tcod.FONT_TYPE_GREYSCALE | tcod.tcod.FONT_LAYOUT_CP437) console_root=tcod.console_init_root(terminal_width, terminal_height, 'Python Game Lol', False, tcod.RENDERER_SDL2, 'C', False) console_display=tcod.console.Console(terminal_width, terminal_height, 'C') with open('gfx/palette.json') as colours: palette=json.load(colours) console_display.bg[:]=palette['terminal_green'] #console_interface=tcod.console.Console(terminal_width, map_height, 'C') game_map=GameMap(map_width, map_height) spawner=Spawner(map_width, map_height, 0) # Testing creatures generate_test_area(game_map, spawner) player=spawner.entities[0] # Then generate map fov_recompute=True # message log game_state=GameStates.TURN_PLAYER prev_game_state=game_state #targeting_item=None # Rendering for the first time game_map.recompute_fov(player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(console_root, console_display, spawner.entities, game_map, fov_recompute) fov_recompute=False tcod.console_flush() # Game loop while True: # Render if fov_recompute: game_map.recompute_fov(player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) render_all(console_root, console_display, spawner.entities, game_map, fov_recompute) fov_recompute=False tcod.console_flush() erase_entities(console_display, spawner.entities, game_map) # Processing action action=handle_event(game_state) move=action.get('move') pickup=action.get('pickup') take_inventory=action.get('take_inventory') fullscreen=action.get('fullscreen') exit=action.get('exit') # Player's Turn results_player=[] # Results: Extend if player turn ends and append if doesn't? Tcod tutorial is confusing. if game_state==GameStates.TURN_PLAYER: if move: dx, dy=move results_movement=player.handle_move(dx, dy, spawner, game_map.path_map, swappable=True) if results_movement: results_player.extend(results_movement) fov_recompute=True game_state=GameStates.TURN_ALLY elif pickup: # Should implement a pickup list like POWDER for entity in spawner.entities: if entity.item and entity.x==player.x and entity.y==player.y: print('ADD ITEM') # Add item break else: print('GRAB GROUND') # Message log to grab ground if take_inventory: prev_game_state=game_state game_state=GameStates.MENU_INVENTORY if exit: if game_state.value>=10: # Game states >= 10 are menus: inventory, quipment, etc. game_state=prev_game_state if game_state.value>=20: # Game states >= 20 are targetings results_player.append({'targeting_cancelled': True}) # else brings up main menu if fullscreen: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) # Player turn messages: handled by an announcer (translation friendly probably) # Faction turns (handled by an announcer also) if game_state==GameStates.TURN_ALLY: for entity in spawner.entities: if entity.faction==Factions.ALLY and entity!=player: results_ally=entity.ai.take_turn(spawner, game_map.path_map) game_state=GameStates.TURN_ENEMY if game_state==GameStates.TURN_ENEMY: for entity in spawner.entities: if entity.faction==Factions.ENEMY: results_enemy=entity.ai.take_turn(spawner, game_map.path_map) game_state=GameStates.TURN_NEUTRAL if game_state==GameStates.TURN_NEUTRAL: for entity in spawner.entities: if entity.faction==Factions.NEUTRAL: if entity.ai: resutls_neutral=entity.ai.take_turn(spawner, game_map.path_map) game_state=GameStates.TURN_PLAYER