Пример #1
0
    def take_turn(self):
        """..."""
        # some kind of lock to prevent double calling AND queueing of
        # same objects on a single turn.

        monster = self.owner

        monster.path = None

        if self.num_turns > 0:  # still confused...
            # move in a random direction, and decrease the number of turns
            # confused
            if monster.visible:
                monster.scene.msg_log.add(
                    (monster.name + " looks confused"), get_color("pink"))
            if random.randint(1, 100) > 33:
                monster.move_rnd()
            else:
                monster.move()
            self.num_turns -= 1

        # restore the previous AI (this one will be deleted because it's not
        # referenced anymore)
        else:
            self.effect = False
            monster.ai = monster.default_ai
            monster.color = monster.default_color
            monster.scene.msg_log.add(
                'The ' + monster.name + ' is no longer confused!',
                get_color("yellow"))
Пример #2
0
def cast_fireball(who, target):
    """..."""
    if target is None:
        return 'cancelled'

    current_level = who.current_level
    msg_log = who.scene.msg_log

    msg_log.add(
        'The fireball explodes, burning everything within ' +
        str(FIREBALL_RADIUS) + ' tiles!', get_color("yellow"))

    area = current_level.get_area(pos=target.pos, radius=FIREBALL_RADIUS)

    for pos in area:
        for creature in current_level[pos].creatures:
            if creature.combat:
                msg_log.add("The {} gets burned for {} hit points.".format(
                    creature.name, FIREBALL_DAMAGE), get_color("orange"))
                creature.combat.receive_dmg(FIREBALL_DAMAGE, source=who)

    who.scene.tile_fx.add(
        coord=area,
        color=get_color("orange"),
        duration=1)

    return True
Пример #3
0
    def __init__(self, *, new=True, character=None, mode='Pit', **kwargs):
        """..."""
        super().__init__()

        self.mode = mode
        self.create_layers(character=character,
                           new=new,
                           msg="Creating a world of treasures and dangers...")
        self.set_fov()
        self.on_update()

        self.msg_log.clear()

        if new:
            self.msg_log.add(
                ('Welcome stranger! '
                 'Prepare to perish in the Tombs of the Ancient Kings.'),
                get_color("purple"))
        else:
            self.msg_log.add(
                ('Welcome back stranger! '
                 'This time you WILL perish in the Tombs of the Ancient'
                 ' Kings!'), get_color("purple"))
        self.msg_log.add(('You are at level {} of the dungeon.'.format(
            self.current_level.header.level)), get_color("orange"))
        # self.manager.disable_fps()
        # [layer.__setattr__('visible', False) for layer in self.layers]
        self.on_update()
Пример #4
0
    def __init__(self, parent, name, alpha=90):
        """..."""
        self.max_width = 160
        super().__init__(parent=parent, rect=Rect(16, 16, self.max_width, 26))

        self.color_table = LBPercentTable(
            default_to_first=True,
            table=(
                (0, (223, 0, 0, 192)),  # red
                (25, (*get_color("yellow")[:3], 176)),
                (50, (*get_color("lime")[:3], 160)),
                (75, (*get_color("green")[:3], 144))))
        self.previous_value = None
        self.previous_max = None
Пример #5
0
def cast_lightning(who, target=None):
    # find closest enemy (inside a maximum range) and damage it
    monster = who.combat.closest_monster(
        who=who, max_range=LIGHTNING_RANGE)
    if monster is None:  # no enemy found within maximum range
        who.scene.msg_log.add(
            'No enemy is close enough to strike.', get_color("yellow"))
        return 'cancelled'

    # zap it!
    who.scene.msg_log.add(
        'A lighting bolt strikes the ' + monster.name +
        ' with a loud thunder! The damage is '
        + str(LIGHTNING_DAMAGE) + ' hit points.', get_color("light_blue"))
    monster.combat.receive_dmg(LIGHTNING_DAMAGE)
