/* DFQEDIT.C - Copyright (c) 1996 - Dave Humphrey - aj589@freenet.carleton.ca
 * v0.10 Beta (12 December 1996)
 * Editor of the QRC and QBN files...hopefully
 */

	/* Standard 'C' Includes */
#include <stdlib.h>
#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <dos.h>
#include <direct.h>
#include <dir.h>
#include <ctype.h>
#include <process.h>
#include <alloc.h>
#include <time.h>

	/* User Defined Includes */
#include "genutil.h"
#include "fileutil.h"
#include "mouse.h"
#include "keyasm.h"
#include "keybrd.h"
#include "buttons.h"
#include "util.h"

	/* DFQEdit Specific Includes */
#include "edit.h"
#include "scrlbar.h"
#include "listbox.h"
#include "filelist.h"
#include "textfld.h"
#include "dragbox.h"
#include "dfqedit.h"

	/* String Descriptions of Program */
char dfqedit_version[] = VERSION;
char dfqedit_title[] = "DFQEDIT.C v%s - Dave Humphrey\n";

	/* Location of various files...from CFG file... */
char quest_path[MAX_STRING_LENGTH + 1] = "";
char backup_path[MAX_STRING_LENGTH + 1] = "";

	/* For the initial available memory */
long int initial_far_heapsize;

	/* Define a drag-type box for selecting guilds */
LIST_BOX guild_list (GUILD_X, GUILD_Y, GUILD_WIDTH, 8, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );

	/* Define drag-type box for selecting minimum rank for quest */
LIST_BOX rank_list (RANK_X, RANK_Y, RANK_WIDTH, 10, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );

	/* Define the drag-box for selecting the pc-status required for quest */
LIST_BOX pc_status_list (PC_STATUS_X, PC_STATUS_Y, PC_STATUS_WIDTH, 4, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );

	/* Define the drag-box for selecting how the quest is given to PC */
LIST_BOX qgiven_list (QGIVEN_X, QGIVEN_Y, QGIVEN_WIDTH, 4, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );

	/* Define the drag-boxs for qbn-editing mode */
