Compare commits
7 Commits
Release_2.
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16b527e3cf | ||
|
|
683204519c | ||
|
|
ecdf802d68 | ||
|
|
dc00dbde0d | ||
|
|
862fe13dcd | ||
|
|
6c299ed103 | ||
|
|
fc1975a607 |
@@ -9,7 +9,8 @@
|
|||||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||||
"cmakeCommandArgs": "",
|
"cmakeCommandArgs": "",
|
||||||
"buildCommandArgs": "",
|
"buildCommandArgs": "",
|
||||||
"ctestCommandArgs": ""
|
"ctestCommandArgs": "",
|
||||||
|
"addressSanitizerEnabled": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "x86-Debug",
|
"name": "x86-Debug",
|
||||||
@@ -20,7 +21,8 @@
|
|||||||
"cmakeCommandArgs": "",
|
"cmakeCommandArgs": "",
|
||||||
"buildCommandArgs": "",
|
"buildCommandArgs": "",
|
||||||
"ctestCommandArgs": "",
|
"ctestCommandArgs": "",
|
||||||
"inheritEnvironments": [ "msvc_x86" ]
|
"inheritEnvironments": [ "msvc_x86" ],
|
||||||
|
"addressSanitizerEnabled": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "x86-Release",
|
"name": "x86-Release",
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ Tested with: macOS Big Sur (Intel) with Xcode 13 & macOS Montery Beta (Apple Sil
|
|||||||
* ~~Decompile original game~~
|
* ~~Decompile original game~~
|
||||||
* ~~Resizable window, scaled graphics~~
|
* ~~Resizable window, scaled graphics~~
|
||||||
* ~~Loader for high-res sprites from CADET.DAT~~
|
* ~~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.
|
* Misc features of Full Tilt: 3 music tracks, multiball, centered textboxes, etc.
|
||||||
* Cross-platform port
|
* Maybe: Text translations
|
||||||
* Using SDL2, SDL2_mixer, ImGui
|
* Maybe: Android port
|
||||||
* Maybe: Android port
|
|
||||||
* Maybe x2: support for other two tables
|
* Maybe x2: support for other two tables
|
||||||
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched
|
* Table specific BL (control interactions and missions) is hardcoded, othere parts might be also patched
|
||||||
|
|
||||||
|
|||||||
@@ -297,7 +297,7 @@ void DatFile::Finalize()
|
|||||||
// PINBALL2.MID is an alternative font provided in 3DPB data
|
// PINBALL2.MID is an alternative font provided in 3DPB data
|
||||||
// Scaled down because it is too large for top text box
|
// Scaled down because it is too large for top text box
|
||||||
/*auto file = pinball::make_path_name("PINBALL2.MID");
|
/*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);
|
fseek(fileHandle, 0, SEEK_END);
|
||||||
auto fileSize = static_cast<uint32_t>(ftell(fileHandle));
|
auto fileSize = static_cast<uint32_t>(ftell(fileHandle));
|
||||||
auto rcData = reinterpret_cast<MsgFont*>(new uint8_t[fileSize]);
|
auto rcData = reinterpret_cast<MsgFont*>(new uint8_t[fileSize]);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ void Sound::PlaySound(Mix_Chunk* wavePtr, int time)
|
|||||||
|
|
||||||
Mix_Chunk* Sound::LoadWaveFile(const std::string& lpName)
|
Mix_Chunk* Sound::LoadWaveFile(const std::string& lpName)
|
||||||
{
|
{
|
||||||
auto wavFile = fopen(lpName.c_str(), "r");
|
auto wavFile = fopenu(lpName.c_str(), "r");
|
||||||
if (!wavFile)
|
if (!wavFile)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
fclose(wavFile);
|
fclose(wavFile);
|
||||||
|
|||||||
@@ -34,6 +34,25 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||||||
{
|
{
|
||||||
return MainActual(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
|
#endif
|
||||||
|
|
||||||
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
|
// Run program: Ctrl + F5 or Debug > Start Without Debugging menu
|
||||||
|
|||||||
@@ -3775,9 +3775,9 @@ void control::SelectMissionController(int code, TPinballComponent* caller)
|
|||||||
if (light_on(&control_lite319_tag))
|
if (light_on(&control_lite319_tag))
|
||||||
control_lite319_tag.Component->Message(20, 0.0);
|
control_lite319_tag.Component->Message(20, 0.0);
|
||||||
control_lite198_tag.Component->MessageField = control_lite56_tag.Component->MessageField;
|
control_lite198_tag.Component->MessageField = control_lite56_tag.Component->MessageField;
|
||||||
|
auto scoreId = control_lite56_tag.Component->MessageField - 2;
|
||||||
MissionControl(66, nullptr);
|
MissionControl(66, nullptr);
|
||||||
int addedScore = SpecialAddScore(
|
int addedScore = SpecialAddScore(mission_select_scores[scoreId]);
|
||||||
mission_select_scores[control_lite56_tag.Component->MessageField - 2]);
|
|
||||||
snprintf(Buffer, sizeof Buffer, pinball::get_rc_string(77, 0), addedScore);
|
snprintf(Buffer, sizeof Buffer, pinball::get_rc_string(77, 0), addedScore);
|
||||||
control_mission_text_box_tag.Component->Display(Buffer, 4.0);
|
control_mission_text_box_tag.Component->Display(Buffer, 4.0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ int loader::get_sound_id(int groupIndex)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto filePath = pinball::make_path_name(fileName);
|
auto filePath = pinball::make_path_name(fileName);
|
||||||
auto file = fopen(filePath.c_str(), "rb");
|
auto file = fopenu(filePath.c_str(), "rb");
|
||||||
if (file)
|
if (file)
|
||||||
{
|
{
|
||||||
fread(&wavHeader, 1, sizeof wavHeader, file);
|
fread(&wavHeader, 1, sizeof wavHeader, file);
|
||||||
|
|||||||
@@ -101,11 +101,12 @@ Mix_Music* midi::load_track(std::string fileName)
|
|||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
auto filePath = basePath + ".MID";
|
auto filePath = basePath + ".MID";
|
||||||
auto fileHandle = fopen(filePath.c_str(), "rb");
|
auto fileHandle = fopenu(filePath.c_str(), "rb");
|
||||||
if (fileHandle)
|
if (fileHandle)
|
||||||
{
|
{
|
||||||
fclose(fileHandle);
|
fclose(fileHandle);
|
||||||
audio = Mix_LoadMUS(filePath.c_str());
|
auto rw = SDL_RWFromFile(filePath.c_str(), "rb");
|
||||||
|
audio = Mix_LoadMUS_RW(rw, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -115,7 +116,7 @@ Mix_Music* midi::load_track(std::string fileName)
|
|||||||
{
|
{
|
||||||
// Dump converted MIDI file
|
// Dump converted MIDI file
|
||||||
/*auto filePath = basePath + ".midi";
|
/*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);
|
fwrite(midi->data(), 1, midi->size(), fileHandle);
|
||||||
fclose(fileHandle);*/
|
fclose(fileHandle);*/
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ bool midi::play_track(Mix_Music* midi)
|
|||||||
/// <returns>Vector that contains MIDI file</returns>
|
/// <returns>Vector that contains MIDI file</returns>
|
||||||
std::vector<uint8_t>* midi::MdsToMidi(std::string file)
|
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)
|
if (!fileHandle)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ DatFile* partman::load_records(LPCSTR lpFileName, bool fullTiltMode)
|
|||||||
dat8BitBmpHeader bmpHeader{};
|
dat8BitBmpHeader bmpHeader{};
|
||||||
dat16BitBmpHeader zMapHeader{};
|
dat16BitBmpHeader zMapHeader{};
|
||||||
|
|
||||||
auto fileHandle = fopen(lpFileName, "rb");
|
auto fileHandle = fopenu(lpFileName, "rb");
|
||||||
if (fileHandle == nullptr)
|
if (fileHandle == nullptr)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ int pb::init()
|
|||||||
{
|
{
|
||||||
float projMat[12], zMin = 0, zScaler = 0;
|
float projMat[12], zMin = 0, zScaler = 0;
|
||||||
|
|
||||||
|
if (winmain::DatFileName.empty())
|
||||||
|
return 1;
|
||||||
auto dataFilePath = pinball::make_path_name(winmain::DatFileName);
|
auto dataFilePath = pinball::make_path_name(winmain::DatFileName);
|
||||||
record_table = partman::load_records(dataFilePath.c_str(), FullTiltMode);
|
record_table = partman::load_records(dataFilePath.c_str(), FullTiltMode);
|
||||||
|
|
||||||
|
|||||||
@@ -83,4 +83,14 @@ int Sign(T val)
|
|||||||
return (T(0) < val) - (val < T(0));
|
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
|
#endif //PCH_H
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ bool winmain::ShowSpriteViewer = false;
|
|||||||
bool winmain::LaunchBallEnabled = true;
|
bool winmain::LaunchBallEnabled = true;
|
||||||
bool winmain::HighScoresEnabled = true;
|
bool winmain::HighScoresEnabled = true;
|
||||||
bool winmain::DemoActive = false;
|
bool winmain::DemoActive = false;
|
||||||
char* winmain::BasePath;
|
std::string winmain::BasePath;
|
||||||
int winmain::MainMenuHeight = 0;
|
int winmain::MainMenuHeight = 0;
|
||||||
std::string winmain::FpsDetails;
|
std::string winmain::FpsDetails;
|
||||||
double winmain::UpdateToFrameRatio;
|
double winmain::UpdateToFrameRatio;
|
||||||
@@ -58,19 +58,44 @@ int winmain::WinMain(LPCSTR lpCmdLine)
|
|||||||
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not initialize SDL2", SDL_GetError(), nullptr);
|
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Could not initialize SDL2", SDL_GetError(), nullptr);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
BasePath = SDL_GetBasePath();
|
|
||||||
|
|
||||||
pinball::quickFlag = strstr(lpCmdLine, "-quick") != nullptr;
|
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*/
|
// Search for game data in: game folder, user folder
|
||||||
auto cadetFilePath = pinball::make_path_name("CADET.DAT");
|
// Game data test order: CADET.DAT, PINBALL.DAT
|
||||||
auto cadetDat = fopen(cadetFilePath.c_str(), "r");
|
char* dataSearchPaths[2]
|
||||||
if (cadetDat)
|
|
||||||
{
|
{
|
||||||
fclose(cadetDat);
|
SDL_GetBasePath(),
|
||||||
DatFileName = "CADET.DAT";
|
SDL_GetPrefPath(nullptr, "SpaceCadetPinball")
|
||||||
pb::FullTiltMode = true;
|
};
|
||||||
|
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
|
// SDL window
|
||||||
@@ -339,7 +364,6 @@ void winmain::RenderUi()
|
|||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
ImGui::PopStyleVar();
|
ImGui::PopStyleVar();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No demo window in release to save space
|
// No demo window in release to save space
|
||||||
@@ -348,7 +372,7 @@ void winmain::RenderUi()
|
|||||||
ImGui::ShowDemoWindow(&ShowImGuiDemo);
|
ImGui::ShowDemoWindow(&ShowImGuiDemo);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (ImGui::BeginMainMenuBar())
|
if (Options.ShowMenu && ImGui::BeginMainMenuBar())
|
||||||
{
|
{
|
||||||
int currentMenuHeight = static_cast<int>(ImGui::GetWindowSize().y);
|
int currentMenuHeight = static_cast<int>(ImGui::GetWindowSize().y);
|
||||||
if (MainMenuHeight != currentMenuHeight)
|
if (MainMenuHeight != currentMenuHeight)
|
||||||
@@ -777,7 +801,14 @@ int winmain::event_handler(const SDL_Event* event)
|
|||||||
case SDL_CONTROLLER_BUTTON_START:
|
case SDL_CONTROLLER_BUTTON_START:
|
||||||
pause();
|
pause();
|
||||||
break;
|
break;
|
||||||
default: ;
|
case SDL_CONTROLLER_BUTTON_BACK:
|
||||||
|
if (single_step)
|
||||||
|
{
|
||||||
|
SDL_Event event{ SDL_QUIT };
|
||||||
|
SDL_PushEvent(&event);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SDL_CONTROLLERBUTTONUP:
|
case SDL_CONTROLLERBUTTONUP:
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
static bool LaunchBallEnabled;
|
static bool LaunchBallEnabled;
|
||||||
static bool HighScoresEnabled;
|
static bool HighScoresEnabled;
|
||||||
static bool DemoActive;
|
static bool DemoActive;
|
||||||
static char* BasePath;
|
static std::string BasePath;
|
||||||
static int MainMenuHeight;
|
static int MainMenuHeight;
|
||||||
|
|
||||||
static int WinMain(LPCSTR lpCmdLine);
|
static int WinMain(LPCSTR lpCmdLine);
|
||||||
|
|||||||
Reference in New Issue
Block a user