From: Sardu <sardu@v-wave.com> /* This is forwarded from one of our coders on Aeon, it's a revision from his previous post to this list. He can be reached at feist@nortel.ca -- Sardu */ I have completed the set of OLC delete commands. There are also some bug fixes for mem.c all of which are related to for loops which have x->next as the increment condition but reassign x->next during the body of the loop thus causing an infinite loop. Compare your free_mob/room/obj_index functions to the new ones. All the functions now free up memory and use the OLC memory management scheme. All instances of whatever your deleting are extracted from the mud. In the case of a room this is includes any exits which lead to this room. There are also a few handy utility functions that some of you may find useful. Please note that none of these functions prevent you from deleting things which may be hardcoded into the src as #defines such as OBJ_VNUM_SCHOOL_DAGGER etc... Doing so would be too much hassle and I assume that the person using the functions knows the code well enough to realize these things. Installation instructions and code follow. Note, I haven't actually tested these instructions; if you have significant problems use the e-mail address at the bottom. Enjoy, Chris --------------------- CUT HERE ---------------------------------- Delete Commands for Ivan's OLC Usage and limitations: The following code is provided "as is". I make no claims to its suitability for a particular purpose. I am not responsible if your machine spontaneously explodes while using this code. Normally I frown on usage limitations however since this code took a significant amount of coding and debugging to write I would ask that if you use this you send a quick mail to feist@nortel.ca saying you are using it. This provision becomes void if this code ever makes it into the actual OLC dist. Hack away. :) To install the OLC delete commands into your mud follow the following steps. Please note that on Aeon (telnet://mud.aeon.org:4000) the ^ character is used for color. You may have to change some strings if your mud doesen't use ANSI color or uses another character for the control character. 1. In mem.c replace free_mob/obj/room_index with the following routines. (Or just compare the old and new versions. There are only minor changes.) void free_mob_index( MOB_INDEX_DATA *pMob ) { PROG_LIST *list, *mp_next; free_string( pMob->player_name ); free_string( pMob->short_descr ); free_string( pMob->long_descr ); free_string( pMob->description ); for( list = pMob->mprogs; list; list = mp_next ) { mp_next = list->next; free_mprog( pMob->mprogs ); } if( pMob->pShop ) { free_shop( pMob->pShop ); } pMob->next = mob_index_free; mob_index_free = pMob; return; } void free_obj_index( OBJ_INDEX_DATA *pObj ) { EXTRA_DESCR_DATA *pExtra, *wExtra; AFFECT_DATA *pAf, *wAf; free_string( pObj->name ); free_string( pObj->short_descr ); free_string( pObj->description ); for ( pAf = pObj->affected; pAf; pAf = wAf ) { wAf = pAf->next; free_affect( pAf ); } for ( pExtra = pObj->extra_descr; pExtra; pExtra = wExtra ) { wExtra = pExtra->next; free_extra_descr( pExtra ); } pObj->next = obj_index_free; obj_index_free = pObj; return; } void free_room_index( ROOM_INDEX_DATA *pRoom ) { int door; EXTRA_DESCR_DATA *pExtra, *wExtra; RESET_DATA *pReset, *wReset; free_string( pRoom->name ); free_string( pRoom->description ); free_string( pRoom->owner ); for ( door = 0; door < MAX_DIR; door++ ) { if ( pRoom->exit[door] ) { free_exit( pRoom->exit[door] ); pRoom->exit[door] = NULL; } } for ( pExtra = pRoom->extra_descr; pExtra; pExtra = wExtra ) { wExtra = pExtra->next; free_extra_descr( pExtra ); } for ( pReset = pRoom->reset_first; pReset; pReset = wReset ) { wReset = pReset->next; free_reset_data( pReset ); } pRoom->next = room_index_free; room_index_free = pRoom; return; } 2. In olc.c add an entry in each of reidit/medit/oedit_table for the new delete function. (look for the RIGHT HERE) Example: const struct olc_cmd_type redit_table[] = { /* { command, function }, */ { "commands", show_commands }, { "create", redit_create }, { "desc", redit_desc }, { "ed", redit_ed }, { "format", redit_format }, { "name", redit_name }, { "show", redit_show }, { "heal", redit_heal }, { "mana", redit_mana }, { "clan", redit_clan }, { "north", redit_north }, { "south", redit_south }, { "east", redit_east }, { "west", redit_west }, { "up", redit_up }, { "down", redit_down }, { "copy", redit_copy }, { "delete", redit_delete }, /* <----RIGHT HERE */ /* New reset commands. */ { "mreset", redit_mreset }, { "oreset", redit_oreset }, { "mlist", redit_mlist }, { "rlist", redit_rlist }, { "olist", redit_olist }, { "mshow", redit_mshow }, { "oshow", redit_oshow }, { "owner", redit_owner }, { "room", redit_room }, { "sector", redit_sector }, { "?", show_help }, { "version", show_version }, { NULL, 0 } }; 3. In olc.c, in each of the functions do_redit/medit/oedit add a hook for the new command such as the following example: (look for the RIGHT HERE) void do_redit( CHAR_DATA *ch, char *argument ) { ROOM_INDEX_DATA *pRoom; char arg1[MAX_STRING_LENGTH]; if ( IS_NPC(ch) ) return; argument = one_argument( argument, arg1 ); pRoom = ch->in_room; if ( !str_cmp( arg1, "reset" ) ) { if ( !IS_BUILDER( ch, pRoom->area ) ) { send_to_char( "Insufficient security to reset rooms.\n\r" , ch ); return; } reset_room( pRoom, TRUE); send_to_char( "Room reset.\n\r", ch ); return; } else if( !str_cmp( arg1, "delete" ) ) { redit_delete( ch, argument ); /* <--- RIGHT HERE */ return; } else if ( !str_cmp( arg1, "create" ) ) { if ( ( argument[0] == '\0' || atoi( argument ) == 0 ) && str_cmp( argument, "next" ) ) { send_to_char( "Syntax: edit room create [vnum | next]\n\r", ch ); return; } if ( redit_create( ch, argument ) ) { ch->desc->editor = ED_ROOM; char_from_room( ch ); char_to_room( ch, ch->desc->pEdit ); SET_BIT( ((ROOM_INDEX_DATA *)ch->desc->pEdit)->area->area_flags, AREA_CHANGED ); } return; } (rest of function not included for brevity. note: my do_redit probably looks slightly different then yours) 4. In olc_act.c paste in the following functions: OEDIT( oedit_delete ) { CHAR_DATA *wch, *ch_next; OBJ_DATA *obj, *obj_next; OBJ_INDEX_DATA *pObj; RESET_DATA *pReset, *wReset, *tReset; ROOM_INDEX_DATA *pRoom; char arg[MIL]; char buf[MSL]; int index, rcount, ocount, i, iHash; if ( argument[0] == '\0' ) { send_to_char( "Syntax: oedit delete [vnum]\n\r", ch ); return FALSE; } one_argument( argument, arg ); if( is_number( arg ) ) { index = atoi( arg ); pObj = get_obj_index( index ); } else { send_to_char( "That is not a number.\n\r", ch ); return FALSE; } if( !pObj ) { send_to_char( "No such object.\n\r", ch ); return FALSE; } SET_BIT( pObj->area->area_flags, AREA_CHANGED ); if( top_vnum_obj == index ) for( i = 1; i < index; i++ ) if( get_obj_index( i ) ) top_vnum_obj = i; top_obj_index--; /* remove objects */ ocount = 0; for( obj = object_list; obj; obj = obj_next ) { obj_next = obj->next; if( obj->pIndexData == pObj ) { extract_obj( obj ); ocount++; } } /* crush resets */ rcount = 0; for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for( pRoom = room_index_hash[iHash]; pRoom; pRoom = pRoom->next ) { for( pReset = pRoom->reset_first; pReset; pReset = wReset ) { wReset = pReset->next; switch( pReset->command ) { case 'O': case 'E': case 'P': case 'G': if( ( pReset->arg1 == index ) || ( ( pReset->command == 'P' ) && ( pReset->arg3 == index ) ) ) { unlink_reset( pRoom, pReset ); free_reset_data( pReset ); rcount++; SET_BIT( pRoom->area->area_flags, AREA_CHANGED ); } } } } } unlink_obj_index( pObj ); pObj->area = NULL; pObj->vnum = 0; free_obj_index( pObj ); sprintf( buf, "Removed object vnum ^C%d^x and" " ^C%d^x resets.\n\r", index,rcount ); send_to_char( buf, ch ); sprintf( buf, "^C%d^x occurences of the object" " were extracted from the mud.\n\r", ocount ); send_to_char( buf, ch ); return TRUE; } MEDIT( medit_delete ) { CHAR_DATA *wch, *wnext; MOB_INDEX_DATA *pMob; RESET_DATA *pReset, *wReset; ROOM_INDEX_DATA *pRoom; char arg[MIL]; char buf[MSL]; int index, mcount, rcount, iHash, i; bool foundmob = FALSE; bool foundobj = FALSE; if( argument[0] == '\0' ) { send_to_char( "Syntax: medit delete [vnum]\n\r", ch ); return FALSE; } one_argument( argument, arg ); if( is_number( arg ) ) { index = atoi( arg ); pMob = get_mob_index( index ); } else { send_to_char( "That is not a number.\n\r", ch ); return FALSE; } if( !pMob ) { send_to_char( "No such mobile.\n\r", ch ); return FALSE; } SET_BIT( pMob->area->area_flags, AREA_CHANGED ); if( top_vnum_mob == index ) for( i = 1; i < index; i++ ) if( get_mob_index( i ) ) top_vnum_mob = i; top_mob_index--; /* Now crush all resets and take out mobs while were at it */ rcount = 0; mcount = 0; for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for( pRoom = room_index_hash[iHash]; pRoom; pRoom = pRoom->next ) { for( wch = pRoom->people; wch; wch = wnext ) { wnext = wch->next_in_room; if( wch->pIndexData == pMob ) { extract_char( wch, TRUE ); mcount++; } } for( pReset = pRoom->reset_first; pReset; pReset = wReset ) { wReset = pReset->next; switch( pReset->command ) { case 'M': if( pReset->arg1 == index ) { foundmob = TRUE; unlink_reset( pRoom, pReset ); free_reset_data( pReset ); rcount++; SET_BIT( pRoom->area->area_flags, AREA_CHANGED ); } else foundmob = FALSE; break; case 'E': case 'G': if( foundmob ) { foundobj = TRUE; unlink_reset( pRoom, pReset ); free_reset_data( pReset ); rcount++; SET_BIT( pRoom->area->area_flags, AREA_CHANGED ); } else foundobj = FALSE; break; case '0': foundobj = FALSE; break; case 'P': if( foundobj && foundmob ) { unlink_reset( pRoom, pReset ); free_reset_data( pReset ); rcount++; SET_BIT( pRoom->area->area_flags, AREA_CHANGED ); } } } } } unlink_mob_index( pMob ); pMob->area = NULL; pMob->vnum = 0; free_mob_index( pMob ); printf_to_char( ch, "Removed mobile vnum ^C%d^x and" " ^C%d^x resets.\n\r", index, rcount ); printf_to_char( ch, "^C%d^x mobiles were extracted" " from the mud.\n\r",mcount ); return TRUE; } REDIT( redit_delete ) { ROOM_INDEX_DATA *pRoom, *pRoom2; RESET_DATA *pReset; EXIT_DATA *ex; OBJ_DATA *Obj, *obj_next; CHAR_DATA *wch, *wnext; EXTRA_DESCR_DATA *pExtra; char arg[MIL]; char buf[MSL]; int index, i, iHash, rcount, ecount, mcount, ocount, edcount; if ( argument[0] == '\0' ) { send_to_char( "Syntax: redit delete [vnum]\n\r", ch ); return FALSE; } one_argument( argument, arg ); if( is_number( arg ) ) { index = atoi( arg ); pRoom = get_room_index( index ); } else { send_to_char( "That is not a number.\n\r", ch ); return FALSE; } if( !pRoom ) { send_to_char( "No such room.\n\r", ch ); return FALSE; } /* Move the player out of the room. */ if( ch->in_room->vnum == index ) { send_to_char( "Moving you out of the room" " you are deleting.\n\r", ch); if( ch->fighting != NULL ) stop_fighting( ch, TRUE ); char_from_room( ch ); char_to_room( ch, get_room_index( 3 ) ); /* limbo */ ch->was_in_room = ch->in_room; ch->from_room = ch->in_room; } SET_BIT( pRoom->area->area_flags, AREA_CHANGED ); /* Count resets. They are freed by free_room_index. */ rcount = 0; for( pReset = pRoom->reset_first; pReset; pReset = pReset->next ) { rcount++; } /* Now contents */ ocount = 0; for( Obj = pRoom->contents; Obj; Obj = obj_next ) { obj_next = Obj->next_content; extract_obj( Obj ); ocount++; } /* Now PCs and Mobs */ mcount = 0; for( wch = pRoom->people; wch; wch = wnext ) { wnext = wch->next_in_room; if( IS_NPC( wch ) ) { extract_char( wch, TRUE ); mcount++; } else { send_to_char( "This room is being deleted. Moving" " you somewhere safe.\n\r", ch ); if( wch->fighting != NULL ) stop_fighting( wch, TRUE ); char_from_room( wch ); /* Midgaard Temple */ char_to_room( wch, get_room_index( 3054 ) ); wch->was_in_room = wch->in_room; wch->from_room = wch->in_room; } } /* unlink all exits to the room. */ ecount = 0; for( iHash = 0; iHash < MAX_KEY_HASH; iHash++ ) { for( pRoom2 = room_index_hash[iHash]; pRoom2; pRoom2 = pRoom2->next ) { for( i = 0; i <= MAX_DIR; i++ ) { if( !( ex = pRoom2->exit[i] ) ) continue; if( pRoom2 == pRoom ) { /* these are freed by free_room_index */ ecount++; continue; } if( ex->u1.to_room == pRoom ) { free_exit( pRoom2->exit[i] ); pRoom2->exit[i] = NULL; SET_BIT( pRoom2->area->area_flags, AREA_CHANGED ); ecount++; } } } } /* count extra descs. they are freed by free_room_index */ edcount = 0; for ( pExtra = pRoom->extra_descr; pExtra; pExtra = pExtra->next ) { edcount++; } if( top_vnum_room == index ) for( i = 1; i < index; i++ ) if( get_room_index( i ) ) top_vnum_room = i; top_room--; unlink_room_index( pRoom ); pRoom->area = NULL; pRoom->vnum = 0; free_room_index( pRoom ); /* Na na na na! Hey Hey Hey, Good Bye! */ sprintf( buf, "Removed room vnum ^C%d^x, %d resets, %d extra " "descriptions and %d exits.\n\r", index, rcount, edcount, ecount ); send_to_char( buf, ch ); sprintf( buf, "^C%d^x objects and ^C%d^x mobiles were extracted " "from the room.\n\r", ocount, mcount ); send_to_char( buf, ch ); return TRUE; } /* unlink a given reset from a given room */ void unlink_reset( ROOM_INDEX_DATA *pRoom, RESET_DATA *pReset ) { RESET_DATA *prev, *wReset; prev = pRoom->reset_first; for( wReset = pRoom->reset_first; wReset; wReset = wReset->next ) { if( wReset == pReset ) { if( pRoom->reset_first == pReset ) { pRoom->reset_first = pReset->next; if( !pRoom->reset_first ) pRoom->reset_last = NULL; } else if( pRoom->reset_last == pReset ) { pRoom->reset_last = prev; prev->next = NULL; } else prev->next = prev->next->next; if( pRoom->area->reset_first == pReset ) pRoom->area->reset_first = pReset->next; if( !pRoom->area->reset_first ) pRoom->area->reset_last = NULL; } prev = wReset; } } void unlink_obj_index( OBJ_INDEX_DATA *pObj ) { int iHash; OBJ_INDEX_DATA *iObj, *sObj; iHash = pObj->vnum % MAX_KEY_HASH; sObj = obj_index_hash[iHash]; if( sObj->next == NULL ) /* only entry */ obj_index_hash[iHash] = NULL; else if( sObj == pObj ) /* first entry */ obj_index_hash[iHash] = pObj->next; else /* everything else */ { for( iObj = sObj; iObj != NULL; iObj = iObj->next ) { if( iObj == pObj ) { sObj->next = pObj->next; break; } sObj = iObj; } } } void unlink_room_index( ROOM_INDEX_DATA *pRoom ) { int iHash; ROOM_INDEX_DATA *iRoom, *sRoom; iHash = pRoom->vnum % MAX_KEY_HASH; sRoom = room_index_hash[iHash]; if( sRoom->next == NULL ) /* only entry */ room_index_hash[iHash] = NULL; else if( sRoom == pRoom ) /* first entry */ room_index_hash[iHash] = pRoom->next; else /* everything else */ { for( iRoom = sRoom; iRoom != NULL; iRoom = iRoom->next ) { if( iRoom == pRoom ) { sRoom->next = pRoom->next; break; } sRoom = iRoom; } } } void unlink_mob_index( MOB_INDEX_DATA *pMob ) { int iHash; MOB_INDEX_DATA *iMob, *sMob; iHash = pMob->vnum % MAX_KEY_HASH; sMob = mob_index_hash[iHash]; if( sMob->next == NULL ) /* only entry */ mob_index_hash[iHash] = NULL; else if( sMob == pMob ) /* first entry */ mob_index_hash[iHash] = pMob->next; else /* everything else */ { for( iMob = sMob; iMob != NULL; iMob = iMob->next ) { if( iMob == pMob ) { sMob->next = pMob->next; break; } sMob = iMob; } } } 5. In olc.h add the following DECLARES in the appropriate locations: DECLARE_OLC_FUN( redit_delete ); DECLARE_OLC_FUN( oedit_delete ); DECLARE_OLC_FUN( medit_delete ); 6. Recompile and all should be well. I STRONGLY suggest either running a backup copy or running a second mud on a different port logging in and deleting a few things then saving and rebooting just to make sure things are working well. (If you do the second mud on the same machine idea DO NOT FORGET to asave world on the main mud to restore the area files). If you have any problems/bugs to report you can mail me at feist@nortel.ca Thats it!