예제 #1
0
파일: bag.py 프로젝트: abjose/whimsylib
 def _discard_aliases(self, item, message=None):
     super()._discard_aliases(item)
     item.holder = None
     if self is G.player.inventory:
         message = message or f"You lose possession of {item.name}."
     if message is not None:
         say.insayne(message)
예제 #2
0
def _resolve_attack(attacker, attack):
    # TODO: Add equipment, different damage dice, etc.
    # TODO: Respect attack.method.
    defender = attack.target
    is_player = attacker is G.player
    if is_player:
        subj, obj = ["you", defender.name]
    else:
        subj, obj = [attacker.name, "you"]
    subj = say.capitalized(subj)
    miss = "miss" if is_player else "misses"
    hit = "hit" if is_player else "hits"

    strength_mod = int((attacker.strength.value - 10) / 2)
    to_hit = strength_mod + dice.roll("1d20")
    if to_hit < (10 + (defender.stamina.value - 10) / 2):
        say.insayne(f"{subj} {miss}.")

    else:
        damage = dice.roll("1d8") + strength_mod
        # TODO: How to organize messages better? Death also creates text, so
        # there should be a way to make sure the messages are ordered.
        say.insayne(f"{subj} {hit} {obj} for {damage} damage!")
        # TODO: Attack should have associated text which is consulted here.
        defender.health.heal_or_harm(
            -1 * damage, cause=f"the fins of {say.a(attacker.name)}")

    if not (is_player or defender.alive):
        G.just_died = True
예제 #3
0
def ability(ability):
    ability_name = ability
    the_ability = G.player.abilities.get(ability_name)
    if the_ability is None:
        say.insayne("You know no such ability.")
    else:
        the_ability.activate()
예제 #4
0
 def librarian_death_throes(librarian):
     say.insayne(
         "The librarian grins impossibly wide. A thin rivulet of blood "
         "appears between his teeth. His eyes roll back and, with a giggle, "
         "he falls backward onto the ground as though reclining on a divan."
     )
     say.insayne("The edge of a hidebound book peeks from his rags.")
예제 #5
0
def random_action():
    skip = [
        "?",
        "help",
        "quit",
        "random",
        "suicide",
        "north",
        "south",
        "east",
        "west",
        None,
    ]
    filtered_commands = [
        c for c in when.CommandHandler.COMMANDS if c[0].prefix not in skip
    ]

    random_command = random.choice(filtered_commands)
    command_pattern = random_command[0]

    entity_names = ([npc.name for npc in G.player.current_room.npcs] +
                    [corpse.name for corpse in G.player.current_room.corpses] +
                    [item.name for item in G.player.inventory] +
                    [item.name for item in G.player.current_room.items] +
                    list(G.player.current_room._exits))

    args = [
        random.choice(entity_names)
        for i in range(len(command_pattern.arguments))
    ]
    final_command = f"{''.join(command_pattern.prefix)} {' '.join(args)}"
    say.insayne(f"random command: {final_command}", insanity=0)

    when.handle(final_command)
예제 #6
0
def cheat(code):
    # TODO: Make healing more general.
    matches = []

    for pattern, function in [
        (_HEAL_PATTERN, _heal_stat),
        (_STAT_PATTERN, _modify_stat),
        (_ABILITY_PATTERN, _cheat_ability),
    ]:
        match = pattern.search(code)
        if match is not None:
            matches.append((function, match))
            break

    for function, match in matches:
        logging.debug("function is %s" % function)
        logging.debug("match.groups is %s" % match.groups())
        try:
            function(*match.groups())
            break
        except _CheatException:
            pass

    else:
        say.insayne("You attempt to pry open cosmic mysteries but fail. Your "
                    "pitiful mind reels with the effort.")
        G.player.insanity.heal_or_harm(15)
예제 #7
0
파일: bag.py 프로젝트: abjose/whimsylib
 def _add_aliases(self, item, message=None):
     super()._add_aliases(item)
     logging.debug("_add_aliases called with %s", item)
     item.holder = self
     if self is G.player.inventory:
         message = message or f"You acquire {item.name}."
     if message is not None:
         say.insayne(message)
예제 #8
0
 def test_no_alteration_when_insanity_low(self, mock_stdout):
     original_text = "There is no death in all the world."
     say.insayne(original_text, insanity=0)
     augmented = mock_stdout.getvalue()
     # whimsylib.say.output freely introduces newlines.
     augmented = re.sub(r"\n", r" ", augmented)
     _, edits = _sifted_edits(original_text, augmented)
     edited_edits = re.sub(r"\s*", r"", edits)
     self.assertEqual("", edited_edits)
