#include "newgame.h"
 
#include "cutscene.h"
 
#include "displays.h"
 
#include "drmem.h"
 
#include "errors.h"
 
#include "flicplay.h"
 
#include "globvars.h"
 
#include "globvrpb.h"
 
#include "grafdata.h"
 
#include "graphics.h"
 
#include "harness/config.h"
 
#include "harness/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"
 
#include <stdlib.h>
 
#include <string.h>
 
 
 
tU8* gFrank_flic_data;
 
tU8* gAnne_flic_data;
 
int gNet_storage_allocated;
 
// 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];
 
tNet_game_options* gOptions;
 
int gNet_target[7];
 
int gLast_graph_sel__newgame;                   // suffix added to avoid duplicate symbol
 
tInterface_spec* gThe_interface_spec__newgame;  // suffix added to avoid duplicate symbol
 
tNet_sequence_type gNet_race_sequence__newgame; // suffix added to avoid duplicate symbol
 
tNet_game_type gLast_game_type;
 
int gCurrent_net_game_count;
 
tU32 gAnne_flic_data_length;
 
int gShifted_default_yet;
 
char* gNet_name;
 
tU32 gFrank_flic_data_length;
 
int gLast_net_choose_box;
 
int gCurrent_game_selection;
 
int gRace_index;
 
int gRadio_selected;
 
 
 
// IDA: void __cdecl StartRollingPlayerNamesIn()
 
void StartRollingPlayerNamesIn(void) {
 
    int i;
 
    LOG_TRACE("()");
 
 
 
    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);
 
    }
 
}
 
 
 
// IDA: void __cdecl FrankAnneStart1()
 
void FrankAnneStart1(void) {
 
    LOG_TRACE("()");
 
 
 
    StartRollingPlayerNamesIn();
 
    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,
 
        gCurrent_graf_data->frank_panel_top,
 
        gCurrent_graf_data->frank_panel_right - gCurrent_graf_data->frank_panel_left,
 
        gCurrent_graf_data->frank_panel_bottom - gCurrent_graf_data->frank_panel_top);
 
    InitialiseFlicPanel(1,
 
        gCurrent_graf_data->anne_panel_left,
 
        gCurrent_graf_data->anne_panel_top,
 
        gCurrent_graf_data->anne_panel_right - gCurrent_graf_data->anne_panel_left,
 
        gCurrent_graf_data->anne_panel_bottom - gCurrent_graf_data->anne_panel_top);
 
}
 
 
 
// 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);
 
    TellyInImage(GetPanelPixelmap(1), gCurrent_graf_data->anne_panel_left, gCurrent_graf_data->anne_panel_top);
 
}
 
 
 
// IDA: void __usercall GetPlayerName(int pStarting_to_type@<EAX>, int pCurrent_choice@<EDX>, char *pString@<EBX>, int *pMax_length@<ECX>)
 
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;
 
}
 
 
 
// IDA: int __usercall FrankAnneDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, 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);
 
    if (gFrank_flic_data) {
 
        MAMSUnlock((void**)&gFrank_flic_data);
 
    }
 
    if (gAnne_flic_data) {
 
        MAMSUnlock((void**)&gAnne_flic_data);
 
    }
 
    gProgram_state.frank_or_anniness = pCurrent_choice;
 
    GetTypedName(gProgram_state.player_name[pCurrent_choice], PLAYER_NAME_MAX_LENGTH);
 
    return pCurrent_choice;
 
}
 
 
 
// IDA: void __usercall FrankAnneDraw(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
 
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) {
 
                TransDRPixelmapText(
 
                    gBack_screen,
 
                    gCurrent_graf_data->enter_name_x[pCurrent_choice],
 
                    gCurrent_graf_data->enter_name_y,
 
                    &gFonts[FONT_GRNLIT],
 
                    GetMiscString(kMiscString_ENTER_NAME),
 
                    gBack_screen->width);
 
            }
 
        }
 
    }
 
}
 
 
 
// IDA: int __cdecl FrankieOrAnnie()
 
