/* Title:   !RunImage.c
 *
 */

#include "wimp.h"
#include "wimpt.h"
#include "win.h"
#include "event.h"
#include "baricon.h"
#include "res.h"
#include "resspr.h"
#include "menu.h"
#include "template.h"
#include "dbox.h"
#include "werr.h"
#include "coords.h"
#include "os.h"
#include "swis.h"
#include "msgs.h"
#include "saveas.h"
#include "xferrecv.h"
#include "visdelay.h"
#include "kernel.h"

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>

#include "main.h"

/********************************* CONSTANTS ********************************/
/*-#define DEBUG-*/

/* Menu items */
#define Main_menu_info     1
#define Main_menu_design   2
#define Main_menu_edit     3
#define Main_menu_ships    4
#define Main_menu_fleets   5
#define Main_menu_fight    6
#define Main_menu_mice     7
#define Main_menu_quit     8

/* Info box fields */
#define Info_name          0
#define Info_purpose       1
#define Info_author        2
#define Info_version       3

#define STAT_CON    0
#define STAT_GEN    1
#define STAT_THR    2
#define STAT_STO    3
#define STAT_LAS    4
#define STAT_SHI    5
#define STAT_ARM    6
#define STAT_DEC    7
#define STAT_EXP    8
#define STAT_DOCKS  9

#define TRUE 1
#define FALSE 0

/******************************** GLOBAL DATA *******************************/

/* Handle for the example window */
wimp_w example_win_handle;
menu iconbar_menu;


dbox desdb = NULL;  /* Ship design dbox */
dbox dockdb = NULL;  /* Dock contents dbox */
dbox pixdb = NULL;  /* Ship char design dbox */
dbox editdb = NULL;  /* Edit ship dbox */
dbox fleet1db = NULL;  /* Fleet selector dbox 1 */
dbox fleet2db = NULL;  /* Fleet selector dbox 2 */
dbox micedb;  /* Mice setup dbox */

menu ship_menu = NULL;  /* Menu containing available ships */
menu flmenu = NULL;  /* Menu containing 'Attacker' and 'Defender'. Wow */

#define MAX_DOCK    5
/* int ship_designed; */  /* Whether a ship has been designed */
int ship_stat[10+MAX_DOCK];  /* Ship statistics */
int max_stat[10];  /* Maximum values for stats */
char dock[MAX_DOCK][10];  /* Name of ship in dock */
int dmass[MAX_DOCK];  /* Mass of ship in dock */
int chr_row[8];  /* Values to pass to VDU23 for ship char */
int pixel[64];   /* Values of pixels in ship char */

int ship_val;  /* Value of ship */
int ship_mass;  /* Mass of ship */
char ship_name[11];  /* Name of ship */
char dir[11];  /* Subdirectory containing ship */

int dock_click;  /* Which dock clicked on for ship_menu(), etc. */
char accn[7];  /* Holds acceleration for calc_acc() */
char ship_names[48][11];  /* Holds list of ships in dir */

/* Used for fleet selection */
int tot_pts;  /* Total points allowed for fleet */
int pts;  /* Points remaining for fleet */
char def[11];  /* Defending player */
char att[11];  /* Attacker */
int ship_points[47];  /* Contains points values of ships */
int ship_number[47];  /* Number of that type of ship in fleet */
int _ship_mass[47];  /* Mass of ship type */
int quant[10];  /* Ship statistics */
char dockf[MAX_DOCK+1][10];  /* Name of ship in dock */
int list;  /* Number of character definitions */
int bits[8][47];  /* Values for VDU23 */
int listnum[47];  /* Number of ships with this char */
char listname[47][11];  /* Name of ship with this char */

/*************************** FUNCTION DEFINITIONS ***************************/

BOOL des_events(dbox dt, void *ve, void *handle);
BOOL pix_events(dbox dt, void *ve, void *handle);
BOOL edit_events(dbox dt, void *ve, void *handle);
BOOL dock_events(dbox dt, void *ve, void *handle);
BOOL fl1_events(dbox dt, void *ve, void *handle);
BOOL fl2_events(dbox dt, void *ve, void *handle);
BOOL mice_events(dbox dt, void *ve, void *handle);
void ship_menu_handler(void *han, char *hit);
void flmenu_handler(void *han, char *hit);
int func_ship_val(void);
int func_ship_points(char *d);
void changed_dock(void);
void open_selectfleets2(int player);

/******************************* COMMON STUFF *******************************/

unsigned getbit(unsigned word, int n)
{
  return (word >> n) & 01;
}

unsigned setbit(unsigned word, int n, unsigned v)
{
  if (v != 0)
    return word | (01 << n);    /* turn on the bit */
  else
    return word & ~(01 << n);   /* turn off the bit */
}

unsigned getbits(unsigned word, int n, int k)
{
   return (word & (~(~0 << k) << n)) >> n;
}

unsigned setbits(unsigned word, int n, int k, unsigned v)
{
   return (word & ~(~(~0 << k) << n)) | (v << n);
}

int mess_min(int a, int b) {if (a<b) return(a); else return(b);}

char *last_2(char *s)
{
int a = 0;
char *i;

   for(i=s; *i != '\0'; i++)
       ;

   for ( ; i != s; i--)
   {
      if (*i=='.') a++;
      if (a == 1)
      {
          return ++i;
      }
   }
   return s;
}


dbox centre_dbox(dbox cd)
{
  int ox0,oy0,ox1,oy1;
  int nx0,ny0,nx1,ny1;
  int width,height;
  int scr_x, scr_y;
  int x_eig,y_eig;
  os_regset regs;

   ox0 = cd->window.box.x0;
   oy0 = cd->window.box.y0;
   ox1 = cd->window.box.x1;
   oy1 = cd->window.box.y1;
   width=ox1 - ox0;
   height=oy0 - oy1;

   regs.r[0]=-1;
   regs.r[1]=11;
   os_swi(0x35,&regs);
   scr_x=regs.r[2];
   regs.r[0]=-1;
   regs.r[1]=12;
   os_swi(0x35,&regs);
   scr_y=regs.r[2];
   regs.r[0]=-1;
   regs.r[1]=4;
   os_swi(0x35,&regs);
   x_eig=regs.r[2];
   regs.r[0]=-1;
   regs.r[1]=5;
   os_swi(0x35,&regs);
   y_eig=regs.r[2];

   scr_x=scr_x<<x_eig;
   scr_y=scr_y<<y_eig;

   nx0=(int) (scr_x - width)/2;
   ny0=(int) (scr_y + height)/2;
   nx1=nx0 + width;
   ny1=ny0 - height;

   cd->window.box.x0 = nx0;
   cd->window.box.y0 = ny0;
   cd->window.box.x1 = nx1;
   cd->window.box.y1 = ny1;

   return(cd);
}

/* Get name of sprite in indirected sprite icon */
void dbox_getsprite(dbox db, wimp_i ic, char *spr) {
  _kernel_swi_regs r;
  int block[64];

  block[0] = (int) db->w;
  block[1] = (int) ic;
  r.r[1] = (int) block;
  _kernel_swi(Wimp_GetIconState, &r, &r);
  strcpy(spr, (char*)block[7]);
}

