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 | |
40 | void 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 | |
55 | void 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 | |
64 | void 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 | |
71 | static 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 | |
87 | static 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 | |
103 | static void updatev(game_state *g) { while (doupdatev(g) || doupdateh(g)) ; } |
104 | static void updateh(game_state *g) { while (doupdateh(g) || doupdatev(g)) ; } |
105 | |
106 | void 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 | |
122 | int 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 | |
138 | void 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 | |
161 | void game_quit(game_state *g) { g->f |= GF_QUIT; } |
162 | |
163 | static 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 | |
176 | void 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 -------------------------------------------------*/ |