demos: bogoman: Many improvements.
[gfxprim.git] / demos / bogoman / bogoman_loader.c
blobe4e17c1d16c9b906f2e1ea956eba73def1af8e03
1 /*****************************************************************************
2 * This file is part of gfxprim library. *
3 * *
4 * Gfxprim is free software; you can redistribute it and/or *
5 * modify it under the terms of the GNU Lesser General Public *
6 * License as published by the Free Software Foundation; either *
7 * version 2.1 of the License, or (at your option) any later version. *
8 * *
9 * Gfxprim is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
12 * Lesser General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU Lesser General Public *
15 * License along with gfxprim; if not, write to the Free Software *
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
17 * Boston, MA 02110-1301 USA *
18 * *
19 * Copyright (C) 2009-2015 Cyril Hrubis <metan@ucw.cz> *
20 * *
21 *****************************************************************************/
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
27 #include "bogoman_debug.h"
28 #include "bogoman_common.h"
29 #include "bogoman_loader.h"
32 * Counts map w and h by reading number of lines and maximal size of line till
33 * first empty line or EOF.
35 static void get_map_info(FILE *f, unsigned int *w, unsigned int *h)
37 unsigned int curw = 0;
38 int ch;
40 *w = 0;
41 *h = 0;
43 while ((ch = getc(f)) != EOF) {
44 switch (ch) {
45 case '\n':
46 if (*w < curw)
47 *w = curw;
49 if (curw == 0) {
50 rewind(f);
51 return;
54 curw = 0;
55 (*h)++;
56 break;
57 default:
58 curw++;
62 rewind(f);
65 static enum bogoman_map_elem_id id_from_char(const char ch)
67 switch (ch) {
68 case ' ':
69 return BOGOMAN_NONE;
70 case '@':
71 return BOGOMAN_PLAYER;
72 case '-':
73 case '|':
74 case '+':
75 case '/':
76 case '\\':
77 return BOGOMAN_WALL;
78 case '$':
79 return BOGOMAN_DIAMOND;
80 case 'M':
81 return BOGOMAN_MOVEABLE;
82 case 'E':
83 return BOGOMAN_EDIBLE;
84 case '(':
85 case ')':
86 case 'O':
87 case 'o':
88 case '<':
89 case '>':
90 case '^':
91 case 'v':
92 return BOGOMAN_PARTICLE;
95 WARN("Unknown map character '%c'", ch);
97 return BOGOMAN_NONE;
100 #define LINE_MAX 256
102 struct line {
103 unsigned int len;
104 unsigned char line[LINE_MAX];
105 unsigned char input[LINE_MAX];
108 static void get_line(FILE *f, struct line *l)
110 int ch;
112 l->len = 0;
114 while ((ch = getc(f)) != EOF) {
115 switch (ch) {
116 case '\n':
117 return;
118 default:
119 l->input[l->len] = ch;
120 l->line[l->len++] = id_from_char(ch);
121 break;
126 static void load_map(FILE *f, struct bogoman_map *map)
128 struct line line_a, line_b;
129 struct line *line_cur, *line_next;
130 unsigned int y = 0;
131 unsigned int player_found = 0;
133 line_cur = &line_a;
134 line_next = &line_b;
136 get_line(f, line_cur);
137 get_line(f, line_next);
139 while (line_cur->len != 0) {
140 unsigned int x;
142 for (x = 0; x < line_cur->len; x++) {
143 struct bogoman_map_elem *elem;
145 elem = bogoman_get_map_elem(map, x, y);
147 elem->id = line_cur->line[x];
149 switch (elem->id) {
150 /* Compute wall continuations */
151 case BOGOMAN_WALL:
152 if (x > 0 &&
153 line_cur->line[x - 1] == BOGOMAN_WALL)
154 elem->flags |= BOGOMAN_LEFT;
156 if (x + 1 < line_cur->len &&
157 line_cur->line[x + 1] == BOGOMAN_WALL)
158 elem->flags |= BOGOMAN_RIGHT;
160 if (y > 0 &&
161 bogoman_map_elem_id(map, x, y-1) == BOGOMAN_WALL)
162 elem->flags |= BOGOMAN_UP;
164 if (x < line_next->len &&
165 line_next->line[x] == BOGOMAN_WALL)
166 elem->flags |= BOGOMAN_DOWN;
168 break;
169 case BOGOMAN_PLAYER:
170 if (player_found)
171 WARN("Duplicated player at %ux%u previously at %ux%u\n",
172 x, y, map->player_x, map->player_y);
174 map->player_x = x;
175 map->player_y = y;
177 player_found = 1;
178 break;
179 case BOGOMAN_DIAMOND:
180 map->diamonds_total++;
181 break;
182 case BOGOMAN_PARTICLE:
183 switch (line_cur->input[x]) {
184 case '(':
185 elem->flags = BOGOMAN_LEFT | BOGOMAN_PARTICLE_ROUND;
186 break;
187 case ')':
188 elem->flags = BOGOMAN_RIGHT | BOGOMAN_PARTICLE_ROUND;
189 break;
190 case 'O':
191 elem->flags = BOGOMAN_UP | BOGOMAN_PARTICLE_ROUND;
192 break;
193 case 'o':
194 elem->flags = BOGOMAN_DOWN | BOGOMAN_PARTICLE_ROUND;
195 break;
196 case '<':
197 elem->flags = BOGOMAN_LEFT | BOGOMAN_PARTICLE_SQUARE;
198 break;
199 case '>':
200 elem->flags = BOGOMAN_RIGHT | BOGOMAN_PARTICLE_SQUARE;
201 break;
202 case '^':
203 elem->flags = BOGOMAN_UP | BOGOMAN_PARTICLE_SQUARE;
204 break;
205 case 'v':
206 elem->flags = BOGOMAN_DOWN | BOGOMAN_PARTICLE_SQUARE;
207 break;
209 break;
210 default:
211 break;
215 SWAP(line_cur, line_next);
216 get_line(f, line_next);
217 y++;
220 if (!player_found)
221 WARN("No player found in map\n");
224 struct bogoman_map *bogoman_load(const char *path)
226 FILE *f = fopen(path, "r");
228 if (f == NULL)
229 return NULL;
231 unsigned int w, h;
233 get_map_info(f, &w, &h);
235 DEBUG(1, "Have map %ux%u\n", w, h);
237 struct bogoman_map *map;
238 size_t map_size;
240 map_size = sizeof(struct bogoman_map) +
241 w * h * sizeof(struct bogoman_map_elem);
243 map = malloc(map_size);
245 if (map == NULL)
246 goto err0;
248 memset(map, 0, map_size);
250 map->w = w;
251 map->h = h;
253 load_map(f, map);
255 return map;
256 err0:
257 fclose(f);
258 return NULL;