/* Alter sprite in icon */
/* Icon must be an indirected sprite */
void dbox_setsprite(dbox db, wimp_i ic, char *spr) {
  _kernel_swi_regs r;
  int block[64];

  block[0] = (int) db->w;
  block[1] = (int) ic;
  r.r[1] = (int) block;
  _kernel_swi(Wimp_GetIconState, &r, &r);
  block[2] = 0;
  block[3] = 0;
  strcpy((char*)block[7], "");
  _kernel_swi(Wimp_SetIconState, &r, &r);
  block[2] = 0;
  block[3] = 0;
  strcpy((char*)block[7], spr);
  _kernel_swi(Wimp_SetIconState, &r, &r);
  block[0] = (int) db->w;
  block[1] = (int) ic;
  r.r[1] = (int) block;
  _kernel_swi(Wimp_GetIconState, &r, &r);
  r.r[0] = db->w;
  r.r[1] = block[2];
  r.r[2] = block[3];
  r.r[3] = block[4];
  r.r[4] = block[5];
  _kernel_swi(Wimp_ForceRedraw, &r, &r);
}

/* Place caret in field 'ic' of dbox 'db' */
void dbox_setcaret(dbox db, wimp_i ic) {
  wimp_caretstr caret;

  caret.i = ic;
  caret.w = db->w;
  caret.x = 0;
  caret.y = 0;
  caret.height = -1;
  caret.index = 0;
  wimp_set_caret_pos(&caret);
}

/* Pop up menu at given co-ords in dbox */
void dbox_menupopup(menu m, event_menu_proc fn, dbox db, int x, int y) {
  wimp_eventstr fake;

  event_attachmenu(db->w, m, fn, 0);
  /* Handler fn should dis-attach itself */
  fake.e = wimp_EBUT;
  fake.data.but.m.bbits = wimp_BMID;
  fake.data.but.m.w = db->w;
  fake.data.but.m.i = 0;
  fake.data.but.m.x = x;
  fake.data.but.m.y = y;
  fake.data.but.b = wimp_BMID;
  wimpt_fake_event(&fake);
}

/***************************** WINDOW FUNCTIONS *****************************/



void example_open_window(wimp_openstr *o)
{
  /* Just pass the open request on to the wimp */
  wimpt_noerr(wimp_open_wind(o));
}

void redraw_baricon(wimp_i i)
{
  wimp_icon icon;
  wimp_redrawstr r;

  wimp_get_icon_info(-1,i,&icon);

/*  werr(FALSE,"%i,%i %i,%i",icon.box.x0, icon.box.y0, icon.box.x1, icon.box.y1);
*/
  r.w=-1;
  r.box=icon.box;
  r.box.x0=0;
  r.box.x1=3600;
  r.box.y1=128;
  wimp_force_redraw(&r);

}

/****************************** GAME ROUTINES *******************************/

char *sp_strncpy(char str[512],int len)
{
  int i;
  char tstr[512];
  char ttstr[512];
  int c;

  strcpy(tstr,"");
  for(i=0 ; i<len ; i++)
  {
    c=str[i];
    sprintf(ttstr,"%s%c",tstr,c);
    strcpy(tstr,ttstr);
  }
  return(tstr);
}

/* Fight! */
void battle(void) {
  wimpt_complain(wimp_starttask("Run <Space$Dir>.Battle 2><Space$Dir>.StdErr"));
}

/* Check if player 'p' has a sub-directory */
int chk_pl(char *p, int flag) {
  os_filestr blk;
  char path[256];

  /* Check subdir exists */
  blk.action = 17;
  sprintf(path, "<Space$Dir>.Ships.%s", p);
  blk.name = path;
  os_file(&blk);
  if (blk.action == 0) {
    /* Dir not found */
    if (flag) werr(0, "Player subdirectory '%s' does not exist.", p);
    return FALSE;
  }
  return TRUE;
}

/* Read mass of docked ship 's' in subdir 'd' */
int ship_mass_dock(char *d, char *s, int flag) {
  char path[256];
  FILE* file;
  os_filestr blk;
  int i, m, q;

  /* Sanity check */
  if (strcmp(s, "") == 0) return 0;
  /* Check subdir exists */
  blk.action = 17;
  sprintf(path, "<Space$Dir>.Ships.%s", d);
  blk.name = path;
  os_file(&blk);
  if (blk.action == 0) {
    /* Dir not found */
    if (flag) werr(0, "Player subdirectory '%s' does not exist.", d);
    return FALSE;
  }
  /* Load ship */
  sprintf(path, "<Space$Dir>.Ships.%s.%s", d, s);
  file = fopen(path, "rb");
  if (file == NULL) {
    if (flag) werr(0, "Ship '%s' does not exist. (Function:ship_mass_dock)", s);
    return FALSE;
  }
  m = 0;
  for (i=0; i<10; i++) {
    fscanf(file, "%2x", &q);
    m += q;
  }
  fclose(file);
  return m;
}

/* Load ship from file */
int load_ship(char *subdir, char *leafname) {
  char path[256];
  FILE* file;
  os_filestr blk;
  int i, j;

  /* Check subdir exists */
  blk.action = 17;
  sprintf(path, "<Space$Dir>.Ships.%s", subdir);
  blk.name = path;
  os_file(&blk);
  if (blk.action == 0) {
    /* Dir not found */
    werr(0, "Player subdirectory does not exist.");
    return FALSE;
  }
  /* Load ship */
  sprintf(path, "<Space$Dir>.Ships.%s.%s", subdir, leafname);
  file = fopen(path, "rb");
  if (file == NULL) {
    werr(0, "Ship does not exist.");
    return FALSE;
  }
  ship_mass = 0;
  for (i=0; i<10; i++) {
    fscanf(file, "%2x", &ship_stat[i]);
    ship_mass += ship_stat[i];
  }
  if (ship_stat[STAT_DOCKS] > 0) {
    for (i=1; i<=ship_stat[STAT_DOCKS]; i++) {
      fscanf(file, "%s", dock[i]);
      if (!strcmp(dock[i], "&")) strcpy(dock[i], "");
      dmass[i] = ship_mass_dock(subdir, dock[i], TRUE);
      /* ship_mass += dmass[i]; */
    }
  }
  ship_val = func_ship_val();
  for (i=0; i<8; i++) {
    fscanf(file, "%03d", &chr_row[i]);
    /* werr(0, "row=%d", chr_row[i]); */
    for (j=0; j<8; j++) {
      pixel[i*8+7-j] = ((chr_row[i] & (1<<j)) != 0);
    }
  }
  fclose(file);
  return TRUE;
}

