Subversion Repositories Games.Carmageddon

Rev

Rev 20 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include "displays.h"
20 pmbaty 2
#include "brender/brender.h"
1 pmbaty 3
#include "constants.h"
4
#include "controls.h"
5
#include "depth.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/trace.h"
13
#include "netgame.h"
14
#include "pd/sys.h"
15
#include "utility.h"
16
#include <stdlib.h>
17
 
18
int gLast_fancy_index;
19
int gLast_credit_headup__displays; // suffix added to avoid duplicate symbol
20
int gLast_time_credit_headup;
21
tDR_font* gCached_font;
22
br_font* gBR_fonts[4];
23
tQueued_headup gQueued_headups[4];
24
int gOld_times[10];
25
int gLast_fancy_headup;
26
tU32 gLast_time_earn_time;
27
tU32 gLast_centre_headup;
28
tU32 gLast_fancy_time;
29
int gQueued_headup_count;
30
tU32 gLast_earn_time;
31
tU32 gLast_time_credit_amount;
32
int gLast_credit_amount;
33
tHeadup gHeadups[15];
34
int gLaps_headup;
35
int gCar_kill_count_headup;
36
int gTimer_headup;
37
int gTime_awarded_headup;
38
int gPed_kill_count_headup;
39
int gDim_amount;
40
br_pixelmap* gHeadup_images[32]; // Modified by DethRace for the demo
41
int gNet_cash_headup;
42
int gNet_ped_headup;
43
int gCredits_lost_headup;
44
int gCredits_won_headup;
45
 
46
// IDA: void __usercall GetTimerString(char *pStr@<EAX>, int pFudge_colon@<EDX>)
47
void GetTimerString(char* pStr, int pFudge_colon) {
48
    LOG_TRACE("(\"%s\", %d)", pStr, pFudge_colon);
49
 
50
    TimerString(gTimer, pStr, pFudge_colon, 0);
51
}
52
 
53
// IDA: void __cdecl InitHeadups()
54
void InitHeadups(void) {
55
    int i;
56
    LOG_TRACE("()");
57
 
58
    for (i = 0; i < 15; i++) {
59
        gHeadups[i].type = eHeadup_unused;
60
    }
61
    gBR_fonts[0] = BrFontProp7x9;
62
    gBR_fonts[1] = BrFontFixed3x5;
63
    gBR_fonts[2] = gFont_7;
64
    gBR_fonts[3] = gHeadup_font;
65
}
66
 
67
// IDA: void __usercall ClearHeadup(int pIndex@<EAX>)
68
void ClearHeadup(int pIndex) {
69
    LOG_TRACE("(%d)", pIndex);
70
 
71
    gHeadups[pIndex].type = eHeadup_unused;
72
}
73
 
74
// IDA: void __usercall ClearHeadupSlot(int pSlot_index@<EAX>)
75
void ClearHeadupSlot(int pSlot_index) {
76
    int i;
77
    tHeadup* the_headup;
78
    LOG_TRACE("(%d)", pSlot_index);
79
 
80
    the_headup = gHeadups;
81
    for (i = 0; i < COUNT_OF(gHeadups); i++) {
82
        if (the_headup->type != eHeadup_unused && the_headup->slot_index == pSlot_index) {
83
            ClearHeadup(i);
84
            return;
85
        }
86
        the_headup++;
87
    }
88
}
89
 
90
// IDA: void __cdecl ClearHeadups()
91
void ClearHeadups(void) {
92
    int i;
93
    LOG_TRACE("()");
94
 
95
    for (i = 0; i < COUNT_OF(gHeadups); i++) {
96
        if (gHeadups[i].type) {
97
            ClearHeadup(i);
98
        }
99
    }
100
    gLast_fancy_index = -1;
101
    gLast_credit_headup__displays = -1;
102
    gLast_time_credit_headup = -1;
103
    gLast_earn_time = 0;
104
    gLast_fancy_time = 0;
105
    gLast_time_earn_time = 0;
106
    for (i = 0; i < COUNT_OF(gOld_times); i++) {
107
        gOld_times[i] = 0;
108
    }
109
    gQueued_headup_count = 0;
110
    gLast_centre_headup = 0;
111
}
112
 
113
// IDA: int __usercall HeadupActive@<EAX>(int pIndex@<EAX>)
114
int HeadupActive(int pIndex) {
115
    LOG_TRACE("(%d)", pIndex);
116
 
117
    return gHeadups[pIndex].type != eHeadup_unused;
118
}
119
 
120
// IDA: void __usercall DRPixelmapText(br_pixelmap *pPixelmap@<EAX>, int pX@<EDX>, int pY@<EBX>, tDR_font *pFont@<ECX>, char *pText, int pRight_edge)
121
void DRPixelmapText(br_pixelmap* pPixelmap, int pX, int pY, tDR_font* pFont, char* pText, int pRight_edge) {
122
    int i;
123
    int x;
124
    int len;
125
    int chr;
126
    int ch_width;
127
    unsigned char* ch;
128
    LOG_TRACE9("(%p, %d, %d, %p, \"%s\", %d)", pPixelmap, pX, pY, pFont, pText, pRight_edge);
129
 
130
    len = strlen(pText);
131
    ch = (unsigned char*)pText;
132
    if (pX >= 0 && pPixelmap->width >= pRight_edge && pY >= 0 && (pY + pFont->height) <= pPixelmap->height) {
133
        x = pX;
134
        for (i = 0; i < len; i++) {
135
            chr = ch[i] - pFont->offset;
136
            ch_width = pFont->width_table[chr];
137
            DRPixelmapRectangleOnscreenCopy(
138
                gBack_screen,
139
                x,
140
                pY,
141
                pFont->images,
142
                0,
143
                pFont->height * chr,
144
                ch_width,
145
                pFont->height);
146
 
147
            x += ch_width + pFont->spacing;
148
        }
149
    } else {
150
        x = pX;
151
        for (i = 0; i < len; i++) {
152
            chr = ch[i] - pFont->offset;
153
            ch_width = pFont->width_table[chr];
154
            DRPixelmapRectangleMaskedCopy(
155
                gBack_screen,
156
                x,
157
                pY,
158
                pFont->images,
159
                0,
160
                pFont->height * chr,
161
                ch_width,
162
                pFont->height);
163
 
164
            x += ch_width + pFont->spacing;
165
        }
166
    }
167
}
168
 
169
// IDA: void __usercall DRPixelmapCleverText2(br_pixelmap *pPixelmap@<EAX>, int pX@<EDX>, int pY@<EBX>, tDR_font *pFont@<ECX>, signed char *pText, int pRight_edge)
170
void DRPixelmapCleverText2(br_pixelmap* pPixelmap, int pX, int pY, tDR_font* pFont, char* pText, int pRight_edge) {
171
    int i;
172
    int x;
173
    int len;
174
    int chr;
175
    int ch_width;
176
    unsigned char* ch;
177
    tDR_font* new_font;
178
    LOG_TRACE("(%p, %d, %d, %p, %p, %d)", pPixelmap, pX, pY, pFont, pText, pRight_edge);
179
 
180
    x = pX;
181
    len = strlen(pText);
182
    ch = (unsigned char*)pText;
183
    if (pX >= 0 && pPixelmap->width >= pRight_edge && pY >= 0 && pY + pFont->height <= pPixelmap->height) {
184
        for (i = 0; i < len; i++) {
185
            if (*ch < 224) {
186
                chr = *ch - pFont->offset;
187
                ch_width = pFont->width_table[chr];
188
                DRPixelmapRectangleOnscreenCopy(
189
                    gBack_screen,
190
                    x,
191
                    pY,
192
                    pFont->images,
193
                    0,
194
                    chr * pFont->height,
195
                    ch_width,
196
                    pFont->height);
197
                x += ch_width + pFont->spacing;
198
            } else {
199
                new_font = &gFonts[-*ch + 256];
200
                pY -= (new_font->height - pFont->height) / 2;
201
                pFont = new_font;
202
            }
203
            ch++;
204
        }
205
    } else {
206
        for (i = 0; i < len; i++) {
207
            if (*ch < 224) {
208
                chr = *ch - pFont->offset;
209
                ch_width = pFont->width_table[chr];
210
                DRPixelmapRectangleMaskedCopy(
211
                    gBack_screen,
212
                    x,
213
                    pY,
214
                    pFont->images,
215
                    0,
216
                    chr * pFont->height,
217
                    ch_width,
218
                    pFont->height);
219
                x += ch_width + pFont->spacing;
220
            } else {
221
                new_font = &gFonts[-*ch + 256];
222
                pY -= (new_font->height - pFont->height) / 2;
223
                pFont = new_font;
224
            }
225
            ch++;
226
        }
227
    }
228
}
229
 
230
// IDA: void __usercall DeviouslyDimRectangle(br_pixelmap *pPixelmap@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pRight@<ECX>, int pBottom, int pKnock_out_corners)
231
void DeviouslyDimRectangle(br_pixelmap* pPixelmap, int pLeft, int pTop, int pRight, int pBottom, int pKnock_out_corners) {
232
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pPixelmap, pLeft, pTop, pRight, pBottom, pKnock_out_corners);
233
    NOT_IMPLEMENTED();
234
}
235
 
