/**************************************************************************** * [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); }