/* Save ship to file */
void save_ship(char *subdir, char* leafname, int flag) {
  /* If flag == TRUE then save as "<Space$Dir>.Ship.<subdir>.<leafname>"
   * else subdir is full path */
  char path[256], str[40];
  FILE *file;
  os_filestr blk;
  int i, j, cho, row;
  dbox error;

  if (flag) {
    /* Check subdir exists */
    blk.action = 17;
    sprintf(str, "<Space$Dir>.Ships.%s", subdir);
    blk.name = str;
    os_file(&blk);
    if (blk.action == 0) {
      /* Dir not found */
      if (error = dbox_new("error"), error != NULL) {
        strcpy(path, msgs_lookup("errss01"));
        dbox_setfield(error, 0, path);
        strcpy(path, msgs_lookup("errss02"));
        dbox_setfield(error, 1, path);
        dbox_show(error);
        cho = dbox_fillin(error);
        dbox_dispose(&error);
        if (cho == 3) {
          /* OK - create subdir */
          sprintf(path, "CDir <Space$Dir>.Ships.%s", subdir);
          os_cli(path);
        } else return;
      } else {
        werr(0, "Unable to create dialogue box 'error'");
        return;
      }
    }
    sprintf(path, "<Space$Dir>.Ships.%s.%s", subdir, leafname);
  } else {
    strcpy(path, subdir);
  }
  /* Check if ship already exists */
  file = fopen(path, "rb");
  if (file != NULL) {
    /* Ship exists */
    fclose(file);
    if (error = dbox_new("error"), error != NULL) {
      strcpy(str, msgs_lookup("errss11"));
      dbox_setfield(error, 0, str);
      strcpy(str, msgs_lookup("errss12"));
      dbox_setfield(error, 1, str);
      dbox_show(error);
      cho = dbox_fillin(error);
      dbox_dispose(&error);
      if (cho != 3) return;
    } else {
      werr(0, "Unable to create dialogue box 'error'");
      return;
    }
  }
  file = fopen(path, "wb");
  for (i=0; i<10; i++) {
    fprintf(file, "%2x", ship_stat[i]);
  }
  fputc(32, file);
  if (ship_stat[STAT_DOCKS]>0) {
    for (i=1; i<=ship_stat[STAT_DOCKS]; i++) {
      if (strcmp(dock[i], "") != 0) {
        fprintf(file, "%s\n", dock[i]);
      } else {
        fprintf(file, "&\n");
      }
    }
  }
  for (i=0; i<64; i+=8) {
    row = 0;
    for (j=0; j<8; j++) {
      row += (pixel[i+j] * (1<<(7-j)));
    }
    fprintf(file, "%03d", row);
  }
  fclose(file);
}

int add_to_list(char *name, char *id) {
  /* Add name to list of character definitions */
  int i, q;
  FILE *file;
  char _dock[11], path[44];

  /*-werr(0, "Adding to list");-*/
  list++;
  strcpy(listname[list], name);
  listnum[list] = 1;
  sprintf(path, "<Space$Dir>.Ships.%s.%s", id, name);
  if (file = fopen(path, "rb"), file == NULL) {
    werr(0, "Ship '%s.%s' not found.", id, name);
    return 0;
  }
  for (i=0; i<10; i++)
    fscanf(file, "%2x", &q);
  if (q > 0) {
    for (i=1; i<=q; i++) {
      fscanf(file, "%s", _dock);
      /*-werr(0, "Dock[%d of %d]=%s", i, q, _dock);-*/
    }
  }
  for (i=0; i<8; i++) {
    fscanf(file, "%03d", &bits[i][list]);
  }
  fclose(file);
  return list;
}

void count(char *name, char *num, int *ch, char *id) {
  /* Increment count for ship type
   * Return a string like #nn in num, and character representation in ch
   * Accumulate list of character definitions */
  int i, found = 0;

  /*-werr(0, "Counting ship; list=%d", list);-*/
  /* Search in list for name */
  for (i=1; i<=list; i++) {
    if (!strcmp(name, listname[i])) found = i;
  }
  /* Add to list? */
  if (found == 0) {
    found = add_to_list(name, id);
  } else {
    listnum[found]++;
  }
  /*-werr(0, "found=%d, listnum=%d, listname=%s", found, listnum[found], listname[found]);-*/
  /* Return parameters */
  sprintf(num, "#%02d", listnum[found]);
  *ch = found - 1;
}

/* Write player's force to file */
void write_force_file(void) {
  char path[256], id[11], num[4];
  int pl, i, j, k, nsh, shpcount, ch, docked;
  FILE *file, *ship;
  int mass, l, q;

  /* Clear ship list */
  list = 0;
  for (i=0; i<47; i++) {
    strcpy(listname[i], "");
    listnum[i] = 0;
  }
  /*-werr(0, "list=%d");-*/

  /* Find correct player */
  dbox_getfield(fleet2db, 0, path, 2);
  if (path[0] == 'A') {
    pl = 2;
    sprintf(path, "<Space$Dir>.Force2");
    strcpy(id, att);
  } else {
    pl = 1;
    sprintf(path, "<Space$Dir>.Force1");
    strcpy(id, def);
  }
  /* Open force file */
  if (file = fopen(path, "wb"), file == NULL) {
    werr(0, "Unable to open force file 'Force%d'", pl);
    return;
  }
  /* Write player's directory */
  fprintf(file, "%s\n", id);
  /* Loop for ship types */
  shpcount = 0; /* So ship docking works correctly */
  nsh = func_ship_points(id);
  /*-werr(0, "List2=%d", list);-*/
  for (i=1; i<=nsh; i++) {
    if (ship_number[i] > 0) {
      /* Read data defining ship type */
      sprintf(path, "<Space$Dir>.Ships.%s.%s", id, ship_names[i]);
      ship = fopen(path, "rb");
      if (ship == NULL) {
        werr(0, "Ship '%s.%s' not found.", id, ship_names[i]);
        fclose(file);
        return;
      }
      /*-werr(0, "Reading ship num %d:%s.%s. List=%d", i, id, ship_names[i], list);-*/
      for (j=0; j<10; j++)
        fscanf(ship, "%2x", &quant[j]);
      if (quant[STAT_DOCKS] > 0) {
        /*-werr(0, "Docks=%d, List=%d", quant[STAT_DOCKS], list);-*/
        for (j=1; j<=quant[STAT_DOCKS]; j++) {
          fscanf(ship, "%s", dockf[j]);
          /*-werr(0, "dock[%d]=%s, list=%d", j, dockf[j], list);-*/
          if (!strcmp(dockf[j], "&")) strcpy(dockf[j], "");
        }
      }
      fclose(ship);
      /* Loop for individual ships */
      for (j=1; j<=ship_number[i]; j++) {
        /* Increment count */
        shpcount++;
        /*-werr(0, "Writing ship %d; shpcount=%d, list=%d", j, shpcount, list);-*/
        /* Write data for ship */
        count(ship_names[i], num, &ch, id); if (ch<0) {fclose(file); return;}
        fprintf(file, "%s%s%s", ship_names[i], sp_strncpy("         ", 9-strlen(ship_names[i])), num);
        fputc(0, file);
        fprintf(file, "%03d", ch);
        for (k=0; k<10; k++)
          fprintf(file, "%2x", quant[k]);
        fputc(32, file);
        fprintf(file, "%03d000", _ship_mass[i]);
        /* Loop for ships docked onto this one */
        docked = -shpcount;
        if (quant[STAT_DOCKS] > 0) {
          for (k=1; k<=quant[STAT_DOCKS]; k++) {
            if (strcmp(dockf[k], "") != 0) {
              shpcount++;  /* Increment count */
              count(dockf[k], num, &ch, id); if(ch<0) {fclose(file); return;}
              sprintf(path, "<Space$Dir>.Ships.%s.%s", id, dockf[k]);
              if (ship = fopen(path, "rb"), ship == NULL) {
                werr(0, "Ship '%s.%s' not found.", id, dockf[k]);
                fclose(file);
                return;
              }
              fprintf(file, "%s%s%s", dockf[k], sp_strncpy("         ", 9-strlen(dockf[k])), num);
              fputc(0, file);
              fprintf(file, "%03d", ch);
              mass = 0;
              for (l=0; l<10; l++) {
                fscanf(ship, "%2x", &q);
                fprintf(file, "%2x", q);
                mass += q;
              }
              fputc(32, file);
              fclose(ship);
              fprintf(file, "%03d%03d", mass, docked);
            }
          }
        }
      }
    }
  }
  fprintf(file, "*END*       ");
  fputc(0, file);
  /* Write data for character representations */
  for (i=1; i<=list; i++) {
    for (j=0; j<8; j++) {
      fprintf(file, "%03d", bits[j][i]);
    }
  }
  fclose(file);
  /* Sort out dboxes */
  dbox_dispose(&fleet2db);
  fleet2db = NULL;
  if (pl == 1) {
    open_selectfleets2(2);
  }
}

