From 3d1ebfa3fcbd18b9954cf0ad05ce716ff5df8065 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Wed, 12 Feb 2025 22:37:19 -0800 Subject: [PATCH] Adding a batchcommands file with descriptions And fixed a number of bugs with starting from scratch. --- commands/lighting.py | 16 +- typeclasses/lightables.py | 97 +++++ typeclasses/objects.py | 110 +---- typeclasses/pets.py | 7 +- typeclasses/rooms.py | 239 +---------- typeclasses/rooms_dark.py | 235 ++++++++++ typeclasses/sittables.py | 4 +- typeclasses/things.py | 6 + world/version1.ev | 884 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 1255 insertions(+), 343 deletions(-) create mode 100755 typeclasses/lightables.py mode change 100644 => 100755 typeclasses/objects.py create mode 100755 typeclasses/rooms_dark.py create mode 100644 world/version1.ev diff --git a/commands/lighting.py b/commands/lighting.py index 9572a54..be4a9f7 100755 --- a/commands/lighting.py +++ b/commands/lighting.py @@ -1,7 +1,7 @@ #!/usr/bin/env python -from commands.command import Command -from evennia import CmdSet +from evennia import Command, CmdSet +# from .command import Command class CmdLight(Command): """ @@ -11,19 +11,17 @@ class CmdLight(Command): key = "light" aliases = ["burn"] # only allow this command if command.obj is carried by caller. - locks = "cmd:holds()" + # locks = "cmd:holds()" def func(self): """ Implements the light command. Since this command is designed to sit on a "lightable" object, we operate only on self.obj. """ - if self.obj.light(): self.caller.msg("You light %s." % self.obj.key) self.caller.location.msg_contents( - "%s lights %s!" % (self.caller, self.obj.key), exclude=[self.caller] - ) + "%s lights %s!" % (self.caller, self.obj.key), exclude=[self.caller]) else: self.caller.msg("%s is already burning." % self.obj.key) @@ -31,10 +29,6 @@ class CmdLight(Command): class CmdSetLight(CmdSet): """CmdSet for the lightsource commands""" - key = "lightsource_cmdset" - # this is higher than the dark cmdset - important! - priority = 3 - def at_cmdset_creation(self): """called at cmdset creation""" - self.add(CmdLight()) + self.add(CmdLight) diff --git a/typeclasses/lightables.py b/typeclasses/lightables.py new file mode 100755 index 0000000..7620b74 --- /dev/null +++ b/typeclasses/lightables.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python + +from commands.lighting import CmdSetLight + +# ------------------------------------------------------------- +# +# LightSource +# +# This object emits light. Once it has been turned on it +# cannot be turned off. When it burns out it will delete +# itself. +# +# This could be implemented using a single-repeat Script or by +# registering with the TickerHandler. We do it simpler by +# using the delay() utility function. This is very simple +# to use but does not survive a server @reload. Because of +# where the light matters (in the Dark Room where you can +# find new light sources easily), this is okay here. +# +# ------------------------------------------------------------- + +class LightSource(Object): + """ + This implements a light source object. + + When burned out, the object will be deleted. + """ + + def at_init(self): + """ + If this is called with the Attribute is_giving_light already + set, we know that the timer got killed by a server + reload/reboot before it had time to finish. So we kill it here + instead. This is the price we pay for the simplicity of the + non-persistent delay() method. + """ + if self.db.is_giving_light: + self.delete() + + def at_object_creation(self): + """Called when object is first created.""" + super().at_object_creation() + + self.db.is_giving_light = False + self.db.burntime = 60 * 3 # 3 minutes + # this is the default desc, it can of course be customized + # when created. + self.db.desc = "A tapered candle." + # add the Light command + self.cmdset.add_default(CmdSetLight, persistent=True) + + def _burnout(self): + """ + This is called when this light source burns out. We make no + use of the return value. + """ + # delete ourselves from the database + self.db.is_giving_light = False + try: + self.location.location.msg_contents( + "%s's %s flickers and dies." % (self.location, self.key), exclude=self.location + ) + self.location.msg("Your %s flickers and dies." % self.key) + self.location.location.check_light_state() + except AttributeError: + try: + self.location.msg_contents("A %s on the floor flickers and dies." % self.key) + self.location.location.check_light_state() + except AttributeError: + # Mainly happens if we happen to be in a None location + pass + self.delete() + + def light(self): + """ + Light this object - this is called by Light command. + """ + if self.db.is_giving_light: + return False + # burn for 3 minutes before calling _burnout + self.db.is_giving_light = True + # if we are in a dark room, trigger its light check + try: + self.location.location.check_light_state() + except AttributeError: + try: + # maybe we are directly in the room + self.location.check_light_state() + except AttributeError: + # we are in a None location + pass + finally: + # start the burn timer. When it runs out, self._burnout + # will be called. We store the deferred so it can be + # killed in unittesting. + self.deferred = delay(60 * 3, self._burnout) + return True diff --git a/typeclasses/objects.py b/typeclasses/objects.py old mode 100644 new mode 100755 index 662276c..6f7971e --- a/typeclasses/objects.py +++ b/typeclasses/objects.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python + """ Object @@ -9,9 +11,8 @@ with a location in the game world (like Characters, Rooms, Exits). """ from evennia.objects.objects import DefaultObject -from evennia.utils import delay, search +from evennia.utils import delay, logger, search -from commands.lighting import CmdSetLight class ObjectParent: """ @@ -231,96 +232,27 @@ class Object(ObjectParent, DefaultObject): elif i == item: return i -# ------------------------------------------------------------- -# -# LightSource -# -# This object emits light. Once it has been turned on it -# cannot be turned off. When it burns out it will delete -# itself. -# -# This could be implemented using a single-repeat Script or by -# registering with the TickerHandler. We do it simpler by -# using the delay() utility function. This is very simple -# to use but does not survive a server @reload. Because of -# where the light matters (in the Dark Room where you can -# find new light sources easily), this is okay here. -# -# ------------------------------------------------------------- - -class LightSource(Object): - """ - This implements a light source object. - - When burned out, the object will be deleted. - """ - - def at_init(self): + def at_look(self, target, **kwargs): """ - If this is called with the Attribute is_giving_light already - set, we know that the timer got killed by a server - reload/reboot before it had time to finish. So we kill it here - instead. This is the price we pay for the simplicity of the - non-persistent delay() method. - """ - if self.db.is_giving_light: - self.delete() + When we look at something that _might_ be hidden, we check + if we are looking at something that _is_ hidden, i.e. has a + view lock of a particular tag, and if so, we interpret this as + 'you are looking at something by name', therefore you see it. + So we give ourselves the right to see it from now on. - def at_object_creation(self): - """Called when object is first created.""" - super().at_object_creation() + To use this, simply add the following lock: - self.db.is_giving_light = False - self.db.burntime = 60 * 3 # 3 minutes - # this is the default desc, it can of course be customized - # when created. - self.db.desc = "A tapered candle." - # add the Light command - self.cmdset.add_default(CmdSetLight, persistent=True) + @lock thing = view:tag(hidden_thing, mp) - def _burnout(self): + Where thing is the single name of the hidden object. """ - This is called when this light source burns out. We make no - use of the return value. - """ - # delete ourselves from the database - self.db.is_giving_light = False - try: - self.location.location.msg_contents( - "%s's %s flickers and dies." % (self.location, self.key), exclude=self.location - ) - self.location.msg("Your %s flickers and dies." % self.key) - self.location.location.check_light_state() - except AttributeError: - try: - self.location.msg_contents("A %s on the floor flickers and dies." % self.key) - self.location.location.check_light_state() - except AttributeError: - # Mainly happens if we happen to be in a None location - pass - self.delete() + hidden_tag = f"hidden_{target}" + lock_string = f"view:tag({hidden_tag}, mp)" + view_lock = target.locks.get("view") - def light(self): - """ - Light this object - this is called by Light command. - """ - if self.db.is_giving_light: - return False - # burn for 3 minutes before calling _burnout - self.db.is_giving_light = True - # if we are in a dark room, trigger its light check - try: - self.location.location.check_light_state() - except AttributeError: - try: - # maybe we are directly in the room - self.location.check_light_state() - except AttributeError: - # we are in a None location - pass - finally: - # start the burn timer. When it runs out, self._burnout - # will be called. We store the deferred so it can be - # killed in unittesting. - self.deferred = delay(60 * 3, self._burnout) - return True + if view_lock == lock_string: + self.tags.add(hidden_tag, category="mp") + + # Regardless of what happened before, we return the normal + # function call. + return super().at_look(target) diff --git a/typeclasses/pets.py b/typeclasses/pets.py index 74afd92..80bd447 100755 --- a/typeclasses/pets.py +++ b/typeclasses/pets.py @@ -7,7 +7,8 @@ Each level of pet requires more aspects for interaction. """ -from typeclasses.objects import Object, LightSource +from typeclasses.objects import Object +# from typeclasses.lightables import LightSource from commands.feedables import CmdFeed, CmdFeedSet from utils.word_list import squish @@ -180,12 +181,12 @@ class Fire(Pet): gets_up = "gets up and" if self.db.hunger_level < 5: - feeder.msg(squish(f"You {get_up} put some {adj} wood in the " + feeder.msg(squish(f"You {get_up} put {adj} wood in the " f"fireplace, and start a fire.")) self.location.msg_contents(squish(f"{feeder.name} {gets_up} starts a fire."), exclude=feeder) else: - feeder.msg(squish(f"You {get_up} put some {adj} wood on the " + feeder.msg(squish(f"You {get_up} put {adj} wood on the " f"fire in the fireplace.")) self.location.msg_contents(squish(f"{feeder.name} {gets_up} puts {adj} wood on the fire."), exclude=feeder) diff --git a/typeclasses/rooms.py b/typeclasses/rooms.py index a386f22..ccd4093 100644 --- a/typeclasses/rooms.py +++ b/typeclasses/rooms.py @@ -9,7 +9,7 @@ from evennia.objects.objects import DefaultRoom from evennia.contrib.grid.extended_room import ExtendedRoom from evennia.prototypes.spawner import spawn -from .objects import LightSource +# from .objects import LightSource from .drinkables import TEACUP_DESCS from .pets import Hunger from commands.drinkables import CmdSetTrolley @@ -35,7 +35,6 @@ from evennia import ( utils, ) -# from .objects import LightSource _SEARCH_AT_RESULT = utils.object_from_module(settings.SEARCH_AT_RESULT) from .objects import ObjectParent @@ -54,242 +53,6 @@ class Room(ObjectParent, ExtendedRoom): is_dark = False has_weather = False - pass - -# ------------------------------------------------------------------------------- -# -# Dark Room - a room with states -# -# This room limits the movemenets of its denizens unless they carry an active -# LightSource object (LightSource is defined in objects.LightSource) -# -# ------------------------------------------------------------------------------- - - -DARK_MESSAGES = ( - "It is pitch black. You are likely to be eaten by a grue.", - "It's pitch black. You fumble around but cannot find anything.", - "You don't see a thing. You feel around, managing to bump your fingers hard against something. Ouch!", - "You don't see a thing! Blindly grasping the air around you, you find nothing.", - "It's totally dark here. You almost stumble over something on the floor.", - "You are completely blind. For a moment you think you hear someone breathing nearby ... " - "\n ... surely you must be mistaken.", -) - -ALREADY_LIGHTSOURCE = ( - "You don't want to stumble around in blindness anymore. You already " - "found what you need. Let's get the fireplace lit already!" -) - -FOUND_LIGHTSOURCE = ( - "Your fingers bump against a candle on a candleabra." - "You pick it up, holding it firmly. Now you just need to" - " |wlight|n it using the flint and steel you carry with you." -) - - -class CmdLookDark(Command): - """ - Look around in darkness - - Usage: - look - - Look around in the darkness, trying - to find something. - """ - - key = "look" - aliases = ["l", "feel", "search", "feel around", "fiddle"] - locks = "cmd:all()" - - def func(self): - """ - Implement the command. - - This works both as a look and a search command; there is a - random chance of eventually finding a light source. - """ - caller = self.caller - - # count how many searches we've done - nr_searches = caller.ndb.dark_searches - if nr_searches is None: - nr_searches = 0 - caller.ndb.dark_searches = nr_searches - - if nr_searches < 4 and random.random() < 0.90: - # we don't find anything - caller.msg(random.choice(DARK_MESSAGES)) - caller.ndb.dark_searches += 1 - else: - # we could have found something! - if any(obj for obj in caller.contents if utils.inherits_from(obj, LightSource)): - # we already carry a LightSource object. - caller.msg(ALREADY_LIGHTSOURCE) - else: - # don't have a light source, create a new one. - create_object(LightSource, key="candle", location=caller) - caller.msg(FOUND_LIGHTSOURCE) - - -class CmdDarkHelp(Command): - """ - Help command for the dark state. - """ - key = "help" - locks = "cmd:all()" - - def func(self): - """ - Replace the the help command with a not-so-useful help - """ - string = ( - "Can't help you until you find some light! Try looking/feeling around for something to burn. " - "You shouldn't give up even if you don't find anything right away." - ) - self.caller.msg(string) - - -class CmdDarkNoMatch(Command): - """ - This is a system command. Commands with special keys are used to - override special sitations in the game. The CMD_NOMATCH is used - when the given command is not found in the current command set (it - replaces Evennia's default behavior or offering command - suggestions) - """ - - key = syscmdkeys.CMD_NOMATCH - locks = "cmd:all()" - - def func(self): - """Implements the command.""" - self.caller.msg( - "Until you find some light, there's not much you can do. " - "Try feeling around, maybe you'll find something helpful!" - ) - - -class DarkCmdSet(CmdSet): - """ - Groups the commands of the dark room together. We also import the - default say command here so that players can still talk in the - darkness. - - We give the cmdset the mergetype "Replace" to make sure it - completely replaces whichever command set it is merged onto - (usually the default cmdset) - """ - - key = "darkroom_cmdset" - mergetype = "Replace" - priority = 2 - - def at_cmdset_creation(self): - """populate the cmdset.""" - self.add(CmdLookDark()) - self.add(CmdDarkHelp()) - self.add(CmdDarkNoMatch()) - self.add(default_cmds.CmdSay()) - self.add(default_cmds.CmdQuit()) - self.add(default_cmds.CmdHome()) - - -class DarkRoom(Room): - """A dark room. This tries to start the DarkState script on all - objects entering. The script is responsible for making sure it is - valid (that is, that there is no light source shining in the room). - - The is_lit Attribute is used to define if the room is currently lit - or not, so as to properly echo state changes. - - Since this room is meant as a sort of catch-all, we also make sure - to heal characters ending up here. - - """ - - def at_object_creation(self): - """ - Called when object is first created. - """ - super().at_object_creation() - # the room starts dark. - self.db.is_lit = False - self.cmdset.add(DarkCmdSet, persistent=True) - - def at_init(self): - """ - Called when room is first recached (such as after a reload) - """ - self.check_light_state() - - def _carries_light(self, obj): - """ - Checks if the given object carries anything that gives light. - - Note that we do NOT look for a specific LightSource typeclass, - but for the Attribute is_giving_light - this makes it easy to - later add other types of light-giving items. We also accept - if there is a light-giving object in the room overall (like if - a candle was dropped in the room or the fireplace is lit). - """ - return ( - obj.is_superuser - or obj.db.is_giving_light - or any(o for o in obj.contents if o.db.is_giving_light) - ) - - def check_light_state(self, exclude=None): - """ - This method checks if there are any light sources in the room. - If there isn't it makes sure to add the dark cmdset to all - characters in the room. It is called whenever characters enter - the room and also by the Light sources when they turn on. - - Args: - exclude (Object): An object to not include in the light check. - """ - if any(self._carries_light(obj) for obj in self.contents if obj != exclude): - self.locks.add("view:all()") - self.cmdset.remove(DarkCmdSet) - self.db.is_lit = True - for char in (obj for obj in self.contents if obj.has_account): - # this won't do anything if it is already removed - char.msg("The room is lit up.") - else: - # noone is carrying light - darken the room - self.db.is_lit = False - self.locks.add("view:false()") - self.cmdset.add(DarkCmdSet, persistent=True) - for char in (obj for obj in self.contents if obj.has_account): - if char.is_superuser: - char.msg("You are Superuser, so you are not affected by the dark state.") - else: - # put players in darkness - char.msg("The room is completely dark.") - - def at_object_receive(self, obj, source_location, move_type="move", **kwargs): - """ - Called when an object enters the room. - """ - if obj.has_account: - # a puppeted object, that is, a Character - self._heal(obj) - # in case the new guy carries light with them - self.check_light_state() - - def at_object_leave(self, obj, target_location, move_type="move", **kwargs): - """ - In case people leave with the light, we make sure to clear the - DarkCmdSet if necessary. This also works if they are - teleported away. - """ - # since this hook is called while the object is still in the room, - # we exclude it from the light check, to ignore any light sources - # it may be carrying. - self.check_light_state(exclude=obj) - class DabblersRoom(Room): teacup_prototype = { diff --git a/typeclasses/rooms_dark.py b/typeclasses/rooms_dark.py new file mode 100755 index 0000000..39433bd --- /dev/null +++ b/typeclasses/rooms_dark.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python + +# ------------------------------------------------------------------------------- +# +# Dark Room - a room with states +# +# This room limits the movemenets of its denizens unless they carry an active +# LightSource object (LightSource is defined in objects.LightSource) +# +# ------------------------------------------------------------------------------- + + +DARK_MESSAGES = ( + "It is pitch black. You are likely to be eaten by a grue.", + "It's pitch black. You fumble around but cannot find anything.", + "You don't see a thing. You feel around, managing to bump your fingers hard against something. Ouch!", + "You don't see a thing! Blindly grasping the air around you, you find nothing.", + "It's totally dark here. You almost stumble over something on the floor.", + "You are completely blind. For a moment you think you hear someone breathing nearby ... " + "\n ... surely you must be mistaken.", +) + +ALREADY_LIGHTSOURCE = ( + "You don't want to stumble around in blindness anymore. You already " + "found what you need. Let's get the fireplace lit already!" +) + +FOUND_LIGHTSOURCE = ( + "Your fingers bump against a candle on a candleabra." + "You pick it up, holding it firmly. Now you just need to" + " |wlight|n it using the flint and steel you carry with you." +) + + +class CmdLookDark(Command): + """ + Look around in darkness + + Usage: + look + + Look around in the darkness, trying + to find something. + """ + + key = "look" + aliases = ["l", "feel", "search", "feel around", "fiddle"] + locks = "cmd:all()" + + def func(self): + """ + Implement the command. + + This works both as a look and a search command; there is a + random chance of eventually finding a light source. + """ + caller = self.caller + + # count how many searches we've done + nr_searches = caller.ndb.dark_searches + if nr_searches is None: + nr_searches = 0 + caller.ndb.dark_searches = nr_searches + + if nr_searches < 4 and random.random() < 0.90: + # we don't find anything + caller.msg(random.choice(DARK_MESSAGES)) + caller.ndb.dark_searches += 1 + else: + # we could have found something! + if any(obj for obj in caller.contents if utils.inherits_from(obj, LightSource)): + # we already carry a LightSource object. + caller.msg(ALREADY_LIGHTSOURCE) + else: + # don't have a light source, create a new one. + create_object(LightSource, key="candle", location=caller) + caller.msg(FOUND_LIGHTSOURCE) + + +class CmdDarkHelp(Command): + """ + Help command for the dark state. + """ + key = "help" + locks = "cmd:all()" + + def func(self): + """ + Replace the the help command with a not-so-useful help + """ + string = ( + "Can't help you until you find some light! Try looking/feeling around for something to burn. " + "You shouldn't give up even if you don't find anything right away." + ) + self.caller.msg(string) + + +class CmdDarkNoMatch(Command): + """ + This is a system command. Commands with special keys are used to + override special sitations in the game. The CMD_NOMATCH is used + when the given command is not found in the current command set (it + replaces Evennia's default behavior or offering command + suggestions) + """ + + key = syscmdkeys.CMD_NOMATCH + locks = "cmd:all()" + + def func(self): + """Implements the command.""" + self.caller.msg( + "Until you find some light, there's not much you can do. " + "Try feeling around, maybe you'll find something helpful!" + ) + + +class DarkCmdSet(CmdSet): + """ + Groups the commands of the dark room together. We also import the + default say command here so that players can still talk in the + darkness. + + We give the cmdset the mergetype "Replace" to make sure it + completely replaces whichever command set it is merged onto + (usually the default cmdset) + """ + + key = "darkroom_cmdset" + mergetype = "Replace" + priority = 2 + + def at_cmdset_creation(self): + """populate the cmdset.""" + self.add(CmdLookDark()) + self.add(CmdDarkHelp()) + self.add(CmdDarkNoMatch()) + self.add(default_cmds.CmdSay()) + self.add(default_cmds.CmdQuit()) + self.add(default_cmds.CmdHome()) + + +class DarkRoom(Room): + """A dark room. This tries to start the DarkState script on all + objects entering. The script is responsible for making sure it is + valid (that is, that there is no light source shining in the room). + + The is_lit Attribute is used to define if the room is currently lit + or not, so as to properly echo state changes. + + Since this room is meant as a sort of catch-all, we also make sure + to heal characters ending up here. + + """ + + def at_object_creation(self): + """ + Called when object is first created. + """ + super().at_object_creation() + # the room starts dark. + self.db.is_lit = False + self.cmdset.add(DarkCmdSet, persistent=True) + + def at_init(self): + """ + Called when room is first recached (such as after a reload) + """ + self.check_light_state() + + def _carries_light(self, obj): + """ + Checks if the given object carries anything that gives light. + + Note that we do NOT look for a specific LightSource typeclass, + but for the Attribute is_giving_light - this makes it easy to + later add other types of light-giving items. We also accept + if there is a light-giving object in the room overall (like if + a candle was dropped in the room or the fireplace is lit). + """ + return ( + obj.is_superuser + or obj.db.is_giving_light + or any(o for o in obj.contents if o.db.is_giving_light) + ) + + def check_light_state(self, exclude=None): + """ + This method checks if there are any light sources in the room. + If there isn't it makes sure to add the dark cmdset to all + characters in the room. It is called whenever characters enter + the room and also by the Light sources when they turn on. + + Args: + exclude (Object): An object to not include in the light check. + """ + if any(self._carries_light(obj) for obj in self.contents if obj != exclude): + self.locks.add("view:all()") + self.cmdset.remove(DarkCmdSet) + self.db.is_lit = True + for char in (obj for obj in self.contents if obj.has_account): + # this won't do anything if it is already removed + char.msg("The room is lit up.") + else: + # noone is carrying light - darken the room + self.db.is_lit = False + self.locks.add("view:false()") + self.cmdset.add(DarkCmdSet, persistent=True) + for char in (obj for obj in self.contents if obj.has_account): + if char.is_superuser: + char.msg("You are Superuser, so you are not affected by the dark state.") + else: + # put players in darkness + char.msg("The room is completely dark.") + + def at_object_receive(self, obj, source_location, move_type="move", **kwargs): + """ + Called when an object enters the room. + """ + if obj.has_account: + # a puppeted object, that is, a Character + self._heal(obj) + # in case the new guy carries light with them + self.check_light_state() + + def at_object_leave(self, obj, target_location, move_type="move", **kwargs): + """ + In case people leave with the light, we make sure to clear the + DarkCmdSet if necessary. This also works if they are + teleported away. + """ + # since this hook is called while the object is still in the room, + # we exclude it from the light check, to ignore any light sources + # it may be carrying. + self.check_light_state(exclude=obj) diff --git a/typeclasses/sittables.py b/typeclasses/sittables.py index be6c13e..19633f7 100755 --- a/typeclasses/sittables.py +++ b/typeclasses/sittables.py @@ -69,6 +69,8 @@ class Sittables(Sittable): multiple = True def sit_msg(self): + aliases = self.aliases.all() + adjective = self.db.adjective or "on" article = self.db.article or "the" name = aliases[-1] # Last alias is singular @@ -76,8 +78,6 @@ class Sittables(Sittable): singular = self.db.singular or default extra = self.db.extra or "" - aliases = self.aliases.all() - return routput(f"You sit {adjective} {singular}. {extra}") def stand_msg(self): diff --git a/typeclasses/things.py b/typeclasses/things.py index 69755b3..dc1ba53 100755 --- a/typeclasses/things.py +++ b/typeclasses/things.py @@ -20,6 +20,12 @@ from random import choice, random import re +class Unhider(Object): + """ + This thing has the ability to "unhide" other things. + The idea is .... ugh. + @set thing/ + """ class Returnable(Object): """ This object can't go far from one or two locations. diff --git a/world/version1.ev b/world/version1.ev new file mode 100644 index 0000000..3388e4c --- /dev/null +++ b/world/version1.ev @@ -0,0 +1,884 @@ +# [[file:../../../projects/mud.org::*Shell][Shell:4]] +# # -*- mode:ruby; -*- +# Shell:4 ends here + + +# Can I rename myself? + + +# [[file:../../../projects/mud.org::*Character: Dabble][Character: Dabble:1]] +@name self = Dabbler;gnome;old gnome +# Character: Dabble:1 ends here + + + +# And a good description that I can rework: + + +# [[file:../../../projects/mud.org::*Character: Dabble][Character: Dabble:2]] +@desc self = A small, hunched old man with a gray vandyke and an eye + twinkle. Spectacles perched precariously on the end of his hooked + nose, wobble with his head. A jaunty crimson cap contrasts with his + dark brown cloak. +# Character: Dabble:2 ends here + + +# Rename the Limbo (or starting place) with the name *Forest*. Note the term =mp01= as a global label that matches my map. + + +# [[file:../../../projects/mud.org::*The Forest][The Forest:1]] +@name here = The Forest;mp01 +# The Forest:1 ends here + + + +# The description will take advantage of the /seasons/ and /times/ of the day: + + +# [[file:../../../projects/mud.org::*The Forest][The Forest:2]] +@desc here = A giant, moss-covered boulder stands among immense trees + that etch the sky and slice the clouds in the darkening + twilightawakening dawnlazy + afternoonnight sky. A footpath winds around + the giant, moss-covered tree roots to the East and West. To the south, + a dock lounges on a large pond. +# The Forest:2 ends here + + + +# Need to add weather and time data to this: + +# [[file:../../../projects/mud.org::*The Forest][The Forest:3]] +# from evennia.contrib.tutorials.tutorial_world.rooms import WeatherRoom +@update here = typeclasses.rooms_weather.TimeWeatherRoom +# The Forest:3 ends here + + +# More details about the room that describes aspects of the boulder in the =desc= above. First, the symbol: + +# [[file:../../../projects/mud.org::*Boulder][Boulder:1]] +@detail symbol = You move an ivy runner to see three curves join + together as if it were three legs. +# Boulder:1 ends here + + + +# The moss is purdy: + +# [[file:../../../projects/mud.org::*Boulder][Boulder:2]] +@detail moss = "Even in this light, the moss radiates a surreal color of green." +# Boulder:2 ends here + + + +# And the ivy is … uh. + +# [[file:../../../projects/mud.org::*Boulder][Boulder:3]] +@detail ivy = "You see...well, ivy. Uhm, it's green, and..." +# Boulder:3 ends here + + + +# The runes use multibyte unicode which screws up the =telnet= client. + +# [[file:../../../projects/mud.org::*Boulder][Boulder:4]] +@detail runes = "The runes read ᛞ ᚪ ᛒ ᛚ ᚱ" +# Boulder:4 ends here + + + +# The top of the boulder should be another room, accessible by the =climb=, but maybe it isn’t “seen” until the boulder has been looked? First, we put some weather at the top of the boulder: + + +# [[file:../../../projects/mud.org::*Boulder][Boulder:5]] +@dig Top of Boulder;mp02 : typeclasses.rooms_weather.TimeWeatherRoom = boulder,climb +# Boulder:5 ends here + + + +# The ability to /climb/ the boulder isn’t immediately obvious, so let’s make it a bit of a secret: + +# [[file:../../../projects/mud.org::*Boulder][Boulder:6]] +@desc boulder = A boulder with patches of moss and delicate clover. + A carved symbol and even some runes try to hide behind tendrils of ivy + as if keeping a secret. Wait! You notice a foot hold, and then + another. You can |bclimb|n this boulder! +# Boulder:6 ends here + + + +# To take advantage of our [[Hidden Things]], we put the right tag on it: + +# [[file:../../../projects/mud.org::*Boulder][Boulder:7]] +@lock boulder = view:tag(hidden_boulder, mp) +# Boulder:7 ends here + + + +# And give it some aliases: + +# [[file:../../../projects/mud.org::*Boulder][Boulder:8]] +@name boulder = boulder;climb;climb up +# Boulder:8 ends here + +# [[file:../../../projects/mud.org::*Boulder][Boulder:9]] +@set boulder/traverse_msg = "You move some ivy out of the way and pick your way up the boulder from one hold to another..." +# Boulder:9 ends here + + + +# Let’s jump to the top of the boulder to proceed: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:1]] +@teleport mp02 +# @name here = Top of Boulder;mp02 +# Top of Boulder:1 ends here + + + +# And the description: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:2]] +@desc here = While high, the trees still tower over you. Still, a nice view. Lots of patches of moss to sit down and relax. +# Top of Boulder:2 ends here + + + +# Describe the climb down: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:3]] +@name climb = climb back down;climb down;climb;down +# Top of Boulder:3 ends here + + +# And a description of the climb: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:4]] +@desc climb = The climb seemed easy, but you're not sure you can + handle the footholds going the other way around. +# Top of Boulder:4 ends here + + +# And describe the journey: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:5]] +@set climb/traverse_msg = "You crawl backwards, feeling with your foot for a hold. Got it! Then another one...hoping the moss' rhizoids hold..." +# Top of Boulder:5 ends here + + + +# Let’s make a nice spot to sit down on: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:6]] +@create/drop moss;patch:typeclasses.sittables.Sittable +# Top of Boulder:6 ends here + + +# With a nice description: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:7]] +@desc moss = A cushioned patch of moss of the most vibrant green. +# Top of Boulder:7 ends here + + +# Can’t take the moss with you: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:8]] +@lock moss = get:false() +# Top of Boulder:8 ends here + + +# Can we hide it too? + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:9]] +@lock moss = view:tag(hidden_moss, mp) +# Top of Boulder:9 ends here + + +# And a lovely message about why you can’t steal moss: + +# [[file:../../../projects/mud.org::*Top of Boulder][Top of Boulder:10]] +@set moss/get_err_msg = The moss is a bryophyte, and as such, has + attached itself to boulder by rhizoids, which are one cell thick root + structures. While this helps with water absorption, you didn't think + you were going to get a biology lesson, did you? tl;dr You can't get it. +# Top of Boulder:10 ends here + + +# To the east, let’s make a nice meadow. Start at the Forest: + +# [[file:../../../projects/mud.org::*Field][Field:1]] +@teleport mp01 +# Field:1 ends here + + + +# And we use the =tunnel= command this time: + +# [[file:../../../projects/mud.org::*Field][Field:2]] +@tunnel e = path +# Field:2 ends here + + +# And a nice journey message to go east out of the forest: + +# [[file:../../../projects/mud.org::*Field][Field:3]] +@set east/traverse_msg = "The mossy tree roots that borders this +footpath begin to thin out to clover and flowers..." +# Field:3 ends here + + + +# Before we label it, we follow =east=: + +# [[file:../../../projects/mud.org::*Field][Field:4]] +east +# Field:4 ends here + + + +# And we give this area a name: + +# [[file:../../../projects/mud.org::*Field][Field:5]] +@name here = Meadow;mp05 +# Field:5 ends here + + + +# And a description that takes advantage of the time of day. We should get busy and get some seasonal description here. + + +# [[file:../../../projects/mud.org::*Field][Field:6]] +@desc here = The giant trees ring this meadow full of tall grass and + large yellow flowers, who nod their heads to you as you pass by in the + darkening twilightawakening + dawnlazy afternoonnight + sky. A gap in the trees show how you can return to the + footpath in the forest. +# Field:6 ends here + + + +# Since we use the =tunnel= command, we need to update the weather system: + +# [[file:../../../projects/mud.org::*Field][Field:7]] +@update here = typeclasses.rooms_weather.TimeWeatherRoom +# Field:7 ends here + + +# And describe the way out: + +# [[file:../../../projects/mud.org::*Field][Field:8]] +@name west = footpath;forest;west +# Field:8 ends here + + +# Along with a mesage: + +# [[file:../../../projects/mud.org::*Field][Field:9]] +@set footpath/traverse_msg = "You leave the open meadow for the footpath through the giant trees. The yellow flowers nod goodbye to you..." +# Field:9 ends here + + +# The dock leads out into the large pond. The break in the trees lets you see the sky. Looks like a nice place to relax. + +# Return to the Forest: + +# [[file:../../../projects/mud.org::*The Dock][The Dock:1]] +@teleport mp01 +# The Dock:1 ends here + + +# And tunnel to the pond: + +# [[file:../../../projects/mud.org::*The Dock][The Dock:2]] +@tunnel s = dock +# The Dock:2 ends here + + +# With a mesage about leaving the trees so that I don’t have to repeat that in the room description: + +# [[file:../../../projects/mud.org::*The Dock][The Dock:3]] +@set south/traverse_msg = "You follow a path down and step out from under giant trees to see the sky." +# The Dock:3 ends here + + +# And move ourselves there: + +# [[file:../../../projects/mud.org::*The Dock][The Dock:4]] +south +# The Dock:4 ends here + + + +# Since we are on a dock in the pond, we’ll emphasize that: + +# [[file:../../../projects/mud.org::*The Dock][The Dock:5]] +@name here = Lazy Dock;mp06 +# The Dock:5 ends here + + +# And describe this. + +# [[file:../../../projects/mud.org::*The Dock][The Dock:6]] +@desc here = The dock you stand on juts into an immense pond. Someone has set a nice chair for viewing. +# The Dock:6 ends here + + + +# And describe the walk back into the forest: + +# [[file:../../../projects/mud.org::*The Dock][The Dock:7]] +@set north/traverse_msg = "You walk up a path and back into the forest of giant trees." +# The Dock:7 ends here + + +# A nice chair to sit on the dock by the bay, watching the clouds as they drift away. + +# [[file:../../../projects/mud.org::*Chair][Chair:1]] +@create/drop chair;lounge chair:typeclasses.sittables.Sittable +# Chair:1 ends here + + + +# How descriptive: + +# [[file:../../../projects/mud.org::*Chair][Chair:2]] +@desc chair = A cushioned wood chair of craftsmanship. +Looks good for being out in the weather. +# Chair:2 ends here + + + +# Can’t steal this chair either: + +# [[file:../../../projects/mud.org::*Chair][Chair:3]] +@lock chair = get:false() +# Chair:3 ends here + +# [[file:../../../projects/mud.org::*Chair][Chair:4]] +@set chair/get_err_msg = "It's way too heavy for you to lift." +# Chair:4 ends here + + +# And a fishing pole? + +# First we need to make a =PermanentObject= (from the regular =Object=), but one that offers a + + +# [[file:../../../projects/mud.org::*Fishing Pole][Fishing Pole:1]] +@create/drop fishing pole;pole:typeclasses.things.FishingPole +@desc pole = A nice pole for catching fish. It even has a hook. +@detail hook = One of those shiny lures, made from gold coins. Curiouser. +@detail water = Despite the weather, the water looks fine. Perhaps there is a hole +# Fishing Pole:1 ends here + + + +# Return to the forest: + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:1]] +@teleport mp01 +# Forest Path:1 ends here + + +# Let’s travel west along the path in the forest: + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:2]] +@tunnel w = path +# Forest Path:2 ends here + + +# With a nice message about wandering: + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:3]] +@set west/traverse_msg = "You meander between mossy tree roots along a +footpath for a while..." +# Forest Path:3 ends here + + +# And some aliases: + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:4]] +@name west = west;w;footpath +# Forest Path:4 ends here + + + +# Jump into the new room: + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:5]] +west +# Forest Path:5 ends here + + +# And name it: + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:6]] +@name here = Forest Path;mp04 +# Forest Path:6 ends here + + + +# And describe the tree and the door: + + +# [[file:../../../projects/mud.org::*Forest Path][Forest Path:7]] +@desc here = Moss-covered tree roots border the meandering footpath. A + red door with a round top lies at the base of a giant tree, a carved + sign over it reads, Dabblers. +# Forest Path:7 ends here + + +# The knocker has the ability to make the door “open” using [[https://www.evennia.com/docs/latest/api/evennia.objects.objects.html][on_traverse]] hooks? + +# Most of the work of the /knocker/ is in the Python code: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:1]] +@create/drop knocker:typeclasses.things.Knocker +# Knocker:1 ends here + + +# If it /looks/ like a goblin… + +# [[file:../../../projects/mud.org::*Knocker][Knocker:2]] +@name knocker = door knocker;knocker;goblin +# Knocker:2 ends here + + + +# The knocker shouldn’t be stealable: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:3]] +@lock knocker = get:false() +# +@set knocker/get_err_msg = "It appears firmly attached to the door." +# Knocker:3 ends here + + + +# Since we can remove the ring, let’s create it: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:4]] +@create ring = typeclasses.things.Returnable +# Knocker:4 ends here + + + +# And give it an alias: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:5]] +@name ring = brass ring;ring +# Knocker:5 ends here + + + +# And a description: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:6]] +@desc ring = "A brass ring that should be in the door knocker's mouth. +How else are you going to knock on a door?" +# Knocker:6 ends here + + + +# Although we can interact with it, let’s not make it obvious that it is an object: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:7]] +@lock ring = view:tag(hidden_ring, mp) +# Knocker:7 ends here + + + +# And put the ring in the knocker’s mouth: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:8]] +@give ring to knocker +# Knocker:8 ends here + + + +# The description is dynamic from the Python code, so we don’t need this statement: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:9]] +@desc knocker = The brass face looks at you and winks. +# Knocker:9 ends here + + + +# In order for us to /knock/ on the door, we have to give a =knock= command to the /room/. + + +# [[file:../../../projects/mud.org::*Knocker][Knocker:10]] +@update here = typeclasses.rooms_weather.KnockableOutsideRoom +# Knocker:10 ends here + + + +# The python object has all the knowledge about knocking and whatnot, but we should have the descriptions here. First, what the knocker reads: + + +# [[file:../../../projects/mud.org::*Knocker][Knocker:11]] +@set here/knock_msg = "You grab the ring and knock firmly on the door." +# Knocker:11 ends here + + + +# Then, what the other’s in the room read: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:12]] +@set here/knock_other_msg = "grabs the ring and knocks firmly on the door." +# Knocker:12 ends here + + + +# And an error message if the ring is not with the goblin: + +# [[file:../../../projects/mud.org::*Knocker][Knocker:13]] +@set here/knock_err_msg = "This door knocker is defective, as it +doesn't have a ring to...er, do the knockin'." +# Knocker:13 ends here + +# [[file:../../../projects/mud.org::*Cozy Tea House][Cozy Tea House:1]] +@dig house = red door;door;house;inside,outside;leave +# Cozy Tea House:1 ends here + + +# The door description should match the artwork on the website: + +# [[file:../../../projects/mud.org::*Red Door][Red Door:1]] +@desc red door = A painted red door where the round top of the door + fits snugly in the bark of the tree. Along with a large brass + doorknob, the door sports the most curious door knocker in the shape + of a goblin's face. +# Red Door:1 ends here + + + +# This exit should be special. First, it is locked unless a character has the =open_red_door= tag. + +# [[file:../../../projects/mud.org::*Red Door][Red Door:2]] +@lock door = traverse:tag(open_red_door, mp) +# Red Door:2 ends here + + +# Needs a message why one can’t walk through: + +# [[file:../../../projects/mud.org::*Red Door][Red Door:3]] +@set door/err_traverse = "The door seems locked." +# Red Door:3 ends here + + + +# If you do figure out how to get through the door: + +# [[file:../../../projects/mud.org::*Red Door][Red Door:4]] +@set door/traverse_msg = "You stoop as you step through the doorway..." +# Red Door:4 ends here + + + +# Fix the inside of the “House”: + +# [[file:../../../projects/mud.org::*Inside][Inside:1]] +@teleport red door +# Inside:1 ends here + + +# Add the Python /special-ness/ for [[file:~/src/moss-n-puddles/typeclasses/rooms.py::class DabblersRoom(Room):][this room]]: + +# [[file:../../../projects/mud.org::*Inside][Inside:2]] +@update here = typeclasses.rooms.DabblersRoom +# Inside:2 ends here + + +# Give it a title: + +# [[file:../../../projects/mud.org::*Inside][Inside:3]] +@name here = Dabbler's House;mp03 +# Inside:3 ends here + + +# Might as well stay a while: + +# [[file:../../../projects/mud.org::*Inside][Inside:4]] +@sethome here +# Inside:4 ends here + + + +# And the best description ever: + +# [[file:../../../projects/mud.org::*Inside][Inside:5]] +@desc here = An enormous stone hearth overshadows this round room with + dark paneling. A subtle smell of tea and incense. Large, overstuffed + chairs sit invitingly by the fireplace. Oddly angled shelves with + books and knickknackery adorn the walls while a trolley supports a + large kettle, cups and scones. +# Inside:5 ends here + + + +# Since we want the description to include the state of the fire, we need some /parts/ to assemble. Still not sure how this should be done. + + +# [[file:../../../projects/mud.org::*Inside][Inside:6]] +@set here/initial_desc = "You found a cozy, cornerless room." + +# Ravenous State +@set here/fire_out = "The room is dim, but you see large, overstuffed chairs placed + by a dark fireplace in a large stone hearth. Perhaps you could light a fire?" + +# Hungry State +@set here/fire_dim = "Large, overstuffed chairs sit invitingly close to the + dimly glowing embers in the fireplace of a stone hearth." + +# Fed State +@set here/fire_on = "Large, overstuffed chairs sit invitingly by a fire casting + shadows that dance on the dark paneling." + +# Full State +@set here/fire_full = "Large, overstuffed chairs slightly shield you + from the bright light of the roaring fire in the fireplace of a stone hearth." + +# And a final description: +@set here/final_desc = "Oddly angled shelves with books and + knickknackery adorn the walls around a tapestry. The subtle smell of + wood smoke, incense and tea leads you to a trolley supporting a large + teapot, cups and freshly baked scones." +# Inside:6 ends here + + + +# Granted, none of the dynamic description will work until we create the [[Fire]]. + +# Let’s come up with a lot of descriptions: + +# [[file:../../../projects/mud.org::*Inside][Inside:7]] +@detail tapestry = The muted colors of the tapestry either show its + age or its location over the sometimes smokey hearth. It shows a + gallant stag surrounded by woodland creatures. A racoon holds aloft a + gold box while a wolf has a gnarled staff. A raven perched on the + stag's antlers grips a blue ball in its beak. +# Inside:7 ends here + + + +# We should describe all the objects in the tapestry, eh? + +# [[file:../../../projects/mud.org::*Inside][Inside:8]] +@detail raven = The raven winks at you, and says, “Nevermore.” Really? + It probably didn't. Your eyes must be playing trickster. +# Inside:8 ends here + + + +# And the other animals: + +# [[file:../../../projects/mud.org::*Inside][Inside:9]] +@detail wolf = The gnarled staff the wolf holds looks a lot like the staff the gnome, Dabbler, has. +# +@detail stag = A majestic looking deer with gold fur and antlers that look more like tree branches. +# +@detail raccoon = The box he's holding seems to be a distraction, for he's pocketing a gold coin with his other paw. +# Inside:9 ends here + + + +# Will this staff get confused at some point? + +# [[file:../../../projects/mud.org::*Inside][Inside:10]] +@detail staff = A gnarled staff made of oak has a dark petina from age. Three small leaves has sprouted from the side. +# Inside:10 ends here + + + +# Touch up the exit: + +# [[file:../../../projects/mud.org::*Inside][Inside:11]] +@desc leave = A wood door with a large brass knob leads to the outside. +# +@set leave/traverse_msg = "You open the door and step outside..." +# Inside:11 ends here + + +# And a fire in the fireplace is a type of /pet/, since we can feed it: + +# [[file:../../../projects/mud.org::*Fireplace][Fireplace:1]] +@create/drop fireplace : typeclasses.pets.Fire +# Fireplace:1 ends here + + +# How about some aliases: + +# [[file:../../../projects/mud.org::*Fireplace][Fireplace:2]] +@name fireplace = fireplace;fire;embers +# Fireplace:2 ends here + + +# And a description that will be overridden: + +# [[file:../../../projects/mud.org::*Fireplace][Fireplace:3]] +@desc fireplace = A stone fireplace with a carved wooden mantel supporting + small pictures, some books and a black statue. +# Fireplace:3 ends here + + +# Since we mentioned some details, we better mention them: + +# [[file:../../../projects/mud.org::*Fireplace][Fireplace:4]] +@detail pictures = Two small framed pictures perch above the fireplace + mantle. One is of a satyr playing a saxophone, and the other is of a + fish with a big smile. +# Fireplace:4 ends here + + + +# This reference in this detail is obviously, only for me: + +# [[file:../../../projects/mud.org::*Fireplace][Fireplace:5]] +@detail statue = A small, black statue of a salamander curled around a + book, engraved with a title, "Seeing Stones". +# Fireplace:5 ends here + + + +# I imagine a giant picture over the fireplace … need to do something interesting with it. + +# [[file:../../../projects/mud.org::*Fireplace][Fireplace:6]] +@detail picture = Above the fireplace is a large, somewhat abstract + painting stretching its arm-like branches with shadowing that looks + like a yawn. +# Fireplace:6 ends here + + +# What sort of non-books do we want to look at? + +# In the meantime, let’s just have some descriptions: + + +# [[file:../../../projects/mud.org::*Knickknacks][Knickknacks:1]] +@detail knickknacks;things;knick-knacks;doodads;stuff;crap = An odd + assortment of knickknacks and doodads that decorate the minimal + space between the askewed books on the skewampus shelves. +# Knickknacks:1 ends here + + + +# We mentioned shelves of books: + +# [[file:../../../projects/mud.org::*Books][Books:1]] +@detail shelves;bookshelf;bookshelves = Shelves at various angles + embellish the walls of this small, cozy room. Leatherbound books + weigh each shelf, while some stacks of books support other shelves. + Dabbler has decorated some shelves with odd trinkets. +# Books:1 ends here + + + +# This should be an object of “books”, but looking should pull up a random list of books. + +# [[file:../../../projects/mud.org::*Books][Books:2]] +@create/drop books:typeclasses.readables.Books +# Books:2 ends here + + +# I start with the name, =books=, but when we look in the room, I want to see /collection/: + +# [[file:../../../projects/mud.org::*Books][Books:3]] +@name books = collection of books;books +# Books:3 ends here + + + +# With a good description: + +# [[file:../../../projects/mud.org::*Books][Books:4]] +@desc books = Books of different sizes and colors. So many books. + Perhaps you want to simply |blook|n at a |bbook|n at random? +# Books:4 ends here + + +# We mentioned a /trolley/ with tea, cups and scones: + +# [[file:../../../projects/mud.org::*Tea Service][Tea Service:1]] +@detail trolley = A tea trolley, complete with a small collection of + teacups, a magical teapot, as well as an assortment of scones and pastries. +# Tea Service:1 ends here + + + +# The “room” gives the teacups, and the “teapot” fills the cups, so we just need descriptions: + +# [[file:../../../projects/mud.org::*Tea Service][Tea Service:2]] +@detail teacups = An odd, yet interesting assortment of teacups. Take one. +# +@detail teacup = Each cup is unique. Take one to look further. +# Tea Service:2 ends here + + + +# A [[file:~/src/moss-n-puddles/typeclasses/drinkables.py::class Teapot(Object):][teapot]] will contain a type of tea … either given or randomly chosen. +# A teapot will “fill” a teacup forever, until it is “remade”. + + +# [[file:../../../projects/mud.org::*Tea Service][Tea Service:3]] +@create/drop teapot;pot;tea pot:typeclasses.drinkables.Teapot +# +@desc teapot = An adorable brown teapot, waiting for you to |bmake|n some tea. +# Tea Service:3 ends here + + +# And of course, you can’t steal the tea pot: + +# [[file:../../../projects/mud.org::*Tea Service][Tea Service:4]] +@lock teapot = get:false() +# +@set teapot/get_err_msg = "You don't need to carry it around to make tea." +# Tea Service:4 ends here + + +# And [[file:~/src/moss-n-puddles/typeclasses/sittables.py::class Sittables(Sittable):][the chairs]] is a /plural/ location to sit, allowing anyone to sit down. + + +# [[file:../../../projects/mud.org::*Chairs][Chairs:1]] +@create/drop chairs:typeclasses.sittables.Sittables +# Chairs:1 ends here + + +# Add aliases afterwards: + +# [[file:../../../projects/mud.org::*Chairs][Chairs:2]] +@name chairs = few overstuffed chairs;overstuffed chairs;chairs;chair +# Chairs:2 ends here + + +# And the description: + +# [[file:../../../projects/mud.org::*Chairs][Chairs:3]] +@desc chairs = A few, dark leather, overstuffed chairs, each with a soft, colorful blanket and pillow. An invitation for a cozy nap. +# Chairs:3 ends here + + + +# Can’t steal ‘em: + +# [[file:../../../projects/mud.org::*Chairs][Chairs:4]] +@lock chairs = get:false() +# +@set chairs/get_err_msg = "It's way too heavy for you to lift." +# Chairs:4 ends here + + + +# And textual descriptions the object can use: + +# [[file:../../../projects/mud.org::*Chairs][Chairs:5]] +@set chairs/adjective = "in" +# +@set chairs/article = "the" +# +@set chairs/singular = "an overstuffed chair" +# +@set chairs/extra = "This feels [|very|quite] [nice|cozy|comfortable].|n" +# Chairs:5 ends here