Re: Wilderness

From: Daniel A. Koepke (dkoepke@california.com)
Date: 01/01/00


On Sat, 1 Jan 2000, Warren Robbins wrote:

> I suppose my question is:  How else do people recommend trimming
> memory usage for an overworld (approx. 300x200 rooms)?  The area is
> composed (ATM) of stock room_data structure types.

Why allocate all of them when most of them aren't used?  Since the
wilderness is mostly arbitrary, allocate only space for rooms that have
players and important items/mobiles in them (not the typical squirrels,
branches, etc.).  When a player enters a room, allocate the space for it,
set a timer on it for it to expire (that starts counting when there are no
players or important items/mobiles in it), and do a bit of a random check
to drop some items in the room -- leaves, oversized magical acorns,
squirrels, what have you.  These items are mostly arbitrarily located
within the wilderness, so the Mud need not actually keep track of their
actual locations.  The timer ensures that a player going 'w' and then 'e'
doesn't wind up in a room with different objects in it.  Of course, if he
goes 'w', waits for 5 minutes, and goes 'e' the objects will be different,
but 5 minutes in real life is quite a spell in Mud time, so that's fairly
easy to explain away.  For commands like 'scan' you can either allocate
the rooms then and there, or report that they don't see much of anything
and on room allocation have any mobiles dropped into the room report their
arrival "from out of the bushes" or what have you.  Links into (and out
of) the wilderness will have to be done in a special manner.

Even better, since the wilderness will be optimally kept separate from the
world[] array, you can use a different type for them.  forest_room_data or
what have you.  Since we're using a 300x200 map (which is really not that
large a wilderness -- only 60000 rooms worth) and each room within that
map is placed relative to another room, the traditional exits structure is
superfluous.  Instead, we might want something like,

    struct forest_room_data
    {
        ush_int x;
        ush_int y;
        ubyte exitFlags;
        struct room_data *outLink;
    };

    #define FRD_EX_NO_NORTH     0x01 /* (1 << 0) */
    #define FRD_EX_NO_EAST      0x02
    #define FRD_EX_NO_SOUTH     0x04
    #define FRD_EX_NO_WEST      0x08
    #define FRD_EX_NORTH_OUT    0x10
    #define FRD_EX_EAST_OUT     0x20
    #define FRD_EX_SOUTH_OUT    0x40
    #define FRD_EX_WEST_OUT     0x80 /* (1 << 7) */

The frd->outLink variable is used for any exit that has the _OUT flag set
on it.  Note that we don't keep separate bitvectors for each exit --
there's only two flags we can set for each one: NO_ or _OUT.  If an exit
has NO_ set on it, you can't exit in that direction.  If an exit has _OUT
set on it, then the exit, instead of taking you to the adjacent room, it
takes you to the room specified by frd->outLink.  It doesn't make sense
for several exits within the same room to have _OUT set on them, since
there's only one outLink.  This is a bit of a restriction, but as you
notice, the entire structure is only 9 bytes[1] (2 bytes for each of the
16 bit integers X/Y; 1 byte for exitFlags; 4 bytes for the pointer).  We
don't maintain pointers to descriptions or room names -- we figure we
won't actually need them for the wilderness (especially if using an ASCII
overhead map).

Next we need to add the necessary 'people', 'contents', etc., lists to the
forest_room_data structure, or provide a link to an instantiated room_data
object.  The latter method is easier, since you'll end up with being able
to get by with char_from_room() and char_to_room() without change and
minor modifications to the movement functions.  The same will go for
ANYTHING that uses ch->in_room.  This is all fairly trivial, which isn't
to say it's not time consuming.  There might be better ways.

After we go through and correct all of this stuff, we'll need to add the
timer logic.  This is just a single byte that is decremented each
PULSE_WILDERNESS, which might occur every minute, and just involves
quickly going through the wilderness_map, looking for instantiated rooms,
and doing some stuff with those that are allocated.

Our complete forest_room_data structure might look like,

    struct forest_room_data {
        ush_int x;
        ush_int y;
        ubyte exitFlags;
        struct room_data *outLink;
        struct room_data *roomInstance;
        ubyte timer;
        ubyte nonWildernessEntity;
    };

or,

    struct forest_room_data {
        ush_int x;
        ush_int y;
        ubyte exitFlags;
        struct room_data *outLink;
        struct char_data *people;
        struct obj_data *contents;
        ubyte timer;
        ubyte nonWildernessEntity;
    };

The 'nonWildernessEntity' byte is used to count how many entities (meaning
objects or mobiles) that are not considered arbitrary (and, thus, may be
entirely extracted when the room expires) are located in the room.  When a
non-wilderness entity is sent to the room (with, say, obj_to_wilderness()
or char_to_wilderness()), the nonWildernessEntity counter is incremented.
When one is removed (with [obj|char]_from_wilderness()), we decrement
it.  When it hits zero, the counter is set to, say, 5, and the wilderness
update loop recognizes sees that it can decrement the timer.

Shrug.  There's lots more to it, most likely, but I'm too tired to think.

-dak


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     |  http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html  |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 04/10/01 PDT