/* Calculate ship acceleration */
char *calc_acc(void) {

  if (ship_mass == 0 || ship_stat[STAT_GEN] == 0) {
    strcpy(accn, "0");
  } else {
    sprintf(accn, "%2.3f", (float)(10.0f * (float)ship_stat[STAT_THR] / (float)ship_mass));
  }
  /* werr(0, "accn=%s", accn); */
  return accn;
}

int powval(int mass) {
  if (mass != 0) {
    return (int)(pow((double) mass, 1.188));
  } else {
    return 0;
  }
}

/* Calculate value of ship being designed */
int func_ship_val(void) {
  int val, i;

  val = powval(ship_mass);
  if (ship_stat[STAT_DOCKS] > 0) {
    for (i=1; i<=ship_stat[STAT_DOCKS]; i++) {
      val += powval(dmass[i]);
    }
  }
  return val;
}

/* Display ship details in desdb */
void put_details(void) {
  int i;

  if (desdb == NULL) return;

  for (i=0; i<10; i++) {
    dbox_setnumeric(desdb, 16+i, ship_stat[i]);
  }
  dbox_setfield(desdb, 1, dir);
  dbox_setfield(desdb, 3, ship_name);
  dbox_setnumeric(desdb, 48, ship_mass);
  dbox_setnumeric(desdb, 52, ship_val);
  dbox_setfield(desdb, 44, calc_acc());

  if (dockdb == NULL) return;
  changed_dock();
}

/* Reset ship statistics to 0 */
void reset_shipstats(void) {
  int i;

  for (i=0; i<10; i++) {
    ship_stat[i] = 0;
    max_stat[i] = 10;
  }
  max_stat[STAT_DOCKS] = MAX_DOCK;
  for (i=0; i<5; i++) {
    ship_stat[10+i] = 0;
    strcpy(dock[i], "");
    dmass[i] = 0;
  }
  for (i=0; i<64; i++) {
    pixel[i] = 0;
  }
  for (i=0; i<8; i++) {
    chr_row[i] = 0;
  }

  ship_val = 0;
  ship_mass = 0;
  /* ship_designed = FALSE; */
  strcpy(ship_name, "");
  strcpy(dir, "");
}

/* Get ship details from writable icons */
void get_shipstats(void) {
  int i;

  ship_mass = 0;
  ship_val = 0;
  dbox_getfield(desdb, 3, ship_name, 10);
  dbox_getfield(desdb, 1, dir, 10);
  for (i=0; i<10; i++) {
    ship_stat[i] = dbox_getnumeric(desdb, i+16);
    ship_mass += ship_stat[i];
  }
  if (ship_stat[STAT_DOCKS] > 0) {
    for (i=1; i<=ship_stat[STAT_DOCKS]; i++) {
      if (dockdb != NULL) dbox_getfield(dockdb, i+4, dock[i], 10);
      dmass[i] = ship_mass_dock(dir, dock[i], TRUE);
      /* ship_mass += dmass[i]; */
    }
  }
  ship_val = func_ship_val();
}

/* Alter display in dockdb */
void changed_dock(void) {
  int i;

  if (dockdb == NULL) {
    if (dockdb = dbox_new("docks"), dockdb == NULL) {
      werr(0, "Unable to create dialogue box 'docks'");
      return;
    }
    dbox_raw_eventhandler(dockdb, dock_events, 0);
    dbox_showstatic(dockdb);
  }
  for (i=1; i<=MAX_DOCK; i++) {
    dbox_setfield(dockdb, i-1+MAX_DOCK, dock[i]);
    if (i>ship_stat[STAT_DOCKS]) {
      dbox_fadefield(dockdb, i-1);
      dbox_fadefield(dockdb, i-1+MAX_DOCK);
      dbox_fadefield(dockdb, i-1+MAX_DOCK*2);
    } else {
      dbox_unfadefield(dockdb, i-1);
      dbox_unfadefield(dockdb, i-1+MAX_DOCK);
      dbox_unfadefield(dockdb, i-1+MAX_DOCK*2);
    }
  }
}

/* Get value of ship "<Space$Dir>.Ships.<d>.<s>" */
int ship_val_file(char *d, char *s, int* mass) {
  FILE *file;
  int val, m, q, i;
  char path[256];

  if (!chk_pl(d, TRUE)) return 0;
  sprintf(path, "<Space$Dir>.Ships.%s.%s", d, s);
  file = fopen(path, "rb");
  if (file == NULL) {
    werr(0, "Ship '%s.%s' not found.", d, s);
    return 0;
  }
  m = 0;
  for (i=0; i<10; i++) {
    fscanf(file, "%2x", &q);
    m += q;
  }
  val = powval(m);
  *mass = m;
  if (q>0) {
    /* Docks present */
    for (i=1; i<=q; i++) {
      fscanf(file, "%s", path);
      if (strcmp(path, "&") != 0) {
        m = ship_mass_dock(d, path, TRUE);
        val += powval(m);
        *mass += m;
      }
    }
  }
  fclose(file);
  return val;
}

/* Create list of ships in directory 'd' and place in ship_names[] */
int create_ship_list(char *d) {
  os_filestr blk;
  _kernel_swi_regs r;
  char path[256], buffer[256];
  int i;

  /* Check subdir exists */
  if (strcmp(d, "") == 0) {
    werr(0, "Player subdirectory not given.", d);
    return 0;
  }
  blk.action = 17;
  sprintf(path, "<Space$Dir>.Ships.%s", d);
  blk.name = path;
  os_file(&blk);
  if (blk.action == 0) {
    /* Dir not found */
    werr(0, "Player subdirectory '%s' does not exist.", d);
    return 0;
  }
  /* Read directory */
  strcpy(ship_names[0], "");
  r.r[0] = 10;
  r.r[1] = (int) path;
  r.r[2] = (int) buffer;
  r.r[4] = 0;
  r.r[5] = 256;
  r.r[6] = '*';
  i=1;
  do {
    r.r[3] = 1;
    _kernel_swi(OS_GBPB, &r, &r);
    strcpy(ship_names[i], buffer+20);
    if (strcmp(ship_names[i], ship_names[i-1])) i++; else strcpy(ship_names[i], "");
    /* werr(0, "C PASSED, i=%d, r3=%d, name=%s", i, r.r[3], buffer+20); */
  } while (r.r[4] != -1 && i<47);
  return i;
}

