예제 #1
0
def mass_heal(actor, target, context):
    for unit in target:
        unit.fighter.apply_status_effect(effects.regeneration())
        amount = int(round(0.25 * unit.fighter.max_hp))
        unit.fighter.heal(amount)
        ui.message(
            "{} {} healed!".format(
                syntax.conjugate(unit is player.instance, ['You', unit.name]),
                syntax.conjugate(unit is player.instance, ['were', 'was'])),
            libtcod.white)
    return 'success'
예제 #2
0
def knock_back(actor, target):
    # check for resistance
    if 'displacement' in target.fighter.immunities:
        if fov.player_can_see(target.x, target.y):
            ui.message(
                '%s %s.' % (syntax.name(target).capitalize(),
                            syntax.conjugate(target is player.instance,
                                             ('resist', 'resists'))),
                libtcod.gray)
        return 'resisted'

    # knock the target back one space. Stun it if it cannot move.
    direction = target.x - actor.x, target.y - actor.y  # assumes the instance is adjacent
    stun = False
    against = ''
    against_tile = main.current_map.tiles[target.x +
                                          direction[0]][target.y +
                                                        direction[1]]
    if against_tile.blocks and not against_tile.is_pit:
        stun = True
        against = main.current_map.tiles[target.x +
                                         direction[0]][target.y +
                                                       direction[1]].name
    elif against_tile.elevation != target.elevation and against_tile.tile_type != 'ramp' and \
                    main.current_map.tiles[target.x][target.y] != 'ramp':
        stun = True
        against = 'cliff'
    else:
        for obj in main.current_map.objects:
            if obj.x == target.x + direction[
                    0] and obj.y == target.y + direction[1] and obj.blocks:
                stun = True
                against = obj.name
                break

    if stun:
        #  stun the target
        if target.fighter.apply_status_effect(effects.stunned(duration=2)):
            ui.message(
                '%s %s with the %s, stunning %s!' %
                (syntax.name(target).capitalize(),
                 syntax.conjugate(target is actor,
                                  ('collide', 'collides')), against,
                 syntax.pronoun(target, objective=True)), libtcod.gold)
    else:
        ui.message(
            '%s %s knocked backwards.' %
            (syntax.name(target).capitalize(),
             syntax.conjugate(target is actor, ('are', 'is'))), libtcod.gray)
        target.set_position(target.x + direction[0], target.y + direction[1])
        main.render_map()
        libtcod.console_flush()
예제 #3
0
def dragonweed_pull(actor, target, context):
    if target.fighter.hp > 0:
        ui.message(
            "The dragonweed's stem lashes out at %s!" % syntax.name(target),
            libtcod.dark_green)
        result = combat.attack_ex(actor.fighter,
                                  target,
                                  0,
                                  accuracy_modifier=1.5,
                                  damage_multiplier=0.75,
                                  verb=('pull', 'pulls'))
        if result == 'hit' and target.fighter is not None:
            if 'displacement' in target.fighter.immunities:
                if fov.player_can_see(target.x, target.y):
                    ui.message(
                        '%s %s.' % (syntax.name(target).capitalize(),
                                    syntax.conjugate(target is player.instance,
                                                     ('resist', 'resists'))),
                        libtcod.gray)
                return 'success'
            beam = main.beam(actor.x, actor.y, target.x, target.y)
            pull_to = beam[max(len(beam) - 3, 0)]
            target.set_position(pull_to[0], pull_to[1])
            if main.roll_dice('1d10') <= 5:
                target.fighter.apply_status_effect(
                    effects.immobilized(duration=2), context['save_dc'], actor)
예제 #4
0
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
예제 #5
0
def disarm(target):
    if target is None or target.fighter is None:
        return 'failure'
    weapon = main.get_equipped_in_slot(target.fighter.inventory, 'right hand')
    if weapon is None:
        return 'failure'
    weapon.dequip(no_message=True)
    possible_tiles = []
    for x in range(target.x - 1, target.x + 2):
        for y in range(target.y - 1, target.y + 2):
            if not main.is_blocked(
                    x, y, from_coord=(target.x, target.y), movement_type=1):
                possible_tiles.append((x, y))
    if len(possible_tiles) == 0:
        selected_tile = main.find_closest_open_tile(target.x, target.y)
    else:
        selected_tile = possible_tiles[libtcod.random_get_int(
            0, 0,
            len(possible_tiles) - 1)]
    weapon.owner.item.drop(no_message=True)
    weapon.owner.x = selected_tile[0]
    weapon.owner.y = selected_tile[1]
    ui.message(
        '%s %s disarmed!' % (syntax.name(target).capitalize(),
                             syntax.conjugate(target is player.instance,
                                              ('are', 'is'))), libtcod.red)
    return 'success'
