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§ion_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§ion_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§ion_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§ion_sprays_anything)==0) {
1412 blood_type=PARTICLE_NULL;
1413 } else {
1414 if (section_data->sempai->flags§ion_sprays_blood) {
1415 blood_type=GetBloodType(sbPtr);
1416 } else if (section_data->sempai->flags§ion_sprays_acid) {
1417 blood_type=PARTICLE_ALIEN_BLOOD;
1418 } else if (section_data->sempai->flags§ion_sprays_predoblood) {
1419 blood_type=PARTICLE_PREDATOR_BLOOD;
1420 } else if (section_data->sempai->flags§ion_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§ion_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(§ion_data->World_Offset,section_data->sempai->Shape->shaperadius,
1452 blastcentre,500,blood_type);
1453 } else {
1454 MakeBloodExplosion(§ion_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§ion_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§ion_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