236
// IDA: void __cdecl DimRectangle(br_pixelmap *pPixelmap, int pLeft, int pTop, int pRight, int pBottom, int pKnock_out_corners)
237
void DimRectangle(br_pixelmap* pPixelmap, int pLeft, int pTop, int pRight, int pBottom, int pKnock_out_corners) {
238
    tU8* ptr;
239
    tU8* depth_table_ptr;
240
    tU8* right_ptr;
241
    int x;
242
    int y;
243
    int line_skip;
244
    int width;
245
    LOG_TRACE9("(%p, %d, %d, %d, %d, %d)", pPixelmap, pLeft, pTop, pRight, pBottom, pKnock_out_corners);
246
 
247
    ptr = (tU8*)pPixelmap->pixels + pLeft + pPixelmap->row_bytes * pTop;
248
    line_skip = pPixelmap->row_bytes - pRight + pLeft;
249
    depth_table_ptr = gDepth_shade_table->pixels;
250
    x = gDepth_shade_table->row_bytes * gDim_amount;
251
    width = pRight - pLeft;
252
 
253
    if (pKnock_out_corners) {
254
        ptr++;
255
        for (right_ptr = ptr + width - 2; ptr < right_ptr; ptr++) {
256
            *ptr = depth_table_ptr[*ptr + x];
257
        }
258
        ptr += line_skip + 1;
259
        for (y = pTop + 1; y < (pBottom - 1); y++, ptr += line_skip) {
260
            for (right_ptr = ptr + width; ptr < right_ptr; ptr++) {
261
                *ptr = depth_table_ptr[*ptr + x];
262
            }
263
        }
264
        ptr++;
265
        for (right_ptr = ptr + width - 2; ptr < right_ptr; ptr++) {
266
            *ptr = depth_table_ptr[*ptr + x];
267
        }
268
    } else {
269
        for (y = pTop; y < pBottom; y++) {
270
            for (right_ptr = ptr + width; ptr < right_ptr; ptr++) {
271
                *ptr = depth_table_ptr[*ptr + x];
272
            }
273
            ptr += line_skip;
274
        }
275
    }
276
}
277
 
278
// IDA: void __cdecl DimAFewBits()
279
void DimAFewBits(void) {
280
    int i;
281
    LOG_TRACE("()");
282
 
283
    int dim_index; // Added
284
    dim_index = gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0;
285
    for (i = 0; i < gProgram_state.current_car.dim_count[dim_index]; i++) {
286
        DimRectangle(
287
            gBack_screen,
288
            gProgram_state.current_car.dim_left[dim_index][i],
289
            gProgram_state.current_car.dim_top[dim_index][i],
290
            gProgram_state.current_car.dim_right[dim_index][i],
291
            gProgram_state.current_car.dim_bottom[dim_index][i],
292
            1);
293
    }
294
}
295
 
296
// IDA: void __cdecl KillOldestQueuedHeadup()
297
void KillOldestQueuedHeadup(void) {
298
    LOG_TRACE("()");
299
 
300
    gQueued_headup_count--;
301
    memmove(&gQueued_headups[0], &gQueued_headups[1], gQueued_headup_count * sizeof(tQueued_headup));
302
}
303
 
304
// IDA: void __usercall DubreyBar(int pX_index@<EAX>, int pY@<EDX>, int pColour@<EBX>)
305
void DubreyBar(int pX_index, int pY, int pColour) {
306
    int x;
307
    LOG_TRACE("(%d, %d, %d)", pX_index, pY, pColour);
308
 
309
    x = gCurrent_graf_data->ps_bar_left - gCurrent_graf_data->ps_x_pitch * pX_index;
310
    BrPixelmapLine(gBack_screen, x, pY, x, gCurrent_graf_data->ps_bar_height + pY, pColour);
311
}
312
 
313
// IDA: void __usercall DoPSPowerHeadup(int pY@<EAX>, int pLevel@<EDX>, char *pName@<EBX>, int pBar_colour@<ECX>)
314
void DoPSPowerHeadup(int pY, int pLevel, char* pName, int pBar_colour) {
315
    //char s[16]; // Pierre-Marie Baty -- unused variable
316
    int i;
317
    LOG_TRACE("(%d, %d, \"%s\", %d)", pY, pLevel, pName, pBar_colour);
318
 
319
    DimRectangle(gBack_screen, gCurrent_graf_data->ps_dim_left, pY, gCurrent_graf_data->ps_dim_right, gCurrent_graf_data->ps_dim_height + pY, 1);
320
    TransDRPixelmapText(gBack_screen, gCurrent_graf_data->ps_name_left, gCurrent_graf_data->ps_name_top_border + pY, gFonts + 6, pName, gBack_screen->width);
321
 
322
    for (i = (6 - gCurrent_graf_data->ps_bars_per_level) * gCurrent_graf_data->ps_bars_per_level + 1; i > (gCurrent_graf_data->ps_bars_per_level * pLevel + 1); i--) {
323
        DubreyBar(i, pY + gCurrent_graf_data->ps_bar_top_border, 0);
324
    }
325
    for (i = gCurrent_graf_data->ps_bars_per_level * pLevel + 1; i >= 0; i--) {
326
        DubreyBar(i, pY + gCurrent_graf_data->ps_bar_top_border, pBar_colour);
327
    }
328
}
329
 
330
// IDA: void __cdecl DoPSPowerupHeadups()
331
void DoPSPowerupHeadups(void) {
332
    LOG_TRACE("()");
333
 
334
    DoPSPowerHeadup(gCurrent_graf_data->armour_headup_y[gProgram_state.cockpit_on], gProgram_state.current_car.power_up_levels[0], "A", 45);
335
    DoPSPowerHeadup(gCurrent_graf_data->power_headup_y[gProgram_state.cockpit_on], gProgram_state.current_car.power_up_levels[1], "P", 99);
336
    DoPSPowerHeadup(gCurrent_graf_data->offense_headup_y[gProgram_state.cockpit_on], gProgram_state.current_car.power_up_levels[2], "O", 4);
337
}
338
 