/* Get list of all ships in dir 'd' and their points values */
int func_ship_points(char *d) {
  int n, s;

  n = create_ship_list(d) - 1;
  if (n < 0) return 0;
  for (s=1; s<=n; s++) {
    ship_points[s] = ship_val_file(d, ship_names[s], &_ship_mass[s]);
  }
  return n;
}

/* Create a menu descriptor from list in ship_names[] */
char *get_menudesc_from_ship_list(int ext) {
  char *desc, *ptr;
  int i, n;

  if (desc = malloc(sizeof(char)*ext*11), desc == NULL) {
    werr(1, "Unable to allocate memory for ship list");
    return desc;
  }
  ptr = desc;
  /* Write list */
  for (i=1; i<ext; i++) {
    n = sprintf(ptr, "%s,", ship_names[i]);
    ptr += n;
  }
  *(ptr-1) = 0;
  return desc;
}

/* Create menu of available ships */
void proc_ship_menu(int x, int y) {
  int extent;
  char *desc, title[17];
  wimp_eventstr fake;

  if (ship_menu != NULL) {
    event_attachmenu(dockdb->w, 0, ship_menu_handler, 0);
    menu_dispose(&ship_menu, 0);
    ship_menu = NULL;
    #ifdef DEBUG
    werr(0, "ship_menu not destroyed");
    #endif
  }
  if (!strcmp(dir, "")) {werr(0, "No player specified");return;}

  extent = create_ship_list(dir); /* Extent is index of last entry + 1 */
  if (extent == 0) return;
  desc = get_menudesc_from_ship_list(extent);
  sprintf(title, "Ships:%s", dir);
  if (ship_menu = menu_new(title, desc), ship_menu == NULL) {
    werr(0, "Unable to create ship menu");
    free(desc);
    return;
  }
  free(desc);
  event_attachmenu(dockdb->w, ship_menu, ship_menu_handler, 0);
  /* Fake menu click */
  fake.e = wimp_EBUT;
  fake.data.but.m.bbits = wimp_BMID;
  fake.data.but.m.w = dockdb->w;
  fake.data.but.m.i = dock_click;
  fake.data.but.m.x = x;
  fake.data.but.m.y = y+10;
  fake.data.but.b = wimp_BMID;
  wimpt_fake_event(&fake);
}

/* Open ship design window */
void open_designship(void) {
  /* dbox error;
  dbox_field cho = 0;
  char str[40];

  if (ship_designed) {
    if (error = dbox_new("error"), error != NULL) {
      strcpy(str, msgs_lookup("errsd1"));
      dbox_setfield(error, 0, str);
      strcpy(str, msgs_lookup("errsd2"));
      dbox_setfield(error, 1, str);
      strcpy(str, msgs_lookup("errsd3"));
      dbox_setfield(error, 2, str);
      dbox_show(error);
      cho = dbox_fillin(error);
      dbox_dispose(&error);

      if (cho == 3) { */
        /* OK clicked - reset stats */
        /* if (ship_stat[STAT_DOCKS] > 0) {
          ship_stat[STAT_DOCKS] = 0;
          changed_dock();
        }
        reset_shipstats();
      }
    } else {
      werr(0, "Unable to create dialogue box 'error'");
      return;
    }
  } */

  if (desdb == NULL) {
    if (desdb = dbox_new("design"), desdb == NULL) {
      werr(0, "Unable to create dialogue box 'design'");
      return;
    } else {
      dbox_raw_eventhandler(desdb, des_events, 0);
      dbox_showstatic(desdb);
    }
  }
  if (ship_stat[STAT_DOCKS] > 0) {
    changed_dock();
  }
  put_details();
}

void edit_ship(void) {

  if (load_ship(dir, ship_name)) {
    open_designship();
  }
}

/* Open ship edit dbox */
void open_editship(void) {
  if (editdb == NULL) {
    if (editdb = dbox_new("edit"), editdb == NULL) {
      werr(0, "Unable to create dialogue box 'edit'");
      return;
    } else {
      dbox_raw_eventhandler(editdb, edit_events, 0);
      dbox_showstatic(editdb);
    }
  }
  dbox_setfield(editdb, 2, dir);
  dbox_setfield(editdb, 3, ship_name);
}

/* Open ship char design dbox */
void open_pixdb(void) {
  int i, mass = 0;
  char s[10];

  if (pixdb != NULL) return;

  if (pixdb = dbox_new("ship"), pixdb == NULL) {
    werr(0, "Unable to create dialogue box 'ship'.");
    return;
  }

  dbox_raw_eventhandler(pixdb, pix_events, 0);
  dbox_showstatic(pixdb);
  dbox_setnumeric(pixdb, 66, ship_mass);
  strcpy(s, "pix0");
  for (i=0; i<64; i++) {
    /* Set/Unset pixels */
    s[3] = '0'+pixel[i];
    dbox_setsprite(pixdb, i, s);
    mass += pixel[i];
  }
  mass = ship_mass - mass;
  if (mass == 0) {
    dbox_setfield(pixdb, 65, "Done");
    dbox_unfadefield(pixdb, 67);
  } else {
    dbox_fadefield(pixdb, 67);
    if (mass < 0) {
      sprintf(s, "Remove %d", -mass);
      dbox_setfield(pixdb, 65, s);
    } else {
      sprintf(s, "Add %d", mass);
      dbox_setfield(pixdb, 65, s);
    }
  }
}

/* Open 1st fleet selector dbox */
void open_selectfleets1(void) {

  if (fleet1db == NULL) {
    if (fleet1db = dbox_new("fleet"), fleet1db == NULL) {
      werr(0, "Unable to create dialogue box 'fleet'");
      return;
    } else {
      dbox_raw_eventhandler(fleet1db, fl1_events, 0);
      dbox_showstatic(fleet1db);
    }
  }
  dbox_setnumeric(fleet1db, 1, tot_pts);
  dbox_setcaret(fleet1db, 1);
}

