/
roa/
roa/lib/boards/
roa/lib/config/
roa/lib/edits/
roa/lib/help/
roa/lib/misc/
roa/lib/plrobjs/
roa/lib/quests/
roa/lib/socials/
roa/lib/www/
roa/lib/www/LEDSign/
roa/lib/www/LEDSign/fonts/
roa/lib/www/LEDSign/scripts/
roa/src/s_inc/
roa/src/sclient/
roa/src/sclient/binary/
roa/src/sclient/text/
roa/src/util/
/************************************************************************
	Realms of Aurealis 		James Rhone aka Vall of RoA

freeall.c			Code which frees up everything the mud
				allocates during runtime. (In theory.)
				Useful for linking to dmalloc to track
				memory leaks and such.

				Also: general freeing code, yanked out
				of db.c during the great db.c splitup
				of January 1997.

		******** 100% completely original code ********
		*** BE AWARE OF ALL RIGHTS AND RESERVATIONS ***
		******** 100% completely original code ********
		        All rights reserved henceforth. 

    Please note that no guarantees are associated with any code from
Realms of Aurealis.  All code which has been released to the general
public has been done so with an 'as is' pretense.  RoA is based on both
Diku and CircleMUD and ALL licenses from both *MUST* be adhered to as well
as the RoA license.   *** Read, Learn, Understand, Improve ***
*************************************************************************/
#include "conf.h"
#include "sysdep.h"

#include "structures.h"
#include "utils.h"
#include "db.h"
#include "comm.h"
#include "handler.h"
#include "mudlimits.h"
#include "magic.h"
#include "mail.h"
#include "interpreter.h"
#include "quest.h"
#include "affect.h"
#include "lists.h"
#include "global.h"
#include "htown.h"
#include "thief.h"

// internal functions
void 	free_this_mob(int i);
void 	free_obj_proto(int i);
void 	free_banned_list(void);
void	free_bufpools(void);
int 	free_this_zone(int i);

// external freeing functions
void 	free_the_boards(void);
void 	free_room_affects(struct room_affect_type *head);
void	reset_mob_proto(int rnum);

// external variables used
extern struct pc_special_data dummy;	// dummy declared in db.c for mobs
extern struct pc_special_data dummy_mob;
extern struct message_list fight_messages[MAX_MESSAGES]; 
extern struct htown_data htowns[];

// globals, ptable names, fight messages, etc
void free_up_globals(void)
{
  FREENULL(races);
  FREENULL(title0);
  FREENULL(title1);
  FREENULL(title2);
  FREENULL(title3);
  FREENULL(title4);
  FREENULL(title5);
  FREENULL(news);
  FREENULL(credits);
  FREENULL(credit_sequence);
  FREENULL(motd);
  FREENULL(imotd);
  FREENULL(info);
  FREENULL(wizlist);
  FREENULL(immlist);
  FREENULL(policies);
  FREENULL(handbook);
  FREENULL(background);
  FREENULL(welcome);
  FREENULL(start);

  FREENULL(currency_name);
  FREENULL(currency_name_plural);
  FREENULL(longmudname);
  FREENULL(shortmudname);
  FREENULL(MENU);
  FREENULL(VTMENU);

  FREENULL(impname);
  FREENULL(cimpname);
  FREENULL(aimpname);
  FREENULL(godname);
  FREENULL(avtrname);
  FREENULL(trustedname);
  FREENULL(ambassname);

  FREENULL(spico_path);

  FREENULL(www_page);
  FREENULL(www_mailto);
  FREENULL(www_contact_name);

  FREENULL(RoA_version);
  FREENULL(OLC_version);
}

void free_wear_offs(void)
{
  int i;

  for (i = 0; i < MAX_SPELLS; i++)
    FREENULL(spell_info[i].wear_off);
}

void free_htowns(void)
{
  int i;

  for (i = 0; i < MAX_HTOWNS && htowns[i].name && *htowns[i].name; i++)
  {
    FREENULL(htowns[i].name);
  }
}