예제 #6
0
def flash_frost(actor, target, context):
    target.fighter.apply_status_effect(effects.frozen(5))
    if actor is player.instance or fov.player_can_see(target.x, target.y):
        ui.message(
            '%s %s frozen solid!' %
            (syntax.name(target).capitalize(),
             syntax.conjugate(target is player.instance,
                              ('are', 'is'))), spells.essence_colors['cold'])
예제 #7
0
def on_hit_knockback(attacker, target, damage, force=6):
    if target.fighter is None:
        return

    if 'displacement' in target.fighter.immunities:
        if fov.player_can_see(target.x, target.y):
            ui.message(
                '%s %s.' % (syntax.name(target).capitalize(),
                            syntax.conjugate(target is player.instance,
                                             ('resist', 'resists'))),
                libtcod.gray)
        return

    diff_x = target.x - attacker.x
    diff_y = target.y - attacker.y
    if diff_x > 0:
        diff_x = diff_x / abs(diff_x)
    if diff_y > 0:
        diff_y = diff_y / abs(diff_y)
    direction = (diff_x, diff_y)

    steps = 0
    while steps <= force:
        steps += 1
        against = main.get_objects(target.x + direction[0],
                                   target.y + direction[1], lambda o: o.blocks)
        if against is None or len(against) == 0:
            against = syntax.name(
                main.current_map.tiles[target.x + direction[0]][target.y +
                                                                direction[1]])
        else:
            against = 'the ' + against.name
        if not target.move(direction[0], direction[1]):
            # Could not move
            damage = combat.roll_damage('%dd4' % steps, '0d0',
                                        target.fighter.armor, 0, 'budgeoning',
                                        1.0, target.fighter.resistances)
            ui.message(
                '%s %s backwards and collides with %s, taking %d damage.' %
                (syntax.name(target).capitalize(),
                 syntax.conjugate(target is player.instance,
                                  ('fly', 'flies')), against, damage),
                libtcod.gray)
            target.fighter.take_damage(damage, attacker=attacker)
            steps = force + 1
예제 #8
0
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'
예제 #9
0
 def sh_raise(self):
     self.sh_timer = 0
     if not self.raised and (self.holder is player.instance
                             or fov.monster_can_see_object(
                                 self.holder, player.instance)):
         ui.message(
             '%s %s %s shield.' %
             (syntax.name(self.holder).capitalize(),
              syntax.conjugate(self.holder is player.instance,
                               ('raise', 'raises')),
              syntax.pronoun(self.holder, possesive=True)), libtcod.blue)
     self.raised = True
     self.sh_points = self.sh_max
예제 #10
0
def confuse(actor, target, context):
    import consts
    if target.fighter.apply_status_effect(
            effects.StatusEffect(
                'confusion',
                consts.CONFUSE_NUM_TURNS,
                color=libtcod.pink,
            )):
        ui.message(
            '%s %s confused!' % (syntax.name(target).capitalize(),
                                 syntax.conjugate(target is player.instance,
                                                  ('are', 'is'))),
            libtcod.light_blue)
예제 #11
0
def berserk_self(actor, target, context):
    if not actor.fighter.has_status(
            'berserk') and not actor.fighter.has_status('exhausted'):
        actor.fighter.apply_status_effect(effects.berserk())
        if actor is not player.instance:
            ui.message(
                '%s %s!' % (syntax.name(actor).capitalize(),
                            syntax.conjugate(False, ('roar', 'roars'))),
                libtcod.red)
        return 'success'
    else:
        if actor is player.instance:
            ui.message("You cannot go berserk right now.", libtcod.yellow)
