예제 #1
0
    def equip(self, no_message=False):
        if self.is_equipped:
            return  # already equipped

        old_equipment = None
        if self.slot == 'ring':
            rings = main.get_equipped_in_slot(self.holder.fighter.inventory,
                                              self.slot)
            if len(rings) >= 2:
                options_ex = collections.OrderedDict()
                options_ex['a'] = {'option': {'text': rings[0].name}}
                options_ex['b'] = {'option': {'text': rings[1].name}}
                index = ui.menu_ex("Unequip which ring?",
                                   options_ex,
                                   40,
                                   return_as_char=True)
                old_equipment = rings[ord(index) - ord('a')].equipment
        else:
            old_equipment = main.get_equipped_in_slot(
                self.holder.fighter.inventory, self.slot)

        # First check weight
        if self.holder is player.instance:
            old_weight = 0
            if old_equipment is not None:
                old_weight = old_equipment.weight
            if self.holder.fighter.equip_weight + self.weight - old_weight > self.holder.fighter.max_equip_weight:
                ui.message('That is too heavy.', libtcod.orange)
                return

        # Attempt to dequip
        if self.slot == 'both hands':
            rh = main.get_equipped_in_slot(self.holder.fighter.inventory,
                                           'right hand')
            lh = main.get_equipped_in_slot(self.holder.fighter.inventory,
                                           'left hand')
            if not ((rh is None or rh.dequip() != 'cancelled') and
                    (lh is None or lh.dequip() != 'cancelled')):
                return 'cancelled'
        else:
            if old_equipment is not None:
                if old_equipment.dequip(self.holder) == 'cancelled':
                    return 'cancelled'

        self.is_equipped = True
        if self.holder is player.instance and not no_message:
            ui.message('Equipped ' + self.owner.name + '.', libtcod.orange)
        if self.status_effect is not None and self.holder.fighter is not None:
            self.holder.fighter.apply_status_effect(self.status_effect(None))
        if self.category == 'book' and self.holder == player.instance:
            for spell, level in self.get_active_spells().items():
                if self.spell_charges[spell] < spells.library[
                        spell].max_spell_charges(level):
                    player.instance.fighter.apply_status_effect(
                        effects.meditate())
                    break
        return 'success'
예제 #2
0
def ranged_attack(actor, target, context):
    spent = actor.fighter.adjust_ammo(-1)
    if spent != 0 and actor.fighter is not None:
        weapon = main.get_equipped_in_slot(actor.fighter.inventory,
                                           'right hand')
        ui.render_projectile((actor.x, actor.y), (target.x, target.y),
                             libtcod.white)
        result = combat.attack_ex(actor.fighter,
                                  target,
                                  0,
                                  verb=("shoot", "shoots"),
                                  weapon=weapon,
                                  ranged=True)
        if result == 'failed':
            actor.fighter.adjust_ammo(-spent, False)  # Refund ammo
            return 'didnt-take-turn'

        if result == 'miss' or target.fighter is None:
            # ammo lands on the ground
            main.drop_ammo(target.x, target.y, -spent)
        else:
            # target was hit, ammo sticks in them
            if hasattr(target, 'recoverable_ammo'):
                target.recoverable_ammo += -spent
            else:
                target.recoverable_ammo = -spent

    else:
        return 'didnt-take-turn'
예제 #3
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'
예제 #4
0
def pickaxe_dig(dx, dy):
    result = common.dig(player.instance.x + dx, player.instance.y + dy)
    if result == 'failed':
        ui.message('You cannot dig there.', libtcod.orange)
    else:
        item = main.get_equipped_in_slot(player.instance.fighter.inventory,
                                         'right hand')
        if item is not None:
            main.check_breakage(item)
예제 #5
0
def summon_equipment(actor, item):
    if actor is player.instance and len(
            player.instance.fighter.inventory) >= 26:
        ui.message('You are carrying too many items to summon another.')
        return 'didnt-take-turn'

    summoned_equipment = main.create_item(item, material='', quality='')
    if summoned_equipment is None:
        return

    expire_ticker = main.Ticker(15, summon_equipment_on_tick)
    equipped_item = None
    expire_ticker.old_left = None
    if summoned_equipment.equipment.slot == 'both hands':
        equipped_item = main.get_equipped_in_slot(actor.fighter.inventory,
                                                  'right hand')
        expire_ticker.old_left = main.get_equipped_in_slot(
            actor.fighter.inventory, 'left hand')
    elif summoned_equipment.equipment.slot == 'floating shield':
        #can't stack two shields
        equipped_item = actor.fighter.get_equipped_shield()
    else:
        equipped_item = main.get_equipped_in_slot(
            actor.fighter.inventory, summoned_equipment.equipment.slot)
    expire_ticker.old_equipment = equipped_item

    if equipped_item is not None:
        equipped_item.dequip()
    summoned_equipment.item.pick_up(actor, True)
    expire_ticker.equipment = summoned_equipment
    effect = effects.StatusEffect('summoned equipment',
                                  expire_ticker.max_ticks + 1,
                                  summoned_equipment.color)
    actor.fighter.apply_status_effect(effect)
    expire_ticker.effect = effect
    expire_ticker.owner = actor
    main.current_map.tickers.append(expire_ticker)

    if actor is player.instance:
        ui.message("A {} appears!".format(summoned_equipment.name),
                   libtcod.white)

    return 'success'