// free up the combat messages
void free_up_messages(void)
{
  int i;
  struct message_type *messages, *temp;

  for (i=0; i < MAX_MESSAGES; i++)
    while (fight_messages[i].msg)
    {
      FREENULL(fight_messages[i].msg->die_msg.attacker_msg);      
      FREENULL(fight_messages[i].msg->die_msg.victim_msg);  
      FREENULL(fight_messages[i].msg->die_msg.room_msg);    

      FREENULL(fight_messages[i].msg->miss_msg.attacker_msg);     
      FREENULL(fight_messages[i].msg->miss_msg.victim_msg);   
      FREENULL(fight_messages[i].msg->miss_msg.room_msg);     

      FREENULL(fight_messages[i].msg->hit_msg.attacker_msg);      
      FREENULL(fight_messages[i].msg->hit_msg.victim_msg);    
      FREENULL(fight_messages[i].msg->hit_msg.room_msg);      

      FREENULL(fight_messages[i].msg->god_msg.attacker_msg);      
      FREENULL(fight_messages[i].msg->god_msg.victim_msg);        
      FREENULL(fight_messages[i].msg->god_msg.room_msg);      

      messages = fight_messages[i].msg;
      REMOVE_FROM_LIST(messages, fight_messages[i].msg, next);
      free(messages);
    }
}

void free_quests(void)
{
  int qnum;
  qslot *qptr;

  qnum = 0;
  while (qarray[qnum].qname && qnum < NUM_QUESTS)
  {
    qptr = &qarray[qnum];

    FREENULL(qptr->qname);
    FREENULL(qptr->qdesc);
    FREENULL(qptr->char_notification);
    FREENULL(qptr->zone_notification);
    FREENULL(qptr->world_notification);
    qnum++;
  }
}

void free_bufpools(void)
{
  extern struct txt_block *bufpool;  
  struct txt_block *b, *temp;

  while ((b = bufpool))
  {
    REMOVE_FROM_LIST(b, bufpool, next);
    FREENULL(b->text);
    FREENULL(b);
  }
}

// added trap freeing  4/10/98 -jtrhone
trap *free_traps(trap *head)
{
  trap *ths, *temp;

  while((ths = head))
  {
    REMOVE_FROM_LIST(ths, head, next);
    FREENULL(ths);
  }

  return NULL;
}

/* goes thru an extra descrip list and waxes each member along with ptr to it -roa */
exdescdata *free_extra_descrips(exdescdata *head)
{
  exdescdata *ths, *temp;

  while((ths = head))
  {
    REMOVE_FROM_LIST(ths, head, next);
    FREENULL(ths->keyword);
    FREENULL(ths->description);
    FREENULL(ths);
  }

  return NULL;
}

/* goes thru an alias list and waxes each member along with ptr to it -roa */
struct alias *free_alias_list(struct alias *head)
{
  struct alias *ths, *temp;

  while((ths = head))
  {
    REMOVE_FROM_LIST(ths, head, next);
    FREENULL(ths->alias);
    FREENULL(ths->replacement);
    FREENULL(ths);
  }

  return NULL;
}

// wax a TRIG list on a char
struct mtrig_type *free_mtriggers(struct mtrig_type *head)
{
  struct mtrig_type *ths, *temp;

  while ((ths = head))
  {
    REMOVE_FROM_LIST(ths, head, next);
    FREENULL(ths->trigger);
    FREENULL(ths->reaction);
    FREENULL(ths);
  }

  return NULL;
}

// wax a TRIG list on a room
rtrig *free_rtriggers(rtrig *head)
{
  rtrig *ths, *temp;

  while ((ths = head))
  {
    REMOVE_FROM_LIST(ths, head, next);
    FREENULL(ths->trigger);
    FREENULL(ths->reaction);
    FREENULL(ths);
  }

  return NULL;
}

/* this frees up all the names allocated in the ptable name field */
void free_ptable_names(void)
{
  int i;
  
  for (i=0; i <= top_of_p_table; i++)
    FREENULL(player_table[i].name);
  FREENULL(player_table);
}

void clear_and_remove_auction(aucdata *aptr)
{
  aucdata *temp = NULL;

  if (aptr == auction_ptr) 
  {
    auction_ptr = aptr->next;
    FREENULL(aptr);
    return;
  }

  REMOVE_FROM_LIST(aptr, auction_ptr, next);
  FREENULL(aptr);
}

void free_auctions(void)
{
  aucdata *a;

  while ((a = auction_ptr))
    clear_and_remove_auction(a);
}

