1 /*
2 
3 Copyright (C) 2015-2018 Night Dive Studios, LLC.
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, either version 3 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 
18 */
19 /*
20  * $Source: u://RCS/gamerend.c $
21  * $Revision: 1.77 $
22  * $Author: xemu $
23  * $Date: 1994/11/25 08:22:19 $
24  */
25 
26 #define __GAMEREND_SRC
27 
28 #include <stdlib.h>
29 
30 #include "tools.h"
31 
32 #include "cyber.h"
33 #include "gamerend.h"
34 #include "weapons.h"
35 #include "colors.h"
36 #include "rcolors.h"
37 #include "cybstrng.h" // for resurrect text
38 #include "gamestrn.h"
39 #include "citres.h"
40 #include "gamescr.h"
41 #include "mainloop.h"
42 #include "game_screen.h"
43 #include "player.h"
44 #include "shodan.h"
45 #include "criterr.h"
46 
47 #include "cit2d.h"
48 #include "diffq.h" // for time limit
49 #include "newmfd.h"
50 #include "fullscrn.h"
51 
52 #include "grenades.h"
53 #include "hud.h"
54 #include "hand.h"
55 #include "wares.h"
56 #include "rendfx.h"
57 #include "hudobj.h" // for beam effect following
58 
59 // maybe we can not have this
60 #include "frtypes.h" // has to be before frprotox so proto gets the context for real
61 #include "frprotox.h"
62 #include "frflags.h"
63 #include "gr2ss.h"
64 
65 #include "faketime.h"
66 #include "hkeyfunc.h"
67 
68 #include "status.h"
69 #include "statics.h"
70 
71 #ifdef AUDIOLOGS
72 #include "audiolog.h"
73 #endif
74 
75 extern uchar tmap_big_buffer[];
76 
77 // prototypes
78 void set_shield_raisage(uchar going_up);
79 void begin_shodan_conquer_fx(uchar begin);
80 void set_dmg_percentage(int which, ubyte percent);
81 void do_secret_fx(void);
82 void gamesys_render_effects(void);
83 uchar use_ir_hack(void);
84 void draw_single_static_line(uchar *line_base, int lx, int rx, int c_base);
85 void draw_line_static(grs_bitmap *stat_dest, int dens1, int color1);
86 void draw_full_static(grs_bitmap *stat_dest, int c_base);
87 uchar gamesys_draw_func(void *fake_dest_canvas, void *fake_dest_bm, int x, int y, int flags);
88 void gamesys_render_func(void *fake_dest_bitmap, int flags);
89 
gamerend_init(void)90 errtype gamerend_init(void) {
91     handart_show = 1;
92     return (OK);
93 }
94 
95 // note these are now 0-255, like all computer percentages should be...
96 static ubyte fr_sfx_color;
97 static ubyte dmg_percentage;
98 static char shield_raisage;
99 
set_shield_raisage(uchar going_up)100 void set_shield_raisage(uchar going_up) {
101     if (going_up)
102         shield_raisage = 1;
103     else
104         shield_raisage = -15;
105     fr_global_mod_flag(FR_SFX_SHIELD, FR_SFX_MASK);
106 }
107 
begin_shodan_conquer_fx(uchar begin)108 void begin_shodan_conquer_fx(uchar begin) {
109     if (begin)
110         fr_global_mod_flag(FR_OVERLAY_SHODAN, FR_OVERLAY_MASK);
111     else
112         fr_global_mod_flag(0, FR_OVERLAY_SHODAN);
113 }
114 
115 uchar color_base[] = {BLUE_8_BASE, RED_8_BASE, GREEN_8_BASE};
116 
117 #define MIN_STATIC 10
118 
set_dmg_percentage(int which,ubyte percent)119 void set_dmg_percentage(int which, ubyte percent) {
120     if (percent > dmg_percentage) {
121         fr_sfx_color = color_base[which];
122         dmg_percentage = percent;
123         if (dmg_percentage < MIN_STATIC)
124             dmg_percentage = MIN_STATIC;
125         fr_global_mod_flag(FR_SFX_STATIC, FR_SFX_MASK);
126     }
127 }
128 
129 // -----------------------------------------------
130 // beam_effect_update()
131 //
132 
133 extern ObjID beam_effect_id;
134 
135 #define PRE_FINAL_DEATH    0x1A
136 #define DYING_FRAMES       0x20
137 #define REBORN_VISION_TICK 0x10
138 #define REBORN_FRAMES      0x18
139 #define FAKEWIN_FRAMES     0x30
140 
141 #define FAKEWIN_NUM_FONT    RES_bigLEDFont
142 #define FAKEWIN_TEXT_FONT   RES_readingFont
143 #define FAKEWIN_EMAIL_MUNGE 0x01c
144 #define FAKEWIN_PAPER       0x8
145 #define FAKEWIN_STRING_BASE REF_STR_fakewinStrings
146 
147 extern uchar kill_player(void);
148 
149 // about a quarter second, really
150 #define V_CLOCK 0x040
151 #define V_MASK (~0x03f)
152 
153 #define build_systems_y_coor(i) (5 + (14 * i))
154 
155 static uchar systems_line_colors[] = {RED_8_BASE, RED_8_BASE + 3, ORANGE_8_BASE, ORANGE_8_BASE + 3, GREEN_8_BASE};
156 
157 //#define NUM_SYS_LINES ((sizeof(systems_lines)/sizeof(systems_lines[0])))
158 // There is probably a clever way to get this out of the resource, but this is much simpler...
159 #define NUM_SYS_LINES 5
160 #define SYSTEM_BASE REF_STR_ResurrectBase
161 #define LINE_BUF_SIZE 40
162 
163 #define STATUS_CHI_AMP 8
164 
165 #define CURRENT_VIEW_W (_current_view->r->lr.x - _current_view->r->ul.x)
166 #define CURRENT_VIEW_H (_current_view->r->lr.y - _current_view->r->ul.y)
167 
168 extern uchar flatline_heart;
169 extern uchar chi_amp;
170 
171 extern void regenerate_player(void);
172 ulong secret_sfx_time;
do_secret_fx(void)173 void do_secret_fx(void) { // boy is this a hack....
174     static char dot_buf[] = "........";
175     static char tmp_buf[] = "99";
176     static grs_font *fx_font = NULL;
177     static long sfx_time = 0;
178     int c_val = secret_render_fx & VAL_REND_SFX, i, cap;
179     char line_buf[LINE_BUF_SIZE];
180     Ref str;
181 
182     if (fx_font == NULL)
183         fx_font = ResLock(RES_mfdFont);
184     switch (secret_render_fx & TYPE_REND_SFX) {
185     case DYING_REND_SFX: // chevron drain, perhaps dim out, view rock at end.....
186         secret_render_fx++;
187         flatline_heart = TRUE;
188         chi_amp = STATUS_CHI_AMP * (DYING_FRAMES - c_val) / DYING_FRAMES;
189         if (c_val == DYING_FRAMES) {
190             if (kill_player()) {
191                 secret_render_fx = 0;
192                 player_struct.dead = FALSE;
193                 flatline_heart = FALSE;
194                 chi_amp = STATUS_CHI_AMP;
195             } else {
196                 secret_render_fx = REBORN_REND_SFX;
197                 fr_global_mod_flag(FR_SOLIDFR_SLDKEEP, FR_SOLIDFR_MASK | FR_SFX_MASK);
198                 fr_solidfr_color = 0xff;
199                 dmg_percentage = 0;
200                 regenerate_player();
201             }
202         } else {
203             if (c_val >= PRE_FINAL_DEATH)
204                 fr_global_mod_flag(FR_SOLIDFR_STATIC, FR_SOLIDFR_MASK);
205             dmg_percentage = 20 + (c_val << 2);
206             fr_global_mod_flag(FR_SFX_STATIC, FR_SFX_MASK);
207         }
208         break;
209     case REBORN_REND_SFX: // add chevron growth, lighting and dimming, starting on back...
210         gr_set_font(fx_font);
211         cap = c_val >> 2;
212         if (cap >= NUM_SYS_LINES)
213             cap = NUM_SYS_LINES;
214         for (i = 0; i < cap; i++) {
215             gr_set_fcolor(systems_line_colors[i]);
216             ss_string(dot_buf, 30, build_systems_y_coor(i));
217             ss_string(get_string(str = (SYSTEM_BASE + i), line_buf, LINE_BUF_SIZE), 56, build_systems_y_coor(i));
218         }
219         if (str == REF_STR_StartHeartString)
220             flatline_heart = FALSE;
221         else if (str == REF_STR_StartBrainString)
222             chi_amp = STATUS_CHI_AMP;
223         if (c_val < REBORN_VISION_TICK) {
224             gr_set_fcolor(systems_line_colors[i]);
225             dot_buf[c_val & 7] = '\0';
226             ss_string(dot_buf, 30, build_systems_y_coor(i));
227             dot_buf[c_val & 7] = '.';
228         }
229 
230         if (*tmd_ticks - sfx_time > V_CLOCK) {
231             secret_render_fx++;
232             if (c_val == REBORN_FRAMES) {
233                 extern errtype spoof_mouse_event(void);
234                 extern uchar music_on;
235                 secret_render_fx = 0;
236 
237                 // look - we should say the player is no longer dead!
238                 player_struct.dead = FALSE;
239                 uiFlush();
240                 // KLC           spoof_mouse_event();
241                 if (music_on)
242                     start_music();
243                 break;
244             } else if (c_val == REBORN_VISION_TICK)
245                 fr_global_mod_flag(0, FR_SOLIDFR_MASK);
246 
247             sfx_time = (*tmd_ticks) & V_MASK;
248         }
249         break;
250     case TIMELIMIT_REND_SFX: {
251         grs_font *f;
252         short w, h;
253         int stage = (MISSION_3_TICKS - player_struct.game_time) / CIT_CYCLE;
254 
255         tmp_buf[0] = tmp_buf[1] = '0';
256         f = ResLock(FAKEWIN_NUM_FONT);
257         gr_set_font(f);
258         gr_string_size(tmp_buf, &w, &h);
259 
260         if (stage < 0 || stage > 99)
261             stage = 0;
262         tmp_buf[0] = '0' + stage / 10;
263         tmp_buf[1] = '0' + stage % 10;
264         draw_shadowed_string(tmp_buf, (CURRENT_VIEW_W - w) / 2, (CURRENT_VIEW_H - h) / 2, TRUE);
265         ResUnlock(FAKEWIN_NUM_FONT);
266         break;
267     }
268     case FAKEWIN_REND_SFX: // do stuff
269     {
270         char stage = (*tmd_ticks - secret_sfx_time) / CIT_CYCLE;
271         gr_set_fcolor(RED_BASE + 6);
272         if (stage < 2)
273             break;
274         if (stage < 5) {
275             res_draw_string(FAKEWIN_TEXT_FONT, FAKEWIN_STRING_BASE, 30, 20);
276             res_draw_string(FAKEWIN_TEXT_FONT, FAKEWIN_STRING_BASE + 1, 50, 45);
277             break;
278         }
279         if (stage < 18) {
280             if ((stage > 10) && (c_val == 0)) {
281                 fr_global_mod_flag(FR_SFX_SHAKE, FR_SFX_MASK);
282                 secret_render_fx++;
283             }
284             res_draw_string(FAKEWIN_TEXT_FONT, FAKEWIN_STRING_BASE + 2, 50, 30);
285             tmp_buf[0] = '0' + ((20 - stage) / 10);
286             tmp_buf[1] = '0' + ((20 - stage) % 10);
287             res_draw_text(FAKEWIN_NUM_FONT, tmp_buf, 85, 45);
288             res_draw_string(FAKEWIN_TEXT_FONT, FAKEWIN_STRING_BASE + 3, 95, 80);
289             break;
290         }
291         if (stage < 22) {
292             if (c_val == 1) {
293                 extern void long_bark(ObjID speaker_id, uchar mug_id, int string_id, ubyte color);
294                 extern void add_email_datamunge(short mung, uchar select);
295                 extern void read_email(Id new_base, int num);
296                 fr_global_mod_flag(FR_SFX_SHAKE, FR_SFX_MASK);
297                 long_bark(OBJ_NULL, FIRST_SHODAN_MUG + 3, REF_STR_Null, 0);
298                 mfd_change_slot(MFD_LEFT, MFD_INFO_SLOT);
299                 mfd_change_slot(MFD_RIGHT, MFD_INFO_SLOT);
300 // KLC-duplicate mail               add_email_datamunge(FAKEWIN_EMAIL_MUNGE, FALSE);
301 #ifdef AUDIOLOGS
302                 if (audiolog_setting)
303                     audiolog_play(FAKEWIN_EMAIL_MUNGE);
304                 if (audiolog_setting != 1)
305 #endif
306                     read_email(RES_paper0, FAKEWIN_PAPER);
307                 fr_global_mod_flag(0, FR_SFX_MASK);
308                 secret_render_fx++;
309             }
310             gr_set_fcolor(RED_BASE + 6);
311             res_draw_string(FAKEWIN_TEXT_FONT, FAKEWIN_STRING_BASE + 4, 75, 50);
312             break;
313         } else {
314             secret_render_fx = 0;
315         }
316     } break;
317     }
318     if (secret_render_fx == 0) // why must we unset both
319     {
320         ResUnlock(RES_mfdFont);
321         fx_font = NULL;
322         chg_unset_sta(GL_CHG_2);
323         chg_unset_flg(GL_CHG_2);
324     }
325 }
326 
327 extern short mouse_attack_x;
328 extern short mouse_attack_y;
329 extern ulong next_fire_time;
330 extern uchar overload_beam;
331 extern uchar saveload_static;
332 extern bool DoubleSize;
333 
334 byte beam_offset[NUM_BEAM_GUN] = {-12, -8, -4};
335 #define DRAW_BEAM_LINE(c1, c2, c3, c4)                                                               \
336     {                                                                                                \
337         a = mx + (c1);                                                                               \
338         b = my + (c2);                                                                               \
339         ss_point_convert(&a, &b, TRUE);                                                              \
340         ss_thick_fix_line(fix_make(a, 0), fix_make(b, 0), fix_make(deltax + (c3) + boff + beamx, 0), \
341                           fix_make(deltay + (c4) + boff + 6, 0));                                    \
342     }
343 
344 /*
345 #define DRAW_BEAM_LINE(c1,c2,c3,c4) { \
346      a = mx+(c1);\
347      b = my+(c2);\
348      if (DoubleSize) \
349         gr_fix_line(fix_make(a,0),fix_make(b,0),fix_make(deltax+(c3)+boff,0), fix_make(deltay+22,0));\
350      else \
351      { \
352         ss_point_convert(&a,&b,TRUE);\
353         ss_thick_fix_line(fix_make(a,0),fix_make(b,0),fix_make(deltax+(c3)+boff,0),fix_make(deltay+(c4)+boff,0));\
354      } \
355 }
356 */
357 
gamesys_render_effects(void)358 void gamesys_render_effects(void) {
359     Ref temp;
360     int deltax, deltay, beamx;
361     short mx, my;
362     extern uchar full_game_3d;
363 
364     TRACE("%s: gamerend", __FUNCTION__);
365 
366     if ((!global_fullmap->cyber) && (!secret_render_fx)) {
367         ubyte active = player_struct.actives[ACTIVE_WEAPON];
368         extern uchar hack_takeover;
369         extern ulong player_death_time;
370 
371         // check to make sure we have an active weapon before drawing handart
372         if ((player_struct.weapons[active].type != EMPTY_WEAPON_SLOT) && !hack_takeover && !saveload_static) {
373             // For hand-to-hand weapons, draw them in the center of the screen.
374             if (player_struct.weapons[active].type == GUN_SUBCLASS_HANDTOHAND) {
375                 mx = (SCREEN_VIEW_WIDTH / 2) + SCREEN_VIEW_X;
376                 my = (SCREEN_VIEW_Y);
377                 ss_point_convert(&mx, &my, TRUE);
378             } else if (handart_show != 1) // Use mouse position for other weapons
379             {
380                 mx = mouse_attack_x;
381                 my = mouse_attack_y;
382                 if (!DoubleSize)
383                     ss_point_convert(&mx, &my, TRUE);
384                 else
385                     ui_mouse_get_xy(&mx, &my);
386             } else // Not showing a weapon
387             {
388                 ui_mouse_get_xy(&mx, &my);
389             }
390 
391             // Get the weapon art to draw.
392             temp = get_handart(&deltax, &deltay, &beamx, mx, my);
393             if (temp != ID_NULL) {
394                 extern uchar ready_to_draw_handart(void);
395 
396                 if (handart_show != 1) // are we showing an attack frame?
397                 {
398                     // If this is a beam weapon, we need to draw the beam during attack.
399                     if (player_struct.weapons[active].type == GUN_SUBCLASS_BEAM) {
400                         short base_color = (overload_beam) ? BLUE_BASE : TURQUOISE_BASE;
401                         byte boff = beam_offset[player_struct.weapons[active].subtype];
402 
403                         if (beam_effect_id) {
404                             int i;
405                             uchar draw_beam = FALSE;
406 
407                             for (i = 0; i < current_num_hudobjs; i++) {
408                                 struct _hudobj_data *dat = &hudobj_vec[i];
409                                 if ((dat->id == beam_effect_id) && beam_effect_id) {
410                                     mx = (dat->xl + dat->xh) / 2;
411                                     my = (dat->yl + dat->yh) / 2;
412                                     if (DoubleSize) {
413                                         mx *= 2;
414                                         my *= 2;
415                                     }
416                                     draw_beam = TRUE;
417                                 }
418                             }
419                             if (draw_beam) {
420                                 short a, b;
421 
422                                 gr_set_fcolor(base_color + 5);
423                                 if (overload_beam) {
424                                     DRAW_BEAM_LINE(-2, 0, 17, 12);
425                                     gr_set_fcolor(base_color + 1);
426                                 }
427                                 DRAW_BEAM_LINE(-1, 0, 18, 12);
428                                 gr_set_fcolor(base_color + 1);
429                                 DRAW_BEAM_LINE(0, 0, 19, 12);
430                                 if (!overload_beam)
431                                     gr_set_fcolor(base_color + 5);
432                                 DRAW_BEAM_LINE(1, 0, 20, 12);
433 
434                                 if (overload_beam) {
435                                     gr_set_fcolor(base_color + 5);
436                                     DRAW_BEAM_LINE(2, 0, 21, 12);
437                                 }
438                             }
439                         }
440                     }
441                 }
442                 if ((handart_show != 1) || ready_to_draw_handart()) {
443                     // draw_hires_resource_bm(temp, SCONV_X(deltax), SCONV_Y(deltay));
444                     draw_res_bm(temp, deltax, deltay);
445                     notify_draw_handart();
446                 }
447             }
448         }
449     }
450 
451     // Redraw hud displays as appropriate
452     // HOW ABOUT A FLAG HERE, NOT HARDCODED LOOP NUMBERS
453     if (!secret_render_fx && _current_loop <= FULLSCREEN_LOOP) {
454         hud_update(FALSE, _current_fr_context);
455     }
456 
457     if (secret_render_fx)
458         do_secret_fx();
459 
460     // draw the gamescreen border
461     if (!full_game_3d) {
462         // was draw_hires_resource_bm
463         draw_res_bm(REF_IMG_bm3dBackground1, 0, -2);
464         draw_res_bm(REF_IMG_bm3dBackground2, 226, -1);
465         draw_res_bm(REF_IMG_bm3dBackground2, 270, -1);
466         draw_res_bm(REF_IMG_bm3dBackground3, 522, -2);
467         draw_res_bm(REF_IMG_bm3dBackground4, 0, 197);
468 
469         // whoop whoop whoop!
470         // hack alert!  hack alert!
471         if (convert_use_mode == 3) {
472             draw_res_bm(REF_IMG_bm3dBackground5, 27, 257);
473             draw_res_bm(REF_IMG_bm3dBackground6, 415, 257);
474         }
475     } else
476         fullscreen_overlay();
477 }
478 
use_ir_hack(void)479 uchar use_ir_hack(void) { return (WareActive(player_struct.hardwarez_status[HARDWARE_GOGGLE_INFRARED])); }
480 
481 //#pragma aux c_ror_by_5 = "ror eax,5" parm [eax] modify exact [eax];
482 
483 // stolen from RND.LIB, without shift gruesomeness...
484 #define LC16_MULT 2053
485 #define LC16_ADD 13849
486 
draw_single_static_line(uchar * line_base,int lx,int rx,int c_base)487 void draw_single_static_line(uchar *line_base, int lx, int rx, int c_base) {
488     uchar *cur_pix;
489     int our_seed = rand();
490     for (cur_pix = line_base + lx; lx < rx; lx++, cur_pix++) {
491 #ifdef SIMPLE_LC_WAY
492         our_seed = (our_seed * LC16_MULT) + LC16_ADD;
493         if (our_seed & 0x300) // 3/4 are colored
494             *cur_pix = c_base + (our_seed & 0x7);
495         else // 1/4 black
496             *cur_pix = 0;
497 #else
498         if (our_seed & 0x300) {
499             *cur_pix = c_base + (our_seed & 0x7);
500             our_seed += (long)cur_pix;
501             our_seed = ((our_seed >> 5) & 0x07ffffff) | (our_seed << 27); //ror by 5
502         } else {
503             *cur_pix = 0;
504             our_seed += (our_seed * LC16_MULT) + LC16_ADD;
505         }
506 //       { *cur_pix=0; our_seed+=rand(); }
507 #endif
508     }
509 }
510 
511 #define LAST_INITIAL 32
512 // probably have to split it up, and then have a static pass and a translucency pass...
draw_line_static(grs_bitmap * stat_dest,int dens1,int color1)513 void draw_line_static(grs_bitmap *stat_dest, int dens1, int color1) {
514     int y, last = 0, lx, rx, cwid = stat_dest->w;
515     uchar *line_base;
516 
517     dens1 >>= 1;
518     for (line_base = stat_dest->bits, y = 0; y < stat_dest->h; y++, line_base += stat_dest->row) {
519         if ((last == LAST_INITIAL) || ((rand() & 0xff) < (dens1 + last))) {
520             lx = (rand() & 0xff) - 0x80;
521             if (lx > cwid)
522                 lx = cwid - (lx & 0x1f);
523             if (lx < 0)
524                 lx = 0;
525             rx = (rand() & 0xff) - 0x80;
526             if (rx > cwid)
527                 rx = cwid - (rx & 0x1f);
528             if (rx < 0)
529                 rx = 0;
530             rx = cwid - rx;
531             if (rx < lx) {
532                 if (cwid - lx > rx)
533                     lx = 0;
534                 else {
535                     lx = rx;
536                     rx = cwid;
537                 } // gnosis move
538             }
539             draw_single_static_line(line_base, lx, rx, color1);
540             if (last == 0)
541                 last = LAST_INITIAL;
542             else if (last > 1)
543                 last >>= 1; // decay repeat freq, stop at 1
544         } else
545             last = 0;
546     }
547 }
548 
draw_full_static(grs_bitmap * stat_dest,int c_base)549 void draw_full_static(
550     grs_bitmap *stat_dest,
551     int c_base) { // note we do this as a for, not a big fill, so it will work with row hacks, full screen, so on....
552     uchar *line_base;
553     int y;
554 
555     for (line_base = stat_dest->bits, y = 0; y < stat_dest->h; y++, line_base += stat_dest->row)
556         draw_single_static_line(line_base, 0, stat_dest->w, c_base);
557 }
558 
559 #define TELEPORT_COLOR 0x1C
560 #define VHOLD_SHIFT_AMOUNT 7
561 short vhold_shift = 0;
562 
563 #define FULL_CONVERT_X
564 
565 // returns whether to send the bitmap out in the render
gamesys_draw_func(void * fake_dest_canvas,void * fake_dest_bm,int x,int y,int flags)566 uchar gamesys_draw_func(void *fake_dest_canvas, void *fake_dest_bm, int x, int y, int flags) {
567     extern void hud_do_objs(short xtop, short ytop, short xwid, short ywid, uchar rev);
568     grs_canvas *dest_canvas = (grs_canvas *)fake_dest_canvas;
569     grs_bitmap *dest_bm = (grs_bitmap *)fake_dest_bm;
570     uchar *orig_bits;
571     int orig_h, loop, orig_w;
572 
573     TRACE("%s: gamerend", __FUNCTION__);
574 
575     if (flags & FR_WINDOWD_MASK)
576         gamesys_render_effects(); // static gets drawn over window dressing due to this
577     else
578         hud_do_objs(x, y, dest_bm->w, dest_bm->h, (flags & FR_DOHFLIP_MASK) != 0);
579 
580     if (flags & FR_DOUBLEB_MASK) // looks like a bug to me, eh?
581     {
582         switch (flags & FR_SFX_MASK) {
583         case FR_SFX_VHOLD:
584             (*fr_mouse_hide)();
585             gr_set_canvas(dest_canvas);
586 
587             // Save off original state
588             orig_bits = dest_bm->bits;
589             orig_h = dest_bm->h;
590 
591             // KLC - adjust x and y if in doublesize mode.
592             if (DoubleSize) {
593                 x *= 2;
594                 y *= 2;
595                 if (y > 0)
596                     y++; // It's one off in slot view.
597             }
598 
599             // Note that all of this contrivance to keep vhold_shift in original
600             // 320x200 coordinates is to avoid the wacky class of bugs of
601             // shifting screen mode in the middle of an EMP grenade
602             {
603                 short vhs = vhold_shift;
604                 if (convert_use_mode)
605                     vhs = SCONV_Y(vhold_shift);
606 
607                 // Draw top bitmap
608                 dest_bm->bits += dest_bm->row * (orig_h - vhs);
609                 dest_bm->h = vhs;
610                 if (dest_bm->h != 0)
611                     gr_bitmap(dest_bm, x, y);
612 
613                 // Draw bottom bitmap
614                 dest_bm->bits = orig_bits;
615                 dest_bm->h = orig_h - vhs;
616                 if (dest_bm->h != 0)
617                     gr_bitmap(dest_bm, x, y + vhs);
618 
619                 // Restore state & increment shift
620                 dest_bm->h = orig_h;
621                 if (convert_use_mode)
622                     vhold_shift += SCONV_Y(VHOLD_SHIFT_AMOUNT);
623                 else
624                     vhold_shift += VHOLD_SHIFT_AMOUNT;
625                 if (convert_use_mode)
626                     vhs = SCONV_Y(vhold_shift);
627                 else
628                     vhs = vhold_shift;
629                 if (vhs > orig_h)
630                     vhold_shift = 0;
631             }
632             (*fr_mouse_show)();
633             return FALSE;
634         case FR_SFX_STATIC:
635             draw_line_static(dest_bm, dmg_percentage, fr_sfx_color);
636             dmg_percentage >>= 2;
637             if (dmg_percentage == 0)
638                 fr_global_mod_flag(0, FR_SFX_MASK);
639             break;
640         case FR_SFX_TELEPORT: {
641             uchar *p = dest_bm->bits;
642             int count = 0;
643             while (count < (dest_bm->w * dest_bm->h)) {
644                 *p = TELEPORT_COLOR + (rand() & 0x3);
645                 p++;
646                 count++;
647             }
648         } break;
649         case FR_SFX_SHIELD:
650             orig_h = (dest_bm->h >> 1) - (dest_bm->h >> 5) * abs(shield_raisage);
651             orig_w = (dest_bm->w >> 1) - (dest_bm->w >> 5) * abs(shield_raisage);
652             orig_bits = dest_bm->bits;
653             for (loop = 1; loop < 5; loop++) {
654                 draw_single_static_line(orig_bits + (orig_h + loop) * dest_bm->w, orig_w + loop,
655                                         dest_bm->w - orig_w - loop, BLUE_8_BASE);
656                 draw_single_static_line(orig_bits + (dest_bm->h - (orig_h + loop)) * dest_bm->w, orig_w + loop,
657                                         dest_bm->w - orig_w - loop, BLUE_8_BASE);
658             }
659             if (shield_raisage & 0xf)
660                 shield_raisage++;
661             else
662                 fr_global_mod_flag(0, FR_SFX_MASK);
663             break;
664         }
665         switch (flags & FR_OVERLAY_MASK) {
666         case FR_OVERLAY_SHODAN: {
667             int i;
668             extern uchar *shodan_bitmask;
669             extern grs_bitmap shodan_draw_fs;
670             extern grs_bitmap shodan_draw_normal;
671             extern char thresh_fail;
672             uchar *shodan_draw_bits;
673             grs_bitmap *curr_shodan;
674             short shodan_level = (player_struct.game_time - time_until_shodan_avatar) >> SHODAN_TIME_SHIFT;
675             if (shodan_level > MAX_SHODAN_LEVEL)
676                 shodan_level = MAX_SHODAN_LEVEL;
677             if (full_game_3d) {
678                 curr_shodan = &shodan_draw_fs;
679                 shodan_draw_bits = shodan_draw_fs.bits;
680             } else {
681                 curr_shodan = &shodan_draw_normal;
682                 shodan_draw_bits = shodan_draw_normal.bits;
683             }
684             if ((thresh_fail) || ((rand() & 0x1FF) == 1)) {
685 #ifdef SVGA_SUPPORT
686                 if (convert_use_mode) {
687                     grs_bitmap temp_bm;
688 
689                     // Note that we can use this since we know that audiologs aren't playing
690                     // and that we don't want normal texture maps
691                     gr_init_bitmap(&temp_bm, tmap_big_buffer, BMT_FLAT8, BMF_TRANS, curr_shodan->w, curr_shodan->h);
692 
693                     for (i = 0; i < temp_bm.h * temp_bm.w; i = i + ((thresh_fail) ? 1 : 2))
694                         *(temp_bm.bits + i) = *(shodan_draw_bits + i);
695 
696                     // Copy in and scale up the snowy bitmap
697                     ss_bitmap(&temp_bm, 0, 0);
698                 } else
699 #endif
700                 {
701                     for (i = 0; i < dest_bm->h * dest_bm->w; i = i + ((thresh_fail) ? 1 : 2))
702                         *(dest_bm->bits + i) = *(shodan_draw_bits + i);
703                 }
704             } else {
705 #ifdef SVGA_SUPPORT
706                 if (convert_use_mode) {
707                     grs_bitmap temp_bm;
708 
709                     // Note that we can use this since we know that audiologs aren't playing
710                     // and that we don't want normal texture maps
711                     gr_init_bitmap(&temp_bm, tmap_big_buffer, BMT_FLAT8, BMF_TRANS, curr_shodan->w, curr_shodan->h);
712 
713                     for (i = 0; i < temp_bm.h * temp_bm.w; i++) {
714                         if (SHODAN_CONQUER_GET(shodan_bitmask, i))
715                             *(temp_bm.bits + i) = *(shodan_draw_bits + i);
716                         else
717                             *(temp_bm.bits + i) = 0;
718                     }
719                     // Copy in and scale up the snowy bitmap
720                     ss_bitmap(&temp_bm, 0, 0);
721                 } else
722 #endif
723                 {
724                     for (i = 0; i < dest_bm->h * dest_bm->w; i++) {
725                         if (SHODAN_CONQUER_GET(shodan_bitmask, i))
726                             *(dest_bm->bits + i) = *(shodan_draw_bits + i);
727                     }
728                 }
729             }
730         } break;
731         }
732     }
733 
734     return TRUE; // let the renderer do the blit
735 }
736 
gamesys_render_func(void * fake_dest_bitmap,int flags)737 void gamesys_render_func(void *fake_dest_bitmap, int flags) {
738     grs_bitmap *dest_bitmap = (grs_bitmap *)fake_dest_bitmap;
739     grs_canvas temp_canvas;
740 
741     gr_make_canvas(dest_bitmap, &temp_canvas);
742     gr_push_canvas(&temp_canvas);
743     switch (flags & FR_SOLIDFR_MASK) {
744     case FR_SOLIDFR_SLDCLR: // if clearing, reset the mask
745         fr_global_mod_flag(0, FR_SOLIDFR_MASK);
746     case FR_SOLIDFR_SLDKEEP: // else just clear to the color
747         gr_clear(fr_solidfr_color);
748         break;
749     case FR_SOLIDFR_STATIC:
750         draw_full_static(dest_bitmap, GRAY_8_BASE);
751         break;
752     }
753     gr_pop_canvas();
754 }
755