def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0, capacity=0): self.traits = Traits.merge(self, traits, Container.DEFAULT_TRAITS) super(Container, self).__init__(game, name, description, aliases, size=size, value=value) self.vocab = game.vocabulary self.put_preposition = 'in' self.capacity = capacity self.items = [] self.add_patient_role('put') self.add_patient_role('get') if not self.traits.surface: self.add_patient_role('open') self.add_patient_role('close') self.add_patient_role('lock') self.add_patient_role('unlock')
def __init__(self, game, name, description, aliases=None, traits=None): self.traits = Traits.merge(self, traits, Door.DEFAULT_TRAITS) super(Door, self).__init__(game, name, description, aliases) self.add_patient_role('open') self.add_patient_role('close') self.add_patient_role('lock') self.add_patient_role('unlock')
def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0): traits = Traits.merge(self, traits, Location.DEFAULT_TRAITS) super(Location, self).__init__(game, name, description, aliases=aliases, traits=traits, size=size, value=value, capacity=Container.MAX_CAPACITY) self.vocab = game.vocabulary self.exits = dict() self.visited = False
def __init__(self, game, name, description, aliases=None, traits=None, health=0, strength=0, dexterity=0, speed=50, activity=33, location=None, entry_action=None, present_action=None, exit_action=None): self.traits = Traits.merge(self, traits, Creature.DEFAULT_TRAITS) super(Creature, self).__init__(game, name, description, aliases) self.health = health self.location = location self.strength = strength self.dexterity = dexterity self.last_movement = 0 self.movement_frequency = int(100 / speed) self.movement_strategy = self.random_walk self.last_activity = 0 self.activity_frequency = int(100 / activity) self.wanted_items = [] if not entry_action: self.entry_action = self.default_entry if not exit_action: self.exit_action = self.default_exit if not present_action: self.present_action = self.neutral_action if self.location: self.location.add_item(self) self.inventory = Container(game, name + '-inv', name + "'s items", traits=Traits(closed=False), capacity=strength) self.add_patient_role('greet') self.add_patient_role('wave') self.add_patient_role('smile') self.add_patient_role('give') self.add_patient_role('ask') self.add_patient_role('kill') self.add_patient_role('take')
def __init__(self, game, location=None): self.traits = Traits.merge(self, None, Player.DEFAULT_TRAITS) super(Player, self).__init__(game=game, name='me', description='A travel-weary but brave adventurer', aliases=None, health=100, strength=75, dexterity=80, location=location) self.game = game self.vocab = game.vocabulary
class VisibleThing(Thing): DEFAULT_TRAITS = Traits(visible=True) def __init__(self, game, name, description, aliases=None, traits=None): self.traits = Traits.merge(self, traits, VisibleThing.DEFAULT_TRAITS) super(VisibleThing, self).__init__(game, name, aliases) self.description = description self.add_patient_role('look') self.add_theme_role('throw') def describe(self): return Success(self.description)
class Door(Item): DEFAULT_TRAITS = Traits(portable=False, evident=False, closed=True, locked=True) def __init__(self, game, name, description, aliases=None, traits=None): self.traits = Traits.merge(self, traits, Door.DEFAULT_TRAITS) super(Door, self).__init__(game, name, description, aliases) self.add_patient_role('open') self.add_patient_role('close') self.add_patient_role('lock') self.add_patient_role('unlock')
def __init__(self, game, name, location, direction, destination, description, condition, fail_result, after=None, traits=None): self.traits = Traits.merge(self, traits, Passage.DEFAULT_TRAITS) super(Passage, self).__init__(game, name, aliases=None) self.vocab = game.vocabulary self.location = location.id self.direction = direction.id self.destination = destination.id self.description = description self.condition = condition self.after = after if fail_result: self.fail_result = fail_result else: self.fail_result = Passage.DEFAULT_FAIL_RESULT
class Key(Item): DEFAULT_TRAITS = Traits() def __init__(self, game, name, description, aliases=None, traits=None): self.traits = Traits.merge(self, traits, Key.DEFAULT_TRAITS) super(Key, self).__init__(game, name, description, aliases) self.add_instrument_role('lock') self.add_instrument_role('unlock') self.key_for = set() def set_lockable(self, lockable): self.key_for.add(lockable.id) def can_lock(self, lockable): return lockable.id in self.key_for
def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0, capacity=MAX_CAPACITY): self.traits = Traits.merge(self, traits, Surface.DEFAULT_TRAITS) super(Surface, self).__init__(game, name, description, aliases, traits, size=size, value=value, capacity=capacity) self.put_preposition = 'on'
def __init__(self, game, name, aliases=None, traits=None): self.game = game self.vocabulary = game.vocabulary self.id = self.vocabulary.register_noun(self) self.name = name if aliases: self.aliases = aliases else: self.aliases = [] self.traits = Traits.merge(self, traits, Thing.DEFAULT_TRAITS) self.modifiers = set() self.valid_roles = { Role.AGENT: [], Role.PATIENT: [], Role.THEME: [], Role.GOAL: [], Role.INSTRUMENT: [] }
class Direction(VisibleThing): DEFAULT_TRAITS = Traits(ubiquitous=True) @classmethod def create(cls, game, name, alias): d = Direction(game, name) Action.create(game=game, name=name, aliases=[alias], callback=lambda schema: schema[Role.AGENT].go(d)) return d def __init__(self, game, name, description=None, aliases=None): if description is None: description = 'An exit leading ' + name self.traits = Traits.merge(self, None, Direction.DEFAULT_TRAITS) super(Direction, self).__init__(game, name, description, aliases) self.add_goal_role('go')
def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0, damage=10, defense=10, accuracy=50): self.traits = Traits.merge(self, traits, Weapon.DEFAULT_TRAITS) super(Weapon, self).__init__(game, name, description, aliases, size=size, value=value) self.add_instrument_role('hit') self.damage = damage self.defense = defense self.accuracy = accuracy
class Surface(Container): MAX_CAPACITY = Container.MAX_CAPACITY DEFAULT_TRAITS = Traits(closed=False, portable=False, surface=True) def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0, capacity=MAX_CAPACITY): self.traits = Traits.merge(self, traits, Surface.DEFAULT_TRAITS) super(Surface, self).__init__(game, name, description, aliases, traits, size=size, value=value, capacity=capacity) self.put_preposition = 'on' def append_container_description(self, description): item_count = len(self.items) if item_count == 1: item = self.vocab.lookup_noun(self.items[0]) description.append(", with {} {} on it".format( item.article(), item.full_name())) elif item_count > 1: description.append("\nOn the {} are: ".format(self.full_name())) for item_id in self.items: item = self.vocab.lookup_noun(item_id) description.append("\n\t" + item.article().capitalize() + " " + item.full_name()) return description
def __init__(self, game, name, description, aliases=None, traits=None): self.traits = Traits.merge(self, traits, VisibleThing.DEFAULT_TRAITS) super(VisibleThing, self).__init__(game, name, aliases) self.description = description self.add_patient_role('look') self.add_theme_role('throw')
class Location(Container): DEFAULT_TRAITS = Traits(closed=False) def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0): traits = Traits.merge(self, traits, Location.DEFAULT_TRAITS) super(Location, self).__init__(game, name, description, aliases=aliases, traits=traits, size=size, value=value, capacity=Container.MAX_CAPACITY) self.vocab = game.vocabulary self.exits = dict() self.visited = False def to_json(self): return vars(self) @staticmethod def free_passage(game, player): return True def add_exit(self, direction, destination, description=None, condition=None, fail_result=None, after=None): if not condition: condition = Location.free_passage passage = Passage(self.game, self.name + '-' + direction.name, self, direction, destination, description, condition, fail_result, after) self.exits[direction.id] = passage def available_exits(self, game): return [self.exits[d] for d in self.exits if self.exits[d].condition(game, game.player)] def list_nondescript_exits(self): return ', '.join([self.vocab.lookup_noun(x).name for x in self.exits.keys() if not self.exits[x].description]) def append_exit_description(self, description): special_exits = [x for x in self.exits.keys() if self.exits[x].description] nondescript_exits = [x for x in self.exits.keys() if not self.exits[x].description] description.append("\n") for x in special_exits: description.append("\n" + self.exits[x].description) if len(special_exits) > 0: if len(nondescript_exits) == 1: description.append("\nAnother exit leads " + self.list_nondescript_exits()) elif len(nondescript_exits) > 1: description.append("\nOther exits lead " + self.list_nondescript_exits()) else: if len(nondescript_exits) == 1: description.append("\nAn exit leads " + self.list_nondescript_exits()) elif len(nondescript_exits) > 1: description.append("\nExits lead " + self.list_nondescript_exits()) def append_compelling_items(self, description): for item_id in self.items: item = self.vocab.lookup_noun(item_id) if item.traits.compelling: description.append("\n" + item.description) def append_evident_items(self, description): for item_id in self.items: item = self.vocab.lookup_noun(item_id) if item.traits.evident and not item.traits.compelling: description.append("\nThere {} {} {} here" .format(item.existential(), item.article(), item.full_name())) if isinstance(item, Container) and not item.traits.closed: item.append_container_description(description) def describe(self, verbose=True): description = Result("\n------ " + self.name + " ------", success=True) if verbose or not self.visited: description.append("\n\n" + self.description) self.append_compelling_items(description) self.append_evident_items(description) self.append_exit_description(description) return description
def __init__(self, game, name, description, aliases=None, traits=None): self.traits = Traits.merge(self, traits, Key.DEFAULT_TRAITS) super(Key, self).__init__(game, name, description, aliases) self.add_instrument_role('lock') self.add_instrument_role('unlock') self.key_for = set()
class Player(Creature): DEFAULT_TRAITS = Traits(evident=False) def __init__(self, game, location=None): self.traits = Traits.merge(self, None, Player.DEFAULT_TRAITS) super(Player, self).__init__(game=game, name='me', description='A travel-weary but brave adventurer', aliases=None, health=100, strength=75, dexterity=80, location=location) self.game = game self.vocab = game.vocabulary def is_valid_for_role(self, role, attempted_action): if role == Role.AGENT: return True else: return super().is_valid_for_role(role, attempted_action) def in_current_location(self, target): return target.id in self.location.items def is_nearby(self, target): return self.in_inventory(target) or self.in_current_location(target) def nearby_container_having(self, target): found_container = None nearby_item_ids = self.inventory.items + self.location.items nearby_items = [ self.game.vocabulary.lookup_noun(i) for i in nearby_item_ids ] nearby_containers = [ c for c in nearby_items if isinstance(c, Container) and not c.traits.closed ] for c in nearby_containers: if target.id in c.items: found_container = c break return found_container def nearby_creature_having(self, target): found_creature = None nearby_item_ids = self.inventory.items + self.location.items nearby_items = [ self.game.vocabulary.lookup_noun(i) for i in nearby_item_ids ] nearby_creatures = [ c for c in nearby_items if isinstance(c, Creature) and c != self ] for c in nearby_creatures: if target.id in c.inventory.items: found_creature = c break return found_creature def go(self, direction): if direction.id in self.location.exits: self.location.visited = True passage = self.location.exits[direction.id] r1 = passage.go(self.game, self) if r1.success: r = self.location.describe(verbose=False) else: r = r1 else: r = Failure("You can't go {} from here".format(direction.name)) return r 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 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 def look(self, item=None): if item is None: item = self.location r = item.describe() elif self.is_nearby(item): r = item.describe() else: container = self.nearby_container_having(item) if container: r = item.describe() else: r = ProximityFailure(item.full_name()) return r 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 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 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 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 def diagnose(self): return Success("Health: {}; strength: {}".format( self.health, self.strength)) 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 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 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 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 def eat(self, edible): return self.consume(edible, 'delicious', 'eat') def drink(self, edible): return self.consume(edible, 'refreshing', 'drink') def greet(self, creature): if not self.is_nearby(creature): r = ProximityFailure(creature.full_name()) else: r = creature.respond_to_greeting() return r 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 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 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 def throw(self, throwable, target=None): if not self.in_inventory(throwable): r = OwnershipFailure(throwable.full_name()) elif target and not self.is_nearby(target): r = ProximityFailure(throwable.full_name()) else: if throwable.size > 30: message = "You heave the {} {}; it falls to the ground {}" direction = "into the air" result = "with a solid thunk" elif 10 < throwable.size <= 30: message = "You lob the {} {}; it hits the ground {}" direction = "across the room" result = "and rolls to a stop" else: # throwable.size < 10 message = "You toss the {} {}; it comes back down {}" direction = "into the air" result = "with a soft plop" if target: direction = "at the {}, but miss".format(target.full_name()) if throwable.traits.fragile: result = "and smashes to bits" self.inventory.remove_item(throwable) else: self.drop(throwable) r = Failure( message.format(throwable.full_name(), direction, result)) return r
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
def __init__(self, game, name, description=None, aliases=None): if description is None: description = 'An exit leading ' + name self.traits = Traits.merge(self, None, Direction.DEFAULT_TRAITS) super(Direction, self).__init__(game, name, description, aliases) self.add_goal_role('go')
class Creature(Item): DEFAULT_TRAITS = Traits(portable=False, hostile=False, friendly=False, dead=False) def __init__(self, game, name, description, aliases=None, traits=None, health=0, strength=0, dexterity=0, speed=50, activity=33, location=None, entry_action=None, present_action=None, exit_action=None): self.traits = Traits.merge(self, traits, Creature.DEFAULT_TRAITS) super(Creature, self).__init__(game, name, description, aliases) self.health = health self.location = location self.strength = strength self.dexterity = dexterity self.last_movement = 0 self.movement_frequency = int(100 / speed) self.movement_strategy = self.random_walk self.last_activity = 0 self.activity_frequency = int(100 / activity) self.wanted_items = [] if not entry_action: self.entry_action = self.default_entry if not exit_action: self.exit_action = self.default_exit if not present_action: self.present_action = self.neutral_action if self.location: self.location.add_item(self) self.inventory = Container(game, name + '-inv', name + "'s items", traits=Traits(closed=False), capacity=strength) self.add_patient_role('greet') self.add_patient_role('wave') self.add_patient_role('smile') self.add_patient_role('give') self.add_patient_role('ask') self.add_patient_role('kill') self.add_patient_role('take') def add_item(self, item): self.inventory.add_item(item) def remove_item(self, item): self.inventory.remove_item(item) def add_wanted_item(self, item): self.wanted_items.append(item) def become_friendly(self): self.traits.friendly = True self.present_action = self.friendly_action def become_hostile(self): self.traits.hostile = True self.present_action = self.hostile_action def default_entry(self, game, player): return Result("{} {} has entered the room".format( self.article().capitalize(), self.full_name())) def default_exit(self, game, player): return Result("The {} has exited the room".format(self.full_name())) def neutral_action(self, game, player): result = Result("The {} eyes you suspiciously".format(self.name)) result.add_message( "The {} glances at you quickly, then away again".format(self.name)) result.add_message("The {} coughs nervously".format(self.name)) result.add_message( "The {} whistles tunelessly, avoiding your gaze".format(self.name)) return result def friendly_action(self, game, player): result = Result( "The {} nods its head at you in friendly greeting".format( self.name)) result.add_message("The {} smiles warmly at you".format(self.name)) result.add_message("The {} leans against the wall of the room".format( self.name)) result.add_message( "The {} hums a happy tune, hands in its pockets".format(self.name)) return result def hostile_action(self, game, player): result = Result("The {} glares at you ferociously".format(self.name)) result.add_message("The {} growls under its breath".format(self.name)) result.add_message("The {} gnashes its teeth in anger".format( self.name)) result.add_message("The {} clenches its fists with fury".format( self.name)) return result def is_near_player(self): player = self.game.player return self.location == player.location def in_inventory(self, target): return target.id in self.inventory.items def is_alive(self): return self.health > 0 def respond_to_greeting(self): if self.traits.hostile: result = Result("The {} snorts derisively at your greeting".format( self.name)) elif self.traits.friendly: result = Result( "The {} gives you a friendly wave in return".format(self.name)) else: result = Result( "The {} acknowledges your greeting with a curt nod".format( self.name)) return result def attack(self, game, player): r = Result("The {} attacks ... ".format(self.name)) attack_difficulty = random.randint(0, 100) if self.dexterity < attack_difficulty: r.append("luckily, its blow fails to connect") else: r.append("and hits you! You stagger back in pain ... ") player.health -= self.strength return r def should_interact(self, game, player): return self.last_activity == 0 \ or self.activity_frequency <= game.turns - self.last_activity def act(self, game, player): self.last_activity = game.turns r = self.present_action(game, player) return r def should_move(self, game, player): return self.last_movement == 0 \ or self.movement_frequency <= game.turns - self.last_movement def random_walk(self, game, location): passages = location.available_exits(game) if len(passages) > 0: p = random.choice(passages) p.go(game, self) return self.location def move(self, game, player): self.last_movement = game.turns start_location = self.location new_location = self.movement_strategy(game, start_location) if start_location != player.location \ and new_location == player.location: r = self.entry_action(game, player) elif start_location == player.location \ and new_location != player.location: r = self.exit_action(game, player) else: r = None return r def update(self, game, player): r = None if self.is_near_player(): if self.traits.hostile: r = self.attack(game, player) elif self.should_interact(game, player): r = self.act(game, player) elif self.traits.mobile: r = self.move(game, player) elif self.traits.mobile: r = self.move(game, player) return r def describe(self): r = super(Creature, self).describe() item_count = len(self.inventory.items) if item_count == 1: item = self.vocabulary.lookup_noun(self.inventory.items[0]) r.append(", carrying {} {}".format(item.article(), item.name)) elif item_count > 1: r.append(", carrying: ") for item_id in self.inventory.items: item = self.vocabulary.lookup_noun(item_id) r.append("\n\t" + item.description) return r
class Container(Item): MAX_CAPACITY = 999 DEFAULT_TRAITS = Traits(closed=True) def __init__(self, game, name, description, aliases=None, traits=None, size=0, value=0, capacity=0): self.traits = Traits.merge(self, traits, Container.DEFAULT_TRAITS) super(Container, self).__init__(game, name, description, aliases, size=size, value=value) self.vocab = game.vocabulary self.put_preposition = 'in' self.capacity = capacity self.items = [] self.add_patient_role('put') self.add_patient_role('get') if not self.traits.surface: self.add_patient_role('open') self.add_patient_role('close') self.add_patient_role('lock') self.add_patient_role('unlock') def item_count(self): return len(self.items) def used_capacity(self): used_capacity = 0 for item_id in self.items: item = self.vocab.lookup_noun(item_id) used_capacity += item.size return used_capacity def remaining_capacity(self): return self.capacity - self.used_capacity() 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 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 def append_container_description(self, description): item_count = len(self.items) if item_count == 0: description.append(", containing nothing") elif len(self.items) == 1: item = self.vocab.lookup_noun(self.items[0]) description.append(", containing {} {}".format( item.article(), item.name)) else: description.append(", containing: ") for item_id in self.items: item = self.vocab.lookup_noun(item_id) description.append("\n\t" + item.article() + " " + item.full_name()) def describe(self): r = super(Container, self).describe() if self.traits.closed: r.append(", which is currently closed") else: self.append_container_description(r) return r