Subversion Repositories Games.Carmageddon

Rev

Rev 1 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "racesumm.h"
18 pmbaty 2
#include "brender.h"
1 pmbaty 3
#include "crush.h"
4
#include "cutscene.h"
5
#include "displays.h"
6
#include "flicplay.h"
7
#include "globvars.h"
8
#include "globvrkm.h"
9
#include "globvrpb.h"
10
#include "grafdata.h"
11
#include "graphics.h"
12
#include "harness/config.h"
13
#include "harness/trace.h"
14
#include "input.h"
15
#include "intrface.h"
16
#include "loading.h"
17
#include "main.h"
18
#include "network.h"
19
#include "opponent.h"
20
#include "pd/sys.h"
21
#include "raycast.h"
22
#include "s3/s3.h"
23
#include "sound.h"
24
#include "utility.h"
25
#include <stdlib.h>
26
 
27
int gPlayer_lookup[6];
28
tMouse_area gOld_back_button;
29
tWreck_info gWreck_array[30];
30
br_actor* gWreck_root;
31
br_actor* gWreck_camera;
32
tU32 gWreck_start_zoom;
33
tU32 gWreck_gallery_start;
34
float gTemp_rank_increase;
35
float gRank_per_ms;
36
tU32 gLast_wreck_draw;
37
tS3_sound_tag gSumm_sound;
38
float gCredits_per_ms;
39
tMouse_area* gBack_button_ptr;
40
tU32 gSummary_start;
41
br_pixelmap* gWreck_z_buffer;
42
br_pixelmap* gWreck_render_area;
43
int gWreck_selected;
44
int gWreck_zoom_out;
45
br_pixelmap* gChrome_font;
46
int gWreck_zoom_in;
47
int gTemp_credits;
48
int gUser_interacted;
49
int gWreck_count;
50
int gRank_etc_munged;
51
int gRank_increase;
52
int gTemp_earned;
53
int gTemp_rank;
54
int gWreck_zoomed_in;
55
int gDone_initial;
56
int gTemp_lost;
57
 
58
// IDA: void __usercall MungeRankEtc(tProgram_state *pThe_state@<EAX>)
59
void MungeRankEtc(tProgram_state* pThe_state) {
60
    int i;
61
    int not_done_yet;
62
    LOG_TRACE("(%p)", pThe_state);
63
 
64
    not_done_yet = 0;
65
    if (!gRank_etc_munged) {
66
        gRank_etc_munged = 1;
67
        gRace_list[pThe_state->current_race_index].been_there_done_that++;
68
        pThe_state->rank -= gRank_increase;
69
        if (pThe_state->rank <= 0) {
70
            pThe_state->rank = 1;
71
            for (i = 0; i < gNumber_of_races; i++) {
72
                if (gRace_list[i].best_rank < 2 && !gRace_list[i].been_there_done_that) {
73
                    not_done_yet = 1;
74
                    break;
75
                }
76
            }
77
 
78
            pThe_state->game_completed = !not_done_yet;
79
        }
80
        pThe_state->credits += pThe_state->credits_earned - pThe_state->credits_lost;
81
        if (pThe_state->credits > 999999) {
82
            pThe_state->credits = 999999;
83
        }
84
        pThe_state->credits_earned = 0;
85
        pThe_state->credits_lost = 0;
86
        gRank_increase = 0;
87
        if (pThe_state->credits < 0) {
88
            pThe_state->credits = 0;
89
        }
90
    }
91
}
92
 
93
// IDA: void __cdecl CalcRankIncrease()
94
void CalcRankIncrease(void) {
95
    LOG_TRACE("()");
96
 
97
    if (gNet_mode == eNet_mode_none) {
98
        gRank_increase = gProgram_state.credits_earned / gProgram_state.credits_per_rank;
99
        if (gRank_increase > 5) {
100
            gRank_increase = 5;
101
        }
102
    } else {
103
        gRank_increase = 1;
104
    }
105
}
106
 
107
// IDA: int __usercall RaceSummaryDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
108
int RaceSummaryDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
109
    LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
110
 
111
    if (pTimed_out) {
112
        pCurrent_choice = 0;
113
    } else if (pEscaped) {
114
        pCurrent_choice = -1;
115
    }
116
    return pCurrent_choice;
117
}
118
 
119
// IDA: void __usercall DrawInBox(int pBox_left@<EAX>, int pText_left@<EDX>, int pTop@<EBX>, int pRight@<ECX>, int pBottom, int pColour, int pAmount)
120
void DrawInBox(int pBox_left, int pText_left, int pTop, int pRight, int pBottom, int pColour, int pAmount) {
121
    LOG_TRACE("(%d, %d, %d, %d, %d, %d, %d)", pBox_left, pText_left, pTop, pRight, pBottom, pColour, pAmount);
122
 
123
    BrPixelmapRectangleFill(gBack_screen,
124
        pBox_left,
125
        pTop,
126
        pRight - pBox_left,
127
        pBottom - pTop,
128
        0);
129
    if (pAmount >= 0) {
130
        BrPixelmapTextF(gBack_screen, pText_left, pTop - (TranslationMode() ? 2 : 0), pColour, gFont_7, "%d", pAmount);
131
    }
132
}
133
 
134
// IDA: void __usercall DrawChromeNumber(int pLeft_1@<EAX>, int pLeft_2@<EDX>, int pPitch@<EBX>, int pTop@<ECX>, int pAmount)
135
void DrawChromeNumber(int pLeft_1, int pLeft_2, int pPitch, int pTop, int pAmount) {
136
    LOG_TRACE("(%d, %d, %d, %d, %d)", pLeft_1, pLeft_2, pPitch, pTop, pAmount);
137
 
138
    if (pAmount < 10) {
139
        DRPixelmapRectangleMaskedCopy(gBack_screen,
140
            pLeft_1,
141
            pTop,
142
            gChrome_font,
143
            0,
144
            gChrome_font->height / 10 * pAmount,
145
            gChrome_font->width,
146
            gChrome_font->height / 10);
147
    } else {
148
        DrawChromeNumber(pLeft_2, 0, 0, pTop, pAmount / 10);
149
        DrawChromeNumber(pPitch + pLeft_2, 0, 0, pTop, pAmount % 10);
150
    }
151
}
152
 
153
// IDA: void __cdecl DrawSummaryItems()
154
void DrawSummaryItems(void) {
155
    LOG_TRACE("()");
156
 
157
    DrawInBox(
158
        gCurrent_graf_data->summ1_credits_box_left,
159
        gCurrent_graf_data->summ1_credits_left,
160
        gCurrent_graf_data->summ1_earned_top,
161
        gCurrent_graf_data->summ1_credits_right,
162
        gCurrent_graf_data->summ1_earned_bottom,
163
        2,
164
        gTemp_earned);
165
    DrawInBox(
166
        gCurrent_graf_data->summ1_credits_box_left,
167
        gCurrent_graf_data->summ1_credits_left,
168
        gCurrent_graf_data->summ1_lost_top,
169
        gCurrent_graf_data->summ1_credits_right,
170
        gCurrent_graf_data->summ1_lost_bottom,
171
        2,
172
        gTemp_lost);
173
    DrawInBox(
174
        gCurrent_graf_data->summ1_credits_box_left,
175
        gCurrent_graf_data->summ1_credits_left,
176
        gCurrent_graf_data->summ1_total_top,
177
        gCurrent_graf_data->summ1_credits_right,
178
        gCurrent_graf_data->summ1_total_bottom,
179
        2,
180
        (gTemp_credits <= 0) ? 0 : ((gTemp_credits >= 999999) ? 999999 : gTemp_credits));
181
    BrPixelmapRectangleFill(
182
        gBack_screen,
183
        gCurrent_graf_data->summ1_rank_inc_left,
184
        gCurrent_graf_data->summ1_rank_top,
185
        gCurrent_graf_data->summ1_rank_inc_right - gCurrent_graf_data->summ1_rank_inc_left,
186
        gCurrent_graf_data->summ1_rank_bot - gCurrent_graf_data->summ1_rank_top,
187
        0);
188
    BrPixelmapRectangleFill(
189
        gBack_screen,
190
        gCurrent_graf_data->summ1_rank_total_left,
191
        gCurrent_graf_data->summ1_rank_top,
192
        gCurrent_graf_data->summ1_rank_total_right - gCurrent_graf_data->summ1_rank_total_left,
193
        gCurrent_graf_data->summ1_rank_bot - gCurrent_graf_data->summ1_rank_top,
194
        0);
195
    DrawChromeNumber(
196
        gCurrent_graf_data->summ1_rank_inc_c,
197
        gCurrent_graf_data->summ1_rank_inc_l,
198
        gCurrent_graf_data->summ1_rank_x_pitch,
199
        gCurrent_graf_data->summ1_rank_y,
200
        (int)(gTemp_rank_increase + .5f));
201
    DrawChromeNumber(
202
        gCurrent_graf_data->summ1_rank_total_c,
203
        gCurrent_graf_data->summ1_rank_total_l,
204
        gCurrent_graf_data->summ1_rank_x_pitch,
205
        gCurrent_graf_data->summ1_rank_y,
206
        gTemp_rank);
207
}
208
 
