infra: Clean up project setup
[xor] / undo.c
1 /* -*-c-*-
2 *
3 * $Id$
4 *
5 * Management of undo records
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
29 /*----- Header files ------------------------------------------------------*/
30
31 #include "xor.h"
32
33 /*----- Main code ---------------------------------------------------------*/
34
35 void undo_init(game_state *g)
36 {
37 g->u = g->r = g->m = 0;
38 }
39
40 void undo_begin(game_state *g)
41 {
42 undo_move *u = CREATE(undo_move);
43 u->next = 0;
44 u->act = 0;
45 g->m = u;
46 }
47
48 void undo_cell(game_state *g, int x, int y, int c)
49 {
50 undo_action *a, **aa;
51
52 for (aa = &g->m->act; *aa; aa = &a->next) {
53 a = *aa;
54 if (a->type == A_CELL && a->u.c.x == x && a->u.c.y == y) {
55 if (a->u.c.c == c) {
56 *aa = a->next;
57 DESTROY(a);
58 }
59 return;
60 }
61 }
62 if (c == CELL(g->l, x, y)) return;
63 a = CREATE(undo_action);
64 a->next = 0;
65 *aa = a;
66 a->type = A_CELL;
67 a->u.c.x = x;
68 a->u.c.y = y;
69 a->u.c.c = CELL(g->l, x, y);
70 }
71
72 void undo_die(game_state *g, game_player *p)
73 {
74 undo_action *a = CREATE(undo_action);
75
76 a->next = g->m->act;
77 a->type = A_DIE;
78 a->u.p = p;
79 g->m->act = a;
80 }
81
82 void undo_levelf(game_state *g)
83 {
84 undo_action *a = CREATE(undo_action);
85
86 a->next = g->m->act;
87 a->type = A_LEVEL;
88 a->u.f = g->l->f;
89 g->m->act = a;
90 }
91
92 void undo_mask(game_state *g)
93 {
94 undo_action *a = CREATE(undo_action);
95
96 a->next = g->m->act;
97 a->type = A_MASK;
98 a->u.n = g->l->m;
99 g->m->act = a;
100 }
101
102 void undo_pmove(game_state *g)
103 {
104 undo_action *a = CREATE(undo_action);
105
106 a->next = g->m->act;
107 a->type = A_MOVE;
108 a->u.c.x = g->p->x;
109 a->u.c.y = g->p->y;
110 g->m->act = a;
111 }
112
113 void undo_switch(game_state *g)
114 {
115 undo_action *a = CREATE(undo_action);
116 a->next = g->m->act;
117 a->type = A_SWITCH;
118 a->u.p = g->p;
119 g->m->act = a;
120 }
121
122 static void freelist(undo_move **mm)
123 {
124 undo_move *u, *uu;
125 undo_action *a, *aa;
126
127 for (u = *mm; u; u = uu) {
128 uu = u->next;
129 for (a = u->act; a; a = aa) {
130 aa = a->next;
131 DESTROY(a);
132 }
133 DESTROY(u);
134 }
135 *mm = 0;
136 }
137
138 void undo_commit(game_state *g)
139 {
140 if (!g->m->act)
141 DESTROY(g->m);
142 else {
143 g->m->next = g->u;
144 g->u = g->m;
145 freelist(&g->r);
146 }
147 g->m = 0;
148 }
149
150 static int do_undo(game_state *g, undo_move **m, undo_move **mm)
151 {
152 undo_move *u = *m;
153 undo_action *a;
154 game_player *p;
155 int x, y, c;
156 unsigned f;
157
158 if (!u) return (0);
159 *m = u->next;
160
161 for (a = u->act; a; a = a->next) {
162 switch (a->type) {
163 case A_CELL:
164 c = a->u.c.c;
165 a->u.c.c = CELL(g->l, a->u.c.x, a->u.c.y);
166 CELLSET(g->l, a->u.c.x, a->u.c.y, c);
167 break;
168 case A_DIE:
169 a->u.p->f &= ~PF_DEAD;
170 a->type = A_LIVE;
171 break;
172 case A_MASK:
173 c = a->u.n;
174 a->u.n = g->l->m;
175 g->l->m = c;
176 break;
177 case A_LEVEL:
178 f = a->u.f;
179 a->u.f = g->l->f;
180 g->l->f = f;
181 break;
182 case A_MOVE:
183 x = a->u.c.x;
184 y = a->u.c.y;
185 a->u.c.x = g->p->x;
186 a->u.c.y = g->p->y;
187 g->p->x = x;
188 g->p->y = y;
189 ui_track(g->p->u, x, y);
190 break;
191 case A_LIVE:
192 a->u.p->f |= PF_DEAD;
193 a->type = A_DIE;
194 break;
195 case A_SWITCH:
196 p = a->u.p;
197 a->u.p = g->p;
198 game_switchto(g, p);
199 break;
200 default:
201 abort();
202 }
203 }
204
205 u->next = *mm;
206 *mm = u;
207 return (1);
208 }
209
210 void undo(game_state *g)
211 {
212 if (do_undo(g, &g->u, &g->r)) g->l->v--;
213 ui_update(g->p->u);
214 }
215
216 void redo(game_state *g)
217 {
218 if (do_undo(g, &g->r, &g->u)) g->l->v++;
219 ui_update(g->p->u);
220 }
221
222 void undo_free(game_state *g)
223 {
224 freelist(&g->m);
225 freelist(&g->u);
226 freelist(&g->r);
227 }
228
229 /*----- That's all, folks -------------------------------------------------*/