| | 1 | #include "system.h" |
| | 2 | #include "prototyp.h" |
| | 3 | #include "stratdef.h" |
| | 4 | #include "bh_types.h" |
| | 5 | #include "debris.h" |
| | 6 | #include "npc_alien.h" |
| | 7 | #include "npc_marine.h" |
| | 8 | #include "scream.h" |
| | 9 | #include "corpse.h" |
| | 10 | #include <assert.h> |
| | 11 | #include "weaponbehaviour.h" |
| | 12 | #include "pldghost.h" |
| | 13 | #include "savegame.h" |
| | 14 | #include "weapons.h" |
| | 15 | #include "dynamics.h" |
| | 16 | #include <stdio.h> |
| | 17 | #include <string.h> |
| | 18 | #include <stdlib.h> |
| | 19 | |
| | 20 | #include "projload.hpp" |
| | 21 | |
| | 22 | #define HDEBRIS_BLEEDING_TIME (ONE_FIXED*2) |
| | 23 | |
| | 24 | extern int NumActiveBlocks; |
| | 25 | extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); |
| | 26 | extern int GetLoadedShapeMSL(char const * shapename); |
| | 27 | extern MATRIXCH IdentityMatrix; |
| | 28 | |
| | 29 | extern void SetSeededFastRandom(int seed); |
| | 30 | |
| | 31 | static int generate_random_between (int first, int second) |
| | 32 | { |
| | 33 | int diff = second - first; |
| | 34 | |
| | 35 | if (!diff) |
| | 36 | return first; |
| | 37 | |
| | 38 | int absdiff = abs (diff); |
| | 39 | int rand_no = FastRandom () % absdiff; |
| | 40 | |
| | 41 | return ( (diff < 0) ? (second + rand_no) : (first + rand_no)); |
| | 42 | } |
| | 43 | |
| | 44 | void MakeFragments(STRATEGYBLOCK * sbptr) |
| | 45 | { |
| | 46 | VECTORCH diff; |
| | 47 | |
| | 48 | if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) |
| | 49 | return; |
| | 50 | |
| | 51 | if (!sbptr->DynPtr || !sbptr->DisplayBlock) |
| | 52 | return; |
| | 53 | |
| | 54 | VECTORCH * posPtr = &sbptr->DynPtr->Position; |
| | 55 | struct shapefragmentdesc * fragdesc = GetFragDesc(sbptr->shapeIndex); |
| | 56 | |
| | 57 | if(!fragdesc) |
| | 58 | { |
| | 59 | Sound_Play(SID_EXPLOSION, "d", posPtr); |
| | 60 | return; |
| | 61 | } |
| | 62 | else if(!fragdesc->sh_fragsound) |
| | 63 | { |
| | 64 | Sound_Play(SID_EXPLOSION, "d", posPtr); |
| | 65 | } |
| | 66 | else |
| | 67 | { |
| | 68 | SHAPEFRAGMENTSOUND * fragsound = fragdesc->sh_fragsound; |
| | 69 | |
| | 70 | if(SID_NOSOUND != fragsound->sound_number) |
| | 71 | { |
| | 72 | Sound_Play((SOUNDINDEX)fragsound->sound_number, "d", posPtr); |
| | 73 | |
| | 74 | /* |
| | 75 | SOUND3DDATA s3d; |
| | 76 | s3d.position = *posPtr; |
| | 77 | s3d.inner_range = fragsound->inner_range; |
| | 78 | s3d.outer_range = fragsound->outer_range; |
| | 79 | s3d.velocity.vx = s3d.velocity.vy = s3d.velocity.vz = 0; |
| | 80 | Sound_Play ((SOUNDINDEX)fragsound->sound_number, "nvp", &s3d, fragsound->max_volume, fragsound->pitch); |
| | 81 | */ |
| | 82 | } |
| | 83 | } |
| | 84 | |
| | 85 | SHAPEFRAGMENT * frags = fragdesc->sh_frags; |
| | 86 | |
| | 87 | while (frags->ShapeIndex > 0) |
| | 88 | { |
| | 89 | int i = 0; |
| | 90 | |
| | 91 | for (; i < frags->NumFrags; i++) |
| | 92 | { |
| | 93 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourFragment); |
| | 94 | |
| | 95 | if (NULL == sbPtr) |
| | 96 | return; |
| | 97 | |
| | 98 | VECTORCH offset = { frags->x_offset, frags->y_offset, frags->z_offset }; |
| | 99 | |
| | 100 | DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(frags->ShapeIndex); |
| | 101 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); |
| | 102 | sbPtr->dataptr = malloc(sizeof(ONE_SHOT_BEHAV_BLOCK)); |
| | 103 | |
| | 104 | if ((NULL == dispPtr) || (NULL == sbPtr->dataptr) || (NULL == dynPtr)) |
| | 105 | { |
| | 106 | RemoveBehaviourStrategy(sbPtr); |
| | 107 | return; |
| | 108 | } |
| | 109 | |
| | 110 | dynPtr->Mass = 10; |
| | 111 | dynPtr->IsStatic = 0; |
| | 112 | dynPtr->IgnoreSameObjectsAsYou = 1; |
| | 113 | |
| | 114 | if (!offset.vx && !offset.vy && !offset.vz) |
| | 115 | { |
| | 116 | // place the fragment randomly within the bounding box of the parent |
| | 117 | offset.vx = generate_random_between(mainshapelist[sbptr->shapeIndex]->shapemaxx, mainshapelist[sbptr->shapeIndex]->shapeminx); |
| | 118 | offset.vy = generate_random_between(mainshapelist[sbptr->shapeIndex]->shapemaxy, mainshapelist[sbptr->shapeIndex]->shapeminy); |
| | 119 | offset.vz = generate_random_between(mainshapelist[sbptr->shapeIndex]->shapemaxz, mainshapelist[sbptr->shapeIndex]->shapeminz); |
| | 120 | } |
| | 121 | |
| | 122 | dispPtr->ObStrategyBlock = sbPtr; |
| | 123 | |
| | 124 | ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = ((FastRandom() & 32768) << 2) + 65535 * 4; |
| | 125 | |
| | 126 | RotateVector(&offset, &sbptr->DynPtr->OrientMat); |
| | 127 | |
| | 128 | if (sbptr->containingModule) |
| | 129 | { |
| | 130 | if (frags->x_offset || frags->y_offset || frags->z_offset) |
| | 131 | { |
| | 132 | diff.vx = offset.vx; |
| | 133 | diff.vy = offset.vy; |
| | 134 | diff.vz = offset.vz; |
| | 135 | } |
| | 136 | else |
| | 137 | { |
| | 138 | diff.vx = sbptr->containingModule->m_mapptr->MapWorld.vx - posPtr->vx; |
| | 139 | diff.vy = sbptr->containingModule->m_mapptr->MapWorld.vy - posPtr->vy; |
| | 140 | diff.vz = sbptr->containingModule->m_mapptr->MapWorld.vz - posPtr->vz; |
| | 141 | } |
| | 142 | |
| | 143 | Normalise(&diff); |
| | 144 | } |
| | 145 | else |
| | 146 | { |
| | 147 | diff.vx = diff.vz = 0; |
| | 148 | diff.vy = ONE_FIXED; |
| | 149 | } |
| | 150 | |
| | 151 | { |
| | 152 | /*give fragment an impulse roughly in the direction of its offset*/ |
| | 153 | VECTORCH impulse = offset; |
| | 154 | |
| | 155 | if(impulse.vx || impulse.vy || impulse.vz) |
| | 156 | { |
| | 157 | Normalise(&impulse); |
| | 158 | |
| | 159 | impulse.vx /= generate_random_between(5,10); |
| | 160 | // impulse.vy /= generate_random_between(5,10); |
| | 161 | impulse.vz /= generate_random_between(5,10); |
| | 162 | } |
| | 163 | |
| | 164 | dynPtr->LinImpulse = impulse; |
| | 165 | } |
| | 166 | |
| | 167 | diff.vx = (diff.vx >> 4); |
| | 168 | diff.vy = (diff.vy >> 4); |
| | 169 | diff.vz = (diff.vz >> 4); |
| | 170 | |
| | 171 | offset.vx += posPtr->vx; |
| | 172 | offset.vy += posPtr->vy; |
| | 173 | offset.vz += posPtr->vz; |
| | 174 | |
| | 175 | dispPtr->ObWorld = offset; |
| | 176 | dispPtr->ObMat = sbptr->DynPtr->OrientMat; |
| | 177 | dispPtr->ObEuler = sbptr->DynPtr->OrientEuler; |
| | 178 | |
| | 179 | dynPtr->Position = offset; |
| | 180 | dynPtr->OrientMat = sbptr->DynPtr->OrientMat; |
| | 181 | dynPtr->OrientEuler = sbptr->DynPtr->OrientEuler; |
| | 182 | dynPtr->PrevOrientMat = sbptr->DynPtr->PrevOrientMat; |
| | 183 | dynPtr->PrevOrientEuler = sbptr->DynPtr->PrevOrientEuler; |
| | 184 | |
| | 185 | dynPtr->AngVelocity.EulerX = (((FastRandom()&2047)-1023))<<2; |
| | 186 | dynPtr->AngVelocity.EulerY = (((FastRandom()&2047)-1023))<<2; |
| | 187 | dynPtr->AngVelocity.EulerZ = (((FastRandom()&2047)-1023))<<2; |
| | 188 | |
| | 189 | dynPtr->LinImpulse.vy = - (FastRandom() & 1023) << 2; |
| | 190 | |
| | 191 | /* Look to see if object has only one polygon in it; |
| | 192 | if so it's probably a glass fragment, so don't bother |
| | 193 | giving it collisions */ |
| | 194 | |
| | 195 | if (1 == dispPtr->ShapeData->numitems) |
| | 196 | dynPtr->DynamicsType = DYN_TYPE_NO_COLLISIONS; |
| | 197 | } |
| | 198 | |
| | 199 | frags++; |
| | 200 | } |
| | 201 | } |
| | 202 | |
| | 203 | static void DoAlienLimbLossSound(VECTORCH *position) |
| | 204 | { |
| | 205 | PlayAlienSound(0, ASC_LimbLoss, 0, NULL, position); |
| | 206 | } |
| | 207 | |
| | 208 | static void MakeFleshRippingNoises(VECTORCH *positionPtr) |
| | 209 | { |
| | 210 | Sound_Play(SID_BODY_BEING_HACKED_UP_0 + (FastRandom() % 5) , "d", positionPtr); |
| | 211 | } |
| | 212 | |
| | 213 | DISPLAYBLOCK *disengage_part(STRATEGYBLOCK *parent_sbPtr, SECTION_DATA *root, VECTORCH *positionPtr, MATRIXCH *orientation, int *wounds, int speed) |
| | 214 | { |
| | 215 | if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) |
| | 216 | return NULL; |
| | 217 | |
| | 218 | assert(root); |
| | 219 | |
| | 220 | STRATEGYBLOCK* sbPtr= CreateActiveStrategyBlock(I_BehaviourHierarchicalFragment); |
| | 221 | |
| | 222 | if(NULL == sbPtr) |
| | 223 | return NULL; |
| | 224 | |
| | 225 | //DISPLAYBLOCK *dispPtr = AllocateNewObject(root->sempai->ShapeNum); |
| | 226 | DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(GetLoadedShapeMSL("Shell")); |
| | 227 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); |
| | 228 | sbPtr->dataptr = malloc(sizeof(HDEBRIS_BEHAV_BLOCK)); |
| | 229 | |
| | 230 | if (!dispPtr || !dynPtr || (NULL == sbPtr->dataptr)) |
| | 231 | { |
| | 232 | RemoveBehaviourStrategy(sbPtr); |
| | 233 | return NULL; |
| | 234 | } |
| | 235 | |
| | 236 | dynPtr->Mass = 10; |
| | 237 | dynPtr->IsStatic = 0; |
| | 238 | dynPtr->IgnoreSameObjectsAsYou = 1; |
| | 239 | dispPtr->ObWorld = *positionPtr; |
| | 240 | |
| | 241 | // 2. NOW set up the strategyblock-specific fields for |
| | 242 | // the new displayblock. We won't go through the "AttachNew |
| | 243 | // StrategyBlock" and "AssignRunTimeBehaviours" pair, since |
| | 244 | // the first switches on ObShape and the second on bhvr; |
| | 245 | // but, in this case, there isn't a particular connection |
| | 246 | // between them. |
| | 247 | |
| | 248 | dispPtr->ObStrategyBlock = sbPtr; |
| | 249 | |
| | 250 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = HDEBRIS_LIFETIME; |
| | 251 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->smokes = 0; |
| | 252 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_NOSOUND; |
| | 253 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->GibbFactor = 0; |
| | 254 | |
| | 255 | if (root->sempai->flags & section_flag_gibbwhenfragged) |
| | 256 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->GibbFactor = (ONE_FIXED >> 1); |
| | 257 | |
| | 258 | /* Inheritance of android flag. */ |
| | 259 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Android = 0; |
| | 260 | |
| | 261 | int wounds_temp = Splice_HModels(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), root); |
| | 262 | |
| | 263 | if (wounds) |
| | 264 | *wounds = wounds_temp; |
| | 265 | |
| | 266 | if (parent_sbPtr) |
| | 267 | { |
| | 268 | /* Inherit fire! */ |
| | 269 | |
| | 270 | sbPtr->DamageBlock.IsOnFire = parent_sbPtr->DamageBlock.IsOnFire; |
| | 271 | |
| | 272 | /* KJL 11:28:27 14/10/98 - this is set so we can later know what the debris was part of */ |
| | 273 | /* CDF 3/3/99 put it in the switch statement, to deal with complex cases */ |
| | 274 | /* Creature specific code! */ |
| | 275 | |
| | 276 | switch (parent_sbPtr->type) |
| | 277 | { |
| | 278 | case I_BehaviourAlien: |
| | 279 | { |
| | 280 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(parent_sbPtr->dataptr); |
| | 281 | /* Just go to spasm. */ |
| | 282 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand,
ASSS_Spasm, -1, 1); |
| | 283 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 284 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 285 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourAlien; |
| | 286 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = alienStatusPointer->Type; |
| | 287 | root->SecMat = *orientation; |
| | 288 | |
| | 289 | DoAlienLimbLossSound(positionPtr); |
| | 290 | |
| | 291 | /* Last as long as a dead alien. */ |
| | 292 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = ALIEN_DYINGTIME; |
| | 293 | } |
| | 294 | break; |
| | 295 | case I_BehaviourMarine: |
| | 296 | { |
| | 297 | /* See if we can strip to template. */ |
| | 298 | MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(parent_sbPtr->dataptr); |
| | 299 | |
| | 300 | SECTION *template_root = GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,
marineStatusPointer->My_Weapon->TemplateName); |
| | 301 | /* Now, find the section that matches. */ |
| | 302 | SECTION *template_sempai = Get_Corresponding_Section_Recursive(template_root, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).Root_Section->Section_Name); |
| | 303 | |
| | 304 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Android = marineStatusPointer->Android; |
| | 305 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourMarine; |
| | 306 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = marineStatusPointer->My_Weapon->ARealMarine; |
| | 307 | |
| | 308 | if (template_sempai) |
| | 309 | { |
| | 310 | /* We have a match! */ |
| | 311 | Transmogrify_HModels(sbPtr, &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), template_sempai, 1, 0, 0); |
| | 312 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_MarineStand, MSSS_Spasm, -1, 1); |
| | 313 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 314 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 315 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 316 | //MakeFleshRippingNoises(positionPtr); |
| | 317 | } |
| | 318 | else |
| | 319 | { |
| | 320 | /* Forget it. Must be a disembodied weapon, or something. */ |
| | 321 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 322 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 323 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 324 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 325 | |
| | 326 | //dispPtr->ObMat = *orientation; |
| | 327 | /* Below is an alternative... */ |
| | 328 | } |
| | 329 | |
| | 330 | root->SecMat = *orientation; |
| | 331 | |
| | 332 | /* Since we're dealing with a marine, consider expressions. */ |
| | 333 | { |
| | 334 | SECTION_DATA *head = GetThisSectionData(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.section_data, "head"); |
| | 335 | |
| | 336 | if (head && !(head->flags & section_data_notreal)) |
| | 337 | { |
| | 338 | TXACTRLBLK *tacb = head->tac_ptr; |
| | 339 | |
| | 340 | while (tacb) |
| | 341 | { |
| | 342 | tacb->tac_sequence = 4; |
| | 343 | tacb->tac_txah_s = GetTxAnimHeaderFromShape(tacb, head->ShapeNum); |
| | 344 | tacb = tacb->tac_next; |
| | 345 | } |
| | 346 | } |
| | 347 | } |
| | 348 | |
| | 349 | /* Last as long as a dead marine. */ |
| | 350 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = MARINE_DYINGTIME; |
| | 351 | } |
| | 352 | break; |
| | 353 | case I_BehaviourPredator: |
| | 354 | { |
| | 355 | /* See if we can strip to template. */ |
| | 356 | |
| | 357 | SECTION *template_root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template"); |
| | 358 | /* Now, find the section that matches. */ |
| | 359 | SECTION *template_sempai = Get_Corresponding_Section_Recursive(template_root, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).Root_Section->Section_Name); |
| | 360 | |
| | 361 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourPredator; |
| | 362 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 363 | |
| | 364 | if (template_sempai) |
| | 365 | { |
| | 366 | /* We have a match! */ |
| | 367 | Transmogrify_HModels(sbPtr, &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), template_sempai, 1, 0, 0); |
| | 368 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_PredatorStand, PSSS_Spasm, -1, 1); |
| | 369 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 370 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 371 | root->SecMat = *orientation; |
| | 372 | } |
| | 373 | else |
| | 374 | { |
| | 375 | /* Forget it. Must be a disembodied weapon, or something. */ |
| | 376 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 377 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 378 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 379 | root->SecMat = *orientation; |
| | 380 | } |
| | 381 | /* Just freeze for now! */ |
| | 382 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.Playing = 0; |
| | 383 | /* Last as long as a dead predator. */ |
| | 384 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = PRED_DIETIME; |
| | 385 | } |
| | 386 | break; |
| | 387 | case I_BehaviourCorpse: |
| | 388 | { |
| | 389 | CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)parent_sbPtr->dataptr; |
| | 390 | |
| | 391 | switch (corpseDataPtr->Type) |
| | 392 | { |
| | 393 | case I_BehaviourAlien: |
| | 394 | { |
| | 395 | DoAlienLimbLossSound(positionPtr); |
| | 396 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand, ASSS_Spasm, -1, 1); |
| | 397 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->subtype; |
| | 398 | } |
| | 399 | break; |
| | 400 | case I_BehaviourMarine: |
| | 401 | { |
| | 402 | SECTION *template_sempai; |
| | 403 | SECTION *template_root = corpseDataPtr->TemplateRoot; |
| | 404 | /* Now, find the section that matches. */ |
| | 405 | template_sempai=Get_Corresponding_Section_Recursive(template_root, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).Root_Section->Section_Name); |
| | 406 | |
| | 407 | //if (template_sempai) MakeFleshRippingNoises(positionPtr); |
| | 408 | |
| | 409 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController),(ONE_FIXED>>2), HMSQT_MarineStand, MSSS_Spasm, -1, 1); |
| | 410 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->ARealMarine; |
| | 411 | } |
| | 412 | break; |
| | 413 | case I_BehaviourPredator: |
| | 414 | { |
| | 415 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_PredatorStand, PSSS_Spasm, -1, 1); |
| | 416 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->subtype; |
| | 417 | } |
| | 418 | break; |
| | 419 | default: |
| | 420 | { |
| | 421 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 422 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->subtype; |
| | 423 | } |
| | 424 | } |
| | 425 | |
| | 426 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 427 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 428 | root->SecMat = *orientation; |
| | 429 | |
| | 430 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = corpseDataPtr->Type; |
| | 431 | /* Inherit counter from parent corpse. */ |
| | 432 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = corpseDataPtr->timer; |
| | 433 | } |
| | 434 | break; |
| | 435 | case I_BehaviourHierarchicalFragment: |
| | 436 | { |
| | 437 | HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)parent_sbPtr->dataptr; |
| | 438 | |
| | 439 | switch (debrisDataPtr->Type) |
| | 440 | { |
| | 441 | case I_BehaviourAlien: |
| | 442 | { |
| | 443 | //DoAlienLimbLossSound(positionPtr); |
| | 444 | /* Sound should be the same for all types of alien! */ |
| | 445 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand,
ASSS_Spasm, -1, 1); |
| | 446 | } |
| | 447 | break; |
| | 448 | case I_BehaviourMarine: |
| | 449 | //MakeFleshRippingNoises(positionPtr); |
| | 450 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_MarineStand,
MSSS_Spasm, -1, 1); |
| | 451 | |
| | 452 | if (!strcmp(root->sempai->Section_Name, "SADAR")) |
| | 453 | { |
| | 454 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 455 | dynPtr->Elasticity = (ONE_FIXED >> 3); |
| | 456 | } |
| | 457 | else if (!strcmp(root->sempai->Section_Name, "gren stock") |
| | 458 | || !strcmp(root->sempai->Section_Name, "flamer") |
| | 459 | || !strcmp(root->sempai->Section_Name, "flame thrower") |
| | 460 | || !strcmp(root->sempai->Section_Name, "mini gun")) |
| | 461 | { |
| | 462 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 463 | } |
| | 464 | else if (!strcmp(root->sempai->Section_Name, "spring one")) |
| | 465 | { |
| | 466 | /* This is a smartgun! */ |
| | 467 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 468 | /* Whilst we're here... */ |
| | 469 | dispPtr->ObMat = *orientation; |
| | 470 | root->SecMat = IdentityMatrix; |
| | 471 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 472 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.Playing = 0; |
| | 473 | } |
| | 474 | else if (!strcmp(root->sempai->Section_Name, "pulse mag")) |
| | 475 | { |
| | 476 | /* Don't have a 'tink' yet... */ |
| | 477 | dynPtr->Elasticity = (ONE_FIXED >> 1); |
| | 478 | } |
| | 479 | break; |
| | 480 | case I_BehaviourPredator: |
| | 481 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_PredatorStand,
PSSS_Spasm, -1, 1); |
| | 482 | break; |
| | 483 | default: |
| | 484 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 485 | } |
| | 486 | |
| | 487 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 488 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 489 | root->SecMat = *orientation; |
| | 490 | |
| | 491 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = debrisDataPtr->Type; |
| | 492 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = debrisDataPtr->SubType; |
| | 493 | /* Inherit counter from parent debris. */ |
| | 494 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = debrisDataPtr->counter; |
| | 495 | } |
| | 496 | break; |
| | 497 | case I_BehaviourNetGhost: |
| | 498 | { |
| | 499 | NETGHOSTDATABLOCK *dataptr = parent_sbPtr->dataptr; |
| | 500 | |
| | 501 | switch (dataptr->type) |
| | 502 | { |
| | 503 | case I_BehaviourAlien: |
| | 504 | { |
| | 505 | //DoAlienLimbLossSound(positionPtr); |
| | 506 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand, ASSS_Spasm, -1, 1); |
| | 507 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 508 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 509 | root->SecMat = *orientation; |
| | 510 | |
| | 511 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourAlien; |
| | 512 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = dataptr->subtype; |
| | 513 | } |
| | 514 | break; |
| | 515 | case I_BehaviourCorpse: |
| | 516 | { |
| | 517 | switch (dataptr->subtype) |
| | 518 | { |
| | 519 | case I_BehaviourAlien: |
| | 520 | { |
| | 521 | DoAlienLimbLossSound(positionPtr); |
| | 522 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand, ASSS_Spasm, -1, 1); |
| | 523 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 524 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 525 | root->SecMat = *orientation; |
| | 526 | |
| | 527 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourAlien; |
| | 528 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = dataptr->IOType; |
| | 529 | } |
| | 530 | break; |
| | 531 | default: |
| | 532 | { |
| | 533 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 534 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 535 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 536 | root->SecMat = *orientation; |
| | 537 | |
| | 538 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = parent_sbPtr->type; |
| | 539 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 540 | } |
| | 541 | } |
| | 542 | } |
| | 543 | break; |
| | 544 | default: |
| | 545 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 546 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 547 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 548 | root->SecMat = *orientation; |
| | 549 | |
| | 550 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = parent_sbPtr->type; |
| | 551 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 552 | } |
| | 553 | } |
| | 554 | break; |
| | 555 | case I_BehaviourAutoGun: |
| | 556 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 557 | // no break for you |
| | 558 | default: |
| | 559 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 560 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 561 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 562 | root->SecMat = *orientation; |
| | 563 | |
| | 564 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = parent_sbPtr->type; |
| | 565 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 566 | } |
| | 567 | } |
| | 568 | else |
| | 569 | { |
| | 570 | /* KJL 11:27:54 14/10/98 - set behaviour type to null to avoid confusion */ |
| | 571 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourNull; |
| | 572 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 573 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 574 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 575 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 576 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 577 | root->SecMat = *orientation; |
| | 578 | } |
| | 579 | |
| | 580 | dispPtr->HModelControlBlock = &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController); |
| | 581 | |
| | 582 | dispPtr->ObWorld = *positionPtr; |
| | 583 | //dispPtr->ObMat = *orientation; |
| | 584 | dispPtr->ObMat = IdentityMatrix; |
| | 585 | |
| | 586 | dynPtr->Position = *positionPtr; |
| | 587 | dynPtr->OrientMat = *orientation; |
| | 588 | //dynPtr->Mass = 5; |
| | 589 | dynPtr->Mass = 1; |
| | 590 | |
| | 591 | ProveHModel(dispPtr->HModelControlBlock, dispPtr); |
| | 592 | |
| | 593 | return dispPtr; |
| | 594 | } |
| | 595 | |
| | 596 | DISPLAYBLOCK *MakeHierarchicalDebris(STRATEGYBLOCK *parent_sbPtr, SECTION_DATA *root, VECTORCH *positionPtr, MATRIXCH *orientation, int *wounds, int speed,
VECTORCH *incoming) |
| | 597 | { |
| | 598 | /* KJL 16:53:22 28/02/98 - this seems to happen a lot in multiplayer */ |
| | 599 | if( |
| | 600 | (positionPtr->vx > 1000000 || positionPtr->vx < -1000000) |
| | 601 | || |
| | 602 | (positionPtr->vy > 1000000 || positionPtr->vy < -1000000) |
| | 603 | || |
| | 604 | (positionPtr->vz > 1000000 || positionPtr->vz < -1000000) |
| | 605 | ) |
| | 606 | return NULL; |
| | 607 | |
| | 608 | if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) |
| | 609 | return NULL; |
| | 610 | |
| | 611 | assert(root); |
| | 612 | |
| | 613 | /* Right away, try to intercept all molotov cocktails! */ |
| | 614 | if (!(root->flags & section_data_notreal) && !strcmp(root->sempai->Section_Name, "bottle")) |
| | 615 | { |
| | 616 | DISPLAYBLOCK *dispPtr = SpawnMolotovCocktail(root, orientation); |
| | 617 | /* Correct speed. */ |
| | 618 | |
| | 619 | if (dispPtr) |
| | 620 | { |
| | 621 | DYNAMICSBLOCK *dynPtr = dispPtr->ObStrategyBlock->DynPtr; |
| | 622 | |
| | 623 | /* This code CnP'd from further down! */ |
| | 624 | dynPtr->AngVelocity.EulerX = (FastRandom() & 2047) - 1024; |
| | 625 | dynPtr->AngVelocity.EulerY = (FastRandom() & 2047) - 1024; |
| | 626 | dynPtr->AngVelocity.EulerZ = (FastRandom() & 2047) - 1024; |
| | 627 | |
| | 628 | { |
| | 629 | int random = (FastRandom() & 1023) - 512; |
| | 630 | |
| | 631 | if (random > 0) |
| | 632 | dynPtr->LinImpulse.vx = (random + 100) << speed; |
| | 633 | else |
| | 634 | dynPtr->LinImpulse.vx = (random - 100) << speed; |
| | 635 | } |
| | 636 | |
| | 637 | { |
| | 638 | int random = (FastRandom() & 1023) - 768; |
| | 639 | |
| | 640 | if (random > 0) |
| | 641 | dynPtr->LinImpulse.vy = (random + 100) << speed; |
| | 642 | else |
| | 643 | dynPtr->LinImpulse.vy = (random - 100) << speed; |
| | 644 | } |
| | 645 | |
| | 646 | { |
| | 647 | int random = (FastRandom() & 1023) - 512; |
| | 648 | |
| | 649 | if (random > 0) |
| | 650 | dynPtr->LinImpulse.vz = (random + 100) << speed; |
| | 651 | else |
| | 652 | dynPtr->LinImpulse.vz = (random - 100) << speed; |
| | 653 | } |
| | 654 | } |
| | 655 | |
| | 656 | return dispPtr; |
| | 657 | } |
| | 658 | |
| | 659 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourHierarchicalFragment); |
| | 660 | |
| | 661 | if(NULL == sbPtr) |
| | 662 | return NULL; |
| | 663 | |
| | 664 | DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(GetLoadedShapeMSL("Shell")); |
| | 665 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); |
| | 666 | sbPtr->dataptr = malloc(sizeof(HDEBRIS_BEHAV_BLOCK)); |
| | 667 | |
| | 668 | if (!dispPtr || !dynPtr || !sbPtr->dataptr) |
| | 669 | { |
| | 670 | RemoveBehaviourStrategy(sbPtr); |
| | 671 | return NULL; |
| | 672 | } |
| | 673 | |
| | 674 | dynPtr->Mass = 10; |
| | 675 | dynPtr->IsStatic = 0; |
| | 676 | dynPtr->IgnoreSameObjectsAsYou = 1; |
| | 677 | |
| | 678 | dispPtr->ObWorld = *positionPtr; |
| | 679 | dispPtr->ObStrategyBlock = sbPtr; |
| | 680 | dynPtr->Mass = 80; |
| | 681 | |
| | 682 | // 2. NOW set up the strategyblock-specific fields for |
| | 683 | // the new displayblock. We won't go through the "AttachNew |
| | 684 | // StrategyBlock" and "AssignRunTimeBehaviours" pair, since |
| | 685 | // the first switches on ObShape and the second on bhvr; |
| | 686 | // but, in this case, there isn't a particular connection |
| | 687 | // between them. |
| | 688 | |
| | 689 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = HDEBRIS_LIFETIME; |
| | 690 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->smokes = 0; |
| | 691 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_NOSOUND; |
| | 692 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->GibbFactor = 0; |
| | 693 | |
| | 694 | if (root->sempai->flags & section_flag_gibbwhenfragged) |
| | 695 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->GibbFactor = (ONE_FIXED >> 1); |
| | 696 | |
| | 697 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Android = 0; |
| | 698 | |
| | 699 | int wounds_temp = Splice_HModels(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), root); |
| | 700 | |
| | 701 | if (wounds) |
| | 702 | *wounds = wounds_temp; |
| | 703 | |
| | 704 | if (parent_sbPtr) |
| | 705 | { |
| | 706 | /* Inherit fire! */ |
| | 707 | |
| | 708 | sbPtr->DamageBlock.IsOnFire = parent_sbPtr->DamageBlock.IsOnFire; |
| | 709 | |
| | 710 | /* KJL 11:28:27 14/10/98 - this is set so we can later know what the debris was part of */ |
| | 711 | /* CDF 3/3/99 put it in the switch statement, to deal with complex cases */ |
| | 712 | /* Creature specific code! */ |
| | 713 | |
| | 714 | switch (parent_sbPtr->type) |
| | 715 | { |
| | 716 | case I_BehaviourAlien: |
| | 717 | { |
| | 718 | ALIEN_STATUS_BLOCK *alienStatusPointer = (ALIEN_STATUS_BLOCK *)(parent_sbPtr->dataptr); |
| | 719 | assert(alienStatusPointer); |
| | 720 | /* Just go to spasm. */ |
| | 721 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand,
ASSS_Spasm, -1, 1); |
| | 722 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 723 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 724 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourAlien; |
| | 725 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = alienStatusPointer->Type; |
| | 726 | root->SecMat = *orientation; |
| | 727 | |
| | 728 | DoAlienLimbLossSound(positionPtr); |
| | 729 | |
| | 730 | /* Last as long as a dead alien. */ |
| | 731 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = ALIEN_DYINGTIME; |
| | 732 | } |
| | 733 | break; |
| | 734 | case I_BehaviourMarine: |
| | 735 | { |
| | 736 | /* See if we can strip to template. */ |
| | 737 | MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(parent_sbPtr->dataptr); |
| | 738 | assert(marineStatusPointer); |
| | 739 | |
| | 740 | SECTION *template_root = GetNamedHierarchyFromLibrary(marineStatusPointer->My_Weapon->Riffname,
marineStatusPointer->My_Weapon->TemplateName); |
| | 741 | /* Now, find the section that matches. */ |
| | 742 | SECTION *template_sempai = Get_Corresponding_Section_Recursive(template_root, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).Root_Section->Section_Name); |
| | 743 | |
| | 744 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Android = marineStatusPointer->Android; |
| | 745 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourMarine; |
| | 746 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = marineStatusPointer->My_Weapon->ARealMarine; |
| | 747 | |
| | 748 | if (template_sempai) |
| | 749 | { |
| | 750 | /* We have a match! */ |
| | 751 | Transmogrify_HModels(sbPtr, &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), template_sempai, 1, 0, 0); |
| | 752 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_MarineStand, MSSS_Spasm, -1, 1); |
| | 753 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 754 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 755 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 756 | //MakeFleshRippingNoises(positionPtr); |
| | 757 | } |
| | 758 | else |
| | 759 | { |
| | 760 | /* Forget it. Must be a disembodied weapon, or something. */ |
| | 761 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 762 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 763 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 764 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 765 | |
| | 766 | //dispPtr->ObMat = *orientation; |
| | 767 | /* Below is an alternative... */ |
| | 768 | } |
| | 769 | |
| | 770 | root->SecMat = *orientation; |
| | 771 | |
| | 772 | /* Since we're dealing with a marine, consider expressions. */ |
| | 773 | { |
| | 774 | SECTION_DATA *head = GetThisSectionData(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.section_data, "head"); |
| | 775 | |
| | 776 | if (head && !(head->flags & section_data_notreal)) |
| | 777 | { |
| | 778 | TXACTRLBLK *tacb = head->tac_ptr; |
| | 779 | |
| | 780 | while (tacb) |
| | 781 | { |
| | 782 | tacb->tac_sequence = 4; |
| | 783 | tacb->tac_txah_s = GetTxAnimHeaderFromShape(tacb, head->ShapeNum); |
| | 784 | tacb = tacb->tac_next; |
| | 785 | } |
| | 786 | } |
| | 787 | } |
| | 788 | |
| | 789 | /* Last as long as a dead marine. */ |
| | 790 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = MARINE_DYINGTIME; |
| | 791 | } |
| | 792 | break; |
| | 793 | case I_BehaviourPredator: |
| | 794 | { |
| | 795 | /* See if we can strip to template. */ |
| | 796 | |
| | 797 | SECTION *template_root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template"); |
| | 798 | /* Now, find the section that matches. */ |
| | 799 | SECTION *template_sempai = Get_Corresponding_Section_Recursive(template_root, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).Root_Section->Section_Name); |
| | 800 | |
| | 801 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourPredator; |
| | 802 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 803 | |
| | 804 | if (template_sempai) |
| | 805 | { |
| | 806 | /* We have a match! */ |
| | 807 | Transmogrify_HModels(sbPtr, &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), template_sempai, 1, 0, 0); |
| | 808 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_PredatorStand, PSSS_Spasm, -1, 1); |
| | 809 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 810 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 811 | root->SecMat = *orientation; |
| | 812 | } |
| | 813 | else |
| | 814 | { |
| | 815 | /* Forget it. Must be a disembodied weapon, or something. */ |
| | 816 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 817 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 818 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 819 | root->SecMat = *orientation; |
| | 820 | } |
| | 821 | /* Just freeze for now! */ |
| | 822 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.Playing = 0; |
| | 823 | /* Last as long as a dead predator. */ |
| | 824 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = PRED_DIETIME; |
| | 825 | } |
| | 826 | break; |
| | 827 | case I_BehaviourCorpse: |
| | 828 | { |
| | 829 | CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)parent_sbPtr->dataptr; |
| | 830 | |
| | 831 | switch (corpseDataPtr->Type) |
| | 832 | { |
| | 833 | case I_BehaviourAlien: |
| | 834 | { |
| | 835 | DoAlienLimbLossSound(positionPtr); |
| | 836 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand, ASSS_Spasm, -1, 1); |
| | 837 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->subtype; |
| | 838 | } |
| | 839 | break; |
| | 840 | case I_BehaviourMarine: |
| | 841 | { |
| | 842 | SECTION *template_sempai; |
| | 843 | SECTION *template_root = corpseDataPtr->TemplateRoot; |
| | 844 | /* Now, find the section that matches. */ |
| | 845 | template_sempai=Get_Corresponding_Section_Recursive(template_root, (((HDEBRIS_BEHAV_BLOCK * )
sbPtr->dataptr)->HModelController).Root_Section->Section_Name); |
| | 846 | |
| | 847 | //if (template_sempai) MakeFleshRippingNoises(positionPtr); |
| | 848 | |
| | 849 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController),(ONE_FIXED>>2), HMSQT_MarineStand, MSSS_Spasm, -1, 1); |
| | 850 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->ARealMarine; |
| | 851 | } |
| | 852 | break; |
| | 853 | case I_BehaviourPredator: |
| | 854 | { |
| | 855 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_PredatorStand, PSSS_Spasm, -1, 1); |
| | 856 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->subtype; |
| | 857 | } |
| | 858 | break; |
| | 859 | default: |
| | 860 | { |
| | 861 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 862 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = corpseDataPtr->subtype; |
| | 863 | } |
| | 864 | } |
| | 865 | |
| | 866 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 867 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 868 | root->SecMat = *orientation; |
| | 869 | |
| | 870 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = corpseDataPtr->Type; |
| | 871 | /* Inherit counter from parent corpse. */ |
| | 872 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = corpseDataPtr->timer; |
| | 873 | } |
| | 874 | break; |
| | 875 | case I_BehaviourHierarchicalFragment: |
| | 876 | { |
| | 877 | HDEBRIS_BEHAV_BLOCK *debrisDataPtr = (HDEBRIS_BEHAV_BLOCK *)parent_sbPtr->dataptr; |
| | 878 | |
| | 879 | switch (debrisDataPtr->Type) |
| | 880 | { |
| | 881 | case I_BehaviourAlien: |
| | 882 | { |
| | 883 | //DoAlienLimbLossSound(positionPtr); |
| | 884 | /* Sound should be the same for all types of alien! */ |
| | 885 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand,
ASSS_Spasm, -1, 1); |
| | 886 | } |
| | 887 | break; |
| | 888 | case I_BehaviourMarine: |
| | 889 | //MakeFleshRippingNoises(positionPtr); |
| | 890 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_MarineStand,
MSSS_Spasm, -1, 1); |
| | 891 | |
| | 892 | if (!strcmp(root->sempai->Section_Name, "SADAR")) |
| | 893 | { |
| | 894 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 895 | dynPtr->Elasticity = (ONE_FIXED >> 3); |
| | 896 | } |
| | 897 | else if (!strcmp(root->sempai->Section_Name, "gren stock") |
| | 898 | || !strcmp(root->sempai->Section_Name, "flamer") |
| | 899 | || !strcmp(root->sempai->Section_Name, "flame thrower") |
| | 900 | || !strcmp(root->sempai->Section_Name, "mini gun")) |
| | 901 | { |
| | 902 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 903 | } |
| | 904 | else if (!strcmp(root->sempai->Section_Name, "spring one")) |
| | 905 | { |
| | 906 | /* This is a smartgun! */ |
| | 907 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 908 | /* Whilst we're here... */ |
| | 909 | dispPtr->ObMat = *orientation; |
| | 910 | root->SecMat = IdentityMatrix; |
| | 911 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 912 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.Playing = 0; |
| | 913 | } |
| | 914 | else if (!strcmp(root->sempai->Section_Name, "pulse mag")) |
| | 915 | { |
| | 916 | /* Don't have a 'tink' yet... */ |
| | 917 | dynPtr->Elasticity = (ONE_FIXED >> 1); |
| | 918 | } |
| | 919 | break; |
| | 920 | case I_BehaviourPredator: |
| | 921 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_PredatorStand,
PSSS_Spasm, -1, 1); |
| | 922 | break; |
| | 923 | default: |
| | 924 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 925 | } |
| | 926 | |
| | 927 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 928 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 929 | root->SecMat = *orientation; |
| | 930 | |
| | 931 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = debrisDataPtr->Type; |
| | 932 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = debrisDataPtr->SubType; |
| | 933 | /* Inherit counter from parent debris. */ |
| | 934 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = debrisDataPtr->counter; |
| | 935 | } |
| | 936 | break; |
| | 937 | case I_BehaviourNetGhost: |
| | 938 | { |
| | 939 | NETGHOSTDATABLOCK *dataptr = parent_sbPtr->dataptr; |
| | 940 | |
| | 941 | switch (dataptr->type) |
| | 942 | { |
| | 943 | case I_BehaviourAlien: |
| | 944 | { |
| | 945 | //DoAlienLimbLossSound(positionPtr); |
| | 946 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand, ASSS_Spasm, -1, 1); |
| | 947 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 948 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 949 | root->SecMat = *orientation; |
| | 950 | |
| | 951 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourAlien; |
| | 952 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = dataptr->subtype; |
| | 953 | } |
| | 954 | break; |
| | 955 | case I_BehaviourCorpse: |
| | 956 | { |
| | 957 | switch (dataptr->subtype) |
| | 958 | { |
| | 959 | case I_BehaviourAlien: |
| | 960 | { |
| | 961 | DoAlienLimbLossSound(positionPtr); |
| | 962 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED>>2), HMSQT_AlienStand, ASSS_Spasm, -1, 1); |
| | 963 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 964 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 965 | root->SecMat = *orientation; |
| | 966 | |
| | 967 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourAlien; |
| | 968 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = dataptr->IOType; |
| | 969 | } |
| | 970 | break; |
| | 971 | default: |
| | 972 | { |
| | 973 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 974 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 975 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 976 | root->SecMat = *orientation; |
| | 977 | |
| | 978 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = parent_sbPtr->type; |
| | 979 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 980 | } |
| | 981 | } |
| | 982 | } |
| | 983 | break; |
| | 984 | default: |
| | 985 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 986 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 987 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 988 | root->SecMat = *orientation; |
| | 989 | |
| | 990 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = parent_sbPtr->type; |
| | 991 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 992 | } |
| | 993 | } |
| | 994 | break; |
| | 995 | case I_BehaviourAutoGun: |
| | 996 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_LARGEWEAPONDROP; |
| | 997 | // no break for you |
| | 998 | default: |
| | 999 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 1000 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 1001 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 1002 | root->SecMat = *orientation; |
| | 1003 | |
| | 1004 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = parent_sbPtr->type; |
| | 1005 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 1006 | } |
| | 1007 | } |
| | 1008 | else |
| | 1009 | { |
| | 1010 | /* KJL 11:27:54 14/10/98 - set behaviour type to null to avoid confusion */ |
| | 1011 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourNull; |
| | 1012 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 1013 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 1014 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 1015 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 1016 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 1017 | root->SecMat = *orientation; |
| | 1018 | } |
| | 1019 | |
| | 1020 | dispPtr->HModelControlBlock = &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController); |
| | 1021 | |
| | 1022 | dispPtr->ObWorld = *positionPtr; |
| | 1023 | //dispPtr->ObMat = *orientation; |
| | 1024 | dispPtr->ObMat = IdentityMatrix; |
| | 1025 | |
| | 1026 | dynPtr->Position = *positionPtr; |
| | 1027 | dynPtr->OrientMat = *orientation; |
| | 1028 | //dynPtr->Mass = 5; |
| | 1029 | if(incoming) |
| | 1030 | dynPtr->LinImpulse = *incoming; |
| | 1031 | /* |
| | 1032 | // Give explosion fragments an angular velocity |
| | 1033 | dynPtr->AngVelocity.EulerX = (FastRandom() & 2047) - 1024; |
| | 1034 | dynPtr->AngVelocity.EulerY = (FastRandom() & 2047) - 1024; |
| | 1035 | dynPtr->AngVelocity.EulerZ = (FastRandom() & 2047) - 1024; |
| | 1036 | |
| | 1037 | { |
| | 1038 | int random = (FastRandom() & 1023) - 512; |
| | 1039 | |
| | 1040 | if (random > 0) |
| | 1041 | dynPtr->LinImpulse.vx = (random + 100) << speed; |
| | 1042 | else |
| | 1043 | dynPtr->LinImpulse.vx = (random - 100) << speed; |
| | 1044 | } |
| | 1045 | |
| | 1046 | { |
| | 1047 | int random = (FastRandom() & 1023) - 768; |
| | 1048 | |
| | 1049 | if (random > 0) |
| | 1050 | dynPtr->LinImpulse.vy = (random + 100) << speed; |
| | 1051 | else |
| | 1052 | dynPtr->LinImpulse.vy = (random - 100) << speed; |
| | 1053 | } |
| | 1054 | |
| | 1055 | { |
| | 1056 | int random = (FastRandom() & 1023) - 512; |
| | 1057 | |
| | 1058 | if (random > 0) |
| | 1059 | dynPtr->LinImpulse.vz = (random + 100) << speed; |
| | 1060 | else |
| | 1061 | dynPtr->LinImpulse.vz = (random - 100) << speed; |
| | 1062 | } |
| | 1063 | */ |
| | 1064 | |
| | 1065 | ProveHModel(dispPtr->HModelControlBlock, dispPtr); |
| | 1066 | |
| | 1067 | return dispPtr; |
| | 1068 | } |
| | 1069 | |
| | 1070 | void make_clip(SECTION_DATA *root, VECTORCH *positionPtr, MATRIXCH *orientation) |
| | 1071 | { |
| | 1072 | assert(root); |
| | 1073 | |
| | 1074 | if( (NumActiveBlocks > maxobjects-5) || (NumActiveStBlocks > maxstblocks-5)) |
| | 1075 | return; |
| | 1076 | |
| | 1077 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourHierarchicalFragment); |
| | 1078 | |
| | 1079 | if(NULL == sbPtr) |
| | 1080 | return; |
| | 1081 | |
| | 1082 | DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = CreateActiveObject(); |
| | 1083 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); |
| | 1084 | sbPtr->dataptr = malloc(sizeof(HDEBRIS_BEHAV_BLOCK)); |
| | 1085 | |
| | 1086 | if(!dispPtr || !sbPtr->dataptr || !dynPtr) |
| | 1087 | { |
| | 1088 | RemoveBehaviourStrategy(sbPtr); |
| | 1089 | return; |
| | 1090 | } |
| | 1091 | |
| | 1092 | dynPtr->Mass = 1; |
| | 1093 | dynPtr->IsStatic = 0; |
| | 1094 | dynPtr->IgnoreSameObjectsAsYou = 1; |
| | 1095 | |
| | 1096 | dispPtr->extent.min_x = -10; |
| | 1097 | dispPtr->extent.min_y = -10; |
| | 1098 | dispPtr->extent.min_z = -10; |
| | 1099 | dispPtr->extent.max_x = 10; |
| | 1100 | dispPtr->extent.max_y = 10; |
| | 1101 | dispPtr->extent.max_z = 10; |
| | 1102 | dispPtr->ObMat = IdentityMatrix; |
| | 1103 | dispPtr->ObWorld = *positionPtr; |
| | 1104 | |
| | 1105 | // 2. NOW set up the strategyblock-specific fields for |
| | 1106 | // the new displayblock. We won't go through the "AttachNew |
| | 1107 | // StrategyBlock" and "AssignRunTimeBehaviours" pair, since |
| | 1108 | // the first switches on ObShape and the second on bhvr; |
| | 1109 | // but, in this case, there isn't a particular connection |
| | 1110 | // between them. |
| | 1111 | |
| | 1112 | dispPtr->ObStrategyBlock = sbPtr; |
| | 1113 | |
| | 1114 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = HDEBRIS_LIFETIME; |
| | 1115 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->smokes = 0; |
| | 1116 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Bounce_Sound = SID_NOSOUND; |
| | 1117 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->GibbFactor = 0; |
| | 1118 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Android = 0; |
| | 1119 | |
| | 1120 | Splice_HModels(&(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), root); |
| | 1121 | |
| | 1122 | /* KJL 11:27:54 14/10/98 - set behaviour type to null to avoid confusion */ |
| | 1123 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->Type = I_BehaviourNull; |
| | 1124 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->SubType = 0; |
| | 1125 | InitHModelTweening( &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController), (ONE_FIXED<<1), 0, 1, ONE_FIXED, 0); |
| | 1126 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.LockTopSection = 1; |
| | 1127 | ((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootDisplacement = 1; |
| | 1128 | //((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController.ZeroRootRotation = 1; |
| | 1129 | root->SecMat = *orientation; |
| | 1130 | |
| | 1131 | dispPtr->HModelControlBlock = &(((HDEBRIS_BEHAV_BLOCK * ) sbPtr->dataptr)->HModelController); |
| | 1132 | |
| | 1133 | dynPtr->Position = *positionPtr; |
| | 1134 | dynPtr->OrientMat = *orientation; |
| | 1135 | dynPtr->Mass = 1; |
| | 1136 | |
| | 1137 | ProveHModel(dispPtr->HModelControlBlock, dispPtr); |
| | 1138 | |
| | 1139 | assert(dispPtr->ObWorld.vx < 1000000 && dispPtr->ObWorld.vx > -1000000); |
| | 1140 | assert(dispPtr->ObWorld.vy < 1000000 && dispPtr->ObWorld.vy > -1000000); |
| | 1141 | assert(dispPtr->ObWorld.vz < 1000000 && dispPtr->ObWorld.vz > -1000000); |
| | 1142 | } |
| | 1143 | |
| | 1144 | void HierarchicalFragmentBehaviour(STRATEGYBLOCK *sptr) |
| | 1145 | { |
| | 1146 | int bounce = 0; |
| | 1147 | assert(sptr); |
| | 1148 | HDEBRIS_BEHAV_BLOCK *hdbhv = (HDEBRIS_BEHAV_BLOCK * )sptr->dataptr; |
| | 1149 | DYNAMICSBLOCK *dynPtr = sptr->DynPtr; |
| | 1150 | assert(dynPtr); |
| | 1151 | COLLISIONREPORT *reportptr = dynPtr->CollisionReportPtr; |
| | 1152 | |
| | 1153 | if (hdbhv->counter < 0) |
| | 1154 | { |
| | 1155 | sptr->please_destroy_me = 1; |
| | 1156 | return; |
| | 1157 | } |
| | 1158 | |
| | 1159 | if (sptr->DisplayBlock) |
| | 1160 | { |
| | 1161 | sptr->DisplayBlock->SpecialFXFlags |= SFXFLAG_MELTINGINTOGROUND; |
| | 1162 | sptr->DisplayBlock->ObFlags2 = hdbhv->counter / 2; |
| | 1163 | } |
| | 1164 | |
| | 1165 | /* CDF 8/3/99 Added this on request... */ |
| | 1166 | if (sptr->DamageBlock.IsOnFire || (hdbhv->counter < (HDEBRIS_LIFETIME - HDEBRIS_BLEEDING_TIME))) |
| | 1167 | hdbhv->HModelController.DisableBleeding = 1; |
| | 1168 | |
| | 1169 | hdbhv->counter -= NormalFrameTime; |
| | 1170 | |
| | 1171 | if (reportptr == NULL) |
| | 1172 | { |
| | 1173 | hdbhv->bouncelastframe = 0; |
| | 1174 | } |
| | 1175 | else if(DynamicObjectIsMoving(dynPtr)) |
| | 1176 | { |
| | 1177 | do |
| | 1178 | { |
| | 1179 | if (NULL == reportptr->ObstacleSBPtr) |
| | 1180 | { |
| | 1181 | bounce = 1; |
| | 1182 | |
| | 1183 | if(-1 != reportptr->ModuleIndex) |
| | 1184 | { |
| | 1185 | if (hdbhv->HModelController.Root_Section->flags & section_sprays_acid) |
| | 1186 | { |
| | 1187 | MakeDecal(DECAL_SCORCHED, &reportptr->ObstacleNormal, &reportptr->ObstaclePoint, reportptr->ModuleIndex); |
| | 1188 | } |
| | 1189 | else if (hdbhv->HModelController.Root_Section->flags & section_sprays_blood) |
| | 1190 | { |
| | 1191 | MakeDecal((hdbhv->Android ? DECAL_ANDROID_BLOOD_SPLASH : DECAL_HUMAN_BLOOD_SPLASH), &reportptr->ObstacleNormal,
&reportptr->ObstaclePoint, reportptr->ModuleIndex); |
| | 1192 | } |
| | 1193 | else if (hdbhv->HModelController.Root_Section->flags & section_sprays_predoblood) |
| | 1194 | { |
| | 1195 | MakeDecal(DECAL_PREDATOR_BLOOD_SPLASH, &reportptr->ObstacleNormal, &reportptr->ObstaclePoint, reportptr->ModuleIndex); |
| | 1196 | } |
| | 1197 | } |
| | 1198 | } |
| | 1199 | else |
| | 1200 | { |
| | 1201 | if (hdbhv->HModelController.Root_Section->flags & section_sprays_acid) |
| | 1202 | { |
| | 1203 | switch(reportptr->ObstacleSBPtr->type) |
| | 1204 | { |
| | 1205 | case I_BehaviourMarine: |
| | 1206 | case I_BehaviourPredator: |
| | 1207 | case I_BehaviourMarinePlayer: |
| | 1208 | case I_BehaviourPredatorPlayer: |
| | 1209 | case I_BehaviourAutoGun: |
| | 1210 | case I_BehaviourInanimateObject: |
| | 1211 | case I_BehaviourPlacedLight: |
| | 1212 | case I_BehaviourVideoScreen: |
| | 1213 | case I_BehaviourSpeargunBolt: |
| | 1214 | CauseDamageToObject(reportptr->ObstacleSBPtr, &TemplateAmmo[AMMO_ALIEN_FRAG].MaxDamage, ONE_FIXED, NULL); |
| | 1215 | break; |
| | 1216 | /* |
| | 1217 | case I_BehaviourRocket: |
| | 1218 | case I_BehaviourFlare: |
| | 1219 | case I_BehaviourPulseGrenade: |
| | 1220 | case I_BehaviourGrenade: |
| | 1221 | case I_BehaviourFragmentationGrenade: |
| | 1222 | case I_BehaviourProximityGrenade: |
| | 1223 | reportptr->ObstacleSBPtr->please_destroy_me = 1; |
| | 1224 | */ |
| | 1225 | default: |
| | 1226 | break; |
| | 1227 | } |
| | 1228 | } |
| | 1229 | } |
| | 1230 | |
| | 1231 | reportptr = reportptr->NextCollisionReportPtr; |
| | 1232 | |
| | 1233 | } while (reportptr); |
| | 1234 | } |
| | 1235 | |
| | 1236 | if (bounce && !hdbhv->bouncelastframe) |
| | 1237 | { |
| | 1238 | if (hdbhv->Bounce_Sound != SID_NOSOUND) |
| | 1239 | Sound_Play(hdbhv->Bounce_Sound, "dp", &dynPtr->Position, ((FastRandom()&511)-255)); |
| | 1240 | |
| | 1241 | hdbhv->bouncelastframe = 1; |
| | 1242 | } |
| | 1243 | |
| | 1244 | if (dynPtr->IsInContactWithFloor) |
| | 1245 | dynPtr->AngVelocity.EulerX = dynPtr->AngVelocity.EulerY = dynPtr->AngVelocity.EulerZ = 0; |
| | 1246 | else |
| | 1247 | DynamicallyRotateObject(dynPtr); |
| | 1248 | } |
| | 1249 | |
| | 1250 | /*-------------------------------** |
| | 1251 | ** Load/Save hierarchical debris ** |
| | 1252 | **-------------------------------*/ |
| | 1253 | |
| | 1254 | typedef struct hier_debris_save_block |
| | 1255 | { |
| | 1256 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 1257 | |
| | 1258 | //behaviour block stuff |
| | 1259 | int counter; |
| | 1260 | int smokes; |
| | 1261 | int GibbFactor; |
| | 1262 | int Android; |
| | 1263 | |
| | 1264 | AVP_BEHAVIOUR_TYPE Type; |
| | 1265 | int SubType; |
| | 1266 | |
| | 1267 | int bouncelastframe; |
| | 1268 | enum soundindex Bounce_Sound; |
| | 1269 | |
| | 1270 | //strategy block stuff |
| | 1271 | DAMAGEBLOCK DamageBlock; |
| | 1272 | DYNAMICSBLOCK dynamics; |
| | 1273 | |
| | 1274 | } HIER_DEBRIS_SAVE_BLOCK; |
| | 1275 | |
| | 1276 | //defines for load/save macros |
| | 1277 | #define SAVELOAD_BLOCK block |
| | 1278 | #define SAVELOAD_BEHAV hdebrisStatusPointer |
| | 1279 | |
| | 1280 | void LoadStrategy_HierarchicalDebris(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 1281 | { |
| | 1282 | HIER_DEBRIS_SAVE_BLOCK* block = (HIER_DEBRIS_SAVE_BLOCK*) header; |
| | 1283 | |
| | 1284 | //check the size of the save block |
| | 1285 | if(header->size != sizeof(*block)) |
| | 1286 | return; |
| | 1287 | |
| | 1288 | //We need to create the debris then. |
| | 1289 | |
| | 1290 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourHierarchicalFragment); |
| | 1291 | |
| | 1292 | if(NULL == sbPtr) |
| | 1293 | return; |
| | 1294 | |
| | 1295 | DISPLAYBLOCK* dispPtr = sbPtr->DisplayBlock = AllocateNewObject(GetLoadedShapeMSL("Shell")); |
| | 1296 | sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); |
| | 1297 | sbPtr->dataptr = malloc(sizeof(HDEBRIS_BEHAV_BLOCK)); |
| | 1298 | |
| | 1299 | if((NULL == dispPtr) || (NULL == sbPtr->DynPtr) || (NULL == sbPtr->dataptr)) |
| | 1300 | { |
| | 1301 | RemoveBehaviourStrategy(sbPtr); |
| | 1302 | return; |
| | 1303 | } |
| | 1304 | |
| | 1305 | sbPtr->DynPtr->Mass = 10; |
| | 1306 | sbPtr->DynPtr->IsStatic = 0; |
| | 1307 | sbPtr->DynPtr->IgnoreSameObjectsAsYou = 1; |
| | 1308 | |
| | 1309 | dispPtr->ObStrategyBlock = sbPtr; |
| | 1310 | |
| | 1311 | HDEBRIS_BEHAV_BLOCK* hdebrisStatusPointer = (HDEBRIS_BEHAV_BLOCK *)sbPtr->dataptr; |
| | 1312 | |
| | 1313 | hdebrisStatusPointer->HModelController.Deltas = NULL; |
| | 1314 | hdebrisStatusPointer->HModelController.Root_Section = NULL; |
| | 1315 | hdebrisStatusPointer->HModelController.section_data = NULL; |
| | 1316 | |
| | 1317 | dispPtr->HModelControlBlock = &hdebrisStatusPointer->HModelController; |
| | 1318 | |
| | 1319 | COPYELEMENT_LOAD(counter) |
| | 1320 | COPYELEMENT_LOAD(smokes) |
| | 1321 | COPYELEMENT_LOAD(GibbFactor) |
| | 1322 | COPYELEMENT_LOAD(Android) |
| | 1323 | COPYELEMENT_LOAD(Type) |
| | 1324 | COPYELEMENT_LOAD(SubType) |
| | 1325 | COPYELEMENT_LOAD(bouncelastframe) |
| | 1326 | COPYELEMENT_LOAD(Bounce_Sound) |
| | 1327 | |
| | 1328 | *sbPtr->DynPtr = block->dynamics; |
| | 1329 | sbPtr->DamageBlock = block->DamageBlock; |
| | 1330 | |
| | 1331 | { |
| | 1332 | SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); |
| | 1333 | |
| | 1334 | if(hier_header) |
| | 1335 | LoadHierarchy(hier_header, &hdebrisStatusPointer->HModelController); |
| | 1336 | } |
| | 1337 | } |
| | 1338 | |
| | 1339 | void SaveStrategy_HierarchicalDebris(STRATEGYBLOCK* sbPtr) |
| | 1340 | { |
| | 1341 | HDEBRIS_BEHAV_BLOCK* hdebrisStatusPointer; |
| | 1342 | HIER_DEBRIS_SAVE_BLOCK* block; |
| | 1343 | |
| | 1344 | GET_STRATEGY_SAVE_BLOCK(block,sbPtr); |
| | 1345 | hdebrisStatusPointer = (HDEBRIS_BEHAV_BLOCK*) sbPtr->dataptr; |
| | 1346 | |
| | 1347 | //start copying stuff |
| | 1348 | |
| | 1349 | COPYELEMENT_SAVE(counter) |
| | 1350 | COPYELEMENT_SAVE(smokes) |
| | 1351 | COPYELEMENT_SAVE(GibbFactor) |
| | 1352 | COPYELEMENT_SAVE(Android) |
| | 1353 | COPYELEMENT_SAVE(Type) |
| | 1354 | COPYELEMENT_SAVE(SubType) |
| | 1355 | COPYELEMENT_SAVE(bouncelastframe) |
| | 1356 | COPYELEMENT_SAVE(Bounce_Sound) |
| | 1357 | |
| | 1358 | //save strategy block stuff |
| | 1359 | block->dynamics = *sbPtr->DynPtr; |
| | 1360 | block->dynamics.CollisionReportPtr = 0; |
| | 1361 | block->DamageBlock = sbPtr->DamageBlock; |
| | 1362 | |
| | 1363 | SaveHierarchy(&hdebrisStatusPointer->HModelController); |
| | 1364 | } |
| | 1365 | |
| | 1366 | /*------------------** |
| | 1367 | ** Load/Save Debris ** |
| | 1368 | **------------------*/ |
| | 1369 | |
| | 1370 | typedef struct debris_save_block |
| | 1371 | { |
| | 1372 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 1373 | |
| | 1374 | int counter; |
| | 1375 | int dynamicModuleObject; |
| | 1376 | int shapeIndex; |
| | 1377 | int shapeNumPoints; |
| | 1378 | int shapeNumItems; |
| | 1379 | int shapeRadius; |
| | 1380 | |
| | 1381 | //strategy block stuff |
| | 1382 | DAMAGEBLOCK DamageBlock; |
| | 1383 | DYNAMICSBLOCK dynamics; |
| | 1384 | |
| | 1385 | } DEBRIS_SAVE_BLOCK; |
| | 1386 | |
| | 1387 | STRATEGYBLOCK* MakeDebrisForLoad(int shapeIndex,int counter, int dynamicModuleObject) |
| | 1388 | { |
| | 1389 | if( (NumActiveBlocks > maxobjects - 5) || (NumActiveStBlocks > maxstblocks - 5)) |
| | 1390 | return NULL; |
| | 1391 | |
| | 1392 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourFragment); |
| | 1393 | |
| | 1394 | if (sbPtr) |
| | 1395 | { |
| | 1396 | DISPLAYBLOCK *dispPtr = sbPtr->DisplayBlock = AllocateNewObject(shapeIndex); |
| | 1397 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_STATIC); |
| | 1398 | sbPtr->dataptr = malloc(sizeof(ONE_SHOT_BEHAV_BLOCK )); |
| | 1399 | sbPtr->shapeIndex = shapeIndex; |
| | 1400 | |
| | 1401 | if ((sbPtr->dataptr == NULL) || (NULL == dynPtr) || (NULL == dispPtr)) |
| | 1402 | { |
| | 1403 | RemoveBehaviourStrategy(sbPtr); |
| | 1404 | return NULL; |
| | 1405 | } |
| | 1406 | |
| | 1407 | dispPtr->ObStrategyBlock = sbPtr; |
| | 1408 | dynPtr->Mass = 10; |
| | 1409 | dynPtr->IsStatic = 0; |
| | 1410 | dynPtr->IgnoreSameObjectsAsYou = 1; |
| | 1411 | |
| | 1412 | ((ONE_SHOT_BEHAV_BLOCK * ) sbPtr->dataptr)->counter = counter; |
| | 1413 | |
| | 1414 | if(dynamicModuleObject) |
| | 1415 | dispPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; |
| | 1416 | |
| | 1417 | return sbPtr; |
| | 1418 | } |
| | 1419 | |
| | 1420 | return NULL; |
| | 1421 | } |
| | 1422 | |
| | 1423 | void LoadStrategy_Debris(SAVE_BLOCK_HEADER* header) |
| | 1424 | { |
| | 1425 | STRATEGYBLOCK* sbPtr; |
| | 1426 | DEBRIS_SAVE_BLOCK* block = (DEBRIS_SAVE_BLOCK*)header; |
| | 1427 | |
| | 1428 | if(block->header.size == sizeof(*block)) |
| | 1429 | { |
| | 1430 | struct shapeheader* shp = GetShapeData(block->shapeIndex); |
| | 1431 | |
| | 1432 | //check that the shape at shapeIndex is correct |
| | 1433 | if(!shp |
| | 1434 | || (shp->numitems != block->shapeNumItems) |
| | 1435 | || (shp->numpoints != block->shapeNumPoints) |
| | 1436 | || (shp->shaperadius != block->shapeRadius) ) |
| | 1437 | return; |
| | 1438 | |
| | 1439 | sbPtr = MakeDebrisForLoad(block->shapeIndex, block->counter, block->dynamicModuleObject); |
| | 1440 | |
| | 1441 | if(!sbPtr) |
| | 1442 | { |
| | 1443 | *sbPtr->DynPtr = block->dynamics; |
| | 1444 | sbPtr->DamageBlock = block->DamageBlock; |
| | 1445 | } |
| | 1446 | } |
| | 1447 | } |
| | 1448 | |
| | 1449 | void SaveStrategy_Debris(STRATEGYBLOCK* sbPtr) |
| | 1450 | { |
| | 1451 | DEBRIS_SAVE_BLOCK* block; |
| | 1452 | ONE_SHOT_BEHAV_BLOCK* behav = (ONE_SHOT_BEHAV_BLOCK*)sbPtr->dataptr; |
| | 1453 | |
| | 1454 | if(!sbPtr->DisplayBlock || !sbPtr->DisplayBlock->ShapeData) |
| | 1455 | return; |
| | 1456 | |
| | 1457 | struct shapeheader* shp = sbPtr->DisplayBlock->ShapeData; |
| | 1458 | |
| | 1459 | GET_STRATEGY_SAVE_BLOCK(block,sbPtr); |
| | 1460 | |
| | 1461 | block->counter = behav->counter; |
| | 1462 | block->shapeIndex = sbPtr->DisplayBlock->ObShape; |
| | 1463 | block->dynamicModuleObject = (sbPtr->DisplayBlock->ObFlags3 & ObFlag3_DynamicModuleObject); |
| | 1464 | |
| | 1465 | block->shapeNumPoints = shp->numpoints; |
| | 1466 | block->shapeNumItems = shp->numitems; |
| | 1467 | block->shapeRadius = shp->shaperadius; |
| | 1468 | |
| | 1469 | //strategy block stuff |
| | 1470 | block->dynamics = *sbPtr->DynPtr; |
| | 1471 | block->dynamics.CollisionReportPtr = NULL; |
| | 1472 | block->DamageBlock = sbPtr->DamageBlock; |
| | 1473 | } |