1 #include "3dc.h"
2 #include "module.h"
3 #include "inline.h"
4
5 #include "stratdef.h"
6 #include "gamedef.h"
7
8 #include "bh_types.h"
9 #include "comp_shp.h"
10 #include "inventry.h"
11
12 #define UseLocalAssert Yes
13
14 #include "ourasert.h"
15
16 #include "bh_weap.h"
17 #include "bh_debri.h"
18 #include "weapons.h"
19 #include "dynblock.h"
20 #include "dynamics.h"
21 #include "lighting.h"
22 #include "bh_pred.h"
23 #include "bh_alien.h"
24 #include "bh_marin.h"
25 #include "bh_dummy.h"
26 #include "bh_rubberduck.h"
27 #include "pvisible.h"
28 #include "pheromon.h"
29 #include "psnd.h"
30 #include "psndplat.h"
31 #include "huddefs.h"
32 #include "ai_sight.h"
33 #include "targeting.h"
34 #include "game_statistics.h"
35
36 #include "particle.h"
37 #include "sfx.h"
38 #include "showcmds.h"
39 #include "savegame.h"
40 #include "los.h"
41 #include "detaillevels.h"
42
43 /* for win95 net game support */
44 #include "pldghost.h"
45 #include "pldnet.h"
46
47 #define FLAMETHROWER_PARTICLES_PER_FRAME (MUL_FIXED(120,NormalFrameTime))
48 #define PREDPISTOLFLECHETTES_PARTICLES_PER_FRAME (MUL_FIXED(50,NormalFrameTime))
49 #define TIME_FOR_PREDPISTOLFLECHETTE (ONE_FIXED/50)
50 #define TIME_FOR_FLAMETHROWER_PARTICLE (ONE_FIXED/120)
51 #define NEAR_WEAPON_FUDGE 1
52 #define PREDPISTOL_SPREAD (4)
53
54 #define NEW_PREDPISTOL_BOLT 1
55 #define FRISBEE_SPEED 20000
56 /* Was 10000. */
57 #define ENERGY_BOLT_SPEED 65536
58
59 /*KJL****************************************************************************************
60 * P R O T O T Y P E S *
61 ****************************************************************************************KJL*/
62 static void InitialiseRocketBehaviour(void);
63 static void InitialiseGrenadeBehaviour(AVP_BEHAVIOUR_TYPE behaviourID);
64 static STRATEGYBLOCK* InitialisePulseGrenadeBehaviour(void);
65 static void InitialisePPPlasmaBoltBehaviour(void);
66 static void InitialiseSpeargunBoltBehaviour(void);
67 void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage, int factor);
68 static void InitialiseFlameThrowerBehaviour(void);
69 void InitialiseDiscBehaviour(STRATEGYBLOCK *target,SECTION_DATA *disc_section);
70 static void InitialiseAlienSpitBehaviour(void);
71 STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor);
72 static void InitialiseFrisbeeBehaviour(void);
73 STRATEGYBLOCK* InitialiseFrisbeeBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor);
74
75 static void GetGunDirection(VECTORCH *gunDirectionPtr, VECTORCH *positionPtr);
76 void PredDisc_GetFirstTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr, DISPLAYBLOCK *target, VECTORCH *position);
77 int PredDisc_TargetFilter(STRATEGYBLOCK *candidate);
78 void EulerAnglesHoming(VECTORCH *source, VECTORCH *Target, EULER *eulr, int rate);
79 void SetEulerAngles(VECTORCH *source, VECTORCH *Target, EULER *eulr);
80 STRATEGYBLOCK *PredDisc_GetNewTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr,VECTORCH *discpos, STRATEGYBLOCK *prevtarg, int mine);
81 int ObjectIsOnScreen(DISPLAYBLOCK *object);
82 void Frisbee_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr);
83 void Crunch_Position_For_Players_Weapon(VECTORCH *position);
84 static int SBForcesBounce(STRATEGYBLOCK *sbPtr);
85 static int Reflect(VECTORCH *Incident, VECTORCH *Normal, EULER *Output);
86
87 /*KJL****************************************************************************************
88 * G L O B A L S *
89 ****************************************************************************************KJL*/
90 extern int NormalFrameTime;
91 extern int ProjectilesFired;
92 extern SECTION_DATA *PWMFSDP;
93 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
94 extern ACTIVESOUNDSAMPLE ActiveSounds[];
95 extern int AccuracyStats_TargetFilter(STRATEGYBLOCK *sbPtr);
96 extern BOOL CalculateFiringSolution(VECTORCH* firing_pos,VECTORCH* target_pos,VECTORCH* target_vel,int projectile_speed,VECTORCH* solution);
97
98 int mx=0;
99 int my=-2000;
100 int mz=12000;
101
102 extern int NumberOfFlaresActive;
103 int PredPistolBoltSpeed=32767;
104 int PredPistolBoltGravity=80000;
105
106 int Caster_BlastRadius=5000;
107
108 SOUND3DDATA Explosion_SoundData={
109 {0,0,0,},
110 {0,0,0,},
111 15000,
112 150000,
113 };
114
115 SOUND3DDATA PredPistolExplosion_SoundData={
116 {0,0,0,},
117 {0,0,0,},
118 15000,
119 100000,
120 };
121
122 /*KJL****************************************************************************************
123 * F U N C T I O N S *
124 ****************************************************************************************KJL*/
125
FireProjectileAmmo(enum AMMO_ID AmmoID)126 void FireProjectileAmmo(enum AMMO_ID AmmoID)
127 {
128 switch (AmmoID)
129 {
130 case AMMO_GRENADE:
131 {
132 switch(GrenadeLauncherData.SelectedAmmo)
133 {
134 case AMMO_GRENADE:
135 {
136 InitialiseGrenadeBehaviour(I_BehaviourGrenade);
137 break;
138 }
139 case AMMO_FLARE_GRENADE:
140 {
141 InitialiseGrenadeBehaviour(I_BehaviourFlareGrenade);
142 break;
143 }
144 case AMMO_FRAGMENTATION_GRENADE:
145 {
146 InitialiseGrenadeBehaviour(I_BehaviourClusterGrenade);
147 break;
148 }
149 case AMMO_PROXIMITY_GRENADE:
150 {
151 InitialiseGrenadeBehaviour(I_BehaviourProximityGrenade);
152 break;
153 }
154 default:
155 {
156 /* KJL 10:36:25 04/21/97 - data error if you got here */
157 LOCALASSERT(0);
158 break;
159 }
160 }
161 break;
162 }
163 case AMMO_PULSE_GRENADE:
164 {
165 InitialisePulseGrenadeBehaviour();
166 break;
167 }
168 case AMMO_SADAR_TOW:
169 {
170 InitialiseRocketBehaviour();
171 break;
172 }
173 case AMMO_FRISBEE:
174 {
175 InitialiseFrisbeeBehaviour();
176 break;
177 }
178
179 case AMMO_PRED_RIFLE:
180 {
181 InitialiseSpeargunBoltBehaviour();
182 break;
183 }
184
185 case AMMO_PRED_PISTOL:
186 {
187 InitialisePPPlasmaBoltBehaviour();
188 break;
189 }
190
191 case AMMO_PRED_ENERGY_BOLT:
192 {
193 InitialiseEnergyBoltBehaviour(&TemplateAmmo[AMMO_PRED_ENERGY_BOLT].MaxDamage[AvP.Difficulty],65536);
194 break;
195 }
196
197 case AMMO_PRED_DISC:
198 {
199 break;
200 }
201
202 case AMMO_FLAMETHROWER:
203 {
204 InitialiseFlameThrowerBehaviour();
205 break;
206 }
207
208 case AMMO_ALIEN_SPIT:
209 {
210 InitialiseAlienSpitBehaviour();
211 break;
212 }
213 default:
214 break;
215 }
216 }
217
218 /* CDF 12/7/99 Smart Frisbee for expansion pack? */
219
FrisbeeSight_FrustrumReject(STRATEGYBLOCK * sbPtr,VECTORCH * localOffset,STRATEGYBLOCK * target)220 int FrisbeeSight_FrustrumReject(STRATEGYBLOCK *sbPtr,VECTORCH *localOffset,STRATEGYBLOCK *target) {
221
222 FRISBEE_BEHAV_BLOCK *frisbeeStatusPointer;
223 VECTORCH fixed_offset;
224
225 LOCALASSERT(sbPtr);
226 LOCALASSERT(sbPtr->containingModule);
227 frisbeeStatusPointer = (FRISBEE_BEHAV_BLOCK *)(sbPtr->SBdataptr);
228 LOCALASSERT(frisbeeStatusPointer);
229
230 #if 0
231 PrintDebuggingText("Local Offset: %d %d %d\n",localOffset->vx,localOffset->vy,localOffset->vz);
232 #endif
233
234 fixed_offset=*localOffset;
235
236 #if 0
237 if ((fixed_offset.vx <0) && (
238 ((fixed_offset.vy) < (-fixed_offset.vx))&&(fixed_offset.vy>=0))
239 ||((fixed_offset.vy<0)&&((-fixed_offset.vy) < (-fixed_offset.vx))
240 )&&(
241 ((fixed_offset.vz) < (-fixed_offset.vx))&&(fixed_offset.vz>=0))
242 ||((fixed_offset.vz<0)&&((-fixed_offset.vz) < (-fixed_offset.vx))
243 )) {
244 /* 90 horizontal, 90 vertical? */
245 #else
246 if (((fixed_offset.vx <0) && (
247 ((fixed_offset.vy) < (-fixed_offset.vx))&&(fixed_offset.vy>=0)))
248 || (((fixed_offset.vy<0)&&((-fixed_offset.vy) < (-fixed_offset.vx))
249 )&&((fixed_offset.vz>0))
250 )) {
251 /* 90 horizontal, 90 vertical? */
252 #endif
253 return(1);
254 } else {
255 return(0);
256 }
257 }
258
259 int Frisbee_TargetFilter(STRATEGYBLOCK *candidate) {
260
261 switch (candidate->I_SBtype) {
262 case I_BehaviourMarinePlayer:
263 case I_BehaviourDummy:
264 {
265 switch (AvP.PlayerType) {
266 default:
267 case I_Marine:
268 return(0);
269 break;
270 case I_Predator:
271 case I_Alien:
272 return(1);
273 break;
274 }
275 return(0);
276 }
277 break;
278 case I_BehaviourAlien:
279 {
280 ALIEN_STATUS_BLOCK *alienStatusPointer;
281 LOCALASSERT(candidate);
282 LOCALASSERT(candidate->DynPtr);
283
284 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr);
285
286 if (NPC_IsDead(candidate)) {
287 return(0);
288 } else {
289 if ((alienStatusPointer->BehaviourState==ABS_Dormant)||
290 (alienStatusPointer->BehaviourState==ABS_Awakening)) {
291 return(0);
292 } else {
293 return(1);
294 }
295 }
296 break;
297 }
298 case I_BehaviourQueenAlien:
299 case I_BehaviourFaceHugger:
300 case I_BehaviourPredator:
301 case I_BehaviourXenoborg:
302 case I_BehaviourSeal:
303 case I_BehaviourPredatorAlien:
304 /* Valid. */
305 return(1);
306 break;
307 case I_BehaviourMarine:
308 return(0);
309 break;
310 case I_BehaviourNetGhost:
311 {
312 NETGHOSTDATABLOCK *dataptr;
313 dataptr=candidate->SBdataptr;
314 switch (dataptr->type) {
315 case I_BehaviourMarinePlayer:
316 switch (netGameData.gameType) {
317 case NGT_Individual:
318 return(1);
319 break;
320 case NGT_CoopDeathmatch:
321 return(0);
322 break;
323 case NGT_LastManStanding:
324 return(0);
325 break;
326 case NGT_PredatorTag:
327 return(1);
328 break;
329 case NGT_Coop:
330 return(0);
331 break;
332 case NGT_AlienTag:
333 return(1); //However, there shouldn't be more than one alien in alien tag anyway.
334 break;
335 default:
336 return(0);
337 break;
338 }
339 break;
340 case I_BehaviourAlienPlayer:
341 case I_BehaviourPredatorPlayer:
342 case I_BehaviourAlien:
343 return(1);
344 break;
345 default:
346 return(0);
347 break;
348 }
349 }
350 break;
351 default:
352 return(0);
353 break;
354 }
355
356 }
357
358 /*
359 Function only does minimal frisbee setup , the rest will be done by the load function
360 */
361 static STRATEGYBLOCK* InitialiseFrisbeeBehaviour_ForLoad() {
362 VECTORCH zeroVect = {0,0,0};
363
364 DISPLAYBLOCK *dispPtr;
365 DYNAMICSBLOCK *dynPtr;
366 FRISBEE_BEHAV_BLOCK *bblk;
367
368 /* make displayblock with correct shape, etc */
369 dispPtr = MakeObject(I_BehaviourFrisbee,&zeroVect);
370
371 if (dispPtr == 0) return NULL; // Failed to allocate display block
372
373 /* make displayblock a dynamic module object */
374 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
375
376 /* setup dynamics block */
377 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
378
379 if (dynPtr == 0)
380 {
381 // Failed to allocate a dynamics block
382 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
383 return NULL;
384 }
385
386 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
387
388
389 /* give missile a maximum lifetime */
390 dispPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(FRISBEE_BEHAV_BLOCK));
391 bblk = dispPtr->ObStrategyBlock->SBdataptr;
392
393 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
394 {
395 // Failed to allocate a strategy block data pointer
396 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
397 return NULL;
398 }
399 memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(FRISBEE_BEHAV_BLOCK));
400
401 bblk->soundHandle = SOUND_NOACTIVEINDEX;
402
403 bblk->Laser.SourcePosition=zeroVect;
404 bblk->Laser.SourcePosition=zeroVect;
405 bblk->Laser.BeamHasHitPlayer=0;
406 bblk->Laser.BeamIsOn=0;
407
408 dispPtr->HModelControlBlock=&bblk->HModelController;
409
410
411 return dispPtr->ObStrategyBlock;
412 }
413
414 STRATEGYBLOCK* CreateFrisbeeKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer) {
415
416 DISPLAYBLOCK *dispPtr;
417 DYNAMICSBLOCK *dynPtr;
418 FRISBEE_BEHAV_BLOCK *fblk;
419
420 /* make displayblock with correct shape, etc */
421 dispPtr = MakeObject(I_BehaviourFrisbee,position);
422 if (dispPtr == 0) return NULL; // Failed to allocate display block
423
424 /* make displayblock a dynamic module object */
425 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
426
427 /* add lighting effect */
428 AddLightingEffectToObject(dispPtr,LFX_ROCKETJET);
429
430 /* setup dynamics block */
431 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
432
433 if (fromplayer==0) {
434 dynPtr->IgnoreThePlayer=0;
435 }
436
437 if (dynPtr == 0)
438 {
439 // Failed to allocate a dynamics block
440 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
441 return NULL;
442 }
443
444 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
445
446 /* give missile a maximum lifetime */
447 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(FRISBEE_BEHAV_BLOCK));
448
449 fblk=((FRISBEE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr);
450
451 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
452 {
453 // Failed to allocate a strategy block data pointer
454 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
455 return NULL;
456 }
457
458 fblk->counter = (5*ONE_FIXED);
459 fblk->soundHandle = SOUND_NOACTIVEINDEX;
460 fblk->Bounced = 0;
461 fblk->bounces = 0;
462
463 fblk->Laser.SourcePosition=*position;
464 fblk->Laser.SourcePosition=*position;
465 fblk->Laser.BeamHasHitPlayer=0;
466 fblk->Laser.BeamIsOn=0;
467
468 /* Create HModel. */
469 {
470 SECTION *root_section;
471
472 root_section=GetNamedHierarchyFromLibrary("mdisk","Mdisk");
473
474 GLOBALASSERT(root_section);
475
476 Create_HModel(&fblk->HModelController,root_section);
477 InitHModelSequence(&fblk->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,(ONE_FIXED>>1));
478
479 ProveHModel(&fblk->HModelController,dispPtr);
480 fblk->HModelController.Looped=1;
481
482 dispPtr->HModelControlBlock=&fblk->HModelController;
483
484 #if 0
485 SECTION_DATA *local_disc;
486 /* Match disks. */
487 local_disc=GetThisSectionData(bblk->HModelController.section_data,"disk");
488 local_disc->World_Offset=disc_section->World_Offset;
489 local_disc->SecMat=disc_section->SecMat;
490 InitHModelTweening(&bblk->HModelController,(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED,1);
491 #endif
492 }
493
494 /* align rocket to launcher */
495 dynPtr->Position=*position;
496 dynPtr->PrevPosition=*position;
497
498 dynPtr->OrientMat = *orient;
499 dynPtr->PrevOrientMat = dynPtr->OrientMat;
500
501 dynPtr->IgnoreThePlayer=1;
502
503 /* I added this next line for networking: Patrick */
504 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
505
506 /* align velocity too */
507 dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31;
508 dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32;
509 dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33;
510
511 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, FRISBEE_SPEED);
512 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, FRISBEE_SPEED);
513 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, FRISBEE_SPEED);
514
515 #if 0
516 if (fromplayer==1) {
517 /* Add player velocity? */
518 dynPtr->LinVelocity.vx+=Player->ObStrategyBlock->DynPtr->LinVelocity.vx;
519 dynPtr->LinVelocity.vy+=Player->ObStrategyBlock->DynPtr->LinVelocity.vy;
520 dynPtr->LinVelocity.vz+=Player->ObStrategyBlock->DynPtr->LinVelocity.vz;
521 }
522 #endif
523
524 /* for net game support */
525 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
526
527 return dispPtr->ObStrategyBlock;
528
529 }
530
531 extern void FrisbeeBehaviour(STRATEGYBLOCK *sbPtr)
532 {
533 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
534 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
535 FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
536 int explodeNow;
537
538 MODULE *dmod;
539
540 dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule);
541
542 //MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position));
543 explodeNow=0;
544
545 if (fbPtr->counter<=0)
546 {
547 explodeNow=1;
548 }
549 else
550 {
551 if (reportPtr)
552 {
553
554 /* Cut from disc code. Don't care about whether it was the player... */
555 {
556
557 /* Hit a random strategyblock - what is it? */
558 if (SBForcesBounce(reportPtr->ObstacleSBPtr)) {
559
560 MATRIXCH mat;
561 /* Bounce. */
562 Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
563 dynPtr->OrientEuler.EulerZ=0;
564 dynPtr->IgnoreThePlayer=0;
565 MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
566 Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
567 fbPtr->bounces++;
568 /*
569 Record that the disc has bounced - for use in network game
570 */
571 fbPtr->Bounced=1;
572
573 CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
574 TransposeMatrixCH(&mat);
575
576 dynPtr->OrientMat=mat;
577
578 dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31,FRISBEE_SPEED);
579 dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32,FRISBEE_SPEED);
580 dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33,FRISBEE_SPEED);
581
582 dynPtr->LinImpulse.vx=0;
583 dynPtr->LinImpulse.vy=0;
584 dynPtr->LinImpulse.vz=0;
585
586
587 } else if (SBIsEnvironment(reportPtr->ObstacleSBPtr)) {
588 Frisbee_Hit_Environment(sbPtr,reportPtr);
589 } else {
590 /* Hit a creature? */
591 VECTORCH attack_dir;
592
593 /* Accuracy snipped. */
594 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
595 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_FRISBEE].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
596 explodeNow=1;
597 }
598 }
599 }
600 }
601
602 if (explodeNow) {
603 //NewOnScreenMessage("Frisbee Exploded.");
604
605 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
606 HandleEffectsOfExplosion
607 (
608 sbPtr,
609 &(dynPtr->Position),
610 TemplateAmmo[AMMO_FRISBEE_BLAST].MaxRange,
611 &TemplateAmmo[AMMO_FRISBEE_BLAST].MaxDamage[AvP.Difficulty],
612 TemplateAmmo[AMMO_FRISBEE_BLAST].ExplosionIsFlat
613 );
614
615 if (sbPtr->containingModule) {
616 Explosion_SoundData.position=dynPtr->Position;
617 Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData);
618 }
619
620 /* for net game support: send a message saying we've blown up... */
621 if(AvP.Network != I_No_Network) {
622 AddNetMsg_LocalObjectDestroyed(sbPtr);
623 AddNetMsg_SpotOtherSound(SID_NICE_EXPLOSION,&dynPtr->Position,1);
624 }
625
626 /* destroy rocket */
627 DestroyAnyStrategyBlock(sbPtr);
628
629 }
630 else
631 {
632 VECTORCH line;
633 SECTION_DATA *disc_section;
634
635 /* We must be flying. Maintain sound. */
636 if(fbPtr->soundHandle!=SOUND_NOACTIVEINDEX) {
637 Sound_Update3d(fbPtr->soundHandle,&(sbPtr->DynPtr->Position));
638 if (ActiveSounds[fbPtr->soundHandle].soundIndex!=SID_PREDATOR_DISK_FLYING) {
639 Sound_Stop(fbPtr->soundHandle);
640 Sound_Play(SID_ED_SKEETERDISC_SPIN,"del",&(sbPtr->DynPtr->Position),&fbPtr->soundHandle);
641 }
642 } else {
643 Sound_Play(SID_ED_SKEETERDISC_SPIN,"del",&(sbPtr->DynPtr->Position),&fbPtr->soundHandle);
644 }
645
646 disc_section=GetThisSectionData(fbPtr->HModelController.section_data,"Mdisk");
647
648 if (disc_section) {
649 //ReleasePrintDebuggingText("Disc section found!\n");
650 line.vx=disc_section->SecMat.mat11;
651 line.vy=disc_section->SecMat.mat12;
652 line.vz=disc_section->SecMat.mat13;
653
654 //MakeParticle(&dynPtr->Position,&line,PARTICLE_PREDATOR_BLOOD);
655 /* Make a laser? */
656 // KJL 12:32:40 08/02/00 - Fox want the laser beam removed
657 fbPtr->Laser.BeamIsOn=0;
658 {
659 int l;
660 for (l=0;l<4;l++)
661 MakeFlareParticle(dynPtr);
662 }
663 /* Now do the target sweep. */
664 if (fbPtr->counter<(4*(ONE_FIXED)))
665 {
666 int a;
667 STRATEGYBLOCK *candidate,*nearest;
668 VECTORCH offset;
669 /*
670 MODULE *dmod;
671 dmod=ModuleFromPosition(&sbPtr->DynPtr->Position,playerPherModule);
672 LOCALASSERT(dmod);
673 */
674 nearest=NULL;
675
676 for (a=0; a<NumActiveStBlocks; a++)
677 {
678 candidate=ActiveStBlockList[a];
679
680 if (candidate!=sbPtr)
681 {
682 if (candidate->DynPtr)
683 {
684 if (Frisbee_TargetFilter(candidate))
685 {
686 /* Check visibility? */
687 if ((candidate->SBdptr)&&(sbPtr->SBdptr))
688 {
689 /* Near case. */
690 if ((!NPC_IsDead(candidate))
691 ||(candidate->I_SBtype==I_BehaviourMarinePlayer)
692 ||(candidate->I_SBtype==I_BehaviourDummy))
693 {
694 if (NPCCanSeeTarget(sbPtr, candidate, ONE_FIXED))
695 {
696 VECTORCH targetPos;
697 nearest=candidate;
698
699 /* Shoot it, */
700 GetTargetingPointOfObject_Far(nearest,&targetPos);
701
702 if (CalculateFiringSolution(&sbPtr->DynPtr->Position,&nearest->DynPtr->Position,
703 &nearest->DynPtr->LinVelocity,ENERGY_BOLT_SPEED,&offset)) {
704 /* Use this. */
705 } else {
706 offset.vx=targetPos.vx-sbPtr->DynPtr->Position.vx;
707 offset.vy=targetPos.vy-sbPtr->DynPtr->Position.vy;
708 offset.vz=targetPos.vz-sbPtr->DynPtr->Position.vz;
709 Normalise(&offset);
710 }
711
712 {
713 MATRIXCH mat;
714 MatrixFromZVector(&offset,&mat);
715 InitialiseFrisbeeBoltBehaviourKernel(&sbPtr->DynPtr->Position,&mat, 0,
716 &TemplateAmmo[AMMO_FRISBEE].MaxDamage[AvP.Difficulty], 65536);
717
718 }
719 }
720 }
721 }
722 else
723 {
724 if ((!NPC_IsDead(candidate))
725 ||(candidate->I_SBtype==I_BehaviourMarinePlayer)
726 ||(candidate->I_SBtype==I_BehaviourDummy))
727 {
728
729 if (dmod)
730 {
731 if ((IsModuleVisibleFromModule(dmod,candidate->containingModule)))
732 {
733 VECTORCH targetPos;
734 nearest=candidate;
735
736 /* Shoot it, */
737 GetTargetingPointOfObject_Far(nearest,&targetPos);
738
739 if (CalculateFiringSolution(&sbPtr->DynPtr->Position,&nearest->DynPtr->Position,
740 &nearest->DynPtr->LinVelocity,ENERGY_BOLT_SPEED,&offset)) {
741 /* Use this. */
742 } else {
743 offset.vx=targetPos.vx-sbPtr->DynPtr->Position.vx;
744 offset.vy=targetPos.vy-sbPtr->DynPtr->Position.vy;
745 offset.vz=targetPos.vz-sbPtr->DynPtr->Position.vz;
746 Normalise(&offset);
747 }
748
749 {
750 MATRIXCH mat;
751 MatrixFromZVector(&offset,&mat);
752 InitialiseFrisbeeBoltBehaviourKernel(&sbPtr->DynPtr->Position,&mat, 0,
753 &TemplateAmmo[AMMO_FRISBEE].MaxDamage[AvP.Difficulty], 65536);
754 }
755 }
756 }
757 }
758 }
759 }
760 }
761 }
762 }
763 if (nearest)
764 {
765 /* And explode. */
766
767 HandleEffectsOfExplosion
768 (
769 sbPtr,
770 &(dynPtr->Position),
771 TemplateAmmo[AMMO_FRISBEE_FIRE].MaxRange,
772 &TemplateAmmo[AMMO_FRISBEE_FIRE].MaxDamage[AvP.Difficulty],
773 TemplateAmmo[AMMO_FRISBEE_FIRE].ExplosionIsFlat
774 );
775
776 if (sbPtr->containingModule) {
777 Explosion_SoundData.position=dynPtr->Position;
778 Sound_Play(SID_ED_SKEETERPLASMAFIRE,"n",&Explosion_SoundData);
779 }
780
781 /* for net game support: send a message saying we've blown up... */
782 if(AvP.Network != I_No_Network) {
783 AddNetMsg_LocalObjectDestroyed(sbPtr);
784 AddNetMsg_SpotOtherSound(SID_ED_SKEETERPLASMAFIRE,&dynPtr->Position,1);
785 }
786
787 /* destroy rocket */
788 DestroyAnyStrategyBlock(sbPtr);
789 }
790 }
791 } else {
792 //ReleasePrintDebuggingText("No disc section found!\n");
793 }
794 fbPtr->counter-=NormalFrameTime;
795 }
796 }
797
798
799 /* KJL 14:08:18 02/21/97 - New rocket & grenade functions */
800
801 STRATEGYBLOCK* CreateRocketKernel(VECTORCH *position, MATRIXCH *orient, int fromplayer) {
802
803 DISPLAYBLOCK *dispPtr;
804 DYNAMICSBLOCK *dynPtr;
805
806 /* make displayblock with correct shape, etc */
807 dispPtr = MakeObject(I_BehaviourRocket,position);
808 if (dispPtr == 0) return NULL; // Failed to allocate display block
809
810 /* make displayblock a dynamic module object */
811 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
812
813 /* add lighting effect */
814 AddLightingEffectToObject(dispPtr,LFX_ROCKETJET);
815
816 /* setup dynamics block */
817 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
818
819 if (fromplayer==0) {
820 dynPtr->IgnoreThePlayer=0;
821 }
822
823 if (dynPtr == 0)
824 {
825 // Failed to allocate a dynamics block
826 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
827 return NULL;
828 }
829
830 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
831
832 /* give missile a maximum lifetime */
833 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK));
834
835 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
836 {
837 // Failed to allocate a strategy block data pointer
838 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
839 return NULL;
840 }
841
842 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
843 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = fromplayer;
844
845 /* align rocket to launcher */
846 dynPtr->Position=*position;
847 dynPtr->PrevPosition=*position;
848
849 dynPtr->OrientMat = *orient;
850 dynPtr->PrevOrientMat = dynPtr->OrientMat;
851 /* I added this next line for networking: Patrick */
852 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
853
854 /* align velocity too */
855 #define MISSILE_SPEED 80000
856 dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31;
857 dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32;
858 dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33;
859
860 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, MISSILE_SPEED);
861 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, MISSILE_SPEED);
862 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, MISSILE_SPEED);
863
864 /* for net game support */
865 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
866
867 return dispPtr->ObStrategyBlock;
868
869 }
870
871 static void InitialiseFrisbeeBehaviour(void)
872 {
873 VECTORCH position;
874
875 /* calculate the position */
876 {
877 extern VECTORCH CentreOfMuzzleOffset;
878 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
879 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
880 position = CentreOfMuzzleOffset;
881
882 RotateVector(&position,&PlayersWeapon.ObMat);
883
884 position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx;
885 position.vx = position.vx/4 + VDBPtr->VDB_World.vx;
886
887 position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy;
888 position.vy = position.vy/4 + VDBPtr->VDB_World.vy;
889
890 position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz;
891 position.vz = position.vz/4 + VDBPtr->VDB_World.vz;
892 }
893
894 CreateFrisbeeKernel(&position,&PlayersWeapon.ObMat,1);
895 }
896
897 static void InitialiseRocketBehaviour(void)
898 {
899 VECTORCH position;
900
901 /* calculate the position */
902 {
903 extern VECTORCH CentreOfMuzzleOffset;
904 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
905 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
906 position = CentreOfMuzzleOffset;
907
908 RotateVector(&position,&PlayersWeapon.ObMat);
909
910 position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx;
911 position.vx = position.vx/4 + VDBPtr->VDB_World.vx;
912
913 position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy;
914 position.vy = position.vy/4 + VDBPtr->VDB_World.vy;
915
916 position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz;
917 position.vz = position.vz/4 + VDBPtr->VDB_World.vz;
918 }
919
920 CreateRocketKernel(&position,&PlayersWeapon.ObMat,1);
921 }
922
923 extern void RocketBehaviour(STRATEGYBLOCK *sbPtr)
924 {
925 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
926 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
927 PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->SBdataptr;
928
929 MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position));
930
931 if (reportPtr || (bbPtr->counter<=0) )
932 {
933
934 if (reportPtr) {
935 if (reportPtr->ObstacleSBPtr) {
936 VECTORCH attack_dir;
937
938 if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) {
939 if (bbPtr->player) {
940 int slot;
941 /* Log accuracy! */
942 slot=SlotForThisWeapon(WEAPON_SADAR);
943 if (slot!=-1) {
944 CurrentGameStats_WeaponHit(slot,1);
945 }
946 }
947 }
948
949 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
950 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_SADAR_TOW].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
951 }
952 }
953
954 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
955 HandleEffectsOfExplosion
956 (
957 sbPtr,
958 &(dynPtr->Position),
959 TemplateAmmo[AMMO_SADAR_BLAST].MaxRange,
960 &TemplateAmmo[AMMO_SADAR_BLAST].MaxDamage[AvP.Difficulty],
961 TemplateAmmo[AMMO_SADAR_BLAST].ExplosionIsFlat
962 );
963
964 if (sbPtr->containingModule) {
965 Explosion_SoundData.position=dynPtr->Position;
966 Sound_Play(SID_NICE_EXPLOSION,"n",&Explosion_SoundData);
967 }
968
969 /* for net game support: send a message saying we've blown up... */
970 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
971
972 /* destroy rocket */
973 DestroyAnyStrategyBlock(sbPtr);
974
975 }
976 else
977 {
978 bbPtr->counter-=NormalFrameTime;
979 //dynPtr->IgnoreThePlayer=0;
980 }
981 }
982
983 STRATEGYBLOCK* CreateGrenadeKernel(AVP_BEHAVIOUR_TYPE behaviourID, VECTORCH *position, MATRIXCH *orient,int fromplayer) {
984
985 DISPLAYBLOCK *dispPtr;
986 DYNAMICSBLOCK *dynPtr;
987
988 /* make displayblock with correct shape, etc */
989 dispPtr = MakeObject(behaviourID,position);
990 if (dispPtr == 0) return NULL; // Failed to allocate display block
991
992 /* make displayblock a dynamic module object */
993 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
994
995 switch(behaviourID)
996 {
997 case I_BehaviourFlareGrenade:
998 {
999 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(FLARE_BEHAV_BLOCK));
1000 break;
1001 }
1002 case I_BehaviourProximityGrenade:
1003 {
1004 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PROX_GRENADE_BEHAV_BLOCK));
1005 break;
1006 }
1007 default:
1008 {
1009 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(GRENADE_BEHAV_BLOCK));
1010 break;
1011 }
1012 }
1013
1014
1015 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
1016 {
1017 // Failed to allocate a strategy block data pointer
1018 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1019 return NULL;
1020 }
1021
1022 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
1023
1024 if (fromplayer==0) {
1025 dynPtr->IgnoreThePlayer=0;
1026 }
1027
1028 if (dynPtr == 0)
1029 {
1030 // Failed to allocate a dynamics block
1031 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1032 return NULL;
1033 }
1034 /* setup dynamics block */
1035 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
1036
1037 /* align grenade to launcher */
1038 dynPtr->Position=*position;
1039 dynPtr->PrevPosition=*position;
1040 dynPtr->OrientMat = *orient;
1041 dynPtr->PrevOrientMat = dynPtr->OrientMat;
1042 /* and convert to an euler */
1043 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1044
1045 /* align velocity too */
1046 #define GRENADE_SPEED 70000
1047 dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->OrientMat.mat31,GRENADE_SPEED);
1048 dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->OrientMat.mat32,GRENADE_SPEED);
1049 dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->OrientMat.mat33,GRENADE_SPEED);
1050 dynPtr->AngImpulse.EulerX = ((FastRandom()&2047)-1024)*4;
1051 dynPtr->AngImpulse.EulerY = ((FastRandom()&2047)-1024)*4;
1052 dynPtr->AngImpulse.EulerZ = ((FastRandom()&2047)-1024)*8;
1053
1054 dynPtr->IgnoresNotVisPolys = 1;
1055
1056 switch(behaviourID)
1057 {
1058 case I_BehaviourFlareGrenade:
1059 {
1060 dynPtr->StopOnCollision = 1;
1061 ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->LifeTimeRemaining = FLARE_LIFETIME*ONE_FIXED;
1062 ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->ParticleGenerationTimer = 0;
1063 AddLightingEffectToObject(dispPtr,LFX_FLARE);
1064 ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SoundHandle = SOUND_NOACTIVEINDEX;
1065
1066 ((FLARE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->becomeStuck = 0;
1067
1068 NumberOfFlaresActive++;
1069
1070 break;
1071 }
1072 case I_BehaviourProximityGrenade:
1073 {
1074 dynPtr->StopOnCollision = 1;
1075 ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->LifeTimeRemaining = 2*ONE_FIXED;
1076 ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SoundHandle = SOUND_NOACTIVEINDEX;
1077 ((PROX_GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->SoundGenerationTimer = 0;
1078 break;
1079 }
1080 default:
1081 {
1082 ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 2*ONE_FIXED;
1083 ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->bouncelastframe = 0;
1084 break;
1085 }
1086 }
1087
1088 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
1089
1090 return dispPtr->ObStrategyBlock;
1091 }
1092
1093 static void InitialiseGrenadeBehaviour(AVP_BEHAVIOUR_TYPE behaviourID)
1094 {
1095 VECTORCH position;
1096
1097 /* calculate the position */
1098 {
1099 extern VECTORCH CentreOfMuzzleOffset;
1100 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
1101 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
1102 position = CentreOfMuzzleOffset;
1103
1104 RotateVector(&position,&PlayersWeapon.ObMat);
1105
1106 position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx;
1107 position.vx = position.vx/4 + VDBPtr->VDB_World.vx;
1108
1109 position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy;
1110 position.vy = position.vy/4 + VDBPtr->VDB_World.vy;
1111
1112 position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz;
1113 position.vz = position.vz/4 + VDBPtr->VDB_World.vz;
1114 }
1115
1116 CreateGrenadeKernel(behaviourID,&position,&PlayersWeapon.ObMat,1);
1117
1118 }
1119
1120
1121 extern void GrenadeBehaviour(STRATEGYBLOCK *sbPtr)
1122 {
1123 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1124 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
1125 GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
1126 int explodeNow = 0;
1127 int bounce=0;
1128
1129 /* some sort of trail would look good */
1130 /* but calling this takes bloody ages */
1131 MakeGrenadeTrailParticles(&dynPtr->PrevPosition,&dynPtr->Position);
1132 #if 0
1133 {
1134 VECTORCH velocity;
1135 velocity.vx = (FastRandom()&255) - 128;
1136 velocity.vy = -1000-(FastRandom()&255);
1137 velocity.vz = (FastRandom()&255) - 128;
1138 MakeParticle(&(dynPtr->Position),&(velocity),PARTICLE_BLACKSMOKE);
1139 }
1140 #endif
1141
1142 //if (reportPtr==NULL) {
1143 // dynPtr->IgnoreThePlayer=0;
1144 //}
1145 /* explode if the grenade touches an alien */
1146 if (reportPtr==NULL) {
1147 bbPtr->bouncelastframe=0;
1148 }
1149
1150 while (reportPtr)
1151 {
1152 STRATEGYBLOCK *sbPtr = reportPtr->ObstacleSBPtr;
1153
1154 bounce=1;
1155
1156 if(sbPtr)
1157 {
1158 if((sbPtr->I_SBtype == I_BehaviourAlien)
1159 ||(sbPtr->I_SBtype == I_BehaviourMarinePlayer)
1160 ||(sbPtr->I_SBtype == I_BehaviourAlienPlayer)
1161 ||(sbPtr->I_SBtype == I_BehaviourPredatorPlayer)
1162 ||(sbPtr->I_SBtype == I_BehaviourPredator)
1163 ||(sbPtr->I_SBtype == I_BehaviourXenoborg)
1164 ||(sbPtr->I_SBtype == I_BehaviourMarine)
1165 ||(sbPtr->I_SBtype == I_BehaviourQueenAlien)
1166 ||(sbPtr->I_SBtype == I_BehaviourPredatorAlien)
1167 ||(sbPtr->I_SBtype == I_BehaviourFaceHugger))
1168 {
1169 explodeNow = 1; /* kaboom */
1170 }
1171
1172 if(sbPtr->I_SBtype == I_BehaviourNetGhost)
1173 {
1174 NETGHOSTDATABLOCK *ghostData = sbPtr->SBdataptr;
1175 LOCALASSERT(ghostData);
1176 LOCALASSERT(AvP.Network!=I_No_Network);
1177
1178 if((ghostData->type == I_BehaviourMarinePlayer)||
1179 (ghostData->type == I_BehaviourPredatorPlayer)||
1180 (ghostData->type == I_BehaviourAlienPlayer)||
1181 (ghostData->type == I_BehaviourAlien))
1182 {
1183 explodeNow = 1;
1184 }
1185 }
1186 } else {
1187 dynPtr->IgnoreThePlayer=0;
1188 }
1189
1190 /* skip to next report */
1191 reportPtr = reportPtr->NextCollisionReportPtr;
1192 }
1193
1194 if (bounce&&(explodeNow==0)&&(bbPtr->bouncelastframe==0)) {
1195 Sound_Play(SID_GRENADE_BOUNCE,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
1196 bbPtr->bouncelastframe=1;
1197 }
1198
1199 if ((bbPtr->counter<=0) || explodeNow)
1200 {
1201 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
1202 HandleEffectsOfExplosion
1203 (
1204 sbPtr,
1205 &(dynPtr->Position),
1206 TemplateAmmo[AMMO_GRENADE].MaxRange,
1207 &TemplateAmmo[AMMO_GRENADE].MaxDamage[AvP.Difficulty],
1208 TemplateAmmo[AMMO_GRENADE].ExplosionIsFlat
1209 );
1210
1211 if (sbPtr->containingModule) {
1212 Explosion_SoundData.position=dynPtr->Position;
1213 Sound_Play(SID_ED_GRENADE_EXPLOSION,"n",&Explosion_SoundData);
1214 }
1215
1216 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
1217
1218 /* destroy rocket */
1219 DestroyAnyStrategyBlock(sbPtr);
1220 }
1221 else
1222 {
1223 bbPtr->counter-=NormalFrameTime;
1224 DynamicallyRotateObject(dynPtr);
1225 }
1226 }
1227 extern void ClusterGrenadeBehaviour(STRATEGYBLOCK *sbPtr)
1228 {
1229 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1230 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
1231 GRENADE_BEHAV_BLOCK *bbPtr = (GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
1232 int explodeNow = 0;
1233 int bounce=0;
1234
1235 {
1236 VECTORCH velocity;
1237 velocity.vx = (FastRandom()&255) - 128;
1238 velocity.vy = -1000-(FastRandom()&255);
1239 velocity.vz = (FastRandom()&255) - 128;
1240 MakeParticle(&(dynPtr->Position),&(velocity),PARTICLE_BLACKSMOKE);
1241 }
1242
1243 //if (reportPtr==NULL) {
1244 // dynPtr->IgnoreThePlayer=0;
1245 //}
1246 /* explode if the grenade touches an alien */
1247 if (reportPtr==NULL) {
1248 bbPtr->bouncelastframe=0;
1249 }
1250
1251 while (reportPtr)
1252 {
1253 STRATEGYBLOCK *sbPtr = reportPtr->ObstacleSBPtr;
1254
1255 bounce=1;
1256
1257 if (sbPtr)
1258 {
1259 if((sbPtr->I_SBtype == I_BehaviourAlien)
1260 ||(sbPtr->I_SBtype == I_BehaviourMarinePlayer)
1261 ||(sbPtr->I_SBtype == I_BehaviourAlienPlayer)
1262 ||(sbPtr->I_SBtype == I_BehaviourPredatorPlayer)
1263 ||(sbPtr->I_SBtype == I_BehaviourPredator)
1264 ||(sbPtr->I_SBtype == I_BehaviourXenoborg)
1265 ||(sbPtr->I_SBtype == I_BehaviourMarine)
1266 ||(sbPtr->I_SBtype == I_BehaviourQueenAlien)
1267 ||(sbPtr->I_SBtype == I_BehaviourPredatorAlien)
1268 ||(sbPtr->I_SBtype == I_BehaviourFaceHugger))
1269 {
1270 explodeNow = 1; /* kaboom */
1271 }
1272
1273 if(sbPtr->I_SBtype == I_BehaviourNetGhost)
1274 {
1275 NETGHOSTDATABLOCK *ghostData = sbPtr->SBdataptr;
1276 LOCALASSERT(ghostData);
1277 LOCALASSERT(AvP.Network!=I_No_Network);
1278
1279 if((ghostData->type == I_BehaviourMarinePlayer)||
1280 (ghostData->type == I_BehaviourPredatorPlayer)||
1281 (ghostData->type == I_BehaviourAlienPlayer)||
1282 (ghostData->type == I_BehaviourAlien))
1283 {
1284 explodeNow = 1;
1285 }
1286 }
1287 } else {
1288 dynPtr->IgnoreThePlayer=0;
1289 }
1290
1291 /* skip to next report */
1292 reportPtr = reportPtr->NextCollisionReportPtr;
1293 }
1294
1295 if (bounce&&(explodeNow==0)&&(bbPtr->bouncelastframe==0)) {
1296 Sound_Play(SID_GRENADE_BOUNCE,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
1297 bbPtr->bouncelastframe=1;
1298 }
1299
1300 if ((bbPtr->counter<=0) || explodeNow)
1301 {
1302 extern void MakeFlechetteExplosionAt(VECTORCH *positionPtr,int seed);
1303 MakeFlechetteExplosionAt(&dynPtr->Position,0);
1304 #if 0
1305 /* make explosion sprite & frag grenades */
1306 {
1307 int num;
1308 for(num=0;num<NO_OF_FRAGS_IN_CLUSTER_BOMB;num++)
1309 {
1310 InitialiseFragmentationGrenade(&(dynPtr->Position));
1311 }
1312 }
1313 #endif
1314 if (sbPtr->containingModule) {
1315 Explosion_SoundData.position=dynPtr->Position;
1316 Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
1317 }
1318 /* for net game support: send a message saying we've blown up... */
1319 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
1320
1321 /* destroy rocket */
1322 DestroyAnyStrategyBlock(sbPtr);
1323 }
1324 else
1325 {
1326 bbPtr->counter-=NormalFrameTime;
1327 DynamicallyRotateObject(dynPtr);
1328 }
1329 }
1330
1331 #if 0
1332 static void InitialiseFragmentationGrenade(VECTORCH *originPtr)
1333 {
1334 DISPLAYBLOCK *dispPtr;
1335 DYNAMICSBLOCK *dynPtr;
1336 VECTORCH position;
1337
1338 /* calculate the position */
1339 position = *originPtr;
1340
1341 /* make displayblock with correct shape, etc */
1342 dispPtr = MakeObject(I_BehaviourFragmentationGrenade,&position);
1343 if (dispPtr == 0) return; // Failed to allocate display block
1344
1345 /* make displayblock a dynamic module object */
1346 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
1347
1348 /* give grenade a maximum lifetime */
1349 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(GRENADE_BEHAV_BLOCK));
1350
1351 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
1352 {
1353 // Failed to allocate a strategy block data pointer
1354 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1355 return;
1356 }
1357
1358 ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = FRAG_LIFETIME;
1359 ((GRENADE_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->bouncelastframe = 0;
1360
1361 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
1362
1363 if (dynPtr == 0)
1364 {
1365 // Failed to allocate a dynamics block
1366 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1367 return;
1368 }
1369
1370 /* setup dynamics block */
1371 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
1372
1373 /* align grenade to launcher */
1374 dynPtr->Position=position;
1375 dynPtr->OrientMat = PlayersWeapon.ObMat;
1376 dynPtr->PrevOrientMat = dynPtr->OrientMat;
1377 /* and convert to an euler */
1378 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1379
1380 /* align velocity too */
1381 dynPtr->LinImpulse.vx = ((FastRandom()&16383)-8192);
1382 dynPtr->LinImpulse.vy = -(FastRandom()&16383)-8192;
1383 dynPtr->LinImpulse.vz = ((FastRandom()&16383)-8192);
1384 dynPtr->AngImpulse.EulerX = ((FastRandom()&2047)-1024)*4;
1385 dynPtr->AngImpulse.EulerY = ((FastRandom()&2047)-1024)*4;
1386 dynPtr->AngImpulse.EulerZ = ((FastRandom()&2047)-1024)*8;
1387
1388 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
1389 }
1390 #endif
1391
1392 extern void ProximityGrenadeBehaviour(STRATEGYBLOCK *sbPtr)
1393 {
1394 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1395 PROX_GRENADE_BEHAV_BLOCK *bbPtr = (PROX_GRENADE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
1396
1397 MakeGrenadeTrailParticles(&dynPtr->PrevPosition,&dynPtr->Position);
1398
1399 if (bbPtr->LifeTimeRemaining<=0)
1400 {
1401 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
1402 HandleEffectsOfExplosion
1403 (
1404 sbPtr,
1405 &(dynPtr->Position),
1406 TemplateAmmo[AMMO_GRENADE].MaxRange,
1407 &TemplateAmmo[AMMO_GRENADE].MaxDamage[AvP.Difficulty],
1408 TemplateAmmo[AMMO_GRENADE].ExplosionIsFlat
1409 );
1410
1411 if (bbPtr->SoundHandle!=SOUND_NOACTIVEINDEX)
1412 {
1413 Sound_Stop(bbPtr->SoundHandle);
1414 bbPtr->SoundHandle = SOUND_NOACTIVEINDEX;
1415
1416 }
1417
1418 if (sbPtr->containingModule) {
1419 Explosion_SoundData.position=dynPtr->Position;
1420 Sound_Play(SID_ED_GRENADE_PROXEXPLOSION,"n",&Explosion_SoundData);
1421 }
1422
1423 /* for net game support: send a message saying we've blown up... */
1424 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
1425
1426 /* destroy! */
1427 DestroyAnyStrategyBlock(sbPtr);
1428 return;
1429 }
1430 else if (dynPtr->IsStatic && bbPtr->LifeTimeRemaining>PROX_GRENADE_TRIGGER_TIME)
1431 {
1432 // scan for objects in proximity
1433 extern int NumActiveStBlocks;
1434 extern STRATEGYBLOCK *ActiveStBlockList[];
1435 int i = NumActiveStBlocks;
1436
1437 {
1438 int scale = ONE_FIXED-bbPtr->LifeTimeRemaining/PROX_GRENADE_LIFETIME;
1439 scale = MUL_FIXED(scale,scale);
1440 scale = MUL_FIXED(scale,scale)*8;
1441 bbPtr->SoundGenerationTimer += NormalFrameTime + MUL_FIXED(NormalFrameTime,scale);
1442 }
1443 while (bbPtr->SoundGenerationTimer >= PROX_GRENADE_SOUND_GENERATION_TIME)
1444 {
1445 bbPtr->SoundGenerationTimer -= PROX_GRENADE_SOUND_GENERATION_TIME;
1446 Sound_Play(SID_PROX_GRENADE_ACTIVE,"d",&(dynPtr->Position));
1447 }
1448
1449
1450 while (i--)
1451 {
1452 STRATEGYBLOCK *obstaclePtr = ActiveStBlockList[i];
1453 DYNAMICSBLOCK *obstacleDynPtr = obstaclePtr->DynPtr;
1454
1455 if (obstacleDynPtr)
1456 {
1457 if(ValidTargetForProxMine(obstaclePtr))
1458 {
1459 VECTORCH disp = obstacleDynPtr->Position;
1460 disp.vx -= dynPtr->Position.vx;
1461 disp.vy -= dynPtr->Position.vy;
1462 disp.vz -= dynPtr->Position.vz;
1463
1464 if (Approximate3dMagnitude(&disp)<=PROX_GRENADE_RANGE)
1465 {
1466 bbPtr->LifeTimeRemaining = PROX_GRENADE_TRIGGER_TIME;
1467 }
1468 }
1469 }
1470 }
1471 }
1472 else
1473 {
1474 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
1475
1476 if (reportPtr)
1477 {
1478 char stickWhereYouAre = 0;
1479
1480 STRATEGYBLOCK *obstaclePtr = reportPtr->ObstacleSBPtr;
1481
1482 if (obstaclePtr)
1483 {
1484 DISPLAYBLOCK *dispPtr = obstaclePtr->SBdptr;
1485
1486 if(ValidTargetForProxMine(obstaclePtr))
1487 {
1488 /* best blow up then */
1489 bbPtr->LifeTimeRemaining=0;
1490 return;
1491 }
1492 else if (dispPtr)
1493 {
1494 if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl))
1495 {
1496 stickWhereYouAre=1;
1497 }
1498 }
1499 }
1500 else
1501 {
1502 stickWhereYouAre = 1;
1503 }
1504
1505
1506 if(stickWhereYouAre)
1507 {
1508 dynPtr->IsStatic=1;
1509 dynPtr->PrevPosition=dynPtr->Position;
1510 MakeMatrixFromDirection(&(reportPtr->ObstacleNormal),&(dynPtr->OrientMat));
1511 /* KJL 15:27:42 23/01/99 - Euler has to be filled out for network play! */
1512 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1513 bbPtr->LifeTimeRemaining = PROX_GRENADE_LIFETIME*ONE_FIXED;
1514 }
1515 }
1516 }
1517
1518 if (bbPtr->LifeTimeRemaining<=PROX_GRENADE_TRIGGER_TIME && bbPtr->SoundHandle==SOUND_NOACTIVEINDEX)
1519 {
1520 Sound_Play(SID_PROX_GRENADE_READYTOBLOW,"de",&(dynPtr->Position),&bbPtr->SoundHandle);
1521 }
1522 bbPtr->LifeTimeRemaining-=NormalFrameTime;
1523
1524
1525 }
1526
1527 int ValidTargetForProxMine(STRATEGYBLOCK *obstaclePtr)
1528 {
1529 if((obstaclePtr->I_SBtype == I_BehaviourAlien)
1530 ||(obstaclePtr->I_SBtype == I_BehaviourMarinePlayer)
1531 ||(obstaclePtr->I_SBtype == I_BehaviourAlienPlayer)
1532 ||(obstaclePtr->I_SBtype == I_BehaviourPredatorPlayer)
1533 ||(obstaclePtr->I_SBtype == I_BehaviourPredator)
1534 ||(obstaclePtr->I_SBtype == I_BehaviourXenoborg)
1535 ||(obstaclePtr->I_SBtype == I_BehaviourMarine)
1536 ||(obstaclePtr->I_SBtype == I_BehaviourQueenAlien)
1537 ||(obstaclePtr->I_SBtype == I_BehaviourFaceHugger))
1538 {
1539 return 1;
1540 }
1541
1542 if(obstaclePtr->I_SBtype == I_BehaviourNetGhost)
1543 {
1544 NETGHOSTDATABLOCK *ghostDataPtr = (NETGHOSTDATABLOCK *)obstaclePtr->SBdataptr;
1545
1546 if (ghostDataPtr->type==I_BehaviourAlienPlayer
1547 ||ghostDataPtr->type==I_BehaviourMarinePlayer
1548 ||ghostDataPtr->type==I_BehaviourPredatorPlayer
1549 ||ghostDataPtr->type==I_BehaviourAlien)
1550 {
1551 return 1;
1552 }
1553 }
1554 return 0;
1555 }
1556
1557
1558 extern void FlareGrenadeBehaviour(STRATEGYBLOCK *sbPtr)
1559 {
1560 FLARE_BEHAV_BLOCK *bbPtr = (FLARE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
1561 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1562
1563
1564 if ((bbPtr->LifeTimeRemaining<=0))
1565 {
1566 if (bbPtr->SoundHandle!=SOUND_NOACTIVEINDEX)
1567 {
1568 Sound_Stop(bbPtr->SoundHandle);
1569 bbPtr->SoundHandle = SOUND_NOACTIVEINDEX;
1570
1571 }
1572
1573 /* for net game support: send a message saying we've blown up... */
1574 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
1575
1576 /* destroy rocket */
1577 DestroyAnyStrategyBlock(sbPtr);
1578
1579
1580 NumberOfFlaresActive--;
1581 return;
1582 }
1583
1584 {
1585 if (bbPtr->LifeTimeRemaining>ONE_FIXED*4)
1586 {
1587 bbPtr->ParticleGenerationTimer += NormalFrameTime;
1588 }
1589 else
1590 {
1591 bbPtr->ParticleGenerationTimer += MUL_FIXED(NormalFrameTime,bbPtr->LifeTimeRemaining)/4;
1592 }
1593
1594 while (bbPtr->ParticleGenerationTimer >= FLARE_PARTICLE_GENERATION_TIME)
1595 {
1596 bbPtr->ParticleGenerationTimer -= FLARE_PARTICLE_GENERATION_TIME;
1597 MakeFlareParticle(dynPtr);
1598 }
1599
1600 /* add lighting effect */
1601 {
1602 LIGHTBLOCK *lightPtr = sbPtr->SBdptr->ObLights[0];
1603 LOCALASSERT(sbPtr->SBdptr->ObNumLights==1);
1604 lightPtr->LightBright = 1+MUL_FIXED
1605 (
1606 (ONE_FIXED*4-(FastRandom()&32767)),
1607 bbPtr->LifeTimeRemaining/FLARE_LIFETIME
1608 );
1609 }
1610
1611 bbPtr->LifeTimeRemaining-=NormalFrameTime;
1612 }
1613
1614 if (dynPtr->IsFloating)
1615 {
1616 RubberDuckBehaviour(sbPtr);
1617 }
1618 else if (!dynPtr->IsStatic)
1619 {
1620 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
1621
1622 //if (reportPtr==NULL) {
1623 // dynPtr->IgnoreThePlayer=0;
1624 //}
1625 if (reportPtr)
1626 {
1627 char stickWhereYouAre = 0;
1628
1629 if (reportPtr->ObstacleSBPtr)
1630 {
1631 DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr;
1632 if (dispPtr)
1633 if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl))
1634 {
1635 stickWhereYouAre=1;
1636 }
1637 }
1638 else
1639 {
1640 stickWhereYouAre = 1;
1641 }
1642
1643
1644 if(stickWhereYouAre)
1645 {
1646 dynPtr->IsStatic=1;
1647 dynPtr->OnlyCollideWithEnvironment = 1;
1648 dynPtr->PrevPosition=dynPtr->Position;
1649 MakeMatrixFromDirection(&(reportPtr->ObstacleNormal),&(dynPtr->OrientMat));
1650 /* KJL 15:27:42 23/01/99 - Euler has to be filled out for network play! */
1651 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1652 Sound_Play(SID_BURNING_FLARE,"dle",&(dynPtr->Position),&bbPtr->SoundHandle);
1653
1654 //set flag ,so appropriate net message gets sent
1655 bbPtr->becomeStuck=1;
1656
1657 }
1658 }
1659 // DynamicallyRotateObject(dynPtr);
1660 }
1661 }
1662
1663 static STRATEGYBLOCK* InitialisePulseGrenadeBehaviour(void)
1664 {
1665 /* more of a rocket than a grenade... */
1666 DISPLAYBLOCK *dispPtr;
1667 DYNAMICSBLOCK *dynPtr;
1668 VECTORCH position;
1669
1670 /* calculate the position */
1671 {
1672 extern VECTORCH CentreOfMuzzleOffset;
1673 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
1674 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
1675 position = CentreOfMuzzleOffset;
1676
1677 RotateVector(&position,&PlayersWeapon.ObMat);
1678
1679 position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx;
1680 position.vx = position.vx/4 + VDBPtr->VDB_World.vx;
1681
1682 position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy;
1683 position.vy = position.vy/4 + VDBPtr->VDB_World.vy;
1684
1685 position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz;
1686 position.vz = position.vz/4 + VDBPtr->VDB_World.vz;
1687 }
1688
1689 /* make displayblock with correct shape, etc */
1690 dispPtr = MakeObject(I_BehaviourPulseGrenade,&position);
1691 if (dispPtr == 0) return NULL; // Failed to allocate display block
1692
1693 /* add lighting effect */
1694 AddLightingEffectToObject(dispPtr,LFX_ROCKETJET);
1695
1696 /* setup dynamics block */
1697 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
1698
1699 if (dynPtr == 0)
1700 {
1701 // Failed to allocate a dynamics block
1702 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1703 return NULL;
1704 }
1705
1706 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
1707
1708 /* give missile a maximum lifetime */
1709 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK));
1710
1711 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
1712 {
1713 // Failed to allocate a strategy block data pointer
1714 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1715 return NULL;
1716 }
1717
1718 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
1719 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = 1;
1720
1721 /* align rocket to launcher */
1722 dynPtr->Position=position;
1723 dynPtr->PrevPosition=position;
1724 dynPtr->OrientMat = PlayersWeapon.ObMat;
1725 dynPtr->PrevOrientMat = dynPtr->OrientMat;
1726
1727 /* align velocity too */
1728 #define PULSEGRENADE_SPEED 100000 // Was 30000
1729 GetGunDirection(&(dynPtr->LinVelocity),&position);
1730 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, PULSEGRENADE_SPEED);
1731 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, PULSEGRENADE_SPEED);
1732 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, PULSEGRENADE_SPEED);
1733
1734 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
1735
1736 return dispPtr->ObStrategyBlock;
1737 }
1738
1739
1740 extern void PulseGrenadeBehaviour(STRATEGYBLOCK *sbPtr)
1741 {
1742 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
1743 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
1744 PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->SBdataptr;
1745
1746 MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position));
1747
1748 //Work out the containing module now , since it doesn't seem to get done anywhere else
1749 sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), sbPtr->containingModule);
1750
1751
1752 //if (reportPtr==NULL) {
1753 // dynPtr->IgnoreThePlayer=0;
1754 //}
1755 if (reportPtr || (bbPtr->counter<=0) )
1756 {
1757
1758 if (reportPtr) {
1759 if (reportPtr->ObstacleSBPtr) {
1760 VECTORCH attack_dir;
1761
1762 if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) {
1763 if (bbPtr->player) {
1764 int slot;
1765 /* Log accuracy! */
1766 slot=SlotForThisWeapon(WEAPON_PULSERIFLE);
1767 if (slot!=-1) {
1768 CurrentGameStats_WeaponHit(slot,1);
1769 }
1770 }
1771 }
1772
1773 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
1774 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PULSE_GRENADE_STRIKE].MaxDamage[AvP.Difficulty], ONE_FIXED,&attack_dir);
1775 }
1776 }
1777
1778 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
1779 HandleEffectsOfExplosion
1780 (
1781 sbPtr,
1782 &(dynPtr->Position),
1783 TemplateAmmo[AMMO_PULSE_GRENADE].MaxRange,
1784 &TemplateAmmo[AMMO_PULSE_GRENADE].MaxDamage[AvP.Difficulty],
1785 TemplateAmmo[AMMO_PULSE_GRENADE].ExplosionIsFlat
1786 );
1787
1788 if (sbPtr->containingModule) {
1789 Explosion_SoundData.position=dynPtr->Position;
1790 Sound_Play(SID_NADEEXPLODE,"n",&Explosion_SoundData);
1791 }
1792
1793 /* for net game support: send a message saying we've blown up... */
1794 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
1795
1796 /* destroy rocket */
1797 DestroyAnyStrategyBlock(sbPtr);
1798 }
1799 else
1800 {
1801 bbPtr->counter-=NormalFrameTime;
1802 }
1803 }
1804
1805 STRATEGYBLOCK* InitialiseEnergyBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor) {
1806
1807 DISPLAYBLOCK *dispPtr;
1808 DYNAMICSBLOCK *dynPtr;
1809
1810 /* make displayblock with correct shape, etc */
1811 dispPtr = MakeObject(I_BehaviourPredatorEnergyBolt,position);
1812 if (dispPtr == 0) return NULL; // Failed to allocate display block
1813
1814 dispPtr->SfxPtr = AllocateSfxBlock();
1815
1816 if (!dispPtr->SfxPtr)
1817 {
1818 // Failed to allocate a special fx block
1819 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1820 return NULL;
1821 }
1822
1823 dispPtr->SfxPtr->SfxID = SFX_PREDATOR_PLASMA_BOLT;
1824 /* make displayblock a dynamic module object */
1825 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
1826 dispPtr->ObShape = 0;
1827 dispPtr->ObStrategyBlock->shapeIndex = 0;
1828 dispPtr->ObMinX = -50;
1829 dispPtr->ObMinY = -50;
1830 dispPtr->ObMinZ = -50;
1831 dispPtr->ObMaxX = 50;
1832 dispPtr->ObMaxY = 50;
1833 dispPtr->ObMaxZ = 50;
1834 /* add lighting effect */
1835 AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT);
1836
1837 /* setup dynamics block */
1838 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
1839
1840 if (dynPtr == 0)
1841 {
1842 // Failed to allocate a dynamics block
1843 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1844 return NULL;
1845 }
1846
1847 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
1848
1849 /* give missile a maximum lifetime */
1850 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK));
1851
1852 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
1853 {
1854 // Failed to allocate a strategy block data pointer
1855 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1856 return NULL;
1857 }
1858
1859 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
1860 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->damage = *damage;
1861 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->blast_radius = MUL_FIXED(factor,Caster_BlastRadius);
1862 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = player;
1863 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->soundHandle = SOUND_NOACTIVEINDEX;
1864
1865 /* align rocket to launcher */
1866 dynPtr->Position=*position;
1867 dynPtr->PrevPosition=*position;
1868
1869 //GetGunDirection(&(dynPtr->LinVelocity),&position);
1870 //MakeMatrixFromDirection(&(dynPtr->LinVelocity),&(dynPtr->OrientMat));
1871 //MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1872 //dynPtr->PrevOrientMat = dynPtr->OrientMat;
1873
1874 /* align velocity too */
1875 dynPtr->OrientMat = *orient;
1876 dynPtr->PrevOrientMat = dynPtr->OrientMat;
1877 /* I added this next line for networking: Patrick */
1878 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1879
1880 /* align velocity too */
1881 dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31;
1882 dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32;
1883 dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33;
1884
1885 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, ENERGY_BOLT_SPEED);
1886 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, ENERGY_BOLT_SPEED);
1887 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, ENERGY_BOLT_SPEED);
1888
1889
1890 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
1891
1892 /* Extra cunning! */
1893 Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&dynPtr->Position);
1894
1895 if (player==0) {
1896 dynPtr->IgnoreThePlayer=0;
1897 }
1898
1899 return dispPtr->ObStrategyBlock;
1900 }
1901
1902 void InitialiseEnergyBoltBehaviour(DAMAGE_PROFILE *damage, int factor)
1903 {
1904 VECTORCH position={-300,0,0};
1905
1906 /* calculate the position */
1907 {
1908 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
1909 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
1910
1911 MATRIXCH matrix = VDBPtr->VDB_Mat;
1912 TransposeMatrixCH(&matrix);
1913
1914 RotateVector(&position,&matrix);
1915
1916 position.vx += VDBPtr->VDB_World.vx;
1917 position.vy += VDBPtr->VDB_World.vy;
1918 position.vz += VDBPtr->VDB_World.vz;
1919 }
1920
1921 #if 1
1922 {
1923 VECTORCH targetDirection;
1924 MATRIXCH orient;
1925
1926 GetGunDirection(&targetDirection,&position);
1927 MakeMatrixFromDirection(&targetDirection,&orient);
1928
1929 InitialiseEnergyBoltBehaviourKernel(&position,&orient,1,damage,factor);
1930 }
1931 #else
1932 /* make displayblock with correct shape, etc */
1933 dispPtr = MakeObject(I_BehaviourPredatorEnergyBolt,&position);
1934 if (dispPtr == 0) return; // Failed to allocate display block
1935
1936 dispPtr->SfxPtr = AllocateSfxBlock();
1937
1938 if (!dispPtr->SfxPtr)
1939 {
1940 // Failed to allocate a special fx block
1941 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1942 return;
1943 }
1944
1945 dispPtr->SfxPtr->SfxID = SFX_PREDATOR_PLASMA_BOLT;
1946 /* make displayblock a dynamic module object */
1947 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
1948 dispPtr->ObShape = 0;
1949 dispPtr->ObStrategyBlock->shapeIndex = 0;
1950 /* add lighting effect */
1951 AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT);
1952
1953 /* setup dynamics block */
1954 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
1955
1956 if (dynPtr == 0)
1957 {
1958 // Failed to allocate a dynamics block
1959 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1960 return;
1961 }
1962
1963 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
1964
1965 /* give missile a maximum lifetime */
1966 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK));
1967
1968 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
1969 {
1970 // Failed to allocate a strategy block data pointer
1971 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
1972 return;
1973 }
1974
1975 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
1976 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->damage = *damage;
1977
1978 /* align rocket to launcher */
1979 dynPtr->Position=position;
1980 dynPtr->PrevPosition=position;
1981
1982 /* align velocity too */
1983 #define ENERGY_BOLT_SPEED 3000
1984 GetGunDirection(&(dynPtr->LinVelocity),&position);
1985 MakeMatrixFromDirection(&(dynPtr->LinVelocity),&(dynPtr->OrientMat));
1986 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
1987 dynPtr->PrevOrientMat = dynPtr->OrientMat;
1988
1989 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
1990
1991 /* Extra cunning! */
1992 Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&dynPtr->Position);
1993 #endif
1994 }
1995
1996 /****/
1997
1998 #if NEW_PREDPISTOL_BOLT
1999 STRATEGYBLOCK* CreatePPPlasmaBoltKernel(VECTORCH *position,MATRIXCH *orient, int player)
2000 {
2001 DISPLAYBLOCK *dispPtr;
2002 DYNAMICSBLOCK *dynPtr;
2003
2004 /* make displayblock with correct shape, etc */
2005 dispPtr = MakeObject(I_BehaviourPPPlasmaBolt,position);
2006 if (dispPtr == 0) return NULL; // Failed to allocate display block
2007
2008 dispPtr->SfxPtr = AllocateSfxBlock();
2009
2010 if (!dispPtr->SfxPtr)
2011 {
2012 // Failed to allocate a special fx block
2013 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2014 return NULL;
2015 }
2016
2017 dispPtr->SfxPtr->SfxID = SFX_SMALL_PREDATOR_PLASMA_BOLT;
2018 /* make displayblock a dynamic module object */
2019 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
2020 dispPtr->ObShape = 0;
2021 dispPtr->ObStrategyBlock->shapeIndex = 0;
2022
2023 /* add lighting effect */
2024 AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT);
2025
2026 /* setup dynamics block */
2027 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
2028
2029 if (dynPtr == 0)
2030 {
2031 // Failed to allocate a dynamics block
2032 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2033 return NULL;
2034 }
2035
2036 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
2037
2038 /* give missile a maximum lifetime */
2039 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PREDPISTOL_BEHAV_BLOCK));
2040
2041 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
2042 {
2043 // Failed to allocate a strategy block data pointer
2044 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2045 return NULL;
2046 }
2047
2048 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
2049 ((PREDPISTOL_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = player;
2050
2051 /* align rocket to launcher */
2052 dynPtr->Position=*position;
2053 dynPtr->PrevPosition=*position;
2054
2055 /* align velocity too */
2056 dynPtr->OrientMat = *orient;
2057 dynPtr->PrevOrientMat = dynPtr->OrientMat;
2058 /* I added this next line for networking: Patrick */
2059 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
2060
2061 /* align velocity too */
2062
2063 dynPtr->LinVelocity.vx = 0;
2064 dynPtr->LinVelocity.vy = 0;
2065 dynPtr->LinVelocity.vz = 0;
2066
2067 dynPtr->LinImpulse.vx = dynPtr->OrientMat.mat31;
2068 dynPtr->LinImpulse.vy = dynPtr->OrientMat.mat32;
2069 dynPtr->LinImpulse.vz = dynPtr->OrientMat.mat33;
2070
2071 dynPtr->LinImpulse.vx = MUL_FIXED(dynPtr->LinImpulse.vx, PredPistolBoltSpeed);
2072 dynPtr->LinImpulse.vy = MUL_FIXED(dynPtr->LinImpulse.vy, PredPistolBoltSpeed);
2073 dynPtr->LinImpulse.vz = MUL_FIXED(dynPtr->LinImpulse.vz, PredPistolBoltSpeed);
2074
2075 dynPtr->UseStandardGravity=0;
2076 dynPtr->GravityDirection.vx=0;
2077 dynPtr->GravityDirection.vy=PredPistolBoltGravity; /* Half gravity! */
2078 dynPtr->GravityDirection.vz=0;
2079
2080 dynPtr->StopOnCollision=1;
2081
2082 if (player==0) {
2083 dynPtr->IgnoreThePlayer=0;
2084 }
2085
2086 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
2087
2088 return dispPtr->ObStrategyBlock;
2089 }
2090 #else
2091 void CreatePPPlasmaBoltKernel(VECTORCH *position,MATRIXCH *orient, int player)
2092 {
2093 DISPLAYBLOCK *dispPtr;
2094 DYNAMICSBLOCK *dynPtr;
2095
2096 /* make displayblock with correct shape, etc */
2097 dispPtr = MakeObject(I_BehaviourPPPlasmaBolt,position);
2098 if (dispPtr == 0) return; // Failed to allocate display block
2099
2100 dispPtr->SfxPtr = AllocateSfxBlock();
2101
2102 if (!dispPtr->SfxPtr)
2103 {
2104 // Failed to allocate a special fx block
2105 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2106 return;
2107 }
2108
2109 dispPtr->SfxPtr->SfxID = SFX_SMALL_PREDATOR_PLASMA_BOLT;
2110 /* make displayblock a dynamic module object */
2111 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
2112 dispPtr->ObShape = 0;
2113 dispPtr->ObStrategyBlock->shapeIndex = 0;
2114
2115 /* add lighting effect */
2116 AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT);
2117
2118 /* setup dynamics block */
2119 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
2120
2121 if (dynPtr == 0)
2122 {
2123 // Failed to allocate a dynamics block
2124 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2125 return;
2126 }
2127
2128 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
2129
2130 /* give missile a maximum lifetime */
2131 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK));
2132
2133 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
2134 {
2135 // Failed to allocate a strategy block data pointer
2136 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2137 return;
2138 }
2139
2140 ((ONE_SHOT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
2141
2142 /* align rocket to launcher */
2143 dynPtr->Position=*position;
2144 dynPtr->PrevPosition=*position;
2145
2146 /* align velocity too */
2147 dynPtr->OrientMat = *orient;
2148 dynPtr->PrevOrientMat = dynPtr->OrientMat;
2149 /* I added this next line for networking: Patrick */
2150 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
2151
2152 /* align velocity too */
2153 #define PPBOLT_SPEED 32767
2154 dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31;
2155 dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32;
2156 dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33;
2157
2158 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, PPBOLT_SPEED);
2159 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, PPBOLT_SPEED);
2160 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, PPBOLT_SPEED);
2161
2162 if (player==0) {
2163 dynPtr->IgnoreThePlayer=0;
2164 }
2165
2166 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
2167 }
2168 #endif
2169
2170 static void InitialisePPPlasmaBoltBehaviour(void)
2171 {
2172 VECTORCH position;
2173
2174 GLOBALASSERT(PWMFSDP);
2175
2176 /* calculate the position */
2177
2178 position=PWMFSDP->World_Offset;
2179
2180 #if NEAR_WEAPON_FUDGE
2181 {
2182 VECTORCH fudgeFactor;
2183 extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
2184
2185 fudgeFactor.vx=position.vx-Global_VDB_Ptr->VDB_World.vx;
2186 fudgeFactor.vy=position.vy-Global_VDB_Ptr->VDB_World.vy;
2187 fudgeFactor.vz=position.vz-Global_VDB_Ptr->VDB_World.vz;
2188
2189 Crunch_Position_For_Players_Weapon(&fudgeFactor);
2190
2191 position=fudgeFactor;
2192 }
2193 #endif
2194
2195 CreatePPPlasmaBoltKernel(&position,&PlayersWeapon.ObMat,1);
2196
2197 }
2198
2199 #if NEW_PREDPISTOL_BOLT
2200 extern void PPPlasmaBoltBehaviour(STRATEGYBLOCK *sbPtr)
2201 {
2202 /* Now, kinda explosive. */
2203 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2204 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
2205 PREDPISTOL_BEHAV_BLOCK *bbPtr = (PREDPISTOL_BEHAV_BLOCK * ) sbPtr->SBdataptr;
2206 int explodeNow=0;
2207
2208 /* check for a collision with something */
2209 if (bbPtr->counter <= 0)
2210 {
2211 /* for net game support: send a message saying we've blown up... */
2212 explodeNow=1;
2213 }
2214 else if (reportPtr)
2215 {
2216 #if 1
2217 if(reportPtr->ObstacleSBPtr) {
2218 VECTORCH attack_dir;
2219 /* A bit more damage if it hits you? */
2220
2221 if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) {
2222 if (bbPtr->player) {
2223 int slot;
2224 /* Log accuracy! */
2225 slot=SlotForThisWeapon(WEAPON_PRED_PISTOL);
2226 if (slot!=-1) {
2227 CurrentGameStats_WeaponHit(slot,1);
2228 }
2229 }
2230 }
2231
2232 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
2233 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PREDPISTOL_STRIKE].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
2234 }
2235 #endif
2236 explodeNow=1;
2237
2238 } else {
2239 bbPtr->counter -= NormalFrameTime;
2240 }
2241
2242 if (explodeNow) {
2243
2244 HandleEffectsOfExplosion
2245 (
2246 sbPtr,
2247 &(dynPtr->Position),
2248 TemplateAmmo[AMMO_PRED_PISTOL].MaxRange,
2249 &TemplateAmmo[AMMO_PRED_PISTOL].MaxDamage[AvP.Difficulty],
2250 TemplateAmmo[AMMO_PRED_PISTOL].ExplosionIsFlat
2251 );
2252
2253
2254 #if 0
2255 MakeBloodExplosion(&dynPtr->Position,50,&dynPtr->Position,100,PARTICLE_PREDPISTOL_FLECHETTE);
2256 #endif
2257
2258 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2259
2260 DestroyAnyStrategyBlock(sbPtr);
2261 }
2262 }
2263 #else
2264 extern void PPPlasmaBoltBehaviour(STRATEGYBLOCK *sbPtr)
2265 {
2266 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2267 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
2268 ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
2269
2270 /* check for a collision with something */
2271 if (bbPtr->counter <= 0)
2272 {
2273 /* for net game support: send a message saying we've blown up... */
2274 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2275
2276 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
2277 }
2278 else if (reportPtr)
2279 {
2280 if(reportPtr->ObstacleSBPtr) {
2281 VECTORCH attack_dir;
2282 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
2283 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_PISTOL].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
2284 }
2285 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2286
2287 DestroyAnyStrategyBlock(sbPtr);
2288
2289 } else {
2290 bbPtr->counter -= NormalFrameTime;
2291 }
2292 }
2293 #endif
2294
2295 /****/
2296
2297 #define SPEAR_BOLT_SPEED (200000)
2298 #define SPEAR_PLAYER_IMPULSE (-8000)
2299 #define SPEAR_FUDGE_FACTOR (500)
2300 /* Was 50000. */
2301
2302 static void InitialiseSpeargunBoltBehaviour(void)
2303 {
2304 DISPLAYBLOCK *dispPtr;
2305 DYNAMICSBLOCK *dynPtr;
2306 VECTORCH position;
2307
2308 LOCALASSERT(0); // this routine should not be called
2309
2310 GLOBALASSERT(PWMFSDP);
2311
2312 position=PWMFSDP->World_Offset;
2313
2314 /* make displayblock with correct shape, etc */
2315 dispPtr = MakeObject(I_BehaviourSpeargunBolt,&position);
2316 if (dispPtr == 0) return; // Failed to allocate display block
2317
2318 /* KJL 17:53:36 01/08/98 - make the extents teeny-weeny */
2319 dispPtr->ObMaxX = 10;
2320 dispPtr->ObMaxY = 10;
2321 dispPtr->ObMaxZ = 10;
2322 dispPtr->ObMinX = -10;
2323 dispPtr->ObMinY = -10;
2324 dispPtr->ObMinZ = -10;
2325
2326 /* setup dynamics block */
2327 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
2328
2329 if (dynPtr == 0)
2330 {
2331 // Failed to allocate a dynamics block
2332 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2333 return;
2334 }
2335
2336 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
2337
2338 /* give missile a maximum lifetime */
2339 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(SPEAR_BEHAV_BLOCK));
2340
2341 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
2342 {
2343 // Failed to allocate a strategy block data pointer
2344 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2345 return;
2346 }
2347 memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(SPEAR_BEHAV_BLOCK));
2348
2349 ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
2350 ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Stuck = 0;
2351 /* Is this function still used? */
2352 ((SPEAR_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->Android = 0;
2353
2354 /* align rocket to launcher */
2355 dynPtr->Position=position;
2356 #if NEAR_WEAPON_FUDGE
2357 {
2358 VECTORCH fudgeFactor;
2359 extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
2360
2361 fudgeFactor.vx=dynPtr->Position.vx-Global_VDB_Ptr->VDB_World.vx;
2362 fudgeFactor.vy=dynPtr->Position.vy-Global_VDB_Ptr->VDB_World.vy;
2363 fudgeFactor.vz=dynPtr->Position.vz-Global_VDB_Ptr->VDB_World.vz;
2364
2365 Crunch_Position_For_Players_Weapon(&fudgeFactor);
2366
2367 dynPtr->Position=fudgeFactor;
2368 }
2369 #endif
2370 dynPtr->PrevPosition=position;
2371 dynPtr->OrientMat = PlayersWeapon.ObMat;
2372 dynPtr->PrevOrientMat = dynPtr->OrientMat;
2373 /* align velocity too */
2374
2375 GetGunDirection(&(dynPtr->LinVelocity),&dynPtr->Position);
2376 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx,SPEAR_BOLT_SPEED);
2377 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy,SPEAR_BOLT_SPEED);
2378 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz,SPEAR_BOLT_SPEED);
2379
2380 Player->ObStrategyBlock->DynPtr->LinImpulse.vx+=MUL_FIXED(PlayersWeapon.ObMat.mat31,SPEAR_PLAYER_IMPULSE);
2381 Player->ObStrategyBlock->DynPtr->LinImpulse.vy+=MUL_FIXED(PlayersWeapon.ObMat.mat32,SPEAR_PLAYER_IMPULSE);
2382 Player->ObStrategyBlock->DynPtr->LinImpulse.vz+=MUL_FIXED(PlayersWeapon.ObMat.mat33,SPEAR_PLAYER_IMPULSE);
2383
2384 dynPtr->Mass=1000;
2385
2386 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
2387 }
2388
2389 static DISPLAYBLOCK* InitialiseSpeargunBoltBehaviour_ForLoad(void)
2390 {
2391 DISPLAYBLOCK *dispPtr;
2392 DYNAMICSBLOCK *dynPtr;
2393 VECTORCH position = {0,0,0};
2394
2395
2396 /* make displayblock with correct shape, etc */
2397 dispPtr = MakeObject(I_BehaviourSpeargunBolt,&position);
2398 if (dispPtr == 0) return NULL; // Failed to allocate display block
2399
2400 /* KJL 17:53:36 01/08/98 - make the extents teeny-weeny */
2401 dispPtr->ObMaxX = 10;
2402 dispPtr->ObMaxY = 10;
2403 dispPtr->ObMaxZ = 10;
2404 dispPtr->ObMinX = -10;
2405 dispPtr->ObMinY = -10;
2406 dispPtr->ObMinZ = -10;
2407
2408 /* setup dynamics block */
2409 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
2410
2411 if (dynPtr == 0)
2412 {
2413 // Failed to allocate a dynamics block
2414 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2415 return NULL;
2416 }
2417
2418 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
2419
2420 /* give missile a maximum lifetime */
2421 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(SPEAR_BEHAV_BLOCK));
2422
2423 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
2424 {
2425 // Failed to allocate a strategy block data pointer
2426 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2427 return NULL;
2428 }
2429
2430 memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(SPEAR_BEHAV_BLOCK));
2431 return dispPtr;
2432 }
2433
2434
2435 extern void SpeargunBoltBehaviour(STRATEGYBLOCK *sbPtr)
2436 {
2437 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2438 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
2439 SPEAR_BEHAV_BLOCK *bbPtr = (SPEAR_BEHAV_BLOCK * ) sbPtr->SBdataptr;
2440
2441 if (!bbPtr->Stuck) {
2442 // MakeRocketTrailParticles(&(dynPtr->PrevPosition), &(dynPtr->Position));
2443 } else {
2444 /* Stuck behaviour. */
2445
2446 dynPtr->LinVelocity.vx = 0;
2447 dynPtr->LinVelocity.vy = 0;
2448 dynPtr->LinVelocity.vz = 0;
2449
2450 dynPtr->LinImpulse.vx = 0;
2451 dynPtr->LinImpulse.vy = 0;
2452 dynPtr->LinImpulse.vz = 0;
2453
2454 bbPtr->counter -= NormalFrameTime;
2455 if (bbPtr->counter <= 0)
2456 {
2457 /* for net game support: send a message saying we've blown up... */
2458 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2459 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
2460 }
2461 return;
2462 }
2463
2464 /* check for a collision with something */
2465 if (bbPtr->counter <= 0)
2466 {
2467 /* for net game support: send a message saying we've blown up... */
2468 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2469 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
2470 }
2471 else if (reportPtr)
2472 {
2473 int normDotBeta = DotProduct(&(dynPtr->LinVelocity),&(reportPtr->ObstacleNormal));
2474 char stickWhereYouAre = 0;
2475
2476 if (reportPtr->ObstacleSBPtr)
2477 {
2478 DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr;
2479 if (dispPtr)
2480 if (dispPtr->ObMyModule && (!dispPtr->ObMorphCtrl))
2481 {
2482 stickWhereYouAre=1;
2483 }
2484 }
2485 else
2486 {
2487 stickWhereYouAre = 1;
2488 }
2489
2490 if(stickWhereYouAre && normDotBeta!=0)
2491 {
2492 /* Sink in... */
2493 Sound_Play(SID_SPEARGUN_HITTING_WALL,"d",&dynPtr->Position);
2494 // MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
2495 bbPtr->Stuck=1;
2496 /* Counter at 20s. */
2497 bbPtr->counter=(20*ONE_FIXED);
2498 dynPtr->GravityOn=0;
2499 dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS;
2500
2501 {
2502 int d;
2503 {
2504 /* get a pt in the poly */
2505 VECTORCH pop = reportPtr->ObstaclePoint;
2506 pop.vx -= dynPtr->Position.vx;
2507 pop.vy -= dynPtr->Position.vy;
2508 pop.vz -= dynPtr->Position.vz;
2509
2510 /* hmm, what about double sided polys? */
2511 d = DotProduct(&(reportPtr->ObstacleNormal),&pop);
2512 }
2513
2514 {
2515 int lambda = DIV_FIXED(d,normDotBeta);
2516
2517 dynPtr->Position.vx += MUL_FIXED(lambda,dynPtr->LinVelocity.vx);
2518 dynPtr->Position.vy += MUL_FIXED(lambda,dynPtr->LinVelocity.vy);
2519 dynPtr->Position.vz += MUL_FIXED(lambda,dynPtr->LinVelocity.vz);
2520 }
2521
2522 }
2523 dynPtr->LinVelocity.vx=0;
2524 dynPtr->LinVelocity.vy=0;
2525 dynPtr->LinVelocity.vz=0;
2526 dynPtr->LinImpulse.vx=0;
2527 dynPtr->LinImpulse.vy=0;
2528 dynPtr->LinImpulse.vz=0;
2529
2530 MakeFocusedExplosion(&(dynPtr->PrevPosition), &(dynPtr->Position), 20, PARTICLE_SPARK);
2531
2532 }
2533 else
2534 {
2535 if(reportPtr->ObstacleSBPtr)
2536 {
2537 VECTORCH attack_dir;
2538 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
2539 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_RIFLE].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
2540 }
2541 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2542 DestroyAnyStrategyBlock(sbPtr);
2543 }
2544 } else {
2545 /* No collisions. */
2546 //dynPtr->IgnoreThePlayer=0;
2547
2548 bbPtr->counter -= NormalFrameTime;
2549 }
2550 }
2551
2552 /****/
2553
2554 void Crunch_Position_For_Players_Weapon(VECTORCH *position) {
2555
2556 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
2557 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
2558
2559 position->vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx;
2560 position->vx = position->vx/4 + VDBPtr->VDB_World.vx;
2561
2562 position->vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy;
2563 position->vy = position->vy/4 + VDBPtr->VDB_World.vy;
2564
2565 position->vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz;
2566 position->vz = position->vz/4 + VDBPtr->VDB_World.vz;
2567
2568 }
2569
2570 void FireFlameThrower(VECTORCH *base_position,VECTORCH *base_offset,MATRIXCH *orientmat,int player, int *timer) {
2571
2572 /* Simple function containing flamethrower function. */
2573
2574 VECTORCH position;
2575
2576 (*timer)+=NormalFrameTime;
2577
2578 while ((*timer)>=TIME_FOR_FLAMETHROWER_PARTICLE)
2579 {
2580 VECTORCH velocity;
2581
2582 (*timer)-=TIME_FOR_FLAMETHROWER_PARTICLE;
2583
2584 /* calculate the position */
2585
2586 {
2587 int offset = MUL_FIXED(FastRandom()&16383,NormalFrameTime);
2588
2589 position=*base_offset;
2590
2591 position.vz += offset;
2592 position.vy += (FastRandom()%(offset/8+1)) - offset/16;
2593 position.vx += (FastRandom()%(offset/8+1)) - offset/16;
2594 }
2595
2596 RotateVector(&position,orientmat);
2597
2598 if (player) {
2599 Crunch_Position_For_Players_Weapon(&position);
2600 } else {
2601 position.vx+=base_position->vx;
2602 position.vy+=base_position->vy;
2603 position.vz+=base_position->vz;
2604 }
2605
2606 velocity.vx = ((FastRandom()&1023) - 512);//*2;
2607 velocity.vy = ((FastRandom()&1023) - 512);//*2;
2608 velocity.vz = ((FastRandom()&511) + 200+512)*16;
2609 RotateVector(&velocity,orientmat);
2610 MakeParticle(&position,&(velocity),PARTICLE_FLAME);
2611 }
2612
2613 }
2614
2615 void FireNetGhostFlameThrower(VECTORCH *positionPtr, MATRIXCH *orientMatPtr)
2616 {
2617 /* KJL 16:31:42 27/01/98 - these particles aren't colliding, so I'll
2618 see what happens if I use more... */
2619 int i = FLAMETHROWER_PARTICLES_PER_FRAME*2;
2620
2621 VECTORCH position;
2622
2623 while(i--)
2624 /* calculate the position */
2625 {
2626 VECTORCH velocity;
2627
2628 {
2629 int offset = MUL_FIXED(FastRandom()&16383,NormalFrameTime);
2630
2631 position.vz = offset;
2632 position.vy = (FastRandom()%(offset/8+1)) - offset/16;
2633 position.vx = (FastRandom()%(offset/8+1)) - offset/16;
2634 }
2635
2636 velocity.vx = ((FastRandom()&1023) - 512);//*2;
2637 velocity.vy = ((FastRandom()&1023) - 512);//*2;
2638 velocity.vz = ((FastRandom()&511) + 200+512)*16;
2639
2640 RotateVector(&position,orientMatPtr);
2641 RotateVector(&velocity,orientMatPtr);
2642
2643 position.vx+=positionPtr->vx;
2644 position.vy+=positionPtr->vy;
2645 position.vz+=positionPtr->vz;
2646
2647 if (LocalDetailLevels.GhostFlameThrowerCollisions==0) {
2648 MakeParticle(&position,&(velocity),PARTICLE_NONCOLLIDINGFLAME);
2649 } else {
2650 MakeParticle(&position,&(velocity),PARTICLE_NONDAMAGINGFLAME);
2651 }
2652 }
2653
2654 }
2655
2656
2657 static void InitialiseFlameThrowerBehaviour(void)
2658 {
2659 VECTORCH position;
2660
2661 #if 1
2662 {
2663 int i = FLAMETHROWER_PARTICLES_PER_FRAME;
2664 while(i--)
2665 /* calculate the position */
2666 {
2667 extern VECTORCH CentreOfMuzzleOffset;
2668 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
2669 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
2670 VECTORCH velocity;
2671
2672 position = CentreOfMuzzleOffset;
2673
2674 #if 1
2675 {
2676 int offset = MUL_FIXED(FastRandom()&16383,NormalFrameTime);
2677 position.vz += offset;
2678 position.vy += (FastRandom()%(offset/8+1)) - offset/16;
2679 position.vx += (FastRandom()%(offset/8+1)) - offset/16;
2680 }
2681 #endif
2682 RotateVector(&position,&PlayersWeapon.ObMat);
2683
2684 position.vx+=PlayersWeapon.ObWorld.vx - VDBPtr->VDB_World.vx;
2685 position.vx = position.vx/4 + VDBPtr->VDB_World.vx;
2686
2687 position.vy+=PlayersWeapon.ObWorld.vy - VDBPtr->VDB_World.vy;
2688 position.vy = position.vy/4 + VDBPtr->VDB_World.vy;
2689
2690 position.vz+=PlayersWeapon.ObWorld.vz - VDBPtr->VDB_World.vz;
2691 position.vz = position.vz/4 + VDBPtr->VDB_World.vz;
2692
2693
2694
2695 velocity.vx = ((FastRandom()&1023) - 512);//*2;
2696 velocity.vy = ((FastRandom()&1023) - 512);//*2;
2697 velocity.vz = ((FastRandom()&1023) + 200)*16;
2698 RotateVector(&velocity,&(PlayersWeapon.ObMat));
2699 MakeParticle(&position,&(velocity),PARTICLE_FLAME);
2700 }
2701 }
2702 #endif
2703 }
2704
2705 /*----------------------Patrick 4/3/97--------------------------
2706 Stuff for predator (and xenoborg) projectiles...
2707 NB will need a creation function for player (AIs have their own)
2708 --------------------------------------------------------------*/
2709 extern void PredatorEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr)
2710 {
2711 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2712 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
2713 CASTER_BOLT_BEHAV_BLOCK *bbPtr = (CASTER_BOLT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
2714 STRATEGYBLOCK *victim;
2715
2716 victim=NULL;
2717
2718 if (bbPtr->damage.Impact) {
2719 MakePlasmaTrailParticles(dynPtr,bbPtr->damage.Impact);
2720 } else if(bbPtr->damage.Id==AMMO_SADAR_TOW) {
2721 MakePlasmaTrailParticles(dynPtr,100);
2722 }
2723
2724 /* check for a collision with something */
2725 if (bbPtr->counter <= 0)
2726 {
2727 /* for net game support: send a message saying we've blown up... */
2728 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2729
2730 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
2731 }
2732 else if (reportPtr)
2733 {
2734 if(reportPtr->ObstacleSBPtr)
2735 {
2736 VECTORCH attack_dir;
2737
2738 if (AccuracyStats_TargetFilter(reportPtr->ObstacleSBPtr)) {
2739 if (bbPtr->player) {
2740 int slot;
2741 /* Log accuracy! */
2742 slot=SlotForThisWeapon(WEAPON_PRED_SHOULDERCANNON);
2743 if (slot!=-1) {
2744 CurrentGameStats_WeaponHit(slot,1);
2745 }
2746 }
2747 }
2748
2749 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
2750
2751 switch (reportPtr->ObstacleSBPtr->I_SBtype)
2752 {
2753 case I_BehaviourMarine:
2754 case I_BehaviourAlien:
2755 {
2756 SECTION_DATA *chest_section=0;
2757 DISPLAYBLOCK *objectPtr = reportPtr->ObstacleSBPtr->SBdptr;
2758
2759 if(objectPtr)
2760 {
2761 SECTION_DATA *firstSectionPtr;
2762
2763 firstSectionPtr=objectPtr->HModelControlBlock->section_data;
2764 LOCALASSERT(firstSectionPtr);
2765 LOCALASSERT(firstSectionPtr->flags§ion_data_initialised);
2766
2767 /* look for the object's torso in preference */
2768 chest_section =GetThisSectionData(objectPtr->HModelControlBlock->section_data,"chest");
2769
2770 if (chest_section)
2771 {
2772 VECTORCH rel_pos;
2773
2774 rel_pos=dynPtr->Position;
2775
2776 rel_pos.vx-=chest_section->World_Offset.vx;
2777 rel_pos.vy-=chest_section->World_Offset.vy;
2778 rel_pos.vz-=chest_section->World_Offset.vz;
2779
2780 Normalise(&rel_pos);
2781
2782 if (reportPtr->ObstacleSBPtr->I_SBtype==I_BehaviourAlien) {
2783 /* Spherical BloodExplosion for aliens. Under protest. Bleagh. */
2784 CauseDamageToHModel(objectPtr->HModelControlBlock,reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED, chest_section,NULL,&chest_section->World_Offset,0);
2785 } else {
2786 CauseDamageToHModel(objectPtr->HModelControlBlock,reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED, chest_section,&rel_pos,&chest_section->World_Offset,0);
2787 }
2788 }
2789 else
2790 {
2791 CauseDamageToObject(reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED,NULL);
2792 }
2793 victim=reportPtr->ObstacleSBPtr;
2794 }
2795
2796 break;
2797 }
2798 default:
2799 {
2800 CauseDamageToObject(reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED,NULL);
2801 victim=reportPtr->ObstacleSBPtr;
2802 break;
2803 }
2804 }
2805 }
2806
2807 {
2808 char hitEnvironment = 0;
2809
2810 if (reportPtr->ObstacleSBPtr)
2811 {
2812 DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr;
2813 if (dispPtr)
2814 if (dispPtr->ObMyModule)
2815 {
2816 hitEnvironment=1;
2817 }
2818 }
2819 else
2820 {
2821 hitEnvironment = 1;
2822 }
2823
2824 #if 0
2825 MakeParticle(&(dynPtr->Position),&(dynPtr->Position),PARTICLE_BLUEPLASMASPHERE);
2826 MakeLightElement(&dynPtr->Position,LIGHTELEMENT_PLASMACASTERHIT);
2827 if(hitEnvironment)
2828 {
2829 MakeBloodExplosion(&(dynPtr->PrevPosition), 127, &(dynPtr->Position), 200, PARTICLE_ORANGE_SPARK);
2830 Sound_Play(SID_PLASMABOLT_DISSIPATE,"d",&(dynPtr->Position));
2831 }
2832 else
2833 {
2834 MakeFocusedExplosion(&(dynPtr->PrevPosition), &(dynPtr->Position), 100, PARTICLE_ORANGE_PLASMA);
2835 Sound_Play(SID_PLASMABOLT_HIT,"d",&(dynPtr->Position));
2836 // Sound_Play(SID_BLOOD_SPLASH,"d",&(dynPtr->Position));
2837 }
2838 #endif
2839 if (hitEnvironment)
2840 {
2841 MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA);
2842 if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA);
2843 }
2844 else
2845 {
2846 MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA);
2847 if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA);
2848 }
2849 }
2850
2851 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2852
2853 /* Splash damage? */
2854 HandleEffectsOfExplosion
2855 (
2856 victim,
2857 &(dynPtr->Position),
2858 bbPtr->blast_radius,
2859 &bbPtr->damage,
2860 0
2861 );
2862 DestroyAnyStrategyBlock(sbPtr);
2863 } else {
2864 {
2865 VECTORCH direction;
2866 direction.vx = dynPtr->LinVelocity.vx + dynPtr->LinImpulse.vx;
2867 direction.vy = dynPtr->LinVelocity.vy + dynPtr->LinImpulse.vy;
2868 direction.vz = dynPtr->LinVelocity.vz + dynPtr->LinImpulse.vz;
2869 Normalise(&direction);
2870 MakeMatrixFromDirection(&direction,&dynPtr->OrientMat);
2871 }
2872 bbPtr->counter -= NormalFrameTime;
2873 }
2874
2875
2876
2877 }
2878
2879 extern void XenoborgEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr)
2880 {
2881 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
2882 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
2883 ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
2884
2885 /* check for a collision with something */
2886 if (bbPtr->counter <= 0)
2887 {
2888 /* for net game support: send a message saying we've blown up... */
2889 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2890
2891 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
2892 }
2893 else if (reportPtr)
2894 {
2895 if(reportPtr->ObstacleSBPtr)
2896 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_XENOBORG].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
2897
2898 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
2899
2900 DestroyAnyStrategyBlock(sbPtr);
2901 }
2902 else bbPtr->counter -= NormalFrameTime;
2903 }
2904
2905 #define DISC_SPEED 30000 //5000
2906 #define DISC_LIFETIME (10*ONE_FIXED)
2907 #define DISC_FREETIME (1*ONE_FIXED)
2908 #define DISC_MAX_BOUNCES (10)
2909
2910 void InitialiseDiscBehaviour(STRATEGYBLOCK *target,SECTION_DATA *disc_section) {
2911
2912 DISPLAYBLOCK *dispPtr;
2913 DYNAMICSBLOCK *dynPtr;
2914 PC_PRED_DISC_BEHAV_BLOCK *bblk;
2915 int a;
2916
2917 GLOBALASSERT(disc_section);
2918
2919 /* make displayblock with correct shape, etc */
2920 dispPtr = MakeObject(I_BehaviourPredatorDisc_SeekTrack,&disc_section->World_Offset);
2921
2922 if (dispPtr == 0) return; // Failed to allocate display block
2923
2924 /* make displayblock a dynamic module object */
2925 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
2926
2927 /* setup dynamics block */
2928 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
2929
2930 if (dynPtr == 0)
2931 {
2932 // Failed to allocate a dynamics block
2933 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2934 return;
2935 }
2936
2937 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
2938
2939 /* Stats! */
2940 dispPtr->ObStrategyBlock->SBDamageBlock.Health=100<<ONE_FIXED_SHIFT;
2941 dispPtr->ObStrategyBlock->SBDamageBlock.Armour=100<<ONE_FIXED_SHIFT;
2942 dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.AcidResistant=0;
2943 dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.FireResistant=0;
2944 dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.ElectricResistant=0;
2945 dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.PerfectArmour=0;
2946 dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.ElectricSensitive=0;
2947 dispPtr->ObStrategyBlock->SBDamageBlock.SB_H_flags.Indestructable=1;
2948
2949 {
2950 /* align rocket to launcher */
2951 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
2952 extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
2953 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
2954 MATRIXCH matrix = VDBPtr->VDB_Mat;
2955
2956 if (PlayersTarget.Distance<1400) {
2957 /* Yuck! */
2958 dynPtr->Position=Global_VDB_Ptr->VDB_World;
2959 /* Nudge down a wee tad bit. */
2960 dynPtr->Position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat21,200);
2961 dynPtr->Position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat22,200);
2962 dynPtr->Position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat23,200);
2963
2964 dynPtr->Position.vx+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat11,200);
2965 dynPtr->Position.vy+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat12,200);
2966 dynPtr->Position.vz+=MUL_FIXED(Player->ObStrategyBlock->DynPtr->OrientMat.mat13,200);
2967
2968 } else {
2969 dynPtr->Position=disc_section->World_Offset;
2970 }
2971
2972
2973 dynPtr->PrevPosition = dynPtr->Position;
2974 TransposeMatrixCH(&matrix);
2975 /* dynPtr->OrientMat = Player->ObMat; */
2976 dynPtr->OrientMat = matrix;
2977 dynPtr->PrevOrientMat = dynPtr->OrientMat;
2978 /* I added this next line for networking: Patrick */
2979 MatrixToEuler(&matrix, &PlayersWeapon.ObEuler);
2980
2981 dynPtr->OrientEuler.EulerX=PlayersWeapon.ObEuler.EulerX;
2982 dynPtr->OrientEuler.EulerY=PlayersWeapon.ObEuler.EulerY;
2983 dynPtr->OrientEuler.EulerZ=PlayersWeapon.ObEuler.EulerZ;
2984
2985 /* align velocity too */
2986 dynPtr->LinVelocity.vx = MUL_FIXED(matrix.mat31,DISC_SPEED);
2987 dynPtr->LinVelocity.vy = MUL_FIXED(matrix.mat32,DISC_SPEED);
2988 dynPtr->LinVelocity.vz = MUL_FIXED(matrix.mat33,DISC_SPEED);
2989
2990 }
2991
2992 /* give missile a maximum lifetime */
2993 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(PC_PRED_DISC_BEHAV_BLOCK));
2994
2995 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
2996 {
2997 // Failed to allocate a strategy block data pointer
2998 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
2999 return;
3000 }
3001
3002 bblk=(PC_PRED_DISC_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr;
3003 if (target) {
3004 bblk->counter = DISC_LIFETIME;
3005 } else {
3006 bblk->counter = DISC_FREETIME;
3007 }
3008 bblk->bounces=0;
3009 bblk->Destruct=0;
3010 bblk->Stuck=0;
3011 bblk->Bounced=0;
3012 bblk->soundHandle = SOUND_NOACTIVEINDEX;
3013 for (a=0; a<SB_NAME_LENGTH; a++) {
3014 bblk->Prev_Target_SBname[a]='\0';
3015 bblk->Prev_Damaged_SBname[a]='\0';
3016 }
3017 bblk->Target=target;
3018
3019 if (bblk->Target) {
3020 COPY_NAME(bblk->Prev_Target_SBname,bblk->Target_SBname);
3021 COPY_NAME(bblk->Target_SBname,bblk->Target->SBname);
3022 } else {
3023 for (a=0; a<SB_NAME_LENGTH; a++) {
3024 bblk->Target_SBname[a]='\0';
3025 }
3026 }
3027
3028 /* Create HModel. */
3029 {
3030 SECTION *root_section;
3031 SECTION_DATA *local_disc;
3032
3033 root_section=GetNamedHierarchyFromLibrary("disk","Disk");
3034
3035 GLOBALASSERT(root_section);
3036
3037 Create_HModel(&bblk->HModelController,root_section);
3038 InitHModelSequence(&bblk->HModelController,HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED);
3039
3040 ProveHModel(&bblk->HModelController,dispPtr);
3041
3042 dispPtr->HModelControlBlock=&bblk->HModelController;
3043
3044 /* Match disks. */
3045 local_disc=GetThisSectionData(bblk->HModelController.section_data,"disk");
3046 local_disc->World_Offset=disc_section->World_Offset;
3047 local_disc->SecMat=disc_section->SecMat;
3048 InitHModelTweening(&bblk->HModelController,(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Minigun_Delta,ONE_FIXED,1);
3049 }
3050
3051 /* for net game support */
3052 if(AvP.Network != I_No_Network) {
3053 AddNetGameObjectID(dispPtr->ObStrategyBlock);
3054 }
3055 }
3056
3057 /*
3058 Function only does minimal disc setup , the rest will be done by the load function
3059 */
3060 static STRATEGYBLOCK* InitialiseDiscBehaviour_ForLoad() {
3061 VECTORCH zeroVect = {0,0,0};
3062
3063 DISPLAYBLOCK *dispPtr;
3064 DYNAMICSBLOCK *dynPtr;
3065 PC_PRED_DISC_BEHAV_BLOCK *bblk;
3066
3067 /* make displayblock with correct shape, etc */
3068 dispPtr = MakeObject(I_BehaviourPredatorDisc_SeekTrack,&zeroVect);
3069
3070 if (dispPtr == 0) return NULL; // Failed to allocate display block
3071
3072 /* make displayblock a dynamic module object */
3073 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
3074
3075 /* setup dynamics block */
3076 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
3077
3078 if (dynPtr == 0)
3079 {
3080 // Failed to allocate a dynamics block
3081 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
3082 return NULL;
3083 }
3084
3085 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
3086
3087
3088 /* give missile a maximum lifetime */
3089 dispPtr->ObStrategyBlock->SBdataptr = AllocateMem(sizeof(PC_PRED_DISC_BEHAV_BLOCK));
3090 bblk = dispPtr->ObStrategyBlock->SBdataptr;
3091
3092 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
3093 {
3094 // Failed to allocate a strategy block data pointer
3095 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
3096 return NULL;
3097 }
3098 memset(dispPtr->ObStrategyBlock->SBdataptr,0,sizeof(PC_PRED_DISC_BEHAV_BLOCK));
3099
3100 bblk->soundHandle = SOUND_NOACTIVEINDEX;
3101
3102 dispPtr->HModelControlBlock=&bblk->HModelController;
3103
3104
3105 return dispPtr->ObStrategyBlock;
3106 }
3107
3108 extern void NPCDiscBehaviour(STRATEGYBLOCK *sbPtr)
3109 {
3110 /* I have change this: mainly because npc preds fire them too... patrick */
3111 #if 0
3112 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3113 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
3114 ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3115 int destruct;
3116
3117 destruct=0;
3118
3119 while (reportPtr) {
3120
3121 if (reportPtr->ObstacleSBPtr!=Player->ObStrategyBlock) {
3122
3123 if (reportPtr->ObstacleSBPtr==NULL)
3124 {
3125 destruct=1;
3126 }
3127 else
3128 {
3129 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3130 }
3131
3132 }
3133 reportPtr=reportPtr->NextCollisionReportPtr;
3134 }
3135
3136 if (destruct || (bbPtr->counter<=0) )
3137 {
3138 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
3139 HandleEffectsOfExplosion
3140 (
3141 sbPtr,
3142 &(dynPtr->Position),
3143 TemplateAmmo[AMMO_PRED_DISC].MaxRange,
3144 &TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty],
3145 TemplateAmmo[AMMO_PRED_DISC].ExplosionIsFlat
3146 );
3147
3148 Sound_Play(SID_EXPLOSION,"d",&(dynPtr->Position));
3149
3150
3151 /* for net game support: send a message saying we've blown up... */
3152 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3153
3154 /* destroy rocket */
3155 DestroyAnyStrategyBlock(sbPtr);
3156
3157 }
3158 else
3159 {
3160 bbPtr->counter-=NormalFrameTime;
3161 }
3162 #endif
3163
3164
3165
3166 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3167 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
3168 ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3169
3170 /* check for a collision with something */
3171 if(bbPtr->counter <= 0)
3172 {
3173 /* for net game support: send a message saying we've blown up... */
3174 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3175
3176 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
3177 }
3178 else if(reportPtr)
3179 {
3180 if(reportPtr->ObstacleSBPtr)
3181 {
3182 if(!((reportPtr->ObstacleSBPtr==Player->ObStrategyBlock)&&(AvP.PlayerType==I_Predator))) {
3183 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3184 }
3185 }
3186
3187 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3188
3189 DestroyAnyStrategyBlock(sbPtr);
3190 } else {
3191 bbPtr->counter -= NormalFrameTime;
3192 }
3193 }
3194
3195
3196 static void InitialiseAlienSpitBehaviour(void)
3197 {
3198 DISPLAYBLOCK *dispPtr;
3199 DYNAMICSBLOCK *dynPtr;
3200 VECTORCH position;
3201 int numGlobules;
3202
3203 /* calculate the position */
3204 {
3205 // position=PlayersWeapon.ObWorld;
3206 /* KJL 12:31:39 8/11/97 - the spit was being created to far in front
3207 of the player */
3208 position=Player->ObWorld;
3209 }
3210
3211 #define NUM_ALIENSPITGLOBULES 7
3212 for(numGlobules=0;numGlobules<NUM_ALIENSPITGLOBULES;numGlobules++)
3213 {
3214 /* make displayblock with correct shape, etc */
3215 dispPtr = MakeObject(I_BehaviourAlienSpit,&position);
3216 if (dispPtr == 0) return; // Failed to allocate display block
3217
3218 /* make displayblock a dynamic module object */
3219 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
3220
3221 /* setup dynamics block */
3222 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
3223
3224 if (dynPtr == 0)
3225 {
3226 // Failed to allocate a dynamics block
3227 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
3228 return;
3229 }
3230
3231 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
3232
3233 /* spit does not collide with other spit */
3234 dynPtr->IgnoreSameObjectsAsYou = 1;
3235
3236 /* give missile a maximum lifetime */
3237 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK));
3238
3239 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
3240 {
3241 // Failed to allocate a strategy block data pointer
3242 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
3243 return;
3244 }
3245
3246 ((ONE_SHOT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
3247
3248 /* align rocket to launcher */
3249 dynPtr->Position=position;
3250 /* align rocket to launcher */
3251 {
3252 #define SPIT_SPEED 10000
3253 #define SPIT_SPREAD 340
3254
3255 extern VIEWDESCRIPTORBLOCK *ActiveVDBList[];
3256 VIEWDESCRIPTORBLOCK *VDBPtr = ActiveVDBList[0];
3257 MATRIXCH spitDirn;
3258 EULER spitOffset;
3259
3260 dynPtr->OrientMat = VDBPtr->VDB_Mat;
3261 TransposeMatrixCH(&dynPtr->OrientMat);
3262
3263 spitOffset.EulerX = (FastRandom()%(SPIT_SPREAD<<1))-SPIT_SPREAD;
3264 if(spitOffset.EulerX<0) spitOffset.EulerX += 4096;
3265 spitOffset.EulerY = (FastRandom()%(SPIT_SPREAD<<1))-SPIT_SPREAD;
3266 if(spitOffset.EulerY<0) spitOffset.EulerY += 4096;
3267 spitOffset.EulerZ = 0;
3268
3269 CreateEulerMatrix(&spitOffset, &spitDirn);
3270 TransposeMatrixCH(&spitDirn);
3271 MatrixMultiply(&dynPtr->OrientMat,&spitDirn,&dynPtr->OrientMat);
3272
3273 /* align velocity to z axis */
3274 dynPtr->PrevOrientMat = dynPtr->OrientMat;
3275 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->OrientMat.mat31,SPIT_SPEED)+
3276 Player->ObStrategyBlock->DynPtr->LinVelocity.vx+
3277 Player->ObStrategyBlock->DynPtr->LinImpulse.vx;
3278 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->OrientMat.mat32,SPIT_SPEED)+
3279 Player->ObStrategyBlock->DynPtr->LinVelocity.vy+
3280 Player->ObStrategyBlock->DynPtr->LinImpulse.vy;
3281 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->OrientMat.mat33,SPIT_SPEED)+
3282 Player->ObStrategyBlock->DynPtr->LinVelocity.vz+
3283 Player->ObStrategyBlock->DynPtr->LinImpulse.vz;
3284
3285 /* dynamics blocks flags */
3286 dynPtr->GravityOn = 1;
3287
3288 }
3289 /* I added this next line for networking: Patrick */
3290 MatrixToEuler(&PlayersWeapon.ObMat, &PlayersWeapon.ObEuler);
3291
3292 /* for net game support */
3293 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
3294 }
3295 }
3296
3297 extern void AlienSpitBehaviour(STRATEGYBLOCK *sbPtr)
3298 {
3299 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3300 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
3301 ONE_SHOT_BEHAV_BLOCK *bbPtr = (ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3302
3303 if (bbPtr->counter<=0)
3304 {
3305 /* for net game support: send a message saying we've blown up... */
3306 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3307
3308 /* destroy rocket */
3309 DestroyAnyStrategyBlock(sbPtr);
3310 }
3311 else if (reportPtr)
3312 {
3313 STRATEGYBLOCK *hitSBPtr = reportPtr->ObstacleSBPtr;
3314
3315 /* ignore hitting another spit or aliens */
3316 if(hitSBPtr)
3317 {
3318 if(!((hitSBPtr->I_SBtype==I_BehaviourAlienSpit)
3319 ||(hitSBPtr->I_SBtype==I_BehaviourAlien)
3320 ||(hitSBPtr==Player->ObStrategyBlock) ) )
3321 CauseDamageToObject(hitSBPtr,&TemplateAmmo[AMMO_ALIEN_SPIT].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3322 }
3323
3324 Sound_Play(SID_PRED_NEWROAR,"d",&(dynPtr->Position));
3325
3326 /* for net game support: send a message saying we've blown up... */
3327 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3328
3329 /* destroy rocket */
3330 DestroyAnyStrategyBlock(sbPtr);
3331 }
3332 else
3333 {
3334 bbPtr->counter-=NormalFrameTime;
3335 }
3336 }
3337
3338
3339 static void GetGunDirection(VECTORCH *gunDirectionPtr, VECTORCH *positionPtr)
3340 {
3341 gunDirectionPtr->vx = PlayersTarget.Position.vx - positionPtr->vx;
3342 gunDirectionPtr->vy = PlayersTarget.Position.vy - positionPtr->vy;
3343 gunDirectionPtr->vz = PlayersTarget.Position.vz - positionPtr->vz;
3344 Normalise(gunDirectionPtr);
3345 }
3346
3347 static int Reflect(VECTORCH *Incident, VECTORCH *Normal, EULER *Output) {
3348
3349 int dot,retval;
3350 VECTORCH outVec,normInc;
3351 MATRIXCH tempMat;
3352 /* Ah, the wonders of better math support. */
3353
3354 GLOBALASSERT(Incident);
3355 GLOBALASSERT(Normal);
3356 GLOBALASSERT(Output);
3357
3358 normInc=*Incident;
3359 Normalise(&normInc);
3360 retval = DotProduct(&normInc,Normal);
3361 /* Hold that thought. */
3362 dot = retval*(-2);
3363 /* Yeah, okay, and a better algorithm. */
3364 outVec.vx = (normInc.vx + MUL_FIXED(dot,Normal->vx));
3365 outVec.vy = (normInc.vy + MUL_FIXED(dot,Normal->vy));
3366 outVec.vz = (normInc.vz + MUL_FIXED(dot,Normal->vz));
3367
3368 MakeMatrixFromDirection(&outVec,&tempMat);
3369 MatrixToEuler(&tempMat,Output);
3370 /* But bear in mind, most of the early one was coping with *
3371 * bad functions and junk inputs... that's my excuse. */
3372
3373 return(retval);
3374 }
3375
3376 static int SBForcesBounce(STRATEGYBLOCK *sbPtr) {
3377
3378 if (sbPtr==NULL) {
3379 return(0);
3380 }
3381
3382 /* Now switch by type. */
3383 switch (sbPtr->I_SBtype) {
3384 case I_BehaviourInanimateObject:
3385 {
3386 INANIMATEOBJECT_STATUSBLOCK* objectStatusPtr;
3387 objectStatusPtr=(INANIMATEOBJECT_STATUSBLOCK *)sbPtr->SBdataptr;
3388 GLOBALASSERT(objectStatusPtr);
3389 if (objectStatusPtr->Indestructable) {
3390 return(1);
3391 } else {
3392 return(0);
3393 }
3394 }
3395 break;
3396 case I_BehaviourProximityDoor:
3397 case I_BehaviourTrackObject:
3398 case I_BehaviourLiftDoor:
3399 case I_BehaviourSwitchDoor:
3400 case I_BehaviourLinkSwitch:
3401 case I_BehaviourBinarySwitch:
3402 case I_BehaviourLift:
3403 case I_BehaviourPlatform:
3404 case I_BehaviourPredatorDisc_SeekTrack:
3405 return(1);
3406 break;
3407 case I_BehaviourNetGhost:
3408 {
3409 NETGHOSTDATABLOCK *dataptr;
3410 dataptr=sbPtr->SBdataptr;
3411 switch (dataptr->type) {
3412 case I_BehaviourPredatorDisc_SeekTrack:
3413 return(1);
3414 break;
3415 default:
3416 return(0);
3417 break;
3418 }
3419 }
3420 break;
3421 default:
3422 return(0);
3423 break;
3424 }
3425
3426 return(0);
3427 }
3428
3429 int SBIsEnvironment(STRATEGYBLOCK *sbPtr) {
3430
3431 if (sbPtr==NULL) {
3432 return(1);
3433 }
3434
3435 if (sbPtr->SBdptr) {
3436 if (sbPtr->SBdptr->ObMyModule) {
3437 return(1);
3438 }
3439 }
3440
3441 return(0);
3442 }
3443
3444 void Frisbee_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr) {
3445
3446 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3447 FRISBEE_BEHAV_BLOCK *fbPtr = (FRISBEE_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3448 MATRIXCH mat;
3449
3450 /* Hit the environment. Bounce? */
3451 int dp;
3452
3453 dp=Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
3454 dynPtr->OrientEuler.EulerZ=0;
3455 dynPtr->IgnoreThePlayer=0;
3456
3457 /* Always bounce. Reference Disc_Hit_Environment for sticking conditions. */
3458 MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
3459 Sound_Play(SID_ED_SKEETERDISC_HITWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
3460
3461 CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
3462 TransposeMatrixCH(&mat);
3463
3464 dynPtr->OrientMat=mat;
3465
3466 dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31,FRISBEE_SPEED);
3467 dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32,FRISBEE_SPEED);
3468 dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33,FRISBEE_SPEED);
3469
3470 dynPtr->LinImpulse.vx=0;
3471 dynPtr->LinImpulse.vy=0;
3472 dynPtr->LinImpulse.vz=0;
3473
3474 /*
3475 Record that the disc has bounced - for use in network game
3476 */
3477 fbPtr->Bounced=1;
3478 fbPtr->bounces++;
3479
3480 }
3481
3482 void Disc_Hit_Environment(STRATEGYBLOCK *sbPtr,COLLISIONREPORT *reportPtr) {
3483
3484 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3485 PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3486 MATRIXCH mat;
3487
3488 /* Hit the environment. Bounce? */
3489 int dp;
3490
3491 dp=Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
3492 dynPtr->OrientEuler.EulerZ=0;
3493 dynPtr->IgnoreThePlayer=0;
3494
3495 if ((dp>-46341)&&(bbPtr->counter>0)&&(bbPtr->bounces<=DISC_MAX_BOUNCES)) { /* 65536/Rt2 */
3496 /* Bounce. */
3497 MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
3498 Sound_Play(SID_PREDATOR_DISK_HITTING_WALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
3499 /*
3500 Record that the disc has bounced - for use in network game
3501 */
3502 bbPtr->Bounced=1;
3503 bbPtr->bounces++;
3504 } else {
3505 CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
3506 TransposeMatrixCH(&mat);
3507 /* very steep angle (or very long flight!) - stick. */
3508 bbPtr->Stuck=1;
3509 bbPtr->HModelController.Playing=0;
3510 MakeSprayOfSparks(&mat,&dynPtr->Position);
3511 Sound_Stop(bbPtr->soundHandle);
3512 Sound_Play(SID_DISC_STICKSINWALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
3513 }
3514
3515 if (bbPtr->Target==NULL) {
3516 /* No target, so come home. */
3517 bbPtr->Target=Player->ObStrategyBlock;
3518 COPY_NAME(bbPtr->Target_SBname,bbPtr->Target->SBname);
3519 }
3520
3521 }
3522
3523 extern void DiscBehaviour_SeekTrack(STRATEGYBLOCK *sbPtr)
3524 {
3525
3526 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
3527 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
3528 PC_PRED_DISC_BEHAV_BLOCK *bbPtr = (PC_PRED_DISC_BEHAV_BLOCK * ) sbPtr->SBdataptr;
3529 MATRIXCH mat;
3530 int getadisc;
3531
3532 textprint("Disc active!\n");
3533
3534 ProveHModel_Far(&bbPtr->HModelController,sbPtr);
3535
3536 if (sbPtr->SBDamageBlock.IsOnFire) {
3537 sbPtr->SBDamageBlock.IsOnFire=0;
3538 }
3539
3540 /* Update target */
3541 if (bbPtr->Stuck) {
3542 /* No business doing anything. */
3543 #if 0
3544 bbPtr->HModelController.Playing=0;
3545 if (sbPtr->SBdptr) {
3546 sbPtr->SBdptr->ObFlags3 &= ~ObFlag3_DynamicModuleObject;
3547 }
3548 #else
3549 dynPtr->LinVelocity.vx = 0;
3550 dynPtr->LinVelocity.vy = 0;
3551 dynPtr->LinVelocity.vz = 0;
3552
3553 dynPtr->LinImpulse.vx = 0;
3554 dynPtr->LinImpulse.vy = 0;
3555 dynPtr->LinImpulse.vz = 0;
3556
3557 Sound_Stop(bbPtr->soundHandle);
3558 /* Are we inside the player? */
3559 {
3560 extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
3561 VECTORCH offset;
3562 int dist;
3563
3564 offset=Global_VDB_Ptr->VDB_World;
3565 offset.vx-=dynPtr->Position.vx;
3566 offset.vy-=dynPtr->Position.vy;
3567 offset.vz-=dynPtr->Position.vz;
3568
3569 dist=Approximate3dMagnitude(&offset);
3570
3571 if (dist<600) {
3572 /* My, that's close. */
3573 PLAYER_STATUS *psptr;
3574 int a;
3575 psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr;
3576 for (a=0; a<MAX_NO_OF_WEAPON_SLOTS; a++) {
3577 if (psptr->WeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) {
3578 break;
3579 }
3580 }
3581 if (a!=MAX_NO_OF_WEAPON_SLOTS) {
3582
3583 if ((psptr->WeaponSlot[a].PrimaryMagazinesRemaining==0)
3584 && (psptr->WeaponSlot[a].PrimaryRoundsRemaining==0)) {
3585 //psptr->WeaponSlot[a].PrimaryRoundsRemaining+=ONE_FIXED;
3586 psptr->WeaponSlot[a].PrimaryMagazinesRemaining+=1;
3587 /* Autoswap to disc here? */
3588 AutoSwapToDisc();
3589 } else {
3590 psptr->WeaponSlot[a].PrimaryMagazinesRemaining+=1;
3591 }
3592
3593 #if 0
3594 NewOnScreenMessage("CAUGHT DISC");
3595 #endif
3596
3597 Sound_Stop(bbPtr->soundHandle);
3598 Sound_Play(SID_PREDATOR_DISK_BEING_CAUGHT,"h");
3599
3600 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3601
3602 DestroyAnyStrategyBlock(sbPtr);
3603
3604 return;
3605 }
3606 }
3607 }
3608 /* Just to make sure... */
3609 Convert_Disc_To_Pickup(sbPtr);
3610 return;
3611 #endif
3612 } else if (bbPtr->Target==Player->ObStrategyBlock) {
3613 VECTORCH targetPos;
3614 /* Home on the player. */
3615 textprint("Disc homing on player.\n");
3616 GetTargetingPointOfObject_Far(bbPtr->Target,&targetPos);
3617 if (bbPtr->counter>0) {
3618 EulerAnglesHoming(&dynPtr->Position,&targetPos,&dynPtr->OrientEuler,4);
3619 } else {
3620 textprint("Disc super homing!\n");
3621 EulerAnglesHoming(&dynPtr->Position,&targetPos,&dynPtr->OrientEuler,2);
3622 }
3623 } else if (bbPtr->Target) {
3624 /* We have a target. */
3625 textprint("Disc homing on target.\n");
3626 if (NAME_ISEQUAL(bbPtr->Target_SBname,bbPtr->Target->SBname)) {
3627 if (!NPC_IsDead(bbPtr->Target)) {
3628 /* Our target lives! */
3629 VECTORCH targetPos;
3630 GLOBALASSERT(bbPtr->Target->DynPtr);
3631 GetTargetingPointOfObject_Far(bbPtr->Target,&targetPos);
3632 EulerAnglesHoming(&dynPtr->Position,&targetPos,&dynPtr->OrientEuler,4);
3633 } else {
3634 /* Target dying - unset. */
3635 bbPtr->Target=NULL;
3636 }
3637 } else {
3638 /* Target no longer valid - unset. */
3639 bbPtr->Target=NULL;
3640 }
3641 } else {
3642 /* No target. Oh well... */
3643 textprint("Disc in free flight.\n");
3644 }
3645
3646 if (bbPtr->Stuck==0) {
3647 /* We must be flying. Maintain sound. */
3648 if(bbPtr->soundHandle!=SOUND_NOACTIVEINDEX) {
3649 Sound_Update3d(bbPtr->soundHandle,&(sbPtr->DynPtr->Position));
3650 if (ActiveSounds[bbPtr->soundHandle].soundIndex!=SID_PREDATOR_DISK_FLYING) {
3651 Sound_Stop(bbPtr->soundHandle);
3652 Sound_Play(SID_PREDATOR_DISK_FLYING,"del",&(sbPtr->DynPtr->Position),&bbPtr->soundHandle);
3653 }
3654 } else {
3655 Sound_Play(SID_PREDATOR_DISK_FLYING,"del",&(sbPtr->DynPtr->Position),&bbPtr->soundHandle);
3656 }
3657 }
3658
3659 /* check for a collision with something */
3660 if(bbPtr->counter <= 0)
3661 {
3662 #if 0
3663 /* for net game support: send a message saying we've blown up... */
3664 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3665
3666 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
3667 return;
3668 #else
3669 /* For now, do nothing... */
3670 if (bbPtr->counter<-DISC_LIFETIME) {
3671 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3672
3673 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
3674 return;
3675 }
3676 #endif
3677 }
3678
3679 getadisc=0;
3680 /* To make sure you can't get multiple discs back! */
3681
3682 while (reportPtr) {
3683 /* Should be while? */
3684 if(reportPtr->ObstacleSBPtr)
3685 {
3686 /* Hit a strategyblock. */
3687
3688 if (bbPtr->Stuck) {
3689 /* Don't hurt anyone. */
3690 if ((reportPtr->ObstacleSBPtr==Player->ObStrategyBlock)&&(AvP.PlayerType==I_Predator)) {
3691 /* Hit the owner. Recover it! */
3692 PLAYER_STATUS *psptr;
3693 int a;
3694 psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr;
3695 for (a=0; a<MAX_NO_OF_WEAPON_SLOTS; a++) {
3696 if (psptr->WeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) {
3697 break;
3698 }
3699 }
3700 if (a!=MAX_NO_OF_WEAPON_SLOTS) {
3701
3702 getadisc=1;
3703
3704 #if 0
3705 NewOnScreenMessage("RECOVERED DISC");
3706 #endif
3707
3708 Sound_Stop(bbPtr->soundHandle);
3709 Sound_Play(SID_PREDATOR_DISK_RECOVERED,"h");
3710
3711 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3712
3713 DestroyAnyStrategyBlock(sbPtr);
3714
3715 }
3716 }
3717 } else if(!((reportPtr->ObstacleSBPtr==Player->ObStrategyBlock)&&(AvP.PlayerType==I_Predator))) {
3718
3719 /* Hit a random strategyblock - what is it? */
3720 if (SBForcesBounce(reportPtr->ObstacleSBPtr)) {
3721
3722 /* Bounce. */
3723 Reflect(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal, &dynPtr->OrientEuler);
3724 dynPtr->OrientEuler.EulerZ=0;
3725 dynPtr->IgnoreThePlayer=0;
3726 MakeImpactSparks(&dynPtr->LinVelocity, &reportPtr->ObstacleNormal,&dynPtr->Position);
3727 Sound_Play(SID_PREDATOR_DISK_HITTING_WALL,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
3728 bbPtr->bounces++;
3729
3730 /*
3731 Record that the disc has bounced - for use in network game
3732 */
3733 bbPtr->Bounced=1;
3734
3735 } else if (SBIsEnvironment(reportPtr->ObstacleSBPtr)) {
3736 Disc_Hit_Environment(sbPtr,reportPtr);
3737 } else {
3738 /* Hit a creature? */
3739 SECTION_DATA *hit_section;
3740 VECTORCH attack_dir;
3741
3742 dynPtr->IgnoreThePlayer=0;
3743 /* To make sure. */
3744
3745 hit_section=NULL;
3746
3747 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
3748
3749 switch (reportPtr->ObstacleSBPtr->I_SBtype)
3750 {
3751 case I_BehaviourMarine:
3752 case I_BehaviourAlien:
3753 {
3754 SECTION_DATA *chest_section=0;
3755 DISPLAYBLOCK *objectPtr = reportPtr->ObstacleSBPtr->SBdptr;
3756
3757 if(objectPtr)
3758 {
3759 SECTION_DATA *firstSectionPtr;
3760
3761 firstSectionPtr=objectPtr->HModelControlBlock->section_data;
3762 LOCALASSERT(firstSectionPtr);
3763 LOCALASSERT(firstSectionPtr->flags§ion_data_initialised);
3764
3765 /* look for the object's torso in preference */
3766 chest_section =GetThisSectionData(objectPtr->HModelControlBlock->section_data,"chest");
3767
3768 if (chest_section)
3769 {
3770 VECTORCH rel_pos;
3771
3772 rel_pos=dynPtr->Position;
3773
3774 rel_pos.vx-=chest_section->World_Offset.vx;
3775 rel_pos.vy-=chest_section->World_Offset.vy;
3776 rel_pos.vz-=chest_section->World_Offset.vz;
3777
3778 Normalise(&rel_pos);
3779
3780 CauseDamageToHModel(objectPtr->HModelControlBlock,reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED, chest_section,&rel_pos,&chest_section->World_Offset,0);
3781 }
3782 else
3783 {
3784 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3785 }
3786 }
3787 break;
3788 }
3789 case I_BehaviourAutoGun:
3790 case I_BehaviourXenoborg:
3791 {
3792 /* Spark a bit? */
3793 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3794 break;
3795 }
3796 case I_BehaviourNetGhost:
3797 {
3798 NETGHOSTDATABLOCK *dataptr;
3799 dataptr=reportPtr->ObstacleSBPtr->SBdataptr;
3800 switch (dataptr->type) {
3801 case I_BehaviourMarinePlayer:
3802 case I_BehaviourAlienPlayer:
3803 case I_BehaviourPredatorPlayer:
3804 /* Maybe a different damage here? */
3805 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3806 break;
3807 default:
3808 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3809 break;
3810 }
3811 }
3812 break;
3813 default:
3814 {
3815 CauseDamageToObject(reportPtr->ObstacleSBPtr,&TemplateAmmo[AMMO_PRED_DISC].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
3816 break;
3817 }
3818 }
3819
3820 Sound_Play(SID_PREDATOR_DISK_HITTING_TARGET,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
3821
3822 if (NAME_ISEQUAL(reportPtr->ObstacleSBPtr->SBname,bbPtr->Target_SBname)) {
3823 /* Got him! Seek the player. */
3824 bbPtr->Target=Player->ObStrategyBlock;
3825 bbPtr->counter = DISC_LIFETIME;
3826 COPY_NAME(bbPtr->Target_SBname,bbPtr->Target->SBname);
3827 }
3828 }
3829 } else {
3830 /* Hit the owner. Catch it! */
3831 PLAYER_STATUS *psptr;
3832 int a;
3833 psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr;
3834 for (a=0; a<MAX_NO_OF_WEAPON_SLOTS; a++) {
3835 if (psptr->WeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) {
3836 break;
3837 }
3838 }
3839 if (a!=MAX_NO_OF_WEAPON_SLOTS) {
3840
3841 getadisc=1;
3842
3843 #if 0
3844 NewOnScreenMessage("CAUGHT DISC");
3845 #endif
3846
3847 Sound_Stop(bbPtr->soundHandle);
3848 Sound_Play(SID_PREDATOR_DISK_BEING_CAUGHT,"h");
3849
3850 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
3851
3852 DestroyAnyStrategyBlock(sbPtr);
3853
3854 }
3855 }
3856 } else {
3857 Disc_Hit_Environment(sbPtr,reportPtr);
3858 }
3859
3860 /* skip to next report */
3861 reportPtr = reportPtr->NextCollisionReportPtr;
3862
3863 }
3864
3865 if (getadisc) {
3866 PLAYER_STATUS *psptr;
3867 int a;
3868 psptr=(PLAYER_STATUS *)Player->ObStrategyBlock->SBdataptr;
3869 for (a=0; a<MAX_NO_OF_WEAPON_SLOTS; a++) {
3870 if (psptr->WeaponSlot[a].WeaponIDNumber==WEAPON_PRED_DISC) {
3871 break;
3872 }
3873 }
3874 if (a!=MAX_NO_OF_WEAPON_SLOTS) {
3875
3876 if ((psptr->WeaponSlot[a].PrimaryMagazinesRemaining==0)
3877 && (psptr->WeaponSlot[a].PrimaryRoundsRemaining==0)) {
3878 psptr->WeaponSlot[a].PrimaryRoundsRemaining+=ONE_FIXED;
3879 /* Autoswap to disc here? */
3880 AutoSwapToDisc();
3881 } else {
3882 psptr->WeaponSlot[a].PrimaryMagazinesRemaining+=1;
3883 }
3884 }
3885 }
3886
3887 #if 0
3888 else {
3889 /* We must be in the clear! */
3890 #if 0
3891 dynPtr->IgnoreThePlayer=0;
3892 #endif
3893 }
3894 #endif
3895
3896 if (bbPtr->Stuck) {
3897 dynPtr->LinVelocity.vx = 0;
3898 dynPtr->LinVelocity.vy = 0;
3899 dynPtr->LinVelocity.vz = 0;
3900
3901 dynPtr->LinImpulse.vx = 0;
3902 dynPtr->LinImpulse.vy = 0;
3903 dynPtr->LinImpulse.vz = 0;
3904
3905 } else {
3906 /* Decrement Timer.. */
3907
3908 bbPtr->counter -= NormalFrameTime;
3909
3910 if (bbPtr->Target==NULL) {
3911 if (bbPtr->counter<=0) {
3912 /* Turn around! */
3913 bbPtr->Target=Player->ObStrategyBlock;
3914 bbPtr->counter = DISC_LIFETIME;
3915 COPY_NAME(bbPtr->Target_SBname,bbPtr->Target->SBname);
3916 dynPtr->IgnoreThePlayer=0;
3917 }
3918 }
3919
3920 /* Move Disc */
3921
3922 CreateEulerMatrix(&dynPtr->OrientEuler, &mat);
3923
3924 TransposeMatrixCH(&mat);
3925
3926 dynPtr->OrientMat=mat;
3927
3928 dynPtr->LinVelocity.vx = MUL_FIXED(mat.mat31,DISC_SPEED);
3929 dynPtr->LinVelocity.vy = MUL_FIXED(mat.mat32,DISC_SPEED);
3930 dynPtr->LinVelocity.vz = MUL_FIXED(mat.mat33,DISC_SPEED);
3931
3932 dynPtr->LinImpulse.vx=0;
3933 dynPtr->LinImpulse.vy=0;
3934 dynPtr->LinImpulse.vz=0;
3935 NewTrailPoint(sbPtr->DynPtr);
3936 }
3937 }
3938
3939 void SetEulerAngles(VECTORCH *source, VECTORCH *Target, EULER *eulr) {
3940
3941 int offsetx,offsety,offsetz;
3942
3943 offsetx=(Target->vx)-(source->vx);
3944 offsety=(Target->vz)-(source->vz);
3945
3946 eulr->EulerY=ArcTan(offsetx,offsety);
3947 eulr->EulerY&=wrap360;
3948
3949 /* That was for the first plane. Now the second. */
3950
3951 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
3952 offsety=-((Target->vy)-(source->vy));
3953
3954 eulr->EulerX=ArcTan(offsety,offsetz);
3955 eulr->EulerX&=wrap360;
3956
3957 eulr->EulerZ=0;
3958
3959 }
3960
3961 void EulerAnglesHoming(VECTORCH *source, VECTORCH *Target, EULER *eulr, int rate) {
3962
3963 int offsetx,offsety,offsetz,angle1,angle2,testangle;
3964
3965 offsetx=(Target->vx)-(source->vx);
3966 offsety=(Target->vz)-(source->vz);
3967
3968 angle1=ArcTan(offsetx,offsety);
3969
3970 angle2=eulr->EulerY;
3971
3972 if (angle1!=angle2) {
3973
3974 testangle=angle2-angle1;
3975 if (abs(testangle)<(NormalFrameTime>>rate)) {
3976 eulr->EulerY=angle1;
3977 eulr->EulerY&=wrap360;
3978 } else if ( ((testangle>0) && (testangle<deg180)) || (testangle<-deg180) ) {
3979 eulr->EulerY-=(NormalFrameTime>>rate);
3980 eulr->EulerY&=wrap360;
3981 } else {
3982 eulr->EulerY+=(NormalFrameTime>>rate);
3983 eulr->EulerY&=wrap360;
3984 }
3985
3986 }
3987
3988 /* That was for the first plane. Now the second. */
3989
3990 offsetz=SqRoot32((offsetx*offsetx)+(offsety*offsety));
3991 offsety=-((Target->vy)-(source->vy));
3992
3993 angle1=ArcTan(offsety,offsetz);
3994 angle2=eulr->EulerX;
3995
3996 if (angle1!=angle2) {
3997 testangle=angle2-angle1;
3998 if (abs(testangle)<(NormalFrameTime>>rate)) {
3999 eulr->EulerX=angle1;
4000 eulr->EulerX&=wrap360;
4001 } else if ( ((testangle>0) && (testangle<deg180)) || (testangle<-deg180) ) {
4002 eulr->EulerX-=(NormalFrameTime>>rate);
4003 eulr->EulerX&=wrap360;
4004 } else {
4005 eulr->EulerX+=(NormalFrameTime>>rate);
4006 eulr->EulerX&=wrap360;
4007 }
4008 }
4009
4010 }
4011
4012 int PredDisc_TargetFilter(STRATEGYBLOCK *candidate) {
4013
4014 switch (candidate->I_SBtype) {
4015 case I_BehaviourAlien:
4016 {
4017 ALIEN_STATUS_BLOCK *alienStatusPointer;
4018 LOCALASSERT(candidate);
4019 LOCALASSERT(candidate->DynPtr);
4020
4021 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(candidate->SBdataptr);
4022
4023 if (alienStatusPointer->BehaviourState==ABS_Dying) {
4024 return(0);
4025 } else {
4026 return(1);
4027 }
4028 break;
4029 }
4030 case I_BehaviourQueenAlien:
4031 case I_BehaviourFaceHugger:
4032 case I_BehaviourPredator:
4033 case I_BehaviourXenoborg:
4034 case I_BehaviourMarine:
4035 case I_BehaviourSeal:
4036 case I_BehaviourPredatorAlien:
4037 /* Valid. */
4038 return(1);
4039 break;
4040 case I_BehaviourNetGhost:
4041 {
4042 NETGHOSTDATABLOCK *dataptr;
4043 dataptr=candidate->SBdataptr;
4044 switch (dataptr->type) {
4045 case I_BehaviourMarinePlayer:
4046 case I_BehaviourAlienPlayer:
4047 case I_BehaviourPredatorPlayer:
4048 return(1);
4049 break;
4050 default:
4051 return(0);
4052 break;
4053 }
4054 }
4055 break;
4056 default:
4057 return(0);
4058 break;
4059 }
4060
4061 }
4062
4063 void PredDisc_GetFirstTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr, DISPLAYBLOCK *target, VECTORCH *position) {
4064
4065 int a;
4066
4067 if (target!=NULL) {
4068 if (target->ObStrategyBlock!=NULL) {
4069 if (PredDisc_TargetFilter(target->ObStrategyBlock)) {
4070 /* Valid. */
4071 bptr->Target=target->ObStrategyBlock;
4072 COPY_NAME(bptr->Target_SBname,target->ObStrategyBlock->SBname);
4073 return;
4074 }
4075 }
4076 }
4077
4078 /* Second try. */
4079
4080 bptr->Target=PredDisc_GetNewTarget(bptr,position,NULL,2);
4081 if (bptr->Target!=NULL) {
4082 COPY_NAME(bptr->Target_SBname,bptr->Target->SBname);
4083 return;
4084 }
4085
4086 /* Failed! */
4087
4088 bptr->Target=NULL;
4089 {
4090 for (a=0; a<SB_NAME_LENGTH; a++) {
4091 bptr->Target_SBname[a]='\0';
4092 }
4093 }
4094
4095 }
4096
4097 int ObjectIsOnScreen(DISPLAYBLOCK *object) {
4098
4099 int a;
4100 extern DISPLAYBLOCK *OnScreenBlockList[];
4101 extern int NumOnScreenBlocks;
4102
4103 for (a=0; a<NumOnScreenBlocks; a++) {
4104 if (OnScreenBlockList[a]==object) break;
4105 }
4106
4107 if (a==NumOnScreenBlocks) return(0); else return(1);
4108
4109 }
4110
4111 #define DISC_PROX_RANGE 90000
4112
4113 STRATEGYBLOCK *PredDisc_GetNewTarget(PC_PRED_DISC_BEHAV_BLOCK *bptr,VECTORCH *discpos, STRATEGYBLOCK *prevtarg, int mine) {
4114
4115 int a,neardist;
4116 STRATEGYBLOCK *nearest;
4117 STRATEGYBLOCK *candidate;
4118 MODULE *dmod;
4119
4120 dmod=ModuleFromPosition(discpos,playerPherModule);
4121
4122 LOCALASSERT(dmod);
4123
4124 nearest=NULL;
4125 neardist=ONE_FIXED;
4126
4127 for (a=0; a<NumActiveStBlocks; a++) {
4128 candidate=ActiveStBlockList[a];
4129 if ((candidate!=prevtarg)&&(candidate!=Player->ObStrategyBlock)) {
4130 if (candidate->DynPtr) {
4131 if (PredDisc_TargetFilter(candidate)) {
4132 VECTORCH offset;
4133 int dist;
4134
4135 offset.vx=discpos->vx-candidate->DynPtr->Position.vx;
4136 offset.vy=discpos->vy-candidate->DynPtr->Position.vy;
4137 offset.vz=discpos->vz-candidate->DynPtr->Position.vz;
4138
4139 dist=Approximate3dMagnitude(&offset);
4140
4141 if (! ((mine==1)&&dist>DISC_PROX_RANGE)) {
4142 if (dist<neardist) {
4143 /* Check visibility? */
4144 if (candidate->SBdptr) {
4145 if (!NPC_IsDead(candidate)) {
4146 /* Not the last one again! */
4147 if (!NAME_ISEQUAL(bptr->Prev_Target_SBname,candidate->SBname)) {
4148 if (mine==1) {
4149 if (IsThisObjectVisibleFromThisPosition(candidate->SBdptr,discpos,DISC_PROX_RANGE) ) {
4150 nearest=candidate;
4151 }
4152 } else if (mine==2) {
4153 if (ObjectIsOnScreen(candidate->SBdptr)) {
4154 nearest=candidate;
4155 }
4156 } else if (candidate->containingModule) {
4157 if ((IsModuleVisibleFromModule(dmod,candidate->containingModule))) {
4158 nearest=candidate;
4159 }
4160 }
4161 }
4162 }
4163 }
4164 }
4165 }
4166 }
4167 }
4168 }
4169 }
4170
4171 return(nearest);
4172
4173 }
4174
4175
4176
4177 void NukeObject(STRATEGYBLOCK *sbPtr)
4178 {
4179 CauseDamageToObject(sbPtr, &certainDeath, ONE_FIXED,NULL);
4180 }
4181
4182
4183
4184 DISPLAYBLOCK *SpawnMolotovCocktail(SECTION_DATA *root, MATRIXCH *master_orient)
4185 {
4186
4187 DISPLAYBLOCK *dispPtr;
4188 STRATEGYBLOCK *sbPtr;
4189 MODULEMAPBLOCK *mmbptr;
4190 MODULE m_temp;
4191 AVP_BEHAVIOUR_TYPE bhvr;
4192 int woundflags;
4193
4194 //if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL;
4195
4196 // 1. Set up shape data BEFORE making the displayblock,
4197 // since "AllocateModuleObject()" will fill in shapeheader
4198 // information and extent data
4199
4200 mmbptr = &TempModuleMap;
4201
4202 /* Doesn't really matter what shape gets generated... */
4203 //CreateShapeInstance(mmbptr,root->sempai->ShapeName);
4204 CreateShapeInstance(mmbptr,"Shell");
4205
4206 bhvr = I_BehaviourMolotov;
4207
4208 // And allocate the modulemapblock object
4209
4210 m_temp.m_numlights = 0;
4211 m_temp.m_lightarray = NULL;
4212 m_temp.m_mapptr = mmbptr;
4213 m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
4214 m_temp.m_dptr = NULL;
4215 AllocateModuleObject(&m_temp);
4216 dispPtr = m_temp.m_dptr;
4217 if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */
4218
4219 dispPtr->ObMyModule = NULL; /* Module that created us */
4220
4221 if(root) //allow case root==NULL for loading
4222 {
4223 dispPtr->ObWorld = root->World_Offset;
4224 }
4225
4226 sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
4227
4228 if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block
4229
4230 // 2. NOW set up the strategyblock-specific fields for
4231 // the new displayblock. We won't go through the "AttachNew
4232 // StrategyBlock" and "AssignRunTimeBehaviours" pair, since
4233 // the first switches on ObShape and the second on bhvr;
4234 // but, in this case, there isn't a particular connection
4235 // between them.
4236
4237 sbPtr->I_SBtype = bhvr;
4238
4239 {
4240 DYNAMICSBLOCK *dynPtr;
4241
4242 sbPtr->SBdataptr = (MOLOTOV_BEHAV_BLOCK *) AllocateMem(sizeof(MOLOTOV_BEHAV_BLOCK));
4243 if (sbPtr->SBdataptr == 0) {
4244 // Failed to allocate a strategy block data pointer
4245 RemoveBehaviourStrategy(sbPtr);
4246 return (DISPLAYBLOCK*)NULL;
4247 }
4248
4249 ((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = 65536;//32767;//FastRandom()&32767;
4250
4251 if(root) //allow case root==NULL for loading
4252 {
4253 woundflags=Splice_HModels(&(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),root);
4254 InitHModelSequence( &(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),0,1,ONE_FIXED);
4255 }
4256
4257 dispPtr->HModelControlBlock=&(((MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController);
4258
4259 if(root) //allow case root==NULL for loading
4260 {
4261 dispPtr->ObWorld=root->World_Offset;
4262 dispPtr->ObMat=root->SecMat;
4263 }
4264
4265 LOCALASSERT(dispPtr->ObWorld.vx<1000000 && dispPtr->ObWorld.vx>-1000000);
4266 LOCALASSERT(dispPtr->ObWorld.vy<1000000 && dispPtr->ObWorld.vy>-1000000);
4267 LOCALASSERT(dispPtr->ObWorld.vz<1000000 && dispPtr->ObWorld.vz>-1000000);
4268
4269 ProveHModel(dispPtr->HModelControlBlock,dispPtr);
4270
4271 dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_GRENADE);
4272
4273 if (dynPtr == 0) {
4274 // Failed to allocate a dynamics block
4275 RemoveBehaviourStrategy(sbPtr);
4276 return (DISPLAYBLOCK*)NULL;
4277 }
4278
4279 if(root) //allow case root==NULL for loading
4280 {
4281 dynPtr->Position = root->World_Offset;
4282
4283 dynPtr->OrientMat=root->SecMat;
4284 }
4285
4286 // Give explosion fragments an angular velocity
4287 dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024;
4288 dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024;
4289 dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024;
4290
4291 dynPtr->LinVelocity.vx=0;
4292 dynPtr->LinVelocity.vy=0;
4293 dynPtr->LinVelocity.vz=0;
4294
4295 dynPtr->IgnoreThePlayer=0;
4296
4297 {
4298 /* Handle velocity... */
4299 //VECTORCH start={0,2000,12000};
4300 MATRIXCH tm=*master_orient;
4301 VECTORCH start;
4302
4303 start.vx=mx;
4304 start.vy=my;
4305 start.vz=mz;
4306
4307 RotateAndCopyVector(&start,&dynPtr->LinImpulse,&tm);
4308
4309 }
4310
4311 }
4312
4313
4314 return dispPtr;
4315
4316 }
4317 extern void MolotovBehaviour(STRATEGYBLOCK *sbPtr)
4318 {
4319 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
4320 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
4321 MOLOTOV_BEHAV_BLOCK *bbPtr = (MOLOTOV_BEHAV_BLOCK * ) sbPtr->SBdataptr;
4322 int explodeNow = 0;
4323
4324 //Work out the containing module now , since it doesn't seem to get done anywhere else
4325 sbPtr->containingModule = ModuleFromPosition(&(sbPtr->DynPtr->Position), sbPtr->containingModule);
4326
4327 /* explode if the grenade touches an alien */
4328 while (reportPtr)
4329 {
4330 STRATEGYBLOCK *sbPtr = reportPtr->ObstacleSBPtr;
4331
4332 if(sbPtr)
4333 {
4334 if((sbPtr->I_SBtype == I_BehaviourAlien)
4335 ||(sbPtr->I_SBtype == I_BehaviourMarinePlayer)
4336 ||(sbPtr->I_SBtype == I_BehaviourAlienPlayer)
4337 ||(sbPtr->I_SBtype == I_BehaviourPredatorPlayer)
4338 ||(sbPtr->I_SBtype == I_BehaviourPredator)
4339 ||(sbPtr->I_SBtype == I_BehaviourXenoborg)
4340 ||(sbPtr->I_SBtype == I_BehaviourMarine)
4341 ||(sbPtr->I_SBtype == I_BehaviourQueenAlien)
4342 ||(sbPtr->I_SBtype == I_BehaviourPredatorAlien)
4343 ||(sbPtr->I_SBtype == I_BehaviourFaceHugger))
4344 {
4345 explodeNow = 1; /* kaboom */
4346 //explodeNow = 0; /* kaboom */
4347 }
4348
4349 if(sbPtr->I_SBtype == I_BehaviourNetGhost)
4350 {
4351 NETGHOSTDATABLOCK *ghostData = sbPtr->SBdataptr;
4352 LOCALASSERT(ghostData);
4353 LOCALASSERT(AvP.Network!=I_No_Network);
4354
4355 if((ghostData->type == I_BehaviourMarinePlayer)||
4356 (ghostData->type == I_BehaviourPredatorPlayer)||
4357 (ghostData->type == I_BehaviourAlienPlayer))
4358 {
4359 explodeNow = 1;
4360 }
4361 }
4362 } else {
4363 /* What the hell! */
4364 explodeNow=1;
4365 }
4366
4367 /* skip to next report */
4368 reportPtr = reportPtr->NextCollisionReportPtr;
4369 }
4370
4371 if ((bbPtr->counter<=0) || explodeNow)
4372 {
4373 /* KJL 17:51:56 12/17/96 - make explosion damage other objects */
4374 HandleEffectsOfExplosion
4375 (
4376 sbPtr,
4377 &(dynPtr->Position),
4378 TemplateAmmo[AMMO_MOLOTOV].MaxRange,
4379 &TemplateAmmo[AMMO_MOLOTOV].MaxDamage[AvP.Difficulty],
4380 TemplateAmmo[AMMO_MOLOTOV].ExplosionIsFlat
4381 );
4382
4383 if (sbPtr->containingModule) {
4384 Explosion_SoundData.position=dynPtr->Position;
4385 Sound_Play(SID_ED_MOLOTOV_EXPLOSION,"n",&Explosion_SoundData);
4386 }
4387
4388 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
4389
4390 /* destroy rocket */
4391 DestroyAnyStrategyBlock(sbPtr);
4392 }
4393 else
4394 {
4395 bbPtr->counter-=NormalFrameTime;
4396 DynamicallyRotateObject(dynPtr);
4397 }
4398 }
4399
4400 void FirePredPistolFlechettes(VECTORCH *base_position,VECTORCH *base_offset,MATRIXCH *orientmat,int player, int *timer,BOOL damaging) {
4401
4402 /* A cheap knock off of the flamethrower function, so as not to rock the boat. */
4403
4404 VECTORCH position;
4405
4406 (*timer)+=NormalFrameTime;
4407
4408 while ((*timer)>=TIME_FOR_PREDPISTOLFLECHETTE)
4409 {
4410 VECTORCH velocity, ratio;
4411
4412 (*timer)-=TIME_FOR_PREDPISTOLFLECHETTE;
4413
4414 /* Calculate velocity... */
4415 velocity.vx = ((FastRandom()&1023) - 512)*PREDPISTOL_SPREAD;//*2;
4416 velocity.vy = ((FastRandom()&1023) - 512)*PREDPISTOL_SPREAD;//*2;
4417 velocity.vz = ((FastRandom()&1023) + 200+1024)*16; // Was 511, 512.
4418
4419 /* calculate the position */
4420
4421 {
4422 int offset = MUL_FIXED(FastRandom()&32767,NormalFrameTime); // Was 16383
4423
4424 position=*base_offset;
4425
4426 /* Make sure position corresponds to velocity direction... */
4427 ratio=velocity;
4428 Normalise(&ratio);
4429 position.vx += MUL_FIXED(offset,ratio.vx);
4430 position.vy += MUL_FIXED(offset,ratio.vy);
4431 position.vz += MUL_FIXED(offset,ratio.vz);
4432
4433 }
4434
4435 RotateVector(&position,orientmat);
4436
4437 if (player) {
4438 Crunch_Position_For_Players_Weapon(&position);
4439 } else {
4440 position.vx+=base_position->vx;
4441 position.vy+=base_position->vy;
4442 position.vz+=base_position->vz;
4443 }
4444
4445 RotateVector(&velocity,orientmat);
4446 MakeParticle(&position,&(velocity),damaging ? PARTICLE_PREDPISTOL_FLECHETTE : PARTICLE_PREDPISTOL_FLECHETTE_NONDAMAGING);
4447 }
4448
4449 }
4450
4451
4452 /*-------------------**
4453 ** Load/Save Grenade **
4454 **-------------------*/
4455 typedef struct grenade_save_block
4456 {
4457 SAVE_BLOCK_STRATEGY_HEADER header;
4458
4459 int counter;
4460 int bouncelastframe;
4461
4462 DYNAMICSBLOCK dynamics;
4463 }GRENADE_SAVE_BLOCK;
4464
4465 //defines for load/save macros
4466 #define SAVELOAD_BLOCK block
4467 #define SAVELOAD_BEHAV behav
4468
4469 void LoadStrategy_Grenade(SAVE_BLOCK_STRATEGY_HEADER* header)
4470 {
4471 STRATEGYBLOCK* sbPtr;
4472 GRENADE_BEHAV_BLOCK* behav;
4473 GRENADE_SAVE_BLOCK* block = (GRENADE_SAVE_BLOCK*) header;
4474
4475 //check the size of the save block
4476 if(header->size!=sizeof(*block)) return;
4477
4478 //create default grende
4479 sbPtr = CreateGrenadeKernel(I_BehaviourGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0);
4480 if(!sbPtr) return;
4481
4482 behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4483
4484 //copy stuff over
4485 COPYELEMENT_LOAD(counter);
4486 COPYELEMENT_LOAD(bouncelastframe);
4487
4488 *sbPtr->DynPtr = block->dynamics;
4489 }
4490
4491 void SaveStrategy_Grenade(STRATEGYBLOCK* sbPtr)
4492 {
4493 GRENADE_BEHAV_BLOCK* behav;
4494 GRENADE_SAVE_BLOCK* block;
4495
4496 behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4497 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4498
4499 COPYELEMENT_SAVE(counter);
4500 COPYELEMENT_SAVE(bouncelastframe);
4501
4502 block->dynamics = *sbPtr->DynPtr;
4503 block->dynamics.CollisionReportPtr=0;
4504
4505 }
4506
4507
4508 /*-------------------**
4509 ** Load/Save Cluster Grenade **
4510 **-------------------*/
4511 typedef struct cluster_grenade_save_block
4512 {
4513 SAVE_BLOCK_STRATEGY_HEADER header;
4514
4515 int counter;
4516 int bouncelastframe;
4517
4518 DYNAMICSBLOCK dynamics;
4519 }CLUSTER_GRENADE_SAVE_BLOCK;
4520
4521
4522 void LoadStrategy_ClusterGrenade(SAVE_BLOCK_STRATEGY_HEADER* header)
4523 {
4524 STRATEGYBLOCK* sbPtr;
4525 GRENADE_BEHAV_BLOCK* behav;
4526 CLUSTER_GRENADE_SAVE_BLOCK* block = (CLUSTER_GRENADE_SAVE_BLOCK*) header;
4527
4528 //check the size of the save block
4529 if(header->size!=sizeof(*block)) return;
4530
4531 //create default grenade
4532 sbPtr = CreateGrenadeKernel(I_BehaviourClusterGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0);
4533 if(!sbPtr) return;
4534
4535 behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4536
4537 //copy stuff over
4538 COPYELEMENT_LOAD(counter);
4539 COPYELEMENT_LOAD(bouncelastframe);
4540
4541 *sbPtr->DynPtr = block->dynamics;
4542 }
4543
4544 void SaveStrategy_ClusterGrenade(STRATEGYBLOCK* sbPtr)
4545 {
4546 GRENADE_BEHAV_BLOCK* behav;
4547 CLUSTER_GRENADE_SAVE_BLOCK* block;
4548
4549 behav = (GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4550 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4551
4552 COPYELEMENT_SAVE(counter);
4553 COPYELEMENT_SAVE(bouncelastframe);
4554
4555 block->dynamics = *sbPtr->DynPtr;
4556 block->dynamics.CollisionReportPtr=0;
4557
4558 }
4559
4560
4561 /*-------------------**
4562 ** Load/Save Flare Grenade **
4563 **-------------------*/
4564 typedef struct flare_grenade_save_block
4565 {
4566 SAVE_BLOCK_STRATEGY_HEADER header;
4567
4568 int LifeTimeRemaining;
4569 int ParticleGenerationTimer;
4570
4571 DYNAMICSBLOCK dynamics;
4572 }FLARE_GRENADE_SAVE_BLOCK;
4573
4574 void LoadStrategy_FlareGrenade(SAVE_BLOCK_STRATEGY_HEADER* header)
4575 {
4576 STRATEGYBLOCK* sbPtr;
4577 FLARE_BEHAV_BLOCK* behav;
4578 FLARE_GRENADE_SAVE_BLOCK* block = (FLARE_GRENADE_SAVE_BLOCK*) header;
4579
4580 //check the size of the save block
4581 if(header->size!=sizeof(*block)) return;
4582
4583 //create default grende
4584 sbPtr = CreateGrenadeKernel(I_BehaviourFlareGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0);
4585 if(!sbPtr) return;
4586
4587 behav = (FLARE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4588
4589 //copy stuff over
4590 COPYELEMENT_LOAD(LifeTimeRemaining)
4591 COPYELEMENT_LOAD(ParticleGenerationTimer)
4592
4593 *sbPtr->DynPtr = block->dynamics;
4594
4595 Load_SoundState(&behav->SoundHandle);
4596 }
4597
4598 void SaveStrategy_FlareGrenade(STRATEGYBLOCK* sbPtr)
4599 {
4600 FLARE_BEHAV_BLOCK* behav;
4601 FLARE_GRENADE_SAVE_BLOCK* block;
4602
4603 behav = (FLARE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4604 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4605
4606 COPYELEMENT_SAVE(LifeTimeRemaining)
4607 COPYELEMENT_SAVE(ParticleGenerationTimer)
4608
4609 block->dynamics = *sbPtr->DynPtr;
4610 block->dynamics.CollisionReportPtr=0;
4611
4612 Save_SoundState(&behav->SoundHandle);
4613
4614 }
4615
4616 /*-------------------**
4617 ** Load/Save Prox Grenade **
4618 **-------------------*/
4619 typedef struct prox_grenade_save_block
4620 {
4621 SAVE_BLOCK_STRATEGY_HEADER header;
4622
4623 int LifeTimeRemaining;
4624 int SoundGenerationTimer;
4625
4626 DYNAMICSBLOCK dynamics;
4627 }PROX_GRENADE_SAVE_BLOCK;
4628
4629 void LoadStrategy_ProxGrenade(SAVE_BLOCK_STRATEGY_HEADER* header)
4630 {
4631 STRATEGYBLOCK* sbPtr;
4632 PROX_GRENADE_BEHAV_BLOCK* behav;
4633 PROX_GRENADE_SAVE_BLOCK* block = (PROX_GRENADE_SAVE_BLOCK*) header;
4634
4635 //check the size of the save block
4636 if(header->size!=sizeof(*block)) return;
4637
4638 //create default grende
4639 sbPtr = CreateGrenadeKernel(I_BehaviourProximityGrenade,&block->dynamics.Position,&block->dynamics.OrientMat,0);
4640 if(!sbPtr) return;
4641
4642 behav = (PROX_GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4643
4644 //copy stuff over
4645 COPYELEMENT_LOAD(LifeTimeRemaining)
4646 COPYELEMENT_LOAD(SoundGenerationTimer)
4647
4648 *sbPtr->DynPtr = block->dynamics;
4649
4650 Load_SoundState(&behav->SoundHandle);
4651 }
4652
4653 void SaveStrategy_ProxGrenade(STRATEGYBLOCK* sbPtr)
4654 {
4655 PROX_GRENADE_BEHAV_BLOCK* behav;
4656 PROX_GRENADE_SAVE_BLOCK* block;
4657
4658 behav = (PROX_GRENADE_BEHAV_BLOCK*) sbPtr->SBdataptr;
4659 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4660
4661 COPYELEMENT_SAVE(LifeTimeRemaining)
4662 COPYELEMENT_SAVE(SoundGenerationTimer)
4663
4664 block->dynamics = *sbPtr->DynPtr;
4665 block->dynamics.CollisionReportPtr=0;
4666
4667 Save_SoundState(&behav->SoundHandle);
4668
4669 }
4670
4671 /*-------------------**
4672 ** Load/Save rocket **
4673 **-------------------*/
4674 typedef struct rocket_save_block
4675 {
4676 SAVE_BLOCK_STRATEGY_HEADER header;
4677
4678 int counter;
4679 int player;
4680
4681 DYNAMICSBLOCK dynamics;
4682 }ROCKET_SAVE_BLOCK;
4683
4684 void LoadStrategy_Rocket(SAVE_BLOCK_STRATEGY_HEADER* header)
4685 {
4686 STRATEGYBLOCK* sbPtr;
4687 PREDPISTOL_BEHAV_BLOCK* behav;
4688 ROCKET_SAVE_BLOCK* block = (ROCKET_SAVE_BLOCK*) header;
4689
4690 //check the size of the save block
4691 if(header->size!=sizeof(*block)) return;
4692
4693 //create default grende
4694 sbPtr = CreateRocketKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0);
4695 if(!sbPtr) return;
4696
4697 behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr;
4698
4699 //copy stuff over
4700 COPYELEMENT_LOAD(counter)
4701 COPYELEMENT_LOAD(player)
4702
4703 *sbPtr->DynPtr = block->dynamics;
4704 }
4705
4706 void SaveStrategy_Rocket(STRATEGYBLOCK* sbPtr)
4707 {
4708 PREDPISTOL_BEHAV_BLOCK* behav;
4709 ROCKET_SAVE_BLOCK* block;
4710
4711 behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr;
4712 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4713
4714 COPYELEMENT_SAVE(counter)
4715 COPYELEMENT_SAVE(player)
4716
4717 block->dynamics = *sbPtr->DynPtr;
4718 block->dynamics.CollisionReportPtr=0;
4719
4720 }
4721
4722
4723 /*-------------------**
4724 ** Load/Save PP plasma bolt **
4725 **-------------------*/
4726 typedef struct ppplasma_save_block
4727 {
4728 SAVE_BLOCK_STRATEGY_HEADER header;
4729
4730 int counter;
4731 int player;
4732
4733 DYNAMICSBLOCK dynamics;
4734 }PPPLASMA_SAVE_BLOCK;
4735
4736 void LoadStrategy_PPPlasmaBolt(SAVE_BLOCK_STRATEGY_HEADER* header)
4737 {
4738 STRATEGYBLOCK* sbPtr;
4739 PREDPISTOL_BEHAV_BLOCK* behav;
4740 PPPLASMA_SAVE_BLOCK* block = (PPPLASMA_SAVE_BLOCK*) header;
4741
4742 //check the size of the save block
4743 if(header->size!=sizeof(*block)) return;
4744
4745 //create default bolt
4746 sbPtr = CreatePPPlasmaBoltKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0);
4747 if(!sbPtr) return;
4748
4749 behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr;
4750
4751 //copy stuff over
4752 COPYELEMENT_LOAD(counter)
4753 COPYELEMENT_LOAD(player)
4754
4755 *sbPtr->DynPtr = block->dynamics;
4756 }
4757
4758 void SaveStrategy_PPPlasmaBolt(STRATEGYBLOCK* sbPtr)
4759 {
4760 PREDPISTOL_BEHAV_BLOCK* behav;
4761 PPPLASMA_SAVE_BLOCK* block;
4762
4763 behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr;
4764 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4765
4766 COPYELEMENT_SAVE(counter)
4767 COPYELEMENT_SAVE(player)
4768
4769 block->dynamics = *sbPtr->DynPtr;
4770 block->dynamics.CollisionReportPtr=0;
4771
4772 }
4773
4774
4775
4776
4777 /*-------------------**
4778 ** Load/Save energy bolt **
4779 **-------------------*/
4780 typedef struct pred_energy_bolt_save_block
4781 {
4782 SAVE_BLOCK_STRATEGY_HEADER header;
4783
4784 int counter;
4785 int player;
4786 DAMAGE_PROFILE damage;
4787 int blast_radius;
4788
4789 DYNAMICSBLOCK dynamics;
4790 }PREDATOR_ENERGY_BOLT_SAVE_BLOCK;
4791
4792 void LoadStrategy_PredatorEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header)
4793 {
4794 STRATEGYBLOCK* sbPtr;
4795 CASTER_BOLT_BEHAV_BLOCK* behav;
4796 PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block = (PREDATOR_ENERGY_BOLT_SAVE_BLOCK*) header;
4797
4798 //check the size of the save block
4799 if(header->size!=sizeof(*block)) return;
4800
4801 //create default bolt
4802 sbPtr = InitialiseEnergyBoltBehaviourKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0,&block->damage,ONE_FIXED);
4803 if(!sbPtr) return;
4804
4805 behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr;
4806
4807 //copy stuff over
4808 COPYELEMENT_LOAD(counter)
4809 COPYELEMENT_LOAD(player)
4810 COPYELEMENT_LOAD(damage)
4811 COPYELEMENT_LOAD(blast_radius)
4812
4813 *sbPtr->DynPtr = block->dynamics;
4814 }
4815
4816 void SaveStrategy_PredatorEnergyBolt(STRATEGYBLOCK* sbPtr)
4817 {
4818 CASTER_BOLT_BEHAV_BLOCK* behav;
4819 PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block;
4820
4821 behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr;
4822 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4823
4824 COPYELEMENT_SAVE(counter)
4825 COPYELEMENT_SAVE(player)
4826 COPYELEMENT_SAVE(damage)
4827 COPYELEMENT_SAVE(blast_radius)
4828
4829 block->dynamics = *sbPtr->DynPtr;
4830 block->dynamics.CollisionReportPtr=0;
4831
4832 }
4833
4834
4835
4836
4837 /*-------------------**
4838 ** Load/Save pulse grenade **
4839 **-------------------*/
4840 typedef struct pulse_grenade_save_block
4841 {
4842 SAVE_BLOCK_STRATEGY_HEADER header;
4843
4844 int counter;
4845 int player;
4846
4847 DYNAMICSBLOCK dynamics;
4848 }PULSE_GRENADE_SAVE_BLOCK;
4849
4850 void LoadStrategy_PulseGrenade(SAVE_BLOCK_STRATEGY_HEADER* header)
4851 {
4852 STRATEGYBLOCK* sbPtr;
4853 PREDPISTOL_BEHAV_BLOCK* behav;
4854 PULSE_GRENADE_SAVE_BLOCK* block = (PULSE_GRENADE_SAVE_BLOCK*) header;
4855
4856 //check the size of the save block
4857 if(header->size!=sizeof(*block)) return;
4858
4859 //create default grenade
4860 sbPtr = InitialisePulseGrenadeBehaviour();
4861 if(!sbPtr) return;
4862
4863 behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr;
4864
4865 //copy stuff over
4866 COPYELEMENT_LOAD(counter)
4867 COPYELEMENT_LOAD(player)
4868
4869 *sbPtr->DynPtr = block->dynamics;
4870 }
4871
4872 void SaveStrategy_PulseGrenade(STRATEGYBLOCK* sbPtr)
4873 {
4874 PREDPISTOL_BEHAV_BLOCK* behav;
4875 PULSE_GRENADE_SAVE_BLOCK* block;
4876
4877 behav = (PREDPISTOL_BEHAV_BLOCK*) sbPtr->SBdataptr;
4878 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4879
4880 COPYELEMENT_SAVE(counter)
4881 COPYELEMENT_SAVE(player)
4882
4883 block->dynamics = *sbPtr->DynPtr;
4884 block->dynamics.CollisionReportPtr=0;
4885
4886 }
4887
4888 /*-------------------**
4889 ** Load/Save molotov **
4890 **-------------------*/
4891 typedef struct molotov_save_block
4892 {
4893 SAVE_BLOCK_STRATEGY_HEADER header;
4894
4895 int counter;
4896
4897 DYNAMICSBLOCK dynamics;
4898 }MOLOTOV_SAVE_BLOCK;
4899
4900 void LoadStrategy_Molotov(SAVE_BLOCK_STRATEGY_HEADER* header)
4901 {
4902 STRATEGYBLOCK* sbPtr;
4903 DISPLAYBLOCK* dPtr;
4904 MOLOTOV_BEHAV_BLOCK* behav;
4905 PULSE_GRENADE_SAVE_BLOCK* block = (PULSE_GRENADE_SAVE_BLOCK*) header;
4906
4907 //check the size of the save block
4908 if(header->size!=sizeof(*block)) return;
4909
4910 //create default molotov
4911 dPtr = SpawnMolotovCocktail(0,&block->dynamics.OrientMat);
4912 if(!dPtr) return;
4913
4914 sbPtr = dPtr->ObStrategyBlock;
4915
4916 behav = (MOLOTOV_BEHAV_BLOCK*) sbPtr->SBdataptr;
4917
4918 //copy stuff over
4919 COPYELEMENT_LOAD(counter)
4920
4921 *sbPtr->DynPtr = block->dynamics;
4922
4923
4924 //load the molotov hierarchy
4925 {
4926 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
4927 if(hier_header)
4928 {
4929 LoadHierarchy(hier_header,&behav->HModelController);
4930 }
4931 }
4932
4933 }
4934
4935 void SaveStrategy_Molotov(STRATEGYBLOCK* sbPtr)
4936 {
4937 MOLOTOV_BEHAV_BLOCK* behav;
4938 PULSE_GRENADE_SAVE_BLOCK* block;
4939
4940 behav = (MOLOTOV_BEHAV_BLOCK*) sbPtr->SBdataptr;
4941 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
4942
4943 COPYELEMENT_SAVE(counter)
4944
4945 block->dynamics = *sbPtr->DynPtr;
4946 block->dynamics.CollisionReportPtr=0;
4947
4948 //save the molotov hierarchy
4949 SaveHierarchy(&behav->HModelController);
4950 }
4951
4952
4953
4954 /*-------------------------**
4955 ** Load/Save Predator Disc **
4956 **-------------------------*/
4957
4958
4959 typedef struct predator_disc_save_block
4960 {
4961 SAVE_BLOCK_STRATEGY_HEADER header;
4962
4963 //behaviour block stuff
4964 int counter;
4965 int Destruct:1;
4966 int Stuck :1;
4967 int Bounced :1;
4968 int bounces;
4969
4970 char Prev_Target_SBname[SB_NAME_LENGTH];
4971 char Prev_Damaged_SBname[SB_NAME_LENGTH];
4972 //pointer things
4973 char Target_SBname[SB_NAME_LENGTH];
4974
4975 //strategy block stuff
4976 int integrity;
4977 DAMAGEBLOCK SBDamageBlock;
4978 DYNAMICSBLOCK dynamics;
4979 }PREDATOR_DISC_SAVE_BLOCK;
4980
4981 void LoadStrategy_PredatorDisc(SAVE_BLOCK_STRATEGY_HEADER* header)
4982 {
4983 STRATEGYBLOCK* sbPtr;
4984 PC_PRED_DISC_BEHAV_BLOCK* behav;
4985 PREDATOR_DISC_SAVE_BLOCK* block = (PREDATOR_DISC_SAVE_BLOCK*) header;
4986
4987 //check the size of the save block
4988 if(header->size!=sizeof(*block)) return;
4989
4990 //create default disc
4991 sbPtr = InitialiseDiscBehaviour_ForLoad();
4992 if(!sbPtr) return;
4993
4994 behav = (PC_PRED_DISC_BEHAV_BLOCK*) sbPtr->SBdataptr;
4995
4996 COPYELEMENT_LOAD(counter)
4997 COPYELEMENT_LOAD(Destruct)
4998 COPYELEMENT_LOAD(Stuck)
4999 COPYELEMENT_LOAD(Bounced)
5000 COPYELEMENT_LOAD(bounces)
5001
5002 COPY_NAME(behav->Target_SBname,block->Target_SBname);
5003 COPY_NAME(behav->Prev_Target_SBname,block->Prev_Target_SBname);
5004 COPY_NAME(behav->Prev_Damaged_SBname,block->Prev_Damaged_SBname);
5005 behav->Target = FindSBWithName(behav->Target_SBname);
5006
5007 //strategy block stuff
5008 *sbPtr->DynPtr = block->dynamics;
5009 sbPtr->integrity = block->integrity;
5010 sbPtr->SBDamageBlock = block->SBDamageBlock;
5011
5012 //load the hierarchy
5013 {
5014 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
5015 if(hier_header)
5016 {
5017 LoadHierarchy(hier_header,&behav->HModelController);
5018 }
5019 }
5020 Load_SoundState(&behav->soundHandle);
5021 }
5022
5023 void SaveStrategy_PredatorDisc(STRATEGYBLOCK* sbPtr)
5024 {
5025 PREDATOR_DISC_SAVE_BLOCK *block;
5026 PC_PRED_DISC_BEHAV_BLOCK *behav;
5027
5028
5029 behav = (PC_PRED_DISC_BEHAV_BLOCK*)sbPtr->SBdataptr;
5030 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
5031
5032 //start copying stuff
5033 COPYELEMENT_SAVE(counter)
5034 COPYELEMENT_SAVE(Destruct)
5035 COPYELEMENT_SAVE(Stuck)
5036 COPYELEMENT_SAVE(Bounced)
5037 COPYELEMENT_SAVE(bounces)
5038
5039 COPY_NAME(block->Target_SBname,behav->Target_SBname);
5040 COPY_NAME(block->Prev_Target_SBname,behav->Prev_Target_SBname);
5041 COPY_NAME(block->Prev_Damaged_SBname,behav->Prev_Damaged_SBname);
5042
5043 //strategy block stuff
5044 block->dynamics = *sbPtr->DynPtr;
5045 block->dynamics.CollisionReportPtr=0;
5046
5047 block->integrity = sbPtr->integrity;
5048 block->SBDamageBlock = sbPtr->SBDamageBlock;
5049 //save hierarchy
5050 SaveHierarchy(&behav->HModelController);
5051
5052 Save_SoundState(&behav->soundHandle);
5053 }
5054
5055
5056
5057 /*-------------------------**
5058 ** Load/Save speargun bolt **
5059 **-------------------------*/
5060
5061 typedef struct spear_bolt_save_block
5062 {
5063 SAVE_BLOCK_STRATEGY_HEADER header;
5064
5065 //behaviour block stuff
5066 int counter;
5067 MATRIXCH Orient;
5068 VECTORCH Position;
5069 // HMODELCONTROLLER HierarchicalFragment;
5070 int Android;
5071 AVP_BEHAVIOUR_TYPE Type;
5072 int SubType;
5073 unsigned int SpearThroughFragment;
5074 unsigned int Stuck :1;
5075
5076 //strategy block stuff
5077 DYNAMICSBLOCK dynamics;
5078 }SPEAR_BOLT_SAVE_BLOCK;
5079
5080
5081 void LoadStrategy_SpearBolt(SAVE_BLOCK_HEADER* header)
5082 {
5083 DISPLAYBLOCK* dPtr;
5084 STRATEGYBLOCK* sbPtr;
5085 SPEAR_BEHAV_BLOCK* behav;
5086 SPEAR_BOLT_SAVE_BLOCK* block = (SPEAR_BOLT_SAVE_BLOCK*) header;
5087
5088 //check the size of the save block
5089 if(header->size!=sizeof(*block)) return;
5090
5091 //create default spear bolt
5092 dPtr = InitialiseSpeargunBoltBehaviour_ForLoad();
5093 if(!dPtr) return;
5094
5095 sbPtr = dPtr->ObStrategyBlock;
5096 if(!sbPtr) return;
5097
5098 behav = (SPEAR_BEHAV_BLOCK*)sbPtr->SBdataptr;
5099
5100 COPYELEMENT_LOAD(counter)
5101 COPYELEMENT_LOAD(Orient)
5102 COPYELEMENT_LOAD(Position)
5103 COPYELEMENT_LOAD(Android)
5104 COPYELEMENT_LOAD(Type)
5105 COPYELEMENT_LOAD(SubType)
5106 COPYELEMENT_LOAD(SpearThroughFragment)
5107 COPYELEMENT_LOAD(Stuck)
5108
5109 *sbPtr->DynPtr = block->dynamics;
5110
5111 {
5112 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
5113 if(hier_header)
5114 {
5115 LoadHierarchy(hier_header,&behav->HierarchicalFragment);
5116 }
5117 }
5118 //if there is a hierarchy fill it in the displayblock
5119 if(behav->HierarchicalFragment.Root_Section)
5120 {
5121 dPtr->HModelControlBlock = &behav->HierarchicalFragment;
5122 }
5123 }
5124
5125 void SaveStrategy_SpearBolt(STRATEGYBLOCK* sbPtr)
5126 {
5127 SPEAR_BOLT_SAVE_BLOCK *block;
5128 SPEAR_BEHAV_BLOCK *behav;
5129
5130 behav = (SPEAR_BEHAV_BLOCK*)sbPtr->SBdataptr;
5131 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
5132
5133
5134
5135 COPYELEMENT_SAVE(counter)
5136 COPYELEMENT_SAVE(Orient)
5137 COPYELEMENT_SAVE(Position)
5138 COPYELEMENT_SAVE(Android)
5139 COPYELEMENT_SAVE(Type)
5140 COPYELEMENT_SAVE(SubType)
5141 COPYELEMENT_SAVE(SpearThroughFragment)
5142 COPYELEMENT_SAVE(Stuck)
5143
5144 block->dynamics = *sbPtr->DynPtr;
5145 block->dynamics.CollisionReportPtr=0;
5146
5147 //save the hierarchy
5148 SaveHierarchy(&behav->HierarchicalFragment);
5149 }
5150
5151 typedef struct frisbee_save_block
5152 {
5153 SAVE_BLOCK_STRATEGY_HEADER header;
5154
5155 //behaviour block stuff
5156 int counter;
5157 int Bounced :1;
5158 int bounces;
5159
5160 //strategy block stuff
5161 int integrity;
5162 DAMAGEBLOCK SBDamageBlock;
5163 DYNAMICSBLOCK dynamics;
5164 } FRISBEE_SAVE_BLOCK;
5165
5166 void LoadStrategy_Frisbee(SAVE_BLOCK_STRATEGY_HEADER* header)
5167 {
5168 STRATEGYBLOCK* sbPtr;
5169 FRISBEE_BEHAV_BLOCK* behav;
5170 FRISBEE_SAVE_BLOCK* block = (FRISBEE_SAVE_BLOCK*) header;
5171
5172 //check the size of the save block
5173 if(header->size!=sizeof(*block)) return;
5174
5175 //create default disc
5176 sbPtr = InitialiseFrisbeeBehaviour_ForLoad();
5177 if(!sbPtr) return;
5178
5179 behav = (FRISBEE_BEHAV_BLOCK*) sbPtr->SBdataptr;
5180
5181 COPYELEMENT_LOAD(counter)
5182 COPYELEMENT_LOAD(Bounced)
5183 COPYELEMENT_LOAD(bounces)
5184
5185 //strategy block stuff
5186 *sbPtr->DynPtr = block->dynamics;
5187 sbPtr->integrity = block->integrity;
5188 sbPtr->SBDamageBlock = block->SBDamageBlock;
5189
5190 //load the hierarchy
5191 {
5192 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
5193 if(hier_header)
5194 {
5195 LoadHierarchy(hier_header,&behav->HModelController);
5196 }
5197 }
5198 Load_SoundState(&behav->soundHandle);
5199 }
5200
5201 void SaveStrategy_Frisbee(STRATEGYBLOCK* sbPtr)
5202 {
5203 FRISBEE_SAVE_BLOCK *block;
5204 FRISBEE_BEHAV_BLOCK *behav;
5205
5206
5207 behav = (FRISBEE_BEHAV_BLOCK*)sbPtr->SBdataptr;
5208 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
5209
5210 //start copying stuff
5211 COPYELEMENT_SAVE(counter)
5212 COPYELEMENT_SAVE(Bounced)
5213 COPYELEMENT_SAVE(bounces)
5214
5215 //strategy block stuff
5216 block->dynamics = *sbPtr->DynPtr;
5217 block->dynamics.CollisionReportPtr=0;
5218
5219 block->integrity = sbPtr->integrity;
5220 block->SBDamageBlock = sbPtr->SBDamageBlock;
5221 //save hierarchy
5222 SaveHierarchy(&behav->HModelController);
5223
5224 Save_SoundState(&behav->soundHandle);
5225 }
5226
5227 STRATEGYBLOCK* InitialiseFrisbeeBoltBehaviourKernel(VECTORCH *position,MATRIXCH *orient, int player, DAMAGE_PROFILE *damage, int factor) {
5228
5229 DISPLAYBLOCK *dispPtr;
5230 DYNAMICSBLOCK *dynPtr;
5231
5232 /* make displayblock with correct shape, etc */
5233 dispPtr = MakeObject(I_BehaviourFrisbeeEnergyBolt,position);
5234 if (dispPtr == 0) return NULL; // Failed to allocate display block
5235
5236 dispPtr->SfxPtr = AllocateSfxBlock();
5237
5238 if (!dispPtr->SfxPtr)
5239 {
5240 // Failed to allocate a special fx block
5241 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
5242 return NULL;
5243 }
5244
5245 dispPtr->SfxPtr->SfxID = SFX_FRISBEE_PLASMA_BOLT;
5246 /* make displayblock a dynamic module object */
5247 dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
5248 dispPtr->ObShape = 0;
5249 dispPtr->ObStrategyBlock->shapeIndex = 0;
5250 dispPtr->ObMinX = -50;
5251 dispPtr->ObMinY = -50;
5252 dispPtr->ObMinZ = -50;
5253 dispPtr->ObMaxX = 50;
5254 dispPtr->ObMaxY = 50;
5255 dispPtr->ObMaxZ = 50;
5256 /* add lighting effect */
5257 AddLightingEffectToObject(dispPtr,LFX_PLASMA_BOLT);
5258
5259 /* setup dynamics block */
5260 dynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET);
5261
5262 if (dynPtr == 0)
5263 {
5264 // Failed to allocate a dynamics block
5265 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
5266 return NULL;
5267 }
5268
5269 dispPtr->ObStrategyBlock->DynPtr = dynPtr;
5270
5271 /* give missile a maximum lifetime */
5272 dispPtr->ObStrategyBlock->SBdataptr=AllocateMem(sizeof(CASTER_BOLT_BEHAV_BLOCK));
5273
5274 if (dispPtr->ObStrategyBlock->SBdataptr == 0)
5275 {
5276 // Failed to allocate a strategy block data pointer
5277 RemoveBehaviourStrategy(dispPtr->ObStrategyBlock);
5278 return NULL;
5279 }
5280
5281 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->counter = 5*ONE_FIXED;
5282 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->damage = *damage;
5283 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->blast_radius = MUL_FIXED(factor,Caster_BlastRadius);
5284 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->player = player;
5285 ((CASTER_BOLT_BEHAV_BLOCK *)dispPtr->ObStrategyBlock->SBdataptr)->soundHandle = SOUND_NOACTIVEINDEX;
5286
5287 /* align rocket to launcher */
5288 dynPtr->Position=*position;
5289 dynPtr->PrevPosition=*position;
5290
5291 dynPtr->IgnoreSameObjectsAsYou = 1;
5292
5293 //GetGunDirection(&(dynPtr->LinVelocity),&position);
5294 //MakeMatrixFromDirection(&(dynPtr->LinVelocity),&(dynPtr->OrientMat));
5295 //MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
5296 //dynPtr->PrevOrientMat = dynPtr->OrientMat;
5297
5298 /* align velocity too */
5299 dynPtr->OrientMat = *orient;
5300 dynPtr->PrevOrientMat = dynPtr->OrientMat;
5301 /* I added this next line for networking: Patrick */
5302 MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler);
5303
5304 /* align velocity too */
5305 dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31;
5306 dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32;
5307 dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33;
5308
5309 dynPtr->LinVelocity.vx = MUL_FIXED(dynPtr->LinVelocity.vx, ENERGY_BOLT_SPEED);
5310 dynPtr->LinVelocity.vy = MUL_FIXED(dynPtr->LinVelocity.vy, ENERGY_BOLT_SPEED);
5311 dynPtr->LinVelocity.vz = MUL_FIXED(dynPtr->LinVelocity.vz, ENERGY_BOLT_SPEED);
5312
5313
5314 if(AvP.Network != I_No_Network) AddNetGameObjectID(dispPtr->ObStrategyBlock);
5315
5316 /* Extra cunning! */
5317 Sound_Play(SID_PRED_LAUNCHER,"hpd",(FastRandom()&255)-128,&dynPtr->Position);
5318
5319 if (player==0) {
5320 dynPtr->IgnoreThePlayer=0;
5321 }
5322
5323 return dispPtr->ObStrategyBlock;
5324 }
5325
5326 extern void FrisbeeEnergyBoltBehaviour(STRATEGYBLOCK *sbPtr)
5327 {
5328 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
5329 COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr;
5330 CASTER_BOLT_BEHAV_BLOCK *bbPtr = (CASTER_BOLT_BEHAV_BLOCK * ) sbPtr->SBdataptr;
5331 STRATEGYBLOCK *victim;
5332
5333 victim=NULL;
5334
5335 MakeDewlineTrailParticles(dynPtr,32);
5336
5337 /* check for a collision with something */
5338 if (bbPtr->counter <= 0)
5339 {
5340 /* for net game support: send a message saying we've blown up... */
5341 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
5342
5343 DestroyAnyStrategyBlock(sbPtr); /* timed-out */
5344 }
5345 else if (reportPtr)
5346 {
5347 if(reportPtr->ObstacleSBPtr)
5348 {
5349 VECTORCH attack_dir;
5350
5351 /* Accuracy snipped again! */
5352
5353 GetDirectionOfAttack(reportPtr->ObstacleSBPtr,&dynPtr->LinVelocity,&attack_dir);
5354
5355 switch (reportPtr->ObstacleSBPtr->I_SBtype)
5356 {
5357 /* No specific location damage. */
5358 default:
5359 {
5360 CauseDamageToObject(reportPtr->ObstacleSBPtr,&bbPtr->damage, ONE_FIXED,NULL);
5361 victim=reportPtr->ObstacleSBPtr;
5362 break;
5363 }
5364 }
5365 }
5366
5367 #if 0
5368 {
5369 char hitEnvironment = 0;
5370
5371 if (reportPtr->ObstacleSBPtr)
5372 {
5373 DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->SBdptr;
5374 if (dispPtr)
5375 if (dispPtr->ObMyModule)
5376 {
5377 hitEnvironment=1;
5378 }
5379 }
5380 else
5381 {
5382 hitEnvironment = 1;
5383 }
5384
5385 if (hitEnvironment)
5386 {
5387 MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA);
5388 if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_DISSIPATINGPLASMA);
5389 }
5390 else
5391 {
5392 MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA);
5393 if (AvP.Network != I_No_Network) AddNetMsg_MakePlasmaExplosion(&(dynPtr->Position),&(dynPtr->PrevPosition),EXPLOSION_FOCUSEDPLASMA);
5394 }
5395 }
5396 #endif
5397
5398 if(AvP.Network != I_No_Network) AddNetMsg_LocalObjectDestroyed(sbPtr);
5399
5400 /* Splash damage? */
5401 HandleEffectsOfExplosion
5402 (
5403 victim,
5404 &(dynPtr->Position),
5405 bbPtr->blast_radius,
5406 &bbPtr->damage,
5407 0
5408 );
5409 DestroyAnyStrategyBlock(sbPtr);
5410 } else {
5411
5412 {
5413 VECTORCH direction;
5414 direction.vx = dynPtr->LinVelocity.vx + dynPtr->LinImpulse.vx;
5415 direction.vy = dynPtr->LinVelocity.vy + dynPtr->LinImpulse.vy;
5416 direction.vz = dynPtr->LinVelocity.vz + dynPtr->LinImpulse.vz;
5417 Normalise(&direction);
5418 MakeMatrixFromDirection(&direction,&dynPtr->OrientMat);
5419 }
5420 bbPtr->counter -= NormalFrameTime;
5421 }
5422
5423 }
5424
5425 void LoadStrategy_FrisbeeEnergyBolt(SAVE_BLOCK_STRATEGY_HEADER* header)
5426 {
5427 STRATEGYBLOCK* sbPtr;
5428 CASTER_BOLT_BEHAV_BLOCK* behav;
5429 PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block = (PREDATOR_ENERGY_BOLT_SAVE_BLOCK*) header;
5430
5431 //check the size of the save block
5432 if(header->size!=sizeof(*block)) return;
5433
5434 //create default bolt
5435 sbPtr = InitialiseFrisbeeBoltBehaviourKernel(&block->dynamics.Position,&block->dynamics.OrientMat,0,&block->damage,ONE_FIXED);
5436 if(!sbPtr) return;
5437
5438 behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr;
5439
5440 //copy stuff over
5441 COPYELEMENT_LOAD(counter)
5442 COPYELEMENT_LOAD(player)
5443 COPYELEMENT_LOAD(damage)
5444 COPYELEMENT_LOAD(blast_radius)
5445
5446 *sbPtr->DynPtr = block->dynamics;
5447 }
5448
5449 void SaveStrategy_FrisbeeEnergyBolt(STRATEGYBLOCK* sbPtr)
5450 {
5451 CASTER_BOLT_BEHAV_BLOCK* behav;
5452 PREDATOR_ENERGY_BOLT_SAVE_BLOCK* block;
5453
5454 behav = (CASTER_BOLT_BEHAV_BLOCK*) sbPtr->SBdataptr;
5455 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
5456
5457 COPYELEMENT_SAVE(counter)
5458 COPYELEMENT_SAVE(player)
5459 COPYELEMENT_SAVE(damage)
5460 COPYELEMENT_SAVE(blast_radius)
5461
5462 block->dynamics = *sbPtr->DynPtr;
5463 block->dynamics.CollisionReportPtr=0;
5464
5465 }
5466