int FrankieOrAnnie(void) {
 
    static tFlicette flicker_on[3] = {
 
        { 83, { 61, 122 }, { 52, 125 } },
 
        { 83, { 184, 398 }, { 52, 125 } },
 
        { 43, { 215, 430 }, { 158, 379 } }
 
    };
 
    static tFlicette flicker_off[3] = {
 
        { 82, { 61, 122 }, { 52, 125 } },
 
        { 82, { 184, 398 }, { 52, 125 } },
 
        { 42, { 215, 430 }, { 158, 379 } }
 
    };
 
    static tFlicette push[3] = {
 
        { 83, { 61, 122 }, { 52, 125 } },
 
        { 83, { 184, 398 }, { 52, 125 } },
 
        { 45, { 215, 430 }, { 158, 379 } }
 
    };
 
    static tMouse_area mouse_areas[3] = {
 
        { { 55, 110 }, { 52, 125 }, { 161, 322 }, { 154, 370 }, 0, 0, 0, NULL },
 
        { { 178, 356 }, { 52, 125 }, { 295, 596 }, { 154, 370 }, 1, 0, 0, NULL },
 
        { { 215, 430 }, { 158, 379 }, { 278, 556 }, { 179, 430 }, 2, 1, 1, NULL }
 
    };
 
    static tRectile recopy_areas[2] = {
 
        { { 55, 110 }, { 132, 317 }, { 161, 322 }, { 154, 370 } },
 
        { { 178, 356 }, { 132, 317 }, { 295, 590 }, { 154, 370 } }
 
    };
 
    static tInterface_spec interface_spec = {
 
        0,               // initial_imode
 
        80,              // first_opening_flic
 
        0,               // second_opening_flic
 
        81,              // end_flic_go_ahead
 
        81,              // end_flic_escaped
 
        81,              // end_flic_otherwise
 
        0,               // flic_bunch_to_load
 
        { -1, -1 },      // move_left_new_mode
 
        { -1, 0 },       // move_left_delta
 
        { 0, 2 },        // move_left_min
 
        { 1, 2 },        // move_left_max
 
        { NULL, NULL },  // move_left_proc
 
        { -1, -1 },      // move_right_new_mode
 
        { 1, 0 },        // move_right_delta
 
        { 0, 2 },        // move_right_min
 
        { 1, 2 },        // move_right_max
 
        { NULL, NULL },  // move_right_proc
 
        { 1, 0 },        // move_up_new_mode
 
        { -2, -1 },      // move_up_delta
 
        { 2, 1 },        // move_up_min
 
        { 2, 1 },        // move_up_max
 
        { NULL, NULL },  // move_up_proc
 
        { 1, 0 },        // move_down_new_mode
 
        { 2, -1 },       // move_down_delta
 
        { 2, 1 },        // move_down_min
 
        { 2, 1 },        // move_down_max
 
        { NULL, NULL },  // move_down_proc
 
        { 1, 1 },        // go_ahead_allowed
 
        { NULL, NULL },  // go_ahead_proc
 
        { 1, 1 },        // escape_allowed
 
        { NULL, NULL },  // escape_proc
 
        NULL,            // exit_proc
 
        FrankAnneDraw,   // draw_proc
 
        0,               // time_out
 
        FrankAnneStart1, // start_proc1
 
        FrankAnneStart2, // start_proc2
 
        FrankAnneDone,   // done_proc
 
        1,               // font_needed
 
        { 1, 0 },        // typeable
 
        GetPlayerName,   // get_original_string
 
        2,               // escape_code
 
        1,               // dont_save_or_load
 
        3,               // number_of_button_flics
 
        flicker_on,      // flicker_on_flics
 
        flicker_off,     // flicker_off_flics
 
        push,            // pushed_flics
 
        3,               // number_of_mouse_areas
 
        mouse_areas,     // mouse_areas
 
        2,               // number_of_recopy_areas
 
        recopy_areas     // recopy_areas
 
    };
 
 
 
    int result;
 
    LOG_TRACE("()");
 
 
 
    LoadFont(FONT_GRNLIT);
 
    result = DoInterfaceScreen(&interface_spec, 0, gProgram_state.frank_or_anniness);
 
    DisposeFlicPanel(1);
 
    DisposeFlicPanel(0);
 
    DisposeFont(FONT_GRNLIT);
 
    return result < 2;
 
}
 
 
 
// IDA: int __cdecl SelectSkillLevel()
 
