DB.C
上传用户:kesirui
上传日期:2007-01-07
资源大小:263k
文件大小:70k
源码类别:

Internet/网络编程

开发平台:

WINDOWS

  1. /***************************************************************************
  2.  *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
  3.  *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
  4.  *                                                                         *
  5.  *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
  6.  *  Chastain, Michael Quan, and Mitchell Tse.                              *
  7.  *                                                                         *
  8.  *  In order to use any part of this Merc Diku Mud, you must comply with   *
  9.  *  both the original Diku license in 'license.doc' as well the Merc       *
  10.  *  license in 'license.txt'.  In particular, you may not remove either of *
  11.  *  these copyright notices.                                               *
  12.  *                                                                         *
  13.  *  Much time and thought has gone into this software and you are          *
  14.  *  benefitting.  We hope that you share your changes too.  What goes      *
  15.  *  around, comes around.                                                  *
  16.  ***************************************************************************/
  17. #if defined(macintosh)
  18. #include <types.h>
  19. #else
  20. #include <sys/types.h>
  21. #endif
  22. #include <ctype.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <time.h>
  27. #include "merc.h"
  28. #if !defined(macintosh)
  29. extern int _filbuf args( (FILE *) );
  30. #endif
  31. /*
  32.  * Globals.
  33.  */
  34. HELP_DATA * help_first;
  35. HELP_DATA * help_last;
  36. SHOP_DATA * shop_first;
  37. SHOP_DATA * shop_last;
  38. CHAR_DATA * char_free;
  39. EXTRA_DESCR_DATA * extra_descr_free;
  40. NOTE_DATA * note_free;
  41. OBJ_DATA * obj_free;
  42. PC_DATA * pcdata_free;
  43. char bug_buf [2*MAX_INPUT_LENGTH];
  44. CHAR_DATA * char_list;
  45. char * help_greeting;
  46. char log_buf [2*MAX_INPUT_LENGTH];
  47. KILL_DATA kill_table [MAX_LEVEL];
  48. NOTE_DATA * note_list;
  49. OBJ_DATA * object_list;
  50. TIME_INFO_DATA time_info;
  51. WEATHER_DATA weather_info;
  52. sh_int gsn_backstab;
  53. sh_int gsn_dodge;
  54. sh_int gsn_hide;
  55. sh_int gsn_peek;
  56. sh_int gsn_pick_lock;
  57. sh_int gsn_sneak;
  58. sh_int gsn_steal;
  59. sh_int gsn_disarm;
  60. sh_int gsn_enhanced_damage;
  61. sh_int gsn_kick;
  62. sh_int gsn_parry;
  63. sh_int gsn_rescue;
  64. sh_int gsn_second_attack;
  65. sh_int gsn_third_attack;
  66. sh_int gsn_blindness;
  67. sh_int gsn_charm_person;
  68. sh_int gsn_curse;
  69. sh_int gsn_invis;
  70. sh_int gsn_mass_invis;
  71. sh_int gsn_poison;
  72. sh_int gsn_sleep;
  73. /*
  74.  * Psionicist gsn's.
  75.  */
  76. int                     gsn_chameleon;
  77. int                     gsn_domination;
  78. int                     gsn_heighten;
  79. int                     gsn_shadow;
  80. /*
  81.  * Locals.
  82.  */
  83. MOB_INDEX_DATA * mob_index_hash [MAX_KEY_HASH];
  84. OBJ_INDEX_DATA * obj_index_hash [MAX_KEY_HASH];
  85. ROOM_INDEX_DATA * room_index_hash [MAX_KEY_HASH];
  86. char * string_hash [MAX_KEY_HASH];
  87. AREA_DATA * area_first;
  88. AREA_DATA * area_last;
  89. char * string_space;
  90. char * top_string;
  91. char str_empty [1];
  92. int top_affect;
  93. int top_area;
  94. int top_ed;
  95. int top_exit;
  96. int top_help;
  97. int top_mob_index;
  98. int top_obj_index;
  99. int top_reset;
  100. int top_room;
  101. int top_shop;
  102. /*
  103.  * MOBprogram locals
  104. */
  105. int  mprog_name_to_type args( ( char* name ) );
  106. MPROG_DATA * mprog_file_read args( ( char* f, MPROG_DATA* mprg, 
  107.                                         MOB_INDEX_DATA *pMobIndex ) );
  108. void load_mobprogs           args( ( FILE* fp ) );
  109. void    mprog_read_programs     args( ( FILE* fp,
  110. MOB_INDEX_DATA *pMobIndex ) );
  111. // Windows version locals
  112. int fIgnoreUnconnected = TRUE;
  113. /*
  114.  * Memory management.
  115.  * Increase MAX_STRING if you have too.
  116.  * Tune the others only if you understand what you're doing.
  117.  */
  118. #define MAX_STRING 1750000
  119. #define MAX_PERM_BLOCK 131072
  120. #define MAX_MEM_LIST 11
  121. void * rgFreeList [MAX_MEM_LIST];
  122. const int rgSizeList [MAX_MEM_LIST] =
  123. {
  124.     16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384, 32768-64
  125. };
  126. int nAllocString;
  127. int sAllocString;
  128. int nAllocPerm;
  129. int sAllocPerm;
  130. /*
  131.  * Semi-locals.
  132.  */
  133. bool fBootDb;
  134. FILE * fpArea;
  135. char strArea[MAX_INPUT_LENGTH];
  136. /*
  137.  * Local booting procedures.
  138.  */
  139. void init_mm args( ( void ) );
  140. void load_area args( ( FILE *fp ) );
  141. void load_helps args( ( FILE *fp ) );
  142. void load_mobiles args( ( FILE *fp ) );
  143. void load_objects args( ( FILE *fp ) );
  144. void load_resets args( ( FILE *fp ) );
  145. void load_rooms args( ( FILE *fp ) );
  146. void load_shops args( ( FILE *fp ) );
  147. void load_specials args( ( FILE *fp ) );
  148. void load_notes args( ( void ) );
  149. void fix_exits args( ( void ) );
  150. void reset_area args( ( AREA_DATA * pArea ) );
  151. /*
  152.  * Big mama top level function.
  153.  */
  154. void boot_db( void )
  155. {
  156.     /*
  157.      * Init some data space stuff.
  158.      */
  159.     {
  160. if ( ( string_space = calloc( 1, MAX_STRING ) ) == NULL )
  161. {
  162.     bug( "Boot_db: can't alloc %d string space.", MAX_STRING );
  163.     exit( 1 );
  164. }
  165. top_string = string_space;
  166. fBootDb = TRUE;
  167.     }
  168.     /*
  169.      * Init random number generator.
  170.      */
  171.     {
  172. init_mm( );
  173.     }
  174.     /*
  175.      * Set time and weather.
  176.      */
  177.     {
  178. long lhour, lday, lmonth;
  179. lhour = (current_time - 650336715)
  180. / (PULSE_TICK / PULSE_PER_SECOND);
  181. time_info.hour = lhour  % 24;
  182. lday = lhour  / 24;
  183. time_info.day = lday   % 35;
  184. lmonth = lday   / 35;
  185. time_info.month = lmonth % 17;
  186. time_info.year = lmonth / 17;
  187.      if ( time_info.hour <  5 ) weather_info.sunlight = SUN_DARK;
  188. else if ( time_info.hour <  6 ) weather_info.sunlight = SUN_RISE;
  189. else if ( time_info.hour < 19 ) weather_info.sunlight = SUN_LIGHT;
  190. else if ( time_info.hour < 20 ) weather_info.sunlight = SUN_SET;
  191. else                            weather_info.sunlight = SUN_DARK;
  192. weather_info.change = 0;
  193. weather_info.mmhg = 960;
  194. if ( time_info.month >= 7 && time_info.month <=12 )
  195.     weather_info.mmhg += number_range( 1, 50 );
  196. else
  197.     weather_info.mmhg += number_range( 1, 80 );
  198.      if ( weather_info.mmhg <=  980 ) weather_info.sky = SKY_LIGHTNING;
  199. else if ( weather_info.mmhg <= 1000 ) weather_info.sky = SKY_RAINING;
  200. else if ( weather_info.mmhg <= 1020 ) weather_info.sky = SKY_CLOUDY;
  201. else                                  weather_info.sky = SKY_CLOUDLESS;
  202.     }
  203.     /*
  204.      * Assign gsn's for skills which have them.
  205.      */
  206.     {
  207. int sn;
  208. for ( sn = 0; sn < MAX_SKILL; sn++ )
  209. {
  210.     if ( skill_table[sn].pgsn != NULL )
  211. *skill_table[sn].pgsn = sn;
  212. }
  213.     }
  214.     /*
  215.      * Read in all the area files.
  216.      */
  217.     {
  218. FILE *fpList;
  219. if ( ( fpList = fopen( AREA_LIST, "r" ) ) == NULL )
  220. {
  221.     perror( AREA_LIST );
  222.     exit( 1 );
  223. }
  224. for ( ; ; )
  225. {
  226.     strcpy( strArea, fread_word( fpList ) );
  227.     if ( strArea[0] == '$' )
  228. break;
  229.     if ( strArea[0] == '-' )
  230.     {
  231. fpArea = stdin;
  232.     }
  233.     else
  234.     {
  235. if ( ( fpArea = fopen( strArea, "r" ) ) == NULL )
  236. {
  237.     perror( strArea );
  238.     exit( 1 );
  239. }
  240.     }
  241.     for ( ; ; )
  242.     {
  243. char *word;
  244. if ( fread_letter( fpArea ) != '#' )
  245. {
  246.     bug( "Boot_db: # not found.", 0 );
  247.     exit( 1 );
  248. }
  249. word = fread_word( fpArea );
  250.      if ( word[0] == '$'               )                 break;
  251. else if ( !str_cmp( word, "AREA"     ) ) load_area    (fpArea);
  252. else if ( !str_cmp( word, "HELPS"    ) ) load_helps   (fpArea);
  253. else if ( !str_cmp( word, "MOBILES"  ) ) load_mobiles (fpArea);
  254. else if ( !str_cmp( word, "MOBPROGS" ) ) load_mobprogs(fpArea);
  255. else if ( !str_cmp( word, "OBJECTS"  ) ) load_objects (fpArea);
  256. else if ( !str_cmp( word, "RESETS"   ) ) load_resets  (fpArea);
  257. else if ( !str_cmp( word, "ROOMS"    ) ) load_rooms   (fpArea);
  258. else if ( !str_cmp( word, "SHOPS"    ) ) load_shops   (fpArea);
  259. else if ( !str_cmp( word, "SPECIALS" ) ) load_specials(fpArea);
  260. else
  261. {
  262.     bug( "Boot_db: bad section name.", 0 );
  263.     exit( 1 );
  264. }
  265.     }
  266.     if ( fpArea != stdin )
  267. fclose( fpArea );
  268.     fpArea = NULL;
  269. }
  270. fclose( fpList );
  271.     }
  272.     /*
  273.      * Fix up exits.
  274.      * Declare db booting over.
  275.      * Reset all areas once.
  276.      * Load up the notes file.
  277.      * Set the MOBtrigger.
  278.      */
  279.     {
  280. fix_exits( );
  281. fBootDb = FALSE;
  282. area_update( );
  283. load_notes( );
  284. MOBtrigger = TRUE;
  285.     }
  286.     return;
  287. }
  288. /*
  289.  * Snarf an 'area' header line.
  290.  */
  291. void load_area( FILE *fp )
  292. {
  293.     AREA_DATA *pArea;
  294.     pArea = alloc_perm( sizeof(*pArea) );
  295.     pArea->reset_first = NULL;
  296.     pArea->reset_last = NULL;
  297.     pArea->name = fread_string( fp );
  298.     pArea->age = 15;
  299.     pArea->nplayer = 0;
  300.     if ( area_first == NULL )
  301. area_first = pArea;
  302.     if ( area_last  != NULL )
  303. area_last->next = pArea;
  304.     area_last = pArea;
  305.     pArea->next = NULL;
  306.     top_area++;
  307.     return;
  308. }
  309. /*
  310.  * Snarf a help section.
  311.  */
  312. void load_helps( FILE *fp )
  313. {
  314.     HELP_DATA *pHelp;
  315.     for ( ; ; )
  316.     {
  317. pHelp = alloc_perm( sizeof(*pHelp) );
  318. pHelp->level = fread_number( fp );
  319. pHelp->keyword = fread_string( fp );
  320. if ( pHelp->keyword[0] == '$' )
  321.     break;
  322. pHelp->text = fread_string( fp );
  323. if ( !str_cmp( pHelp->keyword, "greeting" ) )
  324.     help_greeting = pHelp->text;
  325. if ( help_first == NULL )
  326.     help_first = pHelp;
  327. if ( help_last  != NULL )
  328.     help_last->next = pHelp;
  329. help_last = pHelp;
  330. pHelp->next = NULL;
  331. top_help++;
  332.     }
  333.     return;
  334. }
  335. /*
  336.  * Snarf a mob section.
  337.  */
  338. void load_mobiles( FILE *fp )
  339. {
  340.     MOB_INDEX_DATA *pMobIndex;
  341.     for ( ; ; )
  342.     {
  343. sh_int vnum;
  344. char letter;
  345. int iHash;
  346. letter = fread_letter( fp );
  347. if ( letter != '#' )
  348. {
  349.     bug( "Load_mobiles: # not found.", 0 );
  350.     exit( 1 );
  351. }
  352. vnum = fread_number( fp );
  353. if ( vnum == 0 )
  354.     break;
  355. fBootDb = FALSE;
  356. if ( get_mob_index( vnum ) != NULL )
  357. {
  358.     bug( "Load_mobiles: vnum %d duplicated.", vnum );
  359.     exit( 1 );
  360. }
  361. fBootDb = TRUE;
  362. pMobIndex = alloc_perm( sizeof(*pMobIndex) );
  363. pMobIndex->vnum = vnum;
  364. pMobIndex->player_name = fread_string( fp );
  365. pMobIndex->short_descr = fread_string( fp );
  366. pMobIndex->long_descr = fread_string( fp );
  367. pMobIndex->description = fread_string( fp );
  368. pMobIndex->long_descr[0] = UPPER(pMobIndex->long_descr[0]);
  369. pMobIndex->description[0] = UPPER(pMobIndex->description[0]);
  370. pMobIndex->act = fread_number( fp ) | ACT_IS_NPC;
  371. pMobIndex->affected_by = fread_number( fp );
  372. pMobIndex->pShop = NULL;
  373. pMobIndex->alignment = fread_number( fp );
  374. letter = fread_letter( fp );
  375. pMobIndex->level = number_fuzzy( fread_number( fp ) );
  376. /*
  377.  * The unused stuff is for imps who want to use the old-style
  378.  * stats-in-files method.
  379.  */
  380. pMobIndex->hitroll = fread_number( fp ); /* Unused */
  381. pMobIndex->ac = fread_number( fp ); /* Unused */
  382. pMobIndex->hitnodice = fread_number( fp ); /* Unused */
  383. /* 'd' */   fread_letter( fp ); /* Unused */
  384. pMobIndex->hitsizedice = fread_number( fp ); /* Unused */
  385. /* '+' */   fread_letter( fp ); /* Unused */
  386. pMobIndex->hitplus = fread_number( fp ); /* Unused */
  387. pMobIndex->damnodice = fread_number( fp ); /* Unused */
  388. /* 'd' */   fread_letter( fp ); /* Unused */
  389. pMobIndex->damsizedice = fread_number( fp ); /* Unused */
  390. /* '+' */   fread_letter( fp ); /* Unused */
  391. pMobIndex->damplus = fread_number( fp ); /* Unused */
  392. pMobIndex->gold = fread_number( fp ); /* Unused */
  393. /* xp can't be used! */   fread_number( fp ); /* Unused */
  394. /* position */   fread_number( fp ); /* Unused */
  395. /* start pos */   fread_number( fp ); /* Unused */
  396. /*
  397.  * Back to meaningful values.
  398.  */
  399. pMobIndex->sex = fread_number( fp );
  400.    pMobIndex->cargo     = 0; // @@@ ### Needed?
  401. if ( letter != 'S' )
  402. {
  403.     bug( "Load_mobiles: vnum %d non-S.", vnum );
  404.     exit( 1 );
  405. }
  406. letter=fread_letter(fp);
  407. if (letter=='>')
  408. {
  409.     ungetc(letter,fp);
  410.     mprog_read_programs(fp,pMobIndex);
  411. }
  412. else ungetc(letter,fp);
  413. iHash = vnum % MAX_KEY_HASH;
  414. pMobIndex->next = mob_index_hash[iHash];
  415. mob_index_hash[iHash] = pMobIndex;
  416. top_mob_index++;
  417. kill_table[URANGE(0, pMobIndex->level, MAX_LEVEL-1)].number++;
  418.     }
  419.     return;
  420. }
  421. /*
  422.  * Snarf an obj section.
  423.  */
  424. void load_objects( FILE *fp )
  425. {
  426.     OBJ_INDEX_DATA *pObjIndex;
  427.     for ( ; ; )
  428.     {
  429. sh_int vnum;
  430. char letter;
  431. int iHash;
  432. letter = fread_letter( fp );
  433. if ( letter != '#' )
  434. {
  435.     bug( "Load_objects: # not found.", 0 );
  436.     exit( 1 );
  437. }
  438. vnum = fread_number( fp );
  439. if ( vnum == 0 )
  440.     break;
  441. fBootDb = FALSE;
  442. if ( get_obj_index( vnum ) != NULL )
  443. {
  444.     bug( "Load_objects: vnum %d duplicated.", vnum );
  445.     exit( 1 );
  446. }
  447. fBootDb = TRUE;
  448. pObjIndex = alloc_perm( sizeof(*pObjIndex) );
  449. pObjIndex->vnum = vnum;
  450. pObjIndex->name = fread_string( fp );
  451. pObjIndex->short_descr = fread_string( fp );
  452. pObjIndex->description = fread_string( fp );
  453. /* Action description */   fread_string( fp );
  454. pObjIndex->short_descr[0] = LOWER(pObjIndex->short_descr[0]);
  455. pObjIndex->description[0] = UPPER(pObjIndex->description[0]);
  456. pObjIndex->item_type = fread_number( fp );
  457. pObjIndex->extra_flags = fread_number( fp );
  458. pObjIndex->wear_flags = fread_number( fp );
  459. pObjIndex->value[0] = fread_number( fp );
  460. pObjIndex->value[1] = fread_number( fp );
  461. pObjIndex->value[2] = fread_number( fp );
  462. pObjIndex->value[3] = fread_number( fp );
  463. pObjIndex->weight = fread_number( fp );
  464. pObjIndex->cost = fread_number( fp ); /* Unused */
  465. /* Cost per day */   fread_number( fp );
  466. if ( pObjIndex->item_type == ITEM_POTION )
  467.     SET_BIT(pObjIndex->extra_flags, ITEM_NODROP);
  468. for ( ; ; )
  469. {
  470.     char letter;
  471.     letter = fread_letter( fp );
  472.     if ( letter == 'A' )
  473.     {
  474. AFFECT_DATA *paf;
  475. paf = alloc_perm( sizeof(*paf) );
  476. paf->type = -1;
  477. paf->duration = -1;
  478. paf->location = fread_number( fp );
  479. paf->modifier = fread_number( fp );
  480. paf->bitvector = 0;
  481. paf->next = pObjIndex->affected;
  482. pObjIndex->affected = paf;
  483. top_affect++;
  484.     }
  485.     else if ( letter == 'E' )
  486.     {
  487. EXTRA_DESCR_DATA *ed;
  488. ed = alloc_perm( sizeof(*ed) );
  489. ed->keyword = fread_string( fp );
  490. ed->description = fread_string( fp );
  491. ed->next = pObjIndex->extra_descr;
  492. pObjIndex->extra_descr = ed;
  493. top_ed++;
  494.     }
  495.     else
  496.     {
  497. ungetc( letter, fp );
  498. break;
  499.     }
  500. }
  501. /*
  502.  * Translate spell "slot numbers" to internal "skill numbers."
  503.  */
  504. switch ( pObjIndex->item_type )
  505. {
  506. case ITEM_PILL:
  507. case ITEM_POTION:
  508. case ITEM_SCROLL:
  509.     pObjIndex->value[1] = slot_lookup( pObjIndex->value[1] );
  510.     pObjIndex->value[2] = slot_lookup( pObjIndex->value[2] );
  511.     pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );
  512.     break;
  513. case ITEM_STAFF:
  514. case ITEM_WAND:
  515.     pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] );
  516.     break;
  517. }
  518. iHash = vnum % MAX_KEY_HASH;
  519. pObjIndex->next = obj_index_hash[iHash];
  520. obj_index_hash[iHash] = pObjIndex;
  521. top_obj_index++;
  522.     }
  523.     return;
  524. }
  525. /*
  526.  * Snarf a reset section.
  527.  */
  528. void load_resets( FILE *fp )
  529. {
  530.     RESET_DATA *pReset;
  531.     if ( area_last == NULL )
  532.     {
  533. bug( "Load_resets: no #AREA seen yet.", 0 );
  534. exit( 1 );
  535.     }
  536.     for ( ; ; )
  537.     {
  538. ROOM_INDEX_DATA *pRoomIndex;
  539. EXIT_DATA *pexit;
  540. char letter;
  541. if ( ( letter = fread_letter( fp ) ) == 'S' )
  542.     break;
  543. if ( letter == '*' )
  544. {
  545.     fread_to_eol( fp );
  546.     continue;
  547. }
  548. pReset = alloc_perm( sizeof(*pReset) );
  549. pReset->command = letter;
  550. /* if_flag */   fread_number( fp );
  551. pReset->arg1 = fread_number( fp );
  552. pReset->arg2 = fread_number( fp );
  553. pReset->arg3 = (letter == 'G' || letter == 'R' || letter == 'C' || letter == 'F')
  554.     ? 0 : fread_number( fp );
  555.   fread_to_eol( fp );
  556. /*
  557.  * Validate parameters.
  558.  * We're calling the index functions for the side effect.
  559.  */
  560. switch ( letter )
  561. {
  562. default:
  563.     bug( "Load_resets: bad command '%c'.", letter );
  564.     exit( 1 );
  565.     break;
  566. case 'M':
  567.     get_mob_index  ( pReset->arg1 );
  568.     get_room_index ( pReset->arg3 );
  569.     break;
  570. case 'O':
  571.     get_obj_index  ( pReset->arg1 );
  572.     get_room_index ( pReset->arg3 );
  573.     break;
  574. case 'P':
  575.     get_obj_index  ( pReset->arg1 );
  576.     get_obj_index  ( pReset->arg3 );
  577.     break;
  578. case 'G':
  579. case 'E':
  580.     get_obj_index  ( pReset->arg1 );
  581.     break;
  582. case 'D':
  583.     pRoomIndex = get_room_index( pReset->arg1 );
  584.     if ( pReset->arg2 < 0
  585.     ||   pReset->arg2 > 5
  586.     || ( pexit = pRoomIndex->exit[pReset->arg2] ) == NULL
  587.     || !IS_SET( pexit->exit_info, EX_ISDOOR ) )
  588.     {
  589. bug( "Load_resets: 'D': exit %d not door.", pReset->arg2 );
  590. exit( 1 );
  591.     }
  592.     if ( pReset->arg3 < 0 || pReset->arg3 > 2 )
  593.     {
  594. bug( "Load_resets: 'D': bad 'locks': %d.", pReset->arg3 );
  595. exit( 1 );
  596.     }
  597.     break;
  598. case 'R':
  599.     /*pRoomIndex =*/ get_room_index( pReset->arg1 );
  600.     if ( pReset->arg2 < 0 || pReset->arg2 > 6 )
  601.     {
  602. bug( "Load_resets: 'R': bad exit %d.", pReset->arg2 );
  603. exit( 1 );
  604.     }
  605.     break;
  606.    case 'C':
  607.    case 'F':
  608.       break;
  609. }
  610. if ( area_last->reset_first == NULL )
  611.     area_last->reset_first = pReset;
  612. if ( area_last->reset_last  != NULL )
  613.     area_last->reset_last->next = pReset;
  614.     
  615. area_last->reset_last = pReset;
  616. pReset->next = NULL;
  617. top_reset++;
  618.     }
  619.     return;
  620. }
  621. /*
  622.  * Snarf a room section.
  623.  */
  624. void load_rooms( FILE *fp )
  625. {
  626.     ROOM_INDEX_DATA *pRoomIndex;
  627.     if ( area_last == NULL )
  628.     {
  629. bug( "Load_resets: no #AREA seen yet.", 0 );
  630. exit( 1 );
  631.     }
  632.     for ( ; ; )
  633.     {
  634. sh_int vnum;
  635. char letter;
  636. int door;
  637. int iHash;
  638. letter = fread_letter( fp );
  639. if ( letter != '#' )
  640. {
  641.     bug( "Load_rooms: # not found.", 0 );
  642.     exit( 1 );
  643. }
  644. vnum = fread_number( fp );
  645. if ( vnum == 0 )
  646.     break;
  647. fBootDb = FALSE;
  648. if ( get_room_index( vnum ) != NULL )
  649. {
  650.     bug( "Load_rooms: vnum %d duplicated.", vnum );
  651.     exit( 1 );
  652. }
  653. fBootDb = TRUE;
  654. pRoomIndex = alloc_perm( sizeof(*pRoomIndex) );
  655. pRoomIndex->people = NULL;
  656. pRoomIndex->contents = NULL;
  657. pRoomIndex->extra_descr = NULL;
  658. pRoomIndex->area = area_last;
  659. pRoomIndex->vnum = vnum;
  660. pRoomIndex->name = fread_string( fp );
  661. pRoomIndex->description = fread_string( fp );
  662. /* Area number */   fread_number( fp );
  663. pRoomIndex->room_flags = fread_number( fp );
  664. pRoomIndex->sector_type = fread_number( fp );
  665. pRoomIndex->light = 0;
  666. for ( door = 0; door <= 5; door++ )
  667.     pRoomIndex->exit[door] = NULL;
  668. for ( ; ; )
  669. {
  670.     letter = fread_letter( fp );
  671.     if ( letter == 'S' )
  672. break;
  673.     if ( letter == 'D' )
  674.     {
  675. EXIT_DATA *pexit;
  676. int locks;
  677. door = fread_number( fp );
  678. if ( door < 0 || door > 5 )
  679. {
  680.     bug( "Fread_rooms: vnum %d has bad door number.", vnum );
  681.     exit( 1 );
  682. }
  683. pexit = alloc_perm( sizeof(*pexit) );
  684. pexit->description = fread_string( fp );
  685. pexit->keyword = fread_string( fp );
  686. pexit->exit_info = 0;
  687. locks = fread_number( fp );
  688. pexit->key = fread_number( fp );
  689. pexit->vnum = fread_number( fp );
  690. switch ( locks )
  691. {
  692. case 1: pexit->exit_info = EX_ISDOOR;                break;
  693. case 2: pexit->exit_info = EX_ISDOOR | EX_PICKPROOF; break;
  694. }
  695. pRoomIndex->exit[door] = pexit;
  696. top_exit++;
  697.     }
  698.     else if ( letter == 'E' )
  699.     {
  700. EXTRA_DESCR_DATA *ed;
  701. ed = alloc_perm( sizeof(*ed) );
  702. ed->keyword = fread_string( fp );
  703. ed->description = fread_string( fp );
  704. ed->next = pRoomIndex->extra_descr;
  705. pRoomIndex->extra_descr = ed;
  706. top_ed++;
  707.     }
  708.     else
  709.     {
  710. bug( "Load_rooms: vnum %d has flag not 'DES'.", vnum );
  711. exit( 1 );
  712.     }
  713. }
  714. iHash = vnum % MAX_KEY_HASH;
  715. pRoomIndex->next = room_index_hash[iHash];
  716. room_index_hash[iHash] = pRoomIndex;
  717. top_room++;
  718.     }
  719.     return;
  720. }
  721. /*
  722.  * Snarf a shop section.
  723.  */
  724. void load_shops( FILE *fp )
  725. {
  726.     SHOP_DATA *pShop;
  727.     for ( ; ; )
  728.     {
  729. MOB_INDEX_DATA *pMobIndex;
  730. int iTrade;
  731. pShop = alloc_perm( sizeof(*pShop) );
  732. pShop->keeper = fread_number( fp );
  733. if ( pShop->keeper == 0 )
  734.     break;
  735. for ( iTrade = 0; iTrade < MAX_TRADE; iTrade++ )
  736.     pShop->buy_type[iTrade] = fread_number( fp );
  737. pShop->profit_buy = fread_number( fp );
  738. pShop->profit_sell = fread_number( fp );
  739. pShop->open_hour = fread_number( fp );
  740. pShop->close_hour = fread_number( fp );
  741.   fread_to_eol( fp );
  742. pMobIndex = get_mob_index( pShop->keeper );
  743. pMobIndex->pShop = pShop;
  744. if ( shop_first == NULL )
  745.     shop_first = pShop;
  746. if ( shop_last  != NULL )
  747.     shop_last->next = pShop;
  748. shop_last = pShop;
  749. pShop->next = NULL;
  750. top_shop++;
  751.     }
  752.     return;
  753. }
  754. /*
  755.  * Snarf spec proc declarations.
  756.  */
  757. void load_specials( FILE *fp )
  758. {
  759.     for ( ; ; )
  760.     {
  761. MOB_INDEX_DATA *pMobIndex;
  762. char letter;
  763. switch ( letter = fread_letter( fp ) )
  764. {
  765. default:
  766.     bug( "Load_specials: letter '%c' not *MS.", letter );
  767.     exit( 1 );
  768. case 'S':
  769.     return;
  770. case '*':
  771.     break;
  772. case 'M':
  773.     pMobIndex = get_mob_index ( fread_number ( fp ) );
  774.     pMobIndex->spec_fun = spec_lookup ( fread_word   ( fp ) );
  775.     if ( pMobIndex->spec_fun == 0 )
  776.     {
  777. bug( "Load_specials: 'M': vnum %d.", pMobIndex->vnum );
  778. exit( 1 );
  779.     }
  780.     break;
  781. }
  782. fread_to_eol( fp );
  783.     }
  784. }
  785. /*
  786.  * Snarf notes file.
  787.  */
  788. void load_notes( void )
  789. {
  790.     FILE *fp;
  791.     NOTE_DATA *pnotelast;
  792.     if ( ( fp = fopen( NOTE_FILE, "r" ) ) == NULL )
  793. return;
  794.     pnotelast = NULL;
  795.     for ( ; ; )
  796.     {
  797. NOTE_DATA *pnote;
  798. char letter;
  799. do
  800. {
  801.     letter = getc( fp );
  802.     if ( feof(fp) )
  803.     {
  804. fclose( fp );
  805. return;
  806.     }
  807. }
  808. while ( isspace(letter) );
  809. ungetc( letter, fp );
  810. pnote   = alloc_perm( sizeof(*pnote) );
  811. if ( str_cmp( fread_word( fp ), "sender" ) )
  812.     break;
  813. pnote->sender   = fread_string( fp );
  814. if ( str_cmp( fread_word( fp ), "date" ) )
  815.     break;
  816. pnote->date   = fread_string( fp );
  817. if ( str_cmp( fread_word( fp ), "stamp" ) )
  818.     break;
  819. pnote->date_stamp = fread_number( fp );
  820. if ( str_cmp( fread_word( fp ), "to" ) )
  821.     break;
  822. pnote->to_list   = fread_string( fp );
  823. if ( str_cmp( fread_word( fp ), "subject" ) )
  824.     break;
  825. pnote->subject   = fread_string( fp );
  826. if ( str_cmp( fread_word( fp ), "text" ) )
  827.     break;
  828. pnote->text   = fread_string( fp );
  829. if ( note_list == NULL )
  830.     note_list = pnote;
  831. else
  832.     pnotelast->next = pnote;
  833. pnotelast   = pnote;
  834.     }
  835.     strcpy( strArea, NOTE_FILE );
  836.     fpArea = fp;
  837.     bug( "Load_notes: bad key word.", 0 );
  838.     exit( 1 );
  839.     return;
  840. }
  841. /*
  842.  * Translate all room exits from virtual to real.
  843.  * Has to be done after all rooms are read in.
  844.  * Check for bad reverse exits.
  845.  */
  846. void fix_exits( void )
  847. {
  848.     extern const sh_int rev_dir [];
  849.     char buf[MAX_STRING_LENGTH];
  850.     ROOM_INDEX_DATA *pRoomIndex;
  851.     ROOM_INDEX_DATA *to_room;
  852.     EXIT_DATA *pexit;
  853.     EXIT_DATA *pexit_rev;
  854.     int iHash;
  855.     int door;
  856.     for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
  857.     {
  858. for ( pRoomIndex  = room_index_hash[iHash];
  859.       pRoomIndex != NULL;
  860.       pRoomIndex  = pRoomIndex->next )
  861. {
  862.     bool fexit;
  863.     fexit = FALSE;
  864.     for ( door = 0; door <= 5; door++ )
  865.     {
  866. if ( ( pexit = pRoomIndex->exit[door] ) != NULL )
  867. {
  868.     fexit = TRUE;
  869.     if ( pexit->vnum <= 0 )
  870. pexit->to_room = NULL;
  871.     else
  872. pexit->to_room = get_room_index( pexit->vnum );
  873. }
  874.     }
  875.     if ( !fexit )
  876. SET_BIT( pRoomIndex->room_flags, ROOM_NO_MOB );
  877. }
  878.     }
  879. #if 0
  880.     for ( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
  881.     {
  882. for ( pRoomIndex  = room_index_hash[iHash];
  883.       pRoomIndex != NULL;
  884.       pRoomIndex  = pRoomIndex->next )
  885. {
  886.     for ( door = 0; door <= 5; door++ )
  887.     {
  888. if ( ( pexit     = pRoomIndex->exit[door]       ) != NULL
  889. &&   ( to_room   = pexit->to_room               ) != NULL
  890. &&   ( pexit_rev = to_room->exit[rev_dir[door]] ) != NULL
  891. &&   pexit_rev->to_room != pRoomIndex )
  892. {
  893.     sprintf( buf, "Fix_exits: %d:%d -> %d:%d -> %d.",
  894. pRoomIndex->vnum, door,
  895. to_room->vnum,    rev_dir[door],
  896. (pexit_rev->to_room == NULL)
  897.     ? 0 : pexit_rev->to_room->vnum );
  898.     bug( buf, 0 );
  899. }
  900.     }
  901. }
  902.     }
  903. #endif
  904.     return;
  905. }
  906. /*
  907.  * Repopulate areas periodically.
  908.  */
  909. void area_update( void )
  910. {
  911.     AREA_DATA *pArea;
  912.     for ( pArea = area_first; pArea != NULL; pArea = pArea->next )
  913.     {
  914. CHAR_DATA *pch;
  915. if ( ++pArea->age < 3 )
  916.     continue;
  917. /*
  918.  * Check for PC's.
  919.  */
  920. if ( pArea->nplayer > 0 && pArea->age == 15 - 1 )
  921. {
  922.     for ( pch = char_list; pch != NULL; pch = pch->next )
  923.     {
  924. if ( !IS_NPC(pch)
  925. &&   IS_AWAKE(pch)
  926. &&   pch->in_room != NULL
  927. &&   pch->in_room->area == pArea )
  928. {
  929.     send_to_char( "You hear the patter of little feet.nr",
  930. pch );
  931. }
  932.     }
  933. }
  934. /*
  935.  * Check age and reset.
  936.  * Note: Mud School resets every 3 minutes (not 15).
  937.  */
  938. if ( pArea->nplayer == 0 || pArea->age >= 15 )
  939. {
  940.     ROOM_INDEX_DATA *pRoomIndex;
  941.     reset_area( pArea );
  942.     pArea->age = number_range( 0, 3 );
  943.     pRoomIndex = get_room_index( ROOM_VNUM_SCHOOL );
  944.     if ( pRoomIndex != NULL && pArea == pRoomIndex->area )
  945. pArea->age = 15 - 3;
  946. }
  947.     }
  948.     return;
  949. }
  950. /*
  951.  * Reset one area.
  952.  */
  953. void reset_area( AREA_DATA *pArea )
  954. {
  955.     RESET_DATA *pReset;
  956.     CHAR_DATA *mob;
  957.     bool last;
  958.     int level;
  959.     mob  = NULL;
  960.     last = TRUE;
  961.     level = 0;
  962.     for ( pReset = pArea->reset_first; pReset != NULL; pReset = pReset->next )
  963.     {
  964. ROOM_INDEX_DATA *pRoomIndex;
  965. MOB_INDEX_DATA *pMobIndex;
  966. OBJ_INDEX_DATA *pObjIndex;
  967. OBJ_INDEX_DATA *pObjToIndex;
  968. EXIT_DATA *pexit;
  969. OBJ_DATA *obj;
  970. OBJ_DATA *obj_to;
  971. switch ( pReset->command )
  972. {
  973. default:
  974.     bug( "Reset_area: bad command %c.", pReset->command );
  975.     break;
  976. case 'M':
  977.     if ( ( pMobIndex = get_mob_index( pReset->arg1 ) ) == NULL )
  978.     {
  979. bug( "Reset_area: 'M': bad vnum %d.", pReset->arg1 );
  980. continue;
  981.     }
  982.     if ( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL )
  983.     {
  984. bug( "Reset_area: 'R': bad vnum %d.", pReset->arg3 );
  985. continue;
  986.     }
  987.     level = URANGE( 0, pMobIndex->level - 2, LEVEL_HERO );
  988.     if ( pMobIndex->count >= pReset->arg2 )
  989.     {
  990. last = FALSE;
  991. break;
  992.     }
  993.     mob = create_mobile( pMobIndex );
  994.     /*
  995.      * Check for pet shop.
  996.      */
  997.     {
  998. ROOM_INDEX_DATA *pRoomIndexPrev;
  999. pRoomIndexPrev = get_room_index( pRoomIndex->vnum - 1 );
  1000. if ( pRoomIndexPrev != NULL
  1001. &&   IS_SET(pRoomIndexPrev->room_flags, ROOM_PET_SHOP) )
  1002.     SET_BIT(mob->act, ACT_PET);
  1003.     }
  1004.     if ( room_is_dark( pRoomIndex ) )
  1005. SET_BIT(mob->affected_by, AFF_INFRARED);
  1006.     char_to_room( mob, pRoomIndex );
  1007.     level = URANGE( 0, mob->level - 2, LEVEL_HERO );
  1008.     last  = TRUE;
  1009.     break;
  1010. case 'O':
  1011.     if ( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL )
  1012.     {
  1013. bug( "Reset_area: 'O': bad vnum %d.", pReset->arg1 );
  1014. continue;
  1015.     }
  1016.     if ( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL )
  1017.     {
  1018. bug( "Reset_area: 'R': bad vnum %d.", pReset->arg3 );
  1019. continue;
  1020.     }
  1021.     if ( pArea->nplayer > 0
  1022.     ||   count_obj_list( pObjIndex, pRoomIndex->contents ) > 0 )
  1023.     {
  1024. last = FALSE;
  1025. break;
  1026.     }
  1027.     obj       = create_object( pObjIndex, number_fuzzy( level ) );
  1028.     obj->cost = 0;
  1029.     obj_to_room( obj, pRoomIndex );
  1030.     last = TRUE;
  1031.     break;
  1032. case 'P':
  1033.     if ( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL )
  1034.     {
  1035. bug( "Reset_area: 'P': bad vnum %d.", pReset->arg1 );
  1036. continue;
  1037.     }
  1038.     if ( ( pObjToIndex = get_obj_index( pReset->arg3 ) ) == NULL )
  1039.     {
  1040. bug( "Reset_area: 'P': bad vnum %d.", pReset->arg3 );
  1041. continue;
  1042.     }
  1043.     if ( pArea->nplayer > 0
  1044.     || ( obj_to = get_obj_type( pObjToIndex ) ) == NULL
  1045.     ||   count_obj_list( pObjIndex, obj_to->contains ) > 0 )
  1046.     {
  1047. last = FALSE;
  1048. break;
  1049.     }
  1050.     obj = create_object( pObjIndex, number_fuzzy( obj_to->level ) );
  1051.     obj_to_obj( obj, obj_to );
  1052.     last = TRUE;
  1053.     break;
  1054. case 'G':
  1055. case 'E':
  1056.     if ( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL )
  1057.     {
  1058. bug( "Reset_area: 'E' or 'G': bad vnum %d.", pReset->arg1 );
  1059. continue;
  1060.     }
  1061.     if ( !last )
  1062. break;
  1063.     if ( mob == NULL )
  1064.     {
  1065. bug( "Reset_area: 'E' or 'G': null mob for vnum %d.",
  1066.     pReset->arg1 );
  1067. last = FALSE;
  1068. break;
  1069.     }
  1070.     if ( mob->pIndexData->pShop != NULL )
  1071.     {
  1072. int olevel;
  1073. switch ( pObjIndex->item_type )
  1074. {
  1075. default: olevel = 0;                      break;
  1076. case ITEM_PILL: olevel = number_range(  0, 10 ); break;
  1077. case ITEM_POTION: olevel = number_range(  0, 10 ); break;
  1078. case ITEM_SCROLL: olevel = number_range(  5, 15 ); break;
  1079. case ITEM_WAND: olevel = number_range( 10, 20 ); break;
  1080. case ITEM_STAFF: olevel = number_range( 15, 25 ); break;
  1081. case ITEM_ARMOR: olevel = number_range(  5, 15 ); break;
  1082. case ITEM_WEAPON: olevel = number_range(  5, 15 ); break;
  1083. }
  1084. obj = create_object( pObjIndex, olevel );
  1085. SET_BIT( obj->extra_flags, ITEM_INVENTORY );
  1086.     }
  1087.     else
  1088.     {
  1089. obj = create_object( pObjIndex, number_fuzzy( level ) );
  1090.     }
  1091.     obj_to_char( obj, mob );
  1092.     if ( pReset->command == 'E' )
  1093. equip_char( mob, obj, pReset->arg3 );
  1094.     last = TRUE;
  1095.     break;
  1096. case 'D':
  1097.     if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL )
  1098.     {
  1099. bug( "Reset_area: 'D': bad vnum %d.", pReset->arg1 );
  1100. continue;
  1101.     }
  1102.     if ( ( pexit = pRoomIndex->exit[pReset->arg2] ) == NULL )
  1103. break;
  1104.     switch ( pReset->arg3 )
  1105.     {
  1106.     case 0:
  1107. REMOVE_BIT( pexit->exit_info, EX_CLOSED );
  1108. REMOVE_BIT( pexit->exit_info, EX_LOCKED );
  1109. break;
  1110.     case 1:
  1111. SET_BIT(    pexit->exit_info, EX_CLOSED );
  1112. REMOVE_BIT( pexit->exit_info, EX_LOCKED );
  1113. break;
  1114.     case 2:
  1115. SET_BIT(    pexit->exit_info, EX_CLOSED );
  1116. SET_BIT(    pexit->exit_info, EX_LOCKED );
  1117. break;
  1118.     }
  1119.     last = TRUE;
  1120.     break;
  1121. case 'R':
  1122.     if ( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL )
  1123.     {
  1124. bug( "Reset_area: 'R': bad vnum %d.", pReset->arg1 );
  1125. continue;
  1126.     }
  1127.     {
  1128. int d0;
  1129. int d1;
  1130. for ( d0 = 0; d0 < pReset->arg2 - 1; d0++ )
  1131. {
  1132.     d1                   = number_range( d0, pReset->arg2-1 );
  1133.     pexit                = pRoomIndex->exit[d0];
  1134.     pRoomIndex->exit[d0] = pRoomIndex->exit[d1];
  1135.     pRoomIndex->exit[d1] = pexit;
  1136. }
  1137.     }
  1138.     break;
  1139.    case 'C':
  1140.    case 'F':
  1141.       break;
  1142. }
  1143.     }
  1144.     return;
  1145. }
  1146. #define nelems(a) (sizeof (a)/sizeof (a)[0])
  1147. // Calculate a meaningful modifier and amount
  1148. void random_apply( OBJ_DATA *obj, CHAR_DATA *mob )
  1149. {
  1150.    static int attrib_types[] = { APPLY_STR, APPLY_DEX, APPLY_DEX, APPLY_INT,
  1151.       APPLY_INT, APPLY_WIS, APPLY_CON, APPLY_CON, APPLY_CON };
  1152.    static int power_types[] = { APPLY_MANA, APPLY_HIT, APPLY_MOVE, APPLY_AC };
  1153.    static int combat_types[] = { APPLY_HITROLL, APPLY_HITROLL, APPLY_DAMROLL,
  1154.       APPLY_SAVING_SPELL, APPLY_SAVING_SPELL, APPLY_SAVING_BREATH };
  1155.    AFFECT_DATA *paf = alloc_perm( sizeof(*paf) );
  1156.    paf->type      = -1;
  1157.    paf->duration  = -1;
  1158.    paf->bitvector = 0;
  1159.    paf->next      = obj->affected;
  1160.    obj->affected  = paf;
  1161.    switch (number_bits(2)) {
  1162.    case 0:
  1163.       paf->location  = attrib_types[number_range(0, nelems(attrib_types)-1)];
  1164.       paf->modifier  = 1;
  1165.       break;
  1166.    case 1:
  1167.       paf->location  = power_types[number_range(0, nelems(power_types)-1)];
  1168.       paf->modifier  = number_range(mob->level/2, mob->level);
  1169.       break;
  1170.    case 2:
  1171.    case 3:
  1172.       paf->location  = combat_types[number_range(0, nelems(combat_types)-1)];
  1173.       paf->modifier  = number_range(1, mob->level/6+1);
  1174.       break;
  1175.    }
  1176.    SET_BIT(obj->extra_flags, ITEM_MAGIC);
  1177.    // Is item cursed?
  1178.    if (number_percent() <= 5)
  1179.       {
  1180.       paf->modifier = -paf->modifier;
  1181.       SET_BIT(obj->extra_flags, ITEM_NODROP);
  1182.       if (number_percent() <= 15)
  1183.          SET_BIT(obj->extra_flags, ITEM_NOREMOVE);
  1184.       }
  1185. }
  1186. // Jewelry stuff
  1187. static char *adj1[] = { "splendid", "ancient", "dusty", "scratched",
  1188.    "flawed", "burnt", "heavy", "gilded", "spooky", "flaming", "plain",
  1189.    "ornate", "inscrutable", "obscene", "wrinkled" };
  1190. static char *adj2[] = { "diamond", "emerald", "topaz", "wooden", "jade",
  1191.    "white gold", "onyx", "tin", "glass", "marble", "black", "granite" };
  1192. #define MASK_IGNORE     (1<<TAR_IGNORE)
  1193. #define MASK_OFFENSIVE  (1<<TAR_CHAR_OFFENSIVE)
  1194. #define MASK_DEFENSIVE  (1<<TAR_CHAR_DEFENSIVE)
  1195. #define MASK_SELF       (1<<TAR_CHAR_SELF)
  1196. #define MASK_INV        (1<<TAR_OBJ_INV)
  1197. #define CLASS_MAGE       0
  1198. #define CLASS_CLERIC     1
  1199. // Returns a clerical or magical spell of the appropriate (masked) type
  1200. int random_spell( int level, int mask, sh_int *type )
  1201. {
  1202.    extern const struct skill_type skill_table[MAX_SKILL];
  1203.    for ( ;; )
  1204.       {
  1205.       int skill_no = number_range(0, MAX_SKILL-1);
  1206.       if ((skill_table[skill_no].skill_level[CLASS_MAGE] <= level ||
  1207.            skill_table[skill_no].skill_level[CLASS_CLERIC] <= level) &&
  1208.           skill_table[skill_no].spell_fun &&         /* an actual spell? */
  1209.           mask & (1<<skill_table[skill_no].target))  /* appropriate? */
  1210.          {
  1211.          *type = skill_table[skill_no].target;
  1212.          return skill_no;
  1213.          }
  1214.       }
  1215. }
  1216. // Wands/Staves/Potions/Pills and bags
  1217. void wield_random_magic( CHAR_DATA *mob )
  1218. {
  1219.    int item_type = number_range(48, 53);  /* Get template obj from LIMBO.ARE */
  1220.    OBJ_INDEX_DATA *pObjIndex = get_obj_index( item_type );
  1221.    OBJ_DATA *obj = create_object( pObjIndex, number_fuzzy( mob->level ) );
  1222.    sh_int type;
  1223.    int    n_adj1 = number_range(0, nelems(adj1)-1);
  1224.    int    n_adj2 = number_range(0, nelems(adj2)-1);
  1225.    // Potion stuff
  1226.    static char *potions[] = { "bottle", "snifter", "jar", "bulb", "potion" };
  1227.    // Pill stuff
  1228.    static char *pills[] = { "bag of dust", "honeycomb", "root", "leaf",
  1229.       "crystal", "powder packet", "seed" };
  1230.    // Bag types (no wearable belts/backpacks... yet)
  1231.    static char *skins[] = { "lamia skin", "cloth", "leather", "tough leather",
  1232.       "zebra-skin", "gilded" };
  1233.    static char *bags[] = { "bag", "valise", "pail", "basket", "jar",
  1234.       "box", "sack" };
  1235.    char buffer[256];
  1236.    char buf[MAX_STRING_LENGTH];
  1237.    char name[MAX_STRING_LENGTH];
  1238.    switch (item_type) {
  1239.    case 48: /* scroll */
  1240.       sprintf(buffer, "%s %s scroll", adj1[n_adj1], adj2[n_adj2]);
  1241.       obj->value[0] = number_range(obj->level / 2+1, obj->level * 3 / 2+1); /* level */
  1242.       obj->value[0] = URANGE(1, obj->value[0], 36);
  1243.       obj->value[1] = random_spell(obj->value[0],
  1244.          MASK_IGNORE|MASK_OFFENSIVE|MASK_DEFENSIVE|MASK_SELF, &type);
  1245.       if (number_percent() < 50)
  1246.          obj->value[2] = random_spell(obj->value[0], 1<<type, &type);
  1247.       break;
  1248.    case 49: /* wand */
  1249.       sprintf(buffer, "%s %s wand", adj1[n_adj1], adj2[n_adj2]);
  1250.       obj->value[0] = number_range(obj->level / 3 + 1, obj->level * 3 / 2);  /* level */
  1251.       obj->value[0] = URANGE(1, obj->value[0], 36);
  1252.       obj->value[1] = number_fuzzy(obj->level / 2 + 3); /* max charges */
  1253.       obj->value[2] = number_range(1, obj->value[1]);   /* charges left */
  1254.       obj->value[3] = random_spell(obj->value[0], MASK_OFFENSIVE, &type);
  1255.       break;
  1256.    case 50: /* staff */
  1257.       sprintf(buffer, "%s %s staff", adj1[n_adj1], adj2[n_adj2]);
  1258.       obj->value[0] = number_range(obj->level / 4 + 1, obj->level * 3 / 2);  /* level */
  1259.       obj->value[0] = URANGE(1, obj->value[0], 36);
  1260.       obj->value[1] = number_fuzzy(obj->level / 2 + 3); /* max charges */
  1261.       obj->value[2] = number_range(1, obj->value[1]);   /* charges left */
  1262.       obj->value[3] = random_spell(obj->value[0],
  1263.          MASK_IGNORE|MASK_OFFENSIVE|MASK_DEFENSIVE|MASK_SELF, &type);
  1264.       break;
  1265.    case 51: /* potion */
  1266.       sprintf(buffer, "%s %s %s", adj1[n_adj1], adj2[n_adj2],
  1267.          potions[number_range(0, nelems(potions)-1)]);
  1268.       obj->value[0] = number_range(obj->level / 2+1, obj->level * 3 / 2+1); /* level */
  1269.       obj->value[0] = URANGE(1, obj->value[0], 36);
  1270.       obj->value[1] = random_spell(obj->value[0], MASK_DEFENSIVE, &type);
  1271.       if (number_percent() < 50)
  1272.          obj->value[2] = random_spell(obj->value[0], MASK_DEFENSIVE, &type);
  1273.       break;
  1274.    case 52: /* pill */
  1275.       sprintf(buffer, "%s %s %s", adj1[n_adj1], adj2[n_adj2],
  1276.          pills[number_range(0, nelems(pills)-1)]);
  1277.       obj->value[0] = number_range(obj->level / 2+1, obj->level * 3 / 2+1); /* level */
  1278.       obj->value[0] = URANGE(1, obj->value[0], 36);
  1279.       obj->value[1] = random_spell(obj->value[0], MASK_DEFENSIVE, &type);
  1280.       if (number_percent() < 50)
  1281.          obj->value[2] = random_spell(obj->value[0], MASK_DEFENSIVE, &type);
  1282.       break;
  1283.    case 53: /* bag */
  1284.       sprintf(buffer, "%s %s %s", adj1[n_adj1],
  1285.          skins[number_range(0, nelems(skins)-1)],
  1286.          bags[number_range(0, nelems(bags)-1)]);
  1287.       obj->value[0] = number_range(mob->level, mob->level * 25); /* weight */
  1288.       obj->value[1] = number_range(0, 1);
  1289.       obj->value[2] = -1;
  1290.       break;
  1291.    };
  1292.    // Generate the description strings
  1293.    free_string( obj->name );
  1294.    obj->name = str_dup( buffer );
  1295.    sprintf( buf, "a%s %s",
  1296.       (buffer[0] == 'a' || buffer[0] == 'e' || buffer[0] == 'i' ||
  1297.        buffer[0] == 'o' || buffer[0] == 'u') ? "n" : "", buffer );
  1298.    free_string( obj->short_descr );
  1299.    obj->short_descr = str_dup( buf );
  1300.    free_string( obj->description );
  1301.    sprintf( buf, "%s lies here.", obj->short_descr );
  1302.    obj->description = str_dup( buf );
  1303.    // Put the item in the mob's inventory
  1304.    obj_to_char( obj, mob );
  1305. }
  1306. // Anything wearable, and trinkets
  1307. void wield_random_armor( CHAR_DATA *mob )
  1308. {
  1309.    int item_type = number_range(0, MAX_WEAR - 1); /* template from LIMBO.ARE */
  1310.    OBJ_INDEX_DATA *pObjIndex = get_obj_index( item_type + 30 );
  1311.    OBJ_DATA *obj = create_object( pObjIndex, number_fuzzy( mob->level ) );
  1312.    int    n_adj1 = number_range(0, nelems(adj1)-1);
  1313.    int    n_adj2 = number_range(0, nelems(adj2)-1);
  1314.    char *name = "[random]";
  1315.    // Armor stuff
  1316.    static char *armor_types[] = { "leather", "studded leather", "bronze",
  1317.       "chain", "plate", "mithral" };
  1318.    static int armor_mul[] = { 1, 3, 2, 5, 10, 10 };
  1319.    static int armor_div[] = { 1, 2, 1, 1,  1,  3 };
  1320.    // Weapon stuff
  1321.    static char *weapon_types[] = { "sword", "sword", "sword", "sword", "sword",
  1322.       "short sword", "dagger", "dagger", "hammer", "mace", "mace", "whip" };
  1323.    static int weapon_dam[] = { 3, 3, 3, 3, 3, 11, 11, 11, 0, 7, 7, 4 };
  1324.    // Trinket stuff
  1325.    static char *noun[] = { "pebble", "bauble", "stone", "charm", "fetish",
  1326.       "bone", "trinket" };
  1327.    char buffer[64];
  1328.    char buf[MAX_STRING_LENGTH];
  1329.    if (obj->item_type == ITEM_ARMOR)
  1330.       {
  1331.       int ac_type = URANGE(0, mob->level/5, nelems(armor_types)-1);
  1332.       name = armor_types[ac_type];
  1333.       obj->weight *= armor_mul[ac_type];
  1334.       obj->weight /= armor_div[ac_type];
  1335.       if (number_percent() < mob->level / 3)
  1336.          random_apply(obj, mob);
  1337.       }
  1338.    else if (obj->item_type == ITEM_WEAPON)
  1339.       {
  1340.       int wea_type = number_range(0, nelems(weapon_types)-1);
  1341.       name = weapon_types[wea_type];
  1342.       obj->value[3] = weapon_dam[wea_type];
  1343.       }
  1344.    else if (obj->item_type == ITEM_TREASURE)
  1345.       {
  1346.       if (number_percent() < mob->level)
  1347.          {
  1348.          random_apply(obj, mob);
  1349.          if (number_percent() < mob->level / 3)
  1350.             random_apply(obj, mob);
  1351.          }
  1352.       if (obj->wear_flags & ITEM_HOLD) /* trinket? */
  1353.          sprintf(buffer, "%s %s %s", adj1[n_adj1],
  1354.             adj2[n_adj2],
  1355.             noun[number_range(0, nelems(noun)-1)]);
  1356.       else /* no, necklace or something */
  1357.          sprintf(buffer, "%s %s", adj1[n_adj1],
  1358.             adj2[n_adj2]);
  1359.       name = buffer;
  1360.       }
  1361.    sprintf( buf, obj->short_descr, name );
  1362.    free_string( obj->short_descr );
  1363.    obj->short_descr = str_dup( buf );
  1364.    obj_to_char( obj, mob );
  1365.    equip_char( mob, obj, item_type );
  1366. }
  1367. /*
  1368.  * Create an instance of a mobile.
  1369.  */
  1370. CHAR_DATA *create_mobile( MOB_INDEX_DATA *pMobIndex )
  1371. {
  1372.     CHAR_DATA *mob;
  1373.     if ( pMobIndex == NULL )
  1374.     {
  1375. bug( "Create_mobile: NULL pMobIndex.", 0 );
  1376. exit( 1 );
  1377.     }
  1378.     if ( char_free == NULL )
  1379.     {
  1380. mob = alloc_perm( sizeof(*mob) );
  1381.     }
  1382.     else
  1383.     {
  1384. mob = char_free;
  1385. char_free = char_free->next;
  1386.     }
  1387.     clear_char( mob );
  1388.     mob->pIndexData = pMobIndex;
  1389.     mob->name = pMobIndex->player_name;
  1390.     mob->short_descr = pMobIndex->short_descr;
  1391.     mob->long_descr = pMobIndex->long_descr;
  1392.     mob->description = pMobIndex->description;
  1393.     mob->spec_fun = pMobIndex->spec_fun;
  1394.     mob->prompt         = "<%h %m %v>";
  1395.     mob->level = number_fuzzy( pMobIndex->level );
  1396.     mob->act = pMobIndex->act;
  1397.     mob->affected_by = pMobIndex->affected_by;
  1398.     mob->alignment = pMobIndex->alignment;
  1399.     mob->sex = pMobIndex->sex;
  1400. /*
  1401.  * IMPORTANT !!! to add gold as defined in areas to your MUD, all you
  1402.  *               need to do is remove the coments from the following 
  1403.  *               line.
  1404.  */
  1405.  /* mob->gold           = pMobIndex->gold; */
  1406.     mob->armor = interpolate( mob->level, 100, -100 );
  1407.     mob->max_hit = mob->level * 8 + number_range(
  1408. mob->level * mob->level / 4,
  1409. mob->level * mob->level );
  1410.     mob->hit = mob->max_hit;
  1411. #if 0
  1412. //    if (number_percent() <= 10)
  1413.        wield_random_magic( mob );
  1414. //    else
  1415. //       wield_random_armor( mob );
  1416. #endif
  1417.     /*
  1418.      * Insert in list.
  1419.      */
  1420.     mob->next = char_list;
  1421.     char_list = mob;
  1422.     pMobIndex->count++;
  1423.     return mob;
  1424. }
  1425. /*
  1426.  * Create an instance of an object.
  1427.  */
  1428. OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, int level )
  1429. {
  1430.     static OBJ_DATA obj_zero;
  1431.     OBJ_DATA *obj;
  1432.     if ( pObjIndex == NULL )
  1433.     {
  1434. bug( "Create_object: NULL pObjIndex.", 0 );
  1435. exit( 1 );
  1436.     }
  1437.     if ( obj_free == NULL )
  1438.     {
  1439. obj = alloc_perm( sizeof(*obj) );
  1440.     }
  1441.     else
  1442.     {
  1443. obj = obj_free;
  1444. obj_free = obj_free->next;
  1445.     }
  1446.     *obj = obj_zero;
  1447.     obj->pIndexData = pObjIndex;
  1448.     obj->in_room = NULL;
  1449.     obj->level = level;
  1450.     obj->wear_loc = -1;
  1451.     obj->name = pObjIndex->name;
  1452.     obj->short_descr = pObjIndex->short_descr;
  1453.     obj->description = pObjIndex->description;
  1454.     obj->item_type = pObjIndex->item_type;
  1455.     obj->extra_flags = pObjIndex->extra_flags;
  1456.     obj->wear_flags = pObjIndex->wear_flags;
  1457.     obj->value[0] = pObjIndex->value[0];
  1458.     obj->value[1] = pObjIndex->value[1];
  1459.     obj->value[2] = pObjIndex->value[2];
  1460.     obj->value[3] = pObjIndex->value[3];
  1461.     obj->weight = pObjIndex->weight;
  1462.     obj->cost = number_fuzzy( 10 )
  1463. * number_fuzzy( level ) * number_fuzzy( level );
  1464.     /*
  1465.      * Mess with object properties.
  1466.      */
  1467.     switch ( obj->item_type )
  1468.     {
  1469.     default:
  1470. bug( "Read_object: vnum %d bad type.", pObjIndex->vnum );
  1471. break;
  1472.     case ITEM_LIGHT:
  1473.     case ITEM_TREASURE:
  1474.     case ITEM_FURNITURE:
  1475.     case ITEM_TRASH:
  1476.     case ITEM_CONTAINER:
  1477.     case ITEM_DRINK_CON:
  1478.     case ITEM_KEY:
  1479.     case ITEM_FOOD:
  1480.     case ITEM_BOAT:
  1481.     case ITEM_CORPSE_NPC:
  1482.     case ITEM_CORPSE_PC:
  1483.     case ITEM_FOUNTAIN:
  1484. break;
  1485.     case ITEM_SCROLL:
  1486. obj->value[0] = number_fuzzy( obj->value[0] );
  1487. break;
  1488.     case ITEM_WAND:
  1489.     case ITEM_STAFF:
  1490. obj->value[0] = number_fuzzy( obj->value[0] );
  1491. obj->value[1] = number_fuzzy( obj->value[1] );
  1492. obj->value[2] = obj->value[1];
  1493. break;
  1494.     case ITEM_WEAPON:
  1495. obj->value[1] = number_fuzzy( number_fuzzy( 1 * level / 4 + 2 ) );
  1496. obj->value[2] = number_fuzzy( number_fuzzy( 3 * level / 4 + 6 ) );
  1497. break;
  1498.     case ITEM_ARMOR:
  1499. obj->value[0] = number_fuzzy( level / 4 + 2 );
  1500. break;
  1501.     case ITEM_POTION:
  1502.     case ITEM_PILL:
  1503. obj->value[0] = number_fuzzy( number_fuzzy( obj->value[0] ) );
  1504. break;
  1505.     case ITEM_MONEY:
  1506. obj->value[0] = obj->cost;
  1507. break;
  1508.     }
  1509.     obj->next = object_list;
  1510.     object_list = obj;
  1511.     pObjIndex->count++;
  1512.     return obj;
  1513. }
  1514. /*
  1515.  * Clear a new character.
  1516.  */
  1517. void clear_char( CHAR_DATA *ch )
  1518. {
  1519.     static CHAR_DATA ch_zero;
  1520.     *ch = ch_zero;
  1521.     ch->name = &str_empty[0];
  1522.     ch->short_descr = &str_empty[0];
  1523.     ch->long_descr = &str_empty[0];
  1524.     ch->description = &str_empty[0];
  1525.     ch->prompt                  = &str_empty[0];
  1526.     ch->last_note               = 0;
  1527.     ch->logon = current_time;
  1528.     ch->armor = 100;
  1529.     ch->position = POS_STANDING;
  1530.     ch->practice = 21;
  1531.     ch->hit = 20;
  1532.     ch->max_hit = 20;
  1533.     ch->mana = 100;
  1534.     ch->max_mana = 100;
  1535.     ch->move = 100;
  1536.     ch->max_move = 100;
  1537.     return;
  1538. }
  1539. /*
  1540.  * Free a character.
  1541.  */
  1542. void free_char( CHAR_DATA *ch )
  1543. {
  1544.     OBJ_DATA *obj;
  1545.     OBJ_DATA *obj_next;
  1546.     AFFECT_DATA *paf;
  1547.     AFFECT_DATA *paf_next;
  1548.     for ( obj = ch->carrying; obj != NULL; obj = obj_next )
  1549.     {
  1550. obj_next = obj->next_content;
  1551. extract_obj( obj );
  1552.     }
  1553.     for ( paf = ch->affected; paf != NULL; paf = paf_next )
  1554.     {
  1555. paf_next = paf->next;
  1556. affect_remove( ch, paf );
  1557.     }
  1558.     free_string( ch->name );
  1559.     free_string( ch->short_descr );
  1560.     free_string( ch->long_descr );
  1561.     free_string( ch->description );
  1562.     if ( ch->pcdata != NULL )
  1563.     {
  1564. free_string( ch->pcdata->pwd );
  1565. free_string( ch->pcdata->bamfin );
  1566. free_string( ch->pcdata->bamfout );
  1567. free_string( ch->pcdata->title );
  1568. ch->pcdata->next = pcdata_free;
  1569. pcdata_free      = ch->pcdata;
  1570.     }
  1571.     ch->next      = char_free;
  1572.     char_free      = ch;
  1573.     return;
  1574. }
  1575. /*
  1576.  * Get an extra description from a list.
  1577.  */
  1578. char *get_extra_descr( const char *name, EXTRA_DESCR_DATA *ed )
  1579. {
  1580.     for ( ; ed != NULL; ed = ed->next )
  1581.     {
  1582. if ( is_name( name, ed->keyword ) )
  1583.     return ed->description;
  1584.     }
  1585.     return NULL;
  1586. }
  1587. /*
  1588.  * Translates mob virtual number to its mob index struct.
  1589.  * Hash table lookup.
  1590.  */
  1591. MOB_INDEX_DATA *get_mob_index( int vnum )
  1592. {
  1593.     MOB_INDEX_DATA *pMobIndex;
  1594.     for ( pMobIndex  = mob_index_hash[vnum % MAX_KEY_HASH];
  1595.   pMobIndex != NULL;
  1596.   pMobIndex  = pMobIndex->next )
  1597.     {
  1598. if ( pMobIndex->vnum == vnum )
  1599.     return pMobIndex;
  1600.     }
  1601.     if ( fBootDb )
  1602.     {
  1603. bug( "Get_mob_index: bad vnum %d.", vnum );
  1604. exit( 1 );
  1605.     }
  1606.     return NULL;
  1607. }
  1608. /*
  1609.  * Translates mob virtual number to its obj index struct.
  1610.  * Hash table lookup.
  1611.  */
  1612. OBJ_INDEX_DATA *get_obj_index( int vnum )
  1613. {
  1614.     OBJ_INDEX_DATA *pObjIndex;
  1615.     for ( pObjIndex  = obj_index_hash[vnum % MAX_KEY_HASH];
  1616.   pObjIndex != NULL;
  1617.   pObjIndex  = pObjIndex->next )
  1618.     {
  1619. if ( pObjIndex->vnum == vnum )
  1620.     return pObjIndex;
  1621.     }
  1622.     if ( fBootDb )
  1623.     {
  1624. bug( "Get_obj_index: bad vnum %d.", vnum );
  1625. exit( 1 );
  1626.     }
  1627.     return NULL;
  1628. }
  1629. /*
  1630.  * Translates mob virtual number to its room index struct.
  1631.  * Hash table lookup.
  1632.  */
  1633. ROOM_INDEX_DATA *get_room_index( int vnum )
  1634. {
  1635.     ROOM_INDEX_DATA *pRoomIndex;
  1636.     for ( pRoomIndex  = room_index_hash[vnum % MAX_KEY_HASH];
  1637.   pRoomIndex != NULL;
  1638.   pRoomIndex  = pRoomIndex->next )
  1639.     {
  1640. if ( pRoomIndex->vnum == vnum )
  1641.     return pRoomIndex;
  1642.     }
  1643.     if ( fBootDb && !fIgnoreUnconnected)
  1644.     {
  1645. bug( "Get_room_index: bad vnum %d.", vnum );
  1646. exit( 1 );
  1647.     }
  1648.     return NULL;
  1649. }
  1650. /*
  1651.  * Read a letter from a file.
  1652.  */
  1653. char fread_letter( FILE *fp )
  1654. {
  1655.     char c;
  1656.     do
  1657.     {
  1658. c = getc( fp );
  1659.     }
  1660.     while ( isspace(c) );
  1661.     return c;
  1662. }
  1663. /*
  1664.  * Read a number from a file.
  1665.  */
  1666. int fread_number( FILE *fp )
  1667. {
  1668.     int number;
  1669.     bool sign;
  1670.     char c;
  1671.     do
  1672.     {
  1673. c = getc( fp );
  1674.     }
  1675.     while ( isspace(c) );
  1676.     number = 0;
  1677.     sign   = FALSE;
  1678.     if ( c == '+' )
  1679.     {
  1680. c = getc( fp );
  1681.     }
  1682.     else if ( c == '-' )
  1683.     {
  1684. sign = TRUE;
  1685. c = getc( fp );
  1686.     }
  1687.     if ( !isdigit(c) )
  1688.     {
  1689. bug( "Fread_number: bad format.", 0 );
  1690. exit( 1 );
  1691.     }
  1692.     while ( isdigit(c) )
  1693.     {
  1694. number = number * 10 + c - '0';
  1695. c      = getc( fp );
  1696.     }
  1697.     if ( sign )
  1698. number = 0 - number;
  1699.     if ( c == '|' )
  1700. number += fread_number( fp );
  1701.     else if ( c != ' ' )
  1702. ungetc( c, fp );
  1703.     return number;
  1704. }
  1705. /*
  1706.  * Read and allocate space for a string from a file.
  1707.  * These strings are read-only and shared.
  1708.  * Strings are hashed:
  1709.  *   each string prepended with hash pointer to prev string,
  1710.  *   hash code is simply the string length.
  1711.  * This function takes 40% to 50% of boot-up time.
  1712.  */
  1713. char *fread_string( FILE *fp )
  1714. {
  1715.     char *plast;
  1716.     char c;
  1717.     plast = top_string + sizeof(char *);
  1718.     if ( plast > &string_space[MAX_STRING - MAX_STRING_LENGTH] )
  1719.     {
  1720. bug( "Fread_string: MAX_STRING %d exceeded.", MAX_STRING );
  1721. exit( 1 );
  1722.  }
  1723.  /*
  1724.   * Skip blanks.
  1725.   * Read first char.
  1726.   */
  1727.  do
  1728.  {
  1729. c = getc( fp );
  1730.  }
  1731.  while ( isspace(c) );
  1732.  if ( ( *plast++ = c ) == '~' )
  1733. return &str_empty[0];
  1734.  for ( ;; )
  1735.  {
  1736. /*
  1737.  * Back off the char type lookup,
  1738.  *   it was too dirty for portability.
  1739.  *   -- Furey
  1740.  */
  1741. switch ( *plast = getc( fp ) )
  1742. {
  1743. default:
  1744.  plast++;
  1745.  break;
  1746. case EOF:
  1747.  bug( "Fread_string: EOF", 0 );
  1748.  exit( 1 );
  1749.  break;
  1750. case 'n':
  1751.  plast++;
  1752.  *plast++ = 'r';
  1753.  break;
  1754. case 'r':
  1755.  break;
  1756. case '~':
  1757.  plast++;
  1758.  {
  1759. union
  1760. {
  1761.  char * pc;
  1762.  char rgc[sizeof(char *)];
  1763. } u1;
  1764. int ic;
  1765. int iHash;
  1766. char *pHash;
  1767. char *pHashPrev;
  1768. char *pString;
  1769. plast[-1] = '';
  1770. iHash     = UMIN( MAX_KEY_HASH - 1, plast - 1 - top_string );
  1771. for ( pHash = string_hash[iHash]; pHash; pHash = pHashPrev )
  1772. {
  1773.  for ( ic = 0; ic < sizeof(char *); ic++ )
  1774. u1.rgc[ic] = pHash[ic];
  1775.  pHashPrev = u1.pc;
  1776.  pHash    += sizeof(char *);
  1777.  if ( top_string[sizeof(char *)] == pHash[0]
  1778.  &&   !strcmp( top_string+sizeof(char *)+1, pHash+1 ) )
  1779. return pHash;
  1780. }
  1781. if ( fBootDb )
  1782. {
  1783.  pString = top_string;
  1784.  top_string = plast;
  1785.  u1.pc = string_hash[iHash];
  1786.  for ( ic = 0; ic < sizeof(char *); ic++ )
  1787. pString[ic] = u1.rgc[ic];
  1788.  string_hash[iHash] = pString;
  1789.  nAllocString += 1;
  1790.  sAllocString += top_string - pString;
  1791.  return pString + sizeof(char *);
  1792. }
  1793. else
  1794. {
  1795.  return str_dup( top_string + sizeof(char *) );
  1796. }
  1797.  }
  1798. }
  1799.  }
  1800. }
  1801. /*
  1802.  * Read to end of line (for comments).
  1803.  */
  1804. void fread_to_eol( FILE *fp )
  1805. {
  1806.     char c;
  1807.     do
  1808.     {
  1809. c = getc( fp );
  1810.     }
  1811.     while ( c != 'n' && c != 'r' );
  1812.     do
  1813.     {
  1814. c = getc( fp );
  1815.     }
  1816.     while ( c == 'n' || c == 'r' );
  1817.     ungetc( c, fp );
  1818.     return;
  1819. }
  1820. /*
  1821.  * Read one word (into static buffer).
  1822.  */
  1823. char *fread_word( FILE *fp )
  1824. {
  1825.     static char word[MAX_INPUT_LENGTH];
  1826.     char *pword;
  1827.     char cEnd;
  1828.     do
  1829.     {
  1830. cEnd = getc( fp );
  1831.     }
  1832.     while ( isspace( cEnd ) );
  1833.     if ( cEnd == ''' || cEnd == '"' )
  1834.     {
  1835. pword   = word;
  1836.     }
  1837.     else
  1838.     {
  1839. word[0] = cEnd;
  1840. pword   = word+1;
  1841. cEnd    = ' ';
  1842.     }
  1843.     for ( ; pword < word + MAX_INPUT_LENGTH; pword++ )
  1844.     {
  1845. *pword = getc( fp );
  1846. if ( cEnd == ' ' ? isspace(*pword) : *pword == cEnd )
  1847. {
  1848.     if ( cEnd == ' ' )
  1849. ungetc( *pword, fp );
  1850.     *pword = '';
  1851.     return word;
  1852. }
  1853.     }
  1854.     bug( "Fread_word: word too long.", 0 );
  1855.     exit( 1 );
  1856.     return NULL;
  1857. }
  1858. /*
  1859.  * Allocate some ordinary memory,
  1860.  *   with the expectation of freeing it someday.
  1861.  */
  1862. void *alloc_mem( int sMem )
  1863. {
  1864. #if 0 // %%%
  1865.     return malloc(sMem);
  1866. #else
  1867.     void *pMem;
  1868.     int iList;
  1869.     sMem += 2 * sizeof (int); // @@@
  1870.     for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
  1871.     {
  1872. if ( sMem <= rgSizeList[iList] )
  1873.     break;
  1874.     }
  1875.     if ( iList == MAX_MEM_LIST )
  1876.     {
  1877. #if 1 // @@@
  1878. bug( "Alloc_mem: size %d too large.", sMem );
  1879. exit( 1 );
  1880. #else
  1881.    char szBuffer[256];
  1882.    wsprintf(szBuffer, "alloc_mem(%d) to large.  Continue?", sMem);
  1883.    if (MessageBox(0, szBuffer, "Merc22", MB_ICONQUESTION|MB_YESNO) == IDYES)
  1884.       return 0;
  1885.    else
  1886.       {
  1887.       DebugBreak();
  1888.       exit( 1 );
  1889.       }
  1890. #endif
  1891.     }
  1892.     if ( rgFreeList[iList] == NULL )
  1893.     {
  1894. pMem   = alloc_perm( rgSizeList[iList] );
  1895.     }
  1896.     else
  1897.     {
  1898. pMem              = rgFreeList[iList];
  1899. rgFreeList[iList] = * ((void **) rgFreeList[iList]);
  1900.     }
  1901.     ((int *) pMem)[0] = 0x55555555; // @@@
  1902.     ((int *) pMem)[1] = sMem; // @@@
  1903.     return ((int *) pMem) + 2; // @@@
  1904. //    return pMem; // @@@
  1905. #endif
  1906. }
  1907. /*
  1908.  * Free some memory.
  1909.  * Recycle it back onto the free list for blocks of that size.
  1910.  */
  1911. void free_mem( void *pMem, int sMem )
  1912. {
  1913. #if 0 // %%%
  1914.     free(pMem);
  1915. #else
  1916.     int iList;
  1917. #if 1 // @@@
  1918.     ((int *)pMem) -= 2;
  1919.     sMem += 2 * sizeof (int);
  1920.     if (((int *) pMem)[0] == 0xaaaaaaaa)
  1921.     {
  1922. bug( "Free_mem: this block was already freed.", 0 );
  1923. exit( 1 );
  1924.     }
  1925.     if (((int *) pMem)[0] != 0x55555555)
  1926.     {
  1927. bug( "Free_mem: invalid key.", 0 );
  1928. exit( 1 );
  1929.     }
  1930.     if (((int *) pMem)[1] != sMem)
  1931.     {
  1932. bug( "Free_mem: invalid size.", 0 );
  1933. exit( 1 );
  1934.     }
  1935.     ((int *) pMem)[0] = 0xaaaaaaaa;
  1936. #endif
  1937.     for ( iList = 0; iList < MAX_MEM_LIST; iList++ )
  1938.     {
  1939. if ( sMem <= rgSizeList[iList] )
  1940.     break;
  1941.     }
  1942.     if ( iList == MAX_MEM_LIST )
  1943.     {
  1944. bug( "Free_mem: size %d too large.", sMem );
  1945. exit( 1 );
  1946.     }
  1947.     pMem = memset( pMem, 0, sMem );
  1948.     * ((void **) pMem) = rgFreeList[iList];
  1949.     rgFreeList[iList]  = pMem;
  1950.     return;
  1951. #endif
  1952. }
  1953. /*
  1954.  * Allocate some permanent memory.
  1955.  * Permanent memory is never freed,
  1956.  *   pointers into it may be copied safely.
  1957.  */
  1958. void *alloc_perm( int sMem )
  1959. {
  1960.     static char *pMemPerm;
  1961.     static int iMemPerm;
  1962.     void *pMem;
  1963.     while ( sMem % sizeof(long) != 0 )
  1964. sMem++;
  1965.     if ( sMem > MAX_PERM_BLOCK )
  1966.     {
  1967. bug( "Alloc_perm: %d too large.", sMem );
  1968. exit( 1 );
  1969.     }
  1970.     if ( pMemPerm == NULL || iMemPerm + sMem > MAX_PERM_BLOCK )
  1971.     {
  1972. iMemPerm = 0;
  1973. if ( ( pMemPerm = calloc( 1, MAX_PERM_BLOCK ) ) == NULL )
  1974. {
  1975.     perror( "Alloc_perm" );
  1976.     exit( 1 );
  1977. }
  1978.     }
  1979.     pMem        = pMemPerm + iMemPerm;
  1980.     iMemPerm   += sMem;
  1981.     nAllocPerm += 1;
  1982.     sAllocPerm += sMem;
  1983.     return pMem;
  1984. }
  1985. /*
  1986.  * Duplicate a string into dynamic memory.
  1987.  * Fread_strings are read-only and shared.
  1988.  */
  1989. char *str_dup( const char *str )
  1990. {
  1991.     char *str_new;
  1992. #if 1 // %%%
  1993.     if ( str[0] == '' )
  1994. return &str_empty[0];
  1995.     if ( str >= string_space && str < top_string )
  1996. return (char *) str;
  1997. #endif
  1998.     str_new = alloc_mem( strlen(str) + 1 );
  1999.     strcpy( str_new, str );
  2000.     return str_new;
  2001. }
  2002. /*
  2003.  * Free a string.
  2004.  * Null is legal here to simplify callers.
  2005.  * Read-only shared strings are not touched.
  2006.  */
  2007. void free_string( char *pstr )
  2008. {
  2009.     if ( pstr == NULL
  2010.     ||   pstr == &str_empty[0]
  2011.     || ( pstr >= string_space && pstr < top_string ) )
  2012. return;
  2013.     free_mem( pstr, strlen(pstr) + 1 );
  2014.     return;
  2015. }
  2016. //#if 0
  2017. void do_areas( CHAR_DATA *ch, char *argument )
  2018. {
  2019.     char buf[MAX_STRING_LENGTH];
  2020.     AREA_DATA *pArea1;
  2021.     AREA_DATA *pArea2;
  2022.     int iArea;
  2023.     int iAreaHalf;
  2024.     iAreaHalf = (top_area + 1) / 2;
  2025.     pArea1    = area_first;
  2026.     pArea2    = area_first;
  2027.     for ( iArea = 0; iArea < iAreaHalf; iArea++ )
  2028. pArea2 = pArea2->next;
  2029.     for ( iArea = 0; iArea < iAreaHalf; iArea++ )
  2030.     {
  2031. sprintf( buf, "%-39s%-39snr",
  2032.     pArea1->name, (pArea2 != NULL) ? pArea2->name : "" );
  2033. send_to_char( buf, ch );
  2034. pArea1 = pArea1->next;
  2035. if ( pArea2 != NULL )
  2036.     pArea2 = pArea2->next;
  2037.     }
  2038.     return;
  2039. }
  2040. void do_memory( CHAR_DATA *ch, char *argument )
  2041. {
  2042.     char buf[MAX_STRING_LENGTH];
  2043.     sprintf( buf, "Affects %5dnr", top_affect    ); send_to_char( buf, ch );
  2044.     sprintf( buf, "Areas   %5dnr", top_area      ); send_to_char( buf, ch );
  2045.     sprintf( buf, "ExDes   %5dnr", top_ed        ); send_to_char( buf, ch );
  2046.     sprintf( buf, "Exits   %5dnr", top_exit      ); send_to_char( buf, ch );
  2047.     sprintf( buf, "Helps   %5dnr", top_help      ); send_to_char( buf, ch );
  2048.     sprintf( buf, "Mobs    %5dnr", top_mob_index ); send_to_char( buf, ch );
  2049.     sprintf( buf, "Objs    %5dnr", top_obj_index ); send_to_char( buf, ch );
  2050.  sprintf( buf, "Resets  %5dnr", top_reset     ); send_to_char( buf, ch );
  2051.  sprintf( buf, "Rooms   %5dnr", top_room      ); send_to_char( buf, ch );
  2052.  sprintf( buf, "Shops   %5dnr", top_shop      ); send_to_char( buf, ch );
  2053.  sprintf( buf, "Strings %5d strings of %7d bytes (max %d).nr",
  2054. nAllocString, sAllocString, MAX_STRING );
  2055.  send_to_char( buf, ch );
  2056.  sprintf( buf, "Perms   %5d blocks  of %7d bytes.nr",
  2057. nAllocPerm, sAllocPerm );
  2058.  send_to_char( buf, ch );
  2059.  return;
  2060. }
  2061. //#endif
  2062. /*
  2063.  * Stick a little fuzz on a number.
  2064.  */
  2065. int number_fuzzy( int number )
  2066. {
  2067.     switch ( number_bits( 2 ) )
  2068.     {
  2069.     case 0:  number -= 1; break;
  2070.     case 3:  number += 1; break;
  2071.     }
  2072.     return UMAX( 1, number );
  2073. }
  2074. /*
  2075.  * Generate a random number.
  2076.  */
  2077. int number_range( int from, int to )
  2078. {
  2079.     int power;
  2080.     int number;
  2081.     if ( ( to = to - from + 1 ) <= 1 )
  2082. return from;
  2083.     for ( power = 2; power < to; power <<= 1 )
  2084. ;
  2085.     while ( ( number = number_mm( ) & (power - 1) ) >= to )
  2086. ;
  2087.     return from + number;
  2088. }
  2089. /*
  2090.  * Generate a percentile roll.
  2091.  */
  2092. int number_percent( void )
  2093. {
  2094.     int percent;
  2095.     while ( ( percent = number_mm( ) & (128-1) ) > 99 )
  2096. ;
  2097.     return 1 + percent;
  2098. }
  2099. /*
  2100.  * Generate a random door.
  2101.  */
  2102. int number_door( void )
  2103. {
  2104.     int door;
  2105.     while ( ( door = number_mm( ) & (8-1) ) > 5 )
  2106. ;
  2107.     return door;
  2108. }
  2109. int number_bits( int width )
  2110. {
  2111.     return number_mm( ) & ( ( 1 << width ) - 1 );
  2112. }
  2113. /*
  2114.  * I've gotten too many bad reports on OS-supplied random number generators.
  2115.  * This is the Mitchell-Moore algorithm from Knuth Volume II.
  2116.  * Best to leave the constants alone unless you've read Knuth.
  2117.  * -- Furey
  2118.  */
  2119. static int rgiState[2+55];
  2120. void init_mm( )
  2121. {
  2122.     int *piState;
  2123.     int iState;
  2124.     piState = &rgiState[2];
  2125.     piState[-2] = 55 - 55;
  2126.     piState[-1] = 55 - 24;
  2127.     piState[0] = ((int) current_time) & ((1 << 30) - 1);
  2128.     piState[1] = 1;
  2129.     for ( iState = 2; iState < 55; iState++ )
  2130.     {
  2131. piState[iState] = (piState[iState-1] + piState[iState-2])
  2132. & ((1 << 30) - 1);
  2133.     }
  2134.     return;
  2135. }
  2136. int number_mm( void )
  2137. {
  2138.     int *piState;
  2139.     int iState1;
  2140.     int iState2;
  2141.     int iRand;
  2142.     piState = &rgiState[2];
  2143.     iState1   = piState[-2];
  2144.     iState2   = piState[-1];
  2145.     iRand   = (piState[iState1] + piState[iState2])
  2146. & ((1 << 30) - 1);
  2147.     piState[iState1] = iRand;
  2148.     if ( ++iState1 == 55 )
  2149. iState1 = 0;
  2150.     if ( ++iState2 == 55 )
  2151. iState2 = 0;
  2152.     piState[-2] = iState1;
  2153.     piState[-1] = iState2;
  2154.     return iRand >> 6;
  2155. }
  2156. /*
  2157.  * Roll some dice.
  2158.  */
  2159. int dice( int number, int size )
  2160. {
  2161.     int idice;
  2162.     int sum;
  2163.     switch ( size )
  2164.     {
  2165.     case 0: return 0;
  2166.     case 1: return number;
  2167.     }
  2168.     for ( idice = 0, sum = 0; idice < number; idice++ )
  2169. sum += number_range( 1, size );
  2170.     return sum;
  2171. }
  2172. /*
  2173.  * Simple linear interpolation.
  2174.  */
  2175. int interpolate( int level, int value_00, int value_32 )
  2176. {
  2177.     return value_00 + level * (value_32 - value_00) / 32;
  2178. }
  2179. /*
  2180.  * Removes the tildes from a string.
  2181.  * Used for player-entered strings that go into disk files.
  2182.  */
  2183. void smash_tilde( char *str )
  2184. {
  2185.     for ( ; *str != ''; str++ )
  2186.     {
  2187. if ( *str == '~' )
  2188.     *str = '-';
  2189.     }
  2190.     return;
  2191. }
  2192. /*
  2193.  * Compare strings, case insensitive.
  2194.  * Return TRUE if different
  2195.  *   (compatibility with historical functions).
  2196.  */
  2197. bool str_cmp( const char *astr, const char *bstr )
  2198. {
  2199.     if ( astr == NULL )
  2200.     {
  2201. bug( "Str_cmp: null astr.", 0 );
  2202. return TRUE;
  2203.     }
  2204.     if ( bstr == NULL )
  2205.     {
  2206. bug( "Str_cmp: null bstr.", 0 );
  2207. return TRUE;
  2208.     }
  2209.     for ( ; *astr || *bstr; astr++, bstr++ )
  2210.     {
  2211. if ( LOWER(*astr) != LOWER(*bstr) )
  2212.     return TRUE;
  2213.     }
  2214.     return FALSE;
  2215. }
  2216. /*
  2217.  * Compare strings, case insensitive, for prefix matching.
  2218.  * Return TRUE if astr not a prefix of bstr
  2219.  *   (compatibility with historical functions).
  2220.  */
  2221. bool str_prefix( const char *astr, const char *bstr )
  2222. {
  2223.     if ( astr == NULL )
  2224.     {
  2225. bug( "Strn_cmp: null astr.", 0 );
  2226. return TRUE;
  2227.     }
  2228.     if ( bstr == NULL )
  2229.     {
  2230. bug( "Strn_cmp: null bstr.", 0 );
  2231. return TRUE;
  2232.     }
  2233.     for ( ; *astr; astr++, bstr++ )
  2234.     {
  2235. if ( LOWER(*astr) != LOWER(*bstr) )
  2236.     return TRUE;
  2237.     }
  2238.     return FALSE;
  2239. }
  2240. /*
  2241.  * Compare strings, case insensitive, for match anywhere.
  2242.  * Returns TRUE is astr not part of bstr.
  2243.  *   (compatibility with historical functions).
  2244.  */
  2245. bool str_infix( const char *astr, const char *bstr )
  2246. {
  2247.     int sstr1;
  2248.     int sstr2;
  2249.     int ichar;
  2250.     char c0;
  2251.     if ( ( c0 = LOWER(astr[0]) ) == '' )
  2252. return FALSE;
  2253.     sstr1 = strlen(astr);
  2254.     sstr2 = strlen(bstr);
  2255.     for ( ichar = 0; ichar <= sstr2 - sstr1; ichar++ )
  2256.     {
  2257. if ( c0 == LOWER(bstr[ichar]) && !str_prefix( astr, bstr + ichar ) )
  2258.     return FALSE;
  2259.     }
  2260.     return TRUE;
  2261. }
  2262. /*
  2263.  * Compare strings, case insensitive, for suffix matching.
  2264.  * Return TRUE if astr not a suffix of bstr
  2265.  *   (compatibility with historical functions).
  2266.  */
  2267. bool str_suffix( const char *astr, const char *bstr )
  2268. {
  2269.     int sstr1;
  2270.     int sstr2;
  2271.     sstr1 = strlen(astr);
  2272.     sstr2 = strlen(bstr);
  2273.     if ( sstr1 <= sstr2 && !str_cmp( astr, bstr + sstr2 - sstr1 ) )
  2274. return FALSE;
  2275.     else
  2276. return TRUE;
  2277. }
  2278. /*
  2279.  * Returns an initial-capped string.
  2280.  */
  2281. char *capitalize( const char *str )
  2282. {
  2283.     static char strcap[MAX_STRING_LENGTH];
  2284.     int i;
  2285.     for ( i = 0; str[i] != ''; i++ )
  2286. strcap[i] = LOWER(str[i]);
  2287.     strcap[i] = '';
  2288.     strcap[0] = UPPER(strcap[0]);
  2289.     return strcap;
  2290. }
  2291. /*
  2292.  * Append a string to a file.
  2293.  */
  2294. void append_file( CHAR_DATA *ch, char *file, char *str )
  2295. {
  2296.     FILE *fp;
  2297.     if ( IS_NPC(ch) || str[0] == '' )
  2298. return;
  2299.     fclose( fpReserve );
  2300.     if ( ( fp = fopen( file, "a" ) ) == NULL )
  2301.     {
  2302. perror( file );
  2303. send_to_char( "Could not open the file!nr", ch );
  2304.     }
  2305.     else
  2306.     {
  2307. fprintf( fp, "[%5d] %s: %sn",
  2308.     ch->in_room ? ch->in_room->vnum : 0, ch->name, str );
  2309. fclose( fp );
  2310.     }
  2311.     fpReserve = fopen( NULL_FILE, "r" );
  2312.     return;
  2313. }
  2314. #if 0
  2315. /*
  2316.  * Reports a bug.
  2317.  */
  2318. void bug( const char *str, int param )
  2319. {
  2320.     char buf[MAX_STRING_LENGTH];
  2321.     FILE *fp;
  2322.     if ( fpArea != NULL )
  2323.     {
  2324. int iLine;
  2325. int iChar;
  2326. if ( fpArea == stdin )
  2327. {
  2328.     iLine = 0;
  2329. }
  2330. else
  2331. {
  2332.     iChar = ftell( fpArea );
  2333.     fseek( fpArea, 0, 0 );
  2334.     for ( iLine = 0; ftell( fpArea ) < iChar; iLine++ )
  2335.     {
  2336. while ( getc( fpArea ) != 'n' )
  2337.     ;
  2338.     }
  2339.     fseek( fpArea, iChar, 0 );
  2340. }
  2341. sprintf( buf, "[*****] FILE: %s LINE: %d", strArea, iLine );
  2342. log_string( buf );
  2343. if ( ( fp = fopen( "shutdown.txt", "a" ) ) != NULL )
  2344. {
  2345.     fprintf( fp, "[*****] %sn", buf );
  2346.     fclose( fp );
  2347. }
  2348.     }
  2349.     strcpy( buf, "[*****] BUG: " );
  2350.     sprintf( buf + strlen(buf), str, param );
  2351.     log_string( buf );
  2352.     fclose( fpReserve );
  2353.     if ( ( fp = fopen( BUG_FILE, "a" ) ) != NULL )
  2354.     {
  2355. fprintf( fp, "%sn", buf );
  2356. fclose( fp );
  2357.     }
  2358.     fpReserve = fopen( NULL_FILE, "r" );
  2359.     MessageBox(0, buf, "Merc2.2 server", MB_ICONHAND|MB_OK);
  2360.     DebugBreak();
  2361.     return;
  2362. }
  2363. #endif
  2364. #ifdef SINGLEUSER
  2365. /*
  2366.  * Writes a string to the log.
  2367.  */
  2368. void log_string( const char *str )
  2369. {
  2370.     char *strtime;
  2371.     strtime                    = ctime( &current_time );
  2372.     strtime[strlen(strtime)-1] = '';
  2373.     fprintf( stderr, "%s :: %sn", strtime, str );
  2374.     return;
  2375. }
  2376. #endif
  2377. /*
  2378.  * This function is here to aid in debugging.
  2379.  * If the last expression in a function is another function call,
  2380.  *   gcc likes to generate a JMP instead of a CALL.
  2381.  * This is called "tail chaining."
  2382.  * It hoses the debugger call stack for that call.
  2383.  * So I make this the last call in certain critical functions,
  2384.  *   where I really need the call stack to be right for debugging!
  2385.  *
  2386.  * If you don't understand this, then LEAVE IT ALONE.
  2387.  * Don't remove any calls to tail_chain anywhere.
  2388.  *
  2389.  * -- Furey
  2390.  */
  2391. void tail_chain( void )
  2392. {
  2393.     return;
  2394. }
  2395. /*
  2396.  * MOBprogram code block
  2397. */
  2398. /* the functions */
  2399. /* This routine transfers between alpha and numeric forms of the
  2400.  *  mob_prog bitvector types. This allows the use of the words in the
  2401.  *  mob/script files.
  2402.  */
  2403. int mprog_name_to_type (name) char* name;
  2404. {
  2405.    if (!str_cmp(name,"in_file_prog")) return IN_FILE_PROG;
  2406.    if (!str_cmp(name,"act_prog")) return ACT_PROG;
  2407.    if (!str_cmp(name,"speech_prog")) return SPEECH_PROG;
  2408.    if (!str_cmp(name,"rand_prog")) return RAND_PROG;
  2409.    if (!str_cmp(name,"fight_prog")) return FIGHT_PROG;
  2410.    if (!str_cmp(name,"hitprcnt_prog")) return HITPRCNT_PROG;
  2411.    if (!str_cmp(name,"death_prog")) return DEATH_PROG;
  2412.    if (!str_cmp(name,"entry_prog")) return ENTRY_PROG;
  2413.    if (!str_cmp(name,"greet_prog")) return GREET_PROG;
  2414.    if (!str_cmp(name,"all_greet_prog")) return ALL_GREET_PROG;
  2415.    if (!str_cmp(name,"give_prog")) return GIVE_PROG;
  2416.    if (!str_cmp(name,"bribe_prog")) return BRIBE_PROG;
  2417.    return(ERROR_PROG);
  2418. }
  2419. /* This routine reads in scripts of MOBprograms from a file */
  2420. MPROG_DATA* mprog_file_read(f, mprg, pMobIndex)
  2421. char* f;
  2422. MPROG_DATA* mprg;
  2423. MOB_INDEX_DATA* pMobIndex;
  2424. {
  2425.   MPROG_DATA* mprg2;
  2426.   FILE * progfile;
  2427.   char letter;
  2428.   bool done=FALSE;
  2429.   char MOBProgfile[MAX_INPUT_LENGTH];
  2430.   sprintf( MOBProgfile, "%s%s", MOB_DIR, f );
  2431.   progfile=fopen(MOBProgfile,"r");
  2432.   if (!progfile)
  2433.   {
  2434.      bug("Mob:%d couldnt open mobprog file",pMobIndex->vnum);
  2435.      exit( 1 );
  2436.   }
  2437.   mprg2=mprg;
  2438.   switch (letter=fread_letter(progfile))
  2439.   {
  2440.     case '>':
  2441.      break;
  2442.     case '|':
  2443.        bug("empty mobprog file.", 0);
  2444.        exit( 1 );
  2445.      break;
  2446.     default:
  2447.        bug("in mobprog file syntax error.", 0);
  2448.        exit( 1 );
  2449.      break;
  2450.   }
  2451.   while (!done)
  2452.   {
  2453.   mprg2->type=mprog_name_to_type(fread_word(progfile));
  2454.     switch (mprg2->type)
  2455.     {
  2456.      case ERROR_PROG:
  2457.         bug( "mobprog file type error", 0 );
  2458.         exit( 1 );
  2459.       break;
  2460.      case IN_FILE_PROG:
  2461.         bug( "mprog file contains a call to file.", 0 );
  2462.         exit( 1 );
  2463.       break;
  2464.      default:
  2465.         pMobIndex->progtypes = pMobIndex->progtypes | mprg2->type;
  2466.         mprg2->arglist=fread_string(progfile);
  2467.         mprg2->comlist=fread_string(progfile);
  2468.         switch (letter=fread_letter(progfile))
  2469.         {
  2470.           case '>':
  2471.              mprg2->next=(MPROG_DATA *)alloc_perm(sizeof(MPROG_DATA));
  2472.              mprg2=mprg2->next;
  2473.              mprg2->next=NULL;
  2474.            break;
  2475.           case '|':
  2476.              done=TRUE;
  2477.            break;
  2478.           default:
  2479.              bug( "in mobprog file syntax error.",0);
  2480.              exit( 1 );
  2481.            break;
  2482.         }
  2483.       break;
  2484.     }
  2485.   }
  2486.   fclose(progfile);
  2487.   return mprg2;
  2488. }
  2489. /* Snarf a MOBprogram section from the area file.
  2490.  */
  2491. void load_mobprogs(fp) FILE * fp;
  2492. {
  2493. char letter;
  2494. MOB_INDEX_DATA * iMob;
  2495. int value;
  2496. MPROG_DATA* original;
  2497. MPROG_DATA* working;
  2498. for (;;) switch (letter=fread_letter( fp))
  2499.   {
  2500.   default:
  2501.      bug( "Load_mobprogs: bad command '%c'.",letter);
  2502.      exit(1);
  2503.    break;
  2504.   case 'S':
  2505.   case 's':
  2506.      fread_to_eol(fp); 
  2507.      return;
  2508.   case '*':
  2509.      fread_to_eol(fp); 
  2510.      break;
  2511.   case 'M':
  2512.   case 'm':
  2513.    value=fread_number(fp);
  2514.    if ((iMob=get_mob_index(value))==NULL)
  2515.      {
  2516.       bug( "Load_mobprogs: vnum %d doesnt exist", value );
  2517.       exit( 1 );
  2518.      }
  2519.     
  2520.      if (original=iMob->mobprogs)
  2521.        for (;original->next!=NULL; original=original->next);
  2522.      working=(MPROG_DATA *)alloc_perm(sizeof(MPROG_DATA));
  2523.      if (original) original->next=working;
  2524.      else iMob->mobprogs=working;
  2525.      working=mprog_file_read(fread_word(fp),working,iMob);
  2526.      working->next=NULL;
  2527.      fread_to_eol(fp);
  2528.      break;
  2529.    }
  2530. /* This procedure is responsible for reading any in_file MOBprograms.
  2531.  */
  2532. void mprog_read_programs(fp,pMobIndex) FILE* fp; MOB_INDEX_DATA * pMobIndex;
  2533. {
  2534. MPROG_DATA * mprg;
  2535. bool done=FALSE;
  2536. char letter;
  2537.   if ( (letter=fread_letter(fp)) != '>' )
  2538.   {
  2539.       bug( "Load_mobiles: vnum %d MOBPROG char", pMobIndex->vnum );
  2540.       exit( 1 );
  2541.   }
  2542.   pMobIndex->mobprogs=(MPROG_DATA *)alloc_perm(sizeof(MPROG_DATA));
  2543.   mprg=pMobIndex->mobprogs;
  2544.   while (!done)
  2545.   {
  2546.     mprg->type=mprog_name_to_type(fread_word(fp));
  2547.     switch (mprg->type)
  2548.     {
  2549.      case ERROR_PROG:
  2550.         bug( "Load_mobiles: vnum %d MOBPROG type.", pMobIndex->vnum );
  2551.         exit( 1 );
  2552.       break;
  2553.      case IN_FILE_PROG:
  2554.         mprg=mprog_file_read(fread_string(fp),mprg,pMobIndex);
  2555.         fread_to_eol(fp);
  2556.         switch (letter=fread_letter(fp))
  2557.         {
  2558.           case '>':
  2559.              mprg->next=(MPROG_DATA *)alloc_perm(sizeof(MPROG_DATA));
  2560.              mprg=mprg->next;
  2561.              mprg->next=NULL;
  2562.            break;
  2563.           case '|':
  2564.              mprg->next=NULL;
  2565.              fread_to_eol(fp);
  2566.              done=TRUE;
  2567.            break;
  2568.           default:
  2569.              bug( "Load_mobiles: vnum %d bad MOBPROG.", pMobIndex->vnum );
  2570.              exit( 1 );
  2571.            break;
  2572.         }
  2573.       break;
  2574.      default:
  2575.         pMobIndex->progtypes = pMobIndex->progtypes | mprg->type;
  2576.         mprg->arglist=fread_string(fp);
  2577.         fread_to_eol(fp);
  2578.         mprg->comlist=fread_string(fp);
  2579.         fread_to_eol(fp);
  2580.         switch (letter=fread_letter(fp))
  2581.         {
  2582.           case '>':
  2583.              mprg->next=(MPROG_DATA *)alloc_perm(sizeof(MPROG_DATA));
  2584.              mprg=mprg->next;
  2585.              mprg->next=NULL;
  2586.            break;
  2587.           case '|':
  2588.              mprg->next=NULL;
  2589.              fread_to_eol(fp);
  2590.              done=TRUE;
  2591.            break;
  2592.           default:
  2593.              bug( "Load_mobiles: vnum %d bad MOBPROG.", pMobIndex->vnum );
  2594.              exit( 1 );
  2595.            break;
  2596.         }
  2597.       break;
  2598.     }
  2599.   }
  2600. }