/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | *
* -----------------------------------------------------------| \\._.// *
* SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version) | (0...0) *
* -----------------------------------------------------------| ).:.( *
* SMAUG (C) 1994, 1995, 1996 by Derek Snider | {o o} *
* -----------------------------------------------------------| / ' ' \ *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, |~'~.VxvxV.~'~*
* Scryn, Swordbearer, Rennard, Tricops, and Gorog. | *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe. *
* ------------------------------------------------------------------------ *
* Database management module *
****************************************************************************/
#include "stdafx.h"
#include "smaug.h"
#include "Smaugx.h"
#include "SysData.h"
#include "skill.h"
#include "social.h"
#include "commands.h"
#include "mobiles.h"
#include "objects.h"
#include "rooms.h"
#include "deity.h"
#include "area.h"
#include "boards.h"
#include "auction.h"
#include "help.h"
#include "races.h"
#include "class.h"
#include "SmaugWizDoc.h"
#include "SmaugFiles.h"
#include "descriptor.h"
#include "character.h"
#include "Language.h"
#include "Exits.h"
#include "ObjectMenu.h"
int gAcount;
void init_supermob ();
// Globals.
int nAllocString;
int sAllocString;
int nAllocPerm;
int sAllocPerm;
CWizData *first_wiz;
CWizData *last_wiz;
CHelpData *first_help;
CHelpData *last_help;
CShopData *first_shop;
CShopData *last_shop;
CRepairShopData *first_repair;
CRepairShopData *last_repair;
CTeleportData *first_teleport;
CTeleportData *last_teleport;
CObjData *extracted_obj_queue;
CExtractedCharData *extracted_char_queue;
char bug_buf [2*MAX_INPUT_LENGTH];
CCharacter *first_char;
CCharacter *last_char;
char log_buf [2*MAX_INPUT_LENGTH];
time_info_data time_info;
CWeatherData weather_info;
int cur_qchars;
int nummobsloaded;
CAuctionData *auction; // auctions
// weaponry
short gsn_pugilism;
short gsn_long_blades;
short gsn_short_blades;
short gsn_flexible_arms;
short gsn_talonous_arms;
short gsn_bludgeons;
short gsn_shieldwork;
short gsn_missile_weapons;
// thief
short gsn_detrap;
short gsn_backstab;
short gsn_circle;
short gsn_dodge;
short gsn_hide;
short gsn_peek;
short gsn_pick_lock;
short gsn_sneak;
short gsn_steal;
short gsn_gouge;
short gsn_poison_weapon;
// thief & warrior
short gsn_disarm;
short gsn_enhanced_damage;
short gsn_kick;
short gsn_parry;
short gsn_rescue;
short gsn_second_attack;
short gsn_third_attack;
short gsn_fourth_attack;
short gsn_fifth_attack;
short gsn_dual_wield;
short gsn_punch;
short gsn_bash;
short gsn_stun;
short gsn_bashdoor;
short gsn_grip;
short gsn_berserk;
short gsn_hitall;
short gsn_tumble;
// vampire
short gsn_feed;
short gsn_bloodlet;
short gsn_broach;
short gsn_mistwalk;
// other
short gsn_aid;
short gsn_track;
short gsn_search;
short gsn_dig;
short gsn_mount;
short gsn_bite;
short gsn_claw;
short gsn_sting;
short gsn_tail;
short gsn_scribe;
short gsn_brew;
short gsn_climb;
short gsn_cook;
short gsn_scan;
short gsn_slice;
// spells
short gsn_aqua_breath;
short gsn_blindness;
short gsn_charm_person;
short gsn_curse;
short gsn_invis;
short gsn_mass_invis;
short gsn_poison;
short gsn_sleep;
short gsn_possess;
short gsn_fireball;
short gsn_chill_touch;
short gsn_lightning_bolt;
// languages
short gsn_common;
short gsn_elven;
short gsn_dwarven;
short gsn_pixie;
short gsn_ogre;
short gsn_orcish;
short gsn_trollish;
short gsn_goblin;
short gsn_halfling;
// for searching
short gsn_first_spell;
short gsn_first_skill;
short gsn_first_weapon;
short gsn_first_tongue;
short gsn_top_sn;
// styles
short gsn_style_evasive;
short gsn_style_defensive;
short gsn_style_standard;
short gsn_style_aggressive;
short gsn_style_berserk;
CAreaData *first_build;
CAreaData *last_build;
CAreaData *first_bsort;
CAreaData *last_bsort;
// Locals.
int top_affect;
int top_ed;
int top_exit;
int top_shop;
int top_repair;
int top_vroom;
// Semi-locals.
BOOL fBootDb, bBootLog;
FILE *fpArea;
char strArea [MAX_INPUT_LENGTH];
// Local booting procedures.
void init_mm ();
void load_area (FILE *fp);
void load_reserved ();
void load_buildlist ();
void load_banlist ();
void initialize_economy ();
void ShowConflicts (CCharacter* ch, CPtrList& List, int low, int hi,
BOOL bRoom, BOOL bMob, BOOL bObj);
// MUDprogram locals
void FixRoomExits (CRoomIndexData& Ri, BOOL bBoot);
void remap_slot_numbers ();
void shutdown_mud (char *reason)
{
FILE *fp;
if ((fp = fopen (FileTable.GetName (SM_SHUTDOWN_FILE), "a")) != NULL) {
fprintf (fp, "%s\n", reason);
fclose (fp);
}
}
// Big mama top level function.
void boot_db ()
{
short wear, x;
TRY {
remove (FileTable.GetName (SM_BOOTLOG_FILE));
bBootLog = FALSE;
gpDoc->LogString ("Loading SysData configuration...", LOG_BOOT);
if (! SysData.Load ())
gpDoc->LogString ("Not found. Creating new configuration.",
LOG_BOOT);
gpDoc->LogString ("Loading commands", LOG_BOOT);
CommandTable.Load ();
gpDoc->LogString ("Loading languages", LOG_BOOT);
LanguageTable.Load ();
gpDoc->LogString ("Loading socials", LOG_BOOT);
SocialTable.Load ();
gpDoc->LogString ("Loading skill table", LOG_BOOT);
load_skill_table ();
SkillTable.Sort ();
remap_slot_numbers (); // must be after the sort
gsn_first_spell = 0;
gsn_first_skill = 0;
gsn_first_weapon = 0;
gsn_first_tongue = 0;
gsn_top_sn = SkillTable.GetCount ();
for (x = 0; x < SkillTable.GetCount (); x++)
if (!gsn_first_spell && SkillTable.GetType (x) == SKILL_SPELL)
gsn_first_spell = x;
else
if (!gsn_first_skill && SkillTable.GetType (x) == SKILL_SKILL)
gsn_first_skill = x;
else
if (!gsn_first_weapon && SkillTable.GetType (x) == SKILL_WEAPON)
gsn_first_weapon = x;
else
if (!gsn_first_tongue && SkillTable.GetType (x) == SKILL_TONGUE)
gsn_first_tongue = x;
gpDoc->LogString ("Loading classes", LOG_BOOT);
ClassTable.Load ();
gpDoc->LogString ("Loading races", LOG_BOOT);
RaceTable.Load ();
gpDoc->LogString ("Loading herb table", LOG_BOOT);
load_herb_table ();
gpDoc->LogString ("Making wizlist", LOG_BOOT);
make_wizlist ();
gpDoc->LogString ("Initializing request pipe", LOG_BOOT);
init_request_pipe ();
fBootDb = TRUE;
nummobsloaded = 0;
first_char = NULL;
last_char = NULL;
first_shop = NULL;
last_shop = NULL;
first_repair = NULL;
last_repair = NULL;
first_teleport = NULL;
last_teleport = NULL;
extracted_obj_queue = NULL;
extracted_char_queue= NULL;
cur_qchars = 0;
cur_char = NULL;
cur_obj = 0;
cur_obj_serial = 0;
cur_char_died = FALSE;
cur_obj_extracted = FALSE;
cur_room = NULL;
quitting_char = NULL;
loading_char = NULL;
saving_char = NULL;
auction = new CAuctionData;
for (wear = 0; wear < MAX_WEAR; wear++)
for (x = 0; x < MAX_LAYERS; x++)
save_equipment [wear][x] = NULL;
// Init random number generator.
gpDoc->LogString ("Initializing random number generator", LOG_BOOT);
init_mm ();
// Set time and weather.
gpDoc->LogString ("Setting time and weather", LOG_BOOT);
long lhour, lday, lmonth;
lhour = (CurrentTime.GetTotalSeconds () - 650336715)
/ (PULSE_TICK / PULSE_PER_SECOND);
time_info.hour = lhour % 24;
lday = lhour / 24;
time_info.day = lday % 35;
lmonth = lday / 35;
time_info.month = lmonth % 17;
time_info.year = lmonth / 17;
if (time_info.hour < 5) then weather_info.sunlight = SUN_DARK;
else if (time_info.hour < 6) then weather_info.sunlight = SUN_RISE;
else if (time_info.hour < 19) then weather_info.sunlight = SUN_LIGHT;
else if (time_info.hour < 20) then weather_info.sunlight = SUN_SET;
else weather_info.sunlight = SUN_DARK;
weather_info.change = 0;
weather_info.mmhg = 960;
if (time_info.month >= 7 && time_info.month <=12)
weather_info.mmhg += number_range (1, 50);
else
weather_info.mmhg += number_range (1, 80);
if (weather_info.mmhg <= 980) then weather_info.sky = SKY_LIGHTNING;
else if (weather_info.mmhg <= 1000) then weather_info.sky = SKY_RAINING;
else if (weather_info.mmhg <= 1020) then weather_info.sky = SKY_CLOUDY;
else weather_info.sky = SKY_CLOUDLESS;
// Assign gsn's for skills which need them.
gpDoc->LogString ("Assigning gsn's", LOG_BOOT);
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_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_shieldwork, "shieldwork");
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_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_second_attack, "second attack");
ASSIGN_GSN (gsn_third_attack, "third attack");
ASSIGN_GSN (gsn_fourth_attack, "fourth attack");
ASSIGN_GSN (gsn_fifth_attack, "fifth attack");
ASSIGN_GSN (gsn_dual_wield, "dual wield");
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_hitall, "hitall");
ASSIGN_GSN (gsn_feed, "feed");
ASSIGN_GSN (gsn_bloodlet, "bloodlet");
ASSIGN_GSN (gsn_broach, "broach");
ASSIGN_GSN (gsn_mistwalk, "mistwalk");
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_sting, "sting");
ASSIGN_GSN (gsn_tail, "tail");
ASSIGN_GSN (gsn_scribe, "scribe");
ASSIGN_GSN (gsn_brew, "brew");
ASSIGN_GSN (gsn_climb, "climb");
ASSIGN_GSN (gsn_cook, "cook");
ASSIGN_GSN (gsn_scan, "scan");
ASSIGN_GSN (gsn_slice, "slice");
ASSIGN_GSN (gsn_fireball, "fireball");
ASSIGN_GSN (gsn_chill_touch, "chill touch");
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_mass_invis, "mass invis");
ASSIGN_GSN (gsn_poison, "poison");
ASSIGN_GSN (gsn_sleep, "sleep");
ASSIGN_GSN (gsn_possess, "possess");
ASSIGN_GSN (gsn_common, "common");
ASSIGN_GSN (gsn_elven, "elven");
ASSIGN_GSN (gsn_dwarven, "dwarven");
ASSIGN_GSN (gsn_pixie, "pixie");
ASSIGN_GSN (gsn_ogre, "ogre");
ASSIGN_GSN (gsn_orcish, "orcish");
ASSIGN_GSN (gsn_trollish, "trollese");
ASSIGN_GSN (gsn_goblin, "goblin");
ASSIGN_GSN (gsn_halfling, "halfling");
// Read in all the area files.
FILE *fpList;
gpDoc->LogString ("Reading in area files...", LOG_BOOT);
if (! (fpList = fopen (FileTable.GetName (SM_AREA_LIST), "r"))) {
perror (AREA_LIST);
shutdown_mud ("Unable to open area list");
ThrowSmaugException (SE_AREA);
}
for (;;) {
CString Fname = fread_line (fpList);
if (strchr (Fname, '$'))
break;
int pos = Fname.Find (".are");
if (pos > 0) {
Fname.GetBufferSetLength (pos); // drop the ".are"
CAreaData *pArea = LoadAreaFile (Fname, BOOT);
if (pArea)
AddArea (pArea);
}
}
fclose (fpList);
// initialize supermob. - must be done before reset_area!
init_supermob ();
CObjectMenu::InitObjectMenu ();
// Fix up exits.
// Declare db booting over.
// Reset all areas once.
// Load up the notes file.
fix_exits ();
fBootDb = FALSE;
initialize_economy ();
gpDoc->LogString ("Resetting areas...", LOG_BOOT);
area_update ();
load_buildlist ();
BoardList.Load ();
load_clans ();
load_councils ();
load_deities ();
load_banlist ();
load_reserved( );
load_corpses ();
MOBtrigger = TRUE;
}
CATCH (CException, ex) {
bug ("Boot failure. SmaugWiz not started.");
TRY ClearDatabase ();
CATCH (CSmaugException, ex) {
bug ("Error %d: Clearing after boot failure.", ex->m_cause);
THROW_LAST ();
}
END_CATCH
THROW_LAST ();
}
END_CATCH
}
// Add a character to the list of all characters -Thoric
void add_char (CCharacter *ch)
{
LINK (ch, first_char, last_char);
}
// Go through all areas, and set up initial economy based on mob
// levels and gold
void initialize_economy ()
{
CMobIndexData *mob;
int idx, gold, rng;
gpDoc->LogString ("Initializing economy...", LOG_BOOT);
POSITION pos = AreaList.GetHeadPosition ();
while (pos) {
CAreaData &Area = *AreaList.GetNext (pos);
// skip area if they already got some gold
if (Area.high_economy > 0 || Area.low_economy > 10000)
continue;
rng = Area.hi_soft_range - Area.low_soft_range;
if (rng)
rng /= 2;
else
rng = 25;
gold = rng * rng * 50000;
Area.BoostEconomy (gold);
for (idx = Area.low_m_vnum; idx < Area.hi_m_vnum; idx++)
if ((mob = MobTable.GetMob (idx, fBootDb)) != NULL)
Area.BoostEconomy (mob->gold * 10);
}
}
// 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 (BOOL bBoot /* = FALSE */)
{
CRoomIndexData *pRoomIndex;
CExitData *pexit, *rev_exit;
int iHash;
gpDoc->LogString ("Fixing exits...", LOG_BOOT);
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++) {
pRoomIndex = RoomTable.GetFirstByHash (iHash);
while (pRoomIndex) {
pRoomIndex->FixExits (bBoot);
pRoomIndex = pRoomIndex->GetNext ();
}
}
// Set all the rexit pointers -Thoric
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++) {
for (pRoomIndex = RoomTable.GetFirstByHash (iHash); pRoomIndex;
pRoomIndex = pRoomIndex->GetNext ()) {
for (pexit = pRoomIndex->first_exit; pexit;
pexit = pexit->GetNext ()) {
if (pexit->GetToRoom () && !pexit->rexit) {
rev_exit = get_exit_to (pexit->GetToRoom (),
rev_dir[pexit->vdir], pRoomIndex->vnum);
if (rev_exit) {
pexit->rexit = rev_exit;
rev_exit->rexit = pexit;
}
}
}
}
}
}
/*
* (prelude...) This is going to be fun... NOT!
* (conclusion) QSort is f*cked!
*/
int exit_comp (CExitData **xit1, CExitData **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 (CRoomIndexData *room)
{
CExitData *pexit;
CExitData *exits [MAX_REXITS];
int x, nexits;
nexits = 0;
for (pexit = room->first_exit; pexit; pexit = pexit->GetNext ()) {
exits [nexits++] = pexit;
if (nexits > MAX_REXITS) {
bug ("sort_exits: more than %d exits in room... fatal", nexits);
return;
}
}
qsort (&exits [0], nexits, sizeof (CExitData *),
(int (*) (const void *, const void *)) exit_comp);
for (x = 0; x < nexits; x++) {
if (x > 0)
exits [x]->SetPrev (exits [x-1]);
else {
exits [x]->SetPrev (NULL);
room->first_exit = exits [x];
}
if (x >= (nexits - 1)) {
exits [x]->SetNext (NULL);
room->last_exit = exits [x];
}
else
exits [x]->SetNext (exits [x+1]);
}
}
void randomize_exits (CRoomIndexData *pRoom, short maxdir)
{
CExitData *pexit;
int nexits, d0, d1, count, door;
int vdirs [MAX_REXITS];
nexits = 0;
for (pexit = pRoom->first_exit; pexit; pexit = pexit->GetNext ())
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 = pRoom->first_exit; pexit; pexit = pexit->GetNext ())
pexit->vdir = vdirs [count++];
sort_exits (pRoom);
}
// Repopulate areas periodically.
void area_update ()
{
try {
POSITION pos = AreaList.GetHeadPosition ();
while (pos) {
CAreaData &Area = *AreaList.GetNext (pos);
CCharacter *pch;
int reset_age = Area.reset_frequency ? Area.reset_frequency : 15;
if ((reset_age == -1 && Area.age == -1)
|| ++Area.age < (reset_age-1))
continue;
// Check for PC's.
if (Area.nplayer > 0 && Area.age == (reset_age-1)) {
char buf [MAX_STRING_LENGTH];
// Rennard
if (! Area.m_Resetmsg.IsEmpty ())
sprintf (buf, "%s\n\r", NCCP Area.m_Resetmsg);
else
strcpy (buf, "You hear some squeaking sounds...\n\r");
for (pch = first_char; pch; pch = pch->GetNext ()) {
if (! pch->IsNpc () && pch->IsAwake ()
&& pch->GetInRoom () && pch->GetInRoom ()->GetArea () == &Area) {
set_char_color (AT_RESET, pch);
pch->SendText (buf);
}
}
}
// Check age and reset.
// Note: Mud Academy resets every 3 minutes (not 15).
if (Area.nplayer == 0 || Area.age >= reset_age) {
CRoomIndexData *pRoomIndex;
gpDoc->m_pLog->Printf (LOG_RESET,
"Resetting: %s\n", NCCP Area.m_Filename);
Area.Reset ();
if (reset_age == -1)
Area.age = -1;
else
Area.age = number_range (0, reset_age / 5);
pRoomIndex = RoomTable.GetRoom (SysData.m_RoomSchool);
if (pRoomIndex != NULL && &Area == pRoomIndex->GetArea ()
&& Area.reset_frequency == 0)
Area.age = 15 - 3;
}
}
}
catch (...) {
CSwException ex;
ex.Printf ("area_update Exception.");
throw ex;
}
}
// Create an instance of a mobile.
CCharacter *create_mobile (CMobIndexData *pMobIndex)
{
CCharacter *mob;
if (!pMobIndex) {
bug ("Create_mobile: NULL pMobIndex.");
ThrowSmaugException (SE_MOBILE);
}
mob = new CCharacter;
mob->InitChar ();
mob->SetMobIndex (pMobIndex);
mob->SetEditor (NULL);
mob->SetName (pMobIndex->GetPlayerName ());
mob->SetShortDescr (pMobIndex->GetShortDescr ());
mob->SetLongDescr (pMobIndex->GetLongDescr ());
mob->SetDescription (pMobIndex->GetDescription ());
mob->SetSpecialMobFunction (pMobIndex->spec_fun);
mob->mpscriptpos = 0;
mob->SetLevel (number_fuzzy (pMobIndex->level));
mob->SetMobInvisLevel (pMobIndex->GetMobInvisLevel ());
mob->SetActFlags (pMobIndex->GetActFlags ());
mob->SetAffectFlags (pMobIndex->GetAffectFlags ());
mob->SetAlignment (pMobIndex->alignment);
mob->SetSex (pMobIndex->sex);
if (!pMobIndex->ac)
mob->SetArmor (pMobIndex->ac);
else
mob->SetArmor (interpolate (mob->GetLevel (), 100, -100));
if (!pMobIndex->hitnodice)
mob->SetMaxHp (mob->GetLevel () * 8
+ number_range ( mob->GetLevel () * mob->GetLevel () / 4,
mob->GetLevel () * mob->GetLevel ()));
else
mob->SetMaxHp (pMobIndex->hitnodice
* number_range (1, pMobIndex->hitsizedice) + pMobIndex->hitplus);
mob->SetHp (mob->GetMaxHp ());
mob->SetGold (pMobIndex->gold);
mob->SetExp (pMobIndex->exp);
mob->SetPosition (pMobIndex->position);
mob->defposition = pMobIndex->defposition;
mob->barenumdie = pMobIndex->damnodice;
mob->baresizedie = pMobIndex->damsizedice;
mob->mobthac0 = pMobIndex->mobthac0;
mob->hitplus = pMobIndex->hitplus;
mob->damplus = pMobIndex->damplus;
mob->perm_str = pMobIndex->perm_str;
mob->perm_dex = pMobIndex->perm_dex;
mob->perm_wis = pMobIndex->perm_wis;
mob->perm_int = pMobIndex->perm_int;
mob->perm_con = pMobIndex->perm_con;
mob->perm_cha = pMobIndex->perm_cha;
mob->perm_lck = pMobIndex->perm_lck;
mob->SetHitroll (pMobIndex->hitroll);
mob->SetDamroll (pMobIndex->damroll);
mob->SetRace (pMobIndex->race);
mob->SetClass (pMobIndex->m_Class);
mob->SetXFlags (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->SetHeight (pMobIndex->height);
mob->SetCarryWeight (pMobIndex->weight);
mob->SetResistFlags (pMobIndex->resistant);
mob->SetImmuneFlags (pMobIndex->immune);
mob->SetSusceptFlags (pMobIndex->susceptible);
mob->SetAttackFlags (pMobIndex->GetAttackFlags ());
mob->SetDefenseFlags (pMobIndex->GetDefenseFlags ());
mob->numattacks = pMobIndex->numattacks;
mob->SetSpeaksFlags (pMobIndex->GetSpeaksFlags ());
mob->SetSpeaking (pMobIndex->GetSpeaking ());
// Insert in list.
add_char (mob);
pMobIndex->count++;
nummobsloaded++;
return mob;
}
// Create an instance of an object.
CObjData *create_object (CObjIndexData *pObjIndex, int level)
{
CObjData *obj;
if (!pObjIndex) {
bug ("Create_object: NULL pObjIndex.");
ThrowSmaugException (SE_OBJECT);
}
obj = new CObjData;
obj->pIndexData = pObjIndex;
obj->in_room = NULL;
obj->level = level;
obj->wear_loc = -1;
obj->count = 1;
cur_obj_serial = UMAX ((cur_obj_serial + 1) & (BV30-1), 1);
obj->serial = obj->pIndexData->serial = cur_obj_serial;
obj->SetName (pObjIndex->GetName ());
obj->SetShortDescr (pObjIndex->GetShortDescr ());
obj->SetDescription (pObjIndex->GetDescription ());
obj->SetActionDescr (pObjIndex->GetActionDescr ());
obj->item_type = pObjIndex->item_type;
obj->m_ExtraFlags = pObjIndex->m_ExtraFlags;
obj->wear_flags = pObjIndex->wear_flags;
obj->SetAntiClassFlags (pObjIndex->GetAntiClassFlags ());
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:
bug ("Read_object: vnum %d bad type.", pObjIndex->vnum);
bug ("------------------------> ", obj->item_type);
break;
case ITEM_LIGHT:
case ITEM_TREASURE:
case ITEM_FURNITURE:
case ITEM_TRASH:
case ITEM_CONTAINER:
case ITEM_DRINK_CON:
case ITEM_KEY:
case ITEM_KEYRING:
case ITEM_ODOR:
break;
case ITEM_COOK:
case ITEM_FOOD:
// optional food condition (rotting food) -Thoric
// value1 is the max condition of the food
// value4 is the optional initial condition
if (obj->value [4])
obj->timer = obj->value [4];
else
obj->timer = obj->value [1];
break;
case ITEM_BOAT:
case ITEM_CORPSE_NPC:
case ITEM_CORPSE_PC:
case ITEM_FOUNTAIN:
case ITEM_BLOOD:
case ITEM_BLOODSTAIN:
case ITEM_SCRAPS:
case ITEM_PIPE:
case ITEM_HERB_CON:
case ITEM_HERB:
case ITEM_INCENSE:
case ITEM_FIRE:
case ITEM_BOOK:
case ITEM_SWITCH:
case ITEM_LEVER:
case ITEM_PULLCHAIN:
case ITEM_BUTTON:
case ITEM_DIAL:
case ITEM_RUNE:
case ITEM_RUNEPOUCH:
case ITEM_MATCH:
case ITEM_TRAP:
case ITEM_MAP:
case ITEM_PORTAL:
case ITEM_PAPER:
case ITEM_PEN:
case ITEM_TINDER:
case ITEM_LOCKPICK:
case ITEM_SPIKE:
case ITEM_DISEASE:
case ITEM_OIL:
case ITEM_FUEL:
case ITEM_QUIVER:
case ITEM_SHOVEL:
break;
case ITEM_SALVE:
obj->value [3] = number_fuzzy (obj->value [3]);
break;
case ITEM_SCROLL:
obj->value [0] = number_fuzzy (obj->value [0]);
break;
case ITEM_WAND:
case ITEM_STAFF:
obj->value [0] = number_fuzzy (obj->value [0]);
obj->value [1] = number_fuzzy (obj->value [1]);
obj->value [2] = obj->value [1];
break;
case ITEM_WEAPON:
case ITEM_MISSILE_WEAPON:
case ITEM_PROJECTILE:
if (obj->value [1] && obj->value [2])
obj->value [2] *= obj->value [1];
else {
obj->value [1] = number_fuzzy (number_fuzzy (1 * level / 4 + 2));
obj->value [2] = number_fuzzy (number_fuzzy (3 * level / 4 + 6));
}
if (obj->value [0] == 0)
obj->value [0] = INIT_WEAPON_CONDITION;
break;
case ITEM_ARMOR:
if (obj->value [0] == 0)
obj->value [0] = number_fuzzy (level / 4 + 2);
if (obj->value [1] == 0)
obj->value [1] = obj->value [0];
break;
case ITEM_POTION:
case ITEM_PILL:
obj->value [0] = number_fuzzy (number_fuzzy (obj->value [0]));
break;
case ITEM_MONEY:
obj->value [0] = obj->cost;
if (obj->value [0] == 0)
obj->value [0] = 1;
break;
}
pObjIndex->m_ObjList.AddTail (obj);
++pObjIndex->count;
return obj;
}
// Get an extra description from a list.
char *GetExtraDescr (const char *name, CPtrList &EList)
{
POSITION pos = EList.GetHeadPosition ();
while (pos) {
CExtraDescrData &Ed = *(CExtraDescrData*) EList.GetNext (pos);
if (is_name (name, Ed.keyword))
return Ed.description;
}
return NULL;
}
// Added lots of EOF checks, as most of the file crashes are based on them.
// If an area file encounters EOF, the fread_* functions will shutdown the
// MUD, as all area files should be read in in full or bad things will
// happen during the game. Any files loaded in without fBootDb which
// encounter EOF will return what they have read so far. These files
// should include player files, and in-progress areas that are not loaded
// upon bootup.
// -- Altrag
// This whole scheme has been redone, using exception handling - Rustry
// Read a letter from a file.
char fread_letter (FILE *fp)
{
char c;
do {
if (feof (fp)) {
bug ("fread_letter: EOF encountered on read.\n\r");
if (fBootDb)
ThrowSmaugException (SE_BOOT);
return '\0';
}
c = getc (fp);
}
while (isspace (c));
return c;
}
// Read a number from a file.
int ParseNumber (char*& pLine)
{
int number;
BOOL sign;
char c;
do c = *pLine++;
while (isspace (c));
number = 0;
sign = FALSE;
if (c == '+') {
c = *pLine++;
}
else if (c == '-') {
sign = TRUE;
c = *pLine++;
}
if (!isdigit (c)) {
bug ("ParseNumber: bad format. (%c)", c);
if (fBootDb)
ThrowSmaugException (SE_BOOT);
return 0;
}
while (isdigit (c)) {
number = number * 10 + c - '0';
c = *pLine++;
}
if (sign)
number = 0 - number;
if (c == '|')
number += ParseNumber (pLine);
else if (c != ' ')
--pLine;
return number;
}
// custom str_dup using new
char *str_dup (char const *str)
{
static char *ret;
if (!str)
return NULL;
ret = new char [strlen (str) + 1];
strcpy (ret, str);
return ret;
}
// Read a string from a buffer
char *ParseString (char*& pLine, FILE* fp)
{
char buf [MAX_STRING_LENGTH];
char *plast;
char c;
plast = buf;
buf [0] = '\0';
int Count = 0;
// Skip blanks.
// Read first char.
do c = *pLine++;
while (isspace (c));
if ((*plast++ = c) == '~')
return STRALLOC ("");
for (;;) {
if (Count >= (MAX_STRING_LENGTH - 1)) {
bug ("ParseString: string too long");
*plast = '\0';
return STRALLOC (buf);
}
switch (*plast = *pLine++) {
default:
++plast;
++Count;
break;
case '\0':
*plast++ = '\r';
*plast++ = '\n';
Count += 2;
// get another line (don't trim leading spaces)
pLine = fread_line (fp, FALSE);
break;
case '\r':
if (*pLine == '\n') {
++plast;
++Count;
}
break;
case '~':
*plast = '\0';
return STRALLOC (buf);
}
}
}
// Read a CString from a buffer
CString ParseCString (char*& pLine, FILE* fp)
{
char buf [MAX_STRING_LENGTH];
char *plast;
char c;
plast = buf;
buf [0] = '\0';
int Count = 0;
// Skip blanks.
// Read first char.
do c = *pLine++;
while (isspace (c));
if (c == '~')
return buf;
*plast++ = c;
for (;;) {
if (Count >= (MAX_STRING_LENGTH - 1)) {
bug ("ParseString: string too long");
*plast = '\0';
return buf;
}
switch (*plast = *pLine++) {
default:
++plast;
++Count;
break;
case '\0':
*plast++ = '\r';
*plast++ = '\n';
Count += 2;
// get another line (don't trim leading spaces)
pLine = fread_line (fp, FALSE);
break;
case '\r':
if (*pLine == '\n') {
++plast;
++Count;
}
break;
case '~':
*plast = '\0';
return buf;
}
}
}
// Read a string from buffer using str_dup (ie: no string hashing)
char *ParseStringNohash (char* str, FILE* fp)
{
char buf [MAX_STRING_LENGTH];
char *plast;
char c;
plast = buf;
buf [0] = '\0';
int Count = 0;
// Skip blanks.
// Read first char.
do c = *str++;
while (isspace (c));
if ((*plast++ = c) == '~')
return str_dup ("");
for (;;) {
if (Count >= (MAX_STRING_LENGTH - 1)) {
bug ("ParseStringNohash: string too long");
*plast = '\0';
return str_dup (buf);
}
switch (*plast = *str++) {
default:
++plast;
++Count;
break;
case '\0':
*plast++ = '\r';
*plast++ = '\n';
Count += 2;
break;
case '~':
*plast = '\0';
return str_dup (buf);
}
}
}
// Read a string from file fp using str_dup (ie: no string hashing)
char *fread_string_nohash (FILE *fp)
{
char buf[MAX_STRING_LENGTH];
char *plast;
char c;
int ln;
plast = buf;
buf [0] = '\0';
ln = 0;
// Skip blanks.
// Read first char.
do {
if (feof (fp)) {
bug ("fread_string_no_hash: EOF encountered on read.\n\r");
if (fBootDb)
ThrowSmaugException (SE_BOOT);
return str_dup ("");
}
c = getc (fp);
}
while (isspace (c));
if ((*plast++ = c) == '~')
return str_dup ("");
for (;;) {
if (ln >= (MAX_STRING_LENGTH - 1)) {
bug ("fread_string_no_hash: string too long");
*plast = '\0';
return str_dup (buf);
}
switch (*plast = getc (fp)) {
default:
plast++; ln++;
break;
case EOF:
bug ("Fread_string_no_hash: EOF");
if (fBootDb)
ThrowSmaugException (SE_BOOT);
*plast = '\0';
return str_dup (buf);
break;
case '\n':
plast++; ln++;
*plast++ = '\r'; ln++;
break;
case '\r':
break;
case '~':
*plast = '\0';
return str_dup (buf);
}
}
}
// Read to end of line into static buffer -Thoric
// bTrim (default) says to trim leading spaces
char *fread_line (FILE *fp, BOOL bTrim /* = TRUE */)
{
int len;
static char line [MAX_STRING_LENGTH];
char *ptr;
do {
ptr = line;
if (! fgets (line, MAX_STRING_LENGTH-1, fp)) {
if (feof (fp)) {
if (fBootDb) {
bug ("fread_line: EOF encountered on read.\n\r");
ThrowSmaugException (SE_BOOT);
}
strcpy (line, "");
return line;
} else {
bug ("fread_line: line too long");
if (fBootDb)
ThrowSmaugException (SE_BOOT);
break;
}
}
++gAcount;
if (bTrim) {
while (isspace (*ptr))
++ptr;
}
} while ((len = strlen (ptr)) < 2);
ptr [len-1] = 0; // null the '\n'
return ptr;
}
// Read one word (into static buffer).
char *ParseWord (char*& pLine)
{
static char word [MAX_INPUT_LENGTH];
char *pWord;
char cFirst;
if (! *pLine) return pLine;
do cFirst = *pLine++;
while (isspace (cFirst));
if (cFirst == '\'' || cFirst == '"')
pWord = word;
else {
word [0] = cFirst;
pWord = word+1;
cFirst = ' ';
}
for (; pWord < word + MAX_INPUT_LENGTH; pWord++) {
*pWord = *pLine++;
if ((cFirst == ' ' ? isspace (*pWord) : *pWord == cFirst)
|| *pWord == 0) {
if (cFirst == ' ')
--pLine;
*pWord = '\0';
return word;
}
}
bug ("Fread_word: word too long");
ThrowSmaugException (SE_BOOT);
return NULL;
}
char* ParseLine (char* pLine)
{
while (isspace (*pLine))
++pLine;
return pLine;
}
void ScanToEnd (FILE* fp, const char* end)
{
char *word, *pLine;
// So we don't get so many bug messages when something
// messes up --Shaddai
do {
if (feof (fp))
return;
pLine = fread_line (fp);
word = ParseWord (pLine);
}
while (! strcmp (word, end));
}
void do_memory (CCharacter *ch, char *argument)
{
char arg [MAX_INPUT_LENGTH];
int hash;
CParseinfo Inf;
argument = one_argument (argument, arg);
ch->SendTextf ("Affects %5d Areas %5d\n\r", top_affect,
AreaList.GetCount ());
ch->SendTextf ("ExtDes %5d Exits %5d\n\r", top_ed, top_exit);
ch->SendTextf ("Helps %5d Resets %5d\n\r", HelpList.GetCount (),
gResetCount);
ch->SendTextf ("IdxMobs %5d Mobs %5d\n\r", MobTable.GetCount (),
nummobsloaded);
ch->SendTextf ("IdxObjs %5d Objs %5d (%d)\n\r",
OIdxTable.GetCount (),
Inf.GetCount (COUNT_OBJS), Inf.GetCount (COUNT_TOTAL));
ch->SendTextf ("Rooms %5d VRooms %5d\n\r", RoomTable.GetCount (),
top_vroom);
ch->SendTextf ("Shops %5d RepShps %5d\n\r", top_shop, top_repair);
ch->SendTextf ("CurOq's %5d CurCq's %5d\n\r",
ExtractedObjList.GetCount (), cur_qchars);
ch->SendTextf ("Players %5d Maxplrs %5d\n\r", DList.GetCount (),
SysData.MaxPlayers);
ch->SendTextf ("MaxEver %5d Topsn %5d (%d)\n\r",
SysData.AlltimeMax, SkillTable.GetCount (), MAX_SKILL);
ch->SendTextf ("MaxEver time recorded at: %s\n\r", SysData.pTimeOfMax);
if (!str_cmp (arg, "check")) {
#ifdef HASHSTR
ch->SendText (check_hash (argument));
#else
ch->SendText ("Hash strings not enabled.\n\r");
#endif
return;
}
if (!str_cmp (arg, "showhigh")) {
#ifdef HASHSTR
show_high_hash (atoi (argument));
#else
ch->SendText ("Hash strings not enabled.\n\r");
#endif
return;
}
if (argument[0] != '\0')
hash = atoi (argument);
else
hash = -1;
if (!str_cmp (arg, "hash")) {
#ifdef HASHSTR
ch->SendTextf ("Hash statistics:\n\r%s", hash_stats ());
if (hash != -1)
hash_dump (hash);
#else
ch->SendText ("Hash strings not enabled.\n\r");
#endif
}
}
// Stick a little fuzz on a number.
int number_fuzzy (int number)
{
switch (number_bits (2)) {
case 0: number -= 1; break;
case 3: number += 1; break;
}
return UMAX (1, number);
}
// Generate a random number.
int number_range (int from, int to)
{
if ((to = to - from + 1) <= 1)
return from;
return (number_mm () % to) + from;
}
// Generate a percentile roll.
int number_percent (void)
{
return number_mm () % 100;
}
// 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 ()
{
int *piState;
int iState;
piState = &rgiState [2];
piState [-2] = 55 - 55;
piState [-1] = 55 - 24;
piState [0] = ((int) CurrentTime.GetTotalSeconds ()) & ((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 ()
{
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 (char *str)
{
static char buf [MAX_STRING_LENGTH];
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 (! astr || ! bstr) {
bug ("str_cmp: astr (%s) bstr (%s)\n", astr, bstr);
return TRUE;
}
return stricmp (astr, bstr) != 0;
// for (; *astr || *bstr; astr++, bstr++) {
// if (LOWER (*astr) != LOWER (*bstr))
// return TRUE;
// }
//
// return FALSE;
}
// Compare strings, case insensitive, for prefix matching.
// Return TRUE if astr not a prefix of bstr
// (compatibility with historical functions).
BOOL str_prefix (const char *astr, const char *bstr)
{
if (!astr) {
bug ("Strn_cmp: null astr.");
return TRUE;
}
if (!bstr) {
bug ("Strn_cmp: null bstr.");
return TRUE;
}
for (; *astr; astr++, bstr++) {
if (LOWER (*astr) != LOWER (*bstr))
return TRUE;
}
return FALSE;
}
// 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;
int sstr2;
int 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;
int 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.
char *capitalize (const char *str)
{
static char strcap [MAX_STRING_LENGTH];
int i;
for (i = 0; str [i] != '\0'; i++)
strcap [i] = LOWER (str [i]);
strcap [i] = '\0';
strcap [0] = UPPER (strcap [0]);
return strcap;
}
// Returns a lowercase string.
char *strlower (const char *str)
{
static char strlow [MAX_STRING_LENGTH];
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 [MAX_STRING_LENGTH];
int i;
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 = tolower (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 [MAX_STRING_LENGTH];
if (!str) {
bug ("Aoran (): NULL str");
return "";
}
if (isavowel (str [0])
|| (strlen (str) > 1 && tolower (str[0]) == 'y' && !isavowel (str[1])))
strcpy (temp, "an ");
else
strcpy (temp, "a ");
strcat (temp, str);
return temp;
}
// Append a string to a file.
void append_file (CCharacter *ch, const char *file, char *str)
{
FILE *fp;
if (ch->IsNpc () || str[0] == '\0')
return;
fclose (fpLOG);
if ((fp = fopen (file, "a")) == NULL) {
perror (file);
ch->SendText ("Could not open the file!\n\r");
} else {
fprintf (fp, "[%5d] %s: %s\n",
ch->GetInRoom () ? ch->GetInRoom ()->vnum : 0, ch->GetName (),
str);
fclose (fp);
}
fpLOG = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}
// Append a string to a file.
void append_to_file (const char *file, char *str)
{
FILE *fp;
if ((fp = fopen (file, "a")) == NULL)
perror (file);
else {
fprintf (fp, "%s\n", str);
fclose (fp);
}
}
// Reports a bug.
void bug (const char *str, ...)
{
char buf [MAX_STRING_LENGTH];
FILE *fp;
struct stat fst;
if (fpArea) {
sprintf (buf, "FILE: %s LINE: %d", strArea, gAcount);
gpDoc->LogString (buf, LOG_BUG);
// if exists
if (stat (FileTable.GetName (SM_SHUTDOWN_FILE), &fst) != -1) {
if ((fp = fopen (FileTable.GetName (SM_SHUTDOWN_FILE), "a"))) {
fprintf (fp, "%s\n", buf);
fclose (fp);
}
}
}
strcpy (buf, "BUG: ");
va_list param;
va_start (param, str);
vsprintf (buf + strlen (buf), str, param);
va_end (param);
gpDoc->LogString (buf, LOG_BUG);
// Due to SmaugWiz changes, this code may be executed when fpLog is
// NULL. When this happens we really only want to print to stderr,
// which we have already done, so we skip the bug file.
if (fpLOG) {
fclose (fpLOG);
if ((fp = fopen (FileTable.GetName (SM_BUG_FILE), "a"))) {
fprintf (fp, "%s\n", buf);
fclose (fp);
}
fpLOG = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}
}
// Add a string to the boot-up log -Thoric
void BootLog (const char *str, ...)
{
char buf [MAX_STRING_LENGTH];
FILE *fp;
static char *BlMsg =
"---------------------[ Boot Log ]--------------------\n";
va_list param;
strcpy (buf, "BOOT: ");
va_start (param, str);
vsprintf (buf+strlen (buf), str, param);
va_end (param);
fclose (fpLOG);
if ((fp = fopen (FileTable.GetName (SM_BOOTLOG_FILE), "a"))) {
// If this is the first boot log call, put in a header
if (! bBootLog) {
fprintf (fp, BlMsg);
bBootLog = TRUE;
}
fprintf (fp, "%s\n", buf);
fclose (fp);
}
fpLOG = fopen (FileTable.GetName (SM_NULL_FILE), "r");
gpDoc->LogString (buf, LOG_BOOT);
}
// Dump a text file to a player, a line at a time -Thoric
void show_file (CCharacter *ch, const char *filename)
{
FILE *fp;
char buf [MAX_STRING_LENGTH];
int c;
int num = 0;
if ((fp = fopen (filename, "r"))) {
while (!feof (fp)) {
while ((buf [num] = fgetc (fp)) != EOF
&& buf [num] != '\n'
&& buf [num] != '\r'
&& num < (MAX_STRING_LENGTH-2))
num++;
c = fgetc (fp);
if ((c != '\n' && c != '\r') || c == buf [num])
ungetc (c, fp);
buf [num++] = '\n';
buf [num++] = '\r';
buf [num ] = '\0';
send_to_pager (buf, ch);
num = 0;
}
fclose (fp);
}
}
// Show the boot log file -Thoric
void do_dmesg (CCharacter *ch, char *argument)
{
set_pager_color (AT_LOG, ch);
show_file (ch, FileTable.GetName (SM_BOOTLOG_FILE));
}
// wizlist builder! -Thoric
void towizfile (const char *line)
{
int filler, xx;
char outline [MAX_STRING_LENGTH];
FILE *fp;
outline [0] = '\0';
if (line && line[0] != '\0') {
filler = (78-strlen (line));
if (filler < 1)
filler = 1;
filler /= 2;
for (xx = 0; xx < filler; xx++)
strcat (outline, " ");
strcat (outline, line);
}
strcat (outline, "\n\r");
fp = fopen (FileTable.GetName (SM_WIZLIST_FILE), "a");
if (fp) {
fputs (outline, fp);
fclose (fp);
}
}
void add_to_wizlist (const char *name, int level)
{
CWizData *wiz, *tmp;
#ifdef _DEBUG
gpDoc->LogString ("Adding to wizlist...");
#endif
wiz = new CWizData;
wiz->name = str_dup (name);
wiz->level = level;
if (! first_wiz) {
wiz->SetLast (NULL);
wiz->SetNext (NULL);
first_wiz = wiz;
last_wiz = wiz;
return;
}
// insert sort, of sorts
for (tmp = first_wiz; tmp; tmp = tmp->GetNext ())
if (level > tmp->level) {
if (!tmp->GetLast ())
first_wiz = wiz;
else
tmp->GetLast ()->SetNext (wiz);
wiz->SetLast (tmp->GetLast ());
wiz->SetNext (tmp);
tmp->SetLast (wiz);
return;
}
wiz->SetLast (last_wiz);
wiz->SetNext (NULL);
last_wiz->SetNext (wiz);
last_wiz = wiz;
}
// Wizlist builder -Thoric
void make_wizlist ()
{
FILE *fp;
char *word, *pLine;
int ilevel, iflags;
CWizData *wiz, *wiznext;
char buf [MAX_STRING_LENGTH];
first_wiz = last_wiz = NULL;
WIN32_FIND_DATA Fd;
HANDLE Dh = FindFirstFile (FileTable.MakeName (SD_GOD_DIR, "*"), &Fd);
if (Dh == INVALID_HANDLE_VALUE) then return;
BOOL bFirst = TRUE;
for (;;) {
if (! bFirst)
if (! FindNextFile (Dh, &Fd)) then break; // done
bFirst = FALSE;
CString fWiz = Fd.cFileName;
if (fWiz.GetAt (0) == '.') then continue;
CString Fname = FileTable.MakeName (SD_GOD_DIR, fWiz);
fp = fopen (Fname, "r");
if (fp) {
if (! feof (fp)) {
pLine = fread_line (fp);
word = ParseWord (pLine);
}
else word = "End";
ilevel = ParseNumber (pLine);
pLine = fread_line (fp);
word = ParseWord (pLine);
if (! str_cmp (word, "Pcflags"))
iflags = ParseNumber (pLine);
else
iflags = 0;
fclose (fp);
if (IS_SET (iflags, PCFLAG_RETIRED))
ilevel = MAX_LEVEL - 15;
if (IS_SET (iflags, PCFLAG_GUEST))
ilevel = MAX_LEVEL - 16;
add_to_wizlist (fWiz, ilevel);
}
}
FindClose (Dh);
remove (FileTable.GetName (SM_WIZLIST_FILE));
sprintf (buf, " Masters of the %s!", SysData.GetLongTitle ());
towizfile (buf);
ilevel = 65535;
buf [0] = '\0';
for (wiz = first_wiz; wiz; wiz = wiz->GetNext ()) {
if (wiz->level < ilevel) {
if (buf [0]) {
towizfile (buf);
buf [0] = '\0';
}
towizfile ("");
ilevel = wiz->level;
switch (ilevel) {
case MAX_LEVEL - 0: towizfile (" Supreme Entity"); break;
case MAX_LEVEL - 1: towizfile (" Infinite"); break;
case MAX_LEVEL - 2: towizfile (" Eternal"); break;
case MAX_LEVEL - 3: towizfile (" Ancient"); break;
case MAX_LEVEL - 4: towizfile (" Exalted Gods"); break;
case MAX_LEVEL - 5: towizfile (" Ascendant Gods"); break;
case MAX_LEVEL - 6: towizfile (" Greater Gods"); break;
case MAX_LEVEL - 7: towizfile (" Gods"); break;
case MAX_LEVEL - 8: towizfile (" Lesser Gods"); break;
case MAX_LEVEL - 9: towizfile (" Immortals"); break;
case MAX_LEVEL - 10: towizfile (" Demi Gods"); break;
case MAX_LEVEL - 11: towizfile (" Saviors"); break;
case MAX_LEVEL - 12: towizfile (" Creators"); break;
case MAX_LEVEL - 13: towizfile (" Acolytes"); break;
case MAX_LEVEL - 14: towizfile (" Neophytes"); break;
case MAX_LEVEL - 15: towizfile (" Retired"); break;
case MAX_LEVEL - 16: towizfile (" Guests"); break;
default:
towizfile (" Servants");
break;
}
}
if (strlen (buf) + strlen (wiz->name) > 76) {
towizfile (buf);
buf [0] = '\0';
}
strcat (buf, " ");
strcat (buf, wiz->name);
if (strlen (buf) > 70) {
towizfile (buf);
buf [0] = '\0';
}
}
if (buf [0])
towizfile (buf);
for (wiz = first_wiz; wiz; wiz = wiznext) {
wiznext = wiz->GetNext ();
delete wiz;
}
first_wiz = last_wiz = NULL;
}
void do_makewizlist (CCharacter *ch, char *argument)
{
make_wizlist ();
}
// mud prog functions
// This routine reads in scripts of MUDprograms from a file
int mprog_name_to_type (const char* name)
{
if (!str_cmp (name, "in_file_prog")) return IN_FILE_PROG;
if (!str_cmp (name, "act_prog")) return ACT_PROG;
if (!str_cmp (name, "speech_prog")) return SPEECH_PROG;
if (!str_cmp (name, "rand_prog")) return RAND_PROG;
if (!str_cmp (name, "fight_prog")) return FIGHT_PROG;
if (!str_cmp (name, "hitprcnt_prog")) return HITPRCNT_PROG;
if (!str_cmp (name, "death_prog")) return DEATH_PROG;
if (!str_cmp (name, "entry_prog")) return ENTRY_PROG;
if (!str_cmp (name, "greet_prog")) return GREET_PROG;
if (!str_cmp (name, "all_greet_prog")) return ALL_GREET_PROG;
if (!str_cmp (name, "give_prog")) return GIVE_PROG;
if (!str_cmp (name, "bribe_prog")) return BRIBE_PROG;
if (!str_cmp (name, "time_prog")) return TIME_PROG;
if (!str_cmp (name, "hour_prog")) return HOUR_PROG;
if (!str_cmp (name, "wear_prog")) return WEAR_PROG;
if (!str_cmp (name, "remove_prog")) return REMOVE_PROG;
if (!str_cmp (name, "sac_prog")) return SAC_PROG;
if (!str_cmp (name, "look_prog")) return LOOK_PROG;
if (!str_cmp (name, "exa_prog")) return EXA_PROG;
if (!str_cmp (name, "zap_prog")) return ZAP_PROG;
if (!str_cmp (name, "get_prog")) return GET_PROG;
if (!str_cmp (name, "drop_prog")) return DROP_PROG;
if (!str_cmp (name, "damage_prog")) return DAMAGE_PROG;
if (!str_cmp (name, "repair_prog")) return REPAIR_PROG;
if (!str_cmp (name, "greet_prog")) return GREET_PROG;
if (!str_cmp (name, "randiw_prog")) return RANDIW_PROG;
if (!str_cmp (name, "speechiw_prog")) return SPEECHIW_PROG;
if (!str_cmp (name, "pull_prog")) return PULL_PROG;
if (!str_cmp (name, "push_prog")) return PUSH_PROG;
if (!str_cmp (name, "sleep_prog")) return SLEEP_PROG;
if (!str_cmp (name, "rest_prog")) return REST_PROG;
if (!str_cmp (name, "rfight_prog")) return FIGHT_PROG;
if (!str_cmp (name, "enter_prog")) return ENTRY_PROG;
if (!str_cmp (name, "leave_prog")) return LEAVE_PROG;
if (!str_cmp (name, "rdeath_prog")) return DEATH_PROG;
if (!str_cmp (name, "script_prog")) return SCRIPT_PROG;
if (!str_cmp (name, "use_prog")) return USE_PROG;
return ERROR_PROG;
}
BOOL delete_obj (CObjIndexData *obj)
{
return TRUE;
}
BOOL delete_mob (CMobIndexData *mob)
{
return TRUE;
}
// 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.
CExitData *make_exit (CRoomIndexData *pRoomIndex, CRoomIndexData *to_room, short door)
{
CExitData *pexit, *texit;
BOOL broke;
pexit = new CExitData;
pexit->vdir = door;
pexit->rvnum = pRoomIndex->vnum;
pexit->SetToRoom (to_room);
pexit->distance = 1;
if (to_room) {
pexit->vnum = to_room->vnum;
texit = get_exit_to (to_room, rev_dir[door], pRoomIndex->vnum);
if (texit) { // assign reverse exit pointers
texit->rexit = pexit;
pexit->rexit = texit;
}
}
broke = FALSE;
for (texit = pRoomIndex->first_exit; texit; texit = texit->GetNext ())
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->GetPrev ())
pRoomIndex->first_exit = pexit;
else
texit->GetPrev ()->SetNext (pexit);
pexit->SetPrev (texit->GetPrev ());
pexit->SetNext (texit);
texit->SetPrev (pexit);
top_exit++;
return pexit;
}
pRoomIndex->last_exit->SetNext (pexit);
}
pexit->SetNext (NULL);
pexit->SetPrev (pRoomIndex->last_exit);
pRoomIndex->last_exit = pexit;
top_exit++;
return pexit;
}
void fix_area_exits (CAreaData *tarea)
{
CRoomIndexData *pRoomIndex;
CExitData *pexit, *rev_exit;
int rnum;
BOOL fexit;
for (rnum = tarea->low_r_vnum; rnum <= tarea->hi_r_vnum; rnum++) {
if ((pRoomIndex = RoomTable.GetRoom (rnum)) == NULL)
continue;
fexit = FALSE;
pexit = pRoomIndex->first_exit;
for (; pexit; pexit = pexit->GetNext ()) {
fexit = TRUE;
pexit->rvnum = pRoomIndex->vnum;
if (pexit->vnum <= 0)
pexit->SetToRoom (NULL);
else
pexit->SetToRoom (RoomTable.GetRoom (pexit->vnum));
}
if (!fexit)
pRoomIndex->SetNoMob ();
}
for (rnum = tarea->low_r_vnum; rnum <= tarea->hi_r_vnum; rnum++) {
if ((pRoomIndex = RoomTable.GetRoom (rnum)) == NULL)
continue;
pexit = pRoomIndex->first_exit;
for (; pexit; pexit = pexit->GetNext ()) {
if (pexit->GetToRoom () && !pexit->rexit) {
rev_exit = get_exit_to (pexit->GetToRoom (),
rev_dir [pexit->vdir], pRoomIndex->vnum);
if (rev_exit) {
pexit->rexit = rev_exit;
rev_exit->rexit = pexit;
}
}
}
}
}
CAreaData *LoadAreaFile (const CString Fname, BOOL bBoot /* = FALSE */,
CAreaData* pArea /* = NULL */,
BOOL bBuild /* = FALSE */)
{
strcpy (strArea, FileTable.MakeAreaName (Fname, bBuild));
if (! (fpArea = fopen (strArea, "r"))) {
perror (strArea);
bug ("load_area: error loading file (can't open)");
bug (strArea);
return NULL;
}
BOOL bNewArea = pArea == NULL;
CString Word;
char *pLine = NULL;
gAcount = 0;
pLine = fread_line (fpArea);
Word = ParseWord (pLine);
if (Word != "#VERSION") {
bug ("%s: No Version Found.", strArea);
fclose (fpArea);
if (bBoot)
ThrowSmaugException (SE_AREA);
return NULL;
}
int Version = ParseNumber (pLine);
if (Version != SW_CURRENT_AV) {
bug ("%s: Cannot load Version %d Areas.", strArea, Version);
fclose (fpArea);
if (bBoot)
ThrowSmaugException (SE_AREA);
return NULL;
}
pLine = fread_line (fpArea);
Word = ParseWord (pLine);
if (Word == "#HELPS") {
if (bBoot)
LoadAllHelp (fpArea);
return NULL;
}
if (Word != "#AREA") {
bug ("%s: No Area name Found.", strArea);
fclose (fpArea);
if (bBoot)
ThrowSmaugException (SE_AREA);
return NULL;
}
CString AreaName = ParseCString (pLine, fpArea);
if (bNewArea)
pArea = new CAreaData (Fname, AreaName, Version);
// hack to get around passing bBoot all over the place
BOOL oldBootFlag = fBootDb;
fBootDb = bBoot;
pArea->Load (fpArea, gAcount);
fBootDb = oldBootFlag;
fclose (fpArea);
fpArea = NULL;
if (! pArea->IsLoaded ()) {
gpDoc->m_pLog->Printf (LOG_ALWAYS, "(%s)\n", NCCP Fname);
delete pArea;
return NULL;
}
gpDoc->m_pLog->Printf (LOG_ALWAYS,
"%-14s: Rooms: %5d - %-5d Objs: %5d - %-5d Mobs: %5d - %d\n",
NCCP pArea->m_Filename,
pArea->low_r_vnum, pArea->hi_r_vnum,
pArea->low_o_vnum, pArea->hi_o_vnum,
pArea->low_m_vnum, pArea->hi_m_vnum);
return pArea;
}
void AddArea (CAreaData* pArea)
{
AreaList.AddTail (pArea);
sort_area (pArea, FALSE);
}
void load_reserved ()
{
FILE *fp;
CString Fname = FileTable.MakeName (SD_SYSTEM_DIR, "reserved.lst");
if (! (fp = fopen (Fname, "r")))
return;
gpDoc->LogString ("Loading reserved names", LOG_BOOT);
for ( ; ; ) {
if (feof (fp)) {
bug ("Load_reserved: no $ found.");
fclose (fp);
return;
}
CString Rname = fread_string_nohash (fp);
if (Rname [0] == '$')
break;
ReservedNamesList.AddTail (Rname);
}
fclose (fp);
}
// 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 ()
{
FILE *fp;
char buf [MAX_STRING_LENGTH];
CAreaData *pArea;
char line [81];
char word [81];
int low, hi;
int mlow, mhi, olow, ohi, rlow, rhi;
char temp;
WIN32_FIND_DATA Fd;
HANDLE Dh = FindFirstFile (FileTable.MakeName (SD_GOD_DIR, "*"), &Fd);
if (Dh == INVALID_HANDLE_VALUE) then return;
gpDoc->LogString ("Loading gods...", LOG_BUILD);
BOOL bFirst = TRUE;
for (;;) {
if (! bFirst)
if (! FindNextFile (Dh, &Fd)) then break; // done
bFirst = FALSE;
CString Auth = Fd.cFileName;
if (Auth.GetAt (0) == '.') then continue;
CString Fname = FileTable.MakeName (SD_GOD_DIR, Auth);
if (! (fp = fopen (Fname, "r"))) {
bug ("Load_buildlist: invalid file: %s", NCCP Fname);
continue;
}
gpDoc->LogString (Auth, LOG_BUILD);
BOOL bGoodGod = TRUE;
rlow=rhi=olow=ohi=mlow=mhi=0;
while (!feof (fp) && !ferror (fp)) {
low = 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, "Level")) {
if (low < LEVEL_IMMORTAL) {
gpDoc->LogStringf (LOG_NORMAL, LEVEL_LOG,
"%s: God file with level %d < %d",
NCCP Auth, low, LEVEL_IMMORTAL);
bGoodGod = FALSE;
break;
}
}
if (!strcmp (word, "RoomRange"))
rlow = low, rhi = hi;
else if (!strcmp (word, "MobRange"))
mlow = low, mhi = hi;
else if (!strcmp (word, "ObjRange"))
olow = low, ohi = hi;
}
fclose (fp);
if (bGoodGod && rlow && rhi) {
CString Aname = FileTable.MakeBuildName (Auth);
if (! (fp = fopen (Aname, "r"))) {
bug ("Load_buildlist: cannot open area file for read");
perror (Aname);
continue;
}
sprintf (buf, "{PROTO} %s's area in progress", NCCP Auth);
pArea = new CAreaData (Aname, buf, SW_CURRENT_AV);
pArea->m_Author = Auth;
fclose (fp);
pArea->low_r_vnum = rlow; pArea->hi_r_vnum = rhi;
pArea->low_m_vnum = mlow; pArea->hi_m_vnum = mhi;
pArea->low_o_vnum = olow; pArea->hi_o_vnum = ohi;
pArea->low_soft_range = -1; pArea->hi_soft_range = -1;
pArea->low_hard_range = -1; pArea->hi_hard_range = -1;
BuildList.AddTail (pArea);
gpDoc->m_pLog->Printf (LOG_ALWAYS,
"%-14s: Rooms: %5d - %-5d Objs: %5d - %-5d "
"Mobs: %5d - %-5d\n", NCCP pArea->m_Filename,
pArea->low_r_vnum, pArea->hi_r_vnum,
pArea->low_o_vnum, pArea->hi_o_vnum,
pArea->low_m_vnum, pArea->hi_m_vnum);
sort_area (pArea, TRUE);
}
}
FindClose (Dh);
}
// Sort by room vnums -Altrag & Thoric
void sort_area (CAreaData *pArea, BOOL bProto)
{
if (!pArea) {
bug ("Sort_area: NULL pArea");
return;
}
CPtrList &List = bProto ? BuildList.SortList : AreaList.SortList;
POSITION CurrPos, pos = List.GetHeadPosition ();
while (pos) {
CurrPos = pos;
CAreaData &Ar = *(CAreaData*) List.GetNext (pos);
if (pArea->low_r_vnum < Ar.low_r_vnum) {
List.InsertBefore (CurrPos, pArea);
return;
}
}
List.AddTail (pArea);
}
// Display vnums currently assigned to areas -Altrag & Thoric
// Sorted, and flagged if loaded.
void show_vnums (CCharacter *ch, int low, int high, BOOL bProto, BOOL shownl,
char *loadst, char *notloadst)
{
int count, loaded;
count = loaded = 0;
set_pager_color (AT_PLAIN, ch);
CPtrList &List = bProto ? BuildList.SortList : AreaList.SortList;
POSITION pos = List.GetHeadPosition ();
while (pos) {
CAreaData &Ar = *(CAreaData*) List.GetNext (pos);
if (Ar.IsDeleted ())
continue;
if (Ar.low_r_vnum < low)
continue;
if (Ar.hi_r_vnum > high)
break;
if (Ar.IsLoaded ())
++loaded;
else if (! shownl)
continue;
pager_printf (ch, "%-15s| Rooms: %5d - %-5d"
" Objs: %5d - %-5d Mobs: %5d - %-5d%s\n\r",
(Ar.m_Filename.IsEmpty () ? "(invalid)" : NCCP Ar.m_Filename),
Ar.low_r_vnum, Ar.hi_r_vnum, Ar.low_o_vnum, Ar.hi_o_vnum,
Ar.low_m_vnum, Ar.hi_m_vnum,
Ar.IsLoaded () ? loadst : notloadst);
++count;
}
pager_printf (ch, "Areas listed: %d Loaded: %d\n\r", count, loaded);
}
void show_znums (CCharacter *ch, int low, int high, BOOL bProto, BOOL shownl,
char *loadst, char *notloadst)
{
int count, loaded;
count = loaded = 0;
set_pager_color (AT_PLAIN, ch);
CPtrList &List = bProto ? BuildList.SortList : AreaList.SortList;
POSITION pos = List.GetHeadPosition ();
while (pos) {
CAreaData &Ar = *(CAreaData*) List.GetNext (pos);
if (Ar.IsDeleted ())
continue;
if (Ar.low_r_vnum < low)
continue;
if (Ar.hi_r_vnum > high)
break;
if (Ar.IsLoaded ())
++loaded;
else if (! shownl)
continue;
pager_printf (ch, "&G%-22s&Y| &W%5d - %-5d &Y|"
" &W%5d - %-5d &Y| &W%5d - %-5d%s &Y|\n\r",
(Ar.m_Filename.IsEmpty () ? "(invalid)" : NCCP Ar.m_Filename),
Ar.low_r_vnum, Ar.hi_r_vnum, Ar.low_o_vnum, Ar.hi_o_vnum,
Ar.low_m_vnum, Ar.hi_m_vnum,
Ar.IsLoaded () ? loadst : notloadst);
++count;
}
pager_printf (ch, "Areas listed: %d Loaded: %d\n\r", count, loaded);
}
// Shows prototype vnums ranges, and if loaded
void do_vnums (CCharacter *ch, char *argument)
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
int low, high;
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
low = 0; high = 2097152000; // was 32766
if (arg1 [0] != '\0') {
low = atoi (arg1);
if (arg2 [0] != '\0')
high = atoi (arg2);
}
show_vnums (ch, low, high, TRUE, TRUE, " *", "");
}
/*
* Shows installed areas, sorted. Mark unloaded areas with an X
*/
void do_zones (CCharacter *ch, char *argument)
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
int low, high;
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
low = 0; high = 2097152000; // was 32766
if (arg1[0] != '\0')
{
low = atoi (arg1);
if (arg2[0] != '\0')
high = atoi (arg2);
}
send_to_pager("\n\r &c&GZones &Y| &GRooms &Y| &GObjs &Y| &GMobs &Y| \n\r", ch);
send_to_pager("----------------------+---------------+---------------+---------------+\n\r", ch);
show_znums (ch, low, high, FALSE, TRUE, "", " X");
}
// Show prototype areas, sorted. Only show loaded areas
void do_newzones (CCharacter *ch, char *argument)
{
char arg1[MAX_INPUT_LENGTH];
char arg2[MAX_INPUT_LENGTH];
int low, high;
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
low = 0; high = 2097152000; // was 32766
if (arg1[0] != '\0')
{
low = atoi (arg1);
if (arg2[0] != '\0')
high = atoi (arg2);
}
send_to_pager("\n\r &c&GZones &Y| &GRooms &Y| &GObjs &Y| &GMobs &Y| \n\r", ch);
send_to_pager("----------------------+---------------+---------------+---------------+\n\r", ch);
show_znums (ch, low, high, TRUE, FALSE, "", " X");
}
void load_banlist ()
{
CBanData *pban;
FILE *fp;
int number;
if (! (fp = fopen (FileTable.GetName (SM_BAN_LIST), "r")))
return;
gpDoc->LogString ("Loading bans...", LOG_BOOT);
for (;;) {
if (feof (fp)) {
bug ("Load_banlist: no -1 found.");
fclose (fp);
return;
}
char *pLine = fread_line (fp);
number = ParseNumber (pLine);
if (number == -1) {
fclose (fp);
return;
}
pban = new CBanData;
pban->level = number;
pban->name = ParseStringNohash (pLine, fp);
if (*pLine++ == '~')
pban->ban_time = ParseStringNohash (pLine, fp);
else
pban->ban_time = str_dup ("(unrecorded)");
LINK (pban, first_ban, last_ban);
}
}
void ClearDatabase ()
{
// Take 'em out in reverse order
CObjectMenu::UnInitObjectMenu ();
// The ban list
CBanData *pNban, *pBan = first_ban;
while (pBan) {
pNban = pBan->GetNext ();
delete pBan;
pBan = pNban;
}
first_ban = last_ban = NULL;
// The council list
CCouncilData *pNcouncil, *pCouncil = first_council;
while (pCouncil) {
pNcouncil = pCouncil->GetNext ();
delete pCouncil;
pCouncil = pNcouncil;
}
first_council = last_council = NULL;
// The deity list
CDeityData *pNdeity, *pDeity = first_deity;
while (pDeity) {
pNdeity = pDeity->GetNext ();
delete pDeity;
pDeity = pNdeity;
}
first_deity = last_deity = NULL;
// The clan list
ClanList.RemoveAll ();
// The board list
BoardList.RemoveAll ();
// The build list
BuildList.RemoveAll ();
// The Area list
AreaList.RemoveAll ();
// The auction
delete auction;
auction = NULL;
// The wiz list
CWizData *pNwiz, *pWiz = first_wiz;
while (pWiz) {
pNwiz = pWiz->GetNext ();
delete pWiz;
pWiz = pNwiz;
}
// The herb table
HerbTable.RemoveAll ();
// The class table
ClassTable.RemoveAll ();
// The skill table
SkillTable.RemoveAll ();
// The Race Table
RaceTable.RemoveAll ();
// Socials
SocialTable.RemoveAll ();
// Languages
LanguageTable.RemoveAll ();
// The Command table
CommandTable.RemoveAll ();
// These are things loaded with the areas, which are not
// deleted when an area is deleted.
// Repair Shops
CRepairShopData *pNrshop, *prShop = first_repair;
while (prShop) {
pNrshop = prShop->GetNext ();
delete prShop;
prShop = pNrshop;
}
first_repair = last_repair = NULL;
// Other Shops
CShopData *pNshop, *pShop = first_shop;
while (pShop) {
pNshop = pShop->GetNext ();
delete pShop;
pShop = pNshop;
}
first_shop = last_shop = NULL;
// Rooms, mobs, and objects should be all deleted, but
// we will make sure here.
RoomTable.RemoveAll ();
MobTable.RemoveAll ();
OIdxTable.RemoveAll ();
ExtractedObjList.RemoveAll ();
// Mob Act List
CActProgData *pNact, *pAct = mob_act_list;
while (pAct) {
pNact = pAct->GetNext ();
delete pAct;
pAct = pNact;
}
mob_act_list = NULL;
// The Help list
HelpList.RemoveAll ();
// The rest are misc or items created while running the game, and
// which do not link into any of the lists used by boot items.
// These should be all the NPC characters
CCharacter *pNch, *pCh = first_char;
while (pCh) {
pNch = pCh->GetNext ();
delete pCh;
pCh = pNch;
}
first_char = last_char = NULL;
CTeleportData *pNtel, *pTele = first_teleport;
while (pTele) {
pNtel = pTele->GetNext ();
delete pTele;
pTele = pNtel;
}
first_teleport = last_teleport = NULL;
CRoomIndexData *pRoom, *pNroom;
for (int hash = 0; hash < MAX_VROOMS; ++hash) {
pRoom = GetVRoomFromHash (hash);
while (pRoom) {
pNroom = pRoom->GetNext ();
delete pRoom;
pRoom = pNroom;
}
}
SysData.Empty ();
DeleteAllHash ();
}
// Check to make sure range of vnums is free - Scryn 2/27/96
void do_check_vnums (CCharacter *ch, char *argument)
{
char buf [MAX_STRING_LENGTH];
char arg1 [MAX_STRING_LENGTH];
char arg2 [MAX_STRING_LENGTH];
int low_range, high_range;
BOOL bRoom = FALSE, bMob = FALSE, bObj = FALSE, bAll = FALSE;
argument = one_argument (argument, arg1);
argument = one_argument (argument, arg2);
if (arg1[0] == '\0') {
ch->SendText ("Please specify room, mob, object, or all as your "
"first argument.\n\r");
return;
}
if (!str_cmp (arg1, "room"))
bRoom = TRUE;
else if (!str_cmp (arg1, "mob"))
bMob = TRUE;
else if (!str_cmp (arg1, "object"))
bObj = TRUE;
else if (!str_cmp (arg1, "all"))
bAll = TRUE;
else {
ch->SendText ("Please specify room, mob, or object as your "
"first argument.\n\r");
return;
}
if (arg2 [0] == '\0') {
ch->SendText ("Please specify the low end of the range to "
"be searched.\n\r");
return;
}
if (argument [0] == '\0') {
ch->SendText ("Please specify the high end of the range to "
"be searched.\n\r");
return;
}
low_range = atoi (arg2);
high_range = atoi (argument);
if (low_range < 1 || low_range > 2097152000) { // was 32767
ch->SendText ("Invalid argument for bottom of range.\n\r");
return;
}
if (high_range < 1 || high_range > 2097152000) {
ch->SendText ("Invalid argument for top of range.\n\r");
return;
}
if (high_range < low_range) {
ch->SendText ("Bottom of range must be below top of range.\n\r");
return;
}
if (bAll) {
sprintf (buf, "room %d %d", low_range, high_range);
do_check_vnums (ch, buf);
sprintf (buf, "mob %d %d", low_range, high_range);
do_check_vnums (ch, buf);
sprintf (buf, "object %d %d", low_range, high_range);
do_check_vnums (ch, buf);
return;
}
set_char_color (AT_PLAIN, ch);
ShowConflicts (ch, AreaList.SortList, low_range, high_range,
bRoom, bMob, bObj);
ShowConflicts (ch, BuildList.SortList, low_range, high_range,
bRoom, bMob, bObj);
}
void ShowConflicts (CCharacter* ch, CPtrList& List, int low, int hi,
BOOL bRoom, BOOL bMob, BOOL bObj)
{
POSITION pos = List.GetHeadPosition ();
while (pos) {
CAreaData &Ar = *(CAreaData*) List.GetNext (pos);
if (Ar.IsDeleted ())
continue;
BOOL bConflict = FALSE;
if (bRoom) {
if (low < Ar.low_r_vnum && Ar.low_r_vnum < hi)
bConflict = TRUE;
if (low < Ar.hi_r_vnum && Ar.hi_r_vnum < hi)
bConflict = TRUE;
if ((low >= Ar.low_r_vnum) && (low <= Ar.hi_r_vnum))
bConflict = TRUE;
if ((hi <= Ar.hi_r_vnum) && (hi >= Ar.low_r_vnum))
bConflict = TRUE;
}
if (bMob) {
if (low < Ar.low_m_vnum && Ar.low_m_vnum < hi)
bConflict = TRUE;
if (low < Ar.hi_m_vnum && Ar.hi_m_vnum < hi)
bConflict = TRUE;
if ((low >= Ar.low_m_vnum) && (low <= Ar.hi_m_vnum))
bConflict = TRUE;
if ((hi <= Ar.hi_m_vnum) && (hi >= Ar.low_m_vnum))
bConflict = TRUE;
}
if (bObj) {
if (low < Ar.low_o_vnum && Ar.low_o_vnum < hi)
bConflict = TRUE;
if (low < Ar.hi_o_vnum && Ar.hi_o_vnum < hi)
bConflict = TRUE;
if ((low >= Ar.low_o_vnum) && (low <= Ar.hi_o_vnum))
bConflict = TRUE;
if ((hi <= Ar.hi_o_vnum) && (hi >= Ar.low_o_vnum))
bConflict = TRUE;
}
CString Msg, Msg2;
if (bConflict) {
Msg.Format ("Conflict:%-15s| ",
(Ar.m_Filename.IsEmpty () ? "(invalid)" : NCCP Ar.m_Filename));
if (bRoom)
Msg2.Format ("Rooms: %5d - %-5d\n\r", Ar.low_r_vnum,
Ar.hi_r_vnum);
if (bMob)
Msg2.Format ("Mobs: %5d - %-5d\n\r", Ar.low_m_vnum,
Ar.hi_m_vnum);
if (bObj)
Msg2.Format ("Objects: %5d - %-5d\n\r", Ar.low_o_vnum,
Ar.hi_o_vnum);
Msg += Msg2;
ch->SendText (Msg);
}
}
}
void remap_slot_numbers ()
{
CSkill *pSkill;
CSmaugAffect *pAff;
char tmp [32];
int sn;
gpDoc->LogString ("Remapping slots to sns", LOG_BOOT);
for (sn = 0; sn < SkillTable.GetCount (); ++sn) {
if (pSkill = SkillTable.GetSkill (sn)) {
for (pAff = pSkill->GetAffects (); pAff; pAff = pAff->GetNext ())
if (pAff->location == APPLY_WEAPONSPELL
|| pAff->location == APPLY_WEARSPELL
|| pAff->location == APPLY_REMOVESPELL
|| pAff->location == APPLY_STRIPSN
|| pAff->location == APPLY_RECURRINGSPELL) {
sprintf (tmp, "%d", slot_lookup (atoi (pAff->modifier)));
delete pAff->modifier;
pAff->modifier = str_dup (tmp);
}
}
}
}