1 /* KJL 15:01:53 02/25/97 - bh_debri.c */
2 #include "3dc.h"
3 #include "module.h"
4 #include "inline.h"
5 #include "stratdef.h"
6 #include "gamedef.h"
7 #include "dynblock.h"
8 #include "dynamics.h"
9 #include "comp_shp.h"
10 #include "load_shp.h"
11 #include "bh_types.h"
12 #include "bh_debri.h"
13 #include "bh_weap.h"
14 #include "inventry.h"
15 #include "psnd.h"
16 #include "plat_shp.h"
17 #include "particle.h"
18 #include "jsndsup.h"
19 #include "bh_alien.h"
20 #include "bh_marin.h"
21 #include "bh_corpse.h"
22 
23 #define UseLocalAssert Yes
24 
25 #include "ourasert.h"
26 
27 #include "weapons.h"
28 #include "lighting.h"
29 #include "sfx.h"
30 
31 /* for win95 net game support */
32 #include "pldghost.h"
33 
34 #include "avp_userprofile.h"
35 #include "savegame.h"
36 
37 #include <math.h>
38 
39 #define HDEBRIS_BLEEDING_TIME	(ONE_FIXED*2)
40 
41 /*KJL****************************************************************************************
42 *                                    P R O T O T Y P E S	                                *
43 ****************************************************************************************KJL*/
44 void MakeFleshRippingNoises(VECTORCH *positionPtr);
45 
46 /*KJL****************************************************************************************
47 *  										G L O B A L S 	            					    *
48 ****************************************************************************************KJL*/
49 extern int NormalFrameTime;
50 void SetupSimpleAnimation(int counter, STRATEGYBLOCK *sbPtr);
51 extern int NumActiveBlocks;
52 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
53 extern void MakeBloodExplosion(VECTORCH *originPtr, int creationRadius, VECTORCH *blastPositionPtr, int noOfParticles, enum PARTICLE_ID particleID);
54 extern enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr);
55 extern int SBIsEnvironment(STRATEGYBLOCK *sbPtr);
56 extern void DoAlienLimbLossSound(VECTORCH *position);
57 
58 
59 
60 extern MATRIXCH Identity_RotMat; /* From HModel.c */
61 
62 int NextAlienFragmentToProduce;
63 
64 static char *ShapeNameOfAlienFragment[] =
65 {
66 	"AlFrga",
67 	"AlFrgb",
68 	"AlFrgc",
69 	"AlFrgd",
70 	"AlFrge",
71 	"AlFrgf",
72 	"AlFrgg",
73 	"AlFrgh",
74 	"AlFrgi",
75 	"AlFrgj",
76 };
77 #define NO_OF_DIFFERENT_ALIEN_FRAGS 10
78 
79 /*KJL****************************************************************************************
80 *                                     F U N C T I O N S	                                    *
81 ****************************************************************************************KJL*/
MakeDebris(AVP_BEHAVIOUR_TYPE bhvr,VECTORCH * positionPtr)82 DISPLAYBLOCK *MakeDebris(AVP_BEHAVIOUR_TYPE bhvr, VECTORCH *positionPtr)
83 {
84 
85 	DISPLAYBLOCK *dispPtr;
86   STRATEGYBLOCK *sbPtr;
87   MODULEMAPBLOCK *mmbptr;
88   MODULE m_temp;
89 
90   if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL;
91 
92   // 1. Set up shape data BEFORE making the displayblock,
93   // since "AllocateModuleObject()" will fill in shapeheader
94   // information and extent data
95 
96   mmbptr = &TempModuleMap;
97 
98   switch (bhvr)
99   {
100   		/* KJL 12:45:30 03/20/97 - fragments
101 		switch on object which is going to be destroyed and create the correct fragments */
102     case I_BehaviourAlien:
103 		{
104 			if( (NextAlienFragmentToProduce<0) || (NextAlienFragmentToProduce>=NO_OF_DIFFERENT_ALIEN_FRAGS))
105 				NextAlienFragmentToProduce=0;
106 
107 			/* cycle through the available body parts */
108 			CreateShapeInstance(mmbptr,ShapeNameOfAlienFragment[NextAlienFragmentToProduce++]);
109 
110 			/* 50/50 chance that it's an acid generator */
111 			if (FastRandom()&256)
112 			{
113 				bhvr = I_BehaviourAlienFragment;
114 			}
115 			else
116 			{
117 				bhvr = I_BehaviourFragment;
118 			}
119 			break;
120 		}
121 
122     case I_BehaviourPredator:
123 		{
124 			int randomNumber = FastRandom()&65535;
125 
126 			if (randomNumber>43691)
127 			{
128 				CreateShapeInstance(mmbptr,"Bodprt1");
129 			}
130 			else if (randomNumber>21845)
131 			{
132 				CreateShapeInstance(mmbptr,"Bodprt2");
133 			}
134 			else
135 			{
136 				CreateShapeInstance(mmbptr,"Bodprt3");
137 			}
138 			bhvr = I_BehaviourFragment;
139 			break;
140 		}
141 
142   	default:
143 		{
144       // Don't call this function for undefined types
145       GLOBALASSERT (1 == 0);
146 			break;
147     }
148 	}
149 
150   // And allocate the modulemapblock object
151 
152 	m_temp.m_numlights = 0;
153 	m_temp.m_lightarray = NULL;
154   m_temp.m_mapptr = mmbptr;
155   m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
156   m_temp.m_dptr = NULL;
157   AllocateModuleObject(&m_temp);
158   dispPtr = m_temp.m_dptr;
159 	if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */
160 
161   dispPtr->ObMyModule = NULL;     /* Module that created us */
162 	dispPtr->ObWorld = *positionPtr;
163 
164   sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
165 
166 	if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block
167 
168   // 2. NOW set up the strategyblock-specific fields for
169   // the new displayblock. We won't go through the "AttachNew
170   // StrategyBlock" and "AssignRunTimeBehaviours" pair, since
171   // the first switches on ObShape and the second on bhvr;
172   // but, in this case, there isn't a particular connection
173   // between them.
174 
175   sbPtr->I_SBtype = bhvr;
176 
177   switch (bhvr)
178   {
179 		case I_BehaviourAlienFragment:
180 		{
181 			DYNAMICSBLOCK *dynPtr;
182 
183 			sbPtr->SBdataptr = (SMOKEGEN_BEHAV_BLOCK *) AllocateMem(sizeof(SMOKEGEN_BEHAV_BLOCK));
184 			if (sbPtr->SBdataptr == 0)
185 			{
186 				// Failed to allocate a strategy block data pointer
187 				RemoveBehaviourStrategy(sbPtr);
188 				return (DISPLAYBLOCK*)NULL;
189 			}
190 
191 			((SMOKEGEN_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME;
192 			((SMOKEGEN_BEHAV_BLOCK * ) sbPtr->SBdataptr)->smokes=0;
193 
194 			dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS);
195 
196 			if (dynPtr == 0)
197 			{
198 				// Failed to allocate a dynamics block
199 				RemoveBehaviourStrategy(sbPtr);
200 				return (DISPLAYBLOCK*)NULL;
201 			}
202 
203 			dynPtr->Position = *positionPtr;
204 
205 			// Give explosion fragments an angular velocity
206 			dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024;
207 			dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024;
208 			dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024;
209 
210     		{
211 				int random = (FastRandom()&1023) - 512;
212 				if (random>0) dynPtr->LinImpulse.vx=(random+100)<<4;
213 				else dynPtr->LinImpulse.vx=(random-100)<<4;
214     		}
215     		{
216 				int random = (FastRandom()&1023) - 768;
217 				if (random>0) dynPtr->LinImpulse.vy=(random+100)<<4;
218 				else dynPtr->LinImpulse.vy=(random-100)<<4;
219 			}
220     		{
221 				int random = (FastRandom()&1023) - 512;
222 				if (random>0) dynPtr->LinImpulse.vz=(random+100)<<4;
223 				else dynPtr->LinImpulse.vz=(random-100)<<4;
224 			}
225 			break;
226 		}
227 		case I_BehaviourFragment:
228 		{
229 			DYNAMICSBLOCK *dynPtr;
230 
231 			sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK ));
232 			if (sbPtr->SBdataptr == 0)
233 			{
234 				// Failed to allocate a strategy block data pointer
235 				RemoveBehaviourStrategy(sbPtr);
236 				return(DISPLAYBLOCK*)NULL;
237 			}
238 
239 
240 			((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME;
241 
242 			dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS);
243 
244 			if (dynPtr == 0)
245 			{
246 				// Failed to allocate a dynamics block
247 				RemoveBehaviourStrategy(sbPtr);
248 				return(DISPLAYBLOCK*)NULL;
249 			}
250 
251 			dynPtr->Position = *positionPtr;
252 
253 			// Give explosion fragments an angular velocity
254 			dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024;
255 			dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024;
256 			dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024;
257 
258     		{
259 				int random = (FastRandom()&1023) - 512;
260 				if (random>0) dynPtr->LinImpulse.vx=(random+100)<<4;
261 				else dynPtr->LinImpulse.vx=(random-100)<<4;
262     		}
263     		{
264 				int random = (FastRandom()&1023) - 768;
265 				if (random>0) dynPtr->LinImpulse.vy=(random+100)<<4;
266 				else dynPtr->LinImpulse.vy=(random-100)<<4;
267 			}
268     		{
269 				int random = (FastRandom()&1023) - 512;
270 				if (random>0) dynPtr->LinImpulse.vz=(random+100)<<4;
271 				else dynPtr->LinImpulse.vz=(random-100)<<4;
272 			}
273 			break;
274 		}
275 
276 
277 	   		default:
278 		{
279 		    GLOBALASSERT (1 == 0);
280 		}
281     }
282 
283 
284     return dispPtr;
285 
286 }
287 
288 
289 
CreateShapeInstance(MODULEMAPBLOCK * mmbptr,char * shapeNamePtr)290 void CreateShapeInstance(MODULEMAPBLOCK *mmbptr, char *shapeNamePtr)
291 {
292 	int shapenum;
293 	shapenum = GetLoadedShapeMSL(shapeNamePtr);
294 	#if debug
295 	if (shapenum<=0)
296 	{
297 		textprint("Unable to display shape:%s\n",shapeNamePtr);
298 		LOCALASSERT(0);
299 	}
300 	#endif
301 
302     mmbptr->MapShape = shapenum;
303 	mmbptr->MapType = MapType_Default;
304 }
305 
306 
307 
308 
OneShotBehaveFun(STRATEGYBLOCK * sptr)309 void OneShotBehaveFun(STRATEGYBLOCK *sptr)
310 {
311 
312     // This fn. will have been called from "Execute Behaviour",
313     // as a consequence of "ObjectBehaviours" running each
314     // frame. It simply decrements the counter of the specified
315     // temporary object, and destroys it if that counter hits
316     // zero
317 
318 
319     ONE_SHOT_BEHAV_BLOCK *osbhv;
320     GLOBALASSERT(sptr);
321     osbhv = (ONE_SHOT_BEHAV_BLOCK * ) sptr->SBdataptr;
322     GLOBALASSERT(sptr->SBdptr);
323 
324     if (osbhv->counter < 0)
325     {
326     	DestroyAnyStrategyBlock(sptr);
327 		return;
328 	}
329 
330 	{
331 		DISPLAYBLOCK *dispPtr = sptr->SBdptr;
332 		/* do we have a displayblock? */
333 		if (dispPtr)
334 		{
335 			dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
336 			dispPtr->ObFlags2 = osbhv->counter/2;
337 
338 		}
339 	}
340     osbhv->counter -= NormalFrameTime;
341 
342 
343 	{
344 		DYNAMICSBLOCK *dynPtr = sptr->DynPtr;
345 
346 		if (dynPtr)
347 		{
348 			if (dynPtr->IsInContactWithFloor==0)
349 			{
350 				DynamicallyRotateObject(dynPtr);
351 			}
352 		}
353 	}
354 }
355 
356 
OneShot_Anim_BehaveFun(STRATEGYBLOCK * sptr)357 void OneShot_Anim_BehaveFun(STRATEGYBLOCK *sptr)
358 {
359 
360     // This fn. will have been called from "Execute Behaviour",
361     // as a consequence of "ObjectBehaviours" running each
362     // frame. It simply decrements the counter of the specified
363     // temporary object, and destroys it if that counter hits
364     // zero
365 
366 
367     ONESHOT_ANIM_BEHAV_BLOCK *osbhv;
368     DISPLAYBLOCK* dptr;
369 
370     GLOBALASSERT(sptr);
371     GLOBALASSERT(sptr->SBdptr);
372 
373     osbhv = (ONESHOT_ANIM_BEHAV_BLOCK * ) sptr->SBdataptr;
374 
375     if (osbhv->counter < 0)
376     {
377     	DestroyAnyStrategyBlock(sptr);
378 		return;
379 	}
380 
381     osbhv->counter -= NormalFrameTime;
382 
383 	{
384 		DYNAMICSBLOCK *dynPtr = sptr->DynPtr;
385 
386 		if (dynPtr)
387 		{
388 			if (dynPtr->IsInContactWithFloor==0)
389 			{
390 				DynamicallyRotateObject(dynPtr);
391 			}
392 		}
393 	}
394 
395 	dptr = sptr->SBdptr;
396 
397 	if(dptr)
398 	{
399 		if(!dptr->ObTxAnimCtrlBlks)
400 		{
401 			dptr->ObTxAnimCtrlBlks = osbhv->tac_os;
402 		}
403 	}
404 }
405 
406 
407 
SetupSimpleAnimation(int counter,STRATEGYBLOCK * sbPtr)408 void SetupSimpleAnimation(int counter, STRATEGYBLOCK *sbPtr)
409 {
410 	TXACTRLBLK **pptxactrlblk;
411 	int item_num;
412 	SHAPEHEADER* shptr;
413 	ONESHOT_ANIM_BEHAV_BLOCK* osab;
414 	DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
415 	int shape_num;
416 
417 	sbPtr->SBdataptr = (ONESHOT_ANIM_BEHAV_BLOCK *) AllocateMem(sizeof(ONESHOT_ANIM_BEHAV_BLOCK ));
418 
419 	if (sbPtr->SBdataptr == 0) return;	// Failed to allocate an sb data ptr
420 
421 	osab =	((ONESHOT_ANIM_BEHAV_BLOCK * ) sbPtr->SBdataptr);
422 
423 	osab->counter = counter;
424 
425 	shape_num = dispPtr->ObShape;
426 	shptr = GetShapeData(shape_num);
427 	pptxactrlblk = &osab->tac_os;
428 
429 	SetupPolygonFlagAccessForShape(shptr);
430 
431 	/*
432 	the bhdata is a ptr to the SHAPEHEADER each
433 	animating polygon has an array of sequences, in
434 	this case thers is only onr sequence per array
435 	*/
436 
437 	for(item_num = 0; item_num < shptr->numitems; item_num ++)
438 	{
439 		POLYHEADER *poly =  (POLYHEADER*)(shptr->items[item_num]);
440 		LOCALASSERT(poly);
441 
442 		if((Request_PolyFlags((void *)poly)) & iflag_txanim)
443 		{
444 			TXACTRLBLK *pnew_txactrlblk;
445 
446 			pnew_txactrlblk = AllocateMem(sizeof(TXACTRLBLK));
447 
448 			if (pnew_txactrlblk)
449 			{
450 				// We have allocated the new tx anim control block so initialise it
451 
452 				pnew_txactrlblk->tac_flags = 0;
453 				pnew_txactrlblk->tac_item = item_num;
454 				pnew_txactrlblk->tac_sequence = 0;
455 				pnew_txactrlblk->tac_node = 0;
456 				pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num);
457 				pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num);
458 
459 				pnew_txactrlblk->tac_txah.txa_currentframe = 0;
460 				pnew_txactrlblk->tac_txah.txa_flags = txa_flag_play|txa_flag_noloop;
461 
462 				/* change the value held in pptxactrlblk
463 				 which point to the previous structures "next"
464 			 	pointer*/
465 
466 				*pptxactrlblk = pnew_txactrlblk;
467 				pptxactrlblk = &pnew_txactrlblk->tac_next;
468 			}
469 	 	}
470 	}
471 	dispPtr->ObTxAnimCtrlBlks = osab->tac_os;
472 
473 	*pptxactrlblk=0;
474 }
475 
AlienFragFun(STRATEGYBLOCK * sptr)476 void AlienFragFun(STRATEGYBLOCK *sptr)
477 {
478 	int a;
479 	DYNAMICSBLOCK *dynptr;
480 	COLLISIONREPORT *reportptr;
481     SMOKEGEN_BEHAV_BLOCK *sgbhv;
482     GLOBALASSERT(sptr);
483     sgbhv = (SMOKEGEN_BEHAV_BLOCK * ) sptr->SBdataptr;
484     GLOBALASSERT(sptr->SBdptr);
485 
486 	dynptr=sptr->DynPtr;
487 
488 	GLOBALASSERT(dynptr);
489 
490 	reportptr=dynptr->CollisionReportPtr;
491 
492 	if (sgbhv->counter < 0)
493 	{
494 		DestroyAnyStrategyBlock(sptr);
495 		return;
496 	}
497 
498 	{
499 		DISPLAYBLOCK *dispPtr = sptr->SBdptr;
500 		/* do we have a displayblock? */
501 		if (dispPtr)
502 		{
503 			dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
504 			dispPtr->ObFlags2 = sgbhv->counter/2;
505 
506 		}
507 	}
508 	sgbhv->counter -= NormalFrameTime;
509 
510 	a=0;
511 
512 	while (reportptr) {
513 
514 		if (reportptr->ObstacleSBPtr==NULL) {
515 			#if 0
516 			if (a==0) {
517 				a=1;
518 				sgbhv->counter=1;
519 				sptr->I_SBtype=I_BehaviourSmokeGenerator;
520 			}
521 			#endif
522 		}
523 		else if (reportptr->ObstacleSBPtr->SBdptr==Player)
524 		{
525 
526 			CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
527 		}
528 		reportptr=reportptr->NextCollisionReportPtr;
529 	}
530 
531 	{
532 		DYNAMICSBLOCK *dynPtr = sptr->DynPtr;
533 
534 		if (dynPtr) {
535 			if (dynPtr->IsInContactWithFloor==0) {
536 				DynamicallyRotateObject(dynPtr);
537 			} else {
538 				dynPtr->AngVelocity.EulerX=0;
539 				dynPtr->AngVelocity.EulerY=0;
540 				dynPtr->AngVelocity.EulerZ=0;
541 			}
542 		}
543 	}
544 
545 }
546 
SmokeGeneratorBehaviour(STRATEGYBLOCK * sptr)547 void SmokeGeneratorBehaviour(STRATEGYBLOCK *sptr) {
548 
549     // This fn. will have been called from "Execute Behaviour",
550     // as a consequence of "ObjectBehaviours" running each
551     // frame. It simply decrements the counter of the specified
552     // temporary object, and destroys it if that counter hits
553     // zero
554 
555 	DYNAMICSBLOCK *dynptr;
556 	COLLISIONREPORT *reportptr;
557     SMOKEGEN_BEHAV_BLOCK *sgbhv;
558     GLOBALASSERT(sptr);
559     sgbhv = (SMOKEGEN_BEHAV_BLOCK * ) sptr->SBdataptr;
560     GLOBALASSERT(sptr->SBdptr);
561 
562 	dynptr=sptr->DynPtr;
563 	reportptr=dynptr->CollisionReportPtr;
564 
565 	if (sgbhv->counter < 0) sgbhv->counter=ONE_FIXED<<2;
566 
567 	if (sgbhv->counter > (ONE_FIXED<<1))
568 	{
569 		DestroyAnyStrategyBlock(sptr);
570 		return;
571 	}
572 
573 	sgbhv->counter += NormalFrameTime;
574 
575 	if ((sgbhv->counter>>15)>sgbhv->smokes)
576 	{
577 		{
578 			VECTORCH velocity={0,0,0};
579 			MakeParticle(&(dynptr->Position),&(velocity),PARTICLE_BLACKSMOKE);
580 		}
581 		sgbhv->smokes++;
582 	}
583 
584 	#if 0
585 	{
586 		DYNAMICSBLOCK *dynPtr = sptr->DynPtr;
587 		if (dynPtr) DynamicallyRotateObject(dynPtr);
588 	}
589 	#endif
590 
591 	while (reportptr) {
592 		if (reportptr->ObstacleSBPtr)	{
593 			if (reportptr->ObstacleSBPtr->SBdptr==Player) {
594 				CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], NormalFrameTime,NULL);
595 			}
596 		}
597 		reportptr=reportptr->NextCollisionReportPtr;
598 	}
599 
600 }
601 
generate_random_between(int first,int second)602 int generate_random_between (int first, int second)
603 {
604 	int diff = second - first;
605 	int absdiff;
606 	int rand_no;
607 
608 	if (diff == 0)
609 	{
610 		return(first);
611 	}
612 
613 	absdiff = abs (diff);
614 	rand_no = FastRandom () % absdiff;
615 
616 	if (diff < 0)
617 	{
618 		return (second + rand_no);
619 	}
620 	else
621 	{
622 		return (first + rand_no);
623 	}
624 
625 }
626 
MakeFragments(STRATEGYBLOCK * sbptr)627 void MakeFragments (STRATEGYBLOCK * sbptr)
628 {
629 	extern int NumActiveBlocks;
630 	DISPLAYBLOCK *dispPtr;
631 	STRATEGYBLOCK *sbPtr;
632 	MODULEMAPBLOCK *mmbptr;
633 	MODULE m_temp;
634 	int i=0;
635 	VECTORCH * posPtr;
636 	VECTORCH diff;
637 	int massfact;
638 
639 	int mslpos;
640 	SHAPEFRAGMENT * frags;
641 	SHAPEFRAGMENTDESC * fragdesc;
642 
643 	if( (NumActiveBlocks > maxobjects-5)
644 			|| (NumActiveStBlocks > maxstblocks-5))
645 		return;
646 
647 	if (!sbptr)
648 		return;
649 
650 	if (!sbptr->DynPtr)
651 		return;
652 
653 	if (!sbptr->SBdptr)
654 		return;
655 
656 	memset(&m_temp,0,sizeof(MODULE));
657 
658 	posPtr = &(sbptr->DynPtr->Position);
659 
660   	mmbptr = &TempModuleMap;
661 
662 	mslpos = sbptr->shapeIndex;
663 
664 	if (mslpos < 0)
665 		return;
666 
667 	fragdesc = mainshapelist[mslpos]->sh_fragdesc;
668 
669 	if(!fragdesc || !fragdesc->sh_fragsound)
670 	{
671   		Sound_Play(SID_EXPLOSION,"d",posPtr);
672 	}
673 	else
674 	{
675 		SHAPEFRAGMENTSOUND * fragsound=fragdesc->sh_fragsound;
676 		if(fragsound->sound_loaded)
677 		{
678 			SOUND3DDATA s3d;
679 			s3d.position = *posPtr;
680 			s3d.inner_range = fragsound->inner_range;
681 			s3d.outer_range = fragsound->outer_range;
682 			s3d.velocity.vx = 0;
683 			s3d.velocity.vy = 0;
684 			s3d.velocity.vz = 0;
685 			Sound_Play ((SOUNDINDEX)fragsound->sound_loaded->sound_num, "nvp", &s3d,fragsound->max_volume,fragsound->pitch);
686   			//Sound_Play((SOUNDINDEX)fragsound->sound_loaded->sound_num,"d",posPtr);
687 		}
688 	}
689 
690 	if (!fragdesc)
691 	{
692 		return;
693 	}
694 	frags=fragdesc->sh_frags;
695 	massfact = ((ONE_FIXED / sbptr->DynPtr->Mass)>>2) + ((ONE_FIXED>>2)*3);
696 
697 
698 	while (frags->ShapeIndex > 0)
699 	{
700 		mmbptr->MapShape = frags->ShapeIndex;
701 		mmbptr->MapType = MapType_Default;
702 
703 		for (i=0; i<frags->NumFrags; i++)
704 		{
705 			DYNAMICSBLOCK *dynPtr;
706 			VECTORCH offset;
707 
708 			m_temp.m_numlights = 0;
709 			m_temp.m_lightarray = NULL;
710 			m_temp.m_mapptr = mmbptr;
711 			m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
712 			m_temp.m_dptr = NULL;
713 			AllocateModuleObject(&m_temp);
714 			if(m_temp.m_dptr==NULL) return; /* patrick: cannot create displayblock, so just return (?) */
715 
716 			dispPtr = m_temp.m_dptr;
717 
718 			dispPtr->ObMyModule = NULL;     /* Module that created us */
719 
720 			offset.vx = frags->x_offset;
721 			offset.vy = frags->y_offset;
722 			offset.vz = frags->z_offset;
723 
724 			if (offset.vx == 0 && offset.vy == 0 && offset.vz == 0)
725 			{
726 				// place the fragment randomly within the bounding box of the parent
727 				offset.vx = generate_random_between (mainshapelist[mslpos]->shapemaxx,
728 						mainshapelist[mslpos]->shapeminx);
729 
730 				offset.vy = generate_random_between (mainshapelist[mslpos]->shapemaxy,
731 						mainshapelist[mslpos]->shapeminy);
732 
733 				offset.vz = generate_random_between (mainshapelist[mslpos]->shapemaxz,
734 						mainshapelist[mslpos]->shapeminz);
735 			}
736 
737 			sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
738 	    if (sbPtr == 0) return; // Failed to allocate a strategy block
739 
740 	    sbPtr->I_SBtype = I_BehaviourFragment;
741 
742 			sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK ));
743 
744 			if (sbPtr->SBdataptr == 0)
745 			{
746 				// Failed to allocate a strategy block data pointer
747 				RemoveBehaviourStrategy(sbPtr);
748 				return;
749 			}
750 
751 			((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ((FastRandom()&32768)<<2) + 65535;
752 
753 			dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS);
754 
755 			if (dynPtr == 0)
756 			{
757 				// Failed to allocate a dynamics block
758 				RemoveBehaviourStrategy(sbPtr);
759 				return;
760 			}
761 
762 			RotateVector (&offset, &(sbptr->DynPtr->OrientMat));
763 
764 
765 			if (sbptr->containingModule)
766 			{
767 
768 				if (frags->x_offset || frags->y_offset || frags->z_offset)
769 				{
770 					diff.vx = offset.vx;
771 					diff.vy = offset.vy;
772 					diff.vz = offset.vz;
773 				}
774 				else
775 				{
776 					diff.vx = sbptr->containingModule->m_mapptr->MapWorld.vx - posPtr->vx;
777 					diff.vy = sbptr->containingModule->m_mapptr->MapWorld.vy - posPtr->vy;
778 					diff.vz = sbptr->containingModule->m_mapptr->MapWorld.vz - posPtr->vz;
779 				}
780 
781 
782 				Normalise (&diff);
783 			}
784 			else
785 			{
786 				diff.vx = 0;
787 				diff.vy = ONE_FIXED;
788 				diff.vz = 0;
789 			}
790 
791 
792 			{
793 				/*give fragment an impulse roughly in the direction of its offset*/
794 				VECTORCH impulse=offset;
795 
796 				if(impulse.vx || impulse.vy || impulse.vz)
797 				{
798 					Normalise(&impulse);
799 
800 			 		impulse.vx/=generate_random_between(5,10);
801 			  //	impulse.vy/=generate_random_between(5,10);
802 			 		impulse.vz/=generate_random_between(5,10);
803 				}
804 			   	dynPtr->LinImpulse=impulse;
805 			}
806 
807 			diff.vx = (diff.vx>>4);
808 			diff.vy = (diff.vy>>4);
809 			diff.vz = (diff.vz>>4);
810 
811 
812 			offset.vx += posPtr->vx;
813 			offset.vy += posPtr->vy;
814 			offset.vz += posPtr->vz;
815 
816 			dispPtr->ObWorld = offset;
817 			dispPtr->ObMat = sbptr->DynPtr->OrientMat;
818 			dispPtr->ObEuler = sbptr->DynPtr->OrientEuler;
819 
820 			dynPtr->Position = offset;
821 
822 			dynPtr->OrientMat = sbptr->DynPtr->OrientMat;
823 			dynPtr->PrevOrientMat = sbptr->DynPtr->PrevOrientMat;
824 
825 			dynPtr->OrientEuler = sbptr->DynPtr->OrientEuler;
826 			dynPtr->PrevOrientEuler = sbptr->DynPtr->PrevOrientEuler;
827 
828 
829 
830 			{
831 				dynPtr->AngVelocity.EulerX = (((FastRandom()&2047)-1023))<<2;
832 				dynPtr->AngVelocity.EulerY = (((FastRandom()&2047)-1023))<<2;
833 				dynPtr->AngVelocity.EulerZ = (((FastRandom()&2047)-1023))<<2;
834 
835 				dynPtr->LinImpulse.vy = - (FastRandom()&1023)<<2;
836 
837 				/* Look to see if object has only one polygon in it;
838 				   if so it's probably a glass fragment, so don't bother
839 				   giving it collisions */
840 				if (dispPtr->ObShape)
841 				{
842 					SHAPEHEADER *shapePtr = GetShapeData(dispPtr->ObShape);
843 
844 					if (shapePtr)
845 					{
846 						if (shapePtr->numitems!=1)
847 						{
848 							dynPtr->DynamicsType = DYN_TYPE_NRBB_COLLISIONS;
849 						}
850 					}
851 				}
852 			}
853 
854 		}
855 
856 		frags++;
857 	}
858 }
859 
MakeHierarchicalDebris(STRATEGYBLOCK * parent_sbPtr,SECTION_DATA * root,VECTORCH * positionPtr,MATRIXCH * orientation,int * wounds,int speed)860 DISPLAYBLOCK *MakeHierarchicalDebris(STRATEGYBLOCK *parent_sbPtr,SECTION_DATA *root, VECTORCH *positionPtr, MATRIXCH *orientation, int *wounds, int speed)
861 {
862 
863 	DISPLAYBLOCK *dispPtr;
864 	STRATEGYBLOCK *sbPtr;
865 	DYNAMICSBLOCK *dynPtr;
866 	MODULEMAPBLOCK *mmbptr;
867 	MODULE m_temp;
868 	AVP_BEHAVIOUR_TYPE bhvr;
869 	int woundflags;
870 
871 	/* KJL 16:53:22 28/02/98 - this seems to happen a lot in multiplayer */
872 	if(positionPtr->vx>1000000 || positionPtr->vx<-1000000)
873 		return NULL;
874 	if(positionPtr->vy>1000000 || positionPtr->vy<-1000000)
875 		return NULL;
876 	if(positionPtr->vz>1000000 || positionPtr->vz<-1000000)
877 		return NULL;
878 
879 	if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) return NULL;
880 
881 	/* Right away, try to intercept all molotov cocktails! */
882 	GLOBALASSERT(root);
883 	if ((root->flags&section_data_notreal)==0) {
884 		if (strcmp(root->sempai->Section_Name,"bottle")==0) {
885 			/* Got one. */
886 			dispPtr=SpawnMolotovCocktail(root,orientation);
887 			/* Correct speed. */
888 			if (dispPtr) {
889 				dynPtr=dispPtr->ObStrategyBlock->DynPtr;
890 
891 				/* This code CnP'd from further down! */
892 				dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024;
893 				dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024;
894 				dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024;
895 
896 		   		{
897 					int random = (FastRandom()&1023) - 512;
898 					if (random>0) dynPtr->LinImpulse.vx=(random+100)<<speed;
899 					else dynPtr->LinImpulse.vx=(random-100)<<speed;
900 		   		}
901 		    	{
902 					int random = (FastRandom()&1023) - 768;
903 					if (random>0) dynPtr->LinImpulse.vy=(random+100)<<speed;
904 					else dynPtr->LinImpulse.vy=(random-100)<<speed;
905 				}
906 		    	{
907 					int random = (FastRandom()&1023) - 512;
908 					if (random>0) dynPtr->LinImpulse.vz=(random+100)<<speed;
909 					else dynPtr->LinImpulse.vz=(random-100)<<speed;
910 				}
911 			}
912 			return(dispPtr);
913 		}
914 	}
915 
916 	// 1. Set up shape data BEFORE making the displayblock,
917 	// since "AllocateModuleObject()" will fill in shapeheader
918 	// information and extent data
919 
920 	mmbptr = &TempModuleMap;
921 
922 	/* Doesn't really matter what shape gets generated... */
923 	//CreateShapeInstance(mmbptr,root->sempai->ShapeName);
924 	CreateShapeInstance(mmbptr,"Shell");
925 
926 	bhvr = I_BehaviourHierarchicalFragment;
927 
928 	// And allocate the modulemapblock object
929 
930 	m_temp.m_numlights = 0;
931 	m_temp.m_lightarray = NULL;
932 	m_temp.m_mapptr = mmbptr;
933 	m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
934 	m_temp.m_dptr = NULL;
935 	AllocateModuleObject(&m_temp);
936 	dispPtr = m_temp.m_dptr;
937 	if(dispPtr==NULL) return (DISPLAYBLOCK *)0; /* patrick: cannot create displayblock, so just return 0 */
938 
939 	dispPtr->ObMyModule = NULL;     /* Module that created us */
940 	dispPtr->ObWorld = *positionPtr;
941 
942 	sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
943 
944 	if (sbPtr == 0) return (DISPLAYBLOCK *)0; // Failed to allocate a strategy block
945 
946 	// 2. NOW set up the strategyblock-specific fields for
947 	// the new displayblock. We won't go through the "AttachNew
948 	// StrategyBlock" and "AssignRunTimeBehaviours" pair, since
949 	// the first switches on ObShape and the second on bhvr;
950 	// but, in this case, there isn't a particular connection
951 	// between them.
952 
953 	sbPtr->I_SBtype = bhvr;
954 
955 	GLOBALASSERT(root);
956 
957 	{
958 
959 		sbPtr->SBdataptr = (HDEBRIS_BEHAV_BLOCK *) AllocateMem(sizeof(HDEBRIS_BEHAV_BLOCK));
960 		if (sbPtr->SBdataptr == 0) {
961 			// Failed to allocate a strategy block data pointer
962 			RemoveBehaviourStrategy(sbPtr);
963 			return (DISPLAYBLOCK*)NULL;
964 		}
965 
966 		((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = HDEBRIS_LIFETIME;
967 		((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->smokes=0;
968 
969 		if (root->sempai->flags&section_flag_gibbwhenfragged) {
970 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->GibbFactor=(ONE_FIXED>>1);
971 		} else {
972 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->GibbFactor=0;
973 		}
974 
975 		/* Inheritance of android flag. */
976 		if (GetBloodType(parent_sbPtr)==PARTICLE_ANDROID_BLOOD) {
977 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Android=1;
978 		} else {
979 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Android=0;
980 		}
981 
982 		woundflags=Splice_HModels(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),root);
983 
984 
985 		if (parent_sbPtr)
986 		{
987 			/* Inherit fire! */
988 			if (parent_sbPtr->SBDamageBlock.IsOnFire) {
989 				sbPtr->SBDamageBlock.IsOnFire=1;
990 			}
991 			/* KJL 11:28:27 14/10/98 - this is set so we can later know what the debris was part of */
992 			/* CDF 3/3/99 put it in the switch statement, to deal with complex cases */
993 			/* Creature specific code! */
994 			switch (parent_sbPtr->I_SBtype) {
995 				case I_BehaviourAlien:
996 					{
997 						ALIEN_STATUS_BLOCK *alienStatusPointer;
998 						/* See if we can strip to template. */
999 						alienStatusPointer = (ALIEN_STATUS_BLOCK *)(parent_sbPtr->SBdataptr);
1000 						LOCALASSERT(alienStatusPointer);
1001 						/* Just go to spasm. */
1002 						InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1);
1003 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1004 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1005 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourAlien;
1006 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = alienStatusPointer->Type;
1007 						root->SecMat=*orientation;
1008 
1009 						DoAlienLimbLossSound(positionPtr);
1010 						/* Last as long as a dead alien. */
1011 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = ALIEN_DYINGTIME;
1012 						break;
1013 					}
1014 				case I_BehaviourMarine:
1015 					{
1016 						SECTION *template_root;
1017 						SECTION *template_sempai;
1018 						MARINE_STATUS_BLOCK *marineStatusPointer;
1019 						/* See if we can strip to template. */
1020 						marineStatusPointer = (MARINE_STATUS_BLOCK *)(parent_sbPtr->SBdataptr);
1021 						LOCALASSERT(marineStatusPointer);
1022 						template_root=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName);
1023 						/* Now, find the section that matches. */
1024 						template_sempai=Get_Corresponding_Section_Recursive(template_root,(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).Root_Section->Section_Name);
1025 
1026 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourMarine;
1027 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = marineStatusPointer->My_Weapon->ARealMarine;
1028 
1029 						if (template_sempai) {
1030 							/* We have a match! */
1031 							Transmogrify_HModels(sbPtr,&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),
1032 								template_sempai, 1, 0,0);
1033 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Spasm,-1,1);
1034 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1035 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1036 							//((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1;
1037 							root->SecMat=*orientation;
1038 							MakeFleshRippingNoises(positionPtr);
1039 						} else {
1040 							/* Forget it.  Must be a disembodied weapon, or something. */
1041 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1042 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1043 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1044 							//((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1;
1045 
1046 							//dispPtr->ObMat=*orientation;
1047 							/* Below is an alternative... */
1048 							root->SecMat=*orientation;
1049 						}
1050 						/* Since we're dealing with a marine, consider expressions. */
1051 						{
1052 							TXACTRLBLK *tacb;
1053 							SECTION_DATA *head;
1054 
1055 							head=GetThisSectionData(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.section_data,"head");
1056 							if (head) {
1057 								if ((head->flags&section_data_notreal)==0) {
1058 
1059 									tacb=head->tac_ptr;
1060 
1061 									while (tacb) {
1062 										tacb->tac_sequence = 4;
1063 										tacb->tac_txah_s = GetTxAnimHeaderFromShape(tacb, head->ShapeNum);
1064 
1065 										tacb=tacb->tac_next;
1066 									}
1067 								}
1068 							}
1069 						}
1070 						/* Last as long as a dead marine. */
1071 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = MARINE_DYINGTIME;
1072 					}
1073 					break;
1074 				case I_BehaviourPredator:
1075 					{
1076 						SECTION *template_root;
1077 						SECTION *template_sempai;
1078 						PREDATOR_STATUS_BLOCK *predatorStatusPointer;
1079 						/* See if we can strip to template. */
1080 						predatorStatusPointer = (PREDATOR_STATUS_BLOCK *)(parent_sbPtr->SBdataptr);
1081 						LOCALASSERT(predatorStatusPointer);
1082 						template_root=GetNamedHierarchyFromLibrary("hnpcpredator","Template");
1083 						/* Now, find the section that matches. */
1084 						template_sempai=Get_Corresponding_Section_Recursive(template_root,(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).Root_Section->Section_Name);
1085 
1086 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourPredator;
1087 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0;
1088 
1089 						if (template_sempai) {
1090 							/* We have a match! */
1091 							Transmogrify_HModels(sbPtr,&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),
1092 								template_sempai, 1, 0,0);
1093 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_PredatorStand,PSSS_Spasm,-1,1);
1094 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1095 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1096 							root->SecMat=*orientation;
1097 						} else {
1098 							/* Forget it.  Must be a disembodied weapon, or something. */
1099 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1100 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1101 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1102 							root->SecMat=*orientation;
1103 						}
1104 						/* Just freeze for now! */
1105 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.Playing=0;
1106 						/* Last as long as a dead predator. */
1107 						((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = PRED_DIETIME;
1108 					}
1109 					break;
1110 
1111 				case I_BehaviourNetCorpse:
1112 				{
1113 					NETCORPSEDATABLOCK *corpseDataPtr = (NETCORPSEDATABLOCK *)parent_sbPtr->SBdataptr;
1114 					switch (corpseDataPtr->Type) {
1115 						case I_BehaviourAlien:
1116 						{
1117 							DoAlienLimbLossSound(positionPtr);
1118 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1);
1119 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->subtype;
1120 							break;
1121 						}
1122 						case I_BehaviourMarine:
1123 						{
1124 							SECTION *template_root;
1125 							SECTION *template_sempai;
1126 							template_root=corpseDataPtr->TemplateRoot;
1127 							/* Now, find the section that matches. */
1128 							template_sempai=Get_Corresponding_Section_Recursive(template_root,(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController).Root_Section->Section_Name);
1129 
1130 							if (template_sempai) {
1131 								MakeFleshRippingNoises(positionPtr);
1132 							}
1133 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Spasm,-1,1);
1134 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->ARealMarine;
1135 							break;
1136 						}
1137 						case I_BehaviourPredator:
1138 						{
1139 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_PredatorStand,PSSS_Spasm,-1,1);
1140 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->subtype;
1141 							break;
1142 						}
1143 						default:
1144 						{
1145 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1146 							((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = corpseDataPtr->subtype;
1147 							break;
1148 						}
1149 					}
1150 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1151 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1152 					root->SecMat=*orientation;
1153 
1154 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = corpseDataPtr->Type;
1155 					/* Inherit counter from parent corpse. */
1156 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = corpseDataPtr->timer;
1157 					break;
1158 				}
1159 				case I_BehaviourHierarchicalFragment:
1160 				{
1161 					HDEBRIS_BEHAV_BLOCK *debrisDataPtr  = (HDEBRIS_BEHAV_BLOCK *)parent_sbPtr->SBdataptr;
1162 					switch (debrisDataPtr->Type) {
1163 						case I_BehaviourAlien:
1164 						{
1165 							DoAlienLimbLossSound(positionPtr);
1166 							/* Sound should be the same for all types of alien! */
1167 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1);
1168 							break;
1169 						}
1170 						case I_BehaviourMarine:
1171 						{
1172 							MakeFleshRippingNoises(positionPtr);
1173 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_MarineStand,MSSS_Spasm,-1,1);
1174 							break;
1175 						}
1176 						case I_BehaviourPredator:
1177 						{
1178 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_PredatorStand,PSSS_Spasm,-1,1);
1179 							break;
1180 						}
1181 						default:
1182 						{
1183 							InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1184 							break;
1185 						}
1186 					}
1187 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1188 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1189 					root->SecMat=*orientation;
1190 
1191 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = debrisDataPtr->Type;
1192 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = debrisDataPtr->SubType;
1193 					/* Inherit counter from parent debris. */
1194 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = debrisDataPtr->counter;
1195 					break;
1196 				}
1197 
1198 				case I_BehaviourNetGhost:
1199 					{
1200 						NETGHOSTDATABLOCK *dataptr;
1201 						dataptr=parent_sbPtr->SBdataptr;
1202 						switch (dataptr->type) {
1203 							case I_BehaviourAlien:
1204 							{
1205 								DoAlienLimbLossSound(positionPtr);
1206 								InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1);
1207 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1208 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1209 								root->SecMat=*orientation;
1210 
1211 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourAlien;
1212 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = dataptr->subtype;
1213 								break;
1214 							}
1215 							case I_BehaviourNetCorpse:
1216 							{
1217 								switch (dataptr->subtype) {
1218 									case I_BehaviourAlien:
1219 									{
1220 										DoAlienLimbLossSound(positionPtr);
1221 										InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED>>2),HMSQT_AlienStand,ASSS_Spasm,-1,1);
1222 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1223 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1224 										root->SecMat=*orientation;
1225 
1226 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourAlien;
1227 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = dataptr->IOType;
1228 										break;
1229 									}
1230 									default:
1231 									{
1232 										InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1233 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1234 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1235 										root->SecMat=*orientation;
1236 
1237 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = parent_sbPtr->I_SBtype;
1238 										((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0;
1239 										break;
1240 									}
1241 								}
1242 								break;
1243 							}
1244 							default:
1245 								InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1246 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1247 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1248 								root->SecMat=*orientation;
1249 
1250 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = parent_sbPtr->I_SBtype;
1251 								((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0;
1252 								break;
1253 						}
1254 					}
1255 					break;
1256 
1257 				default:
1258 					InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1259 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1260 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1261 					root->SecMat=*orientation;
1262 
1263 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = parent_sbPtr->I_SBtype;
1264 					((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0;
1265 					break;
1266 			}
1267 		}
1268 		else
1269 		{
1270 			/* KJL 11:27:54 14/10/98 - set behaviour type to null to avoid confusion */
1271 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Type = I_BehaviourNull;
1272 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->SubType = 0;
1273 			InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController),(ONE_FIXED<<1),0,1,ONE_FIXED,0);
1274 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.LockTopSection=1;
1275 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootDisplacement=1;
1276 			//((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1;
1277 			root->SecMat=*orientation;
1278 		}
1279 
1280 		if (wounds) {
1281 			*wounds=woundflags;
1282 		}
1283 
1284 		dispPtr->HModelControlBlock=&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController);
1285 
1286 		dispPtr->ObWorld=*positionPtr;
1287 		//dispPtr->ObMat=*orientation;
1288 		dispPtr->ObMat=Identity_RotMat;
1289 
1290 		LOCALASSERT(dispPtr->ObWorld.vx<1000000 && dispPtr->ObWorld.vx>-1000000);
1291 		LOCALASSERT(dispPtr->ObWorld.vy<1000000 && dispPtr->ObWorld.vy>-1000000);
1292 		LOCALASSERT(dispPtr->ObWorld.vz<1000000 && dispPtr->ObWorld.vz>-1000000);
1293 
1294 		dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS);
1295 
1296 		if (dynPtr == 0) {
1297 			// Failed to allocate a dynamics block
1298 			RemoveBehaviourStrategy(sbPtr);
1299 			return (DISPLAYBLOCK*)NULL;
1300 		}
1301 
1302 		dynPtr->Position = *positionPtr;
1303 
1304 		dynPtr->OrientMat=*orientation;
1305 
1306 		dynPtr->UseDisplacement=0;
1307 
1308 		dynPtr->LinVelocity.vx=0;
1309 		dynPtr->LinVelocity.vy=0;
1310 		dynPtr->LinVelocity.vz=0;
1311 
1312 		dynPtr->Mass=50;
1313 
1314    		#if 1
1315 		// Give explosion fragments an angular velocity
1316 		dynPtr->AngVelocity.EulerX = (FastRandom()&2047)-1024;
1317 		dynPtr->AngVelocity.EulerY = (FastRandom()&2047)-1024;
1318 		dynPtr->AngVelocity.EulerZ = (FastRandom()&2047)-1024;
1319 
1320    		{
1321 			int random = (FastRandom()&1023) - 512;
1322 			if (random>0) dynPtr->LinImpulse.vx=(random+100)<<speed;
1323 			else dynPtr->LinImpulse.vx=(random-100)<<speed;
1324    		}
1325     	{
1326 			int random = (FastRandom()&1023) - 768;
1327 			if (random>0) dynPtr->LinImpulse.vy=(random+100)<<speed;
1328 			else dynPtr->LinImpulse.vy=(random-100)<<speed;
1329 		}
1330     	{
1331 			int random = (FastRandom()&1023) - 512;
1332 			if (random>0) dynPtr->LinImpulse.vz=(random+100)<<speed;
1333 			else dynPtr->LinImpulse.vz=(random-100)<<speed;
1334 		}
1335 		#else
1336 		dynPtr->AngVelocity.EulerX = 0;
1337 		dynPtr->AngVelocity.EulerY = 0;
1338 		dynPtr->AngVelocity.EulerZ = 0;
1339 
1340 		dynPtr->LinImpulse.vx=0;
1341 		dynPtr->LinImpulse.vy=0;
1342 		dynPtr->LinImpulse.vz=0;
1343 		#endif
1344 
1345 		/* Set up default here for neatness. */
1346 		((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_NOSOUND;
1347 		/* Consider the bounce sound, by section name. */
1348 		if (strcmp(root->sempai->Section_Name,"SADAR")==0) {
1349 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1350 			dynPtr->Elasticity=(ONE_FIXED>>3);
1351 		} else if (strcmp(root->sempai->Section_Name,"gren stock")==0) {
1352 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1353 			/* Grenade launchers aren't very bouncy. */
1354 		} else if (strcmp(root->sempai->Section_Name,"flamer")==0) {
1355 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1356 		} else if (strcmp(root->sempai->Section_Name,"spring one")==0) {
1357 			/* This is a smartgun! */
1358 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1359 			/* Whilst we're here... */
1360 			dispPtr->ObMat=*orientation;
1361 			root->SecMat=Identity_RotMat;
1362 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.ZeroRootRotation=1;
1363 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->HModelController.Playing=0;
1364 		} else if (strcmp(root->sempai->Section_Name,"mini gun")==0) {
1365 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1366 		} else if (strcmp(root->sempai->Section_Name,"flame thrower")==0) {
1367 			/* Civvie flamer... */
1368 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1369 		} else if (strcmp(root->sempai->Section_Name,"pulse mag")==0) {
1370 			((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_NOSOUND;
1371 			/* Don't have a 'tink' yet... */
1372 			dynPtr->Elasticity=(ONE_FIXED>>1);
1373 		}
1374 
1375 		if (parent_sbPtr) {
1376 			if (parent_sbPtr->I_SBtype==I_BehaviourAutoGun) {
1377 				/* Always make a thump. */
1378 				((HDEBRIS_BEHAV_BLOCK * ) sbPtr->SBdataptr)->Bounce_Sound=SID_ED_LARGEWEAPONDROP;
1379 			}
1380 		}
1381 
1382 		ProveHModel(dispPtr->HModelControlBlock,dispPtr);
1383 
1384 	}
1385 
1386 	LOCALASSERT(dispPtr->ObWorld.vx<1000000 && dispPtr->ObWorld.vx>-1000000);
1387 	LOCALASSERT(dispPtr->ObWorld.vy<1000000 && dispPtr->ObWorld.vy>-1000000);
1388 	LOCALASSERT(dispPtr->ObWorld.vz<1000000 && dispPtr->ObWorld.vz>-1000000);
1389 
1390     return dispPtr;
1391 
1392 }
1393 /* KJL 16:35:13 08/01/99 - make body ripping noises */
MakeFleshRippingNoises(VECTORCH * positionPtr)1394 void MakeFleshRippingNoises(VECTORCH *positionPtr)
1395 {
1396 	int s = FastRandom()%5;
1397 
1398 	Sound_Play(SID_BODY_BEING_HACKED_UP_0+s,"d",positionPtr);
1399 }
1400 
1401 
Pop_Section(STRATEGYBLOCK * sbPtr,SECTION_DATA * section_data,VECTORCH * blastcentre,int * wounds)1402 void Pop_Section(STRATEGYBLOCK *sbPtr,SECTION_DATA *section_data, VECTORCH *blastcentre, int *wounds) {
1403 
1404 	int temp_wounds=0;
1405 	enum PARTICLE_ID blood_type;
1406 	/* 'Explode' this section, then frag off all it's children! */
1407 
1408 	GLOBALASSERT(section_data);
1409 	GLOBALASSERT(blastcentre);
1410 
1411 	if ((section_data->sempai->flags&section_sprays_anything)==0) {
1412 		blood_type=PARTICLE_NULL;
1413 	} else {
1414 		if (section_data->sempai->flags&section_sprays_blood) {
1415 			blood_type=GetBloodType(sbPtr);
1416 		} else if (section_data->sempai->flags&section_sprays_acid) {
1417 			blood_type=PARTICLE_ALIEN_BLOOD;
1418 		} else if (section_data->sempai->flags&section_sprays_predoblood) {
1419 			blood_type=PARTICLE_PREDATOR_BLOOD;
1420 		} else if (section_data->sempai->flags&section_sprays_sparks) {
1421 			blood_type=PARTICLE_SPARK;
1422 		} else {
1423 			blood_type=PARTICLE_NULL;
1424 		}
1425 	}
1426 	/* Right, should have a blood type set.  Now, trim off the extra bits... */
1427 
1428 	if ((section_data->First_Child!=NULL)
1429 		&&( (section_data->flags&section_data_terminate_here)==0)) {
1430 
1431 		SECTION_DATA *child_ptr;
1432 
1433 		child_ptr=section_data->First_Child;
1434 
1435 		while (child_ptr!=NULL) {
1436 
1437 			LOCALASSERT(child_ptr->My_Parent==section_data);
1438 			/* Please work! */
1439 			MakeHierarchicalDebris(sbPtr,child_ptr,&child_ptr->World_Offset,&child_ptr->SecMat,&temp_wounds,2);
1440 
1441 			(*wounds)|=temp_wounds;
1442 
1443 			child_ptr=child_ptr->Next_Sibling;
1444 		}
1445 
1446 	}
1447 	/* Okay.  Now, call the explosion of blood. */
1448 
1449 	if ((section_data->sempai->Shape)&&(blood_type!=PARTICLE_NULL)) {
1450 		if (SUPERGORE_MODE) {
1451 			MakeBloodExplosion(&section_data->World_Offset,section_data->sempai->Shape->shaperadius,
1452 				blastcentre,500,blood_type);
1453 		} else {
1454 			MakeBloodExplosion(&section_data->World_Offset,section_data->sempai->Shape->shaperadius,
1455 				blastcentre,100,blood_type);
1456 		}
1457 	}
1458 
1459 	/* Now trim off THIS bit, permanently. */
1460 
1461 	(*wounds)|=section_data->sempai->flags&section_flags_wounding;
1462 
1463 	section_data->flags|=section_data_notreal;
1464 	section_data->flags|=section_data_terminate_here;
1465 	/* ~Fin~ */
1466 }
1467 
HierarchicalFragmentBehaviour(STRATEGYBLOCK * sptr)1468 void HierarchicalFragmentBehaviour(STRATEGYBLOCK *sptr)
1469 {
1470 	/* CDF 5/3/99 A new function for all Hierarchical Fragments. */
1471 	int a;
1472 	COLLISIONREPORT *reportptr;
1473     HDEBRIS_BEHAV_BLOCK *hdbhv;
1474  	DYNAMICSBLOCK *dynPtr;
1475 	int bounce=0;
1476 
1477     GLOBALASSERT(sptr);
1478     hdbhv = (HDEBRIS_BEHAV_BLOCK * ) sptr->SBdataptr;
1479     GLOBALASSERT(sptr->SBdptr);
1480 
1481 	dynPtr=sptr->DynPtr;
1482 
1483 	GLOBALASSERT(dynPtr);
1484 
1485 	reportptr=dynPtr->CollisionReportPtr;
1486 
1487 	if (hdbhv->counter < 0)
1488 	{
1489 		DestroyAnyStrategyBlock(sptr);
1490 		return;
1491 	}
1492 
1493 	{
1494 		DISPLAYBLOCK *dispPtr = sptr->SBdptr;
1495 		/* do we have a displayblock? */
1496 		if (dispPtr)
1497 		{
1498 			dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
1499 			dispPtr->ObFlags2 = hdbhv->counter/2;
1500 
1501 		}
1502 	}
1503 
1504 	{
1505 		/* CDF 8/3/99 Added this on request... */
1506 		if (hdbhv->counter<(HDEBRIS_LIFETIME-HDEBRIS_BLEEDING_TIME)) {
1507 			hdbhv->HModelController.DisableBleeding=1;
1508 		}
1509 	}
1510 
1511 	hdbhv->counter -= NormalFrameTime;
1512 
1513 	a=0;
1514 
1515 	if (reportptr==NULL) {
1516 		hdbhv->bouncelastframe=0;
1517 	}
1518 
1519 	while (reportptr) {
1520 
1521 		if (SBIsEnvironment(reportptr->ObstacleSBPtr)) {
1522 			/* Hit environment. */
1523 			bounce=1;
1524 		}
1525 		else if (reportptr->ObstacleSBPtr->SBdptr==Player)
1526 		{
1527 			/* Hurt the player on collision? */
1528 			if (hdbhv->HModelController.Root_Section->flags&section_sprays_acid) {
1529 				/* That's the test that used to be used... */
1530 				CauseDamageToObject(Player->ObStrategyBlock,&TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage[AvP.Difficulty], ONE_FIXED,NULL);
1531 			}
1532 		}
1533 		reportptr=reportptr->NextCollisionReportPtr;
1534 	}
1535 
1536 	if (bounce&&(hdbhv->bouncelastframe==0)) {
1537 		if (hdbhv->Bounce_Sound!=SID_NOSOUND) {
1538 			Sound_Play(hdbhv->Bounce_Sound,"dp",&(dynPtr->Position),((FastRandom()&511)-255));
1539 		}
1540 		hdbhv->bouncelastframe=1;
1541 	}
1542 
1543 	{
1544 		if (dynPtr->IsInContactWithFloor==0) {
1545 			DynamicallyRotateObject(dynPtr);
1546 		} else {
1547 			dynPtr->AngVelocity.EulerX=0;
1548 			dynPtr->AngVelocity.EulerY=0;
1549 			dynPtr->AngVelocity.EulerZ=0;
1550 		}
1551 	}
1552 
1553 }
1554 
1555 
1556 
1557 /*-------------------------------**
1558 ** Load/Save hierarchical debris **
1559 **-------------------------------*/
1560 
1561 typedef struct hier_debris_save_block
1562 {
1563 	SAVE_BLOCK_STRATEGY_HEADER header;
1564 
1565 //behaviour block stuff
1566 	int counter;
1567 	int smokes;
1568 	int GibbFactor;
1569 	int Android;
1570 
1571 	AVP_BEHAVIOUR_TYPE Type;
1572 	int SubType;
1573 
1574 	int bouncelastframe;
1575 	enum soundindex Bounce_Sound;
1576 
1577 //strategy block stuff
1578 	int integrity;
1579 	DAMAGEBLOCK SBDamageBlock;
1580 	DYNAMICSBLOCK dynamics;
1581 }HIER_DEBRIS_SAVE_BLOCK;
1582 
1583 //defines for load/save macros
1584 #define SAVELOAD_BLOCK block
1585 #define SAVELOAD_BEHAV hdebrisStatusPointer
1586 
LoadStrategy_HierarchicalDebris(SAVE_BLOCK_STRATEGY_HEADER * header)1587 void LoadStrategy_HierarchicalDebris(SAVE_BLOCK_STRATEGY_HEADER* header)
1588 {
1589 	STRATEGYBLOCK* sbPtr;
1590 	HIER_DEBRIS_SAVE_BLOCK* block = (HIER_DEBRIS_SAVE_BLOCK*) header;
1591 	HDEBRIS_BEHAV_BLOCK* hdebrisStatusPointer;
1592 
1593 	//check the size of the save block
1594 	if(header->size!=sizeof(*block)) return;
1595 
1596 	//We need to create the debris then.
1597 	{
1598 		MODULEMAPBLOCK *mmbptr;
1599 		MODULE m_temp;
1600 		DISPLAYBLOCK* dispPtr;
1601 
1602 		// 1. Set up shape data BEFORE making the displayblock,
1603 		// since "AllocateModuleObject()" will fill in shapeheader
1604 		// information and extent data
1605 
1606 		mmbptr = &TempModuleMap;
1607 
1608 		/* Doesn't really matter what shape gets generated... */
1609 		//CreateShapeInstance(mmbptr,root->sempai->ShapeName);
1610 		CreateShapeInstance(mmbptr,"Shell");
1611 
1612 
1613 		// And allocate the modulemapblock object
1614 
1615 		m_temp.m_numlights = 0;
1616 		m_temp.m_lightarray = NULL;
1617 		m_temp.m_mapptr = mmbptr;
1618 		m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
1619 		m_temp.m_dptr = NULL;
1620 		AllocateModuleObject(&m_temp);
1621 		dispPtr = m_temp.m_dptr;
1622 		if(dispPtr==NULL) return ; /* patrick: cannot create displayblock, so just return 0 */
1623 
1624 		dispPtr->ObMyModule = NULL;     /* Module that created us */
1625 
1626 		sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
1627   		if (sbPtr == 0) return;  // Failed to allocate a strategy block
1628 		sbPtr->I_SBtype = I_BehaviourHierarchicalFragment;
1629 
1630 		sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ALIEN_DEBRIS);
1631 
1632 		//allocate behaviour block memory
1633 		sbPtr->SBdataptr = (HDEBRIS_BEHAV_BLOCK *) AllocateMem(sizeof(HDEBRIS_BEHAV_BLOCK));
1634 		hdebrisStatusPointer = (HDEBRIS_BEHAV_BLOCK *) sbPtr->SBdataptr;
1635 
1636 		memset(hdebrisStatusPointer,0,sizeof(*hdebrisStatusPointer));
1637 		dispPtr->HModelControlBlock=&hdebrisStatusPointer->HModelController;
1638 
1639 	}
1640 
1641 
1642 	//start copying stuff
1643 
1644 	COPYELEMENT_LOAD(counter)
1645 	COPYELEMENT_LOAD(smokes)
1646 	COPYELEMENT_LOAD(GibbFactor)
1647 	COPYELEMENT_LOAD(Android)
1648 	COPYELEMENT_LOAD(Type)
1649 	COPYELEMENT_LOAD(SubType)
1650 	COPYELEMENT_LOAD(bouncelastframe)
1651 	COPYELEMENT_LOAD(Bounce_Sound)
1652 
1653 	//copy strategy block stuff
1654 	*sbPtr->DynPtr = block->dynamics;
1655 	sbPtr->integrity = block->integrity;
1656 	sbPtr->SBDamageBlock = block->SBDamageBlock;
1657 
1658 	//load hierarchy
1659 	{
1660 		SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
1661 		if(hier_header)
1662 		{
1663 			LoadHierarchy(hier_header,&hdebrisStatusPointer->HModelController);
1664 		}
1665 	}
1666 
1667 }
1668 
SaveStrategy_HierarchicalDebris(STRATEGYBLOCK * sbPtr)1669 void SaveStrategy_HierarchicalDebris(STRATEGYBLOCK* sbPtr)
1670 {
1671 	HDEBRIS_BEHAV_BLOCK* hdebrisStatusPointer;
1672 	HIER_DEBRIS_SAVE_BLOCK* block;
1673 
1674 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
1675 	hdebrisStatusPointer = (HDEBRIS_BEHAV_BLOCK*) sbPtr->SBdataptr;
1676 
1677 	//start copying stuff
1678 
1679 	COPYELEMENT_SAVE(counter)
1680 	COPYELEMENT_SAVE(smokes)
1681 	COPYELEMENT_SAVE(GibbFactor)
1682 	COPYELEMENT_SAVE(Android)
1683 	COPYELEMENT_SAVE(Type)
1684 	COPYELEMENT_SAVE(SubType)
1685 	COPYELEMENT_SAVE(bouncelastframe)
1686 	COPYELEMENT_SAVE(Bounce_Sound)
1687 
1688 	//save strategy block stuff
1689 	block->dynamics = *sbPtr->DynPtr;
1690 	block->dynamics.CollisionReportPtr=0;
1691 
1692 	block->integrity = sbPtr->integrity;
1693 	block->SBDamageBlock = sbPtr->SBDamageBlock;
1694 
1695 	//save the hierarchy
1696 	SaveHierarchy(&hdebrisStatusPointer->HModelController);
1697 
1698 }
1699 
1700 
1701 
1702 /*------------------**
1703 ** Load/Save Debris **
1704 **------------------*/
1705 
1706 typedef struct debris_save_block
1707 {
1708 	SAVE_BLOCK_STRATEGY_HEADER header;
1709 
1710     int counter;
1711 
1712 	BOOL dynamicModuleObject;
1713 
1714 	int shapeIndex;
1715 	int shapeNumPoints;
1716 	int shapeNumItems;
1717 	int shapeRadius;
1718 
1719 
1720 //strategy block stuff
1721 	int integrity;
1722 	DAMAGEBLOCK SBDamageBlock;
1723 	DYNAMICSBLOCK dynamics;
1724 
1725 }DEBRIS_SAVE_BLOCK;
1726 
1727 
MakeDebrisForLoad(int shapeIndex,int counter,BOOL dynamicModuleObject)1728 STRATEGYBLOCK*  MakeDebrisForLoad(int shapeIndex,int counter,BOOL dynamicModuleObject)
1729 {
1730 	DISPLAYBLOCK *dispPtr;
1731 	STRATEGYBLOCK *sbPtr;
1732 	MODULEMAPBLOCK *mmbptr;
1733 	MODULE m_temp;
1734 
1735 	DYNAMICSBLOCK *dynPtr;
1736 
1737 	if( (NumActiveBlocks > maxobjects-5)
1738 			|| (NumActiveStBlocks > maxstblocks-5))
1739 		return NULL;
1740 
1741 
1742 	memset(&m_temp,0,sizeof(MODULE));
1743 
1744 	mmbptr = &TempModuleMap;
1745 
1746 
1747 	mmbptr->MapShape = shapeIndex;
1748 	mmbptr->MapType = MapType_Default;
1749 
1750 
1751 	m_temp.m_numlights = 0;
1752 	m_temp.m_lightarray = NULL;
1753 	m_temp.m_mapptr = mmbptr;
1754 	m_temp.m_sbptr = (STRATEGYBLOCK*)NULL;
1755 	m_temp.m_dptr = NULL;
1756 	AllocateModuleObject(&m_temp);
1757 	if(m_temp.m_dptr==NULL) return NULL; /* patrick: cannot create displayblock, so just return (?) */
1758 
1759 	dispPtr = m_temp.m_dptr;
1760 
1761 	dispPtr->ObMyModule = NULL;     /* Module that created us */
1762 
1763 
1764 	sbPtr = AttachNewStratBlock((MODULE*)NULL, mmbptr, dispPtr);
1765 	if (sbPtr == 0) return NULL; // Failed to allocate a strategy block
1766 
1767 	sbPtr->I_SBtype = I_BehaviourFragment;
1768 
1769 	sbPtr->SBdataptr = (ONE_SHOT_BEHAV_BLOCK *) AllocateMem(sizeof(ONE_SHOT_BEHAV_BLOCK ));
1770 
1771 	if (sbPtr->SBdataptr == 0)
1772 	{
1773 		// Failed to allocate a strategy block data pointer
1774 		RemoveBehaviourStrategy(sbPtr);
1775 		return NULL;
1776 	}
1777 
1778 	((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->SBdataptr)->counter = counter;
1779 
1780 	dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEBRIS);
1781 
1782 	if (dynPtr == 0)
1783 	{
1784 		// Failed to allocate a dynamics block
1785 		RemoveBehaviourStrategy(sbPtr);
1786 		return NULL;
1787 	}
1788 
1789 	if(dynamicModuleObject)
1790 	{
1791 		dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject;
1792 	}
1793 	return sbPtr;
1794 }
1795 
1796 
LoadStrategy_Debris(SAVE_BLOCK_HEADER * header)1797 void LoadStrategy_Debris(SAVE_BLOCK_HEADER* header)
1798 {
1799 	STRATEGYBLOCK* sbPtr;
1800 	DEBRIS_SAVE_BLOCK* block = (DEBRIS_SAVE_BLOCK*)header;
1801 
1802 	//check the size
1803 	if(block->header.size != sizeof(*block)) return;
1804 
1805 	{
1806 		SHAPEHEADER* shp = GetShapeData(block->shapeIndex);
1807 
1808 		//check that the shape at shapeIndex is correct
1809 		if(!shp) return;
1810 
1811 		if(shp->numitems!=block->shapeNumItems) return;
1812 		if(shp->numpoints!=block->shapeNumPoints) return;
1813 		if(shp->shaperadius!=block->shapeRadius) return;
1814 
1815 		sbPtr = MakeDebrisForLoad(block->shapeIndex,block->counter,block->dynamicModuleObject);
1816 		if(!sbPtr) return;
1817 	}
1818 
1819 //strategy block stuff
1820 	*sbPtr->DynPtr = block->dynamics;
1821 	sbPtr->integrity = block->integrity;
1822 	sbPtr->SBDamageBlock = block->SBDamageBlock;
1823 
1824 
1825 }
1826 
SaveStrategy_Debris(STRATEGYBLOCK * sbPtr)1827 void SaveStrategy_Debris(STRATEGYBLOCK* sbPtr)
1828 {
1829 	SHAPEHEADER* shp;
1830 	DEBRIS_SAVE_BLOCK* block;
1831 	ONE_SHOT_BEHAV_BLOCK* behav = (ONE_SHOT_BEHAV_BLOCK*)sbPtr->SBdataptr;
1832 
1833 	if(!sbPtr->SBdptr) return;
1834 	if(!sbPtr->SBdptr->ObShapeData) return;
1835 	shp = sbPtr->SBdptr->ObShapeData;
1836 
1837 
1838 
1839 	GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
1840 
1841 	block->counter = behav->counter;
1842 	block->shapeIndex = sbPtr->SBdptr->ObShape;
1843 	block->dynamicModuleObject = (sbPtr->SBdptr->ObFlags3 & ObFlag3_DynamicModuleObject)!=0;
1844 
1845 	block->shapeNumPoints = shp->numpoints;
1846 	block->shapeNumItems  = shp->numitems;
1847 	block->shapeRadius = shp->shaperadius;
1848 
1849 
1850 //strategy block stuff
1851 	block->dynamics = *sbPtr->DynPtr;
1852 	block->dynamics.CollisionReportPtr=0;
1853 
1854 	block->integrity = sbPtr->integrity;
1855 	block->SBDamageBlock = sbPtr->SBDamageBlock;
1856 
1857 }
1858