209
// IDA: void __usercall RampUpRate(float *pRate@<EAX>, tU32 pTime@<EDX>)
210
void RampUpRate(float* pRate, tU32 pTime) {
211
    LOG_TRACE("(%p, %d)", pRate, pTime);
212
 
213
    if (pTime >= 6000) {
214
        *pRate = 10.f;
215
    } else if (pTime >= 4000) {
216
        *pRate = 5.f;
217
    } else if (pTime >= 3000) {
218
        *pRate = 1.f;
219
    } else if (pTime >= 2000) {
220
        *pRate = 0.5f;
221
    } else {
222
        *pRate = 0.1f;
223
    }
224
}
225
 
226
// IDA: void __usercall DrawSummary(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
227
void DrawSummary(int pCurrent_choice, int pCurrent_mode) {
228
    tU32 the_time;
229
    static tU32 last_time;
230
    static tU32 last_change_time;
231
    int credit_delta;
232
    float old_temp_increase;
233
    float rank_delta;
234
    LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
235
 
236
    the_time = PDGetTotalTime();
237
    if (the_time - gSummary_start > 3000) {
238
        if (gTemp_earned != 0) {
239
            ResetInterfaceTimeout();
240
            if (gSumm_sound == 0) {
241
                gSumm_sound = DRS3StartSound(gEffects_outlet, 3200);
242
            }
243
            credit_delta = (the_time - last_time) * gCredits_per_ms;
244
            gTemp_earned -= credit_delta;
245
            gTemp_credits += credit_delta;
246
            RampUpRate(&gCredits_per_ms, the_time - last_change_time + 1000);
247
            if (gTemp_earned <= 0) {
248
                gTemp_credits += gTemp_earned;
249
                S3StopOutletSound(gEffects_outlet);
250
                gSumm_sound = 0;
251
                gTemp_earned = 0;
252
                gCredits_per_ms = 0.1f;
253
                last_change_time = the_time;
254
            }
255
        } else if (gTemp_lost != 0) {
256
            ResetInterfaceTimeout();
257
            if (the_time - last_change_time > 1000) {
258
                if (gSumm_sound == 0) {
259
                    gSumm_sound = DRS3StartSound(gEffects_outlet, 3201);
260
                }
261
                credit_delta = (the_time - last_time) * gCredits_per_ms;
262
                gTemp_lost -= credit_delta;
263
                gTemp_credits -= credit_delta;
264
                RampUpRate(&gCredits_per_ms, the_time - last_change_time);
265
                if (gTemp_lost <= 0) {
266
                    gTemp_credits -= gTemp_lost;
267
                    S3StopOutletSound(gEffects_outlet);
268
                    gSumm_sound = 0;
269
                    gTemp_lost = 0;
270
                    last_change_time = the_time;
271
                }
272
            }
273
        } else if (gTemp_rank_increase != 0.f) {
274
            ResetInterfaceTimeout();
275
            if (the_time - last_change_time > 1000) {
276
                rank_delta = (the_time - last_time) * gRank_per_ms;
277
                old_temp_increase = gTemp_rank_increase;
278
                gTemp_rank_increase -= rank_delta;
279
                if ((int)(old_temp_increase + 0.5f) != (int)(gTemp_rank_increase + 0.5f)) {
280
                    if (gTemp_rank > 1) {
281
                        gTemp_rank -= 1;
282
                    }
283
                    gSumm_sound = DRS3StartSound(gEffects_outlet, 3202);
284
                }
285
                if (gTemp_rank_increase <= 0.f) {
286
                    S3StopOutletSound(gEffects_outlet);
287
                    gSumm_sound = 0;
288
                    gTemp_rank_increase = 0.f;
289
                    last_change_time = the_time;
290
                }
291
            }
292
        } else {
293
            S3StopOutletSound(gEffects_outlet);
294
            gSumm_sound = 0;
295
        }
296
    } else {
297
        last_change_time = the_time;
298
    }
299
    DrawSummaryItems();
300
    last_time = the_time;
301
}
302
 
303
// IDA: void __cdecl StartSummary()
304
void StartSummary(void) {
305
    LOG_TRACE("()");
306
 
307
    DrawSummaryItems();
308
    gSummary_start = PDGetTotalTime();
309
}
310
 
311
// IDA: void __cdecl SetUpTemps()
312
void SetUpTemps(void) {
313
    LOG_TRACE("()");
314
 
315
    gTemp_earned = gProgram_state.credits_earned;
316
    gTemp_lost = gProgram_state.credits_lost;
317
    gTemp_rank_increase = gRank_increase;
318
    gTemp_rank = gProgram_state.rank;
319
    gTemp_credits = gProgram_state.credits;
320
}
321
 
322
// IDA: int __usercall Summ1GoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
323
int Summ1GoAhead(int* pCurrent_choice, int* pCurrent_mode) {
324
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
325
 
326
    S3StopOutletSound(gEffects_outlet);
327
    MungeRankEtc(&gProgram_state);
328
    SetUpTemps();
329
    DrawSummaryItems();
330
    return 1;
331
}
332
 
333
// IDA: int __usercall SummCheckGameOver@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
334
int SummCheckGameOver(int* pCurrent_choice, int* pCurrent_mode) {
335
    int i;
336
    //tS3_sound_tag sound_tag; // Pierre-Marie Baty -- unused variable
337
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
338
 
339
    if (gTemp_credits > 0) {
340
        return 0;
341
    }
342
    S3StopOutletSound(gEffects_outlet);
343
    RemoveTransientBitmaps(1);
344
    for (i = 0; i < 7; i++) {
345
        DrawInBox(
346
            gCurrent_graf_data->summ1_credits_box_left,
347
            gCurrent_graf_data->summ1_credits_left,
348
            gCurrent_graf_data->summ1_total_top,
349
            gCurrent_graf_data->summ1_credits_right,
350
            gCurrent_graf_data->summ1_total_bottom,
351
            2, -1);
352
        ProcessFlicQueue(gFrame_period);
353
        PDScreenBufferSwap(0);
354
        SoundService();
355
        WaitFor(300);
356
        DrawInBox(
357
            gCurrent_graf_data->summ1_credits_box_left,
358
            gCurrent_graf_data->summ1_credits_left,
359
            gCurrent_graf_data->summ1_total_top,
360
            gCurrent_graf_data->summ1_credits_right,
361
            gCurrent_graf_data->summ1_total_bottom,
362
            2, 0);
363
        ProcessFlicQueue(gFrame_period);
364
        PDScreenBufferSwap(0);
365
        SoundService();
366
        WaitFor(300);
367
    }
368
    S3StopAllOutletSounds();
369
    return 1;
370
}
371
 
