def check_level_up(): """see if the player's experience is enough to level-up""" level_up_xp = var.LEVEL_UP_BASE + var.player.level * var.LEVEL_UP_FACTOR if var.player.fighter.xp >= level_up_xp: #it is! level up var.player.level += 1 var.player.fighter.xp -= level_up_xp message('Your battle skills grow stronger! You reached level ' +\ str(var.player.level) + '!', libtcod.yellow) choice = None while choice is None: #keep asking until a choice is made choice = menu('Level up! Choose a stat to raise:\n',\ ['Constitution (+20 HP, from ' + str(var.player.fighter.max_hp) + ')',\ 'Strength (+1 attack, from ' + str(var.player.fighter.base_power) + ')',\ 'Agility (+1 defense, from ' + str(var.player.fighter.base_defense) + ')'],\ var.LEVEL_SCREEN_WIDTH) if choice == 0: var.player.fighter.base_max_hp += 20 var.player.fighter.hp += 20 elif choice == 1: var.player.fighter.base_power += 1 elif choice == 2: var.player.fighter.base_defense += 1
def dequip(self): """Dequip object and show a mesage about it""" if not self.is_equipped: return self.is_equipped = False message('Dequipped ' + self.owner.name + ' from ' + self.slot + '.',\ libtcod.light_yellow)
def cast_heal(): """heal the player""" if var.player.fighter.hp == var.player.fighter.max_hp: message('You are already at full health.', libtcod.red) return 'cancelled' message('Your wounds start to feel better!', libtcod.light_violet) var.player.fighter.heal(var.HEAL_AMOUNT)
def player_death(player): """the game ended!""" message('You died!', libtcod.red) var.game_state = 'dead' #for added effect, transform the player into a corpse! player.char = '%' player.color = libtcod.dark_red
def equip(self): """Equip equipment""" # if the slot is already being used, dequip whatever is there first old_equipment = get_equipped_in_slot(self.slot) if old_equipment is not None: old_equipment.dequip() # equip object and show a message about it self.is_equipped = True message('Equipped ' + self.owner.name + ' on ' + self.slot + '.',\ libtcod.light_green)
def cast_lightning(): """find closest enemy (inside a maximum range) and damage it""" monster = closest_monster(var.LIGHTNING_RANGE) if monster is None: #no enemy found within maximum range message('No enemy is close enough to strike.', libtcod.red) return 'cancelled' #zap it! message('A lightning bolt strikes the ' + monster.name + ' with a loud thunder! The damage is '\ + str(var.LIGHTNING_DAMAGE) + ' hit points.', color=libtcod.light_blue) monster.fighter.take_damage(var.LIGHTNING_DAMAGE)
def monster_death(monster): """transform it into a nasty corpse! it doesn't block, can't be attacked and doesn't move""" message('The ' + monster.name + ' is dead! You gain ' + str(monster.fighter.xp) +\ ' experience points.', 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.send_to_back()
def drop(self): """add to the map and remove from the player's inventory. also, place it at the player's coordinates""" var.game_objects.append(self.owner) var.inventory.remove(self.owner) self.owner.x = var.player.x self.owner.y = var.player.y message('You dropped a ' + self.owner.name + '.', libtcod.yellow) # special case: if the object has the Equipment component, dequip it before dropping if self.owner.equipment: self.owner.equipment.dequip()
def take_turn(self): """AI for a confused monster.""" if self.num_turns > 0: #still confused... #move in a random direction, and decrease the number of turns confused self.owner.move(libtcod.random_get_int(0, -1, 1), libtcod.random_get_int(0, -1, 1)) self.num_turns -= 1 #restore the previous AI (this one will be deleted because it's not referenced anymore) else: self.owner.ai = self.old_ai message('The ' + self.owner.name + ' is no longer confused!', libtcod.red)
def next_level(): """advance to the next level""" message('You take a moment to rest, and recover your strength.', libtcod.light_violet) var.player.fighter.heal(var.player.fighter.max_hp / 2) #heal the player by 50% var.dungeon_level += 1 message('After a rare moment of peace, you descend deeper into the heart of the dungeon...',\ libtcod.red) make_map() #create a fresh new level! initialize_fov()
def pick_up(self): """add to the player's inventory and remove from the map""" if len(var.inventory) >= 26: message('Your inventory is full, cannot pick up ' + self.owner.name + '.', libtcod.red) else: var.inventory.append(self.owner) var.game_objects.remove(self.owner) message('You picked up a ' + self.owner.name + '!', libtcod.green) # special case: automatically equip, if the corresponding equipment slot is unused equipment = self.owner.equipment if equipment and get_equipped_in_slot(equipment.slot) is None: equipment.equip()
def use(self): """just call the "use_function" if it is defined""" # special case: if the object has the Equipment component, # the "use" action is to equip/dequip if self.owner.equipment: self.owner.equipment.toggle_equip() return if self.use_function is None: message('The '+ self.owner.name + ' cannot be used.') else: if self.use_function() != 'cancelled': #destroy after use, unless it was cancelled for some reason var.inventory.remove(self.owner)
def cast_confuse(): """ask the player for a target to confuse""" message('Left-click an enemy to confuse it, or right-click to cancel.', libtcod.light_cyan) monster = target_monster(var.CONFUSE_RANGE) if monster is None: return 'cancelled' #replace the monster's AI with a "confused" one; after some turns it will restore the old AI old_ai = monster.ai monster.ai = ConfusedMonster(old_ai) monster.ai.owner = monster #tell the new component who owns it message('The eyes of the ' + monster.name + ' look vacant, as he starts to stumble around!',\ libtcod.light_green)
def new_game(): """create a new game""" #create object representing the player fighter_component = Fighter(hp=100, defense=1, power=2, xp=0, death_function=player_death) var.player = Object(0, 0, var.PLAYER_TILE, 'player', libtcod.white, blocks=True, fighter=fighter_component) var.player.level = 1 #generate map (at this point it's not drawn to the screen) var.dungeon_level = 1 make_map() initialize_fov() var.game_state = 'playing' var.inventory = [] #create the list of game messages and their colors, starts empty var.game_msgs = [] #a warm welcoming message! message( 'Welcome stranger! Prepare to perish in the Tombs of the Ancient Kings.', libtcod.red) # initial equipment: a dagger equipment_component = Equipment(slot='right hand', power_bonus=2) obj = Object(0, 0, var.DAGGER_TILE, 'dagger', libtcod.sky, equipment=equipment_component) var.inventory.append(obj) equipment_component.equip() obj.always_visible = True
def cast_fireball(): """ask the player for a target tile to throw a fireball at""" message('Left-click a target tile for the fireball, or right-click to cancel.',\ libtcod.light_cyan) (x, y) = target_tile() if x is None: return 'cancelled' message('The fireball explodes, burning everything within ' + str(var.FIREBALL_RADIUS) +\ ' tiles!', libtcod.orange) for obj in var.game_objects: #damage every fighter in range, including the player if obj.distance(x, y) <= var.FIREBALL_RADIUS and obj.fighter: message('The ' + obj.name + ' gets burned for ' + str(var.FIREBALL_DAMAGE) +\ ' hit points.', libtcod.orange) obj.fighter.take_damage(var.FIREBALL_DAMAGE)