DEADSOFTWARE

e2cb9bf660cc9a4167a33df9168cba13b8b6383b
[flatwaifu.git] / src / soft / render.c
1 #include <string.h>
2 #include <stdarg.h>
3 #include <stdlib.h> // abs()
4 #include <assert.h>
5 #include "glob.h"
6 #include "render.h"
7 #include "view.h"
8 #include "player.h"
9 #include "switch.h"
10 #include "vga.h"
11 #include "menu.h"
12 #include "misc.h"
13 #include "dots.h"
14 #include "items.h"
15 #include "monster.h"
16 #include "weapons.h"
17 #include "smoke.h"
18 #include "fx.h"
19 #include "memory.h"
20 #include "files.h"
21 #include "error.h"
22 #include "game.h"
23 #include "sound.h"
24 #include "music.h"
25 #include "system.h"
27 #include "cp866.h"
29 // game
30 static vgaimg *scrnh[3]; // TITLEPIC INTERPIC ENDPIC
31 static vgaimg *ltn[2][2];
32 static void *cd_scr;
33 // smoke
34 static vgaimg *smk_spr[SMSN];
35 static vgaimg *smk_fspr[FLSN];
36 // fx
37 static vgaimg *fx_spr[15];
38 static char fx_sprd[15];
39 // weapons
40 static vgaimg *wp_spr[49*2];
41 static char wp_sprd[49*2];
42 // items
43 static vgaimg *item_spr[58];
44 static char item_sprd[58];
45 // player
46 static vgaimg *plr_spr[27*2];
47 static char plr_sprd[27*2];
48 static vgaimg *plr_wpn[11][6];
49 // monsters
50 static vgaimg *pl_spr[2];
51 static vgaimg *mn_spr[MN_TN][29*2];
52 static char mn_sprd[MN_TN][29*2];
53 static vgaimg *mn_fspr[8];
54 static vgaimg *mn_sgun[2];
55 // misc
56 #define MAXAIR 1091
57 static vgaimg *sth[22], *bfh[160 - '!'], *sfh[160 - '!'], *stone, *stone2, *keys[3];
58 static int prx = 0, pry = 0;
59 // menu
60 static vgaimg *msklh[2], *mbarl, *mbarm, *mbarr, *mbaro, *mslotl, *mslotm, *mslotr;
61 // low level
62 static int gammaa = 0;
63 static char main_pal[256][3];
64 static char std_pal[256][3];
65 static byte gamcor[5][64]={
66 #include "gamma.dat"
67 };
68 // walls
69 #define ANIT 5
70 static int WD, HT;
71 static int w_o, w_x, w_y;
72 static vgaimg *walp[256];
73 static int walh[256];
74 static byte walani[256];
75 static byte walswp[256];
76 static int anih[ANIT][5];
77 static byte anic[ANIT];
78 static int max_textures;
79 static byte w_horiz = 1;
80 static vgaimg *horiz;
82 static int init_screen_width = 0;
83 static int init_screen_height = 0;
84 static byte init_screen_full = 0xFF;
85 static int init_screen_gammaa = -1;
87 /* --- misc --- */
89 static void *Z_getspr (char n[4], int s, int d, char *dir) {
90 int h = F_getsprid(n, s, d);
91 if (dir) {
92 *dir = (h & 0x8000) ? 1 : 0;
93 }
94 return V_getvgaimg(h);
95 }
97 static vgaimg *Z_get_char_image (vgaimg **img, int ch) {
98 ch = cp866_toupper(ch);
99 return ch > 32 && ch < 160 ? img[ch - '!'] : NULL;
102 static int Z_get_char_width_generic (vgaimg **img, int off, int ch) {
103 vgaimg *p = Z_get_char_image(img, ch);
104 return p == NULL ? off : p->w - 1;
107 static int Z_putch_generic (vgaimg **img, int off, int ch) {
108 vgaimg *p = Z_get_char_image(img, ch);
109 int w = p == NULL ? off : p->w - 1;
110 if (p != NULL) {
111 V_spr(prx, pry, p);
113 prx += w;
114 return w;
117 static int Z_get_string_width_generic (vgaimg **img, int off, const char *fmt, va_list ap) {
118 int i, w, ww;
119 char buf[80];
120 vsprintf(buf, fmt, ap);
121 for (i = w = ww = 0; buf[i]; ++i) {
122 switch (buf[i]) {
123 case '\n':
124 case '\r':
125 ww = max(w, ww);
126 w = 0;
127 break;
128 default:
129 w += Z_get_char_width_generic(img, off, (byte)buf[i]);
132 return max(w, ww);
135 static int Z_printf_generic (vgaimg **img, int off, const char *fmt, va_list ap) {
136 int i, w, ww;
137 char buf[80];
138 vsprintf(buf, fmt, ap);
139 for (i = w = ww = 0; buf[i]; ++i) {
140 switch (buf[i]) {
141 case '\n':
142 pry += off + 1;
143 case '\r':
144 w = max(w, ww);
145 prx = 0;
146 w = 0;
147 break;
148 default:
149 w += Z_putch_generic(img, off, (byte)buf[i]);
152 return w;
155 static void Z_gotoxy (int x, int y) {
156 prx = x;
157 pry = y;
160 static int Z_get_big_string_width (const char *fmt, ...) {
161 va_list a;
162 va_start(a, fmt);
163 int w = Z_get_string_width_generic(bfh, 12, fmt, a);
164 va_end(a);
165 return w;
168 static int Z_printbf (const char *fmt, ...) {
169 va_list a;
170 va_start(a, fmt);
171 int w = Z_printf_generic(bfh, 12, fmt, a);
172 va_end(a);
173 return w;
176 static int Z_get_small_string_width (const char *fmt, ...) {
177 va_list a;
178 va_start(a, fmt);
179 int w = Z_get_string_width_generic(sfh, 7, fmt, a);
180 va_end(a);
181 return w;
184 static int Z_printsf (const char *fmt, ...) {
185 va_list a;
186 va_start(a, fmt);
187 int w =Z_printf_generic(sfh, 7, fmt, a);
188 va_end(a);
189 return w;
192 static void Z_drawspr (int x, int y, void *p, char d) {
193 if (d) {
194 V_spr2(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p);
195 } else {
196 V_spr(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p);
200 static void Z_clrst (void) {
201 V_pic(SCRW - 120, w_o, stone);
202 int y = ((vgaimg*)stone)->h;
203 while (y < HT) {
204 V_pic(SCRW - 120, w_o + y, stone2);
205 y += ((vgaimg*)stone)->h;
209 static void Z_drawstlives (char n) {
210 V_setrect(SCRW - 40, 30, w_o, 40);
211 V_spr(SCRW - 35, w_o + 17, sth[n]);
214 static void Z_drawstkeys (byte k) {
215 int x, n;
216 V_setrect(SCRW - 120, 70, w_o + 77, 23);
217 for (k >>= 4, n = 0, x = SCRW - 75; n < 3; ++n, k >>= 1, x += 9) {
218 if (k & 1) {
219 V_spr(x, w_o + 91, keys[n]);
224 static void Z_drawstair (int a) {
225 V_setrect(SCRW - 120, 120, w_o + 49, 2);
226 if (a > 0) {
227 if (a > MAXAIR) {
228 a = MAXAIR;
230 a = a * 100 / MAXAIR;
231 V_clr(SCRW - 110, a, w_o + 49, 2, 0xC8);
235 static void Z_drawstprcnt (int y, int n) {
236 char s[20];
237 int l, i, x, c;
238 V_setrect(SCRW - 120, 70, y * 19 + 7 + w_o, 19);
239 sprintf(s, "%3d%%", n);
240 l = strlen(s);
241 x = SCRW - 110;
242 for (i = 0; i < l; ++i, x += 14) {
243 if (s[i] >='0' && s[i] <= '9') {
244 c = s[i] - '0';
245 } else if (s[i] == '-') {
246 c = 10;
247 } else if (s[i] == '%') {
248 c = 11;
249 } else {
250 c = -1;
252 if (c >= 0) {
253 V_spr(x, y * 19 + 7 + w_o, sth[c]);
258 static void Z_drawstnum (int n) {
259 char s[20];
260 int l, i, x, c;
261 V_setrect(SCRW - 50, 50, w_o + 77, 23);
262 if (g_dm) {
263 sprintf(s, "%d", n);
264 l = strlen(s);
265 x = (115 - l * 14) + SCRW - 120;
266 for (i = 0; i < l; ++i, x += 14) {
267 if (s[i] >= '0' && s[i] <= '9') {
268 c = s[i] - '0';
269 } else if (s[i] == '-') {
270 c = 10;
271 } else if(s[i] == '%') {
272 c = 11;
273 } else {
274 c =- 1;
276 if (c >= 0) {
277 V_spr(x, w_o + 77 + 5, sth[c]);
283 static void Z_drawstwpn (int n, int a) {
284 char s[20];
285 int l, i, x, c;
286 i = n;
287 V_setrect(SCRW - 120, 120, w_o + 58, 23);
288 if (i >= 0) {
289 V_spr(SCRW - 88, w_o + 58 + 19, sth[i + 12]);
291 if (n >= 2) {
292 sprintf(s, "%d", a);
293 l = strlen(s);
294 x = SCRW - 10 - l * 14;
295 for (i = 0; i < l; ++i, x += 14) {
296 if (s[i] >= '0' && s[i] <= '9') {
297 c = s[i] - '0';
298 } else if (s[i] == '-') {
299 c = 10;
300 } else if (s[i] == '%') {
301 c = 11;
302 } else {
303 c = -1;
305 if (c >= 0) {
306 V_spr(x, w_o + 58 + 2, sth[c]);
312 static void Z_drawmanspr (int x, int y, void *p, char d, byte color) {
313 if (d) {
314 V_manspr2(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p, color);
315 } else {
316 V_manspr(x - w_x + WD / 2, y - w_y + HT / 2 + 1 + w_o, p, color);
320 static void Z_drawfld (byte *fld, int bg) {
321 byte *p = fld;
322 int x, y;
323 for (y = 0; y < FLDH; y++) {
324 for (x = 0; x < FLDW; x++) {
325 int sx = x * CELW - w_x + WD / 2;
326 int sy = y * CELH - w_y + HT / 2 + 1 + w_o;
327 int id = *p;
328 if (id) {
329 //intptr_t spc = (intptr_t) walp[id];
330 int spc = R_get_special_id(id);
331 if (spc >= 0 && spc <= 3) {
332 if (!bg) {
333 byte *cmap = clrmap + (spc + 7) * 256;
334 V_remap_rect(sx, sy, CELW, CELH, cmap);
336 } else {
337 V_pic(sx, sy, walp[id]);
340 p++;
345 /* --- menu --- */
347 static int gm_tm = 0; // ???
349 #define SCROLLER_MIDDLE 10
350 #define TEXTFIELD_MIDDLE 2
352 static void get_entry_size (const menu_t *m, int i, int *w, int *h) {
353 assert(m != NULL);
354 assert(i >= 0);
355 assert(w != NULL);
356 assert(h != NULL);
357 int x = 0;
358 int y = 0;
359 int type = 0;
360 menu_msg_t msg;
361 msg.type = GM_GETENTRY;
362 assert(GM_send(m, i, &msg));
363 type = msg.integer.i;
364 switch (type) {
365 case GM_BUTTON:
366 case GM_SCROLLER:
367 case GM_TEXTFIELD:
368 case GM_TEXTFIELD_BUTTON:
369 msg.type = GM_GETCAPTION;
370 if (GM_send(m, i, &msg)) {
371 x = Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
373 break;
374 case GM_SMALL_BUTTON:
375 msg.type = GM_GETCAPTION;
376 if (GM_send(m, i, &msg)) {
377 x = Z_get_small_string_width("%.*s", msg.string.maxlen, msg.string.s);
379 break;
380 default:
381 assert(0);
383 switch (type) {
384 case GM_BUTTON:
385 msg.type = GM_GETSTR;
386 if (GM_send(m, i, &msg)) {
387 x += Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
389 y = 16;
390 break;
391 case GM_SMALL_BUTTON:
392 msg.type = GM_GETSTR;
393 if (GM_send(m, i, &msg)) {
394 x += Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s);
396 y = 12;
397 break;
398 case GM_SCROLLER:
399 x += (SCROLLER_MIDDLE + 2) * 8;
400 y = 16;
401 break;
402 case GM_TEXTFIELD:
403 case GM_TEXTFIELD_BUTTON:
404 msg.type = GM_GETSTR;
405 if (GM_send(m, i, &msg)) {
406 x += (msg.string.maxlen + 2) * 8;
407 } else {
408 x += (TEXTFIELD_MIDDLE + 2) * 8;
410 y = 16;
411 break;
412 default:
413 assert(0);
415 *w = x;
416 *h = y;
419 static void get_menu_size (const menu_t *m, int *w, int *h) {
420 assert(m != NULL);
421 assert(w != NULL);
422 assert(h != NULL);
423 int i, n, x, y, xx, yy, type;
424 menu_msg_t msg;
425 msg.type = GM_QUERY;
426 if (GM_send_this(m, &msg)) {
427 n = msg.integer.b;
428 type = msg.integer.s;
429 x = 0;
430 y = 0;
431 msg.type = GM_GETTITLE;
432 if (GM_send_this(m, &msg)) {
433 switch (type) {
434 case GM_BIG: x = Z_get_big_string_width("%.*s", msg.string.maxlen, msg.string.s); break;
435 case GM_SMALL: x = Z_get_small_string_width("%.*s", msg.string.maxlen, msg.string.s); break;
436 default: assert(0);
439 for (i = 0; i < n; i++) {
440 get_entry_size(m, i, &xx, &yy);
441 x = max(x, xx);
442 y += yy;
444 *w = x;
445 *h = y;
446 } else {
447 *w = 0;
448 *h = 0;
452 static int GM_draw (void) {
453 int i, j, n, x, y, xoff, yoff, cur, w, type, recv;
454 const menu_t *m = GM_get();
455 menu_msg_t msg;
456 if (m != NULL) {
457 get_menu_size(m, &x, &y);
458 x = SCRW / 2 - x / 2;
459 y = SCRH / 2 - y / 2;
460 // --- title ---
461 msg.type = GM_QUERY;
462 if (GM_send_this(m, &msg)) {
463 cur = msg.integer.i;
464 n = msg.integer.a;
465 type = msg.integer.s;
466 msg.type = GM_GETTITLE;
467 if (GM_send_this(m, &msg)) {
468 Z_gotoxy(x, y - 10);
469 switch (type) {
470 case GM_SMALL: yoff = 8; Z_printsf("%.*s", msg.string.maxlen, msg.string.s); break;
471 case GM_BIG: yoff = 20; Z_printbf("%.*s", msg.string.maxlen, msg.string.s); break;
472 default: assert(0);
474 } else {
475 yoff = 0;
477 for (i = 0; i < n; i++) {
478 msg.type = GM_GETENTRY;
479 if (GM_send(m, i, &msg)) {
480 type = msg.integer.i;
481 if (i == cur) {
482 if (type == GM_SMALL_BUTTON) {
483 Z_gotoxy(x - 8, y + yoff);
484 Z_printsf(">");
485 } else {
486 V_spr(x - 25, y + yoff - 8, msklh[(gm_tm / 6) & 1]);
489 msg.type = GM_GETCAPTION;
490 if (GM_send(m, i, &msg)) {
491 Z_gotoxy(x, y + yoff);
492 if (type == GM_SMALL_BUTTON) {
493 xoff = Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
494 } else {
495 xoff = Z_printbf("%.*s", msg.string.maxlen, msg.string.s);
497 } else {
498 xoff = 0;
500 switch (type) {
501 case GM_BUTTON:
502 case GM_SMALL_BUTTON:
503 msg.type = GM_GETSTR;
504 if (GM_send(m, i, &msg)) {
505 Z_gotoxy(x + xoff, y + yoff);
506 if (type == GM_SMALL_BUTTON) {
507 Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
508 } else {
509 Z_printbf("%.*s", msg.string.maxlen, msg.string.s);
512 yoff += type == GM_BUTTON ? 16 : 12;
513 break;
514 case GM_TEXTFIELD:
515 case GM_TEXTFIELD_BUTTON:
516 yoff += 9;
517 msg.type = GM_GETSTR;
518 recv = GM_send(m, i, &msg);
519 w = recv ? msg.string.maxlen : TEXTFIELD_MIDDLE;
520 V_spr(x + xoff, y + yoff, mslotl);
521 for (j = 1; j <= w; j++) {
522 V_spr(x + xoff + j * 8, y + yoff, mslotm);
524 V_spr(x + xoff + j * 8, y + yoff, mslotr);
525 Z_gotoxy(x + xoff + 4, y + yoff - 7);
526 if (input && i == cur) {
527 Z_printsf("%.*s_", imax, ibuf);
528 } else if (recv) {
529 Z_printsf("%.*s", msg.string.maxlen, msg.string.s);
531 yoff += 7;
532 break;
533 case GM_SCROLLER:
534 V_spr(x + xoff, y + yoff, mbarl);
535 for (j = 1; j < SCROLLER_MIDDLE; j++) {
536 V_spr(x + xoff + j * 8, y + yoff, mbarm);
538 V_spr(x + xoff + j * 8, y + yoff, mbarr);
539 msg.type = GM_GETINT;
540 if (GM_send(m, i, &msg)) {
541 int lev = (msg.integer.i - msg.integer.a) * ((SCROLLER_MIDDLE - 2) * 8) / msg.integer.b;
542 V_spr(x + xoff + lev + 8, y + yoff, mbaro);
544 yoff += 16;
545 break;
546 default:
547 assert(0);
553 return m != NULL;
556 /* --- dots --- */
558 static void DOT_draw (void) {
559 int i;
560 for (i = 0; i < MAXDOT; i++) {
561 if (dot[i].t) {
562 V_dot(dot[i].o.x - w_x + WD / 2, dot[i].o.y - w_y + HT / 2 + 1 + w_o, dot[i].c);
567 /* --- items --- */
569 static void IT_draw (void) {
570 int i, s;
571 for (i = 0; i < MAXITEM; ++i) {
572 s = -1;
573 if (it[i].t && it[i].s >= 0) {
574 switch(it[i].t & 0x7FFF) {
575 case I_ARM1:
576 s = it[i].s / 9 + 18;
577 break;
578 case I_ARM2:
579 s = it[i].s / 9 + 20;
580 break;
581 case I_MEGA:
582 s = it[i].s / 2 + 22;
583 break;
584 case I_INVL:
585 s = it[i].s / 2 + 26;
586 break;
587 case I_SUPER:
588 case I_RTORCH:
589 case I_GTORCH:
590 case I_BTORCH:
591 s = it[i].s / 2 + (it[i].t - I_SUPER) * 4 + 35;
592 break;
593 case I_GOR1: case I_FCAN:
594 s = it[i].s / 2 + (it[i].t - I_GOR1) * 3 + 51;
595 break;
596 case I_AQUA:
597 s = 30;
598 break;
599 case I_SUIT:
600 s = 34;
601 break;
602 case I_KEYR:
603 case I_KEYG:
604 case I_KEYB:
605 s = (it[i].t & 0x7FFF) - I_KEYR + 31;
606 break;
607 case I_GUN2:
608 s = 57;
609 break;
610 default:
611 s = (it[i].t & 0x7FFF) - 1;
614 if (s >= 0) {
615 Z_drawspr(it[i].o.x, it[i].o.y, item_spr[s], item_sprd[s]);
620 /* --- player --- */
622 static int standspr (player_t *p) {
623 if (p->f & PLF_UP) {
624 return 'X';
625 } else if (p->f & PLF_DOWN) {
626 return 'Z';
627 } else {
628 return 'E';
632 static int wpnspr (player_t *p) {
633 if (p->f & PLF_UP) {
634 return 'C';
635 } else if(p->f & PLF_DOWN) {
636 return 'E';
637 } else {
638 return 'A';
642 static void PL_draw (player_t *p) {
643 enum {STAND, GO, DIE, SLOP, DEAD, MESS, OUT, FALL}; // copypasted from player.c!
644 static int wytab[] = {-1, -2, -1, 0};
645 int s = 'A';
646 int w = 0;
647 int wx = 0;
648 int wy = 0;
649 switch (p->st) {
650 case STAND:
651 if (p->f & PLF_FIRE) {
652 s = standspr(p) + 1;
653 w = wpnspr(p) + 1;
654 } else if (p->pain) {
655 s = 'G';
656 w = 'A';
657 wx = p->d ? 2 : -2;
658 wy = 1;
659 } else {
660 s = standspr(p);
661 w = wpnspr(p);
663 break;
664 case DEAD:
665 s = 'N';
666 break;
667 case MESS:
668 s = 'W';
669 break;
670 case GO:
671 if (p->pain) {
672 s = 'G';
673 w = 'A';
674 wx = p->d ? 2 : -2;
675 wy = 1;
676 } else {
677 s = plr_goanim[p->s / 8];
678 w = (p->f & PLF_FIRE) ? 'B' : 'A';
679 wx = p->d ? 2 : -2;
680 wy = 1 + wytab[s - 'A'];
682 break;
683 case DIE:
684 s = plr_dieanim[p->s];
685 break;
686 case SLOP:
687 s = plr_slopanim[p->s];
688 break;
689 case OUT:
690 s = 0;
691 break;
693 if (p->wpn == 0) {
694 w = 0;
696 if (w) {
697 Z_drawspr(p->o.x + wx, p->o.y + wy, plr_wpn[p->wpn][w - 'A'], p->d);
699 if (s) {
700 Z_drawmanspr(p->o.x, p->o.y, plr_spr[(s - 'A') * 2 + p->d], plr_sprd[(s - 'A') * 2 + p->d], p->color);
704 static void PL_drawst (player_t *p) {
705 int i;
706 V_setrect(WD, 120, w_o, HT);
707 Z_clrst();
708 if (p->drawst & PL_DRAWAIR) {
709 if (p->air < PL_AIR) {
710 Z_drawstair(p->air);
713 if (p->drawst & PL_DRAWLIFE) {
714 Z_drawstprcnt(0, p->life);
716 if (p->drawst & PL_DRAWARMOR) {
717 Z_drawstprcnt(1, p->armor);
719 if (p->drawst & PL_DRAWWPN) {
720 switch(p->wpn) {
721 case 2:
722 case 5:
723 i = p->ammo;
724 break;
725 case 3:
726 case 4:
727 case 9:
728 i = p->shel;
729 break;
730 case 6:
731 i = p->rock;
732 break;
733 case 10:
734 i = p->fuel;
735 break;
736 case 7:
737 case 8:
738 i = p->cell;
739 break;
741 Z_drawstwpn(p->wpn, i);
743 if (p->drawst & PL_DRAWFRAG) {
744 Z_drawstnum(p->frag);
746 if (p->drawst & PL_DRAWKEYS) {
747 Z_drawstkeys(p->keys);
749 if (!_2pl) {
750 if (p->drawst & PL_DRAWLIVES) {
751 Z_drawstlives(p->lives);
756 /* --- monster --- */
758 #define MANCOLOR 0xD0
760 static void MN_draw (void) {
761 enum {SLEEP, GO, RUN, CLIMB, DIE, DEAD, ATTACK, SHOOT, PAIN, WAIT, REVIVE, RUNOUT}; // copypasted from monster.c!
762 int i;
763 for (i = 0; i < MAXMN; i++) {
764 if (mn[i].t) {
765 if (mn[i].t >= MN_PL_DEAD) {
766 Z_drawmanspr(mn[i].o.x, mn[i].o.y, pl_spr[mn[i].t - MN_PL_DEAD], 0, mn[i].d);
767 continue;
769 if ((mn[i].t != MN_SOUL && mn[i].t != MN_PAIN) || mn[i].st != DEAD) {
770 if (mn[i].t != MN_MAN) {
771 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]);
772 } else {
773 if (mn[i].ap[mn[i].ac] == 'E' || mn[i].ap[mn[i].ac] == 'F') {
774 Z_drawspr(mn[i].o.x, mn[i].o.y, mn_sgun[mn[i].ap[mn[i].ac] - 'E'], mn[i].d);
776 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);
779 if (mn[i].t == MN_VILE && mn[i].st == SHOOT) {
780 Z_drawspr(mn[i].tx, mn[i].ty, mn_fspr[mn[i].ac / 3], 0);
786 /* --- weapon --- */
788 static void WP_draw (void) {
789 enum {NONE, ROCKET, PLASMA, APLASMA, BALL1, BALL2, BALL7, BFGBALL, BFGHIT, MANF, REVF, FIRE}; // copypasted from weapons.c!
790 int i, s, d, x, y;
791 for (i = 0; i < MAXWPN; ++i) {
792 s = -1;
793 d = 0;
794 switch (wp[i].t) {
795 case NONE:
796 default:
797 break;
798 case REVF:
799 case ROCKET:
800 d = wp[i].s;
801 if (d < 2) {
802 d = wp[i].o.xv > 0 ? 1 : 0;
803 x = abs(wp[i].o.xv);
804 y = wp[i].o.yv;
805 s = 0;
806 if (y < 0) {
807 if (-y >= x) {
808 s = 30;
810 } else if (y > 0) {
811 if (y >= x / 2) {
812 s = 31;
815 } else {
816 s = (d - 2) / 2 + 1;
817 d = 0;
819 break;
820 case MANF:
821 s=wp[i].s;
822 if (s >= 2) {
823 s /= 2;
824 break;
826 case PLASMA:
827 case APLASMA:
828 case BALL1:
829 case BALL7:
830 case BALL2:
831 s = wp[i].s;
832 if (s >= 2) {
833 s = s / 2 + 1;
835 switch (wp[i].t) {
836 case PLASMA:
837 s += 4;
838 break;
839 case APLASMA:
840 s += 11;
841 break;
842 case BALL1:
843 s += 32;
844 break;
845 case BALL2:
846 s += 42;
847 break;
848 case BALL7:
849 s += 37;
850 d = wp[i].o.xv >= 0 ? 1 : 0;
851 break;
852 case MANF:
853 s += 47;
854 d= wp[i].o.xv>=0 ? 1 : 0;
855 break;
857 break;
858 case BFGBALL:
859 s = wp[i].s;
860 if (s >= 2) {
861 s = s / 2 + 1;
863 s += 18;
864 break;
865 case BFGHIT:
866 s = wp[i].s / 2 + 26;
867 break;
869 if (s >= 0) {
870 Z_drawspr(wp[i].o.x, wp[i].o.y, wp_spr[s * 2 + d], wp_sprd[s * 2 + d]);
875 /* --- smoke --- */
877 static void SMK_draw (void) {
878 int i, s;
879 for (i = 0; i < MAXSMOK; ++i) {
880 if (sm[i].t) {
881 switch (sm[i].s) {
882 case 0:
883 s = sm[i].t;
884 if (s >= (SMSN - 1) * 3) {
885 s = 0;
886 } else {
887 s = SMSN - 1 - s / 3;
889 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);
890 break;
891 case 1:
892 s = sm[i].t;
893 if (s >= FLSN - 1) {
894 s = 0;
895 } else {
896 s = FLSN - 1 - s;
898 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);
899 break;
905 /* --- fx --- */
907 static void FX_draw (void) {
908 enum {NONE, TFOG, IFOG, BUBL}; // copypasted from fx.c
909 int i, s;
910 for (i = 0; i < MAXFX; ++i) {
911 s = -1;
912 switch (fx[i].t) {
913 case TFOG:
914 s = fx[i].s / 2;
915 break;
916 case IFOG:
917 s = fx[i].s / 2 + 10;
918 break;
919 case BUBL:
920 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);
921 continue;
923 if (s >= 0) {
924 Z_drawspr(fx[i].x, fx[i].y, fx_spr[s], fx_sprd[s]);
929 /* --- view --- */
931 static void W_adjust (void) {
932 int MAXX = FLDW * CELW - WD / 2;
933 int MAXY = FLDH * CELH - HT / 2;
934 if (w_x < WD / 2) w_x = WD / 2;
935 if (w_y < HT / 2) w_y = HT / 2;
936 if (w_x > MAXX) w_x = MAXX;
937 if (w_y > MAXY) w_y = MAXY;
940 static void W_draw(void) {
941 W_adjust();
942 V_setrect(0, WD, w_o + 1, HT);
943 if (w_horiz) {
944 vgaimg *img = (vgaimg*)horiz;
945 int x = 0;
946 int d = 0;
947 do {
948 int y = w_o;
949 d &= ~2;
950 do {
951 V_rotspr(x, y, img, d);
952 y += img->h;
953 d ^= 2;
954 } while (y < HT + w_o);
955 x += img->w;
956 d ^= 1;
957 } while (x < WD);
958 if (sky_type == 2) {
959 if (lt_time < 0) {
960 if (!lt_side) {
961 V_spr(0, w_o + lt_ypos, ltn[lt_type][lt_time < -5 ? 0 : 1]);
962 } else {
963 V_spr2(WD - 1, w_o + lt_ypos, ltn[lt_type][lt_time < -5 ? 0 : 1]);
967 } else {
968 V_clr(0, WD, w_o + 1, HT, 0x97);
970 Z_drawfld((byte*)fldb, 1);
971 DOT_draw();
972 IT_draw();
973 PL_draw(&pl1);
974 if (_2pl) {
975 PL_draw(&pl2);
977 MN_draw();
978 WP_draw();
979 SMK_draw();
980 FX_draw();
981 Z_drawfld((byte*)fldf, 0);
982 if (sky_type == 2) {
983 if (lt_time == -4 || lt_time == -2) {
984 V_remap_rect(0, WD, w_o + 1, HT, clrmap + 256 * 11);
989 /* --- game --- */
991 #define PL_FLASH 90
993 static void drawview (player_t *p) {
994 if (p->looky < -SCRH / 4) {
995 p->looky = -SCRH / 4;
996 } else if (p->looky > SCRH / 4) {
997 p->looky = SCRH / 4;
999 w_x = p->o.x;
1000 w_y = p->o.y - 12 + p->looky;
1001 W_draw();
1002 PL_drawst(p);
1005 static int get_pu_st (int t) {
1006 if (t >= PL_FLASH) {
1007 return 1;
1008 } else if((t / 9) & 1) {
1009 return 0;
1010 } else {
1011 return 1;
1015 static void pl_info (player_t *p, int y) {
1016 dword t = p->kills * 10920 / g_time;
1017 Z_gotoxy(25, y); Z_printbf("KILLS");
1018 Z_gotoxy(25, y + 15); Z_printbf("KPM");
1019 Z_gotoxy(25, y + 30); Z_printbf("SECRETS %u / %u", p->secrets, sw_secrets);
1020 Z_gotoxy(255, y); Z_printbf("%u", p->kills);
1021 Z_gotoxy(255, y + 15); Z_printbf("%u.%u", t / 10, t % 10);
1024 static void W_act (void) {
1025 int i, a;
1026 if (g_time % 3 == 0) {
1027 for (i = 1; i < 256; i++) {
1028 a = walani[i];
1029 if (a != 0) {
1030 anic[a]++;
1031 if (anih[a][anic[a]] == -1) {
1032 anic[a] = 0;
1034 walp[i] = V_getvgaimg(anih[a][anic[a]]);
1040 void R_draw (void) {
1041 int h;
1042 word hr, mn, sc;
1043 W_act();
1044 switch (g_st) {
1045 case GS_ENDANIM:
1046 case GS_END2ANIM:
1047 case GS_DARKEN:
1048 case GS_BVIDEO:
1049 case GS_EVIDEO:
1050 case GS_END3ANIM:
1051 return;
1052 case GS_TITLE:
1053 V_center(1);
1054 V_pic(0, 0, scrnh[0]);
1055 V_center(0);
1056 break;
1057 case GS_ENDSCR:
1058 V_center(1);
1059 V_clr(0, SCRW, 0, SCRH, 0);
1060 V_pic(0, 0, scrnh[2]);
1061 V_center(0);
1062 break;
1063 case GS_INTER:
1064 V_center(1);
1065 V_clr(0, SCRW, 0, SCRH, 0);
1066 V_pic(0, 0, scrnh[1]);
1067 Z_gotoxy(60, 20);
1068 Z_printbf("LEVEL COMPLETE");
1069 Z_calc_time(g_time, &hr, &mn, &sc);
1070 Z_gotoxy(115, 40);
1071 Z_printbf("TIME %u:%02u:%02u", hr, mn, sc);
1072 h = 60;
1073 if (_2pl) {
1074 Z_gotoxy(80, h);
1075 Z_printbf("PLAYER ONE");
1076 Z_gotoxy(80, h + 70);
1077 Z_printbf("PLAYER TWO");
1078 h += SCRH / 10;
1080 pl_info(&pl1, h);
1081 if (_2pl) {
1082 pl_info(&pl2, h + 70);
1084 V_center(0);
1085 break;
1087 V_center(0);
1088 if (g_st == GS_GAME) {
1089 if (_2pl) {
1090 w_o = 0;
1091 WD = SCRW - 120;
1092 HT = SCRH / 2 - 2;
1093 drawview(&pl1);
1094 w_o = SCRH / 2;
1095 WD = SCRW - 120;
1096 HT = SCRH / 2 - 2;
1097 drawview(&pl2);
1098 } else{
1099 w_o = 0;
1100 WD = SCRW - 120;
1101 HT = SCRH - 2;
1102 drawview(&pl1);
1104 if (pl1.invl) {
1105 h = get_pu_st(pl1.invl) * 6;
1106 } else if (pl1.pain < 15) {
1107 h = 0;
1108 } else if (pl1.pain < 35) {
1109 h = 1;
1110 } else if (pl1.pain < 55) {
1111 h = 2;
1112 } else if (pl1.pain < 75) {
1113 h=3;
1114 } else if (pl1.pain < 95) {
1115 h=4;
1116 } else {
1117 h = 5;
1119 if (h != 0) {
1120 V_maptoscr(0, SCRW - 120, 1, _2pl ? SCRH / 2 - 2 : SCRH - 2, clrmap + h * 256);
1122 if (_2pl) {
1123 if (pl2.invl) {
1124 h = get_pu_st(pl2.invl) * 6;
1125 } else if (pl2.pain < 15) {
1126 h = 0;
1127 } else if (pl2.pain < 35) {
1128 h = 1;
1129 } else if (pl2.pain < 55) {
1130 h = 2;
1131 } else if (pl2.pain < 75) {
1132 h = 3;
1133 } else if (pl2.pain < 95) {
1134 h = 4;
1135 } else {
1136 h = 5;
1138 if (h) {
1139 V_maptoscr(0, SCRW - 120, SCRH / 2 + 1, SCRH / 2 - 2, clrmap + h * 256);
1143 V_center(0);
1144 V_setrect(0, SCRW, 0, SCRH);
1145 GM_draw();
1146 V_copytoscr(0, SCRW, 0, SCRH);
1149 void R_alloc (void) {
1150 int i, j, n;
1151 char s[10];
1152 logo("R_alloc: загрузка графики\n");
1153 // game
1154 scrnh[0] = V_loadvgaimg("TITLEPIC");
1155 scrnh[1] = V_loadvgaimg("INTERPIC");
1156 scrnh[2] = V_loadvgaimg("ENDPIC");
1157 cd_scr = M_lock(F_getresid("CD1PIC"));
1158 for (i = 0; i < 2; ++i) {
1159 sprintf(s, "LTN%c", i + '1');
1160 for (j = 0; j < 2; ++j) {
1161 ltn[i][j] = Z_getspr(s, j, 0, NULL);
1164 // smoke
1165 for (i = 0; i < SMSN; ++i) {
1166 smk_spr[i] = Z_getspr("SMOK", i, 0, NULL);
1168 for (i = 0; i < FLSN; ++i) {
1169 smk_fspr[i] = Z_getspr("FLAM", i, 0, NULL);
1171 // fx
1172 for (i = 0; i < 10; ++i) {
1173 fx_spr[i] = Z_getspr("TFOG", i, 0, fx_sprd + i);
1175 for (; i < 15; ++i) {
1176 fx_spr[i] = Z_getspr("IFOG", i - 10, 0, fx_sprd + i);
1178 // weapons
1179 for (i = 0; i < 4; ++i) {
1180 wp_spr[i * 2] = Z_getspr("MISL", i, 1, wp_sprd + i * 2);
1181 wp_spr[i * 2 + 1] = Z_getspr("MISL", i, 2, wp_sprd + i * 2 + 1);
1183 for (; i < 6; ++i) {
1184 wp_spr[i * 2] = Z_getspr("PLSS", i - 4, 1, wp_sprd + i * 2);
1185 wp_spr[i * 2 + 1] = Z_getspr("PLSS", i - 4, 2, wp_sprd + i * 2 + 1);
1187 for (; i < 11; ++i) {
1188 wp_spr[i * 2] = Z_getspr("PLSE", i - 6, 1, wp_sprd + i * 2);
1189 wp_spr[i * 2 + 1] = Z_getspr("PLSE", i - 6, 2, wp_sprd + i * 2 + 1);
1191 for (; i < 13; ++i) {
1192 wp_spr[i * 2] = Z_getspr("APLS", i - 11, 1, wp_sprd + i * 2);
1193 wp_spr[i * 2 + 1] = Z_getspr("APLS", i - 11, 2, wp_sprd + i * 2 + 1);
1195 for (; i < 18; ++i) {
1196 wp_spr[i * 2] = Z_getspr("APBX", i - 13, 1, wp_sprd + i * 2);
1197 wp_spr[i * 2 + 1] = Z_getspr("APBX", i - 13, 2, wp_sprd + i * 2 + 1);
1199 for(; i < 20; ++i) {
1200 wp_spr[i * 2] = Z_getspr("BFS1", i - 18, 1, wp_sprd + i * 2);
1201 wp_spr[i * 2 + 1] = Z_getspr("BFS1", i - 18, 2, wp_sprd + i * 2 + 1);
1203 for (; i < 26; ++i) {
1204 wp_spr[i * 2] = Z_getspr("BFE1", i - 20, 1, wp_sprd + i * 2);
1205 wp_spr[i * 2 + 1] = Z_getspr("BFE1", i - 20, 2, wp_sprd + i * 2 + 1);
1207 for (; i < 30; ++i) {
1208 wp_spr[i * 2] = Z_getspr("BFE2", i - 26, 1, wp_sprd + i * 2);
1209 wp_spr[i * 2 + 1] = Z_getspr("BFE2", i - 26, 2, wp_sprd + i * 2 + 1);
1211 for (; i < 32; ++i) {
1212 wp_spr[i * 2] = Z_getspr("MISL", i - 30 + 4, 1, wp_sprd + i * 2);
1213 wp_spr[i * 2 + 1] = Z_getspr("MISL", i - 30 + 4, 2, wp_sprd + i * 2 + 1);
1215 for (; i < 37; ++i) {
1216 wp_spr[i * 2] = Z_getspr("BAL1", i - 32, 1, wp_sprd + i * 2);
1217 wp_spr[i * 2 + 1] = Z_getspr("BAL1", i - 32, 2, wp_sprd + i * 2 + 1);
1219 for (; i < 42; ++i) {
1220 wp_spr[i * 2] = Z_getspr("BAL7", i - 37, 1, wp_sprd + i * 2);
1221 wp_spr[i * 2 + 1] = Z_getspr("BAL7", i - 37, 2, wp_sprd + i * 2 + 1);
1223 for (; i < 47; ++i) {
1224 wp_spr[i * 2] = Z_getspr("BAL2", i - 42, 1, wp_sprd + i * 2);
1225 wp_spr[i * 2 + 1] = Z_getspr("BAL2", i - 42, 2, wp_sprd + i * 2 + 1);
1227 for (; i < 49; ++i) {
1228 wp_spr[i * 2] = Z_getspr("MANF", i - 47, 1, wp_sprd + i * 2);
1229 wp_spr[i * 2 + 1] = Z_getspr("MANF", i - 47, 2, wp_sprd + i * 2 + 1);
1231 // items
1232 static char snm[18][4] = {
1233 "CLIP", "SHEL", "ROCK", "CELL", "AMMO", "SBOX", "BROK", "CELP",
1234 "STIM", "MEDI", "BPAK",
1235 "CSAW", "SHOT", "SGN2", "MGUN", "LAUN", "PLAS", "BFUG"
1236 };
1237 static char n4[4][4] = {
1238 "SOUL", "SMRT", "SMGT", "SMBT"
1239 };
1240 static char n3[2][4] = {
1241 "GOR1", "FCAN"
1242 };
1243 for (i = 0; i < 18; ++i) {
1244 item_spr[i] = Z_getspr(snm[i], 0, 0, item_sprd + i);
1246 for (; i < 20; ++i) {
1247 item_spr[i] = Z_getspr("ARM1", i - 18, 0, item_sprd + i);
1248 item_spr[i + 2] = Z_getspr("ARM2", i - 18, 0, item_sprd + i);
1250 i+=2;
1251 for (; i < 26; ++i) {
1252 item_spr[i] = Z_getspr("MEGA", i - 22, 0, item_sprd + i);
1254 for (; i < 30; ++i) {
1255 item_spr[i] = Z_getspr("PINV", i - 26, 0, item_sprd + i);
1257 item_spr[30] = Z_getspr("AQUA", 0, 0, item_sprd + 30);
1258 item_spr[31] = Z_getspr("KEYR", 0, 0, item_sprd + 31);
1259 item_spr[32] = Z_getspr("KEYG", 0, 0, item_sprd + 32);
1260 item_spr[33] = Z_getspr("KEYB", 0, 0, item_sprd + 33);
1261 item_spr[34] = Z_getspr("SUIT", 0, 0, item_sprd + 34);
1262 for (n = 35, j = 0; j < 4; ++j) {
1263 for (i = 0; i < 4; ++i, ++n) {
1264 item_spr[n] = Z_getspr(n4[j], i, 0, item_sprd + n);
1267 for (j = 0; j < 2; ++j) {
1268 for (i = 0; i < 3; ++i, ++n) {
1269 item_spr[n] = Z_getspr(n3[j], i, 0, item_sprd + n);
1272 item_spr[57] = Z_getspr("GUN2", 0, 0, item_sprd + 57);
1273 // player
1274 for (i = 0; i < 27; ++i) {
1275 plr_spr[i * 2] = Z_getspr("PLAY", i, 1, plr_sprd + i * 2);
1276 plr_spr[i * 2 + 1] = Z_getspr("PLAY", i, 2, plr_sprd + i * 2 + 1);
1278 strncpy(s, "PWPx", 4);
1279 for (i = 1; i < 11; ++i) {
1280 s[3] = (i < 10 ? '0' : 'A' - 10) + i;
1281 for (j = 0; j < 6; ++j) {
1282 plr_wpn[i][j] = Z_getspr(s, j, 1, NULL);
1285 // monsters
1286 static char msn[MN_TN][4] = {
1287 "SARG", "TROO", "POSS", "SPOS", "CYBR", "CPOS", "BOSS", "BOS2", "HEAD", "SKUL",
1288 "PAIN", "SPID", "BSPI", "FATT", "SKEL", "VILE", "FISH", "BAR1", "ROBO", "PLAY"
1289 };
1290 static int mms[MN_TN] = {
1291 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,
1292 20*2, 17*2, 29*2, 6*2, 2*2, 17*2, 23*2
1293 };
1294 mn_sgun[0] = Z_getspr("PWP4", 0, 1, NULL);
1295 mn_sgun[1] = Z_getspr("PWP4", 1, 1, NULL);
1296 for (j = 0; j < MN_TN; ++j) {
1297 for (i = 0; i < mms[j]; ++i) {
1298 mn_spr[j][i] = Z_getspr(msn[j], i / 2, (i & 1) + 1, &mn_sprd[j][i]);
1300 if (j == MN_BARREL - 1) {
1301 for (i = 4; i < 14; ++i) {
1302 mn_spr[j][i] = Z_getspr("BEXP", i / 2 - 2, (i & 1) + 1, &mn_sprd[j][i]);
1306 for (i = 0; i < 8; ++i) {
1307 mn_fspr[i] = Z_getspr("FIRE", i, 0, NULL);
1309 pl_spr[0] = Z_getspr("PLAY", 'N' - 'A', 0, NULL);
1310 pl_spr[1] = Z_getspr("PLAY", 'W' - 'A', 0, NULL);
1311 // misc
1312 static char mnm[22][8]={
1313 "STTNUM0","STTNUM1","STTNUM2","STTNUM3","STTNUM4",
1314 "STTNUM5","STTNUM6","STTNUM7","STTNUM8","STTNUM9",
1315 "STTMINUS","STTPRCNT",
1316 "FISTA0","CSAWA0","PISTA0","SHOTA0","SGN2A0","MGUNA0","LAUNA0",
1317 "PLASA0","BFUGA0","GUN2A0"
1318 };
1319 stone=V_loadvgaimg("STONE");
1320 stone2=V_loadvgaimg("STONE2");
1321 keys[0]=V_loadvgaimg("KEYRA0");
1322 keys[1]=V_loadvgaimg("KEYGA0");
1323 keys[2]=V_loadvgaimg("KEYBA0");
1324 for (i = 0; i < 22; ++i) {
1325 sth[i] = V_loadvgaimg(mnm[i]);
1327 strcpy(s, "STBF_*");
1328 for (i = '!'; i < 160; ++i) {
1329 s[5] = i;
1330 bfh[i - '!'] = V_getvgaimg(F_findres(s));
1332 for (i = '!'; i < 160; ++i) {
1333 sprintf(s, "STCFN%03d", i);
1334 sfh[i - '!'] = V_getvgaimg(F_findres(s));
1336 strcpy(s, "WINUM*");
1337 for (i = '0'; i <= '9'; ++i) {
1338 s[5] = i;
1339 bfh[i - '!'] = V_loadvgaimg(s);
1341 bfh[':' - '!'] = V_loadvgaimg("WICOLON");
1342 // menu
1343 msklh[0] = V_loadvgaimg("M_SKULL1");
1344 msklh[1] = V_loadvgaimg("M_SKULL2");
1345 mbarl = V_loadvgaimg("M_THERML");
1346 mbarm = V_loadvgaimg("M_THERMM");
1347 mbarr = V_loadvgaimg("M_THERMR");
1348 mbaro = V_loadvgaimg("M_THERMO");
1349 mslotl = V_loadvgaimg("M_LSLEFT");
1350 mslotm = V_loadvgaimg("M_LSCNTR");
1351 mslotr = V_loadvgaimg("M_LSRGHT");
1352 // walls
1353 static char *anm[ANIT - 1][5] = {
1354 {"WALL22_1", "WALL23_1", "WALL23_2", NULL, NULL},
1355 {"WALL58_1", "WALL58_2", "WALL58_3", NULL, NULL},
1356 {"W73A_1", "W73A_2", NULL, NULL, NULL},
1357 {"RP2_1", "RP2_2", "RP2_3", "RP2_4", NULL}
1358 };
1359 for (i = 1; i < ANIT; i++) {
1360 for (j = 0; anm[i - 1][j]; j++) {
1361 anih[i][j] = F_getresid(anm[i - 1][j]);
1363 for(; j < 5; j++) {
1364 anih[i][j] = -1;
1369 void R_get_name (int n, char s[8]) {
1370 if (walh[n] == -1) {
1371 memset(s, 0, 8);
1372 } else if (walh[n] == -2) {
1373 memcpy(s, "_WATER_", 8);
1374 s[7] = (char)((intptr_t)walp[n] - 1 + '0');
1375 } else {
1376 F_getresname(s, walh[n] & 0x7FFF);
1380 static short getani (char n[8]) {
1381 if (strncasecmp(n, "WALL22_1", 8) == 0) {
1382 return 1;
1383 } else if (strncasecmp(n, "WALL58_1", 8) == 0) {
1384 return 2;
1385 } else if (strncasecmp(n, "W73A_1", 8) == 0) {
1386 return 3;
1387 } else if (strncasecmp(n, "RP2_1", 8) == 0) {
1388 return 4;
1389 } else {
1390 return 0;
1394 int R_get_special_id (int n) {
1395 assert(n >= 0 && n < 256);
1396 intptr_t x = (intptr_t)walp[n];
1397 return x >= 0 && x <= 3 ? x : -1;
1400 void R_begin_load (void) {
1401 int i;
1402 for (i = 0; i < 256; i++) {
1403 if (walp[i] != NULL && walh[i] >= 0) {
1404 M_unlock(walp[i]);
1406 walh[i] = -1;
1407 walp[i] = NULL;
1408 walswp[i] = i;
1409 walani[i] = 0;
1411 memset(anic, 0, sizeof(anic));
1412 max_textures = 1;
1415 void R_load (char s[8], int f) {
1416 assert(max_textures < 256);
1417 if (!s[0]) {
1418 walh[max_textures] = -1;
1419 walp[max_textures] = NULL;
1420 } else {
1421 if (strncasecmp(s, "_WATER_", 7) == 0) {
1422 walh[max_textures] = -2;
1423 walp[max_textures] = (void*)((intptr_t)s[7] - '0' + 1);
1424 } else {
1425 walh[max_textures] = F_getresid(s);
1426 walp[max_textures] = V_getvgaimg(walh[max_textures]);
1427 if (f) {
1428 walh[max_textures] |= 0x8000;
1430 if (s[0] == 'S' && s[1] == 'W' && s[4] == '_') {
1431 walswp[max_textures] = 0;
1434 walani[max_textures] = getani(s);
1436 max_textures++;
1439 void R_end_load (void) {
1440 int i, j, k, g;
1441 char s[8];
1442 j = max_textures;
1443 for (i = 1; i < 256 && j < 256; i++) {
1444 if (walswp[i] == 0) {
1445 R_get_name(i, s);
1446 s[5] ^= 1;
1447 g = F_getresid(s) | (walh[i] & 0x8000);
1448 k = 1;
1449 while (k < 256 && walh[k] != g) {
1450 k += 1;
1452 if (k >= 256) {
1453 k = j;
1454 j += 1;
1455 walh[k] = g;
1456 walp[k] = V_getvgaimg(g);
1457 walf[k] = g & 0x8000 ? 1 : 0;
1459 walswp[i] = k;
1460 walswp[k] = i;
1465 void R_loadsky (int sky) {
1466 char s[6];
1467 strcpy(s, "RSKY1");
1468 s[4] = '0' + sky;
1469 M_unlock(horiz);
1470 horiz = V_loadvgaimg(s);
1473 void R_setgamma(int g) {
1474 int t;
1475 g = g < 0 ? 0 : (g > 4 ? 4 : g);
1476 gammaa = g;
1477 for (t = 0; t < 256; ++t) {
1478 std_pal[t][0]=gamcor[gammaa][main_pal[t][0]];
1479 std_pal[t][1]=gamcor[gammaa][main_pal[t][1]];
1480 std_pal[t][2]=gamcor[gammaa][main_pal[t][2]];
1482 Y_set_vga_palette(std_pal);
1485 int R_getgamma (void) {
1486 return gammaa;
1489 void R_set_videomode (int w, int h, int fullscreen) {
1490 assert(w > 0);
1491 assert(h > 0);
1492 int was = Y_videomode_setted();
1493 int res = Y_set_videomode_software(w, h, fullscreen);
1494 if (res == 0) {
1495 if (was == 0) {
1496 ERR_failinit("Unable to set video mode");
1498 } else {
1499 Y_get_videomode(&SCRW, &SCRH);
1500 V_update_buffer();
1501 R_setgamma(gammaa);
1505 void R_toggle_fullscreen (void) {
1506 Y_set_fullscreen(!Y_get_fullscreen());
1507 fullscreen = Y_get_fullscreen();
1508 Y_get_videomode(&SCRW, &SCRH);
1509 V_update_buffer();
1510 R_setgamma(gammaa);
1513 static int video_menu_handler (menu_msg_t *msg, const menu_t *m, void *data, int i) {
1514 static int cur;
1515 static int w, h, fullscreen;
1516 static char buf[16];
1517 static int buflen;
1518 static int vmode;
1519 const videomode_t *v;
1520 enum { VIDEOMODE, FULLSCREEN, APPLY, __NUM__ };
1521 static const simple_menu_t sm = {
1522 GM_BIG, "Video", NULL,
1524 { "Mode: ", NULL },
1525 { "Fullscreen: ", NULL },
1526 { "Apply ", NULL },
1528 };
1529 if (msg->type == GM_ENTER) {
1530 Y_get_videomode(&w, &h);
1531 fullscreen = Y_get_fullscreen();
1532 v = Y_get_videomode_list_opengl(fullscreen);
1533 vmode = 0;
1534 while (vmode < v->n && v->modes[vmode].w != w && v->modes[vmode].h != h) {
1535 vmode += 1;
1537 if (vmode < v->n) {
1538 w = v->modes[vmode].w;
1539 h = v->modes[vmode].h;
1541 snprintf(buf, 16, "%ix%i", w, h);
1542 buflen = strlen(buf);
1543 return 1;
1545 if (i == VIDEOMODE) {
1546 switch (msg->type) {
1547 case GM_GETSTR: return GM_init_str(msg, buf, buflen);
1548 case GM_SELECT:
1549 v = Y_get_videomode_list_opengl(fullscreen);
1550 vmode = vmode + 1 >= v->n ? 0 : vmode + 1;
1551 if (v->n > 0) {
1552 w = v->modes[vmode].w;
1553 h = v->modes[vmode].h;
1554 } else {
1555 Y_get_videomode(&w, &h);
1557 snprintf(buf, 16, "%ix%i", w, h);
1558 buflen = strlen(buf);
1559 return 1;
1561 } else if (i == FULLSCREEN) {
1562 switch (msg->type) {
1563 case GM_GETSTR: return GM_init_str(msg, fullscreen ? "Yes" : "No ", 3);
1564 case GM_SELECT: fullscreen = !fullscreen; return 1;
1566 } else if (i == APPLY) {
1567 switch (msg->type) {
1568 case GM_SELECT: R_set_videomode(w, h, fullscreen); return 1;
1571 return simple_menu_handler(msg, i, __NUM__, &sm, &cur);
1574 static const menu_t video_menu = {
1575 NULL, &video_menu_handler
1576 };
1578 const menu_t *R_menu (void) {
1579 return &video_menu;
1582 const cfg_t *R_args (void) {
1583 static const cfg_t args[] = {
1584 { "fullscr", &init_screen_full, Y_SW_ON },
1585 { "window", &init_screen_full, Y_SW_OFF },
1586 { "width", &init_screen_width, Y_DWORD },
1587 { "height", &init_screen_height, Y_DWORD },
1588 { "gamma", &init_screen_gammaa, Y_DWORD },
1589 { NULL, NULL, 0 } // end
1590 };
1591 return args;
1594 const cfg_t *R_conf (void) {
1595 static const cfg_t conf[] = {
1596 { "sky", &w_horiz, Y_SW_ON },
1597 { "fullscreen", &fullscreen, Y_SW_ON },
1598 { "screen_width", &SCRW, Y_DWORD },
1599 { "screen_height", &SCRH, Y_DWORD },
1600 { "gamma", &gammaa, Y_DWORD },
1601 { NULL, NULL, 0 } // end
1602 };
1603 return conf;
1606 void R_init () {
1607 int i;
1608 logo("R_init: initialize software render\n");
1609 F_loadres(F_getresid("PLAYPAL"), main_pal, 0, 768);
1610 for (i = 0; i < 256; ++i) {
1611 bright[i] = ((int) main_pal[i][0] + main_pal[i][1] + main_pal[i][2]) * 8 / (63 * 3);
1613 F_loadres(F_getresid("MIXMAP"), mixmap, 0, 0x10000);
1614 F_loadres(F_getresid("COLORMAP"), clrmap, 0, 256*12);
1615 SCRW = init_screen_width > 0 ? init_screen_width : SCRW;
1616 SCRH = init_screen_height > 0 ? init_screen_height : SCRH;
1617 fullscreen = init_screen_full != 0xFF ? init_screen_full : fullscreen;
1618 gammaa = init_screen_gammaa >= 0 ? init_screen_gammaa : gammaa;
1619 R_set_videomode(SCRW, SCRH, fullscreen);
1620 V_setrect(0, SCRW, 0, SCRH);
1621 V_clr(0, SCRW, 0, SCRH, 0);
1622 R_alloc();
1625 void R_done (void) {
1626 buffer = NULL;
1627 buf_w = 0;
1628 buf_h = 0;
1629 pitch = 0;
1630 Y_unset_videomode();
1633 void R_switch_texture (int x, int y) {
1634 assert(x >= 0 && x < FLDW);
1635 assert(y >= 0 && y < FLDH);
1636 fldb[y][x] = walswp[fldb[y][x]];
1639 int R_get_swp (int n) {
1640 assert(n >= 0 && n < 256);
1641 return walswp[n];