DEADSOFTWARE

portability: avoid errors on some compilers
[flatwaifu.git] / src / map.c
1 /* Copyright (C) 1996-1997 Aleksey Volynskov
2 * Copyright (C) 2011 Rambo
3 * Copyright (C) 2020 SovietPony
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
18 #include "map.h"
20 #include "game.h"
21 #include "items.h"
22 #include "things.h"
23 #include "monster.h"
24 #include "switch.h"
25 #include "view.h"
27 #include "music.h"
28 #include "render.h"
30 #include <string.h>
31 #include <assert.h>
32 #include "error.h"
34 #include "common/streams.h"
35 #include "common/files.h"
36 #include "common/cp866.h"
38 enum {
39 MB_COMMENT = -1, MB_END = 0,
40 MB_WALLNAMES, MB_BACK, MB_WTYPE, MB_FRONT, MB_THING, MB_SWITCH,
41 MB_MUSIC, MB_SKY,
42 MB_SWITCH2,
43 MB__UNKNOWN
44 };
46 typedef struct map_header_t {
47 char id[8];
48 short ver;
49 } map_header_t;
51 typedef struct map_block_t {
52 short t;
53 short st;
54 int sz;
55 } map_block_t;
57 typedef struct old_thing_t {
58 short x, y;
59 short t;
60 unsigned short f;
61 } old_thing_t;
63 static map_block_t blk;
65 static int G_load (Stream *h) {
66 switch (blk.t) {
67 case MB_MUSIC:
68 stream_read(g_music, 8, 1, h);
69 //if (music_random) {
70 // F_randmus(g_music);
71 //}
72 MUS_load(g_music);
73 return 1;
74 }
75 return 0;
76 }
78 static int IT_load (Stream *h) {
79 int m, i, j;
80 old_thing_t t;
81 switch (blk.t) {
82 case MB_THING:
83 for (i = 0; blk.sz > 0; ++i, blk.sz -= 8) {
84 t.x = stream_read16(h);
85 t.y = stream_read16(h);
86 t.t = stream_read16(h);
87 t.f = stream_read16(h);
88 it[i].o.x = t.x;
89 it[i].o.y = t.y;
90 it[i].t = t.t;
91 it[i].s = t.f;
92 if (it[i].t && (it[i].s & THF_DM) && !g_dm) {
93 it[i].t=0;
94 }
95 }
96 m = i;
97 for (i = 0, j = -1; i < m; ++i) {
98 if (it[i].t == TH_PLR1) {
99 j = i;
100 it[i].t = 0;
103 if (!g_dm) {
104 if (j == -1) {
105 logo("Player 1 point not exists on the map\n");
106 return 0; // error
108 dm_pos[0].x = it[j].o.x;
109 dm_pos[0].y = it[j].o.y;
110 dm_pos[0].d = it[j].s & THF_DIR;
112 for (i = 0, j = -1; i < m; ++i) {
113 if (it[i].t == TH_PLR2) {
114 j = i;
115 it[i].t = 0;
118 if (!g_dm && _2pl) {
119 if (j == -1) {
120 logo("Player 2 point not exists on the map\n");
121 return 0; // error
123 dm_pos[1].x = it[j].o.x;
124 dm_pos[1].y = it[j].o.y;
125 dm_pos[1].d = it[j].s & THF_DIR;
127 for (i = 0, j = 0; i < m; ++i) {
128 if (it[i].t == TH_DMSTART) {
129 if (g_dm) {
130 dm_pos[j].x = it[i].o.x;
131 dm_pos[j].y = it[i].o.y;
132 dm_pos[j].d = it[i].s & THF_DIR;
134 it[i].t = 0;
135 ++j;
138 if (g_dm && j < 2) {
139 logo("Required at least two DM points on the map\n");
140 return 0; // error
142 if (g_dm) {
143 dm_pnum = j;
144 dm_pl1p = myrand(dm_pnum);
145 do {
146 dm_pl2p = myrand(dm_pnum);
147 } while (dm_pl2p == dm_pl1p);
148 } else {
149 dm_pl1p = 0;
150 dm_pl2p = 1;
151 dm_pnum = 2;
153 PL_spawn(&pl1, dm_pos[dm_pl1p].x, dm_pos[dm_pl1p].y, dm_pos[dm_pl1p].d);
154 if (_2pl) {
155 PL_spawn(&pl2, dm_pos[dm_pl2p].x, dm_pos[dm_pl2p].y, dm_pos[dm_pl2p].d);
157 for (i = 0; i < m; ++i) {
158 if (it[i].t >= TH_CLIP && it[i].t < TH_DEMON) {
159 it[i].s = 0;
160 it[i].t = it[i].t - TH_CLIP + I_CLIP;
161 if (it[i].t >= I_KEYR && it[i].t <= I_KEYB) {
162 it[i].t |= 0x8000;
164 } else if (it[i].t >= TH_DEMON) {
165 MN_spawn(it[i].o.x, it[i].o.y, it[i].s & THF_DIR, it[i].t - TH_DEMON + MN_DEMON);
166 it[i].t = 0;
169 return 1;
171 return 0;
174 static int SW_load (Stream *h) {
175 int i;
176 switch(blk.t) {
177 case MB_SWITCH2:
178 sw_secrets = 0;
179 for (i = 0; i < MAXSW && blk.sz > 0; ++i, blk.sz -= 9) {
180 sw[i].x = stream_read8(h);
181 sw[i].y = stream_read8(h);
182 sw[i].t = stream_read8(h);
183 sw[i].tm = stream_read8(h); // unused
184 sw[i].a = stream_read8(h);
185 sw[i].b = stream_read8(h);
186 sw[i].c = stream_read8(h);
187 sw[i].d = stream_read8(h); // unused
188 sw[i].f = stream_read8(h);
189 sw[i].tm = 0;
190 sw[i].d = 0;
191 sw[i].f |= 0x80;
192 if (sw[i].t == SW_SECRET) {
193 ++sw_secrets;
196 return 1;
198 return 0;
201 static void unpack (void *buf, int len, void *obuf) {
202 int i = 0;
203 int j = 0;
204 unsigned char *p = buf;
205 unsigned char *q = obuf;
206 while (i < len) {
207 int id = p[i];
208 int step = 1;
209 i += 1;
210 if (id == 0xff) {
211 step = p[i] | p[i + 1] << 8;
212 id = p[i + 2];
213 i += 3;
215 memset(&q[j], id, step);
216 j += step;
220 static int read_array (void *p, Stream *h) {
221 void *buf;
222 switch (blk.st) {
223 case 0:
224 stream_read(p, FLDW * FLDH, 1, h);
225 break;
226 case 1:
227 buf = malloc(blk.sz);
228 if (buf == NULL) {
229 logo("Out of memory\n");
230 return 0; // error
232 stream_read(buf, blk.sz, 1, h);
233 unpack(buf, blk.sz, p);
234 free(buf);
235 break;
236 default:
237 return 0;
239 return 1;
242 static int W_load (Stream *h) {
243 int i;
244 char s[8];
245 switch (blk.t) {
246 case MB_WALLNAMES:
247 R_begin_load();
248 memset(walf, 0, sizeof(walf));
249 for (i = 1; i < 256 && blk.sz > 0; i++, blk.sz -= 9) {
250 stream_read(s, 8, 1, h);
251 walf[i] = stream_read8(h) ? 1 : 0; // ???
252 R_load(s);
253 if (cp866_strncasecmp(s, "VTRAP01", 8) == 0) {
254 walf[i] |= 2;
257 R_end_load();
258 return 1;
259 case MB_BACK:
260 return read_array(fldb, h);
261 case MB_WTYPE:
262 return read_array(fld, h);
263 case MB_FRONT:
264 return read_array(fldf, h);
265 case MB_SKY:
266 sky_type = stream_read16(h);
267 R_loadsky(sky_type);
268 return 1;
270 return 0;
273 int MAP_load (Stream *r) {
274 int ok = 0;
275 long off;
276 map_header_t hdr;
277 assert(r != NULL);
278 W_init(); // reset all game data
279 stream_read(hdr.id, 8, 1, r);
280 hdr.ver = stream_read16(r);
281 if (memcmp(hdr.id, "Doom2D\x1A", 8) == 0) {
282 ok = 1;
283 while (ok) {
284 blk.t = stream_read16(r);
285 blk.st = stream_read16(r);
286 blk.sz = stream_read32(r);
287 off = stream_getpos(r) + blk.sz;
288 switch (blk.t) {
289 case MB_MUSIC:
290 ok = G_load(r);
291 break;
292 case MB_WALLNAMES:
293 case MB_BACK:
294 case MB_WTYPE:
295 case MB_FRONT:
296 case MB_SKY:
297 ok = W_load(r);
298 break;
299 case MB_THING:
300 ok = IT_load(r);
301 break;
302 case MB_SWITCH2:
303 ok = SW_load(r);
304 break;
305 case MB_COMMENT:
306 /* skip */
307 break;
308 case MB_END:
309 return ok;
310 default:
311 logo("Unknown block %d(%d)\n", blk.t, blk.st);
312 return 0; // error
314 stream_setpos(r, off);
316 } else {
317 logo("Invalid map header\n");
318 abort();
319 ok = 0;
321 return ok;