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 | |
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 -------------------------------------------------*/ |