1 /* bh_corpse.c 19/8/98 */
2 #include "3dc.h"
3
4 #include "inline.h"
5 #include "module.h"
6
7 #include "stratdef.h"
8 #include "gamedef.h"
9 #include "bh_types.h"
10 #include "comp_shp.h"
11 #include "dynblock.h"
12 #include "dynamics.h"
13 #include "lighting.h"
14
15 #include "pfarlocs.h"
16 #include "pvisible.h"
17 #include "pheromon.h"
18 #include "bh_gener.h"
19 #include "bh_far.h"
20 #include "bh_pred.h"
21 #include "bh_marin.h"
22 #include "bh_weap.h"
23 #include "bh_debri.h"
24 #include "bh_alien.h"
25 #include "bh_xeno.h"
26 #include "psnd.h"
27 #include "weapons.h"
28 #include "load_shp.h"
29 #include "particle.h"
30 #include "sfx.h"
31 #include "huddefs.h"
32 #include "pldghost.h"
33 #include "pldnet.h"
34 #include "psndplat.h"
35 #include "ai_sight.h"
36 #include "los.h"
37 #include "bh_corpse.h"
38
39 #include "dxlog.h"
40
41 #define UseLocalAssert Yes
42 #include "ourasert.h"
43
44 #include "sequnces.h"
45 #include "showcmds.h"
46 #include "extents.h"
47
48 extern int NormalFrameTime;
49 extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name);
50 extern HITLOCATIONTABLE *GetThisHitLocationTable(char *id);
51 extern MARINE_WEAPON_DATA *GetThisNPCMarineWeapon(MARINE_NPC_WEAPONS this_id);
52
53 void SetCorpseAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime);
54
55 /* these functions are called directly by the visibility management system */
MakeCorpseNear(STRATEGYBLOCK * sbPtr)56 void MakeCorpseNear(STRATEGYBLOCK *sbPtr)
57 {
58 extern MODULEMAPBLOCK AlienDefaultMap;
59 NETCORPSEDATABLOCK *corpseData = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
60 MODULE tempModule;
61 DISPLAYBLOCK *dPtr;
62 DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr;
63
64 LOCALASSERT(corpseData);
65 LOCALASSERT(dynPtr);
66 LOCALASSERT(sbPtr->SBdptr == NULL);
67
68 AlienDefaultMap.MapShape = sbPtr->shapeIndex;
69 tempModule.m_mapptr = &AlienDefaultMap;
70 tempModule.m_sbptr = (STRATEGYBLOCK*)NULL;
71 tempModule.m_numlights = 0;
72 tempModule.m_lightarray = (struct lightblock *)0;
73 tempModule.m_extraitemdata = (struct extraitemdata *)0;
74 tempModule.m_dptr = NULL; /* this is important */
75 AllocateModuleObject(&tempModule);
76 dPtr = tempModule.m_dptr;
77 if(dPtr==NULL) return; /* cannot create displayblock, so leave object "far" */
78
79 sbPtr->SBdptr = dPtr;
80 dPtr->ObStrategyBlock = sbPtr;
81 dPtr->ObMyModule = NULL;
82 dPtr->HModelControlBlock=NULL;
83
84 /* need to initialise positional information in the new display block */
85 /*Must be done before ProveHModel*/
86 dPtr->ObWorld = dynPtr->Position;
87 dPtr->ObEuler = dynPtr->OrientEuler;
88 dPtr->ObMat = dynPtr->OrientMat;
89
90 /* set the animation sequence, if we're a player corpse */
91 {
92 /* Okay, no messing, you MUST be a player corpse. */
93 dPtr->HModelControlBlock=&corpseData->HModelController;
94 ProveHModel(dPtr->HModelControlBlock,dPtr);
95 }
96
97
98 }
99
MakeCorpseFar(STRATEGYBLOCK * sbPtr)100 void MakeCorpseFar(STRATEGYBLOCK *sbPtr)
101 {
102 int i;
103 LOCALASSERT(sbPtr->SBdptr != NULL);
104
105 /* get rid of the displayblock */
106 i = DestroyActiveObject(sbPtr->SBdptr);
107 LOCALASSERT(i==0);
108 sbPtr->SBdptr = NULL;
109 }
110
Convert_Alien_To_Corpse(STRATEGYBLOCK * sbPtr,DEATH_DATA * this_death,DAMAGE_PROFILE * damage)111 void Convert_Alien_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death,DAMAGE_PROFILE* damage) {
112
113 NETCORPSEDATABLOCK *corpseDataPtr;
114 ALIEN_STATUS_BLOCK *alienStatusPointer;
115
116 alienStatusPointer=(ALIEN_STATUS_BLOCK *)(sbPtr->SBdataptr);
117 /* Convert an alien... to a corpse. */
118
119 GLOBALASSERT(sbPtr);
120 GLOBALASSERT(this_death);
121 GLOBALASSERT(alienStatusPointer);
122
123 /* Inform the network. */
124 if (AvP.Network != I_No_Network)
125 {
126 AddNetMsg_AlienAIKilled(sbPtr,this_death->Multiplayer_Code,ALIEN_DYINGTIME,alienStatusPointer->GibbFactor,damage);
127 }
128
129 corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK));
130 GLOBALASSERT(corpseDataPtr);
131
132 /* Fill in corpseDataPtr... */
133 corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX;
134 corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX;
135 corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX;
136 corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX;
137
138 corpseDataPtr->Type=I_BehaviourAlien;
139 corpseDataPtr->GibbFactor=alienStatusPointer->GibbFactor;
140 corpseDataPtr->This_Death=this_death;
141
142 corpseDataPtr->CloakStatus = PCLOAK_Off;
143 corpseDataPtr->CloakTimer = 0;
144 corpseDataPtr->destructTimer = -1;
145 corpseDataPtr->WeaponMisfireFunction=NULL;
146 corpseDataPtr->My_Gunflash_Section=NULL;
147 corpseDataPtr->My_Weapon=NULL;
148 corpseDataPtr->weapon_variable=0;
149 corpseDataPtr->Android=0;
150 corpseDataPtr->ARealMarine=0;
151 corpseDataPtr->TemplateRoot=NULL;
152 corpseDataPtr->DeathFiring=0;
153 corpseDataPtr->Wounds=0;
154
155 switch (alienStatusPointer->Type) {
156 case AT_Standard:
157 default:
158 corpseDataPtr->subtype = 0;
159 corpseDataPtr->hltable=GetThisHitLocationTable("alien");
160 break;
161 case AT_Predalien:
162 corpseDataPtr->subtype = 1;
163 corpseDataPtr->hltable=GetThisHitLocationTable("predalien");
164 break;
165 case AT_Praetorian:
166 corpseDataPtr->subtype = 2;
167 corpseDataPtr->hltable=GetThisHitLocationTable("praetorian");
168 break;
169 }
170
171 /* Remember wounds, or not? */
172 Splice_HModels(&corpseDataPtr->HModelController,alienStatusPointer->HModelController.section_data);
173
174 /* Heh... now bin the old data block! */
175 if(alienStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
176 Sound_Stop(alienStatusPointer->soundHandle);
177 }
178 if(alienStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
179 Sound_Stop(alienStatusPointer->soundHandle2);
180 }
181 Dispel_HModel(&alienStatusPointer->HModelController);
182 DeallocateMem(sbPtr->SBdataptr);
183 /* Turn into the corpse. */
184 sbPtr->SBdataptr=corpseDataPtr;
185 sbPtr->I_SBtype=I_BehaviourNetCorpse;
186
187 SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence,
188 this_death->Sequence_Length,this_death->TweeningTime);
189
190 if (sbPtr->SBdptr) {
191 /* Swap controllers round. */
192 sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController;
193 ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr);
194 } else {
195 ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr);
196 }
197
198 corpseDataPtr->timer=ALIEN_DYINGTIME;
199 corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME;
200 corpseDataPtr->HModelController.Looped=0;
201 corpseDataPtr->HModelController.LoopAfterTweening=0;
202
203 /* stop motion */
204 LOCALASSERT(sbPtr->DynPtr);
205 sbPtr->DynPtr->Friction = 400000;
206 sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx;
207 sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy;
208 sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz;
209 sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
210 sbPtr->DynPtr->CanClimbStairs = 0;
211 /* Experiment... */
212 sbPtr->DynPtr->UseStandardGravity=1;
213 sbPtr->DynPtr->Mass = 160;
214 /* Okay... */
215
216 /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */
217 sbPtr->DynPtr->OnlyCollideWithEnvironment = 1;
218
219 /* Electric death sound? */
220 if (corpseDataPtr->This_Death->Electrical) {
221 Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4);
222 }
223 }
224
Convert_Predator_To_Corpse(STRATEGYBLOCK * sbPtr,DEATH_DATA * this_death)225 void Convert_Predator_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death) {
226
227 NETCORPSEDATABLOCK *corpseDataPtr;
228 PREDATOR_STATUS_BLOCK *predatorStatusPointer;
229
230 predatorStatusPointer=(PREDATOR_STATUS_BLOCK *)(sbPtr->SBdataptr);
231 /* Convert a predator... to a corpse. */
232
233 GLOBALASSERT(sbPtr);
234 GLOBALASSERT(this_death);
235 GLOBALASSERT(predatorStatusPointer);
236
237 corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK));
238 GLOBALASSERT(corpseDataPtr);
239
240 /* Fill in corpseDataPtr... */
241 corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX;
242 corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX;
243 corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX;
244 corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX;
245
246 corpseDataPtr->Type=I_BehaviourPredator;
247 corpseDataPtr->GibbFactor=predatorStatusPointer->GibbFactor;
248 corpseDataPtr->This_Death=this_death;
249
250 corpseDataPtr->CloakStatus = predatorStatusPointer->CloakStatus;
251 corpseDataPtr->CloakTimer = predatorStatusPointer->CloakTimer;
252
253 if ((predatorStatusPointer->behaviourState==PBS_SelfDestruct)
254 &&(predatorStatusPointer->internalState==1)) {
255 corpseDataPtr->destructTimer = predatorStatusPointer->stateTimer;
256 } else {
257 corpseDataPtr->destructTimer = -1;
258 }
259
260 corpseDataPtr->WeaponMisfireFunction=NULL;
261 corpseDataPtr->My_Gunflash_Section=NULL;
262 corpseDataPtr->weapon_variable=0;
263 corpseDataPtr->Android=0;
264 corpseDataPtr->ARealMarine=0;
265 corpseDataPtr->TemplateRoot=NULL;
266 corpseDataPtr->My_Weapon=NULL;
267 corpseDataPtr->DeathFiring=0;
268 corpseDataPtr->subtype = 0;
269 corpseDataPtr->Wounds=0;
270
271 corpseDataPtr->hltable=GetThisHitLocationTable(predatorStatusPointer->Selected_Weapon->HitLocationTableName);
272
273 /* Remember wounds, or not? */
274 Splice_HModels(&corpseDataPtr->HModelController,predatorStatusPointer->HModelController.section_data);
275
276 if (this_death->Template) {
277 SECTION *root;
278 /* Convert to template. */
279 root=GetNamedHierarchyFromLibrary("hnpcpredator","Template");
280 Transmogrify_HModels(sbPtr,&corpseDataPtr->HModelController,
281 root, 1, 0,0);
282 }
283
284 /* Heh... now bin the old data block! */
285 if(predatorStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
286 Sound_Stop(predatorStatusPointer->soundHandle);
287 }
288 Dispel_HModel(&predatorStatusPointer->HModelController);
289 DeallocateMem(sbPtr->SBdataptr);
290 /* Turn into the corpse. */
291 sbPtr->SBdataptr=corpseDataPtr;
292 sbPtr->I_SBtype=I_BehaviourNetCorpse;
293
294 SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence,
295 this_death->Sequence_Length,this_death->TweeningTime);
296
297 if (sbPtr->SBdptr) {
298 /* Swap controllers round. */
299 sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController;
300 ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr);
301 } else {
302 ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr);
303 }
304
305 corpseDataPtr->timer=PRED_DIETIME;
306 corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME;
307 corpseDataPtr->HModelController.Looped=0;
308 corpseDataPtr->HModelController.LoopAfterTweening=0;
309
310 /* stop motion */
311 LOCALASSERT(sbPtr->DynPtr);
312 sbPtr->DynPtr->Friction = 400000;
313 sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx;
314 sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy;
315 sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz;
316 sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
317 sbPtr->DynPtr->CanClimbStairs = 0;
318
319 /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */
320 sbPtr->DynPtr->OnlyCollideWithEnvironment = 1;
321
322 /* Electric death sound? */
323 if (corpseDataPtr->This_Death->Electrical) {
324 Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4);
325 }
326
327 }
328
Convert_Marine_To_Corpse(STRATEGYBLOCK * sbPtr,DEATH_DATA * this_death)329 void Convert_Marine_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death) {
330
331 NETCORPSEDATABLOCK *corpseDataPtr;
332 MARINE_STATUS_BLOCK *marineStatusPointer;
333
334 marineStatusPointer=(MARINE_STATUS_BLOCK *)(sbPtr->SBdataptr);
335 /* Convert a predator... to a corpse. */
336
337 GLOBALASSERT(sbPtr);
338 GLOBALASSERT(this_death);
339 GLOBALASSERT(marineStatusPointer);
340
341 corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK));
342 GLOBALASSERT(corpseDataPtr);
343
344 /* Fill in corpseDataPtr... */
345 corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX;
346 corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX;
347 corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX;
348 corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX;
349
350 corpseDataPtr->Type=I_BehaviourMarine;
351 corpseDataPtr->GibbFactor=marineStatusPointer->GibbFactor;
352 corpseDataPtr->This_Death=this_death;
353
354 corpseDataPtr->CloakStatus = PCLOAK_Off;
355 corpseDataPtr->CloakTimer = 0;
356 corpseDataPtr->destructTimer = -1;
357
358 corpseDataPtr->My_Weapon=marineStatusPointer->My_Weapon;
359 corpseDataPtr->WeaponMisfireFunction=marineStatusPointer->My_Weapon->WeaponMisfireFunction;
360 corpseDataPtr->My_Gunflash_Section=marineStatusPointer->My_Gunflash_Section;
361 corpseDataPtr->TemplateRoot=GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,marineStatusPointer->My_Weapon->TemplateName);
362 corpseDataPtr->Android=marineStatusPointer->Android;
363 corpseDataPtr->ARealMarine=marineStatusPointer->My_Weapon->ARealMarine;
364 corpseDataPtr->weapon_variable=0;
365 corpseDataPtr->Wounds=0;
366
367 corpseDataPtr->subtype = 0;
368 corpseDataPtr->hltable=GetThisHitLocationTable(marineStatusPointer->My_Weapon->HitLocationTableName);
369
370 if (corpseDataPtr->WeaponMisfireFunction) {
371 if (marineStatusPointer->behaviourState==MBS_Firing) {
372 corpseDataPtr->DeathFiring=1;
373 } else {
374 corpseDataPtr->DeathFiring=0;
375 }
376 } else {
377 corpseDataPtr->DeathFiring=0;
378 }
379
380 /* Remember wounds, or not? */
381 Splice_HModels(&corpseDataPtr->HModelController,marineStatusPointer->HModelController.section_data);
382
383 if (this_death->Template) {
384 /* Convert to template. */
385 Transmogrify_HModels(sbPtr,&corpseDataPtr->HModelController,
386 corpseDataPtr->TemplateRoot, 1, 0,0);
387 }
388 /* Pass over some sounds? */
389
390 /* Heh... now bin the old data block! */
391 if(marineStatusPointer->soundHandle!=SOUND_NOACTIVEINDEX) {
392 Sound_Stop(marineStatusPointer->soundHandle);
393 }
394 if(marineStatusPointer->soundHandle2!=SOUND_NOACTIVEINDEX) {
395 /* soundHandle2 is the voice! */
396 corpseDataPtr->SoundHandle2=marineStatusPointer->soundHandle2;
397 ActiveSounds[marineStatusPointer->soundHandle2].externalRef=&corpseDataPtr->SoundHandle2;
398 }
399 Dispel_HModel(&marineStatusPointer->HModelController);
400 DeallocateMem(sbPtr->SBdataptr);
401 /* Turn into the corpse. */
402 sbPtr->SBdataptr=corpseDataPtr;
403 sbPtr->I_SBtype=I_BehaviourNetCorpse;
404
405 SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence,
406 this_death->Sequence_Length,this_death->TweeningTime);
407
408 if (sbPtr->SBdptr) {
409 /* Swap controllers round. */
410 sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController;
411 ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr);
412 } else {
413 ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr);
414 }
415
416 corpseDataPtr->timer=MARINE_DYINGTIME;
417 corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME;
418 corpseDataPtr->HModelController.Looped=0;
419 corpseDataPtr->HModelController.LoopAfterTweening=0;
420
421 /* stop motion */
422 LOCALASSERT(sbPtr->DynPtr);
423 sbPtr->DynPtr->Friction = 400000;
424 sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx;
425 sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy;
426 sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz;
427 sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
428 sbPtr->DynPtr->CanClimbStairs = 0;
429
430 /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */
431 sbPtr->DynPtr->OnlyCollideWithEnvironment = 1;
432
433 /* Electric death sound? */
434 if (corpseDataPtr->This_Death->Electrical) {
435 Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4);
436 }
437
438 }
439
Convert_Xenoborg_To_Corpse(STRATEGYBLOCK * sbPtr,DEATH_DATA * this_death)440 void Convert_Xenoborg_To_Corpse(STRATEGYBLOCK *sbPtr,DEATH_DATA *this_death) {
441
442 NETCORPSEDATABLOCK *corpseDataPtr;
443 XENO_STATUS_BLOCK *xenoStatusPointer;
444
445 xenoStatusPointer=(XENO_STATUS_BLOCK *)(sbPtr->SBdataptr);
446 /* Convert an xenoborg... to a corpse. */
447
448 GLOBALASSERT(sbPtr);
449 GLOBALASSERT(this_death);
450 GLOBALASSERT(xenoStatusPointer);
451
452 corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK));
453 GLOBALASSERT(corpseDataPtr);
454
455 /* Fill in corpseDataPtr... */
456 corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX;
457 corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX;
458 corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX;
459 corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX;
460
461 corpseDataPtr->Type=I_BehaviourXenoborg;
462 corpseDataPtr->GibbFactor=xenoStatusPointer->GibbFactor;
463 corpseDataPtr->This_Death=this_death;
464
465 corpseDataPtr->CloakStatus = PCLOAK_Off;
466 corpseDataPtr->CloakTimer = 0;
467 corpseDataPtr->destructTimer = -1;
468 corpseDataPtr->WeaponMisfireFunction=NULL;
469 corpseDataPtr->My_Gunflash_Section=NULL;
470 corpseDataPtr->weapon_variable=0;
471 corpseDataPtr->Android=0;
472 corpseDataPtr->ARealMarine=0;
473 corpseDataPtr->TemplateRoot=NULL;
474 corpseDataPtr->My_Weapon=NULL;
475 corpseDataPtr->DeathFiring=0;
476 corpseDataPtr->subtype = 0;
477 corpseDataPtr->Wounds=0;
478
479 corpseDataPtr->hltable=GetThisHitLocationTable("xenoborg");
480
481 /* Remember wounds, or not? */
482 Splice_HModels(&corpseDataPtr->HModelController,xenoStatusPointer->HModelController.section_data);
483
484 /* Heh... now bin the old data block! */
485 Dispel_HModel(&xenoStatusPointer->HModelController);
486 DeallocateMem(sbPtr->SBdataptr);
487 /* Turn into the corpse. */
488 sbPtr->SBdataptr=corpseDataPtr;
489 sbPtr->I_SBtype=I_BehaviourNetCorpse;
490
491 SetCorpseAnimSequence_Core(sbPtr,this_death->Sequence_Type,this_death->Sub_Sequence,
492 this_death->Sequence_Length,this_death->TweeningTime);
493
494 if (sbPtr->SBdptr) {
495 /* Swap controllers round. */
496 sbPtr->SBdptr->HModelControlBlock=&corpseDataPtr->HModelController;
497 ProveHModel(&corpseDataPtr->HModelController,sbPtr->SBdptr);
498 } else {
499 ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr);
500 }
501
502 corpseDataPtr->timer=XENO_DYINGTIME;
503 corpseDataPtr->validityTimer=CORPSE_VALIDITY_TIME;
504 corpseDataPtr->HModelController.Looped=0;
505 corpseDataPtr->HModelController.LoopAfterTweening=0;
506
507 /* stop motion */
508 LOCALASSERT(sbPtr->DynPtr);
509 sbPtr->DynPtr->Friction = 400000;
510 sbPtr->DynPtr->LinImpulse.vx+=sbPtr->DynPtr->LinVelocity.vx;
511 sbPtr->DynPtr->LinImpulse.vy+=sbPtr->DynPtr->LinVelocity.vy;
512 sbPtr->DynPtr->LinImpulse.vz+=sbPtr->DynPtr->LinVelocity.vz;
513 sbPtr->DynPtr->LinVelocity.vx = sbPtr->DynPtr->LinVelocity.vy = sbPtr->DynPtr->LinVelocity.vz = 0;
514 sbPtr->DynPtr->CanClimbStairs = 0;
515 /* Experiment... */
516 sbPtr->DynPtr->UseStandardGravity=1;
517 sbPtr->DynPtr->Mass = 160;
518 /* Okay... */
519
520 /* KJL 17:19:35 27/08/98 - ignore the player, other body parts, etc */
521 sbPtr->DynPtr->OnlyCollideWithEnvironment = 1;
522
523 #if 0
524 /* Electric death sound? */
525 if (corpseDataPtr->This_Death->Electrical) {
526 Sound_Play(SID_ED_ELEC_DEATH,"de",&sbPtr->DynPtr->Position,&corpseDataPtr->SoundHandle4);
527 }
528 #endif
529
530 }
531
CorpseBehaveFun(STRATEGYBLOCK * sbPtr)532 void CorpseBehaveFun(STRATEGYBLOCK *sbPtr)
533 {
534
535 /* Just count down. */
536 NETCORPSEDATABLOCK *corpseDataPtr;
537
538 LOCALASSERT(sbPtr);
539
540 corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
541 LOCALASSERT(corpseDataPtr);
542
543
544 if (corpseDataPtr->timer<=0)
545 {
546 PLAYER_STATUS *playerStatusPtr = (PLAYER_STATUS *)(Player->ObStrategyBlock->SBdataptr);
547
548 if (playerStatusPtr->MyCorpse==sbPtr) {
549 /* Set players corpse to null. */
550 playerStatusPtr->MyCorpse=NULL;
551 }
552
553 if(corpseDataPtr->SoundHandle != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle);
554 if(corpseDataPtr->SoundHandle2 != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle2);
555 if(corpseDataPtr->SoundHandle3 != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle3);
556 if(corpseDataPtr->SoundHandle4 != SOUND_NOACTIVEINDEX) Sound_Stop(corpseDataPtr->SoundHandle4);
557
558 /* Remove corpse. */
559 DestroyAnyStrategyBlock(sbPtr);
560 AddNetMsg_LocalObjectDestroyed(sbPtr);
561 return;
562 }
563 else
564 {
565 DISPLAYBLOCK *dispPtr = sbPtr->SBdptr;
566
567 /* do we have a displayblock? */
568 if (dispPtr)
569 {
570 dispPtr->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND;
571 dispPtr->ObFlags2 = corpseDataPtr->timer/2;
572
573 if (corpseDataPtr->Type==I_BehaviourXenoborg) {
574 /* Particularly important for xenoborgs... optional for others? */
575 if (dispPtr->ObFlags2<ONE_FIXED) {
576 corpseDataPtr->HModelController.DisableBleeding=1;
577 }
578 }
579 }
580
581 /* Does the corpse that falls when not visible make no sound? */
582 ProveHModel_Far(&corpseDataPtr->HModelController,sbPtr);
583 }
584
585 corpseDataPtr->timer-=NormalFrameTime;
586 corpseDataPtr->validityTimer-=NormalFrameTime;
587
588 /* May get decapitated whilst screaming... */
589 if ((corpseDataPtr->Type==I_BehaviourMarine)
590 ||((corpseDataPtr->Type==I_BehaviourMarinePlayer)&&(AvP.PlayerType==I_Marine))) {
591
592 SECTION_DATA *head;
593
594 head=GetThisSectionData(corpseDataPtr->HModelController.section_data,"head");
595
596 /* Is it still attached? */
597 if (head) {
598 if (head->flags§ion_data_notreal) {
599 head=NULL;
600 }
601 }
602
603 if (head==NULL) {
604 if(corpseDataPtr->SoundHandle2 != SOUND_NOACTIVEINDEX) {
605 Sound_Stop(corpseDataPtr->SoundHandle2);
606 }
607 }
608 }
609
610 if ((corpseDataPtr->Type==I_BehaviourPredator)||
611 ((corpseDataPtr->Type==I_BehaviourMarinePlayer)&&(AvP.PlayerType==I_Predator))) {
612
613 /* If we're a partially cloaked predator, continue to decloak. */
614 if (corpseDataPtr->CloakStatus==PCLOAK_Off) {
615 /* Do nothing. */
616 } else if (corpseDataPtr->CloakStatus==PCLOAK_Activating) {
617 /* Don't reset timer. */
618 corpseDataPtr->CloakStatus = PCLOAK_Deactivating;
619 } else if (corpseDataPtr->CloakStatus==PCLOAK_Deactivating) {
620 /* Okay, okay! */
621 } else {
622 /* Cloak must be On. */
623 corpseDataPtr->CloakStatus = PCLOAK_Deactivating;
624 corpseDataPtr->CloakTimer = 0; /* Was predStatus->PredShimmer. */
625 }
626 GLOBALASSERT((corpseDataPtr->CloakStatus==PCLOAK_Deactivating)||(corpseDataPtr->CloakStatus==PCLOAK_Off));
627 /* Run the timer. */
628 if (corpseDataPtr->CloakStatus==PCLOAK_Deactivating) {
629 corpseDataPtr->CloakTimer += NormalFrameTime;
630 if(corpseDataPtr->CloakTimer>=(ONE_FIXED))
631 {
632 corpseDataPtr->CloakTimer=0;
633 corpseDataPtr->CloakStatus=PCLOAK_Off;
634 }
635 }
636 } else {
637 GLOBALASSERT(corpseDataPtr->CloakStatus==PCLOAK_Off);
638 }
639
640 /* Marine specifics. */
641 if (corpseDataPtr->Type==I_BehaviourMarine) {
642 /* Did marine die with the trigger held down? */
643 if (corpseDataPtr->DeathFiring) {
644 /* Is there a gunflash? */
645 if(corpseDataPtr->My_Gunflash_Section) {
646 /* But is it still attached? */
647 if (corpseDataPtr->My_Gunflash_Section->my_controller==&(corpseDataPtr->HModelController)) {
648 /* Keep firing! */
649 LOCALASSERT(corpseDataPtr->WeaponMisfireFunction);
650 /* Shouldn't be doing this without knowing why. */
651 (*corpseDataPtr->WeaponMisfireFunction)(corpseDataPtr->My_Gunflash_Section,&corpseDataPtr->weapon_variable);
652 }
653 }
654 }
655
656 /* Do we want to trim off the weapons? */
657
658 if (corpseDataPtr->HModelController.keyframe_flags) {
659
660 GLOBALASSERT(corpseDataPtr->TemplateRoot);
661
662 TrimToTemplate(sbPtr,&corpseDataPtr->HModelController,corpseDataPtr->TemplateRoot, 1);
663 }
664 }
665
666 /* Fire sound code. */
667 if(corpseDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) Sound_Update3d(corpseDataPtr->SoundHandle3,&(sbPtr->DynPtr->Position));
668 if(corpseDataPtr->SoundHandle4!=SOUND_NOACTIVEINDEX) Sound_Update3d(corpseDataPtr->SoundHandle4,&(sbPtr->DynPtr->Position));
669
670 if (sbPtr->SBDamageBlock.IsOnFire) {
671 if (corpseDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) {
672 if (ActiveSounds[corpseDataPtr->SoundHandle3].soundIndex!=SID_FIRE) {
673 Sound_Stop(corpseDataPtr->SoundHandle3);
674 Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&corpseDataPtr->SoundHandle3,127);
675 }
676 } else {
677 Sound_Play(SID_FIRE,"dlev",&(sbPtr->DynPtr->Position),&corpseDataPtr->SoundHandle3,127);
678 }
679 } else {
680 if (corpseDataPtr->SoundHandle3!=SOUND_NOACTIVEINDEX) {
681 Sound_Stop(corpseDataPtr->SoundHandle3);
682 }
683 }
684
685 #if CORPSE_SIGHTINGS
686 Marine_CorpseSightingTest(sbPtr);
687 #endif
688
689 /* Finally consider destructing preds. */
690 if (corpseDataPtr->destructTimer>=0) {
691 corpseDataPtr->destructTimer-=NormalFrameTime;
692 if (corpseDataPtr->destructTimer<=0) {
693 StartPredatorSelfDestructExplosion(sbPtr);
694 corpseDataPtr->GibbFactor=ONE_FIXED;
695 corpseDataPtr->destructTimer=-1;
696 }
697 }
698 }
699
SetCorpseAnimSequence_Core(STRATEGYBLOCK * sbPtr,HMODEL_SEQUENCE_TYPES type,int subtype,int length,int tweeningtime)700 void SetCorpseAnimSequence_Core(STRATEGYBLOCK *sbPtr,HMODEL_SEQUENCE_TYPES type, int subtype, int length, int tweeningtime)
701 {
702
703 NETCORPSEDATABLOCK *corpseStatus=(NETCORPSEDATABLOCK *)(sbPtr->SBdataptr);
704
705 GLOBALASSERT(length!=0);
706
707 if (tweeningtime<=0) {
708 InitHModelSequence(&corpseStatus->HModelController,(int)type,subtype,length);
709 } else {
710 InitHModelTweening(&corpseStatus->HModelController, tweeningtime, (int)type,subtype,length,0);
711 }
712
713 corpseStatus->HModelController.Playing=1;
714 /* Might be unset... */
715 }
716
CorpseIsDamaged(STRATEGYBLOCK * sbPtr,DAMAGE_PROFILE * damage,int multiple,int wounds,SECTION_DATA * Section,VECTORCH * incoming)717 void CorpseIsDamaged(STRATEGYBLOCK *sbPtr, DAMAGE_PROFILE *damage, int multiple, int wounds,SECTION_DATA *Section,VECTORCH *incoming) {
718
719 NETCORPSEDATABLOCK *corpseDataPtr;
720 int tkd,deathtype;
721
722 LOCALASSERT(sbPtr);
723 corpseDataPtr = (NETCORPSEDATABLOCK *)sbPtr->SBdataptr;
724 LOCALASSERT(corpseDataPtr);
725
726 /* Set up gibb factor. */
727
728 tkd=TotalKineticDamage(damage);
729 deathtype=0;
730
731 corpseDataPtr->Wounds|=wounds;
732
733 switch(corpseDataPtr->Type) {
734 case I_BehaviourMarinePlayer:
735 {
736 if (damage->ExplosivePower==1) {
737 if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) {
738 /* Okay, you can gibb now. */
739 corpseDataPtr->GibbFactor=ONE_FIXED>>1;
740 deathtype=2;
741 }
742 } else if ((tkd>60)&&((multiple>>16)>1)) {
743 int newmult;
744
745 newmult=DIV_FIXED(multiple,NormalFrameTime);
746 if (MUL_FIXED(tkd,newmult)>(500)) {
747 /* Loadsabullets! */
748 corpseDataPtr->GibbFactor=-(ONE_FIXED>>2);
749 deathtype=2;
750 }
751 }
752
753 if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) {
754 /* Basically SADARS only. */
755 corpseDataPtr->GibbFactor=ONE_FIXED;
756 deathtype=3;
757 }
758
759 if (damage->ForceBoom) {
760 deathtype+=damage->ForceBoom;
761 }
762 }
763 break;
764 case I_BehaviourAlien:
765 case I_BehaviourAlienPlayer:
766 {
767 if (damage->ExplosivePower==1) {
768 /* Explosion case. */
769 if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) {
770 /* Okay, you can gibb now. */
771 corpseDataPtr->GibbFactor=ONE_FIXED>>1;
772 deathtype=2;
773 }
774 } else if ((tkd<40)&&((multiple>>16)>1)) {
775 int newmult;
776
777 newmult=DIV_FIXED(multiple,NormalFrameTime);
778 if (MUL_FIXED(tkd,newmult)>700) {
779 /* Excessive bullets case 1. */
780 corpseDataPtr->GibbFactor=ONE_FIXED>>2;
781 deathtype=2;
782 } else if (MUL_FIXED(tkd,newmult)>250) {
783 /* Excessive bullets case 2. */
784 corpseDataPtr->GibbFactor=ONE_FIXED>>3;
785 deathtype=1;
786 }
787 }
788
789 /* Predaliens and preatorians only gibb for sadars. */
790 if (corpseDataPtr->subtype!=0) {
791 corpseDataPtr->GibbFactor=0;
792 /* But retain deathtype. */
793 }
794
795 if ((damage->ExplosivePower==2)||(damage->ExplosivePower==6)) {
796 /* Basically SADARS only. */
797 if (corpseDataPtr->Type==AT_Standard) {
798 corpseDataPtr->GibbFactor=ONE_FIXED;
799 } else {
800 corpseDataPtr->GibbFactor=ONE_FIXED>>2;
801 }
802 deathtype=3;
803 }
804
805 if (damage->ForceBoom) {
806 deathtype+=damage->ForceBoom;
807 }
808 /* No additional gibbing for flamethrowers. */
809
810 if (damage->Id==AMMO_PREDPISTOL_STRIKE) {
811 /* Blow up if hit by the bolt? */
812 corpseDataPtr->GibbFactor=ONE_FIXED>>3;
813 } else if (damage->Id==AMMO_PRED_PISTOL) {
814 /* Unfortunately, that can't happen. Try this test instead. */
815 if (multiple>(43253)) {
816 /* Must be pretty close. */
817 corpseDataPtr->GibbFactor=ONE_FIXED>>3;
818 }
819 } else if (damage->Id==AMMO_FLECHETTE_POSTMAX) {
820 corpseDataPtr->GibbFactor=ONE_FIXED>>2;
821 }
822 }
823 break;
824 case I_BehaviourPredator:
825 case I_BehaviourXenoborg:
826 /* Predator and Xenoborg 'splatting' currently ommitted... */
827 break;
828 default:
829 break;
830 }
831
832 }
833
834
835
836
837
838
839
840 /*--------------------**
841 ** Loading and Saving **
842 **--------------------*/
843 #include "savegame.h"
844 typedef struct corpse_save_block
845 {
846 SAVE_BLOCK_STRATEGY_HEADER header;
847
848 int timer;
849 int validityTimer;
850
851 AVP_BEHAVIOUR_TYPE Type;
852 int hltable_index;
853 int GibbFactor;
854
855 /* If you're a predator... */
856 PRED_CLOAKSTATE CloakStatus;
857 int CloakTimer;
858 int destructTimer;
859 /* If you're a marine... */
860 int weapon_id;
861 int weapon_variable;
862 int Android;
863 int ARealMarine;
864 /* If you're an alien... */
865 int subtype;
866
867 int Wounds;
868
869 int DeathFiring :1;
870
871
872 int deathCode;
873
874 //strategyblock stuff
875 int integrity;
876 DAMAGEBLOCK SBDamageBlock;
877 DYNAMICSBLOCK dynamics;
878 }CORPSE_SAVE_BLOCK;
879
880
881
882 //defines for load/save macros
883 #define SAVELOAD_BLOCK block
884 #define SAVELOAD_BEHAV corpseDataPtr
885
886
LoadStrategy_Corpse(SAVE_BLOCK_STRATEGY_HEADER * header)887 void LoadStrategy_Corpse(SAVE_BLOCK_STRATEGY_HEADER* header)
888 {
889 extern HITLOCATIONTABLE Global_Hitlocation_Tables[];
890
891 STRATEGYBLOCK* sbPtr;
892 NETCORPSEDATABLOCK* corpseDataPtr;
893 CORPSE_SAVE_BLOCK* block = (CORPSE_SAVE_BLOCK*) header;
894
895 //check the size of the save block
896 if(header->size!=sizeof(*block)) return;
897
898 //see if there is a living version of this corpse
899 sbPtr = FindSBWithName(header->SBname);
900
901 if(sbPtr)
902 {
903 //make sure the strategy found is some type of creature
904 if(sbPtr->I_SBtype != I_BehaviourAlien &&
905 sbPtr->I_SBtype != I_BehaviourMarine &&
906 sbPtr->I_SBtype != I_BehaviourPredator &&
907 sbPtr->I_SBtype != I_BehaviourDormantPredator &&
908 sbPtr->I_SBtype != I_BehaviourXenoborg &&
909 sbPtr->I_SBtype != I_BehaviourFaceHugger)
910 {
911 return;
912 }
913 //get rid of it then
914 DestroyAnyStrategyBlock(sbPtr);
915
916 sbPtr = NULL;
917 }
918
919 //now we need to create a corpse from scratch
920 sbPtr = CreateActiveStrategyBlock();
921 if(!sbPtr)
922 {
923 GLOBALASSERT(0=="Run out of strategy blocks");
924 return;
925 }
926 InitialiseSBValues(sbPtr);
927 corpseDataPtr = (void *)AllocateMem(sizeof(NETCORPSEDATABLOCK));
928
929 //fill in some default values
930 memset(corpseDataPtr,0,sizeof(*corpseDataPtr));
931
932 corpseDataPtr->SoundHandle = SOUND_NOACTIVEINDEX;
933 corpseDataPtr->SoundHandle2 = SOUND_NOACTIVEINDEX;
934 corpseDataPtr->SoundHandle3 = SOUND_NOACTIVEINDEX;
935 corpseDataPtr->SoundHandle4 = SOUND_NOACTIVEINDEX;
936
937 sbPtr->SBdataptr=corpseDataPtr;
938 sbPtr->I_SBtype=I_BehaviourNetCorpse;
939 COPY_NAME(sbPtr->SBname,block->header.SBname);
940 sbPtr->shapeIndex = 0;
941 sbPtr->maintainVisibility = 1;
942
943 //get a dynamics block
944 sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_SPRITE_NPC);
945
946
947 //start copying stuff
948
949 COPYELEMENT_LOAD(timer)
950 COPYELEMENT_LOAD(validityTimer)
951 COPYELEMENT_LOAD(Type)
952 COPYELEMENT_LOAD(GibbFactor)
953 COPYELEMENT_LOAD(CloakStatus)
954 COPYELEMENT_LOAD(CloakTimer)
955 COPYELEMENT_LOAD(destructTimer)
956 COPYELEMENT_LOAD(weapon_variable)
957 COPYELEMENT_LOAD(Android)
958 COPYELEMENT_LOAD(ARealMarine)
959 COPYELEMENT_LOAD(subtype)
960 COPYELEMENT_LOAD(Wounds)
961 COPYELEMENT_LOAD(DeathFiring)
962
963
964 //copy strategy block stuff
965 *sbPtr->DynPtr = block->dynamics;
966 sbPtr->integrity = block->integrity;
967 sbPtr->SBDamageBlock = block->SBDamageBlock;
968
969 //hit location table
970 if(block->hltable_index>=0)
971 {
972 corpseDataPtr->hltable = &Global_Hitlocation_Tables[block->hltable_index];
973 }
974 else
975 {
976 corpseDataPtr->hltable = NULL;
977 }
978
979 // get death_data
980 corpseDataPtr->This_Death = GetThisDeath_FromUniqueCode(block->deathCode);
981
982 //get marine's weapon (if a marine)
983 corpseDataPtr->My_Weapon = GetThisNPCMarineWeapon(block->weapon_id);
984 if(corpseDataPtr->My_Weapon)
985 {
986 corpseDataPtr->WeaponMisfireFunction=corpseDataPtr->My_Weapon->WeaponMisfireFunction;
987 corpseDataPtr->My_Gunflash_Section=corpseDataPtr->My_Gunflash_Section;
988 corpseDataPtr->TemplateRoot=GetNamedHierarchyFromLibrary(corpseDataPtr->My_Weapon->Riffname,corpseDataPtr->My_Weapon->TemplateName);
989 }
990
991
992 //load the corpse's hierarchy
993 {
994 SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy);
995 if(hier_header)
996 {
997 LoadHierarchy(hier_header,&corpseDataPtr->HModelController);
998 }
999 }
1000
1001 Load_SoundState(&corpseDataPtr->SoundHandle);
1002 Load_SoundState(&corpseDataPtr->SoundHandle2);
1003 Load_SoundState(&corpseDataPtr->SoundHandle3);
1004 Load_SoundState(&corpseDataPtr->SoundHandle4);
1005
1006 }
1007
1008
SaveStrategy_Corpse(STRATEGYBLOCK * sbPtr)1009 void SaveStrategy_Corpse(STRATEGYBLOCK* sbPtr)
1010 {
1011 CORPSE_SAVE_BLOCK *block;
1012 NETCORPSEDATABLOCK* corpseDataPtr;
1013
1014 corpseDataPtr = (NETCORPSEDATABLOCK*)sbPtr->SBdataptr;
1015
1016 GET_STRATEGY_SAVE_BLOCK(block,sbPtr);
1017
1018 //start copying stuff
1019
1020 COPYELEMENT_SAVE(timer)
1021 COPYELEMENT_SAVE(validityTimer)
1022 COPYELEMENT_SAVE(Type)
1023 COPYELEMENT_SAVE(GibbFactor)
1024 COPYELEMENT_SAVE(CloakStatus)
1025 COPYELEMENT_SAVE(CloakTimer)
1026 COPYELEMENT_SAVE(destructTimer)
1027 COPYELEMENT_SAVE(weapon_variable)
1028 COPYELEMENT_SAVE(Android)
1029 COPYELEMENT_SAVE(ARealMarine)
1030 COPYELEMENT_SAVE(subtype)
1031 COPYELEMENT_SAVE(Wounds)
1032 COPYELEMENT_SAVE(DeathFiring)
1033
1034
1035 //hit location table
1036 if(corpseDataPtr->hltable)
1037 {
1038 block->hltable_index = corpseDataPtr->hltable->index;
1039 }
1040 else
1041 {
1042 block->hltable_index = -1;
1043 }
1044
1045 //save death code
1046 if(corpseDataPtr->This_Death)
1047 {
1048 block->deathCode = corpseDataPtr->This_Death->Unique_Code;
1049 }
1050 else
1051 {
1052 block->deathCode = -1;
1053 }
1054
1055 //save marine's weapon
1056 if(corpseDataPtr->My_Weapon)
1057 block->weapon_id = corpseDataPtr->My_Weapon->id;
1058 else
1059 block->weapon_id = -1;
1060
1061
1062 //save strategy block stuff
1063
1064 block->dynamics = *sbPtr->DynPtr;
1065 block->dynamics.CollisionReportPtr=0;
1066
1067 block->integrity = sbPtr->integrity;
1068 block->SBDamageBlock = sbPtr->SBDamageBlock;
1069
1070 //save the hierarchy
1071 SaveHierarchy(&corpseDataPtr->HModelController);
1072
1073 Save_SoundState(&corpseDataPtr->SoundHandle);
1074 Save_SoundState(&corpseDataPtr->SoundHandle2);
1075 Save_SoundState(&corpseDataPtr->SoundHandle3);
1076 Save_SoundState(&corpseDataPtr->SoundHandle4);
1077 }
1078