Example #1
0
    def tick(self, game_map):
        results = []
        coords = coordinates_within_circle((self.owner.x, self.owner.y),
                                           self.range)
        for coord in coords:
            entities = game_map.current_level.entities.get_entities_in_position(
                coord)
            if entities:
                for entity in entities:
                    if entity == self.owner:
                        continue

                    if not entity.animate:
                        continue

                    if entity.health:
                        damage = die_roll(self.number_of_dice,
                                          self.type_of_dice)
                        damage_results, total_damage = entity.health.take_damage(
                            damage, self.owner, self.damage_type)
                        if total_damage > 0:
                            msg = Message(
                                f"{entity.name} takes {str(damage)} damage from {self.owner.name}'s {self.name}.",
                                COLORS.get('damage_text'),
                                target=entity,
                                type=MessageType.EFFECT)
                            results.extend(damage_results)
                            results.extend([{ResultTypes.MESSAGE: msg}])

        return results
Example #2
0
def change_power(**kwargs):
    '''Cast increase power.

    Update an entity's power by [number_of_dice]D[type_of_dice].

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       number_of_dice (int): number of die to roll.
       target (Entity): The entity that is being targetted by the spell.
       type_of_dice (int): Type of die to roll.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    number_of_dice = kwargs.get('number_of_dice')
    target = kwargs.get('target')
    type_of_dice = kwargs.get('type_of_dice')

    results = []

    extra = die_roll(number_of_dice, type_of_dice)
    target.offence.base_power = target.offence.base_power + extra
    results.append({
        ResultTypes.MESSAGE:
        Message('You feel like you can take anything on!',
                COLORS.get('success_text'))
    })

    return results
Example #3
0
def lightning(**kwargs):
    '''Cast a lightning bolt.

    A bolt does ELECTRIC damage to all damagable entities in a line. The line is
    drawn between the caster, through the target point and stops when it hits a
    blocking tile.

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       game_map (GameMap): Current game map.
       number_of_dice (int): number of die to roll.
       target_x (int): x co-ordinate.
       target_y (int): y co-ordinate.
       type_of_dice (int): Type of die to roll.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    game_map = kwargs.get('game_map')
    number_of_dice = kwargs.get('number_of_dice')
    target_x = kwargs.get('target_x')
    target_y = kwargs.get('target_y')
    type_of_dice = kwargs.get('type_of_dice')

    ray = bresenham_ray(game_map, (caster.x, caster.y), (target_x, target_y))

    results = []

    ray.pop(0)  #first item is caster xy

    for x, y in ray:
        entities = game_map.current_level.entities.get_entities_in_position(
            (x, y))
        for entity in entities:
            if entity.health and not entity.health.dead:
                damage = die_roll(number_of_dice, type_of_dice)
                results.append({
                    ResultTypes.MESSAGE:
                    Message(
                        f"A lighting bolt strikes the {entity.name} with a loud crack of thunder!",
                        COLORS.get('effect_text'),
                        target=entity,
                        type=MessageType.EFFECT)
                })
                damage_results, total_damage = entity.health.take_damage(
                    damage, caster, DamageType.ELECTRIC)
                results.append({
                    ResultTypes.MESSAGE:
                    Message(f"{entity.name} takes {str(total_damage)} damage.",
                            COLORS.get('damage_text'))
                })
                results.extend(damage_results)

    return results