예제 #12
0
def silence(actor, target, context):
    if target.fighter.apply_status_effect(
            effects.silence(duration=context.get('duration', 10)),
            dc=context.get('base_dc', 20) +
            actor.fighter.spell_power(['arcane']),
            source_fighter=actor.fighter,
            supress_message=True):
        if actor is player.instance or target is player.instance or fov.player_can_see(
                target.x, target.y):
            ui.message(
                '%s %s silenced!' %
                (syntax.name(target).capitalize(),
                 syntax.conjugate(target is player.instance,
                                  ('are', 'is'))), libtcod.light_blue)
예제 #13
0
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'
예제 #14
0
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']))
예제 #15
0
def teleport(actor, x, y):
    if actor is None:
        actor = player.instance

    if actor is player.instance or fov.player_can_see(actor.x, actor.y):
        ui.message(
            '%s %s in a crackle of magical energy!' %
            (syntax.name(actor).capitalize(),
             syntax.conjugate(actor is player.instance,
                              ('vanish', 'vanishes'))),
            spells.essence_colors['arcane'])
    actor.set_position(x, y)
    if actor is not player.instance and fov.player_can_see(actor.x, actor.y):
        ui.message(
            '%s appears out of thin air!' % syntax.name(actor).capitalize(),
            spells.essence_colors['arcane'])
    return 'success'
예제 #16
0
def great_dive(actor, target, context):
    ui.message("{} {} into the ground!".format(
        syntax.name(actor).capitalize(),
        syntax.conjugate(actor is player.instance, ['slam', 'slams'])))

    for obj in main.current_map.fighters:
        if (obj.x, obj.y) in target:
            combat.attack_ex(actor.fighter, obj, 0)

    x, y = context['origin']
    if not main.is_blocked(x, y):
        actor.set_position(x, y)
    else:
        for t in target:
            if not main.is_blocked(t[0], t[1]):
                actor.set_position(t[0], t[1])
                break
예제 #17
0
def frog_tongue(actor, target, context):
    if target.fighter.hp > 0:
        ui.message("The frog's tongue lashes out at %s!" % syntax.name(target),
                   libtcod.dark_green)
        result = combat.attack_ex(actor.fighter,
                                  target,
                                  0,
                                  accuracy_modifier=1.5,
                                  damage_multiplier=1.5,
                                  verb=('pull', 'pulls'))
        if result == 'hit':
            if 'displacement' in target.fighter.immunities:
                if fov.player_can_see(target.x, target.y):
                    ui.message(
                        '%s %s.' % (syntax.name(target).capitalize(),
                                    syntax.conjugate(target is player.instance,
                                                     ('resist', 'resists'))),
                        libtcod.gray)
                return 'success'
            beam = main.beam(actor.x, actor.y, target.x, target.y)
            pull_to = beam[max(len(beam) - 3, 0)]
            target.set_position(pull_to[0], pull_to[1])
예제 #18
0
def reeker_breath(actor, target, context):
    #TODO: Upgrade this to use auto targeting
    x = target.x
    y = target.y
    tiles = main.cone(actor.x, actor.y, x, y, max_range=context['range'])

    if tiles is None or len(tiles) == 0 or tiles[0] is None:
        return 'cancelled'

    if fov.player_can_see(target.x, target.y) or actor is player.instance:
        ui.message(
            '%s %s a cloud of acrid fumes!' %
            (syntax.name(actor).capitalize(),
             syntax.conjugate(actor is player.instance,
                              ('breathe', 'breathes'))), libtcod.fuchsia)
    for tile in tiles:
        main.create_reeker_gas(tile[0],
                               tile[1],
                               duration=main.roll_dice('1d6') + 3)
        for obj in main.current_map.fighters:
            if obj.x == tile[0] and obj.y == tile[1]:
                combat.attack_magical(actor.fighter, obj,
                                      'ability_reeker_breath')