int SelectSkillLevel(void) {
 
    static tFlicette flicker_on[4] = {
 
        { 116, { 38, 76 }, { 55, 132 } },
 
        { 119, { 36, 72 }, { 83, 199 } },
 
        { 121, { 38, 76 }, { 111, 266 } },
 
        { 43, { 227, 454 }, { 158, 379 } }
 
    };
 
 
 
    static tFlicette flicker_off[4] = {
 
        { 115, { 38, 76 }, { 55, 132 } },
 
        { 118, { 36, 72 }, { 83, 199 } },
 
        { 120, { 38, 76 }, { 111, 266 } },
 
        { 42, { 227, 454 }, { 158, 379 } }
 
    };
 
 
 
    static tFlicette push[4] = {
 
        { 117, { 38, 76 }, { 55, 132 } },
 
        { 117, { 36, 72 }, { 83, 199 } },
 
        { 117, { 38, 76 }, { 111, 266 } },
 
        { 45, { 227, 454 }, { 158, 379 } }
 
    };
 
    static tMouse_area mouse_areas[4] = {
 
        { { 38, 76 }, { 55, 132 }, { 205, 410 }, { 69, 166 }, 0, 0, 0, NULL },
 
        { { 36, 72 }, { 83, 199 }, { 205, 410 }, { 98, 235 }, 1, 0, 0, NULL },
 
        { { 38, 76 }, { 111, 266 }, { 205, 410 }, { 125, 300 }, 2, 0, 0, NULL },
 
        { { 227, 454 }, { 158, 379 }, { 290, 580 }, { 178, 427 }, 3, 0, 0, NULL }
 
    };
 
 
 
    static tInterface_spec interface_spec = {
 
        0,              // initial_imode
 
        110,            // first_opening_flic
 
        0,              // second_opening_flic
 
        -1,             // end_flic_go_ahead
 
        111,            // end_flic_escaped
 
        -1,             // end_flic_otherwise
 
        0,              // flic_bunch_to_load
 
        { -1, 0 },      // move_left_new_mode
 
        { 0, 0 },       // move_left_delta
 
        { 0, 0 },       // move_left_min
 
        { 0, 0 },       // move_left_max
 
        { NULL, NULL }, // move_left_proc
 
        { -1, 0 },      // move_right_new_mode
 
        { 0, 0 },       // move_right_delta
 
        { 0, 0 },       // move_right_min
 
        { 0, 0 },       // move_right_max
 
        { NULL, NULL }, // move_right_proc
 
        { -1, 0 },      // move_up_new_mode
 
        { -1, 0 },      // move_up_delta
 
        { 0, 0 },       // move_up_min
 
        { 3, 0 },       // move_up_max
 
        { NULL, NULL }, // move_up_proc
 
        { -1, 0 },      // move_down_new_mode
 
        { 1, 0 },       // move_down_delta
 
        { 0, 0 },       // move_down_min
 
        { 3, 0 },       // move_down_max
 
        { NULL, NULL }, // move_down_proc
 
        { 1, 1 },       // go_ahead_allowed
 
        { NULL, NULL }, // go_ahead_proc
 
        { 1, 1 },       // escape_allowed
 
        { NULL, NULL }, // escape_proc
 
        NULL,           // exit_proc
 
        NULL,           // draw_proc
 
        0u,             // time_out
 
        NULL,           // start_proc1
 
        NULL,           // start_proc2
 
        NULL,           // done_proc
 
        0,              // font_needed
 
        { 0, 0 },       // typeable
 
        NULL,           // get_original_string
 
        3,              // escape_code
 
        1,              // dont_save_or_load
 
        4,              // number_of_button_flics
 
        flicker_on,     // flicker_on_flics
 
        flicker_off,    // flicker_off_flics
 
        push,           // pushed_flics
 
        4,              // number_of_mouse_areas
 
        mouse_areas,    // mouse_areas
 
        0,              // number_of_recopy_areas
 
        NULL            // recopy_areas
 
    };
 
 
 
    int result;
 
    LOG_TRACE("()");
 
 
 
    result = DoInterfaceScreen(&interface_spec, 0, gProgram_state.skill_level);
 
    if (result > 2) {
 
        return 0;
 
    }
 
    gProgram_state.skill_level = result;
 
    return 1;
 
}
 
 
 
// IDA: int __cdecl DoOnePlayerStart()
 
