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 can't just go slinging fireballs without knowing where you're aiming!", 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.combatant: results.append( {'message': Message('The {0} takes {1} fire damage!'.format(entity.name, damage), libtcod.orange)}) results.extend(entity.combatant.lose_hp(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.combatant.ai: confused_ai = ConfusedMonster(entity.combatant.ai, 10) confused_ai.owner = entity entity.combatant.ai = confused_ai results.append({'consumed': True, 'message': Message( 'The eyes of the {0} look vacant, as they start to stumble around aimlessly...'.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 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.combatant 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! {0} takes {1} damage!'.format(target.name, damage))}) results.extend(target.combatant.lose_hp(damage)) else: results.append( {'consumed': False, 'target': None, 'message': Message('No enemy is close enough to strike.', libtcod.red)}) return results
def attempt_pickup_item(party, entities): changes = [] for entity in entities: if entity.x == party.x and entity.y == party.y and (party.inventory.unused_carry_capacity >= entity.mass): message = Message('{0} added to party inventory!'.format(entity.name), DARK_PURPLE) changes.extend([{'pickup_item': entity}, {'message': message}]) break if len(entities) > 0 and len(changes) == 0: message = Message("That's too heavy! Get rid of some things or get stronger!", RED) changes.extend([{'message': message}]) return changes
def encounter_goto_life(self): changes = [{'state': 'life'}] xp = self.handler.loot.xp if xp > 0: changes.append({'xp': xp}) message = Message('You gain {0} experience points!'.format(xp), DARK_ORANGE) else: message = Message("You didn't learn much there...", DARK_ORANGE) changes.append({'message': message}) return changes
def logic(self): changes = [{'debug_message': Message('Command entered: ' + self.handler.current_input, WHITE)}] try: exec(self.handler.current_input, self.handler.allowed_inputs) changes.append({'debug_message': Message('COMMAND ACCEPTED', WHITE)}) for message in self.handler.message_slot: changes.append({'debug_message': message}) self.handler.current_input = '' except NameError: changes.append({'debug_message': Message('COMMAND NOT RECOGNIZED', WHITE)}) return changes
def heal(*args, **kwargs): combatant = args[0].combatant amount = kwargs.get('amount') results = [] if combatant.attributes.current_hp == combatant.max_hp: results.append({'consumed': False, 'message': Message('You are already at full health!', libtcod.yellow)}) else: combatant.gain_hp(amount) results.append({'consumed': True, 'message': Message('Your wounds start to heal!', libtcod.green)}) return results
def encounter_end_turn(self): changes = [] if len(self.handler.combat.enemies.members) > 0: if self.handler.state is EncounterStates.ENEMY_TURN: changes.append({'substate': EncounterStates.THINKING}) else: changes.append({'substate': EncounterStates.ENEMY_TURN}) changes.append({'automate': 'enemy_turn'}) else: changes.append({'message': Message('YOU WIN THE FIGHT!', BLACK)}) changes.append({'message': Message('Press [Enter] to loot.', BLACK)}) changes.append({'substate': EncounterStates.VICTORY}) return changes
def str(self, obj, x, y): """Returns __str__ of obj on current map""" message = Message.placeholder() sub_obj = self.allowed_objs.get(obj)[y][x] message.text = str(sub_obj) self.message_slot = [message]
def spend_competence(self): comp_spender = self.owner if comp_spender.competence >= 0: results.append({ 'message': Message('What would you like to be better at?', libtcod.yellow) }) return True else: results.append({ 'message': Message("You don't have the competence to spare!", libtcod.yellow) }) return False
def use(self, item_entity, **kwargs): results = [] item_component = item_entity.item if item_component.equippable is not None: equippable_component = item_entity.item.equippable if equippable_component: results.append({'equip': item_entity}) else: results.append({ 'message': Message('The {0} cannot be used'.format(item_entity.name), YELLOW) }) else: if item_component.useable.targeting and not ( kwargs.get('target_x') or kwargs.get('target_y')): results.append({'targeting': item_entity}) else: kwargs = {**item_component.useable.function_kwargs, **kwargs} item_use_results = item_component.useable.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 name(self, obj, x, y): """Returns obj.name""" message = Message.placeholder() sub_obj = self.allowed_objs.get(obj)[y][x] if sub_obj is None: message.text = 'OBJECT NOT FOUND' else: message.text = sub_obj.name self.message_slot = [message]
def lose_hp(self, amount): results = [] self.attributes.current_hp -= amount if self.attributes.current_hp <= 0: self.attributes.current_hp = 0 # add overkill here later results.append({'dead': self.owner}) results.append({'message': Message('{0} is dead!'.format(self.owner.name), DARK_RED)}) return results
def attempt_equip_item(party: PartyHandler, menu: AbstractMenu): slot = menu.pointer_data.item.equippable.slot currently_equipped = party.p1.combatant.equipment.slots_dict.get(slot) changes = [] if currently_equipped: # check weight limit later changes.append({'dequipped': slot}) changes.append({'equipped': menu}) message = Message('{0} equipped the {1}!'.format(party.p1.name, menu.pointer_data.name), MIDNIGHT_BLUE) changes.append({'message': message}) changes.append({'subsubstate': 2}) return changes
def interact(self): changes = [] changes.extend(attempt_pickup_item(self.game.model.party, self.game.model.world.current_map.items)) for entity in self.game.model.world.current_map.conversers: if entity.x == self.game.model.party.x and entity.y == self.game.model.party.y: self.game.dialogue.partner = entity self.game.dialogue.set_real_talk() self.game.state_handler = self.game.dialogue self.game.options.current = entity.converser.dialogue if len(changes) == 0: message = Message('Nothing to see here, move along...', DARK_BLUE) changes.append({'message': message}) return changes
def attack(self, target): compare_slash = self.power_slash - target.combatant.resist_slash compare_pierce = self.power_pierce - target.combatant.resist_pierce compare_blunt = self.power_blunt - target.combatant.resist_blunt attack_type = None attack = None best_attack = max(compare_slash, compare_pierce, compare_blunt) if best_attack == compare_slash: attack_type, attack, resist_type = self.power_slash, 'slash', target.combatant.resist_slash elif best_attack == compare_pierce: attack_type, attack, resist_type = self.power_pierce, 'pierce', target.combatant.resist_pierce elif best_attack == compare_blunt: attack_type, attack, resist_type = self.power_blunt, 'blunt', target.combatant.resist_blunt results = [] hit_vs_dodge = self.accuracy - target.combatant.dodge + random.randrange(100) - 50 if hit_vs_dodge >= 0: #damage + or - 5% variation, rounded down damage = math.floor(((attack_type ** 2) - (resist_type))*((random.randrange(10)+95)/100)) if damage > 0: results.append({'message': Message('{0} attacks {1} for {2} {3} damage.'.format(self.owner.name, target.name, str(damage), attack), BLACK)}) results.extend(target.combatant.lose_hp(damage)) else: results.append({'message': Message('{0} attacks {1} but does no damage!.'.format(self.owner.name, target.name), BLACK)}) else: results.append({'message': Message('{0} attacks, but {1} dodges!'.format(self.owner.name, target.name), BLACK)}) results.append({'end_turn': True}) return results
def drop_item(self, item): results = [] if self.owner.combatant.equipment.main_hand == item or self.owner.combatant.equipment.off_hand == item or self.owner.combatant.equipment.head == item or self.owner.combatant.equipment.body == item or self.owner.combatant.equipment.feet == item or self.owner.combatant.equipment.belt == item or self.owner.combatant.equipment.hands == item or self.owner.combatant.equipment.finger == item or self.owner.combatant.equipment.neck == item or self.owner.combatant.equipment.back == item or self.owner.combatant.equipment.accessory == item: self.owner.combatant.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), YELLOW) }) return results
def bool_map(self, obj): """Returns current map as ASCII made of 1's and 0's based on existence of obj""" mes = [] tiles = self.owner.world.current_map.tiles obj_dict = { 'transition': [[tile.floor.transition for tile in row] for row in tiles], } vals = obj_dict.get(obj) for row in vals: message = Message.placeholder() text = '' for val in row: if val is not None: text += '1 ' else: text += '0 ' message.text = text mes.append(message) self.message_slot = mes
def take_turn(self, target, 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 drop_item(party: PartyHandler, menu: AbstractMenu): message = Message('{0} was dropped on the ground.'.format(menu.pointer_data.name), BLACK) return [{'drop_item': menu}, {'message': message}, {'subsubstate': 2}]
def make_item(item_choice): """Will be reworked along with item update, but still functional as is""" if item_choice == 'healing_potion': item_component = Item(5, useable=Useable('Healing Potion', BUNDLE_POTION, use_function=heal, amount=400)) item = Entity(0, 0, render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'sword': image = BUNDLE_WEAPONS.get('longsword') equippable_core = EquippableCore('longsword', image) equippable_material = EquippableMaterial('wood') equippable_quality = EquippableQuality('average') equippable_component = Equippable('Sword', image, EquipmentSlots.MAIN_HAND, equippable_core, equippable_material, equippable_quality) item_component = Item(equippable_component) item = Entity(0, 0, item=item_component) elif item_choice == 'shield': image = BUNDLE_WEAPONS.get('shield') equippable_core = EquippableCore('shield', image) equippable_material = EquippableMaterial('iron') equippable_quality = EquippableQuality('average') equippable_component = Equippable('Shield', image, EquipmentSlots.OFF_HAND, equippable_core, equippable_material, equippable_quality) item_component = Item(equippable_component) item = Entity(0, 0, item=item_component) elif item_choice == 'fireball_scroll': image = SCROLL msg = 'Left-click a target tile for the fireball, or right-click to rethink your life decisions.' item_component = Item( useable=Useable('Fireball Scroll', image, use_function=cast_fireball, targeting=True, targeting_message=Message(msg, libtcod.light_cyan), damage=250, radius=3)) item = Entity(0, 0, render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'confusion_scroll': image = SCROLL item_component = Item(useable=Useable( 'Confusion Scroll', image, 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(0, 0, render_order=RenderOrder.ITEM, item=item_component) elif item_choice == 'lightning_scroll': image = SCROLL item_component = Item(useable=Useable('Lightning Scroll', image, use_function=cast_lightning, damage=400, maximum_range=5)) item = Entity(0, 0, render_order=RenderOrder.ITEM, item=item_component) return item
def kill_player(player): make_corpse(player) return Message('You died!', RED), GameStates.PLAYER_DEAD