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