int DoOnePlayerStart(void) {
 
    int merrily_looping;
 
    tProgram_state saved_state;
 
    LOG_TRACE("()");
 
 
 
    if (OriginalCarmaCDinDrive()) {
 
        memcpy(&saved_state
, &gProgram_state
, sizeof(tProgram_state
));  
        do {
 
            merrily_looping = FrankieOrAnnie();
 
            if (!merrily_looping) {
 
                memcpy(&gProgram_state
, &saved_state
, sizeof(tProgram_state
));  
                return 0;
 
            }
 
            if ((harness_game_info.mode == eGame_carmageddon_demo || harness_game_info.mode == eGame_splatpack_demo || harness_game_info.mode == eGame_splatpack_xmas_demo) && gProgram_state.frank_or_anniness != eFrankie) {
 
                DoFeatureUnavailableInDemo();
 
                memset(&gProgram_state
, 0, sizeof(gProgram_state
));  
                return 0;
 
            }
 
 
 
            if (SelectSkillLevel()) {
 
                DoGoToRaceAnimation();
 
                StartLoadingScreen();
 
                AboutToLoadFirstCar();
 
                PrintMemoryDump(0, "JUST BEFORE LOADING YOUR CAR");
 
                SwitchToRealResolution();
 
                LoadCar(
 
                    gBasic_car_names[gProgram_state.frank_or_anniness],
 
                    eDriver_local_human,
 
                    &gProgram_state.current_car,
 
                    gProgram_state.frank_or_anniness,
 
                    gProgram_state.player_name[gProgram_state.frank_or_anniness],
 
                    &gOur_car_storage_space);
 
                SwitchToLoresMode();
 
                SetCarStorageTexturingLevel(&gOur_car_storage_space, GetCarTexturingLevel(), eCTL_full);
 
                PrintMemoryDump(0, "IMMEDIATELY AFTER LOADING YOUR CAR");
 
                gNet_mode = eNet_mode_none;
 
                InitGame(0);
 
                merrily_looping = 0;
 
            }
 
        } while (merrily_looping);
 
        UnlockBunchOfFlics(4);
 
        return 1;
 
    } else {
 
        DoErrorInterface(kMiscString_PLEASE_INSERT_THE_CARMAGEDDON_CD);
 
        return 0;
 
    }
 
}
 
 
 
// IDA: int __usercall NewNetGameUp@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NewNetGameUp(int* pCurrent_choice, int* pCurrent_mode) {
 
    int new_sel;
 
    int i;
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NewNetGameDown(int* pCurrent_choice, int* pCurrent_mode) {
 
    int new_sel;
 
    int i;
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>)
 
void DisposeJoinableGame(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    NetDisposeGameDetails(gGames_to_join[pIndex].game);
 
    gGames_to_join[pIndex].game = NULL;
 
}
 
 
 
// IDA: void __usercall DrawAnItem(int pX@<EAX>, int pY_index@<EDX>, int pFont_index@<EBX>, char *pText@<ECX>)
 
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);
 
 
 
    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@<EAX>, int pX@<EDX>)
 
void DrawColumnHeading__newgame(int pStr_index, int pX) {
 
    LOG_TRACE("(%d, %d)", pStr_index, pX);
 
 
 
    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@<EAX>, int pCurrent_mode@<EDX>)
 
void DrawGames(int pCurrent_choice, int pCurrent_mode) {
 
    int i;
 
    int font_index;
 
    int current_index;
 
    int x_coord;
 
    int y_coord;
 
    char s[256];
 
    //char* s2; // Pierre-Marie Baty -- unused variable
 
    //char* s3; // Pierre-Marie Baty -- unused variable
 
    LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
 
 
 
    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(kMiscString_NetworkGamesTableHeading_HOST, gCurrent_graf_data->joinable_games_x_1);
 
    DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_GAME_TYPE, gCurrent_graf_data->joinable_games_x_2);
 
    DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_PLAYERS, gCurrent_graf_data->joinable_games_x_3);
 
    DrawColumnHeading__newgame(kMiscString_NetworkGamesTableHeading_STATUS, 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
(kMiscString_NetworkGameTypeNames_START 
+ 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);
 
            GetMiscString(kMiscString_NetworkGameStage_START + gGames_to_join[i].game->status.stage),
 
            GetMiscString(kMiscString_NetworkGameOpenGame_START + 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("()");
 
 
 
    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@<EAX>)
 
void DisposeJoinList(int pExemption) {
 
    int i;
 
    LOG_TRACE("(%d)", pExemption);
 
 
 
    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@<EAX>)
 
void AddToJoinList(tNet_game_details* pGame) {
 
    int i;
 
    int slot_to_use;
 
    tU32 this_game_ID;
 
    LOG_TRACE("(%p)", pGame);
 
 
 
    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("()");
 
 
 
    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("()");
 
 
 
    gTyping_slot = 0;
 
    StartTyping(0, gNet_player_name, 11);
 
}
 
 
 
// IDA: void __usercall NewNetGetName(int pStarting_to_type@<EAX>, int pCurrent_choice@<EDX>, char *pString@<EBX>, int *pMax_length@<ECX>)
 
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);
 
 
 
    strcpy(pString
, gNet_player_name
);  
    *pMax_length = 10;
 
}
 
 
 
