DEADSOFTWARE

c77709c66877c74594ab98b5073b0bf0e66a8069
[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 <string.h>
19 #include <stdarg.h>
20 #include <stdlib.h> // abs()
21 #include <assert.h>
22 #include "glob.h"
23 #include "render.h"
24 #include "view.h"
25 #include "player.h"
26 #include "switch.h"
27 #include "vga.h"
28 #include "menu.h"
29 #include "misc.h"
30 #include "dots.h"
31 #include "items.h"
32 #include "monster.h"
33 #include "weapons.h"
34 #include "smoke.h"
35 #include "fx.h"
36 #include "memory.h"
37 #include "files.h"
38 #include "error.h"
39 #include "game.h"
40 #include "sound.h"
41 #include "music.h"
42 #include "system.h"
44 #include "cp866.h"
46 // game
47 static vgaimg *scrnh[3]; // TITLEPIC INTERPIC ENDPIC
48 static vgaimg *ltn[2][2];
49 static void *cd_scr;
50 // smoke
51 static vgaimg *smk_spr[SMSN];
52 static vgaimg *smk_fspr[FLSN];
53 // fx
54 static vgaimg *fx_spr[15];
55 static char fx_sprd[15];
56 // weapons
57 static vgaimg *wp_spr[49*2];
58 static char wp_sprd[49*2];
59 // items
60 static vgaimg *item_spr[58];
61 static char item_sprd[58];
62 // player
63 static vgaimg *plr_spr[27*2];
64 static char plr_sprd[27*2];
65 static vgaimg *plr_wpn[11][6];
66 // monsters
67 static vgaimg *pl_spr[2];
68 static vgaimg *mn_spr[MN_TN][29*2];
69 static char mn_sprd[MN_TN][29*2];
70 static vgaimg *mn_fspr[8];
71 static vgaimg *mn_sgun[2];
72 // misc
73 #define MAXAIR 1091
74 static vgaimg *sth[22], *bfh[160 - '!'], *sfh[160 - '!'], *stone, *stone2, *keys[3];
75 static int prx = 0, pry = 0;
76 // menu
77 static vgaimg *msklh[2], *mbarl, *mbarm, *mbarr, *mbaro, *mslotl, *mslotm, *mslotr;
78 // low level
79 static int gammaa = 0;
80 static char main_pal[256][3];
81 static char std_pal[256][3];
82 static byte gamcor[5][64]={
83 #include "gamma.dat"
84 };
85 // walls
86 #define ANIT 5
87 static int WD, HT;
88 static int w_o, w_x, w_y;
89 static vgaimg *walp[256];
90 static int walh[256];
91 static byte walani[256];
92 static byte walswp[256];
93 static int anih[ANIT][5];
94 static byte anic[ANIT];
95 static int max_textures;
96 static byte w_horiz = 1;
97 static vgaimg *horiz;
99 static int init_screen_width = 0;
100 static int init_screen_height = 0;
101 static byte init_screen_full = 0xFF;
102 static int init_screen_gammaa = -1;
104 /* --- misc --- */
106 static void *Z_getspr (char n[4], int s, int d, char *dir) {
107 int h = F_getsprid(n, s, d, dir);
108 return V_getvgaimg(h);
111 static vgaimg *Z_get_char_image (vgaimg **img, int ch) {
112 ch = cp866_toupper(ch);
113 return ch > 32 && ch < 160 ? img[ch - '!'] : NULL;
116 static int Z_get_char_width_generic (vgaimg **img, int off, int ch) {
117 vgaimg *p = Z_get_char_image(img, ch);
118 return p == NULL ? off : p->w - 1;
121 static int Z_putch_generic (vgaimg **img, int off, int ch) {
122 vgaimg *p = Z_get_char_image(img, ch);
123 int w = p == NULL ? off : p->w - 1;
124 if (p != NULL) {
125 V_spr(prx, pry, p);
127 prx += w;
128 return w;
131 static int Z_get_string_width_generic (vgaimg **img, int off, const char *fmt, va_list ap) {
132 int i, w, ww;
133 char buf[80];
134 vsprintf(buf, fmt, ap);
135 for (i = w = ww = 0; buf[i]; ++i) {
136 switch (buf[i]) {
137 case '\n':
138 case '\r':
139 ww = max(w, ww);
140 w = 0;
141 break;
142 default:
143 w += Z_get_char_width_generic(img, off, (byte)buf[i]);
146 return max(w, ww);
149 static int Z_printf_generic (vgaimg **img, int off, const char *fmt, va_list ap) {
150 int i, w, ww;
151 char buf[80];
152 vsprintf(buf, fmt, ap);
153 for (i = w = ww = 0; buf[i]; ++i) {
154 switch (buf[i]) {
155 case '\n':
156 pry += off + 1;
157 case '\r':
158 w = max(w, ww);
159 prx = 0;
160 w = 0;
161 break;
162 default:
163 w += Z_putch_generic(img, off, (byte)buf[i]);
166 return w;
169 static void Z_gotoxy (int x, int y) {
170 prx = x;
171 pry = y;
174 static int Z_get_big_string_width (const char *fmt, ...) {
175 va_list a;
176 va_start(a, fmt);
177 int w = Z_get_string_width_generic(bfh, 12, fmt, a);
178 va_end(a);
179 return w;
182 static int Z_printbf (const char *fmt, ...) {
183 va_list a;
184 va_start(a, fmt);
185 int w = Z_printf_generic(bfh, 12, fmt, a);
186 va_end(a);
187 return w;
190 static int Z_get_small_string_width (const char *fmt, ...) {
191 va_list a;
192 va_start(a, fmt);
193 int w = Z_get_string_width_generic(sfh, 7, fmt, a);
194 va_end(a);
195 return w;
198 static int Z_printsf (const char *fmt, ...) {
199 va_list a;
200 va_start(a, fmt);
201 int w =Z_printf_generic(sfh, 7, fmt, a);
202 va_end(a);
203 return w;
206 static void Z_drawspr (int x, int y, void *p, char d) {
207 if (d) {
208 V_spr2(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p);
209 } else {
210 V_spr(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p);
214 static void Z_clrst (void) {
215 V_pic(SCRW - 120, w_o, stone);
216 int y = ((vgaimg*)stone)->h;
217 while (y < HT) {
218 V_pic(SCRW - 120, w_o + y, stone2);
219 y += ((vgaimg*)stone)->h;
223 static void Z_drawstlives (char n) {
224 V_setrect(SCRW - 40, 30, w_o, 40);
225 V_spr(SCRW - 35, w_o + 17, sth[n]);
228 static void Z_drawstkeys (byte k) {
229 int x, n;
230 V_setrect(SCRW - 120, 70, w_o + 77, 23);
231 for (k >>= 4, n = 0, x = SCRW - 75; n < 3; ++n, k >>= 1, x += 9) {
232 if (k & 1) {
233 V_spr(x, w_o + 91, keys[n]);
238 static void Z_drawstair (int a) {
239 V_setrect(SCRW - 120, 120, w_o + 49, 2);
240 if (a > 0) {
241 if (a > MAXAIR) {
242 a = MAXAIR;
244 a = a * 100 / MAXAIR;
245 V_clr(SCRW - 110, a, w_o + 49, 2, 0xC8);
249 static void Z_drawstprcnt (int y, int n) {
250 char s[20];
251 int l, i, x, c;
252 V_setrect(SCRW - 120, 70, y * 19 + 7 + w_o, 19);
253 sprintf(s, "%3d%%", n);
254 l = strlen(s);
255 x = SCRW - 110;
256 for (i = 0; i < l; ++i, x += 14) {
257 if (s[i] >='0' && s[i] <= '9') {
258 c = s[i] - '0';
259 } else if (s[i] == '-') {
260 c = 10;
261 } else if (s[i] == '%') {
262 c = 11;
263 } else {
264 c = -1;
266 if (c >= 0) {
267 V_spr(x, y * 19 + 7 + w_o, sth[c]);
272 static void Z_drawstnum (int n) {
273 char s[20];
274 int l, i, x, c;
275 V_setrect(SCRW - 50, 50, w_o + 77, 23);
276 if (g_dm) {
277 sprintf(s, "%d", n);
278 l = strlen(s);
279 x = (115 - l * 14) + SCRW - 120;
280 for (i = 0; i < l; ++i, x += 14) {
281 if (s[i] >= '0' && s[i] <= '9') {
282 c = s[i] - '0';
283 } else if (s[i] == '-') {
284 c = 10;
285 } else if(s[i] == '%') {
286 c = 11;
287 } else {
288 c =- 1;
290 if (c >= 0) {
291 V_spr(x, w_o + 77 + 5, sth[c]);
297 static void Z_drawstwpn (int n, int a) {
298 char s[20];
299 int l, i, x, c;
300 i = n;
301 V_setrect(SCRW - 120, 120, w_o + 58, 23);
302 if (i >= 0) {
303 V_spr(SCRW - 88, w_o + 58 + 19, sth[i + 12]);
305 if (n >= 2) {
306 sprintf(s, "%d", a);
307 l = strlen(s);
308 x = SCRW - 10 - l * 14;
309 for (i = 0; i < l; ++i, x += 14) {
310 if (s[i] >= '0' && s[i] <= '9') {
311 c = s[i] - '0';
312 } else if (s[i] == '-') {
313 c = 10;
314 } else if (s[i] == '%') {
315 c = 11;
316 } else {
317 c = -1;
319 if (c >= 0) {
320 V_spr(x, w_o + 58 + 2, sth[c]);
326 static void Z_drawmanspr (int x, int y, void *p, char d, byte color) {
327 if (d) {
328 V_manspr2(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p, color);
329 } else {
330 V_manspr(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p, color);
334 static void Z_drawfld (byte *fld, int bg) {
335 byte *p = fld;
336 int x, y;
337 for (y = 0; y < FLDH; y++) {
338 for (x = 0; x < FLDW; x++) {
339 int sx = x * CELW - w_x + WD / 2;
340 int sy = y * CELH - w_y + HT / 2 + 1 + w_o;
341 int id = *p;
342 if (id) {
343 //intptr_t spc = (intptr_t) walp[id];
344 int spc = R_get_special_id(id);
345 if (spc >= 0 && spc <= 3) {
346 if (!bg) {
347 byte *cmap = clrmap + (spc + 7) * 256;
348 V_remap_rect(sx, sy, CELW, CELH, cmap);
350 } else {
351 V_pic(sx, sy, walp[id]);
354 p++;
359 /* --- menu --- */
361 static int gm_tm = 0; // ???
363 #define SCROLLER_MIDDLE 10
364 #define TEXTFIELD_MIDDLE 2
366 static void get_entry_size (const menu_t *m, int i, int *w, int *h) {
367 assert(m != NULL);
368 assert(i >= 0);
369 assert(w != NULL);
370 assert(h != NULL);
371 int x = 0;
372 int y = 0;
373 int type = 0;
374 menu_msg_t msg;
375 msg.type = GM_GETENTRY;
376 if (GM_send(m, i, &msg)) {
377 type = msg.integer.i;
378 switch (type) {
379 case GM_BUTTON:
380 case GM_SCROLLER:
381 case GM_TEXTFIELD:
382 case GM_TEXTFIELD_BUTTON:
383 msg.type = GM_GETCAPTION;
384 if (GM_send(m, i, &msg)) {
385 x = Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
387 break;
388 case GM_SMALL_BUTTON:
389 msg.type = GM_GETCAPTION;
390 if (GM_send(m, i, &msg)) {
391 x = Z_get_small_string_width("%.*s", msg.string.maxlen, msg.string.s);
393 break;
394 default:
395 assert(0);
397 switch (type) {
398 case GM_BUTTON:
399 msg.type = GM_GETSTR;
400 if (GM_send(m, i, &msg)) {
401 x += Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
403 y = 16;
404 break;
405 case GM_SMALL_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 = 12;
411 break;
412 case GM_SCROLLER:
413 x += (SCROLLER_MIDDLE + 2) * 8;
414 y = 16;
415 break;
416 case GM_TEXTFIELD:
417 case GM_TEXTFIELD_BUTTON:
418 msg.type = GM_GETSTR;
419 if (GM_send(m, i, &msg)) {
420 x += (msg.string.maxlen + 2) * 8;
421 } else {
422 x += (TEXTFIELD_MIDDLE + 2) * 8;
424 y = 16;
425 break;
426 default:
427 assert(0);
430 *w = x;
431 *h = y;
434 static void get_menu_size (const menu_t *m, int *w, int *h) {
435 assert(m != NULL);
436 assert(w != NULL);
437 assert(h != NULL);
438 int i, n, x, y, xx, yy, type;
439 menu_msg_t msg;
440 msg.type = GM_QUERY;
441 if (GM_send_this(m, &msg)) {
442 n = msg.integer.b;
443 type = msg.integer.s;
444 x = 0;
445 y = 0;
446 msg.type = GM_GETTITLE;
447 if (GM_send_this(m, &msg)) {
448 switch (type) {
449 case GM_BIG: x = Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s); break;
450 case GM_SMALL: x = Z_get_small_string_width("%.*s", msg.string.maxlen, msg.string.s); break;
451 default: assert(0);
454 for (i = 0; i < n; i++) {
455 get_entry_size(m, i, &xx, &yy);
456 x = max(x, xx);
457 y += yy;
459 *w = x;
460 *h = y;
461 } else {
462 *w = 0;
463 *h = 0;
467 static int GM_draw (void) {
468 int i, j, n, x, y, xoff, yoff, cur, w, type, recv;
469 const menu_t *m = GM_get();
470 menu_msg_t msg;
471 if (m != NULL) {
472 get_menu_size(m, &x, &y);
473 x = SCRW / 2 - x / 2;
474 y = SCRH / 2 - y / 2;
475 // --- title ---
476 msg.type = GM_QUERY;
477 if (GM_send_this(m, &msg)) {
478 cur = msg.integer.i;
479 n = msg.integer.a;
480 type = msg.integer.s;
481 msg.type = GM_GETTITLE;
482 if (GM_send_this(m, &msg)) {
483 Z_gotoxy(x, y - 10);
484 switch (type) {
485 case GM_SMALL: yoff = 8; Z_printsf("%.*s", msg.string.maxlen, msg.string.s); break;
486 case GM_BIG: yoff = 20; Z_printbf("%.*s", msg.string.maxlen, msg.string.s); break;
487 default: assert(0);
489 } else {
490 yoff = 0;
492 for (i = 0; i < n; i++) {
493 msg.type = GM_GETENTRY;
494 if (GM_send(m, i, &msg)) {
495 type = msg.integer.i;
496 if (i == cur) {
497 if (type == GM_SMALL_BUTTON) {
498 Z_gotoxy(x - 8, y + yoff);
499 Z_printsf(">");
500 } else {
501 V_spr(x - 25, y + yoff - 8, msklh[(gm_tm / 6) & 1]);
504 msg.type = GM_GETCAPTION;
505 if (GM_send(m, i, &msg)) {
506 Z_gotoxy(x, y + yoff);
507 if (type == GM_SMALL_BUTTON) {
508 xoff = Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
509 } else {
510 xoff = Z_printbf("%.*s", msg.string.maxlen, msg.string.s);
512 } else {
513 xoff = 0;
515 switch (type) {
516 case GM_BUTTON:
517 case GM_SMALL_BUTTON:
518 msg.type = GM_GETSTR;
519 if (GM_send(m, i, &msg)) {
520 Z_gotoxy(x + xoff, y + yoff);
521 if (type == GM_SMALL_BUTTON) {
522 Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
523 } else {
524 Z_printbf("%.*s", msg.string.maxlen, msg.string.s);
527 yoff += type == GM_BUTTON ? 16 : 12;
528 break;
529 case GM_TEXTFIELD:
530 case GM_TEXTFIELD_BUTTON:
531 yoff += 9;
532 msg.type = GM_GETSTR;
533 recv = GM_send(m, i, &msg);
534 w = recv ? msg.string.maxlen : TEXTFIELD_MIDDLE;
535 V_spr(x + xoff, y + yoff, mslotl);
536 for (j = 1; j <= w; j++) {
537 V_spr(x + xoff + j * 8, y + yoff, mslotm);
539 V_spr(x + xoff + j * 8, y + yoff, mslotr);
540 Z_gotoxy(x + xoff + 4, y + yoff - 7);
541 if (input && i == cur) {
542 Z_printsf("%.*s_", imax, ibuf);
543 } else if (recv) {
544 Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
546 yoff += 7;
547 break;
548 case GM_SCROLLER:
549 V_spr(x + xoff, y + yoff, mbarl);
550 for (j = 1; j < SCROLLER_MIDDLE; j++) {
551 V_spr(x + xoff + j * 8, y + yoff, mbarm);
553 V_spr(x + xoff + j * 8, y + yoff, mbarr);
554 msg.type = GM_GETINT;
555 if (GM_send(m, i, &msg)) {
556 int lev = (msg.integer.i - msg.integer.a) * ((SCROLLER_MIDDLE - 2) * 8) / msg.integer.b;
557 V_spr(x + xoff + lev + 8, y + yoff, mbaro);
559 yoff += 16;
560 break;
561 default:
562 assert(0);
568 return m != NULL;
571 /* --- dots --- */
573 static void DOT_draw (void) {
574 int i;
575 for (i = 0; i < MAXDOT; i++) {
576 if (dot[i].t) {
577 V_dot(dot[i].o.x - w_x + WD / 2, dot[i].o.y - w_y + HT / 2 + 1 + w_o, dot[i].c);
582 /* --- items --- */
584 static void IT_draw (void) {
585 int i, s;
586 for (i = 0; i < MAXITEM; ++i) {
587 s = -1;
588 if (it[i].t && it[i].s >= 0) {
589 switch(it[i].t & 0x7FFF) {
590 case I_ARM1:
591 s = it[i].s / 9 + 18;
592 break;
593 case I_ARM2:
594 s = it[i].s / 9 + 20;
595 break;
596 case I_MEGA:
597 s = it[i].s / 2 + 22;
598 break;
599 case I_INVL:
600 s = it[i].s / 2 + 26;
601 break;
602 case I_SUPER:
603 case I_RTORCH:
604 case I_GTORCH:
605 case I_BTORCH:
606 s = it[i].s / 2 + (it[i].t - I_SUPER) * 4 + 35;
607 break;
608 case I_GOR1: case I_FCAN:
609 s = it[i].s / 2 + (it[i].t - I_GOR1) * 3 + 51;
610 break;
611 case I_AQUA:
612 s = 30;
613 break;
614 case I_SUIT:
615 s = 34;
616 break;
617 case I_KEYR:
618 case I_KEYG:
619 case I_KEYB:
620 s = (it[i].t & 0x7FFF) - I_KEYR + 31;
621 break;
622 case I_GUN2:
623 s = 57;
624 break;
625 default:
626 s = (it[i].t & 0x7FFF) - 1;
629 if (s >= 0) {
630 Z_drawspr(it[i].o.x, it[i].o.y, item_spr[s], item_sprd[s]);
635 /* --- player --- */
637 static int standspr (player_t *p) {
638 if (p->f & PLF_UP) {
639 return 'X';
640 } else if (p->f & PLF_DOWN) {
641 return 'Z';
642 } else {
643 return 'E';
647 static int wpnspr (player_t *p) {
648 if (p->f & PLF_UP) {
649 return 'C';
650 } else if(p->f & PLF_DOWN) {
651 return 'E';
652 } else {
653 return 'A';
657 static void PL_draw (player_t *p) {
658 enum {STAND, GO, DIE, SLOP, DEAD, MESS, OUT, FALL}; // copypasted from player.c!
659 static int wytab[] = {-1, -2, -1, 0};
660 int s = 'A';
661 int w = 0;
662 int wx = 0;
663 int wy = 0;
664 switch (p->st) {
665 case STAND:
666 if (p->f & PLF_FIRE) {
667 s = standspr(p) + 1;
668 w = wpnspr(p) + 1;
669 } else if (p->pain) {
670 s = 'G';
671 w = 'A';
672 wx = p->d ? 2 : -2;
673 wy = 1;
674 } else {
675 s = standspr(p);
676 w = wpnspr(p);
678 break;
679 case DEAD:
680 s = 'N';
681 break;
682 case MESS:
683 s = 'W';
684 break;
685 case GO:
686 if (p->pain) {
687 s = 'G';
688 w = 'A';
689 wx = p->d ? 2 : -2;
690 wy = 1;
691 } else {
692 s = plr_goanim[p->s / 8];
693 w = (p->f & PLF_FIRE) ? 'B' : 'A';
694 wx = p->d ? 2 : -2;
695 wy = 1 + wytab[s - 'A'];
697 break;
698 case DIE:
699 s = plr_dieanim[p->s];
700 break;
701 case SLOP:
702 s = plr_slopanim[p->s];
703 break;
704 case OUT:
705 s = 0;
706 break;
708 if (p->wpn == 0) {
709 w = 0;
711 if (w) {
712 Z_drawspr(p->o.x + wx, p->o.y + wy, plr_wpn[p->wpn][w - 'A'], p->d);
714 if (s) {
715 Z_drawmanspr(p->o.x, p->o.y, plr_spr[(s - 'A') * 2 + p->d], plr_sprd[(s - 'A') * 2 + p->d], p->color);
719 static void PL_drawst (player_t *p) {
720 int i;
721 V_setrect(WD, 120, w_o, HT);
722 Z_clrst();
723 if (p->drawst & PL_DRAWAIR) {
724 if (p->air < PL_AIR) {
725 Z_drawstair(p->air);
728 if (p->drawst & PL_DRAWLIFE) {
729 Z_drawstprcnt(0, p->life);
731 if (p->drawst & PL_DRAWARMOR) {
732 Z_drawstprcnt(1, p->armor);
734 if (p->drawst & PL_DRAWWPN) {
735 switch(p->wpn) {
736 case 2:
737 case 5:
738 i = p->ammo;
739 break;
740 case 3:
741 case 4:
742 case 9:
743 i = p->shel;
744 break;
745 case 6:
746 i = p->rock;
747 break;
748 case 10:
749 i = p->fuel;
750 break;
751 case 7:
752 case 8:
753 i = p->cell;
754 break;
756 Z_drawstwpn(p->wpn, i);
758 if (p->drawst & PL_DRAWFRAG) {
759 Z_drawstnum(p->frag);
761 if (p->drawst & PL_DRAWKEYS) {
762 Z_drawstkeys(p->keys);
764 if (!_2pl) {
765 if (p->drawst & PL_DRAWLIVES) {
766 Z_drawstlives(p->lives);
771 /* --- monster --- */
773 #define MANCOLOR 0xD0
775 static void MN_draw (void) {
776 enum {SLEEP, GO, RUN, CLIMB, DIE, DEAD, ATTACK, SHOOT, PAIN, WAIT, REVIVE, RUNOUT}; // copypasted from monster.c!
777 int i;
778 for (i = 0; i < MAXMN; i++) {
779 if (mn[i].t) {
780 if (mn[i].t >= MN_PL_DEAD) {
781 Z_drawmanspr(mn[i].o.x, mn[i].o.y, pl_spr[mn[i].t - MN_PL_DEAD], 0, mn[i].d);
782 continue;
784 if ((mn[i].t != MN_SOUL && mn[i].t != MN_PAIN) || mn[i].st != DEAD) {
785 if (mn[i].t != MN_MAN) {
786 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]);
787 } else {
788 if (mn[i].ap[mn[i].ac] == 'E' || mn[i].ap[mn[i].ac] == 'F') {
789 Z_drawspr(mn[i].o.x, mn[i].o.y, mn_sgun[mn[i].ap[mn[i].ac] - 'E'], mn[i].d);
791 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);
794 if (mn[i].t == MN_VILE && mn[i].st == SHOOT) {
795 Z_drawspr(mn[i].tx, mn[i].ty, mn_fspr[mn[i].ac / 3], 0);
801 /* --- weapon --- */
803 static void WP_draw (void) {
804 enum {NONE, ROCKET, PLASMA, APLASMA, BALL1, BALL2, BALL7, BFGBALL, BFGHIT, MANF, REVF, FIRE}; // copypasted from weapons.c!
805 int i, s, d, x, y;
806 for (i = 0; i < MAXWPN; ++i) {
807 s = -1;
808 d = 0;
809 switch (wp[i].t) {
810 case NONE:
811 default:
812 break;
813 case REVF:
814 case ROCKET:
815 d = wp[i].s;
816 if (d < 2) {
817 d = wp[i].o.xv > 0 ? 1 : 0;
818 x = abs(wp[i].o.xv);
819 y = wp[i].o.yv;
820 s = 0;
821 if (y < 0) {
822 if (-y >= x) {
823 s = 30;
825 } else if (y > 0) {
826 if (y >= x / 2) {
827 s = 31;
830 } else {
831 s = (d - 2) / 2 + 1;
832 d = 0;
834 break;
835 case MANF:
836 s=wp[i].s;
837 if (s >= 2) {
838 s /= 2;
839 break;
841 case PLASMA:
842 case APLASMA:
843 case BALL1:
844 case BALL7:
845 case BALL2:
846 s = wp[i].s;
847 if (s >= 2) {
848 s = s / 2 + 1;
850 switch (wp[i].t) {
851 case PLASMA:
852 s += 4;
853 break;
854 case APLASMA:
855 s += 11;
856 break;
857 case BALL1:
858 s += 32;
859 break;
860 case BALL2:
861 s += 42;
862 break;
863 case BALL7:
864 s += 37;
865 d = wp[i].o.xv >= 0 ? 1 : 0;
866 break;
867 case MANF:
868 s += 47;
869 d= wp[i].o.xv>=0 ? 1 : 0;
870 break;
872 break;
873 case BFGBALL:
874 s = wp[i].s;
875 if (s >= 2) {
876 s = s / 2 + 1;
878 s += 18;
879 break;
880 case BFGHIT:
881 s = wp[i].s / 2 + 26;
882 break;
884 if (s >= 0) {
885 Z_drawspr(wp[i].o.x, wp[i].o.y, wp_spr[s * 2 + d], wp_sprd[s * 2 + d]);
890 /* --- smoke --- */
892 static void SMK_draw (void) {
893 int i, s;
894 for (i = 0; i < MAXSMOK; ++i) {
895 if (sm[i].t) {
896 switch (sm[i].s) {
897 case 0:
898 s = sm[i].t;
899 if (s >= (SMSN - 1) * 3) {
900 s = 0;
901 } else {
902 s = SMSN - 1 - s / 3;
904 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);
905 break;
906 case 1:
907 s = sm[i].t;
908 if (s >= FLSN - 1) {
909 s = 0;
910 } else {
911 s = FLSN - 1 - s;
913 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);
914 break;
920 /* --- fx --- */
922 static void FX_draw (void) {
923 enum {NONE, TFOG, IFOG, BUBL}; // copypasted from fx.c
924 int i, s;
925 for (i = 0; i < MAXFX; ++i) {
926 s = -1;
927 switch (fx[i].t) {
928 case TFOG:
929 s = fx[i].s / 2;
930 break;
931 case IFOG:
932 s = fx[i].s / 2 + 10;
933 break;
934 case BUBL:
935 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);
936 continue;
938 if (s >= 0) {
939 Z_drawspr(fx[i].x, fx[i].y, fx_spr[s], fx_sprd[s]);
944 /* --- view --- */
946 static void W_adjust (void) {
947 int MAXX = FLDW * CELW - WD / 2;
948 int MAXY = FLDH * CELH - HT / 2;
949 if (w_x < WD / 2) w_x = WD / 2;
950 if (w_y < HT / 2) w_y = HT / 2;
951 if (w_x > MAXX) w_x = MAXX;
952 if (w_y > MAXY) w_y = MAXY;
955 static void W_draw(void) {
956 W_adjust();
957 V_setrect(0, WD, w_o + 1, HT);
958 if (w_horiz) {
959 vgaimg *img = (vgaimg*)horiz;
960 int x = 0;
961 int d = 0;
962 do {
963 int y = w_o;
964 d &= ~2;
965 do {
966 V_rotspr(x, y, img, d);
967 y += img->h;
968 d ^= 2;
969 } while (y < HT + w_o);
970 x += img->w;
971 d ^= 1;
972 } while (x < WD);
973 if (sky_type == 2) {
974 if (lt_time < 0) {
975 if (!lt_side) {
976 V_spr(0, w_o + lt_ypos, ltn[lt_type][lt_time < -5 ? 0 : 1]);
977 } else {
978 V_spr2(WD - 1, w_o + lt_ypos, ltn[lt_type][lt_time < -5 ? 0 : 1]);
982 } else {
983 V_clr(0, WD, w_o + 1, HT, 0x97);
985 Z_drawfld((byte*)fldb, 1);
986 DOT_draw();
987 IT_draw();
988 PL_draw(&pl1);
989 if (_2pl) {
990 PL_draw(&pl2);
992 MN_draw();
993 WP_draw();
994 SMK_draw();
995 FX_draw();
996 Z_drawfld((byte*)fldf, 0);
997 if (sky_type == 2) {
998 if (lt_time == -4 || lt_time == -2) {
999 V_remap_rect(0, WD, w_o + 1, HT, clrmap + 256 * 11);
1004 /* --- game --- */
1006 #define PL_FLASH 90
1008 static void drawview (player_t *p) {
1009 if (p->looky < -SCRH / 4) {
1010 p->looky = -SCRH / 4;
1011 } else if (p->looky > SCRH / 4) {
1012 p->looky = SCRH / 4;
1014 w_x = p->o.x;
1015 w_y = p->o.y - 12 + p->looky;
1016 W_draw();
1017 PL_drawst(p);
1020 static int get_pu_st (int t) {
1021 if (t >= PL_FLASH) {
1022 return 1;
1023 } else if((t / 9) & 1) {
1024 return 0;
1025 } else {
1026 return 1;
1030 static void pl_info (player_t *p, int y) {
1031 dword t = p->kills * 10920 / g_time;
1032 Z_gotoxy(25, y); Z_printbf("KILLS");
1033 Z_gotoxy(25, y + 15); Z_printbf("KPM");
1034 Z_gotoxy(25, y + 30); Z_printbf("SECRETS %u / %u", p->secrets, sw_secrets);
1035 Z_gotoxy(255, y); Z_printbf("%u", p->kills);
1036 Z_gotoxy(255, y + 15); Z_printbf("%u.%u", t / 10, t % 10);
1039 static void W_act (void) {
1040 int i, a;
1041 if (g_time % 3 == 0) {
1042 for (i = 1; i < 256; i++) {
1043 a = walani[i];
1044 if (a != 0) {
1045 anic[a]++;
1046 if (anih[a][anic[a]] == -1) {
1047 anic[a] = 0;
1049 walp[i] = V_getvgaimg(anih[a][anic[a]]);
1055 void R_draw (void) {
1056 int h;
1057 word hr, mn, sc;
1058 W_act();
1059 switch (g_st) {
1060 case GS_ENDANIM:
1061 case GS_END2ANIM:
1062 case GS_DARKEN:
1063 case GS_BVIDEO:
1064 case GS_EVIDEO:
1065 case GS_END3ANIM:
1066 return;
1067 case GS_TITLE:
1068 V_center(1);
1069 V_pic(0, 0, scrnh[0]);
1070 V_center(0);
1071 break;
1072 case GS_ENDSCR:
1073 V_center(1);
1074 V_clr(0, SCRW, 0, SCRH, 0);
1075 V_pic(0, 0, scrnh[2]);
1076 V_center(0);
1077 break;
1078 case GS_INTER:
1079 V_center(1);
1080 V_clr(0, SCRW, 0, SCRH, 0);
1081 V_pic(0, 0, scrnh[1]);
1082 Z_gotoxy(60, 20);
1083 Z_printbf("LEVEL COMPLETE");
1084 Z_calc_time(g_time, &hr, &mn, &sc);
1085 Z_gotoxy(115, 40);
1086 Z_printbf("TIME %u:%02u:%02u", hr, mn, sc);
1087 h = 60;
1088 if (_2pl) {
1089 Z_gotoxy(80, h);
1090 Z_printbf("PLAYER ONE");
1091 Z_gotoxy(80, h + 70);
1092 Z_printbf("PLAYER TWO");
1093 h += SCRH / 10;
1095 pl_info(&pl1, h);
1096 if (_2pl) {
1097 pl_info(&pl2, h + 70);
1099 V_center(0);
1100 break;
1102 V_center(0);
1103 if (g_st == GS_GAME) {
1104 if (_2pl) {
1105 w_o = 0;
1106 WD = SCRW - 120;
1107 HT = SCRH / 2 - 2;
1108 drawview(&pl1);
1109 w_o = SCRH / 2;
1110 WD = SCRW - 120;
1111 HT = SCRH / 2 - 2;
1112 drawview(&pl2);
1113 } else{
1114 w_o = 0;
1115 WD = SCRW - 120;
1116 HT = SCRH - 2;
1117 drawview(&pl1);
1119 if (pl1.invl) {
1120 h = get_pu_st(pl1.invl) * 6;
1121 } else if (pl1.pain < 15) {
1122 h = 0;
1123 } else if (pl1.pain < 35) {
1124 h = 1;
1125 } else if (pl1.pain < 55) {
1126 h = 2;
1127 } else if (pl1.pain < 75) {
1128 h=3;
1129 } else if (pl1.pain < 95) {
1130 h=4;
1131 } else {
1132 h = 5;
1134 if (h != 0) {
1135 V_maptoscr(0, SCRW - 120, 1, _2pl ? SCRH / 2 - 2 : SCRH - 2, clrmap + h * 256);
1137 if (_2pl) {
1138 if (pl2.invl) {
1139 h = get_pu_st(pl2.invl) * 6;
1140 } else if (pl2.pain < 15) {
1141 h = 0;
1142 } else if (pl2.pain < 35) {
1143 h = 1;
1144 } else if (pl2.pain < 55) {
1145 h = 2;
1146 } else if (pl2.pain < 75) {
1147 h = 3;
1148 } else if (pl2.pain < 95) {
1149 h = 4;
1150 } else {
1151 h = 5;
1153 if (h) {
1154 V_maptoscr(0, SCRW - 120, SCRH / 2 + 1, SCRH / 2 - 2, clrmap + h * 256);
1158 V_center(0);
1159 V_setrect(0, SCRW, 0, SCRH);
1160 GM_draw();
1161 V_copytoscr(0, SCRW, 0, SCRH);
1164 void R_alloc (void) {
1165 int i, j, n;
1166 char s[10];
1167 logo("R_alloc: загрузка графики\n");
1168 // game
1169 scrnh[0] = V_loadvgaimg("TITLEPIC");
1170 scrnh[1] = V_loadvgaimg("INTERPIC");
1171 scrnh[2] = V_loadvgaimg("ENDPIC");
1172 cd_scr = M_lock(F_getresid("CD1PIC"));
1173 for (i = 0; i < 2; ++i) {
1174 sprintf(s, "LTN%c", i + '1');
1175 for (j = 0; j < 2; ++j) {
1176 ltn[i][j] = Z_getspr(s, j, 0, NULL);
1179 // smoke
1180 for (i = 0; i < SMSN; ++i) {
1181 smk_spr[i] = Z_getspr("SMOK", i, 0, NULL);
1183 for (i = 0; i < FLSN; ++i) {
1184 smk_fspr[i] = Z_getspr("FLAM", i, 0, NULL);
1186 // fx
1187 for (i = 0; i < 10; ++i) {
1188 fx_spr[i] = Z_getspr("TFOG", i, 0, fx_sprd + i);
1190 for (; i < 15; ++i) {
1191 fx_spr[i] = Z_getspr("IFOG", i - 10, 0, fx_sprd + i);
1193 // weapons
1194 for (i = 0; i < 4; ++i) {
1195 wp_spr[i * 2] = Z_getspr("MISL", i, 1, wp_sprd + i * 2);
1196 wp_spr[i * 2 + 1] = Z_getspr("MISL", i, 2, wp_sprd + i * 2 + 1);
1198 for (; i < 6; ++i) {
1199 wp_spr[i * 2] = Z_getspr("PLSS", i - 4, 1, wp_sprd + i * 2);
1200 wp_spr[i * 2 + 1] = Z_getspr("PLSS", i - 4, 2, wp_sprd + i * 2 + 1);
1202 for (; i < 11; ++i) {
1203 wp_spr[i * 2] = Z_getspr("PLSE", i - 6, 1, wp_sprd + i * 2);
1204 wp_spr[i * 2 + 1] = Z_getspr("PLSE", i - 6, 2, wp_sprd + i * 2 + 1);
1206 for (; i < 13; ++i) {
1207 wp_spr[i * 2] = Z_getspr("APLS", i - 11, 1, wp_sprd + i * 2);
1208 wp_spr[i * 2 + 1] = Z_getspr("APLS", i - 11, 2, wp_sprd + i * 2 + 1);
1210 for (; i < 18; ++i) {
1211 wp_spr[i * 2] = Z_getspr("APBX", i - 13, 1, wp_sprd + i * 2);
1212 wp_spr[i * 2 + 1] = Z_getspr("APBX", i - 13, 2, wp_sprd + i * 2 + 1);
1214 for(; i < 20; ++i) {
1215 wp_spr[i * 2] = Z_getspr("BFS1", i - 18, 1, wp_sprd + i * 2);
1216 wp_spr[i * 2 + 1] = Z_getspr("BFS1", i - 18, 2, wp_sprd + i * 2 + 1);
1218 for (; i < 26; ++i) {
1219 wp_spr[i * 2] = Z_getspr("BFE1", i - 20, 1, wp_sprd + i * 2);
1220 wp_spr[i * 2 + 1] = Z_getspr("BFE1", i - 20, 2, wp_sprd + i * 2 + 1);
1222 for (; i < 30; ++i) {
1223 wp_spr[i * 2] = Z_getspr("BFE2", i - 26, 1, wp_sprd + i * 2);
1224 wp_spr[i * 2 + 1] = Z_getspr("BFE2", i - 26, 2, wp_sprd + i * 2 + 1);
1226 for (; i < 32; ++i) {
1227 wp_spr[i * 2] = Z_getspr("MISL", i - 30 + 4, 1, wp_sprd + i * 2);
1228 wp_spr[i * 2 + 1] = Z_getspr("MISL", i - 30 + 4, 2, wp_sprd + i * 2 + 1);
1230 for (; i < 37; ++i) {
1231 wp_spr[i * 2] = Z_getspr("BAL1", i - 32, 1, wp_sprd + i * 2);
1232 wp_spr[i * 2 + 1] = Z_getspr("BAL1", i - 32, 2, wp_sprd + i * 2 + 1);
1234 for (; i < 42; ++i) {
1235 wp_spr[i * 2] = Z_getspr("BAL7", i - 37, 1, wp_sprd + i * 2);
1236 wp_spr[i * 2 + 1] = Z_getspr("BAL7", i - 37, 2, wp_sprd + i * 2 + 1);
1238 for (; i < 47; ++i) {
1239 wp_spr[i * 2] = Z_getspr("BAL2", i - 42, 1, wp_sprd + i * 2);
1240 wp_spr[i * 2 + 1] = Z_getspr("BAL2", i - 42, 2, wp_sprd + i * 2 + 1);
1242 for (; i < 49; ++i) {
1243 wp_spr[i * 2] = Z_getspr("MANF", i - 47, 1, wp_sprd + i * 2);
1244 wp_spr[i * 2 + 1] = Z_getspr("MANF", i - 47, 2, wp_sprd + i * 2 + 1);
1246 // items
1247 static char snm[18][4] = {
1248 "CLIP", "SHEL", "ROCK", "CELL", "AMMO", "SBOX", "BROK", "CELP",
1249 "STIM", "MEDI", "BPAK",
1250 "CSAW", "SHOT", "SGN2", "MGUN", "LAUN", "PLAS", "BFUG"
1251 };
1252 static char n4[4][4] = {
1253 "SOUL", "SMRT", "SMGT", "SMBT"
1254 };
1255 static char n3[2][4] = {
1256 "GOR1", "FCAN"
1257 };
1258 for (i = 0; i < 18; ++i) {
1259 item_spr[i] = Z_getspr(snm[i], 0, 0, item_sprd + i);
1261 for (; i < 20; ++i) {
1262 item_spr[i] = Z_getspr("ARM1", i - 18, 0, item_sprd + i);
1263 item_spr[i + 2] = Z_getspr("ARM2", i - 18, 0, item_sprd + i);
1265 i+=2;
1266 for (; i < 26; ++i) {
1267 item_spr[i] = Z_getspr("MEGA", i - 22, 0, item_sprd + i);
1269 for (; i < 30; ++i) {
1270 item_spr[i] = Z_getspr("PINV", i - 26, 0, item_sprd + i);
1272 item_spr[30] = Z_getspr("AQUA", 0, 0, item_sprd + 30);
1273 item_spr[31] = Z_getspr("KEYR", 0, 0, item_sprd + 31);
1274 item_spr[32] = Z_getspr("KEYG", 0, 0, item_sprd + 32);
1275 item_spr[33] = Z_getspr("KEYB", 0, 0, item_sprd + 33);
1276 item_spr[34] = Z_getspr("SUIT", 0, 0, item_sprd + 34);
1277 for (n = 35, j = 0; j < 4; ++j) {
1278 for (i = 0; i < 4; ++i, ++n) {
1279 item_spr[n] = Z_getspr(n4[j], i, 0, item_sprd + n);
1282 for (j = 0; j < 2; ++j) {
1283 for (i = 0; i < 3; ++i, ++n) {
1284 item_spr[n] = Z_getspr(n3[j], i, 0, item_sprd + n);
1287 item_spr[57] = Z_getspr("GUN2", 0, 0, item_sprd + 57);
1288 // player
1289 for (i = 0; i < 27; ++i) {
1290 plr_spr[i * 2] = Z_getspr("PLAY", i, 1, plr_sprd + i * 2);
1291 plr_spr[i * 2 + 1] = Z_getspr("PLAY", i, 2, plr_sprd + i * 2 + 1);
1293 strncpy(s, "PWPx", 4);
1294 for (i = 1; i < 11; ++i) {
1295 s[3] = (i < 10 ? '0' : 'A' - 10) + i;
1296 for (j = 0; j < 6; ++j) {
1297 plr_wpn[i][j] = Z_getspr(s, j, 1, NULL);
1300 // monsters
1301 static char msn[MN_TN][4] = {
1302 "SARG", "TROO", "POSS", "SPOS", "CYBR", "CPOS", "BOSS", "BOS2", "HEAD", "SKUL",
1303 "PAIN", "SPID", "BSPI", "FATT", "SKEL", "VILE", "FISH", "BAR1", "ROBO", "PLAY"
1304 };
1305 static int mms[MN_TN] = {
1306 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,
1307 20*2, 17*2, 29*2, 6*2, 2*2, 17*2, 23*2
1308 };
1309 mn_sgun[0] = Z_getspr("PWP4", 0, 1, NULL);
1310 mn_sgun[1] = Z_getspr("PWP4", 1, 1, NULL);
1311 for (j = 0; j < MN_TN; ++j) {
1312 for (i = 0; i < mms[j]; ++i) {
1313 mn_spr[j][i] = Z_getspr(msn[j], i / 2, (i & 1) + 1, &mn_sprd[j][i]);
1315 if (j == MN_BARREL - 1) {
1316 for (i = 4; i < 14; ++i) {
1317 mn_spr[j][i] = Z_getspr("BEXP", i / 2 - 2, (i & 1) + 1, &mn_sprd[j][i]);
1321 for (i = 0; i < 8; ++i) {
1322 mn_fspr[i] = Z_getspr("FIRE", i, 0, NULL);
1324 pl_spr[0] = Z_getspr("PLAY", 'N' - 'A', 0, NULL);
1325 pl_spr[1] = Z_getspr("PLAY", 'W' - 'A', 0, NULL);
1326 // misc
1327 static char mnm[22][8]={
1328 "STTNUM0","STTNUM1","STTNUM2","STTNUM3","STTNUM4",
1329 "STTNUM5","STTNUM6","STTNUM7","STTNUM8","STTNUM9",
1330 "STTMINUS","STTPRCNT",
1331 "FISTA0","CSAWA0","PISTA0","SHOTA0","SGN2A0","MGUNA0","LAUNA0",
1332 "PLASA0","BFUGA0","GUN2A0"
1333 };
1334 stone=V_loadvgaimg("STONE");
1335 stone2=V_loadvgaimg("STONE2");
1336 keys[0]=V_loadvgaimg("KEYRA0");
1337 keys[1]=V_loadvgaimg("KEYGA0");
1338 keys[2]=V_loadvgaimg("KEYBA0");
1339 for (i = 0; i < 22; ++i) {
1340 sth[i] = V_loadvgaimg(mnm[i]);
1342 strcpy(s, "STBF_*");
1343 for (i = '!'; i < 160; ++i) {
1344 s[5] = i;
1345 bfh[i - '!'] = V_getvgaimg(F_findres(s));
1347 for (i = '!'; i < 160; ++i) {
1348 sprintf(s, "STCFN%03d", i);
1349 sfh[i - '!'] = V_getvgaimg(F_findres(s));
1351 strcpy(s, "WINUM*");
1352 for (i = '0'; i <= '9'; ++i) {
1353 s[5] = i;
1354 bfh[i - '!'] = V_loadvgaimg(s);
1356 bfh[':' - '!'] = V_loadvgaimg("WICOLON");
1357 // menu
1358 msklh[0] = V_loadvgaimg("M_SKULL1");
1359 msklh[1] = V_loadvgaimg("M_SKULL2");
1360 mbarl = V_loadvgaimg("M_THERML");
1361 mbarm = V_loadvgaimg("M_THERMM");
1362 mbarr = V_loadvgaimg("M_THERMR");
1363 mbaro = V_loadvgaimg("M_THERMO");
1364 mslotl = V_loadvgaimg("M_LSLEFT");
1365 mslotm = V_loadvgaimg("M_LSCNTR");
1366 mslotr = V_loadvgaimg("M_LSRGHT");
1367 // walls
1368 static char *anm[ANIT - 1][5] = {
1369 {"WALL22_1", "WALL23_1", "WALL23_2", NULL, NULL},
1370 {"WALL58_1", "WALL58_2", "WALL58_3", NULL, NULL},
1371 {"W73A_1", "W73A_2", NULL, NULL, NULL},
1372 {"RP2_1", "RP2_2", "RP2_3", "RP2_4", NULL}
1373 };
1374 for (i = 1; i < ANIT; i++) {
1375 for (j = 0; anm[i - 1][j]; j++) {
1376 anih[i][j] = F_getresid(anm[i - 1][j]);
1378 for(; j < 5; j++) {
1379 anih[i][j] = -1;
1384 void R_get_name (int n, char s[8]) {
1385 if (walh[n] == -1) {
1386 memset(s, 0, 8);
1387 } else if (walh[n] == -2) {
1388 memcpy(s, "_WATER_", 8);
1389 s[7] = (char)((intptr_t)walp[n] - 1 + '0');
1390 } else {
1391 F_getresname(s, walh[n] & 0x7FFF);
1395 static short getani (char n[8]) {
1396 if (strncasecmp(n, "WALL22_1", 8) == 0) {
1397 return 1;
1398 } else if (strncasecmp(n, "WALL58_1", 8) == 0) {
1399 return 2;
1400 } else if (strncasecmp(n, "W73A_1", 8) == 0) {
1401 return 3;
1402 } else if (strncasecmp(n, "RP2_1", 8) == 0) {
1403 return 4;
1404 } else {
1405 return 0;
1409 int R_get_special_id (int n) {
1410 assert(n >= 0 && n < 256);
1411 intptr_t x = (intptr_t)walp[n];
1412 return x >= 0 && x <= 3 ? x : -1;
1415 void R_begin_load (void) {
1416 int i;
1417 for (i = 0; i < 256; i++) {
1418 if (walp[i] != NULL && walh[i] >= 0) {
1419 M_unlock(walp[i]);
1421 walh[i] = -1;
1422 walp[i] = NULL;
1423 walswp[i] = i;
1424 walani[i] = 0;
1426 memset(anic, 0, sizeof(anic));
1427 max_textures = 1;
1430 void R_load (char s[8]) {
1431 assert(max_textures < 256);
1432 if (!s[0]) {
1433 walh[max_textures] = -1;
1434 walp[max_textures] = NULL;
1435 } else {
1436 if (strncasecmp(s, "_WATER_", 7) == 0) {
1437 walh[max_textures] = -2;
1438 walp[max_textures] = (void*)((intptr_t)s[7] - '0' + 1);
1439 } else {
1440 walh[max_textures] = F_getresid(s);
1441 walp[max_textures] = V_getvgaimg(walh[max_textures]);
1442 if (s[0] == 'S' && s[1] == 'W' && s[4] == '_') {
1443 walswp[max_textures] = 0;
1446 walani[max_textures] = getani(s);
1448 max_textures++;
1451 void R_end_load (void) {
1452 int i, j, k, g;
1453 char s[8];
1454 j = max_textures;
1455 for (i = 1; i < 256 && j < 256; i++) {
1456 if (walswp[i] == 0) {
1457 R_get_name(i, s);
1458 s[5] ^= 1;
1459 g = F_getresid(s);
1460 k = 1;
1461 while (k < 256 && walh[k] != g) {
1462 k += 1;
1464 if (k >= 256) {
1465 k = j;
1466 j += 1;
1467 walh[k] = g;
1468 walp[k] = V_getvgaimg(g);
1469 walf[k] = walf[i];
1471 walswp[i] = k;
1472 walswp[k] = i;
1477 void R_loadsky (int sky) {
1478 char s[6];
1479 strcpy(s, "RSKY1");
1480 s[4] = '0' + sky;
1481 M_unlock(horiz);
1482 horiz = V_loadvgaimg(s);
1485 void R_setgamma(int g) {
1486 int t;
1487 g = g < 0 ? 0 : (g > 4 ? 4 : g);
1488 gammaa = g;
1489 for (t = 0; t < 256; ++t) {
1490 std_pal[t][0]=gamcor[gammaa][main_pal[t][0]];
1491 std_pal[t][1]=gamcor[gammaa][main_pal[t][1]];
1492 std_pal[t][2]=gamcor[gammaa][main_pal[t][2]];
1494 Y_set_vga_palette(std_pal);
1497 int R_getgamma (void) {
1498 return gammaa;
1501 void R_set_videomode (int w, int h, int fullscreen) {
1502 assert(w > 0);
1503 assert(h > 0);
1504 int was = Y_videomode_setted();
1505 int res = Y_set_videomode_software(w, h, fullscreen);
1506 if (res == 0) {
1507 if (was == 0) {
1508 ERR_failinit("Unable to set video mode");
1510 } else {
1511 Y_get_videomode(&SCRW, &SCRH);
1512 V_update_buffer();
1513 R_setgamma(gammaa);
1517 void R_toggle_fullscreen (void) {
1518 Y_set_fullscreen(!Y_get_fullscreen());
1519 fullscreen = Y_get_fullscreen();
1520 Y_get_videomode(&SCRW, &SCRH);
1521 V_update_buffer();
1522 R_setgamma(gammaa);
1525 static int video_menu_handler (menu_msg_t *msg, const menu_t *m, void *data, int i) {
1526 static int cur;
1527 static int w, h, fullscreen;
1528 static char buf[16];
1529 static int buflen;
1530 static int vmode;
1531 const videomode_t *v;
1532 enum { VIDEOMODE, FULLSCREEN, APPLY, __NUM__ };
1533 static const simple_menu_t sm = {
1534 GM_BIG, "Video", NULL,
1536 { "Mode: ", NULL },
1537 { "Fullscreen: ", NULL },
1538 { "Apply ", NULL },
1540 };
1541 if (msg->type == GM_ENTER) {
1542 Y_get_videomode(&w, &h);
1543 fullscreen = Y_get_fullscreen();
1544 v = Y_get_videomode_list_opengl(fullscreen);
1545 vmode = 0;
1546 while (vmode < v->n && v->modes[vmode].w != w && v->modes[vmode].h != h) {
1547 vmode += 1;
1549 if (vmode < v->n) {
1550 w = v->modes[vmode].w;
1551 h = v->modes[vmode].h;
1553 snprintf(buf, 16, "%ix%i", w, h);
1554 buflen = strlen(buf);
1555 return 1;
1557 if (i == VIDEOMODE) {
1558 switch (msg->type) {
1559 case GM_GETSTR: return GM_init_str(msg, buf, buflen);
1560 case GM_SELECT:
1561 v = Y_get_videomode_list_opengl(fullscreen);
1562 vmode = vmode + 1 >= v->n ? 0 : vmode + 1;
1563 if (v->n > 0) {
1564 w = v->modes[vmode].w;
1565 h = v->modes[vmode].h;
1566 } else {
1567 Y_get_videomode(&w, &h);
1569 snprintf(buf, 16, "%ix%i", w, h);
1570 buflen = strlen(buf);
1571 return 1;
1573 } else if (i == FULLSCREEN) {
1574 switch (msg->type) {
1575 case GM_GETSTR: return GM_init_str(msg, fullscreen ? "Yes" : "No ", 3);
1576 case GM_SELECT: fullscreen = !fullscreen; return 1;
1578 } else if (i == APPLY) {
1579 switch (msg->type) {
1580 case GM_SELECT: R_set_videomode(w, h, fullscreen); return 1;
1583 return simple_menu_handler(msg, i, __NUM__, &sm, &cur);
1586 const menu_t *R_menu (void) {
1587 static const menu_t m = { video_menu_handler };
1588 return &m;
1591 const cfg_t *R_args (void) {
1592 static const cfg_t args[] = {
1593 { "fullscr", &init_screen_full, Y_SW_ON },
1594 { "window", &init_screen_full, Y_SW_OFF },
1595 { "width", &init_screen_width, Y_DWORD },
1596 { "height", &init_screen_height, Y_DWORD },
1597 { "gamma", &init_screen_gammaa, Y_DWORD },
1598 { NULL, NULL, 0 } // end
1599 };
1600 return args;
1603 const cfg_t *R_conf (void) {
1604 static const cfg_t conf[] = {
1605 { "sky", &w_horiz, Y_SW_ON },
1606 { "fullscreen", &fullscreen, Y_SW_ON },
1607 { "screen_width", &SCRW, Y_DWORD },
1608 { "screen_height", &SCRH, Y_DWORD },
1609 { "gamma", &gammaa, Y_DWORD },
1610 { NULL, NULL, 0 } // end
1611 };
1612 return conf;
1615 void R_init () {
1616 int i;
1617 logo("R_init: initialize software render\n");
1618 F_loadres(F_getresid("PLAYPAL"), main_pal, 0, 768);
1619 for (i = 0; i < 256; ++i) {
1620 bright[i] = ((int) main_pal[i][0] + main_pal[i][1] + main_pal[i][2]) * 8 / (63 * 3);
1622 F_loadres(F_getresid("MIXMAP"), mixmap, 0, 0x10000);
1623 F_loadres(F_getresid("COLORMAP"), clrmap, 0, 256*12);
1624 SCRW = init_screen_width > 0 ? init_screen_width : SCRW;
1625 SCRH = init_screen_height > 0 ? init_screen_height : SCRH;
1626 fullscreen = init_screen_full != 0xFF ? init_screen_full : fullscreen;
1627 gammaa = init_screen_gammaa >= 0 ? init_screen_gammaa : gammaa;
1628 R_set_videomode(SCRW, SCRH, fullscreen);
1629 V_setrect(0, SCRW, 0, SCRH);
1630 V_clr(0, SCRW, 0, SCRH, 0);
1631 R_alloc();
1634 void R_done (void) {
1635 buffer = NULL;
1636 buf_w = 0;
1637 buf_h = 0;
1638 pitch = 0;
1639 Y_unset_videomode();
1642 void R_switch_texture (int x, int y) {
1643 assert(x >= 0 && x < FLDW);
1644 assert(y >= 0 && y < FLDH);
1645 fldb[y][x] = walswp[fldb[y][x]];
1648 int R_get_swp (int n) {
1649 assert(n >= 0 && n < 256);
1650 return walswp[n];