예제 #9
0
def go(direction):
    direction = direction.lower()
    next_room, the_direction = G.player.current_room.exit(direction)
    if next_room is None:
        say.insayne(f"It is not possible to proceed {direction}.")
    else:
        say.insayne(f"You proceed {the_direction.display_description}.")
        G.player.current_room.on_exit()
        enter_room(next_room)
예제 #10
0
    def read(self, actor):
        if actor.has_read(self):
            # TODO: Condition pronoun/verb agreement on whether actor is
            # player or not. Make a utility function for this.
            say.insayne(
                "You have already tasted the wisdom distilled in this book.")

        else:
            actor.add_ability(ability.meditation())
            actor.set_has_read(self)
예제 #11
0
 def execute(self):
     # TODO: This kind of thing could be handled with a description generator.
     say.insayne(
         "You are in a dark tube. The walls and floor quiver at your touch, "
         "and you realize this is the intestine of a vast behemoth.")
     G.player.insanity.heal_or_harm(10)
     # TODO: change to self.room.description
     G.player.current_room.description = (
         "The walls and floor of the intestine room shudder at your step.")
     self._will_execute = False
예제 #12
0
 def test_sets_zalgochance_when_insanity_high(self, mock_stdout):
     # TODO: Refactor the zalgotext library to be more testable.
     original_text = "some text"
     say.insayne(original_text, insanity=100)
     augmented = mock_stdout.getvalue()
     # whimsylib.say.output freely introduces newlines.
     augmented = re.sub(r"\n", r" ", augmented)
     _, edits = _sifted_edits(original_text, augmented)
     edited_edits = re.sub(r"[A-Z]*", r"", edits)
     self.assertNotEqual("", edited_edits)
예제 #13
0
 def use_computer(consumer):
     insanity = _G.player.insanity.value
     desc = extra_description.get_interval(
         insanity, extra_description.use_computer_descriptions
     )
     say.insayne(desc)
     if insanity >= 10 and insanity < 20:
         _G.player.insanity.modify(2)
     elif insanity >= 25:
         _G.player.health.heal_or_harm(-10)
예제 #14
0
 def test_output_reconstructable(self, mock_stdout):
     original_text = (
         "When Gregor Samsa awoke one morning from unsettling dreams, "
         "he found himself changed in his bed into a monstrous vermin.")
     say.insayne(original_text, insanity=100)
     augmented = mock_stdout.getvalue()
     # whimsylib.say.output freely introduces newlines.
     augmented = re.sub(r"\n", r" ", augmented)
     reconstructed, _ = _sifted_edits(original_text, augmented)
     self.assertEqual(original_text, reconstructed)
예제 #15
0
def read(book):
    book_name = book
    _, book = _find_available_item(book_name)
    if book is None:
        say.insayne(f"There is no {book_name} here to read.")
    elif not isinstance(book, Book):
        say.insayne(
            f"You stare intently at the {book_name} but, alas, fail to read it."
        )
    else:
        book.read(G.player)
예제 #16
0
    def die(self, cause=None):
        if self is G.player:
            cause = cause or self.health.last_cause
            G.cause_of_death = cause
            say.insayne("You die.")
            say.insayne("...")
            raise tartarus.RaptureException("")

        self.alive = False
        self._death_throes(self)
        self.current_room.characters.remove(self)
        self.current_room.corpses.add(self)
예제 #17
0
def _look():
    if G.player.current_room.description:
        say.insayne(G.player.current_room.description)

    # TODO: Bespoke descriptions for all items and characters.
    for item in G.player.current_room.items:
        say.insayne(item.idle_description)
    for character in G.player.current_room.npcs:
        say.insayne(character.idle_text)
    for corpse in G.player.current_room.corpses:
        say.insayne(f"The corpse of {say.a(corpse.name)} molders here.")
    say.insayne(f'Exits are {", ".join(G.player.current_room.display_exits)}.')
예제 #18
0
def drop(item):
    item_name = item
    item = G.player.inventory.find(item_name)
    if item is None:
        say.insayne(f"You don't have {say.a(item_name)} to drop.")
    else:
        _move_item(
            G.player.inventory,
            G.player.current_room.items,
            item,
            relinquishment_message=f"You drop the {item_name} on the ground.",
        )
예제 #19
0
 def execute(self):
     self._counter += 1
     if self.room is not G.player.current_room:
         return
     if self._counter % self._TURNS_TO_CHIME == 0:
         say.insayne(
             "Suddenly, the bells begin to chime in simultaneity, if not "
             "exactly unison. From the chaos can be discerned a discordant "
             "melody. It is a blasphemous all-bells rendition of Hanson's "
             "'MMMBop.' As the final incomprehensible peal subsides, you "
             "realize the song is stuck in your head, threatening the "
             "sinews of your very sanity.")
         G.player.insanity.heal_or_harm(15)
         G.add_event(_SongInHeadEvent(), "pre")
