DEADSOFTWARE

portability: avoid errors on some compilers
[flatwaifu.git] / src / soft / render.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 <stdio.h>
19 #include <string.h>
20 #include <stdarg.h>
21 #include <stdlib.h> // abs()
22 #include <assert.h>
23 #include "glob.h"
24 #include "render.h"
25 #include "view.h"
26 #include "player.h"
27 #include "switch.h"
28 #include "vga.h"
29 #include "menu.h"
30 #include "misc.h"
31 #include "dots.h"
32 #include "items.h"
33 #include "monster.h"
34 #include "weapons.h"
35 #include "smoke.h"
36 #include "fx.h"
37 #include "memory.h"
38 #include "files.h"
39 #include "error.h"
40 #include "game.h"
41 #include "sound.h"
42 #include "music.h"
43 #include "system.h"
45 #include "common/cp866.h"
47 #pragma pack(push, 1)
48 typedef struct rgb_t {
49 byte r, g, b;
50 } rgb_t;
51 #pragma pack(pop)
53 // game
54 static vgaimg *scrnh[3]; // TITLEPIC INTERPIC ENDPIC
55 static vgaimg *ltn[2][2];
56 static void *cd_scr;
57 // smoke
58 static vgaimg *smk_spr[SMSN];
59 static vgaimg *smk_fspr[FLSN];
60 // fx
61 static vgaimg *fx_spr[15];
62 static char fx_sprd[15];
63 // weapons
64 static vgaimg *wp_spr[49*2];
65 static char wp_sprd[49*2];
66 // items
67 static vgaimg *item_spr[58];
68 static char item_sprd[58];
69 // player
70 static vgaimg *plr_spr[27*2];
71 static char plr_sprd[27*2];
72 static vgaimg *plr_wpn[11][6];
73 // monsters
74 static vgaimg *pl_spr[2];
75 static vgaimg *mn_spr[MN_TN][29*2];
76 static char mn_sprd[MN_TN][29*2];
77 static vgaimg *mn_fspr[8];
78 static vgaimg *mn_sgun[2];
79 // misc
80 #define MAXAIR 1091
81 static vgaimg *sth[22], *bfh[160 - '!'], *sfh[160 - '!'], *stone, *stone2, *keys[3];
82 static int prx = 0, pry = 0;
83 // menu
84 static vgaimg *msklh[2], *mbarl, *mbarm, *mbarr, *mbaro, *mslotl, *mslotm, *mslotr;
85 // low level
86 static int gammaa = 0;
87 static rgb_t *main_pal;
88 static byte std_pal[256][3];
89 static byte gamcor[5][64]={
90 #include "gamma.dat"
91 };
92 // walls
93 #define ANIT 5
94 static int WD, HT;
95 static int w_o, w_x, w_y;
96 static vgaimg *walp[256];
97 static int walh[256];
98 static byte walani[256];
99 static byte walswp[256];
100 static int anih[ANIT][5];
101 static byte anic[ANIT];
102 static int max_textures;
103 static byte w_horiz = 1;
104 static vgaimg *horiz;
106 static int init_screen_width = 0;
107 static int init_screen_height = 0;
108 static byte init_screen_full = 0xFF;
109 static int init_screen_gammaa = -1;
111 /* --- misc --- */
113 static void *Z_getspr (char n[4], int s, int d, char *dir) {
114 int h = F_getsprid(n, s, d, dir);
115 return V_getvgaimg(h);
118 static vgaimg *Z_get_char_image (vgaimg **img, int ch) {
119 ch = cp866_toupper(ch);
120 return ch > 32 && ch < 160 ? img[ch - '!'] : NULL;
123 static int Z_get_char_width_generic (vgaimg **img, int off, int ch) {
124 vgaimg *p = Z_get_char_image(img, ch);
125 return p == NULL ? off : p->w - 1;
128 static int Z_putch_generic (vgaimg **img, int off, int ch) {
129 vgaimg *p = Z_get_char_image(img, ch);
130 int w = p == NULL ? off : p->w - 1;
131 if (p != NULL) {
132 V_spr(prx, pry, p);
134 prx += w;
135 return w;
138 static int Z_get_string_width_generic (vgaimg **img, int off, const char *fmt, va_list ap) {
139 int i, w, ww;
140 char buf[80];
141 vsprintf(buf, fmt, ap);
142 for (i = w = ww = 0; buf[i]; ++i) {
143 switch (buf[i]) {
144 case '\n':
145 case '\r':
146 ww = max(w, ww);
147 w = 0;
148 break;
149 default:
150 w += Z_get_char_width_generic(img, off, (byte)buf[i]);
153 return max(w, ww);
156 static int Z_printf_generic (vgaimg **img, int off, const char *fmt, va_list ap) {
157 int i, w, ww;
158 char buf[80];
159 vsprintf(buf, fmt, ap);
160 for (i = w = ww = 0; buf[i]; ++i) {
161 switch (buf[i]) {
162 case '\n':
163 pry += off + 1;
164 case '\r':
165 w = max(w, ww);
166 prx = 0;
167 w = 0;
168 break;
169 default:
170 w += Z_putch_generic(img, off, (byte)buf[i]);
173 return w;
176 static void Z_gotoxy (int x, int y) {
177 prx = x;
178 pry = y;
181 static int Z_get_big_string_width (const char *fmt, ...) {
182 va_list a;
183 va_start(a, fmt);
184 int w = Z_get_string_width_generic(bfh, 12, fmt, a);
185 va_end(a);
186 return w;
189 static int Z_printbf (const char *fmt, ...) {
190 va_list a;
191 va_start(a, fmt);
192 int w = Z_printf_generic(bfh, 12, fmt, a);
193 va_end(a);
194 return w;
197 static int Z_get_small_string_width (const char *fmt, ...) {
198 va_list a;
199 va_start(a, fmt);
200 int w = Z_get_string_width_generic(sfh, 7, fmt, a);
201 va_end(a);
202 return w;
205 static int Z_printsf (const char *fmt, ...) {
206 va_list a;
207 va_start(a, fmt);
208 int w =Z_printf_generic(sfh, 7, fmt, a);
209 va_end(a);
210 return w;
213 static void Z_drawspr (int x, int y, void *p, char d) {
214 if (d) {
215 V_spr2(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p);
216 } else {
217 V_spr(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p);
221 static void Z_clrst (void) {
222 V_pic(SCRW - 120, w_o, stone);
223 int y = ((vgaimg*)stone)->h;
224 while (y < HT) {
225 V_pic(SCRW - 120, w_o + y, stone2);
226 y += ((vgaimg*)stone)->h;
230 static void Z_drawstlives (char n) {
231 V_setrect(SCRW - 40, 30, w_o, 40);
232 V_spr(SCRW - 35, w_o + 17, sth[n]);
235 static void Z_drawstkeys (byte k) {
236 int x, n;
237 V_setrect(SCRW - 120, 70, w_o + 77, 23);
238 for (k >>= 4, n = 0, x = SCRW - 75; n < 3; ++n, k >>= 1, x += 9) {
239 if (k & 1) {
240 V_spr(x, w_o + 91, keys[n]);
245 static void Z_drawstair (int a) {
246 V_setrect(SCRW - 120, 120, w_o + 49, 2);
247 if (a > 0) {
248 if (a > MAXAIR) {
249 a = MAXAIR;
251 a = a * 100 / MAXAIR;
252 V_clr(SCRW - 110, a, w_o + 49, 2, 0xC8);
256 static void Z_drawstprcnt (int y, int n) {
257 char s[20];
258 int l, i, x, c;
259 V_setrect(SCRW - 120, 70, y * 19 + 7 + w_o, 19);
260 sprintf(s, "%3d%%", n);
261 l = strlen(s);
262 x = SCRW - 110;
263 for (i = 0; i < l; ++i, x += 14) {
264 if (s[i] >='0' && s[i] <= '9') {
265 c = s[i] - '0';
266 } else if (s[i] == '-') {
267 c = 10;
268 } else if (s[i] == '%') {
269 c = 11;
270 } else {
271 c = -1;
273 if (c >= 0) {
274 V_spr(x, y * 19 + 7 + w_o, sth[c]);
279 static void Z_drawstnum (int n) {
280 char s[20];
281 int l, i, x, c;
282 V_setrect(SCRW - 50, 50, w_o + 77, 23);
283 if (g_dm) {
284 sprintf(s, "%d", n);
285 l = strlen(s);
286 x = (115 - l * 14) + SCRW - 120;
287 for (i = 0; i < l; ++i, x += 14) {
288 if (s[i] >= '0' && s[i] <= '9') {
289 c = s[i] - '0';
290 } else if (s[i] == '-') {
291 c = 10;
292 } else if(s[i] == '%') {
293 c = 11;
294 } else {
295 c =- 1;
297 if (c >= 0) {
298 V_spr(x, w_o + 77 + 5, sth[c]);
304 static void Z_drawstwpn (int n, int a) {
305 char s[20];
306 int l, i, x, c;
307 i = n;
308 V_setrect(SCRW - 120, 120, w_o + 58, 23);
309 if (i >= 0) {
310 V_spr(SCRW - 88, w_o + 58 + 19, sth[i + 12]);
312 if (n >= 2) {
313 sprintf(s, "%d", a);
314 l = strlen(s);
315 x = SCRW - 10 - l * 14;
316 for (i = 0; i < l; ++i, x += 14) {
317 if (s[i] >= '0' && s[i] <= '9') {
318 c = s[i] - '0';
319 } else if (s[i] == '-') {
320 c = 10;
321 } else if (s[i] == '%') {
322 c = 11;
323 } else {
324 c = -1;
326 if (c >= 0) {
327 V_spr(x, w_o + 58 + 2, sth[c]);
333 static void Z_drawmanspr (int x, int y, void *p, char d, byte color) {
334 if (d) {
335 V_manspr2(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p, color);
336 } else {
337 V_manspr(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p, color);
341 static void Z_drawfld (byte *fld, int bg) {
342 byte *p = fld;
343 int x, y;
344 for (y = 0; y < FLDH; y++) {
345 for (x = 0; x < FLDW; x++) {
346 int sx = x * CELW - w_x + WD / 2;
347 int sy = y * CELH - w_y + HT / 2 + 1 + w_o;
348 int id = *p;
349 if (id) {
350 //intptr_t spc = (intptr_t) walp[id];
351 int spc = R_get_special_id(id);
352 if (spc >= 0 && spc <= 3) {
353 if (!bg) {
354 byte *cmap = clrmap + (spc + 7) * 256;
355 V_remap_rect(sx, sy, CELW, CELH, cmap);
357 } else {
358 V_pic(sx, sy, walp[id]);
361 p++;
366 /* --- menu --- */
368 static int gm_tm = 0; // ???
370 #define SCROLLER_MIDDLE 10
371 #define TEXTFIELD_MIDDLE 2
373 static void get_entry_size (const menu_t *m, int i, int *w, int *h) {
374 assert(m != NULL);
375 assert(i >= 0);
376 assert(w != NULL);
377 assert(h != NULL);
378 int x = 0;
379 int y = 0;
380 int type = 0;
381 menu_msg_t msg;
382 msg.type = GM_GETENTRY;
383 if (GM_send(m, i, &msg)) {
384 type = msg.integer.i;
385 switch (type) {
386 case GM_BUTTON:
387 case GM_SCROLLER:
388 case GM_TEXTFIELD:
389 case GM_TEXTFIELD_BUTTON:
390 msg.type = GM_GETCAPTION;
391 if (GM_send(m, i, &msg)) {
392 x = Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
394 break;
395 case GM_SMALL_BUTTON:
396 msg.type = GM_GETCAPTION;
397 if (GM_send(m, i, &msg)) {
398 x = Z_get_small_string_width("%.*s", msg.string.maxlen, msg.string.s);
400 break;
401 default:
402 assert(0);
404 switch (type) {
405 case GM_BUTTON:
406 msg.type = GM_GETSTR;
407 if (GM_send(m, i, &msg)) {
408 x += Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
410 y = 16;
411 break;
412 case GM_SMALL_BUTTON:
413 msg.type = GM_GETSTR;
414 if (GM_send(m, i, &msg)) {
415 x += Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
417 y = 12;
418 break;
419 case GM_SCROLLER:
420 x += (SCROLLER_MIDDLE + 2) * 8;
421 y = 16;
422 break;
423 case GM_TEXTFIELD:
424 case GM_TEXTFIELD_BUTTON:
425 msg.type = GM_GETSTR;
426 if (GM_send(m, i, &msg)) {
427 x += (msg.string.maxlen + 2) * 8;
428 } else {
429 x += (TEXTFIELD_MIDDLE + 2) * 8;
431 y = 16;
432 break;
433 default:
434 assert(0);
437 *w = x;
438 *h = y;
441 static void get_menu_size (const menu_t *m, int *w, int *h) {
442 assert(m != NULL);
443 assert(w != NULL);
444 assert(h != NULL);
445 int i, n, x, y, xx, yy, type;
446 menu_msg_t msg;
447 msg.type = GM_QUERY;
448 if (GM_send_this(m, &msg)) {
449 n = msg.integer.b;
450 type = msg.integer.s;
451 x = 0;
452 y = 0;
453 msg.type = GM_GETTITLE;
454 if (GM_send_this(m, &msg)) {
455 switch (type) {
456 case GM_BIG: x = Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s); break;
457 case GM_SMALL: x = Z_get_small_string_width("%.*s", msg.string.maxlen, msg.string.s); break;
458 default: assert(0);
461 for (i = 0; i < n; i++) {
462 get_entry_size(m, i, &xx, &yy);
463 x = max(x, xx);
464 y += yy;
466 *w = x;
467 *h = y;
468 } else {
469 *w = 0;
470 *h = 0;
474 static int GM_draw (void) {
475 int i, j, n, x, y, xoff, yoff, cur, w, type, recv;
476 const menu_t *m = GM_get();
477 menu_msg_t msg;
478 if (m != NULL) {
479 get_menu_size(m, &x, &y);
480 x = SCRW / 2 - x / 2;
481 y = SCRH / 2 - y / 2;
482 // --- title ---
483 msg.type = GM_QUERY;
484 if (GM_send_this(m, &msg)) {
485 cur = msg.integer.i;
486 n = msg.integer.a;
487 type = msg.integer.s;
488 msg.type = GM_GETTITLE;
489 if (GM_send_this(m, &msg)) {
490 Z_gotoxy(x, y - 10);
491 switch (type) {
492 case GM_SMALL: yoff = 8; Z_printsf("%.*s", msg.string.maxlen, msg.string.s); break;
493 case GM_BIG: yoff = 20; Z_printbf("%.*s", msg.string.maxlen, msg.string.s); break;
494 default: assert(0);
496 } else {
497 yoff = 0;
499 for (i = 0; i < n; i++) {
500 msg.type = GM_GETENTRY;
501 if (GM_send(m, i, &msg)) {
502 type = msg.integer.i;
503 if (i == cur) {
504 if (type == GM_SMALL_BUTTON) {
505 Z_gotoxy(x - 8, y + yoff);
506 Z_printsf(">");
507 } else {
508 V_spr(x - 25, y + yoff - 8, msklh[(gm_tm / 6) & 1]);
511 msg.type = GM_GETCAPTION;
512 if (GM_send(m, i, &msg)) {
513 Z_gotoxy(x, y + yoff);
514 if (type == GM_SMALL_BUTTON) {
515 xoff = Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
516 } else {
517 xoff = Z_printbf("%.*s", msg.string.maxlen, msg.string.s);
519 } else {
520 xoff = 0;
522 switch (type) {
523 case GM_BUTTON:
524 case GM_SMALL_BUTTON:
525 msg.type = GM_GETSTR;
526 if (GM_send(m, i, &msg)) {
527 Z_gotoxy(x + xoff, y + yoff);
528 if (type == GM_SMALL_BUTTON) {
529 Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
530 } else {
531 Z_printbf("%.*s", msg.string.maxlen, msg.string.s);
534 yoff += type == GM_BUTTON ? 16 : 12;
535 break;
536 case GM_TEXTFIELD:
537 case GM_TEXTFIELD_BUTTON:
538 yoff += 9;
539 msg.type = GM_GETSTR;
540 recv = GM_send(m, i, &msg);
541 w = recv ? msg.string.maxlen : TEXTFIELD_MIDDLE;
542 V_spr(x + xoff, y + yoff, mslotl);
543 for (j = 1; j <= w; j++) {
544 V_spr(x + xoff + j * 8, y + yoff, mslotm);
546 V_spr(x + xoff + j * 8, y + yoff, mslotr);
547 Z_gotoxy(x + xoff + 4, y + yoff - 7);
548 if (input && i == cur) {
549 Z_printsf("%.*s_", imax, ibuf);
550 } else if (recv) {
551 Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
553 yoff += 7;
554 break;
555 case GM_SCROLLER:
556 V_spr(x + xoff, y + yoff, mbarl);
557 for (j = 1; j < SCROLLER_MIDDLE; j++) {
558 V_spr(x + xoff + j * 8, y + yoff, mbarm);
560 V_spr(x + xoff + j * 8, y + yoff, mbarr);
561 msg.type = GM_GETINT;
562 if (GM_send(m, i, &msg)) {
563 int lev = (msg.integer.i - msg.integer.a) * ((SCROLLER_MIDDLE - 2) * 8) / msg.integer.b;
564 V_spr(x + xoff + lev + 8, y + yoff, mbaro);
566 yoff += 16;
567 break;
568 default:
569 assert(0);
575 return m != NULL;
578 /* --- dots --- */
580 static void DOT_draw (void) {
581 int i;
582 for (i = 0; i < MAXDOT; i++) {
583 if (dot[i].t) {
584 V_dot(dot[i].o.x - w_x + WD / 2, dot[i].o.y - w_y + HT / 2 + 1 + w_o, dot[i].c);
589 /* --- items --- */
591 static void IT_draw (void) {
592 int i, s;
593 for (i = 0; i < MAXITEM; ++i) {
594 s = -1;
595 if (it[i].t && it[i].s >= 0) {
596 switch(it[i].t & 0x7FFF) {
597 case I_ARM1:
598 s = it[i].s / 9 + 18;
599 break;
600 case I_ARM2:
601 s = it[i].s / 9 + 20;
602 break;
603 case I_MEGA:
604 s = it[i].s / 2 + 22;
605 break;
606 case I_INVL:
607 s = it[i].s / 2 + 26;
608 break;
609 case I_SUPER:
610 case I_RTORCH:
611 case I_GTORCH:
612 case I_BTORCH:
613 s = it[i].s / 2 + (it[i].t - I_SUPER) * 4 + 35;
614 break;
615 case I_GOR1: case I_FCAN:
616 s = it[i].s / 2 + (it[i].t - I_GOR1) * 3 + 51;
617 break;
618 case I_AQUA:
619 s = 30;
620 break;
621 case I_SUIT:
622 s = 34;
623 break;
624 case I_KEYR:
625 case I_KEYG:
626 case I_KEYB:
627 s = (it[i].t & 0x7FFF) - I_KEYR + 31;
628 break;
629 case I_GUN2:
630 s = 57;
631 break;
632 default:
633 s = (it[i].t & 0x7FFF) - 1;
636 if (s >= 0) {
637 Z_drawspr(it[i].o.x, it[i].o.y, item_spr[s], item_sprd[s]);
642 /* --- player --- */
644 static int standspr (player_t *p) {
645 if (p->f & PLF_UP) {
646 return 'X';
647 } else if (p->f & PLF_DOWN) {
648 return 'Z';
649 } else {
650 return 'E';
654 static int wpnspr (player_t *p) {
655 if (p->f & PLF_UP) {
656 return 'C';
657 } else if(p->f & PLF_DOWN) {
658 return 'E';
659 } else {
660 return 'A';
664 static void PL_draw (player_t *p) {
665 enum {STAND, GO, DIE, SLOP, DEAD, MESS, OUT, FALL}; // copypasted from player.c!
666 static int wytab[] = {-1, -2, -1, 0};
667 int s = 'A';
668 int w = 0;
669 int wx = 0;
670 int wy = 0;
671 switch (p->st) {
672 case STAND:
673 if (p->f & PLF_FIRE) {
674 s = standspr(p) + 1;
675 w = wpnspr(p) + 1;
676 } else if (p->pain) {
677 s = 'G';
678 w = 'A';
679 wx = p->d ? 2 : -2;
680 wy = 1;
681 } else {
682 s = standspr(p);
683 w = wpnspr(p);
685 break;
686 case DEAD:
687 s = 'N';
688 break;
689 case MESS:
690 s = 'W';
691 break;
692 case GO:
693 if (p->pain) {
694 s = 'G';
695 w = 'A';
696 wx = p->d ? 2 : -2;
697 wy = 1;
698 } else {
699 s = plr_goanim[p->s / 8];
700 w = (p->f & PLF_FIRE) ? 'B' : 'A';
701 wx = p->d ? 2 : -2;
702 wy = 1 + wytab[s - 'A'];
704 break;
705 case DIE:
706 s = plr_dieanim[p->s];
707 break;
708 case SLOP:
709 s = plr_slopanim[p->s];
710 break;
711 case OUT:
712 s = 0;
713 break;
715 if (p->wpn == 0) {
716 w = 0;
718 if (w) {
719 Z_drawspr(p->o.x + wx, p->o.y + wy, plr_wpn[p->wpn][w - 'A'], p->d);
721 if (s) {
722 Z_drawmanspr(p->o.x, p->o.y, plr_spr[(s - 'A') * 2 + p->d], plr_sprd[(s - 'A') * 2 + p->d], p->color);
726 static void PL_drawst (player_t *p) {
727 int i;
728 V_setrect(WD, 120, w_o, HT);
729 Z_clrst();
730 if (p->drawst & PL_DRAWAIR) {
731 if (p->air < PL_AIR) {
732 Z_drawstair(p->air);
735 if (p->drawst & PL_DRAWLIFE) {
736 Z_drawstprcnt(0, p->life);
738 if (p->drawst & PL_DRAWARMOR) {
739 Z_drawstprcnt(1, p->armor);
741 if (p->drawst & PL_DRAWWPN) {
742 switch(p->wpn) {
743 case 2:
744 case 5:
745 i = p->ammo;
746 break;
747 case 3:
748 case 4:
749 case 9:
750 i = p->shel;
751 break;
752 case 6:
753 i = p->rock;
754 break;
755 case 10:
756 i = p->fuel;
757 break;
758 case 7:
759 case 8:
760 i = p->cell;
761 break;
763 Z_drawstwpn(p->wpn, i);
765 if (p->drawst & PL_DRAWFRAG) {
766 Z_drawstnum(p->frag);
768 if (p->drawst & PL_DRAWKEYS) {
769 Z_drawstkeys(p->keys);
771 if (!_2pl) {
772 if (p->drawst & PL_DRAWLIVES) {
773 Z_drawstlives(p->lives);
778 /* --- monster --- */
780 #define MANCOLOR 0xD0
782 static void MN_draw (void) {
783 enum {SLEEP, GO, RUN, CLIMB, DIE, DEAD, ATTACK, SHOOT, PAIN, WAIT, REVIVE, RUNOUT}; // copypasted from monster.c!
784 int i;
785 for (i = 0; i < MAXMN; i++) {
786 if (mn[i].t) {
787 if (mn[i].t >= MN_PL_DEAD) {
788 Z_drawmanspr(mn[i].o.x, mn[i].o.y, pl_spr[mn[i].t - MN_PL_DEAD], 0, mn[i].d);
789 continue;
791 if ((mn[i].t != MN_SOUL && mn[i].t != MN_PAIN) || mn[i].st != DEAD) {
792 if (mn[i].t != MN_MAN) {
793 Z_drawspr(mn[i].o.x, mn[i].o.y, mn_spr[mn[i].t - 1][(mn[i].ap[mn[i].ac] - 'A') * 2 + mn[i].d], mn_sprd[mn[i].t - 1][(mn[i].ap[mn[i].ac] - 'A') * 2 + mn[i].d]);
794 } else {
795 if (mn[i].ap[mn[i].ac] == 'E' || mn[i].ap[mn[i].ac] == 'F') {
796 Z_drawspr(mn[i].o.x, mn[i].o.y, mn_sgun[mn[i].ap[mn[i].ac] - 'E'], mn[i].d);
798 Z_drawmanspr(mn[i].o.x, mn[i].o.y, mn_spr[mn[i].t - 1][(mn[i].ap[mn[i].ac] - 'A') * 2 + mn[i].d], mn_sprd[mn[i].t - 1][(mn[i].ap[mn[i].ac] - 'A') * 2 + mn[i].d], MANCOLOR);
801 if (mn[i].t == MN_VILE && mn[i].st == SHOOT) {
802 Z_drawspr(mn[i].tx, mn[i].ty, mn_fspr[mn[i].ac / 3], 0);
808 /* --- weapon --- */
810 static void WP_draw (void) {
811 enum {NONE, ROCKET, PLASMA, APLASMA, BALL1, BALL2, BALL7, BFGBALL, BFGHIT, MANF, REVF, FIRE}; // copypasted from weapons.c!
812 int i, s, d, x, y;
813 for (i = 0; i < MAXWPN; ++i) {
814 s = -1;
815 d = 0;
816 switch (wp[i].t) {
817 case NONE:
818 default:
819 break;
820 case REVF:
821 case ROCKET:
822 d = wp[i].s;
823 if (d < 2) {
824 d = wp[i].o.xv > 0 ? 1 : 0;
825 x = abs(wp[i].o.xv);
826 y = wp[i].o.yv;
827 s = 0;
828 if (y < 0) {
829 if (-y >= x) {
830 s = 30;
832 } else if (y > 0) {
833 if (y >= x / 2) {
834 s = 31;
837 } else {
838 s = (d - 2) / 2 + 1;
839 d = 0;
841 break;
842 case MANF:
843 s=wp[i].s;
844 if (s >= 2) {
845 s /= 2;
846 break;
848 case PLASMA:
849 case APLASMA:
850 case BALL1:
851 case BALL7:
852 case BALL2:
853 s = wp[i].s;
854 if (s >= 2) {
855 s = s / 2 + 1;
857 switch (wp[i].t) {
858 case PLASMA:
859 s += 4;
860 break;
861 case APLASMA:
862 s += 11;
863 break;
864 case BALL1:
865 s += 32;
866 break;
867 case BALL2:
868 s += 42;
869 break;
870 case BALL7:
871 s += 37;
872 d = wp[i].o.xv >= 0 ? 1 : 0;
873 break;
874 case MANF:
875 s += 47;
876 d= wp[i].o.xv>=0 ? 1 : 0;
877 break;
879 break;
880 case BFGBALL:
881 s = wp[i].s;
882 if (s >= 2) {
883 s = s / 2 + 1;
885 s += 18;
886 break;
887 case BFGHIT:
888 s = wp[i].s / 2 + 26;
889 break;
891 if (s >= 0) {
892 Z_drawspr(wp[i].o.x, wp[i].o.y, wp_spr[s * 2 + d], wp_sprd[s * 2 + d]);
897 /* --- smoke --- */
899 static void SMK_draw (void) {
900 int i, s;
901 for (i = 0; i < MAXSMOK; ++i) {
902 if (sm[i].t) {
903 switch (sm[i].s) {
904 case 0:
905 s = sm[i].t;
906 if (s >= (SMSN - 1) * 3) {
907 s = 0;
908 } else {
909 s = SMSN - 1 - s / 3;
911 V_sprf((sm[i].x >> 8) - w_x + WD / 2, (sm[i].y >> 8) - w_y + HT / 2 + 1 + w_o, smk_spr[s], &smoke_sprf);
912 break;
913 case 1:
914 s = sm[i].t;
915 if (s >= FLSN - 1) {
916 s = 0;
917 } else {
918 s = FLSN - 1 - s;
920 V_sprf((sm[i].x >> 8) - w_x + WD / 2, (sm[i].y >> 8) - w_y + HT / 2 + 1 + w_o, smk_fspr[s], &flame_sprf);
921 break;
927 /* --- fx --- */
929 static void FX_draw (void) {
930 enum {NONE, TFOG, IFOG, BUBL}; // copypasted from fx.c
931 int i, s;
932 for (i = 0; i < MAXFX; ++i) {
933 s = -1;
934 switch (fx[i].t) {
935 case TFOG:
936 s = fx[i].s / 2;
937 break;
938 case IFOG:
939 s = fx[i].s / 2 + 10;
940 break;
941 case BUBL:
942 V_dot((fx[i].x >> 8) - w_x + WD / 2, (fx[i].y >> 8) - w_y + HT / 2 + 1 + w_o, 0xC0 + fx[i].s);
943 continue;
945 if (s >= 0) {
946 Z_drawspr(fx[i].x, fx[i].y, fx_spr[s], fx_sprd[s]);
951 /* --- view --- */
953 static void W_adjust (void) {
954 int MAXX = FLDW * CELW - WD / 2;
955 int MAXY = FLDH * CELH - HT / 2;
956 if (w_x < WD / 2) w_x = WD / 2;
957 if (w_y < HT / 2) w_y = HT / 2;
958 if (w_x > MAXX) w_x = MAXX;
959 if (w_y > MAXY) w_y = MAXY;
962 static void W_draw(void) {
963 W_adjust();
964 V_setrect(0, WD, w_o + 1, HT);
965 if (w_horiz) {
966 vgaimg *img = (vgaimg*)horiz;
967 int x = 0;
968 int d = 0;
969 do {
970 int y = w_o;
971 d &= ~2;
972 do {
973 V_rotspr(x, y, img, d);
974 y += img->h;
975 d ^= 2;
976 } while (y < HT + w_o);
977 x += img->w;
978 d ^= 1;
979 } while (x < WD);
980 if (sky_type == 2) {
981 if (lt_time < 0) {
982 if (!lt_side) {
983 V_spr(0, w_o + lt_ypos, ltn[lt_type][lt_time < -5 ? 0 : 1]);
984 } else {
985 V_spr2(WD - 1, w_o + lt_ypos, ltn[lt_type][lt_time < -5 ? 0 : 1]);
989 } else {
990 V_clr(0, WD, w_o + 1, HT, 0x97);
992 Z_drawfld((byte*)fldb, 1);
993 DOT_draw();
994 IT_draw();
995 PL_draw(&pl1);
996 if (_2pl) {
997 PL_draw(&pl2);
999 MN_draw();
1000 WP_draw();
1001 SMK_draw();
1002 FX_draw();
1003 Z_drawfld((byte*)fldf, 0);
1004 if (sky_type == 2) {
1005 if (lt_time == -4 || lt_time == -2) {
1006 V_remap_rect(0, WD, w_o + 1, HT, clrmap + 256 * 11);
1011 /* --- game --- */
1013 #define PL_FLASH 90
1015 static void drawview (player_t *p) {
1016 if (p->looky < -SCRH / 4) {
1017 p->looky = -SCRH / 4;
1018 } else if (p->looky > SCRH / 4) {
1019 p->looky = SCRH / 4;
1021 w_x = p->o.x;
1022 w_y = p->o.y - 12 + p->looky;
1023 W_draw();
1024 PL_drawst(p);
1027 static int get_pu_st (int t) {
1028 if (t >= PL_FLASH) {
1029 return 1;
1030 } else if((t / 9) & 1) {
1031 return 0;
1032 } else {
1033 return 1;
1037 static void pl_info (player_t *p, int y) {
1038 dword t = p->kills * 10920 / g_time;
1039 Z_gotoxy(25, y); Z_printbf("KILLS");
1040 Z_gotoxy(25, y + 15); Z_printbf("KPM");
1041 Z_gotoxy(25, y + 30); Z_printbf("SECRETS %u / %u", p->secrets, sw_secrets);
1042 Z_gotoxy(255, y); Z_printbf("%u", p->kills);
1043 Z_gotoxy(255, y + 15); Z_printbf("%u.%u", t / 10, t % 10);
1046 static void W_act (void) {
1047 int i, a;
1048 if (g_time % 3 == 0) {
1049 for (i = 1; i < 256; i++) {
1050 a = walani[i];
1051 if (a != 0) {
1052 anic[a]++;
1053 if (anih[a][anic[a]] == -1) {
1054 anic[a] = 0;
1056 walp[i] = V_getvgaimg(anih[a][anic[a]]);
1062 void R_draw (void) {
1063 int h;
1064 word hr, mn, sc;
1065 W_act();
1066 switch (g_st) {
1067 case GS_ENDANIM:
1068 case GS_END2ANIM:
1069 case GS_DARKEN:
1070 case GS_BVIDEO:
1071 case GS_EVIDEO:
1072 case GS_END3ANIM:
1073 return;
1074 case GS_TITLE:
1075 V_center(1);
1076 V_pic(0, 0, scrnh[0]);
1077 V_center(0);
1078 break;
1079 case GS_ENDSCR:
1080 V_center(1);
1081 V_clr(0, SCRW, 0, SCRH, 0);
1082 V_pic(0, 0, scrnh[2]);
1083 V_center(0);
1084 break;
1085 case GS_INTER:
1086 V_center(1);
1087 V_clr(0, SCRW, 0, SCRH, 0);
1088 V_pic(0, 0, scrnh[1]);
1089 Z_gotoxy(60, 20);
1090 Z_printbf("LEVEL COMPLETE");
1091 Z_calc_time(g_time, &hr, &mn, &sc);
1092 Z_gotoxy(115, 40);
1093 Z_printbf("TIME %u:%02u:%02u", hr, mn, sc);
1094 h = 60;
1095 if (_2pl) {
1096 Z_gotoxy(80, h);
1097 Z_printbf("PLAYER ONE");
1098 Z_gotoxy(80, h + 70);
1099 Z_printbf("PLAYER TWO");
1100 h += SCRH / 10;
1102 pl_info(&pl1, h);
1103 if (_2pl) {
1104 pl_info(&pl2, h + 70);
1106 V_center(0);
1107 break;
1109 V_center(0);
1110 if (g_st == GS_GAME) {
1111 if (_2pl) {
1112 w_o = 0;
1113 WD = SCRW - 120;
1114 HT = SCRH / 2 - 2;
1115 drawview(&pl1);
1116 w_o = SCRH / 2;
1117 WD = SCRW - 120;
1118 HT = SCRH / 2 - 2;
1119 drawview(&pl2);
1120 } else{
1121 w_o = 0;
1122 WD = SCRW - 120;
1123 HT = SCRH - 2;
1124 drawview(&pl1);
1126 if (pl1.invl) {
1127 h = get_pu_st(pl1.invl) * 6;
1128 } else if (pl1.pain < 15) {
1129 h = 0;
1130 } else if (pl1.pain < 35) {
1131 h = 1;
1132 } else if (pl1.pain < 55) {
1133 h = 2;
1134 } else if (pl1.pain < 75) {
1135 h=3;
1136 } else if (pl1.pain < 95) {
1137 h=4;
1138 } else {
1139 h = 5;
1141 if (h != 0) {
1142 V_maptoscr(0, SCRW - 120, 1, _2pl ? SCRH / 2 - 2 : SCRH - 2, clrmap + h * 256);
1144 if (_2pl) {
1145 if (pl2.invl) {
1146 h = get_pu_st(pl2.invl) * 6;
1147 } else if (pl2.pain < 15) {
1148 h = 0;
1149 } else if (pl2.pain < 35) {
1150 h = 1;
1151 } else if (pl2.pain < 55) {
1152 h = 2;
1153 } else if (pl2.pain < 75) {
1154 h = 3;
1155 } else if (pl2.pain < 95) {
1156 h = 4;
1157 } else {
1158 h = 5;
1160 if (h) {
1161 V_maptoscr(0, SCRW - 120, SCRH / 2 + 1, SCRH / 2 - 2, clrmap + h * 256);
1165 V_center(0);
1166 V_setrect(0, SCRW, 0, SCRH);
1167 GM_draw();
1168 V_copytoscr(0, SCRW, 0, SCRH);
1171 void R_alloc (void) {
1172 int i, j, n;
1173 char s[10];
1174 logo("R_alloc: load graphics\n");
1175 // game
1176 scrnh[0] = V_loadvgaimg("TITLEPIC");
1177 scrnh[1] = V_loadvgaimg("INTERPIC");
1178 scrnh[2] = V_loadvgaimg("ENDPIC");
1179 cd_scr = M_lock(F_getresid("CD1PIC"));
1180 for (i = 0; i < 2; ++i) {
1181 sprintf(s, "LTN%c", i + '1');
1182 for (j = 0; j < 2; ++j) {
1183 ltn[i][j] = Z_getspr(s, j, 0, NULL);
1186 // smoke
1187 for (i = 0; i < SMSN; ++i) {
1188 smk_spr[i] = Z_getspr("SMOK", i, 0, NULL);
1190 for (i = 0; i < FLSN; ++i) {
1191 smk_fspr[i] = Z_getspr("FLAM", i, 0, NULL);
1193 // fx
1194 for (i = 0; i < 10; ++i) {
1195 fx_spr[i] = Z_getspr("TFOG", i, 0, fx_sprd + i);
1197 for (; i < 15; ++i) {
1198 fx_spr[i] = Z_getspr("IFOG", i - 10, 0, fx_sprd + i);
1200 // weapons
1201 for (i = 0; i < 4; ++i) {
1202 wp_spr[i * 2] = Z_getspr("MISL", i, 1, wp_sprd + i * 2);
1203 wp_spr[i * 2 + 1] = Z_getspr("MISL", i, 2, wp_sprd + i * 2 + 1);
1205 for (; i < 6; ++i) {
1206 wp_spr[i * 2] = Z_getspr("PLSS", i - 4, 1, wp_sprd + i * 2);
1207 wp_spr[i * 2 + 1] = Z_getspr("PLSS", i - 4, 2, wp_sprd + i * 2 + 1);
1209 for (; i < 11; ++i) {
1210 wp_spr[i * 2] = Z_getspr("PLSE", i - 6, 1, wp_sprd + i * 2);
1211 wp_spr[i * 2 + 1] = Z_getspr("PLSE", i - 6, 2, wp_sprd + i * 2 + 1);
1213 for (; i < 13; ++i) {
1214 wp_spr[i * 2] = Z_getspr("APLS", i - 11, 1, wp_sprd + i * 2);
1215 wp_spr[i * 2 + 1] = Z_getspr("APLS", i - 11, 2, wp_sprd + i * 2 + 1);
1217 for (; i < 18; ++i) {
1218 wp_spr[i * 2] = Z_getspr("APBX", i - 13, 1, wp_sprd + i * 2);
1219 wp_spr[i * 2 + 1] = Z_getspr("APBX", i - 13, 2, wp_sprd + i * 2 + 1);
1221 for(; i < 20; ++i) {
1222 wp_spr[i * 2] = Z_getspr("BFS1", i - 18, 1, wp_sprd + i * 2);
1223 wp_spr[i * 2 + 1] = Z_getspr("BFS1", i - 18, 2, wp_sprd + i * 2 + 1);
1225 for (; i < 26; ++i) {
1226 wp_spr[i * 2] = Z_getspr("BFE1", i - 20, 1, wp_sprd + i * 2);
1227 wp_spr[i * 2 + 1] = Z_getspr("BFE1", i - 20, 2, wp_sprd + i * 2 + 1);
1229 for (; i < 30; ++i) {
1230 wp_spr[i * 2] = Z_getspr("BFE2", i - 26, 1, wp_sprd + i * 2);
1231 wp_spr[i * 2 + 1] = Z_getspr("BFE2", i - 26, 2, wp_sprd + i * 2 + 1);
1233 for (; i < 32; ++i) {
1234 wp_spr[i * 2] = Z_getspr("MISL", i - 30 + 4, 1, wp_sprd + i * 2);
1235 wp_spr[i * 2 + 1] = Z_getspr("MISL", i - 30 + 4, 2, wp_sprd + i * 2 + 1);
1237 for (; i < 37; ++i) {
1238 wp_spr[i * 2] = Z_getspr("BAL1", i - 32, 1, wp_sprd + i * 2);
1239 wp_spr[i * 2 + 1] = Z_getspr("BAL1", i - 32, 2, wp_sprd + i * 2 + 1);
1241 for (; i < 42; ++i) {
1242 wp_spr[i * 2] = Z_getspr("BAL7", i - 37, 1, wp_sprd + i * 2);
1243 wp_spr[i * 2 + 1] = Z_getspr("BAL7", i - 37, 2, wp_sprd + i * 2 + 1);
1245 for (; i < 47; ++i) {
1246 wp_spr[i * 2] = Z_getspr("BAL2", i - 42, 1, wp_sprd + i * 2);
1247 wp_spr[i * 2 + 1] = Z_getspr("BAL2", i - 42, 2, wp_sprd + i * 2 + 1);
1249 for (; i < 49; ++i) {
1250 wp_spr[i * 2] = Z_getspr("MANF", i - 47, 1, wp_sprd + i * 2);
1251 wp_spr[i * 2 + 1] = Z_getspr("MANF", i - 47, 2, wp_sprd + i * 2 + 1);
1253 // items
1254 static char snm[18][4] = {
1255 "CLIP", "SHEL", "ROCK", "CELL", "AMMO", "SBOX", "BROK", "CELP",
1256 "STIM", "MEDI", "BPAK",
1257 "CSAW", "SHOT", "SGN2", "MGUN", "LAUN", "PLAS", "BFUG"
1258 };
1259 static char n4[4][4] = {
1260 "SOUL", "SMRT", "SMGT", "SMBT"
1261 };
1262 static char n3[2][4] = {
1263 "GOR1", "FCAN"
1264 };
1265 for (i = 0; i < 18; ++i) {
1266 item_spr[i] = Z_getspr(snm[i], 0, 0, item_sprd + i);
1268 for (; i < 20; ++i) {
1269 item_spr[i] = Z_getspr("ARM1", i - 18, 0, item_sprd + i);
1270 item_spr[i + 2] = Z_getspr("ARM2", i - 18, 0, item_sprd + i);
1272 i+=2;
1273 for (; i < 26; ++i) {
1274 item_spr[i] = Z_getspr("MEGA", i - 22, 0, item_sprd + i);
1276 for (; i < 30; ++i) {
1277 item_spr[i] = Z_getspr("PINV", i - 26, 0, item_sprd + i);
1279 item_spr[30] = Z_getspr("AQUA", 0, 0, item_sprd + 30);
1280 item_spr[31] = Z_getspr("KEYR", 0, 0, item_sprd + 31);
1281 item_spr[32] = Z_getspr("KEYG", 0, 0, item_sprd + 32);
1282 item_spr[33] = Z_getspr("KEYB", 0, 0, item_sprd + 33);
1283 item_spr[34] = Z_getspr("SUIT", 0, 0, item_sprd + 34);
1284 for (n = 35, j = 0; j < 4; ++j) {
1285 for (i = 0; i < 4; ++i, ++n) {
1286 item_spr[n] = Z_getspr(n4[j], i, 0, item_sprd + n);
1289 for (j = 0; j < 2; ++j) {
1290 for (i = 0; i < 3; ++i, ++n) {
1291 item_spr[n] = Z_getspr(n3[j], i, 0, item_sprd + n);
1294 item_spr[57] = Z_getspr("GUN2", 0, 0, item_sprd + 57);
1295 // player
1296 for (i = 0; i < 27; ++i) {
1297 plr_spr[i * 2] = Z_getspr("PLAY", i, 1, plr_sprd + i * 2);
1298 plr_spr[i * 2 + 1] = Z_getspr("PLAY", i, 2, plr_sprd + i * 2 + 1);
1300 strncpy(s, "PWPx", 4);
1301 for (i = 1; i < 11; ++i) {
1302 s[3] = (i < 10 ? '0' : 'A' - 10) + i;
1303 for (j = 0; j < 6; ++j) {
1304 plr_wpn[i][j] = Z_getspr(s, j, 1, NULL);
1307 // monsters
1308 static char msn[MN_TN][4] = {
1309 "SARG", "TROO", "POSS", "SPOS", "CYBR", "CPOS", "BOSS", "BOS2", "HEAD", "SKUL",
1310 "PAIN", "SPID", "BSPI", "FATT", "SKEL", "VILE", "FISH", "BAR1", "ROBO", "PLAY"
1311 };
1312 static int mms[MN_TN] = {
1313 14*2, 21*2, 21*2, 21*2, 16*2, 20*2, 15*2, 15*2, 12*2, 11*2, 13*2, 19*2, 16*2,
1314 20*2, 17*2, 29*2, 6*2, 2*2, 17*2, 23*2
1315 };
1316 mn_sgun[0] = Z_getspr("PWP4", 0, 1, NULL);
1317 mn_sgun[1] = Z_getspr("PWP4", 1, 1, NULL);
1318 for (j = 0; j < MN_TN; ++j) {
1319 for (i = 0; i < mms[j]; ++i) {
1320 mn_spr[j][i] = Z_getspr(msn[j], i / 2, (i & 1) + 1, &mn_sprd[j][i]);
1322 if (j == MN_BARREL - 1) {
1323 for (i = 4; i < 14; ++i) {
1324 mn_spr[j][i] = Z_getspr("BEXP", i / 2 - 2, (i & 1) + 1, &mn_sprd[j][i]);
1328 for (i = 0; i < 8; ++i) {
1329 mn_fspr[i] = Z_getspr("FIRE", i, 0, NULL);
1331 pl_spr[0] = Z_getspr("PLAY", 'N' - 'A', 0, NULL);
1332 pl_spr[1] = Z_getspr("PLAY", 'W' - 'A', 0, NULL);
1333 // misc
1334 static char mnm[22][8]={
1335 "STTNUM0","STTNUM1","STTNUM2","STTNUM3","STTNUM4",
1336 "STTNUM5","STTNUM6","STTNUM7","STTNUM8","STTNUM9",
1337 "STTMINUS","STTPRCNT",
1338 "FISTA0","CSAWA0","PISTA0","SHOTA0","SGN2A0","MGUNA0","LAUNA0",
1339 "PLASA0","BFUGA0","GUN2A0"
1340 };
1341 stone=V_loadvgaimg("STONE");
1342 stone2=V_loadvgaimg("STONE2");
1343 keys[0]=V_loadvgaimg("KEYRA0");
1344 keys[1]=V_loadvgaimg("KEYGA0");
1345 keys[2]=V_loadvgaimg("KEYBA0");
1346 for (i = 0; i < 22; ++i) {
1347 sth[i] = V_loadvgaimg(mnm[i]);
1349 strcpy(s, "STBF_*");
1350 for (i = '!'; i < 160; ++i) {
1351 s[5] = i;
1352 bfh[i - '!'] = V_getvgaimg(F_findres(s));
1354 for (i = '!'; i < 160; ++i) {
1355 sprintf(s, "STCFN%03d", i);
1356 sfh[i - '!'] = V_getvgaimg(F_findres(s));
1358 strcpy(s, "WINUM*");
1359 for (i = '0'; i <= '9'; ++i) {
1360 s[5] = i;
1361 bfh[i - '!'] = V_loadvgaimg(s);
1363 bfh[':' - '!'] = V_loadvgaimg("WICOLON");
1364 // menu
1365 msklh[0] = V_loadvgaimg("M_SKULL1");
1366 msklh[1] = V_loadvgaimg("M_SKULL2");
1367 mbarl = V_loadvgaimg("M_THERML");
1368 mbarm = V_loadvgaimg("M_THERMM");
1369 mbarr = V_loadvgaimg("M_THERMR");
1370 mbaro = V_loadvgaimg("M_THERMO");
1371 mslotl = V_loadvgaimg("M_LSLEFT");
1372 mslotm = V_loadvgaimg("M_LSCNTR");
1373 mslotr = V_loadvgaimg("M_LSRGHT");
1374 // walls
1375 static char *anm[ANIT - 1][5] = {
1376 {"WALL22_1", "WALL23_1", "WALL23_2", NULL, NULL},
1377 {"WALL58_1", "WALL58_2", "WALL58_3", NULL, NULL},
1378 {"W73A_1", "W73A_2", NULL, NULL, NULL},
1379 {"RP2_1", "RP2_2", "RP2_3", "RP2_4", NULL}
1380 };
1381 for (i = 1; i < ANIT; i++) {
1382 for (j = 0; anm[i - 1][j]; j++) {
1383 anih[i][j] = F_getresid(anm[i - 1][j]);
1385 for(; j < 5; j++) {
1386 anih[i][j] = -1;
1391 void R_get_name (int n, char s[8]) {
1392 if (walh[n] == -1) {
1393 memset(s, 0, 8);
1394 } else if (walh[n] == -2) {
1395 memcpy(s, "_WATER_", 8);
1396 s[7] = (char)((intptr_t)walp[n] - 1 + '0');
1397 } else {
1398 F_getresname(s, walh[n] & 0x7FFF);
1402 static short getani (char n[8]) {
1403 if (cp866_strncasecmp(n, "WALL22_1", 8) == 0) {
1404 return 1;
1405 } else if (cp866_strncasecmp(n, "WALL58_1", 8) == 0) {
1406 return 2;
1407 } else if (cp866_strncasecmp(n, "W73A_1", 8) == 0) {
1408 return 3;
1409 } else if (cp866_strncasecmp(n, "RP2_1", 8) == 0) {
1410 return 4;
1411 } else {
1412 return 0;
1416 int R_get_special_id (int n) {
1417 assert(n >= 0 && n < 256);
1418 intptr_t x = (intptr_t)walp[n];
1419 return x >= 0 && x <= 3 ? x : -1;
1422 void R_begin_load (void) {
1423 int i;
1424 for (i = 0; i < 256; i++) {
1425 if (walp[i] != NULL && walh[i] >= 0) {
1426 M_unlock(walp[i]);
1428 walh[i] = -1;
1429 walp[i] = NULL;
1430 walswp[i] = i;
1431 walani[i] = 0;
1433 memset(anic, 0, sizeof(anic));
1434 max_textures = 1;
1437 void R_load (char s[8]) {
1438 assert(max_textures < 256);
1439 if (!s[0]) {
1440 walh[max_textures] = -1;
1441 walp[max_textures] = NULL;
1442 } else {
1443 if (cp866_strncasecmp(s, "_WATER_", 7) == 0) {
1444 walh[max_textures] = -2;
1445 walp[max_textures] = (void*)((intptr_t)s[7] - '0' + 1);
1446 } else {
1447 walh[max_textures] = F_getresid(s);
1448 walp[max_textures] = V_getvgaimg(walh[max_textures]);
1449 if (s[0] == 'S' && s[1] == 'W' && s[4] == '_') {
1450 walswp[max_textures] = 0;
1453 walani[max_textures] = getani(s);
1455 max_textures++;
1458 void R_end_load (void) {
1459 int i, j, k, g;
1460 char s[8];
1461 j = max_textures;
1462 for (i = 1; i < 256 && j < 256; i++) {
1463 if (walswp[i] == 0) {
1464 R_get_name(i, s);
1465 s[5] ^= 1;
1466 g = F_getresid(s);
1467 k = 1;
1468 while (k < 256 && walh[k] != g) {
1469 k += 1;
1471 if (k >= 256) {
1472 k = j;
1473 j += 1;
1474 walh[k] = g;
1475 walp[k] = V_getvgaimg(g);
1476 walf[k] = walf[i];
1478 walswp[i] = k;
1479 walswp[k] = i;
1484 void R_loadsky (int sky) {
1485 char s[6];
1486 strcpy(s, "RSKY1");
1487 s[4] = '0' + sky;
1488 M_unlock(horiz);
1489 horiz = V_loadvgaimg(s);
1492 void R_setgamma(int g) {
1493 int t;
1494 g = g < 0 ? 0 : (g > 4 ? 4 : g);
1495 gammaa = g;
1496 for (t = 0; t < 256; ++t) {
1497 std_pal[t][0] = gamcor[gammaa][main_pal[t].r];
1498 std_pal[t][1] = gamcor[gammaa][main_pal[t].g];
1499 std_pal[t][2] = gamcor[gammaa][main_pal[t].b];
1501 Y_set_vga_palette(&std_pal[0][0]);
1504 int R_getgamma (void) {
1505 return gammaa;
1508 void R_set_videomode (int w, int h, int fullscreen) {
1509 assert(w > 0);
1510 assert(h > 0);
1511 int was = Y_videomode_setted();
1512 int res = Y_set_videomode_software(w, h, fullscreen);
1513 if (res == 0) {
1514 if (was == 0) {
1515 ERR_failinit("Unable to set video mode");
1517 } else {
1518 Y_get_videomode(&SCRW, &SCRH);
1519 V_update_buffer();
1520 R_setgamma(gammaa);
1524 void R_toggle_fullscreen (void) {
1525 Y_set_fullscreen(!Y_get_fullscreen());
1526 fullscreen = Y_get_fullscreen();
1527 Y_get_videomode(&SCRW, &SCRH);
1528 V_update_buffer();
1529 R_setgamma(gammaa);
1532 static int video_menu_handler (menu_msg_t *msg, const menu_t *m, int i) {
1533 static int cur;
1534 static int w, h, fullscreen;
1535 static char buf[16];
1536 static int buflen;
1537 static int vmode;
1538 const videomode_t *v;
1539 enum { VIDEOMODE, FULLSCREEN, APPLY, __NUM__ };
1540 static const simple_menu_t sm = {
1541 GM_BIG, "Video", NULL,
1543 { "Mode: ", NULL },
1544 { "Fullscreen: ", NULL },
1545 { "Apply ", NULL },
1547 };
1548 if (msg->type == GM_ENTER) {
1549 Y_get_videomode(&w, &h);
1550 fullscreen = Y_get_fullscreen();
1551 v = Y_get_videomode_list_opengl(fullscreen);
1552 vmode = 0;
1553 while (vmode < v->n && v->modes[vmode].w != w && v->modes[vmode].h != h) {
1554 vmode += 1;
1556 if (vmode < v->n) {
1557 w = v->modes[vmode].w;
1558 h = v->modes[vmode].h;
1560 snprintf(buf, 16, "%ix%i", w, h);
1561 buflen = strlen(buf);
1562 return 1;
1564 if (i == VIDEOMODE) {
1565 switch (msg->type) {
1566 case GM_GETSTR: return GM_init_str(msg, buf, buflen);
1567 case GM_SELECT:
1568 v = Y_get_videomode_list_opengl(fullscreen);
1569 vmode = vmode + 1 >= v->n ? 0 : vmode + 1;
1570 if (v->n > 0) {
1571 w = v->modes[vmode].w;
1572 h = v->modes[vmode].h;
1573 } else {
1574 Y_get_videomode(&w, &h);
1576 snprintf(buf, 16, "%ix%i", w, h);
1577 buflen = strlen(buf);
1578 return 1;
1580 } else if (i == FULLSCREEN) {
1581 switch (msg->type) {
1582 case GM_GETSTR: return GM_init_str(msg, fullscreen ? "Yes" : "No ", 3);
1583 case GM_SELECT: fullscreen = !fullscreen; return 1;
1585 } else if (i == APPLY) {
1586 switch (msg->type) {
1587 case GM_SELECT: R_set_videomode(w, h, fullscreen); return 1;
1590 return simple_menu_handler(msg, i, __NUM__, &sm, &cur);
1593 const menu_t *R_menu (void) {
1594 static const menu_t m = { video_menu_handler };
1595 return &m;
1598 const cfg_t *R_args (void) {
1599 static const cfg_t args[] = {
1600 { "fullscr", &init_screen_full, Y_SW_ON },
1601 { "window", &init_screen_full, Y_SW_OFF },
1602 { "width", &init_screen_width, Y_DWORD },
1603 { "height", &init_screen_height, Y_DWORD },
1604 { "gamma", &init_screen_gammaa, Y_DWORD },
1605 { NULL, NULL, 0 } // end
1606 };
1607 return args;
1610 const cfg_t *R_conf (void) {
1611 static const cfg_t conf[] = {
1612 { "sky", &w_horiz, Y_SW_ON },
1613 { "fullscreen", &fullscreen, Y_SW_ON },
1614 { "screen_width", &SCRW, Y_DWORD },
1615 { "screen_height", &SCRH, Y_DWORD },
1616 { "gamma", &gammaa, Y_DWORD },
1617 { NULL, NULL, 0 } // end
1618 };
1619 return conf;
1622 static void *R_load_fixed (char *name, int size) {
1623 int id = F_getresid(name);
1624 if (F_getreslen(id) < size) {
1625 ERR_fatal("invalid %s (%i)", name, F_getreslen(id));
1627 return M_lock(id);
1630 void R_init () {
1631 int i;
1632 logo("R_init: initialize software render\n");
1633 main_pal = R_load_fixed("PLAYPAL", 256 * 3);
1634 clrmap = R_load_fixed("COLORMAP", 256 * 12);
1635 mixmap = R_load_fixed("MIXMAP", 256 * 256);
1636 for (i = 0; i < 256; ++i) {
1637 bright[i] = ((int)main_pal[i].r + main_pal[i].g + main_pal[i].b) * 8 / (63 * 3);
1639 SCRW = init_screen_width > 0 ? init_screen_width : SCRW;
1640 SCRH = init_screen_height > 0 ? init_screen_height : SCRH;
1641 fullscreen = init_screen_full != 0xFF ? init_screen_full : fullscreen;
1642 gammaa = init_screen_gammaa >= 0 ? init_screen_gammaa : gammaa;
1643 R_set_videomode(SCRW, SCRH, fullscreen);
1644 V_setrect(0, SCRW, 0, SCRH);
1645 V_clr(0, SCRW, 0, SCRH, 0);
1646 R_alloc();
1649 void R_done (void) {
1650 buffer = NULL;
1651 buf_w = 0;
1652 buf_h = 0;
1653 pitch = 0;
1654 Y_unset_videomode();
1657 void R_switch_texture (int x, int y) {
1658 assert(x >= 0 && x < FLDW);
1659 assert(y >= 0 && y < FLDH);
1660 fldb[y][x] = walswp[fldb[y][x]];
1663 int R_get_swp (int n) {
1664 assert(n >= 0 && n < 256);
1665 return walswp[n];