chiark / gitweb /
3186523758ec26e4d62360e8db2d1f773bcca8e4
[xor] / undo.c
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
43 void undo_init(game_state *g)
44 {
45   g->u = g->r = g->m = 0;
46 }
47
48 void 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
56 void 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
80 void 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
90 void 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
100 void 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
110 void 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
121 void 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
130 static 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
146 void 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
158 static 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
217 void 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
223 void 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
229 void 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 -------------------------------------------------*/