예제 #19
0
def summon_equipment_on_tick(ticker):
    dead_flag = False
    dropped = False
    owner = ticker.owner
    if not owner or not owner.fighter:
        dead_flag = True
    elif not ticker.equipment.equipment.is_equipped:
        if owner is player.instance or fov.player_can_see(owner.x, owner.y):
            ui.message(
                'The %s fades away as %s %s it from %s grasp.' %
                (ticker.equipment.name.title(), syntax.name(owner),
                 syntax.conjugate(owner is player.instance,
                                  ('release', 'releases')),
                 syntax.pronoun(owner, possesive=True)), libtcod.light_blue)
        dead_flag = True
        dropped = True
    elif ticker.ticks > ticker.max_ticks:
        dead_flag = True
        if owner is player.instance or fov.player_can_see(owner.x, owner.y):
            ui.message(
                "The %s fades away as it's essence depletes." %
                ticker.equipment.name.title(), libtcod.light_blue)
    if dead_flag:
        ticker.dead = True
        if ticker.equipment is not None:
            if hasattr(ticker.equipment.equipment, 'raised'):
                ticker.equipment.equipment.sh_raise()
            ticker.equipment.item.drop(no_message=True)
            ticker.equipment.destroy()
        if owner and owner.fighter:
            owner.fighter.remove_status('summoned equipment')
        if not dropped and owner and owner.fighter:
            if ticker.old_equipment is not None:
                ticker.old_equipment.equip()
            if ticker.old_left is not None:
                ticker.old_left.equip()
예제 #20
0
def throw_net(actor, target, context):
    if actor is player.instance:
        ui.message('Yo implement this', libtcod.red)
        return 'failure'

    dist = actor.distance_to(target)
    if dist > context['range']:
        return 'cancelled'

    ui.message(
        '%s %s a net at %s.' %
        (syntax.name(actor).capitalize(),
         syntax.conjugate(actor is player.instance,
                          ('throw', 'throws')), syntax.name(target)),
        libtcod.gold)
    ui.render_projectile((actor.x, actor.y), (target.x, target.y),
                         libtcod.gold,
                         character='#')
    target.fighter.apply_status_effect(
        effects.immobilized(duration=context['duration']),
        context['save_dc'],
        source_fighter=actor)

    return 'success'
예제 #21
0
def invoke_ability(ability_key,
                   actor,
                   target_override=None,
                   spell_context=None):
    import abilities
    if actor is None:
        raise Exception('Missing parameter: actor')
    info = abilities.data[ability_key]
    if info is None:
        raise Exception("Invalid action key: {}".format(ability_key))
    function = info.get('function')
    if function is None:
        raise Exception("No function for action {}".format(ability_key))

    if spell_context is not None:
        for key in spell_context.keys():
            if spell_context[key] is not None:
                info[key] = spell_context[key]
        #info = dict(info.items() + spell_context.items())

    if 'require_weapon' in info.keys():
        weapon = main.get_equipped_in_slot(actor.fighter.inventory,
                                           'right hand')
        if weapon is None or weapon.subtype != info['require_weapon']:
            ui.message(
                'You need a {} to use this ability'.format(
                    info['require_weapon']), libtcod.gray)
            return 'didnt-take-turn'

    if 'stamina_cost' in info.keys():
        if actor is player.instance and actor.fighter.stamina < info[
                'stamina_cost']:
            ui.message("You don't have enough stamina to use that ability.",
                       libtcod.gray)
            return 'didnt-take-turn'

    if 'cast_time' in info.keys():
        pretargeted = False
        if info.get('warning', False):
            targets = _get_ability_target(actor, info, target_override)
            if targets is None:
                return 'didnt-take-turn'
            info['warning_particles'] = _spawn_warning(actor, targets)
            pretargeted = targets

        if 'pre_cast' in info.keys():
            info['pre_cast'](actor, target_override)
        elif not info.get('suppress_cast_notif', False):
            ui.message_flush(
                syntax.conjugate(
                    actor is player.instance,
                    ['You begin',
                     actor.name.capitalize() + ' begins']) + ' to cast ' +
                info['name'])
        delegate = lambda: _invoke_ability_continuation(
            info, actor, target_override, function, pretargeted=pretargeted)
        if actor is player.instance:
            player.delay(info['cast_time'], delegate, 'channel-spell')
        else:
            actor.behavior.behavior.queue_action(delegate, info['cast_time'])
        return 'success'
    else:
        return _invoke_ability_continuation(info, actor, target_override,
                                            function)
예제 #22
0
def great_dive_channel(actor, target):
    ui.message("{} {} high into the air!".format(
        syntax.name(actor).capitalize(),
        syntax.conjugate(actor is player.instance, ['rise', 'rises'])))