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