Пример #6
0
    def create_items(self):
        items = self._items
        item_render = []

        main_font_size = int(self.head_font_size // 1.1)
        self.main_font = self.fonts.load('caladea-regular.ttf', main_font_size)
        main_font_size = self.main_font.size("A")

        for i, item in enumerate(items):

            txt_sfc = self.main_font.render(item, True, self.unselected_color)
            txt_obj = txt_sfc.get_rect()
            x, y = (self.screen_size[0] // 2, self.head_title_obj.bottom +
                    self.head_title_obj.height * 2 + main_font_size[1] * i)

            txt_obj.midtop = x, y

            txt_shd_sfc = self.main_font.render(item, True, get_color("black"))
            txt_shd_obj = txt_shd_sfc.get_rect()
            txt_shd_obj.midtop = x + 2, y + 2

            item_render.append(
                ((txt_sfc, txt_obj), (txt_shd_sfc, txt_shd_obj)))

            self.item_render = item_render
Пример #7
0
 def add(self, string, color=None):
     if color is None:
         color = get_color("desaturated_green")
     print(string)
     img = self.font.render(string, color)
     self._history.append(img)
     self._history = self._history[-5:]
Пример #8
0
    def equip(self):
        """Equip object and show a message about it.

        If the slot is already being used, unequip whatever is there first.
        """
        equipped_in_slot = self.possessor.combat.equipped_in_slot

        if self.type == 'two-handed melee weapons':
            for slot in ['right hand', 'left hand']:
                old_equipment = equipped_in_slot(slot)
                if old_equipment:
                    old_equipment.unequip()
            self.slot = 'right hand'
        else:
            for slot in ['right hand', 'left hand']:
                old_equipment = equipped_in_slot(slot)
                if old_equipment and \
                        old_equipment.type == 'two-handed melee weapons':
                    old_equipment.unequip()
                    self.slot = 'right hand'
                    break
                elif not old_equipment:
                    self.slot = slot
                    break

            if self.slot is None:
                self.slot = 'right hand'
                old_equipment = equipped_in_slot(self.slot)
                old_equipment.unequip()

        self.is_equipped = True
        self.scene.msg_log.add(
            'Equipped ' + self.owner.name + ' on ' +
            self.slot + '.', get_color("light_green"))
Пример #9
0
def cast_heal(who, target=None):
    if target is None:
        target = who
    elif not hasattr(target, 'combat'):
        who.scene.msg_log.add(
            "You can't heal the " + target.name + " .", get_color("yellow"))
        return 'cancelled'

    # heal the target
    if target.combat.hit_points_current == target.combat.hit_points_total:
        who.scene.msg_log.add(
            'You are already at full health.', get_color("yellow"))
        return 'cancelled'

    target.combat.heal(HEAL_AMOUNT)
    who.scene.msg_log.add(
        'Your wounds start to feel better!', get_color("light_violet"))
Пример #10
0
def change_dng_level(who, direction):
    if direction == "down":
        who.scene.msg_log.add(
            'There are stairs going {} here.'.format(direction) +
            "You descend deeper into the heart of the dungeon...",
            get_color("orange"))
        who.scene.new_level(who.scene.current_level + 1)
        return True
Пример #11
0
    def increase_stat(self, choice):
        """..."""
        id, desc = choice

        self.combat._base_att[id] += 1
        self.update_hp()

        self.scene.gfx.msg_log.add(desc.replace("current", "previous"),
                                   get_color("cyan"))
Пример #12
0
def player_death(victim):
    """..."""
    # the game ended!
    victim.scene.msg_log.add('You died!')
    victim.scene.state = 'dead'

    # for added effect, transform the player into a corpse!
    victim.id = ord('%')
    victim.color = get_color("dark_red")
Пример #13
0
def rnd_cast_confuse(who, target=None):
    # find closest enemy in-range and confuse it
    monster = who.combat.closest_monster(
        who=who, max_range=CONFUSE_RANGE)
    if monster is None:  # no enemy found within maximum range
        who.scene.msg_log.add(
            'No enemy is close enough to confuse.', get_color("yellow"))
        return 'cancelled'
    # replace the monster's AI with a "confused" one; after some turns it will
    # restore the old AI
    monster.ai = ai_comp.Confused()
    monster.ai.owner = monster  # tell the new component who owns it
    monster.color = get_color("pink")

    who.scene.msg_log.add(
        'The eyes of the ' + monster.name +
        ' look vacant, as he starts to stumble around!',
        get_color("light_green"))
Пример #14
0
    def pick_up(self, getter):
        """..."""
        msg_log = self.scene.msg_log

        # add to the player's inventory and remove from the map
        if len(getter.inventory) >= 26:
            if getter == self.player:
                self.scene.msg_log.add(
                    'Your inventory is full, cannot pick up ' +
                    self.owner.name + '.', get_color("yellow"))
        else:
            self.scene.rem_obj(self.owner, 'objects', self.owner.pos)

            getter.inventory.append(self.owner)
            self.possessor = getter

            msg_log.add(
                'You picked up a ' + self.owner.name + '!',
                get_color("blue"))
Пример #15
0
    def unequip(self):
        """Unequip object and show a message about it."""
        if not self.is_equipped:
            return
        self.is_equipped = False

        self.scene.msg_log.add(
            'Unequipped ' + self.owner.name + ' from ' +
            self.slot + '.', get_color("light_yellow"))
        self.slot = None
Пример #16
0
    def __init__(self, **kwargs):
        """..."""
        combat = kwargs.pop("combat", None)
        if combat is None:
            race = kwargs.pop("race", None)
            _class = kwargs.pop('_class', None)
            combat = creatures.Character(race=race, _class=_class, owner=self)
        self.combat = combat

        self.color = get_color("yellow")
        super().__init__(name=combat.name, **kwargs)
Пример #17
0
    def __init__(self, *, parent, rect=None):
        """..."""
        super().__init__(parent=parent, rect=rect)
        self.text = " "
        self.font = Font(name='caladea-bold.ttf',
                         font_size=14,
                         renderer=parent.manager.fonts,
                         color=get_color("desaturated_green"))
        self.def_topright = self.parent.manager.width - 8, 8

        self.previous_text = None
        self.surface = None
Пример #18
0
 def gain_ability():
     self.scene.gfx.msg_log.add(
         'Your battle skills grow stronger! You reached level ' +
         str(self.combat.level) + '!', get_color("cyan"))
     self.scene.parent.choice(
         title='Level up! Choose a stat to raise:',
         items=[
             'Strength (current: {})'.format(self.combat._base_att[0]),
             'Dexterity (current: {})'.format(self.combat._base_att[1]),
             'Constitution (current: {})'.format(
                 self.combat._base_att[2])
         ],
         callback=self.increase_stat)
Пример #19
0
def monster_death(victim):
    """..."""
    import obj_components
    # transform it into a nasty corpse! it doesn't block, can't be
    # attacked and doesn't move
    victim.scene.msg_log.add('{} is dead! You gain {} xp'.format(
        victim.name.capitalize(), victim.combat.xp_award), get_color("cyan"))

    victim.scene.rem_obj(victim, 'creatures', victim.pos)
    if random.randint(1, 100) > 66:
        victim.id = ord('%')
        victim.color = get_color("dark_red")
        victim.item = obj_components.Item('remains')
        victim.item.owner = victim
        victim.name = 'remains of ' + victim.name

        victim.scene.add_obj(victim, 'objects', victim.pos)

    """TODO: standardize death as method."""
    victim.blocks = False
    victim.combat = None
    victim.ai = None
Пример #20
0
def cast_confuse(who, target=None):
    status = 'ok'
    if target is None or not hasattr(target, 'combat'):
        status = 'cancelled'
    elif target.combat is None:
        status = 'cancelled'

    if status == 'cancelled':
        who.scene.msg_log.add("Thats not a valid target.",
                                  get_color("yellow"))
        return 'cancelled'
    else:
        # replace the monster's AI with a "confused" one; after some turns
        # it will restore the old AI
        target.ai = ai.Confused()
        target.ai.owner = target  # tell the new component who owns it
        target.color = get_color("pink")

        who.scene.msg_log.add(
            'The eyes of the ' + target.name +
            ' look vacant, as he starts to stumble around!',
            get_color("pink"))
Пример #21
0
    def drop(self, dropper):
        """Add to the map and remove from the player's inventory.

        Also, place  it at the player's coordinates.
        If it is an equipment, unequip it first.
        """
        if self.owner.equipment:
            self.owner.equipment.unequip()

        self.scene.add_obj(self.owner, 'objects', self.owner.pos)
        dropper.inventory.remove(self.owner)
        self.possessor = None

        self.scene.msg_log.add(
            'You dropped a ' + self.owner.name + '.', get_color("yellow"))
        return 'dropped'
Пример #22
0
    def create_head(self):
        self.screen_size = screen_size = self.screen.get_size()
        self.head_font_size = head_font_size = screen_size[1] // 17
        self.head_font = self.fonts.load('caladea-regular.ttf', head_font_size)

        x, y = (screen_size[0] // 2, screen_size[1] // 5)

        self.head_title_sfc = self.head_font.render(self._title, True,
                                                    self.title_color)
        self.head_title_obj = self.head_title_sfc.get_rect()
        self.head_title_obj.center = (x, y)

        self.head_title_shadow_sfc = self.head_font.render(
            self._title, True, get_color("darker_gray"))
        self.head_title_shadow_obj = self.head_title_sfc.get_rect()
        self.head_title_shadow_obj.center = (x + 2, y + 2)
Пример #23
0
    def equip(self):
        """Equip object and show a message about it.

        If the slot is already being used, unequip whatever is there first.
        """
        equipped_in_slot = self.possessor.combat.equipped_in_slot

        self.slot = 'left hand' if self.type == 'shields' else 'body'

        old_equipment = equipped_in_slot(self.slot)
        if old_equipment:
            old_equipment.unequip()

        self.is_equipped = True
        self.scene.msg_log.add(
            'Equipped ' + self.owner.name + ' on ' +
            self.slot + '.', get_color("light_green"))
Пример #24
0
    def set_inventory(self, holder, target=None, mode="use"):
        """..."""
        self.holder = holder
        self.target = target
        self.mode = mode
        self.inventory = self.holder.inventory
        self.inv_render = []
        offset = self.offset
        main_font = self.main_font

        limit = self.rows * self.cols
        for i, item in enumerate(self.inventory[offset:offset + limit]):
            row = i % self.rows
            col = i // self.rows

            if item.equipment:
                if item.equipment.is_equipped:
                    text = "*{} ({})".format(item.name, item.equipment.slot)
                else:
                    text = "{} ({})".format(item.name, item.equipment.slot)
                color = item.color
            else:
                text = item.name + str(i)
                color = None

            txt_sfc = main_font.render(text, color)
            txt_obj = txt_sfc.get_rect()
            txt_obj.left = (self.main_rect.left + self.tab_x +
                            self.main_item_w * col)
            txt_obj.top = self.main_rect.top + (self.main_item_h * row) + 12
            txt_sfc.set_rect(txt_obj)

            txt_shd_sfc = main_font.render(text, color=get_color("black"))
            txt_shd_sfc.set_rect(txt_obj.mode(2, 2))

            self.inv_render.append(txt_shd_sfc, txt_sfc)
Пример #25
0
    def create_head(self):
        """..."""
        factory = self.manager.factory
        head_font = self.head_font

        h = self.head_font.height * 2
        w = int(self.w * 0.9)
        x, y = int(self.w * 0.05), int(self.h * 0.05)

        head_rect = head_rect = Rect(x, y, w, h)
        self.head_surface = factory.from_gradient(rect=head_rect)

        head_title_sfc = head_font.render("< Inventory >")
        head_title_obj = head_title_sfc.get_rect()
        head_title_obj.center = head_rect.center
        head_title_sfc.set_rect(head_title_obj)

        head_title_shadow_sfc = head_font.render("< Inventory >",
                                                 color=get_color("black"))
        head_title_shadow_sfc.set_rect(head_title_obj.move(2, 2))

        self.head_rect = head_rect
        self.head_title_sfc = head_title_sfc
        self.head_title_shadow_sfc = head_title_shadow_sfc
Пример #26
0
    def on_update(self):
        """..."""
        text = self.text

        if text is None:
            return

        if self.text_rendered != text or not self.sprites:

            render = self.font.render

            msg_sfc = render(text)
            msg_obj = msg_sfc.get_rect()
            msg_obj.center = self.center
            msg_sfc.set_rect(msg_obj)

            msg_shadow_sfc = render(text, color=get_color("gray"))
            msg_shadow_sfc.set_rect(msg_obj.move(2, 2))

            self.sprites = [msg_shadow_sfc, msg_sfc]
            self.text_rendered = text

        if self.sprites:
            self.parent.manager.spriterenderer.render(sprites=self.sprites)
Пример #27
0
 def create_fonts(self):
     """..."""
     fonts = self.fonts
     color = get_color("chartreuse")
     self.head_font = Font(font_size=26, color=color, renderer=fonts)
     self.main_font = Font(font_size=18, color=color, renderer=fonts)
Пример #28
0
class GuiTextbox(GuiButton):
    """Textbox GUI element."""

    states = ["regular", "disabled"]

    radius = 0

    regular_color = get_color("darkest_grey")
    regular_color_mod = None
    regular_alpha_mod = None

    regular_font_color = get_color("green")

    outline_color = get_color("black")
    outline_width = 2
    clear_on_execute = False  # remove text upon enter
    disable_on_execute = True
    blink_speed = 500  # prompt blink time in milliseconds
    delete_speed = 60  # backspace held clear speed in milliseconds

    def __init__(self, rect, command, **kwargs):
        """Initialization.

        Args.:
            command (method): callback to execute when enter key is pressed.
                Callback will receive 2 arguments: id and final (the string
                in the textbox).
        """
        self.buffer = array("B")
        self.blink = True
        self.blink_timer = 0.0
        self.delete_timer = 0.0

        super().__init__(rect=rect, command=command, **kwargs)

        self.create_cursor()
        self.manager.set_text_input(True, self)

    def on_text_input(self, event):
        """..."""
        if event.type == sdl2.SDL_TEXTINPUT:
            self.buffer.append(ord(event.text.text))
            self.create_text()

    def on_key_press(self, event, mod):
        """super__doc__."""
        sym = event.key.keysym.sym
        if sym == sdl2.SDLK_BACKSPACE:
            self.handle_backspace()

    def on_key_release(self, event, mod):
        """super__doc__."""
        sym = event.key.keysym.sym
        if sym == sdl2.SDLK_RETURN:
            self.execute()

    def on_mouse_motion(self, x, y, dx, dy):
        """super__doc__."""
        if self.collidepoint(x=x, y=y):
            self.disabled = False
        else:
            self.disabled = True

    def on_mouse_press(self, event, x, y, button, double):
        """super__doc__."""
        if self.collidepoint(x=x, y=y):
            self.disabled = False
        else:
            self.disabled = True

    def execute(self):
        """..."""
        if self.command:
            self.command(self, self.regular_text)
        self.active = not self.disable_on_execute
        if self.clear_on_execute:
            del self.buffer[:]

    def switch_blink(self):
        """..."""
        ticks = sdl2.SDL_GetTicks()
        if ticks - self.blink_timer > self.blink_speed:
            self.blink = not self.blink
            self.blink_timer = ticks

    def handle_backspace(self):
        """..."""
        ticks = sdl2.SDL_GetTicks()
        if ticks - self.delete_timer > self.delete_speed:
            self.delete_timer = ticks
            try:
                self.buffer.pop()
            except IndexError:
                pass
            else:
                self.create_text()

    @property
    def regular_text(self):
        """..."""
        return self.buffer.tobytes().decode("utf-8") or " "

    def create_cursor(self):
        """..."""
        self.cursor = self.fonts.render(text="|",
                                        name=self.regular_font,
                                        size=self.regular_font_size,
                                        color=self.regular_font_color)
        self.cursor.set_color_mod(self.regular_font_color_mod)

    def on_update(self):
        """super__doc__."""
        self.switch_blink()
        if self.disabled:
            state = "disabled"
        elif self.clicked:
            state = "clicked"
        elif self.hovered:
            state = "hovered"
        else:
            state = "regular"

        sprites = self.sprites[state]

        text_sprite = sprites[1]

        rect = text_sprite.get_rect()

        if self.blink:
            sprites = (*sprites, self.cursor)
            self.cursor.position = rect.topright

        self.manager.spriterenderer.render(sprites=sprites)

    def create_text(self):
        """Create the text sprites."""
        fonts = self.manager.fonts
        text_size = fonts.text_size

        text = self.regular_text
        font = self.regular_font
        color = self.regular_font_color
        size = self.regular_font_size

        # e.g. regular_text, regular_font, regular_font_size,
        # regular_font_color, regular_font_color_mod
        for state in self.states:
            start = 0
            sprite_text = getattr(self, "%s_text" % state) or text
            sprite_font = getattr(self, "%s_font" % state) or font
            sprite_size = getattr(self, "%s_font_size" % state) or size
            sprite_color = getattr(self, "%s_font_color" % state) or color
            sprite_color_mod = getattr(self, "%s_font_color_mod" % state)
            while (text_size(sprite_text[start:], sprite_font, sprite_size)[0]
                   > (self.width - 6)):
                start += 1
            sprite_text = sprite_text[start:]

            sprite = fonts.render(text=sprite_text,
                                  name=sprite_font,
                                  size=sprite_size,
                                  color=sprite_color)

            sprite.set_color_mod(sprite_color_mod)

            button_sprite = self.sprites[state][0]
            sprite.center_on(button_sprite)

            self.sprites[state] = (button_sprite, sprite)
Пример #29
0
 def __init__(self, name, **kwargs):
     """..."""
     self.combat = creatures.Beast(model=name, owner=self)
     self.color = get_color('blood_red')
     self.ai = ai.Basic(owner=self)
     super().__init__(name=self.combat.name, **kwargs)
Пример #30
0
    def take_turn(self):
        """A basic monster takes its turn."""
        # some kind of lock to prevent double calling AND queueing of
        # same objects on a single turn.

        monster = self.owner

        target = monster.scene.player
        distance = monster.distance_to(monster.scene.player)

        if not monster.visible and not monster.path:
            monster.move_rnd()
            print("AI1 (not visible not pathing): monster.move_rnd()")
        elif distance >= 2:  # implement reach here
            if monster.path:
                # continue following the path
                try:
                    old_path = list(monster.path)
                    moved = monster.move(monster.path.pop(2))
                except:
                    print("-AI2: failed to follow path")
                    moved = False
                else:
                    print("AI2: following path, dist {}".format(distance))
                    # show the path remaining
                    for i, pos in enumerate(old_path[2:-1]):

                        if i == 0:
                            color = get_color("orange")
                        elif i == 1:
                            color = get_color("yellow")
                        else:
                            color = get_color("green")
                        """
                        monster.scene.tile_fx.add(
                            coord=[pos],
                            color=color,
                            duration=1)
                        """
            else:
                moved = False

            if not moved:
                # find a new path
                monster.path = monster.move_towards(target=target)
                try:
                    """
                    monster.scene.tile_fx.add(
                        coord=monster.path[2:-1],
                        color=get_color("green"),
                        duration=1)
                    """
                    moved = monster.move(monster.path.pop(2))
                    print("AI3: new path {}, FROM {}, TO {}, DIST {}".format(
                        monster.path,
                        tuple(monster.pos),
                        tuple(monster.scene.player.pos),
                        distance))
                except:
                    monster.scene.pathing = []
                    monster.move_rnd()
                    print("AI4: path failed: monster.move_rnd()")

        # close enough, attack! (if the player is still alive.)
        elif target.combat.hit_points_current > 0:
            try:
                monster.combat.attack(target)
            except Exception as e:
                print(monster.combat.name)
                raise e