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