infra: Clean up project setup
[xor] / level.c
1 /* -*-c-*-
2 *
3 * $Id$
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
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 -------------------------------------------------*/