/* Nertz: multi-player card game
 * by Jonathan Cooper
 *
 * Main Wimp interface
 */

#include "DeskLib:Wimp.h"
#include "DeskLib:WimpSWIs.h"
#include "DeskLib:Window.h"
#include "DeskLib:Error.h"
#include "DeskLib:Event.h"
#include "DeskLib:EventMsg.h"
#include "DeskLib:Handler.h"
#include "DeskLib:Screen.h"
#include "DeskLib:Icon.h"
#include "DeskLib:Menu.h"
#include "DeskLib:Msgs.h"
#include "DeskLib:Resource.h"
#include "DeskLib:Template.h"
#include "DeskLib:Dialog2.h"
#include "DeskLib:SWI.h"
#include "DeskLib:Sprite.h"
#include "DeskLib:GFX.h"

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

#include "nertz.h"
#include "rand.h"

BOOL quit = FALSE;
BOOL playing = FALSE;

menu_ptr mainmenu = NULL;
#define mainmenu_INFO    0
#define mainmenu_PLAY    1
#define mainmenu_LINK    2
#define mainmenu_QUIT    3

icon_handle baricon;

FILE *debugfile;

dialog2_blockptr startgamedb = NULL;
dialog2_blockptr linkgamedb = NULL;
dialog2_blockptr waitingdb = NULL;
window_handle gamewin = NULL;
icon_handle nertz_icon = NULL;
int gamewin_h;
game_data_str game_data;
sprite_area sprites;
scale_block sc_factors;
char pixtrans[16];

char *suitname[5] = {
  "oops", "club", "diamond", "spade", "heart"
};
char *halfsuitname[5] = {
  "oops", "halfclub", "halfdiamond", "halfspade", "halfheart"
};

int drag_from;
card *dragged_card;
int dcard; /* Used for dragging sections of patience piles */

/* Data for scores window */
window_handle scoreswin;
window_info scoresinfo;
icon_block scicons[10];
int *scores;
wimp_box scores_minwork, scores_minscreen;
char sctext[10][15];
char scvalid[10][15];
char **scctext;
int sccsize;

/************************* redraw routines *********************************/

void mark_for_redraw(int area, int pile) {
  window_redrawblock rblk;

  rblk.window = gamewin;
  switch (area) {
    case pile_CENTRE:
      rblk.rect.min.x = (pile % 12) * 68 + 4;
      rblk.rect.max.x = rblk.rect.min.x + 68;
      rblk.rect.max.y = -8 - ((pile / 12) * 96);
      rblk.rect.min.y = rblk.rect.max.y - 96;
      Error_Check(Wimp_ForceRedraw(&rblk));
      break;
    case pile_NERTZ:
      rblk.rect.min.x = 72 - 20;
      rblk.rect.max.x = 140 + 20;
      rblk.rect.max.y = 500 - gamewin_h;
      rblk.rect.min.y = 412 - gamewin_h - 40;
      Error_Check(Wimp_ForceRedraw(&rblk));
      break;
    case pile_TURNOVER:
      rblk.rect.min.x = 548;
      rblk.rect.max.x = 684;
      rblk.rect.max.y = 500 - gamewin_h;
      rblk.rect.min.y = 412 - gamewin_h - 40;
      Error_Check(Wimp_ForceRedraw(&rblk));
      break;
    case pile_PATIENCE:
      rblk.rect.min.x = 4 + 68*(3+pile);
      rblk.rect.max.x = rblk.rect.min.x + 68;
      rblk.rect.min.y = -gamewin_h;
      rblk.rect.max.y = 500 - gamewin_h;
      Error_Check(Wimp_ForceRedraw(&rblk));
      break;
  }
}

void plot_card(card c, wimp_point pos) {
  Error_Check(Sprite_PlotScaled(sprites, suitname[c.suit], &pos, (sprite_scalefactors*)&sc_factors, (void*)pixtrans));
  if (c.suit % 2) Wimp_SetColour(7); else Wimp_SetColour(11);
  GFX_Move(pos.x + 24, pos.y + 72);
  if (c.number>1 && c.number<10) GFX_VDU(c.number + '0');
  if (c.number == 10) {GFX_VDU('1'); GFX_VDU('0');}
  if (c.number == 1) GFX_VDU('A');
  if (c.number == 11) GFX_VDU('J');
  if (c.number == 12) GFX_VDU('Q');
  if (c.number == 13) GFX_VDU('K');
}