372
// IDA: tSO_result __cdecl DoEndRaceSummary1()
373
tSO_result DoEndRaceSummary1(void) {
374
    static tFlicette flicker_on[1] = {
375
        { 43, { 218, 436 }, { 147, 353 } },
376
    };
377
    static tFlicette flicker_off[1] = {
378
        { 42, { 218, 436 }, { 147, 353 } },
379
    };
380
    static tFlicette push[1] = {
381
        { 154, { 218, 436 }, { 147, 353 } },
382
    };
383
    static tMouse_area mouse_areas[1] = {
384
        { { 218, 436 }, { 147, 353 }, { 281, 562 }, { 167, 401 }, 0, 0, 0, NULL },
385
    };
386
    static tInterface_spec interface_spec = {
387
        0,
388
        310,
389
        0,
390
        0,
391
        0,
392
        0,
393
        -1,
394
        { -1, 0 },
395
        { 0, 0 },
396
        { 0, 0 },
397
        { 0, 0 },
398
        { NULL, NULL },
399
        { -1, 0 },
400
        { 0, 0 },
401
        { 0, 0 },
402
        { 0, 0 },
403
        { NULL, NULL },
404
        { -1, 0 },
405
        { 0, 0 },
406
        { 0, 0 },
407
        { 0, 0 },
408
        { NULL, NULL },
409
        { -1, 0 },
410
        { 1, 0 },
411
        { 0, 0 },
412
        { 0, 0 },
413
        { NULL, NULL },
414
        { 1, 1 },
415
        { Summ1GoAhead, NULL },
416
        { 1, 1 },
417
        { NULL, NULL },
418
        SummCheckGameOver,
419
        DrawSummary,
420
        20000,
421
        NULL,
422
        StartSummary,
423
        RaceSummaryDone,
424
        0,
425
        { 0, 0 },
426
        NULL,
427
        -1,
428
        1,
429
        COUNT_OF(flicker_on),
430
        flicker_on,
431
        flicker_off,
432
        push,
433
        COUNT_OF(mouse_areas),
434
        mouse_areas,
435
        0,
436
        NULL,
437
    };
438
    int result;
439
    int completed_already;
440
    LOG_TRACE("()");
441
 
442
    NetPlayerStatusChanged(ePlayer_status_summary);
443
    completed_already = gProgram_state.game_completed;
444
    gSumm_sound = 0;
445
    CalcRankIncrease();
446
    SetUpTemps();
447
    gCredits_per_ms = 0.1f;
448
    gRank_per_ms = 0.003f;
449
    gChrome_font = LoadChromeFont();
450
    result = DoInterfaceScreen(&interface_spec, 0, 0);
451
    MungeRankEtc(&gProgram_state);
452
    NetPlayerStatusChanged(ePlayer_status_loading);
453
    DisposeChromeFont(gChrome_font);
454
    DRS3StartSound(gEffects_outlet, 3004);
455
    if (result < 0) {
456
        DRS3StartSound(gEffects_outlet, 3007);
457
        RunFlic(311);
458
        result = eSO_main_menu_invoked;
459
    } else if (gTemp_credits <= 0) {
460
        FadePaletteDown();
461
        result = eSO_game_over;
462
    } else if (gProgram_state.game_completed && !completed_already) {
463
        FadePaletteDown();
464
        result = eSO_game_completed;
465
    } else {
466
        DRS3StartSound(gEffects_outlet, 3007);
467
        FadePaletteDown();
468
        result = eSO_continue;
469
    }
470
 
471
    return result;
472
}
473
 
474
// IDA: void __usercall PrepareBoundingRadius(br_model *model@<EAX>)
475
//  Suffix added to avoid duplicate symbol
476
void PrepareBoundingRadius__racesumm(br_model* model) {
477
    float d;
478
    float max;
479
    int v;
480
    br_vertex* vp;
481
    LOG_TRACE("(%p)", model);
482
 
483
    max = 0.f;
484
    for (v = 0; v < model->nvertices; v++) {
485
        vp = &model->vertices[v];
486
        d = BrVector3LengthSquared(&vp->p);
487
        if (d > max) {
488
            max = d;
489
        }
490
    }
491
    d = sqrtf(max);
492
    model->radius = d;
493
}
494
 
495
// IDA: void __cdecl BuildWrecks()
496
void BuildWrecks(void) {
497
    int cat;
498
    int i;
499
    int position;
500
    int car_count;
501
    br_actor* this_car;
502
    tCar_spec* the_car;
503
    LOG_TRACE("()");
504
 
505
    gWreck_count = 0;
506
    position = 0;
507
    gWreck_root = BrActorAllocate(BR_ACTOR_NONE, NULL);
508
    gWreck_camera = BrActorAllocate(BR_ACTOR_CAMERA, NULL);
509
    BrActorAdd(gUniverse_actor, gWreck_root);
510
    BrActorAdd(gWreck_root, gWreck_camera);
511
    memcpy(gWreck_camera->type_data, gCamera_list[1]->type_data, sizeof(br_camera));
512
    ((br_camera*)gWreck_camera->type_data)->aspect = 2.f;
513
    ((br_camera*)gWreck_camera->type_data)->field_of_view = BR_ANGLE_DEG(55);
514
    BrMatrix34Identity(&gWreck_camera->t.t.mat);
515
    BrVector3SetFloat(&gWreck_camera->t.t.translate.t, 0.f, 0.f, 2.2f);
516
    for (cat = eVehicle_self; cat < eVehicle_rozzer; cat++) {
517
        if (cat == eVehicle_self) {
518
            car_count = 1;
519
        } else {
520
            car_count = GetCarCount(cat);
521
        }
522
        for (i = 0; i < car_count; i++) {
523
            if (cat == eVehicle_self) {
524
                the_car = &gProgram_state.current_car;
525
            } else {
526
                the_car = GetCarSpec(cat, i);
527
            }
528
            this_car = the_car->car_model_actors[the_car->principal_car_actor].actor;
529
            memcpy(&gWreck_array[gWreck_count].original_matrix, &this_car->t.t.mat, sizeof(br_matrix34));
530
            BrActorRelink(gWreck_root, this_car);
531
            this_car->render_style = BR_RSTYLE_FACES;
532
            gWreck_array[gWreck_count].customised = 0;
533
            gWreck_array[gWreck_count].actor = this_car;
534
            PrepareBoundingRadius__racesumm(this_car->model);
535
            gWreck_array[gWreck_count].scaling_factor = .47f / this_car->model->radius;
536
            gWreck_array[gWreck_count].pos_x = (position % 3) - 1.0f;
537
            gWreck_array[gWreck_count].pos_y = (position / 3) - 0.5f;
538
            this_car->t.t.translate.t.v[0] = 1.5f * gWreck_array[gWreck_count].pos_x;
539
            this_car->t.t.translate.t.v[1] = -1.2f * gWreck_array[gWreck_count].pos_y;
540
            this_car->t.t.translate.t.v[2] = 0.f;
541
            gWreck_array[gWreck_count].car_type = cat;
542
            gWreck_array[gWreck_count].car_index = i;
543
            gWreck_count += 1;
544
            position += 1;
545
        }
546
    }
547
    gWreck_render_area = BrPixelmapAllocateSub(
548
        gBack_screen,
549
        gCurrent_graf_data->wreck_render_x,
550
        gCurrent_graf_data->wreck_render_y,
551
        gCurrent_graf_data->wreck_render_w,
552
        gCurrent_graf_data->wreck_render_h);
553
    gWreck_render_area->origin_x = gWreck_render_area->width / 2;
554
    gWreck_render_area->origin_y = gWreck_render_area->height / 2;
555
    gWreck_z_buffer = BrPixelmapAllocateSub(
556
        gDepth_buffer,
557
        gCurrent_graf_data->wreck_render_x,
558
        gCurrent_graf_data->wreck_render_y,
559
        gCurrent_graf_data->wreck_render_w,
560
        gCurrent_graf_data->wreck_render_h);
561
}
562
 
