[Nathan Y:]
:Not sure what you mean by "input lines". Does this mean runtime determined
:variables in text form? This actually sounds frighteningly close to my
:virtual and real functions/classes. The difference, of course, being that
:as much as possible of my code is real, and soft becomes real in a short
:order of time.
Input line is a command line from a player. Basically, one of the
required attributes (set with a builtin function) of any player structure
is the MUD function to call to handle each input line from the player.
The function is passed a string built from the input line. The current
one I use checks for special stuff like a leading ", a leading :, and
for aliases. It then uses the native-code builtin function 'Parse' to
handle the remaining input based on a "grammar" passed to Parse along
with the string. According to the grammar and the string, Parse will
call out to MUD functions to handle the cases they are registered for.
:Interesting. Quite interesting. So CreateBoolProp()$ creates a boolean
:property... um... which seems to be applied to every object in existance?
Well, it can be applied to every property in existance, in that I don't
prevent you looking it up (or adding it) to whatever object you can lay
your hands on. Just creating the property does nothing besides building
one small database entry to represent it. That gives it a unique ID,
which is used for it in property lists on things. My modularity comes
from the fact that your MUD code can only use properties that it can
name. You can name a property if some symbol table that it is in is
currently "in-use". Symbol tables can be freely created and manipulated.
In the previous example, I avoided them by using 'public' which refers
to the single global table always "in-use" by everyone. There is also
'private', which refers to the per-character symbol table. E.g.
private newtable CreateTable()$
/* symbol 'newtable' is added to the player's private table,
with a newly created empty table as its value. */
use newtable
/* add 'newtable' to the current 'in-use' set for this player. */
define newtable contents CreateThingListProp()$
/* symbol 'contents' is added to 'newtable', with value a
property that can point to arrays/lists of 'things'. */
describe contents$
/* will describe the so-far-unused property 'contents' */
unuse newtable
describe contents$
/* will likely complain that 'contents' is an undefined symbol. */
:What if you have a property list that goes into the thousands? Erm. Hmm.
Very unlikely. The current implementation actually limits you to 255
properties on any 'thing'. My current scenario hasn't come anywhere
near hitting that limit. If it becomes a problem, the workaround is
to attach a new 'thing' as a property on the main 'thing', and add
another bunch of properties to it. Remember, the only properties on a
'thing' are those that have been explicitly set on it; any that it
inherits from ancestors, and doesn't override, don't count, since they
are retrieved directly from that ancestor, by following the ancestor
pointer and repeating the property search. There are several hundred
properties in my current scenario, but a good many of them are only
used on special 'things'. E.g. at a bank, the list of accounts is a list
of 'things', each of which has a property pointing to the owner of the
account, and a property containing the current balance. Those 'things',
and the MUD code for banks, are the only places that those two properties
are ever used. You can call an exported routine to setup a bank in your
own room, and it will work fine, without you ever being able to see
the names of those two properties. You will know that one property (the
account list) has been added to your room, but you won't be able to
tell anything about it unless you are able to 'use' the table in which
it and the rest of the bank symbols are defined.
:Still... an interesting system. I guess I should post up my method of
:dealing with properties. For the above, I have... well... OK, near as can
:get to what you have...
:
:class gender inherits BoolProperty{
:@ functions
: bool male(){ return property; }
: bool female(){ return !property; }
: String sex(){ property ? (return "male";) : (return "female";); }
:@ data
: bool property;
:}
:
:class banana{
: gender bananaSex(); // default const while data member exists with same
: // name... cannot define as non const.
: void setSex(); // toggle gender
:@ data
: gender bananasex = false;
:}
:
:banana.bananasex().male(); // yields false
:banana.setSex();
:banana.bananasex().male(); // yields true
:
:And the rest requires an explicit modification to the banana class. Of
:course, the modification could be made in the Virtual class, which all
:virtual objects inherit, or in the hardcoded Physical, Location, Doorway,
:or Universal classes... but that requires a recompile. The idea is,
:anything fundamental to the entire universe _should_ require a recompile,
:in my formula, because otherwise a) it introduces a violation of
:encapsulation that can be made by anyone, and b) it usually indicates
:improper design, under my paradigm.
I think I followed the example. The key difference, of course, is that
since your world is essentially 'compile-time', you have to reserve
space on anything that can have a sex, for the sex variable. I only need
the space (8 bytes, actually) for 'thing's that require a male sex,
which is a very small proportion of the 'thing's in the universe. (This
is turning out to be a somewhat off-colour example! :-) )
Your system has the potential for a lot of native-code running, which was
your goal. I wanted to be able to do *anything* at run time, but still
have reasonable efficiency. Ignoring any ancestors, if a 'thing' has
20 explicit properties, lookup of a property on it will take on average
10 trips around a while loop. Mind you, its only half a dozen instructions
each time around, so order 60 instructions for the lookup. The only
'things' that get that many properties are players, fancy rooms, and
fancy NPC's.
::This sounds interesting. Can we see a bit more detail here?
:OK, once we have the bucket, a standard, no frills Item, we add a spell to
:it. Say the spell is to a particular stone. Say it is a permanent spell,
:for simplicity, and that it is in place at startup.
:
:So, first we attatch the spell to the bucket, with a trigger to transmit
:weight changes. We have a call to create (or choose) a stone when the
:bucket is created.
:
:#ITEMS
:
:> bucket{
:N bucket~
:// . . . all the other stuff . . .
:P MassSpell(mass()) <void massUpdate()>
:I stone
:}
:
:#PROGRAMS
:
:void bucket:MassSpell(int newMass){
: stone.SetState(mass, newMass);
:};
:
:>From this, there is a series of messages passed, that ultimately reaches
:the tree. This last impulse schedules an immediate event for the tree to
:fall down.
Er, actually I meant Chris L's Crystal Tree example, where Bubba is
holding some helium-filled balloons while standing on a branch of the
crystal tree. He lets go of a balloon, which makes his weight now big
enough to break the branch and drop him down.
Thinking more...
The balloon influences weight, so it is reasonable for it to tell the
holder (Bubba) about a weight change. In your system, would Bubba
automatically transmit information ("impulse"?) about that weight
change to whatever Bubba is standing on, without code in Bubba to
explicitly do that? That way it goes from something concerned about
weight, through to something else concerned about weight, passing
through a third something that has never heard of weight. But then,
how is the impulse limited? It is passed through Bubba to everything
even remotely connected to him, such as everything he is carrying (one
of which might be an anti-gravity belt set on hover)?
Sorry if I'm being dense here!
--
Chris Gray cg@ami-cg.GraySage.Edmonton.AB.CA