void free_plshops(void)
{
  plshop *ptr, *temp;

  while ((ptr = pls_global))
  {
    REMOVE_FROM_LIST(ptr, pls_global, global_next);
    FREENULL(ptr);
  }
}

void free_IdList(IdList *list)
{
  IdList *ptr, *temp;

  while ((ptr = list))
  {
    REMOVE_FROM_LIST(ptr, list, next);
    FREENULL(ptr);
  }
}

/* release memory allocated for a char struct */
// now free sound_file if not matching proto... 2/21/98 -jtrhone
void free_char(chdata *ch)
{
  int i, j;

  TRIGS(ch) = free_mtriggers(TRIGS(ch));

  GET_ALIASES(ch) = free_alias_list(GET_ALIASES(ch));

  // 3/18/98, must free these now too -jtrhone
  free_IdList(ch->gagged);
  ch->gagged = NULL;

  // Free concealed and revealed structures. 03/22/98 -callahan
  free_IdList(ch->concealed);
  ch->concealed = NULL;

  free_IdList(ch->revealed);
  ch->revealed = NULL;

  while (ch->affected)
    affect_remove(ch, ch->affected);

  if ((ch->pc_specials) && (ch->pc_specials != &dummy_mob)) 
  {
    FREENULL(ch->pc_specials);
    if (IS_NPC(ch))
      log("SYSERR: Mob had pc_specials allocated!");
  }

  if (!IS_NPC(ch) || (IS_NPC(ch) && GET_MOB_RNUM(ch) == -1)) 
  {
    /* if this is a player, or a non-prototyped non-player, free all */
    FREENULL(ch->player.name);
    FREENULL(ch->player.title);
    FREENULL(ch->player.afk_str);	// 05/04/98 -callahan
    FREENULL(ch->player.short_descr);
    FREENULL(ch->player.long_descr);
    FREENULL(ch->player.description);
  } 
  else 
  if ((i = GET_MOB_RNUM(ch)) > -1) 
  {
    /* otherwise, free strings only if the string is not pointing at proto */
    if (ch->player.name && ch->player.name != mob_proto[i].player.name)
      free(ch->player.name);
    if (ch->player.title && ch->player.title != mob_proto[i].player.title)
      free(ch->player.title);

    // 05/04/98 -callahan
    if (ch->player.afk_str && ch->player.afk_str != mob_proto[i].player.afk_str)
      free(ch->player.afk_str);

    if (ch->player.short_descr && ch->player.short_descr != mob_proto[i].player.short_descr)
      free(ch->player.short_descr);
    if (ch->player.long_descr && ch->player.long_descr != mob_proto[i].player.long_descr)
      free(ch->player.long_descr);
    if (ch->player.description && ch->player.description != mob_proto[i].player.description)
      free(ch->player.description);

    if (ch->npc_specials.walkIn && ch->npc_specials.walkIn != mob_proto[i].npc_specials.walkIn)
      free(ch->npc_specials.walkIn);

    if (ch->npc_specials.walkOut && ch->npc_specials.walkOut != 
				   mob_proto[i].npc_specials.walkOut)
      free(ch->npc_specials.walkOut);

    if (ch->npc_specials.shop_data && ch->npc_specials.shop_data != 
				   mob_proto[i].npc_specials.shop_data)
      free(ch->npc_specials.shop_data);

    if (ch->npc_specials.sound_file && ch->npc_specials.sound_file != 
				   mob_proto[i].npc_specials.sound_file)
      free(ch->npc_specials.sound_file);

    for (j = 0; j < 5; j++)
     if (ch->npc_specials.strs[j] && 
	 ch->npc_specials.strs[j] != mob_proto[i].npc_specials.strs[j])
     {
	FREENULL(ch->npc_specials.strs[j]);
     }

     // DO NOT free MPROC_CUR on a MOBPROC, 
     // cause its used to point to MPROC_BEG
     MPROC_CUR(ch) = NULL;
  }

  if (ch->skills)
  {
    FREENULL(ch->skills);
    if (IS_NPC(ch))
      log("NPC had skills array allocated.");
  }

  if (ch->gskills)
  {
    FREENULL(ch->gskills);
    if (IS_NPC(ch))
      log("NPC had gskills array allocated.");
  }

  FREENULL(TARGET_CHAR(ch));
  FREENULL(TARGET_OBJ(ch));
  free(ch);
}

