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, §num);
388 updatesector(tsp->x, tsp->y, §num);
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