/**************************************************************************** * [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. * ****************************************************************************/ #include "stdafx.h" #include "smaug.h" #include "SmaugWizDoc.h" #include "Smaugx.h" #include "SysData.h" #include "area.h" #include "help.h" #include "mobiles.h" #include "objects.h" #include "rooms.h" #include "exits.h" extern BOOL fBootDb; // from db.cpp extern int top_shop; // db.cpp extern int top_repair; // db.dpp CAreaData::CAreaData (const char* Fname, const char* Aname, int Ver) { ClearAddrRange (&m_Version, &low_economy, sizeof (low_economy)); SetName (Aname); SetVersion (Ver); m_Filename = Fname; m_Author = "unknown"; hi_soft_range = MAX_LEVEL; hi_hard_range = MAX_LEVEL; age = 15; } void CAreaData::Reset () { POSITION pos = RoomList.GetHeadPosition (); while (pos) ResetRoom ((CRoomIndexData*) RoomList.GetNext (pos), this); } BOOL CAreaData::Load (FILE *fp, int& LineCount) { char *word, *pLine; TRY { for (;;) { pLine = fread_line (fp); if (*pLine++ != '#') { bug ("CAreaData::Load: # character not found."); ThrowSmaugException (SE_BOOT); } word = ParseWord (pLine); if (*word == '$') then break; else if (!str_cmp (word, "AUTHOR")) m_Author = ParseCString (pLine, fp); else if (!str_cmp (word, "FLAGS" )) LoadFlags (fp); else if (!str_cmp (word, "RANGES" )) LoadRanges (fp); else if (!str_cmp (word, "ECONOMY" )) LoadEconomy (pLine); else if (!str_cmp (word, "RESETMSG")) m_Resetmsg = ParseCString (pLine, fp); else if (!str_cmp (word, "MOBILES" )) LoadMobiles (fp); else if (!str_cmp (word, "OBJECTS" )) LoadObjects (fp); else if (!str_cmp (word, "ROOMS" )) LoadRooms (fp); else if (!str_cmp (word, "SHOPS" )) LoadShops (fp); else if (!str_cmp (word, "REPAIRS" )) LoadRepairs (fp); else if (!str_cmp (word, "SPECIALS")) LoadSpecials (fp); else if (!str_cmp (word, "CLIMATE")) then m_Climate = pLine; else { bug ("Bad section name: %s.", word); ThrowSmaugException (SE_AREA); } } } CATCH (CException, ex) { bug ("Unable to load Area file %s", NCCP m_Name); // bug ("Error at line #%d", LineCount); return FALSE; } END_CATCH SetLoaded (); return TRUE; } // Load area flags. Narn, Mar/96 void CAreaData::LoadFlags (FILE* fp) { char *buf = fread_line (fp); int x1 = 0, x2 = 0; sscanf (buf, "%d %d", &x1, &x2); flags = x1; reset_frequency = x2; if (x2) age = x2; } // Load soft / hard area ranges. void CAreaData::LoadRanges (FILE* fp) { int x1, x2, x3, x4; char *pLine, c; for (;;) { pLine = fread_line (fp); do c = *pLine++; while (isspace (c)); if (c == '$') break; x1 = x2 = x3 = x4 = 0; sscanf (--pLine, "%d %d %d %d", &x1, &x2, &x3, &x4); low_soft_range = x1; hi_soft_range = x2; low_hard_range = x3; hi_hard_range = x4; } } // Load an economy section. Thoric void CAreaData::LoadEconomy (char* pLine) { high_economy = ParseNumber (pLine); low_economy = ParseNumber (pLine); } // Load a mob section. void CAreaData::LoadMobiles (FILE* fp) { int MobVnum; char letter; BOOL bOldmob; for (;;) { char *pLine = fread_line (fp); do letter = *pLine++; while (isspace (letter)); if (letter != '#') { bug ("LoadMobiles: # character not found."); if (fBootDb) ThrowSmaugException (SE_MOBILE); return; } if ((MobVnum = ParseNumber (pLine)) == 0) then break; CMobIndexData *pMobIndex; if (MobTable.GetMob (MobVnum)) { if (fBootDb) { bug ("Load_mobiles: vnum %d duplicated.", MobVnum); shutdown_mud ("duplicate vnum"); ThrowSmaugException (SE_MOBILE); } else { pMobIndex = MobTable.GetMob (MobVnum); CString s; s.Format ("Cleaning mobile: %d", MobVnum); gpDoc->LogString (s, LOG_BOOT, SysData.LogLevel); pMobIndex->Clear (); bOldmob = TRUE; } } else { bOldmob = FALSE; pMobIndex = new CMobIndexData (MobVnum); } if (fBootDb) { if (! low_m_vnum) low_m_vnum = MobVnum; if (MobVnum > hi_m_vnum) hi_m_vnum = MobVnum; } pMobIndex->Read (fp); // Read mob data from file letter = fread_letter (fp); // look ahead ungetc (letter, fp); if (letter == '>') pMobIndex->ReadPrograms (fp); if (! bOldmob) { MobTable.Add (pMobIndex, MobVnum); MobList.AddTail (pMobIndex); } } } // Load an obj section. void CAreaData::LoadObjects (FILE *fp) { char buf [MAX_STRING_LENGTH]; CObjIndexData *pObjIndex; char letter; char *pLine; pLine = fread_line (fp); for (;;) { BOOL bOldobj; int ObjVnum; letter = *pLine++; if (letter != '#') { bug ("Load_objects: # character not found."); if (fBootDb) ThrowSmaugException (SE_OBJECT); return; } if ((ObjVnum = ParseNumber (pLine)) == 0) then break; if (OIdxTable.GetObj (ObjVnum)) { if (fBootDb) { bug ("Load_objects: vnum %d duplicated.", ObjVnum); ThrowSmaugException (SE_OBJECT); } else { pObjIndex = OIdxTable.GetObj (ObjVnum); sprintf (buf, "Cleaning object: %d", ObjVnum); gpDoc->LogString (buf, LOG_BOOT, SysData.LogLevel); pObjIndex->Clear (); bOldobj = TRUE; } } else { bOldobj = FALSE; pObjIndex = new CObjIndexData (ObjVnum); } if (fBootDb) { if (! low_o_vnum) low_o_vnum = ObjVnum; if (ObjVnum > hi_o_vnum) hi_o_vnum = ObjVnum; } pLine = pObjIndex->Read (fp, GetVersion ()); // returns the next line if (! bOldobj) { OIdxTable.Add (pObjIndex, ObjVnum); m_ObjIdxList.AddTail (pObjIndex); } } } // Load a room section. void CAreaData::LoadRooms (FILE *fp) { CRoomIndexData *pRoomIndex; char buf [MAX_STRING_LENGTH]; char *pLine; for (;;) { int RoomVnum; char letter; BOOL bOldroom; pLine = fread_line (fp); letter = *pLine++; if (letter != '#') { bug ("Load_rooms: # character not found."); if (fBootDb) ThrowSmaugException (SE_ROOM); return; } if ((RoomVnum = ParseNumber (pLine)) == 0) then break; if (RoomTable.GetRoom (RoomVnum) != NULL) { if (fBootDb) { bug ("Load_rooms: vnum %d duplicated.", RoomVnum); shutdown_mud ("duplicate vnum"); ThrowSmaugException (SE_ROOM); } else { pRoomIndex = RoomTable.GetRoom (RoomVnum); sprintf (buf, "Cleaning room: %d", RoomVnum); gpDoc->LogString (buf, LOG_RESET, SysData.LogLevel); pRoomIndex->Clean (); bOldroom = TRUE; } } else { pRoomIndex = new CRoomIndexData (RoomVnum); bOldroom = FALSE; } pRoomIndex->SetArea (this); if (fBootDb) { if (! low_r_vnum) low_r_vnum = RoomVnum; if (RoomVnum > hi_r_vnum) hi_r_vnum = RoomVnum; } pRoomIndex->Read (fp, fBootDb); if (! bOldroom) { RoomTable.Add (pRoomIndex, RoomVnum); RoomList.AddTail (pRoomIndex); } } } // Load a shop section. void CAreaData::LoadShops (FILE *fp) { CShopData *pShop; char *pLine; for (;;) { CMobIndexData *pMobIndex; int iTrade; pShop = new CShopData; pLine = fread_line (fp); pShop->keeper = ParseNumber (pLine); if (pShop->keeper == 0) { delete pShop; break; } for (iTrade = 0; iTrade < MAX_TRADE; iTrade++) pShop->buy_type [iTrade] = ParseNumber (pLine); pShop->profit_buy = ParseNumber (pLine); pShop->profit_sell = ParseNumber (pLine); pShop->profit_buy = URANGE (pShop->profit_sell+5, pShop->profit_buy, 1000); pShop->profit_sell = URANGE (0, pShop->profit_sell, pShop->profit_buy-5); pShop->open_hour = ParseNumber (pLine); pShop->close_hour = ParseNumber (pLine); pMobIndex = MobTable.GetMob (pShop->keeper, fBootDb); pMobIndex->pShop = pShop; if (!first_shop) first_shop = pShop; else last_shop->SetNext (pShop); pShop->SetNext (NULL); pShop->SetPrev (last_shop); last_shop = pShop; ++top_shop; } } // Load a repair shop section. -Thoric void CAreaData::LoadRepairs (FILE *fp) { CRepairShopData *rShop; char *pLine; for (;;) { CMobIndexData *pMobIndex; int iFix; rShop = new CRepairShopData; pLine = fread_line (fp); rShop->keeper = ParseNumber (pLine); if (rShop->keeper == 0) { delete rShop; break; } for (iFix = 0; iFix < MAX_FIX; iFix++) rShop->fix_type [iFix] = ParseNumber (pLine); rShop->profit_fix = ParseNumber (pLine); rShop->shop_type = ParseNumber (pLine); rShop->open_hour = ParseNumber (pLine); rShop->close_hour = ParseNumber (pLine); pMobIndex = MobTable.GetMob (rShop->keeper, fBootDb); pMobIndex->rShop = rShop; if (! first_repair) first_repair = rShop; else last_repair->SetNext (rShop); rShop->SetNext (NULL); rShop->SetPrev (last_repair); last_repair = rShop; ++top_repair; } } // Load spec proc declarations. void CAreaData::LoadSpecials (FILE *fp) { char *pLine; for (;;) { CMobIndexData *pMobIndex; char letter; pLine = fread_line (fp); switch (letter = *pLine++) { default: bug ("Load_specials: letter '%c' not *MS.", letter); ThrowSmaugException (SE_SPECIAL); case 'S': return; case '*': break; case 'M': pMobIndex = MobTable.GetMob (ParseNumber (pLine), fBootDb); pMobIndex->spec_fun = spec_lookup (ParseWord (pLine)); if (pMobIndex->spec_fun == 0) { bug ("Load_specials: 'M': vnum %d.", pMobIndex->vnum); ThrowSmaugException (SE_SPECIAL); } break; } } } void CAreaData::FixExits (BOOL bBoot /* = FALSE */) { CExitData *pExit, *pRevExit; gpDoc->LogStringf (LOG_BOOT, LEVEL_LOG, "Fixing exits for %s...", NCCP GetName ()); POSITION pos = RoomList.GetHeadPosition (); while (pos) { CRoomIndexData &Room = *(CRoomIndexData*) RoomList.GetNext (pos); Room.FixExits (bBoot); } // Set all the rexit pointers -Thoric pos = RoomList.GetHeadPosition (); while (pos) { CRoomIndexData &Room = *(CRoomIndexData*) RoomList.GetNext (pos); for (pExit = Room.first_exit; pExit; pExit = pExit->GetNext ()) { if (pExit->GetToRoom () && !pExit->rexit) { // Use TRUE to get even disabled exits pRevExit = get_exit_to (pExit->GetToRoom (), rev_dir [pExit->vdir], Room.vnum, TRUE); if (pRevExit) { pExit->rexit = pRevExit; pRevExit->rexit = pExit; pRevExit->SetToRoom (&Room); pRevExit->ClrDisabled (); } } } } } CAreaData *CAreaList::FindByFileName (const char* fname) { POSITION pos = GetHeadPosition (); while (pos) { CAreaData* p = GetNext (pos); if (! stricmp (p->m_Filename, fname)) return p; } return NULL; } CAreaData *CAreaList::FindByName (const char* name) { POSITION pos = GetHeadPosition (); while (pos) { CAreaData* p = GetNext (pos); if (! stricmp (p->m_Name, name)) return p; } return NULL; } CAreaData *CAreaList::FindByAuthor (const char* name) { POSITION pos = GetHeadPosition (); while (pos) { CAreaData* p = GetNext (pos); if (! stricmp (p->m_Author, name)) return p; } return NULL; } // Delete an area and all its resources (rooms, mobs, objs, strings...) CAreaData::~CAreaData () { // Remove & delete all the rooms while (! RoomList.IsEmpty ()) { CRoomIndexData *pRoom = (CRoomIndexData*) RoomList.RemoveTail (); // Remove it from the room table if it is there RoomTable.Remove (pRoom); delete pRoom; } RoomList.RemoveAll (); // Remove & delete all the mobs while (! MobList.IsEmpty ()) { CMobIndexData *pMob = (CMobIndexData*) MobList.RemoveTail (); // Remove it from the mob table if it is there MobTable.Remove (pMob); delete pMob; } MobList.RemoveAll (); // Remove & delete all the objects while (! m_ObjIdxList.IsEmpty ()) { CObjIndexData *pOIdx = (CObjIndexData*) m_ObjIdxList.RemoveTail (); // Remove it from the object table if it is there OIdxTable.Remove (pOIdx); delete pOIdx; } m_ObjIdxList.RemoveAll (); } void CAreaList::Remove (CAreaData* pArea) { POSITION pos = Find (pArea); if (pos) RemoveAt (pos); pos = SortList.Find (pArea); if (pos) { SortList.RemoveAt (pos); } } void CAreaList::RemoveAll () { while (! IsEmpty ()) delete RemoveTail (); CPtrList::RemoveAll (); SortList.RemoveAll (); } // Add gold to an area's economy -Thoric void CAreaData::BoostEconomy (int gold) { while (gold >= 1000000000) { ++high_economy; gold -= 1000000000; } low_economy += gold; while (low_economy >= 1000000000) { ++high_economy; low_economy -= 1000000000; } } // Take gold from an area's economy -Thoric void CAreaData::LowerEconomy (int gold) { while (gold >= 1000000000) { --high_economy; gold -= 1000000000; } low_economy -= gold; while (low_economy < 0) { --high_economy; low_economy += 1000000000; } } // Check to see if economy has at least this much gold -Thoric BOOL CAreaData::CheckGold (int gold) { int hasgold = ((high_economy > 0) ? 1 : 0) * 1000000000 + low_economy; return hasgold >= gold; }