Re: dig/bury

From: Daniel A. Koepke (dkoepke@circlemud.org)
Date: 04/02/01


On Mon, 2 Apr 2001, Edward Felch wrote:

> I noticed an odd bug in digging/searching up buried items recently, it
> seems to search the entire world for buried items and uncovers them,
> can anybody help me with where the loop or whatnot is going wrong?

Note that for() loops exist entirely for the purpose of making code like
what you have readable and maintainable.  So we translate it to:

  for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj->next) {
    .
    .
    .
  }

now we can see the initialization, the iteration, and the exit condition
all in one place.  As someone else pointed out, we really want to use
obj->next_content to iterate over the list, since obj->next is the next
object in the global object list.  So we change that:

  for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj->next_content) {
    .
    .
    .
  }

We try this and see we get weird behavior.  This is because the body of
the loop has a side-effect that changes obj (or one its members).  Looking
into it a bit, we observe that when we do obj_to_char(), the object is
added to the head of the character's inventory and that the next_content
pointer is changed to reflect this insertion in the new list.  So we need
to keep the old next_content pointer just in case we change the one on
obj by calling obj_to_char().  Hence:

  for (obj = world[IN_ROOM(ch)].contents; obj; obj = obj_next) {
    obj_next = obj->next_content;
    .
    .
    .
  }

So good so far.  But now we have a few other weird things:

>           GET_OBJ_WEAR(obj) += ITEM_WEAR_TAKE;

What's this supposed to be doing?  Why are you adding ITEM_WEAR_TAKE (the
number 1) to GET_OBJ_WEAR(obj)?  First, GET_OBJ_WEAR(obj) refers to a
bitvector and ITEM_WEAR_TAKE is 1 (1 << 0 == 1, obviously).  So adding 1
to GET_OBJ_WEAR(obj) is not what we want: if the object already has the
ITEM_WEAR_TAKE flag set, this has the effect of removing it and setting
another wear flag (which depends upon what's already there); if it
doesn't, then we set ITEM_WEAR_TAKE.  This is not what you want to do.  If
you really want to make the object takeable, you want:

  SET_BIT(GET_OBJ_WEAR(obj), ITEM_WEAR_TAKE);

Second, and perhaps more important, why are we doing that?  Can people
bury objects that aren't takeable?  If they can, we probably don't want to
make them takeable when they're dug up, and if they can't, we don't need
to bother changing the object's wear flags, anyway, because we're
guaranteed that it's a takeable object.  A few demonstration cases, given:

  A large fountain carved from blue-streaked marble is here, bubbling
  merilly.

then if we can bury an object that isn't takeable and  dig makes it
takeable, putting it in our inventory:

  > bury fountain
  You bury the large fountain.
  > dig fountain
  You found a the large fountain buried here.
  > inv
  You are carrying:
  the large fountain
  > drop fount
  You drop the large fountain.
  > get fount
  You get the large fountain.

This is clearly not what we want.  One alternative is that we can bury an
object that isn't takeable and dig observes the take flag, rather than
changing it:

  > bury fountain
  You bury the large fountain.
  > dig fountain
  You found a the large fountain buried here.
  > inv
  You are carrying:
   Nothing.
  > get fount
  the large fountain: you can't take that!

We could also just make it impossible to bury an object that isn't
takeable, which seems fairly sensible:

  > bury fountain
  No.

There are a few other problems.  Note how in the messages it shows things
like, "You found a the large fountain buried here."  This is because
you're doing:

  act("You found $a $p buried here.", ...);

The $p act code prints the short description, which usually has an article
prepended to it.  So you get messages that don't make sense.  The code
probably should not decide for itself if an article belongs there.  What
if you have an item where you don't want an article to be prepended?  For
instance, you have an axe named Bladesinger's Axe.  It's the only one of
its kind.  Why should we have, "You get a Bladesinger's Axe," then?

More serious: you don't add to the person's carrying weight or check if
they can pick something up.  So we can do:

  > get axe
  Bladesinger's Axe: you can't carry that many items.
  > bury axe
  You bury Bladesinger's Axe.
  > dig axe
  You found a Bladesinger's Axe buried here.
  > inv
  You are carrying:
  Bladesinger's Axe
  .
  .
  .

Oops!  Also, what if someone buries a cursed item at The Temple of
Midgaard and some newbie comes along and digs?  Now they've wound up with
a cursed item.  It'd be worse for more experienced players, whose
characters very well would have known that the item was cursed and that
they wouldn't want to pick it up... yet by digging, they automatically did
it.  Eck.

It'd probably be better to fix the majority of these problems by simply
not making dig pick up the items.  Just make it remove the bury flag.


(PLEASE[!] read the mailing list FAQ for appropriate subject flags.
No-one uses them, but people should start as part of common courtesy.  It
is much easier for people to filter for threads they want to be involved
in IF YOU PROVIDE A PROPER SUBJECT.)

-dak

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/05/01 PST