563
// IDA: void __cdecl DisposeWrecks()
564
void DisposeWrecks(void) {
565
    int cat;
566
    int i;
567
    //int position; // Pierre-Marie Baty -- unused variable
568
    int car_count;
569
    br_actor* this_car;
570
    tCar_spec* the_car;
571
    LOG_TRACE("()");
572
 
573
    for (cat = eVehicle_self; cat < eVehicle_rozzer; cat++) {
574
        if (cat == eVehicle_self) {
575
            car_count = 1;
576
        } else {
577
            car_count = GetCarCount(cat);
578
        }
579
        for (i = 0; i < car_count; i++) {
580
            if (cat == eVehicle_self) {
581
                the_car = &gProgram_state.current_car;
582
            } else {
583
                the_car = GetCarSpec(cat, i);
584
            }
585
            this_car = the_car->car_model_actors[the_car->principal_car_actor].actor;
586
            BrActorRelink(the_car->car_master_actor, this_car);
587
            this_car->render_style = BR_RSTYLE_NONE;
588
        }
589
    }
590
    for (i = 0; i < gWreck_count; i++) {
591
        memcpy(&gWreck_array[i].actor->t.t.mat, &gWreck_array[i].original_matrix, sizeof(br_matrix34));
592
    }
593
    BrActorRemove(gWreck_root);
594
    BrActorRemove(gWreck_camera);
595
    BrActorFree(gWreck_root);
596
    BrActorFree(gWreck_camera);
597
    gWreck_render_area->pixels = NULL;
598
    gWreck_z_buffer->pixels = NULL;
599
    BrPixelmapFree(gWreck_render_area);
600
    BrPixelmapFree(gWreck_z_buffer);
601
}
602
 
603
// IDA: int __usercall MatrixIsIdentity@<EAX>(br_matrix34 *pMat@<EAX>)
604
int MatrixIsIdentity(br_matrix34* pMat) {
605
    LOG_TRACE("(%p)", pMat);
606
 
607
    return (pMat->m[0][0] == 1.f && pMat->m[1][1] == 1.f && pMat->m[2][2] == 1.f && pMat->m[0][1] == 0.f && pMat->m[0][2] == 0.f && pMat->m[1][0] == 0.f && pMat->m[1][2] == 0.f && pMat->m[2][0] == 0.f && pMat->m[2][1] == 0.f);
608
}
609
 
610
// IDA: void __usercall SpinWrecks(tU32 pFrame_period@<EAX>)
611
void SpinWrecks(tU32 pFrame_period) {
612
    int i;
613
    br_vector3 translation;
614
    br_matrix34 old_mat;
615
    LOG_TRACE("(%d)", pFrame_period);
616
 
617
    for (i = 0; i < gWreck_count; i++) {
618
        if (gWreck_array[i].customised == 0) {
619
            BrMatrix34RotateY(&gWreck_array[i].rotation, BR_ANGLE_DEG(.05f * pFrame_period));
620
        }
621
        BrVector3Copy(&translation, &gWreck_array[i].actor->t.t.translate.t);
622
        BrVector3Set(&gWreck_array[i].actor->t.t.translate.t, 0.f, 0.f, 0.f);
623
        BrMatrix34Post(&gWreck_array[i].actor->t.t.mat, &gWreck_array[i].rotation);
624
        if (!MatrixIsIdentity(&gWreck_array[i].actor->t.t.mat)) {
625
            memcpy(&old_mat, &gWreck_array[i].actor->t.t.mat, sizeof(br_matrix34));
626
            BrMatrix34LPNormalise(&gWreck_array[i].actor->t.t.mat, &old_mat);
627
            BrMatrix34PostScale(&gWreck_array[i].actor->t.t.mat,
628
                gWreck_array[i].scaling_factor, gWreck_array[i].scaling_factor, gWreck_array[i].scaling_factor);
629
        }
630
        BrVector3Copy(&gWreck_array[i].actor->t.t.translate.t, &translation);
631
    }
632
}
633
 
634
// IDA: void __usercall ZoomInTo(int pIndex@<EAX>, int *pCurrent_choice@<EDX>, int *pCurrent_mode@<EBX>)
635
void ZoomInTo(int pIndex, int* pCurrent_choice, int* pCurrent_mode) {
636
    LOG_TRACE("(%d, %p, %p)", pIndex, pCurrent_choice, pCurrent_mode);
637
 
638
    gWreck_zoom_in = pIndex;
639
    gWreck_zoom_out = -1;
640
    gWreck_start_zoom = PDGetTotalTime();
641
    if (gWreck_selected == 0 && !gUser_interacted) {
642
        *pCurrent_choice = 2;
643
        *pCurrent_mode = 1;
644
    } else {
645
        *pCurrent_choice = 0;
646
        *pCurrent_mode = 0;
647
    }
648
    RemoveTransientBitmaps(1);
649
    TurnFlicTransparencyOn();
650
    RunFlicAt(325, 9, 174);
651
    TurnFlicTransparencyOff();
652
    gBack_button_ptr->new_choice = -1;
653
    gBack_button_ptr->new_mode = -1;
654
}
655
 
656
// IDA: void __usercall ZoomOutTo(int pIndex@<EAX>, int *pCurrent_choice@<EDX>, int *pCurrent_mode@<EBX>)
657
void ZoomOutTo(int pIndex, int* pCurrent_choice, int* pCurrent_mode) {
658
    LOG_TRACE("(%d, %p, %p)", pIndex, pCurrent_choice, pCurrent_mode);
659
 
660
    gWreck_zoom_out = pIndex;
661
    gWreck_zoom_in = -1;
662
    gWreck_start_zoom = PDGetTotalTime();
663
    RemoveTransientBitmaps(1);
664
    TurnFlicTransparencyOn();
665
    RunFlicAt(326, 9, 174);
666
    TurnFlicTransparencyOff();
667
    memcpy(gBack_button_ptr, &gOld_back_button, sizeof(tMouse_area));
668
    *pCurrent_choice = 1;
669
    *pCurrent_mode = 1;
670
}
671
 
672
// IDA: int __cdecl WreckPick(br_actor *pActor, br_model *pModel, br_material *pMaterial, br_vector3 *pRay_pos, br_vector3 *pRay_dir, br_scalar pNear, br_scalar pFar, void *pArg)
673
int WreckPick(br_actor* pActor, br_model* pModel, br_material* pMaterial, br_vector3* pRay_pos, br_vector3* pRay_dir, br_scalar pNear, br_scalar pFar, void* pArg) {
674
    int i;
675
    LOG_TRACE("(%p, %p, %p, %p, %p, %f, %f, %p)", pActor, pModel, pMaterial, pRay_pos, pRay_dir, pNear, pFar, pArg);
676
 
677
    for (i = 0; i < gWreck_count; i++) {
678
        if (gWreck_array[i].actor == pActor) {
679
            gWreck_selected = i;
680
            return 1;
681
        }
682
    }
683
    return 0;
684
}
685
 
686
// IDA: int __usercall CastSelectionRay@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
687
int CastSelectionRay(int* pCurrent_choice, int* pCurrent_mode) {
688
    int mouse_x;
689
    int mouse_y;
690
    int i;
691
    int result;
692
    br_scalar inv_wreck_pick_scale_factor;
693
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
694
 
695
    if (!gMouse_in_use) {
696
        return 0;
697
    }
698
    if (*pCurrent_choice != 0) {
699
        return 0;
700
    }
701
    if (*pCurrent_mode != 0) {
702
        return 0;
703
    }
704
    if (gWreck_zoomed_in >= 0) {
705
        return 0;
706
    }
707
    if (gWreck_zoom_out >= 0) {
708
        return 0;
709
    }
710
    if (gWreck_zoom_in >= 0) {
711
        return 0;
712
    }
713
 
714
    inv_wreck_pick_scale_factor = 0.5f;
715
    GetMousePosition(&mouse_x, &mouse_y);
716
    if (gReal_graf_data_index != 0) {
717
        mouse_x = 2 * mouse_x;
718
        mouse_y = 2 * mouse_y + 40;
719
    }
720
    for (i = 0; i < gWreck_count; i++) {
721
        BrMatrix34PreScale(&gWreck_array[i].actor->t.t.mat, 2.f, 2.f, 2.f);
722
    }
723
    result = DRScenePick2DXY(gWreck_root, gWreck_camera, gRender_screen,
724
        mouse_x - gBack_screen->width / 2,
725
        mouse_y - gBack_screen->height / 2,
726
        WreckPick,
727
        NULL);
728
    for (i = 0; i < gWreck_count; i++) {
729
        BrMatrix34PreScale(&gWreck_array[i].actor->t.t.mat,
730
            inv_wreck_pick_scale_factor, inv_wreck_pick_scale_factor, inv_wreck_pick_scale_factor);
731
    }
732
    return result;
733
}
734
 
