circle-3.5/bin/
circle-3.5/cnf/
circle-3.5/lib/
circle-3.5/lib/etc/
circle-3.5/lib/house/
circle-3.5/lib/misc/
circle-3.5/lib/plralias/A-E/
circle-3.5/lib/plralias/F-J/
circle-3.5/lib/plralias/K-O/
circle-3.5/lib/plralias/P-T/
circle-3.5/lib/plralias/U-Z/
circle-3.5/lib/plralias/ZZZ/
circle-3.5/lib/plrobjs/
circle-3.5/lib/plrobjs/A-E/
circle-3.5/lib/plrobjs/F-J/
circle-3.5/lib/plrobjs/K-O/
circle-3.5/lib/plrobjs/P-T/
circle-3.5/lib/plrobjs/U-Z/
circle-3.5/lib/plrobjs/ZZZ/
circle-3.5/lib/plrvars/A-E/
circle-3.5/lib/plrvars/F-J/
circle-3.5/lib/plrvars/K-O/
circle-3.5/lib/plrvars/P-T/
circle-3.5/lib/plrvars/U-Z/
circle-3.5/lib/text/hedit/
circle-3.5/lib/text/help/
circle-3.5/log/
circle-3.5/src/doc/
/************************************************************************
 * Generic OLC Library - General / genolc.c			v1.0	*
 * Original author: Levork						*
 * Copyright 1996 by Harvey Gilpin					*
 * Copyright 1997-2001 by George Greer (greerga@circlemud.org)		*
 ************************************************************************/

#define __GENOLC_C__

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "db.h"
#include "handler.h"
#include "comm.h"
#include "shop.h"
#include "oasis.h"
#include "genolc.h"
#include "genwld.h"
#include "genmob.h"
#include "genshp.h"
#include "genzon.h"
#include "genobj.h"
#include "dg_olc.h"
#include "constants.h"
#include "interpreter.h"

int save_config( IDXTYPE nowhere );        /* Exported from cedit.c */
int top_shop_offset = 0;

/*
 * List of zones to be saved.
 */
struct save_list_data *save_list;

/*
 * Structure defining all known save types.
 */
struct {
  int save_type;
  int (*func)(IDXTYPE rnum);
  const char *message;
} save_types[] = {
  { SL_MOB, save_mobiles , "mobile" },
  { SL_OBJ, save_objects, "object" },
  { SL_SHP, save_shops, "shop" },
  { SL_WLD, save_rooms, "room" },
  { SL_ZON, save_zone, "zone" },
  { SL_CFG, save_config, "config" },
  { SL_ACTION, NULL, "social" },
  { -1, NULL, NULL },
};

/* -------------------------------------------------------------------------- */

int genolc_checkstring(struct descriptor_data *d, char *arg)
{
  smash_tilde(arg);
  return TRUE;
}

char *str_udup(const char *txt)
{
  return strdup((txt && *txt) ? txt : "undefined");
}

/*
 * Original use: to be called at shutdown time.
 */
int save_all(void)
{
  while (save_list) {
    if (save_list->type < 0 || save_list->type > SL_MAX) {
      if (save_list->type == SL_ACTION) {
        log("Actions not saved - can not autosave. Use 'aedit save'.");
        save_list = save_list->next;	/* Fatal error, skip this one. */
      } else
        log("SYSERR: GenOLC: Invalid save type %d in save list.\n", save_list->type);
    } else if ((*save_types[save_list->type].func)(real_zone(save_list->zone)) < 0)
      save_list = save_list->next;	/* Fatal error, skip this one. */
  }

  return TRUE;
}

/* -------------------------------------------------------------------------- */

/*
 * NOTE: This changes the buffer passed in.
 */
void strip_cr(char *buffer)
{
  int rpos, wpos;

  if (buffer == NULL)
    return;

  for (rpos = 0, wpos = 0; buffer[rpos]; rpos++) {
    buffer[wpos] = buffer[rpos];
    wpos += (buffer[rpos] != '\r');
  }
  buffer[wpos] = '\0';
}

/* -------------------------------------------------------------------------- */

void copy_ex_descriptions(struct extra_descr_data **to, struct extra_descr_data *from)
{
  struct extra_descr_data *wpos;

  CREATE(*to, struct extra_descr_data, 1);
  wpos = *to;

  for (; from; from = from->next, wpos = wpos->next) {
    wpos->keyword = str_udup(from->keyword);
    wpos->description = str_udup(from->description);
    if (from->next)
      CREATE(wpos->next, struct extra_descr_data, 1);
  }
}

/* -------------------------------------------------------------------------- */

