Subversion Repositories Games.Carmageddon

Rev

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

  1. #include "powerup.h"
  2. #include "brender/brender.h"
  3. #include "car.h"
  4. #include "controls.h"
  5. #include "crush.h"
  6. #include "displays.h"
  7. #include "errors.h"
  8. #include "globvars.h"
  9. #include "globvrpb.h"
  10. #include "grafdata.h"
  11. #include "graphics.h"
  12. #include "harness/trace.h"
  13. #include "input.h"
  14. #include "loading.h"
  15. #include "netgame.h"
  16. #include "network.h"
  17. #include "opponent.h"
  18. #include "pedestrn.h"
  19. #include "piping.h"
  20. #include "pratcam.h"
  21. #include "sound.h"
  22. #include "utility.h"
  23. #include <stdlib.h>
  24. #include <string.h>
  25.  
  26. tGot_proc* gGot_procs[34] = {
  27.     GotCredits,
  28.     SetPedSpeed,
  29.     SetPedSize,
  30.     SetPedExplode,
  31.     PickAtRandom,
  32.     SetInvulnerability,
  33.     SetFreeRepairs,
  34.     DoInstantRepair,
  35.     FreezeTimer,
  36.     SetEngineFactor,
  37.     SetUnderwater,
  38.     GotTimeOrPower,
  39.     TrashBodywork,
  40.     TakeDrugs,
  41.     SetOpponentsSpeed,
  42.     SetCopsSpeed,
  43.     SetGravity,
  44.     SetPinball,
  45.     SetWallclimb,
  46.     SetBouncey,
  47.     SetSuspension,
  48.     SetTyreGrip,
  49.     SetDamageMultiplier,
  50.     SetHades,
  51.     SetBlindPedestrians,
  52.     PedestrianRespawn,
  53.     GotVouchers,
  54.     SetMassMultiplier,
  55.     SetInstantHandbrake,
  56.     ShowPedestrians,
  57.     HitMine,
  58.     SetProximity,
  59.     SetPedHarvest,
  60.     SetVesuvianCorpses,
  61. };
  62. tLose_proc* gLose_procs[34] = {
  63.     NULL,
  64.     ResetPedSpeed,
  65.     ResetPedSize,
  66.     ResetPedExplode,
  67.     NULL,
  68.     ResetInvulnerability,
  69.     ResetFreeRepairs,
  70.     NULL,
  71.     UnfreezeTimer,
  72.     ResetEngineFactor,
  73.     ResetUnderwater,
  74.     NULL,
  75.     NULL,
  76.     PukeDrugsBackUp,
  77.     ResetOpponentsSpeed,
  78.     ResetCopsSpeed,
  79.     ResetGravity,
  80.     ResetPinball,
  81.     ResetWallclimb,
  82.     ResetBouncey,
  83.     ResetSuspension,
  84.     ResetTyreGrip,
  85.     ResetDamageMultiplier,
  86.     ResetHades,
  87.     ResetBlindPedestrians,
  88.     NULL,
  89.     NULL,
  90.     ResetMassMultiplier,
  91.     ResetInstantHandbrake,
  92.     HidePedestrians,
  93.     NULL,
  94.     ResetProximity,
  95.     ResetPedHarvest,
  96.     ResetVesuvianCorpses,
  97. };
  98. tPeriodic_proc* gPeriodic_procs[34] = {
  99.     NULL,
  100.     NULL,
  101.     NULL,
  102.     NULL,
  103.     NULL,
  104.     NULL,
  105.     NULL,
  106.     NULL,
  107.     NULL,
  108.     NULL,
  109.     NULL,
  110.     NULL,
  111.     NULL,
  112.     TheEffectsOfDrugs,
  113.     NULL,
  114.     NULL,
  115.     NULL,
  116.     NULL,
  117.     NULL,
  118.     DoBouncey,
  119.     NULL,
  120.     NULL,
  121.     NULL,
  122.     NULL,
  123.     NULL,
  124.     NULL,
  125.     MungeVouchers,
  126.     NULL,
  127.     NULL,
  128.     NULL,
  129.     NULL,
  130.     NULL,
  131.     NULL,
  132.     NULL,
  133. };
  134. tU32* gReal_render_palette;
  135. char* gFizzle_names[3] = { "CIRCLES.PIX", "SQUARES.PIX", "DIAMONDS.PIX" };
  136. br_vector3 gZero_v__powerup; // suffix added to avoid duplicate symbol
  137. int gPed_harvest_sounds[4] = { 4010, 4012, 4030, 4032 };
  138. tHeadup_icon gIcon_list[20];
  139. br_pixelmap* gFizzle_in[3];
  140. int gNumber_of_powerups;
  141. int gFizzle_height;
  142. int gNumber_of_icons;
  143. tPowerup* gPowerup_array;
  144.  
  145. #define GET_POWERUP_INDEX(POWERUP) (((POWERUP)-gPowerup_array) / sizeof(tPowerup))
  146.  
  147. // IDA: void __usercall LosePowerupX(tPowerup *pThe_powerup@<EAX>, int pTell_net_players@<EDX>)
  148. void LosePowerupX(tPowerup* pThe_powerup, int pTell_net_players) {
  149.     int i;
  150.     tNet_message* the_message;
  151.     LOG_TRACE("(%p, %d)", pThe_powerup, pTell_net_players);
  152.  
  153.     if (pThe_powerup->got_time != 0 && pThe_powerup->lose_proc != NULL) {
  154.         pThe_powerup->lose_proc(pThe_powerup, pThe_powerup->car);
  155.     }
  156.     if (gNet_mode != eNet_mode_none) {
  157.         the_message = NetBuildMessage(21, 0);
  158.         the_message->contents.data.powerup.event = ePowerup_lost;
  159.         the_message->contents.data.powerup.player = gLocal_net_ID;
  160.         the_message->contents.data.powerup.event = GET_POWERUP_INDEX(pThe_powerup);
  161.         NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL);
  162.     }
  163.     for (i = 0; i < gNumber_of_icons; i++) {
  164.         if (gIcon_list[i].powerup == pThe_powerup) {
  165.             gIcon_list[i].fizzle_stage = 3;
  166.             gIcon_list[i].fizzle_direction = -1;
  167.             gIcon_list[i].fizzle_start = GetTotalTime();
  168.             break;
  169.         }
  170.     }
  171.     pThe_powerup->got_time = 0;
  172. }
  173.  
  174. // IDA: void __usercall LosePowerup(tPowerup *pThe_powerup@<EAX>)
  175. void LosePowerup(tPowerup* pThe_powerup) {
  176.     LOG_TRACE("(%p)", pThe_powerup);
  177.  
  178.     LosePowerupX(pThe_powerup, 1);
  179. }
  180.  
  181. // IDA: void __usercall LoseAllSimilarPowerups(tPowerup *pThe_powerup@<EAX>)
  182. void LoseAllSimilarPowerups(tPowerup* pThe_powerup) {
  183.     int i;
  184.     tPowerup* the_powerup;
  185.     LOG_TRACE("(%p)", pThe_powerup);
  186.  
  187.     for (i = 0, the_powerup = gPowerup_array; i < gNumber_of_powerups; i++, the_powerup++) {
  188.         if (the_powerup != pThe_powerup && the_powerup->got_time != 0) {
  189.             if ((pThe_powerup->group_inclusion & the_powerup->group_inclusion) != 0) {
  190.                 LosePowerup(the_powerup);
  191.             }
  192.         }
  193.     }
  194. }
  195.  
  196. // IDA: int __usercall GotPowerupX@<EAX>(tCar_spec *pCar@<EAX>, int pIndex@<EDX>, int pTell_net_players@<EBX>, int pDisplay_headup@<ECX>, tU32 pTime_left)
  197. int GotPowerupX(tCar_spec* pCar, int pIndex, int pTell_net_players, int pDisplay_headup, tU32 pTime_left) {
  198.     tPowerup* the_powerup;
  199.     int i;
  200.     int original_index;
  201.     //int icon_index; // Pierre-Marie Baty -- unused variable
  202.     int ps_power;
  203.     char s[256];
  204.     char* s2;
  205.     tNet_message* the_message;
  206.     LOG_TRACE("(%p, %d, %d, %d, %d)", pCar, pIndex, pTell_net_players, pDisplay_headup, pTime_left);
  207.  
  208.     if (pIndex < 0 || pIndex >= gNumber_of_powerups) {
  209.         return -1;
  210.     }
  211.     the_powerup = &gPowerup_array[pIndex];
  212.     if (the_powerup->type == ePowerup_dummy) {
  213.         return -1;
  214.     }
  215.     if (the_powerup->got_proc == NULL) {
  216.         NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, GetMiscString(kMiscString_UNAVAILABLE_IN_DEMO));
  217.         return -1;
  218.     }
  219.     original_index = pIndex;
  220.     if (((gProgram_state.sausage_eater_mode || gTotal_peds < 2)
  221.             && (strstr(the_powerup->message, "Ped") != NULL
  222.                 || strstr(the_powerup->message, "ped") != NULL
  223.                 || strstr(the_powerup->message, "corpses") != NULL))
  224.         || (gNet_mode != eNet_mode_none && the_powerup->net_type == eNet_powerup_inappropriate)) {
  225.         pIndex = 0;
  226.         the_powerup = &gPowerup_array[pIndex];
  227.     }
  228.     the_powerup->current_value = -1;
  229.     LoseAllSimilarPowerups(the_powerup);
  230.     ps_power = gNet_mode != eNet_mode_none && the_powerup->got_proc == GotTimeOrPower;
  231.     if (the_powerup->message[0] != '\0' && pDisplay_headup && !ps_power) {
  232.         strcpy(s, the_powerup->message);
  233.         s2 = s;
  234.         if (the_powerup->got_proc == FreezeTimer) {
  235.             s2 = strtok(s, "/");
  236.             if (gFreeze_timer) {
  237.                 s2 = strtok(NULL, "/");
  238.             }
  239.         }
  240.         NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, s2);
  241.     }
  242.     the_powerup->car = pCar;
  243.     if (the_powerup->got_proc != NULL) {
  244.         pIndex = the_powerup->got_proc(the_powerup, pCar);
  245.     }
  246.     if (pCar->driver == eDriver_non_car_unused_slot || pCar->driver == eDriver_non_car) {
  247.         return pIndex;
  248.     }
  249.     if (the_powerup->type == ePowerup_timed) {
  250.         the_powerup->got_time = GetTotalTime();
  251.         if (pTell_net_players) {
  252.             the_powerup->lose_time = the_powerup->got_time + the_powerup->duration;
  253.         } else {
  254.             the_powerup->lose_time = the_powerup->got_time + pTime_left;
  255.         }
  256.         gProgram_state.current_car.powerups[pIndex] = the_powerup->lose_time;
  257.     } else if (the_powerup->type == ePowerup_whole_race) {
  258.         the_powerup->got_time = GetTotalTime();
  259.         gProgram_state.current_car.powerups[pIndex] = -1;
  260.     }
  261.     if (the_powerup->prat_cam_event >= 0) {
  262.         PratcamEvent(the_powerup->prat_cam_event);
  263.     }
  264.     if (gNet_mode != eNet_mode_none && pTell_net_players && pIndex == original_index && !ps_power) {
  265.         the_message = NetBuildMessage(21, 0);
  266.         the_message->contents.data.powerup.event = ePowerup_gained;
  267.         the_message->contents.data.powerup.player = gLocal_net_ID;
  268.         the_message->contents.data.powerup.powerup_index = pIndex;
  269.         if (the_powerup->type == ePowerup_timed) {
  270.             the_message->contents.data.powerup.time_left = the_powerup->duration;
  271.         } else {
  272.             the_message->contents.data.powerup.time_left = 0;
  273.         }
  274.         NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL);
  275.     }
  276.     if (the_powerup->type != ePowerup_instantaneous && the_powerup->icon != NULL) {
  277.         for (i = 0; i < gNumber_of_icons; i++) {
  278.             if (gIcon_list[i].powerup == the_powerup) {
  279.                 gIcon_list[i].fizzle_stage = 4;
  280.                 return pIndex;
  281.             }
  282.         }
  283.         if (gNumber_of_icons != COUNT_OF(gIcon_list)) {
  284.             gIcon_list[gNumber_of_icons].powerup = the_powerup;
  285.             gIcon_list[gNumber_of_icons].fizzle_stage = 0;
  286.             gIcon_list[gNumber_of_icons].fizzle_direction = 1;
  287.             gIcon_list[gNumber_of_icons].fizzle_start = GetTotalTime();
  288.             gNumber_of_icons++;
  289.         }
  290.     }
  291.     return pIndex;
  292. }
  293.  
  294. // IDA: int __usercall GotPowerup@<EAX>(tCar_spec *pCar@<EAX>, int pIndex@<EDX>)
  295. int GotPowerup(tCar_spec* pCar, int pIndex) {
  296.     LOG_TRACE("(%p, %d)", pCar, pIndex);
  297.  
  298.     return GotPowerupX(pCar, pIndex, 1, 1, 0);
  299. }
  300.  
  301. // IDA: void __cdecl LoadPowerups()
  302. void LoadPowerups(void) {
  303.     FILE* f;
  304.     tPath_name the_path;
  305.     char s[256];
  306.     int i;
  307.     int j;
  308.     int time;
  309.     int action_index;
  310.     tPowerup* the_powerup;
  311.     LOG_TRACE("()");
  312.  
  313.     for (i = 0; i < COUNT_OF(gFizzle_in); i++) {
  314.         gFizzle_in[i] = LoadPixelmap(gFizzle_names[i]);
  315.     }
  316.  
  317.     gFizzle_height = gFizzle_in[0]->height / 4;
  318.     PathCat(the_path, gApplication_path, "POWERUP.TXT");
  319.     f = DRfopen(the_path, "rt");
  320.     if (f == NULL) {
  321.         FatalError(kFatalError_LoadResolutionIndependentFile);
  322.     }
  323.     gNumber_of_powerups = GetAnInt(f);
  324.     gPowerup_array = BrMemAllocate(sizeof(tPowerup) * gNumber_of_powerups, kMem_powerup_array);
  325.     for (i = 0; i < gNumber_of_powerups; i++) {
  326.         the_powerup = &gPowerup_array[i];
  327.  
  328.         GetALineAndDontArgue(f, the_powerup->message);
  329.         if (strcmp(the_powerup->message, "dummy") == 0) {
  330.             the_powerup->type = 0;
  331.         } else {
  332.             if (strcmp(the_powerup->message, "n/a") == 0) {
  333.                 the_powerup->message[0] = 0;
  334.             }
  335.             GetAString(f, s);
  336.             the_powerup->icon = LoadPixelmap(s);
  337.             the_powerup->fizzle_type = GetAnInt(f);
  338.             time = 1000 * GetAnInt(f);
  339.             the_powerup->duration = time;
  340.             if (time > 0) {
  341.                 the_powerup->type = ePowerup_timed;
  342.             } else if (time == 0) {
  343.                 the_powerup->type = ePowerup_whole_race;
  344.             } else {
  345.                 the_powerup->type = ePowerup_instantaneous;
  346.             }
  347.         }
  348.         action_index = GetAnInt(f);
  349.         if (action_index >= 0) {
  350.             the_powerup->got_proc = gGot_procs[action_index];
  351.             the_powerup->lose_proc = gLose_procs[action_index];
  352.             the_powerup->periodic_proc = gPeriodic_procs[action_index];
  353.         } else {
  354.             the_powerup->lose_proc = NULL;
  355.             the_powerup->periodic_proc = NULL;
  356.             the_powerup->got_proc = NULL;
  357.         }
  358.         the_powerup->number_of_float_params = GetAnInt(f);
  359.         the_powerup->float_params = BrMemAllocate(sizeof(float) * the_powerup->number_of_float_params, kMem_powerup_float_parms);
  360.         for (j = 0; j < the_powerup->number_of_float_params; j++) {
  361.             the_powerup->float_params[j] = GetAFloat(f);
  362.         }
  363.         the_powerup->number_of_integer_params = GetAnInt(f);
  364.         the_powerup->integer_params = BrMemAllocate(sizeof(int) * the_powerup->number_of_integer_params, kMem_powerup_int_parms);
  365.         for (j = 0; j < the_powerup->number_of_integer_params; j++) {
  366.             the_powerup->integer_params[j] = GetAnInt(f);
  367.         }
  368.         the_powerup->group_inclusion = GetAnInt(f);
  369.         the_powerup->prat_cam_event = GetAnInt(f);
  370.         the_powerup->net_type = GetAnInt(f);
  371.     }
  372.     fclose(f);
  373. }
  374.  
  375. // IDA: void __cdecl InitPowerups()
  376. void InitPowerups(void) {
  377.     int i;
  378.     tPowerup* the_powerup;
  379.     LOG_TRACE("()");
  380.  
  381.     for (i = 0, the_powerup = gPowerup_array; i < gNumber_of_powerups; i++, the_powerup++) {
  382.         the_powerup->got_time = 0;
  383.         the_powerup->current_value = -1;
  384.     }
  385. }
  386.  
  387. // IDA: void __cdecl CloseDownPowerUps()
  388. void CloseDownPowerUps(void) {
  389.     int i;
  390.     tPowerup* the_powerup;
  391.     LOG_TRACE("()");
  392.  
  393.     for (i = 0, the_powerup = gPowerup_array; i < gNumber_of_powerups; i++, the_powerup++) {
  394.         if (the_powerup->got_time != 0) {
  395.             LosePowerup(the_powerup);
  396.         }
  397.     }
  398. }
  399.  
  400. // IDA: void __usercall DrawPowerups(tU32 pTime@<EAX>)
  401. void DrawPowerups(tU32 pTime) {
  402.     int i;
  403.     int y;
  404.     int timer;
  405.     tPowerup* the_powerup;
  406.     char s[8];
  407.     tHeadup_icon* the_icon;
  408.     br_pixelmap* fizzle_pix;
  409.     LOG_TRACE("(%d)", pTime);
  410.  
  411.     y = gCurrent_graf_data->power_up_icon_y;
  412.     for (i = 0; i < gNumber_of_icons && i < 5; i++) {
  413.         the_icon = &gIcon_list[i];
  414.         the_powerup = the_icon->powerup;
  415.         if (the_powerup->icon == NULL) {
  416.             continue;
  417.         }
  418.         y += gCurrent_graf_data->power_up_icon_y_pitch;
  419.         if (the_icon->fizzle_stage < 4) {
  420.             if (the_icon->fizzle_direction >= 0) {
  421.                 the_icon->fizzle_stage = (pTime - the_icon->fizzle_start) / 100;
  422.             } else {
  423.                 the_icon->fizzle_stage = 3 - (pTime - the_icon->fizzle_start) / 100;
  424.             }
  425.             if (the_icon->fizzle_stage >= 5) {
  426.                 the_icon->fizzle_stage = 4;
  427.             } else if (the_icon->fizzle_stage < 0) {
  428.                 memmove(the_icon, the_icon + 1, sizeof(tHeadup_icon) * (gNumber_of_icons - i - 1));
  429.                 gNumber_of_icons--;
  430.                 continue;
  431.             }
  432.         }
  433.         if (the_icon->fizzle_stage >= 4) {
  434.             DRPixelmapRectangleMaskedCopy(gBack_screen,
  435.                 gCurrent_graf_data->power_up_icon_x, y,
  436.                 the_powerup->icon, 0, 0, the_powerup->icon->width, the_powerup->icon->height);
  437.             if (the_powerup->type == ePowerup_timed) {
  438.                 timer = the_powerup->lose_time - pTime;
  439.                 if (timer <= 0) {
  440.                     timer = 0;
  441.                 }
  442.                 TimerString(timer, s, 0, 0);
  443.                 TransDRPixelmapText(gBack_screen,
  444.                     gCurrent_graf_data->power_up_icon_countdown_x,
  445.                     y + gCurrent_graf_data->power_up_icon_countdown_y_offset,
  446.                     &gFonts[kFont_ORANGHED], s, gCurrent_graf_data->power_up_icon_countdown_x + 30);
  447.             } else if (the_powerup->current_value > 0) {
  448.                 sprintf(s, "%d", the_powerup->current_value);
  449.                 TransDRPixelmapText(gBack_screen,
  450.                     gCurrent_graf_data->power_up_icon_countdown_x,
  451.                     y + gCurrent_graf_data->power_up_icon_countdown_y_offset,
  452.                     &gFonts[kFont_BLUEHEAD], s, gCurrent_graf_data->power_up_icon_countdown_x + 30);
  453.             }
  454.         } else {
  455.             fizzle_pix = gFizzle_in[the_powerup->fizzle_type];
  456.             DRPixelmapRectangleMaskedCopy(gBack_screen,
  457.                 gCurrent_graf_data->power_up_icon_x, y, fizzle_pix, 0,
  458.                 the_icon->fizzle_stage * gFizzle_height, fizzle_pix->width, gFizzle_height);
  459.         }
  460.     }
  461. }
  462.  
  463. // IDA: void __usercall DoPowerupPeriodics(tU32 pFrame_period@<EAX>)
  464. void DoPowerupPeriodics(tU32 pFrame_period) {
  465.     int i;
  466.     tPowerup* the_powerup;
  467.     tU32 the_time;
  468.     LOG_TRACE("(%d)", pFrame_period);
  469.  
  470.     the_time = GetTotalTime();
  471.     for (i = 0, the_powerup = gPowerup_array; i < gNumber_of_powerups; i++, the_powerup++) {
  472.         if (the_powerup->got_time != 0) {
  473.             if (the_powerup->type == ePowerup_timed && the_powerup->lose_time <= the_time) {
  474.                 LosePowerup(the_powerup);
  475.             } else if (the_powerup->current_value == 0) {
  476.                 LosePowerup(the_powerup);
  477.             } else if (the_powerup->periodic_proc != NULL) {
  478.                 the_powerup->periodic_proc(the_powerup, pFrame_period);
  479.             }
  480.         }
  481.     }
  482. }
  483.  
  484. // IDA: void __usercall GotPowerupN(int pN@<EAX>)
  485. void GotPowerupN(int pN) {
  486.     int modifiers;
  487.     LOG_TRACE("(%d)", pN);
  488.  
  489.     modifiers = 0;
  490.     if (PDKeyDown(KEY_SHIFT_ANY) != 0) {
  491.         modifiers += 10;
  492.     }
  493.     if (PDKeyDown(KEY_ALT_ANY) != 0) {
  494.         modifiers += 20;
  495.     }
  496.     if (PDKeyDown(KEY_CTRL_ANY) != 0) {
  497.         modifiers += 40;
  498.     }
  499.     GotPowerup(&gProgram_state.current_car, modifiers + pN);
  500. }
  501.  
  502. // IDA: void __cdecl GotPowerup0()
  503. void GotPowerup0(void) {
  504.     LOG_TRACE("()");
  505.  
  506.     GotPowerupN(0);
  507. }
  508.  
  509. // IDA: void __cdecl GotPowerup1()
  510. void GotPowerup1(void) {
  511.     LOG_TRACE("()");
  512.  
  513.     GotPowerupN(1);
  514. }
  515.  
  516. // IDA: void __cdecl GotPowerup2()
  517. void GotPowerup2(void) {
  518.     LOG_TRACE("()");
  519.  
  520.     GotPowerupN(2);
  521. }
  522.  
  523. // IDA: void __cdecl GotPowerup3()
  524. void GotPowerup3(void) {
  525.     LOG_TRACE("()");
  526.  
  527.     GotPowerupN(3);
  528. }
  529.  
  530. // IDA: void __cdecl GotPowerup4()
  531. void GotPowerup4(void) {
  532.     LOG_TRACE("()");
  533.  
  534.     GotPowerupN(4);
  535. }
  536.  
  537. // IDA: void __cdecl GotPowerup5()
  538. void GotPowerup5(void) {
  539.     LOG_TRACE("()");
  540.  
  541.     GotPowerupN(5);
  542. }
  543.  
  544. // IDA: void __cdecl GotPowerup6()
  545. void GotPowerup6(void) {
  546.     LOG_TRACE("()");
  547.  
  548.     GotPowerupN(6);
  549. }
  550.  
  551. // IDA: void __cdecl GotPowerup7()
  552. void GotPowerup7(void) {
  553.     LOG_TRACE("()");
  554.  
  555.     GotPowerupN(7);
  556. }
  557.  
  558. // IDA: void __cdecl GotPowerup8()
  559. void GotPowerup8(void) {
  560.     LOG_TRACE("()");
  561.  
  562.     GotPowerupN(8);
  563. }
  564.  
  565. // IDA: void __cdecl GotPowerup9()
  566. void GotPowerup9(void) {
  567.     LOG_TRACE("()");
  568.  
  569.     GotPowerupN(9);
  570. }
  571.  
  572. // IDA: int __usercall GotCredits@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  573. int GotCredits(tPowerup* pPowerup, tCar_spec* pCar) {
  574.     //int credits; // Pierre-Marie Baty -- unused variable
  575.     char s[256];
  576.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  577.  
  578.     if (pCar->driver == eDriver_local_human) {
  579.         strcpy(s, pPowerup->message);
  580.         strcat(s, " ");
  581.         EarnCredits2((IRandomBetween(pPowerup->integer_params[0], pPowerup->integer_params[1]) / 100) * 100, s);
  582.     }
  583.     return GET_POWERUP_INDEX(pPowerup);
  584. }
  585.  
  586. // IDA: void __usercall ImprovePSPowerup(tCar_spec *pCar@<EAX>, int pIndex@<EDX>)
  587. void ImprovePSPowerup(tCar_spec* pCar, int pIndex) {
  588.     //tNet_message* the_message; // Pierre-Marie Baty -- unused variable
  589.     LOG_TRACE("(%p, %d)", pCar, pIndex);
  590.  
  591.     pCar->power_up_levels[pIndex]++;
  592.     NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, GetMiscString(kMiscString_APOGained_START + pIndex));
  593. }
  594.  
  595. // IDA: int __usercall GotTimeOrPower@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  596. int GotTimeOrPower(tPowerup* pPowerup, tCar_spec* pCar) {
  597.     int time;
  598.     int index;
  599.     int i;
  600.     int not_allowed_power;
  601.     //char s[256]; // Pierre-Marie Baty -- unused variable
  602.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  603.  
  604.     if (gNet_mode == eNet_mode_none) {
  605.         if (pCar->driver == eDriver_local_human) {
  606.             time = IRandomBetween(pPowerup->integer_params[0], pPowerup->integer_params[1]);
  607.             AwardTime(time);
  608.         }
  609.     } else {
  610.         not_allowed_power = (gCurrent_net_game->type == eNet_game_type_foxy && gThis_net_player_index == gIt_or_fox)
  611.             || (gCurrent_net_game->type == eNet_game_type_tag && gThis_net_player_index != gIt_or_fox);
  612.         if (pCar->power_up_levels[0] < 4 || (pCar->power_up_levels[1] < 4 && !not_allowed_power) || pCar->power_up_levels[2] < 4) {
  613.             for (i = 0; i < 50; i++) {
  614.                 if (not_allowed_power) {
  615.                     index = PercentageChance(50) ? 0 : 2;
  616.                 } else {
  617.                     index = IRandomBetween(0, 2);
  618.                 }
  619.                 if (pCar->power_up_levels[index] < 4) {
  620.                     ImprovePSPowerup(pCar, index);
  621.                     break;
  622.                 }
  623.             }
  624.         } else {
  625.             NewTextHeadupSlot(eHeadupSlot_misc, 0, 3000, -4, GetMiscString(kMiscString_YOU_ARE_ALREADY_AT_MAX));
  626.         }
  627.     }
  628.     return GET_POWERUP_INDEX(pPowerup);
  629. }
  630.  
  631. // IDA: int __usercall SetPedSpeed@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  632. int SetPedSpeed(tPowerup* pPowerup, tCar_spec* pCar) {
  633.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  634.  
  635.     gPedestrian_speed_factor = pPowerup->float_params[0];
  636.     return GET_POWERUP_INDEX(pPowerup);
  637. }
  638.  
  639. // IDA: int __usercall SetHades@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  640. int SetHades(tPowerup* pPowerup, tCar_spec* pCar) {
  641.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  642.  
  643.     PedMaterialFromHell();
  644.     return GET_POWERUP_INDEX(pPowerup);
  645. }
  646.  
  647. // IDA: void __usercall ResetHades(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  648. void ResetHades(tPowerup* pPowerup, tCar_spec* pCar) {
  649.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  650.  
  651.     ResetPedMaterial();
  652. }
  653.  
  654. // IDA: int __usercall SetPedSize@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  655. int SetPedSize(tPowerup* pPowerup, tCar_spec* pCar) {
  656.     br_scalar old_scale;
  657.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  658.  
  659.     old_scale = gPed_scale_factor;
  660.     if (old_scale != pPowerup->float_params[0]) {
  661.         if (gPed_scale_factor > 1.f) {
  662.             gPed_scale_factor = pPowerup->float_params[0];
  663.             PipeSingleSpecial(ePipe_special_giant_ped_off);
  664.         } else {
  665.             gPed_scale_factor = pPowerup->float_params[0];
  666.             if (old_scale < 1.f) {
  667.                 PipeSingleSpecial(ePipe_special_min_ped_off);
  668.             }
  669.         }
  670.         if (gPed_scale_factor > 1.f) {
  671.             PipeSingleSpecial(ePipe_special_giant_ped_on);
  672.             old_scale = gPed_scale_factor;
  673.         } else {
  674.             old_scale = gPed_scale_factor;
  675.             if (gPed_scale_factor < 1.f) {
  676.                 PipeSingleSpecial(ePipe_special_min_ped_on);
  677.                 old_scale = gPed_scale_factor;
  678.             }
  679.         }
  680.     }
  681.     gPed_scale_factor = old_scale;
  682.     return GET_POWERUP_INDEX(pPowerup);
  683. }
  684.  
  685. // IDA: int __usercall SetPedExplode@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  686. int SetPedExplode(tPowerup* pPowerup, tCar_spec* pCar) {
  687.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  688.  
  689.     gExploding_pedestrians = 1;
  690.     return GET_POWERUP_INDEX(pPowerup);
  691. }
  692.  
  693. // IDA: int __usercall SetInvulnerability@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  694. int SetInvulnerability(tPowerup* pPowerup, tCar_spec* pCar) {
  695.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  696.  
  697.     pCar->invulnerable = 1;
  698.     return GET_POWERUP_INDEX(pPowerup);
  699. }
  700.  
  701. // IDA: void __usercall ResetInvulnerability(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  702. void ResetInvulnerability(tPowerup* pPowerup, tCar_spec* pCar) {
  703.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  704.  
  705.     pCar->invulnerable = 0;
  706. }
  707.  
  708. // IDA: int __usercall SetFreeRepairs@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  709. int SetFreeRepairs(tPowerup* pPowerup, tCar_spec* pCar) {
  710.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  711.  
  712.     if (pCar->driver == eDriver_local_human) {
  713.         gFree_repairs = 1;
  714.     }
  715.     return GET_POWERUP_INDEX(pPowerup);
  716. }
  717.  
  718. // IDA: void __usercall ResetFreeRepairs(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  719. void ResetFreeRepairs(tPowerup* pPowerup, tCar_spec* pCar) {
  720.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  721.  
  722.     if (pCar->driver == eDriver_local_human) {
  723.         gFree_repairs = 0;
  724.     }
  725. }
  726.  
  727. // IDA: int __usercall SetBlindPedestrians@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  728. int SetBlindPedestrians(tPowerup* pPowerup, tCar_spec* pCar) {
  729.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  730.  
  731.     gBlind_pedestrians = 1;
  732.     return GET_POWERUP_INDEX(pPowerup);
  733. }
  734.  
  735. // IDA: void __usercall ResetBlindPedestrians(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  736. void ResetBlindPedestrians(tPowerup* pPowerup, tCar_spec* pCar) {
  737.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  738.  
  739.     gBlind_pedestrians = 0;
  740. }
  741.  
  742. // IDA: int __usercall FreezeTimer@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  743. int FreezeTimer(tPowerup* pPowerup, tCar_spec* pCar) {
  744.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  745.  
  746.     if (pCar->driver == eDriver_local_human) {
  747.         gFreeze_timer = !gFreeze_timer;
  748.     }
  749.     return GET_POWERUP_INDEX(pPowerup);
  750. }
  751.  
  752. // IDA: void __usercall UnfreezeTimer(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  753. void UnfreezeTimer(tPowerup* pPowerup, tCar_spec* pCar) {
  754.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  755.  
  756.     if (pCar->driver == eDriver_local_human) {
  757.         gFreeze_timer = 0;
  758.     }
  759. }
  760.  
  761. // IDA: int __usercall DoInstantRepair@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  762. int DoInstantRepair(tPowerup* pPowerup, tCar_spec* pCar) {
  763.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  764.  
  765.     if (pCar->driver == eDriver_local_human) {
  766.         TotallyRepairCar();
  767.     }
  768.     return GET_POWERUP_INDEX(gPowerup_array);
  769. }
  770.  
  771. // IDA: void __usercall ResetPedSpeed(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  772. void ResetPedSpeed(tPowerup* pPowerup, tCar_spec* pCar) {
  773.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  774.  
  775.     gPedestrian_speed_factor = 1.f;
  776. }
  777.  
  778. // IDA: void __usercall ResetPedSize(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  779. void ResetPedSize(tPowerup* pPowerup, tCar_spec* pCar) {
  780.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  781.  
  782.     gPed_scale_factor = 1.f;
  783.     PipeSingleSpecial(ePipe_special_giant_ped_off);
  784. }
  785.  
  786. // IDA: void __usercall ResetPedExplode(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  787. void ResetPedExplode(tPowerup* pPowerup, tCar_spec* pCar) {
  788.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  789.  
  790.     gExploding_pedestrians = 0;
  791. }
  792.  
  793. // IDA: int __usercall SetEngineFactor@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  794. int SetEngineFactor(tPowerup* pPowerup, tCar_spec* pCar) {
  795.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  796.  
  797.     pCar->engine_power_multiplier = pPowerup->float_params[0];
  798.     pCar->grip_multiplier = pPowerup->float_params[1];
  799.     SetCarSuspGiveAndHeight(pCar, pPowerup->float_params[2], pPowerup->float_params[3],
  800.         pPowerup->float_params[6], pPowerup->float_params[4], pPowerup->float_params[5]);
  801.     return GET_POWERUP_INDEX(pPowerup);
  802. }
  803.  
  804. // IDA: int __usercall SetUnderwater@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  805. int SetUnderwater(tPowerup* pPowerup, tCar_spec* pCar) {
  806.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  807.  
  808.     pCar->underwater_ability = 1;
  809.     return GET_POWERUP_INDEX(pPowerup);
  810. }
  811.  
  812. // IDA: int __usercall TrashBodywork@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  813. int TrashBodywork(tPowerup* pPowerup, tCar_spec* pCar) {
  814.     int i;
  815.     //tCar_spec* c; // Pierre-Marie Baty -- unused variable
  816.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  817.  
  818.     for (i = 0; i < pCar->car_actor_count; i++) {
  819.         TotallySpamTheModel(pCar, i, pCar->car_model_actors[i].actor, &pCar->car_model_actors[i].crush_data, 0.5f);
  820.     }
  821.     if (pCar->driver == eDriver_local_human) {
  822.         DRS3StartSound2(gCar_outlet, 5000, 1, 255, 255, -1, -1);
  823.         DRS3StartSound2(gCar_outlet, 5001, 1, 255, 255, -1, -1);
  824.         DRS3StartSound2(gCar_outlet, 5002, 1, 255, 255, -1, -1);
  825.     }
  826.     return GET_POWERUP_INDEX(pPowerup);
  827. }
  828.  
  829. // IDA: int __usercall TakeDrugs@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  830. int TakeDrugs(tPowerup* pPowerup, tCar_spec* pCar) {
  831.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  832.  
  833.     if (pCar->driver == eDriver_local_human) {
  834.         if (gReal_render_palette == NULL) {
  835.             gReal_render_palette = BrMemAllocate(sizeof(tU32) * 256, kMem_drugs_palette);
  836.             memcpy(gReal_render_palette, gRender_palette->pixels, sizeof(tU32) * 256);
  837.         }
  838.         gOn_drugs = 1;
  839.     }
  840.     return GET_POWERUP_INDEX(pPowerup);
  841. }
  842.  
  843. // IDA: void __usercall PaletteFuckedUpByDrugs(br_pixelmap *pPixelmap@<EAX>, int pOffset@<EDX>)
  844. void PaletteFuckedUpByDrugs(br_pixelmap* pPixelmap, int pOffset) {
  845.     int i;
  846.     LOG_TRACE("(%p, %d)", pPixelmap, pOffset);
  847.  
  848.     ((tU32*)gRender_palette->pixels)[0] = gReal_render_palette[0];
  849.     for (i = 1; i < 224; i++) {
  850.         ((tU32*)gRender_palette->pixels)[i] = gReal_render_palette[(i + pOffset) & 0xff];
  851.     }
  852.     for (i = 224; i < 256; i++) {
  853.         ((tU32*)gRender_palette->pixels)[i] = gReal_render_palette[i];
  854.     }
  855. }
  856.  
  857. // IDA: void __usercall TheEffectsOfDrugs(tPowerup *pPowerup@<EAX>, tU32 pPeriod@<EDX>)
  858. void TheEffectsOfDrugs(tPowerup* pPowerup, tU32 pPeriod) {
  859.     LOG_TRACE("(%p, %d)", pPowerup, pPeriod);
  860.  
  861.     PaletteFuckedUpByDrugs(gRender_palette, GetTotalTime() / 100);
  862.     ResetPalette();
  863. }
  864.  
  865. // IDA: int __usercall SetOpponentsSpeed@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  866. int SetOpponentsSpeed(tPowerup* pPowerup, tCar_spec* pCar) {
  867.     int i;
  868.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  869.  
  870.     for (i = 0; i < gCurrent_race.number_of_racers && gCurrent_race.opponent_list[i].index != 29; i++) {
  871.     }
  872.     if (i < gCurrent_race.number_of_racers) {
  873.         SetEngineFactor(gPowerup_array + 5, gCurrent_race.opponent_list[i].car_spec);
  874.     }
  875.     gOpponent_speed_factor = pPowerup->float_params[0];
  876.     return GET_POWERUP_INDEX(pPowerup);
  877. }
  878.  
  879. // IDA: int __usercall SetCopsSpeed@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  880. int SetCopsSpeed(tPowerup* pPowerup, tCar_spec* pCar) {
  881.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  882.  
  883.     gCop_speed_factor = pPowerup->float_params[0];
  884.     return GET_POWERUP_INDEX(pPowerup);
  885. }
  886.  
  887. // IDA: int __usercall SetGravity@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  888. int SetGravity(tPowerup* pPowerup, tCar_spec* pCar) {
  889.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  890.  
  891.     gGravity_multiplier = pPowerup->float_params[0];
  892.     return GET_POWERUP_INDEX(pPowerup);
  893. }
  894.  
  895. // IDA: int __usercall SetPinball@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  896. int SetPinball(tPowerup* pPowerup, tCar_spec* pCar) {
  897.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  898.  
  899.     gPinball_factor = pPowerup->float_params[0];
  900.     return GET_POWERUP_INDEX(pPowerup);
  901. }
  902.  
  903. // IDA: int __usercall SetWallclimb@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  904. int SetWallclimb(tPowerup* pPowerup, tCar_spec* pCar) {
  905.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  906.  
  907.     pCar->wall_climber_mode = 1;
  908.     return GET_POWERUP_INDEX(pPowerup);
  909. }
  910.  
  911. // IDA: int __usercall SetBouncey@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  912. int SetBouncey(tPowerup* pPowerup, tCar_spec* pCar) {
  913.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  914.  
  915.     pCar->bounce_rate = 1000.f / pPowerup->float_params[0];
  916.     pCar->bounce_amount = pPowerup->float_params[1];
  917.     pCar->last_bounce = 0;
  918.     return GET_POWERUP_INDEX(pPowerup);
  919. }
  920.  
  921. // IDA: int __usercall SetSuspension@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  922. int SetSuspension(tPowerup* pPowerup, tCar_spec* pCar) {
  923.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  924.  
  925.     SetCarSuspGiveAndHeight(pCar,
  926.         pPowerup->float_params[0], pPowerup->float_params[1], pPowerup->float_params[4],
  927.         pPowerup->float_params[2], pPowerup->float_params[3]);
  928.     return GET_POWERUP_INDEX(pPowerup);
  929. }
  930.  
  931. // IDA: int __usercall SetTyreGrip@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  932. int SetTyreGrip(tPowerup* pPowerup, tCar_spec* pCar) {
  933.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  934.  
  935.     pCar->grip_multiplier = pPowerup->float_params[0];
  936.     return GET_POWERUP_INDEX(pPowerup);
  937. }
  938.  
  939. // IDA: int __usercall SetDamageMultiplier@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  940. int SetDamageMultiplier(tPowerup* pPowerup, tCar_spec* pCar) {
  941.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  942.  
  943.     pCar->damage_multiplier = pPowerup->float_params[0];
  944.     return GET_POWERUP_INDEX(pPowerup);
  945. }
  946.  
  947. // IDA: void __usercall ResetEngineFactor(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  948. void ResetEngineFactor(tPowerup* pPowerup, tCar_spec* pCar) {
  949.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  950.  
  951.     pCar->engine_power_multiplier = 1.f;
  952.     pCar->grip_multiplier = 1.f;
  953.     SetCarSuspGiveAndHeight(pCar, 1.f, 1.f, 1.f, 0.f, 0.f);
  954. }
  955.  
  956. // IDA: void __usercall ResetUnderwater(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  957. void ResetUnderwater(tPowerup* pPowerup, tCar_spec* pCar) {
  958.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  959.  
  960.     pCar->underwater_ability = 0;
  961. }
  962.  
  963. // IDA: void __usercall PukeDrugsBackUp(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  964. void PukeDrugsBackUp(tPowerup* pPowerup, tCar_spec* pCar) {
  965.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  966.  
  967.     if (pCar->driver == eDriver_local_human) {
  968.         gOn_drugs = 0;
  969.         PaletteFuckedUpByDrugs(gRender_palette, 0);
  970.         ResetPalette();
  971.     }
  972. }
  973.  
  974. // IDA: void __usercall ResetOpponentsSpeed(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  975. void ResetOpponentsSpeed(tPowerup* pPowerup, tCar_spec* pCar) {
  976.     int i;
  977.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  978.  
  979.     for (i = 0; i < gCurrent_race.number_of_racers && gCurrent_race.opponent_list[i].index != 29; i++) {
  980.     }
  981.     if (i < gCurrent_race.number_of_racers) {
  982.         ResetEngineFactor(&gPowerup_array[5], gCurrent_race.opponent_list[i].car_spec);
  983.     }
  984.     gOpponent_speed_factor = 1.f;
  985. }
  986.  
  987. // IDA: void __usercall ResetCopsSpeed(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  988. void ResetCopsSpeed(tPowerup* pPowerup, tCar_spec* pCar) {
  989.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  990.  
  991.     gCop_speed_factor = 1.f;
  992. }
  993.  
  994. // IDA: void __usercall ResetGravity(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  995. void ResetGravity(tPowerup* pPowerup, tCar_spec* pCar) {
  996.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  997.  
  998.     gGravity_multiplier = gDefault_gravity;
  999. }
  1000.  
  1001. // IDA: void __usercall ResetPinball(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1002. void ResetPinball(tPowerup* pPowerup, tCar_spec* pCar) {
  1003.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1004.  
  1005.     gPinball_factor = 0.f;
  1006. }
  1007.  
  1008. // IDA: void __usercall ResetWallclimb(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1009. void ResetWallclimb(tPowerup* pPowerup, tCar_spec* pCar) {
  1010.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1011.  
  1012.     pCar->wall_climber_mode = 0;
  1013. }
  1014.  
  1015. // IDA: void __usercall ResetBouncey(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1016. void ResetBouncey(tPowerup* pPowerup, tCar_spec* pCar) {
  1017.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1018.  
  1019.     pCar->bounce_rate = 0.f;
  1020.     pCar->bounce_amount = 0.f;
  1021. }
  1022.  
  1023. // IDA: void __usercall ResetSuspension(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1024. void ResetSuspension(tPowerup* pPowerup, tCar_spec* pCar) {
  1025.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1026.  
  1027.     SetCarSuspGiveAndHeight(pCar, 1.f, 1.f, 1.f, 0.f, 0.f);
  1028. }
  1029.  
  1030. // IDA: void __usercall ResetDamageMultiplier(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1031. void ResetDamageMultiplier(tPowerup* pPowerup, tCar_spec* pCar) {
  1032.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1033.  
  1034.     pCar->damage_multiplier = 1.f;
  1035. }
  1036.  
  1037. // IDA: void __usercall ResetTyreGrip(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1038. void ResetTyreGrip(tPowerup* pPowerup, tCar_spec* pCar) {
  1039.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1040.  
  1041.     pCar->grip_multiplier = 1.f;
  1042.     ;
  1043. }
  1044.  
  1045. // IDA: int __usercall PickAtRandom@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1046. int PickAtRandom(tPowerup* pPowerup, tCar_spec* pCar) {
  1047.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1048.  
  1049.     return GotPowerup(pCar, pPowerup->integer_params[IRandomBetween(0, pPowerup->number_of_integer_params - 1)]);
  1050. }
  1051.  
  1052. // IDA: int __usercall PedestrianRespawn@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1053. int PedestrianRespawn(tPowerup* pPowerup, tCar_spec* pCar) {
  1054.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1055.  
  1056.     RespawnPedestrians();
  1057.     return GET_POWERUP_INDEX(pPowerup);
  1058. }
  1059.  
  1060. // IDA: int __usercall GotVouchers@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1061. int GotVouchers(tPowerup* pPowerup, tCar_spec* pCar) {
  1062.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1063.  
  1064.     if (pCar->driver == eDriver_local_human) {
  1065.         AddVouchers(pPowerup->integer_params[0]);
  1066.     }
  1067.     return GET_POWERUP_INDEX(pPowerup);
  1068. }
  1069.  
  1070. // IDA: void __usercall MungeVouchers(tPowerup *pPowerup@<EAX>, tU32 pPeriod@<EDX>)
  1071. void MungeVouchers(tPowerup* pPowerup, tU32 pPeriod) {
  1072.     LOG_TRACE("(%p, %d)", pPowerup, pPeriod);
  1073.  
  1074.     pPowerup->current_value = GetRecoverVoucherCount();
  1075. }
  1076.  
  1077. // IDA: int __usercall SetInstantHandbrake@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1078. int SetInstantHandbrake(tPowerup* pPowerup, tCar_spec* pCar) {
  1079.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1080.  
  1081.     if (pCar->driver == eDriver_local_human) {
  1082.         gInstant_handbrake = 1;
  1083.     }
  1084.     return GET_POWERUP_INDEX(pPowerup);
  1085. }
  1086.  
  1087. // IDA: void __usercall ResetInstantHandbrake(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1088. void ResetInstantHandbrake(tPowerup* pPowerup, tCar_spec* pCar) {
  1089.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1090.  
  1091.     if (pCar->driver == eDriver_local_human) {
  1092.         gInstant_handbrake = 0;
  1093.     }
  1094. }
  1095.  
  1096. // IDA: void __usercall DoBouncey(tPowerup *pPowerup@<EAX>, tU32 pPeriod@<EDX>)
  1097. void DoBouncey(tPowerup* pPowerup, tU32 pPeriod) {
  1098.     LOG_TRACE("(%p, %d)", pPowerup, pPeriod);
  1099.  
  1100.     if (gProgram_state.current_car.bounce_rate <= GetTotalTime() - gProgram_state.current_car.last_bounce && gProgram_state.current_car.number_of_wheels_on_ground > 2) {
  1101.         PratcamEvent(42);
  1102.         gProgram_state.current_car.last_bounce = GetTotalTime();
  1103.         gProgram_state.current_car.v.v[1] += gProgram_state.current_car.bounce_amount;
  1104.         DRS3StartSound(gCar_outlet, 9010);
  1105.     }
  1106. }
  1107.  
  1108. // IDA: int __usercall HitMine@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1109. int HitMine(tPowerup* pPowerup, tCar_spec* pCar) {
  1110.     int i;
  1111.     float fudge_multiplier;
  1112.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1113.  
  1114.     pCar->v.v[1] = FRandomBetween(pPowerup->float_params[0], pPowerup->float_params[1]) / pCar->M + pCar->v.v[1];
  1115.     pCar->omega.v[2] = FRandomPosNeg(pPowerup->float_params[2]) * TAU / pCar->M + pCar->omega.v[2];
  1116.     pCar->omega.v[0] = FRandomPosNeg(pPowerup->float_params[3]) * TAU / pCar->M + pCar->omega.v[0];
  1117.     if (pCar->driver != eDriver_non_car_unused_slot && !pCar->invulnerable) {
  1118.         fudge_multiplier = pCar->car_model_actors[pCar->principal_car_actor].crush_data.softness_factor / .7f;
  1119.         for (i = 0; i < pCar->car_actor_count; i++) {
  1120.             TotallySpamTheModel(pCar, i, pCar->car_model_actors[i].actor,
  1121.                 &pCar->car_model_actors[i].crush_data, fudge_multiplier * .1f);
  1122.         }
  1123.         for (i = 0; i < 12; i++) {
  1124.             DamageUnit(pCar, i, IRandomBetween(0, fudge_multiplier * 15.f));
  1125.         }
  1126.     }
  1127.     return GET_POWERUP_INDEX(pPowerup);
  1128. }
  1129.  
  1130. // IDA: int __usercall SetMassMultiplier@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1131. int SetMassMultiplier(tPowerup* pPowerup, tCar_spec* pCar) {
  1132.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1133.  
  1134.     pCar->collision_mass_multiplier = pPowerup->float_params[0];
  1135.     return GET_POWERUP_INDEX(pPowerup);
  1136. }
  1137.  
  1138. // IDA: void __usercall ResetMassMultiplier(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1139. void ResetMassMultiplier(tPowerup* pPowerup, tCar_spec* pCar) {
  1140.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1141.  
  1142.     pCar->collision_mass_multiplier = 1.f;
  1143. }
  1144.  
  1145. // IDA: int __usercall ShowPedestrians@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1146. int ShowPedestrians(tPowerup* pPowerup, tCar_spec* pCar) {
  1147.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1148.  
  1149.     if (pCar->driver == eDriver_local_human) {
  1150.         gShow_peds_on_map = 1;
  1151.     }
  1152.     return GET_POWERUP_INDEX(pPowerup);
  1153. }
  1154.  
  1155. // IDA: void __usercall HidePedestrians(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1156. void HidePedestrians(tPowerup* pPowerup, tCar_spec* pCar) {
  1157.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1158.  
  1159.     if (pCar->driver == eDriver_local_human) {
  1160.         gShow_peds_on_map = 0;
  1161.     }
  1162. }
  1163.  
  1164. // IDA: int __usercall SetProximity@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1165. int SetProximity(tPowerup* pPowerup, tCar_spec* pCar) {
  1166.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1167.  
  1168.     pCar->proxy_ray_distance = pPowerup->float_params[0] * pPowerup->float_params[0];
  1169.     return GET_POWERUP_INDEX(pPowerup);
  1170. }
  1171.  
  1172. // IDA: void __usercall ResetProximity(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1173. void ResetProximity(tPowerup* pPowerup, tCar_spec* pCar) {
  1174.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1175.  
  1176.     pCar->proxy_ray_distance = 0.f;
  1177. }
  1178.  
  1179. // IDA: int __usercall SetPedHarvest@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1180. int SetPedHarvest(tPowerup* pPowerup, tCar_spec* pCar) {
  1181.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1182.  
  1183.     gPedestrian_harvest = 1;
  1184.     return GET_POWERUP_INDEX(pPowerup);
  1185. }
  1186.  
  1187. // IDA: void __usercall ResetPedHarvest(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1188. void ResetPedHarvest(tPowerup* pPowerup, tCar_spec* pCar) {
  1189.     int i;
  1190.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1191.  
  1192.     gPedestrian_harvest = 0;
  1193.     for (i = 0; i < COUNT_OF(gPed_harvest_sounds); i++) {
  1194.         DRS3StartSound3D(gPedestrians_outlet, gPed_harvest_sounds[i], &pCar->pos,
  1195.             &gZero_v__powerup, 1, 255, -1, -1);
  1196.     }
  1197. }
  1198.  
  1199. // IDA: int __usercall SetVesuvianCorpses@<EAX>(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1200. int SetVesuvianCorpses(tPowerup* pPowerup, tCar_spec* pCar) {
  1201.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1202.  
  1203.     gVesuvian_corpses = 1;
  1204.     return GET_POWERUP_INDEX(pPowerup);
  1205. }
  1206.  
  1207. // IDA: void __usercall ResetVesuvianCorpses(tPowerup *pPowerup@<EAX>, tCar_spec *pCar@<EDX>)
  1208. void ResetVesuvianCorpses(tPowerup* pPowerup, tCar_spec* pCar) {
  1209.     LOG_TRACE("(%p, %p)", pPowerup, pCar);
  1210.  
  1211.     gVesuvian_corpses = 0;
  1212. }
  1213.  
  1214. // IDA: void __usercall ReceivedPowerup(tNet_contents *pContents@<EAX>)
  1215. void ReceivedPowerup(tNet_contents* pContents) {
  1216.     tPowerup* powerup;
  1217.     tCar_spec* car;
  1218.     LOG_TRACE("(%p)", pContents);
  1219.  
  1220.     if (gProgram_state.racing && pContents->data.powerup.powerup_index >= 0 && pContents->data.powerup.powerup_index < gNumber_of_powerups) {
  1221.         powerup = &gPowerup_array[pContents->data.powerup.powerup_index];
  1222.         if (pContents->data.powerup.event == ePowerup_gained || pContents->data.powerup.event == ePowerup_ongoing) {
  1223.             if (powerup->net_type == eNet_powerup_global) {
  1224.                 GotPowerupX(&gProgram_state.current_car, pContents->data.powerup.powerup_index, 0,
  1225.                     pContents->data.powerup.event == ePowerup_gained, pContents->data.powerup.time_left);
  1226.             } else if (powerup->net_type == eNet_powerup_local && pContents->data.powerup.player != gLocal_net_ID && powerup->got_proc != NULL) {
  1227.                 car = NetCarFromPlayerID(pContents->data.powerup.player);
  1228.                 if (car != NULL) {
  1229.                     powerup->got_proc(powerup, car);
  1230.                     switch (powerup->type) {
  1231.                     case ePowerup_timed:
  1232.                         car->powerups[pContents->data.powerup.powerup_index] = GetTotalTime() + pContents->data.powerup.time_left;
  1233.                         break;
  1234.                     case ePowerup_whole_race:
  1235.                         car->powerups[pContents->data.powerup.powerup_index] = -1;
  1236.                         break;
  1237.                     default:
  1238.                         break;
  1239.                     }
  1240.                 }
  1241.             }
  1242.         } else if (powerup->net_type == eNet_powerup_local && powerup->lose_proc != NULL) {
  1243.             car = NetCarFromPlayerID(pContents->data.powerup.player);
  1244.             if (car != NULL) {
  1245.                 powerup->lose_proc(powerup, car);
  1246.                 car->powerups[pContents->data.powerup.powerup_index] = 0;
  1247.             }
  1248.         }
  1249.     }
  1250. }
  1251.  
  1252. // IDA: void __cdecl SendCurrentPowerups()
  1253. void SendCurrentPowerups(void) {
  1254.     int i;
  1255.     int cat;
  1256.     int j;
  1257.     int car_count;
  1258.     tCar_spec* car;
  1259.     tNet_contents* the_contents;
  1260.     tPlayer_ID ID;
  1261.     LOG_TRACE("()");
  1262.  
  1263.     for (cat = eVehicle_self; cat < eVehicle_net_player; cat++) {
  1264.         if (cat == eVehicle_self) {
  1265.             car_count = 1;
  1266.         } else {
  1267.             car_count = GetCarCount(cat);
  1268.         }
  1269.         for (i = 0; i < car_count; i++) {
  1270.             if (cat == eVehicle_self) {
  1271.                 car = &gProgram_state.current_car;
  1272.             } else {
  1273.                 car = GetCarSpec(cat, i);
  1274.             }
  1275. #if defined(DETHRACE_FIX_BUGS)
  1276.             ID = gNet_players[0].ID;
  1277. #endif
  1278.             for (j = 0; j < gNumber_of_net_players; j++) {
  1279.                 if (gNet_players[j].car == car) {
  1280.                     ID = gNet_players[j].ID;
  1281.                     break;
  1282.                 }
  1283.             }
  1284.             for (j = 0; j < gNumber_of_powerups; j++) {
  1285.                 if (car->powerups[j] != 0) {
  1286.                     the_contents = NetGetBroadcastContents(21, 0);
  1287.                     the_contents->data.powerup.event = ePowerup_ongoing;
  1288.                     the_contents->data.powerup.player = ID;
  1289.                     the_contents->data.powerup.powerup_index = j;
  1290.                     the_contents->data.powerup.time_left = car->powerups[i] - GetTotalTime();
  1291.                 }
  1292.             }
  1293.         }
  1294.     }
  1295. }
  1296.  
  1297. // IDA: void __usercall LoseAllLocalPowerups(tCar_spec *pCar@<EAX>)
  1298. void LoseAllLocalPowerups(tCar_spec* pCar) {
  1299.     int i;
  1300.     LOG_TRACE("(%p)", pCar);
  1301.  
  1302.     if (pCar->driver == eDriver_local_human) {
  1303.         for (i = 0; i < gNumber_of_powerups; i++) {
  1304.             if (pCar->powerups[i] != 0 && gPowerup_array[i].net_type == eNet_powerup_local) {
  1305.                 LosePowerup(&gPowerup_array[i]);
  1306.             }
  1307.         }
  1308.     }
  1309. }
  1310.  
  1311. // Added by dethrace
  1312. void GetPowerupMessage(int pN, char* pMessage) {
  1313.     switch (pN) {
  1314.     case 0:
  1315.         strcpy(pMessage, "Bonus");
  1316.         break;
  1317.     case 1:
  1318.         strcpy(pMessage, "Mega Bonus");
  1319.         break;
  1320.     case 14:
  1321.     case 46:
  1322.         strcpy(pMessage, "Mine");
  1323.         break;
  1324.     case 28:
  1325.     case 29:
  1326.     case 30:
  1327.     case 31:
  1328.         strcpy(pMessage, "Random");
  1329.         break;
  1330.     default:
  1331.         strcpy(pMessage, gPowerup_array[pN].message);
  1332.         break;
  1333.     }
  1334. }
  1335.