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