/* Instaroom code by Kyndig
* Allows resets to be placed on a room, according to current
* mob/obj/container/exit placement of that room.
* Syntax: instaroom
*
*
* Additional needed install instructions:
* Place the following 2 lines in => struct room_index_data{ in merc.h:
* RESET_DATA * last_mob_reset;
* RESET_DATA * last_obj_reset;
*
* Place the following line in => struct reset_data{ in merc.h
* RESET_DATA * prev;
*
* You can build an 'instant area reset maker' based off this code
* Developed by Kyndig from http://www.kyndig.com/ kyndig@kyndig.com
*/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
#include <unistd.h>
#include "merc.h"
#include "olc.h"
#include "recycle.h"
#include "const.h"
/* Locals */
void wipe_resets( ROOM_INDEX_DATA *pRoom );
void instaroom( ROOM_INDEX_DATA *pRoom );
/* NOTE: This does not create RANDOM room exits, my exit system was
* abit to much to port it to stock ROM so I simply removed. It will be up
* to you to edit these functions to return what you desire
*/
/* Original idea taken from the SMAUG server, the LINK macro is a direct
* reflection of the outstanding work of Thoric from realms.org
*/
/* double-linked list handling macros -Thoric */
#define LINK(link, first, last, next, prev) \
do \
{ \
if ( !(first) ) \
(first) = (link); \
else \
(last)->next = (link); \
(link)->next = NULL; \
(link)->prev = (last); \
(last) = (link); \
} while(0)
/* called from do_instaroom further below */
void reset_instaroom( CHAR_DATA *ch, char *argument )
{
ROOM_INDEX_DATA *pRoom;
CHAR_DATA *mob;
OBJ_DATA *obj, *inobj;
pRoom = ch->in_room;
/* Containers can NOT be closed when doing an 'instaroom'. Thus a builder will have to close
* the container after the reset is installed
*/
/* lets go through a mob first */
for ( mob = ch->in_room->people; mob; mob = mob->next_in_room )
{
if ( IS_NPC( mob ) )
{
/* only mobs with this areas vnums are allowed */
if ( mob->pIndexData->area != pRoom->area )
{
send_to_char( "There is a mob in this room that is not part of your area, resets not set.\n\r", ch );
return;
}
for ( obj = mob->carrying; obj; obj = obj->next_content )
{
if( obj->pIndexData->area != pRoom->area )
{
send_to_char( "There is an object in a MOB that is not part of your area, resets not set.\n\r", ch );
return;
}
if ( IS_SET( obj->value[1], CONT_CLOSED ) )
{
send_to_char( "There is a container in a MOB I can't see inside of. Get the container from the mob, open\n\r"
"it up, give it _back_ to your mob, then do an instaroom.\n\r"
"AFTER you have set the container to load into the mob,\n\r"
"you can then get the container from him again, close/lock it, and return it....In other words\n\r"
"A container must be open first, the reset installed, after that, you can close/lock it.\n\r",ch);
return;
}
if ( obj->contains )
{
for (inobj = obj->contains; inobj; inobj = obj->next_content )
{
if ( inobj->pIndexData->area != pRoom->area )
{
send_to_char("There is an object in a container which a MOB in this room has, which is not\n\r"
"a vnum for this area. RESETS NOT SET.\n\r",ch);
return;
}
}
}
}
}
}/* done looking at mobs and their eq/inv */
/* lets take a look at objects in the room and their contents */
for ( obj = pRoom->contents; obj != NULL; obj = obj->next_content )
{
if( obj->pIndexData->area != pRoom->area )
{
send_to_char( "There is an object in this room that is not a vnum of your area, resets not set.\n\r", ch );
return;
}
if ( IS_SET( obj->value[1], CONT_CLOSED ) )
{
send_to_char( "There is a container in this room I can't see inside of. Open it up first, do the\n\r"
"instaroom command, THEN you can close/lock the container.\n\r",ch);
return;
}
if ( obj->contains )
{
for (inobj = obj->contains; inobj; inobj = obj->next_content )
{
if ( inobj->pIndexData->area != pRoom->area )
{
send_to_char("There is an object in a container that does not a vnum in this area. No resets set.\n\r",ch);
return;
}
}
}
}
if ( pRoom->reset_first )
wipe_resets(pRoom);
instaroom( pRoom );
send_to_char( "Room resets installed.\n\r", ch );
return;
}
/* Separate function for recursive purposes */
void delete_reset( ROOM_INDEX_DATA *pRoom, RESET_DATA *pReset, int insert_loc, bool wipe_all)
{
if( !pRoom->reset_first )
{
return;
}
if ( insert_loc-1 <= 0 )
{
pReset = pRoom->reset_first;
pRoom->reset_first = pRoom->reset_first->next;
if ( !pRoom->reset_first )
pRoom->reset_last = NULL;
}
else
{
int iReset = 0;
RESET_DATA *prev = NULL;
for ( pReset = pRoom->reset_first;
pReset;
pReset = pReset->next )
{
if ( ++iReset == insert_loc )
break;
prev = pReset;
}
if ( !pReset )
{
return;
}
if ( prev )
prev->next = prev->next->next;
else
pRoom->reset_first = pRoom->reset_first->next;
for ( pRoom->reset_last = pRoom->reset_first;
pRoom->reset_last->next;
pRoom->reset_last = pRoom->reset_last->next );
}/*else*/
if ( pReset == pRoom->last_mob_reset )
pRoom->last_mob_reset = NULL;
if ( pReset == pRoom->last_obj_reset )
pRoom->last_obj_reset = NULL;
free_reset_data( pReset );
/* TRUE/FALSE call on delete_reset here, so we can delete all resets or just one */
if( wipe_all )
{
if( ( pReset = pRoom->reset_first) != '\0')
delete_reset( pRoom, pReset, 1, TRUE );
}
}
void wipe_resets( ROOM_INDEX_DATA *pRoom )
{
RESET_DATA *pReset;
int i = 1;
for ( pReset = pRoom->reset_first; pReset != NULL; )
{
if (pReset)
{
delete_reset(pRoom, pReset, i, TRUE);
}
i++;
pReset = pReset->next;
}
return;
}
/* make_reset called by add_new_reset in order to create a blank
* reset to load data into the reset_list
*/
RESET_DATA *make_reset( char letter, int arg1, int arg2, int arg3, int arg4 )
{
RESET_DATA *pReset;
pReset = new_reset_data();
pReset->command = letter;
pReset->arg1 = arg1;
pReset->arg2 = arg2;
pReset->arg3 = arg3;
pReset->arg4 = arg4;
return pReset;
}
/* add_new_reset called from several places below, it adds in the actual pReset
* arguments to the reset_list..tricky footwork here
*/
RESET_DATA *add_new_reset( ROOM_INDEX_DATA *pRoom, char letter, int arg1, int arg2, int arg3, int arg4 )
{
RESET_DATA *pReset;
if ( !pRoom )
{
bug( "add_reset: NULL area!", 0 );
return NULL;
}
letter = UPPER(letter);
pReset = make_reset( letter, arg1, arg2, arg3, arg4 );
switch( letter )
{
case 'M': pRoom->last_mob_reset = pReset; break;
case 'E': case 'G': case 'P':
case 'O': pRoom->last_obj_reset = pReset; break;
break;
}
/* LINK code from the SMAUG server */
LINK( pReset, pRoom->reset_first, pRoom->reset_last, next, prev );
return pReset;
}
/* Called from instaroom */
/* The below function debugged by Chalc on the Romlist, thanx again Chalc */
void add_obj_reset( ROOM_INDEX_DATA *pRoom, char cm, OBJ_DATA *obj, int v2, int v3, int v4 )
{
add_new_reset( pRoom, cm, obj->pIndexData->vnum, v2, v3, v4 );
if(obj->contains)
{
OBJ_INDEX_DATA **objList;
OBJ_DATA *inObj;
int *objCount;
int count;
int itemCount;
for(inObj = obj->contains, itemCount = 0; inObj; inObj = inObj->next_content) itemCount++;
/* Now have count objects in obj, allocate space for lists */
objList = (OBJ_INDEX_DATA **)alloc_mem(itemCount * sizeof(OBJ_INDEX_DATA *));
objCount = (int *)alloc_mem(itemCount * sizeof(int));
/* Initialize Memory */
memset(objList, 0, itemCount * sizeof(OBJ_INDEX_DATA *));
memset(objCount, 0, itemCount * sizeof(int));
/* Figure out how many of each obj is in the container */
for(inObj = obj->contains; inObj; inObj = inObj->next_content)
{
for(count = 0; objList[count] && objList[count] != inObj->pIndexData; count++);
if(!objList[count]) objList[count] = inObj->pIndexData;
objCount[count]++;
}
/* Create the resets */
for(count = 0; objList[count]; count++)
add_new_reset(pRoom, 'P', objList[count]->vnum, objCount[count], obj->pIndexData->vnum, objCount[count]);
/* Free the memory */
free_mem(objList, itemCount * sizeof(OBJ_INDEX_DATA *));
free_mem(objCount, itemCount * sizeof(int));
}
/* And Done */
return;
}
void instaroom( ROOM_INDEX_DATA *pRoom )
{
CHAR_DATA *rch;
OBJ_DATA *obj;
for ( rch = pRoom->people; rch; rch = rch->next_in_room )
{
if ( !IS_NPC(rch) )
continue;
add_new_reset( pRoom, 'M',rch->pIndexData->vnum, rch->pIndexData->count, pRoom->vnum, 3 );
for ( obj = rch->carrying; obj; obj = obj->next_content )
{
if ( obj->wear_loc == WEAR_NONE )
add_obj_reset( pRoom, 'G', obj, 1, 0, 3 );
else
add_obj_reset( pRoom, 'E', obj, 1, obj->wear_loc, 3 );
}
}
for ( obj = pRoom->contents; obj; obj = obj->next_content )
{
add_obj_reset( pRoom, 'O', obj, 1, pRoom->vnum, 1 );
}
return;
}
void do_instaroom( CHAR_DATA *ch, char *argument )
{
ROOM_INDEX_DATA *pRoom = ch->in_room;
char arg[MAX_INPUT_LENGTH];
argument = one_argument(argument, arg);
if(!strstr( ch->in_room->area->builders, ch->name ) )
{ send_to_char("You aren't the builder of this area!\n\r",ch);
return;
}
if(ch->pcdata->security < ch->in_room->area->security )
{
send_to_char("You don't have the security to edit this area.\n\r",ch);
return;
}
if ( pRoom->reset_first )
wipe_resets(pRoom);
instaroom( pRoom );
send_to_char( "Room resets installed.\n\r", ch );
}