def use(self, user): (x, y) = ui.target_tile() if (x, y) == (None, None): return False explode(x, y, self.radius, self.damage) user.mana -= self.mana_use return True
def cast_fireball(): #ask the player for a target tile to throw a fireball at ui.message('Left-click a target tile for the fireball, or right-click to cancel.', libtcod.light_cyan) (x, y) = ui.target_tile() if x is None: return 'cancelled' ui.message('The fireball explodes, burning everything within ' + str(FIREBALL_RADIUS) + ' tiles!', libtcod.orange) for obj in g.objects: #damage every fighter in range, including the player if obj.distance(x, y) <= FIREBALL_RADIUS and obj.fighter: ui.message('The ' + obj.name + ' gets burned for ' + str(FIREBALL_DAMAGE) + ' hit points.', libtcod.orange) obj.fighter.take_damage(FIREBALL_DAMAGE)
def bash_attack(actor): x, y = ui.target_tile(max_range=1) target = None for object in main.current_map.fighters: if object.x == x and object.y == y: target = object break if target is not None and target is not player.instance: result = player.bash_attack(target.x - actor.x, target.y - actor.y) if result != 'failed': return result return 'didnt-take-turn'
def use(self, user): pos = ui.target_tile() if pos == (None, None): return False for object in terrain.map.objects: if (object.x, object.y) == pos and isinstance(object, mob.Mob): if object.ai: object.ai = ai.ConfusedMob(object.ai) ui.message( 'The ' + object.name + ' is confused!', tcod.blue) user.mana -= self.mana_use return True # if code hasn't returned yet, no mob is at the position ui.message('There is no being there!')
def cast_flashbang(): #ask the player for a target tile to throw a fireball at ui.message('Left-click a target tile for the flashbang, or right-click to cancel.', libtcod.light_cyan) (x, y) = ui.target_tile() if x is None: return 'cancelled' ui.message('The flashbang explodes, blinding and deafening everything within ' + str(FLASHBANG_RADIUS) + ' tiles!', libtcod.orange) for obj in g.objects: #damage every fighter in range, including the player if obj.distance(x, y) <= FLASHBANG_RADIUS and obj.fighter and obj.ai: old_ai = obj.ai obj.ai = monsters.ConfusedMonster(old_ai, FLASHBANG_LENGTH) obj.ai.owner = obj ui.message("The " + obj.name + " is dazed and confused!", libtcod.light_green)
def throw_water_balloon(): #ask the player for a target tile to throw a fireball at ui.message('Left-click a target tile for the water balloon, or right-click to cancel.', libtcod.light_cyan) (x, y) = ui.target_tile() if x is None: return 'cancelled' ui.message('The water balloon bursts, dampening everything around it!', libtcod.light_blue) for obj in g.objects: #damage every fighter in range, including the player if obj.distance(x, y) <= WATERBALLOON_RADIUS and obj.light: if obj.ai: ui.message('The ' + obj.name + '\'s torch goes out!', libtcod.light_blue) else: ui.message('The ' + obj.name + ' goes out!', libtcod.light_blue) v.remove_light(obj) obj.light = None g.fov_recompute = True
def attack_reach(actor, target, context): if actor is None: actor = player.instance x, y = ui.target_tile(max_range=1) target = None for object in main.current_map.fighters: if object.x == x and object.y == y: target = object break if target is not None and target is not player.instance: result = player.reach_attack(target.x - actor.x, target.y - actor.y) if result != 'failed': return result return 'didnt-take-turn' else: if abs(actor.x - target.x) <= 2 and abs(actor.y - target.y) <= 2: return actor.fighter.attack(target) else: return 'didnt-take-turn'
def throw_light_orb(): #Create a puddle of light around it ui.message('Left-click a target tile for the light orb, or right-click to cancel.', libtcod.light_cyan) (x, y) = ui.target_tile() if x is None: return 'cancelled' #TODO: make this land a bit randomly orb_ai = LightDarkOrb(LIGHT_ORB_TICK_TIME) l = object.Light(LIGHT_ORB_LSL) lit_orb = object.Object(g.player.x, g.player.y, '*', 'light orb', LIGHT_ORB_THROWN_COLOR, light = l, ai = orb_ai) v.add_light(lit_orb) u.throw_object(lit_orb, g.player.x, g.player.y, x, y) g.objects.append(lit_orb) lit_orb.send_to_back() u.qinsert(lit_orb, g.time + LIGHT_ORB_TICK_TIME) ui.message('The light orb bursts into magical fire as it lands on the ground!', libtcod.orange) g.fov_recompute = True
def throw_dark_orb(): #Create a puddle of light around it ui.message('Left-click a target tile for the dark orb, or right-click to cancel.', libtcod.light_cyan) (x, y) = ui.target_tile() if x is None: return 'cancelled' #TODO: make this land a bit randomly #TODO: make this stop being lit eventually orb_ai = LightDarkOrb(DARK_ORB_TICK_TIME) l = object.Light(DARK_ORB_LSL) lit_orb = object.Object(g.player.x, g.player.y, '*', 'dark orb', DARK_ORB_THROWN_COLOR, light = l, ai = orb_ai) v.add_light(lit_orb) u.throw_object(lit_orb, g.player.x, g.player.y, x, y) g.objects.append(lit_orb) lit_orb.send_to_back() u.qinsert(lit_orb, g.time + DARK_ORB_TICK_TIME) ui.message('The temperature drops as the orb begins to absorb light!', libtcod.light_violet) g.fov_recompute = True
def _get_ability_target(actor, info, target_override): targeting = info.get('targeting', 'pick') range = info.get('range', 1000) ground_targeting = info.get('target_ground', False) target = None burst = info.get('burst') if isinstance(target_override, main.GameObject): x = target_override.x y = target_override.y target_override = x, y if targeting == 'override': return (0, 0) if targeting == 'self' and burst is None: if ground_targeting: target = actor.x, actor.y else: target = actor if target is None and targeting is not None: if actor is player.instance: if targeting == 'self': # for self burst target = actor.x, actor.y else: ui.message_flush( 'Left-click a target tile, or right-click to cancel.', libtcod.white) default_target = None if info.get( 'intent', 'aggressive' ) == 'aggressive' and ui.selected_monster is not None: default_target = ui.selected_monster.x, ui.selected_monster.y target = ui.target_tile(range, targeting, default_target=default_target) else: if target_override is not None and targeting != 'self' and \ main.distance(actor.x, actor.y, target_override[0], target_override[1]) > range: target = None return target # out of range if targeting == 'pick': target = (target_override[0], target_override[1]) elif targeting == 'cone': target = main.cone(actor.x, actor.y, target_override[0], target_override[1], max_range=info['range']) elif targeting == 'beam': target = main.beam(actor.x, actor.y, target_override[0], target_override[1]) elif targeting == 'beam wide': # TODO: Support wide beam outside of player targeting raise Exception("Not supported") elif targeting == 'beam_interrupt': target = main.beam_interrupt(actor.x, actor.y, target_override[0], target_override[1]) elif targeting == 'summon': target = main.find_closest_open_tile(target_override[0], target_override[1]) elif targeting == 'self': target = actor.x, actor.y #Targeting failed if isinstance(target, tuple) and target[0] is None: target = None if target is None: return target if burst is not None and isinstance(target, tuple): if info.get('hits_friendlies', False): teams = None elif info.get('team') is not None: if info.get('allies_only') is not None: teams = lambda o: o.fighter.team == info.get('team') else: teams = lambda o: o.fighter.team != info.get('team') else: if info.get('allies_only') is not None: teams = lambda o: o.fighter.team == actor.fighter.team else: teams = lambda o: o.fighter.team != actor.fighter.team info['origin'] = target[0], target[1] if not ground_targeting: target = main.get_fighters_in_burst(target[0], target[1], burst, actor, teams) else: target = main.get_tiles_in_burst(target[0], target[1], burst) elif not ground_targeting and targeting != 'summon': if target is not None: if isinstance(target, list): target = [main.get_monster_at_tile(*t) for t in target] else: pos = target target = None for fighter in main.current_map.fighters: if fighter.x == pos[0] and fighter.y == pos[1]: target = fighter break #randomly select only some of the targets if info.get('random_select') is not None and not isinstance( target, tuple): mode = info.get('random_select') target = [ target[i] for i in random.sample(xrange(len(target)), mode) ] return target
def shatter_item(actor, target, context): x, y = 0, 0 dc = context['save_dc'] if actor is player.instance: # player is casting ui.message_flush('Left-click a target tile, or right-click to cancel.', libtcod.white) (x, y) = ui.target_tile() if x is None: return 'cancelled' choices = main.get_objects( x, y, lambda o: o.fighter and o.fighter.inventory and len( o.fighter.inventory) > 0) if len(choices) == 0: choices = main.get_objects(x, y, lambda o: o.item is not None) if len(choices) > 1: target = choices[ui.menu('Which target?', [i.name for i in choices], 24)] elif len(choices) > 0: target = choices[0] else: ui.message('No valid targets here', libtcod.gray) return 'cancelled' dc += 4 else: x, y = target.x, target.y if target is None: return 'cancelled' item = None inventory = None if target.fighter is not None: inventory = target.fighter.inventory if inventory is None or len(inventory) == 0: if actor == player.instance: ui.message('Target has no items', libtcod.light_blue) return 'cancelled' item = inventory[libtcod.random_get_int(0, 0, len(inventory) - 1)] dc += 5 elif target.item is not None: item = target if main.roll_dice('1d20') + main.roll_dice('1d{}'.format( actor.fighter.spell_power())) > dc: ui.render_explosion(x, y, 1, libtcod.yellow, libtcod.flame) ui.message("The {} shatters into pieces!".format(item.name), libtcod.flame) if inventory is not None: inventory.remove(item) item.destroy() damage_factor = 4 if item.equipment is not None: damage_factor = item.equipment.weight for obj in main.current_map.fighters: if obj.distance(x, y) <= context['burst']: combat.attack_magical_ex( actor, obj, base_damage_dice='2d{}'.format(damage_factor), spell_dice_number=context['dice'], spell_elements=context['element'], pierce=context['pierce'], shred=context['shred'], defense_types=context['defense_types'], damage_types=context['damage_types'], blockable=context['blockable'], attack_name=context['name']) return 'success' else: ui.message("Shatter failed to break the {}!".format(item.name), libtcod.yellow) return 'success'