Example #4
0
def fireball(**kwargs):
    '''Cast a fireball.

    Does FIRE damage to all damagable entities in a circle centered on the
    target point.

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       game_map (GameMap): Current game map.
       number_of_dice (int): number of die to roll.
       radius (int): radius of the spell effect.
       target_x (int): x co-ordinate.
       target_y (int): y co-ordinate.
       type_of_dice (int): Type of die to roll.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    game_map = kwargs.get('game_map')
    number_of_dice = kwargs.get('number_of_dice')
    radius = kwargs.get('radius')
    target_x = kwargs.get('target_x')
    target_y = kwargs.get('target_y')
    type_of_dice = kwargs.get('type_of_dice')

    results = []

    if not game_map.current_level.fov[target_x, target_y]:
        results.append({
            ResultTypes.MESSAGE:
            Message('You cannot target a tile outside your field of view.',
                    COLORS.get('neutral_text'))
        })
        return results

    results.append({
        ResultTypes.MESSAGE:
        Message(
            'The fireball explodes, burning everything within {0} tiles!'.
            format(radius), COLORS.get('effect_text'))
    })

    #TODO: refactor, this is probably horribly inefficent
    for entity in game_map.current_level.entities:
        if entity.point.distance_to(Point(
                target_x, target_y)) <= radius and entity.health:
            damage = die_roll(number_of_dice, type_of_dice)
            damage_results, total_damage = entity.health.take_damage(
                damage, caster, DamageType.FIRE)
            results.extend(damage_results)

    return results
Example #5
0
    def on_attack(self, source, target, game_map):
        results = []

        damage = die_roll(self.number_of_dice, self.type_of_dice)
        damage_results, total_damage = target.health.take_damage(damage, source, self.damage_type)
        if total_damage > 0:
            msg = Message(f"{target.name} takes {str(damage)} {self.name} total_damage.", COLORS.get('damage_text'), source=source, target=target, type=MessageType.EFFECT)
            results.extend(damage_results)
            results.extend([{ResultTypes.MESSAGE: msg}])

        return results
Example #6
0
    def on_attack(self, source, target, game_map):
        results = []

        damage = die_roll(self.number_of_dice, self.type_of_dice)
        damage_results, total_damage = target.health.take_damage(damage, source, DamageType.DEFAULT)
        if total_damage > 0:
            drain_amount = max(1, int(total_damage * self.transfer))
            msg = Message(f"{target.name} takes {str(damage)} {self.name} damage.", COLORS.get('damage_text'), source=source, target=target, type=MessageType.EFFECT)
            results.extend(damage_results)
            results.extend([{ResultTypes.MESSAGE: msg}])
            results.extend(source.health.heal(drain_amount))

        return results
Example #7
0
def heal(**kwargs):
    '''Cast heal.

    Heal a target entity.

    Parameters
    ----------
    kwargs:
       number_of_dice (int): number of die to roll.
       target (Entity): The entity that is being targetted by the spell.
       type_of_dice (int): Type of die to roll.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    number_of_dice = kwargs.get('number_of_dice')
    target = kwargs.get('target')
    type_of_dice = kwargs.get('type_of_dice')

    results = []

    if target.health.hp == target.health.max_hp:
        results.append({
            ResultTypes.MESSAGE:
            Message(f"{target.name} is already at full health.",
                    COLORS.get('neutral_text'),
                    target=target,
                    type=MessageType.EFFECT)
        })
    else:
        target.health.heal(die_roll(number_of_dice, type_of_dice))
        results.append({
            ResultTypes.MESSAGE:
            Message(f"{target.name} wounds start to close up.",
                    COLORS.get('success_text'),
                    target=target,
                    type=MessageType.EFFECT)
        })

    return results
Example #8
0
def change_defence(**kwargs):
    '''Cast change defence.

    Update an entity's defence by [number_of_dice]D[type_of_dice].

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       number_of_dice (int): number of die to roll.
       target (Entity): The entity that is being targetted by the spell.
       type_of_dice (int): Type of die to roll.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    number_of_dice = kwargs.get('number_of_dice')
    target = kwargs.get('target')
    type_of_dice = kwargs.get('type_of_dice')

    results = []

    extra = die_roll(number_of_dice, type_of_dice)
    target.defence.base_defence = target.defence.base_defence + extra
    results.append({
        ResultTypes.MESSAGE:
        Message('You feel more secure in yourself!',
                COLORS.get('success_text'),
                target=target,
                type=MessageType.EFFECT)
    })

    return results
Example #9
0
 def damage(self):
     """Calculate damage done in a hit."""
     return die_roll(self.number_of_dice, self.type_of_dice,
                     self.bonus_damage)
Example #10
0
def teleport(**kwargs):
    '''Cast teleport.

    Transport the casting entity to a random open tile on the map.
    There is a chance the teleport will have a secondary negative effect:
    10% of entity being damaged for 1d6 + distance between start and end points.
    1% chance a clone of the entity is created which hunts them down.

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       game_map (GameMap): Current game map.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    game_map = kwargs.get('game_map')

    results = []

    point = game_map.current_level.find_random_open_position()
    orginal_point = caster.point
    caster.movement.place(point.x, point.y, game_map.current_level)

    results.append({
        ResultTypes.MESSAGE:
        Message(
            'You feel like you are torn apart and put back together again.',
            COLORS.get('success_text'))
    })
    results.append({ResultTypes.FOV_RECOMPUTE: True})

    chance_of_teleport_going_wrong = randint(1, 100)

    if (chance_of_teleport_going_wrong >= 99):
        clone = bestiary.create_player()
        clone_point = game_map.current_level.find_random_open_position()
        clone.set_point(clone_point)
        clone.char = 'C'
        clone.base_name = 'Clone of ' + clone.base_name
        clone.add_component(BasicNPC(), 'ai')
        clone.ai.set_target(caster)
        clone.ai.tree.namespace["target_point"] = caster.point
        game_map.current_level.add_entity(clone)
        results.append({
            ResultTypes.MESSAGE:
            Message(f"You feel as if you are split in two.",
                    COLORS.get('damage_text'))
        })

    elif (chance_of_teleport_going_wrong >= 89):
        damage_results, total_damage = caster.health.take_damage(
            die_roll(1, 6, int(orginal_point.distance_to(point))))
        results.append({
            ResultTypes.MESSAGE:
            Message(f"You take {str(total_damage)} damage.",
                    COLORS.get('damage_text'))
        })
        results.extend(damage_results)

    return results