339
// IDA: void __usercall DoHeadups(tU32 pThe_time@<EAX>)
340
void DoHeadups(tU32 pThe_time) {
341
    int i;
342
    int x_offset;
343
    int y_offset;
344
    tHeadup* the_headup;
345
    int time_factor;
346
    LOG_TRACE("(%d)", pThe_time);
347
 
348
    if (gNet_mode) {
349
        DoNetScores();
350
    }
351
    if (gQueued_headup_count && PDGetTotalTime() - gLast_centre_headup >= 1000) {
21 pmbaty 352
        NewTextHeadupSlot(eHeadupSlot_misc, gQueued_headups[0].flash_rate,
1 pmbaty 353
            gQueued_headups[0].lifetime,
354
            gQueued_headups[0].font_index,
355
            gQueued_headups[0].text);
356
        KillOldestQueuedHeadup();
357
    }
358
 
359
    for (i = 0; i < COUNT_OF(gHeadups); i++) {
360
        the_headup = &gHeadups[i];
361
        if (the_headup->type != eHeadup_unused
362
            && (gProgram_state.which_view == eView_forward || !the_headup->cockpit_anchored)
363
            && (the_headup->type == eHeadup_image
364
                || the_headup->type == eHeadup_fancy
365
                || (the_headup->type == eHeadup_text && the_headup->data.text_info.text[0] != '\0')
366
                || ((the_headup->type == eHeadup_coloured_text || the_headup->type == eHeadup_box_text)
367
                    && the_headup->data.text_info.text[0] != '\0'))) {
368
            if (the_headup->type == eHeadup_fancy || the_headup->end_time == 0 || pThe_time < the_headup->end_time) {
369
                if (the_headup->dimmed_background) {
370
                    DimRectangle(
371
                        gBack_screen,
372
                        the_headup->dim_left,
373
                        the_headup->dim_top,
374
                        the_headup->dim_right,
375
                        the_headup->dim_bottom,
376
                        1);
377
                }
378
                if (the_headup->flash_period == 0
379
                    || Flash(the_headup->flash_period, &the_headup->last_flash, &the_headup->flash_state)) {
380
                    switch (the_headup->type) {
381
                    case eHeadup_text:
382
                        if (the_headup->cockpit_anchored) {
383
                            y_offset = gScreen_wobble_y;
384
                        } else {
385
                            y_offset = 0;
386
                        }
387
                        if (the_headup->cockpit_anchored) {
388
                            x_offset = gScreen_wobble_x;
389
                        } else {
390
                            x_offset = 0;
391
                        }
392
                        TransBrPixelmapText(
393
                            gBack_screen,
394
                            x_offset + the_headup->x,
395
                            y_offset + the_headup->y,
396
                            the_headup->data.text_info.colour,
397
                            the_headup->data.text_info.font,
398
                            the_headup->data.text_info.text);
399
                        break;
400
                    case eHeadup_coloured_text:
401
                        if (the_headup->clever) {
402
                            if (the_headup->cockpit_anchored) {
403
                                y_offset = gScreen_wobble_y;
404
                            } else {
405
                                y_offset = 0;
406
                            }
407
                            if (the_headup->cockpit_anchored) {
408
                                x_offset = gScreen_wobble_x;
409
                            } else {
410
                                x_offset = 0;
411
                            }
412
                            TransDRPixelmapCleverText(
413
                                gBack_screen,
414
                                x_offset + the_headup->x,
415
                                y_offset + the_headup->y,
416
                                the_headup->data.coloured_text_info.coloured_font,
417
                                the_headup->data.coloured_text_info.text,
418
                                the_headup->right_edge);
419
                        } else {
420
                            if (the_headup->cockpit_anchored) {
421
                                y_offset = gScreen_wobble_y;
422
                            } else {
423
                                y_offset = 0;
424
                            }
425
                            if (the_headup->cockpit_anchored) {
426
                                x_offset = gScreen_wobble_x;
427
                            } else {
428
                                x_offset = 0;
429
                            }
430
                            TransDRPixelmapText(
431
                                gBack_screen,
432
                                x_offset + the_headup->x,
433
                                y_offset + the_headup->y,
434
                                the_headup->data.coloured_text_info.coloured_font,
435
                                the_headup->data.coloured_text_info.text,
436
                                the_headup->right_edge);
437
                        }
438
                        break;
439
                    case eHeadup_image:
440
                        if (the_headup->cockpit_anchored) {
441
                            y_offset = gScreen_wobble_y;
442
                        } else {
443
                            y_offset = 0;
444
                        }
445
                        if (the_headup->cockpit_anchored) {
446
                            x_offset = gScreen_wobble_x;
447
                        } else {
448
                            x_offset = 0;
449
                        }
450
                        DRPixelmapRectangleMaskedCopy(
451
                            gBack_screen,
452
                            x_offset + the_headup->x,
453
                            y_offset + the_headup->y,
454
                            the_headup->data.image_info.image,
455
                            0,
456
                            0,
457
                            the_headup->data.image_info.image->width,
458
                            the_headup->data.image_info.image->height);
459
                        break;
460
 
461
                    case eHeadup_fancy:
462
                        switch (the_headup->data.fancy_info.fancy_stage) {
463
                        case eFancy_stage_incoming:
464
                            the_headup->data.fancy_info.offset -= 500 * gFrame_period / 1000;
465
                            if (the_headup->data.fancy_info.offset <= the_headup->data.fancy_info.shear_amount) {
466
                                the_headup->data.fancy_info.offset = the_headup->data.fancy_info.shear_amount;
467
                                the_headup->data.fancy_info.fancy_stage = eFancy_stage_halting;
468
                                the_headup->data.fancy_info.start_time = GetTotalTime();
469
                            }
470
                            DRPixelmapRectangleShearedCopy(
471
                                gBack_screen,
472
                                the_headup->x + the_headup->data.fancy_info.offset,
473
                                the_headup->y,
474
                                the_headup->data.fancy_info.image,
475
                                0,
476
                                0,
477
                                the_headup->data.fancy_info.image->width,
478
                                the_headup->data.fancy_info.image->height,
479
                                -65536);
480
                            break;
481
                        case eFancy_stage_halting:
482
                            time_factor = 1000 * (pThe_time - the_headup->data.fancy_info.start_time) / 100;
483
                            if (time_factor > 1000) {
484
                                if (time_factor > 1500) {
485
                                    time_factor = 1500;
486
                                    the_headup->data.fancy_info.fancy_stage = eFancy_stage_waiting;
487
                                    the_headup->data.fancy_info.start_time = GetTotalTime();
488
                                }
489
                                DRPixelmapRectangleShearedCopy(
490
                                    gBack_screen,
491
                                    the_headup->x - (1500 - time_factor) * the_headup->data.fancy_info.shear_amount / 500,
492
                                    the_headup->y,
493
                                    the_headup->data.image_info.image,
494
                                    0,
495
                                    0,
496
                                    the_headup->data.image_info.image->width,
497
                                    the_headup->data.image_info.image->height,
498
                                    (((1500 - time_factor) * the_headup->data.fancy_info.shear_amount / 500) << 16)
499
                                        / the_headup->data.image_info.image->height);
500
                            } else {
501
#if DETHRACE_FIX_BUGS
502
                                time_factor = MAX(time_factor, 0);
503
#endif
504
                                DRPixelmapRectangleShearedCopy(
505
                                    gBack_screen,
506
                                    the_headup->x - the_headup->data.fancy_info.shear_amount * (time_factor - 500) / 500,
507
                                    the_headup->y,
508
                                    the_headup->data.image_info.image,
509
                                    0,
510
                                    0,
511
                                    the_headup->data.image_info.image->width,
512
                                    the_headup->data.image_info.image->height,
513
                                    ((the_headup->data.fancy_info.shear_amount * (time_factor - 500) / 500) << 16)
514
                                        / the_headup->data.image_info.image->height);
515
                            }
516
                            break;
517
                        case eFancy_stage_waiting:
518
                            if (pThe_time - the_headup->data.fancy_info.start_time > 1000) {
519
                                the_headup->data.fancy_info.fancy_stage = eFancy_stage_readying;
520
                                the_headup->data.fancy_info.start_time = GetTotalTime();
521
                            }
522
                            DRPixelmapRectangleMaskedCopy(
523
                                gBack_screen,
524
                                the_headup->x,
525
                                the_headup->y,
526
                                the_headup->data.image_info.image,
527
                                0,
528
                                0,
529
                                the_headup->data.image_info.image->width,
530
                                the_headup->data.image_info.image->height);
531
                            break;
532
                        case eFancy_stage_readying:
533
                            time_factor = 1000 * (pThe_time - the_headup->data.fancy_info.start_time) / 100;
534
                            if (time_factor > 1000) {
535
                                time_factor = 1000;
536
                                the_headup->data.fancy_info.fancy_stage = eFancy_stage_leaving;
537
                                the_headup->data.fancy_info.start_time = GetTotalTime();
538
                                the_headup->data.fancy_info.offset = 0;
539
                            }
540
                            DRPixelmapRectangleShearedCopy(
541
                                gBack_screen,
542
                                the_headup->x,
543
                                the_headup->y,
544
                                the_headup->data.image_info.image,
545
                                0,
546
                                0,
547
                                the_headup->data.image_info.image->width,
548
                                the_headup->data.image_info.image->height,
549
                                -(((time_factor * the_headup->data.fancy_info.shear_amount / 1000) << 16)
550
                                    / the_headup->data.image_info.image->height));
551
                            break;
552
                        case eFancy_stage_leaving:
553
                            the_headup->data.fancy_info.offset -= 500 * gFrame_period / 1000;
554
                            if (the_headup->data.fancy_info.offset <= the_headup->data.fancy_info.end_offset) {
555
                                ClearHeadup(i);
556
                            } else {
557
                                DRPixelmapRectangleShearedCopy(
558
                                    gBack_screen,
559
                                    the_headup->data.fancy_info.offset + the_headup->x,
560
                                    the_headup->y,
561
                                    the_headup->data.image_info.image,
562
                                    0,
563
                                    0,
564
                                    the_headup->data.image_info.image->width,
565
                                    the_headup->data.image_info.image->height,
566
                                    -65536);
567
                            }
568
                            break;
569
                        default:
570
                            break;
571
                        }
572
                        break;
573
 
574
                    case eHeadup_box_text:
575
                        if (the_headup->cockpit_anchored) {
576
                            y_offset = gScreen_wobble_y;
577
                        } else {
578
                            y_offset = 0;
579
                        }
580
                        if (the_headup->cockpit_anchored) {
581
                            x_offset = gScreen_wobble_x;
582
                        } else {
583
                            x_offset = 0;
584
                        }
585
                        OoerrIveGotTextInMeBoxMissus(
586
                            the_headup->data.coloured_text_info.coloured_font - gFonts,
587
                            the_headup->data.coloured_text_info.text,
588
                            gBack_screen,
589
                            gBack_screen->width / 10,
590
                            x_offset + the_headup->y,
591
                            9 * gBack_screen->width / 10,
592
                            y_offset + the_headup->y + 60,
593
                            1);
594
                        break;
595
                    default:
596
                        break;
597
                    }
598
                }
599
            } else {
600
                ClearHeadup(i);
601
            }
602
        }
603
    }
604
    DoPSPowerupHeadups();
605
}
606
 
607
// IDA: int __usercall FindAHeadupHoleWoofBarkSoundsABitRude@<EAX>(int pSlot_index@<EAX>)
608
int FindAHeadupHoleWoofBarkSoundsABitRude(int pSlot_index) {
609
    int i;
610
    int empty_one;
611
    tHeadup* the_headup;
612
    LOG_TRACE("(%d)", pSlot_index);
613
 
614
    empty_one = -1;
615
    for (i = 0, the_headup = gHeadups; i < COUNT_OF(gHeadups); i++, the_headup++) {
616
        if (pSlot_index >= 0 && the_headup->slot_index == pSlot_index) {
617
            return i;
618
        }
619
        if (the_headup->type == eHeadup_unused) {
620
            empty_one = i;
621
        }
622
    }
623
    return empty_one;
624
}
625
 
626
// IDA: int __usercall DRTextWidth@<EAX>(tDR_font *pFont@<EAX>, char *pText@<EDX>)
627
int DRTextWidth(tDR_font* pFont, char* pText) {
628
    int i;
629
    int len;
630
    int result;
631
    char* c;
632
    LOG_TRACE("(%p, \"%s\")", pFont, pText);
633
 
634
    c = pText;
635
    result = 0;
636
    len = strlen(pText);
637
 
638
    for (i = 0; i < len; i++) {
639
        result += pFont->width_table[*c - pFont->offset];
640
        c++;
641
    }
642
    return result + pFont->spacing * (len - 1);
643
}
644
 
645
// IDA: int __usercall DRTextCleverWidth@<EAX>(tDR_font *pFont@<EAX>, signed char *pText@<EDX>)
646
int DRTextCleverWidth(tDR_font* pFont, signed char* pText) {
647
    int i;
648
    int len;
649
    int result;
650
    unsigned char* c;
651
    LOG_TRACE("(%p, %p)", pFont, pText);
652
 
653
    result = 0;
654
    len = strlen((char*)pText) + 1;
655
 
656
    for (i = 0, c = (unsigned char*)pText; i < len; i++, c++) {
657
        if (*c < 224) {
658
            if (i < (len - 1)) {
659
                result += pFont->spacing;
660
            }
661
            result += pFont->width_table[*c - pFont->offset];
662
        } else {
663
            pFont = &gFonts[256 - *c];
664
        }
665
    }
666
    return result;
667
}
668
 
669
// IDA: void __usercall DRPixelmapCentredText(br_pixelmap *pPixelmap@<EAX>, int pX@<EDX>, int pY@<EBX>, tDR_font *pFont@<ECX>, char *pText)
670
void DRPixelmapCentredText(br_pixelmap* pPixelmap, int pX, int pY, tDR_font* pFont, char* pText) {
671
    int width_over_2;
672
    LOG_TRACE("(%p, %d, %d, %p, \"%s\")", pPixelmap, pX, pY, pFont, pText);
673
 
674
    width_over_2 = DRTextWidth(pFont, pText) / 2;
675
    TransDRPixelmapText(pPixelmap, pX - width_over_2, pY, pFont, pText, width_over_2 + pX);
676
}
677
 
678
// IDA: int __usercall IsHeadupTextClever@<EAX>(signed char *pText@<EAX>)
679
int IsHeadupTextClever(signed char* pText) {
680
    LOG_TRACE("(%p)", pText);
681
 
682
    while (*pText) {
683
        if (*pText < 0) {
684
            return 1;
685
        }
686
        pText++;
687
    }
688
    return 0;
689
}
690
 