735
// IDA: int __usercall DamageScrnExit@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
736
int DamageScrnExit(int* pCurrent_choice, int* pCurrent_mode) {
737
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
738
 
739
    if (gProgram_state.prog_status == eProg_idling) {
740
        return 1;
741
    } else {
742
        if (gWreck_gallery_start == 0) {
743
            gWreck_gallery_start = PDGetTotalTime();
744
        } else if (!gDone_initial && gWreck_selected == 0) {
745
            if (PDGetTotalTime() - gWreck_gallery_start > 1500) {
746
                ZoomOutTo(gWreck_selected, pCurrent_choice, pCurrent_mode);
747
                gDone_initial = 1;
748
            }
749
        }
750
        CastSelectionRay(pCurrent_choice, pCurrent_mode);
751
        return 0;
752
    }
753
}
754
 
755
// IDA: void __usercall DamageScrnDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
756
void DamageScrnDraw(int pCurrent_choice, int pCurrent_mode) {
757
    tU32 the_time;
758
    br_vector3 camera_movement;
759
    int finished;
760
    int h;
761
    int v;
762
    int rows;
763
    int columns;
764
    //float spacing; // Pierre-Marie Baty -- unused variable
765
    br_actor* sel_actor;
766
    char* name;
767
    LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
768
 
769
    if (((pCurrent_choice == 0 && pCurrent_mode == 0) || !gDone_initial) && (gWreck_zoomed_in < 0 && gWreck_selected >= 0)) {
770
        sel_actor = BrActorAllocate(BR_ACTOR_MODEL, NULL);
771
        sel_actor->render_style = BR_RSTYLE_BOUNDING_EDGES;
772
        sel_actor->model = gWreck_array[gWreck_selected].actor->model;
773
        BrActorAdd(gWreck_array[gWreck_selected].actor, sel_actor);
774
    } else {
775
        sel_actor = NULL;
776
    }
777
    the_time = PDGetTotalTime();
778
    SpinWrecks(the_time - gLast_wreck_draw);
779
    gLast_wreck_draw = the_time;
780
    if (gWreck_zoom_out >= 0 || gWreck_zoom_in >= 0) {
781
        if (gWreck_start_zoom == 0) {
782
            gWreck_start_zoom = the_time;
783
        }
784
        finished = the_time - gWreck_start_zoom > 1000;
785
        if (finished) {
786
            the_time = gWreck_start_zoom + 1000;
787
        }
788
        if (gWreck_zoom_out < 0) {
789
            camera_movement.v[0] = (1.f - (the_time - gWreck_start_zoom) / 1000.f) * gWreck_array[gWreck_zoom_in].actor->t.t.translate.t.v[0];
790
            camera_movement.v[1] = (1.f - (the_time - gWreck_start_zoom) / 1000.f) * gWreck_array[gWreck_zoom_in].actor->t.t.translate.t.v[1];
791
            camera_movement.v[2] = (1.f - (the_time - gWreck_start_zoom) / 1000.f) * -1.45f;
792
            if (finished) {
793
                gWreck_zoom_in = -1;
794
                gWreck_zoomed_in = -1;
795
            }
796
        } else {
797
            camera_movement.v[0] = (the_time - gWreck_start_zoom) / 1000.f * gWreck_array[gWreck_zoom_out].actor->t.t.translate.t.v[0];
798
            camera_movement.v[1] = (the_time - gWreck_start_zoom) / 1000.f * gWreck_array[gWreck_zoom_out].actor->t.t.translate.t.v[1];
799
            camera_movement.v[2] = (the_time - gWreck_start_zoom) / 1000.f * -1.45f;
800
            if (finished) {
801
                gWreck_zoomed_in = gWreck_zoom_out;
802
                gWreck_zoom_out = -1;
803
            }
804
        }
805
        gWreck_camera->t.t.translate.t.v[0] = camera_movement.v[0];
806
        gWreck_camera->t.t.translate.t.v[1] = camera_movement.v[1];
807
        gWreck_camera->t.t.translate.t.v[2] = camera_movement.v[2] + 2.2f;
808
    }
809
    EnsureRenderPalette();
810
    EnsurePaletteUp();
811
    BrPixelmapFill(gWreck_z_buffer, 0xffffffff);
812
    BrPixelmapFill(gWreck_render_area, BR_COLOUR_RGBA(0xb0, 0xb0, 0xb0, 0xb0));
813
 
814
    rows = gWreck_render_area->height / 15.f;
815
    columns = gWreck_render_area->width / 15.f;
816
    for (v = 0; v <= rows; v++) {
817
        BrPixelmapLine(gWreck_render_area,
818
            -gWreck_render_area->origin_x,
819
            gWreck_render_area->height / 2.f - 15.f * (rows / 2.f - v) - gWreck_render_area->origin_y,
820
            gWreck_render_area->width - gWreck_render_area->origin_x,
821
            gWreck_render_area->height / 2.f - 15.f * (rows / 2.f - v) - gWreck_render_area->origin_y,
822
            8);
823
    }
824
    for (h = 0; h <= columns; h++) {
825
        BrPixelmapLine(gWreck_render_area,
826
            gWreck_render_area->width / 2.f - 15.f * (columns / 2.f - h) - gWreck_render_area->origin_x,
827
            -gWreck_render_area->origin_y,
828
            gWreck_render_area->width / 2.f - 15.f * (columns / 2.f - h) - gWreck_render_area->origin_x,
829
            gWreck_render_area->height - gWreck_render_area->origin_y,
830
            8);
831
    }
832
    BrZbSceneRenderBegin(gUniverse_actor, gWreck_camera, gWreck_render_area, gWreck_z_buffer);
833
    BrZbSceneRenderAdd(gWreck_root);
834
    BrZbSceneRenderEnd();
835
    if (sel_actor != NULL) {
836
        BrActorRemove(sel_actor);
837
        sel_actor->model = NULL;
838
        BrActorFree(sel_actor);
839
    }
840
    BrPixelmapRectangleFill(gBack_screen,
841
        gCurrent_graf_data->wreck_name_left,
842
        gCurrent_graf_data->wreck_name_top,
843
        gCurrent_graf_data->wreck_name_right - gCurrent_graf_data->wreck_name_left,
844
        gCurrent_graf_data->wreck_name_bottom - gCurrent_graf_data->wreck_name_top,
845
        0);
846
    if (gWreck_selected >= 0 && (gWreck_zoomed_in >= 0 || pCurrent_mode == 0)) {
847
        name = GetDriverName(gWreck_array[gWreck_selected].car_type,
848
            gWreck_array[gWreck_selected].car_index);
849
        TransBrPixelmapText(gBack_screen,
850
            (gCurrent_graf_data->wreck_name_left + gCurrent_graf_data->wreck_name_right - BrPixelmapTextWidth(gBack_screen, gFont_7, name)) / 2,
851
            gCurrent_graf_data->wreck_name_base_line,
852
            84,
853
            gFont_7,
854
            name);
855
    }
856
}
857
 
