--- /dev/null
+.deps config.* stamp-h* xor
+configure aclocal.m4
+Makefile Makefile.in
--- /dev/null
+COPYING
+INSTALL
+install-sh
+mkinstalldirs
+missing
--- /dev/null
+;;; -*-emacs-lisp-*-
+
+(setq skel-alist
+ (append
+ '((author . "Straylight/Edgeware")
+ (program . "XOR")
+ (full-title . "XOR"))
+ skel-alist))
--- /dev/null
+## -*-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 ---------------------------------------------------
--- /dev/null
+/* -*-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
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* 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
--- /dev/null
+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 -------------------------------------------------
--- /dev/null
+#! /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;
+}
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+name "Dots and Waves"
+data
+################################
+# --- #
+# ##########-################# #
+# #+| M %# ----- # #
+#+#+ ### ############### # #
+# ### + # # #
+# #+######-##########M## # # #
+### # #| # # # #
+#-- # +####-###--|##### # # # #
+#+| # ##| +| + |+ # # - # #
+#+| # #+| ############ #+# # # #
+#+| # # | #+#+ # ### # # #
+#+| #|# | # ###----# # #+# # # #
+#|| #M# | # # # # # #$#
+### #|# # # #+## # # # # # # # #
+#+# #|# # # ###++| | | | | #
+# # # # # #+#+#*+# # # # # # # #
+# # # # # ### #### # # # # # # #
+#+# # # # # # # # # # #
+# # # # ### #####-## # # #+# # #
+# # # # #+| # +# # ### # #
+#+# # # +| #-|-###### # #+# # #
+# # - # #+| --||#+ # # # #
+# ### # #####|--######## # # # #
+# #+#|# -+#--|+#+- # #+# #
+# #+#|###|##############|# ### #
+# # #+#++|| #+ #
+# - ####### ############-### #
+# #- -+#+ #
+# ##-#######---------##### M-#
+# |+#
+################################
+end
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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 -------------------------------------------------*/
--- /dev/null
+/* -*-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