void plot_halfcard(card c, wimp_point pos) {
  Error_Check(Sprite_PlotScaled(sprites, halfsuitname[c.suit], &pos, (sprite_scalefactors*)&sc_factors, (void*)pixtrans));
  if (c.suit % 2) Wimp_SetColour(7); else Wimp_SetColour(11);
  GFX_Move(pos.x + 24, pos.y + 32);
  if (c.number>1 && c.number<10) GFX_VDU(c.number + '0');
  if (c.number == 10) {GFX_VDU('1'); GFX_VDU('0');}
  if (c.number == 1) GFX_VDU('A');
  if (c.number == 11) GFX_VDU('J');
  if (c.number == 12) GFX_VDU('Q');
  if (c.number == 13) GFX_VDU('K');
}

void plot_back(wimp_point pos) {
   Error_Check(Sprite_PlotScaled(sprites, "back", &pos, (sprite_scalefactors*)&sc_factors, (void*)pixtrans));
}

void redraw_nertz_pile(wimp_point win_tl) {
  wimp_point pos;

  pos.x = win_tl.x + 8 + 68;
  pos.y = win_tl.y - gamewin_h + 16 + 400;

  if (game_data.player[0].nertz_cards == -1) {
    GFX_GCOL(0, 3);
    /* GFX_Rectangle(pos.x - 10, pos.y + 10, 80, 60); */
    GFX_Move(pos.x - 10, pos.y + 60);
    GFX_Write0("NERTZ");
    return;
  }

  plot_card(game_data.player[0].nertz_pile[game_data.player[0].nertz_cards], pos);

  if (game_data.player[0].nertz_cards >= 0) {
    GFX_GCOL(0, 0);
    GFX_Move(pos.x + 8, pos.y - 4);
    printf("%d", game_data.player[0].nertz_cards+1);
  }
}

void redraw_patience_pile(wimp_point win_tl, int pile) {
  wimp_point pos;
  int i = game_data.player[0].cards[pile];

  if (i == -1) return;
  pos.x = win_tl.x + 8 + 68*(3+pile);
  pos.y = win_tl.y - gamewin_h + 16 + (10 - i)*40;
  plot_card(game_data.player[0].pile[i][pile], pos);
  pos.y += 40;
  while (--i > -1) {
    pos.y += 40;
    plot_halfcard(game_data.player[0].pile[i][pile], pos);
  };
}

void redraw_turnover_pile(wimp_point win_tl) {
  wimp_point pos;

  pos.x = win_tl.x + 8 + 68*8;
  pos.y = win_tl.y - gamewin_h + 16 + 400;
  plot_card(game_data.player[0].turnover_pile[game_data.player[0].turnover_pos], pos);
  pos.x += 68;
  if (game_data.player[0].turnover_pos == game_data.player[0].turnover_cards-1) {
    GFX_GCOL(0, 3);
    GFX_Rectangle(pos.x, pos.y, 60, 80);
  } else {
    plot_back(pos);
  }
  GFX_GCOL(0, 0);
  GFX_Move(pos.x - 32, pos.y - 4);
  printf("%d", game_data.player[0].turnover_cards);
}

void redraw_centre_pile(wimp_point win_tl, int pile) {
  card c;
  wimp_point pos;

  pos.x = win_tl.x + 8 + (pile % 12) * 68;
  pos.y = win_tl.y - (pile/12 + 1) * 96;

  c.suit = game_data.centre_pile[pile].suit;
  c.number = game_data.centre_pile[pile].top;
  plot_card(c, pos);
}

/************************* gamewin_ routines *******************************/

