예제 #1
0
 def hit_with(self, creature, weapon):
     if not self.is_nearby(creature):
         r = ProximityFailure(creature.full_name())
     elif not self.in_inventory(weapon):
         r = OwnershipFailure(weapon.full_name())
     else:
         if not creature.traits.hostile:
             creature.become_hostile()
         attack_difficulty = random.randint(0, 100)
         if weapon.accuracy < attack_difficulty:
             r = Failure("Your attack misses!")
         else:
             creature.health -= weapon.damage
             if creature.is_alive():
                 r = Success(
                     "You hit the {}. It reels from your attack!".format(
                         creature.full_name()))
             else:
                 r = Success((
                     "You deal the {} a fatal blow. It falls to the ground dead, "
                     +
                     "and its body dissolves into the hungry earth").format(
                         creature.full_name()))
                 for item_id in creature.inventory.items:
                     item = self.game.vocabulary.lookup_noun(item_id)
                     creature.inventory.remove_item(item)
                     self.location.add_item(item)
                 self.location.remove_item(creature, force=True)
                 creature.location = None
     return r
예제 #2
0
 def get(self, item):
     if not item.traits.portable:
         r = Failure("You can't carry around the {}!".format(
             item.full_name()))
     elif self.in_inventory(item):
         r = Failure("You already have the {}!".format(item.full_name()))
     elif not self.is_nearby(item):
         container = self.nearby_container_having(item)
         creature = self.nearby_creature_having(item)
         if container:
             r = self.get_from(item, container)
         elif creature:
             r = self.ask_for(creature, item)
         else:
             r = ProximityFailure(item.full_name())
     else:
         r1 = self.location.remove_item(item)
         if r1.success:
             r2 = self.inventory.add_item(item)
             if r2.success:
                 r = Success("You take the " + item.full_name())
             else:
                 self.location.add_item(item)
                 r = Failure(
                     "Your load is too heavy to pick up the {}".format(
                         item.full_name()))
     return r
예제 #3
0
 def put_in(self, item, container):
     if not self.is_nearby(container):
         r = ProximityFailure(container.full_name())
     else:
         if not self.is_nearby(item):
             r = ProximityFailure(item.full_name())
         else:
             if container == item:
                 r = Failure("You can't put the {} {} itself!".format(
                     container.full_name(), container.put_preposition))
             else:
                 if self.in_inventory(item):
                     source = self.inventory
                 else:
                     source = self.location
                 r1 = source.remove_item(item)
                 if r1.success:
                     r2 = container.add_item(item)
                     if r2.success:
                         r = Success("The {} {} now {} the {}".format(
                             item.full_name(),
                             item.existential(), container.put_preposition,
                             container.full_name()))
                     else:
                         source.add_item(item)
                         r = r2
                 else:
                     r = r1
     return r
예제 #4
0
 def history(self):
     r = Success("Recent command history: \n")
     if len(self.command_history) > 0:
         for c in self.command_history:
             r.append("\n|" + self.prompt + c.input_text)
     else:
         r.append("(no commands yet entered)")
     r.append("\n")
     return r
예제 #5
0
 def close(self, closeable):
     if self.is_nearby(closeable):
         if closeable.traits.closed:
             r = Failure("The {} is already closed".format(
                 closeable.full_name()))
         else:
             closeable.traits.closed = True
             r = Success("You close the {}".format(closeable.full_name()))
     else:
         r = ProximityFailure(closeable.full_name())
     return r
예제 #6
0
 def drop(self, item):
     r1 = self.inventory.remove_item(item)
     if r1.success:
         r2 = self.location.add_item(item)
         if r2.success:
             r = Success("You drop the " + item.full_name())
         else:
             r = Failure("You can't drop the " + item.full_name() + "here!")
     else:
         r = OwnershipFailure(item.full_name())
     return r
예제 #7
0
 def go(self, game, creature):
     if self.condition(game, creature):
         location = self.vocab.lookup_noun(self.location)
         destination = self.vocab.lookup_noun(self.destination)
         game.move_creature(creature, location, destination)
         r = Success("Creature moved from {} to {}".format(location.name, destination.name))
         if self.after:
             r = self.after(game, creature, location, destination)
     else:
         r = self.fail_result
     return r
예제 #8
0
 def consume(self, edible, adjective, verb):
     if not self.is_nearby(edible):
         r = ProximityFailure(edible.full_name())
     else:
         self.health += edible.healing
         if self.in_inventory(edible):
             edible.consume_from(self.inventory)
         else:
             edible.consume_from(self.location)
         r = Success("You {} the {} {}".format(verb, adjective,
                                               edible.full_name()))
     return r
예제 #9
0
 def remove_item(self, item, force=False):
     if not force and self.traits.closed:
         result = Failure("The " + self.full_name() + " is closed")
     else:
         if item.id in self.items:
             self.items.remove(item.id)
             result = Success("You remove the " + item.name + " from the " +
                              self.full_name())
         else:
             result = Failure("The {} {}n't {} the {}!".format(
                 item.full_name(), item.existential(), self.put_preposition,
                 self.full_name()))
     return result
