1 /*
2 Copyright (C) 1994-1995 Apogee Software, Ltd.
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
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.
12 
13 See the 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, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #ifdef DOS
22 #include <dos.h>
23 #include <io.h>
24 #include <conio.h>
25 #endif
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 
32 #include "rt_def.h"
33 #include "rt_main.h"
34 #include "rt_game.h"
35 #include "_rt_game.h"
36 #include "rt_menu.h"
37 #include "z_zone.h"
38 #include "w_wad.h"
39 #include "lumpy.h"
40 #include "rt_playr.h"
41 #include "rt_util.h"
42 #include "rt_ted.h"
43 #include "rt_draw.h"
44 #include "rt_view.h"
45 #include "rt_vid.h"
46 #include "rt_door.h"
47 #include "rt_in.h"
48 #include "rt_str.h"
49 #include "isr.h"
50 #include "rt_build.h"
51 #include "rt_rand.h"
52 #include "rt_cfg.h"
53 #include "rt_sound.h"
54 #include "version.h"
55 #include "rt_crc.h"
56 #include "modexlib.h"
57 #include "engine.h"
58 #include "gmove.h"
59 #include "rt_com.h"
60 #include "rt_net.h"
61 #include "watcom.h"
62 #include "rt_floor.h"
63 #include "rt_msg.h"
64 #include "rt_scale.h"
65 #include "develop.h"
66 //MED
67 #include "memcheck.h"
68 
69 #if (SHAREWARE == 1)
70 #define NUMAMMOGRAPHICS 10
71 #else
72 #define NUMAMMOGRAPHICS 20
73 #endif
74 
75 //******************************************************************************
76 //
77 // GLOBALS
78 //
79 //******************************************************************************
80 
81 int PlayerSnds[5] = {SD_PLAYERTCSND, SD_PLAYERTBSND, SD_PLAYERDWSND,
82                      SD_PLAYERLNSND, SD_PLAYERIPFSND};
83 
84 
85 int SHAKETICS   = 0xFFFF;
86 int damagecount = 0;
87 HighScore   Scores[MaxScores] =
88 				{
89                {"Tom",70000,7,1},
90                {"Chuck",60000,6,1},
91                {"Mark",50000,5,1},
92                {"The Joes",40000,4,1},
93                {"William",30000,3,1},
94                {"Jim",20000,2,1},
95                {"Steve",10000,1,1},
96             };
97 
98 
99 //******************************************************************************
100 //
101 // LOCALS
102 //
103 //******************************************************************************
104 
105 static int KeyX[4]  = {KEY1_X, KEY2_X, KEY3_X, KEY4_X};
106 
107 static char *Names[ 5 ] =
108    {
109    "Taradino", "Thi",     "Doug",  "Lorelei", "Ian Paul"
110    };
111 
112 static char *LastNames[ 5 ] =
113    {
114    "Cassatt",  "Barrett", "Wendt", "Ni",      "Freeley"
115    };
116 
117 static STR ScoreStr;
118 static STR LivesStr;
119 static STR TriadStr;
120 static STR KillStr;
121 
122 static pic_t *lifeptnums[10];
123 static pic_t *lifenums[10];
124 static pic_t *timenums[10];
125 static pic_t *scorenums[10];
126 static pic_t *keys[4];
127 static pic_t *men[5];
128 
129 static pic_t *health[6];
130 static pic_t *ammo[26];
131 static pic_t *erase;
132 static pic_t *eraseb;
133 static pic_t *fragpic[ 5 ];
134 static pic_t *frag100pic[ 5 ];
135 static pic_t *negfragpic[ 5 ];
136 static pic_t *menneg[ 5 ];
137 static pic_t *blankfragpic;
138 
139 static int powerpics;
140 static int poweradjust;
141 
142 static int poweruptime;
143 static int powerupheight;
144 static int protectiontime;
145 static int protectionheight;
146 
147 
148 static boolean EndLevelStuff = false;
149 static boolean borderset     = false;
150 static int oldsec            = -1;
151 
152 static pic_t *BkPic;
153 int SaveTime = 0;
154 int oldhealth;
155 
156 static int oldplayerhealth;
157 static int oldpercenthealth;
158 
159 static int playeruniformcolor;
160 
161 #define NUMBONUSES   11
162 #define BONUSBONUS   100000
163 
164 void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly);
165 
166 //******************************************************************************
167 //
168 // V_ReDrawBkgnd ()
169 //
170 //******************************************************************************
171 
V_ReDrawBkgnd(int x,int y,int width,int height,boolean shade)172 void V_ReDrawBkgnd (int x, int y, int width, int height, boolean shade)
173 {
174    byte *src;
175    byte *dest;
176    byte *origdest;
177    int j,
178        k,
179        planes,
180        mask,
181        m;
182 
183    m = (x&3);
184    mask = (1 << m);
185 
186 #ifdef DOS
187    origdest = (byte *)(bufferofs+ylookup[y]+(x>>2));
188 #else
189    origdest = (byte *)(bufferofs+ylookup[y]+x);
190 #endif
191 
192    if (VW_MarkUpdateBlock (x, y, x+width-1, y+height-1))
193    {
194       for (planes = 0; planes < 4; planes++)
195       {
196          src = (&(BkPic->data)+((80*200)*m)+(80*y)+(x>>2));
197          dest = origdest;
198 
199 #ifdef DOS
200          VGAMAPMASK (mask);
201 #else
202          dest += planes;
203 #endif
204 
205          for (j = 0; j < height; j++)
206          {
207             for (k = 0; k < (width/4); k++) {
208                if (shade) {
209                   *dest = *(colormap + ((MENUSHADELEVEL>>2)<<8) + *src++);
210                } else {
211                   *dest = *src++;
212                }
213 #ifdef DOS
214                dest++;
215 #else
216                dest += 4;
217 #endif
218             }
219 
220 #ifndef DOS
221             // draw the remainder.  did the DOS version even bother? - SBF
222             if ((width & 3) > planes) {
223                if (shade) {
224                   *dest = *(colormap + ((MENUSHADELEVEL>>2)<<8) + *src);
225                } else {
226                   *dest = *src;
227                }
228             }
229 #endif
230 
231 	    src += (80-(width/4));
232 #ifdef DOS
233             dest += (linewidth-(width/4));
234 #else
235             dest += (linewidth-(width&~3));
236 #endif
237          }
238 
239          m++;
240 
241          mask <<= 1;
242 
243          if (mask == 16)
244          {
245             x+=4;
246             mask = 1;
247             m = 0;
248 #ifdef DOS
249             origdest++;
250 #endif
251          }
252       }
253    }
254 }
255 
256 
257 //******************************************************************************
258 //
259 // CacheLumpGroup ()
260 //
261 //******************************************************************************
CacheLumpGroup(char * startlump,pic_t ** lumparray,int numberoflumps)262 void CacheLumpGroup
263    (
264    char   *startlump,
265    pic_t **lumparray,
266    int     numberoflumps
267    )
268 
269    {
270    int lumpnum;
271    int i;
272 
273    lumpnum = W_GetNumForName( startlump );
274 
275    for( i = 0; i < numberoflumps; i++ )
276       {
277       lumparray[ i ] = ( pic_t * )W_CacheLumpNum( lumpnum + i, PU_LEVEL, Cvt_pic_t, 1 );
278       }
279    }
280 
281 //******************************************************************************
282 //
283 // SetupPlayScreen ()
284 //
285 //******************************************************************************
SetupPlayScreen(void)286 void SetupPlayScreen
287    (
288    void
289    )
290 
291    {
292 	int i;
293 	int j;
294    int num;
295 
296    erase  = ( pic_t * )W_CacheLumpName( "erase", PU_LEVEL, Cvt_pic_t, 1 );
297    eraseb = ( pic_t * )W_CacheLumpName( "eraseb", PU_LEVEL, Cvt_pic_t, 1 );
298 
299    CacheLumpGroup( "tmnum0", timenums, 10 );
300    CacheLumpGroup( "lfnum0", lifeptnums, 10 );
301    CacheLumpGroup( "lvnum0", lifenums, 10 );
302    CacheLumpGroup( "health1b", health, 6 );
303    CacheLumpGroup( "key1", keys, 4 );
304 
305    if ( !BATTLEMODE )
306       {
307       CacheLumpGroup( "scnum0", scorenums, 10 );
308 
309       num = locplayerstate->player;
310       men[ num ] = ( pic_t * )W_CacheLumpNum( W_GetNumForName( "MAN1" ) +
311          num, PU_LEVEL, Cvt_pic_t, 1 );
312       }
313    else
314       {
315       int  man;
316       int  num100;
317       int  negnum;
318       int  negman;
319 
320       CacheLumpGroup( "kilnum0", scorenums, 10 );
321 
322       negnum  = W_GetNumForName( "botnpic1" );
323       num     = W_GetNumForName( "botpic0" );
324       num100  = W_GetNumForName( "botopic1" );
325       negman  = W_GetNumForName( "negman1" );
326       man     = W_GetNumForName( "man1" );
327 
328       blankfragpic = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
329       num++;
330 
331       for( i = 0; i < numplayers; i++ )
332          {
333          j = PLAYERSTATE[ i ].player;
334          if ( !gamestate.teamplay )
335             {
336             fragpic[ j ]    = ( pic_t * )W_CacheLumpNum( num + j, PU_LEVEL, Cvt_pic_t, 1 );
337             frag100pic[ j ] = ( pic_t * )W_CacheLumpNum( num100 + j, PU_LEVEL, Cvt_pic_t, 1 );
338             negfragpic[ j ] = ( pic_t * )W_CacheLumpNum( negnum + j, PU_LEVEL, Cvt_pic_t, 1 );
339             }
340          else
341             {
342             negfragpic[ j ] = ( pic_t * )W_CacheLumpName( "teamnpic", PU_LEVEL, Cvt_pic_t, 1 );
343             fragpic[ j ]    = ( pic_t * )W_CacheLumpName( "teampic", PU_LEVEL, Cvt_pic_t, 1 );
344             frag100pic[ j ] = fragpic[ j ];
345             }
346 
347          menneg[ j ]     = ( pic_t * )W_CacheLumpNum( negman + j, PU_LEVEL, Cvt_pic_t, 1 );
348          men[ j ]        = ( pic_t * )W_CacheLumpNum( man + j, PU_LEVEL, Cvt_pic_t, 1 );
349          }
350       }
351 
352    powerpics   = W_GetNumForName( "GDMODEP" );
353    poweradjust = POWERUPTICS / 16;
354 
355    num   = W_GetNumForName( "INF_B" );
356 
357    // bullet weapons
358    ammo[0] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
359    ammo[1] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
360    ammo[2] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
361 
362 
363    for(i=3;i < 13; i++ )
364       {
365       ammo[ i ] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
366       }
367 
368    ammo[13] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
369    ammo[14] = ( pic_t * )W_CacheLumpNum( num, PU_LEVEL, Cvt_pic_t, 1 );
370    ammo[15] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
371 
372 
373    for(i=16;i < 26; i++ )
374       {
375       ammo[ i ] = ( pic_t * )W_CacheLumpNum( num++, PU_LEVEL, Cvt_pic_t, 1 );
376       }
377 
378 
379    oldplayerhealth  = -1;
380    oldpercenthealth = -1;
381    }
382 
383 
384 
385 //******************************************************************************
386 //
387 // GameMemToScreen()
388 //
389 //******************************************************************************
390 
GameMemToScreen(pic_t * source,int x,int y,int bufferofsonly)391 void GameMemToScreen
392    (
393    pic_t *source,
394    int   x,
395    int   y,
396    int   bufferofsonly
397    )
398 
399    {
400    if ( bufferofsonly )
401       {
402       VL_MemToScreen( ( byte * )&source->data, source->width,
403          source->height, x, y );
404       }
405    else
406       {
407       GM_MemToScreen( ( byte * )&source->data, source->width,
408          source->height, x, y );
409       }
410    }
411 
412 
413 //******************************************************************************
414 //
415 // DrawPlayScreen ()
416 //
417 //******************************************************************************
DrawPlayScreen(boolean bufferofsonly)418 void DrawPlayScreen
419    (
420    boolean bufferofsonly
421    )
422 
423    {
424    pic_t *shape;
425    int    shapenum;
426 
427    if ( SHOW_TOP_STATUS_BAR() )
428       {
429       shape = W_CacheLumpName( "stat_bar", PU_CACHE, Cvt_pic_t, 1 );
430       GameMemToScreen( shape, 0, 0, bufferofsonly );
431       }
432 
433    if ( BATTLEMODE )
434       {
435       DrawKills( bufferofsonly );
436       }
437 
438    if ( SHOW_BOTTOM_STATUS_BAR() )
439       {
440       shape = ( pic_t * ) W_CacheLumpName( "bottbar", PU_CACHE, Cvt_pic_t, 1 );
441 
442       if ( SHOW_KILLS() )
443          {
444          GameMemToScreen( shape, 0, 160, bufferofsonly );
445          }
446       else
447          {
448          GameMemToScreen( shape, 0, 184, bufferofsonly );
449          }
450 
451       DrawBarAmmo( bufferofsonly );
452       DrawBarHealth( bufferofsonly );
453 
454       if ( demoplayback )
455          {
456          shape = ( pic_t * )W_CacheLumpName( "demo", PU_CACHE, Cvt_pic_t, 1 );
457          DrawPPic( 148, 185, shape->width, shape->height,
458             ( byte * )&shape->data, 1, true, bufferofsonly );
459          }
460       }
461 
462    if ( !SHOW_TOP_STATUS_BAR() )
463       {
464       return;
465       }
466 
467 
468    oldsec = -1;
469 
470    DrawTime( bufferofsonly );
471 
472    if ( !BATTLEMODE )
473       {
474       int character;
475       int width;
476       int height;
477 
478       character = locplayerstate->player;
479       GameMemToScreen( men[ character ], MEN_X, MEN_Y,
480          bufferofsonly );
481 
482       CurrentFont = tinyfont;
483 
484       // Draw player's name
485       DrawGameString ( MEN_X + 3, MEN_Y + 2, Names[ character ], bufferofsonly );
486 
487       VW_MeasurePropString( LastNames[ character ], &width, &height );
488 
489       DrawGameString ( MEN_X + 44 - width, MEN_Y + 8,
490          Names[ character + 5 ], bufferofsonly );
491 
492       UpdateLives( locplayerstate->lives );
493       UpdateScore( gamestate.score );
494       DrawTriads( bufferofsonly );
495       DrawLives( bufferofsonly );
496       DrawScore( bufferofsonly );
497       }
498 
499    DrawKeys( bufferofsonly );
500 
501    if ( locplayerstate->poweruptime )
502       {
503       if ( player->flags & FL_GODMODE )
504          {
505          shapenum = powerpics;
506          }
507       else if ( player->flags & FL_DOGMODE )
508          {
509          shapenum = powerpics + 1;
510          }
511       else if ( player->flags & FL_FLEET )
512          {
513          shapenum = powerpics + 2;
514          }
515       else if ( player->flags & FL_ELASTO )
516          {
517          shapenum = powerpics + 3;
518          }
519       else if ( player->flags & FL_SHROOMS )
520          {
521          shapenum = powerpics + 4;
522          }
523 
524       shape = ( pic_t * )W_CacheLumpNum ( shapenum, PU_CACHE, Cvt_pic_t, 1 );
525 
526       GameMemToScreen( eraseb, POWERUP1X, POWERUPY, bufferofsonly );
527 
528       DrawMPPic( POWERUP1X, POWERUPY + powerupheight, shape->width,
529          shape->height - powerupheight, powerupheight,
530          ( byte * )&shape->data, bufferofsonly );
531       }
532 
533 
534    if ( locplayerstate->protectiontime )
535       {
536       if ( player->flags & FL_BPV )
537          {
538          shapenum = powerpics + 6;
539          }
540       else if ( player->flags & FL_GASMASK )
541          {
542          shapenum = powerpics + 5;
543          }
544       else if ( player->flags & FL_AV )
545          {
546          shapenum = powerpics + 7;
547          }
548 
549       shape = ( pic_t * )W_CacheLumpNum( shapenum, PU_CACHE, Cvt_pic_t, 1 );
550 
551       GameMemToScreen( eraseb, POWERUP2X, POWERUPY, bufferofsonly );
552 
553       DrawMPPic( POWERUP2X, POWERUPY + protectionheight, shape->width,
554          shape->height - protectionheight, protectionheight,
555          ( byte * )&shape->data, bufferofsonly );
556       }
557    }
558 
559 
560 //******************************************************************************
561 //
562 // ShortenCodeName()
563 //
564 //******************************************************************************
GetShortCodeName(char * dest,char * source,int maxwidth)565 void GetShortCodeName
566    (
567    char *dest,
568    char *source,
569    int  maxwidth
570    )
571 
572    {
573    int width;
574    int height;
575    int length;
576 
577    strcpy( dest, source );
578 
579    // Shorten name to fit
580    length = strlen( dest );
581    VW_MeasurePropString( dest, &width, &height );
582    while( width > maxwidth )
583       {
584       dest[ length ] = 0;
585       length--;
586       VW_MeasurePropString( dest, &width, &height );
587       }
588    }
589 
590 
591 //******************************************************************************
592 //
593 // DrawKills ()
594 //
595 //******************************************************************************
DrawKills(boolean bufferofsonly)596 void DrawKills
597    (
598    boolean bufferofsonly
599    )
600    {
601    int  rank;
602 	int  xpos;
603    char codename[ MAXCODENAMELENGTH ];
604    int  width;
605    int  playernum;
606    int  playerimage;
607    int  temp;
608    pic_t *pic;
609 
610    CurrentFont = tinyfont;
611 
612    if ( SHOW_TOP_STATUS_BAR() )
613       {
614       playernum   = BATTLE_Team[ consoleplayer ];
615       playerimage = BATTLE_TeamLeader[ playernum ];
616 
617       // Set uniformcolor
618       playeruniformcolor = PLAYERSTATE[ playerimage ].uniformcolor;
619 
620       // Draw player's point box
621       pic = men[ PLAYERSTATE[ playerimage ].player ];
622       if ( ( gamestate.ShowScores ) && ( BATTLE_Points[ playernum ] < 0 ) )
623          {
624          pic = menneg[ PLAYERSTATE[ playerimage ].player ];
625          }
626 
627       DrawPPic( MEN_X, MEN_Y, pic->width, pic->height,
628          ( byte * )&pic->data, 1, true, bufferofsonly );
629 
630       // Draw player's name
631       if ( gamestate.teamplay )
632          {
633          GetShortCodeName( codename, colorname[ playeruniformcolor ],
634             42 );
635          }
636       else
637          {
638          GetShortCodeName( codename, PLAYERSTATE[ playerimage ].codename,
639             42 );
640          }
641 
642       DrawGameString ( MEN_X + 2, MEN_Y + 2, codename, bufferofsonly );
643       // Draw "It" if player is 'it'
644       if ( ( ( gamestate.battlemode == battle_Tag ) ||
645          ( gamestate.battlemode == battle_Hunter ) ) &&
646          ( BATTLE_It == BATTLE_Team[ consoleplayer ] ) )
647          {
648          DrawGameString ( MEN_X + 22, MEN_Y + 8,
649             "It", bufferofsonly);
650          }
651 
652       // Draw triad if player is 'it' or has caught a triad
653       if ( PLAYER[ consoleplayer ]->flags & FL_DESIGNATED )
654          {
655          pic = W_CacheLumpName( "smalltri", PU_CACHE, Cvt_pic_t, 1 );
656          DrawPPic( TRIAD_X - 1, TRIAD_Y - 2, pic->width, pic->height,
657             ( byte * )&pic->data, 1, true, bufferofsonly );
658          }
659       else if ( ( gamestate.ShowScores ) &&
660          ( DisplayPoints != bo_kills_infinite ) )
661          {
662          // Draw Kill goal
663          if ( ( gamestate.battlemode == battle_Collector ) ||
664             ( gamestate.battlemode == battle_StandAloneGame ) )
665             {
666             temp = BATTLE_NumCollectorItems;
667             }
668          else
669             {
670             temp = DisplayPoints;
671             }
672 
673          ltoa ( temp % 1000, KillStr.str, 10);
674          KillStr.length = strlen (KillStr.str);
675          DrawNumber (TRIAD_X - 6, TRIAD_Y, 3, 5, bufferofsonly);
676          }
677 
678       // Set uniformcolor
679       playeruniformcolor = PLAYERSTATE[ consoleplayer ].uniformcolor;
680 
681       if ( gamestate.ShowScores )
682          {
683          // Draw local player's points
684          temp = BATTLE_Points[ playernum ] % 1000;
685          if ( temp < 0 )
686             {
687             temp = -temp;
688             }
689          ltoa ( temp, KillStr.str, 10);
690          KillStr.length = strlen (KillStr.str);
691 
692          DrawNumber( LIVES_X - 12, LIVES_Y, 3, 4, bufferofsonly);
693          }
694       else
695          {
696          pic = W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 );
697          StatusDrawColoredPic( LIVES_X - 12, LIVES_Y, pic, bufferofsonly, playeruniformcolor );
698          StatusDrawColoredPic( LIVES_X - 4, LIVES_Y, pic, bufferofsonly, playeruniformcolor );
699          }
700 
701       // Draw whoever is 'It'
702       playernum   = BATTLE_It;
703       playerimage = BATTLE_TeamLeader[ playernum ];
704 
705       // Set uniformcolor
706       playeruniformcolor = PLAYERSTATE[ playerimage ].uniformcolor;
707 
708       // Draw player's point box
709       pic = men[ PLAYERSTATE[ playerimage ].player ];
710       if ( ( gamestate.ShowScores ) && ( BATTLE_Points[ playernum ] < 0 ) )
711          {
712          pic = menneg[ PLAYERSTATE[ playerimage ].player ];
713          }
714 
715       DrawPPic( LEADER_X, LEADER_Y, pic->width, pic->height,
716          (byte *)&pic->data, 1, true, bufferofsonly );
717 
718       if ( ( gamestate.battlemode == battle_Tag ) ||
719          ( gamestate.battlemode == battle_Hunter ) )
720          {
721          DrawGameString ( LEADER_X + 22, LEADER_Y + 8,
722             "It", bufferofsonly);
723          }
724 
725       if ( gamestate.ShowScores )
726          {
727          // Draw number of points
728          temp = BATTLE_Points[ playernum ] % 1000;
729          if ( temp < 0 )
730             {
731             temp = -temp;
732             }
733          ltoa ( temp, KillStr.str, 10);
734          KillStr.length = strlen (KillStr.str);
735          DrawNumber ( LEADER_NUM_X, LEADER_NUM_Y, 3, 4, bufferofsonly);
736          }
737       else
738          {
739          pic = W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 );
740          StatusDrawColoredPic( LEADER_NUM_X, LEADER_NUM_Y, pic, bufferofsonly, playeruniformcolor );
741          StatusDrawColoredPic( LEADER_NUM_X + 8, LEADER_NUM_Y, pic, bufferofsonly, playeruniformcolor );
742          }
743 
744       // Draw name
745       if ( gamestate.teamplay )
746          {
747          DrawGameString ( LEADER_NAME_X, LEADER_NAME_Y - 1,
748             colorname[ playeruniformcolor ], bufferofsonly);
749          }
750       else
751          {
752          GetShortCodeName( codename, PLAYERSTATE[ playerimage ].codename,
753             42 );
754          DrawGameString ( LEADER_NAME_X - 1, LEADER_NAME_Y,
755             codename, bufferofsonly);
756          }
757       }
758 
759    // Only draw the rest of the rifraff when the kill count is selected
760    if ( !SHOW_KILLS() )
761       {
762       return;
763       }
764 
765    // Draw all the other losers
766 	xpos = KILLS_X;
767    for( rank = 0; rank < BATTLE_NumberOfTeams; rank++ )
768       {
769       playernum   = BATTLE_PlayerOrder[ rank ];
770       playerimage = BATTLE_TeamLeader[ playernum ];
771 
772       if ( ( playernum == BATTLE_It ) && SHOW_TOP_STATUS_BAR() )
773          {
774          continue;
775          }
776 
777       // Set uniformcolor
778       playeruniformcolor = PLAYERSTATE[ playerimage ].uniformcolor;
779 
780       // Draw player's point box
781       pic = fragpic[ PLAYERSTATE[ playerimage ].player ];
782       if ( gamestate.ShowScores )
783          {
784          if ( BATTLE_Points[ playernum ] < 0 )
785             {
786             pic = negfragpic[ PLAYERSTATE[ playerimage ].player ];
787             }
788          else if ( BATTLE_Points[ playernum ] >= 100 )
789             {
790             pic = frag100pic[ PLAYERSTATE[ playerimage ].player ];
791             }
792          }
793       DrawPPic( xpos, KILLS_Y, pic->width, pic->height,
794          (byte *)&pic->data, 1, true, bufferofsonly );
795 
796       // Draw number of points
797       if ( gamestate.ShowScores )
798          {
799          temp = BATTLE_Points[ playernum ] % 1000;
800          if ( temp < 0 )
801             {
802             temp = -temp;
803             }
804          ltoa ( temp, KillStr.str, 10);
805          KillStr.length = strlen (KillStr.str);
806          width = 2;
807          if ( temp > 99 )
808             {
809             width = 3;
810             }
811          DrawNumber( xpos + KILLS_OFFSET + 16 - ( 8 * width ), KILLS_Y, width, 4, bufferofsonly);
812          }
813       else
814          {
815          pic = W_CacheLumpName( "minus", PU_CACHE, Cvt_pic_t, 1 );
816          StatusDrawColoredPic( ( xpos + KILLS_OFFSET ), KILLS_Y, pic, bufferofsonly, playeruniformcolor );
817          StatusDrawColoredPic( ( xpos + KILLS_OFFSET + 8 ), KILLS_Y, pic, bufferofsonly, playeruniformcolor );
818          }
819 
820       // Get codename
821       if ( gamestate.teamplay )
822          {
823          GetShortCodeName( codename, colorname[ playeruniformcolor ],
824             KILLS_WIDTH - 2 );
825          }
826       else
827          {
828          GetShortCodeName( codename, PLAYERSTATE[ playerimage ].codename,
829             KILLS_WIDTH - 2 );
830          }
831 
832       // Draw name
833       DrawGameString (xpos + 1, KILLS_NAME_Y, codename, bufferofsonly);
834 
835       // Advance to next position
836 		xpos += KILLS_WIDTH;
837 
838       if ( xpos >= 320 )
839          {
840          break;
841          }
842       }
843 
844    for( rank = BATTLE_NumberOfTeams; rank <= MAXKILLBOXES; rank++ )
845       {
846       if ( xpos >= 320 )
847          {
848          break;
849          }
850 
851       pic = blankfragpic;
852       DrawPPic( xpos, KILLS_Y, pic->width, pic->height,
853          (byte *)&pic->data, 1, true, bufferofsonly );
854 
855       // Advance to next position
856 		xpos += KILLS_WIDTH;
857       }
858    }
859 
860 
861 //******************************************************************************
862 //
863 // DrawPlayers ()
864 //
865 //******************************************************************************
DrawPlayers(void)866 void DrawPlayers
867    (
868    void
869    )
870 
871    {
872 	int    num;
873 	int    xpos;
874    char   codename[ MAXCODENAMELENGTH ];
875    int    length;
876    int    width;
877    int    height;
878    int    team;
879    int    player;
880    int    character;
881    pic_t *pic;
882    pic_t *enemy;
883    pic_t *friend;
884 
885    num = W_GetNumForName( "botpic1" );
886 
887    scorenums[ 0 ]= ( pic_t * )W_CacheLumpName( "kilnum0", PU_CACHE, Cvt_pic_t, 1 );
888    friend = ( pic_t * )W_CacheLumpName( "t_friend", PU_CACHE, Cvt_pic_t, 1 );
889    enemy  = ( pic_t * )W_CacheLumpName( "t_enemy", PU_CACHE, Cvt_pic_t, 1 );
890 
891    // Draw all the losers
892    CurrentFont = tinyfont;
893 
894 	xpos = ( 320 - min( numplayers, MAXKILLBOXES ) * KILLS_WIDTH ) / 2;
895 
896    for( team = 0; team < BATTLE_NumberOfTeams; team++ )
897       {
898       for( player = 0; player < numplayers; player++ )
899          {
900          if ( BATTLE_Team[ player ] == team )
901             {
902             character = PLAYERSTATE[ player ].player;
903 
904             fragpic[ character ] = ( pic_t * )W_CacheLumpNum( num +
905                character, PU_CACHE, Cvt_pic_t, 1 );
906 
907             if ( ( numplayers <= MAXKILLBOXES ) ||
908                ( player != consoleplayer ) )
909                {
910                // Set uniformcolor
911                playeruniformcolor = PLAYERSTATE[ player ].uniformcolor;
912 
913                // Draw player's point box
914                pic = fragpic[ PLAYERSTATE[ player ].player ];
915 
916                VWB_DrawPic ( xpos, PLAYERS_Y, pic );
917                if ( gamestate.teamplay )
918                   {
919                   if ( BATTLE_Team[ player ] == BATTLE_Team[ consoleplayer ] )
920                      {
921                      VWB_DrawPic ( xpos, PLAYERS_TEAM_Y, friend );
922                      }
923                   else
924                      {
925                      VWB_DrawPic ( xpos, PLAYERS_TEAM_Y, enemy );
926                      }
927                   }
928 
929                strcpy( KillStr.str, "00" );
930                KillStr.length = strlen ( KillStr.str );
931                DrawNumber( xpos + KILLS_OFFSET, PLAYERS_Y, 2, 4, true );
932 
933                // Get codename
934                strcpy( codename, PLAYERSTATE[ player ].codename );
935 
936                // Shorten name to fit into point count
937                length = strlen( codename );
938                US_MeasureStr( &width, &height, codename );
939                while( width > KILLS_WIDTH )
940                   {
941                   codename[ length ] = 0;
942                   length--;
943                   US_MeasureStr( &width, &height, codename );
944                   }
945 
946                // Draw name
947                PrintX = xpos;
948                PrintY = PLAYERS_NAME_Y;
949                US_Print( codename );
950 
951                // Advance to next position
952                xpos += KILLS_WIDTH;
953                }
954             }
955          if ( xpos >= 320 )
956             {
957             break;
958             }
959          }
960       if ( xpos >= 320 )
961          {
962          break;
963          }
964       }
965    }
966 
967 //******************************************************************************
968 //
969 // StatusDrawPic ()
970 //
971 //******************************************************************************
972 
StatusDrawPic(unsigned x,unsigned y,pic_t * nums,boolean bufferofsonly)973 void StatusDrawPic (unsigned x, unsigned y, pic_t *nums, boolean bufferofsonly)
974 {
975    DrawMPPic (x, y, nums->width, nums->height, 0,
976              (byte *)&nums->data, bufferofsonly);
977 }
978 
979 //******************************************************************************
980 //
981 // StatusDrawColoredPic ()
982 //
983 //******************************************************************************
984 
StatusDrawColoredPic(unsigned x,unsigned y,pic_t * nums,boolean bufferofsonly,int color)985 void StatusDrawColoredPic (unsigned x, unsigned y, pic_t *nums, boolean bufferofsonly, int color)
986 {
987    DrawColoredMPPic (x, y, nums->width, nums->height, 0,
988              (byte *)&nums->data, bufferofsonly, color);
989 }
990 
991 //******************************************************************************
992 //
993 // DrawGameString ()
994 //
995 // draw string to game screen at x,y
996 //
997 //******************************************************************************
998 
DrawGameString(int x,int y,char * str,boolean bufferofsonly)999 void DrawGameString (int x, int y, char * str, boolean bufferofsonly)
1000 {
1001    unsigned tempbuf;
1002 
1003    px=x;
1004    py=y;
1005 
1006    if (bufferofsonly==true)
1007       VW_DrawPropString (str);
1008    else
1009       {
1010       tempbuf=bufferofs;
1011       bufferofs=page1start;
1012       VW_DrawPropString (str);
1013       px=x;
1014       py=y;
1015       bufferofs=page2start;
1016       VW_DrawPropString (str);
1017       px=x;
1018       py=y;
1019       bufferofs=page3start;
1020       VW_DrawPropString (str);
1021       bufferofs=tempbuf;
1022       }
1023 }
1024 
1025 
1026 //******************************************************************************
1027 //
1028 // DrawNumber ()
1029 //
1030 // right justifies and pads with zeros
1031 //
1032 //******************************************************************************
1033 
DrawNumber(int x,int y,int width,int which,boolean bufferofsonly)1034 void DrawNumber (int x, int y, int width, int which, boolean bufferofsonly)
1035 {
1036    unsigned length,c;
1037    char  *str;
1038    byte z;
1039 
1040    switch (which)
1041    {
1042       case 1:
1043          str = ScoreStr.str;
1044          length = ScoreStr.length;
1045       break;
1046 
1047       case 2:
1048          str = LivesStr.str;
1049          length = LivesStr.length;
1050       break;
1051 
1052       case 3:
1053          str = TriadStr.str;
1054          length = TriadStr.length;
1055       break;
1056 
1057       case 4:
1058       case 5:
1059       case 6:
1060          str = KillStr.str;
1061          length = KillStr.length;
1062       break;
1063    }
1064 
1065    z = width - length;     // Num zeros
1066 
1067    while (z)
1068    {
1069       switch (which)
1070       {
1071          case 1: StatusDrawPic (x, y, scorenums[0], bufferofsonly);  x+=8; break;
1072          case 2: StatusDrawPic (x, y, lifenums[0], bufferofsonly);   x+=8; break;
1073          case 3: StatusDrawPic (x, y, lifeptnums[0], bufferofsonly); x+=6; break;
1074          case 4: StatusDrawColoredPic (x, y, scorenums[0], bufferofsonly, playeruniformcolor);   x+=8; break;
1075          case 5: StatusDrawPic (x, y, lifeptnums[0], bufferofsonly); x+=6; break;
1076          case 6: StatusDrawPic (x, y, lifenums[0], bufferofsonly);   x+=8; break;
1077       }
1078       z--;
1079    }
1080 
1081    c = length <= (unsigned)width ? 0 : length-width;
1082    while (c < length)
1083    {
1084       switch (which)
1085       {
1086          case 1: StatusDrawPic (x, y, scorenums[str[c]-'0'], bufferofsonly);  x+=8; break;
1087          case 2: StatusDrawPic (x, y, lifenums[str[c]-'0'], bufferofsonly);   x+=8; break;
1088          case 3: StatusDrawPic (x, y, lifeptnums[str[c]-'0'], bufferofsonly); x+=6; break;
1089          case 4: StatusDrawColoredPic (x, y, scorenums[str[c]-'0'], bufferofsonly, playeruniformcolor);   x+=8; break;
1090          case 5: StatusDrawPic (x, y, lifeptnums[str[c]-'0'], bufferofsonly); x+=6; break;
1091          case 6: StatusDrawPic (x, y, lifenums[str[c]-'0'], bufferofsonly);   x+=8; break;
1092       }
1093       c++;
1094    }
1095 }
1096 
1097 
1098 
1099 //******************************************************************************
1100 //
1101 // HealPlayer ()
1102 //
1103 //******************************************************************************
1104 
HealPlayer(int points,objtype * ob)1105 void HealPlayer
1106    (
1107    int      points,
1108    objtype *ob
1109    )
1110 
1111    {
1112    playertype *pstate;
1113    int maxhitpoints;
1114 
1115 	M_LINKSTATE( ob, pstate );
1116 
1117 	pstate->health += points;
1118 	maxhitpoints = MaxHitpointsForCharacter( pstate );
1119 	if ( pstate->health > maxhitpoints )
1120       {
1121       pstate->health = maxhitpoints;
1122       }
1123 
1124    if ( ( SHOW_BOTTOM_STATUS_BAR() ) && ( ob == player ) )
1125       {
1126       DrawBarHealth( false );
1127       }
1128    }
1129 
1130 //******************************************************************************
1131 //
1132 // DrawLives ()
1133 //
1134 //******************************************************************************
1135 
DrawLives(boolean bufferofsonly)1136 void DrawLives
1137    (
1138    boolean bufferofsonly
1139    )
1140 
1141    {
1142    if ( !SHOW_TOP_STATUS_BAR() )
1143       {
1144       return;
1145       }
1146 
1147 	if ( !EndLevelStuff )
1148       {
1149       DrawNumber( LIVES_X, LIVES_Y, 2, 2, bufferofsonly );
1150       }
1151    }
1152 
1153 
1154 //******************************************************************************
1155 //
1156 // GiveExtraMan ()
1157 //
1158 //******************************************************************************
1159 
GiveExtraMan(void)1160 void  GiveExtraMan (void)
1161 {
1162    if (locplayerstate->lives < 99)
1163       locplayerstate->lives++;
1164    UpdateLives (locplayerstate->lives);
1165    DrawLives (false);
1166 //   SD_PlaySound (BONUS1UPSND);
1167 }
1168 
1169 
1170 
1171 //******************************************************************************
1172 //
1173 // DrawScore ()
1174 //
1175 //******************************************************************************
1176 
DrawScore(boolean bufferofsonly)1177 void DrawScore
1178    (
1179    boolean bufferofsonly
1180    )
1181 
1182    {
1183    if ( !SHOW_TOP_STATUS_BAR() )
1184       {
1185       return;
1186       }
1187 
1188    if ( !BATTLEMODE )
1189       {
1190       DrawNumber( SCORE_X, SCORE_Y, 10, 1, bufferofsonly );
1191       }
1192    }
1193 
1194 
1195 //******************************************************************************
1196 //
1197 // GivePoints ()
1198 //
1199 //******************************************************************************
1200 
GivePoints(long points)1201 void  GivePoints (long points)
1202 {
1203    gamestate.score += points;
1204 
1205    UpdateScore (gamestate.score);
1206 
1207    if (!EndLevelStuff)
1208       DrawScore (false);
1209 }
1210 
1211 
1212 //******************************************************************************
1213 //
1214 // GiveKey ()
1215 //
1216 //******************************************************************************
1217 
GiveKey(int key)1218 void GiveKey (int key)
1219 {
1220    locplayerstate->keys |= (1<<key);
1221    DrawKeys (false);
1222 }
1223 
1224 
1225 //******************************************************************************
1226 //
1227 // GiveLives ()
1228 //
1229 //******************************************************************************
1230 
GiveLives(int newlives)1231 void GiveLives (int newlives)
1232 {
1233    if ((locplayerstate->lives + newlives) <= 99)
1234       locplayerstate->lives += newlives;
1235    else
1236       locplayerstate->lives = 99;
1237    UpdateLives (locplayerstate->lives);
1238    DrawLives (false);
1239 }
1240 
1241 
1242 #define EnableOldWeapon(pstate)    \
1243    {                               \
1244    LASTSTAT->flags |= FL_ABP;      \
1245    LASTSTAT->flags &= ~FL_RESPAWN; \
1246    MakeStatActive(LASTSTAT);       \
1247    pstate->weaponx = ob->tilex;    \
1248    pstate->weapony = ob->tiley;    \
1249    }
1250 
1251 
1252 //******************************************************************************
1253 //
1254 // GiveWeapon ()
1255 //
1256 //******************************************************************************
1257 
GiveWeapon(objtype * ob,int weapon)1258 void GiveWeapon
1259    (
1260    objtype *ob,
1261    int weapon
1262    )
1263 
1264    {
1265    playertype *pstate;
1266 
1267    M_LINKSTATE( ob, pstate );
1268 
1269    if ( pstate->weapon == weapon )
1270       {
1271       return;
1272       }
1273 
1274    pstate->HASBULLETWEAPON[ weapon ] = 1;
1275    if ( ( pstate->weapon == pstate->bulletweapon ) &&
1276       ( pstate->weapon < weapon ) )
1277       {
1278       pstate->new_weapon = weapon;
1279       pstate->weapondowntics = WEAPONS[ pstate->weapon ].screenheight / GMOVE;
1280       if ( ( ob == player ) && ( SHOW_BOTTOM_STATUS_BAR() ) )
1281          {
1282          DrawBarAmmo( false );
1283          }
1284       }
1285 
1286    if ( gamestate.BattleOptions.WeaponPersistence )
1287       {
1288       SpawnStatic(ob->tilex,ob->tiley,GetItemForWeapon(weapon),9);
1289       EnableOldWeapon(pstate);
1290       }
1291 
1292    if ( weapon > pstate->bulletweapon )
1293       {
1294       pstate->bulletweapon = weapon;
1295       }
1296    }
1297 
1298 
1299 //******************************************************************************
1300 //
1301 // GiveMissileWeapon ()
1302 //
1303 //******************************************************************************
1304 
GiveMissileWeapon(objtype * ob,int which)1305 void GiveMissileWeapon(objtype * ob, int which)
1306 {
1307 	playertype * pstate;
1308 
1309 
1310 	//pstate = (ob==player)?(&playerstate):(&remoteplayerstate);
1311 	M_LINKSTATE(ob,pstate);
1312 
1313    if (!gamestate.BattleOptions.WeaponPersistence)
1314       {
1315       if (pstate->ammo &&
1316           (pstate->missileweapon != -1) &&
1317           (!(WEAPON_IS_MAGICAL(which))) &&
1318           (!(WEAPON_IS_MAGICAL(pstate->missileweapon)))
1319          )
1320          {
1321          int nx,ny;
1322 
1323 
1324          nx = ob->tilex;
1325          ny = ob->tiley;
1326          //FindEmptyTile(&nx,&ny);
1327 
1328          if (IsPlatform(nx,ny))
1329             SpawnStatic(nx,ny,GetItemForWeapon(pstate->missileweapon),9);
1330          else
1331             {
1332             int newz = sprites[ob->tilex][ob->tiley]->z;
1333             SpawnStatic(nx,ny,GetItemForWeapon(pstate->missileweapon),-1);
1334             LASTSTAT->z = newz;
1335             }
1336          LASTSTAT->ammo = pstate->ammo;
1337          EnableOldWeapon(pstate);
1338 
1339          }
1340       }
1341 
1342    else if (!WEAPON_IS_MAGICAL(which))
1343       {
1344       int newz = sprites[ob->tilex][ob->tiley]->z;
1345       SpawnStatic(ob->tilex,ob->tiley,GetItemForWeapon(which),9);
1346       LASTSTAT->z = newz;
1347       EnableOldWeapon(pstate);
1348 
1349       }
1350    pstate->new_weapon = pstate->missileweapon = which;
1351    pstate->weapondowntics = WEAPONS[pstate->weapon].screenheight/GMOVE;
1352 
1353 
1354 }
1355 
1356 
1357 //******************************************************************************
1358 //
1359 // DrawKeys ()
1360 //
1361 //******************************************************************************
1362 
DrawKeys(boolean bufferofsonly)1363 void DrawKeys
1364    (
1365    boolean bufferofsonly
1366    )
1367 
1368    {
1369    if ( !SHOW_TOP_STATUS_BAR() )
1370       {
1371       return;
1372       }
1373 
1374    if ( locplayerstate->keys & 1 )
1375       {
1376       GameMemToScreen( keys[ 0 ], KeyX[ 0 ], KEY_Y, bufferofsonly );
1377       }
1378 
1379    if ( locplayerstate->keys & 2 )
1380       {
1381       GameMemToScreen( keys[ 1 ], KeyX[ 1 ], KEY_Y, bufferofsonly );
1382       }
1383 
1384    if ( locplayerstate->keys & 4 )
1385       {
1386       GameMemToScreen( keys[ 2 ], KeyX[ 2 ], KEY_Y, bufferofsonly );
1387       }
1388 
1389    if ( locplayerstate->keys & 8 )
1390       {
1391       GameMemToScreen( keys[ 3 ], KeyX[ 3 ], KEY_Y, bufferofsonly );
1392       }
1393    }
1394 
1395 
1396 //******************************************************************************
1397 //
1398 // StatusDrawTime ()
1399 //
1400 //******************************************************************************
1401 
StatusDrawTime(unsigned x,unsigned y,unsigned num,boolean bufferofsonly)1402 void StatusDrawTime
1403    (
1404    unsigned x,
1405    unsigned y,
1406    unsigned num,
1407    boolean  bufferofsonly
1408    )
1409 
1410    {
1411 	DrawMPPic( x, y, timenums[ num ]->width, timenums[ num ]->height, 0,
1412       ( byte * )&timenums[ num ]->data, bufferofsonly );
1413    }
1414 
1415 
1416 //******************************************************************************
1417 //
1418 // DrawTimeNumber ()
1419 //
1420 // right justifies and pads with blanks
1421 //
1422 //******************************************************************************
1423 
DrawTimeNumber(int x,int y,int number,boolean seconds,boolean bufferofsonly)1424 void DrawTimeNumber (int x, int y, int number, boolean seconds, boolean bufferofsonly)
1425 {
1426    char  str[20];
1427 
1428    ltoa (number,str,10);
1429 
1430    if (seconds)
1431 	{
1432       if (number < 10)
1433       {
1434          StatusDrawTime (x,   y, 0, bufferofsonly);
1435          StatusDrawTime (x+8, y, str[0]-'0', bufferofsonly);
1436       }
1437       else
1438       {
1439          StatusDrawTime (x,   y, str[0]-'0', bufferofsonly);
1440          StatusDrawTime (x+8, y, str[1]-'0', bufferofsonly);
1441       }
1442    }
1443    else
1444    {
1445       if (number < 10)
1446          StatusDrawTime (x+8, y, str[0]-'0', bufferofsonly);
1447       else
1448       {
1449          StatusDrawTime (x,   y, str[0]-'0', bufferofsonly);
1450          StatusDrawTime (x+8, y, str[1]-'0', bufferofsonly);
1451       }
1452    }
1453 }
1454 
1455 
1456 //******************************************************************************
1457 //
1458 // DrawTimeXY ()
1459 //
1460 //******************************************************************************
1461 
DrawTimeXY(int x,int y,int sec,boolean bufferofsonly)1462 void DrawTimeXY
1463    (
1464    int x,
1465    int y,
1466    int sec,
1467    boolean bufferofsonly
1468    )
1469 
1470    {
1471    int min;
1472    int hour;
1473 
1474    while (sec > ( ( 9 * 3600 ) + 3599 ) )
1475       {
1476       sec -= ( ( 9 * 3600 ) + 3599 );
1477       }
1478 
1479    hour  = sec / 3600;
1480    min   = ( sec / 60 ) - ( hour * 60 );
1481    sec  %= 60;
1482 
1483    DrawTimeNumber ( x + HOUR_X, y, hour, false, bufferofsonly );
1484    DrawTimeNumber ( x + MIN_X, y, min, true, bufferofsonly );
1485    DrawTimeNumber ( x + SEC_X, y, sec, true, bufferofsonly );
1486    }
1487 
1488 
1489 //******************************************************************************
1490 //
1491 // DrawTime ()
1492 //
1493 //******************************************************************************
1494 
DrawTime(boolean bufferofsonly)1495 void DrawTime
1496    (
1497    boolean bufferofsonly
1498    )
1499 
1500    {
1501    int sec;
1502 
1503    if ( !SHOW_TOP_STATUS_BAR() )
1504       {
1505       return;
1506       }
1507 
1508    if (timelimitenabled == true)
1509       {
1510       sec = (timelimit-gamestate.TimeCount) / VBLCOUNTER;
1511       }
1512    else
1513       {
1514       sec = gamestate.TimeCount / VBLCOUNTER;
1515       }
1516 
1517    if ( oldsec != sec )
1518       {
1519       oldsec = sec;
1520       DrawTimeXY( GAMETIME_X, GAMETIME_Y, sec, bufferofsonly) ;
1521       }
1522    }
1523 
1524 
1525 //******************************************************************************
1526 //
1527 // DrawMPPic ()
1528 //
1529 // Purpose
1530 //    Draws a masked, planer pic at xpos, ypos.
1531 //
1532 // Parms
1533 //    xpos   - x position.
1534 //    ypos   - y position.
1535 //    width  - width of pic : should be << 2.
1536 //    height - height of pic.
1537 //    src    - data to draw.
1538 //
1539 // Returns
1540 //    Nothing.
1541 //
1542 //******************************************************************************
1543 
DrawMPPic(int xpos,int ypos,int width,int height,int heightmod,byte * src,boolean bufferofsonly)1544 void DrawMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly)
1545 {
1546    byte *olddest;
1547    byte *dest;
1548    int x;
1549    int y;
1550    int planes;
1551    byte mask;
1552    byte pixel;
1553 
1554    mask = 1 << (xpos&3);
1555 
1556 #ifdef DOS
1557    olddest = (byte *)(ylookup[ypos] + (xpos>>2));
1558 #else
1559    olddest = (byte *)(ylookup[ypos] + xpos);
1560 #endif
1561 
1562    for (planes = 0; planes < 4; planes++)
1563    {
1564       VGAMAPMASK (mask);
1565 
1566       dest = olddest;
1567 
1568 #ifndef DOS
1569       dest += planes;
1570 #endif
1571 
1572       for (y = 0; y < height; y++)
1573       {
1574          for (x = 0; x < width; x++)
1575          {
1576             pixel = *src++;
1577 
1578             if (pixel != 255)
1579             {
1580                if (bufferofsonly)
1581                   *(dest+bufferofs) = pixel;
1582                else
1583                {
1584                   *(dest+page1start) = pixel;
1585                   *(dest+page2start) = pixel;
1586                   *(dest+page3start) = pixel;
1587                }
1588             }
1589 
1590 #ifdef DOS
1591             dest++;
1592 #else
1593             dest += 4;
1594 #endif
1595          }
1596 
1597 #ifdef DOS
1598          dest += (linewidth-width);
1599 #else
1600          dest += (linewidth-width*4);
1601 #endif
1602       }
1603 
1604       if (heightmod)
1605          src += (heightmod*width);
1606 
1607 #ifdef DOS
1608       mask <<= 1;
1609       if (mask == 16)
1610       {
1611          mask = 1;
1612          olddest++;
1613       }
1614 #endif
1615    }
1616 }
1617 
1618 
1619 //******************************************************************************
1620 //
1621 // DrawColoredMPPic ()
1622 //
1623 // Purpose
1624 //    Draws a masked, planer pic at xpos, ypos.
1625 //
1626 // Parms
1627 //    xpos   - x position.
1628 //    ypos   - y position.
1629 //    width  - width of pic : should be << 2.
1630 //    height - height of pic.
1631 //    src    - data to draw.
1632 //
1633 // Returns
1634 //    Nothing.
1635 //
1636 //******************************************************************************
1637 
DrawColoredMPPic(int xpos,int ypos,int width,int height,int heightmod,byte * src,boolean bufferofsonly,int color)1638 void DrawColoredMPPic (int xpos, int ypos, int width, int height, int heightmod, byte *src, boolean bufferofsonly, int color)
1639 {
1640    byte *olddest;
1641    byte *dest;
1642    int x;
1643    int y;
1644    int planes;
1645    byte mask;
1646    byte pixel;
1647    byte * cmap;
1648 
1649    cmap=playermaps[color]+(1<<12);
1650 
1651    mask = 1 << (xpos&3);
1652 
1653 #ifdef DOS
1654    olddest = (byte *)(ylookup[ypos] + (xpos>>2));
1655 #else
1656    olddest = (byte *)(ylookup[ypos] + xpos);
1657 #endif
1658 
1659    for (planes = 0; planes < 4; planes++)
1660    {
1661       VGAMAPMASK (mask);
1662 
1663       dest = olddest;
1664 
1665 #ifndef DOS
1666       dest += planes;
1667 #endif
1668 
1669       for (y = 0; y < height; y++)
1670       {
1671          for (x = 0; x < width; x++)
1672          {
1673             pixel = *src++;
1674 
1675             pixel = *(cmap+pixel);
1676 
1677             if (pixel != 255)
1678             {
1679                if (bufferofsonly)
1680                   *(dest+bufferofs) = pixel;
1681                else
1682                {
1683                   *(dest+page1start) = pixel;
1684                   *(dest+page2start) = pixel;
1685                   *(dest+page3start) = pixel;
1686                }
1687             }
1688 
1689 #ifdef DOS
1690             dest++;
1691 #else
1692             dest += 4;
1693 #endif
1694          }
1695 
1696 #ifdef DOS
1697          dest += (linewidth-width);
1698 #else
1699          dest += (linewidth-width*4);
1700 #endif
1701       }
1702 
1703       if (heightmod)
1704          src += (heightmod*width);
1705 
1706 #ifdef DOS
1707       mask <<= 1;
1708       if (mask == 16)
1709       {
1710          mask = 1;
1711          olddest++;
1712       }
1713 #endif
1714    }
1715 }
1716 
1717 
1718 //******************************************************************************
1719 //
1720 // UpdateScore ()
1721 //
1722 //******************************************************************************
1723 
UpdateScore(unsigned int num)1724 void UpdateScore (unsigned int num)
1725 {
1726    if (num > 999999999)
1727    {
1728       num = 999999999;
1729       gamestate.score = 999999999;
1730    }
1731 
1732    ltoa (num, ScoreStr.str, 10);
1733    ScoreStr.length = strlen (ScoreStr.str);
1734 }
1735 
1736 
1737 //******************************************************************************
1738 //
1739 // UpdateLives ()
1740 //
1741 //******************************************************************************
1742 
UpdateLives(int num)1743 void UpdateLives (int num)
1744 {
1745    ltoa (num, LivesStr.str, 10);
1746    LivesStr.length = strlen (LivesStr.str);
1747 }
1748 
1749 //****************************************************************************
1750 //
1751 // ClearTriads ()
1752 //
1753 //****************************************************************************
ClearTriads(playertype * pstate)1754 void ClearTriads (playertype * pstate)
1755 {
1756    pstate->triads = 0;
1757    ltoa (pstate->triads, TriadStr.str, 10);
1758    TriadStr.length = strlen (TriadStr.str);
1759 }
1760 
1761 //****************************************************************************
1762 //
1763 // UpdateTriads ()
1764 //
1765 //****************************************************************************
1766 
UpdateTriads(objtype * ob,int num)1767 void UpdateTriads (objtype * ob, int num)
1768 {
1769    playertype * pstate;
1770 
1771 	M_LINKSTATE(ob,pstate);
1772 
1773    pstate->triads += num;
1774 
1775    if (pstate->triads >= 100)
1776    {
1777       GiveLives(1);
1778       if (ob==player)
1779          {
1780          AddMessage("100 Life Item Points!  Extra Life!\n",MSG_BONUS);
1781          SD_PlaySoundRTP (SD_GET1UPSND, player->x, player->y);
1782          }
1783       pstate->triads -= 100;
1784    }
1785 
1786    if (ob==player)
1787       {
1788       ltoa (pstate->triads, TriadStr.str, 10);
1789       TriadStr.length = strlen (TriadStr.str);
1790       }
1791 }
1792 
1793 //****************************************************************************
1794 //
1795 // DrawTriads ()
1796 //
1797 //****************************************************************************
1798 
DrawTriads(boolean bufferofsonly)1799 void DrawTriads
1800    (
1801    boolean bufferofsonly
1802    )
1803 
1804    {
1805    if ( !SHOW_TOP_STATUS_BAR() )
1806       {
1807       return;
1808       }
1809 
1810    if ( !EndLevelStuff )
1811       {
1812       DrawNumber( TRIAD_X, TRIAD_Y, 2, 3, bufferofsonly );
1813       }
1814    }
1815 
1816 
1817 //******************************************************************************
1818 //
1819 // DrawPPic ()
1820 //
1821 //******************************************************************************
1822 
DrawPPic(int xpos,int ypos,int width,int height,byte * src,int num,boolean up,boolean bufferofsonly)1823 void DrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up, boolean bufferofsonly)
1824 {
1825    byte *olddest;
1826    byte *dest;
1827    int x;
1828    int y;
1829    int planes;
1830    byte mask;
1831    byte pixel;
1832    int k;
1833    int amt;
1834 
1835 #ifdef DOS
1836    if (up)
1837       amt = 2;
1838    else
1839       amt = -2;
1840 #else
1841    if (up)
1842       amt = 8;
1843    else
1844       amt = -8;
1845 #endif
1846 
1847    mask = 1;
1848 
1849 #ifdef DOS
1850    olddest = (byte *)(ylookup[ypos] + (xpos>>2));
1851 #else
1852    olddest = (byte *)(ylookup[ypos] + xpos);
1853 #endif
1854 
1855    for (planes = 0; planes < 4; planes++)
1856    {
1857       VGAMAPMASK (mask);
1858 
1859       dest = olddest;
1860 
1861 #ifndef DOS
1862       dest += planes;
1863 #endif
1864 
1865       for (y = 0; y < height; y++)
1866       {
1867          for (x = 0; x < width; x++)
1868          {
1869             pixel = *src++;
1870 
1871             if (pixel != 255)
1872             {
1873                for (k = 0; k < num; k++)
1874                {
1875                   if (bufferofsonly)
1876                      *(dest+bufferofs+(amt*k)) = pixel;
1877                   else
1878                   {
1879                      *(dest+page1start+(amt*k)) = pixel;
1880                      *(dest+page2start+(amt*k)) = pixel;
1881                      *(dest+page3start+(amt*k)) = pixel;
1882                   }
1883                }
1884             }
1885 
1886 #ifdef DOS
1887             dest++;
1888 #else
1889             dest += 4;
1890 #endif
1891          }
1892 
1893 #ifdef DOS
1894          dest += (linewidth-width);
1895 #else
1896          dest += (linewidth-width*4);
1897 #endif
1898       }
1899 
1900       mask <<= 1;
1901    }
1902 }
1903 
1904 
1905 //****************************************************************************
1906 //
1907 // DrawBarHealth ()
1908 //
1909 //****************************************************************************
1910 
DrawBarHealth(boolean bufferofsonly)1911 void DrawBarHealth
1912    (
1913    boolean bufferofsonly
1914    )
1915 
1916    {
1917    int percenthealth;
1918    int health_y;
1919 
1920    if ( !SHOW_BOTTOM_STATUS_BAR() )
1921       {
1922       return;
1923       }
1924 
1925    health_y = HEALTH_Y;
1926    if ( SHOW_KILLS() )
1927       {
1928       health_y -= KILLS_HEIGHT;
1929       }
1930 
1931    percenthealth = ( locplayerstate->health * 10 ) /
1932       MaxHitpointsForCharacter( locplayerstate );
1933 
1934    oldpercenthealth = percenthealth + 1;
1935 
1936    if ( playstate == ex_died )
1937       {
1938       DrawPPic( HEALTH_X, health_y, 8 >> 2, 16, ( byte * )&erase->data,
1939          10, true, bufferofsonly );
1940 
1941       return;
1942       }
1943 
1944    if ( locplayerstate->health <= 0 )
1945       {
1946       oldpercenthealth = 0;
1947       }
1948 
1949    if ( oldpercenthealth >= 11 )
1950       {
1951       oldpercenthealth = 10;
1952       }
1953 
1954    if ( oldpercenthealth < 4 )
1955       {
1956       DrawPPic( HEALTH_X, health_y, 8 >> 2, 16,
1957          ( byte * )&health[ 0 ]->data, oldpercenthealth,
1958          true, bufferofsonly );
1959       }
1960    else if ( oldpercenthealth < 5 )
1961       {
1962       DrawPPic( HEALTH_X, health_y, 8 >> 2, 16,
1963          (byte *)&health[ 1 ]->data, oldpercenthealth,
1964          true, bufferofsonly );
1965       }
1966    else
1967       {
1968       DrawPPic( HEALTH_X, health_y, 8 >> 2, 16,
1969          ( byte * )&health[ 2 ]->data, oldpercenthealth,
1970          true, bufferofsonly );
1971       }
1972 
1973    if ( oldpercenthealth < 10 )
1974       {
1975       DrawPPic( HEALTH_X + ( 8 * oldpercenthealth ), health_y,
1976          8 >> 2, 16, ( byte * )&erase->data, 10 - oldpercenthealth,
1977          true, bufferofsonly );
1978       }
1979    }
1980 
1981 
1982 //****************************************************************************
1983 //
1984 // DrawBarAmmo ()
1985 //
1986 //****************************************************************************
1987 
DrawBarAmmo(boolean bufferofsonly)1988 void DrawBarAmmo
1989    (
1990    boolean bufferofsonly
1991    )
1992 
1993    {
1994    int ammo_y;
1995 
1996    if ( ( !SHOW_BOTTOM_STATUS_BAR() ) || ( playstate == ex_died ) )
1997       {
1998       return;
1999       }
2000 
2001    ammo_y = AMMO_Y;
2002    if ( SHOW_KILLS() )
2003       {
2004       ammo_y -= KILLS_HEIGHT;
2005       }
2006 
2007    DrawPPic ( AMMO_X, ammo_y + 1, 8 >> 2, 16, ( byte * )&erase->data,
2008       10, false, bufferofsonly );
2009 
2010    if ( !ARMED( player->dirchoosetime ) )
2011       {
2012       return;
2013       }
2014    if ((locplayerstate->new_weapon < wp_bazooka) ||
2015        (locplayerstate->new_weapon == wp_godhand) ||
2016        ( gamestate.BattleOptions.Ammo == bo_infinite_shots )
2017       )
2018       {
2019       DrawPPic( AMMO_X - 16, ammo_y, 24 >> 2, 16,
2020          ( byte * )&ammo[ 0 ]->data, 1, true, bufferofsonly);
2021 
2022       DrawPPic( AMMO_X - 32, ammo_y + 1, 8 >> 2, 16,
2023          ( byte * )&erase->data, 2, true, bufferofsonly );
2024       }
2025 #if (SHAREWARE == 0)
2026    else if ( locplayerstate->new_weapon == wp_dog )
2027       {
2028       DrawPPic( AMMO_X - 16, ammo_y, 24 >> 2, 16,
2029          ( byte * )&ammo[12]->data, 1, true, bufferofsonly );
2030 
2031       DrawPPic( AMMO_X - 32, ammo_y + 1, 8 >> 2, 16,
2032          ( byte * )&erase->data, 2, true, bufferofsonly );
2033       }
2034 #endif
2035    else
2036       {
2037       DrawPPic( AMMO_X, ammo_y + 1, 8 >> 2, 16,
2038          ( byte * )&ammo[ locplayerstate->new_weapon]->data,
2039          locplayerstate->ammo, false, bufferofsonly );
2040       }
2041    }
2042 
2043 
2044 //******************************************************************************
2045 //
2046 // SingleDrawPPic ()
2047 //
2048 //******************************************************************************
2049 
SingleDrawPPic(int xpos,int ypos,int width,int height,byte * src,int num,boolean up)2050 void SingleDrawPPic (int xpos, int ypos, int width, int height, byte *src, int num, boolean up)
2051 {
2052    byte *olddest;
2053    byte *dest;
2054    int x;
2055 	int y;
2056    int planes;
2057    byte mask;
2058    byte pixel;
2059    int k;
2060    int amt;
2061 
2062 #ifdef DOS
2063    if (up)
2064       amt = 2;
2065    else
2066       amt = -2;
2067 #else
2068    if (up)
2069       amt = 8;
2070    else
2071       amt = -8;
2072 #endif
2073 
2074    mask = 1;
2075 
2076 #ifdef DOS
2077    olddest = (byte *)(bufferofs - screenofs + ylookup[ypos] + (xpos>>2));
2078 #else
2079    olddest = (byte *)(bufferofs - screenofs + ylookup[ypos] + xpos);
2080 #endif
2081 
2082    for (planes = 0; planes < 4; planes++)
2083    {
2084       VGAMAPMASK (mask);
2085 
2086       dest = olddest;
2087 
2088 #ifndef DOS
2089       dest += planes;
2090 #endif
2091 
2092       for (y = 0; y < height; y++)
2093       {
2094          for (x = 0; x < width; x++)
2095          {
2096             pixel = *src++;
2097 
2098             if (pixel != 255)
2099             {
2100                for (k = 0; k < num; k++)
2101                {
2102                   *(dest+(amt*k)) = pixel;
2103                }
2104             }
2105 
2106 #ifdef DOS
2107             dest++;
2108 #else
2109             dest += 4;
2110 #endif
2111          }
2112 
2113 #ifdef DOS
2114          dest += (linewidth-width);
2115 #else
2116          dest += (linewidth-width*4);
2117 #endif
2118       }
2119 
2120       mask <<= 1;
2121    }
2122 }
2123 
2124 
2125 
2126 //****************************************************************************
2127 //
2128 // DrawStats ()
2129 //
2130 //****************************************************************************
2131 
DrawStats(void)2132 void DrawStats
2133    (
2134    void
2135    )
2136 
2137    {
2138    int percenthealth;
2139    int health_y;
2140    int ammo_y;
2141 
2142    if ( ( !SHOW_PLAYER_STATS() ) || ( playstate == ex_died ) ||
2143       ( locplayerstate->health <= 0 ) )
2144       {
2145       return;
2146       }
2147 
2148 // Uncomment this if we want transparent health only on sizes < 16
2149 //   if ( viewsize < 16 )
2150 //      {
2151 //      pic_t *shape;
2152 //
2153 //      shape = W_CacheLumpName( "backtile", PU_CACHE );
2154 //      DrawTiledRegion( 0, 160, 320, 24, shape );
2155 //      }
2156 
2157    health_y = HEALTH_Y;
2158    ammo_y   = AMMO_Y;
2159 
2160    if ( SHOW_KILLS() )
2161       {
2162       health_y -= KILLS_HEIGHT;
2163       ammo_y   -= KILLS_HEIGHT;
2164       }
2165 
2166    if ( oldplayerhealth != locplayerstate->health )
2167       {
2168       oldplayerhealth = locplayerstate->health;
2169 
2170       percenthealth = ( locplayerstate->health * 10 ) /
2171          MaxHitpointsForCharacter( locplayerstate );
2172 
2173       oldpercenthealth = percenthealth + 1;
2174       }
2175 
2176    if ( oldpercenthealth > 10 )
2177       {
2178       oldpercenthealth = 10;
2179       }
2180 
2181    if ( oldpercenthealth < 4 )
2182       {
2183       SingleDrawPPic( HEALTH_X - 16, health_y, 8 >> 2, 16,
2184          ( byte * )&health[ 3 ]->data, oldpercenthealth, true);
2185       }
2186    else if ( oldpercenthealth < 5 )
2187       {
2188       SingleDrawPPic( HEALTH_X - 16, health_y, 8 >> 2, 16,
2189          ( byte * )&health[ 4 ]->data, oldpercenthealth, true );
2190       }
2191    else
2192       {
2193       SingleDrawPPic( HEALTH_X - 16, health_y, 8 >> 2, 16,
2194          ( byte * )&health[ 5 ]->data, oldpercenthealth, true );
2195       }
2196 
2197    if ( ARMED( consoleplayer ) )
2198       {
2199       if ((locplayerstate->new_weapon < wp_bazooka) ||
2200           (locplayerstate->new_weapon == wp_godhand) ||
2201           (gamestate.BattleOptions.Ammo == bo_infinite_shots )
2202          )
2203 
2204         {
2205          SingleDrawPPic( AMMO_X - 16, ammo_y, 24 >> 2, 16,
2206             ( byte * )&ammo[13]->data, 1, true );
2207          }
2208 #if (SHAREWARE == 0)
2209       else if ( locplayerstate->new_weapon == wp_dog )
2210          {
2211          SingleDrawPPic( AMMO_X - 16, ammo_y + 1, 24 >> 2, 16,
2212             ( byte * )&ammo[25]->data, 1, true );
2213          }
2214 #endif
2215       else
2216          {
2217          SingleDrawPPic( AMMO_X, ammo_y + 1, 8 >> 2, 16,
2218             ( byte * )&ammo[13 + locplayerstate->new_weapon]->data,
2219             locplayerstate->ammo, false );
2220          }
2221       }
2222    }
2223 
2224 
2225 //****************************************************************************
2226 //
2227 // DrawPauseXY ()
2228 //
2229 //****************************************************************************
2230 
DrawPauseXY(int x,int y)2231 void DrawPauseXY (int x, int y)
2232 {
2233    pic_t *p;
2234 
2235    if (GamePaused == true)
2236    {
2237       p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("paused"), PU_CACHE, Cvt_pic_t, 1);
2238       VWB_DrawPic (x, y, p);
2239       DrawEpisodeLevel (x,y);
2240    }
2241    else
2242    {
2243       p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("wait"), PU_CACHE, Cvt_pic_t, 1);
2244       VWB_DrawPic (x, y, p);
2245    }
2246 }
2247 
2248 //****************************************************************************
2249 //
2250 // DrawPause ()
2251 //
2252 //****************************************************************************
2253 
DrawPause(void)2254 void DrawPause (void)
2255 {
2256    pic_t *p;
2257    int bufftemp = bufferofs;
2258 
2259    bufferofs -= screenofs;
2260 
2261    if (GamePaused == true)
2262    {
2263       p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("paused"), PU_CACHE, Cvt_pic_t, 1);
2264       DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1);
2265    }
2266    else
2267    {
2268       p = (pic_t *) W_CacheLumpNum (W_GetNumForName ("wait"), PU_CACHE, Cvt_pic_t, 1);
2269       DrawPauseXY( (320-(p->width<<2) ) >>1, (200-p->height)>>1);
2270    }
2271 
2272    bufferofs = bufftemp;
2273 }
2274 
2275 //****************************************************************************
2276 //
2277 // GM_DrawBonus ()
2278 //
2279 //****************************************************************************
2280 
GM_DrawBonus(int which)2281 void GM_DrawBonus
2282    (
2283    int which
2284    )
2285 
2286    {
2287    int    x;
2288 
2289    if ( which < stat_gasmask )
2290       {
2291       x = POWERUP1X;
2292       poweruptime = GetBonusTimeForItem(which);
2293       poweradjust = (poweruptime >> 4);
2294       powerupheight  = 0;
2295       GM_UpdateBonus(poweruptime-poweradjust - 1,true);
2296 
2297       }
2298    else
2299       {
2300       x = POWERUP2X;
2301       protectiontime = GetBonusTimeForItem(which);
2302       poweradjust = (protectiontime >> 4);
2303       protectionheight = 0;
2304       GM_UpdateBonus(protectiontime-poweradjust-1,false);
2305 
2306       }
2307 
2308    }
2309 
2310 
2311 //******************************************************************************
2312 //
2313 // GM_UpdateBonus ()
2314 //
2315 //******************************************************************************
2316 
GM_UpdateBonus(int time,int powerup)2317 void GM_UpdateBonus
2318    (
2319    int time,
2320    int powerup
2321    )
2322 
2323    {
2324    pic_t *shape;
2325    int    shapenum;
2326 
2327    if ( powerup )
2328       {
2329       if ( time < ( poweruptime - poweradjust ) )
2330          {
2331          powerupheight++;
2332          if ( !SHOW_TOP_STATUS_BAR() )
2333             {
2334             poweruptime = time;
2335             }
2336          }
2337       }
2338    else
2339       {
2340       if ( time < ( protectiontime - poweradjust ) )
2341          {
2342          protectionheight++;
2343          if ( !SHOW_TOP_STATUS_BAR() )
2344             {
2345             protectiontime = time;
2346             }
2347          }
2348       }
2349 
2350 
2351    if ( !SHOW_TOP_STATUS_BAR() )
2352       {
2353       return;
2354       }
2355 
2356    if ( !time )
2357       {
2358       if ( powerup == 1 )
2359          {
2360          shapenum = POWERUP1X;
2361          }
2362       else
2363          {
2364          shapenum = POWERUP2X;
2365          }
2366 
2367       GM_MemToScreen( ( byte * )&eraseb->data, eraseb->width,
2368          eraseb->height, shapenum, POWERUPY );
2369 
2370       return;
2371       }
2372 
2373    if ( powerup )
2374       {
2375       if ( time < ( poweruptime - poweradjust ) )
2376          {
2377    	   if ( player->flags & FL_GODMODE )
2378             {
2379             shapenum = powerpics;
2380             }
2381          else if ( player->flags & FL_DOGMODE )
2382             {
2383             shapenum = powerpics + 1;
2384             }
2385          else if ( player->flags & FL_FLEET )
2386             {
2387             shapenum = powerpics + 2;
2388             }
2389          else if ( player->flags & FL_ELASTO )
2390             {
2391             shapenum = powerpics + 3;
2392             }
2393          else if ( player->flags & FL_SHROOMS )
2394             {
2395             shapenum = powerpics + 4;
2396             }
2397          else
2398             {
2399             GM_MemToScreen( ( byte * )&eraseb->data,
2400                eraseb->width, eraseb->height, POWERUP1X, POWERUPY );
2401 
2402             return;
2403             }
2404 
2405          poweruptime = time;
2406 
2407          shape = ( pic_t * )W_CacheLumpNum( shapenum, PU_CACHE, Cvt_pic_t, 1 );
2408 
2409          GM_MemToScreen( ( byte * )&eraseb->data, eraseb->width,
2410             eraseb->height, POWERUP1X, POWERUPY );
2411 
2412          DrawMPPic( POWERUP1X, POWERUPY + powerupheight, shape->width,
2413             shape->height - powerupheight, powerupheight,
2414             ( byte * )&shape->data, false );
2415          }
2416       }
2417    else
2418       {
2419       if ( time < ( protectiontime - poweradjust ) )
2420          {
2421          if ( player->flags & FL_BPV )
2422             {
2423             shapenum = powerpics + 6;
2424             }
2425          else if ( player->flags & FL_GASMASK )
2426             {
2427             shapenum = powerpics + 5;
2428             }
2429          else if ( player->flags & FL_AV )
2430             {
2431             shapenum = powerpics + 7;
2432             }
2433 
2434          protectiontime = time;
2435 
2436          shape = ( pic_t * )W_CacheLumpNum( shapenum, PU_CACHE, Cvt_pic_t, 1 );
2437 
2438          GM_MemToScreen( ( byte * )&eraseb->data, eraseb->width,
2439             eraseb->height, POWERUP2X, POWERUPY );
2440 
2441          DrawMPPic( POWERUP2X, POWERUPY + protectionheight,
2442             shape->width, shape->height - protectionheight,
2443             protectionheight, ( byte * )&shape->data, false );
2444          }
2445       }
2446    }
2447 
2448 
2449 //******************************************************************************
2450 //
2451 // Drawpic ()
2452 //
2453 // Purpose
2454 //    Draws a masked, planer pic at xpos, ypos.
2455 //
2456 // Parms
2457 //    xpos   - x position.
2458 //    ypos   - y position.
2459 //    width  - width of pic : should be << 2.
2460 //    height - height of pic.
2461 //    src    - data to draw.
2462 //
2463 // Returns
2464 //    Nothing.
2465 //
2466 //******************************************************************************
2467 
Drawpic(int xpos,int ypos,int width,int height,byte * src)2468 void Drawpic (int xpos, int ypos, int width, int height, byte *src)
2469 {
2470    byte *olddest;
2471    byte *dest;
2472    int x;
2473    int y;
2474    int planes;
2475    byte mask;
2476    byte pixel;
2477 
2478 
2479    mask = 1 << (xpos&3);
2480 
2481 #ifdef DOS
2482    olddest = (byte *)(bufferofs + ylookup[ypos] + (xpos>>2));
2483 #else
2484    olddest = (byte *)(bufferofs + ylookup[ypos] + xpos);
2485 #endif
2486    for (planes = 0; planes < 4; planes++)
2487    {
2488       VGAMAPMASK (mask);
2489 
2490       dest = olddest;
2491 
2492 #ifdef DOS
2493       dest += planes;
2494 #endif
2495 
2496       for (y = 0; y < height; y++)
2497       {
2498          for (x = 0; x < width; x++)
2499          {
2500             pixel = *src++;
2501 
2502             if (pixel != 255)
2503                *(dest) = pixel;
2504 
2505 #ifdef DOS
2506             dest++;
2507 #else
2508             dest += 4;
2509 #endif
2510          }
2511 
2512 #ifdef DOS
2513          dest += (linewidth-width);
2514 #else
2515          dest += (linewidth-width*4);
2516 #endif
2517       }
2518 
2519 #ifdef DOS
2520       mask <<= 1;
2521       if (mask == 16)
2522 		{
2523          mask = 1;
2524          olddest++;
2525       }
2526 #endif
2527    }
2528 }
2529 
2530 
2531 //******************************************************************************
2532 //
2533 // DrawEpisodeLevel ()
2534 //
2535 // right justifies and pads with blanks
2536 //
2537 //******************************************************************************
2538 
DrawEpisodeLevel(int x,int y)2539 void  DrawEpisodeLevel (int x, int y)
2540 {
2541    int level;
2542    char  str[20];
2543    pic_t *p;
2544 
2545    if (!BATTLEMODE)
2546    {
2547       ltoa (gamestate.episode, str, 10);
2548 
2549       Drawpic (x+29, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
2550 
2551       if ((gamestate.mapon == 6) || (gamestate.mapon == 14) ||
2552           (gamestate.mapon == 22) || (gamestate.mapon == 32) ||
2553           (gamestate.mapon == 33))
2554       {
2555          p = (pic_t *) W_CacheLumpName ("tnumb", PU_CACHE, Cvt_pic_t, 1);
2556          Drawpic (x+40, y+16, 8>>2, 16, (byte *)&p->data);
2557 
2558          if (gamestate.mapon == 6)
2559             level = 1;
2560          else
2561             if (gamestate.mapon == 14)
2562                level = 2;
2563             else
2564                if (gamestate.mapon == 22)
2565                   level = 3;
2566                else
2567                   if (gamestate.mapon == 32)
2568 							level = 4;
2569                   else
2570                      level = 5;
2571       }
2572       else
2573          level = GetLevel (gamestate.episode, gamestate.mapon);
2574 
2575       level = abs(level);
2576       ltoa (level, str, 10);
2577 
2578       if (level < 10)
2579          Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
2580       else
2581       {
2582          Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
2583          Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data);
2584       }
2585    }
2586    else
2587    {
2588       p = (pic_t *) W_CacheLumpName ("battp", PU_CACHE, Cvt_pic_t, 1);
2589       Drawpic (x+16, y+15, 32>>2, 16, (byte *)&p->data);
2590 
2591       level = abs(gamestate.mapon + 1);
2592       ltoa (level, str, 10);
2593 
2594       if (level < 10)
2595          Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
2596       else
2597       {
2598          Drawpic (x+49, y+16, 8>>2, 16, (byte *)&timenums[str[0]-'0']->data);
2599          Drawpic (x+57, y+16, 8>>2, 16, (byte *)&timenums[str[1]-'0']->data);
2600       }
2601    }
2602 }
2603 
2604 
2605 //******************************************************************************
2606 //
2607 // GM_MemToScreen ()
2608 //
2609 //******************************************************************************
2610 
GM_MemToScreen(byte * source,int width,int height,int x,int y)2611 void GM_MemToScreen (byte *source, int width, int height, int x, int y)
2612 {
2613    byte *dest, *dest1, *dest2, *dest3, mask;
2614    byte *screen1, *screen2, *screen3;
2615    int  plane;
2616    int w;
2617 
2618 #ifdef DOS
2619    dest = (byte *)(ylookup[y]+(x>>2));
2620 #else
2621    dest = (byte *)(ylookup[y]+x);
2622 #endif
2623    mask = 1 << (x&3);
2624 
2625    dest1 = (byte *)(dest+page1start);
2626    dest2 = (byte *)(dest+page2start);
2627    dest3 = (byte *)(dest+page3start);
2628 
2629    for (plane = 0; plane<4; plane++)
2630    {
2631       VGAMAPMASK (mask);
2632 
2633       screen1 = dest1;
2634       screen2 = dest2;
2635       screen3 = dest3;
2636       for (y = 0; y < height; y++, screen1 += linewidth,
2637                                    screen2 += linewidth,
2638                                    screen3 += linewidth, source+=width)
2639       {
2640 #ifdef DOS
2641          memcpy (screen1, source, width);
2642          memcpy (screen2, source, width);
2643          memcpy (screen3, source, width);
2644 #else
2645 	for (x = 0; x < width; x++) {
2646 		screen1[x*4+plane] = source[x];
2647 		screen2[x*4+plane] = source[x];
2648 		screen3[x*4+plane] = source[x];
2649 	}
2650 #endif
2651       }
2652 
2653 #ifdef DOS
2654       mask <<= 1;
2655 
2656       if (mask == 16)
2657       {
2658          mask = 1;
2659          dest1++;
2660          dest2++;
2661          dest3++;
2662       }
2663 #endif
2664    }
2665 }
2666 
2667 
2668 //==========================================================================
2669 
2670 /*
2671 ==================
2672 =
2673 = ScreenShake
2674 =
2675 ==================
2676 */
2677 
ScreenShake(void)2678 void ScreenShake (void)
2679 {
2680    static int which = 0;
2681 
2682    if (SHAKETICS != 0xFFFF)
2683    {
2684       SHAKETICS -= tics;
2685 
2686       which = (RandomNumber ("ScreenShake",0) & 3);
2687 
2688       switch (which)
2689       {
2690          case 0:
2691             displayofs += 1;
2692          break;
2693 
2694          case 1:
2695             displayofs -= 1;
2696          break;
2697 
2698          case 2:
2699             displayofs += 3*SCREENBWIDE;
2700          break;
2701 
2702          case 3:
2703             displayofs -= 3*SCREENBWIDE;
2704          break;
2705       }
2706    }
2707 }
2708 
2709 //******************************************************************************
2710 //
2711 // DoBorderShifts ()
2712 //
2713 //******************************************************************************
2714 
DoBorderShifts(void)2715 void DoBorderShifts (void)
2716 {
2717 	if (damagecount)
2718    {
2719       if (damagecount > 100)
2720          damagecount = 100;
2721 
2722       damagecount -= 6;
2723 
2724       if (damagecount < 0)
2725          damagecount = 0;
2726 
2727       SetBorderColor (*(colormap+(((100-damagecount)>>2)<<8)+48));
2728 
2729       borderset = true;
2730    }
2731    else
2732       if (borderset)
2733       {
2734          SetBorderColor (0);
2735          borderset = false;
2736       }
2737 }
2738 
2739 
2740 //******************************************************************************
2741 //
2742 // DrawHighScores ()
2743 //
2744 //******************************************************************************
2745 
DrawHighScores(void)2746 void DrawHighScores (void)
2747 {
2748    char buffer[16];
2749 #if (SHAREWARE == 0)
2750    char buffer1[5];
2751 #endif
2752    int  i,
2753         w,
2754         h;
2755    HighScore *s;
2756 
2757    for (i = 0, s = Scores; i < MaxScores; i++, s++)
2758    {
2759       PrintY = 25 + (16 * i);
2760 
2761       //
2762       // name
2763       //
2764 		PrintX = 3*8;
2765       DrawMenuBufPropString (PrintX, PrintY, s->name);
2766 
2767       //
2768       // level
2769       //
2770       ultoa (s->completed, buffer, 10);
2771 
2772       PrintX = (17 * 8)-10;
2773 #if (SHAREWARE == 0)
2774       itoa (s->episode, buffer1, 10);
2775 
2776       DrawMenuBufPropString (PrintX, PrintY, buffer1);
2777 #else
2778       DrawMenuBufPropString (PrintX, PrintY, "S");
2779 #endif
2780 
2781       DrawMenuBufPropString (PrintX, PrintY, "-");
2782 
2783 #if (SHAREWARE == 0)
2784       if (s->completed == 7)
2785          DrawMenuBufPropString (PrintX, PrintY, "B");
2786       else if (s->completed == 8)
2787          DrawMenuBufPropString (PrintX, PrintY, "S");
2788       else if (s->completed == 9)
2789          DrawMenuBufPropString (PrintX, PrintY, "C");
2790       else if (s->completed == 10)
2791          DrawMenuBufPropString (PrintX, PrintY, "D");
2792       else
2793          DrawMenuBufPropString (PrintX, PrintY, buffer);
2794 #else
2795       DrawMenuBufPropString (PrintX, PrintY, buffer);
2796 #endif
2797 
2798       //
2799       // score
2800       //
2801       ultoa(s->score,buffer,10);
2802 
2803       VW_MeasurePropString (buffer, &w, &h);
2804       PrintX = (33 * 8) - w;
2805       DrawMenuBufPropString (PrintX, PrintY, buffer);
2806    }
2807 }
2808 
2809 
2810 
2811 //******************************************************************************
2812 //
2813 // CheckHighScore ()
2814 //
2815 //******************************************************************************
2816 
CheckHighScore(long score,word other,boolean INMENU)2817 void CheckHighScore (long score, word other, boolean INMENU)
2818 {
2819    word        i,j;
2820    int         n;
2821    HighScore   myscore;
2822    int         level;
2823 
2824    MenuFadeIn();
2825    if (!INMENU)
2826       SetupMenuBuf ();
2827 
2828    strcpy (myscore.name,"");
2829    myscore.score     = score;
2830 
2831    level = GetLevel (gamestate.episode, other-1);
2832 
2833    myscore.episode   = gamestate.episode;
2834    myscore.completed = level;
2835 
2836    CurrentFont = smallfont;
2837 
2838    for (i = 0, n = -1; i < MaxScores; i++)
2839    {
2840       if ((myscore.score > Scores[i].score)  ||
2841          ((myscore.score == Scores[i].score) &&
2842           (myscore.completed > Scores[i].completed)))
2843       {
2844          for (j = MaxScores; --j > i;)
2845             Scores[j] = Scores[j - 1];
2846          Scores[i] = myscore;
2847          n = i;
2848          break;
2849       }
2850    }
2851 
2852    if (INMENU)
2853    {
2854       SetAlternateMenuBuf();
2855       SetMenuTitle ("High Scores");
2856       ClearMenuBuf();
2857       DrawHighScores ();
2858 		if (n != -1)
2859          DisplayInfo (6);
2860       else
2861          DisplayInfo (5);
2862       FlipMenuBuf ();
2863    }
2864    else
2865    {
2866       ClearMenuBuf ();
2867       SetMenuTitle ("High Scores");
2868       DrawHighScores ();
2869       if (n != -1)
2870          DisplayInfo (6);
2871       else
2872          DisplayInfo (5);
2873       RefreshMenuBuf (0);
2874    }
2875 
2876    if (n != -1)
2877    {
2878       PrintY = 25 + (16 * n);
2879       PrintX = 3*8;
2880       US_LineInput (PrintX, PrintY, Scores[n].name, NULL,
2881                     true, 10, 98, 0);
2882    }
2883    else
2884    {
2885       IN_ClearKeysDown ();
2886       if ( INMENU )
2887          {
2888          while( !IN_CheckAck () )
2889             {
2890             RefreshMenuBuf (0);
2891             }
2892          }
2893       else
2894          {
2895          for( i = 0; i <= 150; i += tics )
2896             {
2897             RefreshMenuBuf (0);
2898             if (IN_CheckAck ())
2899                {
2900                break;
2901                }
2902             }
2903          }
2904       }
2905 
2906    if (INMENU)
2907       {
2908       SD_Play (SD_ESCPRESSEDSND);
2909       }
2910    else
2911       {
2912       ShutdownMenuBuf ();
2913       }
2914    }
2915 
2916 
2917 //===========================================================================
2918 
2919 //#define HEADERX      140
2920 //#define BONERNAMEX   170
2921 #define HEADERX      152
2922 #define BONERNAMEX   166
2923 
2924 
2925 /*
2926 ==================
2927 =
2928 = DrawEOLHeader ()
2929 =
2930 ==================
2931 */
DrawEOLHeader(int playstate)2932 void DrawEOLHeader
2933    (
2934    int playstate
2935    )
2936 
2937    {
2938    int  health;
2939    char tempstr[ 15 ];
2940    char *string;
2941    int  level;
2942    int  w;
2943    int  h;
2944 
2945    VWB_TBar( 30, 5, 250, 75 );
2946 
2947    switch( playstate )
2948       {
2949       case ex_skiplevel :
2950          if ( ( gamestate.violence >= vl_high ) &&
2951             ( gamestate.difficulty >= gd_hard ) )
2952             {
2953             string = "LEVEL WUSSED OUT ON!";
2954             }
2955          else
2956             {
2957             string = "LEVEL SKIPPED.";
2958             }
2959          break;
2960 
2961       case ex_secretdone :
2962          string = "SECRET LEVEL COMPLETED!";
2963          break;
2964 
2965       case ex_secretlevel :
2966          string = "SECRET EXIT TAKEN!";
2967          break;
2968 
2969       case ex_gameover :
2970          string = "GAME COMPLETED!";
2971          break;
2972 
2973       case ex_bossdied :
2974          string = "BOSS DEFEATED!";
2975          break;
2976 
2977       default :
2978          string = "LEVEL COMPLETED!";
2979          break;
2980       }
2981 
2982    VW_MeasurePropString( string, &w, &h );
2983 
2984    px = ( 320 - w ) / 2;
2985    py = 10;
2986    VWB_DrawPropString( string );
2987 
2988    // draw episode number
2989    string = "EPISODE";
2990    VW_MeasurePropString( string, &w, &h );
2991    px = HEADERX - w;
2992    py = 25;
2993    VWB_DrawPropString( string );
2994 
2995    itoa( gamestate.episode, tempstr, 10 );
2996    px = BONERNAMEX;
2997    VWB_DrawPropString( tempstr );
2998 
2999    // draw area number
3000    level = GetLevel( gamestate.episode, gamestate.mapon );
3001    itoa( level, tempstr, 10 );
3002 
3003    py = 35;
3004 
3005    if ( playstate == ex_secretdone )
3006       {
3007       string = "SECRET AREA";
3008       }
3009    else if ( playstate == ex_bossdied )
3010       {
3011       string = "BOSS AREA";
3012       }
3013    else if ( gamestate.mapon == 32 )
3014       {
3015       string = "CHASE AREA";
3016       }
3017    else
3018       {
3019       string = "AREA";
3020       }
3021 
3022    VW_MeasurePropString( string, &w, &h);
3023    px = HEADERX - w;
3024    VWB_DrawPropString( string );
3025 
3026    if ( gamestate.mapon != 33 )
3027       {
3028       px = BONERNAMEX;
3029       VWB_DrawPropString( tempstr );
3030       }
3031 
3032    string = "SCORE";
3033    VW_MeasurePropString( string, &w, &h);
3034    px = HEADERX - w;
3035    py = 45;
3036    VWB_DrawPropString( string );
3037 
3038    px = BONERNAMEX;
3039    itoa( gamestate.score, tempstr, 10 );
3040 	VWB_DrawPropString( tempstr );
3041 
3042    string = "HEALTH";
3043    VW_MeasurePropString( string, &w, &h );
3044    px = HEADERX - w;
3045    py = 55;
3046    VWB_DrawPropString( string );
3047 
3048    px = BONERNAMEX;
3049    health = ( ( locplayerstate->health * 100 ) /
3050       MaxHitpointsForCharacter( locplayerstate ) );
3051 
3052    itoa( health, tempstr, 10 );
3053    VWB_DrawPropString( tempstr );
3054    VWB_DrawPropString( "%" );
3055 
3056    //
3057    // Secret count
3058    //
3059 
3060    {
3061    char str1[10];
3062    char str2[10];
3063 
3064    itoa(gamestate.secretcount,&(str1[0]),10);
3065    strcat(str1," / ");
3066    itoa(gamestate.secrettotal,&(str2[0]),10);
3067    strcat(str1,str2);
3068    string = "SECRET WALLS";
3069    VW_MeasurePropString( string, &w, &h );
3070    px = HEADERX - w;
3071    py = 65;
3072    VWB_DrawPropString( string );
3073 
3074    px = BONERNAMEX;
3075    VWB_DrawPropString( str1 );
3076    }
3077 
3078    VW_UpdateScreen ();
3079    }
3080 
3081 boolean EndBonusFirst;
3082 boolean EndBonusSkip;
3083 int     EndBonusNumBonuses;
3084 int     EndBonusVoice;
3085 int     EndBonusStartY;
3086 
DrawEndBonus(char * string,char * bonusstring,int type)3087 void DrawEndBonus
3088    (
3089    char *string,
3090    char *bonusstring,
3091    int   type
3092    )
3093 
3094    {
3095    int w;
3096    int h;
3097    int  health;
3098    char tempstr[ 15 ];
3099 
3100    if ( EndBonusFirst )
3101       {
3102       VWB_TBar( 5, EndBonusStartY - 2, 310, 4 );
3103       EndBonusFirst = false;
3104       }
3105 
3106    VWB_TBar( 5, EndBonusStartY + 2, 310, 10 );
3107    VW_MeasurePropString( string, &w, &h );
3108 
3109    py = EndBonusStartY;
3110    if ( bonusstring == NULL )
3111       {
3112       px = ( 320 - w ) / 2;
3113       VWB_DrawPropString( string );
3114       }
3115    else
3116       {
3117       px = BONERNAMEX - w;
3118       VWB_DrawPropString( string );
3119 
3120       EndBonusNumBonuses++;
3121       VW_MeasurePropString( bonusstring, &w, &h );
3122       px = 310 - w;
3123       py = EndBonusStartY;
3124       VWB_DrawPropString( bonusstring );
3125       }
3126 
3127    // Update Score
3128    py = 45;
3129    px = BONERNAMEX;
3130    V_ReDrawBkgnd( px, py, 107, 11, false );
3131    VWB_TBar( px, py, 107, 11 );
3132    itoa( gamestate.score, tempstr, 10 );
3133    VWB_DrawPropString( tempstr );
3134 
3135    // Update Health
3136    py = 55;
3137    px = BONERNAMEX;
3138    V_ReDrawBkgnd( px, py, 107, 11, false );
3139    VWB_TBar( px, py, 107, 11 );
3140    health = ( ( locplayerstate->health * 100 ) /
3141       MaxHitpointsForCharacter( locplayerstate ) );
3142    itoa( health, tempstr, 10 );
3143    VWB_DrawPropString( tempstr );
3144    VWB_DrawPropString( "%" );
3145 
3146    switch( type )
3147       {
3148       case 0 :
3149          EndBonusVoice = SD_Play( SD_ENDBONUS1SND );
3150          break;
3151 
3152       case 1 :
3153          EndBonusVoice = SD_Play( SD_NOBONUSSND );
3154          break;
3155 
3156       case 2 :
3157          VL_FillPalette(255,255,255);
3158          VW_UpdateScreen();
3159          VL_FadeIn(0,255,origpal,10);
3160          EndBonusVoice = SD_Play( SD_LIGHTNINGSND );
3161          break;
3162       }
3163 
3164    EndBonusStartY += 10;
3165 
3166    VW_UpdateScreen();
3167    while( SD_SoundActive( EndBonusVoice ) && !EndBonusSkip )
3168       {
3169       if ( IN_CheckAck() )
3170          {
3171          EndBonusSkip = true;
3172          }
3173       }
3174    }
3175 
3176 
3177 
3178 /*
3179 ==================
3180 =
3181 = LevelCompleted
3182 =
3183 = Exit with the screen faded out
3184 =
3185 ==================
3186 */
3187 
3188 extern int OLDLMWEAPON;
3189 extern int OLDLWEAPON;
3190 
LevelCompleted(exit_t playstate)3191 void LevelCompleted
3192    (
3193    exit_t playstate
3194    )
3195 
3196    {
3197    objtype *obj;
3198    boolean dobonus;
3199    int i;
3200    int kr;
3201    int sr;
3202    int tr;
3203    int missileratio;
3204    int superratio;
3205    int healthratio;
3206    int democraticratio;
3207    int plantratio;
3208    int cnt;
3209 
3210    EndBonusNumBonuses = 0;
3211    EndBonusFirst      = true;
3212    EndBonusSkip       = false;
3213    EndBonusStartY     = 90;
3214 
3215    IN_StartAck();
3216    EndBonusVoice = 0;
3217    if ( playstate != ex_bossdied )
3218       {
3219       EndBonusVoice = SD_Play( SD_LEVELDONESND );
3220       VL_FillPalette( 255, 255, 255 );
3221       VL_FadeIn( 0, 255, origpal, 10 );
3222       if ( player->flags & FL_DOGMODE )
3223          {
3224          MU_StartSong( song_dogend );
3225          }
3226       else
3227          {
3228          MU_StartSong( song_endlevel );
3229          }
3230       }
3231 
3232    BkPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
3233    VWB_DrawPic( 0, 0, BkPic );
3234 
3235    CheckHolidays();
3236    CurrentFont = smallfont;
3237 
3238    // Kill powerups
3239    if ( player->flags & FL_ELASTO )
3240       {
3241       player->flags &= ~FL_NOFRICTION;
3242       }
3243 
3244    player->flags &= ~( FL_FLEET | FL_SHROOMS | FL_ELASTO | FL_GODMODE |
3245       FL_DOGMODE | FL_BPV | FL_AV | FL_GASMASK );
3246 
3247    // Turn off quickload for next level
3248    pickquick = false;
3249 
3250    //
3251    // FIGURE RATIOS OUT BEFOREHAND
3252    //
3253    kr = 0;
3254    tr = 0;
3255    tr = 0;
3256    superratio      = 0;
3257    missileratio    = 0;
3258    healthratio     = 0;
3259    democraticratio = 0;
3260    plantratio      = 0;
3261 
3262    if ( gamestate.killtotal )
3263       {
3264       kr = ( int )( ( ( int )gamestate.killcount ) * 100 ) /
3265          ( ( int )gamestate.killtotal );
3266       }
3267 
3268    if ( gamestate.secrettotal )
3269       {
3270       sr = ( int )( ( ( int )gamestate.secretcount ) * 100 ) /
3271          ( ( int )gamestate.secrettotal );
3272       }
3273 
3274    if ( gamestate.treasuretotal )
3275       {
3276       tr = ( int )( ( ( int )gamestate.treasurecount ) * 100 ) /
3277          ( ( int )gamestate.treasuretotal );
3278       }
3279 
3280    if ( gamestate.supertotal )
3281       {
3282       superratio = ( int )( ( ( int )gamestate.supercount ) * 100 ) /
3283          ( ( int )gamestate.supertotal );
3284       }
3285 
3286    if ( gamestate.missiletotal )
3287       {
3288       missileratio = ( int )( ( ( int )gamestate.missilecount ) * 100 ) /
3289          ( ( int )gamestate.missiletotal );
3290       }
3291 
3292    if ( gamestate.healthtotal )
3293       {
3294       healthratio = ( int )( ( ( int )gamestate.healthcount ) * 100 ) /
3295          ( ( int )gamestate.healthtotal );
3296       }
3297 
3298    if ( gamestate.democratictotal )
3299       {
3300       democraticratio = ( int )( ( ( int )gamestate.democraticcount ) *
3301          100 ) / ( ( int )gamestate.democratictotal );
3302       }
3303 
3304    if ( gamestate.planttotal )
3305       {
3306       plantratio = ( int )( ( ( int )gamestate.plantcount ) * 100 ) /
3307          ( ( int )gamestate.planttotal );
3308       }
3309 
3310    DrawEOLHeader( playstate );
3311 
3312    while( SD_SoundActive( EndBonusVoice ) && !EndBonusSkip )
3313       {
3314       VW_UpdateScreen();
3315       if ( IN_CheckAck() )
3316          {
3317          EndBonusSkip = true;
3318          }
3319       }
3320 
3321    if ( GetNextMap(player->tilex,player->tiley) == -1)
3322       {
3323    	if ( gamestate.dipballs == 3 )
3324          {
3325          gamestate.score += 100000;
3326          DrawEndBonus( "DIP BONUS", "100000 POINTS", 0 );
3327          EndBonusStartY += 10;
3328          }
3329 
3330       if ( locplayerstate->lives > 0 )
3331          {
3332          char str[20];
3333          char str2[60];
3334 
3335          DrawEndBonus( "EXTRA LIVES BONUS", "\0", 0 );
3336          itoa(locplayerstate->lives,str,10);
3337          strcpy(str2,str);
3338          strcat(str2," EXTRA LIVES =");
3339          DrawEndBonus( "\0", str2, 0 );
3340          itoa(locplayerstate->lives,str,10);
3341          strcpy(str2,str);
3342          strcat(str2," X 10000 = ");
3343          itoa(locplayerstate->lives*10000,str,10);
3344          strcat(str2,str);
3345          strcat(str2," POINTS");
3346          gamestate.score += 10000*locplayerstate->lives;
3347          DrawEndBonus( "\0", str2, 0 );
3348          }
3349       }
3350    else
3351       {
3352       //
3353       // Check for SKIN OF YO TEETH
3354       //
3355       if ( locplayerstate->health <= 10 )
3356          {
3357          locplayerstate->health = MaxHitpointsForCharacter( locplayerstate );
3358          DrawEndBonus( "SKIN OF YOUR TEETH", "100% HEALTH", 0 );
3359          }
3360 
3361       // BULL IN CHINA SHOP BONUS
3362       if ( tr == 100 )
3363          {
3364          gamestate.score += 10000;
3365          DrawEndBonus( "BULL IN CHINA SHOP", "10000 POINTS", 0 );
3366          }
3367 
3368       // SUPERCHARE BONUS
3369       if ( superratio == 100 )
3370          {
3371          gamestate.score += 10000;
3372          DrawEndBonus( "SUPERCHARGE BONUS", "10000 POINTS", 0 );
3373          }
3374 
3375       // BLEEDER BONUS
3376       if ( healthratio == 100 )
3377          {
3378          gamestate.score += 10000;
3379          DrawEndBonus( "BLEEDER BONUS", "10000 POINTS", 0 );
3380          }
3381 
3382       // ADRENALINE BONUS
3383       if ( kr == 100 )
3384          {
3385          gamestate.score += 10000;
3386          DrawEndBonus( "ADRENALINE BONUS", "10000 POINTS", 0 );
3387          }
3388 
3389       // CURIOSITY BONUS
3390       dobonus = true;
3391 
3392       //
3393       // Check switches
3394       cnt = lastswitch - &switches[ 0 ];
3395       if ( cnt != 0 )
3396          {
3397          for ( i = 0; i < cnt; i++ )
3398             {
3399             if ( ( switches[ i ].flags & FL_S_FLIPPED ) == 0 )
3400                {
3401                dobonus = false;
3402                break;
3403                }
3404             }
3405          }
3406 
3407       //
3408       // Check pillars
3409       for ( obj = FIRSTACTOR; obj != NULL; obj = obj->next )
3410          {
3411          if ( ( obj->obclass == pillarobj ) &&
3412             ( ( obj->flags & FL_FLIPPED ) == 0 ) )
3413             {
3414             dobonus = false;
3415             }
3416          }
3417 
3418       if ( ( gamestate.secrettotal ) && ( sr != 100 ) )
3419          {
3420          dobonus = false;
3421          }
3422 
3423       if ( dobonus )
3424          {
3425          gamestate.score += 10000;
3426          DrawEndBonus( "CURIOSITY BONUS", "10000 POINTS", 0 );
3427          }
3428 
3429       // GROUND ZERO BONUS
3430       if ( gamestate.DOGROUNDZEROBONUS )
3431          {
3432          gamestate.score += 10000;
3433          DrawEndBonus( "GROUND ZERO BONUS", "10000 POINTS", 0 );
3434          }
3435 
3436       // REPUBLICAN BONUS 1
3437       if ( missileratio == 100 )
3438          {
3439          gamestate.score += 5000;
3440          DrawEndBonus( "REPUBLICAN BONUS 1", " 5000 POINTS", 0 );
3441          }
3442 
3443       // REPUBLICAN BONUS 2
3444       if (plantratio == 100)
3445          {
3446          gamestate.score += 5000;
3447          DrawEndBonus( "REPUBLICAN BONUS 2", " 5000 POINTS", 0 );
3448          }
3449 
3450       // DEMOCRATIC BONUS 1
3451       if ( gamestate.DODEMOCRATICBONUS1 )
3452          {
3453          gamestate.score += 5000;
3454          DrawEndBonus( "DEMOCRATIC BONUS 1", " 5000 POINTS", 0 );
3455          }
3456 
3457       // DEMOCRATIC BONUS 2
3458       if (democraticratio == 100)
3459          {
3460          gamestate.score += 5000;
3461          DrawEndBonus( "DEMOCRATIC BONUS 2", " 5000 POINTS", 0 );
3462          }
3463       }
3464 
3465    if ( EndBonusNumBonuses == 0 )
3466       {
3467       DrawEndBonus( "NO BONUS!", NULL, 1 );
3468       }
3469 
3470    if ( ( EndBonusNumBonuses != 0 ) || ( playstate == ex_gameover ) )
3471       {
3472       SD_Play( PlayerSnds[ locplayerstate->player ] );
3473 
3474       // DO BONUS BONUS
3475       if ( EndBonusNumBonuses == NUMBONUSES )
3476          {
3477          IN_StartAck();
3478          while( !IN_CheckAck() )
3479             {
3480             ;
3481             }
3482 
3483          BkPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
3484          VWB_DrawPic( 0, 0, BkPic );
3485 
3486          gamestate.score += BONUSBONUS;
3487          DrawEOLHeader( playstate );
3488          EndBonusFirst = true;
3489          EndBonusStartY = 110;
3490          EndBonusSkip = true;
3491          DrawEndBonus( "BONUS BONUS!  1,000,000 POINTS!", NULL, 2 );
3492          }
3493       else if ( ( kr == 100 ) && ( dobonus ) )
3494          {
3495          IN_StartAck();
3496          while( !IN_CheckAck() )
3497             {
3498             ;
3499             }
3500 
3501          BkPic = ( pic_t * )W_CacheLumpName( "mmbk", PU_CACHE, Cvt_pic_t, 1 );
3502          VWB_DrawPic( 0, 0, BkPic );
3503 
3504          DrawEOLHeader( playstate );
3505          EndBonusFirst = true;
3506          EndBonusStartY = 110;
3507          DrawEndBonus( "You have done well.", NULL, 3 );
3508 #if (SHAREWARE==1)
3509          EndBonusVoice = SD_Play( SD_RICOCHET3SND );
3510 #else
3511          EndBonusVoice = SD_Play( SD_PERCENT100SND );
3512 #endif
3513          EndBonusSkip = false;
3514          DrawEndBonus( "This level is toast.", NULL, 3 );
3515          }
3516       }
3517 
3518    IN_StartAck();
3519    while( !IN_CheckAck() )
3520       {
3521       ;
3522       }
3523 
3524    EndLevelStuff = false;
3525    CurrentFont = smallfont;
3526    }
3527 
3528 
DrawTallyHeader(int which)3529 void DrawTallyHeader
3530    (
3531    int which
3532    )
3533 
3534    {
3535    pic_t *Name;
3536    pic_t *KillCount;
3537    pic_t *TimesYouKilledPerson;
3538    pic_t *TimesPersonKilledYou;
3539    pic_t *Suicides;
3540    pic_t *Score;
3541    pic_t *Blank;
3542    pic_t *TopBar;
3543 
3544    Name                 = ( pic_t * )W_CacheLumpName( "t_name",    PU_CACHE, Cvt_pic_t, 1 );
3545    Blank                = ( pic_t * )W_CacheLumpName( "t_blnk",    PU_CACHE, Cvt_pic_t, 1 );
3546    KillCount            = ( pic_t * )W_CacheLumpName( "t_kcount",  PU_CACHE, Cvt_pic_t, 1 );
3547    TimesYouKilledPerson = ( pic_t * )W_CacheLumpName( "t_kilper",  PU_CACHE, Cvt_pic_t, 1 );
3548    TimesPersonKilledYou = ( pic_t * )W_CacheLumpName( "t_perkil" , PU_CACHE, Cvt_pic_t, 1 );
3549    Suicides             = ( pic_t * )W_CacheLumpName( "t_suicid",  PU_CACHE, Cvt_pic_t, 1 );
3550    Score                = ( pic_t * )W_CacheLumpName( "t_score",   PU_CACHE, Cvt_pic_t, 1 );
3551    TopBar               = ( pic_t * )W_CacheLumpName( "t_bar",     PU_CACHE, Cvt_pic_t, 1 );
3552 
3553    IFont = ( cfont_t * )W_CacheLumpName( "sifont", PU_CACHE, Cvt_cfont_t, 1 );
3554 
3555    switch( which )
3556       {
3557       case 0 :
3558          VWB_DrawPic (   8,  8, TopBar );
3559          DrawIntensityString( 12, 11, "FINAL SCORE", 20 );
3560          VWB_DrawPic (   8, 24, Name );
3561          VWB_DrawPic ( 136, 24, KillCount );
3562          VWB_DrawPic ( 184, 24, Suicides );
3563          VWB_DrawPic ( 272, 24, Score );
3564          break;
3565 
3566       case 1 :
3567          VWB_DrawPic (   8,  8, TopBar );
3568          DrawIntensityString( 12, 11, "FINAL SCORE", 20 );
3569          VWB_DrawPic (   8, 24, Name );
3570          VWB_DrawPic ( 136, 24, Blank );
3571          VWB_DrawPic ( 272, 24, Score );
3572          break;
3573 
3574       case 2 :
3575          VWB_DrawPic (   8,  8, TopBar );
3576          DrawIntensityString( 12, 11, "YOUR KILLS", 20 );
3577          VWB_DrawPic (   8, 24, Name );
3578          VWB_DrawPic ( 136, 24, KillCount );
3579          VWB_DrawPic ( 184, 24, TimesYouKilledPerson );
3580          break;
3581 
3582       case 3 :
3583          VWB_DrawPic (   8,  8, TopBar );
3584          DrawIntensityString( 12, 11, "YOUR DEATHS", 20 );
3585          VWB_DrawPic (   8, 24, Name );
3586          VWB_DrawPic ( 136, 24, TimesPersonKilledYou );
3587          break;
3588       }
3589 
3590    DrawTimeXY( TALLYTIME_X, TALLYTIME_Y, gamestate.TimeCount / VBLCOUNTER,
3591       true );
3592    }
3593 
3594 
3595 #define BT_RANK_X    23
3596 #define BT_PLAYER_X  30
3597 #define BT_KILLS_X   ( 139 + ( ( 40 + 20 ) / 2 ) )
3598 #define BT_DEATHS_X  ( 193 + ( ( 56 + 20 ) / 2 ) )
3599 //#define BT_SCORE_X   ( 263 + ( ( 46 + 20 ) / 2 ) )
3600 #define BT_SCORE_X   ( 273 + ( ( 46 + 20 ) / 2 ) )
3601 
3602 
ShowKills(int localplayer)3603 void ShowKills( int localplayer )
3604 {
3605    int  w;
3606    int  h;
3607    int  i;
3608    int  j;
3609    int  temp;
3610    int  rank;
3611    int  player;
3612    int  killer;
3613    int  victim;
3614    int  color;
3615    char tempstr[15];
3616    int  KillCount[ MAXPLAYERS ];
3617    int  Order[ MAXPLAYERS ];
3618    int  NumPlayers;
3619 
3620    // show at the most 11 players
3621    NumPlayers = min( numplayers, 11 );
3622 
3623    // Count kills
3624    for( killer = 0; killer < NumPlayers; killer++ )
3625       {
3626       Order[ killer ] = killer;
3627       KillCount[ killer ] = 0;
3628       for( victim = 0; victim < NumPlayers; victim++ )
3629          {
3630          if ( BATTLE_Team[ victim ] != BATTLE_Team[ killer ] )
3631             {
3632             KillCount[ killer ] += WhoKilledWho[ killer ][ victim ];
3633             }
3634          }
3635       }
3636 
3637    for( i = 0; i < NumPlayers - 1; i++ )
3638       {
3639       for( j = i + 1; j < NumPlayers; j++ )
3640          {
3641          if ( KillCount[ Order[ i ] ] < KillCount[ Order[ j ] ] )
3642             {
3643             temp = Order[ i ];
3644             Order[ i ] = Order[ j ];
3645             Order[ j ] = temp;
3646             }
3647          }
3648       }
3649 
3650    DrawTallyHeader( 2 );
3651 
3652    IFont = (cfont_t * )W_CacheLumpNum (W_GetNumForName ("sifont"), PU_CACHE, Cvt_cfont_t, 1);
3653    CurrentFont = smallfont;
3654    py = 43;
3655 
3656    for( rank = 0; rank < NumPlayers; rank++ )
3657       {
3658       player = Order[ rank ];
3659 
3660       color = 21;
3661 
3662       // Highlight the your score
3663       if ( player == localplayer )
3664          {
3665          // Change to Intensity
3666          color = 241;
3667          }
3668 
3669       // Draw rank if not tied with previous rank
3670       if ( ( rank == 0 ) || ( KillCount[ player ] !=
3671          KillCount[ Order[ rank - 1 ] ] ) )
3672          {
3673          itoa( rank + 1, tempstr, 10 );
3674          }
3675       else
3676          {
3677          strcpy( tempstr, "Tie" );
3678          }
3679 
3680       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3681       DrawIntensityString( BT_RANK_X - w, py, tempstr, color );
3682 
3683       // Draw name
3684       DrawIntensityString( BT_PLAYER_X, py, PLAYERSTATE[ player ].codename, color );
3685 
3686       // Draw kills
3687       itoa( KillCount[ player ], tempstr, 10 );
3688       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3689       DrawIntensityString( BT_KILLS_X - w, py, tempstr, color );
3690 
3691       // Draw times you killed that person
3692       if ( player != localplayer )
3693          {
3694          itoa( WhoKilledWho[ localplayer ][ player ], tempstr, 10 );
3695          }
3696       else
3697          {
3698          strcpy( tempstr, "-" );
3699          }
3700 
3701       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3702       DrawIntensityString( BT_DEATHS_X - w, py, tempstr, color );
3703 
3704       if ( gamestate.teamplay )
3705          {
3706          DrawIntensityString( BT_DEATHS_X + 16, py,
3707             colorname[ PLAYERSTATE[ player ].uniformcolor ], color );
3708          }
3709 
3710       py += h;
3711       }
3712    }
3713 
3714 
ShowDeaths(int localplayer)3715 void ShowDeaths( int localplayer )
3716    {
3717    int  w;
3718    int  h;
3719    int  i;
3720    int  j;
3721    int  temp;
3722    int  rank;
3723    int  player;
3724    int  killer;
3725    int  victim;
3726    int  color;
3727    char tempstr[15];
3728    int  DeathCount[ MAXPLAYERS ];
3729    int  Order[ MAXPLAYERS ];
3730    int  NumPlayers;
3731 
3732    // show at the most 11 players
3733    NumPlayers = min( numplayers, 11 );
3734 
3735    // Count Deaths
3736    for( victim = 0; victim < NumPlayers; victim++ )
3737       {
3738       Order[ victim ] = victim;
3739       DeathCount[ victim ] = 0;
3740       for( killer = 0; killer < NumPlayers; killer++ )
3741          {
3742          DeathCount[ victim ] += WhoKilledWho[ killer ][ victim ];
3743          }
3744       }
3745 
3746    for( i = 0; i < NumPlayers - 1; i++ )
3747       {
3748       for( j = i + 1; j < NumPlayers; j++ )
3749          {
3750          if ( DeathCount[ Order[ i ] ] < DeathCount[ Order[ j ] ] )
3751             {
3752             temp = Order[ i ];
3753             Order[ i ] = Order[ j ];
3754             Order[ j ] = temp;
3755             }
3756          }
3757       }
3758 
3759    DrawTallyHeader( 3 );
3760 
3761    IFont = (cfont_t * )W_CacheLumpNum (W_GetNumForName ("sifont"), PU_CACHE, Cvt_cfont_t, 1);
3762    CurrentFont = smallfont;
3763    py = 43;
3764 
3765    for( rank = 0; rank < NumPlayers; rank++ )
3766       {
3767       player = Order[ rank ];
3768       color = 21;
3769 
3770       // Highlight the your score
3771       if ( player == localplayer )
3772          {
3773          // Change to Intensity
3774          color = 241;
3775          }
3776 
3777       // Draw rank if not tied with previous rank
3778       if ( ( rank == 0 ) || ( DeathCount[ player ] !=
3779          DeathCount[ Order[ rank - 1 ] ] ) )
3780          {
3781          itoa( rank + 1, tempstr, 10 );
3782          }
3783       else
3784          {
3785          strcpy( tempstr, "Tie" );
3786          }
3787 
3788       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3789       DrawIntensityString( BT_RANK_X - w, py, tempstr, color );
3790 
3791       // Draw name
3792       DrawIntensityString( BT_PLAYER_X, py, PLAYERSTATE[ player ].codename, color );
3793 
3794       // Draw deaths
3795       itoa( DeathCount[ player ], tempstr, 10 );
3796       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3797       DrawIntensityString( BT_KILLS_X - w, py, tempstr, color );
3798 
3799       // Draw times you were killed by that person
3800       itoa( WhoKilledWho[ player ][ localplayer ], tempstr, 10 );
3801       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3802       DrawIntensityString( BT_DEATHS_X - w, py, tempstr, color );
3803 
3804       if ( gamestate.teamplay )
3805          {
3806          DrawIntensityString( BT_DEATHS_X + 16, py,
3807             colorname[ PLAYERSTATE[ player ].uniformcolor ], color );
3808          }
3809 
3810       py += h;
3811       }
3812    }
3813 
3814 
ShowEndScore(int localplayer)3815 void ShowEndScore( int localplayer )
3816    {
3817    int  w;
3818    int  h;
3819    int  rank;
3820    int  leader;
3821    int  team;
3822    int  color;
3823    int  killer;
3824    int  victim;
3825    int  killcount;
3826    int  suicidecount;
3827    char tempstr[15];
3828    boolean dofullstats;
3829    int  NumPlayers;
3830 
3831    // show at the most 11 players
3832    NumPlayers = min( numplayers, 11 );
3833 
3834    dofullstats = false;
3835    switch( gamestate.battlemode )
3836       {
3837 		case battle_Normal :
3838 		case battle_ScoreMore :
3839 		case battle_Hunter :
3840          dofullstats = true;
3841          DrawTallyHeader( 0 );
3842          break;
3843 
3844 		case battle_Collector :
3845 		case battle_Scavenger :
3846 		case battle_Tag :
3847 		case battle_Eluder :
3848 		case battle_Deluder :
3849 		case battle_CaptureTheTriad :
3850          dofullstats = false;
3851          DrawTallyHeader( 1 );
3852          break;
3853       }
3854 
3855    IFont = (cfont_t * )W_CacheLumpNum (W_GetNumForName ("sifont"), PU_CACHE, Cvt_cfont_t, 1);
3856    CurrentFont = smallfont;
3857    py = 43;
3858 
3859    for( rank = 0; rank < BATTLE_NumberOfTeams; rank++ )
3860       {
3861       team = BATTLE_PlayerOrder[ rank ];
3862 
3863       color = 21;
3864       if ( team == BATTLE_Team[ localplayer ] )
3865          {
3866          // Change to Intensity
3867          color = 241;
3868          }
3869 
3870       // Draw rank if not tied with previous rank
3871       if ( ( rank == 0 ) || ( BATTLE_Points[ team ] !=
3872          BATTLE_Points[ BATTLE_PlayerOrder[ rank - 1 ] ] ) )
3873          {
3874          itoa( rank + 1, tempstr, 10 );
3875          }
3876       else
3877          {
3878          strcpy( tempstr, "Tie" );
3879          }
3880 
3881       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3882       DrawIntensityString( BT_RANK_X - w, py, tempstr, color );
3883 
3884       // Draw name of team leader
3885       leader = BATTLE_TeamLeader[ team ];
3886       if ( gamestate.teamplay )
3887          {
3888          DrawIntensityString( BT_PLAYER_X, py,
3889             colorname[ PLAYERSTATE[ leader ].uniformcolor ], color );
3890          }
3891       else
3892          {
3893          DrawIntensityString( BT_PLAYER_X, py,
3894             PLAYERSTATE[ leader ].codename, color );
3895          }
3896 
3897       if ( dofullstats )
3898          {
3899          // Count how many kills each person on the team got
3900          killcount = 0;
3901          suicidecount = 0;
3902          for( killer = 0; killer < NumPlayers; killer++ )
3903             {
3904             if ( BATTLE_Team[ killer ] == team )
3905                {
3906                for( victim = 0; victim < NumPlayers; victim++ )
3907                   {
3908                   if ( BATTLE_Team[ victim ] != team )
3909                      {
3910                      killcount += WhoKilledWho[ killer ][ victim ];
3911                      }
3912                   else
3913                      {
3914                      suicidecount += WhoKilledWho[ killer ][ victim ];
3915                      }
3916                   }
3917                }
3918             }
3919 
3920          // Draw kills
3921          itoa( killcount, tempstr, 10 );
3922          VW_MeasureIntensityPropString ( tempstr, &w, &h);
3923          DrawIntensityString( BT_KILLS_X - w, py, tempstr, color );
3924 
3925          // Draw suicides
3926          itoa( suicidecount, tempstr, 10 );
3927          VW_MeasureIntensityPropString ( tempstr, &w, &h);
3928          DrawIntensityString( BT_DEATHS_X - w, py, tempstr, color );
3929          }
3930 
3931       // Draw Score
3932       itoa( BATTLE_Points[ team ], tempstr, 10 );
3933       VW_MeasureIntensityPropString ( tempstr, &w, &h);
3934       DrawIntensityString( BT_SCORE_X - w, py, tempstr, color );
3935 
3936       py += h;
3937       }
3938    }
3939 
3940 
BattleLevelCompleted(int localplayer)3941 void BattleLevelCompleted ( int localplayer )
3942    {
3943    ControlInfo ci;
3944    int w;
3945    int h;
3946    int key;
3947    int Screen;
3948    int LastScreen;
3949    int Player;
3950    char text[80];
3951 
3952    IN_ClearKeysDown ();
3953 
3954    Player = localplayer;
3955    Screen = 1;
3956    LastScreen = 0;
3957    key = -1;
3958    while( 1 )
3959       {
3960       if ( Screen != LastScreen )
3961          {
3962          VL_DrawPostPic (W_GetNumForName("trilogo"));
3963 
3964          switch( Screen )
3965             {
3966             case 1 :
3967                ShowEndScore( Player );
3968                break;
3969 
3970             case 2 :
3971                ShowKills( Player );
3972                break;
3973 
3974             case 3 :
3975                ShowDeaths( Player );
3976                break;
3977             }
3978 
3979          CurrentFont = tinyfont;
3980 
3981          sprintf ( text, "Page %d of 3.  Use arrows to switch stats.  "
3982             "Press Esc to quit.", Screen );
3983          VW_MeasurePropString ( text, &w, &h);
3984          py = 192;
3985          px = ( 320 - w ) / 2;
3986          VWB_DrawPropString ( text );
3987          VW_UpdateScreen ();
3988 
3989          do
3990             {
3991             ReadAnyControl (&ci);
3992             }
3993          while( ci.dir == (dirtype)key );
3994          }
3995 
3996       LastScreen = Screen;
3997       ReadAnyControl ( &ci );
3998       key = ci.dir;
3999       if ( ( Screen > 1 ) && ( key == dir_West ) )
4000          {
4001          Screen--;
4002          MN_PlayMenuSnd (SD_MOVECURSORSND);
4003          }
4004       else if ( ( Screen < 3 ) && ( key == dir_East ) )
4005          {
4006          Screen++;
4007          MN_PlayMenuSnd (SD_MOVECURSORSND);
4008          }
4009       // Allow us to select which player to view
4010       if ( Keyboard[ sc_RShift ] && ( key == dir_South ) )
4011          {
4012          Player++;
4013          if ( Player >= numplayers )
4014             {
4015             Player = 0;
4016             }
4017          LastScreen = 0;
4018          MN_PlayMenuSnd (SD_SELECTSND);
4019          }
4020 
4021       if ( Keyboard[ sc_RShift ] && ( key == dir_North ) )
4022          {
4023          Player--;
4024          if ( Player < 0 )
4025             {
4026             Player = numplayers - 1;
4027             }
4028          LastScreen = 0;
4029          MN_PlayMenuSnd (SD_SELECTSND);
4030          }
4031 
4032       if ( Keyboard[sc_Escape] )
4033          {
4034          break;
4035          }
4036       }
4037 
4038    while ( Keyboard[sc_Escape] )
4039       {
4040       IN_UpdateKeyboard ();
4041       }
4042 
4043    MN_PlayMenuSnd (SD_ESCPRESSEDSND);
4044 
4045    CurrentFont = smallfont;
4046    }
4047 
4048 //==========================================================================
4049 
4050 /*
4051 ==================
4052 =
4053 = FindAngleToWindow
4054 =
4055 ==================
4056 */
FindAngleToWindow(int tx,int ty)4057 int FindAngleToWindow ( int tx, int ty )
4058 {
4059    if (!IsWindow(tx+1,ty))
4060       return ANG180;
4061    else if (!IsWindow(tx-1,ty))
4062       return 0;
4063    else if (!IsWindow(tx,ty+1))
4064       return ANG90;
4065    else
4066       return ANG270;
4067 }
4068 
4069 #define STARTRADIUS (0xa000)
4070 #define STOPRADIUS (0x14000)
4071 #define DEATHRADIUS (STOPRADIUS-STARTRADIUS)
4072 #define ROTRATE      (5)
4073 #define TOTALDEATHROT (FINEANGLES<<1)
4074 #define RADIUSINC   ((DEATHRADIUS)/(TOTALDEATHROT))
4075 
4076 /*
4077 ==================
4078 =
4079 = ZoomDeathOkay
4080 =
4081 ==================
4082 */
ZoomDeathOkay(void)4083 boolean ZoomDeathOkay ( void )
4084 {
4085    int x,y;
4086    int radius;
4087 
4088    if (
4089         !(
4090         (player->state==&s_ashwait) ||
4091         ((player->flags & FL_HBM) && (gamestate.violence >= vl_high))
4092         )
4093       )
4094       return false;
4095 
4096    radius=STOPRADIUS;
4097    x=player->x;
4098    y=player->y;
4099    while (radius>0)
4100       {
4101       if (tilemap[x>>16][(y+radius)>>16])
4102          return false;
4103       if (tilemap[x>>16][(y-radius)>>16])
4104          return false;
4105       if (tilemap[(x-radius)>>16][y>>16])
4106          return false;
4107       if (tilemap[(x+radius)>>16][y>>16])
4108          return false;
4109       if (tilemap[(x+radius)>>16][(y+radius)>>16])
4110          return false;
4111       if (tilemap[(x+radius)>>16][(y-radius)>>16])
4112          return false;
4113       if (tilemap[(x-radius)>>16][(y+radius)>>16])
4114          return false;
4115       if (tilemap[(x-radius)>>16][(y-radius)>>16])
4116          return false;
4117       radius-=0x10000;
4118       }
4119    return true;
4120 }
4121 
4122 /*
4123 ==================
4124 =
4125 = Died
4126 =
4127 ==================
4128 */
4129 
4130 #define DEATHROTATE 6
4131 
4132 extern boolean dopefish;
Died(void)4133 void Died (void)
4134 {
4135    long  dx,dy;
4136    int      iangle,curangle,clockwise,change;
4137    int   da;
4138    int   rate;
4139    lbm_t *LBM;
4140    int   slowrate;
4141    playertype *pstate;
4142    objtype * killerobj=(objtype *)player->target;
4143 
4144 
4145    if (killerobj == NULL)
4146       killerobj = player;
4147 
4148    if (CheckParm("slowdeath"))
4149       slowrate=3;
4150    else
4151       slowrate=0;
4152 
4153    M_LINKSTATE (player, pstate);
4154 
4155    if ( (ZoomDeathOkay()==true) && (pstate->falling==false))
4156       {
4157       int x,y,z,radius,heightoffset;
4158       int endangle,startangle,killangle;
4159       boolean deadflagset;
4160       objtype * dummy;
4161 
4162       x=player->x;
4163       y=player->y;
4164       z=player->z;
4165       dummy=player;
4166       SpawnPlayerobj (x>>16, y>>16, 0, 0);
4167       player=dummy;
4168       dummy=new;
4169       dummy->x=x;
4170       dummy->drawx=x;
4171       dummy->y=y;
4172       dummy->z=z;
4173       dummy->drawy=y;
4174       dummy->flags=player->flags;
4175       player->momentumx=0;
4176       player->momentumy=0;
4177       player->speed=0;
4178       radius=STARTRADIUS;
4179       heightoffset=pstate->heightoffset;
4180       deadflagset=false;
4181       startangle=(player->angle+ANG180)&(FINEANGLES-1);
4182       endangle=startangle+TOTALDEATHROT;
4183       killangle=startangle+(TOTALDEATHROT>>1);
4184       if (dopefish==true)
4185          {
4186          AddMessage("Dopefish Death Cam\n",MSG_SYSTEM);
4187          }
4188       for (iangle=startangle;;)
4189          {
4190          if ( iangle > killangle )
4191             {
4192             if ( deadflagset==false )
4193                {
4194                dummy->hitpoints=0;
4195                pstate->health=0;
4196                dummy->flags &= ~FL_DYING;
4197                dummy->flags |= FL_SHOOTABLE;
4198                if (player->state==&s_ashwait)
4199                   dummy->flags |= FL_SKELETON;
4200                Collision(dummy,(objtype*)NULL,0,0);
4201                deadflagset=true;
4202                if ( ( killerobj==player ) && ( gamestate.violence >=
4203                   vl_high ) && ( gamestate.difficulty >= gd_hard ) )
4204                   {
4205                   SD_Play( SD_YOUSUCKSND );
4206                   }
4207                else
4208                   {
4209                   SD_Play (SD_PLAYERTCDEATHSND+(pstate->player));
4210                   }
4211                }
4212             }
4213          else
4214             {
4215             dummy->flags &= ~FL_DYING;
4216             }
4217          if (dopefish==true)
4218             {
4219             dummy->momentumx+=(RandomNumber("Died",0)<<6)-(256<<5);
4220             dummy->momentumy+=(RandomNumber("Died",0)<<6)-(256<<5);
4221             }
4222          player->x=x+FixedMul(radius,costable[iangle&(FINEANGLES-1)]);
4223          player->y=y-FixedMul(radius,sintable[iangle&(FINEANGLES-1)]);
4224          player->z=dummy->z;
4225          player->angle=(iangle+ANG180)&(FINEANGLES-1);
4226          if (dopefish==true)
4227             {
4228             int dx,dy;
4229 
4230             dx = dummy->x - player->x;
4231             dy = player->y - dummy->y;
4232 
4233             if (dx && dy)
4234                player->angle = atan2_appx (dx,dy);
4235             }
4236          pstate->heightoffset=heightoffset;
4237          player->yzangle=0;
4238          UpdateGameObjects();
4239          player->momentumx=0;
4240          player->momentumy=0;
4241          player->speed=0;
4242          ThreeDRefresh ();
4243          AnimateWalls();
4244          DoSprites();
4245          DoAnimatedMaskedWalls();
4246          UpdatePlayers();
4247          UpdateLightLevel(player->areanumber);
4248 
4249          if (iangle<endangle)
4250             {
4251             iangle+=(tics<<ROTRATE);
4252             radius+=tics*(RADIUSINC<<ROTRATE);
4253             }
4254          if ( (dummy->state==dummy->state->next) && (iangle>=endangle) )
4255             break;
4256          }
4257       }
4258    else if (pstate->falling==false)
4259       {
4260 
4261       //
4262       // swing around to face attacker
4263       //
4264 
4265       rate=DEATHROTATE-slowrate;
4266          {
4267          if (killerobj==player)
4268             {
4269             iangle=player->angle;
4270             if ( ( gamestate.violence >= vl_high ) &&
4271                ( gamestate.difficulty >= gd_hard ) )
4272                {
4273                SD_Play( SD_YOUSUCKSND );
4274                }
4275             }
4276          else
4277             {
4278             SD_Play (SD_PLAYERTCDEATHSND+(pstate->player));
4279             if (killerobj->which==PWALL)
4280             {
4281                dx = ((pwallobj_t *)killerobj)->x - player->x;
4282                dy = player->y - ((pwallobj_t *)killerobj)->y;
4283             }
4284             else
4285             {
4286                dx = killerobj->x - player->x;
4287                dy = player->y - killerobj->y;
4288             }
4289 
4290             iangle = atan2_appx (dx,dy);       // returns -pi to pi
4291             }
4292          }
4293 
4294       da = iangle-player->angle;
4295 
4296       if (da>0)
4297          clockwise=1;
4298       else
4299          clockwise=0;
4300       da=abs(da);
4301       if (da>ANG180)
4302          {
4303          clockwise^=1;
4304          da=ANGLES-da;
4305          }
4306 
4307       curangle = player->angle;
4308 
4309       do
4310          {
4311          DoBorderShifts ();
4312          change = tics<<rate;
4313          if (clockwise==1)
4314             curangle+=change;
4315          else
4316             curangle-=change;
4317          da-=change;
4318          if (curangle >= ANGLES)
4319             curangle -= ANGLES;
4320          if (curangle < 0)
4321             curangle += ANGLES;
4322          player->angle = (curangle & (FINEANGLES-1));
4323          ThreeDRefresh ();
4324          CalcTics ();
4325          } while (da>0);
4326       }
4327    else
4328       {
4329       DrawFullSky();
4330       FlipPage();
4331       }
4332 
4333    while (damagecount)
4334       DoBorderShifts ();
4335    DoBorderShifts ();
4336 
4337    locplayerstate->weapon = -1;        // take away weapon
4338 
4339    if (
4340         (tedlevel == false) && // SO'S YA DON'T GET KILLED WHILE LAUNCHING!
4341         (timelimitenabled == false)
4342       )
4343       locplayerstate->lives--;
4344 
4345    if (pstate->falling==false)
4346       {
4347       ThreeDRefresh ();
4348       }
4349 
4350    FlipPage();
4351    FlipPage();
4352 
4353    if (locplayerstate->lives > -1)
4354    {
4355       int rng;
4356 
4357       rng = RandomNumber ("Died",0);
4358 
4359       if (pstate->falling==true)
4360          {
4361          RotateBuffer (0, 0, (FINEANGLES), (FINEANGLES>>6), (VBLCOUNTER*(1+slowrate)));
4362          SD_Play (SD_PLAYERTCDEATHSND+(pstate->player));
4363          pstate->falling=false;
4364          }
4365 
4366       else if (rng < 64)
4367          RotateBuffer (0, 0, (FINEANGLES), (FINEANGLES*64), (VBLCOUNTER*(2+slowrate)));
4368       else if (rng < 128)
4369          {
4370          RotateBuffer (0, 0, (FINEANGLES), (FINEANGLES>>6), (VBLCOUNTER*(1+slowrate)));
4371          }
4372       else if (rng < 192)
4373          RotateBuffer(0, (FINEANGLES*4), (FINEANGLES), (FINEANGLES*64), (VBLCOUNTER*(3+slowrate)));
4374       else
4375          VL_FadeToColor (VBLCOUNTER*2, 100, 0, 0);
4376 
4377       screenfaded=false;
4378 
4379       VL_FadeOut (0, 255, 0,0,0,VBLCOUNTER>>1);
4380       gamestate.episode = 1;
4381       player->flags &= ~FL_DONE;
4382 
4383       InitializeWeapons (locplayerstate);
4384       ResetPlayerstate(locplayerstate);
4385 
4386       UpdateLives (locplayerstate->lives);
4387       UpdateScore (gamestate.score);
4388 
4389       DrawTriads(true);
4390       DrawLives (true);
4391       DrawKeys (true);
4392       DrawScore (true);
4393    }
4394    else
4395    {
4396       int rng;
4397 
4398       SD_Play (SD_GAMEOVERSND);
4399       rng=RandomNumber("Died",0);
4400       if (rng<64)
4401          RotateBuffer(0,(FINEANGLES>>1),(FINEANGLES),(FINEANGLES*64),(VBLCOUNTER*(3+slowrate)));
4402       else if (rng<128)
4403          VL_FadeToColor (VBLCOUNTER*3, 255, 255, 255);
4404       else if (rng<192)
4405          RotateBuffer(0,(FINEANGLES*2),(FINEANGLES),(FINEANGLES*64),(VBLCOUNTER*(3+slowrate)));
4406       else
4407          RotateBuffer(0,(FINEANGLES*2),(FINEANGLES),(FINEANGLES*64),(VBLCOUNTER*(3+slowrate)));
4408 
4409       screenfaded=false;
4410 
4411       VL_FadeOut (0, 255, 0,0,0,VBLCOUNTER>>1);
4412 
4413       MU_StartSong(song_gameover);
4414 
4415 #if (SHAREWARE==0)
4416       if (gamestate.violence==vl_excessive)
4417          LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("bootblod"), PU_CACHE, Cvt_lbm_t, 1);
4418       else
4419          LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("bootnorm"), PU_CACHE, Cvt_lbm_t, 1);
4420 #else
4421       LBM = (lbm_t *) W_CacheLumpNum (W_GetNumForName ("bootblod"), PU_CACHE, Cvt_lbm_t, 1);
4422 #endif
4423       VL_DecompressLBM (LBM,true);
4424 
4425       StopWind();
4426 
4427       IN_UserInput (VBLCOUNTER*60);
4428 
4429       MainMenu[savegame].active = 0;
4430       MainMenu[viewscores].routine = (void *)CP_ViewScores;
4431       MainMenu[viewscores].texture[6] = '7';
4432       MainMenu[viewscores].texture[7] = '\0';
4433       MainMenu[viewscores].letter     = 'V';
4434    }
4435    ClearGraphicsScreen();
4436 
4437    VL_FadeIn (0, 255, origpal, 15);
4438 }
4439 
4440 
4441 //******************************************************************************
4442 //
4443 // DoLoadGameAction ()
4444 //
4445 //******************************************************************************
4446 
4447 static byte whichstr = 0;
4448 
DoLoadGameAction(void)4449 void DoLoadGameAction (void)
4450 {
4451    if ((SaveTime+1) < GetTicCount())
4452    {
4453       int temp = bufferofs;
4454 
4455       bufferofs = displayofs;
4456       SaveTime = GetTicCount();
4457 
4458       CurrentFont=tinyfont;
4459 
4460       px = 92;
4461       py = 152;
4462       if (whichstr)
4463       {
4464 //         VW_DrawPropString ("�");
4465          VW_DrawPropString (".");
4466          whichstr = 0;
4467 		}
4468       else
4469       {
4470 //         VW_DrawPropString ("�");
4471          VW_DrawPropString (".");
4472          whichstr = 1;
4473       }
4474       bufferofs = temp;
4475    }
4476 }
4477 
4478 //******************************************************************************
4479 //
4480 // DoCheckSum ()
4481 //
4482 //******************************************************************************
4483 
DoCheckSum(byte * source,int size,long csum)4484 long DoCheckSum (byte *source, int size, long csum)
4485 {
4486    int i;
4487    long checksum;
4488 
4489    checksum = csum;
4490 
4491    for (i = 0; i < size; i++)
4492       checksum=updatecrc(checksum,*(source+i));
4493 
4494    return checksum;
4495 }
4496 
4497 //******************************************************************************
4498 //
4499 // CaculateSaveGameCheckSum ()
4500 //
4501 //******************************************************************************
4502 
4503 #define SAVECHECKSUMSIZE (10000)
CalculateSaveGameCheckSum(char * filename)4504 long CalculateSaveGameCheckSum (char * filename)
4505 {
4506    int handle;
4507    int lengthleft;
4508    int length;
4509    byte * altbuffer;
4510    long checksum;
4511 
4512    altbuffer=SafeMalloc(SAVECHECKSUMSIZE);
4513 
4514    checksum = 0;
4515 
4516    // Open the savegame file
4517 
4518    handle = SafeOpenRead (filename);
4519    lengthleft = filelength (handle);
4520 
4521    while (lengthleft>0)
4522       {
4523       length=SAVECHECKSUMSIZE;
4524       if (length>lengthleft)
4525          length=lengthleft;
4526 
4527       SafeRead(handle,altbuffer,length);
4528       checksum = DoCheckSum (altbuffer, length, checksum);
4529 
4530       lengthleft-=length;
4531       }
4532 
4533    SafeFree(altbuffer);
4534 
4535    close (handle);
4536 
4537    return checksum;
4538 }
4539 
4540 //******************************************************************************
4541 //
4542 // StoreBuffer
4543 //
4544 //******************************************************************************
StoreBuffer(int handle,byte * src,int size)4545 void StoreBuffer (int handle, byte * src, int size)
4546 {
4547    SafeWrite(handle,&size,sizeof(size));
4548    SafeWrite(handle,src,size);
4549 }
4550 
4551 //******************************************************************************
4552 //
4553 // SaveTag
4554 //
4555 //******************************************************************************
SaveTag(int handle,char * tag,int size)4556 void SaveTag (int handle, char * tag, int size)
4557 {
4558    SafeWrite(handle,tag,size);
4559 }
4560 
4561 
4562 //******************************************************************************
4563 //
4564 // SaveTheGame ()
4565 //
4566 // Expects game to be premalloced
4567 //
4568 //******************************************************************************
4569 
SaveTheGame(int num,gamestorage_t * game)4570 boolean SaveTheGame (int num, gamestorage_t * game)
4571 {
4572    char   loadname[MAX_PATH]="rottgam0.rot";
4573    char   filename[MAX_PATH];
4574    byte   * altbuffer;
4575 	int    size;
4576 	int    avail;
4577    int    savehandle;
4578    int    crc;
4579 	int    i;
4580    char   letter;
4581    int myticcount;
4582 
4583 	if (num > 15 || num < 0)
4584 		Error("Illegal Saved game value=%ld\n",num);
4585 
4586    //
4587    // Save Alternate Game Level information for reloading game
4588    //
4589    memset (&game->info, 0, sizeof (game->info));
4590    if (GameLevels.avail == true)
4591    {
4592       memcpy (&game->info.path[0], &GameLevels.path[0], sizeof (GameLevels.path));
4593       memcpy (&game->info.file[0], &GameLevels.file[0], sizeof (GameLevels.file));
4594       game->info.avail = true;
4595    }
4596 
4597    game->mapcrc=GetMapCRC (gamestate.mapon);
4598 
4599 	// Create the proper file name
4600 
4601    itoa(num,&loadname[7],16);
4602    loadname[8]='.';
4603 
4604 
4605    GetPathFromEnvironment( filename, ApogeePath, loadname );
4606 
4607 #if PLATFORM_DOS
4608 {
4609    struct diskfree_t dfree;
4610    // Determine available disk space
4611    letter = toupper(filename[0]);
4612    if (
4613        (letter >= 'A') &&
4614        (letter <= 'Q')
4615       )
4616       {
4617       if (_dos_getdiskfree ((letter-'A'+1), &dfree))
4618          Error ("Error in _dos_getdiskfree call\n");
4619       }
4620    else
4621       {
4622       if (_dos_getdiskfree (0, &dfree))
4623          Error ("Error in _dos_getdiskfree call\n");
4624       }
4625 
4626 	avail = (int) dfree.avail_clusters *
4627 					  dfree.bytes_per_sector *
4628 					  dfree.sectors_per_cluster;
4629    avail -= 8192;
4630 
4631 	// Check to see if we have enough
4632 
4633    if (avail < MAXSAVEDGAMESIZE)
4634 		{
4635       CP_DisplayMsg ("There is not enough\nspace on your disk\nto Save Game!\nPress any key to continue", 13);
4636 		return (false);
4637 		}
4638 }
4639 #endif
4640 
4641    // Open the savegame file
4642 
4643    savehandle = SafeOpenWrite (filename);
4644 
4645 	// Save out file tag
4646 
4647 	size=4;
4648    SaveTag(savehandle,"ROTT",size);
4649 
4650 	// Save out header
4651 
4652 	size=sizeof(*game);
4653 
4654    SafeWrite(savehandle,game,size);
4655 
4656 /////////////////////////////////////////////////////////////////////////////
4657 // Save out rest of save game file beyond this point
4658 /////////////////////////////////////////////////////////////////////////////
4659 
4660 	// Door Tag
4661 
4662 	size=4;
4663    SaveTag(savehandle,"DOOR",size);
4664 
4665 	// Doors
4666 
4667 	SaveDoors(&altbuffer,&size);
4668    StoreBuffer(savehandle,altbuffer,size);
4669 	SafeFree(altbuffer);
4670 
4671 	// Elevator Tag
4672 
4673 	size = 9;
4674    SaveTag(savehandle,"ELEVATORS",size);
4675 
4676 	// Elevators
4677 
4678 	SaveElevators(&altbuffer,&size);
4679    StoreBuffer(savehandle,altbuffer,size);
4680 	SafeFree(altbuffer);
4681 
4682 	// Pushwall Tag
4683 
4684 	size=5;
4685    SaveTag(savehandle,"PWALL",size);
4686 
4687 	// PushWalls
4688 
4689 	SavePushWalls(&altbuffer,&size);
4690    StoreBuffer(savehandle,altbuffer,size);
4691 	SafeFree(altbuffer);
4692 
4693 	// MaskedWalls Tag
4694 
4695 	size=5;
4696    SaveTag(savehandle,"MWALL",size);
4697 
4698 	// Masked Walls
4699 
4700 	SaveMaskedWalls(&altbuffer,&size);
4701    StoreBuffer(savehandle,altbuffer,size);
4702 	SafeFree(altbuffer);
4703 
4704 	// Switches Tag
4705 
4706 	size=6;
4707    SaveTag(savehandle,"SWITCH",size);
4708 
4709 	// Switches
4710 
4711 	SaveSwitches(&altbuffer,&size);
4712    StoreBuffer(savehandle,altbuffer,size);
4713 	SafeFree(altbuffer);
4714 
4715 	// Statics Tag
4716 
4717 	size=6;
4718    SaveTag(savehandle,"STATIC",size);
4719 
4720 	// Statics
4721 
4722 	SaveStatics(&altbuffer,&size);
4723    StoreBuffer(savehandle,altbuffer,size);
4724 	SafeFree(altbuffer);
4725 
4726 	// Actors Tag
4727 
4728 	size=5;
4729    SaveTag(savehandle,"ACTOR",size);
4730 
4731 	// Actors
4732 
4733 	SaveActors(&altbuffer,&size);
4734    StoreBuffer(savehandle,altbuffer,size);
4735 	SafeFree(altbuffer);
4736 
4737 	// TouchPlates Tag
4738 
4739 	size=5;
4740    SaveTag(savehandle,"TOUCH",size);
4741 
4742 	// TouchPlates
4743 
4744 	SaveTouchPlates(&altbuffer,&size);
4745    StoreBuffer(savehandle,altbuffer,size);
4746 	SafeFree(altbuffer);
4747 
4748 	// GameState Tag
4749 
4750 	size=9;
4751    SaveTag(savehandle,"GAMESTATE",size);
4752 
4753 	// GameState
4754 
4755 	size=sizeof(gamestate);
4756    SafeWrite(savehandle,&gamestate,size);
4757 
4758 	// PlayerState Tag
4759 
4760 	size=12;
4761    SaveTag(savehandle,"PLAYERSTATES",size);
4762 
4763 	// PlayerStates
4764 	size=sizeof(playertype);
4765 	for(i=0;i<numplayers;i++)
4766      {
4767       SafeWrite(savehandle,&PLAYERSTATE[i],size);
4768 	  }
4769 
4770 	// Mapseen Tag
4771 
4772 	size=7;
4773    SaveTag(savehandle,"MAPSEEN",size);
4774 
4775 	// MapSeen
4776 
4777 	size=sizeof(mapseen);
4778    SafeWrite(savehandle,&mapseen,size);
4779 
4780 	// Song Tag
4781 
4782 	size=4;
4783    SaveTag(savehandle,"SONG",size);
4784 
4785 	// Song info
4786 
4787 	MU_SaveMusic(&altbuffer,&size);
4788    StoreBuffer(savehandle,altbuffer,size);
4789 	SafeFree(altbuffer);
4790 
4791 	// Misc Tag
4792 
4793 	size=4;
4794    SaveTag(savehandle,"MISC",size);
4795 
4796 	// Misc
4797 
4798 	// ticcount
4799 	myticcount = GetTicCount();
4800 	size=sizeof(myticcount);
4801    SafeWrite(savehandle,&myticcount,size);
4802 
4803 	// shaketics
4804 	size=sizeof(SHAKETICS);
4805    SafeWrite(savehandle,&SHAKETICS,size);
4806 
4807 	// damagecount
4808 	size=sizeof(damagecount);
4809    SafeWrite(savehandle,&damagecount,size);
4810 
4811 	// viewsize
4812 	size=sizeof(viewsize);
4813    SafeWrite(savehandle,&viewsize,size);
4814 
4815 	// poweruptimes
4816 	size = sizeof (poweruptime);
4817    SafeWrite(savehandle,&poweruptime,size);
4818 
4819 	size = sizeof (protectiontime);
4820    SafeWrite(savehandle,&protectiontime,size);
4821 
4822 	size = sizeof (powerupheight);
4823    SafeWrite(savehandle,&powerupheight,size);
4824 
4825 	size = sizeof (protectionheight);
4826    SafeWrite(savehandle,&protectionheight,size);
4827 
4828 	size = sizeof (poweradjust);
4829    SafeWrite(savehandle,&poweradjust,size);
4830 
4831    close (savehandle);
4832 
4833    // Calculate CRC
4834 
4835    crc = CalculateSaveGameCheckSum (filename);
4836 
4837    // Append the crc
4838 
4839    savehandle = SafeOpenAppend (filename);
4840 
4841    size=sizeof(crc);
4842    SafeWrite(savehandle,&crc,size);
4843 
4844    close (savehandle);
4845 
4846    pickquick = true;
4847 	return (true);
4848 }
4849 
4850 
4851 //******************************************************************************
4852 //
4853 // LoadTag
4854 //
4855 //******************************************************************************
4856 
LoadTag(byte ** src,char * tag,int size)4857 void LoadTag (byte ** src, char * tag, int size)
4858 {
4859 	if (StringsNotEqual((char *)*src,(char *)tag,size)==true)
4860 		Error("Could not locate %s header in saved game file\n",tag);
4861 	*src+=size;
4862 }
4863 
4864 //******************************************************************************
4865 //
4866 // LoadBuffer
4867 //
4868 //******************************************************************************
LoadBuffer(byte ** dest,byte ** src)4869 int LoadBuffer (byte ** dest, byte ** src)
4870 {
4871 	int size;
4872 
4873 	memcpy(&size,*src,sizeof(size));
4874 	*src+=sizeof(size);
4875 	*dest=SafeMalloc(size);
4876 	memcpy(*dest,*src,size);
4877 	*src+=size;
4878 	return size;
4879 }
4880 
4881 
4882 //******************************************************************************
4883 //
4884 // LoadTheGame ()
4885 //
4886 // Expects game to be premalloced
4887 //
4888 //******************************************************************************
4889 
LoadTheGame(int num,gamestorage_t * game)4890 boolean LoadTheGame (int num, gamestorage_t * game)
4891 {
4892    char   loadname[45]="rottgam0.rot";
4893    char   filename[128];
4894    byte   * loadbuffer;
4895 	byte   * bufptr;
4896 	byte   * altbuffer;
4897 	int    size;
4898 	int    totalsize;
4899 	int    checksum;
4900 	int    savedchecksum;
4901 	int    i;
4902    word   mapcrc;
4903         int myticcount;
4904 
4905 	if (num>15 || num<0)
4906 		Error("Illegal Load game value=%ld\n",num);
4907 
4908 	// Create the proper file name
4909 
4910    itoa(num,&loadname[7],16);
4911    loadname[8]='.';
4912 
4913    GetPathFromEnvironment( filename, ApogeePath, loadname );
4914 
4915    // Load the file
4916 
4917 	totalsize=LoadFile(filename,(void **)&loadbuffer);
4918 	bufptr=loadbuffer;
4919 
4920 	// Calculate checksum
4921 
4922 	checksum = DoCheckSum (loadbuffer, totalsize-sizeof(checksum), 0);
4923 
4924 	// Retrieve saved checksum
4925 
4926 	memcpy (&savedchecksum,loadbuffer+(totalsize-sizeof(savedchecksum)),sizeof(savedchecksum));
4927 
4928 	// Compare the two checksums;
4929 
4930 	if (checksum!=savedchecksum)
4931       {
4932       if (CP_DisplayMsg ("Your Saved Game file is\n"
4933                          "shall we say, \"corrupted\".\n"
4934                          "Would you like to\n"
4935                          "continue anyway (Y/N)?\n", 12)==false)
4936          {
4937          return false;
4938          }
4939       }
4940 
4941 	// Load in file tag
4942 
4943 	size=4;
4944 	LoadTag(&bufptr,"ROTT",size);
4945 
4946 	// Load in header
4947 
4948 	size=sizeof(*game);
4949 	memcpy(game,bufptr,size);
4950 	bufptr+=size;
4951 
4952 	if (game->version!=ROTTVERSION)
4953 		return false;
4954 
4955    memcpy (&GameLevels, &game->info, sizeof (GameLevels));
4956 
4957 	gamestate.episode=game->episode;
4958 	gamestate.mapon=game->area;
4959 
4960    mapcrc=GetMapCRC (gamestate.mapon);
4961 
4962    if (mapcrc!=game->mapcrc)
4963       return false;
4964 
4965 /////////////////////////////////////////////////////////////////////////////
4966 // Load in rest of saved game file beyond this point
4967 /////////////////////////////////////////////////////////////////////////////
4968 
4969 	// Free up the current level
4970 	Z_FreeTags (PU_LEVELSTRUCT, PU_LEVELEND);       // Free current level
4971 
4972    gamestate.battlemode = battle_StandAloneGame;
4973    BATTLE_SetOptions( &BATTLE_Options[ battle_StandAloneGame ] );
4974    BATTLE_Init( gamestate.battlemode, 1 );
4975 
4976 	DoLoadGameAction ();
4977 	SetupGameLevel();
4978 
4979 	// Door Tag
4980 
4981 	size=4;
4982 	LoadTag(&bufptr,"DOOR",size);
4983 
4984 	// Doors
4985 
4986 	DoLoadGameAction ();
4987 	size=LoadBuffer(&altbuffer,&bufptr);
4988 	LoadDoors(altbuffer,size);
4989 	SafeFree(altbuffer);
4990 
4991 	// Elevator Tag
4992 
4993 	size = 9;
4994 	LoadTag(&bufptr,"ELEVATORS",size);
4995 
4996 
4997 	// Elevators
4998 
4999 	DoLoadGameAction ();
5000 	size=LoadBuffer(&altbuffer,&bufptr);
5001 	LoadElevators(altbuffer,size);
5002 	SafeFree(altbuffer);
5003 
5004 	// Pushwall Tag
5005 
5006 	size=5;
5007 	LoadTag(&bufptr,"PWALL",size);
5008 
5009 	// PushWalls
5010 
5011 	DoLoadGameAction ();
5012 	size=LoadBuffer(&altbuffer,&bufptr);
5013 	LoadPushWalls(altbuffer,size);
5014 	SafeFree(altbuffer);
5015 #if 0
5016 	// Animated Walls Tag
5017 
5018 	size=5;
5019 	LoadTag(&bufptr,"AWALL",size);
5020 
5021 	// Animated Walls
5022 	size=LoadBuffer(&altbuffer,&bufptr);
5023 	LoadAnimWalls(altbuffer,size);
5024 	SafeFree(altbuffer);
5025 #endif
5026 
5027 	// MaskedWalls Tag
5028 
5029 	size=5;
5030 	LoadTag(&bufptr,"MWALL",size);
5031 
5032 	// Masked Walls
5033 
5034 	DoLoadGameAction ();
5035 	size=LoadBuffer(&altbuffer,&bufptr);
5036 	LoadMaskedWalls(altbuffer,size);
5037 	SafeFree(altbuffer);
5038 
5039 	// Switches Tag
5040 
5041 	size=6;
5042 	LoadTag(&bufptr,"SWITCH",size);
5043 
5044 	// Switches
5045 
5046 	DoLoadGameAction ();
5047 	size=LoadBuffer(&altbuffer,&bufptr);
5048 	LoadSwitches(altbuffer,size);
5049 	SafeFree(altbuffer);
5050 
5051 
5052 	// Statics Tag
5053 
5054 	size=6;
5055 	LoadTag(&bufptr,"STATIC",size);
5056 
5057    // Statics
5058 
5059    DoLoadGameAction ();
5060    size=LoadBuffer(&altbuffer,&bufptr);
5061    LoadStatics(altbuffer,size);
5062    SafeFree(altbuffer);
5063 
5064    // Actors Tag
5065 
5066    size=5;
5067    LoadTag(&bufptr,"ACTOR",size);
5068 
5069    // Actors
5070 
5071    DoLoadGameAction ();
5072    size=LoadBuffer(&altbuffer,&bufptr);
5073    LoadActors(altbuffer,size);
5074 	SafeFree(altbuffer);
5075 
5076 	// TouchPlates Tag
5077 
5078 	size=5;
5079 	LoadTag(&bufptr,"TOUCH",size);
5080 
5081 	// TouchPlates
5082 
5083 	DoLoadGameAction ();
5084 	size=LoadBuffer(&altbuffer,&bufptr);
5085 	LoadTouchPlates(altbuffer,size);
5086 	SafeFree(altbuffer);
5087 
5088    // SetupWindows
5089 
5090    SetupWindows();
5091 
5092 	// GameState Tag
5093 
5094 	size=9;
5095 	LoadTag(&bufptr,"GAMESTATE",size);
5096 
5097    // GameState
5098 
5099    DoLoadGameAction ();
5100    size=sizeof(gamestate);
5101    memcpy(&gamestate,bufptr,size);
5102    bufptr+=size;
5103 
5104    // PlayerState Tag
5105 
5106 	size=12;
5107 	LoadTag(&bufptr,"PLAYERSTATES",size);
5108 
5109 	// PlayerState
5110 
5111 	DoLoadGameAction ();
5112 	size=sizeof(playertype);
5113 	for(i=0;i<numplayers;i++)
5114 	 {memcpy(&PLAYERSTATE[i],bufptr,size);
5115 	  bufptr+=size;
5116 	 }
5117 
5118    // Zero out player targets
5119 
5120    locplayerstate->guntarget=0;
5121    locplayerstate->targettime=0;
5122 
5123    // Mapseen Tag
5124 
5125    size=7;
5126    LoadTag(&bufptr,"MAPSEEN",size);
5127 
5128    // MapSeen
5129 
5130    DoLoadGameAction ();
5131    size=sizeof(mapseen);
5132    memcpy(&mapseen,bufptr,size);
5133    bufptr+=size;
5134 
5135 	// Song Tag
5136 
5137 	size=4;
5138    LoadTag(&bufptr,"SONG",size);
5139 
5140 	// Song info
5141 
5142    DoLoadGameAction ();
5143 	size=LoadBuffer(&altbuffer,&bufptr);
5144 	MU_LoadMusic(altbuffer,size);
5145 	SafeFree(altbuffer);
5146 
5147    // Misc Tag
5148 
5149    size=4;
5150    LoadTag(&bufptr,"MISC",size);
5151 
5152    // Misc
5153 
5154    // ticcount
5155    DoLoadGameAction ();
5156    size=sizeof(myticcount);
5157 	memcpy((void *)&myticcount,bufptr,size);
5158    bufptr+=size;
5159    SaveTime = myticcount;
5160    ISR_SetTime(myticcount);
5161 
5162    // shaketics
5163    DoLoadGameAction ();
5164    size=sizeof(SHAKETICS);
5165    memcpy(&SHAKETICS,bufptr,size);
5166    bufptr+=size;
5167 
5168    // damagecount
5169    DoLoadGameAction ();
5170    size=sizeof(damagecount);
5171    memcpy(&damagecount,bufptr,size);
5172    bufptr+=size;
5173 
5174 	// viewsize
5175    DoLoadGameAction ();
5176    size=sizeof(viewsize);
5177    memcpy(&viewsize,bufptr,size);
5178    bufptr+=size;
5179 
5180    // powerup times
5181    DoLoadGameAction ();
5182    size = sizeof (poweruptime);
5183    memcpy (&poweruptime, bufptr, size);
5184    bufptr += size;
5185    size = sizeof (protectiontime);
5186    memcpy (&protectiontime, bufptr, size);
5187    bufptr += size;
5188    size = sizeof (powerupheight);
5189    memcpy (&powerupheight, bufptr, size);
5190    bufptr += size;
5191    size = sizeof (protectionheight);
5192    memcpy (&protectionheight, bufptr, size);
5193    bufptr += size;
5194    size = sizeof (poweradjust);
5195    memcpy (&poweradjust, bufptr, size);
5196    bufptr += size;
5197 
5198   // Set the viewsize
5199 
5200    SetViewSize(viewsize);
5201    DoLoadGameAction ();
5202 
5203    // Connect areas
5204 
5205    ConnectAreas ();
5206    DoLoadGameAction ();
5207 
5208    // Free up the loadbuffer
5209 
5210    SafeFree (loadbuffer);
5211    DoLoadGameAction ();
5212 
5213    Illuminate();
5214 
5215 	IN_UpdateKeyboard ();
5216    LoadPlayer ();
5217    DoLoadGameAction ();
5218    SetupPlayScreen();
5219    UpdateScore (gamestate.score);
5220    UpdateLives (locplayerstate->lives);
5221    UpdateTriads (player, 0);
5222 	PreCache ();
5223    InitializeMessages();
5224 
5225 	for (i=0;i<100;i++)
5226 		UpdateLightLevel(player->areanumber);
5227 
5228    CalcTics();
5229    CalcTics();
5230 
5231    pickquick = true;
5232 
5233    return (true);
5234 }
5235 
5236 
5237 //******************************************************************************
5238 //
5239 // GetSavedMessage ()
5240 //
5241 // Expects message to be premalloced
5242 //
5243 //******************************************************************************
5244 
GetSavedMessage(int num,char * message)5245 void GetSavedMessage (int num, char * message)
5246 {
5247    gamestorage_t game;
5248    char   loadname[45]="rottgam0.rot";
5249    char   filename[128];
5250    byte   * loadbuffer;
5251    byte   * bufptr;
5252    int    size;
5253 
5254    if (num>15 || num<0)
5255       Error("Illegal Load game value=%ld\n",num);
5256 
5257    // Create the proper file name
5258 
5259    itoa(num,&loadname[7],16);
5260    loadname[8]='.';
5261 
5262    GetPathFromEnvironment( filename, ApogeePath, loadname );
5263 
5264    // Load the file
5265 
5266    size=LoadFile(filename,(void **)&loadbuffer);
5267    bufptr=loadbuffer;
5268 
5269    size=4;
5270    LoadTag(&bufptr,"ROTT",size);
5271 
5272    // Load in header
5273 
5274    size=sizeof(game);
5275    memcpy(&game,bufptr,size);
5276    strcpy(message,game.message);
5277    SafeFree(loadbuffer);
5278 }
5279 
5280 //******************************************************************************
5281 //
5282 // GetSavedHeader ()
5283 //
5284 // Expects game to be premalloced
5285 //
5286 //******************************************************************************
5287 
GetSavedHeader(int num,gamestorage_t * game)5288 void GetSavedHeader (int num, gamestorage_t * game)
5289 {
5290    char   loadname[45]="rottgam0.rot";
5291    char   filename[128];
5292    byte   * loadbuffer;
5293    byte   * bufptr;
5294    int    size;
5295 
5296    if (num>15 || num<0)
5297       Error("Illegal Load game value=%ld\n",num);
5298 
5299    // Create the proper file name
5300 
5301    itoa(num,&loadname[7],16);
5302    loadname[8]='.';
5303 
5304    GetPathFromEnvironment( filename, ApogeePath, loadname );
5305 
5306    // Load the file
5307 
5308    size=LoadFile(filename, (void **)&loadbuffer);
5309    bufptr=loadbuffer;
5310 
5311    size=4;
5312    LoadTag(&bufptr,"ROTT",size);
5313 
5314    // Load in header
5315 
5316    size=sizeof(*game);
5317    memcpy(game,bufptr,size);
5318    SafeFree(loadbuffer);
5319 }
5320 
5321 
5322 
5323 //******************************************************************************
5324 //
5325 // GetLevel ()
5326 //
5327 //******************************************************************************
5328 
GetLevel(int episode,int mapon)5329 int GetLevel (int episode, int mapon)
5330 {
5331    int level;
5332 
5333    level = (mapon+1) - ((episode-1) << 3);
5334 
5335    return (level);
5336 }
5337