BOOL gamewin_redraw(event_pollblock *ev, void *ref) {
  /* Redraw game window */
  /* There aren't many bounds checks, as it is assumed that when playing the window is at the top of the stack; ie. we'll probably get the whole window in one go. */
  BOOL more;
  window_redrawblock blk;
  wimp_point win_tleft;
  int x0, x1, y0, x;

  ref=ref;

  blk.window = ev->data.openblock.window;
  Error_CheckFatal(Wimp_RedrawWindow(&blk, &more));
  win_tleft.x = blk.rect.min.x - blk.scroll.x;
  win_tleft.y = blk.rect.max.y - blk.scroll.y;
  while (more) {
    x0 = (blk.cliprect.min.x - win_tleft.x - 8) / 68; if (x0 > 11) goto next;
    x1 = (blk.cliprect.max.x - win_tleft.x - 8) / 68; if (x1 < 0) goto next;
    y0 = (win_tleft.y - blk.cliprect.min.y - 16) / 96;
    if (y0 > ((game_data.ai_players+1)/3)) {
      /* Not redrawing centre piles */
      for (x=x0; x<=x1; x++) {
        if (x == 1) redraw_nertz_pile(win_tleft);
        if (x > 2 && x < 7) redraw_patience_pile(win_tleft, x-3);
        if (x > 7) redraw_turnover_pile(win_tleft);
      }
    } else {
      /* Redraw centre piles */
      for (x=0; x<=game_data.centre_piles; x++) {
        if ((x % 12) >= x0 && (x % 12) <= x1) {
          redraw_centre_pile(win_tleft, x);
        }
      }
    }
    next:;
    Error_CheckFatal(Wimp_GetRectangle(&blk, &more));
  };
  return TRUE;
}

BOOL gamewin_close(event_pollblock *ev, void *ref) {
  /* Close game window and end game */
  int *s;

  ref=ref;

  s = calculate_scores(NULL);

  Window_Delete(ev->data.openblock.window);
  free(game_data.player);
  free(game_data.centre_pile);
  Error_Report(0, "You just ended the game.");
  return TRUE;
}

BOOL gamewin_click(event_pollblock *ev, void *ref) {
  /* Mouse click in game window */
  window_info w;
  wimp_point m; /* For co-ords relative to window */
  drag_block d;
  int p, q;

  ref=ref;
  if (!ev->data.mouse.button.data.select) return FALSE;

  w.window = ev->data.mouse.window;
  Error_Check(Wimp_GetWindowInfo(&w));
  m.x = ev->data.mouse.pos.x - (w.block.screenrect.min.x - w.block.scroll.x);
  m.y = ev->data.mouse.pos.y - (w.block.screenrect.max.y - w.block.scroll.y);
  /* Click to turnover? */
  if (m.x > 620 && m.x < 680 && m.y > 416 - gamewin_h && m.y < 496 - gamewin_h) {
    game_data.player[0].turnover_pos = (game_data.player[0].turnover_pos + 3) % game_data.player[0].turnover_cards;
    mark_for_redraw(pile_TURNOVER, 0);
    return TRUE;
  }
  /* Start drag from nertz pile? */
  if (m.x >= 76 && m.x <= 136 && m.y > 416 - gamewin_h && m.y < 496 - gamewin_h) {
    if (game_data.player[0].nertz_cards > -1) {
      d.window = gamewin;
      d.type = drag_FIXEDBOX;
      d.screenrect.min.x = ev->data.mouse.pos.x - 30;
      d.screenrect.min.y = ev->data.mouse.pos.y - 40;
      d.screenrect.max.x = ev->data.mouse.pos.x + 30;
      d.screenrect.max.y = ev->data.mouse.pos.y + 40;
      d.parent.min.x = w.block.screenrect.min.x;
      d.parent.min.y = w.block.screenrect.min.y;
      d.parent.max.x = w.block.screenrect.max.x;
      d.parent.max.y = w.block.screenrect.max.y;
      Error_Check(Wimp_DragBox(&d));
      drag_from = drag_NERTZ;
      dragged_card = &(game_data.player[0].nertz_pile[game_data.player[0].nertz_cards]);
    } else {
      game_over(&game_data.player[0]); /* Player has won */
    }
    return TRUE;
  }
  /* Start drag from patience pile? */
  if (m.x > 204 && m.x < 476 && m.y < 496 - gamewin_h) {
    p = (m.x - 208) / 68;
    q = (496 - gamewin_h - m.y) / 40;
    if (q == game_data.player[0].cards[p] + 1) q--;
    if (game_data.player[0].cards[p] >= q) {
      d.window = gamewin;
      d.type = drag_FIXEDBOX;
      d.screenrect.min.x = ev->data.mouse.pos.x - 30;
      d.screenrect.min.y = ev->data.mouse.pos.y - 40;
      d.screenrect.max.x = ev->data.mouse.pos.x + 30;
      d.screenrect.max.y = ev->data.mouse.pos.y + 40;
      d.parent.min.x = w.block.screenrect.min.x;
      d.parent.min.y = w.block.screenrect.min.y;
      d.parent.max.x = w.block.screenrect.max.x;
      d.parent.max.y = w.block.screenrect.max.y;
      Error_Check(Wimp_DragBox(&d));
      drag_from = drag_PATIENCE + p;
      dragged_card = &(game_data.player[0].pile[q][p]);
      dcard = q;
    }
    return TRUE;
  }
  /* Start drag from turnover pile? */
  if (m.x > 552 && m.x < 612 && m.y > 416 - gamewin_h && m.y < 496 - gamewin_h) {
    d.window = gamewin;
    d.type = drag_FIXEDBOX;
    d.screenrect.min.x = ev->data.mouse.pos.x - 30;
    d.screenrect.min.y = ev->data.mouse.pos.y - 40;
    d.screenrect.max.x = ev->data.mouse.pos.x + 30;
    d.screenrect.max.y = ev->data.mouse.pos.y + 40;
    d.parent.min.x = w.block.screenrect.min.x;
    d.parent.min.y = w.block.screenrect.min.y;
    d.parent.max.x = w.block.screenrect.max.x;
    d.parent.max.y = w.block.screenrect.max.y;
    Error_Check(Wimp_DragBox(&d));
    drag_from = drag_TURNOVER;
    dragged_card = &(game_data.player[0].turnover_pile[game_data.player[0].turnover_pos]);
    return TRUE;
  }
  return TRUE;
}

