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