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&section_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&section_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