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