BOOL gamewin_drag(event_pollblock *ev, void *ref) {
  /* Drag finished */
  mouse_block ptr;
  window_info win;
  wimp_point m;
  int drag_to, i, j;
  player_data *pl = &game_data.player[0];

  ref=ref;
  /* Check we're still playing */
  if (!playing) return TRUE;

  win.window = gamewin;
  Error_Check(Wimp_GetWindowInfo(&win));
  Error_Check(Wimp_GetPointerInfo(&ptr));
  m.x = ptr.pos.x - (win.block.screenrect.min.x - win.block.scroll.x);
  m.y = ptr.pos.y - (win.block.screenrect.max.y - win.block.scroll.y);
  /*-Error_Report(0, "ptr.y=%d, ptr.x=%d, m.x=%d, m.y=%d, min.x=%d, max.y=%d, gamewin_h=%d", ptr.pos.y, ptr.pos.x, m.x, m.y, win.block.screenrect.min.x, win.block.screenrect.max.y, gamewin_h);-*/
  if (m.y > 496 - gamewin_h) {
    /* Dropped on a centre pile */
    drag_to = ((m.x - 4)/68) + ((m.y - 8)/98)*12;
    /*-Error_Report(0, "drag_to=%d, drag_from=%d", drag_to, drag_from);-*/
    switch (drag_from) {
      case drag_NERTZ: /* Dragged from nertz pile */
        if ((dragged_card->suit == game_data.centre_pile[drag_to].suit && dragged_card->number == game_data.centre_pile[drag_to].top + 1) || (dragged_card->number == 1 && drag_to > game_data.centre_piles)) {
          if (drag_to > game_data.centre_piles) {
            drag_to = ++game_data.centre_piles;
            game_data.centre_pile[drag_to].suit = dragged_card->suit;
          }
          game_data.centre_pile[drag_to].top++;
          pl->nertz_cards--;
          mark_for_redraw(pile_CENTRE, drag_to);
          mark_for_redraw(pile_NERTZ, 0);
          /*-Error_Report(0, "drag_to=%d, centre_piles=%d, suit=%d, top=%d", drag_to, game_data.centre_piles, game_data.centre_pile[drag_to].suit, game_data.centre_pile[drag_to].top);-*/
        }
        break;
      case drag_TURNOVER: /* Dragged from turnover pile */
        if ((pl->turnover_pile[pl->turnover_pos].suit == game_data.centre_pile[drag_to].suit && pl->turnover_pile[pl->turnover_pos].number == game_data.centre_pile[drag_to].top + 1) || (pl->turnover_pile[pl->turnover_pos].number == 1 && drag_to > game_data.centre_piles)) {
          if (drag_to > game_data.centre_piles) {
            drag_to = ++game_data.centre_piles;
            game_data.centre_pile[drag_to].suit = pl->turnover_pile[pl->turnover_pos].suit;
          }
          game_data.centre_pile[drag_to].top++;
          pl->turnover_cards--;
          pl->turnover_pos--;
          if (pl->turnover_pos != pl->turnover_cards) {
            for (i=pl->turnover_pos+1; i<pl->turnover_cards; i++) {
              pl->turnover_pile[i].suit = pl->turnover_pile[i+1].suit;
              pl->turnover_pile[i].number = pl->turnover_pile[i+1].number;
            }
          }
          if (pl->turnover_pos < 0) pl->turnover_pos = pl->turnover_cards - 1;
          mark_for_redraw(pile_CENTRE, drag_to);
          mark_for_redraw(pile_TURNOVER, 0);
          /*-Error_Report(0, "drag_to=%d, centre_piles=%d, suit=%d, top=%d", drag_to, game_data.centre_piles, game_data.centre_pile[drag_to].suit, game_data.centre_pile[drag_to].top);-*/
        }
        break;
      case drag_PATIENCE+0: /* Dragged from patience pile */
      case drag_PATIENCE+1:
      case drag_PATIENCE+2:
      case drag_PATIENCE+3:
        if ((game_data.player[0].pile[game_data.player[0].cards[drag_from-drag_PATIENCE]][drag_from-drag_PATIENCE].suit == game_data.centre_pile[drag_to].suit && game_data.player[0].pile[game_data.player[0].cards[drag_from-drag_PATIENCE]][drag_from-drag_PATIENCE].number == game_data.centre_pile[drag_to].top + 1) || (game_data.player[0].pile[game_data.player[0].cards[drag_from-drag_PATIENCE]][drag_from-drag_PATIENCE].number == 1 && drag_to > game_data.centre_piles)) {
          if (drag_to > game_data.centre_piles) {
            drag_to = ++game_data.centre_piles;
            game_data.centre_pile[drag_to].suit = pl->pile[pl->cards[drag_from-drag_PATIENCE]][drag_from-drag_PATIENCE].suit;
          }
          game_data.centre_pile[drag_to].top++;
          pl->cards[drag_from-drag_PATIENCE]--;
          mark_for_redraw(pile_CENTRE, drag_to);
          mark_for_redraw(pile_PATIENCE, drag_from-drag_PATIENCE);
          /*-Error_Report(0, "drag_to=%d, centre_piles=%d, suit=%d, top=%d", drag_to, game_data.centre_piles, game_data.centre_pile[drag_to].suit, game_data.centre_pile[drag_to].top);-*/
        }
        break;
    }
  } else {
    /* Possible drag to patience pile */
    drag_to = ((m.x - 4)/68);
    if (drag_to > 2 && drag_to < 7) {
      /* Dragged to pile drag_to - 3 */
      i = drag_to - 3;
      switch (drag_from) {
        case drag_NERTZ: /* Dragged from nertz pile */
          if ((pl->cards[i] == -1) || ((pl->nertz_pile[pl->nertz_cards].suit % 2) != (pl->pile[pl->cards[i]][i].suit % 2) && pl->nertz_pile[pl->nertz_cards].number == pl->pile[pl->cards[i]][i].number - 1)) {
            pl->cards[i]++;
            pl->pile[pl->cards[i]][i].suit = pl->nertz_pile[pl->nertz_cards].suit;
            pl->pile[pl->cards[i]][i].number = pl->nertz_pile[pl->nertz_cards].number;
            pl->nertz_cards--;
            mark_for_redraw(pile_NERTZ, 0);
            mark_for_redraw(pile_PATIENCE, i);
          }
          break;
        case drag_TURNOVER: /* Dragged from turnover pile */
          if ((pl->cards[i] == -1) || ((pl->turnover_pile[pl->turnover_pos].suit % 2) != (pl->pile[pl->cards[i]][i].suit % 2) && pl->turnover_pile[pl->turnover_pos].number == pl->pile[pl->cards[i]][i].number - 1)) {
            pl->cards[i]++;
            pl->pile[pl->cards[i]][i].suit = pl->turnover_pile[pl->turnover_pos].suit;
            pl->pile[pl->cards[i]][i].number = pl->turnover_pile[pl->turnover_pos].number;
            mark_for_redraw(pile_TURNOVER, 0);
            mark_for_redraw(pile_PATIENCE, i);
            /* Shift turnover pile. Note: corrupts i */
            pl->turnover_cards--;
            pl->turnover_pos--;
            if (pl->turnover_pos != pl->turnover_cards) {
              for (i=pl->turnover_pos+1; i<pl->turnover_cards; i++) {
                pl->turnover_pile[i].suit = pl->turnover_pile[i+1].suit;
                pl->turnover_pile[i].number = pl->turnover_pile[i+1].number;
              }
            }
            if (pl->turnover_pos < 0) pl->turnover_pos = pl->turnover_cards - 1;
            i = drag_to - 3; /* Restore i */
          }
          break;
        case drag_PATIENCE+0:  /* Dragged from patience pile */
        case drag_PATIENCE+1:
        case drag_PATIENCE+2:
        case drag_PATIENCE+3:
          if (drag_from - drag_PATIENCE == i) break; /* Can't drag to same pile */
          i = drag_from - drag_PATIENCE;  /* Note: use of i changes */
          drag_to -= 3;  /* Note: drag_to changed */
          if ((pl->cards[drag_to] == -1) || ((dragged_card->suit % 2) != (pl->pile[pl->cards[drag_to]][drag_to].suit % 2) && dragged_card->number == pl->pile[pl->cards[drag_to]][drag_to].number - 1)) {
            pl->cards[drag_to]++;
            pl->pile[pl->cards[drag_to]][drag_to].suit = dragged_card->suit;
            pl->pile[pl->cards[drag_to]][drag_to].number = dragged_card->number;
            if (dcard != pl->cards[i]) {
              /* Dragging section of pile */
              for (j=dcard+1; j<=pl->cards[i]; j++) {
                pl->cards[drag_to]++;
                pl->pile[pl->cards[drag_to]][drag_to].suit = pl->pile[j][i].suit;
                pl->pile[pl->cards[drag_to]][drag_to].number = pl->pile[j][i].number;
              }
              pl->cards[i] -= (pl->cards[i] - dcard);
            }
            pl->cards[i]--;
            mark_for_redraw(pile_PATIENCE, i);
            mark_for_redraw(pile_PATIENCE, drag_to);
          }
          break;
      }
    }
  }

  return TRUE;
}