/* this function purges every mob / player loaded in game */
void purge_all_mobs(void)
{
  int i = 0;
  while (character_list)
  {
    i++;
    extract_char(character_list);
  }

#ifdef DEBUG_MAX
  sprintf(buf, "SYSUPD: %d chars freed.", i);
  mudlog(buf, BUG, LEV_IMM, TRUE);
#endif
}

/* this frees up every mobile in the proto list */
void free_up_mobs(void)
{
  chdata *ch;
  int i = 0;
  int j;

  while (i < top_of_mobt)
  { 
    ch = &mob_proto[i];
    if ((ch->pc_specials) && (ch->pc_specials != &dummy_mob)) 
    {
      FREENULL(ch->pc_specials);
      log("SYSERR: Mob Proto pc_specials allocated!");
    }
    FREENULL(ch->player.name);
    FREENULL(ch->player.title);
    FREENULL(ch->player.afk_str);	// 05/04/98 -callahan
    FREENULL(ch->player.short_descr);
    FREENULL(ch->player.long_descr);
    FREENULL(ch->player.description);
    FREENULL(ch->npc_specials.walkIn);
    FREENULL(ch->npc_specials.walkOut);
    FREENULL(ch->npc_specials.sound_file);
    FREENULL(ch->npc_specials.shop_data);
    for (j = 0; j < 5; j++)
      FREENULL(ch->npc_specials.strs[j]);
    MPROC_CUR(ch) = NULL;  // do NOT free strs[5]
    i++;
  }

  /* now free up the mob_proto list itself */
  free(mob_proto);
  free(mob_index);
}

/* release memory allocated for a char struct */
/* REGARDLESS of proto stuff, cause its used for skipped mob protos */
void free_this_mob(int proto)
{
  chdata *ch;
  int j;

  ch = &mob_proto[proto];
  if ((ch->pc_specials) && (ch->pc_specials != &dummy_mob)) 
  {
    FREENULL(ch->pc_specials);
    if (IS_NPC(ch))
      log("SYSERR: Mob had pc_specials allocated!");
  }

  FREENULL(GET_NAME(ch));
  FREENULL(ch->player.title);
  FREENULL(ch->player.afk_str);		// 05/04/98 -callahan
  FREENULL(ch->player.short_descr);
  FREENULL(ch->player.long_descr);
  FREENULL(ch->player.description);
  FREENULL(ch->npc_specials.walkIn);
  FREENULL(ch->npc_specials.walkOut);
  FREENULL(ch->npc_specials.sound_file);
  FREENULL(ch->npc_specials.shop_data);

  // do NOT free strs[5], its used to point to strs[4]
  for (j = 0; j < 5; j++)
    FREENULL(ch->npc_specials.strs[j]);
  MPROC_CUR(ch) = NULL;

  // now NULL out all information and reset to default
  reset_mob_proto(proto);
}

/* this function purges every object loaded in game */
void purge_all_objs(void)
{
  int i = 0;

  while (object_list)
  {
    i++;
    extract_obj(object_list);
  }

#ifdef DEBUG_MAX
  sprintf(buf, "SYSUPD: %d objs freed.", i);
  mudlog(buf, BUG, LEV_IMM, TRUE);
#endif
}

void purge_descriptors(void)
{
  int i = 0;
  while (descriptor_list)
  {
    i++;
    close_socket(descriptor_list);
  }

#ifdef DEBUG_MAX
  sprintf(buf, "SYSUPD: %d descriptors freed.", i);
  mudlog(buf, BUG, LEV_IMM, TRUE);
#endif
}

/* this frees up every object in the proto list */
void free_up_objs(void)
{
  int i = 0;

  while (i < top_of_objt)
  {
    free_obj_proto(i);
    i++;
  }
  free(obj_proto);
  free(obj_index);
}

