Initial checkin. Not there yet.
authormdw <mdw>
Fri, 12 Dec 2003 10:55:30 +0000 (10:55 +0000)
committermdw <mdw>
Fri, 12 Dec 2003 10:55:30 +0000 (10:55 +0000)
30 files changed:
.cvsignore [new file with mode: 0644]
.links [new file with mode: 0644]
.skelrc [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
cell.c [new file with mode: 0644]
config.h [new file with mode: 0644]
configure.in [new file with mode: 0644]
cvt.pl [new file with mode: 0644]
game.c [new file with mode: 0644]
level.c [new file with mode: 0644]
maps/chicken-supreme [new file with mode: 0644]
maps/deja-vu [new file with mode: 0644]
maps/dollys-revenge [new file with mode: 0644]
maps/dots-and-waves [new file with mode: 0644]
maps/enlightenment [new file with mode: 0644]
maps/explosive-mixture [new file with mode: 0644]
maps/henrys-anguish [new file with mode: 0644]
maps/patience-pending [new file with mode: 0644]
maps/penultimate [new file with mode: 0644]
maps/razor-edge [new file with mode: 0644]
maps/something-fishy [new file with mode: 0644]
maps/the-challenge [new file with mode: 0644]
maps/the-decoder [new file with mode: 0644]
maps/the-dolls-house [new file with mode: 0644]
maps/the-happy-hour [new file with mode: 0644]
ui-curses.c [new file with mode: 0644]
undo.c [new file with mode: 0644]
xor.c [new file with mode: 0644]
xor.h [new file with mode: 0644]

diff --git a/.cvsignore b/.cvsignore
new file mode 100644 (file)
index 0000000..06bba5e
--- /dev/null
@@ -0,0 +1,3 @@
+.deps config.* stamp-h* xor
+configure aclocal.m4
+Makefile Makefile.in
diff --git a/.links b/.links
new file mode 100644 (file)
index 0000000..3cc9833
--- /dev/null
+++ b/.links
@@ -0,0 +1,5 @@
+COPYING
+INSTALL
+install-sh
+mkinstalldirs
+missing
diff --git a/.skelrc b/.skelrc
new file mode 100644 (file)
index 0000000..43d9924
--- /dev/null
+++ b/.skelrc
@@ -0,0 +1,8 @@
+;;; -*-emacs-lisp-*-
+
+(setq skel-alist
+      (append
+       '((author . "Straylight/Edgeware")
+        (program . "XOR")
+        (full-title . "XOR"))
+       skel-alist))
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..1e0b37b
--- /dev/null
@@ -0,0 +1,44 @@
+## -*-makefile-*-
+##
+## $Id: Makefile.am,v 1.1 2003/12/12 10:55:30 mdw Exp $
+##
+## Makefile
+##
+## (c) 2003 Straylight/Edgeware
+##
+
+##----- Licensing notice ----------------------------------------------------
+##
+## This file is part of XOR.
+##
+## XOR is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+## 
+## XOR is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+## 
+## You should have received a copy of the GNU General Public License
+## along with XOR; if not, write to the Free Software Foundation,
+## Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+##----- Revision history ----------------------------------------------------
+##
+## $Log: Makefile.am,v $
+## Revision 1.1  2003/12/12 10:55:30  mdw
+## Initial checkin.  Not there yet.
+##
+
+AUTOMAKE_OPTIONS = foreign
+
+bin_PROGRAMS = xor
+
+xor_SOURCES = \
+       xor.h \
+       xor.c level.c game.c undo.c cell.c \
+       ui-curses.c
+
+##----- That's all, folks ---------------------------------------------------
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..6c94900
--- /dev/null
@@ -0,0 +1,69 @@
+/* -*-c-*-
+ *
+ * $Id: acconfig.h,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Configuration header for XOR
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: acconfig.h,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+#ifndef ACCONFIG_H
+#define ACCONFIG_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Automatic configuration -------------------------------------------*/
+@TOP@
+
+#undef HAVE_NCURSES_H
+/* Define if you have <ncurses.h>.  */
+
+#undef HAVE_NCURSES_NCURSES_H
+/* Define if you have <ncurses/ncurses.h>.  */
+
+#undef HAVE_CURSES_H
+/* Define if you have <curses.h>.  */
+
+#undef HAVE_CURSES
+/* Define if you have curses.  */
+
+#undef BROKEN_LINKER
+/* Set this if you get linker errors about acs_map not being defined.  */
+
+@BOTTOM@
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/cell.c b/cell.c
new file mode 100644 (file)
index 0000000..a9e87b7
--- /dev/null
+++ b/cell.c
@@ -0,0 +1,403 @@
+/* -*-c-*-
+ *
+ * $Id: cell.c,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Cell attributes and behaviour
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: cell.c,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "xor.h"
+
+/*----- Global variables --------------------------------------------------*/
+
+const cellinfo *cellmap[UCHAR_MAX];
+
+/*----- Object behaviour --------------------------------------------------*/
+
+/* --- Player --- */
+
+static void player_hit(game_state *g, int x, int y, int hx, int hy)
+{
+  game_die(g, x, y);
+}
+
+/* --- Bombs --- */
+
+static void hbomb_hit(game_state *g, int x, int y, int hx, int hy)
+{
+  point pt[4];
+  int n = 0;
+
+  pt[n].x = x; pt[n].y = y; n++;
+  pt[n].x = x; pt[n].y = y + 1; n++;
+  pt[n].x = x; pt[n].y = y - 1; n++;
+  if (hx != x) { pt[n].x = hx; pt[n].y = hy; n++; }
+  game_explode(g, pt, n);
+}
+
+static void vbomb_hit(game_state *g, int x, int y, int hx, int hy)
+{
+  point pt[4];
+  int n = 0;
+
+  pt[n].x = x; pt[n].y = y; n++;
+  pt[n].x = x - 1; pt[n].y = y; n++;
+  pt[n].x = x + 1; pt[n].y = y; n++;
+  if (hy != y) { pt[n].x = hx; pt[n].y = hy; n++; }
+  game_explode(g, pt, n);
+}
+
+/* --- Exit --- */
+
+static int exit_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  if (g->l->m == g->l->mtot) {
+    g->f |= GF_QUIT | GF_WIN;
+    return (1);
+  }
+  return (0);
+}
+
+/* --- Masks --- */
+
+static int mask_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  undo_mask(g);
+  g->l->m++;
+  return (1);
+}
+
+static int switch_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  undo_mask(g);
+  undo_levelf(g);
+  g->l->f ^= LF_DARK;
+  g->l->m++;
+  return (1);
+}
+
+/* --- Map segments --- */
+
+static int map_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  undo_levelf(g);
+  g->l->f |= LF_NWMAP << (CELL(g->l, x, y) - C_NWMAP);
+  return (1);
+}
+
+/* --- Chickens and fish --- */
+
+static int chicken_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  if (dx) return (0);
+  if (!(cellmap[CELL(g->l, x, y + dy) & CF_CELLMASK]->f & CF_VPASS))
+    return (0);
+  game_moveobj(g, x, y, x, y + dy);
+  return (1);
+}
+
+static int fish_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  if (dy) return (0);
+  if (!(cellmap[CELL(g->l, x + dx, y) & CF_CELLMASK]->f & CF_HPASS))
+    return (0);
+  game_moveobj(g, x, y, x + dx, y);
+  return (1);
+}
+
+static int chicken_moveh(game_state *g, int x, int y)
+{
+  level *l = g->l;
+  int c;
+
+  c = CELL(l, x - 1, y) & CF_CELLMASK;
+  if (!(cellmap[c]->f & CF_HPASS))
+    return (0);
+  game_moveobj(g, x, y, x - 1, y);
+  x--;
+  c = CELL(l, x - 1, y);
+  if (!(c & CF_INFLIGHT) && cellmap[c & CF_CELLMASK]->hit)
+    cellmap[c & CF_CELLMASK]->hit(g, x - 1, y, x, y);
+  if (cellmap[CELL(l, x - 1, y) & CF_CELLMASK]->f & CF_HPASS)
+    CELLSETFL(l, x, y, CF_INFLIGHT);
+  else
+    CELLCLRFL(l, x, y, CF_INFLIGHT);
+  return (1);
+}
+
+static int fish_movev(game_state *g, int x, int y)
+{
+  level *l = g->l;
+  int c;
+
+  c = CELL(l, x, y + 1) & CF_CELLMASK;
+  if (!(cellmap[c]->f & CF_VPASS))
+    return (0);
+  game_moveobj(g, x, y, x, y + 1);
+  y++;
+  c = CELL(l, x, y + 1);
+  if (!(c & CF_INFLIGHT) && cellmap[c & CF_CELLMASK]->hit)
+    cellmap[c & CF_CELLMASK]->hit(g, x, y + 1, x, y);
+  if (cellmap[CELL(l, x, y + 1) & CF_CELLMASK]->f & CF_VPASS)
+    CELLSETFL(l, x, y, CF_INFLIGHT);
+  else
+    CELLCLRFL(l, x, y, CF_INFLIGHT);
+  return (1);
+}
+
+/* --- Dollies --- */
+
+static int dolly_nudge(game_state *g, int x, int y, int dx, int dy)
+{
+  if (CELL(g->l, x + dx, y + dy) != C_EMPTY)
+    return (0);
+  game_moveobj(g, x, y, x + dx, y + dy);
+  x += dx; y += dy;
+  if (CELL(g->l, x + dx, y + dy) == C_EMPTY) {
+    if (dx < 0) CELLSETFL(g->l, x, y, CF_DOLLYLEFT | CF_INFLIGHT);
+    else if (dx > 0) CELLSETFL(g->l, x, y, CF_DOLLYRIGHT | CF_INFLIGHT);
+    else if (dy < 0) CELLSETFL(g->l, x, y, CF_DOLLYUP | CF_INFLIGHT);
+    else if (dy > 0) CELLSETFL(g->l, x, y, CF_DOLLYDOWN | CF_INFLIGHT);
+  }
+  return (1);
+}
+
+static int dolly_moveh(game_state *g, int x, int y)
+{
+  int c = CELL(g->l, x, y);
+  int dx;
+
+  if (!(c & CF_INFLIGHT)) return (0);
+  switch (c & CF_DOLLYMASK) {
+    case CF_DOLLYLEFT: dx = -1; break;
+    case CF_DOLLYRIGHT: dx = +1; break;
+    default: return (0);
+  }
+  game_moveobj(g, x, y, x + dx, y);
+  x += dx;
+  if (CELL(g->l, x + dx, y) != C_EMPTY)
+    CELLCLRFL(g->l, x, y, CF_DOLLYMASK | CF_INFLIGHT);
+  return (1);
+}
+
+static int dolly_movev(game_state *g, int x, int y)
+{
+  int c = CELL(g->l, x, y);
+  int dy;
+
+  if (!(c & CF_INFLIGHT)) return (0);
+  switch (c & CF_DOLLYMASK) {
+    case CF_DOLLYUP: dy = -1; break;
+    case CF_DOLLYDOWN: dy = +1; break;
+    default: return (0);
+  }
+  game_moveobj(g, x, y, x, y + dy);
+  y += dy;
+  if (CELL(g->l, x, y + dy) != C_EMPTY)
+    CELLCLRFL(g->l, x, y, CF_DOLLYMASK | CF_INFLIGHT);
+  return (1);
+}
+
+/*----- The object table --------------------------------------------------*/
+
+static cellinfo celltab[] = {
+
+  { /* cell type */    C_PLAYER,
+    /* flags */                CF_PLAYER,
+    /* hit */          player_hit,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_SPARE,
+    /* flags */                CF_PLAYER,
+    /* hit */          player_hit,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_WALL,
+    /* flags */                CF_HIDE | CF_MAP,
+    /* hit */          0,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_EXIT,
+    /* flags */                CF_MAP,
+    /* hit */          0,
+    /* nudge */                exit_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_EMPTY,
+    /* flags */                CF_HPASS | CF_VPASS,
+    /* hit */          0,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_MASK,
+    /* flags */                CF_MASK | CF_MAP,
+    /* hit */          0,
+    /* nudge */                mask_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_NWMAP,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                map_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_NEMAP,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                map_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_SWMAP,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                map_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_SEMAP,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                map_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_DOT,
+    /* flags */                CF_HPASS,
+    /* hit */          0,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_WAVE,
+    /* flags */                CF_VPASS,
+    /* hit */          0,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_CHICKEN,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                chicken_nudge,
+    /* horiz move */   chicken_moveh,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_FISH,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                fish_nudge,
+    /* horiz move */   0,
+    /* vert move */    fish_movev,
+  },
+
+  { /* cell type */    C_HBOMB,
+    /* flags */                0,
+    /* hit */          hbomb_hit,
+    /* nudge */                chicken_nudge,
+    /* horiz move */   chicken_moveh,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_VBOMB,
+    /* flags */                0,
+    /* hit */          vbomb_hit,
+    /* nudge */                fish_nudge,
+    /* horiz move */   0,
+    /* vert move */    fish_movev,
+  },
+
+  { /* cell type */    C_DOLLY,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                dolly_nudge,
+    /* horiz move */   dolly_moveh,
+    /* vert move */    dolly_movev,
+  },
+
+  { /* cell type */    C_SWITCH,
+    /* flags */                CF_MASK | CF_MAP,
+    /* hit */          0,
+    /* nudge */                switch_nudge,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    C_BMUS,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  },
+
+  { /* cell type */    0,
+    /* flags */                0,
+    /* hit */          0,
+    /* nudge */                0,
+    /* horiz move */   0,
+    /* vert move */    0,
+  }
+};
+
+void cellinfo_init(void)
+{
+  int i;
+
+  for (i = 0; celltab[i].c; i++) cellmap[celltab[i].c] = &celltab[i];
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/config.h b/config.h
new file mode 100644 (file)
index 0000000..ba1e579
--- /dev/null
+++ b/config.h
@@ -0,0 +1,78 @@
+/* config.h.  Generated automatically by configure.  */
+/* config.h.in.  Generated automatically from configure.in by autoheader 2.13.  */
+/* -*-c-*-
+ *
+ * $Id: config.h,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Configuration header for XOR
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: config.h,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+#ifndef ACCONFIG_H
+#define ACCONFIG_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Automatic configuration -------------------------------------------*/
+
+/* #undef HAVE_CURSES_H */
+/* Define if you have <curses.h>.  */
+
+#define HAVE_CURSES 1
+/* Define if you have curses.  */
+
+/* Define if you have the wresize function.  */
+#define HAVE_WRESIZE 1
+
+/* Define if you have the <curses.h> header file.  */
+/* #undef HAVE_CURSES_H */
+
+/* Define if you have the <ncurses.h> header file.  */
+#define HAVE_NCURSES_H 1
+
+/* Define if you have the <ncurses/ncurses.h> header file.  */
+/* #undef HAVE_NCURSES_NCURSES_H */
+
+/* Name of package */
+#define PACKAGE "xor"
+
+/* Version number of package */
+#define VERSION "1.0.0"
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..51a0d16
--- /dev/null
@@ -0,0 +1,44 @@
+dnl -*-fundamental-*-
+dnl
+dnl $Id: configure.in,v 1.1 2003/12/12 10:55:30 mdw Exp $
+dnl
+dnl Configuration script
+dnl
+dnl (c) 2003 Straylight/Edgeware
+dnl
+
+dnl ----- Licensing notice --------------------------------------------------
+dnl
+dnl This file is part of XOR.
+dnl
+dnl XOR is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 2 of the License, or
+dnl (at your option) any later version.
+dnl 
+dnl XOR is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+dnl GNU General Public License for more details.
+dnl 
+dnl You should have received a copy of the GNU General Public License
+dnl along with XOR; if not, write to the Free Software Foundation,
+dnl Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+dnl ----- Revision history --------------------------------------------------
+dnl
+dnl $Log: configure.in,v $
+dnl Revision 1.1  2003/12/12 10:55:30  mdw
+dnl Initial checkin.  Not there yet.
+dnl
+
+AC_INIT(xor.c)
+AM_INIT_AUTOMAKE(xor, 1.0.0)
+AM_CONFIG_HEADER(config.h)
+AC_PROG_CC
+mdw_GCC_FLAGS
+mdw_MLIB(2.0.3)
+mdw_CURSES
+AC_OUTPUT(Makefile)
+
+dnl ----- That's all, folks -------------------------------------------------
diff --git a/cvt.pl b/cvt.pl
new file mode 100644 (file)
index 0000000..194ee9c
--- /dev/null
+++ b/cvt.pl
@@ -0,0 +1,20 @@
+#! /usr/bin/perl
+
+foreach my $i (@ARGV) {
+  my $n = $i;
+  $n =~ s/.* - (.*)\.txt/$1/;
+  my $o = $n;
+  $o =~ tr/A-Z/a-z/;
+  $o =~ tr/a-zA-Z0-9/-/c;
+  open I, "$i";
+  open O, ">maps/$o";
+  print O "name \"$n\"\n";
+  print O "data\n";
+  while (<I>) {
+    tr(-#12<!@oxMD |SE+)
+      (-#$%<V+UCM@ |~*O);
+    print O $_;
+  }
+  print O "end\n";
+  close I; close O;
+}
diff --git a/game.c b/game.c
new file mode 100644 (file)
index 0000000..937969e
--- /dev/null
+++ b/game.c
@@ -0,0 +1,211 @@
+/* -*-c-*-
+ *
+ * $Id: game.c,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Main game logic
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: game.c,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "xor.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+#define G_CELLSET(g, x, y, c) do {                                     \
+  undo_cell((g), (x), (y), (c));                                       \
+  CELLSET((g)->l, (x), (y), (c));                                      \
+} while (0)
+
+void game_die(game_state *g, int x, int y)
+{
+  game_player *p;
+
+  for (p = g->p; p && (p->x != x || p->y != y); p = p->next) ;
+  if (!p) return;
+  ui_frame(g->p->u);
+  undo_die(g, p);
+  p->f |= PF_DEAD;
+  G_CELLSET(g, p->x, p->y, C_EMPTY);
+  for (p = g->p; p && (p->f & PF_DEAD); p = p->next) ;
+  if (p) ui_message(g->p->u, "Whoops!");
+  else ui_message(g->p->u, "Gotcha!");
+}
+
+void game_explode(game_state *g, const point *pt, int n)
+{
+  int i;
+
+  ui_explode(g->p->u, pt, n);
+  for (i = 0; i < n; i++) game_die(g, pt[i].x, pt[i].y);
+  for (i = 0; i < n; i++) G_CELLSET(g, pt[i].x, pt[i].y, C_EMPTY);
+}
+
+void game_moveobj(game_state *g, int x, int y, int xx, int yy)
+{
+  int c = CELL(g->l, x, y);
+  G_CELLSET(g, x, y, C_EMPTY);
+  G_CELLSET(g, xx, yy, c);
+}
+
+static int doupdateh(game_state *g)
+{
+  level *l = g->l;
+  int i, j, c;
+  int rc = 0;
+
+  for (j = 0; j < l->h; j++) {
+    for (i = 0; i < l->w; i++) {
+      c = CELL(l, i, j) & CF_CELLMASK;
+      if (cellmap[c]->moveh && cellmap[c]->moveh(g, i, j)) rc = 1;
+    }
+  }
+  if (rc) ui_frame(g->p->u);
+  return (rc);
+}
+
+static int doupdatev(game_state *g)
+{
+  level *l = g->l;
+  int i, j, c;
+  int rc = 0;
+
+  for (i = 0; i < l->w; i++) {
+    for (j = l->h - 1; j >= 0; j--) {
+      c = CELL(l, i, j) & CF_CELLMASK;
+      if (cellmap[c]->movev && cellmap[c]->movev(g, i, j)) rc = 1;
+    }
+  }
+  if (rc) ui_frame(g->p->u);
+  return (rc);
+}
+
+static void updatev(game_state *g) { while (doupdatev(g) || doupdateh(g)) ; }
+static void updateh(game_state *g) { while (doupdateh(g) || doupdatev(g)) ; }
+
+void game_switchto(game_state *g, game_player *p)
+{
+  /* --- Don't stash undo records here --- */
+
+  if (!(g->p->f & PF_DEAD))
+    CELLSET(g->l, g->p->x, g->p->y, C_SPARE);
+  g->p->prev = g->ptail;
+  p->prev->next = 0;
+  g->ptail->next = g->p;
+  g->ptail = p->prev;
+  p->prev = 0;
+  g->p = p;
+  g->l->v++;
+  CELLSET(g->l, g->p->x, g->p->y, C_PLAYER);
+  ui_switch(g->p->u);
+}
+
+int game_switch(game_state *g)
+{
+  game_player *p;
+
+  if (!g->p)
+    return (0);
+  for (p = g->p->next; p && (p->f & PF_DEAD); p = p->next)
+    ;
+  if (!p) return (0);
+  if (g->l->v >= g->l->vtot) return (1);
+  undo_switch(g);
+  game_switchto(g, p);
+  return (1);
+}
+
+void game_move(game_state *g, int dx, int dy)
+{
+  int x = g->p->x;
+  int y = g->p->y;
+  int c = CELL(g->l, x + dx, y + dy) & CF_CELLMASK;
+
+  if (g->p->f & PF_DEAD) return;
+  if (g->l->v >= g->l->vtot) return;
+  if ((cellmap[c]->f & ((dx ? CF_HPASS : 0) | (dy ? CF_VPASS : 0))) ||
+      (cellmap[c]->nudge &&
+       cellmap[c]->nudge(g, x + dx, y + dy, dx, dy) > 0)) {
+    undo_pmove(g);
+    game_moveobj(g, x, y, x + dx, y + dy);
+    g->p->x = x + dx;
+    g->p->y = y + dy;
+    g->l->v++;
+    ui_track(g->p->u, x + dx, y + dy);
+    if (dx) updatev(g); else updateh(g);
+    ui_update(g->p->u);
+    if (g->p->f & PF_DEAD) game_switch(g);
+  }
+}
+
+void game_quit(game_state *g) { g->f |= GF_QUIT; }
+
+static void addplayer(game_state *g, int x, int y)
+{
+  game_player *p = CREATE(game_player);
+  p->f = 0;
+  p->x = x;
+  p->y = y;
+  p->u = ui_start(g->l, x, y);
+  p->next = 0;
+  p->prev = g->ptail;
+  if (g->ptail) g->ptail->next = p; else g->p = p;
+  g->ptail = p;
+}
+
+void game_go(level *l)
+{
+  game_state g;
+  int x, y;
+
+  g.l = lev_copy(l);
+  lev_write(g.l, stdout);
+  g.f = 0;
+  g.ptail = 0;
+  lev_findcell(l, C_PLAYER, &x, &y);
+  addplayer(&g, x, y);
+  if (lev_findcell(l, C_SPARE, &x, &y)) {
+    do
+      addplayer(&g, x, y);
+    while (lev_findnext(l, C_SPARE, &x, &y));
+  }
+  undo_init(&g);
+  ui_switch(g.p->u);
+  while (!(g.f & GF_QUIT)) {
+    undo_begin(&g);
+    ui_go(&g, g.p->u);
+    undo_commit(&g);
+  }
+  lev_free(g.l);
+  undo_free(&g);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/level.c b/level.c
new file mode 100644 (file)
index 0000000..f2e7922
--- /dev/null
+++ b/level.c
@@ -0,0 +1,251 @@
+/* -*-c-*-
+ *
+ * $Id: level.c,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Level I/O and handling
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: level.c,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "xor.h"
+
+/*----- Data structures ---------------------------------------------------*/
+
+DA_DECL(int_v, int);
+
+/*----- Main code ---------------------------------------------------------*/
+
+int lev_findnext(const level *l, int c, int *x, int *y)
+{
+  int n = l->w * l->h;
+  int i;
+
+  for (i= *y * l->w + *x + 1; i < n; i++) {
+    if ((l->d[i] & CF_CELLMASK) == c) {
+      *x = i % l->w;
+      *y = i / l->w;
+      return (1);
+    }
+  }
+  return (0);
+}
+
+int lev_findcell(const level *l, int c, int *x, int *y)
+{
+  int n = l->w * l->h;
+  int i;
+
+  for (i = 0; i < n; i++) {
+    if ((l->d[i] & CF_CELLMASK) == c) {
+      if (x) *x = i % l->w;
+      if (y) *y = i / l->w;
+      return (1);
+    }
+  }
+  return (0);
+}
+
+level *lev_read(FILE *fp)
+{
+  level *l = CREATE(level);
+  dstr d = DSTR_INIT, dd = DSTR_INIT;
+  int_v v = DA_INIT;
+  char *p, *q, *r;
+  int *pp;
+  unsigned f;
+  int i, n, nn;
+  int x, y, xx, yy;
+  int ind, max;
+
+  /* --- Basic initialization --- */
+
+  l->name = xstrdup("<untitled>");
+  l->w = l->h = 0;
+  l->d = 0;
+  l->f = 0;
+  l->m = 0;
+  l->mtot = -1;
+  l->v = 0;
+  l->vtot = 2000;
+
+  ind = -1;
+  max = 0;
+
+  /* --- Read the preamble --- */
+
+  while (dstr_reset(&d), dstr_putline(&d, fp) != EOF) {
+    p = d.buf;
+    q = str_qword(&p, 0);
+    if (!q || *q == '#' || *q == ';')
+      continue;
+    if (strcmp(q, "name") == 0 && (q = str_qword(&p, STRF_QUOTE)) != 0) {
+      xfree(l->name);
+      l->name = xstrdup(q);
+    } else if (strcmp(q, "flags") == 0 && (q = str_qword(&p, 0)) != 0) {
+      f = 0;
+      while (*q) {
+       const char *lfmap = LF_MAP;
+       if ((r = strchr(lfmap, *q)) == 0)
+         continue;
+       f |= 1 << (r - lfmap);
+      }
+      l->f = f;
+    } else if (strcmp(q, "masks-collected") == 0 &&
+              (q = str_qword(&p, 0)) != 0)
+      l->m = atoi(q);
+    else if (strcmp(q, "masks-total") == 0 &&
+            (q = str_qword(&p, 0)) != 0)
+      l->mtot = atoi(q);
+    else if (strcmp(q, "moves-made") == 0 &&
+              (q = str_qword(&p, 0)) != 0)
+      l->v = atoi(q);
+    else if (strcmp(q, "moves-allowed") == 0 &&
+            (q = str_qword(&p, 0)) != 0)
+      l->vtot = atoi(q);
+    else if (strcmp(q, "data") == 0) {
+      dstr_reset(&dd);
+      while (dstr_reset(&d), dstr_putline(&d, fp) != EOF) {
+       if (strstr("end", d.buf)) break;
+       i = 0;
+       while (d.buf[i] == C_EMPTY) i++;
+       if (ind == -1 || i < ind) ind = i;
+       while (d.buf[d.len - 1] == C_EMPTY) d.len--;
+       if (d.len > max) max = d.len;
+       dstr_putd(&dd, &d);
+       DA_PUSH(&v, dd.len);
+      }
+      l->h = DA_LEN(&v);
+      l->w = max - ind;
+      l->d = xmalloc(l->h * l->w * sizeof(*l->d));
+      for (i = 0; i < l->w * l->h; i++)
+       l->d[i] = C_EMPTY;
+      n = 0;
+      for (i = 0; i < l->h; i++) {
+       nn = DA(&v)[i];
+       p = dd.buf + n + ind;
+       q = dd.buf + nn;
+       pp = l->d + l->w * i;
+       while (p < q) *pp++ = *p++;
+       n = nn;
+      }
+      break;
+    }
+  }
+
+  if (!l->d)
+    return (0);
+
+  n = 0;
+  while (lev_findcell(l, C_UKMAP, &x, &y)) {
+    for (i = C_NWMAP; lev_findcell(l, i, 0, 0); i++) ;
+    CELLREF(l, x, y) = i;
+  }
+  for (i = 0; i < l->w * l->h; i++) {
+    if (!cellmap[l->d[i]]) {
+      fprintf(stderr, "warning: unknown map item: killing\n");
+      l->d[i] = C_WALL;
+    }
+  }
+  if (l->v > l->vtot) {
+    fprintf(stderr, "warning: too many moves already: locking\n");
+    l->v = l->vtot;
+  }
+  if (lev_findcell(l, C_PLAYER, &x, &y)) {
+    CELLREF(l, x, y) = C_SPARE;
+    if (lev_findcell(l, C_PLAYER, &xx, &yy)) {
+      fprintf(stderr, "warning: multiple active players: deactivating\n");
+      do
+       CELLREF(l, xx, yy) = C_SPARE;
+      while (lev_findcell(l, C_PLAYER, &xx, &yy));
+    }
+    CELLREF(l, x, y) = C_PLAYER;
+  } else if (lev_findcell(l, C_SPARE, &x, &y)) {
+    fprintf(stderr, "warning: no active player: activating a spare\n");
+    CELLREF(l, x, y) = C_SPARE;
+  } else
+    fprintf(stderr, "warning: no player found: hoping for the best\n");
+  for (i = 0; i < l->w * l->h; i++)
+    if (cellmap[l->d[i] & CF_CELLMASK]->f & CF_MASK) n++;
+  if (l->mtot < 0)
+    l->mtot = n - l->m;
+
+  dstr_destroy(&d);
+  dstr_destroy(&dd);
+  DA_DESTROY(&v);
+  return (l);
+}
+
+void lev_write(const level *l, FILE *fp)
+{
+  const char *p = LF_MAP;
+  const int *pp;
+  unsigned f;
+  unsigned i, j;
+
+  fprintf(fp, "name \"%s\"\n", l->name);
+  fprintf(fp, "flags ");
+  f = l->f;
+  while (*p) {
+    if (f & 1) putc(*p, fp);
+    f >>= 1;
+    p++;
+  }
+  putc('\n', fp);
+  fprintf(fp, "masks-collected %d\n", l->m);
+  fprintf(fp, "masks-total %d\n", l->mtot);
+  fprintf(fp, "size = %d x %d\n", l->w, l->h);
+  fprintf(fp, "data\n");
+  for (i = 0, pp = l->d; i < l->h; i++) {
+    for (j = 0; j < l->w; j++) putc(*pp++, fp);
+    putc('\n', fp);
+  }
+  fprintf(fp, "end\n");
+}
+
+void lev_free(level *l)
+{
+  xfree(l->name);
+  xfree(l->d);
+  DESTROY(l);
+}
+
+level *lev_copy(const level *l)
+{
+  level *ll = CREATE(level);
+  *ll = *l;
+  ll->name = xstrdup(l->name);
+  ll->d = xmalloc(l->w * l->h * sizeof(*l->d));
+  memcpy(ll->d, l->d, l->w * l->h * sizeof(*l->d));
+  return (ll);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/maps/chicken-supreme b/maps/chicken-supreme
new file mode 100644 (file)
index 0000000..f5f7c3c
--- /dev/null
@@ -0,0 +1,35 @@
+name "Chicken Supreme"
+data
+################################
+#       #VVV+#     # +# +<#+++V#
+# #  V# #++++# #+< # V+|<<#  V<#
+# | #+< #+#+<# ### # -#  ## V< #
+# |  ++ #+++<# #VV   #    #+<  #
+# | #V# #      #V<             #
+# | ++V<########+  # #  V<#  |<#
+# |  |<-###%   #+  #+#++<<#+   #
+# |     ##V<##-##### ######### #
+# #     #++  #+#+VV VVVV|<<<+# #
+#    V< ###  #+-VV+ ---- |<<<# #
+#|###V  #++  ###V-+ ||+|V |<<# #
+#|--#+  ####MMM#+  ---|--  |<#+#
+###|### ######M###|######|######
+#+  V   #+++                   #
+#+<<< V<########################
+#+ V< V #                      #
+#|<<  V # #########     #<<<<< #
+##    ++# #      #+# V  #+   V #
+#    ####   #+V#<#   -V<## + V #
+# V  +++#####+<#$#    V #    V #
+# ###########+V# #  +<<<#+#  V #
+#      V#   #+<#<#++#+++#++#+V #
+#+##   +# #      ############# #
+#+#     # ######## +<#         #
+#+# V<< #            # V #  V V#
+#+# VV  # #<<<<#   V<# +<#  V+V#
+#+# V#  + #|+#|#  V<|# # # ###V#
+#+#++#++# #+   #+<<###   #|+++<#
+#+####################<<<#|+*+<#
+#+                       #|+++<#
+################################
+end
diff --git a/maps/deja-vu b/maps/deja-vu
new file mode 100644 (file)
index 0000000..e24ce09
--- /dev/null
@@ -0,0 +1,35 @@
+name "Deja Vu"
+data
+################################
+#                   ##M  V V VM#
+# ################   ##+ U U - #
+# #++C<#      #    U  #  - -+|<#
+# #++++# V V  # -#|- |<##+ #####
+# ####+# --+- #  |||  |<##     #
+#   V# #      ## ||| ###### ##<#
+#   V# #      #  --# #+ V # #|<#
+# # -  #    |C#+     ## V<#   |#
+################### +#  ++# #-+#
+#  %   # #    #+  ##### ### ####
+#    V #+V  V #  V ##M  #      #
+# U  - #+V  # #  -  ## ##  V   #
+# #C#< #+V    #|     # #  ##   #
+#    + ###   U#+  U<<# #  ###| #
+#      #   +C### |-  # #  #V|C<#
+######## #####M###- ## #  #-   #
+#      #-      # V |<# #  ##V  #
+#    V # V|<< ## U | # #  # V  #
+#| #<-## ++   #  +C| # #    +  #
+#|  |< # +    #  V | # #       #
+#   +  #    V #  # # #         #
+#C     # ++C#U#      ##   +#+  #
+#|#####################   ||<  #
+#### ###+ V     V V V ##   V   #
+# V<  ##|<<###V + + +  ## -- #<#
+# -+  ##+    +U       |<###    #
+#  |  ##C |   -          ##   $#
+#    |C#+  #  #           ######
+######################### ###+##
+#                         ##*  #
+################################
+end
diff --git a/maps/dollys-revenge b/maps/dollys-revenge
new file mode 100644 (file)
index 0000000..eed9fdd
--- /dev/null
@@ -0,0 +1,35 @@
+name "Dollys Revenge"
+data
+################################
+##                         #  V#
+#++#        |<< V      # #    -#
+#### #### --   @@    ### ### # #
+#VV# #++#U##||    ####     #|< #
+#+-# #######++ ++#V    V+V #+ +#
+# ##  V+#   #####M- @ M#########
+#    @<##              #      +#
+# #    +#     ######## #   @  ##
+#+## #####|#@ #   + V# #    @ ##
+###    ###U#  #  @  +  #   @  ##
+##  @@  ##+#+ #     ##### #    #
+#  @@ @  ###### @   *# -V #### #
+# @@  @@ #    # @ %###< #  | # #
+# @  @@  #  @ #      #     |+# #
+#  @+@   #@   ##########   |<# #
+#  @@@  ## @     V ##++##    # #
+##     ###    $  + #         # #
+#### #####         ## ######## #
+#+V#    #######C##### ##   +   #
+#|<# |< #     ###      #     V #
+# V#    #     M M      #   ||- #
+# +#    #     ### V    # ##    #
+# V#    ## ####V########  #    #
+# +#    #  #   -   #      #    #
+#@V#    #-      #  #      #  @ #
+# +#    ####       # U    #  @ #
+#@ #    #  |    ######    #  V #
+#  #    #+-U   U++###   #U#  - #
+#+#U- # ###################    #
+#+###+#   +#++++++++      #    #
+################################
+end
diff --git a/maps/dots-and-waves b/maps/dots-and-waves
new file mode 100644 (file)
index 0000000..dd7ba6e
--- /dev/null
@@ -0,0 +1,35 @@
+name "Dots and Waves"
+data
+################################
+#          ---                 #
+# ##########-################# #
+# #+|   M %#        -----    # #
+#+#+     ### ############### # #
+# ###    +                 # # #
+#   #+######-##########M## # # #
+### # #|                 # # # #
+#-- #  +####-###--|##### # # # #
+#+| # ##|     +| + |+  # # - # #
+#+| # #+| ############ #+# # # #
+#+| # # | #+#+       # ### # # #
+#+| #|# | # ###----# # #+# # # #
+#|| #M# |          # # # # # #$#
+### #|# # # #+## # # # # # # # #
+#+# #|# # # ###++| |   |   | | #
+# # # # # #+#+#*+# # # # # # # #
+# # # # # ### #### # # # # # # #
+#+# # #   #        # # # # # # #
+# # # # ### #####-## # # #+# # #
+# # # # #+| #       +# # ### # #
+#+# # #  +| #-|-###### # #+# # #
+# # - # #+| --||#+       # # # #
+# ### # #####|--######## # # # #
+# #+#|#   -+#--|+#+-     # #+# #
+# #+#|###|##############|# ### #
+# # #+#++||                #+  #
+# - ####### ############-###   #
+# #-                   -+#+    #
+# ##-#######---------#####   M-#
+#                            |+#
+################################
+end
diff --git a/maps/enlightenment b/maps/enlightenment
new file mode 100644 (file)
index 0000000..d83e959
--- /dev/null
@@ -0,0 +1,35 @@
+name "Enlightenment"
+data
+################################
+#++*V #~<<#| VV~#|M#+V++#VV+#+##
+#++ V #|<<  #VV+#<<# -   --|<  #
+#***V #      -- #     V####    #
+#   V    +# #####    U#V#    @C#
+# ~ ##~####~    ### ##U##   @C #
+# #+#  #+   #~# #   ###U#VV    #
+# ### ## ###### # ##############
+#     #  #      #   V  # V   V #
+#######~##~V    #V  V+<# - @ V #
+#        ###   +#V  V+ #     V #
+# ##  ## -+# U###V ###|#+  # V #
+# #+|<#+ |<# #+##V   ++### + V #
+# ##  ############    U#<C #U#+#
+# ##+## V #######     #### #####
+# ##### -         #C          +#
+# V#V## ########################
+# -V<## #   |  #||     #      +#
+#  V ## #  #~  #-#C @  ##<######
+#  V  # #  #  V#M#   U<#       #
+#  -+## #<<#  ~#-#@  # #  ###V #
+#  #### #||### #|#  -|<~  #+#+ #
+#     M##+             ####+## #
+########################++#  # #
+###V +#  VV######   +#    #  # #
+#+#-@    --   ++# # ## #### V  #
+#+#  ##~###   |<# + #       ####
+#+#     #M#~C   # # ##-###  # +#
+#+#  @U #~#     # #     +#  #  #
+#+#   #   ###<  # ##### ##  # ##
+#+##  @ @ #+#   ~    +#        #
+################################
+end
diff --git a/maps/explosive-mixture b/maps/explosive-mixture
new file mode 100644 (file)
index 0000000..351cd57
--- /dev/null
@@ -0,0 +1,35 @@
+name "Explosive Mixture"
+data
+################################
+#+##+M#M  # U#+#V +##   ####V M#
+#+##  V#  # VV+#-  #   #C|<#M% #
+# -#U$- V<# VU+#C# #U |<#  #U###
+# ####  - # --+#################
+# #+ #  U## V-## #V#    #+C  V<#
+# #  #U #+# U#+#  -# V+ #+|  -##
+# # ####### ####+U # U#####  +##
+# # #+#+#   #+V##### -#        #
+# # VV+ #     -   *########    #
+# # -V# # ##########    #+#### #
+# # UV+ # #V    V#   U  ###V+# #
+# ##### # ##U  |<#  V#  # |C<# #
+#   #+# # #C#   V#  V+< #+ ### #
+# V #|# # ##+#  ## |<   #+   # #
+#|#   # # ############# ####<# #
+#     # # #+            #C   # #
+#+ # +# # ############# #  # # #
+##C#C##+#  #  |#      ###  #<# #
+##########   V<#+ #<U+#C     # #
+####|##+#+   V #  # V+######## #
+#     # #  +<< #    V+# #C     #
+#       # ####### ##### #  #<# #
+#     V #               #  # #+#
+#------ ################# VVV###
+#CCCC## #+#+##          # -U-  #
+#######+#+ +#U  #       # U-+ +#
+##+V+######+#-    #<V< #########
+#+ -##   +#+#C<     #  #|+<+<V<#
+#C      |< ###    ###       #+|#
+#+    #+##                #    #
+################################
+end
diff --git a/maps/henrys-anguish b/maps/henrys-anguish
new file mode 100644 (file)
index 0000000..4180864
--- /dev/null
@@ -0,0 +1,35 @@
+name "Henrys Anguish"
+data
+################################
+# V      #+V     #      ##V#+###
+# V+#### ##- ##  #    # ##V#V###
+# -#V# # ##   ## # V| # #+- - ##
+# # -V # #   ##+ # +# # ##-#- %#
+# #++# # # V|<## #  + # ## ## ##
+# #++# # # - ##+ #C|< # ####+ ##
+#  # # # #+|<+## #+V  # ##### ##
+# V# V # ######  # U ##   V # ##
+# -+#- # #      ## + #  M#U # ##
+# -### # #   V VV#+| #V   - #M##
+# #+ V-#     - -+# ###+# +| #U##
+# ##+- # #|###|<##   ###########
+#-V+#V # #|+#+  ##       # V V #
+# -#V# # #############+< # V U #
+#  #+V # #M    ###C   +  # V - #
+#VV #+|# ## ##  ####+#V  # -   #
+#-V #+ # ##$ ##V  M#  +  #+#   #
+# # V# # ### #+<####VV   ###   #
+# # +# # #VV #  ##C --+  ##   ##
+#+# #+ # #+-   #######   #   #-#
+#    # # ######### #        ## #
+## ##V # ###@####  #-U<U   ##  #
+#  #+- #   ###### ##+-V-  ##   #
+# # V# #       ## #########   ##
+# #+-  ## # #C  #  VV  #     #V#
+# #### #C |<<   #  #U|<# #V  |+#
+#      #*#    V #   #  #  +#V  #
+# ###############      #  U+<  #
+# #   #   #++ #   #U#U##  # #  #
+#   #   V  +#   ###+#+##       #
+################################
+end
diff --git a/maps/patience-pending b/maps/patience-pending
new file mode 100644 (file)
index 0000000..601c648
--- /dev/null
@@ -0,0 +1,35 @@
+name "Patience Pending"
+data
+################################
+#          #V#|   |#V#         #
+# ########  -  # #  -  ## |<<# #
+#        ####### ########|<<<# #
+# #<<<<##  +++#   V     #|<+## #
+# ## O #  #####   #     ####   #
+# #V  #  #         #    #+   V #
+# #+ # O ## V           #@ +C# #
+# #++  # V#@#     ~<<<< #+ U   #
+# ##++ - +# #   U +<<<<C###### #
+# #######################-+<<# #
+# #     V<#+#V    $## ###  V # #
+# # ##< -+#+#- V   ## V##  - # #
+# # ##+ +<# #+V-   ## -####  # #
+# # ##<   # # -  V<##  ##V#  # #
+# # ##   |< ## |<+ ##+*##+#  # #
+# # ##      V    |<######+M#   #
+# # ########################## #
+# # #+   VM#V+V## +<  U #@|C<# #
+# # #   |<#V<<<#+-    - #U  |# #
+# # #+<<##V<    #    V< #@ +<# #
+# # #+<<+<<+ #U#+|<<<<  #+   # #
+# # # ## ######## ### ###### # #
+# #                            #
+# ##############################
+#                         V   %#
+########M##########M#####V<C  V#
+#+ V+            V<     #-V  |<#
+## +< #|<##V|< V#V  @@ V# # |< #
+#+    #|<#+-|#|<#V +  |<#  V<  #
+#+  ++#-|+#+#+   -   |<+#+|< #+#
+################################
+end
diff --git a/maps/penultimate b/maps/penultimate
new file mode 100644 (file)
index 0000000..ce5eddb
--- /dev/null
@@ -0,0 +1,35 @@
+name "Penultimate"
+data
+################################
+#                   #+|< #+#+V #
+# #|########|<#####  #   # ##V #
+# #|--V|V-##+##+ V## V<#+# V#+<#
+# #|V|<|@ ###    +<# -#### -#  #
+# #|-V--|+#   U  ### +#V    #  #
+# ##|-|-|+#  VVV   ####-    ## #
+# +######### --#      #      # #
+# #+V###+++  -|#<       #### # #
+# #--|<#######+#   -@--  #     #
+# #   ##     #+#   V V#  ##V   #
+#   |<#V V |<#+--V #+##  #+V ###
+#    ##V#+  -##########  ##C   #
+#  @ # V#|   ## V+V  ##  #---V #
+#  #+# V< -| ##|<#-V #   #+U+< #
+# V<##V+VO+ ### @@@# #    ##   #
+# V## -|< ###+#      ##-   #####
+# V#      #+#+##    ##   U     #
+# -# ##U#-  #|<# ##### -###M ###
+# +#*#+###### ## ###V#   V#  #+#
+# #######  V#    #$+<##  +#  #V#
+# #+V #    +# ####M |<#   ## #-#
+# ##- #V V< # ###### ## +|<  #|#
+# #+  O- + #C    ### #       #|#
+# ### +#  V## ##|<##   ####### #
+# # V#### -+#    ### #  #+ |   #
+# #V< V+##### ####%M ## #CV<<  #
+#  +  +<#     ######### # +   ##
+##### |<#####           #|C< | #
+#+###  ##+++############# @  +<#
+#                            M+#
+################################
+end
diff --git a/maps/razor-edge b/maps/razor-edge
new file mode 100644 (file)
index 0000000..bc8fd59
--- /dev/null
@@ -0,0 +1,35 @@
+name "Razor Edge"
+data
+################################
+#+  #  #-V  ||V#+ V   V #  U  V#
+#  # | #+< V-|+#C - |<# # |<<<<#
+# ##V|  #  +V-U#C   |<# #    + #
+# #OVC< #+#|<|+#+#  |M# #  % @C#
+# ##V   ### ###### ###  # @   |#
+#  #+ #                ##    + #
+#   ###################V########
+# + ##<<<<<<<<<<V<<<<<<<< @  # #
+# | #           -            # #
+# | #|@                      # #
+# |V#    ##||||||||####      # #
+# |+#   ####|||C||##++##C<   # #
+#|| ##U##++##----#+++++#   @ # #
+# | #+## |< ##+++++#####  #### #
+# | ###  @ @ #+++##   ###      #
+#|#|         #####V V    #  V|<#
+##+#U    @ +###V +< V  V # -#  #
+#####   @  #+ +<    # |C     U #
+# VU#++   ##        #  # #######
+# ++########## U###C<|<#+#  V  #
+#   U  #+V#++#+#+<#++M<#+# ##  #
+# @ @@ # M#++#+#|<########  #|<#
+# @ +~ #  ######|<##   V#   # ##
+########          #C V+V## ##|<#
+#VVVVC #~   U|   V#~ #C+#+ *#  #
+#----  ####### @ V#C    #####  #
+#    @ #+C   #@+ +#####        #
+#$@    # @ +<#########| ##  @C #
+#   +< #  @VO      +++++###    #
+#M     #   -+#     ++~++##+#  +#
+################################
+end
diff --git a/maps/something-fishy b/maps/something-fishy
new file mode 100644 (file)
index 0000000..d81342b
--- /dev/null
@@ -0,0 +1,35 @@
+name "Something Fishy"
+data
+################################
+##                      #+ %  +#
+## VV  #V #--V   #   V  ###  ###
+#|--V #+- ##+##-|#  |## # V  #$#
+#|+|V V## #+#    ## |+# # #### #
+#-+|V -   #   V  #V |M#   +###<#
+#++|- +##+#VVV+VV#+ |+# # #    #
+#M############################ #
+#     ++++#+<+<+<#+    M#    # #
+##### #####       | #+#<#|<# # #
+#V     V-V#  +<<<#+     #|<#|< #
+#-     V|+#|<<<<<#| #+# #+<# # #
+# #### V#+#  +<<<#<<<<<<#|<# # #
+#   V# -#|#+|<<<<#+        #  +#
+#   V# +#|###### ###############
+#+  +#  -+#+-    #<+|#+#+    +<#
+#|  #########  ###++<#+#+   #<<#
+#|      |V#+#< #+#+<   #+#+ #++#
+#|  V   --#    |<#<+<#  |##<#  #
+#|  + # |+###    #+    ###     #
+#     # ###+  +< #             #
+#| V V# VV###### #-|#   ##<<<<<#
+#| + +# V+#--+ | #-|#    #+|||<#
+#|    # VV# |<|| #|<<##  ##  + #
+#|   V# VV#+ -|< #|<<+#  #+ +<|#
+#|#  +#-+V#< |-| #+  +#  #######
+#+# + ##+-#||||- #######       #
+#+#   #   #|---- M       #+#|<<#
+#+#  V#   ########|<<   #+##<<+#
+#+#  +    V  *         #+|<#|<|#
+#+#VVVV   -  #  #+#+#+#+       #
+################################
+end
diff --git a/maps/the-challenge b/maps/the-challenge
new file mode 100644 (file)
index 0000000..740467a
--- /dev/null
@@ -0,0 +1,35 @@
+name "The Challenge"
+data
+################################
+##V##V##  +<|V<##++<#        |~#
+##V#+V## ##C|<###|<<<  ###   V|#
+#M+V<<<#       V#|#   ###    V|#
+#- -  +#    #  -#    ##+#CV< #|#
+#  # ###### # #    @    #+V    #
+##$#     |< #    # VVV  # -V   #
+########  # #    | ---  #  #   #
+#V#V#+ #### #    ### #  ##C##C##
+#- +|<  |<  #  #U#+#+##C#+-++-+#
+##          # ######### ########
+##V|<    ####       #+         #
+# -  -V## U   #+##V #########  #
+#+# # ~#M|<<  V+#VV   M###+##* #
+###C######    +V#+V#   ##+V#####
+#+##  V| #### ###+--   ###-V####
+#  |< #  #V     ######V# % - ###
+#        #~ ##   V|+# -# # +<<##
+#C   V|< ##   V< V++#    #-+-###
+#~#  V   #+C ---VV +##########V#
+#+####U#|###   --V+##        VV#
+#   V++#U|<   UM V#    V U  #++#
+#++####-- # #######  ##V#V<    #
+#++#              ~  # + +   ###
+#### ############ ##############
+#             V<# #            #
+# #########  +< # # ## V#+#~<# #
+#     V   #         VV -#+#### #
+#     - |<#  ##V#-- VV# ###V   #
+#U#U#   @ #  #|+#+# -- +#+ V|<<#
+#~#+C  #  V  #<+### ## +#+ - |<#
+################################
+end
diff --git a/maps/the-decoder b/maps/the-decoder
new file mode 100644 (file)
index 0000000..abb1cad
--- /dev/null
@@ -0,0 +1,35 @@
+name "The Decoder"
+data
+################################
+#          #####     #         #
+# ### #C V ####   VV #     $ V #
+#  V  #  -###     +# #      %@ #
+###-  #<   #         #         #
+##OU     @###U###### #C#########
+####   #  -#U#    *# -#       +#
+################################
+###  V #                       #
+###@ - #  #####         #####  #
+# O    #     ##   ####  ##     #
+# # #<V#    ##          ####   #
+# # #|C#   ##     ####  ##     #
+# #    #  ##            ##     #
+# ######  #####         #####  #
+# ######                       #
+#~###V## ##  ##          ####  #
+#   |< # ##  ##   ####    ##   #
+#      # ######           ##   #
+#  #   # ##  ##   ####    ##   #
+# ##UV # ##  ##           ##   #
+# V#-- # ##  ##          ####  #
+# ######                       #
+#      # #####          ##  ## #
+#- #U  # ##  ##   ####  ##  ## #
+#   V  # #####          ##  ## #
+#C  # -# ##  ##   ####  ##  ## #
+###    # ##  ##         ##  ## #
+#~#    # #####           ##### #
+########                       #
+# MMMM##                       #
+################################
+end
diff --git a/maps/the-dolls-house b/maps/the-dolls-house
new file mode 100644 (file)
index 0000000..15df020
--- /dev/null
@@ -0,0 +1,35 @@
+name "The Dolls House"
+data
+################################
+#     $#      ########+# V#+++<#
+#  V   #    @ #C     #|| V##  ##
+# |-|| #   @  #< @|< #   V   V<#
+#  #   #  @   ##  |  #|| V   V##
+# @ @@ # V  % #      # # V#|#V #
+#C     #+#    #   @| #+# V#|--+#
+######C####C#U#    |+### #####+#
+#   M### V##############     ###
+#V   # #V<# #+#U#  U   #   V< +#
+#+V< # #V   ###--- @ # #   V @##
+##-V # #+    M# #--# | #   V|V##
+# +V # ##     #      |<  #+< +<#
+#  -  |    #< V        #########
+#########  #+ # ########       #
+# |U    #######          ##@   #
+#  V  #       # ##     ###M<   #
+#  -  #   M<  ###    V<#     V #
+##   ##       ##  # |< ## #C## #
+###+##    @|C    ##  @+#+ V    #
+# |###    +#####################
+# ########### V|<#+  V #+|-#   #
+# V#+++++++#* +<###  U ##<   @ #
+# +########## |<#+#  - ##      #
+# ##<+<# V#V# |#### ## ## ##<@ #
+#|      +<#+   #V## #  #   #@V #
+#-##      # #   +#         #@V #
+# +# U@|  --V     |V   ##    --#
+# V# # |# #+V    #|C @<#       #
+# +# #@#VV####   # #   # #U#   #
+# -V   #--     ##+#+#  #+#+#  +#
+################################
+end
diff --git a/maps/the-happy-hour b/maps/the-happy-hour
new file mode 100644 (file)
index 0000000..6daeb86
--- /dev/null
@@ -0,0 +1,35 @@
+name "The Happy Hour"
+data
+################################
+# U +##         # +#+     ##+V #
+# -V #  #  U  V #|C#  ### #+<< #
+#  @    V ##++#    #<  ##     +#
+##    ### ##U##C       ##### ###
+#+   U# #  #######U###U#####   #
+##+ ### #      ++###|#####V#+# #
+##########  ||<###+|<<+#|<+##V #
+#C#U#U#U#  #C  |#+#   ##    #- #
+#########< #++#<     ##++#     #
+#C$#*###|  #C+#  #  |<#### ##|<#
+########|  # ##< # V<#V V# #+|<#
+#MMM~###|        #+<|#V +# ##+|#
+########  #V   #######V< # #####
+########+#-V     #####+  # #OV #
+##+--+#####- +<# #+        ##- #
+#++###C   #+#### #   V ## +#   #
+# ##+## # ###    #   ##U# V# # #
+#  #+#  #     #### ##  -# +# V #
+#+ #   ##   ###++#        ## V #
+## ###|<##  +##### @%V #+    #-#
+#+   #+#+#   #++++   V ##### V #
+#C V< ##+##  ############  ##V #
+#+ -|++#V #   ###++  V<#   ### #
+########- ##<   ###O V   #  ## #
+#C####### # @     #  -  ###  # #
+########+ #### ## #+#   ###    #
+#+++++##+ ##+< ## ### ####  U  #
+#+   +###  #   ##     #+#   #< #
+#+  M+####   ###|<< #- #  @ @  #
+#+++++####~<###++   ##         #
+################################
+end
diff --git a/ui-curses.c b/ui-curses.c
new file mode 100644 (file)
index 0000000..02e09b3
--- /dev/null
@@ -0,0 +1,375 @@
+/* -*-c-*-
+ *
+ * $Id: ui-curses.c,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Curses user interface
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: ui-curses.c,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "xor.h"
+
+#if defined(HAVE_NCURSES_H)
+#  include <ncurses.h>
+#elif defined(HAVE_NCURSES_NCURSES_H)
+#  include <ncurses/ncurses.h>
+#else
+#  include <curses.h>
+#endif
+
+#ifdef __CYGWIN__
+#  include <windows.h>
+#  undef usleep
+#  define usleep(n) Sleep(n / 1000);
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+struct ui_state {
+  int vx, vy;
+  level *l;
+};
+
+/*---- Display setup ------------------------------------------------------*/
+
+#define VIEWX 5
+#define VIEWY 3
+#define VIEWWD 8
+#define VIEWHT 8
+#define CELLHT 2
+#define CELLWD 3
+
+#define STATUSX 40
+#define STATUSY 10
+#define STATUSWD 36
+#define STATUSHT 2
+
+#define MESSAGEY 16
+
+static chtype *dispmap[CHAR_MAX], mdispmap[CHAR_MAX];
+
+static struct { int c; chtype m; chtype d[CELLHT * CELLWD]; } disptab[] = {
+  { C_EMPTY,   ' ',    { ' ', ' ', ' ',   ' ', ' ', ' ' } },
+  { C_PLAYER,  '$',    { '|', '~', '|',   '\\', '_', '/' } },
+  { C_SPARE,   '%',    { '|', 'X', '|',   '\\', '_', '/' } },
+  { C_EXIT,    '=',    { '|', '=', '|',   '|', '_', '|' } },
+  { C_WALL,    '#',    { '#', '#', '#',   '#', '#', '#' } },
+  { C_MASK,    '+',    { 'o', ' ', 'o',   ' ', '>', ' ' } },
+  { C_NWMAP,   'M',    { '|', '~', '|',   '|', '_', '|' } },
+  { C_NEMAP,   'M',    { '|', '~', '|',   '|', '_', '|' } },
+  { C_SWMAP,   'M',    { '|', '~', '|',   '|', '_', '|' } },
+  { C_SEMAP,   'M',    { '|', '~', '|',   '|', '_', '|' } },
+  { C_DOT,     ':',    { ':', ':', ':',   ':', ':', ':' } },
+  { C_WAVE,    '~',    { '~', '~', '~',   '~', '~', '~' } },
+  { C_CHICKEN, '<',    { '<', 'o', ')',   ' ', '(', ')' } },
+  { C_FISH,    'V',    { ' ', 'V', ' ',   ' ', 'V', ' ' } },
+  { C_HBOMB,   'U',    { '_', 'T', '_',   '|', '_', '|' } },
+  { C_VBOMB,   'C',    { ' ', ',', '*',   '(', ')', ' ' } },
+  { C_DOLLY,   '@',    { '\\', '@', '/',  '/', '=', '\\' } },
+  { C_SWITCH,  '~',    { 'o', ' ', 'o',   ' ', '*', ' ' } },
+  { C_BMUS,    'O',    { '/', '~', '\\',  '\\', '_', '/' } },
+  { 0,         0,      { 0 } }
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+static void rect(int x, int y, int w, int h)
+{
+  int i;
+
+  mvaddch(y - 1, x - 1, ACS_ULCORNER);
+  for (i = 0; i < w; i++) addch(ACS_HLINE);
+  addch(ACS_URCORNER);
+  for (i = 0; i < h; i++) {
+    mvaddch(y + i, x - 1, ACS_VLINE);
+    mvaddch(y + i, x + w, ACS_VLINE);
+  }
+  mvaddch(y + h, x - 1, ACS_LLCORNER);
+  for (i = 0; i < w; i++) addch(ACS_HLINE);
+  addch(ACS_LRCORNER);
+}
+
+static void hbar(int x, int y, int w)
+{
+  int i;
+
+  move(y, x - 1);
+  addch(ACS_LTEE);
+  for (i = 0; i < w; i++) addch(ACS_HLINE);
+  addch(ACS_RTEE);
+}
+
+static void vbar(int x, int y, int h)
+{
+  int i;
+
+  mvaddch(y - 1, x, ACS_TTEE);
+  for (i = 0; i < h; i++) mvaddch(y + i, x, ACS_VLINE);
+  mvaddch(y + h, x, ACS_BTEE);
+}
+
+static void draw(void)
+{
+  erase();
+  rect(VIEWX, VIEWY, VIEWWD * CELLWD, VIEWHT * CELLHT);
+  rect(STATUSX, STATUSY - 2, STATUSWD, STATUSHT + 2);
+  hbar(STATUSX, STATUSY - 1, STATUSWD);
+  vbar(STATUSX + STATUSWD - 5, STATUSY, STATUSHT);
+}
+
+void ui_init(void)
+{
+  int i;
+
+  /* --- Kick curses --- */
+
+  initscr();
+  if (LINES < 25 || COLS < 80) {
+    endwin();
+    fprintf(stderr, "terminal too small\n");
+    exit(1);
+  }
+  cbreak();
+  noecho();
+  nonl();
+  intrflush(stdscr, FALSE);
+  keypad(stdscr, TRUE);
+  draw();
+
+  /* --- Initialize the display map --- */
+
+  for (i = 0; disptab[i].c; i++) {
+    dispmap[disptab[i].c] = disptab[i].d;
+    mdispmap[disptab[i].c] = disptab[i].m;
+  }
+  for (i = 0; i < CELLWD * CELLHT; i++)
+    dispmap[C_WALL][i] = ' ' | A_REVERSE;
+  mdispmap[C_WALL] = ' ' | A_REVERSE;
+}
+
+static void redraw(ui_state *u)
+{
+  const level *l = u->l;
+  int x, y, i, j, c;
+  
+  for (y = 0; y < VIEWHT; y++) {
+    for (j = 0; j < CELLHT; j++) {
+      move(VIEWY + y * CELLHT + j, VIEWX);
+      for (x = 0; x < VIEWWD; x++) {
+       c = CELL(l, u->vx + x, u->vy + y) & CF_CELLMASK;
+       if ((l->f & LF_DARK) && (cellmap[c]->f & CF_HIDE)) c = C_EMPTY;
+       for (i = 0; i < CELLWD; i++) {
+         addch(dispmap[c][i + j * CELLWD]);
+       }
+      }
+    }
+  }
+
+  mvaddstr(STATUSY - 2, STATUSX + (STATUSWD - strlen(u->l->name))/2,
+          u->l->name);
+
+  mvprintw(STATUSY, STATUSX, "Masks: %2d/%2d", l->m, l->mtot);
+  mvprintw(STATUSY + 1, STATUSX, "Moves: %4d/%4d", l->v, l->vtot);
+  move(STATUSY, STATUSX + STATUSWD - 4);
+  if (l->f & LF_NWMAP) { addch(' ' | A_REVERSE); addch(' ' | A_REVERSE); }
+  else { addch(' '); addch(' '); }
+  if (l->f & LF_NEMAP) { addch(' ' | A_REVERSE); addch(' ' | A_REVERSE); }
+  else { addch(' '); addch(' '); }
+  move(STATUSY + 1, STATUSX + STATUSWD - 4);
+  if (l->f & LF_SWMAP) { addch(' ' | A_REVERSE); addch(' ' | A_REVERSE); }
+  else { addch(' '); addch(' '); }
+  if (l->f & LF_SEMAP) { addch(' ' | A_REVERSE); addch(' ' | A_REVERSE); }
+  else { addch(' '); addch(' '); }
+}
+
+void ui_update(ui_state *u)
+{
+  redraw(u);
+  refresh();
+}
+
+void ui_explode(struct ui_state *u, const point *pt, int n)
+{
+  int i, j, x, y;
+  static const chtype frame[][CELLWD * CELLHT] = {
+    { '\\', '|', '/',  '/', '|', '\\' },
+    { '*', '*', '*',   '*', '*', '*' },
+    { ':', ':', ':',   ':', ':', ':' },
+    { '.', '.', '.',   ':', ':', ':' },
+    { ' ', ' ', ' ',   ':', ':', ':' },
+    { ' ', ' ', ' ',   '.', '.', '.' }
+  };
+
+  redraw(u);
+  refresh();
+  for (i = 0; i < sizeof(frame)/sizeof(frame[0]); i++) {
+    for (j = 0; j < n; j++) {
+      if (pt[j].x < u->vx || pt[j].x >= u->vx + VIEWWD ||
+         pt[j].y < u->vy || pt[j].y >= u->vy + VIEWHT)
+       continue;
+      for (y = 0; y < CELLHT; y++) {
+       move(VIEWY + (pt[j].y - u->vy) * CELLHT + y,
+            VIEWX + (pt[j].x - u->vx) * CELLWD);
+       for (x = 0; x < CELLWD; x++)
+         addch(frame[i][x + CELLWD * y]);
+      }
+    }
+    refresh();
+    usleep(10000);
+  }
+}
+
+void ui_track(ui_state *u, int x, int y)
+{
+  if (u->vx == -1) {
+    u->vx = x - VIEWWD/2;
+    u->vy = y - VIEWHT/2;
+    if (u->vx < 0) u->vx = 0;
+    else if (u->vx > u->l->w - VIEWWD) u->vx = u->l->w - VIEWWD;
+    if (u->vy < 0) u->vy = 0;
+    else if (u->vy > u->l->h - VIEWHT) u->vy = u->l->h - VIEWHT;
+  } else {
+    if (u->vx + 1 > x) u->vx = x - 1;
+    else if (u->vx + VIEWWD - 2 < x) u->vx = x - VIEWWD + 2;
+    if (u->vy + 1 > y) u->vy = y - 1;
+    else if (u->vy + VIEWHT - 2 < y) u->vy = y - VIEWHT + 2;
+  }
+}
+
+ui_state *ui_start(level *l, int x, int y)
+{
+  ui_state *u = CREATE(ui_state);
+
+  u->l = l;
+  u->vx = u->vy = -1;
+  ui_track(u, x, y);
+  return (u);
+}
+
+void ui_switch(ui_state *u)
+{
+  redraw(u);
+}
+
+void ui_frame(struct ui_state *u)
+{
+  redraw(u);
+  refresh();
+  usleep(20000);
+}
+
+void ui_message(struct ui_state *u, const char *p)
+{
+  size_t n = strlen(p);
+  rect((COLS - n)/2, MESSAGEY, n, 1);
+  mvaddstr(MESSAGEY, (COLS - n)/2, p);
+  refresh();
+  usleep(500000);
+  draw();
+  redraw(u);
+}
+
+static void showmap(ui_state *u)
+{
+  const level *l = u->l;
+  int wd, ht, x, y;
+  int vs = 0, hs = 0, maxv, maxh;
+  int i, j;
+  int bit;
+  int c;
+
+  erase();
+  wd = l->w; if (wd + 6 > COLS) wd = COLS - 6;
+  ht = l->h; if (ht + 6 > LINES) ht = LINES - 6;
+  x = (COLS - wd)/2; y = (LINES - ht)/2;
+  rect(x, y, wd, ht);
+  maxh = l->w - wd; maxv = l->h - ht;
+
+  for (;;) {
+    for (j = 0; j < ht; j++) {
+      move(y + j, x);
+      for (i = 0; i < wd; i++) {
+       bit = LF_NWMAP;
+       if (hs + i >= l->w/2) bit <<= 1;
+       if (vs + j >= l->h/2) bit <<= 2;
+       if (!(l->f & bit))
+         c = C_EMPTY;
+       else {
+         c = CELL(l, hs + i, vs + j) & CF_CELLMASK;
+         if (!(cellmap[c]->f & CF_MAP)) c = C_EMPTY;
+       }
+       addch(mdispmap[c]);
+      }
+    }
+    switch (getch()) {
+      case 'q': case 'Q': case 'm': case 'M': case 0x1b: goto done;
+      case KEY_UP:    case 'k': case 'K': vs--; break;
+      case KEY_DOWN:  case 'j': case 'J': vs++; break;
+      case KEY_LEFT:  case 'h': case 'H': hs--; break;
+      case KEY_RIGHT: case 'l': case 'L': hs++; break;
+    }
+    if (hs < 0) hs = 0; else if (hs > maxh) hs = maxh;
+    if (vs < 0) vs = 0; else if (vs > maxv) vs = maxv;
+  }
+done:
+  draw();
+  redraw(u);
+  return;
+}
+
+void ui_go(struct game_state *g, ui_state *u)
+{
+  refresh();
+  switch (getch()) {
+    case KEY_UP:    case 'k': case 'K': game_move(g,  0, -1); break;
+    case KEY_DOWN:  case 'j': case 'J': game_move(g,  0, +1); break;
+    case KEY_LEFT:  case 'h': case 'H': game_move(g, -1,  0); break;
+    case KEY_RIGHT: case 'l': case 'L': game_move(g, +1,  0); break;
+    case 'u': case 'U': undo(g); break;
+    case 'r': case 'R': redo(g); break;
+    case ' ': case '\r': game_switch(g); break;
+    case 'm': case 'M': showmap(u); break;
+    case 0x1b: case 'q': case 'Q': game_quit(g); break;
+  }
+}
+
+void ui_destroy(ui_state *u)
+{
+  DESTROY(u);
+}
+
+void ui_exit(void)
+{
+  endwin();
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/undo.c b/undo.c
new file mode 100644 (file)
index 0000000..3186523
--- /dev/null
+++ b/undo.c
@@ -0,0 +1,236 @@
+/* -*-c-*-
+ *
+ * $Id: undo.c,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Management of undo records
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: undo.c,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "xor.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+void undo_init(game_state *g)
+{
+  g->u = g->r = g->m = 0;
+}
+
+void undo_begin(game_state *g)
+{
+  undo_move *u = CREATE(undo_move);
+  u->next = 0;
+  u->act = 0;
+  g->m = u;
+}
+
+void undo_cell(game_state *g, int x, int y, int c)
+{
+  undo_action *a, **aa;
+
+  for (aa = &g->m->act; *aa; aa = &a->next) {
+    a = *aa;
+    if (a->type == A_CELL && a->u.c.x == x && a->u.c.y == y) {
+      if (a->u.c.c == c) {
+       *aa = a->next;
+       DESTROY(a);
+      }
+      return;
+    }
+  }
+  if (c == CELL(g->l, x, y)) return;
+  a = CREATE(undo_action);
+  a->next = 0;
+  *aa = a;
+  a->type = A_CELL;
+  a->u.c.x = x;
+  a->u.c.y = y;
+  a->u.c.c = CELL(g->l, x, y);
+}
+
+void undo_die(game_state *g, game_player *p)
+{
+  undo_action *a = CREATE(undo_action);
+
+  a->next = g->m->act;
+  a->type = A_DIE;
+  a->u.p = p;
+  g->m->act = a;
+}
+
+void undo_levelf(game_state *g)
+{
+  undo_action *a = CREATE(undo_action);
+
+  a->next = g->m->act;
+  a->type = A_LEVEL;
+  a->u.f = g->l->f;
+  g->m->act = a;
+}
+
+void undo_mask(game_state *g)
+{
+  undo_action *a = CREATE(undo_action);
+
+  a->next = g->m->act;
+  a->type = A_MASK;
+  a->u.n = g->l->m;
+  g->m->act = a;
+}
+
+void undo_pmove(game_state *g)
+{
+  undo_action *a = CREATE(undo_action);
+
+  a->next = g->m->act;
+  a->type = A_MOVE;
+  a->u.c.x = g->p->x;
+  a->u.c.y = g->p->y;
+  g->m->act = a;
+}
+
+void undo_switch(game_state *g)
+{
+  undo_action *a = CREATE(undo_action);
+  a->next = g->m->act;
+  a->type = A_SWITCH;
+  a->u.p = g->p;
+  g->m->act = a;
+}
+
+static void freelist(undo_move **mm)
+{
+  undo_move *u, *uu;
+  undo_action *a, *aa;
+
+  for (u = *mm; u; u = uu) {
+    uu = u->next;
+    for (a = u->act; a; a = aa) {
+      aa = a->next;
+      DESTROY(a);
+    }
+    DESTROY(u);
+  }
+  *mm = 0;
+}
+
+void undo_commit(game_state *g)
+{
+  if (!g->m->act)
+    DESTROY(g->m);
+  else {
+    g->m->next = g->u;
+    g->u = g->m;
+    freelist(&g->r);
+  }
+  g->m = 0;
+}
+
+static int do_undo(game_state *g, undo_move **m, undo_move **mm)
+{
+  undo_move *u = *m;
+  undo_action *a;
+  game_player *p;
+  int x, y, c;
+  unsigned f;
+
+  if (!u) return (0);
+  *m = u->next;
+
+  for (a = u->act; a; a = a->next) {
+    switch (a->type) {
+      case A_CELL:
+       c = a->u.c.c;
+       a->u.c.c = CELL(g->l, a->u.c.x, a->u.c.y);
+       CELLSET(g->l, a->u.c.x, a->u.c.y, c);
+       break;
+      case A_DIE:
+       a->u.p->f &= ~PF_DEAD;
+       a->type = A_LIVE;
+       break;
+      case A_MASK:
+       c = a->u.n;
+       a->u.n = g->l->m;
+       g->l->m = c;
+       break;
+      case A_LEVEL:
+       f = a->u.f;
+       a->u.f = g->l->f;
+       g->l->f = f;
+       break;
+      case A_MOVE:
+       x = a->u.c.x;
+       y = a->u.c.y;
+       a->u.c.x = g->p->x;
+       a->u.c.y = g->p->y;
+       g->p->x = x;
+       g->p->y = y;
+       break;
+      case A_LIVE:
+       a->u.p->f |= PF_DEAD;
+       a->type = A_DIE;
+       break;
+      case A_SWITCH:
+       p = a->u.p;
+       a->u.p = g->p;
+       game_switchto(g, p);
+       break;
+      default:
+       abort();
+    }
+  }
+  
+  u->next = *mm;
+  *mm = u;
+  return (1);
+}
+
+void undo(game_state *g)
+{
+  if (do_undo(g, &g->u, &g->r)) g->l->v--;
+  ui_update(g->p->u);
+}
+
+void redo(game_state *g)
+{
+  if (do_undo(g, &g->r, &g->u)) g->l->v++;
+  ui_update(g->p->u);
+}
+
+void undo_free(game_state *g)
+{
+  freelist(&g->m);
+  freelist(&g->u);
+  freelist(&g->r);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/xor.c b/xor.c
new file mode 100644 (file)
index 0000000..971feeb
--- /dev/null
+++ b/xor.c
@@ -0,0 +1,58 @@
+/* -*-c-*-
+ *
+ * $Id: xor.c,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Main program
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: xor.c,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "xor.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+int main(void)
+{
+  level *l;
+  FILE *fp;
+
+  cellinfo_init();
+  fp = fopen("map", "r");
+  l = lev_read(fp);
+  ui_init();
+  game_go(l);
+  ui_exit();
+  lev_free(l);
+  return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
diff --git a/xor.h b/xor.h
new file mode 100644 (file)
index 0000000..ece7a74
--- /dev/null
+++ b/xor.h
@@ -0,0 +1,299 @@
+/* -*-c-*-
+ *
+ * $Id: xor.h,v 1.1 2003/12/12 10:55:30 mdw Exp $
+ *
+ * Main header for XOR
+ *
+ * (c) 2003 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------* 
+ *
+ * This file is part of XOR.
+ *
+ * XOR is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * XOR is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with XOR; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------* 
+ *
+ * $Log: xor.h,v $
+ * Revision 1.1  2003/12/12 10:55:30  mdw
+ * Initial checkin.  Not there yet.
+ *
+ */
+
+#ifndef XOR_H
+#define XOR_H
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <unistd.h>
+
+#include <mLib/alloc.h>
+#include <mLib/darray.h>
+#include <mLib/dstr.h>
+#include <mLib/str.h>
+#include <mLib/sub.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct level {
+  int w, h;                            /* Width and height, in cells */
+  char *name;                          /* Level name */
+  unsigned f;                          /* Various flags */
+  int m, mtot;                         /* Masks collected, and total */
+  int v, vtot;                         /* Moves made, and allowed */
+  int *d;                              /* Level data, row-major order */
+} level;
+
+#define LF_NWMAP 1u                    /* North-west map collected */
+#define LF_NEMAP 2u                    /* North-east map collected */
+#define LF_SWMAP 4u                    /* South-west map collected */
+#define LF_SEMAP 8u                    /* South-east map collected */
+#define LF_DARK 16u                    /* Someone turned the lights out */
+
+#define LF_MAP "1234D"                 /* Map bits to characters */
+
+/* --- Cells and their meanings --- */
+
+#define C_PLAYER       '$'             /* Active player */
+#define C_SPARE                '%'             /* Inactive player */
+#define C_WALL         '#'             /* Solid wall */
+#define C_EXIT         '*'             /* Exit door */
+#define C_EMPTY                ' '             /* Empty space */
+#define C_MASK         '+'             /* Mask */
+#define C_NWMAP                '1'             /* North-west map segment */
+#define C_NEMAP                '2'             /* North-east map segment */
+#define C_SWMAP                '3'             /* South-west map segment */
+#define C_SEMAP                '4'             /* South-east map segment */
+#define C_UKMAP                'M'             /* Unknown map segment */
+#define C_DOT          '-'             /* Dots -- horizontal force-field */
+#define C_WAVE         '|'             /* Waves -- vertical force-field */
+#define C_CHICKEN      '<'             /* Chicken -- moves left */
+#define C_FISH         'V'             /* Fish -- moves downwards */
+#define C_HBOMB                'C'             /* H-bomb -- moves like chicken */
+#define C_VBOMB                'U'             /* V-bomb -- moves like fish */
+#define C_DOLLY                '@'             /* Dolly -- slides about */
+#define C_SWITCH       '~'             /* Light-switch mask */
+#define C_BMUS         'O'             /* Teleport pad */
+
+/* --- Celll flags --- */
+
+#define CF_CELLMASK 255u               /* Mask for cell type */
+#define CF_INFLIGHT 256u               /* Object is currently moving */
+#define CF_DOLLYUP 0u                  /* Dolly moving up */
+#define CF_DOLLYDOWN 512u              /* Dolly moving down */
+#define CF_DOLLYLEFT 1024u             /* Dolly moving left */
+#define CF_DOLLYRIGHT 1536u            /* Dolly moving right */
+#define CF_DOLLYMASK 1536u             /* Mask for dolly movement */
+
+/* --- Macros for accessing the map data --- */
+
+#define CELLREF(l, x, y)                                               \
+  ((l)->d[(x) + (y) * (l)->w])
+
+#define CELLOK(l, x, y)                                                        \
+  ((x) >= 0 && (x) < (l)->w && (y) >= 0 && (y) < (l)->h)
+
+#define CELLSET(l, x, y, c)                                            \
+  (CELLOK((l), (x), (y)) ?                                             \
+     CELLREF((l), (x), (y)) = (c), (void)0 :                           \
+     (void)0)
+
+#define CELL(l, x, y)                                                  \
+  (CELLOK((l), (x), (y)) ?                                             \
+     CELLREF((l), (x), (y)) :                                          \
+     C_WALL)
+
+#define CELLSETFL(l, x, y, f)                                          \
+  (CELLOK((l), (x), (y)) ?                                             \
+     CELLREF((l), (x), (y)) |= (f), (void)0 :                          \
+     (void)0)
+
+#define CELLCLRFL(l, x, y, f)                                          \
+  (CELLOK((l), (x), (y)) ?                                             \
+     CELLREF((l), (x), (y)) &= ~(f), (void)0 :                         \
+     (void)0)
+
+/* --- UI information --- *
+ *
+ * This is private to the UI layer.
+ */
+
+typedef struct ui_state ui_state;
+
+/* --- Player structure --- */
+
+typedef struct game_player {
+  struct game_player *next, *prev;     /* Link in list (forward only) */
+  int x, y;                            /* Current position */
+  unsigned f;                          /* Flags */
+  ui_state *u;                         /* User interface state */
+} game_player;
+
+#define PF_DEAD 1u                     /* Player has been killed */
+
+/* --- Undo structures --- */
+
+typedef struct undo_action {
+  struct undo_action *next;            /* Next action in chian */
+  int type;                            /* What kind of thing happened */
+  union {
+    struct { int x, y, c; } c;         /* Cell change */
+    game_player *p;                    /* Player */
+    unsigned f;                                /* Flags to restore */
+    int n;                             /* Counter to restore */
+  } u;
+} undo_action;
+
+enum {
+  A_CELL,                              /* Cell changed contents */
+  A_DIE,                               /* Player died */
+  A_LIVE,                              /* Player became alive */
+  A_LEVEL,                             /* Level flags changed */
+  A_MASK,                              /* Mask count changed */
+  A_MOVE,                              /* Player moved */
+  A_SWITCH,                            /* Switch to other player */
+  A_END
+};
+
+typedef struct undo_move {
+  struct undo_move *next;
+  undo_action *act;
+} undo_move;
+
+/* --- Game state --- */
+
+typedef struct game_state {
+  struct level *l;                     /* Level information */
+  game_player *p, *ptail;              /* Player list */
+  unsigned f;                          /* Various flags */
+  undo_move *u, *r, *m;                        /* Undo, redo and current lists */
+} game_state;
+
+#define GF_QUIT 1u
+#define GF_WIN 2u
+
+/* --- The cell attributes table --- */
+
+typedef struct cellinfo {
+  int c;                               /* Cell type */
+  unsigned f;                          /* Various flags */
+
+  void (*hit)(game_state *, int /*x*/, int /*y*/, int /*hx*/, int /*hy*/);
+  /* Object at @(x, y)@ has been struck by another object (e.g., a chicken)
+     which is now at @(hx, hy)@.  */
+
+  int (*nudge)(game_state *, int /*x*/, int /*y*/, int /*dx*/, int /*dy*/);
+  /* Object is being nudged by player in given direction.  Answer @0@ if
+     nothing happens (and the player cannot enter), @1@ if it's OK and the
+     space is vacated, or @-1@ if something strange happened.  */
+
+  int (*moveh)(game_state *, int /*x*/, int /*y*/);
+  int (*movev)(game_state *, int /*x*/, int /*y*/);
+  /* See if object can move on its own horizontally or vertically.  Return
+   * zero if it won't move, or nonzero otherwise.  */
+} cellinfo;
+
+#define CF_HIDE 1u                     /* Invisible in the dark */
+#define CF_MASK 2u                     /* Must collect these */
+#define CF_HPASS 4u                    /* Object is passable horizontally */
+#define CF_VPASS 8u                    /* Object is passable vertically */
+#define CF_PLAYER 16u                  /* Object is a player */
+#define CF_MAP 32u                     /* Object shows up on map */
+
+/* --- Other structures --- */
+
+typedef struct point { int x, y; } point;
+
+/*----- Global variables --------------------------------------------------*/
+
+extern const cellinfo *cellmap[];
+
+/*----- Cell attributes ---------------------------------------------------*/
+
+extern void cellinfo_init(void);
+
+/*----- Level management --------------------------------------------------*/
+
+extern int lev_findnext(const level */*l*/, int /*c*/,
+                       int */*x*/, int */*y*/);
+extern int lev_findcell(const level */*l*/, int /*c*/,
+                       int */*x*/, int */*y*/);
+extern level *lev_read(FILE */*fp*/);
+extern void lev_write(const level */*l*/, FILE */*fp*/);
+extern void lev_free(level */*l*/);
+extern level *lev_copy(const level */*l*/);
+
+/*----- User interface ----------------------------------------------------*/
+
+extern void ui_frame(ui_state */*u*/);
+extern void ui_message(ui_state */*u*/, const char */*p*/);
+extern void ui_explode(ui_state */*u*/, const point */*pt*/, int /*n*/);
+extern void ui_track(ui_state */*u*/, int /*x*/, int /*y*/);
+extern void ui_update(ui_state */*u*/);
+extern void ui_switch(ui_state */*u*/);
+extern void ui_init(void);
+extern void ui_update(ui_state */*u*/);
+extern ui_state *ui_start(level */*l*/, int /*x*/, int /*y*/);
+extern void ui_go(game_state */*g*/, ui_state */*u*/);
+extern void ui_destroy(ui_state */*u*/);
+extern void ui_exit(void);
+
+/*----- Undo management ---------------------------------------------------*/
+
+extern void undo_init(game_state */*g*/);
+extern void undo_begin(game_state */*g*/);
+extern void undo_cell(game_state */*g*/, int /*x*/, int /*y*/, int /*c*/);
+extern void undo_die(game_state */*g*/, game_player */*p*/);
+extern void undo_pmove(game_state */*g*/);
+extern void undo_levelf(game_state */*g*/);
+extern void undo_mask(game_state */*g*/);
+extern void undo_switch(game_state */*g*/);
+extern void undo_commit(game_state */*g*/);
+extern void undo(game_state */*g*/);
+extern void redo(game_state */*g*/);
+extern void undo_free(game_state */*g*/);
+
+/*----- Game engine -------------------------------------------------------*/
+
+extern void game_explode(game_state */*g*/, const point */*pt*/, int /*n*/);
+extern void game_die(game_state */*g*/, int /*x*/, int /*y*/);
+extern void game_moveobj(game_state */*g*/, int /*x*/, int /*y*/,
+                        int /*xx*/, int /*yy*/);
+extern void game_switchto(game_state *g, game_player */*p*/);
+extern int game_switch(game_state */*g*/);
+extern void game_move(game_state */*g*/, int /*dx*/, int /*dy*/);
+extern void game_go(level */*l*/);
+extern void game_quit(game_state */*g*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif