/*****************************************************************************
* DikuMUD (C) 1990, 1991 by: *
* Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, *
* and Katja Nyboe. *
*---------------------------------------------------------------------------*
* MERC 2.1 (C) 1992, 1993 by: *
* Michael Chastain, Michael Quan, and Mitchell Tse. *
*---------------------------------------------------------------------------*
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. *
* Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, *
* gorog, Grishnakh, Nivek, Tricops, and Fireblade. *
*---------------------------------------------------------------------------*
* SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. *
* Their contributions are greatly appreciated. *
*---------------------------------------------------------------------------*
* LoP (C) 2006, 2007, 2008 by: the LoP team. *
*---------------------------------------------------------------------------*
* 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>
#if !defined(WIN32)
#include <dlfcn.h>
#else
#include <windows.h>
#define dlopen( libname, flags ) LoadLibrary( (libname) )
#endif
#include "h/mud.h"
#define WEATHER_FILE SYSTEM_DIR "weather.dat"
extern int mccpusers;
void randomize_obj( OBJ_DATA *obj );
void load_class_restrictions( void );
void remove_char_from_group( CHAR_DATA *ch );
void update_skill_helps( void );
void update_command_helps( void );
void code_check( void );
void free_all_friends( CHAR_DATA *ch );
void free_phistory( PER_HISTORY *phistory );
void init_supermob( void );
void load_deity( void );
void load_storages( void );
void load_fnames( void );
void load_timeinfo( 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 );
/* Globals. */
SHOP_DATA *first_shop, *last_shop;
REPAIR_DATA *first_repair, *last_repair;
CHAR_DATA *first_char, *last_char;
GROUP_DATA *first_group, *last_group;
OBJ_DATA *first_object, *last_object;
OBJ_DATA *first_corpse, *last_corpse;
AREA_DATA *first_area, *last_area;
AREA_DATA *first_area_name, *last_area_name; /*Used for alphanum. sort */
AREA_DATA *first_build, *last_build;
AREA_DATA *first_asort, *last_asort;
AREA_DATA *first_bsort, *last_bsort;
OBJ_DATA *extracted_obj_queue;
EXTRACT_CHAR_DATA *extracted_char_queue;
time_t last_restore_all_time = 0;
WEATHER_DATA weather_info;
int weath_unit; /* global weather param */
int rand_factor;
int climate_factor;
int neigh_factor;
int max_vector;
int cur_qchars;
int nummobsloaded;
int numobjsloaded;
int physicalobjects;
int last_pkroom;
bool MOBtrigger;
int area_version;
bool DONT_UPPER;
short gsn_barehanded;
short gsn_pugilism;
short gsn_long_blades;
short gsn_short_blades;
short gsn_flexible_arms;
short gsn_talonous_arms;
short gsn_bludgeons;
short gsn_missile_weapons;
short gsn_detrap;
short gsn_backstab;
short gsn_circle;
short gsn_dodge;
short gsn_duck;
short gsn_block;
short gsn_shieldblock;
short gsn_counter;
short gsn_hide;
short gsn_peek;
short gsn_pick_lock;
short gsn_sneak;
short gsn_steal;
short gsn_gouge;
short gsn_poison_weapon;
short gsn_disarm;
short gsn_enhanced_damage;
short gsn_kick;
short gsn_parry;
short gsn_rescue;
short gsn_punch;
short gsn_bash;
short gsn_stun;
short gsn_bashdoor;
short gsn_grip;
short gsn_berserk;
short gsn_tumble;
short gsn_feed;
short gsn_bloodlet;
short gsn_chop;
short gsn_makefire;
short gsn_aid;
short gsn_track;
short gsn_search;
short gsn_dig;
short gsn_mount;
short gsn_bite;
short gsn_claw;
short gsn_tail;
short gsn_scribe;
short gsn_brew;
short gsn_imbue;
short gsn_concoct;
short gsn_carve;
short gsn_mix;
short gsn_climb;
short gsn_cook;
short gsn_scan;
short gsn_slice;
short gsn_aqua_breath;
short gsn_blindness;
short gsn_charm_person;
short gsn_curse;
short gsn_invis;
short gsn_poison;
short gsn_sleep;
short gsn_lightning_bolt;
short gsn_common;
/* for searching */
short gsn_first_spell;
short gsn_first_skill;
short gsn_first_weapon;
short gsn_first_tongue;
short gsn_top_sn;
/* For styles? Trying to rebuild from some kind of accident here - Blod */
short gsn_style_evasive;
short gsn_style_defensive;
short gsn_style_standard;
short gsn_style_aggressive;
short gsn_style_berserk;
/* 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];
SYSTEM_DATA sysdata;
extern int top_help;
extern int top_command;
extern int top_social;
extern int top_news;
extern int top_bti;
int top_affect;
int top_area;
int top_ed;
int top_exit;
int top_mob_index;
int top_obj_index;
int top_reset;
int top_room;
int num_corpses;
int top_shop;
int top_repair;
/* Semi-locals. */
bool fBootDb;
char strArea[MIL];
FILE *fpArea;
/* Local booting procedures. */
void create_transfer( void );
void load_transfer( void );
void init_mm( void );
void boot_log( const char *str, ... );
void load_area( FILE *fp );
void load_author( AREA_DATA *tarea, FILE *fp );
void load_resetmsg( AREA_DATA *tarea, FILE *fp ); /* Rennard */
void load_flags( AREA_DATA *tarea, FILE *fp );
void load_helps( void );
void load_news( void );
void load_highscores( void );
void load_hints( void );
void load_calendarinfo( void );
void load_mwresets( void );
void load_channels( void );
void load_bti( void );
void load_banks( void );
void load_rewards( void );
void load_ranges( AREA_DATA *tarea, FILE *fp );
void load_climate( AREA_DATA *tarea, FILE *fp ); /* FB */
void load_neighbor( AREA_DATA *tarea, FILE *fp );
void load_buildlist( void );
void load_systemdata( void );
void load_version( AREA_DATA *tarea, FILE *fp );
void load_reserved( void );
void fix_exits( void );
void load_weatherdata( void );
void load_specfuns( void );
/* External booting function */
void load_corpses( void );
void renumber_put_resets( ROOM_INDEX_DATA *room );
void wipe_resets( ROOM_INDEX_DATA *room );
/* Assign gsn's for skills which need them. */
void assign_gsns( void )
{
log_string( "Assigning gsn's" );
ASSIGN_GSN( gsn_style_evasive, "evasive style" );
ASSIGN_GSN( gsn_style_defensive, "defensive style" );
ASSIGN_GSN( gsn_style_standard, "standard style" );
ASSIGN_GSN( gsn_style_aggressive, "aggressive style" );
ASSIGN_GSN( gsn_style_berserk, "berserk style" );
ASSIGN_GSN( gsn_barehanded, "barehanded" );
ASSIGN_GSN( gsn_pugilism, "pugilism" );
ASSIGN_GSN( gsn_long_blades, "long blades" );
ASSIGN_GSN( gsn_short_blades, "short blades" );
ASSIGN_GSN( gsn_flexible_arms, "flexible arms" );
ASSIGN_GSN( gsn_talonous_arms, "talonous arms" );
ASSIGN_GSN( gsn_bludgeons, "bludgeons" );
ASSIGN_GSN( gsn_missile_weapons, "missile weapons" );
ASSIGN_GSN( gsn_detrap, "detrap" );
ASSIGN_GSN( gsn_backstab, "backstab" );
ASSIGN_GSN( gsn_circle, "circle" );
ASSIGN_GSN( gsn_tumble, "tumble" );
ASSIGN_GSN( gsn_dodge, "dodge" );
ASSIGN_GSN( gsn_duck, "duck" );
ASSIGN_GSN( gsn_block, "block" );
ASSIGN_GSN( gsn_shieldblock, "shieldblock" );
ASSIGN_GSN( gsn_counter, "counter" );
ASSIGN_GSN( gsn_hide, "hide" );
ASSIGN_GSN( gsn_peek, "peek" );
ASSIGN_GSN( gsn_pick_lock, "pick lock" );
ASSIGN_GSN( gsn_sneak, "sneak" );
ASSIGN_GSN( gsn_steal, "steal" );
ASSIGN_GSN( gsn_gouge, "gouge" );
ASSIGN_GSN( gsn_poison_weapon, "poison weapon" );
ASSIGN_GSN( gsn_disarm, "disarm" );
ASSIGN_GSN( gsn_enhanced_damage, "enhanced damage" );
ASSIGN_GSN( gsn_kick, "kick" );
ASSIGN_GSN( gsn_parry, "parry" );
ASSIGN_GSN( gsn_rescue, "rescue" );
ASSIGN_GSN( gsn_punch, "punch" );
ASSIGN_GSN( gsn_bash, "bash" );
ASSIGN_GSN( gsn_stun, "stun" );
ASSIGN_GSN( gsn_bashdoor, "doorbash" );
ASSIGN_GSN( gsn_grip, "grip" );
ASSIGN_GSN( gsn_berserk, "berserk" );
ASSIGN_GSN( gsn_feed, "feed" );
ASSIGN_GSN( gsn_bloodlet, "bloodlet" );
ASSIGN_GSN( gsn_chop, "chop" );
ASSIGN_GSN( gsn_makefire, "makefire" );
ASSIGN_GSN( gsn_aid, "aid" );
ASSIGN_GSN( gsn_track, "track" );
ASSIGN_GSN( gsn_search, "search" );
ASSIGN_GSN( gsn_dig, "dig" );
ASSIGN_GSN( gsn_mount, "mount" );
ASSIGN_GSN( gsn_bite, "bite" );
ASSIGN_GSN( gsn_claw, "claw" );
ASSIGN_GSN( gsn_tail, "tail" );
ASSIGN_GSN( gsn_scribe, "scribe" );
ASSIGN_GSN( gsn_brew, "brew" );
ASSIGN_GSN( gsn_imbue, "imbue" );
ASSIGN_GSN( gsn_carve, "carve" );
ASSIGN_GSN( gsn_concoct, "concoct" );
ASSIGN_GSN( gsn_mix, "mix" );
ASSIGN_GSN( gsn_climb, "climb" );
ASSIGN_GSN( gsn_cook, "cook" );
ASSIGN_GSN( gsn_scan, "scan" );
ASSIGN_GSN( gsn_slice, "slice" );
ASSIGN_GSN( gsn_lightning_bolt, "lightning bolt" );
ASSIGN_GSN( gsn_aqua_breath, "aqua breath" );
ASSIGN_GSN( gsn_blindness, "blindness" );
ASSIGN_GSN( gsn_charm_person, "charm person" );
ASSIGN_GSN( gsn_curse, "curse" );
ASSIGN_GSN( gsn_invis, "invis" );
ASSIGN_GSN( gsn_poison, "poison" );
ASSIGN_GSN( gsn_sleep, "sleep" );
ASSIGN_GSN( gsn_common, "common" );
}
void shutdown_mud( const char *reason )
{
FILE *fp;
if( ( fp = fopen( SHUTDOWN_FILE, "a" ) ) )
{
fprintf( fp, "%s\n", reason );
fclose( fp );
fp = NULL;
}
}
/* Big mama top level function. */
void boot_db( bool fCopyOver )
{
fpArea = NULL;
remove_file( BOOTLOG_FILE );
if( !fCopyOver )
fprintf( stderr, ".~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~[ Boot Log ]~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.\n" );
else
fprintf( stderr, ".~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~[ Hotboot Log ]~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.~`~.\n" );
log_string( "Creating transfer data" );
create_transfer( );
log_string( "Loading transfer data" );
load_transfer( );
log_string( "Loading fish name data" );
load_fnames( );
log_string( "Loading channels..." );
load_channels( );
log_string( "Initializing libdl support..." );
/* Open up a handle to the executable's symbol table for later use when working with commands */
if( !( sysdata.dlHandle = dlopen( NULL, RTLD_LAZY ) ) )
{
log_string( "dl: Error opening local system executable as handle, please check compile flags." );
shutdown_mud( "libdl failure" );
exit( 1 );
}
log_string( "Loading Calendar..." );
load_calendarinfo( );
log_string( "Loading helps..." );
load_helps( );
log_string( "Loading news..." );
load_news( );
log_string( "Loading HighScores..." );
load_highscores( );
log_string( "Loading Hints..." );
load_hints( );
log_string( "Loading mud wide resets..." );
load_mwresets( );
log_string( "Loading bugs, typos, and ideas..." );
load_bti( );
log_string( "Loading banks..." );
load_banks( );
log_string( "Loading commands..." );
load_commands( );
log_string( "Loading spec_funs..." );
load_specfuns( );
log_string( "Loading sysdata configuration..." );
load_systemdata( );
log_string( "Loading socials" );
load_socials( );
log_string( "Loading skill table" );
load_skill_table( );
sort_skill_table( );
remap_slot_numbers( ); /* must be after the sort */
assign_gsns( );
update_skill_helps( ); /* Update skill helps */
update_command_helps( ); /* Update command helps */
log_string( "Loading classes" );
load_classes( );
log_string( "Loading class restrictions" );
load_class_restrictions( );
log_string( "Loading races" );
load_races( );
log_string( "Loading herb table" );
load_herb_table( );
log_string( "Loading personal table" );
load_pers_table( );
log_string( "Loading tongues" );
load_tongues( );
log_string( "Making wizlist" );
make_wizlist( );
fBootDb = true;
top_shop = 0;
top_repair = 0;
nummobsloaded = 0;
numobjsloaded = 0;
physicalobjects = 0;
sysdata.maxplayers = 0;
num_corpses = 0;
first_object = last_object = NULL;
first_corpse = last_corpse = NULL;
first_char = last_char = NULL;
first_group = last_group = NULL;
first_area = last_area = NULL;
first_area_name = last_area_name = NULL; /* Used for alphanum. sort */
first_build = last_build = NULL;
first_shop = last_shop = NULL;
first_repair = last_repair = NULL;
first_asort = last_asort = NULL;
extracted_obj_queue = NULL;
extracted_char_queue = NULL;
cur_qchars = 0;
cur_char = NULL;
cur_obj = 0;
cur_char_died = false;
cur_obj_extracted = false;
quitting_char = NULL;
loading_char = NULL;
saving_char = NULL;
last_pkroom = 1;
first_ban_class = last_ban_class = NULL;
first_ban_race = last_ban_race = NULL;
first_ban = last_ban = NULL;
weath_unit = 10;
rand_factor = 2;
climate_factor = 1;
neigh_factor = 3;
max_vector = weath_unit * 3;
/* Init random number generator. */
log_string( "Initializing random number generator" );
init_mm( );
/* Load time_info */
log_string( "Loading time_info" );
load_timeinfo( );
/* Read in all the area files. */
{
FILE *fp;
log_string( "Reading in area files..." );
if( !( fp = fopen( AREA_LIST, "r" ) ) )
{
perror( AREA_LIST );
shutdown_mud( "Unable to open area list" );
exit( 1 );
}
for( ;; )
{
mudstrlcpy( strArea, fread_word( fp ), sizeof( strArea ) );
if( strArea[0] == '$' )
break;
load_area_file( last_area, strArea );
}
fclose( fp );
fp = NULL;
}
log_string( "Loading buildlist" );
load_buildlist( );
/* initialize supermob. must be done before reset_area! */
init_supermob( );
/*
* Fix up exits.
* Declare db booting over.
* Reset all areas once.
* Load up the notes file.
*/
log_string( "Fixing exits" );
fix_exits( );
fBootDb = false;
log_string( "Resetting areas" );
area_update( );
log_string( "Loading boards" );
load_boards( );
load_clans( );
load_councils( );
load_deity( );
log_string( "Loading bans" );
load_banlist( );
log_string( "Loading rewards" );
load_rewards( );
log_string( "Loading reserved names" );
load_reserved( );
log_string( "Loading corpses" );
load_corpses( );
/* Morphs MUST be loaded after class and race tables are set up --Shaddai */
log_string( "Loading Morphs" );
load_morphs( );
log_string( "Loading storages" );
load_storages( );
MOBtrigger = true;
/* Initialize area weather data */
load_weatherdata( );
init_area_weather( );
/* Go ahead and check to make sure some things are right and give bugs if not */
code_check( );
}
/* Load an 'area' header line. */
void load_area( FILE *fp )
{
AREA_DATA *pArea;
CREATE( pArea, AREA_DATA, 1 );
pArea->first_room = pArea->last_room = NULL;
pArea->name = fread_string( fp );
pArea->author = STRALLOC( "unknown" );
pArea->filename = STRALLOC( strArea );
pArea->age = 15;
pArea->nplayer = 0;
pArea->low_vnum = 0;
pArea->hi_vnum = 0;
pArea->low_soft_range = 0;
pArea->hi_soft_range = MAX_LEVEL;
pArea->low_hard_range = 0;
pArea->hi_hard_range = MAX_LEVEL;
/* initialize weather data - FB */
CREATE( pArea->weather, WEATHER_DATA, 1 );
pArea->weather->temp = 0;
pArea->weather->precip = 0;
pArea->weather->wind = 0;
pArea->weather->temp_vector = 0;
pArea->weather->precip_vector = 0;
pArea->weather->wind_vector = 0;
pArea->weather->climate_temp = 2;
pArea->weather->climate_precip = 2;
pArea->weather->climate_wind = 2;
pArea->weather->first_neighbor = NULL;
pArea->weather->last_neighbor = NULL;
pArea->weather->echo = NULL;
pArea->weather->echo_color = AT_GRAY;
area_version = 0;
LINK( pArea, first_area, last_area, next, prev );
top_area++;
}
/*
* 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 )
{
area_version = fread_number( fp );
}
/* Load an author section. Scryn 2/1/96 */
void load_author( AREA_DATA *tarea, FILE *fp )
{
STRFREE( tarea->author );
tarea->author = fread_string( fp );
}
/* Reset Message Load, Rennard */
void load_resetmsg( AREA_DATA *tarea, FILE *fp )
{
STRFREE( tarea->resetmsg );
tarea->resetmsg = fread_string( fp );
}
void load_flags( AREA_DATA *tarea, FILE *fp )
{
char *infoflags;
char flag[MSL];
int value;
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_flag( flag, area_flags, AFLAG_MAX );
if( value < 0 || value >= AFLAG_MAX )
bug( "%s: invalid area flag (%s)", __FUNCTION__, flag );
else
xSET_BIT( tarea->flags, value );
}
}
/* Add a character to the list of all characters - Thoric */
void add_char( CHAR_DATA *ch )
{
LINK( ch, first_char, last_char, next, prev );
if( ch->pIndexData )
LINK( ch, ch->pIndexData->first_copy, ch->pIndexData->last_copy, next_index, prev_index );
}
/* load a mob section. */
void load_mobiles( AREA_DATA *tarea, FILE *fp )
{
MOB_INDEX_DATA *pMobIndex = NULL;
const char *word;
char *infoflags = NULL, flag[MIL];
bool oldmob = false, tmpBootDb, fMatch;
int vnum = 0, iHash, value;
for( ;; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = false;
if( word[0] == EOF )
{
bug( "%s: feof didn't detect EOF but fread_word returned EOF...ending now!", __FUNCTION__ );
word = "End";
}
switch( UPPER( word[0] ) )
{
case '*':
fMatch = true;
fread_to_eol( fp );
break;
case '>':
if( !strcmp( word, ">" ) )
{
ungetc( '>', fp );
mprog_read_programs( fp, pMobIndex );
fMatch = true;
break;
}
break;
case '#':
if( !strcmp( word, "#0" ) )
return;
break;
case 'A':
WEXTKEY( "Absorb", pMobIndex->absorb, fp, ris_flags, RIS_MAX );
KEY( "Alignment", pMobIndex->alignment, fread_number( fp ) );
KEY( "Armor", pMobIndex->ac, fread_number( fp ) );
WEXTKEY( "Attacks", pMobIndex->attacks, fp, attack_flags, ATCK_MAX );
WEXTKEY( "Affected", pMobIndex->affected_by, fp, a_flags, AFF_MAX );
break;
case 'D':
KEY( "DamRoll", pMobIndex->damroll, fread_number( fp ) );
KEY( "Description", pMobIndex->description, fread_string( fp ) );
WEXTKEY( "Defenses", pMobIndex->defenses, fp, defense_flags, DFND_MAX );
SKEY( "DefPosition", pMobIndex->defposition, fp, pos_names, POS_MAX );
break;
case 'E':
if( !strcmp( word, "End" ) )
{
if( pMobIndex->ac < 0 )
pMobIndex->ac = -pMobIndex->ac;
/* Make sure its set to NPC if it isn't already */
if( !xIS_SET( pMobIndex->act, ACT_IS_NPC ) )
xSET_BIT( pMobIndex->act, ACT_IS_NPC );
pMobIndex->position = pMobIndex->defposition;
if( !oldmob )
{
iHash = vnum % MAX_KEY_HASH;
pMobIndex->next = mob_index_hash[iHash];
mob_index_hash[iHash] = pMobIndex;
top_mob_index++;
}
fMatch = true;
break;
}
break;
case 'F':
WEXTKEY( "Flags", pMobIndex->act, fp, act_flags, ACT_MAX );
break;
case 'G':
KEY( "Gold", pMobIndex->gold, fread_number( fp ) );
break;
case 'H':
KEY( "HitRoll", pMobIndex->hitroll, fread_number( fp ) );
KEY( "Height", pMobIndex->height, fread_number( fp ) );
if( !strcmp( word, "Hit" ) )
{
pMobIndex->minhit = fread_number( fp );
pMobIndex->maxhit = fread_number( fp );
fMatch = true;
break;
}
break;
case 'I':
WEXTKEY( "Immune", pMobIndex->immune, fp, ris_flags, RIS_MAX );
break;
case 'L':
KEY( "Level", pMobIndex->level, fread_number( fp ) );
KEY( "Long", pMobIndex->long_descr, fread_string( fp ) );
break;
case 'M':
KEY( "MGold", pMobIndex->mgold, fread_number( fp ) );
break;
case 'N':
KEY( "NumAttacks", pMobIndex->numattacks, fread_number( fp ) );
KEY( "Name", pMobIndex->name, fread_string( fp ) );
if( !strcmp( word, "NRepair" ) )
{
REPAIR_DATA *rShop;
int tmpvalue;
char *srepair,sarg[MSL];
CREATE( rShop, REPAIR_DATA, 1 );
for( tmpvalue = 0; tmpvalue < ITEM_TYPE_MAX; tmpvalue++ )
rShop->fix_type[tmpvalue] = false;
rShop->keeper = pMobIndex->vnum;
rShop->profit_fix = fread_number( fp );
rShop->open_hour = fread_number( fp );
rShop->close_hour = fread_number( fp );
srepair = fread_flagstring( fp );
while( srepair && srepair[0] != '\0' )
{
srepair = one_argument( srepair, sarg );
tmpvalue = get_flag( sarg, o_types, ITEM_TYPE_MAX );
if( tmpvalue > 0 || tmpvalue < ITEM_TYPE_MAX )
rShop->fix_type[tmpvalue] = true;
}
pMobIndex->rShop = rShop;
LINK( rShop, first_repair, last_repair, next, prev );
top_repair++;
fMatch = true;
break;
}
if( !strcmp( word, "NShop" ) )
{
SHOP_DATA *pShop;
int tmpvalue;
char *stype, sarg[MSL];
CREATE( pShop, SHOP_DATA, 1 );
for( tmpvalue = 0; tmpvalue < ITEM_TYPE_MAX; tmpvalue++ )
pShop->buy_type[tmpvalue] = false;
pShop->keeper = pMobIndex->vnum;
pShop->profit_buy = fread_number( fp );
pShop->profit_sell = fread_number( fp );
pShop->open_hour = fread_number( fp );
pShop->close_hour = fread_number( fp );
stype = fread_flagstring( fp );
while( stype && stype[0] != '\0' )
{
stype = one_argument( stype, sarg );
tmpvalue = get_flag( sarg, o_types, ITEM_TYPE_MAX );
if( tmpvalue > 0 || tmpvalue < ITEM_TYPE_MAX )
pShop->buy_type[tmpvalue] = true;
}
pShop->profit_buy = URANGE( pShop->profit_sell + 5, pShop->profit_buy, 1000 );
pShop->profit_sell = URANGE( 0, pShop->profit_sell, pShop->profit_buy - 5 );
pMobIndex->pShop = pShop;
LINK( pShop, first_shop, last_shop, next, prev );
top_shop++;
fMatch = true;
break;
}
break;
case 'P':
WEXTKEY( "Parts", pMobIndex->xflags, fp, part_flags, PART_MAX );
SKEY( "Position", pMobIndex->position, fp, pos_names, POS_MAX );
break;
case 'R':
if( !strcmp( word, "Repair" ) )
{
REPAIR_DATA *rShop;
int tmpvalue;
CREATE( rShop, REPAIR_DATA, 1 );
for( tmpvalue = 0; tmpvalue < ITEM_TYPE_MAX; tmpvalue++ )
rShop->fix_type[tmpvalue] = false;
for( tmpvalue = 0; tmpvalue < 3; tmpvalue++ )
{
rShop->fix_type[fread_number( fp )] = true;
}
rShop->keeper = pMobIndex->vnum;
rShop->profit_fix = fread_number( fp );
fread_number( fp );
rShop->open_hour = fread_number( fp );
rShop->close_hour = fread_number( fp );
pMobIndex->rShop = rShop;
LINK( rShop, first_repair, last_repair, next, prev );
top_repair++;
fMatch = true;
break;
}
WEXTKEY( "Resistant", pMobIndex->resistant, fp, ris_flags, RIS_MAX );
break;
case 'S':
WEXTKEY( "Susceptible", pMobIndex->susceptible, fp, ris_flags, RIS_MAX );
SKEY( "Sex", pMobIndex->sex, fp, sex_names, SEX_MAX );
KEY( "Short", pMobIndex->short_descr, fread_string( fp ) );
if( !strcmp( word, "Special" ) )
{
infoflags = fread_word( fp );
if( !( pMobIndex->spec_fun = spec_lookup( infoflags ) ) )
{
bug( "%s: 'M': vnum %d.", __FUNCTION__, pMobIndex->vnum );
pMobIndex->spec_funname = NULL;
}
else
pMobIndex->spec_funname = STRALLOC( infoflags );
fMatch = true;
break;
}
if( !strcmp( word, "Shop" ) )
{
int tmpvalue;
SHOP_DATA *pShop;
CREATE( pShop, SHOP_DATA, 1 );
for( tmpvalue = 0; tmpvalue < ITEM_TYPE_MAX; tmpvalue++ )
pShop->buy_type[tmpvalue] = false;
for( tmpvalue = 0; tmpvalue < 5; tmpvalue++ )
pShop->buy_type[fread_number( fp )] = true;
pShop->keeper = pMobIndex->vnum;
pShop->profit_buy = fread_number( fp );
pShop->profit_sell = fread_number( fp );
pShop->open_hour = fread_number( fp );
pShop->close_hour = 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 );
pMobIndex->pShop = pShop;
LINK( pShop, first_shop, last_shop, next, prev );
top_shop++;
fMatch = true;
break;
}
if( !strcmp( word, "Saves" ) )
{
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 );
fMatch = true;
break;
}
WEXTKEY( "Speaks", pMobIndex->speaks, fp, lang_names, LANG_UNKNOWN );
WEXTKEY( "Speaking", pMobIndex->speaking, fp, lang_names, LANG_UNKNOWN );
if( !strcmp( word, "Stats" ) )
{
int stat;
for( stat = 0; stat < STAT_MAX; stat++ )
pMobIndex->perm_stats[stat] = fread_number( fp );
fMatch = true;
break;
}
break;
case 'V':
if( !strcmp( word, "Vnum" ) )
{
vnum = fread_number( fp );
tmpBootDb = fBootDb;
fBootDb = false;
if( get_mob_index( vnum ) )
{
if( tmpBootDb )
{
bug( "Load_mobiles: vnum %d duplicated.", vnum );
shutdown_mud( "duplicate vnum" );
exit( 1 );
}
else
{
pMobIndex = get_mob_index( vnum );
log_printf_plus( LOG_BUILD, sysdata.perm_log, "Cleaning mobile: %d", vnum );
clean_mob( pMobIndex );
oldmob = true;
}
}
else
{
oldmob = false;
CREATE( pMobIndex, MOB_INDEX_DATA, 1 );
pMobIndex->pShop = NULL;
pMobIndex->rShop = NULL;
}
pMobIndex->vnum = vnum;
fBootDb = tmpBootDb;
if( fBootDb )
{
if( !tarea->low_vnum )
tarea->low_vnum = vnum;
if( vnum > tarea->hi_vnum )
tarea->hi_vnum = vnum;
}
fMatch = true;
break;
}
break;
case 'W':
KEY( "Weight", pMobIndex->weight, fread_number( fp ) );
break;
}
if( !fMatch )
{
bug( "%s: no match: %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
bug( "%s: #0 not found?", __FUNCTION__ );
}
/* Load an obj section. */
void load_objects( AREA_DATA *tarea, FILE *fp )
{
OBJ_INDEX_DATA *pObjIndex = NULL;
int vnum = 0, iHash, value, stat;
bool tmpBootDb, oldobj = false, fMatch;
char *infoflags = NULL;
const char *word;
char flag[MIL];
for( ;; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = false;
if( word[0] == EOF )
{
bug( "%s: feof didn't detect EOF but fread_word returned EOF...ending now!", __FUNCTION__ );
word = "End";
}
switch( UPPER( word[0] ) )
{
case '*':
fMatch = true;
fread_to_eol( fp );
break;
case '#':
if( !strcmp( word, "#0" ) )
return;
break;
case '>':
if( !strcmp( word, ">" ) )
{
ungetc( '>', fp );
oprog_read_programs( fp, pObjIndex );
fMatch = true;
break;
}
break;
case 'A':
if( !strcmp( word, "Affect" ) )
{
AFFECT_DATA *paf;
bool dadd = false;
CREATE( paf, AFFECT_DATA, 1 );
paf->type = -1;
paf->duration = -1;
infoflags = fread_word( fp );
if( str_cmp( infoflags, "0" ) )
{
/* Change blood to mana */
if( !str_cmp( infoflags, "Blood" ) )
infoflags = (char *)"Mana";
value = get_flag( infoflags, a_types, APPLY_MAX );
if( value < 0 || value >= APPLY_MAX )
{
bug( "%s: Unknown apply %s", __FUNCTION__, infoflags );
paf->location = 0;
dadd = true;
}
else
paf->location = value;
}
else
paf->location = 0;
infoflags = fread_word( fp );
if( paf->location == APPLY_RESISTANT || paf->location == APPLY_IMMUNE || paf->location == APPLY_SUSCEPTIBLE || paf->location == APPLY_ABSORB )
{
value = get_flag( infoflags, ris_flags, RIS_MAX );
if( value < 0 || value >= RIS_MAX )
{
bug( "%s: Unknown resistant/immune/susceptible/absorb %s", __FUNCTION__, infoflags );
paf->modifier = -1;
dadd = true;
}
else
paf->modifier = value;
}
else if( paf->location == APPLY_EXT_AFFECT )
{
value = get_flag( infoflags, a_flags, AFF_MAX );
if( value < 0 || value >= AFF_MAX )
{
bug( "%s: Unknown affected %s", __FUNCTION__, infoflags );
paf->modifier = -1;
dadd = true;
}
else
paf->modifier = value;
}
else if( paf->location == APPLY_WEAPONSPELL || paf->location == APPLY_WEARSPELL
|| paf->location == APPLY_REMOVESPELL || paf->location == APPLY_STRIPSN )
paf->modifier = slot_lookup( atoi( infoflags ) );
else
paf->modifier = atoi( infoflags );
xCLEAR_BITS( paf->bitvector );
if( !dadd )
{
LINK( paf, pObjIndex->first_affect, pObjIndex->last_affect, next, prev );
top_affect++;
}
else
{
bug( "%s: Something is bad in affect and it won't be added.", __FUNCTION__ );
DISPOSE( paf );
}
fMatch = true;
break;
}
KEY( "Action", pObjIndex->action_desc, fread_string( fp ) );
break;
case 'C':
KEY( "Cost", pObjIndex->cost, fread_number( fp ) );
if( !str_cmp( word, "Classes" ) )
{
int iclass;
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
for( iclass = 0; iclass < MAX_PC_CLASS; iclass++ )
{
if( !class_table[iclass] || !class_table[iclass]->name )
continue;
if( !str_cmp( class_table[iclass]->name, flag ) )
{
xSET_BIT( pObjIndex->class_restrict, iclass );
break;
}
}
}
fMatch = true;
break;
}
break;
case 'D':
KEY( "Description", pObjIndex->description, fread_string( fp ) );
break;
case 'E':
if( !strcmp( word, "End" ) )
{
if( !oldobj )
{
iHash = vnum % MAX_KEY_HASH;
pObjIndex->next = obj_index_hash[iHash];
obj_index_hash[iHash] = pObjIndex;
top_obj_index++;
}
fMatch = true;
break;
}
if( !strcmp( word, "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 );
top_ed++;
fMatch = true;
break;
}
break;
case 'F':
WEXTKEY( "Flags", pObjIndex->extra_flags, fp, o_flags, ITEM_MAX );
break;
case 'L':
KEY( "Level", pObjIndex->level, fread_number( fp ) );
KEY( "Layers", pObjIndex->layers, fread_number( fp ) );
break;
case 'N':
KEY( "Name", pObjIndex->name, fread_string( fp ) );
if( !strcmp( word, "NAffect" ) )
{
AFFECT_DATA *paf;
bool dadd = false;
CREATE( paf, AFFECT_DATA, 1 );
paf->type = -1;
paf->duration = -1;
infoflags = fread_word( fp );
if( str_cmp( infoflags, "0" ) )
{
/* Change blood to mana */
if( !str_cmp( infoflags, "Blood" ) )
infoflags = (char *)"Mana";
value = get_flag( infoflags, a_types, APPLY_MAX );
if( value < 0 || value >= APPLY_MAX )
{
bug( "%s: Unknown apply %s", __FUNCTION__, infoflags );
paf->location = 0;
dadd = true;
}
else
paf->location = value;
}
else
paf->location = 0;
infoflags = fread_word( fp );
if( paf->location == APPLY_RESISTANT || paf->location == APPLY_IMMUNE || paf->location == APPLY_SUSCEPTIBLE || paf->location == APPLY_ABSORB )
{
value = get_flag( infoflags, ris_flags, RIS_MAX );
if( value < 0 || value >= RIS_MAX )
{
bug( "%s: Unknown resistant/immune/susceptible/absorb %s", __FUNCTION__, infoflags );
paf->modifier = -1;
dadd = true;
}
else
paf->modifier = value;
}
else if( paf->location == APPLY_EXT_AFFECT )
{
value = get_flag( infoflags, a_flags, AFF_MAX );
if( value < 0 || value >= AFF_MAX )
{
bug( "%s: Unknown affected %s", __FUNCTION__, infoflags );
paf->modifier = -1;
dadd = true;
}
else
paf->modifier = value;
}
else if( paf->location == APPLY_WEAPONSPELL || paf->location == APPLY_WEARSPELL
|| paf->location == APPLY_REMOVESPELL || paf->location == APPLY_STRIPSN )
paf->modifier = slot_lookup( atoi( infoflags ) );
else
paf->modifier = atoi( infoflags );
xCLEAR_BITS( paf->bitvector );
infoflags = fread_word( fp );
if( str_cmp( infoflags, "-1" ) && paf->location == APPLY_STAT )
{
value = get_flag( infoflags, stattypes, STAT_MAX );
if( value < 0 || value >= STAT_MAX )
{
bug( "%s: Unknown stat %s", __FUNCTION__, infoflags );
dadd = true;
}
else
xSET_BIT( paf->bitvector, value );
}
if( !dadd )
{
LINK( paf, pObjIndex->first_affect, pObjIndex->last_affect, next, prev );
top_affect++;
}
else
{
bug( "%s: Something is bad in affect and it won't be added.", __FUNCTION__ );
DISPOSE( paf );
}
fMatch = true;
break;
}
break;
case 'R':
if( !str_cmp( word, "Races" ) )
{
int irace;
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
for( irace = 0; irace < MAX_PC_RACE; irace++ )
{
if( !race_table[irace] || !race_table[irace]->name )
continue;
if( !str_cmp( race_table[irace]->name, flag ) )
{
xSET_BIT( pObjIndex->race_restrict, irace );
break;
}
}
}
fMatch = true;
break;
}
break;
case 'S':
KEY( "Short", pObjIndex->short_descr, fread_string( fp ) );
if( !strcmp( word, "Stats" ) )
{
for( stat = 0; stat < STAT_MAX; stat++ )
pObjIndex->stat_reqs[stat] = fread_number( fp );
fMatch = true;
break;
}
break;
case 'T':
SKEY( "Type", pObjIndex->item_type, fp, o_types, ITEM_TYPE_MAX );
break;
case 'V':
if( !strcmp( word, "Val0" ) )
{
pObjIndex->value[0] = fread_number( fp );
fMatch = true;
break;
}
if( !strcmp( word, "Val1" ) )
{
pObjIndex->value[1] = fread_number( fp );
if( pObjIndex->item_type == ITEM_PILL || pObjIndex->item_type == ITEM_POTION
|| pObjIndex->item_type == ITEM_SCROLL )
pObjIndex->value[1] = skill_lookup( fread_word( fp ) );
fMatch = true;
break;
}
if( !strcmp( word, "Val2" ) )
{
pObjIndex->value[2] = fread_number( fp );
if( pObjIndex->item_type == ITEM_PILL || pObjIndex->item_type == ITEM_POTION
|| pObjIndex->item_type == ITEM_SCROLL )
pObjIndex->value[2] = skill_lookup( fread_word( fp ) );
fMatch = true;
break;
}
if( !strcmp( word, "Val3" ) )
{
pObjIndex->value[3] = fread_number( fp );
if( pObjIndex->item_type == ITEM_PILL || pObjIndex->item_type == ITEM_POTION
|| pObjIndex->item_type == ITEM_SCROLL || pObjIndex->item_type == ITEM_STAFF
|| pObjIndex->item_type == ITEM_WAND || pObjIndex->item_type == ITEM_SALVE )
pObjIndex->value[3] = skill_lookup( fread_word( fp ) );
fMatch = true;
break;
}
if( !strcmp( word, "Val4" ) )
{
pObjIndex->value[4] = fread_number( fp );
if( pObjIndex->item_type == ITEM_SALVE )
pObjIndex->value[4] = skill_lookup( fread_word( fp ) );
fMatch = true;
break;
}
if( !strcmp( word, "Val5" ) )
{
pObjIndex->value[5] = fread_number( fp );
if( pObjIndex->item_type == ITEM_SALVE )
pObjIndex->value[5] = skill_lookup( fread_word( fp ) );
fMatch = true;
break;
}
if( !strcmp( word, "Vnum" ) )
{
vnum = fread_number( fp );
tmpBootDb = fBootDb;
fBootDb = false;
if( get_obj_index( vnum ) )
{
if( tmpBootDb )
{
bug( "%s: vnum %d duplicated.", __FUNCTION__, vnum );
shutdown_mud( "duplicate vnum" );
exit( 1 );
}
else
{
pObjIndex = get_obj_index( vnum );
log_printf_plus( LOG_BUILD, sysdata.perm_log, "Cleaning object: %d", vnum );
clean_obj( pObjIndex );
oldobj = true;
}
}
else
{
oldobj = false;
pObjIndex = new_object( vnum );
}
fBootDb = tmpBootDb;
pObjIndex->vnum = vnum;
if( fBootDb )
{
if( !tarea->low_vnum )
tarea->low_vnum = vnum;
if( vnum > tarea->hi_vnum )
tarea->hi_vnum = vnum;
}
fMatch = true;
break;
}
break;
case 'W':
KEY( "Weight", pObjIndex->weight, fread_number( fp ) );
WEXTKEY( "Wear", pObjIndex->wear_flags, fp, w_flags, ITEM_WEAR_MAX );
break;
}
if( !fMatch )
{
bug( "%s: no match: %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
bug( "%s: #0 not found?", __FUNCTION__ );
}
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 );
if( fBootDb )
boot_log( "%s: %s (%d) bad command '%c'.", __FUNCTION__, room->area->filename, count, letter );
return;
case 'M':
if( !get_mob_index( arg1 ) && fBootDb )
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 ) && fBootDb )
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 ) && fBootDb )
boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter,
arg1 );
if( arg3 <= 0 )
arg3 = OBJ_VNUM_MONEY_ONE; /* This may look stupid, but for some reason it works. */
if( !get_obj_index( arg3 ) && fBootDb )
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 ) && fBootDb )
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 ) )
|| !xIS_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 );
if( fBootDb )
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 );
if( fBootDb )
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 );
if( fBootDb )
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, 100 );
if( !not01 )
renumber_put_resets( room );
}
void load_new_room_reset( ROOM_INDEX_DATA *room, FILE *fp )
{
EXIT_DATA *pexit;
char letter;
int extra, arg1, arg2, arg3;
bool not01 = false;
int count = 0;
short rchance = 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 );
rchance = fread_number( fp );
rchance = URANGE( 1, rchance, 100 );
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 );
if( fBootDb )
boot_log( "%s: %s (%d) bad command '%c'.", __FUNCTION__, room->area->filename, count, letter );
return;
case 'M':
if( !get_mob_index( arg1 ) && fBootDb )
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 ) && fBootDb )
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 ) && fBootDb )
boot_log( "%s: %s (%d) '%c': object %d doesn't exist.", __FUNCTION__, room->area->filename, count, letter,
arg1 );
if( arg3 <= 0 )
arg3 = OBJ_VNUM_MONEY_ONE; /* This may look stupid, but for some reason it works. */
if( !get_obj_index( arg3 ) && fBootDb )
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 ) && fBootDb )
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 ) )
|| !xIS_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 );
if( fBootDb )
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 );
if( fBootDb )
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 );
if( fBootDb )
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, rchance );
if( !not01 )
renumber_put_resets( room );
}
/* Load a room section. */
void load_rooms( AREA_DATA *tarea, FILE *fp )
{
ROOM_INDEX_DATA *pRoomIndex = NULL;
const char *word;
int vnum = 0, door, iHash;
bool tmpBootDb, oldroom = false, fMatch;
char *infoflags = NULL;
char flag[MIL];
int value;
tarea->first_room = tarea->last_room = NULL;
for( ;; )
{
word = feof( fp ) ? "End" : fread_word( fp );
fMatch = false;
if( word[0] == EOF )
{
bug( "%s: feof didn't detect EOF but fread_word returned EOF...ending now!", __FUNCTION__ );
word = "End";
}
switch( UPPER( word[0] ) )
{
case '*':
fMatch = true;
fread_to_eol( fp );
break;
case '#':
if( !strcmp( word, "#0" ) )
return;
break;
case '>':
if( !strcmp( word, ">" ) )
{
ungetc( '>', fp );
rprog_read_programs( fp, pRoomIndex );
fMatch = true;
break;
}
break;
case 'D':
KEY( "Description", pRoomIndex->description, fread_string( fp ) );
if( !strcmp( word, "Door" ) )
{
EXIT_DATA *pexit;
const char *check;
bool fcheck, finished = false;
door = fread_number( fp );
if( door < 0 || door > 10 )
{
bug( "%s: vnum %d has bad door number %d.", __FUNCTION__, vnum, door );
if( fBootDb )
exit( 1 );
}
else
{
pexit = make_exit( pRoomIndex, NULL, door );
pexit->key = -1;
for( ;; )
{
check = feof( fp ) ? "End" : fread_word( fp );
fcheck = false;
if( check[0] == EOF )
{
bug( "%s: feof didn't detect EOF but fread_word returned EOF...ending now!", __FUNCTION__ );
check = "End";
}
switch( UPPER( check[0] ) )
{
case '*':
fcheck = true;
fread_to_eol( fp );
break;
case '#':
if( !strcmp( check, "#0" ) )
return;
break;
case 'D':
if( !strcmp( check, "Description" ) )
{
pexit->description = fread_string( fp );
fcheck = true;
break;
}
break;
case 'E':
if( !strcmp( check, "End" ) )
{
finished = true;
fcheck = true;
break;
}
break;
case 'F':
if( !strcmp( check, "Flags" ) )
{
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_flag( flag, ex_flags, EX_MAX );
if( value < 0 || value >= EX_MAX )
bug( "%s: Unknown exit_info: %s", __FUNCTION__, flag );
else
xSET_BIT( pexit->exit_info, value );
}
fcheck = true;
break;
}
break;
case 'K':
if( !strcmp( check, "Key" ) )
{
pexit->key = fread_number( fp );
fcheck = true;
break;
}
if( !strcmp( check, "Keyword" ) )
{
pexit->keyword = fread_string( fp );
fcheck = true;
break;
}
break;
case 'P':
if( !strcmp( check, "Pulltype" ) )
{
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_pulltype( flag );
if( value == -1 )
bug( "%s: Unknown pulltype: %s", __FUNCTION__, flag );
else
pexit->pulltype = value;
}
fcheck = true;
break;
}
if( !strcmp( check, "Pull" ) )
{
pexit->pull = fread_number( fp );
fcheck = true;
break;
}
break;
case 'T':
if( !strcmp( check, "To" ) )
{
pexit->vnum = fread_number( fp );
fcheck = true;
break;
}
break;
}
if( finished )
break;
if( !fcheck )
{
bug( "%s: %s: Unknown word %s", __FUNCTION__, word, check );
fread_to_eol( fp );
}
}
}
fMatch = true;
break;
}
break;
case 'E':
if( !strcmp( word, "Exit" ) )
{
EXIT_DATA *pexit;
const char *check;
bool fcheck, finished = false;
infoflags = fread_word( fp );
door = get_dir( infoflags );
if( door < 0 || door > 10 )
{
bug( "%s: vnum %d has bad door number %d(%s).", __FUNCTION__, vnum, door, infoflags );
if( fBootDb )
exit( 1 );
}
else
{
pexit = make_exit( pRoomIndex, NULL, door );
pexit->key = -1;
for( ;; )
{
check = feof( fp ) ? "End" : fread_word( fp );
fcheck = false;
if( check[0] == EOF )
{
bug( "%s: feof didn't detect EOF but fread_word returned EOF...ending now!", __FUNCTION__ );
check = "End";
}
switch( UPPER( check[0] ) )
{
case '*':
fcheck = true;
fread_to_eol( fp );
break;
case '#':
if( !strcmp( check, "#0" ) )
return;
break;
case 'D':
if( !strcmp( check, "Description" ) )
{
pexit->description = fread_string( fp );
fcheck = true;
break;
}
break;
case 'E':
if( !strcmp( check, "End" ) )
{
finished = true;
fcheck = true;
break;
}
break;
case 'F':
if( !strcmp( check, "Flags" ) )
{
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_flag( flag, ex_flags, EX_MAX );
if( value < 0 || value >= EX_MAX )
bug( "%s: Unknown exit_info: %s", __FUNCTION__, flag );
else
xSET_BIT( pexit->exit_info, value );
}
fcheck = true;
break;
}
break;
case 'K':
if( !strcmp( check, "Key" ) )
{
pexit->key = fread_number( fp );
fcheck = true;
break;
}
if( !strcmp( check, "Keyword" ) )
{
pexit->keyword = fread_string( fp );
fcheck = true;
break;
}
break;
case 'P':
if( !strcmp( check, "Pulltype" ) )
{
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_pulltype( flag );
if( value == -1 )
bug( "%s: Unknown pulltype: %s", __FUNCTION__, flag );
else
pexit->pulltype = value;
}
fcheck = true;
break;
}
if( !strcmp( check, "Pull" ) )
{
pexit->pull = fread_number( fp );
fcheck = true;
break;
}
break;
case 'T':
if( !strcmp( check, "To" ) )
{
pexit->vnum = fread_number( fp );
fcheck = true;
break;
}
break;
}
if( finished )
break;
if( !fcheck )
{
bug( "%s: %s: Unknown word %s", __FUNCTION__, word, check );
fread_to_eol( fp );
}
}
}
fMatch = true;
break;
}
if( !strcmp( word, "End" ) )
{
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 );
top_room++;
}
fMatch = true;
break;
}
if( !strcmp( word, "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 );
top_ed++;
fMatch = true;
break;
}
break;
case 'F':
if( !strcmp( word, "Flags" ) )
{
infoflags = fread_flagstring( fp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_flag( flag, r_flags, ROOM_MAX );
if( value < 0 || value >= ROOM_MAX )
bug( "%s: Unknown flag: %s", __FUNCTION__, flag );
else
xSET_BIT( pRoomIndex->room_flags, value );
}
fMatch = true;
break;
}
break;
case 'N':
KEY( "Name", pRoomIndex->name, fread_string( fp ) );
if( !strcmp( word, "NR" ) )
{
load_new_room_reset( pRoomIndex, fp );
fMatch = true;
break;
}
break;
case 'R':
if( !strcmp( word, "R" ) )
{
load_room_reset( pRoomIndex, fp );
fMatch = true;
break;
}
break;
case 'S':
SKEY( "Sector", pRoomIndex->sector_type, fp, sect_flags, SECT_MAX );
break;
case 'T':
KEY( "Teledelay", pRoomIndex->tele_delay, fread_number( fp ) );
KEY( "Televnum", pRoomIndex->tele_vnum, fread_number( fp ) );
KEY( "Tunnel", pRoomIndex->tunnel, fread_number( fp ) );
break;
case 'V':
if( !strcmp( word, "Vnum" ) )
{
vnum = fread_number( fp );
tmpBootDb = fBootDb;
fBootDb = false;
if( get_room_index( vnum ) )
{
if( tmpBootDb )
{
bug( "%s: vnum %d duplicated.", __FUNCTION__, vnum );
shutdown_mud( "duplicate vnum" );
exit( 1 );
}
else
{
pRoomIndex = get_room_index( vnum );
log_printf_plus( LOG_BUILD, sysdata.perm_log, "Cleaning room: %d", vnum );
clean_room( pRoomIndex );
oldroom = true;
}
}
else
{
oldroom = false;
pRoomIndex = new_room( vnum );
pRoomIndex->area = tarea;
fBootDb = tmpBootDb;
if( fBootDb )
{
if( !tarea->low_vnum )
tarea->low_vnum = vnum;
if( vnum > tarea->hi_vnum )
tarea->hi_vnum = vnum;
}
}
pRoomIndex->light = 0;
pRoomIndex->first_exit = pRoomIndex->last_exit = NULL;
pRoomIndex->sector_type = SECT_INSIDE;
fMatch = true;
break;
}
break;
}
if( !fMatch )
{
bug( "%s: no match: %s", __FUNCTION__, word );
fread_to_eol( fp );
}
}
bug( "%s: #0 not found?", __FUNCTION__ );
}
/* Load soft / hard area ranges. */
void load_ranges( AREA_DATA *tarea, FILE *fp )
{
int x1, x2, x3, x4;
char *ln;
ln = fread_line( fp );
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;
}
/* Load climate information for the area - Fireblade */
void load_climate( AREA_DATA *tarea, FILE *fp )
{
tarea->weather->climate_temp = fread_number( fp );
tarea->weather->climate_precip = fread_number( fp );
tarea->weather->climate_wind = fread_number( fp );
}
/* Load data for a neghboring weather system - Fireblade */
void load_neighbor( AREA_DATA *tarea, FILE *fp )
{
NEIGHBOR_DATA *tnew;
CREATE( tnew, NEIGHBOR_DATA, 1 );
tnew->next = NULL;
tnew->prev = NULL;
tnew->address = NULL;
tnew->name = fread_string( fp );
LINK( tnew, tarea->weather->first_neighbor, tarea->weather->last_neighbor, next, prev );
}
/*
* 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 )
{
ROOM_INDEX_DATA *pRoomIndex;
EXIT_DATA *pexit, *pexit_next, *r_exit;
int iHash;
for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
{
for( pRoomIndex = room_index_hash[iHash]; pRoomIndex; pRoomIndex = pRoomIndex->next )
{
bool fexit = false;
for( pexit = pRoomIndex->first_exit; pexit; pexit = pexit_next )
{
pexit_next = pexit->next;
pexit->rvnum = pRoomIndex->vnum;
if( pexit->vnum <= 0 || !( pexit->to_room = get_room_index( pexit->vnum ) ) )
{
if( fBootDb )
boot_log( "Fix_exits: room %d, exit %s leads to bad vnum (%d)",
pRoomIndex->vnum, dir_name[pexit->vdir], pexit->vnum );
bug( "Deleting %s exit in room %d", dir_name[pexit->vdir], pRoomIndex->vnum );
extract_exit( pRoomIndex, pexit );
}
else
fexit = true;
}
}
}
/* Set all the rexit pointers - Thoric */
for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ )
{
for( pRoomIndex = room_index_hash[iHash]; pRoomIndex; pRoomIndex = pRoomIndex->next )
{
for( pexit = pRoomIndex->first_exit; pexit; pexit = pexit->next )
{
if( pexit->to_room && !pexit->rexit )
{
r_exit = get_exit_to( pexit->to_room, rev_dir[pexit->vdir], pRoomIndex->vnum );
if( r_exit )
{
pexit->rexit = r_exit;
r_exit->rexit = pexit;
}
}
}
}
}
return;
}
/*
* (prelude...) This is going to be fun... NOT!
* (conclusion) QSort is f*cked!
*/
int exit_comp( EXIT_DATA **xit1, EXIT_DATA **xit2 )
{
int d1, d2;
d1 = ( *xit1 )->vdir;
d2 = ( *xit2 )->vdir;
if( d1 < d2 )
return -1;
if( d1 > d2 )
return 1;
return 0;
}
void sort_exits( ROOM_INDEX_DATA *room )
{
EXIT_DATA *pexit;
EXIT_DATA *exits[MAX_REXITS];
int x, nexits;
nexits = 0;
for( pexit = room->first_exit; pexit; pexit = pexit->next )
{
exits[nexits++] = pexit;
if( nexits > MAX_REXITS )
{
bug( "%s: more than %d exits in room... fatal", __FUNCTION__, nexits );
return;
}
}
qsort( &exits[0], nexits, sizeof( EXIT_DATA *), ( int ( * )( const void *, const void * ) )exit_comp );
for( x = 0; x < nexits; x++ )
{
if( x > 0 )
exits[x]->prev = exits[x - 1];
else
{
exits[x]->prev = NULL;
room->first_exit = exits[x];
}
if( x >= ( nexits - 1 ) )
{
exits[x]->next = NULL;
room->last_exit = exits[x];
}
else
exits[x]->next = exits[x + 1];
}
}
void randomize_exits( ROOM_INDEX_DATA *room, short maxdir )
{
EXIT_DATA *pexit;
int nexits, d0, d1, count, door;
int vdirs[MAX_REXITS];
nexits = 0;
for( pexit = room->first_exit; pexit; pexit = pexit->next )
vdirs[nexits++] = pexit->vdir;
for( d0 = 0; d0 < nexits; d0++ )
{
if( vdirs[d0] > maxdir )
continue;
count = 0;
while( vdirs[( d1 = number_range( d0, nexits - 1 ) )] > maxdir || ++count > 5 );
if( vdirs[d1] > maxdir )
continue;
door = vdirs[d0];
vdirs[d0] = vdirs[d1];
vdirs[d1] = door;
}
count = 0;
for( pexit = room->first_exit; pexit; pexit = pexit->next )
pexit->vdir = vdirs[count++];
sort_exits( room );
}
/* Repopulate areas periodically. */
void area_update( void )
{
AREA_DATA *pArea;
for( pArea = first_area; pArea; pArea = pArea->next )
{
CHAR_DATA *pch;
int reset_age = pArea->reset_frequency ? pArea->reset_frequency : 15;
if( ( reset_age == -1 && pArea->age == -1 ) || ++pArea->age < ( reset_age - 1 ) )
continue;
/* Check for PC's. */
if( pArea->nplayer > 0 && pArea->age == ( reset_age - 1 ) )
{
char buf[MSL];
/* Rennard */
if( pArea->resetmsg )
snprintf( buf, sizeof( buf ), "%s\r\n", pArea->resetmsg );
else
mudstrlcpy( buf, "You hear some squeaking sounds...\r\n", sizeof( buf ) );
for( pch = first_char; pch; pch = pch->next )
{
if( !is_npc( pch ) && is_awake( pch ) && pch->in_room && pch->in_room->area == pArea )
{
set_char_color( AT_RESET, pch );
send_to_char( buf, pch );
}
}
}
/* Check age and reset. */
if( pArea->nplayer == 0 || pArea->age >= reset_age )
{
reset_area( pArea );
if( reset_age == -1 )
pArea->age = -1;
else
pArea->age = number_range( 0, reset_age / 5 );
}
}
}
/* Create an instance of a mobile. */
CHAR_DATA *create_mobile( MOB_INDEX_DATA *pMobIndex )
{
CHAR_DATA *mob;
int stat;
if( !pMobIndex )
{
bug( "%s: NULL pMobIndex.", __FUNCTION__ );
exit( 1 );
}
CREATE( mob, CHAR_DATA, 1 );
if( !mob )
{
bug( "%s: mob is still NULL after CREATE.", __FUNCTION__ );
return NULL;
}
clear_char( mob );
mob->pIndexData = pMobIndex;
mob->name = QUICKLINK( pMobIndex->name );
mob->short_descr = QUICKLINK( pMobIndex->short_descr );
mob->long_descr = QUICKLINK( pMobIndex->long_descr );
mob->description = QUICKLINK( pMobIndex->description );
mob->spec_fun = pMobIndex->spec_fun;
mob->spec_funname = QUICKLINK( pMobIndex->spec_funname );
mob->mpscriptpos = 0;
mob->level = number_range( pMobIndex->level - 1, pMobIndex->level + 1 );
mob->level = URANGE( 1, mob->level, MAX_LEVEL );
mob->act = pMobIndex->act;
mob->resetvnum = -1;
mob->resetnum = -1;
if( xIS_SET( mob->act, ACT_MOBINVIS ) )
mob->mobinvis = mob->level;
mob->affected_by = pMobIndex->affected_by;
mob->alignment = pMobIndex->alignment;
mob->sex = pMobIndex->sex;
if( pMobIndex->ac )
mob->armor = pMobIndex->ac;
else
mob->armor = interpolate( mob->level, 100, -100 );
mob->max_hit = UMAX( 1, number_range( pMobIndex->minhit, pMobIndex->maxhit ) );
mob->hit = mob->max_hit;
mob->gold = pMobIndex->gold;
mob->mgold = pMobIndex->mgold;
mob->position = pMobIndex->position;
mob->defposition = pMobIndex->defposition;
for( stat = 0; stat < STAT_MAX; stat++ )
mob->perm_stats[stat] = pMobIndex->perm_stats[stat];
mob->hitroll = pMobIndex->hitroll;
mob->damroll = pMobIndex->damroll;
mob->xflags = pMobIndex->xflags;
mob->saving_poison_death = pMobIndex->saving_poison_death;
mob->saving_wand = pMobIndex->saving_wand;
mob->saving_para_petri = pMobIndex->saving_para_petri;
mob->saving_breath = pMobIndex->saving_breath;
mob->saving_spell_staff = pMobIndex->saving_spell_staff;
mob->height = pMobIndex->height;
mob->weight = pMobIndex->weight;
mob->resistant = pMobIndex->resistant;
mob->immune = pMobIndex->immune;
mob->absorb = pMobIndex->absorb;
mob->susceptible = pMobIndex->susceptible;
mob->attacks = pMobIndex->attacks;
mob->defenses = pMobIndex->defenses;
mob->numattacks = pMobIndex->numattacks;
mob->speaks = pMobIndex->speaks;
mob->speaking = pMobIndex->speaking;
add_char( mob );
pMobIndex->count++;
nummobsloaded++;
return mob;
}
/* Create an instance of an object. */
OBJ_DATA *create_object( OBJ_INDEX_DATA *pObjIndex, int level )
{
OBJ_DATA *obj;
if( !pObjIndex )
{
bug( "%s: NULL pObjIndex. EXITING THE MUD...", __FUNCTION__ );
exit( 1 );
}
CREATE( obj, OBJ_DATA, 1 );
if( !obj )
{
bug( "%s: obj is still NULL after CREATE.", __FUNCTION__ );
return NULL;
}
obj->pIndexData = pObjIndex;
obj->in_room = NULL;
obj->level = level;
obj->wear_loc = -1;
obj->t_wear_loc = -1;
obj->count = 1;
obj->bsplatter = 0; /* Clean */
obj->bstain = 0; /* Clean */
obj->name = QUICKLINK( pObjIndex->name );
obj->short_descr = QUICKLINK( pObjIndex->short_descr );
obj->description = QUICKLINK( pObjIndex->description );
obj->action_desc = QUICKLINK( pObjIndex->action_desc );
obj->owner = NULL;
obj->item_type = pObjIndex->item_type;
obj->extra_flags = pObjIndex->extra_flags;
obj->wear_flags = pObjIndex->wear_flags;
obj->value[0] = pObjIndex->value[0];
obj->value[1] = pObjIndex->value[1];
obj->value[2] = pObjIndex->value[2];
obj->value[3] = pObjIndex->value[3];
obj->value[4] = pObjIndex->value[4];
obj->value[5] = pObjIndex->value[5];
obj->weight = pObjIndex->weight;
obj->cost = pObjIndex->cost;
/* Mess with object properties. */
switch( obj->item_type )
{
default:
break;
case ITEM_COOK:
case ITEM_FOOD:
case ITEM_FISH:
obj->timer = obj->value[1];
break;
case ITEM_MONEY:
obj->value[0] = UMAX( 1, obj->cost );
break;
}
LINK( obj, first_object, last_object, next, prev );
if( obj->pIndexData->vnum == OBJ_VNUM_CORPSE_PC )
{
LINK( obj, first_corpse, last_corpse, next_corpse, prev_corpse );
++num_corpses;
}
LINK( obj, pObjIndex->first_copy, pObjIndex->last_copy, next_index, prev_index );
++pObjIndex->count;
++numobjsloaded;
++physicalobjects;
randomize_obj( obj );
return obj;
}
/* Clear a new character. */
void clear_char( CHAR_DATA *ch )
{
int stat;
ch->editor = NULL;
ch->hunting = NULL;
ch->fearing = NULL;
ch->hating = NULL;
ch->name = NULL;
ch->short_descr = NULL;
ch->long_descr = NULL;
ch->description = NULL;
ch->next = ch->prev = NULL;
ch->reply = NULL;
ch->retell = NULL;
ch->first_carrying = ch->last_carrying = NULL;
ch->next_in_room = ch->prev_in_room = NULL;
ch->next_in_group = ch->prev_in_group = NULL;
ch->group = NULL;
ch->fighting = NULL;
ch->first_affect = ch->last_affect = NULL;
ch->first_host = ch->last_host = NULL;
ch->prev_cmd = ch->last_cmd = NULL;
ch->dest_buf = NULL;
ch->alloc_ptr = NULL;
ch->spare_ptr = NULL;
ch->mount = NULL;
ch->mounter = NULL;
ch->morph = NULL;
ch->was_in_room = NULL;
xCLEAR_BITS( ch->act );
xCLEAR_BITS( ch->affected_by );
xCLEAR_BITS( ch->no_affected_by );
xCLEAR_BITS( ch->resistant );
xCLEAR_BITS( ch->no_resistant );
xCLEAR_BITS( ch->susceptible );
xCLEAR_BITS( ch->no_susceptible );
xCLEAR_BITS( ch->immune );
xCLEAR_BITS( ch->no_immune );
xCLEAR_BITS( ch->absorb );
xCLEAR_BITS( ch->no_absorb );
xCLEAR_BITS( ch->xflags );
xCLEAR_BITS( ch->speaking );
xSET_BIT( ch->speaking, LANG_COMMON );
xCLEAR_BITS( ch->speaks );
xSET_BIT( ch->speaks, LANG_COMMON );
ch->logon = current_time;
ch->bsplatter = 0;
ch->armor = 0;
ch->position = POS_STANDING;
ch->mobinvis = 0;
ch->practice = 0;
ch->hit = 20;
ch->max_hit = 20;
ch->mana = 100;
ch->max_mana = 100;
ch->move = 100;
ch->max_move = 100;
ch->height = 72;
ch->weight = 180;
ch->race = 0;
ch->substate = 0;
ch->tempnum = 0;
ch->mental_state = -10;
ch->saving_poison_death = 0;
ch->saving_wand = 0;
ch->saving_para_petri = 0;
ch->saving_breath = 0;
ch->saving_spell_staff = 0;
ch->style = STYLE_FIGHTING;
for( stat = 0; stat < STAT_MAX; stat++ )
{
ch->perm_stats[stat] = 13;
ch->mod_stats[stat] = 0;
}
}
/* Free a character. */
void free_char( CHAR_DATA *ch )
{
CHAR_DATA *pet, *pet_next;
OBJ_DATA *obj;
AFFECT_DATA *paf;
TIMER *timer;
MPROG_ACT_LIST *mpact, *mpact_next;
HOST_DATA *host, *host_next;
EXP_DATA *fexp, *nexp;
if( !ch )
{
bug( "%s: null ch!", __FUNCTION__ );
return;
}
if( ch->desc )
bug( "%s: char still has descriptor.", __FUNCTION__ );
if( ch->morph )
DISPOSE( ch->morph );
if( ch->group )
remove_char_from_group( ch );
while( ( obj = ch->last_carrying ) )
extract_obj( obj );
while( ( paf = ch->last_affect ) )
affect_remove( ch, paf );
while( ( timer = ch->first_timer ) )
extract_timer( ch, timer );
if( ch->editor )
stop_editing( ch );
for( host = ch->first_host; host; host = host_next )
{
host_next = host->next;
STRFREE( host->host );
UNLINK( host, ch->first_host, ch->last_host, next, prev );
DISPOSE( host );
}
STRFREE( ch->name );
STRFREE( ch->short_descr );
STRFREE( ch->long_descr );
STRFREE( ch->description );
STRFREE( ch->spec_funname );
stop_hunting( ch );
stop_hating( ch );
stop_fearing( ch );
free_fight( ch );
if( ch->pnote )
free_note( ch->pnote );
if( ch->pcdata )
{
MCLASS_DATA *mclass, *mnext;
IGNORE_DATA *temp, *next;
for( pet = ch->pcdata->first_pet; pet; pet = pet_next )
{
pet_next = pet->next_pet;
UNLINK( pet, ch->pcdata->first_pet, ch->pcdata->last_pet, next_pet, prev_pet );
extract_char( pet, true );
}
for( mclass = ch->pcdata->first_mclass; mclass; mclass = mnext )
{
mnext = mclass->next;
UNLINK( mclass, ch->pcdata->first_mclass, ch->pcdata->last_mclass, next, prev );
DISPOSE( mclass );
}
for( fexp = ch->pcdata->first_explored; fexp; fexp = nexp )
{
nexp = fexp->next;
UNLINK( fexp, ch->pcdata->first_explored, ch->pcdata->last_explored, next, prev );
DISPOSE( fexp );
}
free_all_friends( ch );
if( ch->pcdata->gnote )
free_note( ch->pcdata->gnote );
/* free up memory allocated to stored ignored names */
for( temp = ch->pcdata->first_ignored; temp; temp = next )
{
next = temp->next;
UNLINK( temp, ch->pcdata->first_ignored, ch->pcdata->last_ignored, next, prev );
STRFREE( temp->name );
DISPOSE( temp );
}
STRFREE( ch->pcdata->channels );
STRFREE( ch->pcdata->spouse );
STRFREE( ch->pcdata->filename );
STRFREE( ch->pcdata->pwd );
STRFREE( ch->pcdata->bamfin );
STRFREE( ch->pcdata->bamfout );
STRFREE( ch->pcdata->rank );
STRFREE( ch->pcdata->title );
STRFREE( ch->pcdata->bio );
STRFREE( ch->pcdata->bestowments );
STRFREE( ch->pcdata->homepage );
STRFREE( ch->pcdata->email );
STRFREE( ch->pcdata->msn );
STRFREE( ch->pcdata->yahoo );
STRFREE( ch->pcdata->gtalk );
STRFREE( ch->pcdata->authed_by );
STRFREE( ch->pcdata->prompt );
STRFREE( ch->pcdata->fprompt );
STRFREE( ch->pcdata->subprompt );
while( ch->pcdata->last_tell )
{
PER_HISTORY *phistory;
phistory = ch->pcdata->last_tell;
UNLINK( phistory, ch->pcdata->first_tell, ch->pcdata->last_tell, next, prev );
free_phistory( phistory );
}
while( ch->pcdata->last_say )
{
PER_HISTORY *phistory;
phistory = ch->pcdata->last_say;
UNLINK( phistory, ch->pcdata->first_say, ch->pcdata->last_say, next, prev );
free_phistory( phistory );
}
while( ch->pcdata->last_yell )
{
PER_HISTORY *phistory;
phistory = ch->pcdata->last_yell;
UNLINK( phistory, ch->pcdata->first_yell, ch->pcdata->last_yell, next, prev );
free_phistory( phistory );
}
while( ch->pcdata->last_whisper )
{
PER_HISTORY *phistory;
phistory = ch->pcdata->last_whisper;
UNLINK( phistory, ch->pcdata->first_whisper, ch->pcdata->last_whisper, next, prev );
free_phistory( phistory );
}
#ifdef IMC
imc_freechardata( ch );
#endif
UNLINK( ch->pcdata, first_pc, last_pc, next, prev );
ch->pcdata->character = NULL;
DISPOSE( ch->pcdata );
}
for( mpact = ch->mpact; mpact; mpact = mpact_next )
{
mpact_next = mpact->next;
STRFREE( mpact->buf );
DISPOSE( mpact );
}
DISPOSE( ch );
}
/* Get an extra description from a list. */
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;
if( fBootDb )
bug( "%s: bad vnum %d.", __FUNCTION__, vnum );
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;
if( fBootDb )
bug( "%s: bad vnum %d.", __FUNCTION__, vnum );
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;
if( fBootDb )
bug( "%s: bad vnum %d.", __FUNCTION__, vnum );
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 aren't loaded
* upon bootup.
* -- Altrag
*/
/* Read a letter from a file. */
char fread_letter( FILE *fp )
{
char c;
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
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( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
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( "%s: bad format. (%c)", __FUNCTION__, c );
if( fBootDb )
exit( 1 );
return 0;
}
while( isdigit( c ) )
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
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;
}
unsigned int fread_un_number( FILE *fp )
{
unsigned int number;
char c;
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
return 0;
}
c = getc( fp );
}
while( isspace( c ) );
number = 0;
if( !isdigit( c ) )
{
bug( "%s: bad format. (%c)", __FUNCTION__, c );
if( fBootDb )
exit( 1 );
return 0;
}
while( isdigit( c ) )
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
return number;
}
number = number * 10 + c - '0';
c = getc( fp );
}
if( c != ' ' )
ungetc( c, fp );
return number;
}
/* Read a time from a file. */
time_t fread_time( FILE *fp )
{
time_t number;
bool sign;
char c;
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
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( "%s: bad format. (%c)", __FUNCTION__, c );
if( fBootDb )
exit( 1 );
return 0;
}
while( isdigit( c ) )
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
return number;
}
number = number * 10 + c - '0';
c = getc( fp );
}
if( sign )
number = ( 0 - number );
if( c == '|' )
number += fread_time( fp );
else if( c != ' ' )
ungetc( c, fp );
return number;
}
/* Read a double from a file. */
double fread_double( FILE *fp )
{
double number;
bool sign;
char c;
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
return 0;
}
c = getc( fp );
}
while( isspace( c ) );
number = 0.0;
sign = false;
if( c == '+' )
{
c = getc( fp );
}
else if( c == '-' )
{
sign = true;
c = getc( fp );
}
if( !isdigit( c ) )
{
bug( "%s: bad format. (%c)", __FUNCTION__, c );
if( fBootDb )
exit( 1 );
return 0;
}
while( isdigit( c ) )
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
return number;
}
number = number * 10 + c - '0';
c = getc( fp );
}
if( sign )
number = 0 - number;
if( c == '|' )
number += fread_double( 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, MSL );
return ret;
}
/* Read a string from file and return it */
char *fread_flagstring( FILE *fp )
{
static char flagstring[MSL];
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__ );
if( fBootDb )
exit( 1 );
return (char *)"";
}
c = getc( fp );
}
while( isspace( c ) );
if( ( *plast++ = c ) == '~' )
return (char *)"";
for( ;; )
{
if( ln >= ( MSL - 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__ );
if( fBootDb )
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 */
char *fread_string( FILE *fp )
{
char buf[MSL];
mudstrlcpy( buf, fread_flagstring( fp ), MSL );
if( buf == NULL || buf[0] == '\0' )
return NULL;
return STRALLOC( buf );
}
/* Read to end of line (for comments). */
void fread_to_eol( FILE *fp )
{
char c;
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
return;
}
c = getc( fp );
}
while( c != '\r' && c != '\n' );
do
{
c = getc( fp );
}
while( c == '\r' || c == '\n' );
ungetc( c, fp );
return;
}
/* Read to end of line into static buffer - Thoric */
char *fread_line( FILE *fp )
{
static char line[MSL];
char *pline;
char c;
int ln;
pline = line;
line[0] = '\0';
ln = 0;
/* Skip blanks. Read first char. */
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
mudstrlcpy( line, "", sizeof( line ) );
return line;
}
c = getc( fp );
}
while( isspace( c ) );
ungetc( c, fp );
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
*pline = '\0';
return line;
}
c = getc( fp );
*pline++ = c;
ln++;
if( ln >= ( MSL - 1 ) )
{
bug( "%s: line too long", __FUNCTION__ );
break;
}
}
while( c != '\r' && c != '\n' );
do
{
c = getc( fp );
}
while( c == '\r' || c == '\n' );
ungetc( c, fp );
*pline = '\0';
return line;
}
/* Read one word (into static buffer). */
char *fread_word( FILE *fp )
{
static char word[MIL];
char *pword;
char cEnd;
do
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
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 + MIL; pword++ )
{
if( feof( fp ) )
{
bug( "%s: EOF encountered on read.", __FUNCTION__ );
if( fBootDb )
exit( 1 );
*pword = '\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;
}
CMDF( do_memory )
{
char arg[MIL];
#ifdef HASHSTR
int hash;
#endif
set_char_color( AT_PLAIN, ch );
argument = one_argument( argument, arg );
send_to_char( "\r\n&wSystem Memory [arguments - hash, check, showhigh]\r\n", ch );
ch_printf( ch, "&wObjAffects: &W%5d &wAreas: &W%5d\r\n", top_affect, top_area );
ch_printf( ch, "&wExtDes: &W%5d &wExits: &W%5d\r\n", top_ed, top_exit );
ch_printf( ch, "&wHelps: &W%5d &wResets: &W%5d\r\n", top_help, top_reset );
ch_printf( ch, "&wCommands: &W%5d &wSocials: &W%5d\r\n", top_command, top_social );
ch_printf( ch, "&wIdxMobs: &W%5d &wMobiles: &W%5d\r\n", top_mob_index, nummobsloaded );
ch_printf( ch, "&wIdxObjs: &W%5d &wObjs: &W%5d(%d)\r\n", top_obj_index, numobjsloaded, physicalobjects );
ch_printf( ch, "&wCorpses: &W%5d\r\n", num_corpses );
ch_printf( ch, "&wRooms: &W%5d &wNews: &W%5d\r\n", top_room, top_news );
ch_printf( ch, "&wBTI: &W%5d &wCurCq's &W%5d\r\n", top_bti, cur_qchars );
ch_printf( ch, "&wShops: &W%5d &wRepShps: &W%5d\r\n", top_shop, top_repair );
ch_printf( ch, "&wPlayers: &W%5d &wTopSn: &W%5d(%d)\r\n", num_descriptors, top_sn, MAX_SKILL );
ch_printf( ch, "&wUsing MCCP: &W%5d\r\n", mccpusers );
ch_printf( ch, "&wMaxplrs: &W%5d &wRaces: &W%5d(%d)\r\n", sysdata.maxplayers, MAX_PC_RACE, MAX_RACE );
ch_printf( ch, "&wMaxEver: &W%5d &wClasses: &W%5d(%d)\r\n", sysdata.alltimemax, MAX_PC_CLASS, MAX_CLASS );
ch_printf( ch, "&wMaxEver was recorded &W%s\r\n", distime( sysdata.time_of_max ) );
if( arg == NULL || arg[0] == '\0' )
return;
#ifndef HASHSTR
send_to_char( "Hash strings not enabled.\r\n", ch );
#else
if( !str_cmp( arg, "check" ) )
{
if( !argument || argument[0] == '\0' )
{
send_to_char( "Usage: memory check <string to check for>\r\n", ch );
return;
}
send_to_char( check_hash( argument ), ch );
return;
}
if( !str_cmp( arg, "showhigh" ) )
{
show_high_hash( atoi( argument ) );
send_to_char( "You will have to look in the current log file to see the hash info you wanted.\r\n", ch );
return;
}
if( argument[0] != '\0' )
hash = atoi( argument );
else
hash = -1;
if( !str_cmp( arg, "hash" ) )
{
ch_printf( ch, "Hash statistics:\r\n%s", hash_stats( ) );
if( hash != -1 )
hash_dump( hash );
}
#endif
}
/*
* 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 );
}
/*
* Generate a percentile roll.
* number_mm() % 100 only does 0-99, changed to do 1-100 -Shaddai
*/
int number_percent( void )
{
return ( number_mm( ) % 100 ) + 1;
}
/* Generate a random door. */
int number_door( void )
{
int door;
while( ( door = number_mm( ) & ( 16 - 1 ) ) > 9 )
;
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( void )
{
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 );
}
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. - Thoric */
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;
}
/*
* 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 = '-';
}
}
/*
* Encodes the tildes in a string. -Thoric
* Used for player-entered strings that go into disk files.
*/
void hide_tilde( char *str )
{
for( ; *str != '\0'; str++ )
{
if( *str == '~' )
*str = HIDDEN_TILDE;
}
}
char *show_tilde( const char *str )
{
static char buf[MSL];
char *bufptr;
bufptr = buf;
for( ; *str != '\0'; str++, bufptr++ )
{
if( *str == HIDDEN_TILDE )
*bufptr = '~';
else
*bufptr = *str;
}
*bufptr = '\0';
return buf;
}
/*
* Compare strings, case insensitive.
* Return true if different
* (compatibility with historical functions).
*/
bool str_cmp( const char *astr, const char *bstr )
{
/* If both empty they match I think */
if( !astr && !bstr )
return false;
/* If just one or the other is NULL they dont match */
if( !astr || !bstr )
return true;
/* Check the strings to see if they don't match */
for( ; *astr || *bstr; astr++, bstr++ )
{
if( LOWER( *astr ) != LOWER( *bstr ) )
return true;
}
/* If you get here then they matched */
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 both empty they match I think */
if( !astr && !bstr )
return false;
/* If just one or the other is NULL they dont match */
if( !astr || !bstr )
return true;
for( ; *astr; astr++, bstr++ )
{
if( LOWER( *astr ) != LOWER( *bstr ) )
return true;
}
/* If you get here then they matched */
return false;
}
/*
* Compare strings, case insensitive, for match anywhere.
* Returns true is astr not part of bstr.
* (compatibility with historical functions).
*/
bool str_infix( const char *astr, const char *bstr )
{
int sstr1, sstr2, ichar;
char c0;
if( ( c0 = LOWER( astr[0] ) ) == '\0' )
return false;
sstr1 = strlen( astr );
sstr2 = strlen( bstr );
for( ichar = 0; ichar <= sstr2 - sstr1; ichar++ )
if( c0 == LOWER( bstr[ichar] ) && !str_prefix( astr, bstr + ichar ) )
return false;
return true;
}
/*
* Compare strings, case insensitive, for suffix matching.
* Return true if astr not a suffix of bstr
* (compatibility with historical functions).
*/
bool str_suffix( const char *astr, const char *bstr )
{
int sstr1, sstr2;
sstr1 = strlen( astr );
sstr2 = strlen( bstr );
if( sstr1 <= sstr2 && !str_cmp( astr, bstr + sstr2 - sstr1 ) )
return false;
else
return true;
}
/*
* Returns an initial-capped string.
* Rewritten by FearItself@AvP
*/
char *capitalize( const char *str )
{
static char buf[MAX_STRING_LENGTH];
char *dest = buf;
enum { Normal, Color } state = Normal;
bool bFirst = true;
char c;
while( (c = *str++) )
{
if( state == Normal )
{
if( c == '&' || c == '^' || c == '}' )
{
state = Color;
}
else if( isalpha(c) )
{
c = bFirst ? toupper(c) : tolower(c);
bFirst = false;
}
}
else
{
state = Normal;
}
*dest++ = c;
}
*dest = c;
return buf;
}
/* Returns a lowercase string. */
char *strlower( const char *str )
{
static char strlow[MSL];
int i;
for( i = 0; str[i] != '\0'; i++ )
strlow[i] = LOWER( str[i] );
strlow[i] = '\0';
return strlow;
}
/* Returns an uppercase string. */
char *strupper( const char *str )
{
static char strup[MSL];
int i;
strup[0] = '\0';
for( i = 0; str[i] != '\0'; i++ )
strup[i] = UPPER( str[i] );
strup[i] = '\0';
return strup;
}
/* 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;
}
/* Shove either "a " or "an " onto the beginning of a string - Thoric */
char *aoran( const char *str )
{
static char temp[MSL];
if( !str )
{
bug( "%s: NULL str", __FUNCTION__ );
return (char *)"";
}
if( isavowel( str[0] ) || ( strlen( str ) > 1 && LOWER( str[0] ) == 'y' && !isavowel( str[1] ) ) )
mudstrlcpy( temp, "an ", sizeof( temp ) );
else
mudstrlcpy( temp, "a ", sizeof( temp ) );
mudstrlcat( temp, str, sizeof( temp ) );
return temp;
}
/* Append a string to a file. */
void append_file( CHAR_DATA *ch, const char *file, const char *str )
{
FILE *fp;
struct tm *t = localtime( ¤t_time );
if( ( ch && is_npc( ch ) ) || str[0] == '\0' )
return;
if( !( fp = fopen( file, "a" ) ) )
{
perror( file );
send_to_char( "Could not open the file!\r\n", ch );
}
else
{
fprintf( fp, "[%5d] [%2.2d:%2.2d:%2.2d %2.2d/%2.2d/%4.4d] %s: %s\n", ( ch && ch->in_room ) ? ch->in_room->vnum : 0,
t->tm_hour, t->tm_min, t->tm_sec, ( t->tm_mon + 1 ), t->tm_mday, ( t->tm_year + 1900 ),
( ch && ch->name ) ? ch->name : "(Unknown)", str );
fclose( fp );
fp = NULL;
}
}
/* Append a string to a file. */
void append_to_file( const char *file, const char *str )
{
FILE *fp;
if( !( fp = fopen( file, "a" ) ) )
perror( file );
else
{
fprintf( fp, "%s\n", str );
fclose( fp );
fp = NULL;
}
}
/* Reports a bug. */
void bug( const char *str, ... )
{
char buf[MSL];
FILE *fp;
int letter;
struct stat fst;
mudstrlcpy( buf, "[*****] BUG: ", sizeof( buf ) );
{
va_list param;
va_start( param, str );
vsnprintf( buf + strlen( buf ), ( sizeof( buf ) - strlen( buf ) ), str, param );
va_end( param );
}
log_string_plus( buf, LOG_BUG, PERM_IMM );
if( fpArea )
{
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( ( letter = getc( fpArea ) ) && letter != EOF && letter != '\n' )
;
}
fseek( fpArea, iChar, 0 );
}
log_printf_plus( LOG_BUG, PERM_IMM, "[*****] FILE: %s LINE: %d", strArea, iLine );
if( stat( SHUTDOWN_FILE, &fst ) != -1 ) /* file exists */
{
if( ( fp = fopen( SHUTDOWN_FILE, "a" ) ) )
{
fprintf( fp, "[*****] <FILE: %s LINE: %d> %s\n", strArea, iLine, buf );
fclose( fp );
fp = NULL;
}
}
}
}
/* Add a string to the boot-up log - Thoric */
void boot_log( const char *str, ... )
{
char buf[MSL];
FILE *fp;
va_list param;
mudstrlcpy( buf, "[*****] BOOT: ", sizeof( buf ) );
va_start( param, str );
vsnprintf( buf + strlen( buf ), ( sizeof( buf ) - strlen( buf ) ), str, param );
va_end( param );
log_string( buf );
if( ( fp = fopen( BOOTLOG_FILE, "a" ) ) )
{
fprintf( fp, "%s\n", buf );
fclose( fp );
fp = NULL;
}
}
/* Dump a text file to a player, a line at a time - Thoric */
void show_file( CHAR_DATA *ch, const char *filename )
{
FILE *fp;
char buf[MSL];
int c;
int num = 0;
if( ( fp = fopen( filename, "r" ) ) )
{
while( !feof( fp ) )
{
while( ( buf[num] = fgetc( fp ) ) != EOF
&& buf[num] != '\r' && buf[num] != '\n' && num < ( MSL - 2 ) )
num++;
c = fgetc( fp );
if( ( c != '\r' && c != '\n' ) || c == buf[num] )
ungetc( c, fp );
buf[num++] = '\r';
buf[num++] = '\n';
buf[num] = '\0';
send_to_pager( buf, ch );
num = 0;
}
/* Thanks to stu <sprice@ihug.co.nz> from the mailing list in pointing This out. */
fclose( fp );
fp = NULL;
}
}
/* Show the boot log file - Thoric */
CMDF( do_dmesg )
{
set_pager_color( AT_LOG, ch );
send_to_pager( "Boot Log Messages:\r\n", ch );
show_file( ch, BOOTLOG_FILE );
}
/* wizlist builder! - Thoric */
void towizfile( const char *line )
{
int filler, xx;
char outline[MSL];
FILE *fp;
outline[0] = '\0';
if( line && line[0] != '\0' )
{
filler = ( 78 - color_strlen( line ) );
if( filler < 1 )
filler = 1;
filler /= 2;
for( xx = 0; xx < filler; xx++ )
mudstrlcat( outline, " ", sizeof( outline ) );
mudstrlcat( outline, line, sizeof( outline ) );
}
mudstrlcat( outline, "\r\n", sizeof( outline ) );
if( ( fp = fopen( WIZLIST_FILE, "a" ) ) )
{
fputs( outline, fp );
fclose( fp );
fp = NULL;
}
}
typedef struct wizent WIZENT;
/* Structure used to build wizlist */
struct wizent
{
WIZENT *next, *last;
char *name;
int level;
short sex;
};
WIZENT *first_wiz, *last_wiz;
void add_to_wizlist( char *name, int level, short sex )
{
WIZENT *wiz, *tmp;
CREATE( wiz, WIZENT, 1 );
wiz->name = STRALLOC( name );
wiz->level = level;
wiz->sex = sex;
if( !first_wiz )
{
wiz->last = NULL;
wiz->next = NULL;
first_wiz = wiz;
last_wiz = wiz;
return;
}
/* insert sort, of sorts */
for( tmp = first_wiz; tmp; tmp = tmp->next )
{
if( level > tmp->level )
{
if( !tmp->last )
first_wiz = wiz;
else
tmp->last->next = wiz;
wiz->last = tmp->last;
wiz->next = tmp;
tmp->last = wiz;
return;
}
}
wiz->last = last_wiz;
wiz->next = NULL;
last_wiz->next = wiz;
last_wiz = wiz;
}
/* Wizlist builder - Thoric */
void make_wizlist( void )
{
DIR *dp;
struct dirent *dentry;
FILE *gfp;
const char *word;
int ilevel, heads = 0, imps = 0, leaders = 0, builders = 0, imms = 0, guests = 0, retirees = 0, servants = 0, value;
short sex;
EXT_BV iflags;
WIZENT *wiz, *wiznext;
char buf[MSL], *infoflags, flag[MSL];
first_wiz = NULL;
last_wiz = NULL;
dp = opendir( GOD_DIR );
ilevel = 0;
dentry = readdir( dp );
while( dentry )
{
if( dentry->d_name[0] != '.' )
{
snprintf( buf, sizeof( buf ), "%s%s", GOD_DIR, dentry->d_name );
if( ( gfp = fopen( buf, "r" ) ) )
{
word = feof( gfp ) ? "End" : fread_word( gfp );
ilevel = fread_number( gfp );
sex = SEX_NEUTRAL;
word = feof( gfp ) ? "End" : fread_word( gfp );
if( !str_cmp( word, "Sex" ) )
{
infoflags = fread_flagstring( gfp );
value = get_flag( infoflags, sex_names, SEX_MAX );
if( value >= SEX_NEUTRAL && value < SEX_MAX )
sex = value;
}
word = feof( gfp ) ? "End" : fread_word( gfp );
xCLEAR_BITS( iflags );
if( !str_cmp( word, "Pcflags" ) )
{
infoflags = fread_flagstring( gfp );
while( infoflags && infoflags[0] != '\0' )
{
infoflags = one_argument( infoflags, flag );
value = get_flag( flag, pc_flags, PCFLAG_MAX );
if( value >= 0 && value < PCFLAG_MAX )
xSET_BIT( iflags, value );
}
}
fclose( gfp );
gfp = NULL;
if( xIS_SET( iflags, PCFLAG_RETIRED ) )
{
ilevel = -1;
retirees++;
}
if( xIS_SET( iflags, PCFLAG_GUEST ) )
{
ilevel = -2;
guests++;
}
if( ilevel == PERM_IMP )
imps++;
if( ilevel == PERM_HEAD )
heads++;
if( ilevel == PERM_LEADER )
leaders++;
if( ilevel == PERM_BUILDER )
builders++;
if( ilevel == PERM_IMM )
imms++;
if( ilevel == PERM_ALL )
servants++;
add_to_wizlist( dentry->d_name, ilevel, sex );
}
}
dentry = readdir( dp );
}
closedir( dp );
remove_file( WIZLIST_FILE );
snprintf( buf, sizeof( buf ), " &[lblue]Masters of the &[green]%s&[lblue]!", sysdata.mud_name );
towizfile( buf );
buf[0] = '\0';
ilevel = PERM_MAX;
for( wiz = first_wiz; wiz; wiz = wiz->next )
{
if( wiz->level < ilevel )
{
if( buf[0] )
{
towizfile( buf );
buf[0] = '\0';
}
towizfile( "&[lblue]" );
ilevel = wiz->level;
switch( ilevel )
{
case PERM_IMP:
if( imps != 1 )
towizfile( " Implementors" );
else
towizfile( " Implementor" );
break;
case PERM_HEAD:
if( heads != 1 )
towizfile( " Head Immortals" );
else
towizfile( " Head Immortal" );
break;
case PERM_LEADER:
if( leaders != 1 )
towizfile( " Leaders" );
else
towizfile( " Leader" );
break;
case PERM_BUILDER:
if( builders != 1 )
towizfile( " Builders" );
else
towizfile( " Builder" );
break;
case PERM_IMM:
if( imms != 1 )
towizfile( " Immortals" );
else
towizfile( " Immortal" );
break;
case -1:
if( retirees != 1 )
towizfile( " Retirees" );
else
towizfile( " Retired" );
break;
case -2:
if( guests != 1 )
towizfile( " Guests" );
else
towizfile( " Guest" );
break;
case PERM_ALL:
default:
if( servants != 1 )
towizfile( " Servants" );
else
towizfile( " Servant" );
break;
}
}
if( color_strlen( buf ) + strlen( wiz->name ) > 76 )
{
towizfile( buf );
buf[0] = '\0';
}
mudstrlcat( buf, " ", sizeof( buf ) );
if( wiz->sex == SEX_NEUTRAL )
mudstrlcat( buf, "&[people]", sizeof( buf ) );
if( wiz->sex == SEX_FEMALE )
mudstrlcat( buf, "&[female]", sizeof( buf ) );
if( wiz->sex == SEX_MALE )
mudstrlcat( buf, "&[male]", sizeof( buf ) );
mudstrlcat( buf, wiz->name, sizeof( buf ) );
if( color_strlen( buf ) > 70 )
{
towizfile( buf );
buf[0] = '\0';
}
}
if( buf[0] )
towizfile( buf );
for( wiz = first_wiz; wiz; wiz = wiznext )
{
wiznext = wiz->next;
STRFREE( wiz->name );
DISPOSE( wiz );
}
first_wiz = last_wiz = NULL;
}
CMDF( do_makewizlist )
{
make_wizlist( );
send_to_char( "Done.\r\n", ch );
}
/* mud prog functions */
/* This routine reads in scripts of MUDprograms from a file */
int mprog_name_to_type( 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, "open_prog" ) )
return OPEN_PROG;
if( !str_cmp( name, "close_prog" ) )
return CLOSE_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, "scrap_prog" ) )
return SCRAP_PROG;
if( !str_cmp( name, "put_prog" ) )
return PUT_PROG;
if( !str_cmp( name, "repair_prog" ) )
return REPAIR_PROG;
if( !str_cmp( name, "greet_prog" ) )
return GREET_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, "leave_prog" ) )
return LEAVE_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, char *f )
{
MPROG_DATA *mprg = NULL;
char MUDProgfile[256];
FILE *progfile;
char letter;
snprintf( MUDProgfile, sizeof( MUDProgfile ), "%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 aren't 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;
}
/* 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, char *f )
{
MPROG_DATA *mprg = NULL;
char MUDProgfile[256];
FILE *progfile;
char letter;
snprintf( MUDProgfile, sizeof( MUDProgfile ), "%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 aren't 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;
}
/* 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, char *f )
{
MPROG_DATA *mprg = NULL;
char MUDProgfile[256];
FILE *progfile;
char letter;
snprintf( MUDProgfile, sizeof( MUDProgfile ), "%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 aren't 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;
}
/* 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;
}
}
}
/*************************************************************/
/*
* Function to delete a room index.
* Called from do_rdelete in build.c - Narn, May/96
* Don't ask me why they return bool.. :).. oh well.. -- Alty
* Don't ask me either, so I changed it to void. - Samson
*/
void delete_room( ROOM_INDEX_DATA *room )
{
int hash;
ROOM_INDEX_DATA *prev, *limbo = get_room_index( sysdata.room_limbo );
OBJ_DATA *o;
CHAR_DATA *ch;
EXTRA_DESCR_DATA *ed;
EXIT_DATA *ex;
MPROG_ACT_LIST *mpact;
MPROG_DATA *mp;
UNLINK( room, room->area->first_room, room->area->last_room, next_aroom, prev_aroom );
while( ( ch = room->first_person ) )
{
if( !is_npc( ch ) )
{
char_from_room( ch );
char_to_room( ch, limbo );
}
else
extract_char( ch, true );
}
for( ch = first_char; ch; ch = ch->next )
{
if( ch->was_in_room == room )
ch->was_in_room = ch->in_room;
if( ch->substate == SUB_ROOM_DESC && ch->dest_buf == room )
{
stop_editing( ch );
ch->substate = SUB_NONE;
ch->dest_buf = NULL;
send_to_char( "The room is no more.\r\n", ch );
}
else if( ch->substate == SUB_ROOM_EXTRA && ch->dest_buf )
{
for( ed = room->first_extradesc; ed; ed = ed->next )
{
if( ed == ch->dest_buf )
{
stop_editing( ch );
ch->substate = SUB_NONE;
ch->dest_buf = NULL;
send_to_char( "The room is no more.\r\n", ch );
break;
}
}
}
}
while( ( o = room->first_content ) )
extract_obj( o );
wipe_resets( room );
while( ( ed = room->first_extradesc ) )
{
room->first_extradesc = ed->next;
STRFREE( ed->keyword );
STRFREE( ed->description );
DISPOSE( ed );
--top_ed;
}
while( ( ex = room->first_exit ) )
extract_exit( room, ex );
while( ( mpact = room->mpact ) )
{
room->mpact = mpact->next;
STRFREE( mpact->buf );
DISPOSE( mpact );
}
while( ( mp = room->mudprogs ) )
{
room->mudprogs = mp->next;
STRFREE( mp->arglist );
STRFREE( mp->comlist );
DISPOSE( mp );
}
STRFREE( room->name );
STRFREE( room->description );
hash = room->vnum % MAX_KEY_HASH;
if( room == room_index_hash[hash] )
room_index_hash[hash] = room->next;
else
{
for( prev = room_index_hash[hash]; prev; prev = prev->next )
if( prev->next == room )
break;
if( prev )
prev->next = room->next;
else
bug( "delete_room: room %d not in hash bucket %d.", room->vnum, hash );
}
DISPOSE( room );
--top_room;
}
/* See comment on delete_room. */
void delete_obj( OBJ_INDEX_DATA *obj )
{
int hash;
OBJ_INDEX_DATA *prev;
OBJ_DATA *o, *o_next;
CHAR_DATA *ch;
EXTRA_DESCR_DATA *ed;
AFFECT_DATA *af;
MPROG_DATA *mp;
/* Remove references to object index */
for( o = obj->first_copy; o; o = o_next )
{
o_next = o->next_index;
if( o->pIndexData == obj )
extract_obj( o );
}
for( ch = first_char; ch; ch = ch->next )
{
if( ch->substate == SUB_OBJ_EXTRA && ch->dest_buf )
{
for( ed = obj->first_extradesc; ed; ed = ed->next )
{
if( ed == ch->dest_buf )
{
stop_editing( ch );
ch->substate = SUB_NONE;
send_to_char( "You suddenly forget which object you were editing!\r\n", ch );
break;
}
}
}
else if( ch->substate == SUB_MPROG_EDIT && ch->dest_buf )
{
for( mp = obj->mudprogs; mp; mp = mp->next )
{
if( mp == ch->dest_buf )
{
stop_editing( ch );
ch->dest_buf = NULL;
ch->substate = SUB_NONE;
send_to_char( "You suddenly forget which object you were working on.\r\n", ch );
break;
}
}
}
}
while( ( ed = obj->first_extradesc ) )
{
obj->first_extradesc = ed->next;
STRFREE( ed->keyword );
STRFREE( ed->description );
DISPOSE( ed );
--top_ed;
}
while( ( af = obj->first_affect ) )
{
obj->first_affect = af->next;
DISPOSE( af );
--top_affect;
}
while( ( mp = obj->mudprogs ) )
{
obj->mudprogs = mp->next;
STRFREE( mp->arglist );
STRFREE( mp->comlist );
DISPOSE( mp );
}
STRFREE( obj->name );
STRFREE( obj->short_descr );
STRFREE( obj->description );
STRFREE( obj->action_desc );
hash = obj->vnum % MAX_KEY_HASH;
if( obj == obj_index_hash[hash] )
obj_index_hash[hash] = obj->next;
else
{
for( prev = obj_index_hash[hash]; prev; prev = prev->next )
if( prev->next == obj )
break;
if( prev )
prev->next = obj->next;
else
bug( "%s: object %d not in hash bucket %d.", __FUNCTION__, obj->vnum, hash );
}
DISPOSE( obj );
--top_obj_index;
}
/* See comment on delete_room. */
void delete_mob( MOB_INDEX_DATA *mob )
{
int hash;
MOB_INDEX_DATA *prev;
CHAR_DATA *ch, *ch_next;
MPROG_DATA *mp;
for( ch = mob->first_copy; ch; ch = ch_next )
{
ch_next = ch->next_index;
if( ch->pIndexData == mob )
extract_char( ch, true );
else if( ch->substate == SUB_MPROG_EDIT && ch->dest_buf )
{
for( mp = mob->mudprogs; mp; mp = mp->next )
{
if( mp == ch->dest_buf )
{
send_to_char( "Your victim has departed.\r\n", ch );
stop_editing( ch );
ch->dest_buf = NULL;
ch->substate = SUB_NONE;
break;
}
}
}
}
while( ( mp = mob->mudprogs ) )
{
mob->mudprogs = mp->next;
STRFREE( mp->arglist );
STRFREE( mp->comlist );
DISPOSE( mp );
}
if( mob->pShop )
{
UNLINK( mob->pShop, first_shop, last_shop, next, prev );
DISPOSE( mob->pShop );
--top_shop;
}
if( mob->rShop )
{
UNLINK( mob->rShop, first_repair, last_repair, next, prev );
DISPOSE( mob->rShop );
--top_repair;
}
STRFREE( mob->name );
STRFREE( mob->short_descr );
STRFREE( mob->long_descr );
STRFREE( mob->description );
STRFREE( mob->spec_funname );
hash = mob->vnum % MAX_KEY_HASH;
if( mob == mob_index_hash[hash] )
mob_index_hash[hash] = mob->next;
else
{
for( prev = mob_index_hash[hash]; prev; prev = prev->next )
if( prev->next == mob )
break;
if( prev )
prev->next = mob->next;
else
bug( "%s: mobile %d not in hash bucket %d.", __FUNCTION__, mob->vnum, hash );
}
DISPOSE( mob );
--top_mob_index;
}
ROOM_INDEX_DATA *new_room( int vnum )
{
ROOM_INDEX_DATA *nroom;
CREATE( nroom, ROOM_INDEX_DATA, 1 );
if( !nroom )
{
bug( "%s: nroom is NULL after CREATE.", __FUNCTION__ );
return NULL;
}
nroom->first_person = nroom->last_person = NULL;
nroom->first_content = nroom->last_content = NULL;
nroom->first_reset = nroom->last_reset = NULL;
nroom->first_extradesc = nroom->last_extradesc = NULL;
nroom->first_exit = nroom->last_exit = NULL;
nroom->name = NULL;
nroom->description = NULL;
xCLEAR_BITS( nroom->room_flags );
nroom->area = NULL;
nroom->vnum = vnum;
nroom->sector_type = SECT_INSIDE;
nroom->light = 0;
nroom->tele_delay = 0;
nroom->tele_vnum = 0;
nroom->tunnel = 0;
nroom->charcount = 0;
nroom->objcount = 0;
return nroom;
}
/* Creat a new room (for online building) - Thoric */
ROOM_INDEX_DATA *make_room( int vnum, AREA_DATA *area )
{
ROOM_INDEX_DATA *pRoomIndex;
int iHash;
if( !( pRoomIndex = new_room( vnum ) ) )
{
bug( "%s: pRoomIndex is NULL after new_room.", __FUNCTION__ );
return NULL;
}
pRoomIndex->area = area;
pRoomIndex->name = STRALLOC( "Floating in a void" );
LINK( pRoomIndex, area->first_room, area->last_room, next_aroom, prev_aroom );
iHash = vnum % MAX_KEY_HASH;
pRoomIndex->next = room_index_hash[iHash];
room_index_hash[iHash] = pRoomIndex;
++top_room;
return pRoomIndex;
}
OBJ_INDEX_DATA *new_object( int vnum )
{
OBJ_INDEX_DATA *nobj;
int x;
CREATE( nobj, OBJ_INDEX_DATA, 1 );
if( !nobj )
{
bug( "%s: nobj is NULL after CREATE.", __FUNCTION__ );
return NULL;
}
nobj->vnum = vnum;
nobj->name = NULL;
nobj->short_descr = NULL;
nobj->description = NULL;
nobj->action_desc = NULL;
nobj->first_affect = nobj->last_affect = NULL;
nobj->first_extradesc = nobj->last_extradesc = NULL;
nobj->first_copy = nobj->last_copy = NULL;
xCLEAR_BITS( nobj->extra_flags );
xCLEAR_BITS( nobj->wear_flags );
xCLEAR_BITS( nobj->class_restrict );
xCLEAR_BITS( nobj->race_restrict );
nobj->item_type = ITEM_TRASH;
nobj->value[0] = -1;
nobj->value[1] = -1;
nobj->value[2] = -1;
nobj->value[3] = -1;
nobj->value[4] = -1;
nobj->value[5] = -1;
nobj->weight = 1;
nobj->cost = 0;
nobj->count = 0;
nobj->layers = 0;
for( x = 0; x < STAT_MAX; x++ )
nobj->stat_reqs[x] = 0;
return nobj;
}
/*
* Create a new INDEX object (for online building) - Thoric
* Option to clone an existing index object.
*/
OBJ_INDEX_DATA *make_object( int vnum, int cvnum, char *name )
{
OBJ_INDEX_DATA *pObjIndex = NULL, *cObjIndex = NULL;
char buf[MSL];
int iHash;
if( cvnum > 0 )
cObjIndex = get_obj_index( cvnum );
if( !( pObjIndex = new_object( vnum ) ) )
{
bug( "%s: failed to CREATE pObjIndex.", __FUNCTION__ );
return NULL;
}
pObjIndex->name = STRALLOC( name );
if( !cObjIndex )
{
snprintf( buf, sizeof( buf ), "A newly created %s", name );
pObjIndex->short_descr = STRALLOC( buf );
snprintf( buf, sizeof( buf ), "Some god dropped a newly created %s here.", name );
pObjIndex->description = STRALLOC( buf );
pObjIndex->short_descr[0] = LOWER( pObjIndex->short_descr[0] );
pObjIndex->description[0] = UPPER( pObjIndex->description[0] );
xSET_BIT( pObjIndex->extra_flags, ITEM_PROTOTYPE );
}
else
{
EXTRA_DESCR_DATA *ed, *ced;
AFFECT_DATA *paf, *cpaf;
pObjIndex->short_descr = QUICKLINK( cObjIndex->short_descr );
pObjIndex->description = QUICKLINK( cObjIndex->description );
pObjIndex->action_desc = QUICKLINK( cObjIndex->action_desc );
pObjIndex->item_type = cObjIndex->item_type;
pObjIndex->extra_flags = cObjIndex->extra_flags;
xSET_BIT( pObjIndex->extra_flags, ITEM_PROTOTYPE );
pObjIndex->wear_flags = cObjIndex->wear_flags;
pObjIndex->value[0] = cObjIndex->value[0];
pObjIndex->value[1] = cObjIndex->value[1];
pObjIndex->value[2] = cObjIndex->value[2];
pObjIndex->value[3] = cObjIndex->value[3];
pObjIndex->value[4] = cObjIndex->value[4];
pObjIndex->value[5] = cObjIndex->value[5];
pObjIndex->weight = cObjIndex->weight;
pObjIndex->cost = cObjIndex->cost;
for( ced = cObjIndex->first_extradesc; ced; ced = ced->next )
{
CREATE( ed, EXTRA_DESCR_DATA, 1 );
ed->keyword = QUICKLINK( ced->keyword );
ed->description = QUICKLINK( ced->description );
LINK( ed, pObjIndex->first_extradesc, pObjIndex->last_extradesc, next, prev );
top_ed++;
}
for( cpaf = cObjIndex->first_affect; cpaf; cpaf = cpaf->next )
{
CREATE( paf, AFFECT_DATA, 1 );
paf->type = cpaf->type;
paf->duration = cpaf->duration;
paf->location = cpaf->location;
paf->modifier = cpaf->modifier;
paf->bitvector = cpaf->bitvector;
LINK( paf, pObjIndex->first_affect, pObjIndex->last_affect, next, prev );
top_affect++;
}
}
iHash = vnum % MAX_KEY_HASH;
pObjIndex->next = obj_index_hash[iHash];
obj_index_hash[iHash] = pObjIndex;
top_obj_index++;
return pObjIndex;
}
/*
* Create a new INDEX mobile (for online building) - Thoric
* Option to clone an existing index mobile.
*/
MOB_INDEX_DATA *make_mobile( int vnum, int cvnum, char *name )
{
MOB_INDEX_DATA *pMobIndex = NULL, *cMobIndex = NULL;
char buf[MSL];
int iHash, stat;
if( cvnum > 0 )
cMobIndex = get_mob_index( cvnum );
CREATE( pMobIndex, MOB_INDEX_DATA, 1 );
if( !pMobIndex )
{
bug( "%s: failed to CREATE pMobIndex.", __FUNCTION__ );
return NULL;
}
pMobIndex->vnum = vnum;
pMobIndex->count = 0;
pMobIndex->killed = 0;
pMobIndex->name = STRALLOC( name );
pMobIndex->first_copy = pMobIndex->last_copy = NULL;
if( !cMobIndex )
{
snprintf( buf, sizeof( buf ), "A newly created %s", name );
pMobIndex->short_descr = STRALLOC( buf );
snprintf( buf, sizeof( buf ), "Some god abandoned a newly created %s here.\r\n", name );
pMobIndex->long_descr = STRALLOC( buf );
pMobIndex->description = NULL;
xCLEAR_BITS( pMobIndex->act );
xSET_BIT( pMobIndex->act, ACT_IS_NPC );
xSET_BIT( pMobIndex->act, ACT_PROTOTYPE );
xCLEAR_BITS( pMobIndex->affected_by );
pMobIndex->pShop = NULL;
pMobIndex->rShop = NULL;
pMobIndex->spec_fun = NULL;
pMobIndex->mudprogs = NULL;
xCLEAR_BITS( pMobIndex->progtypes );
pMobIndex->alignment = 0;
pMobIndex->level = 1;
pMobIndex->ac = 0;
pMobIndex->minhit = 0;
pMobIndex->maxhit = 0;
pMobIndex->gold = 0;
pMobIndex->mgold = 0;
pMobIndex->position = POS_STANDING;
pMobIndex->defposition = POS_STANDING;
pMobIndex->sex = 0;
for( stat = 0; stat < STAT_MAX; stat++ )
pMobIndex->perm_stats[stat] = 13;
pMobIndex->numattacks = 0;
xCLEAR_BITS( pMobIndex->xflags );
xCLEAR_BITS( pMobIndex->resistant );
xCLEAR_BITS( pMobIndex->immune );
xCLEAR_BITS( pMobIndex->absorb );
xCLEAR_BITS( pMobIndex->susceptible );
xCLEAR_BITS( pMobIndex->attacks );
xCLEAR_BITS( pMobIndex->defenses );
}
else
{
pMobIndex->short_descr = QUICKLINK( cMobIndex->short_descr );
pMobIndex->long_descr = QUICKLINK( cMobIndex->long_descr );
pMobIndex->description = QUICKLINK( cMobIndex->description );
pMobIndex->act = cMobIndex->act;
xSET_BIT( pMobIndex->act, ACT_PROTOTYPE );
pMobIndex->affected_by = cMobIndex->affected_by;
pMobIndex->pShop = NULL;
pMobIndex->rShop = NULL;
pMobIndex->spec_fun = cMobIndex->spec_fun;
pMobIndex->mudprogs = NULL;
xCLEAR_BITS( pMobIndex->progtypes );
pMobIndex->alignment = cMobIndex->alignment;
pMobIndex->level = cMobIndex->level;
pMobIndex->ac = cMobIndex->ac;
pMobIndex->minhit = cMobIndex->minhit;
pMobIndex->maxhit = cMobIndex->maxhit;
pMobIndex->gold = cMobIndex->gold;
pMobIndex->mgold = cMobIndex->mgold;
pMobIndex->position = cMobIndex->position;
pMobIndex->defposition = cMobIndex->defposition;
pMobIndex->sex = cMobIndex->sex;
for( stat = 0; stat < STAT_MAX; stat++ )
pMobIndex->perm_stats[stat] = cMobIndex->perm_stats[stat];
pMobIndex->xflags = cMobIndex->xflags;
pMobIndex->resistant = cMobIndex->resistant;
pMobIndex->immune = cMobIndex->immune;
pMobIndex->absorb = cMobIndex->absorb;
pMobIndex->susceptible = cMobIndex->susceptible;
pMobIndex->numattacks = cMobIndex->numattacks;
pMobIndex->attacks = cMobIndex->attacks;
pMobIndex->defenses = cMobIndex->defenses;
}
iHash = vnum % MAX_KEY_HASH;
pMobIndex->next = mob_index_hash[iHash];
mob_index_hash[iHash] = pMobIndex;
top_mob_index++;
return pMobIndex;
}
/*
* 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;
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;
top_exit++;
return pexit;
}
pRoomIndex->last_exit->next = pexit;
}
pexit->next = NULL;
pexit->prev = pRoomIndex->last_exit;
pRoomIndex->last_exit = pexit;
top_exit++;
return pexit;
}
void load_area_file( AREA_DATA *tarea, char *filename )
{
char newfilename[MSL];
if( fBootDb )
tarea = last_area;
if( !fBootDb && !tarea )
{
bug( "%s: null area!", __FUNCTION__ );
return;
}
if( tarea && xIS_SET( tarea->flags, AFLAG_PROTOTYPE ) )
snprintf( newfilename, sizeof( newfilename ), "%s%s", BUILD_DIR, filename );
else
snprintf( newfilename, sizeof( newfilename ), "%s%s", AREA_DIR, filename );
if( !( fpArea = fopen( newfilename, "r" ) ) )
{
perror( newfilename );
bug( "%s: error loading file (%s) for reading", __FUNCTION__, newfilename );
return;
}
area_version = 0;
for( ;; )
{
char *word;
if( fread_letter( fpArea ) != '#' )
{
bug( "%s: #not found", __FUNCTION__ );
exit( 1 );
}
word = fread_word( fpArea );
if( word[0] == '$' )
break;
else if( !str_cmp( word, "AREA" ) )
{
if( fBootDb )
{
load_area( fpArea );
tarea = last_area;
}
else
{
STRFREE( tarea->name );
tarea->name = fread_string( fpArea );
}
}
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" ) )
{
fread_number( fpArea );
fread_number( fpArea );
}
else if( !str_cmp( word, "RESETMSG" ) )
load_resetmsg( tarea, fpArea );
else if( !str_cmp( word, "RESETFREQ" ) )
{
tarea->reset_frequency = fread_number( fpArea );
tarea->age = tarea->reset_frequency;
}
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, "ROOMS" ) )
load_rooms( tarea, 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" ) )
fread_number( fpArea );
else
{
bug( "%s: bad section name: %s", __FUNCTION__, word );
if( fBootDb )
exit( 1 );
else
{
fclose( fpArea );
fpArea = NULL;
return;
}
}
}
fclose( fpArea );
fpArea = NULL;
if( tarea )
{
if( fBootDb )
{
sort_area_by_name( tarea ); /* 4/27/97 */
sort_area( tarea, false );
}
log_printf( "%s: %-14s: Vnums: %5d - %-5d", __FUNCTION__, tarea->filename, tarea->low_vnum, tarea->hi_vnum );
SET_BIT( tarea->status, AREA_LOADED );
}
else
log_printf( "%s: (%s)", __FUNCTION__, filename );
}
/*
* Build list of in_progress areas. Do not load areas.
* define AREA_READ if you want it to build area names rather than reading
* them out of the area files. -- Altrag
*/
void load_buildlist( void )
{
DIR *dp;
struct dirent *dentry;
AREA_DATA *pArea;
FILE *fp;
char temp, buf[MSL], line[81], word[81];
int low, hi, mlow, mhi, olow, ohi, rlow, rhi;
bool badfile = false;
dp = opendir( GOD_DIR );
dentry = readdir( dp );
while( dentry )
{
if( dentry->d_name[0] != '.' )
{
snprintf( buf, sizeof( buf ), "%s%s", GOD_DIR, dentry->d_name );
if( !( fp = fopen( buf, "r" ) ) )
{
bug( "%s: invalid file %s", __FUNCTION__, buf );
perror( buf );
dentry = readdir( dp );
continue;
}
log_string( buf );
badfile = false;
rlow = rhi = olow = ohi = mlow = mhi = 0;
while( !feof( fp ) && !ferror( fp ) )
{
low = 0;
hi = 0;
word[0] = 0;
line[0] = 0;
if( ( temp = fgetc( fp ) ) != EOF )
ungetc( temp, fp );
else
break;
fgets( line, 80, fp );
sscanf( line, "%s %d %d", word, &low, &hi );
if( !strcmp( word, "Trust" ) )
{
if( low < PERM_IMM )
{
snprintf( buf, sizeof( buf ), "%s: God file with level %d < %d", dentry->d_name, low, PERM_IMM );
badfile = true;
}
}
if( !strcmp( word, "VnumRange" ) )
rlow = low, rhi = hi;
}
fclose( fp );
if( rlow && rhi && !badfile )
{
snprintf( buf, sizeof( buf ), "%s%s.are", BUILD_DIR, dentry->d_name );
if( !( fp = fopen( buf, "r" ) ) )
{
bug( "%s: can't open building area file [%s] for read", __FUNCTION__, buf );
perror( buf );
dentry = readdir( dp );
continue;
}
mudstrlcpy( strArea, buf, sizeof( strArea ) );
#if !defined(READ_AREA) /* Dont always want to read stuff.. dunno.. shrug */
mudstrlcpy( word, fread_word( fp ), sizeof( word ) );
if( word[0] != '#' || strcmp( &word[1], "AREA" ) )
{
snprintf( buf, sizeof( buf ), "%s: %s.are: no #AREA found.", __FUNCTION__, dentry->d_name );
fclose( fp );
dentry = readdir( dp );
continue;
}
#endif
CREATE( pArea, AREA_DATA, 1 );
snprintf( buf, sizeof( buf ), "%s.are", dentry->d_name );
pArea->author = STRALLOC( dentry->d_name );
pArea->filename = STRALLOC( buf );
#if !defined(READ_AREA)
pArea->name = fread_string( fp );
#else
snprintf( buf, sizeof( buf ), "{PROTO} %s's area in progress", dentry->d_name );
pArea->name = STRALLOC( buf );
#endif
fclose( fp );
pArea->low_vnum = rlow;
pArea->hi_vnum = rhi;
pArea->low_soft_range = -1;
pArea->hi_soft_range = -1;
pArea->low_hard_range = -1;
pArea->hi_hard_range = -1;
CREATE( pArea->weather, WEATHER_DATA, 1 ); /* FB */
pArea->weather->temp = 0;
pArea->weather->precip = 0;
pArea->weather->wind = 0;
pArea->weather->temp_vector = 0;
pArea->weather->precip_vector = 0;
pArea->weather->wind_vector = 0;
pArea->weather->climate_temp = 2;
pArea->weather->climate_precip = 2;
pArea->weather->climate_wind = 2;
pArea->weather->first_neighbor = NULL;
pArea->weather->last_neighbor = NULL;
pArea->weather->echo = NULL;
pArea->weather->echo_color = AT_GRAY;
pArea->first_room = pArea->last_room = NULL;
xSET_BIT( pArea->flags, AFLAG_PROTOTYPE );
LINK( pArea, first_build, last_build, next, prev );
sort_area( pArea, true );
top_area++;
fBootDb = false;
load_area_file( pArea, pArea->filename );
fBootDb = true;
mudstrlcpy( strArea, "$", sizeof( strArea ) );
reset_area( pArea );
}
}
dentry = readdir( dp );
}
closedir( dp );
}
/* Sort areas by name alphanumercially - 4/27/97, Fireblade */
void sort_area_by_name( AREA_DATA *pArea )
{
AREA_DATA *temp_area;
if( !pArea )
{
bug( "%s: NULL pArea", __FUNCTION__ );
return;
}
for( temp_area = first_area_name; temp_area; temp_area = temp_area->next_sort_name )
{
if( strcmp( pArea->name, temp_area->name ) < 0 )
{
INSERT( pArea, temp_area, first_area_name, next_sort_name, prev_sort_name );
break;
}
}
if( !temp_area )
LINK( pArea, first_area_name, last_area_name, next_sort_name, prev_sort_name );
}
/* Sort by room vnums - Altrag & Thoric */
void sort_area( AREA_DATA *pArea, bool proto )
{
AREA_DATA *area = NULL;
AREA_DATA *first_sort, *last_sort;
bool found;
if( !pArea )
{
bug( "%s: NULL pArea", __FUNCTION__ );
return;
}
if( proto )
{
first_sort = first_bsort;
last_sort = last_bsort;
}
else
{
first_sort = first_asort;
last_sort = last_asort;
}
found = false;
pArea->prev_sort = pArea->next_sort = NULL;
if( !first_sort )
{
first_sort = last_sort = pArea;
found = true;
}
else
{
for( area = first_sort; area; area = area->next_sort )
{
if( pArea->low_vnum < area->low_vnum )
{
if( !area->prev_sort )
first_sort = pArea;
else
area->prev_sort->next_sort = pArea;
pArea->prev_sort = area->prev_sort;
pArea->next_sort = area;
area->prev_sort = pArea;
found = true;
break;
}
}
}
if( !found )
{
pArea->prev_sort = last_sort;
pArea->next_sort = NULL;
last_sort->next_sort = pArea;
last_sort = pArea;
}
if( proto )
{
first_bsort = first_sort;
last_bsort = last_sort;
}
else
{
first_asort = first_sort;
last_asort = last_sort;
}
}
/*
* Display vnums currently assigned to areas -Altrag & Thoric
* Sorted, and flagged if loaded.
*/
void show_vnums( CHAR_DATA *ch, int low, int high, bool proto, bool shownl, const char *loadst, const char *notloadst )
{
AREA_DATA *pArea, *first_sort;
int count, loaded;
count = 0;
loaded = 0;
set_pager_color( AT_PLAIN, ch );
if( proto )
first_sort = first_bsort;
else
first_sort = first_asort;
for( pArea = first_sort; pArea; pArea = pArea->next_sort )
{
if( IS_SET( pArea->status, AREA_DELETED ) )
continue;
if( pArea->low_vnum < low )
continue;
if( pArea->hi_vnum > high )
break;
if( IS_SET( pArea->status, AREA_LOADED ) )
loaded++;
else if( !shownl )
continue;
pager_printf( ch, "%-15s| Vnums: %5d - %-5d%s\r\n",
( pArea->filename ? pArea->filename : "(invalid)" ),
pArea->low_vnum, pArea->hi_vnum,
IS_SET( pArea->status, AREA_LOADED ) ? loadst : notloadst );
count++;
}
pager_printf( ch, "Areas listed: %d Loaded: %d\r\n", count, loaded );
}
/* Shows prototype vnums ranges, and if loaded */
CMDF( do_vnums )
{
char arg1[MIL], arg2[MIL];
int low, high;
argument = one_argument( argument, arg1 );
argument = one_argument( argument, arg2 );
low = 1;
high = MAX_VNUM;
if( arg1 != NULL && arg1[0] != '\0' )
{
low = atoi( arg1 );
if( arg2 != NULL && arg2[0] != '\0' )
high = atoi( arg2 );
}
show_vnums( ch, low, high, true, true, " *", "" );
}
/* Shows installed areas, sorted. Mark unloaded areas with an X */
CMDF( do_zones )
{
char arg1[MIL], arg2[MIL];
int low, high;
argument = one_argument( argument, arg1 );
argument = one_argument( argument, arg2 );
low = 1;
high = MAX_VNUM;
if( arg1 != NULL && arg1[0] != '\0' )
{
low = atoi( arg1 );
if( arg2 != NULL && arg2[0] != '\0' )
high = atoi( arg2 );
}
show_vnums( ch, low, high, false, true, "", " X" );
}
/* Check to make sure range of vnums is free - Scryn 2/27/96 */
CMDF( do_check_vnums )
{
AREA_DATA *pArea;
char arg1[MSL];
bool area_conflict;
int low_range, high_range;
argument = one_argument( argument, arg1 );
if( arg1 == NULL || arg1[0] == '\0' )
{
send_to_char( "Please specify the low end of the range to be searched.\r\n", ch );
return;
}
low_range = atoi( arg1 );
argument = one_argument( argument, arg1 );
if( arg1 == NULL || arg1[0] == '\0' )
{
send_to_char( "Please specify the high end of the range to be searched.\r\n", ch );
return;
}
high_range = atoi( arg1 );
if( low_range < 1 || low_range > MAX_VNUM )
{
send_to_char( "Invalid argument for bottom of range.\r\n", ch );
return;
}
if( high_range < 1 || high_range > MAX_VNUM )
{
send_to_char( "Invalid argument for top of range.\r\n", ch );
return;
}
if( high_range < low_range )
{
send_to_char( "Bottom of range must be below top of range.\r\n", ch );
return;
}
set_char_color( AT_PLAIN, ch );
for( pArea = first_asort; pArea; pArea = pArea->next_sort )
{
area_conflict = false;
if( IS_SET( pArea->status, AREA_DELETED ) )
continue;
if( low_range < pArea->low_vnum && pArea->low_vnum < high_range )
area_conflict = true;
if( low_range < pArea->hi_vnum && pArea->hi_vnum < high_range )
area_conflict = true;
if( ( low_range >= pArea->low_vnum ) && ( low_range <= pArea->hi_vnum ) )
area_conflict = true;
if( ( high_range <= pArea->hi_vnum ) && ( high_range >= pArea->low_vnum ) )
area_conflict = true;
if( area_conflict )
{
ch_printf( ch, "Conflict: %-15s| ", ( pArea->filename ? pArea->filename : "(invalid)" ) );
ch_printf( ch, "Vnums: %5d - %-5d\r\n", pArea->low_vnum, pArea->hi_vnum );
}
}
for( pArea = first_bsort; pArea; pArea = pArea->next_sort )
{
area_conflict = false;
if( IS_SET( pArea->status, AREA_DELETED ) )
continue;
if( low_range < pArea->low_vnum && pArea->low_vnum < high_range )
area_conflict = true;
if( low_range < pArea->hi_vnum && pArea->hi_vnum < high_range )
area_conflict = true;
if( ( low_range >= pArea->low_vnum ) && ( low_range <= pArea->hi_vnum ) )
area_conflict = true;
if( ( high_range <= pArea->hi_vnum ) && ( high_range >= pArea->low_vnum ) )
area_conflict = true;
if( area_conflict )
{
ch_printf( ch, "Conflict: %-15s| ", ( pArea->filename ? pArea->filename : "(invalid)" ) );
ch_printf( ch, "Vnums: %5d - %-5d\r\n", pArea->low_vnum, pArea->hi_vnum );
}
}
}
/*
* 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;
}
/*
* Initialize the weather for all the areas
* Last Modified: July 21, 1997
* Fireblade
*/
void init_area_weather( void )
{
AREA_DATA *pArea;
NEIGHBOR_DATA *neigh, *next_neigh;
for( pArea = first_area; pArea; pArea = pArea->next )
{
int cf;
/* init temp and temp vector */
cf = pArea->weather->climate_temp - 2;
pArea->weather->temp = number_range( -weath_unit, weath_unit ) + cf * number_range( 0, weath_unit );
pArea->weather->temp_vector = cf + number_range( -rand_factor, rand_factor );
/* init precip and precip vector */
cf = pArea->weather->climate_precip - 2;
pArea->weather->precip = number_range( -weath_unit, weath_unit ) + cf * number_range( 0, weath_unit );
pArea->weather->precip_vector = cf + number_range( -rand_factor, rand_factor );
/* init wind and wind vector */
cf = pArea->weather->climate_wind - 2;
pArea->weather->wind = number_range( -weath_unit, weath_unit ) + cf * number_range( 0, weath_unit );
pArea->weather->wind_vector = cf + number_range( -rand_factor, rand_factor );
/* check connections between neighbors */
for( neigh = pArea->weather->first_neighbor; neigh; neigh = next_neigh )
{
AREA_DATA *tarea;
NEIGHBOR_DATA *tneigh;
/* get the address if needed */
if( !neigh->address )
neigh->address = get_area( neigh->name );
/* area does not exist */
if( !neigh->address )
{
next_neigh = neigh->next;
UNLINK( neigh, pArea->weather->first_neighbor, pArea->weather->last_neighbor, next, prev );
STRFREE( neigh->name );
DISPOSE( neigh );
fold_area( pArea, pArea->filename, false );
continue;
}
/* make sure neighbors both point to each other */
tarea = neigh->address;
for( tneigh = tarea->weather->first_neighbor; tneigh; tneigh = tneigh->next )
{
if( !strcmp( pArea->name, tneigh->name ) )
break;
}
if( !tneigh )
{
CREATE( tneigh, NEIGHBOR_DATA, 1 );
tneigh->name = STRALLOC( pArea->name );
LINK( tneigh, tarea->weather->first_neighbor, tarea->weather->last_neighbor, next, prev );
fold_area( tarea, tarea->filename, false );
}
tneigh->address = pArea;
next_neigh = neigh->next;
}
}
}
/*
* Load weather data from appropriate file in system dir
* Last Modified: July 24, 1997 - Fireblade
*/
void load_weatherdata( void )
{
FILE *fp;
if( ( fp = fopen( WEATHER_FILE, "r" ) ) )
{
for( ;; )
{
char letter;
char *word;
letter = fread_letter( fp );
if( letter != '#' )
{
bug( "%s: # not found", __FUNCTION__ );
return;
}
word = fread_word( fp );
if( !str_cmp( word, "RANDOM" ) )
rand_factor = fread_number( fp );
else if( !str_cmp( word, "CLIMATE" ) )
climate_factor = fread_number( fp );
else if( !str_cmp( word, "NEIGHBOR" ) )
neigh_factor = fread_number( fp );
else if( !str_cmp( word, "UNIT" ) )
weath_unit = fread_number( fp );
else if( !str_cmp( word, "MAXVECTOR" ) )
max_vector = fread_number( fp );
else if( !str_cmp( word, "END" ) )
{
fclose( fp );
fp = NULL;
break;
}
else
{
bug( "%s: unknown field", __FUNCTION__ );
fclose( fp );
fp = NULL;
break;
}
}
}
}
/* Write data for global weather parameters - Fireblade */
void save_weatherdata( void )
{
FILE *fp;
if( !( fp = fopen( WEATHER_FILE, "w" ) ) )
{
bug( "%s: could not open %s for writing", __FUNCTION__, WEATHER_FILE );
return;
}
fprintf( fp, "#RANDOM %d\n", rand_factor );
fprintf( fp, "#CLIMATE %d\n", climate_factor );
fprintf( fp, "#NEIGHBOR %d\n", neigh_factor );
fprintf( fp, "#UNIT %d\n", weath_unit );
fprintf( fp, "#MAXVECTOR %d\n", max_vector );
fprintf( fp, "#END\n" );
fclose( fp );
fp = NULL;
}
size_t newmudstrlcpy( char *dst, const char *src, size_t siz, const char *filename, int line )
{
register char *d = dst;
register const char *s = src;
register size_t n = siz;
if( !src )
{
bug( "%s: %s[%d] passing NULL src string!", __FUNCTION__, filename, line );
return 0;
}
if( !dst )
{
bug( "%s: %s[%d] passing NULL dst string!", __FUNCTION__, filename, line );
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 NULL 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 && *s != '\0' )
{
if( n != 1 )
{
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return ( dlen + ( s - src ) ); /* count does not include NUL */
}