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