LIST_BOX reward_type_list (REWARD_TYPE_X, REWARD_TYPE_Y, REWARD_TYPE_WIDTH, 4, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX reward_list (REWARD_X, REWARD_Y, REWARD_WIDTH, 10, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX msg_type_list (MSG_TYPE_X, MSG_TYPE_Y, MSG_TYPE_WIDTH, 10, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX find_msg_list (FIND_MSG_X, FIND_MSG_Y, FIND_MSG_WIDTH, FIND_MSG_HEIGHT, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, BLACK, LIGHTGREEN );
LIST_BOX gender_list (GENDER_X, GENDER_Y, 16, 3, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
BUTTON_ARRAY find_msg_buttons;

	/* Many lists for the section[4] qbn data */
LIST_BOX gen_loc_list (LOC_X, LOC_Y, 14, 3, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX loc_list (LOC_X, LOC_Y + 2, 18, 8, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX sec41_list (LOC_X, LOC_Y + 16, 18, 8, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX sec42_list (LOC_X, LOC_Y + 18, 18, 3, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX sec43_list (LOC_X, LOC_Y + 20, 16, 3, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );

	/* Section 7 List */
LIST_BOX mob_list (MOB_X, MOB_Y, 18, 8, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );
LIST_BOX sec71_list (MOB_X, MOB_Y + 6, 16, 8, DRAGBOX_TEXT_COLOR, DRAGBOX_BACK_COLOR, DRAGBOX_BOLDTEXT_COLOR, DRAGBOX_BOLDBACK_COLOR );

	/* Data for all buttons/fields/lists on the screen */
DRAG_ARRAY drag_buttons;
DRAG_ARRAY section_drag[11];
BUTTON_ARRAY section_button[11];
TEXT_ARRAY section_field[11];

	/* Define the main screen buttons, load, save, edit */
BUTTON_ARRAY main_buttons;

	/* Option Buttons for editting QText */
BUTTON_ARRAY qtext_buttons;

	/* Buttons for the qbn edit screen */
BUTTON_ARRAY qbn_buttons;

	/* Holds all the data loaded from QBN file */
QBN_DATA qbn_data;

	/* Define all the quest text types for displaying/editting */
QUEST_TEXT_ARRAY quest_texts;

	/* Holds all the QRC data */
QRC_DATA qrc_data;

	/* Description of quest text types */
QTEXT_DESC_TYPE qtext_desc[] = {
  { "Description", 	0x3E8 },
  { "Unaccepted", 	0x3E9 },
  { "Accepted", 	0x3EA },
  { "Failed Quest", 	0x3EB },
  { "Successful", 	0x3EC },
  { "Rumours During",	0x3ED },
  { "Rumours Success",	0x3EE },
  { "Rumours Failed", 	0x3EF },
  { "Success Greeting",	0x3F0 },
  { "Failed Greeting", 	0x3F1 },
  { "Log Entry", 	0x3F2 },
  { "End", 		0xFFFF},
  { "", 		0x000 }
 };


	/* Quest Filenames and current save/load status */
char quest_filename[MAX_STRING_LENGTH];
char new_quest_filename[MAX_STRING_LENGTH];
boolean quest_loaded = FALSE;
boolean quest_saved = FALSE;

	/* Editting modes */
boolean qrc_screen = TRUE;	/* Which screen mode are we in? */
int qbn_mode = 0;		/* Which screen mode in the qbn screen are we in? */

	/* Array indices */
int PC_STATUS_INDEX = 0;
int GUILD_INDEX = 0;
int QGIVEN_INDEX = 0;
int RANK_INDEX = 0;
int REWARD_TYPE_INDEX = 0;
int REWARD_INDEX = 0;
int MSG_TYPE_INDEX[11];
int MSGID1_INDEX[11];
int MSGID2_INDEX[11];
int NUMBER1_INDEX[11];
int NUMBER2_INDEX[11];
int NUMBER3_INDEX[11];
int NUMBER4_INDEX[11];
int GENDER_INDEX;
int GEN_LOC_INDEX;
int LOC_INDEX;
int MOB_INDEX;

	/* What QBN object in each section is being editted/displayed currently */
int current_section[11];

	/* Maximum sizes of the QBN section arrays */
const int MAX_QBN_ARRAY[11] = {
  MAX_QBN0_ARRAY,
  MAX_QBN1_ARRAY,
  MAX_QBN2_ARRAY,
  MAX_QBN3_ARRAY,
  MAX_QBN4_ARRAY,
  MAX_QBN5_ARRAY,
  MAX_QBN6_ARRAY,
  MAX_QBN7_ARRAY,
  MAX_QBN8_ARRAY,
  MAX_QBN9_ARRAY,
  MAX_QBN10_ARRAY
 };


/*========== Displays information about Q-Edit and Environment ============*/
void click_about(void) {
  int x = (80 - ABOUT_WIDTH)/2 + 3;	/* Where to print stuff */
  int y = (50 - ABOUT_HEIGHT)/2 + 3;
  struct date current_date;
  struct time current_time;

  char months[12][10] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };

  textcolor (BIGWIN_BORD_COLOR);
  textbackground (BIGWIN_BACK_COLOR);

  draw_textbox_center (ABOUT_WIDTH, ABOUT_HEIGHT, "About DFQEdit", BIGWIN_TEXT_COLOR);

  gotoxy (x, y);
  textcolor (BLUE);
  gotoxy (x, y + 1);
  cprintf ("DFQEdit v%s - Copyright (c) 1996 - by Dave Humphrey", VERSION);

  getdate (&current_date);
  gettime (&current_time);

  textcolor (BIGWIN_TEXT_COLOR);
  gotoxy (ABOUT_WIDTH + x - 30, y + 3);
  cprintf ("%2d:%02d - %2d %s %4d", (int) current_time.ti_hour, (int)current_time.ti_min,
	   (int) current_date.da_day, months[current_date.da_mon - 1], current_date.da_year);

  gotoxy (x, y + 5);
  cprintf ("TES: Daggerfall Quest Editor.  Can currently load and save QRC");
  gotoxy (x, y + 6);
  cprintf ("files which contain all quest texts.");

  gotoxy (x, y + 9);
  textcolor (BLUE);
  cprintf ("CREDITS");
  gotoxy (x, y + 10);
  textcolor (BIGWIN_TEXT_COLOR);
  cprintf ("    Peggy S Hanks (df4@juno.com)");
  gotoxy (x, y + 11);
  cprintf ("    Lord Phoenix (gozer@esoterica.pt)");
  gotoxy (x, y + 12);
  cprintf ("    INT9 (IRQ1) keyboard handler #9 by Patch (hamell@cs.pdx.edu)");

  gotoxy (x, y + 15);
  textcolor (BLUE);
  cprintf ("SYSTEM");
  gotoxy (x, y + 16);
  textcolor (BIGWIN_TEXT_COLOR);
  cprintf ("        Initial Memory: %ld bytes", initial_far_heapsize);
  gotoxy (x, y + 17);
  cprintf ("     Current Available: %ld bytes", farcoreleft());
  gotoxy (x, y + 18);
  cprintf ("     Current Status of Heap: ");

  switch (farheapcheck()){
    case _HEAPCORRUPT: cprintf ("Corrupt Heap - Quit and Reboot!\n"); break;
    case _HEAPOK: cprintf ("Heap is OK\n"); break;
    default: cprintf ("No Heap\n"); break;
   };

  gotoxy (x, y + 19);

  if (MouseInstalled) {	/* Get Mouse information */
    cprintf ("     Mouse detected with %d buttons", MouseButtonCount);
   }
  else
    cprintf ("     No Mouse present!");

  get_ok_button (y + ABOUT_HEIGHT - 7); /* Get input key/mouse */
 }
/*========== End of procedure click_about() ===============================*/


/*========== When exit button is pressed - Display Exit Window ============*/
void click_exit(void) {
  if (get_yn_choice(EXIT_WIDTH, EXIT_HEIGHT, "Exit DFQEdit", "Really Exit from DFQEdit"))
    exit(TRUE);	/* If 'Y'...exit program */
 }
/*========== End of procedure click_exit() ================================*/


/*========== Clears all contents of Current Quest =========================*/
void click_new(void) {
  if (get_yn_choice(EXIT_WIDTH, EXIT_HEIGHT, "New Quest", "Clear Current Quest"))
    new_quest();	/* If 'Y'...clear all variables */
 }
/*========== End of procedure click_new() =================================*/


/*========== Attempts to Load a QRC/QBN file set ==========================*/
void click_load(void) {
  new_quest_filename[0] = 0;	/* Reset string to nothing */

	/* Input filename */
  if (file_dialogue(&new_quest_filename[0], &quest_path[0], "Load QRC", "Load", "*.qrc")) {
    parse_quest_filename(&new_quest_filename[0]);	/* Make sure no extension... */
    new_quest();    /* Make sure we clear everything out first */

    if (qbn_data.load (new_quest_filename) && qrc_data.load (new_quest_filename)) {
      quest_loaded = TRUE;
      strcpy (quest_filename, new_quest_filename);
     } /* End of if loaded qbn... */
    else {
      error_box ("ERROR: Load Quest", "Could not Load file '%s' (QBN/QRC)!", new_quest_filename);
     }
   }
 }
/*========== End of procedure click_load() ================================*/


/*========== Attempts to Save a QRC/QBN file set ==========================*/
void click_save(void) {

  if (!quest_loaded) quest_filename[0] = 0;	/* Reset string to nothing */

		/* Input filename */
  if (file_dialogue(&new_quest_filename[0], &quest_path[0], "Save QRC", "Save", "*.qrc")) {
    parse_quest_filename(&new_quest_filename[0]);	//Make sure no extension...

    if (qrc_data.save (new_quest_filename)) {
      qbn_data.save (new_quest_filename);
      _fstrcpy (quest_filename, new_quest_filename);
      quest_loaded = TRUE;
     }
    else {
      error_box ("ERROR: Save Quest", "Could not Save file '%s'!", new_quest_filename);
     }
   }
 }
/*========== End of procedure click_save() ================================*/


/*========== Converts the edit text into a char * =========================*/
boolean convert_edit_list (char far **text) {
  EDIT_TYPE far *line;

  if (*text) delete *text;

  if (get_editsize() <= 1) { //No strings...
    *text = NULL;
    return (FALSE);
   }

  if (get_editsize() > 64000l || !(*text = new far char[(unsigned int) get_editsize() + 24]))
    bug (MEM_ERR_MSG, "convert_edit_list() - **text (%d)", get_editsize() + 24);

  line = edit_start;

  **text = 0;	/* Make sure string is initially empty */

  while (line) {	/* Go through edit dllist */
    _fstrcat (*text, line->data);

	/* Figure out what type of line, center or left justified */
    if (_fstrlen(*text) > 0) {
      if (*(*text + _fstrlen(*text) - 1) == TEXT_CR_CENTER)
	*(*text + _fstrlen(*text) - 1) = CR_CENTER;
      else if (*(*text + _fstrlen(*text) - 1) == TEXT_CR_LEFT)
	*(*text + _fstrlen(*text) - 1) = CR_LEFT;
      else if (*(*text + _fstrlen(*text) - 1) == '~') {
		/* Do Nothing */
	}
      else
	chrcat (*text, CR_LEFT);
     }

    line = line->next;
   } /* End of while loop */

  chrcat (*text, 0);	/* Terminate the string */
  return(TRUE);
 }
/*========== End of Procedure convert_edit_list() =========================*/


/*========== Converts a char * data of QText into an Edit Line LList ======*/
void convert_qtext (char far *text) {
  char buffer[MAX_STRING_LENGTH + 1];

  delete_all_editlines();	/* Make sure we clear the edit file */

  buffer[0] = 0;	/* Terminate string, 0 length */

  while (*text != 0) { 	/* Continue until end of string */
    if ((unsigned char) *text == CR_CENTER) {		/* A CR signalling end of centered text line */
      chrcat (&buffer[0], TEXT_CR_CENTER);
      create_new_end (buffer);	/* Add line to end of llist */
      buffer[0] = 0;	/* Reset string */
     }
    else if ((unsigned char) *text == CR_LEFT) {	/* A CR signalling end of left justified text line */
      chrcat (&buffer[0], TEXT_CR_LEFT);
      create_new_end (buffer);	//Add line to end of llist
      buffer[0] = 0;	//Reset string
     }
    else if ((unsigned char) *text == '~') {		/* End of one text section */
      chrcat (&buffer[0], *text);
      create_new_end (buffer);
      buffer[0] = 0;
     }
    else { /* Just add to buffer */
      chrcat(&buffer[0], *text);

      if (_fstrlen(buffer) >= max_length) {	/* Make sure we don't exceed line length */
	create_new_end(buffer);	/*  Add line to end of llist */
	buffer[0] = 0;	/* Reset string */
       }
      else if (_fstrlen(buffer) >= max_length - 7 && *text == ' ') {
	create_new_end(buffer);	/* Add line to end of llist */
	buffer[0] = 0;	/* Reset string */
       }
     }

    text++;
   } /* End of while loop */

  if (_fstrlen(buffer) > 0)  	/* Make sure we add last line if it exists */
    create_new_end(buffer);

  edit_line = edit_start;	/* Move to beginning of edit text */
 }
/*========== End of procedure convert_qtext() =============================*/


/*========== Computes the Base of a New Quest Filename based on Types =====*/
void determine_new_quest_filename (char far *string) {
  *string = (char) drag_buttons.buttons[GUILD_INDEX].number;
  string++;

  *string = '0';
  string++;

  *string = (char) drag_buttons.buttons[PC_STATUS_INDEX].number;
  string++;

  *string = (char) drag_buttons.buttons[RANK_INDEX].number + '0';
  string++;

  *string = '0';
  string++;

  *string = (char) drag_buttons.buttons[QGIVEN_INDEX].number;
  string++;

  *string = 0;	/* Terminate string */
 }
/*========== End of procedure determine_new_quest_filename() ==============*/


/*========== Displays the Filenames at top of Screen ======================*/
void draw_filenames (void) {
  int orig_textattr;
  char far *temp_ptr;

  orig_textattr = get_textattr ();

	/* Set proper colors and clear the screen */
  textbackground (BACK_COLOR);
  textcolor (BORDER_COLOR);

	/* Based on current quest settings...compute what the filename would be */
  determine_new_quest_filename (&new_quest_filename[0]);

  if (!quest_loaded) _fstrcpy (quest_filename, "<none>");

	/* Strip the path, if any off of filename... (for length) */
  if ((temp_ptr = _fstrrchr(quest_filename, '\\')) == NULL)
    temp_ptr = &quest_filename[0];

  gotoxy ((80 - _fstrlen(temp_ptr) - _fstrlen(new_quest_filename) - 8)/2, 1);
  cprintf ("| %s / ", temp_ptr);

	/* Redraw the new filename in another color */
  textcolor (LIGHTGREEN);
  cprintf ("%s ", new_quest_filename);
  textcolor (WHITE);
  cprintf ("|");

  textattr (orig_textattr);
 }
/*========== End of procedure draw_filenames() ============================*/


/*========== Draws the Quest Edit Text window on Screen ===================*/
int draw_qtext_window (const char *string) {
  char far *save_screen;	/* For saving the screen background */
  boolean done = FALSE;	/* Loop Counter */
  int ret;	/* Return Value */

  if (!(save_screen = new far char[(QTEXT_WIDTH + 2) * (QTEXT_HEIGHT + 2) * 2 + 2]))
    bug (MEM_ERR_MSG, "draw_qtext_window() - *save_screen (%d)", (QTEXT_WIDTH + 2) * (QTEXT_HEIGHT  +2) * 2 + 2);

  hide_mouse ();

	/* Save background */
  gettext (40 - QTEXT_WIDTH/2, 25 - QTEXT_HEIGHT/2,
	   40 + QTEXT_WIDTH/2, 25 + QTEXT_HEIGHT/2, save_screen);

  textcolor (BIGWIN_BORD_COLOR);
  textbackground (BIGWIN_BACK_COLOR);
  draw_textbox_center (QTEXT_WIDTH, QTEXT_HEIGHT, string, BIGWIN_TEXT_COLOR);

  textcolor (BIGWIN_TEXT_COLOR);
  cprintf_cent (-2, "You may Edit or Delete this Quest Text [E/D]?");
  textcolor (BUTTON_BORD_COLOR);
  textbackground (BUTTON_BACK_COLOR);

	/* Draw the buttons */
  qtext_buttons.draw ();

  show_mouse();
  delay(KEY_DELAY);

  do {
	/* Update mouse status */
    switch (qtext_buttons.check (MOUSEX, MOUSEY, get_mouse_event (LEFT_BUTTON)) ) {
      case 0: ret = 0;	/* Edit */
	      done = TRUE;
	      break;
      case 1: ret = 1;	/* Delete */
	      done = TRUE;
	      break;
      case 2: ret = -1; /* Esc */
	      done = TRUE;
	      break;
     } /* End of switch which button pressed */

    GetKey();	/* Get keyboard status */

    if (key_press[SCAN_E]) {
      delay (KEY_DELAY);
      ret = 0;
      done = TRUE;
     }
    else if (key_press[SCAN_D]) {
      delay (KEY_DELAY);
      ret = 1;
      done = TRUE;
     }
    else if (get_esc_state()) {
      ret = -1;
      done = TRUE;
     }

  } while (!done);

  hide_mouse ();

	/* Restore background */
  puttext (40 - QTEXT_WIDTH/2, 25 - QTEXT_HEIGHT/2,
	   40 + QTEXT_WIDTH/2, 25 + QTEXT_HEIGHT/2, save_screen);

  show_mouse ();
  delete save_screen;
  return (ret);
 }
/*========== End of procedure draw_qtext_window() =========================*/


/*========== Draws the entire screen ======================================*/
void draw_screen(void) {
  _setcursortype (_NOCURSOR);	/* Don't want the cursor appearing */
  textcolor (BORDER_COLOR);
  textbackground (BACK_COLOR);

	/* Draw the main window box */
  draw_textbox (1, 1, 80, 50, NULL, TEXT_COLOR);

	/* Display the quest filenames */
  draw_filenames ();

	/* Display the main buttons */
  main_buttons.draw ();

  if (qrc_screen) {
	/* Display what drag buttons titles */
    textcolor (TITLE_COLOR);
    textbackground (BACK_COLOR);
    drag_buttons.draw_titles();

	/* Display the current values of the filename lists */
    drag_buttons.draw_texts();

	/* Draw all qtext fields */
    quest_texts.draw ();

	/* Draws all the little nice arrows for the drawboxes */
    drag_buttons.draw_arrows ();
   } /* End of if qrc_screen */
  else {
	/* Draw the QBN edit single-border box */
    textcolor (LIGHTGRAY);
    draw_sing_textbox (QBN_BOX_X, QBN_BOX_Y, QBN_BOX_X + QBN_BOX_WIDTH, QBN_BOX_Y + QBN_BOX_HEIGHT, NULL, LIGHTGRAY);

    qbn_buttons.draw ();
    section_button[qbn_mode].draw ();
    section_field[qbn_mode].draw_titles();
    draw_qbn_screen();
   } /* End of if qbn screen */

	/* Delete the temp string buffer and reshow the mouse cursor */
  show_mouse ();
 }
/*========== End of procedure draw_screen() ===============================*/


/*========== Draws only the QBN data screen ===============================*/
void draw_qbn_screen (void) {
  int i;

	/* Make sure current_section[] is set correctly */
  if (qbn_data.section_size[qbn_mode] > 0 && current_section[qbn_mode] == 0)
    current_section[qbn_mode] = 1;
  else if (qbn_data.section_size[qbn_mode] == 0)
    current_section[qbn_mode] = 0;

	/* Get the data from the qbn data structure */
  parse_qbn_data();

  textcolor (TITLE_COLOR);
  textbackground (BACK_COLOR);
  section_drag[qbn_mode].draw_all();
  section_field[qbn_mode].draw();

  i = current_section[qbn_mode];
  gotoxy (30, 6);
  textcolor (LIGHTCYAN);
  cprintf (" Record %2d of %2d (Maximum = %2d) ", i, qbn_data.section_size[qbn_mode], MAX_QBN_ARRAY[qbn_mode]);

  gotoxy (QBN_BOX_X + 12, 3);
  textcolor (LIGHTGRAY);
  cprintf (" Editing QBN Data: ");
  i--;

  if (qbn_mode == QBN_ITEMS) {
    cprintf ("Items      ");
    textcolor (CYAN);
    gotoxy (QBN_BOX_X + 8, 28);
    cprintf ("    Index: %3u (0x%02x) ", qbn_data.section0[i].section_index, qbn_data.section0[i].section_index);
    gotoxy (QBN_BOX_X + 4, 29);
    cprintf (" Reward Type: %5u (0x%04x) ", qbn_data.section0[i].reward_type, qbn_data.section0[i].reward_type);
    gotoxy (QBN_BOX_X + 4, 30);
    cprintf ("      Reward: %10lu (0x%08lx) ", qbn_data.section0[i].reward, qbn_data.section0[i].reward);
    gotoxy (QBN_BOX_X + 4, 31);
    cprintf ("           Sub-Type 1: %5u (0x%04x) ", qbn_data.section0[i].rew1, qbn_data.section0[i].rew1);
    gotoxy (QBN_BOX_X + 4, 32);
    cprintf ("           Sub-Type 2: %5u (0x%04x) ", qbn_data.section0[i].rew2, qbn_data.section0[i].rew2);
    gotoxy (QBN_BOX_X + 4, 33);
    cprintf ("Message Type: %10lu (0x%08lx) ", qbn_data.section0[i].message_type, qbn_data.section0[i].message_type);
   } /* End of items mode */
  else if (qbn_mode == QBN_NPCS) {
    cprintf ("NPC's      ");
    textcolor (CYAN);
    gotoxy (QBN_BOX_X + 8, 32);
    cprintf ("    Index: %3u (0x%02x) ", qbn_data.section3[i].section_index, qbn_data.section3[i].section_index);
    gotoxy (QBN_BOX_X + 8, 33);
    cprintf (" Msg Type: %10lu (0x%08lx) ", qbn_data.section3[i].message_type, qbn_data.section3[i].message_type);
   }
  else if (qbn_mode == QBN_LOC) {
    cprintf ("Location    ");
    textcolor (CYAN);
    gotoxy (QBN_BOX_X + 8, 36);
    cprintf ("    Index: %3u (0x%02x) ", qbn_data.section4[i].section_index, qbn_data.section4[i].section_index);
    gotoxy (QBN_BOX_X + 8, 37);
    cprintf (" Msg Type: %10lu (0x%08lx) ", qbn_data.section4[i].message_type, qbn_data.section4[i].message_type);
   }
  else if (qbn_mode == QBN_MOB) {
    cprintf ("Monsters    ");
    gotoxy (QBN_BOX_X + 8, 31);
    cprintf ("   Index: %3u (0x%02x) ", qbn_data.section7[i].section_index, qbn_data.section7[i].section_index);
    gotoxy (QBN_BOX_X + 8, 32);
    cprintf (" Monster: %3u (0x%02x) ", qbn_data.section7[i].mob_index, qbn_data.section7[i].mob_index);
    gotoxy (QBN_BOX_X + 8, 33);
    cprintf (" Message Type: %10lu (0x%08lx) ", qbn_data.section7[i].message_type, qbn_data.section7[i].message_type);
    gotoxy (QBN_BOX_X + 8, 34);
    cprintf ("   NULL1: %5u (0x%04x) ", qbn_data.section7[i].null1, qbn_data.section7[i].null1);
    gotoxy (QBN_BOX_X + 8, 35);
    cprintf ("   NULL2: %10u (0x%08x) ", qbn_data.section7[i].null2, qbn_data.section7[i].null2);
   }

 }
/*========== End of procedure draw_qbn_screen() ===========================*/


/*========== Edits a Quest Text With a Given Message ID# ==================*/
void edit_msgid (const unsigned id) {
  int i;	/* Loop counter */
  char buffer[41];	/* Temp string buffer */

  if (id == 0) return;

  for (i = 0; i < qrc_data.num_entries; i++) {
    if (qrc_data.header[i].type == id) {	/* Did we find it? */
		/* Edit the text */
      if (quest_texts.texts[i].active)
	convert_qtext (qrc_data.text[i]);
      else {
	delete_all_editlines();
	init_edit();
       }

      sprintf (buffer, "Edit %s (%d)", get_qtext_desc (qrc_data.header[i].tag), qrc_data.header[i].type);

      text_editor (buffer);
      quest_texts.texts[i].active = convert_edit_list(&qrc_data.text[i]);
      draw_screen();
      return;
     }
   } /* End of for loop */

  get_message_box ("Text Not Found", "Quest Text with Type = %u not found!", id);
 }
/*========== End of procedure edit_msgid() ================================*/


/*========== Routines run when program is stopped =========================*/
void exit_dfqedit(void) {
  int i;	/* Loop counter */

  textmode(C80);	/* Normal text mode */
  printf ("Returned to textmode (80x25)\n");

	/* Reset to original drive and directory */
  setdisk (orig_drive);

  if (chdir (orig_directory) == -1)
    printf ("Failed to restore original path!\n");

	/* Replace our own keyboard interrupt routine with the original */
  delete_keyboard ();
  printf ("Replaced original keyboard driver\n");

  printf ("Freeing allocated memory\n");

  new_quest ();
  editmenu_new ("!");
  guild_list.delete_list ();
  rank_list.delete_list ();
  pc_status_list.delete_list ();
  qgiven_list.delete_list ();
  reward_type_list.delete_list();
  reward_list.delete_list();
  msg_type_list.delete_list();
  find_msg_list.delete_list();
  gender_list.delete_list();

	/* Delete all section 4 lists */
  gen_loc_list.delete_list();
  loc_list.delete_list();
  sec41_list.delete_list();
  sec42_list.delete_list();
  sec43_list.delete_list();

	/* Delete all section 7 lists */
  mob_list.delete_list();
  sec71_list.delete_list();

  find_msg_buttons.destroy();

  for (i = 0; i < 11;i ++)
    section_button[i].destroy();

  main_buttons.destroy();
  qtext_buttons.destroy();
  qbn_buttons.destroy();

  printf ("     Freed all allocated memory\n");

  printf ("Initial/Final Available Memory Check: %ld / %ld bytes\n", initial_far_heapsize, farcoreleft());

  if (initial_far_heapsize - farcoreleft() != 0)
    printf ("     WARNING: Memory may not be fully freed?\n");

  printf ("farheapcheck() returns ");

  switch (farheapcheck()) {
    case _HEAPCORRUPT: printf ("Heap has been Corrupted - You Should Reboot!\n"); break;
    case _HEAPOK: printf ("Heap OK\n"); break;
    default: printf ("No heap\n"); break;
   };

  printf ("Finished clean-up of DFQEDIT v%s\n\n", VERSION);

 }
/*========== End of procedure exit_dfqedit() ==============================*/


/*========== Searches QRC Texts for a particular message type =============*/
void find_msg (const char far *message) {
  int event, i;	/* Loop counter */
  char buffer[81], buffer1[6], far *temp_ptr;	/* Temp string buffers */
  boolean do_edit = FALSE, main_redraw = TRUE, redraw = TRUE, done = FALSE;
  CAPTURE_TEXT cap_text;	/* For saving the screen background */
  int double_click_item = 0;
  clock_t double_click_time = 0;

  find_msg_list.delete_list();	/* Clear the list */

	/* Search for the message in all non-null quest texts */
  for (i = 0; i < qrc_data.num_entries; i++) {
    if (qrc_data.text[i]) {
		/* Did we find a match? Add to end of list if we did */
      if ((temp_ptr = _fstrstr(qrc_data.text[i], message)) != NULL ) {
	if ((temp_ptr[-1] == '_' || temp_ptr[-1] == '=') &&
	     temp_ptr[_fstrlen(message)] == '_') {
	  sprintf (buffer, "Text: %-20s (%4u)", get_qtext_desc(qrc_data.header[i].tag), qrc_data.header[i].type);
	  sprintf (buffer1, "%4u", i);
	  find_msg_list.add_dual_item (buffer, buffer1);
	 }
       }
     }
   } /* End of for loop */

  find_msg_list.view = find_msg_list.start;

  if (find_msg_list.view) {
    find_msg_list.active = TRUE;
    find_msg_list.current = 0;
   }
  else {
    find_msg_list.active = FALSE;
    find_msg_list.current = -1;
   }

  do {
    if (main_redraw) {
      hide_mouse();
      get_screen (FIND_MSG_WIDTH + 8, FIND_MSG_HEIGHT + 10, &cap_text);

      textcolor (BIGWIN_BORD_COLOR);
      textbackground (BIGWIN_BACK_COLOR);

      draw_textbox_center (FIND_MSG_WIDTH + 8, FIND_MSG_HEIGHT + 10, "Find Message", BIGWIN_TEXT_COLOR);
      find_msg_buttons.draw ();
      textcolor (BLUE);
      cprintf_cent (FIND_MSG_Y - get_screenheight()/2 - 2, "Finding message '%s'", message);
      show_mouse();
     }

    if (redraw || main_redraw) {
      redraw = FALSE;
      main_redraw = FALSE;
      find_msg_list.draw();
      _setcursortype (_NOCURSOR);
     }
	/* Check for any mouse events */
    event = get_mouse_event (LEFT_BUTTON) | get_mouse_event (RIGHT_BUTTON);

    if ((i = find_msg_buttons.check (MOUSEX, MOUSEY, event) ) != -1) {

      switch (i) {
	case 0: /* Edit Button Was Pressed */
		do_edit = TRUE;
		break;
	case 1: /*  The Cancel button Pressed */
		done = TRUE;
		break;
       } /* End of switch */
     } /*  End of if buttons pressed */
    else if (event == BUTTON_RELEASE && (i = find_msg_list.check (MOUSEX, MOUSEY, event)) != NO_ITEM && i != SCROLL_BAR) {
      if (   find_msg_list.active && find_msg_list.current + i == double_click_item
	  && clock() - double_click_time <= DOUBLE_CLICK_TIME) {
	do_edit = TRUE;
	double_click_time = 0;
       }
      else {
	double_click_time = clock();
	double_click_item = find_msg_list.current + i;
       }

      find_msg_list.move (i);
      redraw = TRUE;
     } /* End of if button click in list box */

	/* Get Keyboard input */
    GetKey();

    if (get_esc_state()) { /* ESC */
      done = TRUE;
     }
    else if (get_enter_state()) { /* Enter */
      do_edit = TRUE;
     }
    else if (get_up_state()) { /* Up */
      if (find_msg_list.move(-1)) redraw = TRUE;
      delay (2*KEY_DELAY);
     }
    else if (get_down_state()) { /* Down */
      if (find_msg_list.move(1)) redraw = TRUE;
      delay (2*KEY_DELAY);
     }
    else if (get_pgup_state()) { /* PgUp */
      if (find_msg_list.move(find_msg_list.height)) redraw = TRUE;
      delay (2*KEY_DELAY);
     }
    else if (get_pgdn_state()) { /* PgDn */
      if (find_msg_list.move(find_msg_list.height)) redraw = TRUE;
      delay (2*KEY_DELAY);
     }
    else if (get_home_state()) { /* Home */
      find_msg_list.view = find_msg_list.start;
      find_msg_list.current = 0;
      redraw = TRUE;
      delay (KEY_DELAY);
     }
    else if (get_end_state()) { /* End */
      find_msg_list.view = find_msg_list.end;
      find_msg_list.current = 0;
      redraw = TRUE;
      delay (KEY_DELAY);
     }

    if (do_edit && find_msg_list.start) {
      do_edit = FALSE;
      delete cap_text.save_screen;
      find_msg_list.get_name (NULL);
      i = get_ext_int (find_msg_list.list);

      if (quest_texts.texts[i].active)
	convert_qtext (qrc_data.text[i]);
      else {
	delete_all_editlines();
	init_edit();
       }

      sprintf (buffer, "Edit %s (%d)", get_qtext_desc (qrc_data.header[i].tag), qrc_data.header[i].type);

      text_editor (buffer);
      quest_texts.texts[i].active = convert_edit_list(&qrc_data.text[i]);
      draw_screen();
      main_redraw = TRUE;
     }

  } while (!done);

  hide_mouse();
  put_screen (&cap_text);
  show_mouse();
  find_msg_list.delete_list();
 }
/*========== End of procedure find_msg() ==================================*/


/*========== Returns the Quest text's Description =========================*/
char *get_qtext_desc (unsigned int type) {
  int i = 0;	/* loop counter */

  while (strlen(qtext_desc[i].desc) && i < 100) {
    if (qtext_desc[i].type == type) return (qtext_desc[i].desc);
    i++;
   }

  return ("Unknown");
 }
/*========== End of Function get_qtext_desc() =============================*/


/*========== Takes values in Drag-Lists and tranfers them to the QBN_DATA =*/
void get_qbn_data (void) {
  int i = current_section[qbn_mode] - 1;

  if (qbn_mode == QBN_ITEMS) {	/* Item mode */
    if (i >= 0) {
      qbn_data.section0[i].reward_type = (unsigned int) section_drag[0].buttons[REWARD_TYPE_INDEX].number;
      qbn_data.section0[i].reward = section_drag[0].buttons[REWARD_INDEX].number;
      qbn_data.section0[i].message_type = section_drag[0].buttons[MSG_TYPE_INDEX[0]].number;
      qbn_data.section0[i].message_id1 = (unsigned) strtol(section_field[0].fields[MSGID1_INDEX[0]].value, NULL, 0);
      qbn_data.section0[i].message_id2 = (unsigned) strtol(section_field[0].fields[MSGID2_INDEX[0]].value, NULL, 0);
     }

   } /* End of items mode */
  else if (qbn_mode == QBN_NPCS) {	/* NPC mode */
    if (i >= 0) {
      qbn_data.section3[i].gender = (unsigned int) section_drag[3].buttons[GENDER_INDEX].number;
      qbn_data.section3[i].message_type = section_drag[3].buttons[MSG_TYPE_INDEX[3]].number;
      qbn_data.section3[i].message_id1 = (unsigned) strtol(section_field[3].fields[MSGID1_INDEX[3]].value, NULL, 0);
      qbn_data.section3[i].message_id2 = (unsigned) strtol(section_field[3].fields[MSGID2_INDEX[3]].value, NULL, 0);
      qbn_data.section3[i].val1 = (unsigned char) strtol(section_field[3].fields[NUMBER1_INDEX[3]].value, NULL, 0);
      qbn_data.section3[i].val2 = (unsigned) strtol(section_field[3].fields[NUMBER2_INDEX[3]].value, NULL, 0);
      qbn_data.section3[i].val3 = (unsigned) strtol(section_field[3].fields[NUMBER3_INDEX[3]].value, NULL, 0);
     }
   } /* End of items mode */
  else if (qbn_mode == QBN_LOC) { 	/* Location mode */
    if (i >= 0) {
      qbn_data.section4[i].gen_location = (unsigned char) section_drag[4].buttons[GEN_LOC_INDEX].number;
      qbn_data.section4[i].location = (unsigned) section_drag[4].buttons[LOC_INDEX].number;

      qbn_data.section4[i].val1 = (unsigned) section_drag[4].buttons[NUMBER1_INDEX[4]].number;
      qbn_data.section4[i].val2 = (unsigned) section_drag[4].buttons[NUMBER2_INDEX[4]].number;
      qbn_data.section4[i].val3 = (unsigned char) section_drag[4].buttons[NUMBER3_INDEX[4]].number;
      qbn_data.section4[i].val4 = (unsigned char) strtol(section_field[4].fields[NUMBER4_INDEX[4]].value, NULL, 0);

      qbn_data.section4[i].message_type = (unsigned) section_drag[4].buttons[MSG_TYPE_INDEX[4]].number;
      qbn_data.section4[i].message_id1 = (unsigned) strtol(section_field[4].fields[MSGID1_INDEX[4]].value, NULL, 0);
      qbn_data.section4[i].message_id2 = (unsigned) strtol(section_field[4].fields[MSGID2_INDEX[4]].value, NULL, 0);
     }
   } /* End of location mode */
  else if (qbn_mode == QBN_MOB) {
    if (i >= 0) {
      qbn_data.section7[i].mob_index = (unsigned char) section_drag[7].buttons[MOB_INDEX].number;
      qbn_data.section7[i].val1 = (unsigned) section_drag[7].buttons[NUMBER1_INDEX[7]].number;
      qbn_data.section7[i].message_type = (unsigned long) section_drag[7].buttons[MSG_TYPE_INDEX[7]].number;
     }
   } /* End of mob mode */
 }
/*========== End of procedure get_qbn_data() ==============================*/


/*========== Initializes everything =======================================*/
void init_dfqedit(void) {
  char ch;   	/* Temp character buffer */
  int i;      	/* Loop counter */

  _wscroll = 0;		/* No scrolling of text on screen */
  qrc_screen = TRUE;
  qbn_mode = 0;
  initial_far_heapsize = farcoreleft();	/* Save initial available memory */
  atexit (exit_dfqedit);	/* Define exit procedure */
  max_string_length = MAX_STRING_LENGTH;	/* Set the maximum string length */
  init_buttons ();	/* Intialize the Default Buttons in UTIL.CPP */
  err_header_string = &dfqedit_title[0];
  err_header_version = &dfqedit_version[0];

	/* Initialize the QBN section selection */
  for (i = 0 ; i < 10; i++) {
    current_section[i] = 0;
   }

	/* Print opening title.... */
  printf ("DFQEDIT v%s - Copyright (c) 1996 - by Dave Humphrey\n\n", VERSION);

	/* Check to see if program has been run before... */
  if (fileexists("file_id.diz")) {
    printf ("Since this is the first time you have run this version of DFQEdit, you may wish\n");
    printf ("to read the DFQEdit Manual First. It contains a lot of important information\n");
    printf ("about this program.    This message will not be displayed again.\n");
    printf ("Do you wish to read DFQEDIT.TXT now? [y/n]?");

    do {
      ch = toupper(getch());
    } while (ch != 'Y' && ch != 'N');

    unlink ("file_id.diz");	/* Delete the temp file */

    if (ch == 'Y') { //Read DFQEDIT.TXT
      if (system ("edit dfqedit.txt") != 0)
	bug ("Couldn't Spawn EDIT dfqedit.txt!", NULL);
     }

    printf ("\n\n");
   }

	/* Save the current directory and drive...for reseting at end and
	 * goto intial directory */
  if (getcwd (&orig_directory[0], MAX_STRING_LENGTH) == NULL)
    printf ("ERROR: Path too Long, Path length cannot exceed 80 bytes!\n\n");

  orig_drive = getdisk();

	/* Replace some DOS error handling routines with our own */
  harderr (dos_err_handler);
  ctrlbrk (ctrl_brk_handler);
  setcbrk(1);
  printf ("Replaced DOS error handler and CTRL-BRK routines\r\n");

	/* Initialize the Mouse Driver */
  printf ("Initialize Mouse Driver\r\n");
  if (!mouse_init()) bug ("Could not intialize mouse driver!", NULL);
  printf ("    Mouse Driver Initialized\r\n");

	/* Replace keyboard interrupt with our own routine */
  printf ("Replace default keyboard interrupt\r\n");
  install_keyboard ();
  ClearKeys();
  printf ("     Keyboard interrupt replaced\n");

	/* Initialize some buttons */
  section_button[0].new_button (REWARD_X + 24, REWARD_Y + 2, REWARD_Y/2 + 2, 10, 1, "Find Msg", BLACK, BLACK);
  section_button[0].new_button (MSG_X + 14, MSG_Y, MSG_Y/2, 10, 1, "View Msg", BLACK, BLACK);
  section_button[0].new_button (MSG_X + 14, MSG_Y + 3, MSG_Y/2 + 4, 10, 1, "View Msg", BLACK, BLACK);

  section_button[3].new_button (GENDER_X + 24, GENDER_Y + 2, GENDER_Y/2 + 2, 10, 1, "Find Msg", BLACK, BLACK);
  section_button[3].new_button (MSG_X + 14, MSG_Y, MSG_Y/2 + 2, 10, 1, "View Msg", BLACK, BLACK);
  section_button[3].new_button (MSG_X + 14, MSG_Y + 3, MSG_Y/2 + 2, 10, 1, "View Msg", BLACK, BLACK);

  section_button[4].new_button (LOC_X + 24, LOC_Y + 4, GENDER_Y/2 + 2, 10, 1, "Find Msg", BLACK, BLACK);
  section_button[4].new_button (MSG_X + 14, MSG_Y, MSG_Y/2 + 2, 10, 1, "View Msg", BLACK, BLACK);
  section_button[4].new_button (MSG_X + 14, MSG_Y + 3, MSG_Y/2 + 2, 10, 1, "View Msg", BLACK, BLACK);

  section_button[7].new_button (REWARD_X + 24, REWARD_Y + 2, REWARD_Y/2 + 2, 10, 1, "Find Msg", BLACK, BLACK);

  find_msg_buttons.new_button (FIND_MSG_X + 3, FIND_MSG_Y + FIND_MSG_HEIGHT + 1, 5, 8, 3, "Edit");
  find_msg_buttons.new_button (FIND_MSG_X + 22, FIND_MSG_Y + FIND_MSG_HEIGHT + 1, 5, 8, 3, "Cancel");
  qtext_buttons.new_button (40-QTEXT_WIDTH/2 +  3, 25-QTEXT_HEIGHT/2 + 4, (25-QTEXT_HEIGHT)/2 + 4, 13, 3, "Edit Text");
  qtext_buttons.new_button (40-QTEXT_WIDTH/2 + 20, 25-QTEXT_HEIGHT/2 + 4, (25-QTEXT_HEIGHT)/2 + 4, 15, 3, "Delete Text");
  qtext_buttons.new_button (40-QTEXT_WIDTH/2 + 41, 25-QTEXT_HEIGHT/2 + 4, (25-QTEXT_HEIGHT)/2 + 4, 10, 3, "Cancel");
  qbn_buttons.new_button (QBN_BOX_X + 15, QBN_BOX_Y + QBN_BOX_HEIGHT - 4, 20, 8, 3, "Prev");
  qbn_buttons.new_button (QBN_BOX_X + 27, QBN_BOX_Y + QBN_BOX_HEIGHT - 4, 20, 8, 3, "Add");
  qbn_buttons.new_button (QBN_BOX_X + 39, QBN_BOX_Y + QBN_BOX_HEIGHT - 4, 20, 8, 3, "Next");
  qbn_buttons.new_button (4, 10, 5, 10, 3, "Items");
  qbn_buttons.new_button (4, 15, 5, 10, 3, "NPC's");
  qbn_buttons.new_button (4, 20, 5, 10, 3, "Location");
  qbn_buttons.new_button (4, 25, 5, 10, 3, "Monsters");
  main_buttons.new_button ( 3, 46, 22,  8, 3, "Load" );
  main_buttons.new_button (15, 46, 22,  8, 3, "Save" );
  main_buttons.new_button (43, 46, 22,  8, 3, "New" );
  main_buttons.new_button (55, 46, 22,  9, 3, "About" );
  main_buttons.new_button (68, 46, 22,  8, 3, "Exit" );
  main_buttons.new_button (27, 46, 22, 12, 3, "QBN Data" );

	/* Create some lists of values */
  qgiven_list.add_dual_end ("in Person", "Y");
  qgiven_list.add_dual_end ("by Letter", "L");
  qgiven_list.add_dual_end ("Unknown", "0");

  gender_list.add_dual_end ("Random? - 0xFF00", "0xFF00");
  gender_list.add_dual_end ("Male? - 0x0000", "0x0000");
  gender_list.add_dual_end ("Female? - 0x0100", "0x0100");

  pc_status_list.add_dual_end ("is Member", "B");
  pc_status_list.add_dual_end ("is Not Member", "C");
  pc_status_list.add_dual_end ("is Joining", "A");
  pc_status_list.add_dual_end ("Unknown", "0");

	/* Define the rank list */
  rank_list.add_dual_end ("0", "\0");
  rank_list.add_dual_end ("1", "\1");
  rank_list.add_dual_end ("2", "\2");
  rank_list.add_dual_end ("3", "\3");
  rank_list.add_dual_end ("4", "\4");
  rank_list.add_dual_end ("5", "\5");
  rank_list.add_dual_end ("6", "\6");
  rank_list.add_dual_end ("7", "\7");
  rank_list.add_dual_end ("8", "\8");
  rank_list.add_dual_end ("9", "\9");

	/* Section 0 Lists */
  reward_type_list.add_dual_end ("Item?", "00");
  reward_type_list.add_dual_end ("Item", "256");
  reward_type_list.add_dual_end ("Gold", "512");
  reward_type_list.add_dual_end ("Unknown", "768");

	/* Some Section 4 Lists */
  gen_loc_list.add_dual_end ("Unknown", "00");
  gen_loc_list.add_dual_end ("Current Town", "01");
  gen_loc_list.add_dual_end ("Outside Town", "02");

  if (load_dual_list ("loc.dat", &loc_list)) {
    printf ("Location data types successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Location data types!\n");
    getch ();
   }

  if (load_dual_list ("val41.dat", &sec41_list)) {
    printf ("Section 4, Val1 data types successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Section 4, Val1 data types!\n");
    getch ();
   }

  if (load_dual_list ("val42.dat", &sec42_list)) {
    printf ("Section 4, Val2 data types successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Section 4, Val2 data types!\n");
    getch ();
   }

  if (load_dual_list ("val43.dat", &sec43_list)) {
    printf ("Section 4, Val3 data types successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Section 4, Val3 data types!\n");
    getch ();
   }

	/* Section 7 Lists */
  if (load_dual_list ("mobs.dat", &mob_list)) {
    printf ("Mob data types successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Mob data types!\n");
    getch ();
   }

  if (load_dual_list ("val71.dat", &sec71_list)) {
    printf ("Section 7, Val1 data types successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Section 7, Val1 data types!\n");
    getch ();
   }

	/* Load the guild names data file */
  if (load_guilds ("guilds.dat", &guild_list)) {
    printf ("Guild data types succesfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Guild data types!\n");
    getch();
   }

  guild_list.add_dual_end ("Unknown", "~");	/* Make sure there's at least one element in list */

	/* Load the item names data file */
  if (load_dual_list("items.dat", &reward_list)) {
    printf ("Item data file successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Item data file 'items.dat'!\n");
    getch();
   }

  reward_list.add_dual_end ("Unknown", "0");

	/* Load the msg_type data file */
  if (load_msg("msg.dat")) {
    printf ("Message name data file successfully loaded\n");
   }
  else {
    printf ("Warning: Could not load Message name data file 'msg.dat'!\n");
    getch();
   }

  msg_type_list.add_dual_end ("Unknown", "0");

	/* Create the Drag Button Array for the QRC screen */
  GUILD_INDEX = drag_buttons.add_button (&guild_list, "Quest Guild:");
  RANK_INDEX = drag_buttons.add_button (&rank_list, "Minimum Rank:");
  PC_STATUS_INDEX = drag_buttons.add_button (&pc_status_list, "PC Status:");
  QGIVEN_INDEX = drag_buttons.add_button (&qgiven_list, "Quest is Given:");

	/* Section 0 Drag Buttons */
  REWARD_TYPE_INDEX = section_drag[0].add_button (&reward_type_list, "Item Type:");
  REWARD_INDEX = section_drag[0].add_button (&reward_list, "Item:");
  MSG_TYPE_INDEX[0] = section_drag[0].add_button (&msg_type_list, "Message Type:");
  MSGID1_INDEX[0] = section_field[0].add_text (MSG_X, MSG_Y, MSG_WIDTH, "Message ID (int):");
  MSGID2_INDEX[0] = section_field[0].add_text (MSG_X, MSG_Y + 3, MSG_WIDTH, "Letter ID (int):");

	/* Section 3 Drag Buttons */
  MSGID1_INDEX[3] = section_field[3].add_text (MSG_X, MSG_Y, MSG_WIDTH, "Message ID1 (int):");
  MSGID2_INDEX[3] = section_field[3].add_text (MSG_X, MSG_Y + 3, MSG_WIDTH, "Message ID2 (int):");
  NUMBER1_INDEX[3] = section_field[3].add_text (MSG_X, MSG_Y + 6, 5, "Unknown #1 (char):");
  NUMBER2_INDEX[3] = section_field[3].add_text (MSG_X, MSG_Y + 8, 8, "Unknown #2 (int):");
  NUMBER3_INDEX[3] = section_field[3].add_text (MSG_X, MSG_Y + 10, 8, "Unknown #3 (int):");
  GENDER_INDEX = section_drag[3].add_button (&gender_list, "Gender?:");
  MSG_TYPE_INDEX[3] = section_drag[3].add_button (&msg_type_list, "Message Type:");

	/* Section 4 Drag Buttons */
  GEN_LOC_INDEX = section_drag[4].add_button (&gen_loc_list, "Location #1:");
  LOC_INDEX = section_drag[4].add_button (&loc_list, "Location #2:");
  NUMBER1_INDEX[4] = section_drag[4].add_button (&sec41_list, "Unknown #1 (int):");
  NUMBER2_INDEX[4] = section_drag[4].add_button (&sec42_list, "Unknown #2 (int):");
  NUMBER3_INDEX[4] = section_drag[4].add_button (&sec43_list, "Unknown #3 (int):");
  NUMBER4_INDEX[4] = section_field[4].add_text (LOC_X, LOC_Y + 21, 6, "Unknown #4 (char):");
  MSG_TYPE_INDEX[4] = section_drag[4].add_button (&msg_type_list, "Message Type:");
  MSGID1_INDEX[4] = section_field[4].add_text (MSG_X, MSG_Y, MSG_WIDTH, "Message ID1 (int):");
  MSGID2_INDEX[4] = section_field[4].add_text (MSG_X, MSG_Y + 3, MSG_WIDTH, "Message ID2 (int):");

	/* Section 7 Drag Buttons */
  NUMBER1_INDEX[7] = section_drag[7].add_button (&sec71_list, "Unknown #1 (int):");
  MOB_INDEX = section_drag[7].add_button (&mob_list, "Monster:");
  MSG_TYPE_INDEX[7] = section_drag[7].add_button (&msg_type_list, "Message Type:");

	/* Initialize the guild values */
  drag_buttons.init_values();
  section_drag[0].init_values();
  section_drag[3].init_values();
  section_drag[4].init_values();
  section_drag[7].init_values();

	/* Goto 80x50 and Show mouse cursor */
  printf ("Going to textmode (80x50) and showing mouse cursor\r\n");
  textmode(64);
  show_mouse ();
 }
/*========== End of procedure init_dfqedit() ==============================*/


/*========== Loads a Data file for a Dual List Values =====================*/
boolean load_dual_list (const char *filename, LIST_BOX *list) {
  FILE *f;	/* File pointer */
  boolean done = FALSE;	/* Loop counter */
  char l[81], *buf, *temp_ptr;	/* Temp input buffers */

	/* Try and open file... */
  if (!(f = fopen (filename, "rt")) ) {
    printf ("\n    Error: Couldn't open file '%s'!\n", filename);
    return(FALSE);
   }

	/* Attempt to allocate temp input buffer */
  buf = create_ptr (MAX_STRING_LENGTH + 1);

  while (!done) {

	/* Read number */
    if (read_word (f, buf) == READ_EOF)
      done = TRUE;

    sprintf (l, "0x%lx", strtoul (buf, NULL, 0));

    if (!done) {	/* Read description */
      if (read_eol (f, buf, MAX_STRING_LENGTH) == READ_EOF)
	done = TRUE;

      if (strlen(buf)) {
	temp_ptr = lstrip (buf);
	rstrip (temp_ptr);
	list->add_dual_sort (temp_ptr, l);
       }
     }
   }; /* End of while loop */

  fclose (f);	/* Close file */
  delete buf;
  list->view = list->start;
  return (TRUE);
 }
/*========== End of function load_dual_list() =============================*/


/*========== Loads the Guild Data file for a Dual List Values =============*/
boolean load_guilds (const char *filename, LIST_BOX *list) {
  FILE *f;	/* File pointer */
  boolean done = FALSE;	/* Loop counter */
  char l[81], *buf, *temp_ptr;	/* Temp input buffers */

	/* Try and open file... */
  if (!(f = fopen (filename, "rt")) ) {
    printf ("\n    Error: Couldn't open file '%s'!\n", filename);
    return(FALSE);
   }

	/* Attempt to allocate temp input buffer */
  buf = create_ptr (MAX_STRING_LENGTH + 1);

  while (!done) {

	/* Read number */
    if (read_word (f, buf) == READ_EOF)
      done = TRUE;

    sprintf (l, "%d", *buf);

    if (!done) {	/* Read description */
      if (read_eol (f, buf, MAX_STRING_LENGTH) == READ_EOF)
	done = TRUE;

      if (strlen(buf)) {
	temp_ptr = lstrip (buf);
	rstrip (temp_ptr);
	list->add_dual_sort (temp_ptr, l);
       }
     }
   }; /* End of while loop */

  fclose (f);	/* Close file */
  delete buf;
  list->view = list->start;
  return (TRUE);
 }
/*========== End of function load_guilds() ================================*/


/*========== Loads the Message Data file ==================================*/
boolean load_msg (const char *filename) {
  FILE *f;	/* File pointer */
  boolean done = FALSE;	/* Loop counter */
  char l[12], *buf, *temp_ptr;	/* Temp input buffers */

	/* Try and open file... */
  if (!(f = fopen (filename, "rt")) ) return(FALSE);

	/* Attempt to allocate temp input buffer */
  buf = create_ptr (MAX_STRING_LENGTH + 1);

  while (!done) {
	/* Read line */
    done = (boolean) !read_eol (f, buf);

	/* Remove trailing/leading spaces...if any */
    temp_ptr = lstrip(buf);
    rstrip(temp_ptr);

	/* Create the hash numerical value */
    sprintf (l, "0x%lx", msg_hash(temp_ptr));

	/* Add to list */
    msg_type_list.add_dual_sort (temp_ptr, l);
   }; /* End of while loop */

  fclose (f);	/* Close file */
  delete buf;
  return (TRUE);
 }
/*========== End of function load_msg() ===================================*/


/*========== Converts a Message Name into a Hash Value ===================*/
long msg_hash (const char far *msg) {
  long int val = 0;

  while ((*msg == '_' || *msg == '=') && *msg)
    msg++;

  while(*msg && *msg != '_')
    val = (val<<1) + *msg++;

  return (val);
 }
/*========== End of function msg_hash() ==================================*/


/*========== Deletes all current quest texts ==============================*/
void new_quest(void) {
  int i = 0;

  quest_loaded = FALSE;
  qrc_data.num_entries = 0;
  qrc_data.delete_texts ();
  qbn_data.delete_data ();
  drag_buttons.init_values();

  for (i = 0; i < MAX_QRC_ARRAY; i++) {
    quest_texts.texts[i].visible = quest_texts.texts[i].active = FALSE;
   }

 }
/*========== End of procedure new_quest() =================================*/


/*========== Translates the QBN data into list values =====================*/
void parse_qbn_data (void) {
  int i;

  i = current_section[qbn_mode] - 1;

  if (qbn_mode == QBN_ITEMS) {	/* Item mode */
    if (i >= 0) {
      section_drag[0].buttons[REWARD_TYPE_INDEX].find_ext_int (qbn_data.section0[i].reward_type);
      section_drag[0].buttons[REWARD_INDEX].find_ext_long (qbn_data.section0[i].reward);
      section_drag[0].buttons[MSG_TYPE_INDEX[0]].find_ext_long (qbn_data.section0[i].message_type);
      section_field[0].fields[MSGID1_INDEX[0]].number = qbn_data.section0[i].message_id1;
      sprintf (section_field[0].fields[MSGID1_INDEX[0]].value, "%u", qbn_data.section0[i].message_id1);
      section_field[0].fields[MSGID2_INDEX[0]].number = qbn_data.section0[i].message_id2;
      sprintf (section_field[0].fields[MSGID2_INDEX[0]].value, "%u", qbn_data.section0[i].message_id2);
     }
   }
  else if (qbn_mode == QBN_NPCS) {	/* NPC mode */
    if (i >= 0) {
      section_drag[3].buttons[GENDER_INDEX].find_ext_int (qbn_data.section3[i].gender);
      section_drag[3].buttons[MSG_TYPE_INDEX[3]].find_ext_long (qbn_data.section3[i].message_type);
      section_field[3].fields[MSGID1_INDEX[3]].number = qbn_data.section3[i].message_id1;
      sprintf (section_field[3].fields[MSGID1_INDEX[3]].value, "%u", qbn_data.section3[i].message_id1);
      section_field[3].fields[MSGID2_INDEX[3]].number = qbn_data.section3[i].message_id2;
      sprintf (section_field[3].fields[MSGID2_INDEX[3]].value, "%u", qbn_data.section3[i].message_id2);

      section_field[3].fields[NUMBER1_INDEX[3]].number = qbn_data.section3[i].val1;
      sprintf (section_field[3].fields[NUMBER1_INDEX[3]].value, "%u", qbn_data.section3[i].val1);
      section_field[3].fields[NUMBER2_INDEX[3]].number = qbn_data.section3[i].val2;
      sprintf (section_field[3].fields[NUMBER2_INDEX[3]].value, "%u", qbn_data.section3[i].val2);
      section_field[3].fields[NUMBER3_INDEX[3]].number = qbn_data.section3[i].val3;
      sprintf (section_field[3].fields[NUMBER3_INDEX[3]].value, "%u", qbn_data.section3[i].val3);
     }
   }
  else if (qbn_mode == QBN_LOC) { 	/* Location mode */
    if (i >= 0) {
      section_drag[4].buttons[GEN_LOC_INDEX].find_ext_int (qbn_data.section4[i].gen_location);
      section_drag[4].buttons[LOC_INDEX].find_ext_int (qbn_data.section4[i].location);
      section_drag[4].buttons[NUMBER1_INDEX[4]].find_ext_int (qbn_data.section4[i].val1);
      section_drag[4].buttons[NUMBER2_INDEX[4]].find_ext_int (qbn_data.section4[i].val2);
      section_drag[4].buttons[NUMBER3_INDEX[4]].find_ext_int (qbn_data.section4[i].val3);
      section_drag[4].buttons[MSG_TYPE_INDEX[4]].find_ext_long (qbn_data.section4[i].message_type);

      section_field[4].fields[NUMBER4_INDEX[4]].number = qbn_data.section4[i].val4;
      sprintf (section_field[4].fields[NUMBER4_INDEX[4]].value, "%u", qbn_data.section4[i].val4);

      section_field[4].fields[MSGID1_INDEX[4]].number = qbn_data.section4[i].message_id1;
      sprintf (section_field[4].fields[MSGID1_INDEX[4]].value, "%u", qbn_data.section4[i].message_id1);
      section_field[4].fields[MSGID2_INDEX[4]].number = qbn_data.section4[i].message_id2;
      sprintf (section_field[4].fields[MSGID2_INDEX[4]].value, "%u", qbn_data.section4[i].message_id2);
     }
   }
  else if (qbn_mode == QBN_MOB) {	/* Monster mode */
    if (i >= 0) {
      section_drag[7].buttons[MOB_INDEX].find_ext_int (qbn_data.section7[i].mob_index);
      section_drag[7].buttons[NUMBER1_INDEX[7]].find_ext_int (qbn_data.section7[i].val1);
      section_drag[7].buttons[MSG_TYPE_INDEX[7]].find_ext_long (qbn_data.section7[i].message_type);
     }
   }
 }
/*========== End of procedure parse_qbn_data() ============================*/


/*========== Translates a Quest filename into Screen List Values ==========*/
void parse_filename (const char far *filename) {
  drag_buttons.buttons[GUILD_INDEX].find_ext_char (toupper(*filename));

		/* These quests don't conform to known standards... */
  if (!filename || *filename == 'S' || *filename == '$' || *filename == '_' || strlen(filename) < 3) {
    drag_buttons.buttons[RANK_INDEX].number = '\0';
    strcpy (drag_buttons.buttons[RANK_INDEX].value, "0");
    drag_buttons.buttons[PC_STATUS_INDEX].number = '0';
    strcpy (drag_buttons.buttons[PC_STATUS_INDEX].value, "<none>");
    drag_buttons.buttons[QGIVEN_INDEX].number = '0';
    strcpy (drag_buttons.buttons[QGIVEN_INDEX].value, "<none>");
    return;
   }

  filename += 2;	/* Move to 3rd character */
  drag_buttons.buttons[PC_STATUS_INDEX].find_ext_char (toupper(*filename));

  if (_fstrlen(filename) > 3) {
    filename++;		/* Move to 4th character */
    drag_buttons.buttons[RANK_INDEX].find_ext_char (*filename - '0');

    if (_fstrlen(filename) > 5) {
      filename += 2;	/* Move to 6th character */
      drag_buttons.buttons[QGIVEN_INDEX].find_ext_char (toupper(*filename));
     }
   }
 }
/*========== End of procedure parse_filename() ============================*/


/*========== Removes any QRC/QBN extension on the end of inputed Filenames */
void parse_quest_filename(char far *filename) {
  char far *temp_ptr;

  _fstrupr(filename);

  if ((temp_ptr = _fstrstr(filename, ".QRC")) != NULL) {
    *temp_ptr = 0;  /* Simply terminate string at found location */
   }
  else if ((temp_ptr = _fstrstr(filename, ".QBN")) != NULL) {
    *temp_ptr = 0;  /* Simply terminate string at found location */
   }
}
/*========== End of procedure parse_quest_filename() ======================*/


/*========== Class QBN_DATA Constructor ===================================*/
void QBN_DATA::QBN_DATA (void) {
  int i;    	/* Loop counter */

  for (i = 0; i < 10; i++) {
    section_size[i] = 0;
    section_offset[i] = -1;
    header[i] = 0;
   }

  for (; i < 16; i++)
    header[i] = 0;

  for (i = 0; i < MAX_QBN1_ARRAY; i++)
    section1[i].data = NULL;

  for (i = 0; i < MAX_QBN2_ARRAY; i++)
    section2[i].data = NULL;

  for (i = 0; i < MAX_QBN5_ARRAY; i++)
    section5[i].data = NULL;

  for (i = 0; i < MAX_QBN6_ARRAY; i++)
    section6[i].data = NULL;

  for (i = 0; i < MAX_QBN8_ARRAY; i++)
    section8[i].data = NULL;

  for (i = 0; i < MAX_QBN9_ARRAY; i++)
    section9[i].data = NULL;

  for (i = 0; i < MAX_QBN10_ARRAY; i++)
    section10[i].data = NULL;

 }
//========== End of Class QBN_DATA Constructor ==============================


//========== Class QBN_DATA Destructor ======================================
void QBN_DATA::~QBN_DATA (void) {
  delete_data ();
 }
//========== End of Class QBN_DATA Destructor ===============================


//========== Deletes All Data in the QBN_DATA Class =========================
void QBN_DATA::delete_data (void) {
  int i;	/* Loop counter */

	/* Delete the Section 1 Data */
  for (i = 0; i < MAX_QBN1_ARRAY; i++) {
    if (section1[i].data) {
      delete section1[i].data;
      section1[i].data = NULL;
     }
   }

	/* Delete the Section 2 Data */
  for (i = 0; i < MAX_QBN2_ARRAY; i++) {
    if (section2[i].data) {
      delete section2[i].data;
      section2[i].data = NULL;
     }
   }

	/* Delete the Section 5 Data */
  for (i = 0; i < MAX_QBN5_ARRAY; i++) {
    if (section5[i].data) {
      delete section5[i].data;
      section5[i].data = NULL;
     }
   }

	/* Delete the Section 6 Data */
  for (i = 0; i < MAX_QBN6_ARRAY; i++) {
    if (section6[i].data) {
      delete section6[i].data;
      section6[i].data = NULL;
     }
   }

	/* Delete the Section 8 Data */
  for (i = 0; i < MAX_QBN8_ARRAY; i++) {
    if (section8[i].data) {
      delete section8[i].data;
      section8[i].data = NULL;
     }
   }

	/* Delete the Section 9 Data */
  for (i = 0; i < MAX_QBN9_ARRAY; i++) {
    if (section9[i].data) {
      delete section9[i].data;
      section9[i].data = NULL;
     }
   }

	/* Delete the Section 10 Data */
  for (i = 0; i < MAX_QBN10_ARRAY; i++) {
    if (section10[i].data) {
      delete section10[i].data;
      section10[i].data = NULL;
     }
   }

 }
/*========== End of Procedure QBN_DATA::delete_data () ====================*/


/*========== Attempts to Load the QBN =====================================*/
boolean QBN_DATA::load (const char far *filename) {
  FILE *f; 	/* File Pointer */
  char *temp_file;	/* For creating the proper filename, QBN */
  long filesize;
  int i;	/* Loop counter */

	/* Allocate Temp String Buffer */
  if (!(temp_file = new char[_fstrlen(quest_path) + _fstrlen(filename) + 7]))
    bug (MEM_ERR_MSG, "load_qrc() - *temp_file (%d)", _fstrlen(quest_path) + _fstrlen(filename) + 7);

  _fstrcpy (temp_file, quest_path);

	/* Make sure there is a proper slash at end */
  if (_fstrlen(temp_file) > 0 && *(temp_file + _fstrlen(temp_file) - 1) != '\\')
    chrcat (temp_file, '\\');

  _fstrcat (temp_file, filename);
  _fstrcat (temp_file, ".QBN");

	/* Make sure the file exists before opening it */
  if (!fileexists(temp_file)) return(FALSE);

	/* Open QBN file */
  f = openfile (temp_file, "rb");
  filesize = get_filesize (f);

	/* Read the 15-Byte Header */
  if (fread (header, sizeof(char), 15, f) != 15) return (FALSE);

	/* Read the 10th Section Byte */
  section10_status = fgetc (f);

	/* Read the Section Size Info */
  for (i = 0; i < 10; i++)
    section_size[i] = read_int (f);

	/* Make sure there are no array-size limit violations */
  for (i = 0; i < 10; i++) {
    if (section_size[i] >= MAX_QBN_ARRAY[i])
      bug ("Error Loading QBN File. Array %d Size Exceeded.", "Filename = '%s' - %d of %d", i, temp_file, section_size[i], MAX_QBN_ARRAY[i]);
   }

	/* Read the Section Offset Info */
  for (i = 0; i < 11; i++)
    section_offset[i] = read_int (f);

	/* Read the Section 0 Data */
  if (fseek (f, section_offset[0] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[0] && i < MAX_QBN0_ARRAY; i++) {
    section0[i].section_index = fgetc (f);
    section0[i].reward_type = read_int (f);
    section0[i].rew1 = read_int (f);
    section0[i].rew2 = read_int (f);
    section0[i].reward = section0[i].rew1 + ((long)section0[i].rew2 << 16);
    section0[i].message_type = read_long (f);
    section0[i].null_bytes = read_long (f);
    section0[i].message_id1 = read_int (f);
    section0[i].message_id2 = read_int (f);
   }

	/* Read the Section 1 Data */
  if (fseek (f, section_offset[1] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[1] && i < MAX_QBN1_ARRAY; i++) {
    bug ("Error: No Size Defined For QBN Section #1", "Filename = '%s'   Section Size = %d", temp_file, section_size[1]);
   }

	/* Read the Section 2 Data */
  if (fseek (f, section_offset[2] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[2] && i < MAX_QBN2_ARRAY; i++) {
    bug ("Error: No Size Defined For QBN Section #2", "Filename = '%s'   Section Size = %d", temp_file, section_size[2]);
   }

	/* Read the Section 3 Data */
  if (fseek (f, section_offset[3] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[3] && i < MAX_QBN3_ARRAY; i++) {
    section3[i].section_index = fgetc(f);
    section3[i].gender = read_int(f);
    section3[i].val1 = fgetc(f);
    section3[i].val2 = read_int (f);
    section3[i].val3 = read_int (f);
    section3[i].message_type = read_long(f);
    section3[i].null_bytes = read_long(f);
    section3[i].message_id1 = read_int(f);
    section3[i].message_id2 = read_int(f);
   }

	/* Read the Section 4 Data */
  if (fseek (f, section_offset[4] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[4] && i < MAX_QBN4_ARRAY; i++) {
    section4[i].section_index = fgetc(f);
    section4[i].null1 = read_int(f);
    section4[i].gen_location = fgetc(f);
    section4[i].location = read_int (f);
    section4[i].val1 = read_int (f);
    section4[i].val2 = read_int (f);
    section4[i].val3 = fgetc (f);
    section4[i].val4 = fgetc (f);
    section4[i].message_type = read_long (f);
    section4[i].null2 = read_long (f);
    section4[i].message_id1 = read_int (f);
    section4[i].message_id2 = read_int (f);
   }

	/* Read the Section 5 Data */
  if (fseek (f, section_offset[5] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[5] && i < MAX_QBN5_ARRAY; i++) {
    bug ("Error: No Size Defined For QBN Section #5", "Filename = '%s'   Section Size = %d", temp_file, section_size[5]);
   }

	/* Read the Section 6 Data */
  if (fseek (f, section_offset[6] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[6] && i < MAX_QBN6_ARRAY; i++) {
    if (!(section6[i].data = new far char[33]))
      bug (MEM_ERR_MSG, "QBN_DATA::load() - section6[i].data (33)");

    if (fread (section6[i].data, sizeof (char), 33, f) != 33) return (FALSE);
   }

	/* Read the Section 7 Data */
  if (fseek (f, section_offset[7] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[7] && i < MAX_QBN7_ARRAY; i++) {
    section7[i].section_index = fgetc(f);
    section7[i].null1 = read_int(f);
    section7[i].mob_index = fgetc(f);
    section7[i].val1 = read_int(f);
    section7[i].message_type = read_long(f);
    section7[i].null2 = read_long (f);
   }

	/* Read the Section 8 Data */
  if (fseek (f, section_offset[8] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[8] && i < MAX_QBN8_ARRAY; i++) {
    if (!(section8[i].data = new far char[87]))
      bug (MEM_ERR_MSG, "QBN_DATA::load() - section8[i].data (87)");

    if (fread (section8[i].data, sizeof (char), 87, f) != 87) return (FALSE);
   }

	/* Read the Section 9 Data */
  if (fseek (f, section_offset[9] , SEEK_SET)) return (FALSE);

  for (i = 0; i < section_size[9] && i < MAX_QBN9_ARRAY; i++) {
    if (!(section9[i].data = new far char[8]))
      bug (MEM_ERR_MSG, "QBN_DATA::load() - section9[i].data (8)");

    if (fread (section9[i].data, sizeof (char), 8, f) != 8) return (FALSE);
   }

	/* Read the section 10 Data */
  if (section10_status && section_offset[10]) {
    if (fseek (f, section_offset[10], SEEK_SET)) return (FALSE);
    i = 0;

	/* Read until end of file */
    while (ftell(f) < filesize && i < MAX_QBN10_ARRAY) {
      if (!(section10[i].data = new far char[27]))
	bug (MEM_ERR_MSG, "QBN_DATA::load() - section10[i].data (27)");

      if (fread (section10[i].data, sizeof (char), 27, f) != 27) return (FALSE);
      i++;
     }

    if (i >= MAX_QBN10_ARRAY) bug ("Error Loading QBN File. Array Size Exceeded.", "Filename = '%s' - %d of %d", temp_file, i, MAX_QBN10_ARRAY);
   } /* End of if Section 10 Read */

  fclose (f);

	/* Use this data to get the current type of quest we just loaded */
  parse_filename (filename);

  delete temp_file;	/* Delete temp string buffer */
  return (TRUE);
 }
/*========== End of Function QBN_DATA::load() =============================*/


/*========== Saves The QRC-Hopefully ======================================*/
boolean QBN_DATA::save (const char far *filename) {
  FILE *f; 	/* File Pointer */
  char *temp_file;	/* For creating the proper filename, QBN */
  int i;	/* Loop counter */

	/* Allocate Temp String Buffer */
  if (!(temp_file = new char[_fstrlen(quest_path) + _fstrlen(filename) + 7]))
    bug (MEM_ERR_MSG, "load_qrc() - *temp_file (%d)", _fstrlen(quest_path) + _fstrlen(filename) + 5);

  _fstrcpy (temp_file, quest_path);

	/* Make sure there is a proper slash at end */
  if (_fstrlen(temp_file) > 0 && *(temp_file + _fstrlen(temp_file) - 1) != '\\')
    chrcat (temp_file, '\\');

  _fstrcat (temp_file, filename);
  _fstrcat (temp_file, ".QBN");

	/* Open QBN file */
  f = openfile (temp_file, "wb");

	/* Write the Header */
  fwrite (header, sizeof (char), 15, f);

	/* Write Section 10 Byte */
  fputc (section10_status, f);

	/* Write the Section Sizes */
  for (i = 0; i < 10; i++)
    write_int (f, section_size[i]);

	/* Write the Section Offsets */
  for (i = 0; i < 11; i++)
    write_int (f, section_offset[i]);

	/* Write Padding 0's */
  write_int (f, 0);

	/* Write the Section 0 Data */
  fseek (f, section_offset[0], SEEK_SET);

  for (i = 0; i < section_size[0]; i++) {
    fputc (section0[i].section_index, f);
    write_int (f, section0[i].reward_type);
    write_long (f, section0[i].reward);
    write_long (f, section0[i].message_type);
    write_long (f, section0[i].null_bytes);
    write_int (f, section0[i].message_id1);
    write_int (f, section0[i].message_id2);
   }

	/* Write the Section 1 Data */
  fseek (f, section_offset[1], SEEK_SET);

  for (i = 0; i < section_size[1]; i++) {
    fwrite (section1[i].data, sizeof (char), 1, f);
   }

	/* Write the Section 2 Data */
  fseek (f, section_offset[2], SEEK_SET);

  for (i = 0; i < section_size[2]; i++) {
    fwrite (section2[i].data, sizeof (char), 1, f);
   }

	/* Write the Section 3 Data */
  fseek (f, section_offset[3], SEEK_SET);

  for (i = 0; i < section_size[3]; i++) {
    fputc (section3[i].section_index, f);
    write_int (f, section3[i].gender);
    fputc (section3[i].val1, f);
    write_int (f, section3[i].val2);
    write_int (f, section3[i].val3);
    write_long (f, section3[i].message_type);
    write_long (f, section3[i].null_bytes);
    write_int (f, section3[i].message_id1);
    write_int (f, section3[i].message_id2);
   }

	/* Write the Section 4 Data */
  fseek (f, section_offset[4], SEEK_SET);

  for (i = 0; i < section_size[4]; i++) {
    fputc (section4[i].section_index, f);
    write_int (f, section4[i].null1);
    fputc (section4[i].gen_location , f);
    write_int (f, section4[i].location);
    write_int (f, section4[i].val1);
    write_int (f, section4[i].val2);
    fputc (section4[i].val3, f);
    fputc (section4[i].val4, f);
    write_long (f, section4[i].message_type);
    write_long (f, section4[i].null2);
    write_int (f, section4[i].message_id1);
    write_int (f, section4[i].message_id2);
   }

	/* Write the Section 5 Data */
  fseek (f, section_offset[5], SEEK_SET);

  for (i = 0; i < section_size[5]; i++) {
    fwrite (section5[i].data, sizeof (char), 1, f);
   }

	/* Write the Section 6 Data */
  fseek (f, section_offset[6], SEEK_SET);

  for (i = 0; i < section_size[6]; i++) {
    fwrite (section6[i].data, sizeof (char), 33, f);
   }

	/* Write the Section 7 Data */
  fseek (f, section_offset[7], SEEK_SET);

  for (i = 0; i < section_size[7]; i++) {
    fputc (section7[i].section_index, f);
    write_int (f, section7[i].null1);
    fputc (section7[i].mob_index, f);
    write_int (f, section7[i].val1);
    write_long (f, section7[i].message_type);
    write_long (f, section7[i].null2);
   }

	/* Write the Section 8 Data */
  fseek (f, section_offset[8], SEEK_SET);

  for (i = 0; i < section_size[8]; i++) {
    fwrite (section8[i].data, sizeof (char), 87, f);
   }

	/* Write the Section 9 Data */
  fseek (f, section_offset[9], SEEK_SET);

  for (i = 0; i < section_size[9]; i++) {
    fwrite (section9[i].data, sizeof (char), 8, f);
   }

	/* Write the section 10 Data */
  if (section10_status) {
    fseek (f, section_offset[10], SEEK_SET);
    i = 0;

	/* Read until end of file */
    while (section10[i].data) {
      fwrite (section10[i].data, sizeof (char), 27, f);
      i++;
     }
   } /* End of if Section 10 Read */

  fclose(f);	/* Close the QBN file */
  delete temp_file;
  return (TRUE);
 }
/*========== End of Function QBN_DATA::save() =============================*/


/*========== Class QRC_DATA Constructor ===================================*/
void QRC_DATA::QRC_DATA (void) {
  int i;	/* Loop Counter */

  for (i = 0; i < MAX_QRC_ARRAY; i++) {
    text[i] = NULL;
   }

  num_entries = 0;

 }
/*========== End Class QRC_DATA Constructor ===============================*/


/*========== Class QRC_DATA Destructor ====================================*/
void QRC_DATA::~QRC_DATA (void) {
  delete_texts();
 }
/*========== End Class QRC_DATA Destructor ================================*/


/*========== Deletes All Allocated Texts Loaded From QRC ==================*/
void QRC_DATA::delete_texts (void) {
  int i;	/* Loop counter */

  for (i = 0; i < MAX_QRC_ARRAY; i++) {
    if (text[i]) {
      delete text[i];
      text[i] = NULL;
     }
   }
 }
/*========== End of Procedure QRC_DATA::delete_texts() ====================*/


/*========== Attempts to load a QRC quest file into memory ================*/
boolean QRC_DATA::load (const char far *filename) {
  FILE *f;	/* File pointer */
  long int file_size;
  int header_size, i, string_length;
  char far *buf, *temp_file;	/* Temp string buffers */
  unsigned char ch;

		/* Allocate memory for temp_string */
  if (!(temp_file = new char[_fstrlen (quest_path) + _fstrlen(filename) + 7]))
    bug (MEM_ERR_MSG, "load_qrc() - *temp_file (%d)", _fstrlen (quest_path) + _fstrlen(filename) + 7);

  _fstrcpy (temp_file, quest_path);

  if (_fstrlen(temp_file) > 0 && *(temp_file + _fstrlen(temp_file) - 1) != '\\')
    chrcat (temp_file, '\\');	/* Make sure there is a proper slash at end */

  _fstrcat (temp_file, filename);
  _fstrcat (temp_file, ".QRC");

	/* Make sure the file exists before opening it */
  if (!fileexists(temp_file)) return(FALSE);

  f = openfile (temp_file, "rb");
  file_size = get_filesize(f);
  delete temp_file;

  header_size = read_int (f);
  i = 0;

	/* Read in header information */
  while (ftell(f) < header_size) { /* Make sure we don't read past the header */
		/* Read in type of text */
    header[i].tag = header[i].type = read_int (f);

		/* Read in offset to start of text from file beginning */
    header[i].offset = read_long (f);

    if (header[i].type != QTEXT_END) quest_texts.texts[i].visible = quest_texts.texts[i].active = TRUE;
    i++;
   } /* End of while reading header loop */

  num_entries = i - 1;

	/* Read in all texts in QRC File */
  for (i = 0; i < num_entries && ftell(f) < file_size; i++) {
    if (header[i].type == QTEXT_END) break;
    string_length = (unsigned int) (header[i + 1].offset - header[i].offset);

	/* Allocate the Text Data */
    if (!(text[i] = new far char[string_length + 10]))
      bug (MEM_ERR_MSG, "load_qrc() - qrc_data.texts[i] (%d)", string_length + 10);

    fseek (f, header[i].offset, SEEK_SET);	//Move to beginning of text data
    buf = text[i];		/* Makes things shorter... */
    *buf = 0;	/* Make sure string is initially nothing */

    while (ftell(f) < header[i+1].offset) { /* Read all of next text */
      ch = fgetc(f);

      if (ch < 0xFC) { /* Normal character? */
	chrcat (buf, (char)ch);
       }
      else if (ch == CR_CENTER) { /* CR, Center aligned type */
	chrcat(buf, CR_CENTER);
       }
      else if (ch == CR_LEFT) { /* CR, Left justified type */
	chrcat (buf, CR_LEFT);
       }
      else if (ch == 0xFE) { /* End of text section */
	break;
       }
      else if (ch == 0xFF) { /* Different text in section begins */
	chrcat((char *)buf, '~');
       }
     } /* End of While reading text section */
   } /* End of for loop */

  fclose(f);
  return(TRUE);
 }
/*========== End of function QRC_DATA::load() =============================*/


/*========== Attempts to save a QRC file ==================================*/
boolean QRC_DATA::save (const char far *filename) {
  FILE *f; 	/* File pointer */
  unsigned offset = 0, i, current_header = 0;
  unsigned header_size = num_entries*6 + 6;;
  char far *buf, *temp_ptr, far *temp_file;

  if (!(temp_file = new far char[_fstrlen (quest_path) + _fstrlen (filename) + 7]))
    bug (MEM_ERR_MSG, "save_qrc() - *temp_file (%d)", _fstrlen (quest_path) + _fstrlen (filename) + 7);

  _fstrcpy (temp_file, quest_path);

  if (_fstrlen(temp_file) > 0 && *(temp_file + _fstrlen(temp_file) - 1) != '\\')
    chrcat (temp_file, '\\');	/* Make sure there is a proper slash at end */

  _fstrcat (temp_file, filename);
  _fstrcat (temp_file, ".QRC");

	/* If file already exists...overwrite? */
  if (fileexists (temp_file)) {

    if (!(buf = new far char[_fstrlen (temp_file) + 20]))
      bug (MEM_ERR_MSG, "save_qrc() = *buf (%d)", _fstrlen (temp_file) + 20);

    sprintf (buf, "Overwrite file '%s'", temp_file);

    if (!get_yn_choice (_fstrlen(buf) + 17, 9, "File Exists", buf)) {
      delete buf;
      delete temp_file;
      return (FALSE);
     }

    delete buf;	/* Delete temp string buffer */
   }
	/* Attempt to open file for writing */
  f = openfile (temp_file, "wb");

	/* Write header size */
  write_int (f, header_size);
  offset = header_size + 2;

	/* Write the header and text information */
  for (i = 0; i < num_entries; i++, current_header++) {
    temp_ptr = text[i];

	/* Allocate data to hold parsed text data for QRC file */
    if (!(buf = new far char[_fstrlen(temp_ptr) + 20]))
      bug (MEM_ERR_MSG, "save_qrc() - *buf (%d)", _fstrlen(temp_ptr) + 20);

    *buf = 0;	/* Make sure string is initially empty */

	/* Parse quest text data into QRC format */
    while (*temp_ptr != 0) { /*  Parse all of quest text */
      if (*temp_ptr == '~')	/* End of part of text section */
	chrcat (buf, 0xFF);
      else	/* Normal character */
	chrcat (buf, *temp_ptr);

      temp_ptr++;
     } /* End of while loop */

    chrcat (buf, 0xFE);	/* End of text section */

	/* Write header - Goto Proper Header Location */
    fseek (f, 2 + current_header*6, SEEK_SET);
    write_int (f, header[i].type);	/* Write text type */
    write_int (f, offset);		/* Write Offset to text */
    fputc (0, f);
    fputc (0, f);

		/* Write Text - Goto Proper Header Location */
    if (header[i].type != QTEXT_END) {
      fseek (f, offset, SEEK_SET);
      fwrite (buf, sizeof(char), _fstrlen(buf), f);
      offset += _fstrlen(buf);	/* Update offset */
     }

    delete buf;
   }

	/* Write terminating header */
  fseek (f, 2 + current_header*6, SEEK_SET);
  write_int (f, 0xFFFF);
  write_int (f, offset);
  fputc (0, f);
  fputc (0, f);
  fclose(f);

  delete temp_file;
  return(TRUE);
 }
/*========== End of function QRC_DATA::save() =============================*/


/*========== Class QRC_HEADER Constructor =================================*/
void QRC_HEADER::QRC_HEADER (void) {
  offset = 0;
  type = 0;
  tag = 0;
 }
/*========== End Class QRC_HEADER Constructor =============================*/


/*========== Class QUEST_TEXT Constructor =================================*/
void QUEST_TEXT::QUEST_TEXT (void) {
  x = 1;
  y = 1;
  active = FALSE;
  visible = FALSE;
 }
/*========== End Class QUEST_TEXT Constructor =============================*/


/*========== Draws One Quest Text Entry on Screen =========================*/
void QUEST_TEXT::draw (const int index) {
  int orig_textattr;

  if (!visible) return;

  orig_textattr = get_textattr ();
  hide_mouse ();

	/* Print title of field */
  gotoxy (x, y);
  textcolor (TEXT_COLOR);
  textbackground (BACK_COLOR);

	/* Display Type and hex_type of Quest Text */
  cprintf ("%*s (%04u) ", QTEXT_TITLE_WIDTH - 8, get_qtext_desc(qrc_data.header[index].tag), qrc_data.header[index].type);

	/* Print value of field, if any */
  textcolor (WIN_TEXT_COLOR);
  textbackground (WIN_BACK_COLOR);

  if (active)
    cprintf (" %-*s ", QTEXT_VALUE_WIDTH, "Yes");
  else
    cprintf (" %-*s ", QTEXT_VALUE_WIDTH, "No");

  textattr (orig_textattr);
  show_mouse ();
 }
//========== End of procedure QUEST_TEXT::draw () ===========================


//========== Class QUEST_TEXT_ARRAY Constructor =============================
void QUEST_TEXT_ARRAY::QUEST_TEXT_ARRAY (void) {
	/* Set all the x-y coordinates for the text fields */
  add_text (15,  8);
  add_text (15, 10);
  add_text (15, 12);
  add_text (15, 14);
  add_text (15, 16);
  add_text (15, 18);
  add_text (15, 20);
  add_text (15, 22);
  add_text (15, 24);
  add_text (15, 26);
  add_text (15, 28);
  add_text (15, 30);
  add_text (15, 32);
  add_text (15, 34);
  add_text (15, 36);
  add_text (15, 38);
  add_text (15, 40);
  add_text (15, 42);
  add_text (48,  8);
  add_text (48, 10);
  add_text (48, 12);
  add_text (48, 14);
  add_text (48, 16);
  add_text (48, 18);
  add_text (48, 20);
  add_text (48, 22);
  add_text (48, 24);
  add_text (48, 26);
  add_text (48, 28);
  add_text (48, 30);
  add_text (48, 32);
  add_text (48, 34);
  add_text (48, 36);
  add_text (48, 38);
  add_text (48, 40);
  add_text (48, 42);
  new_quest ();
 }
/*========== End of Class QUEST_TEXT_ARRAY Constructor ====================*/


/*========== Adds a Quest Text to End of Array ============================*/
boolean QUEST_TEXT_ARRAY::add_text (const int x, const int y, const boolean visible) {
  int i;	/* Loop counter */

  for (i = 0; i < MAX_QRC_ARRAY && texts[i].visible; i++) {
   }

  if (i == MAX_QRC_ARRAY) return (FALSE);
  texts[i].x = x;
  texts[i].y = y;
  texts[i].visible = visible;
  texts[i].active = TRUE;
  return (TRUE);
 }
/*========== End of Function QUEST_TEXT_ARRAY::add_text() =================*/


/*========== Checks the Quest Texts for a mouse click event ===============*/
boolean QUEST_TEXT_ARRAY::check (const int mx, const int my, const int event) {
  int i;		/* Loop Counter */
  char buffer[41];	/* Temp String Buffer */

  if (event != BUTTON_RELEASE) return (FALSE);

  for (i = 0; i < MAX_QRC_ARRAY && texts[i].visible; i++) {
    if (mx >= texts[i].x && mx < texts[i].x + QTEXT_TITLE_WIDTH + QTEXT_VALUE_WIDTH + 3 &&
	my == texts[i].y) {

      sprintf (buffer, "Edit %s (%d)", get_qtext_desc (qrc_data.header[i].tag), qrc_data.header[i].type);

		/* Run the general quest edit window */
      switch (draw_qtext_window (buffer)) {
	case 0:  /* Edit text */

	    if (texts[i].active)
	      convert_qtext (qrc_data.text[i]);
	    else {
	      delete_all_editlines();
	      init_edit();
	     }

	    text_editor (buffer);
	    texts[i].active = convert_edit_list(&qrc_data.text[i]);
	    return (TRUE);
	case 1: /* Delete */
	    texts[i].active = FALSE;

	    if (qrc_data.text[i]) delete qrc_data.text[i];
	    qrc_data.text[i] = NULL;
	    return (TRUE);
       } /* End of switch */

      return (FALSE);
     }
   } /* End of for loop */

  return (FALSE); }
/*========== End of function QUEST_TEXT_ARRAY::check() ====================*/


/*========== Draws Visible Portions of the Array ==========================*/
void QUEST_TEXT_ARRAY::draw (void) {
  int i;	/* Loop counter */

  for (i = 0; i < MAX_QRC_ARRAY && texts[i].visible; i++)
    texts[i].draw (i);

 }
/*========== End of procedure QUEST_TEXT_ARRAY::draw() ====================*/


/*========== Begin Main Program ===========================================*/
boolean main(void) {
  boolean done = FALSE;		/* Loop counter */
  boolean redraw = TRUE;	/* Do we draw the screen or not? */
  int event, i;

  init_dfqedit();		/* Initialize the program */

  do {

    if (redraw) {
      draw_screen();
      show_mouse();
      redraw = FALSE;
     }

	/* Update mouse status */
    event = get_mouse_event (LEFT_BUTTON);

    if ((i = main_buttons.check (MOUSEX, MOUSEY, event)) != -1) {
      switch (i) {
	case 0: click_load();	/* Load */
		redraw = TRUE;
		break;
	case 1: click_save();	/* Save */
		redraw = TRUE;
		break;
	case 2: click_new();	/* New */
		redraw = TRUE;
		break;
	case 3: click_about();	/* About */
		redraw = TRUE;
		break;
	case 4: click_exit();	/* Exit */
		redraw = TRUE;
		break;
	case 5: if (qrc_screen) {	/* Change to QRC/QBN Data screen */
		  qrc_screen = FALSE;
		  _fstrcpy (main_buttons.buttons[5].text, "QRC Data");
		 }
		else {
		  qrc_screen = TRUE;
		  _fstrcpy (main_buttons.buttons[5].text, "QBN Data");
		 }

		redraw = TRUE;
		break;
       } /* End of switch(i) */
     } /* End of if main buttons pressed */
    else if (qrc_screen) {
      if (quest_texts.check (MOUSEX, MOUSEY, event)) {
	redraw = TRUE;
       }
      else if (drag_buttons.check (MOUSEX, MOUSEY, event)) {
	drag_buttons.draw_texts();
	draw_filenames ();
       }
     } /* End of if qrc_screen */
    else {	/* else qbn_screen */
      if ((i = qbn_buttons.check (MOUSEX, MOUSEY, event)) != -1) {
	switch (i) {
	  case 0:	/* Prev Button */
		  if (qbn_data.section_size[qbn_mode] > 1) {
		    current_section[qbn_mode]--;

		    if (current_section[qbn_mode] < 1)
		      current_section[qbn_mode] = qbn_data.section_size[qbn_mode];

		    draw_qbn_screen();
		   }

		  break;

	  case 1: 	/* Add button */
		  break;

	  case 2:	/* Next button */
		  if (qbn_data.section_size[qbn_mode] > 1) {
		    current_section[qbn_mode]++;

		    if (current_section[qbn_mode] > qbn_data.section_size[qbn_mode])
		      current_section[qbn_mode] = 1;

		    draw_qbn_screen();
		   }
		  break;

	  case 3:	/* Item mode */
		  if (qbn_mode != QBN_ITEMS) {
		    qbn_mode = QBN_ITEMS;
		    redraw = TRUE;
		   }
		  break;
	  case 4:	/* NPC mode */
		  if (qbn_mode != QBN_NPCS) {
		    qbn_mode = QBN_NPCS;
		    redraw = TRUE;
		   }
		  break;
	  case 5:	/* Location mode */
		  if (qbn_mode != QBN_LOC) {
		    qbn_mode = QBN_LOC;
		    redraw = TRUE;
		   }
		  break;
	  case 6:	/* Monster mode */
		  if (qbn_mode != QBN_MOB) {
		    qbn_mode = QBN_MOB;
		    redraw = TRUE;
		   }
		  break;


	 } /* End of switch(i) */
       }
      else if (current_section[qbn_mode] > 0) {
	if (qbn_mode == QBN_ITEMS) {
	  if (section_drag[0].check (MOUSEX, MOUSEY, event)) {
	    section_drag[0].draw_texts();
	    get_qbn_data();
	   }
	  else if (section_field[0].check (MOUSEX, MOUSEY, event)) {
	    get_qbn_data();
	    parse_qbn_data();
	    section_field[0].draw();
	   }
	  else if ((i = section_button[0].check (MOUSEX, MOUSEY, event)) != NO_ITEM && i != SCROLL_BAR) {
	    switch (i) {
	      case 0: find_msg(section_drag[0].buttons[ MSG_TYPE_INDEX[0] ].value);
		      break;
	      case 1: edit_msgid ((unsigned) section_field[0].fields[ MSGID1_INDEX[0] ].number);
		      break;
	      case 2: edit_msgid ((unsigned) section_field[0].fields[ MSGID2_INDEX[0] ].number);
		      break;
	     } /* End of switch(i) */
	   }
	 } /* End of if qbn_mode == 0 */
	else if (qbn_mode == QBN_NPCS) {
	  if (section_drag[3].check (MOUSEX, MOUSEY, event)) {
	    section_drag[3].draw_texts();
	    get_qbn_data();
	   }
	  else if (section_field[3].check (MOUSEX, MOUSEY, event)) {
	    get_qbn_data();
	    parse_qbn_data();
	    section_field[3].draw();
	   }
	  else if ((i = section_button[3].check (MOUSEX, MOUSEY, event)) != NO_ITEM && i != SCROLL_BAR) {
	    switch (i) {
	      case 0: find_msg(section_drag[3].buttons[ MSG_TYPE_INDEX[3] ].value);
		      break;
	      case 1: edit_msgid ((unsigned) section_field[3].fields[ MSGID1_INDEX[3] ].number);
		      break;
	      case 2: edit_msgid ((unsigned) section_field[3].fields[ MSGID2_INDEX[3] ].number);
		      break;
	     } /* End of switch(i) */
	   }
	 } /* End of if qbn_mode == 3 */
	else if (qbn_mode == QBN_LOC) {
	  if (section_drag[4].check (MOUSEX, MOUSEY, event)) {
	    section_drag[4].draw_texts();
	    get_qbn_data();
	   }
	  else if (section_field[4].check (MOUSEX, MOUSEY, event)) {
	    get_qbn_data();
	    parse_qbn_data();
	    section_field[4].draw();
	   }
	  else if ((i = section_button[4].check (MOUSEX, MOUSEY, event)) != NO_ITEM && i != SCROLL_BAR) {
	    switch (i) {
	      case 0: find_msg(section_drag[4].buttons[ MSG_TYPE_INDEX[4] ].value);
		      break;
	      case 1: edit_msgid ((unsigned) section_field[4].fields[ MSGID1_INDEX[4] ].number);
		      break;
	      case 2: edit_msgid ((unsigned) section_field[4].fields[ MSGID2_INDEX[4] ].number);
		      break;
	     } /* End of switch(i) */
	   }
	 } /* End of if qbn_mode == 4 */
	else if (qbn_mode == QBN_MOB) {
	  if (section_drag[7].check (MOUSEX, MOUSEY, event)) {
	    section_drag[7].draw_texts();
	    get_qbn_data();
	   }
	  else if (section_button[7].check (MOUSEX, MOUSEY, event) == 0) {
	    find_msg(section_drag[7].buttons[ MSG_TYPE_INDEX[7] ].value);
	   }
	 } /* End of if qbn_mode == 7 */
       }

     } /* End of if qbn_screen */

    GetKey();

    if (get_esc_state()) {
      click_exit();
      redraw = TRUE;
     }

  } while (!done);

  return(TRUE);
 }
/*========== End Main Program =============================================*/