예제 #10
0
 def list_inventory(self):
     if len(self.inventory.items) > 0:
         r = Success("You are carrying:")
         for item_id in self.inventory.items:
             item = self.vocab.lookup_noun(item_id)
             r.append("\n\t" + item.description)
     else:
         r = Success("You're not carrying anything")
     return r
예제 #11
0
 def open(self, openable):
     if self.is_nearby(openable):
         if openable.traits.closed:
             if openable.traits.locked:
                 r = Failure(
                     "You try to open the {}, but it is firmly locked".
                     format(openable.full_name()))
             else:
                 openable.traits.closed = False
                 if isinstance(openable, Container):
                     container = openable
                     item_count = container.item_count()
                     if item_count == 0:
                         r = Success(
                             "You open the {}, which is empty".format(
                                 container.full_name()))
                     elif item_count == 1:
                         r = Success("Opening the {} reveals a {}".format(
                             container.full_name(),
                             self.vocab.lookup_noun(
                                 container.items[0]).full_name()))
                     else:
                         r = Success("Opening the {} reveals: ".format(
                             container.full_name()))
                         for item_id in container.items:
                             item = self.vocab.lookup_noun(item_id)
                             r.append("\n\t" + item.description)
                 else:
                     r = Success("You open the {}".format(
                         openable.full_name()))
         else:
             r = Failure("The {} is already open".format(
                 openable.full_name()))
     else:
         r = ProximityFailure(openable.full_name())
     return r
예제 #12
0
 def lock_with(self, lockable, key):
     if self.is_nearby(lockable):
         if lockable.traits.locked:
             r = Failure("The {} is already locked".format(
                 lockable.full_name()))
         else:
             if key.can_lock(lockable):
                 lockable.traits.locked = True
                 r = Success("The {} is now locked".format(
                     lockable.full_name()))
             else:
                 r = Failure("The {} cannot be locked with the {}!".format(
                     lockable.full_name(), key.full_name()))
     else:
         r = ProximityFailure(lockable.full_name())
     return r
예제 #13
0
 def add_item(self, item, force=False):
     if not force and self.traits.closed:
         result = Failure("The " + self.full_name() + " is closed")
     else:
         if item.id in self.items:
             result = Failure("The {} {} already {} the {}".format(
                 item.full_name(), item.existential(), self.put_preposition,
                 self.full_name()))
         elif item.size > self.remaining_capacity():
             result = Failure("Sorry, the {} won't fit {} the {}".format(
                 item.full_name(), self.put_preposition, self.full_name()))
         else:
             self.items.append(item.id)
             result = Success("Okay, the {} {} now {} the {}".format(
                 item.full_name(), item.existential(), self.put_preposition,
                 self.full_name()))
     return result
예제 #14
0
 def unlock_with(self, lockable, key):
     if self.is_nearby(lockable) or self.nearby_container_having(lockable):
         if not lockable.traits.locked:
             r = Failure("The {} is already unlocked".format(
                 lockable.full_name()))
         else:
             if key.can_lock(lockable):
                 lockable.traits.locked = False
                 r = Success("The {} is now unlocked".format(
                     lockable.full_name()))
             else:
                 r = Failure(
                     "The {} cannot be unlocked with the {}!".format(
                         lockable.full_name(), key.full_name()))
     else:
         r = ProximityFailure(lockable.full_name())
     return r
예제 #15
0
 def is_valid_schema(self, schema):
     r = None
     missing_roles = set()
     for role in Role.values:
         if role in self.unassigned_roles and schema.get_role(role):
             r = NotUnderstoodFailure()
             break
         elif role in self.required_roles:
             if schema.get_role(role) is None:
                 missing_roles.add(role)
             else:
                 role_value = schema.get_role(role)
                 if not (role in self.permissive_roles
                         or role_value.is_valid_for_role(role, self)):
                     r = Failure(self.role_messages[role].format(
                         role_value.full_name()))
                     break
     if r is None:
         # TODO: Add heuristic to guess identity of missing words, if possible
         if len(missing_roles) > 0:
             preposition = None
             for k, v in self.preposition_roles.items():
                 if v in missing_roles:
                     preposition = k
             if Role.PATIENT in missing_roles:
                 if preposition:
                     r = Failure("What do you want to {} {}?".format(
                         self.name, preposition))
                 else:
                     r = Failure("What do you want to {}?".format(
                         self.name))
             elif Role.THEME in missing_roles or Role.INSTRUMENT in missing_roles:
                 if preposition:
                     r = Failure("What do you want to {} the {} {}?".format(
                         self.name, schema[Role.PATIENT].full_name(),
                         preposition))
                 else:
                     r = Failure("What do you want to {} the {}?".format(
                         self.name, schema[Role.PATIENT].full_name()))
             else:
                 r = NotUnderstoodFailure()
         else:
             r = Success("Success")
     return r
예제 #16
0
 def get_from(self, item, container):
     if isinstance(container, Creature):
         r = self.ask_for(container, item)
     else:
         if not self.is_nearby(container):
             r = ProximityFailure(container.full_name())
         else:
             r1 = container.remove_item(item)
             if r1.success:
                 r2 = self.inventory.add_item(item)
                 if r2.success:
                     r = Success("You take the {} from the {}".format(
                         item.full_name(), container.full_name()))
                 else:
                     container.add_item(item)
                     r = r2
             else:
                 r = r1
     return r