예제 #20
0
def use(item, actor, verb):
    item_name = item
    actor_name = actor

    # Inventory item case
    item = G.player.inventory.find(item_name)
    if item:
        if actor_name:
            actor = _get_present_actor(actor_name)
            if actor:
                try:
                    item.consume(actor)
                except AttributeError:
                    say.insayne(
                        f"You can't {verb} the {item_name} on {actor_name}.")
        else:
            try:
                item.consume(G.player)
            except AttributeError:
                say.insayne(f"You can't {verb} the {item_name}.")
        return

    # NPC case
    item = G.player.current_room.npcs.find(item_name)
    if item:
        try:
            item.consume(G.player)
        except AttributeError:
            say.insayne(f"You can't {verb} the {item_name}.")
        return

    say.insayne(f"You don't have {say.a(item_name)}.")
예제 #21
0
        def execute(self):
            # TODO: Should not be G.player--what if somebody else wants a smoke?
            if _G.player.inventory.find("cigarette") or _G.player.inventory.find(
                "stub"
            ):
                say.insayne(
                    "The smoker clucks his tongue. \"You've already got a "
                    'smoke; why are you trying to bum one off me?"'
                )

            else:
                cigarette = random.choice(
                    [items.Cigarette, items.CigaretteStub]
                ).create()
                say.insayne(
                    '"Here you go," says the smoker between puffs. "Have a '
                    "smoke with me. It's all there is to do here, man. Just "
                    'that and wait to die and live again."'
                )
                _G.player.inventory.add(cigarette)
                lighter = npc.inventory.find("lighter")
                if lighter is not None:
                    say.insayne('"Here, you\'ll need this, too."')
                    npc.inventory.remove(lighter)
                    _G.player.inventory.add(lighter)
                    say.insayne('"No smoke without fire."')
예제 #22
0
 def test_interpolates_voices_when_insanity_high(self, mock_stdout):
     # TODO: Refactor the zalgotext library to be more testable.
     original_text = "no, not a text, not a text at all"
     say.insayne(original_text, insanity=100)
     augmented = mock_stdout.getvalue()
     # whimsylib.say.output freely introduces newlines.
     augmented = re.sub(r"\n", r" ", augmented)
     _, edits = _sifted_edits(original_text, augmented)
     edited_edits = re.sub(r"[^A-Z]*", r"", edits)
     with open("/tmp/output.txt", "w") as outp:
         outp.write(mock_stdout.getvalue())
     self.assertIsNotNone(
         re.search(
             r"^(HEEEHEHEHEHEHE|THEREISNOHOPE|DIDYOUHEARTHAT?"
             "|IPROMISEYOUKNOWLEDGE)+$",
             edited_edits,
         ))
예제 #23
0
파일: when.py 프로젝트: abjose/whimsylib
 def handle(cls, command):
     command = command.lower().strip()
     max_matches = -1
     call_me = None
     func_me = None
     for template, function, kwargs in cls._COMMANDS:
         match = template.match(command)
         if match is not None:
             call_kwargs = match.groupdict()
             if len(call_kwargs) > max_matches:
                 max_matches = len(call_kwargs)
             call_kwargs.update(kwargs)
             call_me = call_kwargs
             func_me = function
     if func_me is not None:
         func_me(**call_me)
     else:
         say.insayne(f'I don\'t understand "{command}."')
예제 #24
0
 def use_office_copier(consumer):
     insanity = _G.player.insanity.value
     if insanity < 20:
         say.insayne("The copier seems to be broken, as usual.")
     elif insanity < 29:
         bodyparts = ["fingers", "tongues", "arms", "lips", "nipples"]
         say.insayne(
             "The copier moans lasciviously. You feel its hot breath on your neck. It envelops you, and penetrates you."
         )
         say.insayne(
             "Abruptly, orgasmically, new "
             f"{random.choice(bodyparts)} erupt from your skin."
         )
         _G.player.insanity.modify(3)
     else:
         say.insayne("The copier sighs.")
         say.insayne(
             "You hear a meaty thumping coming from the direction of the meeting room."
         )
예제 #25
0
 def execute(self):
     say.insayne("The writhing mass speaks, many voices merging into one:")
     say.insayne(
         '"Hey champ! How are those quarterly targets coming along? Working hard or hardly working?"'
     )
     say.insayne("The writhing mass cackles.")
     say.insayne(
         "\"You should go see Gary! Now there's a team player. Maybe do him a favor! Lord knows he's done enough for you...\""
     )
     insanity = _G.player.insanity.value
     if insanity == 29:
         _G.player.insanity.modify(1)