Example #11
0
def chain_lightning(**kwargs):
    '''Cast chain lightning.

    Does ELECTRIC damage to a max of [number_of_dice] entities within a [radius].
    Each entity recieves 1D[type_of_dice] damage.

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       game_map (GameMap): Current game map.
       number_of_dice (int): number of die to roll.
       radius (int): radius of the spell effect.
       target_x (int): x co-ordinate.
       target_y (int): y co-ordinate.
       type_of_dice (int): Type of die to roll.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    game_map = kwargs.get('game_map')
    number_of_dice = kwargs.get('number_of_dice')
    radius = kwargs.get('radius')
    target = kwargs.get('target')
    target_x = kwargs.get('target_x')
    target_y = kwargs.get('target_y')
    type_of_dice = kwargs.get('type_of_dice')

    results = []
    targets = []

    if (not target_x) and target:
        target_x = target.x
        target_y = target.y

    start_x = max(0, target_x - radius)
    start_y = max(0, target_y - radius)

    end_x = min(target_x + radius, game_map.current_level.width)
    end_y = min(target_y + radius, game_map.current_level.width)

    for x in range(start_x, end_x):
        for y in range(start_y, end_y):
            entities = game_map.current_level.entities.get_entities_in_position(
                (x, y))
            for entity in entities:
                if entity == caster:
                    continue
                if not entity.health:
                    continue
                if entity.health.dead:
                    continue

                targets.append(entity)

    if targets:
        total_targets = min(len(targets), number_of_dice)
        for i in range(total_targets):
            target = targets.pop()
            damage = die_roll(1, type_of_dice)
            if i > 0:
                results.append({
                    ResultTypes.MESSAGE:
                    Message(
                        f"The bolt bounces and strikes {target.name} with a loud crack of thunder!",
                        COLORS.get('effect_text'),
                        target=target,
                        type=MessageType.EFFECT)
                })
            else:
                results.append({
                    ResultTypes.MESSAGE:
                    Message(
                        f"A lighting bolt strikes the {target.name} with a loud crack of thunder!",
                        COLORS.get('effect_text'),
                        target=target,
                        type=MessageType.EFFECT)
                })

            damage_results, total_damage = target.health.take_damage(
                damage, caster, DamageType.ELECTRIC)
            results.append({
                ResultTypes.MESSAGE:
                Message(f"{target.name} takes {str(total_damage)} damage.",
                        COLORS.get('damage_text'))
            })
            results.extend(damage_results)
    else:
        results.append({
            ResultTypes.MESSAGE:
            Message("No enemy is close enough to strike.",
                    COLORS.get('failure_text'))
        })

    return results
Example #12
0
def magic_missile(**kwargs):
    '''Cast a number of magic missiles.

    Cast a missile that does 1d6 damage. 1 missile plus an additional missile
    per 3 caster level.
    e.g.:
    Caster level 1: 1 missile
    Caster level 3: 2 missiles
    Caster level 5: 2 missiles
    Caster level 7: 3 missiles
    etc.

    Parameters
    ----------
    kwargs:
       caster (Entity): Entity that initiated the spell.
       game_map (GameMap): Current game map.
       target (Entity): The entity that is being targetted by the spell.

    Returns
    -------
    results (list)
        Results of casting the spell.
    '''
    caster = kwargs.get('caster')
    game_map = kwargs.get('game_map')
    target = kwargs.get('target')

    results = []

    if not game_map.current_level.fov[target.x, target.y]:
        results.append({
            ResultTypes.MESSAGE:
            Message('You cannot target a tile outside your field of view.',
                    COLORS.get('neutral_text'))
        })
        return results
    else:
        end = bresenham_line(game_map, caster.point.tuple(),
                             target.point.tuple())

        if end[-1] != target.point.tuple():
            results.append({
                ResultTypes.MESSAGE:
                Message('Target is not in line of sight.',
                        COLORS.get('neutral_text'))
            })
            return results

    missiles = (caster.level.current_level // 3) + 1
    for _ in range(missiles):
        damage = die_roll(1, 6)
        results.append({
            ResultTypes.MESSAGE:
            Message(f"A magic missile strikes {target.name}.",
                    COLORS.get('effect_text'),
                    target=target,
                    type=MessageType.EFFECT)
        })
        damage_results, total_damage = target.health.take_damage(
            damage, caster, DamageType.MAGIC)
        results.append({
            ResultTypes.MESSAGE:
            Message(f"{target.name} takes {str(total_damage)} damage.",
                    COLORS.get('damage_text'))
        })
        results.extend(damage_results)

    return results