BOOL gamewin_scroll(event_pollblock *ev, void *ref) {
  /* Scroll game window */

  ref=ref;

  return TRUE;
}

BOOL gamewin_null(event_pollblock *ev, void *ref) {
  /* AI turn (null event) */
  static int player;
  static unsigned int time_last;
  int won, time_now;

  if (!playing) return TRUE;
  ref=ref;
  if (player > game_data.ai_players || player < 1) player = 1;
  Error_Check(SWI(0, 1, SWI_OS_ReadMonotonicTime, &time_now));
  if (time_now - time_last > game_data.difficulty) {
    time_last = time_now;
    won = ai_turn(&game_data.player[player]);
    if (won) game_over(&game_data.player[player]);
    player++;
  }
  if (game_data.difficulty > 1000) fprintf(debugfile, "Ooops.diff=%d ", game_data.difficulty);
  return TRUE;
}

/********************* Event handlers for scoreswin ************************/

BOOL sc_continue(event_pollblock *ev, void *ref) {
  /* Continue with current match */
  int i;

  /* Delete scores window & free memory */
  Window_Delete(scoreswin);
  free(ref);
  for (i=0; i<sccsize; i++) {
    free(scctext[i]);
  }
  free(scctext);

  /* Start next round */
  begin_game();

  return TRUE;
}

