def holy_lance(actor, target, context): import actions x, y = context['origin'] ui.render_explosion(x, y, context['burst'], libtcod.violet, libtcod.light_yellow) spell_context = { 'stamina_cost': context['stamina_cost'], 'charges': context['charges'], 'caster': actor, 'team': actor.fighter.team, } lance = main.GameObject( x, y, chr(23), 'Holy Lance', libtcod.light_azure, on_tick=lambda o: actions.invoke_ability( 'ability_holy_lance_tick', o, spell_context=spell_context), summon_time=10) main.current_map.add_object(lance) for obj in main.get_fighters_in_burst(x, y, context['burst'], lance, actor.fighter.team): combat.attack_magical(actor.fighter, obj, 'ability_holy_lance') return 'success'
def bomb_beetle_corpse_tick(object=None, context=None): if object is None: return object.bomb_timer -= 1 if object.bomb_timer > 2: object.color = libtcod.black elif object.bomb_timer > 1: object.color = libtcod.darkest_red elif object.bomb_timer > 0: object.color = libtcod.red elif object.bomb_timer <= 0: ui.message('The bomb beetle corpse explodes!', libtcod.orange) ui.render_explosion(object.x, object.y, 1, libtcod.yellow, libtcod.flame) main.create_fire(object.x, object.y, 10) for tile in main.adjacent_tiles_diagonal(object.x, object.y): if libtcod.random_get_int(0, 0, 3) != 0: main.create_fire(tile[0], tile[1], 10) main.melt_ice(tile[0], tile[1]) monster = main.get_objects(tile[0], tile[1], lambda o: o.fighter is not None) if len(monster) > 0: monster[0].fighter.take_damage(main.roll_dice('22d3')) if monster[0].fighter is not None: monster[0].fighter.apply_status_effect(effects.burning()) object.destroy()
def on_damaged_teleport(actor, attacker, damage): valid_teleports = [] for x in range(attacker.x - 5, attacker.x + 5): if x < 0 or x >= consts.MAP_WIDTH - 1: continue for y in range(attacker.y - 5, attacker.y + 5): if y < 0 or y >= consts.MAP_HEIGHT - 1: continue if fov.monster_can_see_tile(actor, x, y): if not main.is_blocked(x, y, movement_type=actor.movement_type, is_player=actor is player.instance): valid_teleports.append((x, y)) final_teleports = [] if attacker is not None: for vt in valid_teleports: if fov.monster_can_see_tile(attacker, vt[0], vt[1]): final_teleports.append(vt) else: final_teleports = list(valid_teleports) final_teleports.sort( key=lambda o: main.distance(o[0], o[1], actor.x, actor.y)) index = len(final_teleports) - main.roll_dice( '1d%d' % min(len(final_teleports), 5)) teleport_position = final_teleports[index] ui.render_explosion(actor.x, actor.y, 0, libtcod.fuchsia, libtcod.white) actor.set_position(teleport_position[0], teleport_position[1]) ui.render_explosion(actor.x, actor.y, 0, libtcod.fuchsia, libtcod.white)
def blastcap_explode(blastcap, context): blastcap.fighter = None main.current_map.fighters.remove(blastcap) ui.render_explosion(blastcap.x, blastcap.y, 1, libtcod.gold, libtcod.white, distance_h='manhattan') ui.message('The blastcap explodes with a BANG, stunning nearby creatures!', libtcod.gold) for obj in main.current_map.fighters: if main.is_adjacent_orthogonal(blastcap.x, blastcap.y, obj.x, obj.y): if obj.fighter.apply_status_effect( effects.stunned(duration=context['duration'])): ui.message( '%s %s stunned!' % (syntax.name(obj).capitalize(), syntax.conjugate(obj is player.instance, ('are', 'is'))), libtcod.gold) if ui.selected_monster is blastcap: main.changed_tiles.append((blastcap.x, blastcap.y)) ui.selected_monster = None ui.auto_target_monster() blastcap.destroy() return
def acid_flask(actor, target, context): (x, y) = context['origin'] ui.render_projectile((actor.x, actor.y), (x, y), libtcod.lime, character='!') ui.render_explosion(x, y, 1, libtcod.lightest_lime, libtcod.dark_lime) for t in target: combat.attack_magical(actor.fighter, t, 'ability_acid_flask')
def castigate(actor, target, context): origin = context['origin'] ui.render_explosion(origin[0], origin[1], 1, libtcod.violet, libtcod.light_yellow) dc = context['save_dc'] + actor.fighter.spell_power(elements=['radiance']) for f in target: f.fighter.apply_status_effect( effects.judgement(stacks=main.roll_dice('3d8')), dc, actor)
def haste(actor, target, context): target.fighter.apply_status_effect( effects.hasted(duration=context['duration'])) ui.render_explosion(target.x, target.y, 0, libtcod.lightest_fuchsia, libtcod.fuchsia) ui.message( '%s %s hasted.' % (syntax.name(target).capitalize(), syntax.conjugate(target is player.instance, ('are', 'is'))), spells.essence_colors['arcane']) return 'success'
def firebomb(actor, target, context): (x, y) = context['origin'] ui.render_projectile((actor.x, actor.y), (x, y), spells.essence_colors['fire'], chr(7)) ui.render_explosion(x, y, 1, libtcod.yellow, libtcod.flame) if actor is player.instance or fov.player_can_see(x, y): ui.message('The firebomb explodes!', spells.essence_colors['fire']) for f in target: if combat.attack_magical( actor.fighter, f, 'ability_fire_bomb') == 'hit' and f.fighter is not None: f.fighter.apply_status_effect(effects.burning())
def spatial_exchange(actor, target, context): if combat.attack_magical(actor.fighter, target, 'ability_spatial_exchange', accuracy_bonus=actor.fighter.spell_power( ['arcane'])) != 'missed': ui.render_explosion(actor.x, actor.y, 0, libtcod.white, spells.essence_colors['arcane']) ui.render_explosion(target.x, target.y, 0, libtcod.white, spells.essence_colors['arcane']) actor.swap_positions(target) combat.attack_magical(actor.fighter, target, 'data_ability_spatial_exchange')
def lightning_storm(actor, target, context): for tile in target: obj = main.get_monster_at_tile(tile[0], tile[1]) ui.render_explosion(tile[0], tile[1], 0, libtcod.light_green, libtcod.lightest_blue, chr(251)) if obj is not None and obj is not actor: if fov.player_can_see(tile[0], tile[1]) or actor is player.instance: ui.message( '%s is struck by a bolt of lightning!' % syntax.name(obj).capitalize(), libtcod.lightest_blue) combat.attack_magical(actor.fighter, obj, 'ability_lightning_storm')
def icebomb(actor, target, context): (x, y) = context['origin'] ui.render_projectile((actor.x, actor.y), (x, y), spells.essence_colors['cold'], chr(7)) ui.render_explosion(x, y, 1, libtcod.white, libtcod.light_sky) if actor is player.instance or fov.player_can_see(x, y): ui.message('The icebomb explodes!', spells.essence_colors['cold']) for f in target: if combat.attack_magical( actor.fighter, f, 'ability_ice_bomb') == 'hit' and f.fighter is not None: f.fighter.apply_status_effect( effects.frozen(duration=context['freeze_duration']))
def _timebomb_ticker(ticker): if ticker.ticks >= ticker.max_ticks: ticker.dead = True ui.message("The rune explodes!", spells.essence_colors['arcane']) ui.render_explosion(ticker.rune.x, ticker.rune.y, 1, libtcod.white, spells.essence_colors['arcane']) x = ticker.rune.x y = ticker.rune.y ticker.rune.destroy() for adj in main.adjacent_inclusive(x, y): for f in main.current_map.fighters: if f.x == adj[0] and f.y == adj[1]: combat.attack_magical(ticker.actor.fighter, f, 'data_time_bomb_explosion')
def heal_other(actor, target, context): if actor is player.instance: ui.message('Yo implement this', libtcod.red) return 'failure' ui.render_explosion(target.x, target.y, 0, libtcod.lightest_green, libtcod.green) amount = main.roll_dice('3d4') target.fighter.heal(amount) ui.message( '%s %s %s for %d damage.' % (syntax.name(actor).capitalize(), syntax.conjugate(actor is player.instance, ('heal', 'heals')), syntax.name(target, reflexive=actor), amount), libtcod.green) return 'success'
def fireball(actor, target, context): (x, y) = context['origin'] if actor is not player.instance and not fov.monster_can_see_tile( actor, x, y): return 'cancelled' ui.message('The fireball explodes!', libtcod.flame) ui.render_explosion(x, y, 1, libtcod.yellow, libtcod.flame) for obj in target: combat.attack_magical(actor.fighter, obj, 'ability_fireball') if obj.fighter is not None: obj.fighter.apply_status_effect(effects.burning()) for _x in range(x - 1, x + 2): for _y in range(y - 1, y + 2): main.melt_ice(_x, _y)
def corpse_dance(actor, target, context): x, y = target ui.render_explosion(x, y, context['radius'], libtcod.violet, libtcod.light_yellow) ui.message("{} calls the dead to dance!".format( syntax.conjugate(actor is player.instance, ["You", actor.name.capitalize()]))) for o in main.get_objects(x, y, None, context['radius']): if o is not None and o.is_corpse: main.raise_dead(actor, o) if o.fighter is not None and o.fighter.team == actor.fighter.team and o.fighter.subtype == 'undead': o.fighter.apply_status_effect( effects.swiftness(context['buff_duration'])) o.fighter.apply_status_effect( effects.berserk(context['buff_duration']))
def sacrifice(actor, target, context): actor.fighter.take_damage(min(30, int(actor.fighter.hp / 2)), attacker=actor) damage_mod = float(actor.fighter.max_hp - actor.fighter.hp) / float( actor.fighter.max_hp) ui.render_explosion(actor.x, actor.y, 1, libtcod.violet, libtcod.darkest_violet) for f in target: combat.attack_magical_ex(actor, f, accuracy=None, base_damage_dice=context['base_damage'], spell_dice_number=context['dice'], spell_elements=context['elements'], damage_mod=1 + damage_mod, defense_types=context['defense_types'], damage_types=context.get( 'damage_types', context['elements']), attack_name=context['name'])
def thermal_instability(actor, target, context): ui.render_explosion(actor.x, actor.y, 0, libtcod.yellow, libtcod.dark_flame, chr(19)) actor.fighter.apply_status_effect( effects.unstable(context['buff_duration']))
def holy_lance_tick(actor, target, context): caster = context['caster'] ui.render_explosion(actor.x, actor.y, context['burst'], libtcod.violet, libtcod.light_yellow) for f in target: combat.attack_magical(caster.fighter, f, 'ability_holy_lance_tick')
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'