/* release memory allocated for an obj struct */
void free_obj(obdata *obj)
{
  int nr;

  // wax the traps, 4/10/98 -jtrhone
  TRAPS(obj) = free_traps(TRAPS(obj));

  // bugfix, do not treat instruments any differently than other objects with
  // respect to freeing... only free strings if they
  // a) dont belong to a proto or 
  // b) are different from the protos strings (in the case of instrums... they have
  //    differing strings than protos...)  5/13/98 - jtrhone
  if ((nr = GET_OBJ_RNUM(obj)) <= -1) 
  {
    FREENULL(obj->name);
    FREENULL(obj->description);
    FREENULL(obj->shdesc);
    FREENULL(obj->actdesc);
    FREENULL(obj->wear_mesg);
    FREENULL(obj->rem_mesg);
    FREENULL(obj->weap_sing);
    FREENULL(obj->weap_plur);
    obj->exdesc = free_extra_descrips(obj->exdesc);
  }
  else
  {
    if (obj->name && obj->name != obj_proto[nr].name)
      free(obj->name);
    if (obj->description && obj->description != obj_proto[nr].description)
      free(obj->description);
    if (obj->shdesc  && obj->shdesc  != obj_proto[nr].shdesc)
      free(obj->shdesc);
    if (obj->actdesc && obj->actdesc != obj_proto[nr].actdesc)
      free(obj->actdesc);
    if (obj->wear_mesg && obj->wear_mesg != obj_proto[nr].wear_mesg)
      free(obj->wear_mesg);
    if (obj->rem_mesg && obj->rem_mesg != obj_proto[nr].rem_mesg)
      free(obj->rem_mesg);
    if (obj->weap_sing && obj->weap_sing != obj_proto[nr].weap_sing)
      free(obj->weap_sing);
    if (obj->weap_plur && obj->weap_plur != obj_proto[nr].weap_plur)
      free(obj->weap_plur);
    if (obj->exdesc  && obj->exdesc  != obj_proto[nr].exdesc)
      obj->exdesc = free_extra_descrips(obj->exdesc);
  }
  free(obj);
}

/* release memory allocated for an obj struct */
/* do so REGARDLESS of proto, its used to free a skipped proto -roa */
void free_obj_proto(int i)
{
  obdata *obj = &obj_proto[i];

  FREENULL(obj->name);
  FREENULL(obj->description);
  FREENULL(obj->shdesc);
  FREENULL(obj->actdesc);
  FREENULL(obj->wear_mesg);
  FREENULL(obj->rem_mesg);
  FREENULL(obj->weap_sing);
  FREENULL(obj->weap_plur);
  obj->exdesc = free_extra_descrips(obj->exdesc);
}

/* waxes one rooms descrips, and extra descriptions, 
   including DIRs string data */
void free_this_room(int i)
{
  int dir;

  FREENULL(world[i].name);
  FREENULL(world[i].description);

  for (dir = 0; dir < 5; dir++)
    FREENULL(world[i].randoms[dir]);

  world[i].exdesc = free_extra_descrips(world[i].exdesc);

  free_room_affects(world[i].room_affects);
  world[i].room_affects = NULL;

  // wax the traps, 4/10/98 -jtrhone
  TRAPS(&world[i]) = free_traps(TRAPS(&world[i]));

  /* free the directions off each room */
  // UPDATE 2/15/97, no longer free the direction itself
  // just free the strings off it -jtrhone roa
  for (dir = 0; dir < NUM_OF_DIRS; dir++)
    if(DIR(i, dir))
    {
      FREENULL(DIR(i, dir)->exit_descr);
      FREENULL(DIR(i, dir)->keyword);

      // Exit messages. 03/24/98 -callahan
      FREENULL(DIR(i, dir)->enter);
      FREENULL(DIR(i, dir)->oenter);
      FREENULL(DIR(i, dir)->drop);
      FREENULL(DIR(i, dir)->odrop);

      // wax the traps, 4/10/98 -jtrhone
      TRAPS(DIR(i, dir)) = free_traps(TRAPS(DIR(i, dir)));
    }

  // now free triggers  6/5/98 -jtrhone
  RTRIGS(&world[i]) = free_rtriggers(RTRIGS(&world[i]));
  FREENULL(RPROC_BEG(&world[i]));
  RPROC_CUR(&world[i]) = NULL;
  FREENULL(RTARGET_CHAR(&world[i]));
  FREENULL(RTARGET_OBJ(&world[i]));
}