/* Open 2nd fleet selector window */
void open_selectfleets2(int player) {
  int s, i, nsh;
  char *pl, str[16];

  /* Count appropriate players ships and store their points values */
  if (player == 1) {
    if (strcmp(def, "") == 0) return;
    nsh = func_ship_points(def);
    pl = "Defending";
  } else {
    if (strcmp(att, "") == 0) return;
    nsh = func_ship_points(att);
    pl = "Attacking";
  }
  if (nsh == 0) {
    werr(0, "%s player has no ships!", pl);
    return;
  }

  /* Open dbox */
  if (fleet2db == NULL) {
    if (fleet2db = dbox_new("fleet2"), fleet2db == NULL) {
      werr(0, "Unable to create dialogue box 'fleet2'");
      return;
    }
    dbox_raw_eventhandler(fleet2db, fl2_events, 0);
    dbox_showstatic(fleet2db);
  }
  sprintf(str, "%s fleet", pl);
  dbox_setfield(fleet2db, 0, str);
  dbox_setnumeric(fleet2db, 7, tot_pts);
  pts = tot_pts;
  /* Ships start at icon 11. (icon-11)%4 gives:
   *                                     0 = name and points value
   *                                     1 = left arrow
   *                                     2 = number of that type of ship
   *                                     3 = right arrow */
  for (s=1; s<47; s++) {
    if (s <= nsh) {
      sprintf(str, "%s %d", ship_names[s], ship_points[s]);
      dbox_setfield(fleet2db, s*4+7, str);
      dbox_setfield(fleet2db, s*4+9, "0");
      for (i=1; i<5; i++) {
        dbox_unfadefield(fleet2db, s*4+i+6);
      }
    } else {
      dbox_setfield(fleet2db, s*4+7, "<No ship>");
      dbox_setfield(fleet2db, s*4+9, "0");
      for (i=1; i<5; i++) {
        dbox_fadefield(fleet2db, s*4+i+6);
      }
    }
    ship_number[s] = 0;
  }
}

void open_micesetup(void) {

  if (micedb == NULL) {
    if (micedb = dbox_new("mice"), micedb == NULL) {
      werr(0, "Unable to create dialogue box 'mice'");
      return;
    }
    dbox_raw_eventhandler(micedb, mice_events, 0);
    dbox_showstatic(micedb);
  }
}

/****************************** EVENT HANDLERS ******************************/

void flmenu_handler(void *han, char *hit) {
  char str[2];
  int pl;

  han=han;
  event_attachmenu(fleet2db->w, 0, flmenu_handler, 0);
  dbox_getfield(fleet2db, 0, str, 2);
  if (str[0] == 'A') pl = 2; else pl = 1;
  if (hit[0] != pl) {
    /* Change player selecting fleet */
    pl = 3 - pl;
    open_selectfleets2(pl);
  }
}

void ship_menu_handler(void *han, char *hit) {
  os_filestr blk;
  char path[256];

  han=han;
  if (desdb != NULL) dbox_getfield(desdb, 1, dir, 11);
  /* Check subdir exists */
  blk.action = 17;
  sprintf(path, "<Space$Dir>.Ships.%s", dir);
  blk.name = path;
  os_file(&blk);
  if (blk.action == 0) {
    /* Dir not found */
    werr(0, "Player subdirectory '%s' does not exist.", dir);
    return;
  }
  /* Place ship name in icon 'dock_click+1-MAX_DOCK*2' */
  /* ship_mass -= dmass[dock_click+1-MAX_DOCK*2]; */
  strcpy(dock[dock_click+1-MAX_DOCK*2], ship_names[(int)hit[0]]);
  dmass[dock_click+1-MAX_DOCK*2] = ship_mass_dock(dir, ship_names[(int)hit[0]], TRUE);
  /* ship_mass += dmass[dock_click+1-MAX_DOCK*2]; */
  ship_val = func_ship_val();
  put_details();
  event_attachmenu(dockdb->w, 0, ship_menu_handler, 0);
  menu_dispose(&ship_menu, 0);
  ship_menu = NULL;
}

BOOL mice_events(dbox dt, void *ve, void *handle) {
  /* Events in mice setup dbox */
  wimp_eventstr *e;
  wimp_icon res;
  FILE *f;

  e = (wimp_eventstr*) ve;
  handle = handle;

  switch (e->e) {
    case wimp_ECLOSE:
      dbox_dispose(&dt);
      micedb = NULL;
      break;

    case wimp_EBUT:
      if (e->data.but.m.bbits != wimp_BMID) {
        switch(e->data.but.m.i) {
          case 4:
          case 7:
            /* Def,sel or Att,adj*/
            wimp_get_icon_info(dt->w, e->data.but.m.i, &res);
            if (res.flags & wimp_ISELECTED) {
              wimp_set_icon_state(dt->w, 4, wimp_ISELECTED, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 5, 0, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 6, 0, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 7, wimp_ISELECTED, wimp_ISELECTED);
            } else {
              wimp_set_icon_state(dt->w, 4, 0, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 5, wimp_ISELECTED, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 6, wimp_ISELECTED, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 7, 0, wimp_ISELECTED);
            }
            break;
          case 5:
          case 6:
            /* Def,adj or Att,sel */
            wimp_get_icon_info(dt->w, e->data.but.m.i, &res);
            if (res.flags & wimp_ISELECTED) {
              wimp_set_icon_state(dt->w, 4, 0, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 5, wimp_ISELECTED, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 6, wimp_ISELECTED, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 7, 0, wimp_ISELECTED);
            } else {
              wimp_set_icon_state(dt->w, 4, wimp_ISELECTED, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 5, 0, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 6, 0, wimp_ISELECTED);
              wimp_set_icon_state(dt->w, 7, wimp_ISELECTED, wimp_ISELECTED);
            }
            break;
          case 8:
            /* OK */
            wimpt_complain(wimp_get_icon_info(dt->w, 4, &res));
            if (f = fopen("<Space$Dir>.Choices", "wb"), f == NULL) {
              werr(0, "Unable to open Choices file");
              return FALSE;
            }
            if (res.flags & wimp_ISELECTED) {
              fputc('4', f);
              fputc('3', f);
            } else {
              fputc('3', f);
              fputc('4', f);
            }
            fclose(f);
            dbox_dispose(&micedb);
            micedb = NULL;
            break;
        }
      }
  }
  return FALSE;
}

BOOL fl2_events(dbox dt, void *ve, void *handle) {
  /* Events in fleet selection 2 dbox */
  wimp_eventstr *e;
  int arrow, ship, icn;
  wimp_mousestr mouse;

  e = (wimp_eventstr*) ve;
  handle = handle;

  switch (e->e) {
    case wimp_EBUT:
      if (e->data.but.m.bbits == wimp_BLEFT) {
        icn = e->data.but.m.i;
        if (icn > 10) {
          arrow = (icn-11)%4;
          ship = ((icn-11)/4) + 1;
          if (arrow == 1) {
            /* Left arrow: decrease number */
            if (ship_number[ship] > 0) {
              ship_number[ship]--;
              pts += ship_points[ship];
              dbox_setnumeric(fleet2db, 7, pts);
              dbox_setnumeric(fleet2db, ship*4+9, ship_number[ship]);
            }
          }
          if (arrow == 3) {
            /* Right arrow: increase number */
            if (pts - ship_points[ship] >= 0 && ship_points[ship] > 0) {
              ship_number[ship]++;
              pts -= ship_points[ship];
              dbox_setnumeric(fleet2db, 7, pts);
              dbox_setnumeric(fleet2db, ship*4+9, ship_number[ship]);
            }
          }
        }
        if (icn == 8) {
          /* Done */
          write_force_file();
        }
        if (icn == 1) {
          wimpt_complain(wimp_get_point_info(&mouse));
          dbox_menupopup(flmenu, flmenu_handler, fleet2db, mouse.x - 60, mouse.y + 10);
        }
      }
      break;

    case wimp_ECLOSE:
      dbox_dispose(&fleet2db);
      fleet2db = NULL;
      break;
  }
  return FALSE;
}