858
// IDA: int __usercall DamageScrnLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
859
int DamageScrnLeft(int* pCurrent_choice, int* pCurrent_mode) {
860
    int i;
861
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
862
 
863
    gDone_initial = 1;
864
    DRS3StartSound(gEffects_outlet, 3000);
865
    if (*pCurrent_mode == 0 && gWreck_zoomed_in < 0) {
866
        if (gWreck_selected < 0) {
867
            gWreck_selected = gWreck_count - 1;
868
        } else if (gWreck_selected != 0 && gWreck_array[gWreck_selected - 1].pos_y == gWreck_array[gWreck_selected].pos_y) {
869
            gWreck_selected--;
870
        } else {
871
            for (i = gWreck_count - 1; i >= 0; i--) {
872
                if (gWreck_array[i].pos_y == gWreck_array[gWreck_selected].pos_y) {
873
                    gWreck_selected = i;
874
                    break;
875
                }
876
            }
877
        }
878
    } else if (gWreck_zoomed_in >= 0) {
879
        *pCurrent_choice = *pCurrent_choice + 1;
880
        if (*pCurrent_choice == 3) {
881
            *pCurrent_choice = 1;
882
        }
883
    }
884
    return 1;
885
}
886
 
887
// IDA: int __usercall DamageScrnRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
888
int DamageScrnRight(int* pCurrent_choice, int* pCurrent_mode) {
889
    int i;
890
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
891
 
892
    gDone_initial = 1;
893
    DRS3StartSound(gEffects_outlet, 3000);
894
    if (*pCurrent_mode == 0 && gWreck_zoomed_in < 0) {
895
        if (gWreck_selected < 0) {
896
            gWreck_selected = 0;
897
        } else if (gWreck_selected - 1 != gWreck_count && gWreck_array[gWreck_selected + 1].pos_y == gWreck_array[gWreck_selected].pos_y) {
898
            gWreck_selected++;
899
        } else {
900
            for (i = 0; i < gWreck_count; i++) {
901
                if (gWreck_array[i].pos_y == gWreck_array[gWreck_selected].pos_y) {
902
                    gWreck_selected = i;
903
                    break;
904
                }
905
            }
906
        }
907
    } else if (gWreck_zoomed_in >= 0) {
908
        *pCurrent_choice = *pCurrent_choice + 1;
909
        if (*pCurrent_choice == 3) {
910
            *pCurrent_choice = 1;
911
        }
912
    }
913
    return 1;
914
}
915
 
916
// IDA: int __usercall DamageScrnUp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
917
int DamageScrnUp(int* pCurrent_choice, int* pCurrent_mode) {
918
    int i;
919
    int difference;
920
    int new_difference;
921
    int new_selection;
922
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
923
 
924
    gDone_initial = 1;
925
    DRS3StartSound(gEffects_outlet, 3000);
926
    if (*pCurrent_mode != 0) {
927
        *pCurrent_mode = 0;
928
        *pCurrent_choice = 0;
929
        if (gWreck_zoomed_in < 0) {
930
            gWreck_selected = gWreck_count + -1;
931
        }
932
    } else {
933
        if (gWreck_selected < 0) {
934
            if (gWreck_zoomed_in < 0) {
935
                gWreck_selected = gWreck_count - 1;
936
            }
937
        } else if (gWreck_zoomed_in >= 0) {
938
            *pCurrent_mode = 1;
939
            *pCurrent_choice = 1;
940
        } else if (gWreck_array[gWreck_selected].pos_y == gWreck_array[0].pos_y) {
941
            *pCurrent_mode = 1;
942
            *pCurrent_choice = 2;
943
        } else {
944
            new_difference = 1000;
945
            new_selection = gWreck_selected;
946
            for (i = 0; i < gWreck_count; i++) {
947
                if (gWreck_array[gWreck_selected].pos_y - 1.f == gWreck_array[i].pos_y) {
948
                    if (gWreck_array[i].pos_x == gWreck_array[gWreck_selected].pos_x) {
949
                        new_selection = i;
950
                        break;
951
                    }
952
                    difference = abs((int)(gWreck_array[i].pos_x - gWreck_array[gWreck_selected].pos_x));
953
                    if (difference < new_difference) {
954
                        new_selection = i;
955
                        new_difference = difference;
956
                    }
957
                }
958
            }
959
            gWreck_selected = new_selection;
960
        }
961
    }
962
    return 1;
963
}
964
 
965
// IDA: int __usercall DamageScrnDown@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
966
int DamageScrnDown(int* pCurrent_choice, int* pCurrent_mode) {
967
    int i;
968
    int difference;
969
    int new_difference;
970
    int new_selection;
971
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
972
 
973
    gDone_initial = 1;
974
    DRS3StartSound(gEffects_outlet, 3000);
975
    if (*pCurrent_mode != 0) {
976
        *pCurrent_mode = 0;
977
        *pCurrent_choice = 0;
978
        if (gWreck_zoomed_in < 0) {
979
            for (i = gWreck_count - 1; i >= 0; i--) {
980
                if (gWreck_array[i].pos_y == gWreck_array[0].pos_y) {
981
                    gWreck_selected = i;
982
                    break;
983
                }
984
            }
985
        }
986
    } else {
987
        if (gWreck_selected < 0) {
988
            gWreck_selected = 0;
989
        } else if (gWreck_zoomed_in >= 0) {
990
            *pCurrent_mode = 1;
991
            *pCurrent_choice = 1;
992
        } else if (gWreck_array[gWreck_selected].pos_y == gWreck_array[gWreck_count - 1].pos_y) {
993
            *pCurrent_mode = 1;
994
            *pCurrent_choice = 2;
995
        } else {
996
            new_difference = 1000;
997
            new_selection = gWreck_selected;
998
            for (i = 0; i < gWreck_count; i++) {
999
                if (gWreck_array[gWreck_selected].pos_y + 1.f == gWreck_array[i].pos_y) {
1000
                    if (gWreck_array[i].pos_x == gWreck_array[gWreck_selected].pos_x) {
1001
                        new_selection = i;
1002
                        break;
1003
                    }
1004
                    difference = abs((int)(gWreck_array[i].pos_x - gWreck_array[gWreck_selected].pos_x));
1005
                    if (difference < new_difference) {
1006
                        new_selection = i;
1007
                        new_difference = difference;
1008
                    }
1009
                }
1010
            }
1011
            gWreck_selected = new_selection;
1012
        }
1013
    }
1014
    return 1;
1015
}
1016
 
1017
// IDA: int __usercall DamageScrnGoHead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
1018
int DamageScrnGoHead(int* pCurrent_choice, int* pCurrent_mode) {
1019
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
1020
 
1021
    gDone_initial = 1;
1022
    if (*pCurrent_choice == 2) {
1023
        return 1;
1024
    } else if (gWreck_zoomed_in < 0) {
1025
        if (*pCurrent_choice == 0 && gWreck_selected >= 0) {
1026
            ZoomOutTo(gWreck_selected, pCurrent_choice, pCurrent_mode);
1027
            gUser_interacted = 1;
1028
        }
1029
    } else if (*pCurrent_choice == 1) {
1030
        ZoomInTo(gWreck_selected, pCurrent_choice, pCurrent_mode);
1031
    }
1032
    gDone_initial = 1;
1033
    return 0;
1034
}
1035
 
1036
// IDA: int __usercall ClickDamage@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
1037
int ClickDamage(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
1038
    int mouse_x;
1039
    int mouse_y;
1040
    int old_mouse_x;
1041
    int old_mouse_y;
1042
    LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
1043
 
1044
#if defined(DETHRACE_FIX_BUGS)
1045
    old_mouse_x = 0; // Fixes warning caused by -Wsometimes-uninitialized
1046
    old_mouse_y = 0; // Fixes warning caused by -Wsometimes-uninitialized
1047
#endif
1048
    GetMousePosition(&old_mouse_y, &old_mouse_y);
1049
    if (gWreck_zoomed_in < 0) {
1050
        if (CastSelectionRay(pCurrent_choice, pCurrent_mode)) {
1051
            gUser_interacted = 1;
1052
            return 1;
1053
        } else {
1054
            return 0;
1055
        }
1056
    } else {
1057
        while (1) {
1058
            GetMousePosition(&mouse_x, &mouse_y);
1059
            BrMatrix34RollingBall(&gWreck_array[gWreck_zoomed_in].rotation, mouse_x - old_mouse_x, old_mouse_y - mouse_y, 50);
1060
            old_mouse_x = mouse_x;
1061
            old_mouse_y = mouse_y;
1062
            gWreck_array[gWreck_zoomed_in].customised = 1;
1063
            RemoveTransientBitmaps(1);
1064
            DamageScrnDraw(0, 0);
1065
            ProcessFlicQueue(gFrame_period);
1066
            DoMouseCursor();
1067
            PDScreenBufferSwap(0);
1068
            ServiceGame();
1069
            if (!EitherMouseButtonDown()) {
1070
                break;
1071
            }
1072
        }
1073
        return 0;
1074
    }
1075
}
1076
 
