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