| | 1 | #include "system.h" |
| | 2 | #include "prototyp.h" |
| | 3 | #include "stratdef.h" |
| | 4 | #include "debris.h" |
| | 5 | #include "weapons.h" |
| | 6 | #include "decal.h" |
| | 7 | #include "userprofile.h" |
| | 8 | #include "sfx.h" |
| | 9 | #include "kshape.h" |
| | 10 | #include <math.h> |
| | 11 | #include <assert.h> |
| | 12 | |
| | 13 | #define AUTODETECT 1 |
| | 14 | #define SPARKS_FOR_A_SPRAY 15 |
| | 15 | |
| | 16 | extern int NumberOfBloodParticles; |
| | 17 | extern void RenderThisHierarchicalDisplayblock(DISPLAYBLOCK *dbPtr); |
| | 18 | extern int GetLoadedShapeMSL(char const * shapename); |
| | 19 | extern int SeededFastRandom(); |
| | 20 | |
| | 21 | /* external globals */ |
| | 22 | extern int GlobalFrameCounter; |
| | 23 | extern const MATRIXCH IdentityMatrix; |
| | 24 | |
| | 25 | static const int GlobalGoreRate = NORMAL_GORE_RATE; |
| | 26 | int GlobalLevelOfDetail_Hierarchical; |
| | 27 | int Simplify_HModel_Rendering = 0; |
| | 28 | |
| | 29 | static STRATEGYBLOCK *Global_HModel_Sptr; |
| | 30 | static HMODELCONTROLLER *Global_Controller_Ptr; |
| | 31 | static DISPLAYBLOCK *Global_HModel_DispPtr; |
| | 32 | |
| | 33 | static const DAMAGEBLOCK Default_Damageblock = |
| | 34 | { |
| | 35 | 5, /* Health */ |
| | 36 | 0, /* Armour */ |
| | 37 | 0, /* IsOnFire */ |
| | 38 | 0, /* Acid Resistant */ |
| | 39 | 0, /* Fire Resistant */ |
| | 40 | 0, /* Electric Resistant */ |
| | 41 | 0, /* Perfect Armour */ |
| | 42 | 0, /* Electric Sensitive */ |
| | 43 | 0, /* Combustability */ |
| | 44 | 0, /* Indestructable */ |
| | 45 | }; |
| | 46 | |
| | 47 | void QNormalise(QUAT *q) |
| | 48 | { |
| | 49 | float nw = q->quatw; |
| | 50 | float nx = q->quatx; |
| | 51 | float ny = q->quaty; |
| | 52 | float nz = q->quatz; |
| | 53 | |
| | 54 | float m = sqrt(nw*nw+nx*nx+ny*ny+nz*nz); |
| | 55 | |
| | 56 | if (!m) |
| | 57 | return; |
| | 58 | |
| | 59 | m = 65536.0/m; |
| | 60 | |
| | 61 | q->quatw = (nw * m); |
| | 62 | q->quatx = (nx * m); |
| | 63 | q->quaty = (ny * m); |
| | 64 | q->quatz = (nz * m); |
| | 65 | } |
| | 66 | |
| | 67 | int GetSequenceID(int sequence_type, int sub_sequence) |
| | 68 | { |
| | 69 | return( (sub_sequence << 16) + sequence_type); |
| | 70 | } |
| | 71 | |
| | 72 | static SEQUENCE *GetSequencePointer(int sequence_type, int sub_sequence, const SECTION *this_section) |
| | 73 | { |
| | 74 | int a = 0; |
| | 75 | int sequence_id = GetSequenceID(sequence_type, sub_sequence); |
| | 76 | |
| | 77 | for (; a < this_section->num_sequences; a++) |
| | 78 | { |
| | 79 | if (this_section->sequence_array[a].sequence_id == sequence_id) |
| | 80 | return &(this_section->sequence_array[a]); |
| | 81 | } |
| | 82 | |
| | 83 | if (a == this_section->num_sequences) |
| | 84 | { |
| | 85 | //printf("Unknown HModel sequence! %d,%d\n", sequence_type, sub_sequence); |
| | 86 | return &(this_section->sequence_array[0]); |
| | 87 | //assert(0); |
| | 88 | //return(NULL); |
| | 89 | } |
| | 90 | |
| | 91 | return NULL; |
| | 92 | } |
| | 93 | |
| | 94 | int QDot(QUAT *this_quat, QUAT *next_quat) |
| | 95 | { |
| | 96 | return ( (MUL_FIXED(this_quat->quatx,next_quat->quatx)) + |
| | 97 | (MUL_FIXED(this_quat->quaty,next_quat->quaty)) + |
| | 98 | (MUL_FIXED(this_quat->quatz,next_quat->quatz)) + |
| | 99 | (MUL_FIXED(this_quat->quatw,next_quat->quatw)) ); |
| | 100 | } |
| | 101 | |
| | 102 | void GetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* output_vector) |
| | 103 | { |
| | 104 | if(frame->shift_offset) |
| | 105 | { |
| | 106 | output_vector->vx = ((int)frame->Offset_x) << KEYFRAME_VECTOR_SHIFT; |
| | 107 | output_vector->vy = ((int)frame->Offset_y) << KEYFRAME_VECTOR_SHIFT; |
| | 108 | output_vector->vz = ((int)frame->Offset_z) << KEYFRAME_VECTOR_SHIFT; |
| | 109 | } |
| | 110 | else |
| | 111 | { |
| | 112 | output_vector->vx = (int)frame->Offset_x; |
| | 113 | output_vector->vy = (int)frame->Offset_y; |
| | 114 | output_vector->vz = (int)frame->Offset_z; |
| | 115 | } |
| | 116 | } |
| | 117 | |
| | 118 | void Setup_Texture_Animation_For_Section(SECTION_DATA *this_section_data) |
| | 119 | { |
| | 120 | assert(this_section_data); |
| | 121 | |
| | 122 | if(this_section_data->tac_ptr) |
| | 123 | { |
| | 124 | //get rid of old animation control blocks |
| | 125 | TXACTRLBLK *tac_next = this_section_data->tac_ptr; |
| | 126 | |
| | 127 | while (NULL != tac_next) |
| | 128 | { |
| | 129 | TXACTRLBLK *tac_temp = tac_next->tac_next; |
| | 130 | free(tac_next); |
| | 131 | tac_next = tac_temp; |
| | 132 | } |
| | 133 | |
| | 134 | this_section_data->tac_ptr = NULL; |
| | 135 | } |
| | 136 | |
| | 137 | if (this_section_data->Shape && (this_section_data->Shape->shapeflags & ShapeFlag_HasTextureAnimation)) |
| | 138 | { |
| | 139 | int item_num = 0; |
| | 140 | int shape_num = this_section_data->ShapeNum; |
| | 141 | struct shapeheader* shptr = mainshapelist[shape_num]; |
| | 142 | TXACTRLBLK **pptxactrlblk = &this_section_data->tac_ptr; |
| | 143 | |
| | 144 | for(; item_num < shptr->numitems; item_num ++) |
| | 145 | { |
| | 146 | POLYHEADER *poly = (POLYHEADER*)(shptr->items[item_num]); |
| | 147 | assert(poly); |
| | 148 | |
| | 149 | if(poly->PolyFlags & iflag_txanim) |
| | 150 | { |
| | 151 | TXACTRLBLK *pnew_txactrlblk = malloc(sizeof(TXACTRLBLK)); |
| | 152 | |
| | 153 | if(pnew_txactrlblk) |
| | 154 | { |
| | 155 | pnew_txactrlblk->tac_flags = 0; |
| | 156 | pnew_txactrlblk->tac_item = item_num; |
| | 157 | pnew_txactrlblk->tac_sequence = 0; |
| | 158 | pnew_txactrlblk->tac_node = 0; |
| | 159 | pnew_txactrlblk->tac_txarray = GetTxAnimArrayZ(shape_num, item_num); |
| | 160 | pnew_txactrlblk->tac_txah_s = GetTxAnimHeaderFromShape(pnew_txactrlblk, shape_num); |
| | 161 | |
| | 162 | *pptxactrlblk = pnew_txactrlblk; |
| | 163 | pptxactrlblk = &pnew_txactrlblk->tac_next; |
| | 164 | } |
| | 165 | else |
| | 166 | *pptxactrlblk = NULL; |
| | 167 | } |
| | 168 | } |
| | 169 | |
| | 170 | *pptxactrlblk = NULL; |
| | 171 | } |
| | 172 | } |
| | 173 | |
| | 174 | static SECTION_DATA *Create_New_Section(const SECTION *this_section) |
| | 175 | { |
| | 176 | SECTION_DATA *this_section_data = malloc(sizeof(SECTION_DATA)); |
| | 177 | assert(this_section_data); |
| | 178 | |
| | 179 | this_section_data->tac_ptr = NULL; |
| | 180 | this_section_data->sempai = this_section; |
| | 181 | this_section_data->current_damage = this_section_data->sempai->StartingStats; |
| | 182 | this_section_data->current_damage.Health = this_section_data->sempai->StartingStats.Health << 16; |
| | 183 | this_section_data->current_damage.Armour = this_section_data->sempai->StartingStats.Armour << 16; |
| | 184 | |
| | 185 | if (this_section_data->current_damage.Health <= 0) |
| | 186 | this_section_data->current_damage = Default_Damageblock; /* Wrong! */ |
| | 187 | |
| | 188 | this_section_data->my_controller = Global_Controller_Ptr; |
| | 189 | /* Note not initialised! */ |
| | 190 | this_section_data->flags = 0; |
| | 191 | |
| | 192 | /* KJL 17:04:41 31/07/98 - Decal support */ |
| | 193 | this_section_data->NumberOfDecals = this_section_data->NextDecalToUse = 0; |
| | 194 | this_section_data->ShapeNum = this_section->ShapeNum; |
| | 195 | this_section_data->Shape = this_section->Shape; |
| | 196 | |
| | 197 | /* This just so it's not uninitialised. */ |
| | 198 | this_section_data->Prev_Sibling = this_section_data->My_Parent = this_section_data->Next_Sibling = NULL; |
| | 199 | this_section_data->replacement_id = 0; |
| | 200 | |
| | 201 | /* Init texture animations. */ |
| | 202 | this_section_data->tac_ptr = NULL; |
| | 203 | Setup_Texture_Animation_For_Section(this_section_data); |
| | 204 | |
| | 205 | /* Now call recursion... */ |
| | 206 | |
| | 207 | if (this_section->Children != NULL) |
| | 208 | { |
| | 209 | SECTION_DATA *new_child_list_ptr; |
| | 210 | SECTION_DATA *last_child = NULL; |
| | 211 | SECTION_DATA *first_child = NULL; |
| | 212 | |
| | 213 | /* Create subsections. */ |
| | 214 | |
| | 215 | SECTION **child_list_ptr = this_section->Children; |
| | 216 | |
| | 217 | while (*child_list_ptr != NULL) |
| | 218 | { |
| | 219 | (new_child_list_ptr) = Create_New_Section(*child_list_ptr); |
| | 220 | (new_child_list_ptr)->Prev_Sibling = last_child; |
| | 221 | (new_child_list_ptr)->My_Parent = this_section_data; |
| | 222 | (new_child_list_ptr)->Next_Sibling = NULL; /* For now... */ |
| | 223 | |
| | 224 | if (first_child == NULL) |
| | 225 | first_child = new_child_list_ptr; |
| | 226 | |
| | 227 | if (last_child) |
| | 228 | last_child->Next_Sibling = (new_child_list_ptr); |
| | 229 | |
| | 230 | last_child = (new_child_list_ptr); |
| | 231 | |
| | 232 | child_list_ptr++; |
| | 233 | } |
| | 234 | |
| | 235 | (new_child_list_ptr) = NULL; |
| | 236 | this_section_data->First_Child = first_child; |
| | 237 | } |
| | 238 | else |
| | 239 | { |
| | 240 | this_section_data->First_Child = NULL; |
| | 241 | } |
| | 242 | |
| | 243 | return(this_section_data); |
| | 244 | } |
| | 245 | |
| | 246 | void Create_HModel(HMODELCONTROLLER *controller, const SECTION *root) |
| | 247 | { |
| | 248 | /* Connects sequence to controller and must generate |
| | 249 | the list of section_data structures. */ |
| | 250 | |
| | 251 | assert(root); /* Stop messin' about... */ |
| | 252 | |
| | 253 | Global_Controller_Ptr = controller; |
| | 254 | |
| | 255 | controller->Root_Section = root; /* That's a given. */ |
| | 256 | controller->Seconds_For_Sequence = ONE_FIXED; |
| | 257 | controller->timer_increment = ONE_FIXED; |
| | 258 | /* Seconds_For_Sequence and timer_increment are dealt with elsewhere. */ |
| | 259 | controller->sequence_timer = 0; |
| | 260 | controller->FrameStamp = -1; |
| | 261 | controller->View_FrameStamp = -1; |
| | 262 | controller->Computed_Position.vx = controller->Computed_Position.vy = controller->Computed_Position.vz = 0; |
| | 263 | controller->Playing = controller->Reversed = controller->Looped = 0; |
| | 264 | controller->After_Tweening_Sequence_Type = -1; |
| | 265 | controller->After_Tweening_Sub_Sequence = -1; |
| | 266 | controller->AT_seconds_for_sequence = ONE_FIXED; |
| | 267 | controller->AT_sequence_timer = 0; |
| | 268 | controller->Tweening = Controller_NoTweening; |
| | 269 | controller->LoopAfterTweening = controller->StopAfterTweening = 0; |
| | 270 | controller->DisableBleeding = controller->LockTopSection = 0; |
| | 271 | controller->ZeroRootDisplacement = controller->ZeroRootRotation = 0; |
| | 272 | controller->DisableSounds = 0; |
| | 273 | |
| | 274 | /* Controller elevation now removed. All done through delta sequences, 8/4/98. */ |
| | 275 | controller->ElevationTweening = 0; |
| | 276 | controller->Deltas = NULL; |
| | 277 | |
| | 278 | /* Every time a section is preprocessed, it must generate a section_data for |
| | 279 | itself, and clip it to the last section_data that was generated. */ |
| | 280 | |
| | 281 | controller->section_data = Create_New_Section(controller->Root_Section); |
| | 282 | controller->section_data->Prev_Sibling = controller->section_data->My_Parent = controller->section_data->Next_Sibling = NULL; |
| | 283 | |
| | 284 | if (root->flags & section_is_master_root) |
| | 285 | controller->section_data->flags |= section_data_master_root; |
| | 286 | } |
| | 287 | |
| | 288 | static void Destructor_Recursion(SECTION_DATA *doomed_section_data) |
| | 289 | { |
| | 290 | /* Remove other bits. */ |
| | 291 | |
| | 292 | if (doomed_section_data->tac_ptr) |
| | 293 | { |
| | 294 | TXACTRLBLK *tac_next = doomed_section_data->tac_ptr; |
| | 295 | |
| | 296 | while (tac_next) |
| | 297 | { |
| | 298 | TXACTRLBLK *tac_temp = tac_next->tac_next; |
| | 299 | free(tac_next); |
| | 300 | tac_next = tac_temp; |
| | 301 | } |
| | 302 | } |
| | 303 | |
| | 304 | /* Recurse. */ |
| | 305 | |
| | 306 | if (doomed_section_data->First_Child != NULL) |
| | 307 | { |
| | 308 | SECTION_DATA *child_list_ptr = doomed_section_data->First_Child; |
| | 309 | |
| | 310 | while (child_list_ptr != NULL) |
| | 311 | { |
| | 312 | /* Remove each child... */ |
| | 313 | /* JH - 19/2/98 store the next sibling so that we don't access dealloced memory */ |
| | 314 | SECTION_DATA * next_sibling_ptr = child_list_ptr->Next_Sibling; |
| | 315 | Destructor_Recursion(child_list_ptr); |
| | 316 | child_list_ptr = next_sibling_ptr; |
| | 317 | } |
| | 318 | } |
| | 319 | |
| | 320 | /* Now remove the section... */ |
| | 321 | |
| | 322 | free(doomed_section_data); |
| | 323 | doomed_section_data = NULL; |
| | 324 | } |
| | 325 | |
| | 326 | static void Prune_Section(SECTION_DATA *doomed_section_data) |
| | 327 | { |
| | 328 | assert(doomed_section_data); |
| | 329 | /* Destroys section, and all children. */ |
| | 330 | |
| | 331 | if (doomed_section_data->Prev_Sibling) |
| | 332 | { |
| | 333 | assert(doomed_section_data->Prev_Sibling->Next_Sibling==doomed_section_data); |
| | 334 | doomed_section_data->Prev_Sibling->Next_Sibling=doomed_section_data->Next_Sibling; |
| | 335 | } |
| | 336 | |
| | 337 | if (doomed_section_data->Next_Sibling) |
| | 338 | { |
| | 339 | assert(doomed_section_data->Next_Sibling->Prev_Sibling==doomed_section_data); |
| | 340 | doomed_section_data->Next_Sibling->Prev_Sibling=doomed_section_data->Prev_Sibling; |
| | 341 | } |
| | 342 | |
| | 343 | if (doomed_section_data->My_Parent) |
| | 344 | { |
| | 345 | if (doomed_section_data->My_Parent->First_Child==doomed_section_data) |
| | 346 | doomed_section_data->My_Parent->First_Child=doomed_section_data->Next_Sibling; |
| | 347 | } |
| | 348 | |
| | 349 | /* Now destroy. */ |
| | 350 | Destructor_Recursion(doomed_section_data); |
| | 351 | } |
| | 352 | |
| | 353 | static void Delete_Deltas_Recursion(DELTA_CONTROLLER *delta_controller) |
| | 354 | { |
| | 355 | if ( NULL == delta_controller) |
| | 356 | return; |
| | 357 | |
| | 358 | if (delta_controller->next_controller) |
| | 359 | Delete_Deltas_Recursion(delta_controller->next_controller); |
| | 360 | |
| | 361 | free(delta_controller->id); |
| | 362 | delta_controller->id = NULL; |
| | 363 | free(delta_controller); |
| | 364 | delta_controller = NULL; |
| | 365 | } |
| | 366 | |
| | 367 | void Dispel_HModel(HMODELCONTROLLER *controller) |
| | 368 | { |
| | 369 | /* For getting rid of the section_data. */ |
| | 370 | |
| | 371 | if (controller->section_data != NULL) |
| | 372 | { |
| | 373 | Destructor_Recursion(controller->section_data); |
| | 374 | controller->section_data = NULL; |
| | 375 | } |
| | 376 | |
| | 377 | Delete_Deltas_Recursion(controller->Deltas); |
| | 378 | } |
| | 379 | |
| | 380 | void RemoveAllDeltas(HMODELCONTROLLER *controller) |
| | 381 | { |
| | 382 | /* Pretty self explainatory. */ |
| | 383 | assert(controller); |
| | 384 | |
| | 385 | Delete_Deltas_Recursion(controller->Deltas); |
| | 386 | controller->Deltas = NULL; |
| | 387 | } |
| | 388 | |
| | 389 | void Slerp(KEYFRAME_DATA *input,int lerp,QUAT *output) |
| | 390 | { |
| | 391 | int omega = input->omega; //probably faster copying to an int , rather than using the bitfield |
| | 392 | |
| | 393 | KEYFRAME_DATA* next_frame = input->Next_Frame; |
| | 394 | |
| | 395 | /* First check for special case. */ |
| | 396 | |
| | 397 | #if DEBUG |
| | 398 | if ((lerp < 0) || (lerp >= 65536)) |
| | 399 | { |
| | 400 | assert(lerp >= 0); |
| | 401 | assert(lerp < 65536); |
| | 402 | } |
| | 403 | #endif |
| | 404 | |
| | 405 | if (omega == 2048) |
| | 406 | { |
| | 407 | output->quatx = ((int)-input->QOrient.quaty)<<1; |
| | 408 | output->quaty = ((int)input->QOrient.quatx)<<1; |
| | 409 | output->quatz = ((int)-input->QOrient.quatw)<<1; |
| | 410 | output->quatw = ((int)input->QOrient.quatz)<<1; |
| | 411 | |
| | 412 | int t1 = MUL_FIXED((ONE_FIXED-lerp),1024); |
| | 413 | int sclp = GetSin(t1); |
| | 414 | |
| | 415 | int t2 = MUL_FIXED(lerp,1024); |
| | 416 | int sclq = GetSin(t2); |
| | 417 | |
| | 418 | //multiply sclp and sclq by 2 to make up for short quats |
| | 419 | sclp <<= 1; |
| | 420 | sclq <<= 1; |
| | 421 | |
| | 422 | output->quatx = (MUL_FIXED((int)input->QOrient.quatx,sclp))+(MUL_FIXED(output->quatx,sclq)); |
| | 423 | output->quaty = (MUL_FIXED((int)input->QOrient.quaty,sclp))+(MUL_FIXED(output->quaty,sclq)); |
| | 424 | output->quatz = (MUL_FIXED((int)input->QOrient.quatz,sclp))+(MUL_FIXED(output->quatz,sclq)); |
| | 425 | output->quatw = (MUL_FIXED((int)input->QOrient.quatw,sclp))+(MUL_FIXED(output->quatw,sclq)); |
| | 426 | } |
| | 427 | else |
| | 428 | { |
| | 429 | int sclp, sclq; |
| | 430 | if (!omega) |
| | 431 | { |
| | 432 | sclp = ONE_FIXED-lerp; |
| | 433 | sclq = lerp; |
| | 434 | } |
| | 435 | else |
| | 436 | { |
| | 437 | int oneoversinomega = GetOneOverSin(omega); |
| | 438 | int t1 = MUL_FIXED((ONE_FIXED-lerp),omega); |
| | 439 | int t2 = GetSin(t1); |
| | 440 | sclp = MUL_FIXED(t2,oneoversinomega); |
| | 441 | |
| | 442 | t1 = MUL_FIXED(lerp,omega); |
| | 443 | t2 = GetSin(t1); |
| | 444 | sclq = MUL_FIXED(t2,oneoversinomega); |
| | 445 | } |
| | 446 | //multiply sclp and sclq by 2 to make up for short quats |
| | 447 | sclp <<= 1; |
| | 448 | sclq <<= 1; |
| | 449 | |
| | 450 | if(input->slerp_to_negative_quat) |
| | 451 | { |
| | 452 | //instead of actually negating the quaternion , negate sclq |
| | 453 | sclq = -sclq; |
| | 454 | } |
| | 455 | |
| | 456 | output->quatx = MUL_FIXED((int)input->QOrient.quatx, sclp) + MUL_FIXED((int)next_frame->QOrient.quatx, sclq); |
| | 457 | output->quaty = MUL_FIXED((int)input->QOrient.quaty, sclp) + MUL_FIXED((int)next_frame->QOrient.quaty, sclq); |
| | 458 | output->quatz = MUL_FIXED((int)input->QOrient.quatz, sclp) + MUL_FIXED((int)next_frame->QOrient.quatz, sclq); |
| | 459 | output->quatw = MUL_FIXED((int)input->QOrient.quatw, sclp) + MUL_FIXED((int)next_frame->QOrient.quatw, sclq); |
| | 460 | } |
| | 461 | |
| | 462 | QNormalise(output); |
| | 463 | } |
| | 464 | |
| | 465 | static void PlayHierarchySound(HIERARCHY_SOUND* sound, VECTORCH* location) |
| | 466 | { |
| | 467 | assert(sound); |
| | 468 | assert(location); |
| | 469 | |
| | 470 | sound->s3d.position = *location; |
| | 471 | |
| | 472 | /* Marine_ignore, to stop them getting alarmed by their own footsteps! */ |
| | 473 | Sound_Play(sound->sound_index, "nvpm", &sound->s3d, sound->volume, sound->pitch); |
| | 474 | } |
| | 475 | |
| | 476 | static void Process_Delta_Controller(SECTION_DATA *this_section_data,DELTA_CONTROLLER *delta_controller,VECTORCH *output_offset,QUAT *output_quat) |
| | 477 | { |
| | 478 | int a = 0; |
| | 479 | if (delta_controller == NULL) |
| | 480 | return; |
| | 481 | |
| | 482 | int sequence_type = delta_controller->sequence_type; |
| | 483 | int sub_sequence = delta_controller->sub_sequence; |
| | 484 | int timer = delta_controller->timer; |
| | 485 | |
| | 486 | assert(sequence_type>-1); |
| | 487 | assert(sub_sequence>-1); |
| | 488 | |
| | 489 | SEQUENCE *delta_sequence = GetSequencePointer(sequence_type,sub_sequence,this_section_data->sempai); |
| | 490 | |
| | 491 | assert(delta_sequence); |
| | 492 | |
| | 493 | /* Final Frame Correction. */ |
| | 494 | |
| | 495 | KEYFRAME_DATA *this_frame = delta_sequence->first_frame; |
| | 496 | |
| | 497 | while (!this_frame->last_frame) |
| | 498 | { |
| | 499 | a += this_frame->Sequence_Length; |
| | 500 | this_frame = this_frame->Next_Frame; |
| | 501 | } |
| | 502 | |
| | 503 | /* Now a is the 'real' sequence length. */ |
| | 504 | |
| | 505 | int working_timer = MUL_FIXED(timer, a); |
| | 506 | int lastframe_working_timer = delta_controller->lastframe_timer; |
| | 507 | lastframe_working_timer = MUL_FIXED(lastframe_working_timer, a); |
| | 508 | |
| | 509 | /* Now do that thing. */ |
| | 510 | |
| | 511 | this_frame = delta_sequence->first_frame; |
| | 512 | |
| | 513 | KEYFRAME_DATA *next_frame; |
| | 514 | |
| | 515 | while (1) |
| | 516 | { |
| | 517 | next_frame = this_frame->Next_Frame; |
| | 518 | |
| | 519 | if (working_timer >= this_frame->Sequence_Length) |
| | 520 | { |
| | 521 | /* We've gone beyond this frame: get next keyframe. */ |
| | 522 | working_timer -= this_frame->Sequence_Length; |
| | 523 | lastframe_working_timer -= this_frame->Sequence_Length; |
| | 524 | |
| | 525 | /* Have we looped? */ |
| | 526 | if (this_frame->last_frame) |
| | 527 | { |
| | 528 | /* Some deltas are really fast. */ |
| | 529 | this_frame = delta_sequence->first_frame; |
| | 530 | } |
| | 531 | else |
| | 532 | { |
| | 533 | /* Advance frame... */ |
| | 534 | this_frame = next_frame; |
| | 535 | } |
| | 536 | |
| | 537 | if (lastframe_working_timer <= 0) |
| | 538 | { |
| | 539 | if(this_frame->frame_has_extended_data) |
| | 540 | { |
| | 541 | KEYFRAME_DATA_EXTENDED* this_frame_extended = (KEYFRAME_DATA_EXTENDED*) this_frame; |
| | 542 | /* Check flags... */ |
| | 543 | this_section_data->my_controller->keyframe_flags |= this_frame_extended->flags; |
| | 544 | /* ...And keyframe sounds... */ |
| | 545 | |
| | 546 | if (this_frame_extended->sound && !this_section_data->my_controller->DisableSounds) |
| | 547 | PlayHierarchySound(this_frame_extended->sound, &this_section_data->Last_World_Offset); |
| | 548 | } |
| | 549 | } |
| | 550 | } |
| | 551 | else |
| | 552 | { |
| | 553 | break; // Exit loop with success. |
| | 554 | } |
| | 555 | /* Better make sure the last 'frame' has 65536 length... */ |
| | 556 | } |
| | 557 | |
| | 558 | /* Now, this_frame and next_frame are set, and working_timer<this_frame->Sequence_Length. */ |
| | 559 | int lerp = MUL_FIXED(working_timer,this_frame->oneoversequencelength); |
| | 560 | |
| | 561 | GetKeyFrameOffset(this_frame,output_offset); |
| | 562 | |
| | 563 | if(next_frame->shift_offset) |
| | 564 | { |
| | 565 | VECTORCH next_offset; |
| | 566 | GetKeyFrameOffset(next_frame,&next_offset); |
| | 567 | output_offset->vx += MUL_FIXED(next_offset.vx - output_offset->vx,lerp); |
| | 568 | output_offset->vy += MUL_FIXED(next_offset.vy - output_offset->vy,lerp); |
| | 569 | output_offset->vz += MUL_FIXED(next_offset.vz - output_offset->vz,lerp); |
| | 570 | } |
| | 571 | else |
| | 572 | { |
| | 573 | output_offset->vx += MUL_FIXED((int)next_frame->Offset_x - output_offset->vx,lerp); |
| | 574 | output_offset->vy += MUL_FIXED((int)next_frame->Offset_y - output_offset->vy,lerp); |
| | 575 | output_offset->vz += MUL_FIXED((int)next_frame->Offset_z - output_offset->vz,lerp); |
| | 576 | } |
| | 577 | |
| | 578 | /* Now deal with orientation. */ |
| | 579 | |
| | 580 | Slerp(this_frame,lerp,output_quat); |
| | 581 | |
| | 582 | delta_controller->lastframe_timer = delta_controller->timer; |
| | 583 | } |
| | 584 | |
| | 585 | static void Handle_Section_Timer(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,KEYFRAME_DATA *input_frame,int base_timer, int *working_timer) |
| | 586 | { |
| | 587 | if (this_section_data->freezeframe_timer != -1) |
| | 588 | (*working_timer) = this_section_data->freezeframe_timer; |
| | 589 | else |
| | 590 | (*working_timer) = base_timer; |
| | 591 | |
| | 592 | if (this_section_data->accumulated_timer>(*working_timer)) |
| | 593 | { |
| | 594 | /* We must have looped. Or be reversed.... ! */ |
| | 595 | this_section_data->accumulated_timer = 0; |
| | 596 | this_section_data->current_keyframe = input_frame; |
| | 597 | |
| | 598 | if(input_frame->frame_has_extended_data) |
| | 599 | { |
| | 600 | /* Check start flags... */ |
| | 601 | KEYFRAME_DATA_EXTENDED* input_frame_extended = (KEYFRAME_DATA_EXTENDED*) input_frame; |
| | 602 | controller->keyframe_flags |= input_frame_extended->flags; |
| | 603 | /* And Keyframe Sounds. */ |
| | 604 | |
| | 605 | if (input_frame_extended->sound && !controller->DisableSounds) |
| | 606 | PlayHierarchySound(input_frame_extended->sound, &this_section_data->World_Offset); |
| | 607 | } |
| | 608 | } |
| | 609 | |
| | 610 | KEYFRAME_DATA *this_frame = this_section_data->current_keyframe; |
| | 611 | (*working_timer) -= this_section_data->accumulated_timer; |
| | 612 | |
| | 613 | /* Now, a lot like the old way, but we shouldn't need to loop more than once. */ |
| | 614 | /* If we do, we have a game framerate slower than the anim framerate. */ |
| | 615 | |
| | 616 | KEYFRAME_DATA *next_frame; |
| | 617 | |
| | 618 | while (1) |
| | 619 | { |
| | 620 | if (this_frame == NULL) |
| | 621 | this_frame = input_frame; // Heaven help us. |
| | 622 | |
| | 623 | if (this_frame->last_frame) |
| | 624 | next_frame = input_frame; /* Low framerate loop? */ |
| | 625 | else |
| | 626 | next_frame = this_frame->Next_Frame; |
| | 627 | |
| | 628 | if ((*working_timer) >= this_frame->Sequence_Length) |
| | 629 | { |
| | 630 | /* We've gone beyond this frame: get next keyframe. */ |
| | 631 | (*working_timer) -= this_frame->Sequence_Length; |
| | 632 | /* Add sequence length to accumulated_timer. */ |
| | 633 | this_section_data->accumulated_timer += this_frame->Sequence_Length; |
| | 634 | /* Advance frame... */ |
| | 635 | this_frame = next_frame; |
| | 636 | |
| | 637 | if (!controller->Reversed && this_frame->frame_has_extended_data) |
| | 638 | { |
| | 639 | KEYFRAME_DATA_EXTENDED* this_frame_extended = (KEYFRAME_DATA_EXTENDED*) this_frame; |
| | 640 | /* Check flags... */ |
| | 641 | controller->keyframe_flags |= this_frame_extended->flags; |
| | 642 | /* ...And keyframe sounds... */ |
| | 643 | |
| | 644 | if (this_frame_extended->sound && !controller->DisableSounds) |
| | 645 | PlayHierarchySound(this_frame_extended->sound, &this_section_data->World_Offset); |
| | 646 | } |
| | 647 | |
| | 648 | /* Update current keyframe. */ |
| | 649 | this_section_data->current_keyframe = this_frame; |
| | 650 | } |
| | 651 | else |
| | 652 | { |
| | 653 | break; // Exit loop with success. |
| | 654 | } |
| | 655 | /* Better make sure the last 'frame' has 65536 length... */ |
| | 656 | } |
| | 657 | |
| | 658 | if (controller->Reversed) |
| | 659 | { |
| | 660 | /* Okay, maybe a bit cheesy. Trigger flags and sounds... */ |
| | 661 | KEYFRAME_DATA *cnext_frame; |
| | 662 | KEYFRAME_DATA *cthis_frame = this_frame; |
| | 663 | int rev_working_timer = this_section_data->lastframe_timer-this_section_data->accumulated_timer; |
| | 664 | |
| | 665 | while (1) |
| | 666 | { |
| | 667 | if (cthis_frame == NULL) |
| | 668 | cthis_frame = input_frame; // Heaven help us. |
| | 669 | |
| | 670 | if (cthis_frame->last_frame) |
| | 671 | cnext_frame = input_frame; /* Low framerate loop? */ |
| | 672 | else |
| | 673 | cnext_frame = cthis_frame->Next_Frame; |
| | 674 | |
| | 675 | if (rev_working_timer >= cthis_frame->Sequence_Length) |
| | 676 | { |
| | 677 | /* We've gone beyond this frame: get next keyframe. */ |
| | 678 | rev_working_timer -= cthis_frame->Sequence_Length; |
| | 679 | /* Advance frame... */ |
| | 680 | cthis_frame = cnext_frame; |
| | 681 | /* Check flags... */ |
| | 682 | |
| | 683 | if(this_frame->frame_has_extended_data) |
| | 684 | { |
| | 685 | KEYFRAME_DATA_EXTENDED* this_frame_extended = (KEYFRAME_DATA_EXTENDED*) this_frame; |
| | 686 | controller->keyframe_flags |= this_frame_extended->flags; |
| | 687 | /* ...And keyframe sounds... */ |
| | 688 | |
| | 689 | if (this_frame_extended->sound && !controller->DisableSounds) |
| | 690 | PlayHierarchySound(this_frame_extended->sound, &this_section_data->World_Offset); |
| | 691 | } |
| | 692 | } |
| | 693 | else |
| | 694 | { |
| | 695 | break; /* Exit loop with success. */ |
| | 696 | } |
| | 697 | /* Better make sure the last 'frame' has 65536 length... */ |
| | 698 | } |
| | 699 | } |
| | 700 | |
| | 701 | /* Check for looping? */ |
| | 702 | if (this_frame->last_frame && !controller->Looped) |
| | 703 | { |
| | 704 | /* Stop at last frame. */ |
| | 705 | (*working_timer) = 0; |
| | 706 | } |
| | 707 | |
| | 708 | this_section_data->lastframe_timer = base_timer; |
| | 709 | } |
| | 710 | |
| | 711 | void MulQuat(QUAT *q1,QUAT *q2,QUAT *output) |
| | 712 | { |
| | 713 | VECTORCH v1,v2,v3; |
| | 714 | |
| | 715 | /* Multiply quats... */ |
| | 716 | |
| | 717 | v1.vx = q1->quatx; |
| | 718 | v1.vy = q1->quaty; |
| | 719 | v1.vz = q1->quatz; |
| | 720 | |
| | 721 | v2.vx = q2->quatx; |
| | 722 | v2.vy = q2->quaty; |
| | 723 | v2.vz = q2->quatz; |
| | 724 | |
| | 725 | CrossProduct(&v1,&v2,&v3); |
| | 726 | |
| | 727 | int tw = MUL_FIXED(q1->quatw,q2->quatw); |
| | 728 | tw -= DotProduct(&v1,&v2); |
| | 729 | |
| | 730 | v3.vx += MUL_FIXED(q1->quatw,v2.vx); |
| | 731 | v3.vx += MUL_FIXED(q2->quatw,v1.vx); |
| | 732 | |
| | 733 | v3.vy += MUL_FIXED(q1->quatw,v2.vy); |
| | 734 | v3.vy += MUL_FIXED(q2->quatw,v1.vy); |
| | 735 | |
| | 736 | v3.vz += MUL_FIXED(q1->quatw,v2.vz); |
| | 737 | v3.vz += MUL_FIXED(q2->quatw,v1.vz); |
| | 738 | |
| | 739 | output->quatw = tw; |
| | 740 | output->quatx = v3.vx; |
| | 741 | output->quaty = v3.vy; |
| | 742 | output->quatz = v3.vz; |
| | 743 | |
| | 744 | QNormalise(output); |
| | 745 | } |
| | 746 | |
| | 747 | static void New_Analyse_Keyframe_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,KEYFRAME_DATA *input_frame,int base_timer,VECTORCH
*output_offset,MATRIXCH *output_matrix) |
| | 748 | { |
| | 749 | QUAT output_quat; |
| | 750 | /* This *should* never fire, should it? */ |
| | 751 | |
| | 752 | assert(input_frame); |
| | 753 | |
| | 754 | /* First find the current frame. */ |
| | 755 | |
| | 756 | if (input_frame->last_frame) |
| | 757 | { |
| | 758 | /* This is rigid. */ |
| | 759 | GetKeyFrameOffset(input_frame,output_offset); |
| | 760 | |
| | 761 | CopyShortQuatToInt(&input_frame->QOrient,&output_quat); |
| | 762 | |
| | 763 | /* Elevation gone! Now deltas? */ |
| | 764 | |
| | 765 | { |
| | 766 | QUAT elevation_quat,temp_quat; |
| | 767 | VECTORCH elevation_offset; |
| | 768 | DELTA_CONTROLLER *dcon = controller->Deltas; |
| | 769 | |
| | 770 | while (dcon) |
| | 771 | { |
| | 772 | if (dcon->Active) |
| | 773 | { |
| | 774 | Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat); |
| | 775 | output_offset->vx += elevation_offset.vx; |
| | 776 | output_offset->vy += elevation_offset.vy; |
| | 777 | output_offset->vz += elevation_offset.vz; |
| | 778 | |
| | 779 | temp_quat.quatw = output_quat.quatw; |
| | 780 | temp_quat.quatx = output_quat.quatx; |
| | 781 | temp_quat.quaty = output_quat.quaty; |
| | 782 | temp_quat.quatz = output_quat.quatz; |
| | 783 | |
| | 784 | MulQuat(&elevation_quat,&temp_quat,&output_quat); |
| | 785 | } |
| | 786 | |
| | 787 | dcon = dcon->next_controller; |
| | 788 | } |
| | 789 | } |
| | 790 | |
| | 791 | QuatToMat(&output_quat,output_matrix); |
| | 792 | |
| | 793 | /* Check the output is in a sensible place. */ |
| | 794 | if ( !( (output_offset->vx < 1000000 && output_offset->vx > -1000000) |
| | 795 | && (output_offset->vy < 1000000 && output_offset->vy > -1000000) |
| | 796 | && (output_offset->vz < 1000000 && output_offset->vz > -1000000) ) ) |
| | 797 | { |
| | 798 | VECTORCH frame_offset; |
| | 799 | GetKeyFrameOffset(input_frame,&frame_offset); |
| | 800 | |
| | 801 | printf("Second Tests in NEW_ANALYSE_KEYFRAME_DATA.\n"); |
| | 802 | |
| | 803 | if (Global_HModel_Sptr) |
| | 804 | { |
| | 805 | printf("Misplaced object is of type %d\n",Global_HModel_Sptr->type); |
| | 806 | |
| | 807 | if (Global_HModel_Sptr->DisplayBlock) |
| | 808 | printf("Object is Near.\n"); |
| | 809 | else |
| | 810 | printf("Object is Far.\n"); |
| | 811 | } |
| | 812 | else |
| | 813 | { |
| | 814 | printf("Misplaced object has no SBptr.\n"); |
| | 815 | } |
| | 816 | |
| | 817 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 818 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 819 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 820 | printf("Tweening flags %d\n",controller->Tweening); |
| | 821 | |
| | 822 | if (this_section_data->My_Parent) |
| | 823 | printf("Parent Position
%d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->Wor
ld_Offset.vz); |
| | 824 | else |
| | 825 | printf("No parent.\n"); |
| | 826 | |
| | 827 | printf("This Position
%d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz); |
| | 828 | printf("This Keyframe Position %d,%d,%d\n",frame_offset.vx,frame_offset.vy,frame_offset.vz); |
| | 829 | printf("Output Offset %d,%d,%d\n",output_offset->vx,output_offset->vy,output_offset->vz); |
| | 830 | |
| | 831 | assert(output_offset->vx<1000000 && output_offset->vx>-1000000); |
| | 832 | assert(output_offset->vy<1000000 && output_offset->vy>-1000000); |
| | 833 | assert(output_offset->vz<1000000 && output_offset->vz>-1000000); |
| | 834 | } |
| | 835 | |
| | 836 | return; |
| | 837 | } |
| | 838 | |
| | 839 | /* New way. */ |
| | 840 | |
| | 841 | int working_timer; |
| | 842 | Handle_Section_Timer(controller,this_section_data,input_frame,base_timer,&working_timer); |
| | 843 | KEYFRAME_DATA *this_frame = this_section_data->current_keyframe; |
| | 844 | |
| | 845 | /* Now, this_frame and next_frame are set, and working_timer<this_frame->Sequence_Length. */ |
| | 846 | |
| | 847 | int lerp = MUL_FIXED(working_timer,this_frame->oneoversequencelength); |
| | 848 | |
| | 849 | { |
| | 850 | KEYFRAME_DATA* next_frame = this_frame->Next_Frame; |
| | 851 | |
| | 852 | GetKeyFrameOffset(this_frame,output_offset); |
| | 853 | |
| | 854 | if(next_frame->shift_offset) |
| | 855 | { |
| | 856 | VECTORCH next_offset; |
| | 857 | GetKeyFrameOffset(next_frame,&next_offset); |
| | 858 | output_offset->vx += MUL_FIXED(next_offset.vx - output_offset->vx,lerp); |
| | 859 | output_offset->vy += MUL_FIXED(next_offset.vy - output_offset->vy,lerp); |
| | 860 | output_offset->vz += MUL_FIXED(next_offset.vz - output_offset->vz,lerp); |
| | 861 | } |
| | 862 | else |
| | 863 | { |
| | 864 | output_offset->vx += MUL_FIXED((int)next_frame->Offset_x - output_offset->vx,lerp); |
| | 865 | output_offset->vy += MUL_FIXED((int)next_frame->Offset_y - output_offset->vy,lerp); |
| | 866 | output_offset->vz += MUL_FIXED((int)next_frame->Offset_z - output_offset->vz,lerp); |
| | 867 | } |
| | 868 | } |
| | 869 | /* Now deal with orientation. */ |
| | 870 | |
| | 871 | Slerp(this_frame,lerp,&output_quat); |
| | 872 | |
| | 873 | /* Elevation gone! Now deltas? */ |
| | 874 | { |
| | 875 | QUAT elevation_quat,temp_quat; |
| | 876 | VECTORCH elevation_offset; |
| | 877 | DELTA_CONTROLLER *dcon = controller->Deltas; |
| | 878 | |
| | 879 | while (dcon) |
| | 880 | { |
| | 881 | if (dcon->Active) |
| | 882 | { |
| | 883 | Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat); |
| | 884 | output_offset->vx += elevation_offset.vx; |
| | 885 | output_offset->vy += elevation_offset.vy; |
| | 886 | output_offset->vz += elevation_offset.vz; |
| | 887 | |
| | 888 | temp_quat.quatw = output_quat.quatw; |
| | 889 | temp_quat.quatx = output_quat.quatx; |
| | 890 | temp_quat.quaty = output_quat.quaty; |
| | 891 | temp_quat.quatz = output_quat.quatz; |
| | 892 | |
| | 893 | MulQuat(&elevation_quat,&temp_quat,&output_quat); |
| | 894 | } |
| | 895 | |
| | 896 | dcon = dcon->next_controller; |
| | 897 | } |
| | 898 | } |
| | 899 | |
| | 900 | QuatToMat(&output_quat,output_matrix); |
| | 901 | |
| | 902 | /* Check the output is in a sensible place. */ |
| | 903 | if ( !( (output_offset->vx < 1000000 && output_offset->vx > -1000000) |
| | 904 | && (output_offset->vy < 1000000 && output_offset->vy > -1000000) |
| | 905 | && (output_offset->vz < 1000000 && output_offset->vz > -1000000) ) ) |
| | 906 | { |
| | 907 | |
| | 908 | VECTORCH frame_offset; |
| | 909 | GetKeyFrameOffset(input_frame,&frame_offset); |
| | 910 | |
| | 911 | printf("Third Tests in NEW_ANALYSE_KEYFRAME_DATA.\n"); |
| | 912 | |
| | 913 | if (Global_HModel_Sptr) |
| | 914 | { |
| | 915 | printf("Misplaced object is of type %d\n",Global_HModel_Sptr->type); |
| | 916 | |
| | 917 | if (Global_HModel_Sptr->DisplayBlock) |
| | 918 | printf("Object is Near.\n"); |
| | 919 | else |
| | 920 | printf("Object is Far.\n"); |
| | 921 | } |
| | 922 | else |
| | 923 | { |
| | 924 | printf("Misplaced object has no SBptr.\n"); |
| | 925 | } |
| | 926 | |
| | 927 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 928 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 929 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 930 | printf("Tweening flags %d\n",controller->Tweening); |
| | 931 | |
| | 932 | if (this_section_data->My_Parent) |
| | 933 | printf("Parent Position
%d,%d,%d\n",this_section_data->My_Parent->World_Offset.vx,this_section_data->My_Parent->World_Offset.vy,this_section_data->My_Parent->Wor
ld_Offset.vz); |
| | 934 | else |
| | 935 | printf("No parent.\n"); |
| | 936 | |
| | 937 | printf("This Position
%d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz); |
| | 938 | printf("This Keyframe Position %d,%d,%d\n",frame_offset.vx,frame_offset.vy,frame_offset.vz); |
| | 939 | printf("Output Offset %d,%d,%d\n",output_offset->vx,output_offset->vy,output_offset->vz); |
| | 940 | |
| | 941 | assert(output_offset->vx<1000000 && output_offset->vx>-1000000); |
| | 942 | assert(output_offset->vy<1000000 && output_offset->vy>-1000000); |
| | 943 | assert(output_offset->vz<1000000 && output_offset->vz>-1000000); |
| | 944 | } |
| | 945 | } |
| | 946 | |
| | 947 | static struct shapeheader* Get_Degraded_Shape(struct shapeheader* base_shape) |
| | 948 | { |
| | 949 | VECTORCH viewposition; |
| | 950 | extern float CameraZoomScale; |
| | 951 | |
| | 952 | if (Global_HModel_Sptr == NULL) |
| | 953 | return base_shape; |
| | 954 | |
| | 955 | VECTORCH *worldposition = &Global_HModel_Sptr->DynPtr->Position; |
| | 956 | |
| | 957 | viewposition.vx = worldposition->vx - Global_VDB.VDB_World.vx; |
| | 958 | viewposition.vy = worldposition->vy - Global_VDB.VDB_World.vy; |
| | 959 | viewposition.vz = worldposition->vz - Global_VDB.VDB_World.vz; |
| | 960 | |
| | 961 | RotateVector(&viewposition, &Global_VDB.VDB_Mat); |
| | 962 | |
| | 963 | ADAPTIVE_DEGRADATION_DESC *array_ptr = base_shape->shape_degradation_array; |
| | 964 | |
| | 965 | int lodScale = (float)GlobalLevelOfDetail_Hierarchical * CameraZoomScale; |
| | 966 | |
| | 967 | /* Now walk array. */ |
| | 968 | { |
| | 969 | int objectDistance = viewposition.vz; |
| | 970 | |
| | 971 | if (lodScale != ONE_FIXED) |
| | 972 | objectDistance = MUL_FIXED(objectDistance, lodScale); |
| | 973 | |
| | 974 | if (objectDistance <= 0) |
| | 975 | objectDistance = 1; |
| | 976 | |
| | 977 | viewposition.vz = (viewposition.vz * CameraZoomScale); |
| | 978 | |
| | 979 | /* KJL 12:30:37 09/06/98 - the object distance is scaled by a global variable |
| | 980 | so that the level of detail can be changed on the fly. |
| | 981 | |
| | 982 | N.B. The last distance stored in the shape_degradation_array is always zero, so that |
| | 983 | the while loop below will always terminate. */ |
| | 984 | |
| | 985 | if (!array_ptr->shapeCanBeUsedCloseUp) |
| | 986 | { |
| | 987 | if(array_ptr->distance<viewposition.vz) |
| | 988 | return (array_ptr->shape); |
| | 989 | else |
| | 990 | array_ptr++; |
| | 991 | } |
| | 992 | |
| | 993 | while (array_ptr->distance>objectDistance) |
| | 994 | array_ptr++; |
| | 995 | } |
| | 996 | |
| | 997 | /* Should have a valid entry now. */ |
| | 998 | return(array_ptr->shape); |
| | 999 | } |
| | 1000 | |
| | 1001 | static void ReSnap(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data, int elevation) |
| | 1002 | { |
| | 1003 | /* In this procedure, we have to get the new target quat and offset. */ |
| | 1004 | SEQUENCE *sequence_ptr =
GetSequencePointer(controller->After_Tweening_Sequence_Type,controller->After_Tweening_Sub_Sequence,this_section_data->sempai); |
| | 1005 | |
| | 1006 | /* Now, irritatingly, we have to put our faith in AT_sequence_timer. */ |
| | 1007 | if (controller->AT_sequence_timer == (ONE_FIXED-1)) |
| | 1008 | { |
| | 1009 | /* We're in a backwards tween. */ |
| | 1010 | /* Deduce last frame. */ |
| | 1011 | KEYFRAME_DATA *current_frame = sequence_ptr->last_frame; |
| | 1012 | |
| | 1013 | /* Must now have the last frame. */ |
| | 1014 | GetKeyFrameOffset(current_frame,&this_section_data->target_offset); |
| | 1015 | CopyShortQuatToInt(¤t_frame->QOrient,&this_section_data->target_quat); |
| | 1016 | } |
| | 1017 | else if (!controller->AT_sequence_timer) |
| | 1018 | { |
| | 1019 | GetKeyFrameOffset(sequence_ptr->first_frame,&this_section_data->target_offset); |
| | 1020 | CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient,&this_section_data->target_quat); |
| | 1021 | } |
| | 1022 | else |
| | 1023 | { |
| | 1024 | KEYFRAME_DATA *next_frame; |
| | 1025 | KEYFRAME_DATA *this_frame = sequence_ptr->first_frame; |
| | 1026 | int working_timer = controller->AT_sequence_timer; |
| | 1027 | assert(this_frame); |
| | 1028 | |
| | 1029 | while (1) |
| | 1030 | { |
| | 1031 | if (this_frame->last_frame) |
| | 1032 | next_frame = sequence_ptr->first_frame; /* Low framerate loop? */ |
| | 1033 | else |
| | 1034 | next_frame = this_frame->Next_Frame; |
| | 1035 | |
| | 1036 | if (working_timer >= this_frame->Sequence_Length) |
| | 1037 | { |
| | 1038 | /* We've gone beyond this frame: get next keyframe. */ |
| | 1039 | working_timer -= this_frame->Sequence_Length; |
| | 1040 | /* Advance frame... */ |
| | 1041 | this_frame = next_frame; |
| | 1042 | } |
| | 1043 | else |
| | 1044 | { |
| | 1045 | break; /* Exit loop with success. */ |
| | 1046 | } |
| | 1047 | /* Better make sure the last 'frame' has 65536 length... */ |
| | 1048 | } |
| | 1049 | |
| | 1050 | assert(working_timer >= 0); |
| | 1051 | /* Now we should have a frame and a timer. */ |
| | 1052 | |
| | 1053 | int lerp = MUL_FIXED(working_timer,this_frame->oneoversequencelength); |
| | 1054 | |
| | 1055 | GetKeyFrameOffset(this_frame,&this_section_data->target_offset); |
| | 1056 | |
| | 1057 | if(next_frame->shift_offset) |
| | 1058 | { |
| | 1059 | VECTORCH next_offset; |
| | 1060 | GetKeyFrameOffset(next_frame,&next_offset); |
| | 1061 | this_section_data->target_offset.vx += MUL_FIXED(next_offset.vx - this_section_data->target_offset.vx,lerp); |
| | 1062 | this_section_data->target_offset.vy += MUL_FIXED(next_offset.vy - this_section_data->target_offset.vy,lerp); |
| | 1063 | this_section_data->target_offset.vz += MUL_FIXED(next_offset.vz - this_section_data->target_offset.vz,lerp); |
| | 1064 | } |
| | 1065 | else |
| | 1066 | { |
| | 1067 | this_section_data->target_offset.vx += MUL_FIXED((int)next_frame->Offset_x - this_section_data->target_offset.vx,lerp); |
| | 1068 | this_section_data->target_offset.vy += MUL_FIXED((int)next_frame->Offset_y - this_section_data->target_offset.vy,lerp); |
| | 1069 | this_section_data->target_offset.vz += MUL_FIXED((int)next_frame->Offset_z - this_section_data->target_offset.vz,lerp); |
| | 1070 | } |
| | 1071 | |
| | 1072 | /* Now deal with orientation. */ |
| | 1073 | |
| | 1074 | Slerp(this_frame,lerp,&this_section_data->target_quat); |
| | 1075 | } |
| | 1076 | |
| | 1077 | if (elevation) |
| | 1078 | { |
| | 1079 | /* Elevation gone! Now deltas? */ |
| | 1080 | DELTA_CONTROLLER *dcon = controller->Deltas; |
| | 1081 | |
| | 1082 | while (dcon) |
| | 1083 | { |
| | 1084 | if (dcon->Active) |
| | 1085 | { |
| | 1086 | QUAT elevation_quat,temp_quat; |
| | 1087 | VECTORCH elevation_offset; |
| | 1088 | Process_Delta_Controller(this_section_data,dcon,&elevation_offset,&elevation_quat); |
| | 1089 | this_section_data->target_offset.vx += elevation_offset.vx; |
| | 1090 | this_section_data->target_offset.vy += elevation_offset.vy; |
| | 1091 | this_section_data->target_offset.vz += elevation_offset.vz; |
| | 1092 | |
| | 1093 | temp_quat.quatw = this_section_data->target_quat.quatw; |
| | 1094 | temp_quat.quatx = this_section_data->target_quat.quatx; |
| | 1095 | temp_quat.quaty = this_section_data->target_quat.quaty; |
| | 1096 | temp_quat.quatz = this_section_data->target_quat.quatz; |
| | 1097 | |
| | 1098 | MulQuat(&elevation_quat,&temp_quat,&this_section_data->target_quat); |
| | 1099 | } |
| | 1100 | |
| | 1101 | dcon = dcon->next_controller; |
| | 1102 | } |
| | 1103 | } |
| | 1104 | |
| | 1105 | /* Now recompute values. */ |
| | 1106 | |
| | 1107 | this_section_data->delta_offset.vx = this_section_data->target_offset.vx-this_section_data->stored_offset.vx; |
| | 1108 | this_section_data->delta_offset.vy = this_section_data->target_offset.vy-this_section_data->stored_offset.vy; |
| | 1109 | this_section_data->delta_offset.vz = this_section_data->target_offset.vz-this_section_data->stored_offset.vz; |
| | 1110 | |
| | 1111 | { |
| | 1112 | QUAT *this_quat = &this_section_data->stored_quat; |
| | 1113 | QUAT *next_quat = &this_section_data->target_quat; |
| | 1114 | int cosom = QDot(this_quat, next_quat); |
| | 1115 | |
| | 1116 | if (cosom < 0) |
| | 1117 | { |
| | 1118 | next_quat->quatx = -next_quat->quatx; |
| | 1119 | next_quat->quaty = -next_quat->quaty; |
| | 1120 | next_quat->quatz = -next_quat->quatz; |
| | 1121 | next_quat->quatw = -next_quat->quatw; |
| | 1122 | cosom = -cosom; |
| | 1123 | } |
| | 1124 | |
| | 1125 | this_section_data->omega = ArcCos(cosom); |
| | 1126 | |
| | 1127 | if (GetSin(this_section_data->omega)) |
| | 1128 | { |
| | 1129 | this_section_data->oneoversinomega = GetOneOverSin(this_section_data->omega); |
| | 1130 | } |
| | 1131 | else |
| | 1132 | { |
| | 1133 | /* Yuk. */ |
| | 1134 | this_section_data->omega = 0; |
| | 1135 | this_section_data->oneoversinomega = 0; |
| | 1136 | } |
| | 1137 | } |
| | 1138 | } |
| | 1139 | |
| | 1140 | static void Slerp2(SECTION_DATA *input,int lerp,QUAT *output) |
| | 1141 | { |
| | 1142 | /* Just a different input structure. */ |
| | 1143 | /* First check for special case. */ |
| | 1144 | |
| | 1145 | assert(lerp >= 0); |
| | 1146 | assert(lerp < 65536); |
| | 1147 | |
| | 1148 | if (input->omega == 2048) |
| | 1149 | { |
| | 1150 | output->quatx = -input->stored_quat.quaty; |
| | 1151 | output->quaty = input->stored_quat.quatx; |
| | 1152 | output->quatz = -input->stored_quat.quatw; |
| | 1153 | output->quatw = input->stored_quat.quatz; |
| | 1154 | |
| | 1155 | int t1 = MUL_FIXED((ONE_FIXED-lerp),1024); |
| | 1156 | int sclp = GetSin(t1); |
| | 1157 | |
| | 1158 | int t2 = MUL_FIXED(lerp,1024); |
| | 1159 | int sclq = GetSin(t2); |
| | 1160 | |
| | 1161 | output->quatx = (MUL_FIXED(input->stored_quat.quatx,sclp))+(MUL_FIXED(output->quatx,sclq)); |
| | 1162 | output->quaty = (MUL_FIXED(input->stored_quat.quaty,sclp))+(MUL_FIXED(output->quaty,sclq)); |
| | 1163 | output->quatz = (MUL_FIXED(input->stored_quat.quatz,sclp))+(MUL_FIXED(output->quatz,sclq)); |
| | 1164 | output->quatw = (MUL_FIXED(input->stored_quat.quatw,sclp))+(MUL_FIXED(output->quatw,sclq)); |
| | 1165 | } |
| | 1166 | else |
| | 1167 | { |
| | 1168 | int sclp,sclq; |
| | 1169 | |
| | 1170 | if ( !input->omega && !input->oneoversinomega) |
| | 1171 | { |
| | 1172 | sclp = ONE_FIXED - lerp; |
| | 1173 | sclq = lerp; |
| | 1174 | } |
| | 1175 | else |
| | 1176 | { |
| | 1177 | int t1 = MUL_FIXED((ONE_FIXED-lerp),input->omega); |
| | 1178 | int t2 = GetSin(t1); |
| | 1179 | sclp = MUL_FIXED(t2,input->oneoversinomega); |
| | 1180 | |
| | 1181 | t1 = MUL_FIXED(lerp,input->omega); |
| | 1182 | t2 = GetSin(t1); |
| | 1183 | sclq = MUL_FIXED(t2,input->oneoversinomega); |
| | 1184 | } |
| | 1185 | |
| | 1186 | output->quatx = (MUL_FIXED(input->stored_quat.quatx,sclp))+(MUL_FIXED(input->target_quat.quatx,sclq)); |
| | 1187 | output->quaty = (MUL_FIXED(input->stored_quat.quaty,sclp))+(MUL_FIXED(input->target_quat.quaty,sclq)); |
| | 1188 | output->quatz = (MUL_FIXED(input->stored_quat.quatz,sclp))+(MUL_FIXED(input->target_quat.quatz,sclq)); |
| | 1189 | output->quatw = (MUL_FIXED(input->stored_quat.quatw,sclp))+(MUL_FIXED(input->target_quat.quatw,sclq)); |
| | 1190 | } |
| | 1191 | |
| | 1192 | QNormalise(output); |
| | 1193 | } |
| | 1194 | |
| | 1195 | static void Analyse_Tweening_Data(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int base_timer,VECTORCH *output_offset,MATRIXCH *output_matrix) |
| | 1196 | { |
| | 1197 | QUAT output_quat; |
| | 1198 | |
| | 1199 | /* Go go gadget tweening. */ |
| | 1200 | /* There is only one frame. */ |
| | 1201 | |
| | 1202 | int working_timer = base_timer; |
| | 1203 | /* Tests: can't be too careful. */ |
| | 1204 | |
| | 1205 | if (working_timer >= 65536) |
| | 1206 | working_timer = 65535; |
| | 1207 | else if (working_timer < 0) |
| | 1208 | working_timer = 0; |
| | 1209 | |
| | 1210 | /* Now, a lot like the old way, but we shouldn't need to loop more than once. */ |
| | 1211 | /* If we do, we have a game framerate slower than the anim framerate. */ |
| | 1212 | |
| | 1213 | if (controller->Deltas) |
| | 1214 | { |
| | 1215 | /* Resnap with elevation. */ |
| | 1216 | ReSnap(controller,this_section_data,1); |
| | 1217 | |
| | 1218 | controller->ElevationTweening = 1; |
| | 1219 | } |
| | 1220 | else if (controller->ElevationTweening) |
| | 1221 | { |
| | 1222 | /* It's all messed up now. 'Resnap' WITHOUT elevation. */ |
| | 1223 | |
| | 1224 | ReSnap(controller,this_section_data,0); |
| | 1225 | |
| | 1226 | controller->ElevationTweening = 0; |
| | 1227 | } |
| | 1228 | |
| | 1229 | /* Now, this_frame and next_frame are set, and working_timer<this_frame->Sequence_Length. */ |
| | 1230 | |
| | 1231 | output_offset->vx = (MUL_FIXED(this_section_data->delta_offset.vx, working_timer)) + this_section_data->stored_offset.vx; |
| | 1232 | output_offset->vy = (MUL_FIXED(this_section_data->delta_offset.vy, working_timer)) + this_section_data->stored_offset.vy; |
| | 1233 | output_offset->vz = (MUL_FIXED(this_section_data->delta_offset.vz, working_timer)) + this_section_data->stored_offset.vz; |
| | 1234 | |
| | 1235 | /* Now deal with orientation. */ |
| | 1236 | |
| | 1237 | int lerp = working_timer; |
| | 1238 | |
| | 1239 | Slerp2(this_section_data,lerp,&output_quat); |
| | 1240 | |
| | 1241 | /* NO elevation! */ |
| | 1242 | |
| | 1243 | QuatToMat(&output_quat,output_matrix); |
| | 1244 | |
| | 1245 | /* Just to make sure. */ |
| | 1246 | MNormalise(output_matrix); |
| | 1247 | } |
| | 1248 | |
| | 1249 | #include "npc_marine.h" |
| | 1250 | #include "corpse.h" |
| | 1251 | #include "pldghost.h" |
| | 1252 | #include "weaponbehaviour.h" |
| | 1253 | |
| | 1254 | enum PARTICLE_ID GetBloodType(STRATEGYBLOCK *sbPtr) |
| | 1255 | { |
| | 1256 | if (sbPtr == NULL) |
| | 1257 | return PARTICLE_NULL; |
| | 1258 | |
| | 1259 | switch (sbPtr->type) |
| | 1260 | { |
| | 1261 | case I_BehaviourHierarchicalFragment: |
| | 1262 | { |
| | 1263 | HDEBRIS_BEHAV_BLOCK *debrisStatusPointer = (HDEBRIS_BEHAV_BLOCK *)(sbPtr->dataptr); |
| | 1264 | assert(debrisStatusPointer); |
| | 1265 | |
| | 1266 | switch (debrisStatusPointer->Type) |
| | 1267 | { |
| | 1268 | case I_BehaviourMarine: |
| | 1269 | case I_BehaviourMarinePlayer: |
| | 1270 | return (debrisStatusPointer->Android) ? PARTICLE_ANDROID_BLOOD : PARTICLE_HUMAN_BLOOD; |
| | 1271 | case I_BehaviourAlien: |
| | 1272 | case I_BehaviourAlienPlayer: |
| | 1273 | case I_BehaviourQueenAlien: |
| | 1274 | return PARTICLE_ALIEN_BLOOD; |
| | 1275 | case I_BehaviourPredator: |
| | 1276 | case I_BehaviourPredatorPlayer: |
| | 1277 | return PARTICLE_PREDATOR_BLOOD; |
| | 1278 | case I_BehaviourXenoborg: |
| | 1279 | case I_BehaviourAutoGun: |
| | 1280 | return PARTICLE_SPARK; |
| | 1281 | default: |
| | 1282 | return PARTICLE_NULL; |
| | 1283 | } |
| | 1284 | } |
| | 1285 | case I_BehaviourAlien: |
| | 1286 | case I_BehaviourQueenAlien: |
| | 1287 | return PARTICLE_ALIEN_BLOOD; |
| | 1288 | case I_BehaviourMarine: |
| | 1289 | { |
| | 1290 | MARINE_STATUS_BLOCK *marineStatusPointer = (MARINE_STATUS_BLOCK *)(sbPtr->dataptr); |
| | 1291 | assert(marineStatusPointer); |
| | 1292 | |
| | 1293 | return (marineStatusPointer->Android) ? PARTICLE_ANDROID_BLOOD : PARTICLE_HUMAN_BLOOD; |
| | 1294 | } |
| | 1295 | case I_BehaviourPredator: |
| | 1296 | return PARTICLE_PREDATOR_BLOOD; |
| | 1297 | case I_BehaviourXenoborg: |
| | 1298 | case I_BehaviourAutoGun: |
| | 1299 | return PARTICLE_SPARK; |
| | 1300 | case I_BehaviourCorpse: |
| | 1301 | { |
| | 1302 | CORPSEDATABLOCK *corpseDataPtr = (CORPSEDATABLOCK *)sbPtr->dataptr; |
| | 1303 | assert(corpseDataPtr); |
| | 1304 | |
| | 1305 | switch (corpseDataPtr->Type) |
| | 1306 | { |
| | 1307 | case I_BehaviourMarinePlayer: |
| | 1308 | case I_BehaviourMarine: |
| | 1309 | return (corpseDataPtr->Android) ? PARTICLE_ANDROID_BLOOD : PARTICLE_HUMAN_BLOOD; |
| | 1310 | case I_BehaviourAlienPlayer: |
| | 1311 | case I_BehaviourAlien: |
| | 1312 | case I_BehaviourQueenAlien: |
| | 1313 | return PARTICLE_ALIEN_BLOOD; |
| | 1314 | case I_BehaviourPredatorPlayer: |
| | 1315 | case I_BehaviourPredator: |
| | 1316 | return PARTICLE_PREDATOR_BLOOD; |
| | 1317 | case I_BehaviourXenoborg: |
| | 1318 | case I_BehaviourAutoGun: |
| | 1319 | return PARTICLE_SPARK; |
| | 1320 | default: |
| | 1321 | return PARTICLE_NULL; |
| | 1322 | } |
| | 1323 | } |
| | 1324 | case I_BehaviourNetGhost: |
| | 1325 | { |
| | 1326 | NETGHOSTDATABLOCK *corpseDataPtr = sbPtr->dataptr; |
| | 1327 | |
| | 1328 | switch (corpseDataPtr->type) |
| | 1329 | { |
| | 1330 | default: |
| | 1331 | return PARTICLE_NULL; |
| | 1332 | case I_BehaviourMarinePlayer: |
| | 1333 | case I_BehaviourMarine: |
| | 1334 | /* Add an Android test here? */ |
| | 1335 | return PARTICLE_HUMAN_BLOOD; |
| | 1336 | case I_BehaviourAlienPlayer: |
| | 1337 | case I_BehaviourAlien: |
| | 1338 | case I_BehaviourQueenAlien: |
| | 1339 | return PARTICLE_ALIEN_BLOOD; |
| | 1340 | case I_BehaviourPredatorPlayer: |
| | 1341 | case I_BehaviourPredator: |
| | 1342 | return PARTICLE_PREDATOR_BLOOD; |
| | 1343 | case I_BehaviourXenoborg: |
| | 1344 | case I_BehaviourAutoGun: |
| | 1345 | return PARTICLE_SPARK; |
| | 1346 | case I_BehaviourCorpse: |
| | 1347 | switch (corpseDataPtr->subtype) |
| | 1348 | { |
| | 1349 | case I_BehaviourMarinePlayer: |
| | 1350 | case I_BehaviourMarine: |
| | 1351 | /* Add an Android test here? */ |
| | 1352 | return PARTICLE_HUMAN_BLOOD; |
| | 1353 | case I_BehaviourAlienPlayer: |
| | 1354 | case I_BehaviourAlien: |
| | 1355 | case I_BehaviourQueenAlien: |
| | 1356 | return PARTICLE_ALIEN_BLOOD; |
| | 1357 | case I_BehaviourPredatorPlayer: |
| | 1358 | case I_BehaviourPredator: |
| | 1359 | return PARTICLE_PREDATOR_BLOOD; |
| | 1360 | case I_BehaviourXenoborg: |
| | 1361 | case I_BehaviourAutoGun: |
| | 1362 | return PARTICLE_SPARK; |
| | 1363 | default: |
| | 1364 | return PARTICLE_NULL; |
| | 1365 | } |
| | 1366 | } |
| | 1367 | } |
| | 1368 | case I_BehaviourSpeargunBolt: |
| | 1369 | { |
| | 1370 | SPEAR_BEHAV_BLOCK *debrisStatusPointer = (SPEAR_BEHAV_BLOCK *)(sbPtr->dataptr); |
| | 1371 | assert(debrisStatusPointer); |
| | 1372 | |
| | 1373 | return (debrisStatusPointer->Android) ? PARTICLE_ANDROID_BLOOD : PARTICLE_HUMAN_BLOOD; |
| | 1374 | } |
| | 1375 | default: |
| | 1376 | return PARTICLE_NULL; |
| | 1377 | } |
| | 1378 | } |
| | 1379 | |
| | 1380 | static void Process_Section(HMODELCONTROLLER *controller, SECTION_DATA *this_section_data, |
| | 1381 | const VECTORCH *parent_position, const MATRIXCH *parent_orientation, int frame_timer, const int sequence_type, const int subsequence, const int render) |
| | 1382 | { |
| | 1383 | VECTORCH diagnostic_vector = { 0, 0, 0}; |
| | 1384 | |
| | 1385 | /* Work out which SECTION to use. */ |
| | 1386 | const SECTION *this_section = this_section_data->sempai; |
| | 1387 | |
| | 1388 | if (controller != this_section_data->my_controller) |
| | 1389 | { |
| | 1390 | printf("Wrong Controller assert in PROCESS_SECTION.w\n"); |
| | 1391 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 1392 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 1393 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 1394 | printf("Tweening flags %d\n",controller->Tweening); |
| | 1395 | assert(controller == this_section_data->my_controller); |
| | 1396 | } |
| | 1397 | |
| | 1398 | /* We can't just stop at a terminate_here, because that will |
| | 1399 | do over the section_data list. */ |
| | 1400 | |
| | 1401 | /* Well, actually, now we can. */ |
| | 1402 | |
| | 1403 | /* Put in a sequence switcher!!! */ |
| | 1404 | |
| | 1405 | /* There now is one. */ |
| | 1406 | |
| | 1407 | /* Quick auto-correction... */ |
| | 1408 | |
| | 1409 | if (frame_timer < 0) |
| | 1410 | frame_timer = 0; |
| | 1411 | else if (frame_timer >= 65536) |
| | 1412 | frame_timer = 65535; |
| | 1413 | |
| | 1414 | if ((controller->FrameStamp != GlobalFrameCounter) || !(this_section_data->flags & section_data_initialised)) |
| | 1415 | { |
| | 1416 | /* Positions not computed yet this frame. */ |
| | 1417 | |
| | 1418 | SEQUENCE *this_sequence = GetSequencePointer(sequence_type,subsequence,this_section); |
| | 1419 | KEYFRAME_DATA *sequence_start = this_sequence->first_frame; |
| | 1420 | int fake_frame_timer = (controller->LockTopSection && (this_section_data == controller->section_data)) ? 0 : frame_timer; |
| | 1421 | |
| | 1422 | /* For this section, find the interpolated offset and eulers. */ |
| | 1423 | this_section_data->Last_World_Offset = this_section_data->World_Offset; |
| | 1424 | |
| | 1425 | if (this_section_data->Tweening) |
| | 1426 | Analyse_Tweening_Data(controller, this_section_data, frame_timer, &this_section_data->World_Offset, &this_section_data->RelSecMat); |
| | 1427 | else |
| | 1428 | New_Analyse_Keyframe_Data(controller, this_section_data, sequence_start, fake_frame_timer, &this_section_data->World_Offset,
&this_section_data->RelSecMat); |
| | 1429 | |
| | 1430 | if (controller->ZeroRootDisplacement && (this_section_data == controller->section_data)) |
| | 1431 | this_section_data->World_Offset.vx = this_section_data->World_Offset.vy = this_section_data->World_Offset.vz = 0; |
| | 1432 | |
| | 1433 | if (controller->ZeroRootRotation && (this_section_data == controller->section_data)) |
| | 1434 | this_section_data->RelSecMat = IdentityMatrix; |
| | 1435 | |
| | 1436 | this_section_data->Offset = this_section_data->World_Offset; |
| | 1437 | |
| | 1438 | diagnostic_vector = this_section_data->World_Offset; |
| | 1439 | |
| | 1440 | /* The parent's position will be used with the offset value and rotation |
| | 1441 | matrix to determine the position of the new section. */ |
| | 1442 | |
| | 1443 | RotateVector(&this_section_data->World_Offset, parent_orientation); |
| | 1444 | |
| | 1445 | this_section_data->World_Offset.vx += parent_position->vx; |
| | 1446 | this_section_data->World_Offset.vy += parent_position->vy; |
| | 1447 | this_section_data->World_Offset.vz += parent_position->vz; |
| | 1448 | |
| | 1449 | /* Create the absolute rotation matrix for this section. */ |
| | 1450 | MatrixMultiply(parent_orientation, &this_section_data->RelSecMat, &this_section_data->SecMat); |
| | 1451 | |
| | 1452 | /* Set the initialised flag... */ |
| | 1453 | this_section_data->flags |= section_data_initialised; |
| | 1454 | } |
| | 1455 | |
| | 1456 | /* Check the object is in a sensible place. */ |
| | 1457 | if ( !( (this_section_data->World_Offset.vx < 1000000 && this_section_data->World_Offset.vx > -1000000) |
| | 1458 | && (this_section_data->World_Offset.vy < 1000000 && this_section_data->World_Offset.vy > -1000000) |
| | 1459 | && (this_section_data->World_Offset.vz < 1000000 && this_section_data->World_Offset.vz > -1000000) ) ) |
| | 1460 | { |
| | 1461 | printf("Tests in PROCESS_SECTION.\n"); |
| | 1462 | |
| | 1463 | if (Global_HModel_Sptr) |
| | 1464 | { |
| | 1465 | printf("Misplaced object is of type %d\n", Global_HModel_Sptr->type); |
| | 1466 | |
| | 1467 | if (Global_HModel_Sptr->DisplayBlock) |
| | 1468 | printf("Object is Near.\n"); |
| | 1469 | else |
| | 1470 | printf("Object is Far.\n"); |
| | 1471 | } |
| | 1472 | else |
| | 1473 | { |
| | 1474 | printf("Misplaced object has no SBptr.\n"); |
| | 1475 | } |
| | 1476 | |
| | 1477 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 1478 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 1479 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 1480 | printf("Tweening flags %d\n",controller->Tweening); |
| | 1481 | printf("Diagnostic Vector %d,%d,%d\n",diagnostic_vector.vx,diagnostic_vector.vy,diagnostic_vector.vz); |
| | 1482 | printf("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat11,parent_orientation->mat12,parent_orientation->mat13); |
| | 1483 | printf("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat21,parent_orientation->mat22,parent_orientation->mat23); |
| | 1484 | printf("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat31,parent_orientation->mat32,parent_orientation->mat33); |
| | 1485 | printf("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz); |
| | 1486 | printf("This Position
%d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz); |
| | 1487 | |
| | 1488 | assert(this_section_data->World_Offset.vx < 1000000 && this_section_data->World_Offset.vx > -1000000); |
| | 1489 | assert(this_section_data->World_Offset.vy < 1000000 && this_section_data->World_Offset.vy > -1000000); |
| | 1490 | assert(this_section_data->World_Offset.vz < 1000000 && this_section_data->World_Offset.vz > -1000000); |
| | 1491 | } |
| | 1492 | |
| | 1493 | /* Now call recursion... */ |
| | 1494 | |
| | 1495 | if ((this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 1496 | { |
| | 1497 | SECTION_DATA *child_ptr = this_section_data->First_Child; |
| | 1498 | |
| | 1499 | while (child_ptr != NULL) |
| | 1500 | { |
| | 1501 | assert(child_ptr->My_Parent == this_section_data); |
| | 1502 | Process_Section(controller, child_ptr, &this_section_data->World_Offset, &this_section_data->SecMat, frame_timer, sequence_type,
subsequence, render); |
| | 1503 | child_ptr = child_ptr->Next_Sibling; |
| | 1504 | } |
| | 1505 | } |
| | 1506 | |
| | 1507 | /* Finally, if this section has a shape, and we are rendering, render it. */ |
| | 1508 | |
| | 1509 | if ((this_section_data->Shape != NULL) && !(this_section_data->flags & section_data_notreal) && render) |
| | 1510 | { |
| | 1511 | extern const DISPLAYBLOCK Zero_Displayblock; |
| | 1512 | /* Unreal things don't get plotted, either. */ |
| | 1513 | |
| | 1514 | DISPLAYBLOCK dummy_displayblock = Zero_Displayblock; |
| | 1515 | |
| | 1516 | assert(this_section_data->ShapeNum); |
| | 1517 | |
| | 1518 | /* Decide what shape to use. */ |
| | 1519 | |
| | 1520 | struct shapeheader* shape_to_use = NULL; |
| | 1521 | |
| | 1522 | if (this_section_data->Shape) |
| | 1523 | { |
| | 1524 | if (this_section_data->Shape->shape_degradation_array == NULL) |
| | 1525 | shape_to_use = this_section_data->Shape; |
| | 1526 | else |
| | 1527 | shape_to_use = Get_Degraded_Shape(this_section_data->Shape); |
| | 1528 | |
| | 1529 | dummy_displayblock.extent.radius = shape_to_use->shaperadius; |
| | 1530 | } |
| | 1531 | |
| | 1532 | if (Simplify_HModel_Rendering) |
| | 1533 | { |
| | 1534 | dummy_displayblock.ObShape = GetLoadedShapeMSL("Shell"); |
| | 1535 | dummy_displayblock.ShapeData = GetShapeData(dummy_displayblock.ObShape); |
| | 1536 | } |
| | 1537 | else |
| | 1538 | { |
| | 1539 | dummy_displayblock.ObShape = this_section_data->ShapeNum; |
| | 1540 | dummy_displayblock.ShapeData = shape_to_use; |
| | 1541 | } |
| | 1542 | |
| | 1543 | dummy_displayblock.ObWorld = this_section_data->World_Offset; |
| | 1544 | dummy_displayblock.ObMat = this_section_data->SecMat; |
| | 1545 | dummy_displayblock.ObFlags = 0; |
| | 1546 | dummy_displayblock.ObFlags2 = Global_HModel_DispPtr->ObFlags2; |
| | 1547 | dummy_displayblock.ObTxAnimCtrlBlks = this_section_data->tac_ptr; |
| | 1548 | dummy_displayblock.ObStrategyBlock = Global_HModel_Sptr; |
| | 1549 | dummy_displayblock.SpecialFXFlags = Global_HModel_DispPtr->SpecialFXFlags; |
| | 1550 | |
| | 1551 | dummy_displayblock.ObView.vx = dummy_displayblock.ObWorld.vx - Global_VDB.VDB_World.vx; |
| | 1552 | dummy_displayblock.ObView.vy = dummy_displayblock.ObWorld.vy - Global_VDB.VDB_World.vy; |
| | 1553 | dummy_displayblock.ObView.vz = dummy_displayblock.ObWorld.vz - Global_VDB.VDB_World.vz; |
| | 1554 | |
| | 1555 | RotateVector(&dummy_displayblock.ObView, &Global_VDB.VDB_Mat); |
| | 1556 | |
| | 1557 | /* Whilst we're here... */ |
| | 1558 | |
| | 1559 | this_section_data->View_Offset = dummy_displayblock.ObView; |
| | 1560 | this_section_data->flags |= section_data_view_init; |
| | 1561 | controller->View_FrameStamp = GlobalFrameCounter; |
| | 1562 | |
| | 1563 | if(this_section->flags & (section_flag_heatsource | section_flag_affectedbyheat)) |
| | 1564 | dummy_displayblock.SpecialFXFlags |= SFXFLAG_ISAFFECTEDBYHEAT; |
| | 1565 | |
| | 1566 | if(CHEATMODE_PIPECLEANER == UserProfile.active_bonus) |
| | 1567 | { |
| | 1568 | if ( (Global_HModel_Sptr && Global_HModel_Sptr->DisplayBlock) |
| | 1569 | && (!((Global_HModel_Sptr->DisplayBlock->ObWorld.vx == parent_position->vx) |
| | 1570 | && (Global_HModel_Sptr->DisplayBlock->ObWorld.vy == parent_position->vy) |
| | 1571 | && (Global_HModel_Sptr->DisplayBlock->ObWorld.vz == parent_position->vz)))) |
| | 1572 | { |
| | 1573 | PARTICLE particle; |
| | 1574 | |
| | 1575 | particle.Colour = 0xffffffff; |
| | 1576 | particle.Size = 30; |
| | 1577 | |
| | 1578 | particle.ParticleID = PARTICLE_LASERBEAM; |
| | 1579 | particle.Position = this_section_data->World_Offset; |
| | 1580 | particle.Offset = *parent_position;; |
| | 1581 | |
| | 1582 | DecalSystem_Setup(); |
| | 1583 | RenderParticle(&particle); |
| | 1584 | |
| | 1585 | particle.ParticleID = PARTICLE_ANDROID_BLOOD; |
| | 1586 | |
| | 1587 | particle.Size = dummy_displayblock.extent.radius / 8; |
| | 1588 | RenderParticle(&particle); |
| | 1589 | DecalSystem_End(); |
| | 1590 | } |
| | 1591 | } |
| | 1592 | |
| | 1593 | RenderThisHierarchicalDisplayblock(&dummy_displayblock); |
| | 1594 | } |
| | 1595 | else if (controller->View_FrameStamp != GlobalFrameCounter) |
| | 1596 | { |
| | 1597 | this_section_data->flags &= (~section_data_view_init); |
| | 1598 | } |
| | 1599 | |
| | 1600 | /* Gore spray... */ |
| | 1601 | |
| | 1602 | if (controller->DisableBleeding || (NumberOfBloodParticles >= UserProfile.GameOptions.BloodParticles)) |
| | 1603 | return; |
| | 1604 | |
| | 1605 | int Use_GoreRate = (CHEATMODE_SUPERGORE == UserProfile.active_bonus) ? GlobalGoreRate/5 : GlobalGoreRate; |
| | 1606 | |
| | 1607 | /* A terminator must spray (backwards) from the origin, to be the stump. */ |
| | 1608 | |
| | 1609 | if (this_section_data->current_damage.Health < (this_section->StartingStats.Health << ONE_FIXED_SHIFT)) |
| | 1610 | { |
| | 1611 | if (this_section->flags & section_sprays_anything) |
| | 1612 | { |
| | 1613 | /* Bleed a lot. Or Just bleed a bit. */ |
| | 1614 | int bleeding_rate = (!this_section_data->current_damage.Health) ? Use_GoreRate : (Use_GoreRate << 1); |
| | 1615 | |
| | 1616 | /* Don't care about non-zero spray direction here. */ |
| | 1617 | |
| | 1618 | this_section_data->gore_timer += NormalFrameTime; |
| | 1619 | |
| | 1620 | /* I don't *think* a section can be both... */ |
| | 1621 | /* But if it is, we'll just have to live with it. */ |
| | 1622 | |
| | 1623 | /* New and Special Sparks Code! 16/7/98 */ |
| | 1624 | |
| | 1625 | if (this_section->flags & section_sprays_sparks) |
| | 1626 | { |
| | 1627 | while (this_section_data->gore_timer > (bleeding_rate * SPARKS_FOR_A_SPRAY)) |
| | 1628 | { |
| | 1629 | VECTORCH final_spray_direction = {0,0,0}; |
| | 1630 | MATRIXCH spray_orient; |
| | 1631 | |
| | 1632 | /* Spray is go! */ |
| | 1633 | |
| | 1634 | /* Add random element. */ |
| | 1635 | |
| | 1636 | while ( !final_spray_direction.vx && !final_spray_direction.vy && !final_spray_direction.vz) |
| | 1637 | { |
| | 1638 | final_spray_direction.vx += ( (FastRandom() & 1023) -512); |
| | 1639 | final_spray_direction.vy += ( (FastRandom() & 1023) -512); |
| | 1640 | final_spray_direction.vz += ( (FastRandom() & 1023) -512); |
| | 1641 | } |
| | 1642 | |
| | 1643 | Normalise(&final_spray_direction); |
| | 1644 | |
| | 1645 | /* Now convert back to a matrix. */ |
| | 1646 | MakeMatrixFromDirection(&final_spray_direction, &spray_orient); |
| | 1647 | |
| | 1648 | /* Call spray function. */ |
| | 1649 | |
| | 1650 | MakeSprayOfSparks(&spray_orient, &this_section_data->World_Offset); |
| | 1651 | |
| | 1652 | Sound_Play(SID_SPARKS, "d", &this_section_data->World_Offset); |
| | 1653 | |
| | 1654 | this_section_data->gore_timer -= (bleeding_rate * SPARKS_FOR_A_SPRAY); |
| | 1655 | } |
| | 1656 | |
| | 1657 | assert(this_section_data->gore_timer <= (bleeding_rate*SPARKS_FOR_A_SPRAY)); |
| | 1658 | } |
| | 1659 | else |
| | 1660 | { |
| | 1661 | while (this_section_data->gore_timer > bleeding_rate) |
| | 1662 | { |
| | 1663 | enum PARTICLE_ID blood_type; |
| | 1664 | VECTORCH final_spray_direction = {0,0,0}; |
| | 1665 | /* Spray is go! */ |
| | 1666 | |
| | 1667 | /* Add random element. */ |
| | 1668 | |
| | 1669 | final_spray_direction.vx += ( (FastRandom() & 1023) -512); |
| | 1670 | final_spray_direction.vy += ( (FastRandom() & 1023) -512); |
| | 1671 | final_spray_direction.vz += ( (FastRandom() & 1023) -512); |
| | 1672 | |
| | 1673 | /* Identify spray type. */ |
| | 1674 | |
| | 1675 | if (this_section->flags & section_sprays_blood) |
| | 1676 | { |
| | 1677 | blood_type = GetBloodType(Global_HModel_Sptr); |
| | 1678 | /* Er... default? */ |
| | 1679 | } |
| | 1680 | else if (this_section->flags & section_sprays_acid) |
| | 1681 | { |
| | 1682 | blood_type = PARTICLE_ALIEN_BLOOD; |
| | 1683 | } |
| | 1684 | else if (this_section->flags & section_sprays_predoblood) |
| | 1685 | { |
| | 1686 | blood_type = PARTICLE_PREDATOR_BLOOD; |
| | 1687 | } |
| | 1688 | else if (this_section->flags & section_sprays_sparks) |
| | 1689 | { |
| | 1690 | blood_type = PARTICLE_SPARK; |
| | 1691 | } |
| | 1692 | else |
| | 1693 | { |
| | 1694 | blood_type = PARTICLE_FLAME; |
| | 1695 | /* Distinctive. */ |
| | 1696 | } |
| | 1697 | |
| | 1698 | /* Call spray function. */ |
| | 1699 | |
| | 1700 | MakeBloodParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type); |
| | 1701 | |
| | 1702 | this_section_data->gore_timer -= bleeding_rate; |
| | 1703 | } |
| | 1704 | |
| | 1705 | assert(this_section_data->gore_timer <= bleeding_rate); |
| | 1706 | } |
| | 1707 | } |
| | 1708 | } |
| | 1709 | else |
| | 1710 | return; |
| | 1711 | |
| | 1712 | if (this_section_data->flags & section_data_terminate_here) |
| | 1713 | { |
| | 1714 | if (this_section->flags & section_sprays_anything) |
| | 1715 | { |
| | 1716 | /* Check for non-zero spray direction... */ |
| | 1717 | if ( this_section->gore_spray_direction.vx || this_section->gore_spray_direction.vy || this_section->gore_spray_direction.vz) |
| | 1718 | { |
| | 1719 | this_section_data->gore_timer += NormalFrameTime; |
| | 1720 | |
| | 1721 | /* New and Special Sparks Code! 16/7/98 */ |
| | 1722 | if (this_section->flags §ion_sprays_sparks) |
| | 1723 | { |
| | 1724 | while (this_section_data->gore_timer > (GlobalGoreRate * SPARKS_FOR_A_SPRAY)) |
| | 1725 | { |
| | 1726 | VECTORCH final_spray_direction; |
| | 1727 | MATRIXCH spray_orient; |
| | 1728 | /* Spray is go! */ |
| | 1729 | |
| | 1730 | RotateAndCopyVector(&this_section->gore_spray_direction, &final_spray_direction, &this_section_data->SecMat); |
| | 1731 | |
| | 1732 | /* Reverse direction for stumps. */ |
| | 1733 | |
| | 1734 | final_spray_direction.vx = -final_spray_direction.vx; |
| | 1735 | final_spray_direction.vy = -final_spray_direction.vy; |
| | 1736 | final_spray_direction.vz = -final_spray_direction.vz; |
| | 1737 | |
| | 1738 | /* Scale down. */ |
| | 1739 | |
| | 1740 | final_spray_direction.vx >>= 5; |
| | 1741 | final_spray_direction.vy >>= 5; |
| | 1742 | final_spray_direction.vz >>= 5; |
| | 1743 | |
| | 1744 | /* Add random element. */ |
| | 1745 | |
| | 1746 | final_spray_direction.vx += ( (FastRandom() & 1023) -512); |
| | 1747 | final_spray_direction.vy += ( (FastRandom() & 1023) -512); |
| | 1748 | final_spray_direction.vz += ( (FastRandom() & 1023) -512); |
| | 1749 | |
| | 1750 | Normalise(&final_spray_direction); |
| | 1751 | /* Now convert back to a matrix. */ |
| | 1752 | MakeMatrixFromDirection(&final_spray_direction, &spray_orient); |
| | 1753 | |
| | 1754 | /* Call spray function. */ |
| | 1755 | |
| | 1756 | MakeSprayOfSparks(&spray_orient, &this_section_data->World_Offset); |
| | 1757 | |
| | 1758 | Sound_Play(SID_SPARKS, "d", &this_section_data->World_Offset); |
| | 1759 | |
| | 1760 | this_section_data->gore_timer -= (GlobalGoreRate * SPARKS_FOR_A_SPRAY); |
| | 1761 | } |
| | 1762 | |
| | 1763 | assert(this_section_data->gore_timer <= (GlobalGoreRate * SPARKS_FOR_A_SPRAY)); |
| | 1764 | } |
| | 1765 | else |
| | 1766 | { |
| | 1767 | while (this_section_data->gore_timer > Use_GoreRate) |
| | 1768 | { |
| | 1769 | VECTORCH final_spray_direction; |
| | 1770 | enum PARTICLE_ID blood_type; |
| | 1771 | /* Spray is go! */ |
| | 1772 | |
| | 1773 | RotateAndCopyVector(&this_section->gore_spray_direction, &final_spray_direction, &this_section_data->SecMat); |
| | 1774 | |
| | 1775 | /* Reverse direction for stumps. */ |
| | 1776 | |
| | 1777 | final_spray_direction.vx = -final_spray_direction.vx; |
| | 1778 | final_spray_direction.vy = -final_spray_direction.vy; |
| | 1779 | final_spray_direction.vz = -final_spray_direction.vz; |
| | 1780 | |
| | 1781 | /* Scale down. */ |
| | 1782 | |
| | 1783 | final_spray_direction.vx >>= 5; |
| | 1784 | final_spray_direction.vy >>= 5; |
| | 1785 | final_spray_direction.vz >>= 5; |
| | 1786 | |
| | 1787 | /* Add random element. */ |
| | 1788 | |
| | 1789 | final_spray_direction.vx += ( (FastRandom() & 1023) -512); |
| | 1790 | final_spray_direction.vy += ( (FastRandom() & 1023) -512); |
| | 1791 | final_spray_direction.vz += ( (FastRandom() & 1023) -512); |
| | 1792 | |
| | 1793 | if (CHEATMODE_SUPERGORE == UserProfile.active_bonus) |
| | 1794 | { |
| | 1795 | final_spray_direction.vx <<= 1; |
| | 1796 | final_spray_direction.vy <<= 1; |
| | 1797 | final_spray_direction.vz <<= 1; |
| | 1798 | } |
| | 1799 | |
| | 1800 | /* Identify spray type. */ |
| | 1801 | |
| | 1802 | if (this_section->flags & section_sprays_blood) |
| | 1803 | { |
| | 1804 | blood_type = GetBloodType(Global_HModel_Sptr); |
| | 1805 | /* Er... default? */ |
| | 1806 | } |
| | 1807 | else if (this_section->flags & section_sprays_acid) |
| | 1808 | { |
| | 1809 | blood_type = PARTICLE_ALIEN_BLOOD; |
| | 1810 | } |
| | 1811 | else if (this_section->flags & section_sprays_predoblood) |
| | 1812 | { |
| | 1813 | blood_type = PARTICLE_PREDATOR_BLOOD; |
| | 1814 | } |
| | 1815 | else if (this_section->flags & section_sprays_sparks) |
| | 1816 | { |
| | 1817 | blood_type = PARTICLE_SPARK; |
| | 1818 | } |
| | 1819 | else |
| | 1820 | { |
| | 1821 | blood_type = PARTICLE_FLAME; |
| | 1822 | /* Distinctive. */ |
| | 1823 | } |
| | 1824 | |
| | 1825 | /* Call spray function. */ |
| | 1826 | |
| | 1827 | MakeBloodParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type); |
| | 1828 | |
| | 1829 | this_section_data->gore_timer -= Use_GoreRate; |
| | 1830 | } |
| | 1831 | } |
| | 1832 | } |
| | 1833 | } |
| | 1834 | } |
| | 1835 | |
| | 1836 | /* A false root must also spray from the origin... to be the missing part. */ |
| | 1837 | |
| | 1838 | if (this_section_data->flags & section_data_false_root) |
| | 1839 | { |
| | 1840 | if (this_section->flags & section_sprays_anything) |
| | 1841 | { |
| | 1842 | /* Check for non-zero spray direction... */ |
| | 1843 | if (this_section->gore_spray_direction.vx || this_section->gore_spray_direction.vy || this_section->gore_spray_direction.vz) |
| | 1844 | { |
| | 1845 | this_section_data->gore_timer += NormalFrameTime; |
| | 1846 | |
| | 1847 | /* I don't *think* a section can be both... */ |
| | 1848 | /* But if it is, we'll just have to live with it. */ |
| | 1849 | |
| | 1850 | /* New and Special Sparks Code! 16/7/98 */ |
| | 1851 | if (this_section->flags & section_sprays_sparks) |
| | 1852 | { |
| | 1853 | while (this_section_data->gore_timer > (GlobalGoreRate * SPARKS_FOR_A_SPRAY)) |
| | 1854 | { |
| | 1855 | VECTORCH final_spray_direction; |
| | 1856 | MATRIXCH spray_orient; |
| | 1857 | |
| | 1858 | /* Spray is go! */ |
| | 1859 | |
| | 1860 | RotateAndCopyVector(&this_section->gore_spray_direction, &final_spray_direction, &this_section_data->SecMat); |
| | 1861 | |
| | 1862 | /* Scale down. */ |
| | 1863 | |
| | 1864 | final_spray_direction.vx >>= 5; |
| | 1865 | final_spray_direction.vy >>= 5; |
| | 1866 | final_spray_direction.vz >>= 5; |
| | 1867 | |
| | 1868 | /* Add random element. */ |
| | 1869 | |
| | 1870 | final_spray_direction.vx += ( (FastRandom() & 1023) -512); |
| | 1871 | final_spray_direction.vy += ( (FastRandom() & 1023) -512); |
| | 1872 | final_spray_direction.vz += ( (FastRandom() & 1023) -512); |
| | 1873 | Normalise(&final_spray_direction); |
| | 1874 | |
| | 1875 | /* Now convert back to a matrix. */ |
| | 1876 | MakeMatrixFromDirection(&final_spray_direction, &spray_orient); |
| | 1877 | |
| | 1878 | /* Call spray function. */ |
| | 1879 | |
| | 1880 | MakeSprayOfSparks(&spray_orient, &this_section_data->World_Offset); |
| | 1881 | |
| | 1882 | Sound_Play(SID_SPARKS, "d", &this_section_data->World_Offset); |
| | 1883 | |
| | 1884 | this_section_data->gore_timer -= (GlobalGoreRate * SPARKS_FOR_A_SPRAY); |
| | 1885 | } |
| | 1886 | |
| | 1887 | assert(this_section_data->gore_timer <= (GlobalGoreRate * SPARKS_FOR_A_SPRAY)); |
| | 1888 | } |
| | 1889 | else |
| | 1890 | { |
| | 1891 | while (this_section_data->gore_timer > Use_GoreRate) |
| | 1892 | { |
| | 1893 | enum PARTICLE_ID blood_type; |
| | 1894 | VECTORCH final_spray_direction; |
| | 1895 | /* Spray is go! */ |
| | 1896 | |
| | 1897 | RotateAndCopyVector(&this_section->gore_spray_direction, &final_spray_direction, &this_section_data->SecMat); |
| | 1898 | |
| | 1899 | /* Scale down. */ |
| | 1900 | |
| | 1901 | final_spray_direction.vx >>= 5; |
| | 1902 | final_spray_direction.vy >>= 5; |
| | 1903 | final_spray_direction.vz >>= 5; |
| | 1904 | |
| | 1905 | /* Add random element. */ |
| | 1906 | |
| | 1907 | final_spray_direction.vx += ( (FastRandom() & 1023) -512); |
| | 1908 | final_spray_direction.vy += ( (FastRandom() & 1023) -512); |
| | 1909 | final_spray_direction.vz += ( (FastRandom() & 1023) -512); |
| | 1910 | |
| | 1911 | if (CHEATMODE_SUPERGORE == UserProfile.active_bonus) |
| | 1912 | { |
| | 1913 | final_spray_direction.vx <<= 1; |
| | 1914 | final_spray_direction.vy <<= 1; |
| | 1915 | final_spray_direction.vz <<= 1; |
| | 1916 | } |
| | 1917 | |
| | 1918 | /* Identify spray type. */ |
| | 1919 | |
| | 1920 | if (this_section->flags & section_sprays_blood) |
| | 1921 | { |
| | 1922 | blood_type = GetBloodType(Global_HModel_Sptr); |
| | 1923 | /* Er... default? */ |
| | 1924 | } |
| | 1925 | else if (this_section->flags & section_sprays_acid) |
| | 1926 | { |
| | 1927 | blood_type = PARTICLE_ALIEN_BLOOD; |
| | 1928 | } |
| | 1929 | else if (this_section->flags & section_sprays_predoblood) |
| | 1930 | { |
| | 1931 | blood_type = PARTICLE_PREDATOR_BLOOD; |
| | 1932 | } |
| | 1933 | else if (this_section->flags & section_sprays_sparks) |
| | 1934 | { |
| | 1935 | blood_type = PARTICLE_SPARK; |
| | 1936 | } |
| | 1937 | else |
| | 1938 | { |
| | 1939 | blood_type = PARTICLE_FLAME; |
| | 1940 | /* Distinctive. */ |
| | 1941 | } |
| | 1942 | |
| | 1943 | /* Call spray function. */ |
| | 1944 | |
| | 1945 | MakeBloodParticle(&this_section_data->World_Offset, &final_spray_direction, blood_type); |
| | 1946 | |
| | 1947 | this_section_data->gore_timer -= Use_GoreRate; |
| | 1948 | } |
| | 1949 | } |
| | 1950 | } |
| | 1951 | } |
| | 1952 | } |
| | 1953 | |
| | 1954 | /* Part three... wounded section. */ |
| | 1955 | |
| | 1956 | |
| | 1957 | } |
| | 1958 | |
| | 1959 | static void Init_Sequence_Recursion(SECTION_DATA *this_section_data, int sequence_type,int subsequence, int seconds_for_sequence) |
| | 1960 | { |
| | 1961 | SEQUENCE *sequence_ptr = GetSequencePointer(sequence_type, subsequence, this_section_data->sempai); |
| | 1962 | |
| | 1963 | this_section_data->current_sequence = sequence_ptr; |
| | 1964 | this_section_data->current_keyframe = sequence_ptr->first_frame; |
| | 1965 | this_section_data->accumulated_timer = 0; |
| | 1966 | this_section_data->freezeframe_timer = -1; |
| | 1967 | this_section_data->lastframe_timer = 0; |
| | 1968 | this_section_data->gore_timer = 0; /* As good a time as any. */ |
| | 1969 | |
| | 1970 | /* Zero last world offset, just for the record. */ |
| | 1971 | this_section_data->Last_World_Offset.vx = this_section_data->Last_World_Offset.vy = this_section_data->Last_World_Offset.vz = 0; |
| | 1972 | |
| | 1973 | /* Deinit tweening. */ |
| | 1974 | |
| | 1975 | this_section_data->Tweening = 0; |
| | 1976 | |
| | 1977 | /* Keyframe and Sound Flags. */ |
| | 1978 | if(sequence_ptr->first_frame->frame_has_extended_data) |
| | 1979 | { |
| | 1980 | KEYFRAME_DATA_EXTENDED* first_frame_extended = (KEYFRAME_DATA_EXTENDED*) sequence_ptr->first_frame; |
| | 1981 | this_section_data->my_controller->keyframe_flags |= first_frame_extended->flags; |
| | 1982 | |
| | 1983 | if (first_frame_extended->sound) |
| | 1984 | { |
| | 1985 | if ((this_section_data->flags & section_data_initialised) && !this_section_data->my_controller->DisableSounds) |
| | 1986 | PlayHierarchySound(first_frame_extended->sound, &this_section_data->World_Offset); |
| | 1987 | } |
| | 1988 | } |
| | 1989 | |
| | 1990 | /* Recurse. */ |
| | 1991 | |
| | 1992 | if ( (this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 1993 | { |
| | 1994 | /* Respect the terminator! */ |
| | 1995 | |
| | 1996 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 1997 | |
| | 1998 | while (child_list_ptr != NULL) |
| | 1999 | { |
| | 2000 | Init_Sequence_Recursion(child_list_ptr,sequence_type,subsequence,seconds_for_sequence); |
| | 2001 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 2002 | } |
| | 2003 | } |
| | 2004 | } |
| | 2005 | |
| | 2006 | void HModel_ChangeSpeed(HMODELCONTROLLER *controller, int seconds_for_sequence) |
| | 2007 | { |
| | 2008 | /* Simple enough... */ |
| | 2009 | |
| | 2010 | controller->Seconds_For_Sequence = seconds_for_sequence; |
| | 2011 | controller->timer_increment = DIV_FIXED(ONE_FIXED, controller->Seconds_For_Sequence); |
| | 2012 | } |
| | 2013 | |
| | 2014 | void HModel_SetToolsRelativeSpeed(HMODELCONTROLLER *controller, int factor) |
| | 2015 | { |
| | 2016 | assert(controller); |
| | 2017 | assert(factor > 0); |
| | 2018 | /* Find the tools speed for this sequence... */ |
| | 2019 | |
| | 2020 | SEQUENCE *this_sequence = GetSequencePointer(controller->Sequence_Type, controller->Sub_Sequence, controller->Root_Section); |
| | 2021 | |
| | 2022 | int real_time = this_sequence->Time; |
| | 2023 | |
| | 2024 | if (real_time <= 0) |
| | 2025 | { |
| | 2026 | real_time = ONE_FIXED; |
| | 2027 | /* Might want to assert here? */ |
| | 2028 | } |
| | 2029 | |
| | 2030 | real_time = MUL_FIXED(real_time, factor); |
| | 2031 | HModel_ChangeSpeed(controller, real_time); |
| | 2032 | } |
| | 2033 | |
| | 2034 | void InitHModelSequence(HMODELCONTROLLER *controller, int sequence_type, int subsequence, int seconds_for_sequence) |
| | 2035 | { |
| | 2036 | int real_time; |
| | 2037 | |
| | 2038 | assert(controller); |
| | 2039 | assert(seconds_for_sequence); |
| | 2040 | |
| | 2041 | /* Check this sequence exists... */ |
| | 2042 | |
| | 2043 | SEQUENCE *this_sequence = GetSequencePointer(sequence_type, subsequence, controller->Root_Section); |
| | 2044 | |
| | 2045 | if (seconds_for_sequence > 0) |
| | 2046 | { |
| | 2047 | real_time = seconds_for_sequence; |
| | 2048 | } |
| | 2049 | else |
| | 2050 | { |
| | 2051 | real_time = this_sequence->Time; |
| | 2052 | |
| | 2053 | if (real_time <= 0) |
| | 2054 | { |
| | 2055 | real_time = ONE_FIXED; |
| | 2056 | /* Might want to assert here. */ |
| | 2057 | } |
| | 2058 | } |
| | 2059 | |
| | 2060 | /* Now set it up. */ |
| | 2061 | |
| | 2062 | controller->Sequence_Type = sequence_type; |
| | 2063 | controller->Sub_Sequence = subsequence; |
| | 2064 | controller->Seconds_For_Sequence = real_time; |
| | 2065 | controller->timer_increment = DIV_FIXED(ONE_FIXED, controller->Seconds_For_Sequence); |
| | 2066 | controller->sequence_timer = 0; |
| | 2067 | controller->Playing = 1; |
| | 2068 | controller->Reversed = 0; |
| | 2069 | controller->Looped = 1; |
| | 2070 | controller->keyframe_flags = 0; |
| | 2071 | controller->After_Tweening_Sequence_Type = -1; |
| | 2072 | controller->After_Tweening_Sub_Sequence = -1; |
| | 2073 | controller->AT_seconds_for_sequence = ONE_FIXED; |
| | 2074 | controller->AT_sequence_timer = 0; |
| | 2075 | controller->Tweening = Controller_NoTweening; |
| | 2076 | |
| | 2077 | /* Recurse though hierarchy, setting up all the section_data sequence stores? */ |
| | 2078 | |
| | 2079 | Init_Sequence_Recursion(controller->section_data, sequence_type, subsequence, seconds_for_sequence); |
| | 2080 | } |
| | 2081 | |
| | 2082 | static void HMTimer_Kernel(HMODELCONTROLLER *controller) |
| | 2083 | { |
| | 2084 | /* Core of the timer code. */ |
| | 2085 | |
| | 2086 | if (controller->Tweening == Controller_EndTweening) |
| | 2087 | { |
| | 2088 | int reversed=controller->Reversed; /* Remember this! */ |
| | 2089 | int AT_sequence_timer = controller->AT_sequence_timer; /* Remember this, too! */ |
| | 2090 | |
| | 2091 | #if DEBUG |
| | 2092 | if (!controller->AT_seconds_for_sequence) |
| | 2093 | { |
| | 2094 | assert(controller->AT_seconds_for_sequence); |
| | 2095 | } |
| | 2096 | #endif |
| | 2097 | |
| | 2098 | InitHModelSequence(controller,controller->After_Tweening_Sequence_Type, |
| | 2099 | controller->After_Tweening_Sub_Sequence,controller->AT_seconds_for_sequence); |
| | 2100 | |
| | 2101 | if (reversed) |
| | 2102 | controller->Reversed = 1; |
| | 2103 | |
| | 2104 | /* This should now always be set, though InitHModelSequence zeros it (D'oh!). */ |
| | 2105 | controller->sequence_timer = AT_sequence_timer; |
| | 2106 | |
| | 2107 | controller->Looped = controller->LoopAfterTweening; |
| | 2108 | |
| | 2109 | if (controller->StopAfterTweening) |
| | 2110 | controller->Playing = 0; /* Hey ho. */ |
| | 2111 | |
| | 2112 | controller->Tweening = Controller_NoTweening; |
| | 2113 | controller->ElevationTweening = 0; |
| | 2114 | } |
| | 2115 | |
| | 2116 | if (controller->Playing) |
| | 2117 | { |
| | 2118 | if (controller->Reversed) |
| | 2119 | { |
| | 2120 | if (controller->Tweening != Controller_NoTweening) |
| | 2121 | { |
| | 2122 | assert(controller->Tweening == Controller_Tweening); |
| | 2123 | /* Still tween forwards. */ |
| | 2124 | controller->sequence_timer += MUL_FIXED(controller->timer_increment,NormalFrameTime); |
| | 2125 | |
| | 2126 | if (controller->sequence_timer >= ONE_FIXED) |
| | 2127 | { |
| | 2128 | controller->sequence_timer = ONE_FIXED; |
| | 2129 | controller->Tweening = Controller_EndTweening; |
| | 2130 | } |
| | 2131 | } |
| | 2132 | else |
| | 2133 | { |
| | 2134 | assert(controller->Tweening == Controller_NoTweening); |
| | 2135 | controller->sequence_timer -= MUL_FIXED(controller->timer_increment,NormalFrameTime); |
| | 2136 | |
| | 2137 | if (controller->Looped) |
| | 2138 | { |
| | 2139 | while (controller->sequence_timer < 0) |
| | 2140 | { |
| | 2141 | /* Might lose count of how many times we've looped, but who's counting? */ |
| | 2142 | controller->sequence_timer += ONE_FIXED; |
| | 2143 | } |
| | 2144 | } |
| | 2145 | else |
| | 2146 | { |
| | 2147 | if (controller->sequence_timer < 0) |
| | 2148 | controller->sequence_timer = 0; |
| | 2149 | } |
| | 2150 | } |
| | 2151 | } |
| | 2152 | else |
| | 2153 | { |
| | 2154 | controller->sequence_timer += MUL_FIXED(controller->timer_increment,NormalFrameTime); |
| | 2155 | |
| | 2156 | if (controller->Tweening != Controller_NoTweening) |
| | 2157 | { |
| | 2158 | assert(controller->Tweening == Controller_Tweening); |
| | 2159 | |
| | 2160 | if (controller->sequence_timer >= ONE_FIXED) |
| | 2161 | { |
| | 2162 | controller->sequence_timer = ONE_FIXED; |
| | 2163 | controller->Tweening = Controller_EndTweening; |
| | 2164 | } |
| | 2165 | } |
| | 2166 | else if (controller->Looped) |
| | 2167 | { |
| | 2168 | while (controller->sequence_timer >= ONE_FIXED) |
| | 2169 | { |
| | 2170 | /* Might lose count of how many times we've looped, but who's counting? */ |
| | 2171 | controller->sequence_timer -= ONE_FIXED; |
| | 2172 | } |
| | 2173 | } |
| | 2174 | else |
| | 2175 | { |
| | 2176 | if (controller->sequence_timer >= ONE_FIXED) |
| | 2177 | controller->sequence_timer = ONE_FIXED-1; |
| | 2178 | } |
| | 2179 | } |
| | 2180 | } |
| | 2181 | |
| | 2182 | /* Do delta timers, too. */ |
| | 2183 | |
| | 2184 | { |
| | 2185 | DELTA_CONTROLLER *dcon = controller->Deltas; |
| | 2186 | |
| | 2187 | while (dcon) |
| | 2188 | { |
| | 2189 | if (dcon->seconds_for_sequence && dcon->Playing && dcon->Active) |
| | 2190 | { |
| | 2191 | dcon->timer += MUL_FIXED(dcon->timer_increment,NormalFrameTime); |
| | 2192 | |
| | 2193 | if (dcon->timer >= ONE_FIXED) |
| | 2194 | { |
| | 2195 | if (dcon->Looped) |
| | 2196 | dcon->timer -= ONE_FIXED; |
| | 2197 | else |
| | 2198 | dcon->timer = ONE_FIXED-1; |
| | 2199 | } |
| | 2200 | } |
| | 2201 | |
| | 2202 | dcon = dcon->next_controller; |
| | 2203 | } |
| | 2204 | } |
| | 2205 | } |
| | 2206 | |
| | 2207 | static void Budge_Recursion(SECTION_DATA *this_section_data,VECTORCH *offset) |
| | 2208 | { |
| | 2209 | /* Budge! */ |
| | 2210 | this_section_data->World_Offset.vx += offset->vx; |
| | 2211 | this_section_data->World_Offset.vy += offset->vy; |
| | 2212 | this_section_data->World_Offset.vz += offset->vz; |
| | 2213 | |
| | 2214 | /* Now call recursion... */ |
| | 2215 | |
| | 2216 | if (this_section_data->First_Child != NULL) |
| | 2217 | { |
| | 2218 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 2219 | |
| | 2220 | while (child_list_ptr != NULL) |
| | 2221 | { |
| | 2222 | Budge_Recursion(child_list_ptr,offset); |
| | 2223 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 2224 | } |
| | 2225 | } |
| | 2226 | } |
| | 2227 | |
| | 2228 | static void Process_PlayersWeapon(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,VECTORCH *parent_position,MATRIXCH *parent_orientation,int
frame_timer, int sequence_type, int subsequence) |
| | 2229 | { |
| | 2230 | VECTORCH diagnostic_vector = { 0, 0, 0}; |
| | 2231 | |
| | 2232 | /* Work out which SECTION to use. */ |
| | 2233 | const SECTION *this_section = this_section_data->sempai; |
| | 2234 | |
| | 2235 | if (controller != this_section_data->my_controller) |
| | 2236 | { |
| | 2237 | printf("Wrong Controller assert in PROCESS_SECTION.w\n"); |
| | 2238 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 2239 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 2240 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 2241 | printf("Tweening flags %d\n",controller->Tweening); |
| | 2242 | assert(controller == this_section_data->my_controller); |
| | 2243 | } |
| | 2244 | |
| | 2245 | /* We can't just stop at a terminate_here, because that will |
| | 2246 | do over the section_data list. */ |
| | 2247 | |
| | 2248 | /* Well, actually, now we can. */ |
| | 2249 | |
| | 2250 | /* Put in a sequence switcher!!! */ |
| | 2251 | |
| | 2252 | /* There now is one. */ |
| | 2253 | |
| | 2254 | /* Quick auto-correction... */ |
| | 2255 | |
| | 2256 | if (frame_timer < 0) |
| | 2257 | frame_timer = 0; |
| | 2258 | else if (frame_timer >= 65536) |
| | 2259 | frame_timer = 65535; |
| | 2260 | |
| | 2261 | if ((controller->FrameStamp != GlobalFrameCounter) || !(this_section_data->flags & section_data_initialised)) |
| | 2262 | { |
| | 2263 | /* Positions not computed yet this frame. */ |
| | 2264 | |
| | 2265 | SEQUENCE *this_sequence = GetSequencePointer(sequence_type, subsequence, this_section); |
| | 2266 | KEYFRAME_DATA *sequence_start = this_sequence->first_frame; |
| | 2267 | int fake_frame_timer; |
| | 2268 | |
| | 2269 | if (controller->LockTopSection && (this_section_data == controller->section_data)) |
| | 2270 | fake_frame_timer = 0; |
| | 2271 | else |
| | 2272 | fake_frame_timer = frame_timer; |
| | 2273 | |
| | 2274 | /* For this section, find the interpolated offset and eulers. */ |
| | 2275 | this_section_data->Last_World_Offset = this_section_data->World_Offset; |
| | 2276 | |
| | 2277 | if (this_section_data->Tweening) |
| | 2278 | Analyse_Tweening_Data(controller, this_section_data, frame_timer, &this_section_data->World_Offset, &this_section_data->RelSecMat); |
| | 2279 | else |
| | 2280 | New_Analyse_Keyframe_Data(controller, this_section_data, sequence_start, fake_frame_timer, &this_section_data->World_Offset,
&this_section_data->RelSecMat); |
| | 2281 | |
| | 2282 | if (controller->ZeroRootDisplacement && (this_section_data == controller->section_data)) |
| | 2283 | this_section_data->World_Offset.vx = this_section_data->World_Offset.vy = this_section_data->World_Offset.vz = 0; |
| | 2284 | |
| | 2285 | if (controller->ZeroRootRotation && (this_section_data == controller->section_data)) |
| | 2286 | this_section_data->RelSecMat = IdentityMatrix; |
| | 2287 | |
| | 2288 | this_section_data->Offset = this_section_data->World_Offset; |
| | 2289 | |
| | 2290 | diagnostic_vector = this_section_data->World_Offset; |
| | 2291 | |
| | 2292 | /* The parent's position will be used with the offset value and rotation |
| | 2293 | matrix to determine the position of the new section. */ |
| | 2294 | |
| | 2295 | RotateVector(&this_section_data->World_Offset, parent_orientation); |
| | 2296 | |
| | 2297 | this_section_data->World_Offset.vx += parent_position->vx; |
| | 2298 | this_section_data->World_Offset.vy += parent_position->vy; |
| | 2299 | this_section_data->World_Offset.vz += parent_position->vz; |
| | 2300 | |
| | 2301 | /* Create the absolute rotation matrix for this section. */ |
| | 2302 | MatrixMultiply(parent_orientation, &this_section_data->RelSecMat, &this_section_data->SecMat); |
| | 2303 | |
| | 2304 | /* Set the initialised flag... */ |
| | 2305 | this_section_data->flags |= section_data_initialised; |
| | 2306 | } |
| | 2307 | |
| | 2308 | /* Check the object is in a sensible place. */ |
| | 2309 | if ( !( (this_section_data->World_Offset.vx < 1000000 && this_section_data->World_Offset.vx > -1000000) |
| | 2310 | && (this_section_data->World_Offset.vy < 1000000 && this_section_data->World_Offset.vy > -1000000) |
| | 2311 | && (this_section_data->World_Offset.vz < 1000000 && this_section_data->World_Offset.vz > -1000000) ) ) |
| | 2312 | { |
| | 2313 | printf("Tests in PROCESS_SECTION.\n"); |
| | 2314 | |
| | 2315 | if (Global_HModel_Sptr) |
| | 2316 | { |
| | 2317 | printf("Misplaced object is of type %d\n",Global_HModel_Sptr->type); |
| | 2318 | |
| | 2319 | if (Global_HModel_Sptr->DisplayBlock) |
| | 2320 | printf("Object is Near.\n"); |
| | 2321 | else |
| | 2322 | printf("Object is Far.\n"); |
| | 2323 | } |
| | 2324 | else |
| | 2325 | { |
| | 2326 | printf("Misplaced object has no SBptr.\n"); |
| | 2327 | } |
| | 2328 | |
| | 2329 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 2330 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 2331 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 2332 | printf("Tweening flags %d\n",controller->Tweening); |
| | 2333 | printf("Diagnostic Vector %d,%d,%d\n",diagnostic_vector.vx,diagnostic_vector.vy,diagnostic_vector.vz); |
| | 2334 | printf("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat11,parent_orientation->mat12,parent_orientation->mat13); |
| | 2335 | printf("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat21,parent_orientation->mat22,parent_orientation->mat23); |
| | 2336 | printf("Parent Orientation Matrix: %d,%d,%d\n",parent_orientation->mat31,parent_orientation->mat32,parent_orientation->mat33); |
| | 2337 | printf("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz); |
| | 2338 | printf("This Position
%d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz); |
| | 2339 | |
| | 2340 | assert(this_section_data->World_Offset.vx < 1000000 && this_section_data->World_Offset.vx > -1000000); |
| | 2341 | assert(this_section_data->World_Offset.vy < 1000000 && this_section_data->World_Offset.vy > -1000000); |
| | 2342 | assert(this_section_data->World_Offset.vz < 1000000 && this_section_data->World_Offset.vz > -1000000); |
| | 2343 | } |
| | 2344 | |
| | 2345 | /* Now call recursion... */ |
| | 2346 | |
| | 2347 | if ((this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 2348 | { |
| | 2349 | SECTION_DATA *child_ptr = this_section_data->First_Child; |
| | 2350 | |
| | 2351 | while (child_ptr != NULL) |
| | 2352 | { |
| | 2353 | assert(child_ptr->My_Parent == this_section_data); |
| | 2354 | Process_PlayersWeapon(controller, child_ptr, &this_section_data->World_Offset, &this_section_data->SecMat, frame_timer, sequence_type,
subsequence); |
| | 2355 | child_ptr = child_ptr->Next_Sibling; |
| | 2356 | } |
| | 2357 | } |
| | 2358 | |
| | 2359 | /* Finally, if this section has a shape, and we are rendering, render it. */ |
| | 2360 | |
| | 2361 | if ((this_section_data->Shape != NULL) && !(this_section_data->flags & section_data_notreal)) |
| | 2362 | { |
| | 2363 | extern const DISPLAYBLOCK Zero_Displayblock; |
| | 2364 | /* Unreal things don't get plotted, either. */ |
| | 2365 | |
| | 2366 | DISPLAYBLOCK dummy_displayblock = Zero_Displayblock; |
| | 2367 | |
| | 2368 | assert(this_section_data->ShapeNum); |
| | 2369 | |
| | 2370 | /* Decide what shape to use. */ |
| | 2371 | |
| | 2372 | struct shapeheader* shape_to_use = this_section_data->Shape; |
| | 2373 | dummy_displayblock.extent.radius = shape_to_use->shaperadius; |
| | 2374 | |
| | 2375 | if (Simplify_HModel_Rendering) |
| | 2376 | { |
| | 2377 | dummy_displayblock.ObShape = GetLoadedShapeMSL("Shell"); |
| | 2378 | dummy_displayblock.ShapeData = GetShapeData(dummy_displayblock.ObShape); |
| | 2379 | } |
| | 2380 | else |
| | 2381 | { |
| | 2382 | dummy_displayblock.ObShape = this_section_data->ShapeNum; |
| | 2383 | dummy_displayblock.ShapeData = shape_to_use; |
| | 2384 | } |
| | 2385 | |
| | 2386 | dummy_displayblock.ObWorld = this_section_data->World_Offset; |
| | 2387 | dummy_displayblock.ObMat = this_section_data->SecMat; |
| | 2388 | dummy_displayblock.ObFlags = 0; |
| | 2389 | dummy_displayblock.ObFlags2 = Global_HModel_DispPtr->ObFlags2; |
| | 2390 | dummy_displayblock.ObTxAnimCtrlBlks = this_section_data->tac_ptr; |
| | 2391 | dummy_displayblock.ObStrategyBlock = Global_HModel_Sptr; |
| | 2392 | dummy_displayblock.SpecialFXFlags = Global_HModel_DispPtr->SpecialFXFlags; |
| | 2393 | |
| | 2394 | dummy_displayblock.ObView.vx = dummy_displayblock.ObWorld.vx - Global_VDB.VDB_World.vx; |
| | 2395 | dummy_displayblock.ObView.vy = dummy_displayblock.ObWorld.vy - Global_VDB.VDB_World.vy; |
| | 2396 | dummy_displayblock.ObView.vz = dummy_displayblock.ObWorld.vz - Global_VDB.VDB_World.vz; |
| | 2397 | |
| | 2398 | RotateVector(&dummy_displayblock.ObView, &Global_VDB.VDB_Mat); |
| | 2399 | |
| | 2400 | /* Whilst we're here... */ |
| | 2401 | |
| | 2402 | this_section_data->View_Offset = dummy_displayblock.ObView; |
| | 2403 | this_section_data->flags |= section_data_view_init; |
| | 2404 | controller->View_FrameStamp = GlobalFrameCounter; |
| | 2405 | |
| | 2406 | AddPlayersWeaponShape(&dummy_displayblock); |
| | 2407 | } |
| | 2408 | else if (controller->View_FrameStamp != GlobalFrameCounter) |
| | 2409 | { |
| | 2410 | this_section_data->flags &= ~section_data_view_init; |
| | 2411 | } |
| | 2412 | } |
| | 2413 | |
| | 2414 | void DoPlayersWeaponHModel(DISPLAYBLOCK *dptr) |
| | 2415 | { |
| | 2416 | HMODELCONTROLLER *controller = dptr->HModelControlBlock; |
| | 2417 | Global_HModel_Sptr = dptr->ObStrategyBlock; |
| | 2418 | Global_HModel_DispPtr = dptr; |
| | 2419 | |
| | 2420 | /* Check the object is in a sensible place. */ |
| | 2421 | if ( !( (dptr->ObWorld.vx < 1000000 && dptr->ObWorld.vx > -1000000) |
| | 2422 | && (dptr->ObWorld.vy < 1000000 && dptr->ObWorld.vy > -1000000) |
| | 2423 | && (dptr->ObWorld.vz < 1000000 && dptr->ObWorld.vz > -1000000) ) ) |
| | 2424 | { |
| | 2425 | printf("Tests in DOHMODEL.\n"); |
| | 2426 | |
| | 2427 | if (Global_HModel_Sptr) |
| | 2428 | printf("Misplaced object is of type %d\n", Global_HModel_Sptr->type); |
| | 2429 | else |
| | 2430 | printf("Misplaced object has no SBptr.\n"); |
| | 2431 | |
| | 2432 | printf("It was playing sequence: %d,%d\n", controller->Sequence_Type, controller->Sub_Sequence); |
| | 2433 | |
| | 2434 | assert(dptr->ObWorld.vx < 1000000 && dptr->ObWorld.vx > -1000000); |
| | 2435 | assert(dptr->ObWorld.vy < 1000000 && dptr->ObWorld.vy > -1000000); |
| | 2436 | assert(dptr->ObWorld.vz < 1000000 && dptr->ObWorld.vz > -1000000); |
| | 2437 | } |
| | 2438 | |
| | 2439 | assert(controller->section_data->my_controller == controller); |
| | 2440 | |
| | 2441 | /* Only do timer if you're out of date. */ |
| | 2442 | |
| | 2443 | if (controller->FrameStamp != GlobalFrameCounter) |
| | 2444 | { |
| | 2445 | HMTimer_Kernel(controller); |
| | 2446 | controller->keyframe_flags = 0; |
| | 2447 | } |
| | 2448 | else |
| | 2449 | { |
| | 2450 | VECTORCH offset; |
| | 2451 | /* Want to budge? */ |
| | 2452 | |
| | 2453 | offset.vx = dptr->ObWorld.vx - controller->Computed_Position.vx; |
| | 2454 | offset.vy = dptr->ObWorld.vy - controller->Computed_Position.vy; |
| | 2455 | offset.vz = dptr->ObWorld.vz - controller->Computed_Position.vz; |
| | 2456 | |
| | 2457 | if (offset.vx || offset.vy || offset.vz) |
| | 2458 | { |
| | 2459 | /* I reckon you'd be better off taking the budge. */ |
| | 2460 | Budge_Recursion(controller->section_data, &offset); |
| | 2461 | } |
| | 2462 | } |
| | 2463 | |
| | 2464 | Process_PlayersWeapon(controller, controller->section_data, &dptr->ObWorld, &dptr->ObMat, controller->sequence_timer,
controller->Sequence_Type, controller->Sub_Sequence); |
| | 2465 | |
| | 2466 | /* Update frame stamp. */ |
| | 2467 | |
| | 2468 | controller->FrameStamp = GlobalFrameCounter; |
| | 2469 | controller->Computed_Position = dptr->ObWorld; |
| | 2470 | } |
| | 2471 | |
| | 2472 | void DoHModel(DISPLAYBLOCK *dptr) |
| | 2473 | { |
| | 2474 | HMODELCONTROLLER *controller = dptr->HModelControlBlock; |
| | 2475 | Global_HModel_Sptr = dptr->ObStrategyBlock; |
| | 2476 | Global_HModel_DispPtr = dptr; |
| | 2477 | |
| | 2478 | /* Check the object is in a sensible place. */ |
| | 2479 | if ( !( (dptr->ObWorld.vx < 1000000 && dptr->ObWorld.vx > -1000000) |
| | 2480 | && (dptr->ObWorld.vy < 1000000 && dptr->ObWorld.vy > -1000000) |
| | 2481 | && (dptr->ObWorld.vz < 1000000 && dptr->ObWorld.vz > -1000000) ) ) |
| | 2482 | { |
| | 2483 | printf("Tests in DOHMODEL.\n"); |
| | 2484 | |
| | 2485 | if (dptr->ObStrategyBlock) |
| | 2486 | printf("Misplaced object is of type %d\n", dptr->ObStrategyBlock->type); |
| | 2487 | else |
| | 2488 | printf("Misplaced object has no SBptr.\n"); |
| | 2489 | |
| | 2490 | printf("It was playing sequence: %d,%d\n", controller->Sequence_Type, controller->Sub_Sequence); |
| | 2491 | |
| | 2492 | assert(dptr->ObWorld.vx < 1000000 && dptr->ObWorld.vx > -1000000); |
| | 2493 | assert(dptr->ObWorld.vy < 1000000 && dptr->ObWorld.vy > -1000000); |
| | 2494 | assert(dptr->ObWorld.vz < 1000000 && dptr->ObWorld.vz > -1000000); |
| | 2495 | } |
| | 2496 | |
| | 2497 | assert(controller->section_data->my_controller == controller); |
| | 2498 | |
| | 2499 | /* Only do timer if you're out of date. */ |
| | 2500 | |
| | 2501 | if (controller->FrameStamp != GlobalFrameCounter) |
| | 2502 | { |
| | 2503 | HMTimer_Kernel(controller); |
| | 2504 | controller->keyframe_flags = 0; |
| | 2505 | } |
| | 2506 | else |
| | 2507 | { |
| | 2508 | VECTORCH offset; |
| | 2509 | /* Want to budge? */ |
| | 2510 | |
| | 2511 | offset.vx = dptr->ObWorld.vx - controller->Computed_Position.vx; |
| | 2512 | offset.vy = dptr->ObWorld.vy - controller->Computed_Position.vy; |
| | 2513 | offset.vz = dptr->ObWorld.vz - controller->Computed_Position.vz; |
| | 2514 | |
| | 2515 | if (offset.vx || offset.vy || offset.vz) |
| | 2516 | { |
| | 2517 | /* I reckon you'd be better off taking the budge. */ |
| | 2518 | Budge_Recursion(controller->section_data, &offset); |
| | 2519 | } |
| | 2520 | } |
| | 2521 | |
| | 2522 | /* That handled the timer. Now render it. */ |
| | 2523 | { |
| | 2524 | int render = !(dptr->ObFlags & ObFlag_NotVis); |
| | 2525 | |
| | 2526 | //if (dptr->ObFlags & ObFlag_NotVis) printf("HModel NotVis!\n"); |
| | 2527 | |
| | 2528 | Process_Section(controller, controller->section_data, &dptr->ObWorld, &dptr->ObMat, controller->sequence_timer,
controller->Sequence_Type, controller->Sub_Sequence, render); |
| | 2529 | } |
| | 2530 | /* Note braces! Process_Section is OUTSIDE, 'cos you might still want to render! */ |
| | 2531 | |
| | 2532 | /* Update frame stamp. */ |
| | 2533 | |
| | 2534 | controller->FrameStamp = GlobalFrameCounter; |
| | 2535 | controller->Computed_Position = dptr->ObWorld; |
| | 2536 | } |
| | 2537 | |
| | 2538 | static void DoHModelTimer_Recursion(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,int frame_timer, int sequence_type, int subsequence) |
| | 2539 | { |
| | 2540 | const SECTION *this_section = this_section_data->sempai; |
| | 2541 | |
| | 2542 | /* Cut down Process_Section. */ |
| | 2543 | |
| | 2544 | if (controller->FrameStamp != GlobalFrameCounter) |
| | 2545 | { |
| | 2546 | /* Positions not computed yet this frame. */ |
| | 2547 | |
| | 2548 | SEQUENCE *this_sequence = GetSequencePointer(sequence_type,subsequence,this_section); |
| | 2549 | KEYFRAME_DATA *sequence_start = this_sequence->first_frame; |
| | 2550 | |
| | 2551 | /* For this section, find the interpolated offset and eulers. */ |
| | 2552 | |
| | 2553 | if (!this_section_data->Tweening) |
| | 2554 | { |
| | 2555 | int working_timer; |
| | 2556 | |
| | 2557 | Handle_Section_Timer(controller, this_section_data, sequence_start, frame_timer, &working_timer); |
| | 2558 | } |
| | 2559 | } |
| | 2560 | |
| | 2561 | /* Now call recursion... */ |
| | 2562 | |
| | 2563 | if ((this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 2564 | { |
| | 2565 | SECTION_DATA *child_ptr = this_section_data->First_Child; |
| | 2566 | |
| | 2567 | while (child_ptr != NULL) |
| | 2568 | { |
| | 2569 | assert(child_ptr->My_Parent == this_section_data); |
| | 2570 | |
| | 2571 | DoHModelTimer_Recursion(controller, child_ptr, frame_timer, sequence_type,subsequence); |
| | 2572 | child_ptr = child_ptr->Next_Sibling; |
| | 2573 | } |
| | 2574 | } |
| | 2575 | } |
| | 2576 | |
| | 2577 | void DoHModelTimer(HMODELCONTROLLER *controller) |
| | 2578 | { |
| | 2579 | /* Be VERY careful with this function - it can put the timer and the |
| | 2580 | position computations out of step. Once you've called this, call NO |
| | 2581 | OTHER HMODEL FUNCTIONS on this model until the next frame! */ |
| | 2582 | |
| | 2583 | assert(controller); |
| | 2584 | |
| | 2585 | if (controller->FrameStamp == GlobalFrameCounter) |
| | 2586 | return; /* Done a timer this frame already! */ |
| | 2587 | |
| | 2588 | controller->keyframe_flags = 0; |
| | 2589 | |
| | 2590 | HMTimer_Kernel(controller); |
| | 2591 | |
| | 2592 | /* That handled the timer. No rendering this time. */ |
| | 2593 | |
| | 2594 | DoHModelTimer_Recursion(controller, controller->section_data, controller->sequence_timer, controller->Sequence_Type, controller->Sub_Sequence); |
| | 2595 | } |
| | 2596 | |
| | 2597 | void ProveHModel(HMODELCONTROLLER *controller, DISPLAYBLOCK *dptr) |
| | 2598 | { |
| | 2599 | /* Simply to verify a new hmodel, and remove junk. */ |
| | 2600 | |
| | 2601 | assert(controller); |
| | 2602 | assert(dptr); |
| | 2603 | |
| | 2604 | Global_HModel_Sptr = dptr->ObStrategyBlock; |
| | 2605 | |
| | 2606 | /* Check the object is in a sensible place. */ |
| | 2607 | if ( !( (dptr->ObWorld.vx < 1000000 && dptr->ObWorld.vx > -1000000) |
| | 2608 | && (dptr->ObWorld.vy < 1000000 && dptr->ObWorld.vy > -1000000) |
| | 2609 | && (dptr->ObWorld.vz < 1000000 && dptr->ObWorld.vz > -1000000) ) ) |
| | 2610 | { |
| | 2611 | printf("Tests in PROVEHMODEL.\n"); |
| | 2612 | |
| | 2613 | if (Global_HModel_Sptr) |
| | 2614 | printf("Misplaced object is of type %d\n",Global_HModel_Sptr->type); |
| | 2615 | else |
| | 2616 | printf("Misplaced object has no SBptr.\n"); |
| | 2617 | |
| | 2618 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 2619 | |
| | 2620 | assert(dptr->ObWorld.vx < 1000000 && dptr->ObWorld.vx > -1000000); |
| | 2621 | assert(dptr->ObWorld.vy < 1000000 && dptr->ObWorld.vy > -1000000); |
| | 2622 | assert(dptr->ObWorld.vz < 1000000 && dptr->ObWorld.vz > -1000000); |
| | 2623 | } |
| | 2624 | |
| | 2625 | assert(controller->section_data->my_controller == controller); |
| | 2626 | |
| | 2627 | if (controller->FrameStamp == GlobalFrameCounter) |
| | 2628 | { |
| | 2629 | VECTORCH offset; |
| | 2630 | /* Want to budge? */ |
| | 2631 | |
| | 2632 | offset.vx = dptr->ObWorld.vx - controller->Computed_Position.vx; |
| | 2633 | offset.vy = dptr->ObWorld.vy - controller->Computed_Position.vy; |
| | 2634 | offset.vz = dptr->ObWorld.vz - controller->Computed_Position.vz; |
| | 2635 | |
| | 2636 | if (offset.vx || offset.vy || offset.vz) |
| | 2637 | Budge_Recursion(controller->section_data, &offset); |
| | 2638 | } |
| | 2639 | |
| | 2640 | if (controller->FrameStamp != GlobalFrameCounter) |
| | 2641 | { |
| | 2642 | controller->keyframe_flags = 0; |
| | 2643 | HMTimer_Kernel(controller); |
| | 2644 | } |
| | 2645 | |
| | 2646 | /* That handled the timer. Now update positions. */ |
| | 2647 | |
| | 2648 | Process_Section(controller, controller->section_data, &dptr->ObWorld, &dptr->ObMat, controller->sequence_timer,
controller->Sequence_Type, controller->Sub_Sequence, 0); |
| | 2649 | |
| | 2650 | controller->FrameStamp = GlobalFrameCounter; |
| | 2651 | controller->Computed_Position = dptr->ObWorld; |
| | 2652 | |
| | 2653 | assert(controller->section_data->flags§ion_data_initialised); |
| | 2654 | } |
| | 2655 | |
| | 2656 | void ProveHModel_Far(HMODELCONTROLLER *controller, STRATEGYBLOCK *sbPtr) |
| | 2657 | { |
| | 2658 | /* Simply to verify a new hmodel, and remove junk. */ |
| | 2659 | |
| | 2660 | assert(controller); |
| | 2661 | assert(sbPtr); |
| | 2662 | |
| | 2663 | Global_HModel_Sptr = sbPtr; |
| | 2664 | |
| | 2665 | assert(sbPtr->DynPtr); |
| | 2666 | |
| | 2667 | /* Check the object is in a sensible place. */ |
| | 2668 | if ( !( (sbPtr->DynPtr->Position.vx < 1000000 && sbPtr->DynPtr->Position.vx > -1000000) |
| | 2669 | && (sbPtr->DynPtr->Position.vy < 1000000 && sbPtr->DynPtr->Position.vy > -1000000) |
| | 2670 | && (sbPtr->DynPtr->Position.vz < 1000000 && sbPtr->DynPtr->Position.vz > -1000000) ) ) |
| | 2671 | { |
| | 2672 | printf("Tests in PROVEHMODEL_FAR.\n"); |
| | 2673 | |
| | 2674 | if (Global_HModel_Sptr) |
| | 2675 | printf("Misplaced object is of type %d\n",Global_HModel_Sptr->type); |
| | 2676 | else |
| | 2677 | printf("Misplaced object has no SBptr.\n"); |
| | 2678 | |
| | 2679 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 2680 | |
| | 2681 | assert(sbPtr->DynPtr->Position.vx < 1000000 && sbPtr->DynPtr->Position.vx > -1000000); |
| | 2682 | assert(sbPtr->DynPtr->Position.vy < 1000000 && sbPtr->DynPtr->Position.vy > -1000000); |
| | 2683 | assert(sbPtr->DynPtr->Position.vz < 1000000 && sbPtr->DynPtr->Position.vz > -1000000); |
| | 2684 | } |
| | 2685 | |
| | 2686 | assert(controller->section_data->my_controller == controller); |
| | 2687 | |
| | 2688 | if (controller->FrameStamp == GlobalFrameCounter) |
| | 2689 | { |
| | 2690 | VECTORCH offset; |
| | 2691 | /* Want to budge? */ |
| | 2692 | |
| | 2693 | offset.vx = controller->Computed_Position.vx - sbPtr->DynPtr->Position.vx; |
| | 2694 | offset.vy = controller->Computed_Position.vy - sbPtr->DynPtr->Position.vy; |
| | 2695 | offset.vz = controller->Computed_Position.vz - sbPtr->DynPtr->Position.vz; |
| | 2696 | |
| | 2697 | if (offset.vx || offset.vy || offset.vz) |
| | 2698 | Budge_Recursion(controller->section_data, &offset); |
| | 2699 | } |
| | 2700 | |
| | 2701 | if (controller->FrameStamp != GlobalFrameCounter) |
| | 2702 | { |
| | 2703 | controller->keyframe_flags = 0; |
| | 2704 | HMTimer_Kernel(controller); |
| | 2705 | } |
| | 2706 | /* That handled the timer. Now update positions. */ |
| | 2707 | |
| | 2708 | Process_Section(controller, controller->section_data, &sbPtr->DynPtr->Position, &sbPtr->DynPtr->OrientMat,
controller->sequence_timer, controller->Sequence_Type, controller->Sub_Sequence, 0); |
| | 2709 | |
| | 2710 | controller->FrameStamp = GlobalFrameCounter; |
| | 2711 | controller->Computed_Position = sbPtr->DynPtr->Position; |
| | 2712 | |
| | 2713 | assert(controller->section_data->flags§ion_data_initialised); |
| | 2714 | } |
| | 2715 | |
| | 2716 | static int Prune_Recursion_Virtual(SECTION_DATA *this_section_data) |
| | 2717 | { |
| | 2718 | const SECTION *this_section = this_section_data->sempai; |
| | 2719 | |
| | 2720 | /* Work out which SECTION_DATA to use. */ |
| | 2721 | |
| | 2722 | int sol = (this_section->flags & section_has_sparkoflife); |
| | 2723 | |
| | 2724 | this_section_data->flags |= section_data_notreal; |
| | 2725 | |
| | 2726 | if ( (this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 2727 | { |
| | 2728 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 2729 | |
| | 2730 | while (child_list_ptr != NULL) |
| | 2731 | { |
| | 2732 | if (Prune_Recursion_Virtual(child_list_ptr)) |
| | 2733 | sol = 1; |
| | 2734 | |
| | 2735 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 2736 | } |
| | 2737 | } |
| | 2738 | |
| | 2739 | return sol; |
| | 2740 | } |
| | 2741 | |
| | 2742 | int Prune_HModel_Virtual(SECTION_DATA *top_section) |
| | 2743 | { |
| | 2744 | /* To make top_section, and everything below it, unreal. */ |
| | 2745 | /* Must pass back up the recursion if any section pruned */ |
| | 2746 | /* has the spark of life. */ |
| | 2747 | |
| | 2748 | int sol = Prune_Recursion_Virtual(top_section); |
| | 2749 | |
| | 2750 | top_section->flags |= section_data_terminate_here; |
| | 2751 | top_section->gore_timer = 0; |
| | 2752 | |
| | 2753 | return sol; |
| | 2754 | } |
| | 2755 | |
| | 2756 | static void Gibbing_Recursion(STRATEGYBLOCK *sbPtr, SECTION_DATA *this_section_data, int probability) |
| | 2757 | { |
| | 2758 | //this_section_data->current_damage.Health = 0; // make it bleed |
| | 2759 | if ((this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 2760 | { |
| | 2761 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 2762 | |
| | 2763 | while(child_list_ptr != NULL) |
| | 2764 | { |
| | 2765 | if(!(child_list_ptr->flags & section_data_terminate_here)) |
| | 2766 | { |
| | 2767 | /* Right. Roll some dice... */ |
| | 2768 | //if((this_section_data->current_damage.Health <= 0) && !(child_list_ptr->sempai->flags & section_flag_never_frag)) |
| | 2769 | if (!(child_list_ptr->sempai->flags & section_flag_never_frag) && ((SeededFastRandom() & 65535) < probability)) |
| | 2770 | { |
| | 2771 | child_list_ptr->current_damage.Health = 0; // make it bleed |
| | 2772 | /* Frag this bit... */ |
| | 2773 | //DISPLAYBLOCK *this_debris = MakeHierarchicalDebris(sbPtr, child_list_ptr, &child_list_ptr->World_Offset,
&child_list_ptr->SecMat, NULL, 4); |
| | 2774 | DISPLAYBLOCK *this_debris = disengage_part(sbPtr, child_list_ptr, &child_list_ptr->World_Offset, &child_list_ptr->SecMat,
NULL, 4); |
| | 2775 | /* Oh Dear! Every section below and including this one becomes... unreal. |
| | 2776 | And if any of them contain the spark of life, we need to know. */ |
| | 2777 | |
| | 2778 | /* Now, gibb the debris ;-) */ |
| | 2779 | |
| | 2780 | if (this_debris && !(this_debris->HModelControlBlock->section_data->sempai->flags & section_flag_nofurthergibbing)) |
| | 2781 | { |
| | 2782 | assert(this_debris->HModelControlBlock); |
| | 2783 | assert(this_debris->HModelControlBlock->section_data); |
| | 2784 | Gibbing_Recursion(sbPtr, this_debris->HModelControlBlock->section_data, probability); |
| | 2785 | } |
| | 2786 | } |
| | 2787 | else |
| | 2788 | { |
| | 2789 | Gibbing_Recursion(sbPtr, child_list_ptr, probability); |
| | 2790 | } |
| | 2791 | } |
| | 2792 | |
| | 2793 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 2794 | } |
| | 2795 | } |
| | 2796 | } |
| | 2797 | |
| | 2798 | void Extreme_Gibbing(STRATEGYBLOCK *sbPtr, SECTION_DATA *this_section_data, int probability, VECTORCH *incoming) |
| | 2799 | { |
| | 2800 | /* Shell for gibbing. Do gibbing... */ |
| | 2801 | |
| | 2802 | Gibbing_Recursion(sbPtr, this_section_data, probability); |
| | 2803 | |
| | 2804 | /* Now frag the body off. */ |
| | 2805 | |
| | 2806 | if ((SeededFastRandom() & 65535) < probability) |
| | 2807 | MakeHierarchicalDebris(sbPtr, this_section_data, &this_section_data->World_Offset, &this_section_data->SecMat, NULL, 4, incoming); |
| | 2808 | } |
| | 2809 | |
| | 2810 | static int Change_Controller_Recursion(HMODELCONTROLLER *new_controller, SECTION_DATA *this_section_data) |
| | 2811 | { |
| | 2812 | this_section_data->my_controller = new_controller; |
| | 2813 | int wounds = this_section_data->sempai->flags & section_flags_wounding; |
| | 2814 | |
| | 2815 | /* Now call recursion... */ |
| | 2816 | |
| | 2817 | if (this_section_data->First_Child != NULL) |
| | 2818 | { |
| | 2819 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 2820 | |
| | 2821 | while (child_list_ptr != NULL) |
| | 2822 | { |
| | 2823 | wounds |= Change_Controller_Recursion(new_controller, child_list_ptr); |
| | 2824 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 2825 | } |
| | 2826 | } |
| | 2827 | |
| | 2828 | return wounds; |
| | 2829 | } |
| | 2830 | |
| | 2831 | int Splice_HModels(HMODELCONTROLLER *new_controller, SECTION_DATA *top_section_data) |
| | 2832 | { |
| | 2833 | /* Real fragging. */ |
| | 2834 | |
| | 2835 | /* Init new controller. */ |
| | 2836 | |
| | 2837 | Global_Controller_Ptr = new_controller; |
| | 2838 | |
| | 2839 | new_controller->Seconds_For_Sequence = ONE_FIXED; |
| | 2840 | new_controller->timer_increment = ONE_FIXED; |
| | 2841 | /* Seconds_For_Sequence and timer_increment are dealt with elsewhere. */ |
| | 2842 | new_controller->sequence_timer = 0; |
| | 2843 | new_controller->Playing = 0; |
| | 2844 | new_controller->Reversed = 0; |
| | 2845 | new_controller->Looped = 0; |
| | 2846 | new_controller->FrameStamp = -1; |
| | 2847 | new_controller->View_FrameStamp = -1; |
| | 2848 | |
| | 2849 | if (top_section_data->my_controller) |
| | 2850 | { |
| | 2851 | new_controller->DisableBleeding = top_section_data->my_controller->DisableBleeding; |
| | 2852 | new_controller->DisableSounds = top_section_data->my_controller->DisableSounds; |
| | 2853 | } |
| | 2854 | else |
| | 2855 | { |
| | 2856 | new_controller->DisableBleeding = new_controller->DisableSounds = 0; |
| | 2857 | } |
| | 2858 | |
| | 2859 | /* Probably set on return, but never mind. */ |
| | 2860 | new_controller->LockTopSection = 0; |
| | 2861 | new_controller->ZeroRootDisplacement = 0; |
| | 2862 | new_controller->ZeroRootRotation = 0; |
| | 2863 | new_controller->AT_sequence_timer = 0; |
| | 2864 | |
| | 2865 | /* Copy them over, splice them over, or ignore BY HAND. */ |
| | 2866 | new_controller->Deltas = NULL; |
| | 2867 | new_controller->keyframe_flags = 0; |
| | 2868 | |
| | 2869 | /* Every time a section is preprocessed, it must generate a section_data for |
| | 2870 | itself, and clip it to the last section_data that was generated. */ |
| | 2871 | |
| | 2872 | /* Create a new top section... */ |
| | 2873 | |
| | 2874 | SECTION_DATA *new_top_section = malloc(sizeof(SECTION_DATA)); |
| | 2875 | assert(new_top_section); |
| | 2876 | |
| | 2877 | /* Now. Copy the old top_section_data into the new top section. */ |
| | 2878 | |
| | 2879 | *new_top_section = *top_section_data; |
| | 2880 | |
| | 2881 | top_section_data->tac_ptr = NULL; |
| | 2882 | |
| | 2883 | /* Correct for new parentage. */ |
| | 2884 | new_top_section->My_Parent = NULL; |
| | 2885 | |
| | 2886 | if (new_top_section->First_Child != NULL) |
| | 2887 | { |
| | 2888 | SECTION_DATA *child_ptr = new_top_section->First_Child; |
| | 2889 | |
| | 2890 | while (child_ptr != NULL) |
| | 2891 | { |
| | 2892 | child_ptr->My_Parent = new_top_section; |
| | 2893 | child_ptr = child_ptr->Next_Sibling; |
| | 2894 | } |
| | 2895 | } |
| | 2896 | |
| | 2897 | /* ...and top_section_data gets no children. */ |
| | 2898 | |
| | 2899 | top_section_data->First_Child = NULL; |
| | 2900 | |
| | 2901 | /* Set flags. */ |
| | 2902 | |
| | 2903 | new_top_section->flags = top_section_data->flags &(~section_data_initialised); |
| | 2904 | top_section_data->flags |= section_data_terminate_here; |
| | 2905 | top_section_data->gore_timer = 0; |
| | 2906 | top_section_data->flags |= section_data_notreal; |
| | 2907 | new_top_section->flags |= section_data_false_root; |
| | 2908 | new_top_section->gore_timer = 0; |
| | 2909 | |
| | 2910 | /* Connect to controller. */ |
| | 2911 | |
| | 2912 | new_controller->section_data = new_top_section; |
| | 2913 | new_controller->Root_Section = new_top_section->sempai; |
| | 2914 | |
| | 2915 | return Change_Controller_Recursion(new_controller, new_top_section); |
| | 2916 | } |
| | 2917 | |
| | 2918 | SECTION_DATA *GetThisSectionData(SECTION_DATA *this_section_data, const char *name) |
| | 2919 | { |
| | 2920 | if (!strcmp(name, this_section_data->sempai->Section_Name)) |
| | 2921 | return(this_section_data); /* We are that section! */ |
| | 2922 | |
| | 2923 | /* Now call recursion... */ |
| | 2924 | |
| | 2925 | if (this_section_data->First_Child != NULL) |
| | 2926 | { |
| | 2927 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 2928 | |
| | 2929 | while (child_list_ptr != NULL) |
| | 2930 | { |
| | 2931 | SECTION_DATA *sdptr = GetThisSectionData(child_list_ptr, name); |
| | 2932 | |
| | 2933 | if (sdptr) |
| | 2934 | return sdptr; /* We got one! */ |
| | 2935 | |
| | 2936 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 2937 | } |
| | 2938 | } |
| | 2939 | |
| | 2940 | return NULL; |
| | 2941 | } |
| | 2942 | |
| | 2943 | static const SECTION *GetSection_Recursion(const SECTION *this_section, const char *name) |
| | 2944 | { |
| | 2945 | if (!strcmp(name, this_section->Section_Name)) |
| | 2946 | return(this_section); /* We are that section! */ |
| | 2947 | |
| | 2948 | /* Now call recursion... */ |
| | 2949 | |
| | 2950 | if (this_section->Children != NULL) |
| | 2951 | { |
| | 2952 | SECTION **child_list_ptr = this_section->Children; |
| | 2953 | |
| | 2954 | while (*child_list_ptr != NULL) |
| | 2955 | { |
| | 2956 | const SECTION *sptr = GetSection_Recursion(*child_list_ptr,name); |
| | 2957 | |
| | 2958 | if (sptr) |
| | 2959 | return sptr; /* We got one! */ |
| | 2960 | |
| | 2961 | child_list_ptr++; |
| | 2962 | } |
| | 2963 | } |
| | 2964 | |
| | 2965 | return NULL; |
| | 2966 | } |
| | 2967 | |
| | 2968 | const SECTION *GetThisSection(const SECTION *root, const char *name) |
| | 2969 | { |
| | 2970 | if ((root == NULL) || (name == NULL)) |
| | 2971 | return NULL; |
| | 2972 | |
| | 2973 | return GetSection_Recursion(root,name); |
| | 2974 | } |
| | 2975 | |
| | 2976 | static void MatToQuat (MATRIXCH *m, QUAT *quat) |
| | 2977 | { |
| | 2978 | const int X = 0; |
| | 2979 | const int Y = 1; |
| | 2980 | const int Z = 2; |
| | 2981 | const int W = 3; |
| | 2982 | |
| | 2983 | double mat[4][4]; |
| | 2984 | double q[4]; |
| | 2985 | |
| | 2986 | int i,j,k; |
| | 2987 | |
| | 2988 | int const nxt[3] = |
| | 2989 | { |
| | 2990 | //Y,Z,X |
| | 2991 | 1,2,0 |
| | 2992 | }; |
| | 2993 | |
| | 2994 | // we could try transposing the matrix here |
| | 2995 | |
| | 2996 | // TransposeMatrixCH(m); |
| | 2997 | |
| | 2998 | mat[0][0] = (double) m->mat11 / ONE_FIXED; |
| | 2999 | mat[1][0] = (double) m->mat21 / ONE_FIXED; |
| | 3000 | mat[2][0] = (double) m->mat31 / ONE_FIXED; |
| | 3001 | mat[0][1] = (double) m->mat12 / ONE_FIXED; |
| | 3002 | mat[1][1] = (double) m->mat22 / ONE_FIXED; |
| | 3003 | mat[2][1] = (double) m->mat32 / ONE_FIXED; |
| | 3004 | mat[0][2] = (double) m->mat13 / ONE_FIXED; |
| | 3005 | mat[1][2] = (double) m->mat23 / ONE_FIXED; |
| | 3006 | mat[2][2] = (double) m->mat33 / ONE_FIXED; |
| | 3007 | |
| | 3008 | double tr = mat[0][0]+mat[1][1]+mat[2][2]; |
| | 3009 | |
| | 3010 | if (tr > 0.0) |
| | 3011 | { |
| | 3012 | double s = sqrt(tr+1.0); |
| | 3013 | q[W] = s*0.5; |
| | 3014 | s = 0.5/s; |
| | 3015 | |
| | 3016 | q[X] = (mat[1][2] - mat[2][1])*s; |
| | 3017 | q[Y] = (mat[2][0] - mat[0][2])*s; |
| | 3018 | q[Z] = (mat[0][1] - mat[1][0])*s; |
| | 3019 | } |
| | 3020 | else |
| | 3021 | { |
| | 3022 | i = X; |
| | 3023 | if (mat[Y][Y] > mat[X][X]) |
| | 3024 | i = Y; |
| | 3025 | |
| | 3026 | if (mat[Z][Z] > mat[i][i]) |
| | 3027 | i = Z; |
| | 3028 | |
| | 3029 | j = nxt[i]; k = nxt[j]; |
| | 3030 | |
| | 3031 | double s = sqrt((mat[i][i] - (mat[j][j]+mat[k][k])) + 1.0); |
| | 3032 | |
| | 3033 | q[i] = s*0.5; |
| | 3034 | s = 0.5/s; |
| | 3035 | q[W] = (mat[j][k] - mat[k][j])*s; |
| | 3036 | q[j] = (mat[i][j] + mat[j][i])*s; |
| | 3037 | q[k] = (mat[i][k] + mat[k][i])*s; |
| | 3038 | } |
| | 3039 | |
| | 3040 | quat->quatx = (int) ((double) q[X]*65536.0); |
| | 3041 | quat->quaty = (int) ((double) q[Y]*65536.0); |
| | 3042 | quat->quatz = (int) ((double) q[Z]*65536.0); |
| | 3043 | quat->quatw = (int) ((double) q[W]*65536.0); |
| | 3044 | |
| | 3045 | quat->quatw = -quat->quatw; |
| | 3046 | |
| | 3047 | QNormalise(quat); |
| | 3048 | } |
| | 3049 | |
| | 3050 | static void Init_Tweening_Recursion(SECTION_DATA *this_section_data, int target_sequence_type,int target_subsequence, int seconds_for_tweening, int backwards) |
| | 3051 | { |
| | 3052 | /* Firstly, store current state. */ |
| | 3053 | |
| | 3054 | this_section_data->stored_offset = this_section_data->Offset; |
| | 3055 | MatToQuat(&this_section_data->RelSecMat,&this_section_data->stored_quat); |
| | 3056 | |
| | 3057 | /* Now, get target state. */ |
| | 3058 | |
| | 3059 | SEQUENCE *sequence_ptr = GetSequencePointer(target_sequence_type, target_subsequence, this_section_data->sempai); |
| | 3060 | |
| | 3061 | if (backwards) |
| | 3062 | { |
| | 3063 | KEYFRAME_DATA *current_frame = sequence_ptr->last_frame; |
| | 3064 | /* Deduce last frame. */ |
| | 3065 | |
| | 3066 | /* Must now have the last frame. */ |
| | 3067 | GetKeyFrameOffset(current_frame, &this_section_data->target_offset); |
| | 3068 | CopyShortQuatToInt(¤t_frame->QOrient, &this_section_data->target_quat); |
| | 3069 | } |
| | 3070 | else |
| | 3071 | { |
| | 3072 | GetKeyFrameOffset(sequence_ptr->first_frame, &this_section_data->target_offset); |
| | 3073 | CopyShortQuatToInt(&sequence_ptr->first_frame->QOrient, &this_section_data->target_quat); |
| | 3074 | } |
| | 3075 | |
| | 3076 | this_section_data->delta_offset.vx = this_section_data->target_offset.vx-this_section_data->stored_offset.vx; |
| | 3077 | this_section_data->delta_offset.vy = this_section_data->target_offset.vy-this_section_data->stored_offset.vy; |
| | 3078 | this_section_data->delta_offset.vz = this_section_data->target_offset.vz-this_section_data->stored_offset.vz; |
| | 3079 | |
| | 3080 | { |
| | 3081 | QUAT *this_quat = &this_section_data->stored_quat; |
| | 3082 | QUAT *next_quat = &this_section_data->target_quat; |
| | 3083 | int cosom = QDot(this_quat,next_quat); |
| | 3084 | |
| | 3085 | if (cosom < 0) |
| | 3086 | { |
| | 3087 | next_quat->quatx = -next_quat->quatx; |
| | 3088 | next_quat->quaty = -next_quat->quaty; |
| | 3089 | next_quat->quatz = -next_quat->quatz; |
| | 3090 | next_quat->quatw = -next_quat->quatw; |
| | 3091 | |
| | 3092 | cosom = -cosom; |
| | 3093 | } |
| | 3094 | |
| | 3095 | this_section_data->omega = ArcCos(cosom); |
| | 3096 | |
| | 3097 | if (GetSin(this_section_data->omega)) |
| | 3098 | this_section_data->oneoversinomega = GetOneOverSin(this_section_data->omega); |
| | 3099 | else |
| | 3100 | this_section_data->omega = this_section_data->oneoversinomega = 0; /* Yuk. */ |
| | 3101 | |
| | 3102 | assert(seconds_for_tweening > 0); |
| | 3103 | this_section_data->oneovertweeninglength = DIV_FIXED(ONE_FIXED,seconds_for_tweening); |
| | 3104 | } |
| | 3105 | |
| | 3106 | /* Init fields... I guess. */ |
| | 3107 | |
| | 3108 | this_section_data->current_sequence = sequence_ptr; |
| | 3109 | this_section_data->current_keyframe = sequence_ptr->first_frame; |
| | 3110 | this_section_data->accumulated_timer = 0; |
| | 3111 | this_section_data->freezeframe_timer = -1; |
| | 3112 | this_section_data->lastframe_timer = 0; |
| | 3113 | this_section_data->gore_timer = 0; /* As good a time as any. */ |
| | 3114 | this_section_data->Tweening = 1; |
| | 3115 | |
| | 3116 | /* Animation? */ |
| | 3117 | /* Nah. */ |
| | 3118 | /* Recurse. */ |
| | 3119 | |
| | 3120 | if ( (this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 3121 | { |
| | 3122 | /* Respect the terminator! */ |
| | 3123 | |
| | 3124 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 3125 | |
| | 3126 | while (child_list_ptr != NULL) |
| | 3127 | { |
| | 3128 | Init_Tweening_Recursion(child_list_ptr,target_sequence_type,target_subsequence,seconds_for_tweening,backwards); |
| | 3129 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 3130 | } |
| | 3131 | } |
| | 3132 | } |
| | 3133 | |
| | 3134 | void InitHModelTweening(HMODELCONTROLLER *controller, int seconds_for_tweening, int target_sequence_type, int target_subsequence, int
target_seconds_for_sequence, int loop) |
| | 3135 | { |
| | 3136 | /* Just set it up... */ |
| | 3137 | assert(target_seconds_for_sequence); |
| | 3138 | |
| | 3139 | controller->Sequence_Type = target_sequence_type; |
| | 3140 | controller->Sub_Sequence = target_subsequence; |
| | 3141 | controller->Seconds_For_Sequence = seconds_for_tweening; |
| | 3142 | controller->timer_increment = DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); |
| | 3143 | controller->sequence_timer = 0; |
| | 3144 | controller->Playing = 1; |
| | 3145 | controller->Reversed = 0; |
| | 3146 | controller->Looped = 1; |
| | 3147 | |
| | 3148 | controller->After_Tweening_Sequence_Type = target_sequence_type; |
| | 3149 | controller->After_Tweening_Sub_Sequence = target_subsequence; |
| | 3150 | controller->AT_seconds_for_sequence = target_seconds_for_sequence; |
| | 3151 | controller->AT_sequence_timer = 0; |
| | 3152 | controller->Tweening = Controller_Tweening; |
| | 3153 | controller->LoopAfterTweening = loop; |
| | 3154 | controller->StopAfterTweening = controller->ElevationTweening = 0; |
| | 3155 | |
| | 3156 | /* Recurse though hierarchy, setting up all the section_data sequence stores? */ |
| | 3157 | |
| | 3158 | Init_Tweening_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,0); |
| | 3159 | } |
| | 3160 | |
| | 3161 | void InitHModelTweening_Backwards(HMODELCONTROLLER *controller, int seconds_for_tweening, int target_sequence_type, int target_subsequence, int
target_seconds_for_sequence, int loop) |
| | 3162 | { |
| | 3163 | /* Ooh, yuck. */ |
| | 3164 | assert(target_seconds_for_sequence); |
| | 3165 | |
| | 3166 | controller->Sequence_Type = target_sequence_type; |
| | 3167 | controller->Sub_Sequence = target_subsequence; |
| | 3168 | controller->Seconds_For_Sequence = seconds_for_tweening; |
| | 3169 | controller->timer_increment = DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); |
| | 3170 | controller->sequence_timer = 0; |
| | 3171 | controller->Playing = controller->Reversed = controller->Looped = 1; |
| | 3172 | |
| | 3173 | controller->After_Tweening_Sequence_Type = target_sequence_type; |
| | 3174 | controller->After_Tweening_Sub_Sequence = target_subsequence; |
| | 3175 | controller->AT_seconds_for_sequence = target_seconds_for_sequence; |
| | 3176 | controller->AT_sequence_timer = (ONE_FIXED-1); |
| | 3177 | controller->Tweening = Controller_Tweening; |
| | 3178 | controller->LoopAfterTweening= loop; |
| | 3179 | controller->StopAfterTweening = controller->ElevationTweening = 0; |
| | 3180 | |
| | 3181 | /* Recurse though hierarchy, setting up all the section_data sequence stores? */ |
| | 3182 | |
| | 3183 | Init_Tweening_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,1); |
| | 3184 | } |
| | 3185 | |
| | 3186 | static void FindHeatSource_Recursion(HMODELCONTROLLER *controllerPtr, SECTION_DATA *sectionDataPtr) |
| | 3187 | { |
| | 3188 | /* KJL 16:29:40 10/02/98 - Recurse through hmodel */ |
| | 3189 | if ((sectionDataPtr->First_Child != NULL) && !(sectionDataPtr->flags & section_data_terminate_here)) |
| | 3190 | { |
| | 3191 | SECTION_DATA *childSectionPtr = sectionDataPtr->First_Child; |
| | 3192 | |
| | 3193 | while (childSectionPtr != NULL) |
| | 3194 | { |
| | 3195 | assert(childSectionPtr->My_Parent == sectionDataPtr); |
| | 3196 | |
| | 3197 | FindHeatSource_Recursion(controllerPtr,childSectionPtr); |
| | 3198 | childSectionPtr = childSectionPtr->Next_Sibling; |
| | 3199 | } |
| | 3200 | } |
| | 3201 | |
| | 3202 | /* KJL 16:30:03 10/02/98 - record heat source */ |
| | 3203 | if (sectionDataPtr->sempai->flags & section_flag_heatsource) |
| | 3204 | { |
| | 3205 | /* KJL 16:36:58 10/02/98 - currently just position; could have size, orientation, etc. */ |
| | 3206 | HeatSourceList[NumberOfHeatSources].Position.vx = sectionDataPtr->World_Offset.vx; |
| | 3207 | HeatSourceList[NumberOfHeatSources].Position.vy = sectionDataPtr->World_Offset.vy; |
| | 3208 | HeatSourceList[NumberOfHeatSources].Position.vz = sectionDataPtr->World_Offset.vz; |
| | 3209 | TranslatePointIntoViewspace(&HeatSourceList[NumberOfHeatSources].Position); |
| | 3210 | NumberOfHeatSources++; |
| | 3211 | } |
| | 3212 | } |
| | 3213 | |
| | 3214 | /* KJL 16:51:20 10/02/98 - Heat source stuff */ |
| | 3215 | |
| | 3216 | void FindHeatSourcesInHModel(DISPLAYBLOCK *dispPtr) |
| | 3217 | { |
| | 3218 | HMODELCONTROLLER *controllerPtr = dispPtr->HModelControlBlock; |
| | 3219 | |
| | 3220 | /* KJL 16:36:12 10/02/98 - check positions are up to date */ |
| | 3221 | ProveHModel(controllerPtr, dispPtr); |
| | 3222 | |
| | 3223 | /* KJL 16:36:25 10/02/98 - process model */ |
| | 3224 | FindHeatSource_Recursion(controllerPtr, controllerPtr->section_data); |
| | 3225 | } |
| | 3226 | |
| | 3227 | DELTA_CONTROLLER *Get_Delta_Sequence(HMODELCONTROLLER *controller,char *id) |
| | 3228 | { |
| | 3229 | /* Get the controller that matches id. */ |
| | 3230 | DELTA_CONTROLLER *delta_controller = controller->Deltas; |
| | 3231 | |
| | 3232 | while (delta_controller) |
| | 3233 | { |
| | 3234 | if (!strcmp(id, delta_controller->id)) |
| | 3235 | break; |
| | 3236 | |
| | 3237 | delta_controller = delta_controller->next_controller; |
| | 3238 | } |
| | 3239 | |
| | 3240 | return delta_controller; |
| | 3241 | } |
| | 3242 | |
| | 3243 | void Remove_Delta_Sequence(HMODELCONTROLLER *controller,char *id) |
| | 3244 | { |
| | 3245 | DELTA_CONTROLLER *delta_controller = controller->Deltas; |
| | 3246 | DELTA_CONTROLLER **source = &controller->Deltas; |
| | 3247 | |
| | 3248 | while (delta_controller) |
| | 3249 | { |
| | 3250 | if (!strcmp(id, delta_controller->id)) |
| | 3251 | break; |
| | 3252 | |
| | 3253 | source = &delta_controller->next_controller; |
| | 3254 | delta_controller = delta_controller->next_controller; |
| | 3255 | } |
| | 3256 | |
| | 3257 | if (delta_controller) |
| | 3258 | { |
| | 3259 | /* Remove it. */ |
| | 3260 | *source = delta_controller->next_controller; |
| | 3261 | |
| | 3262 | free(delta_controller->id); |
| | 3263 | delta_controller->id = NULL; |
| | 3264 | free(delta_controller); |
| | 3265 | delta_controller = NULL; |
| | 3266 | } |
| | 3267 | } |
| | 3268 | |
| | 3269 | DELTA_CONTROLLER *Add_Delta_Sequence(HMODELCONTROLLER *controller,char *id,int sequence_type,int sub_sequence, int seconds_for_sequence) |
| | 3270 | { |
| | 3271 | DELTA_CONTROLLER *delta_controller = malloc(sizeof(DELTA_CONTROLLER)); |
| | 3272 | |
| | 3273 | assert(delta_controller); |
| | 3274 | |
| | 3275 | delta_controller->next_controller = controller->Deltas; |
| | 3276 | controller->Deltas = delta_controller; |
| | 3277 | |
| | 3278 | delta_controller->id = malloc(strlen(id)+1); |
| | 3279 | strcpy(delta_controller->id,id); |
| | 3280 | |
| | 3281 | delta_controller->sequence_type = sequence_type; |
| | 3282 | delta_controller->sub_sequence = sub_sequence; |
| | 3283 | delta_controller->timer = 0; |
| | 3284 | delta_controller->lastframe_timer = -1; |
| | 3285 | delta_controller->Looped = 0; |
| | 3286 | delta_controller->Playing = 0; |
| | 3287 | delta_controller->Active = 1; /* By default. */ |
| | 3288 | delta_controller->my_hmodel_controller = controller; |
| | 3289 | |
| | 3290 | SEQUENCE *this_sequence = GetSequencePointer(sequence_type,sub_sequence,delta_controller->my_hmodel_controller->Root_Section); |
| | 3291 | |
| | 3292 | assert(this_sequence->first_frame); |
| | 3293 | |
| | 3294 | if (seconds_for_sequence >= 0) |
| | 3295 | { |
| | 3296 | delta_controller->seconds_for_sequence = seconds_for_sequence; // Special case, 0 is legal. |
| | 3297 | } |
| | 3298 | else |
| | 3299 | { |
| | 3300 | delta_controller->seconds_for_sequence = this_sequence->Time; |
| | 3301 | |
| | 3302 | if (delta_controller->seconds_for_sequence <= 0) |
| | 3303 | { |
| | 3304 | delta_controller->seconds_for_sequence = ONE_FIXED; |
| | 3305 | /* Might want to assert here? */ |
| | 3306 | } |
| | 3307 | } |
| | 3308 | |
| | 3309 | if (delta_controller->seconds_for_sequence) |
| | 3310 | delta_controller->timer_increment = DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence); |
| | 3311 | else |
| | 3312 | delta_controller->timer_increment = 0; |
| | 3313 | |
| | 3314 | return delta_controller; |
| | 3315 | } |
| | 3316 | |
| | 3317 | void Start_Delta_Sequence(DELTA_CONTROLLER *delta_controller,int sequence_type,int sub_sequence,int seconds_for_sequence) |
| | 3318 | { |
| | 3319 | assert(delta_controller); |
| | 3320 | |
| | 3321 | /* Again, you must start it and loop it by hand. */ |
| | 3322 | |
| | 3323 | delta_controller->sequence_type = sequence_type; |
| | 3324 | delta_controller->sub_sequence = sub_sequence; |
| | 3325 | delta_controller->timer = delta_controller->Looped = delta_controller->Playing = 0; |
| | 3326 | |
| | 3327 | SEQUENCE *this_sequence = GetSequencePointer(sequence_type,sub_sequence,delta_controller->my_hmodel_controller->Root_Section); |
| | 3328 | |
| | 3329 | if (seconds_for_sequence >= 0) |
| | 3330 | { |
| | 3331 | delta_controller->seconds_for_sequence = seconds_for_sequence; // Special case, 0 is legal. |
| | 3332 | } |
| | 3333 | else |
| | 3334 | { |
| | 3335 | delta_controller->seconds_for_sequence = this_sequence->Time; |
| | 3336 | |
| | 3337 | if (delta_controller->seconds_for_sequence <= 0) |
| | 3338 | { |
| | 3339 | delta_controller->seconds_for_sequence = ONE_FIXED; |
| | 3340 | /* Might want to assert here? */ |
| | 3341 | } |
| | 3342 | } |
| | 3343 | |
| | 3344 | if (delta_controller->seconds_for_sequence) |
| | 3345 | delta_controller->timer_increment = DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence); |
| | 3346 | else |
| | 3347 | delta_controller->timer_increment = 0; |
| | 3348 | } |
| | 3349 | |
| | 3350 | void Delta_Sequence_ChangeSpeed(DELTA_CONTROLLER *delta_controller,int seconds_for_sequence) |
| | 3351 | { |
| | 3352 | assert(delta_controller); |
| | 3353 | |
| | 3354 | delta_controller->seconds_for_sequence = seconds_for_sequence; // Special case. |
| | 3355 | |
| | 3356 | if (delta_controller->seconds_for_sequence) |
| | 3357 | delta_controller->timer_increment = DIV_FIXED(ONE_FIXED,delta_controller->seconds_for_sequence); |
| | 3358 | else |
| | 3359 | delta_controller->timer_increment = 0; |
| | 3360 | } |
| | 3361 | |
| | 3362 | static SECTION *Get_Corresponding_Section(SECTION **List_Ptr,char *Name) |
| | 3363 | { |
| | 3364 | SECTION **child_list_ptr = List_Ptr; |
| | 3365 | |
| | 3366 | while (*child_list_ptr != NULL) |
| | 3367 | { |
| | 3368 | if (!strcmp((*child_list_ptr)->Section_Name,Name)) |
| | 3369 | break; |
| | 3370 | |
| | 3371 | child_list_ptr++; |
| | 3372 | } |
| | 3373 | |
| | 3374 | return *child_list_ptr; |
| | 3375 | } |
| | 3376 | |
| | 3377 | static SECTION_DATA *GetThisSectionData_FromChildrenOnly(const SECTION_DATA *parent, char *name) |
| | 3378 | { |
| | 3379 | if (parent && name) |
| | 3380 | { |
| | 3381 | if (parent->First_Child != NULL) |
| | 3382 | { |
| | 3383 | SECTION_DATA *child_list_ptr = parent->First_Child; |
| | 3384 | |
| | 3385 | while (child_list_ptr != NULL) |
| | 3386 | { |
| | 3387 | if (!strcmp(name,child_list_ptr->sempai->Section_Name)) |
| | 3388 | { |
| | 3389 | /* Got it. */ |
| | 3390 | return(child_list_ptr); |
| | 3391 | } |
| | 3392 | |
| | 3393 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 3394 | } |
| | 3395 | } |
| | 3396 | } |
| | 3397 | |
| | 3398 | return NULL; |
| | 3399 | } |
| | 3400 | |
| | 3401 | static void |
| | 3402 | Transmogrification_Recursion(STRATEGYBLOCK *sbPtr, HMODELCONTROLLER *controller, SECTION_DATA *this_section_data, const SECTION *new_template, const SECTION
*old_template, int frag, int newsections, int regrowsections) |
| | 3403 | { |
| | 3404 | /* Doesn't really matter which tree we're walking... does it? */ |
| | 3405 | |
| | 3406 | assert(new_template); |
| | 3407 | assert(old_template); |
| | 3408 | assert(strcmp(new_template->Section_Name,old_template->Section_Name) == 0); |
| | 3409 | assert(this_section_data); |
| | 3410 | |
| | 3411 | if ( (new_template->Children != NULL) && (old_template->Children != NULL) ) |
| | 3412 | { |
| | 3413 | /* Complex. I'd really like to walk both at the same time. */ |
| | 3414 | SECTION **new_child_list_ptr = new_template->Children; |
| | 3415 | SECTION **old_child_list_ptr = old_template->Children; |
| | 3416 | |
| | 3417 | /* First, let's walk the new template. */ |
| | 3418 | while (*new_child_list_ptr != NULL) |
| | 3419 | { |
| | 3420 | SECTION *corresponding_section = Get_Corresponding_Section(old_child_list_ptr,(*new_child_list_ptr)->Section_Name); |
| | 3421 | |
| | 3422 | if (corresponding_section != NULL) |
| | 3423 | { |
| | 3424 | /* Section also exists in old template. Deal with it and recurse. */ |
| | 3425 | SECTION_DATA *child_section_data = GetThisSectionData_FromChildrenOnly(this_section_data,(*new_child_list_ptr)->Section_Name); |
| | 3426 | |
| | 3427 | if (child_section_data) |
| | 3428 | { |
| | 3429 | /* Hey, it might be fragged off. Now deal with it. */ |
| | 3430 | |
| | 3431 | child_section_data->sempai = *new_child_list_ptr; |
| | 3432 | |
| | 3433 | Transmogrification_Recursion(sbPtr,controller,child_section_data,*new_child_list_ptr, corresponding_section, frag, newsections, regrowsections); |
| | 3434 | } |
| | 3435 | else if (regrowsections) |
| | 3436 | { |
| | 3437 | /* If it is fragged off, put it back. */ |
| | 3438 | SECTION_DATA *new_child = Create_New_Section(*new_child_list_ptr); |
| | 3439 | |
| | 3440 | new_child->My_Parent = this_section_data; |
| | 3441 | new_child->Prev_Sibling = NULL; |
| | 3442 | new_child->Next_Sibling = this_section_data->First_Child; |
| | 3443 | |
| | 3444 | if (this_section_data->First_Child) |
| | 3445 | this_section_data->First_Child->Prev_Sibling = new_child; |
| | 3446 | |
| | 3447 | this_section_data->First_Child = new_child; |
| | 3448 | Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence); |
| | 3449 | /* Prove new positions. */ |
| | 3450 | Process_Section(controller, new_child, &this_section_data->World_Offset, &this_section_data->SecMat, 0, controller->Sequence_Type,
controller->Sub_Sequence, 0); |
| | 3451 | } |
| | 3452 | } |
| | 3453 | else if (newsections) |
| | 3454 | { |
| | 3455 | /* No corresponding old section: create a new bit. */ |
| | 3456 | SECTION_DATA *new_child = Create_New_Section(*new_child_list_ptr); |
| | 3457 | |
| | 3458 | new_child->My_Parent = this_section_data; |
| | 3459 | new_child->Prev_Sibling = NULL; |
| | 3460 | new_child->Next_Sibling = this_section_data->First_Child; |
| | 3461 | |
| | 3462 | if (this_section_data->First_Child) |
| | 3463 | this_section_data->First_Child->Prev_Sibling = new_child; |
| | 3464 | |
| | 3465 | this_section_data->First_Child = new_child; |
| | 3466 | Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence); |
| | 3467 | /* Prove new positions. */ |
| | 3468 | Process_Section(controller, new_child, &this_section_data->World_Offset, &this_section_data->SecMat, 0, controller->Sequence_Type,
controller->Sub_Sequence, 0); |
| | 3469 | } |
| | 3470 | |
| | 3471 | new_child_list_ptr++; |
| | 3472 | } |
| | 3473 | |
| | 3474 | /* Now, let's walk the old template. */ |
| | 3475 | new_child_list_ptr = new_template->Children; |
| | 3476 | |
| | 3477 | while (*old_child_list_ptr != NULL) |
| | 3478 | { |
| | 3479 | SECTION *corresponding_section = Get_Corresponding_Section(new_child_list_ptr,(*old_child_list_ptr)->Section_Name); |
| | 3480 | |
| | 3481 | if (corresponding_section != NULL) |
| | 3482 | { |
| | 3483 | /* Section also exists in new template. Do nothing, it should already have been dealt with. */ |
| | 3484 | } |
| | 3485 | else |
| | 3486 | { |
| | 3487 | /* No corresponding new section: delete this branch. */ |
| | 3488 | SECTION_DATA *superfluous_section = GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name); |
| | 3489 | |
| | 3490 | if (superfluous_section) |
| | 3491 | { |
| | 3492 | if (frag) |
| | 3493 | //MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset,
&superfluous_section->SecMat,NULL,2); // jadda |
| | 3494 | MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset, &superfluous_section->SecMat,NULL,2,
NULL); |
| | 3495 | |
| | 3496 | Prune_Section(superfluous_section); |
| | 3497 | } |
| | 3498 | } |
| | 3499 | |
| | 3500 | old_child_list_ptr++; |
| | 3501 | } |
| | 3502 | } |
| | 3503 | else if (new_template->Children != NULL) |
| | 3504 | { |
| | 3505 | if (newsections) |
| | 3506 | { |
| | 3507 | /* A whole lotta new branches. */ |
| | 3508 | SECTION **new_child_list_ptr = new_template->Children; |
| | 3509 | |
| | 3510 | while (*new_child_list_ptr != NULL) |
| | 3511 | { |
| | 3512 | SECTION_DATA *new_child = Create_New_Section(*new_child_list_ptr); |
| | 3513 | |
| | 3514 | new_child->My_Parent = this_section_data; |
| | 3515 | new_child->Prev_Sibling = NULL; |
| | 3516 | new_child->Next_Sibling = this_section_data->First_Child; |
| | 3517 | |
| | 3518 | if (this_section_data->First_Child) |
| | 3519 | this_section_data->First_Child->Prev_Sibling = new_child; |
| | 3520 | |
| | 3521 | this_section_data->First_Child = new_child; |
| | 3522 | |
| | 3523 | Init_Sequence_Recursion(new_child, controller->Sequence_Type, controller->Sub_Sequence,controller->Seconds_For_Sequence); |
| | 3524 | |
| | 3525 | new_child_list_ptr++; |
| | 3526 | } |
| | 3527 | } |
| | 3528 | } |
| | 3529 | else if (old_template->Children != NULL) |
| | 3530 | { |
| | 3531 | /* Remove all branches. */ |
| | 3532 | SECTION_DATA *data_child_ptr = this_section_data->First_Child; |
| | 3533 | |
| | 3534 | while (data_child_ptr != NULL) |
| | 3535 | { |
| | 3536 | assert(data_child_ptr->My_Parent == this_section_data); |
| | 3537 | SECTION_DATA *next_one = data_child_ptr->Next_Sibling; |
| | 3538 | |
| | 3539 | if (frag) |
| | 3540 | //MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2); |
| | 3541 | MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2, NULL); // jadda |
| | 3542 | |
| | 3543 | Prune_Section(data_child_ptr); |
| | 3544 | data_child_ptr = next_one; |
| | 3545 | } |
| | 3546 | } |
| | 3547 | } |
| | 3548 | |
| | 3549 | void Transmogrify_HModels(STRATEGYBLOCK *sbPtr, HMODELCONTROLLER *controller, const SECTION *new_template, int frag, int newsections, int regrowsections) |
| | 3550 | { |
| | 3551 | /* Convert one HModel to another template... */ |
| | 3552 | Global_Controller_Ptr = controller; |
| | 3553 | const SECTION *old_template = controller->Root_Section; |
| | 3554 | |
| | 3555 | /* Compare the two templates to each other. */ |
| | 3556 | |
| | 3557 | assert(controller->section_data->sempai == old_template); |
| | 3558 | |
| | 3559 | controller->section_data->sempai = new_template; |
| | 3560 | |
| | 3561 | Transmogrification_Recursion(sbPtr, controller, controller->section_data, new_template, old_template, frag, newsections, regrowsections); |
| | 3562 | |
| | 3563 | controller->Root_Section = new_template; |
| | 3564 | } |
| | 3565 | |
| | 3566 | static void TrimToTemplate_Recursion(STRATEGYBLOCK *sbPtr, HMODELCONTROLLER *controller, const SECTION_DATA *this_section_data, const SECTION *new_template,
const SECTION *old_template, int frag) |
| | 3567 | { |
| | 3568 | /* Doesn't really matter which tree we're walking... does it? */ |
| | 3569 | |
| | 3570 | assert(new_template); |
| | 3571 | assert(old_template); |
| | 3572 | assert(strcmp(new_template->Section_Name,old_template->Section_Name)==0); |
| | 3573 | assert(this_section_data); |
| | 3574 | |
| | 3575 | if ( (new_template->Children != NULL) && (old_template->Children != NULL) ) |
| | 3576 | { |
| | 3577 | /* Complex. I'd really like to walk both at the same time. */ |
| | 3578 | SECTION **new_child_list_ptr = new_template->Children; |
| | 3579 | SECTION **old_child_list_ptr = old_template->Children; |
| | 3580 | |
| | 3581 | /* Let's walk the old template. */ |
| | 3582 | while (*old_child_list_ptr != NULL) |
| | 3583 | { |
| | 3584 | SECTION *corresponding_section = Get_Corresponding_Section(new_child_list_ptr,(*old_child_list_ptr)->Section_Name); |
| | 3585 | |
| | 3586 | if (corresponding_section != NULL) |
| | 3587 | { |
| | 3588 | /* Section also exists in new template. Recurse. */ |
| | 3589 | SECTION_DATA *child_section_data = GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name); |
| | 3590 | |
| | 3591 | if (child_section_data) |
| | 3592 | { |
| | 3593 | /* Hey, it might be fragged off. Now deal with it. */ |
| | 3594 | |
| | 3595 | TrimToTemplate_Recursion(sbPtr,controller,child_section_data,corresponding_section,*old_child_list_ptr, frag); |
| | 3596 | } |
| | 3597 | } |
| | 3598 | else |
| | 3599 | { |
| | 3600 | /* No corresponding new section: delete this branch. */ |
| | 3601 | SECTION_DATA *superfluous_section = GetThisSectionData_FromChildrenOnly(this_section_data,(*old_child_list_ptr)->Section_Name); |
| | 3602 | |
| | 3603 | if (superfluous_section) |
| | 3604 | { |
| | 3605 | if (frag) |
| | 3606 | //MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset,
&superfluous_section->SecMat,NULL,2); // jadda |
| | 3607 | MakeHierarchicalDebris(sbPtr,superfluous_section, &superfluous_section->World_Offset, &superfluous_section->SecMat,NULL,2,
NULL); |
| | 3608 | |
| | 3609 | Prune_Section(superfluous_section); |
| | 3610 | } |
| | 3611 | } |
| | 3612 | |
| | 3613 | old_child_list_ptr++; |
| | 3614 | } |
| | 3615 | } |
| | 3616 | else if (old_template->Children != NULL) |
| | 3617 | { |
| | 3618 | /* Remove all branches. */ |
| | 3619 | SECTION_DATA *data_child_ptr = this_section_data->First_Child; |
| | 3620 | |
| | 3621 | while (data_child_ptr != NULL) |
| | 3622 | { |
| | 3623 | assert(data_child_ptr->My_Parent==this_section_data); |
| | 3624 | SECTION_DATA *next_one = data_child_ptr->Next_Sibling; |
| | 3625 | |
| | 3626 | if (frag) |
| | 3627 | //MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2); |
| | 3628 | MakeHierarchicalDebris(sbPtr,data_child_ptr, &data_child_ptr->World_Offset, &data_child_ptr->SecMat,NULL,2 ,NULL); // jadda |
| | 3629 | |
| | 3630 | Prune_Section(data_child_ptr); |
| | 3631 | |
| | 3632 | data_child_ptr = next_one; |
| | 3633 | } |
| | 3634 | } |
| | 3635 | } |
| | 3636 | |
| | 3637 | void TrimToTemplate(STRATEGYBLOCK *sbPtr, HMODELCONTROLLER *controller, const SECTION *new_template, int frag) |
| | 3638 | { |
| | 3639 | /* Convert one HModel to another template... */ |
| | 3640 | const SECTION *old_template = controller->Root_Section; |
| | 3641 | |
| | 3642 | /* Compare the two templates to each other. */ |
| | 3643 | |
| | 3644 | #if DEBUG |
| | 3645 | assert(controller->section_data->sempai == old_template); |
| | 3646 | if (strcmp(new_template->Section_Name, old_template->Section_Name)) |
| | 3647 | { |
| | 3648 | assert(strcmp(new_template->Section_Name,old_template->Section_Name) == 0); |
| | 3649 | } |
| | 3650 | #endif |
| | 3651 | |
| | 3652 | TrimToTemplate_Recursion(sbPtr, controller, controller->section_data, new_template, old_template, frag); |
| | 3653 | } |
| | 3654 | |
| | 3655 | int HModelSequence_Exists(HMODELCONTROLLER *controller,int sequence_type,int sub_sequence) |
| | 3656 | { |
| | 3657 | int a = 0; |
| | 3658 | int sequence_id = GetSequenceID(sequence_type, sub_sequence); |
| | 3659 | |
| | 3660 | for (; a < controller->Root_Section->num_sequences; a++) |
| | 3661 | { |
| | 3662 | if (controller->Root_Section->sequence_array[a].sequence_id == sequence_id) |
| | 3663 | return 1; |
| | 3664 | } |
| | 3665 | |
| | 3666 | return 0; |
| | 3667 | } |
| | 3668 | |
| | 3669 | int HModelSequence_Exists_FromRoot(const SECTION *root, int sequence_type, int sub_sequence) |
| | 3670 | { |
| | 3671 | if (root) |
| | 3672 | { |
| | 3673 | int a = 0; |
| | 3674 | int sequence_id = GetSequenceID(sequence_type,sub_sequence); |
| | 3675 | |
| | 3676 | for (; a < root->num_sequences; a++) |
| | 3677 | { |
| | 3678 | if (root->sequence_array[a].sequence_id == sequence_id) |
| | 3679 | return 1; |
| | 3680 | } |
| | 3681 | } |
| | 3682 | |
| | 3683 | return 0; |
| | 3684 | } |
| | 3685 | |
| | 3686 | static void HModelRegen_Recursion(SECTION_DATA *this_section_data, int time) |
| | 3687 | { |
| | 3688 | /* Regenerate this section. */ |
| | 3689 | if (this_section_data->current_damage.Health != (this_section_data->sempai->StartingStats.Health << ONE_FIXED_SHIFT)) |
| | 3690 | { |
| | 3691 | this_section_data->current_damage.Health += DIV_FIXED((this_section_data->sempai->StartingStats.Health * NormalFrameTime), time); |
| | 3692 | //printf("healing %d orig %d\n", this_section_data->current_damage.Health, (this_section_data->sempai->StartingStats.Health <<
ONE_FIXED_SHIFT)); |
| | 3693 | |
| | 3694 | if (this_section_data->current_damage.Health > (this_section_data->sempai->StartingStats.Health << ONE_FIXED_SHIFT)) |
| | 3695 | { |
| | 3696 | this_section_data->current_damage.Health = (this_section_data->sempai->StartingStats.Health << ONE_FIXED_SHIFT); |
| | 3697 | this_section_data->NumberOfDecals = 0; |
| | 3698 | } |
| | 3699 | } |
| | 3700 | |
| | 3701 | /* Now call recursion... */ |
| | 3702 | |
| | 3703 | if (this_section_data->First_Child != NULL) |
| | 3704 | { |
| | 3705 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 3706 | |
| | 3707 | while (child_list_ptr != NULL) |
| | 3708 | { |
| | 3709 | HModelRegen_Recursion(child_list_ptr,time); |
| | 3710 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 3711 | } |
| | 3712 | } |
| | 3713 | } |
| | 3714 | |
| | 3715 | void HModel_Regen(HMODELCONTROLLER *controller,int time) |
| | 3716 | { |
| | 3717 | /* Regenerate sections. */ |
| | 3718 | |
| | 3719 | HModelRegen_Recursion(controller->section_data, time); |
| | 3720 | } |
| | 3721 | |
| | 3722 | int HModelAnimation_IsFinished(HMODELCONTROLLER *controller) |
| | 3723 | { |
| | 3724 | /* This now gets used all over the place... */ |
| | 3725 | |
| | 3726 | if ((controller->Tweening != Controller_NoTweening) || controller->Looped) |
| | 3727 | return 0; |
| | 3728 | |
| | 3729 | if (controller->Reversed) |
| | 3730 | { |
| | 3731 | if (controller->sequence_timer) |
| | 3732 | return 0; |
| | 3733 | } |
| | 3734 | else if (controller->sequence_timer != (ONE_FIXED-1)) |
| | 3735 | { |
| | 3736 | return 0; |
| | 3737 | } |
| | 3738 | |
| | 3739 | return 1; |
| | 3740 | } |
| | 3741 | |
| | 3742 | int DeltaAnimation_IsFinished(DELTA_CONTROLLER *controller) |
| | 3743 | { |
| | 3744 | if (controller->Looped) |
| | 3745 | return 0; |
| | 3746 | |
| | 3747 | if (!controller->Playing || !controller->Active) |
| | 3748 | return 1; |
| | 3749 | |
| | 3750 | if (controller->timer != (ONE_FIXED-1)) |
| | 3751 | return 0; |
| | 3752 | return 1; |
| | 3753 | } |
| | 3754 | |
| | 3755 | SECTION *Get_Corresponding_Section_Recursive(SECTION *this_section,char *Name) |
| | 3756 | { |
| | 3757 | if (!strcmp(this_section->Section_Name,Name)) |
| | 3758 | return this_section; |
| | 3759 | |
| | 3760 | /* Recurse. */ |
| | 3761 | SECTION **child_list_ptr = this_section->Children; |
| | 3762 | |
| | 3763 | if (child_list_ptr) |
| | 3764 | { |
| | 3765 | while (*child_list_ptr != NULL) |
| | 3766 | { |
| | 3767 | SECTION *cosec = Get_Corresponding_Section_Recursive(*child_list_ptr,Name); |
| | 3768 | |
| | 3769 | if (cosec) |
| | 3770 | return cosec; /* Back out! */ |
| | 3771 | |
| | 3772 | child_list_ptr++; |
| | 3773 | } |
| | 3774 | } |
| | 3775 | |
| | 3776 | return NULL; |
| | 3777 | } |
| | 3778 | |
| | 3779 | static SECTION_DATA *GetSectionFromID_Recursion(SECTION_DATA *this_section_data, int IDnumber) |
| | 3780 | { |
| | 3781 | if (this_section_data->sempai->IDnumber == IDnumber) |
| | 3782 | return this_section_data; |
| | 3783 | |
| | 3784 | /* Now call recursion... */ |
| | 3785 | |
| | 3786 | if (this_section_data->First_Child != NULL) |
| | 3787 | { |
| | 3788 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 3789 | |
| | 3790 | while (child_list_ptr != NULL) |
| | 3791 | { |
| | 3792 | SECTION_DATA *sdptr = GetSectionFromID_Recursion(child_list_ptr, IDnumber); |
| | 3793 | |
| | 3794 | if (sdptr) |
| | 3795 | return sdptr; /* We got one! */ |
| | 3796 | |
| | 3797 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 3798 | } |
| | 3799 | } |
| | 3800 | |
| | 3801 | return NULL; |
| | 3802 | } |
| | 3803 | |
| | 3804 | SECTION_DATA *GetThisSectionData_FromID(SECTION_DATA *root, int IDnumber) |
| | 3805 | { |
| | 3806 | return ((root == NULL) ? NULL : GetSectionFromID_Recursion(root,IDnumber)); |
| | 3807 | } |
| | 3808 | |
| | 3809 | static SECTION *GetThisSection_FromID(SECTION *this_section,int IDnumber) |
| | 3810 | { |
| | 3811 | if (this_section) |
| | 3812 | { |
| | 3813 | //is this the section that we're looking for |
| | 3814 | if(this_section->IDnumber == IDnumber) |
| | 3815 | return this_section; |
| | 3816 | |
| | 3817 | //try this section's children then |
| | 3818 | if(this_section->Children) |
| | 3819 | { |
| | 3820 | SECTION **child_list_ptr = this_section->Children; |
| | 3821 | |
| | 3822 | while(*child_list_ptr) |
| | 3823 | { |
| | 3824 | SECTION* return_section = GetThisSection_FromID(*child_list_ptr,IDnumber); |
| | 3825 | |
| | 3826 | if(return_section) |
| | 3827 | return return_section; |
| | 3828 | |
| | 3829 | child_list_ptr++; |
| | 3830 | } |
| | 3831 | } |
| | 3832 | } |
| | 3833 | |
| | 3834 | return NULL; |
| | 3835 | } |
| | 3836 | |
| | 3837 | static void Init_Tweening_ToTheMiddle_Recursion(SECTION_DATA *this_section_data, int target_sequence_type,int target_subsequence, int seconds_for_tweening, int
target_sequence_timer, int backwards) |
| | 3838 | { |
| | 3839 | /* Firstly, store current state. */ |
| | 3840 | |
| | 3841 | this_section_data->stored_offset = this_section_data->Offset; |
| | 3842 | MatToQuat(&this_section_data->RelSecMat,&this_section_data->stored_quat); |
| | 3843 | |
| | 3844 | /* Now, get target state. */ |
| | 3845 | |
| | 3846 | SEQUENCE *sequence_ptr = GetSequencePointer(target_sequence_type,target_subsequence,this_section_data->sempai); |
| | 3847 | |
| | 3848 | /* Deduce target positions. Backwards flag is irrelevant... */ |
| | 3849 | |
| | 3850 | { |
| | 3851 | int working_timer = target_sequence_timer; |
| | 3852 | KEYFRAME_DATA *this_frame = sequence_ptr->first_frame; |
| | 3853 | KEYFRAME_DATA *next_frame; |
| | 3854 | |
| | 3855 | assert(this_frame); |
| | 3856 | |
| | 3857 | while (1) |
| | 3858 | { |
| | 3859 | if (this_frame->last_frame) |
| | 3860 | { |
| | 3861 | /* Low framerate loop? */ |
| | 3862 | next_frame = sequence_ptr->first_frame; |
| | 3863 | } |
| | 3864 | else |
| | 3865 | { |
| | 3866 | next_frame = this_frame->Next_Frame; |
| | 3867 | } |
| | 3868 | |
| | 3869 | if (working_timer >= this_frame->Sequence_Length) |
| | 3870 | { |
| | 3871 | /* We've gone beyond this frame: get next keyframe. */ |
| | 3872 | working_timer -= this_frame->Sequence_Length; |
| | 3873 | /* Advance frame... */ |
| | 3874 | this_frame = next_frame; |
| | 3875 | } |
| | 3876 | else |
| | 3877 | { |
| | 3878 | break; /* Exit loop with success. */ |
| | 3879 | } |
| | 3880 | /* Better make sure the last 'frame' has 65536 length... */ |
| | 3881 | } |
| | 3882 | |
| | 3883 | assert(working_timer >= 0); |
| | 3884 | /* Now we should have a frame and a timer. */ |
| | 3885 | int lerp = MUL_FIXED(working_timer,this_frame->oneoversequencelength); |
| | 3886 | |
| | 3887 | GetKeyFrameOffset(this_frame,&this_section_data->target_offset); |
| | 3888 | |
| | 3889 | if(next_frame->shift_offset) |
| | 3890 | { |
| | 3891 | VECTORCH next_offset; |
| | 3892 | GetKeyFrameOffset(next_frame,&next_offset); |
| | 3893 | this_section_data->target_offset.vx += MUL_FIXED(next_offset.vx - this_section_data->target_offset.vx,lerp); |
| | 3894 | this_section_data->target_offset.vy += MUL_FIXED(next_offset.vy - this_section_data->target_offset.vy,lerp); |
| | 3895 | this_section_data->target_offset.vz += MUL_FIXED(next_offset.vz - this_section_data->target_offset.vz,lerp); |
| | 3896 | } |
| | 3897 | else |
| | 3898 | { |
| | 3899 | this_section_data->target_offset.vx += MUL_FIXED((int)next_frame->Offset_x - this_section_data->target_offset.vx,lerp); |
| | 3900 | this_section_data->target_offset.vy += MUL_FIXED((int)next_frame->Offset_y - this_section_data->target_offset.vy,lerp); |
| | 3901 | this_section_data->target_offset.vz += MUL_FIXED((int)next_frame->Offset_z - this_section_data->target_offset.vz,lerp); |
| | 3902 | } |
| | 3903 | |
| | 3904 | /* Now deal with orientation. */ |
| | 3905 | |
| | 3906 | Slerp(this_frame,lerp,&this_section_data->target_quat); |
| | 3907 | } |
| | 3908 | |
| | 3909 | this_section_data->delta_offset.vx = this_section_data->target_offset.vx - this_section_data->stored_offset.vx; |
| | 3910 | this_section_data->delta_offset.vy = this_section_data->target_offset.vy - this_section_data->stored_offset.vy; |
| | 3911 | this_section_data->delta_offset.vz = this_section_data->target_offset.vz - this_section_data->stored_offset.vz; |
| | 3912 | |
| | 3913 | { |
| | 3914 | QUAT *this_quat = &this_section_data->stored_quat; |
| | 3915 | QUAT *next_quat = &this_section_data->target_quat; |
| | 3916 | int cosom = QDot(this_quat,next_quat); |
| | 3917 | |
| | 3918 | if (cosom < 0) |
| | 3919 | { |
| | 3920 | next_quat->quatx = -next_quat->quatx; |
| | 3921 | next_quat->quaty = -next_quat->quaty; |
| | 3922 | next_quat->quatz = -next_quat->quatz; |
| | 3923 | next_quat->quatw = -next_quat->quatw; |
| | 3924 | cosom = -cosom; |
| | 3925 | } |
| | 3926 | |
| | 3927 | this_section_data->omega = ArcCos(cosom); |
| | 3928 | |
| | 3929 | if (GetSin(this_section_data->omega)) |
| | 3930 | this_section_data->oneoversinomega = GetOneOverSin(this_section_data->omega); |
| | 3931 | else |
| | 3932 | this_section_data->omega = this_section_data->oneoversinomega = 0; /* Yuk. */ |
| | 3933 | |
| | 3934 | assert(seconds_for_tweening > 0); |
| | 3935 | this_section_data->oneovertweeninglength = DIV_FIXED(ONE_FIXED,seconds_for_tweening); |
| | 3936 | } |
| | 3937 | |
| | 3938 | /* Init fields... I guess. */ |
| | 3939 | |
| | 3940 | this_section_data->current_sequence = sequence_ptr; |
| | 3941 | this_section_data->current_keyframe = sequence_ptr->first_frame; |
| | 3942 | this_section_data->accumulated_timer = 0; |
| | 3943 | this_section_data->freezeframe_timer = -1; |
| | 3944 | this_section_data->lastframe_timer = 0; |
| | 3945 | this_section_data->gore_timer = 0; /* As good a time as any. */ |
| | 3946 | this_section_data->Tweening= 1; |
| | 3947 | |
| | 3948 | /* Animation? */ |
| | 3949 | /* Nah. */ |
| | 3950 | /* Recurse. */ |
| | 3951 | |
| | 3952 | if ( (this_section_data->First_Child != NULL) && !(this_section_data->flags & section_data_terminate_here)) |
| | 3953 | { |
| | 3954 | /* Respect the terminator! */ |
| | 3955 | |
| | 3956 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 3957 | |
| | 3958 | while (child_list_ptr != NULL) |
| | 3959 | { |
| | 3960 | Init_Tweening_ToTheMiddle_Recursion(child_list_ptr,target_sequence_type,target_subsequence,seconds_for_tweening,target_sequence_timer,backwards); |
| | 3961 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 3962 | } |
| | 3963 | } |
| | 3964 | } |
| | 3965 | |
| | 3966 | void InitHModelTweening_ToTheMiddle(HMODELCONTROLLER *controller, int seconds_for_tweening, |
| | 3967 | int target_sequence_type, int target_subsequence, int target_seconds_for_sequence, int target_sequence_timer, int loop) |
| | 3968 | { |
| | 3969 | /* Just set it up... */ |
| | 3970 | assert(target_seconds_for_sequence); |
| | 3971 | |
| | 3972 | controller->Sequence_Type = target_sequence_type; |
| | 3973 | controller->Sub_Sequence = target_subsequence; |
| | 3974 | controller->Seconds_For_Sequence = seconds_for_tweening; |
| | 3975 | controller->timer_increment = DIV_FIXED(ONE_FIXED,controller->Seconds_For_Sequence); |
| | 3976 | controller->sequence_timer = 0; |
| | 3977 | controller->Playing = 1; |
| | 3978 | controller->Reversed = 0; |
| | 3979 | controller->Looped = 1; |
| | 3980 | controller->After_Tweening_Sequence_Type = target_sequence_type; |
| | 3981 | controller->After_Tweening_Sub_Sequence = target_subsequence; |
| | 3982 | controller->AT_seconds_for_sequence = target_seconds_for_sequence; |
| | 3983 | controller->AT_sequence_timer = target_sequence_timer; |
| | 3984 | |
| | 3985 | while (controller->AT_sequence_timer >= ONE_FIXED) |
| | 3986 | controller->AT_sequence_timer -= ONE_FIXED; |
| | 3987 | |
| | 3988 | controller->Tweening = Controller_Tweening; |
| | 3989 | controller->LoopAfterTweening = loop; |
| | 3990 | controller->StopAfterTweening = controller->ElevationTweening = 0; |
| | 3991 | |
| | 3992 | /* Recurse though hierarchy, setting up all the section_data sequence stores? */ |
| | 3993 | |
| | 3994 | Init_Tweening_ToTheMiddle_Recursion(controller->section_data, target_sequence_type, target_subsequence,seconds_for_tweening,target_sequence_timer,0); |
| | 3995 | } |
| | 3996 | |
| | 3997 | static void Verify_Positions_Recursion(HMODELCONTROLLER *controller,SECTION_DATA *this_section_data,VECTORCH *parent_position,char *callCode) |
| | 3998 | { |
| | 3999 | /* Verify positions... */ |
| | 4000 | |
| | 4001 | if ( !( (this_section_data->World_Offset.vx < 1000000 && this_section_data->World_Offset.vx > -1000000) |
| | 4002 | && (this_section_data->World_Offset.vy < 1000000 && this_section_data->World_Offset.vy > -1000000) |
| | 4003 | && (this_section_data->World_Offset.vz < 1000000 && this_section_data->World_Offset.vz > -1000000) ) ) |
| | 4004 | { |
| | 4005 | printf("Tests in VERIFY_POSITIONS_RECURSION.\n"); |
| | 4006 | |
| | 4007 | if (callCode) |
| | 4008 | printf("Call code %s\n",callCode); |
| | 4009 | else |
| | 4010 | printf("No call code!\n"); |
| | 4011 | |
| | 4012 | if (Global_HModel_Sptr) |
| | 4013 | { |
| | 4014 | printf("Misplaced object is of type %d\n",Global_HModel_Sptr->type); |
| | 4015 | |
| | 4016 | if (Global_HModel_Sptr->DisplayBlock) |
| | 4017 | printf("Object is Near.\n"); |
| | 4018 | else |
| | 4019 | printf("Object is Far.\n"); |
| | 4020 | } |
| | 4021 | else |
| | 4022 | { |
| | 4023 | printf("Misplaced object has no SBptr.\n"); |
| | 4024 | } |
| | 4025 | |
| | 4026 | printf("Name of section: %s\n",this_section_data->sempai->Section_Name); |
| | 4027 | printf("It was playing sequence: %d,%d\n",controller->Sequence_Type,controller->Sub_Sequence); |
| | 4028 | printf("Sequence Timer = %d\n",controller->sequence_timer); |
| | 4029 | printf("Tweening flags %d\n",controller->Tweening); |
| | 4030 | |
| | 4031 | printf("Parent Position %d,%d,%d\n",parent_position->vx,parent_position->vy,parent_position->vz); |
| | 4032 | printf("This Position
%d,%d,%d\n",this_section_data->World_Offset.vx,this_section_data->World_Offset.vy,this_section_data->World_Offset.vz); |
| | 4033 | |
| | 4034 | assert(this_section_data->World_Offset.vx < 1000000 && this_section_data->World_Offset.vx > -1000000); |
| | 4035 | assert(this_section_data->World_Offset.vy < 1000000 && this_section_data->World_Offset.vy > -1000000); |
| | 4036 | assert(this_section_data->World_Offset.vz < 1000000 && this_section_data->World_Offset.vz > -1000000); |
| | 4037 | } |
| | 4038 | |
| | 4039 | /* Now call recursion... */ |
| | 4040 | |
| | 4041 | if (this_section_data->First_Child != NULL) |
| | 4042 | { |
| | 4043 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 4044 | |
| | 4045 | while (child_list_ptr != NULL) |
| | 4046 | { |
| | 4047 | Verify_Positions_Recursion(controller,child_list_ptr,&this_section_data->World_Offset,callCode); |
| | 4048 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 4049 | } |
| | 4050 | } |
| | 4051 | } |
| | 4052 | |
| | 4053 | void Verify_Positions_In_HModel(STRATEGYBLOCK *sbPtr, HMODELCONTROLLER *controller, char *callCode) |
| | 4054 | { |
| | 4055 | /* Verify position integrity. */ |
| | 4056 | |
| | 4057 | if (controller && sbPtr) |
| | 4058 | { |
| | 4059 | Global_HModel_Sptr = sbPtr; |
| | 4060 | Global_Controller_Ptr = controller; |
| | 4061 | Global_HModel_DispPtr = sbPtr->DisplayBlock; |
| | 4062 | Verify_Positions_Recursion(controller,controller->section_data,&sbPtr->DynPtr->Position,callCode); |
| | 4063 | } |
| | 4064 | } |
| | 4065 | |
| | 4066 | void CopyShortQuatToInt(QUAT_SHORT* qs, QUAT* q) |
| | 4067 | { |
| | 4068 | q->quatx = ((int)qs->quatx) << 1; |
| | 4069 | q->quaty = ((int)qs->quaty) << 1; |
| | 4070 | q->quatz = ((int)qs->quatz) << 1; |
| | 4071 | q->quatw = ((int)qs->quatw) << 1; |
| | 4072 | } |
| | 4073 | |
| | 4074 | void SetKeyFrameOffset(KEYFRAME_DATA* frame,VECTORCH* input_vector) |
| | 4075 | { |
| | 4076 | if(input_vector->vx >= -32768 && input_vector->vx <= 32767 && |
| | 4077 | input_vector->vy >= -32768 && input_vector->vy <= 32767 && |
| | 4078 | input_vector->vz >= -32768 && input_vector->vz <= 32767) |
| | 4079 | { |
| | 4080 | frame->Offset_x = (int16_t)input_vector->vx; |
| | 4081 | frame->Offset_y = (int16_t)input_vector->vy; |
| | 4082 | frame->Offset_z = (int16_t)input_vector->vz; |
| | 4083 | |
| | 4084 | frame->shift_offset = 0; |
| | 4085 | } |
| | 4086 | else |
| | 4087 | { |
| | 4088 | frame->Offset_x = (int16_t)(input_vector->vx >> KEYFRAME_VECTOR_SHIFT); |
| | 4089 | frame->Offset_y = (int16_t)(input_vector->vy >> KEYFRAME_VECTOR_SHIFT); |
| | 4090 | frame->Offset_z = (int16_t)(input_vector->vz >> KEYFRAME_VECTOR_SHIFT); |
| | 4091 | |
| | 4092 | frame->shift_offset = 1; |
| | 4093 | } |
| | 4094 | } |
| | 4095 | |
| | 4096 | static int HModelDepthTest_Recursion(SECTION_DATA *this_section_data, SECTION_DATA *test_section_data, int depth) |
| | 4097 | { |
| | 4098 | int totals = 0; |
| | 4099 | |
| | 4100 | /* Return if too deep. */ |
| | 4101 | if (depth < 0) |
| | 4102 | return 0; |
| | 4103 | |
| | 4104 | /* Test this section? */ |
| | 4105 | if (this_section_data == test_section_data) |
| | 4106 | return 1; // Success. |
| | 4107 | |
| | 4108 | /* Now call recursion... */ |
| | 4109 | |
| | 4110 | if (this_section_data->First_Child != NULL) |
| | 4111 | { |
| | 4112 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 4113 | |
| | 4114 | while (child_list_ptr != NULL) |
| | 4115 | { |
| | 4116 | totals += HModelDepthTest_Recursion(child_list_ptr,test_section_data,depth-1); |
| | 4117 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 4118 | } |
| | 4119 | } |
| | 4120 | |
| | 4121 | return totals; |
| | 4122 | } |
| | 4123 | |
| | 4124 | int HModel_DepthTest(HMODELCONTROLLER *controller, SECTION_DATA *test_section_data, int depth) |
| | 4125 | { |
| | 4126 | /* Regenerate sections. */ |
| | 4127 | |
| | 4128 | return HModelDepthTest_Recursion(controller->section_data, test_section_data, depth); |
| | 4129 | } |
| | 4130 | |
| | 4131 | static void DeInitialise_Recursion(SECTION_DATA *this_section_data) |
| | 4132 | { |
| | 4133 | this_section_data->flags = this_section_data->flags&(~section_data_initialised); |
| | 4134 | |
| | 4135 | /* Now call recursion... */ |
| | 4136 | |
| | 4137 | if (this_section_data->First_Child != NULL) |
| | 4138 | { |
| | 4139 | SECTION_DATA *child_list_ptr = this_section_data->First_Child; |
| | 4140 | |
| | 4141 | while (child_list_ptr != NULL) |
| | 4142 | { |
| | 4143 | DeInitialise_Recursion(child_list_ptr); |
| | 4144 | child_list_ptr = child_list_ptr->Next_Sibling; |
| | 4145 | } |
| | 4146 | } |
| | 4147 | } |
| | 4148 | |
| | 4149 | void DeInitialise_HModel(HMODELCONTROLLER *controller) |
| | 4150 | { |
| | 4151 | /* Recursively set all 'initialised' flags to zero. */ |
| | 4152 | |
| | 4153 | if (controller != NULL) |
| | 4154 | DeInitialise_Recursion(controller->section_data); |
| | 4155 | } |
| | 4156 | |
| | 4157 | static void EnsureChildrenAreInAscendingIDOrder(SECTION_DATA* section) |
| | 4158 | { |
| | 4159 | /* |
| | 4160 | This checks all the children of a section to make sure that they are placed in ascending Id order. |
| | 4161 | This is needed for the saving and loading process to work properly. |
| | 4162 | (In the majority of cases, sections will be in the right order , so this should be fairly quick) |
| | 4163 | */ |
| | 4164 | |
| | 4165 | SECTION_DATA* child_section = section->First_Child; |
| | 4166 | |
| | 4167 | if(child_section) |
| | 4168 | while(child_section->Next_Sibling) |
| | 4169 | { |
| | 4170 | SECTION_DATA* next_section = child_section->Next_Sibling; |
| | 4171 | |
| | 4172 | if(next_section->sempai->IDnumber<child_section->sempai->IDnumber) |
| | 4173 | { |
| | 4174 | /* These two sections are out of order , so we need to swap them */ |
| | 4175 | |
| | 4176 | /*First correct the children before and adter the ones being swapped*/ |
| | 4177 | |
| | 4178 | if(child_section->Prev_Sibling) |
| | 4179 | child_section->Prev_Sibling->Next_Sibling = next_section; |
| | 4180 | |
| | 4181 | if(next_section->Next_Sibling) |
| | 4182 | next_section->Next_Sibling->Prev_Sibling = child_section; |
| | 4183 | |
| | 4184 | /* If we are swapping the first child , then we need to alter the parent's pointer */ |
| | 4185 | |
| | 4186 | if(section->First_Child == child_section) |
| | 4187 | section->First_Child = next_section; |
| | 4188 | |
| | 4189 | /* Give the sections being swapped the pointers to the sections before and after them */ |
| | 4190 | |
| | 4191 | child_section->Next_Sibling = next_section->Next_Sibling; |
| | 4192 | next_section->Prev_Sibling = child_section->Prev_Sibling; |
| | 4193 | |
| | 4194 | child_section->Prev_Sibling = next_section; |
| | 4195 | next_section->Next_Sibling = child_section; |
| | 4196 | |
| | 4197 | /*The next section we will have to consider is the one we have just swapped ealier in the list*/ |
| | 4198 | |
| | 4199 | child_section = next_section; |
| | 4200 | |
| | 4201 | /* |
| | 4202 | If the section has a previous sibling then we need to look back at that one , since the previous sibling's |
| | 4203 | if could be higher than that of the section we have just swapped |
| | 4204 | */ |
| | 4205 | |
| | 4206 | if(child_section->Prev_Sibling) |
| | 4207 | child_section = child_section->Prev_Sibling; |
| | 4208 | } |
| | 4209 | else |
| | 4210 | { |
| | 4211 | //No problem with this section , go on to the next |
| | 4212 | child_section = child_section->Next_Sibling; |
| | 4213 | } |
| | 4214 | } |
| | 4215 | } |
| | 4216 | |
| | 4217 | /*--------------------** |
| | 4218 | ** Loading and Saving ** |
| | 4219 | **--------------------*/ |
| | 4220 | #include "savegame.h" |
| | 4221 | |
| | 4222 | static void LoadHierarchySection(SECTION_DATA* section); |
| | 4223 | static void SaveHierarchySectionRecursion(SECTION_DATA* section); |
| | 4224 | |
| | 4225 | static void LoadHierarchySectionDecals(SAVE_BLOCK_HEADER* header,SECTION_DATA* section); |
| | 4226 | static void SaveHierarchySectionDecals(SECTION_DATA* section); |
| | 4227 | |
| | 4228 | static void LoadHierarchySectionTween(SAVE_BLOCK_HEADER* header,SECTION_DATA* section); |
| | 4229 | static void SaveHierarchySectionTween(SECTION_DATA* section); |
| | 4230 | |
| | 4231 | static void LoadHierarchyDelta(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller); |
| | 4232 | static void SaveHierarchyDelta(DELTA_CONTROLLER* delta); |
| | 4233 | |
| | 4234 | typedef struct hierarchy_save_block |
| | 4235 | { |
| | 4236 | SAVE_BLOCK_HEADER header; |
| | 4237 | |
| | 4238 | int structure_size; |
| | 4239 | |
| | 4240 | int Seconds_For_Sequence; |
| | 4241 | int timer_increment; |
| | 4242 | int Sequence_Type; |
| | 4243 | int Sub_Sequence; |
| | 4244 | int sequence_timer; |
| | 4245 | int FrameStamp; |
| | 4246 | VECTORCH Computed_Position; |
| | 4247 | |
| | 4248 | int keyframe_flags; |
| | 4249 | |
| | 4250 | int After_Tweening_Sequence_Type; |
| | 4251 | int After_Tweening_Sub_Sequence; |
| | 4252 | int AT_seconds_for_sequence; |
| | 4253 | int AT_sequence_timer; |
| | 4254 | |
| | 4255 | unsigned int Playing:1; |
| | 4256 | unsigned int Reversed:1; |
| | 4257 | unsigned int Looped:1; |
| | 4258 | unsigned int Tweening:2; |
| | 4259 | unsigned int LoopAfterTweening:1; |
| | 4260 | unsigned int StopAfterTweening:1; |
| | 4261 | unsigned int ElevationTweening:1; |
| | 4262 | unsigned int DisableBleeding:1; |
| | 4263 | unsigned int LockTopSection:1; |
| | 4264 | unsigned int ZeroRootDisplacement:1; |
| | 4265 | unsigned int ZeroRootRotation:1; |
| | 4266 | unsigned int DisableSounds:1; |
| | 4267 | |
| | 4268 | int root_section_id; |
| | 4269 | |
| | 4270 | } HIERARCHY_SAVE_BLOCK; |
| | 4271 | |
| | 4272 | //defines for load/save macros |
| | 4273 | #define SAVELOAD_BLOCK block |
| | 4274 | #define SAVELOAD_BEHAV controller |
| | 4275 | |
| | 4276 | void LoadHierarchy(SAVE_BLOCK_HEADER* header, HMODELCONTROLLER* controller) |
| | 4277 | { |
| | 4278 | SECTION *root_section; |
| | 4279 | const char *Rif_Name; |
| | 4280 | const char *Hierarchy_Name; |
| | 4281 | HIERARCHY_SAVE_BLOCK* block = (HIERARCHY_SAVE_BLOCK*) header; |
| | 4282 | |
| | 4283 | //make sure the block is the correct size |
| | 4284 | if(block->structure_size != sizeof(*block)) |
| | 4285 | return; |
| | 4286 | |
| | 4287 | //get the names from just after the block |
| | 4288 | { |
| | 4289 | char* buffer=(char*) header; |
| | 4290 | buffer += sizeof(*block); |
| | 4291 | |
| | 4292 | Hierarchy_Name = buffer; |
| | 4293 | buffer += strlen(Hierarchy_Name)+1; |
| | 4294 | Rif_Name = buffer; |
| | 4295 | } |
| | 4296 | |
| | 4297 | { |
| | 4298 | int needToCreateHModel = 0; |
| | 4299 | |
| | 4300 | //make sure that the initial model has been set up , and is using the correct hierarchy |
| | 4301 | if(controller->Root_Section) |
| | 4302 | { |
| | 4303 | if(strcmp(Rif_Name, controller->Root_Section->Rif_Name) || strcmp(Hierarchy_Name, controller->Root_Section->Hierarchy_Name)) |
| | 4304 | { |
| | 4305 | needToCreateHModel = 1; |
| | 4306 | } |
| | 4307 | else if(controller->Root_Section->IDnumber != block->root_section_id) |
| | 4308 | { |
| | 4309 | needToCreateHModel = 1; |
| | 4310 | } |
| | 4311 | } |
| | 4312 | else |
| | 4313 | { |
| | 4314 | needToCreateHModel = 1; |
| | 4315 | } |
| | 4316 | |
| | 4317 | //check to see if we need to change hierarchy |
| | 4318 | if(needToCreateHModel) |
| | 4319 | { |
| | 4320 | extern SECTION * GetNamedHierarchyFromLibrary(const char * rif_name, const char * hier_name); |
| | 4321 | |
| | 4322 | root_section = GetNamedHierarchyFromLibrary(Rif_Name,Hierarchy_Name); |
| | 4323 | |
| | 4324 | if(!root_section) |
| | 4325 | return; |
| | 4326 | |
| | 4327 | //may not want the 'real' root (hierarchical debris) |
| | 4328 | root_section = GetThisSection_FromID(root_section,block->root_section_id); |
| | 4329 | if(!root_section) |
| | 4330 | return; |
| | 4331 | |
| | 4332 | //reinitialise the hierarchy |
| | 4333 | Dispel_HModel(controller); |
| | 4334 | Create_HModel(controller,root_section); |
| | 4335 | } |
| | 4336 | } |
| | 4337 | |
| | 4338 | //copy the stuff for the controller |
| | 4339 | COPYELEMENT_LOAD(Seconds_For_Sequence) |
| | 4340 | COPYELEMENT_LOAD(timer_increment) |
| | 4341 | COPYELEMENT_LOAD(Sequence_Type) |
| | 4342 | COPYELEMENT_LOAD(Sub_Sequence) |
| | 4343 | COPYELEMENT_LOAD(sequence_timer) |
| | 4344 | COPYELEMENT_LOAD(FrameStamp) |
| | 4345 | COPYELEMENT_LOAD(Computed_Position) |
| | 4346 | COPYELEMENT_LOAD(keyframe_flags) |
| | 4347 | COPYELEMENT_LOAD(After_Tweening_Sequence_Type) |
| | 4348 | COPYELEMENT_LOAD(After_Tweening_Sub_Sequence) |
| | 4349 | COPYELEMENT_LOAD(AT_seconds_for_sequence) |
| | 4350 | COPYELEMENT_LOAD(AT_sequence_timer) |
| | 4351 | COPYELEMENT_LOAD(Playing) |
| | 4352 | COPYELEMENT_LOAD(Reversed) |
| | 4353 | COPYELEMENT_LOAD(Looped) |
| | 4354 | COPYELEMENT_LOAD(Tweening) |
| | 4355 | COPYELEMENT_LOAD(LoopAfterTweening) |
| | 4356 | COPYELEMENT_LOAD(StopAfterTweening) |
| | 4357 | COPYELEMENT_LOAD(ElevationTweening) |
| | 4358 | COPYELEMENT_LOAD(DisableBleeding) |
| | 4359 | COPYELEMENT_LOAD(LockTopSection) |
| | 4360 | COPYELEMENT_LOAD(ZeroRootDisplacement) |
| | 4361 | COPYELEMENT_LOAD(ZeroRootRotation) |
| | 4362 | COPYELEMENT_LOAD(DisableSounds); |
| | 4363 | |
| | 4364 | //load the delta sequences |
| | 4365 | { |
| | 4366 | SAVE_BLOCK_HEADER* delta_header; |
| | 4367 | |
| | 4368 | while((delta_header = GetNextBlockIfOfType(SaveBlock_HierarchyDelta))) |
| | 4369 | { |
| | 4370 | LoadHierarchyDelta(delta_header,controller); |
| | 4371 | } |
| | 4372 | } |
| | 4373 | |
| | 4374 | ///load the section data |
| | 4375 | LoadHierarchySection(controller->section_data); |
| | 4376 | } |
| | 4377 | |
| | 4378 | void SaveHierarchy(HMODELCONTROLLER* controller) |
| | 4379 | { |
| | 4380 | HIERARCHY_SAVE_BLOCK* block; |
| | 4381 | if(!controller || !controller->Root_Section) |
| | 4382 | return; |
| | 4383 | |
| | 4384 | GET_SAVE_BLOCK_POINTER(block); |
| | 4385 | |
| | 4386 | //fill in header |
| | 4387 | block->header.type = SaveBlock_Hierarchy; |
| | 4388 | block->header.size = sizeof(*block); |
| | 4389 | block->structure_size =block->header.size; |
| | 4390 | |
| | 4391 | COPYELEMENT_SAVE(Seconds_For_Sequence) |
| | 4392 | COPYELEMENT_SAVE(timer_increment) |
| | 4393 | COPYELEMENT_SAVE(Sequence_Type) |
| | 4394 | COPYELEMENT_SAVE(Sub_Sequence) |
| | 4395 | COPYELEMENT_SAVE(sequence_timer) |
| | 4396 | COPYELEMENT_SAVE(FrameStamp) |
| | 4397 | COPYELEMENT_SAVE(Computed_Position) |
| | 4398 | COPYELEMENT_SAVE(keyframe_flags) |
| | 4399 | COPYELEMENT_SAVE(After_Tweening_Sequence_Type) |
| | 4400 | COPYELEMENT_SAVE(After_Tweening_Sub_Sequence) |
| | 4401 | COPYELEMENT_SAVE(AT_seconds_for_sequence) |
| | 4402 | COPYELEMENT_SAVE(AT_sequence_timer) |
| | 4403 | COPYELEMENT_SAVE(Playing) |
| | 4404 | COPYELEMENT_SAVE(Reversed) |
| | 4405 | COPYELEMENT_SAVE(Looped) |
| | 4406 | COPYELEMENT_SAVE(Tweening) |
| | 4407 | COPYELEMENT_SAVE(LoopAfterTweening) |
| | 4408 | COPYELEMENT_SAVE(StopAfterTweening) |
| | 4409 | COPYELEMENT_SAVE(ElevationTweening) |
| | 4410 | COPYELEMENT_SAVE(DisableBleeding) |
| | 4411 | COPYELEMENT_SAVE(LockTopSection) |
| | 4412 | COPYELEMENT_SAVE(ZeroRootDisplacement) |
| | 4413 | COPYELEMENT_SAVE(ZeroRootRotation) |
| | 4414 | COPYELEMENT_SAVE(DisableSounds); |
| | 4415 | |
| | 4416 | block->root_section_id = controller->Root_Section->IDnumber; |
| | 4417 | |
| | 4418 | { |
| | 4419 | char* buffer; |
| | 4420 | char* Hierarchy_Name = controller->Root_Section->Hierarchy_Name; |
| | 4421 | char* Rif_Name = controller->Root_Section->Rif_Name; |
| | 4422 | |
| | 4423 | //increase the block size by enough to hold these names |
| | 4424 | block->header.size+= strlen(Hierarchy_Name)+strlen(Rif_Name)+2; |
| | 4425 | |
| | 4426 | //alllocate memoey , and copy names; |
| | 4427 | buffer = GetPointerForSaveBlock(strlen(Hierarchy_Name)+1); |
| | 4428 | strcpy(buffer,Hierarchy_Name); |
| | 4429 | |
| | 4430 | buffer = GetPointerForSaveBlock(strlen(Rif_Name)+1); |
| | 4431 | strcpy(buffer,Rif_Name); |
| | 4432 | } |
| | 4433 | |
| | 4434 | //save the delta sequences |
| | 4435 | { |
| | 4436 | DELTA_CONTROLLER* delta = controller->Deltas; |
| | 4437 | |
| | 4438 | while(delta) |
| | 4439 | { |
| | 4440 | SaveHierarchyDelta(delta); |
| | 4441 | delta = delta->next_controller; |
| | 4442 | } |
| | 4443 | } |
| | 4444 | |
| | 4445 | //now save the section data |
| | 4446 | SaveHierarchySectionRecursion(controller->section_data); |
| | 4447 | } |
| | 4448 | |
| | 4449 | typedef struct hierarchy_delta_save_block |
| | 4450 | { |
| | 4451 | SAVE_BLOCK_HEADER header; |
| | 4452 | |
| | 4453 | int timer; |
| | 4454 | int lastframe_timer; |
| | 4455 | int sequence_type; |
| | 4456 | int sub_sequence; |
| | 4457 | int seconds_for_sequence; |
| | 4458 | int timer_increment; |
| | 4459 | int Looped:1; |
| | 4460 | int Playing:1; |
| | 4461 | int Active:1; |
| | 4462 | |
| | 4463 | } HIERARCHY_DELTA_SAVE_BLOCK; |
| | 4464 | |
| | 4465 | #undef SAVELOAD_BEHAV |
| | 4466 | //defines for load/save macros |
| | 4467 | #define SAVELOAD_BEHAV delta |
| | 4468 | |
| | 4469 | static void LoadHierarchyDelta(SAVE_BLOCK_HEADER* header,HMODELCONTROLLER* controller) |
| | 4470 | { |
| | 4471 | DELTA_CONTROLLER* delta; |
| | 4472 | HIERARCHY_DELTA_SAVE_BLOCK* block = (HIERARCHY_DELTA_SAVE_BLOCK*) header; |
| | 4473 | char* name = (char*) (block+1); |
| | 4474 | |
| | 4475 | delta = Get_Delta_Sequence(controller,name); |
| | 4476 | |
| | 4477 | if(!delta) |
| | 4478 | delta = Add_Delta_Sequence(controller,name,block->sequence_type,block->sub_sequence,block->seconds_for_sequence); |
| | 4479 | |
| | 4480 | COPYELEMENT_LOAD(timer) |
| | 4481 | COPYELEMENT_LOAD(lastframe_timer) |
| | 4482 | COPYELEMENT_LOAD(timer_increment) |
| | 4483 | COPYELEMENT_LOAD(Looped) |
| | 4484 | COPYELEMENT_LOAD(Playing) |
| | 4485 | COPYELEMENT_LOAD(Active) |
| | 4486 | COPYELEMENT_LOAD(sequence_type) |
| | 4487 | COPYELEMENT_LOAD(sub_sequence) |
| | 4488 | COPYELEMENT_LOAD(seconds_for_sequence) |
| | 4489 | } |
| | 4490 | |
| | 4491 | static void SaveHierarchyDelta(DELTA_CONTROLLER* delta) |
| | 4492 | { |
| | 4493 | HIERARCHY_DELTA_SAVE_BLOCK* block; |
| | 4494 | int size; |
| | 4495 | |
| | 4496 | //work out memory needed |
| | 4497 | size = sizeof(*block) + strlen(delta->id) +1; |
| | 4498 | block = (HIERARCHY_DELTA_SAVE_BLOCK*) GetPointerForSaveBlock(size); |
| | 4499 | |
| | 4500 | //fill in the header |
| | 4501 | block->header.size = size; |
| | 4502 | block->header.type = SaveBlock_HierarchyDelta; |
| | 4503 | |
| | 4504 | COPYELEMENT_SAVE(timer) |
| | 4505 | COPYELEMENT_SAVE(lastframe_timer) |
| | 4506 | COPYELEMENT_SAVE(timer_increment) |
| | 4507 | COPYELEMENT_SAVE(Looped) |
| | 4508 | COPYELEMENT_SAVE(Playing) |
| | 4509 | COPYELEMENT_SAVE(Active) |
| | 4510 | COPYELEMENT_SAVE(sequence_type) |
| | 4511 | COPYELEMENT_SAVE(sub_sequence) |
| | 4512 | COPYELEMENT_SAVE(seconds_for_sequence) |
| | 4513 | |
| | 4514 | //tack the name on the end |
| | 4515 | { |
| | 4516 | char* name = (char*)(block+1); |
| | 4517 | strcpy(name,delta->id); |
| | 4518 | } |
| | 4519 | } |
| | 4520 | |
| | 4521 | typedef struct hierarchy_section_save_block |
| | 4522 | { |
| | 4523 | SAVE_BLOCK_HEADER header; |
| | 4524 | |
| | 4525 | //from section |
| | 4526 | int IDnumber; |
| | 4527 | |
| | 4528 | //from section_data |
| | 4529 | VECTORCH Offset; |
| | 4530 | VECTORCH World_Offset; |
| | 4531 | VECTORCH Last_World_Offset; |
| | 4532 | MATRIXCH RelSecMat; |
| | 4533 | MATRIXCH SecMat; |
| | 4534 | |
| | 4535 | struct damageblock current_damage; |
| | 4536 | |
| | 4537 | int accumulated_timer; |
| | 4538 | int freezeframe_timer; |
| | 4539 | int lastframe_timer; |
| | 4540 | int gore_timer; |
| | 4541 | int flags; |
| | 4542 | int sequence_id; |
| | 4543 | int keyframe_time; |
| | 4544 | int replacement_id; |
| | 4545 | |
| | 4546 | } HIERARCHY_SECTION_SAVE_BLOCK; |
| | 4547 | |
| | 4548 | #undef SAVELOAD_BEHAV |
| | 4549 | //defines for load/save macros |
| | 4550 | #define SAVELOAD_BEHAV section |
| | 4551 | |
| | 4552 | extern HIERARCHY_SHAPE_REPLACEMENT* GetHierarchyAlternateShapeFromId(const char* rif_name,int replacement_id,char* section_name); |
| | 4553 | |
| | 4554 | static void LoadHierarchySection(SECTION_DATA* section) |
| | 4555 | { |
| | 4556 | SAVE_BLOCK_HEADER* header; |
| | 4557 | SAVE_BLOCK_HEADER* decal_header; |
| | 4558 | SAVE_BLOCK_HEADER* tween_header; |
| | 4559 | |
| | 4560 | HIERARCHY_SECTION_SAVE_BLOCK* block; |
| | 4561 | |
| | 4562 | header = GetNextBlockIfOfType(SaveBlock_HierarchySection); |
| | 4563 | decal_header = GetNextBlockIfOfType(SaveBlock_HierarchyDecals); |
| | 4564 | tween_header = GetNextBlockIfOfType(SaveBlock_HierarchyTween); |
| | 4565 | |
| | 4566 | /* |
| | 4567 | In this bit we go through the hierechy section data , and saved section data in increasing |
| | 4568 | ID number order. Whenever we find any sections without saved data , we need to prunce them |
| | 4569 | (since they will have been blown off the original hierarchy) |
| | 4570 | */ |
| | 4571 | |
| | 4572 | while(header && section) |
| | 4573 | { |
| | 4574 | block = (HIERARCHY_SECTION_SAVE_BLOCK*) header; |
| | 4575 | |
| | 4576 | if(block->header.size!=sizeof(*block)) return; |
| | 4577 | //compare section id numbers |
| | 4578 | if(block->IDnumber == section->sempai->IDnumber) |
| | 4579 | { |
| | 4580 | //copy stuff for this section then |
| | 4581 | COPYELEMENT_LOAD(Offset); |
| | 4582 | COPYELEMENT_LOAD(World_Offset); |
| | 4583 | COPYELEMENT_LOAD(Last_World_Offset); |
| | 4584 | COPYELEMENT_LOAD(RelSecMat); |
| | 4585 | COPYELEMENT_LOAD(SecMat); |
| | 4586 | COPYELEMENT_LOAD(current_damage); |
| | 4587 | COPYELEMENT_LOAD(accumulated_timer); |
| | 4588 | COPYELEMENT_LOAD(freezeframe_timer); |
| | 4589 | COPYELEMENT_LOAD(lastframe_timer); |
| | 4590 | COPYELEMENT_LOAD(gore_timer); |
| | 4591 | COPYELEMENT_LOAD(flags); |
| | 4592 | COPYELEMENT_LOAD(replacement_id); |
| | 4593 | |
| | 4594 | //see if this section is using an alternate shape set |
| | 4595 | { |
| | 4596 | int desiredShapeIndex = section->sempai->ShapeNum; |
| | 4597 | HIERARCHY_SHAPE_REPLACEMENT* replacement =
GetHierarchyAlternateShapeFromId(section->sempai->Rif_Name,block->replacement_id,section->sempai->Section_Name); |
| | 4598 | |
| | 4599 | if(replacement) |
| | 4600 | desiredShapeIndex = replacement->replacement_shape_index; |
| | 4601 | |
| | 4602 | if(section->ShapeNum != desiredShapeIndex) |
| | 4603 | { |
| | 4604 | section->ShapeNum = desiredShapeIndex; |
| | 4605 | |
| | 4606 | if(desiredShapeIndex >= 0) |
| | 4607 | section->Shape = mainshapelist[desiredShapeIndex]; |
| | 4608 | else |
| | 4609 | section->Shape = 0; |
| | 4610 | |
| | 4611 | Setup_Texture_Animation_For_Section(section); |
| | 4612 | } |
| | 4613 | } |
| | 4614 | |
| | 4615 | //load decals |
| | 4616 | if(decal_header) |
| | 4617 | LoadHierarchySectionDecals(decal_header,section); |
| | 4618 | else |
| | 4619 | section->NumberOfDecals = section->NextDecalToUse = 0; |
| | 4620 | |
| | 4621 | //load tweening data |
| | 4622 | if(tween_header) |
| | 4623 | LoadHierarchySectionTween(tween_header,section); |
| | 4624 | else |
| | 4625 | section->Tweening = 0; |
| | 4626 | |
| | 4627 | //get the current sequence and frame |
| | 4628 | |
| | 4629 | { |
| | 4630 | int a; |
| | 4631 | const SECTION* this_section = section->sempai; |
| | 4632 | section->current_sequence = &(this_section->sequence_array[0]); |
| | 4633 | |
| | 4634 | for (a=0; a < this_section->num_sequences; a++) |
| | 4635 | { |
| | 4636 | if (this_section->sequence_array[a].sequence_id == block->sequence_id) |
| | 4637 | { |
| | 4638 | section->current_sequence = &(this_section->sequence_array[a]); |
| | 4639 | break; |
| | 4640 | } |
| | 4641 | } |
| | 4642 | |
| | 4643 | int time = block->keyframe_time; |
| | 4644 | section->current_keyframe = section->current_sequence->first_frame; |
| | 4645 | |
| | 4646 | while(time >= section->current_keyframe->Sequence_Length) |
| | 4647 | { |
| | 4648 | time -= section->current_keyframe->Sequence_Length; |
| | 4649 | |
| | 4650 | if(section->current_keyframe->last_frame) |
| | 4651 | break; |
| | 4652 | else |
| | 4653 | section->current_keyframe = section->current_keyframe->Next_Frame; |
| | 4654 | } |
| | 4655 | } |
| | 4656 | |
| | 4657 | //move to the next section data |
| | 4658 | if(section->First_Child) |
| | 4659 | { |
| | 4660 | section = section->First_Child; |
| | 4661 | } |
| | 4662 | else if (section->Next_Sibling) |
| | 4663 | { |
| | 4664 | section = section->Next_Sibling; |
| | 4665 | } |
| | 4666 | else |
| | 4667 | { |
| | 4668 | int section_found = 0; |
| | 4669 | |
| | 4670 | while(section && !section_found) |
| | 4671 | { |
| | 4672 | section = section->My_Parent; |
| | 4673 | |
| | 4674 | if(section && section->Next_Sibling) |
| | 4675 | { |
| | 4676 | section = section->Next_Sibling; |
| | 4677 | section_found = 1; |
| | 4678 | } |
| | 4679 | } |
| | 4680 | } |
| | 4681 | |
| | 4682 | //move to next saved section |
| | 4683 | header = GetNextBlockIfOfType(SaveBlock_HierarchySection); |
| | 4684 | decal_header = GetNextBlockIfOfType(SaveBlock_HierarchyDecals); |
| | 4685 | tween_header = GetNextBlockIfOfType(SaveBlock_HierarchyTween); |
| | 4686 | } |
| | 4687 | else if(block->IDnumber > section->sempai->IDnumber) |
| | 4688 | { |
| | 4689 | /* There was no saved data for this section , so we will need to prune it */ |
| | 4690 | |
| | 4691 | SECTION_DATA* pruned_section = section; |
| | 4692 | |
| | 4693 | if (section->Next_Sibling) |
| | 4694 | { |
| | 4695 | section = section->Next_Sibling; |
| | 4696 | } |
| | 4697 | else |
| | 4698 | { |
| | 4699 | int section_found = 0; |
| | 4700 | |
| | 4701 | while(section && !section_found) |
| | 4702 | { |
| | 4703 | section = section->My_Parent; |
| | 4704 | |
| | 4705 | if(section && section->Next_Sibling) |
| | 4706 | { |
| | 4707 | section=section->Next_Sibling; |
| | 4708 | section_found = 1; |
| | 4709 | } |
| | 4710 | } |
| | 4711 | } |
| | 4712 | |
| | 4713 | Prune_Section(pruned_section); |
| | 4714 | } |
| | 4715 | else |
| | 4716 | { |
| | 4717 | //move to next saved section (we will need to advance until the saved id number matches |
| | 4718 | //the section id number) |
| | 4719 | //Nb. This probably never happens anyway |
| | 4720 | header = GetNextBlockIfOfType(SaveBlock_HierarchySection); |
| | 4721 | decal_header = GetNextBlockIfOfType(SaveBlock_HierarchyDecals); |
| | 4722 | tween_header = GetNextBlockIfOfType(SaveBlock_HierarchyTween); |
| | 4723 | } |
| | 4724 | } |
| | 4725 | |
| | 4726 | //prune the remaining sections |
| | 4727 | while(section) |
| | 4728 | { |
| | 4729 | SECTION_DATA* pruned_section = section; |
| | 4730 | |
| | 4731 | if (section->Next_Sibling) |
| | 4732 | { |
| | 4733 | section = section->Next_Sibling; |
| | 4734 | } |
| | 4735 | else |
| | 4736 | { |
| | 4737 | int section_found = 0; |
| | 4738 | |
| | 4739 | while(section && !section_found) |
| | 4740 | { |
| | 4741 | section = section->My_Parent; |
| | 4742 | |
| | 4743 | if(section && section->Next_Sibling) |
| | 4744 | { |
| | 4745 | section = section->Next_Sibling; |
| | 4746 | section_found = 1; |
| | 4747 | } |
| | 4748 | } |
| | 4749 | } |
| | 4750 | |
| | 4751 | Prune_Section(pruned_section); |
| | 4752 | } |
| | 4753 | } |
| | 4754 | |
| | 4755 | static void SaveHierarchySectionRecursion(SECTION_DATA* section) |
| | 4756 | { |
| | 4757 | HIERARCHY_SECTION_SAVE_BLOCK* block; |
| | 4758 | |
| | 4759 | GET_SAVE_BLOCK_POINTER(block); |
| | 4760 | |
| | 4761 | //fill in header |
| | 4762 | block->header.type = SaveBlock_HierarchySection; |
| | 4763 | block->header.size = sizeof(*block); |
| | 4764 | block->IDnumber = section->sempai->IDnumber; |
| | 4765 | |
| | 4766 | //copy stuff |
| | 4767 | COPYELEMENT_SAVE(Offset); |
| | 4768 | COPYELEMENT_SAVE(World_Offset); |
| | 4769 | COPYELEMENT_SAVE(Last_World_Offset); |
| | 4770 | COPYELEMENT_SAVE(RelSecMat); |
| | 4771 | COPYELEMENT_SAVE(SecMat); |
| | 4772 | COPYELEMENT_SAVE(current_damage); |
| | 4773 | COPYELEMENT_SAVE(accumulated_timer); |
| | 4774 | COPYELEMENT_SAVE(freezeframe_timer); |
| | 4775 | COPYELEMENT_SAVE(lastframe_timer); |
| | 4776 | COPYELEMENT_SAVE(gore_timer); |
| | 4777 | COPYELEMENT_SAVE(flags); |
| | 4778 | COPYELEMENT_SAVE(replacement_id); |
| | 4779 | |
| | 4780 | //get current sequence id |
| | 4781 | block->sequence_id = section->current_sequence->sequence_id; |
| | 4782 | |
| | 4783 | { |
| | 4784 | KEYFRAME_DATA* frame = section->current_sequence->first_frame; |
| | 4785 | int time=0; |
| | 4786 | |
| | 4787 | while(frame != section->current_keyframe) |
| | 4788 | { |
| | 4789 | time += frame->Sequence_Length; |
| | 4790 | |
| | 4791 | if(frame->last_frame) |
| | 4792 | break; |
| | 4793 | |
| | 4794 | frame = frame->Next_Frame; |
| | 4795 | } |
| | 4796 | |
| | 4797 | block->keyframe_time = time; |
| | 4798 | } |
| | 4799 | |
| | 4800 | //save decals (if needed) |
| | 4801 | if(section->NumberOfDecals) |
| | 4802 | SaveHierarchySectionDecals(section); |
| | 4803 | |
| | 4804 | //save tweening (if needed) |
| | 4805 | if(section->Tweening) |
| | 4806 | SaveHierarchySectionTween(section); |
| | 4807 | |
| | 4808 | //recurse down hierarchy |
| | 4809 | if (section->First_Child != NULL) |
| | 4810 | { |
| | 4811 | SECTION_DATA * child_section; |
| | 4812 | /* Must make sure the children are in the right order before saving. */ |
| | 4813 | EnsureChildrenAreInAscendingIDOrder(section); |
| | 4814 | |
| | 4815 | child_section = section->First_Child; |
| | 4816 | |
| | 4817 | while (child_section) |
| | 4818 | { |
| | 4819 | SaveHierarchySectionRecursion(child_section); |
| | 4820 | child_section = child_section->Next_Sibling; |
| | 4821 | } |
| | 4822 | } |
| | 4823 | } |
| | 4824 | |
| | 4825 | //section decal data |
| | 4826 | typedef struct hierarchy_decal_save_block |
| | 4827 | { |
| | 4828 | SAVE_BLOCK_HEADER header; |
| | 4829 | |
| | 4830 | int NumberOfDecals; |
| | 4831 | int NextDecalToUse; |
| | 4832 | OBJECT_DECAL Decals[MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION]; |
| | 4833 | |
| | 4834 | } HIERARCHY_DECAL_SAVE_BLOCK; |
| | 4835 | |
| | 4836 | static void LoadHierarchySectionDecals(SAVE_BLOCK_HEADER* header,SECTION_DATA* section) |
| | 4837 | { |
| | 4838 | int i = 0; |
| | 4839 | |
| | 4840 | HIERARCHY_DECAL_SAVE_BLOCK* block = (HIERARCHY_DECAL_SAVE_BLOCK*) header; |
| | 4841 | |
| | 4842 | COPYELEMENT_LOAD(NumberOfDecals); |
| | 4843 | COPYELEMENT_LOAD(NextDecalToUse); |
| | 4844 | |
| | 4845 | for(;i < block->NumberOfDecals; i++) |
| | 4846 | COPYELEMENT_LOAD(Decals[i]); |
| | 4847 | } |
| | 4848 | |
| | 4849 | static void SaveHierarchySectionDecals(SECTION_DATA* section) |
| | 4850 | { |
| | 4851 | HIERARCHY_DECAL_SAVE_BLOCK* block; |
| | 4852 | int i = 0; |
| | 4853 | |
| | 4854 | //determine how much space is required for the decals present |
| | 4855 | int size = sizeof(HIERARCHY_DECAL_SAVE_BLOCK); |
| | 4856 | size -= (MAX_NO_OF_DECALS_PER_HIERARCHICAL_SECTION - section->NumberOfDecals) * sizeof(OBJECT_DECAL); |
| | 4857 | |
| | 4858 | block = (HIERARCHY_DECAL_SAVE_BLOCK*) GetPointerForSaveBlock(size); |
| | 4859 | |
| | 4860 | //fill in the header |
| | 4861 | block->header.type = SaveBlock_HierarchyDecals; |
| | 4862 | block->header.size = size; |
| | 4863 | |
| | 4864 | //copy the decals |
| | 4865 | |
| | 4866 | COPYELEMENT_SAVE(NumberOfDecals); |
| | 4867 | COPYELEMENT_SAVE(NextDecalToUse); |
| | 4868 | |
| | 4869 | for(; i < block->NumberOfDecals; i++) |
| | 4870 | COPYELEMENT_SAVE(Decals[i]); |
| | 4871 | } |
| | 4872 | |
| | 4873 | //section tweening data |
| | 4874 | typedef struct hierarchy_tween_save_block |
| | 4875 | { |
| | 4876 | SAVE_BLOCK_HEADER header; |
| | 4877 | |
| | 4878 | /* Tweening */ |
| | 4879 | VECTORCH stored_offset; |
| | 4880 | VECTORCH target_offset; |
| | 4881 | VECTORCH delta_offset; |
| | 4882 | QUAT stored_quat; |
| | 4883 | QUAT target_quat; |
| | 4884 | int omega; |
| | 4885 | int oneoversinomega; |
| | 4886 | int oneovertweeninglength; |
| | 4887 | unsigned int Tweening:1; |
| | 4888 | |
| | 4889 | } HIERARCHY_TWEEN_SAVE_BLOCK; |
| | 4890 | |
| | 4891 | static void LoadHierarchySectionTween(SAVE_BLOCK_HEADER* header,SECTION_DATA* section) |
| | 4892 | { |
| | 4893 | //see if this section has tweening data saved |
| | 4894 | HIERARCHY_TWEEN_SAVE_BLOCK* block = (HIERARCHY_TWEEN_SAVE_BLOCK*) header; |
| | 4895 | if(!block) |
| | 4896 | return; |
| | 4897 | |
| | 4898 | COPYELEMENT_LOAD(stored_offset); |
| | 4899 | COPYELEMENT_LOAD(target_offset); |
| | 4900 | COPYELEMENT_LOAD(delta_offset); |
| | 4901 | COPYELEMENT_LOAD(stored_quat); |
| | 4902 | COPYELEMENT_LOAD(target_quat); |
| | 4903 | COPYELEMENT_LOAD(omega); |
| | 4904 | COPYELEMENT_LOAD(oneoversinomega); |
| | 4905 | COPYELEMENT_LOAD(oneovertweeninglength); |
| | 4906 | COPYELEMENT_LOAD(Tweening); |
| | 4907 | } |
| | 4908 | |
| | 4909 | static void SaveHierarchySectionTween(SECTION_DATA* section) |
| | 4910 | { |
| | 4911 | HIERARCHY_TWEEN_SAVE_BLOCK* block; |
| | 4912 | |
| | 4913 | GET_SAVE_BLOCK_POINTER(block); |
| | 4914 | |
| | 4915 | //fill in the header |
| | 4916 | block->header.type = SaveBlock_HierarchyTween; |
| | 4917 | block->header.size = sizeof(*block); |
| | 4918 | |
| | 4919 | //copy stuff |
| | 4920 | |
| | 4921 | COPYELEMENT_SAVE(stored_offset); |
| | 4922 | COPYELEMENT_SAVE(target_offset); |
| | 4923 | COPYELEMENT_SAVE(delta_offset); |
| | 4924 | COPYELEMENT_SAVE(stored_quat); |
| | 4925 | COPYELEMENT_SAVE(target_quat); |
| | 4926 | COPYELEMENT_SAVE(omega); |
| | 4927 | COPYELEMENT_SAVE(oneoversinomega); |
| | 4928 | COPYELEMENT_SAVE(oneovertweeninglength); |
| | 4929 | COPYELEMENT_SAVE(Tweening); |
| | 4930 | } |