BOOL fl1_events(dbox dt, void *ve, void *handle) {
  /* Events in fleet selection 1 dbox */
  wimp_eventstr *e;

  e = (wimp_eventstr*) ve;
  handle = handle;

  switch (e->e) {
    case wimp_EBUT:
      if (e->data.but.m.bbits == wimp_BLEFT) {
        switch (e->data.but.m.i) {
          case 5:
            /* Cancel */
            dbox_dispose(&fleet1db);
            fleet1db = NULL;
            break;
          case 4:
            /* OK */
            tot_pts = dbox_getnumeric(dt, 1);
            pts = tot_pts;
            dbox_getfield(dt, 2, def, 11);
            dbox_getfield(dt, 3, att, 11);
            if (!chk_pl(def, 0)) {
              werr(0, "Defender subdirectory not found.");
              return FALSE;
            }
            if (!chk_pl(att, 0)) {
              werr(0, "Attacker subdirectory not found.");
              return FALSE;
            }
            dbox_dispose(&fleet1db);
            fleet1db = NULL;
            open_selectfleets2(1);
            break;
        }
      }
      break;

    case wimp_ECLOSE:
      dbox_dispose(&fleet1db);
      fleet1db = NULL;
      break;

    case wimp_EKEY:
      if (e->data.key.chcode == 13 && e->data.key.c.i == 3) {
        /* OK */
        tot_pts = dbox_getnumeric(dt, 1);
        pts = tot_pts;
        dbox_getfield(dt, 2, def, 11);
        dbox_getfield(dt, 3, att, 11);
        if (!chk_pl(def, 0)) {
          werr(0, "Defender subdirectory not found.");
          return FALSE;
        }
        if (!chk_pl(att, 0)) {
          werr(0, "Attacker subdirectory not found.");
          return FALSE;
        }
        dbox_dispose(&fleet1db);
        fleet1db = NULL;
        open_selectfleets2(1);
      }
      break;
  }
  return FALSE;
}

BOOL dock_events(dbox dt, void *ve, void *handle) {
  /* Events in docks dbox */
  wimp_eventstr *e;

  e = (wimp_eventstr*) ve;
  handle = handle;

  if (ship_menu != NULL && e->data.but.m.bbits != wimp_BMID && (e->e == wimp_EBUT || e->e == wimp_ECLOSE)) {
    event_attachmenu(dockdb->w, 0, ship_menu_handler, 0);
    menu_dispose(&ship_menu, 0);
    ship_menu = NULL;
  }

  switch (e->e) {
    case wimp_EBUT:
      if (e->data.but.m.i > 9 && ship_menu == NULL) {
        if (desdb != NULL) {
          dbox_getfield(desdb, 1, dir, 11);
        }
        dock_click = e->data.but.m.i;
        proc_ship_menu(e->data.but.m.x-40, e->data.but.m.y);
      }
      break;
    case wimp_ECLOSE:
      dbox_dispose(&dockdb);
      dockdb = NULL;
      break;
  }
  return FALSE;
}

BOOL edit_events(dbox dt, void *ve, void *handle) {
  /* Events in edit ship dbox */
  wimp_eventstr *e;

  e = (wimp_eventstr*) ve;
  handle = handle;

  switch (e->e) {
    case wimp_EBUT:
      switch (e->data.but.m.i) {
        case 5:
          /* Cancel */
          dbox_dispose(&editdb);
          editdb = NULL;
          break;
        case 4:
          /* OK */
          dbox_getfield(editdb, 2, dir, 11);
          dbox_getfield(editdb, 3, ship_name, 11);
          dbox_dispose(&editdb);
          editdb = NULL;
          edit_ship();
          break;
      }
      break;

    case wimp_EKEY:
      if (e->data.key.chcode == 13 && e->data.key.c.i == 3) {
        dbox_getfield(editdb, 2, dir, 11);
        dbox_getfield(editdb, 3, ship_name, 11);
        dbox_dispose(&editdb);
        editdb = NULL;
        edit_ship();
      }
      break;

    case wimp_ECLOSE:
      dbox_dispose(&editdb);
      editdb = NULL;
      break;
  }
  return FALSE;
}

BOOL des_events(dbox dt, void *ve, void *handle) {
  /* Events in design dbox */
  wimp_eventstr *e;
  wimp_i icn;
  wimp_caretstr caret;

  e = (wimp_eventstr*) ve;
  handle=handle;

  if (ship_menu != NULL && (e->e == wimp_EBUT || e->e == wimp_EKEY || e->e == wimp_ECLOSE)) {
    event_attachmenu(dockdb->w, 0, ship_menu_handler, 0);
    menu_dispose(&ship_menu, 0);
    ship_menu = NULL;
  }

  switch (e->e) {

    case wimp_EBUT:
      switch (e->data.but.m.bbits) {
        case wimp_BLEFT:
          get_shipstats();  /* Get contents of WIs */
          icn = e->data.but.m.i;
          if (icn>5 && icn<16) {
            /* Decrease stat */
            if (ship_stat[icn-6] > 0) {
              /* if (icn == 15) ship_mass -= dmass[ship_stat[STAT_DOCKS]]; */
              ship_stat[icn-6]--;
              ship_mass--;
              if (icn == 15) changed_dock();
              ship_val = func_ship_val();
              dbox_setnumeric(dt, icn+10, ship_stat[icn-6]);
              dbox_setnumeric(dt, 52, ship_val);
              dbox_setfield(dt, 44, calc_acc());
              dbox_setnumeric(dt, 48, ship_mass);
            }
          }

          if (icn>25 && icn<36) {
            /* Increase stat */
            if (ship_stat[icn-26] < max_stat[icn-26]) {
              if ( (icn == 26+STAT_LAS || icn == 26+STAT_SHI) && ship_stat[STAT_STO] == 0) {
                werr(0, "You need a storage unit for lasers and shields");
              } else {
                ship_stat[icn-26]++;
                ship_mass++;
                /* if (icn == 35) ship_mass += dmass[ship_stat[STAT_DOCKS]]; */
                if (icn == 35) changed_dock();
                ship_val = func_ship_val();
                dbox_setnumeric(desdb, icn-10, ship_stat[icn-26]);
                dbox_setnumeric(desdb, 52, ship_val);
                dbox_setfield(desdb, 44, calc_acc());
                dbox_setnumeric(desdb, 48, ship_mass);
              }
            } else {
              werr(0, "The maximum for that stat. is %d.", max_stat[icn-26]);
            }
          }

          if (icn == 49) {
            /* OK clicked */
            if (ship_mass>0 && strcmp(ship_name, "") && strcmp(dir, "")) {
              dbox_dispose(&desdb); desdb = NULL;
              if (dockdb) {dbox_dispose(&dockdb); dockdb = NULL;}
              open_pixdb();
            }
            else
            {
              if (ship_mass == 0) {
                werr(0, "The ship needs to have components before its structure can be designed.");
              } else {
                if (!strcmp(ship_name, "")) {
                  werr(0, "You must give the ship a name.");
                } else {
                  if (!strcmp(dir, "")) {
                    werr(0, "You must specify which player the ship is for.");
                  }
                }
              }
            }
          }
          break;
      }
      break;

    case wimp_ECLOSE:
      get_shipstats();
      desdb = NULL;
      dbox_dispose(&dt);
      return FALSE;
      break;

    case wimp_EKEY:
      if (e->data.key.chcode == 13) {
        /* Return pressed */
        if (e->data.key.c.w == desdb->w) {
          icn = e->data.key.c.i;
          if (icn>15 && icn<26) {
            get_shipstats();
            dbox_setnumeric(desdb, 48, ship_mass);
            dbox_setnumeric(desdb, 52, ship_val);
            dbox_setfield(desdb, 44, calc_acc());
            if (icn == 25) caret.i = 0; else caret.i = icn; /* I'm not sure why, but it appears wscp() puts caret in i+1 */
            caret.w = desdb->w;
            caret.x = 0;
            caret.y = 0;
            caret.height = -1;
            caret.index = 0;
            wimp_set_caret_pos(&caret);
            if (icn == 25) changed_dock();
          }
        }
      }
      break;
  }
  return FALSE;
}