691
// IDA: int __usercall MungeHeadupWidth@<EAX>(tHeadup *pHeadup@<EAX>)
692
int MungeHeadupWidth(tHeadup* pHeadup) {
693
    int width;
694
    LOG_TRACE("(%p)", pHeadup);
695
 
696
    width = 0;
697
    if (pHeadup->type == eHeadup_box_text) {
698
        return 0;
699
    }
700
    if (pHeadup->type == eHeadup_coloured_text) {
701
        pHeadup->clever = IsHeadupTextClever((signed char*)(&pHeadup->data.text_info.text));
702
        if (pHeadup->justification) {
703
            if (pHeadup->justification == eJust_right) {
704
                if (pHeadup->clever) {
705
                    width = DRTextCleverWidth(
706
                        pHeadup->data.coloured_text_info.coloured_font,
707
                        (signed char*)(&pHeadup->data.text_info.text));
708
                } else {
709
                    width = DRTextWidth(pHeadup->data.coloured_text_info.coloured_font, pHeadup->data.text_info.text);
710
                }
711
                pHeadup->x = pHeadup->original_x - width;
712
            } else if (pHeadup->justification == eJust_centre) {
713
                if (pHeadup->clever) {
714
                    width = DRTextCleverWidth(
715
                        pHeadup->data.coloured_text_info.coloured_font,
716
                        (signed char*)(&pHeadup->data.text_info.text));
717
                } else {
718
                    width = DRTextWidth(pHeadup->data.coloured_text_info.coloured_font, pHeadup->data.text_info.text);
719
                }
720
                pHeadup->x = pHeadup->original_x - width / 2;
721
            }
722
        } else {
723
            pHeadup->x = pHeadup->original_x;
724
        }
725
    } else {
726
        pHeadup->clever = 0;
727
        if (pHeadup->justification) {
728
            if (pHeadup->justification == eJust_right) {
729
                width = BrPixelmapTextWidth(gBack_screen, pHeadup->data.text_info.font, pHeadup->data.text_info.text);
730
                pHeadup->x = pHeadup->original_x - width;
731
            } else if (pHeadup->justification == eJust_centre) {
732
                width = BrPixelmapTextWidth(gBack_screen, pHeadup->data.text_info.font, pHeadup->data.text_info.text);
733
                pHeadup->x = pHeadup->original_x - width / 2;
734
            }
735
        } else {
736
            pHeadup->x = pHeadup->original_x;
737
        }
738
    }
739
    return width;
740
}
741
 
742
// IDA: int __usercall NewTextHeadupSlot2@<EAX>(int pSlot_index@<EAX>, int pFlash_rate@<EDX>, int pLifetime@<EBX>, int pFont_index@<ECX>, char *pText, int pQueue_it)
743
int NewTextHeadupSlot2(int pSlot_index, int pFlash_rate, int pLifetime, int pFont_index, char* pText, int pQueue_it) {
744
    int index;
745
    tHeadup* the_headup;
746
    tHeadup_slot* headup_slot;
747
    tU32 time;
748
    LOG_TRACE("(%d, %d, %d, %d, \"%s\", %d)", pSlot_index, pFlash_rate, pLifetime, pFont_index, pText, pQueue_it);
749
 
750
    time = PDGetTotalTime();
751
    if (pQueue_it && pSlot_index == 4 && time - gLast_centre_headup < 1000) {
752
        if (gQueued_headup_count == 4) {
753
            KillOldestQueuedHeadup();
754
        }
755
        gQueued_headups[gQueued_headup_count].flash_rate = pFlash_rate;
756
        gQueued_headups[gQueued_headup_count].lifetime = pLifetime;
757
        gQueued_headups[gQueued_headup_count].font_index = pFont_index;
758
        strcpy(gQueued_headups[gQueued_headup_count].text, pText);
759
        gQueued_headup_count++;
760
        index = -1;
761
    } else {
762
        index = FindAHeadupHoleWoofBarkSoundsABitRude(pSlot_index);
763
        if (index >= 0) {
764
            if (pSlot_index == 4) {
765
                gLast_centre_headup = time;
766
            }
767
            headup_slot = &gProgram_state.current_car.headup_slots[gProgram_state.cockpit_on][pSlot_index];
768
            the_headup = &gHeadups[index];
769
            the_headup->data.coloured_text_info.coloured_font = &gFonts[-pFont_index];
770
            if (pSlot_index == 4) {
771
                the_headup->type = eHeadup_box_text;
772
            } else {
773
                the_headup->type = eHeadup_coloured_text;
774
            }
775
            if (!pText) {
776
                LOG_PANIC("panic");
777
            }
778
            strcpy(the_headup->data.text_info.text, pText);
779
 
780
            the_headup->slot_index = pSlot_index;
781
            the_headup->justification = headup_slot->justification;
782
            if (pSlot_index < 0) {
783
                the_headup->cockpit_anchored = 0;
784
            } else {
785
                the_headup->cockpit_anchored = headup_slot->cockpit_anchored;
786
            }
787
            the_headup->dimmed_background = headup_slot->dimmed_background;
788
            the_headup->dim_left = headup_slot->dim_left;
789
            the_headup->dim_top = headup_slot->dim_top;
790
            the_headup->dim_right = headup_slot->dim_right;
791
            the_headup->dim_bottom = headup_slot->dim_bottom;
792
            the_headup->original_x = headup_slot->x;
793
            the_headup->right_edge = MungeHeadupWidth(the_headup) + the_headup->x;
794
            the_headup->y = headup_slot->y;
795
            if (pFlash_rate) {
796
                the_headup->flash_period = 1000 / pFlash_rate;
797
            } else {
798
                the_headup->flash_period = 0;
799
            }
800
            the_headup->last_flash = 0;
801
            the_headup->flash_state = 0;
802
            if (pLifetime) {
803
                the_headup->end_time = GetTotalTime() + pLifetime;
804
            } else {
805
                the_headup->end_time = 0;
806
            }
807
        }
808
    }
809
    return index;
810
}
811
 
812
// IDA: int __usercall NewTextHeadupSlot@<EAX>(int pSlot_index@<EAX>, int pFlash_rate@<EDX>, int pLifetime@<EBX>, int pFont_index@<ECX>, char *pText)
813
int NewTextHeadupSlot(int pSlot_index, int pFlash_rate, int pLifetime, int pFont_index, char* pText) {
814
    LOG_TRACE("(%d, %d, %d, %d, \"%s\")", pSlot_index, pFlash_rate, pLifetime, pFont_index, pText);
815
 
816
    return NewTextHeadupSlot2(pSlot_index, pFlash_rate, pLifetime, pFont_index, pText, 1);
817
}
818
 
819
// IDA: int __usercall NewImageHeadupSlot@<EAX>(int pSlot_index@<EAX>, int pFlash_rate@<EDX>, int pLifetime@<EBX>, int pImage_index@<ECX>)
820
int NewImageHeadupSlot(int pSlot_index, int pFlash_rate, int pLifetime, int pImage_index) {
821
    int index;
822
    tHeadup* the_headup;
823
    tHeadup_slot* headup_slot;
824
    LOG_TRACE("(%d, %d, %d, %d)", pSlot_index, pFlash_rate, pLifetime, pImage_index);
825
 
826
    index = FindAHeadupHoleWoofBarkSoundsABitRude(pSlot_index);
827
    if (index >= 0) {
828
        headup_slot = &gProgram_state.current_car.headup_slots[gProgram_state.cockpit_on][pSlot_index];
829
        the_headup = &gHeadups[index];
830
        the_headup->type = eHeadup_image;
831
        the_headup->slot_index = pSlot_index;
832
        the_headup->justification = headup_slot->justification;
833
        if (pSlot_index < 0) {
834
            the_headup->cockpit_anchored = 0;
835
        } else {
836
            the_headup->cockpit_anchored = headup_slot->cockpit_anchored;
837
        }
838
        the_headup->dimmed_background = headup_slot->dimmed_background;
839
        the_headup->dim_left = headup_slot->dim_left;
840
        the_headup->dim_top = headup_slot->dim_top;
841
        the_headup->dim_right = headup_slot->dim_right;
842
        the_headup->dim_bottom = headup_slot->dim_bottom;
843
        the_headup->original_x = headup_slot->x;
844
 
845
        if (headup_slot->justification) {
846
            if (headup_slot->justification == eJust_right) {
847
                the_headup->x = the_headup->original_x - gHeadup_images[pImage_index]->width;
848
            } else if (headup_slot->justification == eJust_centre) {
849
                the_headup->x = the_headup->original_x - gHeadup_images[pImage_index]->width / 2;
850
            }
851
        } else {
852
            the_headup->x = the_headup->original_x;
853
        }
854
        the_headup->y = headup_slot->y;
855
        if (pFlash_rate) {
856
            the_headup->flash_period = 1000 / pFlash_rate;
857
        } else {
858
            the_headup->flash_period = 0;
859
        }
860
        the_headup->last_flash = 0;
861
        the_headup->flash_state = 0;
862
        if (pLifetime) {
863
            the_headup->end_time = GetTotalTime() + pLifetime;
864
        } else {
865
            the_headup->end_time = 0;
866
        }
867
        the_headup->data.image_info.image = gHeadup_images[pImage_index];
868
    }
869
    return index;
870
}
871
 
872
// IDA: void __usercall DoFancyHeadup(int pIndex@<EAX>)
873
void DoFancyHeadup(int pIndex) {
874
    tU32 the_time;
875
    tHeadup* the_headup;
876
    int temp_ref;
877
    LOG_TRACE("(%d)", pIndex);
878
 
879
    the_time = GetTotalTime();
880
    if (!gMap_mode && (gLast_fancy_index < 0 || the_time - gLast_fancy_time > 2000 || gLast_fancy_index <= pIndex)) {
881
        temp_ref = NewImageHeadupSlot(6, 0, 2000, pIndex + 10);
882
        if (temp_ref >= 0) {
883
            gLast_fancy_headup = temp_ref;
884
            gLast_fancy_index = pIndex;
885
            gLast_fancy_time = the_time;
886
            the_headup = &gHeadups[temp_ref];
887
            the_headup->type = eHeadup_fancy;
888
            the_headup->data.fancy_info.offset = (the_headup->data.image_info.image->width + gBack_screen->width) / 2;
889
            the_headup->data.fancy_info.end_offset = -the_headup->data.fancy_info.offset;
890
            the_headup->data.fancy_info.fancy_stage = eFancy_stage_incoming;
891
            the_headup->data.fancy_info.shear_amount = the_headup->data.image_info.image->height;
892
        }
893
    }
894
}
895
 
