7 Commits

Author SHA1 Message Date
Muzychenko Andrey
16b527e3cf Added AddressSanitizer to Windows build config, disabled by default.
VS older that 2019 do not support it.
Game passes ASan checks at the moment of writing.
2021-11-09 16:50:09 +03:00
Muzychenko Andrey
683204519c Added UTF-8 path support on Windows.
Ref issue #82.
2021-11-06 19:22:56 +03:00
Muzychenko Andrey
ecdf802d68 Added game data loading from user folder (SDL_GetPrefPath).
Ref issue #80.
2021-11-05 10:16:27 +03:00
Muzychenko Andrey
dc00dbde0d Fixed bug with mission accept scores.
Ref issue #81.
2021-11-04 18:46:04 +03:00
Muzychenko Andrey
862fe13dcd Added game controller exit shortcut: back/select when paused.
Ref issue #79.
2021-11-01 09:09:19 +03:00
Muzychenko Andrey
6c299ed103 Updated plans in readme 2021-10-30 12:51:24 +03:00
Muzychenko Andrey
fc1975a607 Fixed bug: dialogs not shown when main menu is hidden.
Ref issue #76.
2021-10-30 12:34:17 +03:00
13 changed files with 94 additions and 29 deletions

View File

@@ -9,7 +9,8 @@
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
"ctestCommandArgs": "",
"addressSanitizerEnabled": false
},
{
"name": "x86-Debug",
@@ -20,7 +21,8 @@
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x86" ]
"inheritEnvironments": [ "msvc_x86" ],
"addressSanitizerEnabled": false
},
{
"name": "x86-Release",

View File

@@ -77,10 +77,10 @@ Tested with: macOS Big Sur (Intel) with Xcode 13 & macOS Montery Beta (Apple Sil
* ~~Decompile original game~~
* ~~Resizable window, scaled graphics~~
* ~~Loader for high-res sprites from CADET.DAT~~
* ~~Cross-platform port using SDL2, SDL2_mixer, ImGui~~
* Misc features of Full Tilt: 3 music tracks, multiball, centered textboxes, etc.
* Cross-platform port
* Using SDL2, SDL2_mixer, ImGui
* Maybe: Android port
* Maybe: Text translations
* Maybe: Android port
* Maybe x2: support for other two tables
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched

View File

@@ -297,7 +297,7 @@ void DatFile::Finalize()
// PINBALL2.MID is an alternative font provided in 3DPB data
// Scaled down because it is too large for top text box
/*auto file = pinball::make_path_name("PINBALL2.MID");
auto fileHandle = fopen(file.c_str(), "rb");
auto fileHandle = fopenu(file.c_str(), "rb");
fseek(fileHandle, 0, SEEK_END);
auto fileSize = static_cast<uint32_t>(ftell(fileHandle));
auto rcData = reinterpret_cast<MsgFont*>(new uint8_t[fileSize]);

View File

@@ -57,7 +57,7 @@ void Sound::PlaySound(Mix_Chunk* wavePtr, int time)
Mix_Chunk* Sound::LoadWaveFile(const std::string& lpName)
{
auto wavFile = fopen(lpName.c_str(), "r");
auto wavFile = fopenu(lpName.c_str(), "r");
if (!wavFile)
return nullptr;
fclose(wavFile);

View File

@@ -34,6 +34,25 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
{
return MainActual(lpCmdLine);
}
// fopen to _wfopen adapter, for UTF-8 paths
FILE* fopenu(const char* path, const char* opt)
{
wchar_t* wideArgs[2]{};
for (auto& arg : wideArgs)
{
auto src = wideArgs[0] ? opt : path;
auto length = MultiByteToWideChar(CP_UTF8, 0, src, -1, nullptr, 0);
arg = new wchar_t[length];
MultiByteToWideChar(CP_UTF8, 0, src, -1, arg, length);
}
auto fileHandle = _wfopen(wideArgs[0], wideArgs[1]);
for (auto arg : wideArgs)
delete[] arg;
return fileHandle;
}
#endif
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu

View File

@@ -3775,9 +3775,9 @@ void control::SelectMissionController(int code, TPinballComponent* caller)
if (light_on(&control_lite319_tag))
control_lite319_tag.Component->Message(20, 0.0);
control_lite198_tag.Component->MessageField = control_lite56_tag.Component->MessageField;
auto scoreId = control_lite56_tag.Component->MessageField - 2;
MissionControl(66, nullptr);
int addedScore = SpecialAddScore(
mission_select_scores[control_lite56_tag.Component->MessageField - 2]);
int addedScore = SpecialAddScore(mission_select_scores[scoreId]);
snprintf(Buffer, sizeof Buffer, pinball::get_rc_string(77, 0), addedScore);
control_mission_text_box_tag.Component->Display(Buffer, 4.0);
}

View File

@@ -158,7 +158,7 @@ int loader::get_sound_id(int groupIndex)
}
auto filePath = pinball::make_path_name(fileName);
auto file = fopen(filePath.c_str(), "rb");
auto file = fopenu(filePath.c_str(), "rb");
if (file)
{
fread(&wavHeader, 1, sizeof wavHeader, file);

View File

@@ -101,11 +101,12 @@ Mix_Music* midi::load_track(std::string fileName)
if (i == 0)
{
auto filePath = basePath + ".MID";
auto fileHandle = fopen(filePath.c_str(), "rb");
auto fileHandle = fopenu(filePath.c_str(), "rb");
if (fileHandle)
{
fclose(fileHandle);
audio = Mix_LoadMUS(filePath.c_str());
auto rw = SDL_RWFromFile(filePath.c_str(), "rb");
audio = Mix_LoadMUS_RW(rw, 1);
}
}
else
@@ -115,7 +116,7 @@ Mix_Music* midi::load_track(std::string fileName)
{
// Dump converted MIDI file
/*auto filePath = basePath + ".midi";
FILE* fileHandle = fopen(filePath.c_str(), "wb");
FILE* fileHandle = fopenu(filePath.c_str(), "wb");
fwrite(midi->data(), 1, midi->size(), fileHandle);
fclose(fileHandle);*/
@@ -164,7 +165,7 @@ bool midi::play_track(Mix_Music* midi)
/// <returns>Vector that contains MIDI file</returns>
std::vector<uint8_t>* midi::MdsToMidi(std::string file)
{
auto fileHandle = fopen(file.c_str(), "rb");
auto fileHandle = fopenu(file.c_str(), "rb");
if (!fileHandle)
return nullptr;

View File

@@ -16,7 +16,7 @@ DatFile* partman::load_records(LPCSTR lpFileName, bool fullTiltMode)
dat8BitBmpHeader bmpHeader{};
dat16BitBmpHeader zMapHeader{};
auto fileHandle = fopen(lpFileName, "rb");
auto fileHandle = fopenu(lpFileName, "rb");
if (fileHandle == nullptr)
return nullptr;

View File

@@ -39,6 +39,8 @@ int pb::init()
{
float projMat[12], zMin = 0, zScaler = 0;
if (winmain::DatFileName.empty())
return 1;
auto dataFilePath = pinball::make_path_name(winmain::DatFileName);
record_table = partman::load_records(dataFilePath.c_str(), FullTiltMode);

View File

@@ -83,4 +83,14 @@ int Sign(T val)
return (T(0) < val) - (val < T(0));
}
// UTF-8 path adapter for fopen on Windows, implemented in SpaceCadetPinball.cpp
#ifdef _WIN32
extern FILE* fopenu(const char* path, const char* opt);
#else
inline FILE* fopenu(const char* path, const char* opt)
{
return fopen(path, opt);
}
#endif
#endif //PCH_H

View File

@@ -36,7 +36,7 @@ bool winmain::ShowSpriteViewer = false;
bool winmain::LaunchBallEnabled = true;
bool winmain::HighScoresEnabled = true;
bool winmain::DemoActive = false;
char* winmain::BasePath;
std::string winmain::BasePath;
int winmain::MainMenuHeight = 0;
std::string winmain::FpsDetails;
double winmain::UpdateToFrameRatio;
@@ -58,19 +58,44 @@ int winmain::WinMain(LPCSTR lpCmdLine)
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not initialize SDL2", SDL_GetError(), nullptr);
return 1;
}
BasePath = SDL_GetBasePath();
pinball::quickFlag = strstr(lpCmdLine, "-quick") != nullptr;
DatFileName = options::get_string("Pinball Data", pinball::get_rc_string(168, 0));
/*Check for full tilt .dat file and switch to it automatically*/
auto cadetFilePath = pinball::make_path_name("CADET.DAT");
auto cadetDat = fopen(cadetFilePath.c_str(), "r");
if (cadetDat)
// Search for game data in: game folder, user folder
// Game data test order: CADET.DAT, PINBALL.DAT
char* dataSearchPaths[2]
{
fclose(cadetDat);
DatFileName = "CADET.DAT";
pb::FullTiltMode = true;
SDL_GetBasePath(),
SDL_GetPrefPath(nullptr, "SpaceCadetPinball")
};
std::string datFileNames[2]
{
"CADET.DAT",
options::get_string("Pinball Data", pinball::get_rc_string(168, 0))
};
for (auto path : dataSearchPaths)
{
if (DatFileName.empty() && path)
{
BasePath = path;
for (int i = 0; i < 2; i++)
{
auto datFileName = datFileNames[i];
auto datFilePath = pinball::make_path_name(datFileName);
auto datFile = fopenu(datFilePath.c_str(), "r");
if (datFile)
{
fclose(datFile);
DatFileName = datFileName;
if (i == 0)
pb::FullTiltMode = true;
printf("Loading game from: %s\n", datFilePath.c_str());
break;
}
}
}
SDL_free(path);
}
// SDL window
@@ -339,7 +364,6 @@ void winmain::RenderUi()
}
ImGui::End();
ImGui::PopStyleVar();
return;
}
// No demo window in release to save space
@@ -348,7 +372,7 @@ void winmain::RenderUi()
ImGui::ShowDemoWindow(&ShowImGuiDemo);
#endif
if (ImGui::BeginMainMenuBar())
if (Options.ShowMenu && ImGui::BeginMainMenuBar())
{
int currentMenuHeight = static_cast<int>(ImGui::GetWindowSize().y);
if (MainMenuHeight != currentMenuHeight)
@@ -777,7 +801,14 @@ int winmain::event_handler(const SDL_Event* event)
case SDL_CONTROLLER_BUTTON_START:
pause();
break;
default: ;
case SDL_CONTROLLER_BUTTON_BACK:
if (single_step)
{
SDL_Event event{ SDL_QUIT };
SDL_PushEvent(&event);
}
break;
default:;
}
break;
case SDL_CONTROLLERBUTTONUP:

View File

@@ -48,7 +48,7 @@ public:
static bool LaunchBallEnabled;
static bool HighScoresEnabled;
static bool DemoActive;
static char* BasePath;
static std::string BasePath;
static int MainMenuHeight;
static int WinMain(LPCSTR lpCmdLine);