[LONG] [Spec-Proc] was Re: Im a newbie, plz help

From: Alvoria MUD (mudguy@conan.ids.net)
Date: 12/26/96


On Mon, 23 Dec 1996, Daniel Durnin wrote:
> 2> A mob that stops players from going any exits other than the one they
> came from unless the mob gets a certain item from the PC.

Hee hee... this one wasn't so easy as I thought it would be... here is the
spec proc for everyone... I believe it works with 0 problems now... sortof.

Here is a list of quirks about the proc... so be warned...

1. Giving an obj to one mob will result in all mobs of the same vnum
allowing the char to pass in the directions defined... but this proc
is made with the idea that every mob that has this will be the only
one of it's own vnum within the world.

2. The timer stuff is put in because if a mob remembers a char giving it
an obj and then dies without the char actually triggering it to let it
go and thus forget about receiving the obj will result in the memory
set aside for remembering it never to be freed. Also, this prevents
players from giving hundreds of objs to mobs with this spec and eating
up gobs of memory :P.

3. You will have to edit this if you don't want the mob to say things
when the player attempts to walk by without giving it the right obj.

4. This proc doesn't recognize giving multiple items in order to let a
player by. You could simulate this by putting several mobs with different
vnums in the room and putting duplicate entries for those mobs... etc..

5. This proc doesn't recognize mobs giving it items. But it does let
mobs go by freely.

6. It's relatively easy to change this so that a player has to give an obj
to one mob, and then run somewhere else before the timer runs out to be
let by another mob. In fact, if both mobs are alike then it will work if
one mob doesn't have the exits defined in it's room (the one receving the
item).

7. To make some of the coding easier on my part... I made it so that
the mob junks all the items previously in it's inventory every time
it receives a new obj so it doesn't relist the old objs again.

--

#define BTV_NORTH  (1 << 0)
#define BTV_EAST   (1 << 1)
#define BTV_SOUTH  (1 << 2)
#define BTV_WEST   (1 << 3)
#define BTV_UP     (1 << 4)
#define BTV_DOWN   (1 << 5)

#define NUM_OBJ_SENTINELS (1)

struct obj_given_data {
  long whom;
  int where;     /* what room the obj was given in */
  int vnum;      /* vnum of the obj. Do NOT try and use rnums */
  int self_vnum; /* so you can assign this to several mobs,
                    without having attach this to every char  */
  int timer;     /* so players can't tie up memory by giving the mob
                    a zillion items and never walking thru an exit,
                    the timer will keep ticking and eventually forget
                    that a player ever gave the mob anything in the
                    first place */
  struct obj_given_data *next;
};

struct obj_sentinel_recog {
  int vnum;
  int self_vnum;
  int direction;
  char *can_pass; /* What is said if the char can go */
  char *cannot_pass; /* what is said if the char cannot go */
};

struct obj_sentinel_recog osn_list[(NUM_OBJ_SENTINELS-1)] = {

  /* Do yourself a favor and don't leave this entry of info in. I used
     the stock receptionist to test this proc */

  { 10, 3005,
   (BTV_DOWN | BTV_NORTH),
   "You may pass.",
   "Give me a waybread first and you may pass."
   }
};


