fc27aa70 |
1 | /* -*-c-*- |
2 | * |
73e1eaf2 |
3 | * $Id$ |
fc27aa70 |
4 | * |
5 | * Level I/O and handling |
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 | /*----- Data structures ---------------------------------------------------*/ |
34 | |
35 | DA_DECL(int_v, int); |
36 | |
37 | /*----- Main code ---------------------------------------------------------*/ |
38 | |
39 | int lev_findnext(const level *l, int c, int *x, int *y) |
40 | { |
41 | int n = l->w * l->h; |
42 | int i; |
43 | |
44 | for (i= *y * l->w + *x + 1; i < n; i++) { |
45 | if ((l->d[i] & CF_CELLMASK) == c) { |
46 | *x = i % l->w; |
47 | *y = i / l->w; |
48 | return (1); |
49 | } |
50 | } |
51 | return (0); |
52 | } |
53 | |
54 | int lev_findcell(const level *l, int c, int *x, int *y) |
55 | { |
56 | int n = l->w * l->h; |
57 | int i; |
58 | |
59 | for (i = 0; i < n; i++) { |
60 | if ((l->d[i] & CF_CELLMASK) == c) { |
61 | if (x) *x = i % l->w; |
62 | if (y) *y = i / l->w; |
63 | return (1); |
64 | } |
65 | } |
66 | return (0); |
67 | } |
68 | |
69 | level *lev_read(FILE *fp) |
70 | { |
71 | level *l = CREATE(level); |
72 | dstr d = DSTR_INIT, dd = DSTR_INIT; |
73 | int_v v = DA_INIT; |
74 | char *p, *q, *r; |
75 | int *pp; |
76 | unsigned f; |
77 | int i, n, nn; |
78 | int x, y, xx, yy; |
79 | int ind, max; |
80 | |
81 | /* --- Basic initialization --- */ |
82 | |
83 | l->name = xstrdup("<untitled>"); |
84 | l->w = l->h = 0; |
85 | l->d = 0; |
86 | l->f = 0; |
87 | l->m = 0; |
88 | l->mtot = -1; |
89 | l->v = 0; |
90 | l->vtot = 2000; |
91 | |
92 | ind = -1; |
93 | max = 0; |
94 | |
95 | /* --- Read the preamble --- */ |
96 | |
97 | while (dstr_reset(&d), dstr_putline(&d, fp) != EOF) { |
98 | p = d.buf; |
99 | q = str_qword(&p, 0); |
100 | if (!q || *q == '#' || *q == ';') |
101 | continue; |
102 | if (strcmp(q, "name") == 0 && (q = str_qword(&p, STRF_QUOTE)) != 0) { |
103 | xfree(l->name); |
104 | l->name = xstrdup(q); |
105 | } else if (strcmp(q, "flags") == 0 && (q = str_qword(&p, 0)) != 0) { |
106 | f = 0; |
107 | while (*q) { |
108 | const char *lfmap = LF_MAP; |
109 | if ((r = strchr(lfmap, *q)) == 0) |
110 | continue; |
111 | f |= 1 << (r - lfmap); |
112 | } |
113 | l->f = f; |
114 | } else if (strcmp(q, "masks-collected") == 0 && |
115 | (q = str_qword(&p, 0)) != 0) |
116 | l->m = atoi(q); |
117 | else if (strcmp(q, "masks-total") == 0 && |
118 | (q = str_qword(&p, 0)) != 0) |
119 | l->mtot = atoi(q); |
120 | else if (strcmp(q, "moves-made") == 0 && |
121 | (q = str_qword(&p, 0)) != 0) |
122 | l->v = atoi(q); |
123 | else if (strcmp(q, "moves-allowed") == 0 && |
124 | (q = str_qword(&p, 0)) != 0) |
125 | l->vtot = atoi(q); |
126 | else if (strcmp(q, "data") == 0) { |
127 | dstr_reset(&dd); |
128 | while (dstr_reset(&d), dstr_putline(&d, fp) != EOF) { |
129 | if (strstr("end", d.buf)) break; |
130 | i = 0; |
131 | while (d.buf[i] == C_EMPTY) i++; |
132 | if (ind == -1 || i < ind) ind = i; |
133 | while (d.buf[d.len - 1] == C_EMPTY) d.len--; |
134 | if (d.len > max) max = d.len; |
135 | dstr_putd(&dd, &d); |
136 | DA_PUSH(&v, dd.len); |
137 | } |
138 | l->h = DA_LEN(&v); |
139 | l->w = max - ind; |
140 | l->d = xmalloc(l->h * l->w * sizeof(*l->d)); |
141 | for (i = 0; i < l->w * l->h; i++) |
142 | l->d[i] = C_EMPTY; |
143 | n = 0; |
144 | for (i = 0; i < l->h; i++) { |
145 | nn = DA(&v)[i]; |
146 | p = dd.buf + n + ind; |
147 | q = dd.buf + nn; |
148 | pp = l->d + l->w * i; |
149 | while (p < q) *pp++ = *p++; |
150 | n = nn; |
151 | } |
152 | break; |
153 | } |
154 | } |
155 | |
156 | if (!l->d) |
157 | return (0); |
158 | |
159 | n = 0; |
160 | while (lev_findcell(l, C_UKMAP, &x, &y)) { |
161 | for (i = C_NWMAP; lev_findcell(l, i, 0, 0); i++) ; |
162 | CELLREF(l, x, y) = i; |
163 | } |
164 | for (i = 0; i < l->w * l->h; i++) { |
165 | if (!cellmap[l->d[i]]) { |
166 | fprintf(stderr, "warning: unknown map item: killing\n"); |
167 | l->d[i] = C_WALL; |
168 | } |
169 | } |
170 | if (l->v > l->vtot) { |
171 | fprintf(stderr, "warning: too many moves already: locking\n"); |
172 | l->v = l->vtot; |
173 | } |
174 | if (lev_findcell(l, C_PLAYER, &x, &y)) { |
175 | CELLREF(l, x, y) = C_SPARE; |
176 | if (lev_findcell(l, C_PLAYER, &xx, &yy)) { |
177 | fprintf(stderr, "warning: multiple active players: deactivating\n"); |
178 | do |
179 | CELLREF(l, xx, yy) = C_SPARE; |
180 | while (lev_findcell(l, C_PLAYER, &xx, &yy)); |
181 | } |
182 | CELLREF(l, x, y) = C_PLAYER; |
183 | } else if (lev_findcell(l, C_SPARE, &x, &y)) { |
184 | fprintf(stderr, "warning: no active player: activating a spare\n"); |
185 | CELLREF(l, x, y) = C_SPARE; |
186 | } else |
187 | fprintf(stderr, "warning: no player found: hoping for the best\n"); |
188 | for (i = 0; i < l->w * l->h; i++) |
189 | if (cellmap[l->d[i] & CF_CELLMASK]->f & CF_MASK) n++; |
190 | if (l->mtot < 0) |
191 | l->mtot = n - l->m; |
192 | |
193 | dstr_destroy(&d); |
194 | dstr_destroy(&dd); |
195 | DA_DESTROY(&v); |
196 | return (l); |
197 | } |
198 | |
199 | void lev_write(const level *l, FILE *fp) |
200 | { |
201 | const char *p = LF_MAP; |
202 | const int *pp; |
203 | unsigned f; |
204 | unsigned i, j; |
205 | |
206 | fprintf(fp, "name \"%s\"\n", l->name); |
207 | fprintf(fp, "flags "); |
208 | f = l->f; |
209 | while (*p) { |
210 | if (f & 1) putc(*p, fp); |
211 | f >>= 1; |
212 | p++; |
213 | } |
214 | putc('\n', fp); |
215 | fprintf(fp, "masks-collected %d\n", l->m); |
216 | fprintf(fp, "masks-total %d\n", l->mtot); |
217 | fprintf(fp, "size = %d x %d\n", l->w, l->h); |
218 | fprintf(fp, "data\n"); |
219 | for (i = 0, pp = l->d; i < l->h; i++) { |
220 | for (j = 0; j < l->w; j++) putc(*pp++, fp); |
221 | putc('\n', fp); |
222 | } |
223 | fprintf(fp, "end\n"); |
224 | } |
225 | |
226 | void lev_free(level *l) |
227 | { |
228 | xfree(l->name); |
229 | xfree(l->d); |
230 | DESTROY(l); |
231 | } |
232 | |
233 | level *lev_copy(const level *l) |
234 | { |
235 | level *ll = CREATE(level); |
236 | *ll = *l; |
237 | ll->name = xstrdup(l->name); |
238 | ll->d = xmalloc(l->w * l->h * sizeof(*l->d)); |
239 | memcpy(ll->d, l->d, l->w * l->h * sizeof(*l->d)); |
240 | return (ll); |
241 | } |
242 | |
243 | /*----- That's all, folks -------------------------------------------------*/ |