void free_ex_descriptions(struct extra_descr_data *head)
{
  struct extra_descr_data *thised, *next_one;

  if (!head) {
    log("free_ex_descriptions: NULL pointer or NULL data.");
    return;
  }

  for (thised = head; thised; thised = next_one) {
    next_one = thised->next;
    if (thised->keyword)
      free(thised->keyword);
    if (thised->description)
      free(thised->description);
    free(thised);
  }
}

/* -------------------------------------------------------------------------- */

int remove_from_save_list(zone_vnum zone, int type)
{
  struct save_list_data *ritem, *temp;

  for (ritem = save_list; ritem; ritem = ritem->next)
    if (ritem->zone == zone && ritem->type == type)
      break;

  if (ritem == NULL) {
    log("SYSERR: remove_from_save_list: Saved item not found. (%d/%d)", zone, type);
    return FALSE;
  }
  REMOVE_FROM_LIST(ritem, save_list, next);
  free(ritem);
  return TRUE;
}

/* -------------------------------------------------------------------------- */

int add_to_save_list(zone_vnum zone, int type)
{
  struct save_list_data *nitem;
  zone_rnum rznum;
  
  if (type == SL_CFG)
    return FALSE; 
  
  rznum = real_zone(zone);
  if (rznum == NOWHERE || rznum > top_of_zone_table) {
    if (zone != AEDIT_PERMISSION) {
      log("SYSERR: add_to_save_list: Invalid zone number passed. (%d => %d, 0-%d)", zone, rznum, top_of_zone_table);
      return FALSE;
    }
  } 
  
  for (nitem = save_list; nitem; nitem = nitem->next)
    if (nitem->zone == zone && nitem->type == type)
      return FALSE;
  
  CREATE(nitem, struct save_list_data, 1);
  nitem->zone = zone;
  nitem->type = type;
  nitem->next = save_list;
  save_list = nitem;
  return TRUE;
}

/* -------------------------------------------------------------------------- */

int in_save_list(zone_vnum zone, int type)
{
  struct save_list_data *nitem;
  
  for (nitem = save_list; nitem; nitem = nitem->next)
    if (nitem->zone == zone && nitem->type == type)
      return TRUE;
  
  return FALSE;
}

/* -------------------------------------------------------------------------- */

/*
 * Used from do_show(), ideally.
 */
void do_show_save_list(struct char_data *ch)
{
  if (save_list == NULL)
    send_to_char(ch, "All world files are up to date.\r\n");
  else {
    struct save_list_data *item;

    send_to_char(ch, "The following files need saving:\r\n");
    for (item = save_list; item; item = item->next) {
      if (item->type != SL_CFG)
        send_to_char(ch, " - %s data for zone %d.\r\n", save_types[item->type].message, item->zone);
      else
        send_to_char(ch, " - Game configuration data.\r\n");
    }
  }
}

room_vnum genolc_zonep_bottom(struct zone_data *zone)
{
  return zone->bot;
}

/* -------------------------------------------------------------------------- */

zone_vnum genolc_zone_bottom(zone_rnum rznum)
{
  return zone_table[rznum].bot;
}

/* -------------------------------------------------------------------------- */

int sprintascii(char *out, bitvector_t bits)
{
  int i, j = 0;
  /* 32 bits, don't just add letters to try to get more unless your bitvector_t is also as large. */
  char *flags = "abcdefghijklmnopqrstuvwxyzABCDEF";

  for (i = 0; flags[i] != '\0'; i++)
    if (bits & (1 << i))
      out[j++] = flags[i];

  if (j == 0) /* Didn't write anything. */
    out[j++] = '0';

  /* NUL terminate the output string. */
  out[j++] = '\0';
  return j;
}



/* Zone export functions */


int export_save_shops(zone_rnum zrnum);
int export_save_mobiles(zone_rnum rznum);
int export_save_zone(zone_rnum zrnum);
int export_save_objects(zone_rnum zrnum);
int export_save_rooms(zone_rnum zrnum);
int export_save_triggers(zone_rnum zrnum);
int export_mobile_record(mob_vnum mvnum, struct char_data *mob, FILE *fd);
void export_script_save_to_disk(FILE *fp, void *item, int type);
int export_info_file(zone_rnum zrnum);
static int zone_exits = 0;
ACMD(do_export_zone);