BOOL sc_abandon(event_pollblock *ev, void *ref){
  /* Abandon current match */
  int i;

  /* Delete scores window & free memory */
  Window_Delete(scoreswin);
  free(ref);
  for (i=0; i<sccsize; i++) {
    free(scctext[i]);
  }
  free(scctext);
  free(scores);

  return TRUE;
}

/************************* Event handlers **********************************/

BOOL iconbar_click(event_pollblock *ev, void *ref) {
  /* Handler click on iconbar icon */

  ref=ref;

  if (ev->data.mouse.button.data.menu) {
    Menu_Show(mainmenu, ev->data.mouse.pos.x, -1);
    return TRUE;
  }

  if (ev->data.mouse.button.data.select) {
    /* Open start single player game window */
    Dialog2_OpenDialogStatic(startgamedb, open_WHEREVER);
    return TRUE;
  }
  return FALSE;
}

BOOL menu_click(event_pollblock *ev, void *ref) {
  /* Handles menu choices */

  ref=ref;

  if (menu_currentopen == mainmenu) {
    switch (ev->data.selection[0]) {
      case mainmenu_QUIT:
        quit = TRUE;
        break;

      case mainmenu_PLAY:
        Dialog2_OpenDialogStatic(startgamedb, open_WHEREVER);
        break;

      case mainmenu_LINK:
        Dialog2_OpenDialogStatic(linkgamedb, open_WHEREVER);
        break;
    }
    return TRUE;
  }
  return FALSE;
}

