From: mdw Date: Fri, 12 Dec 2003 10:55:30 +0000 (+0000) Subject: Initial checkin. Not there yet. X-Git-Url: https://git.distorted.org.uk/~mdw/xor/commitdiff_plain/fc27aa702e12309b976e4014fcb8b05e5e2e2e0a Initial checkin. Not there yet. --- fc27aa702e12309b976e4014fcb8b05e5e2e2e0a 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