896
// IDA: void __cdecl AdjustHeadups()
897
void AdjustHeadups(void) {
898
    int i;
899
    int delta_x;
900
    int delta_y;
901
    tHeadup* the_headup;
902
    LOG_TRACE("()");
903
 
904
    the_headup = gHeadups;
905
    for (i = 0; i < COUNT_OF(gHeadups); i++) {
906
        the_headup = &gHeadups[i];
907
        if (the_headup->type == eHeadup_unused) {
908
            continue;
909
        }
910
        delta_x = gProgram_state.current_car.headup_slots[gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0][the_headup->slot_index].x
911
            - gProgram_state.current_car.headup_slots[!gProgram_state.cockpit_on || gProgram_state.cockpit_image_index < 0][the_headup->slot_index].x;
912
        delta_y = gProgram_state.current_car.headup_slots[gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0][the_headup->slot_index].y
913
            - gProgram_state.current_car.headup_slots[!gProgram_state.cockpit_on || gProgram_state.cockpit_image_index < 0][the_headup->slot_index].y;
914
        the_headup->x += delta_x;
915
        the_headup->original_x += delta_x;
916
        the_headup->y += delta_y;
917
        the_headup->dim_left += delta_x;
918
        the_headup->dim_top += delta_y;
919
        the_headup->dim_right += delta_x;
920
        the_headup->dim_bottom += delta_y;
921
    }
922
}
923
 
924
// IDA: void __usercall MoveHeadupTo(int pHeadup_index@<EAX>, int pNew_x@<EDX>, int pNew_y@<EBX>)
925
void MoveHeadupTo(int pHeadup_index, int pNew_x, int pNew_y) {
20 pmbaty 926
    //int delta_x; // Pierre-Marie Baty -- unused variable
1 pmbaty 927
    //tHeadup* the_headup; // Pierre-Marie Baty -- unused variable
928
    LOG_TRACE("(%d, %d, %d)", pHeadup_index, pNew_x, pNew_y);
20 pmbaty 929
    NOT_IMPLEMENTED();
1 pmbaty 930
}
931
 
932
// IDA: void __usercall ChangeHeadupText(int pHeadup_index@<EAX>, char *pNew_text@<EDX>)
933
void ChangeHeadupText(int pHeadup_index, char* pNew_text) {
934
    tHeadup* the_headup;
935
    LOG_TRACE("(%d, \"%s\")", pHeadup_index, pNew_text);
936
 
937
    if (pHeadup_index >= 0) {
938
        the_headup = &gHeadups[pHeadup_index];
939
        strcpy(the_headup->data.text_info.text, pNew_text);
940
        MungeHeadupWidth(the_headup);
941
    }
942
}
943
 
944
// IDA: void __usercall ChangeHeadupImage(int pHeadup_index@<EAX>, int pNew_image@<EDX>)
945
void ChangeHeadupImage(int pHeadup_index, int pNew_image) {
946
    tHeadup* the_headup;
947
    LOG_TRACE("(%d, %d)", pHeadup_index, pNew_image);
948
 
949
    if (pHeadup_index >= 0) {
950
        the_headup = &gHeadups[pHeadup_index];
951
        the_headup->data.image_info.image = gHeadup_images[pNew_image];
952
        switch (the_headup->justification) {
953
        case eJust_left:
954
            the_headup->x = the_headup->original_x;
955
            break;
956
        case eJust_right:
957
            the_headup->x = the_headup->original_x - the_headup->data.image_info.image->width;
958
            break;
959
        case eJust_centre:
960
            the_headup->x = the_headup->original_x - the_headup->data.image_info.image->width / 2;
961
            break;
962
        }
963
    }
964
}
965
 
966
// IDA: void __usercall ChangeHeadupColour(int pHeadup_index@<EAX>, int pNew_colour@<EDX>)
967
void ChangeHeadupColour(int pHeadup_index, int pNew_colour) {
968
    LOG_TRACE("(%d, %d)", pHeadup_index, pNew_colour);
969
 
970
    if (pHeadup_index >= 0) {
971
        gHeadups[pHeadup_index].data.text_info.colour = gColours[pNew_colour];
972
    }
973
}
974
 
975
// IDA: void __usercall DoDamageScreen(tU32 pThe_time@<EAX>)
976
void DoDamageScreen(tU32 pThe_time) {
977
    int i;
978
    int y_pitch;
979
    int the_step;
980
    int the_wobble_x;
981
    int the_wobble_y;
982
    br_pixelmap* the_image;
983
    tDamage_unit* the_damage;
984
    LOG_TRACE("(%d)", pThe_time);
985
 
986
    if (&gProgram_state.current_car != gCar_to_view || gProgram_state.current_car_index != gProgram_state.current_car.index) {
987
        return;
988
    }
989
    if (gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0) {
990
        if (gProgram_state.which_view != eView_forward) {
991
            return;
992
        }
993
        the_wobble_x = gScreen_wobble_x;
994
        the_wobble_y = gScreen_wobble_y;
995
    } else {
996
        the_wobble_x = gProgram_state.current_car.damage_x_offset;
997
        the_wobble_y = gProgram_state.current_car.damage_y_offset;
998
        if (gProgram_state.current_car.damage_background != NULL) {
999
            DRPixelmapRectangleMaskedCopy(
1000
                gBack_screen,
1001
                gProgram_state.current_car.damage_background_x,
1002
                gProgram_state.current_car.damage_background_y,
1003
                gProgram_state.current_car.damage_background,
1004
                0,
1005
                0,
1006
                gProgram_state.current_car.damage_background->width,
1007
                gProgram_state.current_car.damage_background->height);
1008
        }
1009
    }
1010
    for (i = 0; i < COUNT_OF(gProgram_state.current_car.damage_units); i++) {
1011
        the_damage = &gProgram_state.current_car.damage_units[i];
1012
        if (i != eDamage_driver) {
1013
            the_image = the_damage->images;
1014
            the_step = 5 * the_damage->damage_level / 100;
1015
            y_pitch = (the_image->height / 2) / 5;
1016
            DRPixelmapRectangleMaskedCopy(
1017
                gBack_screen,
1018
                the_wobble_x + gProgram_state.current_car.damage_units[i].x_coord,
1019
                the_wobble_y + gProgram_state.current_car.damage_units[i].y_coord,
1020
                the_image,
1021
                0,
1022
                y_pitch * (2 * the_step + ((pThe_time / the_damage->periods[the_step]) & 1)),
1023
                the_image->width,
1024
                y_pitch);
1025
        }
1026
    }
1027
}
1028
 
1029
// IDA: void __cdecl PoshDrawLine(float pAngle, br_pixelmap *pDestn, int pX1, int pY1, int pX2, int pY2, int pColour)
1030
void PoshDrawLine(float pAngle, br_pixelmap* pDestn, int pX1, int pY1, int pX2, int pY2, int pColour) {
1031
    LOG_TRACE("(%f, %p, %d, %d, %d, %d, %d)", pAngle, pDestn, pX1, pY1, pX2, pY2, pColour);
1032
 
1033
    if (pColour < 0) {
1034
        if (pAngle >= 0.785 && pAngle <= 5.498 && (pAngle <= 2.356 || pAngle >= 3.926)) {
1035
            if ((pAngle <= 0.785 || pAngle >= 1.57) && (pAngle <= 3.926 || pAngle >= 4.712)) {
1036
                DRDrawLine(pDestn, pX1 - 1, pY1, pX2 - 1, pY2, -pColour - 1);
1037
                DRDrawLine(pDestn, pX1 + 1, pY1, pX2 + 1, pY2, 1 - pColour);
1038
            } else {
1039
                DRDrawLine(pDestn, pX1 - 1, pY1, pX2 - 1, pY2, 1 - pColour);
1040
                DRDrawLine(pDestn, pX1 + 1, pY1, pX2 + 1, pY2, -pColour - 1);
1041
            }
1042
        } else {
1043
            DRDrawLine(pDestn, pX1, pY1 + 1, pX2, pY2 + 1, -pColour - 1);
1044
            DRDrawLine(pDestn, pX1, pY1 - 1, pX2, pY2 - 1, 1 - pColour);
1045
        }
1046
        DRDrawLine(pDestn, pX1, pY1, pX2, pY2, -pColour);
1047
    } else {
1048
        DRDrawLine(pDestn, pX1, pY1, pX2, pY2, pColour);
1049
    }
1050
}
1051
 