// IDA: int __usercall NewNetDone@<EAX>(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>, int pGo_ahead@<EBX>, int pEscaped@<ECX>, 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);
 
 
 
    if (pCurrent_choice != 1) {
 
        GetTypedName(gNet_player_name, 10);
 
    }
 
    return pCurrent_choice;
 
}
 
 
 
// IDA: int __usercall NewNetGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NewNetGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    return gLast_graph_sel__newgame >= 0;
 
}
 
 
 
// IDA: tJoin_or_host_result __usercall JoinOrHostGame@<EAX>(tNet_game_details **pGame_to_join@<EAX>)
 
tJoin_or_host_result JoinOrHostGame(tNet_game_details** pGame_to_join) {
 
    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);
 
 
 
    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@<EAX>)
 
void GetNetOptions(tNet_game_options* pGame_options) {
 
    LOG_TRACE("(%p)", pGame_options);
 
 
 
    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@<EAX>)
 
void SetNetOptions(tNet_game_options* pGame_options) {
 
    LOG_TRACE("(%p)", pGame_options);
 
 
 
    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@<EAX>)
 
void NetPlayCheckboxOn2(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    RunFlicAt(95,
 
        gRadio_bastards__newgame[pIndex].left[0],
 
        gRadio_bastards__newgame[pIndex].top + 1);
 
}
 
 
 
// IDA: void __usercall NetPlayCheckboxOff2(int pIndex@<EAX>)
 
void NetPlayCheckboxOff2(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    RunFlicAt(96,
 
        gRadio_bastards__newgame[pIndex].left[0],
 
        gRadio_bastards__newgame[pIndex].top + 1);
 
}
 
 
 
// IDA: void __usercall NetPlayCheckboxOn(int pIndex@<EAX>)
 
void NetPlayCheckboxOn(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    RemoveTransientBitmaps(1);
 
    DontLetFlicFuckWithPalettes();
 
    TurnFlicTransparencyOn();
 
    NetPlayCheckboxOn2(pIndex);
 
    TurnFlicTransparencyOff();
 
    LetFlicFuckWithPalettes();
 
}
 
 
 
// IDA: void __usercall NetPlayCheckboxOff(int pIndex@<EAX>)
 
void NetPlayCheckboxOff(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    RemoveTransientBitmaps(1);
 
    DontLetFlicFuckWithPalettes();
 
    TurnFlicTransparencyOn();
 
    NetPlayCheckboxOff2(pIndex);
 
    TurnFlicTransparencyOff();
 
    LetFlicFuckWithPalettes();
 
}
 
 
 
// IDA: void __usercall NetPlayRadioOn2(int pIndex@<EAX>, int pValue@<EDX>)
 
void NetPlayRadioOn2(int pIndex, int pValue) {
 
    LOG_TRACE("(%d, %d)", pIndex, pValue);
 
 
 
    RunFlicAt(288,
 
        gRadio_bastards__newgame[pIndex].left[pValue],
 
        gRadio_bastards__newgame[pIndex].top + 1);
 
}
 
 
 
// IDA: void __usercall NetPlayRadioOff2(int pIndex@<EAX>, int pValue@<EDX>)
 
