doing alot of cleanup on exit (just for fun)
[d2dvcd.git] / src / doom2d / view.c
blob1db29377b1ddb943390afc08803506ee18473cfa
1 /*
2 * Doom2D:Vaya Con Dios
4 * Copyright (C) Prikol Software 1996-1997
5 * Copyright (C) Aleksey Volynskov 1996-1997
6 * Copyright (C) <ARembo@gmail.com> 2011
7 * Copyright (C) Ketmar Dark 2013
9 * coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
10 * Understanding is not required. Only obedience.
12 * This program is free software. It comes without any warranty, to
13 * the extent permitted by applicable law. You can redistribute it
14 * and/or modify it under the terms of the Do What The Fuck You Want
15 * To Public License, Version 2, as published by Sam Hocevar. See
16 * http://www.wtfpl.net/ for more details.
18 * Visit the site of the original author:
19 * http://ranmantaru.com/
21 #include <string.h>
22 #include <malloc.h>
24 #include "bmap.h"
25 #include "common.h"
26 #include "cmdcon.h"
27 #include "dots.h"
28 #include "error.h"
29 #include "files.h"
30 #include "fx.h"
31 #include "game.h"
32 #include "items.h"
33 #include "jimapi.h"
34 #include "map.h"
35 #include "mapio.h"
36 #include "misc.h"
37 #include "monster.h"
38 #include "player.h"
39 #include "sdldrv.h"
40 #include "smoke.h"
41 #include "sound.h"
42 #include "switch.h"
43 #include "vga.h"
44 #include "view.h"
45 #include "weapons.h"
48 ////////////////////////////////////////////////////////////////////////////////
49 #define ANIT (5)
52 #define w_view_wdt 200
53 #define w_view_hgt 98
55 #define MAXX (FLDW*CELW-w_view_wdt/2)
56 #define MAXY (FLDH*CELH-w_view_hgt/2)
60 ////////////////////////////////////////////////////////////////////////////////
61 int w_view_wdt;
62 int w_view_hgt;
64 vgaimg ltn[2][2];
66 ccBool r_drawsky = CC_TRUE;
67 static vgaimg horiz;
68 int w_viewofs_vert, w_viewofs_x, w_viewofs_y;
69 int sky_type = 1;
70 vgaimg walpix[256];
71 vgaimg *walp[256];
72 uint32_t walf[256];
73 int walh[256];
74 uint8_t walswp[256];
75 uint8_t walani[256];
76 int anih[ANIT][5];
77 vgaimg anispr[ANIT][5];
78 uint8_t anic[ANIT];
80 int FLDW = 0, FLDH = 0; // 100x100
81 uint8_t *fldb = NULL;
82 uint8_t *fldf = NULL;
83 uint8_t *fldm = NULL;
85 ccBool cheatNoBack = CC_FALSE;
86 ccBool cheatNoFront = CC_FALSE;
89 ////////////////////////////////////////////////////////////////////////////////
90 CONVAR_BOOL(r_drawsky, r_drawsky, CMDCON_FLAGS_PERSISTENT, "draw sky?")
93 ////////////////////////////////////////////////////////////////////////////////
94 GCC_DESTRUCTOR_USER {
95 if (fldb) free(fldb);
96 if (fldf) free(fldf);
97 if (fldm) free(fldm);
101 void W_set_field_size (int w, int h) {
102 // arbitrary limits
103 if (w < 1) w = 1; else if (w > 32767) w = 32767;
104 if (h < 1) h = 1; else if (h > 32767) h = 32767;
105 if (w != FLDW || h != FLDH) {
106 if ((fldb = realloc(fldb, w*h)) == NULL) ERR_fatal("W_set_field_size: out of memory!");
107 if ((fldf = realloc(fldf, w*h)) == NULL) ERR_fatal("W_set_field_size: out of memory!");
108 if ((fldm = realloc(fldm, w*h)) == NULL) ERR_fatal("W_set_field_size: out of memory!");
109 FLDW = w;
110 FLDH = h;
111 BM_set_size();
116 ////////////////////////////////////////////////////////////////////////////////
117 static const char *anm[ANIT-1][5] = {
118 {"WALL22_1", "WALL23_1", "WALL23_2", NULL, NULL},
119 {"WALL58_1", "WALL58_2", "WALL58_3", NULL, NULL},
120 {"W73A_1", "W73A_2", NULL, NULL, NULL},
121 {"RP2_1", "RP2_2", "RP2_3", "RP2_4", NULL}
125 //???
126 static void getname (int n, char *s) {
127 switch (walh[n]) {
128 case -1:
129 memset(s, 0, 8);
130 break;
131 case -2:
132 memcpy(s, "_WATER_", 8);
133 //s[7] = (char)((((uintptr_t)walp[n])&0xff)-1+'0');
134 s[7] = walpix[n].wanim-1+'0';
135 //fprintf(stderr, "n=%d; wanim=%d\n", n, walpix[n].wanim);
136 break;
137 default:
138 F_getresname(s, walh[n]&0x7FFF);
139 break;
144 static short getani (const char *n) {
145 for (int f = 0; f < ANIT-1; ++f) if (strncasecmp(n, anm[f][0], 8) == 0) return f+1;
146 return 0;
150 void W_adjust (void) {
151 int MAXX = (FLDW*CELW-w_view_wdt/2);
152 int MAXY = (FLDH*CELH-w_view_hgt/2);
154 if (w_viewofs_x < w_view_wdt/2) w_viewofs_x = w_view_wdt/2;
155 if (w_viewofs_y < w_view_hgt/2) w_viewofs_y = w_view_hgt/2;
156 if (w_viewofs_x > MAXX) w_viewofs_x = MAXX;
157 if (w_viewofs_y > MAXY) w_viewofs_y = MAXY;
161 ccBool r_lighting = CC_FALSE;
162 static int r_lights_tnum = 0;
163 static int r_lights_trad = 250;
164 static ccBool r_flashlight = CC_FALSE;
166 CONVAR_BOOL(r_lighting, r_lighting, 0, "test dynamic lighting")
167 CONVAR_INT(r_lights_tnum, r_lights_tnum, 0, "# of additional lights for testing")
168 CONVAR_INT(r_lights_trad, r_lights_trad, 0, "radius of additional lights")
169 CONVAR_BOOL(r_flashlight, r_flashlight, 0, "test marine flashlight")
172 ////////////////////////////////////////////////////////////////////////////////
173 #include "zlight.c"
176 ////////////////////////////////////////////////////////////////////////////////
177 // bg!=0: cheatNoBack
178 // bg==0: cheatNoFront
179 void Z_drawfld (const uint8_t *xfld, int bg) {
180 const uint8_t *p = xfld, *pb = &FIELD_TBG(0, 0), *pf = &FIELD_TFG(0, 0), *pm = &FIELD_MAP(0, 0);
181 int semi = (bg ? cheatNoBack : cheatNoFront);
183 for (int y = 0; y < FLDH; ++y) {
184 for (int x = 0; x < FLDW; ++x) {
185 int sx = Z_MAP2SCR_X(x*CELW);
186 int sy = Z_MAP2SCR_Y(y*CELH);
188 if (sx >= -CELW*256 && sx < w_view_wdt && sy >= -CELH*256 && sy < SCRH) {
189 if (*p > 0 && *p < 255) {
190 // non-empty tile
191 vgaimg *pic = walp[*p];
193 // check the following in postprocessor
194 //if (pic == NULL) continue; // the thing that should not be; no, really!
196 if (pic->wanim <= 0) {
197 // normal texture, not 'liquid'
198 // check the following in postprocessor
199 //if (pic->w < 1) continue; // the thing that should not be; no, really!
201 if (r_lighting) {
202 // 'FitL' mode
203 if (!bg || pm[0] == TILE_WALL /*|| (pf[0] && pm[0]) || pf[0]*/) {
204 // this is impassable or foreground wall, draw it fulllit
205 V_draw_tile(sx, sy, pic, semi);
206 } else {
207 // this is passable wall, light it later
208 V_draw_tile_lm(sx, sy, pic, semi);
210 } else {
211 // vanilla mode
212 V_draw_tile(sx, sy, pic, semi);
215 } else {
216 // empty tile
217 if (r_lighting && bg && *p == 255) {
218 // unoccupied background tile
219 // fill background, so light will have something to lit
220 V_draw_tile_lm(sx, sy, walp[1], semi);
224 ++p;
225 ++pb;
226 ++pf;
227 ++pm;
233 void Z_drawliquids (void) {
234 const uint8_t *p = &FIELD_TFG(0, 0);
236 for (int y = 0; y < FLDH; ++y) {
237 for (int x = 0; x < FLDW; ++x) {
238 int sx = Z_MAP2SCR_X(x*CELW);
239 int sy = Z_MAP2SCR_Y(y*CELH);
241 if (sx >= -CELW && sx < w_view_wdt && sy >= -CELH && sy < SCRH) {
242 if (*p > 0 && *p < 255) {
243 // non-empty tile
244 vgaimg *pic = walp[*p];
246 if (pic == NULL) continue; // the thing that should not be; no, really!
248 if (pic->wanim > 0 && pic->wanim <= 3 && sy < w_viewofs_vert+w_view_hgt) {
249 // one of the 'water' textures
250 // 1: water (blue)
251 // 2: acid (green)
252 // 3: lava (red)
253 uint32_t src = 0;
254 static const Uint32 aa[8] = {
255 0x5f<<24, 0x4f<<24, 0x3f<<24, 0x2f<<24, 0x1f<<24, 0x2f<<24, 0x3f<<24, 0x4f<<24,
258 switch (pic->wanim) {
259 case 1: src = 0x5f0000ff; break; // water
260 case 2: src = 0x5f00ff00; break; // acid
261 case 3: src = 0x5fff0000; break; // lava
264 int ypix = (sy >= vidcy1 ? sy : vidcy1), ye = (sy+CELH < vidcy2 ? sy+CELH : vidcy2);
265 int xpix = (sx >= vidcx1 ? sx : vidcx1), xe = (sx+CELW < vidcx2 ? sx+CELW : vidcx2);
267 if (r_lighting) {
268 src = (src&0xffffff)|aa[(g_time/2)&7];
269 } else {
270 src = (src&0xffffff)|aa[(g_time/2)&7];
271 //src = (src&0xffffff)|(0x5f<<24);
274 for (; ypix < ye; ++ypix) {
275 Uint32 *d = (Uint32 *)(((Uint8 *)frameSfc->pixels)+(ypix*frameSfc->pitch)+xpix*4);
277 const uint8_t *lm = scrlightmap+SCRW*ypix+xpix;
278 const uint8_t *vs = vscrbuf+SCRW*ypix+xpix;
279 const uint8_t *lb = lightbuf+(SCRW*LB_ITEM_SZ)*ypix+(xpix*LB_ITEM_SZ);
282 for (int h = xpix; h < xe; ++h, ++d/*, ++lm, ++vs, lb += LB_ITEM_SZ*/) {
284 if (*lm == LMAP_NORMAL && *lb == 0) {
285 // *d = palette[*vs];
286 *d = 0;
287 // pixel_blend32(d, palette[*vs]|(64<<24));
290 pixel_blend32(d, 0x8f000000); // darken
291 pixel_blend32(d, src);
297 ++p;
303 static void Z_draw_sky (void) {
304 if (!r_lighting) {
305 if (r_drawsky && horiz.w > 0) {
306 //V_pic(127-(uint16_t)(w_viewofs_x-w_view_wdt/2)*56U/(uint16_t)(MAXX-w_view_wdt/2), w_viewofs_vert+123-(uint16_t)(w_viewofs_y-w_view_hgt/2)*28U/(uint16_t)(MAXY-w_view_hgt/2), horiz);
307 vgaimg *img = &horiz;
308 int x = 0, d = 0;
310 do {
311 int y = w_viewofs_vert;
313 d &= ~2;
314 do {
315 V_rotspr(x, y, img, d);
316 y += img->h;
317 d ^= 2;
318 } while (y < w_view_hgt+w_viewofs_vert);
319 x += img->w;
320 d ^= 1;
321 } while (x < w_view_wdt);
323 if (sky_type == 2 && lt_time < 0) {
324 if (!lt_side) V_spr(0, w_viewofs_vert+lt_ypos, &ltn[lt_type][lt_time < -5 ? 0 : 1]);
325 else V_spr2(w_view_wdt-1, w_viewofs_vert+lt_ypos, &ltn[lt_type][lt_time < -5 ? 0 : 1]);
327 } else {
328 V_clr(0, w_view_wdt, w_viewofs_vert+1, w_view_hgt, 0x97);
330 } else {
331 V_clr(0, w_view_wdt, w_viewofs_vert, w_view_hgt, 0);
336 ////////////////////////////////////////////////////////////////////////////////
337 #define DECL_CONVAR_INT(_xname,_xdef,_xfags,_xhelp) \
338 static int _xname = (_xdef); \
339 CONVAR_INT(_xname, _xname, (_xfags), (_xhelp))
341 DECL_CONVAR_INT(r_flashlight_r, 128, 0, "flashlight red")
342 DECL_CONVAR_INT(r_flashlight_g, 128, 0, "flashlight green")
343 DECL_CONVAR_INT(r_flashlight_b, 0, 0, "flashlight blue")
344 DECL_CONVAR_INT(r_flashlight_a, 255, 0, "flashlight alpha")
348 ////////////////////////////////////////////////////////////////////////////////
349 static void Z_add_lights (player_t *p) {
350 if (r_lighting) {
351 Uint32 stt = SDL_GetTicks();
352 //int ang = g_time%360*2;
353 int ang = g_time/2%64;
355 if (g_map == 1) {
356 int lang = sin(ang*2*(M_PI/32.0f))*20;
358 //Z_add_light_sector(197, 330, 192, 35+lang, 145+lang, 255, 0, 0, 120);
359 Z_add_light_sector(197, 330, 192, 35+lang, 145+lang, 255, 0, 0, 128);
361 Z_add_light_sector(388, 410, 192, 35+lang, 145+lang, 255, 0, 0, 180);
364 int lpx = sin(ang*(M_PI/32.0f))*40;
365 int lpy = sin(ang*(M_PI/32.0f))*10;
366 Z_add_light(200+lpx, 300+lpy, 128, 255, 127, 0, 200);
370 if (r_lights_tnum > 0 && r_lights_trad > 2) {
371 if (r_lights_trad > 250) r_lights_trad = 250;
373 Z_add_light(p->o.x, p->o.y, 64, 0, 128, 0, 255);
374 //Z_add_light(p->o.x, p->o.y, 64, 0, 0, 0, 128);
375 //Z_add_light(197, 330, 192, 255, 0, 0, 92);
376 //Z_add_light_sector(p->o.x, p->o.y, 92, ang, ang+42, 0, 255, 0, 64);
378 //Z_add_light_sector(197, 330, 192, 90-35+ang, 90+35+ang, 255, 0, 0, 92);
379 //Z_add_light_sector(197, 360, 192, 90-35+ang, 90+35+ang, 255, 0, 0, 255);
381 //Z_add_light_sector(197, 360, 192, 90-35+ang, 90+35+ang, 255, 0, 0, 255);
382 //Z_add_light_sector(197, 360, 192, 0+ang, 35+ang, 255, 0, 0, 255);
383 //Z_add_light_sector(197, 360, 192, 0, ang%180, 255, 0, 0, 255);
384 //Z_add_light_sector(197, 360, 192, 0/*90-35+ang*/, 359/*90+35+ang*/, 255, 0, 0, 255);
386 for (int f = 0; f < 30; ++f) {
387 Z_add_light(f*64, f*64, 250, 0, 0, 255-f*10, 98);
390 for (int f = 1; f < r_lights_tnum; ++f) {
391 Z_add_light(p->o.x, p->o.y-8, r_lights_trad, 0, 0, 60, 40);
394 stt = SDL_GetTicks()-stt;
395 //fprintf(stderr, "draw: %u msecs\n", stt);
398 if (r_flashlight) {
399 for (int plnum = 0; plnum < g_plrcount; ++plnum) {
400 player_t *p = &pl[plnum];
401 int x, y, ss, se;
403 if (n_host != NULL && !(g_st == GS_GAME && !g_trans && gnet_state == GNETS_PLAYING)) {
404 continue;
407 if (p->d) {
408 // to the right
409 x = p->o.x-2+(p->st == PLST_GO ? 5 : 0);
410 y = p->o.y-24-(p->st == PLST_GO ? 1 : 0);
411 ss = 340;
412 se = 375;
413 if (p->f&PLF_UP) { ss -= 45; se -= 45; }
414 else if (p->f&PLF_DOWN) { ss += 45; se += 45; }
416 x -= 10;
417 if (p->f&PLF_UP) { x += 2; y += 4; }
418 if (p->f&PLF_DOWN) { x += 0; y -= 6; }
419 } else {
420 // to the left
421 x = p->o.x-1-(p->st == PLST_GO ? 4 : 0);
422 y = p->o.y-24-(p->st == PLST_GO ? 1 : 0);
423 ss = 160;
424 se = 195;
425 if (p->f&PLF_UP) { ss += 45; se += 45; }
426 else if (p->f&PLF_DOWN) { ss -= 45; se -= 45; }
427 x += 10;
428 if (p->f&PLF_UP) { x += 1; y += 4; }
429 if (p->f&PLF_DOWN) { x += 0; y -= 7; }
431 y += 3;
432 if (x > p->o.x) {
433 while (fldhit1(x, y) && x >= p->o.x-6) --x;
434 } else {
435 while (fldhit1(x, y) && x <= p->o.x+6) ++x;
437 Z_add_light_sector_mr(x, y, 220, ss, se, r_flashlight_r, r_flashlight_g, r_flashlight_b, r_flashlight_a, 8);
444 static ccBool dbg_dump_light_time = CC_FALSE;
445 CONVAR_BOOL(dbg_dump_light_time, dbg_dump_light_time, 0, "dump lightning time")
448 ////////////////////////////////////////////////////////////////////////////////
449 void Z_light_start (void) {
450 lb_reset(0);
451 Z_reset_lights();
455 void W_draw (player_t *p) {
456 //memset(vscrbuf, 0, SCRW*SCRH);
457 //memset(scrlightmap, (r_lighting ? /*LMAP_BACK*/LMAP_NORMAL : LMAP_FULLLIT), SCRW*SCRH);
459 W_adjust();
460 V_setrect(0, w_view_wdt, w_viewofs_vert, w_view_hgt);
462 if (r_lighting) Z_light_start();
464 Z_draw_sky();
465 Z_drawfld((const uint8_t *)fldb, 1);
466 DOT_draw();
467 SW_draw();
468 IT_draw();
469 MN_draw();
470 WP_draw();
472 if (n_host == NULL) {
473 for (int f = 0; f < g_plrcount; ++f) PL_draw(&pl[f]);
474 } else {
475 if (g_st == GS_GAME && !g_trans && gnet_state == GNETS_PLAYING) {
476 for (int f = 0; f < g_plrcount; ++f) PL_draw(&pl[f]);
477 } else {
478 PL_draw(&pl[n_local_player_num]);
482 SMK_draw();
483 FX_draw();
484 Z_drawfld((const uint8_t *)fldf, 0);
486 if (r_lighting) {
487 Uint32 st = SDL_GetTicks();
489 Z_add_lights(p);
490 Z_render_lights();
491 lb_draw(0, w_viewofs_vert, w_view_wdt, w_view_hgt);
492 if (dbg_dump_light_time) {
493 st = SDL_GetTicks()-st;
494 fprintf(stderr, "light time: %u ms\n", st);
496 } else {
497 lbx_draw(0, w_viewofs_vert, w_view_wdt, w_view_hgt);
499 Z_drawliquids();
501 if (sky_type == 2 && (lt_time == -4 || lt_time == -2)) V_remap_rect(0, w_view_wdt, w_viewofs_vert+1, w_view_hgt, clrmap+256*11);
503 V_setrect(0, SCRW, 0, SCRH);
507 ////////////////////////////////////////////////////////////////////////////////
508 void W_init (void) {
509 Z_reset_level_lights();
511 for (int i = 1; i < ANIT; ++i) {
512 int j;
514 for (j = 0; anm[i-1][j]; ++j) {
515 anih[i][j] = F_getresid(anm[i-1][j]);
516 V_loadvga(anm[i-1][j], &anispr[i][j]);
518 for (; j < 5; ++j) anih[i][j] = -1;
521 memset(anic, 0, sizeof(anic));
522 cheatNoBack = cheatNoFront = CC_FALSE;
524 DOT_init();
525 SMK_init();
526 FX_init();
527 WP_init();
528 IT_init();
529 SW_init();
530 PL_init();
531 MN_init();
532 //M_unlock(horiz);
533 //horiz = M_lock(F_getresid("RSKY1"));
534 V_loadvga("RSKY1", &horiz);
536 free_chunks();
538 m_notarget = CC_FALSE;
542 static void fix_anim (void) {
543 walp[0] = NULL;
545 for (int f = 1; f < 256; ++f) {
546 int a = walani[f];
548 walp[f] = &walpix[f];
549 if (a != 0) walp[f] = &anispr[a][anic[a]];
554 void W_act (void) {
555 if (g_time%3 != 0) return;
557 for (int f = 1; f < 256; ++f) {
558 int a = walani[f];
560 if (a != 0) {
561 if (anih[a][++anic[a]] == -1) anic[a] = 0;
562 //walp[f] = M_lock(anih[a][anic[a]]);
563 //fprintf(stderr, "f=%d; a=%d; anic=%u; anih=%d\n", f, a, anic[a], anih[a][anic[a]]);
564 walp[f] = &anispr[a][anic[a]];
565 //walp[f]->wanim = 666;
571 ////////////////////////////////////////////////////////////////////////////////
572 static wall_t w_wallnames[256];
574 static int W_mapload_wallnames (MemBuffer *mbuf, const map_block_t *blk) {
575 if (mbuf == NULL) return 0; // no post-processing
577 int sz = blk->sz;
578 int f, c;
579 wall_t w;
581 for (f = 0; f < 256; ++f) {
582 walh[f] = -1;
583 walswp[f] = f;
584 walani[f] = 0;
586 memset(w_wallnames, 0, sizeof(w_wallnames));
588 for (f = 1; f < 256 && sz > 0; ++f, sz -= sizeof(w)) {
589 if (membuf_read_full(mbuf, &w, sizeof(w)) < 0) return -1;
591 w_wallnames[f] = w;
592 if (strncasecmp(w.n, "_WATER_", 7) == 0) {
593 // animated water/laval/acid texture
594 V_freevga(&walpix[f]);
595 walpix[f].wanim = (w.n[7]-'0'+1);
596 walh[f] = -2;
597 continue;
599 walh[f] = F_getresid(w.n);
600 V_loadvga(w.n, &walpix[f]);
601 if (w.n[0] == 'S' && w.n[1] == 'W' && w.n[4] == '_') walswp[f] = 0;
602 walf[f] = (w.t ? 1 : 0);
603 if (w.t) walh[f] |= 0x8000;
604 if (strncasecmp(w.n, "VTRAP01", 8) == 0) walf[f] |= 2;
605 walani[f] = getani(w.n);
608 for (c = f, f = 1; f < 256; ++f) {
609 if (walswp[f] == 0) {
610 int k, g;
612 if (c >= 256) break;
613 F_getresname(w.n, walh[f]&0x7FFF);
614 w.n[5] ^= 1;
615 g = F_getresid(w.n)|(walh[f]&0x8000);
616 for (k = 1; k < 256; ++k) if (walh[k] == g) break;
617 if (k >= 256) {
618 walh[k = c++] = g;
619 V_loadvga(w.n, &walpix[k]);// = M_lock(g);
620 walf[k] = (g&0x8000)?1:0;
622 walswp[f] = k;
623 walswp[k] = f;
626 fix_anim();
628 return 0;
632 static int W_mapload_sky (MemBuffer *mbuf, const map_block_t *blk) {
633 char n[9];
635 if (mbuf == NULL) return 0; // no post-processing
637 memset(n, 0, sizeof(n));
638 sky_type = membuf_read_ui16(mbuf);
639 if (sky_type > 2) sky_type = 0;
640 strcpy(n, "RSKY1");
641 n[4] = sky_type+'0';
642 V_loadvga(n, &horiz);
644 return 0;
648 static void rle_unpack (const void *buf, int len, void *obuf) {
649 const uint8_t *p;
650 uint8_t *o;
651 int l, n;
653 for (p = (const uint8_t *)buf, o = (uint8_t *)obuf, l = len; l; ++p, --l) {
654 if (*p == 255) {
655 n = *((const uint16_t *)(++p));
656 memset(o, *(p += 2), n);
657 o += n;
658 l -= 3;
659 } else {
660 *(o++) = *p;
666 // fill tiles occupied by big textures
667 static int postprocess_field (uint8_t *fld) {
668 uint8_t *fp = fld;
669 char reported[256];
671 memset(reported, 0, sizeof(reported));
673 for (int y = 0; y < FLDH; ++y) {
674 for (int x = 0; x < FLDW; ++x, ++fp) {
676 if (*fp == 255) {
677 conlogf("too many different tiles on level!\n");
678 return -1;
681 if (*fp == 0) {
682 // let's fill this with 255, so light will have something to lit
683 // for foreground tiles -- mark as 'unoccupied'
684 *fp = 255;
685 } else {
686 const vgaimg *pic = walp[*fp];
688 if (pic == NULL || pic->w < 1) {
689 if (!reported[*fp]) {
690 char n[9];
692 reported[*fp] = 1;
694 n[8] = 0;
695 memcpy(n, w_wallnames[*fp].n, 8);
696 if (strncasecmp(n, "_water_", 7) != 0) {
697 conlogf("invalid texture on level: %u! [%s]\n", *fp, n);
698 //return -1;
699 *fp = 0;
700 } else {
701 *fp = 255;
709 fp = fld;
710 for (int y = 0; y < FLDH; ++y) {
711 for (int x = 0; x < FLDW; ++x, ++fp) {
712 if (*fp > 0 && *fp < 255) {
713 // this is textured tile, let's try to mark adjacent tiles as used if necessary
714 const vgaimg *pic = walp[*fp];
716 if (pic != NULL && pic->w > 0 && pic->wanim <= 0) {
717 int sx = x*CELW-pic->sx, ex = sx+pic->w;
718 int sy = y*CELH-pic->sy, ey = sy+pic->h;
720 for (int yy = sy; yy < ey; yy += CELH) {
721 for (int xx = sx; xx < ex; xx += CELW) {
722 int fx = xx/CELW, fy = yy/CELH;
724 if (fx >= 0 && fx < FLDW && fy >= 0 && fy < FLDH) {
725 uint8_t *ff = fld+fy*FLDW+fx;
727 if (*ff == 255) *ff = 0; // this tile is 'occupied'
736 return 0;
740 static int W_mapload_field (MemBuffer *mbuf, const map_block_t *blk, uint8_t *fld) {
741 void *buf;
743 switch (blk->st) {
744 case 0:
745 if (membuf_read_full(mbuf, fld, FLDW*FLDH) < 0) return -1;
746 break;
747 case 1:
748 if ((buf = malloc(blk->sz)) == NULL) {
749 conlogf("map loader: out of memory!\n");
750 return -1;
752 if (membuf_read_full(mbuf, buf, blk->sz) < 0) { free(buf); return -1; }
753 rle_unpack(buf, blk->sz, fld);
754 free(buf);
755 break;
756 default: return 0;
759 return 0;
763 static int W_mapload_back (MemBuffer *mbuf, const map_block_t *blk) {
764 if (mbuf == NULL) return postprocess_field(fldb);
766 return W_mapload_field(mbuf, blk, fldb);
769 static int W_mapload_front (MemBuffer *mbuf, const map_block_t *blk) {
770 if (mbuf == NULL) return postprocess_field(fldf);
772 return W_mapload_field(mbuf, blk, fldf);
775 static int W_mapload_wtype (MemBuffer *mbuf, const map_block_t *blk) {
776 if (mbuf == NULL) return 0; // no post-processing
778 return W_mapload_field(mbuf, blk, fldm);
782 ////////////////////////////////////////////////////////////////////////////////
783 static int W_savegame (MemBuffer *mbuf, int waserror) {
784 if (mbuf != NULL) {
785 membuf_write_ui8(mbuf, 0); // version
786 membuf_write_ui16(mbuf, FLDW);
787 membuf_write_ui16(mbuf, FLDH);
788 membuf_write_ui8(mbuf, sky_type&0x7f);
790 for (int f = 1; f < 256; ++f) {
791 char s[8];
793 getname(f, s);
794 membuf_write(mbuf, s, 8);
797 membuf_write(mbuf, walf, sizeof(walf));
798 membuf_write(mbuf, walswp, sizeof(walswp));
799 membuf_write(mbuf, fldb, FLDW*FLDH);
800 membuf_write(mbuf, fldm, FLDW*FLDH);
801 membuf_write(mbuf, fldf, FLDW*FLDH);
804 return 0;
808 static int W_loadgame (MemBuffer *mbuf, int waserror) {
809 if (mbuf != NULL) {
810 uint16_t w, h;
811 char s[9];
813 if (membuf_read_ui8(mbuf) != 0) {
814 conlogf("LOADGAME ERROR: invalid map version!\n");
815 return -1;
817 w = membuf_read_ui16(mbuf);
818 h = membuf_read_ui16(mbuf);
819 if (w < 1 || w > 32767 || h < 1 || h > 32767) {
820 conlogf("LOADGAME ERROR: invalid map size!\n");
821 return -1;
823 W_set_field_size(w, h);
824 sky_type = membuf_read_ui8(mbuf);
825 if (sky_type > 2) {
826 conlogf("LOADGAME WARNING: invalid sky!\n");
827 sky_type = 0;
830 for (int f = 1; f < 256; ++f) {
831 memset(s, 0, sizeof(s));
832 walani[f] = 0;
833 walp[f] = &walpix[f];
834 if (membuf_read_full(mbuf, s, 8) < 0) return -1;
835 if (!s[0]) {
836 walh[f] = -1;
837 V_freevga(&walpix[f]);
838 walp[f] = NULL;
839 continue;
841 walani[f] = getani(s);
842 if (strncasecmp(s, "_WATER_", 7) == 0) {
843 walh[f] = -2;
844 walpix[f].wanim = (s[7]-'0'+1);
845 } else {
846 walh[f] = F_getresid(s);
847 V_loadvga(s, &walpix[f]);
851 membuf_read_full(mbuf, walf, sizeof(walf));
852 for (int f = 1; f < 256; ++f) if (walf[f]&1) walh[f] |= 0x8000;
853 membuf_read_full(mbuf, walswp, sizeof(walswp));
854 membuf_read_full(mbuf, fldb, FLDW*FLDH);
855 membuf_read_full(mbuf, fldm, FLDW*FLDH);
856 membuf_read_full(mbuf, fldf, FLDW*FLDH);
858 strcpy(s, "RSKY1");
859 s[4] = sky_type+'0';
860 V_loadvga(s, &horiz);
862 fix_anim();
865 return 0;
869 ////////////////////////////////////////////////////////////////////////////////
870 GCC_CONSTRUCTOR_USER {
871 for (size_t f = 0; f < sizeof(ltn)/sizeof(ltn[0]); ++f) { V_initvga(&ltn[f][0]); V_initvga(&ltn[f][1]); }
872 for (size_t f = 0; f < sizeof(walpix)/sizeof(walpix[0]); ++f) V_initvga(&walpix[f]);
873 for (size_t f = 0; f < sizeof(anih)/sizeof(anih[0]); ++f) {
874 V_initvga(&anispr[f][0]);
875 V_initvga(&anispr[f][1]);
876 V_initvga(&anispr[f][2]);
877 V_initvga(&anispr[f][3]);
878 V_initvga(&anispr[f][4]);
880 V_initvga(&horiz);
882 _light_constructor_();
884 F_registerMapLoad(MB_WALLNAMES, W_mapload_wallnames, NULL);
885 F_registerMapLoad(MB_BACK, W_mapload_back, NULL);
886 F_registerMapLoad(MB_WTYPE, W_mapload_wtype, NULL);
887 F_registerMapLoad(MB_FRONT, W_mapload_front, NULL);
888 F_registerMapLoad(MB_SKY, W_mapload_sky, NULL);
890 F_registerSaveLoad("LEVELMAPS", W_savegame, W_loadgame, SAV_NORMAL);
891 F_registerSaveLoad("LEVELLIGHTS", W_savelights, W_loadlights, SAV_OPTIONAL);
895 GCC_DESTRUCTOR_USER {
896 for (size_t f = 0; f < sizeof(ltn)/sizeof(ltn[0]); ++f) { V_freevga(&ltn[f][0]); V_freevga(&ltn[f][1]); }
897 for (size_t f = 0; f < sizeof(walpix)/sizeof(walpix[0]); ++f) V_freevga(&walpix[f]);
898 for (size_t f = 0; f < sizeof(anih)/sizeof(anih[0]); ++f) {
899 V_freevga(&anispr[f][0]);
900 V_freevga(&anispr[f][1]);
901 V_freevga(&anispr[f][2]);
902 V_freevga(&anispr[f][3]);
903 V_freevga(&anispr[f][4]);
905 V_freevga(&horiz);