chiark / gitweb /
infra: Clean up project setup
[xor] / game.c
CommitLineData
fc27aa70 1/* -*-c-*-
2 *
73e1eaf2 3 * $Id$
fc27aa70 4 *
5 * Main game logic
6 *
7 * (c) 2003 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of XOR.
13 *
14 * XOR is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * XOR is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with XOR; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
fc27aa70 29/*----- Header files ------------------------------------------------------*/
30
31#include "xor.h"
32
33/*----- Main code ---------------------------------------------------------*/
34
35#define G_CELLSET(g, x, y, c) do { \
36 undo_cell((g), (x), (y), (c)); \
37 CELLSET((g)->l, (x), (y), (c)); \
38} while (0)
39
40void game_die(game_state *g, int x, int y)
41{
42 game_player *p;
43
44 for (p = g->p; p && (p->x != x || p->y != y); p = p->next) ;
45 if (!p) return;
46 ui_frame(g->p->u);
47 undo_die(g, p);
48 p->f |= PF_DEAD;
49 G_CELLSET(g, p->x, p->y, C_EMPTY);
50 for (p = g->p; p && (p->f & PF_DEAD); p = p->next) ;
51 if (p) ui_message(g->p->u, "Whoops!");
52 else ui_message(g->p->u, "Gotcha!");
53}
54
55void game_explode(game_state *g, const point *pt, int n)
56{
57 int i;
58
59 ui_explode(g->p->u, pt, n);
60 for (i = 0; i < n; i++) game_die(g, pt[i].x, pt[i].y);
61 for (i = 0; i < n; i++) G_CELLSET(g, pt[i].x, pt[i].y, C_EMPTY);
62}
63
64void game_moveobj(game_state *g, int x, int y, int xx, int yy)
65{
66 int c = CELL(g->l, x, y);
67 G_CELLSET(g, x, y, C_EMPTY);
68 G_CELLSET(g, xx, yy, c);
69}
70
71static int doupdateh(game_state *g)
72{
73 level *l = g->l;
74 int i, j, c;
75 int rc = 0;
76
77 for (j = 0; j < l->h; j++) {
78 for (i = 0; i < l->w; i++) {
79 c = CELL(l, i, j) & CF_CELLMASK;
80 if (cellmap[c]->moveh && cellmap[c]->moveh(g, i, j)) rc = 1;
81 }
82 }
83 if (rc) ui_frame(g->p->u);
84 return (rc);
85}
86
87static int doupdatev(game_state *g)
88{
89 level *l = g->l;
90 int i, j, c;
91 int rc = 0;
92
93 for (i = 0; i < l->w; i++) {
94 for (j = l->h - 1; j >= 0; j--) {
95 c = CELL(l, i, j) & CF_CELLMASK;
96 if (cellmap[c]->movev && cellmap[c]->movev(g, i, j)) rc = 1;
97 }
98 }
99 if (rc) ui_frame(g->p->u);
100 return (rc);
101}
102
103static void updatev(game_state *g) { while (doupdatev(g) || doupdateh(g)) ; }
104static void updateh(game_state *g) { while (doupdateh(g) || doupdatev(g)) ; }
105
106void game_switchto(game_state *g, game_player *p)
107{
108 /* --- Don't stash undo records here --- */
109
110 if (!(g->p->f & PF_DEAD))
111 CELLSET(g->l, g->p->x, g->p->y, C_SPARE);
112 g->p->prev = g->ptail;
113 p->prev->next = 0;
114 g->ptail->next = g->p;
115 g->ptail = p->prev;
116 p->prev = 0;
117 g->p = p;
fc27aa70 118 CELLSET(g->l, g->p->x, g->p->y, C_PLAYER);
119 ui_switch(g->p->u);
120}
121
122int game_switch(game_state *g)
123{
124 game_player *p;
125
126 if (!g->p)
127 return (0);
128 for (p = g->p->next; p && (p->f & PF_DEAD); p = p->next)
129 ;
130 if (!p) return (0);
131 if (g->l->v >= g->l->vtot) return (1);
73e1eaf2 132 g->l->v++;
fc27aa70 133 undo_switch(g);
134 game_switchto(g, p);
135 return (1);
136}
137
138void game_move(game_state *g, int dx, int dy)
139{
140 int x = g->p->x;
141 int y = g->p->y;
142 int c = CELL(g->l, x + dx, y + dy) & CF_CELLMASK;
143
144 if (g->p->f & PF_DEAD) return;
145 if (g->l->v >= g->l->vtot) return;
146 if ((cellmap[c]->f & ((dx ? CF_HPASS : 0) | (dy ? CF_VPASS : 0))) ||
147 (cellmap[c]->nudge &&
148 cellmap[c]->nudge(g, x + dx, y + dy, dx, dy) > 0)) {
149 undo_pmove(g);
150 game_moveobj(g, x, y, x + dx, y + dy);
151 g->p->x = x + dx;
152 g->p->y = y + dy;
153 g->l->v++;
154 ui_track(g->p->u, x + dx, y + dy);
155 if (dx) updatev(g); else updateh(g);
156 ui_update(g->p->u);
157 if (g->p->f & PF_DEAD) game_switch(g);
158 }
159}
160
161void game_quit(game_state *g) { g->f |= GF_QUIT; }
162
163static void addplayer(game_state *g, int x, int y)
164{
165 game_player *p = CREATE(game_player);
166 p->f = 0;
167 p->x = x;
168 p->y = y;
169 p->u = ui_start(g->l, x, y);
170 p->next = 0;
171 p->prev = g->ptail;
172 if (g->ptail) g->ptail->next = p; else g->p = p;
173 g->ptail = p;
174}
175
176void game_go(level *l)
177{
178 game_state g;
179 int x, y;
180
181 g.l = lev_copy(l);
182 lev_write(g.l, stdout);
183 g.f = 0;
184 g.ptail = 0;
185 lev_findcell(l, C_PLAYER, &x, &y);
186 addplayer(&g, x, y);
187 if (lev_findcell(l, C_SPARE, &x, &y)) {
188 do
189 addplayer(&g, x, y);
190 while (lev_findnext(l, C_SPARE, &x, &y));
191 }
192 undo_init(&g);
193 ui_switch(g.p->u);
194 while (!(g.f & GF_QUIT)) {
195 undo_begin(&g);
196 ui_go(&g, g.p->u);
197 undo_commit(&g);
198 }
199 lev_free(g.l);
200 undo_free(&g);
201}
202
203/*----- That's all, folks -------------------------------------------------*/