void NetPlayRadioOff2(int pIndex, int pValue) {
 
    LOG_TRACE("(%d, %d)", pIndex, pValue);
 
 
 
    RunFlicAt(287,
 
        gRadio_bastards__newgame[pIndex].left[pValue],
 
        gRadio_bastards__newgame[pIndex].top + 1);
 
}
 
 
 
// IDA: void __usercall NetPlayRadioOn(int pIndex@<EAX>, int pValue@<EDX>)
 
void NetPlayRadioOn(int pIndex, int pValue) {
 
    LOG_TRACE("(%d, %d)", pIndex, pValue);
 
 
 
    RemoveTransientBitmaps(1);
 
    DontLetFlicFuckWithPalettes();
 
    TurnFlicTransparencyOn();
 
    NetPlayRadioOn2(pIndex, pValue);
 
    TurnFlicTransparencyOff();
 
    LetFlicFuckWithPalettes();
 
}
 
 
 
// IDA: void __usercall NetPlayRadioOff(int pIndex@<EAX>, int pValue@<EDX>)
 
void NetPlayRadioOff(int pIndex, int pValue) {
 
    LOG_TRACE("(%d, %d)", pIndex, pValue);
 
 
 
    RemoveTransientBitmaps(1);
 
    DontLetFlicFuckWithPalettes();
 
    TurnFlicTransparencyOn();
 
    NetPlayRadioOff2(pIndex, pValue);
 
    TurnFlicTransparencyOff();
 
    LetFlicFuckWithPalettes();
 
}
 
 
 
// IDA: void __cdecl DrawNOptInitialRadios()
 
void DrawNOptInitialRadios(void) {
 
    int i;
 
    int j;
 
    LOG_TRACE("()");
 
 
 
    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@<EAX>, int pNew_value@<EDX>)
 
void NetRadioChanged(int pIndex, int pNew_value) {
 
    LOG_TRACE("(%d, %d)", pIndex, pNew_value);
 
 
 
    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@<EAX>)
 
void NetCheckboxChanged(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetOptLeft(int* pCurrent_choice, int* pCurrent_mode) {
 
    int new_value;
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetOptRight(int* pCurrent_choice, int* pCurrent_mode) {
 
    int new_value;
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetOptUp(int* pCurrent_choice, int* pCurrent_mode) {
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetOptDown(int* pCurrent_choice, int* pCurrent_mode) {
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>, int pX_offset@<EBX>, int pY_offset@<ECX>)
 
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);
 
 
 
    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()
 
void RevertToDefaults(void) {
 
    tPath_name the_path;
 
    FILE* f;
 
    tNet_game_options net_options;
 
    int i;
 
    LOG_TRACE("()");
 
 
 
    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();
 
}
 
 
 
// IDA: void __cdecl DefaultNetSettings()
 
void DefaultNetSettings(void) {
 
    FILE* f;
 
    int i;
 
    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);
 
    for (i = 0; i < COUNT_OF(gNet_settings) - 1; i++) {
 
        ReadNetworkSettings(f, &gNet_settings[i + 1]);
 
    }
 
}
 
 
 
// IDA: int __usercall NetOptGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetOptGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>, int pColour_value@<EDX>)
 
void NetPlotAGraphBox(int pIndex, int pColour_value) {
 
    LOG_TRACE("(%d, %d)", pIndex, pColour_value);
 
 
 
    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@<EAX>)
 
void NetDrawAGraphBox(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    NetPlotAGraphBox(pIndex, 45);
 
}
 
 
 
// IDA: void __usercall NetEraseAGraphBox(int pIndex@<EAX>)
 
void NetEraseAGraphBox(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    NetPlotAGraphBox(pIndex, 0);
 
}
 
 
 
// IDA: void __usercall DrawNetOptBox(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
 
void DrawNetOptBox(int pCurrent_choice, int pCurrent_mode) {
 
    LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>)
 
void DoNetOptions(tNet_game_options* pGame_options) {
 
    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);
 
 
 
    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@<EAX>)
 
//  Suffix added to avoid duplicate symbol
 
void PlayRadioOn__newgame(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    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@<EAX>)
 
//  Suffix added to avoid duplicate symbol
 
void PlayRadioOff__newgame(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    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@<EAX>, tNet_game_options *pGame_options@<EDX>)
 
void SetOptions(tNet_game_type pGame_type, tNet_game_options* pGame_options) {
 
    LOG_TRACE("(%d, %p)", pGame_type, pGame_options);
 
 
 
    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("()");
 
 
 
    PlayRadioOn__newgame(gLast_game_type);
 
}
 
 
 
// IDA: int __usercall NetChooseGoAhead@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetChooseGoAhead(int* pCurrent_choice, int* pCurrent_mode) {
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    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@<EAX>, int pColour_value@<EDX>)
 
