def add_item(self, item_to_add): results = [] if len(self.items) >= self.capacity: results.append({ 'item_added': None, 'message': Message('You cannot carry any more, your inventory is full') }) else: results.append({ 'item_added': item_to_add, 'message': Message( 'You pick up {0} {1}!'.format(item_to_add.number, item_to_add.name), colors.get('green')) }) item_added = False for item in self.items: if item.name == item_to_add.name: item.number += item_to_add.number item_added = True if not item_added: self.items.append(item_to_add) return results
def use(self, item_entity, **kwargs): results = [] item_component = item_entity.item if item_component.use_function is None: equippable_component = item_entity.equippable if equippable_component: results.append({'equip': item_entity}) else: results.append({ 'message': Message('The {0} cannot be used'.format(item_entity.name), colors.get('red')) }) else: if item_component.targeting and not (kwargs.get('target_x') or kwargs.get('target_y')): results.append({'targeting': item_entity}) else: kwargs = {**item_component.function_kwargs, **kwargs} item_use_results = item_component.use_function( self.owner, **kwargs) for item_use_result in item_use_results: if item_use_result.get('consumed'): self.remove_item(item_entity) results.extend(item_use_results) return results
def main_menu(con, background_image, screen_width, screen_height, window_title): libtcod.image_blit_2x(background_image, 0, 0, 0) libtcod.console_set_default_foreground(0, colors.get('light')) menu(con, window_title, ['Play a new game', 'Continue last game', 'Quit'], int(screen_width / 2) - 8, int(screen_width / 2), screen_height, 'dark', 'light')
def menu(con, header, options, width, screen_width, screen_height, background='light', foreground='dark'): if len(options) > 26: raise ValueError('Cannot have a menu with more than 26 options.') # calculate total height for the header (after auto-wrap) and one line per option header_height = libtcod.console_get_height_rect(con, 0, 0, width, screen_height, header) + 2 height = len(options) + header_height + 1 # create an off-screen console that represents the menu's window window = libtcod.console_new(width, height) # print the header, with auto-wrap libtcod.console_set_default_foreground(window, colors.get(foreground)) libtcod.console_set_default_background(window, colors.get(background)) libtcod.console_clear(window) libtcod.console_print_rect_ex(window, 1, 1, width, height, libtcod.BKGND_SET, libtcod.LEFT, header) # print all the options y = header_height letter_index = ord('a') for option_text in options: text = '(' + chr(letter_index) + ') ' + option_text libtcod.console_print_ex(window, 1, y, libtcod.BKGND_SET, libtcod.LEFT, text) y += 1 letter_index += 1 libtcod.console_print_ex(window, 1, y, libtcod.BKGND_SET, libtcod.LEFT, " ") # blit the contents of "window" to the root console x = int(screen_width / 2 - width / 2) y = int(screen_height / 2 - height / 2) libtcod.console_blit(window, 0, 0, width, height, 0, x, y, 1.0, 1.0)
def character_screen(player, character_screen_width, character_screen_height, screen_width, screen_height): window = libtcod.console_new(character_screen_width, character_screen_height) libtcod.console_set_default_foreground(window, colors.get('dark')) libtcod.console_set_default_background(window, colors.get('light')) libtcod.console_clear(window) libtcod.console_print_rect_ex(window, 1, 1, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'CHARACTER INFORMATION') libtcod.console_print_rect_ex( window, 1, 2, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'Level: {0}'.format(player.level.current_level)) libtcod.console_print_rect_ex( window, 1, 3, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'Experience: {0}'.format(player.level.current_xp)) libtcod.console_print_rect_ex( window, 1, 4, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'Experience to Level: {0}'.format( player.level.experience_to_next_level)) libtcod.console_print_rect_ex( window, 1, 6, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'Maximum HP: {0}'.format(player.fighter.max_hp)) libtcod.console_print_rect_ex(window, 1, 7, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'Attack: {0}'.format(player.fighter.power)) libtcod.console_print_rect_ex( window, 1, 8, character_screen_width + 2, character_screen_height, libtcod.BKGND_SET, libtcod.LEFT, 'Defense: {0}'.format(player.fighter.defense)) x = screen_width // 2 - character_screen_width // 2 y = screen_height // 2 - character_screen_height // 2 libtcod.console_blit(window, 0, 0, character_screen_width, character_screen_height, 0, x, y, 1.0, 1.0)
def kill_monster(monster): death_message = Message('{0} is dead!'.format(monster.name.capitalize()), colors.get('green')) # monster.color = colors.get('dark') monster.blocks = False monster.fighter = None monster.ai = None monster.name = 'remains of ' + monster.name monster.render_order = RenderOrder.CORPSE return death_message
def next_floor(self, player, message_log, constants): self.dungeon_level += 1 entities = [player] self.tiles = self.initialize_tiles() self.make_map(constants['max_rooms'], constants['room_min_size'], constants['room_max_size'], constants['map_width'], constants['map_height'], player, entities) player.fighter.heal(player.fighter.max_hp // 2) message_log.add_message( Message('You take a moment to rest, and recover your strength.', colors.get('green'))) return entities
def drop_item(self, item): results = [] if self.owner.equipment.main_hand == item or self.owner.equipment.off_hand == item: self.owner.equipment.toggle_equip(item) item.x = self.owner.x item.y = self.owner.y self.remove_item(item) results.append({ 'item_dropped': item, 'message': Message('You dropped the {0}'.format(item.name), colors.get('dark')) }) return results
def __init__(self, text, color=colors.get('dark')): self.text = text self.color = color
def render_all(con, panel, tooltip, messages_pane, inventory_pane, entities, player, game_map, fov_map, fov_recompute, message_log, screen_width, screen_height, map_width, map_height, panel_width, panel_height, panel_x, mouse, colors, cam_x, cam_y, anim_frame, game_state, targeting_item, log_scroll, log_height, inv_scroll, inv_height, inv_selected): libtcod.console_clear(0) if fov_recompute or game_state == GameStates.TARGETING: # Draw all the tiles in the game map libtcod.console_set_default_foreground(con, libtcod.white) for y in range(game_map.height): for x in range(game_map.width): visible = libtcod.map_is_in_fov(fov_map, x, y) wall = game_map.tiles[x][y].block_sight if visible: if game_state == GameStates.TARGETING and distanceBetween( math.floor((mouse.cx + cam_x) / 3), math.ceil((mouse.cy + cam_y) / 2), x, y) <= targeting_item.item.targeting_radius: backcolor = colors.get('red') else: backcolor = colors.get('light') game_map.tiles[x][y].explored = True else: backcolor = colors.get('dark') libtcod.console_set_char_background(con, x * 3, y * 2, backcolor, libtcod.BKGND_SET) libtcod.console_set_char_background(con, x * 3 + 1, y * 2, backcolor, libtcod.BKGND_SET) libtcod.console_set_char_background(con, x * 3 + 2, y * 2, backcolor, libtcod.BKGND_SET) libtcod.console_set_char_background(con, x * 3, y * 2 + 1, backcolor, libtcod.BKGND_SET) libtcod.console_set_char_background(con, x * 3 + 1, y * 2 + 1, backcolor, libtcod.BKGND_SET) libtcod.console_set_char_background(con, x * 3 + 2, y * 2 + 1, backcolor, libtcod.BKGND_SET) if (game_map.tiles[x][y].explored or visible) and wall: libtcod.console_put_char(con, x * 3, y * 2, tiles.get('wall_tile'), libtcod.BKGND_NONE) libtcod.console_put_char(con, x * 3 + 1, y * 2, tiles.get('wall_tile') + 1, libtcod.BKGND_NONE) libtcod.console_put_char(con, x * 3 + 2, y * 2, tiles.get('wall_tile') + 2, libtcod.BKGND_NONE) libtcod.console_put_char(con, x * 3, y * 2 + 1, tiles.get('wall_tile') + 32, libtcod.BKGND_NONE) libtcod.console_put_char(con, x * 3 + 1, y * 2 + 1, tiles.get('wall_tile') + 33, libtcod.BKGND_NONE) libtcod.console_put_char(con, x * 3 + 2, y * 2 + 1, tiles.get('wall_tile') + 34, libtcod.BKGND_NONE) # Draw all entities in the list entities_in_render_order = sorted(entities, key=lambda x: x.render_order.value) for entity in entities_in_render_order: draw_entity(con, entity, fov_map, anim_frame, game_map, game_state) libtcod.console_blit(con, 0, 0, map_width * 3, map_height * 2, 0, -cam_x, -cam_y) libtcod.console_set_default_background(panel, colors.get('light')) libtcod.console_set_default_foreground(panel, colors.get('dark')) libtcod.console_clear(panel) # Print the game messages, one line at a time libtcod.console_print_ex(panel, int(panel_width / 2), 3, libtcod.BKGND_SET, libtcod.CENTER, "-------- Messages --------") libtcod.console_set_default_background(messages_pane, colors.get('light')) libtcod.console_clear(messages_pane) y = 1 for message in message_log.messages: libtcod.console_set_default_foreground(messages_pane, message.color) libtcod.console_print_ex(messages_pane, message_log.x, y, libtcod.BKGND_NONE, libtcod.LEFT, message.text) y += 1 # if log_scroll > y - log_height: # log_scroll = y - log_height libtcod.console_blit(messages_pane, 0, y - log_height - log_scroll, panel_width - 3, log_height, panel, 2, 4) # libtcod.console_set_default_background(panel, colors.get('dark')) # libtcod.console_set_default_foreground(panel, colors.get('light')) # libtcod.console_put_char(panel, panel_width-1, 5, " ", libtcod.BKGND_SET) libtcod.console_put_char(panel, panel_width - 2, 4, tiles.get('up_tile'), libtcod.BKGND_SET) # libtcod.console_put_char(panel, panel_width-3, 5, " ", libtcod.BKGND_SET) # libtcod.console_put_char(panel, panel_width-1, 5+log_height, " ", libtcod.BKGND_SET) libtcod.console_put_char(panel, panel_width - 2, 4 + log_height, tiles.get('down_tile'), libtcod.BKGND_SET) # libtcod.console_put_char(panel, panel_width-3, 5+log_height, " ", libtcod.BKGND_SET) # Print the inventory items # libtcod.console_set_default_background(panel, colors.get('light')) # libtcod.console_set_default_foreground(panel, colors.get('dark')) libtcod.console_print_ex(panel, int(panel_width / 2), 5 + log_height, libtcod.BKGND_SET, libtcod.CENTER, "-------- Backpack --------") libtcod.console_set_default_foreground(panel, colors.get('green')) libtcod.console_print_ex(panel, int(panel_width / 2), 6 + log_height, libtcod.BKGND_SET, libtcod.CENTER, "<> select | [u]se | [d]rop") libtcod.console_set_default_background(inventory_pane, colors.get('light')) libtcod.console_clear(inventory_pane) y = 1 for item in player.inventory.items: if y == inv_selected + 1: libtcod.console_set_default_background(inventory_pane, colors.get('dark')) libtcod.console_set_default_foreground(inventory_pane, colors.get('light')) else: libtcod.console_set_default_background(inventory_pane, colors.get('light')) libtcod.console_set_default_foreground(inventory_pane, colors.get('dark')) if player.equipment.main_hand == item: libtcod.console_print_ex( inventory_pane, 0, y, libtcod.BKGND_SET, libtcod.LEFT, '{0} ({1}) (main)'.format(item.name, item.number)) elif player.equipment.off_hand == item: libtcod.console_print_ex( inventory_pane, 0, y, libtcod.BKGND_SET, libtcod.LEFT, '{0} ({1}) (off)'.format(item.name, item.number)) else: libtcod.console_print_ex( inventory_pane, 0, y, libtcod.BKGND_SET, libtcod.LEFT, '{0} ({1})'.format(item.name, item.number)) y += 1 libtcod.console_blit(inventory_pane, 0, y - inv_height, panel_width - 3, inv_height, panel, 2, 7 + log_height) render_bar(panel, 2, 1, panel_width - 4, 'Health', player.fighter.hp, player.fighter.max_hp, colors.get('green'), colors.get('dark'), colors.get('light')) libtcod.console_set_default_foreground(panel, colors.get('dark')) # libtcod.console_print_ex(panel, 1, 3, libtcod.BKGND_NONE, libtcod.LEFT, 'Dungeon level: {0}'.format(game_map.dungeon_level)) libtcod.console_set_default_background(panel, colors.get('light')) libtcod.console_set_default_foreground(panel, colors.get('dark')) for y in range(0, screen_height): libtcod.console_put_char(panel, 0, y, tiles.get('gradient_tile'), libtcod.BKGND_SET) libtcod.console_set_default_foreground(panel, colors.get('dark')) libtcod.console_set_default_background(panel, colors.get('light')) libtcod.console_blit(panel, 0, 0, panel_width, panel_height, 0, panel_x, 0) tooltip_text = get_names_under_mouse(cam_x, cam_y, mouse, entities, fov_map) tooltip_len = len(tooltip_text) libtcod.console_set_default_background(tooltip, libtcod.black) libtcod.console_clear(tooltip) libtcod.console_set_default_foreground(tooltip, colors.get('light')) libtcod.console_set_default_background(tooltip, colors.get('dark')) libtcod.console_print_ex(tooltip, 0, 0, libtcod.BKGND_SET, libtcod.LEFT, tooltip_text) libtcod.console_set_key_color(tooltip, libtcod.black) libtcod.console_blit(tooltip, 0, 0, tooltip_len, 1, 0, mouse.cx + 2, mouse.cy + 1) if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY): if game_state == GameStates.SHOW_INVENTORY: inventory_title = 'Use or equip item.\n' else: inventory_title = 'Drop an item.\n' inventory_menu(con, inventory_title, player, 50, screen_width, screen_height) elif game_state == GameStates.LEVEL_UP: level_up_menu(con, 'Level up! Choose a stat to raise:', player, 40, screen_width, screen_height) elif game_state == GameStates.CHARACTER_SCREEN: character_screen(player, 30, 10, screen_width, screen_height)
def kill_player(player): #player.char = '%' #player.color = colors.get('dark') return Message('You died!', colors.get('light')), GameStates.PLAYER_DEAD
def play_game(player, entities, game_map, message_log, con, panel, tooltip, messages_pane, inventory_pane, constants, cam_x, cam_y, anim_frame, anim_time, log_scroll, log_height, inv_scroll, inv_height, inv_selected): fov_recompute = True fov_map = initialize_fov(game_map) key = libtcod.Key() mouse = libtcod.Mouse() game_state = GameStates.PLAYERS_TURN previous_game_state = game_state targeting_item = None while not libtcod.console_is_window_closed(): anim_frame, anim_time = animation(anim_frame, anim_time) libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if fov_recompute: recompute_fov(fov_map, player.x, player.y, constants['fov_radius'], constants['fov_light_walls'], constants['fov_algorithm']) log_height, inv_height = update_panels_heights( player, constants['panel_height']) render_all(con, panel, tooltip, messages_pane, inventory_pane, entities, player, game_map, fov_map, fov_recompute, message_log, constants['screen_width'], constants['screen_height'], constants['map_width'], constants['map_height'], constants['panel_width'], constants['panel_height'], constants['panel_x'], mouse, colors, cam_x, cam_y, anim_frame, game_state, targeting_item, log_scroll, log_height, inv_scroll, inv_height, inv_selected) fov_recompute = False libtcod.console_flush() clear_all(con, entities) action = handle_keys(key, game_state) mouse_action = handle_mouse(mouse, cam_x, cam_y) move = action.get('move') wait = action.get('wait') pickup = action.get('pickup') # show_inventory = action.get('show_inventory') prev_inventory = action.get('prev_inventory') next_inventory = action.get('next_inventory') use_inventory = action.get('use_inventory') drop_inventory = action.get('drop_inventory') # inventory_index = action.get('inventory_index') # toggle_log = action.get('toggle_log') take_stairs = action.get('take_stairs') level_up = action.get('level_up') show_character_screen = action.get('show_character_screen') exit = action.get('exit') fullscreen = action.get('fullscreen') left_click = mouse_action.get('left_click') right_click = mouse_action.get('right_click') player_turn_results = [] #inventory highlight for mouse use if mouse.cx > constants['screen_width'] - constants[ 'panel_width'] and mouse.cy >= constants[ 'panel_height'] - 1 - inv_height and mouse.cy < constants[ 'panel_height'] - 1: inv_selected = mouse.cy - (constants['panel_height'] - 1 - inv_height) if left_click: #move if mouse.cx < player.x * 3 - cam_x and mouse.cx > player.x * 3 - cam_x - 6 and mouse.cy <= player.y * 2 - cam_y + 1 and mouse.cy >= player.y * 2 - cam_y: #move left move = (-1, 0) if mouse.cx > player.x * 3 - cam_x + 2 and mouse.cx < player.x * 3 - cam_x + 9 and mouse.cy <= player.y * 2 - cam_y + 1 and mouse.cy >= player.y * 2 - cam_y: #move right move = (1, 0) if mouse.cx >= player.x * 3 - cam_x and mouse.cx <= player.x * 3 - cam_x + 2 and mouse.cy < player.y * 2 - cam_y and mouse.cy > player.y * 2 - cam_y - 4: #move up move = (0, -1) if mouse.cx >= player.x * 3 - cam_x and mouse.cx <= player.x * 3 - cam_x + 2 and mouse.cy > player.y * 2 - cam_y + 1 and mouse.cy < player.y * 2 - cam_y + 6: #move down move = (0, 1) #use inventory item if mouse.cx > constants['screen_width'] - constants[ 'panel_width'] and mouse.cy >= constants[ 'panel_height'] - 1 - inv_height and mouse.cy < constants[ 'panel_height'] - 1: item = player.inventory.items[mouse.cy - (constants['panel_height'] - 1 - inv_height)] player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 #scroll log if mouse.cx == constants[ 'screen_width'] - 1 or mouse.cx == constants[ 'screen_width'] - 2 or mouse.cx == constants[ 'screen_width'] - 3: if mouse.cy == 4: #scroll message log up log_scroll += 1 if log_scroll > len(message_log.messages) - log_height: log_scroll = len(message_log.messages) - log_height elif mouse.cy == 4 + log_height and log_scroll > 0: # scroll message log down log_scroll -= 1 if right_click: #drop inventory item if mouse.cx > constants['screen_width'] - constants[ 'panel_width'] and mouse.cy >= constants[ 'panel_height'] - 1 - inv_height and mouse.cy < constants[ 'panel_height'] - 1 and len( player.inventory.items) > 0: item = player.inventory.items[mouse.cy - (constants['panel_height'] - 1 - inv_height)] player_turn_results.extend(player.inventory.drop_item(item)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 if next_inventory and inv_selected < len(player.inventory.items) - 1: inv_selected += 1 if prev_inventory and inv_selected > 0: inv_selected -= 1 if use_inventory and game_state != GameStates.PLAYER_DEAD: item = player.inventory.items[inv_selected] player_turn_results.extend( player.inventory.use(item, entities=entities, fov_map=fov_map)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 if drop_inventory and game_state != GameStates.PLAYER_DEAD: item = player.inventory.items[inv_selected] player_turn_results.extend(player.inventory.drop_item(item)) if inv_selected > len(player.inventory.items) - 1: inv_selected = len(player.inventory.items) - 1 if inv_selected < 0: inv_selected = 0 if move and game_state == GameStates.PLAYERS_TURN: dx, dy = move destination_x = player.x + dx destination_y = player.y + dy if not game_map.is_blocked(destination_x, destination_y): target = get_blocking_entities_at_location( entities, destination_x, destination_y) if target: attack_results = player.fighter.attack(target) player_turn_results.extend(attack_results) else: player.move(dx, dy) cam_x, cam_y = update_cam(player, constants) fov_recompute = True else: message_log.add_message( Message('You stupidly walk into the wall. Ouch.')) game_state = GameStates.ENEMY_TURN elif wait: game_state = GameStates.ENEMY_TURN elif pickup and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickup_results = player.inventory.add_item(entity) player_turn_results.extend(pickup_results) break else: message_log.add_message( Message('There is nothing here to pick up.')) # if show_inventory: # previous_game_state = game_state # game_state = GameStates.SHOW_INVENTORY # if inventory_index is not None and previous_game_state != GameStates.PLAYER_DEAD and inventory_index < len( # player.inventory.items): # item = player.inventory.items[inventory_index] # if game_state == GameStates.SHOW_INVENTORY: # player_turn_results.extend(player.inventory.use(item, entities=entities, fov_map=fov_map)) # elif game_state == GameStates.DROP_INVENTORY: # player_turn_results.extend(player.inventory.drop_item(item)) # if toggle_log: # if constants['panel_height'] == constants['screen_height']: # constants['panel_height'] = 5 # else: # constants['panel_height'] = constants['screen_height'] if take_stairs and game_state == GameStates.PLAYERS_TURN: for entity in entities: if entity.stairs and entity.x == player.x and entity.y == player.y: entities = game_map.next_floor(player, message_log, constants) fov_map = initialize_fov(game_map) fov_recompute = True libtcod.console_clear(con) cam_x, cam_y = update_cam(player, constants) break else: message_log.add_message( Message('There are no stairs here.', colors.get('red'))) if level_up: if level_up == 'hp': player.fighter.base_max_hp += 20 player.fighter.hp += 20 elif level_up == 'str': player.fighter.base_power += 1 elif level_up == 'def': player.fighter.base_defense += 1 game_state = previous_game_state if show_character_screen: previous_game_state = game_state game_state = GameStates.CHARACTER_SCREEN if game_state == GameStates.TARGETING: if left_click: target_x, target_y = left_click item_use_results = player.inventory.use(targeting_item, entities=entities, fov_map=fov_map, target_x=target_x, target_y=target_y) player_turn_results.extend(item_use_results) fov_recompute = True elif right_click: player_turn_results.append({'targeting_cancelled': True}) fov_recompute = True if exit: if game_state in (GameStates.SHOW_INVENTORY, GameStates.DROP_INVENTORY, GameStates.CHARACTER_SCREEN): game_state = previous_game_state elif game_state == GameStates.TARGETING: player_turn_results.append({'targeting_cancelled': True}) else: save_game(player, entities, game_map, message_log, game_state) return True if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) for player_turn_result in player_turn_results: message = player_turn_result.get('message') dead_entity = player_turn_result.get('dead') item_added = player_turn_result.get('item_added') item_consumed = player_turn_result.get('consumed') item_dropped = player_turn_result.get('item_dropped') equip = player_turn_result.get('equip') targeting = player_turn_result.get('targeting') targeting_cancelled = player_turn_result.get('targeting_cancelled') xp = player_turn_result.get('xp') if message: message_log.add_message(message) if targeting_cancelled: game_state = previous_game_state message_log.add_message(Message('Targeting cancelled')) fov_recompute = True if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if item_added: entities.remove(item_added) game_state = GameStates.ENEMY_TURN if item_consumed: game_state = GameStates.ENEMY_TURN if targeting: previous_game_state = GameStates.PLAYERS_TURN game_state = GameStates.TARGETING targeting_item = targeting message_log.add_message(targeting_item.item.targeting_message) if item_dropped: entities.append(item_dropped) game_state = GameStates.ENEMY_TURN if equip: equip_results = player.equipment.toggle_equip(equip) for equip_result in equip_results: equipped = equip_result.get('equipped') dequipped = equip_result.get('dequipped') if equipped: message_log.add_message( Message('You equipped the {0}'.format( equipped.name))) if dequipped: message_log.add_message( Message('You unquipped the {0}'.format( dequipped.name))) game_state = GameStates.ENEMY_TURN if xp: leveled_up = player.level.add_xp(xp) message_log.add_message( Message('You gain {0} experience points.'.format(xp))) if leveled_up: message_log.add_message( Message( 'You reached level {0}'.format( player.level.current_level) + '!', colors.get('green'))) previous_game_state = game_state game_state = GameStates.LEVEL_UP if game_state == GameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemy_turn_results = entity.ai.take_turn( player, fov_map, game_map, entities) for enemy_turn_result in enemy_turn_results: message = enemy_turn_result.get('message') dead_entity = enemy_turn_result.get('dead') if message: message_log.add_message(message) if dead_entity: if dead_entity == player: message, game_state = kill_player(dead_entity) else: message = kill_monster(dead_entity) message_log.add_message(message) if game_state == GameStates.PLAYER_DEAD: break if game_state == GameStates.PLAYER_DEAD: break else: game_state = GameStates.PLAYERS_TURN
def main(): constants = get_constants() libtcod.sys_set_fps(30) # Animate anim_time = libtcod.sys_elapsed_milli() anim_frame = 0 libtcod.console_set_custom_font( 'sprite-font.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD, 32, 48) libtcod.console_init_root(constants['screen_width'], constants['screen_height'], constants['window_title'], False) libtcod.console_set_default_background(0, colors.get('dark')) load_customfont() con = libtcod.console_new(constants['map_width'] * 3, constants['map_height'] * 2) panel = libtcod.console_new(constants['panel_width'], constants['screen_height']) tooltip = libtcod.console_new(constants['screen_width'], 1) messages_pane = libtcod.console_new(constants['message_width'], 1000) inventory_pane = libtcod.console_new(constants['message_width'], 40) player = None entities = [] game_map = None message_log = None game_state = None show_main_menu = True show_load_error_message = False main_menu_background_image_0 = libtcod.image_load('menu_background_0.png') main_menu_background_image_1 = libtcod.image_load('menu_background_1.png') main_menu_background_image_2 = libtcod.image_load('menu_background_2.png') main_menu_background_image_3 = libtcod.image_load('menu_background_3.png') log_scroll = 0 inv_scroll = 0 key = libtcod.Key() mouse = libtcod.Mouse() while not libtcod.console_is_window_closed(): anim_frame, anim_time = animation(anim_frame, anim_time) if anim_frame == 0: main_menu_background_image = main_menu_background_image_0 elif anim_frame == 1: main_menu_background_image = main_menu_background_image_1 elif anim_frame == 2: main_menu_background_image = main_menu_background_image_2 else: main_menu_background_image = main_menu_background_image_3 libtcod.sys_check_for_event( libtcod.EVENT_KEY_PRESS | libtcod.EVENT_MOUSE, key, mouse) if show_main_menu: main_menu(con, main_menu_background_image, constants['screen_width'], constants['screen_height'], constants['window_title']) if show_load_error_message: message_box(con, 'No save game to load', 50, constants['screen_width'], constants['screen_height']) libtcod.console_flush() action = handle_main_menu(key) new_game = action.get('new_game') load_saved_game = action.get('load_game') exit_game = action.get('exit') if show_load_error_message and (new_game or load_saved_game or exit_game): show_load_error_message = False elif new_game: player, entities, game_map, message_log, game_state = get_game_variables( constants) game_state = GameStates.PLAYERS_TURN show_main_menu = False elif load_saved_game: try: player, entities, game_map, message_log, game_state = load_game( ) show_main_menu = False except FileNotFoundError: show_load_error_message = True elif exit_game: break else: libtcod.console_clear(con) cam_x, cam_y = update_cam(player, constants) log_height, inv_height = update_panels_heights( player, constants['panel_height']) log_scroll = 0 inv_scroll = 0 inv_selected = 0 play_game(player, entities, game_map, message_log, con, panel, tooltip, messages_pane, inventory_pane, constants, cam_x, cam_y, anim_frame, anim_time, log_scroll, log_height, inv_scroll, inv_height, inv_selected) show_main_menu = True
def place_entities(self, room, entities): max_monsters_per_room = from_dungeon_level([[2, 1], [3, 4], [5, 6]], self.dungeon_level) max_items_per_room = from_dungeon_level([[1, 1], [2, 4]], self.dungeon_level) number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) monster_chances = { 'orc': 80, 'troll': from_dungeon_level([[15, 3], [30, 5], [60, 7]], self.dungeon_level) } item_chances = { 'healing_potion': 35, 'sword': from_dungeon_level([[10, 5]], self.dungeon_level), 'shield': from_dungeon_level([[10, 6]], self.dungeon_level), 'lightning_scroll': from_dungeon_level([[25, 4]], self.dungeon_level), 'fireball_scroll': from_dungeon_level([[25, 6]], self.dungeon_level), 'confusion_scroll': from_dungeon_level([[10, 2]], self.dungeon_level) } for i in range(number_of_monsters): # Choose a random location in the room x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) # Check if an entity is already in that location if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): monster_choice = random_choice_from_dict(monster_chances) if monster_choice == 'orc': fighter_component = Fighter(hp=20, defense=0, power=4, xp=35) ai_component = BasicMonster() monster = Entity(x, y, tiles.get('orc_tile'), libtcod.white, 'Orc', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component = Fighter(hp=30, defense=2, power=8, xp=100) ai_component = BasicMonster() monster = Entity(x, y, tiles.get('troll_tile'), libtcod.white, 'Troll', blocks=True, render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) entities.append(monster) for i in range(number_of_items): x = randint(room.x1 + 1, room.x2 - 1) y = randint(room.y1 + 1, room.y2 - 1) if not any([ entity for entity in entities if entity.x == x and entity.y == y ]): item_choice = random_choice_from_dict(item_chances) if item_choice == 'healing_potion': item_component = Item(use_function=heal, amount=40) item = Entity(x, y, tiles.get('healingpotion_tile'), libtcod.white, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'sword': equippable_component = Equippable(EquipmentSlots.MAIN_HAND, power_bonus=3) item = Entity(x, y, tiles.get('sword_tile'), libtcod.white, 'Sword', render_order=RenderOrder.ITEM, equippable=equippable_component, sprite_main_shift=576) elif item_choice == 'shield': equippable_component = Equippable(EquipmentSlots.OFF_HAND, defense_bonus=1) item = Entity(x, y, tiles.get('shield_tile'), libtcod.white, 'Shield', render_order=RenderOrder.ITEM, equippable=equippable_component, sprite_off_shift=320) elif item_choice == 'fireball_scroll': item_component = Item( use_function=cast_fireball, targeting=True, targeting_message=Message( 'Left-click a target tile for the fireball, or right-click to cancel.', colors.get('dark')), targeting_radius=3, damage=25, radius=3) item = Entity(x, y, tiles.get('scroll_tile'), libtcod.white, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': item_component = Item( use_function=cast_confuse, targeting=True, targeting_message=Message( 'Left-click an enemy to confuse it, or right-click to cancel.', colors.get('dark')), targeting_radius=0) item = Entity(x, y, tiles.get('scroll_tile'), libtcod.white, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=40, maximum_range=5) item = Entity(x, y, tiles.get('scroll_tile'), libtcod.white, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)