1 /* KJL 14:30:27 06/05/98 - weapon targeting code */
2 #include "3dc.h"
3 #include "module.h"
4 #include "inline.h"
5
6 #include "stratdef.h"
7 #include "gamedef.h"
8 #include "gameplat.h"
9
10 #include "bh_types.h"
11 #include "inventry.h"
12 #include "comp_shp.h"
13 #include "load_shp.h"
14 #include "huddefs.h"
15
16 #define UseLocalAssert Yes
17 #include "ourasert.h"
18
19 #include "dynblock.h"
20 #include "dynamics.h"
21 #include "lighting.h"
22 #include "pvisible.h"
23 #include "bh_alien.h"
24 #include "bh_pred.h"
25 #include "bh_xeno.h"
26 #include "bh_paq.h"
27 #include "bh_queen.h"
28 #include "bh_fhug.h"
29 #include "bh_marin.h"
30 #include "bh_debri.h"
31 #include "bh_weap.h"
32 #include "bh_agun.h"
33 #include "weapons.h"
34 #include "avpview.h"
35
36 #include "psnd.h"
37 #include "vision.h"
38 #include "plat_shp.h"
39
40 #include "particle.h"
41 #include "psndproj.h"
42 #include "showcmds.h"
43 #include "los.h"
44 #include <math.h>
45
46
47 #include "paintball.h"
48 /* for win 95 net support */
49 #include "pldghost.h"
50 #include "pldnet.h"
51
52 /*KJL****************************************************************************************
53 * G L O B A L S *
54 ****************************************************************************************KJL*/
55
56 void SmartTarget_GetCofM(DISPLAYBLOCK *target,VECTORCH *viewSpaceOutput);
57 void GetTargetingPointOfObject(DISPLAYBLOCK *objectPtr, VECTORCH *targetPtr);
58
59 extern int NumOnScreenBlocks;
60 extern DISPLAYBLOCK *OnScreenBlockList[];
61 extern struct Target PlayersTarget;
62 extern VECTORCH GunMuzzleDirectionInVS;
63 extern VECTORCH GunMuzzleDirectionInWS;
64 extern int NormalFrameTime;
65 extern int Weapon_ThisBurst;
66
67 /* stuff to do with where a gun is pointing */
68 extern int GunMuzzleSightX, GunMuzzleSightY;
69 /* In 16.16 for smoothness. On-screen coords indicating to where the gun's muzzle is pointing */
70
71 int SmartTargetSightX, SmartTargetSightY;
72 char CurrentlySmartTargetingObject;
73 DISPLAYBLOCK *SmartTarget_Object;
74 DISPLAYBLOCK *Old_SmartTarget_Object;
75
76 void CalculateWhereGunIsPointing(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr);
77 void CalculatePlayersTarget(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr);
78 DISPLAYBLOCK *SmartTarget_GetNewTarget(void);
79 int SmartTarget_TargetFilter(STRATEGYBLOCK *candidate);
80
CalculateWhereGunIsPointing(TEMPLATE_WEAPON_DATA * twPtr,PLAYER_WEAPON_DATA * weaponPtr)81 void CalculateWhereGunIsPointing(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr)
82 {
83 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
84 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
85
86 extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
87 MATRIXCH matrix = VDBPtr->VDB_Mat;
88
89 TransposeMatrixCH(&matrix);
90
91 // textprint("Calculating where gun is pointing...\n");
92
93 /* unnormalised vector in the direction which the gun's muzzle is pointing, IN VIEW SPACE */
94 /* very useful when considering sprites, which lie in a Z-plane in view space */
95 GunMuzzleDirectionInVS.vz = 65536;
96 GunMuzzleDirectionInVS.vx =
97 (GunMuzzleSightX-(ScreenDescriptorBlock.SDB_Width<<15))/(VDBPtr->VDB_ProjX);
98 GunMuzzleDirectionInVS.vy =
99 (((GunMuzzleSightY-(ScreenDescriptorBlock.SDB_Height<<15))/(VDBPtr->VDB_ProjY))*3)/4;
100
101 /* Now fudge for gun judder! */
102 if ((twPtr->UseStateMovement==0)||(weaponPtr->WeaponIDNumber == WEAPON_MINIGUN)) {
103 if ((weaponPtr->CurrentState==WEAPONSTATE_FIRING_PRIMARY)
104 ||( (weaponPtr->CurrentState==WEAPONSTATE_FIRING_SECONDARY)&&(weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS) )){
105 if ((twPtr->PrimaryIsRapidFire)||(weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS)) {
106
107 EULER judder;
108 MATRIXCH juddermat;
109
110 if (twPtr->RecoilMaxRandomZ>0) {
111 weaponPtr->PositionOffset.vz = (FastRandom()%twPtr->RecoilMaxRandomZ) - twPtr->RecoilMaxZ;
112 }
113
114 if ((Weapon_ThisBurst>0)||(weaponPtr->WeaponIDNumber == WEAPON_TWO_PISTOLS)) {
115
116 /* jiggle the weapon around when you shoot */
117 int speed=Approximate3dMagnitude(&Player->ObStrategyBlock->DynPtr->LinVelocity);
118 /* speed should be between ~0 and ~27000 (jumping alien). ~15000 is a moving marine. */
119
120 if (twPtr->RecoilMaxXTilt>0) {
121 judder.EulerX=(FastRandom()%twPtr->RecoilMaxXTilt)-twPtr->RecoilMaxXTilt/2;
122 } else {
123 judder.EulerX=0;
124 }
125 if (twPtr->RecoilMaxYTilt>0) {
126 judder.EulerY=(FastRandom()%twPtr->RecoilMaxYTilt)-twPtr->RecoilMaxYTilt/2;
127 } else {
128 judder.EulerY=0;
129 }
130 judder.EulerZ=0;
131
132 judder.EulerX=MUL_FIXED(judder.EulerX,(ONE_FIXED+(speed<<2)));
133 judder.EulerY=MUL_FIXED(judder.EulerY,(ONE_FIXED+(speed<<2)));
134
135 judder.EulerX&=wrap360;
136 judder.EulerY&=wrap360;
137
138 CreateEulerMatrix(&judder,&juddermat);
139 RotateVector(&GunMuzzleDirectionInVS,&juddermat);
140 }
141 }
142 } else {
143 /* Recentre Z offset. */
144 int linearCenteringSpeed = MUL_FIXED(300,NormalFrameTime);
145
146 if (weaponPtr->PositionOffset.vz > 0 )
147 {
148 weaponPtr->PositionOffset.vz -= linearCenteringSpeed;
149 if (weaponPtr->PositionOffset.vz < 0) weaponPtr->PositionOffset.vz = 0;
150 }
151 else if (weaponPtr->PositionOffset.vz < 0 )
152 {
153 weaponPtr->PositionOffset.vz += linearCenteringSpeed;
154 if (weaponPtr->PositionOffset.vz > 0) weaponPtr->PositionOffset.vz = 0;
155 }
156
157 }
158 }
159
160 GunMuzzleDirectionInWS = GunMuzzleDirectionInVS;
161 /* rotate vector into world space and then normalise */
162 RotateVector(&GunMuzzleDirectionInWS,&matrix);
163 Normalise(&GunMuzzleDirectionInWS);
164
165 }
166
CalculatePlayersTarget(TEMPLATE_WEAPON_DATA * twPtr,PLAYER_WEAPON_DATA * weaponPtr)167 void CalculatePlayersTarget(TEMPLATE_WEAPON_DATA *twPtr, PLAYER_WEAPON_DATA *weaponPtr)
168 {
169
170 CalculateWhereGunIsPointing(twPtr,weaponPtr);
171
172 FindPolygonInLineOfSight(&GunMuzzleDirectionInWS, &Global_VDB_Ptr->VDB_World, 1,Player);
173
174 PlayersTarget.DispPtr = LOS_ObjectHitPtr;
175 PlayersTarget.Distance = LOS_Lambda;
176 PlayersTarget.HModelSection = LOS_HModel_Section;
177
178 if (PaintBallMode.IsOn)
179 {
180 PaintBallMode.TargetDispPtr = LOS_ObjectHitPtr;
181 PaintBallMode.TargetPosition = LOS_Point;
182 PaintBallMode.TargetNormal = LOS_ObjectNormal;
183 }
184
185 //textprint("Exiting CPT - PT.DP is %x, PT.HMS is %x\n",PlayersTarget.DispPtr,PlayersTarget.HModelSection);
186
187 if (PlayersTarget.DispPtr) {
188 if (PlayersTarget.HModelSection) {
189 if (PlayersTarget.HModelSection->my_controller!=PlayersTarget.DispPtr->HModelControlBlock) {
190 PlayersTarget.HModelSection=NULL;
191 }
192 }
193 }
194
195 /* did we hit anything? */
196 if (PlayersTarget.DispPtr)
197 {
198 PlayersTarget.Position = LOS_Point;
199 }
200 else
201 {
202 /* pretend the target is right in front of the player, but a very long way off */
203 PlayersTarget.Position.vx = Global_VDB_Ptr->VDB_World.vx + (Global_VDB_Ptr->VDB_Mat.mat13<<7);
204 PlayersTarget.Position.vy = Global_VDB_Ptr->VDB_World.vy + (Global_VDB_Ptr->VDB_Mat.mat23<<7);
205 PlayersTarget.Position.vz = Global_VDB_Ptr->VDB_World.vz + (Global_VDB_Ptr->VDB_Mat.mat33<<7);
206 PlayersTarget.HModelSection = NULL;
207 }
208 if (ShowDebuggingText.Target)
209 {
210 PrintDebuggingText("Target Position: %d %d %d\n",PlayersTarget.Position.vx,PlayersTarget.Position.vy,PlayersTarget.Position.vz);
211 }
212
213 if (PlayersTarget.HModelSection) {
214 GLOBALASSERT(PlayersTarget.DispPtr->HModelControlBlock==PlayersTarget.HModelSection->my_controller);
215 }
216
217 if(AvP.Network!=I_No_Network)
218 {
219 AddNetMsg_PredatorLaserSights(&PlayersTarget.Position,&LOS_ObjectNormal,PlayersTarget.DispPtr);
220 }
221
222
223 /* find position/orientation of predator's targeting sights */
224 if ( (AvP.PlayerType == I_Predator)
225 &&((weaponPtr->WeaponIDNumber == WEAPON_PRED_RIFLE)
226 ||(weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON)) )
227 {
228 int i=2;
229
230 VECTORCH offset[3] =
231 {
232 {0,-50,0},
233 {43,25,0},
234 {-43,25,0},
235 };
236
237 MATRIXCH matrix = Global_VDB_Ptr->VDB_Mat;
238 TransposeMatrixCH(&matrix);
239
240 do
241 {
242 VECTORCH position = offset[i];
243
244 RotateVector(&position,&matrix);
245 position.vx += Global_VDB_Ptr->VDB_World.vx;
246 position.vy += Global_VDB_Ptr->VDB_World.vy;
247 position.vz += Global_VDB_Ptr->VDB_World.vz;
248 FindPolygonInLineOfSight(&GunMuzzleDirectionInWS, &position, 1,Player);
249 PredatorLaserTarget.Normal[i] = LOS_ObjectNormal;
250
251 if (PlayersTarget.DispPtr)
252 {
253 PredatorLaserTarget.Position[i] = LOS_Point;
254 }
255 else
256 {
257 /* pretend the target is right in front of the player, but a very long way off */
258 PredatorLaserTarget.Position[i].vx = Global_VDB_Ptr->VDB_World.vx + (Global_VDB_Ptr->VDB_Mat.mat13<<7);
259 PredatorLaserTarget.Position[i].vy = Global_VDB_Ptr->VDB_World.vy + (Global_VDB_Ptr->VDB_Mat.mat23<<7);
260 PredatorLaserTarget.Position[i].vz = Global_VDB_Ptr->VDB_World.vz + (Global_VDB_Ptr->VDB_Mat.mat33<<7);
261 }
262
263 }
264 while(i--);
265 PredatorLaserTarget.ShouldBeDrawn=1;
266 }
267 else
268 {
269 PredatorLaserTarget.ShouldBeDrawn=0;
270 }
271
272
273 }
274
CalculateFiringSolution(VECTORCH * firing_pos,VECTORCH * target_pos,VECTORCH * target_vel,int projectile_speed,VECTORCH * solution)275 BOOL CalculateFiringSolution(VECTORCH* firing_pos,VECTORCH* target_pos,VECTORCH* target_vel,int projectile_speed,VECTORCH* solution)
276 {
277 VECTORCH normal; //normal from firer to target
278 VECTORCH rotated_vel;
279 VECTORCH rotated_solution;
280 MATRIXCH mat;
281
282 int distance_to_target;
283
284 GLOBALASSERT(firing_pos);
285 GLOBALASSERT(target_pos);
286 GLOBALASSERT(target_vel);
287 GLOBALASSERT(projectile_speed);
288 GLOBALASSERT(solution);
289
290 //get a normalised vector from start to destination
291 normal=*target_pos;
292 SubVector(firing_pos,&normal);
293
294 if(!normal.vx && !normal.vy && !normal.vz)
295 return FALSE;
296
297 distance_to_target=Approximate3dMagnitude(&normal);
298 Normalise(&normal);
299
300 //calculate a matrix that will rotate the normal to the zaxis
301 {
302 //normal will be the third row
303 VECTORCH row1,row2;
304
305
306 if(normal.vx>30000 || normal.vx<-30000 || normal.vy>30000 || normal.vy<-30000)
307 {
308 row1.vx=-normal.vy;
309 row1.vy=normal.vx;
310 row1.vz=0;
311 }
312 else
313 {
314 row1.vx=-normal.vz;
315 row1.vy=0;
316 row1.vz=normal.vx;
317 }
318 Normalise(&row1);
319
320 CrossProduct(&normal,&row1,&row2);
321
322 mat.mat11=row1.vx;
323 mat.mat21=row1.vy;
324 mat.mat31=row1.vz;
325
326 mat.mat12=row2.vx;
327 mat.mat22=row2.vy;
328 mat.mat32=row2.vz;
329
330 mat.mat13=normal.vx;
331 mat.mat23=normal.vy;
332 mat.mat33=normal.vz;
333
334 }
335
336
337 //apply the rotation to the velocity
338 rotated_vel=*target_vel;
339 RotateVector(&rotated_vel,&mat);
340
341 //is the target moving too fast?
342 if(rotated_vel.vz>=projectile_speed || -rotated_vel.vz>=projectile_speed)
343 {
344 return FALSE;
345 }
346
347 //the x and y components of the rotated solution should match the rotated velocity
348 //(scale down by projectile speed , because we want a normalised direction)
349
350 rotated_solution.vx=DIV_FIXED(rotated_vel.vx,projectile_speed);
351 rotated_solution.vy=DIV_FIXED(rotated_vel.vy,projectile_speed);
352
353 //z=1-(x*x+y*y)
354 {
355 //not sure we have a fixed point square root
356 float x=(float)rotated_solution.vx;
357 float y=(float)rotated_solution.vy;
358 float z_squared=65536.0*65536.0-(x*x+y*y);
359 if(z_squared<0)
360 {
361 //target moving too fast to hit
362 return FALSE;
363 }
364 rotated_solution.vz=(int)sqrt(z_squared);
365 }
366
367 //finally need to rotated solution back
368 *solution=rotated_solution;
369 TransposeMatrixCH(&mat);
370 RotateVector(solution,&mat);
371
372 //normalise solution to be on the safe side
373 Normalise(solution);
374
375 return TRUE;
376
377 }
378
SmartTarget(int speed,int projectile_speed)379 void SmartTarget(int speed,int projectile_speed)
380 {
381 DISPLAYBLOCK *trackedObject;
382
383 if (SmartgunMode==I_Track) {
384 trackedObject=SmartTarget_GetNewTarget();
385 } else {
386 trackedObject=NULL;
387 }
388
389 // textprint("Tracking object %x ",trackedObject);
390 {
391 int screenX;
392 int screenY;
393 CurrentlySmartTargetingObject=0;
394
395 /* If there is a valid near object which isn't so close as to cause a division by zero */
396 if (trackedObject && (trackedObject->ObView.vz!=0))
397 {
398 VECTORCH targetView;
399 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
400 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
401 #if 0
402 STRATEGYBLOCK *sbPtr = trackedObject->ObStrategyBlock;
403 int offsetX,offsetY;
404
405 {
406 /* calculate offset required to aim at the middle torso rather
407 than the sprite's bollocks */
408 MATRIXCH mat;
409 int offsetMag;
410 {
411 SHAPEHEADER *shapePtr = GetShapeData(sbPtr->SBdptr->ObShape);
412 offsetMag = shapePtr->shapeminy/2;
413 }
414
415 offsetX = MUL_FIXED(trackedObject->ObMat.mat21,offsetMag);
416 offsetY = MUL_FIXED(trackedObject->ObMat.mat22,offsetMag);
417 }
418 #endif
419 /* Set targetView. */
420 SmartTarget_GetCofM(trackedObject,&targetView);
421
422 if(projectile_speed)
423 {
424 //get a firing solution so that projectile should hit if target maintains curremt velocity
425 if(trackedObject->ObStrategyBlock)
426 {
427 if(trackedObject->ObStrategyBlock->DynPtr)
428 {
429 DYNAMICSBLOCK *dynPtr = trackedObject->ObStrategyBlock->DynPtr;
430 if(dynPtr->LinVelocity.vx || dynPtr->LinVelocity.vy || dynPtr->LinVelocity.vz)
431 {
432
433 VECTORCH velocity=dynPtr->LinVelocity;
434 VECTORCH zero={0,0,0};
435 VECTORCH solution;
436 //rotate velocity into view space
437 RotateVector(&velocity,&Global_VDB_Ptr->VDB_Mat);
438
439 if(CalculateFiringSolution(&zero,&targetView,&velocity,projectile_speed,&solution))
440 {
441 targetView=solution;
442 }
443
444
445 }
446 }
447 }
448 }
449
450 if (targetView.vz>0)
451 {
452 screenX = WideMulNarrowDiv
453 (
454 //trackedObject->ObView.vx,//+offsetX,
455 targetView.vx,
456 VDBPtr->VDB_ProjX,
457 //trackedObject->ObView.vz
458 targetView.vz
459 );
460 screenY = WideMulNarrowDiv
461 (
462 //trackedObject->ObView.vy,//+offsetY,
463 targetView.vy*4,
464 VDBPtr->VDB_ProjY,
465 //trackedObject->ObView.vz
466 (targetView.vz*3)
467 );
468 CurrentlySmartTargetingObject=1;
469 }
470 else
471 {
472 screenX=0;
473 screenY=0;
474 }
475 }
476 else
477 {
478 screenX=0;
479 screenY=0;
480 }
481
482
483 {
484 extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock;
485 int targetX,targetY,dx,dy;
486 int targetingSpeed = NormalFrameTime*speed;
487
488 /* KJL 14:08:50 09/20/96 - the targeting is FRI, but care has to be taken
489 at very low frame rates to ensure that the sight doesn't jump about
490 all over the place. */
491 if (targetingSpeed > 65536) targetingSpeed=65536;
492
493 targetX = (ScreenDescriptorBlock.SDB_Width>>1);
494 targetY = (ScreenDescriptorBlock.SDB_Height>>1);
495
496 {
497 int maxRangeX = (ScreenDescriptorBlock.SDB_Width*14)/32; /* gives nearly 90% of screen */
498
499 if ((screenX>-maxRangeX) && (screenX<maxRangeX))
500 {
501 int maxRangeY = (ScreenDescriptorBlock.SDB_Height*14)/32; /* gives nearly 90% of screen */
502
503 if ((screenY>-maxRangeY) && (screenY<maxRangeY))
504 {
505 targetX += screenX;
506 targetY += screenY;
507 }
508 else CurrentlySmartTargetingObject=0;
509 }
510 else CurrentlySmartTargetingObject=0;
511 }
512
513 if (speed<=0)
514 {
515 SmartTargetSightX = targetX<<16;
516 SmartTargetSightY = targetY<<16;
517 }
518 else
519 {
520 dx = MUL_FIXED( ((targetX<<16)-SmartTargetSightX), targetingSpeed );
521 dy = MUL_FIXED( ((targetY<<16)-SmartTargetSightY), targetingSpeed );
522
523 /* If the x-coord difference between the sight and the target is small,
524 just move the sight so that it has the same x-coord as the target.
525 This stops the sight from hovering a pixel away from where it should be */
526 if (dx>16384 || dx<-16384) SmartTargetSightX += dx;
527 else SmartTargetSightX = targetX<<16;
528
529 /* Similarly for the y-coord */
530 if (dy>16384 || dy<-16384) SmartTargetSightY += dy;
531 else SmartTargetSightY = targetY<<16;
532 }
533 }
534
535 }
536
537 Old_SmartTarget_Object=SmartTarget_Object;
538
539 if (CurrentlySmartTargetingObject) {
540 SmartTarget_Object=trackedObject;
541 } else {
542 SmartTarget_Object=NULL;
543 }
544
545 return;
546 }
547
548 #define SMART_TRACKABLE_TARGETS 100
549
SmartTarget_GetNewTarget(void)550 DISPLAYBLOCK *SmartTarget_GetNewTarget(void) {
551
552 int a,b,c;
553 int numberOfObjects = NumOnScreenBlocks;
554 DISPLAYBLOCK *nearestObjectPtr, *target;
555 int nearestObjectDist;
556
557 DISPLAYBLOCK *track_array[SMART_TRACKABLE_TARGETS];
558
559 target=NULL;
560
561 nearestObjectPtr=NULL;
562
563 for (a=0; a<SMART_TRACKABLE_TARGETS; a++) {
564 track_array[a]=NULL;
565 }
566 a=0;
567
568 while (numberOfObjects--)
569 {
570 DISPLAYBLOCK* objectPtr = OnScreenBlockList[numberOfObjects];
571 STRATEGYBLOCK* sbPtr = objectPtr->ObStrategyBlock;
572
573 if (sbPtr && sbPtr->DynPtr)
574 {
575 VECTORCH viewPos;
576 /* Arc reject. */
577 SmartTarget_GetCofM(objectPtr,&viewPos);
578 if (viewPos.vz>0) {
579 if (SmartTarget_TargetFilter(sbPtr)) {
580 if (a<SMART_TRACKABLE_TARGETS) {
581 track_array[a]=objectPtr;
582 a++;
583 } else {
584 /* Arse. Well, I said I didn't like this way. */
585 }
586 }
587 }
588 }
589 }
590
591 /* Now, filter the track array. */
592 b=a;
593 c=a;
594
595
596 while (b--) {
597
598 int notFar;
599
600 nearestObjectDist=SMART_TARGETING_RANGE;
601 nearestObjectPtr=NULL;
602 notFar=-1;
603
604 a=c;
605
606 while (a) {
607
608 DISPLAYBLOCK* objectPtr;
609 STRATEGYBLOCK* sbPtr;
610
611 a--;
612
613 objectPtr = track_array[a];
614
615 if (objectPtr) {
616 /* calc distance to player - no parallel strat support yet */
617 /* 2d vector from player to object */
618 int dist = FandVD_Distance_3d(&objectPtr->ObWorld,&Player->ObWorld);
619
620 sbPtr = objectPtr->ObStrategyBlock;
621
622 if (dist<nearestObjectDist)
623 {
624 nearestObjectDist=dist;
625 nearestObjectPtr=objectPtr;
626 notFar=a;
627 }
628 }
629
630 }
631
632 if (nearestObjectPtr) {
633
634 GLOBALASSERT(notFar!=-1);
635
636 if (IsThisObjectVisibleFromThisPosition_WithIgnore(track_array[notFar],Player,&(Global_VDB_Ptr->VDB_World),nearestObjectDist) ) {
637 /* Valid. */
638 target=track_array[notFar];
639 break; // Exit loop
640 } else {
641 /* Remove from list. */
642 track_array[notFar]=NULL;
643 }
644 }
645 }
646
647 return(target);
648
649 }
650
SmartTarget_GetCofM(DISPLAYBLOCK * target,VECTORCH * viewSpaceOutput)651 void SmartTarget_GetCofM(DISPLAYBLOCK *target,VECTORCH *viewSpaceOutput) {
652
653 AVP_BEHAVIOUR_TYPE targetType;
654
655 /* Get smartgun aiming point. */
656
657 if (target->HModelControlBlock==NULL) {
658 *viewSpaceOutput=target->ObView;
659 return;
660 } else if (target->HModelControlBlock->section_data==NULL) {
661 /* Always consider extreme possibilities. */
662 *viewSpaceOutput=target->ObView;
663 return;
664 }
665
666 /* Must be a hierarchy. */
667
668 if (target->ObStrategyBlock->I_SBtype==I_BehaviourNetGhost) {
669
670 NETGHOSTDATABLOCK *dataptr;
671
672 dataptr=target->ObStrategyBlock->SBdataptr;
673
674 targetType=dataptr->type;
675
676 } else if (
677 (target->ObStrategyBlock->I_SBtype==I_BehaviourMarinePlayer)||
678 (target->ObStrategyBlock->I_SBtype==I_BehaviourAlienPlayer)||
679 (target->ObStrategyBlock->I_SBtype==I_BehaviourPredatorPlayer)) {
680
681 switch(AvP.PlayerType)
682 {
683 case I_Alien:
684 targetType=I_BehaviourAlienPlayer;
685 break;
686 case I_Predator:
687 targetType=I_BehaviourPredatorPlayer;
688 break;
689 case I_Marine:
690 targetType=I_BehaviourMarinePlayer;
691 break;
692 default:
693 GLOBALASSERT(0);
694 return;
695 break;
696 }
697
698 } else {
699 targetType=target->ObStrategyBlock->I_SBtype;
700 }
701
702 /* Now, switch case on targetType. */
703
704 switch (targetType) {
705 case I_BehaviourMarine:
706 case I_BehaviourMarinePlayer:
707 {
708 SECTION_DATA *targetsection;
709
710 targetsection=GetThisSectionData(target->HModelControlBlock->section_data,
711 "chest");
712
713 if (targetsection==NULL) {
714 targetsection=target->HModelControlBlock->section_data;
715 }
716
717 if (targetsection->flags§ion_data_view_init) {
718 *viewSpaceOutput=targetsection->View_Offset;
719 return;
720 } else {
721 /* Whoops. */
722 *viewSpaceOutput=target->ObView;
723 return;
724 }
725 }
726 break;
727 case I_BehaviourPredator:
728 case I_BehaviourPredatorPlayer:
729 {
730 SECTION_DATA *targetsection;
731
732 targetsection=GetThisSectionData(target->HModelControlBlock->section_data,
733 "chest");
734
735 if (targetsection==NULL) {
736 targetsection=target->HModelControlBlock->section_data;
737 }
738
739 if (targetsection->flags§ion_data_view_init) {
740 *viewSpaceOutput=targetsection->View_Offset;
741 return;
742 } else {
743 /* Whoops. */
744 *viewSpaceOutput=target->ObView;
745 return;
746 }
747 }
748 break;
749 case I_BehaviourAlien:
750 case I_BehaviourAlienPlayer:
751 {
752 SECTION_DATA *targetsection;
753
754 targetsection=GetThisSectionData(target->HModelControlBlock->section_data,
755 "chest");
756
757 if (targetsection==NULL) {
758 targetsection=target->HModelControlBlock->section_data;
759 }
760
761 if (targetsection->flags§ion_data_view_init) {
762 *viewSpaceOutput=targetsection->View_Offset;
763 return;
764 } else {
765 /* Whoops. */
766 *viewSpaceOutput=target->ObView;
767 return;
768 }
769 }
770 break;
771 default:
772 {
773 /* General case. */
774 if (target->HModelControlBlock->section_data->flags§ion_data_view_init) {
775 *viewSpaceOutput=target->HModelControlBlock->section_data->View_Offset;
776 return;
777 } else {
778 /* Whoops. */
779 *viewSpaceOutput=target->ObView;
780 return;
781 }
782 }
783 break;
784 }
785
786 }
787
788
789
SmartTarget_TargetFilter(STRATEGYBLOCK * candidate)790 int SmartTarget_TargetFilter(STRATEGYBLOCK *candidate)
791 {
792 PLAYER_WEAPON_DATA *weaponPtr = &(PlayerStatusPtr->WeaponSlot[PlayerStatusPtr->SelectedWeaponSlot]);
793
794 /* KJL 11:56:33 14/10/98 - the Predator's Shoulder cannon can only track objects when used in the correct
795 vision mode, e.g. you can only target marines when in infrared mode */
796 if ((weaponPtr->WeaponIDNumber == WEAPON_PRED_SHOULDERCANNON)
797 ||(weaponPtr->WeaponIDNumber == WEAPON_PRED_DISC))
798 {
799 switch (CurrentVisionMode)
800 {
801 case VISION_MODE_PRED_SEEALIENS:
802 {
803 if (candidate->I_SBtype==I_BehaviourAlien && !NPC_IsDead(candidate))
804 {
805 return 1;
806 }
807 if (candidate->I_SBtype==I_BehaviourXenoborg && !NPC_IsDead(candidate))
808 {
809 return 1;
810 }
811 if (candidate->I_SBtype==I_BehaviourMarine && !NPC_IsDead(candidate))
812 {
813 MARINE_STATUS_BLOCK *marineStatusPointer;
814 LOCALASSERT(candidate);
815 marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr);
816 LOCALASSERT(marineStatusPointer);
817
818 if (marineStatusPointer->My_Weapon->Android) {
819 return(1);
820 } else {
821 return(0);
822 }
823 }
824 if (candidate->I_SBtype==I_BehaviourNetGhost)
825 {
826 NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr;
827
828 if (ghostDataPtr->type==I_BehaviourAlienPlayer || ghostDataPtr->type==I_BehaviourAlien)
829 {
830 return 1;
831 }
832 }
833 break;
834 }
835 case VISION_MODE_PRED_THERMAL:
836 {
837 if (candidate->I_SBtype==I_BehaviourMarine && !NPC_IsDead(candidate))
838 {
839 MARINE_STATUS_BLOCK *marineStatusPointer;
840 LOCALASSERT(candidate);
841 marineStatusPointer = (MARINE_STATUS_BLOCK *)(candidate->SBdataptr);
842 LOCALASSERT(marineStatusPointer);
843
844 if (marineStatusPointer->My_Weapon->Android) {
845 return(0);
846 } else {
847 return(1);
848 }
849 }
850 if (candidate->I_SBtype==I_BehaviourNetGhost)
851 {
852 NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr;
853
854 if (ghostDataPtr->type==I_BehaviourMarinePlayer || ghostDataPtr->type==I_BehaviourMarine)
855 {
856 return 1;
857 }
858 }
859 break;
860
861 }
862 case VISION_MODE_PRED_SEEPREDTECH:
863 {
864 if (candidate->I_SBtype==I_BehaviourPredator && !NPC_IsDead(candidate))
865 {
866 return 1;
867 }
868 if (candidate->I_SBtype==I_BehaviourNetGhost)
869 {
870 NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr;
871
872 if (ghostDataPtr->type==I_BehaviourPredatorPlayer || ghostDataPtr->type==I_BehaviourPredator)
873 {
874 /* Check for game type? */
875 switch (netGameData.gameType) {
876 case NGT_Individual:
877 return(1);
878 break;
879 case NGT_CoopDeathmatch:
880 return(0);
881 break;
882 case NGT_LastManStanding:
883 return(0);
884 break;
885 case NGT_PredatorTag:
886 return(1);
887 break;
888 case NGT_Coop:
889 return(0);
890 break;
891 default:
892 return(1);
893 break;
894 }
895 return (1);
896 }
897 }
898 break;
899 }
900 default:
901 break;
902 }
903 return 0;
904 } else if (weaponPtr->WeaponIDNumber == WEAPON_SMARTGUN) {
905 /* Don't target marines if Friendly Fire is disabled. */
906 if (netGameData.disableFriendlyFire && (netGameData.gameType==NGT_CoopDeathmatch || netGameData.gameType==NGT_Coop)) {
907 NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)candidate->SBdataptr;
908 if (ghostDataPtr->type==I_BehaviourMarinePlayer || ghostDataPtr->type==I_BehaviourMarine) {
909 return(0);
910 }
911 }
912 }
913
914 switch (candidate->I_SBtype) {
915 case I_BehaviourPredator:
916 /* Valid. */
917 if (NPC_IsDead(candidate)) {
918 return(0);
919 } else {
920 #if 0
921 if (NPCPredatorIsCloaked(candidate)) {
922 return(0);
923 } else {
924 return(1);
925 }
926 #else
927 return(1);
928 #endif
929 }
930 break;
931 case I_BehaviourAlien:
932 case I_BehaviourQueenAlien:
933 case I_BehaviourFaceHugger:
934 case I_BehaviourXenoborg:
935 case I_BehaviourMarine:
936 case I_BehaviourSeal:
937 case I_BehaviourPredatorAlien:
938 /* Valid. */
939 if (NPC_IsDead(candidate)) {
940 return(0);
941 } else {
942 return(1);
943 }
944 break;
945 case I_BehaviourNetGhost:
946 {
947 NETGHOSTDATABLOCK *dataptr;
948 dataptr=candidate->SBdataptr;
949 switch (dataptr->type) {
950 case I_BehaviourPredatorPlayer:
951 #if 0
952 if (dataptr->CloakingEffectiveness) {
953 return(0);
954 } else {
955 return(1);
956 }
957 #else
958 return(1);
959 #endif
960 break;
961 case I_BehaviourMarinePlayer:
962 case I_BehaviourAlienPlayer:
963 case I_BehaviourRocket:
964 case I_BehaviourFrisbee:
965 case I_BehaviourGrenade:
966 case I_BehaviourFlareGrenade:
967 case I_BehaviourFragmentationGrenade:
968 case I_BehaviourClusterGrenade:
969 case I_BehaviourNPCPredatorDisc:
970 case I_BehaviourPredatorDisc_SeekTrack:
971 case I_BehaviourAlien:
972 return(1);
973 break;
974 case I_BehaviourProximityGrenade:
975 {
976 DYNAMICSBLOCK *dynPtr=candidate->DynPtr;
977
978 /* Only visible when moving. */
979
980 if (!((dynPtr->Position.vx==dynPtr->PrevPosition.vx)
981 &&(dynPtr->Position.vy==dynPtr->PrevPosition.vy)
982 &&(dynPtr->Position.vz==dynPtr->PrevPosition.vz) )) {
983
984 return(1);
985
986 } else {
987 return(0);
988 }
989
990 }
991 break;
992 default:
993 return(0);
994 break;
995 }
996 }
997 break;
998 default:
999 return(0);
1000 break;
1001 }
1002
1003 }
1004
GetTargetingPointOfObject_Far(STRATEGYBLOCK * sbPtr,VECTORCH * targetPtr)1005 void GetTargetingPointOfObject_Far(STRATEGYBLOCK *sbPtr, VECTORCH *targetPtr)
1006 {
1007 /* Can we use the near one? This is a more general shell. */
1008 if (sbPtr->SBdptr) {
1009 GetTargetingPointOfObject(sbPtr->SBdptr,targetPtr);
1010 return;
1011 } else {
1012 if (sbPtr->DynPtr) {
1013 *targetPtr=sbPtr->DynPtr->Position;
1014 targetPtr->vy-=500; /* Just to be on the safe side. */
1015 return;
1016 } else {
1017 /* Aw, gawd! I don't know! There's NO position for this! */
1018 GLOBALASSERT(0);
1019 }
1020 }
1021
1022 }
1023
GetTargetingPointOfObject(DISPLAYBLOCK * objectPtr,VECTORCH * targetPtr)1024 void GetTargetingPointOfObject(DISPLAYBLOCK *objectPtr, VECTORCH *targetPtr)
1025 {
1026 /* try to look at the centre of the object */
1027 if (objectPtr->HModelControlBlock)
1028 {
1029 SECTION_DATA *targetSectionPtr;
1030 SECTION_DATA *firstSectionPtr;
1031
1032 ProveHModel(objectPtr->HModelControlBlock,objectPtr);
1033
1034 firstSectionPtr=objectPtr->HModelControlBlock->section_data;
1035 LOCALASSERT(firstSectionPtr);
1036 LOCALASSERT(firstSectionPtr->flags§ion_data_initialised);
1037
1038 /* look for the object's torso in preference */
1039 targetSectionPtr =GetThisSectionData(objectPtr->HModelControlBlock->section_data,"chest");
1040
1041 if (targetSectionPtr)
1042 {
1043 LOCALASSERT(targetSectionPtr->flags§ion_data_initialised);
1044 *targetPtr = targetSectionPtr->World_Offset;
1045 }
1046 else /* just use the top of the hierarchy then */
1047 {
1048 *targetPtr = firstSectionPtr->World_Offset;
1049 }
1050 }
1051 else
1052 {
1053 /* KJL 12:23:26 15/05/98 - need to consider the player differently */
1054 if (objectPtr == Player)
1055 {
1056 #if 0
1057 *targetPtr = Global_VDB_Ptr->VDB_World;
1058 #else
1059 int height;
1060
1061 /* Let's try a little experiment. */
1062 if (PlayerStatusPtr->IsAlive==0) {
1063 *targetPtr = Global_VDB_Ptr->VDB_World;
1064 return;
1065 }
1066
1067 if (PlayerStatusPtr->ShapeState!=PMph_Standing) {
1068 height=-800;
1069 } else {
1070 height=-1500;
1071 }
1072
1073 targetPtr->vx=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat21,height);
1074 targetPtr->vy=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat22,height);
1075 targetPtr->vz=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat23,height);
1076 #if 0
1077 targetPtr->vx+=Player->ObStrategyBlock->DynPtr->Position.vx;
1078 targetPtr->vy+=Player->ObStrategyBlock->DynPtr->Position.vy;
1079 targetPtr->vz+=Player->ObStrategyBlock->DynPtr->Position.vz;
1080 #else
1081 targetPtr->vx+=Player->ObWorld.vx;
1082 targetPtr->vy+=Player->ObWorld.vy;
1083 targetPtr->vz+=Player->ObWorld.vz;
1084 #endif
1085 #endif
1086 }
1087 else
1088 {
1089 *targetPtr = objectPtr->ObWorld;
1090 }
1091
1092 }
1093 }
1094