1 //-------------------------------------------------------------------------
2 /*
3 Copyright (C) 1997, 2005 - 3D Realms Entertainment
4 
5 This file is part of Shadow Warrior version 1.2
6 
7 Shadow Warrior is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 
16 See the GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 
22 Original Source: 1997 - Frank Maddin and Jim Norwood
23 Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms
24 */
25 //-------------------------------------------------------------------------
26 #define QUIET
27 #include "build.h"
28 #include "pragmas.h"
29 #include "cache1d.h"
30 
31 #include "keys.h"
32 #include "names2.h"
33 #include "panel.h"
34 #include "game.h"
35 #include "quake.h"
36 #include "vis.h"
37 
38 #include "jsector.h"
39 
40 #include "mytypes.h"
41 #include "control.h"
42 #include "function.h"
43 #include "net.h"
44 #include "pal.h"
45 #include "player.h"
46 #include "jtags.h"
47 #include "parent.h"
48 
49 #include "cache.h"
50 #include "reserve.h"
51 
52 #include "text.h"
53 #include "menus.h"
54 #include "interp.h"
55 #include "sector.h"
56 
57 static int OverlapDraw = FALSE;
58 extern BOOL QuitFlag, LocationInfo, ConPanel, SpriteInfo, PauseKeySet;
59 extern BOOL Voxel;
60 extern char tempbuf[];
61 extern char buffer[];
62 BOOL DrawScreen;
63 extern short f_c;
64 
65 extern BOOL HelpInputMode;
66 extern short HelpPage;
67 extern short HelpPagePic[];
68 extern ParentalStruct aVoxelArray[MAXTILES];
69 extern BOOL RedrawScreen;
70 BOOL RedrawCompass=FALSE;
71 BOOL ScreenDidCapture = FALSE;
72 extern int Follow_posx,Follow_posy;
73 short LastCompassAngle = -1;
74 BOOL RestartVideo;
75 VMODE NewVideoMode;
76 
77 int ConnectCopySprite(SPRITEp tsp);
78 void PreDrawStackedWater(void );
79 VOID DrawCompass(PLAYERp pp);
80 
81 #if 1
82 VOID
ShadeSprite(SPRITEp tsp)83 ShadeSprite(SPRITEp tsp)
84     {
85     // set shade of sprite
86     tsp->shade = sector[tsp->sectnum].floorshade - 25;
87 
88     if (tsp->shade > -3)
89         tsp->shade = -3;
90 
91     if (tsp->shade < -30)
92         tsp->shade = -30;
93     }
94 #else
95 #endif
96 
97 
98 short
GetRotation(short tSpriteNum,int viewx,int viewy)99 GetRotation(short tSpriteNum, int viewx, int viewy)
100     {
101     static short RotTable8[] = {0, 7, 6, 5, 4, 3, 2, 1};
102     static short RotTable5[] = {0, 1, 2, 3, 4, 3, 2, 1};
103     short rotation;
104     extern short screenpeek;
105 
106     SPRITEp tsp = &tsprite[tSpriteNum];
107     USERp tu = User[tsp->owner];
108     PLAYERp pp = Player + screenpeek;
109     short angle2;
110 
111     if (tu->RotNum == 0)
112         return (0);
113 
114     // Get which of the 8 angles of the sprite to draw (0-7)
115     // rotation ranges from 0-7
116     angle2 = getangle(tsp->x - viewx, tsp->y - viewy);
117     rotation = ((tsp->ang + 3072 + 128 - angle2) & 2047);
118     rotation = (rotation >> 8) & 7;
119 
120     if (tu->RotNum == 5)
121         {
122         if (TEST(tu->Flags, SPR_XFLIP_TOGGLE))
123             {
124             if (rotation <= 4)
125                 {
126                 // leave rotation alone
127                 RESET(tsp->cstat, CSTAT_SPRITE_XFLIP);
128                 }
129             else
130                 {
131                 rotation = (8 - rotation);
132                 SET(tsp->cstat, CSTAT_SPRITE_XFLIP);    // clear x-flipping bit
133                 }
134             }
135         else
136             {
137             if (rotation > 3 || rotation == 0)
138                 {
139                 // leave rotation alone
140                 RESET(tsp->cstat, CSTAT_SPRITE_XFLIP);  // clear x-flipping bit
141                 }
142             else
143                 {
144                 rotation = (8 - rotation);
145                 SET(tsp->cstat, CSTAT_SPRITE_XFLIP);    // set
146                 }
147             }
148 
149         // Special case bunk
150         if(tu->ID == TOILETGIRL_R0 || tu->ID == WASHGIRL_R0 || tu->ID == TRASHCAN ||
151             tu->ID == CARGIRL_R0 || tu->ID == MECHANICGIRL_R0 || tu->ID == PRUNEGIRL_R0 ||
152             tu->ID == SAILORGIRL_R0)
153                 RESET(tsp->cstat, CSTAT_SPRITE_XFLIP);  // clear x-flipping bit
154 
155         return (RotTable5[rotation]);
156         }
157 
158     return (RotTable8[rotation]);
159 
160     }
161 
162 /*
163 
164 
165 !AIC - At draw time this is called for actor rotation.  GetRotation() is more
166 complex than needs to be in part because importing of actor rotations and x-flip
167 directions was not standardized.
168 
169 */
170 
171 int
SetActorRotation(short tSpriteNum,int viewx,int viewy)172 SetActorRotation(short tSpriteNum, int viewx, int viewy)
173     {
174     SPRITEp tsp = &tsprite[tSpriteNum];
175     USERp tu = User[tsp->owner];
176     short StateOffset, Rotation;
177 
178     // don't modify ANY tu vars - back them up!
179     STATEp State = tu->State;
180     STATEp StateStart = tu->StateStart;
181 
182     if (tu->RotNum == 0)
183         return (0);
184 
185     // Get the offset into the State animation
186     StateOffset = State - StateStart;
187 
188     // Get the rotation angle
189     Rotation = GetRotation(tSpriteNum, viewx, viewy);
190 
191     ASSERT(Rotation < 5);
192 
193     // Reset the State animation start based on the Rotation
194     StateStart = tu->Rot[Rotation];
195 
196     // Set the sprites state
197     State = StateStart + StateOffset;
198 
199     // set the picnum here - may be redundant, but we just changed states and
200     // thats a big deal
201     tsp->picnum = State->Pic;
202 
203     //sprintf(ds,"SetActorRotation:tsp->picnum: %d",tsp->picnum);
204     //CON_Message(ds);
205 
206 /*
207 
208  !AIC KEY - For actor states EVERY rotation needs to have the same tics
209  animators.  The only thing different can be the picnum.  If not then sync bugs
210  will occur.  This code attempts to check to the best of its ability for this
211  problem.  Should go away with shipped compile.
212 
213 */
214 
215 #if DEBUG
216         {
217         short i;
218 
219         for (i = 0; i < tu->RotNum; i++)
220             {
221             STATEp TestStateStart, TestState;
222 
223             TestStateStart = tu->Rot[i];
224             TestState = TestStateStart + StateOffset;
225 
226             ASSERT(State->Tics == TestState->Tics);
227             ASSERT(State->Animator == TestState->Animator);
228             }
229         }
230 #endif
231     return (0);
232     }
233 
234 int
DoShadowFindGroundPoint(SPRITEp sp)235 DoShadowFindGroundPoint(SPRITEp sp)
236     {
237     // USES TSPRITE !!!!!
238     USERp u = User[sp->owner];
239     SPRITEp hsp;
240     int ceilhit, florhit;
241     int hiz, loz = u->loz;
242     short save_cstat, bak_cstat;
243     BOOL found = FALSE;
244 
245     // recursive routine to find the ground - either sector or floor sprite
246     // skips over enemy and other types of sprites
247 
248     // IMPORTANT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
249     // This will return invalid FAF ceiling and floor heights inside of analyzesprite
250     // because the ceiling and floors get moved out of the way for drawing.
251 
252     save_cstat = sp->cstat;
253     RESET(sp->cstat, CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN);
254     FAFgetzrangepoint(sp->x, sp->y, sp->z, sp->sectnum, &hiz, &ceilhit, &loz, &florhit);
255     sp->cstat = save_cstat;
256 
257     ASSERT(TEST(florhit, HIT_SPRITE | HIT_SECTOR));
258 
259     switch (TEST(florhit, HIT_MASK))
260         {
261     case HIT_SPRITE:
262             {
263             hsp = &sprite[NORM_SPRITE(florhit)];
264 
265             if (TEST(hsp->cstat, CSTAT_SPRITE_FLOOR))
266                 {
267                 // found a sprite floor
268                 return (loz);
269                 }
270             else
271                 {
272                 // reset the blocking bit of what you hit and try again -
273                 // recursive
274                 bak_cstat = hsp->cstat;
275                 RESET(hsp->cstat, CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN);
276                 loz = DoShadowFindGroundPoint(sp);
277                 hsp->cstat = bak_cstat;
278                 }
279             }
280 
281     case HIT_SECTOR:
282             {
283             return (loz);
284             }
285 
286     default:
287         ASSERT(TRUE == FALSE);
288         break;
289         }
290 
291     return (loz);
292 
293     }
294 
295 #if 0
296 #define GENERIC_SHADOW_PIC 66
297 extern BOOL bVoxelsOn;
298 VOID
299 DoVoxelShadow(SPRITEp tspr)
300 {
301     // Check for voxels
302     if(bVoxelsOn)
303     {
304         switch(tspr->picnum)
305         {
306             case ICON_STAR:             // 1793
307             case ICON_UZI:              // 1797
308             case ICON_UZIFLOOR:         // 1807
309             case ICON_LG_UZI_AMMO:      // 1799
310             case ICON_HEART:            // 1824
311             case ICON_HEART_LG_AMMO:    // 1820
312             case ICON_GUARD_HEAD:       // 1814
313             case ICON_FIREBALL_LG_AMMO: // 3035
314             case ICON_ROCKET:           // 1843
315             case ICON_SHOTGUN:          // 1794
316             case ICON_LG_ROCKET:        // 1796
317             case ICON_LG_SHOTSHELL:     // 1823
318             case ICON_MICRO_GUN:        // 1818
319             case ICON_MICRO_BATTERY:    // 1800
320             case ICON_GRENADE_LAUNCHER: // 1817
321             case ICON_LG_GRENADE:       // 1831
322             case ICON_LG_MINE:          // 1842
323             case ICON_RAIL_GUN:         // 1811
324             case ICON_RAIL_AMMO:        // 1812
325             case ICON_SM_MEDKIT:        // 1802
326             case ICON_MEDKIT:           // 1803
327             case ICON_CHEMBOMB:         // 1808
328             case ICON_FLASHBOMB:        // 1805
329             case ICON_NUKE:             // 1809
330             case ICON_CALTROPS:
331             case ICON_BOOSTER:          // 1810
332             case ICON_HEAT_CARD:        // 1819
333             case ICON_REPAIR_KIT:       // 1813
334             case ICON_EXPLOSIVE_BOX:    // 1801
335             case ICON_ENVIRON_SUIT:     // 1837
336             case ICON_FLY:              // 1782
337             case ICON_CLOAK:            // 1826
338             case ICON_NIGHT_VISION:     // 3031
339             case ICON_NAPALM:           // 3046
340             case ICON_RING:             // 3050
341             //case ICON_GOROAMMO:       // 3035
342             //case ICON_HEARTAMMO:      // 1820
343             case ICON_RINGAMMO:         // 3054
344             case ICON_NAPALMAMMO:       // 3058
345             case ICON_GRENADE:          // 3059
346             //case ICON_OXYGEN:         // 1800
347             case ICON_ARMOR:            // 3030
348             case BLUE_KEY:              // 1766
349             case RED_KEY:               // 1770
350             case GREEN_KEY:             // 1774
351             case YELLOW_KEY:            // 1778
352             case GOLD_SKELKEY:
353             case SILVER_SKELKEY:
354             case BRONZE_SKELKEY:
355             case RED_SKELKEY:
356             case BLUE_CARD:
357             case RED_CARD:
358             case GREEN_CARD:
359             case YELLOW_CARD:
360 //              tspr->picnum = GENERIC_SHADOW_PIC;
361                 tspr->xrepeat = 0;  // For now, don't do voxel shadows
362                 tspr->yrepeat = 0;
363 //              tspr->xrepeat = 27;
364 //              tspr->yrepeat = 4;
365                 //tspr->z+=(sintable[(rotang*2)%2047]/16);
366             break;
367         }
368     }
369 }
370 #endif
371 
372 VOID
DoShadows(SPRITEp tsp,int viewz)373 DoShadows(SPRITEp tsp, int viewz)
374     {
375     SPRITEp new = &tsprite[spritesortcnt];
376     USERp tu = User[tsp->owner];
377     int ground_dist = 0;
378     int view_dist = 0;
379     int loz;
380     short xrepeat;
381     short yrepeat;
382     short sectnum;
383 
384     sectnum = tsp->sectnum;
385     // make sure its the correct sector
386     // DoShadowFindGroundPoint calls FAFgetzrangepoint and this is sensitive
387     //updatesectorz(tsp->x, tsp->y, tsp->z, &sectnum);
388     updatesector(tsp->x, tsp->y, &sectnum);
389 
390     if (sectnum < 0)
391         {
392         //int cz,fz;
393         //getzsofslope(tsp->sectnum, tsp->x, tsp->y, &cz, &fz);
394         ////DSPRINTF(ds,"Shad sect !fnd x%d, y%d, z%d, sect%d, cz %d, fz %d", tsp->x, tsp->y, tsp->z, tsp->sectnum, cz, fz);
395         //MONO_PRINT(ds);
396         return;
397         }
398 
399     tsp->sectnum = sectnum;
400     memcpy(new, tsp, sizeof(SPRITE));
401     // shadow is ALWAYS draw last - status is priority
402     new->statnum = MAXSTATUS;
403     new->sectnum = sectnum;
404 
405     if ((tsp->yrepeat >> 2) > 4)
406         {
407         yrepeat = (tsp->yrepeat >> 2) - (SPRITEp_SIZE_Y(tsp) / 64) * 2;
408         xrepeat = new->xrepeat;
409         }
410     else
411         {
412         yrepeat = new->yrepeat;
413         xrepeat = new->xrepeat;
414         }
415 
416     new->shade = 127;
417     SET(new->cstat, CSTAT_SPRITE_TRANSLUCENT);
418 
419     loz = tu->loz;
420     if (tu->lo_sp)
421         {
422         if (!TEST(tu->lo_sp->cstat, CSTAT_SPRITE_WALL | CSTAT_SPRITE_FLOOR))
423             {
424             loz = DoShadowFindGroundPoint(tsp);
425             }
426         }
427 
428     #if 0
429     if (SectUser[tsp->sectnum] && SectUser[tsp->sectnum]->depth)
430         {
431         loz -= Z(SectUser[tsp->sectnum]->depth);
432         }
433     #endif
434 
435     // need to find the ground here
436     new->z = loz;
437 
438     // if below or close to sprites z don't bother to draw it
439     if ((viewz - loz) > -Z(8))
440         return;
441 
442     // if close to shadows z shrink it
443     view_dist = labs(loz - viewz) >> 8;
444     if (view_dist < 32)
445         view_dist = 256/view_dist;
446     else
447         view_dist = 0;
448 
449     // make shadow smaller depending on height from ground
450     ground_dist = labs(loz - SPRITEp_BOS(tsp)) >> 8;
451     ground_dist = DIV16(ground_dist);
452 
453     xrepeat = max(xrepeat - ground_dist - view_dist, 4);
454     yrepeat = max(yrepeat - ground_dist - view_dist, 4);
455     xrepeat = min(xrepeat, 255);
456     yrepeat = min(yrepeat, 255);
457 
458     new->xrepeat = xrepeat;
459     new->yrepeat = yrepeat;
460 
461     // Check for voxel items and use a round generic pic if so
462     //DoVoxelShadow(new);
463 
464     spritesortcnt++;
465     }
466 
467 VOID
DoMotionBlur(SPRITEp tsp)468 DoMotionBlur(SPRITEp tsp)
469     {
470     SPRITEp new;
471     USERp tu = User[tsp->owner];
472     int nx,ny,nz = 0,dx,dy,dz;
473     short i, ang;
474     short xrepeat, yrepeat, repeat_adj = 0;
475     int z_amt_per_pixel;
476 
477     ang = NORM_ANGLE(tsp->ang + 1024);
478 
479     if (tsp->xvel == 0)
480         {
481         return;
482         }
483 
484     if (TEST(tsp->extra, SPRX_PLAYER_OR_ENEMY))
485         {
486         z_amt_per_pixel = (((int)-tu->jump_speed * ACTORMOVETICS)<<16)/tsp->xvel;
487         }
488     else
489         {
490         z_amt_per_pixel = (((int)-tsp->zvel)<<16)/tsp->xvel;
491         }
492 
493     switch (tu->motion_blur_dist)
494         {
495         case 64:
496             dx = nx = MOVEx(64, ang);
497             dy = ny = MOVEy(64, ang);
498             nz = (z_amt_per_pixel * 64)>>16;
499             break;
500         case 128:
501             dx = nx = MOVEx(128, ang);
502             dy = ny = MOVEy(128, ang);
503             nz = (z_amt_per_pixel * 128)>>16;
504             break;
505         case 256:
506             dx = nx = MOVEx(256, ang);
507             dy = ny = MOVEy(256, ang);
508             nz = (z_amt_per_pixel * 256)>>16;
509             break;
510         case 512:
511             dx = nx = MOVEx(512, ang);
512             dy = ny = MOVEy(512, ang);
513             nz = (z_amt_per_pixel * 512)>>16;
514             break;
515         default:
516             dx = nx = MOVEx(tu->motion_blur_dist, ang);
517             dy = ny = MOVEy(tu->motion_blur_dist, ang);
518             break;
519         }
520 
521     dz = nz;
522 
523     xrepeat = tsp->xrepeat;
524     yrepeat = tsp->yrepeat;
525 
526     switch (TEST(tu->Flags2, SPR2_BLUR_TAPER))
527         {
528         case 0:
529             repeat_adj = 0;
530             break;
531         case SPR2_BLUR_TAPER_SLOW:
532             repeat_adj = xrepeat / (tu->motion_blur_num*2);
533             break;
534         case SPR2_BLUR_TAPER_FAST:
535             repeat_adj = xrepeat / tu->motion_blur_num;
536             break;
537         }
538 
539     for (i = 0; i < tu->motion_blur_num; i++)
540         {
541         new = &tsprite[spritesortcnt];
542         memcpy(new, tsp, sizeof(SPRITE));
543         SET(new->cstat, CSTAT_SPRITE_TRANSLUCENT|CSTAT_SPRITE_TRANS_FLIP);
544 
545         new->x += dx;
546         new->y += dy;
547         dx += nx;
548         dy += ny;
549 
550         new->z += dz;
551         dz += nz;
552 
553         new->xrepeat = xrepeat;
554         new->yrepeat = yrepeat;
555 
556         xrepeat -= repeat_adj;
557         yrepeat -= repeat_adj;
558 
559         spritesortcnt++;
560         }
561 
562     }
563 
SetVoxelSprite(SPRITEp sp,short pic)564 VOID SetVoxelSprite(SPRITEp sp, short pic)
565     {
566     SET(sp->cstat, CSTAT_SPRITE_SLAB);
567     sp->picnum = pic;
568     }
569 
WarpCopySprite(VOID)570 VOID WarpCopySprite(VOID)
571     {
572     SPRITEp new, sp1, sp2, sp;
573     short sn, nsn;
574     short sn2, nsn2;
575     short spnum, next_spnum;
576     int xoff,yoff,zoff;
577     short match;
578     short sect1, sect2;
579 
580     // look for the first one
581     TRAVERSE_SPRITE_STAT(headspritestat[STAT_WARP_COPY_SPRITE1], sn, nsn)
582         {
583         sp1 = &sprite[sn];
584         match = sp1->lotag;
585 
586         // look for the second one
587         TRAVERSE_SPRITE_STAT(headspritestat[STAT_WARP_COPY_SPRITE2], sn2, nsn2)
588             {
589             sp = &sprite[sn2];
590 
591             if (sp->lotag == match)
592                 {
593                 sp2 = sp;
594                 sect1 = sp1->sectnum;
595                 sect2 = sp2->sectnum;
596 
597                 TRAVERSE_SPRITE_SECT(headspritesect[sect1], spnum, next_spnum)
598                     {
599                     if (&sprite[spnum] == sp1)
600                         continue;
601 
602                     if (sprite[spnum].picnum == ST1)
603                         continue;
604 
605                     new = &tsprite[spritesortcnt];
606                     memcpy(new, &sprite[spnum], sizeof(SPRITE));
607                     spritesortcnt++;
608                     new->owner = spnum;
609                     new->statnum = 0;
610 
611                     xoff = sp1->x - new->x;
612                     yoff = sp1->y - new->y;
613                     zoff = sp1->z - new->z;
614 
615                     new->x = sp2->x - xoff;
616                     new->y = sp2->y - yoff;
617                     new->z = sp2->z - zoff;
618                     new->sectnum = sp2->sectnum;
619                     }
620 
621                 TRAVERSE_SPRITE_SECT(headspritesect[sect2], spnum, next_spnum)
622                     {
623                     if (&sprite[spnum] == sp2)
624                         continue;
625 
626                     if (sprite[spnum].picnum == ST1)
627                         continue;
628 
629                     new = &tsprite[spritesortcnt];
630                     memcpy(new, &sprite[spnum], sizeof(SPRITE));
631                     spritesortcnt++;
632                     new->owner = spnum;
633                     new->statnum = 0;
634 
635                     xoff = sp2->x - new->x;
636                     yoff = sp2->y - new->y;
637                     zoff = sp2->z - new->z;
638 
639                     new->x = sp1->x - xoff;
640                     new->y = sp1->y - yoff;
641                     new->z = sp1->z - zoff;
642                     new->sectnum = sp1->sectnum;
643                     }
644                 }
645             }
646         }
647     }
648 
DoStarView(SPRITEp tsp,USERp tu,int viewz)649 VOID DoStarView(SPRITEp tsp, USERp tu, int viewz)
650     {
651     extern STATE s_Star[], s_StarDown[];
652     extern STATE s_StarStuck[], s_StarDownStuck[];
653     int zdiff = viewz - tsp->z;
654 
655     if (labs(zdiff) > Z(24))
656         {
657         if (tu->StateStart == s_StarStuck)
658             tsp->picnum = s_StarDownStuck[tu->State - s_StarStuck].Pic;
659         else
660             tsp->picnum = s_StarDown[tu->State - s_Star].Pic;
661 
662         if (zdiff > 0)
663             SET(tsp->cstat, CSTAT_SPRITE_YFLIP);
664         }
665     else
666         {
667         if (zdiff > 0)
668             SET(tsp->cstat, CSTAT_SPRITE_YFLIP);
669         }
670     }
671 
672 VOID
analyzesprites(int viewx,int viewy,int viewz,BOOL mirror)673 analyzesprites(int viewx, int viewy, int viewz, BOOL mirror)
674     {
675     int tSpriteNum, j, k;
676     short SpriteNum, pnum;
677     int smr4, smr2;
678     SPRITEp tsp;
679     USERp tu;
680     static int ang = 0;
681     PLAYERp pp = Player + screenpeek;
682     short newshade=0;
683 
684 
685     ang = NORM_ANGLE(ang + 12);
686 
687     smr4 = smoothratio + (((int) MoveSkip4) << 16);
688     smr2 = smoothratio + (((int) MoveSkip2) << 16);
689 
690     for (tSpriteNum = spritesortcnt - 1; tSpriteNum >= 0; tSpriteNum--)
691         {
692         SpriteNum = tsprite[tSpriteNum].owner;
693         tsp = &tsprite[tSpriteNum];
694         tu = User[SpriteNum];
695 
696         //if(tsp->statnum == STAT_GENERIC_QUEUE)
697         //    CON_ConMessage("tsp->pal = %d",tsp->pal);
698 
699         #if 0
700         // Brighten up the sprite if set somewhere else to do so
701         if (tu && tu->Vis > 0)
702             {
703             short tmpshade; // Having this prevent overflow
704 
705             tmpshade = tsp->shade  - tu->Vis;
706             if(tmpshade < -128) tmpshade = -128;
707 
708             tsp->shade = tmpshade;
709             tu->Vis -= 8;
710             }
711         #endif
712 
713         // don't draw these
714         if (tsp->statnum >= STAT_DONT_DRAW)
715             {
716             tsp->owner = -1;
717             continue;
718             }
719 
720         // Diss any parentally locked sprites
721         if(gs.ParentalLock || Global_PLock)
722         {
723         if(aVoxelArray[tsp->picnum].Parental == 6145)
724             {
725             tsp->owner = -1;
726             tu = NULL;
727             } else
728         if(aVoxelArray[tsp->picnum].Parental > 0)
729             {
730             ASSERT(aVoxelArray[tsp->picnum].Parental >= 0 && aVoxelArray[tsp->picnum].Parental < 6145);
731             tsp->picnum=aVoxelArray[tsp->picnum].Parental; // Change the pic
732             }
733         }
734 
735         if (tu)
736             {
737             if (tsp->statnum != STAT_DEFAULT)
738                 {
739                 if (TEST(tu->Flags, SPR_SKIP4))
740                     {
741                     if (tsp->statnum <= STAT_SKIP4_INTERP_END)
742                         {
743                         tsp->x = tu->ox + mulscale(tsp->x - tu->ox, smr4, 18);
744                         tsp->y = tu->oy + mulscale(tsp->y - tu->oy, smr4, 18);
745                         tsp->z = tu->oz + mulscale(tsp->z - tu->oz, smr4, 18);
746                         }
747                     }
748 
749                 if (TEST(tu->Flags, SPR_SKIP2))
750                     {
751                     if (tsp->statnum <= STAT_SKIP2_INTERP_END)
752                         {
753                         tsp->x = tu->ox + mulscale(tsp->x - tu->ox, smr2, 17);
754                         tsp->y = tu->oy + mulscale(tsp->y - tu->oy, smr2, 17);
755                         tsp->z = tu->oz + mulscale(tsp->z - tu->oz, smr2, 17);
756                         }
757                     }
758                 }
759 
760             if (gs.Shadows && TEST(tu->Flags, SPR_SHADOW))
761                 {
762                 DoShadows(tsp, viewz);
763                 }
764 
765             //#define UK_VERSION 1
766 
767             //#define DART_REPEAT 6
768             //#define DART_PIC 2233
769             if (useDarts)
770             if (tu->ID == 1793 || tsp->picnum == 1793)
771                 {
772                 tsp->picnum = 2519;
773                 tsp->xrepeat = 27;
774                 tsp->yrepeat = 29;
775                 }
776 
777             #define DART_PIC 2526
778             #define DART_REPEAT 16
779             if (tu->ID == STAR1)
780                 {
781 		if (useDarts)
782 		    {
783                     tsp->picnum = DART_PIC;
784                     tsp->ang = NORM_ANGLE(tsp->ang - 512 - 24);
785                     tsp->xrepeat = tsp->yrepeat = DART_REPEAT;
786                     SET(tsp->cstat, CSTAT_SPRITE_WALL);
787                     }
788 		else
789                     DoStarView(tsp, tu, viewz);
790                 }
791 
792             // rotation
793             if (tu->RotNum > 0)
794                 SetActorRotation(tSpriteNum, viewx, viewy);
795 
796             if (tu->motion_blur_num)
797                 {
798                 DoMotionBlur(tsp);
799                 }
800 
801             // set palette lookup correctly
802             if (tsp->pal != sector[tsp->sectnum].floorpal)
803                 {
804                 if (sector[tsp->sectnum].floorpal == PALETTE_DEFAULT)
805                     {
806                     // default pal for sprite is stored in tu->spal
807                     // mostly for players and other monster types
808                     tsp->pal = tu->spal;
809                     }
810                 else
811                     {
812                     // if sector pal is something other than default
813                     SECT_USERp sectu = SectUser[tsp->sectnum];
814                     BYTE pal = sector[tsp->sectnum].floorpal;
815                     BOOL nosectpal=FALSE;
816 
817                     // sprite does not take on the new pal if sector flag is set
818                     if (sectu && TEST(sectu->flags, SECTFU_DONT_COPY_PALETTE))
819                         {
820                         pal = PALETTE_DEFAULT;
821                         nosectpal = TRUE;
822                         }
823 
824                     //if(tu->spal == PALETTE_DEFAULT)
825                     if(tsp->hitag != SECTFU_DONT_COPY_PALETTE && tsp->hitag != LUMINOUS
826                             && !nosectpal
827                             && pal != PALETTE_FOG && pal != PALETTE_DIVE &&
828                             pal != PALETTE_DIVE_LAVA)
829                         tsp->pal = pal;
830                     else
831                         tsp->pal = tu->spal;
832 
833                     }
834                 }
835 
836             // Sprite debug information mode
837             if(tsp->hitag == 9997)
838                 {
839                 tsp->pal = PALETTE_RED_LIGHTING;
840                 // Turn it off, it gets reset by PrintSpriteInfo
841                 sprite[tu->SpriteNum].hitag = 0;
842                 }
843             }
844 
845 	if (useDarts)
846         if (tsp->statnum == STAT_STAR_QUEUE)
847             {
848             tsp->picnum = DART_PIC;
849             tsp->ang = NORM_ANGLE(tsp->ang - 512);
850             tsp->xrepeat = tsp->yrepeat = DART_REPEAT;
851             SET(tsp->cstat, CSTAT_SPRITE_WALL);
852             }
853 
854         // Call my sprite handler
855         // Does autosizing and voxel handling
856         JAnalyzeSprites(tsp);
857 
858         // only do this of you are a player sprite
859         //if (tsp->statnum >= STAT_PLAYER0 && tsp->statnum < STAT_PLAYER0 + MAX_SW_PLAYERS)
860         if (tu && tu->PlayerP)
861             {
862             // Shadow spell
863             if (!TEST(tsp->cstat, CSTAT_SPRITE_TRANSLUCENT))
864                 ShadeSprite(tsp);
865 
866             // sw if its your playersprite
867             //if ((Player + screenpeek)->PlayerSprite == SpriteNum)
868             if ((Player + screenpeek)->PlayerSprite == tu->SpriteNum)
869                 {
870                 PLAYERp pp = Player + screenpeek;
871                 if (mirror || TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE|PF_VIEW_FROM_CAMERA))
872                     {
873                     if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))
874                         SET(tsp->cstat, CSTAT_SPRITE_TRANSLUCENT);
875 
876                     if (TEST(pp->Flags, PF_CLIMBING))
877                         {
878                         // move sprite forward some so he looks like he's
879                         // climbing
880                         tsp->x = pp->six + MOVEx(128 + 80, tsp->ang);
881                         tsp->y = pp->siy + MOVEy(128 + 80, tsp->ang);
882                         }
883                     else
884                         {
885                         tsp->x = pp->six;
886                         tsp->y = pp->siy;
887                         }
888 
889                     tsp->z = tsp->z + pp->siz;
890                     tsp->ang = pp->siang;
891                     //continue;
892                     }
893                 else
894                     {
895                     // dont draw your sprite
896                     tsp->owner = -1;
897                     //SET(tsp->cstat, CSTAT_SPRITE_INVISIBLE);
898                     }
899                 }
900             }
901 
902         if (OverlapDraw && FAF_ConnectArea(tsp->sectnum) && tsp->owner >= 0)
903             {
904             ConnectCopySprite(tsp);
905             }
906 
907         //
908         // kens original sprite shade code he moved out of the engine
909         //
910 
911         switch (tsp->statnum)
912             {
913             case STAT_ENEMY:
914             case STAT_DEAD_ACTOR:
915             case STAT_FAF_COPY:
916                 break;
917             default:
918                 newshade = tsp->shade;
919                 newshade += 6;
920                 if (newshade > 127) newshade = 127;
921                 tsp->shade = newshade;
922             }
923 
924         if (TEST(sector[tsp->sectnum].ceilingstat, CEILING_STAT_PLAX))
925             {
926             newshade = tsp->shade;
927             newshade += sector[tsp->sectnum].ceilingshade;
928             if (newshade > 127) newshade = 127;
929             if (newshade < -128) newshade = -128;
930             tsp->shade = newshade;
931             }
932         else
933             {
934             newshade = tsp->shade;
935             newshade += sector[tsp->sectnum].floorshade;
936             if (newshade > 127) newshade = 127;
937             if (newshade < -128) newshade = -128;
938             tsp->shade = newshade;
939             }
940 
941             if(tsp->hitag == 9998)
942                 tsp->shade = 127; // Invisible enemy ninjas
943 
944             // Correct shades for luminous sprites
945             if(tsp->hitag == LUMINOUS)
946                 {
947                 tsp->shade = -128;
948                 }
949 
950             if(pp->NightVision && TEST(tsp->extra, SPRX_PLAYER_OR_ENEMY))
951             {
952                 if(tu && tu->ID == TRASHCAN) continue; // Don't light up trashcan
953 
954                 tsp->pal = PALETTE_ILLUMINATE;  // Make sprites REALLY bright green.
955                 tsp->shade = -128;
956             }
957 
958         if (tu && tu->PlayerP)
959             {
960             if (TEST(tu->Flags2, SPR2_VIS_SHADING))
961                 {
962                 if ((Player + screenpeek)->PlayerSprite != tu->SpriteNum)
963                     {
964                     if (!TEST(tu->PlayerP->Flags, PF_VIEW_FROM_OUTSIDE))
965                         {
966                         RESET(tsp->cstat, CSTAT_SPRITE_TRANSLUCENT);
967                         }
968                     }
969 
970                 tsp->shade = 12 - STD_RANDOM_RANGE(30);
971                 }
972             }
973         }
974 
975     WarpCopySprite();
976 
977     }
978 
979 #if 1
980 SPRITEp
get_tsprite(short SpriteNum)981 get_tsprite(short SpriteNum)
982     {
983     int tSpriteNum;
984 
985     for (tSpriteNum = spritesortcnt - 1; tSpriteNum >= 0; tSpriteNum--)
986         {
987         if (tsprite[tSpriteNum].owner == SpriteNum)
988             return(&tsprite[tSpriteNum]);
989         }
990 
991     return(NULL);
992     }
993 
994 VOID
post_analyzesprites(void)995 post_analyzesprites(void)
996     {
997     int tSpriteNum;
998     short SpriteNum;
999     SPRITEp tsp;
1000     USERp tu;
1001 
1002     for (tSpriteNum = spritesortcnt - 1; tSpriteNum >= 0; tSpriteNum--)
1003         {
1004         SpriteNum = tsprite[tSpriteNum].owner;
1005 	if (SpriteNum < 0) continue;	// JBF: verify this is safe
1006         tsp = &tsprite[tSpriteNum];
1007         tu = User[SpriteNum];
1008 
1009         if (tu)
1010             {
1011             if (tu->ID == FIREBALL_FLAMES && tu->Attach >= 0)
1012                 {
1013                 //SPRITEp atsp = &sprite[tu->Attach];
1014                 SPRITEp atsp;
1015 
1016                 atsp = get_tsprite(tu->Attach);
1017 
1018                 if (!atsp)
1019                     {
1020                     //DSPRINTF(ds,"Attach not found");
1021                     MONO_PRINT(ds);
1022                     continue;
1023                     }
1024 
1025                 tsp->x = atsp->x;
1026                 tsp->y = atsp->y;
1027                 // statnum is priority - draw this ALWAYS first at 0
1028                 // statnum is priority - draw this ALWAYS last at MAXSTATUS
1029                 if (TEST(atsp->extra, SPRX_BURNABLE))
1030                     {
1031                     atsp->statnum = 1;
1032                     tsp->statnum = 0;
1033                     }
1034                 else
1035                     tsp->statnum = MAXSTATUS;
1036                 }
1037             }
1038         }
1039     }
1040 #endif
1041 
1042 VOID
ResizeView(PLAYERp pp)1043 ResizeView(PLAYERp pp)
1044     {
1045    if (MenuInputMode || InputMode || HelpInputMode || ConPanel || ConInputMode || PauseKeySet)
1046        return;
1047 
1048     if (dimensionmode == 2 || dimensionmode == 5 || dimensionmode == 6)
1049         {
1050         if (PKEY_PRESSED(KEYSC_DASH)||PKEY_PRESSED(KEYSC_GMINUS))
1051             {
1052             if((zoom -= (zoom >> 4)) < 48) zoom = 48;
1053             }
1054 
1055         if (PKEY_PRESSED(KEYSC_EQUAL)||PKEY_PRESSED(KEYSC_GPLUS))
1056             {
1057             if((zoom += (zoom >> 4)) > 4096) zoom = 4096;
1058             }
1059 
1060         if (KEY_PRESSED(KEYSC_ESC))
1061             {
1062             extern BOOL ScrollMode2D;
1063 
1064             KEY_PRESSED(KEYSC_ESC) = 0;
1065             dimensionmode = 3;
1066             ScrollMode2D = FALSE;
1067             SetRedrawScreen(pp);
1068             }
1069         }
1070     else
1071         {
1072         if (BUTTON(gamefunc_Shrink_Screen))      // &&
1073                                                 // !BUTTONHELD(gamefunc_SizeVi
1074                                                 // ewDown))
1075             {
1076             CONTROL_ClearButton(gamefunc_Shrink_Screen);
1077             SetBorder(pp, gs.BorderNum + 1);
1078             SetRedrawScreen(pp);
1079             }
1080 
1081         if (BUTTON(gamefunc_Enlarge_Screen))// &&
1082                                         // !BUTTONHELD(gamefunc_SizeViewUp))
1083             {
1084             CONTROL_ClearButton(gamefunc_Enlarge_Screen);
1085             SetBorder(pp, gs.BorderNum - 1);
1086             SetRedrawScreen(pp);
1087             }
1088         }
1089     }
1090 
1091 // !JIM! 08/06
1092 extern BOOL UsingMenus;
1093 
1094 #if 0
1095 VOID
1096 ViewOutsidePlayerRecurse(PLAYERp pp, LONGp vx, LONGp vy, LONGp vz, SHORTp ang, SHORTp vsectnum)
1097     {
1098     int nx, ny;
1099     int ret;
1100 
1101     *vx = pp->posx;
1102     *vy = pp->posy;
1103     *vz = pp->posz;
1104     *vsectnum = pp->cursectnum;
1105 
1106     *ang = pp->pang + pp->view_outside_dang;
1107 
1108     nx = sintable[NORM_ANGLE(*ang + 512 + 1024)] << 11;
1109     ny = sintable[NORM_ANGLE(*ang + 1024)] << 11;
1110 
1111     ret = clipmove(vx, vy, vz, vsectnum, nx, ny, 64L, 4 << 8, 4 << 8, CLIPMASK_PLAYER);
1112 
1113     switch (TEST(ret, HIT_MASK))
1114         {
1115     case HIT_SPRITE:
1116             {
1117             short hitsprite;
1118             SPRITEp sp;
1119 
1120             hitsprite = NORM_SPRITE(ret);
1121             sp = &sprite[hitsprite];
1122 
1123             // if you hit a sprite that's not a wall sprite - try again
1124             if (!TEST(sp->cstat, CSTAT_SPRITE_WALL))
1125                 {
1126                 FLIP(sp->cstat, CSTAT_SPRITE_BLOCK);
1127                 ViewOutsidePlayerRecurse(pp, vx, vy, vz, ang, vsectnum);
1128                 FLIP(sp->cstat, CSTAT_SPRITE_BLOCK);
1129                 }
1130 
1131             break;
1132             }
1133         }
1134 
1135     if (TEST(sector[*vsectnum].floorstat, FLOOR_STAT_SLOPE)|TEST(sector[*vsectnum].ceilingstat, CEILING_STAT_SLOPE))
1136         {
1137         int cz, fz;
1138 
1139         getzsofslope(*vsectnum, *vx, *vy, &cz, &fz);
1140 
1141         if (*vz > fz - Z(12))
1142             *vz = fz - Z(12);
1143 
1144         if (*vz < cz + Z(12))
1145             *vz = cz + Z(12);
1146 
1147         }
1148     }
1149 #endif
1150 
1151 
1152 
1153 void
BackView(int * nx,int * ny,int * nz,short * vsect,short * nang,short horiz)1154 BackView(int *nx, int *ny, int *nz, short *vsect, short *nang, short horiz)
1155     {
1156     SPRITEp sp;
1157     int i, vx, vy, vz, hx, hy, hz, hitx, hity, hitz;
1158     short bakcstat, hitsect, hitwall, hitsprite, daang;
1159     PLAYERp pp = &Player[screenpeek];
1160     short ang;
1161 
1162     ASSERT(*vsect >= 0 && *vsect < MAXSECTORS);
1163 
1164     ang = *nang + pp->view_outside_dang;
1165 
1166     // Calculate the vector (nx,ny,nz) to shoot backwards
1167     vx = (sintable[NORM_ANGLE(ang + 1536)] >> 3);
1168     vy = (sintable[NORM_ANGLE(ang + 1024)] >> 3);
1169     vz = (horiz - 100) * 256L;
1170 
1171     // Player sprite of current view
1172     sp = &sprite[pp->PlayerSprite];
1173 
1174     bakcstat = sp->cstat;
1175     RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
1176 
1177     // Make sure sector passed to FAFhitscan is correct
1178     //COVERupdatesector(*nx, *ny, vsect);
1179 
1180     hitscan(*nx, *ny, *nz, *vsect, vx, vy, vz,
1181         &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK_PLAYER);
1182 
1183     ASSERT(*vsect >= 0 && *vsect < MAXSECTORS);
1184 
1185     sp->cstat = bakcstat;              // Restore cstat
1186 
1187     hx = hitx - (*nx);
1188     hy = hity - (*ny);
1189 
1190     // If something is in the way, make pp->camera_dist lower if necessary
1191     if (klabs(vx) + klabs(vy) > klabs(hx) + klabs(hy))
1192         {
1193         if (hitwall >= 0)               // Push you a little bit off the wall
1194             {
1195             *vsect = hitsect;
1196 
1197             daang = getangle(wall[wall[hitwall].point2].x - wall[hitwall].x,
1198                 wall[wall[hitwall].point2].y - wall[hitwall].y);
1199 
1200             i = vx * sintable[daang] + vy * sintable[NORM_ANGLE(daang + 1536)];
1201             if (klabs(vx) > klabs(vy))
1202                 hx -= mulscale28(vx, i);
1203             else
1204                 hy -= mulscale28(vy, i);
1205             }
1206         else
1207         if (hitsprite < 0)         // Push you off the ceiling/floor
1208             {
1209             *vsect = hitsect;
1210 
1211             if (klabs(vx) > klabs(vy))
1212                 hx -= (vx >> 5);
1213             else
1214                 hy -= (vy >> 5);
1215             }
1216         else
1217             {
1218             SPRITEp hsp = &sprite[hitsprite];
1219             int flag_backup;
1220 
1221             // if you hit a sprite that's not a wall sprite - try again
1222             if (!TEST(hsp->cstat, CSTAT_SPRITE_WALL))
1223                 {
1224                 flag_backup = hsp->cstat;
1225                 RESET(hsp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
1226                 ASSERT(*vsect >= 0 && *vsect < MAXSECTORS);
1227                 BackView(nx, ny, nz, vsect, nang, horiz);
1228                 hsp->cstat = flag_backup;
1229                 return;
1230                 }
1231             else
1232                 {
1233                 // same as wall calculation
1234                 daang = NORM_ANGLE(sp->ang-512);
1235 
1236                 i = vx * sintable[daang] + vy * sintable[NORM_ANGLE(daang + 1536)];
1237                 if (klabs(vx) > klabs(vy))
1238                     hx -= mulscale28(vx, i);
1239                 else
1240                     hy -= mulscale28(vy, i);
1241                 }
1242 
1243             }
1244 
1245         if (klabs(vx) > klabs(vy))
1246             i = (hx << 16) / vx;
1247         else
1248             i = (hy << 16) / vy;
1249 
1250         if (i < pp->camera_dist)
1251             pp->camera_dist = i;
1252         }
1253 
1254     // Actually move you!  (Camerdist is 65536 if nothing is in the way)
1255     *nx = (*nx) + mulscale16(vx, pp->camera_dist);
1256     *ny = (*ny) + mulscale16(vy, pp->camera_dist);
1257     *nz = (*nz) + mulscale16(vz, pp->camera_dist);
1258 
1259     // Slowly increase pp->camera_dist until it reaches 65536
1260     // Synctics is a timer variable so it increases the same rate
1261     // on all speed computers
1262     pp->camera_dist = min(pp->camera_dist + (3 << 10), 65536);
1263     //pp->camera_dist = min(pp->camera_dist + (synctics << 10), 65536);
1264 
1265     // Make sure vsect is correct
1266     updatesectorz(*nx, *ny, *nz, vsect);
1267 
1268     *nang = ang;
1269     }
1270 
1271 void
CircleCamera(int * nx,int * ny,int * nz,short * vsect,short * nang,short horiz)1272 CircleCamera(int *nx, int *ny, int *nz, short *vsect, short *nang, short horiz)
1273     {
1274     SPRITEp sp;
1275     int i, vx, vy, vz, hx, hy, hz, hitx, hity, hitz;
1276     short bakcstat, hitsect, hitwall, hitsprite, daang;
1277     PLAYERp pp = &Player[screenpeek];
1278     short ang;
1279 
1280     ang = *nang + pp->circle_camera_ang;
1281 
1282     // Calculate the vector (nx,ny,nz) to shoot backwards
1283     vx = (sintable[NORM_ANGLE(ang + 1536)] >> 4);
1284     vy = (sintable[NORM_ANGLE(ang + 1024)] >> 4);
1285 
1286     // lengthen the vector some
1287     vx += DIV2(vx);
1288     vy += DIV2(vy);
1289 
1290     vz = (horiz - 100) * 256;
1291 
1292     // Player sprite of current view
1293     sp = &sprite[pp->PlayerSprite];
1294 
1295     bakcstat = sp->cstat;
1296     RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
1297 
1298     // Make sure sector passed to hitscan is correct
1299     //COVERupdatesector(*nx, *ny, vsect);
1300 
1301     hitscan(*nx, *ny, *nz, *vsect, vx, vy, vz,
1302         &hitsect, &hitwall, &hitsprite, &hitx, &hity, &hitz, CLIPMASK_MISSILE);
1303 
1304     sp->cstat = bakcstat;              // Restore cstat
1305     //ASSERT(hitsect >= 0);
1306 
1307     hx = hitx - (*nx);
1308     hy = hity - (*ny);
1309 
1310     // If something is in the way, make pp->circle_camera_dist lower if necessary
1311     if (klabs(vx) + klabs(vy) > klabs(hx) + klabs(hy))
1312         {
1313         if (hitwall >= 0)               // Push you a little bit off the wall
1314             {
1315             *vsect = hitsect;
1316 
1317             daang = getangle(wall[wall[hitwall].point2].x - wall[hitwall].x,
1318                 wall[wall[hitwall].point2].y - wall[hitwall].y);
1319 
1320             i = vx * sintable[daang] + vy * sintable[NORM_ANGLE(daang + 1536)];
1321             if (klabs(vx) > klabs(vy))
1322                 hx -= mulscale28(vx, i);
1323             else
1324                 hy -= mulscale28(vy, i);
1325             }
1326         else
1327         if (hitsprite < 0)         // Push you off the ceiling/floor
1328             {
1329             *vsect = hitsect;
1330 
1331             if (klabs(vx) > klabs(vy))
1332                 hx -= (vx >> 5);
1333             else
1334                 hy -= (vy >> 5);
1335             }
1336         else
1337             {
1338             SPRITEp hsp = &sprite[hitsprite];
1339             int flag_backup;
1340 
1341             // if you hit a sprite that's not a wall sprite - try again
1342             if (!TEST(hsp->cstat, CSTAT_SPRITE_WALL))
1343                 {
1344                 flag_backup = hsp->cstat;
1345                 RESET(hsp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
1346 
1347                 CircleCamera(nx, ny, nz, vsect, nang, horiz);
1348                 hsp->cstat = flag_backup;
1349                 return;
1350                 }
1351             }
1352 
1353         if (klabs(vx) > klabs(vy))
1354             i = (hx << 16) / vx;
1355         else
1356             i = (hy << 16) / vy;
1357 
1358         if (i < pp->circle_camera_dist)
1359             pp->circle_camera_dist = i;
1360         }
1361 
1362     // Actually move you!  (Camerdist is 65536 if nothing is in the way)
1363     *nx = (*nx) + ((vx * pp->circle_camera_dist) >> 16);
1364     *ny = (*ny) + ((vy * pp->circle_camera_dist) >> 16);
1365     *nz = (*nz) + ((vz * pp->circle_camera_dist) >> 16);
1366 
1367     // Slowly increase pp->circle_camera_dist until it reaches 65536
1368     // Synctics is a timer variable so it increases the same rate
1369     // on all speed computers
1370     pp->circle_camera_dist = min(pp->circle_camera_dist + (3 << 8), 65536);
1371     //pp->circle_camera_dist = min(pp->circle_camera_dist + (synctics << 10), 65536);
1372 
1373     // Make sure vsect is correct
1374     updatesectorz(*nx, *ny, *nz, vsect);
1375 
1376     *nang = ang;
1377     }
1378 
PrintLocationInfo(PLAYERp pp)1379 VOID PrintLocationInfo(PLAYERp pp)
1380   {
1381     #define Y_STEP 7
1382     #define AVERAGEFRAMES 16
1383     int x = windowx1+2;
1384     int y = windowy1+2;
1385     static int frameval[AVERAGEFRAMES], framecnt = 0;
1386     int i;
1387 
1388     if (LocationInfo)
1389         {
1390 
1391         i = totalclock;
1392         if (i != frameval[framecnt])
1393             {
1394             sprintf(tempbuf, "FPS: %d", ((120 * AVERAGEFRAMES) / (i - frameval[framecnt])) + f_c);
1395             printext256(x, y, 1, -1, tempbuf, 1);
1396             frameval[framecnt] = i;
1397             }
1398 
1399         framecnt = ((framecnt + 1) & (AVERAGEFRAMES - 1));
1400 
1401         if (LocationInfo > 1)
1402             {
1403             y += Y_STEP;
1404 
1405             sprintf(buffer, "POSX:%d", pp->posx);
1406             printext256(x, y, 1, -1, buffer, 1);
1407             y += Y_STEP;
1408             sprintf(buffer, "POSY:%d", pp->posy);
1409             printext256(x, y, 1, -1, buffer, 1);
1410             y += Y_STEP;
1411             sprintf(buffer, "POSZ:%d", pp->posz);
1412             printext256(x, y, 1, -1, buffer, 1);
1413             y += Y_STEP;
1414             sprintf(buffer, "ANG:%d", (LONG) pp->pang);
1415             printext256(x, y, 1, -1, buffer, 1);
1416             y += Y_STEP;
1417             }
1418         }
1419     }
1420 
1421 BOOL DebugSecret = FALSE;
SecretInfo(PLAYERp pp)1422 VOID SecretInfo(PLAYERp pp)
1423     {
1424     #define Y_STEP 7
1425     #define AVERAGEFRAMES 16
1426     int x = windowx1+2;
1427     int y = windowy1+2+8;
1428     extern short LevelSecrets,TotalKillable;
1429 
1430     if (CommEnabled || CommPlayers > 1)
1431         return;
1432 
1433     x = x / (xdim/320.0);
1434     y = y / (ydim/200.0);
1435 
1436     if (gs.Stats)
1437         {
1438         sprintf(ds, "Kills %d/%d", Player->Kills, TotalKillable);
1439         DisplayMiniBarSmString(pp, x, y, PAL_XLAT_BROWN, ds);
1440 
1441         sprintf(ds, "Secrets %d/%d", Player->SecretsFound, LevelSecrets);
1442         DisplayMiniBarSmString(pp, x, y+10, PAL_XLAT_BROWN, ds);
1443         }
1444     }
1445 
PrintSpriteInfo(PLAYERp pp)1446 VOID PrintSpriteInfo(PLAYERp pp)
1447   {
1448     #define Y_STEP 7
1449     int x = windowx1+2;
1450     int y = windowy1+2;
1451     SPRITEp sp;
1452     USERp u;
1453     short hitsprite;
1454 
1455     if (SpriteInfo && !LocationInfo)
1456         {
1457         hitsprite = DoPickTarget(pp->SpriteP, 32, 2);
1458 
1459         sp = &sprite[hitsprite];
1460         u = User[hitsprite];
1461 
1462         sp->hitag = 9997; // Special tag to make the actor glow red for one frame
1463 
1464         y += Y_STEP;
1465 
1466         if(hitsprite == -1)
1467             {
1468             sprintf(buffer, "SPRITENUM: NONE TARGETED");
1469             printext256(x, y, 1, -1, buffer, 1);
1470             return;
1471             } else
1472             sprintf(buffer, "SPRITENUM:%d", hitsprite);
1473 
1474         printext256(x, y, 1, -1, buffer, 1);
1475         y += Y_STEP;
1476         if(u)
1477             {
1478             sprintf(buffer, "ID:%d", u->ID);
1479             printext256(x, y, 1, -1, buffer, 1);
1480             y += Y_STEP;
1481             sprintf(buffer, "PALETTE:%d", u->spal);
1482             printext256(x, y, 1, -1, buffer, 1);
1483             y += Y_STEP;
1484             sprintf(buffer, "HEALTH:%d", u->Health);
1485             printext256(x, y, 1, -1, buffer, 1);
1486             y += Y_STEP;
1487             sprintf(buffer, "WAITTICS:%d", u->WaitTics);
1488             printext256(x, y, 1, -1, buffer, 1);
1489             y += Y_STEP;
1490             sprintf(buffer, "COUNTER:%d", u->Counter);
1491             printext256(x, y, 1, -1, buffer, 1);
1492             y += Y_STEP;
1493             sprintf(buffer, "COUNTER2:%d", u->Counter);
1494             printext256(x, y, 1, -1, buffer, 1);
1495             y += Y_STEP;
1496             }
1497         if(SpriteInfo > 1)
1498             {
1499             sprintf(buffer, "POSX:%d", sp->x);
1500             printext256(x, y, 1, -1, buffer, 1);
1501             y += Y_STEP;
1502             sprintf(buffer, "POSY:%d", sp->y);
1503             printext256(x, y, 1, -1, buffer, 1);
1504             y += Y_STEP;
1505             sprintf(buffer, "POSZ:%d", sp->z);
1506             printext256(x, y, 1, -1, buffer, 1);
1507             y += Y_STEP;
1508             sprintf(buffer, "ANG:%d", (LONG) sp->ang);
1509             printext256(x, y, 1, -1, buffer, 1);
1510             y += Y_STEP;
1511             }
1512         }
1513     }
1514 
1515 
SpriteSortList2D(int tx,int ty)1516 VOID SpriteSortList2D(int tx, int ty)
1517     {
1518     SPRITEp sp;
1519     int i;
1520     int dist,a,b,c;
1521 
1522     spritesortcnt = 0;
1523     for (i = 0; i < MAXSPRITES; i++)
1524         {
1525         if (sprite[i].statnum < MAXSTATUS)
1526             {
1527             sp = &sprite[i];
1528 
1529             if (!TEST(sp->cstat, CSTAT_SPRITE_INVISIBLE) &&
1530                 (sp->xrepeat > 0) && (sp->yrepeat > 0) &&
1531                 (spritesortcnt < MAXSPRITESONSCREEN))
1532                 {
1533                 DISTANCE(tx,ty,sp->x,sp->y,dist,a,b,c);
1534 
1535                 if (dist < 22000)
1536                     {                   memcpy(&tsprite[spritesortcnt], sp, sizeof(SPRITE));
1537                     tsprite[spritesortcnt++].owner = i;
1538                     }
1539                 }
1540             }
1541         }
1542     }
1543 
COVERsetgamemode(int mode,int xdim,int ydim,int bpp)1544 int COVERsetgamemode(int mode, int xdim, int ydim, int bpp)
1545     {
1546     extern int ScreenHeight, ScreenWidth, ScreenMode, ScreenBPP;
1547 
1548 
1549     ScreenHeight = ydim;
1550     ScreenWidth  = xdim;
1551     ScreenMode   = mode;
1552     ScreenBPP    = bpp;
1553 
1554     return((int)setgamemode(mode,xdim,ydim,bpp));
1555       }
1556 
VideoRestart(void)1557 void VideoRestart(void)
1558     {
1559     resetvideomode();
1560     if (COVERsetgamemode(NewVideoMode.fs, NewVideoMode.x, NewVideoMode.y, NewVideoMode.bpp))
1561         buildputs("video restart failed\n");
1562 
1563     SetupAspectRatio();
1564     SetRedrawScreen(Player + myconnectindex);
1565     }
1566 
1567 #if 0
1568 void CheatResChange(void)
1569     {
1570     extern char permanentupdate;
1571     int i;
1572 
1573     // needs to be called from drawscreen - crashes otherwise
1574 
1575     //cycle through all vesa modes, then screen-buffer mode
1576     if (vidoption == 1)
1577         {
1578         for(i=0;i < validmodecnt;i++)
1579             {
1580             if ((validmodexdim[i] == xdim) && (validmodeydim[i] == ydim))
1581                 {
1582                 if (i == validmodecnt-1)
1583                     COVERsetgamemode(2,320L,200L);
1584                 else
1585                     COVERsetgamemode(1,validmodexdim[i+1],validmodeydim[i+1]);
1586                 break;
1587                 }
1588             }
1589         }
1590     else
1591         {
1592         if (validmodecnt > 0)
1593             COVERsetgamemode(1,validmodexdim[0],validmodeydim[0]);
1594         }
1595 
1596     permanentupdate = 0;
1597 
1598     SetupAspectRatio();
1599     SetRedrawScreen(Player + myconnectindex);
1600 
1601     sprintf(ds,"%d x %d mode selected.", xdim, ydim);
1602     PutStringInfo(Player + myconnectindex, ds);
1603 }
1604 
1605 void ResChange(void)
1606     {
1607     extern char permanentupdate;
1608     int i;
1609 
1610     static short sw_res[5];
1611     static short res_ndx=0;
1612 
1613     // clear pages before and after res set for good measure
1614     for (i = 0; i < numpages; i++)
1615         {
1616         clearview(0);
1617         nextpage();
1618         }
1619 
1620     // needs to be called from drawscreen - crashes otherwise
1621 
1622     if (res_ndx == 0)
1623         {
1624         // choose resolutions for shadow warrior
1625         for(i=0; i < validmodecnt; i++)
1626             {
1627             if (validmodexdim[i] + validmodeydim[i] == 320 + 200)
1628                 sw_res[res_ndx++] = i;
1629             else
1630             if (validmodexdim[i] + validmodeydim[i] == 640 + 400)
1631                 sw_res[res_ndx++] = i;
1632             else
1633             if (validmodexdim[i] + validmodeydim[i] == 640 + 480)
1634                 sw_res[res_ndx++] = i;
1635             else
1636             if (validmodexdim[i] + validmodeydim[i] == 800 + 600)
1637                 sw_res[res_ndx++] = i;
1638             }
1639         }
1640 
1641     //cycle through all sw modes, then screen-buffer mode
1642     if (vidoption == 1)
1643         {
1644         for(i = 0; i < res_ndx; i++)
1645             {
1646             if ((validmodexdim[sw_res[i]] == xdim) && (validmodeydim[sw_res[i]] == ydim))
1647                 {
1648                 if (i >= res_ndx-1)
1649                     COVERsetgamemode(2, 320L, 200L);
1650                 else
1651                     COVERsetgamemode(1, validmodexdim[sw_res[i+1]], validmodeydim[sw_res[i+1]]);
1652                 break;
1653                 }
1654             }
1655 
1656 
1657         // if did not find current res then reset to 320x200
1658         if (i >= res_ndx)
1659             COVERsetgamemode(2, 320L, 200L);
1660         }
1661     else
1662         {
1663         if (validmodecnt > 0)
1664             COVERsetgamemode(1, validmodexdim[0], validmodeydim[0]);
1665         }
1666 
1667     permanentupdate = 0;
1668 
1669     for (i = 0; i < numpages; i++)
1670         {
1671         clearview(0);
1672         nextpage();
1673         }
1674 
1675     SetupAspectRatio();
1676     SetRedrawScreen(Player + myconnectindex);
1677 
1678     sprintf(ds,"%d x %d mode selected.", xdim, ydim);
1679     PutStringInfo(Player + myconnectindex, ds);
1680 }
1681 #endif
1682 
ScreenCaptureKeys(VOID)1683 VOID ScreenCaptureKeys(VOID)
1684     {
1685     if (ConPanel)
1686         return;
1687 
1688     // screen capture
1689     if (ScreenDidCapture)
1690         {
1691         PutStringInfo(Player + myconnectindex, "Screen Captured");
1692         ScreenDidCapture = FALSE;
1693         }
1694     if (KEY_PRESSED(KEYSC_F12))
1695         {
1696         KEY_PRESSED(KEYSC_F12) = 0;
1697         PauseAction();
1698         screencapture("swcpxxxx.pcx", 2);
1699         ResumeAction();
1700         ScreenDidCapture = TRUE;
1701         }
1702     }
1703 
DrawCheckKeys(PLAYERp pp)1704 VOID DrawCheckKeys(PLAYERp pp)
1705     {
1706     extern BOOL ResCheat;
1707     extern BOOL PauseKeySet;
1708 
1709     /* JonoF: Who really needs this now?
1710     if (KEY_PRESSED(KEYSC_F5) && !(KEY_PRESSED(KEYSC_RSHIFT) || KEY_PRESSED(KEYSC_LSHIFT) || KEY_PRESSED(KEYSC_ALT) || KEY_PRESSED(KEYSC_RALT)) && !PauseKeySet)
1711         {
1712         KEY_PRESSED(KEYSC_F5) = 0;
1713         ResChange();
1714         }
1715 
1716     if (ResCheat)
1717         {
1718         ResCheat = FALSE;
1719         CheatResChange(); // allow all modes when cheating
1720         }
1721     */
1722 
1723     if (RestartVideo)
1724         {
1725         RestartVideo = FALSE;
1726         VideoRestart();
1727         }
1728 
1729     if (ConPanel) return;
1730 
1731     if (!InputMode)
1732         ResizeView(pp);
1733 
1734     ScreenCaptureKeys();
1735     }
1736 
1737 #if 0
1738 VOID DrawMessageInput(PLAYERp pp)
1739     {
1740     short w,h;
1741     static BOOL cur_show;
1742     short c;
1743 
1744     // Used to make cursor fade in and out
1745     c = 4-(sintable[(totalclock<<4)&2047]>>11);
1746 
1747     if (MessageInputMode)
1748         {
1749         MNU_MeasureString(MessageInputString, &w, &h);
1750 
1751         cur_show ^= 1;
1752         if (cur_show)
1753             {
1754             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,1,ROTATE_SPRITE_SCREEN_CLIP);
1755             rotatesprite((TEXT_XCENTER(w)+w+7)<<16,(MESSAGE_LINE+3)<<16,64<<9,0,COINCURSOR+((totalclock>>3)%7),c,0,
1756             (ROTATE_SPRITE_SCREEN_CLIP),0,0,xdim-1,ydim-1);
1757             }
1758         else
1759             {
1760             MNU_DrawString(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,1,ROTATE_SPRITE_SCREEN_CLIP);
1761             rotatesprite((TEXT_XCENTER(w)+w+7)<<16,(MESSAGE_LINE+3)<<16,64<<9,0,COINCURSOR+((totalclock>>3)%7),c,0,
1762             (ROTATE_SPRITE_SCREEN_CLIP),0,0,xdim-1,ydim-1);
1763             }
1764         }
1765     }
1766 #else
DrawMessageInput(PLAYERp UNUSED (pp))1767 VOID DrawMessageInput(PLAYERp UNUSED(pp))
1768     {
1769     short w,h;
1770     static BOOL cur_show;
1771     short c;
1772 
1773     // Used to make cursor fade in and out
1774     c = 4-(sintable[(totalclock<<4)&2047]>>11);
1775 
1776     if (MessageInputMode)
1777         {
1778         MNU_MeasureSmallString(MessageInputString, &w, &h);
1779 
1780         cur_show ^= 1;
1781         if (cur_show)
1782             {
1783             minigametext(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,0,ROTATE_SPRITE_SCREEN_CLIP);
1784             rotatesprite((TEXT_XCENTER(w)+w+2)<<16,(MESSAGE_LINE+1)<<16,20000,0,COINCURSOR+((totalclock>>3)%7),c,0,ROTATE_SPRITE_SCREEN_CLIP,0,0,xdim-1,ydim-1);
1785             }
1786         else
1787             {
1788             minigametext(TEXT_XCENTER(w), MESSAGE_LINE, MessageInputString,0,ROTATE_SPRITE_SCREEN_CLIP);
1789             rotatesprite((TEXT_XCENTER(w)+w+2)<<16,(MESSAGE_LINE+1)<<16,20000,0,COINCURSOR+((totalclock>>3)%7),c,0,ROTATE_SPRITE_SCREEN_CLIP,0,0,xdim-1,ydim-1);
1790             }
1791         }
1792     }
1793 #endif
1794 
DrawConInput(PLAYERp UNUSED (pp))1795 VOID DrawConInput(PLAYERp UNUSED(pp))
1796     {
1797     #define PANELINPUTX 30
1798     #define PANELINPUTY 100
1799     short w,h;
1800     static BOOL cur_show;
1801     short c;
1802 
1803     // Used to make cursor fade in and out
1804     c = 4-(sintable[(totalclock<<4)&2047]>>11);
1805 
1806     if (ConInputMode)
1807         {
1808         MNU_MeasureSmallString(MessageInputString, &w, &h);
1809 
1810         cur_show ^= 1;
1811         if (cur_show)
1812             {
1813             MNU_DrawSmallString(PANELINPUTX, PANELINPUTY, MessageInputString,1,17);
1814             rotatesprite((PANELINPUTX+w+1)<<16,(PANELINPUTY)<<16,65536L,0,2992,c,0,ROTATE_SPRITE_SCREEN_CLIP,0,0,xdim-1,ydim-1);
1815             //rotatesprite((PANELINPUTX+w+3)<<16,(PANELINPUTY)<<16,64<<8,0,COINCURSOR+((totalclock>>3)%7),c,0,ROTATE_SPRITE_SCREEN_CLIP,0,0,xdim-1,ydim-1);
1816             }
1817         else
1818             {
1819             MNU_DrawSmallString(PANELINPUTX, PANELINPUTY, MessageInputString,1,17);
1820             rotatesprite((PANELINPUTX+w+1)<<16,(PANELINPUTY)<<16,65536L,0,2992,c,0,ROTATE_SPRITE_SCREEN_CLIP,0,0,xdim-1,ydim-1);
1821             //rotatesprite((PANELINPUTX+w+3)<<16,(PANELINPUTY)<<16,64<<8,0,COINCURSOR+((totalclock>>3)%7),c,0,ROTATE_SPRITE_SCREEN_CLIP,0,0,xdim-1,ydim-1);
1822             }
1823         }
1824     }
1825 
DrawCrosshair(PLAYERp pp)1826 VOID DrawCrosshair(PLAYERp pp)
1827     {
1828     extern int CrosshairX, CrosshairY;
1829     extern BOOL DemoMode,CameraTestMode;
1830 
1831     if (!gs.Crosshair)
1832         return;
1833 
1834     if (DemoMode || CameraTestMode)
1835         return;
1836 
1837     if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))
1838         return;
1839 
1840     if (dimensionmode == 6)
1841         return;
1842 
1843 //  wdx = 160;
1844 //  wdy = 100;
1845 #if 0
1846     if (gs.AutoAim)
1847     {
1848         int daz;
1849         short hitsprite, daang;
1850         static int handle=-1;
1851 
1852         daz = pp->posz + pp->bob_z;
1853         daang = 32;
1854         if ((hitsprite = WeaponAutoAimHitscan(pp->SpriteP, &daz, &daang, FALSE)) != -1)
1855         {
1856             SPRITEp hp = &sprite[hitsprite];
1857             USERp hu = User[hitsprite];
1858             int dx,dy,dz;
1859 
1860 
1861             // Find the delta coordinates from player to monster that is targeted
1862             dx = hp->x - pp->posx;
1863             dy = hp->y - pp->posy;
1864             dz = ((hp->z - (SPRITE_SIZE_Z(hitsprite)/2)) - pp->posz) >> 4;
1865 
1866             rotatepoint(0,0,dx,dy,(-pp->pang)&2047,&dx,&dy);
1867 
1868             if( dx == 0) return;
1869 
1870             wdx = windowx1 + ((windowx2-windowx1)/2);
1871             wdy = windowy1 + ((windowy2-windowy1)/2);
1872 
1873             x = (dy * wdx << 8) / dx + (wdx << 8);
1874             y = (dz * wdx << 8) / dx + (wdy << 8);
1875 
1876             y -= 100;
1877             y += (pp->horiz*wdx)/160;
1878 
1879             if(pp->CurWpn == pp->Wpn[WPN_RAIL])
1880             {
1881                 if(!FX_SoundActive(handle))
1882                     handle = PlaySound(DIGI_RAILLOCKED, &pp->posx, &pp->posy, &pp->posz, v3df_follow|v3df_dontpan);
1883             }
1884         }
1885         else
1886         {
1887             // It didn't target anything.
1888             if(pp->CurWpn == pp->Wpn[WPN_RAIL])
1889             {
1890                 if(FX_SoundActive(handle))
1891                     FX_StopSound(handle);
1892             }
1893             goto NORMALXHAIR;
1894         }
1895 
1896         rotatesprite(x << 8, y << 8, (1 << 16), 0,
1897             2326, 10, 0,
1898             ROTATE_SPRITE_VIEW_CLIP|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1899     }else
1900 #endif
1901     {
1902 //NORMALXHAIR:
1903         rotatesprite(CrosshairX, CrosshairY, (1 << 16), 0,
1904             2326, 10, 0,
1905             //ROTATE_SPRITE_VIEW_CLIP|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1906             ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_CORNER, 0, 0, xdim - 1, ydim - 1);
1907     }
1908 
1909     //#define TITLE_ROT_FLAGS (ROTATE_SPRITE_CORNER|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK)
1910 
1911     }
1912 
CameraView(PLAYERp pp,int * tx,int * ty,int * tz,short * tsectnum,short * tang,int * thoriz)1913 void CameraView(PLAYERp pp, int *tx, int *ty, int *tz, short *tsectnum, short *tang, int *thoriz)
1914     {
1915     int i,nexti;
1916     short ang;
1917     SPRITEp sp;
1918     BOOL found_camera = FALSE;
1919     BOOL player_in_camera = FALSE;
1920     BOOL FAFcansee_test;
1921     BOOL ang_test;
1922 
1923     if (pp == &Player[screenpeek])
1924         {
1925         TRAVERSE_SPRITE_STAT(headspritestat[STAT_DEMO_CAMERA], i, nexti)
1926             {
1927             sp = &sprite[i];
1928 
1929             ang = getangle(*tx - sp->x, *ty - sp->y);
1930             ang_test  = GetDeltaAngle(sp->ang, ang) < sp->lotag;
1931 
1932             FAFcansee_test =
1933                 (FAFcansee(sp->x, sp->y, sp->z, sp->sectnum, *tx, *ty, *tz, pp->cursectnum) ||
1934                 FAFcansee(sp->x, sp->y, sp->z, sp->sectnum, *tx, *ty, *tz + SPRITEp_SIZE_Z(pp->SpriteP), pp->cursectnum));
1935 
1936             player_in_camera = ang_test && FAFcansee_test;
1937 
1938             if (player_in_camera || pp->camera_check_time_delay > 0)
1939                     {
1940 
1941                     // if your not in the camera but are still looking
1942                     // make sure that only the last camera shows you
1943 
1944                     if (!player_in_camera && pp->camera_check_time_delay > 0)
1945                         {
1946                         if (pp->last_camera_sp != sp)
1947                             continue;
1948                         }
1949 
1950                     switch (sp->clipdist)
1951                         {
1952                         case 1:
1953                             pp->last_camera_sp = sp;
1954                             CircleCamera(tx, ty, tz, tsectnum, tang, 100);
1955                             found_camera = TRUE;
1956                             break;
1957 
1958                         default:
1959                             {
1960                             int xvect,yvect,zvect,zdiff;
1961 
1962                             pp->last_camera_sp = sp;
1963 
1964                             xvect = sintable[NORM_ANGLE(ang + 512)] >> 3;
1965                             yvect = sintable[NORM_ANGLE(ang)] >> 3;
1966 
1967                             zdiff = sp->z - *tz;
1968                             if (labs(sp->x - *tx) > 1000)
1969                                 zvect = scale(xvect, zdiff, sp->x - *tx);
1970                             else
1971                             if (labs(sp->y - *ty) > 1000)
1972                                 zvect = scale(yvect, zdiff, sp->y - *ty);
1973                             else
1974                             if (sp->x - *tx != 0)
1975                                 zvect = scale(xvect, zdiff, sp->x - *tx);
1976                             else
1977                             if (sp->y - *ty != 0)
1978                                 zvect = scale(yvect, zdiff, sp->y - *ty);
1979                             else
1980                                 zvect = 0;
1981 
1982                             // new horiz to player
1983                             *thoriz = 100 - (zvect/256);
1984                             *thoriz = max(*thoriz, PLAYER_HORIZ_MIN);
1985                             *thoriz = min(*thoriz, PLAYER_HORIZ_MAX);
1986 
1987                             //DSPRINTF(ds,"xvect %d,yvect %d,zvect %d,thoriz %d",xvect,yvect,zvect,*thoriz);
1988                             MONO_PRINT(ds);
1989 
1990                             *tang = ang;
1991                             *tx = sp->x;
1992                             *ty = sp->y;
1993                             *tz = sp->z;
1994                             *tsectnum = sp->sectnum;
1995 
1996                             found_camera = TRUE;
1997                             break;
1998                             }
1999                         }
2000                     }
2001 
2002             if (found_camera)
2003                 break;
2004             }
2005         }
2006 
2007     // if you player_in_camera you definately have a camera
2008     if (player_in_camera)
2009         {
2010         pp->camera_check_time_delay = 120/2;
2011         SET(pp->Flags, PF_VIEW_FROM_CAMERA);
2012 
2013         ASSERT(found_camera);
2014         }
2015     else
2016     // if you !player_in_camera you still might have a camera
2017     // for a split second
2018         {
2019         if (found_camera)
2020             {
2021             SET(pp->Flags, PF_VIEW_FROM_CAMERA);
2022             }
2023         else
2024             {
2025             pp->circle_camera_ang = 0;
2026             pp->circle_camera_dist = CIRCLE_CAMERA_DIST_MIN;
2027             RESET(pp->Flags, PF_VIEW_FROM_CAMERA);
2028             }
2029         }
2030     }
2031 
2032 VOID
PreDraw(VOID)2033 PreDraw(VOID)
2034     {
2035     short i, nexti;
2036 
2037     PreDrawStackedWater();
2038 
2039     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FLOOR_SLOPE_DONT_DRAW], i, nexti)
2040         {
2041         RESET(sector[sprite[i].sectnum].floorstat, FLOOR_STAT_SLOPE);
2042         }
2043     }
2044 
2045 VOID
PostDraw(VOID)2046 PostDraw(VOID)
2047     {
2048     short i, nexti;
2049     short sectnum,statnum;
2050     SPRITEp sp;
2051 
2052     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FLOOR_SLOPE_DONT_DRAW], i, nexti)
2053         {
2054         SET(sector[sprite[i].sectnum].floorstat, FLOOR_STAT_SLOPE);
2055         }
2056 
2057     TRAVERSE_SPRITE_STAT(headspritestat[STAT_FAF_COPY], i, nexti)
2058         {
2059         if (User[i])
2060             {
2061             FreeMem(User[i]);
2062             User[i] = NULL;
2063             }
2064 
2065         #if DEBUG
2066         sp = &sprite[i];
2067         statnum = sp->statnum;
2068         sectnum = sp->sectnum;
2069         memset(sp, 0xCC, sizeof(SPRITE));
2070         sp->statnum = statnum;
2071         sp->sectnum = sectnum;
2072         #endif
2073 
2074         deletesprite(i);
2075         }
2076     }
2077 
CopySprite(SPRITEp tsp,short newsector)2078 int CopySprite(SPRITEp tsp, short newsector)
2079     {
2080     short new;
2081     SPRITEp sp;
2082 
2083     new = COVERinsertsprite(newsector, STAT_FAF_COPY);
2084     sp = &sprite[new];
2085 
2086     sp->x = tsp->x;
2087     sp->y = tsp->y;
2088     sp->z = tsp->z;
2089     sp->cstat = tsp->cstat;
2090     sp->picnum = tsp->picnum;
2091     sp->pal = tsp->pal;
2092     sp->xrepeat = tsp->xrepeat;
2093     sp->yrepeat = tsp->yrepeat;
2094     sp->xoffset = tsp->xoffset;
2095     sp->yoffset = tsp->yoffset;
2096     sp->ang = tsp->ang;
2097     sp->xvel = tsp->xvel;
2098     sp->yvel = tsp->yvel;
2099     sp->zvel = tsp->zvel;
2100     sp->shade = tsp->shade;
2101 
2102     RESET(sp->cstat, CSTAT_SPRITE_BLOCK|CSTAT_SPRITE_BLOCK_HITSCAN);
2103 
2104     return(new);
2105     }
2106 
ConnectCopySprite(SPRITEp tsp)2107 int ConnectCopySprite(SPRITEp tsp)
2108     {
2109     short newsector;
2110     int testz;
2111 
2112     if (FAF_ConnectCeiling(tsp->sectnum))
2113         {
2114         newsector = tsp->sectnum;
2115         testz = SPRITEp_TOS(tsp) - Z(10);
2116 
2117         if (testz < sector[tsp->sectnum].ceilingz)
2118             updatesectorz(tsp->x, tsp->y, testz, &newsector);
2119 
2120         if (newsector >= 0 && newsector != tsp->sectnum)
2121             {
2122             return(CopySprite(tsp, newsector));
2123             }
2124         }
2125 
2126     if (FAF_ConnectFloor(tsp->sectnum))
2127         {
2128         newsector = tsp->sectnum;
2129         testz = SPRITEp_BOS(tsp) + Z(10);
2130 
2131         if (testz > sector[tsp->sectnum].floorz)
2132             updatesectorz(tsp->x, tsp->y, testz, &newsector);
2133 
2134         if (newsector >= 0 && newsector != tsp->sectnum)
2135             {
2136             return(CopySprite(tsp, newsector));
2137             }
2138         }
2139 
2140     return(-1);
2141     }
2142 
2143 
PreDrawStackedWater(void)2144 void PreDrawStackedWater(void)
2145     {
2146     short si,snexti;
2147     short i,nexti;
2148     SPRITEp sp,np;
2149     USERp u,nu;
2150     short new;
2151     int smr4,smr2;
2152     int x,y,z;
2153     short ang;
2154     PLAYERp pp = Player + screenpeek;
2155 
2156     smr4 = smoothratio + (((int) MoveSkip4) << 16);
2157     smr2 = smoothratio + (((int) MoveSkip2) << 16);
2158 
2159     TRAVERSE_SPRITE_STAT(headspritestat[STAT_CEILING_FLOOR_PIC_OVERRIDE], si, snexti)
2160         {
2161         TRAVERSE_SPRITE_SECT(headspritesect[sprite[si].sectnum], i, nexti)
2162             {
2163             if (User[i])
2164                 {
2165                 if (sprite[i].statnum == STAT_ITEM)
2166                     continue;
2167 
2168                 if (sprite[i].statnum <= STAT_DEFAULT || sprite[i].statnum > STAT_PLAYER0 + MAX_SW_PLAYERS)
2169                     continue;
2170 
2171                 // code so that a copied sprite will not make another copy
2172                 if (User[i]->xchange == -989898)
2173                     continue;
2174 
2175                 sp = &sprite[i];
2176                 u = User[i];
2177 
2178                 new = ConnectCopySprite(sp);
2179                 if (new >= 0)
2180                     {
2181                     np = &sprite[new];
2182 
2183                     // spawn a user
2184                     User[new] = nu = (USERp)CallocMem(sizeof(USER), 1);
2185                     ASSERT(nu != NULL);
2186 
2187                     nu->xchange = -989898;
2188 
2189                     // copy everything reasonable from the user that
2190                     // analyzesprites() needs to draw the image
2191                     nu->State = u->State;
2192                     nu->Rot = u->Rot;
2193                     nu->StateStart = u->StateStart;
2194                     nu->StateEnd = u->StateEnd;
2195                     nu->ox = u->ox;
2196                     nu->oy = u->oy;
2197                     nu->oz = u->oz;
2198                     nu->Flags = u->Flags;
2199                     nu->Flags2 = u->Flags2;
2200                     nu->RotNum = u->RotNum;
2201                     nu->ID = u->ID;
2202 
2203                     // set these to other sprite for players draw
2204                     nu->SpriteNum = i;
2205                     nu->SpriteP = sp;
2206 
2207                     nu->PlayerP = u->PlayerP;
2208                     nu->spal = u->spal;
2209                     }
2210                 }
2211             }
2212         }
2213     }
2214 
2215 
FAF_DrawRooms(int x,int y,int z,short ang,int horiz,short sectnum)2216 void FAF_DrawRooms(int x, int y, int z, short ang, int horiz, short sectnum)
2217     {
2218     short i,nexti;
2219 
2220     TRAVERSE_SPRITE_STAT(headspritestat[STAT_CEILING_FLOOR_PIC_OVERRIDE], i, nexti)
2221         {
2222         if (SPRITE_TAG3(i) == 0)
2223             {
2224             // back up ceilingpicnum and ceilingstat
2225             SPRITE_TAG5(i) = sector[sprite[i].sectnum].ceilingpicnum;
2226             sector[sprite[i].sectnum].ceilingpicnum = SPRITE_TAG2(i);
2227             SPRITE_TAG4(i) = sector[sprite[i].sectnum].ceilingstat;
2228             //SET(sector[sprite[i].sectnum].ceilingstat, ((int)SPRITE_TAG7(i))<<7);
2229             SET(sector[sprite[i].sectnum].ceilingstat, SPRITE_TAG6(i));
2230             RESET(sector[sprite[i].sectnum].ceilingstat, CEILING_STAT_PLAX);
2231             }
2232         else
2233         if (SPRITE_TAG3(i) == 1)
2234             {
2235             SPRITE_TAG5(i) = sector[sprite[i].sectnum].floorpicnum;
2236             sector[sprite[i].sectnum].floorpicnum = SPRITE_TAG2(i);
2237             SPRITE_TAG4(i) = sector[sprite[i].sectnum].floorstat;
2238             //SET(sector[sprite[i].sectnum].floorstat, ((int)SPRITE_TAG7(i))<<7);
2239             SET(sector[sprite[i].sectnum].floorstat, SPRITE_TAG6(i));
2240             RESET(sector[sprite[i].sectnum].floorstat, FLOOR_STAT_PLAX);
2241             }
2242         }
2243 
2244     drawrooms(x,y,z,ang,horiz,sectnum);
2245 
2246     TRAVERSE_SPRITE_STAT(headspritestat[STAT_CEILING_FLOOR_PIC_OVERRIDE], i, nexti)
2247         {
2248         // manually set gotpic
2249         if (TEST_GOTSECTOR(sprite[i].sectnum))
2250             {
2251             SET_GOTPIC(FAF_MIRROR_PIC);
2252             }
2253 
2254         if (SPRITE_TAG3(i) == 0)
2255             {
2256             // restore ceilingpicnum and ceilingstat
2257             sector[sprite[i].sectnum].ceilingpicnum = SPRITE_TAG5(i);
2258             sector[sprite[i].sectnum].ceilingstat = SPRITE_TAG4(i);
2259             //RESET(sector[sprite[i].sectnum].ceilingstat, CEILING_STAT_TYPE_MASK);
2260             RESET(sector[sprite[i].sectnum].ceilingstat, CEILING_STAT_PLAX);
2261             }
2262         else
2263         if (SPRITE_TAG3(i) == 1)
2264             {
2265             sector[sprite[i].sectnum].floorpicnum = SPRITE_TAG5(i);
2266             sector[sprite[i].sectnum].floorstat = SPRITE_TAG4(i);
2267             //RESET(sector[sprite[i].sectnum].floorstat, FLOOR_STAT_TYPE_MASK);
2268             RESET(sector[sprite[i].sectnum].floorstat, FLOOR_STAT_PLAX);
2269             }
2270         }
2271     }
2272 
2273 short ScreenSavePic = FALSE;
2274 
2275 VOID
drawscreen(PLAYERp pp)2276 drawscreen(PLAYERp pp)
2277     {
2278     extern BOOL DemoMode,CameraTestMode;
2279     int tx, ty, tz,thoriz,pp_siz;
2280     short tang,tsectnum;
2281     short i,j;
2282     walltype *wal;
2283     int tiltlock;
2284     int bob_amt = 0;
2285     int quake_z, quake_x, quake_y;
2286     short quake_ang;
2287     BOOL PicInView(short, BOOL);
2288     extern BOOL FAF_DebugView;
2289         PLAYERp camerapp;                       // prediction player if prediction is on, else regular player
2290     VOID DoPlayerDiveMeter(PLAYERp pp);
2291 
2292     // last valid stuff
2293     static short lv_sectnum = -1;
2294     static int lv_x, lv_y, lv_z;
2295 
2296     if (HelpInputMode)
2297         {
2298         flushperms();
2299         // note - could put Order Info Pages at the top like this also
2300 
2301         rotatesprite(0,0,65536L,0,HelpPagePic[HelpPage],0,0,
2302             (ROTATE_SPRITE_CORNER|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK|ROTATE_SPRITE_IGNORE_START_MOST),
2303             0, 0, xdim-1, ydim-1);
2304         nextpage();
2305 
2306         return;
2307         }
2308 
2309     #if 0
2310     if (TenScreenMode)
2311         {
2312         #define TEN_PIC 5109
2313 
2314         flushperms();
2315         // note - could put Order Info Pages at the top like this also
2316         rotatesprite(0,0,65536L,0,TEN_PIC,0,0,
2317             (ROTATE_SPRITE_CORNER|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK|ROTATE_SPRITE_IGNORE_START_MOST),
2318             0, 0, xdim-1, ydim-1);
2319 
2320         nextpage();
2321         return;
2322         }
2323     #endif
2324 
2325     DrawScreen = TRUE;
2326     PreDraw();
2327     // part of new border refresh method
2328     if (RedrawScreen)
2329         {
2330         RedrawCompass = TRUE;
2331         RedrawScreen = FALSE;
2332         // get rid of all PERM sprites!
2333         flushperms();
2334         // get rid of all PANF_KILL_AFTER_SHOW sprites!
2335         pFlushPerms(pp);
2336         SetBorder(pp,gs.BorderNum);
2337         }
2338 
2339     PreUpdatePanel();
2340 
2341 
2342     smoothratio = min(max((totalclock - ototalclock) * (65536 / synctics),0),65536);
2343 
2344     if (!ScreenSavePic)
2345         {
2346         dointerpolations(smoothratio);                      // Stick at beginning of drawscreen
2347         short_dointerpolations(smoothratio);                      // Stick at beginning of drawscreen
2348         }
2349 
2350         // TENSW: when rendering with prediction, the only thing that counts should
2351         // be the predicted player.
2352     if (PredictionOn && CommEnabled && pp == Player+myconnectindex)
2353                 camerapp = ppp;
2354         else
2355                 camerapp = pp;
2356 
2357     tx = camerapp->oposx + mulscale(camerapp->posx - camerapp->oposx, smoothratio, 16);
2358     ty = camerapp->oposy + mulscale(camerapp->posy - camerapp->oposy, smoothratio, 16);
2359     tz = camerapp->oposz + mulscale(camerapp->posz - camerapp->oposz, smoothratio, 16);
2360     tang = camerapp->oang + mulscale(((camerapp->pang + 1024 - camerapp->oang) & 2047) - 1024, smoothratio, 16);
2361     thoriz = camerapp->ohoriz + mulscale(camerapp->horiz - camerapp->ohoriz, smoothratio, 16);
2362     tsectnum = camerapp->cursectnum;
2363 
2364     //ASSERT(tsectnum >= 0 && tsectnum <= MAXSECTORS);
2365     // if updatesectorz is to sensitive try COVERupdatesector
2366     //updatesectorz(tx, ty, tz, &tsectnum);
2367 
2368     COVERupdatesector(tx, ty, &tsectnum);
2369 
2370     if (tsectnum < 0)
2371         {
2372         // if we hit an invalid sector move to the last valid position for drawing
2373         tsectnum = lv_sectnum;
2374         tx = lv_x;
2375         ty = lv_y;
2376         tz = lv_z;
2377         }
2378     else
2379         {
2380         // last valid stuff
2381         lv_sectnum = tsectnum;
2382         lv_x = tx;
2383         lv_y = ty;
2384         lv_z = tz;
2385         }
2386 
2387     // with "last valid" code this should never happen
2388     ASSERT(tsectnum >= 0 && tsectnum <= MAXSECTORS);
2389 
2390     pp->six = tx;
2391     pp->siy = ty;
2392     pp->siz = tz - pp->posz;
2393     pp_siz = tz;
2394     pp->siang = tang;
2395 
2396     if (pp->sop_riding || pp->sop_control)
2397         {
2398         tx = pp->posx;
2399         ty = pp->posy;
2400         tz = pp->posz;
2401         tang = pp->pang;
2402         tsectnum = pp->cursectnum;
2403         updatesectorz(tx, ty, tz, &tsectnum);
2404 
2405         pp->six = tx;
2406         pp->siy = ty;
2407         pp->siz = tz - pp->posz;
2408         pp->siang = tang;
2409         }
2410 
2411     QuakeViewChange(camerapp, &quake_z, &quake_x, &quake_y, &quake_ang);
2412     VisViewChange(camerapp, &visibility);
2413     tz = tz + quake_z;
2414     tx = tx + quake_x;
2415     ty = ty + quake_y;
2416     //thoriz = thoriz + quake_x;
2417     tang = NORM_ANGLE(tang + quake_ang);
2418 
2419     if (pp->sop_remote)
2420         {
2421         if (TEST_BOOL1(pp->remote_sprite))
2422             tang = pp->remote_sprite->ang;
2423         else
2424             tang = getangle(pp->sop_remote->xmid - tx, pp->sop_remote->ymid - ty);
2425         }
2426 
2427     //if (TEST(camerapp->Flags, PF_VIEW_FROM_OUTSIDE))
2428     if (TEST(pp->Flags, PF_VIEW_FROM_OUTSIDE))
2429         {
2430         BackView(&tx, &ty, &tz, &tsectnum, &tang, thoriz);
2431         }
2432     else
2433         {
2434         bob_amt = camerapp->bob_amt;
2435 
2436         if (DemoMode || CameraTestMode)
2437             CameraView(camerapp, &tx, &ty, &tz, &tsectnum, &tang, &thoriz);
2438         }
2439 
2440     if (!TEST(pp->Flags, PF_VIEW_FROM_CAMERA|PF_VIEW_FROM_OUTSIDE))
2441         {
2442         tz += bob_amt;
2443         tz += camerapp->bob_z;
2444 
2445         // recoil only when not in camera
2446         //thoriz = thoriz + camerapp->recoil_horizoff;
2447         thoriz = thoriz + pp->recoil_horizoff;
2448         thoriz = max(thoriz, PLAYER_HORIZ_MIN);
2449         thoriz = min(thoriz, PLAYER_HORIZ_MAX);
2450         }
2451 
2452     if (FAF_DebugView)
2453         clearview(255);
2454 
2455     OverlapDraw = TRUE;
2456     DrawOverlapRoom(tx, ty, tz, tang, thoriz, tsectnum);
2457     OverlapDraw = FALSE;
2458 
2459     if (dimensionmode != 6 && !ScreenSavePic)
2460         {
2461         // TEST this! Changed to camerapp
2462         //JS_DrawMirrors(camerapp, tx, ty, tz, tang, thoriz);
2463         JS_DrawMirrors(pp, tx, ty, tz, tang, thoriz);
2464         }
2465 
2466     if (!FAF_DebugView)
2467         {
2468         FAF_DrawRooms(tx, ty, tz, tang, thoriz, tsectnum);
2469         PicInView(FAF_MIRROR_PIC, FALSE);
2470         }
2471 
2472     analyzesprites(tx, ty, tz, FALSE);
2473     post_analyzesprites();
2474     drawmasks();
2475 
2476 	DrawCompass(pp);
2477     UpdatePanel();
2478 
2479     #define SLIME 2305
2480     // Only animate lava if its picnum is on screen
2481     // gotpic is a bit array where the tile number's bit is set
2482     // whenever it is drawn (ceilings, walls, sprites, etc.)
2483     if ((gotpic[SLIME >> 3] & (1 << (SLIME & 7))) > 0)
2484         {
2485         gotpic[SLIME >> 3] &= ~(1 << (SLIME & 7));
2486 
2487         if (waloff[SLIME])
2488             movelava((char *) waloff[SLIME]);
2489         }
2490 
2491 
2492     i = pp->cursectnum;
2493 
2494     show2dsector[i>>3] |= (1<<(i&7));
2495     wal = &wall[sector[i].wallptr];
2496     for(j=sector[i].wallnum;j>0;j--,wal++)
2497     {
2498         i = wal->nextsector;
2499         if (i < 0) continue;
2500         if (wal->cstat&0x0071) continue;
2501         if (wall[wal->nextwall].cstat&0x0071) continue;
2502         if (sector[i].lotag == 32767) continue;
2503         if (sector[i].ceilingz >= sector[i].floorz) continue;
2504         show2dsector[i>>3] |= (1<<(i&7));
2505     }
2506 
2507     if ((dimensionmode == 5 || dimensionmode == 6) && pp == Player+myconnectindex)
2508         {
2509         VOID MoveScrollMode2D(PLAYERp pp);
2510         extern BOOL ScrollMode2D;
2511 
2512         if (ScrollMode2D)
2513             {
2514             tx = Follow_posx;
2515             ty = Follow_posy;
2516             }
2517 
2518         for (j = 0; j < MAXSPRITES; j++)
2519             {
2520             // Don't show sprites tagged with 257
2521             if (sprite[j].lotag == 257)
2522                 {
2523                 if (TEST(sprite[j].cstat, CSTAT_SPRITE_FLOOR))
2524                     {
2525                     RESET(sprite[j].cstat, CSTAT_SPRITE_FLOOR);
2526                     sprite[j].owner = -2;
2527                     }
2528                 }
2529             }
2530 
2531         if (dimensionmode == 6)
2532             {
2533             clearview(0L);
2534             drawmapview(tx, ty, zoom, tang);
2535             }
2536 
2537         // Draw the line map on top of texture 2d map or just stand alone
2538         drawoverheadmap(tx, ty, zoom, tang);
2539         }
2540 
2541         for (j = 0; j < MAXSPRITES; j++)
2542             {
2543             // Don't show sprites tagged with 257
2544             if (sprite[j].lotag == 257 && sprite[j].owner == -2)
2545                 SET(sprite[j].cstat, CSTAT_SPRITE_FLOOR);
2546             }
2547 
2548     // if doing a screen save don't need to process the rest
2549     if (ScreenSavePic)
2550         {
2551         DrawScreen = FALSE;
2552         return;
2553         }
2554 
2555     PrintLocationInfo(pp);
2556     PrintSpriteInfo(pp);
2557 
2558     #if SYNC_TEST
2559     SyncStatMessage();
2560     #endif
2561 
2562     DrawCrosshair(pp);
2563 
2564 
2565     operatefta();           // Draw all the user quotes in the quote array
2566 
2567     operateconfta();        // Draw messages in the console
2568 
2569     DoPlayerDiveMeter(pp); // Do the underwater breathing bar
2570 
2571     // Boss Health Meter, if Boss present
2572     BossHealthMeter();
2573 
2574     if(ConInputMode)
2575         {
2576         DrawConInput(pp);   // Console panel input mode
2577         }
2578     else
2579         DrawMessageInput(pp);   // This is only used for non-multiplayer input now
2580 
2581     UpdateMiniBar(pp);
2582 
2583     if (UsingMenus)
2584         MNU_DrawMenu();
2585     else
2586         SecretInfo(pp);
2587 
2588     nextpage();
2589 
2590     // certain input is done here - probably shouldn't be
2591     DrawCheckKeys(pp);
2592 
2593     restoreinterpolations();                 // Stick at end of drawscreen
2594     short_restoreinterpolations();                 // Stick at end of drawscreen
2595 
2596     PostDraw();
2597     DrawScreen = FALSE;
2598     }
2599 
2600 VOID
DrawCompass(PLAYERp pp)2601 DrawCompass(PLAYERp pp)
2602     {
2603 #define COMPASS_TIC     2380
2604 #define COMPASS_TIC2    2381
2605 
2606 #define COMPASS_NORTH   2382
2607 #define COMPASS_NORTH2  2383
2608 
2609 #define COMPASS_SOUTH   2384
2610 #define COMPASS_SOUTH2  2385
2611 
2612 #define COMPASS_EAST    2386
2613 #define COMPASS_EAST2   2387
2614 
2615 #define COMPASS_WEST    2388
2616 #define COMPASS_WEST2   2389
2617 
2618 #define COMPASS_MID_TIC    2390
2619 #define COMPASS_MID_TIC2   2391
2620 
2621 #define COMPASS_X   140
2622 #define COMPASS_Y   (162-5)
2623 
2624 #define NORM_CANG(ang) (((ang) + 32) & 31)
2625 
2626     short start_ang,ang;
2627     short x_size = tilesizx[COMPASS_NORTH];
2628     short x;
2629     short i;
2630     int flags;
2631     PANEL_SPRITEp psp;
2632 
2633     static short CompassPic[32] =
2634         {
2635         COMPASS_EAST, COMPASS_EAST2,
2636         COMPASS_TIC, COMPASS_TIC2,
2637         COMPASS_MID_TIC, COMPASS_MID_TIC2,
2638         COMPASS_TIC, COMPASS_TIC2,
2639 
2640         COMPASS_SOUTH, COMPASS_SOUTH2,
2641         COMPASS_TIC, COMPASS_TIC2,
2642         COMPASS_MID_TIC, COMPASS_MID_TIC2,
2643         COMPASS_TIC, COMPASS_TIC2,
2644 
2645         COMPASS_WEST, COMPASS_WEST2,
2646         COMPASS_TIC, COMPASS_TIC2,
2647         COMPASS_MID_TIC, COMPASS_MID_TIC2,
2648         COMPASS_TIC, COMPASS_TIC2,
2649 
2650         COMPASS_NORTH, COMPASS_NORTH2,
2651         COMPASS_TIC, COMPASS_TIC2,
2652         COMPASS_MID_TIC, COMPASS_MID_TIC2,
2653         COMPASS_TIC, COMPASS_TIC2,
2654         };
2655 
2656     static short CompassShade[10] =
2657         {
2658         //20, 16, 11, 6, 1, 1, 6, 11, 16, 20
2659         25, 19, 15, 9, 1, 1, 9, 15, 19, 25
2660         };
2661 
2662     extern BOOL PanelUpdateMode;
2663 
2664     if (!PanelUpdateMode)
2665         return;
2666 
2667     if (gs.BorderNum < BORDER_BAR || pp - Player != screenpeek)
2668         return;
2669 
2670     ang = pp->pang;
2671 
2672     if (pp->sop_remote)
2673         ang = 0;
2674 
2675     start_ang = (ang + 32) >> 6;
2676 
2677     start_ang = NORM_CANG(start_ang - 4);
2678 
2679     if (!RedrawCompass && LastCompassAngle == start_ang)
2680         return;
2681     LastCompassAngle = start_ang;
2682     RedrawCompass = FALSE;
2683 
2684     for (i = 0, x = COMPASS_X; i < 10; i++)
2685         {
2686         psp = pSpawnFullScreenSprite(pp, CompassPic[NORM_CANG(start_ang + i)], PRI_FRONT_MAX, x, COMPASS_Y);
2687         SET(psp->flags, PANF_NON_MASKED|PANF_SCALE_BOTTOM);
2688         psp->shade = CompassShade[i];
2689         x += x_size;
2690         }
2691     }
2692 
2693 
ScreenTileLock(void)2694 VOID ScreenTileLock(void)
2695     {
2696     walock[SAVE_SCREEN_TILE] = CACHE_LOCK_MAX;
2697     }
2698 
ScreenTileUnLock(void)2699 VOID ScreenTileUnLock(void)
2700     {
2701     walock[SAVE_SCREEN_TILE] = CACHE_UNLOCK_MAX;
2702     }
2703 
2704 int
ScreenLoadSaveSetup(PLAYERp UNUSED (pp))2705 ScreenLoadSaveSetup(PLAYERp UNUSED(pp))
2706     {
2707     int tx, ty, tz,thoriz,pp_siz;
2708     short tang,tsectnum;
2709     short i;
2710 
2711     // lock and allocate memory
2712 
2713     ScreenTileLock();
2714 
2715     if (!waloff[SAVE_SCREEN_TILE])
2716         allocache((void **)&waloff[SAVE_SCREEN_TILE], SAVE_SCREEN_XSIZE * SAVE_SCREEN_YSIZE, &walock[SAVE_SCREEN_TILE]);
2717 
2718     tilesizx[SAVE_SCREEN_TILE] = SAVE_SCREEN_XSIZE;
2719     tilesizx[SAVE_SCREEN_TILE] = SAVE_SCREEN_YSIZE;
2720 
2721     return(SAVE_SCREEN_TILE);
2722     }
2723 
2724 int
ScreenSaveSetup(PLAYERp UNUSED (pp))2725 ScreenSaveSetup(PLAYERp UNUSED(pp))
2726     {
2727     short i;
2728 
2729     ScreenLoadSaveSetup(Player + myconnectindex);
2730 
2731     setviewtotile(SAVE_SCREEN_TILE, SAVE_SCREEN_YSIZE, SAVE_SCREEN_XSIZE);
2732 
2733     ScreenSavePic = TRUE;
2734     drawscreen(Player + myconnectindex);
2735     ScreenSavePic = FALSE;
2736 
2737     setviewback();
2738 
2739     return(SAVE_SCREEN_TILE);
2740     }
2741 
2742 
2743 
2744 
2745