/**************************************************************************** * [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. * * ------------------------------------------------------------------------ * * Online Reset Editing Module * ****************************************************************************/ /* * This file relies heavily on the fact that your linked lists are correct, * and that pArea->reset_first is the first reset in pArea. Likewise, * pArea->reset_last *MUST* be the last reset in pArea. Weird and * wonderful things will happen if any of your lists are messed up, none * of them good. The most important are your pRoom->contents, * pRoom->people, rch->carrying, obj->contains, and pArea->reset_first .. * pArea->reset_last. -- Altrag */ #include "stdafx.h" #include "smaug.h" #include "mobiles.h" #include "objects.h" #include "rooms.h" #include "area.h" #include "Exits.h" #include "descriptor.h" #include "character.h" // Externals int get_wearloc (char* type); int get_trapflag (char* flag); // internal function prototypes int generate_itemlevel (CAreaData* pArea, CObjIndexData* pObjIndex); void add_obj_reset (CRoomIndexData* pRoom, char cm, CObjData* obj, int v2, int v3); void DeleteReset (CRoomIndexData* pRoom, CResetData* pReset); void InstaRoom (CRoomIndexData* pRoom, BOOL dodoors); void RenumberPutResetsForRoom (CRoomIndexData* pRoom); void edit_reset (CCharacter* ch, char* argument, CAreaData* pArea, CRoomIndexData* aRoom); void list_resets (CCharacter* ch, CRoomIndexData* pRoom, int start, int end); void WipeResets (CRoomIndexData* pRoom); void PlaceReset (CRoomIndexData* pRoom, CResetData* pReset); CRoomIndexData *find_room (CCharacter* ch, char* argument, CRoomIndexData* pRoom); CResetData *ParseReset (CRoomIndexData* pRoom, char* argument, CCharacter* ch); CResetData *FindReset (CRoomIndexData* pRoom, int num); CResetData *find_mreset (CCharacter* ch, CRoomIndexData* pRoom, char* name); CResetData *find_oreset (CCharacter* ch, CRoomIndexData* pRoom, char* name); CResetData *FindReset (CRoomIndexData* pRoom, int numb) { POSITION pos; CResetList &RList = pRoom->ResetList; pos = RList.FindIndex (numb-1); return pos ? RList.GetAt (pos) : NULL; } #ifdef XXXX // This is one loopy function. Ugh. -- Altrag BOOL is_room_reset (CResetData *pReset, CRoomIndexData *aRoom, CAreaData *pArea) { CRoomIndexData *pRoom; POSITION pos; int pr; if (! aRoom) return TRUE; switch (pReset->command) { case 'M': case 'O': pRoom = RoomTable.GetRoom (pReset->arg3); if (! pRoom || pRoom != aRoom) return FALSE; return TRUE; case 'P': case 'T': case 'H': pr = (pReset->command == 'H') ? pReset->arg1 : pReset->arg3; pos = pArea->ResetList.GetCurPos (); while (pos) { CResetData &Res = *pArea->ResetList.GetPrev (pos); if ((Res.command == 'O' || Res.command == 'P' || Res.command == 'G' || Res.command == 'E') && (!pr || pr == Res.arg1) && OIdxTable.GetObj (Res.arg1)) return is_room_reset (&Res, aRoom, pArea); } return FALSE; case 'B': switch (pReset->arg2 & BIT_RESET_TYPE_MASK) { case BIT_RESET_DOOR: case BIT_RESET_ROOM: return (aRoom->vnum == pReset->arg1); case BIT_RESET_MOBILE: pos = pArea->ResetList.GetCurPos (); while (pos) { CResetData &Res = *pArea->ResetList.GetPrev (pos); if (Res.command == 'M' && MobTable.GetMob (Res.arg1)) return is_room_reset (&Res, aRoom, pArea); } return FALSE; case BIT_RESET_OBJECT: pos = pArea->ResetList.GetCurPos (); while (pos) { CResetData &Res = *pArea->ResetList.GetPrev (pos); if ((Res.command == 'O' || Res.command == 'P' || Res.command == 'G' || Res.command == 'E') && (!pReset->arg1 || pReset->arg1 == Res.arg1) && OIdxTable.GetObj (Res.arg1)) return is_room_reset (&Res, aRoom, pArea); } return FALSE; } return FALSE; case 'G': case 'E': pos = pArea->ResetList.GetCurPos (); while (pos) { CResetData &Res = *pArea->ResetList.GetPrev (pos); if (Res.command == 'M' && MobTable.GetMob (Res.arg1)) then return is_room_reset (&Res, aRoom, pArea); } return FALSE; case 'D': case 'R': pRoom = RoomTable.GetRoom (pReset->arg1); if (!pRoom || pRoom->GetArea () != pArea || (aRoom && pRoom != aRoom)) return FALSE; return TRUE; } return FALSE; } #endif CRoomIndexData *find_room (CCharacter *ch, char *argument, CRoomIndexData *pRoom) { char arg [MAX_INPUT_LENGTH]; if (pRoom) return pRoom; one_argument (argument, arg); if (! is_number (arg) && arg [0] != '\0') { ch->SendText ("Reset to which room?\n\r"); return NULL; } if (arg [0] == '\0') pRoom = ch->GetInRoom (); else pRoom = RoomTable.GetRoom (atoi (arg)); if (! pRoom) { ch->SendText ("Room does not exist.\n\r"); return NULL; } return pRoom; } void DeleteReset (CRoomIndexData *pRoom, CResetData *pReset) { CResetList &RList = pRoom->ResetList; POSITION InPos = RList.Find (pReset); POSITION pos = InPos; // Set pos to the item after the pReset that we entered with RList.GetNext (pos); if (pReset->command == 'M') { while (pos) { CResetData &Res = *RList.GetNext (pos); // Break when a new mob found if (Res.command == 'M') break; // Delete anything mob is holding if (Res.command == 'G' || Res.command == 'E') { // here we need to ensure that the value pos ends up pointing // at the list item after the one we are about to delete. So // we first set it to before that item, delete the item, and // then advance pos to the next item - the one we want... pos = RList.GetCurPos (); RList.GetPrev (pos); // pos = prev DeleteReset (pRoom, &Res); RList.GetNext (pos); // pos = next continue; } if (Res.command == 'B' && (Res.arg2 & BIT_RESET_TYPE_MASK) == BIT_RESET_MOBILE && (! Res.arg1 || Res.arg1 == pReset->arg1)) { pos = RList.GetCurPos (); RList.GetPrev (pos); // pos = prev DeleteReset (pRoom, &Res); continue; } } } else if (pReset->command == 'O' || pReset->command == 'P' || pReset->command == 'G' || pReset->command == 'E') { while (pos) { CResetData &Res = *RList.GetNext (pos); if (Res.command == 'T' && (!Res.arg3 || Res.arg3 == pReset->arg1)) { pos = RList.GetCurPos (); RList.GetPrev (pos); // pos = prev DeleteReset (pRoom, &Res); continue; } if (Res.command == 'H' && (!Res.arg1 || Res.arg1 == pReset->arg1)) { pos = RList.GetCurPos (); RList.GetPrev (pos); // pos = prev DeleteReset (pRoom, &Res); continue; } // Delete nested objects, even if they are the same object. if (Res.command == 'P' && (Res.arg3 > 0 || pReset->command != 'P' || Res.extra-1 == pReset->extra) && (!Res.arg3 || Res.arg3 == pReset->arg1)) { pos = RList.GetCurPos (); RList.GetPrev (pos); // pos = prev DeleteReset (pRoom, &Res); continue; } if (Res.command == 'B' && (Res.arg2 & BIT_RESET_TYPE_MASK) == BIT_RESET_OBJECT && (!Res.arg1 || Res.arg1 == pReset->arg1)) { pos = RList.GetCurPos (); RList.GetPrev (pos); // pos = prev DeleteReset (pRoom, &Res); continue; } // Break when a new object of same type is found if ((Res.command == 'O' || Res.command == 'P' || Res.command == 'G' || Res.command == 'E') && Res.arg1 == pReset->arg1) break; } } RList.RemoveAt (InPos); delete pReset; } CResetData *find_oreset (CCharacter *ch, CRoomIndexData *pRoom, char *name) { CResetData *pReset = NULL; POSITION pos; CResetList &RList = pRoom->ResetList; if (! *name) { pos = RList.GetTailPosition (); while (pos) { pReset = RList.GetPrev (pos); char c = pReset->command; if (c == 'O' || c == 'E' || c == 'G' || c == 'P') then return pReset; } ch->SendText ("No object resets in list.\n\r"); return NULL; } char arg [MAX_INPUT_LENGTH]; int cnt = 0; int num = number_argument (name, arg); CObjIndexData *pObjTo = NULL; pos = RList.GetHeadPosition (); while (pos) { pReset = RList.GetNext (pos); char c = pReset->command; if (c == 'O' || c == 'E' || c == 'G' || c == 'P') if ((pObjTo = OIdxTable.GetObj (pReset->arg1)) && is_name (arg, pObjTo->GetName ()) && ++cnt == num) return pReset; } ch->SendText ("To object not in reset list.\n\r"); return NULL; } CResetData *find_mreset (CCharacter *ch, CRoomIndexData *pRoom, char *name) { CResetData *pReset = NULL; POSITION pos; CResetList &RList = pRoom->ResetList; if (! *name) { pos = RList.GetTailPosition (); while (pos) { pReset = RList.GetPrev (pos); if (pReset->command == 'M') then return pReset; } ch->SendText ("No mobile resets in list.\n\r"); return NULL; } char arg [MAX_INPUT_LENGTH]; int cnt = 0, num = number_argument (name, arg); CMobIndexData *pMob = NULL; pos = RList.GetHeadPosition (); while (pos) { pReset = RList.GetNext (pos); if (pReset->command == 'M') { if ((pMob = MobTable.GetMob (pReset->mob)) && is_name (arg, pMob->GetPlayerName ()) && ++cnt == num) return pReset; } } ch->SendText ("Mobile not in reset list.\n\r"); return NULL; } void edit_reset (CCharacter *ch, char *argument, CAreaData *pArea, CRoomIndexData *pRoom) { CMobIndexData *pMob = NULL; CObjIndexData *pObj; CResetData *pReset = NULL; CResetData *reset = NULL; int num = 0; int vnum; char *origarg = argument; char arg [MAX_INPUT_LENGTH]; argument = one_argument (argument, arg); if (! *arg || ! str_cmp (arg, "?")) { char *nm = (ch->GetSubstate () == SUB_REPEATCMD ? "" : "reset "); ch->SendTextf ( "Syntax: %s<list|edit|delete|add|insert|place|room|area>\n\r", nm); ch->SendTextf ("Syntax: %sremove <#>\n\r", nm); ch->SendTextf ("Syntax: %smobile <mob#> [limit]\n\r", nm); ch->SendTextf ("Syntax: %sobject <obj#> [limit [room]]\n\r", nm); ch->SendTextf ("Syntax: %sequip <mob name> <obj#> <location> [limit]\n\r", nm); ch->SendTextf ("Syntax: %sgive <mob name> <obj#> [limit]\n\r", nm); ch->SendTextf ("Syntax: %sobject <obj#> put <to_obj name> [limit]\n\r", nm); ch->SendTextf ("Syntax: %shide <obj name>\n\r", nm); ch->SendTextf ("Syntax: %strap <obj name> <type> <charges> " "<flags>\n\r", nm); ch->SendTextf ("Syntax: %strap room <type> <charges> <flags>\n\r", nm); ch->SendTextf ("Syntax: %sbit <set|toggle|remove> door <dir> " "<exit flags>\n\r", nm); ch->SendTextf ("Syntax: %sbit <set|toggle|remove> object <obj name> " "<extra flags>\n\r", nm); ch->SendTextf ("Syntax: %sbit <set|toggle|remove> mobile <mob name> " "<affect flags>\n\r", nm); ch->SendTextf ("Syntax: %sbit <set|toggle|remove> room " "<room flags>\n\r", nm); ch->SendTextf ("Syntax: %srandom <last dir>\n\r", nm); return; } if (! str_cmp (arg, "on")) { ch->SetSubstate (SUB_REPEATCMD); ch->dest_buf = (pRoom ? (void *)pRoom : (void *)pArea); ch->SendText ("Reset mode on.\n\r"); return; } if (! str_cmp (arg, "area")) { num = pArea->nplayer; pArea->nplayer = 0; pArea->Reset (); pArea->nplayer = num; ch->SendText ("Done.\n\r"); return; } if (! str_cmp (arg, "room")) { num = pArea->nplayer; pArea->nplayer = 0; ResetRoom (pRoom, pArea); pArea->nplayer = num; ch->SendText ("Done.\n\r"); return; } if (! str_cmp (arg, "list")) { argument = one_argument (argument, arg); int start = is_number (arg) ? atoi (arg) : -1; argument = one_argument (argument, arg); int end = is_number (arg) ? atoi (arg) : -1; list_resets (ch, pRoom, start, end); return; } CResetList &RList = pRoom->ResetList; if (! str_cmp (arg, "edit")) { argument = one_argument (argument, arg); if (! *arg || ! is_number (arg)) { ch->SendText ("Usage: reset edit <number> <command>\n\r"); return; } num = atoi (arg); if (! (pReset = FindReset (pRoom, num))) { ch->SendText ("Reset not found.\n\r"); return; } if (! (reset = ParseReset (pRoom, argument, ch))) { ch->SendText ("Error in reset. Reset not changed.\n\r"); return; } POSITION pos = RList.Find (pReset); RList.SetAt (pos, reset); delete pReset; ch->SendText ("Done.\n\r"); return; } if (! str_cmp (arg, "add")) { if ((pReset = ParseReset (pRoom, argument, ch)) == NULL) { ch->SendText ("Error in reset. Reset not added.\n\r"); return; } RList.AddTail (pReset); ch->SendText ("Done.\n\r"); return; } if (! str_cmp (arg, "place")) { if ((pReset = ParseReset (pRoom, argument, ch)) == NULL) { ch->SendText ("Error in reset. Reset not added.\n\r"); return; } PlaceReset (pRoom, pReset); ch->SendText ("Done.\n\r"); return; } if (! str_cmp (arg, "insert")) { char *uMsg = "USAGE: insert <number> <command>\n\r"; argument = one_argument (argument, arg); if (! *arg || ! is_number (arg)) { ch->SendText (uMsg); return; } num = atoi (arg); if ((reset = FindReset (pRoom, num)) == NULL) { ch->SendText ("Reset not found.\n\r"); ch->SendText (uMsg); return; } if ((pReset = ParseReset (pRoom, argument, ch)) == NULL) { ch->SendText ("Error in reset. Reset not inserted.\n\r"); return; } POSITION pos = RList.Find (reset); RList.InsertBefore (pos, pReset); ch->SendText ("Done.\n\r"); return; } if (! str_prefix (arg, "delete")) { if (! *argument) { ch->SendText ("USAGE: delete <start> [end]\n\r"); return; } argument = one_argument (argument, arg); int start = is_number (arg) ? atoi (arg) : -1; one_argument (argument, arg); int end = is_number (arg) ? atoi (arg) : start; BOOL bFound = FALSE; POSITION pos = RList.GetHeadPosition (); for (int num=1; pos; ++num) { pReset = RList.GetNext (pos); if (num > end) then break; if (num >= start) { RList.Remove (pReset); bFound = TRUE; } } if (! bFound) ch->SendText ("Reset not found.\n\r"); else ch->SendText ("Done.\n\r"); return; } if (! str_prefix (arg, "remove")) { argument = one_argument (argument, arg); if (arg [0] == '\0' || ! is_number (arg)) { ch->SendText ("Remove which reset?\n\r"); return; } int iarg = atoi (arg); POSITION pos = RList.FindIndex (iarg-1); if (! pos) { ch->SendText ("Reset does not exist.\n\r"); return; } DeleteReset (pRoom, RList.GetAt (pos)); ch->SendText ("Reset deleted.\n\r"); return; } if (! str_prefix (arg, "mobile")) { char *uMsg = "USAGE: mobile <mob#> [limit]\n\r"; argument = one_argument (argument, arg); if (arg [0] == '\0' || ! is_number (arg)) { ch->SendText ("Reset which mobile vnum?\n\r"); ch->SendText (uMsg); return; } if (! (pMob = MobTable.GetMob (atoi (arg)))) { ch->SendText ("Mobile does not exist.\n\r"); ch->SendText (uMsg); return; } argument = one_argument (argument, arg); if (arg [0] == '\0') num = 1; else if (! is_number (arg)) { ch->SendText ("Reset how many mobiles?\n\r"); ch->SendText (uMsg); return; } else num = atoi (arg); pReset = new CResetData ('M', 0, pMob->vnum, pMob->vnum, num, pRoom->vnum); RList.AddTail (pReset); ch->SendText ("Mobile reset added.\n\r"); return; } if (! str_prefix (arg, "equip")) { char *uMsg = "USAGE: equip <mob name> <obj#> <wear loc> [limit]\n\r"; argument = one_argument (argument, arg); if (! (reset = find_mreset (ch, pRoom, arg))) { ch->SendText ("Equip which object vnum?\n\r"); ch->SendText (uMsg); return; } int MobVnum = reset->mob; argument = one_argument (argument, arg); if (arg [0] == '\0' || ! is_number (arg)) { ch->SendText ("Equip which object vnum?\n\r"); ch->SendText (uMsg); return; } if (! (pObj = OIdxTable.GetObj (atoi (arg)))) { ch->SendText ("Object does not exist.\n\r"); ch->SendText (uMsg); return; } argument = one_argument (argument, arg); num = get_wearloc (arg); if (num < 0) { ch->SendText ("Equip mob at which location?\n\r"); ch->SendText (uMsg); return; } // Find the insert location, goes after any Bit resets, and // after any other Eq resets for same mob BOOL bFound = FALSE; POSITION CurPos = NULL, pos = RList.Find (reset); RList.GetNext (pos); while (pos) { reset = RList.GetNext (pos); char cmd = reset->command; if (reset->mob != MobVnum || (cmd != 'B' && cmd != 'E')) { CurPos = RList.GetCurPos (); break; } } while (pos) { reset = RList.GetNext (pos); if (reset->command == 'M') then break; if (reset->command == 'E' && reset->arg3 == num) { ch->SendText ("Mobile already has an item equipped " "there.\n\r"); return; } } // find the limit argument = one_argument (argument, arg); int limit = max (atoi (arg), 1); pReset = new CResetData ('E', 1, MobVnum, pObj->vnum, limit, num); if (CurPos) then RList.InsertBefore (CurPos, pReset); else RList.AddTail (pReset); ch->SendText ("Object equip to Mobile reset created.\n\r"); return; } if (! str_prefix (arg, "give")) { char *uMsg = "USAGE: give <mob name> <obj#> [limit]\n\r"; argument = one_argument (argument, arg); if (! (reset = find_mreset (ch, pRoom, arg))) { ch->SendText (uMsg); return; } int MobVnum = reset->mob; argument = one_argument (argument, arg); if (arg [0] == '\0' || ! is_number (arg)) { ch->SendText ("Give which object vnum?\n\r"); ch->SendText (uMsg); return; } if (! (pObj = OIdxTable.GetObj (atoi (arg)))) { ch->SendText ("Object does not exist.\n\r"); ch->SendText (uMsg); return; } argument = one_argument (argument, arg); int limit = max (atoi (arg), 1); // Find the insert location, goes after all other resets for this mob BOOL bFound = FALSE; POSITION CurPos = NULL, pos = RList.Find (reset); RList.GetNext (pos); while (pos) { reset = RList.GetNext (pos); if (reset->mob != MobVnum) { CurPos = RList.GetCurPos (); break; } } pReset = new CResetData ('G', 1, MobVnum, pObj->vnum, limit, 0); if (CurPos) then RList.InsertBefore (CurPos, pReset); else RList.AddTail (pReset); ch->SendText ("Object give to mobile reset created.\n\r"); return; } if (! str_prefix (arg, "object")) { argument = one_argument (argument, arg); if (arg [0] == '\0' || ! is_number (arg)) { ch->SendText ("Reset which object vnum?\n\r"); return; } if (! (pObj = OIdxTable.GetObj (atoi (arg)))) { ch->SendText ("Object does not exist.\n\r"); return; } argument = one_argument (argument, arg); if (arg [0] == '\0') strcpy (arg, "room"); if (! str_prefix (arg, "put")) { argument = one_argument (argument, arg); if (! (reset = find_oreset (ch, pRoom, arg))) return; argument = one_argument (argument, arg); if ((vnum = atoi (arg)) < 1) vnum = 1; pReset = new CResetData ('P', reset->extra+1, 0, pObj->vnum, vnum, 0); // Put in_objects after hide and trap resets BOOL bFound = FALSE; POSITION pos = RList.Find (reset); while (pos) { reset = RList.GetNext (pos); char c = reset->command; if (c != 'H' && c != 'T' && c != 'B') { RList.InsertBefore (RList.GetCurPos (), pReset); bFound = TRUE; break; } } if (! bFound) then RList.AddTail (pReset); ch->SendText ("Object reset in object created.\n\r"); return; } if (arg [0] == '\0' || ! (num = (int) str_cmp (arg, "room")) || is_number (arg)) { if (! (BOOL) num) argument = one_argument (argument, arg); if ((vnum = atoi (arg)) < 1) vnum = 1; pReset = new CResetData ('O', 0, 0, pObj->vnum, vnum, pRoom->vnum); RList.AddTail (pReset); ch->SendText ("Object reset added.\n\r"); return; } ch->SendText ("Reset object to where?\n\r"); return; } if (! str_cmp (arg, "random")) { argument = one_argument (argument, arg); vnum = get_dir (arg); if (vnum < 0 || vnum > 9) { ch->SendText ("Reset which random doors?\n\r"); return; } if (vnum == 0) { ch->SendText ("There is no point in randomizing one door.\n\r"); return; } pReset = new CResetData ('R', 0, 0, pRoom->vnum, vnum, 0); RList.AddTail (pReset); ch->SendText ("Reset random doors created.\n\r"); return; } if (! str_cmp (arg, "trap")) { char oname [MAX_INPUT_LENGTH]; int value, extra = 0; char *uMsg = "USAGE: trap <\"room\"|object name> <type> <charges> [flags]\n\r"; argument = one_argument (argument, oname); BOOL bRoom = is_name (oname, "room"); argument = one_argument (argument, arg); int TrapType = is_number (arg) ? atoi (arg) : -1; argument = one_argument (argument, arg); int chrg = is_number (arg) ? atoi (arg) : -1; if (bRoom) { vnum = pRoom->vnum; extra = TRAP_ROOM; reset = NULL; } else { if (! (reset = find_oreset (ch, pRoom, oname))) { ch->SendText ("TRAP: invalid object name\n\r"); ch->SendText (uMsg); return; } vnum = 0; extra = TRAP_OBJ; } if (TrapType < 1 || TrapType > MAX_TRAPTYPE) { ch->SendText ("TRAP: invalid trap type\n\r"); ch->SendText (uMsg); return; } if (chrg < 0 || chrg > 10000) { ch->SendText ("TRAP: invalid trap charges\n\r"); ch->SendText (uMsg); return; } while (*argument) { argument = one_argument (argument, arg); value = get_trapflag (arg); if (value < 0 || value > 31) { ch->SendText ("TRAP: bad flag\n\r"); ch->SendText (uMsg); return; } SET_BIT (extra, 1 << value); } pReset = new CResetData ('T', extra, 0, TrapType, chrg, vnum); if (reset) { POSITION pos = RList.Find (reset); if (pos) then RList.InsertAfter (pos, pReset); else RList.AddTail (pReset); } else RList.AddTail (pReset); ch->SendText ("Trap created.\n\r"); return; } if (! str_cmp (arg, "bit")) { int (*flfunc) (const char *type); int flags = 0; char option [MAX_INPUT_LENGTH]; argument = one_argument (argument, option); if (! *option) { ch->SendText ("You must specify SET, REMOVE, or TOGGLE.\n\r"); return; } num = 0; if (! str_prefix (option, "set")) SET_BIT (num, BIT_RESET_SET); else if (!str_prefix (option, "toggle")) SET_BIT (num, BIT_RESET_TOGGLE); else if (str_prefix (option, "remove")) { ch->SendText ("You must specify SET, REMOVE, or TOGGLE.\n\r"); return; } argument = one_argument (argument, option); if (! *option) { ch->SendText ("Must specify OBJECT, MOBILE, ROOM, or DOOR.\n\r"); return; } if (! str_prefix (option, "door")) { SET_BIT (num, BIT_RESET_DOOR); argument = one_argument (argument, arg); if (! *arg) { ch->SendText ("Must specify direction.\n\r"); return; } vnum = get_dir (arg); SET_BIT (num, vnum << BIT_RESET_DOOR_THRESHOLD); vnum = pRoom->vnum; flfunc = &get_exflag; reset = NULL; } else if (! str_prefix (option, "object")) { SET_BIT (num, BIT_RESET_OBJECT); vnum = 0; flfunc = &get_oflag; if (! (reset = find_oreset (ch, pRoom, arg))) return; } else if (! str_prefix (option, "mobile")) { SET_BIT (num, BIT_RESET_MOBILE); vnum = 0; flfunc = &get_aflag; if (! (reset = find_mreset (ch, pRoom, arg))) return; } else if (! str_prefix (option, "room")) { SET_BIT (num, BIT_RESET_ROOM); vnum = pRoom->vnum; flfunc = &get_rflag; reset = NULL; } else { ch->SendText ("Must specify OBJECT, MOBILE, ROOM, or DOOR.\n\r"); return; } while (*argument) { int value; argument = one_argument (argument, arg); value = (*flfunc) (arg); if (value < 0 || value > 31) { ch->SendText ("Reset: BIT: bad flag\n\r"); return; } SET_BIT (flags, 1 << value); } if (! flags) { ch->SendText ("Set which flags?\n\r"); return; } pReset = new CResetData ('B', 1, 0, vnum, num, flags); if (reset) { POSITION pos = RList.Find (reset); if (pos) then RList.InsertAfter (pos, pReset); else RList.AddTail (pReset); } else RList.AddTail (pReset); ch->SendText ("Bitvector reset created.\n\r"); return; } if (! str_cmp (arg, "hide")) { argument = one_argument (argument, arg); if (! (reset = find_oreset (ch, pRoom, arg))) return; pReset = new CResetData ('H', 1, 0, 0, 0, 0); POSITION pos = RList.Find (reset); if (pos) then RList.InsertBefore (pos, pReset); else RList.AddTail (pReset); ch->SendText ("Object hide reset created.\n\r"); return; } if (ch->GetSubstate () == SUB_REPEATCMD) { ch->SetSubstate (SUB_NONE); interpret (ch, origarg); ch->SetSubstate (SUB_REPEATCMD); ch->last_cmd = (pRoom ? do_rreset : do_reset); } else edit_reset (ch, "", pArea, pRoom); } // Parse a reset command string into a CResetData structure CResetData *ParseReset (CRoomIndexData* pRoom, char* argument, CCharacter* ch) { char arg1 [MAX_INPUT_LENGTH]; char arg2 [MAX_INPUT_LENGTH]; char arg3 [MAX_INPUT_LENGTH]; char arg4 [MAX_INPUT_LENGTH]; char letter; int extra, val1, val2, val3; int value; CRoomIndexData *room; CExitData *pexit; int mob = 0; argument = one_argument (argument, arg1); argument = one_argument (argument, arg2); argument = one_argument (argument, arg3); argument = one_argument (argument, arg4); extra = 0; letter = '*'; val1 = atoi (arg2); val2 = atoi (arg3); val3 = atoi (arg4); if (arg1 [0] == '\0') { ch->SendText ("Reset commands: mob obj door rand trap hide.\n\r"); return NULL; } if (! str_cmp (arg1, "hide")) { if (arg2 [0] != '\0' && ! OIdxTable.GetObj (val1)) { ch->SendText ("Reset: HIDE: no such object\n\r"); return NULL; } else val1 = 0; extra = 1; val2 = 0; val3 = 0; letter = 'H'; } else if (arg2 [0] == '\0') { ch->SendText ("Reset: not enough arguments.\n\r"); return NULL; } else if (val1 < 1 || val1 > 2097152000) { // was 32767 ch->SendText ("Reset: value out of range.\n\r"); return NULL; } else if (! str_cmp (arg1, "mob")) { if (! MobTable.GetMob (val1)) { ch->SendText ("Reset: MOB: no such mobile\n\r"); return NULL; } val3 = val2; if (val3 < 1) val3 = 1; val2 = pRoom->vnum; letter = 'M'; mob = val1; } else if (!str_cmp (arg1, "obj")) { if (! OIdxTable.GetObj (val1)) { ch->SendText ("Reset: OBJ: no such object\n\r"); return NULL; } val3 = val2; if (val3 < 1) val3 = 1; val2 = pRoom->vnum; letter = 'O'; } else if (!str_cmp (arg1, "put")) { if (! OIdxTable.GetObj (val1)) { ch->SendText ("Reset: PUT: no such object\n\r"); return NULL; } if (val2 > 0 && !OIdxTable.GetObj (val2)) { ch->SendText ("Reset: PUT: no such container\n\r"); return NULL; } extra = UMAX (val3, 0); argument = one_argument (argument, arg4); val3 = (is_number (argument) ? atoi (arg4) : 0); if (val3 < 0) val3 = 0; letter = 'P'; } else if (!str_cmp (arg1, "door")) { if ((room = RoomTable.GetRoom (val1)) == NULL) { ch->SendText ("Reset: DOOR: no such room\n\r"); return NULL; } if (val2 < 0 || val2 > 9) { ch->SendText ("Reset: DOOR: invalid exit\n\r"); return NULL; } if ((pexit = get_exit (room, val2)) == NULL || ! pexit->IsDoor ()) { ch->SendText ("Reset: DOOR: no such door\n\r"); return NULL; } if (val3 < 0 || val3 > 2) { ch->SendText ("Reset: DOOR: invalid door state (0 = open, 1 = close, 2 = lock)\n\r"); return NULL; } letter = 'D'; value = val3; val3 = val2; val2 = value; } else if (! str_cmp (arg1, "rand")) { val1 = pRoom->vnum; if (val2 < 0 || val2 > 9) { ch->SendText ("Reset: RAND: invalid max exit\n\r"); return NULL; } val3 = val2; val2 = 0; letter = 'R'; } else if (! str_cmp (arg1, "trap")) { if (val2 < 1 || val2 > MAX_TRAPTYPE) { ch->SendText ("Reset: TRAP: invalid trap type\n\r"); return NULL; } if (val3 < 0 || val3 > 10000) { ch->SendText ("Reset: TRAP: invalid trap charges\n\r"); return NULL; } while (argument [0] != '\0') { argument = one_argument (argument, arg4); value = get_trapflag (arg4); if (value >= 0 || value < 32) SET_BIT (extra, 1 << value); else { ch->SendText ("Reset: TRAP: bad flag\n\r"); return NULL; } } if (IS_SET (extra, TRAP_ROOM) && IS_SET (extra, TRAP_OBJ)) { ch->SendText ("Reset: TRAP: Must specify room OR object, " "not both!\n\r"); return NULL; } if (IS_SET (extra, TRAP_ROOM)) val1 = pRoom->vnum; if (IS_SET (extra, TRAP_OBJ) && val1>0 && !OIdxTable.GetObj (val1)){ ch->SendText ("Reset: TRAP: no such object\n\r"); return NULL; } if (! IS_SET (extra, TRAP_ROOM) && ! IS_SET (extra, TRAP_OBJ)) { ch->SendText ("Reset: TRAP: Must specify ROOM or OBJECT\n\r"); return NULL; } // fix order value = val1; val1 = val2; val2 = value; letter = 'T'; } if (letter == '*') return NULL; else return new CResetData (letter, extra, mob, val1, val3, val2); } void do_rreset (CCharacter *ch, char *argument) { do_reset (ch, argument); } void do_reset (CCharacter *ch, char *argument) { CRoomIndexData *pRoom; if (ch->GetSubstate () == SUB_REPEATCMD) { pRoom = (CRoomIndexData*) ch->dest_buf; if (! pRoom) { ch->SendText ("Your room pointer got lost. Reset mode off.\n\r"); bug ("do_reset: %s's dest_buf points to invalid room", (int) ch->GetName ()); ch->SetSubstate (SUB_NONE); ch->dest_buf = NULL; return; } } else pRoom = ch->GetInRoom (); if (can_rmodify (ch, pRoom)) edit_reset (ch, argument, pRoom->GetArea (), pRoom); } void add_obj_reset (CRoomIndexData *pRoom, char cm, CObjData *obj, int v2, int v3) { CObjData *inobj; static int iNest; if ((cm == 'O' || cm == 'P') && obj->pIndexData->vnum == OBJ_VNUM_TRAP) { if (cm == 'O') pRoom->AddReset ('T', obj->value [3], 0, obj->value [1], obj->value [0], v3); return; } pRoom->AddReset (cm, (cm == 'P' ? iNest : 1), 0, obj->pIndexData->vnum, v2, v3); // Only add hide for in-room objects that are hidden and cant be // moved, as hide is an update reset, not a load-only reset. if (cm == 'O' && obj->IsHidden () && ! IS_SET (obj->wear_flags, ITEM_TAKE)) pRoom->AddReset ('H', 1, 0, 0, 0, 0); POSITION Cpos = obj->GetHeadContentPos (); while (inobj = obj->GetNextContent (Cpos)) if (inobj->pIndexData->vnum == OBJ_VNUM_TRAP) add_obj_reset (pRoom, 'O', inobj, 0, 0); if (cm == 'P') iNest++; Cpos = obj->GetHeadContentPos (); while (inobj = obj->GetNextContent (Cpos)) add_obj_reset (pRoom, 'P', inobj, 1, 0); if (cm == 'P') iNest--; } void InstaRoom (CRoomIndexData *pRoom, BOOL dodoors) { CCharacter *rch; CObjData *obj; for (rch = pRoom->first_person; rch; rch = rch->GetNextInRoom ()) { if (! rch->IsNpc ()) continue; int MobVnum = rch->GetMobIndex ()->vnum; pRoom->AddReset ('M', 1, MobVnum, MobVnum, rch->GetMobIndex ()->count, pRoom->vnum); POSITION Cpos = rch->GetHeadCarryPos (); while (obj = rch->GetNextCarrying (Cpos)) { if (obj->wear_loc == WEAR_NONE) add_obj_reset (pRoom, 'G', obj, 1, 0); else add_obj_reset (pRoom, 'E', obj, 1, obj->wear_loc); } } POSITION Cpos = pRoom->GetHeadContentPos (); while (obj = pRoom->GetNextContent (Cpos)) add_obj_reset (pRoom, 'O', obj, 1, pRoom->vnum); if (dodoors) { CExitData *pexit; for (pexit = pRoom->first_exit; pexit; pexit = pexit->GetNext ()) { int state = 0; if (! pexit->IsDoor ()) continue; if (pexit->IsClosed ()) { if (pexit->IsLocked ()) state = 2; else state = 1; } pRoom->AddReset ('D', 0, 0, pRoom->vnum, pexit->vdir, state); } } } void WipeResets (CRoomIndexData *pRoom) { CResetData *pReset; CResetList &RList = pRoom->ResetList; POSITION pos = RList.GetHeadPosition (); while (pos) { pReset = RList.GetNext (pos); if (pReset->command != 'R') { // Resets always go forward, so we can safely use the // previous reset, providing it exists, or first_reset // if it doesnt. -- Altrag pos = RList.GetCurPos (); RList.GetPrev (pos); // set pos to previous (or NULL) DeleteReset (pRoom, pReset); if (! pos) then pos = RList.GetHeadPosition (); } } } void do_instaroom (CCharacter *ch, char *argument) { CRoomIndexData *pRoom; BOOL dodoors; char arg [MAX_INPUT_LENGTH]; CAreaData *pArea = ch->GetArea (); if (ch->IsNpc () || ch->GetTrustLevel () < LEVEL_SAVIOR || ! pArea) { ch->SendText ("You don't have an assigned area to create resets for.\n\r"); return; } argument = one_argument (argument, arg); if (!str_cmp (argument, "nodoors")) dodoors = FALSE; else dodoors = TRUE; if (! (pRoom = find_room (ch, arg, NULL))) { ch->SendText ("Room doesn't exist.\n\r"); return; } if (!can_rmodify (ch, pRoom)) return; if (pRoom->GetArea () != pArea && ch->GetTrustLevel () < LEVEL_GREATER) { ch->SendText ("You cannot reset that room.\n\r"); return; } if (! pRoom->ResetList.IsEmpty ()) WipeResets (pRoom); InstaRoom (pRoom, dodoors); ch->SendText ("Room resets installed.\n\r"); } void do_instazone (CCharacter *ch, char *argument) { int vnum; CRoomIndexData *pRoom; BOOL dodoors; CAreaData *pArea = ch->GetArea (); if (ch->IsNpc () || ch->GetTrustLevel () < LEVEL_SAVIOR || ! pArea) { ch->SendText ("You don't have an assigned area to create resets for.\n\r"); return; } if (!str_cmp (argument, "nodoors")) dodoors = FALSE; else dodoors = TRUE; for (vnum = pArea->low_r_vnum; vnum <= pArea->hi_r_vnum; vnum++) { if (! (pRoom = RoomTable.GetRoom (vnum)) || pRoom->GetArea () != pArea) continue; WipeResets (pRoom); InstaRoom (pRoom, dodoors); } ch->SendText ("Area resets installed.\n\r"); } int generate_itemlevel (CAreaData *pArea, CObjIndexData *pObjIndex) { int olevel; int min = UMAX (pArea->low_soft_range, 1); int max = UMIN (pArea->hi_soft_range, min + 15); if (pObjIndex->level > 0) olevel = UMIN (pObjIndex->level, MAX_LEVEL); else switch (pObjIndex->item_type) { default: olevel = 0; break; case ITEM_PILL: olevel = number_range ( min, max); break; case ITEM_POTION: olevel = number_range ( min, max); break; case ITEM_SCROLL: olevel = pObjIndex->value[0]; break; case ITEM_WAND: olevel = number_range (min+4, max+1); break; case ITEM_STAFF: olevel = number_range (min+9, max+5); break; case ITEM_ARMOR: olevel = number_range (min+4, max+1); break; case ITEM_WEAPON: olevel = number_range (min+4, max+1); break; } return olevel; } // Reset one room. void ResetRoom (CRoomIndexData* pRoom, CAreaData* pArea) { CResetData *pReset; CCharacter *mob; CObjData *obj; CObjData *lastobj; CMobIndexData *pMobIndex; CObjIndexData *pObjIndex; CObjIndexData *pObjToIndex; CExitData *pexit; CObjData *to_obj; int level = 0; int *bits = NULL; CIntVector *pIv = NULL; CBitVector *pBv = NULL; if (! pRoom) { bug ("ResetRoom: NULL pRoom"); return; } mob = NULL; obj = NULL; lastobj = NULL; CResetList &RList = pRoom->ResetList; level = 0; POSITION pos = RList.GetHeadPosition (); while (pos) { pReset = RList.GetNext (pos); switch (pReset->command) { default: bug ("ResetRoom %s: bad command %c.", NCCP pRoom->GetName (), pReset->command); break; case 'M': { if (! (pMobIndex = MobTable.GetMob (pReset->mob))) { bug ("ResetRoom %s: 'M': bad mob vnum %d.", NCCP pRoom->GetName (), pReset->mob); continue; } if (pMobIndex->count >= pReset->arg2) { mob = NULL; break; } mob = create_mobile (pMobIndex); CRoomIndexData *pRoomPrev = RoomTable.GetRoom (pRoom->vnum - 1); if (pRoomPrev && pRoomPrev->IsPetShop ()) mob->SetPetFlag (); if (room_is_dark (pRoom)) mob->SetSeeInfra (); mob->SendToRoom (pRoom); economize_mobgold (mob); level = URANGE (0, mob->GetLevel () - 2, LEVEL_AVATAR); } break; case 'G': case 'E': if (! (pObjIndex = OIdxTable.GetObj (pReset->arg1))) { bug ("ResetRoom %s: 'E' or 'G': bad obj vnum %d.", NCCP pRoom->GetName (), pReset->arg1); continue; } if (! mob) lastobj = NULL; else { int olevel = pObjIndex->level; if (mob->GetMobIndex ()->pShop) { if (olevel == 0) olevel = URANGE (0, generate_itemlevel (pArea, pObjIndex), LEVEL_AVATAR); obj = create_object (pObjIndex, olevel); obj->SetInventory (); obj = obj_to_char (obj, mob, ADDBYLEVEL); } else { if (olevel == 0) olevel = number_fuzzy (level); obj = create_object (pObjIndex, olevel); obj->level = URANGE (0, obj->level, LEVEL_AVATAR); obj = obj_to_char (obj, mob); } if (pReset->command == 'E') equip_char (mob, obj, pReset->arg3); lastobj = obj; } break; case 'O': if (! (pObjIndex = OIdxTable.GetObj (pReset->arg1))) { bug ("ResetRoom %s: 'O': bad obj vnum %d.", NCCP pRoom->GetName (), pReset->arg1); continue; } if (pArea->nplayer > 0 || count_obj_list (pObjIndex, pRoom->GetContentList ()) > 0) obj = NULL; else { int lev = pObjIndex->level; if (lev == 0) lev = number_fuzzy (generate_itemlevel (pArea, pObjIndex)); obj = create_object (pObjIndex, lev); obj->level = UMIN (obj->level, LEVEL_AVATAR); obj->cost = 0; obj_to_room (obj, pRoom); } lastobj = obj; break; case 'P': if (! (pObjIndex = OIdxTable.GetObj (pReset->arg1))) { bug ("ResetRoom %s: 'P': bad obj vnum %d.", NCCP pRoom->GetName (), pReset->arg1); continue; } if (pReset->arg3 > 0) { if (! (pObjToIndex = OIdxTable.GetObj (pReset->arg3))) { bug ("ResetRoom %s: 'P': bad objto vnum %d.", NCCP pRoom->GetName (), pReset->arg3); continue; } if (pArea->nplayer > 0 || ! (to_obj = pObjToIndex->GetLast ()) || ! to_obj->in_room || count_obj_list (pObjIndex, to_obj->GetContentList ()) > 0) { obj = NULL; break; } lastobj = to_obj; } else { int iNest; if (! lastobj) break; to_obj = lastobj; for (iNest = 0; iNest < pReset->extra; iNest++) if (! (to_obj = to_obj->GetLastContent ())) { bug ("ResetRoom %s: 'P': Invalid nesting obj %d.", NCCP pRoom->GetName (), pReset->arg1); iNest = -1; break; } if (iNest < 0) continue; } { int lev = pObjIndex->level; if (lev == 0) lev = number_fuzzy (UMAX (generate_itemlevel (pArea, pObjIndex), to_obj->level)); obj = create_object (pObjIndex, lev); obj->level = UMIN (obj->level, LEVEL_AVATAR); obj_to_obj (obj, to_obj); } break; case 'T': if (IS_SET (pReset->extra, TRAP_OBJ)) { // We need to preserve obj for future 'T' and 'H' checks CObjData *pobj; if (pReset->arg3 > 0) { if (! (pObjToIndex = OIdxTable.GetObj (pReset->arg3))) { bug ("ResetRoom %s: 'T': bad objto vnum %d.", NCCP pRoom->GetName (), pReset->arg3); continue; } if (pArea->nplayer > 0 || ! (to_obj = pObjToIndex->GetLast ()) || (to_obj->carried_by && ! to_obj->carried_by->IsNpc ()) || to_obj->IsTrapped ()) break; } else { if (!lastobj || !obj) break; to_obj = obj; } pobj = make_trap (pReset->arg2, pReset->arg1, number_fuzzy (to_obj->level), pReset->extra); obj_to_obj (pobj, to_obj); } else { if (pArea->nplayer > 0 || count_obj_list (OIdxTable.GetObj (OBJ_VNUM_TRAP), pRoom->GetContentList ()) > 0) break; to_obj = make_trap (pReset->arg1, pReset->arg1, 10, pReset->extra); obj_to_room (to_obj, pRoom); } break; case 'H': if (pReset->arg1 > 0) { if (! (pObjToIndex = OIdxTable.GetObj (pReset->arg1))) { bug ("ResetRoom %s: 'H': bad objto vnum %d.", NCCP pRoom->GetName (), pReset->arg1); continue; } if (pArea->nplayer > 0 || ! (to_obj = pObjToIndex->GetLast ()) || ! to_obj->in_room || to_obj->in_room->GetArea () != pArea || to_obj->IsHidden ()) break; } else { if (! lastobj || !obj) break; to_obj = obj; } to_obj->SetHidden (); break; case 'B': switch (pReset->arg2 & BIT_RESET_TYPE_MASK) { case BIT_RESET_DOOR: { int doornum = (pReset->arg2 & BIT_RESET_DOOR_MASK) >> BIT_RESET_DOOR_THRESHOLD; if (! (pexit = get_exit (pRoom, doornum))) break; pIv = pexit->GetFlags (); } break; case BIT_RESET_ROOM: bits = pRoom->GetRoomFlagsAddr (); break; case BIT_RESET_OBJECT: if (pReset->arg1 > 0) { if (! (pObjToIndex = OIdxTable.GetObj (pReset->arg1))) { bug ("ResetRoom %s: 'B': object: bad objto vnum %d.", NCCP pRoom->GetName (), pReset->arg1); continue; } to_obj = pObjToIndex->GetLast (); if (! to_obj || ! to_obj->in_room || to_obj->in_room->GetArea () != pArea) continue; } else { if (!lastobj || !obj) continue; to_obj = obj; } pBv = &to_obj->m_ExtraFlags; break; case BIT_RESET_MOBILE: if (!mob) continue; pBv = mob->GetAffectBitsAddr (); break; default: bug ("ResetRoom %s: 'B': bad options %d.", NCCP pRoom->GetName (), pReset->arg2); continue; } if (bits) { if (IS_SET (pReset->arg2, BIT_RESET_SET)) SET_BIT (*bits, pReset->arg3); else if (IS_SET (pReset->arg2, BIT_RESET_TOGGLE)) TOGGLE_BIT (*bits, pReset->arg3); else REMOVE_BIT (*bits, pReset->arg3); break; } if (pBv) { if (IS_SET (pReset->arg2, BIT_RESET_SET)) pBv->SetBit (pReset->arg3); else if (IS_SET (pReset->arg2, BIT_RESET_TOGGLE)) pBv->ToggleBit (pReset->arg3); else pBv->ClrBit (pReset->arg3); break; } if (pIv) { if (IS_SET (pReset->arg2, BIT_RESET_SET)) pIv->SetBit (pReset->arg3); else if (IS_SET (pReset->arg2, BIT_RESET_TOGGLE)) pIv->ToggleBit (pReset->arg3); else pIv->ClrBit (pReset->arg3); break; } break; case 'D': if (! (pexit = get_exit (pRoom, pReset->arg2))) break; switch (pReset->arg3) { case 0: pexit->ClrClosed (); pexit->ClrLocked (); break; case 1: pexit->SetClosed (); pexit->ClrLocked (); if (pexit->CanSearch ()) pexit->SetSecret (); break; case 2: pexit->SetClosed (); pexit->SetLocked (); if (pexit->CanSearch ()) pexit->SetSecret (); break; } break; case 'R': randomize_exits (pRoom, pReset->arg2-1); break; } } } void list_resets (CCharacter *ch, CRoomIndexData *pRoom, int start, int end) { CResetData *pReset; CRoomIndexData *room; CMobIndexData *mob; CObjIndexData *obj, *obj2; CObjIndexData *lastobj; BOOL found; int num = 0; const char *rname, *mname, *oname; char buf [256]; char *pbuf; if (!ch || !pRoom) return; room = NULL; mob = NULL; obj = NULL; lastobj = NULL; found = FALSE; ch->SendColorf ("&YResets for: %s (%d):\n", pRoom->GetName (), pRoom->vnum); CResetList &RList = pRoom->ResetList; if (RList.IsEmpty ()) { ch->SendText ("No Resets\n"); return; } POSITION LoResetPos = NULL; POSITION pos = RList.GetHeadPosition (); while (pos) { pReset = RList.GetNext (pos); ++num; sprintf (buf, "&G%2d) ", num); pbuf = buf+strlen (buf); switch (pReset->command) { default: sprintf (pbuf, "*** BAD RESET: %c %d %d %d %d %d ***\n\r", pReset->command, pReset->extra, pReset->mob, pReset->arg1, pReset->arg2, pReset->arg3); break; case 'M': if (! (mob = MobTable.GetMob (pReset->mob))) mname = "Mobile: *BAD VNUM*"; else mname = mob->GetPlayerName (); sprintf (pbuf, "%s (%d) [%d]%s\n\r", mname, pReset->mob, pReset->arg2, pRoom->IsPetShop () ? " (pet)" : ""); break; case 'G': case 'E': if (! mob) mname = "* ERROR: NO MOBILE! *"; if (! (obj = OIdxTable.GetObj (pReset->arg1))) oname = "Object: *BAD VNUM*"; else oname = obj->GetName (); sprintf (pbuf, "%s (%d) -> %s (%s) [%d]", oname, pReset->arg1, mname, (pReset->command == 'G' ? "carry" : wear_locs[pReset->arg3]), pReset->arg2); if (mob && mob->pShop) strcat (buf, " (shop)\n\r"); else strcat (buf, "\n\r"); lastobj = obj; LoResetPos = pos; break; case 'O': if (! (obj = OIdxTable.GetObj (pReset->arg1))) oname = "Object: *BAD VNUM*"; else oname = obj->GetName (); sprintf (pbuf, "(object) %s (%d) [%d]\n\r", oname, pReset->arg1, pReset->arg2); lastobj = obj; LoResetPos = pos; break; case 'P': if (! (obj = OIdxTable.GetObj (pReset->arg1))) oname = "Object1: *BAD VNUM*"; else oname = obj->GetName (); obj2 = NULL; if (pReset->arg3 > 0) { obj2 = OIdxTable.GetObj (pReset->arg3); rname = (obj2 ? obj2->GetName () : "Object2: *BAD VNUM*"); lastobj = obj2; } else if (!lastobj) rname = "Object2: *NULL obj*"; else if (pReset->extra == 0) { rname = lastobj->GetName (); obj2 = lastobj; } else { int iNest; CResetData *reset; reset = RList.GetAt (LoResetPos); POSITION pos = LoResetPos; for (iNest = 0; iNest < pReset->extra; iNest++) { while (pos) { reset = RList.GetNext (pos); char c = reset->command; if (c == 'O' || c == 'G' || c == 'E' || (c == 'P' && !reset->arg3 && reset->extra == iNest)) break; reset = NULL; } if (! reset || reset->command != 'P') break; } if (! reset) rname = "Object2: *BAD NESTING*"; else if (! (obj2 = OIdxTable.GetObj (reset->arg1))) rname = "Object2: *NESTED BAD VNUM*"; else rname = obj2->GetName (); } sprintf (pbuf, "(Put) %s (%d) -> %s (%d) [%d] {nest %d}\n\r", oname, pReset->arg1, rname, (obj2 ? obj2->vnum : pReset->arg3), pReset->arg2, pReset->extra); break; case 'T': sprintf (pbuf, "TRAP: %d %d %d %d (%s)\n\r", pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, flag_string (pReset->extra, trap_flags)); break; case 'H': if (pReset->arg1 > 0) if (! (obj2 = OIdxTable.GetObj (pReset->arg1))) rname = "Object: *BAD VNUM*"; else rname = obj2->GetName (); else if (!obj) rname = "Object: *NULL obj*"; else rname = oname; sprintf (pbuf, "Hide %s (%d)\n\r", rname, (pReset->arg1 > 0 ? pReset->arg1 : obj ? obj->vnum : 0)); break; case 'B': { char* const *flagarray; strcpy (pbuf, "BIT: "); pbuf += 5; if (IS_SET (pReset->arg2, BIT_RESET_SET)) { strcpy (pbuf, "Set: "); pbuf += 5; } else if (IS_SET (pReset->arg2, BIT_RESET_TOGGLE)) { strcpy (pbuf, "Toggle: "); pbuf += 8; } else { strcpy (pbuf, "Remove: "); pbuf += 8; } switch (pReset->arg2 & BIT_RESET_TYPE_MASK) { case BIT_RESET_DOOR: { int door; if (! (room = RoomTable.GetRoom (pReset->arg1))) rname = "Room: *BAD VNUM*"; else rname = room->GetName (); door = (pReset->arg2 & BIT_RESET_DOOR_MASK) >> BIT_RESET_DOOR_THRESHOLD; door = URANGE (0, door, MAX_DIR+1); sprintf (pbuf, "Exit %s%s (%d), Room %s (%d)", dir_name [door], (room && get_exit (room, door) ? "" : " (NO EXIT!)"), door, rname, pReset->arg1); } flagarray = (char* const *) ExitTypeNames; break; case BIT_RESET_ROOM: sprintf (pbuf, "Room %s (%d)", pRoom->GetName (), pReset->arg1); flagarray = r_flags; break; case BIT_RESET_OBJECT: if (pReset->arg1 > 0) if (! (obj2 = OIdxTable.GetObj (pReset->arg1))) rname = "Object: *BAD VNUM*"; else rname = obj2->GetName (); else if (!obj) rname = "Object: *NULL obj*"; else rname = oname; sprintf (pbuf, "Object %s (%d)", rname, (pReset->arg1 > 0 ? pReset->arg1 : obj ? obj->vnum : 0)); flagarray = (char* const *) ItemFlagNames; break; case BIT_RESET_MOBILE: if (pReset->arg1 > 0) { CMobIndexData *mob2; if (! (mob2 = MobTable.GetMob (pReset->arg1))) rname = "Mobile: *BAD VNUM*"; else rname = mob2->GetPlayerName (); } else if (!mob) rname = "Mobile: *NULL mob*"; else rname = mname; sprintf (pbuf, "Mobile %s (%d)", rname, (pReset->arg1 > 0 ? pReset->arg1 : mob ? mob->vnum : 0)); flagarray = (char* const *) AffectNames; break; default: sprintf (pbuf, "bad type %d", pReset->arg2 & BIT_RESET_TYPE_MASK); flagarray = NULL; break; } pbuf += strlen (pbuf); if (flagarray) sprintf (pbuf, "; flags: %s [%d]\n\r", flag_string (pReset->arg3, flagarray), pReset->arg3); else sprintf (pbuf, "; flags %d\n\r", pReset->arg3); } break; case 'D': { char *ef_name; pReset->arg2 = URANGE (0, pReset->arg2, MAX_DIR+1); switch (pReset->arg3) { default: ef_name = "(* ERROR *)"; break; case 0: ef_name = "Open"; break; case 1: ef_name = "Close"; break; case 2: ef_name = "Close and lock"; break; } CExitData *pExit = get_exit (pRoom, pReset->arg2); const char *eroom = "UNASSIGNED"; int evnum = 0; if (pExit && pExit->GetToRoom ()) { eroom = pExit->GetToRoom ()->GetName (); evnum = pExit->GetToRoom ()->vnum; } sprintf (pbuf, "%s [%d] the %s [%d] door to %s (%d)\n\r", ef_name, pReset->arg3, dir_name [pReset->arg2], pReset->arg2, pExit ? eroom : "NO EXIT!", evnum); } break; case 'R': sprintf (pbuf, "Randomize exits 0 to %d -> %s (%d)\n\r", pReset->arg2, pRoom->GetName (), pReset->arg1); break; } if (start == -1 || num >= start) ch->SendColor (buf); if (end != -1 && num >= end) break; } if (num == 0) ch->SendText ("You don't have any resets defined.\n\r"); } void RenumberPutResets (CAreaData* pArea) { POSITION pos = pArea->RoomList.GetHeadPosition (); while (pos) RenumberPutResetsForRoom ( (CRoomIndexData*) pArea->RoomList.GetNext (pos)); } // Setup put nesting levels, regardless of whether or not the resets will // actually reset, or if they're bugged. void RenumberPutResetsForRoom (CRoomIndexData* pRoom) { CResetData *pLast = NULL; POSITION pos = pRoom->ResetList.GetHeadPosition (); while (pos) { CResetData &Res = *pRoom->ResetList.GetNext (pos); switch (Res.command) { case 'G': case 'E': case 'O': pLast = &Res; break; case 'P': if (Res.arg3 == 0) { if (! pLast) Res.extra = 1000000; else if (pLast->command != 'P' || pLast->arg3 > 0) Res.extra = 0; else Res.extra = pLast->extra + 1; pLast = &Res; } } } } // Search backwards to find a reset with an equal command letter. // Enter with pos set to NULL to start at end, or else with pos set to the // reset which you want to search backwards from. // If a previous equal command is found then set pos to it, and return TRUE. // Otherwise return FALSE and with pos set to the last reset with a command // which is less than the one we are searching for, or to the head of the // list (or to NULL if the list is empty). BOOL CResetList::FindPrevCommand (POSITION& pos, char cmd) { if (! pos) then pos = GetTailPosition (); else GetPrev (pos); while (pos) { CResetData *rd = GetPrev (pos); if (rd->command <= cmd) { pos = m_CurPos; return rd->command == cmd; } } pos = GetHeadPosition (); return FALSE; } enum { A1A1, A1A2, A1A3, A3A1 }; POSITION FindInsertLocation (CResetList& RList, char c, int i1, int i2, int Type) { CResetData tmp; int *p1, *p2; switch (Type) { case A1A1: p1 = &tmp.arg1; p2 = &tmp.arg1; break; case A1A2: p1 = &tmp.arg1; p2 = &tmp.arg2; break; case A1A3: p1 = &tmp.arg1; p2 = &tmp.arg3; break; case A3A1: p1 = &tmp.arg3; p2 = &tmp.arg1; break; } int &t1 = *p1; int &t2 = *p2; POSITION pos = NULL; // makes FindPrevCommand start at end if (! RList.FindPrevCommand (pos, c)) return pos; // pos points to the reset to insert after, // (or NULL) int test = 1; for (;;) { tmp = *RList.GetAt (pos); switch (test) { case 1: if (i1 < t1) then break; if (i1 == t1) then ++test; case 2: if (i1 != t1 || i2 > t2) { RList.GetNext (pos); return pos; } break; } POSITION LastPos = pos; if (! RList.FindPrevCommand (pos, c)) return pos; } } // Place a reset into a room, insert sorting it -Thoric void PlaceReset (CRoomIndexData *pRoom, CResetData* pReset) { CResetData *tmp = NULL; int Cmd = pReset->command; int Extra = pReset->extra; int Mob = pReset->mob; int arg1 = pReset->arg1; int arg2 = pReset->arg2; int arg3 = pReset->arg3; CResetList &RList = pRoom->ResetList; if (! RList.IsEmpty ()) { POSITION pos; switch (Cmd) { default: bug ("place_reset: Bad reset type %c", Cmd); delete pReset; return; case 'D': case 'R': pos = FindInsertLocation (RList, Cmd, arg1, arg2, A1A2); if (pos) then RList.InsertBefore (pos, pReset); else RList.AddTail (pReset); return; // for (tmp = tarea->last_reset; tmp; tmp = tmp->GetPrev ()) // if (tmp->command == letter) // break; // if (tmp) // organize by location // for (; tmp && tmp->command == letter && tmp->arg1 > arg1; // tmp = tmp->GetPrev ()); // if (tmp) // organize by direction // for (; tmp && tmp->command == letter && // tmp->arg1 == tmp->arg1 && tmp->arg2 > arg2; // tmp = tmp->GetPrev ()); // if (tmp) // INSERT (pReset, tmp, tarea->first_reset); // else // LINK (pReset, tarea->first_reset, tarea->last_reset); // return pReset; case 'M': case 'O': // for a new mob or object we want to insert just after the // last mob or object with a lower vnum pos = FindInsertLocation (RList, Cmd, arg3, arg1, A3A1); if (pos) { // skip over E or G for that mob if (Cmd == 'M') { while (pos) { tmp = RList.GetNext (pos); if (tmp->command != 'E' && tmp->command != 'G') break; } } // skip over P, T or H for that obj else if (Cmd == 'O') { while (pos) { tmp = RList.GetNext (pos); char c = tmp->command; if (c != 'P' && c != 'T' && c != 'H') then break; } } } if (pos) RList.InsertBefore (pos, pReset); else RList.AddTail (pReset); return; case 'G': case 'E': pos = FindInsertLocation (RList, Cmd, arg1, arg1, A1A1); if (pos) then RList.InsertBefore (pos, pReset); else RList.AddTail (pReset); return; case 'P': case 'T': case 'H': // find the object in question if ((Cmd == 'P' && arg3 == 0) || (Cmd == 'T' && IS_SET (Extra, TRAP_OBJ) && arg1 == 0) || (Cmd == 'H' && arg1 == 0)) { // && (tmp = tarea->last_obj_reset)) { pos = RList.Find (tmp); RList.GetNext (pos); if (pos) RList.InsertBefore (pos, pReset); else RList.AddTail (pReset); return; } pos = FindInsertLocation (RList, Cmd, arg1, arg3, A1A3); if (pos) then RList.InsertBefore (pos, pReset); else RList.AddTail (pReset); return; } } RList.AddTail (pReset); } void CRoomIndexData::AddReset (char cm, int ex, int mob, int a1, int a2, int a3) { CResetData *pReset = new CResetData (cm, ex, mob, a1, a2, a3); ResetList.AddTail (pReset); }