1077
// IDA: int __usercall DamageScrnDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
1078
int DamageScrnDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
1079
    LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
1080
 
1081
    if (pTimed_out) {
1082
        pCurrent_choice = 2;
1083
    }
1084
    return pCurrent_choice;
1085
}
1086
 
1087
// IDA: tSO_result __cdecl DoEndRaceSummary2()
1088
tSO_result DoEndRaceSummary2(void) {
1089
    static tFlicette flicker_on[3] = {
1090
        { -1, { 0, 0 }, { 0, 0 } },
1091
        { 321, { 9, 18 }, { 174, 418 } },
1092
        { 321, { 247, 494 }, { 174, 418 } },
1093
    };
1094
    static tFlicette flicker_off[3] = {
1095
        { -1, { 0, 0 }, { 0, 0 } },
1096
        { 322, { 9, 18 }, { 174, 418 } },
1097
        { 322, { 247, 494 }, { 174, 418 } },
1098
    };
1099
    static tFlicette push[3] = {
1100
        { -1, { 0, 0 }, { 0, 0 } },
1101
        { 324, { 9, 18 }, { 174, 418 } },
1102
        { 323, { 247, 494 }, { 174, 418 } },
1103
    };
1104
    static tMouse_area mouse_areas[3] = {
1105
        { { 11, 22 }, { 20, 48 }, { 309, 618 }, { 169, 406 }, 0, 0, 0, ClickDamage },
1106
        { { 9, 18 }, { 174, 418 }, { 72, 144 }, { 194, 466 }, 1, 1, 0, NULL },
1107
        { { 247, 494 }, { 174, 418 }, { 310, 620 }, { 194, 466 }, 2, 1, 0, NULL },
1108
    };
1109
    static tInterface_spec interface_spec = {
1110
        1, 320, 0, -1, -1, -1, -1,
1111
        { -1, -1 }, { 0, 0 }, { 0, 0 }, { 0, 2 }, { DamageScrnLeft, DamageScrnLeft },
1112
        { -1, -1 }, { 0, 0 }, { 0, 0 }, { 0, 2 }, { DamageScrnRight, DamageScrnRight },
1113
        { 1, 0 }, { 0, 0 }, { 1, 0 }, { 2, 0 }, { DamageScrnUp, DamageScrnUp },
1114
        { 1, 0 }, { 0, 0 }, { 1, 0 }, { 2, 0 }, { DamageScrnDown, DamageScrnDown },
1115
        { 1, 1 }, { DamageScrnGoHead, DamageScrnGoHead },
1116
        { 1, 1 }, { NULL, NULL },
1117
        DamageScrnExit, DamageScrnDraw,
1118
        20000, NULL, NULL, DamageScrnDone, 0,
1119
        { 0, 0 }, NULL, 2, 1,
1120
        COUNT_OF(flicker_on), flicker_on, flicker_off, push,
1121
        COUNT_OF(mouse_areas), mouse_areas,
1122
        0, NULL
1123
    };
1124
    int result;
1125
    LOG_TRACE("()");
1126
 
1127
    if (gAusterity_mode) {
1128
        return eSO_continue;
1129
    }
1130
    NetPlayerStatusChanged(ePlayer_status_wrecks_gallery);
1131
    gBack_button_ptr = &mouse_areas[1];
1132
    memcpy(&gOld_back_button, &mouse_areas[1], sizeof(tMouse_area));
1133
    gOld_back_button.new_choice = 1;
1134
    gOld_back_button.new_mode = 1;
1135
    memcpy(gBack_button_ptr, &gOld_back_button, sizeof(tMouse_area));
1136
    BuildWrecks();
1137
    gWreck_zoom_out = -1;
1138
    gWreck_zoom_in = -1;
1139
    gWreck_start_zoom = 0;
1140
    gWreck_zoomed_in = -1;
1141
    gWreck_selected = 0;
1142
    gUser_interacted = 0;
1143
    gDone_initial = 0;
1144
    TurnOnPaletteConversion();
1145
    gWreck_gallery_start = 0;
1146
    result = DoInterfaceScreen(&interface_spec, 0, 2);
1147
    NetPlayerStatusChanged(ePlayer_status_loading);
1148
    TurnOffPaletteConversion();
1149
    DisposeWrecks();
1150
    if (result < 0) {
1151
        return eSO_main_menu_invoked;
1152
    }
1153
    return eSO_continue;
1154
}
1155
 
1156
// IDA: void __usercall DrawAnItem(int pX@<EAX>, int pY_index@<EDX>, int pFont_index@<EBX>, char *pText@<ECX>)
1157
//  Suffix added to avoid duplicate symbol
1158
void DrawAnItem__racesumm(int pX, int pY_index, int pFont_index, char* pText) {
1159
    LOG_TRACE("(%d, %d, %d, \"%s\")", pX, pY_index, pFont_index, pText);
18 pmbaty 1160
 
1161
    TransBrPixelmapText(gBack_screen,
1162
        pX,
1163
        gCurrent_graf_data->net_sum_headings_y + gCurrent_graf_data->net_sum_y_pitch * pY_index,
1164
        pFont_index,
1165
        gFont_7,
1166
        pText);
1 pmbaty 1167
}
1168
 
1169
// IDA: void __usercall DrawColumnHeading(int pStr_index@<EAX>, int pX@<EDX>)
1170
//  Suffix added to avoid duplicate symbol
1171
void DrawColumnHeading__racesumm(int pStr_index, int pX) {
1172
    LOG_TRACE("(%d, %d)", pStr_index, pX);
18 pmbaty 1173
 
1174
    TransBrPixelmapText(gBack_screen,
1175
        pX,
1176
        gCurrent_graf_data->net_sum_headings_y - gCurrent_graf_data->net_sum_y_pitch,
1177
        250,
1178
        gFont_7,
1179
        GetMiscString(pStr_index));
1 pmbaty 1180
}
1181
 
1182
// IDA: int __usercall SortScores@<EAX>(void *pFirst_one@<EAX>, void *pSecond_one@<EDX>)
18 pmbaty 1183
int SortScores(const void* pFirst_one, const void* pSecond_one) {
1 pmbaty 1184
    LOG_TRACE("(%p, %p)", pFirst_one, pSecond_one);
18 pmbaty 1185
 
1186
    return gNet_players[*(int*)pSecond_one].games_score - gNet_players[*(int*)pFirst_one].games_score;
1 pmbaty 1187
}
1188
 
1189
// IDA: void __cdecl SortGameScores()
1190
void SortGameScores(void) {
1191
    LOG_TRACE("()");
18 pmbaty 1192
    qsort(gPlayer_lookup, gNumber_of_net_players, sizeof(gPlayer_lookup[0]), SortScores);
1 pmbaty 1193
}
1194
 
