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 #include "rt_def.h"
21 #include "rt_view.h"
22 #include "z_zone.h"
23 #include "w_wad.h"
24 #include "lumpy.h"
25 #include "rt_util.h"
26 #include "rt_vid.h"
27 #include "rt_game.h"
28 #include "rt_draw.h"
29 #include "rt_ted.h"
30 #include "isr.h"
31 #include "rt_rand.h"
32 #include "rt_sound.h"
33 #include "modexlib.h"
34 #include "rt_menu.h"
35 
36 #ifdef DOS
37 #include <mem.h>
38 #endif
39 
40 #include <stdlib.h>
41 
42 #include "rt_main.h"
43 #include "rt_battl.h"
44 #include "rt_floor.h"
45 #include "rt_str.h"
46 #include "watcom.h"
47 #include "develop.h"
48 //MED
49 #include "memcheck.h"
50 
51 #define LIGHTNINGLEVEL 4
52 #define MINLIGHTNINGLEVEL   2
53 #define MAXLIGHTNINGLEVEL   10
54 
55 /*
56 =============================================================================
57 
58                                GLOBALS
59 
60 =============================================================================
61 */
62 int    StatusBar = 0;
63 int    lightninglevel=0;
64 boolean  lightning=false;
65 int    normalshade;
66 int    darknesslevel;
67 int    maxshade;
68 int    minshade;
69 int    baseminshade;
70 int    basemaxshade;
71 int    viewheight;
72 int    viewwidth;
73 longword   heightnumerator;
74 fixed  scale;
75 int    screenofs;
76 int    centerx;
77 int    centery;
78 int    centeryfrac;
79 int    fulllight;
80 int    weaponscale;
81 int    viewsize;
82 byte * colormap;
83 byte * redmap;
84 byte * greenmap;
85 byte * playermaps[MAXPLAYERCOLORS];
86 short  pixelangle[MAXVIEWWIDTH];
87 byte   gammatable[GAMMAENTRIES];
88 int    gammaindex;
89 int    focalwidth=FOCALWIDTH;
90 int    yzangleconverter;
91 byte   uniformcolors[MAXPLAYERCOLORS]={
92                                        25,
93                                        222,
94                                        29,
95                                        206,
96                                        52,
97                                        6,
98                                        155,
99                                        16,
100                                        90,
101                                        129,
102                                        109
103                                        };
104 
105 #ifdef DOS
106 byte    mapmasks1[4][9] = {
107 {1 ,3 ,7 ,15,15,15,15,15,15},
108 {2 ,6 ,14,14,14,14,14,14,14},
109 {4 ,12,12,12,12,12,12,12,12},
110 {8 ,8 ,8 ,8 ,8 ,8 ,8 ,8 ,8} };
111 
112 byte    mapmasks2[4][9] = {
113 {0 ,0 ,0 ,0 ,1 ,3 ,7 ,15,15},
114 {0 ,0 ,0 ,1 ,3 ,7 ,15,15,15},
115 {0 ,0 ,1 ,3 ,7 ,15,15,15,15},
116 {0 ,1 ,3 ,7 ,15,15,15,15,15} };
117 
118 byte    mapmasks3[4][9] = {
119 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1},
120 {0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,3},
121 {0 ,0 ,0 ,0 ,0 ,0 ,1 ,3 ,7},
122 {0 ,0 ,0 ,0 ,0 ,1 ,3 ,7 ,15} };
123 #endif
124 
125 
126 /*
127 =============================================================================
128 
129                                LOCAL
130 
131 =============================================================================
132 */
133 
134 static char *YourComputerSucksString = "Buy a 486! :)";
135 
136 static int viewsizes[MAXVIEWSIZES*2]={ 80,48,
137                            128,72,
138                            160,88,
139                            192,104,
140                            224,120,
141                            256,136,
142                            288,152,
143                            320,168,
144                            320,184,
145                            320,200,
146                            320,200};
147 
148 static int ColorMapLoaded=0;
149 
150 static int      lightningtime=0;
151 static int      lightningdelta=0;
152 static int      lightningdistance=0;
153 static int      lightningsoundtime=0;
154 static boolean  periodic=false;
155 static int      periodictime=0;
156 
157 void SetViewDelta ( void );
158 void UpdatePeriodicLighting (void);
159 
160 /*
161 ====================
162 =
163 = ResetFocalWidth
164 =
165 ====================
166 */
ResetFocalWidth(void)167 void ResetFocalWidth ( void )
168 {
169    focalwidth=FOCALWIDTH;
170    SetViewDelta();
171 }
172 
173 /*
174 ====================
175 =
176 = ChangeFocalWidth
177 =
178 ====================
179 */
ChangeFocalWidth(int amount)180 void ChangeFocalWidth ( int amount )
181 {
182    focalwidth=FOCALWIDTH+amount;
183    SetViewDelta();
184 }
185 
186 
187 /*
188 ====================
189 =
190 = SetViewDelta
191 =
192 ====================
193 */
194 
SetViewDelta(void)195 void SetViewDelta ( void )
196 {
197 
198 //
199 // calculate scale value for vertical height calculations
200 // and sprite x calculations
201 //
202    scale = (centerx*focalwidth)/160;
203 
204 //
205 // divide heightnumerator by a posts distance to get the posts height for
206 // the heightbuffer.  The pixel height is height>>HEIGHTFRACTION
207 //
208    heightnumerator = (((focalwidth/10)*centerx*4096)<<HEIGHTFRACTION);
209 }
210 
211 /*
212 ====================
213 =
214 = CalcProjection
215 =
216 ====================
217 */
218 
CalcProjection(void)219 void CalcProjection ( void )
220 {
221     int   i;
222     int   frac;
223     long  intang;
224     byte * table;
225     byte * ptr;
226     int   length;
227     int  * pangle;
228 
229 
230 
231 // Already being called in ResetFocalWidth
232 //    SetViewDelta();
233 
234 //
235 // load in tables file
236 //
237 
238 
239 //Hey, isn't this stuff already loaded in?
240 //Why don't we make this a lump?
241    table=W_CacheLumpName("tables",PU_STATIC, CvtFixme, 1);
242    ptr=table;
243 
244 //
245 // get size of table
246 //
247 
248    memcpy(&length,ptr,sizeof(int));
249    SwapIntelLong((long *)&length);
250    ptr+=sizeof(int);
251    pangle=SafeMalloc(length*sizeof(int));
252    memcpy(pangle,ptr,length*sizeof(int));
253 
254    frac=((length*65536/centerx))>>1;
255    for (i=0;i<centerx;i++)
256       {
257       // start 1/2 pixel over, so viewangle bisects two middle pixels
258       intang=pangle[frac>>16];
259       SwapIntelLong(&intang);
260       pixelangle[centerx-1-i] =(short) intang;
261       pixelangle[centerx+i] =(short) -intang;
262       frac+=(length*65536/centerx);
263       }
264    table=W_CacheLumpName("tables",PU_CACHE, CvtFixme, 1);
265    SafeFree(pangle);
266 }
267 
268 
269 /*
270 ==========================
271 =
272 = SetViewSize
273 =
274 ==========================
275 */
276 
SetViewSize(int size)277 void SetViewSize
278    (
279    int size
280    )
281 
282    {
283    int height;
284    int maxheight;
285    int screenx;
286    int screeny;
287    int topy;
288 
289    if ((size<0) || (size>=MAXVIEWSIZES))
290       Error("Illegal screen size = %ld\n",size);
291 
292    viewwidth  = viewsizes[ size << 1 ];         // must be divisable by 16
293    viewheight = viewsizes[ ( size << 1 ) + 1 ]; // must be even
294 
295    maxheight = 200;
296    topy      = 0;
297 
298    // Only keep the kills flag
299    StatusBar &= ~( BOTTOM_STATUS_BAR | TOP_STATUS_BAR |
300       STATUS_PLAYER_STATS );
301 
302    if ( SHOW_KILLS() )
303       {
304       // Account for height of kill boxes
305       maxheight -= 24;
306       }
307 
308    if ( size < 9 )
309       {
310       StatusBar |= TOP_STATUS_BAR;
311 
312       // Account for height of top status bar
313       maxheight -= 16;
314       topy      += 16;
315       }
316 
317    if ( size < 8 )
318       {
319       // Turn on health and ammo bar
320       StatusBar |= BOTTOM_STATUS_BAR;
321       maxheight -= 16;
322       }
323    else if ( size < 10 )
324       {
325       // Turn on transparent health and ammo bar
326       StatusBar |= STATUS_PLAYER_STATS;
327       }
328 
329    height = viewheight;
330    if ( height > 168 )
331       {
332       // Prevent weapon from being scaled too big
333       height = 168;
334       }
335 
336    weaponscale = ( height << 16 ) / 168;
337    centerx     = viewwidth >> 1;
338    centery     = viewheight >> 1;
339    centeryfrac = (centery << 16);
340    yzangleconverter = ( 0xaf85 * viewheight ) / 200;
341 
342    // Center the view horizontally
343    screenx = ( 320 - viewwidth ) >> 1;
344 
345    if ( viewheight >= maxheight )
346       {
347       screeny = topy;
348       viewheight = maxheight;
349       }
350    else
351       {
352       // Center the view vertically
353       screeny = ( ( maxheight - viewheight ) >> 1 ) + topy;
354       }
355 
356    // Calculate offset of view window
357 #ifdef DOS
358    screenofs = ( screenx >> 2 ) + ylookup[ screeny ];
359 #else
360    screenofs = screenx + ylookup[ screeny ];
361 #endif
362 
363 //
364 // calculate trace angles and projection constants
365 //
366 
367    ResetFocalWidth();
368 
369 
370 // Already being called in ResetFocalWidth
371 //   SetViewDelta();
372 
373    CalcProjection();
374    }
375 
376 
377 //******************************************************************************
378 //
379 // DrawCPUJape ()
380 //
381 //******************************************************************************
382 
DrawCPUJape(void)383 void DrawCPUJape
384    (
385    void
386    )
387 
388    {
389    int width;
390    int height;
391 
392    CurrentFont = tinyfont;
393    VW_MeasurePropString( YourComputerSucksString, &width, &height );
394 
395    DrawGameString( 160 - width / 2, 100 + 48 / 2 + 2,
396       YourComputerSucksString, true );
397    }
398 
399 
400 /*
401 ==========================
402 =
403 = SetupScreen
404 =
405 ==========================
406 */
407 
SetupScreen(boolean flip)408 void SetupScreen ( boolean flip )
409 {
410    pic_t *shape;
411 
412    SetViewSize(viewsize);
413    if ( viewsize < 7 )
414       {
415       shape = W_CacheLumpName( "backtile", PU_CACHE, Cvt_pic_t, 1 );
416       DrawTiledRegion( 0, 16, 320, 200 - 32, 0, 16, shape );
417       }
418 
419    if ( viewsize == 0 )
420       {
421       DrawCPUJape();
422       }
423 
424    DrawPlayScreen (true);
425    if (flip==true)
426       {
427       ThreeDRefresh();
428       VL_CopyDisplayToHidden();
429       }
430 }
431 
432 
433 
LoadColorMap(void)434 void LoadColorMap( void )
435 {
436    int i,j;
437    int lump, length;
438 
439    if (ColorMapLoaded==1)
440       Error("Called LoadColorMap twice\n");
441    ColorMapLoaded=1;
442 //
443 //   load in the light tables
444 //   256 byte align tables
445 //
446 
447 	lump = W_GetNumForName("colormap");
448 	length = W_LumpLength (lump) + 255;
449 	colormap = SafeMalloc (length);
450 	colormap = (byte *)( ((int)colormap + 255)&~0xff);
451 	W_ReadLump (lump,colormap);
452 
453 // Fix fire colors in colormap
454 
455    for (i=31;i>=16;i--)
456 		for (j=0xea;j<0xf9;j++)
457          colormap[i*256+j]=colormap[(((i-16)/4+16))*256+j];
458 
459 // Get special maps
460 
461 	lump = W_GetNumForName("specmaps");
462 	length = W_LumpLength (lump+1) + 255;
463 	redmap = SafeMalloc (length);
464 	redmap = (byte *)( ((int)redmap + 255)&~0xff);
465 	W_ReadLump (lump+1,redmap);
466    greenmap = redmap+(16*256);
467 
468 // Get player colormaps
469 
470 //   if (modemgame==true)
471       {
472       lump = W_GetNumForName("playmaps")+1;
473       for (i=0;i<MAXPLAYERCOLORS;i++)
474          {
475 	      length = W_LumpLength (lump+i) + 255;
476 	      playermaps[i] = SafeMalloc (length);
477 	      playermaps[i] = (byte *)( ((int)playermaps[i] + 255)&~0xff);
478 	      W_ReadLump (lump+i,playermaps[i]);
479          }
480       }
481 
482    if (!quiet)
483       printf("RT_VIEW: Colormaps Initialized\n");
484 
485 }
486 
487 /*
488 ==========================
489 =
490 = SetupLightLevels
491 =
492 ==========================
493 */
494 #define LIGHTRATEBASE 252
495 #define LIGHTRATEEND  267
496 #define LIGHTLEVELBASE 216
497 #define LIGHTLEVELEND  223
SetupLightLevels(void)498 void SetupLightLevels ( void )
499 {
500    int glevel;
501 
502    periodic=false;
503 	fog=0;
504 	lightsource=0;
505 
506 // Set up light level for level
507 
508 	if (((word)MAPSPOT(2,0,1)>=104) && ((word)MAPSPOT(2,0,1)<=105))
509 		fog=(word)MAPSPOT(2,0,1)-104;
510 	else
511 		Error ("There is no Fog icon on map %ld\n",gamestate.mapon);
512 	if ((word)MAPSPOT(3,0,1)==139)
513       {
514       if (fog==0)
515          {
516 		   lightsource=1;
517          lights=Z_Malloc(MAPSIZE*MAPSIZE*(sizeof(unsigned long)),PU_LEVEL,NULL);
518          memset (lights,0,MAPSIZE*MAPSIZE*(sizeof(unsigned long)));
519          }
520       else
521 		   Error("You cannot use light sourcing on a level with fog on map %ld\n",gamestate.mapon);
522       }
523 	else if ((word)MAPSPOT(3,0,1))
524 		Error("You must use the lightsource icon or nothing at all at (3,0) in plane 1 on map %ld\n",gamestate.mapon);
525    if (((word)MAPSPOT(2,0,0)>=LIGHTLEVELBASE) && ((word)MAPSPOT(2,0,0)<=LIGHTLEVELEND))
526       glevel=(MAPSPOT(2,0,0)-LIGHTLEVELBASE);
527 	else
528 		Error("You must specify a valid darkness level icon at (2,0) on map %ld\n",gamestate.mapon);
529 
530    SetLightLevels ( glevel );
531 
532    if (((word)MAPSPOT(3,0,0)>=LIGHTRATEBASE) && ((word)MAPSPOT(3,0,0)<=LIGHTRATEEND))
533       glevel=(MAPSPOT(3,0,0)-LIGHTRATEBASE);
534 	else
535       {
536 //      Error("You must specify a valid darkness rate icon at (3,0) on map %ld\n",gamestate.mapon);
537       glevel = 4;
538       }
539 
540    SetLightRate ( glevel );
541    lightningtime=0;
542    lightningdistance=0;
543    lightninglevel=0;
544    lightningdelta=0;
545    lightningsoundtime=0;
546 }
547 
548 /*
549 ==========================
550 =
551 = SetLightLevels
552 =
553 ==========================
554 */
SetLightLevels(int darkness)555 void SetLightLevels ( int darkness )
556 {
557    if (fog==0)
558       {
559       baseminshade=0x10+((7-darkness)>>1);
560       basemaxshade=0x1f-(darkness>>1);
561       }
562    else
563       {
564       baseminshade=darkness;
565       basemaxshade=0x10;
566       }
567    minshade=baseminshade;
568    maxshade=basemaxshade;
569    darknesslevel=darkness;
570 }
571 
572 /*
573 ==========================
574 =
575 = GetLightLevelTile
576 =
577 ==========================
578 */
GetLightLevelTile(void)579 int GetLightLevelTile ( void )
580 {
581    if (fog==0)
582       {
583       return ((7-((baseminshade-0x10)<<1))+LIGHTLEVELBASE);
584       }
585    else
586       {
587       return (baseminshade+LIGHTLEVELBASE);
588       }
589 }
590 
591 
592 /*
593 ==========================
594 =
595 = SetLightRate
596 =
597 ==========================
598 */
SetLightRate(int rate)599 void SetLightRate ( int rate )
600 {
601    normalshade=(HEIGHTFRACTION+8)-rate;
602    if (normalshade>14) normalshade=14;
603    if (normalshade<3) normalshade=3;
604 }
605 
606 /*
607 ==========================
608 =
609 = GetLightRate
610 =
611 ==========================
612 */
GetLightRate(void)613 int GetLightRate ( void )
614 {
615    return ((HEIGHTFRACTION+8)-normalshade);
616 }
617 
618 /*
619 ==========================
620 =
621 = GetLightRateTile
622 =
623 ==========================
624 */
GetLightRateTile(void)625 int GetLightRateTile ( void )
626 {
627    return ((HEIGHTFRACTION+8)-normalshade+LIGHTRATEBASE);
628 }
629 
630 
631 
632 /*
633 ==========================
634 =
635 = UpdateLightLevel
636 =
637 ==========================
638 */
UpdateLightLevel(int area)639 void UpdateLightLevel (int area)
640 {
641    int numlights;
642    int targetmin;
643    int targetmax;
644    int numtiles;
645 
646    if (fog==true)
647       return;
648 
649    numtiles=(numareatiles[area]>>5)-2;
650    numlights=(LightsInArea[area]-numtiles)>>1;
651 
652    if (numlights<0)
653       numlights=0;
654    if (numlights>GENERALNUMLIGHTS)
655       numlights=GENERALNUMLIGHTS;
656    targetmin=baseminshade+(GENERALNUMLIGHTS-numlights);
657    targetmax=basemaxshade-numlights;
658    if (targetmax<baseminshade)
659       targetmax=baseminshade;
660    if (targetmin>targetmax)
661       targetmin=targetmax;
662 
663    if (minshade>targetmin)
664       minshade-=1;
665    else if (minshade<targetmin)
666       minshade+=1;
667 
668    if (maxshade>targetmax)
669       maxshade-=1;
670    else if (maxshade<targetmax)
671       maxshade+=1;
672 
673 #if 0
674    targetlevel=baseminshade+(GENERALNUMLIGHTS-numlights);
675    if (abs(minshade-targetlevel)==1)
676       minshade=targetlevel;
677    else if (minshade>targetlevel)
678       minshade-=2;
679    else if (minshade<targetlevel)
680       minshade+=2;
681 #endif
682 }
683 
684 /*
685 ==========================
686 =
687 = SetIllumination
688 =
689 = Postive value lightens
690 = Negative value darkens
691 =
692 ==========================
693 */
SetIllumination(int level)694 void SetIllumination (int level)
695 {
696    if (fog)
697       return;
698 	maxshade-=level;
699    if (maxshade>31)
700       maxshade=31;
701    if (maxshade<0x10)
702       maxshade=0x10;
703 	minshade-=level;
704    if (minshade<0x10)
705       minshade=0x10;
706    if (minshade>31)
707       minshade=31;
708 }
709 
710 /*
711 ==========================
712 =
713 = GetIlluminationDelta
714 =
715 ==========================
716 */
GetIlluminationDelta(void)717 int GetIlluminationDelta (void)
718 {
719    if (fog)
720       return 0;
721    else
722       return maxshade-basemaxshade;
723 }
724 
725 /*
726 ==========================
727 =
728 = UpdateLightning
729 =
730 ==========================
731 */
UpdateLightning(void)732 void UpdateLightning (void)
733 {
734    if (periodic==true)
735       {
736       UpdatePeriodicLighting();
737       return;
738       }
739    if ((fog==1) || (lightning==false))
740       return;
741 
742    if (lightningtime<=0)
743       {
744       if (lightningsoundtime>0)
745          SD_Play3D (SD_LIGHTNINGSND, 0, lightningdistance);
746       lightningtime=GameRandomNumber("UpdateLightning",0)<<1;
747       lightningdistance=GameRandomNumber("UpdateLightning",0);
748       lightninglevel=(255-lightningdistance)>>LIGHTNINGLEVEL;
749       if (lightninglevel<MINLIGHTNINGLEVEL)
750          lightninglevel=MINLIGHTNINGLEVEL;
751       if (lightninglevel>MAXLIGHTNINGLEVEL)
752          lightninglevel=MAXLIGHTNINGLEVEL;
753       lightningdelta=lightninglevel>>1;
754       lightningsoundtime=lightningdistance>>1;
755       if (lightningdistance<100)
756          {
757          SetIllumination(lightninglevel);
758          }
759       }
760    else if (lightninglevel>0)
761       {
762       lightninglevel-=lightningdelta;
763       if (lightninglevel<=0)
764          {
765          lightninglevel=0;
766          }
767       }
768    else
769       lightningtime--;
770    if (lightningsoundtime)
771       {
772       lightningsoundtime--;
773       if (lightningsoundtime<=0)
774          {
775          int volume;
776 
777          volume=255-lightningdistance;
778          if (volume>170) volume=170;
779          SD_PlayPitchedSound ( SD_LIGHTNINGSND, volume,-(lightningdistance<<2));
780          lightningsoundtime=0;
781          }
782       }
783 }
784 
785 /*
786 ==========================
787 =
788 = UpdatePeriodicLighting
789 =
790 ==========================
791 */
792 #define PERIODICMAG (6)
793 #define PERIODICSTEP (20)
794 #define PERIODICBASE (0x0f)
UpdatePeriodicLighting(void)795 void UpdatePeriodicLighting (void)
796 {
797    int val;
798 
799    val=FixedMul(PERIODICMAG,sintable[periodictime]);
800    periodictime=(periodictime+PERIODICSTEP)&(FINEANGLES-1);
801    basemaxshade=PERIODICBASE+(PERIODICMAG)+val;
802    baseminshade=basemaxshade-GENERALNUMLIGHTS-1;
803 }
804 
805 /*
806 ==========================
807 =
808 = SetModemLightLevel
809 =
810 ==========================
811 */
SetModemLightLevel(int type)812 void SetModemLightLevel ( int type )
813 {
814    periodic=false;
815    fulllight=false;
816    switch (type)
817       {
818       case bo_light_dark:
819          MAPSPOT(2,0,0)=(word)216;
820          MAPSPOT(3,0,0)=(word)255;
821          MAPSPOT(3,0,1)=(word)139;
822          MAPSPOT(2,0,1)=(word)104;
823          SetupLightLevels ();
824          break;
825       case bo_light_normal:
826          break;
827       case bo_light_bright:
828          MAPSPOT(2,0,0)=(word)223;
829          MAPSPOT(3,0,0)=(word)267;
830          MAPSPOT(3,0,1)=(word)0;
831          MAPSPOT(2,0,1)=(word)104;
832          SetupLightLevels ();
833          break;
834       case bo_light_fog:
835          MAPSPOT(2,0,0)=(word)219;
836          MAPSPOT(3,0,0)=(word)259;
837          MAPSPOT(2,0,1)=(word)105;
838          MAPSPOT(3,0,1)=(word)0;
839          SetupLightLevels ();
840          break;
841       case bo_light_periodic:
842          fog=0;
843          MAPSPOT(2,0,1)=(word)104;
844          MAPSPOT(3,0,1)=(word)139;
845          SetupLightLevels ();
846          periodic=true;
847          break;
848       case bo_light_lightning:
849          if (sky!=0)
850             {
851             MAPSPOT(2,0,0)=(word)222;
852             MAPSPOT(3,0,0)=(word)255;
853             MAPSPOT(3,0,1)=(word)139;
854             MAPSPOT(2,0,1)=(word)104;
855             SetupLightLevels ();
856             lightning=true;
857             }
858          break;
859       }
860 }
861 
862