infra: Clean up project setup
[xor] / undo.c
CommitLineData
fc27aa70 1/* -*-c-*-
2 *
73e1eaf2 3 * $Id$
fc27aa70 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
fc27aa70 29/*----- Header files ------------------------------------------------------*/
30
31#include "xor.h"
32
33/*----- Main code ---------------------------------------------------------*/
34
35void undo_init(game_state *g)
36{
37 g->u = g->r = g->m = 0;
38}
39
40void 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
48void 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
72void 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
82void 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
92void 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
102void 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
113void 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
122static 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
138void 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
150static 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;
73e1eaf2 189 ui_track(g->p->u, x, y);
fc27aa70 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
210void 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
216void 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
222void 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 -------------------------------------------------*/