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