sleep - a ROM snippet by Jason De Leon   10/13/02
------------------------------------------
This is a ROM hack of the popular SMAUG mpsleep
snippet written by Rasmus Brosboel.  It allows you to delay
a mobprog for a number of pulses without using the
delay command, thus making all life easier :)

Here's an example of usage in a mobprog:
say Greetings $n 
sleep 6 
say I have now paused for 6 pulses 
sleep 4 
say I have now paused for 4 pulses

This code has not been heavily tested and may contain bugs.
I can't see any :P, but if you find some or if you see any
way to improve this code, please send reports to miro@kyndig.com.

********************************************************************
* This snippet was written using the QuickMUD build of ROM. It may *
* require slight modifications for other versions.  I know for a   *
* fact that Rouge bases will require modifications.                *
********************************************************************

About using this file:
Any lines of code preceded with a + are going to be ADDed.
Any lines of code preceded with a - are going to be deleted.
Any lines of code that are not preceded by anything are just
there for reference.

================================================================================
================================================================================
Disclaimer:
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!
BACK UP YOUR CODE BEFORE INSTALLING!

I am not responsible for any loss of code due to this snippet.

================================================================================
================================================================================

                            merc.h
--------------------------------------------------------------------------------
( DID YOU BACK UP YOUR CODE YET?? )
FIND this line:

  typedef struct    pc_data          PC_DATA;

and ADD this after it:

+ typedef struct    sleep_data       SLEEP_DATA;

...

FIND this:

#define BAN_PERMIT     E
#define BAN_PERMANENT  F

struct    ban_data
{
    BAN_DATA *  next;
    bool        valid;
    sh_int      ban_flags;
    sh_int      level;
    char *      name;
};

and ADD this after it:

+ extern SLEEP_DATA *first_sleep;
+ /*
+  *  Sleeping prog data
+  */
+ struct sleep_data
+ {
+     SLEEP_DATA *next;
+     SLEEP_DATA *prev;
+     CHAR_DATA *ch;
+     CHAR_DATA *mob;
+     MPROG_CODE *prog;
+     int valid;
+     int vnum;
+     int line;
+     int timer;
+ };

...

FIND:

- /* mob_prog.c */
- void	program_flow	args( ( sh_int vnum, char *source, CHAR_DATA *mob,
- 				CHAR_DATA *ch, const void *arg1, const void *arg2 ) );

and REPLACE it with:

+ /* mob_prog.c */
+ void	program_flow	args( ( sh_int vnum, char *source, CHAR_DATA *mob,
+ 				CHAR_DATA *ch, const void *arg1,
+ 				const void *arg2, int numlines ) );
+
+ MPROG_CODE *get_mprog_by_vnum args( (int vnum) );


                            recycle.h
--------------------------------------------------------------------------------
just ADD theses two lines to the bottom:

+ void free_sleep_data(SLEEP_DATA *sd);
+ SLEEP_DATA *new_sleep_data(void);


                            recycle.c
--------------------------------------------------------------------------------
ADD theses two functions to the end of the file:


+ SLEEP_DATA *sd_free;
+
+ SLEEP_DATA *new_sleep_data(void)
+ {
+    SLEEP_DATA *sd;
+    if (sd_free == NULL)
+        sd = alloc_perm(sizeof(*sd));
+    else
+    {
+        sd = sd_free;
+        sd_free=sd_free->next;
+    }
+ 
+    sd->vnum             = 0;
+    sd->timer            = 0;
+    sd->line             = 0;
+    sd->prog             = NULL;
+    sd->mob              = NULL;
+    sd->ch               = NULL;
+    sd->next             = NULL;
+    sd->prev             = NULL;
+    VALIDATE(sd);
+    return sd;
+ }
+
+ void free_sleep_data(SLEEP_DATA *sd)
+ {
+    if (!IS_VALID(sd))
+       return;
+
+    INVALIDATE(sd);
+    sd->next = sd_free;
+    sd_free = sd;
+ }

                            update.c
-----------------------------------------------------------------------------------
ADD at the top:
+ #include "recycle.h"

just before update_handler(), ADD:

+ void sleep_update(void)
+ {
+     SLEEP_DATA *temp = first_sleep, *temp_next;
+     
+     for( ; temp != NULL; temp = temp_next)
+     {
+         bool delete = FALSE;
+         
+         temp_next = temp->next;
+         
+         /* checks to make sure the mob still exists*/
+         if(!temp->mob)
+             delete = TRUE;
+         /*checks to make sure the character is still in the same room as the mob*/
+         else if(temp->mob && temp->ch && temp->mob->in_room != temp->ch->in_room)
+            delete = TRUE;
+          if(delete)
+         {
+             /* some slick linked list manipulation */
+             if(temp->prev)
+                 temp->prev->next = temp->next;
+             if(temp->next)
+                 temp->next->prev = temp->prev;
+             if( temp == first_sleep && (temp->next == NULL || temp->prev == NULL) )
+                 first_sleep = temp->next;
+             free_sleep_data(temp);
+             continue;
+         }
+         
+         if(--temp->timer <= 0)
+         {
+             program_flow(temp->vnum, temp->prog->code, temp->mob, temp->ch, NULL, NULL, temp->line);
+             
+             /* more slick linked list manipulation */
+             if(temp->prev)
+                 temp->prev->next = temp->next;
+             if(temp->next)
+                 temp->next->prev = temp->prev;
+             if( temp == first_sleep && (temp->next == NULL || temp->prev == NULL) )
+                 first_sleep = temp->next;
+             free_sleep_data(temp);
+         }
+     }
+ }


