/****************************************************************************
* [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. *
****************************************************************************/
// mobiles.cpp
#include "stdafx.h"
#include "smaug.h"
#include "language.h"
#include "races.h"
#include "class.h"
#include "Smaugx.h"
#include "mobiles.h"
// Create a new INDEX mobile (for online building) -Thoric
// Option to clone an existing index mobile.
CMobIndexData *make_mobile (int vnum, int cvnum, char *name)
{
CMobIndexData *pMobIndex, *cMobIndex;
char buf [MAX_STRING_LENGTH];
if (cvnum > 0)
cMobIndex = MobTable.GetMob (cvnum);
else
cMobIndex = NULL;
pMobIndex = new CMobIndexData (vnum);
pMobIndex->SetPlayerName (STRALLOC (name));
if (! cMobIndex) {
sprintf (buf, "a newly created %s", name);
pMobIndex->SetShortDescr (STRALLOC (buf));
sprintf (buf,
"Some god abandoned a newly created %s here.\n\r", name);
pMobIndex->SetLongDescr (STRALLOC (buf));
pMobIndex->SetDescription (STRALLOC (""));
pMobIndex->SetNpc ();
pMobIndex->SetPrototype ();
pMobIndex->level = 1;
pMobIndex->position = POS_STANDING;
pMobIndex->defposition = POS_STANDING;
pMobIndex->perm_str = 13;
pMobIndex->perm_dex = 13;
pMobIndex->perm_int = 13;
pMobIndex->perm_wis = 13;
pMobIndex->perm_cha = 13;
pMobIndex->perm_con = 13;
pMobIndex->perm_lck = 13;
pMobIndex->m_Class = NPC_WARRIOR;
pMobIndex->SetSpeaks (LANG_COMMON);
pMobIndex->SetSpeaking (LANG_COMMON);
pMobIndex->SetComplex (); // all new mobs are complex
} else {
pMobIndex->SetShortDescr ( QUICKLINK (cMobIndex->GetShortDescr ()));
pMobIndex->SetLongDescr (QUICKLINK (cMobIndex->GetLongDescr ()));
pMobIndex->SetDescription (QUICKLINK (cMobIndex->GetDescription ()));
pMobIndex->SetActFlags (cMobIndex->GetActFlags ());
pMobIndex->SetPrototype ();
pMobIndex->SetAffectFlags (cMobIndex->GetAffectFlags ());
pMobIndex->spec_fun = cMobIndex->spec_fun;
pMobIndex->alignment = cMobIndex->alignment;
pMobIndex->level = cMobIndex->level;
pMobIndex->mobthac0 = cMobIndex->mobthac0;
pMobIndex->ac = cMobIndex->ac;
pMobIndex->hitnodice = cMobIndex->hitnodice;
pMobIndex->hitsizedice = cMobIndex->hitsizedice;
pMobIndex->hitplus = cMobIndex->hitplus;
pMobIndex->damnodice = cMobIndex->damnodice;
pMobIndex->damsizedice = cMobIndex->damsizedice;
pMobIndex->damplus = cMobIndex->damplus;
pMobIndex->gold = cMobIndex->gold;
pMobIndex->exp = cMobIndex->exp;
pMobIndex->position = cMobIndex->position;
pMobIndex->defposition = cMobIndex->defposition;
pMobIndex->sex = cMobIndex->sex;
pMobIndex->perm_str = cMobIndex->perm_str;
pMobIndex->perm_dex = cMobIndex->perm_dex;
pMobIndex->perm_int = cMobIndex->perm_int;
pMobIndex->perm_wis = cMobIndex->perm_wis;
pMobIndex->perm_cha = cMobIndex->perm_cha;
pMobIndex->perm_con = cMobIndex->perm_con;
pMobIndex->perm_lck = cMobIndex->perm_lck;
pMobIndex->race = cMobIndex->race;
pMobIndex->m_Class = cMobIndex->m_Class;
pMobIndex->xflags = cMobIndex->xflags;
pMobIndex->resistant = cMobIndex->resistant;
pMobIndex->immune = cMobIndex->immune;
pMobIndex->susceptible = cMobIndex->susceptible;
pMobIndex->numattacks = cMobIndex->numattacks;
pMobIndex->SetComplex (); // all new mobs are complex
pMobIndex->SetAttackFlags (cMobIndex->GetAttackFlags ());
pMobIndex->SetDefenseFlags (cMobIndex->GetDefenseFlags ());
pMobIndex->SetSpeaksFlags (cMobIndex->GetSpeaksFlags ());
pMobIndex->SetSpeaking (cMobIndex->GetSpeaking ());
}
MobTable.Add (pMobIndex, vnum);
return pMobIndex;
}
void CMobIndexData::Read (FILE* fp)
{
char letter;
char *pLine;
int x1, x2, x3, x4, x5;
// for now this is the way I'm going to handle this so that the line
// count gets incremented. Later perhaps I can modify fread_string to
// handle it, or build a new function to do both.
pLine = fread_line (fp);
m_pPlayerName = ParseString (pLine, fp);
pLine = fread_line (fp);
m_pShortDescr = ParseString (pLine, fp);
pLine = fread_line (fp);
m_pLongDescr = ParseString (pLine, fp);
pLine = fread_line (fp);
m_pDescription = ParseString (pLine, fp);
m_pLongDescr [0] = UPPER (m_pLongDescr [0]);
m_pDescription [0] = UPPER (m_pDescription [0]);
pLine = fread_line (fp);
m_Act.Parse (pLine);
m_Act.SetNpc ();
m_Affected.Parse (pLine);
pShop = NULL;
rShop = NULL;
alignment = ParseNumber (pLine);
letter = *pLine++;
if (letter != 'S' && letter != 'C') {
bug ("Load_mobiles: vnum %d: letter '%c' not S or C.", vnum, letter);
shutdown_mud ("bad mob data");
ThrowSmaugException (SE_MOBILE);
}
pLine = fread_line (fp);
level = ParseNumber (pLine);
mobthac0 = ParseNumber (pLine);
ac = ParseNumber (pLine);
hitnodice = ParseNumber (pLine);
++pLine; // skip over the 'd'
hitsizedice = ParseNumber (pLine);
++pLine; // skip over the '+'
hitplus = ParseNumber (pLine);
damnodice = ParseNumber (pLine);
++pLine; // skip over the 'd'
damsizedice = ParseNumber (pLine);
++pLine; // skip over the '+'
damplus = ParseNumber (pLine);
pLine = fread_line (fp);
x1 = x2 = x3 = 0;
gold = exp = 0;
m_MobInvisLevel = 0;
sscanf (pLine, "%d %d %u", &x1, &x2, &x3);
gold = x1;
exp = x2;
m_MobInvisLevel = x3;
pLine = fread_line (fp);
position = ParseNumber (pLine);
defposition = ParseNumber (pLine);
sex = ParseNumber (pLine);
if (letter == 'C') { // Realms complex mob -Thoric
m_bComplex = TRUE;
pLine = fread_line (fp);
perm_str = ParseNumber (pLine);
perm_int = ParseNumber (pLine);
perm_wis = ParseNumber (pLine);
perm_dex = ParseNumber (pLine);
perm_con = ParseNumber (pLine);
perm_cha = ParseNumber (pLine);
perm_lck = ParseNumber (pLine);
pLine = fread_line (fp);
saving_poison_death = ParseNumber (pLine);
saving_wand = ParseNumber (pLine);
saving_para_petri = ParseNumber (pLine);
saving_breath = ParseNumber (pLine);
saving_spell_staff = ParseNumber (pLine);
pLine = fread_line (fp);
x1 = x2 = x3 = x4 = x5 = 0;
sscanf (pLine, "%d %d %d %d %d", &x1, &x2, &x3, &x4, &x5);
race = x1;
m_Class = x2;
height = x3;
weight = x4;
numattacks = x5;
pLine = fread_line (fp);
LanguageTable.LoadFromString (m_Speaks, NCCP ParseCString (pLine, fp));
pLine = fread_line (fp);
m_Speaking = LanguageTable.GetLanguage (ParseCString (pLine, fp));
// make sure the mob speaks something
if (m_Speaks.IsEmpty ())
SetSpeaks (LanguageTable.GetCommon ());
if (! m_Speaking)
m_Speaking = LanguageTable.GetCommon ();
pLine = fread_line (fp);
hitroll = ParseNumber (pLine);
damroll = ParseNumber (pLine);
xflags = ParseNumber (pLine);
resistant = ParseNumber (pLine);
immune = ParseNumber (pLine);
susceptible = ParseNumber (pLine);
m_Attacks.Parse (pLine);
m_Defenses.Parse (pLine);
} else {
m_bComplex = FALSE;
perm_str = 13;
perm_dex = 13;
perm_int = 13;
perm_wis = 13;
perm_cha = 13;
perm_con = 13;
perm_lck = 13;
race = 0;
m_Class = 3;
xflags = 0;
resistant = 0;
immune = 0;
susceptible = 0;
numattacks = 0;
m_Attacks.Empty ();
m_Defenses.Empty ();
}
}
// clean out a mobile (index) (leave list pointers intact) -Thoric
void CMobIndexData::Clear ()
{
STRFREE (m_pPlayerName);
m_pPlayerName = NULL;
STRFREE (m_pShortDescr);
m_pShortDescr = NULL;
STRFREE (m_pLongDescr);
m_pLongDescr = NULL;
STRFREE (m_pDescription);
m_pDescription = NULL;
spec_fun = NULL;
pShop = NULL;
rShop = NULL;
m_Progtypes.Empty ();
count = killed = 0;
SetSex (0);
SetLevel (0);
m_Act.Empty ();
m_Affected.Empty ();
alignment = mobthac0 = 0;
ac = hitnodice = 0;
hitsizedice = hitplus = 0;
damnodice = damsizedice = 0;
damplus = gold = 0;
exp = position = 0;
defposition = height = 0;
weight = 0;
while (! MobPrgList.IsEmpty ())
delete (CMobProgData*) MobPrgList.RemoveTail ();
MobPrgList.RemoveAll ();
}
// This procedure is responsible for reading any in_file MUDprograms.
void CMobIndexData::ReadPrograms (FILE *fp)
{
char letter;
BOOL done = FALSE;
char* pLine = fread_line (fp);
if ((letter = *pLine++) != '>') {
bug ("LoadMobiles: vnum %d MUDPROG char", vnum);
ThrowSmaugException (SE_MOBPROG);
}
CMobProgData *pMprg = new CMobProgData;
MobPrgList.AddTail (pMprg);
while (!done) {
pMprg->type = mprog_name_to_type (ParseWord (pLine));
switch (pMprg->type) {
case ERROR_PROG:
bug ("LoadMobiles: vnum %d MUDPROG type.", vnum);
ThrowSmaugException (SE_MOBPROG);
break;
case IN_FILE_PROG:
bug ("Error: Mobile %d. SmaugWiz does not handle "
"file Mob Progs.", vnum);
ThrowSmaugException (SE_MOBPROG);
break;
default:
m_Progtypes.SetBit (pMprg->type);
pMprg->arglist = ParseString (pLine, fp);
pLine = fread_line (fp);
pMprg->comlist = ParseString (pLine, fp);
pLine = fread_line (fp);
switch (letter = *pLine++) {
case '>':
pMprg = new CMobProgData;
MobPrgList.AddTail (pMprg);
break;
case '|':
done = TRUE;
break;
default:
bug ("LoadMobiles: vnum %d bad MUDPROG.", vnum);
ThrowSmaugException (SE_MOBPROG);
break;
}
break;
}
}
}
void CMobIndexData::Write (FILE *fp)
{
m_bComplex = TRUE; // write all mobs as complex
fprintf (fp, "#%d\n", vnum);
fprintf (fp, "%s~\n", m_pPlayerName);
fprintf (fp, "%s~\n", m_pShortDescr);
fprintf (fp, "%s~\n", strip_cr (m_pLongDescr));
fprintf (fp, "%s~\n", strip_cr (m_pDescription));
fprintf (fp, "%s ", m_Act.PrintVector ());
fprintf (fp, "%s %d C\n", GetAffectFlags ().PrintVector (),
alignment);
fprintf (fp, "%d %d %d ", level, mobthac0, ac);
fprintf (fp, "%dd%d+%d ", hitnodice, hitsizedice, hitplus);
fprintf (fp, "%dd%d+%d\n", damnodice, damsizedice, damplus);
fprintf (fp, "%d %d %d\n", gold, exp, m_MobInvisLevel);
fprintf (fp, "%d %d %d\n", position, defposition, sex);
// This data section is for complex mobs, but now is written for all.
fprintf (fp, "%d %d %d %d %d %d %d\n", perm_str, perm_int,
perm_wis, perm_dex, perm_con, perm_cha, perm_lck);
fprintf (fp, "%d %d %d %d %d\n",
saving_poison_death, saving_wand, saving_para_petri,
saving_breath, saving_spell_staff);
fprintf (fp, "%d %d %d %d %d\n", race, m_Class, height, weight,
numattacks);
fprintf (fp, "%s~\n", LanguageTable.PrintAssigned (GetSpeaksFlags ()));
fprintf (fp, "%s~\n", LanguageTable.GetName (GetSpeaking ()));
fprintf (fp, "%d %d %d %d %d %d %s %s\n",
hitroll, damroll, xflags, resistant, immune, susceptible,
NCCP GetAttackFlags ().PrintVector (),
NCCP GetDefenseFlags ().PrintVector ());
// End of complex section
if (! MobPrgList.IsEmpty ()) {
POSITION pos = MobPrgList.GetHeadPosition ();
while (pos) {
CMobProgData &Mprg = *(CMobProgData*) MobPrgList.GetNext (pos);
fprintf (fp, "> %s %s~\n%s~\n",
mprog_type_to_name (Mprg.type),
Mprg.arglist, strip_cr (Mprg.comlist));
}
fprintf (fp, "|\n");
}
}
CMobIndexData::~CMobIndexData ()
{
STRFREE (m_pPlayerName);
STRFREE (m_pShortDescr);
STRFREE (m_pLongDescr);
STRFREE (m_pDescription);
while (! MobPrgList.IsEmpty ())
delete (CMobProgData*) MobPrgList.RemoveTail ();
MobPrgList.RemoveAll ();
}
// Translates mob virtual number to its mob index struct.
// Hash table lookup.
CMobIndexData *CMobileTable::GetMob (int vnum, BOOL bBug /* = FALSE */)
{
CMobIndexData *pIdx;
if (vnum < 0)
vnum = 0;
for (pIdx = GetFirst (vnum); pIdx; pIdx = pIdx->GetNext ())
if (pIdx->vnum == vnum)
return pIdx;
if (bBug)
bug ("MobTable.GetMob: bad vnum %d.", vnum);
return NULL;
}
void CMobileTable::Remove (CMobIndexData *pMob)
{
CMobIndexData *tmp, *prev = NULL;
int iHash = GetHash (pMob->vnum);
// Take the room index out of the hash list.
for (tmp = m_mt [iHash]; tmp && tmp != pMob; tmp = tmp->GetNext ())
prev = tmp;
if (tmp) {
if (prev)
prev->SetNext (pMob->GetNext ());
else
m_mt [iHash] = pMob->GetNext ();
--m_Count;
}
}
void CMobileTable::Add (CMobIndexData *pIndex, int vnum)
{
pIndex->SetNext (GetFirst (vnum));
SetFirst (vnum, pIndex);
++m_Count;
}
void CMobileTable::RemoveAll ()
{
CMobIndexData *pNidx, *pIdx;
for (int hash = 0; hash < MAX_KEY_HASH; ++hash) {
pIdx = GetFirstByHash (hash);
while (pIdx) {
pNidx = pIdx->GetNext ();
delete pIdx;
pIdx = pNidx;
}
}
Empty (); // clear pointers and count
}
#ifdef _DEBUG
void CMobIndexData::Dump (CDumpContext& dc) const
{
CObject::Dump (dc);
dc << "CMobIndexData Name: " << m_pPlayerName << "\n";
}
#endif
CMobProgData::~CMobProgData ()
{
STRFREE (arglist);
STRFREE (comlist);
}