예제 #17
0
 def give_to(self, item, creature):
     if not self.is_nearby(creature):
         r = ProximityFailure(creature.full_name())
     elif not self.in_inventory(item):
         r = OwnershipFailure(item.full_name())
     elif item in creature.wanted_items:
         r1 = self.inventory.remove_item(item)
         if r1.success:
             r2 = creature.inventory.add_item(item)
             if r2.success:
                 creature.become_friendly()
                 r = Success("The {} gratefully accepts the {}".format(
                     creature.full_name(), item.full_name()))
             else:
                 self.inventory.add_item(item)
                 r = r2
         else:
             r = r1
     else:
         r = Failure("The {} politely declines to take the {}".format(
             creature.full_name(), item.full_name()))
     return r
예제 #18
0
 def create(cls,
            game,
            name,
            callback=lambda schema: Success("Done"),
            preposition_roles=None,
            direct_object_role=None,
            indirect_object_role=None,
            required_roles=None,
            permissive_roles=None,
            aliases=None,
            role_scopes=None,
            role_messages=None):
     if not preposition_roles:
         preposition_roles = {}
     if not required_roles:
         required_roles = {Role.AGENT}
     if not permissive_roles:
         permissive_roles = {}
     a = Action(game, name, callback, preposition_roles, direct_object_role,
                indirect_object_role, required_roles, permissive_roles,
                aliases, role_scopes, role_messages)
     game.vocabulary.register_verb(a)
     return a
예제 #19
0
 def ask_for(self, creature, item):
     if not self.is_nearby(creature):
         r = ProximityFailure(creature.full_name())
     elif not creature.in_inventory(item):
         r = Failure("The {} doesn't have the {}".format(
             creature.full_name(), item.full_name()))
     elif not creature.traits.friendly or item in creature.wanted_items:
         r = Failure("The {} is unwilling to part with the {}".format(
             creature.full_name(), item.full_name()))
     else:
         r1 = creature.inventory.remove_item(item)
         if r1.success:
             r2 = self.inventory.add_item(item)
             if r2.success:
                 r = Success(
                     "The {} gladly hands over the {} to you".format(
                         creature.full_name(), item.full_name()))
             else:
                 creature.inventory.add_item(item)
                 r = r2
         else:
             r = r1
     return r
예제 #20
0
 def help(self):
     r = Success("Available commands are: \n")
     r.append(', '.join(self.vocabulary.get_valid_verbs()))
     return r
예제 #21
0
 def describe(self):
     return Success(self.description)