BOOL pix_events(dbox dt, void *ve, void *handle) {
  /* Events in 'ship' dbox */
  wimp_eventstr *e;
  wimp_i icn;
  int i, mass = 0;
  char s[10];

  e = (wimp_eventstr*) ve;
  handle=handle;

  switch (e->e) {

    case wimp_EBUT:
      switch (e->data.but.m.bbits) {
        case wimp_BLEFT:
          icn = e->data.but.m.i;
          if (icn < 64) {
            /* Pixel clicked on */
            pixel[icn]++;
            if (pixel[icn] == 2) pixel[icn] = 0;
            /* Toggle pixel sprite */
            sprintf(s, "pix%1d", pixel[icn]);
            dbox_setsprite(pixdb, icn, s);
            for (i=0; i<64; i++) {
              /* Count set pixels */
              mass += pixel[i];
            }
            mass = ship_mass - mass;
            if (mass == 0) {
              dbox_setfield(pixdb, 65, "Done");
              dbox_unfadefield(pixdb, 67);
            } else {
              dbox_fadefield(pixdb, 67);
              if (mass < 0) {
                sprintf(s, "Remove %d", -mass);
                dbox_setfield(pixdb, 65, s);
              } else {
                sprintf(s, "Add %d", mass);
                dbox_setfield(pixdb, 65, s);
              }
            }
          }
          if (icn == 67) {
            /* Ship finished */
            save_ship(dir, ship_name, TRUE);
            dbox_dispose(&pixdb);
            pixdb = NULL;
          }
          if (icn == 68) {
            /* Return to desdb */
            dbox_dispose(&pixdb);
            pixdb = NULL;
            open_designship();
          }
          break;
      }
      break;
    case wimp_ECLOSE:
      dbox_dispose(&pixdb);
      pixdb = NULL;
      break;
  }
  return FALSE;
}

/*--- Event handler called on a left click on the icon. ---*/
static void example_iconclick(wimp_i icon)
{
  dbox d;
  dbox_field f;

  icon = icon; /* We don't need the handle: this stops compiler warning */

  /* Open menu dbox and wait for selection */
  if (d = dbox_new("main"), d != NULL) {
    dbox_show(d);
    f = dbox_fillin_fixedcaret(d);
    switch (f) {
      case 0:
        /* Design ship */
        open_designship();
        break;
      case 1:
        /* Edit ship */
        open_editship();
        break;
      case 2:
        /* Select fleets */
        open_selectfleets1();
        break;
      case 4:
        /* Fight battle */
        battle();
        break;
    }
    dbox_dispose(&d);
  }
}

/*--- Display the program info box - called from the menu processor. ---*/
static void example_info_about_program(void)
{
  dbox  d;  /* Dialogue box handle */
  char str[48];

  /* Create the dialogue box */
  if (d = dbox_new("ProgInfo"), d != NULL)
  {
    /* Fill in the version number */
    strcpy(str, msgs_lookup("info"));
    dbox_setfield(d, Info_version, str);
    dbox_setfield(d, Info_author, " Jonathan Cooper 1999");
    dbox_setfield(d, Info_name, "Space");
    dbox_setfield(d, Info_purpose, "Total destruction");

    /* Show the dialogue box */
    dbox_show(d);

    /* Keep it on the screen as long as needed */
    dbox_fillin(d);

    /* Dispose of the dialogue box */
    dbox_dispose(&d);
  }
}

/*--- Event handler for the menu. ---*/
static void example_menuproc(void *handle, char *hit)
{
  handle = handle; /* We don't need handle: this stops compiler warning */

  /* Find which menu item was hit and take action as appropriate */
  switch (hit[0])
  {
    case Main_menu_info:
      example_info_about_program();
      break;

    case Main_menu_design:
      open_designship();
      break;

    case Main_menu_edit:
      open_editship();
      break;

    case Main_menu_ships:
      wimpt_complain(wimp_starttask("Filer_OpenDir <Space$Dir>.Ships"));
      break;

    case Main_menu_fleets:
      open_selectfleets1();
      break;

    case Main_menu_fight:
      battle();
      break;

    case Main_menu_mice:
      open_micesetup();
      break;

    case Main_menu_quit:
      /* Exit from the program. The wimp gets rid of the window and icon */
      exit(0);
  }
}


/****************************** INITIALISATION ******************************/


/*--- Initialise the program, returning TRUE if it was all OK. ---*/
static BOOL example_initialise(void)
{
  char message[256];
  char mname[32];

  /* RISC_OSlib initialisation */
  wimpt_init("Space");             /* Main Wimp initialisation */
  res_init("Space");               /* Resources */
  resspr_init();                   /* Application sprites */
  template_init();                 /* Templates */
  dbox_init();                     /* Dialogue boxes */
  msgs_init();
  visdelay_init();

  strcpy(message,msgs_lookup("menu0"));
  strcpy(mname,msgs_lookup("menuname0"));
  if (iconbar_menu = menu_new(mname, message), iconbar_menu == NULL)
    return FALSE; /* Menu create failed */
/*
  strcpy(message,msgs_lookup("menu1"));
  strcpy(mname,msgs_lookup("menuname1"));
  if (mode_menu = menu_new(mname, message), mode_menu == NULL)
    return FALSE;
*/

  /* Set up the icon on the icon bar, and declare its event handlers */
  baricon("!space", (int)resspr_area(), example_iconclick);

  /* Install Event Handler for Icon Bar Loading */
  /* win_register_event_handler(win_ICONBARLOAD, loader, 0); */

  if (!event_attachmenu(win_ICONBAR, iconbar_menu, example_menuproc, 0))
    return FALSE; /* Unable to attach menu */

  /* menu_submenu(iconbar_menu,2,mode_menu); */

  /* Create flmenu */
  if (flmenu = menu_new("Fleet:", "Defender,Attacker"), flmenu == NULL)
    return FALSE;

  /* Set default ship stats */
  reset_shipstats();
  tot_pts = 80;

  /* All went ok */
  return TRUE;
}

/******************************* MAIN PROGRAM ********************************/

/*--- Main entry point. ---*/
int main()
{
  if (example_initialise())
  {
    /* event_setmask(wimp_EPTRLEAVE | wimp_EPTRENTER); */
    /* The main event loop */
    while (TRUE)
      event_process();
  }

  return 0;
}
