/****************************************************************************
* [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame | \\._.// *
* -----------------------------------------------------------| (0...0) *
* SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by Derek Snider | ).:.( *
* -----------------------------------------------------------| {o o} *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus, | / ' ' \ *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh, Nivek, |~'~.VxvxV.~'~*
* Tricops and Fireblade | *
* ------------------------------------------------------------------------ *
* 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 St{rfeldt, Tom Madsen, and Katja Nyboe. *
* ------------------------------------------------------------------------ *
* Game Reset Handler and Editing Module *
* SmaugFUSS 1.8 Version *
****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "h/mud.h"
/* Externals */
extern int top_reset;
int get_trapflag(char *flag);
extern bool mud_down;
/*
* Find some object with a given index data.
* Used by area-reset 'P', 'T' and 'H' commands.
*/
OBJ_DATA *get_obj_type(OBJ_INDEX_DATA *pObjIndex)
{
OBJ_DATA *obj;
for(obj = first_object; obj; obj = obj->next)
{
if(obj->pIndexData == pObjIndex)
return obj;
}
return NULL;
}
/* Find an object in a room so we can check it's dependents. Used by 'O' resets. */
OBJ_DATA *get_obj_room(OBJ_INDEX_DATA *pObjIndex, ROOM_INDEX_DATA *pRoomIndex)
{
OBJ_DATA *obj;
for(obj = pRoomIndex->first_content; obj; obj = obj->next_content)
{
if(obj->pIndexData == pObjIndex)
return obj;
}
return NULL;
}
char *sprint_reset(RESET_DATA *pReset, short *num)
{
RESET_DATA *tReset, *gReset;
static char buf[MAX_STRING_LENGTH];
char mobname[MAX_STRING_LENGTH], roomname[MAX_STRING_LENGTH], objname[MAX_STRING_LENGTH];
static ROOM_INDEX_DATA *room;
static OBJ_INDEX_DATA *obj, *obj2;
static MOB_INDEX_DATA *mob;
switch (pReset->command)
{
default:
snprintf(buf, MAX_STRING_LENGTH, "%2d) *** BAD RESET: %c %d %d %d %d ***\r\n", *num, pReset->command, pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3);
break;
case 'M':
mob = get_mob_index(pReset->arg1);
room = get_room_index(pReset->arg3);
if(mob)
strncpy(mobname, mob->player_name, MAX_STRING_LENGTH);
else
strncpy(mobname, "Mobile: *BAD VNUM*", MAX_STRING_LENGTH);
if(room)
strncpy(roomname, room->name, MAX_STRING_LENGTH);
else
strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
snprintf(buf, MAX_STRING_LENGTH, "%2d) %s (%d) -> %s Room: %d [%d]%s\r\n", *num, mobname, pReset->arg1, roomname, pReset->arg3, pReset->arg2, pReset->ch ? " [Reseted]" : "");
for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
{
(*num)++;
switch (tReset->command)
{
case 'E':
if(!mob)
strncpy(mobname, "* ERROR: NO MOBILE! *", MAX_STRING_LENGTH);
if(!(obj = get_obj_index(tReset->arg1)))
strncpy(objname, "Object: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(objname, obj->name, MAX_STRING_LENGTH);
snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf),
"%2d) (equip) %s (%d) -> %s (%s) [%d]%s\r\n", *num, objname, tReset->arg1, mobname, wear_locs[tReset->arg3], tReset->arg2, tReset->obj ? " [Reseted]" : "");
break;
case 'G':
if(!mob)
strncpy(mobname, "* ERROR: NO MOBILE! *", MAX_STRING_LENGTH);
if(!(obj = get_obj_index(tReset->arg1)))
strncpy(objname, "Object: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(objname, obj->name, MAX_STRING_LENGTH);
snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf), "%2d) (carry) %s (%d) -> %s [%d]%s\r\n", *num, objname, tReset->arg1, mobname, tReset->arg2, tReset->obj ? " [Reseted]" : "");
break;
}
if(tReset->first_reset)
{
for(gReset = tReset->first_reset; gReset; gReset = gReset->next_reset)
{
(*num)++;
switch (gReset->command)
{
case 'P':
if(!(obj2 = get_obj_index(gReset->arg1)))
strncpy(objname, "Object1: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(objname, obj2->name, MAX_STRING_LENGTH);
if(gReset->arg3 > 0 && (obj = get_obj_index(gReset->arg3)) == NULL)
strncpy(roomname, "Object2: *BAD VNUM*", MAX_STRING_LENGTH);
else if(!obj)
strncpy(roomname, "Object2: *NULL obj*", MAX_STRING_LENGTH);
else
strncpy(roomname, obj->name, MAX_STRING_LENGTH);
snprintf(buf + strlen(buf),
MAX_STRING_LENGTH - strlen(buf),
"%2d) (put) %s (%d) -> %s (%d) [%d]%s\r\n", *num, objname, gReset->arg1, roomname, obj ? obj->vnum : gReset->arg3, gReset->arg2, gReset->obj ? " [Reseted]" : "");
break;
}
}
}
}
break;
case 'O':
if(!(obj = get_obj_index(pReset->arg1)))
strncpy(objname, "Object: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(objname, obj->name, MAX_STRING_LENGTH);
room = get_room_index(pReset->arg3);
if(!room)
strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(roomname, room->name, MAX_STRING_LENGTH);
snprintf(buf, MAX_STRING_LENGTH, "%2d) (object) %s (%d) -> %s Room: %d [%d]%s\r\n", *num, objname, pReset->arg1, roomname, pReset->arg3, pReset->arg2, pReset->obj ? " [Reseted]" : "");
for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
{
(*num)++;
switch (tReset->command)
{
case 'P':
if(!(obj2 = get_obj_index(tReset->arg1)))
strncpy(objname, "Object1: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(objname, obj2->name, MAX_STRING_LENGTH);
if(tReset->arg3 > 0 && (obj = get_obj_index(tReset->arg3)) == NULL)
strncpy(roomname, "Object2: *BAD VNUM*", MAX_STRING_LENGTH);
else if(!obj)
strncpy(roomname, "Object2: *NULL obj*", MAX_STRING_LENGTH);
else
strncpy(roomname, obj->name, MAX_STRING_LENGTH);
snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf),
"%2d) (put) %s (%d) -> %s (%d) [%d]%s\r\n", *num, objname, tReset->arg1, roomname, obj ? obj->vnum : tReset->arg3, tReset->arg2, tReset->obj ? " [Reseted]" : "");
break;
case 'T':
snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf),
"%2d) (trap) %d %d %d %d (%s) -> %s (%d)\r\n", *num,
tReset->extra, tReset->arg1, tReset->arg2, tReset->arg3, flag_string(tReset->extra, trap_flags), objname, obj ? obj->vnum : 0);
break;
case 'H':
snprintf(buf + strlen(buf), MAX_STRING_LENGTH - strlen(buf), "%2d) (hide) -> %s\r\n", *num, objname);
break;
}
}
break;
case 'D':
if(pReset->arg2 < 0 || pReset->arg2 > MAX_DIR + 1)
pReset->arg2 = 0;
if(!(room = get_room_index(pReset->arg1)))
{
strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
snprintf(objname, MAX_STRING_LENGTH, "%s (no exit)", dir_name[pReset->arg2]);
}
else
{
strncpy(roomname, room->name, MAX_STRING_LENGTH);
snprintf(objname, MAX_STRING_LENGTH, "%s%s", dir_name[pReset->arg2], get_exit(room, pReset->arg2) ? "" : " (NO EXIT!)");
}
switch (pReset->arg3)
{
default:
strncpy(mobname, "(* ERROR *)", MAX_STRING_LENGTH);
break;
case 0:
strncpy(mobname, "Open", MAX_STRING_LENGTH);
break;
case 1:
strncpy(mobname, "Close", MAX_STRING_LENGTH);
break;
case 2:
strncpy(mobname, "Close and lock", MAX_STRING_LENGTH);
break;
case 3:
strncpy(mobname, "Dig (collapse)", MAX_STRING_LENGTH);
break;
}
snprintf(buf, MAX_STRING_LENGTH, "%2d) %s [%d] the %s [%d] door %s (%d)\r\n", *num, mobname, pReset->arg3, objname, pReset->arg2, roomname, pReset->arg1);
break;
case 'R':
if(!(room = get_room_index(pReset->arg1)))
strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(roomname, room->name, MAX_STRING_LENGTH);
snprintf(buf, MAX_STRING_LENGTH, "%2d) Randomize exits 0 to %d -> %s (%d)\r\n", *num, pReset->arg2, roomname, pReset->arg1);
break;
case 'T':
if(!(room = get_room_index(pReset->arg3)))
strncpy(roomname, "Room: *BAD VNUM*", MAX_STRING_LENGTH);
else
strncpy(roomname, room->name, MAX_STRING_LENGTH);
snprintf(buf, MAX_STRING_LENGTH, "%2d) Trap: %d %d %d %d (%s) -> %s (%d)\r\n",
*num, pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, flag_string(pReset->extra, trap_flags), roomname, room ? room->vnum : 0);
break;
}
return buf;
}
/*
* Create a new reset (for online building) - Thoric
*/
RESET_DATA *make_reset(char letter, int extra, int arg1, int arg2, int arg3)
{
RESET_DATA *pReset;
CREATE(pReset, RESET_DATA, 1);
pReset->command = letter;
pReset->extra = extra;
pReset->arg1 = arg1;
pReset->arg2 = arg2;
pReset->arg3 = arg3;
pReset->obj = NULL;
pReset->ch = NULL;
top_reset++;
return pReset;
}
void add_obj_reset(ROOM_INDEX_DATA *room, char cm, OBJ_DATA *obj, int v2, int v3)
{
RESET_DATA *reset;
OBJ_DATA *inobj;
static int iNest;
if((cm == 'O' || cm == 'P') && obj->pIndexData->vnum == OBJ_VNUM_TRAP)
{
if(cm == 'O')
{
reset = add_reset(room, 'T', obj->value[3], obj->value[1], obj->value[0], v3);
if(reset)
{
obj->reset = reset;
reset->obj = obj;
}
}
return;
}
reset = add_reset(room, cm, (cm == 'P' ? iNest : 0), obj->pIndexData->vnum, v2, v3);
if(reset)
{
obj->reset = reset;
reset->obj = obj;
}
if(cm == 'O' && IS_OBJ_STAT(obj, ITEM_HIDDEN) && !CAN_WEAR(obj, ITEM_TAKE))
{
reset = add_reset(room, 'H', 1, 0, 0, 0);
if(reset)
{
obj->reset = reset;
reset->obj = obj;
}
}
for(inobj = obj->first_content; inobj; inobj = inobj->next_content)
{
if(inobj->pIndexData->vnum == OBJ_VNUM_TRAP)
add_obj_reset(room, 'O', inobj, 0, 0);
}
if(cm == 'P')
iNest++;
for(inobj = obj->first_content; inobj; inobj = inobj->next_content)
add_obj_reset(room, 'P', inobj, inobj->count, obj->pIndexData->vnum);
if(cm == 'P')
iNest--;
return;
}
void delete_reset(RESET_DATA *pReset)
{
RESET_DATA *tReset, *tReset_next;
for(tReset = pReset->first_reset; tReset; tReset = tReset_next)
{
tReset_next = tReset->next_reset;
UNLINK(tReset, pReset->first_reset, pReset->last_reset, next_reset, prev_reset);
delete_reset(tReset);
}
if(pReset->ch)
pReset->ch->reset = NULL;
pReset->ch = NULL;
if(pReset->obj)
pReset->obj->reset = NULL;
pReset->obj = NULL;
pReset->first_reset = pReset->last_reset = NULL;
DISPOSE(pReset);
return;
}
void instaroom(ROOM_INDEX_DATA *pRoom, bool dodoors)
{
CHAR_DATA *rch;
OBJ_DATA *obj;
RESET_DATA *preset;
for(rch = pRoom->first_person; rch; rch = rch->next_in_room)
{
if(!IS_NPC(rch))
continue;
preset = add_reset(pRoom, 'M', 1, rch->pIndexData->vnum, rch->pIndexData->count, pRoom->vnum);
preset->obj = NULL;
if(rch->reset) /* Set the old ch reset ch to NULL so it can reset later */
rch->reset->ch = NULL;
preset->ch = rch;
rch->reset = preset;
for(obj = rch->first_carrying; obj; obj = obj->next_content)
{
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);
}
}
for(obj = pRoom->first_content; obj; obj = obj->next_content)
add_obj_reset(pRoom, 'O', obj, obj->count, pRoom->vnum);
if(dodoors)
{
EXIT_DATA *pexit;
for(pexit = pRoom->first_exit; pexit; pexit = pexit->next)
{
int state = 0;
/* Volk - updated this so we can reset dig/hidden exits */
if(!IS_SET(pexit->exit_info, EX_ISDOOR) && !IS_SET(pexit->exit_info, EX_DIG))
continue;
if(IS_SET(pexit->exit_info, EX_CLOSED))
{
if(IS_SET(pexit->exit_info, EX_LOCKED))
state = 2;
else
state = 1;
}
if(IS_SET(pexit->exit_info, EX_DIG))
state = 3;
add_reset(pRoom, 'D', 0, pRoom->vnum, pexit->vdir, state);
}
}
return;
}
void wipe_resets(ROOM_INDEX_DATA *room)
{
RESET_DATA *pReset, *pReset_next;
for(pReset = room->first_reset; pReset; pReset = pReset_next)
{
pReset_next = pReset->next;
UNLINK(pReset, room->first_reset, room->last_reset, next, prev);
delete_reset(pReset);
}
room->first_reset = room->last_reset = NULL;
return;
}
void wipe_area_resets(AREA_DATA *area)
{
ROOM_INDEX_DATA *room;
if(!mud_down)
{
for(room = area->first_room; room; room = room->next_aroom)
wipe_resets(room);
}
return;
}
/* Function modified from original form - Samson */
void do_instaroom(CHAR_DATA *ch, char *argument)
{
bool dodoors;
if(IS_NPC(ch) || get_trust(ch) < LEVEL_IMMORTAL || !ch->pcdata->area)
{
send_to_char("You don't have an assigned area to create resets for.\r\n", ch);
return;
}
if(!str_cmp(argument, "nodoors"))
dodoors = FALSE;
else
dodoors = TRUE;
if(!can_rmodify(ch, ch->in_room))
return;
if(ch->in_room->area != ch->pcdata->area && get_trust(ch) < LEVEL_AJ_SGT)
{
send_to_char("You cannot reset this room.\r\n", ch);
return;
}
if(ch->in_room->first_reset)
wipe_resets(ch->in_room);
instaroom(ch->in_room, dodoors);
send_to_char("Room resets installed.\r\n", ch);
}
/* Function modified from original form - Samson */
void do_instazone(CHAR_DATA *ch, char *argument)
{
AREA_DATA *pArea;
ROOM_INDEX_DATA *pRoom;
bool dodoors;
if(IS_NPC(ch) || get_trust(ch) < LEVEL_IMMORTAL || !ch->pcdata->area)
{
send_to_char("You don't have an assigned area to create resets for.\r\n", ch);
return;
}
if(!str_cmp(argument, "nodoors"))
dodoors = FALSE;
else
dodoors = TRUE;
pArea = ch->pcdata->area;
wipe_area_resets(pArea);
for(pRoom = pArea->first_room; pRoom; pRoom = pRoom->next_aroom)
instaroom(pRoom, dodoors);
send_to_char("Area resets installed.\r\n", ch);
return;
}
int generate_itemlevel(AREA_DATA *pArea, OBJ_INDEX_DATA *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;
}
/*
* Count occurrences of an obj in a list.
*/
int count_obj_list(OBJ_INDEX_DATA *pObjIndex, OBJ_DATA *list)
{
OBJ_DATA *obj;
int nMatch = 0;
for(obj = list; obj; obj = obj->next_content)
{
if(obj->pIndexData == pObjIndex)
{
if(obj->count > 1)
nMatch += obj->count;
else
nMatch++;
}
}
return nMatch;
}
/*
* Reset one room.
*/
void reset_room(ROOM_INDEX_DATA *room)
{
RESET_DATA *pReset, *tReset, *gReset;
OBJ_DATA *nestmap[MAX_NEST];
CHAR_DATA *mob;
OBJ_DATA *obj, *lastobj, *to_obj;
ROOM_INDEX_DATA *pRoomIndex = NULL;
MOB_INDEX_DATA *pMobIndex = NULL;
OBJ_INDEX_DATA *pObjIndex = NULL, *pObjToIndex;
EXIT_DATA *pexit;
const char *filename = room->area->filename;
int level = 0, n, num = 0, lastnest;
mob = NULL;
obj = NULL;
lastobj = NULL;
if(!room->first_reset)
return;
level = 0;
for(pReset = room->first_reset; pReset; pReset = pReset->next)
{
switch (pReset->command)
{
default:
bug("%s: %s: bad command %c.", __FUNCTION__, filename, pReset->command);
break;
case 'M':
if(!(pMobIndex = get_mob_index(pReset->arg1)))
{
bug("%s: %s: 'M': bad mob vnum %d.", __FUNCTION__, filename, pReset->arg1);
continue;
}
if(!(pRoomIndex = get_room_index(pReset->arg3)))
{
bug("%s: %s: 'M': bad room vnum %d.", __FUNCTION__, filename, pReset->arg3);
continue;
}
if(pReset->ch)
mob = pReset->ch;
else
{
mob = create_mobile(pMobIndex);
if(IS_SET(pRoomIndex->room_flags, ROOM_PET_STOREROOM))
{
ROOM_INDEX_DATA *pRoomPrev = get_room_index(pReset->arg3 - 1);
if(pRoomPrev && IS_SET(pRoomPrev->room_flags, ROOM_PET_SHOP))
xSET_BIT(mob->act, ACT_PET);
}
if(room_is_dark(pRoomIndex))
xSET_BIT(mob->affected_by, AFF_INFRARED);
char_to_room(mob, pRoomIndex);
}
mob->reset = pReset;
pReset->ch = mob;
level = URANGE(0, mob->level - 2, LEVEL_AVATAR);
if(pReset->first_reset)
{
for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
{
switch (tReset->command)
{
case 'G':
case 'E':
if(!(pObjIndex = get_obj_index(tReset->arg1)))
{
bug("%s: %s: 'E' or 'G': bad obj vnum %d.", __FUNCTION__, filename, tReset->arg1);
continue;
}
if(!mob)
{
lastobj = NULL;
continue;
}
if(tReset->obj)
obj = tReset->obj;
else
{
/*
* If we are giving it to them (can be sold) then do the inventory else
* just handle it normal
*/
if(tReset->command == 'G')
{
if(mob->pIndexData->pShop)
{
int olevel = generate_itemlevel(room->area, pObjIndex);
obj = create_object(pObjIndex, olevel);
xSET_BIT(obj->extra_flags, ITEM_INVENTORY);
}
else
obj = create_object(pObjIndex, number_fuzzy(level));
}
else
obj = create_object(pObjIndex, number_fuzzy(level));
}
if(!obj)
{
bug("%s: object is NULL.", __FUNCTION__);
continue;
}
tReset->obj = obj;
obj->reset = tReset;
obj->level = URANGE(0, obj->level, LEVEL_AVATAR);
if(!obj->carried_by)
{
xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
obj = obj_to_char(obj, mob);
if(obj)
{
tReset->obj = obj;
obj->reset = tReset;
}
if(tReset->command == 'E')
{
if(obj->carried_by != mob)
{
bug("'E' reset: can't give object %d to mob %d.", obj->pIndexData->vnum, mob->pIndexData->vnum);
continue;
}
equip_char(mob, obj, tReset->arg3);
}
xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
}
for(n = 0; n < MAX_NEST; n++)
nestmap[n] = NULL;
nestmap[0] = obj;
lastobj = nestmap[0];
lastnest = 0;
if(tReset->first_reset)
{
for(gReset = tReset->first_reset; gReset; gReset = gReset->next_reset)
{
int iNest;
to_obj = lastobj;
switch (gReset->command)
{
case 'H':
if(!lastobj)
break;
xSET_BIT(lastobj->extra_flags, ITEM_HIDDEN);
break;
case 'P':
if(!(pObjIndex = get_obj_index(gReset->arg1)))
{
bug("%s: %s: 'P': bad obj vnum %d.", __FUNCTION__, filename, gReset->arg1);
continue;
}
iNest = gReset->extra;
if(!(pObjToIndex = get_obj_index(gReset->arg3)))
{
bug("%s: %s: 'P': bad objto vnum %d.", __FUNCTION__, filename, gReset->arg3);
continue;
}
if(iNest >= MAX_NEST)
{
bug("%s: %s: 'P': Exceeded nesting limit of %d", __FUNCTION__, filename, MAX_NEST);
obj = NULL;
break;
}
if(count_obj_list(pObjIndex, to_obj->first_content) > 0)
{
obj = NULL;
continue;
}
if(gReset->obj)
obj = gReset->obj;
else
{
if(iNest < lastnest)
to_obj = nestmap[iNest];
else if(iNest == lastnest)
to_obj = nestmap[lastnest];
else
to_obj = lastobj;
obj = create_object(pObjIndex, number_fuzzy(UMAX(generate_itemlevel(room->area, pObjIndex), to_obj->level)));
if(num > 1)
pObjIndex->count += (num - 1);
obj->count = gReset->arg2;
obj->level = UMIN(obj->level, LEVEL_AVATAR);
obj->count = gReset->arg2;
xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
obj_to_obj(obj, to_obj);
xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
if(iNest > lastnest)
{
nestmap[iNest] = to_obj;
lastnest = iNest;
}
}
if(!obj)
{
bug("%s: object is NULL.", __FUNCTION__);
continue;
}
obj->reset = gReset;
gReset->obj = obj;
lastobj = obj;
/*
* Hackish fix for nested puts
*/
if(gReset->arg3 == OBJ_VNUM_MONEY_ONE)
gReset->arg3 = to_obj->pIndexData->vnum;
break;
}
}
}
break;
}
}
}
break;
case 'O':
if(!(pObjIndex = get_obj_index(pReset->arg1)))
{
bug("%s: %s: 'O': bad obj vnum %d.", __FUNCTION__, filename, pReset->arg1);
continue;
}
if(!(pRoomIndex = get_room_index(pReset->arg3)))
{
bug("%s: %s: 'O': bad room vnum %d.", __FUNCTION__, filename, pReset->arg3);
continue;
}
if(pReset->obj)
obj = pReset->obj;
else
{
if(count_obj_list(pObjIndex, pRoomIndex->first_content) < 1)
{
obj = create_object(pObjIndex, number_fuzzy(generate_itemlevel(room->area, pObjIndex)));
if(num > 1)
pObjIndex->count += (num - 1);
obj->count = pReset->arg2;
obj->level = UMIN(obj->level, LEVEL_AVATAR);
obj->cost = 0;
xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
obj_to_room(obj, pRoomIndex);
xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
obj->reset = pReset;
pReset->obj = obj;
}
else
{
int x;
if(!(obj = get_obj_room(pObjIndex, pRoomIndex)))
{
obj = NULL;
lastobj = NULL;
break;
}
obj->extra_flags = pObjIndex->extra_flags;
for(x = 0; x < 6; ++x)
obj->value[x] = pObjIndex->value[x];
}
}
if(!obj)
{
bug("%s: object is NULL.", __FUNCTION__);
continue;
}
for(n = 0; n < MAX_NEST; n++)
nestmap[n] = NULL;
nestmap[0] = obj;
lastobj = nestmap[0];
lastnest = 0;
if(pReset->first_reset)
{
for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
{
int iNest;
to_obj = lastobj;
switch (tReset->command)
{
case 'H':
if(!lastobj)
break;
xSET_BIT(lastobj->extra_flags, ITEM_HIDDEN);
break;
case 'T':
if(!IS_SET(tReset->extra, TRAP_OBJ))
{
bug("%s: Room reset found on object reset list", __FUNCTION__);
break;
}
else
{
/*
* We need to preserve obj for future 'T' checks
*/
OBJ_DATA *pobj;
if(tReset->arg3 > 0)
{
if(!(pObjToIndex = get_obj_index(tReset->arg3)))
{
bug("%s: %s: 'T': bad objto vnum %d.", __FUNCTION__, filename, tReset->arg3);
continue;
}
if(room->area->nplayer > 0 || !(to_obj = get_obj_type(pObjToIndex)) || (to_obj->carried_by && !IS_NPC(to_obj->carried_by)) || is_trapped(to_obj))
break;
}
else
{
if(!lastobj || !obj)
break;
to_obj = obj;
}
pobj = make_trap(tReset->arg2, tReset->arg1, number_fuzzy(to_obj->level), tReset->extra);
xSET_BIT(pobj->extra_flags, ITEM_NOGROUP);
obj_to_obj(pobj, to_obj);
xREMOVE_BIT(pobj->extra_flags, ITEM_NOGROUP);
}
break;
case 'P':
if(!(pObjIndex = get_obj_index(tReset->arg1)))
{
bug("%s: %s: 'P': bad obj vnum %d.", __FUNCTION__, filename, tReset->arg1);
continue;
}
iNest = tReset->extra;
if(!(pObjToIndex = get_obj_index(tReset->arg3)))
{
bug("%s: %s: 'P': bad objto vnum %d.", __FUNCTION__, filename, tReset->arg3);
continue;
}
if(iNest >= MAX_NEST)
{
bug("%s: %s: 'P': Exceeded nesting limit of %d. Room %d.", __FUNCTION__, filename, MAX_NEST, room->vnum);
obj = NULL;
break;
}
if(count_obj_list(pObjIndex, to_obj->first_content) > 0)
{
obj = NULL;
continue;
}
if(tReset->obj)
obj = tReset->obj;
else
{
if(iNest < lastnest)
to_obj = nestmap[iNest];
else if(iNest == lastnest)
to_obj = nestmap[lastnest];
else
to_obj = lastobj;
obj = create_object(pObjIndex, number_fuzzy(UMAX(generate_itemlevel(room->area, pObjIndex), to_obj->level)));
if(num > 1)
pObjIndex->count += (num - 1);
xSET_BIT(obj->extra_flags, ITEM_NOGROUP);
obj_to_obj(obj, to_obj);
xREMOVE_BIT(obj->extra_flags, ITEM_NOGROUP);
if(iNest > lastnest)
{
nestmap[iNest] = to_obj;
lastnest = iNest;
}
}
if(!obj)
{
bug("%s: object is NULL.", __FUNCTION__);
continue;
}
obj->count = tReset->arg2;
obj->level = UMIN(obj->level, LEVEL_AVATAR);
obj->count = tReset->arg2;
obj->reset = tReset;
tReset->obj = obj;
lastobj = obj;
/*
* Hackish fix for nested puts
*/
if(tReset->arg3 == OBJ_VNUM_MONEY_ONE)
tReset->arg3 = to_obj->pIndexData->vnum;
break;
}
}
}
break;
case 'T':
if(IS_SET(pReset->extra, TRAP_OBJ))
{
bug("%s: Object trap found in room %d reset list", __FUNCTION__, room->vnum);
break;
}
else
{
if(!(pRoomIndex = get_room_index(pReset->arg3)))
{
bug("%s: %s: 'T': bad room %d.", __FUNCTION__, filename, pReset->arg3);
continue;
}
if(room->area->nplayer > 0 || count_obj_list(get_obj_index(OBJ_VNUM_TRAP), pRoomIndex->first_content) > 0)
break;
to_obj = make_trap(pReset->arg1, pReset->arg1, 10, pReset->extra);
xSET_BIT(to_obj->extra_flags, ITEM_NOGROUP);
obj_to_room(to_obj, pRoomIndex);
xREMOVE_BIT(to_obj->extra_flags, ITEM_NOGROUP);
}
break;
case 'D':
if(!(pRoomIndex = get_room_index(pReset->arg1)))
{
bug("%s: %s: 'D': bad room vnum %d.", __FUNCTION__, filename, pReset->arg1);
continue;
}
if(!(pexit = get_exit(pRoomIndex, pReset->arg2)))
break;
switch (pReset->arg3)
{
case 0:
REMOVE_BIT(pexit->exit_info, EX_CLOSED);
REMOVE_BIT(pexit->exit_info, EX_LOCKED);
break;
case 1:
SET_BIT(pexit->exit_info, EX_CLOSED);
REMOVE_BIT(pexit->exit_info, EX_LOCKED);
if(IS_SET(pexit->exit_info, EX_xSEARCHABLE))
SET_BIT(pexit->exit_info, EX_SECRET);
break;
case 2:
SET_BIT(pexit->exit_info, EX_CLOSED);
SET_BIT(pexit->exit_info, EX_LOCKED);
if(IS_SET(pexit->exit_info, EX_xSEARCHABLE))
SET_BIT(pexit->exit_info, EX_SECRET);
break;
case 3:
SET_BIT(pexit->exit_info, EX_DIG);
break;
}
break;
case 'R':
if(!(pRoomIndex = get_room_index(pReset->arg1)))
{
bug("%s: %s: 'R': bad room vnum %d.", __FUNCTION__, filename, pReset->arg1);
continue;
}
randomize_exits(pRoomIndex, pReset->arg2);
break;
}
}
}
void reset_area(AREA_DATA *area)
{
ROOM_INDEX_DATA *room;
if(!area->first_room)
return;
for(room = area->first_room; room; room = room->next_aroom)
reset_room(room);
}
/* Setup put nesting levels, regardless of whether or not the resets will
actually reset, or if they're bugged. */
void renumber_put_resets(ROOM_INDEX_DATA *room)
{
RESET_DATA *pReset, *tReset, *lastobj = NULL;
for(pReset = room->first_reset; pReset; pReset = pReset->next)
{
switch (pReset->command)
{
default:
break;
case 'O':
lastobj = pReset;
for(tReset = pReset->first_reset; tReset; tReset = tReset->next_reset)
{
switch (tReset->command)
{
case 'P':
if(tReset->arg3 == 0)
{
if(!lastobj)
tReset->extra = 1000000;
else if(lastobj->command != 'P' || lastobj->arg3 > 0)
tReset->extra = 0;
else
tReset->extra = lastobj->extra + 1;
lastobj = tReset;
}
break;
}
}
break;
}
}
}
/*
* Add a reset to an area -Thoric
*/
RESET_DATA *add_reset(ROOM_INDEX_DATA *room, char letter, int extra, int arg1, int arg2, int arg3)
{
RESET_DATA *pReset;
if(!room)
{
bug("%s: NULL room!", __FUNCTION__);
return NULL;
}
letter = UPPER(letter);
pReset = make_reset(letter, extra, arg1, arg2, arg3);
switch (letter)
{
case 'M':
room->last_mob_reset = pReset;
break;
case 'E':
case 'G':
if(!room->last_mob_reset)
{
bug("%s: Can't add '%c' reset to room: last_mob_reset is NULL.", __FUNCTION__, letter);
return NULL;
}
room->last_obj_reset = pReset;
LINK(pReset, room->last_mob_reset->first_reset, room->last_mob_reset->last_reset, next_reset, prev_reset);
return pReset;
case 'P':
if(!room->last_obj_reset)
{
bug("%s: Can't add '%c' reset to room: last_obj_reset is NULL.", __FUNCTION__, letter);
return NULL;
}
LINK(pReset, room->last_obj_reset->first_reset, room->last_obj_reset->last_reset, next_reset, prev_reset);
return pReset;
case 'O':
room->last_obj_reset = pReset;
break;
case 'T':
if(IS_SET(extra, TRAP_OBJ))
{
pReset->prev_reset = NULL;
pReset->next_reset = room->last_obj_reset->first_reset;
if(room->last_obj_reset->first_reset)
room->last_obj_reset->first_reset->prev_reset = pReset;
room->last_obj_reset->first_reset = pReset;
if(!room->last_obj_reset->last_reset)
room->last_obj_reset->last_reset = pReset;
return pReset;
}
break;
case 'H':
pReset->prev_reset = NULL;
pReset->next_reset = room->last_obj_reset->first_reset;
if(room->last_obj_reset->first_reset)
room->last_obj_reset->first_reset->prev_reset = pReset;
room->last_obj_reset->first_reset = pReset;
if(!room->last_obj_reset->last_reset)
room->last_obj_reset->last_reset = pReset;
return pReset;
}
LINK(pReset, room->first_reset, room->last_reset, next, prev);
return pReset;
}
RESET_DATA *find_oreset(ROOM_INDEX_DATA *room, char *oname)
{
RESET_DATA *pReset;
OBJ_INDEX_DATA *pobj;
char arg[MAX_INPUT_LENGTH];
int cnt = 0, num = number_argument(oname, arg);
for(pReset = room->first_reset; pReset; pReset = pReset->next)
{
/*
* Only going to allow traps/hides on room reset objects. Unless someone can come up with a better way to do this.
*/
if(pReset->command != 'O')
continue;
if(!(pobj = get_obj_index(pReset->arg1)))
continue;
if(is_name(arg, pobj->name) && ++cnt == num)
return pReset;
}
return NULL;
}
void do_reset(CHAR_DATA *ch, char *argument)
{
char arg[MAX_INPUT_LENGTH];
if(!argument || argument[0] == '\0')
{
send_to_char("Usage: reset area\r\n", ch);
send_to_char("Usage: reset room\r\n", ch);
send_to_char("Usage: reset rlist ( Room resets )\r\n", ch);
send_to_char("Usage: reset list ( Area resets )\r\n", ch);
send_to_char("Usage: reset random <direction>\r\n", ch);
send_to_char("Usage: reset delete <number>\r\n", ch);
send_to_char("Usage: reset hide <objname>\r\n", ch);
send_to_char("Usage: reset trap room <type> <charges> [flags]\r\n", ch);
send_to_char("Usage: reset trap obj <name> <type> <charges> [flags]\r\n", ch);
return;
}
argument = one_argument(argument, arg);
if(!str_cmp(arg, "area"))
{
reset_area(ch->in_room->area);
send_to_char("Area has been reset.\r\n", ch);
return;
}
if(!str_cmp(arg, "room"))
{
reset_room(ch->in_room);
send_to_char("Room has been reset.\r\n", ch);
return;
}
if(!str_cmp(arg, "rlist"))
{
RESET_DATA *pReset;
char *rbuf;
short num;
ROOM_INDEX_DATA *room;
bool found = FALSE;
room = ch->in_room;
num = 0;
if(room->first_reset)
{
for(pReset = room->first_reset; pReset; pReset = pReset->next)
{
found = TRUE;
if(++num == 1)
ch_printf(ch, "Room:[%d]\r\n", room->vnum);
if(!(rbuf = sprint_reset(pReset, &num)))
continue;
send_to_char(rbuf, ch);
}
}
if(!found)
send_to_char("The room you're in has no resets.\r\n", ch);
return;
}
if(!str_cmp(arg, "list"))
{
RESET_DATA *pReset;
char *rbuf;
short num;
ROOM_INDEX_DATA *room;
bool found = FALSE;
for(room = ch->in_room->area->first_room; room; room = room->next_aroom)
{
num = 0;
if(!room->first_reset)
continue;
for(pReset = room->first_reset; pReset; pReset = pReset->next)
{
num++;
found = TRUE;
if(num == 1)
ch_printf(ch, "Room:[%d]\r\n", room->vnum);
if(!(rbuf = sprint_reset(pReset, &num)))
continue;
send_to_char(rbuf, ch);
}
}
if(!found)
send_to_char("The area you're in has no resets.\r\n", ch);
return;
}
/*
* Yeah, I know, this function is mucho ugly... but...
*/
if(!str_cmp(arg, "delete"))
{
RESET_DATA *pReset, *tReset, *pReset_next, *tReset_next, *gReset, *gReset_next;
int num, nfind = 0;
if(!argument || argument[0] == '\0')
{
send_to_char("You must specify a reset # in this room to delete one.\r\n", ch);
return;
}
if(!is_number(argument))
{
send_to_char("Specified reset must be designated by number. See &Wredit rlist&D.\r\n", ch);
return;
}
num = atoi(argument);
for(pReset = ch->in_room->first_reset; pReset; pReset = pReset_next)
{
pReset_next = pReset->next;
nfind++;
if(nfind == num)
{
UNLINK(pReset, ch->in_room->first_reset, ch->in_room->last_reset, next, prev);
delete_reset(pReset);
send_to_char("Reset deleted.\r\n", ch);
return;
}
for(tReset = pReset->first_reset; tReset; tReset = tReset_next)
{
tReset_next = tReset->next_reset;
nfind++;
if(nfind == num)
{
UNLINK(tReset, pReset->first_reset, pReset->last_reset, next_reset, prev_reset);
delete_reset(tReset);
send_to_char("Reset deleted.\r\n", ch);
return;
}
for(gReset = tReset->first_reset; gReset; gReset = gReset_next)
{
gReset_next = gReset->next_reset;
nfind++;
if(nfind == num)
{
UNLINK(gReset, tReset->first_reset, tReset->last_reset, next_reset, prev_reset);
delete_reset(gReset);
send_to_char("Reset deleted.\r\n", ch);
return;
}
}
}
}
send_to_char("No reset matching that number was found in this room.\r\n", ch);
return;
}
if(!str_cmp(arg, "random"))
{
RESET_DATA *pReset;
int vnum;
argument = one_argument(argument, arg);
vnum = get_dir(arg);
if(vnum < 0 || vnum > 9)
{
send_to_char("Reset which random doors?\r\n", ch);
return;
}
if(vnum == 0)
{
send_to_char("There is no point in randomizing one door.\r\n", ch);
return;
}
pReset = make_reset('R', 0, ch->in_room->vnum, vnum, 0);
pReset->prev = NULL;
pReset->next = ch->in_room->first_reset;
if(ch->in_room->first_reset)
ch->in_room->first_reset->prev = pReset;
ch->in_room->first_reset = pReset;
if(!ch->in_room->last_reset)
ch->in_room->last_reset = pReset;
send_to_char("Reset random doors created.\r\n", ch);
return;
}
if(!str_cmp(arg, "trap"))
{
RESET_DATA *pReset = NULL;
RESET_DATA *tReset = NULL;
char oname[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
int num, chrg, value, extra = 0, vnum;
argument = one_argument(argument, arg2);
if(!str_cmp(arg2, "room"))
{
vnum = ch->in_room->vnum;
extra = TRAP_ROOM;
argument = one_argument(argument, arg);
num = is_number(arg) ? atoi(arg) : -1;
argument = one_argument(argument, arg);
chrg = is_number(arg) ? atoi(arg) : -1;
}
else if(!str_cmp(arg2, "obj"))
{
argument = one_argument(argument, oname);
if(!(pReset = find_oreset(ch->in_room, oname)))
{
send_to_char("No matching reset found to set a trap on.\r\n", ch);
return;
}
vnum = 0;
extra = TRAP_OBJ;
argument = one_argument(argument, arg);
num = is_number(arg) ? atoi(arg) : -1;
argument = one_argument(argument, arg);
chrg = is_number(arg) ? atoi(arg) : -1;
}
else
{
send_to_char("Trap reset must be on 'room' or 'obj'\r\n", ch);
return;
}
if(num < 1 || num > MAX_TRAPTYPE)
{
send_to_char("Invalid trap type.\r\n", ch);
return;
}
if(chrg < 0 || chrg > 10000)
{
send_to_char("Invalid trap charges. Must be between 1 and 10000.\r\n", ch);
return;
}
while(*argument)
{
argument = one_argument(argument, arg);
value = get_trapflag(arg);
if(value < 0 || value > 31)
{
ch_printf(ch, "Bad trap flag: %s\r\n", arg);
continue;
}
SET_BIT(extra, 1 << value);
}
tReset = make_reset('T', extra, num, chrg, vnum);
if(pReset)
{
tReset->prev_reset = NULL;
tReset->next_reset = pReset->first_reset;
if(pReset->first_reset)
pReset->first_reset->prev_reset = tReset;
pReset->first_reset = tReset;
if(!pReset->last_reset)
pReset->last_reset = tReset;
}
else
{
tReset->prev = NULL;
tReset->next = ch->in_room->first_reset;
if(ch->in_room->first_reset)
ch->in_room->first_reset->prev = tReset;
ch->in_room->first_reset = tReset;
if(!ch->in_room->last_reset)
ch->in_room->last_reset = tReset;
}
send_to_char("Trap created.\r\n", ch);
return;
}
if(!str_cmp(arg, "hide"))
{
RESET_DATA *pReset = NULL;
RESET_DATA *tReset = NULL;
if(!(pReset = find_oreset(ch->in_room, argument)))
{
send_to_char("No such object to hide in this room.\r\n", ch);
return;
}
tReset = make_reset('H', 1, 0, 0, 0);
if(pReset)
{
tReset->prev_reset = NULL;
tReset->next_reset = pReset->first_reset;
if(pReset->first_reset)
pReset->first_reset->prev_reset = tReset;
pReset->first_reset = tReset;
if(!pReset->last_reset)
pReset->last_reset = tReset;
}
else
{
tReset->prev = NULL;
tReset->next = ch->in_room->first_reset;
if(ch->in_room->first_reset)
ch->in_room->first_reset->prev = tReset;
ch->in_room->first_reset = tReset;
if(!ch->in_room->last_reset)
ch->in_room->last_reset = tReset;
}
send_to_char("Hide reset created.\r\n", ch);
return;
}
do_reset(ch, (char *)"");
return;
}