From fc27aa702e12309b976e4014fcb8b05e5e2e2e0a Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 12 Dec 2003 10:55:30 +0000 Subject: [PATCH] Initial checkin. Not there yet. --- .cvsignore | 3 + .links | 5 + .skelrc | 8 + Makefile.am | 44 ++++++ acconfig.h | 69 +++++++++ cell.c | 403 +++++++++++++++++++++++++++++++++++++++++++++++++ config.h | 78 ++++++++++ configure.in | 44 ++++++ cvt.pl | 20 +++ game.c | 211 ++++++++++++++++++++++++++ level.c | 251 ++++++++++++++++++++++++++++++ maps/chicken-supreme | 35 +++++ maps/deja-vu | 35 +++++ maps/dollys-revenge | 35 +++++ maps/dots-and-waves | 35 +++++ maps/enlightenment | 35 +++++ maps/explosive-mixture | 35 +++++ maps/henrys-anguish | 35 +++++ maps/patience-pending | 35 +++++ maps/penultimate | 35 +++++ maps/razor-edge | 35 +++++ maps/something-fishy | 35 +++++ maps/the-challenge | 35 +++++ maps/the-decoder | 35 +++++ maps/the-dolls-house | 35 +++++ maps/the-happy-hour | 35 +++++ ui-curses.c | 375 +++++++++++++++++++++++++++++++++++++++++++++ undo.c | 236 +++++++++++++++++++++++++++++ xor.c | 58 +++++++ xor.h | 299 ++++++++++++++++++++++++++++++++++++ 30 files changed, 2629 insertions(+) create mode 100644 .cvsignore create mode 100644 .links create mode 100644 .skelrc create mode 100644 Makefile.am create mode 100644 acconfig.h create mode 100644 cell.c create mode 100644 config.h create mode 100644 configure.in create mode 100644 cvt.pl create mode 100644 game.c create mode 100644 level.c create mode 100644 maps/chicken-supreme create mode 100644 maps/deja-vu create mode 100644 maps/dollys-revenge create mode 100644 maps/dots-and-waves create mode 100644 maps/enlightenment create mode 100644 maps/explosive-mixture create mode 100644 maps/henrys-anguish create mode 100644 maps/patience-pending create mode 100644 maps/penultimate create mode 100644 maps/razor-edge create mode 100644 maps/something-fishy create mode 100644 maps/the-challenge create mode 100644 maps/the-decoder create mode 100644 maps/the-dolls-house create mode 100644 maps/the-happy-hour create mode 100644 ui-curses.c create mode 100644 undo.c create mode 100644 xor.c create mode 100644 xor.h diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 0000000..06bba5e --- /dev/null +++ b/.cvsignore @@ -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 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 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 index 0000000..1e0b37b --- /dev/null +++ b/Makefile.am @@ -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 index 0000000..6c94900 --- /dev/null +++ b/acconfig.h @@ -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 . */ + +#undef HAVE_NCURSES_NCURSES_H +/* Define if you have . */ + +#undef HAVE_CURSES_H +/* Define if you have . */ + +#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 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 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 . */ + +#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 header file. */ +/* #undef HAVE_CURSES_H */ + +/* Define if you have the header file. */ +#define HAVE_NCURSES_H 1 + +/* Define if you have the 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 index 0000000..51a0d16 --- /dev/null +++ b/configure.in @@ -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 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 () { + tr(-#12l, (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 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(""); + 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 index 0000000..f5f7c3c --- /dev/null +++ b/maps/chicken-supreme @@ -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 index 0000000..e24ce09 --- /dev/null +++ b/maps/deja-vu @@ -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 index 0000000..eed9fdd --- /dev/null +++ b/maps/dollys-revenge @@ -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 index 0000000..dd7ba6e --- /dev/null +++ b/maps/dots-and-waves @@ -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 index 0000000..d83e959 --- /dev/null +++ b/maps/enlightenment @@ -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# +#elif defined(HAVE_NCURSES_NCURSES_H) +# include +#else +# include +#endif + +#ifdef __CYGWIN__ +# include +# 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 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 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 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 +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +/*----- 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 -- 2.11.0