/***************************************************************************** * DikuMUD (C) 1990, 1991 by: * * Sebastian Hammer, Michael Seifert, Hans Henrik Staefeldt, Tom Madsen, * * and Katja Nyboe. * *---------------------------------------------------------------------------* * MERC 2.1 (C) 1992, 1993 by: * * Michael Chastain, Michael Quan, and Mitchell Tse. * *---------------------------------------------------------------------------* * SMAUG 1.4 (C) 1994, 1995, 1996, 1998 by: Derek Snider. * * Team: Thoric, Altrag, Blodkai, Narn, Haus, Scryn, Rennard, Swordbearer, * * gorog, Grishnakh, Nivek, Tricops, and Fireblade. * *---------------------------------------------------------------------------* * SMAUG 1.7 FUSS by: Samson and others of the SMAUG community. * * Their contributions are greatly appreciated. * *---------------------------------------------------------------------------* * LoP (C) 2006, 2007, 2008 by: the LoP team. * *---------------------------------------------------------------------------* * Game Reset Handler and Editing Module * * Smaug FUSS 1.6 Version * *****************************************************************************/ #include <stdio.h> #include <string.h> #include "h/mud.h" /* Externals */ extern int top_reset; void handle_mwmobilereset( ROOM_INDEX_DATA *room ); extern bool fBootDb; int get_trapflag( char *flag ); /* * 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[MSL]; char mobname[MSL], roomname[MSL], objname[MSL]; static ROOM_INDEX_DATA *room; static OBJ_INDEX_DATA *obj, *obj2; static MOB_INDEX_DATA *mob; switch( pReset->command ) { default: snprintf( buf, sizeof( buf ), "%2d) *** BAD RESET: %c %d %d %d %d %d***\r\n", *num, pReset->command, pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, pReset->rchance ); break; case 'M': mob = get_mob_index( pReset->arg1 ); room = get_room_index( pReset->arg3 ); if( mob ) strncpy( mobname, mob->name, sizeof( mobname ) ); else strncpy( mobname, "Mobile: *BAD VNUM*", sizeof( mobname ) ); if( room ) strncpy( roomname, room->name, sizeof( roomname ) ); else strncpy( roomname, "Room: *BAD VNUM*", sizeof( roomname ) ); snprintf( buf, sizeof( buf ), "%2d) %s (%d) -> %s Room: %d [%d] (%d)\r\n", *num, mobname, pReset->arg1, roomname, pReset->arg3, pReset->arg2, pReset->rchance ); for( tReset = pReset->first_reset; tReset; tReset = tReset->next_reset ) { ( *num )++; switch( tReset->command ) { case 'E': if( !mob ) strncpy( mobname, "* ERROR: NO MOBILE! *", sizeof( mobname ) ); if( !( obj = get_obj_index( tReset->arg1 ) ) ) strncpy( objname, "Object: *BAD VNUM*", sizeof( objname ) ); else strncpy( objname, obj->name, sizeof( objname ) ); snprintf( buf + strlen( buf ), sizeof( buf ) - strlen( buf ), "%2d) (equip) %s (%d) -> %s (%s) [%d] (%d)\r\n", *num, objname, tReset->arg1, mobname, wear_locs[tReset->arg3], tReset->arg2, tReset->rchance ); break; case 'G': if( !mob ) strncpy( mobname, "* ERROR: NO MOBILE! *", sizeof( mobname ) ); if( !( obj = get_obj_index( tReset->arg1 ) ) ) strncpy( objname, "Object: *BAD VNUM*", sizeof( objname ) ); else strncpy( objname, obj->name, sizeof( objname ) ); snprintf( buf + strlen( buf ), sizeof( buf ) - strlen( buf ), "%2d) (carry) %s (%d) -> %s [%d] (%d)\r\n", *num, objname, tReset->arg1, mobname, tReset->arg2, tReset->rchance ); 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*", sizeof( objname ) ); else strncpy( objname, obj2->name, sizeof( objname ) ); if( gReset->arg3 > 0 && !( obj = get_obj_index( gReset->arg3 ) ) ) strncpy( roomname, "Object2: *BAD VNUM*", sizeof( roomname ) ); else if( !obj ) strncpy( roomname, "Object2: *NULL obj*", sizeof( roomname ) ); else strncpy( roomname, obj->name, sizeof( roomname ) ); snprintf( buf + strlen( buf ), sizeof( buf ) - strlen( buf ), "%2d) (put) %s (%d) -> %s (%d) [%d] (%d)\r\n", *num, objname, gReset->arg1, roomname, obj ? obj->vnum : gReset->arg3, gReset->arg2, gReset->rchance ); break; } } } } break; case 'O': if( !( obj = get_obj_index( pReset->arg1 ) ) ) strncpy( objname, "Object: *BAD VNUM*", sizeof( objname ) ); else strncpy( objname, obj->name, sizeof( objname ) ); room = get_room_index( pReset->arg3 ); if( !room ) strncpy( roomname, "Room: *BAD VNUM*", sizeof( roomname ) ); else strncpy( roomname, room->name, sizeof( roomname ) ); snprintf( buf, sizeof( buf ), "%2d) (object) %s (%d) -> %s Room: %d [%d] (%d)\r\n", *num, objname, pReset->arg1, roomname, pReset->arg3, pReset->arg2, pReset->rchance ); 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*", sizeof( objname ) ); else strncpy( objname, obj2->name, sizeof( objname ) ); if( tReset->arg3 > 0 && !( obj = get_obj_index( tReset->arg3 ) ) ) strncpy( roomname, "Object2: *BAD VNUM*", sizeof( roomname ) ); else if( !obj ) strncpy( roomname, "Object2: *NULL obj*", sizeof( roomname ) ); else strncpy( roomname, obj->name, sizeof( roomname ) ); snprintf( buf + strlen( buf ), sizeof( buf ) - strlen( buf ), "%2d) (put) %s (%d) -> %s (%d) [%d] (%d)\r\n", *num, objname, tReset->arg1, roomname, obj ? obj->vnum : tReset->arg3, tReset->arg2, tReset->rchance ); break; case 'T': snprintf( buf + strlen( buf ), sizeof( buf ) - strlen( buf ), "%2d) (trap) %d %d %d %d (%s) -> %s (%d) (%d)\r\n", *num, tReset->extra, tReset->arg1, tReset->arg2, tReset->arg3, flag_string( tReset->extra, trap_flags ), objname, obj ? obj->vnum : 0, tReset->rchance ); break; case 'H': snprintf( buf + strlen( buf ), sizeof( buf ) - strlen( buf ), "%2d) (hide) -> %s (%d)\r\n", *num, objname, tReset->rchance ); 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*", sizeof( roomname ) ); snprintf( objname, sizeof( objname ), "%s (no exit)", dir_name[pReset->arg2] ); } else { strncpy( roomname, room->name, sizeof( roomname ) ); snprintf( objname, sizeof( objname ), "%s%s", dir_name[pReset->arg2], get_exit( room, pReset->arg2 ) ? "" : " (NO EXIT!)" ); } switch( pReset->arg3 ) { default: strncpy( mobname, "(* ERROR *)", sizeof( mobname ) ); break; case 0: strncpy( mobname, "Open", sizeof( mobname ) ); break; case 1: strncpy( mobname, "Close", sizeof( mobname ) ); break; case 2: strncpy( mobname, "Close and lock", sizeof( mobname ) ); break; } snprintf( buf, sizeof( buf ), "%2d) %s [%d] the %s [%d] door %s (%d) (%d)\r\n", *num, mobname, pReset->arg3, objname, pReset->arg2, roomname, pReset->arg1, pReset->rchance ); break; case 'R': if( !( room = get_room_index( pReset->arg1 ) ) ) strncpy( roomname, "Room: *BAD VNUM*", sizeof( roomname ) ); else strncpy( roomname, room->name, sizeof( roomname ) ); snprintf( buf, sizeof( buf ), "%2d) Randomize exits 0 to %d -> %s (%d) (%d)\r\n", *num, pReset->arg2, roomname, pReset->arg1, pReset->rchance ); break; case 'T': if( !( room = get_room_index( pReset->arg3 ) ) ) strncpy( roomname, "Room: *BAD VNUM*", sizeof( roomname ) ); else strncpy( roomname, room->name, sizeof( roomname ) ); snprintf( buf, sizeof( buf ), "%2d) Trap: %d %d %d %d (%s) -> %s (%d) (%d)\r\n", *num, pReset->extra, pReset->arg1, pReset->arg2, pReset->arg3, flag_string( pReset->extra, trap_flags ), roomname, room ? room->vnum : 0, pReset->rchance ); 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, short rchance ) { RESET_DATA *pReset; CREATE( pReset, RESET_DATA, 1 ); pReset->command = letter; pReset->extra = extra; pReset->arg1 = arg1; pReset->arg2 = arg2; pReset->arg3 = arg3; pReset->rchance = rchance; top_reset++; return pReset; } void add_obj_reset( ROOM_INDEX_DATA *room, char cm, OBJ_DATA *obj, int v2, int v3, short rchance ) { OBJ_DATA *inobj; static int iNest; if( ( cm == 'O' || cm == 'P' ) && obj->pIndexData->vnum == OBJ_VNUM_TRAP ) { if( cm == 'O' ) add_reset( room, 'T', obj->value[3], obj->value[1], obj->value[0], v3, 100 ); return; } add_reset( room, cm, ( cm == 'P' ? iNest : 0 ), obj->pIndexData->vnum, v2, v3, 100 ); if( cm == 'O' && is_obj_stat( obj, ITEM_HIDDEN ) && can_wear( obj, ITEM_NO_TAKE ) ) add_reset( room, 'H', 1, 0, 0, 0, 100 ); 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, 100 ); } 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, 100 ); if( cm == 'P' ) iNest--; } 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 ); } pReset->first_reset = pReset->last_reset = NULL; DISPOSE( pReset ); } void instaroom( ROOM_INDEX_DATA *pRoom, bool dodoors ) { CHAR_DATA *rch; OBJ_DATA *obj; RESET_DATA *uReset; for( rch = pRoom->first_person; rch; rch = rch->next_in_room ) { if( !is_npc( rch ) ) continue; uReset = add_reset( pRoom, 'M', 1, rch->pIndexData->vnum, 1, pRoom->vnum, 100 ); uReset->doreset = false; rch->resetvnum = pRoom->vnum; for( obj = rch->first_carrying; obj; obj = obj->next_content ) { if( obj->wear_loc == WEAR_NONE ) add_obj_reset( pRoom, 'G', obj, 1, 0, 100 ); else add_obj_reset( pRoom, 'E', obj, 1, obj->wear_loc, 100 ); } } for( obj = pRoom->first_content; obj; obj = obj->next_content ) add_obj_reset( pRoom, 'O', obj, obj->count, pRoom->vnum, 100 ); if( dodoors ) { EXIT_DATA *pexit; for( pexit = pRoom->first_exit; pexit; pexit = pexit->next ) { int state = 0; if( !xIS_SET( pexit->exit_info, EX_ISDOOR ) ) continue; if( xIS_SET( pexit->exit_info, EX_CLOSED ) ) { if( xIS_SET( pexit->exit_info, EX_LOCKED ) ) state = 2; else state = 1; } add_reset( pRoom, 'D', 0, pRoom->vnum, pexit->vdir, state, 100 ); } } } 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; } 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 ); } } /* Function modified from original form - Samson */ CMDF( do_instaroom ) { bool dodoors; if( is_npc( ch ) || get_trust( ch ) < PERM_BUILDER || !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 ) < PERM_HEAD ) { send_to_char( "You can't 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 */ CMDF( do_instazone ) { AREA_DATA *pArea; ROOM_INDEX_DATA *pRoom; bool dodoors; if( is_npc( ch ) || get_trust( ch ) < PERM_BUILDER || !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 ); } /* 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 = NULL; OBJ_DATA *obj = NULL, *lastobj = NULL, *to_obj; ROOM_INDEX_DATA *pRoomIndex = NULL; MOB_INDEX_DATA *pMobIndex = NULL; OBJ_INDEX_DATA *pObjIndex = NULL, *pObjToIndex; EXIT_DATA *pexit; char *filename = room->area->filename; int level = 0, n, num = 0, lastnest, resetnum = 0; if( !fBootDb ) handle_mwmobilereset( room ); if( !room->first_reset ) return; level = 0; for( pReset = room->first_reset; pReset; pReset = pReset->next ) { resetnum++; if( pReset->rchance < number_percent( ) ) continue; 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->doreset ) { mob = NULL; continue; } if( !( mob = create_mobile( pMobIndex ) ) ) { bug( "%s: failed to create_mobile for mob vnum %d.", __FUNCTION__, pMobIndex->vnum ); continue; } /* See if this is a pet room */ { ROOM_INDEX_DATA *pRoomPrev = get_room_index( pRoomIndex->vnum - 1 ); if( pRoomPrev && xIS_SET( pRoomPrev->room_flags, ROOM_PET_SHOP ) ) xSET_BIT( mob->act, ACT_PET ); } mob->resetvnum = room->vnum; mob->resetnum = resetnum; pReset->doreset = false; if( room_is_dark( pRoomIndex ) ) xSET_BIT( mob->affected_by, AFF_INFRARED ); char_to_room( mob, pRoomIndex ); if( pReset->first_reset ) { for( tReset = pReset->first_reset; tReset; tReset = tReset->next_reset ) { resetnum++; if( tReset->rchance < number_percent( ) ) continue; switch( tReset->command ) { case 'G': case 'E': if( !mob ) { lastobj = NULL; break; } if( !( pObjIndex = get_obj_index( tReset->arg1 ) ) ) { bug( "%s: %s: 'E' or 'G': bad obj vnum %d.", __FUNCTION__, filename, tReset->arg1 ); continue; } if( mob->pIndexData->pShop ) { obj = create_object( pObjIndex, pObjIndex->level ); xSET_BIT( obj->extra_flags, ITEM_INVENTORY ); } else obj = create_object( pObjIndex, pObjIndex->level ); if( !obj ) { bug( "%s: failed to create_object for obj vnum %d", __FUNCTION__, pObjIndex->vnum ); continue; } obj->level = URANGE( 0, obj->level, MAX_LEVEL ); obj = obj_to_char( obj, mob ); 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 ); break; } equip_char( mob, obj, tReset->arg3 ); } 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; resetnum++; if( gReset->rchance < number_percent( ) ) continue; 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; break; } if( iNest < lastnest ) to_obj = nestmap[iNest]; else if( iNest == lastnest ) to_obj = nestmap[lastnest]; else to_obj = lastobj; if( !( obj = create_object( pObjIndex, pObjIndex->level ) ) ) { bug( "%s: failed to create_object for obj vnum %d", __FUNCTION__, pObjIndex->vnum ); continue; } if( num > 1 ) pObjIndex->count += ( num - 1 ); obj->count = gReset->arg2; obj->level = UMIN( obj->level, MAX_LEVEL ); obj->count = gReset->arg2; obj_to_obj( obj, to_obj ); if( iNest > lastnest ) { nestmap[iNest] = to_obj; lastnest = iNest; } 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( count_obj_list( pObjIndex, pRoomIndex->first_content ) < 1 ) { if( !( obj = create_object( pObjIndex, pObjIndex->level ) ) ) { bug( "%s: failed to create_object for obj vnum %d", __FUNCTION__, pObjIndex->vnum ); continue; } if( num > 1 ) pObjIndex->count += ( num - 1 ); obj->count = pReset->arg2; obj->level = UMIN( obj->level, MAX_LEVEL ); obj->cost = 0; obj_to_room( obj, pRoomIndex ); } 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]; } 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; resetnum++; to_obj = lastobj; if( tReset->rchance < number_percent( ) ) continue; 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, to_obj->level, tReset->extra ); obj_to_obj( pobj, to_obj ); } 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; break; } if( iNest < lastnest ) to_obj = nestmap[iNest]; else if( iNest == lastnest ) to_obj = nestmap[lastnest]; else to_obj = lastobj; obj = create_object( pObjIndex, pObjIndex->level ); if( num > 1 ) pObjIndex->count += ( num - 1 ); obj->count = tReset->arg2; obj->level = UMIN( obj->level, MAX_LEVEL ); obj->count = tReset->arg2; obj_to_obj( obj, to_obj ); if( iNest > lastnest ) { nestmap[iNest] = to_obj; lastnest = iNest; } 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 ); obj_to_room( to_obj, pRoomIndex ); } 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: xREMOVE_BIT( pexit->exit_info, EX_CLOSED ); xREMOVE_BIT( pexit->exit_info, EX_LOCKED ); break; case 1: xSET_BIT( pexit->exit_info, EX_CLOSED ); xREMOVE_BIT( pexit->exit_info, EX_LOCKED ); if( xIS_SET( pexit->exit_info, EX_xSEARCHABLE ) ) xSET_BIT( pexit->exit_info, EX_SECRET ); break; case 2: xSET_BIT( pexit->exit_info, EX_CLOSED ); xSET_BIT( pexit->exit_info, EX_LOCKED ); if( xIS_SET( pexit->exit_info, EX_xSEARCHABLE ) ) xSET_BIT( pexit->exit_info, EX_SECRET ); 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 - 1 ); 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, short rchance ) { RESET_DATA *pReset; if( !room ) { bug( "%s: NULL room!", __FUNCTION__ ); return NULL; } letter = UPPER( letter ); pReset = make_reset( letter, extra, arg1, arg2, arg3, rchance ); switch( letter ) { case 'M': pReset->doreset = true; 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; } pReset->doreset = true; 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; } pReset->doreset = true; LINK( pReset, room->last_obj_reset->first_reset, room->last_obj_reset->last_reset, next_reset, prev_reset ); return pReset; case 'O': pReset->doreset = true; room->last_obj_reset = pReset; break; case 'T': if( IS_SET( extra, TRAP_OBJ ) ) { pReset->doreset = true; 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->doreset = true; 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[MIL]; 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; } CMDF( do_reset ) { char arg[MIL]; if( !argument || argument[0] == '\0' ) { send_to_char( "Usage: reset area/list\r\n", ch ); send_to_char( "Usage: reset randomize <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 rchance <number> <chance>\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, "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 ) { 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 your 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; 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; 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; 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, "rchance" ) ) { RESET_DATA *pReset, *tReset, *pReset_next, *tReset_next, *gReset, *gReset_next; int num, nfind = 0, rchance = 0; char numarg[MIL]; if( !argument || argument[0] == '\0' ) { send_to_char( "You must specify a reset # in this room to change.\r\n", ch ); return; } argument = one_argument( argument, numarg ); if( !is_number( numarg ) ) { send_to_char( "Specified reset must be designated by number. See &Wredit rlist&D.\r\n", ch ); return; } num = atoi( numarg ); rchance = atoi( argument ); if( rchance <= 0 || rchance > 100 ) { send_to_char( "Reset Chance range is 1-100.\r\n", ch ); return; } for( pReset = ch->in_room->first_reset; pReset; pReset = pReset_next ) { pReset_next = pReset->next; if( ++nfind == num ) { pReset->rchance = rchance; send_to_char( "Reset chance changed.\r\n", ch ); return; } for( tReset = pReset->first_reset; tReset; tReset = tReset_next ) { tReset_next = tReset->next_reset; if( ++nfind == num ) { tReset->rchance = rchance; send_to_char( "Reset chance changed.\r\n", ch ); return; } for( gReset = tReset->first_reset; gReset; gReset = gReset_next ) { gReset_next = gReset->next_reset; if( ++nfind == num ) { gReset->rchance = rchance; send_to_char( "Reset chance changed.\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 = get_dir( arg ); argument = one_argument( argument, 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; } if( !get_room_index( vnum ) ) { send_to_char( "Target room does not exist.\r\n", ch ); return; } pReset = make_reset( 'R', 0, ch->in_room->vnum, vnum, 0, 100 ); 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[MIL], arg2[MIL]; 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 >= TRAP_TYPE_MAX ) { ch_printf( ch, "Invalid trap type (%d).\r\n", num ); 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_flag( arg, trap_flags, TRAP_MAX ); if( value < 0 || value >= TRAP_MAX ) { ch_printf( ch, "Bad trap flag: %s\r\n", arg ); continue; } SET_BIT( extra, 1 << value ); } tReset = make_reset( 'T', extra, num, chrg, vnum, 100 ); 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, 100 ); 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 *)"" ); } /* Update the mobile resets to let it know to reset it again */ void update_room_reset( CHAR_DATA *ch ) { ROOM_INDEX_DATA *room; RESET_DATA *pReset, *tReset, *pReset_next, *tReset_next, *gReset, *gReset_next; int nfind = 0; if( !ch ) return; if( !( room = get_room_index( ch->resetvnum ) ) ) return; for( pReset = room->first_reset; pReset; pReset = pReset_next ) { pReset_next = pReset->next; if( ++nfind == ch->resetnum ) { pReset->doreset = true; return; } for( tReset = pReset->first_reset; tReset; tReset = tReset_next ) { tReset_next = tReset->next_reset; if( ++nfind == ch->resetnum ) { tReset->doreset = true; return; } for( gReset = tReset->first_reset; gReset; gReset = gReset_next ) { gReset_next = gReset->next_reset; if( ++nfind == ch->resetnum ) { gReset->doreset = true; return; } } } } }