1052
// IDA: void __usercall DoInstruments(tU32 pThe_time@<EAX>)
1053
void DoInstruments(tU32 pThe_time) {
1054
    br_pixelmap* speedo_image;
1055
    br_pixelmap* tacho_image;
1056
    int the_wobble_x;
1057
    int the_wobble_y;
1058
    int gear;
1059
    int gear_height; /* Added by dethrace. */
1060
    double the_angle;
1061
    double the_angle2;
1062
    double sin_angle;
1063
    double cos_angle;
1064
    double speed_mph;
1065
    LOG_TRACE("(%d)", pThe_time);
1066
 
1067
    if (gProgram_state.current_car_index == gProgram_state.current_car.index) {
1068
        speed_mph = gCar_to_view->speedo_speed * WORLD_SCALE / 1600.0f * 3600000.0f;
1069
        if (speed_mph < 0.0f) {
1070
            speed_mph = 0.0f;
1071
        }
1072
        if (gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0) {
1073
            if (gProgram_state.which_view != eView_forward) {
1074
                return;
1075
            }
1076
            the_wobble_x = gScreen_wobble_x;
1077
            the_wobble_y = gScreen_wobble_y;
1078
        } else {
1079
            the_wobble_x = 0;
1080
            the_wobble_y = 0;
1081
        }
1082
        tacho_image = gProgram_state.current_car.tacho_image[gProgram_state.cockpit_on];
1083
        if (gProgram_state.current_car.tacho_radius_2[gProgram_state.cockpit_on] >= 0) {
1084
            if (gCar_to_view->red_line >= gCar_to_view->revs) {
1085
                the_angle = DEG_TO_RAD((double)(gProgram_state.current_car.tacho_end_angle[gProgram_state.cockpit_on] - gProgram_state.current_car.tacho_start_angle[gProgram_state.cockpit_on]) * gCar_to_view->revs / (double)gCar_to_view->red_line + (double)gProgram_state.current_car.tacho_start_angle[gProgram_state.cockpit_on]);
1086
            } else {
1087
                the_angle = DEG_TO_RAD((double)gProgram_state.current_car.tacho_end_angle[gProgram_state.cockpit_on]);
1088
            }
1089
            if (the_angle >= 0.0) {
1090
                if (the_angle >= TAU) {
1091
                    the_angle -= TAU;
1092
                }
1093
            } else {
1094
                the_angle += TAU;
1095
            }
1096
            the_angle2 = DR_PI_OVER_2 - the_angle;
1097
            if (the_angle2 < 0) {
1098
                the_angle2 += TAU;
1099
            }
1100
            if (the_angle2 > DR_3PI_OVER_2) {
1101
                cos_angle = gCosine_array[(unsigned int)((TAU - the_angle2) / DR_PI * 128.0)];
1102
            } else if (the_angle2 > DR_PI) {
1103
                cos_angle = -gCosine_array[(unsigned int)((the_angle2 - DR_PI) / DR_PI * 128.0)];
1104
#if defined(DETHRACE_FIX_BUGS)
1105
            } else if (the_angle2 >= DR_PI_OVER_2) {
1106
#else
1107
            } else if (the_angle2 > DR_PI_OVER_2) {
1108
#endif
1109
                cos_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle2) / DR_PI * 128.0)];
1110
            } else {
1111
                cos_angle = gCosine_array[(unsigned int)(the_angle2 / DR_PI * 128.0)];
1112
            }
1113
            if (the_angle > DR_3PI_OVER_2) {
1114
                sin_angle = gCosine_array[(unsigned int)((TAU - the_angle) / DR_PI * 128.0)];
1115
            } else if (the_angle > DR_PI) {
1116
                sin_angle = -gCosine_array[(unsigned int)((the_angle - DR_PI) / DR_PI * 128.0)];
1117
#if defined(DETHRACE_FIX_BUGS)
1118
            } else if (the_angle >= DR_PI_OVER_2) {
1119
#else
1120
            } else if (the_angle > DR_PI_OVER_2) {
1121
#endif
1122
                sin_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle) / DR_PI * 128.0)];
1123
            } else {
1124
                sin_angle = gCosine_array[(unsigned int)(the_angle / DR_PI * 128.0)];
1125
            }
1126
            if (tacho_image != NULL) {
1127
                DRPixelmapRectangleMaskedCopy(
1128
                    gBack_screen,
1129
                    the_wobble_x + gProgram_state.current_car.tacho_x[gProgram_state.cockpit_on],
1130
                    the_wobble_y + gProgram_state.current_car.tacho_y[gProgram_state.cockpit_on],
1131
                    tacho_image,
1132
                    0,
1133
                    0,
1134
                    tacho_image->width,
1135
                    tacho_image->height);
1136
            }
1137
 
1138
            PoshDrawLine(
1139
                the_angle,
1140
                gBack_screen,
1141
                ((double)gProgram_state.current_car.tacho_radius_1[gProgram_state.cockpit_on] * sin_angle
1142
                    + (double)gProgram_state.current_car.tacho_centre_x[gProgram_state.cockpit_on]
1143
                    + (double)the_wobble_x),
1144
                ((double)gProgram_state.current_car.tacho_centre_y[gProgram_state.cockpit_on]
1145
                    - (double)gProgram_state.current_car.tacho_radius_1[gProgram_state.cockpit_on] * cos_angle
1146
                    + (double)the_wobble_y),
1147
                ((double)gProgram_state.current_car.tacho_radius_2[gProgram_state.cockpit_on] * sin_angle
1148
                    + (double)gProgram_state.current_car.tacho_centre_x[gProgram_state.cockpit_on]
1149
                    + (double)the_wobble_x),
1150
                ((double)gProgram_state.current_car.tacho_centre_y[gProgram_state.cockpit_on]
1151
                    - (double)gProgram_state.current_car.tacho_radius_2[gProgram_state.cockpit_on] * cos_angle
1152
                    + (double)the_wobble_y),
1153
                gProgram_state.current_car.tacho_needle_colour[gProgram_state.cockpit_on]);
1154
        } else if (tacho_image != NULL) {
1155
            BrPixelmapRectangleCopy(
1156
                gBack_screen,
1157
                the_wobble_x + gProgram_state.current_car.tacho_x[gProgram_state.cockpit_on],
1158
                the_wobble_y + gProgram_state.current_car.tacho_y[gProgram_state.cockpit_on],
1159
                gProgram_state.current_car.tacho_image[gProgram_state.cockpit_on],
1160
                0,
1161
                0,
1162
                ((gCar_to_view->revs - 1.0) / (double)gCar_to_view->red_line * (double)gProgram_state.current_car.tacho_image[gProgram_state.cockpit_on]->width + 1.0),
1163
                gProgram_state.current_car.tacho_image[gProgram_state.cockpit_on]->height);
1164
        }
1165
        if (!gProgram_state.cockpit_on || gProgram_state.cockpit_image_index < 0 || gProgram_state.which_view == eView_forward) {
1166
            if (gCar_to_view->gear < 0) {
1167
                gear = -1;
1168
            } else {
1169
                gear = gCar_to_view->gear;
1170
            }
1171
#if defined(DETHRACE_FIX_BUGS)
1172
/*
1173
 * The OG derives gear mask height of 16 or 28 by `gears_image->height / 8`, but
1174
 * this is only valid for HGEARS.PIX, which contains 8 gear images. Hardcoding
1175
 * this number fixes gear rendering for cars using HGEARS4.PIX, which consists
1176
 * of 11 gear images.
1177
 */
1178
#define GEAR_HEIGHT 16
1179
#define GEAR_HEIGHT_HIRES 28
1180
#else
1181
#define GEAR_HEIGHT ((int)gProgram_state.current_car.gears_image->height / 8)
1182
#define GEAR_HEIGHT_HIRES GEAR_HEIGHT
1183
#endif
1184
            gear_height = gGraf_spec_index ? GEAR_HEIGHT_HIRES : GEAR_HEIGHT;
1185
            DRPixelmapRectangleMaskedCopy(
1186
                gBack_screen,
1187
                the_wobble_x + gProgram_state.current_car.gear_x[gProgram_state.cockpit_on],
1188
                the_wobble_y + gProgram_state.current_car.gear_y[gProgram_state.cockpit_on],
1189
                gProgram_state.current_car.gears_image,
1190
                0,
1191
                (gear + 1) * gear_height,
1192
                gProgram_state.current_car.gears_image->width,
1193
                gear_height);
1194
        }
1195
        speedo_image = gProgram_state.current_car.speedo_image[gProgram_state.cockpit_on];
1196
        if (gProgram_state.current_car.speedo_radius_2[gProgram_state.cockpit_on] >= 0) {
1197
            if (speedo_image && (!gProgram_state.cockpit_on || gProgram_state.cockpit_image_index < 0)) {
1198
                DRPixelmapRectangleMaskedCopy(
1199
                    gBack_screen,
1200
                    the_wobble_x + gProgram_state.current_car.speedo_x[gProgram_state.cockpit_on],
1201
                    the_wobble_y + gProgram_state.current_car.speedo_y[gProgram_state.cockpit_on],
1202
                    speedo_image,
1203
                    0,
1204
                    0,
1205
                    speedo_image->width,
1206
                    speedo_image->height);
1207
            }
1208
            if ((double)gProgram_state.current_car.max_speed >= speed_mph) {
1209
                the_angle = DEG_TO_RAD((double)(gProgram_state.current_car.speedo_end_angle[gProgram_state.cockpit_on] - gProgram_state.current_car.speedo_start_angle[gProgram_state.cockpit_on]) * speed_mph / (double)gProgram_state.current_car.max_speed + (double)gProgram_state.current_car.speedo_start_angle[gProgram_state.cockpit_on]);
1210
            } else {
1211
                the_angle = DEG_TO_RAD((double)gProgram_state.current_car.speedo_end_angle[gProgram_state.cockpit_on]);
1212
            }
1213
 
1214
            if (the_angle < 0.0) {
1215
                the_angle = the_angle + TAU;
1216
            } else if (the_angle >= TAU) {
1217
                the_angle -= TAU;
1218
            }
1219
            the_angle2 = DR_PI_OVER_2 - the_angle;
1220
            if (the_angle2 < 0.0) {
1221
                the_angle2 += TAU;
1222
            }
1223
            if (the_angle2 > DR_3PI_OVER_2) {
1224
                cos_angle = gCosine_array[(unsigned int)((TAU - the_angle2) / DR_PI * 128.0)];
1225
            } else if (the_angle2 > DR_PI) {
1226
                cos_angle = -gCosine_array[(unsigned int)((the_angle2 - DR_PI) / DR_PI * 128.0)];
1227
            } else if (the_angle2 > DR_PI_OVER_2) {
1228
                cos_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle2) / DR_PI * 128.0)];
1229
            } else {
1230
                cos_angle = gCosine_array[(unsigned int)(the_angle2 / DR_PI * 128.0)];
1231
            }
1232
 
1233
            if (the_angle > DR_3PI_OVER_2) {
1234
                sin_angle = gCosine_array[(unsigned int)((TAU - the_angle) / DR_PI * 128.0)];
1235
            } else if (the_angle > DR_PI) {
1236
                sin_angle = -gCosine_array[(unsigned int)((the_angle - DR_PI) / DR_PI * 128.0)];
1237
            } else if (the_angle > DR_PI_OVER_2) {
1238
                sin_angle = -gCosine_array[(unsigned int)((DR_PI - the_angle) / DR_PI * 128.0)];
1239
            } else {
1240
                sin_angle = gCosine_array[(unsigned int)(the_angle / DR_PI * 128.0)];
1241
            }