예제 #22
0
    def setup_actions(self, game):

        Action.create(
            game,
            name='history',
            callback=lambda schema: schema[Role.AGENT].game.history())
        Action.create(game,
                      name='help',
                      callback=lambda schema: schema[Role.AGENT].game.help())
        Action.create(game,
                      name='status',
                      aliases=['score'],
                      callback=lambda schema: schema[Role.AGENT].game.status())
        Action.create(game,
                      name='exit',
                      aliases=['quit', 'end', 'done'],
                      callback=lambda schema: game.exit_game())
        Action.create(game,
                      name='diagnose',
                      callback=lambda schema: schema[Role.AGENT].diagnose())
        Action.create(game,
                      name='wait',
                      callback=lambda schema: Success("Time passes..."))
        Action.create(
            game,
            name='inventory',
            aliases=['i'],
            callback=lambda schema: schema[Role.AGENT].list_inventory())
        Action.create(game,
                      name='look',
                      aliases=['l'],
                      direct_object_role=Role.THEME,
                      preposition_roles={
                          'at': Role.THEME,
                          'in': Role.THEME,
                          'on': Role.THEME
                      },
                      callback=lambda schema: schema[Role.AGENT].look(schema[
                          Role.THEME]))

        def process_get(schema):
            if schema[Role.PATIENT]:
                r = schema[Role.AGENT].get_from(schema[Role.THEME],
                                                schema[Role.PATIENT])
            else:
                theme = schema[Role.THEME]
                if isinstance(theme, Creature) and not theme.traits.portable:
                    r = Failure(
                        "You are unable to subdue and capture the {}!".format(
                            theme.full_name()))
                elif not theme.traits.portable:
                    r = Failure(
                        "The {} is solidly anchored and cannot be removed".
                        format(theme.full_name()))
                else:
                    r = schema[Role.AGENT].get(schema[Role.THEME])
            return r

        Action.create(
            game,
            name='get',
            aliases=['take'],
            required_roles={Role.AGENT},
            direct_object_role=Role.THEME,
            preposition_roles={'from': Role.PATIENT},
            role_scopes={
                Role.THEME: Scope.EXTERNAL,
                Role.PATIENT: Scope.EXTERNAL
            },
            role_messages={
                Role.THEME:
                "Admire the {} all you want, you can't take it with you."
            },
            callback=process_get)

        Action.create(game,
                      name='drop',
                      aliases=['leave'],
                      direct_object_role=Role.THEME,
                      required_roles={Role.AGENT, Role.THEME},
                      role_scopes={Role.THEME: Scope.INVENTORY},
                      callback=lambda schema: schema[Role.AGENT].drop(schema[
                          Role.THEME]))

        Action.create(
            game,
            name='go',
            aliases=['walk'],
            required_roles={Role.AGENT, Role.GOAL},
            direct_object_role=Role.GOAL,
            role_messages={Role.GOAL: "That's not a direction!"},
            callback=lambda schema: schema[Role.AGENT].go(schema[Role.GOAL]))

        Action.create(game,
                      name='open',
                      required_roles={Role.AGENT, Role.PATIENT},
                      direct_object_role=Role.PATIENT,
                      callback=lambda schema: schema[Role.AGENT].open(schema[
                          Role.PATIENT]))

        Action.create(game,
                      name='close',
                      required_roles={Role.AGENT, Role.PATIENT},
                      direct_object_role=Role.PATIENT,
                      callback=lambda schema: schema[Role.AGENT].close(schema[
                          Role.PATIENT]))

        Action.create(
            game,
            name='lock',
            required_roles={Role.AGENT, Role.PATIENT, Role.INSTRUMENT},
            direct_object_role=Role.PATIENT,
            preposition_roles={'with': Role.INSTRUMENT},
            callback=lambda schema: schema[Role.AGENT].lock_with(
                schema[Role.PATIENT], schema[Role.INSTRUMENT]))

        Action.create(
            game,
            name='unlock',
            required_roles={Role.AGENT, Role.PATIENT, Role.INSTRUMENT},
            direct_object_role=Role.PATIENT,
            preposition_roles={'with': Role.INSTRUMENT},
            callback=lambda schema: schema[Role.AGENT].unlock_with(
                schema[Role.PATIENT], schema[Role.INSTRUMENT]))
        Action.create(game,
                      name='put',
                      required_roles={Role.AGENT, Role.PATIENT, Role.THEME},
                      direct_object_role=Role.THEME,
                      preposition_roles={
                          'in': Role.PATIENT,
                          'into': Role.PATIENT,
                          'on': Role.PATIENT
                      },
                      callback=lambda schema: schema[Role.AGENT].put_in(
                          schema[Role.THEME], schema[Role.PATIENT]))

        Action.create(
            game,
            name='eat',
            required_roles={Role.AGENT, Role.THEME},
            direct_object_role=Role.THEME,
            role_messages={
                Role.THEME: "I don't think the {} would agree with you."
            },
            callback=lambda schema: schema[Role.AGENT].eat(schema[Role.THEME]))

        Action.create(game,
                      name='drink',
                      required_roles={Role.AGENT, Role.THEME},
                      direct_object_role=Role.THEME,
                      role_messages={
                          Role.THEME:
                          "I don't think the {} would agree with you."
                      },
                      callback=lambda schema: schema[Role.AGENT].drink(schema[
                          Role.THEME]))

        Action.create(game,
                      name='greet',
                      required_roles={Role.AGENT, Role.PATIENT},
                      direct_object_role=Role.PATIENT,
                      callback=lambda schema: schema[Role.AGENT].greet(schema[
                          Role.PATIENT]))

        Action.create(game,
                      name='smile',
                      required_roles={Role.AGENT, Role.PATIENT},
                      preposition_roles={'at': Role.PATIENT},
                      callback=lambda schema: schema[Role.AGENT].greet(schema[
                          Role.PATIENT]))

        Action.create(game,
                      name='wave',
                      required_roles={Role.AGENT, Role.PATIENT},
                      preposition_roles={
                          'at': Role.PATIENT,
                          'to': Role.PATIENT
                      },
                      callback=lambda schema: schema[Role.AGENT].greet(schema[
                          Role.PATIENT]))

        Action.create(game,
                      name='give',
                      aliases=['offer'],
                      required_roles={Role.AGENT, Role.PATIENT, Role.THEME},
                      direct_object_role=Role.THEME,
                      indirect_object_role=Role.PATIENT,
                      preposition_roles={'to': Role.PATIENT},
                      callback=lambda schema: schema[Role.AGENT].give_to(
                          schema[Role.THEME], schema[Role.PATIENT]))

        Action.create(game,
                      name='ask',
                      required_roles={Role.AGENT, Role.PATIENT, Role.THEME},
                      direct_object_role=Role.PATIENT,
                      preposition_roles={'for': Role.THEME},
                      callback=lambda schema: schema[Role.AGENT].ask_for(
                          schema[Role.PATIENT], schema[Role.THEME]))

        Action.create(
            game,
            name='kill',
            aliases=['attack', 'fight', 'hit'],
            required_roles={Role.AGENT, Role.PATIENT, Role.INSTRUMENT},
            direct_object_role=Role.PATIENT,
            preposition_roles={'with': Role.INSTRUMENT},
            role_messages={
                Role.INSTRUMENT:
                "The {} proves an ineffective choice of weapon"
            },
            callback=lambda schema: schema[Role.AGENT].hit_with(
                schema[Role.PATIENT], schema[Role.INSTRUMENT]))

        def process_throw(schema):
            if schema[Role.GOAL]:
                r = schema[Role.AGENT].throw(schema[Role.THEME],
                                             schema[Role.GOAL])
            else:
                r = schema[Role.AGENT].throw(schema[Role.THEME])
            return r

        Action.create(
            game,
            name='throw',
            aliases=['toss', 'pitch', 'fling', 'lob'],
            required_roles={Role.AGENT, Role.THEME},
            direct_object_role=Role.THEME,
            role_scopes={
                Role.THEME: Scope.INVENTORY,
                Role.PATIENT: Scope.EXTERNAL
            },
            preposition_roles={
                'at': Role.GOAL,
                'to': Role.GOAL
            },
            role_messages={
                Role.THEME:
                "The {} is too unwieldy to make an effective missile",
                Role.GOAL: "The {} is not intended for target practice!"
            },
            callback=lambda schema: process_throw(schema))

        Action.create(
            game,
            name='smell',
            required_roles={Role.AGENT, Role.THEME},
            direct_object_role=Role.THEME,
            permissive_roles={Role.THEME},
            callback=lambda schema: Success("Smells like {} {} to me!".format(
                schema[Role.THEME].article(), schema[Role.THEME].full_name())))

        Action.create(game,
                      name='listen',
                      required_roles={Role.AGENT, Role.THEME},
                      permissive_roles={Role.THEME},
                      preposition_roles={'to': Role.THEME},
                      callback=lambda schema: Success(
                          "The {} is keeping pretty quiet right now".format(
                              schema[Role.THEME].full_name())))

        Action.create(game,
                      name='admire',
                      aliases=['appreciate'],
                      direct_object_role=Role.THEME,
                      required_roles={Role.AGENT, Role.THEME},
                      permissive_roles={Role.THEME},
                      callback=lambda schema: Success(
                          "Breathtaking! You feel enriched by this profound "
                          "artistic experience."))

        jump_result = Success("You take a great leap into the air")
        jump_result.add_message("Wheeeeeee!")
        jump_result.add_message("Boing boing boing ...")
        jump_result.add_message("Up, up and away!")

        def process_jump(schema):
            return jump_result

        Action.create(game,
                      name='jump',
                      required_roles={Role.AGENT},
                      callback=process_jump)