BOOL info_menuwarn(event_pollblock *ev, void *ref) {
  /* Called to display info window */

  if ((menu_currentopen != mainmenu) || (ev->data.message.data.menuwarn.selection[0] != mainmenu_INFO)) return FALSE;
  Dialog2_OpenDialogMenuLeaf(ev, (dialog2_block*)ref);
  return TRUE;
}

void info_popup(dialog2_blockptr db) {
  /* Called when info window opened */
  char ver[30];

  Msgs_Lookup("info.version", ver, 30);
  Icon_SetText(db->window, 3, ver);
}

BOOL close_dialog(event_pollblock *ev, void *ref) {
  /* Closes dialog box passed in ref */
  return Dialog2_CloseDialog((dialog2_blockptr) ref);
}

void openfn_start(dialog2_blockptr db) {
  /* Called when start-single-player-game dbox opened */
  Event_Claim(event_CLOSE, db->window, event_ANY, close_dialog, db);
  Icon_SetCaret(db->window, 2);
  Icon_SetInteger(db->window, 2, 2);
  Icon_SetInteger(db->window, 5, 5);
}

void okfn_start(dialog2_blockptr db) {
  /* Called when OK clicked in start-single-player-game dbox */
  int d;
  game_data.ai_players = Icon_GetInteger(db->window, 2);
  game_data.linked_game = FALSE;
  d = Icon_GetInteger(db->window, 5);
  /* if (d<1) d=1; */
  if (d>10) d=10;
  game_data.difficulty = ((10 - d) * 80) / game_data.ai_players;
  Error_Report(0, "d=%d, diff=%d", d, game_data.difficulty);
  /* calloc() memory for scores */
  scores = calloc(game_data.ai_players+1, sizeof(int));
  if (scores == NULL) {
    Error_Report(0, "Failed to allocate memory for score sheet");
    return;
  }
  begin_game();
}

void openfn_link(dialog2_blockptr db) {
  /* Called when start-linked-game dbox opened */
  Event_Claim(event_CLOSE, db->window, event_ANY, close_dialog, db);
  Icon_SetCaret(db->window, 5);
  Icon_SetInteger(db->window, 5, 0);
  Icon_SetInteger(db->window, 8, 0);
}