1195
// IDA: void __usercall NetSumDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
1196
void NetSumDraw(int pCurrent_choice, int pCurrent_mode) {
18 pmbaty 1197
    int i;
1198
    char s[256];
1199
    tNet_game_player_info* player;
1 pmbaty 1200
    LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
18 pmbaty 1201
 
1202
    DrawColumnHeading__racesumm(kMiscString_PLAYED, gCurrent_graf_data->net_sum_x_3);
1203
    DrawColumnHeading__racesumm(kMiscString_WON, gCurrent_graf_data->net_sum_x_4);
1204
    DrawColumnHeading__racesumm(kMiscString_SCORE, gCurrent_graf_data->net_sum_x_5);
1205
    BrPixelmapLine(gBack_screen,
1206
        gCurrent_graf_data->net_sum_x_1,
1207
        gCurrent_graf_data->net_sum_headings_y + 1 + gFont_7->glyph_y - gCurrent_graf_data->net_sum_y_pitch,
1208
        gBack_screen->width - gCurrent_graf_data->net_sum_x_1,
1209
        gCurrent_graf_data->net_sum_headings_y + 1 + gFont_7->glyph_y - gCurrent_graf_data->net_sum_y_pitch,
1210
        252);
1211
 
1212
    for (i = 0; i < gNumber_of_net_players; i++) {
1213
        player = &gNet_players[gPlayer_lookup[i]];
1214
 
1215
        strcpy(s, player->player_name);
1216
        if (player->host) {
1217
            strcat(s, " -");
1218
            strcat(s, GetMiscString(kMiscString_HOST));
1219
            strcat(s, "-");
1220
        }
1221
        TurnOffPaletteConversion();
1222
        DRPixelmapRectangleMaskedCopy(gBack_screen,
1223
            gCurrent_graf_data->net_sum_x_1,
1224
            gCurrent_graf_data->net_sum_headings_y + 1 + i * gCurrent_graf_data->net_sum_y_pitch,
1225
            gIcons_pix_low_res,  /* DOS version uses low res, Windows version uses normal res */
1226
            0,
1227
            gCurrent_graf_data->net_head_icon_height * player->car_index,
1228
            gIcons_pix_low_res->width,  /* DOS version uses low res, Windows version uses normal res */
1229
            gCurrent_graf_data->net_head_icon_height);
1230
        TurnOnPaletteConversion();
1231
        DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_2, i, 83, s);
1232
        sprintf(s, "%d", player->played);
1233
        DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_3, i, 83, s);
1234
        sprintf(s, "%d", player->won);
1235
        DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_4, i, 83, s);
1236
        sprintf(s, "%d", player->games_score);
1237
        DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_5, i, 83, s);
1238
    }
1 pmbaty 1239
}
1240
 
1241
// IDA: void __cdecl DoNetRaceSummary()
1242
void DoNetRaceSummary(void) {
18 pmbaty 1243
    static tFlicette flicker_on[1] = { { 321, { 219, 112 }, { 172, 362 } } };
1244
    static tFlicette flicker_off[1] = { { 322, { 219, 112 }, { 172, 362 } } };
1245
    static tFlicette push[1] = { { 323, { 219, 112 }, { 172, 362 } } };
1246
    static tMouse_area mouse_areas[1] = { { { 219, 112 }, { 172, 362 }, { 282, 182 }, { 192, 379 }, 0, 0, 0, NULL } };
1247
    static tInterface_spec interface_spec = {
1248
        0,              // initial_imode
1249
        63,             // first_opening_flic
1250
        0,              // second_opening_flic
1251
        -1,             // end_flic_go_ahead
1252
        -1,             // end_flic_escaped
1253
        -1,             // end_flic_otherwise
1254
        8,              // flic_bunch_to_load
1255
        { -1, 0 },      // move_left_new_mode
1256
        { 0, 0 },       // move_left_delta
1257
        { 0, 0 },       // move_left_min
1258
        { 0, 0 },       // move_left_max
1259
        { NULL, NULL }, // move_left_proc
1260
        { -1, 0 },      // move_right_new_mode
1261
        { 0, 0 },       // move_right_delta
1262
        { 0, 0 },       // move_right_min
1263
        { 0, 0 },       // move_right_max
1264
        { NULL, NULL }, // move_right_proc
1265
        { -1, 0 },      // move_up_new_mode
1266
        { 0, 0 },       // move_up_delta
1267
        { 0, 0 },       // move_up_min
1268
        { 0, 0 },       // move_up_max
1269
        { NULL, NULL }, // move_up_proc
1270
        { -1, 0 },      // move_down_new_mode
1271
        { 0, 0 },       // move_down_delta
1272
        { 0, 0 },       // move_down_min
1273
        { 0, 0 },       // move_down_max
1274
        { NULL, NULL }, // move_down_proc
1275
        { 1, 1 },       // go_ahead_allowed
1276
        { NULL, NULL }, // go_ahead_proc
1277
        { 1, 1 },       // escape_allowed
1278
        { NULL, NULL }, // escape_proc
1279
        NULL,           // exit_proc
1280
        &NetSumDraw,    // draw_proc
1281
        10000,          // time_out
1282
        NULL,           // start_proc1
1283
        NULL,           // start_proc2
1284
        NULL,           // done_proc
1285
        0,              // font_needed
1286
        { 0, 0 },       // typeable
1287
        NULL,           // get_original_string
1288
        0,              // escape_code
1289
        1,              // dont_save_or_load
1290
        1,              // number_of_button_flics
1291
        flicker_on,     // flicker_on_flics
1292
        flicker_off,    // flicker_off_flics
1293
        push,           // pushed_flics
1294
        1,              // number_of_mouse_areas
1295
        mouse_areas,    // mouse_areas
1296
        0,              // number_of_recopy_areas
1297
        NULL            // recopy_areas
1298
    };
1299
    int i;
1300
    int result;
1301
    tS32 start_time;
1 pmbaty 1302
    LOG_TRACE("()");
18 pmbaty 1303
 
1304
    NetPlayerStatusChanged(ePlayer_status_summary);
1305
    start_time = PDGetTotalTime();
1306
    while (!gReceived_game_scores && PDGetTotalTime() - start_time < 20000) {
1307
        NetService(0);
1308
    }
1309
    if (gReceived_game_scores) {
1310
        for (i = 0; i < gNumber_of_net_players; i++) {
1311
            gPlayer_lookup[i] = i;
1312
        }
1313
        SortGameScores();
1314
        TurnOnPaletteConversion();
1315
        DoInterfaceScreen(&interface_spec, 0, 0);
1316
        NetPlayerStatusChanged(ePlayer_status_loading);
1317
        TurnOffPaletteConversion();
1318
        FadePaletteDown();
1319
    }
1 pmbaty 1320
}
1321
 
1322
// IDA: tSO_result __usercall DoEndRaceSummary@<EAX>(int *pFirst_summary_done@<EAX>, tRace_result pRace_result@<EDX>)
1323
tSO_result DoEndRaceSummary(int* pFirst_summary_done, tRace_result pRace_result) {
1324
    tSO_result result;
1325
    LOG_TRACE("(%p, %d)", pFirst_summary_done, pRace_result);
1326
 
1327
    if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
1328
        gRank_etc_munged = 1;
1329
        DoEndRaceSummary2();
1330
        return eSO_continue;
1331
    }
1332
    gRank_etc_munged = 0;
1333
    if (!*pFirst_summary_done && pRace_result != eRace_timed_out) {
1334
        if (gNet_mode != eNet_mode_none) {
1335
            CalcRankIncrease();
1336
            MungeRankEtc(&gProgram_state);
1337
            DoNetRaceSummary();
1338
            return eSO_continue;
1339
        }
1340
        result = DoEndRaceSummary1();
1341
    } else {
1342
        result = eSO_continue;
1343
    }
1344
    *pFirst_summary_done = 1;
1345
    if (result == eSO_game_over) {
1346
        DoGameOverAnimation();
1347
        gProgram_state.prog_status = eProg_opening;
1348
        result = eSO_continue;
1349
    } else if (result == eSO_main_menu_invoked) {
1350
        *pFirst_summary_done = 0;
1351
        result = eSO_main_menu_invoked;
1352
    } else {
1353
        if (result == eSO_game_completed) {
1354
            DoGameCompletedAnimation();
1355
        }
1356
        result = DoEndRaceSummary2();
1357
        if (result != eSO_main_menu_invoked) {
1358
            TotallyRepairCar();
1359
            result = eSO_continue;
1360
        }
1361
    }
1362
    return result;
1363
}