SPECIAL(obj_sentinel)
{
  ACMD(do_give);
  ACMD(do_say);
  int can_go=FALSE, i, which_sent=NULL, freed=FALSE;
  struct char_data *self;
  struct obj_data *tmp1,*tmp2;
  struct obj_given_data *new_info, *tmp3, *tmp4, *temp;
  char loc_buf[250];

  static struct obj_given_data *obj_give_master;

  self=(struct char_data *) me;

  if(CMD_IS("give"))
    {
      /* first clean out my inv. so the objs given to me are all from
         the same char */
      if(self->carrying)
        {
          for(tmp1=self->carrying; tmp1; tmp1=tmp2)
            {
              tmp2=tmp1->next_content;
              extract_obj(tmp1); /* Obj_from_char is called from within it */
            }
        }
      do_give(ch,argument,cmd,0);

      if(GET_IDNUM(ch)==-1) /* Ignore if mobs give items.. too hard :P */
        return (1);

      if(self->carrying)
        {
          for(tmp1=self->carrying; tmp1; tmp1=tmp1->next_content)
            {
              CREATE(new_info, struct obj_given_data, 1);
              new_info->whom=GET_IDNUM(ch);
              new_info->where=self->in_room;
              new_info->vnum=GET_OBJ_VNUM(tmp1);
              new_info->self_vnum=GET_MOB_VNUM(self);
              new_info->timer=20;
              /*
                My PULSE_MOBILE is 8 sec, yours may be different. To
                figure out how much time this is in RL, multiply the value
                here times PULSE_MOBILE. For me, this would be 160 secs.
                You can also create some nifty effects with this. But that
                is for you to add to this.
                  - mendar
              */
              new_info->next=obj_give_master;
              obj_give_master=new_info;
            }
        }
      return (1);
    }

  if(IS_MOVE(cmd))
    {
      if(IS_NPC(ch))
        {
          return (1); /* let the other mobs go */
        }

      for(tmp3=obj_give_master; tmp3 && (!can_go) ; tmp3=tmp3->next)
        {
          if(((tmp3->whom)==GET_IDNUM(ch))&&
             ((tmp3->self_vnum)==GET_MOB_VNUM(self)))
            {
              for(i=0; (i<NUM_OBJ_SENTINELS) && (!can_go) ; i++)
                {
                  if(osn_list[i].self_vnum==tmp3->self_vnum)
                    {
                      if((tmp3->vnum)==(osn_list[i].vnum))
                        {
                          if(((osn_list[i].direction)&(1 << (cmd-1)) ) > 0 )
                            {
                              can_go=TRUE;
                              which_sent=i;
                            }
                        }
                    }
                }
            }
        }

      if(can_go)
        {
          /* first, we remove one obj from the 'memory' of objs given */
          for(tmp3=obj_give_master; tmp3 && (!freed) ; tmp3=tmp4)
            {
              tmp4=tmp3->next;

              if((tmp3->vnum)==(osn_list[which_sent].vnum))
                {
                  REMOVE_FROM_LIST(tmp3,obj_give_master,next);
                  free(tmp3);
                  freed=TRUE;
                }
            }
          /* now we tell the player they may pass and let them go */
          do_say(self, osn_list[which_sent].can_pass, 0, 0);
          return (0);
        }
      else
        {
          /* now we tell the player they can't go :P */
          do_say(self, osn_list[which_sent].cannot_pass, 0, 0);
          act("$n blocks your way!", FALSE, self, 0, ch, TO_VICT);
          act("$n blocks $N's way!", FALSE, self, 0, ch, TO_NOTVICT);
          return (1);
        }
    }

    if(!FIGHTING(self))
      {
        for(tmp3=obj_give_master; tmp3 ; tmp3=tmp4)
          {
            tmp4=tmp3->next;

            if((tmp3->where)==(self->in_room))
              {
                tmp3->timer--;
                if(tmp3->timer<=0)
                  {
                    REMOVE_FROM_LIST(tmp3,obj_give_master,next);
                    free(tmp3);
                    freed=TRUE;
                  }
              }
          }
      
      }

  return FALSE;
}


--

Alvoria MUD -- "Hand it over, kiddo."
  Address   -- telnet://conan.ids.net:4000/
  Homepage  -- http://users.ids.net/~mudguy/
  Host Site -- http://www.ids.net/

+-----------------------------------------------------------+
| Ensure that you have read the CircleMUD Mailing List FAQ: |
|   http://cspo.queensu.ca/~fletcher/Circle/list_faq.html   |
+-----------------------------------------------------------+



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