예제 #26
0
def stats():
    lines = []
    name_str = f"{G.player.name}"
    lines.append(name_str)
    # TODO: Unfuck this for zalgo.
    lines.append("".join("-" for _ in name_str))
    for stat in G.player.all_stats():
        if hasattr(stat, "maximum"):
            lines.append(f"{stat.name:10}: {stat.value}/{stat.maximum}")
        else:
            lines.append(f"{stat.name:10}: {stat.value}")
    lines.append("".join("-" for _ in name_str))
    lines.append("- abilities -")
    for ability_name, ability in sorted(G.player.abilities.items()):
        if ability_name:
            lines.append(f"{ability_name}: {ability.DESCRIPTION}")

    for i, line in enumerate(lines):
        add_newline = i == 0
        say.insayne(line, add_newline=add_newline)
예제 #27
0
    def consume(self, consumer):
        if consumer is _G.player:
            say.insayne("You drink the coffee.")
            consumer.insanity.modify(-5)
        elif consumer.name == "gary":
            insanity = _G.player.insanity.value
            if insanity >= 30:
                # Trigger Office ending
                say.insayne(
                    "With a horrific tearing sound and a wet pop, Gary vanishes from existence. "
                    "In his place is a perfectly Gary-shaped hole in space.")
                say.insayne("YOU MADE IT!")
                # TODO: make "enter gary" action or just teleport.
                consumer.current_room.characters.remove(consumer)
            else:
                say.insayne(
                    'Gary loudly slurps the coffee. "Well thanks, pal!"')
        else:
            say.insayne("Nothing happens.")

        _G.player.inventory.remove(self)
예제 #28
0
def take(item):
    item_name = item
    location, item = _find_in_room(item_name)
    if location is None or item is None:
        if G.player.current_room.npcs.find(item_name):
            say.insayne("You cannot take sentient beings.")
        elif G.player.current_room.corpses.find(item_name):
            say.insayne("The corpse would be too burdensome to carry.")
        else:
            say.insayne(f"There is no {item_name} here to take.")
    elif not item.obtainable:
        say.insayne("You can't take the {item_name}.")
    else:
        _move_item(location, G.player.inventory, item)
예제 #29
0
    def consume(self, consumer):
        if not consumer.inventory.find("lighter"):
            if consumer is _G.player:
                say.insayne(f"You have no way to light the {self.name}.")
                return
        consumer.inventory.remove(self)
        cigarette_butt = CigaretteButt.create()
        consumer.inventory.add(cigarette_butt)
        consumer.current_room.items.add(Smoke.create(consumer.current_room))

        if consumer is _G.player:
            say.insayne(
                f"You take a furtive puff on the {self.name}. It tastes foul "
                "and acrid. You do not feel like you are wearing a leather "
                "jacket at all.")
            consumer.psyche.heal_or_harm(dice.roll("1d2"))
            # TODO: Make insanity a variable statistic?
            consumer.insanity.heal_or_harm(-dice.roll("1d2"))
            # TODO: Interesting problem with how this is implemented:
            # because text is not queued but printed directly, if this line
            # precedes anything else in this function and player dies,
            # weird stuff will ensue.
            consumer.health.heal_or_harm(-dice.roll("2d2"),
                                         cause="smoking half a cig")
        else:
            name = say.capitalized(consumer.name)
            say.insayne(f"{name} puffs furtively on a {self.name}.")
예제 #30
0
    def consume(self, consumer):
        if not consumer.inventory.find("lighter"):
            if consumer is _G.player:
                say.insayne(f"You have no way to light the {self.name}.")
                return

        # TODO: Buff strength for a little bit.
        # TODO: Heal insanity, restore psyche.
        # TODO: I don't like this solution as it presumes the item is in the
        # consumer's inventory. Maybe that is a fine assumption. If not,
        # consider storing the inventory relationship as two-way.
        consumer.inventory.remove(self)
        cigarette_stub = CigaretteStub.create()
        consumer.inventory.add(cigarette_stub)
        consumer.current_room.items.add(Smoke.create(consumer.current_room))

        # TODO: Customize text based on whether consumer is player.
        # TODO: Add location to actors so that the state of onlookers can
        # be properly assessed.
        aliases = random.sample(self.aliases, 2)
        if consumer is _G.player:
            say.insayne(
                f"You take a long, smooth drag on the {aliases[0]}. Time seems "
                "to mellow; all activity nearby slows. Onlookers watch as you "
                "draw measured, pensive little puffs from the delicious "
                f"{aliases[1]}. You look very cool.")
            consumer.health.heal_or_harm(-dice.roll("1d2"), cause="being cool")
            consumer.psyche.heal_or_harm(dice.roll("2d2"))
            # TODO: Make insanity a variable statistic?
            consumer.insanity.heal_or_harm(-dice.roll("2d2"))
        else:
            name = say.capitalized(consumer.name)
            say.insayne(
                f"{name} puffs mellowly on a {self.name}, looking extremely fly."
            )