def cast_lightning(*args, **kwargs): caster = args[0] entities = kwargs.get('entities') fov_map = kwargs.get('fov_map') damage = kwargs.get('damage') maximum_range = kwargs.get('maximum_range') results = [] target = None closest_distance = maximum_range + 1 for entity in entities: if entity.fighter and entity != caster and libtcod.map_is_in_fov(fov_map, entity.x, entity.y): distance = caster.distance_to(entity) if distance < closest_distance: target = entity closest_distance = distance if target: results.append({'consumed': True, 'target': target, 'message': Message('A lightning bolt strikes the {0} with a loud thunder! The damage is {1}'.format(target.name, damage))}) results.extend(target.fighter.take_damage(damage)) else: results.append({'consumed': False, 'target': None, 'message': Message('No enemy is close enough to strike.', libtcod.red)}) return results
def attack(self, target): results = [] damage = self.power - target.fighter.defense if damage > 0: results.append({ 'message': Message( '{0} attacks {1} for {2} hit points.'.format( self.owner.name.capitalize(), target.name, str(damage)), libtcod.white) }) results.extend(target.fighter.take_damage(damage)) else: results.append({ 'message': Message( '{0} attacks {1} but does no damage.'.format( self.owner.name.capitalize(), target.name), libtcod.white) }) return results
def attack(self, target): results = [] # Damage Calculation damage = self.power - target.fighter.defense if damage > 0: results.append({ 'message': Message( '{} attacks {} for {} damage.'.format( self.owner.name.capitalize(), target.name, str(damage)), tcod.white) }) results.extend(target.fighter.takeDamage(damage)) else: results.append({ 'message': Message( '{} attacks {} but does no damage.'.format( self.owner.name.capitalize(), target.name), tcod.white) }) results.extend(target.fighter.takeDamage(damage)) return results
def cast_confuse(*args, **kwargs): entities = kwargs.get('entities') fov_map = kwargs.get('fov_map') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') results = [] if not libtcod.map_is_in_fov(fov_map, target_x, target_y): results.append({'consumed': False, 'message': Message('You cannot target a tile outside your field of view.', libtcod.yellow)}) return results for entity in entities: if entity.x == target_x and entity.y == target_y and entity.ai: confused_ai = ConfusedMonster(entity.ai, 10) confused_ai.owner = entity entity.ai = confused_ai results.append({'consumed': True, 'message': Message('The eyes of the {0} look vacant, as they start to stumble around!'.format(entity.name), libtcod.light_green)}) break else: results.append({'consumed': False, 'message': Message('There is no targetable enemy at that location.', libtcod.yellow)}) return results
def heal(*args, **kwargs): entity = args[0] amount = kwargs.get('amount') results = [] if entity.fighter.hp == entity.fighter.maxHP: results.append({'consumed': False, 'message': Message('You are already at full health.')}) else: entity.fighter.heal(amount) results.append({'consumed': True, 'message': Message('You have healed.')}) return results
def heal(*args, **kwargs): entity = args[0] amount = kwargs.get('amount') results = [] if entity.fighter.hp == entity.fighter.max_hp: results.append({'consumed': False, 'message': Message('You are already at full health.', libtcod.yellow)}) else: entity.fighter.heal(amount) results.append({'consumed': True, 'message': Message('Your wounds start to feel better!', libtcod.green)}) return results
def addItem(self, item): results = [] if len(self.items) >= self.capacity: results.append({ 'itemAdded': None, 'message': Message('Inventory is Full', tcod.yellow) }) else: results.append({ 'itemAdded': item, 'message': Message('You picked up {}'.format(item.name), tcod.blue) }) self.items.append(item) return results
def use(self, item_entity, **kwargs): results = [] item_component = item_entity.item if item_component.use_function is None: resutls.append({ 'message': Message('The {0} cannot be used'.format(item_entity.name), libtcod.yellow) }) 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 use(self, itemEntity, **kwargs): results = [] itemComponent = itemEntity.item if itemComponent.useFunction is None: results.append({ 'message': Message( 'You struggle to find a use for the {0}'.format( itemEntity.name), libtcod.yellow) }) else: kwargs = {**itemComponent.function_kwargs, **kwargs} itemUseResults = itemComponent.useFunction(self.owner, **kwargs) for itemUseResult in itemUseResults: if itemUseResult.get('consumed'): self.removeItem(itemEntity) results.extend(itemUseResults) return results
def killMonster(monster): deathMessage = Message('{0} has died.'.format(monster.name.capitalize()), libtcod.yellow) monster.char = '%' monster.color = libtcod.dark_red monster.blocks = False monster.stats = None monster.ai = None monster.name = monster.name + 'remains' monster.renderOrder = renderOrder.CORPSE return deathMessage
def kill_monster(monster): death_message = Message('{0} is dead!'.format(monster.name.capitalize()), libtcod.orange) monster.char = '%' monster.color = libtcod.dark_red monster.blocks = False monster.fighter = None monster.ai = None monster.name = 'remains of ' + monster.name monster.render_order = RenderOrder.CORPSE return death_message
def add_item(self, item): results = [] if len(self.items) >= self.capacity: results.append({ 'item_added': None, 'message': Message('You cannot carry any more, your inventory is full', libtcod.yellow) }) else: results.append({ 'item_added': item, 'message': Message('You pick up the {0}!'.format(item.name), libtcod.blue) }) self.items.append(item) return results
def cast_fireball(*args, **kwargs): entities = kwargs.get('entities') fov_map = kwargs.get('fov_map') damage = kwargs.get('damage') radius = kwargs.get('radius') target_x = kwargs.get('target_x') target_y = kwargs.get('target_y') results = [] if not libtcod.map_is_in_fov(fov_map, target_x, target_y): results.append({'consumed': False, 'message': Message('You cannot target a tile outside your field of view.', libtcod.yellow)}) return results results.append({'consumed': True, 'message': Message('The fireball explodes, burning everything within {0} tiles!'.format(radius), libtcod.orange)}) for entity in entities: if entity.distance(target_x, target_y) <= radius and entity.fighter: results.append({'message': Message('The {0} gets burned for {1} hit points.'.format(entity.name, damage), libtcod.orange)}) results.extend(entity.fighter.take_damage(damage)) return results
def killMonster(monster): # deathMessage = '{0} is dead!'.format(monster.name.capitalize()) deathMessage = Message('{} is dead!'.format(monster.name.capitalize()), tcod.orange) monster.char = '%' monster.color = tcod.dark_red monster.blocks = False monster.fighter = None monster.ai = None monster.name = 'Remains of ' + monster.name monster.rOrder = renderOrder.corpse return deathMessage
def addItem(self, item): results = [] if len(self.items) >= self.capacity: results.append({ 'itemAdded': None, 'message': Message('Your inventory is full!', libtcod.yellow) }) else: results.append({ 'itemAdded': item, 'message': Message('You pick up the {0}'.format(item.name), libtcod.light_blue) }) self.items.append(item) return results
def heal(*args, **kwargs): entity = args[0] amount = kwargs.get('amount') results = [] if entity.stats.HP == entity.stats.maxHP: results.append({ 'consumed' : False, 'message' : Message('You are already at full health.', libtcod.yellow) }) else: entity.stats.heal(amount) if entity.stats.HP >= entity.stats.maxHP: entity.stats.HP = entity.stats.maxHP results.append({ 'consumed' : True, 'message' : Message('Your wounds start to feel better.', libtcod.yellow) }) return results
def dropItem(self, item): results = [] item.x = self.owner.x item.y = self.owner.y self.removeItem(item) results.append({ 'itemDropped': item, 'message': Message('You dropped the {0}'.format(item.name), libtcod.yellow) }) return results
def use(self, itemEntity, **kwargs): results = [] itemComponent = itemEntity.item if itemComponent.useFunction is None: results.append({ 'message': Message('The {} cannot be used'.format(itemEntity.name), tcod.yellow) }) else: kwargs = {**itemComponent.functionKwargs, **kwargs} itemUseResults = itemComponent.useFunction(self.owner, **kwargs) for itemUseResult in itemUseResults: if itemUseResult.get('consumed'): self.removeItem(itemEntity) results.extend(itemUseResults) return results
def take_turn(self, targets, fov_map, game_map, entities): results = [] if self.number_of_turns > 0: random_x = self.owner.x + randint(0, 2) - 1 random_y = self.owner.y + randint(0, 2) - 1 if random_x != self.owner.x and random_y != self.owner.y: self.owner.move_towards(random_x, random_y, game_map, entities) self.number_of_turns -= 1 else: self.owner.ai = self.previous_ai results.append({ 'message': Message( 'The {0} is no longer confused!'.format(self.owner.name), libtcod.red) }) return results
def kill_player(player): player.char = '%' player.color = libtcod.dark_red return Message('You died!', libtcod.red), GameStates.PLAYER_DEAD
def main(): # screen size screenWidth = 80 screenHeight = 80 # ui elements barWidth = 20 panelHeight = 7 panelDiff = screenHeight - panelHeight # message log messageX = barWidth + 2 messageWidth = screenWidth - barWidth - 2 messageHeight = panelHeight - 1 # map size mapWidth = 80 mapHeight = 58 # room parameters roomMaxSize = 14 roomMinSize = 6 maxRooms = 30 # monsters maxMonstersRoom = 4 # items maxItemsRoom = 2 # object colors dictionary colors = { 'darkWall': libtcod.Color(50, 50, 50), 'darkGround': libtcod.Color(25, 25, 25), 'lightWall': libtcod.Color(100, 100, 100), 'lightGround': libtcod.Color(200, 200, 200), 'whiteWall': libtcod.Color(255, 255, 255) } # player stats, location, symbol, and color playerStats = stats(HP=40, DEF=2, STR=5) invStorage = Inventory(28) player = Entity(0, 0, '@', libtcod.red, 'Player', blocks=True, render_order=renderOrder.ACTOR, stats=playerStats, inventory=invStorage) # npc list; location, symbol, color entities = [player] # game font libtcod.console_set_custom_font( 'arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD) libtcod.console_init_root(screenWidth, screenHeight, 'libtcod tutorial revised', False) # creates windows [DO NOT DELETE] # console window con = libtcod.console_new(screenWidth, screenHeight) # panel window, holds HP and message log panel = libtcod.console_new(screenWidth, panelHeight) # creates the game map and initializes its attributes game_map = gameMap(mapWidth, mapHeight) game_map.makeMap(maxRooms, roomMinSize, roomMaxSize, mapWidth, mapHeight, player, entities, maxMonstersRoom, maxItemsRoom) # field of view fov_algorithm = 0 fov_light_walls = True fov_radius = 10 fov_recompute = True fov_map = initializeFOV(game_map) # message log msg_log = messageLog(messageX, messageWidth, messageHeight) # mouse, keyboard init key = libtcod.Key() mouse = libtcod.Mouse() # sets game to player's turn gameState = gameStates.PLAYER_TURN previousState = gameState # 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: recomputeFOV(fov_map, player.x, player.y, fov_radius, fov_light_walls, fov_algorithm) # [DO NOT DELETE] renders entities each frame renderAll(con, panel, entities, player, game_map, fov_map, fov_recompute, msg_log, screenWidth, screenHeight, barWidth, panelHeight, panelDiff, mouse, colors, gameState) fov_recompute = False # [DO NOT DELETE] refreshes each frame libtcod.console_flush() # [DO NOT DELETE] clears each frame clearAll(con, entities) # each turn processes player input action = handleKeys(key, gameState) # assigns input to an action move = action.get('move') wait = action.get('wait') grab = action.get('grab') show = action.get('showInventory') drop = action.get('drop') invIndex = action.get('inventoryIndex') exit = action.get('exit') fullscreen = action.get('fullscreen') playerTurnResults = [] # character movement check if move and gameState == gameStates.PLAYER_TURN: dx, dy = move destX = player.x + dx destY = player.y + dy if not game_map.isBlocked(destX, destY): target = getBlockingEntitiesAtLocation(entities, destX, destY) if target: attackResults = player.stats.attack(target) playerTurnResults.extend(attackResults) else: player.move(dx, dy) fov_recompute = True gameState = gameStates.ENEMY_TURN # character grab item check elif grab and gameState == gameStates.PLAYER_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickupResults = player.inventory.addItem(entity) playerTurnResults.extend(pickupResults) break else: msg_log.addMessage( Message('There\'s nothing here to pick up.', libtcod.yellow)) # character inventory check if show: previousState = gameState gameState = gameStates.SHOW_INVENTORY # character drop check if drop: previousState = gameState gameState = gameStates.DROP_INVENTORY # inventory screen check if invIndex is not None and previousState != gameStates.PLAYER_DEAD and invIndex < len( player.inventory.items): item = player.inventory.items[invIndex] if gameState == gameStates.SHOW_INVENTORY: playerTurnResults.extend(player.inventory.use(item)) elif gameState == gameStates.DROP_INVENTORY: playerTurnResults.extend(player.inventory.dropItem(item)) # exit from inputHandlers if exit: if gameState in (gameStates.SHOW_INVENTORY, gameStates.DROP_INVENTORY): gameState = previousState else: return True # fullscreen check if fullscreen: libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen()) for playerTurnResult in playerTurnResults: message = playerTurnResult.get('message') deadEntity = playerTurnResult.get('dead') itemAdded = playerTurnResult.get('itemAdded') itemUsed = playerTurnResult.get('consumed') itemDropped = playerTurnResult.get('itemDropped') if message: msg_log.addMessage(message) if deadEntity: if deadEntity == player: message, gameState = killPlayer(deadEntity) else: message = killMonster(deadEntity) msg_log.addMessage(message) # If you pick up an item... if itemAdded: entities.remove(itemAdded) gameState = gameStates.ENEMY_TURN # If you use an item... if itemUsed: gameState = gameStates.ENEMY_TURN # If you drop an item... if itemDropped: entities.append(itemDropped) gameState = gameStates.ENEMY_TURN if gameState == gameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemyTurnResults = entity.ai.takeTurn( player, fov_map, game_map, entities) for enemyTurnResult in enemyTurnResults: message = enemyTurnResult.get('message') deadEntity = enemyTurnResult.get('dead') if message: msg_log.addMessage(message) if deadEntity: if deadEntity == player: message, gameState = killPlayer(deadEntity) else: message = killMonster(deadEntity) msg_log.addMessage(message) if gameState == gameStates.PLAYER_DEAD: break if gameState == gameStates.PLAYER_DEAD: break else: gameState = gameStates.PLAYER_TURN
def killPlayer(player): player.char = '#' player.color = libtcod.white return Message('You are dead.', libtcod.red), gameStates.PLAYER_DEAD
def main(): #---------------------------------------------------------------------------------- fighterComponent = Fighter(hp=30, defense=2, power=5) inventoryComponent = Inventory(26) player = Entity(0, 0, '@', tcod.white, 'Player', blocks=True, rOrder=renderOrder.actor, fighter=fighterComponent, inventory=inventoryComponent) entities = [player] #---------------------------------------------------------------------------------- tcod.console_set_custom_font( Config.FONT, tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) tcod.console_init_root(Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT, Config.TITLE, False) con = tcod.console_new(Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT) panel = tcod.console_new(Config.SCREEN_WIDTH, Config.PANEL_HEIGHT) map = gameMap(Config.MAP_WIDTH, Config.MAP_HEIGHT) map.makeMap(Config.MAX_ROOMS, Config.ROOM_MIN_SIZE, Config.ROOM_MAX_SIZE, Config.MAP_WIDTH, Config.MAP_HEIGHT, player, entities, Config.MAX_MONSTERS_PER_ROOM, Config.MAX_ITEMS_PER_ROOM) fovRecompute = True fovMap = initializeFOV(map) messageLog = MessageLog(Config.MESSAGE_X, Config.MESSAGE_WIDTH, Config.MESSAGE_HEIGHT) key = tcod.Key() mouse = tcod.Mouse() gameState = gameStates.PLAYERS_TURN previousGameState = gameState #---------------------------------------------------------------------------------- while not tcod.console_is_window_closed(): tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse) if fovRecompute: recomputeFOV(fovMap, player.x, player.y, Config.FOV_RADIUS, Config.FOV_LIGHT_WALLS, Config.FOV_ALGORITHM) renderAll(con, panel, entities, player, map, fovMap, fovRecompute, messageLog, Config.SCREEN_WIDTH, Config.SCREEN_HEIGHT, Config.BAR_WIDTH, Config.PANEL_HEIGHT, Config.PANEL_Y, mouse, Config.COLORS, gameState) fovRecompute = False tcod.console_flush() clearAll(con, entities) #---------------------------------------------------------------------------------- action = handleKeys(key, gameState) move = action.get('move') pickup = action.get('pickup') showInventory = action.get('showInventory') inventoryIndex = action.get('inventoryIndex') EXIT = action.get('EXIT') FULLSCREEN = action.get('FULLSCREEN') playerTurnResults = [] if move and gameState == gameStates.PLAYERS_TURN: dx, dy = move destinationX = player.x + dx destinationY = player.y + dy if not map.isBlocked(destinationX, destinationY): target = getBlockingEntities(entities, destinationX, destinationY) if target: attackResults = player.fighter.attack(target) playerTurnResults.extend(attackResults) else: player.move(dx, dy) fovRecompute = True gameState = gameStates.ENEMY_TURN elif pickup and gameState == gameStates.PLAYERS_TURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickupResults = player.inventory.addItem(entity) playerTurnResults.extend(pickupResults) break else: messageLog.addMessage( Message('There is nothing to pickup', tcod.yellow)) if showInventory: previousGameState = gameState gameState = gameStates.SHOW_INVENTORY if inventoryIndex is not None and previousGameState != gameStates.PLAYER_DEAD and \ inventoryIndex < len(player.inventory.items): item = player.inventory.items[inventoryIndex] playerTurnResults.extend(player.inventory.use(item)) #---------------------------------------------------------------------------------- if EXIT: if gameState == gameStates.SHOW_INVENTORY: gameState = previousGameState else: return True if FULLSCREEN: tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) #---------------------------------------------------------------------------------- for playerTurnResult in playerTurnResults: message = playerTurnResult.get('message') deadEntity = playerTurnResult.get('dead') itemAdded = playerTurnResult.get('itemAdded') itemConsumed = playerTurnResult.get('consumed') if message: messageLog.addMessage(message) if deadEntity: if deadEntity == player: message, gameState = killPlayer(deadEntity) else: message = killMonster(deadEntity) messageLog.addMessage(message) if itemAdded: entities.remove(itemAdded) gameState = gameStates.ENEMY_TURN if itemConsumed: gameState = gameStates.ENEMY_TURN #---------------------------------------------------------------------------------- if gameState == gameStates.ENEMY_TURN: for entity in entities: if entity.ai: enemyTurnResults = entity.ai.takeTurn( player, fovMap, map, entities) for enemyTurnResult in enemyTurnResults: message = enemyTurnResult.get('message') deadEntity = enemyTurnResult.get('dead') if message: messageLog.addMessage(message) if deadEntity: if deadEntity == player: message, gameState = killPlayer(deadEntity) else: message = killMonster(deadEntity) messageLog.addMessage(message) if gameState == gameStates.PLAYER_DEAD: break if gameState == gameStates.PLAYER_DEAD: break else: gameState = gameStates.PLAYERS_TURN
def place_entities(self, room, entities, max_monsters_per_room, max_items_per_room): # Get a random number of monsters number_of_monsters = randint(0, max_monsters_per_room) number_of_items = randint(0, max_items_per_room) 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) if not any([entity for entity in entities if entity.x == x and entity.y == y]): if randint(0, 100) < 80: fighter_component = Fighter(hp=10, defense=0, power=3) ai_component = BasicMonster() monster = Entity(x, y, 'o', libtcod.desaturated_green, 'Orc', blocks=True,render_order=RenderOrder.ACTOR, fighter=fighter_component, ai=ai_component) else: fighter_component = Fighter(hp=10, defense=1, power=4) ai_component = BasicMonster() monster = Entity(x, y, 'T', libtcod.darker_green, '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_chance = randint(0, 100) if item_chance < 69: item_component = Item(use_function=cast_confuse,targeting = True, targeting_message = Message('Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan)) item = Entity(x, y, '#', libtcod.light_pink, 'Confusion Scroll', render_order=RenderOrder.ITEM, item=item_component) elif item_chance < 70: item_component = Item(use_function=heal, amount=4) item = Entity(x, y, '!', libtcod.violet, 'Healing Potion', render_order=RenderOrder.ITEM, item=item_component) elif item_chance < 80: 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.', libtcod.light_cyan), damage=20, radius = 3) item = Entity(x, y, '#', libtcod.red, 'Fireball Scroll', render_order=RenderOrder.ITEM, item=item_component) else: item_component = Item(use_function=cast_lightning, damage=20, maximum_range=5) item = Entity(x, y, '#', libtcod.yellow, 'Lightning Scroll', render_order=RenderOrder.ITEM, item=item_component) entities.append(item)
def killPlayer(player): player.char = '%' player.color = tcod.dark_red # return 'You died!', GameStates.PLAYERDEAD return Message('You died!', tcod.red), GameStates.PLAYERDEAD
def main(): #----------------------------------------------------------------------------------------------- ################################################################################################ #----------------------------------------------------------------------------------------------- # CONFIG SCREENWIDTH = 80 SCREENHEIGHT = 50 MAPWIDTH = 80 MAPHEIGHT = 43 BARWIDTH = 20 PANELHEIGHT = 7 PANELY = SCREENHEIGHT - PANELHEIGHT MESSAGEX = BARWIDTH + 2 MESSAGEWIDTH = SCREENWIDTH - BARWIDTH - 2 MESSAGEHEIGHT = PANELHEIGHT - 2 ROOMMAX = 10 ROOMMIN = 6 NUMROOMSMAX = 30 FOVALGORITHM = 0 FOVLIGHTWALLS = True FOVRADIUS = 15 MAXMONSTERSPERROOM = 3 MAXITEMSPERROOM = 2 COLORS = { 'darkWall': tcod.Color(0,0,100), 'darkGround': tcod.Color(50,50,150), 'lightWall': tcod.Color(130,110,50), 'lightGround': tcod.Color(200,180,50) } #----------------------------------------------------------------------------------------------- ################################################################################################ #----------------------------------------------------------------------------------------------- # INITIALIZATION fighterComponent = Fighter(hp=30, defense=2, power=5) inventoryComponent = Inventory(26) player = Entity(0, 0, '@', tcod.white, 'Player', blocks=True, renderOrder=RenderOrder.ACTOR, fighter=fighterComponent, inventory=inventoryComponent) # Player Entity Object entities = [player] # Entity List #----------------------------------------------------------------------------------------------- # Initialize Font tcod.console_set_custom_font('arial10x10.png', tcod.FONT_TYPE_GREYSCALE | tcod.FONT_LAYOUT_TCOD) # Initialize Console Window tcod.console_init_root(SCREENWIDTH, SCREENHEIGHT, title = 'ASCII Roguelike', fullscreen = False) baseConsole = tcod.console_new(SCREENWIDTH, SCREENHEIGHT) # Base Console panel = tcod.console_new(SCREENWIDTH, PANELHEIGHT) #----------------------------------------------------------------------------------------------- MAP = GameMap(MAPWIDTH, MAPHEIGHT) # CREATE MAP MAP.makeMap(NUMROOMSMAX, ROOMMIN, ROOMMAX, MAPWIDTH, MAPHEIGHT, player, entities, MAXMONSTERSPERROOM, MAXITEMSPERROOM) fovRecompute = True # FOV Recomputing Boolean fovMap = initializeFOV(MAP) # Initialize FOV Map #----------------------------------------------------------------------------------------------- messageLog = MessageLog(MESSAGEX, MESSAGEWIDTH, MESSAGEHEIGHT) key = tcod.Key() # Store Keyboard Input mouse = tcod.Mouse() # Store Mouse Input gameState = GameStates.PLAYERTURN # Start On Player's Turn previousGameState = gameState #----------------------------------------------------------------------------------------------- ################################################################################################ #----------------------------------------------------------------------------------------------- # GAME LOOP while not tcod.console_is_window_closed(): tcod.sys_check_for_event(tcod.EVENT_KEY_PRESS | tcod.EVENT_MOUSE, key, mouse) # Capture User Input #----------------------------------------------------------------------------------------------- if fovRecompute: # Recompute FOV Based on Player Position recomputeFOV(fovMap, player.x, player.y, FOVRADIUS, FOVLIGHTWALLS, FOVALGORITHM) # Render All Entities renderAll(baseConsole, panel, entities, player, MAP, fovMap, fovRecompute, messageLog, SCREENWIDTH, SCREENHEIGHT, BARWIDTH, PANELHEIGHT, PANELY, mouse, COLORS, gameState) fovRecompute = False # Turn Off FOV Recompute Until Player Move #----------------------------------------------------------------------------------------------- tcod.console_flush() # Update Console to Current State clearAll(baseConsole, entities) # Clear Entities #----------------------------------------------------------------------------------------------- action = handleKeys(key, gameState) # Get Key Press # Key Press Action move = action.get('move') # Movement pickup = action.get('pickup') # Pickup Object showInventory = action.get('showInventory') inventoryIndex = action.get('inventoryIndex') exit = action.get('exit') # Exit Boolean fullscreen = action.get('fullscreen') # Fullscreen Boolean playerTurnResults = [] # Initialize Player's Turn Results # Check for movement and players turn if move and gameState == GameStates.PLAYERTURN: dx,dy = move # Movement Deltas # Movement Destination destinationX = player.x + dx destinationY = player.y + dy # If map is not blocked: if not MAP.isBlocked(destinationX, destinationY): # Check for blocking entities target = getBlockingEntities(entities, destinationX, destinationY) if target: # player.fighter.attack(target) attackResults = player.fighter.attack(target) # Gather Attack Results playerTurnResults.extend(attackResults) # Add to Player Turn Results else: player.move(dx,dy) # Move Player By Delta fovRecompute = True gameState = GameStates.ENEMYTURN # Set To Enemy's Turn elif pickup and gameState == GameStates.PLAYERTURN: for entity in entities: if entity.item and entity.x == player.x and entity.y == player.y: pickupResults = player.inventory.addItem(entity) playerTurnResults.extend(pickupResults) break else: messageLog.addMessage(Message('There is nothing to pick up.', tcod.yellow)) if showInventory: previousGameState = gameState gameState = GameStates.INVENTORY if inventoryIndex is not None and previousGameState != GameStates.PLAYERDEAD and inventoryIndex < len(player.inventory.items): item = player.inventory.items[inventoryIndex] playerTurnResults.extend(player.inventory.use(item)) if exit: # Exit Window if gameState == GameStates.INVENTORY: gameState = previousGameState else: return True if fullscreen: # Fullscreen tcod.console_set_fullscreen(not tcod.console_is_fullscreen()) for playerTurnResult in playerTurnResults: message = playerTurnResult.get('message') deadEntity = playerTurnResult.get('dead') itemAdded = playerTurnResult.get('itemAdded') itemConsumed = playerTurnResult.get('consumed') if message: messageLog.addMessage(message) if deadEntity: if deadEntity == player: message, gameState = killPlayer(deadEntity) else: message = killMonster(deadEntity) messageLog.addMessage(message) if itemAdded: entities.remove(itemAdded) gameState = GameStates.ENEMYTURN if itemConsumed: gameState = GameStates.ENEMYTURN if gameState == GameStates.ENEMYTURN: for entity in entities: if entity.ai: # entity.ai.takeTurn(player, fovMap, MAP, entities) enemyTurnResults = entity.ai.takeTurn(player, fovMap, MAP, entities) for enemyTurnResult in enemyTurnResults: message = enemyTurnResult.get('message') deadEntity = enemyTurnResult.get('dead') if message: messageLog.addMessage(message) if deadEntity: if deadEntity == player: message, gameState = killPlayer(deadEntity) else: message = killMonster(deadEntity) messageLog.addMessage(message) if gameState == GameStates.PLAYERDEAD: break if gameState == GameStates.PLAYERDEAD: break else: gameState = GameStates.PLAYERTURN # Set To Player's Turn