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