void okfn_link(dialog2_blockptr db) {
  /* Called when OK clicked in start-linked-game dbox */
  int d;
  game_data.master = Icon_GetSelect(db->window, 0);
  game_data.linked_game = TRUE;
  if (game_data.master) {
    game_data.ai_players = Icon_GetInteger(db->window, 5);
    d = Icon_GetInteger(db->window, 8);
    /* if (d<1) d=1; */
    if (d>10) d=10;
    game_data.difficulty = (10 - d) * 100;
    /* wait_for_players(); */
  } else {
    /* hunt_for_master(); */
  }
}

void openfn_wait(dialog2_blockptr db) {
  /* Called when waiting-for-players dbox opened */
  Event_Claim(event_CLOSE, db->window, event_ANY, close_dialog, db);
}

void okfn_wait(dialog2_blockptr db) {
  /* Called when OK clicked in waiting-for-players dbox */
  /* begin_link_game(); */
}

BOOL modechange_handler(event_pollblock *ev, void *ref) {
  wimp_point old_eig = screen_eig;

  ref=ref; ev=ev;
  Screen_CacheModeInfo();
  if (old_eig.y != screen_eig.y || old_eig.x != screen_eig.x)
    Window_ModeChange();

  Error_Check(Wimp_ReadPixTrans(256, sprites, "club", &sc_factors, (void*)pixtrans));

  return TRUE;
}

int main(void) {
  char menudesc[256];
  dialog2_block *proginfo;

  /* Open debug file */
  debugfile = fopen("<Nertz$Dir>.Debug", "a+");
  if (debugfile == NULL) {
    Error_Report(0, "Unable to open debug file");
    exit(1);
  }

  Resource_Initialise("Nertz");

  Msgs_LoadFile("Messages");

  Event_Initialise("Nertz");
  EventMsg_Initialise();

  Screen_CacheModeInfo();
  EventMsg_Claim(message_MODECHANGE, event_ANY, modechange_handler, NULL);

  baricon = Icon_BarIcon("!nertz", iconbar_RIGHT);

  Event_Claim(event_REDRAW, event_ANY, event_ANY, Handler_NullRedraw, NULL);
  Event_Claim(event_OPEN, event_ANY, event_ANY, Handler_OpenWindow, NULL);

  Template_Initialise();
  Template_LoadFile("Templates");

  Event_Claim(event_CLOSE, event_ANY, event_ANY, Handler_DeleteWindow, NULL);

  /* Setup iconbar menu */
  Msgs_Lookup("menu.main", menudesc, 256);
  mainmenu = Menu_New("Nertz", menudesc);

  proginfo = Dialog2_CreateDialogBlock("ProgInfo", -1, -1, info_popup, NULL, NULL);
  Menu_Warn(mainmenu, mainmenu_INFO, TRUE, info_menuwarn, proginfo);

  /* Prepare dboxes */
  startgamedb = Dialog2_CreateDialogBlock("startgame", 3, -1, openfn_start, okfn_start, NULL);
  linkgamedb = Dialog2_CreateDialogBlock("link", 6, -1, openfn_link, okfn_link, NULL);
  waitingdb = Dialog2_CreateDialogBlock("waiting", 5, 6, openfn_wait, okfn_wait, NULL);

  /* Icon bar click */
  Event_Claim(event_CLICK, window_ICONBAR, baricon, iconbar_click, NULL);
  /* Menu click */
  Event_Claim(event_MENU, event_ANY, event_ANY, menu_click, NULL);

  /* Seed RNG */
  Error_Check(SWI(0, 1, SWI_OS_ReadMonotonicTime, &Rand_value));

  /* Load in sprites file */
  sprites = Sprite_LoadFile("<Nertz$Dir>.GSprites");
  if (sprites == NULL) Error_ReportFatal(0, "Unable to load sprites file.");
  Error_Check(Wimp_ReadPixTrans(256, sprites, "club", &sc_factors, pixtrans));
  /*-Error_Report(0, "mul.x=%d, mul.y=%d, div.x=%d, div.y=%d", sc_factors.mul.x,sc_factors.mul.y,sc_factors.div.x,sc_factors.div.y);-*/

  /* Get data from template scores window */
  load_scores_win();

  while (!quit)
    Event_Poll();

  Template_ClearAll();
  fclose(debugfile);

  return 0;
}