1242
 
1243
            PoshDrawLine(
1244
                the_angle,
1245
                gBack_screen,
1246
                ((double)gProgram_state.current_car.speedo_radius_1[gProgram_state.cockpit_on] * sin_angle
1247
                    + (double)gProgram_state.current_car.speedo_centre_x[gProgram_state.cockpit_on]
1248
                    + (double)the_wobble_x),
1249
                ((double)gProgram_state.current_car.speedo_centre_y[gProgram_state.cockpit_on]
1250
                    - (double)gProgram_state.current_car.speedo_radius_1[gProgram_state.cockpit_on] * cos_angle
1251
                    + (double)the_wobble_y),
1252
                ((double)gProgram_state.current_car.speedo_radius_2[gProgram_state.cockpit_on] * sin_angle
1253
                    + (double)gProgram_state.current_car.speedo_centre_x[gProgram_state.cockpit_on]
1254
                    + (double)the_wobble_x),
1255
                ((double)gProgram_state.current_car.speedo_centre_y[gProgram_state.cockpit_on]
1256
                    - (double)gProgram_state.current_car.speedo_radius_2[gProgram_state.cockpit_on] * cos_angle
1257
                    + (double)the_wobble_y),
1258
                gProgram_state.current_car.speedo_needle_colour[gProgram_state.cockpit_on]);
1259
            if (speedo_image != NULL && gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0) {
1260
                DRPixelmapRectangleMaskedCopy(
1261
                    gBack_screen,
1262
                    the_wobble_x + gProgram_state.current_car.speedo_x[gProgram_state.cockpit_on],
1263
                    the_wobble_y + gProgram_state.current_car.speedo_y[gProgram_state.cockpit_on],
1264
                    speedo_image,
1265
                    0,
1266
                    0,
1267
                    speedo_image->width,
1268
                    speedo_image->height);
1269
            }
1270
        } else if (speedo_image != NULL) {
1271
            DrawNumberAt(
1272
                speedo_image,
1273
                the_wobble_x + gProgram_state.current_car.speedo_x[gProgram_state.cockpit_on],
1274
                the_wobble_y + gProgram_state.current_car.speedo_y[gProgram_state.cockpit_on],
1275
                gProgram_state.current_car.speedo_x_pitch[gProgram_state.cockpit_on],
1276
                gProgram_state.current_car.speedo_y_pitch[gProgram_state.cockpit_on],
1277
                speed_mph,
1278
                3,
1279
                1);
1280
        }
1281
    }
1282
}
1283
 
1284
// IDA: void __usercall DoSteeringWheel(tU32 pThe_time@<EAX>)
1285
void DoSteeringWheel(tU32 pThe_time) {
1286
    br_pixelmap* hands_image;
1287
    int hands_index;
1288
    LOG_TRACE("(%d)", pThe_time);
1289
 
1290
    if (gProgram_state.current_car_index == gProgram_state.current_car.index && gProgram_state.cockpit_on && gProgram_state.cockpit_image_index >= 0 && gProgram_state.which_view == eView_forward) {
1291
        hands_index = (int)floor(gProgram_state.current_car.number_of_hands_images * ((1.f - gProgram_state.current_car.steering_angle / 10.f) / 2.f));
1292
        if (hands_index < 0) {
1293
            hands_index = 0;
1294
        } else if (hands_index >= gProgram_state.current_car.number_of_hands_images) {
1295
            hands_index = gProgram_state.current_car.number_of_hands_images - 1;
1296
        }
1297
        hands_image = gProgram_state.current_car.lhands_images[hands_index];
1298
        if (hands_image != NULL) {
1299
            DRPixelmapRectangleMaskedCopy(gBack_screen,
1300
                gProgram_state.current_car.lhands_x[hands_index] + gScreen_wobble_x,
1301
                gProgram_state.current_car.lhands_y[hands_index] + gScreen_wobble_y,
1302
                hands_image, 0, 0, hands_image->width, hands_image->height);
1303
        }
1304
        hands_image = gProgram_state.current_car.rhands_images[hands_index];
1305
        if (hands_image != NULL) {
1306
            DRPixelmapRectangleMaskedCopy(gBack_screen,
1307
                gProgram_state.current_car.rhands_x[hands_index] + gScreen_wobble_x,
1308
                gProgram_state.current_car.rhands_y[hands_index] + gScreen_wobble_y,
1309
                hands_image, 0, 0, hands_image->width, hands_image->height);
1310
        }
1311
    }
1312
}
1313
 
1314
// IDA: void __cdecl ChangingView()
1315
void ChangingView(void) {
1316
    tU32 the_time;
1317
    LOG_TRACE("()");
1318
 
1319
    if (gProgram_state.new_view == eView_undefined) {
1320
        return;
1321
    }
1322
    the_time = PDGetTotalTime() - gProgram_state.view_change_start;
1323
    gScreen_wobble_x = 0;
1324
    gScreen_wobble_y = 0;
1325
    if (the_time > 175 && gProgram_state.which_view == gProgram_state.new_view) {
1326
        if (gProgram_state.pending_view != eView_undefined) {
1327
            if (gProgram_state.pending_view == eView_left) {
1328
                LookLeft();
1329
                return;
1330
            }
1331
            if (gProgram_state.pending_view == eView_forward) {
1332
                LookForward();
1333
                return;
1334
            }
1335
            if (gProgram_state.pending_view == eView_right) {
1336
                LookRight();
1337
                return;
1338
            }
1339
            gScreen_wobble_x = 0;
1340
            gScreen_wobble_y = 0;
1341
            return;
1342
        }
1343
        if (gProgram_state.which_view == gProgram_state.new_view) {
1344
            gProgram_state.new_view = eView_undefined;
1345
            gScreen_wobble_x = 0;
1346
            gScreen_wobble_y = 0;
1347
            return;
1348
        }
1349
    }
1350
    if (the_time < 88) {
1351
        if (gProgram_state.old_view < gProgram_state.new_view) {
1352
            gScreen_wobble_x = -gCurrent_graf_data->cock_margin_x * the_time * 2.f / 175.f;
1353
        } else {
1354
            gScreen_wobble_x = gCurrent_graf_data->cock_margin_x * the_time * 2.f / 175.f;
1355
        }
1356
    } else {
1357
        gProgram_state.which_view = gProgram_state.new_view;
1358
        switch (gProgram_state.new_view) {
1359
        case eView_left:
1360
            gProgram_state.cockpit_image_index = 1;
1361
            break;
1362
        case eView_forward:
1363
            gProgram_state.cockpit_image_index = 0;
1364
            break;
1365
        case eView_right:
1366
            gProgram_state.cockpit_image_index = 2;
1367
            break;
1368
        default:
1369
            break;
1370
        }
1371
        AdjustRenderScreenSize();
1372
        if (gProgram_state.old_view < gProgram_state.new_view) {
1373
            gScreen_wobble_x = gCurrent_graf_data->cock_margin_x * (175 - the_time) * 2.f / 175.f;
1374
        } else {
1375
            gScreen_wobble_x = -gCurrent_graf_data->cock_margin_x * (175 - the_time) * 2.f / 175.f;
1376
        }
1377
    }
1378
}
1379
 
1380
// IDA: void __usercall EarnCredits2(int pAmount@<EAX>, char *pPrefix_text@<EDX>)
1381
void EarnCredits2(int pAmount, char* pPrefix_text) {
1382
    char s[256];
1383
    int original_amount;
1384
    tU32 the_time;
1385
    LOG_TRACE("(%d, \"%s\")", pAmount, pPrefix_text);
1386
 
1387
    if (gRace_finished) {
1388
        return;
1389
    }
1390
    the_time = GetTotalTime();
1391
    if (pAmount == 0) {
1392
        return;
1393
    }
1394
    if (gNet_mode != eNet_mode_none && gProgram_state.credits_earned - gProgram_state.credits_lost + pAmount < 0) {
1395
        pAmount = gProgram_state.credits_lost - gProgram_state.credits_lost;
1396
    }
1397
    original_amount = pAmount;
1398
    if (gLast_credit_headup__displays >= 0 && the_time - gLast_earn_time < 2000) {
1399
        pAmount += gLast_credit_amount;
1400
    }
1401
    gLast_credit_amount = pAmount;
1402
    if (pAmount >= 2) {
1403
        sprintf(s, "%s%d %s", pPrefix_text, pAmount, GetMiscString(kMiscString_Credits));
1404
        gProgram_state.credits_earned += original_amount;
1405
    } else if (pAmount >= 1) {
1406
        sprintf(s, "%s1 %s", pPrefix_text, GetMiscString(kMiscString_Credit));
1407
        gProgram_state.credits_earned += original_amount;
1408
    } else if (pAmount >= -1) {
1409
        sprintf(s, "%s%s 1 %s", pPrefix_text, GetMiscString(kMiscString_Lost), GetMiscString(kMiscString_Credit));
1410
        gProgram_state.credits_lost -= original_amount;
1411
    } else {
1412
        sprintf(s, "%s%s %d %s", GetMiscString(kMiscString_Lost), pPrefix_text, -pAmount, GetMiscString(kMiscString_Credits));
1413
        gProgram_state.credits_lost -= original_amount;
1414
    }
21 pmbaty 1415
    gLast_credit_headup__displays = NewTextHeadupSlot(eHeadupSlot_misc, 0, 2000, -4, s);
1 pmbaty 1416
    gLast_earn_time = the_time;
1417
}
1418
 
1419
// IDA: void __usercall EarnCredits(int pAmount@<EAX>)
1420
void EarnCredits(int pAmount) {
1421
    LOG_TRACE("(%d)", pAmount);
1422
 
1423
    EarnCredits2(pAmount, "");
1424
}
1425
 