ACMD(do_export_zone)
{
  zone_rnum zrnum;
  zone_vnum zvnum;
  char sysbuf[MAX_INPUT_LENGTH];
  char fn[MAX_INPUT_LENGTH], *f;
  void space_to_minus(char *str);
  
  if (IS_NPC(ch) || GET_LEVEL(ch) < LVL_IMPL)
    return;

  skip_spaces(&argument);
  zvnum = atoi(argument);
  zrnum = real_zone(zvnum);
  
  if (zrnum == NOWHERE) {
    send_to_char(ch, "Export which zone?\r\n");
    return;
  }
  
  if (!export_info_file(zrnum))
    send_to_char(ch, "Info file not saved!\r\n");
  if (!export_save_shops(zrnum))
    send_to_char(ch, "Shops not saved!\r\n");
  if (!export_save_mobiles(zrnum))
    send_to_char(ch, "Mobiles not saved!\r\n");
  if (!export_save_objects(zrnum))
    send_to_char(ch, "Objects not saved!\r\n");
  if (!export_save_zone(zrnum))
    send_to_char(ch, "Zone info not saved!\r\n");
  if (!export_save_rooms(zrnum))
    send_to_char(ch, "Rooms not saved!\r\n");
  if (!export_save_triggers(zrnum))
    send_to_char(ch, "Triggers not saved!\r\n");

  send_to_char(ch, "Files saved to /lib/world/export.\r\n");
  snprintf(fn, sizeof(fn), "%d_%s.tgz", zvnum, zone_table[zrnum].name);
  f = fn;
  space_to_minus(f);
  snprintf(sysbuf, sizeof(sysbuf), 
           LIB_ETC "export_script.sh %s &", 
           fn);
  system(sysbuf);
  send_to_char(ch, "Files tar'ed to \"%s\"\r\n", fn);

}

