Clarification on item timer

From: Jeff (jfink@csugrad.cs.vt.edu)
Date: 06/15/94


I've gotten some questions about my comments on the "timers" on objects,
and looking through the code, I found that my reply was somewhat incorrect.
Standard Diku does not support items crumbling as I had said, but it does
in fact support AFF_ bits set on items.  At any rate, I've pulled out my
code that does support timers on items, and included instructions for
installing it.  I can't be positive that the lines that I tell you to
look for are correct, since my copies of Circle have been mangled pretty
bad, and I don't have the patience to get a new copy at 1200 baud.  The
new code below was pulled from my copy of Circle 2.01, and should work
fine with 2.2, and probably 3.0.  I think the instructions below are pretty
easy to follow, but if anyone has any questions, feel free to send them my way.


Step 1:  Go into db.c and look for the following lines in load_objects():

         for (; (j < MAX_OBJ_AFFECT); j++) {
            obj_proto[i].affected[j].location = APPLY_NONE;
            obj_proto[i].affected[j].modifier = 0;
         }

After these, add:

	 if (*chk == 'F') {
	    fscanf(obj_f, " %d %d \n", &tmp, &tmp2);
	    obj_proto[i].obj_flags.bitvector = tmp;
	    obj_proto[i].obj_flags.timer = tmp2;
	    fscanf(obj_f, " %s \n", chk);
	 }

At this point, you can add flag lines to your object files by going
to the very end of the object (after the Affected values if you
have them) and adding a single line of the form:
F <bitvector> <timer>

The bitvector corresponds to the AFF_ values in structs.h, and whenever
this item is worn, these AFF_ bits will be set.  At this point, the timer
does not work yet.  To get it to work:


Step 2: Go into handler.c and look for void update_object().  Delete
update_object() and replace it with the following code:


void crumble_obj(struct char_data *ch, struct obj_data *obj)
{
   struct obj_data *loop;
   int index;

   if (obj->in_room != NOWHERE) {               /* In a room */
      if (world[obj->in_room].people) {
         act("A quivering horde of maggots consumes $p.",
           TRUE, world[obj->in_room].people, obj, 0, TO_ROOM);
         act("A quivering horde of maggots consumes $p.",
           TRUE, world[obj->in_room].people, obj, 0, TO_CHAR);
         for(loop = obj->contains; loop; loop = obj->contains) {
            obj_from_obj(loop);
            obj_to_room(loop, obj->in_room);
         }
      }
   } else if (!obj->in_obj) {                   /* Worn or inventory */
      act("$p decays in your hands.", FALSE, ch, obj, 0, TO_CHAR);
      for(loop = obj->contains; loop; loop = obj->contains) {
         obj_from_obj(loop);
         obj_to_char(loop, ch);
      }
      if (!obj->carried_by)
         for(index = 0; index < MAX_EQUIP; index++)
            if (ch->equipment[index] == obj)
               obj = unequip_char(ch, index);
   } else                                       /* In an object */
      for(loop = obj->contains; loop; loop = obj->contains) {
         obj_from_obj(loop);
         obj_to_obj(loop, obj->in_obj);
      }
   extract_obj(obj);
}


void    update_object(struct char_data *ch, struct obj_data *obj, int use)
{

   if (obj->next_content)
      update_object(ch, obj->next_content, use);
   if (obj->contains)
      update_object(ch, obj->contains, use);
   if (obj->obj_flags.timer > 0)
      if ((obj->obj_flags.timer -= use) < 1)
         crumble_obj(ch, obj);
}


Step 3:  Go down to update_char_objects() (in the same file) and modify
the calls to update_object() so that they look like 
update_object(ch, ch->equipment[i], 2) and update_object(ch, ch->carrying, 1).


Step 4:  Go into limits.c and look for void point_update().  There's a
set of code that looks like:

      if (!IS_NPC(i)) {
         update_char_objects(i);
         if (GET_LEVEL(i) < LEVEL_GOD)
            check_idling(i);
      }

Change the ifs to match the ones below:

      if (!IS_NPC(i) || IS_AFFECTED(i, AFF_CHARM)) {
         update_char_objects(i);
         if (!IS_NPC(i) && (GET_LEVEL(i) < LEVEL_GOD))
            check_idling(i);
      }


Step 5: Further down in point update there's a loop that starts with
for(j = object_list; j; j = next_thing) {.  Delete everything between
this for() statement and it's closing bracket, and insert this as the
loop contents:

      next_thing = j->next; /* Next in object list */

      if (j->in_room == NOWHERE)
         continue;

      if ((GET_ITEM_TYPE(j) != ITEM_CONTAINER) || (!j->obj_flags.value[3]))
         continue;

      if (j->obj_flags.timer > 0)
         if (!(--j->obj_flags.timer))
            crumble_obj(0, j);


And there you go.  If the timer is set > 0 in the object file, the objects
will deteriorate by 1 if in a PC's inventory (or in a PCs bag), and by 2 if
equipped.  Since I have experience with running a MUD with this code, I think
I ought to give a warning:  Objects with any of the AFF_ bits can be extremely
powerful and should be quite rare.  The example I used of of an AFF_INVISIBLE
object will dramatically change the style of game, because players will almost
always be running around invisible to avoid mobs or PKs.  Of course, you could
set a timer on the object and hope it crumbles as they walk in on the
dracolich.  ;-)


-Jeff



This archive was generated by hypermail 2b30 : 12/07/00 PST