Subversion Repositories Games.Carmageddon

Rev

Rev 18 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include "displays.h"
  2. #include "brender/brender.h"
  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) {
  352.         NewTextHeadupSlot(4, gQueued_headups[0].flash_rate,
  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) {
  926.     //int delta_x; // Pierre-Marie Baty -- unused variable
  927.     //tHeadup* the_headup; // Pierre-Marie Baty -- unused variable
  928.     LOG_TRACE("(%d, %d, %d)", pHeadup_index, pNew_x, pNew_y);
  929.     NOT_IMPLEMENTED();
  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.     }
  1415.     gLast_credit_headup__displays = NewTextHeadupSlot(4, 0, 2000, -4, s);
  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);
  1468.     gLast_time_credit_headup = NewTextHeadupSlot(11, 0, 2000, -2, s);
  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. }
  1601.