___in update_handler()___
FIND:
     aggr_update ();

and ADD this right before it:
+    sleep_update ();


                            mob_cmds.c
-----------------------------------------------------------------------------------

___in void do_mpcall()___

FIND:
-     extern void program_flow(sh_int, char *, CHAR_DATA *, CHAR_DATA *, const void *, const void *);

and REPLACE it with:
+     extern void program_flow(sh_int, char *, CHAR_DATA *, CHAR_DATA *, const void *, const void *, int );

FIND:
-     program_flow( prg->vnum, prg->code, ch, vch, (void *)obj1, (void *)obj2 );

and REPLACE it with:
+     program_flow( prg->vnum, prg->code, ch, vch, (void *)obj1, (void *)obj2, 1 );



                            mob_prog.c
---------------------------------------------------------------------------------------
ADD:
#inclide "recycle.h"

ADD this right after the includes:

+ SLEEP_DATA *first_sleep = NULL;


FIND the program_flow() function:
- void program_flow( sh_int pvnum, char *source, CHAR_DATA *mob, CHAR_DATA *ch, const void *arg1, const void *arg2 )

and REPLACE it with:
+ void program_flow( sh_int pvnum, char *source, CHAR_DATA *mob, CHAR_DATA *ch, const void *arg1, const void *arg2, int numlines )


___in void program_flow()___

FIND:
    int state[MAX_NESTED_LEVEL], cond[MAX_NESTED_LEVEL];

and ADD after it:
+    int count = 0;
+    MPROG_CODE *prog = get_mprog_by_vnum(pvnum);
    
FIND:
-    if( ++call_level > MAX_CALL_LEVEL )
-    {
    
and REPLACE it with:
+    if( numlines == 1 && ++call_level > MAX_CALL_LEVEL )
+    {
    
FIND:
		else
		   *d++ = *code;
	    }
	    *b++ = *code++;
	}
	*b = *c = *d = '\0';

and ADD after it:
+    if(++count < numlines)
+	    {
+    	    if ( !str_cmp( control, "if" ) )
+    	    {
+    	        state[level] = BEGIN_BLOCK;
+    	        state[++level] = END_BLOCK;
+    	    }
+    	    else if ( !str_cmp( control, "endif" ) )
+    	    {
+    	        state[level] = IN_BLOCK;
+    	        state[--level] = END_BLOCK;
+    	    }
+    	
+    	    continue;
+    	}

then FIND:
-   /* 
-	 * Match control words
-	 */


and REPLACE it with:
+   /* 
+	 * Match control words
+	 */
+	if ( !str_cmp( control, "sleep" ) )
+	{
+	    int timer;
+	    SLEEP_DATA *sd;
+	    
+	    line = one_argument( line, control );
+	    if(control[0] == '\0')
+	        timer = 4;
+	    else if(is_number(control) && atoi(control) > 0)
+	        timer = atoi(control);
+	    else
+	    {
+		    sprintf( buf, "Mobprog: argument NaN, using 4 as default. mob %d prog %d",
+			mvnum, pvnum );
+		    bug( buf, 0 );
+           timer = 4;
+	    }
+	    
+	    sd = new_sleep_data();
+	    sd->ch = ch;
+	    sd->mob = mob;
+	    sd->line = count + 1;
+	    sd->vnum = prog->vnum;
+	    sd->timer = timer;
+	    sd->prog = prog;
+	    
+	    sd->next = first_sleep;
+	    if(first_sleep)
+	        first_sleep->prev = sd;
+	    first_sleep = sd;
+	    return;
+	}



ok, this gets a little complicated...
in every function called mp_$$$_trigger that calls on program_flow,
ADD this right after   MPROG_CODE *prg;:
+    SLEEP_DATA *test;
    
then FIND every call to program_flow in this file. Here's an example:
    program_flow( prg->vnum, prg->code, mob, ch, arg1, arg2 );

and ADD just before it:
+             for(test = first_sleep; test != NULL; test = test->next)
+                 if(test->ch == ch && test->vnum == prg->vnum)
+                     return;

***If the trigger is supposed to return a bool, change the "return;"
***in the above line to "return (TRUE);"

you will also need to ADD ", 1" (without the quotes) right
after the last argument(arg2 in this case) for every call to program_flow


and finally, ADD this to the end of the file:
+ MPROG_CODE *get_mprog_by_vnum(int vnum)
+ {
+     MPROG_CODE *temp;
+     for(temp = mprog_list; temp != NULL; temp = temp->next)
+         if(temp->vnum == vnum)
+             return temp;
+     return NULL;
+         
+ }



---------------------------------------------------------------------------------

That's all folks!  You may use this snippet as long as you send any bugs you find
or suggestions on how to make this file easier to understand to miro@kyndig.com