From 1c10b74141bf111c7dfb518fa984198090b73ab4 Mon Sep 17 00:00:00 2001 From: Dethrace Engineering Department <78985374+dethrace-labs@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:18:52 +1200 Subject: [PATCH] Networking #1 - Lobby implemented (#335) * Basic networking functions implemented to get the lobby functional * Apply suggestions from code review * PDNetObtainSystemUserName gets local system name --------- Co-authored-by: Anonymous Maarten --- .github/scripts/build-msvc.ps1 | 8 + CMakeLists.txt | 5 +- src/DETHRACE/CMakeLists.txt | 11 +- src/DETHRACE/common/car.c | 54 +- src/DETHRACE/common/controls.c | 29 +- src/DETHRACE/common/errors.c | 10 + src/DETHRACE/common/init.c | 8 +- src/DETHRACE/common/intrface.c | 44 +- src/DETHRACE/common/loading.c | 7 +- src/DETHRACE/common/mainmenu.c | 12 +- src/DETHRACE/common/netgame.c | 252 ++++- src/DETHRACE/common/network.c | 1218 ++++++++++++++++++++++-- src/DETHRACE/common/network.h | 2 +- src/DETHRACE/common/newgame.c | 1152 ++++++++++++++++++++-- src/DETHRACE/common/pedestrn.c | 4 +- src/DETHRACE/common/pratcam.c | 6 + src/DETHRACE/common/racestrt.c | 292 +++++- src/DETHRACE/common/structur.c | 28 +- src/DETHRACE/common/utility.c | 1 - src/DETHRACE/constants.h | 36 + src/DETHRACE/dr_types.h | 923 ++---------------- src/DETHRACE/pc-dos/dosnet.c | 44 +- src/DETHRACE/pc-dos/dosnet.h | 193 ++++ src/DETHRACE/pc-dos/dossys.c | 13 +- src/DETHRACE/pc-win95/win95net.c | 668 +++++++++++++ src/DETHRACE/pc-win95/win95net_types.h | 25 + src/DETHRACE/pd/net.h | 54 +- src/S3/sos_dos_types.h | 187 ++++ src/harness/CMakeLists.txt | 2 + src/harness/harness.c | 5 + src/harness/include/harness/config.h | 1 + src/harness/include/harness/winsock.h | 52 + src/harness/win95/winsock.c | 27 + test/CMakeLists.txt | 2 +- 34 files changed, 4199 insertions(+), 1176 deletions(-) create mode 100644 src/DETHRACE/pc-dos/dosnet.h create mode 100644 src/DETHRACE/pc-win95/win95net.c create mode 100644 src/DETHRACE/pc-win95/win95net_types.h create mode 100644 src/S3/sos_dos_types.h create mode 100644 src/harness/include/harness/winsock.h create mode 100644 src/harness/win95/winsock.c diff --git a/.github/scripts/build-msvc.ps1 b/.github/scripts/build-msvc.ps1 index 2d5f2d50..90c3e58a 100644 --- a/.github/scripts/build-msvc.ps1 +++ b/.github/scripts/build-msvc.ps1 @@ -1,3 +1,5 @@ +$ErrorActionPreference = "Stop" + if ($($Env:PLATFORM_ARCH) -eq "x86") { $sdl_path = "x86" } else { @@ -18,7 +20,13 @@ Expand-Archive $Env:TEMP\SDL2-devel.zip -DestinationPath $Env:TEMP # build cmake -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTS=ON "-DSDL2_ROOT_DIR=$($Env:TEMP)\SDL2-$sdl2_version" -B build +if ($LASTEXITCODE -ne 0) { + Exit $LASTEXITCODE +} cmake --build build --config RelWithDebInfo +if ($LASTEXITCODE -ne 0) { + Exit $LASTEXITCODE +} # copy SDL2.dll to build folder, so tests can run cp $Env:TEMP\SDL2-$sdl2_version\lib\$sdl_path\SDL2.dll build diff --git a/CMakeLists.txt b/CMakeLists.txt index 98e04180..fa1f014f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,7 +48,10 @@ endfunction() test_big_endian(IS_BIGENDIAN) -find_package(SDL2 REQUIRED) +find_package(SDL2 CONFIG) +if(NOT SDL2_FOUND) + find_package(SDL2 MODULE REQUIRED) +endif() add_subdirectory(lib/libsmacker) add_subdirectory(lib/glad) diff --git a/src/DETHRACE/CMakeLists.txt b/src/DETHRACE/CMakeLists.txt index db255787..76b864aa 100644 --- a/src/DETHRACE/CMakeLists.txt +++ b/src/DETHRACE/CMakeLists.txt @@ -10,6 +10,9 @@ target_include_directories(dethrace_obj pd ) +# add_compile_options(-fsanitize=address) +# add_link_options(-fsanitize=address) + target_link_libraries(dethrace_obj PUBLIC SDL2::SDL2 smackw32 harness brender s3) @@ -35,6 +38,7 @@ else() -Wstrict-prototypes ) endif() +target_compile_definitions(dethrace_obj PRIVATE INSIDE_DETHRACE) if(DETHRACE_FIX_BUGS) target_compile_definitions(dethrace_obj PRIVATE DETHRACE_FIX_BUGS) endif() @@ -154,14 +158,15 @@ target_sources(dethrace_obj PRIVATE common/world.h constants.h dr_types.h - pc-dos/dosnet.c pd/net.h - pc-dos/dossys.c pd/sys.h pc-win95/win95sys.c pc-win95/dinput.h pc-win95/ssdx.c pc-win95/ssdx.h + pc-win95/win95net.c + pc-dos/dosnet.c + pc-dos/dossys.c ) # Create our main game binary. @@ -184,7 +189,7 @@ if(NOT MSVC) else() target_link_libraries(dethrace PRIVATE dbghelp) target_link_options(dethrace PRIVATE /subsystem:windows /ENTRY:mainCRTStartup) - target_compile_definitions(dethrace PRIVATE -D_CRT_SECURE_NO_WARNINGS -DSDL_MAIN_HANDLED) + target_compile_definitions(dethrace PRIVATE -D_CRT_SECURE_NO_WARNINGS -DSDL_MAIN_HANDLED -DWIN32_LEAN_AND_MEAN) endif() if(DETHRACE_IDE_ROOT_DIR) diff --git a/src/DETHRACE/common/car.c b/src/DETHRACE/common/car.c index 06bc0ce8..db992113 100644 --- a/src/DETHRACE/common/car.c +++ b/src/DETHRACE/common/car.c @@ -494,36 +494,60 @@ void SetInitialPosition(tRace_info* pThe_race, int pCar_index, int pGrid_index) car = pThe_race->opponent_list[pCar_index].car_spec; BrMatrix34Identity(&car_actor->t.t.mat); place_on_grid = 1; - if (gNet_mode && !gCurrent_net_game->options.grid_start && pThe_race->number_of_net_start_points) { - TELL_ME_IF_WE_PASS_THIS_WAY(); + if (gNet_mode != eNet_mode_none && !gCurrent_net_game->options.grid_start && pThe_race->number_of_net_start_points != 0) { + start_i = i = IRandomBetween(0, pThe_race->number_of_net_start_points - 1); + do { + PossibleService(); + for (j = 0; j < gNumber_of_net_players; j++) { + if (j != pCar_index) { + BrVector3Copy(&real_pos, &pThe_race->opponent_list[j].car_spec->car_master_actor->t.t.translate.t); + if (real_pos.v[0] > 500.f) { + real_pos.v[0] -= 1000.f; + real_pos.v[1] -= 1000.f; + real_pos.v[2] -= 1000.f; + } + BrVector3Sub(&dist, &real_pos, &pThe_race->net_starts[i].pos); + if (BrVector3LengthSquared(&dist) < 16.f) { + break; + } + } + } + if (j == gNumber_of_net_players) { + BrVector3Copy(&car_actor->t.t.translate.t, &pThe_race->net_starts[i].pos); + initial_yaw = BrDegreeToAngle(pThe_race->net_starts[i].yaw); + place_on_grid = 0; + } + i++; + if (i == pThe_race->number_of_net_start_points) { + i = 0; + } + } while (start_i != i); } if (place_on_grid) { - initial_yaw = (pThe_race->initial_yaw * 182.0444444444445); + initial_yaw = BrDegreeToAngle(pThe_race->initial_yaw); BrMatrix34RotateY(&initial_yaw_matrix, initial_yaw); - grid_offset.v[0] = 0.0 - pGrid_index % 2; - grid_offset.v[1] = 0.0; - grid_offset.v[2] = (double)(pGrid_index / 2) * 2.0 + (double)(pGrid_index % 2) * 0.40000001; + grid_offset.v[0] = 0.0f - pGrid_index % 2; + grid_offset.v[1] = 0.0f; + grid_offset.v[2] = (br_scalar)(pGrid_index / 2) * 2.0f + (br_scalar)(pGrid_index % 2) * 0.4f; BrMatrix34ApplyV(&car_actor->t.t.translate.t, &grid_offset, &initial_yaw_matrix); BrVector3Accumulate(&car_actor->t.t.translate.t, &pThe_race->initial_position); } FindBestY( &car_actor->t.t.translate.t, gTrack_actor, - 10.0, + 10.0f, &nearest_y_above, &nearest_y_below, &above_model, &below_model, &above_face_index, &below_face_index); - if (nearest_y_above == 30000.0) { - if (nearest_y_below == -30000.0) { - car_actor->t.t.translate.t.v[1] = 0.0; - } else { - car_actor->t.t.translate.t.v[1] = nearest_y_below; - } - } else { + if (nearest_y_above != 30000.0f) { car_actor->t.t.translate.t.v[1] = nearest_y_above; + } else if (nearest_y_below != -30000.0f) { + car_actor->t.t.translate.t.v[1] = nearest_y_below; + } else { + car_actor->t.t.translate.t.v[1] = 0.0f; } BrMatrix34PreRotateY(&car_actor->t.t.mat, initial_yaw); if (gNet_mode) { @@ -531,7 +555,7 @@ void SetInitialPosition(tRace_info* pThe_race, int pCar_index, int pGrid_index) &gNet_players[pThe_race->opponent_list[pCar_index].net_player_index].initial_position, &car->car_master_actor->t.t.mat); } - if (gNet_mode && car->disabled && car_actor->t.t.translate.t.v[0] < 500.0) { + if (gNet_mode != eNet_mode_none && car->disabled && car_actor->t.t.translate.t.v[0] < 500.0f) { DisableCar(car); } // Enable to start all opponent cars upside down ;) diff --git a/src/DETHRACE/common/controls.c b/src/DETHRACE/common/controls.c index fa53a948..ea847e49 100644 --- a/src/DETHRACE/common/controls.c +++ b/src/DETHRACE/common/controls.c @@ -2500,7 +2500,34 @@ void InitAbuseomatic(void) { int i; int len; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gString[20] = '\0'; + PDBuildAppPath(path); + strcat(path, "ABUSE.TXT"); + for (i = 0; i < COUNT_OF(gAbuse_text); i++) { + gAbuse_text[i] = NULL; + } + f = fopen(path, "rt"); + if (f == NULL) { + return; + } + for (i = 0; i < COUNT_OF(gAbuse_text); i++) { + if (fgets(s, COUNT_OF(s) - 1, f) == NULL) { + break; + } + len = strlen(s); + if (len > 63) { + s[63] = '\0'; + } + len = strlen(s); + while (len != 0 && s[len - 1] < ' ') { + s[len - 1] = '\0'; + len--; + } + gAbuse_text[i] = BrMemAllocate(strlen(s) + 1, kMem_abuse_text); + strcpy(gAbuse_text[i], s); + } + fclose(f); } // IDA: void __cdecl DisposeAbuseomatic() diff --git a/src/DETHRACE/common/errors.c b/src/DETHRACE/common/errors.c index 4776761f..7d95a792 100644 --- a/src/DETHRACE/common/errors.c +++ b/src/DETHRACE/common/errors.c @@ -242,6 +242,10 @@ void dr_dprintf(char* fmt_string, ...) { return; } + if (gDiagnostic_file == NULL) { + return; + } + if (first_time == 0) { first_time = GetTotalTime(); } @@ -254,6 +258,12 @@ void dr_dprintf(char* fmt_string, ...) { va_end(args); fputs("\n", gDiagnostic_file); fflush(gDiagnostic_file); + + // Added by dethrace for debugging + // 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/init.c b/src/DETHRACE/common/init.c index c6f9a02c..9bbe5d9c 100644 --- a/src/DETHRACE/common/init.c +++ b/src/DETHRACE/common/init.c @@ -425,7 +425,7 @@ void InitGame(int pStart_race) { gWaiting_for_unpause = 1; gWait_for_it = 1; - if (gNet_mode) { + if (gNet_mode != eNet_mode_none) { gCredit_period = gCredit_period_network[gCurrent_net_game->type]; } else { gCredit_period = gCredit_period_single[gProgram_state.skill_level]; @@ -448,10 +448,10 @@ void InitGame(int pStart_race) { gProgram_state.current_car.power_up_levels[i] = 0; } } - for (i = 0; gNumber_of_races > i; ++i) { + for (i = 0; i < gNumber_of_races; i++) { gRace_list[i].been_there_done_that = 0; } - for (i = 0; gNumber_of_racers > i; ++i) { + for (i = 0; i < gNumber_of_racers; i++) { gOpponents[i].dead = 0; } gProgram_state.rank = gInitial_rank; @@ -470,7 +470,7 @@ void DisposeGameIfNecessary(void) { int i; LOG_TRACE("()"); - if (gNet_mode) { + if (gNet_mode != eNet_mode_none) { NetLeaveGame(gCurrent_net_game); } if (gGame_initialized) { diff --git a/src/DETHRACE/common/intrface.c b/src/DETHRACE/common/intrface.c index 40470ba7..ff4c95fe 100644 --- a/src/DETHRACE/common/intrface.c +++ b/src/DETHRACE/common/intrface.c @@ -511,33 +511,29 @@ int DoInterfaceScreen(tInterface_spec* pSpec, int pOptions, int pCurrent_choice) } else { result = gCurrent_choice; } - if (!go_ahead) { - if (!escaped) { - if (pSpec->end_flic_otherwise > 0) { - DRS3StartSound(gEffects_outlet, 3007); - RunFlic(pSpec->end_flic_otherwise); - } else if (pSpec->end_flic_otherwise < 0) { - FadePaletteDown(); - } - goto LABEL_230; - } else { - if (pSpec->end_flic_escaped > 0) { - DRS3StartSound(gEffects_outlet, 3007); - RunFlic(pSpec->end_flic_escaped); - } else if (pSpec->end_flic_escaped < 0) { - FadePaletteDown(); - } - goto LABEL_230; + if (go_ahead) { + if (pSpec->end_flic_go_ahead > 0) { + DRS3StartSound(gIndexed_outlets[0], 3007); + RunFlic(pSpec->end_flic_go_ahead); + } else if (pSpec->end_flic_go_ahead < 0) { + FadePaletteDown(); + } + } else if (escaped) { + if (pSpec->end_flic_escaped > 0) { + DRS3StartSound(gIndexed_outlets[0], 3007); + RunFlic(pSpec->end_flic_escaped); + } else if (pSpec->end_flic_escaped < 0) { + FadePaletteDown(); + } + } else { + if (pSpec->end_flic_otherwise > 0) { + DRS3StartSound(gIndexed_outlets[0], 3007); + RunFlic(pSpec->end_flic_otherwise); + } else if (pSpec->end_flic_otherwise < 0) { + FadePaletteDown(); } } - if (pSpec->end_flic_go_ahead > 0) { - DRS3StartSound(gEffects_outlet, 3007); - RunFlic(pSpec->end_flic_go_ahead); - } else if (pSpec->end_flic_go_ahead < 0) { - FadePaletteDown(); - } -LABEL_230: gProgram_state.dont_save_or_load = 0; EndMouseCursor(); UnlockInterfaceStuff(); diff --git a/src/DETHRACE/common/loading.c b/src/DETHRACE/common/loading.c index c484a10f..80967ec7 100644 --- a/src/DETHRACE/common/loading.c +++ b/src/DETHRACE/common/loading.c @@ -3411,7 +3411,12 @@ int OriginalCarmaCDinDrive(void) { // IDA: int __cdecl CarmaCDinDriveOrFullGameInstalled() int CarmaCDinDriveOrFullGameInstalled(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gCD_fully_installed) { + return 1; + } else { + return OriginalCarmaCDinDrive(); + } } // IDA: void __usercall ReadNetworkSettings(FILE *pF@, tNet_game_options *pOptions@) diff --git a/src/DETHRACE/common/mainmenu.c b/src/DETHRACE/common/mainmenu.c index 87c8afba..61ca0891 100644 --- a/src/DETHRACE/common/mainmenu.c +++ b/src/DETHRACE/common/mainmenu.c @@ -323,10 +323,10 @@ int DoMainMenuInterface(tU32 pTime_out, int pContinue_allowed) { if (pContinue_allowed) { gMain_menu_spec = &interface_spec1; result = DoInterfaceScreen(&interface_spec1, gFaded_palette | 2, 0); - if (result != 7 && result && result != 1 && result != 2) { - RunFlic(12); - } else { + if (result == 0 || result == 1 || result == 2 || result == 7) { FadePaletteDown(); + } else { + RunFlic(12); } switch (result) { case 0: @@ -352,10 +352,10 @@ int DoMainMenuInterface(tU32 pTime_out, int pContinue_allowed) { } else { interface_spec2.time_out = pTime_out; result = DoInterfaceScreen(&interface_spec2, gFaded_palette, 0); - if (result != 4 && result != -1) { - RunFlic(32); - } else { + if (result == -1 || result == 4) { FadePaletteDown(); + } else { + RunFlic(32); } switch (result) { case 0: diff --git a/src/DETHRACE/common/netgame.c b/src/DETHRACE/common/netgame.c index baf3a75d..75f51890 100644 --- a/src/DETHRACE/common/netgame.c +++ b/src/DETHRACE/common/netgame.c @@ -1,11 +1,21 @@ #include "netgame.h" +#include "brender/brender.h" +#include "car.h" #include "displays.h" +#include "errors.h" #include "globvars.h" #include "globvrpb.h" +#include "graphics.h" #include "harness/trace.h" +#include "loading.h" #include "network.h" +#include "newgame.h" #include "opponent.h" +#include "pd/sys.h" +#include "pedestrn.h" #include "powerup.h" +#include "racestrt.h" +#include "structur.h" #include "utility.h" #include #include @@ -74,7 +84,20 @@ void SendAllNonCarPositions(void) { tNon_car_spec* non_car; tNet_contents* contents; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + list = gProgram_state.track_spec.non_car_list; + for (i = 0; i < gProgram_state.track_spec.ampersand_digits; ++i) { + if (list[i]->type_data != NULL) { + non_car = (tNon_car_spec*)list[i]->type_data; + if (non_car->collision_info.driver == eDriver_non_car_unused_slot || non_car->collision_info.car_ID != i) { + contents = NetGetBroadcastContents(NETMSGID_NONCARPOSITION, 0); + BrMatrix34Copy(&contents->data.non_car_position.mat, &list[i]->t.t.mat); + contents->data.non_car_position.ID = i; + contents->data.non_car_position.flags = list[i]->identifier[3] == '!'; + } + } + } + NetSendMessageStacks(); } // IDA: void __usercall ReceivedNonCarPosition(tNet_contents *pContents@) @@ -103,13 +126,60 @@ void SignalToStartRace2(int pIndex) { int i; int j; LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + if (gCurrent_race.number_of_racers > 6) { + FadePaletteUp(); + dr_dprintf("AAAARRRGGGHHH!!!! More than 6 racers!!!!"); + PDFatalError("AAAARRRGGGHHH!!!! More than 6 racers!!!!"); + } + gNeed_to_send_start_race = 0; + gStart_race_sent = 1; + the_message = NetBuildMessage(NETMSGID_STARTRACE, 0); + the_message->contents.data.start_race.racing = gProgram_state.racing; + if (pIndex >= 0) { + gNet_players[pIndex].last_waste_message = 0; + gNet_players[pIndex].wasteage_attributed = 0; + the_message->contents.data.start_race.car_count = -1; + the_message->contents.data.start_race.car_list[0].index = pIndex; + BrMatrix34Copy(&the_message->contents.data.start_race.car_list[0].mat, + &gCurrent_race.opponent_list[gNet_players[pIndex].opponent_list_index].car_spec->car_master_actor->t.t.mat); + } else { + the_message->contents.data.start_race.car_count = gCurrent_race.number_of_racers; + for (i = 0; i < gCurrent_race.number_of_racers; i++) { + BrMatrix34Copy(&the_message->contents.data.start_race.car_list[i].mat, + &gCurrent_race.opponent_list[i].car_spec->car_master_actor->t.t.mat); + for (j = 0; j < gNumber_of_net_players; j++) { + if (gCurrent_race.opponent_list[i].car_spec == gNet_players[j].car) { + the_message->contents.data.start_race.car_list[i].index = j; + break; + } + } + 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[the_message->contents.data.start_race.car_list[i].index].next_car_index < 0) { + gNet_players[the_message->contents.data.start_race.car_list[i].index].next_car_index = PickARandomCar(); + gCar_details[gNet_players[the_message->contents.data.start_race.car_list[i].index].next_car_index].ownership = eCar_owner_someone; + } + the_message->contents.data.start_race.car_list[i].next_car_index = gNet_players[the_message->contents.data.start_race.car_list[i].index].next_car_index; + } + } + if (gPending_race < 0) { + gPending_race = PickNetRace(gProgram_state.current_race_index, + gCurrent_net_game->options.race_sequence_type); + } + the_message->contents.data.start_race.next_race = gPending_race; + } + NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL); + if (gProgram_state.racing) { + SendCurrentPowerups(); + } } // IDA: void __cdecl SignalToStartRace() void SignalToStartRace(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gCurrent_net_game->no_races_yet = 0; + SignalToStartRace2(-1); } // IDA: void __cdecl SetUpNetCarPositions() @@ -120,7 +190,62 @@ void SetUpNetCarPositions(void) { int grid_index; int racer_count; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + DisableNetService(); + if (!gInitialised_grid) { + for (i = 0; i < gNumber_of_net_players; i++) { + gNet_players[i].grid_position_set = 0; + gNet_players[i].last_waste_message = 0; + gNet_players[i].wasteage_attributed = 0; + } + } + for (i = 0; i < gNumber_of_net_players; i++) { + gCurrent_race.opponent_list[i].index = -1; + gCurrent_race.opponent_list[i].ranking = IRandomBetween(0, 99); + gCurrent_race.opponent_list[i].car_spec = gNet_players[i].car; + gCurrent_race.opponent_list[i].net_player_index = i; + gNet_players[i].opponent_list_index = i; + } + if (!gInitialised_grid && gCurrent_net_game->options.grid_start) { + qsort(gCurrent_race.opponent_list, gNumber_of_net_players, sizeof(tOpp_spec), SortGridFunction); + } + gCurrent_race.number_of_racers = 0; + for (i = 0; i < gNumber_of_net_players; i++) { + gNet_players[gCurrent_race.opponent_list[i].net_player_index].opponent_list_index = i; + } + for (i = 0; i < gNumber_of_net_players; i++) { + if ((gCurrent_race.opponent_list[i].car_spec->driver == eDriver_oppo && !gInitialised_grid) + || (gCurrent_race.opponent_list[i].car_spec->driver >= eDriver_net_human && !gNet_players[gCurrent_race.opponent_list[i].net_player_index].grid_position_set)) { + grid_index = -1; + racer_count = 0; + while (racer_count < 6 && grid_index < 0) { + grid_index = racer_count; + for (k = 0; k < gNumber_of_net_players; k++) { + if (k != i + && gNet_players[gCurrent_race.opponent_list[k].net_player_index].grid_position_set + && gNet_players[gCurrent_race.opponent_list[k].net_player_index].grid_index == racer_count) { + grid_index = -1; + break; + } + } + racer_count++; + } + if (grid_index < 0) { + FatalError(kFatalError_NetworkCodeSelfCheck); + } + SetInitialPosition(&gCurrent_race, i, grid_index); + gNet_players[gCurrent_race.opponent_list[i].net_player_index].grid_index = grid_index; + if (gInitialised_grid) { + InitialiseCar2(gCurrent_race.opponent_list[i].car_spec, 0); + } else { + gCurrent_race.number_of_racers = i + 1; + } + gNet_players[gCurrent_race.opponent_list[i].net_player_index].grid_position_set = 1; + } + } + gCurrent_race.number_of_racers = gNumber_of_net_players; + gInitialised_grid = 1; + ReenableNetService(); } // IDA: void __usercall ReinitialiseCar(tCar_spec *pCar@) @@ -185,7 +310,56 @@ void DoNetworkHeadups(int pCredits) { static tU32 last_flash; static int flash_state; LOG_TRACE("(%d)", pCredits); - STUB_ONCE(); + + if (gNot_shown_race_type_headup) { + gNot_shown_race_type_headup = 0; + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(59 + gCurrent_net_game->type)); + } + if (gTime_for_punishment && gTime_for_punishment <= PDGetTotalTime()) { + gTime_for_punishment = 0; + switch (gCurrent_net_game->type) { + case eNet_game_type_carnage: + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(219)); + break; + case eNet_game_type_checkpoint: + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(220)); + break; + case eNet_game_type_sudden_death: + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(221)); + break; + case eNet_game_type_foxy: + NewTextHeadupSlot(4, 0, 2000, -4, GetMiscString(222)); + break; + default: + break; + } + } + if (gNet_mode == eNet_mode_none || gNet_recovery_cost[gCurrent_net_game->type] <= gProgram_state.credits_earned - gProgram_state.credits_lost || Flash(200, &last_flash, &flash_state)) { + sprintf(s, "\xf8%d\xfa %s", pCredits, GetMiscString(94)); + ChangeHeadupText(gNet_cash_headup, s); + } else { + ChangeHeadupText(gNet_cash_headup, ""); + } + switch (gCurrent_net_game->type) { + case eNet_game_type_carnage: + sprintf(s, "%s \xf8%d\xfa", GetMiscString(180), gPed_target); + break; + case eNet_game_type_car_crusher: + sprintf(s, "%s \xf8%d\xfa", GetMiscString(181), gCurrent_net_game->options.race_end_target); + break; + case eNet_game_type_foxy: + TimerString(gCurrent_net_game->options.race_end_target, s2, 1, 1); + sprintf(s, "%s \xf8%s\xfa", GetMiscString(182), s2); + break; + case eNet_game_type_tag: + TimerString(gCurrent_net_game->options.race_end_target, s2, 1, 1); + sprintf(s, "%s \xf8%s\xfa", GetMiscString(183), s2); + break; + default: + s[0] = '\0'; + break; + } + ChangeHeadupText(gNet_ped_headup, s); } // IDA: int __usercall SortNetHeadAscending@(void *pFirst_one@, void *pSecond_one@) @@ -234,13 +408,29 @@ void DoNetScores(void) { // IDA: void __cdecl InitNetHeadups() void InitNetHeadups(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gIcons_pix = LoadPixelmap("CARICONS.PIX"); + if (gIcons_pix != NULL) { + BrMapAdd(gIcons_pix); + } + gDigits_pix = LoadPixelmap("HDIGITS.PIX"); + if (gDigits_pix != NULL) { + BrMapAdd(gDigits_pix); + } } // IDA: void __cdecl DisposeNetHeadups() void DisposeNetHeadups(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gIcons_pix != NULL) { + BrMapRemove(gIcons_pix); + BrPixelmapFree(gIcons_pix); + } + if (gDigits_pix != NULL) { + BrMapRemove(gDigits_pix); + BrPixelmapFree(gDigits_pix); + } } // IDA: void __cdecl EverybodysLost() @@ -323,13 +513,26 @@ void SendPlayerScores(void) { tNet_contents* the_contents; int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + the_contents = NetGetBroadcastContents(NETMSGID_SCORES, 0); + if (gCurrent_net_game->type == eNet_game_type_carnage) { + the_contents->data.scores.general_score = gPed_target; + } else if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) { + the_contents->data.scores.general_score = gNet_players[gIt_or_fox].ID; + } + for (i = 0; i < gNumber_of_net_players; i++) { + the_contents->data.scores.scores[i] = gNet_players[i].score; + } } // IDA: void __cdecl DoNetGameManagement() void DoNetGameManagement(void) { LOG_TRACE("()"); - STUB_ONCE(); + + if (gNet_mode == eNet_mode_host) { + CalcPlayerScores(); + SendPlayerScores(); + } } // IDA: void __usercall InitialisePlayerScore(tNet_game_player_info *pPlayer@) @@ -442,14 +645,24 @@ void UseGeneralScore(int pScore) { // IDA: void __usercall NetSendEnvironmentChanges(tNet_game_player_info *pPlayer@) void NetSendEnvironmentChanges(tNet_game_player_info* pPlayer) { LOG_TRACE("(%p)", pPlayer); - NOT_IMPLEMENTED(); + + SendAllPedestrianPositions(pPlayer->ID); + SendAllNonCarPositions(); } // IDA: void __cdecl UpdateEnvironments() void UpdateEnvironments(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + for (i = 1; i < gNumber_of_net_players; i++) { + if (!gNet_players[i].race_stuff_initialised) { + NetSendEnvironmentChanges(&gNet_players[i]); + gNet_players[i].race_stuff_initialised = 1; + } + NetSendMessageStacks(); + SendGameplay(gNet_players[i].ID, eNet_gameplay_go_for_it, 0, 0, 0, 0); + } } // IDA: void __usercall ReceivedGameplay(tNet_contents *pContents@, tNet_message *pMessage@, tU32 pReceive_time@) @@ -467,7 +680,14 @@ void ReceivedGameplay(tNet_contents* pContents, tNet_message* pMessage, tU32 pRe void SendGameplay(tPlayer_ID pPlayer, 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, %d)", pPlayer, pMess, pParam_1, pParam_2, pParam_3, pParam_4); - NOT_IMPLEMENTED(); + + 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; + NetGuaranteedSendMessageToPlayer(gCurrent_net_game, the_message, pPlayer, 0); } // IDA: void __usercall SendGameplayToAllPlayers(tNet_gameplay_mess pMess@, int pParam_1@, int pParam_2@, int pParam_3@, int pParam_4) @@ -475,7 +695,13 @@ void SendGameplayToAllPlayers(tNet_gameplay_mess pMess, int pParam_1, int pParam tNet_message* the_message; LOG_TRACE("(%d, %d, %d, %d, %d)", pMess, pParam_1, pParam_2, pParam_3, pParam_4); - STUB_ONCE(); + 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; + NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL); } // IDA: void __usercall SendGameplayToHost(tNet_gameplay_mess pMess@, int pParam_1@, int pParam_2@, int pParam_3@, int pParam_4) diff --git a/src/DETHRACE/common/network.c b/src/DETHRACE/common/network.c index 6f24022a..80421367 100644 --- a/src/DETHRACE/common/network.c +++ b/src/DETHRACE/common/network.c @@ -1,33 +1,51 @@ #include "network.h" #include "brender/brender.h" +#include "car.h" #include "controls.h" #include "displays.h" +#include "errors.h" #include "globvars.h" #include "globvrpb.h" #include "graphics.h" +#include "harness/hooks.h" #include "harness/trace.h" +#include "loading.h" #include "netgame.h" +#include "newgame.h" +#include "oil.h" +#include "opponent.h" #include "pd/net.h" #include "pd/sys.h" +#include "pedestrn.h" +#include "piping.h" +#include "powerup.h" +#include "replay.h" +#include "spark.h" +#include "structur.h" #include "utility.h" +#include "world.h" #include tU32 gMess_max_flags; tU32 gMess_mid_flags; tU32 gMess_min_flags; tU32 gGuarantee_number; -int gNet_service_disable; -int gIn_net_service; -int gPlayer_list_batch_number; -int gOnly_receive_guarantee_replies; +int gNet_service_disable = 0; +int gIn_net_service = 0; +int gPlayer_list_batch_number = 0; +int gOnly_receive_guarantee_replies = 0; void* gMessage_to_free; tNet_message* gBroadcast_stack; tNet_message* gTo_host_stack; -tU32 gLast_flush_message; -int gRace_only_flags[33]; +tU32 gLast_flush_message = 0; +int gRace_only_flags[33] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, + 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, + 0 +}; int gJoin_list_mode; tNet_game_player_info gNew_net_players[6]; -tGuaranteed_message gGuarantee_list[150]; +tGuaranteed_message gGuarantee_list[100]; // DOS debug symbols has this as [150] tMid_message* gMid_messages; tU32 gLast_player_list_received; tMin_message* gMin_messages; @@ -49,11 +67,43 @@ int gBastard_has_answered; int gTime_for_next_one; int gReceived_game_scores; +#define MIN_MESSAGES_CAPACITY 20 +#define MID_MESSAGES_CAPACITY 10 +#define MAX_MESSAGES_CAPACITY 20 + +#define MAX_MESAGE_STACK_SIZE 512 + // IDA: int __cdecl NetInitialise() int NetInitialise(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + SwitchToRealResolution(); + InitAbuseomatic(); + gNet_service_disable = 0; + gIn_net_service = 0; + gMessage_header_size = PDNetGetHeaderSize(); + gOnly_receive_guarantee_replies = 0; + gMin_messages = BrMemAllocate(MIN_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMin_message)), kMem_net_min_messages); + gMid_messages = BrMemAllocate(MID_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMid_message)), kMem_net_mid_messages); + gMax_messages = BrMemAllocate(MAX_MESSAGES_CAPACITY * (gMessage_header_size + sizeof(tMax_message)), kMem_net_max_messages); + for (i = 0; i < MIN_MESSAGES_CAPACITY; i++) { + ((tNet_message*)&gMin_messages[i])->contents.header.type = NETMSGID_NONE; + } + for (i = 0; i < MID_MESSAGES_CAPACITY; i++) { + ((tNet_message*)&gMid_messages[i])->contents.header.type = NETMSGID_NONE; + } + for (i = 0; i < MAX_MESSAGES_CAPACITY; i++) { + ((tNet_message*)&gMax_messages[i])->contents.header.type = NETMSGID_NONE; + } + gNet_initialised = PDNetInitialise() == 0; + if (gNet_initialised) { + InitNetHeadups(); + } + GenerateItFoxShadeTable(); + gDont_allow_joiners = 0; + SwitchToLoresMode(); + return !gNet_initialised; } // IDA: int __cdecl NetShutdown() @@ -117,7 +167,11 @@ void HaltNetServiceReentrancy(void) { void NetSendHeadupToAllPlayers(char* pMessage) { tNet_contents* the_contents; LOG_TRACE("(\"%s\")", pMessage); - NOT_IMPLEMENTED(); + + if (gNet_mode) { + the_contents = NetGetBroadcastContents(NETMSGID_HEADUP, 0); + strcpy(the_contents->data.headup.text, pMessage); + } } // IDA: void __usercall NetSendHeadupToEverybody(char *pMessage@) @@ -138,63 +192,132 @@ void NetSendHeadupToPlayer(char* pMessage, tPlayer_ID pPlayer) { void InitialisePlayerStati(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + for (i = 0; i < COUNT_OF(gNet_players); i++) { + gNet_players[i].last_heard_from_him = PDGetTotalTime(); + gNet_players[i].player_status = ePlayer_status_loading; + } } // IDA: void __cdecl LeaveTempGame() void LeaveTempGame(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gCurrent_join_poll_game != NULL) { + NetLeaveGameLowLevel(gCurrent_join_poll_game); + } + gTime_for_next_one = 1; + gCurrent_join_poll_game = NULL; } // IDA: void __cdecl DisposeCurrentJoinPollGame() void DisposeCurrentJoinPollGame(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gCurrent_join_poll_game != NULL) { + NetDisposeGameDetails(gCurrent_join_poll_game); + gCurrent_join_poll_game = NULL; + } } // IDA: void __cdecl DoNextJoinPoll() void DoNextJoinPoll(void) { tNet_message* the_message; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gTime_for_next_one) { + gCurrent_join_poll_game = NetAllocatePIDGameDetails(); + if (gCurrent_join_poll_game != NULL) { + if (PDNetGetNextJoinGame(gCurrent_join_poll_game, gJoin_poll_index)) { + if (NetJoinGameLowLevel(gCurrent_join_poll_game, "!TEMP!")) { + DisposeCurrentJoinPollGame(); + } else { + gTime_for_next_one = 0; + the_message = NetBuildMessage(NETMSGID_SENDMEDETAILS, 0); + NetSendMessageToAddress(gCurrent_join_poll_game, the_message, gCurrent_join_poll_game); + gBastard_has_answered = 0; + gAsk_time = PDGetTotalTime(); + } + gJoin_poll_index++; + } else { + gJoin_poll_index = 0; + if (gCurrent_join_poll_game != NULL) { + DisposeCurrentJoinPollGame(); + } + } + } + } else { + if (gBastard_has_answered) { + gAdd_proc(gCurrent_join_poll_game); + LeaveTempGame(); + } else { + if (PDGetTotalTime() - gAsk_time > 10000) { + LeaveTempGame(); + DisposeCurrentJoinPollGame(); + } + } + } } // IDA: void __usercall NetStartProducingJoinList(void (*pAdd_proc)(tNet_game_details*)@) void NetStartProducingJoinList(void (*pAdd_proc)(tNet_game_details*)) { LOG_TRACE("(%p)", pAdd_proc); - NOT_IMPLEMENTED(); + + gAdd_proc = pAdd_proc; + gJoin_list_mode = 1; + gBastard_has_answered = 0; + gTime_for_next_one = 1; + gJoin_poll_index = 0; + gCurrent_join_poll_game = NULL; + PDNetStartProducingJoinList(); } // IDA: void __cdecl NetEndJoinList() void NetEndJoinList(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gJoin_list_mode = 0; + DisposeCurrentJoinPollGame(); + LeaveTempGame(); + PDNetEndJoinList(); } // IDA: void __usercall NetDisposePIDGameInfo(tNet_game_details *pDetails@) void NetDisposePIDGameInfo(tNet_game_details* pDetails) { LOG_TRACE("(%p)", pDetails); - NOT_IMPLEMENTED(); + + if (pDetails != NULL) { + BrMemFree(pDetails); + } } // IDA: void __usercall NetDisposeGameDetails(tNet_game_details *pDetails@) void NetDisposeGameDetails(tNet_game_details* pDetails) { LOG_TRACE("(%p)", pDetails); - NOT_IMPLEMENTED(); + + // LOG_WARN("NetDisposeGameDetails(%p)", pDetails); + if (pDetails != NULL) { + NetDisposePIDGameInfo(pDetails); + } } // IDA: tNet_game_details* __cdecl NetAllocatePIDGameDetails() tNet_game_details* NetAllocatePIDGameDetails(void) { tNet_game_details* game; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + return BrMemAllocate(sizeof(tNet_game_details), kMem_net_pid_details); } // IDA: void __usercall NetLeaveGameLowLevel(tNet_game_details *pDetails@) void NetLeaveGameLowLevel(tNet_game_details* pDetails) { LOG_TRACE("(%p)", pDetails); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_host) { + PDNetHostFinishGame(gCurrent_net_game); + } else { + PDNetLeaveGame(pDetails); + } } // IDA: void __usercall NetLeaveGame(tNet_game_details *pNet_game@) @@ -205,13 +328,51 @@ void NetLeaveGame(tNet_game_details* pNet_game) { int i; int must_revert_reentrancy; LOG_TRACE("(%p)", pNet_game); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none) { + return; + } + gOnly_receive_guarantee_replies = 1; + if (gNet_mode == eNet_mode_host) { + gDont_allow_joiners = 1; + the_message = NetBuildMessage(NETMSGID_HOSTICIDE, 0); + must_revert_reentrancy = PermitNetServiceReentrancy(); + NetGuaranteedSendMessageToAllPlayers(pNet_game, the_message, NULL); + if (must_revert_reentrancy) { + HaltNetServiceReentrancy(); + } + } else if (!gHost_died) { + the_message = NetBuildMessage(NETMSGID_LEAVE, 0); + NetGuaranteedSendMessageToHost(pNet_game, the_message, NULL); + strcpy(s, gProgram_state.player_name[0]); + strcat(s, " "); + strcat(s, GetMiscString(74)); + NetSendHeadupToAllPlayers(s); + } + for (i = 0; i < gNumber_of_net_players; i++) { + DisposeCarN(i); + } + ClearOutStorageSpace(&gOur_car_storage_space); + ClearOutStorageSpace(&gNet_cars_storage_space); + must_revert_reentrancy = PermitNetServiceReentrancy(); + NetSendMessageStacks(); + NetWaitForGuaranteeReplies(); + NetLeaveGameLowLevel(gCurrent_net_game); + if (must_revert_reentrancy) { + HaltNetServiceReentrancy(); + } + gCurrent_net_game = NULL; + gNet_mode = eNet_mode_none; + gNumber_of_net_players = 0; + gProgram_state.prog_status = eProg_idling; + gOnly_receive_guarantee_replies = 0; } // IDA: void __usercall NetSetPlayerSystemInfo(tNet_game_player_info *pPlayer@, void *pSender_address@) void NetSetPlayerSystemInfo(tNet_game_player_info* pPlayer, void* pSender_address) { LOG_TRACE("(%p, %p)", pPlayer, pSender_address); - NOT_IMPLEMENTED(); + + PDNetSetPlayerSystemInfo(pPlayer, pSender_address); } // IDA: void __usercall NetDisposePlayer(tNet_game_player_info *pPlayer@) @@ -223,14 +384,47 @@ void NetDisposePlayer(tNet_game_player_info* pPlayer) { // IDA: void __usercall FillInThisPlayer(tNet_game_details *pGame@, tNet_game_player_info *pPlayer@, int pCar_index@, int pHost@) void FillInThisPlayer(tNet_game_details* pGame, tNet_game_player_info* pPlayer, int pCar_index, int pHost) { LOG_TRACE("(%p, %p, %d, %d)", pGame, pPlayer, pCar_index, pHost); - NOT_IMPLEMENTED(); + + pPlayer->host = pHost; + pPlayer->ID = NetExtractPlayerID(pGame); + strcpy(pPlayer->player_name, gProgram_state.player_name[0]); + pPlayer->this_players_time_stamp = PDGetTotalTime(); + pPlayer->car_index = pCar_index; + pPlayer->reposition_time = 0; + pPlayer->last_waste_message = 0; + pPlayer->wasteage_attributed = 0; + pPlayer->name_not_clipped = 1; + pPlayer->played = 0; + pPlayer->won = 0; + pPlayer->games_score = 0; + pPlayer->race_stuff_initialised = 0; + if (pGame->options.random_car_choice && (pGame->options.car_choice == eNet_car_all || pGame->options.car_choice == eNet_car_both)) { + pPlayer->next_car_index = -1; + } + InitialisePlayerScore(pPlayer); } // IDA: void __usercall LoadCarN(int pIndex@, tNet_game_player_info *pPlayer@) void LoadCarN(int pIndex, tNet_game_player_info* pPlayer) { int switched_res; LOG_TRACE("(%d, %p)", pIndex, pPlayer); - NOT_IMPLEMENTED(); + + pPlayer->car = BrMemAllocate(sizeof(tCar_spec), kMem_net_car_spec); + switched_res = SwitchToRealResolution(); + LoadCar(gOpponents[pPlayer->car_index].car_file_name, + eDriver_net_human, + pPlayer->car, + pPlayer->car_index, + pPlayer->player_name, + &gNet_cars_storage_space); + if (switched_res) { + SwitchToLoresMode(); + } + InitialiseCar(pPlayer->car); + if (pPlayer->player_status < ePlayer_status_racing) { + pPlayer->car->disabled = 1; + } + SetCarStorageTexturingLevel(&gNet_cars_storage_space, GetCarTexturingLevel(), eCTL_full); } // IDA: void __usercall DisposeCarN(int pIndex@) @@ -238,7 +432,29 @@ void DisposeCarN(int pIndex) { int i; int j; LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + for (i = 0; i < gCurrent_race.number_of_racers; i++) { + if (gCurrent_race.opponent_list[i].car_spec == gNet_players[pIndex].car) { + gCurrent_race.number_of_racers--; + for (j = i; j < gCurrent_race.number_of_racers; j++) { + gCurrent_race.opponent_list[j].index = gCurrent_race.opponent_list[j + 1].index; + gCurrent_race.opponent_list[j].ranking = gCurrent_race.opponent_list[j + 1].ranking; + gCurrent_race.opponent_list[j].net_player_index = gCurrent_race.opponent_list[j + 1].net_player_index; + gCurrent_race.opponent_list[j].car_spec = gCurrent_race.opponent_list[j + 1].car_spec; + } + } + } + if (gProgram_state.racing) { + DisposeKevStuffCar(gNet_players[pIndex].car); + } + DisposeCar(gNet_players[pIndex].car, gNet_players[pIndex].car_index); + if (gThis_net_player_index != pIndex) { + BrMemFree(gNet_players[pIndex].car); + } + if (gAction_replay_mode) { + ToggleReplay(); + } + ResetPiping(); } // IDA: void __usercall PlayerHasLeft(int pIndex@) @@ -257,7 +473,99 @@ void NetPlayersChanged(int pNew_count, tNet_game_player_info* pNew_players) { int player_still_there; tPlayer_ID old_fox_it; LOG_TRACE("(%d, %p)", pNew_count, pNew_players); - NOT_IMPLEMENTED(); + + 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; + } + for (i = 0; i < pNew_count; i++) { + new_player = 1; + for (j = 0; j < gNumber_of_net_players; j++) { + if (pNew_players[i].ID == gNet_players[j].ID) { + new_player = 0; + pNew_players[i].last_waste_message = gNet_players[j].last_waste_message; + pNew_players[i].player_status = gNet_players[j].player_status; + pNew_players[i].car_index = gNet_players[j].car_index; + pNew_players[i].score = gNet_players[j].score; + pNew_players[i].credits = gNet_players[j].credits; + pNew_players[i].wasted = gNet_players[j].wasted; + pNew_players[i].wasteage_attributed = gNet_players[j].wasteage_attributed; + pNew_players[i].next_car_index = gNet_players[j].next_car_index; + pNew_players[i].car = gNet_players[j].car; + break; + } + } + if (new_player) { + if (pNew_players[i].ID == gLocal_net_ID) { + switched_res = SwitchToRealResolution(); + LoadCar(gOpponents[pNew_players[i].car_index].car_file_name, + eDriver_local_human, + &gProgram_state.current_car, + pNew_players[i].car_index, + pNew_players[i].player_name, + &gNet_cars_storage_space); + if (switched_res) { + SwitchToLoresMode(); + } + pNew_players[i].car = &gProgram_state.current_car; + if (pNew_players[i].player_status < ePlayer_status_racing) { + pNew_players[i].car->disabled = 1; + } + SetCarStorageTexturingLevel(&gNet_cars_storage_space, GetCarTexturingLevel(), eCTL_full); + } else { + LoadCarN(i, &pNew_players[i]); + } + gCurrent_race.opponent_list[i].index = -1; + gCurrent_race.opponent_list[i].ranking = IRandomBetween(0, 99); + gCurrent_race.opponent_list[i].car_spec = pNew_players[i].car; + gCurrent_race.opponent_list[i].net_player_index = i; + pNew_players[i].opponent_list_index = i; + gCurrent_race.number_of_racers = pNew_count; + } + } + for (i = 0; i < gNumber_of_net_players; i++) { + player_still_there = 0; + for (j = 0; j < pNew_count; j++) { + if (pNew_players[j].ID == gNet_players[i].ID) { + player_still_there = 1; + break; + } + } + if (!player_still_there) { + for (j = 0; j < gNumber_of_net_players; j++) { + if (gCurrent_race.opponent_list[j].net_player_index == i) { + memmove(&gCurrent_race.opponent_list[j], &gCurrent_race.opponent_list[j + 1], (gNumber_of_net_players - j - 1) * sizeof(tOpp_spec)); + for (k = 0; k < pNew_count; k++) { + if (j < pNew_players[k].opponent_list_index) { + pNew_players[k].opponent_list_index--; + } + } + break; + } + } + PlayerHasLeft(i); + DisposeCarN(i); + if (gInitialised_grid) { + for (i = 0; i < pNew_count; i++) { + gCurrent_race.opponent_list[pNew_players[i].opponent_list_index].net_player_index = i; + } + } + } + } + gNumber_of_net_players = pNew_count; + memcpy(gNet_players, pNew_players, pNew_count * sizeof(tNet_game_player_info)); + for (i = 0; i < gNumber_of_net_players; i++) { + gNet_players[i].last_heard_from_him = PDGetTotalTime(); + } + ForceRebuildActiveCarList(); + if (gCurrent_net_game->type == eNet_game_type_tag || gCurrent_net_game->type == eNet_game_type_foxy) { + gIt_or_fox = -1; + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == old_fox_it) { + gIt_or_fox = i; + break; + } + } + } } // IDA: tNet_game_details* __usercall NetHostGame@(tNet_game_type pGame_type@, tNet_game_options *pOptions@, int pStart_rank@, char *pHost_name@, int pCar_index) @@ -266,7 +574,39 @@ tNet_game_details* NetHostGame(tNet_game_type pGame_type, tNet_game_options* pOp void* host_address; tNet_game_player_info me; LOG_TRACE("(%d, %p, %d, \"%s\", %d)", pGame_type, pOptions, pStart_rank, pHost_name, pCar_index); - NOT_IMPLEMENTED(); + + game = NetAllocatePIDGameDetails(); + if (pHost_name[0] == '\0') { + sprintf(pHost_name, "%s", "HOST"); + } + DisableNetService(); + if (PDNetHostGame(game, pHost_name, &host_address) == 0) { + NetDisposeGameDetails(game); + return NULL; + } + gCurrent_net_game = game; + gNeed_to_send_start_race = 0; + strcpy(game->host_name, pHost_name); + game->host_ID = NetExtractPlayerID(game); + game->num_players = 1; + memcpy(&game->options, pOptions, sizeof(tNet_game_options)); + game->status.stage = eNet_game_starting; + game->type = pGame_type; + game->start_race = pStart_rank; + game->no_races_yet = 1; + gReceiving_new_players = 0; + gHost_died = 0; + gNumber_of_net_players = 0; + gThis_net_player_index = 0; + gLocal_net_ID = game->host_ID; + FillInThisPlayer(game, &me, pCar_index, 1); + gNet_players[0].race_stuff_initialised = 1; + NetSetPlayerSystemInfo(&me, host_address); + NetPlayersChanged(1, &me); + InitialisePlayerStati(); + gNet_mode = eNet_mode_host; + gDont_allow_joiners = 0; + return game; } // IDA: int __usercall NetInitClient@(tNet_game_details *pDetails@) @@ -278,7 +618,8 @@ int NetInitClient(tNet_game_details* pDetails) { // IDA: int __usercall NetJoinGameLowLevel@(tNet_game_details *pDetails@, char *pPlayer_name@) int NetJoinGameLowLevel(tNet_game_details* pDetails, char* pPlayer_name) { LOG_TRACE("(%p, \"%s\")", pDetails, pPlayer_name); - NOT_IMPLEMENTED(); + + return PDNetJoinGame(pDetails, pPlayer_name); } // IDA: int __usercall NetJoinGame@(tNet_game_details *pDetails@, char *pPlayer_name@, int pCar_index@) @@ -287,14 +628,63 @@ int NetJoinGame(tNet_game_details* pDetails, char* pPlayer_name, int pCar_index) tNet_message* the_message; tU32 start_time; LOG_TRACE("(%p, \"%s\", %d)", pDetails, pPlayer_name, pCar_index); - NOT_IMPLEMENTED(); + + result = NetJoinGameLowLevel(pDetails, pPlayer_name); + if (result != 0) { + return result; + } + DisableNetService(); + gReceiving_new_players = 0; + gNet_mode = eNet_mode_client; + gCurrent_net_game = pDetails; + gLocal_net_ID = NetExtractPlayerID(pDetails); + gNumber_of_net_players = 0; + gLast_player_list_received = 0; + gJoin_request_denied = 0; + gCar_was_taken = 0; + gHost_died = 0; + the_message = NetBuildMessage(NETMSGID_JOIN, 0); + FillInThisPlayer(pDetails, &the_message->contents.data.join.player_info, pCar_index, 0); + ReenableNetService(); + NetGuaranteedSendMessageToAddress(pDetails, the_message, pDetails, NULL); + start_time = PDGetTotalTime(); + while (1) { + NetService(0); + if (gNumber_of_net_players != 0) { + break; + } + if (PDGetTotalTime() - start_time >= 30000 || gJoin_request_denied || gHost_died) { + break; + } + } + DisableNetService(); + InitialisePlayerStati(); + if (gNumber_of_net_players == 0) { + ReenableNetService(); + if (gJoin_request_denied && gCar_was_taken) { + result = -4; + } else { + gNet_mode = eNet_mode_none; +#if !defined(DETHRACE_FIX_BUGS) + // Avoid double free + NetDisposeGameDetails(gCurrent_net_game); +#endif + gCurrent_net_game = NULL; + if (gJoin_request_denied) { + result = -2; + } else { + result = -1; + } + } + } + return result; } // IDA: void __usercall NetObtainSystemUserName(char *pName@, int pMax_length@) void NetObtainSystemUserName(char* pName, int pMax_length) { PDNetObtainSystemUserName(pName, pMax_length); - pName[9] = 0; + pName[9] = '\0'; } // IDA: tU32 __usercall NetExtractGameID@(tNet_game_details *pDetails@) @@ -314,7 +704,14 @@ tPlayer_ID NetExtractPlayerID(tNet_game_details* pDetails) { // IDA: int __usercall NetSendMessageToAddress@(tNet_game_details *pDetails@, tNet_message *pMessage@, void *pAddress@) int NetSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress) { LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pAddress); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none && !gJoin_list_mode) { + return -3; + } + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + GetCheckSum(pMessage); + return PDNetSendMessageToAddress(pDetails, pMessage, pAddress); } // IDA: int __usercall NetSendMessageToPlayer@(tNet_game_details *pDetails@, tNet_message *pMessage@, tPlayer_ID pPlayer@) @@ -339,7 +736,11 @@ int NetReplyToMessage(tNet_game_details* pDetails, tNet_message* pIncoming_messa // IDA: int __usercall NetSendMessageToAllPlayers@(tNet_game_details *pDetails@, tNet_message *pMessage@) int NetSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage) { LOG_TRACE("(%p, %p)", pDetails, pMessage); - NOT_IMPLEMENTED(); + + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + GetCheckSum(pMessage); + return PDNetSendMessageToAllPlayers(pDetails, pMessage); } // IDA: tU32 __usercall NetGetContentsSize@(tNet_message_type pType@, tS32 pSize_decider@) @@ -348,10 +749,86 @@ tU32 NetGetContentsSize(tNet_message_type pType, tS32 pSize_decider) { LOG_TRACE("(%d, %d)", pType, pSize_decider); switch (pType) { - case ENET_MESSAGE_HEADUP: - return 0x82; + case NETMSGID_SENDMEDETAILS: + return sizeof(tNet_message_send_me_details); + case NETMSGID_DETAILS: + return sizeof(tNet_message_my_details); + case NETMSGID_JOIN: + return sizeof(tNet_message_join); + case NETMSGID_NEWPLAYERLIST: + return sizeof(tNet_message_new_player_list); + case NETMSGID_GUARANTEEREPLY: + return sizeof(tNet_message_guarantee_reply); + case NETMSGID_CARDETAILSREQ: + return sizeof(tNet_message_car_details_req); + case NETMSGID_CARDETAILS: + return sizeof(tNet_message_car_details); + case NETMSGID_LEAVE: + return sizeof(tNet_message_leave); + case NETMSGID_HOSTICIDE: + return sizeof(tNet_message_host_pissing_off); + case NETMSGID_RACEOVER: + return sizeof(tNet_message_race_over); + case NETMSGID_STATUSREPORT: + return sizeof(tNet_message_status_report); + case NETMSGID_STARTRACE: + return sizeof(tNet_message_start_race); + case NETMSGID_HEADUP: + return sizeof(tNet_message_headup); + case NETMSGID_HOSTQUERY: + return sizeof(tNet_message_host_query); + case NETMSGID_HOSTREPLY: + return sizeof(tNet_message_host_reply); + case NETMSGID_MECHANICS: + if (pSize_decider == 0) { + return offsetof(tNet_message_mechanics_info, wheel_dam_offset); + } else { + return sizeof(tNet_message_mechanics_info); + } + case NETMSGID_NONCAR_INFO: + return sizeof(tNet_message_non_car_info); + case NETMSGID_TIMESYNC: + return sizeof(tNet_message_time_sync); + case NETMSGID_CONFIRM: + return sizeof(tNet_message_players_confirm); + case NETMSGID_DISABLECAR: + return sizeof(tNet_message_disable_car); + case NETMSGID_ENABLECAR: + return sizeof(tNet_message_enable_car); + case NETMSGID_POWERUP: + return sizeof(tNet_message_powerup); + case NETMSGID_RECOVER: + return sizeof(tNet_message_recover); + case NETMSGID_SCORES: + return sizeof(tNet_message_scores); + case NETMSGID_WASTED: + return sizeof(tNet_message_wasted); + case NETMSGID_PEDESTRIAN: + switch (pSize_decider) { + case 0: + return offsetof(tNet_message_pedestrian, to_pos); + case 1: + return offsetof(tNet_message_pedestrian, offset); + case 2: + return sizeof(tNet_message_pedestrian); default: TELL_ME_IF_WE_PASS_THIS_WAY(); + } + case NETMSGID_GAMEPLAY: + return sizeof(tNet_message_gameplay); + case NETMSGID_NONCARPOSITION: + return sizeof(tNet_message_non_car_position); + case NETMSGID_COPINFO: + return sizeof(tNet_message_cop_info); + case NETMSGID_GAMESCORES: + return sizeof(tNet_message_game_scores); + case NETMSGID_OILSPILL: + return sizeof(tNet_message_oil_spill); + case NETMSGID_CRUSHPOINT: + return sizeof(tNet_message_crush_point); + default: + TELL_ME_IF_WE_PASS_THIS_WAY(); + return 4; } } @@ -359,8 +836,7 @@ tU32 NetGetContentsSize(tNet_message_type pType, tS32 pSize_decider) { tU32 NetGetMessageSize(tNet_message_type pType, tS32 pSize_decider) { LOG_TRACE("(%d, %d)", pType, pSize_decider); - return NetGetContentsSize(pType, pSize_decider) + 28; - + return NetGetContentsSize(pType, pSize_decider) + sizeof(tNet_message) - sizeof(tNet_contents); } // IDA: tS32 __usercall NetCalcSizeDecider@(tNet_contents *pContents@) @@ -399,13 +875,38 @@ tNet_contents* NetGetBroadcastContents(tNet_message_type pType, tS32 pSize_decid tU32 the_size; tNet_contents* contents; LOG_TRACE("(%d, %d)", pType, pSize_decider); - NOT_IMPLEMENTED(); + + the_size = NetGetContentsSize(pType, pSize_decider); + if (gBroadcast_stack && the_size + gBroadcast_stack->overall_size > MAX_MESAGE_STACK_SIZE) { + NetSendMessageToAllPlayers(gCurrent_net_game, gBroadcast_stack); + gBroadcast_stack = NULL; + } + if (gBroadcast_stack == NULL) { + gBroadcast_stack = NetAllocateMessage(MAX_MESAGE_STACK_SIZE); + gBroadcast_stack->overall_size = offsetof(tNet_message, contents); + gBroadcast_stack->num_contents = 0; + } + contents = (tNet_contents*)((char*)gBroadcast_stack + gBroadcast_stack->overall_size); + gBroadcast_stack->overall_size += the_size; + contents->header.type = pType; + contents->header.contents_size = the_size; + gBroadcast_stack->num_contents++; + return contents; } // IDA: void __cdecl NetSendMessageStacks() void NetSendMessageStacks(void) { LOG_TRACE("()"); - STUB_ONCE(); + + gLast_flush_message = PDGetTotalTime(); + if (gBroadcast_stack != NULL) { + NetSendMessageToAllPlayers(gCurrent_net_game, gBroadcast_stack); + gBroadcast_stack = NULL; + } + if (gTo_host_stack != NULL) { + NetSendMessageToHost(gCurrent_net_game, gTo_host_stack); + gTo_host_stack = NULL; + } } // IDA: tNet_message* __usercall NetAllocateMessage@(int pSize@) @@ -419,39 +920,122 @@ tNet_message* NetAllocateMessage(int pSize) { tNet_message* message; int i; LOG_TRACE("(%d)", pSize); - NOT_IMPLEMENTED(); + + pointer = NULL; + if (pSize <= sizeof(tMin_message) - sizeof(void*)) { + for (i = 0; i < MIN_MESSAGES_CAPACITY; i++) { + if (((tNet_message*)&gMin_messages[rr_min])->contents.header.type == NETMSGID_NONE) { + pointer = &gMin_messages[rr_min]; + break; + } + rr_min++; + if (rr_min >= MIN_MESSAGES_CAPACITY) { + rr_min = 0; + } + } + } + if (pointer == NULL && pSize <= sizeof(tMid_message) - sizeof(void*)) { + for (i = 0; i < MID_MESSAGES_CAPACITY; i++) { + if (((tNet_message*)&gMid_messages[rr_mid])->contents.header.type == NETMSGID_NONE) { + pointer = &gMid_messages[rr_mid]; + break; + } + rr_mid++; + if (rr_mid >= MID_MESSAGES_CAPACITY) { + rr_mid = 0; + } + } + } + if (pointer == NULL && pSize <= sizeof(tMax_message) - sizeof(void*)) { + for (i = 0; i < MAX_MESSAGES_CAPACITY; i++) { + if (((tNet_message*)&gMax_messages[rr_max])->contents.header.type == NETMSGID_NONE) { + pointer = &gMax_messages[rr_max]; + break; + } + rr_max++; + if (rr_max >= MAX_MESSAGES_CAPACITY) { + rr_max = 0; + } + } + } + if (pointer == NULL) { + pointer = BrMemAllocate(gMessage_header_size + pSize + sizeof(void*), kMem_dynamic_message); + if (pointer != NULL) { + *(void**)pointer = NULL; + if (gMessage_to_free != NULL) { + for (last_message = gMessage_to_free; *(void**)last_message != NULL; last_message = *(void**)last_message) { + } + *(void**)last_message = pointer; + } else { + gMessage_to_free = pointer; + } + pointer = ((void**)pointer)[1]; + } + } + if (pointer == NULL) { + LOG_PANIC("null pointer!"); + message = NULL; + } else { + message = (tNet_message*)((tU8*)pointer + gMessage_header_size); + message->guarantee_number = 0; + message->version = 1; + message->magic_number = 0x763a5058; + } + return message; } // IDA: void __cdecl NetFreeExcessMemory() void NetFreeExcessMemory(void) { void* temp; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + while (gMessage_to_free != NULL && ((tNet_message*)((char*)gMessage_to_free + sizeof(void*)))->contents.header.type == NETMSGID_NONE) { + temp = *(void**)gMessage_to_free; + BrMemFree(gMessage_to_free); + gMessage_to_free = temp; + } } // IDA: int __usercall NetDisposeMessage@(tNet_game_details *pDetails@, tNet_message *pMessage@) int NetDisposeMessage(tNet_game_details* pDetails, tNet_message* pMessage) { LOG_TRACE("(%p, %p)", pDetails, pMessage); - NOT_IMPLEMENTED(); + + if (pMessage->guarantee_number != 0) { + return -1; + } + pMessage->contents.header.type = NETMSGID_NONE; + return 0; } // IDA: tNet_message* __usercall NetGetNextMessage@(tNet_game_details *pDetails@, void **pSender_address@) tNet_message* NetGetNextMessage(tNet_game_details* pDetails, void** pSender_address) { LOG_TRACE("(%p, %p)", pDetails, pSender_address); - NOT_IMPLEMENTED(); + + return PDNetGetNextMessage(pDetails, pSender_address); } // IDA: void __usercall ReceivedSendMeDetails(tNet_contents *pContents@, void *pSender_address@) void ReceivedSendMeDetails(tNet_contents* pContents, void* pSender_address) { tNet_message* message; LOG_TRACE("(%p, %p)", pContents, pSender_address); - NOT_IMPLEMENTED(); + + if (gDont_allow_joiners) { + return; + } + message = NetBuildMessage(NETMSGID_DETAILS, 0); + memcpy(&message->contents.data.details.details.host_name, gCurrent_net_game->host_name, sizeof(*gCurrent_net_game) - offsetof(tNet_game_details, host_name)); + NetSendMessageToAddress(gCurrent_net_game, message, pSender_address); } // IDA: void __usercall ReceivedDetails(tNet_contents *pContents@) void ReceivedDetails(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + if (gCurrent_join_poll_game == NULL) { + return; + } + gBastard_has_answered = 1; + memcpy(gCurrent_join_poll_game->host_name, &pContents->data.details.details.host_name, sizeof(*gCurrent_join_poll_game) - offsetof(tNet_game_details, host_name)); } // IDA: void __cdecl SendOutPlayerList() @@ -459,7 +1043,26 @@ void SendOutPlayerList(void) { tNet_message* message; int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gCurrent_net_game->num_players = gNumber_of_net_players; + for (i = 0; i < gNumber_of_net_players; i++) { + message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 1); + message->contents.data.player_list.number_of_players = gNumber_of_net_players; + message->contents.data.player_list.this_index = i; + message->contents.data.player_list.batch_number = gPlayer_list_batch_number; + memcpy(&message->contents.data.player_list.player, &gNet_players[i], sizeof(gNet_players[i])); + NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, message, 0); + } + gPlayer_list_batch_number++; + if (gInitialised_grid) { + SetUpNetCarPositions(); + if (gStart_race_sent) { + gNeed_to_send_start_race = 1; + for (i = 1; i < gNumber_of_net_players; i++) { + gNet_players[i].awaiting_confirmation = 1; + } + } + } } // IDA: void __usercall ReceivedJoin(tNet_contents *pContents@, void *pSender_address@) @@ -470,7 +1073,52 @@ void ReceivedJoin(tNet_contents* pContents, void* pSender_address) { tNet_message* message; tNet_game_player_info* new_players; LOG_TRACE("(%p, %p)", pContents, pSender_address); - NOT_IMPLEMENTED(); + + new_player_count = gNumber_of_net_players; + 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) { + message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 0); + // Send player count = 0 when race has already begun or is full + message->contents.data.player_list.number_of_players = 0; + NetSendMessageToAddress(gCurrent_net_game, message, pSender_address); + } else { + for (i = 0; i < new_player_count; i++) { + if (new_players[i].ID == pContents->data.join.player_info.ID) { + return; + } + } + slot_index = new_player_count; + new_player_count++; + if (pContents->data.join.player_info.car_index < 0) { + pContents->data.join.player_info.car_index = PickARandomCar(); + } else { + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].car_index == pContents->data.join.player_info.car_index) { + message = NetBuildMessage(NETMSGID_NEWPLAYERLIST, 0); + // Send player count = -1 when selected car is unavailable + message->contents.data.player_list.number_of_players = -1; + NetSendMessageToAddress(gCurrent_net_game, message, pSender_address); + return; + } + } + } + if (pContents->data.join.player_info.car_index >= 0) { + gCar_details[pContents->data.join.player_info.car_index].ownership = eCar_owner_someone; + } + memcpy(&new_players[slot_index], &pContents->data.join.player_info, sizeof(tNet_game_player_info)); + new_players[slot_index].player_status = ePlayer_status_loading; + new_players[slot_index].last_heard_from_him = PDGetTotalTime(); + new_players[slot_index].grid_position_set = 0; + if (new_players[slot_index].player_name[0] == '\0') { + sprintf(new_players[slot_index].player_name, "%s %d", "PLAYER", slot_index); + } + NetSetPlayerSystemInfo(&new_players[slot_index], pSender_address); + NetPlayersChanged(new_player_count, new_players); + BrMemFree(new_players); + SendOutPlayerList(); + } } // IDA: void __usercall KickPlayerOut(tPlayer_ID pID@) @@ -553,13 +1201,19 @@ void NetFullScreenMessage(int pStr_index, int pLeave_it_up_there) { // IDA: void __usercall HostHasBittenTheDust(int pMessage_index@) void HostHasBittenTheDust(int pMessage_index) { LOG_TRACE("(%d)", pMessage_index); - NOT_IMPLEMENTED(); + + if (!gHost_died) { + gHost_died = 1; + NetFullScreenMessage(pMessage_index, 0); + gProgram_state.prog_status = eProg_idling; + } } // IDA: void __usercall ReceivedHosticide(tNet_contents *pContents@) void ReceivedHosticide(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + HostHasBittenTheDust(73); } // IDA: void __cdecl ConfirmReceipt() @@ -573,20 +1227,88 @@ void ConfirmReceipt(void) { void ReceivedNewPlayerList(tNet_contents* pContents, tNet_message* pM) { int i; LOG_TRACE("(%p, %p)", pContents, pM); - NOT_IMPLEMENTED(); + + if (pContents->data.player_list.number_of_players <= 0) { + gJoin_request_denied = 1; + if (pContents->data.player_list.number_of_players < 0) { + gCar_was_taken = 1; + } + return; + } + if (pContents->data.player_list.batch_number >= gReceiving_batch_number) { + if (!gReceiving_new_players) { + gLast_player_list_received = pM->senders_time_stamp; + for (i = 0; i < COUNT_OF(gNew_net_players); i++) { + gNew_net_players[i].car_index = -1; + } + gReceiving_new_players = 1; + gReceiving_batch_number = pContents->data.player_list.batch_number; + } + if (pContents->data.player_list.batch_number <= gReceiving_batch_number) { + memcpy(&gNew_net_players[pContents->data.player_list.this_index], &pContents->data.player_list.player, sizeof(tNet_game_player_info)); + for (i = 0; i < pContents->data.player_list.number_of_players; i++) { + if (gNew_net_players[i].car_index < 0) { + return; + } + } + gReceiving_new_players = 0; + NetPlayersChanged(pContents->data.player_list.number_of_players, gNew_net_players); + gThis_net_player_index = -1; + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == gLocal_net_ID) { + gThis_net_player_index = i; + break; + } + } + if (gThis_net_player_index < 0) { + FatalError(kFatalError_NonInReceivedPlayerList); + } + gNet_players[0].last_heard_from_him = PDGetTotalTime(); + gCurrent_race.number_of_racers = gNumber_of_net_players; + if (gSynch_race_start) { + for (i = 0; i < gNumber_of_net_players; i++) { + gCurrent_race.opponent_list[gNet_players[i].opponent_list_index].net_player_index = i; + } + } + } else { + gReceiving_new_players = 0; + ReceivedNewPlayerList(pContents, pM); + } + } } // IDA: void __usercall ReceivedRaceOver(tNet_contents *pContents@) void ReceivedRaceOver(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + gRace_finished = 0; + if (gProgram_state.racing && (gNet_mode == eNet_mode_client || pContents->data.race_over.reason == eRace_over_network_victory || pContents->data.race_over.reason == eRace_over_network_loss)) { + RaceCompleted(pContents->data.race_over.reason); + } } // IDA: void __usercall ReceivedStatusReport(tNet_contents *pContents@, tNet_message *pMessage@) void ReceivedStatusReport(tNet_contents* pContents, tNet_message* pMessage) { int i; LOG_TRACE("(%p, %p)", pContents, pMessage); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pMessage->sender) { + gNet_players[i].player_status = pContents->data.report.status; + gNet_players[i].last_heard_from_him = PDGetTotalTime(); + if (gNet_players[i].player_status < ePlayer_status_racing || gNet_players[i].player_status == ePlayer_status_recovering) { + if (gNet_players[i].player_status < ePlayer_status_racing) { + DisableCar(gNet_players[i].car); + } + } else { + if (gNet_players[i].car->disabled) { + SendCurrentPowerups(); + } + EnableCar(gNet_players[i].car); + } + return; + } + } } // IDA: void __usercall ReceivedStartRace(tNet_contents *pContents@) @@ -601,41 +1323,82 @@ void ReceivedStartRace(tNet_contents* pContents) { void ReceivedGuaranteeReply(tNet_contents* pContents) { int i; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNext_guarantee; i++) { + if (gGuarantee_list[i].guarantee_number == pContents->data.reply.guarantee_number) { + gGuarantee_list[i].recieved = 1; + } + } } // IDA: void __usercall ReceivedHeadup(tNet_contents *pContents@) void ReceivedHeadup(tNet_contents* pContents) { LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + if (gProgram_state.racing) { + NewTextHeadupSlot(4, 0, 3000, -4, pContents->data.headup.text); + } } // IDA: void __usercall ReceivedHostQuery(tNet_contents *pContents@, tNet_message *pMessage@) void ReceivedHostQuery(tNet_contents* pContents, tNet_message* pMessage) { tNet_message* message; LOG_TRACE("(%p, %p)", pContents, pMessage); - NOT_IMPLEMENTED(); + + message = NetBuildMessage(NETMSGID_HOSTREPLY, 0); + message->contents.data.heres_where_we_at.race_has_started = gProgram_state.racing; + message->contents.data.heres_where_we_at.race_index = gProgram_state.current_race_index; + message->contents.data.heres_where_we_at.pending_race = gPending_race; + NetGuaranteedSendMessageToPlayer(gCurrent_net_game, message, pMessage->sender, NULL); + if (gProgram_state.racing) { + SignalToStartRace(); + UpdateEnvironments(); + } } // IDA: void __usercall ReceivedHostReply(tNet_contents *pContents@) void ReceivedHostReply(tNet_contents* pContents) { tNet_message* message; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + if (pContents->data.heres_where_we_at.race_index != gProgram_state.current_race_index) { + NetLeaveGame(gCurrent_net_game); + NetFullScreenMessage(128, 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); + gProgram_state.prog_status = eProg_idling; + } + } } // IDA: void __usercall SendGuaranteeReply(tNet_message *pMessage@, void *pSender_address@) void SendGuaranteeReply(tNet_message* pMessage, void* pSender_address) { tNet_message* message; LOG_TRACE("(%p, %p)", pMessage, pSender_address); - NOT_IMPLEMENTED(); + + message = NetBuildMessage(NETMSGID_GUARANTEEREPLY, 0); + message->contents.data.reply.guarantee_number = pMessage->guarantee_number; + pMessage->guarantee_number = 0; + NetSendMessageToAddress(gCurrent_net_game, message, pSender_address); } // IDA: int __usercall PlayerIsInList@(tPlayer_ID pID@) int PlayerIsInList(tPlayer_ID pID) { int i; LOG_TRACE("(%d)", pID); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_net_players; i++) { + if (gNet_players[i].ID == pID) { + gNet_players[i].last_heard_from_him = PDGetTotalTime(); + return 1; + } + } + return 0; } // IDA: void __usercall ReceivedTimeSync(tNet_contents *pContents@, tNet_message *pMessage@, tU32 pReceive_time@) @@ -690,7 +1453,16 @@ void ReceivedCarDetailsReq(tNet_contents* pContents, void* pSender_address) { tNet_message* message; int i; LOG_TRACE("(%p, %p)", pContents, pSender_address); - NOT_IMPLEMENTED(); + + message = NetBuildMessage(NETMSGID_CARDETAILS, 0); + message->contents.data.car_details.count = gNumber_of_net_players; + for (i = 0; i < gNumber_of_net_players; i++) { + message->contents.data.car_details.details[i].car_index = gNet_players[i].car_index; + // truncates from 32 to 16 characters + memcpy(message->contents.data.car_details.details[i].owner, gNet_players[i].player_name, sizeof(message->contents.data.car_details.details[i].owner)); + message->contents.data.car_details.details[i].owner[sizeof(message->contents.data.car_details.details[i].owner) - 1] = '\0'; + } + NetGuaranteedSendMessageToAddress(gCurrent_net_game, message, pSender_address, NULL); } // IDA: void __usercall ReceivedCarDetails(tNet_contents *pContents@) @@ -698,7 +1470,17 @@ void ReceivedCarDetails(tNet_contents* pContents) { int i; int j; LOG_TRACE("(%p)", pContents); - NOT_IMPLEMENTED(); + + SetNetAvailability(gNet_options); + for (i = 0; i < gNumber_of_racers; i++) { + for (j = 0; j < pContents->data.car_details.count; j++) { + if (i == pContents->data.car_details.details[j].car_index) { + gCar_details[i].ownership = eCar_owner_someone; + strcpy(gCar_details[i].name, pContents->data.car_details.details[j].owner); + } + } + } + gReceived_car_details = 1; } // IDA: void __usercall ReceivedGameScores(tNet_contents *pContents@) @@ -713,7 +1495,121 @@ void ReceivedMessage(tNet_message* pMessage, void* pSender_address, tU32 pReceiv tNet_contents* contents; int i; LOG_TRACE("(%p, %p, %d)", pMessage, pSender_address, pReceive_time); - NOT_IMPLEMENTED(); + + contents = &pMessage->contents; + if (pMessage->guarantee_number != 0) { + SendGuaranteeReply(pMessage, pSender_address); + } + if (!gProgram_state.racing && gRace_only_flags[pMessage->contents.header.type]) { + return; + } + if (gOnly_receive_guarantee_replies && pMessage->contents.header.type != NETMSGID_GUARANTEEREPLY) { + return; + } + + for (i = 0; i < pMessage->num_contents; i++) { + if (contents->header.type <= NETMSGID_CARDETAILS || PlayerIsInList(pMessage->sender)) { + switch (contents->header.type) { + case NETMSGID_SENDMEDETAILS: // 0x00, + ReceivedSendMeDetails(contents, pSender_address); + break; + case NETMSGID_DETAILS: // 0x01, + ReceivedDetails(contents); + break; + case NETMSGID_JOIN: // 0x02, + ReceivedJoin(contents, pSender_address); + break; + case NETMSGID_NEWPLAYERLIST: // 0x03, + ReceivedNewPlayerList(contents, pMessage); + break; + case NETMSGID_GUARANTEEREPLY: // 0x04, + ReceivedGuaranteeReply(contents); + break; + case NETMSGID_CARDETAILSREQ: // 0x05, + ReceivedCarDetailsReq(contents, pSender_address); + break; + case NETMSGID_CARDETAILS: // 0x06, + ReceivedCarDetails(contents); + break; + case NETMSGID_LEAVE: // 0x07, + ReceivedLeave(contents, pMessage); + break; + case NETMSGID_HOSTICIDE: // 0x08, + ReceivedHosticide(contents); + break; + case NETMSGID_RACEOVER: // 0x09, + ReceivedRaceOver(contents); + break; + case NETMSGID_STATUSREPORT: // 0x0a, + ReceivedStatusReport(contents, pMessage); + break; + case NETMSGID_STARTRACE: // 0x0b, + ReceivedStartRace(contents); + break; + case NETMSGID_HEADUP: // 0x0c, + ReceivedHeadup(contents); + break; + case NETMSGID_HOSTQUERY: // 0x0d, + ReceivedHostQuery(contents, pMessage); + break; + case NETMSGID_HOSTREPLY: // 0x0e, + ReceivedHostReply(contents); + break; + case NETMSGID_MECHANICS: // 0x0f, + ReceivedMechanics(contents); + break; + case NETMSGID_NONCAR_INFO: // 0x10, + ReceivedNonCar(contents); + break; + case NETMSGID_TIMESYNC: // 0x11, + ReceivedTimeSync(contents, pMessage, pReceive_time); + break; + case NETMSGID_CONFIRM: // 0x12, + ReceivedConfirm(contents); + break; + case NETMSGID_DISABLECAR: // 0x13, + ReceivedDisableCar(contents); + break; + case NETMSGID_ENABLECAR: // 0x14, + ReceivedEnableCar(contents); + break; + case NETMSGID_POWERUP: // 0x15, + ReceivedPowerup(contents); + break; + case NETMSGID_RECOVER: // 0x16, + ReceivedRecover(contents); + break; + case NETMSGID_SCORES: // 0x17, + ReceivedScores(contents); + break; + case NETMSGID_WASTED: // 0x18, + ReceivedWasted(contents); + break; + case NETMSGID_PEDESTRIAN: // 0x19, + ReceivedPedestrian(contents, pMessage, pReceive_time); + break; + case NETMSGID_GAMEPLAY: // 0x1a, + ReceivedGameplay(contents, pMessage, pReceive_time); + break; + case NETMSGID_NONCARPOSITION: // 0x1b, + ReceivedNonCarPosition(contents); + break; + case NETMSGID_COPINFO: // 0x1c, + ReceivedCopInfo(contents); + break; + case NETMSGID_GAMESCORES: // 0x1d, + ReceivedGameScores(contents); + break; + case NETMSGID_OILSPILL: // 0x1e, + ReceivedOilSpill(contents); + break; + case NETMSGID_CRUSHPOINT: // 0x1f, + RecievedCrushPoint(contents); + break; + } + } + contents = (tNet_contents*)((tU8*)contents + contents->header.contents_size); + } } // IDA: void __cdecl NetReceiveAndProcessMessages() @@ -723,14 +1619,32 @@ void NetReceiveAndProcessMessages(void) { tU32 receive_time; int old_net_service; LOG_TRACE("()"); - STUB_ONCE(); + + old_net_service = gIn_net_service; + if (gNet_mode != eNet_mode_none || gJoin_list_mode) { + gIn_net_service = 1; + while ((message = NetGetNextMessage(gCurrent_net_game, &sender_address)) != NULL) { + receive_time = GetRaceTime(); + if (message->magic_number == 0x763a5058) { + CheckCheckSum(message); + ReceivedMessage(message, sender_address, receive_time); + } else { + message->guarantee_number = 0; + } + NetDisposeMessage(gCurrent_net_game, message); + } + } + gIn_net_service = old_net_service; } // IDA: void __cdecl BroadcastStatus() void BroadcastStatus(void) { tNet_message* message; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + message = NetBuildMessage(NETMSGID_STATUSREPORT, 0); + message->contents.data.report.status = gNet_players[gThis_net_player_index].player_status; + NetSendMessageToAllPlayers(gCurrent_net_game, message); } // IDA: void __cdecl CheckForDisappearees() @@ -741,28 +1655,87 @@ void CheckForDisappearees(void) { char s[256]; char* s2; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + the_time = PDGetTotalTime(); + if (gNet_mode == eNet_mode_host) { + for (i = 0; i < gNumber_of_net_players; i++) { + if (!gNet_players[i].host && gNet_players[i].last_heard_from_him != 0 && the_time - gNet_players[i].last_heard_from_him >= 20000) { + strcpy(s, gNet_players[i].player_name); + strcat(s, " "); + strcat(s, GetMiscString(90)); + NetSendHeadupToAllPlayers(s); + KickPlayerOut(gNet_players[i].ID); + if (gProgram_state.racing) { + NewTextHeadupSlot(4, 0, 3000, -4, s); + } + } + } + } 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); + } } // IDA: void __cdecl CheckForPendingStartRace() void CheckForPendingStartRace(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_host && gNeed_to_send_start_race) { + for (i = 1; i < gNumber_of_net_players; i++) { + if (gNet_players[i].awaiting_confirmation) { + return; + } + } + SignalToStartRace(); + } } // IDA: void __usercall NetService(int pIn_race@) void NetService(int pIn_race) { tU32 time; static tU32 last_status_broadcast; - STUB_ONCE(); + + if (gIn_net_service || gNet_service_disable) { + return; + } + time = PDGetTotalTime(); + gIn_net_service = 1; + if (gJoin_list_mode) { + NetFreeExcessMemory(); + DoNextJoinPoll(); + NetReceiveAndProcessMessages(); + } else { + if (gNet_mode != eNet_mode_none) { + NetFreeExcessMemory(); + if (!pIn_race) { + NetReceiveAndProcessMessages(); + } + if (time - last_status_broadcast > 1000) { + last_status_broadcast = PDGetTotalTime(); + BroadcastStatus(); + } + CheckForDisappearees(); + CheckForPendingStartRace(); + } + } + if (gJoin_list_mode || gNet_mode != eNet_mode_none) { + ResendGuaranteedMessages(); + if (time > gLast_flush_message + 200) { + NetSendMessageStacks(); + } + } + gIn_net_service = 0; } // IDA: void __usercall NetFinishRace(tNet_game_details *pDetails@, tRace_over_reason pReason@) void NetFinishRace(tNet_game_details* pDetails, tRace_over_reason pReason) { tNet_message* the_message; LOG_TRACE("(%p, %d)", pDetails, pReason); - STUB(); + + gNeed_to_send_start_race = 0; + the_message = NetBuildMessage(NETMSGID_RACEOVER, 0); + the_message->contents.data.race_over.reason = pReason; + NetGuaranteedSendMessageToAllPlayers(gCurrent_net_game, the_message, NULL); } // IDA: void __usercall NetPlayerStatusChanged(tPlayer_status pNew_status@) @@ -784,7 +1757,8 @@ void NetPlayerStatusChanged(tPlayer_status pNew_status) { // IDA: tPlayer_status __cdecl NetGetPlayerStatus() tPlayer_status NetGetPlayerStatus(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + return gNet_players[gThis_net_player_index].player_status; } // IDA: int __usercall NetGuaranteedSendMessageToAllPlayers@(tNet_game_details *pDetails@, tNet_message *pMessage@, int (*pNotifyFail)(tU32, tNet_message*)@) @@ -792,7 +1766,19 @@ int NetGuaranteedSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_messa int i; int err; LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail); - NOT_IMPLEMENTED(); + + err = 0; + if (gNumber_of_net_players == 1) { + NetDisposeMessage(pDetails, pMessage); + err = 0; + } else { + for (i = 0; i < gNumber_of_net_players; i++) { + if (gThis_net_player_index != i) { + err |= NetGuaranteedSendMessageToAddress(pDetails, pMessage, &gNet_players[i], pNotifyFail); + } + } + } + return err; } // IDA: int __usercall NetGuaranteedSendMessageToEverybody@(tNet_game_details *pDetails@, tNet_message *pMessage@, int (*pNotifyFail)(tU32, tNet_message*)@) @@ -804,20 +1790,64 @@ int NetGuaranteedSendMessageToEverybody(tNet_game_details* pDetails, tNet_messag // IDA: int __usercall NetGuaranteedSendMessageToHost@(tNet_game_details *pDetails@, tNet_message *pMessage@, int (*pNotifyFail)(tU32, tNet_message*)@) int NetGuaranteedSendMessageToHost(tNet_game_details* pDetails, tNet_message* pMessage, int (*pNotifyFail)(tU32, tNet_message*)) { LOG_TRACE("(%p, %p, %p)", pDetails, pMessage, pNotifyFail); - NOT_IMPLEMENTED(); + + return NetGuaranteedSendMessageToAddress(pDetails, pMessage, &pDetails->pd_net_info, pNotifyFail); } // IDA: int __usercall NetGuaranteedSendMessageToPlayer@(tNet_game_details *pDetails@, tNet_message *pMessage@, tPlayer_ID pPlayer@, int (*pNotifyFail)(tU32, tNet_message*)@) int NetGuaranteedSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer, int (*pNotifyFail)(tU32, tNet_message*)) { int i; LOG_TRACE("(%p, %p, %d, %p)", pDetails, pMessage, pPlayer, pNotifyFail); - NOT_IMPLEMENTED(); + + for (i = 0; i <= gNumber_of_net_players; i++) { + if (pPlayer == gNet_players[i].ID) { + break; + } + } + if (i == gNumber_of_net_players) { + return -1; + } + if (gLocal_net_ID != pPlayer) { + return NetGuaranteedSendMessageToAddress(pDetails, pMessage, &gNet_players[i].pd_net_info, pNotifyFail); + } + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + pMessage->num_contents = 1; + pMessage->guarantee_number = 0; + ReceivedMessage(pMessage, &gNet_players[i], GetRaceTime()); + NetDisposeMessage(pDetails, pMessage); + return 0; } // IDA: int __usercall NetGuaranteedSendMessageToAddress@(tNet_game_details *pDetails@, tNet_message *pMessage@, void *pAddress@, int (*pNotifyFail)(tU32, tNet_message*)@) int NetGuaranteedSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress, int (*pNotifyFail)(tU32, tNet_message*)) { + char buffer[256]; // Added by Dethrace LOG_TRACE("(%p, %p, %p, %p)", pDetails, pMessage, pAddress, pNotifyFail); - NOT_IMPLEMENTED(); + + if (gNet_mode == eNet_mode_none && !gJoin_list_mode) { + return -3; + } + pMessage->sender = gLocal_net_ID; + pMessage->senders_time_stamp = PDGetTotalTime(); + if (gNext_guarantee >= COUNT_OF(gGuarantee_list)) { + sprintf(buffer, "Guarantee list full %d", pMessage->contents.header.type); + NewTextHeadupSlot(4, 0, 500, -1, buffer); + pMessage->guarantee_number = 0; + return 0; + } + pMessage->guarantee_number = gGuarantee_number; + gGuarantee_list[gNext_guarantee].guarantee_number = gGuarantee_number; + gGuarantee_number++; + gGuarantee_list[gNext_guarantee].message = pMessage; + gGuarantee_list[gNext_guarantee].send_time = PDGetTotalTime(); + gGuarantee_list[gNext_guarantee].next_resend_time = gGuarantee_list[gNext_guarantee].send_time + 100; + gGuarantee_list[gNext_guarantee].resend_period = 100; + memcpy(&gGuarantee_list[gNext_guarantee].pd_address, pAddress, sizeof(tPD_net_player_info)); + gGuarantee_list[gNext_guarantee].NotifyFail = pNotifyFail; + gGuarantee_list[gNext_guarantee].recieved = 0; + gNext_guarantee++; + DoCheckSum(pMessage); + return PDNetSendMessageToAddress(pDetails, pMessage, pAddress); } // IDA: void __cdecl ResendGuaranteedMessages() @@ -826,7 +1856,38 @@ void ResendGuaranteedMessages(void) { int j; tU32 time; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + i = 0; + time = PDGetTotalTime(); + for (j = 0; j < gNext_guarantee; j++) { + if (i != j) { + memcpy(&gGuarantee_list[i], &gGuarantee_list[j], sizeof(tGuaranteed_message)); + } + if (!gGuarantee_list[i].recieved) { + if (gGuarantee_list[i].NotifyFail != NULL) { + gGuarantee_list[i].recieved |= gGuarantee_list[i].NotifyFail(time - gGuarantee_list[i].send_time, gGuarantee_list[i].message); + } else { + if (time - gGuarantee_list[i].send_time > 10000) { + gGuarantee_list[i].recieved = 1; + } + } + } + if (!gGuarantee_list[i].recieved) { + if (time > gGuarantee_list[i].next_resend_time) { + gGuarantee_list[i].message->guarantee_number = gGuarantee_list[i].guarantee_number; + GetCheckSum(gGuarantee_list[i].message); + PDNetSendMessageToAddress(gCurrent_net_game, gGuarantee_list[i].message, &gGuarantee_list[i].pd_address); + gGuarantee_list[i].resend_period = (tU32)(gGuarantee_list[i].resend_period * 1.2f); + gGuarantee_list[i].next_resend_time += gGuarantee_list[i].resend_period; + } + i++; + } else if ((i <= 0 || gGuarantee_list[i - 1].message != gGuarantee_list[i].message) + && (gNext_guarantee <= j + 1 || gGuarantee_list[j + 1].message != gGuarantee_list[i].message)) { + gGuarantee_list[i].message->guarantee_number = 0; + NetDisposeMessage(gCurrent_net_game, gGuarantee_list[i].message); + } + } + gNext_guarantee = i; } // IDA: int __usercall SampleFailNotifier@(tU32 pAge@, tNet_message *pMessage@) @@ -839,7 +1900,14 @@ int SampleFailNotifier(tU32 pAge, tNet_message* pMessage) { void NetWaitForGuaranteeReplies(void) { tU32 start_time; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + start_time = PDGetTotalTime(); + while (gNext_guarantee != 0) { + if (PDGetTotalTime() - start_time >= 5000) { + break; + } + NetService(0); + } } // IDA: tNet_game_player_info* __usercall NetPlayerFromID@(tPlayer_ID pPlayer@) @@ -872,17 +1940,17 @@ tU32 DoCheckSum(tNet_message* pMessage) { tU32* p; tU8* q; LOG_TRACE("(%p)", pMessage); - NOT_IMPLEMENTED(); + + // empty function + return 0; } // IDA: void __usercall GetCheckSum(tNet_message *pMessage@) void GetCheckSum(tNet_message* pMessage) { LOG_TRACE("(%p)", pMessage); - NOT_IMPLEMENTED(); } // IDA: void __usercall CheckCheckSum(tNet_message *pMessage@) void CheckCheckSum(tNet_message* pMessage) { LOG_TRACE("(%p)", pMessage); - NOT_IMPLEMENTED(); } diff --git a/src/DETHRACE/common/network.h b/src/DETHRACE/common/network.h index 3e142a05..09195339 100644 --- a/src/DETHRACE/common/network.h +++ b/src/DETHRACE/common/network.h @@ -17,7 +17,7 @@ extern tU32 gLast_flush_message; extern int gRace_only_flags[33]; extern int gJoin_list_mode; extern tNet_game_player_info gNew_net_players[6]; -extern tGuaranteed_message gGuarantee_list[150]; +extern tGuaranteed_message gGuarantee_list[100]; extern tMid_message* gMid_messages; extern tU32 gLast_player_list_received; extern tMin_message* gMin_messages; diff --git a/src/DETHRACE/common/newgame.c b/src/DETHRACE/common/newgame.c index 6789182b..fb4c2d63 100644 --- a/src/DETHRACE/common/newgame.c +++ b/src/DETHRACE/common/newgame.c @@ -8,11 +8,17 @@ #include "globvrpb.h" #include "grafdata.h" #include "graphics.h" +#include "harness/config.h" +#include "harness/hooks.h" #include "harness/trace.h" #include "init.h" #include "input.h" #include "intrface.h" #include "loading.h" +#include "network.h" +#include "pd/sys.h" +#include "racestrt.h" +#include "sound.h" #include "structur.h" #include "utility.h" #include "world.h" @@ -22,9 +28,23 @@ tU8* gFrank_flic_data; tU8* gAnne_flic_data; int gNet_storage_allocated; -tRadio_bastards gRadio_bastards__newgame[11]; // suffix added to avoid duplicate symbol -char _name1[] = "xxxxxxxx.TXT"; // keep compiler happy -char _name2[] = "yyyyyyyy.TXT"; // keep compiler happy +// clang-format off +tRadio_bastards gRadio_bastards__newgame[11] = { // suffix added to avoid duplicate symbol + { 1, 32, 0, { 245, 0, 0, 0, 0, }, }, + { 1, 43, 0, { 245, 0, 0, 0, 0, }, }, + { 1, 54, 0, { 245, 0, 0, 0, 0, }, }, + { 1, 65, 0, { 245, 0, 0, 0, 0, }, }, + { 1, 76, 0, { 245, 0, 0, 0, 0, }, }, + { 2, 86, 0, { 81, 150, 0, 0, 0, }, }, + { 2, 97, 0, { 81, 150, 0, 0, 0, }, }, + { 2, 108, 0, { 81, 150, 0, 0, 0, }, }, + { 2, 119, 0, { 150, 201, 0, 0, 0, }, }, + { 4, 130, 0, { 115, 150, 183, 215, 0, }, }, + { 5, 141, 0, { 142, 160, 182, 204, 230, }, }, +}; +// clang-format on +char _name1[] = "xxxxxxxx.TXT"; // keep compiler happy +char _name2[] = "yyyyyyyy.TXT"; // keep compiler happy char* gBasic_car_names[2] = { _name1, _name2 }; tNet_game_options gNet_settings[8]; tJoinable_game gGames_to_join[6]; @@ -49,7 +69,7 @@ void StartRollingPlayerNamesIn(void) { int i; LOG_TRACE("()"); - for (i = 0; i < 2; i++) { + for (i = 0; i < COUNT_OF(gCurrent_graf_data->player_name_x); i++) { SetSlotXY(i, gCurrent_graf_data->player_name_x[i], gCurrent_graf_data->player_name_y); AddRollingString(gProgram_state.player_name[i], gCurrent_graf_data->player_name_x[i], gCurrent_graf_data->player_name_y, eRT_alpha); } @@ -58,16 +78,21 @@ void StartRollingPlayerNamesIn(void) { // IDA: void __cdecl FrankAnneStart1() void FrankAnneStart1(void) { LOG_TRACE("()"); + StartRollingPlayerNamesIn(); - if (!gFrank_flic_data) { + if (gFrank_flic_data == NULL) { if (!LoadFlicData("FRANK.FLI", &gFrank_flic_data, &gFrank_flic_data_length)) { FatalError(kFatalError_LoadOpponentMugShotFile); } + } else { + MAMSLock((void**)&gFrank_flic_data); } if (!gAnne_flic_data) { if (!LoadFlicData("ANNIE.FLI", &gAnne_flic_data, &gAnne_flic_data_length)) { FatalError(kFatalError_LoadOpponentMugShotFile); } + } else { + MAMSLock((void**)&gAnne_flic_data); } InitialiseFlicPanel(0, gCurrent_graf_data->frank_panel_left, @@ -84,6 +109,7 @@ void FrankAnneStart1(void) { // IDA: void __cdecl FrankAnneStart2() void FrankAnneStart2(void) { LOG_TRACE("()"); + ChangePanelFlic(0, gFrank_flic_data, gFrank_flic_data_length); ChangePanelFlic(1, gAnne_flic_data, gAnne_flic_data_length); TellyInImage(GetPanelPixelmap(0), gCurrent_graf_data->frank_panel_left, gCurrent_graf_data->frank_panel_top); @@ -93,6 +119,7 @@ void FrankAnneStart2(void) { // IDA: void __usercall GetPlayerName(int pStarting_to_type@, int pCurrent_choice@, char *pString@, int *pMax_length@) void GetPlayerName(int pStarting_to_type, int pCurrent_choice, char* pString, int* pMax_length) { LOG_TRACE("(%d, %d, \"%s\", %p)", pStarting_to_type, pCurrent_choice, pString, pMax_length); + strcpy(pString, gProgram_state.player_name[pCurrent_choice]); *pMax_length = PLAYER_NAME_MAX_LENGTH; } @@ -100,6 +127,7 @@ void GetPlayerName(int pStarting_to_type, int pCurrent_choice, char* pString, in // IDA: int __usercall FrankAnneDone@(int pCurrent_choice@, int pCurrent_mode@, int pGo_ahead@, int pEscaped@, int pTimed_out) int FrankAnneDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) { LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out); + RemoveTransientBitmaps(1); TellyOutImage(GetPanelPixelmap(1), gCurrent_graf_data->anne_panel_left, gCurrent_graf_data->anne_panel_top); TellyOutImage(GetPanelPixelmap(0), gCurrent_graf_data->frank_panel_left, gCurrent_graf_data->frank_panel_top); @@ -117,6 +145,7 @@ int FrankAnneDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEs // IDA: void __usercall FrankAnneDraw(int pCurrent_choice@, int pCurrent_mode@) void FrankAnneDraw(int pCurrent_choice, int pCurrent_mode) { LOG_TRACE9("(%d, %d)", pCurrent_choice, pCurrent_mode); + if (gTyping) { if (GetTotalTime() & 0x100) { if (pCurrent_choice < 2) { @@ -314,8 +343,6 @@ int SelectSkillLevel(void) { gProgram_state.skill_level = result; return 1; } -#include "harness/config.h" -#include "harness/hooks.h" // IDA: int __cdecl DoOnePlayerStart() int DoOnePlayerStart(void) { @@ -353,7 +380,7 @@ int DoOnePlayerStart(void) { SwitchToLoresMode(); SetCarStorageTexturingLevel(&gOur_car_storage_space, GetCarTexturingLevel(), eCTL_full); PrintMemoryDump(0, "IMMEDIATELY AFTER LOADING YOUR CAR"); - gNet_mode = 0; + gNet_mode = eNet_mode_none; InitGame(0); merrily_looping = 0; } @@ -371,7 +398,36 @@ int NewNetGameUp(int* pCurrent_choice, int* pCurrent_mode) { int new_sel; int i; LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + DRS3StartSound(gEffects_outlet, 3000); + if (*pCurrent_mode == 0) { + gLast_graph_sel__newgame = COUNT_OF(gGames_to_join); + } + new_sel = -1; + for (i = gLast_graph_sel__newgame - 1; i >= 0; i--) { + gLast_graph_sel__newgame = i; + if (gGames_to_join[i].game == NULL) { + continue; + } + if (!gGames_to_join[i].game->options.open_game && !gGames_to_join[i].game->no_races_yet) { + continue; + } + if (gGames_to_join[i].game->num_players > 5) { + continue; + } + new_sel = i; + break; + } + if (new_sel < 0) { + gLast_graph_sel__newgame = -1; + *pCurrent_choice = 0; + *pCurrent_mode = 0; + } else { + gLast_graph_sel__newgame = new_sel; + *pCurrent_choice = 2; + *pCurrent_mode = 1; + } + return 1; } // IDA: int __usercall NewNetGameDown@(int *pCurrent_choice@, int *pCurrent_mode@) @@ -379,25 +435,69 @@ int NewNetGameDown(int* pCurrent_choice, int* pCurrent_mode) { int new_sel; int i; LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + DRS3StartSound(gEffects_outlet, 3000); + if (*pCurrent_mode == 0) { + gLast_graph_sel__newgame = -1; + } + + new_sel = -1; + for (i = gLast_graph_sel__newgame - 1; i < COUNT_OF(gGames_to_join); i++) { + gLast_graph_sel__newgame = i; + if (gGames_to_join[i].game == NULL) { + continue; + } + if (!gGames_to_join[i].game->options.open_game && !gGames_to_join[i].game->no_races_yet) { + continue; + } + if (gGames_to_join[i].game->num_players > 5) { + continue; + } + new_sel = i; + break; + } + if (new_sel < 0) { + gLast_graph_sel__newgame = -1; + *pCurrent_choice = 0; + *pCurrent_mode = 0; + } else { + gLast_graph_sel__newgame = new_sel; + *pCurrent_choice = 2; + *pCurrent_mode = 1; + } + return 1; } // IDA: void __usercall DisposeJoinableGame(int pIndex@) void DisposeJoinableGame(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + NetDisposeGameDetails(gGames_to_join[pIndex].game); + gGames_to_join[pIndex].game = NULL; } // IDA: void __usercall DrawAnItem(int pX@, int pY_index@, int pFont_index@, char *pText@) void DrawAnItem__newgame(int pX, int pY_index, int pFont_index, char* pText) { LOG_TRACE("(%d, %d, %d, \"%s\")", pX, pY_index, pFont_index, pText); - NOT_IMPLEMENTED(); + + TransDRPixelmapText(gBack_screen, + pX, + gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_y_pitch * pY_index, + &gFonts[pFont_index], + pText, + pX + DRTextWidth(&gFonts[pFont_index], pText)); } // IDA: void __usercall DrawColumnHeading(int pStr_index@, int pX@) void DrawColumnHeading__newgame(int pStr_index, int pX) { LOG_TRACE("(%d, %d)", pStr_index, pX); - NOT_IMPLEMENTED(); + + TransDRPixelmapText(gBack_screen, + pX, + gCurrent_graf_data->joinable_games_y - gCurrent_graf_data->joinable_games_y_pitch, + &gFonts[12], + GetMiscString(pStr_index), + pX + DRTextWidth(&gFonts[12], GetMiscString(pStr_index))); } // IDA: void __usercall DrawGames(int pCurrent_choice@, int pCurrent_mode@) @@ -411,21 +511,123 @@ void DrawGames(int pCurrent_choice, int pCurrent_mode) { char* s2; char* s3; LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + current_index = 0; + BrPixelmapRectangleFill(gBack_screen, + gCurrent_graf_data->joinable_games_sel_left, + gCurrent_graf_data->joinable_games_sel_top_marg + gCurrent_graf_data->joinable_games_y, + gCurrent_graf_data->joinable_games_sel_right - gCurrent_graf_data->joinable_games_sel_left, + (COUNT_OF(gGames_to_join) + 1) * gCurrent_graf_data->joinable_games_y_pitch + gCurrent_graf_data->joinable_games_sel_bot_marg, + 0); + if (gMouse_in_use && pCurrent_mode) { + GetMousePosition(&x_coord, &y_coord); + gLast_graph_sel__newgame = -1; + } + DrawColumnHeading__newgame(206, gCurrent_graf_data->joinable_games_x_1); + DrawColumnHeading__newgame(207, gCurrent_graf_data->joinable_games_x_2); + DrawColumnHeading__newgame(208, gCurrent_graf_data->joinable_games_x_3); + DrawColumnHeading__newgame(209, gCurrent_graf_data->joinable_games_x_4); + BrPixelmapLine(gBack_screen, + gCurrent_graf_data->joinable_games_sel_left, + gCurrent_graf_data->joinable_games_y + gFonts[12].height + 1 - (TranslationMode() ? 2 : 0) - gCurrent_graf_data->joinable_games_y_pitch, + gCurrent_graf_data->joinable_games_sel_right - 1, + gCurrent_graf_data->joinable_games_y + gFonts[12].height + 1 - (TranslationMode() ? 2 : 0) - gCurrent_graf_data->joinable_games_y_pitch, + 6); + for (i = 0; i < COUNT_OF(gGames_to_join); i++) { + if (gGames_to_join[i].game == NULL) { + continue; + } + if (gGames_to_join[i].game->type < 0 || gGames_to_join[i].game->type >= eNet_game_type_count) { + continue; + } + if ((PDGetTotalTime() - gGames_to_join[i].time) >= 15000) { + DisposeJoinableGame(i); + continue; + } + if (gMouse_in_use + && pCurrent_mode != 0 + && gGames_to_join[i].game != NULL + && (gGames_to_join[i].game->options.open_game || gGames_to_join[i].game->no_races_yet) + && gGames_to_join[i].game->num_players <= 5 + && x_coord >= gCurrent_graf_data->joinable_games_sel_left + && x_coord <= gCurrent_graf_data->joinable_games_sel_right + && y_coord >= (gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_top_marg + current_index * gCurrent_graf_data->joinable_games_y_pitch) + && y_coord <= (gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_bot_marg + current_index * gCurrent_graf_data->joinable_games_y_pitch - 1)) { + gLast_graph_sel__newgame = i; + } + if (i == gLast_graph_sel__newgame) { + font_index = 10; + } else { + font_index = 9; + } + sprintf(s, "%s", gGames_to_join[i].game->host_name); + DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_1, current_index, font_index, s); + sprintf(s, "%s", GetMiscString(59 + gGames_to_join[i].game->type)); + DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_2, current_index, font_index, s); + sprintf(s, "%d", gGames_to_join[i].game->num_players); + DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_3, current_index, font_index, s); + sprintf(s, "%s, %s", + GetMiscString(68 + gGames_to_join[i].game->status.stage), + GetMiscString(71 + gGames_to_join[i].game->options.open_game)); + DrawAnItem__newgame(gCurrent_graf_data->joinable_games_x_4, current_index, font_index, s); + if (i == gLast_graph_sel__newgame) { + DrawRectangle(gBack_screen, + gCurrent_graf_data->joinable_games_sel_left, + gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_top_marg + gCurrent_graf_data->joinable_games_y_pitch * current_index, + gCurrent_graf_data->joinable_games_sel_right - 1, + gCurrent_graf_data->joinable_games_y + gCurrent_graf_data->joinable_games_sel_bot_marg + gCurrent_graf_data->joinable_games_y_pitch * current_index - 1, + 45); + } + current_index++; + } + + if (current_index != 0 && (gCurrent_game_selection == 0 || (gLast_graph_sel__newgame >= 0 && (gGames_to_join[gLast_graph_sel__newgame].game == NULL || (!gGames_to_join[gLast_graph_sel__newgame].game->options.open_game && !gGames_to_join[gLast_graph_sel__newgame].game->no_races_yet) || gGames_to_join[gLast_graph_sel__newgame].game->num_players > 5)))) { + gCurrent_game_selection = 1; + for (i = 0; i < COUNT_OF(gGames_to_join); i++) { + if (gGames_to_join[i].game != NULL && (gGames_to_join[i].game->options.open_game || gGames_to_join[i].game->no_races_yet) && gGames_to_join[i].game->num_players <= 5) { + gLast_graph_sel__newgame = i; + ChangeSelectionTo(2, 1); + return; + } + } + } + if (pCurrent_mode != 0 && +#if defined(DETHRACE_FIX_BUGS) + (gLast_graph_sel__newgame >= 0) && +#endif + (current_index == 0 + || gGames_to_join[gLast_graph_sel__newgame].game == NULL + || (!gGames_to_join[gLast_graph_sel__newgame].game->options.open_game && !gGames_to_join[gLast_graph_sel__newgame].game->no_races_yet) + || gGames_to_join[gLast_graph_sel__newgame].game->num_players > 5)) { + gLast_graph_sel__newgame = -1; + ChangeSelectionTo(0, 0); + } } // IDA: void __cdecl InitGamesToJoin() void InitGamesToJoin(void) { int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + for (i = 0; i < COUNT_OF(gGames_to_join); i++) { + gGames_to_join[i].game = NULL; + } + gLast_graph_sel__newgame = -1; } // IDA: void __usercall DisposeJoinList(int pExemption@) void DisposeJoinList(int pExemption) { int i; LOG_TRACE("(%d)", pExemption); - NOT_IMPLEMENTED(); + + for (i = 0; i < COUNT_OF(gGames_to_join); i++) { + if (i == pExemption) { + continue; + } + if (gGames_to_join[i].game != NULL) { + DisposeJoinableGame(i); + } + } } // IDA: void __usercall AddToJoinList(tNet_game_details *pGame@) @@ -434,110 +636,304 @@ void AddToJoinList(tNet_game_details* pGame) { int slot_to_use; tU32 this_game_ID; LOG_TRACE("(%p)", pGame); - NOT_IMPLEMENTED(); + + slot_to_use = -1; + this_game_ID = NetExtractGameID(pGame); + for (i = 0; i < COUNT_OF(gGames_to_join); i++) { + if (gGames_to_join[i].game != NULL) { + if (NetExtractGameID(gGames_to_join[i].game) == this_game_ID) { + DisposeJoinableGame(i); + slot_to_use = i; + break; + } + } + } + if (slot_to_use < 0) { + for (i = 0; i < COUNT_OF(gGames_to_join); i++) { + if (gGames_to_join[i].game == NULL) { + slot_to_use = i; + break; + } + } + } + if (slot_to_use >= 0) { + gGames_to_join[slot_to_use].game = pGame; + gGames_to_join[slot_to_use].time = PDGetTotalTime(); + } } // IDA: void __cdecl NewNetStart1() void NewNetStart1(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gTyping = 1; + SetSlotXY(0, gCurrent_graf_data->net_player_name_x, gCurrent_graf_data->net_player_name_y); + AddRollingString(gNet_player_name, + gCurrent_graf_data->net_player_name_x, gCurrent_graf_data->net_player_name_y, eRT_alpha); } // IDA: void __cdecl NewNetStart2() void NewNetStart2(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + gTyping_slot = 0; + StartTyping(0, gNet_player_name, 11); } // IDA: void __usercall NewNetGetName(int pStarting_to_type@, int pCurrent_choice@, char *pString@, int *pMax_length@) void NewNetGetName(int pStarting_to_type, int pCurrent_choice, char* pString, int* pMax_length) { LOG_TRACE("(%d, %d, \"%s\", %p)", pStarting_to_type, pCurrent_choice, pString, pMax_length); - NOT_IMPLEMENTED(); + + strcpy(pString, gNet_player_name); + *pMax_length = 10; } // IDA: int __usercall NewNetDone@(int pCurrent_choice@, int pCurrent_mode@, int pGo_ahead@, int pEscaped@, int pTimed_out) int NewNetDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) { LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out); - NOT_IMPLEMENTED(); + + if (pCurrent_choice != 1) { + GetTypedName(gNet_player_name, 10); + } + return pCurrent_choice; } // IDA: int __usercall NewNetGoAhead@(int *pCurrent_choice@, int *pCurrent_mode@) int NewNetGoAhead(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + return gLast_graph_sel__newgame >= 0; } // IDA: tJoin_or_host_result __usercall JoinOrHostGame@(tNet_game_details **pGame_to_join@) tJoin_or_host_result JoinOrHostGame(tNet_game_details** pGame_to_join) { - static tFlicette flicker_on[2]; - static tFlicette flicker_off[2]; - static tFlicette push[2]; - static tMouse_area mouse_areas[3]; - static tRectile recopy_areas[1]; - static tInterface_spec interface_spec; + static tFlicette flicker_on[2] = { + { 43, { 41, 122 }, { 164, 370 } }, + { 43, { 230, 440 }, { 164, 370 } }, + }; + static tFlicette flicker_off[2] = { + { 42, { 41, 122 }, { 164, 370 } }, + { 42, { 230, 440 }, { 164, 370 } }, + }; + static tFlicette push[2] = { + { 90, { 41, 122 }, { 164, 370 } }, + { 45, { 230, 440 }, { 164, 370 } }, + }; + static tMouse_area mouse_areas[3] = { + { { 41, 122 }, { 164, 370 }, { 104, 326 }, { 184, 422 }, 0, 0, 1, NULL }, + { { 230, 440 }, { 164, 370 }, { 293, 568 }, { 184, 422 }, 1, 0, 1, NULL }, + { { 42, 94 }, { 57, 137 }, { 290, 556 }, { 150, 341 }, 2, 1, 1, NULL }, + }; + static tRectile recopy_areas[1] = { + { + { 124, 110 }, + { 163, 317 }, + { 212, 322 }, + { 180, 370 }, + }, + }; + static tInterface_spec interface_spec = { + 0, + 100, + 0, + 101, + 101, + 101, + -1, + { 0, -1 }, + { -1, -1 }, + { 0, 2 }, + { 1, 2 }, + { NULL, NULL }, + { 0, -1 }, + { 1, -1 }, + { 0, 2 }, + { 1, 2 }, + { NULL, NULL }, + { 1, -1 }, + { 0, 0 }, + { 2, 0 }, + { 2, 0 }, + { NewNetGameUp, NewNetGameUp }, + { 1, -1 }, + { 0, 0 }, + { 2, 0 }, + { 2, 0 }, + { NewNetGameDown, NewNetGameDown }, + { 1, 1 }, + { NULL, NewNetGoAhead }, + { 1, 1 }, + { NULL, NULL }, + NULL, + DrawGames, + 0, + NewNetStart1, + NewNetStart2, + NewNetDone, + 1, + { 1, 1 }, + NewNetGetName, + 1, + 1, + COUNT_OF(flicker_on), + flicker_on, + flicker_off, + push, + COUNT_OF(mouse_areas), + mouse_areas, + COUNT_OF(recopy_areas), + recopy_areas, + }; int result; LOG_TRACE("(%p)", pGame_to_join); - NOT_IMPLEMENTED(); + + gCurrent_game_selection = 0; + LoadFont(9); + LoadFont(10); + LoadFont(3); + LoadFont(12); + SetAlwaysTyping(); + InitGamesToJoin(); + NetStartProducingJoinList(AddToJoinList); + result = DoInterfaceScreen(&interface_spec, 0, 0); + ClearAlwaysTyping(); + NetEndJoinList(); + DisposeJoinList(gLast_graph_sel__newgame); + DisposeFont(9); + DisposeFont(10); + DisposeFont(3); + DisposeFont(12); + strcpy(gProgram_state.player_name[0], gNet_player_name); + SaveOptions(); + switch (result) { + case 0: + return eJoin_or_host_host; + case 1: + return eJoin_or_host_cancel; + case 2: + *pGame_to_join = gGames_to_join[gLast_graph_sel__newgame].game; + return eJoin_or_host_join; + default: + return eJoin_or_host_cancel; + } } // IDA: void __usercall GetNetOptions(tNet_game_options *pGame_options@) void GetNetOptions(tNet_game_options* pGame_options) { LOG_TRACE("(%p)", pGame_options); - NOT_IMPLEMENTED(); + + pGame_options->enable_text_messages = gRadio_bastards__newgame[0].current_value; + pGame_options->show_players_on_map = gRadio_bastards__newgame[1].current_value; + pGame_options->show_peds_on_map = gRadio_bastards__newgame[2].current_value; + pGame_options->show_powerups_on_map = gRadio_bastards__newgame[3].current_value; + pGame_options->powerup_respawn = gRadio_bastards__newgame[4].current_value; + pGame_options->open_game = !gRadio_bastards__newgame[5].current_value; + pGame_options->grid_start = !gRadio_bastards__newgame[6].current_value; + pGame_options->race_sequence_type = gRadio_bastards__newgame[7].current_value ? eNet_sequence_sequential : eNet_sequence_random; + pGame_options->random_car_choice = gRadio_bastards__newgame[8].current_value; + pGame_options->car_choice = gRadio_bastards__newgame[9].current_value; + pGame_options->starting_money_index = gRadio_bastards__newgame[10].current_value; } // IDA: void __usercall SetNetOptions(tNet_game_options *pGame_options@) void SetNetOptions(tNet_game_options* pGame_options) { LOG_TRACE("(%p)", pGame_options); - NOT_IMPLEMENTED(); + + gRadio_bastards__newgame[0].current_value = pGame_options->enable_text_messages; + gRadio_bastards__newgame[1].current_value = pGame_options->show_players_on_map; + gRadio_bastards__newgame[2].current_value = pGame_options->show_peds_on_map; + gRadio_bastards__newgame[3].current_value = pGame_options->show_powerups_on_map; + gRadio_bastards__newgame[4].current_value = pGame_options->powerup_respawn; + gRadio_bastards__newgame[5].current_value = !pGame_options->open_game; + gRadio_bastards__newgame[6].current_value = !pGame_options->grid_start; + gRadio_bastards__newgame[7].current_value = pGame_options->race_sequence_type == eNet_sequence_sequential; + gRadio_bastards__newgame[8].current_value = pGame_options->random_car_choice; + gRadio_bastards__newgame[9].current_value = pGame_options->car_choice; + gRadio_bastards__newgame[10].current_value = pGame_options->starting_money_index; } // IDA: void __usercall NetPlayCheckboxOn2(int pIndex@) void NetPlayCheckboxOn2(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + RunFlicAt(95, + gRadio_bastards__newgame[pIndex].left[0], + gRadio_bastards__newgame[pIndex].top + 1); } // IDA: void __usercall NetPlayCheckboxOff2(int pIndex@) void NetPlayCheckboxOff2(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + RunFlicAt(96, + gRadio_bastards__newgame[pIndex].left[0], + gRadio_bastards__newgame[pIndex].top + 1); } // IDA: void __usercall NetPlayCheckboxOn(int pIndex@) void NetPlayCheckboxOn(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + RemoveTransientBitmaps(1); + DontLetFlicFuckWithPalettes(); + TurnFlicTransparencyOn(); + NetPlayCheckboxOn2(pIndex); + TurnFlicTransparencyOff(); + LetFlicFuckWithPalettes(); } // IDA: void __usercall NetPlayCheckboxOff(int pIndex@) void NetPlayCheckboxOff(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + RemoveTransientBitmaps(1); + DontLetFlicFuckWithPalettes(); + TurnFlicTransparencyOn(); + NetPlayCheckboxOff2(pIndex); + TurnFlicTransparencyOff(); + LetFlicFuckWithPalettes(); } // IDA: void __usercall NetPlayRadioOn2(int pIndex@, int pValue@) void NetPlayRadioOn2(int pIndex, int pValue) { LOG_TRACE("(%d, %d)", pIndex, pValue); - NOT_IMPLEMENTED(); + + RunFlicAt(288, + gRadio_bastards__newgame[pIndex].left[pValue], + gRadio_bastards__newgame[pIndex].top + 1); } // IDA: void __usercall NetPlayRadioOff2(int pIndex@, int pValue@) void NetPlayRadioOff2(int pIndex, int pValue) { LOG_TRACE("(%d, %d)", pIndex, pValue); - NOT_IMPLEMENTED(); + + RunFlicAt(287, + gRadio_bastards__newgame[pIndex].left[pValue], + gRadio_bastards__newgame[pIndex].top + 1); } // IDA: void __usercall NetPlayRadioOn(int pIndex@, int pValue@) void NetPlayRadioOn(int pIndex, int pValue) { LOG_TRACE("(%d, %d)", pIndex, pValue); - NOT_IMPLEMENTED(); + + RemoveTransientBitmaps(1); + DontLetFlicFuckWithPalettes(); + TurnFlicTransparencyOn(); + NetPlayRadioOn2(pIndex, pValue); + TurnFlicTransparencyOff(); + LetFlicFuckWithPalettes(); } // IDA: void __usercall NetPlayRadioOff(int pIndex@, int pValue@) void NetPlayRadioOff(int pIndex, int pValue) { LOG_TRACE("(%d, %d)", pIndex, pValue); - NOT_IMPLEMENTED(); + + RemoveTransientBitmaps(1); + DontLetFlicFuckWithPalettes(); + TurnFlicTransparencyOn(); + NetPlayRadioOff2(pIndex, pValue); + TurnFlicTransparencyOff(); + LetFlicFuckWithPalettes(); } // IDA: void __cdecl DrawNOptInitialRadios() @@ -545,52 +941,142 @@ void DrawNOptInitialRadios(void) { int i; int j; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + RemoveTransientBitmaps(1); + DontLetFlicFuckWithPalettes(); + TurnFlicTransparencyOn(); + for (i = 0; i < COUNT_OF(gRadio_bastards__newgame); i++) { + if (gRadio_bastards__newgame[i].count < 2) { + if (gRadio_bastards__newgame[i].current_value) { + NetPlayCheckboxOn2(i); + } else { + NetPlayCheckboxOff2(i); + } + } else { + NetPlayRadioOn2(i, gRadio_bastards__newgame[i].current_value); + for (j = 0; j < gRadio_bastards__newgame[i].count; j++) { + if (j != gRadio_bastards__newgame[i].current_value) { + NetPlayRadioOff2(i, j); + } + } + } + } + TurnFlicTransparencyOff(); + LetFlicFuckWithPalettes(); } // IDA: void __usercall NetRadioChanged(int pIndex@, int pNew_value@) void NetRadioChanged(int pIndex, int pNew_value) { LOG_TRACE("(%d, %d)", pIndex, pNew_value); - NOT_IMPLEMENTED(); + + NetPlayRadioOff(pIndex, gRadio_bastards__newgame[pIndex].current_value); + NetPlayRadioOn(pIndex, pNew_value); + gRadio_bastards__newgame[pIndex].current_value = pNew_value; } // IDA: void __usercall NetCheckboxChanged(int pIndex@) void NetCheckboxChanged(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + if (gRadio_bastards__newgame[pIndex].current_value) { + NetPlayCheckboxOff(pIndex); + } else { + NetPlayCheckboxOn(pIndex); + } + gRadio_bastards__newgame[pIndex].current_value = !gRadio_bastards__newgame[pIndex].current_value; } // IDA: int __usercall NetOptLeft@(int *pCurrent_choice@, int *pCurrent_mode@) int NetOptLeft(int* pCurrent_choice, int* pCurrent_mode) { int new_value; LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + DRS3StartSound(gEffects_outlet, 3000); + if (gRadio_bastards__newgame[*pCurrent_choice - 3].count < 2) { + NetCheckboxChanged(*pCurrent_choice - 3); + } else { + new_value = gRadio_bastards__newgame[*pCurrent_choice - 3].current_value - 1; + if (new_value < 0) { + new_value = gRadio_bastards__newgame[*pCurrent_choice - 3].count - 1; + } + NetRadioChanged(*pCurrent_choice - 3, new_value); + } + return 1; } // IDA: int __usercall NetOptRight@(int *pCurrent_choice@, int *pCurrent_mode@) int NetOptRight(int* pCurrent_choice, int* pCurrent_mode) { int new_value; LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + DRS3StartSound(gEffects_outlet, 3000); + if (gRadio_bastards__newgame[*pCurrent_choice - 3].count < 2) { + NetCheckboxChanged(*pCurrent_choice - 3); + } else { + new_value = gRadio_bastards__newgame[*pCurrent_choice - 3].current_value + 1; + if (new_value == gRadio_bastards__newgame[*pCurrent_choice - 3].count) { + new_value = 0; + } + NetRadioChanged(*pCurrent_choice - 3, new_value); + } + return 1; } // IDA: int __usercall NetOptUp@(int *pCurrent_choice@, int *pCurrent_mode@) int NetOptUp(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (*pCurrent_mode == 0) { + *pCurrent_mode = 1; + *pCurrent_choice = 13; + DRS3StartSound(gEffects_outlet, 3000); + return 1; + } else if (*pCurrent_choice == 2) { + *pCurrent_mode = 0; + *pCurrent_choice = 0; + DRS3StartSound(gEffects_outlet, 3000); + return 1; + } else { + return 0; + } } // IDA: int __usercall NetOptDown@(int *pCurrent_choice@, int *pCurrent_mode@) int NetOptDown(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (*pCurrent_mode == 0) { + *pCurrent_mode = 1; + *pCurrent_choice = 3; + DRS3StartSound(gEffects_outlet, 3000); + return 1; + } else if (*pCurrent_choice == 14) { + *pCurrent_mode = 0; + *pCurrent_choice = 0; + DRS3StartSound(gEffects_outlet, 3000); + return 1; + } else { + return 0; + } } // IDA: int __usercall NetRadioClick@(int *pCurrent_choice@, int *pCurrent_mode@, int pX_offset@, int pY_offset@) int NetRadioClick(int* pCurrent_choice, int* pCurrent_mode, int pX_offset, int pY_offset) { int i; LOG_TRACE("(%p, %p, %d, %d)", pCurrent_choice, pCurrent_mode, pX_offset, pY_offset); - NOT_IMPLEMENTED(); + + if (gRadio_bastards__newgame[*pCurrent_choice - 3].count < 2) { + NetCheckboxChanged(*pCurrent_choice - 3); + } else { + for (i = gRadio_bastards__newgame[*pCurrent_choice - 3].count - 1; i >= 0; i--) { + if (gThe_interface_spec__newgame->mouse_areas[3].left[gGraf_data_index] + pX_offset + 3 >= gRadio_bastards__newgame[*pCurrent_choice - 3].left[i]) { + DRS3StartSound(gEffects_outlet, 3000); + NetRadioChanged(*pCurrent_choice - 3, i); + break; + } + } + } + return 0; } // IDA: void __cdecl RevertToDefaults() @@ -600,108 +1086,289 @@ void RevertToDefaults(void) { tNet_game_options net_options; int i; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + PathCat(the_path, gApplication_path, "NETDEFLT.TXT"); + f = DRfopen(the_path, "rt"); + if (f == NULL) { + return; + } + for (i = 0; i < gLast_game_type + 1; i++) { + ReadNetworkSettings(f, &net_options); + } + SetNetOptions(&net_options); + DrawNOptInitialRadios(); + fclose(f); } // IDA: void __cdecl DefaultNetSettings() void DefaultNetSettings(void) { FILE* f; int i; - STUB(); + tPath_name the_path; // added + + PathCat(the_path, gApplication_path, "NETDEFLT.TXT"); + f = DRfopen(the_path, "rt"); + if (f == NULL) { + return; + } + ReadNetworkSettings(f, gNet_settings); + rewind(f); + for (i = 0; i < COUNT_OF(gNet_settings) - 1; i++) { + ReadNetworkSettings(f, &gNet_settings[i + 1]); + } + fclose(f); } // IDA: int __usercall NetOptGoAhead@(int *pCurrent_choice@, int *pCurrent_mode@) int NetOptGoAhead(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (*pCurrent_mode == 0) { + if (*pCurrent_choice == 2) { + RevertToDefaults(); + return 0; + } else { + return 1; + } + } else { + NetOptRight(pCurrent_choice, pCurrent_mode); + return 0; + } } // IDA: void __usercall NetPlotAGraphBox(int pIndex@, int pColour_value@) void NetPlotAGraphBox(int pIndex, int pColour_value) { LOG_TRACE("(%d, %d)", pIndex, pColour_value); - NOT_IMPLEMENTED(); + + if (pIndex >= 0) { + DrawRRectangle(gBack_screen, + gThe_interface_spec__newgame->mouse_areas[pIndex + 3].left[gGraf_data_index], + gThe_interface_spec__newgame->mouse_areas[pIndex + 3].top[gGraf_data_index], + gThe_interface_spec__newgame->mouse_areas[pIndex + 3].right[gGraf_data_index], + gThe_interface_spec__newgame->mouse_areas[pIndex + 3].bottom[gGraf_data_index], + pColour_value); + } } // IDA: void __usercall NetDrawAGraphBox(int pIndex@) void NetDrawAGraphBox(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + NetPlotAGraphBox(pIndex, 45); } // IDA: void __usercall NetEraseAGraphBox(int pIndex@) void NetEraseAGraphBox(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + NetPlotAGraphBox(pIndex, 0); } // IDA: void __usercall DrawNetOptBox(int pCurrent_choice@, int pCurrent_mode@) void DrawNetOptBox(int pCurrent_choice, int pCurrent_mode) { LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (gRadio_selected != pCurrent_choice) { + NetEraseAGraphBox(gRadio_selected - 3); + NetDrawAGraphBox(pCurrent_choice - 3); + gRadio_selected = pCurrent_choice; + } } // IDA: void __usercall DoNetOptions(tNet_game_options *pGame_options@) void DoNetOptions(tNet_game_options* pGame_options) { - static tFlicette flicker_on[14]; - static tFlicette flicker_off[14]; - static tFlicette push[14]; - static tMouse_area mouse_areas[14]; - static tInterface_spec interface_spec; + static tFlicette flicker_on[14] = { + { 43, { 169, 90 }, { 156, 398 } }, + { 43, { 236, 440 }, { 156, 398 } }, + { 43, { 37, 440 }, { 156, 398 } }, + { 68, { 81, 98 }, { 32, 86 } }, + { 75, { 81, 98 }, { 43, 108 } }, + { 77, { 81, 98 }, { 54, 130 } }, + { 79, { 81, 98 }, { 65, 161 } }, + { 112, { 81, 98 }, { 76, 182 } }, + { 127, { 81, 98 }, { 86, 214 } }, + { 129, { 81, 98 }, { 97, 235 } }, + { 134, { 81, 98 }, { 108, 266 } }, + { 137, { 81, 98 }, { 119, 288 } }, + { 139, { 81, 98 }, { 130, 310 } }, + { 143, { 81, 98 }, { 141, 331 } }, + }; + static tFlicette flicker_off[14] = { + { 42, { 169, 90 }, { 156, 398 } }, + { 42, { 236, 440 }, { 156, 398 } }, + { 42, { 37, 440 }, { 156, 398 } }, + { 69, { 81, 98 }, { 32, 86 } }, + { 76, { 81, 98 }, { 43, 108 } }, + { 78, { 81, 98 }, { 54, 130 } }, + { 109, { 81, 98 }, { 65, 161 } }, + { 113, { 81, 98 }, { 76, 182 } }, + { 128, { 81, 98 }, { 86, 214 } }, + { 133, { 81, 98 }, { 97, 235 } }, + { 136, { 81, 98 }, { 108, 266 } }, + { 138, { 81, 98 }, { 119, 288 } }, + { 142, { 81, 98 }, { 130, 310 } }, + { 148, { 81, 98 }, { 141, 331 } }, + }; + static tFlicette push[14] = { + { 154, { 169, 90 }, { 156, 398 } }, + { 45, { 236, 440 }, { 156, 398 } }, + { 67, { 37, 440 }, { 156, 398 } }, + { 68, { 81, 98 }, { 32, 86 } }, + { 75, { 81, 98 }, { 43, 108 } }, + { 77, { 81, 98 }, { 54, 130 } }, + { 79, { 81, 98 }, { 65, 161 } }, + { 112, { 81, 98 }, { 76, 182 } }, + { 127, { 81, 98 }, { 86, 214 } }, + { 129, { 81, 98 }, { 97, 235 } }, + { 134, { 81, 98 }, { 108, 266 } }, + { 137, { 81, 98 }, { 119, 288 } }, + { 139, { 81, 98 }, { 130, 310 } }, + { 143, { 81, 98 }, { 141, 331 } }, + }; + static tMouse_area mouse_areas[14] = { + { { 169, 90 }, { 156, 396 }, { 232, 214 }, { 176, 444 }, 0, 0, 0, NULL }, + { { 236, 440 }, { 156, 396 }, { 299, 552 }, { 176, 444 }, 1, 0, 0, NULL }, + { { 37, 98 }, { 156, 84 }, { 100, 568 }, { 176, 103 }, 2, 0, 0, NULL }, + { { 61, 98 }, { 30, 106 }, { 270, 568 }, { 40, 125 }, 3, 1, 0, NetRadioClick }, + { { 61, 98 }, { 41, 127 }, { 270, 568 }, { 51, 146 }, 4, 1, 0, NetRadioClick }, + { { 61, 98 }, { 52, 158 }, { 270, 568 }, { 62, 178 }, 5, 1, 0, NetRadioClick }, + { { 61, 98 }, { 63, 180 }, { 270, 568 }, { 73, 199 }, 6, 1, 0, NetRadioClick }, + { { 61, 98 }, { 74, 192 }, { 270, 568 }, { 84, 230 }, 7, 1, 0, NetRadioClick }, + { { 61, 98 }, { 84, 233 }, { 270, 568 }, { 94, 252 }, 8, 1, 0, NetRadioClick }, + { { 61, 98 }, { 95, 264 }, { 270, 568 }, { 105, 283 }, 9, 1, 0, NetRadioClick }, + { { 61, 98 }, { 106, 286 }, { 270, 568 }, { 116, 305 }, 10, 1, 0, NetRadioClick }, + { { 61, 98 }, { 117, 307 }, { 270, 322 }, { 127, 326 }, 11, 1, 0, NetRadioClick }, + { { 61, 98 }, { 128, 329 }, { 270, 322 }, { 138, 348 }, 12, 1, 0, NetRadioClick }, + { { 61, 98 }, { 139, 358 }, { 270, 322 }, { 149, 377 }, 13, 1, 0, NetRadioClick }, + }; + static tInterface_spec interface_spec = { + 0, 65, 0, 66, 66, 66, -1, + { -1, 0 }, { -1, 0 }, { 0, 3 }, { 2, 13 }, { NULL, NetOptLeft }, + { -1, 0 }, { 1, 0 }, { 0, 3 }, { 2, 13 }, { NULL, NetOptRight }, + { -1, -1 }, { 0, -1 }, { 0, 2 }, { 0, 13 }, { NetOptUp, NetOptUp }, + { -1, -1 }, { 1, 1 }, { 0, 3 }, { 0, 14 }, { NetOptDown, NetOptDown }, + { 1, 1 }, { NetOptGoAhead, NetOptGoAhead }, { 1, 1 }, { NULL, NULL }, + NULL, DrawNetOptBox, 0, + NULL, DrawNOptInitialRadios, NULL, 0, { 0, 0 }, NULL, 1, 1, + COUNT_OF(flicker_on), flicker_on, flicker_off, push, + COUNT_OF(mouse_areas), mouse_areas, + 0, NULL + }; LOG_TRACE("(%p)", pGame_options); - NOT_IMPLEMENTED(); + + gThe_interface_spec__newgame = &interface_spec; + gRadio_selected = -1; + LoadFont(12); + SetNetOptions(pGame_options); + if (DoInterfaceScreen(&interface_spec, 0, 0) == 0) { + GetNetOptions(pGame_options); + } + DisposeFont(12); } // IDA: void __usercall PlayRadioOn(int pIndex@) // Suffix added to avoid duplicate symbol void PlayRadioOn__newgame(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + RunFlicAt(288, + gThe_interface_spec__newgame->pushed_flics[pIndex + 4].x[gGraf_data_index], + gThe_interface_spec__newgame->pushed_flics[pIndex + 4].y[gGraf_data_index]); } // IDA: void __usercall PlayRadioOff(int pIndex@) // Suffix added to avoid duplicate symbol void PlayRadioOff__newgame(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + RunFlicAt(287, + gThe_interface_spec__newgame->pushed_flics[pIndex + 4].x[gGraf_data_index], + gThe_interface_spec__newgame->pushed_flics[pIndex + 4].y[gGraf_data_index]); } // IDA: void __usercall SetOptions(tNet_game_type pGame_type@, tNet_game_options *pGame_options@) void SetOptions(tNet_game_type pGame_type, tNet_game_options* pGame_options) { LOG_TRACE("(%d, %p)", pGame_type, pGame_options); - NOT_IMPLEMENTED(); + + pGame_options->show_players_on_map = gNet_settings[0].show_players_on_map; + pGame_options->show_peds_on_map = gNet_settings[pGame_type + 1].show_peds_on_map; + pGame_options->enable_text_messages = gNet_settings[0].enable_text_messages; + pGame_options->powerup_respawn = gNet_settings[0].powerup_respawn; + pGame_options->show_powerups_on_map = gNet_settings[0].show_powerups_on_map; + pGame_options->open_game = gNet_settings[pGame_type + 1].open_game; + pGame_options->grid_start = gNet_settings[pGame_type + 1].grid_start; + pGame_options->random_car_choice = gNet_settings[0].random_car_choice; + pGame_options->car_choice = gNet_settings[0].car_choice; + pGame_options->starting_money_index = gNet_settings[0].starting_money_index; + pGame_options->race_sequence_type = gNet_settings[0].race_sequence_type; } // IDA: void __cdecl DrawNetChooseInitial() void DrawNetChooseInitial(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + PlayRadioOn__newgame(gLast_game_type); } // IDA: int __usercall NetChooseGoAhead@(int *pCurrent_choice@, int *pCurrent_mode@) int NetChooseGoAhead(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (*pCurrent_mode == 0) { + return 1; + } else { + if (*pCurrent_choice - 4 != gLast_game_type) { + RemoveTransientBitmaps(1); + DontLetFlicFuckWithPalettes(); + TurnFlicTransparencyOn(); + PlayRadioOff__newgame(gLast_game_type); + gLast_game_type = *pCurrent_choice - 4; + PlayRadioOn__newgame(gLast_game_type); + LoadRaces(gRace_list, &gNumber_of_races, gLast_game_type); + SetOptions(gLast_game_type, gOptions); + TurnFlicTransparencyOff(); + LetFlicFuckWithPalettes(); + if (gRace_index >= gNumber_of_races) { + gRace_index = PickNetRace(-1, gNet_race_sequence__newgame); + } + if (!gMouse_in_use) { + *pCurrent_mode = 0; + *pCurrent_choice = 0; + } + } + return 0; + } } // IDA: void __usercall PlotAGraphBox(int pIndex@, int pColour_value@) // Suffix added to avoid duplicate symbol void PlotAGraphBox__newgame(int pIndex, int pColour_value) { LOG_TRACE("(%d, %d)", pIndex, pColour_value); - NOT_IMPLEMENTED(); + + if (pIndex >= 0) { + DrawRRectangle(gBack_screen, + gThe_interface_spec__newgame->mouse_areas[pIndex].left[gGraf_data_index], + gThe_interface_spec__newgame->mouse_areas[pIndex].top[gGraf_data_index], + gThe_interface_spec__newgame->mouse_areas[pIndex].right[gGraf_data_index], + gThe_interface_spec__newgame->mouse_areas[pIndex].bottom[gGraf_data_index], + pColour_value); + } } // IDA: void __usercall DrawAGraphBox(int pIndex@) // Suffix added to avoid duplicate symbol void DrawAGraphBox__newgame(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + PlotAGraphBox__newgame(pIndex, 45); } // IDA: void __usercall EraseAGraphBox(int pIndex@) // Suffix added to avoid duplicate symbol void EraseAGraphBox__newgame(int pIndex) { LOG_TRACE("(%d)", pIndex); - NOT_IMPLEMENTED(); + + PlotAGraphBox__newgame(pIndex, 0); } // IDA: void __usercall DrawNetChoose(int pCurrent_choice@, int pCurrent_mode@) @@ -710,13 +1377,58 @@ void DrawNetChoose(int pCurrent_choice, int pCurrent_mode) { tU32* k; int i; LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (gLast_net_choose_box >= 0) { + EraseAGraphBox__newgame(gLast_net_choose_box); + } + if (pCurrent_mode != 0) { + gLast_net_choose_box = pCurrent_choice; + DrawAGraphBox__newgame(pCurrent_choice); + } else { + gLast_net_choose_box = -1; + } + BrPixelmapRectangleFill(gBack_screen, + gCurrent_graf_data->net_descr_race_l, + gCurrent_graf_data->net_choose_race_y, + gCurrent_graf_data->net_descr_race_r - gCurrent_graf_data->net_descr_race_l, + gFonts[10].height + 1 - (TranslationMode() ? 2 : 0), 0); + sprintf(s, "%s %s", GetMiscString(201), gRace_list[gRace_index].name); + DRPixelmapCentredText(gBack_screen, + gCurrent_graf_data->net_choose_race_x, + gCurrent_graf_data->net_choose_race_y, + &gFonts[10], s); + BrPixelmapRectangleFill(gBack_screen, + gCurrent_graf_data->net_descr_race_l, + gCurrent_graf_data->net_descr_race_top - (TranslationMode() ? 2 : 0), + gCurrent_graf_data->net_descr_race_r - gCurrent_graf_data->net_descr_race_l, + gCurrent_graf_data->net_descr_race_bot - gCurrent_graf_data->net_descr_race_top, + 0); + OoerrIveGotTextInMeBoxMissus(9, + GetMiscString(194 + (pCurrent_mode ? pCurrent_choice - 4 : gLast_game_type)), + gBack_screen, + gCurrent_graf_data->net_descr_race_l, + gCurrent_graf_data->net_descr_race_top, + gCurrent_graf_data->net_descr_race_r, + gCurrent_graf_data->net_descr_race_bot, + 1); + k = KevKeyService(); + if (k[0] == 0x2212d981 && k[1] == 0x90e8cf51) { + DRS3StartSound(gEffects_outlet, 3202); + DRS3StartSound(gEffects_outlet, 3202); + for (i = 0; i < gNumber_of_racers; i++) { + if (gOpponents[i].network_availability == eNet_avail_never) { + gOpponents[i].network_availability = eNet_avail_all; + } + } + } } // IDA: int __usercall NetChooseLR@(int *pCurrent_choice@, int *pCurrent_mode@) int NetChooseLR(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + *pCurrent_choice = gLast_game_type + 4; + return 0; } // IDA: void __usercall SetGameTarget(tNet_game_type *pGame_type@, tNet_game_options *pGame_options@) @@ -742,14 +1454,111 @@ void SetGameTarget(tNet_game_type* pGame_type, tNet_game_options* pGame_options) // IDA: int __usercall NetGameChoices@(tNet_game_type *pGame_type@, tNet_game_options *pGame_options@, int *pRace_index@) int NetGameChoices(tNet_game_type* pGame_type, tNet_game_options* pGame_options, int* pRace_index) { - static tFlicette flicker_on[11]; - static tFlicette flicker_off[11]; - static tFlicette push[11]; - static tMouse_area mouse_areas[11]; - static tInterface_spec interface_spec; + static tFlicette flicker_on[11] = { + { 43, { 226, 90 }, { 117, 398 } }, + { 43, { 226, 440 }, { 148, 398 } }, + { 43, { 226, 98 }, { 42, 86 } }, + { 43, { 226, 98 }, { 74, 108 } }, + { 162, { 74, 98 }, { 73, 130 } }, + { 163, { 74, 98 }, { 83, 161 } }, + { 164, { 74, 98 }, { 93, 182 } }, + { 165, { 74, 98 }, { 103, 214 } }, + { 166, { 74, 98 }, { 113, 235 } }, + { 167, { 74, 98 }, { 123, 266 } }, + { 168, { 74, 98 }, { 133, 288 } }, + }; + static tFlicette flicker_off[11] = { + { 42, { 226, 90 }, { 117, 398 } }, + { 42, { 226, 440 }, { 148, 398 } }, + { 42, { 226, 98 }, { 42, 86 } }, + { 42, { 226, 98 }, { 74, 108 } }, + { 182, { 74, 98 }, { 73, 130 } }, + { 183, { 74, 98 }, { 83, 161 } }, + { 184, { 74, 98 }, { 93, 182 } }, + { 185, { 74, 98 }, { 103, 214 } }, + { 186, { 74, 98 }, { 113, 235 } }, + { 187, { 74, 98 }, { 123, 266 } }, + { 188, { 74, 98 }, { 133, 288 } }, + }; + static tFlicette push[11] = { + { 88, { 227, 90 }, { 117, 398 } }, + { 45, { 226, 440 }, { 148, 398 } }, + { 195, { 227, 98 }, { 42, 86 } }, + { 124, { 226, 98 }, { 74, 108 } }, + { 162, { 74, 98 }, { 73, 130 } }, + { 163, { 74, 98 }, { 83, 161 } }, + { 164, { 74, 98 }, { 93, 182 } }, + { 165, { 74, 98 }, { 103, 214 } }, + { 166, { 74, 98 }, { 113, 235 } }, + { 167, { 74, 98 }, { 123, 266 } }, + { 168, { 74, 98 }, { 133, 288 } }, + }; + static tMouse_area mouse_areas[11] = { + { { 226, 90 }, { 117, 396 }, { 290, 214 }, { 137, 444 }, 0, 0, 0, NULL }, + { { 226, 440 }, { 148, 396 }, { 290, 552 }, { 168, 444 }, 1, 0, 0, NULL }, + { { 226, 98 }, { 42, 84 }, { 290, 568 }, { 62, 103 }, 2, 0, 0, NULL }, + { { 226, 98 }, { 74, 106 }, { 290, 568 }, { 94, 125 }, 3, 0, 0, NULL }, + { { 53, 98 }, { 71, 127 }, { 211, 568 }, { 79, 146 }, 4, 1, 0, NULL }, + { { 53, 98 }, { 81, 158 }, { 211, 568 }, { 89, 178 }, 5, 1, 0, NULL }, + { { 53, 98 }, { 91, 180 }, { 211, 568 }, { 99, 199 }, 6, 1, 0, NULL }, + { { 53, 98 }, { 101, 192 }, { 211, 568 }, { 109, 230 }, 7, 1, 0, NULL }, + { { 53, 98 }, { 111, 233 }, { 211, 568 }, { 119, 252 }, 8, 1, 0, NULL }, + { { 53, 98 }, { 121, 264 }, { 211, 568 }, { 129, 283 }, 9, 1, 0, NULL }, + { { 53, 98 }, { 131, 264 }, { 211, 568 }, { 139, 283 }, 10, 1, 0, NULL }, + }; + static tInterface_spec interface_spec = { + 0, 122, 0, 0, 0, 0, -1, + { 1, 0 }, { 4, -10 }, { 4, 0 }, { 4, 0 }, { NetChooseLR, NULL }, + { 1, 0 }, { 3, -10 }, { 4, 0 }, { 4, 0 }, { NetChooseLR, NULL }, + { -1, -1 }, { -1, -1 }, { 0, 4 }, { 3, 10 }, { NULL, NULL }, + { -1, -1 }, { 1, 1 }, { 0, 4 }, { 3, 10 }, { NULL, NULL }, + { 1, 1 }, { NetChooseGoAhead, NetChooseGoAhead }, { 1, 1 }, { NULL, NULL }, + NULL, DrawNetChoose, 0, NULL, DrawNetChooseInitial, NULL, 0, { 0, 0 }, NULL, + 1, 1, + COUNT_OF(flicker_on), flicker_on, flicker_off, push, + COUNT_OF(mouse_areas), mouse_areas, + 0, NULL + + }; int result; LOG_TRACE("(%p, %p, %p)", pGame_type, pGame_options, pRace_index); - NOT_IMPLEMENTED(); + + gRace_index = *pRace_index; + gLast_game_type = *pGame_type; + do { + LoadFont(10); + LoadFont(9); + gThe_interface_spec__newgame = &interface_spec; + gLast_net_choose_box = -1; + gOptions = pGame_options; + gNet_race_sequence__newgame = pGame_options->race_sequence_type; + result = DoInterfaceScreen(&interface_spec, 0, 0); + if (result || !pGame_options->random_car_choice) { + RunFlic(123); + } else { + FadePaletteDown(); + } + DisposeFont(9); + DisposeFont(10); + switch (result) { + case 0: + *pGame_type = gLast_game_type; + *pRace_index = gRace_index; + break; + case 2: + ChangeRace(&gRace_index, 1, pGame_options->race_sequence_type); + break; + case 3: + DoNetOptions(pGame_options); + break; + } + } while (result > 1); + gLast_game_type = *pGame_type; + gNet_settings[0] = *pGame_options; + gNet_settings[gLast_game_type + 1] = *pGame_options; + SaveOptions(); + SetGameTarget(pGame_type, pGame_options); + return result == 0; } // IDA: void __usercall ReadNetGameChoices(tNet_game_type *pGame_type@, tNet_game_options *pGame_options@, int *pRace_index@) @@ -771,14 +1580,23 @@ int ChooseStartRace(int* pRank) { // IDA: void __usercall SetUpOtherNetThings(tNet_game_details *pNet_game@) void SetUpOtherNetThings(tNet_game_details* pNet_game) { LOG_TRACE("(%p)", pNet_game); - NOT_IMPLEMENTED(); + + StartLoadingScreen(); + gProgram_state.skill_level = 1; + InitGame(pNet_game->start_race); } // IDA: void __usercall RequestCarDetails(tNet_game_details *pNet_game@) void RequestCarDetails(tNet_game_details* pNet_game) { tNet_message* message; LOG_TRACE("(%p)", pNet_game); - NOT_IMPLEMENTED(); + + gReceived_car_details = 0; + if (gNet_mode == eNet_mode_none) { + gNet_mode = eNet_mode_thinking_about_it; + } + message = NetBuildMessage(NETMSGID_CARDETAILSREQ, 0); + NetGuaranteedSendMessageToAddress(pNet_game, message, &pNet_game->pd_net_info.addr_in, NULL); } // IDA: int __cdecl PickARandomCar() @@ -787,14 +1605,26 @@ int PickARandomCar(void) { int cars[120]; int array_size; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + array_size = 0; + for (i = 0; i < gNumber_of_racers; i++) { + if (gCar_details[i].ownership == eCar_owner_none) { + cars[array_size] = i; + array_size++; + if (gOpponents[i].network_availability == eNet_avail_all) { + cars[array_size] = i; + array_size++; + } + } + } + return cars[IRandomBetween(0, array_size - 1)]; } // IDA: void __usercall PollCarDetails(tNet_game_details *pNet_game@) void PollCarDetails(tNet_game_details* pNet_game) { LOG_TRACE("(%p)", pNet_game); - if (gReceived_car_details != 0) { + if (gReceived_car_details) { RequestCarDetails(pNet_game); } } @@ -803,7 +1633,34 @@ void PollCarDetails(tNet_game_details* pNet_game) { void SetNetAvailability(tNet_game_options* pOptions) { int i; LOG_TRACE("(%p)", pOptions); - NOT_IMPLEMENTED(); + + for (i = 0; i < gNumber_of_racers; i++) { + switch (gOpponents[i].network_availability) { + case eNet_avail_never: + gCar_details[i].ownership = eCar_owner_not_allowed; + break; + case eNet_avail_eagle: + if (pOptions->car_choice == eNet_car_annie) { + gCar_details[i].ownership = eCar_owner_not_allowed; + } else { + gCar_details[i].ownership = eCar_owner_none; + } + break; + case eNet_avail_hawk: + if (pOptions->car_choice == eNet_car_frankie) { + gCar_details[i].ownership = eCar_owner_not_allowed; + } else { + gCar_details[i].ownership = eCar_owner_none; + } + break; + case eNet_avail_all: + if (pOptions->car_choice == eNet_car_all) { + gCar_details[i].ownership = eCar_owner_none; + } else { + gCar_details[i].ownership = eCar_owner_not_allowed; + } + } + } } // IDA: int __usercall ChooseNetCar@(tNet_game_details *pNet_game@, tNet_game_options *pOptions@, int *pCar_index@, int pIm_the_host_so_fuck_off@) @@ -814,7 +1671,51 @@ int ChooseNetCar(tNet_game_details* pNet_game, tNet_game_options* pOptions, int* int car_index; int the_car_index; LOG_TRACE("(%p, %p, %p, %d)", pNet_game, pOptions, pCar_index, pIm_the_host_so_fuck_off); - NOT_IMPLEMENTED(); + + if (!pOptions->random_car_choice || pIm_the_host_so_fuck_off) { + gNet_options = pOptions; + if (pIm_the_host_so_fuck_off) { + SetNetAvailability(pOptions); + } else { + RequestCarDetails(pNet_game); + start_time = PDGetTotalTime(); + while (!gReceived_car_details && PDGetTotalTime() - start_time < 10000) { + NetService(0); + } + gNet_mode = eNet_mode_none; + if (!gReceived_car_details) { + gNet_mode = eNet_mode_none; + return 0; + } + } + if (pOptions->random_car_choice) { + *pCar_index = PickARandomCar(); + if (pIm_the_host_so_fuck_off && *pCar_index >= 0) { + gCar_details[*pCar_index].ownership = eCar_owner_someone; + } + result = 1; + } else { + if (*pCar_index < 0) { + *pCar_index = PickARandomCar(); + car_index = 0; + for (i = 0; i < gNumber_of_racers; i++) { + if (gCar_details[i].ownership != eCar_owner_not_allowed) { + gProgram_state.cars_available[car_index] = i; + car_index++; + } + } + gProgram_state.number_of_cars = car_index; + } + result = ChangeCar(1, pCar_index, pNet_game); + gNet_mode = eNet_mode_none; + if (pIm_the_host_so_fuck_off) { + gCar_details[*pCar_index].ownership = eCar_owner_someone; + } + } + } else { + result = 1; + } + return result; } // IDA: void __cdecl InitNetStorageSpace() @@ -822,7 +1723,7 @@ void InitNetStorageSpace(void) { int i; LOG_TRACE("()"); - for (i = 0; i < 6; i++) { + for (i = 0; i < COUNT_OF(gNet_players); i++) { gCurrent_race.opponent_list[i].car_spec = NULL; } gNet_storage_allocated = 1; @@ -849,6 +1750,7 @@ int DoMultiPlayerStart(void) { tNet_game_options new_game_options; int start_rank; int car_index; + int race_index; // added by dethrace LOG_TRACE("()"); if (harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) { @@ -856,5 +1758,87 @@ int DoMultiPlayerStart(void) { DoFeatureUnavailableInDemo(); return 0; } - NOT_IMPLEMENTED(); + + if (gAusterity_mode) { + NetFullScreenMessage(192, 0); + return 0; + } + if (NetInitialise()) { + SuspendPendingFlic(); + DoErrorInterface(76); + return 0; + } + gSynch_race_start = 0; + gPending_race = -1; + gCurrent_race.number_of_racers = 0; + gAsk_time = 0; + AboutToLoadFirstCar(); + result = JoinOrHostGame(&game_to_join); + switch (result) { + case eJoin_or_host_cancel: + return 0; + case eJoin_or_host_join: + gProgram_state.frank_or_anniness = eFrankie; + if (!CarmaCDinDriveOrFullGameInstalled()) { + DoErrorInterface(223); + return 0; + } + car_index = -1; + // Abusing 'start_rank' here, it's probably better to introduce a new variable name (e.g. join_result) + start_rank = -4; + while (start_rank == -4) { + start_rank = 0; + if (!ChooseNetCar(game_to_join, &game_to_join->options, &car_index, 0)) { + continue; + } + StartLoadingScreen(); + InitNetStorageSpace(); + start_rank = NetJoinGame(game_to_join, gProgram_state.player_name[0], car_index); + if (start_rank == 0) { + LoadRaces(gRace_list, &gNumber_of_races, gCurrent_net_game->type); + SetUpOtherNetThings(game_to_join); + ReenableNetService(); + strcpy(s, gProgram_state.player_name[0]); + strcat(s, " "); + strcat(s, GetMiscString(58)); + NetSendHeadupToAllPlayers(s); + start_rank = 1; + } else { + DisposeNetStorageSpace(); + } + } + if (start_rank <= 0) { + NetDisposeGameDetails(game_to_join); + return 0; + } else { + return 1; + } + case eJoin_or_host_host: + gProgram_state.frank_or_anniness = eFrankie; + if (!OriginalCarmaCDinDrive()) { + DoErrorInterface(223); + return 0; + } + car_index = -1; + ReadNetGameChoices(&new_game_type, &new_game_options, &start_rank); + LoadRaces(gRace_list, &gNumber_of_races, new_game_type); + start_rank = PickNetRace(-1, new_game_options.race_sequence_type); + if (NetGameChoices(&new_game_type, &new_game_options, &start_rank) != 0 + && ChooseNetCar(gCurrent_net_game, &new_game_options, &car_index, 1) != 0) { + StartLoadingScreen(); + InitNetStorageSpace(); + if (NetHostGame(new_game_type, &new_game_options, start_rank, gProgram_state.player_name[0], car_index) != NULL) { + SetUpOtherNetThings(gCurrent_net_game); + ReenableNetService(); + return 1; + } else { + DisposeNetStorageSpace(); + ReenableNetService(); + NetLeaveGame(gCurrent_net_game); + return 0; + } + } + default: + return 0; + } } diff --git a/src/DETHRACE/common/pedestrn.c b/src/DETHRACE/common/pedestrn.c index 619ea259..6119cfd5 100644 --- a/src/DETHRACE/common/pedestrn.c +++ b/src/DETHRACE/common/pedestrn.c @@ -1989,13 +1989,13 @@ void SendPedestrian(tPedestrian_data* pPedestrian, int pIndex) { size_decider = 1; } the_message = NULL; - the_contents = NetGetBroadcastContents(0x19, size_decider); + the_contents = NetGetBroadcastContents(NETMSGID_PEDESTRIAN, size_decider); } else { size_decider = 2; if (pPedestrian->current_frame == pPedestrian->sequences[pPedestrian->current_sequence].number_of_frames - 1) { pPedestrian->sent_dead_message++; } - the_message = NetBuildMessage(0x19, size_decider); + the_message = NetBuildMessage(NETMSGID_PEDESTRIAN, size_decider); the_contents = &the_message->contents; } the_contents->data.pedestrian.index = pIndex; diff --git a/src/DETHRACE/common/pratcam.c b/src/DETHRACE/common/pratcam.c index 8edd92d1..79b322d5 100644 --- a/src/DETHRACE/common/pratcam.c +++ b/src/DETHRACE/common/pratcam.c @@ -294,6 +294,12 @@ void PratcamEvent(int pIndex) { if (gInterface_within_race_mode) { return; } +#if defined(DETHRACE_FIX_BUGS) + // In low memory mode, `gPratcam_sequences`is not allocated and thus unsafe to access + if (gAusterity_mode) { + return; + } +#endif if (gPratcam_sequences[pIndex].precedence <= gCurrent_pratcam_precedence) { return; } diff --git a/src/DETHRACE/common/racestrt.c b/src/DETHRACE/common/racestrt.c index 5831c3a1..3ccae3df 100644 --- a/src/DETHRACE/common/racestrt.c +++ b/src/DETHRACE/common/racestrt.c @@ -14,9 +14,12 @@ #include "input.h" #include "intrface.h" #include "loading.h" +#include "netgame.h" +#include "network.h" #include "newgame.h" #include "opponent.h" #include "pd/sys.h" +#include "racestrt.h" #include "sound.h" #include "structur.h" #include "utility.h" @@ -37,7 +40,7 @@ tParts_category gPart_category; tU32 gNet_synch_start; tNet_game_details* gChoose_car_net_game; int gPart_index; -int gChallenger_index__racestrt; // suffix added to avoid duplicate symbol +int gChallenger_index__racestrt; // suffix added to avoid duplicate symbol tGrid_draw gDraw_grid_status; tNet_sequence_type gNet_race_sequence__racestrt; // suffix added to avoid duplicate symbol br_pixelmap* gTaken_image; @@ -2495,20 +2498,38 @@ void CheckPlayersAreResponding(void) { tU32 time; tNet_message* message; LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + time = PDGetTotalTime(); + for (i = 0; i < gNumber_of_net_players; i++) { + if (i != gThis_net_player_index && time - gNet_players[i].last_heard_from_him > 20000) { + gNet_players[i].player_status = ePlayer_status_not_responding; + } + } + if (gNet_mode == eNet_mode_client && gLast_host_query == 0) { + message = NetBuildMessage(NETMSGID_HOSTQUERY, 0); + NetGuaranteedSendMessageToHost(gCurrent_net_game, message, NULL); + gLast_host_query = time; + } } // IDA: void __cdecl NetSynchStartStart() void NetSynchStartStart(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + CheckPlayersAreResponding(); } // IDA: void __usercall DrawAnItem(int pX@, int pY_index@, int pFont_index@, char *pText@) // Suffix added to avoid duplicate symbol void DrawAnItem__racestrt(int pX, int pY_index, int pFont_index, char* pText) { LOG_TRACE("(%d, %d, %d, \"%s\")", pX, pY_index, pFont_index, pText); - NOT_IMPLEMENTED(); + + TransBrPixelmapText(gBack_screen, + pX, + gCurrent_graf_data->start_synch_top + gCurrent_graf_data->start_synch_y_pitch * pY_index, + pFont_index, + gFont_7, + pText); } // IDA: void __usercall NetSynchStartDraw(int pCurrent_choice@, int pCurrent_mode@) @@ -2517,51 +2538,272 @@ void NetSynchStartDraw(int pCurrent_choice, int pCurrent_mode) { int number_ready; char s[256]; LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + number_ready = 0; + CheckPlayersAreResponding(); + NetPlayerStatusChanged(ePlayer_status_ready); + for (i = 0; i < COUNT_OF(gNet_players); i++) { + BrPixelmapRectangleFill(gBack_screen, + gCurrent_graf_data->start_synch_x_0, + gCurrent_graf_data->start_synch_y_pitch * i + gCurrent_graf_data->start_synch_top, + gCurrent_graf_data->start_synch_x_r - gCurrent_graf_data->start_synch_x_1, + gFont_7->glyph_y, + 0); + } + for (i = 0; i < gNumber_of_net_players; i++) { + strcpy(s, gNet_players[i].player_name); + if (gNet_players[i].host) { + strcat(s, " -"); + strcat(s, GetMiscString(88)); + strcat(s, "-"); + } + TurnOffPaletteConversion(); + DRPixelmapRectangleMaskedCopy(gBack_screen, + gCurrent_graf_data->start_synch_x_0, + gCurrent_graf_data->start_synch_top + 1 + gCurrent_graf_data->start_synch_y_pitch * i, + gIcons_pix, + 0, + gNet_players[i].car_index * gCurrent_graf_data->net_head_icon_height, + gIcons_pix->width, + gCurrent_graf_data->net_head_icon_height); + TurnOnPaletteConversion(); + DrawAnItem__racestrt( + gCurrent_graf_data->start_synch_x_1, + i, + (gNet_players[i].player_status == ePlayer_status_ready) ? 66 : 4, + s); + DrawAnItem__racestrt(gCurrent_graf_data->start_synch_x_2, + i, + (gNet_players[i].player_status == ePlayer_status_ready) ? 83 : ((gNet_players[i].player_status == ePlayer_status_not_responding) ? 247 : 4), + GetMiscString(77 + gNet_players[i].player_status)); + if (gNet_players[i].player_status == ePlayer_status_ready) { + number_ready++; + } + } + if (gNet_mode == eNet_mode_host && gNumber_of_net_players == number_ready && gNumber_of_net_players > 1 && (!gNo_races_yet || gNumber_of_net_players == 6)) { + SignalToStartRace(); + gSynch_race_start = 1; + } } // IDA: int __usercall NetSynchStartDone@(int pCurrent_choice@, int pCurrent_mode@, int pGo_ahead@, int pEscaped@, int pTimed_out) int NetSynchStartDone(int pCurrent_choice, int pCurrent_mode, int pGo_ahead, int pEscaped, int pTimed_out) { LOG_TRACE("(%d, %d, %d, %d, %d)", pCurrent_choice, pCurrent_mode, pGo_ahead, pEscaped, pTimed_out); - NOT_IMPLEMENTED(); + + if (pEscaped) { + pCurrent_choice = -1; + } else if (pCurrent_choice == 0) { + gProgram_state.prog_status = eProg_idling; + } + return pCurrent_choice; } // IDA: int __usercall NetSynchStartGoAhead@(int *pCurrent_choice@, int *pCurrent_mode@) int NetSynchStartGoAhead(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (*pCurrent_choice == 0 || (gNet_mode == eNet_mode_host && *pCurrent_choice >= 0)) { + if (*pCurrent_choice == 0) { + gProgram_state.prog_status = eProg_idling; + return 1; + } else if (gNet_mode == eNet_mode_host && *pCurrent_choice == 1) { + if (gNumber_of_net_players <= 1) { + DRS3StartSound(gEffects_outlet, 3100); + return 0; + } else { + SignalToStartRace(); + gSynch_race_start = 1; + gNo_races_yet = 0; + return 1; + } + } else { + return 1; + } + } else { + DRS3StartSound(gEffects_outlet, 3100); + return 0; + } } // IDA: int __usercall ExitWhenReady@(int *pCurrent_choice@, int *pCurrent_mode@) int ExitWhenReady(int* pCurrent_choice, int* pCurrent_mode) { LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode); - NOT_IMPLEMENTED(); + + if (!gSynch_race_start && gProgram_state.prog_status != eProg_game_starting) { + if (gProgram_state.prog_status == eProg_idling) { + *pCurrent_choice = 0; + return 1; + } else { + return 0; + } + } else { + *pCurrent_choice = 1; + return 1; + } } // IDA: tSO_result __usercall NetSynchRaceStart2@(tNet_synch_mode pMode@) tSO_result NetSynchRaceStart2(tNet_synch_mode pMode) { - static tFlicette flicker_on_hf[2]; - static tFlicette flicker_off_hf[2]; - static tFlicette push_hf[2]; - static tMouse_area mouse_areas_hf[2]; - static tInterface_spec interface_spec_hf; - static tFlicette flicker_on_hs[1]; - static tFlicette flicker_off_hs[1]; - static tFlicette push_hs[1]; - static tMouse_area mouse_areas_hs[1]; - static tInterface_spec interface_spec_hs; - static tFlicette flicker_on_c[1]; - static tFlicette flicker_off_c[1]; - static tFlicette push_c[1]; - static tMouse_area mouse_areas_c[1]; - static tInterface_spec interface_spec_c; + static tFlicette flicker_on_hf[2] = { + { 321, { 219, 112 }, { 172, 362 } }, + { 321, { 39, 480 }, { 172, 379 } }, + }; + static tFlicette flicker_off_hf[2] = { + { 322, { 219, 112 }, { 172, 362 } }, + { 322, { 39, 480 }, { 172, 379 } }, + }; + static tFlicette push_hf[2] = { + { 206, { 219, 112 }, { 172, 362 } }, + { 205, { 39, 480 }, { 172, 379 } }, + }; + static tMouse_area mouse_areas_hf[2] = { + { { 219, 480 }, { 172, 379 }, { 282, 182 }, { 192, 427 }, 0, 0, 0, NULL }, + { { 39, 112 }, { 172, 362 }, { 102, 182 }, { 192, 379 }, 1, 0, 0, NULL }, + }; + static tInterface_spec interface_spec_hf = { + 0, + 203, + 0, + 0, + 0, + 0, + 8, + { -1, 0 }, + { 1, 0 }, + { 0, 0 }, + { 1, 0 }, + { NULL, NULL }, + { -1, 0 }, + { 1, 0 }, + { 0, 0 }, + { 1, 0 }, + { NULL, NULL }, + { -1, 0 }, + { 1, 0 }, + { 0, 0 }, + { 1, 0 }, + { NULL, NULL }, + { -1, 0 }, + { 1, 0 }, + { 0, 0 }, + { 1, 0 }, + { NULL, NULL }, + { 1, 1 }, + { NetSynchStartGoAhead, NetSynchStartGoAhead }, + { 1, 1 }, + { NULL, NULL }, + ExitWhenReady, + NetSynchStartDraw, + 0, + NULL, + NetSynchStartStart, + NetSynchStartDone, + 0, + { 0, 0 }, + NULL, + -1, + 1, + COUNT_OF(flicker_on_hf), + flicker_on_hf, + flicker_off_hf, + push_hf, + COUNT_OF(mouse_areas_hf), + mouse_areas_hf, + 0, + NULL, + }; + static tFlicette flicker_on_hs[1] = { + { 321, { 219, 112 }, { 172, 362 } }, + }; + static tFlicette flicker_off_hs[1] = { + { 322, { 219, 112 }, { 172, 362 } }, + }; + static tFlicette push_hs[1] = { + { 206, { 219, 112 }, { 172, 362 } }, + }; + static tMouse_area mouse_areas_hs[1] = { + { { 219, 480 }, { 172, 379 }, { 282, 182 }, { 192, 427 }, 0, 0, 0, NULL }, + }; + static tInterface_spec interface_spec_hs = { + 0, 209, 0, 0, 0, 0, 8, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { 1, 1 }, { NetSynchStartGoAhead, NetSynchStartGoAhead }, { 1, 1 }, { NULL, NULL }, + ExitWhenReady, NetSynchStartDraw, 0, NULL, NetSynchStartStart, NetSynchStartDone, 0, { 0, 0 }, + NULL, -1, 1, + COUNT_OF(flicker_on_hs), flicker_on_hs, flicker_off_hs, push_hs, + COUNT_OF(mouse_areas_hs), mouse_areas_hs, 0, NULL + }; + static tFlicette flicker_on_c[1] = { + { 321, { 219, 112 }, { 172, 362 } }, + }; + static tFlicette flicker_off_c[1] = { + { 322, { 219, 112 }, { 172, 362 } }, + }; + static tFlicette push_c[1] = { + { 207, { 219, 112 }, { 172, 362 } }, + }; + static tMouse_area mouse_areas_c[1] = { + { { 219, 112 }, { 172, 362 }, { 282, 182 }, { 192, 379 }, 0, 0, 0, NULL }, + }; + static tInterface_spec interface_spec_c = { + 0, 204, 0, 0, 0, 0, 8, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { -1, 0 }, { 1, 0 }, { 0, 0 }, { 1, 0 }, { NULL, NULL }, + { 1, 1 }, { NetSynchStartGoAhead, NetSynchStartGoAhead }, { 1, 1 }, { NULL, NULL }, + ExitWhenReady, NetSynchStartDraw, 0, NULL, NetSynchStartStart, NetSynchStartDone, 0, { 0, 0 }, + NULL, -1, 1, + COUNT_OF(flicker_on_c), flicker_on_c, flicker_off_c, push_c, + COUNT_OF(mouse_areas_c), mouse_areas_c, 0, NULL + }; int result; LOG_TRACE("(%d)", pMode); - NOT_IMPLEMENTED(); + + if (pMode != eNet_synch_client) { + if (gCurrent_net_game->status.stage == eNet_game_starting) { + gCurrent_net_game->status.stage = eNet_game_ready; + } + SetUpNetCarPositions(); + // gNet_synch_start = PDGetTotalTime(); + } + TurnOnPaletteConversion(); + switch (pMode) { + case eNet_synch_host_first: + result = DoInterfaceScreen(&interface_spec_hf, 0, 1); + break; + case eNet_synch_host_subsequent: + result = DoInterfaceScreen(&interface_spec_hs, 0, -1); + break; + case eNet_synch_client: + result = DoInterfaceScreen(&interface_spec_c, 0, -1); + break; + default: + break; + } + TurnOffPaletteConversion(); + FadePaletteDown(); + if (result > -2 && result < 1) { + NetLeaveGame(gCurrent_net_game); + } + return eSO_continue; } // IDA: tSO_result __cdecl NetSynchRaceStart() tSO_result NetSynchRaceStart(void) { LOG_TRACE("()"); - NOT_IMPLEMENTED(); + + SuspendPendingFlic(); + if (gNet_mode == eNet_mode_host) { + if (gNo_races_yet) { + return NetSynchRaceStart2(eNet_synch_host_first); + } else { + return NetSynchRaceStart2(eNet_synch_host_subsequent); + } + } else { + return NetSynchRaceStart2(eNet_synch_client); + } } diff --git a/src/DETHRACE/common/structur.c b/src/DETHRACE/common/structur.c index 12c9c12e..bd2068ca 100644 --- a/src/DETHRACE/common/structur.c +++ b/src/DETHRACE/common/structur.c @@ -395,7 +395,31 @@ int PickNetRace(int pCurrent_race, tNet_sequence_type pNet_race_sequence) { int most_seldom_seen; int races_to_pick_from[50]; LOG_TRACE("(%d, %d)", pCurrent_race, pNet_race_sequence); - NOT_IMPLEMENTED(); + + if (pNet_race_sequence == eNet_sequence_sequential) { + pCurrent_race++; + if (pCurrent_race >= gNumber_of_races) { + pCurrent_race = 0; + } + } else { + most_seldom_seen = 10000; + for (i = 0; i < gNumber_of_races; i++) { + if (gRace_list[i].been_there_done_that < most_seldom_seen) { + most_seldom_seen = gRace_list[i].been_there_done_that; + } + } + races_count = 0; + for (i = 0; i < gNumber_of_races; i++) { + if (gRace_list[i].been_there_done_that == most_seldom_seen && (i != pCurrent_race)) { + races_to_pick_from[races_count] = i; + races_count++; + } + } + new_index = IRandomBetween(0, races_count - 1); + pCurrent_race = races_to_pick_from[new_index]; + gRace_list[pCurrent_race].been_there_done_that++; + } + return pCurrent_race; } // IDA: void __cdecl SwapNetCarsLoad() @@ -445,7 +469,7 @@ void DoGame(void) { StartLoadingScreen(); gProgram_state.prog_status = eProg_game_ongoing; second_select_race = 0; - if (gNet_mode_of_last_game == gNet_mode) { + if (gNet_mode == gNet_mode_of_last_game) { PrintMemoryDump(0, "BEFORE START RACE SCREEN"); SelectOpponents(&gCurrent_race); if (gNet_mode != eNet_mode_none) { diff --git a/src/DETHRACE/common/utility.c b/src/DETHRACE/common/utility.c index 87c97dab..2f90b4c1 100644 --- a/src/DETHRACE/common/utility.c +++ b/src/DETHRACE/common/utility.c @@ -479,7 +479,6 @@ br_uint_32 DRPixelmapLoadMany(char* pFile_name, br_pixelmap** pPixelmaps, br_uin int i; br_uint_8 lobyte; LOG_TRACE("(\"%s\", %p, %d)", pFile_name, pPixelmaps, pNum); - number_loaded = BrPixelmapLoadMany(pFile_name, pPixelmaps, pNum); for (i = 0; i < number_loaded; i++) { the_map = pPixelmaps[i]; diff --git a/src/DETHRACE/constants.h b/src/DETHRACE/constants.h index fbe0cf39..f4ad2d4b 100644 --- a/src/DETHRACE/constants.h +++ b/src/DETHRACE/constants.h @@ -453,6 +453,42 @@ enum { kFatalError_RandomNumberOutOfRange_S = 116, }; +enum { + NETMSGID_SENDMEDETAILS = 0x00, + NETMSGID_DETAILS = 0x01, + NETMSGID_JOIN = 0x02, + NETMSGID_NEWPLAYERLIST = 0x03, + NETMSGID_GUARANTEEREPLY = 0x04, + NETMSGID_CARDETAILSREQ = 0x05, + NETMSGID_CARDETAILS = 0x06, + NETMSGID_LEAVE = 0x07, + NETMSGID_HOSTICIDE = 0x08, + NETMSGID_RACEOVER = 0x09, + NETMSGID_STATUSREPORT = 0x0a, + NETMSGID_STARTRACE = 0x0b, + NETMSGID_HEADUP = 0x0c, + NETMSGID_HOSTQUERY = 0x0d, + NETMSGID_HOSTREPLY = 0x0e, + NETMSGID_MECHANICS = 0x0f, + NETMSGID_NONCAR_INFO = 0x10, + NETMSGID_TIMESYNC = 0x11, + NETMSGID_CONFIRM = 0x12, + NETMSGID_DISABLECAR = 0x13, + NETMSGID_ENABLECAR = 0x14, + NETMSGID_POWERUP = 0x15, + NETMSGID_RECOVER = 0x16, + NETMSGID_SCORES = 0x17, + NETMSGID_WASTED = 0x18, + NETMSGID_PEDESTRIAN = 0x19, + NETMSGID_GAMEPLAY = 0x1a, + NETMSGID_NONCARPOSITION = 0x1b, + NETMSGID_COPINFO = 0x1c, + NETMSGID_GAMESCORES = 0x1d, + NETMSGID_OILSPILL = 0x1e, + NETMSGID_CRUSHPOINT = 0x1f, + NETMSGID_NONE = 0x20, +}; + #define FONT_TYPEABLE 0 #define FONT_ORANGHED 1 #define FONT_BLUEHEAD 2 diff --git a/src/DETHRACE/dr_types.h b/src/DETHRACE/dr_types.h index b9ec567b..4d5bee35 100644 --- a/src/DETHRACE/dr_types.h +++ b/src/DETHRACE/dr_types.h @@ -4,6 +4,7 @@ #include "brender/br_types.h" #include "constants.h" #include "macros.h" + #include "s3/s3.h" #include #include @@ -11,53 +12,6 @@ #include #include -// #ifdef _WIN32 -// #include -// #else -// typedef short short; -// typedef unsigned short unsigned short; -// typedef int INT; -// typedef int BOOL; -// typedef unsigned int UINT; -// typedef unsigned char unsigned char; -// typedef unsigned short WORD; -// typedef long long; -// typedef unsigned long unsigned long; -// typedef unsigned char* Punsigned char; -// typedef char* char*; -// typedef WORD* PWORD; -// typedef unsigned short* Pshort; -// typedef long* Plong; -// typedef void* PVOID; -// typedef unsigned char* LPunsigned char; -// typedef unsigned char* Lchar*; -// typedef WORD* LPWORD; -// typedef long* LPlong; -// typedef void* LPVOID; -// typedef unsigned char* HPunsigned char; -// typedef unsigned char* Hchar*; -// typedef long* HPlong; -// typedef void* HPVOID; -// #endif -typedef unsigned int W32; -typedef unsigned short W16; -typedef W32* LPW32; -typedef struct _tagRMI_REGS _RMI_REGS; -typedef struct _tagBREGS _HMI_BREGS; -typedef struct _tagWREGS _HMI_WREGS; -typedef struct _tagDREGS _HMI_DREGS; -typedef struct _tagSREGS _HMI_SREGS; -typedef struct _tagIPX_HEADER _IPX_HEADER; -typedef struct _tagIPX_ECB _IPX_ECB; -typedef struct _tagIPX_INTERNET_ADDR _IPX_INTERNET_ADDR; -typedef struct _tagIPX_NETWORK_ADDR _IPX_NETWORK_ADDR; -typedef struct _tagIPX_LOCAL_TARGET _IPX_LOCAL_TARGET; -typedef struct _tagIPX_ELEMENT _IPX_ELEMENT; -typedef struct _tag_NETBIOS_NCB _NETBIOS_NCB; -typedef struct _tagNETBIOS_ADAPTER_STATUS _NETBIOS_ADAPTER_STATUS; -typedef struct _tagNETBIOS_ELEMENT _NETBIOS_ELEMENT; -typedef struct _tagNETBIOS_LOCAL_TARGET _NETBIOS_LOCAL_TARGET; -typedef struct _tagXFER_BLOCK_HEADER _XFER_BLOCK_HEADER; typedef unsigned char tU8; typedef signed char tS8; typedef uint16_t tU16; @@ -75,6 +29,10 @@ typedef struct tPath_section_struct tPath_section; typedef tU32 tPlayer_ID; typedef void tPipe_reset_proc(void); typedef struct tPowerup tPowerup; + +// FIXME? hardcoding pc-win95 here +#include "pc-win95/win95net_types.h" + #ifdef DETHRACE_FIX_BUGS typedef int tGot_proc(tPowerup*, tCar_spec*); typedef void tLose_proc(tPowerup*, tCar_spec*); @@ -439,8 +397,6 @@ typedef enum tSmear_type { eSmear_blood = 1, eSmear_count = 2 } tSmear_type; -typedef struct ot_vertex ot_vertex; -typedef void zs_order_table_traversal_cbfn(int, ot_vertex*, ot_vertex*, ot_vertex*); // Make gcc happy typedef struct exception_ { @@ -451,253 +407,6 @@ typedef struct exception_ { double retval; } exception_; -typedef struct ot_vertex { - br_scalar screenX; - br_scalar screenY; - br_scalar distanceZ; -} ot_vertex; - -typedef struct _tagRMI_REGS { - long EDI; - long ESI; - long EBP; - long reserved_by_system; - long EBX; - long EDX; - long ECX; - long EAX; - short flags; - short ES; - short DS; - short FS; - short GS; - short IP; - short CS; - short SP; - short SS; -} _RMI_REGS; - -typedef struct _tagBREGS { - char al; - char ah; - unsigned short _1; - char bl; - char bh; - unsigned short _2; - char cl; - char ch; - unsigned short _3; - char dl; - char dh; - unsigned short _4; -} _HMI_BREGS; - -typedef struct _tagWREGS { - unsigned short ax; - unsigned short _1; - unsigned short bx; - unsigned short _2; - unsigned short cx; - unsigned short _3; - unsigned short dx; - unsigned short _4; - unsigned short si; - unsigned short _5; - unsigned short di; - unsigned short _6; -} _HMI_WREGS; - -typedef struct _tagDREGS { - unsigned int eax; - unsigned int ebx; - unsigned int ecx; - unsigned int edx; - unsigned int esi; - unsigned int edi; - unsigned int cflags; -} _HMI_DREGS; - -typedef struct _tagSREGS { - unsigned short es; - unsigned short cs; - unsigned short ss; - unsigned short ds; - unsigned short fs; - unsigned short gs; -} _HMI_SREGS; - -typedef struct _HMI_REGS { - _HMI_DREGS x; - _HMI_WREGS w; - _HMI_BREGS h; -} _HMI_REGS; - -typedef struct _tagIPX_HEADER { - unsigned short wChecksum; - unsigned short wLength; - unsigned char bTransportControl; - unsigned char bPacketType; - unsigned char bDestNetworkNumber[4]; - unsigned char bDestNetworkNode[6]; - unsigned short wDestNetworkSocket; - unsigned char bSourceNetworkNumber[4]; - unsigned char bSourceNetworkNode[6]; - unsigned short wSourceNetworkSocket; -} _IPX_HEADER; - -typedef struct _PACKET { - char* pData; - unsigned short wLength; -} _PACKET; - -typedef struct _REAL_PACKET { - short wOffset; - short wSegment; - unsigned short wLength; -} _REAL_PACKET; - -typedef struct _ECB_PACKET { - _PACKET sPacket; - _REAL_PACKET sRealPacket; -} _ECB_PACKET; - -typedef struct _tagIPX_ECB { - char* pLinkAddress; - char* pESRRoutine; - unsigned char bInUse; - unsigned char bCompletionCode; - unsigned short wSocket; - unsigned short wConnectionID; - unsigned short wWorkSpace; - unsigned char bDriverWorkSpace[12]; - unsigned char bImmediateAddress[6]; - unsigned short wPacketCount; - _ECB_PACKET sPacket[2]; -} _IPX_ECB; - -typedef struct _tagIPX_INTERNET_ADDR { - unsigned char bNetwork[4]; - unsigned char bNode[6]; -} _IPX_INTERNET_ADDR; - -typedef struct _tagIPX_NETWORK_ADDR { - _IPX_INTERNET_ADDR sInternetAddr; - unsigned char bSocket[2]; -} _IPX_NETWORK_ADDR; - -typedef struct _tagIPX_LOCAL_TARGET { - _IPX_INTERNET_ADDR sInternetAddr; - unsigned char bImmediate[6]; -} _IPX_LOCAL_TARGET; - -typedef struct _tagIPX_ELEMENT { - unsigned short wFlags; - unsigned short wOffset; - _IPX_HEADER sHeader; - _IPX_ECB sECB; - _IPX_ECB* pECB; - _IPX_HEADER* pIPXHeader; - char* pHeader; - unsigned short wHSize; -} _IPX_ELEMENT; - -typedef struct _PROT_PTR { - char* pData; -} _PROT_PTR; - -typedef struct _REAL_PTR { - short wOffset; - short wSegment; -} _REAL_PTR; - -typedef struct _PTR { - _PROT_PTR sPointer; - _REAL_PTR sRealPtr; -} _PTR; - -typedef struct _tag_NETBIOS_NCB { - unsigned char bCommand; - unsigned char bReturnCode; - unsigned char bLocalSession; - unsigned char bNetworkNameNumber; - _PTR sPtr; - unsigned short wLength; - unsigned char bCallName[16]; - unsigned char bName[16]; - unsigned char bReceiveTimeOut; - unsigned char bSendTimeOut; - char* pPostFunction; - unsigned char bAdapter; - unsigned char bCompletionCode; - unsigned char bReserve[14]; -} _NETBIOS_NCB; - -typedef struct _tagNETBIOS_ADAPTER_STATUS { - unsigned char bCardID[6]; - unsigned char bReleaseLevel; - unsigned char bReserved1; - unsigned char bTypeOfAdapter; - unsigned char bOldOrNewParameters; - unsigned short wReportingPeriodMinutes; - unsigned short wFrameRejectReceivedCount; - unsigned short wFrameRejectSentCount; - unsigned short wReceivedDataFrameErrors; - unsigned short wUnsuccessfulTransmissions; - long dwGoodTransmissions; - long dwGoodReceptions; - unsigned short wRetransmissions; - unsigned short wExhaustedResourceCount; - unsigned short wT1TimerExpiredCount; - unsigned short wTITimerExpiredCount; - unsigned char bReserved2[4]; - unsigned short wAvailableNCBS; - unsigned short wMaxNCBSConfigured; - unsigned short wMaxNCBSPossible; - unsigned short wBufferOrStationBusyCount; - unsigned short wMaxDatagramSize; - unsigned short wPendingSessions; - unsigned short wMaxSessionsConfigured; - unsigned short wMaxSessionsPossible; - unsigned short wMaxFrameSize; - unsigned short wNameCount; - struct { - unsigned char bName[16]; - unsigned char bNameNumber; - unsigned char bNameStatus; - } sNameTable[20]; -} _NETBIOS_ADAPTER_STATUS; - -typedef struct _tagNETBIOS_ELEMENT { - unsigned short wFlags; - unsigned short wOffset; - _NETBIOS_NCB sNCB; - _NETBIOS_NCB* pNCB; - char* pHeader; - unsigned short wHSize; -} _NETBIOS_ELEMENT; - -typedef struct _tagNETBIOS_LOCAL_TARGET { - unsigned char bNode[16]; -} _NETBIOS_LOCAL_TARGET; - -typedef struct _tagXFER_BLOCK_HEADER { - W32 wSequence; - W32 wType; - W32 wID; - W32 wLength; - W32 wNode; - W32 wUser1; -} _XFER_BLOCK_HEADER; - -typedef struct _NETNOW_NODE_ADDR { - _IPX_LOCAL_TARGET sIPX; - _NETBIOS_LOCAL_TARGET sNETBIOS; -} _NETNOW_NODE_ADDR; - -typedef struct tPD_net_player_info { - _IPX_LOCAL_TARGET addr_ipx; -} tPD_net_player_info; - typedef struct tTrack_spec { tU8 ncolumns_x; tU8 ncolumns_z; @@ -1324,65 +1033,65 @@ typedef struct tFace_ref { br_scalar d; } tFace_ref; -typedef struct tNet_game_player_info { - tPD_net_player_info pd_net_info; - tU32 this_players_time_stamp; - tU32 last_heard_from_him; - tU32 reposition_time; - tU32 last_waste_message; - int host; - tPlayer_ID ID; - char player_name[32]; - tPlayer_status player_status; - int car_index; - int grid_index; - int grid_position_set; - int opponent_list_index; - int awaiting_confirmation; - int score; - int credits; - int wasted; - int wasteage_attributed; - int name_not_clipped; - int race_stuff_initialised; - int played; - int won; - int next_car_index; - int games_score; - int last_score_index; - br_matrix34 initial_position; - tCar_spec* car; +typedef struct tNet_game_player_info { // size: 0xc0 + tPD_net_player_info pd_net_info; // @0x0 + tU32 this_players_time_stamp; // @0x10 + tU32 last_heard_from_him; // @0x14 + tU32 reposition_time; // @0x18 + tU32 last_waste_message; // @0x1c + int host; // @0x20 + tPlayer_ID ID; // @0x24 + char player_name[32]; // @0x28 + tPlayer_status player_status; // @0x48 + int car_index; // @0x4c + int grid_index; // @0x50 + int grid_position_set; // @0x54 + int opponent_list_index; // @0x58 + int awaiting_confirmation; // @0x5c + int score; // @0x60 + int credits; // @0x64 + int wasted; // @0x68 + int wasteage_attributed; // @0x6c + int name_not_clipped; // @0x70 + int race_stuff_initialised; // @0x74 + int played; // @0x78 + int won; // @0x7c + int next_car_index; // @0x80 + int games_score; // @0x84 + int last_score_index; // @0x88 + br_matrix34 initial_position; // @0x8c + tCar_spec* car; // @0xbc } tNet_game_player_info; -typedef struct tNet_game_options { - int show_players_on_map; - int show_peds_on_map; - int enable_text_messages; - int show_powerups_on_map; - int powerup_respawn; - int open_game; - int starting_money_index; - int grid_start; - int race_end_target; - int random_car_choice; - tNet_sequence_type race_sequence_type; - tCar_choice car_choice; +typedef struct tNet_game_options { // size: 0x30 + int show_players_on_map; // @0x0 + int show_peds_on_map; // @0x4 + int enable_text_messages; // @0x8 + int show_powerups_on_map; // @0xc + int powerup_respawn; // @0x10 + int open_game; // @0x14 + int starting_money_index; // @0x18 + int grid_start; // @0x1c + int race_end_target; // @0x20 + int random_car_choice; // @0x24 + tNet_sequence_type race_sequence_type; // @0x28 + tCar_choice car_choice; // @0x2c } tNet_game_options; -typedef struct tNet_game_status { - tNet_game_stage stage; +typedef struct tNet_game_status { // size: 0x4 + tNet_game_stage stage; // @0x0 } tNet_game_status; -typedef struct tNet_game_details { - tPD_net_player_info pd_net_info; - char host_name[32]; - tPlayer_ID host_ID; - int num_players; - int start_race; - int no_races_yet; - tNet_game_status status; - tNet_game_options options; - tNet_game_type type; +typedef struct tNet_game_details { // size: 0x78 + tPD_net_player_info pd_net_info; // @0x0 + char host_name[32]; // @0x10 + tPlayer_ID host_ID; // @0x30 + int num_players; // @0x34 + int start_race; // @0x38 + int no_races_yet; // @0x3c + tNet_game_status status; // @0x40 + tNet_game_options options; // @0x44 + tNet_game_type type; // @0x74 } tNet_game_details; typedef struct tNet_message_send_me_details { @@ -1631,8 +1340,6 @@ typedef struct tNet_message_crush_point { br_vector3 energy_vector; } tNet_message_crush_point; -#define ENET_MESSAGE_HEADUP 0xc - typedef union tNet_contents { // size: 0x160 struct { // size: 0x2 tU8 contents_size; // @0x0 @@ -1674,16 +1381,16 @@ typedef union tNet_contents { // size: 0x160 } data; // @0x0 } tNet_contents; -typedef struct tNet_message { - tU32 pd_stuff_so_DO_NOT_USE; - tU32 magic_number; - tU32 guarantee_number; - tPlayer_ID sender; - int version; - tU32 senders_time_stamp; - tU16 num_contents; - tU16 overall_size; - tNet_contents contents; +typedef struct tNet_message { // size: 0x17c + tU32 pd_stuff_so_DO_NOT_USE; // @0x0 + tU32 magic_number; // @0x4 + tU32 guarantee_number; // @0x8 + tPlayer_ID sender; // @0xc + int version; // @0x10 + tU32 senders_time_stamp; // @0x14 + tU16 num_contents; // @0x18 + tU16 overall_size; // @0x1a + tNet_contents contents; // @0x1c } tNet_message; typedef struct tCar_detail_info { @@ -2658,8 +2365,8 @@ typedef struct tPipe_skid_adjustment { int material_index; } tPipe_skid_adjustment; -typedef struct tPipe_chunk { // size: 0x58 - tChunk_subject_index subject_index; // @0x0 +typedef struct tPipe_chunk { // size: 0x58 + tChunk_subject_index subject_index; // @0x0 #if defined(DETHRACE_REPLAY_DEBUG) int chunk_magic1; #endif @@ -2754,205 +2461,6 @@ typedef struct tCheat { int num; } tCheat; -typedef struct _tag_sos_evds_struct _SOS_EVDS_STRUCT; -typedef struct _tag_sos_vds_struct _SOS_VDS_STRUCT; -typedef struct _tag_sos_sample _SOS_SAMPLE; -typedef _SOS_SAMPLE* PSOSSAMPLE; -typedef struct _tagCAPABILITIES _SOS_CAPABILITIES; -typedef _SOS_CAPABILITIES* PSOSCAPABILITIES; -typedef struct _SOS_HARDWARE* PSOSHARDWARE; -typedef struct _tag_sos_driver _SOS_DIGI_DRIVER; -typedef _SOS_DIGI_DRIVER* PSOSDIGIDRIVER; -typedef struct _SOS_DRV_FILEHEADER* PSOSDRVFILEHEADER; -typedef struct _SOS_DRV_DRIVERHEADER* PSOSDRVDRIVERHEADER; -typedef struct _tag_sos_system _SOS_SYSTEM; -typedef _SOS_SYSTEM* PSOSSYSTEM; -typedef struct _tag_sos_det_system _SOS_DET_SYSTEM; -typedef _SOS_DET_SYSTEM* PSOSDETSYSTEM; -typedef struct _tag_sos_timer_system _SOS_TIMER_SYSTEM; -typedef _SOS_TIMER_SYSTEM* PSOSTIMERSYSTEM; -typedef struct SmackTag Smack; -typedef struct SmackSumTag SmackSum; -typedef void* SmackTimerSetupType(void); -typedef unsigned long* SmackTimerReadType(void); -typedef void* SmackTimerDoneType(void); -typedef struct _heapinfo _HEAPINFO; -typedef struct _tag_sos_evds_struct { - unsigned int region_size; - unsigned int offset; - unsigned int segment; - unsigned short number_available; - unsigned short number_used; - unsigned int page0; -} _SOS_EVDS_STRUCT; - -typedef struct _tag_sos_vds_struct { - unsigned int region_size; - unsigned int offset; - unsigned short segment; - unsigned short ID; - unsigned int physical; -} _SOS_VDS_STRUCT; - -typedef struct _tag_sos_sample { - char* pSample; - char* pSampleCurrent; - char* pSampleLoop; - unsigned long wLength; - unsigned long wLoopLength; - unsigned long wLoopEndLength; - unsigned long wLoopStage; - unsigned long wID; - unsigned long wFlags; - unsigned long wPriority; - unsigned long hSample; - unsigned long wVolume; - unsigned long wLoopCount; - unsigned long wRate; - unsigned long wBitsPerSample; - unsigned long wChannels; - unsigned long wFormat; - unsigned long wPanPosition; - unsigned long wPanSpeed; - unsigned long wPanStart; - unsigned long wPanEnd; - unsigned long wPanMode; - unsigned long wTotalBytesProcessed; - void (*pfnSampleProcessed)(PSOSSAMPLE*); - void (*pfnSampleDone)(PSOSSAMPLE*); - void (*pfnSampleLoop)(PSOSSAMPLE*); - unsigned long wSystem[16]; - unsigned long wUser[16]; - PSOSSAMPLE* pLink; - PSOSSAMPLE* pNext; -} _SOS_SAMPLE; - -typedef struct _tagCAPABILITIES { - unsigned char szDeviceName[32]; - W32 wDeviceVersion; - W32 wBitsPerSample; - W32 wChannels; - W32 wMinRate; - W32 wMaxRate; - W32 wMixerOnBoard; - W32 wMixerFlags; - W32 wFlags; - short* lpPortList; - short* lpDMAList; - short* lpIRQList; - short* lpRateList; - W32 fBackground; - W32 wID; - W32 wTimerID; -} _SOS_CAPABILITIES; - -typedef struct _SOS_HARDWARE { - W32 wPort; - W32 wIRQ; - W32 wDMA; - W32 wParam; -} _SOS_HARDWARE; - -typedef struct _tag_sos_driver { - W32 wFlags; - unsigned long wDriverRate; - unsigned long wDriverChannels; - unsigned long wDriverBitsPerSample; - unsigned long wDriverFormat; - unsigned long wMixerChannels; - unsigned long wDMACountRegister; - unsigned long wDMAPosition; - unsigned long wDMALastPosition; - unsigned long wDMADistance; - char* pXFERPosition; - unsigned long wXFERJumpAhead; - _SOS_SAMPLE* pSampleList; - void (*pfnPseudoDMAFunction)(void); - char* pDMABuffer; - char* pDMABufferEnd; - unsigned long wDMABufferSize; - char* pMixingBuffer; - char* pMixingBufferEnd; - unsigned long wMixingBufferSize; - unsigned long wActiveChannels; - _SOS_SAMPLE* pSamples; - _SOS_HARDWARE sHardware; - _SOS_CAPABILITIES sCaps; - char* lpDriverDS; - char* lpDriverCS; - W32 wSize; - unsigned long dwLinear; - unsigned long dwDMAPhysical; - char* lpDMABuffer; - W32 hMemory; - W32 wDMARealSeg; - W32 wID; - void (*pfnMixFunction)(void); -} _SOS_DIGI_DRIVER; - -typedef struct _SOS_DRV_FILEHEADER { - unsigned char szName[32]; - W32 wDrivers; - W32 lOffset; - W32 lFileSize; -} _SOS_DRV_FILEHEADER; - -typedef struct _SOS_DRV_DRIVERHEADER { - unsigned char szName[32]; - W32 lNextDriver; - W32 wSize; - W32 wDeviceID; - W32 wExtenderType; -} _SOS_DRV_DRIVERHEADER; - -typedef struct _tag_sos_system { - W32 wFlags; - unsigned char szDriverPath[128]; - unsigned char szTempDriverPath[128]; - PSOSDIGIDRIVER pDriver[5]; - _SOS_VDS_STRUCT sVDS; - _SOS_DRV_FILEHEADER sFileHeader; - _SOS_DRV_DRIVERHEADER sDriverHeader; - char* (*pMemAllocFunction)(unsigned long); - void (*pMemFreeFunction)(char*, W32); -} _SOS_SYSTEM; - -typedef struct _tag_sos_det_system { - W32 wFlags; - unsigned char szDriverPath[128]; - unsigned char szTempDriverPath[128]; - _SOS_DRV_FILEHEADER sFileHeader; - _SOS_DRV_DRIVERHEADER sDriverHeader; - _SOS_CAPABILITIES sCaps; - PSOSCAPABILITIES pCaps; - char* lpBufferDS; - char* lpBufferCS; - W32 hFile; - unsigned long dwDriverIndex; - W32 wDriverIndexCur; - W32 hMemory; - unsigned long dwLinear; -} _SOS_DET_SYSTEM; - -typedef struct _tag_sos_timer_system { - W32 wFlags; - W32 wChipDivisor; - void (*pfnEvent[16])(void); - W32 wEventRate[16]; - unsigned long dwAdditiveFraction[16]; - unsigned long dwCurrentSummation[16]; - W32 wMIDIEventSongHandle[16]; - W32 wMIDIActiveSongHandle; -} _SOS_TIMER_SYSTEM; - -#ifndef _WIN32 -typedef struct _heapinfo { - void* _pentry; - size_t _size; - int _useflag; -} _HEAPINFO; -#endif - typedef enum tSpec_vol_depth_effect { eSpec_dep_acid = 0, eSpec_dep_water = 1, @@ -3235,26 +2743,29 @@ typedef struct tHeadup_pair { } tHeadup_pair; typedef struct tMax_message { - char buffer[516]; + // char buffer[516]; // 512 + sizeof(void*) + char buffer[520]; } tMax_message; typedef struct tMid_message { - char buffer[132]; + // char buffer[132]; // 128 + sizeof(void*) + char buffer[136]; } tMid_message; typedef struct tMin_message { - char buffer[36]; + // char buffer[36]; // 32 + sizeof(void*) + char buffer[40]; } tMin_message; -typedef struct tGuaranteed_message { - tNet_message* message; - tU32 send_time; - tU32 next_resend_time; - tU32 resend_period; - int recieved; - tPD_net_player_info pd_address; - int (*NotifyFail)(tU32, tNet_message*); - tU32 guarantee_number; +typedef struct tGuaranteed_message { // size: 0x2c + tNet_message* message; // @0x0 + tU32 send_time; // @0x4 + tU32 next_resend_time; // @0x8 + tU32 resend_period; // @0xc + int recieved; // @0x10 + tPD_net_player_info pd_address; // @0x14 + int (*NotifyFail)(tU32, tNet_message*); // @0x24 + tU32 guarantee_number; // @0x28 } tGuaranteed_message; typedef enum tJoin_or_host_result { @@ -3839,266 +3350,6 @@ typedef struct tGroovidelic_spec { // size: 0x80 } object_data; // @0x68 } tGroovidelic_spec; -typedef struct DWORDREGS { - unsigned int eax; - unsigned int ebx; - unsigned int ecx; - unsigned int edx; - unsigned int esi; - unsigned int edi; - unsigned int cflag; -} DWORDREGS; - -typedef struct WORDREGS { - unsigned short ax; - unsigned short _1; - unsigned short bx; - unsigned short _2; - unsigned short cx; - unsigned short _3; - unsigned short dx; - unsigned short _4; - unsigned short si; - unsigned short _5; - unsigned short di; - unsigned short _6; - unsigned int cflag; -} WORDREGS; - -typedef struct BYTEREGS { - unsigned char al; - unsigned char ah; - unsigned short _1; - unsigned char bl; - unsigned char bh; - unsigned short _2; - unsigned char cl; - unsigned char ch; - unsigned short _3; - unsigned char dl; - unsigned char dh; - unsigned short _4; -} BYTEREGS; - -typedef union REGS { - DWORDREGS x; - WORDREGS w; - BYTEREGS h; -} REGS; - -typedef struct SREGS { - unsigned short es; - unsigned short cs; - unsigned short ss; - unsigned short ds; - unsigned short fs; - unsigned short gs; -} SREGS; - -typedef struct REGPACKB { - unsigned char al; - unsigned char ah; - unsigned short _1; - unsigned char bl; - unsigned char bh; - unsigned short _2; - unsigned char cl; - unsigned char ch; - unsigned short _3; - unsigned char dl; - unsigned char dh; - unsigned short _4; -} REGPACKB; - -typedef struct REGPACKW { - unsigned short ax; - unsigned short _1; - unsigned short bx; - unsigned short _2; - unsigned short cx; - unsigned short _3; - unsigned short dx; - unsigned short _4; - unsigned short bp; - unsigned short _5; - unsigned short si; - unsigned short _6; - unsigned short di; - unsigned short _7; - unsigned short ds; - unsigned short es; - unsigned short fs; - unsigned short gs; - unsigned int flags; -} REGPACKW; - -typedef struct REGPACKX { - unsigned int eax; - unsigned int ebx; - unsigned int ecx; - unsigned int edx; - unsigned int ebp; - unsigned int esi; - unsigned int edi; - unsigned short ds; - unsigned short es; - unsigned short fs; - unsigned short gs; - unsigned int flags; -} REGPACKX; - -typedef struct REGPACK { - REGPACKB h; - REGPACKW w; - REGPACKX x; -} REGPACK; - -typedef struct INTPACKX { - unsigned int gs; - unsigned int fs; - unsigned int es; - unsigned int ds; - unsigned int edi; - unsigned int esi; - unsigned int ebp; - unsigned int esp; - unsigned int ebx; - unsigned int edx; - unsigned int ecx; - unsigned int eax; - unsigned int eip; - unsigned int cs; - unsigned int flags; -} INTPACKX; - -typedef struct INTPACKW { - unsigned short gs; - unsigned short _1; - unsigned short fs; - unsigned short _2; - unsigned short es; - unsigned short _3; - unsigned short ds; - unsigned short _4; - unsigned short di; - unsigned short _5; - unsigned short si; - unsigned short _6; - unsigned short bp; - unsigned short _7; - unsigned short sp; - unsigned short _8; - unsigned short bx; - unsigned short _9; - unsigned short dx; - unsigned short _a; - unsigned short cx; - unsigned short _b; - unsigned short ax; - unsigned short _c; - unsigned short ip; - unsigned short _d; - unsigned short cs; - unsigned short _e; - unsigned int flags; -} INTPACKW; - -typedef struct INTPACKB { - unsigned char bl; - unsigned char bh; - unsigned short _1; - unsigned char dl; - unsigned char dh; - unsigned short _2; - unsigned char cl; - unsigned char ch; - unsigned short _3; - unsigned char al; - unsigned char ah; - unsigned short _4; -} INTPACKB; - -typedef struct INTPACK { - INTPACKB h; - INTPACKW w; - INTPACKX x; -} INTPACK; - -typedef struct _DOSERROR { - int exterror; - char errclass; - char action; - char locus; -} _DOSERROR; - -typedef struct DOSERROR { - int exterror; - char class; - char action; - char locus; -} DOSERROR; - -typedef struct dosdate_t { - unsigned char day; - unsigned char month; - unsigned short year; - unsigned char dayofweek; -} dosdate_t; - -typedef struct dostime_t { - unsigned char hour; - unsigned char minute; - unsigned char second; - unsigned char hsecond; -} dostime_t; - -typedef struct find_t { - char reserved[21]; - char attrib; - unsigned short wr_time; - unsigned short wr_date; - unsigned long size; - char name[13]; -} find_t; - -#ifndef _WIN32 -typedef struct _diskfree_t { - unsigned short total_clusters; - unsigned short avail_clusters; - unsigned short sectors_per_cluster; - unsigned short bytes_per_sector; -} _diskfree_t; -#endif - -typedef struct tPD_net_game_info { - _IPX_LOCAL_TARGET addr_ipx; - tU32 last_response; -} tPD_net_game_info; - -typedef struct tIPX_netnum { - unsigned char bNetwork[4]; -} tIPX_netnum; - -typedef struct tRM_info { - unsigned long EDI; - unsigned long ESI; - unsigned long EBP; - unsigned long reserved; - unsigned long EBX; - unsigned long EDX; - unsigned long ECX; - unsigned long EAX; - unsigned short flags; - unsigned short ES; - unsigned short DS; - unsigned short FS; - unsigned short GS; - unsigned short IP; - unsigned short CS; - unsigned short SP; - unsigned short SS; -} tRM_info; - typedef struct tMem_info { unsigned int largest_block_avail; unsigned int max_unlocked_page; @@ -4112,4 +3363,8 @@ typedef struct tMem_info { unsigned int reserved[3]; } tMem_info; +typedef struct tIPX_netnum { + unsigned char bNetwork[4]; +} tIPX_netnum; + #endif diff --git a/src/DETHRACE/pc-dos/dosnet.c b/src/DETHRACE/pc-dos/dosnet.c index a6c2c960..9b30b50b 100644 --- a/src/DETHRACE/pc-dos/dosnet.c +++ b/src/DETHRACE/pc-dos/dosnet.c @@ -1,10 +1,16 @@ #include "pd/net.h" #include "errors.h" +#include "globvrpb.h" +#include "harness/hooks.h" #include "harness/trace.h" +#include "network.h" +#include #include #include +#ifdef __DOS__ + tU32 gNetwork_init_flags; tPD_net_game_info* gJoinable_games; int gMatts_PC; @@ -26,9 +32,11 @@ tU8* gSend_packet_ptr; W32 gSend_segment; tU8* gListen_packet; tU8* gListen_packet_ptr; + size_t gMsg_header_strlen; int gNumber_of_networks; int gNumber_of_hosts; + tRM_info RMI; _IPX_HEADER gLast_received_IPX_header; tU16 gSocket_number_network_order; @@ -42,7 +50,7 @@ tU16 gSend_selector; /*static*/ int GetSocketNumberFromProfileFile(void); /*static*/ tU32 EthernetAddressToU32(_IPX_LOCAL_TARGET* pAddr_ipx); /*static*/ void NetNowIPXLocalTarget2String(char* pString, _IPX_LOCAL_TARGET* pSock_addr_ipx); -/*static*/ int GetMessageTypeFromMessage(char* pMessage_str) ; +/*static*/ int GetMessageTypeFromMessage(char* pMessage_str); /*static*/ int SameEthernetAddress(_IPX_LOCAL_TARGET* pAddr_ipx1, _IPX_LOCAL_TARGET* pAddr_ipx2); /*static*/ _IPX_LOCAL_TARGET* GetIPXAddrFromPlayerID(tPlayer_ID pPlayer_id); /*static*/ void MakeMessageToSend(int pMessage_type); @@ -297,6 +305,7 @@ int PDNetInitialise(void) { tU32 netnum; char str[256]; int mess_num; + LOG_TRACE("()"); NOT_IMPLEMENTED(); } @@ -326,7 +335,7 @@ int PDNetGetNextJoinGame(tNet_game_details* pGame, int pIndex) { int j; int number_of_hosts_has_changed; char str[256]; - LOG_TRACE("(%p, %d)", pGame, pIndex); + LOG_TRACE9("(%p, %d)", pGame, pIndex); NOT_IMPLEMENTED(); } @@ -374,35 +383,7 @@ tPlayer_ID PDNetExtractPlayerID(tNet_game_details* pDetails) { // IDA: void __usercall PDNetObtainSystemUserName(char *pName@, int pMax_length@) void PDNetObtainSystemUserName(char* pName, int pMax_length) { -#ifdef _WIN32 - uint32_t size; - char buffer[16]; - int result; - -#endif - - dr_dprintf("PDNetObtainSystemUserName()\n"); - // todo -#if 0 - size = COUNT_OF(buffer); - result = GetComputerNameA(buffer, &size); - if (result == 0) { - LOG_WARN("GetComputerNameA failed with code=%u", GetLastError()); - buffer[0] = '\0'; - size = 0; - } - strncpy(pName, buffer, pMax_length - 1); - pName[pMax_length - 1] = '\0'; - while (1) { - pName = strpbrk(pName, "_=(){}[]<>!$%^&*/:@~;'#,?\\|`\""); - if (pName == NULL || *pName == '\0') { - break; - } - *pName = '-'; - } -#else strcpy(pName, "Ron Turn"); -#endif } // IDA: int __usercall PDNetSendMessageToPlayer@(tNet_game_details *pDetails@, tNet_message *pMessage@, tPlayer_ID pPlayer@) @@ -417,6 +398,7 @@ int PDNetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage int PDNetSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage) { char str[256]; int i; + int r; // Added by dethrace LOG_TRACE("(%p, %p)", pDetails, pMessage); NOT_IMPLEMENTED(); } @@ -472,3 +454,5 @@ int PDNetGetHeaderSize(void) { LOG_TRACE("()"); NOT_IMPLEMENTED(); } + +#endif diff --git a/src/DETHRACE/pc-dos/dosnet.h b/src/DETHRACE/pc-dos/dosnet.h new file mode 100644 index 00000000..d0d3850e --- /dev/null +++ b/src/DETHRACE/pc-dos/dosnet.h @@ -0,0 +1,193 @@ +#include "dr_types.h" + +#ifdef __DOS__ + +typedef struct _tagIPX_HEADER { + unsigned short wChecksum; + unsigned short wLength; + unsigned char bTransportControl; + unsigned char bPacketType; + unsigned char bDestNetworkNumber[4]; + unsigned char bDestNetworkNode[6]; + unsigned short wDestNetworkSocket; + unsigned char bSourceNetworkNumber[4]; + unsigned char bSourceNetworkNode[6]; + unsigned short wSourceNetworkSocket; +} _IPX_HEADER; + +typedef struct _PACKET { + char* pData; + unsigned short wLength; +} _PACKET; + +typedef struct _REAL_PACKET { + short wOffset; + short wSegment; + unsigned short wLength; +} _REAL_PACKET; + +typedef struct _ECB_PACKET { + _PACKET sPacket; + _REAL_PACKET sRealPacket; +} _ECB_PACKET; + +typedef struct _tagIPX_ECB { + char* pLinkAddress; + char* pESRRoutine; + unsigned char bInUse; + unsigned char bCompletionCode; + unsigned short wSocket; + unsigned short wConnectionID; + unsigned short wWorkSpace; + unsigned char bDriverWorkSpace[12]; + unsigned char bImmediateAddress[6]; + unsigned short wPacketCount; + _ECB_PACKET sPacket[2]; +} _IPX_ECB; + +typedef struct _tagIPX_INTERNET_ADDR { + unsigned char bNetwork[4]; + unsigned char bNode[6]; +} _IPX_INTERNET_ADDR; + +typedef struct _tagIPX_NETWORK_ADDR { + _IPX_INTERNET_ADDR sInternetAddr; + unsigned char bSocket[2]; +} _IPX_NETWORK_ADDR; + +typedef struct _tagIPX_LOCAL_TARGET { + _IPX_INTERNET_ADDR sInternetAddr; + unsigned char bImmediate[6]; +} _IPX_LOCAL_TARGET; + +typedef struct _tagIPX_ELEMENT { + unsigned short wFlags; + unsigned short wOffset; + _IPX_HEADER sHeader; + _IPX_ECB sECB; + _IPX_ECB* pECB; + _IPX_HEADER* pIPXHeader; + char* pHeader; + unsigned short wHSize; +} _IPX_ELEMENT; + +typedef struct _PROT_PTR { + char* pData; +} _PROT_PTR; + +typedef struct _REAL_PTR { + short wOffset; + short wSegment; +} _REAL_PTR; + +typedef struct _PTR { + _PROT_PTR sPointer; + _REAL_PTR sRealPtr; +} _PTR; + +typedef struct _tag_NETBIOS_NCB { + unsigned char bCommand; + unsigned char bReturnCode; + unsigned char bLocalSession; + unsigned char bNetworkNameNumber; + _PTR sPtr; + unsigned short wLength; + unsigned char bCallName[16]; + unsigned char bName[16]; + unsigned char bReceiveTimeOut; + unsigned char bSendTimeOut; + char* pPostFunction; + unsigned char bAdapter; + unsigned char bCompletionCode; + unsigned char bReserve[14]; +} _NETBIOS_NCB; + +typedef struct _tagNETBIOS_ADAPTER_STATUS { + unsigned char bCardID[6]; + unsigned char bReleaseLevel; + unsigned char bReserved1; + unsigned char bTypeOfAdapter; + unsigned char bOldOrNewParameters; + unsigned short wReportingPeriodMinutes; + unsigned short wFrameRejectReceivedCount; + unsigned short wFrameRejectSentCount; + unsigned short wReceivedDataFrameErrors; + unsigned short wUnsuccessfulTransmissions; + long dwGoodTransmissions; + long dwGoodReceptions; + unsigned short wRetransmissions; + unsigned short wExhaustedResourceCount; + unsigned short wT1TimerExpiredCount; + unsigned short wTITimerExpiredCount; + unsigned char bReserved2[4]; + unsigned short wAvailableNCBS; + unsigned short wMaxNCBSConfigured; + unsigned short wMaxNCBSPossible; + unsigned short wBufferOrStationBusyCount; + unsigned short wMaxDatagramSize; + unsigned short wPendingSessions; + unsigned short wMaxSessionsConfigured; + unsigned short wMaxSessionsPossible; + unsigned short wMaxFrameSize; + unsigned short wNameCount; + struct { + unsigned char bName[16]; + unsigned char bNameNumber; + unsigned char bNameStatus; + } sNameTable[20]; +} _NETBIOS_ADAPTER_STATUS; + +typedef struct _tagNETBIOS_ELEMENT { + unsigned short wFlags; + unsigned short wOffset; + _NETBIOS_NCB sNCB; + _NETBIOS_NCB* pNCB; + char* pHeader; + unsigned short wHSize; +} _NETBIOS_ELEMENT; + +typedef struct _tagNETBIOS_LOCAL_TARGET { + unsigned char bNode[16]; +} _NETBIOS_LOCAL_TARGET; + +typedef struct _tagXFER_BLOCK_HEADER { + unsigned int wSequence; + unsigned int wType; + unsigned int wID; + unsigned int wLength; + unsigned int wNode; + unsigned int wUser1; +} _XFER_BLOCK_HEADER; + +typedef struct _NETNOW_NODE_ADDR { + _IPX_LOCAL_TARGET sIPX; + _NETBIOS_LOCAL_TARGET sNETBIOS; +} _NETNOW_NODE_ADDR; + +typedef struct _tagRMI_REGS _RMI_REGS; +typedef struct _tagBREGS _HMI_BREGS; +typedef struct _tagWREGS _HMI_WREGS; +typedef struct _tagDREGS _HMI_DREGS; +typedef struct _tagSREGS _HMI_SREGS; +typedef struct _tagIPX_HEADER _IPX_HEADER; +typedef struct _tagIPX_ECB _IPX_ECB; +typedef struct _tagIPX_INTERNET_ADDR _IPX_INTERNET_ADDR; +typedef struct _tagIPX_NETWORK_ADDR _IPX_NETWORK_ADDR; +typedef struct _tagIPX_LOCAL_TARGET _IPX_LOCAL_TARGET; +typedef struct _tagIPX_ELEMENT _IPX_ELEMENT; +typedef struct _tag_NETBIOS_NCB _NETBIOS_NCB; +typedef struct _tagNETBIOS_ADAPTER_STATUS _NETBIOS_ADAPTER_STATUS; +typedef struct _tagNETBIOS_ELEMENT _NETBIOS_ELEMENT; +typedef struct _tagNETBIOS_LOCAL_TARGET _NETBIOS_LOCAL_TARGET; +typedef struct _tagXFER_BLOCK_HEADER _XFER_BLOCK_HEADER; + +typedef struct tPD_net_player_info { + _IPX_LOCAL_TARGET addr_ipx; +} tPD_net_player_info; + +typedef struct tPD_net_game_info { + _IPX_LOCAL_TARGET addr_ipx; + tU32 last_response; +} tPD_net_game_info; + +#endif diff --git a/src/DETHRACE/pc-dos/dossys.c b/src/DETHRACE/pc-dos/dossys.c index 582581d5..ccd3f7f8 100644 --- a/src/DETHRACE/pc-dos/dossys.c +++ b/src/DETHRACE/pc-dos/dossys.c @@ -137,13 +137,16 @@ void PDInitialiseSystem(void) { } // IDA: void __cdecl PDShutdownSystem() -void PDShutdownSystem(void) { +void PDShutdownSystem() { + static int been_here = 0; // Added by dethrace LOG_TRACE("()"); - Harness_Hook_PDShutdownSystem(); - - CloseDiagnostics(); - exit(0); + if (!been_here) { + Harness_Hook_PDShutdownSystem(); + } else { + LOG_WARN("recursion detected => force exit"); + exit(8); + } } // IDA: void __cdecl PDSaveOriginalPalette() diff --git a/src/DETHRACE/pc-win95/win95net.c b/src/DETHRACE/pc-win95/win95net.c new file mode 100644 index 00000000..57a31891 --- /dev/null +++ b/src/DETHRACE/pc-win95/win95net.c @@ -0,0 +1,668 @@ +#include "pd/net.h" + +#include "brender/brender.h" +#include "dr_types.h" +#include "errors.h" +#include "globvrpb.h" +#include "harness/config.h" +#include "harness/hooks.h" +#include "harness/trace.h" +#include "harness/winsock.h" +#include "network.h" +#include "pd/net.h" +#include "pd/sys.h" +#include +#include +#include + +// dethrace: have switched out IPX implementation for IP + +tU32 gNetwork_init_flags; +tPD_net_game_info* gJoinable_games; +int gMatts_PC; +tU16 gSocket_number_pd_format; +//_IPX_ELEMENT gListen_elements[16]; +char gLocal_ipx_addr_string[32]; +//_IPX_ELEMENT gSend_elements[16]; +struct sockaddr_in* gLocal_addr_ipx; +char gReceive_buffer[512]; +tPD_net_player_info gRemote_net_player_info; +struct sockaddr_in* gBroadcast_addr_ipx; +tPD_net_player_info gLocal_net_player_info; +char gSend_buffer[512]; +tIPX_netnum gNetworks[16]; +struct sockaddr_in* gRemote_addr_ipx; +tU8* gSend_packet; +// W32 gListen_segment; +tU8* gSend_packet_ptr; +// W32 gSend_segment; +tU8* gListen_packet; +tU8* gListen_packet_ptr; +size_t gMsg_header_strlen; +int gNumber_of_networks; +int gNumber_of_hosts; +//_IPX_HEADER gLast_received_IPX_header; +tU16 gSocket_number_network_order; +// unsigned short gECB_offset; +tU16 gListen_selector; +tU16 gSend_selector; + +struct sockaddr_in gLocal_addr; +struct sockaddr_in gRemote_addr; +struct sockaddr_in gBroadcast_addr; +struct sockaddr_in gLast_received_addr; +int gSocket; + +#define MESSAGE_HEADER_STR "CW95MSG" +#define JOINABLE_GAMES_CAPACITY 16 + +// IDA: void __cdecl ClearupPDNetworkStuff() +void ClearupPDNetworkStuff(void) { + LOG_TRACE("()"); + NOT_IMPLEMENTED(); +} + +// IDA: void __usercall MATTMessageCheck(char *pFunction_name@, tNet_message *pMessage@, int pAlleged_size@) +void MATTMessageCheck(char* pFunction_name, tNet_message* pMessage, int pAlleged_size) { + LOG_TRACE("(\"%s\", %p, %d)", pFunction_name, pMessage, pAlleged_size); + NOT_IMPLEMENTED(); +} + +// IDA: int __usercall GetProfileText@(char *pDest@, int pDest_len@, char *pFname@, char *pKeyname@) +int GetProfileText(char* pDest, int pDest_len, char* pFname, char* pKeyname) { + FILE* fp; + char in_buf[256]; + int i; + int j; + int len; + LOG_TRACE("(\"%s\", %d, \"%s\", \"%s\")", pDest, pDest_len, pFname, pKeyname); + NOT_IMPLEMENTED(); +} + +// IDA: int __cdecl GetSocketNumberFromProfileFile() +int GetSocketNumberFromProfileFile(void) { + char str[256]; + int sscanf_res; + tU32 socknum; + LOG_TRACE("()"); + NOT_IMPLEMENTED(); +} + +// tU32 EthernetAddressToU32(SOCKADDR_IPX_* pAddr_ipx) { +// LOG_TRACE("(%p)", pAddr_ipx); +// NOT_IMPLEMENTED(); +// } + +void NetNowIPXLocalTarget2String(char* pString, struct sockaddr_in* pSock_addr_ipx) { + LOG_TRACE("(\"%s\", %p)", pString, pSock_addr_ipx); + + char portbuf[10]; + + inet_ntop(AF_INET, &pSock_addr_ipx->sin_addr, pString, 32); + sprintf(portbuf, ":%d", ntohs(pSock_addr_ipx->sin_port)); + strcat(pString, portbuf); +} + +// IDA: int __usercall GetMessageTypeFromMessage@(char *pMessage_str@) +int GetMessageTypeFromMessage(char* pMessage_str) { + char* real_msg; + int msg_type_int; + LOG_TRACE("(\"%s\")", pMessage_str); + + real_msg = &pMessage_str[4]; + msg_type_int = 0; + + // FIXME: "CW95MSG" value is used in and depends on platform + if (strncmp(real_msg, MESSAGE_HEADER_STR, gMsg_header_strlen) == 0) { + if (isdigit(real_msg[gMsg_header_strlen])) { + msg_type_int = real_msg[gMsg_header_strlen] - '0'; + } + if (msg_type_int != 0 && msg_type_int < 3) { + return msg_type_int; + } + } + return 999; +} + +int SameEthernetAddress(struct sockaddr_in* pAddr_ipx1, struct sockaddr_in* pAddr_ipx2) { + LOG_TRACE("(%p, %p)", pAddr_ipx1, pAddr_ipx2); + + return memcmp(pAddr_ipx1, pAddr_ipx2, sizeof(struct sockaddr_in)) == 0; +} + +/*SOCKADDR_IPX_* */ void* GetIPXAddrFromPlayerID(tPlayer_ID pPlayer_id) { + int i; + tU8* nodenum; + NOT_IMPLEMENTED(); +} + +// IDA: void __usercall MakeMessageToSend(int pMessage_type@) +void MakeMessageToSend(int pMessage_type) { + LOG_TRACE("(%d)", pMessage_type); + +#ifdef DETHRACE_FIX_BUGS + sprintf(gSend_buffer, "XXXX%s%1d", MESSAGE_HEADER_STR, pMessage_type); +#else + sprintf(gSend_buffer, "XXXX%s%0.1d", MESSAGE_HEADER_STR, pMessage_type); +#endif +} + +// IDA: int __cdecl ReceiveHostResponses() +int ReceiveHostResponses(void) { + char str[256]; + int i; + int already_registered; + LOG_TRACE("()"); + + char addr_string[32]; + unsigned int sa_len; + int wsa_error; + + sa_len = sizeof(gRemote_addr); + while (1) { + if (recvfrom(gSocket, gReceive_buffer, sizeof(gReceive_buffer), 0, (struct sockaddr*)&gRemote_addr, &sa_len) == -1) { + break; + } + NetNowIPXLocalTarget2String(addr_string, gRemote_addr_ipx); + dr_dprintf("ReceiveHostResponses(): Received string '%s' from %s", gReceive_buffer, addr_string); + + if (SameEthernetAddress(gLocal_addr_ipx, gRemote_addr_ipx)) { + dr_dprintf("*** Discounting the above 'cos we sent it ***"); + continue; + } + if (GetMessageTypeFromMessage(gReceive_buffer) != 2) { + dr_dprintf("*** Discounting the above 'cos it's not a host reply ***"); + continue; + } + + dr_dprintf("*** It's a host reply! ***"); + already_registered = 0; + for (i = 0; i < gNumber_of_hosts; i++) { + if (SameEthernetAddress(&gJoinable_games[i].addr_in, gRemote_addr_ipx)) { + already_registered = 1; + break; + } + } + if (already_registered) { + dr_dprintf("That game already registered"); + gJoinable_games[i].last_response = PDGetTotalTime(); + } else { + dr_dprintf("Adding joinable game to slot #%d", gNumber_of_hosts); + gJoinable_games[gNumber_of_hosts].addr_in = *gRemote_addr_ipx; + gJoinable_games[gNumber_of_hosts].last_response = PDGetTotalTime(); + gNumber_of_hosts++; + dr_dprintf("Number of games found so far: %d", gNumber_of_hosts); + } + if (gNumber_of_hosts) { + dr_dprintf("Currently registered net games:"); + for (i = 0; i < gNumber_of_hosts; i++) { + NetNowIPXLocalTarget2String(str, &gJoinable_games[i].addr_in); + dr_dprintf("%d: Host addr %s", i, str); + } + } + } + wsa_error = WSAGetLastError() != WSAEWOULDBLOCK; + if (wsa_error == 0) { + return 1; + } + dr_dprintf("ReceiveHostResponses(): Error on recvfrom() - WSAGetLastError=%d", wsa_error); + return 0; +} + +// IDA: int __cdecl BroadcastMessage() +int BroadcastMessage(void) { + int i; + int errors; + char broadcast_addr_string[32]; + char* real_msg; + LOG_TRACE("()"); + + errors = 0; + for (i = 0; i < gNumber_of_networks; i++) { + //*(_DWORD*)gBroadcast_addr_ipx->sa_netnum = gNetworks[i]; + NetNowIPXLocalTarget2String(broadcast_addr_string, gBroadcast_addr_ipx); + dr_dprintf("Broadcasting on address '%s'", broadcast_addr_string); + if (sendto(gSocket, gSend_buffer, strlen(gSend_buffer) + 1, 0, (struct sockaddr*)&gBroadcast_addr, sizeof(gBroadcast_addr)) == -1) { + dr_dprintf("BroadcastMessage(): Error on sendto() - WSAGetLastError=%d", WSAGetLastError()); + errors = 1; + } + } + return errors == 0; +} + +// IDA: int __cdecl PDNetInitialise() +int PDNetInitialise(void) { + tU32 timenow; + char profile_string[32]; + char key_name[32]; + int sscanf_res; + int i; + tU32 netnum; + char str[256]; + int mess_num; + + struct linger so_linger; + unsigned int sa_len; + WSADATA wsadata; + LOG_TRACE("()"); + + sa_len = sizeof(struct sockaddr_in); + dr_dprintf("PDNetInitialise()"); + int ipx_socket_num = 12286; + // Dont bother to handle network.ini + // if (gWin32_should_load_network_ini) { + // if (GetPrivateProfileStringA( + // "Network", + // "IPXSocket", + // Default, + // (LPSTR)ReturnedString, + // 0x20u, + // gNetwork_profile_fname)) { + // v11 = sscanf(ReturnedString, "%x", &v9); + // if (v11) { + // if (v11 != -1) { + // dr_dprintf("New IPX socket %4.4x", v9); + // ipx_socket_num = sub_454930(v9); + // } + // } + // } + // } + gLocal_addr_ipx = &gLocal_addr; + gRemote_addr_ipx = &gRemote_addr; + gBroadcast_addr_ipx = &gBroadcast_addr; + memset(&gLocal_addr, 0, sizeof(struct sockaddr_in)); + memset(&gRemote_addr, 0, sizeof(struct sockaddr_in)); + memset(&gBroadcast_addr, 0, sizeof(struct sockaddr_in)); + + // gLocal_addr_ipx->sa_family = AF_IPX; + // gRemote_addr_ipx->sa_family = AF_IPX; + // gBroadcast_addr_ipx->sa_family = AF_IPX; + // gLocal_addr_ipx->sa_socket = ipx_socket_num; + // gRemote_addr_ipx->sa_socket = ipx_socket_num; + // gBroadcast_addr_ipx->sa_socket = ipx_socket_num; + + // // IPX broadcast + // gBroadcast_addr_ipx->sa_nodenum[0] = -1; + // gBroadcast_addr_ipx->sa_nodenum[1] = -1; + // gBroadcast_addr_ipx->sa_nodenum[2] = -1; + // gBroadcast_addr_ipx->sa_nodenum[3] = -1; + // gBroadcast_addr_ipx->sa_nodenum[4] = -1; + // gBroadcast_addr_ipx->sa_nodenum[5] = -1; + + gLocal_addr.sin_family = AF_INET; + gLocal_addr.sin_port = htons(12286); + gLocal_addr.sin_addr.s_addr = INADDR_ANY; + gRemote_addr.sin_family = AF_INET; + gRemote_addr.sin_port = htons(12286); + gBroadcast_addr.sin_family = AF_INET; + gBroadcast_addr.sin_port = htons(12286); + + // original code was using MAKEWORD(1, 1) + if (WSAStartup(MAKEWORD(2, 2), &wsadata) == -1) { + dr_dprintf("PDNetInitialise(): WSAStartup() failed"); + return -1; + } + + // gSocket = socket(6, 2, 1000); + gSocket = socket(AF_INET, SOCK_DGRAM, 0); + if (gSocket == -1) { + dr_dprintf("PDNetInitialise(): Failed to create socket - WSAGetLastError=%d", WSAGetLastError()); + WSACleanup(); + return -1; + } + int broadcast = 1; + setsockopt(gSocket, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof(broadcast)); + so_linger.l_onoff = 1; + so_linger.l_linger = 0; + setsockopt(gSocket, SOL_SOCKET, SO_LINGER, &so_linger, sizeof(so_linger)); + + unsigned long nobio = 1; + if (ioctlsocket(gSocket, FIONBIO, &nobio) == -1) { + dr_dprintf("Error on ioctlsocket() - WSAGetLastError=%d", WSAGetLastError()); + closesocket(gSocket); + WSACleanup(); + return -1; + } + + if (harness_game_config.no_bind == 0) { + if (bind(gSocket, (struct sockaddr*)&gLocal_addr, sizeof(gLocal_addr)) == -1) { + dr_dprintf("Error on bind() - WSAGetLastError=%d", WSAGetLastError()); + closesocket(gSocket); + WSACleanup(); + return -1; + } + } + + int res = getsockname(gSocket, (struct sockaddr*)&gLocal_addr, &sa_len); + NetNowIPXLocalTarget2String(gLocal_ipx_addr_string, gLocal_addr_ipx); + // gNetworks[0] = *(tIPX_netnum*)gLocal_addr_ipx->sa_netnum; + gNumber_of_networks = 1; + + // if (gWin32_should_load_network_ini) { + // for (i = 1; i <= 15; ++i) { + // sprintf(KeyName, "%s%d", "Network", i); + // if (GetPrivateProfileStringA( + // "Network", + // KeyName, + // Default, + // (LPSTR)ReturnedString, + // 0x20u, + // gNetwork_profile_fname)) { + // v11 = sscanf(ReturnedString, "%x", &network_nbr); + // if (v11) { + // if (v11 != -1) { + // dr_dprintf("Found network number '%x' in INI file", network_nbr); + // gNetworks[gNumber_of_networks].bNetwork[0] = HIBYTE(network_nbr); + // gNetworks[gNumber_of_networks].bNetwork[1] = (network_nbr & 0xFF0000u) >> 16; + // gNetworks[gNumber_of_networks].bNetwork[2] = BYTE1(network_nbr); + // gNetworks[gNumber_of_networks].bNetwork[3] = network_nbr; + // if (gNetworks[gNumber_of_networks].bNetwork[0] != gLocal_addr_ipx->sa_netnum[0] + // || gNetworks[gNumber_of_networks].bNetwork[1] != gLocal_addr_ipx->sa_netnum[1] + // || gNetworks[gNumber_of_networks].bNetwork[2] != gLocal_addr_ipx->sa_netnum[2] + // || gNetworks[gNumber_of_networks].bNetwork[3] != gLocal_addr_ipx->sa_netnum[3]) { + // ++gNumber_of_networks; + // } + // } + // } + // } + // } + // dr_dprintf("Total networks = %d", gNumber_of_networks); + // } + // byte_536440 = *gLocal_addr_ipx; + + dr_dprintf("Socket bound OK; local address is '%s'", gLocal_ipx_addr_string); + gMsg_header_strlen = 7; + if (strstr(gLocal_ipx_addr_string, "00a0240f9fac")) { + gMatts_PC = 1; + } + return 0; +} + +// IDA: int __cdecl PDNetShutdown() +int PDNetShutdown(void) { + LOG_TRACE("()"); + + dr_dprintf("PDNetShutdown()"); + if (gSocket != -1) { + closesocket(gSocket); + } + gSocket = -1; + return 0; +} + +// IDA: void __cdecl PDNetStartProducingJoinList() +void PDNetStartProducingJoinList(void) { + LOG_TRACE("()"); + + dr_dprintf("PDNetStartProducingJoinList()"); + gNumber_of_hosts = 0; + gJoinable_games = BrMemAllocate(sizeof(tPD_net_game_info) * JOINABLE_GAMES_CAPACITY, 0x80u); + if (gJoinable_games == NULL) { + PDFatalError("Can't allocate memory for joinable games"); + } +} + +// IDA: void __cdecl PDNetEndJoinList() +void PDNetEndJoinList(void) { + LOG_TRACE("()"); + + dr_dprintf("PDNetEndJoinList()"); + if (gJoinable_games) { + BrMemFree(gJoinable_games); + } + gJoinable_games = NULL; +} + +// IDA: int __usercall PDNetGetNextJoinGame@(tNet_game_details *pGame@, int pIndex@) +int PDNetGetNextJoinGame(tNet_game_details* pGame, int pIndex) { + static tU32 next_broadcast_time = 0; + int i; + int j; + int number_of_hosts_has_changed; + char str[256]; + LOG_TRACE9("(%p, %d)", pGame, pIndex); + + dr_dprintf("PDNetGetNextJoinGame(): pIndex is %d", pIndex); + if (pIndex == 0) { + do { + number_of_hosts_has_changed = 0; + for (i = 0; i < gNumber_of_hosts; i++) { + if (gJoinable_games[i].last_response + 10000 < PDGetTotalTime()) { + number_of_hosts_has_changed = 1; + for (j = i; j < gNumber_of_hosts - 1; j++) { + memcpy(&gJoinable_games[j], &gJoinable_games[j + 1], sizeof(tPD_net_game_info)); + } + } + } + if (number_of_hosts_has_changed) { + gNumber_of_hosts--; + } + } while (number_of_hosts_has_changed); + if (PDGetTotalTime() > next_broadcast_time) { + next_broadcast_time = PDGetTotalTime() + 3000; + MakeMessageToSend(1); + if (BroadcastMessage() == 0) { + dr_dprintf("PDNetGetNextJoinGame(): Error on BroadcastMessage()"); + } + } + } + ReceiveHostResponses(); + if (gNumber_of_hosts <= pIndex) { + return 0; + } + dr_dprintf("PDNetGetNextJoinGame(): Adding game."); + memcpy(&pGame->pd_net_info.addr_in, &gJoinable_games[pIndex].addr_in, sizeof(pGame->pd_net_info.addr_in)); + return 1; +} + +// IDA: void __usercall PDNetDisposeGameDetails(tNet_game_details *pDetails@) +void PDNetDisposeGameDetails(tNet_game_details* pDetails) { + LOG_TRACE("(%p)", pDetails); + NOT_IMPLEMENTED(); +} + +// IDA: int __usercall PDNetHostGame@(tNet_game_details *pDetails@, char *pHost_name@, void **pHost_address@) +int PDNetHostGame(tNet_game_details* pDetails, char* pHost_name, void** pHost_address) { + LOG_TRACE("(%p, \"%s\", %p)", pDetails, pHost_name, pHost_address); + + dr_dprintf("PDNetHostGame()"); + *pHost_address = &gLocal_addr; + return 1; +} + +// IDA: int __usercall PDNetJoinGame@(tNet_game_details *pDetails@, char *pPlayer_name@) +int PDNetJoinGame(tNet_game_details* pDetails, char* pPlayer_name) { + LOG_TRACE("(%p, \"%s\")", pDetails, pPlayer_name); + + dr_dprintf("PDNetJoinGame()"); + return 0; +} + +// IDA: void __usercall PDNetLeaveGame(tNet_game_details *pDetails@) +void PDNetLeaveGame(tNet_game_details* pDetails) { + LOG_TRACE("(%p)", pDetails); + + dr_dprintf("PDNetLeaveGame()"); +} + +// IDA: void __usercall PDNetHostFinishGame(tNet_game_details *pDetails@) +void PDNetHostFinishGame(tNet_game_details* pDetails) { + LOG_TRACE("(%p)", pDetails); + + dr_dprintf("PDNetHostFinishGame()"); +} + +// IDA: tU32 __usercall PDNetExtractGameID@(tNet_game_details *pDetails@) +tU32 PDNetExtractGameID(tNet_game_details* pDetails) { + LOG_TRACE("(%p)", pDetails); + + dr_dprintf("PDNetExtractGameID()"); + return ntohs(pDetails->pd_net_info.addr_in.sin_port); // PDGetTotalTime(); +} + +// IDA: tPlayer_ID __usercall PDNetExtractPlayerID@(tNet_game_details *pDetails@) +tPlayer_ID PDNetExtractPlayerID(tNet_game_details* pDetails) { + LOG_TRACE("(%p)", pDetails); + + dr_dprintf("PDNetExtractPlayerID()"); + return ntohs(gLocal_addr_ipx->sin_port); +} + +// IDA: void __usercall PDNetObtainSystemUserName(char *pName@, int pMax_length@) +void PDNetObtainSystemUserName(char* pName, int pMax_length) { + int result; + char* found; + dr_dprintf("PDNetObtainSystemUserName()"); + + result = gethostname(pName, pMax_length); + if (result == 0) { + } + + while (1) { + found = strpbrk(pName, "_=(){}[]<>!$%^&*/:@~;'#,?\\|`\""); + if (found == NULL) { + break; + } + *found = '-'; + } +} + +// IDA: int __usercall PDNetSendMessageToPlayer@(tNet_game_details *pDetails@, tNet_message *pMessage@, tPlayer_ID pPlayer@) +int PDNetSendMessageToPlayer(tNet_game_details* pDetails, tNet_message* pMessage, tPlayer_ID pPlayer) { + char str[256]; + // SOCKADDR_IPX_* remote_addr_ipx; + LOG_TRACE("(%p, %p, %d)", pDetails, pMessage, pPlayer); + NOT_IMPLEMENTED(); +} + +// IDA: int __usercall PDNetSendMessageToAllPlayers@(tNet_game_details *pDetails@, tNet_message *pMessage@) +int PDNetSendMessageToAllPlayers(tNet_game_details* pDetails, tNet_message* pMessage) { + char str[256]; + int i; + LOG_TRACE("(%p, %p)", pDetails, pMessage); + + for (i = 0; i < gNumber_of_net_players; ++i) { + if (i == gThis_net_player_index) { + continue; + } + if (sendto(gSocket, (const char*)pMessage, pMessage->overall_size, 0, (struct sockaddr*)&gNet_players[i].pd_net_info.addr_in, sizeof(gNet_players[i].pd_net_info.addr_in)) == -1) { + dr_dprintf("PDNetSendMessageToAllPlayers(): Error on sendto() - WSAGetLastError=%d", WSAGetLastError()); + NetDisposeMessage(pDetails, pMessage); + return 1; + } + } + NetDisposeMessage(pDetails, pMessage); + return 0; +} + +// IDA: tNet_message* __usercall PDNetGetNextMessage@(tNet_game_details *pDetails@, void **pSender_address@) +tNet_message* PDNetGetNextMessage(tNet_game_details* pDetails, void** pSender_address) { + char* receive_buffer; + char str[256]; + int msg_type; + LOG_TRACE("(%p, %p)", pDetails, pSender_address); + + char addr_str[32]; + unsigned int sa_len; + int res; + tNet_message* msg; + + sa_len = sizeof(gRemote_addr); + msg = NetAllocateMessage(512); + receive_buffer = (char*)msg; + res = recvfrom(gSocket, receive_buffer, 512, 0, (struct sockaddr*)&gRemote_addr, &sa_len); + res = res != -1; + if (res == 0) { + res = WSAGetLastError() != WSAEWOULDBLOCK; + if (res) { + sprintf(str, "PDNetGetNextMessage(): Error on recvfrom() - WSAGetLastError=%d", res); + PDFatalError(str); + } + } else { + NetNowIPXLocalTarget2String(addr_str, gRemote_addr_ipx); + if (!SameEthernetAddress(gLocal_addr_ipx, gRemote_addr_ipx)) { + msg_type = GetMessageTypeFromMessage(receive_buffer); + switch (msg_type) { + case 1: + if (gNet_mode == eNet_mode_host) { + dr_dprintf("PDNetGetNextMessage(): Received '%s' from '%s', replying to joiner", receive_buffer, addr_str); + MakeMessageToSend(2); + if (sendto(gSocket, gSend_buffer, strlen(gSend_buffer) + 1, 0, (struct sockaddr*)&gRemote_addr, sizeof(gRemote_addr)) == -1) { + dr_dprintf("PDNetGetNextMessage(): Error on sendto() - WSAGetLastError=%d", WSAGetLastError()); + } + } + break; + case 2: + // no-op + break; + default: + dr_dprintf("PDNetGetNextMessage(): res is %d, received message type %d from '%s', passing up", res, msg->contents.header.type, addr_str); + memcpy(&gLast_received_addr, gRemote_addr_ipx, sizeof(gLast_received_addr)); + *pSender_address = &gLast_received_addr; + return msg; + } + } + } + msg->guarantee_number = 0; + NetDisposeMessage(pDetails, msg); + return 0; +} + +// IDA: tNet_message* __usercall PDNetAllocateMessage@(tU32 pSize@, tS32 pSize_decider@) +tNet_message* PDNetAllocateMessage(tU32 pSize, tS32 pSize_decider) { + LOG_TRACE("(%d, %d)", pSize, pSize_decider); + NOT_IMPLEMENTED(); +} + +// IDA: void __usercall PDNetDisposeMessage(tNet_game_details *pDetails@, tNet_message *pMessage@) +void PDNetDisposeMessage(tNet_game_details* pDetails, tNet_message* pMessage) { + LOG_TRACE("(%p, %p)", pDetails, pMessage); + NOT_IMPLEMENTED(); +} + +// IDA: void __usercall PDNetSetPlayerSystemInfo(tNet_game_player_info *pPlayer@, void *pSender_address@) +void PDNetSetPlayerSystemInfo(tNet_game_player_info* pPlayer, void* pSender_address) { + LOG_TRACE("(%p, %p)", pPlayer, pSender_address); + + dr_dprintf("PDNetSetPlayerSystemInfo()"); + memcpy(&pPlayer->pd_net_info, pSender_address, sizeof(pPlayer->pd_net_info)); +} + +// IDA: void __usercall PDNetDisposePlayer(tNet_game_player_info *pPlayer@) +void PDNetDisposePlayer(tNet_game_player_info* pPlayer) { + LOG_TRACE("(%p)", pPlayer); + NOT_IMPLEMENTED(); +} + +// IDA: int __usercall PDNetSendMessageToAddress@(tNet_game_details *pDetails@, tNet_message *pMessage@, void *pAddress@) +int PDNetSendMessageToAddress(tNet_game_details* pDetails, tNet_message* pMessage, void* pAddress) { + char str[256]; + 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()); + NetDisposeMessage(pDetails, pMessage); + return 1; + } + + NetDisposeMessage(pDetails, pMessage); + return 0; +} + +// IDA: int __usercall PDNetInitClient@(tNet_game_details *pDetails@) +int PDNetInitClient(tNet_game_details* pDetails) { + LOG_TRACE("(%p)", pDetails); + NOT_IMPLEMENTED(); +} + +// IDA: int __cdecl PDNetGetHeaderSize() +int PDNetGetHeaderSize(void) { + LOG_TRACE("()"); + + return 0; +} diff --git a/src/DETHRACE/pc-win95/win95net_types.h b/src/DETHRACE/pc-win95/win95net_types.h new file mode 100644 index 00000000..f51a9c31 --- /dev/null +++ b/src/DETHRACE/pc-win95/win95net_types.h @@ -0,0 +1,25 @@ +#ifndef WIN95_NET_TYPES_H +#define WIN95_NET_TYPES_H + +// #include "dr_types.h" +#include "harness/win95_polyfill.h" +#include "harness/winsock.h" + +// dethrace: have switched out IPX implementation for IP + +typedef struct tPD_net_player_info { + // struct sockaddr_ipx addr_ipx; + struct sockaddr_in addr_in; +} tPD_net_player_info; + +typedef struct tPD_net_game_info { + // struct sockaddr_ipx addr_ipx; + struct sockaddr_in addr_in; + tU32 last_response; +} tPD_net_game_info; + +// typedef struct tIPX_netnum { +// unsigned char bNetwork[4]; +// } tIPX_netnum; + +#endif diff --git a/src/DETHRACE/pd/net.h b/src/DETHRACE/pd/net.h index 53dae38b..f0abb54d 100644 --- a/src/DETHRACE/pd/net.h +++ b/src/DETHRACE/pd/net.h @@ -10,59 +10,17 @@ #include "brender/br_types.h" #include "dr_types.h" -// void ClearupPDNetworkStuff(void); +void ClearupPDNetworkStuff(void); -// void MATTMessageCheck(char* pFunction_name, tNet_message* pMessage, int pAlleged_size); +void MATTMessageCheck(char* pFunction_name, tNet_message* pMessage, int pAlleged_size); -// int GetProfileText(char* pDest, int pDest_len, char* pFname, char* pKeyname); +int GetMessageTypeFromMessage(char* pMessage_str); -// int GetSocketNumberFromProfileFile(void); +void MakeMessageToSend(int pMessage_type); -// tU32 EthernetAddressToU32(_IPX_LOCAL_TARGET* pAddr_ipx); +int ReceiveHostResponses(void); -// void NetNowIPXLocalTarget2String(char* pString, _IPX_LOCAL_TARGET* pSock_addr_ipx); - -// int GetMessageTypeFromMessage(char* pMessage_str); - -// int SameEthernetAddress(_IPX_LOCAL_TARGET* pAddr_ipx1, _IPX_LOCAL_TARGET* pAddr_ipx2); - -// _IPX_LOCAL_TARGET* GetIPXAddrFromPlayerID(tPlayer_ID pPlayer_id); - -// void MakeMessageToSend(int pMessage_type); - -// int ReceiveHostResponses(void); - -// int BroadcastMessage(void); - -// int hmiIPXCloseSocket(W32 wSocket); - -// void hmiIPXListenForPacket(_IPX_ECB* pECB_ptr, tU32 pOffset); - -// int hmiIPXPostListen(_IPX_ECB* pECB_ptr, tU32 pOffset); - -// int hmiIPXGetData(PSTR pData, tU32 wDSize); - -// void hmiIPXSendPacket(_IPX_ECB* sECB, _IPX_ECB** pPacket, PSTR pHeader, W32 wSize); - -// int hmiIPXSendDataDirect(PSTR pHeader, W32 wHSize, PSTR pData, W32 wDSize, _NETNOW_NODE_ADDR* sNode); - -// void hmiIPXGetInternetworkAddr(_IPX_INTERNET_ADDR* sInterworkAddr); - -// void hmiIPXGetLocalTarget(_IPX_LOCAL_TARGET* sNetworkAddr); - -// int AllocateRealMem(W32 wSize, PSTR* pPtr, W32* pSegment, tU16* pSelector); - -// int FreeRealMem(tU16 pSelector); - -// int hmiIPXInstalled(void); - -// int hmiIPXOpenSocket(W32 wSocket); - -// void GetLargestPacketSizeOoErBetterInsertLinfordChristieJokeHere(void); - -// int hmiIPXInitSystem(W32 wSocket); - -// void GetIPXToStickItsEarToTheGround(void); +int BroadcastMessage(void); int PDNetInitialise(void); diff --git a/src/S3/sos_dos_types.h b/src/S3/sos_dos_types.h new file mode 100644 index 00000000..3deeb24d --- /dev/null +++ b/src/S3/sos_dos_types.h @@ -0,0 +1,187 @@ +typedef unsigned int W32; + +typedef struct _tag_sos_evds_struct _SOS_EVDS_STRUCT; +typedef struct _tag_sos_vds_struct _SOS_VDS_STRUCT; +typedef struct _tag_sos_sample _SOS_SAMPLE; +typedef _SOS_SAMPLE* PSOSSAMPLE; +typedef struct _tagCAPABILITIES _SOS_CAPABILITIES; +typedef _SOS_CAPABILITIES* PSOSCAPABILITIES; +typedef struct _SOS_HARDWARE* PSOSHARDWARE; +typedef struct _tag_sos_driver _SOS_DIGI_DRIVER; +typedef _SOS_DIGI_DRIVER* PSOSDIGIDRIVER; +typedef struct _SOS_DRV_FILEHEADER* PSOSDRVFILEHEADER; +typedef struct _SOS_DRV_DRIVERHEADER* PSOSDRVDRIVERHEADER; +typedef struct _tag_sos_system _SOS_SYSTEM; +typedef _SOS_SYSTEM* PSOSSYSTEM; +typedef struct _tag_sos_det_system _SOS_DET_SYSTEM; +typedef _SOS_DET_SYSTEM* PSOSDETSYSTEM; +typedef struct _tag_sos_timer_system _SOS_TIMER_SYSTEM; +typedef _SOS_TIMER_SYSTEM* PSOSTIMERSYSTEM; + +typedef struct _tag_sos_evds_struct { + unsigned int region_size; + unsigned int offset; + unsigned int segment; + unsigned short number_available; + unsigned short number_used; + unsigned int page0; +} _SOS_EVDS_STRUCT; + +typedef struct _tag_sos_vds_struct { + unsigned int region_size; + unsigned int offset; + unsigned short segment; + unsigned short ID; + unsigned int physical; +} _SOS_VDS_STRUCT; + +typedef struct _tag_sos_sample { + char* pSample; + char* pSampleCurrent; + char* pSampleLoop; + unsigned long wLength; + unsigned long wLoopLength; + unsigned long wLoopEndLength; + unsigned long wLoopStage; + unsigned long wID; + unsigned long wFlags; + unsigned long wPriority; + unsigned long hSample; + unsigned long wVolume; + unsigned long wLoopCount; + unsigned long wRate; + unsigned long wBitsPerSample; + unsigned long wChannels; + unsigned long wFormat; + unsigned long wPanPosition; + unsigned long wPanSpeed; + unsigned long wPanStart; + unsigned long wPanEnd; + unsigned long wPanMode; + unsigned long wTotalBytesProcessed; + void (*pfnSampleProcessed)(PSOSSAMPLE*); + void (*pfnSampleDone)(PSOSSAMPLE*); + void (*pfnSampleLoop)(PSOSSAMPLE*); + unsigned long wSystem[16]; + unsigned long wUser[16]; + PSOSSAMPLE* pLink; + PSOSSAMPLE* pNext; +} _SOS_SAMPLE; + +typedef struct _tagCAPABILITIES { + unsigned char szDeviceName[32]; + W32 wDeviceVersion; + W32 wBitsPerSample; + W32 wChannels; + W32 wMinRate; + W32 wMaxRate; + W32 wMixerOnBoard; + W32 wMixerFlags; + W32 wFlags; + short* lpPortList; + short* lpDMAList; + short* lpIRQList; + short* lpRateList; + W32 fBackground; + W32 wID; + W32 wTimerID; +} _SOS_CAPABILITIES; + +typedef struct _SOS_HARDWARE { + W32 wPort; + W32 wIRQ; + W32 wDMA; + W32 wParam; +} _SOS_HARDWARE; + +typedef struct _tag_sos_driver { + W32 wFlags; + unsigned long wDriverRate; + unsigned long wDriverChannels; + unsigned long wDriverBitsPerSample; + unsigned long wDriverFormat; + unsigned long wMixerChannels; + unsigned long wDMACountRegister; + unsigned long wDMAPosition; + unsigned long wDMALastPosition; + unsigned long wDMADistance; + char* pXFERPosition; + unsigned long wXFERJumpAhead; + _SOS_SAMPLE* pSampleList; + void (*pfnPseudoDMAFunction)(void); + char* pDMABuffer; + char* pDMABufferEnd; + unsigned long wDMABufferSize; + char* pMixingBuffer; + char* pMixingBufferEnd; + unsigned long wMixingBufferSize; + unsigned long wActiveChannels; + _SOS_SAMPLE* pSamples; + _SOS_HARDWARE sHardware; + _SOS_CAPABILITIES sCaps; + char* lpDriverDS; + char* lpDriverCS; + W32 wSize; + unsigned long dwLinear; + unsigned long dwDMAPhysical; + char* lpDMABuffer; + W32 hMemory; + W32 wDMARealSeg; + W32 wID; + void (*pfnMixFunction)(void); +} _SOS_DIGI_DRIVER; + +typedef struct _SOS_DRV_FILEHEADER { + unsigned char szName[32]; + W32 wDrivers; + W32 lOffset; + W32 lFileSize; +} _SOS_DRV_FILEHEADER; + +typedef struct _SOS_DRV_DRIVERHEADER { + unsigned char szName[32]; + W32 lNextDriver; + W32 wSize; + W32 wDeviceID; + W32 wExtenderType; +} _SOS_DRV_DRIVERHEADER; + +typedef struct _tag_sos_system { + W32 wFlags; + unsigned char szDriverPath[128]; + unsigned char szTempDriverPath[128]; + PSOSDIGIDRIVER pDriver[5]; + _SOS_VDS_STRUCT sVDS; + _SOS_DRV_FILEHEADER sFileHeader; + _SOS_DRV_DRIVERHEADER sDriverHeader; + char* (*pMemAllocFunction)(unsigned long); + void (*pMemFreeFunction)(char*, W32); +} _SOS_SYSTEM; + +typedef struct _tag_sos_det_system { + W32 wFlags; + unsigned char szDriverPath[128]; + unsigned char szTempDriverPath[128]; + _SOS_DRV_FILEHEADER sFileHeader; + _SOS_DRV_DRIVERHEADER sDriverHeader; + _SOS_CAPABILITIES sCaps; + PSOSCAPABILITIES pCaps; + char* lpBufferDS; + char* lpBufferCS; + W32 hFile; + unsigned long dwDriverIndex; + W32 wDriverIndexCur; + W32 hMemory; + unsigned long dwLinear; +} _SOS_DET_SYSTEM; + +typedef struct _tag_sos_timer_system { + W32 wFlags; + W32 wChipDivisor; + void (*pfnEvent[16])(void); + W32 wEventRate[16]; + unsigned long dwAdditiveFraction[16]; + unsigned long dwCurrentSummation[16]; + W32 wMIDIEventSongHandle[16]; + W32 wMIDIActiveSongHandle; +} _SOS_TIMER_SYSTEM; diff --git a/src/harness/CMakeLists.txt b/src/harness/CMakeLists.txt index 13f08467..5228f774 100644 --- a/src/harness/CMakeLists.txt +++ b/src/harness/CMakeLists.txt @@ -64,6 +64,7 @@ target_sources(harness PRIVATE sound/sound.c sound/sound.h win95/polyfill.c + win95/winsock.c platforms/null.c platforms/null.h @@ -101,6 +102,7 @@ if(WIN32) target_sources(harness PRIVATE os/windows.c ) + target_link_libraries(harness PRIVATE ws2_32) elseif(APPLE) target_sources(harness PRIVATE os/macos.c diff --git a/src/harness/harness.c b/src/harness/harness.c index 6762be25..ef82c074 100644 --- a/src/harness/harness.c +++ b/src/harness/harness.c @@ -161,6 +161,8 @@ void Harness_Init(int* argc, char* argv[]) { harness_game_config.start_full_screen = 0; // Emulate DOS behavior harness_game_config.dos_mode = 0; + // Skip binding socket to allow local network testing + harness_game_config.no_bind = 0; // install signal handler by default harness_game_config.install_signalhandler = 1; @@ -249,6 +251,9 @@ int Harness_ProcessCommandLine(int* argc, char* argv[]) { } else if (strcasecmp(argv[i], "--dos-mode") == 0) { harness_game_config.dos_mode = 1; handled = 1; + } else if (strcasecmp(argv[i], "--no-bind") == 0) { + harness_game_config.no_bind = 1; + handled = 1; } if (handled) { diff --git a/src/harness/include/harness/config.h b/src/harness/include/harness/config.h index f42cd6f6..38bdeb19 100644 --- a/src/harness/include/harness/config.h +++ b/src/harness/include/harness/config.h @@ -42,6 +42,7 @@ typedef struct tHarness_game_config { float volume_multiplier; int start_full_screen; int dos_mode; + int no_bind; int install_signalhandler; } tHarness_game_config; diff --git a/src/harness/include/harness/winsock.h b/src/harness/include/harness/winsock.h new file mode 100644 index 00000000..51ab2ee9 --- /dev/null +++ b/src/harness/include/harness/winsock.h @@ -0,0 +1,52 @@ +/* + * Inspiration taken from https://github.com/TheAssemblyArmada/Vanilla-Conquer/blob/vanilla/common/sockets.h + */ + +#ifndef HARNESS_WINSOCK_H +#define HARNESS_WINSOCK_H + +#include + +#ifdef _WIN32 +#define _WINSOCK_DEPRECATED_NO_WARNINGS +#include +#include + +#else /* Assume posix style sockets on non-windows */ + +#include +#include +#include +#include // for getaddrinfo() and freeaddrinfo() +#include +#include +#include +#include // for close() + +#define closesocket(x) close(x) +#define WSAEISCONN EISCONN +#define WSAEINPROGRESS EINPROGRESS +#define WSAEALREADY EALREADY +#define WSAEADDRINUSE EADDRINUSE +#define WSAEADDRNOTAVAIL EADDRNOTAVAIL +#define WSAEBADF EBADF +#define WSAECONNREFUSED ECONNREFUSED +#define WSAEINTR EINTR +#define WSAENOTSOCK ENOTSOCK +#define WSAEWOULDBLOCK EWOULDBLOCK +#define WSAEINVAL EINVAL +#define WSAETIMEDOUT ETIMEDOUT + +#define MAKEWORD(x, y) ((y) << 8 | (x)) + +typedef struct WSADATA { +} WSADATA; + +int WSAStartup(int version, WSADATA* data); +int WSAGetLastError(void); +int WSACleanup(void); +int ioctlsocket(int handle, long cmd, unsigned long* argp); + +#endif /* _WIN32 */ + +#endif diff --git a/src/harness/win95/winsock.c b/src/harness/win95/winsock.c new file mode 100644 index 00000000..15e86e83 --- /dev/null +++ b/src/harness/win95/winsock.c @@ -0,0 +1,27 @@ +#include "harness/winsock.h" + +#ifndef _WIN32 + +int WSAStartup(int version, WSADATA* data) { + // very minimal, we don't care about the arguments + return 0; +} + +int WSAGetLastError(void) { + return errno; +} + +int WSACleanup(void) { + return 0; +} + +// Only implement non-blocking call for now +int ioctlsocket(int handle, long cmd, unsigned long* argp) { + assert(cmd == FIONBIO); + + int flags = fcntl(handle, F_GETFL); + flags |= O_NONBLOCK; + return fcntl(handle, F_SETFL, flags); +} + +#endif diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 460cbbe9..5d91982c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -28,7 +28,7 @@ if(NOT MSVC) endif() endif() else() - target_compile_definitions(dethrace_test PRIVATE -D_CRT_SECURE_NO_WARNINGS -DSDL_MAIN_HANDLED) + target_compile_definitions(dethrace_test PRIVATE -D_CRT_SECURE_NO_WARNINGS -DSDL_MAIN_HANDLED -DWIN32_LEAN_AND_MEAN) target_link_libraries(dethrace_test PRIVATE dbghelp) endif()