From cff3ca54e07f7caa4de0dfbdf602a0cfb0c6c7c3 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Thu, 6 Jul 2023 12:56:48 +1200 Subject: [PATCH 01/40] SendCarData, ReceivedStartRace --- src/DETHRACE/common/netgame.c | 142 +++++++++++++++++++++++++++++++++- src/DETHRACE/common/network.c | 45 ++++++++++- src/DETHRACE/dr_types.h | 2 +- 3 files changed, 183 insertions(+), 6 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 75f51890..3a2a29af 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -1,6 +1,7 @@ #include "netgame.h" #include "brender/brender.h" #include "car.h" +#include "crush.h" #include "displays.h" #include "errors.h" #include "globvars.h" @@ -15,6 +16,7 @@ #include "pedestrn.h" #include "powerup.h" #include "racestrt.h" +#include "spark.h" #include "structur.h" #include "utility.h" #include @@ -30,6 +32,8 @@ tNet_game_player_info* gLast_lepper; int gInitialised_grid; int gIt_or_fox; +#define PACK_POWERUPS(car) (car->power_up_levels[0] & 0xff) + ((car->power_up_levels[2] & 0xff) << 6) + ((car->power_up_levels[1] & 0xff) << 3); + // IDA: void __usercall SendCarData(tU32 pNext_frame_time@) void SendCarData(tU32 pNext_frame_time) { tNet_contents* contents; @@ -42,8 +46,122 @@ void SendCarData(tU32 pNext_frame_time) { int damaged_wheels; LOG_TRACE("(%d)", pNext_frame_time); - if (gNet_mode) { - TELL_ME_IF_WE_PASS_THIS_WAY(); + time = GetRaceTime(); + if (gNet_mode == eNet_mode_none || (time > last_time && last_time + 80 > time)) { + return; + } + last_time = time; + contents = NetGetBroadcastContents(NETMSGID_TIMESYNC, 0); + contents->data.time_sync.race_start_time = gRace_start; + + if (gNet_mode == eNet_mode_host) { + for (i = 0; i < gNumber_of_net_players; i++) { + car = gNet_players[i].car; + if (car->disabled) { + continue; + } + damaged_wheels = car->damage_units[eDamage_lf_wheel].damage_level > 30 || car->damage_units[eDamage_rf_wheel].damage_level > 30 || car->damage_units[eDamage_lr_wheel].damage_level > 30 || car->damage_units[eDamage_rr_wheel].damage_level > 30; + contents = NetGetBroadcastContents(0xFu, damaged_wheels); + GetReducedMatrix(&contents->data.mech.mat, &car->car_master_actor->t.t.mat); + contents->data.mech.ID = gNet_players[i].ID; + contents->data.mech.time = pNext_frame_time; + BrVector3Copy(&contents->data.mech.omega, &car->omega); + BrVector3Copy(&contents->data.mech.v, &car->v); + contents->data.mech.curvature = (car->curvature / car->maxcurve * 32767.0f); + contents->data.mech.keys = car->keys; + contents->data.mech.keys.joystick_acc = (tU8)(car->joystick.acc >> 9); + contents->data.mech.keys.joystick_dec = (tU8)(car->joystick.dec >> 9); + contents->data.mech.revs = car->revs; + for (j = 0; j < COUNT_OF(contents->data.mech.d); j++) { + contents->data.mech.d[j] = car->oldd[j] / car->susp_height[j >> 1] * 255.0f; + } + for (j = 0; j < COUNT_OF(contents->data.mech.damage); j++) { + contents->data.mech.damage[j] = car->damage_units[j].damage_level; + } + contents->data.mech.front = car->bounds[1].min.v[2]; + contents->data.mech.back = car->bounds[1].max.v[2]; + contents->data.mech.powerups = PACK_POWERUPS(car); + contents->data.mech.repair_time = car->repair_time; + contents->data.mech.cc_coll_time = car->last_car_car_collision; + if (damaged_wheels) { + for (j = 0; j < COUNT_OF(contents->data.mech.wheel_dam_offset); j++) { + contents->data.mech.wheel_dam_offset[j] = car->wheel_dam_offset[j]; + } + } + if (car->time_to_recover != 0) { + if (car->time_to_recover - 500 < pNext_frame_time) { + contents = NetGetBroadcastContents(NETMSGID_RECOVER, 0); + contents->data.recover.ID = gNet_players[i].ID; + contents->data.recover.time_to_recover = car->time_to_recover; + } + } + } + for (i = 0; i < gNum_active_non_cars; i++) { + contents = NetGetBroadcastContents(NETMSGID_NONCAR_INFO, 0); + ncar = (tCollision_info*)gActive_non_car_list[i]; + GetReducedMatrix(&contents->data.mech.mat, &ncar->car_master_actor->t.t.mat); + contents->data.non_car.ID = ncar->car_ID; + contents->data.non_car.time = pNext_frame_time; + BrVector3Copy(&contents->data.non_car.omega, &ncar->omega); + BrVector3Copy(&contents->data.non_car.v, &ncar->v); + contents->data.non_car.flags = ncar->car_master_actor->identifier[3] == 2 * ncar->doing_nothing_flag + '!'; + } + for (i = 0; i < gProgram_state.AI_vehicles.number_of_cops; i++) { + if (!gProgram_state.AI_vehicles.cops[i].finished_for_this_race) { + contents = NetGetBroadcastContents(NETMSGID_COPINFO, 0); + car = gProgram_state.AI_vehicles.cops[i].car_spec; + GetReducedMatrix(&contents->data.mech.mat, &car->car_master_actor->t.t.mat); + contents->data.cop_info.ID = car->car_ID; + contents->data.cop_info.time = pNext_frame_time; + BrVector3Copy(&contents->data.cop_info.omega, &car->omega); + BrVector3Copy(&contents->data.cop_info.v, &car->v); + for (j = 0; j < COUNT_OF(contents->data.cop_info.damage); ++j) { + contents->data.cop_info.damage[j] = car->damage_units[j].damage_level; + } + for (j = 0; j < COUNT_OF(contents->data.cop_info.d); j++) { + contents->data.cop_info.d[j] = car->oldd[j]; + } + } + } + } else if (gNet_mode == eNet_mode_client) { + car = &gProgram_state.current_car; + if (car->disabled) { + return; + } + damaged_wheels = car->damage_units[eDamage_lf_wheel].damage_level > 30 || car->damage_units[eDamage_rf_wheel].damage_level > 30 || car->damage_units[eDamage_lr_wheel].damage_level > 30 || car->damage_units[eDamage_rr_wheel].damage_level > 30; + contents = NetGetToHostContents(NETMSGID_MECHANICS, damaged_wheels); + GetReducedMatrix(&contents->data.mech.mat, &gProgram_state.current_car.car_master_actor->t.t.mat); + contents->data.mech.ID = gNet_players[gThis_net_player_index].ID; + contents->data.mech.time = pNext_frame_time; + BrVector3Copy(&contents->data.mech.omega, &car->omega); + BrVector3Copy(&contents->data.mech.v, &car->v); + + contents->data.mech.curvature = car->curvature / car->maxcurve * 32767.0f; + contents->data.mech.keys = car->keys; + contents->data.mech.keys.joystick_acc = (tU8)(car->joystick.acc >> 9); + contents->data.mech.keys.joystick_dec = (tU8)(car->joystick.dec >> 9); + contents->data.mech.revs = car->revs; + contents->data.mech.cc_coll_time = car->last_car_car_collision; + for (j = 0; j < COUNT_OF(contents->data.mech.d); j++) { + contents->data.mech.d[j] = car->oldd[j] / car->susp_height[j >> 1] * 255.f; + } + for (j = 0; j < COUNT_OF(contents->data.mech.damage); j++) { + contents->data.mech.damage[j] = car->damage_units[j].damage_level; + } + contents->data.mech.front = car->bounds[1].min.v[2]; + contents->data.mech.back = car->bounds[1].max.v[2]; + contents->data.mech.powerups = PACK_POWERUPS(car); + contents->data.mech.repair_time = car->repair_time; + if (damaged_wheels) { + for (j = 0; j < COUNT_OF(contents->data.mech.wheel_dam_offset); j++) { + contents->data.mech.wheel_dam_offset[j] = car->wheel_dam_offset[j]; + } + } + if (car->time_to_recover > 0 && car->time_to_recover - 500 < pNext_frame_time) { + contents = NetGetToHostContents(NETMSGID_RECOVER, 0); + contents->data.recover.ID = gNet_players[gThis_net_player_index].ID; + contents->data.recover.time_to_recover = gProgram_state.current_car.time_to_recover; + } } } @@ -252,7 +370,14 @@ void SetUpNetCarPositions(void) { void ReinitialiseCar(tCar_spec* pCar) { int i; LOG_TRACE("(%p)", pCar); - NOT_IMPLEMENTED(); + + StopCarSmokingInstantly(pCar); + LoseAllLocalPowerups(pCar); + InitialiseCar(pCar); + TotallyRepairACar(pCar); + if (pCar->driver == eDriver_local_human) { + gLast_it_change = PDGetTotalTime() + 2000; + } } // IDA: void __usercall RepositionPlayer(int pIndex@) @@ -739,7 +864,16 @@ void RecievedCrushPoint(tNet_contents* pContents) { // IDA: void __usercall GetReducedMatrix(tReduced_matrix *m1@, br_matrix34 *m2@) void GetReducedMatrix(tReduced_matrix* m1, br_matrix34* m2) { LOG_TRACE("(%p, %p)", m1, m2); - NOT_IMPLEMENTED(); + + m1->row1.v[0] = m2->m[0][0]; + m1->row1.v[1] = m2->m[0][1]; + m1->row1.v[2] = m2->m[0][2]; + m1->row2.v[0] = m2->m[1][0]; + m1->row2.v[1] = m2->m[1][1]; + m1->row2.v[2] = m2->m[1][2]; + m1->translation.v[0] = m2->m[2][0]; + m1->translation.v[1] = m2->m[2][1]; + m1->translation.v[2] = m2->m[2][2]; } // IDA: void __usercall GetExpandedMatrix(br_matrix34 *m1@, tReduced_matrix *m2@) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 80421367..c47dc743 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -1316,7 +1316,50 @@ void ReceivedStartRace(tNet_contents* pContents) { int i; int index; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + if (pContents->data.player_list.number_of_players == -1) { + if (gProgram_state.racing) { + index = pContents->data.start_race.car_list[0].index; + BrMatrix34Copy(&gNet_players[index].car->car_master_actor->t.t.mat, &pContents->data.start_race.car_list[0].mat); + ReinitialiseCar(gNet_players[index].car); + if (gThis_net_player_index == index) { + if (!gInterface_within_race_mode) { + FadePaletteDown(); + } + CancelPendingCunningStunt(); + gProgram_state.credits_earned = gInitial_net_credits[gCurrent_net_game->options.starting_money_index]; + gProgram_state.credits_lost = 0; + InitialiseExternalCamera(); + } + gNet_players[index].last_waste_message = 0; + gNet_players[index].wasteage_attributed = 0; + } + } else if (gSynch_race_start) { + for (i = 0; i < pContents->data.start_race.car_count; i++) { + gNet_players[pContents->data.start_race.car_list[i].index].next_car_index = pContents->data.start_race.car_list[i].next_car_index; + } + } else { + for (i = 0; i < pContents->data.player_list.number_of_players; i++) { + gCurrent_race.number_of_racers = i + 1; + gCurrent_race.opponent_list[i].index = -1; + gCurrent_race.opponent_list[i].ranking = -1; + gCurrent_race.opponent_list[i].car_spec = gNet_players[pContents->data.start_race.car_list[i].index].car; + gCurrent_race.opponent_list[i].net_player_index = pContents->data.start_race.car_list[i].index; + gNet_players[gCurrent_race.opponent_list[i].net_player_index].last_waste_message = 0; + gNet_players[gCurrent_race.opponent_list[i].net_player_index].wasteage_attributed = 0; + if (!gProgram_state.racing || gCurrent_race.opponent_list[i].car_spec->driver != eDriver_local_human) { + BrMatrix34Copy(&gCurrent_race.opponent_list[i].car_spec->car_master_actor->t.t.mat, &pContents->data.start_race.car_list[i].mat); + InitialiseCar(gCurrent_race.opponent_list[i].car_spec); + } + gNet_players[pContents->data.start_race.car_list[i].index].next_car_index = pContents->data.start_race.car_list[i].next_car_index; + } + gPending_race = pContents->data.player_list.batch_number; + gCurrent_race.number_of_racers = pContents->data.player_list.number_of_players; + gSynch_race_start = 1; + if (!pContents->data.player_list.this_index || gProgram_state.racing) { + gWait_for_it = 0; + } + } } // IDA: void __usercall ReceivedGuaranteeReply(tNet_contents *pContents@) diff --git a/src/DETHRACE/dr_types.h b/src/DETHRACE/dr_types.h index 4d5bee35..f35b16c9 100644 --- a/src/DETHRACE/dr_types.h +++ b/src/DETHRACE/dr_types.h @@ -473,7 +473,7 @@ typedef struct tReduced_matrix { br_vector3 translation; } tReduced_matrix; -typedef struct tCar_controls { +typedef struct tCar_controls { // size: 0x4 int joystick_acc : 8; int joystick_dec : 8; unsigned int left : 1; // 0x10000 bit 17 From 60356fc39d6529dc7e9892fa8e2e2960a70a5f85 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Thu, 6 Jul 2023 13:13:50 +1200 Subject: [PATCH 02/40] fixes heap overflow during join --- src/DETHRACE/CMakeLists.txt | 4 ++-- src/DETHRACE/common/network.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DETHRACE/CMakeLists.txt b/src/DETHRACE/CMakeLists.txt index 76b864aa..7d645432 100644 --- a/src/DETHRACE/CMakeLists.txt +++ b/src/DETHRACE/CMakeLists.txt @@ -10,8 +10,8 @@ target_include_directories(dethrace_obj pd ) -# add_compile_options(-fsanitize=address) -# add_link_options(-fsanitize=address) +add_compile_options(-fsanitize=address) +add_link_options(-fsanitize=address) target_link_libraries(dethrace_obj PUBLIC SDL2::SDL2 smackw32 harness brender s3) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index c47dc743..7a27fb1a 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -1075,7 +1075,7 @@ void ReceivedJoin(tNet_contents* pContents, void* pSender_address) { LOG_TRACE("(%p, %p)", pContents, pSender_address); new_player_count = gNumber_of_net_players; - new_players = BrMemAllocate(new_player_count + 1 * sizeof(tNet_game_player_info), kMem_player_list_join); + new_players = BrMemAllocate((new_player_count + 1) * sizeof(tNet_game_player_info), kMem_player_list_join); memcpy(new_players, gNet_players, gNumber_of_net_players * sizeof(tNet_game_player_info)); if ((!gCurrent_net_game->options.open_game && gProgram_state.racing) || gCurrent_net_game->num_players > 5 || gDont_allow_joiners) { From b0c21e7d4da7baa9ab831287d0db542545f12fdf Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Thu, 6 Jul 2023 13:36:09 +1200 Subject: [PATCH 03/40] fixes access on possibly-null pDetails --- src/DETHRACE/common/netgame.c | 3 ++- src/DETHRACE/pc-win95/win95net.c | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 3a2a29af..31b37760 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -527,7 +527,8 @@ void DoNetScores2(int pOnly_sort_scores) { // IDA: void __cdecl DoNetScores() void DoNetScores(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + DoNetScores2(0); } // IDA: void __cdecl InitNetHeadups() diff --git a/src/DETHRACE/pc-win95/win95net.c b/src/DETHRACE/pc-win95/win95net.c index 57a31891..bd4875ad 100644 --- a/src/DETHRACE/pc-win95/win95net.c +++ b/src/DETHRACE/pc-win95/win95net.c @@ -640,9 +640,6 @@ int PDNetSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessag LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pAddress); NetNowIPXLocalTarget2String(str, (struct sockaddr_in*)pAddress); - if (pDetails->pd_net_info.addr_in.sin_port == 0) { - int i = 0; - } if (sendto(gSocket, (const char*)pMessage, pMessage->overall_size, 0, (const struct sockaddr*)pAddress, sizeof(struct sockaddr)) == -1) { dr_dprintf("PDNetSendMessageToAddress(): Error on sendto() - WSAGetLastError=%d", WSAGetLastError()); From e25bbd8225a4ef67ffb04de60ae2855b09481f48 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Thu, 6 Jul 2023 14:17:19 +1200 Subject: [PATCH 04/40] DoNetScores --- src/DETHRACE/common/netgame.c | 142 +++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 3 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 31b37760..ff06798f 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -6,6 +6,7 @@ #include "errors.h" #include "globvars.h" #include "globvrpb.h" +#include "grafdata.h" #include "graphics.h" #include "harness/trace.h" #include "loading.h" @@ -19,6 +20,7 @@ #include "spark.h" #include "structur.h" #include "utility.h" +#include #include #include @@ -496,13 +498,30 @@ int SortNetHeadAscending(void* pFirst_one, void* pSecond_one) { // IDA: int __usercall SortNetHeadDescending@(void *pFirst_one@, void *pSecond_one@) int SortNetHeadDescending(void* pFirst_one, void* pSecond_one) { LOG_TRACE("(%p, %p)", pFirst_one, pSecond_one); - NOT_IMPLEMENTED(); + + if (((tHeadup_pair*)pFirst_one)->out_of_game) { + if (((tHeadup_pair*)pSecond_one)->out_of_game) { + return ((tHeadup_pair*)pFirst_one)->out_of_game - ((tHeadup_pair*)pSecond_one)->out_of_game; + } else { + return INT_MAX; + } + } else if (((tHeadup_pair*)pSecond_one)->out_of_game) { + return -INT_MAX; + } else if (((tHeadup_pair*)pSecond_one)->score == ((tHeadup_pair*)pFirst_one)->score) { + return gNet_players[((tHeadup_pair*)pFirst_one)->player_index].last_score_index + - gNet_players[((tHeadup_pair*)pSecond_one)->player_index].last_score_index; + } else { + return ((tHeadup_pair*)pSecond_one)->score - ((tHeadup_pair*)pFirst_one)->score; + } } // IDA: void __usercall ClipName(char *pName@, tDR_font *pFont@, int pMax_width@) void ClipName(char* pName, tDR_font* pFont, int pMax_width) { LOG_TRACE("(\"%s\", %p, %d)", pName, pFont, pMax_width); - NOT_IMPLEMENTED(); + + while (DRTextWidth(pFont, pName) > pMax_width) { + pName[strlen(pName) - 1] = 0; + } } // IDA: void __usercall DoNetScores2(int pOnly_sort_scores@) @@ -521,7 +540,124 @@ void DoNetScores2(int pOnly_sort_scores) { static int flash_state; tHeadup_pair headup_pairs[6]; LOG_TRACE("(%d)", pOnly_sort_scores); - NOT_IMPLEMENTED(); + + ascending_order = gCurrent_net_game->type == eNet_game_type_checkpoint || gCurrent_net_game->type == eNet_game_type_tag; + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].player_status < ePlayer_status_racing) { + headup_pairs[i].player_index = -1; + if (ascending_order) { + headup_pairs[i].score = 1000001; + } else { + headup_pairs[i].score = -1000001; + } + headup_pairs[i].out_of_game = 1000; + } else { + headup_pairs[i].player_index = i; + headup_pairs[i].score = gNet_players[i].score; + if (abs(gNet_players[i].score) != 1000000 && (gNet_players[i].score >= 0 || gCurrent_net_game->type == eNet_game_type_car_crusher)) { + headup_pairs[i].out_of_game = 0; + } else { + headup_pairs[i].out_of_game = gNet_players[i].last_score_index + 1; + } + } + } + for (i = gNumber_of_net_players; i < COUNT_OF(headup_pairs); i++) { + headup_pairs[i].player_index = -1; + if (ascending_order) { + headup_pairs[i].score = 1000001; + } else { + headup_pairs[i].score = -1000001; + } + headup_pairs[i].out_of_game = 1000; + } + qsort(headup_pairs, COUNT_OF(headup_pairs), sizeof(tHeadup_pair), ascending_order ? SortNetHeadAscending : SortNetHeadDescending); + + right_edge = gCurrent_graf_data->net_head_box_x + gCurrent_graf_data->net_head_box_width + 5 * gCurrent_graf_data->net_head_box_pitch; + for (i = 0; i < COUNT_OF(headup_pairs); i++) { + index = headup_pairs[i].player_index; + if (index >= 0) { + gNet_players[index].last_score_index = i; + } + if (pOnly_sort_scores) { + continue; + } + x = gCurrent_graf_data->net_head_box_x + i * gCurrent_graf_data->net_head_box_pitch; + if (gCurrent_graf_data->net_head_box_bot > gProgram_state.current_render_top) { + DimRectangle(gBack_screen, x, gCurrent_graf_data->net_head_box_top, x + gCurrent_graf_data->net_head_box_width, gCurrent_graf_data->net_head_box_bot, 1); + } + if (index >= 0) { + Flash(200, &last_flash, &flash_state); + if (flash_state + || (gCurrent_net_game->type != eNet_game_type_tag && gCurrent_net_game->type != eNet_game_type_foxy) + || index != gIt_or_fox) { + if (gNet_players[index].name_not_clipped) { + ClipName(gNet_players[index].player_name, &gFonts[6], gCurrent_graf_data->net_head_box_width - gCurrent_graf_data->net_head_name_x_marg - 2); + gNet_players[index].name_not_clipped = 0; + } + TransDRPixelmapText(gBack_screen, x + gCurrent_graf_data->net_head_name_x_marg, gCurrent_graf_data->net_head_name_y, &gFonts[6], gNet_players[index].player_name, right_edge); + } + if (abs(gNet_players[index].score) == 1000000) { + if (flash_state) { + strcpy(s, GetMiscString(173)); + } else { + s[0] = '\0'; + } + } else { + switch (gCurrent_net_game->type) { + case eNet_game_type_fight_to_death: + sprintf(s, "%d%%", gNet_players[index].score); + break; + case eNet_game_type_car_crusher: + case eNet_game_type_carnage: + sprintf(s, "%d", gNet_players[index].score); + break; + case eNet_game_type_checkpoint: + sprintf(s, "%d left", gNet_players[index].score >> 16); + break; + case eNet_game_type_sudden_death: + if (gNet_players[index].score < 0) { + if (flash_state) { + sprintf(s, "%s", GetMiscString(93)); + } else { + s[0] = '\0'; + } + } else { + score = gNet_players[index].score; + sprintf(s, "%s -%d-", GetMiscString(92), score); + } + break; + case eNet_game_type_tag: + case eNet_game_type_foxy: + if (gNet_players[index].score >= 0) { + if (index == gIt_or_fox && !flash_state) { + s[0] = '\0'; + } else { + TimerString(gNet_players[index].score, s, 0, 1); + } + } else { + sprintf(s, "%s", GetMiscString(93)); + } + break; + default: + break; + } + } + len = DRTextWidth(&gFonts[6], s); + TransDRPixelmapText(gBack_screen, x + gCurrent_graf_data->net_head_score_x - len, gCurrent_graf_data->net_head_score_y, &gFonts[6], s, right_edge); + DRPixelmapRectangleMaskedCopy(gBack_screen, x + gCurrent_graf_data->net_head_num_x, gCurrent_graf_data->net_head_num_y, gDigits_pix, 0, i * gCurrent_graf_data->net_head_num_height, gDigits_pix->width, gCurrent_graf_data->net_head_num_height); + DRPixelmapRectangleMaskedCopy(gBack_screen, x + gCurrent_graf_data->net_head_icon_x, gCurrent_graf_data->net_head_icon_y, gIcons_pix, 0, gCurrent_graf_data->net_head_icon_height * gNet_players[index].car_index, gIcons_pix->width, gCurrent_graf_data->net_head_icon_height); + if (gNet_players[index].ID == gLocal_net_ID) { + BrPixelmapLine(gBack_screen, x, gCurrent_graf_data->net_head_box_top, x, gCurrent_graf_data->net_head_box_bot - 1, 0); + BrPixelmapLine(gBack_screen, x + gCurrent_graf_data->net_head_box_width - 1, gCurrent_graf_data->net_head_box_top, x + gCurrent_graf_data->net_head_box_width - 1, gCurrent_graf_data->net_head_box_bot - 1, 0); + BrPixelmapLine(gBack_screen, x + 1, gCurrent_graf_data->net_head_box_bot, x + gCurrent_graf_data->net_head_box_width - 2, gCurrent_graf_data->net_head_box_bot, 0); + BrPixelmapLine(gBack_screen, x - 1, gCurrent_graf_data->net_head_box_top, x - 1, gCurrent_graf_data->net_head_box_bot - 1, 255); + BrPixelmapLine(gBack_screen, x + gCurrent_graf_data->net_head_box_width, gCurrent_graf_data->net_head_box_top, x + gCurrent_graf_data->net_head_box_width, gCurrent_graf_data->net_head_box_bot - 1, 255); + BrPixelmapLine(gBack_screen, x + 1, gCurrent_graf_data->net_head_box_bot + 1, x + gCurrent_graf_data->net_head_box_width - 2, gCurrent_graf_data->net_head_box_bot + 1, 255); + BrPixelmapPixelSet(gBack_screen, x, gCurrent_graf_data->net_head_box_bot, 255); + BrPixelmapPixelSet(gBack_screen, x + gCurrent_graf_data->net_head_box_width - 1, gCurrent_graf_data->net_head_box_bot, 255); + } + } + } } // IDA: void __cdecl DoNetScores() From c3dcf53c853a4cab5a922a3299b95d68555e700f Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 6 Jul 2023 13:29:28 +0200 Subject: [PATCH 05/40] Fix cast warning of comparefn of qsort --- src/DETHRACE/common/netgame.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index ff06798f..f26d02f8 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -570,7 +570,7 @@ void DoNetScores2(int pOnly_sort_scores) { } headup_pairs[i].out_of_game = 1000; } - qsort(headup_pairs, COUNT_OF(headup_pairs), sizeof(tHeadup_pair), ascending_order ? SortNetHeadAscending : SortNetHeadDescending); + qsort(headup_pairs, COUNT_OF(headup_pairs), sizeof(tHeadup_pair), (int(*)(const void*,const void*))(ascending_order ? SortNetHeadAscending : SortNetHeadDescending)); right_edge = gCurrent_graf_data->net_head_box_x + gCurrent_graf_data->net_head_box_width + 5 * gCurrent_graf_data->net_head_box_pitch; for (i = 0; i < COUNT_OF(headup_pairs); i++) { From af5c05cbc1a91576cc81291f9315f77346b62db3 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Fri, 7 Jul 2023 06:35:01 +1200 Subject: [PATCH 06/40] DisplayUserMessage --- src/DETHRACE/common/controls.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/DETHRACE/common/controls.c b/src/DETHRACE/common/controls.c index ea847e49..e325d58f 100644 --- a/src/DETHRACE/common/controls.c +++ b/src/DETHRACE/common/controls.c @@ -2489,7 +2489,36 @@ void DisplayUserMessage(void) { int len; tDR_font* font; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + font = &gFonts[FONT_NEWHITE]; + the_message = &gString[20]; + if (!gEntering_message || gNet_mode == eNet_mode_none) { + return; + } + + len = strlen(the_message); + if (len < 63 && (PDGetTotalTime() & 512) != 0) { + the_message[len] = '_'; + the_message[len + 1] = '\0'; + } + DimRectangle(gBack_screen, + 15 * gBack_screen->width / 100, + gCurrent_graf_data->net_message_enter_y - font->height, + 85 * gBack_screen->width / 100, + gCurrent_graf_data->net_message_enter_y + 6 * font->height, + 1); + + TransDRPixelmapText(gBack_screen, 20 * gBack_screen->width / 100, gCurrent_graf_data->net_message_enter_y, font, GetMiscString(227), 100); + OoerrIveGotTextInMeBoxMissus( + FONT_NEWHITE, + the_message, + gBack_screen, + 20 * gBack_screen->width / 100, + gCurrent_graf_data->net_message_enter_y + 2 * font->height, + 80 * gBack_screen->width / 100, + gCurrent_graf_data->net_message_enter_y + 6 * font->height, + 0); + the_message[len] = 0; } // IDA: void __cdecl InitAbuseomatic() From 1ba40667fc65d81b6b99f3a13a959e4308d90500 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 02:44:47 +0200 Subject: [PATCH 07/40] Pack tNet_contents on 4 byte boundary so 32-bit and 64-bit Intel cpu get same struct lay-out --- src/DETHRACE/dr_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DETHRACE/dr_types.h b/src/DETHRACE/dr_types.h index f35b16c9..d3d9b069 100644 --- a/src/DETHRACE/dr_types.h +++ b/src/DETHRACE/dr_types.h @@ -1340,6 +1340,7 @@ typedef struct tNet_message_crush_point { br_vector3 energy_vector; } tNet_message_crush_point; +#pragma pack(push, 4) typedef union tNet_contents { // size: 0x160 struct { // size: 0x2 tU8 contents_size; // @0x0 @@ -1380,6 +1381,7 @@ typedef union tNet_contents { // size: 0x160 tNet_message_crush_point crush; // @0x0 } data; // @0x0 } tNet_contents; +#pragma pack(pop) typedef struct tNet_message { // size: 0x17c tU32 pd_stuff_so_DO_NOT_USE; // @0x0 From 31cb9d5e32a03c9a6e1b6bf27eba8fc4045e37a8 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 02:45:16 +0200 Subject: [PATCH 08/40] Add a few static assertions to verify net message offsets --- src/DETHRACE/macros.h | 5 +++++ src/DETHRACE/pc-win95/win95net.c | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/DETHRACE/macros.h b/src/DETHRACE/macros.h index 5e961d87..15312314 100644 --- a/src/DETHRACE/macros.h +++ b/src/DETHRACE/macros.h @@ -1,6 +1,11 @@ #ifndef MACROS_H #define MACROS_H +#define DR_VALUE(V) V +#define DR_JOIN2(A,B) A##B +#define DRJOIN(A,B) DR_JOIN2(A, B) +#define DR_STATIC_ASSERT(V) typedef int DR_JOIN(dr_static_assert_, DR_VALUE(__COUNTER__))[(V)?1:-1] + #define VEHICLE_TYPE_FROM_ID(id) ((tVehicle_type)(id >> 8)) #define VEHICLE_INDEX_FROM_ID(id) ((id)&0x00ff) diff --git a/src/DETHRACE/pc-win95/win95net.c b/src/DETHRACE/pc-win95/win95net.c index bd4875ad..39448d20 100644 --- a/src/DETHRACE/pc-win95/win95net.c +++ b/src/DETHRACE/pc-win95/win95net.c @@ -56,6 +56,16 @@ int gSocket; #define MESSAGE_HEADER_STR "CW95MSG" #define JOINABLE_GAMES_CAPACITY 16 +DR_STATIC_ASSERT(offsetof(tNet_message, pd_stuff_so_DO_NOT_USE) == 0); +DR_STATIC_ASSERT(offsetof(tNet_message, magic_number) == 4); +DR_STATIC_ASSERT(offsetof(tNet_message, guarantee_number) == 8); +DR_STATIC_ASSERT(offsetof(tNet_message, sender) == 12); +DR_STATIC_ASSERT(offsetof(tNet_message, version) == 16); +DR_STATIC_ASSERT(offsetof(tNet_message, senders_time_stamp) == 20); +DR_STATIC_ASSERT(offsetof(tNet_message, num_contents) == 24); +DR_STATIC_ASSERT(offsetof(tNet_message, overall_size) == 26); +DR_STATIC_ASSERT(offsetof(tNet_message, contents) == 28); + // IDA: void __cdecl ClearupPDNetworkStuff() void ClearupPDNetworkStuff(void) { LOG_TRACE("()"); From 3fcf165d3cc475a8923598e2d3025ecbfa229d98 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 02:45:52 +0200 Subject: [PATCH 09/40] Add dethrace Wireshark dissector (WIP) --- tools/dethrace.lua | 542 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 tools/dethrace.lua diff --git a/tools/dethrace.lua b/tools/dethrace.lua new file mode 100644 index 00000000..e052a2e1 --- /dev/null +++ b/tools/dethrace.lua @@ -0,0 +1,542 @@ +dethrace_protocol = Proto("dethrace", "Dethrace Protocol") +DETHRACE_PORT = 12286 + +broadcast_types = { + [0x31] = "PING Request", + [0x32] = "PONG Response", +} + +content_types = { + [0x00] = "SendMeDetails", + [0x01] = "Details", + [0x02] = "Join", + [0x03] = "NewPlayerList", + [0x04] = "GuaranteeReply", + [0x05] = "CarDetailsReq", + [0x06] = "CarDetails", + [0x07] = "Leave", + [0x08] = "Hosticide", + [0x09] = "RaceOver", + [0x0a] = "StatusReport", + [0x0b] = "StartRace", + [0x0c] = "HeadUp", + [0x0d] = "HostQuery", + [0x0e] = "HostReply", + [0x0f] = "Mechanics", + [0x10] = "NonCar_Info", + [0x11] = "TimeSync", + [0x12] = "Confirm", + [0x13] = "DisableCar", + [0x14] = "EnableCar", + [0x15] = "PowerUp", + [0x16] = "Recover", + [0x17] = "Scores", + [0x18] = "Wasted", + [0x19] = "Pedestrian", + [0x1a] = "Gameplay", + [0x1b] = "NonCarPosition", + [0x1c] = "CopInfo", + [0x1d] = "GameScores", + [0x1e] = "OilSpill", + [0x1f] = "CrushPoint", + [0x20] = "None", +} + +f_checksum = ProtoField.uint32("dethrace.checksum", "Checksum") +f_broadcast_magic = ProtoField.string("dethrace.broadcast_magic", "Broadcast Magic", base.ASCII) +f_broadcast_type = ProtoField.char("dethrace.broadcast_type", "Broadcast Type", base.NONE, broadcast_types) + +f_terminator = ProtoField.char("dethrace.terminator", "Terminator") + +f_message_magic = ProtoField.uint32("dethrace.magic", "Magic", base.HEX) +f_message_guarantee = ProtoField.uint32("dethrace.guarantee", "Guarantee Number") +f_message_sender = ProtoField.uint32("dethrace.sender", "Sender Player ID") +f_message_version = ProtoField.int32("dethrace.version", "Version") +f_message_timestamp = ProtoField.uint32("dethrace.time", "Sender Time Stamp") +f_message_count = ProtoField.uint16("dethrace.count", "Count Contents") +f_message_size = ProtoField.uint16("dethrace.size", "Overall Size") + +f_contents_size = ProtoField.uint8("dethrace.content_size", "Content Size") +f_contents_type = ProtoField.uint8("dethrace.content_type", "Content Type", base.DEC, content_types) + +function create_message_size_type(parent, message, name) + local message_type = message(1, 1):uint() + local tree = parent:add(dethrace_protocol, message(), string.format("%s (%d)", name, message_type)) + tree:add_le(f_contents_size, message(0, 1)) + tree:add_le(f_contents_type, message(1, 1)) + return tree +end + +f_pd_player_info = ProtoField.bytes("dethrace.pd_info", "PD Net Info") + +function dissect_pd_player_info(tree, data) + tree:add_le(f_pd_player_info, data(0, 18)) +end + +function dissect_message_sendmedetails(tree, message) + -- tNet_message_send_me_details (0) + create_message_size_type(tree, message, "Send Me Details") + -- finished +end + +race_tracks = { + [0] = "Sumo", + [1] = "Coliseum", + [2] = "Maim Street", + [3] = "Coastal Carnage", + [4] = "Fridge Racer", + [5] = "Death Valley", + [6] = "Off Quay", + [7] = "Industrial Injury", + [8] = "Avenue of Atrocities", + [9] = "Terror on the Trails", + [10] = "MagnaChem Mayhem", + [11] = "Downtown Devastation", +} + +game_stages = { + [0] = "Starting", + [1] = "Ready", + [2] = "Playing", +} + +game_types = { + [0] = "Driven To Destruction", + [1] = "Car Crusher", + [2] = "Carnage", + [3] = "Checkpoint Stampede", + [4] = "Sudden Death", + [5] = "Terminal Tag", + [6] = "Fox 'n' Hounds", +} + +details_options_start_types = { + [0] = "Random Start", + [1] = "Grid Start", +} + +details_options_starting_money = { + [0] = "$0", + [1] = "$2,000", + [2] = "$5,000", + [3] = "$10,000", + [4] = "$20,000", +} + +details_options_car_choices = { + [0] = "Eagle", + [1] = "Hawk", + [2] = "Both", + [3] = "All", +} + +f_details_host_name = ProtoField.stringz("dethrace.details.host_name", "Host Name") +f_details_host_id = ProtoField.uint32("dethrace.details.host_id", "Host ID") +f_details_num_players = ProtoField.uint32("dethrace.details.num_players", "Number Players") +f_details_start_race = ProtoField.uint32("dethrace.details.start_race", "Start Race", base.DEC, race_tracks) +f_details_no_races_yet = ProtoField.bool("dethrace.details.no_races_yet", "No Races Yet") +f_details_status = ProtoField.uint32("dethrace.details.game_status", "Status", base.DEC, game_stages) +f_details_type = ProtoField.uint32("dethrace.details.type", "Type", base.DEC, game_types) + +f_details_option_show_players_on_map = ProtoField.bool("dethrace.details.options.players_on_map", "Show Players On Map") +f_details_option_show_peds_on_map = ProtoField.bool("dethrace.details.options.peds_on_map", "Show Peds On Map") +f_details_option_enable_text_messages = ProtoField.bool("dethrace.details.options.text_messages", "Enable Text Messages") +f_details_option_show_powerups_on_map = ProtoField.bool("dethrace.details.options.powerups_on_map", "Show Powerups On Map") +f_details_option_powerup_respawn = ProtoField.bool("dethrace.details.options.powerup_respawn", "Powerup Respawn") +f_details_option_open_game = ProtoField.bool("dethrace.details.options.open_game", "Open Game") +f_details_option_starting_money_index = ProtoField.uint32("dethrace.details.options.starting_money", "Starting Money", base.DEC, details_options_starting_money) +f_details_option_start_type = ProtoField.uint32("dethrace.details.options.start_Type", "Start Type", base.DEC, details_options_start_types) +f_details_option_race_end_target = ProtoField.uint32("dethrace.details.options.end_target", "Race End Target") +f_details_option_random_car_choice = ProtoField.bool("dethrace.details.options.random_car", "Random Cars") +f_details_option_race_sequence_type = ProtoField.uint32("dethrace.details.options.race_sequence_type", "Race Sequence Type") +f_details_option_car_choice = ProtoField.uint32("dethrace.details.options.car_choice", "Car Choice", base.DEC, details_options_car_choices) + +function dissect_game_details(tree, data) + -- tNet_game_options + tree:add_le(f_details_option_show_players_on_map, data(0, 4)) + tree:add_le(f_details_option_show_peds_on_map, data(4, 4)) + tree:add_le(f_details_option_enable_text_messages, data(8, 4)) + tree:add_le(f_details_option_show_powerups_on_map, data(12, 4)) + tree:add_le(f_details_option_powerup_respawn, data(16, 4)) + tree:add_le(f_details_option_open_game, data(20, 4)) + tree:add_le(f_details_option_starting_money_index, data(24, 4)) + tree:add_le(f_details_option_start_type, data(28, 4)) + tree:add_le(f_details_option_race_end_target, data(32, 4)) + tree:add_le(f_details_option_random_car_choice, data(36, 4)) + tree:add_le(f_details_option_race_sequence_type, data(40, 4)) + tree:add_le(f_details_option_car_choice, data(44, 4)) +end + +function dissect_message_details(tree, message) + -- tNet_message_my_details (1) + local t = create_message_size_type(tree, message, "Details") + dissect_pd_player_info(t, message(2)) + t:add(f_details_host_name, message(20, 32)) + t:add_le(f_details_host_id, message(52, 4)) + t:add_le(f_details_num_players, message(56, 4)) + t:add_le(f_details_start_race, message(60, 4)) + t:add_le(f_details_no_races_yet, message(64, 4)) + t:add_le(f_details_status, message(68, 4)) + do + local option_data = message(72, 48) + dissect_game_details(t:add(option_data, "Options"), option_data) + end + t:add_le(f_details_type, message(120, 4)) +end + +function dissect_game_player_info(tree, message) + -- tNet_game_player_info +end + +function dissect_message_join(tree, message) + -- tNet_message_join (2) + local t = create_message_size_type(tree, message, "Join (INCOMPLETE)") + local game_player_info_data = message(4) + dissect_game_player_info(t, game_player_info_data) +end + +function dissect_message_newplayerlist(tree, message) + -- tNet_message_new_player_list (3) + local t = create_message_size_type(tree, message, "New Player List") + -- FIXME +end + +f_guaranteereply_number = ProtoField.uint32("dethrace.guaranteereply.number", "Guarantee Number") + +function dissect_message_guaranteereply(tree, message) + -- tNet_message_guarantee_reply (4) + local t = create_message_size_type(tree, message, "Guarantee Reply") + t:add_le(f_guaranteereply_number, message(4, 4)) + -- FIXME: add reference to packet with this reply number + -- finished +end + +function dissect_message_cardetailsreq(tree, message) + -- tNet_message_car_details_req (5) + create_message_size_type(tree, message, "Car Details Req") + -- finished +end + +f_cardetails_count = ProtoField.uint32("dethrace.cardetails.count", "Car Count") +f_cardetails_car = ProtoField.uint32("dethrace.cardetails.car_index", "Car") +f_cardetails_owner = ProtoField.stringz("dethrace.cardetails.owner", "Owner") + +function dissect_message_cardetails(tree, message) + -- tNet_message_car_details (6) + local t = create_message_size_type(tree, message, "Car Details") + t:add_le(f_cardetails_count, message(4, 4)) + for i = 0, 5 do + local car_detail = message(8 + 20 * i, 20) + local subtree = t:add(car_detail, string.format("Car %d", i)) + subtree:add_le(f_cardetails_car, car_detail(0, 4)) + subtree:add(f_cardetails_owner, car_detail(4, 16)) + end + -- finished +end + +function dissect_message_leave(tree, message) + -- tNet_message_leave (7) + create_message_size_type(tree, message, "Leave") + -- finished +end + +function dissect_message_hosticide(tree, message) + -- tNet_message_host_pissing_off (8) + create_message_size_type(tree, message, "Hosticide") + -- finished +end + +raceover_reasons = { + [-1] = eRace_not_over_yet, + [ 0] = eRace_over_laps, + [ 1] = eRace_over_peds, + [ 2] = eRace_over_opponents, + [ 3] = eRace_over_abandoned, + [ 4] = eRace_over_out_of_time, + [ 5] = eRace_over_demo, + [ 6] = eRace_over_network_victory, + [ 7] = eRace_over_network_loss, +} + +f_raceover_reason = ProtoField.uint32("dethrace.raceover.reason", "Reason", base.DEC, raceover_reasons) + +function dissect_message_raceover(tree, message) + -- tNet_message_race_over (9) + local t = create_message_size_type(tree, message, "Race Over (UNTESTED)") + t:add_le(f_raceover_reason, message(4, 4)) + -- finished +end + +player_statuses = { + [0] = "Unknown", + [1] = "Ready", + [2] = "Loading", + [3] = "Wrecks Gallery", + [4] = "Summary", + [5] = "Not Responding", + [6] = "Racing", + [7] = "Main Menu", + [8] = "Recovering", + [9] = "Action Replay", +} + +f_statusreport_status = ProtoField.uint32("dethrace.statusreport.status", "Player Status", base.DEC, player_statuses) + +function dissect_message_statusreport(tree, message) + -- tNet_message_status_report (10) + local t = create_message_size_type(tree, message, "Status Report (UNTESTED)") + t:add_le(f_statusReport_status, message(4, 4)) + -- finished +end + +f_startrace_count = ProtoField.uint32("dethrace.startrace.count", "Car Count", base.DEC) +f_startrace_racing = ProtoField.bool("dethrace.startrace.racing", "Racing") +f_startrace_next = ProtoField.uint32("dethrace.startrace.next", "Next Race", base.DEC, race_tracks) + +function dissect_message_startrace(tree, message) + -- tNet_message_start_race (11) + local t = create_message_size_type(tree, message, "Start Race (UNTESTED/INCOMPLETE)") + t:add_le(f_startrace_count, message(4, 4)) + t:add_le(f_startrace_racing, message(8, 4)) + t:add_le(f_startrace_racing, message(8, 4)) + t:add_le(f_startrace_next, message(12, 4)) + for i = 0, 6 do + specdata = message(16 + i * 56, 56) + local subtree = t:add(specdata, string.format("Grid Car %d", i)) + -- FIXME + end + -- FIXME +end + +f_headup_text = ProtoField.stringz("dethrace.headup.message", "Message") + +function dissect_message_headup(tree, message) + -- tNet_message_headup (12) + local t = create_message_size_type(tree, message, "Head-Up (UNTESTED)") + t:add(f_headup_text, message(4, 128)) + -- finished +end + +function dissect_message_hostquery(tree, message) + -- tNet_message_host_query (13) + create_message_size_type(tree, message, "Host Query") + -- finished +end + +f_hostreply_started = ProtoField.bool("dethrace.hostreply.started", "Race Started") +f_hostreply_race = ProtoField.uint32("dethrace.hostreply.race", "Race", base.DEC, race_tracks) +f_hostreply_pending = ProtoField.uint32("dethrace.hostreply.pending", "Pending Race", base.DEC, race_tracks) + +function dissect_message_hostreply(tree, message) + -- tNet_message_host_reply (14) + local t = create_message_size_type(tree, message, "Host Reply (UNTESTED)") + t:add(f_hostreply_started, message(4, 4)) + t:add(f_hostreply_race, message(8, 4)) + t:add(f_hostreply_pending, message(12, 4)) + -- finished +end + +function dissect_message_mechanics(tree, message) + -- tNet_message_mechanics_info (15) + local t = create_message_size_type(tree, message, "Mechanics") + -- FIXME +end + +function dissect_message_noncar_info(tree, message) + -- tNet_message_non_car_info (16) + local t = create_message_size_type(tree, message, "Non-Car Info") + -- FIXME +end + +function dissect_message_timesync(tree, message) + -- tNet_message_time_sync (17) + local t = create_message_size_type(tree, message, "Time Sync") + -- FIXME +end + +function dissect_message_confirm(tree, message) + -- tNet_message_players_confirm (18) + local t = create_message_size_type(tree, message, "Confirm") + -- FIXME +end + +function dissect_message_disablecar(tree, message) + -- tNet_message_disable_car (19) + local t = create_message_size_type(tree, message, "Disable Car") + -- FIXME +end + +function dissect_message_enablecar(tree, message) + -- tNet_message_enable_car (20) + local t = create_message_size_type(tree, message, "Enable Car") + -- FIXME +end + +function dissect_message_powerup(tree, message) + -- tNet_message_powerup (21) + local t = create_message_size_type(tree, message, "Power-Up") + -- FIXME +end + +function dissect_message_recover(tree, message) + -- tNet_message_recover (22) + local t = create_message_size_type(tree, message, "Recover") + -- FIXME +end + +function dissect_message_scores(tree, message) + -- tNet_message_game_scores (23) + local t = create_message_size_type(tree, message, "Scores") + -- FIXME +end + +function dissect_message_wasted(tree, message) + -- tNet_message_wasted (24) + local t = create_message_size_type(tree, message, "Wasted") + -- FIXME +end + +function dissect_message_pedestrian(tree, message) + -- tNet_message_pedestrian (25) + local t = create_message_size_type(tree, message, "Pedestrian") + -- FIXME +end + +function dissect_message_gameplay(tree, message) + -- tNet_message_gameplay (26) + local t = create_message_size_type(tree, message, "Gameplay") + -- FIXME +end + +function dissect_message_noncarposition(tree, message) + -- tNet_message_non_car_position (27) + local t = create_message_size_type(tree, message, "Non-Car Position") + -- FIXME +end + +function dissect_message_copinfo(tree, message) + -- tNet_message_cop_info (28) + local t = create_message_size_type(tree, message, "Cop Info") + -- FIXME +end + +function dissect_message_gamescores(tree, message) + -- tNet_message_oil_spill (29) + local t = create_message_size_type(tree, message, "Game Scores") + -- FIXME +end + +function dissect_message_oilspill(tree, message) + -- tNet_message_oil_spill (30) + local t = create_message_size_type(tree, message, "Oil Spill") + -- FIXME +end + +function dissect_message_crushpoint(tree, message) + -- tNet_message_crush_point (31) + local t = create_message_size_type(tree, message, "Crush Point") + -- FIXME +end + +function dissect_message_none(tree, message) + -- none (32) + create_message_size_type(tree, message, "None") + -- finished +end + +dethrace_protocol.fields = { + f_checksum, f_broadcast_magic, f_broadcast_type, f_terminator, + + f_pd_player_info, + + f_message_magic, f_message_guarantee, f_message_sender, f_message_version, f_message_timestamp, f_message_count, f_message_size, + f_contents_size, f_contents_type, + + f_details_host_name, f_details_host_id, f_details_num_players, f_details_start_race, f_details_no_races_yet, f_details_status, + f_details_option_show_players_on_map, f_details_option_show_peds_on_map, f_details_option_enable_text_messages, f_details_option_show_powerups_on_map, f_details_option_powerup_respawn, f_details_option_open_game, f_details_option_starting_money_index, f_details_option_start_type, f_details_option_race_end_target, f_details_option_random_car_choice, f_details_option_race_sequence_type, f_details_option_car_choice, + f_details_type, + + f_guaranteereply_number, + + f_cardetails_count, f_cardetails_car, f_cardetails_owner, + + f_raceover_reason, + + f_statusreport_status, + + f_startrace_count, f_startrace_racing, f_startrace_next, + + f_headup_text, + + f_hostreply_started, f_hostreply_race, f_hostreply_pending, +} + +dethrace_message_dissectors = { + [ 0] = dissect_message_sendmedetails, + [ 1] = dissect_message_details, + [ 2] = dissect_message_join, + [ 3] = dissect_message_newplayerlist, + [ 4] = dissect_message_guaranteereply, + [ 5] = dissect_message_cardetailsreq, + [ 6] = dissect_message_cardetails, + [ 7] = dissect_message_leave, + [ 8] = dissect_message_hosticide, + [ 9] = dissect_message_raceover, + [10] = dissect_message_statusreport, + [11] = dissect_message_startrace, + [12] = dissect_message_headup, + [13] = dissect_message_hostquery, + [14] = dissect_message_hostreply, + [15] = dissect_message_mechanics, + [16] = dissect_message_noncar_info, + [17] = dissect_message_timesync, + [18] = dissect_message_confirm, + [19] = dissect_message_disablecar, + [20] = dissect_message_enablecar, + [21] = dissect_message_powerup, + [22] = dissect_message_recover, + [23] = dissect_message_scores, + [24] = dissect_message_wasted, + [25] = dissect_message_pedestrian, + [26] = dissect_message_gameplay, + [27] = dissect_message_noncarposition, + [28] = dissect_message_copinfo, + [29] = dissect_message_gamescores, + [30] = dissect_message_oilspill, + [31] = dissect_message_crushpoint, + [32] = dissect_message_none, +} + +function dethrace_protocol.dissector(buffer, pinfo, tree) + if buffer:bytes(4, 7) == ByteArray.new("43 57 39 35 4d 53 47") then -- "CW95MSG" + pinfo.cols.protocol = "DRBC" + local t = tree:add(dethrace_protocol, buffer(), "DethRace Broadcast Protocol") + t:add(f_checksum, buffer(0, 4)) + t:add(f_broadcast_magic, buffer(4, 7)) + t:add(f_broadcast_type, buffer(11, 1)) + t:add(f_terminator, buffer(12, 1)) + elseif buffer(4, 4):le_uint() == 0x763a5058 then -- "XP:v" + pinfo.cols.protocol = "DR"; + do + local t = tree:add(dethrace_protocol, buffer(0, 28), "DethRace Message Protocol") + + t:add(f_checksum, buffer(0, 4)) + t:add_le(f_message_magic, buffer(4, 4)) + t:add_le(f_message_guarantee, buffer(8, 4)) + t:add_le(f_message_sender, buffer(12, 4)) + t:add_le(f_message_version, buffer(16, 4)) + t:add_le(f_message_timestamp, buffer(20, 4)) + t:add_le(f_message_count, buffer(24, 2)) + t:add_le(f_message_size, buffer(26, 2)) + end + local message = buffer(28) + local message_type = message(1, 1):uint() + dethrace_message_dissectors[message_type](tree, message) + end +end + +-- load the udp.port table +udp_table = DissectorTable.get("udp.port") +-- register our protocol to handle udp port 39456 +udp_table:add(DETHRACE_PORT, dethrace_protocol) + From c0f87dea73f66ab0bbc1a79681dc68b761e77d55 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 03:02:10 +0200 Subject: [PATCH 10/40] add dissector installation instructions --- tools/dethrace.lua | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index e052a2e1..19138e05 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -1,3 +1,13 @@ +-- Bisic Dethrace Wireshark dissector +-- +-- Installation instructions: +-- 1. Open Wireshark GUI +-- 2. Navigate to "Help -> About Wireshark" menu +-- 3. Clock on "Folder" tab andclick in the list of paths on "Personal Lua Plugins". +-- If the folder does not yet exist, a dialog will ask you to. +-- 4. Paste this lua script in the "Personal Lua Plugins" directory, or create a symlink. +-- 5. When modifying this script, reload all plug-ins with CTRL+SHIRT+L + dethrace_protocol = Proto("dethrace", "Dethrace Protocol") DETHRACE_PORT = 12286 From c05de2327f75698472ece94d8a38996a370b5bfc Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 03:14:43 +0200 Subject: [PATCH 11/40] Set wireshark info column --- tools/dethrace.lua | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index 19138e05..dd27aae1 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -519,8 +519,9 @@ dethrace_message_dissectors = { function dethrace_protocol.dissector(buffer, pinfo, tree) if buffer:bytes(4, 7) == ByteArray.new("43 57 39 35 4d 53 47") then -- "CW95MSG" - pinfo.cols.protocol = "DRBC" local t = tree:add(dethrace_protocol, buffer(), "DethRace Broadcast Protocol") + pinfo.cols.protocol = "DRBC" + pinfo.cols.info = string.format("Broadcast: %s", broadcast_types[buffer(11, 1):uint()]) t:add(f_checksum, buffer(0, 4)) t:add(f_broadcast_magic, buffer(4, 7)) t:add(f_broadcast_type, buffer(11, 1)) @@ -541,6 +542,7 @@ function dethrace_protocol.dissector(buffer, pinfo, tree) end local message = buffer(28) local message_type = message(1, 1):uint() + pinfo.cols.info = string.format("%s (%d)", content_types[message_type], message_type) dethrace_message_dissectors[message_type](tree, message) end end From b96c0129f7484726715e1e87b04595f0739c23f6 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 13:47:12 +0200 Subject: [PATCH 12/40] Fix various typo's --- src/DETHRACE/macros.h | 2 +- tools/dethrace.lua | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DETHRACE/macros.h b/src/DETHRACE/macros.h index 15312314..c8d77640 100644 --- a/src/DETHRACE/macros.h +++ b/src/DETHRACE/macros.h @@ -3,7 +3,7 @@ #define DR_VALUE(V) V #define DR_JOIN2(A,B) A##B -#define DRJOIN(A,B) DR_JOIN2(A, B) +#define DR_JOIN(A,B) DR_JOIN2(A, B) #define DR_STATIC_ASSERT(V) typedef int DR_JOIN(dr_static_assert_, DR_VALUE(__COUNTER__))[(V)?1:-1] #define VEHICLE_TYPE_FROM_ID(id) ((tVehicle_type)(id >> 8)) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index dd27aae1..8687297e 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -1,12 +1,12 @@ --- Bisic Dethrace Wireshark dissector +-- Basic Dethrace Wireshark dissector -- -- Installation instructions: -- 1. Open Wireshark GUI -- 2. Navigate to "Help -> About Wireshark" menu --- 3. Clock on "Folder" tab andclick in the list of paths on "Personal Lua Plugins". --- If the folder does not yet exist, a dialog will ask you to. +-- 3. Click on "Folder" tab and click in the list of paths on "Personal Lua Plugins". +-- If the folder does not yet exist, a dialog will ask you to create it. -- 4. Paste this lua script in the "Personal Lua Plugins" directory, or create a symlink. --- 5. When modifying this script, reload all plug-ins with CTRL+SHIRT+L +-- 5. When modifying this script, reload all plug-ins with CTRL+SHIFT+L dethrace_protocol = Proto("dethrace", "Dethrace Protocol") DETHRACE_PORT = 12286 From fc07e7dae93fb2427cc5e8f6a949b95903a567da Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 15:59:22 +0200 Subject: [PATCH 13/40] 4-byte align tNet_message_join as well + more dethrace.lua --- src/DETHRACE/common/network.c | 3 + src/DETHRACE/dr_types.h | 4 +- src/DETHRACE/macros.h | 3 +- tools/dethrace.lua | 268 +++++++++++++++++++++++++++++----- 4 files changed, 234 insertions(+), 44 deletions(-) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 7a27fb1a..ccecb85a 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -622,6 +622,9 @@ int NetJoinGameLowLevel(tNet_game_details* pDetails, char* pPlayer_name) { return PDNetJoinGame(pDetails, pPlayer_name); } +DR_STATIC_ASSERT(offsetof(tNet_message_join, player_info) == 4); +DR_STATIC_ASSERT(offsetof(tNet_game_player_info, this_players_time_stamp) == 0x10); + // IDA: int __usercall NetJoinGame@(tNet_game_details *pDetails@, char *pPlayer_name@, int pCar_index@) int NetJoinGame(tNet_game_details* pDetails, char* pPlayer_name, int pCar_index) { int result; diff --git a/src/DETHRACE/dr_types.h b/src/DETHRACE/dr_types.h index d3d9b069..df91d680 100644 --- a/src/DETHRACE/dr_types.h +++ b/src/DETHRACE/dr_types.h @@ -1033,6 +1033,7 @@ typedef struct tFace_ref { br_scalar d; } tFace_ref; +#pragma pack(push, 4) typedef struct tNet_game_player_info { // size: 0xc0 tPD_net_player_info pd_net_info; // @0x0 tU32 this_players_time_stamp; // @0x10 @@ -1062,6 +1063,7 @@ typedef struct tNet_game_player_info { // size: 0xc0 br_matrix34 initial_position; // @0x8c tCar_spec* car; // @0xbc } tNet_game_player_info; +#pragma pack(pop) typedef struct tNet_game_options { // size: 0x30 int show_players_on_map; // @0x0 @@ -1340,7 +1342,6 @@ typedef struct tNet_message_crush_point { br_vector3 energy_vector; } tNet_message_crush_point; -#pragma pack(push, 4) typedef union tNet_contents { // size: 0x160 struct { // size: 0x2 tU8 contents_size; // @0x0 @@ -1381,7 +1382,6 @@ typedef union tNet_contents { // size: 0x160 tNet_message_crush_point crush; // @0x0 } data; // @0x0 } tNet_contents; -#pragma pack(pop) typedef struct tNet_message { // size: 0x17c tU32 pd_stuff_so_DO_NOT_USE; // @0x0 diff --git a/src/DETHRACE/macros.h b/src/DETHRACE/macros.h index c8d77640..384e3313 100644 --- a/src/DETHRACE/macros.h +++ b/src/DETHRACE/macros.h @@ -1,10 +1,9 @@ #ifndef MACROS_H #define MACROS_H -#define DR_VALUE(V) V #define DR_JOIN2(A,B) A##B #define DR_JOIN(A,B) DR_JOIN2(A, B) -#define DR_STATIC_ASSERT(V) typedef int DR_JOIN(dr_static_assert_, DR_VALUE(__COUNTER__))[(V)?1:-1] +#define DR_STATIC_ASSERT(V) typedef int DR_JOIN(dr_static_assert_, __COUNTER__)[(V)?1:-1] #define VEHICLE_TYPE_FROM_ID(id) ((tVehicle_type)(id >> 8)) #define VEHICLE_INDEX_FROM_ID(id) ((id)&0x00ff) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index 8687297e..c1c8fed8 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -52,6 +52,8 @@ content_types = { [0x20] = "None", } +-- FIXME: missing table: index -> car name + f_checksum = ProtoField.uint32("dethrace.checksum", "Checksum") f_broadcast_magic = ProtoField.string("dethrace.broadcast_magic", "Broadcast Magic", base.ASCII) f_broadcast_type = ProtoField.char("dethrace.broadcast_type", "Broadcast Type", base.NONE, broadcast_types) @@ -69,6 +71,21 @@ f_message_size = ProtoField.uint16("dethrace.size", "Overall Size") f_contents_size = ProtoField.uint8("dethrace.content_size", "Content Size") f_contents_type = ProtoField.uint8("dethrace.content_type", "Content Type", base.DEC, content_types) +player_statuses = { + [0] = "Unknown", + [1] = "Ready", + [2] = "Loading", + [3] = "Wrecks Gallery", + [4] = "Summary", + [5] = "Not Responding", + [6] = "Racing", + [7] = "Main Menu", + [8] = "Recovering", + [9] = "Action Replay", +} + +f_player_status = ProtoField.uint32("dethrace.player_status", "Player Status", base.DEC, player_statuses) + function create_message_size_type(parent, message, name) local message_type = message(1, 1):uint() local tree = parent:add(dethrace_protocol, message(), string.format("%s (%d)", name, message_type)) @@ -80,7 +97,25 @@ end f_pd_player_info = ProtoField.bytes("dethrace.pd_info", "PD Net Info") function dissect_pd_player_info(tree, data) - tree:add_le(f_pd_player_info, data(0, 18)) + tree:add_le(f_pd_player_info, data(0, 16)) + return 16 +end + +f_float = ProtoField.float("dethrace.float", "Floating value") + +function dissect_br_matrix34(parent, data, name) + local matrix_tree = parent:add(name, data(0, 48)) + local offset = 0 + for row_i = 0, 3 do + local row_tree = matrix_tree:add(string.format("m[%d]", row_i), data(offset, 12)) + + for col_i = 0, 2 do + local f = data(offset, 4):float() + row_tree:add_le(f_float, data(offset, 4)):set_text(string.format("m[%d][%d] = %f", row_i, col_i, f)) + offset = offset + 4 + end + end + return offset end function dissect_message_sendmedetails(tree, message) @@ -161,8 +196,9 @@ f_details_option_random_car_choice = ProtoField.bool("dethrace.details.options.r f_details_option_race_sequence_type = ProtoField.uint32("dethrace.details.options.race_sequence_type", "Race Sequence Type") f_details_option_car_choice = ProtoField.uint32("dethrace.details.options.car_choice", "Car Choice", base.DEC, details_options_car_choices) -function dissect_game_details(tree, data) +function dissect_game_details(parent, data) -- tNet_game_options + local tree = parent:add("Options", data(48)) tree:add_le(f_details_option_show_players_on_map, data(0, 4)) tree:add_le(f_details_option_show_peds_on_map, data(4, 4)) tree:add_le(f_details_option_enable_text_messages, data(8, 4)) @@ -175,40 +211,189 @@ function dissect_game_details(tree, data) tree:add_le(f_details_option_random_car_choice, data(36, 4)) tree:add_le(f_details_option_race_sequence_type, data(40, 4)) tree:add_le(f_details_option_car_choice, data(44, 4)) + return 48 end function dissect_message_details(tree, message) -- tNet_message_my_details (1) local t = create_message_size_type(tree, message, "Details") - dissect_pd_player_info(t, message(2)) - t:add(f_details_host_name, message(20, 32)) - t:add_le(f_details_host_id, message(52, 4)) - t:add_le(f_details_num_players, message(56, 4)) - t:add_le(f_details_start_race, message(60, 4)) - t:add_le(f_details_no_races_yet, message(64, 4)) - t:add_le(f_details_status, message(68, 4)) - do - local option_data = message(72, 48) - dissect_game_details(t:add(option_data, "Options"), option_data) - end - t:add_le(f_details_type, message(120, 4)) -end - -function dissect_game_player_info(tree, message) + local offset = 2 + + offset = offset + dissect_pd_player_info(t, message(offset)) + + t:add(f_details_host_name, message(offset, 32)) + offset = offset + 4 + + t:add_le(f_details_host_id, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_details_num_players, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_details_start_race, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_details_no_races_yet, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_details_status, message(offset, 4)) + offset = offset + 4 + + offset = offset + dissect_game_details(t, message(offset)) + + t:add_le(f_details_type, message(offset, 4)) + offset = offset + 4 +end + +f_join_timestamp = ProtoField.uint32("dethrace.join.timestamp", "Timestamp") +f_join_last_heard = ProtoField.uint32("dethrace.join.time_last_heard", "Last heard timestamp") +f_join_reposition_time = ProtoField.uint32("dethrace.join.time_reposition", "Reposition timestamp") +f_join_last_waste_time = ProtoField.uint32("dethrace.join.time_waste", "Last waste message timestamp") +f_join_host = ProtoField.bool("dethrace.join.host", "Host") +f_join_playerid = ProtoField.uint32("dethrace.join.playerid", "Player ID") +f_join_player_name = ProtoField.stringz("dethrace.join.player_name", "Player Name") +f_join_car = ProtoField.uint32("dethrace.join.car", "Car") -- FIXME: use table index -> car name +f_join_grid = ProtoField.uint32("dethrace.join.grid", "Grid Index") +f_join_grid_set = ProtoField.bool("dethrace.join.grid_set", "Grid Position Set") +f_join_opponent_index = ProtoField.uint32("dethrace.join.opponent_index", "Opponent List Index") +f_join_wait_confirm = ProtoField.uint32("dethrace.join.wait_confirm", "Awaiting Confirmation") -- FIXME: find out values +f_join_score = ProtoField.uint32("dethrace.join.score", "Score") +f_join_credits = ProtoField.uint32("dethrace.join.credits", "Credits") +f_join_wasted = ProtoField.bool("dethrace.join.wasted", "Wasted") +f_join_wasteage_attributed = ProtoField.bool("dethrace.join.wasteage_attributed", "Wasteage Attributed") -- FIXME: find out what this is +f_join_name_not_clipped = ProtoField.bool("dethrace.join.name_not_clipped", "Name Not Clipped") -- FIXME: find out what this is +f_join_race_stuff_initialized = ProtoField.bool("dethrace.join.race_stuff_initialized", "Race Stuff Initialized") +f_join_played = ProtoField.bool("dethrace.join.played", "Played") +f_join_won = ProtoField.bool("dethrace.join.won", "Won") +f_join_next_car_index = ProtoField.uint32("dethrace.join.next_car_index", "Next Car Index") -- FIXME: find out what this is +f_join_games_score = ProtoField.uint32("dethrace.join.games_score", "Games Score") +f_join_last_score_index = ProtoField.uint32("dethrace.join.last_score_index", "Last Score Index") +f_join_last_score_index = ProtoField.uint32("dethrace.join.last_score_index", "Last Score Index") +f_join_car_ptr = ProtoField.uint64("dethrace.join.car_ptr", "Car Spec (pointer)") + +function dissect_game_player_info(tree, data) -- tNet_game_player_info + local offset = dissect_pd_player_info(tree, data) + + tree:add_le(f_join_timestamp, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_last_heard, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_reposition_time, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_last_waste_time, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_host, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_playerid, data(offset, 4)) + offset = offset + 4 + + tree:add(f_join_player_name, data(offset, 32)) + offset = offset + 32 + + tree:add_le(f_player_status, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_car, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_grid, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_grid_set, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_opponent_index, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_wait_confirm, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_score, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_credits, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_wasted, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_wasteage_attributed, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_name_not_clipped, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_race_stuff_initialized, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_played, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_won, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_next_car_index, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_games_score, data(offset, 4)) + offset = offset + 4 + + tree:add_le(f_join_last_score_index, data(offset, 4)) + offset = offset + 4 + + offset = offset + dissect_br_matrix34(tree, data(offset), "Initial Position") + + assert(offset == 0xbc, "offset of car spec ptr") + + tree:add_le(f_join_car_ptr, data(offset, 4)) + + tree:set_len(offset) end function dissect_message_join(tree, message) -- tNet_message_join (2) - local t = create_message_size_type(tree, message, "Join (INCOMPLETE)") - local game_player_info_data = message(4) - dissect_game_player_info(t, game_player_info_data) + local t = create_message_size_type(tree, message, "Join") + local offset = 4 + + dissect_game_player_info(t:add("Player Info", message(offset)), message(offset)) end +newerplayerlist_count_magics = { + [-1] = "-1 (Selected Car Unavailable)", + [0] = "0 (Game Already Started)", +} + +f_newplayerlist_count = ProtoField.int32("dethrace.newplayerlist.count", "Number Of Players")--, base.DEC, newerplayerlist_count_magics) +f_newplayerlist_index = ProtoField.int32("dethrace.newplayerlist.index", "This Index") +f_newplayerlist_batch_number = ProtoField.int32("dethrace.newplayerlist.batch_number", "Batch Number") + function dissect_message_newplayerlist(tree, message) -- tNet_message_new_player_list (3) local t = create_message_size_type(tree, message, "New Player List") - -- FIXME + local offset = 4 + + local t_count = t:add_le(f_newplayerlist_count, message(offset, 4)) + if message(offset, 4):int() == 0 then + t_count:set_text("Number Of Players: Game Already Started (0)") + elseif message(offset, 4):int() == -1 then + t_count:set_text("Number Of Players: Car Unavailable (-1)") + end + offset = offset + 4 + + t:add_le(f_newplayerlist_index, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_newplayerlist_batch_number, message(offset, 4)) + offset = offset + 4 + + dissect_game_player_info(t:add("Player", message(offset)), message(offset)) + -- finished end f_guaranteereply_number = ProtoField.uint32("dethrace.guaranteereply.number", "Guarantee Number") @@ -228,18 +413,24 @@ function dissect_message_cardetailsreq(tree, message) end f_cardetails_count = ProtoField.uint32("dethrace.cardetails.count", "Car Count") -f_cardetails_car = ProtoField.uint32("dethrace.cardetails.car_index", "Car") +f_cardetails_car = ProtoField.uint32("dethrace.cardetails.car_index", "Car") -- FIXME: use table index -> car name f_cardetails_owner = ProtoField.stringz("dethrace.cardetails.owner", "Owner") function dissect_message_cardetails(tree, message) -- tNet_message_car_details (6) local t = create_message_size_type(tree, message, "Car Details") + local offset = 4 + t:add_le(f_cardetails_count, message(4, 4)) + offset = offset + 4 + for i = 0, 5 do - local car_detail = message(8 + 20 * i, 20) - local subtree = t:add(car_detail, string.format("Car %d", i)) + local car_detail = message(offset, 20) + local subtree = t:add(car_detail, string.format("Car[%d]", i)) subtree:add_le(f_cardetails_car, car_detail(0, 4)) subtree:add(f_cardetails_owner, car_detail(4, 16)) + + offset = offset + 20 end -- finished end @@ -277,25 +468,10 @@ function dissect_message_raceover(tree, message) -- finished end -player_statuses = { - [0] = "Unknown", - [1] = "Ready", - [2] = "Loading", - [3] = "Wrecks Gallery", - [4] = "Summary", - [5] = "Not Responding", - [6] = "Racing", - [7] = "Main Menu", - [8] = "Recovering", - [9] = "Action Replay", -} - -f_statusreport_status = ProtoField.uint32("dethrace.statusreport.status", "Player Status", base.DEC, player_statuses) - function dissect_message_statusreport(tree, message) -- tNet_message_status_report (10) local t = create_message_size_type(tree, message, "Status Report (UNTESTED)") - t:add_le(f_statusReport_status, message(4, 4)) + t:add_le(f_player_status, message(4, 4)) -- finished end @@ -456,12 +632,23 @@ end dethrace_protocol.fields = { f_checksum, f_broadcast_magic, f_broadcast_type, f_terminator, + f_float, f_pd_player_info, f_message_magic, f_message_guarantee, f_message_sender, f_message_version, f_message_timestamp, f_message_count, f_message_size, f_contents_size, f_contents_type, + -- 2 (join) + f_join_timestamp, f_join_last_heard, f_join_reposition_time, f_join_last_waste_time, + f_join_host, f_join_playerid, f_join_player_name, f_join_car, f_join_grid, f_join_grid_set, + f_join_opponent_index, f_join_wait_confirm, f_join_score, f_join_credits, f_join_wasted, + f_join_wasteage_attributed, f_join_name_not_clipped, f_join_race_stuff_initialized, f_join_played, + f_join_won, f_join_next_car_index, f_join_games_score, f_join_last_score_index, f_join_car_ptr, + + -- 3 (newplayerlist) + f_newplayerlist_count, f_newplayerlist_index, f_newplayerlist_batch_number, + f_details_host_name, f_details_host_id, f_details_num_players, f_details_start_race, f_details_no_races_yet, f_details_status, f_details_option_show_players_on_map, f_details_option_show_peds_on_map, f_details_option_enable_text_messages, f_details_option_show_powerups_on_map, f_details_option_powerup_respawn, f_details_option_open_game, f_details_option_starting_money_index, f_details_option_start_type, f_details_option_race_end_target, f_details_option_random_car_choice, f_details_option_race_sequence_type, f_details_option_car_choice, f_details_type, @@ -479,6 +666,7 @@ dethrace_protocol.fields = { f_headup_text, f_hostreply_started, f_hostreply_race, f_hostreply_pending, + f_player_status, } dethrace_message_dissectors = { From 78919fdc1fd718acee468648a5d7b4b84c318eb3 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 18:02:37 +0200 Subject: [PATCH 14/40] Add more assertions --- src/DETHRACE/common/network.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index ccecb85a..f96abf23 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -624,6 +624,9 @@ int NetJoinGameLowLevel(tNet_game_details* pDetails, char* pPlayer_name) { DR_STATIC_ASSERT(offsetof(tNet_message_join, player_info) == 4); DR_STATIC_ASSERT(offsetof(tNet_game_player_info, this_players_time_stamp) == 0x10); +DR_STATIC_ASSERT(offsetof(tNet_game_player_info, wasted) == 0x68); +DR_STATIC_ASSERT(offsetof(tNet_game_player_info, initial_position) == 0x8c); +DR_STATIC_ASSERT(offsetof(tNet_game_player_info, car) == 0xbc); // IDA: int __usercall NetJoinGame@(tNet_game_details *pDetails@, char *pPlayer_name@, int pCar_index@) int NetJoinGame(tNet_game_details* pDetails, char* pPlayer_name, int pCar_index) { From 11c81f4c9eece90ba06394c5bd11bad670be3159 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 7 Jul 2023 18:03:00 +0200 Subject: [PATCH 15/40] Fix network car choose loop --- src/DETHRACE/common/newgame.c | 2 +- src/DETHRACE/common/racestrt.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DETHRACE/common/newgame.c b/src/DETHRACE/common/newgame.c index fb4c2d63..14110167 100644 --- a/src/DETHRACE/common/newgame.c +++ b/src/DETHRACE/common/newgame.c @@ -1699,7 +1699,7 @@ int ChooseNetCar(tNet_game_details* pNet_game, tNet_game_options* pOptions, int* *pCar_index = PickARandomCar(); car_index = 0; for (i = 0; i < gNumber_of_racers; i++) { - if (gCar_details[i].ownership != eCar_owner_not_allowed) { + if (gCar_details[i].ownership < eCar_owner_not_allowed) { gProgram_state.cars_available[car_index] = i; car_index++; } diff --git a/src/DETHRACE/common/racestrt.c b/src/DETHRACE/common/racestrt.c index 3ccae3df..13a1805a 100644 --- a/src/DETHRACE/common/racestrt.c +++ b/src/DETHRACE/common/racestrt.c @@ -615,7 +615,7 @@ int ChangeCar(int pNet_mode, int* pCar_index, tNet_game_details* pNet_game) { } if (result == 0) { if (pNet_mode) { - *pCar_index = gProgram_state.cars_available[gCurrent_race_index]; + *pCar_index = gProgram_state.cars_available[gCurrent_car_index]; } else { AboutToLoadFirstCar(); SwitchToRealResolution(); From e0425d9d756a087dba1cb56a6b9cbd8469ffbe39 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Sun, 9 Jul 2023 16:35:05 +1200 Subject: [PATCH 16/40] player scores --- src/DETHRACE/common/netgame.c | 313 +++++++++++++++++++++++++++++++++- src/DETHRACE/common/network.c | 60 ++++++- 2 files changed, 359 insertions(+), 14 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index f26d02f8..b5de1d09 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -1,6 +1,7 @@ #include "netgame.h" #include "brender/brender.h" #include "car.h" +#include "controls.h" #include "crush.h" #include "displays.h" #include "errors.h" @@ -25,7 +26,7 @@ #include int gPowerup_cost[4] = { 1500, 2500, 4000, 6000 }; -int gGame_scores[6]; +int gGame_scores[6] = { 1, 2, 3, 4, 6, 10 }; int gPed_target; int gNot_shown_race_type_headup; tU32 gLast_it_change; @@ -387,7 +388,26 @@ void RepositionPlayer(int pIndex) { tNet_message* the_message; tCar_spec* car; LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + car = gNet_players[pIndex].car; + gNet_players[pIndex].wasted = 0; + gNet_players[pIndex].reposition_time = 0; + if (gCurrent_net_game->type == eNet_game_type_carnage + || gCurrent_net_game->type == eNet_game_type_checkpoint + || gCurrent_net_game->type == eNet_game_type_sudden_death) { + BrMatrix34Copy(&car->car_master_actor->t.t.mat, &gNet_players[pIndex].initial_position); + } else { + SetInitialPosition(&gCurrent_race, gNet_players[pIndex].opponent_list_index, gNet_players[pIndex].grid_index); + } + ReinitialiseCar(car); + SetFlipUpCar(car); + car->last_car_car_collision = GetRaceTime() + 100; + SignalToStartRace2(pIndex); + if (car->driver == eDriver_local_human) { + CancelPendingCunningStunt(); + gProgram_state.credits_earned = gInitial_net_credits[gCurrent_net_game->options.starting_money_index]; + gProgram_state.credits_lost = 0; + } } // IDA: void __usercall DisableCar(tCar_spec *pCar@) @@ -570,7 +590,7 @@ void DoNetScores2(int pOnly_sort_scores) { } headup_pairs[i].out_of_game = 1000; } - qsort(headup_pairs, COUNT_OF(headup_pairs), sizeof(tHeadup_pair), (int(*)(const void*,const void*))(ascending_order ? SortNetHeadAscending : SortNetHeadDescending)); + qsort(headup_pairs, COUNT_OF(headup_pairs), sizeof(tHeadup_pair), (int (*)(const void*, const void*))(ascending_order ? SortNetHeadAscending : SortNetHeadDescending)); right_edge = gCurrent_graf_data->net_head_box_x + gCurrent_graf_data->net_head_box_width + 5 * gCurrent_graf_data->net_head_box_pitch; for (i = 0; i < COUNT_OF(headup_pairs); i++) { @@ -719,14 +739,39 @@ void PlayerIsIt(tNet_game_player_info* pPlayer) { int i; char s[256]; LOG_TRACE("(%p)", pPlayer); - NOT_IMPLEMENTED(); + + if (pPlayer - gNet_players == gIt_or_fox) { + return; + } + for (i = 0; i < gNumber_of_net_players; i++) { + StopCarBeingIt(gNet_players[i].car); + } + if (gCurrent_net_game->type == eNet_game_type_foxy) { + pPlayer->car->power_up_levels[1] = 0; + } else if (gCurrent_net_game->type == eNet_game_type_tag && gIt_or_fox >= 0) { + gNet_players[gIt_or_fox].car->power_up_levels[1] = 0; + } + MakeCarIt(pPlayer->car); + gIt_or_fox = pPlayer - gNet_players; + sprintf(s, "%s", GetMiscString(gCurrent_net_game->type == eNet_game_type_tag ? 186 : 188)); + NetSendHeadupToPlayer(s, pPlayer->ID); + for (i = 0; i < gNumber_of_net_players; i++) { + if (&gNet_players[i] != pPlayer) { + sprintf(s, "%s %s", pPlayer->player_name, GetMiscString(gCurrent_net_game->type == eNet_game_type_tag ? 185 : 187)); + NetSendHeadupToPlayer(s, gNet_players[i].ID); + } + } } // IDA: int __usercall FarEnoughAway@(tNet_game_player_info *pPlayer_1@, tNet_game_player_info *pPlayer_2@) int FarEnoughAway(tNet_game_player_info* pPlayer_1, tNet_game_player_info* pPlayer_2) { br_vector3 difference; LOG_TRACE("(%p, %p)", pPlayer_1, pPlayer_2); - NOT_IMPLEMENTED(); + + difference.v[0] = pPlayer_1->car->pos.v[0] - pPlayer_2->car->pos.v[0]; + difference.v[1] = pPlayer_1->car->pos.v[1] - pPlayer_2->car->pos.v[1]; + difference.v[2] = pPlayer_1->car->pos.v[2] - pPlayer_2->car->pos.v[2]; + return BrVector3LengthSquared(&difference) >= 4.0f; } // IDA: void __usercall CarInContactWithItOrFox(tNet_game_player_info *pPlayer@) @@ -740,7 +785,28 @@ void SelectRandomItOrFox(int pNot_this_one) { int i; int new_choice; LOG_TRACE("(%d)", pNot_this_one); - NOT_IMPLEMENTED(); + + new_choice = 0; + gLast_lepper = 0; + if (gCurrent_net_game->type == eNet_game_type_tag) { + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].last_score_index == 0) { + new_choice = i; + break; + } + } + } else { + for (i = 0; i < gNumber_of_net_players; i++) { + if (i != pNot_this_one && gNet_players[i].last_score_index == gNumber_of_net_players - 1) { + PlayerIsIt(&gNet_players[i]); + return; + } + } + do { + new_choice = IRandomBetween(0, gNumber_of_net_players - 1); + } while (new_choice == pNot_this_one && !gNet_players[new_choice].car->knackered); + } + PlayerIsIt(&gNet_players[new_choice]); } // IDA: void __cdecl CalcPlayerScores() @@ -767,7 +833,225 @@ void CalcPlayerScores(void) { char s[256]; tNet_game_player_info* lowest_score_player; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + time = GetTotalTime(); + + if (gCurrent_net_game->type == eNet_game_type_carnage) { + highest = 0; + next_highest = 0; + for (i = 0; i < gNumber_of_net_players; ++i) { + if (gNet_players[i].score > highest) { + next_highest = highest; + highest = gNet_players[i].score; + } else if (gNet_players[i].score > next_highest) { + next_highest = gNet_players[i].score; + } + } + gPed_target = (gTotal_peds - (gProgram_state.peds_killed - highest - next_highest)) / 2 + 1; + if (gCurrent_net_game->options.race_end_target < gPed_target) { + gPed_target = gCurrent_net_game->options.race_end_target; + } + } else if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) { + if (gIt_or_fox < 0) { + SelectRandomItOrFox(-1); + } + if (gLast_lepper != NULL && gIt_or_fox >= 0 && FarEnoughAway(gLast_lepper, &gNet_players[gIt_or_fox])) { + gLast_lepper = NULL; + } + } + lowest_score = 9999; + lowest_score_player = NULL; + for (i = 0; i < gNumber_of_net_players; i++) { + car = gNet_players[i].car; + if (gNet_players[i].reposition_time != 0 && gNet_players[i].reposition_time <= time && (!gRace_finished || gRace_over_reason == -1)) { + RepositionPlayer(i); + } + if (gNet_players[i].last_waste_message != 0 + && !gNet_players[i].wasteage_attributed + && time - gNet_players[i].last_waste_message > 500) { + sprintf(s, "%s %s", gNet_players[i].player_name, GetMiscString(172)); + gNet_players[i].last_waste_message = 0; + gNet_players[i].wasteage_attributed = 0; + if (gCurrent_net_game->type == eNet_game_type_car_crusher) { + gNet_players[i].score--; + } + NetSendHeadupToEverybody(s); + } + SetKnackeredFlag(car); + if (car->knackered && !gNet_players[i].wasted) { + gNet_players[i].wasted = 1; + message = NetBuildMessage(NETMSGID_WASTED, 0); + message->contents.data.wasted.victim = gNet_players[i].ID; + message->contents.data.wasted.culprit = -1; + NetGuaranteedSendMessageToEverybody(gCurrent_net_game, message, 0); + switch (gCurrent_net_game->type) { + case eNet_game_type_fight_to_death: + cars_left = 0; + for (j = 0; j < gNumber_of_net_players; j++) { + if (!gNet_players[j].wasted) { + cars_left++; + car_left = j; + } + } + gNet_players[i].games_score += gGame_scores[5 - cars_left]; + if (cars_left == 1) { + DeclareWinner(car_left); + } else if (cars_left <= 0) { + EverybodysLost(); + } + break; + case eNet_game_type_car_crusher: + case eNet_game_type_sudden_death: + gNet_players[i].reposition_time = GetTotalTime() + 5000; + break; + case eNet_game_type_carnage: + gNet_players[i].reposition_time = GetTotalTime() + 5000; + gNet_players[i].score /= 2; + break; + case eNet_game_type_checkpoint: + if (gNet_players[i].score >> 16 != gCurrent_race.check_point_count) { + knock_out_bit = IRandomBetween(0, gCurrent_race.check_point_count - 1); + while (((1 << knock_out_bit) & gNet_players[i].score) != 0) { + knock_out_bit++; + if (gCurrent_race.check_point_count <= knock_out_bit) { + knock_out_bit = 0; + } + } + gNet_players[i].score |= 1 << knock_out_bit; + } + gNet_players[i].reposition_time = GetTotalTime() + 5000; + break; + case eNet_game_type_tag: + gNet_players[i].reposition_time = GetTotalTime() + 5000; + PlayerIsIt(&gNet_players[i]); + break; + case eNet_game_type_foxy: + gNet_players[i].reposition_time = GetTotalTime() + 5000; + gNet_players[i].score /= 2; + if (gNumber_of_net_players > 1 && i == gIt_or_fox) { + SelectRandomItOrFox(i); + } + break; + default: + break; + } + } + switch (gCurrent_net_game->type) { + case eNet_game_type_fight_to_death: + if (car->knackered) { + if (gCurrent_net_game->type == eNet_game_type_checkpoint + || gCurrent_net_game->type == eNet_game_type_tag) { + gNet_players[i].score = 1000000; + } else { + gNet_players[i].score = -1000000; + } + } else { + e_dam = car->damage_units[eDamage_engine].damage_level; + t_dam = car->damage_units[eDamage_transmission].damage_level; + d_dam = car->damage_units[eDamage_driver].damage_level; + w_dam = (car->damage_units[eDamage_lr_wheel].damage_level + + car->damage_units[eDamage_lf_wheel].damage_level + + car->damage_units[eDamage_rr_wheel].damage_level + + car->damage_units[eDamage_rf_wheel].damage_level) + / 4; + + if (e_dam >= t_dam && e_dam >= d_dam && e_dam >= w_dam) { + gNet_players[i].score = 100 - e_dam; + } else if (t_dam >= d_dam && t_dam >= w_dam) { + gNet_players[i].score = 100 - t_dam; + } else if (w_dam >= d_dam) { + gNet_players[i].score = 100 - w_dam; + } else { + gNet_players[i].score = 100 - d_dam; + } + } + break; + case eNet_game_type_carnage: + if (gNet_players[i].score >= gPed_target && !gRace_finished) { + DeclareWinner(i); + } + break; + case eNet_game_type_checkpoint: + score = 0; + gNet_players[i].score = gNet_players[i].score & 0xffff; + flags = gNet_players[i].score; + for (j = 0; j < gCurrent_race.check_point_count; j++) { + if ((flags & 1) != 0) { + score++; + } + flags >>= 1; + } + gNet_players[i].score |= score << 16; + if (!score && !gRace_finished) { + DeclareWinner(i); + } + break; + case eNet_game_type_sudden_death: + if (gNet_players[i].score >= 0) { + if (gNet_players[i].score >= lowest_score) { + if (gNet_players[i].score == lowest_score) { + lowest_score_player = 0; + } + } else { + lowest_score = gNet_players[i].score; + lowest_score_player = &gNet_players[i]; + } + } + break; + case eNet_game_type_tag: + if (i == gIt_or_fox && !gCountdown && gNet_players[i].score >= 0) { + gNet_players[i].score += gFrame_period; + if (gNet_players[i].score >= gCurrent_net_game->options.race_end_target) { + lowest_score_player = &gNet_players[i]; + } + } + break; + case eNet_game_type_foxy: + if (i == gIt_or_fox && !gCountdown && !gRace_finished) { + gNet_players[i].score += gFrame_period; + if (gNet_players[i].score >= gCurrent_net_game->options.race_end_target) { + DeclareWinner(i); + } + } + break; + default: + continue; + } + } + if ((gCurrent_net_game->type == eNet_game_type_sudden_death || gCurrent_net_game->type == eNet_game_type_tag) + && lowest_score_player != NULL + && lowest_score_player->score >= 0) { + player_left = -1; + cars_left = 0; + for (i = 0; i < gNumber_of_net_players; ++i) { + if (gNet_players[i].score >= 0 && &gNet_players[i] != lowest_score_player) { + ++cars_left; + if (player_left == -1) { + player_left = i; + } else { + player_left = -2; + } + } + } + if (cars_left) { + lowest_score_player->car->knackered = 1; + lowest_score_player->wasted = 1; + lowest_score_player->games_score += gGame_scores[6 - cars_left]; + lowest_score_player->score = -1; + if (player_left == -1) { + EverybodysLost(); + } else if (player_left < 0) { + if (gCurrent_net_game->type == eNet_game_type_tag) { + SelectRandomItOrFox(i); + } + SendGameplay(lowest_score_player->ID, eNet_gameplay_suddenly_death, 0, 0, 0, 0); + sprintf(s, "%s %s", lowest_score_player->player_name, GetMiscString(184)); + NetSendHeadupToEverybody(s); + } else { + DeclareWinner(player_left); + } + } + } } // IDA: void __cdecl SendPlayerScores() @@ -901,7 +1185,20 @@ void BuyOffense(void) { void UseGeneralScore(int pScore) { int i; LOG_TRACE("(%d)", pScore); - NOT_IMPLEMENTED(); + + if (gCurrent_net_game->type == eNet_game_type_carnage) { + gPed_target = pScore; + } else if ((gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) && gNet_players[gIt_or_fox].ID != pScore) { + for (i = 0; i < gNumber_of_net_players; i++) { + StopCarBeingIt(gNet_players[i].car); + } + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pScore) { + MakeCarIt(gNet_players[i].car); + gIt_or_fox = i; + } + } + } } // IDA: void __usercall NetSendEnvironmentChanges(tNet_game_player_info *pPlayer@) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index f96abf23..a96fd7b7 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -185,7 +185,19 @@ void NetSendHeadupToEverybody(char* pMessage) { void NetSendHeadupToPlayer(char* pMessage, tPlayer_ID pPlayer) { tNet_message* message; LOG_TRACE("(\"%s\", %d)", pMessage, pPlayer); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none) { + return; + } + if (gLocal_net_ID == pPlayer) { + if (gProgram_state.racing) { + NewTextHeadupSlot(4, 0, 3000, -4, pMessage); + } + } else { + message = NetBuildMessage(NETMSGID_HEADUP, 0); + strcpy(message->contents.data.headup.text, pMessage); + NetGuaranteedSendMessageToPlayer(gCurrent_net_game, message, pPlayer, 0); + } } // IDA: void __cdecl InitialisePlayerStati() @@ -730,7 +742,14 @@ int NetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, // IDA: int __usercall NetSendMessageToHost@(tNet_game_details *pDetails@, tNet_message *pMessage@) int NetSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage) { LOG_TRACE("(%p, %p)", pDetails, pMessage); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none) { + return -3; + } + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + DoCheckSum(pMessage); + return PDNetSendMessageToAddress(pDetails, pMessage, &pDetails->pd_net_info); } // IDA: int __usercall NetReplyToMessage@(tNet_game_details *pDetails@, tNet_message *pIncoming_message@, tNet_message *pReply_message@) @@ -873,7 +892,23 @@ tNet_contents* NetGetToHostContents(tNet_message_type pType, tS32 pSize_decider) tU32 the_size; tNet_contents* contents; LOG_TRACE("(%d, %d)", pType, pSize_decider); - NOT_IMPLEMENTED(); + + the_size = NetGetContentsSize(pType, pSize_decider); + if (gTo_host_stack && the_size + gTo_host_stack->overall_size > MAX_MESAGE_STACK_SIZE) { + NetSendMessageToHost(gCurrent_net_game, gTo_host_stack); + gTo_host_stack = 0; + } + if (!gTo_host_stack) { + gTo_host_stack = NetAllocateMessage(MAX_MESAGE_STACK_SIZE); + gTo_host_stack->overall_size = offsetof(tNet_message, contents); + gTo_host_stack->num_contents = 0; + } + contents = (tNet_contents*)((char*)gTo_host_stack + gTo_host_stack->overall_size); + gTo_host_stack->overall_size += the_size; + contents->header.type = pType; + contents->header.contents_size = the_size; + gTo_host_stack->num_contents++; + return contents; } // IDA: tNet_contents* __usercall NetGetBroadcastContents@(tNet_message_type pType@, tS32 pSize_decider@) @@ -1453,7 +1488,10 @@ int PlayerIsInList(tPlayer_ID pID) { // IDA: void __usercall ReceivedTimeSync(tNet_contents *pContents@, tNet_message *pMessage@, tU32 pReceive_time@) void ReceivedTimeSync(tNet_contents* pContents, tNet_message* pMessage, tU32 pReceive_time) { LOG_TRACE("(%p, %p, %d)", pContents, pMessage, pReceive_time); - NOT_IMPLEMENTED(); + + if (pMessage->senders_time_stamp - pContents->data.time_sync.race_start_time > pReceive_time + 10) { + gRace_start -= pMessage->senders_time_stamp - pContents->data.time_sync.race_start_time - pReceive_time; + } } // IDA: void __usercall ReceivedConfirm(tNet_contents *pContents@) @@ -1479,7 +1517,11 @@ void ReceivedEnableCar(tNet_contents* pContents) { void ReceivedScores(tNet_contents* pContents) { int i; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + UseGeneralScore(pContents->data.scores.general_score); + for (i = 0; i < gNumber_of_net_players; i++) { + gNet_players[i].score = pContents->data.scores.scores[i]; + } } // IDA: void __usercall ReceivedWasted(tNet_contents *pContents@) @@ -1978,7 +2020,13 @@ tCar_spec* NetCarFromPlayerID(tPlayer_ID pPlayer) { tNet_game_player_info* NetPlayerFromCar(tCar_spec* pCar) { int i; LOG_TRACE("(%p)", pCar); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].car == pCar) { + return &gNet_players[i]; + } + } + return 0; } // IDA: tU32 __usercall DoCheckSum@(tNet_message *pMessage@) From 032fa8d1ab133be007c38792b1885d5c87aaa564 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Sun, 9 Jul 2023 16:36:16 +1200 Subject: [PATCH 17/40] tidy --- src/DETHRACE/common/netgame.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index b5de1d09..0acc09c1 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -768,9 +768,7 @@ int FarEnoughAway(tNet_game_player_info* pPlayer_1, tNet_game_player_info* pPlay br_vector3 difference; LOG_TRACE("(%p, %p)", pPlayer_1, pPlayer_2); - difference.v[0] = pPlayer_1->car->pos.v[0] - pPlayer_2->car->pos.v[0]; - difference.v[1] = pPlayer_1->car->pos.v[1] - pPlayer_2->car->pos.v[1]; - difference.v[2] = pPlayer_1->car->pos.v[2] - pPlayer_2->car->pos.v[2]; + BrVector3Sub(&difference, &pPlayer_1->car->pos, &pPlayer_2->car->pos); return BrVector3LengthSquared(&difference) >= 4.0f; } From 25f4401360d1d522b220f61c3a1c2afe85d4ef67 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Sun, 9 Jul 2023 20:59:41 +1200 Subject: [PATCH 18/40] mechanics --- src/DETHRACE/common/netgame.c | 113 +++++++++++++++++++++++++++++++++- src/DETHRACE/common/sound.c | 2 +- src/DETHRACE/dr_types.h | 38 ++++++------ src/S3/3d.c | 8 +-- 4 files changed, 134 insertions(+), 27 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 0acc09c1..b9ff06c8 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -179,7 +179,14 @@ void ReceivedRecover(tNet_contents* pContents) { void CopyMechanics(tCar_spec* pCar, tNet_contents* pContents) { int j; LOG_TRACE("(%p, %p)", pCar, pContents); - NOT_IMPLEMENTED(); + + memcpy(&pCar->message, pContents, pContents->header.contents_size); + // if it is not a full mechanics message... + if (pContents->header.contents_size != sizeof(tNet_message_mechanics_info)) { + for (j = 0; j < COUNT_OF(pCar->message.wheel_dam_offset); j++) { + pCar->message.wheel_dam_offset[j] = 0.0f; + } + } } // IDA: void __usercall ReceivedMechanics(tNet_contents *pContents@) @@ -187,7 +194,92 @@ void ReceivedMechanics(tNet_contents* pContents) { int i; tCar_spec* car; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + car = NULL; + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pContents->data.mech.ID) { + car = gNet_players[i].car; + break; + } + } + if (car == NULL || car->message.time >= pContents->data.mech.time) { + return; + } + if (car->disabled) { + EnableCar(car); + GetExpandedMatrix(&car->car_master_actor->t.t.mat, &pContents->data.mech.mat); + BrMatrix34Copy(&car->oldmat, &car->car_master_actor->t.t.mat); + BrVector3InvScale(&car->car_master_actor->t.t.translate.t, &car->car_master_actor->t.t.translate.t, WORLD_SCALE); + // car->car_master_actor->t.t.mat.m[3][0] = car->car_master_actor->t.t.mat.m[3][0] * 0.14492753; + // car->car_master_actor->t.t.mat.m[3][1] = car->car_master_actor->t.t.mat.m[3][1] * 0.14492753; + // car->car_master_actor->t.t.mat.m[3][2] = car->car_master_actor->t.t.mat.m[3][2] * 0.14492753; + car->box_face_ref = gFace_num__car - 2; + car->message.time = pContents->data.mech.time; + car->message.type = NETMSGID_NONE; + BrVector3Copy(&car->v, &pContents->data.mech.v); + BrVector3Copy(&car->omega, &pContents->data.mech.omega); + + for (i = 0; i < COUNT_OF(car->message.d); i++) { + car->message.d[i] = pContents->data.mech.d[i]; + } + for (i = 0; i < COUNT_OF(car->message.damage); i++) { + car->message.damage[i] = pContents->data.mech.damage[i]; + } + DisableCar(car); + return; + } + if (gNet_mode == eNet_mode_host) { + if (gThis_net_player_index == i) { + return; + } + if (car->last_car_car_collision <= pContents->data.mech.cc_coll_time) { + CopyMechanics(car, pContents); + } + car->power_up_levels[0] = pContents->data.mech.powerups & 7; + car->power_up_levels[1] = (pContents->data.mech.powerups >> 3) & 7; + car->power_up_levels[2] = (pContents->data.mech.powerups >> 6) & 7; + car->keys = car->message.keys; + if (car->message.keys.joystick_acc < 0) { + car->joystick.acc = -1; + } else { + car->joystick.acc = car->message.keys.joystick_acc << 9; + } + if (car->message.keys.joystick_dec < 0) { + car->joystick.dec = -1; + } else { + car->joystick.dec = car->message.keys.joystick_dec << 9; + } + } else if (gNet_mode == eNet_mode_client) { + if (gThis_net_player_index == i) { + if (car->last_car_car_collision < pContents->data.mech.cc_coll_time) { + CopyMechanics(car, pContents); + } + } else { + CopyMechanics(car, pContents); + car->power_up_levels[0] = pContents->data.mech.powerups & 7; + car->power_up_levels[1] = (pContents->data.mech.powerups >> 3) & 7; + car->power_up_levels[2] = (pContents->data.mech.powerups >> 6) & 7; + car->keys = car->message.keys; + if (car->message.keys.joystick_acc < 0) { + car->joystick.acc = -1; + } else { + car->joystick.acc = car->message.keys.joystick_acc << 9; + } + if (car->message.keys.joystick_dec < 0) { + car->joystick.dec = -1; + } else { + car->joystick.dec = car->message.keys.joystick_dec << 9; + } + if (!car->active) { + GetExpandedMatrix(&car->car_master_actor->t.t.mat, &pContents->data.mech.mat); + BrMatrix34Copy(&car->oldmat, &car->car_master_actor->t.t.mat); + BrMatrix34ApplyP(&car->pos, &car->cmpos, &car->car_master_actor->t.t.mat); + BrVector3InvScale(&car->car_master_actor->t.t.translate.t, &car->car_master_actor->t.t.translate.t, WORLD_SCALE); + BrVector3InvScale(&car->pos, &car->pos, WORLD_SCALE); + car->box_face_ref = gFace_num__car - 2; + } + } + } } // IDA: void __usercall ReceivedCopInfo(tNet_contents *pContents@) @@ -1311,7 +1403,22 @@ void GetReducedMatrix(tReduced_matrix* m1, br_matrix34* m2) { // IDA: void __usercall GetExpandedMatrix(br_matrix34 *m1@, tReduced_matrix *m2@) void GetExpandedMatrix(br_matrix34* m1, tReduced_matrix* m2) { LOG_TRACE("(%p, %p)", m1, m2); - NOT_IMPLEMENTED(); + + m1->m[0][0] = m2->row1.v[0]; + m1->m[0][1] = m2->row1.v[1]; + m1->m[0][2] = m2->row1.v[2]; + + m1->m[1][0] = m2->row2.v[0]; + m1->m[1][1] = m2->row2.v[1]; + m1->m[1][2] = m2->row2.v[2]; + + m1->m[3][0] = m2->translation.v[0]; + m1->m[3][1] = m2->translation.v[1]; + m1->m[3][2] = m2->translation.v[2]; + + m1->m[2][0] = m2->row2.v[2] * m2->row1.v[1] - m2->row2.v[1] * m2->row1.v[2]; + m1->m[2][1] = m2->row1.v[2] * m2->row2.v[0] - m2->row2.v[2] * m2->row1.v[0]; + m1->m[2][2] = m2->row2.v[1] * m2->row1.v[0] - m2->row1.v[1] * m2->row2.v[0]; } // IDA: void __usercall NetEarnCredits(tNet_game_player_info *pPlayer@, tS32 pCredits@) diff --git a/src/DETHRACE/common/sound.c b/src/DETHRACE/common/sound.c index f445d2ab..b936e976 100644 --- a/src/DETHRACE/common/sound.c +++ b/src/DETHRACE/common/sound.c @@ -102,7 +102,7 @@ void InitSound(void) { gSound_enabled = S3Init(the_path, gAusterity_mode) == 0; gSound_available = gSound_enabled; } - S3Set3DSoundEnvironment(0.14492753, -1.0, -1.0); + S3Set3DSoundEnvironment(1.0f / WORLD_SCALE, -1.0, -1.0); gVirgin_pass = 0; gCD_is_disabled = 0; UsePathFileToDetermineIfFullInstallation(); diff --git a/src/DETHRACE/dr_types.h b/src/DETHRACE/dr_types.h index df91d680..1d9337c6 100644 --- a/src/DETHRACE/dr_types.h +++ b/src/DETHRACE/dr_types.h @@ -490,25 +490,25 @@ typedef struct tCar_controls { // size: 0x4 unsigned int horn : 1; // 0x8000000 bit 28 } tCar_controls; -typedef struct tNet_message_mechanics_info { - tU8 contents_size; - tNet_message_type type; - tU32 ID; - tU32 time; - tReduced_matrix mat; - br_vector3 v; - br_vector3 omega; - tU8 d[4]; - tCar_controls keys; - tU32 cc_coll_time; - tS16 curvature; - tU16 revs; - br_scalar front; - br_scalar back; - tU32 repair_time; - tU8 damage[12]; - tU16 powerups; - br_scalar wheel_dam_offset[4]; +typedef struct tNet_message_mechanics_info { // size: 0x84 + tU8 contents_size; // @0x0 + tNet_message_type type; // @0x1 + tU32 ID; // @0x4 + tU32 time; // @0x8 + tReduced_matrix mat; // @0xc + br_vector3 v; // @0x30 + br_vector3 omega; // @0x3c + tU8 d[4]; // @0x48 + tCar_controls keys; // @0x4c + tU32 cc_coll_time; // @0x50 + tS16 curvature; // @0x54 + tU16 revs; // @0x56 + br_scalar front; // @0x58 + br_scalar back; // @0x5c + tU32 repair_time; // @0x60 + tU8 damage[12]; // @0x64 + tU16 powerups; // @0x70 + br_scalar wheel_dam_offset[4]; // @0x74 } tNet_message_mechanics_info; typedef struct tDamage_unit { diff --git a/src/S3/3d.c b/src/S3/3d.c index f51d6203..9b415ec5 100644 --- a/src/S3/3d.c +++ b/src/S3/3d.c @@ -24,11 +24,11 @@ float dword_531D9C; float flt_531D7C; float flt_531D98; -void S3Set3DSoundEnvironment(float a1, float a2, float a3) { +void S3Set3DSoundEnvironment(float pInverse_world_scale, float a2, float a3) { float tmp; - if (a1 == -1.0f) { - a1 = 0.25f; + if (pInverse_world_scale == -1.0f) { + pInverse_world_scale = 0.25f; } if (a2 == -1.0f) { a2 = 1.2f; @@ -36,7 +36,7 @@ void S3Set3DSoundEnvironment(float a1, float a2, float a3) { if (a3 == -1.0f) { a3 = 130000.0f; } - dword_531D9C = a1; + dword_531D9C = pInverse_world_scale; tmp = sqrtf(a3 / a2); flt_531D7C = tmp; flt_531D98 = tmp * dword_531D9C; From 6fcf8f019e0449c1b3f53777c7befaf12b284fe0 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 9 Jul 2023 18:53:28 +0200 Subject: [PATCH 19/40] Implement SortNetHeadAscending for 'Terminal Tag' --- src/DETHRACE/common/netgame.c | 38 ++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index b9ff06c8..970529e1 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -601,32 +601,52 @@ void DoNetworkHeadups(int pCredits) { ChangeHeadupText(gNet_ped_headup, s); } +#define HEADUP1 ((tHeadup_pair*)pFirst_one) +#define HEADUP2 ((tHeadup_pair*)pSecond_one) + // IDA: int __usercall SortNetHeadAscending@(void *pFirst_one@, void *pSecond_one@) int SortNetHeadAscending(void* pFirst_one, void* pSecond_one) { LOG_TRACE("(%p, %p)", pFirst_one, pSecond_one); - NOT_IMPLEMENTED(); + + if (HEADUP1->out_of_game) { + if (HEADUP2->out_of_game) { + return HEADUP1->out_of_game - HEADUP2->out_of_game; + } else { + return INT_MAX; + } + } else if (HEADUP2->out_of_game) { + return -INT_MAX; + } else if (HEADUP2->score == HEADUP1->score) { + return gNet_players[HEADUP1->player_index].last_score_index + - gNet_players[HEADUP2->player_index].last_score_index; + } else { + return HEADUP1->score - HEADUP2->score; + } } // IDA: int __usercall SortNetHeadDescending@(void *pFirst_one@, void *pSecond_one@) int SortNetHeadDescending(void* pFirst_one, void* pSecond_one) { LOG_TRACE("(%p, %p)", pFirst_one, pSecond_one); - if (((tHeadup_pair*)pFirst_one)->out_of_game) { - if (((tHeadup_pair*)pSecond_one)->out_of_game) { - return ((tHeadup_pair*)pFirst_one)->out_of_game - ((tHeadup_pair*)pSecond_one)->out_of_game; + if (HEADUP1->out_of_game) { + if (HEADUP2->out_of_game) { + return HEADUP1->out_of_game - HEADUP2->out_of_game; } else { return INT_MAX; } - } else if (((tHeadup_pair*)pSecond_one)->out_of_game) { + } else if (HEADUP2->out_of_game) { return -INT_MAX; - } else if (((tHeadup_pair*)pSecond_one)->score == ((tHeadup_pair*)pFirst_one)->score) { - return gNet_players[((tHeadup_pair*)pFirst_one)->player_index].last_score_index - - gNet_players[((tHeadup_pair*)pSecond_one)->player_index].last_score_index; + } else if (HEADUP2->score == HEADUP1->score) { + return gNet_players[HEADUP1->player_index].last_score_index + - gNet_players[HEADUP2->player_index].last_score_index; } else { - return ((tHeadup_pair*)pSecond_one)->score - ((tHeadup_pair*)pFirst_one)->score; + return HEADUP2->score - HEADUP1->score; } } +#undef HEADUP2 +#undef HEADUP1 + // IDA: void __usercall ClipName(char *pName@, tDR_font *pFont@, int pMax_width@) void ClipName(char* pName, tDR_font* pFont, int pMax_width) { LOG_TRACE("(\"%s\", %p, %d)", pName, pFont, pMax_width); From a4d3a4c8e9ae238812de9a9409247126e694762f Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 14 Jul 2023 20:31:00 +0200 Subject: [PATCH 20/40] Update WireShark dissector --- tools/dethrace.lua | 215 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 186 insertions(+), 29 deletions(-) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index c1c8fed8..5a24af75 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -110,7 +110,7 @@ function dissect_br_matrix34(parent, data, name) local row_tree = matrix_tree:add(string.format("m[%d]", row_i), data(offset, 12)) for col_i = 0, 2 do - local f = data(offset, 4):float() + local f = data(offset, 4):le_float() row_tree:add_le(f_float, data(offset, 4)):set_text(string.format("m[%d][%d] = %f", row_i, col_i, f)) offset = offset + 4 end @@ -118,6 +118,33 @@ function dissect_br_matrix34(parent, data, name) return offset end +function dissect_reduced_matrix(parent, data, name) + local matrix_tree = parent:add(name, data(0, 36)) + local offset = 0 + for row_i = 0, 2 do + local row_tree = matrix_tree:add(string.format("m[%d]", row_i), data(offset, 12)) + + for col_i = 0, 2 do + local f = data(offset, 4):le_float() + row_tree:add_le(f_float, data(offset, 4)):set_text(string.format("m[%d][%d] = %f", row_i, col_i, f)) + offset = offset + 4 + end + end + return offset +end + +function dissect_br_vector3(parent, data, name) + local tree = parent:add(name, data(0, 12)) + local offset = 0 + + for i = 0, 2 do + local f = data(offset, 4):le_float() + tree:add_le(f_float, data(offset, 4)):set_text(string.format("v[%d] = %f", i, f)) + offset = offset + 4 + end + return offset +end + function dissect_message_sendmedetails(tree, message) -- tNet_message_send_me_details (0) create_message_size_type(tree, message, "Send Me Details") @@ -470,7 +497,7 @@ end function dissect_message_statusreport(tree, message) -- tNet_message_status_report (10) - local t = create_message_size_type(tree, message, "Status Report (UNTESTED)") + local t = create_message_size_type(tree, message, "Status Report") t:add_le(f_player_status, message(4, 4)) -- finished end @@ -478,18 +505,34 @@ end f_startrace_count = ProtoField.uint32("dethrace.startrace.count", "Car Count", base.DEC) f_startrace_racing = ProtoField.bool("dethrace.startrace.racing", "Racing") f_startrace_next = ProtoField.uint32("dethrace.startrace.next", "Next Race", base.DEC, race_tracks) +f_startrace_grid_index = ProtoField.uint32("dethrace.startrace.grid.index", "Index", base.DEC) +f_startrace_grid_next_car_index = ProtoField.uint32("dethrace.startrace.grid.next_car_index", "Next Car Index", base.DEC) function dissect_message_startrace(tree, message) -- tNet_message_start_race (11) - local t = create_message_size_type(tree, message, "Start Race (UNTESTED/INCOMPLETE)") - t:add_le(f_startrace_count, message(4, 4)) - t:add_le(f_startrace_racing, message(8, 4)) - t:add_le(f_startrace_racing, message(8, 4)) - t:add_le(f_startrace_next, message(12, 4)) - for i = 0, 6 do - specdata = message(16 + i * 56, 56) - local subtree = t:add(specdata, string.format("Grid Car %d", i)) - -- FIXME + local t = create_message_size_type(tree, message, "Start Race") + local offset = 4 + + t:add_le(f_startrace_count, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_startrace_racing, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_startrace_next, message(offset, 4)) + offset = offset + 4 + + for i = 0, 5 do + local start = offset + local subtree = t:add(message(offset), string.format("Grid Car[%d]", i)) + subtree:add_le(f_startrace_grid_index, message(offset, 4)) + offset = offset + 4 + + subtree:add_le(f_startrace_grid_next_car_index, message(offset, 4)) + offset = offset + 4 + + offset = offset + dissect_br_matrix34(subtree, message(offset), "Matrix") + subtree:set_len(offset - start) end -- FIXME end @@ -522,105 +565,211 @@ function dissect_message_hostreply(tree, message) -- finished end +f_mechanics_id = ProtoField.bool("dethrace.mechanics.id", "ID") +f_mechanics_time = ProtoField.uint32("dethrace.mechanics.time", "Time") +f_mechanics_d = ProtoField.uint8("dethrace.mechanics.d", "D") +f_mechanics_carcontrols = ProtoField.uint32("dethrace.mechanics.carcontrols", "Car Controls") -- FIXME: bitmask +f_mechanics_coll_time = ProtoField.uint32("dethrace.mechanics.coll_time", "Car Control Collision Time") +f_mechanics_curvature = ProtoField.int16("dethrace.mechanics.curvature", "Curvature") +f_mechanics_revs = ProtoField.uint16("dethrace.mechanics.revs", "Revs") +f_mechanics_front = ProtoField.float("dethrace.mechanics.front", "Front") +f_mechanics_back = ProtoField.float("dethrace.mechanics.back", "Back") +f_mechanics_repair_time = ProtoField.uint32("dethrace.mechanics.repair_time", "Repair Time") +f_mechanics_powerups = ProtoField.int16("dethrace.mechanics.powerups", "Powerups") +f_mechanics_damage = ProtoField.uint8("dethrace.mechanics.damage", "Damage") + function dissect_message_mechanics(tree, message) -- tNet_message_mechanics_info (15) local t = create_message_size_type(tree, message, "Mechanics") - -- FIXME + local offset = 4 + + t:add_le(f_mechanics_id, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_mechanics_time, message(offset, 4)) + offset = offset + 4 + + offset = offset + dissect_reduced_matrix(t, message(offset), "Matrix") + + offset = offset + dissect_br_vector3(t, message(offset), "Velocity") + + offset = offset + dissect_br_vector3(t, message(offset), "Omega") + + do + local sub = t:add("d", message(offset, 4)) + for i = 0, 3 do + local item = sub:add_le(f_mechanics_d, message(offset, 1)) + item:set_text(string.format("d[%d] = %d", i, message(offset, 1):le_uint())) + offset = offset + 1 + end + end + + t:add_le(f_mechanics_carcontrols, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_mechanics_coll_time, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_mechanics_curvature, message(offset, 2)) + offset = offset + 2 + + t:add_le(f_mechanics_revs, message(offset, 2)) + offset = offset + 2 + + t:add_le(f_mechanics_front, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_mechanics_back, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_mechanics_repair_time, message(offset, 4)) + offset = offset + 4 + + t:add_le(f_mechanics_powerups, message(offset, 2)) + offset = offset + 2 + + do + local sub = t:add("Damage", message(offset, 4)) + for i = 0, 11 do + local item = sub:add_le(f_mechanics_damage, message(offset, 1)) + item:set_text(string.format("damage[%d] = %d", i, message(offset, 1):le_uint())) + offset = offset + 1 + end + end + + t:add_le(f_mechanics_powerups, message(offset, 2)) + offset = offset + 2 + + -- omit 2 bytes of padding + offset = offset + 2 + + if offset < message:len() then + do + local sub = t:add("Wheel Damage Offset", message(offset, 4)) + for i = 0, 3 do + local item = sub:add_le(f_float, message(offset, 4)) + item:set_text(string.format("offset[%d] = %d", i, message(offset, 4):le_float())) + offset = offset + 4 + end + end + end end function dissect_message_noncar_info(tree, message) -- tNet_message_non_car_info (16) - local t = create_message_size_type(tree, message, "Non-Car Info") + local t = create_message_size_type(tree, message, "Non-Car Info (INCOMPLETE)") -- FIXME end +f_timesync_time = ProtoField.uint32("dethrace.timesync.start_time", "Race Start Time") + function dissect_message_timesync(tree, message) -- tNet_message_time_sync (17) local t = create_message_size_type(tree, message, "Time Sync") - -- FIXME + local offset = 4 + + t:add_le(f_timesync_time, message(offset, 4)) + offset = offset + 4 end function dissect_message_confirm(tree, message) -- tNet_message_players_confirm (18) - local t = create_message_size_type(tree, message, "Confirm") + local t = create_message_size_type(tree, message, "Confirm (INCOMPLETE)") -- FIXME end function dissect_message_disablecar(tree, message) -- tNet_message_disable_car (19) - local t = create_message_size_type(tree, message, "Disable Car") + local t = create_message_size_type(tree, message, "Disable Car (INCOMPLETE)") -- FIXME end function dissect_message_enablecar(tree, message) -- tNet_message_enable_car (20) - local t = create_message_size_type(tree, message, "Enable Car") + local t = create_message_size_type(tree, message, "Enable Car (INCOMPLETE)") -- FIXME end function dissect_message_powerup(tree, message) -- tNet_message_powerup (21) - local t = create_message_size_type(tree, message, "Power-Up") + local t = create_message_size_type(tree, message, "Power-Up (INCOMPLETE)") -- FIXME end function dissect_message_recover(tree, message) -- tNet_message_recover (22) - local t = create_message_size_type(tree, message, "Recover") + local t = create_message_size_type(tree, message, "Recover (INCOMPLETE)") -- FIXME end +f_scores_played = ProtoField.bool("dethrace.score.played", "Played") +f_scores_won = ProtoField.bool("dethrace.scored.won", "Won") +f_scores_score = ProtoField.int32("dethrace.scored.score", "Score") + function dissect_message_scores(tree, message) -- tNet_message_game_scores (23) local t = create_message_size_type(tree, message, "Scores") - -- FIXME + local offset = 4 + + for i = 0, 5 do + local subtree = t:add(string.format("Scores[%d]", i), message(offset, 12)) + + subtree:add_le(f_scores_played, message(offset, 4)) + offset = offset + 4 + + subtree:add_le(f_scores_won, message(offset, 4)) + offset = offset + 4 + + subtree:add_le(f_scores_score, message(offset, 4)) + offset = offset + 4 + end end function dissect_message_wasted(tree, message) -- tNet_message_wasted (24) - local t = create_message_size_type(tree, message, "Wasted") + local t = create_message_size_type(tree, message, "Wasted (INCOMPLETE)") -- FIXME end function dissect_message_pedestrian(tree, message) -- tNet_message_pedestrian (25) - local t = create_message_size_type(tree, message, "Pedestrian") + local t = create_message_size_type(tree, message, "Pedestrian (INCOMPLETE)") -- FIXME end function dissect_message_gameplay(tree, message) -- tNet_message_gameplay (26) - local t = create_message_size_type(tree, message, "Gameplay") + local t = create_message_size_type(tree, message, "Gameplay (INCOMPLETE)") -- FIXME end function dissect_message_noncarposition(tree, message) -- tNet_message_non_car_position (27) - local t = create_message_size_type(tree, message, "Non-Car Position") + local t = create_message_size_type(tree, message, "Non-Car Position (INCOMPLETE)") -- FIXME end function dissect_message_copinfo(tree, message) -- tNet_message_cop_info (28) - local t = create_message_size_type(tree, message, "Cop Info") + local t = create_message_size_type(tree, message, "Cop Info (INCOMPLETE)") -- FIXME end function dissect_message_gamescores(tree, message) -- tNet_message_oil_spill (29) - local t = create_message_size_type(tree, message, "Game Scores") + local t = create_message_size_type(tree, message, "Game Scores (INCOMPLETE)") -- FIXME end function dissect_message_oilspill(tree, message) -- tNet_message_oil_spill (30) - local t = create_message_size_type(tree, message, "Oil Spill") + local t = create_message_size_type(tree, message, "Oil Spill (INCOMPLETE)") -- FIXME end function dissect_message_crushpoint(tree, message) -- tNet_message_crush_point (31) - local t = create_message_size_type(tree, message, "Crush Point") + local t = create_message_size_type(tree, message, "Crush Point (INCOMPLETE)") -- FIXME end @@ -661,12 +810,20 @@ dethrace_protocol.fields = { f_statusreport_status, - f_startrace_count, f_startrace_racing, f_startrace_next, + f_startrace_count, f_startrace_racing, f_startrace_next, f_startrace_grid_index, f_startrace_grid_next_car_index, f_headup_text, f_hostreply_started, f_hostreply_race, f_hostreply_pending, f_player_status, + + f_mechanics_id, f_mechanics_time, f_mechanics_d, f_mechanics_carcontrols, f_mechanics_coll_time, + f_mechanics_curvature, f_mechanics_revs, f_mechanics_front, f_mechanics_back, f_mechanics_repair_time, + f_mechanics_powerups, f_mechanics_damage, + + f_timesync_time, + + f_scores_played, f_scores_won, f_scores_score, } dethrace_message_dissectors = { From 6867fee105f2fd2dc73ddb362e76176a829d419c Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 14 Jul 2023 21:14:57 +0200 Subject: [PATCH 21/40] start of tNet_message_pedestrian dissector --- tools/dethrace.lua | 100 ++++++++++++++++++++++++++++++--------------- 1 file changed, 66 insertions(+), 34 deletions(-) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index 5a24af75..ec34939d 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -91,7 +91,11 @@ function create_message_size_type(parent, message, name) local tree = parent:add(dethrace_protocol, message(), string.format("%s (%d)", name, message_type)) tree:add_le(f_contents_size, message(0, 1)) tree:add_le(f_contents_type, message(1, 1)) - return tree + result = {} + result["tree"] = tree + result["size"] = message(0, 1):le_uint() + result["type"] = message(1, 1):le_uint() + return result end f_pd_player_info = ProtoField.bytes("dethrace.pd_info", "PD Net Info") @@ -147,7 +151,7 @@ end function dissect_message_sendmedetails(tree, message) -- tNet_message_send_me_details (0) - create_message_size_type(tree, message, "Send Me Details") + local t = create_message_size_type(tree, message, "Send Me Details")["tree"] -- finished end @@ -243,7 +247,7 @@ end function dissect_message_details(tree, message) -- tNet_message_my_details (1) - local t = create_message_size_type(tree, message, "Details") + local t = create_message_size_type(tree, message, "Details")["tree"] local offset = 2 offset = offset + dissect_pd_player_info(t, message(offset)) @@ -385,7 +389,7 @@ end function dissect_message_join(tree, message) -- tNet_message_join (2) - local t = create_message_size_type(tree, message, "Join") + local t = create_message_size_type(tree, message, "Join")["tree"] local offset = 4 dissect_game_player_info(t:add("Player Info", message(offset)), message(offset)) @@ -402,7 +406,7 @@ f_newplayerlist_batch_number = ProtoField.int32("dethrace.newplayerlist.batch_nu function dissect_message_newplayerlist(tree, message) -- tNet_message_new_player_list (3) - local t = create_message_size_type(tree, message, "New Player List") + local t = create_message_size_type(tree, message, "New Player List")["tree"] local offset = 4 local t_count = t:add_le(f_newplayerlist_count, message(offset, 4)) @@ -427,7 +431,7 @@ f_guaranteereply_number = ProtoField.uint32("dethrace.guaranteereply.number", "G function dissect_message_guaranteereply(tree, message) -- tNet_message_guarantee_reply (4) - local t = create_message_size_type(tree, message, "Guarantee Reply") + local t = create_message_size_type(tree, message, "Guarantee Reply")["tree"] t:add_le(f_guaranteereply_number, message(4, 4)) -- FIXME: add reference to packet with this reply number -- finished @@ -435,7 +439,7 @@ end function dissect_message_cardetailsreq(tree, message) -- tNet_message_car_details_req (5) - create_message_size_type(tree, message, "Car Details Req") + local t = create_message_size_type(tree, message, "Car Details Req")["tree"] -- finished end @@ -445,7 +449,7 @@ f_cardetails_owner = ProtoField.stringz("dethrace.cardetails.owner", "Owner") function dissect_message_cardetails(tree, message) -- tNet_message_car_details (6) - local t = create_message_size_type(tree, message, "Car Details") + local t = create_message_size_type(tree, message, "Car Details")["tree"] local offset = 4 t:add_le(f_cardetails_count, message(4, 4)) @@ -464,13 +468,13 @@ end function dissect_message_leave(tree, message) -- tNet_message_leave (7) - create_message_size_type(tree, message, "Leave") + local t = create_message_size_type(tree, message, "Leave")["tree"] -- finished end function dissect_message_hosticide(tree, message) -- tNet_message_host_pissing_off (8) - create_message_size_type(tree, message, "Hosticide") + local t = create_message_size_type(tree, message, "Hosticide")["tree"] -- finished end @@ -490,14 +494,14 @@ f_raceover_reason = ProtoField.uint32("dethrace.raceover.reason", "Reason", base function dissect_message_raceover(tree, message) -- tNet_message_race_over (9) - local t = create_message_size_type(tree, message, "Race Over (UNTESTED)") + local t = create_message_size_type(tree, message, "Race Over (UNTESTED)")["tree"] t:add_le(f_raceover_reason, message(4, 4)) -- finished end function dissect_message_statusreport(tree, message) -- tNet_message_status_report (10) - local t = create_message_size_type(tree, message, "Status Report") + local t = create_message_size_type(tree, message, "Status Report")["tree"] t:add_le(f_player_status, message(4, 4)) -- finished end @@ -510,7 +514,7 @@ f_startrace_grid_next_car_index = ProtoField.uint32("dethrace.startrace.grid.nex function dissect_message_startrace(tree, message) -- tNet_message_start_race (11) - local t = create_message_size_type(tree, message, "Start Race") + local t = create_message_size_type(tree, message, "Start Race")["tree"] local offset = 4 t:add_le(f_startrace_count, message(offset, 4)) @@ -541,14 +545,14 @@ f_headup_text = ProtoField.stringz("dethrace.headup.message", "Message") function dissect_message_headup(tree, message) -- tNet_message_headup (12) - local t = create_message_size_type(tree, message, "Head-Up (UNTESTED)") + local t = create_message_size_type(tree, message, "Head-Up (UNTESTED)")["tree"] t:add(f_headup_text, message(4, 128)) -- finished end function dissect_message_hostquery(tree, message) -- tNet_message_host_query (13) - create_message_size_type(tree, message, "Host Query") + local t = create_message_size_type(tree, message, "Host Query")["tree"] -- finished end @@ -558,7 +562,7 @@ f_hostreply_pending = ProtoField.uint32("dethrace.hostreply.pending", "Pending R function dissect_message_hostreply(tree, message) -- tNet_message_host_reply (14) - local t = create_message_size_type(tree, message, "Host Reply (UNTESTED)") + local t = create_message_size_type(tree, message, "Host Reply (UNTESTED)")["tree"] t:add(f_hostreply_started, message(4, 4)) t:add(f_hostreply_race, message(8, 4)) t:add(f_hostreply_pending, message(12, 4)) @@ -580,7 +584,7 @@ f_mechanics_damage = ProtoField.uint8("dethrace.mechanics.damage", "Damage") function dissect_message_mechanics(tree, message) -- tNet_message_mechanics_info (15) - local t = create_message_size_type(tree, message, "Mechanics") + local t = create_message_size_type(tree, message, "Mechanics")["tree"] local offset = 4 t:add_le(f_mechanics_id, message(offset, 4)) @@ -630,6 +634,7 @@ function dissect_message_mechanics(tree, message) do local sub = t:add("Damage", message(offset, 4)) + -- FIXME: use names of damage system (in addition to index) for i = 0, 11 do local item = sub:add_le(f_mechanics_damage, message(offset, 1)) item:set_text(string.format("damage[%d] = %d", i, message(offset, 1):le_uint())) @@ -657,7 +662,7 @@ end function dissect_message_noncar_info(tree, message) -- tNet_message_non_car_info (16) - local t = create_message_size_type(tree, message, "Non-Car Info (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Non-Car Info (INCOMPLETE)")["tree"] -- FIXME end @@ -665,7 +670,7 @@ f_timesync_time = ProtoField.uint32("dethrace.timesync.start_time", "Race Start function dissect_message_timesync(tree, message) -- tNet_message_time_sync (17) - local t = create_message_size_type(tree, message, "Time Sync") + local t = create_message_size_type(tree, message, "Time Sync")["tree"] local offset = 4 t:add_le(f_timesync_time, message(offset, 4)) @@ -674,31 +679,31 @@ end function dissect_message_confirm(tree, message) -- tNet_message_players_confirm (18) - local t = create_message_size_type(tree, message, "Confirm (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Confirm (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_disablecar(tree, message) -- tNet_message_disable_car (19) - local t = create_message_size_type(tree, message, "Disable Car (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Disable Car (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_enablecar(tree, message) -- tNet_message_enable_car (20) - local t = create_message_size_type(tree, message, "Enable Car (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Enable Car (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_powerup(tree, message) -- tNet_message_powerup (21) - local t = create_message_size_type(tree, message, "Power-Up (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Power-Up (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_recover(tree, message) -- tNet_message_recover (22) - local t = create_message_size_type(tree, message, "Recover (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Recover (INCOMPLETE)")["tree"] -- FIXME end @@ -708,7 +713,8 @@ f_scores_score = ProtoField.int32("dethrace.scored.score", "Score") function dissect_message_scores(tree, message) -- tNet_message_game_scores (23) - local t = create_message_size_type(tree, message, "Scores") + local header = create_message_size_type(tree, message, "Scores") + local t = header["tree"] local offset = 4 for i = 0, 5 do @@ -727,55 +733,79 @@ end function dissect_message_wasted(tree, message) -- tNet_message_wasted (24) - local t = create_message_size_type(tree, message, "Wasted (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Wasted (INCOMPLETE)")["tree"] -- FIXME end +f_ped_instruction = ProtoField.int8("dethrace.ped.instruction", "Action Instruction") +f_ped_flags = ProtoField.int8("dethrace.ped.flags", "Flags") +f_ped_index = ProtoField.int16("dethrace.ped.index", "Index") + function dissect_message_pedestrian(tree, message) -- tNet_message_pedestrian (25) - local t = create_message_size_type(tree, message, "Pedestrian (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Pedestrian (INCOMPLETE)")["tree"] + local offset = 2 + + t:add_le(f_ped_instruction, message(offset, 1)) + offset = offset + 1 + + t:add_le(f_ped_flags, message(offset, 1)) + offset = offset + 1 + + t:add_le(f_ped_index, message(offset, 2)) + offset = offset + 2 + + -- padding + offset = offset + 2 + + offset = offset + dissect_br_vector3(t, message(offset, 12), "Position") + + t:add_le(f_float, message(offset, 4)):set_text(string.format("Speed: %f", message(offset, 4):le_float())) + offset = offset + 4 + + --offset = offset + dissect_br_vector3(t, message(offset, 12), "to_pos") -- FIXME end function dissect_message_gameplay(tree, message) -- tNet_message_gameplay (26) - local t = create_message_size_type(tree, message, "Gameplay (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Gameplay (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_noncarposition(tree, message) -- tNet_message_non_car_position (27) - local t = create_message_size_type(tree, message, "Non-Car Position (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Non-Car Position (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_copinfo(tree, message) -- tNet_message_cop_info (28) - local t = create_message_size_type(tree, message, "Cop Info (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Cop Info (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_gamescores(tree, message) -- tNet_message_oil_spill (29) - local t = create_message_size_type(tree, message, "Game Scores (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Game Scores (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_oilspill(tree, message) -- tNet_message_oil_spill (30) - local t = create_message_size_type(tree, message, "Oil Spill (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Oil Spill (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_crushpoint(tree, message) -- tNet_message_crush_point (31) - local t = create_message_size_type(tree, message, "Crush Point (INCOMPLETE)") + local t = create_message_size_type(tree, message, "Crush Point (INCOMPLETE)")["tree"] -- FIXME end function dissect_message_none(tree, message) -- none (32) - create_message_size_type(tree, message, "None") + local t = create_message_size_type(tree, message, "None")["tree"] -- finished end @@ -824,6 +854,8 @@ dethrace_protocol.fields = { f_timesync_time, f_scores_played, f_scores_won, f_scores_score, + + f_ped_instruction, f_ped_flags, f_ped_index, } dethrace_message_dissectors = { From 707973a8adb5afe663f61f9a4397297184f03da2 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Sun, 16 Jul 2023 09:37:41 +1200 Subject: [PATCH 22/40] network player cars can see each other move --- src/DETHRACE/common/car.c | 66 +++++++++++++++++++++++++++++++++-- src/DETHRACE/common/errors.c | 8 ++--- src/DETHRACE/common/netgame.c | 61 +++++++++++++++++++++++++++++--- src/DETHRACE/common/network.c | 17 +++++++-- 4 files changed, 137 insertions(+), 15 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index db992113..03f29261 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -886,8 +886,7 @@ void CalcEngineForce(tCar_spec* c, br_scalar dt) { } else if (c->joystick.acc < 0) { ts = 1.2; } else { - ts = c->joystick.acc / 54613.0; - LOG_PANIC("ooo"); + ts = c->joystick.acc / 54613.0f; } torque = c->engine_power_multiplier * ts * gEngine_powerup_factor[c->power_up_levels[1]]; @@ -1085,7 +1084,68 @@ void GetNetPos(tCar_spec* pCar) { float amount; br_scalar total_deflection; LOG_TRACE("(%p)", pCar); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_host && pCar->last_car_car_collision > pCar->message.cc_coll_time) { + pCar->message.type = 0; + pCar->dt = -1.0f; + return; + } + if (fabsf(pCar->message.omega.v[0]) > 10000.0 + || fabsf(pCar->message.omega.v[1]) > 10000.0 + || fabsf(pCar->message.omega.v[2]) > 10000.0 + || fabsf(pCar->message.omega.v[0]) > 10000.0 + || fabsf(pCar->message.omega.v[1]) > 10000.0 + || fabsf(pCar->message.omega.v[2]) > 10000.0) { + BrVector3SetFloat(&pCar->message.omega, 0.0, 0.0, 0.0); + BrVector3SetFloat(&pCar->message.v, 0.0, 0.0, 0.0); + } + GetExpandedMatrix(&pCar->car_master_actor->t.t.mat, &pCar->message.mat); + if (gNet_mode == eNet_mode_client) { + BrMatrix34Copy(&pCar->oldmat, &pCar->car_master_actor->t.t.mat); + } + + BrVector3Copy(&pCar->v, &pCar->message.v); + BrVector3Copy(&pCar->omega, &pCar->message.omega); + + if (pCar->driver > eDriver_non_car) { + pCar->curvature = pCar->message.curvature * pCar->maxcurve / 32767.0f; + for (j = 0; j < sizeof(pCar->oldd); j++) { + pCar->oldd[j] = (pCar->message.d[j] * pCar->susp_height[j >> 1]) / 255.0f; + } + if (pCar->driver == eDriver_oppo || pCar->repair_time >= pCar->message.repair_time) { + for (j = 0; j < COUNT_OF(pCar->damage_units); j++) { + pCar->damage_units[j].damage_level = pCar->message.damage[j]; + } + SortOutSmoke(pCar); + } else { + if (pCar->message.repair_time - pCar->repair_time < 100000) { + amount = RepairCar2(pCar, pCar->message.repair_time - pCar->repair_time, &total_deflection); + } else { + TotallyRepairACar(pCar); + pCar->repair_time = pCar->message.repair_time; + } + for (j = 0; j < COUNT_OF(pCar->damage_units); j++) { + pCar->damage_units[j].damage_level = pCar->message.damage[j]; + } + SetSmokeLastDamageLevel(pCar); + StopCarSmoking(pCar); + } + if (pCar->driver == eDriver_net_human) { + pCar->revs = pCar->message.revs; + } + if (pCar->driver >= eDriver_net_human) { + pCar->bounds[1].min.v[2] = pCar->message.front; + pCar->bounds[1].max.v[2] = pCar->message.back; + } + if (pCar->driver != eDriver_local_human) { + for (j = 0; j < COUNT_OF(pCar->wheel_dam_offset); j++) { + pCar->wheel_dam_offset[j] = pCar->message.wheel_dam_offset[j]; + } + } + GetFacesInBox((tCollision_info*)pCar); + } + pCar->message.type = 0; + pCar->last_car_car_collision = pCar->message.cc_coll_time; } // IDA: void __usercall ApplyPhysicsToCars(tU32 last_frame_time@, tU32 pTime_difference@) diff --git a/src/DETHRACE/common/errors.c b/src/DETHRACE/common/errors.c index 7d95a792..81d7607b 100644 --- a/src/DETHRACE/common/errors.c +++ b/src/DETHRACE/common/errors.c @@ -260,10 +260,10 @@ void dr_dprintf(char* fmt_string, ...) { fflush(gDiagnostic_file); // Added by dethrace for debugging - // va_start(args, fmt_string); - // vprintf(fmt_string, args); - // va_end(args); - // printf("\n"); + va_start(args, fmt_string); + vprintf(fmt_string, args); + va_end(args); + printf("\n"); } // IDA: int __usercall DoErrorInterface@(int pMisc_text_index@) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 970529e1..4cc0b041 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -1,5 +1,6 @@ #include "netgame.h" #include "brender/brender.h" +#include "brucetrk.h" #include "car.h" #include "controls.h" #include "crush.h" @@ -64,7 +65,7 @@ void SendCarData(tU32 pNext_frame_time) { continue; } damaged_wheels = car->damage_units[eDamage_lf_wheel].damage_level > 30 || car->damage_units[eDamage_rf_wheel].damage_level > 30 || car->damage_units[eDamage_lr_wheel].damage_level > 30 || car->damage_units[eDamage_rr_wheel].damage_level > 30; - contents = NetGetBroadcastContents(0xFu, damaged_wheels); + contents = NetGetBroadcastContents(NETMSGID_MECHANICS, damaged_wheels); GetReducedMatrix(&contents->data.mech.mat, &car->car_master_actor->t.t.mat); contents->data.mech.ID = gNet_players[i].ID; contents->data.mech.time = pNext_frame_time; @@ -330,7 +331,57 @@ void ReceivedNonCar(tNet_contents* pContents) { tNon_car_spec* ncar; tCollision_info* c; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + track_spec = &gProgram_state.track_spec; + if (pContents->data.non_car.ID >= track_spec->ampersand_digits) { + return; + } + actor = track_spec->non_car_list[pContents->data.non_car.ID]; + if (actor == NULL) { + return; + } + ncar = (tNon_car_spec*)actor->type_data; + if (ncar && (ncar->collision_info.driver != eDriver_non_car || ncar->collision_info.car_ID != pContents->data.non_car.ID)) { + ncar = NULL; + } + if ((pContents->data.non_car.flags & 1) != 0) { + actor->identifier[3] = '!'; + } else { + actor->identifier[3] = 'x'; + } + if (!ncar && actor->identifier[1] >= '0' && actor->identifier[1] <= '9') { + BrVector3Sub(&tv, &gProgram_state.current_car.car_master_actor->t.t.translate.t, &actor->t.t.translate.t); + if (BrVector3LengthSquared(&tv) < 900.0f) { + DoPullActorFromWorld(actor); + ncar = (tNon_car_spec*)actor->type_data; + } + } + if (ncar) { + c = &ncar->collision_info; + if ((pContents->data.non_car.flags & 2) != 0) { + GetExpandedMatrix(&c->car_master_actor->t.t.mat, &pContents->data.non_car.mat); + BrVector3Copy(&c->v, &pContents->data.non_car.v); + BrVector3Copy(&c->omega, &pContents->data.non_car.omega); + c->doing_nothing_flag = 1; + } else { + BrVector3Copy(&c->message.v, &pContents->data.non_car.v); + BrVector3Copy(&c->message.omega, &pContents->data.non_car.omega); + memcpy(&c->message.mat, &pContents->data.non_car.mat, sizeof(c->message.mat)); + c->message.time = pContents->data.non_car.time; + c->message.type = NETMSGID_NONCAR_INFO; + c->doing_nothing_flag = 0; + } + } else { + GetExpandedMatrix(&actor->t.t.mat, &pContents->data.mech.mat); + BrVector3InvScale(&actor->t.t.translate.t, &actor->t.t.translate.t, WORLD_SCALE); + XZToColumnXZ(&cx, &cz, actor->t.t.translate.t.v[0], actor->t.t.translate.t.v[2], track_spec); + if (track_spec->columns[cz][cx] != actor->parent) { + if (track_spec->columns[cz][cx]) { + BrActorRemove(actor); + BrActorAdd(track_spec->columns[cz][cx], actor); + } + } + } } // IDA: void __usercall SignalToStartRace2(int pIndex@) @@ -1415,9 +1466,9 @@ void GetReducedMatrix(tReduced_matrix* m1, br_matrix34* m2) { m1->row2.v[0] = m2->m[1][0]; m1->row2.v[1] = m2->m[1][1]; m1->row2.v[2] = m2->m[1][2]; - m1->translation.v[0] = m2->m[2][0]; - m1->translation.v[1] = m2->m[2][1]; - m1->translation.v[2] = m2->m[2][2]; + m1->translation.v[0] = m2->m[3][0]; + m1->translation.v[1] = m2->m[3][1]; + m1->translation.v[2] = m2->m[3][2]; } // IDA: void __usercall GetExpandedMatrix(br_matrix34 *m1@, tReduced_matrix *m2@) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index a96fd7b7..3ac44503 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -1010,7 +1010,7 @@ tNet_message* NetAllocateMessage(int pSize) { } else { gMessage_to_free = pointer; } - pointer = ((void**)pointer)[1]; + pointer = (char*)pointer + sizeof(void*); } } if (pointer == NULL) { @@ -2005,7 +2005,13 @@ void NetWaitForGuaranteeReplies(void) { tNet_game_player_info* NetPlayerFromID(tPlayer_ID pPlayer) { int i; LOG_TRACE("(%d)", pPlayer); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pPlayer) { + return &gNet_players[i]; + } + } + return 0; } // IDA: tCar_spec* __usercall NetCarFromPlayerID@(tPlayer_ID pPlayer@) @@ -2013,7 +2019,12 @@ tCar_spec* NetCarFromPlayerID(tPlayer_ID pPlayer) { int i; tNet_game_player_info* player; LOG_TRACE("(%d)", pPlayer); - NOT_IMPLEMENTED(); + + player = NetPlayerFromID(pPlayer); + if (player) { + return player->car; + } + return NULL; } // IDA: tNet_game_player_info* __usercall NetPlayerFromCar@(tCar_spec *pCar@) From 4a638c6f7930c1912b84ef0f4f28272882af6af4 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Sun, 16 Jul 2023 09:39:09 +1200 Subject: [PATCH 23/40] netmsgid tidy ups --- src/DETHRACE/common/car.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index 03f29261..98c96771 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1196,7 +1196,7 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) { for (i = 0; i < gNum_active_cars; i++) { car = gActive_car_list[i]; car->dt = -1.f; - if (car->message.type == 15 && car->message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= car->message.time) { + if (car->message.type == NETMSGID_MECHANICS && car->message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= car->message.time) { car->dt = (double)(gLast_mechanics_time + harness_game_config.physics_step_time - car->message.time) / 1000.0; if (gDt - 0.0001f <= car->dt) { GetNetPos(car); @@ -1230,7 +1230,7 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) { non_car = gActive_non_car_list[i]; if (!non_car->collision_info.doing_nothing_flag) { non_car->collision_info.dt = -1.f; - if (non_car->collision_info.message.type == 16 && non_car->collision_info.message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= non_car->collision_info.message.time) { + if (non_car->collision_info.message.type == NETMSGID_NONCAR_INFO && non_car->collision_info.message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= non_car->collision_info.message.time) { non_car->collision_info.dt = (gLast_mechanics_time + harness_game_config.physics_step_time - non_car->collision_info.message.time) / 1000.0f; GetNetPos((tCar_spec*)non_car); } From ca7b84dabac5544dcff8c4b29bc94bc17aca0b25 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sun, 16 Jul 2023 17:46:28 +0200 Subject: [PATCH 24/40] dissector: print HOST/CLIENT in info column --- tools/dethrace.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/dethrace.lua b/tools/dethrace.lua index ec34939d..bb371c64 100644 --- a/tools/dethrace.lua +++ b/tools/dethrace.lua @@ -569,7 +569,7 @@ function dissect_message_hostreply(tree, message) -- finished end -f_mechanics_id = ProtoField.bool("dethrace.mechanics.id", "ID") +f_mechanics_id = ProtoField.uint32("dethrace.mechanics.id", "ID") f_mechanics_time = ProtoField.uint32("dethrace.mechanics.time", "Time") f_mechanics_d = ProtoField.uint8("dethrace.mechanics.d", "D") f_mechanics_carcontrols = ProtoField.uint32("dethrace.mechanics.carcontrols", "Car Controls") -- FIXME: bitmask @@ -917,9 +917,15 @@ function dethrace_protocol.dissector(buffer, pinfo, tree) t:add_le(f_message_count, buffer(24, 2)) t:add_le(f_message_size, buffer(26, 2)) end + local sender_type_str + if (pinfo.src_port == DETHRACE_PORT) then + sender_type_str = "HOST" + else + sender_type_str = "CLIENT" + end local message = buffer(28) local message_type = message(1, 1):uint() - pinfo.cols.info = string.format("%s (%d)", content_types[message_type], message_type) + pinfo.cols.info = string.format("[%s] %s (%d)", sender_type_str, content_types[message_type], message_type) dethrace_message_dissectors[message_type](tree, message) end end From a6e859ae5ce797f63a32efc8ded48ef0eee42974 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Sat, 22 Jul 2023 02:16:11 +0200 Subject: [PATCH 25/40] Don't allow hosting a game when starting dethrace with --no-bind --- src/DETHRACE/common/newgame.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/DETHRACE/common/newgame.c b/src/DETHRACE/common/newgame.c index 14110167..ed406638 100644 --- a/src/DETHRACE/common/newgame.c +++ b/src/DETHRACE/common/newgame.c @@ -1814,6 +1814,13 @@ int DoMultiPlayerStart(void) { return 1; } case eJoin_or_host_host: +#if defined(DETHRACE_FIX_BUGS) + /* Don't allow hosting a game when the game is launched with --no-bind */ + if (harness_game_config.no_bind) { + DoErrorInterface(76); + return 0; + } +#endif gProgram_state.frank_or_anniness = eFrankie; if (!OriginalCarmaCDinDrive()) { DoErrorInterface(223); From 7fc992497260ee81e02ecc5abe25a287108bf427 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Thu, 27 Jul 2023 16:47:40 +1200 Subject: [PATCH 26/40] fix oldd copy --- src/DETHRACE/common/car.c | 4 ++-- src/DETHRACE/common/netgame.c | 4 ++-- src/DETHRACE/common/network.c | 8 +++++++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index 98c96771..e32449db 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1103,13 +1103,12 @@ void GetNetPos(tCar_spec* pCar) { if (gNet_mode == eNet_mode_client) { BrMatrix34Copy(&pCar->oldmat, &pCar->car_master_actor->t.t.mat); } - BrVector3Copy(&pCar->v, &pCar->message.v); BrVector3Copy(&pCar->omega, &pCar->message.omega); if (pCar->driver > eDriver_non_car) { pCar->curvature = pCar->message.curvature * pCar->maxcurve / 32767.0f; - for (j = 0; j < sizeof(pCar->oldd); j++) { + for (j = 0; j < COUNT_OF(pCar->oldd); j++) { pCar->oldd[j] = (pCar->message.d[j] * pCar->susp_height[j >> 1]) / 255.0f; } if (pCar->driver == eDriver_oppo || pCar->repair_time >= pCar->message.repair_time) { @@ -1144,6 +1143,7 @@ void GetNetPos(tCar_spec* pCar) { } GetFacesInBox((tCollision_info*)pCar); } + pCar->message.type = 0; pCar->last_car_car_collision = pCar->message.cc_coll_time; } diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 4cc0b041..823b2e1b 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -77,7 +77,7 @@ void SendCarData(tU32 pNext_frame_time) { contents->data.mech.keys.joystick_dec = (tU8)(car->joystick.dec >> 9); contents->data.mech.revs = car->revs; for (j = 0; j < COUNT_OF(contents->data.mech.d); j++) { - contents->data.mech.d[j] = car->oldd[j] / car->susp_height[j >> 1] * 255.0f; + contents->data.mech.d[j] = (int)(car->oldd[j] / car->susp_height[j >> 1] * 255.0f); } for (j = 0; j < COUNT_OF(contents->data.mech.damage); j++) { contents->data.mech.damage[j] = car->damage_units[j].damage_level; @@ -147,7 +147,7 @@ void SendCarData(tU32 pNext_frame_time) { contents->data.mech.revs = car->revs; contents->data.mech.cc_coll_time = car->last_car_car_collision; for (j = 0; j < COUNT_OF(contents->data.mech.d); j++) { - contents->data.mech.d[j] = car->oldd[j] / car->susp_height[j >> 1] * 255.f; + contents->data.mech.d[j] = (int)(car->oldd[j] / car->susp_height[j >> 1] * 255.f); } for (j = 0; j < COUNT_OF(contents->data.mech.damage); j++) { contents->data.mech.damage[j] = car->damage_units[j].damage_level; diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 3ac44503..00392ad8 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -1875,7 +1875,13 @@ int NetGuaranteedSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_messa // IDA: int __usercall NetGuaranteedSendMessageToEverybody@(tNet_game_details *pDetails@, tNet_message *pMessage@, int (*pNotifyFail)(tU32, tNet_message*)@) int NetGuaranteedSendMessageToEverybody(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) { LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail); - NOT_IMPLEMENTED(); + + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + pMessage->num_contents = 1; + pMessage->guarantee_number = 0; + ReceivedMessage(pMessage, &gNet_players[gThis_net_player_index], GetRaceTime()); + return NetGuaranteedSendMessageToAllPlayers(pDetails, pMessage, pNotifyFail); } // IDA: int __usercall NetGuaranteedSendMessageToHost@(tNet_game_details *pDetails@, tNet_message *pMessage@, int (*pNotifyFail)(tU32, tNet_message*)@) From 523ef3d80fdcaf0f5558c742fe604017993afeb4 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Thu, 27 Jul 2023 22:26:24 +1200 Subject: [PATCH 27/40] time_step is integer, fixes client car out of sync --- src/DETHRACE/common/car.c | 9 ++++++--- src/DETHRACE/common/netgame.c | 11 +++++++++-- src/harness/harness.c | 4 ++-- src/harness/include/harness/config.h | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index e32449db..48b370dd 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1108,6 +1108,7 @@ void GetNetPos(tCar_spec* pCar) { if (pCar->driver > eDriver_non_car) { pCar->curvature = pCar->message.curvature * pCar->maxcurve / 32767.0f; + for (j = 0; j < COUNT_OF(pCar->oldd); j++) { pCar->oldd[j] = (pCar->message.d[j] * pCar->susp_height[j >> 1]) / 255.0f; } @@ -1196,9 +1197,11 @@ void ApplyPhysicsToCars(tU32 last_frame_time, tU32 pTime_difference) { for (i = 0; i < gNum_active_cars; i++) { car = gActive_car_list[i]; car->dt = -1.f; - if (car->message.type == NETMSGID_MECHANICS && car->message.time >= gLast_mechanics_time && gLast_mechanics_time + harness_game_config.physics_step_time >= car->message.time) { - car->dt = (double)(gLast_mechanics_time + harness_game_config.physics_step_time - car->message.time) / 1000.0; - if (gDt - 0.0001f <= car->dt) { + if (car->message.type == NETMSGID_MECHANICS && car->message.time >= gLast_mechanics_time && car->message.time <= gLast_mechanics_time + harness_game_config.physics_step_time) { + // time between car message and next mechanics + car->dt = (gLast_mechanics_time + harness_game_config.physics_step_time - car->message.time) / 1000.0f; + // if the time between car message and next mechanics is about equal to timestep + if (car->dt >= gDt - 0.0001f) { GetNetPos(car); } else if (gNet_mode == eNet_mode_host) { car->dt = -1.f; diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 823b2e1b..612ff808 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -140,7 +140,7 @@ void SendCarData(tU32 pNext_frame_time) { BrVector3Copy(&contents->data.mech.omega, &car->omega); BrVector3Copy(&contents->data.mech.v, &car->v); - contents->data.mech.curvature = car->curvature / car->maxcurve * 32767.0f; + contents->data.mech.curvature = (car->curvature / car->maxcurve * 32767.0f); contents->data.mech.keys = car->keys; contents->data.mech.keys.joystick_acc = (tU8)(car->joystick.acc >> 9); contents->data.mech.keys.joystick_dec = (tU8)(car->joystick.dec >> 9); @@ -173,7 +173,14 @@ void SendCarData(tU32 pNext_frame_time) { void ReceivedRecover(tNet_contents* pContents) { int i; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + if (gNet_players[gThis_net_player_index].ID != pContents->data.player_list.number_of_players) { + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pContents->data.player_list.number_of_players) { + gNet_players[i].car->time_to_recover = pContents->data.mech.time; + } + } + } } // IDA: void __usercall CopyMechanics(tCar_spec *pCar@, tNet_contents *pContents@) diff --git a/src/harness/harness.c b/src/harness/harness.c index ef82c074..0113f4a9 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -213,8 +213,8 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) { handled = 1; } else if (strstr(argv[i], "--physics-step-time=") != NULL) { char* s = strstr(argv[i], "="); - harness_game_config.physics_step_time = atof(s + 1); - LOG_INFO("Physics step time set to %f", harness_game_config.physics_step_time); + harness_game_config.physics_step_time = atoi(s + 1); + LOG_INFO("Physics step time set to %d", harness_game_config.physics_step_time); handled = 1; } else if (strstr(argv[i], "--fps=") != NULL) { char* s = strstr(argv[i], "="); diff --git a/src/harness/include/harness/config.h b/src/harness/include/harness/config.h index 38bdeb19..fc0dc152 100644 --- a/src/harness/include/harness/config.h +++ b/src/harness/include/harness/config.h @@ -34,7 +34,7 @@ typedef struct tHarness_game_info { typedef struct tHarness_game_config { int enable_cd_check; - float physics_step_time; + int physics_step_time; float fps; int freeze_timer; unsigned demo_timeout; From c85a991f4b00f169ede765251858443561f91b16 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Sun, 30 Jul 2023 16:44:59 +1200 Subject: [PATCH 28/40] wasted, recover, kick player out --- src/DETHRACE/common/netgame.c | 71 ++++++++++++++++++++++++++- src/DETHRACE/common/network.c | 90 +++++++++++++++++++++++++++++++++-- src/DETHRACE/common/spark.c | 10 ++-- 3 files changed, 161 insertions(+), 10 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 612ff808..9a9cbb25 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -18,6 +18,7 @@ #include "pd/sys.h" #include "pedestrn.h" #include "powerup.h" +#include "pratcam.h" #include "racestrt.h" #include "spark.h" #include "structur.h" @@ -1400,7 +1401,72 @@ void ReceivedGameplay(tNet_contents* pContents, tNet_message* pMessage, tU32 pRe char* gPalette_copy; static int pause_semaphore; LOG_TRACE("(%p, %p, %d)", pContents, pMessage, pReceive_time); - NOT_IMPLEMENTED(); + + switch (pContents->data.gameplay.mess) { + case eNet_gameplay_host_paused: + if (!pause_semaphore) { + gPixel_buffer_size = gBack_screen->row_bytes * gBack_screen->height; + gPixels_copy = BrMemAllocate(gPixel_buffer_size, kMem_quit_vfy_pixels); + gPalette_copy = BrMemAllocate(1024, kMem_quit_vfy_pal); + memcpy(gPixels_copy, gBack_screen->pixels, gPixel_buffer_size); + memcpy(gPalette_copy, gCurrent_palette_pixels, 1024); + pause_semaphore = 1; + NetFullScreenMessage(228, 1); + must_revert_reentrancy = PermitNetServiceReentrancy(); + do { + NetService(0); + if (CheckQuit()) { + NetFullScreenMessage(228, 1); + } + } while (gWaiting_for_unpause + && gProgram_state.prog_status != eProg_idling + && (!gRace_finished || gRace_over_reason != eRace_over_abandoned)); + if (must_revert_reentrancy) { + HaltNetServiceReentrancy(); + } + gWaiting_for_unpause = 1; + FadePaletteDown(); + memcpy(gBack_screen->pixels, gPixels_copy, gPixel_buffer_size); + memcpy(gCurrent_palette_pixels, gPalette_copy, 1024); + BrMemFree(gPixels_copy); + BrMemFree(gPalette_copy); + PDScreenBufferSwap(0); + FadePaletteUp(); + pause_semaphore = 0; + } + break; + case eNet_gameplay_earn_credits: + EarnCredits(pContents->data.gameplay.param_1); + break; + case eNet_gameplay_host_unpaused: + gWaiting_for_unpause = 0; + break; + case eNet_gameplay_suicide: + KnackerThisCar(NetCarFromPlayerID(pMessage->sender)); + break; + case eNet_gameplay_go_for_it: + gWait_for_it = 0; + break; + default: + if (gCurrent_net_game->type == eNet_game_type_checkpoint || gCurrent_net_game->type == eNet_game_type_sudden_death || gCurrent_net_game->type == eNet_game_type_tag) { + switch (pContents->data.gameplay.mess) { + case eNet_gameplay_checkpoint: + Checkpoint(pContents->data.gameplay.param_1, 1); + break; + case eNet_gameplay_wrong_checkpoint: + WrongCheckpoint(pContents->data.gameplay.param_1); + break; + case eNet_gameplay_suddenly_death: + DoFancyHeadup(17); + ChangeAmbientPratcam(36); + gRace_finished = 1; + break; + default: + break; + } + } + break; + } } // IDA: void __usercall SendGameplay(tPlayer_ID pPlayer@, tNet_gameplay_mess pMess@, int pParam_1@, int pParam_2@, int pParam_3, int pParam_4) @@ -1502,5 +1568,6 @@ void GetExpandedMatrix(br_matrix34* m1, tReduced_matrix* m2) { // IDA: void __usercall NetEarnCredits(tNet_game_player_info *pPlayer@, tS32 pCredits@) void NetEarnCredits(tNet_game_player_info* pPlayer, tS32 pCredits) { LOG_TRACE("(%p, %d)", pPlayer, pCredits); - NOT_IMPLEMENTED(); + + // empty function } diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 00392ad8..d5d06ddf 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -19,6 +19,7 @@ #include "pedestrn.h" #include "piping.h" #include "powerup.h" +#include "pratcam.h" #include "replay.h" #include "spark.h" #include "structur.h" @@ -160,7 +161,8 @@ int PermitNetServiceReentrancy(void) { // IDA: void __cdecl HaltNetServiceReentrancy() void HaltNetServiceReentrancy(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gIn_net_service = 1; } // IDA: void __usercall NetSendHeadupToAllPlayers(char *pMessage@) @@ -1169,7 +1171,32 @@ void KickPlayerOut(tPlayer_ID pID) { int new_player_count; tNet_game_player_info* new_players; LOG_TRACE("(%d)", pID); - NOT_IMPLEMENTED(); + + new_player_count = gNumber_of_net_players; + new_players = (tNet_game_player_info*)BrMemAllocate(sizeof(tNet_game_player_info) * gNumber_of_net_players, kMem_player_list_leave); + memcpy(new_players, gNet_players, sizeof(tNet_game_player_info) * new_player_count); + for (i = 0; i < new_player_count; i++) { + if (new_players[i].ID == pID) { + if (new_players[i].car_index >= 0) { + gCar_details[new_players[i].car_index].ownership = eCar_owner_none; + } + if (new_players[i].next_car_index >= 0 && gCurrent_net_game->options.random_car_choice && (gCurrent_net_game->options.car_choice == eNet_car_all || gCurrent_net_game->options.car_choice == eNet_car_both)) { + gCar_details[new_players[i].next_car_index].ownership = eCar_owner_none; + } +#ifdef DETHRACE_FIX_BUGS + for (j = i; j < new_player_count - 1; j++) { +#else + for (j = i; j < new_player_count; j++) { +#endif + memcpy(&new_players[j], &new_players[j + 1], sizeof(tNet_game_player_info)); + } + new_player_count--; + break; + } + } + NetPlayersChanged(new_player_count, new_players); + BrMemFree(new_players); + SendOutPlayerList(); } // IDA: void __usercall ReceivedLeave(tNet_contents *pContents@, tNet_message *pMessage@) @@ -1536,7 +1563,64 @@ void ReceivedWasted(tNet_contents* pContents) { static tNet_game_player_info* last_culprit; static tNet_game_player_info* last_victim; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + victim = NetPlayerFromID(pContents->data.wasted.victim); + if (victim == NULL) { + return; + } + victim->car->knackered = 1; + if (pContents->data.wasted.victim == gLocal_net_ID) { + if (gCurrent_net_game->type == eNet_game_type_fight_to_death) { + DoFancyHeadup(19); + gRace_finished = 1; + } else { + last_got_wasted_time = PDGetTotalTime(); + if (last_got_wasted_time - last_wasted_em_time > 1000) { + DoFancyHeadup(15); + } else { + DoFancyHeadup(16); + } + } + } + if (pContents->data.wasted.culprit == -1) { + if (victim->last_waste_message == 0) { + victim->last_waste_message = GetTotalTime(); + } + } else if (!victim->wasteage_attributed) { + if (pContents->data.wasted.culprit == -2) { + culprit = NULL; + } else { + culprit = NetPlayerFromID(pContents->data.wasted.culprit); + } + if (culprit != NULL) { + if (gNet_mode == eNet_mode_host && gCurrent_net_game->type == eNet_game_type_car_crusher) { + culprit->score++; + } + if (culprit->score >= gCurrent_net_game->options.race_end_target) { + DeclareWinner(culprit - gNet_players); + } + } + victim->last_waste_message = GetTotalTime(); + victim->wasteage_attributed = 1; + if (culprit != NULL && victim == last_culprit && culprit == last_victim && PDGetTotalTime() - last_wasty_message_time < 1000) { + sprintf(s, "%s %s %s %s", victim->player_name, GetMiscString(126), culprit->player_name, GetMiscString(127)); + } else { + sprintf(s, "%s %s %s", victim->player_name, GetMiscString(171), culprit ? culprit->player_name : GetMiscString(216)); + } + NewTextHeadupSlot2(4, 0, 3000, -4, s, 0); + last_wasty_message_time = PDGetTotalTime(); + last_culprit = culprit; + last_victim = victim; + if (pContents->data.wasted.culprit == gLocal_net_ID) { + PratcamEvent(32); + last_wasted_em_time = PDGetTotalTime(); + if (last_wasted_em_time - last_got_wasted_time > 1000) { + DoFancyHeadup(11); + } else { + DoFancyHeadup(16); + } + } + } } // IDA: void __usercall ReceivedCarDetailsReq(tNet_contents *pContents@, void *pSender_address@) diff --git a/src/DETHRACE/common/spark.c b/src/DETHRACE/common/spark.c index 3680cecd..bd1df951 100644 --- a/src/DETHRACE/common/spark.c +++ b/src/DETHRACE/common/spark.c @@ -2692,14 +2692,14 @@ void MakeCarIt(tCar_spec* pCar) { actor = pCar->car_model_actors[pCar->principal_car_actor].actor; bonny = pCar->car_model_actors[pCar->car_actor_count - 1].actor; - if (((actor->model->flags & BR_MODF_CUSTOM) == 0) || actor->model->custom != DoTrueColModelThing) { + if (((actor->model->flags & BR_MODF_CUSTOM) == 0) || actor->model->custom != DoModelThing) { SetModelShade(actor, shade[shade_num]); - actor->model->user = DoTrueColModelThing; - actor->model->custom = DoTrueColModelThing; + actor->model->user = DoModelThing; + actor->model->custom = DoModelThing; actor->model->flags |= BR_MODF_CUSTOM; if (bonny != actor) { - bonny->model->user = DoTrueColModelThing; - bonny->model->custom = DoTrueColModelThing; + bonny->model->user = DoModelThing; + bonny->model->custom = DoModelThing; bonny->model->flags |= BR_MODF_CUSTOM; SetModelShade(bonny, shade[shade_num]); } From 63a7180da3371141a6f886e0bfdbb05cb5052eb0 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Mon, 7 Aug 2023 06:14:58 +1200 Subject: [PATCH 29/40] NetSendPointCrush --- src/DETHRACE/common/netgame.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 9a9cbb25..185a1c5c 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -1519,7 +1519,10 @@ void NetSendPointCrush(tCar_spec* pCar, tU16 pCrush_point_index, br_vector3* pEn tNet_contents* contents; LOG_TRACE("(%p, %d, %p)", pCar, pCrush_point_index, pEnergy_vector); - STUB_ONCE(); + contents = NetGetBroadcastContents(NETMSGID_CRUSHPOINT, 0); + contents->data.crush.id = NetPlayerFromCar(pCar)->ID; + contents->data.crush.vertex = pCrush_point_index; + BrVector3Copy(&contents->data.crush.energy_vector, pEnergy_vector); } // IDA: void __usercall RecievedCrushPoint(tNet_contents *pContents@) From 2f8b81ac6976c01314b983086c410d07070722a1 Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Mon, 21 Aug 2023 14:14:37 +1200 Subject: [PATCH 30/40] crushpoint, declarewinner --- src/DETHRACE/common/netgame.c | 58 +++++++++++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 2 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index 172bb936..b8264b0c 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -915,7 +915,44 @@ void DeclareWinner(int pWinner_index) { int best_score_index; char s[256]; LOG_TRACE("(%d)", pWinner_index); - NOT_IMPLEMENTED(); + + DoNetScores2(1); + the_message = NetBuildMessage(NETMSGID_RACEOVER, 0); + the_message->contents.data.race_over.reason = eRace_over_network_victory; + NetGuaranteedSendMessageToPlayer(gCurrent_net_game, the_message, gNet_players[pWinner_index].ID, NULL); + gNet_players[pWinner_index].won++; + if (gCurrent_net_game->type == eNet_game_type_sudden_death + || gCurrent_net_game->type == eNet_game_type_tag + || gCurrent_net_game->type == eNet_game_type_fight_to_death) { + gNet_players[pWinner_index].games_score += gGame_scores[5]; + } + sprintf(s, "%s %s", gNet_players[pWinner_index].player_name, GetMiscString(kMiscString_IS_THE_WINNER)); + for (i = 0; i < gNumber_of_net_players; i++) { + if (gCurrent_net_game->type != eNet_game_type_sudden_death && gCurrent_net_game->type != eNet_game_type_tag && gCurrent_net_game->type != eNet_game_type_fight_to_death) { + best_score_index = gNet_players[i].last_score_index; + for (j = 0; j < gNumber_of_net_players; j++) { + if (gNet_players[j].score == gNet_players[i].score && gNet_players[j].last_score_index < best_score_index) { + best_score_index = gNet_players[j].last_score_index; + } + } + gNet_players[i].games_score += gGame_scores[5 - best_score_index]; + } + gNet_players[i].played++; + if (i != pWinner_index) { + the_message = NetBuildMessage(NETMSGID_RACEOVER, 0); + the_message->contents.data.race_over.reason = eRace_over_network_loss; + NetGuaranteedSendMessageToPlayer(gCurrent_net_game, the_message, gNet_players[i].ID, NULL); + NetSendHeadupToPlayer(s, gNet_players[i].ID); + } + } + gReceived_game_scores = 1; + the_message = NetBuildMessage(NETMSGID_GAMESCORES, 0); + for (i = 0; i < gNumber_of_net_players; i++) { + the_message->contents.data.game_scores.scores[i].played = gNet_players[i].played; + the_message->contents.data.game_scores.scores[i].won = gNet_players[i].won; + the_message->contents.data.game_scores.scores[i].score = gNet_players[i].games_score; + } + NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL); } // IDA: void __usercall PlayerIsIt(tNet_game_player_info *pPlayer@) @@ -1542,7 +1579,24 @@ void NetSendPointCrush(tCar_spec* pCar, tU16 pCrush_point_index, br_vector3* pEn void RecievedCrushPoint(tNet_contents* pContents) { tCar_spec* car; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + car = NetCarFromPlayerID(pContents->data.crush.id); + if (car == NULL || gNet_mode == eNet_mode_host || car->active || gArrow_mode) { + return; + } + if (car->car_model_actors[car->principal_car_actor].crush_data.number_of_crush_points == 0) { + return; + } + + CrushModelPoint( + car, + car->principal_car_actor, + car->car_model_actors[car->principal_car_actor].actor->model, + pContents->data.crush.vertex, + &pContents->data.crush.energy_vector, + BrVector3Length(&pContents->data.crush.energy_vector) + 0.06f, + &car->car_model_actors[car->principal_car_actor].crush_data); + SetModelForUpdate(car->car_model_actors[car->principal_car_actor].actor->model, car, 0); } // IDA: void __usercall GetReducedMatrix(tReduced_matrix *m1@, br_matrix34 *m2@) From 9c43627adf6c7cb4bb4f3afe51b5765565a70e3e Mon Sep 17 00:00:00 2001 From: Dethrace Labs <78985374+dethrace-labs@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:41:47 +1200 Subject: [PATCH 31/40] network race summary wip --- src/DETHRACE/common/network.c | 18 ++++++- src/DETHRACE/common/racesumm.c | 86 ++++++++++++++++++++++++++++++---- src/DETHRACE/common/racesumm.h | 2 +- 3 files changed, 94 insertions(+), 12 deletions(-) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 481cdf45..965b291e 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -474,7 +474,15 @@ void DisposeCarN(int pIndex) { // IDA: void __usercall PlayerHasLeft(int pIndex@) void PlayerHasLeft(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + if (gCurrent_net_game->options.random_car_choice && (gCurrent_net_game->options.car_choice == eNet_car_all || gCurrent_net_game->options.car_choice == eNet_car_both)) { + if (gNet_players[pIndex].car_index >= 0) { + gCar_details[gNet_players[pIndex].car_index].ownership = eCar_owner_none; + } + if (gNet_players[pIndex].next_car_index >= 0) { + gCar_details[gNet_players[pIndex].next_car_index].ownership = eCar_owner_none; + } + } } // IDA: void __usercall NetPlayersChanged(int pNew_count@, tNet_game_player_info *pNew_players@) @@ -1662,7 +1670,13 @@ void ReceivedCarDetails(tNet_contents* pContents) { void ReceivedGameScores(tNet_contents* pContents) { int i; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + gReceived_game_scores = 1; + for (i = 0; i < gNumber_of_net_players; i++) { + gNet_players[i].played = pContents->data.game_scores.scores[i].played; + gNet_players[i].won = pContents->data.game_scores.scores[i].won; + gNet_players[i].games_score = pContents->data.game_scores.scores[i].score; + } } // IDA: void __usercall ReceivedMessage(tNet_message *pMessage@, void *pSender_address@, tU32 pReceive_time@) diff --git a/src/DETHRACE/common/racesumm.c b/src/DETHRACE/common/racesumm.c index 7c31d2e2..44025e4b 100644 --- a/src/DETHRACE/common/racesumm.c +++ b/src/DETHRACE/common/racesumm.c @@ -1168,15 +1168,16 @@ void DrawColumnHeading__racesumm(int pStr_index, int pX) { } // IDA: int __usercall SortScores@(void *pFirst_one@, void *pSecond_one@) -int SortScores(void* pFirst_one, void* pSecond_one) { +int SortScores(const void* pFirst_one, const void* pSecond_one) { LOG_TRACE("(%p, %p)", pFirst_one, pSecond_one); - NOT_IMPLEMENTED(); + + return gNet_players[*(int*)pSecond_one].games_score - gNet_players[*(int*)pFirst_one].games_score; } // IDA: void __cdecl SortGameScores() void SortGameScores(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + qsort(gPlayer_lookup, gNumber_of_net_players, sizeof(gPlayer_lookup[0]), SortScores); } // IDA: void __usercall NetSumDraw(int pCurrent_choice@, int pCurrent_mode@) @@ -1190,16 +1191,83 @@ void NetSumDraw(int pCurrent_choice, int pCurrent_mode) { // IDA: void __cdecl DoNetRaceSummary() void DoNetRaceSummary(void) { - static tFlicette flicker_on[1]; - static tFlicette flicker_off[1]; - static tFlicette push[1]; - static tMouse_area mouse_areas[1]; - static tInterface_spec interface_spec; + static tFlicette flicker_on[1] = { { 321, { 219, 112 }, { 172, 362 } } }; + static tFlicette flicker_off[1] = { { 322, { 219, 112 }, { 172, 362 } } }; + static tFlicette push[1] = { { 323, { 219, 112 }, { 172, 362 } } }; + static tMouse_area mouse_areas[1] = { { { 219, 112 }, { 172, 362 }, { 282, 182 }, { 192, 379 }, 0, 0, 0, NULL } }; + static tInterface_spec interface_spec = { + 0, // initial_imode + 63, // first_opening_flic + 0, // second_opening_flic + -1, // end_flic_go_ahead + -1, // end_flic_escaped + -1, // 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 + { NULL, 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 + { 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 + NULL, // exit_proc + &NetSumDraw, // draw_proc + 10000, // time_out + NULL, // start_proc1 + NULL, // start_proc2 + NULL, // done_proc + 0, // font_needed + { 0, 0 }, // typeable + NULL, // get_original_string + 0, // escape_code + 1, // dont_save_or_load + 1, // number_of_button_flics + flicker_on, // flicker_on_flics + flicker_off, // flicker_off_flics + push, // pushed_flics + 1, // number_of_mouse_areas + mouse_areas, // mouse_areas + 0, // number_of_recopy_areas + NULL // recopy_areas + }; int i; int result; tS32 start_time; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + NetPlayerStatusChanged(ePlayer_status_summary); + start_time = PDGetTotalTime(); + while (!gReceived_game_scores && PDGetTotalTime() - start_time < 20000) { + NetService(0); + } + if (gReceived_game_scores) { + for (i = 0; i < gNumber_of_net_players; i++) { + gPlayer_lookup[i] = i; + } + SortGameScores(); + TurnOnPaletteConversion(); + DoInterfaceScreen(&interface_spec, 0, 0); + NetPlayerStatusChanged(ePlayer_status_loading); + TurnOffPaletteConversion(); + FadePaletteDown(); + } } // IDA: tSO_result __usercall DoEndRaceSummary@(int *pFirst_summary_done@, tRace_result pRace_result@) diff --git a/src/DETHRACE/common/racesumm.h b/src/DETHRACE/common/racesumm.h index 2dc020b6..09918573 100644 --- a/src/DETHRACE/common/racesumm.h +++ b/src/DETHRACE/common/racesumm.h @@ -106,7 +106,7 @@ void DrawAnItem__racesumm(int pX, int pY_index, int pFont_index, char* pText); // Suffix added to avoid duplicate symbol void DrawColumnHeading__racesumm(int pStr_index, int pX); -int SortScores(void* pFirst_one, void* pSecond_one); +int SortScores(const void* pFirst_one, const void* pSecond_one); void SortGameScores(void); From c6010a2466995737bb3de7fc6b400b33b5140cf7 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 10 Jun 2024 04:42:19 +0200 Subject: [PATCH 32/40] Start and finish a game of tag/fox --- src/BRSRC13/include/brender/br_defs.h | 1 + src/BRSRC13/include/brender/br_inline_funcs.h | 15 ++ src/BRSRC13/include/brender/brender.h | 4 + src/DETHRACE/common/car.c | 214 +++++++++++++++++- src/DETHRACE/common/controls.c | 1 - src/DETHRACE/common/depth.c | 20 +- src/DETHRACE/common/displays.c | 8 +- src/DETHRACE/common/finteray.c | 98 +++++++- src/DETHRACE/common/loading.c | 29 ++- src/DETHRACE/common/netgame.c | 75 +++++- src/DETHRACE/common/network.c | 62 +++-- src/DETHRACE/common/newgame.c | 6 +- src/DETHRACE/common/options.c | 2 +- src/DETHRACE/common/racesumm.c | 54 ++++- src/DETHRACE/common/spark.c | 83 ++++++- src/DETHRACE/common/structur.c | 14 +- src/DETHRACE/common/utility.c | 15 +- 17 files changed, 637 insertions(+), 64 deletions(-) diff --git a/src/BRSRC13/include/brender/br_defs.h b/src/BRSRC13/include/brender/br_defs.h index 5193c44f..1dd15e9b 100644 --- a/src/BRSRC13/include/brender/br_defs.h +++ b/src/BRSRC13/include/brender/br_defs.h @@ -8,6 +8,7 @@ #define PI 3.14159265358979323846 #define TAU 6.283185307179586 +#define BR_SQR2(a, b) ((a) * (a) + (b) * (b)) #define BR_MAC3(a, b, c, d, e, f) ((a) * (b) + (c) * (d) + (e) * (f)) #define BR_SQR3(a, b, c) ((a) * (a) + (b) * (b) + (c) * (c)) diff --git a/src/BRSRC13/include/brender/br_inline_funcs.h b/src/BRSRC13/include/brender/br_inline_funcs.h index dd7644c7..1a2346f9 100644 --- a/src/BRSRC13/include/brender/br_inline_funcs.h +++ b/src/BRSRC13/include/brender/br_inline_funcs.h @@ -3,12 +3,20 @@ #include "br_defs.h" +#define BrVector2LengthSquared(v1) BR_SQR2((v1)->v[0], (v1)->v[1]) + #define BrVector2Set(v1, s1, s2) \ do { \ (v1)->v[0] = (s1); \ (v1)->v[1] = (s2); \ } while (0) +#define BrVector2Sub(v1, v2, v3) \ + do { \ + (v1)->v[0] = (v2)->v[0] - (v3)->v[0]; \ + (v1)->v[1] = (v2)->v[1] - (v3)->v[1]; \ + } while (0) + #define BrVector3Length(v1) BR_LENGTH3((v1)->v[0], (v1)->v[1], (v1)->v[2]) #define BrVector3LengthSquared(v1) BR_SQR3((v1)->v[0], (v1)->v[1], (v1)->v[2]) #define BrVector3Dot(v1, v2) BR_MAC3((v1)->v[0], (v2)->v[0], (v1)->v[1], (v2)->v[1], (v1)->v[2], (v2)->v[2]) @@ -62,6 +70,13 @@ (v1)->v[2] = (v2)->v[2] * (v3)->v[2]; \ } while (0) +#define BrVector3Div(v1, v2, v3) \ + do { \ + (v1)->v[0] = (v2)->v[0] / (v3)->v[0]; \ + (v1)->v[1] = (v2)->v[1] / (v3)->v[1]; \ + (v1)->v[2] = (v2)->v[2] / (v3)->v[2]; \ + } while (0) + #define BrVector3Accumulate(v1, v2) \ do { \ (v1)->v[0] += (v2)->v[0]; \ diff --git a/src/BRSRC13/include/brender/brender.h b/src/BRSRC13/include/brender/brender.h index 6c7346ac..739336a8 100644 --- a/src/BRSRC13/include/brender/brender.h +++ b/src/BRSRC13/include/brender/brender.h @@ -149,6 +149,10 @@ void BrPixelmapText(br_pixelmap* dst, br_int_32 x, br_int_32 y, br_uint_32 colou void BrPixelmapTextF(br_pixelmap* dst, br_int_32 x, br_int_32 y, br_uint_32 colour, br_font* font, char* fmt, ...); br_uint_16 BrPixelmapTextWidth(br_pixelmap* dst, br_font* font, char* text); +// BrEuler +br_matrix34* BrEulerToMatrix34(br_matrix34* mat, br_euler* euler); +br_euler* BrMatrix34ToEuler(br_euler* euler, br_matrix34* mat); + // BrRes void* BrResAllocate(void* vparent, br_size_t size, br_uint_8 res_class); br_resource_class* BrResClassAdd(br_resource_class* rclass); diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index 03ba10d0..851ebb6b 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1510,13 +1510,81 @@ void ToggleControls(void) { // IDA: void __usercall ControlCar2(tCar_spec *c@, br_scalar dt) void ControlCar2(tCar_spec* c, br_scalar dt) { LOG_TRACE("(%p, %f)", c, dt); - NOT_IMPLEMENTED(); + + c->acc_force = 0.f; + if (c->keys.acc) { + c->acc_force = 7.f * c->M; + } + if (c->keys.dec) { + c->acc_force = -7.f * c->M; + } + if (c->keys.left) { + if (c->turn_speed < 0.f) { + c->turn_speed = 0.f; + } + if (c->curvature >= 0.f) { + c->turn_speed += dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f); + } else { + c->turn_speed += 0.01f * dt / 0.04f / 2.f; + } + } + if (c->keys.right) { + if (c->turn_speed > 0.f) { + c->turn_speed = 0.f; + } + if (c->curvature <= 0.f) { + c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f); + } else { + c->turn_speed -= 0.01f * dt / 0.04f / 2.f; + } + } + if (c->keys.left && c->keys.right) { + c->turn_speed = 0.f; + } + c->curvature += c->turn_speed; + if (c->curvature > c->maxcurve) { + c->curvature = c->maxcurve; + } + if (c->curvature < -c->maxcurve) { + c->curvature = -c->maxcurve; + } } // IDA: void __usercall ControlCar3(tCar_spec *c@, br_scalar dt) void ControlCar3(tCar_spec* c, br_scalar dt) { LOG_TRACE("(%p, %f)", c, dt); - NOT_IMPLEMENTED(); + + if (c->keys.left) { + if (c->turn_speed < 0.f) { + c->turn_speed = 0.f; + } + if (c->curvature >= 0.f && c->omega.v[1] >= 0.f) { + c->turn_speed += dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.75f; + } else { + c->turn_speed += 0.01f * dt / 0.04f / 2.f * 3.f; + } + } + + if (c->keys.right) { + if (c->turn_speed > 0.f) { + c->turn_speed = 0.f; + } + if (c->curvature >= 0.f && c->omega.v[1] <= 0.f) { + c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.75f; + } else { + c->turn_speed -= 0.01f * dt / 0.04f / 2.f * 3.f; + } + } + if (c->keys.left && c->keys.right) { + c->turn_speed = 0.f; + } + c->curvature += c->turn_speed; + if (c->curvature > c->maxcurve) { + c->curvature = c->maxcurve; + } + if (c->curvature < -c->maxcurve) { + c->curvature = -c->maxcurve; + } } // IDA: void __usercall ControlCar4(tCar_spec *c@, br_scalar dt) @@ -1576,20 +1644,101 @@ void ControlCar4(tCar_spec* c, br_scalar dt) { // IDA: void __usercall ControlCar5(tCar_spec *c@, br_scalar dt) void ControlCar5(tCar_spec* c, br_scalar dt) { LOG_TRACE("(%p, %f)", c, dt); - NOT_IMPLEMENTED(); + + c->acc_force = 0.f; + if (c->keys.acc) { + c->acc_force = 7.f * c->M; + } + if (c->keys.dec) { + c->acc_force = - 7.f * c->M; + } + if (c->keys.left) { + if (c->turn_speed < 0.f) { + c->turn_speed = 0.f; + } + if (c->curvature >= 0) { + c->turn_speed += dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.5f; + } else { + c->turn_speed += 0.01f * dt / 0.04f / 2.f * .5f; + } + } + if (c->keys.right) { + if (c->turn_speed > 0.f) { + c->turn_speed = 0.f; + } + if (c->curvature <= 0) { + c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.5f; + } else { + c->turn_speed -= 0.01f * dt / 0.04f / 2.f * .5f; + } + } + if (!c->keys.left && !c->keys.right) { + c->turn_speed = 0.f; + if (c->curvature < 0.f && !c->keys.holdw) { + c->curvature += dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)) / 2.f * 4.f; + if (c->curvature > 0.f) { + c->curvature = 0.f; + } + } else if (c->curvature > 0.f && !c->keys.holdw) { + c->curvature -= dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)) / 2.f * 4.f; + if (c->curvature < 0.f) { + c->curvature = 0.f; + } + } + } + c->curvature += c->turn_speed; + if (c->curvature > c->maxcurve) { + c->curvature = c->maxcurve; + } + if (c->curvature < -c->maxcurve) { + c->curvature = -c->maxcurve; + } + c->keys.left = 1; } // IDA: void __usercall ControlCar1(tCar_spec *c@, br_scalar dt) void ControlCar1(tCar_spec* c, br_scalar dt) { LOG_TRACE("(%p, %f)", c, dt); - NOT_IMPLEMENTED(); + + c->acc_force = 0.f; + if (c->keys.acc) { + c->acc_force = 7.f * c->M; + } + if (c->keys.dec) { + c->acc_force = -7.f * c->M; + } + if (c->keys.left) { + if (c->curvature >= 0.f) { + c->curvature += dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)); + } else { + c->curvature += dt / 0.04f * 0.05f; + } + } + if (c->keys.right) { + if (c->curvature <= 0.f) { + c->curvature -= dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)); + } else { + c->curvature -= dt / 0.04f * 0.05f; + } + } + if (c->curvature > c->maxcurve) { + c->curvature = c->maxcurve; + } + if (c->curvature < -c->maxcurve) { + c->curvature = -c->maxcurve; + } } // IDA: void __usercall setrotate(br_vector3 *wdt@, br_matrix34 *m@) void setrotate(br_vector3* wdt, br_matrix34* m) { br_euler e; LOG_TRACE("(%p, %p)", wdt, m); - NOT_IMPLEMENTED(); + + e.a = BR_ANGLE_RAD(wdt->v[0]); + e.b = BR_ANGLE_RAD(wdt->v[1]); + e.c = BR_ANGLE_RAD(wdt->v[2]); + e.order = 0; + BrEulerToMatrix34(m, &e); } // IDA: void __usercall RotateCar2(tCollision_info *c@, br_scalar dt) @@ -1600,7 +1749,18 @@ void RotateCar2(tCollision_info* c, br_scalar dt) { br_vector3 L2; br_matrix34 m; LOG_TRACE("(%p, %f)", c, dt); - NOT_IMPLEMENTED(); + + BrVector3Scale(&wdt, &c->omega, dt); + BrVector3Negate(&wdt2, &wdt); + BrVector3Mul(&L, &c->I, &c->omega); + setrotate(&wdt2, &m); + BrMatrix34ApplyV(&L2, &L, &m); + setrotate(&wdt, &m); + BrMatrix34PreTranslate(&m, -c->cmpos.v[0], -c->cmpos.v[1], -c->cmpos.v[2]); + BrMatrix34PostTranslate(&m, c->cmpos.v[0], c->cmpos.v[1], c->cmpos.v[2]); + BrMatrix34Pre(&c->car_master_actor->t.t.mat, &m); + BrVector3Copy(&c->oldomega, &c->omega); + BrVector3Div(&c->omega, &L2, &c->I); } // IDA: void __usercall RotateCarSecondOrder(tCollision_info *c@, br_scalar dt) @@ -4395,7 +4555,20 @@ tCar_spec* GetRaceLeader(void) { int score; tCar_spec* car; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if ((gCurrent_net_game->type == eNet_game_type_foxy || gCurrent_net_game->type == eNet_game_type_tag) && gIt_or_fox > -1 && gIt_or_fox > gNumber_of_net_players) { + car = gNet_players[gIt_or_fox].car; + } else { + car = gNet_players[0].car; + score = gNet_players[0].last_score_index; + for (i = 1; i < gNumber_of_net_players; i++) { + if (score > gNet_players[i].last_score_index) { + score = gNet_players[i].last_score_index; + car = gNet_players[i].car; + } + } + } + return car; } // IDA: void __cdecl AmIGettingBoredWatchingCameraSpin() @@ -5472,7 +5645,13 @@ int CollideCamera2(br_vector3* car_pos, br_vector3* cam_pos, br_vector3* old_cam int BoundsTest(br_bounds* bnds, br_vector3* p) { int j; LOG_TRACE("(%p, %p)", bnds, p); - NOT_IMPLEMENTED(); + + for (j = 0; j < 3; j++) { + if (p->v[j] > bnds->max.v[j] || p->v[j] < bnds->min.v[j]) { + return 0; + } + } + return 1; } // IDA: int __usercall CollideCameraWithOtherCars@(br_vector3 *car_pos@, br_vector3 *cam_pos@) @@ -5489,7 +5668,24 @@ int CollideCameraWithOtherCars(br_vector3* car_pos, br_vector3* cam_pos) { br_bounds bnds; LOG_TRACE("(%p, %p)", car_pos, cam_pos); - STUB_ONCE(); + for (i = 0; i < gNum_cars_and_non_cars; i++) { + if (BoundsTest(&gActive_car_list[i]->bounds_world_space, cam_pos)) { + c = gActive_car_list[i]; + BrVector3Sub(&tv, cam_pos, &c->car_master_actor->t.t.translate.t); + BrMatrix34TApplyV(&p, &tv, &c->car_master_actor->t.t.mat); + if (BoundsTest(&c->bounds[0], &p)) { + BrVector3Sub(&tv, cam_pos, car_pos); + BrMatrix34TApplyV(&dir, &tv, &c->car_master_actor->t.t.mat); + BrVector3Add(&pos_car_space, &p, &dir); + BrVector3SetFloat(&tv, 0.03f, 0.03f, 0.03f); + BrVector3Sub(&bnds.min, &c->bounds[0].min, &tv); + BrVector3Add(&bnds.max, &c->bounds[0].min, &tv); + plane = LineBoxColl(&pos_car_space, &p, &bnds, &tv); + BrMatrix34ApplyP(cam_pos, &tv, &c->car_master_actor->t.t.mat); + return 1; + } + } + } return 0; } diff --git a/src/DETHRACE/common/controls.c b/src/DETHRACE/common/controls.c index 75e5dce0..3a14e138 100644 --- a/src/DETHRACE/common/controls.c +++ b/src/DETHRACE/common/controls.c @@ -1105,7 +1105,6 @@ void ConcussMe(void) { // IDA: void __cdecl CheckHelp() void CheckHelp(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); } // IDA: void __cdecl CheckLoadSave() diff --git a/src/DETHRACE/common/depth.c b/src/DETHRACE/common/depth.c index c52acfc5..a2d9c4b9 100644 --- a/src/DETHRACE/common/depth.c +++ b/src/DETHRACE/common/depth.c @@ -924,7 +924,15 @@ void ToggleSkyQuietly(void) { // IDA: void __cdecl ToggleSky() void ToggleSky(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + SetSkyTextureOn(!GetSkyTextureOn()); + if (gProgram_state.current_depth_effect.sky_texture != NULL) { + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_SkyTextureOn)); + } else if (gSwap_sky_texture != NULL) { + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_SkyTextureOff)); + } else { + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ThereIsNoSkyTextureForThisRace)); + } } // IDA: int __cdecl GetDepthCueingOn() @@ -968,7 +976,15 @@ void ToggleDepthCueingQuietly(void) { // IDA: void __cdecl ToggleDepthCueing() void ToggleDepthCueing(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + SetDepthCueingOn(!GetDepthCueingOn()); + if (gProgram_state.current_depth_effect.type != eDepth_effect_none) { + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_DepthCueingOn)); + } else if (gSwap_depth_effect_type != eDepth_effect_none) { + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_DepthCueingOff)); + } else { + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(kMiscString_ThereIsNoDepthCueingForThisRace)); + } } // IDA: void __cdecl ChangeDepthEffect() diff --git a/src/DETHRACE/common/displays.c b/src/DETHRACE/common/displays.c index a7d0c52d..6d8df054 100644 --- a/src/DETHRACE/common/displays.c +++ b/src/DETHRACE/common/displays.c @@ -926,7 +926,13 @@ void MoveHeadupTo(int pHeadup_index, int pNew_x, int pNew_y) { int delta_x; tHeadup* the_headup; LOG_TRACE("(%d, %d, %d)", pHeadup_index, pNew_x, pNew_y); - NOT_IMPLEMENTED(); + + if (pHeadup_index >= 0) { + delta_x = gHeadups[pHeadup_index].x - gHeadups[pHeadup_index].original_x; + gHeadups[pHeadup_index].original_x = pNew_x; + gHeadups[pHeadup_index].x = pNew_x + delta_x; + gHeadups[pHeadup_index].y = pNew_y; + } } // IDA: void __usercall ChangeHeadupText(int pHeadup_index@, char *pNew_text@) diff --git a/src/DETHRACE/common/finteray.c b/src/DETHRACE/common/finteray.c index 4229ec47..0c0209d0 100644 --- a/src/DETHRACE/common/finteray.c +++ b/src/DETHRACE/common/finteray.c @@ -714,7 +714,23 @@ int FindFacesInBox2(tBounds* bnds, tFace_ref* face_list, int max_face) { int i; int j; LOG_TRACE("(%p, %p, %d)", bnds, face_list, max_face); - NOT_IMPLEMENTED(); + + a.v[0] = (bnds->original_bounds.min.v[0] + bnds->original_bounds.max.v[0]) * .5f; + a.v[1] = (bnds->original_bounds.min.v[1] + bnds->original_bounds.max.v[1]) * .5f; + a.v[2] = (bnds->original_bounds.min.v[2] + bnds->original_bounds.max.v[2]) * .5f; + BrMatrix34ApplyP(&bnds->box_centre, &a, bnds->mat); + BrVector3Sub(&b, &bnds->original_bounds.max, &bnds->original_bounds.min); + bnds->radius = BrVector3Length(&b) / 2.f; + BrMatrix34ApplyP(&bnds->real_bounds.min, &bnds->original_bounds.min, bnds->mat); + BrVector3Copy(&bnds->real_bounds.max, &bnds->real_bounds.min); + for (i = 0; i < 3; i++) { + BrVector3Scale(&c[i], (br_vector3*)bnds->mat->m[i], b.v[i]); + } + for (i = 0; i < 3; i++) { + bnds->real_bounds.min.v[i] += MIN(0.f, c[0].v[i]) + MIN(0.f, c[1].v[i]) + MIN(0.f, c[2].v[i]); + bnds->real_bounds.max.v[i] += MAX(0.f, c[0].v[i]) + MAX(0.f, c[1].v[i]) + MAX(0.f, c[2].v[i]); + } + return max_face - ActorBoxPick(bnds, gTrack_actor, model_unk1, material_unk1, face_list, max_face, NULL); } // IDA: int __usercall ActorBoxPick@(tBounds *bnds@, br_actor *ap@, br_model *model@, br_material *material@, tFace_ref *face_list, int max_face, br_matrix34 *pMat) @@ -1202,7 +1218,20 @@ int CompVert(int v1, int v2) { br_vector3 tv; br_vector2 tv2; LOG_TRACE("(%d, %d)", v1, v2); - NOT_IMPLEMENTED(); + + if (v1 == v2) { + return 1; + } + vl = gSelected_model->vertices; + BrVector3Sub(&tv, &vl[v1].p, &vl[v2].p); + if (BrVector3LengthSquared(&tv) > 1e-5f) { + return 0; + } + BrVector2Sub(&tv2, &vl[v1].map, &vl[v2].map); + if (BrVector2LengthSquared(&tv2) > 1e-5f) { + return 0; + } + return 1; } // IDA: void __usercall SetFacesGroup(int pFace@) @@ -1234,7 +1263,25 @@ void GetTilingLimits(br_vector2* min, br_vector2* max) { br_vertex* verts; br_face* faces; LOG_TRACE("(%p, %p)", min, max); - NOT_IMPLEMENTED(); + + verts = gSelected_model->vertices; + faces = gSelected_model->faces; + BrVector2Set(min, 32000.f, 32000.f); + BrVector2Set(max, -32000.f, -32000.f); + for (f = 0; f < gSelected_model->nfaces; f++) { + if (faces[f].material == gSub_material) { + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + if (verts[faces[f].vertices[i]].map.v[j] < min->v[j]) { + min->v[j] = verts[faces[f].vertices[i]].map.v[j]; + } + if (verts[faces[f].vertices[i]].map.v[j] > max->v[j]) { + max->v[j] = verts[faces[f].vertices[i]].map.v[j]; + } + } + } + } + } } // IDA: void __usercall Scale(int pD@, int factor@) @@ -1247,43 +1294,74 @@ void Scale(int pD, int factor) { br_vertex* verts; br_face* faces; LOG_TRACE("(%d, %d)", pD, factor); - NOT_IMPLEMENTED(); + + if (gSelected_model == NULL) { + return; + } + if (gSelected_model->nfaces != gNfaces) { + return; + } + verts = gSelected_model->vertices; + faces = gSelected_model->faces; + GetTilingLimits(&min, &max); + d = max.v[pD] - min.v[pD]; + if (d <= 0.f || factor + d <= 0.f) { + return; + } + for (v = 0; v < gSelected_model->nvertices; v++) { + for (f = 0; f < gSelected_model->nfaces; f++) { + if (faces[f].material == gSub_material + && (faces[f].vertices[0] == v || faces[f].vertices[1] == v || faces[f].vertices[2] == v)) { + verts[v].map.v[pD] = (factor + d) / d * verts[v].map.v[pD]; + break; + } + } + } + BrModelUpdate(gSelected_model, BR_MODU_ALL); } // IDA: void __cdecl ScaleUpX() void ScaleUpX(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + Scale(0, 1); } // IDA: void __cdecl ScaleDnX() void ScaleDnX(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + Scale(0, -1); } // IDA: void __cdecl ScaleUpY() void ScaleUpY(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + Scale(1, 1); } // IDA: void __cdecl ScaleDnY() void ScaleDnY(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + Scale(1, -1); } // IDA: void __cdecl SelectFaceForward() void SelectFaceForward(void) { br_vector3 dir; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + BrVector3Scale(&dir, (br_vector3*)&gProgram_state.current_car.car_master_actor->t.t.mat.m[2], -2.f); + SelectFace(&dir); } // IDA: void __cdecl SelectFaceDown() void SelectFaceDown(void) { br_vector3 dir; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + BrVector3Scale(&dir, (br_vector3*)&gProgram_state.current_car.car_master_actor->t.t.look_up.up, -2.f); + SelectFace(&dir); } diff --git a/src/DETHRACE/common/loading.c b/src/DETHRACE/common/loading.c index 6d6d41a8..14a411fa 100644 --- a/src/DETHRACE/common/loading.c +++ b/src/DETHRACE/common/loading.c @@ -1607,7 +1607,14 @@ void ReadShrapnelMaterials(FILE* pF, tCollision_info* pCar_spec) { void CloneCar(tCar_spec** pOutput_car, tCar_spec* pInput_car) { int i; LOG_TRACE("(%p, %p)", pOutput_car, pInput_car); - NOT_IMPLEMENTED(); + + *pOutput_car = BrMemAllocate(sizeof(tCar_spec), kMem_cop_car_spec); + *pOutput_car = pInput_car; + (*pOutput_car)->car_master_actor = CloneActor(pInput_car->car_master_actor); + BrActorAdd(gNon_track_actor, (*pOutput_car)->car_master_actor); + for (i = 0; i < pInput_car->car_actor_count; i++) { + (*pOutput_car)->car_model_actors[i].actor = DRActorFindRecurse((*pOutput_car)->car_master_actor, pInput_car->car_model_actors[i].actor->identifier); + } } // IDA: void __usercall DisposeClonedCar(tCar_spec *pCar@) @@ -2897,7 +2904,11 @@ float GetAFloatPercent(FILE* pF) { char* str; float result; LOG_TRACE("(%p)", pF); - NOT_IMPLEMENTED(); + + GetALineAndDontArgue(pF, s); + str = strtok(s, "\t ,/"); + sscanf(str, "%f", &result); + return result / 100.f; } // IDA: void __usercall GetPairOfFloats(FILE *pF@, float *pF1@, float *pF2@) @@ -2957,7 +2968,16 @@ void GetThreeIntsAndAString(FILE* pF, int* pF1, int* pF2, int* pF3, char* pS) { char s[256]; char* str; LOG_TRACE("(%p, %p, %p, %p, \"%s\")", pF, pF1, pF2, pF3, pS); - NOT_IMPLEMENTED(); + + GetALineAndDontArgue(pF, s); + str = strtok(s, "\t ,/"); + sscanf(str, "%d", pF1); + str = strtok(NULL, "\t ,/"); + sscanf(str, "%d", pF2); + str = strtok(NULL, "\t ,/"); + sscanf(str, "%d", pF3); + str = strtok(NULL, "\t ,/"); + strcpy(pS, str); } // IDA: void __usercall GetFourInts(FILE *pF@, int *pF1@, int *pF2@, int *pF3@, int *pF4) @@ -2986,7 +3006,8 @@ br_scalar GetAScalar(FILE* pF) { // IDA: void __usercall GetPairOfScalars(FILE *pF@, br_scalar *pS1@, br_scalar *pS2@) void GetPairOfScalars(FILE* pF, br_scalar* pS1, br_scalar* pS2) { LOG_TRACE("(%p, %p, %p)", pF, pS1, pS2); - NOT_IMPLEMENTED(); + + GetPairOfFloats(pF, pS1, pS2); } // IDA: void __usercall GetThreeScalars(FILE *pF@, br_scalar *pS1@, br_scalar *pS2@, br_scalar *pS3@) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index b8264b0c..a9d62bd5 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -296,7 +296,38 @@ void ReceivedCopInfo(tNet_contents* pContents) { tCar_spec* c; int i; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + if (gNet_mode != eNet_mode_client) { + return; + } + if (NetCalcSizeDecider(pContents) & 0xffffff00) { + c = GetCarSpec(pContents->data.cop_info.ID >> 8, pContents->data.cop_info.ID & 0xff); + } else { + c = &gProgram_state.current_car; + } + if (c == NULL || c->message.time > pContents->data.cop_info.time) { + return; + } + c->message.time = pContents->data.cop_info.time; + if (c->active) { + c->message.type = NETMSGID_MECHANICS; + c->message.mat = pContents->data.cop_info.mat; + BrVector3Copy(&c->message.v, &pContents->data.cop_info.v); + BrVector3Copy(&c->message.omega, &pContents->data.cop_info.omega); + c->message.curvature = (tS16)pContents->data.cop_info.curvature; + for (i = 0; i < COUNT_OF(c->message.d); i++) { + c->message.d[i] = pContents->data.cop_info.d[i]; + } + for (i = 0; i < COUNT_OF(c->message.damage); i++) { + c->message.damage[i] = pContents->data.cop_info.damage[i]; + } + } else { + GetExpandedMatrix(&c->car_master_actor->t.t.mat, &pContents->data.cop_info.mat); + BrVector3InvScale(&c->car_master_actor->t.t.translate.t, &c->car_master_actor->t.t.translate.t, WORLD_SCALE); + for (i = 0; i < COUNT_OF(c->damage_units); i++) { + c->damage_units[i].damage_level = pContents->data.cop_info.damage[i]; + } + } } // IDA: void __cdecl SendAllNonCarPositions() @@ -326,7 +357,14 @@ void SendAllNonCarPositions(void) { void ReceivedNonCarPosition(tNet_contents* pContents) { br_actor* actor; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + actor = gProgram_state.track_spec.non_car_list[pContents->data.non_car_position.ID]; + if (actor != NULL && gNet_mode != eNet_mode_none) { + BrMatrix34Copy(&actor->t.t.mat, &pContents->data.non_car_position.mat); + if (pContents->data.non_car_position.flags) { + actor->identifier[3] = '!'; + } + } } // IDA: void __usercall ReceivedNonCar(tNet_contents *pContents@) @@ -904,7 +942,12 @@ void EverybodysLost(void) { tNet_message* the_message; int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_net_players; i++) { + gNet_players[i].played += 1; + the_message = NetBuildMessage(NETMSGID_RACEOVER, 0); + the_message->contents.data.race_over.reason = eRace_over_network_loss; + } } // IDA: void __usercall DeclareWinner(int pWinner_index@) @@ -996,7 +1039,16 @@ int FarEnoughAway(tNet_game_player_info* pPlayer_1, tNet_game_player_info* pPlay // IDA: void __usercall CarInContactWithItOrFox(tNet_game_player_info *pPlayer@) void CarInContactWithItOrFox(tNet_game_player_info* pPlayer) { LOG_TRACE("(%p)", pPlayer); - NOT_IMPLEMENTED(); + + if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) { + if (PDGetTotalTime() - gLast_it_change > 500) { + gLast_it_change = PDGetTotalTime(); + if (gIt_or_fox >= 0) { + gLast_lepper = &gNet_players[gIt_or_fox]; + } + PlayerIsIt(pPlayer); + } + } } // IDA: void __usercall SelectRandomItOrFox(int pNot_this_one@) @@ -1461,12 +1513,12 @@ void ReceivedGameplay(tNet_contents* pContents, tNet_message* pMessage, tU32 pRe memcpy(gPixels_copy, gBack_screen->pixels, gPixel_buffer_size); memcpy(gPalette_copy, gCurrent_palette_pixels, 1024); pause_semaphore = 1; - NetFullScreenMessage(228, 1); + NetFullScreenMessage(kMiscString_PLEASE_WAIT_HOST_HAS_PAUSED, 1); must_revert_reentrancy = PermitNetServiceReentrancy(); do { NetService(0); if (CheckQuit()) { - NetFullScreenMessage(228, 1); + NetFullScreenMessage(kMiscString_PLEASE_WAIT_HOST_HAS_PAUSED, 1); } } while (gWaiting_for_unpause && gProgram_state.prog_status != eProg_idling @@ -1551,7 +1603,16 @@ void SendGameplayToAllPlayers(tNet_gameplay_mess pMess, int pParam_1, int pParam void SendGameplayToHost(tNet_gameplay_mess pMess, int pParam_1, int pParam_2, int pParam_3, int pParam_4) { tNet_message* the_message; LOG_TRACE("(%d, %d, %d, %d, %d)", pMess, pParam_1, pParam_2, pParam_3, pParam_4); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_client) { + the_message = NetBuildMessage(NETMSGID_GAMEPLAY, 0); + the_message->contents.data.gameplay.mess = pMess; + the_message->contents.data.gameplay.param_1 = pParam_1; + the_message->contents.data.gameplay.param_2 = pParam_2; + the_message->contents.data.gameplay.param_3 = pParam_3; + the_message->contents.data.gameplay.param_4 = pParam_4; + NetGuaranteedSendMessageToHost(gCurrent_net_game, the_message, NULL); + } } // IDA: void __cdecl InitNetGameplayStuff() diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index ffd434dc..9065e6d4 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -180,7 +180,15 @@ void NetSendHeadupToAllPlayers(char* pMessage) { void NetSendHeadupToEverybody(char* pMessage) { tNet_contents* the_contents; LOG_TRACE("(\"%s\")", pMessage); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none) { + return; + } + if (gProgram_state.racing) { + NewTextHeadupSlot(4, 0, 3000, -4, pMessage); + } + the_contents = NetGetBroadcastContents(NETMSGID_HEADUP, 0); + strcpy(the_contents->data.headup.text, pMessage); } // IDA: void __usercall NetSendHeadupToPlayer(char *pMessage@, tPlayer_ID pPlayer@) @@ -392,7 +400,8 @@ void NetSetPlayerSystemInfo(tNet_game_player_info* pPlayer, void* pSender_addres // IDA: void __usercall NetDisposePlayer(tNet_game_player_info *pPlayer@) void NetDisposePlayer(tNet_game_player_info* pPlayer) { LOG_TRACE("(%p)", pPlayer); - NOT_IMPLEMENTED(); + + PDNetDisposePlayer(pPlayer); } // IDA: void __usercall FillInThisPlayer(tNet_game_details *pGame@, tNet_game_player_info *pPlayer@, int pCar_index@, int pHost@) @@ -634,7 +643,8 @@ tNet_game_details* NetHostGame(tNet_game_type pGame_type, tNet_game_options* pOp // IDA: int __usercall NetInitClient@(tNet_game_details *pDetails@) int NetInitClient(tNet_game_details* pDetails) { LOG_TRACE("(%p)", pDetails); - NOT_IMPLEMENTED(); + + return PDNetInitClient(pDetails); } // IDA: int __usercall NetJoinGameLowLevel@(tNet_game_details *pDetails@, char *pPlayer_name@) @@ -746,7 +756,19 @@ int NetSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, int NetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer) { int i; LOG_TRACE("(%p, %p, %d)", pDetails, pMessage, pPlayer); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none) { + return -1; + } + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pPlayer) { + GetCheckSum(pMessage); + return PDNetSendMessageToAddress(pDetails, pMessage, &gNet_players[i]); + } + } + return -1; } // IDA: int __usercall NetSendMessageToHost@(tNet_game_details *pDetails@, tNet_message *pMessage@) @@ -765,7 +787,8 @@ int NetSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage) { // IDA: int __usercall NetReplyToMessage@(tNet_game_details *pDetails@, tNet_message *pIncoming_message@, tNet_message *pReply_message@) int NetReplyToMessage(tNet_game_details* pDetails, tNet_message* pIncoming_message, tNet_message* pReply_message) { LOG_TRACE("(%p, %p, %p)", pDetails, pIncoming_message, pReply_message); - NOT_IMPLEMENTED(); + + return NetSendMessageToPlayer(pDetails, pReply_message, pIncoming_message->sender); } // IDA: int __usercall NetSendMessageToAllPlayers@(tNet_game_details *pDetails@, tNet_message *pMessage@) @@ -878,7 +901,8 @@ tU32 NetGetMessageSize(tNet_message_type pType, tS32 pSize_decider) { tS32 NetCalcSizeDecider(tNet_contents* pContents) { tS32 the_decider; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + return 0; } // IDA: tNet_message* __usercall NetBuildMessage@(tNet_message_type pType@, tS32 pSize_decider@) @@ -1210,7 +1234,8 @@ void KickPlayerOut(tPlayer_ID pID) { // IDA: void __usercall ReceivedLeave(tNet_contents *pContents@, tNet_message *pMessage@) void ReceivedLeave(tNet_contents* pContents, tNet_message* pMessage) { LOG_TRACE("(%p, %p)", pContents, pMessage); - NOT_IMPLEMENTED(); + + KickPlayerOut(pMessage->sender); } // IDA: void __usercall NetFullScreenMessage(int pStr_index@, int pLeave_it_up_there@) @@ -1289,7 +1314,7 @@ void HostHasBittenTheDust(int pMessage_index) { void ReceivedHosticide(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - HostHasBittenTheDust(73); + HostHasBittenTheDust(kMiscString_GAME_TERMINATED_BY_HOST); } // IDA: void __cdecl ConfirmReceipt() @@ -1482,14 +1507,14 @@ void ReceivedHostReply(tNet_contents* pContents) { if (pContents->data.heres_where_we_at.race_index != gProgram_state.current_race_index) { NetLeaveGame(gCurrent_net_game); - NetFullScreenMessage(128, 0); + NetFullScreenMessage(kMiscString_RACE_CHANGED_DURING_LOADING, 0); gProgram_state.prog_status = eProg_idling; } if (pContents->data.heres_where_we_at.race_has_started) { if (gCurrent_net_game->options.open_game) { gPending_race = pContents->data.heres_where_we_at.pending_race; } else { - NetFullScreenMessage(89, 0); + NetFullScreenMessage(kMiscString_SORRY_YOU_RE_TOO_LATE, 0); gProgram_state.prog_status = eProg_idling; } } @@ -1533,19 +1558,25 @@ void ReceivedTimeSync(tNet_contents* pContents, tNet_message* pMessage, tU32 pRe void ReceivedConfirm(tNet_contents* pContents) { int i; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pContents->data.confirm.player) { + gNet_players[i].awaiting_confirmation = 0; + return; + } + } } // IDA: void __usercall ReceivedDisableCar(tNet_contents *pContents@) void ReceivedDisableCar(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + } // IDA: void __usercall ReceivedEnableCar(tNet_contents *pContents@) void ReceivedEnableCar(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + } // IDA: void __usercall ReceivedScores(tNet_contents *pContents@) @@ -1860,7 +1891,7 @@ void CheckForDisappearees(void) { } } } else if (!gHost_died && gNumber_of_net_players != 0 && gNet_players[0].last_heard_from_him != 0 && the_time - gNet_players[0].last_heard_from_him >= 20000) { - HostHasBittenTheDust(91); + HostHasBittenTheDust(kMiscString_PANIC_HOST_HAS_DISAPPEARED); } } @@ -2088,7 +2119,8 @@ void ResendGuaranteedMessages(void) { // IDA: int __usercall SampleFailNotifier@(tU32 pAge@, tNet_message *pMessage@) int SampleFailNotifier(tU32 pAge, tNet_message* pMessage) { LOG_TRACE("(%d, %p)", pAge, pMessage); - NOT_IMPLEMENTED(); + + return pAge > 9999; } // IDA: void __cdecl NetWaitForGuaranteeReplies() diff --git a/src/DETHRACE/common/newgame.c b/src/DETHRACE/common/newgame.c index 0c681d90..2b8eb028 100644 --- a/src/DETHRACE/common/newgame.c +++ b/src/DETHRACE/common/newgame.c @@ -1574,7 +1574,9 @@ void ReadNetGameChoices(tNet_game_type* pGame_type, tNet_game_options* pGame_opt // IDA: int __usercall ChooseStartRace@(int *pRank@) int ChooseStartRace(int* pRank) { LOG_TRACE("(%p)", pRank); - NOT_IMPLEMENTED(); + + *pRank = 0; + return 1; } // IDA: void __usercall SetUpOtherNetThings(tNet_game_details *pNet_game@) @@ -1760,7 +1762,7 @@ int DoMultiPlayerStart(void) { } if (gAusterity_mode) { - NetFullScreenMessage(192, 0); + NetFullScreenMessage(kMiscString_NOT_ENOUGH_MEMORY, 0); return 0; } if (NetInitialise()) { diff --git a/src/DETHRACE/common/options.c b/src/DETHRACE/common/options.c index fc5711d1..5b840034 100644 --- a/src/DETHRACE/common/options.c +++ b/src/DETHRACE/common/options.c @@ -840,7 +840,7 @@ void CalibrateJoysticks(void) { #ifdef __DOS__ NOT_IMPLEMENTED(); #else - NetFullScreenMessage(229, 0); + NetFullScreenMessage(kMiscString_USE_SYSTEM_CONTROL_PANEL_FOR_JOYSTICKS, 0); #endif } diff --git a/src/DETHRACE/common/racesumm.c b/src/DETHRACE/common/racesumm.c index 44025e4b..f58d62ee 100644 --- a/src/DETHRACE/common/racesumm.c +++ b/src/DETHRACE/common/racesumm.c @@ -1158,13 +1158,26 @@ tSO_result DoEndRaceSummary2(void) { // Suffix added to avoid duplicate symbol void DrawAnItem__racesumm(int pX, int pY_index, int pFont_index, char* pText) { LOG_TRACE("(%d, %d, %d, \"%s\")", pX, pY_index, pFont_index, pText); - NOT_IMPLEMENTED(); + + TransBrPixelmapText(gBack_screen, + pX, + gCurrent_graf_data->net_sum_headings_y + gCurrent_graf_data->net_sum_y_pitch * pY_index, + pFont_index, + gFont_7, + pText); } // IDA: void __usercall DrawColumnHeading(int pStr_index@, int pX@) // Suffix added to avoid duplicate symbol void DrawColumnHeading__racesumm(int pStr_index, int pX) { LOG_TRACE("(%d, %d)", pStr_index, pX); + + TransBrPixelmapText(gBack_screen, + pX, + gCurrent_graf_data->net_sum_headings_y - gCurrent_graf_data->net_sum_y_pitch, + 250, + gFont_7, + GetMiscString(pStr_index)); } // IDA: int __usercall SortScores@(void *pFirst_one@, void *pSecond_one@) @@ -1186,7 +1199,44 @@ void NetSumDraw(int pCurrent_choice, int pCurrent_mode) { char s[256]; tNet_game_player_info* player; LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + DrawColumnHeading__racesumm(kMiscString_PLAYED, gCurrent_graf_data->net_sum_x_3); + DrawColumnHeading__racesumm(kMiscString_WON, gCurrent_graf_data->net_sum_x_4); + DrawColumnHeading__racesumm(kMiscString_SCORE, gCurrent_graf_data->net_sum_x_5); + BrPixelmapLine(gBack_screen, + gCurrent_graf_data->net_sum_x_1, + gCurrent_graf_data->net_sum_headings_y + 1 + gFont_7->glyph_y - gCurrent_graf_data->net_sum_y_pitch, + gBack_screen->width - gCurrent_graf_data->net_sum_x_1, + gCurrent_graf_data->net_sum_headings_y + 1 + gFont_7->glyph_y - gCurrent_graf_data->net_sum_y_pitch, + 252); + for (i = 0; i < gNumber_of_net_players; i++) { + + player = &gNet_players[gPlayer_lookup[i]]; + + strcpy(s, player->player_name); + if (player->host) { + strcat(s, " -"); + strcat(s, GetMiscString(kMiscString_HOST)); + strcat(s, "-"); + } + TurnOffPaletteConversion(); + DRPixelmapRectangleMaskedCopy(gBack_screen, + gCurrent_graf_data->net_sum_x_1, + gCurrent_graf_data->net_sum_headings_y + 1 + i * gCurrent_graf_data->net_sum_y_pitch, + gIcons_pix, + 0, + gCurrent_graf_data->net_head_icon_height * player->car_index, + gIcons_pix->width, + gCurrent_graf_data->net_head_icon_height); + TurnOnPaletteConversion(); + DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_2, i, 83, s); + sprintf(s, "%d", player->played); + DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_3, i, 83, s); + sprintf(s, "%d", player->won); + DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_4, i, 83, s); + sprintf(s, "%d", player->games_score); + DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_5, i, 83, s); + } } // IDA: void __cdecl DoNetRaceSummary() diff --git a/src/DETHRACE/common/spark.c b/src/DETHRACE/common/spark.c index bd1df951..84aab061 100644 --- a/src/DETHRACE/common/spark.c +++ b/src/DETHRACE/common/spark.c @@ -1,7 +1,9 @@ #include "spark.h" #include "brender/brender.h" #include "car.h" +#include "crush.h" #include "depth.h" +#include "displays.h" #include "errors.h" #include "globvars.h" #include "globvrkm.h" @@ -1206,7 +1208,12 @@ void GenerateContinuousSmoke(tCar_spec* pCar, int wheel, tU32 pTime) { // IDA: void __cdecl DustRotate() void DustRotate(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gDust_rotate += 1; + if (gDust_rotate >= gNum_dust_tables) { + gDust_rotate = 0; + } + NewTextHeadupSlot(4, 0, 1000, -4, "Dust colour rotated"); } // IDA: void __usercall RenderSmoke(br_pixelmap *pRender_screen@, br_pixelmap *pDepth_buffer@, br_actor *pCamera@, br_matrix34 *pCamera_to_world@, tU32 pTime) @@ -2160,7 +2167,9 @@ void SetSmokeOn(int pSmoke_on) { // IDA: void __usercall ReallySetSmokeOn(int pSmoke_on@) void ReallySetSmokeOn(int pSmoke_on) { LOG_TRACE("(%d)", pSmoke_on); - NOT_IMPLEMENTED(); + + ResetSmoke(); + ResetSmokeColumns(); } // IDA: void __usercall SetSmoke(int pSmoke_on@) @@ -2647,7 +2656,42 @@ void DoModelThing(br_actor* actor, br_model* pModel, br_material* material, void tU32 t; int val; LOG_TRACE("(%p, %p, %p, %p, %d, %d)", actor, pModel, material, render_data, style, on_screen); - NOT_IMPLEMENTED(); + + GetRaceTime(); + for (group = 0; group < V11MODEL(pModel)->ngroups; group++) { + for (j = 0; j < V11MODEL(pModel)->groups[group].nvertices; j++) { + if (!((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) & 1)) { + if ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) < 0xc9) { + val = ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) + 2 * IRandomBetween(5, 10)) << 24; + V11MODEL(pModel)->groups[group].vertex_colours[j] = BR_COLOUR_RGBA(0, 0, 0, val); + if (pModel->flags & BR_MODF_UPDATEABLE) { + pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = val; + } + } else { + V11MODEL(pModel)->groups[group].vertex_colours[j] = BR_COLOUR_RGBA(0, 0, 0, 0xc9); + if (pModel->flags & BR_MODF_UPDATEABLE) { + pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = val; + } + } + } else if ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) < 20) { + V11MODEL(pModel)->groups[group].vertex_colours[j] = 0; + if (pModel->flags & BR_MODF_UPDATEABLE) { + pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = 0; + } + } else { + val = ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) - 2 * IRandomBetween(5, 10)) << 24; + V11MODEL(pModel)->groups[group].vertex_colours[j] = BR_COLOUR_RGBA(0, 0, 0, val); + if (pModel->flags & BR_MODF_UPDATEABLE) { + pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = val; + } + } + } + } + if ((pModel->flags & BR_MODF_UPDATEABLE) && pModel->user != NULL) { + BrModelUpdate(pModel, BR_MODU_VERTEX_POSITIONS); + } + pModel->user = NULL; + BrZbModelRender(actor, pModel, material, style, BrOnScreenCheck(&pModel->bounds), 0); } // IDA: void __usercall SetModelShade(br_actor *pActor@, br_pixelmap *pShade@) @@ -2680,9 +2724,6 @@ void MakeCarIt(tCar_spec* pCar) { int i; LOG_TRACE("(%p)", pCar); - STUB(); - return; - shade[0] = gIt_shade_table; shade[1] = gFog_shade_table; shade[2] = gShade_list[0]; @@ -2713,5 +2754,33 @@ void StopCarBeingIt(tCar_spec* pCar) { br_actor* actor; br_actor* bonny; LOG_TRACE("(%p)", pCar); - STUB(); + + actor = pCar->car_model_actors[pCar->principal_car_actor].actor; + bonny = pCar->car_model_actors[pCar->car_actor_count - 1].actor; + if (actor->model->custom == DoModelThing) { + actor->model->flags &= BR_MODF_CUSTOM; + SetModelShade(actor, gShade_list[0]); + for (group = 0; group < V11MODEL(actor->model)->ngroups; group++) { + for (i = 0; i < V11MODEL(actor->model)->groups[group].nvertices; i++) { + V11MODEL(actor->model)->groups[group].vertex_colours[i] = 0; + if (actor->model->flags & BR_MODF_UPDATEABLE) { + actor->model->vertices[V11MODEL(actor->model)->groups[group].vertex_user[i]].index = 0; + } + } + } + SetModelForUpdate(actor->model, pCar, 0); + if (bonny != actor) { + bonny->model->flags &= BR_MODF_CUSTOM; + SetModelShade(bonny, gShade_list[0]); + for (group = 0; group < V11MODEL(bonny->model)->ngroups; group++) { + for (i = 0; i < V11MODEL(bonny->model)->groups[group].nvertices; i++) { + V11MODEL(bonny->model)->groups[group].vertex_colours[i] = 0; + if (bonny->model->flags & BR_MODF_UPDATEABLE) { + bonny->model->vertices[V11MODEL(bonny->model)->groups[group].vertex_user[i]].index = 0; + } + } + } + SetModelForUpdate(bonny->model, pCar, 0); + } + } } diff --git a/src/DETHRACE/common/structur.c b/src/DETHRACE/common/structur.c index 5e77402e..65e58d35 100644 --- a/src/DETHRACE/common/structur.c +++ b/src/DETHRACE/common/structur.c @@ -27,6 +27,7 @@ #include "racesumm.h" #include "sound.h" #include "utility.h" +#include "world.h" #include int gLast_wrong_checkpoint; @@ -95,7 +96,7 @@ void RaceCompleted(tRace_over_reason pReason) { case eRace_over_abandoned: if (gNet_mode == eNet_mode_client) { gHost_abandon_game = 1; - NetFullScreenMessage(87, 0); + NetFullScreenMessage(kMiscString_HOST_ABANDONED_RACE, 0); } break; case eRace_over_out_of_time: @@ -451,7 +452,16 @@ void SwapNetCarsLoad(void) { void SwapNetCarsDispose(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + DisableNetService(); + for (i = 0; i < gNumber_of_net_players; i++) { + DisposeCar(gNet_players[i].car, gNet_players[i].car_index); + if (gNet_players[i].car_index >= 0) { + gCar_details[gNet_players[i].car_index].ownership = eCar_owner_none; + } + } + ClearOutStorageSpace(&gOur_car_storage_space); + ClearOutStorageSpace(&gNet_cars_storage_space); } // IDA: void __cdecl DoGame() diff --git a/src/DETHRACE/common/utility.c b/src/DETHRACE/common/utility.c index 2f90b4c1..218bbb4b 100644 --- a/src/DETHRACE/common/utility.c +++ b/src/DETHRACE/common/utility.c @@ -1147,7 +1147,20 @@ void SubsStringJob(char* pStr, ...) { char* sub_pt; va_list ap; LOG_TRACE("(\"%s\")", pStr); - NOT_IMPLEMENTED(); + + va_start(ap, pStr); + for (;;) { + sub_pt = strchr(pStr, '%'); + if (sub_pt == NULL) { + va_end(ap); + return; + } + sub_str = va_arg(ap, char *); + StripCR(sub_str); + strcpy(temp_str, &sub_pt[1]); + strcpy(sub_pt, sub_str); + strcat(pStr, temp_str); + } } // IDA: void __usercall DecodeLine2(char *pS@) From 84beab345cba10ef9983f3e30470f44aa40b9b47 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 10 Jun 2024 19:54:38 +0200 Subject: [PATCH 33/40] network fixes --- src/DETHRACE/common/car.c | 16 ++++++++-------- src/DETHRACE/common/loading.c | 2 +- src/DETHRACE/common/netgame.c | 11 ++++++----- src/DETHRACE/common/network.c | 4 ++-- src/DETHRACE/common/racesumm.c | 2 +- src/DETHRACE/common/spark.c | 16 +++++++++++----- src/DETHRACE/common/structur.c | 1 + 7 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index 851ebb6b..d011f369 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1538,7 +1538,7 @@ void ControlCar2(tCar_spec* c, br_scalar dt) { c->turn_speed -= 0.01f * dt / 0.04f / 2.f; } } - if (c->keys.left && c->keys.right) { + if (!c->keys.left && !c->keys.right) { c->turn_speed = 0.f; } c->curvature += c->turn_speed; @@ -1569,13 +1569,13 @@ void ControlCar3(tCar_spec* c, br_scalar dt) { if (c->turn_speed > 0.f) { c->turn_speed = 0.f; } - if (c->curvature >= 0.f && c->omega.v[1] <= 0.f) { + if (c->curvature <= 0.f && c->omega.v[1] <= 0.f) { c->turn_speed -= dt / 0.04f * (0.05f / (5.f + BrVector3Length(&c->v)) / 2.f) * 0.75f; } else { c->turn_speed -= 0.01f * dt / 0.04f / 2.f * 3.f; } } - if (c->keys.left && c->keys.right) { + if (!c->keys.left && !c->keys.right) { c->turn_speed = 0.f; } c->curvature += c->turn_speed; @@ -1650,7 +1650,7 @@ void ControlCar5(tCar_spec* c, br_scalar dt) { c->acc_force = 7.f * c->M; } if (c->keys.dec) { - c->acc_force = - 7.f * c->M; + c->acc_force = -7.f * c->M; } if (c->keys.left) { if (c->turn_speed < 0.f) { @@ -1711,14 +1711,14 @@ void ControlCar1(tCar_spec* c, br_scalar dt) { if (c->curvature >= 0.f) { c->curvature += dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)); } else { - c->curvature += dt / 0.04f * 0.05f; + c->curvature += 0.01f * dt / 0.04f; } } if (c->keys.right) { if (c->curvature <= 0.f) { c->curvature -= dt / 0.04f * 0.05f / (5.f + BrVector3Length(&c->v)); } else { - c->curvature -= dt / 0.04f * 0.05f; + c->curvature -= 0.01f * dt / 0.04f; } } if (c->curvature > c->maxcurve) { @@ -4556,7 +4556,7 @@ tCar_spec* GetRaceLeader(void) { tCar_spec* car; LOG_TRACE("()"); - if ((gCurrent_net_game->type == eNet_game_type_foxy || gCurrent_net_game->type == eNet_game_type_tag) && gIt_or_fox > -1 && gIt_or_fox > gNumber_of_net_players) { + if ((gCurrent_net_game->type == eNet_game_type_foxy || gCurrent_net_game->type == eNet_game_type_tag) && gIt_or_fox >= 0 && gIt_or_fox < gNumber_of_net_players) { car = gNet_players[gIt_or_fox].car; } else { car = gNet_players[0].car; @@ -5679,7 +5679,7 @@ int CollideCameraWithOtherCars(br_vector3* car_pos, br_vector3* cam_pos) { BrVector3Add(&pos_car_space, &p, &dir); BrVector3SetFloat(&tv, 0.03f, 0.03f, 0.03f); BrVector3Sub(&bnds.min, &c->bounds[0].min, &tv); - BrVector3Add(&bnds.max, &c->bounds[0].min, &tv); + BrVector3Add(&bnds.max, &c->bounds[0].max, &tv); plane = LineBoxColl(&pos_car_space, &p, &bnds, &tv); BrMatrix34ApplyP(cam_pos, &tv, &c->car_master_actor->t.t.mat); return 1; diff --git a/src/DETHRACE/common/loading.c b/src/DETHRACE/common/loading.c index 14a411fa..adf89d42 100644 --- a/src/DETHRACE/common/loading.c +++ b/src/DETHRACE/common/loading.c @@ -1609,7 +1609,7 @@ void CloneCar(tCar_spec** pOutput_car, tCar_spec* pInput_car) { LOG_TRACE("(%p, %p)", pOutput_car, pInput_car); *pOutput_car = BrMemAllocate(sizeof(tCar_spec), kMem_cop_car_spec); - *pOutput_car = pInput_car; + **pOutput_car = *pInput_car; (*pOutput_car)->car_master_actor = CloneActor(pInput_car->car_master_actor); BrActorAdd(gNon_track_actor, (*pOutput_car)->car_master_actor); for (i = 0; i < pInput_car->car_actor_count; i++) { diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index a9d62bd5..dc0f2ded 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -300,7 +300,7 @@ void ReceivedCopInfo(tNet_contents* pContents) { if (gNet_mode != eNet_mode_client) { return; } - if (NetCalcSizeDecider(pContents) & 0xffffff00) { + if (pContents->data.cop_info.ID & 0xffffff00) { c = GetCarSpec(pContents->data.cop_info.ID >> 8, pContents->data.cop_info.ID & 0xff); } else { c = &gProgram_state.current_car; @@ -387,7 +387,7 @@ void ReceivedNonCar(tNet_contents* pContents) { return; } ncar = (tNon_car_spec*)actor->type_data; - if (ncar && (ncar->collision_info.driver != eDriver_non_car || ncar->collision_info.car_ID != pContents->data.non_car.ID)) { + if (ncar != NULL && (ncar->collision_info.driver != eDriver_non_car || ncar->collision_info.car_ID != pContents->data.non_car.ID)) { ncar = NULL; } if ((pContents->data.non_car.flags & 1) != 0) { @@ -395,14 +395,14 @@ void ReceivedNonCar(tNet_contents* pContents) { } else { actor->identifier[3] = 'x'; } - if (!ncar && actor->identifier[1] >= '0' && actor->identifier[1] <= '9') { + if (ncar == NULL && actor->identifier[1] >= '0' && actor->identifier[1] <= '9') { BrVector3Sub(&tv, &gProgram_state.current_car.car_master_actor->t.t.translate.t, &actor->t.t.translate.t); if (BrVector3LengthSquared(&tv) < 900.0f) { DoPullActorFromWorld(actor); ncar = (tNon_car_spec*)actor->type_data; } } - if (ncar) { + if (ncar != NULL) { c = &ncar->collision_info; if ((pContents->data.non_car.flags & 2) != 0) { GetExpandedMatrix(&c->car_master_actor->t.t.mat, &pContents->data.non_car.mat); @@ -422,7 +422,7 @@ void ReceivedNonCar(tNet_contents* pContents) { BrVector3InvScale(&actor->t.t.translate.t, &actor->t.t.translate.t, WORLD_SCALE); XZToColumnXZ(&cx, &cz, actor->t.t.translate.t.v[0], actor->t.t.translate.t.v[2], track_spec); if (track_spec->columns[cz][cx] != actor->parent) { - if (track_spec->columns[cz][cx]) { + if (track_spec->columns[cz][cx] != NULL) { BrActorRemove(actor); BrActorAdd(track_spec->columns[cz][cx], actor); } @@ -947,6 +947,7 @@ void EverybodysLost(void) { gNet_players[i].played += 1; the_message = NetBuildMessage(NETMSGID_RACEOVER, 0); the_message->contents.data.race_over.reason = eRace_over_network_loss; + NetGuaranteedSendMessageToPlayer(gCurrent_net_game, the_message, gNet_players[i].ID, NULL); } } diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 9065e6d4..0defe03c 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -758,7 +758,7 @@ int NetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, LOG_TRACE("(%p, %p, %d)", pDetails, pMessage, pPlayer); if (gNet_mode == eNet_mode_none) { - return -1; + return -3; } pMessage->sender = gLocal_net_ID; pMessage->senders_time_stamp = PDGetTotalTime(); @@ -768,7 +768,7 @@ int NetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, return PDNetSendMessageToAddress(pDetails, pMessage, &gNet_players[i]); } } - return -1; + return -3; } // IDA: int __usercall NetSendMessageToHost@(tNet_game_details *pDetails@, tNet_message *pMessage@) diff --git a/src/DETHRACE/common/racesumm.c b/src/DETHRACE/common/racesumm.c index f58d62ee..6ece16e4 100644 --- a/src/DETHRACE/common/racesumm.c +++ b/src/DETHRACE/common/racesumm.c @@ -1209,8 +1209,8 @@ void NetSumDraw(int pCurrent_choice, int pCurrent_mode) { gBack_screen->width - gCurrent_graf_data->net_sum_x_1, gCurrent_graf_data->net_sum_headings_y + 1 + gFont_7->glyph_y - gCurrent_graf_data->net_sum_y_pitch, 252); - for (i = 0; i < gNumber_of_net_players; i++) { + for (i = 0; i < gNumber_of_net_players; i++) { player = &gNet_players[gPlayer_lookup[i]]; strcpy(s, player->player_name); diff --git a/src/DETHRACE/common/spark.c b/src/DETHRACE/common/spark.c index 84aab061..7da89bbf 100644 --- a/src/DETHRACE/common/spark.c +++ b/src/DETHRACE/common/spark.c @@ -2154,7 +2154,13 @@ void SmudgeCar(tCar_spec* pCar, int fire_point) { void ResetSmokeColumns(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + for (i = 0; i < MAX_SMOKE_COLUMNS; i++) { + if (gColumn_flags & (1 << i)) { + BrActorRemove(gSmoke_column[i].flame_actor); + } + } + gColumn_flags = 0; } // IDA: void __usercall SetSmokeOn(int pSmoke_on@) @@ -2670,7 +2676,7 @@ void DoModelThing(br_actor* actor, br_model* pModel, br_material* material, void } else { V11MODEL(pModel)->groups[group].vertex_colours[j] = BR_COLOUR_RGBA(0, 0, 0, 0xc9); if (pModel->flags & BR_MODF_UPDATEABLE) { - pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = val; + pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = 0xc9; } } } else if ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) < 20) { @@ -2733,7 +2739,7 @@ void MakeCarIt(tCar_spec* pCar) { actor = pCar->car_model_actors[pCar->principal_car_actor].actor; bonny = pCar->car_model_actors[pCar->car_actor_count - 1].actor; - if (((actor->model->flags & BR_MODF_CUSTOM) == 0) || actor->model->custom != DoModelThing) { + if (!(actor->model->flags & BR_MODF_CUSTOM) || actor->model->custom != DoModelThing) { SetModelShade(actor, shade[shade_num]); actor->model->user = DoModelThing; actor->model->custom = DoModelThing; @@ -2758,7 +2764,7 @@ void StopCarBeingIt(tCar_spec* pCar) { actor = pCar->car_model_actors[pCar->principal_car_actor].actor; bonny = pCar->car_model_actors[pCar->car_actor_count - 1].actor; if (actor->model->custom == DoModelThing) { - actor->model->flags &= BR_MODF_CUSTOM; + actor->model->flags &= ~BR_MODF_CUSTOM; SetModelShade(actor, gShade_list[0]); for (group = 0; group < V11MODEL(actor->model)->ngroups; group++) { for (i = 0; i < V11MODEL(actor->model)->groups[group].nvertices; i++) { @@ -2770,7 +2776,7 @@ void StopCarBeingIt(tCar_spec* pCar) { } SetModelForUpdate(actor->model, pCar, 0); if (bonny != actor) { - bonny->model->flags &= BR_MODF_CUSTOM; + bonny->model->flags &= ~BR_MODF_CUSTOM; SetModelShade(bonny, gShade_list[0]); for (group = 0; group < V11MODEL(bonny->model)->ngroups; group++) { for (i = 0; i < V11MODEL(bonny->model)->groups[group].nvertices; i++) { diff --git a/src/DETHRACE/common/structur.c b/src/DETHRACE/common/structur.c index 65e58d35..6a81c59d 100644 --- a/src/DETHRACE/common/structur.c +++ b/src/DETHRACE/common/structur.c @@ -462,6 +462,7 @@ void SwapNetCarsDispose(void) { } ClearOutStorageSpace(&gOur_car_storage_space); ClearOutStorageSpace(&gNet_cars_storage_space); + ReenableNetService(); } // IDA: void __cdecl DoGame() From f512abc7dff53ab452a2ad109482528200767f78 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Mon, 10 Jun 2024 22:33:19 +0200 Subject: [PATCH 34/40] Players can now send love letters to each other --- src/DETHRACE/common/car.c | 42 +++++++++++- src/DETHRACE/common/controls.c | 116 ++++++++++++++++++++++++++++++++- src/DETHRACE/common/crush.c | 24 ++++++- src/DETHRACE/common/depth.c | 6 +- src/DETHRACE/common/graphics.c | 6 +- 5 files changed, 188 insertions(+), 6 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index d011f369..81b511af 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -29,6 +29,7 @@ #include "skidmark.h" #include "sound.h" #include "spark.h" +#include "structur.h" #include "trig.h" #include "utility.h" #include "world.h" @@ -4579,7 +4580,46 @@ void AmIGettingBoredWatchingCameraSpin(void) { char s[256]; LOG_TRACE("()"); - STUB_ONCE(); + if (gNet_mode == eNet_mode_none + || (gCurrent_net_game->type != eNet_game_type_sudden_death + && gCurrent_net_game->type != eNet_game_type_tag + && gCurrent_net_game->type != eNet_game_type_fight_to_death)) { + gOpponent_viewing_mode = 0; + } else if (!gRace_finished) { + time_of_death = 0; + gOpponent_viewing_mode = 0; + } else if (time_of_death == 0) { + time_of_death = GetRaceTime(); + } else { + if (GetRaceTime() >= time_of_death + 10000) { + if (gOpponent_viewing_mode == 0) { + gOpponent_viewing_mode = 1; + gNet_player_to_view_index = -2; + ViewNetPlayer(); + } + if (gNet_player_to_view_index >= gNumber_of_net_players) { + gNet_player_to_view_index = -2; + ViewNetPlayer(); + } + if (gNet_player_to_view_index < 0 && gCar_to_view != GetRaceLeader()) { + gNet_player_to_view_index = -2; + ViewNetPlayer(); + } + if ((GetRaceTime() > headup_timer + 1000 || headup_timer > GetRaceTime()) && gRace_over_reason == eRace_not_over_yet) { + strcpy(s, GetMiscString(kMiscString_WATCHING)); + strcat(s, " "); + if (gNet_player_to_view_index >= 0) { + strcat(s, gNet_players[gNet_player_to_view_index].player_name); + } else if (gCurrent_net_game->type == eNet_game_type_tag) { + strcat(s, GetMiscString(kMiscString_QUOTE_IT_QUOTE)); + } else { + strcat(s, GetMiscString(kMiscString_RACE_LEADER)); + } + headup_timer = GetRaceTime(); + NewTextHeadupSlot(6, 0, 500, -4, s); + } + } + } } // IDA: void __cdecl ViewNetPlayer() diff --git a/src/DETHRACE/common/controls.c b/src/DETHRACE/common/controls.c index 3a14e138..b60493b4 100644 --- a/src/DETHRACE/common/controls.c +++ b/src/DETHRACE/common/controls.c @@ -1282,7 +1282,27 @@ void CheckHornLocal(tCar_spec* pCar) { // IDA: void __usercall CheckHorn3D(tCar_spec *pCar@) void CheckHorn3D(tCar_spec* pCar) { LOG_TRACE("(%p)", pCar); - STUB_ONCE(); + + if (pCar->keys.horn && pCar->horn_sound_tag == 0) { + pCar->horn_sound_tag = DRS3StartSound3D(gEffects_outlet, + 5209, + &pCar->car_master_actor->t.t.translate.t, + &pCar->velocity_bu_per_sec, + 0, + 255, + ((pCar->car_ID & 7) << 12) + 0xc000, + 0x10000); + } else { + if (!pCar->keys.horn && pCar->horn_sound_tag != 0) { + while (S3SoundStillPlaying(pCar->horn_sound_tag)) { + DRS3StopSound(pCar->horn_sound_tag); + DRS3StopOutletSound(gEffects_outlet); + } + if (!S3SoundStillPlaying(pCar->horn_sound_tag)) { + pCar->horn_sound_tag = 0; + } + } + } } // IDA: void __cdecl CheckHorns() @@ -2479,7 +2499,99 @@ void EnterUserMessage(void) { int the_key; int abuse_num; LOG_TRACE("()"); - STUB_ONCE(); + + if (!gEntering_message) { + return; + } + if (gNet_mode == eNet_mode_none) { + return; + } + if (!gCurrent_net_game->options.enable_text_messages) { + return; + } + the_key = PDAnyKeyDown(); + if (gEntering_message == 1) { + if (the_key != -1) { + return; + } + gEntering_message = 2; + } + if (about_to_die) { + if (the_key != -1) { + return; + } + gEntering_message = 0; + about_to_die = 0; + return; + } + if (the_key == last_key) { + if (next_time < PDGetTotalTime()) { + next_time += 100; + } else { + the_key = -1; + } + } else { + last_key = the_key; + next_time = PDGetTotalTime() + 500; + } + switch (the_key) { + case -1: + case KEY_SHIFT_ANY: + break; + case KEY_CTRL_ANY: + case KEY_CTRL_ANY_2: + case KEY_TAB: + case KEY_ESCAPE: + about_to_die = 1; + break; + case KEY_BACKSPACE: + case KEY_DELETE: + case KEY_LEFT: + len = strlen(&gString[20]); + if (len > 0) { + gString[20 + len - 1] = '\0'; + } + break; + case KEY_RETURN: + case KEY_KP_ENTER: + len = strlen(gNet_players[gThis_net_player_index].player_name); + if (len <= 18) { + the_message = gString + 18 - len; + strcpy(the_message, gNet_players[gThis_net_player_index].player_name); + the_message[len + 0] = ':'; + the_message[len + 1] = ' '; + gString[COUNT_OF(gString) - 1] = '\0'; + NetSendHeadupToAllPlayers(the_message); + gString[20] = '\0'; + NewTextHeadupSlot(4, 0, 1000, -4, GetMiscString(kMiscString_MESSAGE_SENT)); + about_to_die = 1; + } + break; + default: + if (gKey_mapping[66] == the_key) { + about_to_die = 1; + } else if (the_key <= KEY_KP_NUMLOCK || the_key >= KEY_SPACE) { + len = strlen(&gString[20]); + if (len < 64 - 1) { + gString[20 + len] = PDGetASCIIFromKey(the_key); + if (gString[20 + len] < gFonts[4].offset || gString[20 + len] >= gFonts[4].offset + gFonts[4].num_entries) { + gString[20 + len] = '\0'; + } + gString[20 + len + 1] = '\0'; + } + } else if (the_key < KEY_KP_0 || the_key > KEY_KP_9) { + gEntering_message = 0; + } else { + if (the_key == KEY_KP_0) { + abuse_num = 9; + } else { + abuse_num = the_key - KEY_KP_1; + } + if (gAbuse_text[abuse_num] != NULL) { + strcpy(&gString[20], gAbuse_text[abuse_num]); + } + } + } } // IDA: void __cdecl DisplayUserMessage() diff --git a/src/DETHRACE/common/crush.c b/src/DETHRACE/common/crush.c index 56e0710a..45793c68 100644 --- a/src/DETHRACE/common/crush.c +++ b/src/DETHRACE/common/crush.c @@ -667,7 +667,29 @@ void DoPratcamHit(br_vector3* pHit_vector) { br_scalar strength; LOG_TRACE("(%p)", pHit_vector); - STUB_ONCE(); + strength = BrVector3LengthSquared(pHit_vector); + if (strength > 0.2f) { + strength_modifier = 8; + } else if (strength > 0.015f) { + strength_modifier = 4; + } else if (strength >= 0.001f) { + strength_modifier = 0; + } else { + return; + } + if (fabsf(pHit_vector->v[2]) >= fabsf(pHit_vector->v[0])) { + if (pHit_vector->v[2] >= 0.f) { + PratcamEvent(14 + strength_modifier); + } else { + PratcamEvent(13 + strength_modifier); + } + } else { + if (pHit_vector->v[0] >= 0.f) { + PratcamEvent(15 + strength_modifier); + } else { + PratcamEvent(16 + strength_modifier); + } + } } // IDA: void __usercall DamageSystems(tCar_spec *pCar@, br_vector3 *pImpact_point@, br_vector3 *pEnergy_vector@, int pWas_hitting_a_car@) diff --git a/src/DETHRACE/common/depth.c b/src/DETHRACE/common/depth.c index a2d9c4b9..9502eb46 100644 --- a/src/DETHRACE/common/depth.c +++ b/src/DETHRACE/common/depth.c @@ -998,7 +998,11 @@ void ChangeDepthEffect(void) { br_scalar distance; tSpecial_volume* special_volume; LOG_TRACE("()"); - STUB_ONCE(); + + gProgram_state.current_depth_effect.type = gProgram_state.default_depth_effect.type; + gProgram_state.current_depth_effect.sky_texture = gProgram_state.default_depth_effect.sky_texture; + gProgram_state.current_depth_effect.start = gProgram_state.default_depth_effect.start; + gProgram_state.current_depth_effect.end = gProgram_state.default_depth_effect.end; } // IDA: void __cdecl MungeForwardSky() diff --git a/src/DETHRACE/common/graphics.c b/src/DETHRACE/common/graphics.c index 7ab3431f..db6fbc46 100644 --- a/src/DETHRACE/common/graphics.c +++ b/src/DETHRACE/common/graphics.c @@ -709,7 +709,11 @@ void InitializePalettes(void) { void SwitchToPalette(char* pPal_name) { br_pixelmap* the_palette; LOG_TRACE("(\"%s\")", pPal_name); - NOT_IMPLEMENTED(); + + the_palette = BrTableFind(pPal_name); + if (the_palette != NULL) { + DRSetPalette(the_palette); + } } // IDA: void __cdecl ClearEntireScreen() From 84f7de422cc49f19fa25c0f998a2edec46f2dad8 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Wed, 12 Jun 2024 15:04:56 +0200 Subject: [PATCH 35/40] Rewrite if's a bit --- src/DETHRACE/common/car.c | 2 +- src/DETHRACE/common/flicplay.c | 24 ++++++++++-------------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index 81b511af..f8e84d48 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1486,7 +1486,7 @@ void ToggleControls(void) { LOG_TRACE("()"); gControl__car++; - if (ControlCar[gControl__car] == 0) { + if (ControlCar[gControl__car] == NULL) { gControl__car = 0; } switch (gControl__car) { diff --git a/src/DETHRACE/common/flicplay.c b/src/DETHRACE/common/flicplay.c index 34533874..5abe85bc 100644 --- a/src/DETHRACE/common/flicplay.c +++ b/src/DETHRACE/common/flicplay.c @@ -736,23 +736,19 @@ int StartFlic(char* pFile_name, int pIndex, tFlic_descriptor_ptr pFlic_info, tU3 MemSkipBytes(&pFlic_info->data, 0x6e); pFlic_info->the_pixelmap = pDest_pixelmap; - if (pX_offset == -1) { - if (pDest_pixelmap != NULL) { - pFlic_info->x_offset = (pDest_pixelmap->width - pFlic_info->width) / 2; - } else { - pFlic_info->x_offset = 0; - } - } else { + if (pX_offset != -1) { pFlic_info->x_offset = pX_offset; - } - if (pY_offset == -1) { - if (pDest_pixelmap != NULL) { - pFlic_info->y_offset = (pDest_pixelmap->height - pFlic_info->height) / 2; - } else { - pFlic_info->y_offset = 0; - } + } else if (pDest_pixelmap != NULL) { + pFlic_info->x_offset = (pDest_pixelmap->width - pFlic_info->width) / 2; } else { + pFlic_info->x_offset = 0; + } + if (pY_offset != -1) { pFlic_info->y_offset = pY_offset; + } else if (pDest_pixelmap != NULL) { + pFlic_info->y_offset = (pDest_pixelmap->height - pFlic_info->height) / 2; + } else { + pFlic_info->y_offset = 0; } if (pFrame_rate != 0) { From e1a602fe84715a32d4a96ca3a7462070be019630 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Wed, 12 Jun 2024 22:10:26 +0200 Subject: [PATCH 36/40] Use enum values for GetMiscString and DoFancyHeadup --- src/BRSRC13/include/brender/br_inline_funcs.h | 7 ------ src/DETHRACE/common/car.c | 2 +- src/DETHRACE/common/controls.c | 2 +- src/DETHRACE/common/crush.c | 8 +++---- src/DETHRACE/common/netgame.c | 16 +++++++------- src/DETHRACE/common/network.c | 22 +++++++++---------- src/DETHRACE/common/pedestrn.c | 2 +- src/DETHRACE/common/powerup.c | 2 +- src/DETHRACE/common/racesumm.c | 4 ++-- src/DETHRACE/constants.h | 6 ++--- 10 files changed, 31 insertions(+), 40 deletions(-) diff --git a/src/BRSRC13/include/brender/br_inline_funcs.h b/src/BRSRC13/include/brender/br_inline_funcs.h index 1a2346f9..fb8b76e1 100644 --- a/src/BRSRC13/include/brender/br_inline_funcs.h +++ b/src/BRSRC13/include/brender/br_inline_funcs.h @@ -70,13 +70,6 @@ (v1)->v[2] = (v2)->v[2] * (v3)->v[2]; \ } while (0) -#define BrVector3Div(v1, v2, v3) \ - do { \ - (v1)->v[0] = (v2)->v[0] / (v3)->v[0]; \ - (v1)->v[1] = (v2)->v[1] / (v3)->v[1]; \ - (v1)->v[2] = (v2)->v[2] / (v3)->v[2]; \ - } while (0) - #define BrVector3Accumulate(v1, v2) \ do { \ (v1)->v[0] += (v2)->v[0]; \ diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index f8e84d48..d75c2531 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -1761,7 +1761,7 @@ void RotateCar2(tCollision_info* c, br_scalar dt) { BrMatrix34PostTranslate(&m, c->cmpos.v[0], c->cmpos.v[1], c->cmpos.v[2]); BrMatrix34Pre(&c->car_master_actor->t.t.mat, &m); BrVector3Copy(&c->oldomega, &c->omega); - BrVector3Div(&c->omega, &L2, &c->I); + Vector3Div(&c->omega, &L2, &c->I); } // IDA: void __usercall RotateCarSecondOrder(tCollision_info *c@, br_scalar dt) diff --git a/src/DETHRACE/common/controls.c b/src/DETHRACE/common/controls.c index b60493b4..159904e3 100644 --- a/src/DETHRACE/common/controls.c +++ b/src/DETHRACE/common/controls.c @@ -2619,7 +2619,7 @@ void DisplayUserMessage(void) { gCurrent_graf_data->net_message_enter_y + 6 * font->height, 1); - TransDRPixelmapText(gBack_screen, 20 * gBack_screen->width / 100, gCurrent_graf_data->net_message_enter_y, font, GetMiscString(227), 100); + TransDRPixelmapText(gBack_screen, 20 * gBack_screen->width / 100, gCurrent_graf_data->net_message_enter_y, font, GetMiscString(kMiscString_ENTER_MESSAGE), 100); OoerrIveGotTextInMeBoxMissus( FONT_NEWHITE, the_message, diff --git a/src/DETHRACE/common/crush.c b/src/DETHRACE/common/crush.c index 45793c68..b09403cb 100644 --- a/src/DETHRACE/common/crush.c +++ b/src/DETHRACE/common/crush.c @@ -1177,7 +1177,7 @@ int DoCrashEarnings(tCar_spec* pCar1, tCar_spec* pCar2) { NetEarnCredits(NetPlayerFromCar(culprit), credits); } else { PratcamEvent(32); - DoFancyHeadup(11); + DoFancyHeadup(kFancyHeadupYouWastedEm); credits_squared = sqr(0.7f / victim->car_model_actors[victim->principal_car_actor].crush_data.softness_factor) * gWasted_creds[gProgram_state.skill_level] + 50.0f; credits = 100 * (int)(credits_squared / 100.0); AwardTime(gWasted_time[gProgram_state.skill_level]); @@ -1242,13 +1242,13 @@ int DoCrashEarnings(tCar_spec* pCar1, tCar_spec* pCar2) { AwardTime(MIN(time, 90)); if (pCar2) { if (head_on) { - DoFancyHeadup(10); + DoFancyHeadup(kFancyHeadupHeadOnBonus); } else if (bonus_level <= 2) { if (bonus_level > 1) { - DoFancyHeadup(2); + DoFancyHeadup(kFancyHeadupExtraStyleBonus); } } else { - DoFancyHeadup(3); + DoFancyHeadup(kFancyHeadupBonusForArtisticImpression); } } } diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index dc0f2ded..3db80ec0 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -827,7 +827,7 @@ void DoNetScores2(int pOnly_sort_scores) { } if (abs(gNet_players[index].score) == 1000000) { if (flash_state) { - strcpy(s, GetMiscString(173)); + strcpy(s, GetMiscString(kMiscString_WASTED_173)); } else { s[0] = '\0'; } @@ -846,13 +846,13 @@ void DoNetScores2(int pOnly_sort_scores) { case eNet_game_type_sudden_death: if (gNet_players[index].score < 0) { if (flash_state) { - sprintf(s, "%s", GetMiscString(93)); + sprintf(s, "%s", GetMiscString(kMiscString_OUT)); } else { s[0] = '\0'; } } else { score = gNet_players[index].score; - sprintf(s, "%s -%d-", GetMiscString(92), score); + sprintf(s, "%s -%d-", GetMiscString(kMiscString_IN), score); } break; case eNet_game_type_tag: @@ -864,7 +864,7 @@ void DoNetScores2(int pOnly_sort_scores) { TimerString(gNet_players[index].score, s, 0, 1); } } else { - sprintf(s, "%s", GetMiscString(93)); + sprintf(s, "%s", GetMiscString(kMiscString_OUT)); } break; default: @@ -1141,7 +1141,7 @@ void CalcPlayerScores(void) { if (gNet_players[i].last_waste_message != 0 && !gNet_players[i].wasteage_attributed && time - gNet_players[i].last_waste_message > 500) { - sprintf(s, "%s %s", gNet_players[i].player_name, GetMiscString(172)); + sprintf(s, "%s %s", gNet_players[i].player_name, GetMiscString(kMiscString_COMMITTED_SUICIDE)); gNet_players[i].last_waste_message = 0; gNet_players[i].wasteage_attributed = 0; if (gCurrent_net_game->type == eNet_game_type_car_crusher) { @@ -1308,7 +1308,7 @@ void CalcPlayerScores(void) { if (cars_left) { lowest_score_player->car->knackered = 1; lowest_score_player->wasted = 1; - lowest_score_player->games_score += gGame_scores[6 - cars_left]; + lowest_score_player->games_score += gGame_scores[5 - cars_left]; lowest_score_player->score = -1; if (player_left == -1) { EverybodysLost(); @@ -1317,7 +1317,7 @@ void CalcPlayerScores(void) { SelectRandomItOrFox(i); } SendGameplay(lowest_score_player->ID, eNet_gameplay_suddenly_death, 0, 0, 0, 0); - sprintf(s, "%s %s", lowest_score_player->player_name, GetMiscString(184)); + sprintf(s, "%s %s", lowest_score_player->player_name, GetMiscString(kMiscString_IS_OUT)); NetSendHeadupToEverybody(s); } else { DeclareWinner(player_left); @@ -1560,7 +1560,7 @@ void ReceivedGameplay(tNet_contents* pContents, tNet_message* pMessage, tU32 pRe WrongCheckpoint(pContents->data.gameplay.param_1); break; case eNet_gameplay_suddenly_death: - DoFancyHeadup(17); + DoFancyHeadup(kFancyHeadupNetworkRaceOverNetworkLoss); ChangeAmbientPratcam(36); gRace_finished = 1; break; diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 0defe03c..a9f579d8 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -1610,14 +1610,14 @@ void ReceivedWasted(tNet_contents* pContents) { victim->car->knackered = 1; if (pContents->data.wasted.victim == gLocal_net_ID) { if (gCurrent_net_game->type == eNet_game_type_fight_to_death) { - DoFancyHeadup(19); + DoFancyHeadup(kFancyHeadupYouLost); gRace_finished = 1; } else { last_got_wasted_time = PDGetTotalTime(); if (last_got_wasted_time - last_wasted_em_time > 1000) { - DoFancyHeadup(15); + DoFancyHeadup(kFancyHeadupYouAreWasted); } else { - DoFancyHeadup(16); + DoFancyHeadup(kFancyHeadupYouAreBothWasted); } } } @@ -1631,20 +1631,18 @@ void ReceivedWasted(tNet_contents* pContents) { } else { culprit = NetPlayerFromID(pContents->data.wasted.culprit); } - if (culprit != NULL) { - if (gNet_mode == eNet_mode_host && gCurrent_net_game->type == eNet_game_type_car_crusher) { - culprit->score++; - } + if (culprit != NULL && gNet_mode == eNet_mode_host && gCurrent_net_game->type == eNet_game_type_car_crusher) { + culprit->score++; if (culprit->score >= gCurrent_net_game->options.race_end_target) { DeclareWinner(culprit - gNet_players); } } victim->last_waste_message = GetTotalTime(); victim->wasteage_attributed = 1; - if (culprit != NULL && victim == last_culprit && culprit == last_victim && PDGetTotalTime() - last_wasty_message_time < 1000) { - sprintf(s, "%s %s %s %s", victim->player_name, GetMiscString(126), culprit->player_name, GetMiscString(127)); + if (victim == last_culprit && culprit == last_victim && victim != NULL && culprit != NULL && PDGetTotalTime() - last_wasty_message_time < 1000) { + sprintf(s, "%s %s %s %s", victim->player_name, GetMiscString(kMiscString_AND), culprit->player_name, GetMiscString(kMiscString_WASTED_EACH_OTHER)); } else { - sprintf(s, "%s %s %s", victim->player_name, GetMiscString(171), culprit ? culprit->player_name : GetMiscString(216)); + sprintf(s, "%s %s %s", victim->player_name, GetMiscString(kMiscString_WastedBy), culprit ? culprit->player_name : GetMiscString(kMiscString_COP)); } NewTextHeadupSlot2(4, 0, 3000, -4, s, 0); last_wasty_message_time = PDGetTotalTime(); @@ -1654,9 +1652,9 @@ void ReceivedWasted(tNet_contents* pContents) { PratcamEvent(32); last_wasted_em_time = PDGetTotalTime(); if (last_wasted_em_time - last_got_wasted_time > 1000) { - DoFancyHeadup(11); + DoFancyHeadup(kFancyHeadupYouWastedEm); } else { - DoFancyHeadup(16); + DoFancyHeadup(kFancyHeadupYouAreBothWasted); } } } diff --git a/src/DETHRACE/common/pedestrn.c b/src/DETHRACE/common/pedestrn.c index 4cfa913d..524210fe 100644 --- a/src/DETHRACE/common/pedestrn.c +++ b/src/DETHRACE/common/pedestrn.c @@ -1925,7 +1925,7 @@ void CheckPedestrianDeathScenario(tPedestrian_data* pPedestrian) { if (billiards_shot) { credits_value *= 4; PratcamEvent(30); - DoFancyHeadup(8); + DoFancyHeadup(kFancyHeadupNiceShotSir); } else if (fabsf(the_car->omega.v[V_X]) <= 5.0f && fabsf(the_car->omega.v[V_Z]) <= 5.0f && BrVector3Dot(&the_car->car_master_actor->t.t.look_up.up, &up) >= 0.1f diff --git a/src/DETHRACE/common/powerup.c b/src/DETHRACE/common/powerup.c index 24be7423..7ae86fa2 100644 --- a/src/DETHRACE/common/powerup.c +++ b/src/DETHRACE/common/powerup.c @@ -142,7 +142,7 @@ int gFizzle_height; int gNumber_of_icons; tPowerup* gPowerup_array; -#define GET_POWERUP_INDEX(POWERUP) (((POWERUP)-gPowerup_array) / sizeof(tPowerup)) +#define GET_POWERUP_INDEX(POWERUP) ((POWERUP)-gPowerup_array) // IDA: void __usercall LosePowerupX(tPowerup *pThe_powerup@, int pTell_net_players@) void LosePowerupX(tPowerup* pThe_powerup, int pTell_net_players) { diff --git a/src/DETHRACE/common/racesumm.c b/src/DETHRACE/common/racesumm.c index 6ece16e4..7a331804 100644 --- a/src/DETHRACE/common/racesumm.c +++ b/src/DETHRACE/common/racesumm.c @@ -1223,10 +1223,10 @@ void NetSumDraw(int pCurrent_choice, int pCurrent_mode) { DRPixelmapRectangleMaskedCopy(gBack_screen, gCurrent_graf_data->net_sum_x_1, gCurrent_graf_data->net_sum_headings_y + 1 + i * gCurrent_graf_data->net_sum_y_pitch, - gIcons_pix, + gIcons_pix_low_res, /* DOS version uses low res, Windows version uses normal res */ 0, gCurrent_graf_data->net_head_icon_height * player->car_index, - gIcons_pix->width, + gIcons_pix_low_res->width, /* DOS version uses low res, Windows version uses normal res */ gCurrent_graf_data->net_head_icon_height); TurnOnPaletteConversion(); DrawAnItem__racesumm(gCurrent_graf_data->net_sum_x_2, i, 83, s); diff --git a/src/DETHRACE/constants.h b/src/DETHRACE/constants.h index f77faf37..e3916c21 100644 --- a/src/DETHRACE/constants.h +++ b/src/DETHRACE/constants.h @@ -324,11 +324,11 @@ enum { kFancyHeadupCheckpoint = 12, kFancyHeadupOutOfTime = 13, kFancyHeadupRaceCompleted = 14, - - // FIXME: missing network fancy head-ups - + kFancyHeadupYouAreWasted = 15, + kFancyHeadupYouAreBothWasted = 16, kFancyHeadupNetworkRaceOverNetworkLoss = 17, kFancyHeadupNetworkRaceNoMoreMoney = 18, + kFancyHeadupYouLost = 19, kFancyHeadupNetworkVictory = 20, kFancyHeadupDemoTimeout = 21, }; From a498a4c1a376c715eac65b26fdc81b19b2759e01 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 13 Jun 2024 21:54:21 +0200 Subject: [PATCH 37/40] Fix fox effect --- src/DETHRACE/common/spark.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/DETHRACE/common/spark.c b/src/DETHRACE/common/spark.c index 4bf82404..61843e50 100644 --- a/src/DETHRACE/common/spark.c +++ b/src/DETHRACE/common/spark.c @@ -2668,9 +2668,9 @@ void DoModelThing(br_actor* actor, br_model* pModel, br_material* material, void GetRaceTime(); for (group = 0; group < V11MODEL(pModel)->ngroups; group++) { for (j = 0; j < V11MODEL(pModel)->groups[group].nvertices; j++) { - if (!((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) & 1)) { - if ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) < 0xc9) { - val = ((V11MODEL(pModel)->groups[group].vertex_colours[j] >> 24) + 2 * IRandomBetween(5, 10)) << 24; + if (!(((V11MODEL(pModel)->groups[group].vertex_colours[j]) >> 24) & 1)) { + if (((V11MODEL(pModel)->groups[group].vertex_colours[j]) >> 24) < 0xc9) { + val = ((V11MODEL(pModel)->groups[group].vertex_colours[j]) >> 24) + 2 * IRandomBetween(5, 10); V11MODEL(pModel)->groups[group].vertex_colours[j] = BR_COLOUR_RGBA(0, 0, 0, val); if (pModel->flags & BR_MODF_UPDATEABLE) { pModel->vertices[V11MODEL(pModel)->groups[group].vertex_user[j]].index = val; From 8836cc5740c0b7e4d57af7f04eb1c8074fa10d48 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Fri, 14 Jun 2024 15:42:35 +0200 Subject: [PATCH 38/40] Fix fox/it effect at start of race --- src/DETHRACE/common/netgame.c | 4 ++-- src/DETHRACE/common/network.c | 9 ++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index a819a3ad..31bad5c8 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -1018,7 +1018,7 @@ void PlayerIsIt(tNet_game_player_info* pPlayer) { } MakeCarIt(pPlayer->car); gIt_or_fox = pPlayer - gNet_players; - sprintf(s, "%s", GetMiscString(gCurrent_net_game->type == eNet_game_type_tag ? 186 : 188)); + sprintf(s, "%s", GetMiscString(gCurrent_net_game->type == eNet_game_type_tag ? kMiscString_HA_HA_YOU_ARE_IT : kMiscString_YOU_ARE_THE_FOX)); NetSendHeadupToPlayer(s, pPlayer->ID); for (i = 0; i < gNumber_of_net_players; i++) { if (&gNet_players[i] != pPlayer) { @@ -1059,7 +1059,7 @@ void SelectRandomItOrFox(int pNot_this_one) { LOG_TRACE("(%d)", pNot_this_one); new_choice = 0; - gLast_lepper = 0; + gLast_lepper = NULL; if (gCurrent_net_game->type == eNet_game_type_tag) { for (i = 0; i < gNumber_of_net_players; i++) { if (gNet_players[i].last_score_index == 0) { diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 28089dde..3c94403c 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -506,7 +506,14 @@ void NetPlayersChanged(int pNew_count, tNet_game_player_info* pNew_players) { LOG_TRACE("(%d, %p)", pNew_count, pNew_players); if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) { - old_fox_it = gNet_players[gIt_or_fox].ID; +#ifdef DETHRACE_FIX_BUGS + old_fox_it = -1; + if (gIt_or_fox >= 0) { +#endif + old_fox_it = gNet_players[gIt_or_fox].ID; +#ifdef DETHRACE_FIX_BUGS + } +#endif } for (i = 0; i < pNew_count; i++) { new_player = 1; From 44ec100bd1612be7aa6423a92c51c8e52ae4d786 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 20 Jun 2024 00:55:28 +0200 Subject: [PATCH 39/40] Use KEYMAP_ enum values --- src/DETHRACE/common/controls.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/DETHRACE/common/controls.c b/src/DETHRACE/common/controls.c index b131f91a..766bfc81 100644 --- a/src/DETHRACE/common/controls.c +++ b/src/DETHRACE/common/controls.c @@ -1397,14 +1397,14 @@ void CheckMapRenderMove(void) { old_x = gMap_render_x; if (gMap_mode) { amount = gFrame_period * .1f; - if (KeyIsDown(30)) { + if (KeyIsDown(KEYMAP_MOVE_UP)) { gMap_render_y -= amount; - } else if (KeyIsDown(31)) { + } else if (KeyIsDown(KEYMAP_MOVE_DOWN)) { gMap_render_y += amount; } - if (KeyIsDown(32)) { + if (KeyIsDown(KEYMAP_MOVE_LEFT)) { gMap_render_x -= amount; - } else if (KeyIsDown(33)) { + } else if (KeyIsDown(KEYMAP_MOVE_RIGHT)) { gMap_render_x += amount; } if (gMap_render_x != old_x || gMap_render_y != old_y) { @@ -1750,7 +1750,7 @@ void FlipUpCar(tCar_spec* car) { count = 0; if (car->driver == eDriver_local_human && gNet_mode == eNet_mode_none) { FadePaletteDown(); - while (KeyIsDown(44)) { + while (KeyIsDown(KEYMAP_REPAIR)) { ; } } @@ -2568,7 +2568,7 @@ void EnterUserMessage(void) { } break; default: - if (gKey_mapping[66] == the_key) { + if (gKey_mapping[KEYMAP_SEND_MESSAGE] == the_key) { about_to_die = 1; } else if (the_key <= KEY_KP_NUMLOCK || the_key >= KEY_SPACE) { len = strlen(&gString[20]); From 7c765ae444603edf2b0e29353a523cf1a59232d5 Mon Sep 17 00:00:00 2001 From: Anonymous Maarten Date: Thu, 20 Jun 2024 12:19:16 +0200 Subject: [PATCH 40/40] Disable address sanitizer and dr_dprintf logging --- src/DETHRACE/CMakeLists.txt | 4 ++-- src/DETHRACE/common/errors.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/DETHRACE/CMakeLists.txt b/src/DETHRACE/CMakeLists.txt index 5b142aa3..c679a5cf 100644 --- a/src/DETHRACE/CMakeLists.txt +++ b/src/DETHRACE/CMakeLists.txt @@ -10,8 +10,8 @@ target_include_directories(dethrace_obj pd ) -add_compile_options(-fsanitize=address) -add_link_options(-fsanitize=address) +# add_compile_options(-fsanitize=address) +# add_link_options(-fsanitize=address) target_link_libraries(dethrace_obj PUBLIC SDL2::SDL2 smackw32 harness BRender::Full BRender::DDI s3) diff --git a/src/DETHRACE/common/errors.c b/src/DETHRACE/common/errors.c index 81d7607b..7d95a792 100644 --- a/src/DETHRACE/common/errors.c +++ b/src/DETHRACE/common/errors.c @@ -260,10 +260,10 @@ void dr_dprintf(char* fmt_string, ...) { fflush(gDiagnostic_file); // Added by dethrace for debugging - va_start(args, fmt_string); - vprintf(fmt_string, args); - va_end(args); - printf("\n"); + // va_start(args, fmt_string); + // vprintf(fmt_string, args); + // va_end(args); + // printf("\n"); } // IDA: int __usercall DoErrorInterface@(int pMisc_text_index@)