#include "racestrt.h"
#include "brender/brender.h"
#include "cutscene.h"
#include "displays.h"
#include "drmem.h"
#include "errors.h"
#include "flicplay.h"
#include "globvars.h"
#include "globvrpb.h"
#include "grafdata.h"
#include "graphics.h"
#include "harness/config.h"
#include "harness/trace.h"
#include "input.h"
#include "intrface.h"
#include "loading.h"
#include "netgame.h"
#include "network.h"
#include "newgame.h"
#include "opponent.h"
#include "pd/sys.h"
#include "racestrt.h"
#include "sound.h"
#include "structur.h"
#include "utility.h"
#include "world.h"
#include <stdlib.h>
int gGrid_number_colour[4] = { 49u, 201u, 1u, 201u };
int gJust_bought_part;
tU32 gLast_host_query;
br_pixelmap* gDead_car;
int gFade_away_parts_shop;
tU32 gDare_start_time;
int gRefund_rate;
int gSwap_grid_2;
int gSwap_grid_1;
int gChange_race_net_mode;
tParts_category gPart_category;
tU32 gNet_synch_start;
tNet_game_details* gChoose_car_net_game;
int gPart_index;
int gChallenger_index__racestrt; // suffix added to avoid duplicate symbol
tGrid_draw gDraw_grid_status;
tNet_sequence_type gNet_race_sequence__racestrt; // suffix added to avoid duplicate symbol
br_pixelmap* gTaken_image;
int gGrid_number_x_coords[31];
int gGrid_transition_stage;
int gGrid_y_adjust;
br_pixelmap* gBullet_image;
br_pixelmap* gDeceased_image;
int gBest_pos_available;
int gChallenger_position;
int gOpponent_index;
int gChallenge_time;
int gOriginal_position;
int gCurrent_race_index;
tInterface_spec* gStart_interface_spec;
int gCurrent_car_index;
int gOur_starting_position;
// IDA: void __usercall DrawRaceList(int pOffset@<EAX>)
void DrawRaceList(int pOffset) {
int i;
//int font_height; // Pierre-Marie Baty -- unused variable
int pitch;
int y;
int left_most;
int right_most;
int rank_colour;
int text_colour;
//int box_bot; // Pierre-Marie Baty -- unused variable
//int text_width; // Pierre-Marie Baty -- unused variable
int text_x;
char rank_str[256];
LOG_TRACE("(%d)", pOffset);
left_most = (gCurrent_graf_data->choose_race_rank_right - 2 * gBig_font->width[48] + gCurrent_graf_data->choose_race_left) / 2;
right_most = gCurrent_graf_data->choose_race_right - (left_most - gCurrent_graf_data->choose_race_left);
BrPixelmapRectangleFill(gBack_screen,
left_most,
gCurrent_graf_data->choose_race_y_top,
gCurrent_graf_data->choose_race_right - gCurrent_graf_data->choose_race_left - 2 * (left_most - gCurrent_graf_data->choose_race_left),
gCurrent_graf_data->choose_race_y_bottom - gCurrent_graf_data->choose_race_y_top,
0);
pitch = gCurrent_graf_data->choose_race_y_pitch;
for (i = 0; i < gNumber_of_races; i++) {
y = pitch * i + gCurrent_graf_data->choose_race_curr_y - pOffset;
if (gCurrent_graf_data->choose_race_y_top <= (y - (TranslationMode() ? 2 : 0)) && (y + gBig_font->glyph_y) < gCurrent_graf_data->choose_race_line_y) {
if ((gProgram_state.rank > gRace_list[i].rank_required || gProgram_state.rank < gRace_list[i].best_rank) && !gProgram_state.game_completed && !gChange_race_net_mode) {
rank_colour = 44;
text_colour = 49;
} else if (gCurrent_graf_data->choose_race_curr_y == y) {
rank_colour = 5;
text_colour = 1;
} else {
rank_colour = 198;
text_colour = 201;
}
if (!gChange_race_net_mode) {
sprintf(rank_str
, "%2d", gRace_list
[i
].
rank_required);
TransBrPixelmapText(gBack_screen,
gCurrent_graf_data->choose_race_rank_right - BrPixelmapTextWidth(gBack_screen, gBig_font, rank_str),
y,
rank_colour,
gBig_font,
rank_str);
}
TransBrPixelmapText(gBack_screen,
gCurrent_graf_data->choose_race_name_left,
y,
text_colour,
gBig_font,
gRace_list[i].name);
if (gRace_list[i].been_there_done_that && gBullet_image != NULL) {
BrPixelmapRectangleCopy(gBack_screen,
gCurrent_graf_data->choose_race_bullet_left,
y + (gBig_font->glyph_y - gBullet_image->height) / 2,
gBullet_image,
0,
0,
gBullet_image->width,
gBullet_image->height);
}
}
}
if (gChange_race_net_mode) {
strcpy(rank_str
, GetMiscString
(gNet_race_sequence__racestrt
== 1 ? kMiscString_SUBSEQUENT_RACES_WILL_BE_RANDOM
: kMiscString_RACES_WILL_CONTINUE_DOWN_THIS_LIST
));
TransBrPixelmapText(gBack_screen,
(right_most + left_most - BrPixelmapTextWidth(gBack_screen, gBig_font, rank_str)) / 2,
gCurrent_graf_data->choose_race_current_text_y,
5,
gBig_font,
rank_str);
} else {
sprintf(rank_str
, "%s%d", GetMiscString
(kMiscString_YourCurrentRankIs
), gProgram_state.
rank);
text_x = (gCurrent_graf_data->choose_race_left + gCurrent_graf_data->choose_race_right) / 2 - BrPixelmapTextWidth(gBack_screen, gBig_font, rank_str) / 2;
TransBrPixelmapText(gBack_screen,
text_x,
gCurrent_graf_data->choose_race_current_text_y,
3,
gBig_font,
GetMiscString(kMiscString_YourCurrentRankIs));
sprintf(rank_str
, "%d", gProgram_state.
rank);
TransBrPixelmapText(gBack_screen,
text_x + BrPixelmapTextWidth(gBack_screen, gBig_font, GetMiscString(kMiscString_YourCurrentRankIs)),
gCurrent_graf_data->choose_race_current_text_y,
5,
gBig_font,
rank_str);
}
BrPixelmapLine(gBack_screen,
left_most,
gCurrent_graf_data->choose_race_line_y,
right_most,
gCurrent_graf_data->choose_race_line_y,
6);
DrawRectangle(gBack_screen,
left_most,
gCurrent_graf_data->choose_race_box_top - 1,
right_most,
2 * gCurrent_graf_data->choose_race_curr_y - gCurrent_graf_data->choose_race_box_top + gBig_font->glyph_y,
3);
PDScreenBufferSwap(0);
}
// IDA: void __usercall MoveRaceList(int pFrom@<EAX>, int pTo@<EDX>, tS32 pTime_to_move@<EBX>)
void MoveRaceList(int pFrom, int pTo, tS32 pTime_to_move) {
tS32 start_time;
tS32 the_time;
//int move_distance; // Pierre-Marie Baty -- unused variable
int pitch;
LOG_TRACE("(%d, %d, %d)", pFrom, pTo, pTime_to_move);
pitch = gCurrent_graf_data->choose_race_y_pitch;
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime();
if (start_time + pTime_to_move <= the_time)
break;
DrawRaceList((the_time - start_time) * (pTo - pFrom) * pitch / pTime_to_move + pitch * pFrom);
}
DrawRaceList(pitch * pTo);
}
// IDA: int __usercall UpRace@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int UpRace(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
AddToFlicQueue(gStart_interface_spec->pushed_flics[2].flic_index,
gStart_interface_spec->pushed_flics[2].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[2].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
if (gCurrent_race_index != 0 && (gRace_list[gCurrent_race_index - 1].best_rank <= gProgram_state.rank || gProgram_state.game_completed || gChange_race_net_mode)) {
RemoveTransientBitmaps(1);
MoveRaceList(gCurrent_race_index, gCurrent_race_index - 1, 150);
gCurrent_race_index--;
}
return 0;
}
// IDA: int __usercall DownRace@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int DownRace(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
AddToFlicQueue(gStart_interface_spec->pushed_flics[3].flic_index,
gStart_interface_spec->pushed_flics[3].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[3].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
if (gCurrent_race_index < gNumber_of_races - 1 && (gProgram_state.rank <= gRace_list[gCurrent_race_index + 1].rank_required || gProgram_state.game_completed || gChange_race_net_mode)) {
RemoveTransientBitmaps(1);
MoveRaceList(gCurrent_race_index, gCurrent_race_index + 1, 150);
gCurrent_race_index++;
}
return 0;
}
// IDA: int __usercall ClickOnRace@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int ClickOnRace(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
int x_coord;
int y_coord;
int race_delta;
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
GetMousePosition(&x_coord, &y_coord);
race_delta = (y_coord - (gCurrent_graf_data->choose_race_curr_y - 5 * (gCurrent_graf_data->choose_race_y_pitch / 2) + gBig_font->glyph_y / 2)) / gCurrent_graf_data->choose_race_y_pitch - 2;
if (race_delta >= -2 && race_delta <= -1) {
do {
UpRace(pCurrent_choice, pCurrent_mode);
race_delta++;
} while (race_delta != 0);
} else if (race_delta > 0 && race_delta < 3) {
do {
DownRace(pCurrent_choice, pCurrent_mode);
race_delta--;
} while (race_delta != 0);
}
return 0;
}
// IDA: int __usercall UpClickRace@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int UpClickRace(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
UpRace(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall DownClickRace@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int DownClickRace(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
DownRace(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: void __cdecl StartChangeRace()
void StartChangeRace(void) {
LOG_TRACE("()");
MoveRaceList(-3, gCurrent_race_index, 400);
}
// IDA: int __usercall ChangeRace@<EAX>(int *pRace_index@<EAX>, int pNet_mode@<EDX>, tNet_sequence_type pNet_race_sequence@<EBX>)
int ChangeRace(int* pRace_index, int pNet_mode, tNet_sequence_type pNet_race_sequence) {
static tFlicette flicker_on[4] = {
{ 43, { 60, 120 }, { 154, 370 } },
{ 43, { 221, 442 }, { 154, 370 } },
{ 221, { 30, 60 }, { 78, 187 } },
{ 221, { 30, 60 }, { 78, 187 } },
};
static tFlicette flicker_off[4] = {
{ 42, { 60, 120 }, { 154, 370 } },
{ 42, { 221, 442 }, { 154, 370 } },
{ 220, { 30, 60 }, { 78, 187 } },
{ 220, { 30, 60 }, { 78, 187 } },
};
static tFlicette push[4] = {
{ 154, { 60, 120 }, { 154, 370 } },
{ 45, { 221, 442 }, { 154, 370 } },
{ 222, { 30, 60 }, { 78, 187 } },
{ 225, { 30, 60 }, { 118, 283 } },
};
static tMouse_area mouse_areas[5] = {
{ { 60, 120 }, { 154, 370 }, { 125, 250 }, { 174, 418 }, 0, 0, 0, NULL },
{ { 221, 442 }, { 154, 370 }, { 286, 572 }, { 174, 418 }, 1, 0, 0, NULL },
{ { 30, 60 }, { 78, 187 }, { 45, 90 }, { 104, 250 }, -1, 0, 0, UpClickRace },
{ { 30, 60 }, { 118, 283 }, { 45, 90 }, { 145, 348 }, -1, 0, 0, DownClickRace },
{ { 66, 132 }, { 33, 79 }, { 278, 556 }, { 144, 346 }, -1, 0, 0, ClickOnRace },
};
static tInterface_spec interface_spec = {
0, 230, 60, 231, 231, 231, 6,
{ -1, 0 }, { -1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { UpRace, NULL },
{ -1, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { DownRace, NULL },
{ 1, 1 }, { NULL, NULL }, { 1, 1 }, { NULL, NULL },
NULL, NULL, 0, NULL, StartChangeRace, NULL, 0, { 0, 0 },
NULL, 1, 1, COUNT_OF(flicker_on), flicker_on, flicker_off, push,
COUNT_OF(mouse_areas), mouse_areas, 0, NULL
};
int result;
LOG_TRACE("(%p, %d, %d)", pRace_index, pNet_mode, pNet_race_sequence);
gNet_race_sequence__racestrt = pNet_race_sequence;
gChange_race_net_mode = pNet_mode;
gStart_interface_spec = &interface_spec;
gCurrent_race_index = *pRace_index;
if (pNet_mode == 0) {
gBullet_image = LoadPixelmap("BULLET.PIX");
} else {
gBullet_image = NULL;
}
result = DoInterfaceScreen(&interface_spec, pNet_mode != 0, 0);
if (result == 0) {
*pRace_index = gCurrent_race_index;
}
if (gBullet_image != NULL) {
BrPixelmapFree(gBullet_image);
}
return result == 0;
}
// IDA: void __cdecl DoChangeRace()
void DoChangeRace(void) {
LOG_TRACE("()");
if (ChangeRace(&gProgram_state.current_race_index, 0, eNet_sequence_sequential) != 0) {
gProgram_state.current_race_index = gCurrent_race_index;
}
}
// IDA: void __usercall DrawCar(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
void DrawCar(int pCurrent_choice, int pCurrent_mode) {
char s[64];
int text_x;
int text_width;
LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
// Added by dethrace to ignore warnings about using sprintf without a literal format string
#ifndef _MSC_VER // Pierre-Marie Baty -- exclude MSVC
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-security"
#endif // !_MSC_VER
PollCarDetails(gChoose_car_net_game);
if (gChange_race_net_mode == 0) {
if (gProgram_state.number_of_cars == 1) {
sprintf(s
, GetMiscString
(kMiscString_NoOtherCarsToChooseFromYet
));
} else if (gProgram_state.cars_available[gCurrent_car_index] == gProgram_state.frank_or_anniness) {
sprintf(s
, GetMiscString
(kMiscString_YourOriginalCar
));
} else {
sprintf(s
, "%s %s", GetMiscString
(kMiscString_OriginalDriverWas
), gOpponents
[gProgram_state.
cars_available[gCurrent_car_index
]].
name);
}
} else if (gCar_details[gProgram_state.cars_available[gCurrent_car_index]].ownership == eCar_owner_someone) {
sprintf(s
, "%s %s", GetMiscString
(kMiscString_THIS_CAR_ALREADY_TAKEN_BY
), gCar_details
[gProgram_state.
cars_available[gCurrent_car_index
]].
name);
} else {
sprintf(s
, GetMiscString
(kMiscString_AVAILABLE
));
}
#ifndef _MSC_VER // Pierre-Marie Baty -- exclude MSVC
#pragma GCC diagnostic pop
#endif // !_MSC_VER
text_width = BrPixelmapTextWidth(gBack_screen, gFont_7, s);
text_x = (gCurrent_graf_data->change_car_line_right + gCurrent_graf_data->change_car_line_left - text_width) / 2;
BrPixelmapRectangleFill(gBack_screen,
gCurrent_graf_data->change_car_line_left,
gCurrent_graf_data->change_car_text_y,
gCurrent_graf_data->change_car_line_right - gCurrent_graf_data->change_car_line_left,
gFont_7->glyph_y,
0);
TransBrPixelmapText(gBack_screen,
text_x,
gCurrent_graf_data->change_car_text_y,
3,
gFont_7,
s);
BrPixelmapLine(gBack_screen,
gCurrent_graf_data->change_car_line_left,
gCurrent_graf_data->change_car_line_y,
gCurrent_graf_data->change_car_line_right,
gCurrent_graf_data->change_car_line_y,
6);
if (gChange_race_net_mode && gCar_details[gProgram_state.cars_available[gCurrent_car_index]].ownership == eCar_owner_someone) {
DRPixelmapRectangleMaskedCopy(
gBack_screen,
(gCurrent_graf_data->change_car_panel_left + gCurrent_graf_data->change_car_panel_right - gTaken_image->width) / 2,
(gCurrent_graf_data->change_car_panel_bottom + gCurrent_graf_data->change_car_panel_bottom - gTaken_image->height) / 2,
gTaken_image,
0,
0,
gTaken_image->width,
gTaken_image->height);
}
}
// IDA: void __cdecl SetCarFlic()
void SetCarFlic(void) {
LOG_TRACE("()");
ChangePanelFlic(0,
gOpponents[gProgram_state.cars_available[gCurrent_car_index]].stolen_car_image_data,
gOpponents[gProgram_state.cars_available[gCurrent_car_index]].stolen_car_image_data_length);
}
// IDA: int __usercall UpCar@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int UpCar(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
AddToFlicQueue(gStart_interface_spec->pushed_flics[2].flic_index,
gStart_interface_spec->pushed_flics[2].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[2].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
if (gCurrent_car_index != 0) {
RemoveTransientBitmaps(1);
DropOutImageThruBottom(GetPanelPixelmap(0),
gCurrent_graf_data->change_car_panel_left,
gCurrent_graf_data->change_car_panel_top,
gCurrent_graf_data->change_car_panel_top_clip,
gCurrent_graf_data->change_car_panel_bottom_clip);
gCurrent_car_index--;
SetCarFlic();
DropInImageFromTop(GetPanelPixelmap(0),
gCurrent_graf_data->change_car_panel_left,
gCurrent_graf_data->change_car_panel_top,
gCurrent_graf_data->change_car_panel_top_clip,
gCurrent_graf_data->change_car_panel_bottom_clip);
}
return 0;
}
// IDA: int __usercall DownCar@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int DownCar(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
AddToFlicQueue(gStart_interface_spec->pushed_flics[3].flic_index,
gStart_interface_spec->pushed_flics[3].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[3].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
if (gCurrent_car_index < gProgram_state.number_of_cars - 1) {
RemoveTransientBitmaps(1);
DropOutImageThruTop(GetPanelPixelmap(0),
gCurrent_graf_data->change_car_panel_left,
gCurrent_graf_data->change_car_panel_top,
gCurrent_graf_data->change_car_panel_top_clip,
gCurrent_graf_data->change_car_panel_bottom_clip);
gCurrent_car_index++;
SetCarFlic();
DropInImageFromBottom(GetPanelPixelmap(0),
gCurrent_graf_data->change_car_panel_left,
gCurrent_graf_data->change_car_panel_top,
gCurrent_graf_data->change_car_panel_top_clip,
gCurrent_graf_data->change_car_panel_bottom_clip);
}
return 0;
}
// IDA: int __usercall UpClickCar@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int UpClickCar(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
UpCar(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall DownClickCar@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int DownClickCar(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
DownCar(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall ChangeCarGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int ChangeCarGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (gChange_race_net_mode == 0 || gCar_details[gProgram_state.cars_available[gCurrent_car_index]].ownership != eCar_owner_someone) {
return 1;
} else {
DRS3StartSound(gEffects_outlet, 3100);
return 0;
}
}
// IDA: int __usercall ChangeCar@<EAX>(int pNet_mode@<EAX>, int *pCar_index@<EDX>, tNet_game_details *pNet_game@<EBX>)
int ChangeCar(int pNet_mode, int* pCar_index, tNet_game_details* pNet_game) {
static tFlicette flicker_on[4] = {
{ 43, { 60, 120 }, { 154, 370 } },
{ 43, { 221, 442 }, { 154, 370 } },
{ 221, { 30, 60 }, { 78, 187 } },
{ 221, { 30, 60 }, { 78, 187 } },
};
static tFlicette flicker_off[4] = {
{ 42, { 60, 120 }, { 154, 370 } },
{ 42, { 221, 442 }, { 154, 370 } },
{ 220, { 30, 60 }, { 78, 187 } },
{ 220, { 30, 60 }, { 78, 187 } },
};
static tFlicette push[4] = {
{ 154, { 60, 120 }, { 154, 370 } },
{ 45, { 221, 442 }, { 154, 370 } },
{ 222, { 30, 60 }, { 78, 187 } },
{ 225, { 30, 60 }, { 118, 283 } },
};
static tMouse_area mouse_areas[4] = {
{ { 60, 120 }, { 154, 370 }, { 125, 250 }, { 174, 418 }, 0, 0, 0, NULL },
{ { 221, 442 }, { 154, 370 }, { 286, 572 }, { 174, 418 }, 1, 0, 0, NULL },
{ { 30, 60 }, { 78, 187 }, { 45, 90 }, { 104, 250 }, -1, 0, 0, UpClickCar },
{ { 30, 60 }, { 118, 283 }, { 45, 90 }, { 145, 348 }, -1, 0, 0, DownClickCar },
};
static tInterface_spec interface_spec = {
0,
236,
62,
0,
0,
0,
-1,
{ -1, 0 },
{ -1, 0 },
{ 0, 0 },
{ 1, 0 },
{ NULL, NULL },
{ -1, 0 },
{ 1, 0 },
{ 0, 0 },
{ 1, 0 },
{ NULL, NULL },
{ -1, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ UpCar, NULL },
{ -1, 0 },
{ 0, 0 },
{ 0, 0 },
{ 0, 0 },
{ DownCar, NULL },
{ 1, 1 },
{ ChangeCarGoAhead, NULL },
{ 1, 1 },
{ NULL, NULL },
NULL,
DrawCar,
0,
NULL,
NULL,
NULL,
0,
{ 0, 0 },
NULL,
1,
1,
COUNT_OF(flicker_on),
flicker_on,
flicker_off,
push,
COUNT_OF(mouse_areas),
mouse_areas,
0,
NULL,
};
int i;
int result;
int power_up_levels[3];
LOG_TRACE("(%d, %p, %p)", pNet_mode, pCar_index, pNet_game);
gChoose_car_net_game = pNet_game;
gChange_race_net_mode = pNet_mode;
gStart_interface_spec = &interface_spec;
for (i = 0; i < gProgram_state.number_of_cars; i++) {
if (gProgram_state.cars_available[i] == *pCar_index) {
gCurrent_car_index = i;
break;
}
}
if (gProgram_state.game_completed) {
gProgram_state.number_of_cars = gNumber_of_racers;
for (i = 0; i < gProgram_state.number_of_cars; i++) {
gProgram_state.cars_available[i] = i;
}
}
for (i = 0; i < gProgram_state.number_of_cars; i++) {
if (gOpponents[gProgram_state.cars_available[i]].stolen_car_image_data == NULL) {
LoadFlicData(gOpponents[gProgram_state.cars_available[i]].stolen_car_flic_name,
&gOpponents[gProgram_state.cars_available[i]].stolen_car_image_data,
&gOpponents[gProgram_state.cars_available[i]].stolen_car_image_data_length);
} else {
MAMSLock((void**)&gOpponents[gProgram_state.cars_available[i]].stolen_car_image_data);
}
}
InitialiseFlicPanel(0,
gCurrent_graf_data->change_car_panel_left,
gCurrent_graf_data->change_car_panel_top,
gCurrent_graf_data->change_car_panel_right - gCurrent_graf_data->change_car_panel_left,
gCurrent_graf_data->change_car_panel_bottom - gCurrent_graf_data->change_car_panel_top);
SetCarFlic();
if (pNet_mode) {
gTaken_image = LoadPixelmap("TAKEN.PIX");
}
result = DoInterfaceScreen(&interface_spec, pNet_mode, 0);
if (pNet_mode) {
FadePaletteDown();
} else {
RunFlic(237);
}
for (i = 0; i < gProgram_state.number_of_cars; i++) {
MAMSUnlock((void**)&gOpponents[gProgram_state.cars_available[i]].stolen_car_image_data);
}
DisposeFlicPanel(0);
if (pNet_mode) {
BrPixelmapFree(gTaken_image);
}
if (result == 0) {
if (pNet_mode) {
*pCar_index = gProgram_state.cars_available[gCurrent_race_index];
} else {
AboutToLoadFirstCar();
SwitchToRealResolution();
for (i = 0; i < COUNT_OF(power_up_levels); i++) {
power_up_levels[i] = gProgram_state.current_car.power_up_levels[i];
}
LoadCar(gOpponents[gProgram_state.cars_available[gCurrent_car_index]].car_file_name,
eDriver_local_human,
&gProgram_state.current_car,
gProgram_state.cars_available[gCurrent_car_index],
gProgram_state.player_name[gProgram_state.frank_or_anniness],
&gOur_car_storage_space);
for (i = 0; i < COUNT_OF(power_up_levels); i++) {
gProgram_state.current_car.power_up_levels[i] = power_up_levels[i];
}
SwitchToLoresMode();
SetCarStorageTexturingLevel(&gOur_car_storage_space, GetCarTexturingLevel(), eCTL_full);
DisposeRaceInfo(&gCurrent_race);
SelectOpponents(&gCurrent_race);
LoadRaceInfo(gProgram_state.current_race_index, &gCurrent_race);
}
return 1;
} else {
return 0;
}
}
// IDA: void __cdecl DoChangeCar()
void DoChangeCar(void) {
LOG_TRACE("()");
ChangeCar(0, &gProgram_state.current_car.index, NULL);
}
// IDA: int __cdecl PartsShopRecommended()
int PartsShopRecommended(void) {
int running_cost;
int i;
int current_index;
int counter;
LOG_TRACE("()");
running_cost = 0;
counter = 0;
for (i = 0; i < eParts_count; i++) {
current_index = gProgram_state.current_car.power_up_levels[i];
if (current_index + 1 < gProgram_state.current_car.power_ups[i].number_of_parts && (gProgram_state.rank <= gProgram_state.current_car.power_ups[i].info[current_index + 1].rank_required || gProgram_state.game_completed)) {
running_cost += gProgram_state.current_car.power_ups[i].info[current_index + 1].prices[gProgram_state.skill_level];
counter++;
}
}
return running_cost != 0 && ((float)running_cost / counter * 1.5f <= gProgram_state.credits);
}
// IDA: void __usercall CalcPartPrice(int pCategory@<EAX>, int pIndex@<EDX>, int *pPrice@<EBX>, int *pCost@<ECX>)
void CalcPartPrice(int pCategory, int pIndex, int* pPrice, int* pCost) {
//int current_value; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d, %d, %p, %p)", pCategory, pIndex, pPrice, pCost);
*pPrice = gProgram_state.current_car.power_ups[pCategory].info[pIndex].prices[gProgram_state.skill_level];
if (gProgram_state.current_car.power_up_levels[pCategory] == pIndex) {
*pCost = 0;
} else {
*pCost = *pPrice - 10 * (gRefund_rate * gProgram_state.current_car.power_ups[pCategory].info[gProgram_state.current_car.power_up_levels[pCategory]].prices[gProgram_state.skill_level] / 1000);
}
}
// IDA: int __usercall BuyPart@<EAX>(int pCategory@<EAX>, int pIndex@<EDX>)
int BuyPart(int pCategory, int pIndex) {
int price;
int cost;
LOG_TRACE("(%d, %d)", pCategory, pIndex);
CalcPartPrice(pCategory, pIndex, &price, &cost);
if (cost == 0) {
return 1;
} else if (gProgram_state.credits < cost) {
return 0;
} else {
gProgram_state.credits -= cost;
if (gProgram_state.credits > 999999) {
gProgram_state.credits = 999999;
}
gProgram_state.current_car.power_up_levels[pCategory] = pIndex;
return 1;
}
}
// IDA: void __cdecl DoAutoParts()
void DoAutoParts(void) {
int i;
int lowest_yet;
int lowest_one;
int price;
int cost;
int current_level;
LOG_TRACE("()");
while (1) {
if (!PartsShopRecommended()) {
return;
}
lowest_yet = COUNT_OF(((tParts_spec*)NULL)->info);
for (i = 0; i < eParts_count; i++) {
current_level = gProgram_state.current_car.power_up_levels[i];
if (current_level + 1 < gProgram_state.current_car.power_ups[i].number_of_parts && (gProgram_state.rank <= gProgram_state.current_car.power_ups[i].info[current_level + 1].rank_required || gProgram_state.game_completed)) {
CalcPartPrice(i, current_level + 1, &price, &cost);
if (cost != 0 && cost <= gProgram_state.credits && current_level < lowest_yet) {
lowest_one = i;
lowest_yet = current_level + 1;
}
}
}
if (lowest_yet == COUNT_OF(((tParts_spec*)NULL)->info)) {
break;
}
if (!BuyPart(lowest_one, lowest_yet)) {
return;
}
}
}
// IDA: void __cdecl DrawPartsLabel()
void DrawPartsLabel(void) {
LOG_TRACE("()");
switch (gPart_category) {
case eParts_armour:
RunFlicAt(262, gCurrent_graf_data->parts_label_x, gCurrent_graf_data->parts_label_y);
break;
case eParts_power:
RunFlicAt(263, gCurrent_graf_data->parts_label_x, gCurrent_graf_data->parts_label_y);
break;
case eParts_offensive:
RunFlicAt(264, gCurrent_graf_data->parts_label_x, gCurrent_graf_data->parts_label_y);
break;
default:
break;
}
}
// IDA: void __usercall ErasePartsText(int pTotal_as_well@<EAX>)
void ErasePartsText(int pTotal_as_well) {
LOG_TRACE("(%d)", pTotal_as_well);
BrPixelmapRectangleFill(gBack_screen,
gCurrent_graf_data->parts_cost_x,
gCurrent_graf_data->parts_cost_y,
gCurrent_graf_data->parts_image_width - (gCurrent_graf_data->parts_cost_x - gCurrent_graf_data->parts_image_x),
gFont_7->glyph_y + gCurrent_graf_data->parts_net_y - gCurrent_graf_data->parts_cost_y,
0);
if (pTotal_as_well) {
BrPixelmapRectangleFill(gBack_screen,
gCurrent_graf_data->parts_total_x,
gCurrent_graf_data->parts_total_y,
gCurrent_graf_data->parts_image_width - (gCurrent_graf_data->parts_total_x - gCurrent_graf_data->parts_image_x),
gFont_7->glyph_y,
0);
}
}
// IDA: void __cdecl DrawPartsText()
void DrawPartsText(void) {
int price;
int cost;
LOG_TRACE("()");
CalcPartPrice(gPart_category, gPart_index, &price, &cost);
TransBrPixelmapText(gBack_screen, gCurrent_graf_data->parts_cost_x, gCurrent_graf_data->parts_cost_y, 5, gFont_7, GetMiscString(kMiscString_RetailColon));
BrPixelmapTextF(gBack_screen, gCurrent_graf_data->parts_numbers_x, gCurrent_graf_data->parts_cost_y - (TranslationMode() ? 2 : 0), 5, gFont_7, "%d", price);
if (cost > 0) {
TransBrPixelmapText(gBack_screen, gCurrent_graf_data->parts_net_x, gCurrent_graf_data->parts_net_y, 45, gFont_7, GetMiscString(kMiscString_YouPayColon));
BrPixelmapTextF(gBack_screen, gCurrent_graf_data->parts_numbers_x, gCurrent_graf_data->parts_net_y - (TranslationMode() ? 2 : 0), 45, gFont_7, "%d", cost);
} else if (cost < 0) {
TransBrPixelmapText(gBack_screen, gCurrent_graf_data->parts_net_x, gCurrent_graf_data->parts_net_y, 201, gFont_7, GetMiscString(kMiscString_RefundColon));
BrPixelmapTextF(gBack_screen, gCurrent_graf_data->parts_numbers_x, gCurrent_graf_data->parts_net_y - (TranslationMode() ? 2 : 0), 201, gFont_7, "%d", -cost);
} else if (gJust_bought_part) {
TransBrPixelmapText(gBack_screen, gCurrent_graf_data->parts_net_x, gCurrent_graf_data->parts_net_y, 134, gFont_7, GetMiscString(kMiscString_YouGotIt));
} else {
TransBrPixelmapText(gBack_screen, gCurrent_graf_data->parts_net_x, gCurrent_graf_data->parts_net_y, 134, gFont_7, GetMiscString(kMiscString_YoursAlready));
}
TransBrPixelmapText(gBack_screen, gCurrent_graf_data->parts_total_x, gCurrent_graf_data->parts_total_y, 2, gFont_7, GetMiscString(kMiscString_CreditsColon));
BrPixelmapTextF(gBack_screen, gCurrent_graf_data->parts_numbers_x, gCurrent_graf_data->parts_total_y - (TranslationMode() ? 2 : 0), 2, gFont_7, "%d", gProgram_state.credits);
}
// IDA: void __cdecl SetPartsImage()
void SetPartsImage(void) {
LOG_TRACE("()");
ChangePanelFlic(0,
gProgram_state.current_car.power_ups[gPart_category].info[gPart_index].data_ptr,
gProgram_state.current_car.power_ups[gPart_category].info[gPart_index].data_length);
TellyInImage(GetPanelPixelmap(0), gCurrent_graf_data->parts_image_x, gCurrent_graf_data->parts_image_y);
DrawPartsText();
}
// IDA: int __cdecl GetPartsMax()
int GetPartsMax(void) {
int i;
LOG_TRACE("()");
for (i = gProgram_state.current_car.power_ups[gPart_category].number_of_parts - 1; i >= 0; i--) {
if (gProgram_state.rank <= gProgram_state.current_car.power_ups[gPart_category].info[i].rank_required) {
return i;
}
if (gProgram_state.game_completed) {
return i;
}
}
return 0;
}
// IDA: void __cdecl CalcPartsIndex()
void CalcPartsIndex(void) {
//int current_index; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
gPart_index = gProgram_state.current_car.power_up_levels[gPart_category];
if (gPart_index + 1 < gProgram_state.current_car.power_ups[gPart_category].number_of_parts && (gProgram_state.rank <= gProgram_state.current_car.power_ups[gPart_category].info[gPart_index + 1].rank_required || gProgram_state.game_completed)) {
gPart_index += 1;
}
}
// IDA: void __cdecl DoExchangePart()
void DoExchangePart(void) {
int price;
int cost;
LOG_TRACE("()");
CalcPartPrice(gPart_category, gPart_index, &price, &cost);
if (cost == 0 || gProgram_state.credits < cost) {
DRS3StartSound(gEffects_outlet, 3100);
} else {
gJust_bought_part = 1;
DRS3StartSound(gEffects_outlet, 3101);
BuyPart(gPart_category, gPart_index);
ErasePartsText(1);
DrawPartsText();
}
}
// IDA: int __usercall PartsShopGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int PartsShopGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
//int flic_index; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (*pCurrent_choice < 3 && *pCurrent_mode == 0) {
RemoveTransientBitmaps(1);
DontLetFlicFuckWithPalettes();
TurnFlicTransparencyOn();
RunFlicAt(
gStart_interface_spec->pushed_flics[*pCurrent_choice].flic_index,
gStart_interface_spec->pushed_flics[*pCurrent_choice].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[*pCurrent_choice].y[gGraf_data_index]);
TurnFlicTransparencyOff();
LetFlicFuckWithPalettes();
gJust_bought_part = 0;
ErasePartsText(1);
TellyOutImage(GetPanelPixelmap(0), gCurrent_graf_data->parts_image_x, gCurrent_graf_data->parts_image_y);
gPart_category = *pCurrent_choice;
CalcPartsIndex();
RunFlic(261);
AddToFlicQueue(
gStart_interface_spec->flicker_on_flics[*pCurrent_choice].flic_index,
gStart_interface_spec->flicker_on_flics[*pCurrent_choice].x[gGraf_data_index],
gStart_interface_spec->flicker_on_flics[*pCurrent_choice].y[gGraf_data_index],
1);
DrawPartsLabel();
SetPartsImage();
ProcessFlicQueue(gFrame_period);
DoMouseCursor();
PDScreenBufferSwap(0);
return 0;
} else if (*pCurrent_mode == 1) {
AddToFlicQueue(
gStart_interface_spec->flicker_on_flics[4].flic_index,
gStart_interface_spec->flicker_on_flics[4].x[gGraf_data_index],
gStart_interface_spec->flicker_on_flics[4].y[gGraf_data_index],
1);
DoExchangePart();
return 0;
} else {
return 1;
}
}
// IDA: int __usercall UpPart@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int UpPart(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
gJust_bought_part = 0;
AddToFlicQueue(
gStart_interface_spec->pushed_flics[5].flic_index,
gStart_interface_spec->pushed_flics[5].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[5].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
RemoveTransientBitmaps(1);
ErasePartsText(0);
gPart_index = (gPart_index == 0) ? GetPartsMax() : (gPart_index - 1);
DropOutImageThruBottom(
GetPanelPixelmap(0),
gCurrent_graf_data->parts_image_x,
gCurrent_graf_data->parts_image_y,
gCurrent_graf_data->parts_top_clip,
gCurrent_graf_data->parts_bottom_clip);
ChangePanelFlic(0,
gProgram_state.current_car.power_ups[gPart_category].info[gPart_index].data_ptr,
gProgram_state.current_car.power_ups[gPart_category].info[gPart_index].data_length);
DropInImageFromTop(
GetPanelPixelmap(0),
gCurrent_graf_data->parts_image_x,
gCurrent_graf_data->parts_image_y,
gCurrent_graf_data->parts_top_clip,
gCurrent_graf_data->parts_bottom_clip);
DrawPartsText();
return 0;
}
// IDA: int __usercall DownPart@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int DownPart(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
gJust_bought_part = 0;
AddToFlicQueue(
gStart_interface_spec->pushed_flics[6].flic_index,
gStart_interface_spec->pushed_flics[6].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[6].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
RemoveTransientBitmaps(1);
ErasePartsText(0);
gPart_index = (gPart_index == GetPartsMax()) ? 0 : (gPart_index + 1);
DropOutImageThruTop(
GetPanelPixelmap(0),
gCurrent_graf_data->parts_image_x,
gCurrent_graf_data->parts_image_y,
gCurrent_graf_data->parts_top_clip,
gCurrent_graf_data->parts_bottom_clip);
ChangePanelFlic(0,
gProgram_state.current_car.power_ups[gPart_category].info[gPart_index].data_ptr,
gProgram_state.current_car.power_ups[gPart_category].info[gPart_index].data_length);
DropInImageFromBottom(
GetPanelPixelmap(0),
gCurrent_graf_data->parts_image_x,
gCurrent_graf_data->parts_image_y,
gCurrent_graf_data->parts_top_clip,
gCurrent_graf_data->parts_bottom_clip);
DrawPartsText();
return 0;
}
// IDA: int __usercall UpClickPart@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int UpClickPart(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
UpPart(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall DownClickPart@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int DownClickPart(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
DownPart(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall PartsArrowsOn@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int PartsArrowsOn(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
AddToFlicQueue(
gStart_interface_spec->flicker_on_flics[5].flic_index,
gStart_interface_spec->flicker_on_flics[5].x[gGraf_data_index],
gStart_interface_spec->flicker_on_flics[5].y[gGraf_data_index],
1);
AddToFlicQueue(gStart_interface_spec->flicker_on_flics[6].flic_index,
gStart_interface_spec->flicker_on_flics[6].x[gGraf_data_index],
gStart_interface_spec->flicker_on_flics[6].y[gGraf_data_index],
1);
return 0;
}
// IDA: int __usercall PartsArrowsOff@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int PartsArrowsOff(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
AddToFlicQueue(gStart_interface_spec->flicker_off_flics[5].flic_index,
gStart_interface_spec->flicker_off_flics[5].x[gGraf_data_index],
gStart_interface_spec->flicker_off_flics[5].y[gGraf_data_index],
1);
AddToFlicQueue(gStart_interface_spec->flicker_off_flics[6].flic_index,
gStart_interface_spec->flicker_off_flics[6].x[gGraf_data_index],
gStart_interface_spec->flicker_off_flics[6].y[gGraf_data_index],
1);
return 0;
}
// IDA: void __cdecl StartPartsShop()
void StartPartsShop(void) {
LOG_TRACE("()");
DrawPartsLabel();
SetPartsImage();
}
// IDA: int __usercall DonePartsShop@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
int DonePartsShop(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
if (gFade_away_parts_shop) {
FadePaletteDown();
} else {
RunFlic(251);
}
return pGo_ahead;
}
// IDA: void __usercall DrawPartsShop(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
void DrawPartsShop(int pCurrent_choice, int pCurrent_mode) {
LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
DrawPartsText();
}
// IDA: void __usercall DoPartsShop(int pFade_away@<EAX>)
void DoPartsShop(int pFade_away) {
static tFlicette flicker_on[7] = {
{ 43, { 225, 450 }, { 30, 72 } },
{ 43, { 225, 450 }, { 60, 144 } },
{ 43, { 225, 450 }, { 89, 214 } },
{ 43, { 225, 450 }, { 152, 365 } },
{ 43, { 85, 170 }, { 152, 365 } },
{ 221, { 30, 60 }, { 79, 190 } },
{ 221, { 30, 60 }, { 79, 190 } },
};
static tFlicette flicker_off[7] = {
{ 42, { 225, 450 }, { 30, 72 } },
{ 42, { 225, 450 }, { 60, 144 } },
{ 42, { 225, 450 }, { 89, 214 } },
{ 42, { 225, 450 }, { 152, 365 } },
{ 42, { 85, 170 }, { 152, 365 } },
{ 220, { 30, 60 }, { 79, 190 } },
{ 220, { 30, 60 }, { 79, 190 } },
};
static tFlicette push[7] = {
{ 254, { 225, 450 }, { 30, 72 } },
{ 255, { 225, 450 }, { 60, 144 } },
{ 256, { 225, 450 }, { 89, 214 } },
{ 154, { 225, 450 }, { 152, 365 } },
{ 260, { 85, 170 }, { 152, 365 } },
{ 222, { 30, 60 }, { 79, 190 } },
{ 225, { 30, 60 }, { 120, 288 } },
};
static tMouse_area mouse_areas[7] = {
{ { 225, 450 }, { 30, 72 }, { 288, 576 }, { 50, 120 }, 0, 0, 0, NULL },
{ { 225, 450 }, { 60, 144 }, { 288, 576 }, { 80, 192 }, 1, 0, 0, NULL },
{ { 225, 450 }, { 89, 214 }, { 288, 576 }, { 109, 262 }, 2, 0, 0, NULL },
{ { 225, 450 }, { 152, 365 }, { 288, 576 }, { 172, 413 }, 3, 0, 0, NULL },
{ { 85, 170 }, { 152, 365 }, { 148, 296 }, { 172, 413 }, 4, 1, 0, NULL },
{ { 30, 60 }, { 79, 190 }, { 45, 90 }, { 106, 254 }, -1, 1, 0, UpClickPart },
{ { 30, 60 }, { 120, 288 }, { 45, 90 }, { 147, 353 }, -1, 1, 0, DownClickPart },
};
static tInterface_spec interface_spec = {
0, 250, 190, 0, 0, 0, 6,
{ 1, 0 }, { 4, -1 }, { 4, 0 }, { 4, 3 }, { PartsArrowsOn, PartsArrowsOff },
{ 1, 0 }, { 4, -1 }, { 4, 0 }, { 4, 3 }, { PartsArrowsOn, PartsArrowsOff },
{ -1, -1 }, { -1, 0 }, { 0, 4 }, { 3, 4 }, { NULL, UpPart },
{ -1, -1 }, { 1, 0 }, { 0, 4 }, { 3, 4 }, { NULL, DownPart },
{ 1, 1 }, { PartsShopGoAhead, PartsShopGoAhead },
{ 1, 1 }, { NULL, NULL },
NULL, DrawPartsShop, 0, NULL, StartPartsShop, DonePartsShop,
0, { 0, 0 }, NULL, 3, 1,
COUNT_OF(flicker_on),
flicker_on,
flicker_off,
push,
COUNT_OF(mouse_areas),
mouse_areas,
0,
NULL
};
//int result; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%d)", pFade_away);
LoadParts();
gFade_away_parts_shop = pFade_away;
InitialiseFlicPanel(0,
gCurrent_graf_data->parts_image_x,
gCurrent_graf_data->parts_image_y,
gCurrent_graf_data->parts_image_width,
gCurrent_graf_data->parts_image_height);
gStart_interface_spec = &interface_spec;
gPart_category = eParts_armour;
gJust_bought_part = 0;
gRefund_rate = 75;
CalcPartsIndex();
DoInterfaceScreen(&interface_spec, gFaded_palette, 3);
DisposeFlicPanel(0);
UnlockParts();
gProgram_state.parts_shop_visited = 1;
}
// IDA: int __usercall AutoPartsDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
int AutoPartsDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
if (pEscaped) {
pCurrent_choice = -1;
}
return pCurrent_choice;
}
// IDA: tSO_result __cdecl DoAutoPartsShop()
tSO_result DoAutoPartsShop(void) {
static tFlicette flicker_on[3] = {
{ 43, { 84, 168 }, { 67, 161 } },
{ 43, { 84, 168 }, { 95, 228 } },
{ 43, { 84, 168 }, { 124, 298 } },
};
static tFlicette flicker_off[3] = {
{ 42, { 84, 168 }, { 67, 161 } },
{ 42, { 84, 168 }, { 95, 228 } },
{ 42, { 84, 168 }, { 124, 298 } },
};
static tFlicette push[3] = {
{ 284, { 84, 168 }, { 67, 161 } },
{ 284, { 84, 168 }, { 95, 228 } },
{ 284, { 84, 168 }, { 124, 298 } },
};
static tMouse_area mouse_areas[3] = {
{ { 84, 168 }, { 32, 77 }, { 147, 294 }, { 87, 209 }, 0, 0, 0, NULL },
{ { 84, 168 }, { 95, 228 }, { 147, 294 }, { 115, 276 }, 1, 0, 0, NULL },
{ { 84, 168 }, { 124, 298 }, { 147, 294 }, { 144, 346 }, 2, 0, 0, NULL },
};
static tInterface_spec interface_spec = {
0, 280, 0, 0, 0, 0, 6,
{ -1, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { NULL, NULL },
{ -1, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { NULL, NULL },
{ -1, -1 }, { -1, 0 }, { 0, 0 }, { 2, 0 }, { NULL, NULL },
{ -1, -1 }, { 1, 0 }, { 0, 0 }, { 2, 0 }, { NULL, NULL },
{ 1, 1 }, { NULL, NULL },
{ 1, 1 }, { NULL, NULL },
NULL, NULL, 0, NULL, NULL, AutoPartsDone, 0,
{ 0, 0 }, NULL, -1, 1,
COUNT_OF(flicker_on), flicker_on, flicker_off, push,
COUNT_OF(mouse_areas), mouse_areas,
0, NULL
};
int result;
LOG_TRACE("()");
gProgram_state.dont_load = 1;
result = DoInterfaceScreen(&interface_spec, 0, gProgram_state.auto_parts_reply);
gProgram_state.dont_load = 0;
if (result < 0) {
RunFlic(281);
return eSO_main_menu_invoked;
} else {
gProgram_state.auto_parts_reply = result;
switch (result) {
case eAP_auto:
DoAutoParts();
break;
case eAP_manual:
RunFlic(281);
DoPartsShop(1);
break;
}
FadePaletteDown();
return eSO_continue;
}
}
// IDA: void __cdecl SetOpponentFlic()
void SetOpponentFlic(void) {
LOG_TRACE("()");
ChangePanelFlic(0,
gOpponents[gCurrent_race.opponent_list[gOpponent_index].index].mug_shot_image_data,
gOpponents[gCurrent_race.opponent_list[gOpponent_index].index].mug_shot_image_data_length);
}
// IDA: void __cdecl DrawSceneyMappyInfoVieweyThing()
void DrawSceneyMappyInfoVieweyThing(void) {
LOG_TRACE("()");
RemoveTransientBitmaps(1);
if (gProgram_state.view_type) {
if (gProgram_state.view_type == eVT_Info) {
ChangePanelFlic(0, gCurrent_race.info_image_data, gCurrent_race.info_image_data_length);
} else if (gProgram_state.view_type == eVT_Opponents) {
SetOpponentFlic();
}
} else {
ChangePanelFlic(0, gCurrent_race.scene_image_data, gCurrent_race.scene_image_data_length);
}
TellyInImage(GetPanelPixelmap(0), gCurrent_graf_data->start_race_panel_left, gCurrent_graf_data->start_race_panel_top);
}
// IDA: void __cdecl DismissSceneyMappyInfoVieweyThing()
void DismissSceneyMappyInfoVieweyThing(void) {
LOG_TRACE("()");
RemoveTransientBitmaps(1);
TellyOutImage(GetPanelPixelmap(0), gCurrent_graf_data->start_race_panel_left, gCurrent_graf_data->start_race_panel_top);
}
// IDA: int __usercall SelectRaceDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
int SelectRaceDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
DismissSceneyMappyInfoVieweyThing();
if (pEscaped) {
return -1;
}
return pCurrent_choice;
}
// IDA: int __usercall StartRaceGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int StartRaceGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (*pCurrent_choice != 1 || *pCurrent_mode) {
return 1;
}
RemoveTransientBitmaps(1);
DismissSceneyMappyInfoVieweyThing();
gProgram_state.view_type++;
if (gProgram_state.view_type > eVT_Opponents) {
gProgram_state.view_type = eVT_Scene;
}
if (gProgram_state.view_type) {
if (gProgram_state.view_type == eVT_Info) {
RunFlic(210);
} else if (gProgram_state.view_type == eVT_Opponents) {
RunFlic(212);
}
} else {
RunFlic(213);
}
DrawSceneyMappyInfoVieweyThing();
return 0;
}
// IDA: int __usercall TryToMoveToArrows@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int TryToMoveToArrows(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (gProgram_state.view_type != eVT_Opponents) {
return 0;
}
*pCurrent_choice = 5;
*pCurrent_mode = 1;
DRS3StartSound(gEffects_outlet, 3000);
return 1;
}
// IDA: int __usercall UpOpponent@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int UpOpponent(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
#if defined(DETHRACE_FIX_BUGS)
// fixes bug where racers could be scrolled in other race menu modes
if (gProgram_state.view_type != eVT_Opponents) {
return 0;
}
#endif
AddToFlicQueue(gStart_interface_spec->pushed_flics[5].flic_index,
gStart_interface_spec->pushed_flics[5].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[5].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
RemoveTransientBitmaps(1);
DropOutImageThruBottom(GetPanelPixelmap(0),
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_top_clip,
gCurrent_graf_data->start_race_panel_bottom_clip);
if (gOpponent_index == 0) {
gOpponent_index = gCurrent_race.number_of_racers;
}
gOpponent_index--;
SetOpponentFlic();
DropInImageFromTop(GetPanelPixelmap(0),
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_top_clip,
gCurrent_graf_data->start_race_panel_bottom_clip);
return 0;
}
// IDA: int __usercall DownOpponent@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int DownOpponent(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
#if defined(DETHRACE_FIX_BUGS)
// fixes bug where racers could be scrolled in other race menu modes
if (gProgram_state.view_type != eVT_Opponents) {
return 0;
}
#endif
AddToFlicQueue(gStart_interface_spec->pushed_flics[6].flic_index,
gStart_interface_spec->pushed_flics[6].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[6].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
RemoveTransientBitmaps(1);
DropOutImageThruTop(GetPanelPixelmap(0),
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_top_clip,
gCurrent_graf_data->start_race_panel_bottom_clip);
gOpponent_index++;
if (gOpponent_index == gCurrent_race.number_of_racers) {
gOpponent_index = 0;
}
SetOpponentFlic();
DropInImageFromBottom(GetPanelPixelmap(0),
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_top_clip,
gCurrent_graf_data->start_race_panel_bottom_clip);
return 0;
}
// IDA: int __usercall UpClickOpp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int UpClickOpp(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
UpOpponent(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall DownClickOpp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int DownClickOpp(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
DownOpponent(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: void __cdecl SelectRaceStart()
void SelectRaceStart(void) {
LOG_TRACE("()");
DrawSceneyMappyInfoVieweyThing();
PrintMemoryDump(0, "INSIDE START RACE");
}
// IDA: int __cdecl SuggestRace()
int SuggestRace(void) {
int i;
int least_done;
int suggested_so_far;
int suggested_race;
int new_suggestion;
int number_of_visits;
LOG_TRACE("()");
suggested_so_far = 32767;
suggested_race = 0;
if (gProgram_state.game_completed) {
return IRandomBetween(0, gNumber_of_races - 1);
}
if (gProgram_state.redo_race_index >= 0) {
return gProgram_state.redo_race_index;
}
for (i = 0; i < gNumber_of_races; i++) {
if (gRace_list[i].suggested_rank <= suggested_so_far && gRace_list[i].suggested_rank >= gProgram_state.rank) {
suggested_so_far = gRace_list[i].suggested_rank;
suggested_race = i;
}
}
number_of_visits = gRace_list[suggested_race].been_there_done_that;
new_suggestion = suggested_race;
if (number_of_visits) {
// Jeff: if we have already completed the suggested race, look backwards for a race that we haven't completed as many times
for (i = suggested_race - 1; i >= 0 && i >= suggested_race - 5; i--) {
if (gRace_list[i].rank_required < gProgram_state.rank || gRace_list[i].best_rank > gProgram_state.rank) {
continue;
}
least_done = gRace_list[i].been_there_done_that < number_of_visits;
if (!gRace_list[i].been_there_done_that
|| (least_done && suggested_race - 3 <= i)) {
new_suggestion = i;
number_of_visits = gRace_list[i].been_there_done_that;
}
}
// Jeff: look forwards for a race that we haven't completed as many times as the previous suggestion
for (i = suggested_race + 1; i < gNumber_of_races; i++) {
least_done = gRace_list[i].been_there_done_that < number_of_visits;
if (!least_done) {
continue;
}
if ((gRace_list[i].rank_required >= gProgram_state.rank && gRace_list[i].best_rank <= gProgram_state.rank)
|| gProgram_state.game_completed) {
new_suggestion = i;
number_of_visits = gRace_list[i].been_there_done_that;
}
}
}
return new_suggestion;
}
// IDA: void __usercall SelectRaceDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
void SelectRaceDraw(int pCurrent_choice, int pCurrent_mode) {
tOpponent* the_opponent;
tText_chunk* the_chunk;
int j;
int k;
int y_coord;
//char s[256]; // Pierre-Marie Baty -- unused variable
//char temp_str[256]; // Pierre-Marie Baty -- unused variable
//char* sub_pt; // Pierre-Marie Baty -- unused variable
//char sub_str[16]; // Pierre-Marie Baty -- unused variable
tU32* test;
static tU32 test2;
LOG_TRACE8("(%d, %d)", pCurrent_choice, pCurrent_mode);
if (gProgram_state.view_type == eVT_Opponents) {
the_opponent = &gOpponents[gCurrent_race.opponent_list[gOpponent_index].index];
for (j = 0; j < the_opponent->text_chunk_count; j++) {
the_chunk = &the_opponent->text_chunks[j];
if (GetPanelFlicFrameIndex(0) >= the_chunk->frame_cue && GetPanelFlicFrameIndex(0) < the_chunk->frame_end) {
y_coord = the_chunk->y_coord * gGraf_specs[gGraf_spec_index].total_height / 200
+ gCurrent_graf_data->start_race_panel_top;
for (k = 0; k < the_chunk->line_count; k++) {
TransBrPixelmapText(
gBack_screen,
the_chunk->x_coord * gGraf_specs[gGraf_spec_index].total_width / 320
+ gCurrent_graf_data->start_race_panel_left,
y_coord,
201,
gFont_7,
the_chunk->text[k]);
y_coord += gFont_7->glyph_y + gFont_7->glyph_y / 2;
}
}
}
} else if (gProgram_state.view_type == eVT_Info) {
for (j = 0; j < gCurrent_race.text_chunk_count; j++) {
the_chunk = &gCurrent_race.text_chunks[j];
if (GetPanelFlicFrameIndex(0) >= the_chunk->frame_cue && GetPanelFlicFrameIndex(0) < the_chunk->frame_end) {
y_coord = the_chunk->y_coord * gGraf_specs[gGraf_spec_index].total_height / 200
+ gCurrent_graf_data->start_race_panel_top;
for (k = 0; k < the_chunk->line_count; k++) {
TransBrPixelmapText(
gBack_screen,
the_chunk->x_coord * gGraf_specs[gGraf_spec_index].total_width / 320
+ gCurrent_graf_data->start_race_panel_left,
y_coord,
201,
gFont_7,
the_chunk->text[k]);
y_coord += gFont_7->glyph_y + gFont_7->glyph_y / 2;
}
}
}
}
test = KevKeyService();
if (*test) {
test2 = *test;
}
if (test[0] == 0x27645433 && test[1] == 0x758f0015) {
// cheat code: "KEVWOZEAR"
gProgram_state.game_completed = 1;
DRS3StartSound(gEffects_outlet, 3202);
DRS3StartSound(gEffects_outlet, 3202);
}
if (test[0] == 0x33f75455 && test[1] == 0xC10AAAF2) {
// cheat code: "IWANTTOFIDDLE"
char s[128];
FILE* f;
size_t i; // Pierre-Marie Baty -- fixed type
// Jeff
PathCat(s, gApplication_path, "ACTORS");
PathCat(s, s, "PROG.ACT");
PDFileUnlock(s);
if (f != NULL) {
DRS3StartSound(gEffects_outlet, 9000);
if (gDecode_thing) {
for (i
= 0; i
< strlen(gDecode_string
); i
++) {
gDecode_string[i] -= 50;
}
fputs(gDecode_string
, f
);
for (i
= 0; i
< strlen(gDecode_string
); i
++) {
gDecode_string[i] += 50;
}
} else {
for (i = 0; i < 20; i++) {
fputs("*************", f
);
}
}
gDecode_thing ^= 0x40u;
EncodeAllFilesInDirectory("");
EncodeAllFilesInDirectory("CARS");
EncodeAllFilesInDirectory("NONCARS");
EncodeAllFilesInDirectory("RACES");
EncodeAllFilesInDirectory("32X20X8");
EncodeAllFilesInDirectory("64X48X8");
PathCat(s, "32X20X8", "CARS");
EncodeAllFilesInDirectory(s);
PathCat(s, "64X48X8", "CARS");
EncodeAllFilesInDirectory(s);
PathCat(s, "32X20X8", "FONTS");
EncodeAllFilesInDirectory(s);
PathCat(s, "64X48X8", "FONTS");
EncodeAllFilesInDirectory(s);
}
DRS3StartSound(gEffects_outlet, 9000);
}
}
// IDA: tSO_result __usercall DoSelectRace@<EAX>(int *pSecond_time_around@<EAX>)
tSO_result DoSelectRace(int* pSecond_time_around) {
static tFlicette flicker_on[7] = {
{ 43, { 224, 448 }, { 28, 67 } },
{ 43, { 224, 448 }, { 56, 134 } },
{ 43, { 224, 448 }, { 85, 204 } },
{ 43, { 224, 448 }, { 113, 271 } },
{ 43, { 224, 448 }, { 147, 353 } },
{ 221, { 30, 60 }, { 79, 190 } },
{ 221, { 30, 60 }, { 79, 190 } }
};
static tFlicette flicker_off[7] = {
{ 42, { 224, 448 }, { 28, 67 } },
{ 42, { 224, 448 }, { 56, 134 } },
{ 42, { 224, 448 }, { 85, 204 } },
{ 42, { 224, 448 }, { 113, 271 } },
{ 42, { 224, 448 }, { 147, 353 } },
{ 220, { 30, 60 }, { 79, 190 } },
{ 220, { 30, 60 }, { 79, 190 } }
};
static tFlicette push[7] = {
{ 195, { 224, 448 }, { 28, 67 } },
{ -1, { 224, 448 }, { 56, 134 } },
{ 200, { 224, 448 }, { 85, 204 } },
{ 202, { 224, 448 }, { 113, 271 } },
{ 201, { 224, 448 }, { 147, 353 } },
{ 222, { 30, 60 }, { 79, 190 } },
{ 225, { 30, 60 }, { 119, 286 } }
};
static tMouse_area mouse_areas[7] = {
{ { 224, 448 }, { 28, 67 }, { 287, 574 }, { 48, 115 }, 0, 0, 0, NULL },
{ { 224, 448 }, { 56, 134 }, { 287, 574 }, { 76, 182 }, 1, 0, 0, NULL },
{ { 224, 448 }, { 85, 204 }, { 287, 574 }, { 105, 252 }, 2, 0, 0, NULL },
{ { 224, 448 }, { 113, 271 }, { 287, 574 }, { 133, 319 }, 3, 0, 0, NULL },
{ { 224, 448 }, { 147, 353 }, { 287, 574 }, { 167, 401 }, 4, 0, 0, NULL },
{ { 30, 60 },
{ 79, 190 },
{ 45, 90 },
{ 106, 254 },
-1,
0,
0,
&UpClickOpp },
{ { 30, 60 },
{ 119, 286 },
{ 45, 90 },
{ 146, 350 },
-1,
0,
0,
&DownClickOpp }
};
static tInterface_spec interface_spec = {
0, // initial_imode
191, // first_opening_flic
190, // second_opening_flic
0, // end_flic_go_ahead
0, // end_flic_escaped
0, // end_flic_otherwise
6, // flic_bunch_to_load
{ -1, 0 }, // move_left_new_mode
{ 0, -4 }, // move_left_delta
{ 0, 1 }, // move_left_min
{ 0, 1 }, // move_left_max
{ &TryToMoveToArrows, NULL }, // move_left_proc
{ -1, 0 }, // move_right_new_mode
{ 0, -4 }, // move_right_delta
{ 0, 1 }, // move_right_min
{ 0, 1 }, // move_right_max
{ &TryToMoveToArrows, NULL }, // move_right_proc
{ -1, -1 }, // move_up_new_mode
{ -1, 0 }, // move_up_delta
{ 0, 5 }, // move_up_min
{ 4, 5 }, // move_up_max
{ NULL, &UpOpponent }, // move_up_proc
{ -1, -1 }, // move_down_new_mode
{ 1, 0 }, // move_down_delta
{ 0, 5 }, // move_down_min
{ 4, 5 }, // move_down_max
{ NULL, &DownOpponent }, // move_down_proc
{ 1, 1 }, // go_ahead_allowed
{ &StartRaceGoAhead, NULL }, // go_ahead_proc
{ 1, 1 }, // escape_allowed
{ NULL, NULL }, // escape_proc
NULL, // exit_proc
&SelectRaceDraw, // draw_proc
0u, // time_out
NULL, // start_proc1
&SelectRaceStart, // start_proc2
&SelectRaceDone, // done_proc
0, // font_needed
{ 0, 0 }, // typeable
NULL, // get_original_string
-1, // escape_code
1, // dont_save_or_load
7, // number_of_button_flics
flicker_on, // flicker_on_flics
flicker_off, // flicker_off_flics
push, // pushed_flics
7, // number_of_mouse_areas
mouse_areas, // mouse_areas
0, // number_of_recopy_areas
NULL // recopy_areas
};
int result;
//int default_choice; // Pierre-Marie Baty -- unused variable
int suggested;
int old_current_race;
LOG_TRACE("(%p)", pSecond_time_around);
suggested = SuggestRace();
if (!*pSecond_time_around) {
gProgram_state.current_race_index = suggested;
SelectOpponents(&gCurrent_race);
}
gProgram_state.parts_shop_visited = 0;
gProgram_state.dont_load = 1;
gDeceased_image = LoadPixelmap("DECEASED.PIX");
InitialiseFlicPanel(
0,
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_right - gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_bottom - gCurrent_graf_data->start_race_panel_top);
LoadRaceInfo(gProgram_state.current_race_index, &gCurrent_race);
do {
gProgram_state.view_type = 0;
gOpponent_index = 0;
gStart_interface_spec = &interface_spec;
if (gFaded_palette || gCurrent_splash) {
result = DoInterfaceScreen(&interface_spec, 1, 4);
} else {
result = DoInterfaceScreen(&interface_spec, 0, 4);
}
if (result == 0 || result == 2 || result == 3) {
DisposeFlicPanel(0);
if (result == 2) {
if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) {
DoFeatureUnavailableInDemo();
} else {
RunFlic(192);
DoPartsShop(0);
}
} else if (result == 3) {
RunFlic(192);
DoChangeCar();
} else if (result == 0) {
RunFlic(192);
old_current_race = gProgram_state.current_race_index;
DoChangeRace();
if (gProgram_state.current_race_index != old_current_race) {
DisposeRaceInfo(&gCurrent_race);
SelectOpponents(&gCurrent_race);
LoadRaceInfo(gProgram_state.current_race_index, &gCurrent_race);
}
}
InitialiseFlicPanel(
0,
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_right - gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_bottom - gCurrent_graf_data->start_race_panel_top);
}
} while (result >= 0 && result != 4);
BrPixelmapFree(gDeceased_image);
FillInRaceInfo(&gCurrent_race);
DisposeRaceInfo(&gCurrent_race);
DisposeFlicPanel(0);
*pSecond_time_around = 1;
gProgram_state.dont_load = 0;
if (result >= 0) {
*pSecond_time_around = 1;
if (gProgram_state.parts_shop_visited || !PartsShopRecommended()) {
FadePaletteDown();
return eSO_continue;
} else {
RunFlic(192);
return DoAutoPartsShop();
}
} else {
RunFlic(192);
gDisallow_abandon_race = 1;
return eSO_main_menu_invoked;
}
}
// IDA: void __usercall DrawGridCar(int pX@<EAX>, int pY@<EDX>, br_pixelmap *pImage@<EBX>)
void DrawGridCar(int pX, int pY, br_pixelmap* pImage) {
LOG_TRACE("(%d, %d, %p)", pX, pY, pImage);
if (gCurrent_graf_data->grid_left_clip <= pX && pX + pImage->width < gCurrent_graf_data->grid_right_clip) {
DRPixelmapRectangleMaskedCopy(gBack_screen, pX, pY, pImage, 0, 0, pImage->width, pImage->height);
}
}
// IDA: void __usercall DrawGrid(int pOffset@<EAX>, int pDraw_it@<EDX>)
void DrawGrid(int pOffset, int pDraw_it) {
int i;
int j;
int y;
int x;
int str_x;
//int width_job; // Pierre-Marie Baty -- unused variable
int done_highest;
int str_index;
int swap_1_x = 0;
int swap_1_y = 0;
int swap_2_x = 0;
int swap_2_y = 0;
br_pixelmap* the_image = NULL;
br_pixelmap* swap_1_image = NULL;
br_pixelmap* swap_2_image = NULL;
char numbers_str[4][100];
char total_str[256];
tU32 the_time;
LOG_TRACE("(%d, %d)", pOffset, pDraw_it);
done_highest = 0;
str_index = 0;
memset(numbers_str
, 0, sizeof(numbers_str
));
memset(total_str
, 0, sizeof(total_str
));
the_time = PDGetTotalTime();
BrPixelmapRectangleFill(
gBack_screen,
gCurrent_graf_data->grid_left_clip,
gCurrent_graf_data->grid_top_clip,
gCurrent_graf_data->grid_right_clip - gCurrent_graf_data->grid_left_clip,
gCurrent_graf_data->grid_bottom_clip - gCurrent_graf_data->grid_top_clip,
0);
for (i = 0; i < gCurrent_race.number_of_racers; i++) {
if (gCurrent_race.opponent_list[i].index == -1) {
the_image = gProgram_state.current_car.grid_icon_image;
} else {
the_image = gCurrent_race.opponent_list[i].car_spec->grid_icon_image;
}
y = gCurrent_graf_data->grid_top_y
+ i % 2 * gCurrent_graf_data->grid_y_pitch
- the_image->height / 2
- gGrid_y_adjust;
x = gCurrent_graf_data->grid_left_x
+ i % 2 * gCurrent_graf_data->grid_x_stagger
+ i / 2 * gCurrent_graf_data->grid_x_pitch
- pOffset;
if (i == gSwap_grid_1) {
swap_1_x = x;
swap_1_y = y;
swap_1_image = the_image;
} else if (i == gSwap_grid_2) {
swap_2_x = x;
swap_2_y = y;
swap_2_image = the_image;
} else if (gCurrent_race.opponent_list[i].index != -1 || the_time % 900 / 300) {
DrawGridCar(x, y, the_image);
}
if (!done_highest && gCurrent_race.opponent_list[i].ranking >= gProgram_state.rank) {
done_highest = 1;
if (x - gCurrent_graf_data->grid_marker_margin >= gCurrent_graf_data->grid_left_clip
&& x + the_image->width < gCurrent_graf_data->grid_right_clip) {
BrPixelmapLine(
gBack_screen,
x - gCurrent_graf_data->grid_marker_margin,
y - gCurrent_graf_data->grid_marker_margin,
x - gCurrent_graf_data->grid_marker_margin,
y + gCurrent_graf_data->grid_marker_margin + the_image->height,
45);
BrPixelmapLine(
gBack_screen,
x - gCurrent_graf_data->grid_marker_margin,
y - gCurrent_graf_data->grid_marker_margin,
x + gCurrent_graf_data->grid_marker_x_len,
y - gCurrent_graf_data->grid_marker_margin,
45);
BrPixelmapLine(
gBack_screen,
x - gCurrent_graf_data->grid_marker_margin,
y + gCurrent_graf_data->grid_marker_margin + the_image->height,
x + gCurrent_graf_data->grid_marker_x_len,
y + gCurrent_graf_data->grid_marker_margin + the_image->height,
45);
}
}
if (gCurrent_race.opponent_list[i].index < 0) {
str_index = 2;
} else if (gProgram_state.rank <= gCurrent_race.opponent_list[i].ranking) {
if (str_index >= 2) {
str_index = 3;
} else {
str_index = 1;
}
}
if (gCurrent_race.opponent_list[i].index >= 0) {
if (gOpponents[gCurrent_race.opponent_list[i].index].car_number <= 0
|| gOpponents[gCurrent_race.opponent_list[i].index].car_number >= 100) {
if (gOpponents[gCurrent_race.opponent_list[i].index].car_number < 0) {
sprintf(&numbers_str
[str_index
][strlen(numbers_str
[str_index
])], "%c ", ':');
}
} else {
&numbers_str
[str_index
][strlen(numbers_str
[str_index
])],
"%d ",
gOpponents[gCurrent_race.opponent_list[i].index].car_number);
}
} else {
if (gProgram_state.frank_or_anniness == eAnnie) {
sprintf(&numbers_str
[str_index
][strlen(numbers_str
[str_index
])], "%c ", '<');
} else {
sprintf(&numbers_str
[str_index
][strlen(numbers_str
[str_index
])], "%c ", ';');
}
}
}
if (gSwap_grid_1 >= 0) {
DrawGridCar(
gGrid_transition_stage * (swap_2_x - swap_1_x) / 100 + swap_1_x,
gGrid_transition_stage * (swap_2_y - swap_1_y) / 100 + swap_1_y,
swap_1_image);
DrawGridCar(
gGrid_transition_stage * (swap_1_x - swap_2_x) / 100 + swap_2_x,
gGrid_transition_stage * (swap_1_y - swap_2_y) / 100 + swap_2_y,
swap_2_image);
}
if (gDraw_grid_status == eGrid_draw_all) {
numbers_str
[3][strlen(numbers_str
[3]) - 1] = '\0';
} else {
numbers_str
[2][strlen(numbers_str
[2]) - 1] = '\0';
}
strcpy(total_str
, numbers_str
[0]);
for (i = 1; i < COUNT_OF(numbers_str); i++) {
strcat(total_str
, numbers_str
[i
]);
}
str_x = (gCurrent_graf_data->grid_numbers_left + gCurrent_graf_data->grid_numbers_right) / 2
- (BrPixelmapTextWidth(gBack_screen, gBig_font, total_str) / 2);
BrPixelmapRectangleFill(
gBack_screen,
gCurrent_graf_data->grid_numbers_left,
gCurrent_graf_data->grid_numbers_top,
gCurrent_graf_data->grid_numbers_right - gCurrent_graf_data->grid_numbers_left,
gBig_font->glyph_y,
0);
gGrid_number_x_coords[0] = str_x - 3 - gCurrent_graf_data->grid_numbers_left;
for (i = 0; i < 4; ++i) {
if (i != 2 || the_time % 900 / 300) {
TransBrPixelmapText(
gBack_screen,
str_x,
gCurrent_graf_data->grid_numbers_top,
gGrid_number_colour[i],
gBig_font,
numbers_str[i]);
}
str_x += BrPixelmapTextWidth(gBack_screen, gBig_font, numbers_str[i]);
}
for (i = gCurrent_race.number_of_racers - 1; i > 0; i--) {
for (j
= strlen(total_str
) - 2; j
>= 0; j
--) {
if (total_str[j] == ' ') {
total_str[j + 1] = '\0';
break;
}
}
gGrid_number_x_coords[i] = gGrid_number_x_coords[0] + BrPixelmapTextWidth(gBack_screen, gBig_font, total_str);
}
}
if (pDraw_it) {
PDScreenBufferSwap(0);
}
}
// IDA: void __usercall MoveGrid(int pFrom@<EAX>, int pTo@<EDX>, tS32 pTime_to_move@<EBX>)
void MoveGrid(int pFrom, int pTo, tS32 pTime_to_move) {
tS32 start_time;
tS32 the_time;
//int move_distance; // Pierre-Marie Baty -- unused variable
int pitch;
LOG_TRACE("(%d, %d, %d)", pFrom, pTo, pTime_to_move);
pitch = gCurrent_graf_data->grid_x_pitch;
start_time = PDGetTotalTime();
while (1) {
the_time = PDGetTotalTime();
if (start_time + pTime_to_move <= the_time) {
break;
}
DrawGrid(pitch * pFrom + pitch * (pTo - pFrom) * (the_time - start_time) / pTime_to_move, 1);
}
DrawGrid(pitch * pTo, 1);
}
// IDA: int __usercall CalcGridOffset@<EAX>(int pPosition@<EAX>)
int CalcGridOffset(int pPosition) {
LOG_TRACE("(%d)", pPosition);
return pPosition / 2 - 1;
}
// IDA: void __usercall GridDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
void GridDraw(int pCurrent_choice, int pCurrent_mode) {
LOG_TRACE8("(%d, %d)", pCurrent_choice, pCurrent_mode);
if (gDraw_grid_status > eGrid_draw_none) {
DrawGrid(gCurrent_graf_data->grid_x_pitch * CalcGridOffset(gOur_starting_position), 0);
}
}
// IDA: void __usercall ActuallySwapOrder(int pFirst_index@<EAX>, int pSecond_index@<EDX>)
void ActuallySwapOrder(int pFirst_index, int pSecond_index) {
tOpp_spec temp_opp;
LOG_TRACE("(%d, %d)", pFirst_index, pSecond_index);
temp_opp = gCurrent_race.opponent_list[pFirst_index];
gCurrent_race.opponent_list[pFirst_index] = gCurrent_race.opponent_list[pSecond_index];
gCurrent_race.opponent_list[pSecond_index] = temp_opp;
gOur_starting_position = pSecond_index;
// LOG_DEBUG("first %d, second %d", gCurrent_race.opponent_list[pFirst_index].index, gCurrent_race.opponent_list[pSecond_index].index);
}
// IDA: void __usercall DoGridTransition(int pFirst_index@<EAX>, int pSecond_index@<EDX>)
void DoGridTransition(int pFirst_index, int pSecond_index) {
tU32 start_time;
tU32 the_time;
LOG_TRACE("(%d, %d)", pFirst_index, pSecond_index);
if (pFirst_index != pSecond_index) {
start_time = PDGetTotalTime();
gSwap_grid_1 = pFirst_index;
gSwap_grid_2 = pSecond_index;
while (1) {
the_time = PDGetTotalTime();
if (start_time + 150 <= the_time) {
break;
}
RemoveTransientBitmaps(1);
gGrid_transition_stage = 100 * (the_time - start_time) / 150;
DrawGrid(gCurrent_graf_data->grid_x_pitch * CalcGridOffset(gOur_starting_position), 0);
ProcessFlicQueue(gFrame_period);
DoMouseCursor();
PDScreenBufferSwap(0);
}
gSwap_grid_1 = -1;
gSwap_grid_2 = -1;
ActuallySwapOrder(pFirst_index, pSecond_index);
MoveGrid(CalcGridOffset(pFirst_index), CalcGridOffset(pSecond_index), 150);
}
}
// IDA: void __cdecl ChallengeStart()
void ChallengeStart(void) {
br_pixelmap* the_map;
int i;
int j;
int line_count;
int dare_index;
FILE* f;
tPath_name the_path;
char s[256];
LOG_TRACE("()");
InitialiseFlicPanel(
0,
gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_top,
gCurrent_graf_data->start_race_panel_right - gCurrent_graf_data->start_race_panel_left,
gCurrent_graf_data->start_race_panel_bottom - gCurrent_graf_data->start_race_panel_top);
ChangePanelFlic(
0,
gOpponents[gChallenger_index__racestrt].mug_shot_image_data,
gOpponents[gChallenger_index__racestrt].mug_shot_image_data_length);
if (gScreen->row_bytes < 0) {
BrFatal("C:\\Msdev\\Projects\\DethRace\\Racestrt.c", 2610, "Bruce bug at line %d, file C:\\Msdev\\Projects\\DethRace\\Racestrt.c", 50);
}
the_map = DRPixelmapAllocate(
gScreen->type,
gCurrent_graf_data->dare_mugshot_width,
gCurrent_graf_data->dare_mugshot_height,
0,
0);
BrPixelmapRectangleCopy(the_map, 0, 0, GetPanelPixelmap(0), gCurrent_graf_data->dare_mug_left_margin, gCurrent_graf_data->dare_mug_top_margin, gCurrent_graf_data->dare_mugshot_width, gCurrent_graf_data->dare_mugshot_height);
DisposeFlicPanel(0);
TellyInImage(the_map, gCurrent_graf_data->dare_mugshot_left, gCurrent_graf_data->dare_mugshot_top);
BrPixelmapFree(the_map);
the_map = DRPixelmapAllocate(gScreen->type, gCurrent_graf_data->dare_text_width, gCurrent_graf_data->dare_mugshot_height, 0, 0);
BrPixelmapFill(the_map, 0);
TransBrPixelmapText(the_map, 0, 0, 1u, gBig_font, gOpponents[gChallenger_index__racestrt].abbrev_name);
PathCat(the_path, gApplication_path, "DARES.TXT");
f = DRfopen(the_path, "rt");
if (f == NULL) {
FatalError(kFatalError_OpenDareTxt);
}
dare_index = IRandomBetween(0, GetAnInt(f) - 1);
for (i = 0; i < dare_index; i++) {
line_count = GetAnInt(f);
for (j = 0; j < line_count; j++) {
GetALineAndDontArgue(f, s);
}
}
line_count = GetAnInt(f);
for (i = 0; i < line_count; i++) {
GetALineAndDontArgue(f, s);
TransBrPixelmapText(the_map, 0, 2 * (i + 1) * gBig_font->glyph_y, 0x86u, gBig_font, s);
}
BrPixelmapLine(the_map, 0, gBig_font->glyph_y + 2, the_map->width, gBig_font->glyph_y + 2, 45);
TellyInImage(the_map, gCurrent_graf_data->dare_text_left, gCurrent_graf_data->dare_mugshot_top);
BrPixelmapFree(the_map);
UnlockOpponentMugshot(gChallenger_index__racestrt);
gDare_start_time = PDGetTotalTime();
}
// IDA: int __usercall CheckNextStage@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int CheckNextStage(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (gDare_start_time && (unsigned int)(PDGetTotalTime() - gDare_start_time) >= 7500) {
BrPixelmapRectangleFill(
gBack_screen,
gCurrent_graf_data->grid_left_clip,
gCurrent_graf_data->dare_mugshot_top,
gCurrent_graf_data->grid_right_clip - gCurrent_graf_data->grid_left_clip,
gCurrent_graf_data->dare_mugshot_height,
0);
DoGridTransition(gOur_starting_position, gChallenger_position);
gDraw_grid_status = eGrid_draw_icons_only;
gDare_start_time = 0;
}
return 0;
}
// IDA: int __usercall ChallengeDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
int ChallengeDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
if (!pEscaped || gDare_start_time) {
if (!pEscaped && gDare_start_time) {
ActuallySwapOrder(gOur_starting_position, gChallenger_position);
ChallengeOccurred(gChallenger_index__racestrt, 1);
}
} else {
DoGridTransition(gOur_starting_position, gOriginal_position);
ActuallySwapOrder(gOur_starting_position, gOriginal_position);
ChallengeOccurred(gChallenger_index__racestrt, 0);
}
ChallengeOccurred(gChallenger_index__racestrt, pEscaped == 0);
if (pTimed_out) {
return 0;
} else {
return pCurrent_choice;
}
}
// IDA: void __cdecl DoChallengeScreen()
void DoChallengeScreen(void) {
static tFlicette flicker_on[2] = { { 43, { 54, 108 }, { 157, 377 } }, { 43, { 218, 436 }, { 157, 377 } } };
static tFlicette flicker_off[2] = { { 42, { 54, 108 }, { 157, 377 } }, { 42, { 218, 436 }, { 157, 377 } } };
static tFlicette push[2] = { { 304, { 54, 108 }, { 157, 377 } }, { 305, { 218, 436 }, { 157, 377 } } };
static tMouse_area mouse_areas[2] = {
{ { 54, 108 }, { 157, 377 }, { 117, 234 }, { 178, 427 }, 0, 0, 0, NULL },
{ { 218, 436 }, { 157, 377 }, { 281, 562 }, { 178, 427 }, 1, 0, 0, NULL }
};
static tInterface_spec interface_spec = {
0, // initial_imode
301, // first_opening_flic
0, // second_opening_flic
-1, // end_flic_go_ahead
-1, // end_flic_escaped
-1, // end_flic_otherwise
0, // flic_bunch_to_load
{ -1, 0 }, // move_left_new_mode
{ -1, 0 }, // move_left_delta
{ 0, 0 }, // move_left_min
{ 1, 0 }, // move_left_max
{ NULL, NULL }, // move_left_proc
{ -1, 0 }, // move_right_new_mode
{ 1, 0 }, // move_right_delta
{ 0, 0 }, // move_right_min
{ 1, 0 }, // move_right_max
{ NULL, NULL }, // move_right_proc
{ -1, 0 }, // move_up_new_mode
{ 0, 0 }, // move_up_delta
{ 0, 0 }, // move_up_min
{ 0, 0 }, // move_up_max
{ NULL, NULL }, // move_up_proc
{ -1, 0 }, // move_down_new_mode
{ 0, 0 }, // move_down_delta
{ 0, 0 }, // move_down_min
{ 0, 0 }, // move_down_max
{ NULL, NULL }, // move_down_proc
{ 1, 1 }, // go_ahead_allowed
{ NULL, NULL }, // go_ahead_proc
{ 1, 1 }, // escape_allowed
{ NULL, NULL }, // escape_proc
&CheckNextStage, // exit_proc
&GridDraw, // draw_proc
0u, // time_out
NULL, // start_proc1
&ChallengeStart, // start_proc2
&ChallengeDone, // done_proc
0, // font_needed
{ 0, 0 }, // typeable
NULL, // get_original_string
1, // escape_code
1, // dont_save_or_load
2, // number_of_button_flics
flicker_on, // flicker_on_flics
flicker_off, // flicker_off_flics
push, // pushed_flics
2, // number_of_mouse_areas
mouse_areas, // mouse_areas
0, // number_of_recopy_areas
NULL // recopy_areas
};
//int result; // Pierre-Marie Baty -- unused variable
LOG_TRACE("()");
gOriginal_position = gOur_starting_position;
gChallenger_position = IRandomBetween(0, 1);
if (gOpponents[gCurrent_race.opponent_list[gChallenger_position].index].car_number < 0) {
gChallenger_position ^= 1u;
}
gChallenger_index__racestrt = gCurrent_race.opponent_list[gChallenger_position].index;
LoadOpponentMugShot(gChallenger_index__racestrt);
gDraw_grid_status = eGrid_draw_none;
gGrid_y_adjust = gCurrent_graf_data->dare_y_adjust;
DoInterfaceScreen(&interface_spec, 0, 0);
}
// IDA: int __usercall GridDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
int GridDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
if (pTimed_out) {
return 0;
}
if (pEscaped) {
return -1;
}
return pCurrent_choice;
}
// IDA: void __cdecl GridStart()
void GridStart(void) {
LOG_TRACE("()");
MoveGrid(-2, CalcGridOffset(gOur_starting_position), 400);
PrintMemoryDump(0, "IN GRID SCREEN");
}
// IDA: int __usercall GridMoveLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int GridMoveLeft(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (gOur_starting_position
&& gCurrent_race.opponent_list[gOur_starting_position - 1].ranking >= gProgram_state.rank) {
AddToFlicQueue(
gStart_interface_spec->pushed_flics[1].flic_index,
gStart_interface_spec->pushed_flics[1].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[1].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
DoGridTransition(gOur_starting_position, gOur_starting_position - 1);
}
return 0;
}
// IDA: int __usercall GridMoveRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int GridMoveRight(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (gOur_starting_position < gCurrent_race.number_of_racers - 1) {
AddToFlicQueue(
gStart_interface_spec->pushed_flics[2].flic_index,
gStart_interface_spec->pushed_flics[2].x[gGraf_data_index],
gStart_interface_spec->pushed_flics[2].y[gGraf_data_index],
1);
DRS3StartSound(gEffects_outlet, 3000);
DoGridTransition(gOur_starting_position, gOur_starting_position + 1);
}
return 0;
}
// IDA: int __usercall GridClickCar@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int GridClickCar(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
int rel_pos;
int new_pos;
//int base_pos; // Pierre-Marie Baty -- unused variable
int x_coord;
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
rel_pos = ((gCurrent_graf_data->grid_bottom_clip - gCurrent_graf_data->grid_top_clip) / 2) < pY_offset;
if (rel_pos) {
pX_offset -= gCurrent_graf_data->grid_x_stagger;
}
x_coord = pX_offset / gCurrent_graf_data->grid_x_pitch;
if (x_coord > 2) {
x_coord = 2;
}
new_pos = 2 * x_coord + rel_pos + (gOur_starting_position & ~1) - 2;
if (new_pos >= 0 && new_pos < gCurrent_race.number_of_racers && gProgram_state.rank < gCurrent_race.opponent_list[new_pos].ranking) {
DRS3StartSound(gEffects_outlet, 3000);
DoGridTransition(gOur_starting_position, new_pos);
}
return 0;
}
// IDA: int __usercall GridClickNumbers@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int GridClickNumbers(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
int new_pos;
int i;
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
new_pos = -1;
for (i = 0; i < gCurrent_race.number_of_racers; i++) {
if (gGrid_number_x_coords[i] <= pX_offset && (gCurrent_race.number_of_racers - 1 == i || pX_offset < gGrid_number_x_coords[i + 1])) {
new_pos = i;
break;
}
}
if (new_pos >= 0 && new_pos < gCurrent_race.number_of_racers && gProgram_state.rank <= gCurrent_race.opponent_list[new_pos].ranking) {
DRS3StartSound(gEffects_outlet, 3000);
DoGridTransition(gOur_starting_position, new_pos);
}
return 0;
}
// IDA: int __usercall GridClickLeft@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int GridClickLeft(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
GridMoveLeft(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall GridClickRight@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
int GridClickRight(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) {
LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset);
GridMoveRight(pCurrent_choice, pCurrent_mode);
return 0;
}
// IDA: int __usercall CheckChallenge@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int CheckChallenge(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE8("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (!gChallenge_time || PDGetTotalTime() < gChallenge_time) {
return 0;
}
*pCurrent_choice = -2;
return 1;
}
// IDA: int __usercall FindBestPos@<EAX>(int pOur_rank@<EAX>)
int FindBestPos(int pOur_rank) {
int i;
LOG_TRACE("(%d)", pOur_rank);
for (i = gCurrent_race.number_of_racers - 1; i >= 0; i--) {
if (gCurrent_race.opponent_list[i].ranking < pOur_rank) {
return i + 1;
}
}
return 0;
}
// IDA: int __usercall SortGridFunction@<EAX>(void *pFirst_one@<EAX>, void *pSecond_one@<EDX>)
int SortGridFunction(const void* pFirst_one, const void* pSecond_one) {
LOG_TRACE("(%p, %p)", pFirst_one, pSecond_one);
return ((tOpp_spec*)pFirst_one)->ranking - ((tOpp_spec*)pSecond_one)->ranking;
}
// IDA: void __cdecl SortOpponents()
void SortOpponents(void) {
int i;
LOG_TRACE("()");
for (i = 0; gCurrent_race.number_of_racers > i; ++i) {
if (gCurrent_race.opponent_list[i].index < 0) {
return;
}
}
qsort(gCurrent_race.
opponent_list, gCurrent_race.
number_of_racers, sizeof(tOpp_spec
), SortGridFunction
);
gBest_pos_available = FindBestPos(gProgram_state.rank);
gOur_starting_position = gCurrent_race.number_of_racers - 70 * (gCurrent_race.number_of_racers - gBest_pos_available) / 100;
for (i = gCurrent_race.number_of_racers; i > gOur_starting_position; i--) {
gCurrent_race.opponent_list[i] = gCurrent_race.opponent_list[i - 1];
}
gCurrent_race.opponent_list[gOur_starting_position].index = -1;
gCurrent_race.opponent_list[gOur_starting_position].ranking = gProgram_state.rank;
gCurrent_race.opponent_list[gOur_starting_position].car_spec = &gProgram_state.current_car;
gCurrent_race.number_of_racers++;
}
// IDA: tSO_result __cdecl DoGridPosition()
tSO_result DoGridPosition(void) {
static tFlicette flicker_on[3] = {
{ 43, { 240, 480 }, { 158, 379 } },
{ 293, { 56, 112 }, { 151, 362 } },
{ 296, { 136, 272 }, { 151, 362 } }
};
static tFlicette flicker_off[3] = {
{ 42, { 240, 480 }, { 158, 379 } },
{ 292, { 56, 112 }, { 151, 362 } },
{ 295, { 136, 272 }, { 151, 362 } }
};
static tFlicette push[3] = {
{ 154, { 240, 480 }, { 158, 379 } },
{ 294, { 56, 112 }, { 151, 362 } },
{ 297, { 136, 272 }, { 151, 362 } }
};
static tMouse_area mouse_areas[5] = {
{ { 240, 480 }, { 158, 379 }, { 305, 610 }, { 178, 427 }, 0, 0, 0, NULL },
{ { 56, 112 },
{ 151, 362 },
{ 91, 182 },
{ 158, 379 },
-1,
0,
0,
GridClickLeft },
{ { 136, 272 },
{ 151, 362 },
{ 171, 342 },
{ 158, 379 },
-1,
0,
0,
GridClickRight },
{ { 52, 104 },
{ 56, 134 },
{ 269, 538 },
{ 141, 338 },
-1,
0,
0,
GridClickCar },
{ { 60, 120 },
{ 163, 391 },
{ 235, 470 },
{ 176, 422 },
-1,
0,
0,
GridClickNumbers }
};
static tInterface_spec interface_spec = {
0, // initial_imode
290, // first_opening_flic
0, // second_opening_flic
0, // end_flic_go_ahead
0, // end_flic_escaped
0, // end_flic_otherwise
8, // flic_bunch_to_load
{ -1, 0 }, // move_left_new_mode
{ 0, 0 }, // move_left_delta
{ 0, 0 }, // move_left_min
{ 0, 0 }, // move_left_max
{ GridMoveLeft, NULL }, // move_left_proc
{ -1, 0 }, // move_right_new_mode
{ 0, 0 }, // move_right_delta
{ 0, 0 }, // move_right_min
{ 0, 0 }, // move_right_max
{ GridMoveRight, NULL }, // move_right_proc
{ -1, 0 }, // move_up_new_mode
{ 0, 0 }, // move_up_delta
{ 0, 0 }, // move_up_min
{ 0, 0 }, // move_up_max
{ GridMoveLeft, NULL }, // move_up_proc
{ -1, 0 }, // move_down_new_mode
{ 0, 0 }, // move_down_delta
{ 0, 0 }, // move_down_min
{ 0, 0 }, // move_down_max
{ GridMoveRight, NULL }, // move_down_proc
{ 1, 1 }, // go_ahead_allowed
{ NULL, NULL }, // go_ahead_proc
{ 1, 1 }, // escape_allowed
{ NULL, NULL }, // escape_proc
CheckChallenge, // exit_proc
GridDraw, // draw_proc
0u, // time_out
NULL, // start_proc1
GridStart, // start_proc2
GridDone, // done_proc
0, // font_needed
{ 0, 0 }, // typeable
NULL, // get_original_string
-1, // escape_code
1, // dont_save_or_load
3, // number_of_button_flics
flicker_on, // flicker_on_flics
flicker_off, // flicker_off_flics
push, // pushed_flics
5, // number_of_mouse_areas
mouse_areas, // mouse_areas
0, // number_of_recopy_areas
NULL // recopy_areas
};
int result;
LOG_TRACE("()");
gStart_interface_spec = &interface_spec;
if (!gAusterity_mode) {
LoadGridIcons(&gCurrent_race);
}
gSwap_grid_1 = -1;
gSwap_grid_2 = -1;
gDraw_grid_status = eGrid_draw_all;
gGrid_y_adjust = 0;
SortOpponents();
if (!gAusterity_mode) {
if (gBest_pos_available > 1
&& (gOpponents[gCurrent_race.opponent_list[0].index].car_number >= 0
|| gOpponents[gCurrent_race.opponent_list[1].index].car_number >= 0)
&& PercentageChance(10)) {
gChallenge_time = PDGetTotalTime() + IRandomBetween(1000, 10000);
} else {
gChallenge_time = 0;
}
result = DoInterfaceScreen(&interface_spec, 0, 0);
if (result >= 0) {
FadePaletteDown();
} else {
RunFlic(291);
}
if (result == -1) {
return eSO_main_menu_invoked;
}
if (result == -2) {
DoChallengeScreen();
}
DisposeGridIcons(&gCurrent_race);
}
return eSO_continue;
}
// IDA: void __cdecl CheckPlayersAreResponding()
void CheckPlayersAreResponding(void) {
int i;
tNet_message* message;
LOG_TRACE("()");
for (i = 0; i < gNumber_of_net_players; i++) {
if (i
!= gThis_net_player_index
&& time - gNet_players
[i
].
last_heard_from_him > 20000) {
gNet_players[i].player_status = ePlayer_status_not_responding;
}
}
if (gNet_mode == eNet_mode_client && gLast_host_query == 0) {
message = NetBuildMessage(NETMSGID_HOSTQUERY, 0);
NetGuaranteedSendMessageToHost(gCurrent_net_game, message, NULL);
}
}
// IDA: void __cdecl NetSynchStartStart()
void NetSynchStartStart(void) {
LOG_TRACE("()");
CheckPlayersAreResponding();
}
// IDA: void __usercall DrawAnItem(int pX@<EAX>, int pY_index@<EDX>, int pFont_index@<EBX>, char *pText@<ECX>)
// Suffix added to avoid duplicate symbol
void DrawAnItem__racestrt(int pX, int pY_index, int pFont_index, char* pText) {
LOG_TRACE("(%d, %d, %d, \"%s\")", pX, pY_index, pFont_index, pText);
TransBrPixelmapText(gBack_screen,
pX,
gCurrent_graf_data->start_synch_top + gCurrent_graf_data->start_synch_y_pitch * pY_index,
pFont_index,
gFont_7,
pText);
}
// IDA: void __usercall NetSynchStartDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
void NetSynchStartDraw(int pCurrent_choice, int pCurrent_mode) {
int i;
int number_ready;
char s[256];
LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
number_ready = 0;
CheckPlayersAreResponding();
NetPlayerStatusChanged(ePlayer_status_ready);
for (i = 0; i < COUNT_OF(gNet_players); i++) {
BrPixelmapRectangleFill(gBack_screen,
gCurrent_graf_data->start_synch_x_0,
gCurrent_graf_data->start_synch_y_pitch * i + gCurrent_graf_data->start_synch_top,
gCurrent_graf_data->start_synch_x_r - gCurrent_graf_data->start_synch_x_1,
gFont_7->glyph_y,
0);
}
for (i = 0; i < gNumber_of_net_players; i++) {
strcpy(s
, gNet_players
[i
].
player_name);
if (gNet_players[i].host) {
strcat(s
, GetMiscString
(kMiscString_HOST
));
}
TurnOffPaletteConversion();
DRPixelmapRectangleMaskedCopy(gBack_screen,
gCurrent_graf_data->start_synch_x_0,
gCurrent_graf_data->start_synch_top + 1 + gCurrent_graf_data->start_synch_y_pitch * i,
gIcons_pix_low_res, /* DOS version uses low res, Windows version uses normal res */
0,
gNet_players[i].car_index * gCurrent_graf_data->net_head_icon_height,
gIcons_pix_low_res->width, /* DOS version uses low res, Windows version uses normal res */
gCurrent_graf_data->net_head_icon_height);
TurnOnPaletteConversion();
DrawAnItem__racestrt(
gCurrent_graf_data->start_synch_x_1,
i,
(gNet_players[i].player_status == ePlayer_status_ready) ? 66 : 4,
s);
DrawAnItem__racestrt(gCurrent_graf_data->start_synch_x_2,
i,
(gNet_players[i].player_status == ePlayer_status_ready) ? 83 : ((gNet_players[i].player_status == ePlayer_status_not_responding) ? 247 : 4),
GetMiscString(kMiscString_NetworkPlayerStatus_START + gNet_players[i].player_status));
if (gNet_players[i].player_status == ePlayer_status_ready) {
number_ready++;
}
}
if (gNet_mode == eNet_mode_host && gNumber_of_net_players == number_ready && gNumber_of_net_players > 1 && (!gNo_races_yet || gNumber_of_net_players == 6)) {
SignalToStartRace();
gSynch_race_start = 1;
}
}
// IDA: int __usercall NetSynchStartDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, int pTimed_out)
int NetSynchStartDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) {
LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out);
if (pEscaped) {
pCurrent_choice = -1;
} else if (pCurrent_choice == 0) {
gProgram_state.prog_status = eProg_idling;
}
return pCurrent_choice;
}
// IDA: int __usercall NetSynchStartGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int NetSynchStartGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (*pCurrent_choice == 0 || (gNet_mode == eNet_mode_host && *pCurrent_choice >= 0)) {
if (*pCurrent_choice == 0) {
gProgram_state.prog_status = eProg_idling;
return 1;
} else if (gNet_mode == eNet_mode_host && *pCurrent_choice == 1) {
if (gNumber_of_net_players <= 1) {
DRS3StartSound(gEffects_outlet, 3100);
return 0;
} else {
SignalToStartRace();
gSynch_race_start = 1;
gNo_races_yet = 0;
return 1;
}
} else {
return 1;
}
} else {
DRS3StartSound(gEffects_outlet, 3100);
return 0;
}
}
// IDA: int __usercall ExitWhenReady@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
int ExitWhenReady(int* pCurrent_choice, int* pCurrent_mode) {
LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
if (!gSynch_race_start && gProgram_state.prog_status != eProg_game_starting) {
if (gProgram_state.prog_status == eProg_idling) {
*pCurrent_choice = 0;
return 1;
} else {
return 0;
}
} else {
*pCurrent_choice = 1;
return 1;
}
}
// IDA: tSO_result __usercall NetSynchRaceStart2@<EAX>(tNet_synch_mode pMode@<EAX>)
tSO_result NetSynchRaceStart2(tNet_synch_mode pMode) {
static tFlicette flicker_on_hf[2] = {
{ 321, { 219, 112 }, { 172, 362 } },
{ 321, { 39, 480 }, { 172, 379 } },
};
static tFlicette flicker_off_hf[2] = {
{ 322, { 219, 112 }, { 172, 362 } },
{ 322, { 39, 480 }, { 172, 379 } },
};
static tFlicette push_hf[2] = {
{ 206, { 219, 112 }, { 172, 362 } },
{ 205, { 39, 480 }, { 172, 379 } },
};
static tMouse_area mouse_areas_hf[2] = {
{ { 219, 480 }, { 172, 379 }, { 282, 182 }, { 192, 427 }, 0, 0, 0, NULL },
{ { 39, 112 }, { 172, 362 }, { 102, 182 }, { 192, 379 }, 1, 0, 0, NULL },
};
static tInterface_spec interface_spec_hf = {
0,
203,
0,
0,
0,
0,
8,
{ -1, 0 },
{ 1, 0 },
{ 0, 0 },
{ 1, 0 },
{ NULL, NULL },
{ -1, 0 },
{ 1, 0 },
{ 0, 0 },
{ 1, 0 },
{ NULL, NULL },
{ -1, 0 },
{ 1, 0 },
{ 0, 0 },
{ 1, 0 },
{ NULL, NULL },
{ -1, 0 },
{ 1, 0 },
{ 0, 0 },
{ 1, 0 },
{ NULL, NULL },
{ 1, 1 },
{ NetSynchStartGoAhead, NetSynchStartGoAhead },
{ 1, 1 },
{ NULL, NULL },
ExitWhenReady,
NetSynchStartDraw,
0,
NULL,
NetSynchStartStart,
NetSynchStartDone,
0,
{ 0, 0 },
NULL,
-1,
1,
COUNT_OF(flicker_on_hf),
flicker_on_hf,
flicker_off_hf,
push_hf,
COUNT_OF(mouse_areas_hf),
mouse_areas_hf,
0,
NULL,
};
static tFlicette flicker_on_hs[1] = {
{ 321, { 219, 112 }, { 172, 362 } },
};
static tFlicette flicker_off_hs[1] = {
{ 322, { 219, 112 }, { 172, 362 } },
};
static tFlicette push_hs[1] = {
{ 206, { 219, 112 }, { 172, 362 } },
};
static tMouse_area mouse_areas_hs[1] = {
{ { 219, 480 }, { 172, 379 }, { 282, 182 }, { 192, 427 }, 0, 0, 0, NULL },
};
static tInterface_spec interface_spec_hs = {
0, 209, 0, 0, 0, 0, 8,
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ 1, 1 }, { NetSynchStartGoAhead, NetSynchStartGoAhead }, { 1, 1 }, { NULL, NULL },
ExitWhenReady, NetSynchStartDraw, 0, NULL, NetSynchStartStart, NetSynchStartDone, 0, { 0, 0 },
NULL, -1, 1,
COUNT_OF(flicker_on_hs), flicker_on_hs, flicker_off_hs, push_hs,
COUNT_OF(mouse_areas_hs), mouse_areas_hs, 0, NULL
};
static tFlicette flicker_on_c[1] = {
{ 321, { 219, 112 }, { 172, 362 } },
};
static tFlicette flicker_off_c[1] = {
{ 322, { 219, 112 }, { 172, 362 } },
};
static tFlicette push_c[1] = {
{ 207, { 219, 112 }, { 172, 362 } },
};
static tMouse_area mouse_areas_c[1] = {
{ { 219, 112 }, { 172, 362 }, { 282, 182 }, { 192, 379 }, 0, 0, 0, NULL },
};
static tInterface_spec interface_spec_c = {
0, 204, 0, 0, 0, 0, 8,
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL },
{ 1, 1 }, { NetSynchStartGoAhead, NetSynchStartGoAhead }, { 1, 1 }, { NULL, NULL },
ExitWhenReady, NetSynchStartDraw, 0, NULL, NetSynchStartStart, NetSynchStartDone, 0, { 0, 0 },
NULL, -1, 1,
COUNT_OF(flicker_on_c), flicker_on_c, flicker_off_c, push_c,
COUNT_OF(mouse_areas_c), mouse_areas_c, 0, NULL
};
int result;
LOG_TRACE("(%d)", pMode);
if (pMode != eNet_synch_client) {
if (gCurrent_net_game->status.stage == eNet_game_starting) {
gCurrent_net_game->status.stage = eNet_game_ready;
}
SetUpNetCarPositions();
// gNet_synch_start = PDGetTotalTime();
}
TurnOnPaletteConversion();
switch (pMode) {
case eNet_synch_host_first:
result = DoInterfaceScreen(&interface_spec_hf, 0, 1);
break;
case eNet_synch_host_subsequent:
result = DoInterfaceScreen(&interface_spec_hs, 0, -1);
break;
case eNet_synch_client:
result = DoInterfaceScreen(&interface_spec_c, 0, -1);
break;
default:
break;
}
TurnOffPaletteConversion();
FadePaletteDown();
if (result > -2 && result < 1) {
NetLeaveGame(gCurrent_net_game);
}
return eSO_continue;
}
// IDA: tSO_result __cdecl NetSynchRaceStart()
tSO_result NetSynchRaceStart(void) {
LOG_TRACE("()");
SuspendPendingFlic();
if (gNet_mode == eNet_mode_host) {
if (gNo_races_yet) {
return NetSynchRaceStart2(eNet_synch_host_first);
} else {
return NetSynchRaceStart2(eNet_synch_host_subsequent);
}
} else {
return NetSynchRaceStart2(eNet_synch_client);
}
}