/* release the strings of all the rooms in this zone */
/* also release the zones comlist */
// now also free sound_file 2/21/98 -jtrhone
int free_this_zone(int i)
{
  int rroom, vroom, vbase, vtop;

  if (ZONE_FLAGGED(i, Z_LOCKED))
  {
    sprintf(buf, "SYSERR: attempted free of locked zone (%d).",i);
    mudlog(buf, BRF, LEV_IMM, TRUE);
    return (0);
  }

  for (vroom = 0; vroom < 4; vroom++)
  {
    FREENULL(zone_table[i].seasons[vroom].sunrise);
    FREENULL(zone_table[i].seasons[vroom].daytime);
    FREENULL(zone_table[i].seasons[vroom].sunset);
    FREENULL(zone_table[i].seasons[vroom].nighttime);
  }

  FREENULL(zone_table[i].sound_file);
  FREENULL(zone_table[i].comlist);

  // rooms in zone range from XXX00 to XXX99
  vbase = i * 100;
  vtop = vbase + 99;

  for (vroom = vbase; vroom <= vtop; vroom++)
    if ((rroom = real_room(vroom)) >= 0)
      free_this_room(rroom);

  SET_ZONE_FREED(i);

  return(1);
}

/* this function frees up rooms/dirs/extra descrips on rooms/randoms */
// also free sound_file now 2/20/98 -jtrhone
void free_up_world(void)
{
  rmdata *temp;
  int i = 0, dir;

  while (i < top_of_world)
  {
    temp = &world[i];
    FREENULL(temp->name);
    FREENULL(temp->description);

    for (dir = 0; dir < 5; dir++)
      FREENULL(temp->randoms[dir]);

    temp->exdesc = free_extra_descrips(temp->exdesc);

    free_room_affects(temp->room_affects);
    temp->room_affects = NULL;

    // wax the traps, 4/10/98 -jtrhone
    TRAPS(temp) = free_traps(TRAPS(temp));

    /* free the directions off each room */
    for (dir = 0; dir < NUM_OF_DIRS; dir++)
      if(DIR(i, dir))
      {
	FREENULL(DIR(i, dir)->exit_descr);
	FREENULL(DIR(i, dir)->keyword);

        // Exit messages. 03/24/98 -callahan
	FREENULL(DIR(i, dir)->enter);
	FREENULL(DIR(i, dir)->oenter);
	FREENULL(DIR(i, dir)->drop);
	FREENULL(DIR(i, dir)->odrop);

        // wax the traps, 4/10/98 -jtrhone
        TRAPS(DIR(i, dir)) = free_traps(TRAPS(DIR(i, dir)));

        free(DIR(i, dir));
      }

    FREENULL(temp->sound_file);

    // now free triggers  6/5/98 -jtrhone
    RTRIGS(&world[i]) = free_rtriggers(RTRIGS(&world[i]));
    FREENULL(RPROC_BEG(&world[i]));
    RPROC_CUR(&world[i]) = NULL;
    FREENULL(RTARGET_CHAR(&world[i]));
    FREENULL(RTARGET_OBJ(&world[i]));

    i++;
  }

  /* all the descrips are freed now lets free world array */
  free(world);
  world = NULL;
}

/* free_the_mud calls every purge function and frees up everything the
   mud had allocated (save a couple things, like plrmail) */
void free_the_mud(void)
{
  int zon = 0;
  int i;

  free_the_boards();
  free_up_messages();
  free_up_globals();
  purge_all_mobs();
  purge_descriptors();  // get rid of players ... 3/7/98 -jtrhone
  purge_all_objs();
  free_up_mobs();
  free_up_objs();
  free_up_world();
  free_ptable_names();
  free_banned_list();
  free_bufpools();
  free_auctions();
  free_quests();
  free_wear_offs();
  free_plshops();
  free_htowns();

  while (zon < NUM_ZONES)
  {
    FREENULL(zone_table[zon].name);
    for (i = 0; i < 4; i++)
    {
      FREENULL(zone_table[zon].seasons[i].sunrise);
      FREENULL(zone_table[zon].seasons[i].daytime);
      FREENULL(zone_table[zon].seasons[i].sunset);
      FREENULL(zone_table[zon].seasons[i].nighttime);
    }
    FREENULL(zone_table[zon].comlist);
    FREENULL(zone_table[zon].sound_file);
    zon++;
  }
}