예제 #23
0
 def diagnose(self):
     return Success("Health: {}; strength: {}".format(
         self.health, self.strength))
예제 #24
0
 def status(self):
     r = Success("You have a score of {} after {} turns".format(
         self.score, self.turns))
     return r
예제 #25
0
    def setup_items(self, game):

        # --------------- Common effects of commands

        def update_score(game, points):
            game.score += points

        def update_health(player, points):
            player.health += points

        def make_creature_hostile(creature):
            creature.become_hostile()

        def instant_death(player):
            player.health = 0

        def lose_item(player, item):
            player.inventory.remove_item(item)

        def end_section(name, game, player, points):
            update_score(game, points)
            result = Result(
                "Congratulations! You have finished {}. ".format(name))
            status = game.status()
            result.append(status.get_message())
            return result

        # ---------------- Create basic locations and objects

        player = game.player

        crumbly_room = Location(
            game,
            name='Crumbly Room',
            description='A small storage room with crumbling plaster walls')
        paneled_room = Location(
            game,
            name='Wood Paneled Room',
            description='A large, warm room with wood-paneled walls')
        north_tower = Location(
            game,
            name='North Tower',
            description='A tower with a high ceiling and red-stained windows')
        balcony = Location(
            game,
            name='Balcony',
            description=
            'A breezy, open balcony with a beautiful view of the landscape below',
            traits=Traits(precarious=True))
        east_tower = Location(
            game,
            name='East Tower',
            description='The tall tower at the eastern side of the house')
        roof = Location(
            game,
            name='Roof',
            description='You are on the roof of the eastern tower.  ' +
            'There is a ladder leading back downwards, and to the west is an open window.',
            traits=Traits(precarious=True))

        west_tower = Location(
            game,
            name='West Tower',
            description='The tall tower at the western side of the house.')

        master_bedroom = Location(
            game,
            'Master Bedroom',
            description=
            'This appears to be a former bedroom, but the bed itself is missing.  '
            + 'A window to the east is open.')
        basement = Location(game,
                            'Basement',
                            description='An empty room, very drafty')
        garden = Location(game, 'garden', description='a lush blooming garden')
        patio = Location(game, 'patio', description='an empty stone patio')
        front_porch = Location(
            game,
            'porch',
            description=
            'The front porch of the house.  A metal gate prevents you from leaving'
        )
        front_porch.add_modifier('front')

        metal_gate = Surface(
            game,
            name='gate',
            description=
            'An impassable metal gate with two locks: one golden and one bronze, '
            + 'blocking your exit!')
        metal_gate.traits.closed = True
        metal_gate.add_modifier('metal')
        front_porch.add_item(metal_gate)

        golden_lock = Door(game, name='lock', description='a golden lock')
        golden_lock.add_modifier('golden')
        metal_gate.add_item(golden_lock, force=True)

        bronze_lock = Door(game, name='lock', description='a bronze lock')
        bronze_lock.add_modifier('bronze')
        metal_gate.add_item(bronze_lock, force=True)

        street = Location(game, 'street', description='an empty street')

        fancy_painting = Item(
            game,
            name='painting',
            description='An ornate painting of the house\'s previous owner',
            aliases=['portrait', 'picture'],
            size=15,
            value=100)
        fancy_painting.add_modifier('fancy')
        west_tower.add_item(fancy_painting)

        east_tower.add_exit(direction.west, paneled_room)
        crumbly_room.add_exit(direction.north, paneled_room)
        paneled_room.add_exit(direction.south, crumbly_room)
        paneled_room.add_exit(direction.north, north_tower)
        paneled_room.add_exit(direction.east, east_tower)
        paneled_room.add_exit(direction.west, west_tower)
        west_tower.add_exit(direction.east, paneled_room)
        roof.add_exit(direction.west, master_bedroom)
        master_bedroom.add_exit(direction.down, basement)
        master_bedroom.add_exit(direction.east, roof)
        basement.add_exit(direction.up, master_bedroom)
        basement.add_exit(direction.west, garden)
        garden.add_exit(direction.east, basement)
        garden.add_exit(direction.south, patio)
        patio.add_exit(direction.north, garden)
        patio.add_exit(direction.south, front_porch)

        front_porch.add_exit(direction.north, patio)
        front_porch.add_exit(
            direction.south,
            street,
            condition=lambda g, p: not metal_gate.traits.closed,
            after=lambda g, p, l, d: end_section("section one", g, p, 50),
            fail_result=Failure("The metal gate blocks your way"))

        def too_small_check(g, p):
            return p.inventory.used_capacity() <= 25

        too_small_result = Failure(
            "Your load is too large to fit through the small hole")

        east_tower.add_exit(
            direction.up,
            roof,
            description='A ladder leads up to a hole in the ceiling far above',
            condition=too_small_check,
            fail_result=too_small_result)
        roof.add_exit(
            direction.down,
            east_tower,
            description="There is a hole here leading down to the tower below",
            condition=too_small_check,
            fail_result=too_small_result)

        sturdy_door = Door(
            game,
            name='door',
            description=
            'A sturdy door leading out to the balcony above the tower')
        sturdy_door.add_modifier('sturdy')

        silver_key = Key(game,
                         name='key',
                         description='A brilliant silver key')
        silver_key.add_modifier('silver')

        steel_key = Key(game, name='key', description='A small steel key')
        steel_key.add_modifier('steel')
        steel_key.set_lockable(sturdy_door)
        roof.add_item(steel_key)

        north_tower.add_item(sturdy_door)
        north_tower.add_exit(direction.south, paneled_room)
        north_tower.add_exit(
            direction.up,
            balcony,
            description="Stairs lead up to a door high above",
            condition=lambda g, p: not sturdy_door.traits.closed,
            fail_result=Failure("A sturdy door blocks the way"))
        balcony.add_exit(direction.down, north_tower)

        light_thing = Item(
            game,
            name='thing',
            description='An easily carried thing, light as a feather',
            size=0)
        light_thing.add_modifier('light')

        fragile_thing = Item(game,
                             name='thing',
                             description='An easily breakable, delicate thing',
                             traits=Traits(fragile=True),
                             size=15)
        fragile_thing.add_modifier('fragile')

        heavy_thing = Item(
            game,
            name='thing',
            description='A heavy block of some unknown material',
            size=45)
        heavy_thing.add_modifier('heavy')

        trunk = Container(game,
                          name='trunk',
                          description='An old wooden trunk',
                          aliases=['chest', 'box'],
                          size=75,
                          value=5,
                          capacity=90)
        trunk.add_modifier('wooden')
        sword = Weapon(game,
                       name='sword',
                       description='A serviceable iron sword',
                       size=15,
                       value=15,
                       damage=50,
                       defense=10,
                       accuracy=80)
        sword.add_modifier('iron')
        trunk.add_item(sword, force=True)

        diamond = Item(game,
                       name='diamond',
                       aliases=['gem', 'jewel'],
                       size=5,
                       value=100,
                       description='A brilliant diamond')

        apple = Edible(game,
                       name='apple',
                       description='A delicious, juicy red apple',
                       size=15,
                       value=5)
        small_table = Surface(game,
                              name='table',
                              description='A small table',
                              size=20,
                              capacity=15)
        small_table.add_modifier('small')
        small_table.add_item(apple, force=True)

        large_table = Surface(game,
                              name='table',
                              description='A large table',
                              size=75,
                              capacity=100)
        large_table.add_modifier('large')
        large_table.add_item(heavy_thing, force=True)
        large_table.add_item(light_thing, force=True)
        large_table.add_item(fragile_thing, force=True)

        bread = Edible(game,
                       name='bread',
                       description='A loaf of crusty brown bread',
                       size=20,
                       value=5,
                       healing=10)

        puddle = Drinkable(game,
                           name='puddle',
                           aliases=['water'],
                           description='A puddle of refreshing water',
                           size=25,
                           value=5,
                           healing=15)

        mouse = Item(
            game,
            name='mouse',
            description='A small mouse scampers back and forth across the ' +
            'room here, searching for food.  It is carrying something '
            'shiny in its mouth.',
            traits=Traits(compelling=True),
            size=0,
            value=0)
        mouse.add_modifier('brown')
        west_tower.add_item(mouse)

        core = Item(game,
                    name='core',
                    description='The core of an eaten apple',
                    size=5,
                    value=0)
        core.add_modifier('apple')
        apple.add_consumed(core)

        crumbs = Edible(game,
                        name='crumbs',
                        description='A small pile of leftover bread crumbs',
                        aliases=['pile'],
                        traits=Traits(composite=True, plural=True),
                        size=5,
                        value=0,
                        healing=0)
        bread.add_consumed(crumbs)

        mud = Item(game,
                   name='mud',
                   description='A clump of soggy wet mud',
                   traits=Traits(composite=True),
                   size=15,
                   value=1)
        puddle.add_consumed(mud)
        vase = Container(game,
                         name='flowerpot',
                         description='a patterned flowerpot',
                         aliases=['flowerpot', 'pot', 'vase'],
                         traits=Traits(closed=False, fragile=True),
                         size=5,
                         value=10,
                         capacity=3)
        flower = Item(game,
                      name='flower',
                      description='a beautiful, fragrant sunflower',
                      size=3,
                      value=5)
        crumbly_room.add_item(small_table)
        crumbly_room.add_item(large_table)
        paneled_room.add_item(trunk)
        paneled_room.add_item(puddle)

        vase.add_item(flower)
        balcony.add_item(vase)

        villager = Creature(
            game,
            name='villager',
            traits=Traits(mobile=True),
            aliases=['farmer'],
            description="A stout but simple villager in farming garb",
            health=75,
            strength=25,
            dexterity=65,
            location=paneled_room)
        villager.add_wanted_item(apple)
        villager.add_item(diamond)

        golden_key = Key(game,
                         name='key',
                         description='A fashionable golden key')
        golden_key.add_modifier('golden')
        golden_key.set_lockable(golden_lock)

        red_fox = Creature(game,
                           name='fox',
                           traits=Traits(hostile=True, mobile=False),
                           description="a bloodthirsty red fox",
                           health=65,
                           strength=15,
                           dexterity=50,
                           location=front_porch)
        red_fox.add_modifier('red')
        red_fox.add_item(golden_key)

        bronze_key = Key(game, name='key', description='A dull bronze key')
        bronze_key.add_modifier('bronze')
        bronze_key.set_lockable(bronze_lock)

        brown_fox = Creature(game,
                             name='fox',
                             traits=Traits(hostile=True, mobile=False),
                             description="a vicious brown fox",
                             health=65,
                             strength=25,
                             dexterity=50,
                             location=front_porch)
        brown_fox.add_modifier('brown')
        red_fox.add_item(bronze_key)

        townsfolk = Creature(
            game,
            name='townsfolk',
            traits=Traits(mobile=True),
            description='A short, well-dressed man with a stubbly beard',
            aliases=['folk', 'man'],
            health=75,
            strength=30,
            dexterity=65,
            location=north_tower)
        townsfolk.add_wanted_item(diamond)
        townsfolk.add_item(bread)

        def shadow_action(game, player):
            player.health -= 5
            return Result("A dark shadow looms ominously in the corner")

        shadow = Creature(
            game,
            name='shadow',
            traits=Traits(hostile=False, mobile=True, evident=False),
            description=
            'You attempt to examine the shadow, but your vision blurs as you try to focus '
            'on its constantly shifting shape, preventing you from forming '
            'any clear impression',
            health=9001,
            strength=20,
            dexterity=90,
            location=east_tower)
        shadow.add_modifier('dark')
        shadow.entry_action = lambda g, p: Result(
            "A dark shadow enters.  The temperature in the room drops "
            "several degrees, as does your blood")
        shadow.exit_action = lambda g, p: Result(
            "The shadow leaves the room, and you once again find "
            "you can breathe freely")
        shadow.present_action = shadow_action

        # -------- Consequences: game milestones and achievements, and special results
        vocabulary = game.vocabulary

        open = vocabulary.lookup_verb_by_name('open')
        get = vocabulary.lookup_verb_by_name('get')
        ask = vocabulary.lookup_verb_by_name('ask')
        smell = vocabulary.lookup_verb_by_name('smell')
        jump = vocabulary.lookup_verb_by_name('jump')
        drop = vocabulary.lookup_verb_by_name('drop')
        throw = vocabulary.lookup_verb_by_name('throw')
        kill = vocabulary.lookup_verb_by_name('kill')
        unlock = vocabulary.lookup_verb_by_name('unlock')

        # Trying to pick up creatures turns them hostile
        for creature in vocabulary.get_objects_of_class(Creature):
            get.add_consequence(schema=Schema(roles={
                Role.AGENT: player,
                Role.THEME: creature
            }),
                                necessary_result=result.GENERIC_FAILURE,
                                effect=lambda schema: make_creature_hostile(
                                    schema[Role.THEME]))

        # Be careful in precarious places!
        for room in vocabulary.get_objects_of_class(Location):
            if room.traits.precarious:
                jump.add_consequence(
                    schema=Schema(roles={Role.AGENT: player}),
                    necessary_result=result.GENERIC_SUCCESS,
                    necessary_location=room,
                    effect=lambda schema: instant_death(player),
                    consequent_result=Success(
                        "In your excitement, you slip and fall to the hard ground far below!\n"
                        +
                        "You should probably be more careful where you do your jumping."
                    ))

                # TODO: Some kind of pattern-matching logic here.  This configures for _no_ theme, not _any_ theme ...
                throw.add_consequence(
                    schema=Schema(roles={Role.AGENT: player}),
                    necessary_result=result.GENERIC_FAILURE,
                    necessary_location=room,
                    effect=lambda schema: lose_item(player, schema[Role.THEME]
                                                    ),
                    consequent_result=Failure(
                        "You toss it carelessly, and it sails over the edge and out of sight"
                    ))

        # The mouse is too fast to catch or kill, but it's hungry
        def fed_mouse(crumbs):
            west_tower.remove_item(mouse)
            west_tower.remove_item(crumbs)
            west_tower.add_item(silver_key)

        get.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.THEME: mouse
            }),
            necessary_result=result.GENERIC_SUCCESS,
            necessary_location=west_tower,
            effect=lambda schema: player.drop(mouse),
            consequent_result=Failure(
                "You try, but the mouse is far too small and fast for you to catch!"
            ))

        drop.add_consequence(schema=Schema(roles={
            Role.AGENT: player,
            Role.THEME: crumbs
        }),
                             necessary_result=result.GENERIC_SUCCESS,
                             necessary_location=west_tower,
                             effect=lambda schema: update_score(game, 20))

        drop.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.THEME: crumbs
            }),
            necessary_result=result.GENERIC_SUCCESS,
            necessary_location=west_tower,
            effect=lambda schema: fed_mouse(crumbs),
            consequent_result=Success(
                "The mouse devours the crumbs, dropping something shiny to the floor in the "
                "process.  It then returns to its hole, well-fed and content"))

        # Foxes work cooperatively!
        def killed_fox(dead_fox, other_fox, key):
            dead_fox.remove_item(key)
            if other_fox.is_alive:
                other_fox.add_item(key)
                return result.GENERIC_SUCCESS
            else:
                return result.GENERIC_FAILURE

        kill.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.THEME: red_fox
            }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=killed_fox(red_fox, brown_fox, golden_key),
            consequent_result=Success(
                "As the red fox falls dead to the ground, its brother retrieves "
                "the golden key from its lifeless form"))

        kill.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.THEME: brown_fox
            }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=killed_fox(brown_fox, red_fox, bronze_key),
            consequent_result=Success(
                "As the brown fox falls dead to the ground, its brother retrieves "
                "the bronze key from its lifeless form"))

        # Achievement: unlock and open the sturdy door
        open.add_consequence(schema=Schema(roles={
            Role.AGENT: player,
            Role.PATIENT: sturdy_door
        }),
                             necessary_result=result.GENERIC_SUCCESS,
                             effect=lambda schema: update_score(game, 10))

        # Achievement: get the diamond from the villager
        ask.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.PATIENT: villager,
                Role.THEME: diamond
            }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=lambda schema: update_score(game, 20))

        get.add_consequence(schema=Schema(roles={
            Role.AGENT: player,
            Role.THEME: diamond
        }),
                            necessary_result=result.GENERIC_SUCCESS,
                            effect=lambda schema: update_score(game, 20))

        get.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.PATIENT: villager,
                Role.THEME: diamond
            }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=lambda schema: update_score(game, 20))

        # Health bonus: smell the sunflower
        smell.add_consequence(
            schema=Schema(roles={
                Role.AGENT: player,
                Role.THEME: flower
            }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=lambda schema: update_health(player, 10),
            consequent_result=Success(
                "You feel revived by the bloom's invigorating fragrance"))

        def unlock_gate(this_lock, other_lock):
            this_lock.traits.locked = False
            if other_lock.traits.locked:
                return result.GENERIC_FAILURE
            else:
                update_score(game, 50)
                metal_gate.traits.closed = False
                return result.GENERIC_SUCCESS

        unlock.add_consequence(
            schema=Schema(
                roles={
                    Role.AGENT: player,
                    Role.THEME: golden_lock,
                    Role.INSTRUMENT: golden_key
                }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=lambda schema: unlock_gate(golden_lock, bronze_lock),
            consequent_result=WON_GAME)

        unlock.add_consequence(
            schema=Schema(
                roles={
                    Role.AGENT: player,
                    Role.THEME: golden_lock,
                    Role.INSTRUMENT: golden_key
                }),
            necessary_result=result.GENERIC_SUCCESS,
            effect=lambda schema: unlock_gate(golden_lock, bronze_lock),
            consequent_result=WON_GAME)

        # Start game in crumbly room
        return crumbly_room