10 static void parse_cell(struct level *lvl, int x, int y, char c);
12 void init_level(struct level *lvl)
14 memset(lvl, 0, sizeof *lvl);
17 lvl->rects = darr_alloc(0, sizeof *lvl->rects);
20 void destroy_level(struct level *lvl)
22 darr_free(lvl->rects);
25 static int rect_area(struct level_rect *rect)
27 return rect->w * rect->h;
30 static int grow_rect(struct level *lvl, struct level_cell *orgcell, struct level_rect *rect)
32 int i, j, x, y, area_a, area_b;
33 struct level_rect ra, rb;
34 struct level_cell *cell;
38 /* try expanding horizontally first */
41 while(x < lvl->xsz && cell->type != CELL_SOLID) {
45 /* then for each line below, expand as long as we have at least ra.w space */
46 cell = orgcell + lvl->xsz;
48 while(y++ < lvl->ysz) {
51 while(x++ < lvl->xsz && cell->type != CELL_SOLID) {
55 if(rowsz < ra.w) break;
57 cell += lvl->xsz - rowsz;
60 /* then try the same thing, but vertical first */
61 cell = orgcell + lvl->xsz;
63 while(y++ < lvl->ysz && cell->type != CELL_SOLID) {
67 /* then for each next column, expand as long as we have at least rb.h space */
72 cell = lvl->cells + y * lvl->xsz + x;
73 while(y++ < lvl->ysz && cell->type != CELL_SOLID) {
77 if(colsz < rb.h) break;
82 /* return the rect with the largest area */
83 area_a = rect_area(&ra);
84 area_b = rect_area(&rb);
86 *rect = area_a > area_b ? ra : rb;
89 for(i=0; i<rect->h; i++) {
90 for(j=0; j<rect->w; j++) {
98 void lvl_gen_rects(struct level *lvl)
101 struct level_cell *cell;
102 struct level_rect rect;
104 darr_clear(lvl->rects);
106 for(i=0; i<lvl->ysz; i++) {
107 for(j=0; j<lvl->xsz; j++) {
114 for(i=0; i<lvl->ysz; i++) {
115 for(j=0; j<lvl->xsz; j++) {
116 if(cell->type != CELL_SOLID && !cell->visited) {
120 if(grow_rect(lvl, cell, &rect) != -1) {
121 rect.dbgcol[0] = (rand() & 0x7f) + 0x7f;
122 rect.dbgcol[1] = (rand() & 0x7f) + 0x7f;
123 rect.dbgcol[2] = (rand() & 0x7f) + 0x7f;
125 darr_push(lvl->rects, &rect);
133 int save_level(const struct level *lvl, const char *fname)
137 struct level_cell *cell;
138 struct level_rect *rect;
140 if(!(fp = fopen(fname, "wb"))) {
141 fprintf(stderr, "save_level: failed to open: %s: %s\n", fname, strerror(errno));
145 fprintf(fp, "RDLEVEL\n");
146 fprintf(fp, "size = %dx%d\n", lvl->xsz, lvl->ysz);
147 fprintf(fp, "scale = %f\n", lvl->scale);
149 fputs("\nMAPSTART\n", fp);
151 for(i=0; i<lvl->ysz; i++) {
152 for(j=0; j<lvl->xsz; j++) {
153 switch(cell->type & 0xff) {
155 if(lvl->sx == j && lvl->sy == i) {
157 } else if((cell->type & CELL_WALK) == 0) {
172 fputs("MAPEND\n", fp);
174 if(!darr_empty(lvl->rects)) {
175 num = darr_size(lvl->rects);
176 fprintf(fp, "\nRECTSTART %d\n", num);
178 for(i=0; i<num; i++) {
179 fprintf(fp, "rect %d %d %d %d\n", rect->x, rect->y, rect->w, rect->h);
182 fprintf(fp, "RECTEND\n\n");
189 static char *clean_line(char *s)
193 while(*s && isspace(*s)) s++;
195 if(!(end = strchr(s, '#'))) {
196 end = s + strlen(s) - 1;
198 while(end >= s && isspace(*end)) *end-- = 0;
203 int load_level(struct level *lvl, const char *fname)
207 char *line, *val, *endp;
211 struct level_rect rect;
213 if(!(fp = ass_fopen(fname, "rb"))) {
214 fprintf(stderr, "load_level: failed to open: %s\n", fname);
218 while(ass_fgets(buf, sizeof buf, fp)) {
221 if(memcmp(buf, "RDLEVEL", 7) != 0) {
222 fprintf(stderr, "load_level: invalid level file: %s\n", fname);
230 if(!(line = clean_line(buf)) || *line == '#') {
234 if((val = strchr(line, '='))) {
237 if(!(val = clean_line(val))) {
238 fprintf(stderr, "load_level: ignoring invalid value for %s: %s\n", line, val);
241 if(strcmp(line, "size") == 0) {
243 if(sscanf(val, "%dx%d", &x, &y) != 2) {
244 fprintf(stderr, "load_level: ignoring invalid size: %s\n", val);
249 } else if(strcmp(line, "scale") == 0) {
250 fnum = strtod(val, &endp);
252 fprintf(stderr, "load_level: ignoring invalid scale: %s\n", val);
257 fprintf(stderr, "load_level: ignoring unknown option: %s\n", line);
261 } else if(strcmp(line, "MAPSTART") == 0) {
262 if(!lvl->xsz || !lvl->ysz) {
263 fprintf(stderr, "load_level: missing size before level data\n");
268 lvl->cells = calloc_nf(lvl->xsz * lvl->ysz, sizeof *lvl->cells);
272 } else if(sscanf(line, "rect %d %d %d %d", &rect.x, &rect.y, &rect.w, &rect.h) == 4) {
273 rect.dbgcol[0] = (rand() & 0x7f) + 0x7f;
274 rect.dbgcol[1] = (rand() & 0x7f) + 0x7f;
275 rect.dbgcol[2] = (rand() & 0x7f) + 0x7f;
276 darr_push(lvl->rects, &rect);
282 if(memcmp(buf, "MAPEND", 6) == 0) {
286 for(i=0; i<lvl->xsz; i++) {
288 parse_cell(lvl, i, nrow, buf[i]);
290 if(++nrow >= lvl->ysz) {
302 static void parse_cell(struct level *lvl, int x, int y, char c)
304 struct level_cell *cell = lvl->cells + y * lvl->xsz + x;
308 cell->type = CELL_OPEN | CELL_WALK;
312 cell->type = CELL_OPEN | CELL_WALK;
319 cell->type = CELL_OPEN;