home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / t / toaster.zip / Compat / object.c < prev    next >
C/C++ Source or Header  |  1992-02-02  |  22KB  |  931 lines

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <stdio.h>
  4. #include <string.h>
  5. #ifdef __STDC__
  6. #include <memory.h>
  7. #endif
  8.  
  9. #include "lint.h"
  10. #include "interpret.h"
  11. #include "object.h"
  12. #include "sent.h"
  13. #include "config.h"
  14. #include "wiz_list.h"
  15. #include "exec.h"
  16.  
  17. extern int d_flag;
  18. int total_object_size = 0;
  19.  
  20. #ifdef USE_TIOCGETP        /* Check if BSD */
  21. extern int getpid();
  22. #else
  23. extern int getpid();
  24. #endif
  25.  
  26. extern char *xalloc PROT((int)), *string_copy PROT((char *));
  27.  
  28. void remove_swap_file PROT((struct object *));
  29.  
  30. extern int atoi(), total_prog_block_size, total_num_prog_blocks;
  31.  
  32. struct object *previous_ob;
  33. extern struct svalue const0;
  34.  
  35. int tot_alloc_object;
  36.  
  37. /*
  38.  * Replace newlines in a string with a carriage return, to make the string
  39.  * writeable on one line.
  40.  */
  41.  
  42. static void replace_newline(str)
  43.     char *str;
  44. {
  45.     for (; *str; str++) {
  46.     if (str[0] == '\n')
  47. #ifndef MSDOS
  48.         str[0] = '\r';
  49. #else
  50.         str[0] = 30;
  51. #endif
  52.     }
  53. }
  54.  
  55. /*
  56.  * Replace carriage return in a string with newlines.
  57.  */
  58.  
  59. static void restore_newline(str)
  60.     char *str;
  61. {
  62.     for (; *str; str++) {
  63. #ifndef MSDOS
  64.     if (str[0] == '\r')
  65. #else
  66.     if (str[0] == 30)
  67. #endif
  68.         str[0] = '\n';
  69.     }
  70. }
  71.  
  72. static int my_strlen(str)
  73.     char *str;
  74. {
  75.     int sz = 0;
  76.  
  77.     while (*str) {
  78.     sz++; 
  79.     if (*str == '\"' || *str == '\\') sz++;
  80.     str++;
  81.     }
  82.     return sz;
  83. }
  84.  
  85. /*
  86.  * Similar to strcat(), but escapes all funny characters.
  87.  * Used by save_object().
  88.  * src is modified temporarily, but restored again :-(
  89.  */
  90. static void my_strcat(dest,src)
  91.     char *dest,*src;
  92. {
  93.     char *pt,*pt2,ch[2];
  94.  
  95.     pt = strchr(src,'\\'); ch[1] = 0;
  96.     pt2 = strchr(src,'\"');
  97.     if (pt2 && pt2<pt || pt == 0)
  98.     pt = pt2;
  99.     while (pt) {
  100.     ch[0] = *pt; *pt = 0; 
  101.     strcat(dest,src); strcat(dest,"\\"); strcat(dest,ch);
  102.     src = pt+1; *pt = ch[0];
  103.     pt = strchr(src,'\\'); 
  104.     pt2 = strchr(src,'\"');
  105.     if (pt2 && pt2<pt || !pt)
  106.         pt = pt2;
  107.     }
  108.     strcat(dest,src);
  109. }
  110.     
  111.  
  112. static int save_size(v)
  113.      struct vector *v;
  114. {
  115.   int i,siz;
  116.   char numbuf[100];
  117.  
  118.   for (i=0, siz = 0; i < v->size; i++) {
  119.     if (v->item[i].type == T_STRING) {
  120.       siz += my_strlen(v->item[i].u.string) + 3; /* my_ */
  121.     }
  122.     else if (v->item[i].type == T_POINTER) {
  123.       siz += 2 + save_size(v->item[i].u.vec) + 2 + 1;
  124.     }
  125.     else if (v->item[i].type == T_NUMBER) {
  126.       sprintf(numbuf,"%d",v->item[i].u.number);
  127.       siz += strlen(numbuf) + 1;
  128.     }
  129.     else siz += 2;
  130.   }
  131.   return siz;
  132. }
  133.  
  134. static char *save_array(v)
  135.     struct vector *v;
  136. {
  137.     char *buf,*tbuf,numbuf[100];
  138.     int i;
  139.     
  140.     buf = xalloc(2+save_size(v)+2+1);
  141.     
  142.     strcpy(buf,"({");
  143.     for (i=0; i < v->size; i++) {
  144.     if (v->item[i].type == T_STRING) {
  145.         strcat(buf,"\""); my_strcat(buf,v->item[i].u.string); /* my_ */
  146.          strcat(buf,"\","); 
  147.     }
  148.      else if (v->item[i].type == T_POINTER) {
  149.          tbuf = save_array(v->item[i].u.vec);
  150.          strcat(buf,tbuf); strcat(buf,",");
  151.          free(tbuf);
  152.      }
  153.      else if (v->item[i].type == T_NUMBER) {
  154.          sprintf(numbuf,"%d,",v->item[i].u.number);
  155.          strcat(buf,numbuf);
  156.      }
  157.      else strcat(buf,"0,");    /* Objects can't be saved. */
  158.     }
  159.     strcat(buf,"})");
  160.     return buf;
  161. }
  162.   
  163.  
  164. /*
  165.  * Save an object to a file. Two kinds of saves are allowed.
  166.  * First: standard objects from /room and /obj can save anywhere. These are
  167.  *        "trusted".
  168.  * Second: A wizard defined object can only save at the home directory
  169.  *         of that wizard.
  170.  */
  171. void save_object(ob, file)
  172.     struct object *ob;
  173.     char *file;
  174. {
  175.     char *name, tmp_name[80];
  176.     int len, i;
  177.     FILE *f;
  178.     int failed = 0;
  179.     /* struct svalue *v; */
  180.  
  181.     if (ob->flags & O_DESTRUCTED)
  182.     return;
  183. #ifdef COMPAT_MODE
  184.     if (ob->user) {
  185.     strcpy(tmp_name,ob->user->name);strcat(tmp_name,"/");
  186.     if (strncmp(file, "players/", 8) != 0 ||
  187.         strncmp(file+8, tmp_name, strlen(tmp_name)) != 0 ||
  188.         strchr(file, '.'))
  189.         {
  190.         error("Illegal save file name %s\n", file);
  191.         }
  192.     } else {
  193.     if (strncmp(current_prog->name, "obj/", 4) != 0 &&
  194.         strncmp(current_prog->name, "room/", 5) != 0 &&
  195.         strncmp(current_prog->name, "std/", 4) != 0) 
  196.         {
  197.         error("Illegal use of save_object()\n");
  198.         }
  199.     }
  200. #else
  201.     file = check_valid_path(file, ob->eff_user, "save_object", 1);
  202.     if (file == 0)
  203.     error("Illegal use of save_object()\n");
  204. #endif
  205.     len = strlen(file);
  206.     name = xalloc(len + 3);
  207.     (void)strcpy(name, file);
  208. #ifndef MSDOS
  209.     (void)strcat(name, ".o");
  210. #endif
  211.     /*
  212.      * Write the save-files to different directories, just in case
  213.      * they are on different file systems.
  214.      */
  215.     sprintf(tmp_name, "%s.%d.tmp", name, getpid());
  216.     f = fopen(tmp_name, "w");
  217.     if (f == 0) {
  218.     free(name);
  219.     error("Could not open %s for a save.\n", tmp_name);
  220.     }
  221.     for (i=0; i < ob->prog->num_variables; i++) {
  222.     struct svalue *v = &ob->variables[i];
  223.     char *new_string;
  224.  
  225.     if (ob->prog->variable_names[i].type & TYPE_MOD_STATIC)
  226.         continue;
  227.     if (v->type == T_NUMBER) {
  228.         if (fprintf(f, "%s %d\n", ob->prog->variable_names[i].name,
  229.             v->u.number) == EOF)
  230.         failed = 1;
  231.     } else if (v->type == T_STRING) {
  232.         new_string = string_copy(v->u.string);
  233.         replace_newline(new_string);
  234.         if (fprintf(f, "%s \"%s\"\n", ob->prog->variable_names[i].name,
  235.             new_string) == EOF)
  236.         failed = 1;
  237.         free(new_string);
  238.  
  239. /* Saving of arrays: JnA 910520
  240. */
  241.     } else if (v->type == T_POINTER) {
  242.         new_string = save_array(v->u.vec);
  243.         replace_newline(new_string);
  244.         if (fprintf(f, "%s %s\n", ob->prog->variable_names[i].name,
  245.             new_string) == EOF)
  246.             failed = 1;
  247.         free(new_string);
  248.     }
  249.     }
  250.     (void)unlink(name);
  251. #ifndef MSDOS
  252.     if (link(tmp_name, name) == -1)
  253. #else
  254.     (void) fclose(f);
  255.     if (rename(tmp_name,name) < 0)
  256. #endif
  257.     {
  258.     perror(name);
  259.     printf("Failed to link %s to %s\n", tmp_name, name);
  260.     add_message("Failed to save object !\n");
  261.     }
  262. #ifndef MSDOS
  263.     (void)fclose(f);
  264.     unlink(tmp_name);
  265. #endif
  266.     free(name);
  267.     if (failed)
  268.     add_message("Failed to save to file. Disk could be full.\n");
  269. }
  270.  
  271. static char *my_string_copy(str)
  272.     char *str;
  273. {
  274.     char *apa,*cp;
  275.  
  276.     cp = apa = xalloc(strlen(str)+1);
  277.     
  278.     while(*str) {
  279.     if (*str == '\\') {
  280.         *cp = str[1];
  281.         if (str[1]) str+=2;
  282.         else str++;   /* String ends with a \\ buggy probably */
  283.         cp++;
  284.     }
  285.     else { *cp = *str; cp++; str++; }
  286.     }
  287.     *cp=0;
  288.     cp = string_copy(apa);
  289.     free(apa);
  290.     return cp;
  291. }
  292.  
  293. static int restore_size(str)
  294.      char **str;
  295. {
  296.   char *pt,*pt2;
  297.   int siz,tsiz;
  298.  
  299.   pt = *str; 
  300.   if (strncmp(pt,"({",2)) return -1;
  301.   else pt += 2;
  302.   siz = 0;
  303.  
  304.   while ((pt) && (*pt)) {
  305.     if (pt[0] == '}') {
  306.       if (pt[1] != ')') return -1;
  307.       *str = &pt[2];
  308.       return siz;
  309.     }
  310.     if (pt[0] == '\"') {
  311.       pt2 = strchr(&pt[1],'\"');
  312.       if (!pt2) return -1;
  313.       pt2--;
  314.       while (pt2[0] == '\\') {
  315.       pt = pt2;
  316.       pt2 = strchr(&pt[2],'\"');
  317.       if (!pt2) return -1;
  318.       pt2--;
  319.       }
  320.       if (pt2[2] != ',') return -1;
  321.       siz++;
  322.       pt = &pt2[3];
  323.     }
  324.     else if (pt[0] == '(') { 
  325.       tsiz = restore_size(&pt); /* Lazy way of doing it, a bit inefficient */
  326.       if (tsiz < 0)
  327.       return -1;
  328.       pt++;
  329.       siz++;
  330.     }
  331.     else {
  332.       pt2 = strchr(pt, ',');
  333.       if (!pt2)
  334.       return -1;
  335.       siz++;
  336.       pt = &pt2[1];
  337.     }
  338.   }
  339.   return -1;
  340. }
  341.  
  342. static struct vector *restore_array(str)
  343.      char **str;
  344. {
  345.   struct vector *v,*t;
  346.   char *pt,*pt2;
  347.   int i,siz;
  348.   
  349.   pt = *str; 
  350.   if (strncmp(pt,"({",2)) return 0;
  351.   pt2 = pt;
  352.   siz = restore_size(&pt2);
  353.   if (siz < 0) return 0;
  354.   v = allocate_array(siz);
  355.   pt+=2;
  356.  
  357.   for (i=0;i<siz;i++) {
  358.     if (!*pt) return v;
  359.     if (pt[0] == '\"') {
  360.       pt2 = strchr(&pt[1],'\"');
  361.       if (!pt2) return v;
  362.       pt2--;
  363.       while (pt2[0] == '\\') {
  364.       pt2 = strchr(&pt2[2],'\"');
  365.       if (!pt2) return v;
  366.       pt2--;
  367.       }
  368.       if (pt2[2] != ',') return v;
  369.       pt2[1] = 0;
  370.       v->item[i].type = T_STRING;
  371.       v->item[i].u.string = my_string_copy(pt+1); /* my_ */
  372.       v->item[i].string_type = STRING_MALLOC;
  373.       pt = &pt2[3];
  374.     }
  375.     else if (pt[0] == '(') {
  376.       t = restore_array(&pt);
  377.       if (!t) return v;
  378.       v->item[i].type = T_POINTER;
  379.       v->item[i].u.vec = t;
  380.       /* v->item[i].u.vec->ref++; marion - ref is already 1 (allocate_array) */
  381.       pt++;
  382.     }
  383.     else {
  384.       pt2 = strchr(pt,',');
  385.       if (!pt2) return v;
  386.       pt2[0] = 0;
  387.       v->item[i].type = T_NUMBER;
  388.       sscanf(pt,"%d",&(v->item[i].u.number));
  389.       pt = &pt2[1];
  390.     }
  391.   }
  392.   if (strncmp(pt,"})",2)) return v;
  393.   *str = &pt[2];
  394.   return v;
  395. }
  396.  
  397. int restore_object(ob, file)
  398.     struct object *ob;
  399.     char *file;
  400. {
  401.     char *name, var[100], *val, *buff, *space;
  402.     int len;
  403.     FILE *f;
  404.     struct object *save = current_object;
  405.     struct stat st;
  406.     struct variable *p;
  407.  
  408.     if (current_object != ob)
  409.     fatal("Bad argument to restore_object()\n");
  410.     if (ob->flags & O_DESTRUCTED)
  411.     return 0;
  412. #ifndef COMPAT_MODE
  413.      file = check_valid_path(file, ob->eff_user, "restore_object", 0);
  414.      if (file == 0)
  415.           error("Illegal use of restore_object()\n");
  416. #endif
  417.     len = strlen(file);
  418.     name = xalloc(len + 3);
  419.     (void)strcpy(name, file);
  420.     if (name[len-2] == '.' && name[len-1] == 'c')
  421.     name[len-1] = 'o';
  422.     else
  423.     (void)strcat(name, ".o");
  424.     f = fopen(name, "r");
  425.     if (!f || fstat(fileno(f), &st) == -1) {
  426.     free (name);
  427.     if (f) 
  428.         (void)fclose(f);
  429.     return 0;
  430.     }
  431.     if (st.st_size == 0) {
  432.     (void)fclose(f);
  433.     free (name);
  434.     return 0;
  435.     }
  436.     val = xalloc(st.st_size + 1);
  437.     buff = xalloc(st.st_size + 1);
  438.     current_object = ob;
  439.     while(1) {
  440.     struct svalue *v;
  441.  
  442.     if (fgets(buff, st.st_size + 1, f) == 0)
  443.         break;
  444.     /* Remember that we have a newline at end of buff ! */
  445.     space = strchr(buff, ' ');
  446.     if (space == 0 || space - buff >= sizeof (var)) {
  447.         (void)fclose(f);
  448.         error("Illegal format when restore %s.\n", name);
  449.     }
  450.     (void)strncpy(var, buff, space - buff);
  451.     var[space - buff] = '\0';
  452.     (void)strcpy(val, space+1);
  453.     p = find_status(var, 0);
  454.     if (p == 0 || (p->type & TYPE_MOD_STATIC))
  455.         continue;
  456.     v = &ob->variables[p - ob->prog->variable_names];
  457.     if (val[0] == '"') {
  458.         val[strlen(val) - 2] = '\0';    /* Strip trailing "\n */
  459.         restore_newline(val+1);
  460.         free_svalue(v, "restore_object");
  461.         v->type = T_STRING;
  462.         v->u.string = make_shared_string(val+1); /**MALLOC**/
  463.         v->string_type = STRING_SHARED; /**MALLOC**/
  464.         continue;
  465.     }
  466. /* Restore array: JnA 910520
  467. */
  468.     if (val[0] == '(') {
  469.         char *pt = val;
  470.         val[strlen(val) - 1] = '\0';    /* Strip trailing "\n */
  471.         restore_newline(val+1);
  472.         free_svalue(v, "restore_object");
  473.         v->type = T_POINTER;
  474.         v->u.vec = restore_array(&pt);
  475.         if (!v->u.vec) {
  476.                *v = const0;
  477.            (void)fclose(f);
  478.            error("Illegal array format when restore %s.\n", name);
  479.         }
  480.         continue;
  481.     }
  482.  
  483.     free_svalue(v, "restore_object");
  484.     v->type = T_NUMBER;
  485.     v->u.number = atoi(val);
  486.     }
  487.     current_object = save;
  488.     if (d_flag > 1)
  489.     debug_message("Object %s restored from %s.\n", ob->name, name);
  490.     free(name);
  491.     free(buff);
  492.     free(val);
  493.     
  494.     (void)fclose(f);
  495.     return 1;
  496. }
  497.  
  498. void tell_npc(ob, str)
  499.     struct object *ob;
  500.     char *str;
  501. {
  502.     push_constant_string(str);
  503.     (void) apply("catch_tell", ob, 1);
  504. }
  505.  
  506. /*
  507.  * Send a message to an object.
  508.  * If it is an interactive object, it will go to his
  509.  * screen. Otherwise, it will go to a local function
  510.  * catch_tell() in that object. This enables communications
  511.  * between players and NPC's, and between other NPC's.
  512.  */
  513. void tell_object(ob, str)
  514.     struct object *ob;
  515.     char *str;
  516. {
  517.     struct object *save_command_giver;
  518.  
  519.     if (ob->flags & O_DESTRUCTED)
  520.     return;
  521.     if (ob->interactive) {
  522.     save_command_giver = command_giver;
  523.     command_giver = ob;
  524.     add_message("%s", str);
  525.     command_giver = save_command_giver;
  526.     return;
  527.     }
  528.     tell_npc(ob, str);
  529. }
  530.  
  531. void free_object(ob, from)
  532.     struct object *ob;
  533.     char *from;
  534. {
  535.     struct sentence *s;
  536.     int num_vars;
  537.  
  538.     ob->ref--;
  539.     if (d_flag > 1)
  540.     printf("Subtr ref to ob %s: %d (%s)\n", ob->name,
  541.               ob->ref, from);
  542.     if (ob->ref > 0)
  543.     return;
  544.     if (d_flag)
  545.     printf("free_object: %s.\n", ob->name);
  546.     if (!(ob->flags & O_DESTRUCTED)) {
  547.     /* This is fatal, and should never happen. */
  548.     fatal("FATAL: Object 0x%x %s ref count 0, but not destructed (from %s).\n",
  549.         ob, ob->name, from);
  550.     }
  551.     if (ob->interactive)
  552.     fatal("Tried to free an interactive object.\n");
  553.     /*
  554.      * If the program is freed, then we can also free the variable
  555.      * declarations.
  556.      */
  557.     num_vars = ob->prog->num_variables;
  558.     if (ob->prog) {
  559.     free_prog(ob->prog, 1);
  560.     ob->prog = 0;
  561.     }
  562.     if (ob->swap_num != -1)
  563.     remove_swap_file(ob);
  564.     for (s = ob->sent; s;) {
  565.     struct sentence *next;
  566.     next = s->next;
  567.     free_sentence(s);
  568.     s = next;
  569.     }
  570.     if (ob->name) {
  571.     if (d_flag > 1)
  572.         debug_message("Free object %s\n", ob->name);
  573.     if (lookup_object_hash(ob->name) == ob)
  574.         fatal("Freeing object %s but name still in name table", ob->name);
  575.     free(ob->name);
  576.     ob->name = 0;
  577.     }
  578. #if 0 /* Variables are now allocated together with the struct object */
  579.     if (ob->variables) {
  580.     free((char *)ob->variables);
  581.     ob->variables = 0;
  582.     }
  583. #endif
  584.     if (ob->attributes)
  585.     {
  586.        int i;
  587.  
  588.        for (i = 0; i < ob->num_attributes; ++i)
  589.           free_string(ob->attributes[i].attribute);
  590.        free((char *)(ob->attributes));
  591.        ob->attributes = NULL;
  592.        ob->num_attributes = 0;
  593.     } 
  594.     tot_alloc_object--;
  595.     total_object_size -= (sizeof(struct object) + 
  596.                           (num_vars-1)*sizeof(struct svalue));
  597.     free((char *)ob);
  598. }
  599.  
  600. void add_ref(ob, from)
  601.     struct object *ob;
  602.     char *from;
  603. {
  604.     ob->ref++;
  605.     if (d_flag > 1)
  606.     printf("Add reference to object %s: %d (%s)\n", ob->name,
  607.            ob->ref, from);
  608. }
  609.  
  610.  
  611. /*
  612.  * Allocate an empty object, and set all variables to 0. Note that a
  613.  * 'struct object' already has space for one variable. So, if no variables
  614.  * are needed, we allocate a space that is smaller than 'struct object'. This
  615.  * unused (last) part must of course (and will not) be referenced.
  616.  */
  617. struct object *get_empty_object(num_var)
  618.     int num_var;
  619. {
  620.     static struct object NULL_object;
  621.     struct object *ob;
  622.     int size;
  623.     int i;
  624.  
  625.     if (num_var)
  626.        size = sizeof(struct object) + (num_var - 1) * sizeof (struct svalue);
  627.     else
  628.        size = sizeof(struct object);
  629.     tot_alloc_object++;
  630.     total_object_size += size; 
  631.     ob = (struct object *)xalloc(size);
  632.     *ob = NULL_object;
  633.     ob->sent = 0;
  634.     ob->swap_num = -1;        /* Object not swapped. */
  635.     for (i=0; i<num_var; i++) 
  636.         ob->variables[i] = const0;
  637.     return ob;
  638. }
  639.  
  640. void remove_all_objects() {
  641.     struct object *ob;
  642.     struct svalue v;
  643.  
  644.     v.type = T_OBJECT;
  645.     while(1) {
  646.     if (obj_list == 0)
  647.         break;
  648.     ob = obj_list;
  649.     v.u.ob = ob;
  650.     destruct_object(&v, 1);
  651.     if (ob == obj_list)
  652.         break;
  653.     }
  654.     remove_destructed_objects();
  655. }
  656.  
  657. #if 0
  658. /*
  659.  * For debugging purposes.
  660.  */
  661. void check_ob_ref(ob, from)
  662.     struct object *ob;
  663.     char *from;
  664. {
  665.     struct object *o;
  666.     int i;
  667.  
  668.     for (o = obj_list, i=0; o; o = o->next_all) {
  669.     if (o->inherit == ob)
  670.         i++;
  671.     }
  672.     if (i+1 > ob->ref) {
  673.     fatal("FATAL too many references to inherited object %s (%d) from %s.\n",
  674.           ob->name, ob->ref, from);
  675.     if (current_object)
  676.         fprintf(stderr, "current_object: %s\n", current_object->name);
  677.     for (o = obj_list; o; o = o->next_all) {
  678.         if (o->inherit != ob)
  679.         continue;
  680.         fprintf(stderr, "  %s\n", ob->name);
  681.     }
  682.     }
  683. }
  684. #endif /* 0 */
  685.  
  686. static struct object *hashed_living[LIVING_HASH_SIZE];
  687.  
  688. static int num_living_names, num_searches = 1, search_length = 1;
  689.  
  690. static int hash_living_name(str)
  691.     char *str;
  692. {
  693. #if 1
  694.     return hashstr(str, 100, LIVING_HASH_SIZE);
  695. #else
  696.     unsigned ret = 0;
  697.  
  698.     while(*str)
  699.     ret = ret * 2 + *str++;
  700.     return ret % LIVING_HASH_SIZE;
  701. #endif
  702. }
  703.  
  704.  
  705. struct object *old_find_living(name)
  706.     char *name;
  707. {
  708.     struct object *ob;
  709.     struct svalue *ret;
  710.  
  711.     for (ob = obj_list; ob; ob = ob->next_all) {
  712.     if (!(ob->flags&O_ENABLE_COMMANDS) || ob->super == 0)
  713.         continue;
  714.         push_constant_string(name);
  715.     ret = apply("id", ob, 1);
  716.     /* Did the object self destruct ? (unlikely, but possible) */
  717.     if (ob->flags&O_DESTRUCTED)
  718.         return 0;
  719.     if (ret == 0 || (ret->type == T_NUMBER && ret->u.number == 0))
  720.         continue;
  721.     return ob;
  722.     }
  723.     return 0;
  724. }
  725. struct object *find_living_object(str, player)
  726.     char *str;
  727.     int player;
  728. {
  729.     struct object **obp, *tmp;
  730.     struct object **hl;
  731.     struct svalue *ret;
  732.  
  733.     num_searches++;
  734.     hl = &hashed_living[hash_living_name(str)];
  735.     for (obp = hl; *obp; obp = &(*obp)->next_hashed_living) {
  736.     search_length++;
  737.     if (player && !((*obp)->flags & O_ONCE_INTERACTIVE))
  738.         continue;
  739.     if (!((*obp)->flags & O_ENABLE_COMMANDS))
  740.         continue;
  741.     if (strcmp((*obp)->living_name, str) == 0)
  742.         {
  743. #ifndef FIND_LIVING_NO_ID
  744.             push_constant_string(str);
  745.             ret = apply("id", *obp, 1);
  746.             if (ret && ret->type == T_NUMBER && ret->u.number != 0)
  747. #endif
  748.             break;
  749.         }
  750.     }
  751. #ifdef OLD_FIND_LIVING
  752.     if (*obp == 0) 
  753.     {
  754.     if (player) return 0;
  755.     else return old_find_living(str); 
  756.     }
  757.     
  758. #else
  759.     if (*obp == 0) return 0;
  760. #endif
  761.     /* Move the found ob first. */
  762.     if (obp == hl)
  763.     return *obp;
  764.     tmp = *obp;
  765.     *obp = tmp->next_hashed_living;
  766.     tmp->next_hashed_living = *hl;
  767.     *hl = tmp;
  768.     return tmp;
  769. }
  770.  
  771. void set_living_name(ob, str)
  772.     struct object *ob;
  773.     char *str;
  774. {
  775.     struct object **hl;
  776.  
  777.     if (ob->flags & O_DESTRUCTED)
  778.     return;
  779.     if (ob->living_name) {
  780.     remove_living_name(ob);
  781.     }
  782.     num_living_names++;
  783.     hl = &hashed_living[hash_living_name(str)];
  784.     ob->next_hashed_living = *hl;
  785.     *hl = ob;
  786.     ob->living_name = make_shared_string(str);
  787. #if 0    /* This is not a pretty way to find out if it is a wizard */
  788.     if (ob->interactive) {
  789.     struct svalue *v;
  790.     
  791.     v = apply("query_level", ob, 0);
  792.     if (v && v->type == T_NUMBER && v->u.number >= 21)
  793.         ob->flags |= O_IS_WIZARD;
  794.     }
  795. #endif
  796.     return;
  797. }
  798.  
  799. void remove_living_name(ob)
  800.     struct object *ob;
  801. {
  802.     struct object **hl;
  803.  
  804. #ifdef MUDWHO
  805.     sendmudwhologout(ob);
  806. #endif
  807.     num_living_names--;
  808.     if (!ob->living_name)
  809.     fatal("remove_living_name: no living name set.\n");
  810.     hl = &hashed_living[hash_living_name(ob->living_name)];
  811.     while(*hl) {
  812.     if (*hl == ob)
  813.         break;
  814.     hl = &(*hl)->next_hashed_living;
  815.     }
  816.     if (*hl == 0)
  817.     fatal("remove_living_name: Object named %s no in hash list.\n",
  818.           ob->living_name);
  819.     *hl = ob->next_hashed_living;
  820.     free_string(ob->living_name);
  821.     ob->next_hashed_living = 0;
  822.     ob->living_name = 0;
  823. }
  824.  
  825. void stat_living_objects() {
  826.     add_message("Hash table of living objects:\n");
  827.     add_message("-----------------------------\n");
  828.     add_message("%d living named objects, average search length: %4.2f\n",
  829.         num_living_names, (double)search_length / num_searches);
  830. }
  831.  
  832. void reference_prog (progp, from)
  833.     struct program *progp;
  834.     char *from;
  835. {
  836.     progp->ref++;
  837.     if (d_flag)
  838.     printf("reference_prog: %s ref %d (%s)\n",
  839.         progp->name, progp->ref, from);
  840. }
  841.  
  842. /*
  843.  * Decrement reference count for a program. If it is 0, then free the prgram.
  844.  * The flag free_sub_strings tells if the propgram plus all used strings
  845.  * should be freed. They normally are, except when objects are swapped,
  846.  * as we want to be able to read the program in again from the swap area.
  847.  * That means that strings are not swapped.
  848.  */
  849. void free_prog(progp, free_sub_strings)
  850.     struct program *progp;
  851.     int free_sub_strings;
  852. {
  853.     progp->ref--;
  854.     if (progp->ref > 0)
  855.     return;
  856.     total_prog_block_size -= progp->total_size;
  857.     total_num_prog_blocks -= 1;
  858.     if (d_flag)
  859.     printf("free_prog: %s\n", progp->name);
  860.     if (progp->ref < 0)
  861.     fatal("Negative ref count for prog ref.\n");
  862.     if (free_sub_strings) {
  863.     int i;
  864.  
  865.     /* Free all function names. */
  866.     for (i=0; i < progp->num_functions; i++)
  867.         if (progp->functions[i].name)
  868.         free_string(progp->functions[i].name);
  869.     /* Free all strings */
  870.     for (i=0; i < progp->num_strings; i++)
  871.         free_string(progp->strings[i]);
  872.     /* Free all variable names */
  873.     for (i=0; i < progp->num_variables; i++)
  874.         free_string(progp->variable_names[i].name);
  875.     /* Free all inherited objects */
  876.     for (i=0; i < progp->num_inherited; i++)
  877.         free_prog(progp->inherit[i].prog, 1);
  878.     free(progp->name);
  879.     }
  880.     free((char *)progp);
  881. }
  882.  
  883. void reset_object(ob, arg)
  884.     struct object *ob;
  885.     int arg;
  886. {
  887.     extern int current_time, eval_cost;
  888.     int save_eval = eval_cost;
  889.  
  890.     /* Be sure to update time first ! */
  891.     ob->next_reset = current_time + TIME_TO_RESET/2 +
  892.     random_number(TIME_TO_RESET/2);
  893. #ifdef COMPAT_MODE
  894.     push_number(arg);
  895.     (void)apply("reset", ob, 1);
  896. #else
  897.     if (arg == 0)
  898.     apply("create", ob, 0);
  899.     else
  900.     apply("reset", ob, 0);
  901. #endif    
  902.     ob->flags |= O_RESET_STATE;
  903. }
  904.  
  905. /*
  906.  * If there is a shadow for this object, then the message should be
  907.  * sent to it. But only if catch_tell() is defined. Beware that one of the
  908.  * shadows may be the originator of the message, which means that we must
  909.  * not send the message to that shadow, or any shadows in the linked list
  910.  * before that shadow.
  911.  */
  912. int shadow_catch_message(ob, str)
  913.     struct object *ob;
  914.     char *str;
  915. {
  916.     if (!ob->shadowed)
  917.     return 0;
  918.     while(ob->shadowed && ob->shadowed != current_object)
  919.     ob = ob->shadowed;
  920.     while(ob->shadowing) {
  921.         if (function_exists("catch_tell", ob))   
  922.         { 
  923.        push_constant_string(str);
  924.        if (apply("catch_tell", ob, 1))
  925.            return 1;
  926.         }
  927.     ob = ob->shadowing;
  928.     }
  929.     return 0;
  930. }
  931.