/**************************************************************************** * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// * * -----------------------------------------------------------| (0...0) * * SMAUG 1.0 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( * * -----------------------------------------------------------| {o o} * * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ * * Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~* * Tricops and Fireblade | * * ------------------------------------------------------------------------ * * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * ------------------------------------------------------------------------ * * Database management module * ****************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <time.h> #include <sys/time.h> #include <sys/stat.h> #include <dirent.h> #include <unistd.h> #include <dlfcn.h> #include "mud.h" char strArea[MAX_INPUT_LENGTH]; FILE *fpArea; MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH]; OBJ_INDEX_DATA *obj_index_hash[MAX_KEY_HASH]; ROOM_INDEX_DATA *room_index_hash[MAX_KEY_HASH]; AREA_DATA *first_area; AREA_DATA *last_area; short num_skills; short num_sorted_skills; void fold_all_areas( void ); void mprog_read_programs( FILE * fp, MOB_INDEX_DATA * pMobIndex ); void oprog_read_programs( FILE * fp, OBJ_INDEX_DATA * pObjIndex ); void rprog_read_programs( FILE * fp, ROOM_INDEX_DATA * pRoomIndex ); void init_mm( void ); void boot_log( const char *str, ... ); void load_resets( AREA_DATA * tarea, FILE * fp ); void renumber_put_resets( ROOM_INDEX_DATA * room ); void shutdown_mud( const char *reason ) { FILE *fp; if( ( fp = fopen( SHUTDOWN_FILE, "a" ) ) != NULL ) { fprintf( fp, "%s\n", reason ); fclose( fp ); fp = NULL; } } void boot_db( void ) { fpArea = NULL; log_string( "Loading skill table" ); load_skill_table( ); sort_skill_table( ); remap_slot_numbers( ); /* must be after the sort */ num_sorted_skills = num_skills; first_area = NULL; last_area = NULL; log_string( "Initializing random number generator" ); init_mm( ); /* Read in all the area files. */ { FILE *fpList; log_string( "Reading in area files..." ); if( !( fpList = fopen( AREA_LIST, "r" ) ) ) { perror( AREA_LIST ); shutdown_mud( "Unable to open area list" ); exit( 1 ); } for( ;; ) { if( feof( fpList ) ) { bug( "%s: EOF encountered reading area list - no $ found at end of file.", __FUNCTION__ ); break; } mudstrlcpy( strArea, fread_word( fpList ), MAX_INPUT_LENGTH ); if( strArea[0] == '$' ) break; load_area_file( NULL, strArea ); } fclose( fpList ); fpList = NULL; } fold_all_areas( ); } /* * Load an 'area' header line. */ AREA_DATA *load_area( FILE * fp, int aversion ) { AREA_DATA *pArea; CREATE( pArea, AREA_DATA, 1 ); pArea->version = aversion; pArea->first_room = pArea->last_room = NULL; pArea->name = fread_string_nohash( fp ); pArea->author = STRALLOC( "unknown" ); pArea->credits = STRALLOC( "" ); pArea->filename = str_dup( strArea ); pArea->age = 15; pArea->nplayer = 0; pArea->low_r_vnum = 0; pArea->low_o_vnum = 0; pArea->low_m_vnum = 0; pArea->hi_r_vnum = 0; pArea->hi_o_vnum = 0; pArea->hi_m_vnum = 0; pArea->low_soft_range = 0; pArea->hi_soft_range = MAX_LEVEL; pArea->low_hard_range = 0; pArea->hi_hard_range = MAX_LEVEL; pArea->spelllimit = 0; pArea->weatherx = 0; pArea->weathery = 0; LINK( pArea, first_area, last_area, next, prev ); return pArea; } /* Load the version number of the area file if none exists, then it * is set to version 0 when #AREA is read in which is why we check for * the #AREA here. --Shaddai */ void load_version( AREA_DATA * tarea, FILE * fp ) { tarea->version = fread_number( fp ); } /* * Load an author section. Scryn 2/1/96 */ void load_author( AREA_DATA * tarea, FILE * fp ) { if( !tarea ) { bug( "%s: no #AREA seen yet.", __FUNCTION__ ); shutdown_mud( "No #AREA" ); exit( 1 ); } if( tarea->author ) STRFREE( tarea->author ); tarea->author = fread_string( fp ); } /* * Load a credits section. Edmond */ void load_credits( AREA_DATA * tarea, FILE * fp ) { if( !tarea ) { bug( "%s: no #AREA seen yet.", __FUNCTION__ ); shutdown_mud( "No #AREA" ); exit( 1 ); } if( tarea->credits ) STRFREE( tarea->credits ); tarea->credits = fread_string( fp ); } /* * Load an economy section. Thoric */ void load_economy( AREA_DATA * tarea, FILE * fp ) { if( !tarea ) { bug( "Load_economy: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } tarea->high_economy = fread_number( fp ); tarea->low_economy = fread_number( fp ); } /* Reset Message Load, Rennard */ void load_resetmsg( AREA_DATA * tarea, FILE * fp ) { if( !tarea ) { bug( "%s: no #AREA seen yet.", __FUNCTION__ ); shutdown_mud( "No #AREA" ); exit( 1 ); } if( tarea->resetmsg ) DISPOSE( tarea->resetmsg ); tarea->resetmsg = fread_string_nohash( fp ); } /* * Load area flags. Narn, Mar/96 */ void load_flags( AREA_DATA * tarea, FILE * fp ) { char *ln; int x1, x2; if( !tarea ) { bug( "Load_flags: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } ln = fread_line( fp ); x1 = x2 = 0; sscanf( ln, "%d %d", &x1, &x2 ); tarea->flags = x1; tarea->reset_frequency = x2; if( x2 ) tarea->age = x2; } /* * Load a mob section. */ void load_mobiles( AREA_DATA * tarea, FILE * fp ) { MOB_INDEX_DATA *pMobIndex; char *ln; int x1, x2, x3, x4, x5, x6, x7, x8; if( !tarea ) { bug( "Load_mobiles: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } for( ;; ) { int vnum; char letter; int iHash; bool oldmob; letter = fread_letter( fp ); if( letter != '#' ) { bug( "Load_mobiles: # not found." ); shutdown_mud( "# not found" ); exit( 1 ); } vnum = fread_number( fp ); if( vnum == 0 ) break; if( get_mob_index( vnum ) ) { bug( "Load_mobiles: vnum %d duplicated.", vnum ); shutdown_mud( "duplicate vnum" ); exit( 1 ); } else { oldmob = false; CREATE( pMobIndex, MOB_INDEX_DATA, 1 ); } pMobIndex->vnum = vnum; if( !tarea->low_m_vnum ) tarea->low_m_vnum = vnum; if( vnum > tarea->hi_m_vnum ) tarea->hi_m_vnum = vnum; pMobIndex->player_name = fread_string( fp ); pMobIndex->short_descr = fread_string( fp ); pMobIndex->long_descr = fread_string( fp ); pMobIndex->description = fread_string( fp ); // well, it's pretty nasty to cast, but we know that we own this // memory because we just created it. ((char*)pMobIndex->long_descr)[0] = UPPER( pMobIndex->long_descr[0] ); ((char*)pMobIndex->description)[0] = UPPER( pMobIndex->description[0] ); pMobIndex->act = fread_bitvector( fp ); xSET_BIT( pMobIndex->act, ACT_IS_NPC ); pMobIndex->affected_by = fread_bitvector( fp ); pMobIndex->pShop = NULL; pMobIndex->rShop = NULL; pMobIndex->alignment = fread_number( fp ); letter = fread_letter( fp ); pMobIndex->level = fread_number( fp ); pMobIndex->mobthac0 = fread_number( fp ); pMobIndex->ac = fread_number( fp ); pMobIndex->hitnodice = fread_number( fp ); /* * 'd' */ fread_letter( fp ); pMobIndex->hitsizedice = fread_number( fp ); /* * '+' */ fread_letter( fp ); pMobIndex->hitplus = fread_number( fp ); pMobIndex->damnodice = fread_number( fp ); /* * 'd' */ fread_letter( fp ); pMobIndex->damsizedice = fread_number( fp ); /* * '+' */ fread_letter( fp ); pMobIndex->damplus = fread_number( fp ); ln = fread_line( fp ); x1 = x2 = 0; sscanf( ln, "%d %d", &x1, &x2 ); pMobIndex->gold = x1; pMobIndex->exp = x2; /* * pMobIndex->position = fread_number( fp ); */ pMobIndex->position = fread_number( fp ); if( pMobIndex->position < 100 ) { switch ( pMobIndex->position ) { default: case 0: case 1: case 2: case 3: case 4: break; case 5: pMobIndex->position = 6; break; case 6: pMobIndex->position = 8; break; case 7: pMobIndex->position = 9; break; case 8: pMobIndex->position = 12; break; case 9: pMobIndex->position = 13; break; case 10: pMobIndex->position = 14; break; case 11: pMobIndex->position = 15; break; } } else { pMobIndex->position -= 100; } /* * pMobIndex->defposition = fread_number( fp ); */ pMobIndex->defposition = fread_number( fp ); if( pMobIndex->defposition < 100 ) { switch ( pMobIndex->defposition ) { default: case 0: case 1: case 2: case 3: case 4: break; case 5: pMobIndex->defposition = 6; break; case 6: pMobIndex->defposition = 8; break; case 7: pMobIndex->defposition = 9; break; case 8: pMobIndex->defposition = 12; break; case 9: pMobIndex->defposition = 13; break; case 10: pMobIndex->defposition = 14; break; case 11: pMobIndex->defposition = 15; break; } } else { pMobIndex->defposition -= 100; } /* * Back to meaningful values. */ pMobIndex->sex = fread_number( fp ); if( letter != 'S' && letter != 'C' ) { bug( "Load_mobiles: vnum %d: letter '%c' not S or C.", vnum, letter ); shutdown_mud( "bad mob data" ); exit( 1 ); } if( letter == 'C' ) /* Realms complex mob -Thoric */ { pMobIndex->perm_str = fread_number( fp ); pMobIndex->perm_int = fread_number( fp ); pMobIndex->perm_wis = fread_number( fp ); pMobIndex->perm_dex = fread_number( fp ); pMobIndex->perm_con = fread_number( fp ); pMobIndex->perm_cha = fread_number( fp ); pMobIndex->perm_lck = fread_number( fp ); pMobIndex->saving_poison_death = fread_number( fp ); pMobIndex->saving_wand = fread_number( fp ); pMobIndex->saving_para_petri = fread_number( fp ); pMobIndex->saving_breath = fread_number( fp ); pMobIndex->saving_spell_staff = fread_number( fp ); if( tarea->version < 1000 ) /* Normal Smaug zones load here */ { ln = fread_line( fp ); x1 = x2 = x3 = x4 = x5 = x6 = x7 = x8 = 0; sscanf( ln, "%d %d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6, &x7 ); pMobIndex->race = x1; pMobIndex->Class = x2; pMobIndex->height = x3; pMobIndex->weight = x4; pMobIndex->speaks = x5; pMobIndex->speaking = x6; pMobIndex->numattacks = x7; } else /* SmaugWiz zone here */ { ln = fread_line( fp ); x1 = x2 = x3 = x4 = x5 = 0; sscanf( ln, "%d %d %d %d %d", &x1, &x2, &x3, &x4, &x5 ); pMobIndex->race = x1; pMobIndex->Class = x2; pMobIndex->height = x3; pMobIndex->weight = x4; pMobIndex->numattacks = x5; ln = fread_line( fp ); ln = fread_line( fp ); } pMobIndex->hitroll = fread_number( fp ); pMobIndex->damroll = fread_number( fp ); pMobIndex->xflags = fread_number( fp ); pMobIndex->resistant = fread_number( fp ); pMobIndex->immune = fread_number( fp ); pMobIndex->susceptible = fread_number( fp ); pMobIndex->attacks = fread_bitvector( fp ); pMobIndex->defenses = fread_bitvector( fp ); } else { pMobIndex->perm_str = 13; pMobIndex->perm_dex = 13; pMobIndex->perm_int = 13; pMobIndex->perm_wis = 13; pMobIndex->perm_cha = 13; pMobIndex->perm_con = 13; pMobIndex->perm_lck = 13; pMobIndex->race = 0; pMobIndex->Class = 3; pMobIndex->xflags = 0; pMobIndex->resistant = 0; pMobIndex->immune = 0; pMobIndex->susceptible = 0; pMobIndex->numattacks = 0; xCLEAR_BITS( pMobIndex->attacks ); xCLEAR_BITS( pMobIndex->defenses ); } letter = fread_letter( fp ); if( letter == '>' ) { ungetc( letter, fp ); mprog_read_programs( fp, pMobIndex ); } else ungetc( letter, fp ); if( !oldmob ) { iHash = vnum % MAX_KEY_HASH; pMobIndex->next = mob_index_hash[iHash]; mob_index_hash[iHash] = pMobIndex; } } } /* * Load an obj section. */ void load_objects( AREA_DATA * tarea, FILE * fp ) { OBJ_INDEX_DATA *pObjIndex; char letter; char *ln; int x1, x2, x3, x4, x5, x6; if( !tarea ) { bug( "Load_objects: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } for( ;; ) { int vnum; int iHash; bool oldobj; letter = fread_letter( fp ); if( letter != '#' ) { bug( "Load_objects: # not found." ); shutdown_mud( "# not found" ); exit( 1 ); } vnum = fread_number( fp ); if( vnum == 0 ) break; if( get_obj_index( vnum ) ) { bug( "Load_objects: vnum %d duplicated.", vnum ); shutdown_mud( "duplicate vnum" ); exit( 1 ); } else { oldobj = false; CREATE( pObjIndex, OBJ_INDEX_DATA, 1 ); } pObjIndex->vnum = vnum; if( !tarea->low_o_vnum ) tarea->low_o_vnum = vnum; if( vnum > tarea->hi_o_vnum ) tarea->hi_o_vnum = vnum; pObjIndex->name = fread_string( fp ); pObjIndex->short_descr = fread_string( fp ); pObjIndex->description = fread_string( fp ); pObjIndex->action_desc = fread_string( fp ); /* * Commented out by Narn, Apr/96 to allow item short descs like * Bonecrusher and Oblivion */ /* * pObjIndex->short_descr[0] = LOWER(pObjIndex->short_descr[0]); */ // we just created this, so we know we can touch the string ((char*)pObjIndex->description)[0] = UPPER( pObjIndex->description[0] ); pObjIndex->item_type = fread_number( fp ); pObjIndex->extra_flags = fread_bitvector( fp ); ln = fread_line( fp ); x1 = x2 = x3 = 0; sscanf( ln, "%d %d %d", &x1, &x2, &x3 ); pObjIndex->wear_flags = x1; pObjIndex->layers = x2; pObjIndex->level = x3; ln = fread_line( fp ); x1 = x2 = x3 = x4 = x5 = x6 = 0; sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 ); pObjIndex->value[0] = x1; pObjIndex->value[1] = x2; pObjIndex->value[2] = x3; pObjIndex->value[3] = x4; pObjIndex->value[4] = x5; pObjIndex->value[5] = x6; if( tarea->version < 1000 ) { pObjIndex->weight = fread_number( fp ); pObjIndex->weight = UMAX( 1, pObjIndex->weight ); pObjIndex->cost = fread_number( fp ); pObjIndex->rent = fread_number( fp ); /* unused */ } if( tarea->version > 0 ) { switch ( pObjIndex->item_type ) { case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: pObjIndex->value[1] = skill_lookup( fread_word( fp ) ); pObjIndex->value[2] = skill_lookup( fread_word( fp ) ); pObjIndex->value[3] = skill_lookup( fread_word( fp ) ); break; case ITEM_STAFF: case ITEM_WAND: pObjIndex->value[3] = skill_lookup( fread_word( fp ) ); break; case ITEM_SALVE: pObjIndex->value[4] = skill_lookup( fread_word( fp ) ); pObjIndex->value[5] = skill_lookup( fread_word( fp ) ); break; } } if( tarea->version == 1000 ) { while( !isdigit( letter = fread_letter( fp ) ) ) fread_to_eol( fp ); ungetc( letter, fp ); pObjIndex->weight = fread_number( fp ); pObjIndex->weight = UMAX( 1, pObjIndex->weight ); pObjIndex->cost = fread_number( fp ); pObjIndex->rent = fread_number( fp ); /* unused */ } for( ;; ) { letter = fread_letter( fp ); if( letter == 'A' ) { AFFECT_DATA *paf; CREATE( paf, AFFECT_DATA, 1 ); paf->type = -1; paf->duration = -1; paf->location = fread_number( fp ); if( paf->location == APPLY_WEAPONSPELL || paf->location == APPLY_WEARSPELL || paf->location == APPLY_REMOVESPELL || paf->location == APPLY_STRIPSN || paf->location == APPLY_RECURRINGSPELL ) paf->modifier = slot_lookup( fread_number( fp ) ); else paf->modifier = fread_number( fp ); xCLEAR_BITS( paf->bitvector ); LINK( paf, pObjIndex->first_affect, pObjIndex->last_affect, next, prev ); } else if( letter == 'E' ) { EXTRA_DESCR_DATA *ed; CREATE( ed, EXTRA_DESCR_DATA, 1 ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); LINK( ed, pObjIndex->first_extradesc, pObjIndex->last_extradesc, next, prev ); } else if( letter == '>' ) { ungetc( letter, fp ); oprog_read_programs( fp, pObjIndex ); } else { ungetc( letter, fp ); break; } } /* * Translate spell "slot numbers" to internal "skill numbers." */ if( tarea->version == 0 ) switch ( pObjIndex->item_type ) { case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: pObjIndex->value[1] = slot_lookup( pObjIndex->value[1] ); pObjIndex->value[2] = slot_lookup( pObjIndex->value[2] ); pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] ); break; case ITEM_STAFF: case ITEM_WAND: pObjIndex->value[3] = slot_lookup( pObjIndex->value[3] ); break; case ITEM_SALVE: pObjIndex->value[4] = slot_lookup( pObjIndex->value[4] ); pObjIndex->value[5] = slot_lookup( pObjIndex->value[5] ); break; } if( !oldobj ) { iHash = vnum % MAX_KEY_HASH; pObjIndex->next = obj_index_hash[iHash]; obj_index_hash[iHash] = pObjIndex; } } } /* * Load a reset section. */ void load_resets( AREA_DATA * tarea, FILE * fp ) { ROOM_INDEX_DATA *pRoomIndex = NULL; ROOM_INDEX_DATA *roomlist; bool not01 = false; int count = 0; if( !tarea ) { bug( "%s", "Load_resets: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } if( !tarea->first_room ) { bug( "%s: No #ROOMS section found. Cannot load resets.", __FUNCTION__ ); shutdown_mud( "No #ROOMS" ); exit( 1 ); } for( ;; ) { EXIT_DATA *pexit; char letter; int extra, arg1, arg2, arg3; if( ( letter = fread_letter( fp ) ) == 'S' ) break; if( letter == '*' ) { fread_to_eol( fp ); continue; } extra = fread_number( fp ); if( letter == 'M' || letter == 'O' ) extra = 0; arg1 = fread_number( fp ); arg2 = fread_number( fp ); arg3 = ( letter == 'G' || letter == 'R' ) ? 0 : fread_number( fp ); fread_to_eol( fp ); ++count; /* * Validate parameters. * We're calling the index functions for the side effect. */ switch ( letter ) { default: bug( "%s: bad command '%c'.", __FUNCTION__, letter ); boot_log( "%s: %s (%d) bad command '%c'.", __FUNCTION__, tarea->filename, count, letter ); return; case 'M': if( get_mob_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) 'M': mobile %d doesn't exist.", __FUNCTION__, tarea->filename, count, arg1 ); if( ( pRoomIndex = get_room_index( arg3 ) ) == NULL ) boot_log( "%s: %s (%d) 'M': room %d doesn't exist.", __FUNCTION__, tarea->filename, count, arg3 ); else add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); break; case 'O': if( get_obj_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, tarea->filename, count, letter, arg1 ); if( ( pRoomIndex = get_room_index( arg3 ) ) == NULL ) boot_log( "%s: %s (%d) '%c': room %d doesn't exist.", __FUNCTION__, tarea->filename, count, letter, arg3 ); else { if( !pRoomIndex ) bug( "%s: Unable to add room reset - room not found.", __FUNCTION__ ); else add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); } break; case 'P': if( get_obj_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, tarea->filename, count, letter, arg1 ); if( arg3 > 0 ) { if( get_obj_index( arg3 ) == NULL ) boot_log( "%s: %s (%d) 'P': destination object %d doesn't exist.", __FUNCTION__, tarea->filename, count, arg3 ); if( extra > 1 ) not01 = true; } if( !pRoomIndex ) bug( "%s: Unable to add room reset - room not found.", __FUNCTION__ ); else { if( arg3 == 0 ) arg3 = 2; add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); } break; case 'G': case 'E': if( get_obj_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, tarea->filename, count, letter, arg1 ); if( !pRoomIndex ) bug( "%s: Unable to add room reset - room not found.", __FUNCTION__ ); else add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); break; case 'T': if( IS_SET( extra, TRAP_OBJ ) ) bug( "%s: Unable to add legacy object trap reset. Must be converted manually.", __FUNCTION__ ); else { if( !( pRoomIndex = get_room_index( arg3 ) ) ) bug( "%s: Unable to add trap reset - room not found.", __FUNCTION__ ); else add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); } break; case 'H': bug( "%s: Unable to convert legacy hide reset. Must be converted manually.", __FUNCTION__ ); break; case 'D': if( !( pRoomIndex = get_room_index( arg1 ) ) ) { bug( "%s: 'D': room %d doesn't exist.", __FUNCTION__, arg1 ); bug( "Reset: %c %d %d %d %d", letter, extra, arg1, arg2, arg3 ); boot_log( "%s: %s (%d) 'D': room %d doesn't exist.", __FUNCTION__, tarea->filename, count, arg1 ); break; } if( arg2 < 0 || arg2 > MAX_DIR + 1 || !( pexit = get_exit( pRoomIndex, arg2 ) ) || !IS_SET( pexit->exit_info, EX_ISDOOR ) ) { bug( "%s: 'D': exit %d not door.", __FUNCTION__, arg2 ); bug( "Reset: %c %d %d %d %d", letter, extra, arg1, arg2, arg3 ); boot_log( "%s: %s (%d) 'D': exit %d not door.", __FUNCTION__, tarea->filename, count, arg2 ); } if( arg3 < 0 || arg3 > 2 ) { bug( "%s: 'D': bad 'locks': %d.", __FUNCTION__, arg3 ); boot_log( "%s: %s (%d) 'D': bad 'locks': %d.", __FUNCTION__, tarea->filename, count, arg3 ); } add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); break; case 'R': if( !( pRoomIndex = get_room_index( arg1 ) ) ) boot_log( "%s: %s (%d) 'R': room %d doesn't exist.", __FUNCTION__, tarea->filename, count, arg1 ); else add_reset( pRoomIndex, letter, extra, arg1, arg2, arg3 ); if( arg2 < 0 || arg2 > 10 ) { bug( "%s: 'R': bad exit %d.", __FUNCTION__, arg2 ); boot_log( "%s: %s (%d) 'R': bad exit %d.", __FUNCTION__, tarea->filename, count, arg2 ); break; } break; } } if( !not01 ) { for( roomlist = tarea->first_room; roomlist; roomlist = roomlist->next_aroom ) renumber_put_resets( roomlist ); } return; } void load_smaugwiz_reset( ROOM_INDEX_DATA * room, FILE * fp ) { EXIT_DATA *pexit; char letter2; int extra, arg1, arg2, arg3, arg4; int count = 0; letter2 = fread_letter( fp ); extra = fread_number( fp ); arg1 = fread_number( fp ); arg2 = fread_number( fp ); arg3 = fread_number( fp ); arg4 = ( letter2 == 'G' || letter2 == 'R' ) ? 0 : fread_number( fp ); fread_to_eol( fp ); ++count; /* * Validate parameters. * We're calling the index functions for the side effect. */ switch ( letter2 ) { default: bug( "%s: SmaugWiz - bad command '%c'.", __FUNCTION__, letter2 ); boot_log( "%s: %s (%d) bad command '%c'.", __FUNCTION__, room->area->filename, count, letter2 ); return; case 'M': if( get_mob_index( arg2 ) == NULL ) boot_log( "%s: SmaugWiz - %s (%d) 'M': mobile %d doesn't exist.", __FUNCTION__, room->area->filename, count, arg2 ); break; case 'O': if( get_obj_index( arg2 ) == NULL ) boot_log( "%s: SmaugWiz - %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter2, arg2 ); break; case 'P': if( get_obj_index( arg2 ) == NULL ) boot_log( "%s: SmaugWiz - %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter2, arg2 ); if( arg4 > 0 ) { if( get_obj_index( arg4 ) == NULL ) boot_log( "$s: SmaugWiz - %s (%d) 'P': destination object %d doesn't exist.", __FUNCTION__, room->area->filename, count, arg4 ); } break; case 'G': case 'E': if( get_obj_index( arg2 ) == NULL ) boot_log( "%s: SmaugWiz - %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter2, arg2 ); break; case 'T': break; case 'H': if( arg1 > 0 ) if( get_obj_index( arg2 ) == NULL ) boot_log( "%s: SmaugWiz - %s (%d) 'H': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, arg2 ); break; case 'D': if( arg3 < 0 || arg3 > MAX_DIR + 1 || ( pexit = get_exit( room, arg3 ) ) == NULL || !IS_SET( pexit->exit_info, EX_ISDOOR ) ) { bug( "%s: SmaugWiz - 'D': exit %d not door.", __FUNCTION__, arg3 ); bug( "Reset: %c %d %d %d %d %d", letter2, extra, arg1, arg2, arg3, arg4 ); boot_log( "%s: SmaugWiz - %s (%d) 'D': exit %d not door.", __FUNCTION__, room->area->filename, count, arg3 ); } if( arg4 < 0 || arg4 > 2 ) { bug( "%s: 'D': bad 'locks': %d.", __FUNCTION__, arg4 ); boot_log( "%s: SmaugWiz - %s (%d) 'D': bad 'locks': %d.", __FUNCTION__, room->area->filename, count, arg4 ); } break; case 'R': if( arg3 < 0 || arg3 > 10 ) { bug( "%s: 'R': bad exit %d.", __FUNCTION__, arg3 ); boot_log( "%s: SmaugWiz - %s (%d) 'R': bad exit %d.", __FUNCTION__, room->area->filename, count, arg3 ); break; } break; } /* * Don't bother asking why arg1 isn't passed, SmaugWiz had some purpose for it, but it remains a mystery */ add_reset( room, letter2, extra, arg2, arg3, arg4 ); } /* End SmaugWiz resets */ void load_room_reset( ROOM_INDEX_DATA * room, FILE * fp ) { EXIT_DATA *pexit; char letter; int extra, arg1, arg2, arg3; bool not01 = false; int count = 0; letter = fread_letter( fp ); extra = fread_number( fp ); if( letter == 'M' || letter == 'O' ) extra = 0; arg1 = fread_number( fp ); arg2 = fread_number( fp ); arg3 = ( letter == 'G' || letter == 'R' ) ? 0 : fread_number( fp ); fread_to_eol( fp ); ++count; /* * Validate parameters. * We're calling the index functions for the side effect. */ switch ( letter ) { default: bug( "%s: bad command '%c'.", __FUNCTION__, letter ); boot_log( "%s: %s (%d) bad command '%c'.", __FUNCTION__, room->area->filename, count, letter ); return; case 'M': if( get_mob_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) 'M': mobile %d doesn't exist.", __FUNCTION__, room->area->filename, count, arg1 ); break; case 'O': if( get_obj_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter, arg1 ); break; case 'P': if( get_obj_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter, arg1 ); if( arg3 <= 0 ) arg3 = 2; if( get_obj_index( arg3 ) == NULL ) boot_log( "%s: %s (%d) 'P': destination object %d doesn't exist.", __FUNCTION__, room->area->filename, count, arg3 ); if( extra > 1 ) not01 = true; break; case 'G': case 'E': if( get_obj_index( arg1 ) == NULL ) boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter, arg1 ); break; case 'T': case 'H': break; case 'D': if( arg2 < 0 || arg2 > MAX_DIR + 1 || !( pexit = get_exit( room, arg2 ) ) || !IS_SET( pexit->exit_info, EX_ISDOOR ) ) { bug( "%s: 'D': exit %d not door.", __FUNCTION__, arg2 ); bug( "Reset: %c %d %d %d %d", letter, extra, arg1, arg2, arg3 ); boot_log( "%s: %s (%d) 'D': exit %d not door.", __FUNCTION__, room->area->filename, count, arg2 ); } if( arg3 < 0 || arg3 > 2 ) { bug( "%s: 'D': bad 'locks': %d.", __FUNCTION__, arg3 ); boot_log( "%s: %s (%d) 'D': bad 'locks': %d.", __FUNCTION__, room->area->filename, count, arg3 ); } break; case 'R': if( arg2 < 0 || arg2 > 10 ) { bug( "%s: 'R': bad exit %d.", __FUNCTION__, arg2 ); boot_log( "%s: %s (%d) 'R': bad exit %d.", __FUNCTION__, room->area->filename, count, arg2 ); break; } break; } add_reset( room, letter, extra, arg1, arg2, arg3 ); if( !not01 ) renumber_put_resets( room ); return; } /* * Load a room section. */ void load_rooms( AREA_DATA * tarea, FILE * fp ) { ROOM_INDEX_DATA *pRoomIndex; char *ln; if( !tarea ) { bug( "Load_rooms: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } tarea->first_room = tarea->last_room = NULL; for( ;; ) { int vnum; char letter; int door; int iHash; bool oldroom; int x1, x2, x3, x4, x5, x6; letter = fread_letter( fp ); if( letter != '#' ) { bug( "Load_rooms: # not found." ); shutdown_mud( "# not found" ); exit( 1 ); } vnum = fread_number( fp ); if( vnum == 0 ) break; if( get_room_index( vnum ) != NULL ) { bug( "Load_rooms: vnum %d duplicated.", vnum ); shutdown_mud( "duplicate vnum" ); exit( 1 ); } else { oldroom = false; CREATE( pRoomIndex, ROOM_INDEX_DATA, 1 ); } pRoomIndex->area = tarea; pRoomIndex->vnum = vnum; pRoomIndex->first_extradesc = NULL; pRoomIndex->last_extradesc = NULL; pRoomIndex->first_affect = NULL; pRoomIndex->last_affect = NULL; pRoomIndex->first_permaffect = NULL; pRoomIndex->last_permaffect = NULL; if( !tarea->low_r_vnum ) tarea->low_r_vnum = vnum; if( vnum > tarea->hi_r_vnum ) tarea->hi_r_vnum = vnum; pRoomIndex->name = fread_string( fp ); pRoomIndex->description = fread_string( fp ); /* * Area number fread_number( fp ); */ fread_number( fp ); pRoomIndex->room_flags = fread_bitvector( fp ); ln = fread_line( fp ); x3 = x4 = x5 = x6 = 0; sscanf( ln, "%d %d %d %d", &x3, &x4, &x5, &x6 ); pRoomIndex->sector_type = x3; pRoomIndex->tele_delay = x4; pRoomIndex->tele_vnum = x5; pRoomIndex->tunnel = x6; if( pRoomIndex->sector_type < 0 || pRoomIndex->sector_type >= SECT_MAX ) { bug( "Fread_rooms: vnum %d has bad sector_type %d.", vnum, pRoomIndex->sector_type ); pRoomIndex->sector_type = 1; } pRoomIndex->light = 0; pRoomIndex->first_exit = NULL; pRoomIndex->last_exit = NULL; for( ;; ) { letter = fread_letter( fp ); if( letter == 'S' ) break; if( letter == 'D' ) { EXIT_DATA *pexit; int locks; door = fread_number( fp ); if( door < 0 || door > 10 ) { bug( "Fread_rooms: vnum %d has bad door number %d.", vnum, door ); exit( 1 ); } else { pexit = make_exit( pRoomIndex, NULL, door ); pexit->description = fread_string( fp ); pexit->keyword = fread_string( fp ); pexit->exit_info = 0; ln = fread_line( fp ); x1 = x2 = x3 = x4 = x5 = x6 = 0; sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 ); locks = x1; pexit->key = x2; pexit->vnum = x3; pexit->vdir = door; pexit->distance = x4; pexit->pulltype = x5; pexit->pull = x6; switch ( locks ) { case 1: pexit->exit_info = EX_ISDOOR; break; case 2: pexit->exit_info = EX_ISDOOR | EX_PICKPROOF; break; default: pexit->exit_info = locks; } } } else if( letter == 'E' ) { EXTRA_DESCR_DATA *ed; CREATE( ed, EXTRA_DESCR_DATA, 1 ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); LINK( ed, pRoomIndex->first_extradesc, pRoomIndex->last_extradesc, next, prev ); } else if( letter == 'R' ) { if( tarea->version < 1000 ) load_room_reset( pRoomIndex, fp ); else load_smaugwiz_reset( pRoomIndex, fp ); } else if( letter == 'M' ) /* old map stuff no longer supported */ { fread_to_eol( fp ); } else if( letter == '>' ) { ungetc( letter, fp ); rprog_read_programs( fp, pRoomIndex ); } else { bug( "Load_rooms: vnum %d has flag '%c' not 'DES'.", vnum, letter ); shutdown_mud( "Room flag not DES" ); exit( 1 ); } } if( !oldroom ) { iHash = vnum % MAX_KEY_HASH; pRoomIndex->next = room_index_hash[iHash]; room_index_hash[iHash] = pRoomIndex; LINK( pRoomIndex, tarea->first_room, tarea->last_room, next_aroom, prev_aroom ); } } } /* * Load a shop section. */ void load_shops( FILE * fp ) { SHOP_DATA *pShop; for( ;; ) { MOB_INDEX_DATA *pMobIndex; int iTrade; CREATE( pShop, SHOP_DATA, 1 ); pShop->keeper = fread_number( fp ); if( pShop->keeper == 0 ) { DISPOSE( pShop ); break; } for( iTrade = 0; iTrade < MAX_TRADE; iTrade++ ) pShop->buy_type[iTrade] = fread_number( fp ); pShop->profit_buy = fread_number( fp ); pShop->profit_sell = fread_number( fp ); pShop->profit_buy = URANGE( pShop->profit_sell + 5, pShop->profit_buy, 1000 ); pShop->profit_sell = URANGE( 0, pShop->profit_sell, pShop->profit_buy - 5 ); pShop->open_hour = fread_number( fp ); pShop->close_hour = fread_number( fp ); fread_to_eol( fp ); pMobIndex = get_mob_index( pShop->keeper ); pMobIndex->pShop = pShop; } } /* * Load a repair shop section. -Thoric */ void load_repairs( FILE * fp ) { REPAIR_DATA *rShop; for( ;; ) { MOB_INDEX_DATA *pMobIndex; int iFix; CREATE( rShop, REPAIR_DATA, 1 ); rShop->keeper = fread_number( fp ); if( rShop->keeper == 0 ) { DISPOSE( rShop ); break; } for( iFix = 0; iFix < MAX_FIX; iFix++ ) rShop->fix_type[iFix] = fread_number( fp ); rShop->profit_fix = fread_number( fp ); rShop->shop_type = fread_number( fp ); rShop->open_hour = fread_number( fp ); rShop->close_hour = fread_number( fp ); fread_to_eol( fp ); pMobIndex = get_mob_index( rShop->keeper ); pMobIndex->rShop = rShop; } } /* * Load spec proc declarations. */ void load_specials( FILE * fp ) { for( ;; ) { MOB_INDEX_DATA *pMobIndex; char letter; switch ( letter = fread_letter( fp ) ) { default: bug( "Load_specials: letter '%c' not *MS.", letter ); exit( 1 ); case 'S': return; case '*': break; case 'M': { char *temp; pMobIndex = get_mob_index( fread_number( fp ) ); temp = fread_word( fp ); pMobIndex->spec_funname = STRALLOC( temp ); } break; } fread_to_eol( fp ); } } /* * Load soft / hard area ranges. */ void load_ranges( AREA_DATA * tarea, FILE * fp ) { int x1, x2, x3, x4; char *ln; if( !tarea ) { bug( "Load_ranges: no #AREA seen yet." ); shutdown_mud( "No #AREA" ); exit( 1 ); } for( ;; ) { ln = fread_line( fp ); if( ln[0] == '$' ) break; x1 = x2 = x3 = x4 = 0; sscanf( ln, "%d %d %d %d", &x1, &x2, &x3, &x4 ); tarea->low_soft_range = x1; tarea->hi_soft_range = x2; tarea->low_hard_range = x3; tarea->hi_hard_range = x4; } return; } /* * With the new Weather System, these are unneeded as the weather is it's own * entity seperated from everything else. - Kayle 10-17-07 */ void load_climate( AREA_DATA * tarea, FILE * fp ) { fread_number( fp ); fread_number( fp ); fread_number( fp ); } /* * With the new Weather System, these are unneeded as the weather is it's own * entity seperated from everything else. - Kayle 10-17-07 */ void load_neighbor( AREA_DATA * tarea, FILE * fp ) { fread_flagstring( fp ); } /* * Get an extra description from a list. */ const char *get_extra_descr( const char *name, EXTRA_DESCR_DATA * ed ) { for( ; ed; ed = ed->next ) if( is_name( name, ed->keyword ) ) return ed->description; return NULL; } /* * Translates mob virtual number to its mob index struct. * Hash table lookup. */ MOB_INDEX_DATA *get_mob_index( int vnum ) { MOB_INDEX_DATA *pMobIndex; if( vnum < 0 ) vnum = 0; for( pMobIndex = mob_index_hash[vnum % MAX_KEY_HASH]; pMobIndex; pMobIndex = pMobIndex->next ) if( pMobIndex->vnum == vnum ) return pMobIndex; return NULL; } /* * Translates obj virtual number to its obj index struct. * Hash table lookup. */ OBJ_INDEX_DATA *get_obj_index( int vnum ) { OBJ_INDEX_DATA *pObjIndex; if( vnum < 0 ) vnum = 0; for( pObjIndex = obj_index_hash[vnum % MAX_KEY_HASH]; pObjIndex; pObjIndex = pObjIndex->next ) if( pObjIndex->vnum == vnum ) return pObjIndex; return NULL; } /* * Translates room virtual number to its room index struct. * Hash table lookup. */ ROOM_INDEX_DATA *get_room_index( int vnum ) { ROOM_INDEX_DATA *pRoomIndex; if( vnum < 0 ) vnum = 0; for( pRoomIndex = room_index_hash[vnum % MAX_KEY_HASH]; pRoomIndex; pRoomIndex = pRoomIndex->next ) if( pRoomIndex->vnum == vnum ) return pRoomIndex; return NULL; } /* * Added lots of EOF checks, as most of the file crashes are based on them. * If an area file encounters EOF, the fread_* functions will shutdown the * MUD, as all area files should be read in in full or bad things will * happen during the game. Any files loaded in without fBootDb which * encounter EOF will return what they have read so far. These files * should include player files, and in-progress areas that are not loaded * upon bootup. * -- Altrag */ /* * Read a letter from a file. */ char fread_letter( FILE * fp ) { char c; do { if( feof( fp ) ) { bug( "fread_letter: EOF encountered on read.\r\n" ); exit( 1 ); return '\0'; } c = getc( fp ); } while( isspace( c ) ); return c; } /* * Read a number from a file. */ int fread_number( FILE * fp ) { int number; bool sign; char c; do { if( feof( fp ) ) { bug( "fread_number: EOF encountered on read.\r\n" ); exit( 1 ); return 0; } c = getc( fp ); } while( isspace( c ) ); number = 0; sign = false; if( c == '+' ) { c = getc( fp ); } else if( c == '-' ) { sign = true; c = getc( fp ); } if( !isdigit( c ) ) { bug( "Fread_number: bad format. (%c)", c ); exit( 1 ); return 0; } while( isdigit( c ) ) { if( feof( fp ) ) { bug( "fread_number: EOF encountered on read.\r\n" ); exit( 1 ); return number; } number = number * 10 + c - '0'; c = getc( fp ); } if( sign ) number = 0 - number; if( c == '|' ) number += fread_number( fp ); else if( c != ' ' ) ungetc( c, fp ); return number; } /* * custom str_dup using create -Thoric */ char *str_dup( char const *str ) { static char *ret; int len; if( !str ) return NULL; len = strlen( str ) + 1; CREATE( ret, char, len ); mudstrlcpy( ret, str, MAX_STRING_LENGTH ); return ret; } /* Read a string from file and return it */ const char *fread_flagstring( FILE * fp ) { static char flagstring[MAX_STRING_LENGTH]; char *plast; char c; int ln; plast = flagstring; flagstring[0] = '\0'; ln = 0; /* * Skip blanks. Read first char. */ do { if( feof( fp ) ) { bug( "%s: EOF encountered on read.", __FUNCTION__ ); exit( 1 ); return ""; } c = getc( fp ); } while( isspace( c ) ); if( ( *plast++ = c ) == '~' ) return ""; for( ;; ) { if( ln >= ( MAX_STRING_LENGTH - 1 ) ) { bug( "%s: string too long", __FUNCTION__ ); *plast = '\0'; return flagstring; } switch ( *plast = getc( fp ) ) { default: plast++; ln++; break; case EOF: bug( "%s: EOF", __FUNCTION__ ); exit( 1 ); *plast = '\0'; return flagstring; break; case '\n': plast++; ln++; *plast++ = '\r'; ln++; break; case '\r': break; case '~': *plast = '\0'; return flagstring; } } } /* * Read a string from file fp */ const char *fread_string( FILE * fp ) { char buf[MAX_STRING_LENGTH]; char *plast; char c; int ln; plast = buf; buf[0] = '\0'; ln = 0; /* * Skip blanks. * Read first char. */ do { if( feof( fp ) ) { bug( "fread_string: EOF encountered on read.\r\n" ); exit( 1 ); return STRALLOC( "" ); } c = getc( fp ); } while( isspace( c ) ); if( ( *plast++ = c ) == '~' ) return STRALLOC( "" ); for( ;; ) { if( ln >= ( MAX_STRING_LENGTH - 1 ) ) { bug( "fread_string: string too long" ); *plast = '\0'; return STRALLOC( buf ); } switch ( *plast = getc( fp ) ) { default: plast++; ln++; break; case EOF: bug( "Fread_string: EOF" ); exit( 1 ); *plast = '\0'; return STRALLOC( buf ); break; case '\n': plast++; ln++; *plast++ = '\r'; ln++; break; case '\r': break; case '~': *plast = '\0'; return STRALLOC( buf ); } } } /* * Read a string from file fp using str_dup (ie: no string hashing) */ char *fread_string_nohash( FILE * fp ) { char buf[MAX_STRING_LENGTH]; char *plast; char c; int ln; plast = buf; buf[0] = '\0'; ln = 0; /* * Skip blanks. * Read first char. */ do { if( feof( fp ) ) { bug( "fread_string_no_hash: EOF encountered on read.\r\n" ); exit( 1 ); return str_dup( "" ); } c = getc( fp ); } while( isspace( c ) ); if( ( *plast++ = c ) == '~' ) return str_dup( "" ); for( ;; ) { if( ln >= ( MAX_STRING_LENGTH - 1 ) ) { bug( "fread_string_no_hash: string too long" ); *plast = '\0'; return str_dup( buf ); } switch ( *plast = getc( fp ) ) { default: plast++; ln++; break; case EOF: bug( "Fread_string_no_hash: EOF" ); exit( 1 ); *plast = '\0'; return str_dup( buf ); break; case '\n': plast++; ln++; *plast++ = '\r'; ln++; break; case '\r': break; case '~': *plast = '\0'; return str_dup( buf ); } } } /* * Read to end of line (for comments). */ void fread_to_eol( FILE * fp ) { char c; do { if( feof( fp ) ) { bug( "fread_to_eol: EOF encountered on read.\r\n" ); exit( 1 ); return; } c = getc( fp ); } while( c != '\n' && c != '\r' ); do { c = getc( fp ); } while( c == '\n' || c == '\r' ); ungetc( c, fp ); return; } /* * Read to end of line into static buffer -Thoric */ char *fread_line( FILE * fp ) { static char line[MAX_STRING_LENGTH]; char *pline; char c; int ln; pline = line; line[0] = '\0'; ln = 0; /* * Skip blanks. * Read first char. */ do { if( feof( fp ) ) { bug( "fread_line: EOF encountered on read.\r\n" ); exit( 1 ); mudstrlcpy( line, "", MAX_STRING_LENGTH ); return line; } c = getc( fp ); } while( isspace( c ) ); ungetc( c, fp ); do { if( feof( fp ) ) { bug( "fread_line: EOF encountered on read.\r\n" ); exit( 1 ); *pline = '\0'; return line; } c = getc( fp ); *pline++ = c; ln++; if( ln >= ( MAX_STRING_LENGTH - 1 ) ) { bug( "fread_line: line too long" ); break; } } while( c != '\n' && c != '\r' ); do { c = getc( fp ); } while( c == '\n' || c == '\r' ); ungetc( c, fp ); *pline = '\0'; return line; } /* * Read one word (into static buffer). */ char *fread_word( FILE * fp ) { static char word[MAX_INPUT_LENGTH]; char *pword; char cEnd; do { if( feof( fp ) ) { bug( "fread_word: EOF encountered on read.\r\n" ); exit( 1 ); word[0] = '\0'; return word; } cEnd = getc( fp ); } while( isspace( cEnd ) ); if( cEnd == '\'' || cEnd == '"' ) { pword = word; } else { word[0] = cEnd; pword = word + 1; cEnd = ' '; } for( ; pword < word + MAX_INPUT_LENGTH; pword++ ) { if( feof( fp ) ) { bug( "fread_word: EOF encountered on read.\r\n" ); exit( 1 ); word[0] = '\0'; return word; } *pword = getc( fp ); if( cEnd == ' ' ? isspace( *pword ) : *pword == cEnd ) { if( cEnd == ' ' ) ungetc( *pword, fp ); *pword = '\0'; return word; } } bug( "%s: word too long", __FUNCTION__ ); return NULL; } /* * Generate a random number. * Ooops was (number_mm() % to) + from which doesn't work -Shaddai */ int number_range( int from, int to ) { if( ( to - from ) < 1 ) return from; return ( ( number_mm( ) % ( to - from + 1 ) ) + from ); } /* * I've gotten too many bad reports on OS-supplied random number generators. * This is the Mitchell-Moore algorithm from Knuth Volume II. * Best to leave the constants alone unless you've read Knuth. * -- Furey */ static int rgiState[2 + 55]; void init_mm( ) { int *piState; int iState; piState = &rgiState[2]; piState[-2] = 55 - 55; piState[-1] = 55 - 24; piState[0] = ( ( int )current_time ) & ( ( 1 << 30 ) - 1 ); piState[1] = 1; for( iState = 2; iState < 55; iState++ ) { piState[iState] = ( piState[iState - 1] + piState[iState - 2] ) & ( ( 1 << 30 ) - 1 ); } return; } int number_mm( void ) { int *piState; int iState1; int iState2; int iRand; piState = &rgiState[2]; iState1 = piState[-2]; iState2 = piState[-1]; iRand = ( piState[iState1] + piState[iState2] ) & ( ( 1 << 30 ) - 1 ); piState[iState1] = iRand; if( ++iState1 == 55 ) iState1 = 0; if( ++iState2 == 55 ) iState2 = 0; piState[-2] = iState1; piState[-1] = iState2; return iRand >> 6; } /* * Removes the tildes from a string. * Used for player-entered strings that go into disk files. */ void smash_tilde( char *str ) { for( ; *str != '\0'; str++ ) if( *str == '~' ) *str = '-'; return; } /* * Compare strings, case insensitive. * Return true if different * (compatibility with historical functions). */ bool str_cmp( const char *astr, const char *bstr ) { if( !astr ) { bug( "Str_cmp: null astr." ); if( bstr ) fprintf( stderr, "str_cmp: astr: (null) bstr: %s\n", bstr ); return true; } if( !bstr ) { bug( "Str_cmp: null bstr." ); if( astr ) fprintf( stderr, "str_cmp: astr: %s bstr: (null)\n", astr ); return true; } for( ; *astr || *bstr; astr++, bstr++ ) { if( LOWER( *astr ) != LOWER( *bstr ) ) return true; } return false; } /* * Compare strings, case insensitive, for prefix matching. * Return true if astr not a prefix of bstr * (compatibility with historical functions). */ bool str_prefix( const char *astr, const char *bstr ) { if( !astr ) { bug( "Strn_cmp: null astr." ); return true; } if( !bstr ) { bug( "Strn_cmp: null bstr." ); return true; } for( ; *astr; astr++, bstr++ ) { if( LOWER( *astr ) != LOWER( *bstr ) ) return true; } return false; } /* * Returns true or false if a letter is a vowel -Thoric */ bool isavowel( char letter ) { char c; c = LOWER( letter ); if( c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u' ) return true; else return false; } /* * Reports a bug. */ void bug( const char *str, ... ) { char buf[MAX_STRING_LENGTH]; FILE *fp; struct stat fst; mudstrlcpy( buf, "[*****] BUG: ", MAX_STRING_LENGTH ); { va_list param; va_start( param, str ); vsnprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH - strlen( buf ) ), str, param ); va_end( param ); } log_string( buf ); if( fpArea != NULL ) { int iLine; int iChar; if( fpArea == stdin ) { iLine = 0; } else { iChar = ftell( fpArea ); fseek( fpArea, 0, 0 ); for( iLine = 0; ftell( fpArea ) < iChar; iLine++ ) { int letter; while( ( letter = getc( fpArea ) ) && letter != EOF && letter != '\n' ) ; } fseek( fpArea, iChar, 0 ); } log_printf( "[*****] FILE: %s LINE: %d", strArea, iLine ); if( stat( SHUTDOWN_FILE, &fst ) != -1 ) /* file exists */ { if( ( fp = fopen( SHUTDOWN_FILE, "a" ) ) != NULL ) { fprintf( fp, "%s\n", buf ); fprintf( fp, "[*****] FILE: %s LINE: %d\n", strArea, iLine ); fclose( fp ); fp = NULL; } } } return; } /* * Add a string to the boot-up log -Thoric */ void boot_log( const char *str, ... ) { char buf[MAX_STRING_LENGTH]; FILE *fp; va_list param; mudstrlcpy( buf, "[*****] BOOT: ", MAX_STRING_LENGTH ); va_start( param, str ); vsnprintf( buf + strlen( buf ), ( MAX_STRING_LENGTH - strlen( buf ) ), str, param ); va_end( param ); log_string( buf ); if( ( fp = fopen( BOOTLOG_FILE, "a" ) ) != NULL ) { fprintf( fp, "%s\n", buf ); fclose( fp ); } return; } /* * Writes a string to the log, extended version -Thoric */ void log_string_plus( const char *str, short log_type, short level ) { char *strtime; struct timeval now_time; /* * Update time. */ gettimeofday( &now_time, NULL ); current_time = ( time_t ) now_time.tv_sec; strtime = ctime( ¤t_time ); strtime[strlen( strtime ) - 1] = '\0'; fprintf( stderr, "%s :: %s\n", strtime, str ); } void log_printf_plus( short log_type, short level, const char *fmt, ... ) { char buf[MAX_STRING_LENGTH * 2]; va_list args; va_start( args, fmt ); vsnprintf( buf, MAX_STRING_LENGTH * 2, fmt, args ); va_end( args ); log_string_plus( buf, log_type, level ); } void log_printf( const char *fmt, ... ) { char buf[MAX_STRING_LENGTH * 2]; va_list args; va_start( args, fmt ); vsnprintf( buf, MAX_STRING_LENGTH * 2, fmt, args ); va_end( args ); log_string_plus( buf, LOG_NORMAL, LEVEL_LOG ); } /* mud prog functions */ /* This routine reads in scripts of MUDprograms from a file */ int mprog_name_to_type( const char *name ) { if( !str_cmp( name, "in_file_prog" ) ) return IN_FILE_PROG; if( !str_cmp( name, "act_prog" ) ) return ACT_PROG; if( !str_cmp( name, "speech_prog" ) ) return SPEECH_PROG; if( !str_cmp( name, "rand_prog" ) ) return RAND_PROG; if( !str_cmp( name, "fight_prog" ) ) return FIGHT_PROG; if( !str_cmp( name, "hitprcnt_prog" ) ) return HITPRCNT_PROG; if( !str_cmp( name, "death_prog" ) ) return DEATH_PROG; if( !str_cmp( name, "entry_prog" ) ) return ENTRY_PROG; if( !str_cmp( name, "greet_prog" ) ) return GREET_PROG; if( !str_cmp( name, "all_greet_prog" ) ) return ALL_GREET_PROG; if( !str_cmp( name, "give_prog" ) ) return GIVE_PROG; if( !str_cmp( name, "bribe_prog" ) ) return BRIBE_PROG; if( !str_cmp( name, "time_prog" ) ) return TIME_PROG; if( !str_cmp( name, "hour_prog" ) ) return HOUR_PROG; if( !str_cmp( name, "wear_prog" ) ) return WEAR_PROG; if( !str_cmp( name, "remove_prog" ) ) return REMOVE_PROG; if( !str_cmp( name, "sac_prog" ) ) return SAC_PROG; if( !str_cmp( name, "look_prog" ) ) return LOOK_PROG; if( !str_cmp( name, "exa_prog" ) ) return EXA_PROG; if( !str_cmp( name, "zap_prog" ) ) return ZAP_PROG; if( !str_cmp( name, "get_prog" ) ) return GET_PROG; if( !str_cmp( name, "drop_prog" ) ) return DROP_PROG; if( !str_cmp( name, "damage_prog" ) ) return DAMAGE_PROG; if( !str_cmp( name, "repair_prog" ) ) return REPAIR_PROG; if( !str_cmp( name, "greet_prog" ) ) return GREET_PROG; if( !str_cmp( name, "randiw_prog" ) ) return RANDIW_PROG; if( !str_cmp( name, "speechiw_prog" ) ) return SPEECHIW_PROG; if( !str_cmp( name, "pull_prog" ) ) return PULL_PROG; if( !str_cmp( name, "push_prog" ) ) return PUSH_PROG; if( !str_cmp( name, "sleep_prog" ) ) return SLEEP_PROG; if( !str_cmp( name, "rest_prog" ) ) return REST_PROG; if( !str_cmp( name, "rfight_prog" ) ) return FIGHT_PROG; if( !str_cmp( name, "enter_prog" ) ) return ENTRY_PROG; if( !str_cmp( name, "leave_prog" ) ) return LEAVE_PROG; if( !str_cmp( name, "rdeath_prog" ) ) return DEATH_PROG; if( !str_cmp( name, "script_prog" ) ) return SCRIPT_PROG; if( !str_cmp( name, "use_prog" ) ) return USE_PROG; return ( ERROR_PROG ); } void mobprog_file_read( MOB_INDEX_DATA * mob, const char *f ) { MPROG_DATA *mprg = NULL; char MUDProgfile[256]; FILE *progfile; char letter; snprintf( MUDProgfile, 256, "%s%s", PROG_DIR, f ); if( !( progfile = fopen( MUDProgfile, "r" ) ) ) { bug( "%s: couldn't open mudprog file", __FUNCTION__ ); return; } for( ;; ) { letter = fread_letter( progfile ); if( letter == '|' ) break; if( letter != '>' ) { bug( "%s: MUDPROG char", __FUNCTION__ ); break; } CREATE( mprg, MPROG_DATA, 1 ); mprg->type = mprog_name_to_type( fread_word( progfile ) ); switch ( mprg->type ) { case ERROR_PROG: bug( "%s: mudprog file type error", __FUNCTION__ ); DISPOSE( mprg ); continue; case IN_FILE_PROG: bug( "%s: Nested file programs are not allowed.", __FUNCTION__ ); DISPOSE( mprg ); continue; default: mprg->arglist = fread_string( progfile ); mprg->comlist = fread_string( progfile ); mprg->fileprog = true; xSET_BIT( mob->progtypes, mprg->type ); mprg->next = mob->mudprogs; mob->mudprogs = mprg; break; } } fclose( progfile ); progfile = NULL; return; } /* This procedure is responsible for reading any in_file MUDprograms. */ void mprog_read_programs( FILE * fp, MOB_INDEX_DATA * mob ) { MPROG_DATA *mprg; char letter; char *word; for( ;; ) { letter = fread_letter( fp ); if( letter == '|' ) return; if( letter != '>' ) { bug( "%s: vnum %d MUDPROG char", __FUNCTION__, mob->vnum ); exit( 1 ); } CREATE( mprg, MPROG_DATA, 1 ); mprg->next = mob->mudprogs; mob->mudprogs = mprg; word = fread_word( fp ); mprg->type = mprog_name_to_type( word ); switch ( mprg->type ) { case ERROR_PROG: bug( "%s: vnum %d MUDPROG type.", __FUNCTION__, mob->vnum ); exit( 1 ); case IN_FILE_PROG: mprg->arglist = fread_string( fp ); mprg->fileprog = false; mobprog_file_read( mob, mprg->arglist ); break; default: xSET_BIT( mob->progtypes, mprg->type ); mprg->fileprog = false; mprg->arglist = fread_string( fp ); mprg->comlist = fread_string( fp ); break; } } return; } /*************************************************************/ /* obj prog functions */ /* This routine transfers between alpha and numeric forms of the * mob_prog bitvector types. This allows the use of the words in the * mob/script files. */ /* This routine reads in scripts of OBJprograms from a file */ void objprog_file_read( OBJ_INDEX_DATA * obj, const char *f ) { MPROG_DATA *mprg = NULL; char MUDProgfile[256]; FILE *progfile; char letter; snprintf( MUDProgfile, 256, "%s%s", PROG_DIR, f ); if( !( progfile = fopen( MUDProgfile, "r" ) ) ) { bug( "%s: couldn't open mudprog file", __FUNCTION__ ); return; } for( ;; ) { letter = fread_letter( progfile ); if( letter == '|' ) break; if( letter != '>' ) { bug( "%s: MUDPROG char", __FUNCTION__ ); break; } CREATE( mprg, MPROG_DATA, 1 ); mprg->type = mprog_name_to_type( fread_word( progfile ) ); switch ( mprg->type ) { case ERROR_PROG: bug( "%s: mudprog file type error", __FUNCTION__ ); DISPOSE( mprg ); continue; case IN_FILE_PROG: bug( "%s: Nested file programs are not allowed.", __FUNCTION__ ); DISPOSE( mprg ); continue; default: mprg->arglist = fread_string( progfile ); mprg->comlist = fread_string( progfile ); mprg->fileprog = true; xSET_BIT( obj->progtypes, mprg->type ); mprg->next = obj->mudprogs; obj->mudprogs = mprg; break; } } fclose( progfile ); progfile = NULL; return; } /* This procedure is responsible for reading any in_file OBJprograms. */ void oprog_read_programs( FILE * fp, OBJ_INDEX_DATA * obj ) { MPROG_DATA *mprg; char letter; char *word; for( ;; ) { letter = fread_letter( fp ); if( letter == '|' ) return; if( letter != '>' ) { bug( "%s: vnum %d MUDPROG char", __FUNCTION__, obj->vnum ); exit( 1 ); } CREATE( mprg, MPROG_DATA, 1 ); mprg->next = obj->mudprogs; obj->mudprogs = mprg; word = fread_word( fp ); mprg->type = mprog_name_to_type( word ); switch ( mprg->type ) { case ERROR_PROG: bug( "%s: vnum %d MUDPROG type.", __FUNCTION__, obj->vnum ); exit( 1 ); case IN_FILE_PROG: mprg->arglist = fread_string( fp ); mprg->fileprog = false; objprog_file_read( obj, mprg->arglist ); break; default: xSET_BIT( obj->progtypes, mprg->type ); mprg->fileprog = false; mprg->arglist = fread_string( fp ); mprg->comlist = fread_string( fp ); break; } } return; } /*************************************************************/ /* room prog functions */ /* This routine transfers between alpha and numeric forms of the * mob_prog bitvector types. This allows the use of the words in the * mob/script files. */ /* This routine reads in scripts of OBJprograms from a file */ void roomprog_file_read( ROOM_INDEX_DATA * room, const char *f ) { MPROG_DATA *mprg = NULL; char MUDProgfile[256]; FILE *progfile; char letter; snprintf( MUDProgfile, 256, "%s%s", PROG_DIR, f ); if( !( progfile = fopen( MUDProgfile, "r" ) ) ) { bug( "%s: couldn't open mudprog file", __FUNCTION__ ); return; } for( ;; ) { letter = fread_letter( progfile ); if( letter == '|' ) break; if( letter != '>' ) { bug( "%s: MUDPROG char", __FUNCTION__ ); break; } CREATE( mprg, MPROG_DATA, 1 ); mprg->type = mprog_name_to_type( fread_word( progfile ) ); switch ( mprg->type ) { case ERROR_PROG: bug( "%s: mudprog file type error", __FUNCTION__ ); DISPOSE( mprg ); continue; case IN_FILE_PROG: bug( "%s: Nested file programs are not allowed.", __FUNCTION__ ); DISPOSE( mprg ); continue; default: mprg->arglist = fread_string( progfile ); mprg->comlist = fread_string( progfile ); mprg->fileprog = true; xSET_BIT( room->progtypes, mprg->type ); mprg->next = room->mudprogs; room->mudprogs = mprg; break; } } fclose( progfile ); progfile = NULL; return; } /* This procedure is responsible for reading any in_file ROOMprograms. */ void rprog_read_programs( FILE * fp, ROOM_INDEX_DATA * room ) { MPROG_DATA *mprg; char letter; char *word; for( ;; ) { letter = fread_letter( fp ); if( letter == '|' ) return; if( letter != '>' ) { bug( "%s: vnum %d MUDPROG char", __FUNCTION__, room->vnum ); exit( 1 ); } CREATE( mprg, MPROG_DATA, 1 ); mprg->next = room->mudprogs; room->mudprogs = mprg; word = fread_word( fp ); mprg->type = mprog_name_to_type( word ); switch ( mprg->type ) { case ERROR_PROG: bug( "%s: vnum %d MUDPROG type.", __FUNCTION__, room->vnum ); exit( 1 ); case IN_FILE_PROG: mprg->arglist = fread_string( fp ); mprg->fileprog = false; roomprog_file_read( room, mprg->arglist ); break; default: xSET_BIT( room->progtypes, mprg->type ); mprg->fileprog = false; mprg->arglist = fread_string( fp ); mprg->comlist = fread_string( fp ); break; } } return; } /* * Creates a simple exit with no fields filled but rvnum and optionally * to_room and vnum. -Thoric * Exits are inserted into the linked list based on vdir. */ EXIT_DATA *make_exit( ROOM_INDEX_DATA * pRoomIndex, ROOM_INDEX_DATA * to_room, short door ) { EXIT_DATA *pexit, *texit; bool broke; CREATE( pexit, EXIT_DATA, 1 ); pexit->vdir = door; pexit->rvnum = pRoomIndex->vnum; pexit->to_room = to_room; pexit->distance = 1; pexit->key = -1; if( to_room ) { pexit->vnum = to_room->vnum; texit = get_exit_to( to_room, rev_dir[door], pRoomIndex->vnum ); if( texit ) /* assign reverse exit pointers */ { texit->rexit = pexit; pexit->rexit = texit; } } broke = false; for( texit = pRoomIndex->first_exit; texit; texit = texit->next ) if( door < texit->vdir ) { broke = true; break; } if( !pRoomIndex->first_exit ) pRoomIndex->first_exit = pexit; else { /* * keep exits in incremental order - insert exit into list */ if( broke && texit ) { if( !texit->prev ) pRoomIndex->first_exit = pexit; else texit->prev->next = pexit; pexit->prev = texit->prev; pexit->next = texit; texit->prev = pexit; return pexit; } pRoomIndex->last_exit->next = pexit; } pexit->next = NULL; pexit->prev = pRoomIndex->last_exit; pRoomIndex->last_exit = pexit; return pexit; } void process_sorting( AREA_DATA * tarea ) { fprintf( stderr, "%-14s: Rooms: %5d - %-5d Objs: %5d - %-5d Mobs: %5d - %d\n", tarea->filename, tarea->low_r_vnum, tarea->hi_r_vnum, tarea->low_o_vnum, tarea->hi_o_vnum, tarea->low_m_vnum, tarea->hi_m_vnum ); if( !tarea->author ) tarea->author = STRALLOC( "" ); } EXTRA_DESCR_DATA *fread_fuss_exdesc( FILE * fp ) { EXTRA_DESCR_DATA *ed; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro CREATE( ed, EXTRA_DESCR_DATA, 1 ); for( ;; ) { const char *word = ( feof( fp ) ? "#ENDEXDESC" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDEXDESC"; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case '#': if( !str_cmp( word, "#ENDEXDESC" ) ) { if( !ed->keyword ) { bug( "%s: Missing ExDesc keyword. Returning NULL.", __FUNCTION__ ); STRFREE( ed->description ); DISPOSE( ed ); return NULL; } if( !ed->description ) ed->description = STRALLOC( "" ); return ed; } break; case 'E': KEY( "ExDescKey", ed->keyword, fread_string( fp ) ); KEY( "ExDesc", ed->description, fread_string( fp ) ); break; } } // Reach this point, you fell through somehow. The data is no longer valid. bug( "%s: Reached fallout point! ExtraDesc data invalid.", __FUNCTION__ ); DISPOSE( ed ); return NULL; } AFFECT_DATA *fread_fuss_affect( FILE * fp, const char *word ) { AFFECT_DATA *paf; int pafmod; CREATE( paf, AFFECT_DATA, 1 ); if( !strcmp( word, "Affect" ) ) { paf->type = fread_number( fp ); } else { int sn; sn = skill_lookup( fread_word( fp ) ); if( sn < 0 ) bug( "%s: unknown skill.", __FUNCTION__ ); else paf->type = sn; } paf->duration = fread_number( fp ); pafmod = fread_number( fp ); paf->location = fread_number( fp ); paf->bitvector = fread_bitvector( fp ); if( paf->location == APPLY_WEAPONSPELL || paf->location == APPLY_WEARSPELL || paf->location == APPLY_STRIPSN || paf->location == APPLY_REMOVESPELL || paf->location == APPLY_RECURRINGSPELL ) paf->modifier = slot_lookup( pafmod ); else paf->modifier = pafmod; return paf; } void fread_fuss_exit( FILE * fp, ROOM_INDEX_DATA * pRoomIndex ) { EXIT_DATA *pexit = NULL; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDEXIT" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDEXIT"; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case '#': if( !str_cmp( word, "#ENDEXIT" ) ) { if( !pexit->description ) pexit->description = STRALLOC( "" ); if( !pexit->keyword ) pexit->keyword = STRALLOC( "" ); return; } break; case 'D': KEY( "Desc", pexit->description, fread_string( fp ) ); KEY( "Distance", pexit->distance, fread_number( fp ) ); if( !str_cmp( word, "Direction" ) ) { int door = get_dir( fread_flagstring( fp ) ); if( door < 0 || door > DIR_SOMEWHERE ) { bug( "%s: vnum %d has bad door number %d.", __FUNCTION__, pRoomIndex->vnum, door ); return; } pexit = make_exit( pRoomIndex, NULL, door ); } break; case 'F': if( !str_cmp( word, "Flags" ) ) { const char *exitflags = NULL; char flag[MAX_INPUT_LENGTH]; int value; exitflags = fread_flagstring( fp ); while( exitflags[0] != '\0' ) { exitflags = one_argument( exitflags, flag ); value = get_exflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown exitflag: %s", flag ); else SET_BIT( pexit->exit_info, 1 << value ); } break; } break; case 'K': KEY( "Key", pexit->key, fread_number( fp ) ); KEY( "Keywords", pexit->keyword, fread_string( fp ) ); break; case 'P': if( !str_cmp( word, "Pull" ) ) { pexit->pulltype = fread_number( fp ); pexit->pull = fread_number( fp ); break; } break; case 'T': KEY( "ToRoom", pexit->vnum, fread_number( fp ) ); break; } } // Reach this point, you fell through somehow. The data is no longer valid. bug( "%s: Reached fallout point! Exit data invalid.", __FUNCTION__ ); if( pexit ) extract_exit( pRoomIndex, pexit ); } void rprog_file_read( ROOM_INDEX_DATA * prog_target, const char *f ) { MPROG_DATA *mprg = NULL; char MUDProgfile[256]; FILE *progfile; char letter; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro snprintf( MUDProgfile, 256, "%s%s", PROG_DIR, f ); if( !( progfile = fopen( MUDProgfile, "r" ) ) ) { bug( "%s: couldn't open mudprog file", __FUNCTION__ ); return; } for( ;; ) { letter = fread_letter( progfile ); if( letter != '#' ) { bug( "%s: MUDPROG char", __FUNCTION__ ); break; } const char *word = ( feof( progfile ) ? "ENDFILE" : fread_word( progfile ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "ENDFILE"; } if( !str_cmp( word, "ENDFILE" ) ) break; if( !str_cmp( word, "MUDPROG" ) ) { CREATE( mprg, MPROG_DATA, 1 ); for( ;; ) { word = ( feof( progfile ) ? "#ENDPROG" : fread_word( progfile ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDPROG"; } if( !str_cmp( word, "#ENDPROG" ) ) { mprg->next = prog_target->mudprogs; prog_target->mudprogs = mprg; break; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( progfile ); break; case 'A': if( !str_cmp( word, "Arglist" ) ) { mprg->arglist = fread_string( progfile ); mprg->fileprog = true; switch ( mprg->type ) { case IN_FILE_PROG: bug( "%s: Nested file programs are not allowed.", __FUNCTION__ ); DISPOSE( mprg ); break; default: break; } break; } break; case 'C': KEY( "Comlist", mprg->comlist, fread_string( progfile ) ); break; case 'P': if( !str_cmp( word, "Progtype" ) ) { mprg->type = mprog_name_to_type( fread_flagstring( progfile ) ); break; } break; } } } } fclose( progfile ); progfile = NULL; return; } void fread_fuss_roomprog( FILE * fp, MPROG_DATA * mprg, ROOM_INDEX_DATA * prog_target ) { bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDPROG" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDPROG"; } if( !str_cmp( word, "#ENDPROG" ) ) return; switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case 'A': if( !str_cmp( word, "Arglist" ) ) { mprg->arglist = fread_string( fp ); mprg->fileprog = false; switch ( mprg->type ) { case IN_FILE_PROG: rprog_file_read( prog_target, mprg->arglist ); break; default: break; } break; } break; case 'C': KEY( "Comlist", mprg->comlist, fread_string( fp ) ); break; case 'P': if( !str_cmp( word, "Progtype" ) ) { mprg->type = mprog_name_to_type( fread_flagstring( fp ) ); xSET_BIT( prog_target->progtypes, mprg->type ); break; } break; } } } void fread_fuss_room( FILE * fp, AREA_DATA * tarea ) { ROOM_INDEX_DATA *pRoomIndex = NULL; bool oldroom = false; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDROOM" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDROOM"; } switch ( word[0] ) { default: bug( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case '#': if( !str_cmp( word, "#ENDROOM" ) ) { if( !pRoomIndex->description ) pRoomIndex->description = STRALLOC( "" ); if( !oldroom ) { int iHash = pRoomIndex->vnum % MAX_KEY_HASH; pRoomIndex->next = room_index_hash[iHash]; room_index_hash[iHash] = pRoomIndex; LINK( pRoomIndex, tarea->first_room, tarea->last_room, next_aroom, prev_aroom ); } return; } if( !str_cmp( word, "#EXIT" ) ) { fread_fuss_exit( fp, pRoomIndex ); break; } if( !str_cmp( word, "#EXDESC" ) ) { EXTRA_DESCR_DATA *ed = fread_fuss_exdesc( fp ); if( ed ) LINK( ed, pRoomIndex->first_extradesc, pRoomIndex->last_extradesc, next, prev ); break; } if( !str_cmp( word, "#MUDPROG" ) ) { MPROG_DATA *mprg; CREATE( mprg, MPROG_DATA, 1 ); fread_fuss_roomprog( fp, mprg, pRoomIndex ); mprg->next = pRoomIndex->mudprogs; pRoomIndex->mudprogs = mprg; break; } break; case 'A': if( !str_cmp( word, "Affect" ) || !str_cmp( word, "AffectData" ) ) { AFFECT_DATA *af = fread_fuss_affect( fp, word ); if( af ) LINK( af, pRoomIndex->first_permaffect, pRoomIndex->last_permaffect, next, prev ); break; } break; case 'D': KEY( "Desc", pRoomIndex->description, fread_string( fp ) ); break; case 'F': if( !str_cmp( word, "Flags" ) ) { const char *roomflags = NULL; char flag[MAX_INPUT_LENGTH]; int value; roomflags = fread_flagstring( fp ); while( roomflags[0] != '\0' ) { roomflags = one_argument( roomflags, flag ); value = get_rflag( flag ); if( value < 0 || value >= MAX_BITS ) bug( "Unknown roomflag: %s", flag ); else xSET_BIT( pRoomIndex->room_flags, value ); } break; } break; case 'N': KEY( "Name", pRoomIndex->name, fread_string( fp ) ); break; case 'R': if( !str_cmp( word, "Reset" ) ) { load_room_reset( pRoomIndex, fp ); break; } break; case 'S': if( !str_cmp( word, "Sector" ) ) { int sector = get_secflag( fread_flagstring( fp ) ); if( sector < 0 || sector >= SECT_MAX ) { bug( "%s: Room #%d has bad sector type.", __FUNCTION__, pRoomIndex->vnum ); sector = 1; } pRoomIndex->sector_type = sector; break; } if( !str_cmp( word, "Stats" ) ) { char *ln = fread_line( fp ); int x1, x2, x3; x1 = x2 = x3 = 0; sscanf( ln, "%d %d %d", &x1, &x2, &x3 ); pRoomIndex->tele_delay = x1; pRoomIndex->tele_vnum = x2; pRoomIndex->tunnel = x3; break; } break; case 'V': if( !str_cmp( word, "Vnum" ) ) { int vnum = fread_number( fp ); if( get_room_index( vnum ) ) { bug( "%s: vnum %d duplicated.", __FUNCTION__, vnum ); // Try to recover, read to end of duplicated room and then bail out for( ;; ) { word = feof( fp ) ? "#ENDROOM" : fread_word( fp ); if( !str_cmp( word, "#ENDROOM" ) ) return; } } else { CREATE( pRoomIndex, ROOM_INDEX_DATA, 1 ); oldroom = false; } pRoomIndex->vnum = vnum; pRoomIndex->area = tarea; if( !tarea->low_r_vnum ) tarea->low_r_vnum = vnum; if( vnum > tarea->hi_r_vnum ) tarea->hi_r_vnum = vnum; break; } break; } } } void oprog_file_read( OBJ_INDEX_DATA * prog_target, const char *f ) { MPROG_DATA *mprg = NULL; char MUDProgfile[256]; FILE *progfile; char letter; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro snprintf( MUDProgfile, 256, "%s%s", PROG_DIR, f ); if( !( progfile = fopen( MUDProgfile, "r" ) ) ) { bug( "%s: couldn't open mudprog file", __FUNCTION__ ); return; } for( ;; ) { letter = fread_letter( progfile ); if( letter != '#' ) { bug( "%s: MUDPROG char", __FUNCTION__ ); break; } const char *word = ( feof( progfile ) ? "ENDFILE" : fread_word( progfile ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "ENDFILE"; } if( !str_cmp( word, "ENDFILE" ) ) break; if( !str_cmp( word, "MUDPROG" ) ) { CREATE( mprg, MPROG_DATA, 1 ); for( ;; ) { word = ( feof( progfile ) ? "#ENDPROG" : fread_word( progfile ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDPROG"; } if( !str_cmp( word, "#ENDPROG" ) ) { mprg->next = prog_target->mudprogs; prog_target->mudprogs = mprg; break; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( progfile ); break; case 'A': if( !str_cmp( word, "Arglist" ) ) { mprg->arglist = fread_string( progfile ); mprg->fileprog = true; switch ( mprg->type ) { case IN_FILE_PROG: bug( "%s: Nested file programs are not allowed.", __FUNCTION__ ); DISPOSE( mprg ); break; default: break; } break; } break; case 'C': KEY( "Comlist", mprg->comlist, fread_string( progfile ) ); break; case 'P': if( !str_cmp( word, "Progtype" ) ) { mprg->type = mprog_name_to_type( fread_flagstring( progfile ) ); break; } break; } } } } fclose( progfile ); progfile = NULL; return; } void fread_fuss_objprog( FILE * fp, MPROG_DATA * mprg, OBJ_INDEX_DATA * prog_target ) { bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDPROG" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDPROG"; } if( !str_cmp( word, "#ENDPROG" ) ) return; switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case 'A': if( !str_cmp( word, "Arglist" ) ) { mprg->arglist = fread_string( fp ); mprg->fileprog = false; switch ( mprg->type ) { case IN_FILE_PROG: oprog_file_read( prog_target, mprg->arglist ); break; default: break; } break; } break; case 'C': KEY( "Comlist", mprg->comlist, fread_string( fp ) ); break; case 'P': if( !str_cmp( word, "Progtype" ) ) { mprg->type = mprog_name_to_type( fread_flagstring( fp ) ); xSET_BIT( prog_target->progtypes, mprg->type ); break; } break; } } } void fread_fuss_object( FILE * fp, AREA_DATA * tarea ) { OBJ_INDEX_DATA *pObjIndex = NULL; bool oldobj = false; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDOBJECT" : fread_word( fp ) ); char flag[MAX_INPUT_LENGTH]; int value = 0; if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDOBJECT"; } switch ( word[0] ) { default: bug( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case '#': if( !str_cmp( word, "#ENDOBJECT" ) ) { if( !pObjIndex->description ) pObjIndex->description = STRALLOC( "" ); if( !pObjIndex->action_desc ) pObjIndex->action_desc = STRALLOC( "" ); if( !oldobj ) { int iHash = pObjIndex->vnum % MAX_KEY_HASH; pObjIndex->next = obj_index_hash[iHash]; obj_index_hash[iHash] = pObjIndex; } return; } if( !str_cmp( word, "#EXDESC" ) ) { EXTRA_DESCR_DATA *ed = fread_fuss_exdesc( fp ); if( ed ) LINK( ed, pObjIndex->first_extradesc, pObjIndex->last_extradesc, next, prev ); break; } if( !str_cmp( word, "#MUDPROG" ) ) { MPROG_DATA *mprg; CREATE( mprg, MPROG_DATA, 1 ); fread_fuss_objprog( fp, mprg, pObjIndex ); mprg->next = pObjIndex->mudprogs; pObjIndex->mudprogs = mprg; break; } break; case 'A': KEY( "Action", pObjIndex->action_desc, fread_string( fp ) ); if( !str_cmp( word, "Affect" ) || !str_cmp( word, "AffectData" ) ) { AFFECT_DATA *af = fread_fuss_affect( fp, word ); if( af ) LINK( af, pObjIndex->first_affect, pObjIndex->last_affect, next, prev ); break; } break; case 'F': if( !str_cmp( word, "Flags" ) ) { const char *eflags = fread_flagstring( fp ); while( eflags[0] != '\0' ) { eflags = one_argument( eflags, flag ); value = get_oflag( flag ); if( value < 0 || value >= MAX_BITS ) bug( "Unknown object extraflag: %s", flag ); else xSET_BIT( pObjIndex->extra_flags, value ); } break; } break; case 'K': KEY( "Keywords", pObjIndex->name, fread_string( fp ) ); break; case 'L': KEY( "Long", pObjIndex->description, fread_string( fp ) ); break; case 'S': KEY( "Short", pObjIndex->short_descr, fread_string( fp ) ); if( !str_cmp( word, "Spells" ) ) { switch ( pObjIndex->item_type ) { default: break; case ITEM_PILL: case ITEM_POTION: case ITEM_SCROLL: pObjIndex->value[1] = skill_lookup( fread_word( fp ) ); pObjIndex->value[2] = skill_lookup( fread_word( fp ) ); pObjIndex->value[3] = skill_lookup( fread_word( fp ) ); break; case ITEM_STAFF: case ITEM_WAND: pObjIndex->value[3] = skill_lookup( fread_word( fp ) ); break; case ITEM_SALVE: pObjIndex->value[4] = skill_lookup( fread_word( fp ) ); pObjIndex->value[5] = skill_lookup( fread_word( fp ) ); break; } break; } if( !str_cmp( word, "Stats" ) ) { char *ln = fread_line( fp ); int x1, x2, x3, x4, x5; x1 = x2 = x3 = x4 = x5 = 0; sscanf( ln, "%d %d %d %d %d", &x1, &x2, &x3, &x4, &x5 ); pObjIndex->weight = x1; pObjIndex->cost = x2; pObjIndex->rent = x3; pObjIndex->level = x4; pObjIndex->layers = x5; break; } break; case 'T': if( !str_cmp( word, "Type" ) ) { value = get_otype( fread_flagstring( fp ) ); if( value < 0 ) { bug( "%s: vnum %d: Object has invalid type! Defaulting to trash.", __FUNCTION__, pObjIndex->vnum ); value = get_otype( "trash" ); } pObjIndex->item_type = value; break; } break; case 'V': if( !str_cmp( word, "Values" ) ) { char *ln = fread_line( fp ); int x1, x2, x3, x4, x5, x6; x1 = x2 = x3 = x4 = x5 = x6 = 0; sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 ); pObjIndex->value[0] = x1; pObjIndex->value[1] = x2; pObjIndex->value[2] = x3; pObjIndex->value[3] = x4; pObjIndex->value[4] = x5; pObjIndex->value[5] = x6; break; } if( !str_cmp( word, "Vnum" ) ) { int vnum = fread_number( fp ); if( get_obj_index( vnum ) ) { bug( "%s: vnum %d duplicated.", __FUNCTION__, vnum ); // Try to recover, read to end of duplicated object and then bail out for( ;; ) { word = feof( fp ) ? "#ENDOBJECT" : fread_word( fp ); if( !str_cmp( word, "#ENDOBJECT" ) ) return; } } else { CREATE( pObjIndex, OBJ_INDEX_DATA, 1 ); oldobj = false; } pObjIndex->vnum = vnum; if( !tarea->low_o_vnum ) tarea->low_o_vnum = vnum; if( vnum > tarea->hi_o_vnum ) tarea->hi_o_vnum = vnum; break; } break; case 'W': if( !str_cmp( word, "WFlags" ) ) { const char *wflags = fread_flagstring( fp ); while( wflags[0] != '\0' ) { wflags = one_argument( wflags, flag ); value = get_wflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown wear flag: %s", flag ); else SET_BIT( pObjIndex->wear_flags, 1 << value ); } break; } break; } } } void mprog_file_read( MOB_INDEX_DATA * prog_target, const char *f ) { MPROG_DATA *mprg = NULL; char MUDProgfile[256]; FILE *progfile; char letter; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro snprintf( MUDProgfile, 256, "%s%s", PROG_DIR, f ); if( !( progfile = fopen( MUDProgfile, "r" ) ) ) { bug( "%s: couldn't open mudprog file", __FUNCTION__ ); return; } for( ;; ) { letter = fread_letter( progfile ); if( letter != '#' ) { bug( "%s: MUDPROG char", __FUNCTION__ ); break; } const char *word = ( feof( progfile ) ? "ENDFILE" : fread_word( progfile ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "ENDFILE"; } if( !str_cmp( word, "ENDFILE" ) ) break; if( !str_cmp( word, "MUDPROG" ) ) { CREATE( mprg, MPROG_DATA, 1 ); for( ;; ) { word = ( feof( progfile ) ? "#ENDPROG" : fread_word( progfile ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDPROG"; } if( !str_cmp( word, "#ENDPROG" ) ) { mprg->next = prog_target->mudprogs; prog_target->mudprogs = mprg; break; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( progfile ); break; case 'A': if( !str_cmp( word, "Arglist" ) ) { mprg->arglist = fread_string( progfile ); mprg->fileprog = true; switch ( mprg->type ) { case IN_FILE_PROG: bug( "%s: Nested file programs are not allowed.", __FUNCTION__ ); DISPOSE( mprg ); break; default: break; } break; } break; case 'C': KEY( "Comlist", mprg->comlist, fread_string( progfile ) ); break; case 'P': if( !str_cmp( word, "Progtype" ) ) { mprg->type = mprog_name_to_type( fread_flagstring( progfile ) ); break; } break; } } } } fclose( progfile ); progfile = NULL; return; } void fread_fuss_mobprog( FILE * fp, MPROG_DATA * mprg, MOB_INDEX_DATA * prog_target ) { bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDPROG" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDPROG"; } if( !str_cmp( word, "#ENDPROG" ) ) return; switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case 'A': if( !str_cmp( word, "Arglist" ) ) { mprg->arglist = fread_string( fp ); mprg->fileprog = false; switch ( mprg->type ) { case IN_FILE_PROG: mprog_file_read( prog_target, mprg->arglist ); break; default: break; } break; } break; case 'C': KEY( "Comlist", mprg->comlist, fread_string( fp ) ); break; case 'P': if( !str_cmp( word, "Progtype" ) ) { mprg->type = mprog_name_to_type( fread_flagstring( fp ) ); xSET_BIT( prog_target->progtypes, mprg->type ); break; } break; } } } void fread_fuss_mobile( FILE * fp, AREA_DATA * tarea ) { MOB_INDEX_DATA *pMobIndex = NULL; bool oldmob = false; bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDMOBILE" : fread_word( fp ) ); char flag[MAX_INPUT_LENGTH]; int value = 0; if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDMOBILE"; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case '#': if( !str_cmp( word, "#MUDPROG" ) ) { MPROG_DATA *mprg; CREATE( mprg, MPROG_DATA, 1 ); fread_fuss_mobprog( fp, mprg, pMobIndex ); mprg->next = pMobIndex->mudprogs; pMobIndex->mudprogs = mprg; break; } if( !str_cmp( word, "#ENDMOBILE" ) ) { if( !pMobIndex->long_descr ) pMobIndex->long_descr = STRALLOC( "" ); if( !pMobIndex->description ) pMobIndex->description = STRALLOC( "" ); if( !oldmob ) { int iHash = pMobIndex->vnum % MAX_KEY_HASH; pMobIndex->next = mob_index_hash[iHash]; mob_index_hash[iHash] = pMobIndex; } return; } break; case 'A': if( !str_cmp( word, "Actflags" ) ) { const char *actflags = NULL; actflags = fread_flagstring( fp ); while( actflags[0] != '\0' ) { actflags = one_argument( actflags, flag ); value = get_actflag( flag ); if( value < 0 || value >= MAX_BITS ) bug( "Unknown actflag: %s", flag ); else xSET_BIT( pMobIndex->act, value ); } break; } if( !str_cmp( word, "Affected" ) ) { const char *affectflags = NULL; affectflags = fread_flagstring( fp ); while( affectflags[0] != '\0' ) { affectflags = one_argument( affectflags, flag ); value = get_aflag( flag ); if( value < 0 || value >= MAX_BITS ) bug( "Unknown affectflag: %s", flag ); else xSET_BIT( pMobIndex->affected_by, value ); } break; } if( !str_cmp( word, "Attacks" ) ) { const char *attacks = fread_flagstring( fp ); while( attacks[0] != '\0' ) { attacks = one_argument( attacks, flag ); value = get_attackflag( flag ); if( value < 0 || value >= MAX_BITS ) bug( "Unknown attackflag: %s", flag ); else xSET_BIT( pMobIndex->attacks, value ); } break; } if( !str_cmp( word, "Attribs" ) ) { char *ln = fread_line( fp ); int x1, x2, x3, x4, x5, x6, x7; x1 = x2 = x3 = x4 = x5 = x6 = x7 = 0; sscanf( ln, "%d %d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6, &x7 ); pMobIndex->perm_str = x1; pMobIndex->perm_int = x2; pMobIndex->perm_wis = x3; pMobIndex->perm_dex = x4; pMobIndex->perm_con = x5; pMobIndex->perm_cha = x6; pMobIndex->perm_lck = x7; break; } break; case 'B': if( !str_cmp( word, "Bodyparts" ) ) { const char *bodyparts = fread_flagstring( fp ); while( bodyparts[0] != '\0' ) { bodyparts = one_argument( bodyparts, flag ); value = get_partflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown bodypart: %s", flag ); else SET_BIT( pMobIndex->xflags, 1 << value ); } break; } break; case 'C': if( !str_cmp( word, "Class" ) ) { fread_flagstring( fp ); break; } break; case 'D': if( !str_cmp( word, "Defenses" ) ) { const char *defenses = fread_flagstring( fp ); while( defenses[0] != '\0' ) { defenses = one_argument( defenses, flag ); value = get_defenseflag( flag ); if( value < 0 || value >= MAX_BITS ) bug( "Unknown defenseflag: %s", flag ); else xSET_BIT( pMobIndex->defenses, value ); } break; } if( !str_cmp( word, "DefPos" ) ) { short position = get_npc_position( fread_flagstring( fp ) ); if( position < 0 || position > POS_DRAG ) { bug( "%s: vnum %d: Mobile in invalid default position! Defaulting to standing.", __FUNCTION__, pMobIndex->vnum ); position = POS_STANDING; } pMobIndex->defposition = position; break; } KEY( "Desc", pMobIndex->description, fread_string( fp ) ); break; case 'G': if( !str_cmp( word, "Gender" ) ) { short sex = get_npc_sex( fread_flagstring( fp ) ); if( sex < 0 || sex > SEX_FEMALE ) { bug( "%s: vnum %d: Mobile has invalid sex! Defaulting to neuter.", __FUNCTION__, pMobIndex->vnum ); sex = SEX_NEUTRAL; } pMobIndex->sex = sex; break; } break; case 'I': if( !str_cmp( word, "Immune" ) ) { const char *immune = fread_flagstring( fp ); while( immune[0] != '\0' ) { immune = one_argument( immune, flag ); value = get_risflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown RIS flag (I): %s", flag ); else SET_BIT( pMobIndex->immune, 1 << value ); } break; } break; case 'K': KEY( "Keywords", pMobIndex->player_name, fread_string( fp ) ); break; case 'L': KEY( "Long", pMobIndex->long_descr, fread_string( fp ) ); break; case 'P': if( !str_cmp( word, "Position" ) ) { short position = get_npc_position( fread_flagstring( fp ) ); if( position < 0 || position > POS_DRAG ) { bug( "%s: vnum %d: Mobile in invalid position! Defaulting to standing.", __FUNCTION__, pMobIndex->vnum ); position = POS_STANDING; } pMobIndex->position = position; break; } break; case 'R': if( !str_cmp( word, "Race" ) ) { fread_flagstring( fp ); break; } if( !str_cmp( word, "RepairData" ) ) { int iFix; REPAIR_DATA *rShop; CREATE( rShop, REPAIR_DATA, 1 ); rShop->keeper = pMobIndex->vnum; for( iFix = 0; iFix < MAX_FIX; ++iFix ) rShop->fix_type[iFix] = fread_number( fp ); rShop->profit_fix = fread_number( fp ); rShop->shop_type = fread_number( fp ); rShop->open_hour = fread_number( fp ); rShop->close_hour = fread_number( fp ); pMobIndex->rShop = rShop; break; } if( !str_cmp( word, "Resist" ) ) { const char *resist = fread_flagstring( fp ); while( resist[0] != '\0' ) { resist = one_argument( resist, flag ); value = get_risflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown RIS flag (R): %s", flag ); else SET_BIT( pMobIndex->resistant, 1 << value ); } break; } break; case 'S': if( !str_cmp( word, "Saves" ) ) { char *ln = fread_line( fp ); int x1, x2, x3, x4, x5; x1 = x2 = x3 = x4 = x5 = 0; sscanf( ln, "%d %d %d %d %d", &x1, &x2, &x3, &x4, &x5 ); pMobIndex->saving_poison_death = x1; pMobIndex->saving_wand = x2; pMobIndex->saving_para_petri = x3; pMobIndex->saving_breath = x4; pMobIndex->saving_spell_staff = x5; break; } KEY( "Short", pMobIndex->short_descr, fread_string( fp ) ); if( !str_cmp( word, "ShopData" ) ) { int iTrade; SHOP_DATA *pShop; CREATE( pShop, SHOP_DATA, 1 ); pShop->keeper = pMobIndex->vnum; for( iTrade = 0; iTrade < MAX_TRADE; ++iTrade ) pShop->buy_type[iTrade] = fread_number( fp ); pShop->profit_buy = fread_number( fp ); pShop->profit_sell = fread_number( fp ); pShop->profit_buy = URANGE( pShop->profit_sell + 5, pShop->profit_buy, 1000 ); pShop->profit_sell = URANGE( 0, pShop->profit_sell, pShop->profit_buy - 5 ); pShop->open_hour = fread_number( fp ); pShop->close_hour = fread_number( fp ); pMobIndex->pShop = pShop; break; } if( !str_cmp( word, "Speaks" ) ) { fread_flagstring( fp ); break; } if( !str_cmp( word, "Speaking" ) ) { fread_flagstring( fp ); break; } if( !str_cmp( word, "Specfun" ) ) { pMobIndex->spec_funname = fread_string( fp ); break; } if( !str_cmp( word, "Stats1" ) ) { char *ln = fread_line( fp ); int x1, x2, x3, x4, x5, x6; x1 = x2 = x3 = x4 = x5 = x6 = 0; sscanf( ln, "%d %d %d %d %d %d", &x1, &x2, &x3, &x4, &x5, &x6 ); pMobIndex->alignment = x1; pMobIndex->level = x2; pMobIndex->mobthac0 = x3; pMobIndex->ac = x4; pMobIndex->gold = x5; pMobIndex->exp = x6; break; } if( !str_cmp( word, "Stats2" ) ) { char *ln = fread_line( fp ); int x1, x2, x3; x1 = x2 = x3 = 0; sscanf( ln, "%d %d %d", &x1, &x2, &x3 ); pMobIndex->hitnodice = x1; pMobIndex->hitsizedice = x2; pMobIndex->hitplus = x3; break; } if( !str_cmp( word, "Stats3" ) ) { char *ln = fread_line( fp ); int x1, x2, x3; x1 = x2 = x3 = 0; sscanf( ln, "%d %d %d", &x1, &x2, &x3 ); pMobIndex->damnodice = x1; pMobIndex->damsizedice = x2; pMobIndex->damplus = x3; break; } if( !str_cmp( word, "Stats4" ) ) { char *ln = fread_line( fp ); int x1, x2, x3, x4, x5; x1 = x2 = x3 = x4 = x5 = 0; sscanf( ln, "%d %d %d %d %d", &x1, &x2, &x3, &x4, &x5 ); pMobIndex->height = x1; pMobIndex->weight = x2; pMobIndex->numattacks = x3; pMobIndex->hitroll = x4; pMobIndex->damroll = x5; break; } if( !str_cmp( word, "Suscept" ) ) { const char *suscep = fread_flagstring( fp ); while( suscep[0] != '\0' ) { suscep = one_argument( suscep, flag ); value = get_risflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown RIS flag (S): %s", flag ); else SET_BIT( pMobIndex->susceptible, 1 << value ); } break; } break; case 'V': if( !str_cmp( word, "Vnum" ) ) { int vnum = fread_number( fp ); if( get_mob_index( vnum ) ) { bug( "%s: vnum %d duplicated.", __FUNCTION__, vnum ); // Try to recover, read to end of duplicated mobile and then bail out for( ;; ) { word = feof( fp ) ? "#ENDMOBILE" : fread_word( fp ); if( !str_cmp( word, "#ENDMOBILE" ) ) return; } } else { CREATE( pMobIndex, MOB_INDEX_DATA, 1 ); oldmob = false; } pMobIndex->vnum = vnum; if( !tarea->low_m_vnum ) tarea->low_m_vnum = vnum; if( vnum > tarea->hi_m_vnum ) tarea->hi_m_vnum = vnum; break; } break; } } } void fread_fuss_areadata( FILE * fp, AREA_DATA * tarea ) { bool fMatch; // Unused, but needed to shut the compiler up about the KEY macro for( ;; ) { const char *word = ( feof( fp ) ? "#ENDAREADATA" : fread_word( fp ) ); if( word[0] == '\0' ) { log_printf( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "#ENDAREADATA"; } switch ( word[0] ) { default: log_printf( "%s: no match: %s", __FUNCTION__, word ); fread_to_eol( fp ); break; case '#': if( !str_cmp( word, "#ENDAREADATA" ) ) { tarea->age = tarea->reset_frequency; return; } break; case 'A': KEY( "Author", tarea->author, fread_string( fp ) ); break; case 'C': KEY( "Credits", tarea->credits, fread_string( fp ) ); break; case 'E': if( !str_cmp( word, "Economy" ) ) { tarea->high_economy = fread_number( fp ); tarea->low_economy = fread_number( fp ); break; } break; case 'F': if( !str_cmp( word, "Flags" ) ) { const char *areaflags = NULL; char flag[MAX_INPUT_LENGTH]; int value; areaflags = fread_flagstring( fp ); while( areaflags[0] != '\0' ) { areaflags = one_argument( areaflags, flag ); value = get_areaflag( flag ); if( value < 0 || value > 31 ) bug( "Unknown area flag: %s", flag ); else SET_BIT( tarea->flags, 1 << value ); } break; } break; case 'N': KEY( "Name", tarea->name, fread_string_nohash( fp ) ); break; case 'R': if( !str_cmp( word, "Ranges" ) ) { int x1, x2, x3, x4; char *ln; ln = fread_line( fp ); x1 = x2 = x3 = x4 = 0; sscanf( ln, "%d %d %d %d", &x1, &x2, &x3, &x4 ); tarea->low_soft_range = x1; tarea->hi_soft_range = x2; tarea->low_hard_range = x3; tarea->hi_hard_range = x4; break; } KEY( "ResetMsg", tarea->resetmsg, fread_string_nohash( fp ) ); KEY( "ResetFreq", tarea->reset_frequency, fread_number( fp ) ); break; case 'S': KEY( "Spelllimit", tarea->spelllimit, fread_number( fp ) ); break; case 'V': KEY( "Version", tarea->version, fread_number( fp ) ); break; case 'W': KEY( "WeatherX", tarea->weatherx, fread_number( fp ) ); KEY( "WeatherY", tarea->weathery, fread_number( fp ) ); break; } } } /* * Load an 'area' header line. */ AREA_DATA *create_area( void ) { AREA_DATA *pArea; CREATE( pArea, AREA_DATA, 1 ); pArea->first_room = pArea->last_room = NULL; pArea->name = NULL; pArea->author = NULL; pArea->credits = NULL; pArea->filename = str_dup( strArea ); pArea->age = 15; pArea->reset_frequency = 15; pArea->nplayer = 0; pArea->low_r_vnum = 0; pArea->low_o_vnum = 0; pArea->low_m_vnum = 0; pArea->hi_r_vnum = 0; pArea->hi_o_vnum = 0; pArea->hi_m_vnum = 0; pArea->low_soft_range = 0; pArea->hi_soft_range = MAX_LEVEL; pArea->low_hard_range = 0; pArea->hi_hard_range = MAX_LEVEL; pArea->spelllimit = 0; pArea->weatherx = 0; pArea->weathery = 0; pArea->version = 1; LINK( pArea, first_area, last_area, next, prev ); return pArea; } AREA_DATA *fread_fuss_area( AREA_DATA * tarea, FILE * fp ) { for( ;; ) { char letter; const char *word; letter = fread_letter( fp ); if( letter == '*' ) { fread_to_eol( fp ); continue; } if( letter != '#' ) { bug( "%s: # not found. Invalid format.", __FUNCTION__ ); exit( 1 ); break; } word = ( feof( fp ) ? "ENDAREA" : fread_word( fp ) ); if( word[0] == '\0' ) { bug( "%s: EOF encountered reading file!", __FUNCTION__ ); word = "ENDAREA"; } if( !str_cmp( word, "AREADATA" ) ) { if( !tarea ) tarea = create_area( ); fread_fuss_areadata( fp, tarea ); } else if( !str_cmp( word, "MOBILE" ) ) fread_fuss_mobile( fp, tarea ); else if( !str_cmp( word, "OBJECT" ) ) fread_fuss_object( fp, tarea ); else if( !str_cmp( word, "ROOM" ) ) fread_fuss_room( fp, tarea ); else if( !str_cmp( word, "ENDAREA" ) ) break; else { bug( "%s: Bad section header: %s", __FUNCTION__, word ); fread_to_eol( fp ); } } return tarea; } void load_helps( FILE * fp ) { char *help; for( ;; ) { fread_number( fp ); help = ( char * )fread_flagstring( fp ); if( help[0] == '$' ) break; fread_flagstring( fp ); } } void load_area_file( AREA_DATA * tarea, const char *filename ) { char *word, nfilename[MSL]; int aversion = 0; snprintf( nfilename, sizeof( nfilename ), "../area/%s", filename ); if( !( fpArea = fopen( nfilename, "r" ) ) ) { perror( nfilename ); bug( "%s: error loading file (can't open) %s", __FUNCTION__, nfilename ); return; } if( fread_letter( fpArea ) != '#' ) { bug( "%s: No # found at start of area file.", __FUNCTION__ ); exit( 1 ); } word = fread_word( fpArea ); // New FUSS area format support -- Samson 7/5/07 if( !str_cmp( word, "FUSSAREA" ) ) { tarea = fread_fuss_area( tarea, fpArea ); fclose( fpArea ); fpArea = NULL; if( tarea ) process_sorting( tarea ); return; } // Drop through to the old format processor if( !str_cmp( word, "AREA" ) ) { tarea = load_area( fpArea, 0 ); } // Only seen at this stage for help.are else if( !str_cmp( word, "HELPS" ) ) load_helps( fpArea ); // Only seen at this stage for SmaugWiz areas else if( !str_cmp( word, "VERSION" ) ) aversion = fread_number( fpArea ); for( ;; ) { if( fread_letter( fpArea ) != '#' ) { bug( "%s: # not found", __FUNCTION__ ); exit( 1 ); } word = fread_word( fpArea ); if( word[0] == '$' ) break; // Only seen at this stage for SmaugWiz areas. The format had better be right or there'll be trouble here! else if( !str_cmp( word, "AREA" ) ) tarea = load_area( fpArea, aversion ); else if( !str_cmp( word, "AUTHOR" ) ) load_author( tarea, fpArea ); else if( !str_cmp( word, "FLAGS" ) ) load_flags( tarea, fpArea ); else if( !str_cmp( word, "RANGES" ) ) load_ranges( tarea, fpArea ); else if( !str_cmp( word, "ECONOMY" ) ) load_economy( tarea, fpArea ); else if( !str_cmp( word, "RESETMSG" ) ) load_resetmsg( tarea, fpArea ); /* * Rennard */ else if( !str_cmp( word, "HELPS" ) ) load_helps( fpArea ); else if( !str_cmp( word, "MOBILES" ) ) load_mobiles( tarea, fpArea ); else if( !str_cmp( word, "OBJECTS" ) ) load_objects( tarea, fpArea ); else if( !str_cmp( word, "RESETS" ) ) load_resets( tarea, fpArea ); else if( !str_cmp( word, "ROOMS" ) ) load_rooms( tarea, fpArea ); else if( !str_cmp( word, "SHOPS" ) ) load_shops( fpArea ); else if( !str_cmp( word, "REPAIRS" ) ) load_repairs( fpArea ); else if( !str_cmp( word, "SPECIALS" ) ) load_specials( fpArea ); else if( !str_cmp( word, "CLIMATE" ) ) load_climate( tarea, fpArea ); else if( !str_cmp( word, "NEIGHBOR" ) ) load_neighbor( tarea, fpArea ); else if( !str_cmp( word, "VERSION" ) ) load_version( tarea, fpArea ); else if( !str_cmp( word, "SPELLLIMIT" ) ) { tarea->spelllimit = fread_number( fpArea ); } else { bug( "%s: bad section name: %s", __FUNCTION__, word ); exit( 1 ); } } fclose( fpArea ); fpArea = NULL; if( !tarea ) fprintf( stderr, "(%s)\n", filename ); } size_t mudstrlcpy( char *dst, const char *src, size_t siz ) { register char *d = dst; register const char *s = src; register size_t n = siz; if( !src ) { bug( "%s: NULL src string passed!", __FUNCTION__ ); return 0; } if( !dst ) { bug( "%s: NULL dst string being passed!", __FUNCTION__ ); return 0; } /* * Copy as many bytes as will fit */ if( n != 0 && --n != 0 ) { do { if( ( *d++ = *s++ ) == 0 ) break; } while( --n != 0 ); } /* * Not enough room in dst, add NUL and traverse rest of src */ if( n == 0 ) { if( siz != 0 ) *d = '\0'; /* NUL-terminate dst */ while( *s++ ) ; } return ( s - src - 1 ); /* count does not include NUL */ } size_t mudstrlcat( char *dst, const char *src, size_t siz ) { register char *d = dst; register const char *s = src; register size_t n = siz; size_t dlen; if( !src ) { bug( "%s: NULL src string passed!", __FUNCTION__ ); return 0; } /* * Find the end of dst and adjust bytes left but don't go past end */ while( n-- != 0 && *d != '\0' ) d++; dlen = d - dst; n = siz - dlen; if( n == 0 ) return ( dlen + strlen( s ) ); while( *s != '\0' ) { if( n != 1 ) { *d++ = *s; n--; } s++; } *d = '\0'; return ( dlen + ( s - src ) ); /* count does not include NUL */ } time_t current_time; /* Time of this pulse */ #ifdef WIN32 int mainthread( int argc, char **argv ) #else int main( int argc, char **argv ) #endif { struct timeval now_time; gettimeofday( &now_time, NULL ); current_time = ( time_t ) now_time.tv_sec; log_string( "Booting Database" ); boot_db( ); exit( 0 ); }