int export_info_file(zone_rnum zrnum)
{
  int i;
  FILE *info_file;
  
  if (!(info_file = fopen("world/export/qq.info", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_info_file : Cannot open file!");
    return FALSE;
  } else if (fprintf(info_file, "CircleMUD v3.1 Area file.\n") < 0) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_info_file: Cannot write to file!");
    fclose(info_file);
    return FALSE;
  }
  
  fprintf(info_file, "The files accompanying this info file contain the area: %s\n", zone_table[zrnum].name);
  fprintf(info_file, "It was written by: %s.\n\n", zone_table[zrnum].builders);
  fprintf(info_file, "The author has given permission to distribute the area, provided credit is\n");
  fprintf(info_file, "given. The area may be modified as you see fit, except you are not allowed to\n");
  fprintf(info_file, "remove the builder name or credits.\n\n");
  fprintf(info_file, "Implementation:\n");
  fprintf(info_file, "1. All the files have been QQ'ed. This means all occurences of the zone number\n");
  fprintf(info_file, "   have been changed to QQ. In other words, if you decide to have this zone as\n");
  fprintf(info_file, "   zone 123, replace all occurences of QQ with 123 and rename the qq.zon file\n");
  fprintf(info_file, "   to 123.zon (etc.). And of course add 123.zon to the respective index file.\n");
  if (zone_exits) {
    fprintf(info_file, "2. Exits out of this zone have been ZZ'd. So all doors leading out have ZZ??\n");
    fprintf(info_file, "   instead of the room vnum (?? are numbers 00 - 99).\n");
    fprintf(info_file, "   In this zone, the exit rooms in question are:\n");
		     
    for (i = genolc_zone_bottom(zrnum); i <= zone_table[zrnum].top; i++) {
      room_rnum rnum = real_room(i);
      struct room_data *room;
      int j;
  
      if (rnum == NOWHERE) 
        continue;
  
      room = &world[rnum];
  
      for (j = 0; j < NUM_OF_DIRS; j++) {
        if (!R_EXIT(room, j))
          continue;
  
        if (R_EXIT(room, j)->to_room == NOWHERE || world[R_EXIT(room, j)->to_room].zone == zrnum)
          continue;
  
        fprintf(info_file, "      Room QQ%02d : Exit to the %s\n",
                           room->number%100, dirs[j]);
      }
    }
    zone_exits = 0;
  } else {
    fprintf(info_file, "2. This area doesn't have any exits _out_ of the zone.\n");
    fprintf(info_file, "   More info on connections in the zone description room.\n");    
  }
  
  fprintf(info_file, "\nAdditional zone information is available in the zone description room QQ00.\n");
  fprintf(info_file, "The Builder's Academy is maintaining and improving these zones. Any typo or\n");
  fprintf(info_file, "bug reports should be reported to rumble@builderacademy.net or stop by The Builder Academy\n");
  fprintf(info_file, "port telnet://builderacademy.net:9091\n");
  fprintf(info_file, "\nAnyone interested in submitting areas or helping improve the existing ones\n");
  fprintf(info_file, "please stop by TBA and talk to Rumble.\n\n");
  fprintf(info_file, "We at The Builder's Academy hope you will enjoy using the area.\n\n");

  fprintf(info_file, "Rumble - Admin of TBA\n");
  fprintf(info_file, "Welcor - Coder of TBA\n");
  fprintf(info_file, "\ntelnet://builderacademy.net:9091/\n");
  
  fclose(info_file);
  return TRUE;
}

int export_save_shops(zone_rnum zrnum)
{
  int i, j, rshop;
  FILE *shop_file;
  struct shop_data *shop;

  if (!(shop_file = fopen("world/export/qq.shp", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_shops : Cannot open shop file!");
    return FALSE;
  } else if (fprintf(shop_file, "CircleMUD v3.0 Shop File~\n") < 0) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_shops: Cannot write to shop file!");
    fclose(shop_file);
    return FALSE;
  }
  /*
   * Search database for shops in this zone.
   */
  for (i = genolc_zone_bottom(zrnum); i <= zone_table[zrnum].top; i++) {
    if ((rshop = real_shop(i)) != NOWHERE) {
      fprintf(shop_file, "#QQ%02d~\n", i%100);
      shop = &shop_index[rshop];

      /*
       * Save the products.
       */
      for (j = 0; S_PRODUCT(shop, j) != NOTHING; j++) {
        if (obj_index[S_PRODUCT(shop, j)].vnum < genolc_zone_bottom(zrnum) ||
            obj_index[S_PRODUCT(shop, j)].vnum > zone_table[zrnum].top)
          continue;
	
	fprintf(shop_file, "QQ%02d\n", obj_index[S_PRODUCT(shop, j)].vnum%100);
      }
      fprintf(shop_file, "-1\n");

      /*
       * Save the rates.
       */
      fprintf(shop_file, "%1.2f\n"
                         "%1.2f\n",
                         S_BUYPROFIT(shop),
                         S_SELLPROFIT(shop));

      /*
       * Save the buy types and namelists.
       */
      for (j = 0;S_BUYTYPE(shop, j) != NOTHING; j++) 
        fprintf(shop_file, "%d%s\n", 
                S_BUYTYPE(shop, j),
		S_BUYWORD(shop, j) ? S_BUYWORD(shop, j) : "");
      fprintf(shop_file, "-1\n");

      /*
       * Save messages'n'stuff.
       * Added some small'n'silly defaults as sanity checks.
       */
      fprintf(shop_file,
	      "%s~\n"
	      "%s~\n"
	      "%s~\n"
	      "%s~\n"
	      "%s~\n"
	      "%s~\n"
	      "%s~\n"
	      "%d\n"
	      "%ld\n"
	      "QQ%02d\n"
	      "%d\n",
	      S_NOITEM1(shop) ? S_NOITEM1(shop) : "%s Ke?!",
	      S_NOITEM2(shop) ? S_NOITEM2(shop) : "%s Ke?!",
	      S_NOBUY(shop) ? S_NOBUY(shop) : "%s Ke?!",
	      S_NOCASH1(shop) ? S_NOCASH1(shop) : "%s Ke?!",
	      S_NOCASH2(shop) ? S_NOCASH2(shop) : "%s Ke?!",
	      S_BUY(shop) ? S_BUY(shop) : "%s Ke?! %d?",
	      S_SELL(shop) ? S_SELL(shop) : "%s Ke?! %d?",
	      S_BROKE_TEMPER(shop),
	      S_BITVECTOR(shop),
	      mob_index[S_KEEPER(shop)].vnum%100,
	      S_NOTRADE(shop)
	      );

      /*
       * Save the rooms.
       */
      for (j = 0;S_ROOM(shop, j) != NOWHERE; j++) {
        if (S_ROOM(shop, j) < genolc_zone_bottom(zrnum) ||
            S_ROOM(shop, j) > zone_table[zrnum].top)
          continue;
      
        fprintf(shop_file, "QQ%02d\n", S_ROOM(shop, j)%100);
      }
      fprintf(shop_file, "-1\n");

      /*
       * Save open/closing times 
       */
      fprintf(shop_file, "%d\n%d\n%d\n%d\n", S_OPEN1(shop), S_CLOSE1(shop),
		S_OPEN2(shop), S_CLOSE2(shop));
    }
  }
  fprintf(shop_file, "$~\n");
  fclose(shop_file);

  return TRUE;
}

int export_save_mobiles(zone_rnum rznum)
{
  FILE *mob_file;
  mob_vnum i;
  mob_rnum rmob;

  if (!(mob_file = fopen("world/export/qq.mob", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_mobiles : Cannot open file!");
    return FALSE;
  }

  for (i = genolc_zone_bottom(rznum); i <= zone_table[rznum].top; i++) {
    if ((rmob = real_mobile(i)) == NOBODY)
      continue;
    check_mobile_strings(&mob_proto[rmob]);
    if (export_mobile_record(i, &mob_proto[rmob], mob_file) < 0)
      log("SYSERR: export_save_mobiles: Error writing mobile #%d.", i);
  }
  fputs("$\n", mob_file);
  fclose(mob_file);

  return TRUE;
}


int export_mobile_record(mob_vnum mvnum, struct char_data *mob, FILE *fd)
{

  char bit1[64]; 
  char bit2[64];
  char ldesc[MAX_STRING_LENGTH];
  char ddesc[MAX_STRING_LENGTH];

  ldesc[MAX_STRING_LENGTH - 1] = '\0';
  ddesc[MAX_STRING_LENGTH - 1] = '\0';
  strip_cr(strncpy(ldesc, GET_LDESC(mob), MAX_STRING_LENGTH - 1));
  strip_cr(strncpy(ddesc, GET_DDESC(mob), MAX_STRING_LENGTH - 1));

  fprintf(fd,	"#QQ%02d\n"
		"%s%c\n"
		"%s%c\n"
		"%s%c\n"
		"%s%c\n",
	mvnum%100,
	GET_ALIAS(mob), STRING_TERMINATOR,
	GET_SDESC(mob), STRING_TERMINATOR,
	ldesc, STRING_TERMINATOR,
	ddesc, STRING_TERMINATOR
  );

  sprintascii(bit1, MOB_FLAGS(mob));
  sprintascii(bit2, AFF_FLAGS(mob));

  fprintf(fd,	"%s %s %d E\n"
		"%d %d %d %dd%d+%d %dd%d+%d\n",
		bit1, bit2, GET_ALIGNMENT(mob),
		GET_LEVEL(mob), 20 - GET_HITROLL(mob), GET_AC(mob) / 10, GET_HIT(mob),
		GET_MANA(mob), GET_MOVE(mob), GET_NDD(mob), GET_SDD(mob),
		GET_DAMROLL(mob)
  );
  fprintf(fd, 	"%d %d\n"
		"%d %d %d\n",
		GET_GOLD(mob), GET_EXP(mob),
		GET_POS(mob), GET_DEFAULT_POS(mob), GET_SEX(mob)
  );

  if (write_mobile_espec(mvnum, mob, fd) < 0)
    log("SYSERR: GenOLC: Error writing E-specs for mobile #%d.", mvnum);

  export_script_save_to_disk(fd, mob, MOB_TRIGGER);

  return TRUE;
}

int export_save_zone(zone_rnum zrnum)
{
  int subcmd;
  FILE *zone_file;
  
  if (!(zone_file = fopen("world/export/qq.zon", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_zone : Cannot open file!");
    return FALSE;
  }

  /*
   * Print zone header to file	
   */
  fprintf(zone_file, "#QQ\n"
                 "%s~\n"
                 "%s~\n"
                 "QQ%02d QQ%02d %d %d\n",
	  (zone_table[zrnum].builders && *zone_table[zrnum].builders)
		? zone_table[zrnum].builders : "None.",
	  (zone_table[zrnum].name && *zone_table[zrnum].name)
		? zone_table[zrnum].name : "undefined",
          genolc_zone_bottom(zrnum)%100,
	  zone_table[zrnum].top%100,
	  zone_table[zrnum].lifespan,
	  zone_table[zrnum].reset_mode
	  );

	/*
	 * Handy Quick Reference Chart for Zone Values.
	 *
	 * Field #1    Field #3   Field #4  Field #5
	 * -------------------------------------------------
	 * M (Mobile)  Mob-Vnum   Wld-Max   Room-Vnum
	 * O (Object)  Obj-Vnum   Wld-Max   Room-Vnum
	 * G (Give)    Obj-Vnum   Wld-Max   Unused
	 * E (Equip)   Obj-Vnum   Wld-Max   EQ-Position
	 * P (Put)     Obj-Vnum   Wld-Max   Target-Obj-Vnum
	 * D (Door)    Room-Vnum  Door-Dir  Door-State
	 * R (Remove)  Room-Vnum  Obj-Vnum  Unused
         * T (Trigger) Trig-type  Trig-Vnum Room-Vnum
         * V (var)     Trig-type  Context   Room-Vnum Varname Value
	 * -------------------------------------------------
	 */

  for (subcmd = 0; ZCMD(zrnum, subcmd).command != 'S'; subcmd++) {
    switch (ZCMD(zrnum, subcmd).command) {
    case 'M':
      fprintf(zone_file, "M %d QQ%02d %d QQ%02d \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		mob_index[ZCMD(zrnum, subcmd).arg1].vnum%100,
		ZCMD(zrnum, subcmd).arg2,
		world[ZCMD(zrnum, subcmd).arg3].number%100,
		mob_proto[ZCMD(zrnum, subcmd).arg1].player.short_descr);
      break;
    case 'O':
      fprintf(zone_file, "O %d QQ%02d %d QQ%02d \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		obj_index[ZCMD(zrnum, subcmd).arg1].vnum%100,
		ZCMD(zrnum, subcmd).arg2,
		world[ZCMD(zrnum, subcmd).arg3].number%100,
		obj_proto[ZCMD(zrnum, subcmd).arg1].short_description);
      break;
    case 'G':
      fprintf(zone_file, "G %d QQ%02d %d -1 \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
                obj_index[ZCMD(zrnum, subcmd).arg1].vnum%100,
                ZCMD(zrnum, subcmd).arg2,
                obj_proto[ZCMD(zrnum, subcmd).arg1].short_description);
      break;
    case 'E':
      fprintf(zone_file, "E %d QQ%02d %d %d \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		 obj_index[ZCMD(zrnum, subcmd).arg1].vnum%100,
		 ZCMD(zrnum, subcmd).arg2,
		 ZCMD(zrnum, subcmd).arg3,
		 obj_proto[ZCMD(zrnum, subcmd).arg1].short_description);
      break;
    case 'P':
      fprintf(zone_file, "P %d QQ%02d %d QQ%02d \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		obj_index[ZCMD(zrnum, subcmd).arg1].vnum%100,
		ZCMD(zrnum, subcmd).arg2,
		obj_index[ZCMD(zrnum, subcmd).arg3].vnum%100,
		obj_proto[ZCMD(zrnum, subcmd).arg1].short_description);
      break;
    case 'D':
      fprintf(zone_file, "D %d QQ%02d %d %d \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		world[ZCMD(zrnum, subcmd).arg1].number%100,
		ZCMD(zrnum, subcmd).arg2,
		ZCMD(zrnum, subcmd).arg3,
		world[ZCMD(zrnum, subcmd).arg1].name);
      break;
    case 'R':
      fprintf(zone_file, "R %d QQ%02d QQ%02d -1 \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		world[ZCMD(zrnum, subcmd).arg1].number%100,
		obj_index[ZCMD(zrnum, subcmd).arg2].vnum%100,
		obj_proto[ZCMD(zrnum, subcmd).arg2].short_description);
      break;
    case 'T':
      fprintf(zone_file, "T %d %d QQ%02d QQ%02d \t(%s)\n",
		ZCMD(zrnum, subcmd).if_flag,
		ZCMD(zrnum, subcmd).arg1,
		trig_index[ZCMD(zrnum, subcmd).arg2]->vnum%100,
		world[ZCMD(zrnum, subcmd).arg3].number%100,
		GET_TRIG_NAME(trig_index[ZCMD(zrnum, subcmd).arg2]->proto));
      break;
    case 'V':
      fprintf(zone_file, "V %d %d %d QQ%02d %s %s\n",
              ZCMD(zrnum, subcmd).if_flag,
              ZCMD(zrnum, subcmd).arg1,
              ZCMD(zrnum, subcmd).arg2,
              world[ZCMD(zrnum, subcmd).arg3].number%100, 
              ZCMD(zrnum, subcmd).sarg1,
              ZCMD(zrnum, subcmd).sarg2);
      break;
    case '*':
      /*
       * Invalid commands are replaced with '*' - Ignore them.
       */
      continue;
    default:
      mudlog(BRF, LVL_BUILDER, TRUE, "SYSERR: export_save_zone(): Unknown cmd '%c' - NOT saving", ZCMD(zrnum, subcmd).command);
      continue;
    }
  }
  fputs("S\n$\n", zone_file);
  fclose(zone_file);
 
  return TRUE;
}

int export_save_objects(zone_rnum zrnum)
{
  char buf[MAX_STRING_LENGTH], bit1[64], bit2[64];
  obj_rnum ornum;
  obj_vnum ovnum;
  int i;
  FILE *obj_file;
  struct obj_data *obj;
  struct extra_descr_data *ex_desc;

  if (!(obj_file = fopen("world/export/qq.obj", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_objects : Cannot open file!");
    return FALSE;
  }
  /*
   * Start running through all objects in this zone.
   */
  for (ovnum = genolc_zone_bottom(zrnum); ovnum <= zone_table[zrnum].top; ovnum++) {
    if ((ornum = real_object(ovnum)) != NOTHING) {
      if ((obj = &obj_proto[ornum])->action_description) {
	strncpy(buf, obj->action_description, sizeof(buf) - 1);
	strip_cr(buf);
      } else
	*buf = '\0';

      fprintf(obj_file,
	      "#QQ%02d\n"
	      "%s~\n"
	      "%s~\n"
	      "%s~\n"
	      "%s~\n",

	      GET_OBJ_VNUM(obj)%100,
	      (obj->name && *obj->name) ? obj->name : "undefined",
	      (obj->short_description && *obj->short_description) ? obj->short_description : "undefined",
	      (obj->description && *obj->description) ?	obj->description : "undefined",
	      buf);

      sprintascii(buf, GET_OBJ_EXTRA(obj));
      sprintascii(bit1, GET_OBJ_WEAR(obj));
      sprintascii(bit2, GET_OBJ_PERM(obj));

      fprintf(obj_file,
	      "%d %s %s %s\n", 
	      GET_OBJ_TYPE(obj), buf, bit1, bit2);

      if (GET_OBJ_TYPE(obj) != ITEM_CONTAINER)
        fprintf(obj_file,
                "%d %d %d %d\n",
	        GET_OBJ_VAL(obj, 0), GET_OBJ_VAL(obj, 1), GET_OBJ_VAL(obj, 2), GET_OBJ_VAL(obj, 3));
      else
        fprintf(obj_file,
                "%d %d %s%02d %d\n",
	        GET_OBJ_VAL(obj, 0),
	        GET_OBJ_VAL(obj, 1),
	        GET_OBJ_VAL(obj, 2) == -1 ? "" : "QQ", /* key */
	        GET_OBJ_VAL(obj, 2) == -1 ? -1 : GET_OBJ_VAL(obj, 2)%100,
	        GET_OBJ_VAL(obj, 3));
      
      fprintf(obj_file,
	      "%d %d %d %d\n",	      
	      GET_OBJ_WEIGHT(obj), GET_OBJ_COST(obj), GET_OBJ_RENT(obj), GET_OBJ_LEVEL(obj));

      /*
       * Do we have script(s) attached ? 
       */
      export_script_save_to_disk(obj_file, obj, OBJ_TRIGGER);
      
      /*
       * Do we have extra descriptions? 
       */
      if (obj->ex_description) {	/* Yes, save them too. */
	for (ex_desc = obj->ex_description; ex_desc; ex_desc = ex_desc->next) {
	  /*
	   * Sanity check to prevent nasty protection faults.
	   */
	  if (!ex_desc->keyword || !ex_desc->description || !*ex_desc->keyword || !*ex_desc->description) {
	    mudlog(BRF, LVL_IMMORT, TRUE, "SYSERR: OLC: export_save_objects: Corrupt ex_desc!");
	    continue;
	  }
	  strncpy(buf, ex_desc->description, sizeof(buf) - 1);
	  strip_cr(buf);
	  fprintf(obj_file, "E\n"
		  "%s~\n"
		  "%s~\n", ex_desc->keyword, buf);
	}
      }
      /*
       * Do we have affects? 
       */
      for (i = 0; i < MAX_OBJ_AFFECT; i++)
	if (obj->affected[i].modifier)
	  fprintf(obj_file, "A\n"
		            "%d %d\n", 
		  obj->affected[i].location,
		  obj->affected[i].modifier);
    }
  }

  /*
   * Write the final line, close the file.
   */
  fprintf(obj_file, "$~\n");
  fclose(obj_file);

  return TRUE;
}

int export_save_rooms(zone_rnum zrnum)
{
  int i;
  struct room_data *room;
  FILE *room_file;
  char buf[MAX_STRING_LENGTH];
  char buf1[MAX_STRING_LENGTH];
  char bit[64];

  if (!(room_file = fopen("world/export/qq.wld", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_rooms : Cannot open file!");
    return FALSE;
  }

  for (i = genolc_zone_bottom(zrnum); i <= zone_table[zrnum].top; i++) {
    room_rnum rnum;

    if ((rnum = real_room(i)) != NOWHERE) {
      int j;

      room = &world[rnum];

      /*
       * Copy the description and strip off trailing newlines.
       */
      strncpy(buf, room->description ? room->description : "Empty room.", sizeof(buf)-1 );
      strip_cr(buf);

      /*
       * Save the numeric and string section of the file.
       */
      sprintascii(bit, room->room_flags);
      fprintf(room_file, 	"#QQ%02d\n"
			"%s%c\n"
			"%s%c\n"
			"QQ %s %d\n",
		room->number%100,
		room->name ? room->name : "Untitled", STRING_TERMINATOR,
		buf, STRING_TERMINATOR,
		bit, room->sector_type
      );

      /*
       * Now you write out the exits for the room.
       */
      for (j = 0; j < NUM_OF_DIRS; j++) {
	if (R_EXIT(room, j)) {
	  int dflag;
	  if (R_EXIT(room, j)->general_description) {
	    strncpy(buf, R_EXIT(room, j)->general_description, sizeof(buf)-1);
	    strip_cr(buf);
	  } else
	    *buf = '\0';

	  /*
	   * Figure out door flag.
	   */
	  if (IS_SET(R_EXIT(room, j)->exit_info, EX_ISDOOR)) {
	    if (IS_SET(R_EXIT(room, j)->exit_info, EX_PICKPROOF))
	      dflag = 2;
	    else
	      dflag = 1;
	  } else
	    dflag = 0;

	  if (R_EXIT(room, j)->keyword)
	    strncpy(buf1, R_EXIT(room, j)->keyword, sizeof(buf1)-1 );
	  else
	    *buf1 = '\0';

	  /*
	   * Now write the exit to the file.
	   */
          if (R_EXIT(room, j)->to_room == NOWHERE || world[R_EXIT(room, j)->to_room].zone == zrnum)
	    fprintf(room_file,"D%d\n"
		              "%s~\n"
			      "%s~\n"
        		      "%d %s%02d %s%02d\n",
			      j,
			      buf,
			      buf1,
			      dflag,
			      R_EXIT(room, j)->key == NOTHING ? "" : "QQ",
			      R_EXIT(room, j)->key == NOTHING ? -1 : R_EXIT(room, j)->key % 100 ,
			      R_EXIT(room, j)->to_room == NOTHING ? "" : "QQ", 
			      R_EXIT(room, j)->to_room != NOTHING ? (world[R_EXIT(room, j)->to_room].number%100) : -1);
          else {
	    fprintf(room_file,"D%d\n"
		              "%s~\n"
			      "%s~\n"
        		      "%d %s%02d ZZ%02d\n",
			      j,
			      buf,
			      buf1,
			      dflag,
			      R_EXIT(room, j)->key == NOTHING ? "" : "QQ",
			      R_EXIT(room, j)->key == NOTHING ? -1 : R_EXIT(room, j)->key % 100 ,
			      world[R_EXIT(room, j)->to_room].number%100);
            zone_exits++;
          }
	}
      }

      if (room->ex_description) {
        struct extra_descr_data *xdesc;

	for (xdesc = room->ex_description; xdesc; xdesc = xdesc->next) {
	  strncpy(buf, xdesc->description, sizeof(buf));
	  strip_cr(buf);
	  fprintf(room_file,	"E\n"
			"%s~\n"
			"%s~\n", xdesc->keyword, buf);
	}
      }
      fprintf(room_file, "S\n");
      export_script_save_to_disk(room_file, room, WLD_TRIGGER);
    }
  }

  /*
   * Write the final line and close it.
   */
  fprintf(room_file, "$~\n");
  fclose(room_file);

  return TRUE;
}

void export_script_save_to_disk(FILE *fp, void *item, int type)
{
  struct trig_proto_list *t;

  if (type==MOB_TRIGGER)
    t = ((struct char_data *)item)->proto_script;
  else if (type==OBJ_TRIGGER)
    t = ((struct obj_data *)item)->proto_script;
  else if (type==WLD_TRIGGER)
    t = ((struct room_data *)item)->proto_script;
  else {
    log("SYSERR: Invalid type passed to export_script_save_to_disk()");
    return;
  }

  while (t)
  {
    fprintf(fp, "T QQ%02d\n", t->vnum%100);
    t = t->next;
  }
}

/* save the zone's triggers to internal memory and to disk */
int export_save_triggers(zone_rnum zrnum)
{
  int i;
  trig_data *trig;
  struct cmdlist_element *cmd;
  FILE *trig_file;
  char bitBuf[MAX_INPUT_LENGTH];

  if (!(trig_file = fopen("world/export/qq.trg", "w"))) {
    mudlog(BRF, LVL_GOD, TRUE, "SYSERR: export_save_triggers : Cannot open file!");
    return FALSE;
  }
        
  for (i = genolc_zone_bottom(zrnum); i <= zone_table[zrnum].top; i++) {
    trig_rnum rnum;

    if ((rnum = real_trigger(i)) != NOTHING) {
      trig = trig_index[rnum]->proto;

      fprintf(trig_file, "#QQ%02d\n", i%100);

      sprintascii(bitBuf, GET_TRIG_TYPE(trig));
      fprintf(trig_file,      "%s%c\n"
                              "%d %s %d\n"
                              "%s%c\n",
           (GET_TRIG_NAME(trig)) ? (GET_TRIG_NAME(trig)) : "unknown trigger", STRING_TERMINATOR,
           trig->attach_type,
           *bitBuf ? bitBuf : "0", GET_TRIG_NARG(trig),
           GET_TRIG_ARG(trig) ? GET_TRIG_ARG(trig) : "", STRING_TERMINATOR);
                
      fprintf(trig_file, "* This trigger has been exported 'as is'. This means that vnums\n"
                         "* in this file are not changed, and will have to be edited by hand.\n"
                         "* This zone was number %d on The Builder Academy, so you\n"
                         "* should be looking for %dxx, where xx is 00-99.\n",
                         zone_table[zrnum].number, zone_table[zrnum].number);
        for (cmd = trig->cmdlist; cmd; cmd = cmd->next) {
          fprintf(trig_file, "%s\n", cmd->cmd);
        }
      fprintf(trig_file, "%c\n", STRING_TERMINATOR);
    }
  }
        
  fprintf(trig_file, "$%c\n", STRING_TERMINATOR);
  fclose(trig_file);
  return TRUE;
}