/*************************************************************************** * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. * * * * Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * * * Ack 2.2 improvements copyright (C) 1994 by Stephen Dooley * * * * In order to use any part of this Merc Diku Mud, you must comply with * * both the original Diku license in 'license.doc' as well the Merc * * license in 'license.txt'. In particular, you may not remove either of * * these copyright notices. * * * * _/ _/_/_/ _/ _/ _/ ACK! MUD is modified * * _/_/ _/ _/ _/ _/ Merc2.0/2.1/2.2 code * * _/ _/ _/ _/_/ _/ (c)Stephen Zepp 1998 * * _/_/_/_/ _/ _/ _/ Version #: 4.3.1 * * _/ _/ _/_/_/ _/ _/ _/ * * * * http://ackmud.nuc.net/ * * zenithar@ackmud.nuc.net * * Much time and thought has gone into this software and you are * * benefitting. We hope that you share your changes too. What goes * * around, comes around. * ***************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <assert.h> #include <stdarg.h> #include "globals.h" #include "hash.h" #include "ssm.h" #include <unistd.h> /* for execl */ #include <sys/wait.h> #include <errno.h> #include <signal.h> #ifndef DEC_MONEY_H #include "money.h" #endif #ifndef DEC_ACT_MOB_H #include "act_mob.h" #endif #if !defined(macintosh) extern int _filbuf args( ( FILE * ) ); #endif /* * Globals. */ char bug_buf[2 * MAX_INPUT_LENGTH]; char log_buf[2 * MAX_INPUT_LENGTH]; char testerbuf[MSL]; KILL_DATA kill_table[MAX_LEVEL]; TIME_INFO_DATA time_info; WEATHER_DATA weather_info; SYS_DATA_TYPE sysdata; bool booting_up; bool area_resetting_global; bool mem_log; sh_int gsn_martial_arts; sh_int gsn_stake; sh_int gsn_dualwield; sh_int gsn_stun; sh_int gsn_feed; sh_int gsn_knee; sh_int gsn_shadow; sh_int gsn_appraise; sh_int gsn_climb; sh_int gsn_find_doors; sh_int gsn_bash; sh_int gsn_smash; sh_int gsn_notrip; sh_int gsn_nodisarm; sh_int gsn_trip; sh_int gsn_dirt; sh_int gsn_fourth_attack; sh_int gsn_shield_block; sh_int gsn_beserk; sh_int gsn_circle; sh_int gsn_backstab; sh_int gsn_dodge; sh_int gsn_hide; sh_int gsn_hunt; sh_int gsn_peek; sh_int gsn_pick_lock; sh_int gsn_sneak; sh_int gsn_steal; sh_int gsn_punch; sh_int gsn_headbutt; sh_int gsn_disarm; sh_int gsn_enhanced_damage; sh_int gsn_kick; sh_int gsn_parry; sh_int gsn_rescue; sh_int gsn_second_attack; sh_int gsn_third_attack; sh_int gsn_blindness; sh_int gsn_charm_person; sh_int gsn_curse; sh_int gsn_invis; sh_int gsn_mass_invis; sh_int gsn_poison; sh_int gsn_sleep; sh_int gsn_disguise; sh_int gsn_instruct; sh_int gsn_adrenaline; sh_int gsn_frenzy; sh_int gsn_emotion_control; sh_int gsn_fifth_attack; sh_int gsn_sixth_attack; sh_int gsn_target; sh_int gsn_charge; sh_int gsn_unit_tactics; sh_int gsn_imprint; sh_int gsn_scent; sh_int gsn_mount; sh_int gsn_scout; sh_int gsn_decapitate; sh_int gsn_potency; sh_int gsn_thaumatergy; #ifdef TFS sh_int gsn_mana_sense; #endif extern bool auto_quest; extern COUNCIL_DATA super_councils[MAX_SUPER]; const int convert_wearflags[] = { BIT_24, BIT_14, BIT_8, BIT_19, BIT_4, BIT_21, BIT_22, BIT_13, BIT_11, BIT_16, BIT_17, BIT_18, BIT_12, BIT_16, BIT_16, BIT_5, BIT_7, BIT_16, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24, BIT_24 }; /* * Locals. */ 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]; char *string_hash[MAX_KEY_HASH]; AREA_DATA *area_used[MAX_AREAS]; AREA_DATA *area_load; /* * replaced for SSM */ #if 0 char *string_space = NULL; char *top_string = NULL; char str_empty[1] = { 0 }; #endif extern char str_empty[1]; extern long sOverFlowString; extern long nOverFlowString; extern bool Full; int top_affect; int top_area; int top_ed; int top_exit; int top_help; int top_mob_index; int top_obj_index; int top_reset; int top_room; int top_shop; /* * MOBprogram locals */ int mprog_name_to_type args( ( char *name ) ); void mprog_file_read args( ( char *f, MOB_INDEX_DATA * pMobIndex ) ); void load_mobprogs args( ( FILE * fp ) ); void mprog_read_programs args( ( FILE * fp, MOB_INDEX_DATA * pMobIndex ) ); /* * Memory management. * Increase MAX_STRING if you have too. * Tune the others only if you understand what you're doing. */ #if 0 #define MAX_STRING 2097152 /*#define MAX_PERM_BLOCK 131072 #define MAX_MEM_LIST 12 void * rgFreeList [MAX_MEM_LIST]; const int rgSizeList [MAX_MEM_LIST] = { 16, 32, 64, 128, 256, 1024, 2048, 4096, 8192, 16384, 32768-64, 65536-16 };*/ int nAllocString; int sAllocString; #endif extern long nAllocString; extern long sAllocString; int nAllocPerm; int sAllocPerm; extern long MAX_STRING; void init_string_space( void ); void boot_done( void ); /* * Semi-locals. */ bool fBootDb; FILE *fpArea; char strArea[MAX_INPUT_LENGTH]; int area_revision = -1; /* * Local booting procedures. */ void init_mm args( ( void ) ); void load_area args( ( FILE * fp ) ); void load_helps args( ( FILE * fp ) ); void load_mobiles args( ( FILE * fp ) ); void load_objects args( ( FILE * fp ) ); void load_resets args( ( FILE * fp ) ); void load_rooms args( ( FILE * fp ) ); void load_shops args( ( FILE * fp ) ); void load_specials args( ( FILE * fp ) ); void load_objfuns args( ( FILE * fp ) ); void load_notes args( ( void ) ); void load_gold args( ( void ) ); void load_corpses args( ( void ) ); void load_marks args( ( void ) ); void load_bans args( ( void ) ); void load_brands args( ( void ) ); void fix_exits args( ( void ) ); void check_resets args( ( void ) ); void reset_area args( ( AREA_DATA * pArea ) ); #define SHOW_AREA \ if (!previous_bug) \ { \ bug (" In %s.",(int) pArea->filename); \ previous_bug=1; \ } /* * Big mama top level function. */ void boot_db( void ) { int a; /* * Init some data space stuff. */ #if 0 { if( ( string_space = calloc( 1, MAX_STRING ) ) == NULL ) { bug( "Boot_db: can't alloc %d string space.", MAX_STRING ); exit( 1 ); } top_string = string_space; fBootDb = TRUE; } #endif init_string_space( ); fBootDb = TRUE; send_to_descrips( "Initialising Ack! Mud. Please Wait....\n\r" ); /* * Init random number generator. */ { init_mm( ); } /* * Set time and weather. */ { long lhour, lday, lmonth; lhour = ( current_time - 650336715 ) / ( PULSE_TICK / PULSE_PER_SECOND ); time_info.hour = lhour % 24; lday = lhour / 24; time_info.day = lday % 35; lmonth = lday / 35; time_info.month = lmonth % 17; time_info.year = lmonth / 17; time_info.moon = 0; weather_info.moon_loc = MOON_DOWN; weather_info.moon_phase = number_range( MOON_NEW, MOON_FULL ); if( time_info.hour < 5 ) weather_info.sunlight = SUN_DARK; else if( time_info.hour < 6 ) weather_info.sunlight = SUN_RISE; else if( time_info.hour < 19 ) weather_info.sunlight = SUN_LIGHT; else if( time_info.hour < 20 ) weather_info.sunlight = SUN_SET; else weather_info.sunlight = SUN_DARK; weather_info.change = 0; weather_info.mmhg = 960; if( time_info.month >= 7 && time_info.month <= 12 ) weather_info.mmhg += number_range( 1, 50 ); else weather_info.mmhg += number_range( 1, 80 ); if( weather_info.mmhg <= 980 ) weather_info.sky = SKY_LIGHTNING; else if( weather_info.mmhg <= 1000 ) weather_info.sky = SKY_RAINING; else if( weather_info.mmhg <= 1020 ) weather_info.sky = SKY_CLOUDY; else weather_info.sky = SKY_CLOUDLESS; } /* * Initialize Supernatural Councils */ { sh_int index; char buf[MAX_STRING_LENGTH]; log_f( "Initializing Supernatural Councils" ); for( index = SUPER_NONE; index < MAX_SUPER; index++ ) { super_councils[index].first_member = NULL; super_councils[index].last_member = NULL; super_councils[index].quorum = FALSE; super_councils[index].council_time = 0; switch ( index ) { case SUPER_NONE: sprintf( buf, "%s", "ORDINARIES" ); break; case SUPER_VAMP: sprintf( buf, "%s", "@@rJUSTICARS@@N" ); break; default: sprintf( buf, "%s", "NONE" ); break; } super_councils[index].council_name = str_dup( buf ); } } /* * Assign gsn's for skills which have them. */ { int sn; for( sn = 0; sn < MAX_SKILL; sn++ ) { if( skill_table[sn].pgsn != 0 ) *skill_table[sn].pgsn = sn; } } /* * Clear list of used areas */ for( a = 0; a < MAX_AREAS; a++ ) { area_used[a] = NULL; } /* * Read in clan data table */ { extern POL_DATA politics_data; FILE *clanfp; char clan_file_name[MAX_STRING_LENGTH]; sh_int x, y; char buf[MAX_STRING_LENGTH]; log_f( "Loading in Clan diplomacy info." ); sprintf( clan_file_name, "%s", CLAN_FILE ); sprintf( buf, "Loading %s\n\r", clan_file_name ); monitor_chan( buf, MONITOR_CLAN ); if( ( clanfp = fopen( clan_file_name, "r" ) ) == NULL ) { log_f( "failed open of clan_table.dat in load_clan_table" ); } else { fpArea = clanfp; sprintf( strArea, "%s", clan_file_name ); for( x = 1; x < MAX_CLAN; x++ ) { for( y = 1; y < MAX_CLAN; y++ ) { politics_data.diplomacy[x][y] = fread_number( clanfp ); } } for( x = 1; x < MAX_CLAN; x++ ) { politics_data.treasury[x] = fread_number( clanfp ); } for( x = 1; x < MAX_CLAN; x++ ) { for( y = 1; y < MAX_CLAN; y++ ) { politics_data.end_current_state[x][y] = fread_number( clanfp ); } } fclose( clanfp ); } fpArea = NULL; sprintf( buf, "Done Loading %s", clan_file_name ); log_f( buf ); } /* * Read in all the socials. */ { load_social_table( ); } /* * Read in all the area files. */ { FILE *fpList; log_f( "Reading Area Files..." ); if( ( fpList = fopen( AREA_LIST, "r" ) ) == NULL ) { perror( AREA_LIST ); log_f( "Unable to open area.lst, aborting bootup." ); kill( getpid( ), SIGQUIT ); } for( ;; ) { strcpy( strArea, fread_word( fpList ) ); if( strArea[0] == '$' ) break; if( strArea[0] == '-' ) { fpArea = stdin; } else { if( ( fpArea = fopen( strArea, "r" ) ) == NULL ) { log_string( strArea ); kill( getpid( ), SIGQUIT ); } } for( ;; ) { char *word; if( fread_letter( fpArea ) != '#' ) { bug( "Boot_db: # not found.", 0 ); kill( getpid( ), SIGQUIT ); } word = fread_word( fpArea ); if( word[0] == '$' ) break; else if( !str_cmp( word, "AREA" ) ) load_area( fpArea ); else if( !str_cmp( word, "HELPS" ) ) load_helps( fpArea ); else if( !str_cmp( word, "MOBILES" ) ) load_mobiles( fpArea ); else if( !str_cmp( word, "MOBPROGS" ) ) load_mobprogs( fpArea ); else if( !str_cmp( word, "OBJECTS" ) ) load_objects( fpArea ); else if( !str_cmp( word, "RESETS" ) ) load_resets( fpArea ); else if( !str_cmp( word, "ROOMS" ) ) load_rooms( fpArea ); else if( !str_cmp( word, "SHOPS" ) ) load_shops( fpArea ); else if( !str_cmp( word, "SPECIALS" ) ) load_specials( fpArea ); else if( !str_cmp( word, "OBJFUNS" ) ) load_objfuns( fpArea ); else { bug( "Boot_db: bad section name.", 0 ); exit( 1 ); } } if( fpArea != stdin ) fclose( fpArea ); fpArea = NULL; } fclose( fpList ); } /* * Fix up exits. * MAG Mod: Check resets. (Allows loading objects of later areas.) * MAG Mod: Load gold for areas. * Declare db booting over. * Reset all areas once. * Load up the notes file. * Set the MOBtrigger. */ { log_f( "Fixing Exits......" ); fix_exits( ); log_f( "Done.\n\r" ); fBootDb = FALSE; log_f( "Checking Resets..." ); check_resets( ); log_f( "Done." ); /* load_gold(); */ log_f( "Updating Areas...." ); area_update( ); log_f( "Loading notes" ); load_notes( ); MOBtrigger = TRUE; log_f( "Loading corpses." ); load_corpses( ); booting_up = TRUE; log_f( "Loading room marks." ); load_marks( ); booting_up = FALSE; save_marks( ); log_f( "Loading banned sites." ); load_bans( ); log_f( "Loading ruler data." ); load_rulers( ); log_f( "Loading imm brands." ); load_brands( ); log_f( "Loading System Data." ); load_sysdata( ); } auto_quest = TRUE; return; } /* * Snarf an 'area' header line. */ void load_area( FILE * fp ) { AREA_DATA *pArea; char letter; int a; GET_FREE( pArea, area_free ); pArea->first_reset = NULL; pArea->last_reset = NULL; pArea->name = fread_string( fp ); pArea->age = 15; pArea->reset_rate = 15; pArea->nplayer = 0; pArea->offset = 0; /* MAG Mod */ pArea->modified = 0; pArea->min_vnum = 0; pArea->max_vnum = MAX_VNUM; pArea->area_num = 0; pArea->filename = str_dup( strArea ); pArea->owner = str_empty; pArea->can_read = str_dup( "all" ); pArea->can_write = str_dup( "all" ); pArea->level_label = str_dup( "{?? ??}" ); pArea->keyword = str_dup( "none" ); pArea->reset_msg = str_dup( "You hear the screams of the Dead within your head." ); pArea->min_level = 0; pArea->max_level = 0; pArea->gold = 0; pArea->flags = 0; pArea->first_area_room = NULL; pArea->last_area_room = NULL; pArea->first_area_help_text = NULL; pArea->last_area_help_text = NULL; pArea->first_area_object = NULL; pArea->last_area_object = NULL; pArea->first_area_mobile = NULL; pArea->last_area_mobile = NULL; pArea->first_area_shop = NULL; pArea->last_area_shop = NULL; pArea->first_area_specfunc = NULL; pArea->last_area_specfunc = NULL; pArea->first_area_mobprog = NULL; area_revision = -1; /* MAG Mod for optionals additions to area headers. */ for( ;; ) { letter = fread_letter( fp ); if( letter == '#' ) { ungetc( letter, fp ); break; } switch ( letter ) { case 'F': pArea->reset_rate = fread_number( fp ); break; case 'O': pArea->owner = fread_string( fp ); break; case 'Q': area_revision = fread_number( fp ); break; case 'U': free_string( pArea->reset_msg ); pArea->reset_msg = fread_string( fp ); break; case 'R': free_string( pArea->can_read ); pArea->can_read = fread_string( fp ); break; case 'W': free_string( pArea->can_write ); pArea->can_write = fread_string( fp ); break; case 'P': SET_BIT( pArea->flags, AREA_PAYAREA ); fread_to_eol( fp ); break; case 'M': SET_BIT( pArea->flags, AREA_NO_ROOM_AFF ); fread_to_eol( fp ); break; case 'X': pArea->offset = fread_number( fp ); break; case 'V': pArea->min_vnum = fread_number( fp ); pArea->max_vnum = fread_number( fp ); break; case 'N': pArea->area_num = fread_number( fp ); break; case 'T': SET_BIT( pArea->flags, AREA_TELEPORT ); fread_to_eol( fp ); break; case 'B': SET_BIT( pArea->flags, AREA_BUILDING ); fread_to_eol( fp ); break; case 'S': SET_BIT( pArea->flags, AREA_NOSHOW ); fread_to_eol( fp ); break; case 'K': free_string( pArea->keyword ); pArea->keyword = fread_string( fp ); break; case 'L': free_string( pArea->level_label ); pArea->level_label = fread_string( fp ); break; case 'I': pArea->min_level = fread_number( fp ); pArea->max_level = fread_number( fp ); break; } } if( pArea->area_num == 0 ) { /* * Find a unique area number */ for( a = 0; a < MAX_AREAS; a++ ) if( area_used[a] == NULL ) break; pArea->area_num = a; } area_used[pArea->area_num] = pArea; area_load = pArea; LINK( pArea, first_area, last_area, next, prev ); top_area++; return; } /* * Snarf a help section. */ void load_helps( FILE * fp ) { HELP_DATA *pHelp; BUILD_DATA_LIST *pList; for( ;; ) { GET_FREE( pHelp, help_free ); pHelp->level = fread_number( fp ); pHelp->keyword = fread_string( fp ); if( pHelp->keyword[0] == '$' ) break; pHelp->text = fread_string( fp ); /* * greeting text handled in comm.c now -S- */ LINK( pHelp, first_help, last_help, next, prev ); /* MAG Mod */ GET_FREE( pList, build_free ); pList->data = pHelp; LINK( pList, area_load->first_area_help_text, area_load->last_area_help_text, next, prev ); top_help++; } return; } void load_corpses( void ) { FILE *corpsefp; char corpse_file_name[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; sprintf( corpse_file_name, "%s", CORPSE_FILE ); sprintf( buf, "Loading %s\n\r", corpse_file_name ); log_f( buf ); if( ( corpsefp = fopen( corpse_file_name, "r" ) ) == NULL ) { log_f( "Load corpse Table: fopen" ); perror( "failed open of corpse_table.dat in load_corpse_table" ); } else { fpArea = corpsefp; sprintf( strArea, "%s", corpse_file_name ); for( ;; ) { char letter; char *word; letter = fread_letter( corpsefp ); if( letter == '*' ) { fread_to_eol( corpsefp ); continue; } if( letter != '#' ) { log_f( "Load_char_obj: # not found." ); break; } word = fread_word( corpsefp ); if( !str_cmp( word, "OBJECT" ) ) fread_corpse( corpsefp ); else if( !str_cmp( word, "END" ) ) break; else { log_f( "Load_char_obj: bad section." ); break; } } } fclose( corpsefp ); fpArea = NULL; sprintf( buf, "Done Loading %s", corpse_file_name ); monitor_chan( buf, MONITOR_CLAN ); } /* * Load marked rooms * */ void load_marks( void ) { FILE *marksfp; char marks_file_name[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; sprintf( marks_file_name, "%s", MARKS_FILE ); sprintf( buf, "Loading %s\n\r", marks_file_name ); log_f( buf ); if( ( marksfp = fopen( marks_file_name, "r" ) ) == NULL ) { log_f( "Load marks Table: fopen" ); perror( "failed open of marks_table.dat in load_marks_table" ); } else { fpArea = marksfp; sprintf( strArea, "%s", marks_file_name ); for( ;; ) { char *word; int rvnum = 0; MARK_DATA *mark; word = fread_string( marksfp ); if( !str_cmp( word, "#MARK" ) ) { GET_FREE( mark, mark_free ); rvnum = fread_number( marksfp ); mark->message = fread_string( marksfp ); mark->author = fread_string( marksfp ); mark->duration = fread_number( marksfp ); mark->type = fread_number( marksfp ); mark_to_room( rvnum, mark ); free_string( word ); } else if( !str_cmp( word, "#END" ) ) { free_string( word ); break; } else { free_string( word ); log_f( "Load_marks: bad section." ); break; } } fclose( marksfp ); fpArea = NULL; sprintf( buf, "Done Loading %s", marks_file_name ); monitor_chan( buf, MONITOR_CLAN ); } } void load_bans( void ) { FILE *bansfp; char bans_file_name[MAX_STRING_LENGTH]; char buf[MAX_STRING_LENGTH]; sprintf( bans_file_name, "%s", BANS_FILE ); sprintf( buf, "Loading %s\n\r", bans_file_name ); log_f( buf ); if( ( bansfp = fopen( bans_file_name, "r" ) ) == NULL ) { log_f( "Load bans Table: fopen" ); perror( "failed open of bans_table.dat in load_bans_table" ); } else { fpArea = bansfp; sprintf( strArea, "%s", bans_file_name ); for( ;; ) { char *word; BAN_DATA *pban; word = fread_string( bansfp ); if( !str_cmp( word, "#BAN" ) ) { sh_int get_bool = FALSE; GET_FREE( pban, ban_free ); get_bool = fread_number( bansfp ); if( get_bool == 1 ) pban->newbie = TRUE; else pban->newbie = FALSE; pban->name = fread_string( bansfp ); pban->banned_by = fread_string( bansfp ); LINK( pban, first_ban, last_ban, next, prev ); free_string( word ); } else if( !str_cmp( word, "#END" ) ) { free_string( word ); break; } else { free_string( word ); log_f( "Load_bans: bad section." ); break; } } fclose( bansfp ); fpArea = NULL; sprintf( buf, "Done Loading %s", bans_file_name ); log_f( buf ); } } /* * Snarf a mob section. */ void load_mobiles( FILE * fp ) { MOB_INDEX_DATA *pMobIndex; BUILD_DATA_LIST *pList; for( ;; ) { sh_int vnum; char letter; int iHash; letter = fread_letter( fp ); if( letter != '#' ) { bug( "Load_mobiles: # not found.", 0 ); hang( "Loading Mobiles in db.c" ); } vnum = fread_number( fp ); if( vnum == 0 ) break; fBootDb = FALSE; if( get_mob_index( vnum ) != NULL ) { bug( "Load_mobiles: vnum %d duplicated.", vnum ); hang( "Loading Mobiles in db.c" ); } fBootDb = TRUE; GET_FREE( pMobIndex, mid_free ); pMobIndex->vnum = vnum; pMobIndex->area = area_load; pMobIndex->player_name = fread_string( fp ); pMobIndex->short_descr = fread_string( fp ); pMobIndex->long_descr = fread_string( fp ); pMobIndex->description = fread_string( fp ); pMobIndex->long_descr[0] = UPPER( pMobIndex->long_descr[0] ); pMobIndex->description[0] = UPPER( pMobIndex->description[0] ); pMobIndex->act = fread_number( fp ) | ACT_IS_NPC; pMobIndex->affected_by = fread_number( fp ); pMobIndex->pShop = NULL; pMobIndex->alignment = fread_number( fp ); letter = fread_letter( fp ); pMobIndex->level = number_fuzzy( fread_number( fp ) ); pMobIndex->sex = fread_number( fp ); pMobIndex->ac_mod = fread_number( fp ); /* read */ pMobIndex->hr_mod = fread_number( fp ); /* in the */ pMobIndex->dr_mod = fread_number( fp ); /* modifiers */ if( letter != 'S' ) { bug( "Load_mobiles: vnum %d non-S.", vnum ); hang( "Loading Mobiles in db.c" ); } /* * The "new" additions to mobs start with a ! */ letter = fread_letter( fp ); if( letter == '!' ) { pMobIndex->class = fread_number( fp ); pMobIndex->clan = fread_number( fp ); pMobIndex->race = fread_number( fp ); pMobIndex->position = POS_STANDING; fread_number( fp ); /* position */ pMobIndex->skills = fread_number( fp ); pMobIndex->cast = fread_number( fp ); pMobIndex->def = fread_number( fp ); if( ( area_revision < 16 ) || ( pMobIndex->race < 0 ) ) { #ifdef AA pMobIndex->race = 14; #else pMobIndex->race = 0; #endif } else; } else ungetc( letter, fp ); letter = fread_letter( fp ); if( letter == '|' ) { pMobIndex->strong_magic = fread_number( fp ); pMobIndex->weak_magic = fread_number( fp ); pMobIndex->race_mods = fread_number( fp ); pMobIndex->power_skills = fread_number( fp ); pMobIndex->power_cast = fread_number( fp ); pMobIndex->resist = fread_number( fp ); pMobIndex->suscept = fread_number( fp ); } else ungetc( letter, fp ); letter = fread_letter( fp ); if( letter == '>' ) { ungetc( letter, fp ); mprog_read_programs( fp, pMobIndex ); } else ungetc( letter, fp ); iHash = vnum % MAX_KEY_HASH; SING_TOPLINK( pMobIndex, mob_index_hash[iHash], next ); /* MAG Mod */ GET_FREE( pList, build_free ); pList->data = pMobIndex; LINK( pList, area_load->first_area_mobile, area_load->last_area_mobile, next, prev ); top_mob_index++; kill_table[URANGE( 0, pMobIndex->level, MAX_LEVEL - 1 )].number++; } return; } /* * Snarf an obj section. */ void load_objects( FILE * fp ) { OBJ_INDEX_DATA *pObjIndex; BUILD_DATA_LIST *pList; sh_int looper; for( ;; ) { sh_int vnum; char letter; int iHash; letter = fread_letter( fp ); if( letter != '#' ) { bug( "Load_objects: # not found.", 0 ); hang( "Loading Objects in db.c" ); } vnum = fread_number( fp ); if( vnum == 0 ) break; fBootDb = FALSE; if( get_obj_index( vnum ) != NULL ) { bug( "Load_objects: vnum %d duplicated.", vnum ); hang( "Loading Objects in db.c" ); } fBootDb = TRUE; GET_FREE( pObjIndex, oid_free ); pObjIndex->vnum = vnum; pObjIndex->area = area_load; pObjIndex->name = fread_string( fp ); pObjIndex->short_descr = fread_string( fp ); pObjIndex->description = fread_string( fp ); pObjIndex->short_descr[0] = LOWER( pObjIndex->short_descr[0] ); pObjIndex->description[0] = UPPER( pObjIndex->description[0] ); pObjIndex->item_type = fread_number( fp ); pObjIndex->extra_flags = fread_number( fp ); if( area_revision < 15 ) { int temp_flags, index, new_flags = 0; temp_flags = fread_number( fp ); for( index = 0; index < 32; index++ ) { if( IS_SET( temp_flags, ( 1 << index ) ) ) { SET_BIT( new_flags, convert_wearflags[index] ); } pObjIndex->wear_flags = new_flags; } } else { pObjIndex->wear_flags = fread_number( fp ); } pObjIndex->item_apply = fread_number( fp ); pObjIndex->value[0] = fread_number( fp ); pObjIndex->value[1] = fread_number( fp ); pObjIndex->value[2] = fread_number( fp ); pObjIndex->value[3] = fread_number( fp ); if( area_revision < 15 ) { for( looper = 4; looper < 10; pObjIndex->value[looper] = 0, looper++ ); } else { for( looper = 4; looper < 10; pObjIndex->value[looper] = fread_number( fp ), looper++ ); } pObjIndex->weight = fread_number( fp ); pObjIndex->cost = 0; if( pObjIndex->item_type == ITEM_POTION ) SET_BIT( pObjIndex->extra_flags, ITEM_NODROP ); for( ;; ) { char letter; letter = fread_letter( fp ); if( letter == 'A' ) { AFFECT_DATA *paf; GET_FREE( paf, affect_free ); paf->type = -1; paf->duration = -1; paf->location = fread_number( fp ); paf->modifier = fread_number( fp ); paf->bitvector = 0; paf->caster = NULL; LINK( paf, pObjIndex->first_apply, pObjIndex->last_apply, next, prev ); top_affect++; } else if( letter == 'E' ) { EXTRA_DESCR_DATA *ed; GET_FREE( ed, exdesc_free ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); LINK( ed, pObjIndex->first_exdesc, pObjIndex->last_exdesc, next, prev ); top_ed++; } else if( letter == 'L' ) { pObjIndex->level = fread_number( fp ); } else { ungetc( letter, fp ); break; } } /* * Translate spell "slot numbers" to internal "skill numbers." */ 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; } iHash = vnum % MAX_KEY_HASH; SING_TOPLINK( pObjIndex, obj_index_hash[iHash], next ); /* MAG Mod */ GET_FREE( pList, build_free ); pList->data = pObjIndex; LINK( pList, area_load->first_area_object, area_load->last_area_object, next, prev ); top_obj_index++; } return; } /* * Snarf a reset section. */ /* Spec: it isn't obvious how this works, so I'll add a comment here. * * load_resets only allows resets that are placed in current rooms - this is * the reset_ok code here. It does _not_ check the validity of room and object * vnums. It handles linking the resets into the appropriate room-reset-list * for OLC. * * check_resets is called after all areas are loaded. It checks that all * resets point to valid mobs and object and spits errors as necessary. It * does _not_ touch the room lists any more! */ void load_resets( FILE * fp ) { RESET_DATA *pReset = NULL; BUILD_DATA_LIST *pList = NULL; ROOM_INDEX_DATA *last_mob_room; ROOM_INDEX_DATA *last_obj_room; last_mob_room = NULL; last_obj_room = NULL; if( area_load == NULL ) { bug( "Load_resets: no #AREA seen yet.", 0 ); hang( "Loading Resets in db.c" ); } for( ;; ) { ROOM_INDEX_DATA *pRoomIndex; /* * EXIT_DATA *pexit; unused? */ char letter; /* * Temp values to hold reset, while we see if valid */ char Tcommand; int Tifflag; int Targ1; int Targ2; int Targ3; bool reset_ok; reset_ok = FALSE; if( ( letter = fread_letter( fp ) ) == 'S' ) break; if( letter == '*' ) { fread_to_eol( fp ); continue; } Tcommand = letter; /* * MAG Mod */ Tifflag = fread_number( fp ); /* Not used */ Targ1 = fread_number( fp ); Targ2 = fread_number( fp ); Targ3 = ( letter == 'G' || letter == 'R' ) ? 0 : fread_number( fp ); pRoomIndex = NULL; /* Set it to check for room numbers */ /* * Validate parameters. * We're calling the index functions for the side effect. */ switch ( letter ) { default: bug( "Load_resets: bad command '%c'.", letter ); reset_ok = FALSE; break; case 'A': reset_ok = FALSE; break; /* obsolete reset, discard */ case 'M': if( ( pRoomIndex = get_room_index( Targ3 ) ) != NULL ) { reset_ok = TRUE; last_mob_room = pRoomIndex; } break; case 'O': if( ( pRoomIndex = get_room_index( Targ3 ) ) != NULL ) { reset_ok = TRUE; last_obj_room = pRoomIndex; } break; case 'P': /* apparently these resets are no longer in use */ /* * if ( last_obj_room ) * { * pRoomIndex = last_obj_room; * reset_ok = TRUE; * } */ break; case 'G': case 'E': if( last_mob_room ) { pRoomIndex = last_mob_room; reset_ok = TRUE; } break; case 'D': if( ( pRoomIndex = get_room_index( Targ1 ) ) != NULL ) { reset_ok = TRUE; } break; case 'R': if( ( pRoomIndex = get_room_index( Targ1 ) ) != NULL ) { reset_ok = TRUE; } break; } if( reset_ok ) /* i.e. only add if reset is valid. */ { GET_FREE( pReset, reset_free ); pReset->command = Tcommand; pReset->arg1 = Targ1; pReset->arg2 = Targ2; pReset->arg3 = Targ3; pReset->notes = fsave_to_eol( fp ); LINK( pReset, area_load->first_reset, area_load->last_reset, next, prev ); top_reset++; GET_FREE( pList, build_free ); pList->data = pReset; LINK( pList, pRoomIndex->first_room_reset, pRoomIndex->last_room_reset, next, prev ); } } return; } /* * Snarf a room section. */ void load_rooms( FILE * fp ) { ROOM_INDEX_DATA *pRoomIndex; BUILD_DATA_LIST *pList; MONEY_TYPE *room_treasure; sh_int cnt; if( area_load == NULL ) { bug( "Load_rooms: no #AREA seen yet.", 0 ); hang( "Loading Rooms in db.c" ); } for( ;; ) { sh_int vnum; char letter; int door; int iHash; letter = fread_letter( fp ); if( letter != '#' ) { bug( "Load_rooms: # not found.", 0 ); hang( "Loading Rooms in db.c" ); } vnum = fread_number( fp ); if( vnum == 0 ) break; fBootDb = FALSE; if( get_room_index( vnum ) != NULL ) { bug( "Load_rooms: vnum %d duplicated.", vnum ); hang( "Loading Rooms in db.c" ); } fBootDb = TRUE; GET_FREE( pRoomIndex, rid_free ); pRoomIndex->first_person = NULL; pRoomIndex->last_person = NULL; pRoomIndex->first_content = NULL; pRoomIndex->last_content = NULL; pRoomIndex->first_exdesc = NULL; pRoomIndex->last_exdesc = NULL; pRoomIndex->area = area_load; pRoomIndex->vnum = vnum; pRoomIndex->name = fread_string( fp ); pRoomIndex->description = fread_string( fp ); pRoomIndex->room_flags = fread_number( fp ); pRoomIndex->sector_type = fread_number( fp ); if( pRoomIndex->sector_type == SECT_NULL ) pRoomIndex->sector_type = SECT_INSIDE; pRoomIndex->light = 0; pRoomIndex->affected_by = ROOM_BV_NONE; pRoomIndex->first_room_affect = NULL; pRoomIndex->last_room_affect = NULL; for( door = 0; door <= 5; door++ ) pRoomIndex->exit[door] = NULL; pRoomIndex->first_room_reset = NULL; /* MAG Mod */ pRoomIndex->last_room_reset = NULL; GET_FREE( room_treasure, money_type_free ); #ifdef DEBUG_MONEY { char testbuf[MSL]; sprintf( testbuf, "loading rooms, vnum is %d", pRoomIndex->vnum ); room_treasure->money_key = str_dup( testbuf ); } #endif for( cnt = 0; cnt < MAX_CURRENCY; cnt++ ) room_treasure->cash_unit[cnt] = 0; pRoomIndex->treasure = room_treasure; 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 > 5 ) { bug( "Fread_rooms: vnum %d has bad door number.", vnum ); hang( "Loading Rooms in db.c" ); } GET_FREE( pexit, exit_free ); pexit->description = fread_string( fp ); pexit->keyword = fread_string( fp ); pexit->exit_info = 0; locks = fread_number( fp ); pexit->key = fread_number( fp ); pexit->vnum = fread_number( fp ); /* * -S- Mod: exit_flags now saved as-is, with EX_CLOSED and * EX_LOCKED filtered out. If locks is 2, it's from an * 'old' area, so handle it, otherwise just set exit_info. * This allows new exit flags to be easily added. :) * (Impossible for new area to have locks = 2(closed) */ if( locks == 2 ) pexit->exit_info = EX_ISDOOR | EX_PICKPROOF; else pexit->exit_info = locks; pRoomIndex->exit[door] = pexit; top_exit++; } else if( letter == 'E' ) { EXTRA_DESCR_DATA *ed; GET_FREE( ed, exdesc_free ); ed->keyword = fread_string( fp ); ed->description = fread_string( fp ); LINK( ed, pRoomIndex->first_exdesc, pRoomIndex->last_exdesc, next, prev ); top_ed++; } else { bug( "Load_rooms: vnum %d has flag not 'DES'.", vnum ); hang( "Loading Rooms in db.c" ); } } iHash = vnum % MAX_KEY_HASH; SING_TOPLINK( pRoomIndex, room_index_hash[iHash], next ); /* MAG Mod */ GET_FREE( pList, build_free ); pList->data = pRoomIndex; LINK( pList, area_load->first_area_room, area_load->last_area_room, next, prev ); top_room++; } return; } /* * Snarf a shop section. */ void load_shops( FILE * fp ) { SHOP_DATA *pShop; BUILD_DATA_LIST *pList; for( ;; ) { MOB_INDEX_DATA *pMobIndex; int iTrade; int keeper; keeper = fread_number( fp ); if( keeper == 0 ) break; GET_FREE( pShop, shop_free ); pShop->keeper = keeper; 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->open_hour = fread_number( fp ); pShop->close_hour = fread_number( fp ); fread_to_eol( fp ); pMobIndex = get_mob_index( pShop->keeper ); pMobIndex->pShop = pShop; /* MAG Mod */ GET_FREE( pList, build_free ); pList->data = pShop; LINK( pList, area_load->first_area_shop, area_load->last_area_shop, next, prev ); LINK( pShop, first_shop, last_shop, next, prev ); top_shop++; } return; } /* * Snarf 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 *, M, or S.", letter ); hang( "Loading Specials in db.c" ); case 'S': return; case '*': break; case 'M': pMobIndex = get_mob_index( fread_number( fp ) ); pMobIndex->spec_fun = spec_lookup( fread_word( fp ) ); if( pMobIndex->spec_fun == 0 ) { bug( "Load_specials(mob): 'M': vnum %d.", pMobIndex->vnum ); } else { BUILD_DATA_LIST *pList; /* * MAG Mod */ GET_FREE( pList, build_free ); pList->data = pMobIndex; LINK( pList, area_load->first_area_specfunc, area_load->last_area_specfunc, next, prev ); } break; } /* * NB. Comments will not be saved when using areasave - MAG. */ fread_to_eol( fp ); } } /* Snarf objfun declarations. -S- */ void load_objfuns( FILE * fp ) { for( ;; ) { OBJ_INDEX_DATA *pObj; char letter; switch ( letter = fread_letter( fp ) ) { default: bug( "Load_objfuns: letter '%c' not *, O or S.", letter ); hang( "Loading Objfuns in db.c" ); case 'S': return; case '*': break; case 'O': /* -S- mod => obj_funs */ if( ( pObj = get_obj_index( fread_number( fp ) ) ) == NULL ) { char *temp; char buf[MSL]; temp = fread_word( fp ); sprintf( buf, "Error in Load Objfuns: area %s has Objfun without corresponding object. Save this area after booting complete to remove.", strArea ); log_f( buf ); free_string( temp ); } else pObj->obj_fun = obj_fun_lookup( fread_word( fp ) ); if( pObj != NULL ) { if( pObj->obj_fun == 0 ) { bug( "Load_specials(obj): 'X': vnum %d.", pObj->vnum ); } else { BUILD_DATA_LIST *pList; GET_FREE( pList, build_free ); pList->data = pObj; LINK( pList, area_load->first_area_objfunc, area_load->last_area_objfunc, next, prev ); } } break; } /* * NB. Comments will not be saved when using areasave - MAG. */ fread_to_eol( fp ); } } /* * Snarf notes file. */ void load_notes( void ) { FILE *fp; if( ( fp = fopen( NOTE_FILE, "r" ) ) == NULL ) { log_f( "No note file to read." ); return; } for( ;; ) { NOTE_DATA *pnote; char letter; do { letter = getc( fp ); if( feof( fp ) ) { fclose( fp ); return; } } while( isspace( letter ) ); ungetc( letter, fp ); GET_FREE( pnote, note_free ); if( str_cmp( fread_word( fp ), "sender" ) ) break; pnote->sender = fread_string( fp ); if( str_cmp( fread_word( fp ), "date" ) ) break; pnote->date = fread_string( fp ); if( str_cmp( fread_word( fp ), "stamp" ) ) break; pnote->date_stamp = fread_number( fp ); if( str_cmp( fread_word( fp ), "to" ) ) break; pnote->to_list = fread_string( fp ); if( str_cmp( fread_word( fp ), "subject" ) ) break; pnote->subject = fread_string( fp ); if( str_cmp( fread_word( fp ), "text" ) ) break; pnote->text = fread_string( fp ); LINK( pnote, first_note, last_note, next, prev ); } strcpy( strArea, NOTE_FILE ); fpArea = fp; bug( "Load_notes: bad key word.", 0 ); hang( "Loading Notes in db.c" ); return; } /* * Translate all room exits from virtual to real. * Has to be done after all rooms are read in. * Check for bad reverse exits. */ void fix_exits( void ) { char buf[MAX_STRING_LENGTH]; ROOM_INDEX_DATA *pRoomIndex; EXIT_DATA *pexit; int iHash; int door; for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for( pRoomIndex = room_index_hash[iHash]; pRoomIndex != NULL; pRoomIndex = pRoomIndex->next ) { bool fexit; fexit = FALSE; for( door = 0; door <= 5; door++ ) { if( ( pexit = pRoomIndex->exit[door] ) != NULL ) { if( ( pexit->vnum <= 0 ) || ( get_room_index( pexit->vnum ) == NULL ) ) { sprintf( buf, "Bad exit vnum %d in room %d", pexit->vnum, pRoomIndex->vnum ); bug( buf, 0 ); PUT_FREE( pexit, exit_free ); pRoomIndex->exit[door] = NULL; /* pexit->to_room = NULL; */ } else { fexit = TRUE; pexit->to_room = get_room_index( pexit->vnum ); } } } if( !fexit ) SET_BIT( pRoomIndex->room_flags, ROOM_NO_MOB ); } } return; } /* Load up gold into areas */ void load_gold( void ) { FILE *fpArea; int area_num; int gold; AREA_DATA *pArea; fpArea = fopen( "area.gld", "r" ); if( fpArea == NULL ) { bug( "Could not open area.gld for reading.", 0 ); return; } for( ;; ) { area_num = fread_number( fpArea ); if( area_num == -1 ) break; gold = fread_number( fpArea ); if( ( pArea = area_used[area_num] ) != NULL ) pArea->gold = gold; } fclose( fpArea ); } /* Spec: see the comments on load_resets about what check_resets does */ #define VALID_RESET 0 #define INVAL_ROOM 1 #define INVAL_OBJ 2 #define INVAL_MOB 3 #define INVAL_GEN 4 void check_resets( void ) { AREA_DATA *pArea; RESET_DATA *pReset; RESET_DATA *nextReset; ROOM_INDEX_DATA *last_mob_room; int previous_bug = 0; for( pArea = first_area; pArea; pArea = pArea->next ) { last_mob_room = NULL; for( pReset = pArea->first_reset; pReset; pReset = nextReset ) { ROOM_INDEX_DATA *pRoomIndex = NULL; EXIT_DATA *pexit; int ValReset = VALID_RESET; nextReset = pReset->next; switch ( pReset->command ) { default: SHOW_AREA; bug( "Load_resets: bad command '%c'.", pReset->command ); ValReset = INVAL_GEN; break; case 'A': /* obsolete.. */ if( !get_room_index( pReset->arg1 ) ) ValReset = INVAL_ROOM; break; case 'M': if( !get_mob_index( pReset->arg1 ) ) ValReset = INVAL_MOB; if( !( last_mob_room = get_room_index( pReset->arg3 ) ) ) ValReset = INVAL_ROOM; break; case 'O': if( !get_obj_index( pReset->arg1 ) ) ValReset = INVAL_OBJ; if( !get_room_index( pReset->arg3 ) ) ValReset = INVAL_ROOM; break; case 'P': /* obsolete.. */ if( !get_obj_index( pReset->arg1 ) || !get_obj_index( pReset->arg3 ) ) ValReset = INVAL_OBJ; break; case 'G': case 'E': if( !get_obj_index( pReset->arg1 ) ) ValReset = INVAL_OBJ; if( !last_mob_room ) ValReset = INVAL_ROOM; break; case 'D': if( !( pRoomIndex = get_room_index( pReset->arg1 ) ) ) { ValReset = INVAL_ROOM; break; } if( pReset->arg2 < 0 || pReset->arg2 > 5 || !( pexit = pRoomIndex->exit[pReset->arg2] ) || !IS_SET( pexit->exit_info, EX_ISDOOR ) ) { SHOW_AREA; bug( "Check_resets: 'D': exit %d not door.", pReset->arg2 ); ValReset = INVAL_GEN; } if( pReset->arg3 < 0 || pReset->arg3 > 2 ) { SHOW_AREA; bug( "Check_resets: 'D': bad 'locks': %d.", pReset->arg3 ); ValReset = INVAL_GEN; } break; case 'R': if( !( pRoomIndex = get_room_index( pReset->arg1 ) ) ) { ValReset = INVAL_ROOM; break; } if( pReset->arg2 < 0 || pReset->arg2 > 5 ) { SHOW_AREA; bug( "Check_resets: 'R': bad exit %d.", pReset->arg2 ); ValReset = INVAL_GEN; } break; } if( ValReset != VALID_RESET ) { char buf[128]; switch ( ValReset ) { case INVAL_ROOM: sprintf( buf, "Invalid room for reset: " ); break; case INVAL_OBJ: sprintf( buf, "Invalid obj for reset: " ); break; case INVAL_MOB: sprintf( buf, "Invalid mob for reset: " ); break; case INVAL_GEN: default: sprintf( buf, "Invalid arg for reset: " ); break; } SHOW_AREA; sprintf( buf + strlen( buf ), "%c %d %d %d %d.", pReset->command, pReset->ifflag, pReset->arg1, pReset->arg2, pReset->arg3 ); bug( buf, 0 ); { int room = 0; ROOM_INDEX_DATA *reset_room; RESET_DATA *criminal; BUILD_DATA_LIST *guilty_reset; room = pReset->arg1; reset_room = get_room_index( room ); for( guilty_reset = reset_room->first_room_reset; guilty_reset; guilty_reset = guilty_reset->next ) { criminal = guilty_reset->data; if( criminal == pReset ) { bug( "Found the reset", 0 ); break; } } if( guilty_reset == NULL ) { sprintf( bug_buf, "Uhoh, couldn't find that damn reset!" ); monitor_chan( bug_buf, MONITOR_AREA_BUGS ); bug( "Couldn't find the reset.", 0 ); } else { UNLINK( guilty_reset, reset_room->first_room_reset, reset_room->last_room_reset, next, prev ); guilty_reset->data = NULL; PUT_FREE( guilty_reset, build_free ); } } UNLINK( pReset, pArea->first_reset, pArea->last_reset, next, prev ); PUT_FREE( pReset, reset_free ); } } } return; } /* * Repopulate areas periodically. */ void area_update( void ) { AREA_DATA *pArea; for( pArea = first_area; pArea != NULL; pArea = pArea->next ) { CHAR_DATA *pch; pArea->age++; /* * Check for PC's. */ if( ( pArea->nplayer > 0 ) && ( pArea->age >= ( pArea->reset_rate - 1 ) ) ) { for( pch = first_char; pch != NULL; pch = pch->next ) { if( !IS_NPC( pch ) && IS_AWAKE( pch ) && pch->in_room != NULL && pch->in_room->area == pArea ) { char reset_buf[MSL]; sprintf( reset_buf, "%s\n\r", pArea->reset_msg ); send_to_char( reset_buf, pch ); } } } /* * Check age and reset. * Note: Mud School resets every 3 minutes (not 15). */ if( ( ( pArea->nplayer == 0 ) && ( pArea->age >= 5 ) ) || ( pArea->age >= pArea->reset_rate ) ) { reset_area( pArea ); pArea->age = UMIN( pArea->reset_rate - 1, number_range( 0, 3 ) ); } } return; } /* * Reset one area. */ void reset_area( AREA_DATA * pArea ) { RESET_DATA *pReset; CHAR_DATA *mob; char buf[MAX_STRING_LENGTH]; bool last; bool just_loaded = FALSE; int level; int previous_bug = 0; sprintf( buf, "Area Reset called for %s.", pArea->name ); monitor_chan( buf, MONITOR_AREA_UPDATE ); area_resetting_global = TRUE; mob = NULL; last = TRUE; level = 0; for( pReset = pArea->first_reset; pReset != NULL; pReset = pReset->next ) { ROOM_INDEX_DATA *pRoomIndex; MOB_INDEX_DATA *pMobIndex; OBJ_INDEX_DATA *pObjIndex; OBJ_INDEX_DATA *pObjToIndex; EXIT_DATA *pexit; OBJ_DATA *obj; OBJ_DATA *obj_to; sh_int num_allowed = 2; switch ( pReset->command ) { default: bug( "Reset_area: bad command %c.", pReset->command ); break; case 'A': break; case 'M': just_loaded = FALSE; if( ( pMobIndex = get_mob_index( pReset->arg1 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'M': bad vnum %d.", pReset->arg1 ); continue; } if( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'R': bad vnum %d.", pReset->arg3 ); continue; } level = pMobIndex->level; if( pMobIndex->count >= pReset->arg2 ) { last = FALSE; break; } mob = create_mobile( pMobIndex ); just_loaded = TRUE; /* * Check for pet shop. */ { ROOM_INDEX_DATA *pRoomIndexPrev; pRoomIndexPrev = get_room_index( pRoomIndex->vnum - 1 ); if( pRoomIndexPrev != NULL && IS_SET( pRoomIndexPrev->room_flags, ROOM_PET_SHOP ) ) SET_BIT( mob->act, ACT_PET ); } if( room_is_dark( pRoomIndex ) ) SET_BIT( mob->affected_by, AFF_INFRARED ); if( mob->in_room != NULL ) char_to_room( mob, mob->in_room ); else char_to_room( mob, pRoomIndex ); level = URANGE( 0, mob->level - 2, LEVEL_HERO ); last = TRUE; break; case 'O': if( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'O': bad vnum %d.", pReset->arg1 ); continue; } if( ( pRoomIndex = get_room_index( pReset->arg3 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'R': bad vnum %d.", pReset->arg3 ); continue; } num_allowed = ( ( pReset->arg2 == 0 ) ? 2 : pReset->arg2 - 1 ); if( ( count_obj_room( pObjIndex, pRoomIndex->first_content ) > num_allowed ) || ( ( count_obj_room( pObjIndex, pRoomIndex->first_content ) > 0 ) && ( ( pObjIndex->item_type == ITEM_BOARD ) || ( pObjIndex->item_type == ITEM_FOUNTAIN ) || ( pObjIndex->item_type == ITEM_FURNITURE ) || ( pObjIndex->item_type == ITEM_PORTAL ) || ( pObjIndex->item_type == ITEM_PIECE ) || ( pObjIndex->extra_flags == ITEM_RARE ) ) ) ) { last = FALSE; break; } obj = create_object( pObjIndex, number_fuzzy( level ) ); obj_to_room( obj, pRoomIndex ); if( ( IS_SET( obj->extra_flags, ITEM_RARE ) ) && !( ( number_percent( ) < 2 ) && ( number_percent( ) < 8 ) ) ) { extract_obj( obj ); } else if( ( IS_SET( pRoomIndex->room_flags, ROOM_NO_REPOP ) ) && ( pRoomIndex->first_person != NULL ) ) { extract_obj( obj ); } last = TRUE; break; case 'P': if( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'P': bad vnum %d.", pReset->arg1 ); continue; } if( ( pObjToIndex = get_obj_index( pReset->arg3 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'P': bad vnum %d.", pReset->arg3 ); continue; } if( pArea->nplayer > 0 || ( obj_to = get_obj_type( pObjToIndex ) ) == NULL || count_obj_list( pObjIndex, obj_to->first_in_carry_list ) > 0 ) { last = FALSE; break; } obj = create_object( pObjIndex, number_fuzzy( obj_to->level ) ); obj_to_obj( obj, obj_to ); last = TRUE; break; case 'G': case 'E': if( ( pObjIndex = get_obj_index( pReset->arg1 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'E' or 'G': bad vnum %d.", pReset->arg1 ); continue; } if( !just_loaded ) break; if( mob == NULL ) { SHOW_AREA; bug( "Reset_area: 'E' or 'G': null mob for vnum %d.", pReset->arg1 ); last = FALSE; break; } if( mob->pIndexData->pShop != NULL ) { int olevel; switch ( pObjIndex->item_type ) { default: olevel = 0; break; case ITEM_PILL: olevel = number_range( 0, 10 ); break; case ITEM_POTION: olevel = number_range( 0, 10 ); break; case ITEM_SCROLL: olevel = number_range( 5, 15 ); break; case ITEM_WAND: olevel = number_range( 10, 20 ); break; case ITEM_STAFF: olevel = number_range( 15, 25 ); break; case ITEM_ARMOR: olevel = number_range( 5, 15 ); break; case ITEM_WEAPON: olevel = number_range( 5, 15 ); break; } obj = create_object( pObjIndex, olevel ); SET_BIT( obj->extra_flags, ITEM_INVENTORY ); } else { bool has_obj = FALSE; OBJ_DATA *carried; for( carried = mob->first_carry; carried; carried = carried->next_in_carry_list ) { if( carried->pIndexData == pObjIndex ) { has_obj = TRUE; break; } } if( has_obj ) break; obj = create_object( pObjIndex, number_fuzzy( level ) ); } obj_to_char( obj, mob ); if( pReset->command == 'E' ) { char objname[MSL]; one_argument( obj->name, objname ); do_wear( mob, objname ); } last = TRUE; break; case 'D': if( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL ) { bug( "Reset_area: 'D': bad vnum %d.", pReset->arg1 ); continue; } if( ( pexit = pRoomIndex->exit[pReset->arg2] ) == NULL ) break; switch ( pReset->arg3 ) { case 0: REMOVE_BIT( pexit->exit_info, EX_CLOSED ); REMOVE_BIT( pexit->exit_info, EX_LOCKED ); break; case 1: SET_BIT( pexit->exit_info, EX_CLOSED ); REMOVE_BIT( pexit->exit_info, EX_LOCKED ); break; case 2: SET_BIT( pexit->exit_info, EX_CLOSED ); SET_BIT( pexit->exit_info, EX_LOCKED ); break; } last = TRUE; break; case 'R': if( ( pRoomIndex = get_room_index( pReset->arg1 ) ) == NULL ) { SHOW_AREA; bug( "Reset_area: 'R': bad vnum %d.", pReset->arg1 ); continue; } { int d0; int d1; for( d0 = 0; d0 < pReset->arg2 - 1; d0++ ) { d1 = number_range( d0, pReset->arg2 - 1 ); pexit = pRoomIndex->exit[d0]; pRoomIndex->exit[d0] = pRoomIndex->exit[d1]; pRoomIndex->exit[d1] = pexit; } } break; } } area_resetting_global = FALSE; return; } /* Nasty hack to get back the address of a loaded mob */ extern CHAR_DATA *loaded_mob_addr; /* * Create an instance of a mobile. */ CHAR_DATA *create_mobile( MOB_INDEX_DATA * pMobIndex ) { CHAR_DATA *mob; int level; char buf[255]; MONEY_TYPE *money; sh_int cnt; if( pMobIndex == NULL ) { bug( "Create_mobile: NULL pMobIndex.", 0 ); hang( "Create Mobile in db.c" ); } if( IS_SET( pMobIndex->act, ACT_INTELLIGENT ) ) { /* * Only load one with the same name */ #if !defined(machintosh) && !defined(MSDOS) sprintf( buf, "%s n%i", pMobIndex->player_name, pMobIndex->count + 1 ); #else sprintf( buf, "n%i %s", pMobIndex->count + 1, pMobIndex->player_name ); #endif } GET_FREE( mob, char_free ); clear_char( mob ); mob->pIndexData = pMobIndex; if( IS_SET( pMobIndex->act, ACT_INTELLIGENT ) ) mob->name = str_dup( buf ); else mob->name = str_dup( pMobIndex->player_name ); mob->short_descr = str_dup( pMobIndex->short_descr ); mob->long_descr = str_dup( pMobIndex->long_descr ); mob->description = str_dup( pMobIndex->description ); mob->switched = FALSE; mob->old_body = NULL; mob->spec_fun = pMobIndex->spec_fun; mob->sitting = NULL; mob->prompt = str_dup( "<%h %m %v> " ); mob->first_shield = NULL; mob->last_shield = NULL; /* * Changed exp value for mobs */ level = ( pMobIndex->level ); mob->level = level; mob->act = pMobIndex->act; mob->affected_by = pMobIndex->affected_by; mob->alignment = pMobIndex->alignment; mob->sex = pMobIndex->sex; mob->ac_mod = pMobIndex->ac_mod; mob->hr_mod = pMobIndex->hr_mod; mob->dr_mod = pMobIndex->dr_mod; /* mob->move_to = NO_VNUM; */ mob->armor = interpolate( mob->level / 2, 100, -100 ); mob->max_hit = mob->level * 15 + number_range( mob->level * mob->level / 2, mob->level * mob->level / 1 ); mob->hit = mob->max_hit; mob->exp = exp_for_mobile( mob->level, mob ); mob->intell_exp = 0; /* * mana for mobs... */ mob->max_mana = level * 25; mob->mana = level * 25; mob->skills = pMobIndex->skills; mob->cast = pMobIndex->cast; mob->def = pMobIndex->def; mob->class = pMobIndex->class; mob->clan = pMobIndex->clan; mob->strong_magic = pMobIndex->strong_magic; mob->weak_magic = pMobIndex->weak_magic; mob->resist = pMobIndex->resist; mob->suscept = pMobIndex->suscept; mob->race_mods = pMobIndex->race_mods; mob->power_skills = pMobIndex->power_skills; mob->power_cast = pMobIndex->power_cast; mob->race = pMobIndex->race; mob->position = POS_STANDING; mob->is_quitting = FALSE; mob->extract_timer = -1; mob->in_room = NULL; /* to distinguish between loaded mobs */ /* * and creted mobs */ mob->ngroup = NULL; GET_FREE( money, money_type_free ); #ifdef DEBUG_MONEY { char testbuf[MSL]; sprintf( testbuf, "create_mobile, %s", mob->name ); money->money_key = str_dup( testbuf ); } #endif for( cnt = 0; cnt < MAX_CURRENCY; cnt++ ) money->cash_unit[cnt] = pMobIndex->pShop ? 10 : 0; mob->money = money; GET_FREE( money, money_type_free ); #ifdef DEBUG_MONEY { char testbuf[MSL]; sprintf( testbuf, "create_mobile, %s", mob->name ); money->money_key = str_dup( testbuf ); } #endif for( cnt = 0; cnt < MAX_CURRENCY; cnt++ ) money->cash_unit[cnt] = 0; mob->bank_money = money; /* * Insert in list. */ mob->next = NULL; mob->prev = NULL; LINK( mob, first_char, last_char, next, prev ); pMobIndex->count++; // Create group data for mob if( AI_MOB( mob ) ) { NPC_GROUP_DATA *ngroup; GET_FREE( ngroup, npc_group_free ); ngroup->next = NULL; ngroup->prev = NULL; ngroup->state = GRP_STATE_IDLE; ngroup->first_follower = NULL; ngroup->last_follower = NULL; ngroup->leader = mob; ngroup->seek_room = NULL; ngroup->enemies = str_dup( "none" ); ngroup->last_fighting = str_dup( "none" ); ngroup->wants = str_dup( "none" ); ngroup->needs = str_dup( "none" ); mob->ngroup = ngroup; LINK( ngroup, first_npc_group, last_npc_group, next, prev ); } return mob; } /* * Create an instance of an object. */ OBJ_DATA *create_object( OBJ_INDEX_DATA * pObjIndex, int level ) { static OBJ_DATA obj_zero; OBJ_DATA *obj; AFFECT_DATA *af; AFFECT_DATA *new_af; int new_cost; int looper; MONEY_TYPE *money; sh_int cnt; if( level < 0 ) level = 1; if( pObjIndex == NULL ) { bug( "Create_object: NULL pObjIndex.", 0 ); hang( "Creating Objext in db.c" ); } GET_FREE( obj, obj_free ); *obj = obj_zero; obj->pIndexData = pObjIndex; obj->in_room = NULL; if( pObjIndex->level < 3 ) { if( pObjIndex->level == 2 ) { obj->level = 1; } else { obj->level = level; } } else { obj->level = pObjIndex->level; } obj->wear_loc = -1; obj->name = str_dup( pObjIndex->name ); obj->short_descr = str_dup( pObjIndex->short_descr ); obj->description = str_dup( pObjIndex->description ); obj->item_type = pObjIndex->item_type; obj->extra_flags = pObjIndex->extra_flags; obj->wear_flags = pObjIndex->wear_flags; obj->item_apply = pObjIndex->item_apply; obj->obj_fun = pObjIndex->obj_fun; obj->first_in_room = NULL; obj->next_in_room = NULL; obj->last_in_room = NULL; obj->prev_in_room = NULL; obj->first_in_carry_list = NULL; obj->next_in_carry_list = NULL; obj->last_in_carry_list = NULL; obj->prev_in_carry_list = NULL; obj->first_content = NULL; obj->next_content = NULL; obj->last_content = NULL; obj->prev_content = NULL; obj->weight = pObjIndex->weight; GET_FREE( money, money_type_free ); #ifdef DEBUG_MONEY { char testbuf[MSL]; sprintf( testbuf, "create_object, %s", obj->name ); money->money_key = str_dup( testbuf ); } #endif for( cnt = 0; cnt < MAX_CURRENCY; cnt++ ) money->cash_unit[cnt] = 0; obj->money = money; obj->in_obj = NULL; /* * We want to copy pObjIndex->affected to obj->index */ for( af = pObjIndex->first_apply; af != NULL; af = af->next ) { /* * Create new_af, or use a free_affect */ GET_FREE( new_af, affect_free ); /* * Now initialize the contents of new_af */ new_af->type = -1; new_af->duration = -1; new_af->location = af->location; new_af->modifier = af->modifier; new_af->bitvector = 0; new_af->caster = NULL; LINK( new_af, obj->first_apply, obj->last_apply, next, prev ); } for( looper = 0; looper < 10; looper++ ) { obj->value[looper] = pObjIndex->value[looper]; } new_cost = get_item_value( obj ); if( IS_SET( obj->extra_flags, ITEM_REMORT ) ) new_cost *= 2; if( IS_SET( obj->extra_flags, ITEM_ADEPT ) ) new_cost *= 3; if( IS_SET( obj->extra_flags, ITEM_RARE ) ) new_cost *= 10; obj->cost = new_cost; if( obj->item_type == ITEM_FOOD ) obj->cost /= 200; obj->cost = UMAX( 10, obj->cost ); obj->condition = 100; /* New, so in tip-top condition */ /* * Mess with object properties. */ switch ( obj->item_type ) { default: bugf( "create_object: vnum %d bad type %d.", pObjIndex->vnum, obj->item_type ); break; case ITEM_SPELL_MATRIX: case ITEM_ENCHANTMENT: case ITEM_LIGHT: case ITEM_BEACON: case ITEM_TREASURE: case ITEM_FURNITURE: case ITEM_TRASH: case ITEM_CLUTCH: break; case ITEM_CONTAINER: obj->wear_flags = ITEM_TAKE; case ITEM_DRINK_CON: case ITEM_BOARD: case ITEM_KEY: case ITEM_FOOD: case ITEM_BOAT: case ITEM_CORPSE_NPC: case ITEM_CORPSE_PC: case ITEM_FOUNTAIN: case ITEM_PORTAL: case ITEM_PIECE: case ITEM_SOUL: case ITEM_TRIGGER: case ITEM_STAKE: case ITEM_QUEST: case ITEM_WRAPPED_PRESENT: break; case ITEM_SCROLL: obj->value[0] = number_fuzzy( obj->value[0] ); break; case ITEM_WAND: case ITEM_STAFF: obj->value[0] = number_fuzzy( obj->value[0] ); obj->value[1] = number_fuzzy( obj->value[1] ); obj->value[2] = obj->value[1]; break; case ITEM_WEAPON: obj->value[1] = number_fuzzy( number_fuzzy( 1 * level / 8 + 3 ) ); obj->value[2] = number_fuzzy( number_fuzzy( 3 * level / 8 + 4 ) ); break; case ITEM_ARMOR: obj->value[0] = number_fuzzy( level / 12 + 4 ); break; case ITEM_POTION: case ITEM_PILL: obj->value[0] = number_fuzzy( number_fuzzy( obj->value[0] ) ); break; case ITEM_MONEY: obj->value[0] = obj->cost; break; } if( pObjIndex->value[7] > 0 ) obj->timer = pObjIndex->value[7]; LINK( obj, first_obj, last_obj, next, prev ); pObjIndex->count++; return obj; } /* * Clear a new character. */ void clear_char( CHAR_DATA * ch ) { static CHAR_DATA ch_zero; *ch = ch_zero; ch->name = &str_empty[0]; ch->short_descr = &str_empty[0]; ch->long_descr = &str_empty[0]; ch->long_descr_orig = &str_empty[0]; ch->description = &str_empty[0]; ch->prompt = &str_empty[0]; ch->last_note = 0; ch->logon = current_time; ch->armor = 100; ch->position = POS_STANDING; ch->practice = 21; ch->hit = 20; ch->max_hit = 20; ch->mana = 100; ch->max_mana = 100; ch->move = 100; ch->sitting = NULL; ch->max_move = 100; ch->act_build = 0; ch->build_vnum = -1; ch->sentence = 0; ch->switched = FALSE; ch->old_body = NULL; ch->first_shield = NULL; ch->last_shield = NULL; ch->stunTimer = 0; /* ch->pcdata->recall_vnum = 3001; */ return; } /* * Free a character. */ void free_char( CHAR_DATA * ch ) { MPROG_ACT_LIST *mpact; CHAR_DATA *rch; ch->is_quitting = TRUE; while( ch->first_carry != NULL ) extract_obj( ch->first_carry ); while( ch->first_affect != NULL ) affect_remove( ch, ch->first_affect ); while( ( mpact = ch->first_mpact ) != NULL ) { ch->first_mpact = mpact->next; PUT_FREE( mpact, mpact_free ); } for( rch = first_char; rch; rch = rch->next ) { AFFECT_DATA *paf; if( rch->master == ch ) rch->master = NULL; if( rch->leader == ch ) rch->leader = NULL; if( rch->fighting == ch ) rch->fighting = NULL; if( rch->reply == ch ) rch->reply = NULL; if( rch->hunting == ch ) { if( IS_NPC( rch ) && !IS_NPC( ch ) ) { free_string( rch->searching ); rch->searching = str_dup( ch->name ); } else if( !IS_NPC( rch ) ) { send_to_char( "@@RYou seem to have lost your prey.\n\r", rch ); } end_hunt( rch ); } if( rch->hunt_for == ch ) rch->hunt_for = NULL; if( rch->old_body == ch ) { do_return( rch, "" ); rch->old_body = NULL; } for( mpact = rch->first_mpact; mpact; mpact = mpact->next ) { if( mpact->ch == ch ) mpact->ch = NULL; if( mpact->vo == ch ) mpact->vo = NULL; } for( paf = rch->first_affect; paf; paf = paf->next ) if( paf->caster == ch ) paf->caster = NULL; } { ROOM_INDEX_DATA *room; int rvnum; ROOM_AFFECT_DATA *raf; for( rvnum = 0; rvnum < MAX_KEY_HASH; rvnum++ ) for( room = room_index_hash[rvnum]; room; room = room->next ) for( raf = room->first_room_affect; raf; raf = raf->next ) if( raf->caster == ch ) raf->caster = NULL; } if( ch->pnote ) { PUT_FREE( ch->pnote, note_free ); } if( ch->current_brand ) { PUT_FREE( ch->current_brand, brand_data_free ); } if( ch->pcdata != NULL ) { #ifdef IMC imc_freechardata( ch ); #endif #ifdef I3 free_i3chardata( ch ); #endif PUT_FREE( ch->pcdata, pcd_free ); } PUT_FREE( ch, char_free ); return; } /* * Get an extra description from a list. */ char *get_extra_descr( const char *name, EXTRA_DESCR_DATA * ed ) { for( ; ed != NULL; 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; for( pMobIndex = mob_index_hash[vnum % MAX_KEY_HASH]; pMobIndex != NULL; pMobIndex = pMobIndex->next ) { if( pMobIndex->vnum == vnum ) return pMobIndex; } if( fBootDb ) { bug( "Get_mob_index: bad vnum %d.", vnum ); hang( "Get mob index in db.c" ); } return NULL; } /* * Translates mob virtual number to its obj index struct. * Hash table lookup. */ OBJ_INDEX_DATA *get_obj_index( int vnum ) { OBJ_INDEX_DATA *pObjIndex; for( pObjIndex = obj_index_hash[vnum % MAX_KEY_HASH]; pObjIndex != NULL; pObjIndex = pObjIndex->next ) { if( pObjIndex->vnum == vnum ) return pObjIndex; } if( fBootDb ) { bug( "Get_obj_index: bad vnum %d.", vnum ); hang( "Get Object Index in db.c" ); } return NULL; } /* * Translates mob virtual number to its room index struct. * Hash table lookup. */ ROOM_INDEX_DATA *get_room_index( int vnum ) { ROOM_INDEX_DATA *pRoomIndex; for( pRoomIndex = room_index_hash[vnum % MAX_KEY_HASH]; pRoomIndex != NULL; pRoomIndex = pRoomIndex->next ) { if( pRoomIndex->vnum == vnum ) return pRoomIndex; } if( fBootDb ) { bug( "Get_room_index: bad vnum %d.", vnum ); /* exit( 1 ); */ } return NULL; } /* * Read a letter from a file. */ char fread_letter( FILE * fp ) { char c; do { 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 { 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 ) ) { char error_buf[MSL]; sprintf( error_buf, "%c", c ); bug_string( "Fread_number: looking for a digit, found a %s.", error_buf ); hang( "Error in fread_number" ); } while( isdigit( c ) ) { 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; } /* * Read to end of line (for comments). */ /* Spec: fixed to handle EOF more gracefully */ void fread_to_eol( FILE * fp ) { char c; do { c = getc( fp ); } while( c != '\n' && c != '\r' && c != EOF ); while( c == '\n' || c == '\r' ) { c = getc( fp ); } if( c == EOF ) { bugf( "fread_to_eol: EOF" ); return; } ungetc( c, fp ); return; } /* Same as above, but returns the rest of the line */ /* Spec: fixed to handle EOF more gracefully */ char *fsave_to_eol( FILE * fp ) { char string[MAX_INPUT_LENGTH + 1]; int a; char c; a = 0; do { string[a++] = getc( fp ); } while( a < MAX_INPUT_LENGTH && string[a - 1] != '\n' && string[a - 1] != '\r' && string[a - 1] != EOF ); if( string[a - 1] == EOF ) { bugf( "fsave_to_eol: EOF" ); string[a - 1] = 0; return str_dup( string ); } if( a == MAX_INPUT_LENGTH ) fread_to_eol( fp ); else { c = string[a - 1]; while( c == '\n' || c == '\r' ) c = getc( fp ); if( c == EOF ) bugf( "fsave_to_eol: EOF" ); else ungetc( c, fp ); } string[a] = '\0'; return str_dup( string ); } /* * 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.\n\r", 0 ); if( fBootDb ) kill( getpid( ), SIGQUIT ); strcpy( word, "" ); 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.\n\r", 0 ); if( fBootDb ) kill( getpid( ), SIGQUIT ); *pword = '\0'; return word; } *pword = getc( fp ); if( cEnd == ' ' ? isspace( *pword ) : *pword == cEnd ) { if( cEnd == ' ' ) ungetc( *pword, fp ); *pword = '\0'; return word; } } bug( "Fread_word: word too long", 0 ); kill( getpid( ), SIGQUIT ); return NULL; } void *_getmem( int size, const char *caller, int log ) { void *mem; if( !( mem = malloc( size ) ) ) { fprintf( stderr, "Out of memory.\n" ); raise( SIGSEGV ); } memset( mem, 0, size ); if( log && mem_log ) log_f( "getmem(%d)=%p from %s", size, mem, caller ); return mem; } #if 0 /* * Duplicate a string into dynamic memory. * Fread_strings are read-only and shared. */ #define STRING_FREELIST #ifdef STRING_FREELIST #define MAX_SIZE_LIST 13 static const int sizelist[MAX_SIZE_LIST] = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768 }; struct text_data { struct text_data *next; char *text; }; static struct text_data *text_free[MAX_SIZE_LIST] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; static struct text_data *tdf_free = NULL; #endif char *str_dup( const char *str ) { char *str_new; #ifdef STRING_FREELIST sh_int size; int len; #endif if( !str || !*str ) return &str_empty[0]; if( str >= string_space && str < top_string ) return ( char * )str; #ifdef STRING_FREELIST len = strlen( str ) + 1; for( size = 0; size < MAX_SIZE_LIST; size++ ) if( len < sizelist[size] ) break; if( size < MAX_SIZE_LIST ) { if( text_free[size] != NULL ) { struct text_data *tdf = text_free[size]; text_free[size] = tdf->next; str_new = tdf->text; tdf->next = tdf_free; tdf_free = tdf; } else str_new = getmem( sizelist[size] ); } else str_new = getmem( len ); #else str_new = getmem( strlen( str ) + 1 ); #endif strcpy( str_new, str ); return str_new; } /* * Free a string. * Null is legal here to simplify callers. * Read-only shared strings are not touched. */ void free_string( char *pstr ) { #ifdef STRING_FREELIST sh_int size; int len; #endif if( pstr == NULL || pstr == &str_empty[0] || ( pstr >= string_space && pstr < top_string ) ) return; #ifdef STRING_FREELIST len = strlen( pstr ) + 1; for( size = 0; size < MAX_SIZE_LIST; size++ ) if( len < sizelist[size] ) break; if( size < MAX_SIZE_LIST ) { struct text_data *tdf; if( tdf_free ) { tdf = tdf_free; tdf_free = tdf->next; } else tdf = getmem( sizeof( *tdf ) ); tdf->text = pstr; tdf->next = text_free[size]; text_free[size] = tdf; } else dispose( pstr, len ); #else dispose( pstr, strlen( pstr ) + 1 ); #endif return; } #endif void do_areas( CHAR_DATA * ch, char *argument ) { char buf[MAX_STRING_LENGTH]; char msg[MAX_STRING_LENGTH]; char arg1[MSL]; sh_int foo; AREA_DATA *pArea; bool fall = FALSE; argument = one_argument( argument, arg1 ); if( !str_cmp( arg1, "all" ) ) fall = TRUE; sprintf( buf, "@@W" mudnamecolor " AREA LISTING\n\r" ); safe_strcat( MAX_STRING_LENGTH, buf, "+-------+------------+------------------------------------------------+\n\r" ); safe_strcat( MAX_STRING_LENGTH, buf, "| @@yLevel@@W | | |\n\r" ); safe_strcat( MAX_STRING_LENGTH, buf, "| @@yrange@@W | @@yAuthor@@W | @@yName of Area@@W |\n\r" ); safe_strcat( MAX_STRING_LENGTH, buf, "+-------+------------+------------------------------------------------+\n\r" ); foo = 0; for( pArea = first_area; pArea != NULL; pArea = pArea->next ) { if( ( IS_SET( pArea->flags, AREA_NOSHOW ) ) || ( IS_SET( pArea->flags, AREA_BUILDING ) ) ) continue; /* for non-finished areas - don't show */ if( ( !fall ) && ( ( pArea->min_level > ( get_psuedo_level( ch ) ) ) || ( pArea->max_level < ( get_psuedo_level( ch ) ) ) ) ) continue; foo++; sprintf( msg, " %s %12s %s\n\r", pArea->level_label, capitalize( pArea->owner ), pArea->name ); safe_strcat( MAX_STRING_LENGTH, buf, msg ); } sprintf( msg, "@@R%d Areas listed.\n\r@@N Type areas all to list the entire " mudnamecolor " realm.\n\r@@N", foo ); safe_strcat( MAX_STRING_LENGTH, buf, msg ); send_to_char( buf, ch ); return; } void perm_update( ) { /* * output perm usage to log file */ FILE *po; char *strtime; po = fopen( "perm.out", "a" ); strtime = ctime( ¤t_time ); strtime[strlen( strtime ) - 1] = '\0'; fprintf( po, "%s :: Perms %5d blocks of %7d bytes.\n\r", strtime, nAllocPerm, sAllocPerm ); fclose( po ); return; } void do_memory( CHAR_DATA * ch, char *argument ) { char buf[MAX_STRING_LENGTH]; if( !str_cmp( argument, "defrag" ) ) { send_to_char( "Defragmenting SSM heap.", ch ); log_f( "SSM: %s called defrag_heap.", ch->name ); defrag_heap( ); return; } if( !str_cmp( argument, "log" ) ) { if( get_trust( ch ) < MAX_LEVEL ) { send_to_char( "Not at your level.\n\r", ch ); return; } if( mem_log ) { mem_log = FALSE; send_to_char( "Memory logging is now OFF.\n\r", ch ); log_f( "%s turned off memory logging", ch->name ); return; } else { mem_log = TRUE; send_to_char( "Memory logging is now ON.. remember to turn it off!\n\r", ch ); log_f( "%s turned on memory logging", ch->name ); return; } } sprintf( buf, "Affects %5d\n\r", top_affect ); send_to_char( buf, ch ); sprintf( buf, "Areas %5d\n\r", top_area ); send_to_char( buf, ch ); sprintf( buf, "ExDes %5d\n\r", top_ed ); send_to_char( buf, ch ); sprintf( buf, "Exits %5d\n\r", top_exit ); send_to_char( buf, ch ); sprintf( buf, "Helps %5d\n\r", top_help ); send_to_char( buf, ch ); sprintf( buf, "Mobs %5d\n\r", top_mob_index ); send_to_char( buf, ch ); sprintf( buf, "Objs %5d\n\r", top_obj_index ); send_to_char( buf, ch ); sprintf( buf, "Resets %5d\n\r", top_reset ); send_to_char( buf, ch ); sprintf( buf, "Rooms %5d\n\r", top_room ); send_to_char( buf, ch ); sprintf( buf, "Shops %5d\n\r", top_shop ); send_to_char( buf, ch ); #if 0 sprintf( buf, "Strings %5d strings of %7d bytes (max %d).\n\r", nAllocString, sAllocString, MAX_STRING ); #endif sprintf( buf, "Shared String Info:\n\r" ); send_to_char( buf, ch ); sprintf( buf, "Strings %5ld strings of %7ld bytes (max %ld).\n\r", nAllocString, sAllocString, MAX_STRING ); send_to_char( buf, ch ); sprintf( buf, "Overflow Strings %5ld strings of %7ld bytes.\n\r", nOverFlowString, sOverFlowString ); send_to_char( buf, ch ); if( Full ) { send_to_char( "Shared String Heap is full, increase MAX_STRING.\n\r", ch ); sprintf( buf, "Overflow high-water-mark is %ld bytes.\n\r", hwOverFlow ); send_to_char( buf, ch ); } sprintf( buf, "Perms %5d blocks of %7d bytes.\n\r", nAllocPerm, sAllocPerm ); send_to_char( buf, ch ); return; } void do_status( CHAR_DATA * ch, char *argument ) { char buf[MAX_STRING_LENGTH]; send_to_char( " Status Report for Ack! Mud:\n\r", ch ); send_to_char( " ---------------------------\n\r\n\r", ch ); do_time( ch, "" ); send_to_char( "\n\r", ch ); send_to_char( "The following counts are for *distinct* mobs/objs/rooms, not a count\n\r", ch ); send_to_char( "of how many are actually in the game at this time.\n\r", ch ); send_to_char( "NB. Areas count will include areas used as help files.\n\r\n\r", ch ); sprintf( buf, "Areas %5d\n\r", top_area ); send_to_char( buf, ch ); sprintf( buf, "Helps %5d\n\r", top_help ); send_to_char( buf, ch ); sprintf( buf, "Mobs %5d\n\r", top_mob_index ); send_to_char( buf, ch ); sprintf( buf, "Objs %5d\n\r", top_obj_index ); send_to_char( buf, ch ); sprintf( buf, "Rooms %5d\n\r", top_room ); send_to_char( buf, ch ); return; } /* * Stick a little fuzz on a number. */ int number_fuzzy( int number ) { switch ( number_bits( 2 ) ) { case 0: number -= 1; break; case 3: number += 1; break; } return UMAX( 1, number ); } /* * Generate a random number. */ int number_range( int from, int to ) { int power; int number; if( ( to = to - from + 1 ) <= 1 ) return from; for( power = 2; power < to; power <<= 1 ) ; while( ( number = number_mm( ) & ( power - 1 ) ) >= to ) ; return from + number; } /* * Generate a percentile roll. */ int number_percent( void ) { int percent; while( ( percent = number_mm( ) & ( 128 - 1 ) ) > 99 ) ; return 1 + percent; } /* * Generate a random door. */ int number_door( void ) { int door; while( ( door = number_mm( ) & ( 8 - 1 ) ) > 5 ) ; return door; } int number_bits( int width ) { return number_mm( ) & ( ( 1 << width ) - 1 ); } /* * 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; } /* * Roll some dice. */ int dice( int number, int size ) { int idice; int sum; switch ( size ) { case 0: return 0; case 1: return number; } for( idice = 0, sum = 0; idice < number; idice++ ) sum += number_range( 1, size ); return sum; } /* * Simple linear interpolation. */ int interpolate( int level, int value_00, int value_32 ) { return value_00 + level * ( value_32 - value_00 ) / 32; } /* * Append a string to a file. */ void append_file( CHAR_DATA * ch, char *file, char *str ) { FILE *fp; if( IS_NPC( ch ) || str[0] == '\0' ) return; fclose( fpReserve ); if( ( fp = fopen( file, "a" ) ) == NULL ) { perror( file ); send_to_char( "Could not open the file!\n\r", ch ); } else { fprintf( fp, "[%5d] %s: %s\n", ch->in_room ? ch->in_room->vnum : 0, ch->name, str ); fclose( fp ); } fpReserve = fopen( NULL_FILE, "r" ); return; } /* * Nice little functions that limit the amount of typing you have to do with * each and every log File entry and bug report.---Flar */ void bugf( char *fmt, ... ) { char buf[MSL]; va_list args; va_start( args, fmt ); vsnprintf( buf, sizeof( buf ), fmt, args ); va_end( args ); bug( buf, 0 ); } void log_f( char *fmt, ... ) { char buf[2 * MSL]; va_list args; va_start( args, fmt ); vsnprintf( buf, sizeof( buf ), fmt, args ); va_end( args ); log_string( buf ); } /* * Reports a bug. */ void bug( const char *str, int param ) { char buf[MAX_STRING_LENGTH]; FILE *fp; 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++ ) { while( getc( fpArea ) != '\n' ) ; } fseek( fpArea, iChar, 0 ); } sprintf( buf, "[*****] FILE: %s LINE: %d", strArea, iLine ); log_string( buf ); if( ( fp = fopen( SHUTDOWN_FILE, "a" ) ) != NULL ) { fprintf( fp, "[*****] %s\n", buf ); fclose( fp ); } } strcpy( buf, "[*****] BUG: " ); sprintf( buf + strlen( buf ), str, param ); log_string( buf ); fclose( fpReserve ); if( ( fp = fopen( BUG_FILE, "a" ) ) != NULL ) { fprintf( fp, "%s\n", buf ); fclose( fp ); } fpReserve = fopen( NULL_FILE, "r" ); return; } void bug_string( const char *str, const char *str2 ) { char buf[MAX_STRING_LENGTH]; FILE *fp; 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++ ) { while( getc( fpArea ) != '\n' ) ; } fseek( fpArea, iChar, 0 ); } sprintf( buf, "[*****] FILE: %s LINE: %d", strArea, iLine ); log_string( buf ); if( ( fp = fopen( SHUTDOWN_FILE, "a" ) ) != NULL ) { fprintf( fp, "[*****] %s\n", buf ); fclose( fp ); } } strcpy( buf, "[*****] BUG: " ); sprintf( buf + strlen( buf ), str, str2 ); log_string( buf ); fclose( fpReserve ); if( ( fp = fopen( BUG_FILE, "a" ) ) != NULL ) { fprintf( fp, "%s\n", buf ); fclose( fp ); } fpReserve = fopen( NULL_FILE, "r" ); return; } /* * Writes a string to the log. */ void log_string( const char *str ) { char *strtime; strtime = ctime( ¤t_time ); strtime[strlen( strtime ) - 1] = '\0'; fprintf( stderr, "%s :: %s\n", strtime, str ); return; } /* * This function is here to aid in debugging. * If the last expression in a function is another function call, * gcc likes to generate a JMP instead of a CALL. * This is called "tail chaining." * It hoses the debugger call stack for that call. * So I make this the last call in certain critical functions, * where I really need the call stack to be right for debugging! * * If you don't understand this, then LEAVE IT ALONE. * Don't remove any calls to tail_chain anywhere. * * -- Furey */ void tail_chain( void ) { return; } /* * MOBprogram code block */ /* the 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. */ int mprog_name_to_type( name ) 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; return ( ERROR_PROG ); } /* Had to redo mobprog loading to work with double linked lists. -- Altrag */ void mprog_file_read( char *f, MOB_INDEX_DATA * pMobIndex ) { MPROG_DATA *mprog; FILE *fp; char letter; char name[128]; char *permf; int type; sprintf( name, "%s%s", MOB_DIR, f ); if( !( fp = fopen( name, "r" ) ) ) { bug( "Mob: %d couldn't opne mobprog file.", pMobIndex->vnum ); return; } permf = str_dup( f ); for( ;; ) { if( ( letter = fread_letter( fp ) ) == '|' ) break; else if( letter != '>' ) { bug( "Mprog_file_read: Invalid letter mob %d.", pMobIndex->vnum ); return; } switch ( ( type = fread_number( fp ) ) ) { case ERROR_PROG: bug( "Mob %d: in file prog error.", pMobIndex->vnum ); return; case IN_FILE_PROG: bug( "Mob %d: nested in file progs.", pMobIndex->vnum ); return; default: SET_BIT( pMobIndex->progtypes, type ); GET_FREE( mprog, mprog_free ); mprog->type = type; mprog->arglist = fread_string( fp ); fread_to_eol( fp ); mprog->comlist = fread_string( fp ); fread_to_eol( fp ); mprog->filename = permf; break; } } fclose( fp ); return; } void load_mobprogs( FILE * fp ) { char letter; MOB_INDEX_DATA *iMob; int value; for( ;; ) switch ( LOWER( letter = fread_letter( fp ) ) ) { default: bug( "Load_mobprogs: bad command '%c'.", letter ); fread_to_eol( fp ); break; case 's': fread_to_eol( fp ); return; case '*': fread_to_eol( fp ); break; case 'm': value = fread_number( fp ); if( !( iMob = get_mob_index( value ) ) ) { bug( "Load_mobprogs: vnum %d doesn't exist.", value ); fread_to_eol( fp ); break; } mprog_file_read( fread_word( fp ), iMob ); fread_to_eol( fp ); break; } return; } void mprog_read_programs( FILE * fp, MOB_INDEX_DATA * pMobIndex ) { MPROG_DATA *mprog; char letter; int type; for( ;; ) { if( ( letter = fread_letter( fp ) ) == '|' ) break; else if( letter != '>' ) { bug( "Load_mobiles: vnum %d MOBPROG char", pMobIndex->vnum ); ungetc( letter, fp ); return; } type = mprog_name_to_type( fread_word( fp ) ); switch ( type ) { case ERROR_PROG: bug( "Load_mobiles: vnum %d MOBPROG type.", pMobIndex->vnum ); fread_to_eol( fp ); return; case IN_FILE_PROG: mprog_file_read( fread_string( fp ), pMobIndex ); fread_to_eol( fp ); break; default: SET_BIT( pMobIndex->progtypes, type ); GET_FREE( mprog, mprog_free ); mprog->type = type; mprog->arglist = fread_string( fp ); fread_to_eol( fp ); mprog->comlist = fread_string( fp ); fread_to_eol( fp ); LINK( mprog, pMobIndex->first_mprog, pMobIndex->last_mprog, next, prev ); break; } } return; } void message_update( void ) { RESET_DATA *pReset; AREA_DATA *pArea; ROOM_INDEX_DATA *pRoom; CHAR_DATA *ch; for( pArea = first_area; pArea != NULL; pArea = pArea->next ) { for( pReset = pArea->first_reset; pReset != NULL; pReset = pReset->next ) { if( pReset->command != 'A' ) continue; if( ( pRoom = get_room_index( pReset->arg1 ) ) == NULL ) { bug( "message_update, no room %d found.", pReset->arg1 ); continue; } for( ch = pRoom->first_person; ch != NULL; ch = ch->next_in_room ) if( ch->level >= pReset->arg2 && ch->level <= pReset->arg3 ) send_to_char( pReset->notes, ch ); } } return; }