예제 #6
0
def bow_shot(actor, target, context):
    weapon = main.get_equipped_in_slot(actor.fighter.inventory, 'right hand')
    ui.render_projectile((actor.x, actor.y), (target.x, target.y),
                         libtcod.white)
    combat.attack_ex(actor.fighter,
                     target,
                     0,
                     verb=("shoot", "shoots"),
                     weapon=weapon,
                     ranged=True)
예제 #7
0
def sweep_attack(actor, target, context):
    weapon = main.get_equipped_in_slot(actor.fighter.inventory, 'right hand')

    if weapon is None or weapon.subtype != 'polearm':
        ui.message('You need a polearm to use this ability')
        return 'didnt-take-turn'

    targets = main.get_objects(actor.x,actor.y,distance=2, condition=lambda o: o.fighter is not None and o.fighter.team != 'ally')
    targets = [t for t in targets if (abs(t.x - actor.x) == 2 or abs(t.y - actor.y) == 2)]
    if len(targets) > 0:
        for enemy in targets:
            combat.attack_ex(actor.fighter,enemy,0, verb=('sweep','sweeps'))
        actor.fighter.adjust_stamina(-(weapon.stamina_cost * context['stamina_multiplier']))
        return True
    else:
        ui.message('There are no targets in range')
        return 'didnt-take-turn'
예제 #8
0
def mace_stun(attacker, target, damage):
    scaling_factor = 1
    stun_duration = 1
    if target.fighter is None:
        return
    if (attacker is player.instance):
        scaling_factor = attacker.player_stats.str / 10
        if main.has_skill('ringing_blows'):
            scaling_factor *= 1.5
            stun_duration = 2
    if libtcod.random_get_float(0, 0.0, 1.0) * scaling_factor > 0.85:
        if attacker == player.instance:
            ui.message(
                "Your " +
                main.get_equipped_in_slot(player.instance.fighter.inventory,
                                          'right hand').owner.name.title() +
                " rings out!", libtcod.blue)
        target.fighter.apply_status_effect(effects.stunned(stun_duration))
예제 #9
0
def boomerang(actor, target, context):
    sprites = ['<', 'v', '>', '^']
    ui.render_projectile((actor.x, actor.y), (target.x, target.y),
                         libtcod.yellow, sprites)
    attack_result = actor.fighter.attack(target)
    if attack_result == 'failed':
        return 'didnt-take-turn'
    catch_skill = 30
    if actor.player_stats:
        catch_skill = actor.player_stats.agi
    if main.roll_dice('1d' + str(catch_skill)) >= 10:
        #catch boomerang
        ui.render_projectile((target.x, target.y), (actor.x, actor.y),
                             libtcod.yellow, sprites)
        if actor is player.instance:
            ui.message('You catch the boomerang as it returns to you',
                       libtcod.gray)
    else:
        possible_tiles = []
        for y in range(actor.y - 2, actor.y + 2):
            for x in range(actor.x - 2, actor.x + 2):
                if x >= 0 and y >= 0 and x < consts.MAP_WIDTH and y < consts.MAP_HEIGHT and not main.is_blocked(
                        x, y):
                    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)]
        ui.render_projectile((target.x, target.y),
                             (selected_tile[0], selected_tile[1]),
                             libtcod.yellow, sprites)
        weapon = main.get_equipped_in_slot(actor.fighter.inventory,
                                           'right hand')
        weapon.owner.item.drop(no_message=True)
        weapon.owner.x = selected_tile[0]
        weapon.owner.y = selected_tile[1]
        if actor is player.instance or fov.player_can_see(actor.x, actor.y):
            ui.message(
                '%s boomerang falls to the ground.' %
                syntax.name(target, possesive=True).capitalize(), libtcod.gray)
        libtcod.console_flush()
예제 #10
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)
예제 #11
0
def vanguard_attack(actor,target):
    weapon = main.get_equipped_in_slot(actor.fighter.inventory, 'right hand')
    if weapon is not None and weapon.subtype == 'polearm':
        common.attack(actor,target)