// Suffix added to avoid duplicate symbol
 
void PlotAGraphBox__newgame(int pIndex, int pColour_value) {
 
    LOG_TRACE("(%d, %d)", pIndex, pColour_value);
 
 
 
    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@<EAX>)
 
// Suffix added to avoid duplicate symbol
 
void DrawAGraphBox__newgame(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    PlotAGraphBox__newgame(pIndex, 45);
 
}
 
 
 
// IDA: void __usercall EraseAGraphBox(int pIndex@<EAX>)
 
// Suffix added to avoid duplicate symbol
 
void EraseAGraphBox__newgame(int pIndex) {
 
    LOG_TRACE("(%d)", pIndex);
 
 
 
    PlotAGraphBox__newgame(pIndex, 0);
 
}
 
 
 
// IDA: void __usercall DrawNetChoose(int pCurrent_choice@<EAX>, int pCurrent_mode@<EDX>)
 
void DrawNetChoose(int pCurrent_choice, int pCurrent_mode) {
 
    char s[256];
 
    tU32* k;
 
    int i;
 
    LOG_TRACE("(%d, %d)", pCurrent_choice, pCurrent_mode);
 
 
 
    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
(kMiscString_FIRST_RACE
), 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(kMiscString_NetworkGameTypeDescriptions_START + (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@<EAX>(int *pCurrent_choice@<EAX>, int *pCurrent_mode@<EDX>)
 
int NetChooseLR(int* pCurrent_choice, int* pCurrent_mode) {
 
    LOG_TRACE("(%p, %p)", pCurrent_choice, pCurrent_mode);
 
 
 
    *pCurrent_choice = gLast_game_type + 4;
 
    return 0;
 
}
 
 
 
// IDA: void __usercall SetGameTarget(tNet_game_type *pGame_type@<EAX>, tNet_game_options *pGame_options@<EDX>)
 
void SetGameTarget(tNet_game_type* pGame_type, tNet_game_options* pGame_options) {
 
    LOG_TRACE("(%p, %p)", pGame_type, pGame_options);
 
 
 
    pGame_options->race_end_target = gNet_target[*pGame_type];
 
    switch (*pGame_type) {
 
    case eNet_game_type_car_crusher:
 
        pGame_options->race_end_target = gNet_target[*pGame_type];
 
        break;
 
    case eNet_game_type_tag:
 
        pGame_options->race_end_target = 1000 * gNet_target[*pGame_type];
 
        break;
 
    case eNet_game_type_foxy:
 
        pGame_options->race_end_target = 1000 * gNet_target[*pGame_type];
 
        break;
 
    default:
 
        pGame_options->race_end_target = gNet_target[*pGame_type];
 
        break;
 
    }
 
}
 
 
 
// IDA: int __usercall NetGameChoices@<EAX>(tNet_game_type *pGame_type@<EAX>, tNet_game_options *pGame_options@<EDX>, int *pRace_index@<EBX>)
 
int NetGameChoices(tNet_game_type* pGame_type, tNet_game_options* pGame_options, int* pRace_index) {
 
    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);
 
 
 
    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@<EAX>, tNet_game_options *pGame_options@<EDX>, int *pRace_index@<EBX>)
 
void ReadNetGameChoices(tNet_game_type* pGame_type, tNet_game_options* pGame_options, int* pRace_index) {
 
    LOG_TRACE("(%p, %p, %p)", pGame_type, pGame_options, pRace_index);
 
 
 
    *pGame_type = gLast_game_type;
 
    SetOptions(*pGame_type, pGame_options);
 
    SetGameTarget(pGame_type, pGame_options);
 
    *pRace_index = PickNetRace(-1, pGame_options->race_sequence_type);
 
}
 
 
 
// IDA: int __usercall ChooseStartRace@<EAX>(int *pRank@<EAX>)
 
int ChooseStartRace(int* pRank) {
 
    LOG_TRACE("(%p)", pRank);
 
    NOT_IMPLEMENTED();
 
}
 
 
 
// IDA: void __usercall SetUpOtherNetThings(tNet_game_details *pNet_game@<EAX>)
 
void SetUpOtherNetThings(tNet_game_details* pNet_game) {
 
    LOG_TRACE("(%p)", pNet_game);
 
 
 
    StartLoadingScreen();
 
    gProgram_state.skill_level = 1;
 
    InitGame(pNet_game->start_race);
 
}
 
 
 
// IDA: void __usercall RequestCarDetails(tNet_game_details *pNet_game@<EAX>)
 
void RequestCarDetails(tNet_game_details* pNet_game) {
 
    tNet_message* message;
 
    LOG_TRACE("(%p)", pNet_game);
 
 
 
    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()
 
int PickARandomCar(void) {
 
    int i;
 
    int cars[120];
 
    int array_size;
 
    LOG_TRACE("()");
 
 
 
    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@<EAX>)
 
void PollCarDetails(tNet_game_details* pNet_game) {
 
    LOG_TRACE("(%p)", pNet_game);
 
 
 
    if (gReceived_car_details) {
 
        RequestCarDetails(pNet_game);
 
    }
 
}
 
 
 
// IDA: void __usercall SetNetAvailability(tNet_game_options *pOptions@<EAX>)
 
void SetNetAvailability(tNet_game_options* pOptions) {
 
    int i;
 
    LOG_TRACE("(%p)", pOptions);
 
 
 
    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@<EAX>(tNet_game_details *pNet_game@<EAX>, tNet_game_options *pOptions@<EDX>, int *pCar_index@<EBX>, int pIm_the_host_so_fuck_off@<ECX>)
 
int ChooseNetCar(tNet_game_details* pNet_game, tNet_game_options* pOptions, int* pCar_index, int pIm_the_host_so_fuck_off) {
 
    tS32 start_time;
 
    int i;
 
    int result;
 
    int car_index;
 
    //int the_car_index; // Pierre-Marie Baty -- unused variable
 
    LOG_TRACE("(%p, %p, %p, %d)", pNet_game, pOptions, pCar_index, pIm_the_host_so_fuck_off);
 
 
 
    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()
 
void InitNetStorageSpace(void) {
 
    int i;
 
    LOG_TRACE("()");
 
 
 
    for (i = 0; i < COUNT_OF(gNet_players); i++) {
 
        gCurrent_race.opponent_list[i].car_spec = NULL;
 
    }
 
    gNet_storage_allocated = 1;
 
    InitialiseStorageSpace(&gNet_cars_storage_space, 500, 50, 500, 300);
 
}
 
 
 
// IDA: void __cdecl DisposeNetStorageSpace()
 
void DisposeNetStorageSpace(void) {
 
    LOG_TRACE("()");
 
 
 
    if (gNet_storage_allocated) {
 
        DisposeStorageSpace(&gNet_cars_storage_space);
 
    }
 
    gNet_storage_allocated = 0;
 
}
 
 
 
// IDA: int __cdecl DoMultiPlayerStart()
 
int DoMultiPlayerStart(void) {
 
    tJoin_or_host_result result;
 
    tNet_game_details* game_to_join;
 
    char s[256];
 
    //char* s2; // Pierre-Marie Baty -- unused variable
 
    tNet_game_type new_game_type;
 
    tNet_game_options new_game_options;
 
    int start_rank;
 
    int car_index;
 
    //int race_index; // added by dethrace // Pierre-Marie Baty -- unused variable
 
    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) {
 
        SuspendPendingFlic();
 
        DoFeatureUnavailableInDemo();
 
        return 0;
 
    }
 
 
 
    if (gAusterity_mode) {
 
        NetFullScreenMessage(192, 0);
 
        return 0;
 
    }
 
    if (NetInitialise()) {
 
        SuspendPendingFlic();
 
        DoErrorInterface(kMiscString_NetworkPlayIsNotAvailable);
 
        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(kMiscString_PLEASE_INSERT_THE_CARMAGEDDON_CD);
 
            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
, GetMiscString
(kMiscString_HasJoinedTheGame
));  
                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(kMiscString_PLEASE_INSERT_THE_CARMAGEDDON_CD);
 
            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;
 
    }
 
}