1426
// IDA: int __usercall SpendCredits@<EAX>(int pAmount@<EAX>)
1427
int SpendCredits(int pAmount) {
1428
    int amount;
1429
    LOG_TRACE("(%d)", pAmount);
1430
 
1431
    gProgram_state.credits_lost += pAmount;
1432
    if (gNet_mode == eNet_mode_none) {
1433
        return 0;
1434
    }
1435
    amount = gProgram_state.credits_earned - gProgram_state.credits_lost;
1436
    if (gProgram_state.credits_earned - gProgram_state.credits_lost >= 0) {
1437
        return 0;
1438
    }
1439
    gProgram_state.credits_lost = gProgram_state.credits_earned;
1440
    return amount;
1441
}
1442
 
1443
// IDA: void __usercall AwardTime(tU32 pTime@<EAX>)
1444
void AwardTime(tU32 pTime) {
1445
    char s[256];
1446
    tU32 original_amount;
1447
    tU32 the_time;
1448
    int i;
1449
    LOG_TRACE("(%d)", pTime);
1450
 
1451
    if (gRace_finished || gFreeze_timer || gNet_mode != eNet_mode_none || pTime == 0) {
1452
        return;
1453
    }
1454
 
1455
    original_amount = pTime;
1456
    the_time = GetTotalTime();
1457
    for (i = COUNT_OF(gOld_times) - 1; i > 0; i--) {
1458
        gOld_times[i] = gOld_times[i - 1];
1459
    }
1460
    gOld_times[0] = pTime;
1461
    if (gLast_time_credit_headup >= 0 && (the_time - gLast_time_earn_time) < 2000) {
1462
        pTime += gLast_time_credit_amount;
1463
    }
1464
    gLast_time_credit_amount = pTime;
1465
    gTimer += original_amount * 1000;
1466
    s[0] = '+';
1467
    TimerString(1000 * pTime, &s[1], 0, 0);
21 pmbaty 1468
    gLast_time_credit_headup = NewTextHeadupSlot(eHeadupSlot_time_award, 0, 2000, -2, s);
1 pmbaty 1469
    gLast_time_earn_time = the_time;
1470
}
1471
 
1472
// IDA: void __usercall DrawRectangle(br_pixelmap *pPixelmap@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pRight@<ECX>, int pBottom, int pColour)
1473
void DrawRectangle(br_pixelmap* pPixelmap, int pLeft, int pTop, int pRight, int pBottom, int pColour) {
1474
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pPixelmap, pLeft, pTop, pRight, pBottom, pColour);
1475
 
1476
    BrPixelmapLine(pPixelmap, pLeft, pTop, pRight, pTop, pColour);
1477
    BrPixelmapLine(pPixelmap, pLeft, pBottom, pRight, pBottom, pColour);
1478
    BrPixelmapLine(pPixelmap, pLeft, pTop, pLeft, pBottom, pColour);
1479
    BrPixelmapLine(pPixelmap, pRight, pTop, pRight, pBottom, pColour);
1480
}
1481
 
1482
// IDA: void __usercall DrawRRectangle(br_pixelmap *pPixelmap@<EAX>, int pLeft@<EDX>, int pTop@<EBX>, int pRight@<ECX>, int pBottom, int pColour)
1483
void DrawRRectangle(br_pixelmap* pPixelmap, int pLeft, int pTop, int pRight, int pBottom, int pColour) {
1484
    LOG_TRACE("(%p, %d, %d, %d, %d, %d)", pPixelmap, pLeft, pTop, pRight, pBottom, pColour);
1485
 
1486
    BrPixelmapLine(pPixelmap, pLeft + 1, pTop, pRight - 1, pTop, pColour);
1487
    BrPixelmapLine(pPixelmap, pLeft + 1, pBottom, pRight - 1, pBottom, pColour);
1488
    BrPixelmapLine(pPixelmap, pLeft, pTop + 1, pLeft, pBottom - 1, pColour);
1489
    BrPixelmapLine(pPixelmap, pRight, pTop + 1, pRight, pBottom - 1, pColour);
1490
}
1491
 
1492
// IDA: void __usercall OoerrIveGotTextInMeBoxMissus(int pFont_index@<EAX>, char *pText@<EDX>, br_pixelmap *pPixelmap@<EBX>, int pLeft@<ECX>, int pTop, int pRight, int pBottom, int pCentred)
1493
void OoerrIveGotTextInMeBoxMissus(int pFont_index, char* pText, br_pixelmap* pPixelmap, int pLeft, int pTop, int pRight, int pBottom, int pCentred) {
1494
    tDR_font* font;
1495
    int width;
1496
    int current_width;
1497
    int i;
1498
    int centre;
1499
    int line_char_index;
1500
    int input_str_index;
1501
    int start_line;
1502
    int current_y;
1503
    int font_needed_loading;
1504
    char line[256];
1505
    LOG_TRACE("(%d, \"%s\", %p, %d, %d, %d, %d, %d)", pFont_index, pText, pPixelmap, pLeft, pTop, pRight, pBottom, pCentred);
1506
 
1507
    font = &gFonts[pFont_index];
1508
    current_width = 0;
1509
    font_needed_loading = font->images == NULL;
1510
    if (font_needed_loading) {
1511
        LoadFont(pFont_index);
1512
    }
1513
    centre = (pRight + pLeft) / 2;
1514
    current_y = pTop;
1515
    width = pRight - pLeft;
1516
    line_char_index = 0;
1517
    input_str_index = 0;
1518
    start_line = 0;
1519
 
1520
    while (pText[input_str_index]) {
1521
        line[line_char_index] = pText[input_str_index];
1522
        line[line_char_index + 1] = 0;
1523
        current_width += font->spacing + font->width_table[pText[input_str_index] - font->offset];
1524
        if (current_width > width) {
1525
            for (i = input_str_index; i >= start_line; i--) {
1526
                if (pText[i] == ' ') {
1527
                    break;
1528
                }
1529
            }
1530
            if (i == start_line) {
1531
                i = input_str_index;
1532
            }
1533
            line_char_index += i - input_str_index;
1534
            input_str_index = i;
1535
            if (pText[input_str_index] == ' ') {
1536
                input_str_index++;
1537
            }
1538
            line[line_char_index] = 0;
1539
            if (pCentred) {
1540
                DRPixelmapCentredText(gBack_screen, centre, current_y, font, line);
1541
            } else {
1542
                TransDRPixelmapText(gBack_screen, pLeft, current_y, font, line, pRight);
1543
            }
1544
            current_width = 0;
1545
            current_y += 3 * (font->height - (TranslationMode() ? 2 : 0)) / 2;
1546
            line_char_index = 0;
1547
            start_line = input_str_index;
1548
        } else {
1549
            line_char_index++;
1550
            input_str_index++;
1551
        }
1552
    }
1553
    if (line_char_index != 0) {
1554
        if (pCentred) {
1555
            TransDRPixelmapText(gBack_screen, centre - (DRTextWidth(font, line) / 2), current_y, font, line, (DRTextWidth(font, line) / 2) + centre);
1556
        } else {
1557
            TransDRPixelmapText(gBack_screen, pLeft, current_y, font, line, pRight);
1558
        }
1559
    }
1560
    if (font_needed_loading) {
1561
        DisposeFont(pFont_index);
1562
    }
1563
}
1564
 
1565
// IDA: void __usercall TransBrPixelmapText(br_pixelmap *pPixelmap@<EAX>, int pX@<EDX>, int pY@<EBX>, br_uint_32 pColour@<ECX>, br_font *pFont, signed char *pText)
1566
void TransBrPixelmapText(br_pixelmap* pPixelmap, int pX, int pY, br_uint_32 pColour, br_font* pFont, char* pText) {
1567
    int len;
1568
    LOG_TRACE("(%p, %d, %d, %d, %p, %p)", pPixelmap, pX, pY, pColour, pFont, pText);
1569
 
1570
    len = TranslationMode() ? 2 : 0;
1571
    BrPixelmapText(pPixelmap, pX, pY - len, pColour, pFont, (char*)pText);
1572
}
1573
 
1574
// IDA: void __usercall TransDRPixelmapText(br_pixelmap *pPixelmap@<EAX>, int pX@<EDX>, int pY@<EBX>, tDR_font *pFont@<ECX>, char *pText, int pRight_edge)
1575
void TransDRPixelmapText(br_pixelmap* pPixelmap, int pX, int pY, tDR_font* pFont, char* pText, int pRight_edge) {
1576
    LOG_TRACE("(%p, %d, %d, %p, \"%s\", %d)", pPixelmap, pX, pY, pFont, pText, pRight_edge);
1577
 
1578
    if (gAusterity_mode && FlicsPlayedFromDisk() && pFont != gCached_font) {
1579
        if (gCached_font != NULL && gCached_font - gFonts > 13) {
1580
            DisposeFont(gCached_font - gFonts);
1581
        }
1582
        gCached_font = pFont;
1583
    }
1584
    LoadFont(pFont - gFonts);
1585
    DRPixelmapText(pPixelmap, pX, pY - (TranslationMode() ? 2 : 0), pFont, pText, pRight_edge);
1586
}
1587
 
1588
// IDA: void __usercall TransDRPixelmapCleverText(br_pixelmap *pPixelmap@<EAX>, int pX@<EDX>, int pY@<EBX>, tDR_font *pFont@<ECX>, char *pText, int pRight_edge)
1589
void TransDRPixelmapCleverText(br_pixelmap* pPixelmap, int pX, int pY, tDR_font* pFont, char* pText, int pRight_edge) {
1590
    LOG_TRACE("(%p, %d, %d, %p, \"%s\", %d)", pPixelmap, pX, pY, pFont, pText, pRight_edge);
1591
 
1592
    if (gAusterity_mode && FlicsPlayedFromDisk() && gCached_font != pFont) {
1593
        if (gCached_font && gCached_font - gFonts > 13) {
1594
            DisposeFont(gCached_font - gFonts);
1595
        }
1596
        gCached_font = pFont;
1597
    }
1598
    LoadFont(pFont - gFonts);
1599
    DRPixelmapCleverText2(pPixelmap, pX, pY - (TranslationMode() == 0 ? 0 : 2), pFont, pText, pRight_edge);
1600
}