summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml43
-rw-r--r--premake5.lua35
-rw-r--r--src/audio/MusicManager.cpp2
-rw-r--r--src/control/CarCtrl.cpp2
-rw-r--r--src/core/CdStreamPosix.cpp48
-rw-r--r--src/core/Frontend.cpp50
-rw-r--r--src/core/Game.cpp6
-rw-r--r--src/core/Pad.h2
-rw-r--r--src/core/common.h4
-rw-r--r--src/core/config.h6
-rw-r--r--src/core/main.h5
-rw-r--r--src/core/re3.cpp148
-rw-r--r--src/core/timebars.cpp2
-rw-r--r--src/extras/frontendoption.cpp16
-rw-r--r--src/extras/frontendoption.h16
-rw-r--r--src/extras/ini_parser.hpp314
-rw-r--r--src/render/Hud.cpp8
-rw-r--r--src/skel/crossplatform.cpp10
-rw-r--r--src/skel/crossplatform.h4
-rw-r--r--src/skel/glfw/glfw.cpp98
-rw-r--r--src/skel/win/win.cpp2
-rw-r--r--src/text/Text.cpp2
-rw-r--r--src/vehicles/CarGen.cpp10
23 files changed, 693 insertions, 140 deletions
diff --git a/.travis.yml b/.travis.yml
index 51ef58eb..c124a9f0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,44 @@
language: cpp
-os: linux
dist: focal
-matrix:
+os: linux
+jobs:
include:
- env: TARGET=release_linux-amd64-librw_gl3_glfw-oal
+ os: linux
- env: TARGET=debug_linux-amd64-librw_gl3_glfw-oal
+ os: linux
+ - env: TARGET=release_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15
+ compiler: clang
+ os: osx
+ osx_image: xcode12u
+ - env: TARGET=debug_macosx-amd64-librw_gl3_glfw-oal PREMAKE5=premake-5.0.0-alpha15
+ compiler: clang
+ os: osx
+ osx_image: xcode12u
+addons:
+ apt:
+ update: true
+ packages:
+ - linux-libc-dev
+ - libopenal-dev
+ - libglew-dev
+ - libglfw3-dev
+ - libsndfile1-dev
+ - libmpg123-dev
+ - gcc-8-multilib
+ - g++-8-multilib
+ homebrew:
+ packages:
+ - libsndfile
+ - mpg123
+ - glew
+ - glfw
+ - openal-soft
script:
- - sudo apt-get update
- - sudo apt-get -y install linux-libc-dev libopenal-dev libglew-dev libglfw3-dev libsndfile1-dev libmpg123-dev gcc-8-multilib g++-8-multilib
- mkdir -p "$TRAVIS_BUILD_DIR/build"
- cd "$TRAVIS_BUILD_DIR"
- - ./premake5Linux --with-librw gmake2
- - cd build
- - CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1
+ - if [ "$TRAVIS_OS_NAME" = linux ]; then ./premake5Linux --with-librw gmake2; fi
+ - if [ "$TRAVIS_OS_NAME" = osx ]; then curl -L -o "${PREMAKE5}.zip" "https://github.com/premake/premake-core/releases/download/v5.0.0-alpha15/${PREMAKE5}-src.zip" && unzip -q "${PREMAKE5}.zip" && cd "$PREMAKE5" && make -f Bootstrap.mak osx && cd .. && "./${PREMAKE5}/bin/release/premake5" --with-librw gmake2; fi
+ - cd build
+ - if [ "$TRAVIS_OS_NAME" = linux ]; then env CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1; fi
+ - if [ "$TRAVIS_OS_NAME" = osx ]; then make config=$TARGET -j4 verbose=1; fi
diff --git a/premake5.lua b/premake5.lua
index 881035ef..49be07c3 100644
--- a/premake5.lua
+++ b/premake5.lua
@@ -85,6 +85,12 @@ workspace "re3"
"bsd-amd64-librw_gl3_glfw-oal"
}
+ filter { "system:macosx" }
+ platforms {
+ "macosx-arm64-librw_gl3_glfw-oal",
+ "macosx-amd64-librw_gl3_glfw-oal",
+ }
+
filter "configurations:Debug"
defines { "DEBUG" }
@@ -100,6 +106,9 @@ workspace "re3"
filter { "platforms:bsd*" }
system "bsd"
+
+ filter { "platforms:macosx*" }
+ system "macosx"
filter { "platforms:*x86*" }
architecture "x86"
@@ -110,6 +119,12 @@ workspace "re3"
filter { "platforms:*arm*" }
architecture "ARM"
+ filter { "platforms:macosx-arm64-*" }
+ buildoptions { "-target", "arm64-apple-macos11", "-std=gnu++14" }
+
+ filter { "platforms:macosx-amd64-*" }
+ buildoptions { "-target", "x86_64-apple-macos10.12", "-std=gnu++14" }
+
filter { "platforms:*librw_d3d9*" }
defines { "RW_D3D9" }
if(not _OPTIONS["with-librw"]) then
@@ -162,6 +177,13 @@ project "librw"
filter "platforms:bsd*"
includedirs { "/usr/local/include" }
libdirs { "/usr/local/lib" }
+
+ filter "platforms:macosx*"
+ -- Support MacPorts and Homebrew
+ includedirs { "/opt/local/include" }
+ includedirs {"/usr/local/include" }
+ libdirs { "/opt/local/lib" }
+ libdirs { "/usr/local/lib" }
filter "platforms:*RW33*"
flags { "ExcludeFromBuild" }
@@ -276,6 +298,11 @@ project "re3"
filter "platforms:bsd*oal"
links { "openal", "mpg123", "sndfile", "pthread" }
+
+ filter "platforms:macosx*oal"
+ links { "openal", "mpg123", "sndfile", "pthread" }
+ includedirs { "/usr/local/opt/openal-soft/include" }
+ libdirs { "/usr/local/opt/openal-soft/lib" }
if _OPTIONS["with-opus"] then
filter {}
@@ -329,3 +356,11 @@ project "re3"
links { "GL", "GLEW", "glfw", "sysinfo" }
includedirs { "/usr/local/include" }
libdirs { "/usr/local/lib" }
+
+ filter "platforms:macosx*gl3_glfw*"
+ links { "GLEW", "glfw" }
+ linkoptions { "-framework OpenGL" }
+ includedirs { "/opt/local/include" }
+ includedirs { "/usr/local/include" }
+ libdirs { "/opt/local/lib" }
+ libdirs { "/usr/local/lib" }
diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp
index 9cf092b3..5519d899 100644
--- a/src/audio/MusicManager.cpp
+++ b/src/audio/MusicManager.cpp
@@ -161,7 +161,7 @@ cMusicManager::DisplayRadioStationName()
CFont::SetPropOn();
CFont::SetFontStyle(FONT_HEADING);
CFont::SetCentreOn();
- CFont::SetCentreSize(SCREEN_STRETCH_X(640.0f));
+ CFont::SetCentreSize(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH));
CFont::SetColor(CRGBA(0, 0, 0, 255));
CFont::PrintString(SCREEN_WIDTH / 2 + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(22.0f) + SCREEN_SCALE_Y(2.0f), pCurrentStation);
diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp
index 5a2def05..76ee47b0 100644
--- a/src/control/CarCtrl.cpp
+++ b/src/control/CarCtrl.cpp
@@ -2578,7 +2578,7 @@ void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle* pVehicle)
void CCarCtrl::JoinCarWithRoadSystem(CVehicle* pVehicle)
{
pVehicle->AutoPilot.m_nPrevRouteNode = pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nNextRouteNode = 0;
- pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nPreviousPathNodeInfo = pVehicle->AutoPilot.m_nNextPathNodeInfo = 0;
+ pVehicle->AutoPilot.m_nCurrentPathNodeInfo = pVehicle->AutoPilot.m_nPreviousPathNodeInfo = pVehicle->AutoPilot.m_nNextPathNodeInfo = 0;
int nodeId = ThePaths.FindNodeClosestToCoorsFavourDirection(pVehicle->GetPosition(), 0, pVehicle->GetForward().x, pVehicle->GetForward().y);
CPathNode* pNode = &ThePaths.m_pathNodes[nodeId];
int prevNodeId = -1;
diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp
index e114a29a..40000f03 100644
--- a/src/core/CdStreamPosix.cpp
+++ b/src/core/CdStreamPosix.cpp
@@ -36,9 +36,9 @@ struct CdReadInfo
#ifdef ONE_THREAD_PER_CHANNEL
int8 nThreadStatus; // 0: created 1:initalized 2:abort now
pthread_t pChannelThread;
- sem_t pStartSemaphore;
+ sem_t *pStartSemaphore;
#endif
- sem_t pDoneSemaphore; // used for CdStreamSync
+ sem_t *pDoneSemaphore; // used for CdStreamSync
int32 hFile;
};
@@ -51,7 +51,7 @@ char *gImgNames[MAX_CDIMAGES];
#ifndef ONE_THREAD_PER_CHANNEL
pthread_t _gCdStreamThread;
-sem_t gCdStreamSema; // released when we have new thing to read(so channel is set)
+sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set)
int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now
Queue gChannelRequestQ;
bool _gbCdStreamOverlapped;
@@ -76,11 +76,11 @@ CdStreamInitThread(void)
gChannelRequestQ.tail = 0;
gChannelRequestQ.size = gNumChannels + 1;
ASSERT(gChannelRequestQ.items != nil );
- status = sem_init(&gCdStreamSema, 0, 0);
+ gCdStreamSema = sem_open("/semaphore_cd_stream", O_CREAT, 0644, 1);
#endif
- if (status == -1) {
+ if (gCdStreamSema == SEM_FAILED) {
CDTRACE("failed to create stream semaphore");
ASSERT(0);
return;
@@ -91,18 +91,18 @@ CdStreamInitThread(void)
{
for ( int32 i = 0; i < gNumChannels; i++ )
{
- status = sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0);
+ gpReadInfo[i].pDoneSemaphore = sem_open("/semaphore_done", O_CREAT, 0644, 1);
- if (status == -1)
+ if (gpReadInfo[i].pDoneSemaphore == SEM_FAILED)
{
CDTRACE("failed to create sync semaphore");
ASSERT(0);
return;
}
#ifdef ONE_THREAD_PER_CHANNEL
- status = sem_init(&gpReadInfo[i].pStartSemaphore, 0, 0);
+ gpReadInfo[i].pStartSemaphore = sem_open("/semaphore_start", O_CREAT, 0644, 1);
- if (status == -1)
+ if (gpReadInfo[i].pStartSemaphore == SEM_FAILED)
{
CDTRACE("failed to create start semaphore");
ASSERT(0);
@@ -135,7 +135,7 @@ CdStreamInitThread(void)
return;
}
#else
- debug("Using seperate streaming threads for each channel\n");
+ debug("Using separate streaming threads for each channel\n");
#endif
}
@@ -163,7 +163,7 @@ CdStreamInit(int32 numChannels)
debug("Using no buffered loading for streaming\n");
}
*/
- void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, fsInfo.f_bsize);
+ void *pBuffer = (void *)RwMallocAlign(CDSTREAM_SECTOR_SIZE, (RwUInt32)fsInfo.f_bsize);
ASSERT( pBuffer != nil );
gNumImages = 0;
@@ -205,7 +205,7 @@ GetGTA3ImgSize(void)
return 0;
}
ok:
- return statbuf.st_size;
+ return (uint32)statbuf.st_size;
}
void
@@ -214,7 +214,7 @@ CdStreamShutdown(void)
// Destroying semaphores and free(gpReadInfo) will be done at threads
#ifndef ONE_THREAD_PER_CHANNEL
gCdStreamThreadStatus = 2;
- sem_post(&gCdStreamSema);
+ sem_post(gCdStreamSema);
#endif
#ifdef ONE_THREAD_PER_CHANNEL
@@ -254,7 +254,7 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size)
#ifndef ONE_THREAD_PER_CHANNEL
AddToQueue(&gChannelRequestQ, channel);
- if ( sem_post(&gCdStreamSema) != 0 )
+ if ( sem_post(gCdStreamSema) != 0 )
printf("Signal Sema Error\n");
#else
if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 )
@@ -332,7 +332,7 @@ CdStreamSync(int32 channel)
{
pChannel->bLocked = true;
- sem_wait(&pChannel->pDoneSemaphore);
+ sem_wait(pChannel->pDoneSemaphore);
}
pChannel->bReading = false;
@@ -383,7 +383,7 @@ void *CdStreamThread(void *param)
#ifndef ONE_THREAD_PER_CHANNEL
while (gCdStreamThreadStatus != 2) {
- sem_wait(&gCdStreamSema);
+ sem_wait(gCdStreamSema);
int32 channel = GetFirstInQueue(&gChannelRequestQ);
#else
int channel = *((int*)param);
@@ -437,20 +437,24 @@ void *CdStreamThread(void *param)
if ( pChannel->bLocked )
{
- sem_post(&pChannel->pDoneSemaphore);
+ sem_post(pChannel->pDoneSemaphore);
}
pChannel->bReading = false;
}
#ifndef ONE_THREAD_PER_CHANNEL
for ( int32 i = 0; i < gNumChannels; i++ )
{
- sem_destroy(&gpReadInfo[i].pDoneSemaphore);
+ sem_close(gpReadInfo[i].pDoneSemaphore);
+ sem_unlink("/semaphore_done");
}
- sem_destroy(&gCdStreamSema);
- free(gChannelRequestQ.items);
+ sem_close(gCdStreamSema);
+ sem_unlink("/semaphore_cd_stream");
+ free(gChannelRequestQ.items);
#else
- sem_destroy(&gpReadInfo[channel].pStartSemaphore);
- sem_destroy(&gpReadInfo[channel].pDoneSemaphore);
+ sem_close(gpReadInfo[channel].pStartSemaphore);
+ sem_unlink("/semaphore_start");
+ sem_close(gpReadInfo[channel].pDoneSemaphore);
+ sem_unlink("/semaphore_done");
#endif
free(gpReadInfo);
pthread_exit(nil);
diff --git a/src/core/Frontend.cpp b/src/core/Frontend.cpp
index 9ead2a0a..db3774a7 100644
--- a/src/core/Frontend.cpp
+++ b/src/core/Frontend.cpp
@@ -854,6 +854,13 @@ CMenuManager::Draw()
str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName);
break;
default:
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ if (aScreens[m_nCurrScreen].m_aEntries[0].m_SaveSlot == SAVESLOT_CFO) {
+ FrontendOption& option = customFrontendOptions[aScreens[m_nCurrScreen].m_aEntries[0].m_TargetMenu];
+ str = (wchar*)option.leftText;
+ }
+ else
+#endif
str = TheText.Get(aScreens[m_nCurrScreen].m_aEntries[0].m_EntryName);
break;
}
@@ -3443,19 +3450,6 @@ CMenuManager::LoadSettings()
CFileMgr::Read(fileHandle, m_PrefsSkinFile, 256);
CFileMgr::Read(fileHandle, (char*)&m_ControlMethod, 1);
CFileMgr::Read(fileHandle, (char*)&m_PrefsLanguage, 1);
-#ifdef CUSTOM_FRONTEND_OPTIONS
- for (int i = 0; i < numCustomFrontendOptions; i++) {
- FrontendOption& option = customFrontendOptions[i];
- if (option.save) {
- CFileMgr::Read(fileHandle, (char*)option.value, 1);
- option.lastSavedValue = option.displayedValue = *option.value;
- }
- }
-#endif
-#ifdef NO_ISLAND_LOADING
- CFileMgr::Read(fileHandle, (char *)&CMenuManager::m_PrefsIslandLoading, 1);
- CMenuManager::m_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading;
-#endif
}
}
@@ -3472,8 +3466,11 @@ CMenuManager::LoadSettings()
m_bLanguageLoaded = false;
else {
m_bLanguageLoaded = true;
+ // Already called in InitialiseChangedLanguageSettings
+ /*
TheText.Unload();
TheText.Load();
+ */
m_bFrontEnd_ReloadObrTxtGxt = true;
InitialiseChangedLanguageSettings();
@@ -3546,21 +3543,14 @@ CMenuManager::SaveSettings()
CFileMgr::Write(fileHandle, m_PrefsSkinFile, 256);
CFileMgr::Write(fileHandle, (char*)&m_ControlMethod, 1);
CFileMgr::Write(fileHandle, (char*)&m_PrefsLanguage, 1);
-#ifdef CUSTOM_FRONTEND_OPTIONS
- for (int i = 0; i < numCustomFrontendOptions; i++) {
- FrontendOption &option = customFrontendOptions[i];
- if (option.save) {
- CFileMgr::Write(fileHandle, (char*)option.value, 1);
- }
- }
-#endif
-#ifdef NO_ISLAND_LOADING
- CFileMgr::Write(fileHandle, (char *)&CMenuManager::m_PrefsIslandLoading, 1);
-#endif
}
CFileMgr::CloseFile(fileHandle);
CFileMgr::SetDir("");
+
+#ifdef LOAD_INI_SETTINGS
+ SaveINISettings();
+#endif
}
bool DoRWStuffStartOfFrame(int16 TopRed, int16 TopGreen, int16 TopBlue, int16 BottomRed, int16 BottomGreen, int16 BottomBlue, int16 Alpha);
@@ -3880,7 +3870,10 @@ CMenuManager::Process(void)
MouseButtonJustClicked = 4;
else if (CPad::GetPad(0)->GetMouseWheelDownJustUp())
MouseButtonJustClicked = 5;
- // TODO two more buttons
+ else if (CPad::GetPad(0)->GetMouseX1JustUp())
+ MouseButtonJustClicked = 6;
+ else if (CPad::GetPad(0)->GetMouseX2JustUp())
+ MouseButtonJustClicked = 7;
JoyButtonJustClicked = ControlsManager.GetJoyButtonJustDown();
@@ -5106,7 +5099,8 @@ CMenuManager::ProcessButtonPresses(void)
*option.value = option.lastSavedValue = option.displayedValue;
} else if (option.type == FEOPTION_DYNAMIC) {
- option.buttonPressFunc(FEOPTION_ACTION_SELECT);
+ if (option.buttonPressFunc)
+ option.buttonPressFunc(FEOPTION_ACTION_SELECT);
} else if (option.type == FEOPTION_REDIRECT) {
ChangeScreen(option.to, option.option, true, option.fadeIn);
} else if (option.type == FEOPTION_GOBACK) {
@@ -5349,7 +5343,7 @@ CMenuManager::ProcessButtonPresses(void)
option.changeFunc(option.displayedValue);
*option.value = option.lastSavedValue = option.displayedValue;
}
- } else if (option.type == FEOPTION_DYNAMIC) {
+ } else if (option.type == FEOPTION_DYNAMIC && option.buttonPressFunc) {
option.buttonPressFunc(changeValueBy > 0 ? FEOPTION_ACTION_RIGHT : FEOPTION_ACTION_LEFT);
}
DMAudio.PlayFrontEndSound(SOUND_FRONTEND_MENU_SETTING_CHANGE, 0);
@@ -6317,4 +6311,4 @@ CMenuManager::ConstructStatLine(int rowIdx)
#undef GetBackJustDown
#undef ChangeScreen
-#endif \ No newline at end of file
+#endif
diff --git a/src/core/Game.cpp b/src/core/Game.cpp
index e944512a..93f0d1b0 100644
--- a/src/core/Game.cpp
+++ b/src/core/Game.cpp
@@ -295,11 +295,15 @@ bool CGame::InitialiseOnceAfterRW(void)
CWorld::Players[0].SetPlayerSkin(CMenuManager::m_PrefsSkinFile);
#ifdef CUSTOM_FRONTEND_OPTIONS
+ // Apparently this func. can be run multiple times at the start.
if (numCustomFrontendOptions == 0 && numCustomFrontendScreens == 0) {
+ // needs stored language and TheText to be loaded, and last TheText reload is at the start of here
CustomFrontendOptionsPopulate();
- FrontEndMenuManager.LoadSettings();
}
#endif
+#ifdef LOAD_INI_SETTINGS
+ LoadINISettings(); // needs frontend options to be loaded
+#endif
return true;
}
diff --git a/src/core/Pad.h b/src/core/Pad.h
index 8c3bc752..8c5d7ba3 100644
--- a/src/core/Pad.h
+++ b/src/core/Pad.h
@@ -277,6 +277,8 @@ public:
bool GetMiddleMouseJustUp() { return !!(!NewMouseControllerState.MMB && OldMouseControllerState.MMB); }
bool GetMouseWheelUpJustUp() { return !!(!NewMouseControllerState.WHEELUP && OldMouseControllerState.WHEELUP); }
bool GetMouseWheelDownJustUp() { return !!(!NewMouseControllerState.WHEELDN && OldMouseControllerState.WHEELDN); }
+ bool GetMouseX1JustUp() { return !!(!NewMouseControllerState.MXB1 && OldMouseControllerState.MXB1); }
+ bool GetMouseX2JustUp() { return !!(!NewMouseControllerState.MXB2 && OldMouseControllerState.MXB2); }
bool GetLeftMouse() { return NewMouseControllerState.LMB; }
bool GetRightMouse() { return NewMouseControllerState.RMB; }
diff --git a/src/core/common.h b/src/core/common.h
index 9b5c2369..ef3da265 100644
--- a/src/core/common.h
+++ b/src/core/common.h
@@ -219,6 +219,8 @@ public:
extern int strcasecmp(const char *str1, const char *str2);
#endif
+extern wchar *AllocUnicode(const char*src);
+
#define clamp(v, low, high) ((v)<(low) ? (low) : (v)>(high) ? (high) : (v))
inline float sq(float x) { return x*x; }
@@ -444,4 +446,4 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
assert(ReadSaveBuf<uint32>(buf) == size);
-void cprintf(char*, ...); \ No newline at end of file
+void cprintf(char*, ...);
diff --git a/src/core/config.h b/src/core/config.h
index e8e15ebe..171c6be9 100644
--- a/src/core/config.h
+++ b/src/core/config.h
@@ -198,6 +198,7 @@ enum Config {
#define FIX_BUGS // fixes bugs that we've came across during reversing, TODO: use this more
#define MORE_LANGUAGES // Add more translations to the game
#define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible
+#define LOAD_INI_SETTINGS
// Rendering/display
#define ASPECT_RATIO_SCALE // Not just makes everything scale with aspect ratio, also adds support for all aspect ratios
@@ -226,6 +227,9 @@ enum Config {
#if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT
#endif
+#if !defined(_WIN32) && !defined(__SWITCH__)
+#define DONT_TRUST_RECOGNIZED_JOYSTICKS // Then we'll only rely on GLFW gamepad DB, and expect user to enter Controller->Detect joysticks if his joystick isn't on that list.
+#endif
#define DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m
#define KANGAROO_CHEAT
#define ALLCARSHELI_CHEAT
@@ -306,4 +310,4 @@ enum Config {
#undef NO_ISLAND_LOADING
#define PC_PARTICLE
#define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial
-#endif \ No newline at end of file
+#endif
diff --git a/src/core/main.h b/src/core/main.h
index 96fbef05..7eb080cb 100644
--- a/src/core/main.h
+++ b/src/core/main.h
@@ -36,3 +36,8 @@ void ResetLoadingScreenBar(void);
#ifndef MASTER
void TheModelViewer(void);
#endif
+
+#ifdef LOAD_INI_SETTINGS
+void LoadINISettings();
+void SaveINISettings();
+#endif
diff --git a/src/core/re3.cpp b/src/core/re3.cpp
index 13cb6283..069320ec 100644
--- a/src/core/re3.cpp
+++ b/src/core/re3.cpp
@@ -1,6 +1,7 @@
#include <csignal>
#define WITHWINDOWS
#include "common.h"
+#include "platform.h"
#include "crossplatform.h"
#include "Renderer.h"
#include "Credits.h"
@@ -16,7 +17,6 @@
#include "Heli.h"
#include "Automobile.h"
#include "Ped.h"
-#include "Particle.h"
#include "Console.h"
#include "Debug.h"
#include "Hud.h"
@@ -38,8 +38,6 @@
#include <stdarg.h>
#endif
-#include <list>
-
#ifdef RWLIBS
extern "C" int vsprintf(char* const _Buffer, char const* const _Format, va_list _ArgList);
#endif
@@ -73,7 +71,6 @@ mysrand(unsigned int seed)
#ifdef CUSTOM_FRONTEND_OPTIONS
#include "frontendoption.h"
-#include "platform.h"
#include "Font.h"
void ReloadFrontendOptions(void)
@@ -195,6 +192,7 @@ wchar* MultiSamplingDraw(bool *disabled, bool userHovering) {
return unicodeTemp;
}
}
+const char* multisamplingKey = "MultiSampling";
#endif
#ifdef MORE_LANGUAGES
@@ -247,6 +245,7 @@ void FreeCamChange(int8 displayedValue)
TheCamera.bFreeCam = !!displayedValue;
FrontEndMenuManager.SaveSettings();
}
+const char* freeCamKey = "FreeCam";
#endif
#ifdef CUTSCENE_BORDERS_SWITCH
@@ -255,6 +254,7 @@ void BorderModeChange(int8 displayedValue)
CMenuManager::m_PrefsCutsceneBorders = !!displayedValue;
FrontEndMenuManager.SaveSettings();
}
+const char* cutsceneBordersKey = "CutsceneBorders";
#endif
#ifdef PS2_ALPHA_TEST
@@ -263,11 +263,52 @@ void PS2AlphaTestChange(int8 displayedValue)
gPS2alphaTest = !!displayedValue;
FrontEndMenuManager.SaveSettings();
}
+const char* ps2alphaKey = "PS2AlphaTest";
#endif
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+wchar selectedJoystickUnicode[128];
+
+wchar* DetectJoystickDraw(bool* disabled, bool userHovering) {
+ int numButtons;
+ int found = -1;
+ const char *joyname;
+ if (userHovering) {
+ for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
+ if (joyname = glfwGetJoystickName(i)) {
+ const uint8* buttons = glfwGetJoystickButtons(i, &numButtons);
+ for (int j = 0; j < numButtons; j++) {
+ if (buttons[j]) {
+ found = i;
+ break;
+ }
+ }
+ if (found != -1)
+ break;
+ }
+ }
+
+ if (found != -1 && PSGLOBAL(joy1id) != found) {
+ if (PSGLOBAL(joy1id) != -1 && PSGLOBAL(joy1id) != found)
+ PSGLOBAL(joy2id) = PSGLOBAL(joy1id);
+ else
+ PSGLOBAL(joy2id) = -1;
+
+ strcpy(gSelectedJoystickName, joyname);
+ PSGLOBAL(joy1id) = found;
+ }
+ }
+ if (PSGLOBAL(joy1id) == -1)
+ AsciiToUnicode("Not found", selectedJoystickUnicode);
+ else
+ AsciiToUnicode(gSelectedJoystickName, selectedJoystickUnicode);
+
+ return selectedJoystickUnicode;
+}
+#endif
// Important: Make sure to read the warnings/informations in frontendoption.h!!
-// For texts: Either use TheText.Get, or use wcsdup(wchar version of strdup)
+// If you will hardcode any text, please use AllocUnicode! wchar_t size differs between platforms
void
CustomFrontendOptionsPopulate(void)
{
@@ -342,14 +383,14 @@ CustomFrontendOptionsPopulate(void)
#ifdef MULTISAMPLING
SWITCH_TO_GRAPHICS_MENU
- FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, true);
+ FrontendOptionAddDynamic(TheText.Get("FED_AAS"), MultiSamplingDraw, (int8*)&FrontEndMenuManager.m_nPrefsMSAALevel, MultiSamplingButtonPress, MultiSamplingGoBack, multisamplingKey);
#endif
CLONE_OPTION(TheText.Get("FED_TRA"), MENUACTION_TRAILS, nil, nil);
#ifdef PS2_ALPHA_TEST
SWITCH_TO_GRAPHICS_MENU
- FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, true);
+ FrontendOptionAddSelect(TheText.Get("FEM_2PR"), off_on, 2, (int8*)&gPS2alphaTest, false, PS2AlphaTestChange, nil, ps2alphaKey);
#endif
ADD_RESTORE_DEFAULTS(RestoreDefGraphics)
@@ -365,13 +406,12 @@ CustomFrontendOptionsPopulate(void)
#ifdef CUTSCENE_BORDERS_SWITCH
SWITCH_TO_DISPLAY_MENU
- FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, true);
+ FrontendOptionAddSelect(TheText.Get("FEM_CSB"), off_on, 2, (int8 *)&CMenuManager::m_PrefsCutsceneBorders, false, BorderModeChange, nil, cutsceneBordersKey);
#endif
#ifdef FREE_CAM
SWITCH_TO_DISPLAY_MENU
- static const wchar* text = (wchar*)wcsdup(L"FREE CAM");
- FrontendOptionAddSelect(text, off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, true);
+ FrontendOptionAddSelect(TheText.Get("FEC_FRC"), off_on, 2, (int8*)&TheCamera.bFreeCam, false, FreeCamChange, nil, freeCamKey);
#endif
CLONE_OPTION(TheText.Get("FED_SUB"), MENUACTION_SUBTITLES, nil, nil);
@@ -389,9 +429,95 @@ CustomFrontendOptionsPopulate(void)
ADD_RESTORE_DEFAULTS(RestoreDefDisplay)
ADD_BACK
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ int detectJoystickMenu = FrontendScreenAdd("FEC_JOD", MENUSPRITE_MAINMENU, MENUPAGE_CONTROLLER_PC, 40, 60, 20,
+ FONT_BANK, MEDIUMTEXT_X_SCALE, MEDIUMTEXT_Y_SCALE, FESCREEN_LEFT_ALIGN, false);
+
+ FrontendOptionSetCursor(detectJoystickMenu, 0);
+
+ FrontendOptionAddBuiltinAction(TheText.Get("FEC_JPR"), MENUACTION_LABEL, nil, nil);
+ FrontendOptionAddDynamic(TheText.Get("FEC_JDE"), DetectJoystickDraw, nil, nil, nil);
+ FrontendOptionAddBackButton(TheText.Get("FEDS_TB"));
+
+ FrontendOptionSetCursor(MENUPAGE_CONTROLLER_PC, 2);
+ FrontendOptionAddRedirect(TheText.Get("FEC_JOD"), detectJoystickMenu, 1);
+#endif
}
#endif
+#ifdef LOAD_INI_SETTINGS
+#include "ini_parser.hpp"
+void LoadINISettings()
+{
+ linb::ini cfg;
+ cfg.load_file("re3.ini");
+ char defaultStr[4];
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ strcpy(gSelectedJoystickName, cfg.get("DetectJoystick", "JoystickName", "").c_str());
+ _InputInitialiseJoys();
+#endif
+
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ for (int i = 0; i < numCustomFrontendOptions; i++) {
+ FrontendOption& option = customFrontendOptions[i];
+ if (option.save) {
+ // CFO only supports saving uint8 right now
+ sprintf(defaultStr, "%u", *option.value);
+ option.lastSavedValue = option.displayedValue = *option.value = atoi(cfg.get("FrontendOptions", option.save, defaultStr).c_str());
+ }
+ }
+#endif
+
+#ifdef NO_ISLAND_LOADING
+ sprintf(defaultStr, "%u", CMenuManager::m_PrefsIslandLoading);
+ CMenuManager::m_PrefsIslandLoading = atoi(cfg.get("FrontendOptions", "NoIslandLoading", defaultStr).c_str());
+ CMenuManager::m_DisplayIslandLoading = CMenuManager::m_PrefsIslandLoading;
+#endif
+
+}
+
+void SaveINISettings()
+{
+ linb::ini cfg;
+ cfg.load_file("re3.ini");
+ bool changed = false;
+ char temp[4];
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ if (strncmp(cfg.get("DetectJoystick", "JoystickName", "").c_str(), gSelectedJoystickName, strlen(gSelectedJoystickName)) != 0) {
+ changed = true;
+ cfg.set("DetectJoystick", "JoystickName", gSelectedJoystickName);
+ }
+#endif
+#ifdef CUSTOM_FRONTEND_OPTIONS
+ for (int i = 0; i < numCustomFrontendOptions; i++) {
+ FrontendOption &option = customFrontendOptions[i];
+ if (option.save) {
+ if (atoi(cfg.get("FrontendOptions", option.save, "xxx").c_str()) != *option.value) { // if .ini doesn't have that key compare with xxx, so we can add it
+ changed = true;
+ sprintf(temp, "%u", *option.value);
+ cfg.set("FrontendOptions", option.save, temp);
+ }
+ }
+ }
+#endif
+#ifdef NO_ISLAND_LOADING
+ if (atoi(cfg.get("FrontendOptions", "NoIslandLoading", "xxx").c_str()) != CMenuManager::m_PrefsIslandLoading) {
+ changed = true;
+ sprintf(temp, "%u", CMenuManager::m_PrefsIslandLoading);
+ cfg.set("FrontendOptions", "NoIslandLoading", temp);
+ }
+#endif
+
+ if (changed)
+ cfg.write_file("re3.ini");
+}
+
+#endif
+
+
#ifdef DEBUGMENU
void WeaponCheat();
void HealthCheat();
@@ -539,6 +665,8 @@ static const char *carnames[] = {
"yankee", "escape", "borgnine", "toyz", "ghost",
};
+//#include <list>
+
static CTweakVar** TweakVarsList;
static int TweakVarsListSize = -1;
static bool bAddTweakVarsNow = false;
diff --git a/src/core/timebars.cpp b/src/core/timebars.cpp
index 5ac5565d..94051b25 100644
--- a/src/core/timebars.cpp
+++ b/src/core/timebars.cpp
@@ -89,7 +89,7 @@ void tbDisplay()
CFont::SetScale(0.48f, 1.12f);
CFont::SetCentreOff();
CFont::SetJustifyOff();
- CFont::SetWrapx(640.0f);
+ CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH));
CFont::SetRightJustifyOff();
CFont::SetPropOn();
CFont::SetFontStyle(FONT_BANK);
diff --git a/src/extras/frontendoption.cpp b/src/extras/frontendoption.cpp
index b365a3fe..ed8aa2a9 100644
--- a/src/extras/frontendoption.cpp
+++ b/src/extras/frontendoption.cpp
@@ -213,10 +213,10 @@ void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPre
TextCopy(option.leftText, leftText);
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = returnPrevPageFunc;
- option.save = false;
+ option.save = nil;
}
-void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save)
+void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName)
{
int8 screenOptionOrder = RegisterNewOption();
@@ -229,14 +229,14 @@ void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, in
option.value = var;
option.displayedValue = *var;
option.lastSavedValue = *var;
- option.save = save;
+ option.save = saveName;
option.onlyApplyOnEnter = onlyApplyOnEnter;
option.changeFunc = changeFunc;
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = returnPrevPageFunc;
}
-void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save)
+void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName)
{
int8 screenOptionOrder = RegisterNewOption();
@@ -246,7 +246,7 @@ void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc drawFunc, int8 *va
option.buttonPressFunc = buttonPressFunc;
TextCopy(option.leftText, leftText);
option.value = var;
- option.save = save;
+ option.save = saveName;
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = returnPrevPageFunc;
}
@@ -263,7 +263,7 @@ void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption, b
TextCopy(option.leftText, text);
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = nil;
- option.save = false;
+ option.save = nil;
}
void FrontendOptionAddBackButton(const wchar* text, bool fadeIn)
@@ -276,7 +276,7 @@ void FrontendOptionAddBackButton(const wchar* text, bool fadeIn)
TextCopy(option.leftText, text);
option.screenOptionOrder = screenOptionOrder;
option.returnPrevPageFunc = nil;
- option.save = false;
+ option.save = nil;
}
uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight,
@@ -300,4 +300,4 @@ uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, i
return screenOrder;
}
-#endif \ No newline at end of file
+#endif
diff --git a/src/extras/frontendoption.h b/src/extras/frontendoption.h
index b2bfbf5e..dac6be62 100644
--- a/src/extras/frontendoption.h
+++ b/src/extras/frontendoption.h
@@ -10,7 +10,7 @@
// About texts:
// All text parameters accept wchar(including hardcoded wchar* and TheText.Get)
-// except FrontendScreenAdd(it's char[8] by the design of Frontend).
+// except FrontendScreenAdd(it's char[8] GXT key by the design of Frontend).
// All texts reload if custom options reloaded too, which includes language changes and via live reload feature in debug menu!
// Execute direction:
@@ -26,7 +26,7 @@
//
// Static/select: You allocate the variable, pass it to function and game sets it from user input among the strings given to function,
// then you can handle ChangeFunc(only called on enter if onlyApplyOnEnter set, or set immediately)
-// and ReturnPrevPageFunc optionally. You can store the option in gta3.set if you pass true to corresponding parameter.
+// and ReturnPrevPageFunc optionally. You can store the option in an INI file if you pass the key(as a char array) to corresponding parameter.
//
// Dynamic: Passing variable to function is only needed if you want to store it, otherwise you should do
// all the operations with ButtonPressFunc, this includes allocating the variable.
@@ -91,11 +91,11 @@ struct FrontendOption
int8 type;
int8 screenOptionOrder;
int32 screen;
- wchar leftText[64];
+ wchar leftText[128];
ReturnPrevPageFunc returnPrevPageFunc;
int8* value;
int8 displayedValue; // only if onlyApplyOnEnter enabled for now
- bool save;
+ const char* save;
int32 ogOptionId; // for replacements, see overwrite parameter of SetCursor
union {
@@ -151,12 +151,12 @@ uint8 GetNumberOfMenuOptions(int screen);
void FrontendOptionSetCursor(int screen, int8 option, bool overwrite = false);
-// var is optional in AddDynamic, you can enable save parameter if you pass one, otherwise pass nil/0
+// var is optional in AddDynamic, enables you to save them in an INI file(also needs passing char array to saveName param. obv), otherwise pass nil/0
void FrontendOptionAddBuiltinAction(const wchar* leftText, int action, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc);
-void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false);
-void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, bool save = false);
+void FrontendOptionAddSelect(const wchar* leftText, const wchar** rightTexts, int8 numRightTexts, int8 *var, bool onlyApplyOnEnter, ChangeFunc changeFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil);
+void FrontendOptionAddDynamic(const wchar* leftText, DrawFunc rightTextDrawFunc, int8 *var, ButtonPressFunc buttonPressFunc, ReturnPrevPageFunc returnPrevPageFunc, const char* saveName = nil);
void FrontendOptionAddRedirect(const wchar* text, int to, int8 selectedOption = 0, bool fadeIn = true);
void FrontendOptionAddBackButton(const wchar* text, bool fadeIn = true);
uint8 FrontendScreenAdd(const char* gxtKey, eMenuSprites sprite, int prevPage, int columnWidth, int headerHeight, int lineHeight, int8 font, float fontScaleX, float fontScaleY, int8 alignment, bool showLeftRightHelper, ReturnPrevPageFunc returnPrevPageFunc = nil);
-#endif \ No newline at end of file
+#endif
diff --git a/src/extras/ini_parser.hpp b/src/extras/ini_parser.hpp
new file mode 100644
index 00000000..99acf1ee
--- /dev/null
+++ b/src/extras/ini_parser.hpp
@@ -0,0 +1,314 @@
+/*
+ * Copyright (c) 2013-2015 Denilson das Mercês Amorim <dma_2012@hotmail.com>
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source
+ * distribution.
+ *
+ */
+#ifndef LINB_INI_PARSER_HPP
+#define LINB_INI_PARSER_HPP
+
+/*
+ * STL-like INI Container
+ */
+
+#include <string> // for std::string
+#include <map> // for std::map
+#include <cstdio> // for std::FILE
+#include <algorithm> // for std::find_if
+#include <functional> // for std::function
+
+namespace linb
+{
+ template<
+ class CharT = char, /* Not compatible with other type here, since we're using C streams */
+ class StringType = std::basic_string<CharT>,
+ class KeyContainer = std::map<StringType, StringType>,
+ class SectionContainer = std::map<StringType, KeyContainer>
+ > class basic_ini
+ {
+ public:
+ typedef CharT char_type;
+ typedef StringType string_type;
+ typedef KeyContainer key_container;
+ typedef SectionContainer section_container;
+
+ // Typedef container values types
+ typedef typename section_container::value_type value_type;
+ typedef typename section_container::key_type key_type;
+ typedef typename section_container::mapped_type mapped_type;
+
+ // Typedef common types
+ typedef typename section_container::size_type size_type;
+ typedef typename section_container::difference_type difference_type;
+
+ // Typedef iterators
+ typedef typename section_container::iterator iterator;
+ typedef typename section_container::const_iterator const_iterator;
+ typedef typename section_container::reverse_iterator reverse_iterator;
+ typedef typename section_container::const_reverse_iterator const_reverse_iterator;
+
+ // typedef References and pointers
+ typedef typename section_container::reference reference;
+ typedef typename section_container::const_reference const_reference;
+ typedef typename section_container::pointer pointer;
+ typedef typename section_container::const_pointer const_pointer;
+
+ private:
+ section_container data;
+
+ public:
+
+ basic_ini()
+ { }
+
+ basic_ini(const char_type* filename)
+ { this->read_file(filename); }
+
+ /* Iterator methods */
+ iterator begin()
+ { return data.begin(); }
+ const_iterator begin() const
+ { return data.begin(); }
+ iterator end()
+ { return data.end(); }
+ const_iterator end() const
+ { return data.end(); }
+ const_iterator cbegin() const
+ { return data.cbegin(); }
+ const_iterator cend() const
+ { return data.cend(); }
+
+ /* Reverse iterator methods */
+ reverse_iterator rbegin()
+ { return data.rbegin(); }
+ const_reverse_iterator rbegin() const
+ { return data.rbegin(); }
+ reverse_iterator rend()
+ { return data.rend(); }
+ const_reverse_iterator rend() const
+ { return data.rend(); }
+ const_reverse_iterator crbegin() const
+ { return data.crbegin(); }
+ const_reverse_iterator crend() const
+ { return data.crend(); }
+
+ /* Acessing index methods */
+ mapped_type& operator[](const string_type& sect)
+ { return data[sect]; }
+ mapped_type& operator[](string_type&& sect)
+ { return data[std::forward<string_type>(sect)]; }
+ mapped_type& at( const string_type& sect)
+ { return data.at(sect); }
+ const mapped_type& at(const string_type& sect) const
+ { return data.at(sect); }
+
+ /* Capacity information */
+ bool empty() const
+ { return data.empty(); }
+ size_type size() const
+ { return data.size(); }
+ size_type max_size() const
+ { return data.max_size(); }
+
+ /* Modifiers */
+ void clear()
+ { return data.clear(); }
+
+ /* Lookup */
+ size_type count(const string_type& sect)
+ { return data.count(sect); }
+ iterator find(const string_type& sect)
+ { return data.find(sect); }
+
+ /* Gets a value from the specified section & key, default_value is returned if the sect & key doesn't exist */
+ string_type get(const string_type& sect, const key_type& key, const string_type& default_value)
+ {
+ auto it = this->find(sect);
+ if(it != this->end())
+ {
+ auto itv = it->second.find(key);
+ if(itv != it->second.end())
+ return itv->second;
+ }
+ return default_value;
+ }
+
+ /* Sets the value of a value in the ini */
+ void set(const string_type& sect, const key_type& key, const string_type& value)
+ {
+ (*this)[sect][key] = value; // no emplace since overwrite!
+ }
+
+ /* Too lazy to continue this container... If you need more methods, just add it */
+
+
+#if 1
+ bool read_file(const char_type* filename)
+ {
+ /* Using C stream in a STL-like container, funny?
+ */
+ if(FILE* f = fopen(filename, "r"))
+ {
+ key_container* keys = nullptr;
+ char_type buf[2048];
+ string_type line;
+ string_type key;
+ string_type value;
+ string_type null_string;
+ size_type pos;
+
+ // Trims an string
+ auto trim = [](string_type& s, bool trimLeft, bool trimRight) -> string_type&
+ {
+ if(s.size())
+ {
+ // Ignore UTF-8 BOM
+ while(s.size() >= 3 && s[0] == (char)(0xEF) && s[1] == (char)(0xBB) && s[2] == (char)(0xBF))
+ s.erase(s.begin(), s.begin() + 3);
+
+ if(trimLeft)
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::function<int(int)>(::isspace))));
+ if(trimRight)
+ s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::function<int(int)>(::isspace))).base(), s.end());
+ }
+ return s;
+ };
+
+ // Start parsing
+ while(fgets(buf, sizeof(buf), f))
+ {
+ // What a thing, reading into a char buffer and then putting in the string...
+ line = buf;
+
+ // Find comment and remove anything after it from the line
+ if((pos = line.find_first_of(';')) != line.npos)
+ line.erase(pos);
+
+ // Trim the string, and if it gets empty, skip this line
+ if(trim(line, true, true).empty())
+ continue;
+
+ // Find section name
+ if(line.front() == '[' && line.back() == ']')
+ {
+ pos = line.length() - 1; //line.find_first_of(']');
+ if(pos != line.npos)
+ {
+ trim(key.assign(line, 1, pos-1), true, true);
+ keys = &data[std::move(key)]; // Create section
+ }
+ else
+ keys = nullptr;
+ }
+ else
+ {
+ // Find key and value positions
+ pos = line.find_first_of('=');
+ if(pos == line.npos)
+ {
+ // There's only the key
+ key = line; // No need for trim, line is already trimmed
+ value.clear();
+ }
+ else
+ {
+ // There's the key and the value
+ trim(key.assign(line, 0, pos), false, true); // trim the right
+ trim(value.assign(line, pos + 1, line.npos), true, false); // trim the left
+ }
+
+ // Put the key/value into the current keys object, or into the section "" if no section has been found
+ #if __cplusplus >= 201103L || _MSC_VER >= 1800
+ (keys ? *keys : data[null_string]).emplace(std::move(key), std::move(value));
+ #else
+ (keys ? *keys : data[null_string])[key] = value;
+ key.clear(); value.clear();
+ #endif
+ }
+ }
+
+ fclose(f);
+ return true;
+ }
+ return false;
+ }
+
+ /*
+ * Dumps the content of this container into an ini file
+ */
+ bool write_file(const char_type* filename)
+ {
+ if(FILE* f = fopen(filename, "w"))
+ {
+ bool first = true;
+ for(auto& sec : this->data)
+ {
+ fprintf(f, first? "[%s]\n" : "\n[%s]\n", sec.first.c_str());
+ first = false;
+ for(auto& kv : sec.second)
+ {
+ if(kv.second.empty())
+ fprintf(f, "%s\n", kv.first.c_str());
+ else
+ fprintf(f, "%s = %s\n", kv.first.c_str(), kv.second.c_str());
+ }
+ }
+ fclose(f);
+ return true;
+ }
+ return false;
+ }
+
+
+ /*
+ */
+ bool load_file(const char_type* filename)
+ {
+ return read_file(filename);
+ }
+
+ bool load_file(const StringType& filename)
+ {
+ return load_file(filename.c_str());
+ }
+
+ bool write_file(const StringType& filename)
+ {
+ return write_file(filename.c_str());
+ }
+#endif
+
+
+
+ };
+
+
+ /* Use default basic_ini
+ *
+ * Limitations:
+ * * Not unicode aware
+ * * Case sensitive
+ * * Sections must have unique keys
+ */
+ typedef basic_ini<> ini;
+}
+
+#endif
+
diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp
index 5c0dd86e..63bf0b06 100644
--- a/src/render/Hud.cpp
+++ b/src/render/Hud.cpp
@@ -997,7 +997,7 @@ void CHud::Draw()
}
else {
BigMessageAlpha[0] = 0.0f;
- BigMessageX[0] = SCALE_AND_CENTER_X(-60.0f);
+ BigMessageX[0] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f);
BigMessageInUse[0] = 1.0f;
}
}
@@ -1008,7 +1008,7 @@ void CHud::Draw()
// WastedBustedText
if (m_BigMessage[2][0]) {
if (BigMessageInUse[2] != 0.0f) {
- BigMessageAlpha[2] += (CTimer::GetTimeStepInSeconds() * 255.0f);
+ BigMessageAlpha[2] += (CTimer::GetTimeStepInMilliseconds() * 0.4f);
if (BigMessageAlpha[2] > 255.0f)
BigMessageAlpha[2] = 255.0f;
@@ -1261,7 +1261,7 @@ void CHud::DrawAfterFade()
}
break;
case 2:
- OddJob2Timer += (20.0f * CTimer::GetTimeStep());
+ OddJob2Timer += CTimer::GetTimeStepInMilliseconds();
if (OddJob2Timer > 1500) {
OddJob2On = 3;
}
@@ -1355,7 +1355,7 @@ void CHud::DrawAfterFade()
}
else {
BigMessageAlpha[1] = 0.0f;
- BigMessageX[1] = SCALE_AND_CENTER_X(-60.0f);
+ BigMessageX[1] = SCREEN_SCALE_FROM_RIGHT(DEFAULT_SCREEN_WIDTH + 60.0f);
BigMessageInUse[1] = 1.0f;
}
}
diff --git a/src/skel/crossplatform.cpp b/src/skel/crossplatform.cpp
index 6188992d..452ad9fa 100644
--- a/src/skel/crossplatform.cpp
+++ b/src/skel/crossplatform.cpp
@@ -84,6 +84,16 @@ void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) {
}
#endif
+// Because wchar length differs between platforms.
+wchar*
+AllocUnicode(const char* src)
+{
+ wchar *dst = (wchar*)malloc(strlen(src)*2 + 2);
+ wchar *i = dst;
+ while((*i++ = (unsigned char)*src++) != '\0');
+ return dst;
+}
+
// Funcs/features from Windows that we need on other platforms
#ifndef _WIN32
char *strupr(char *s) {
diff --git a/src/skel/crossplatform.h b/src/skel/crossplatform.h
index 69600385..1635781b 100644
--- a/src/skel/crossplatform.h
+++ b/src/skel/crossplatform.h
@@ -67,6 +67,10 @@ void CapturePad(RwInt32 padID);
void joysChangeCB(int jid, int event);
#endif
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+extern char gSelectedJoystickName[128];
+#endif
+
enum eGameState
{
GS_START_UP = 0,
diff --git a/src/skel/glfw/glfw.cpp b/src/skel/glfw/glfw.cpp
index b9dbf5ac..4dd9570e 100644
--- a/src/skel/glfw/glfw.cpp
+++ b/src/skel/glfw/glfw.cpp
@@ -41,7 +41,6 @@
#include "AnimViewer.h"
#include "Font.h"
-
#define MAX_SUBSYSTEMS (16)
@@ -81,12 +80,22 @@ DWORD _dwOperatingSystemVersion;
#include "resource.h"
#else
long _dwOperatingSystemVersion;
+#ifndef __APPLE__
#include <sys/sysinfo.h>
+#else
+#include <mach/mach_host.h>
+#include <sys/sysctl.h>
+#endif
#include <stddef.h>
#include <locale.h>
#include <signal.h>
#include <errno.h>
#endif
+
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+char gSelectedJoystickName[128] = "";
+#endif
+
/*
*****************************************************************************
*/
@@ -420,6 +429,10 @@ psInitialize(void)
_dwOperatingSystemVersion = OS_WIN95;
}
}
+#else
+ _dwOperatingSystemVersion = OS_WINXP; // To fool other classes
+#endif
+
#ifndef PS2_MENU
@@ -429,6 +442,8 @@ psInitialize(void)
#endif
+
+#ifdef _WIN32
MEMORYSTATUS memstats;
GlobalMemoryStatus(&memstats);
@@ -436,26 +451,28 @@ psInitialize(void)
debug("Physical memory size %u\n", memstats.dwTotalPhys);
debug("Available physical memory %u\n", memstats.dwAvailPhys);
+#elif defined (__APPLE__)
+ uint64_t size = 0;
+ uint64_t page_size = 0;
+ size_t uint64_len = sizeof(uint64_t);
+ size_t ull_len = sizeof(unsigned long long);
+ sysctl((int[]){CTL_HW, HW_PAGESIZE}, 2, &page_size, &ull_len, NULL, 0);
+ sysctl((int[]){CTL_HW, HW_MEMSIZE}, 2, &size, &uint64_len, NULL, 0);
+ vm_statistics_data_t vm_stat;
+ mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
+ host_statistics(mach_host_self(), HOST_VM_INFO, (host_info_t)&vm_stat, &count);
+ _dwMemAvailPhys = (uint64_t)(vm_stat.free_count * page_size);
+ debug("Physical memory size %llu\n", _dwMemAvailPhys);
+ debug("Available physical memory %llu\n", size);
#else
-
-#ifndef PS2_MENU
-
-#ifdef GTA3_1_1_PATCH
- FrontEndMenuManager.LoadSettings();
-#endif
-
-#endif
- struct sysinfo systemInfo;
+ struct sysinfo systemInfo;
sysinfo(&systemInfo);
-
_dwMemAvailPhys = systemInfo.freeram;
- _dwOperatingSystemVersion = OS_WINXP; // To fool other classes
-
debug("Physical memory size %u\n", systemInfo.totalram);
debug("Available physical memory %u\n", systemInfo.freeram);
-
#endif
- TheText.Unload();
+
+ TheText.Unload();
return TRUE;
}
@@ -822,35 +839,26 @@ void joysChangeCB(int jid, int event);
bool IsThisJoystickBlacklisted(int i)
{
+#ifndef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ return false;
+#else
if (glfwJoystickIsGamepad(i))
return false;
const char* joyname = glfwGetJoystickName(i);
- // this is just a keyboard and mouse
- // Microsoft Microsoft® 2.4GHz Transceiver v8.0 Consumer Control
- // Microsoft Microsoft® 2.4GHz Transceiver v8.0 System Control
- if (strstr(joyname, "2.4GHz Transceiver"))
- return true;
- // COMPANY USB Device System Control
- // COMPANY USB Device Consumer Control
- if (strstr(joyname, "COMPANY USB"))
- return true;
- // i.e. Synaptics TM2438-005
- if (strstr(joyname, "Synaptics "))
- return true;
- // i.e. ELAN Touchscreen
- if (strstr(joyname, "ELAN "))
- return true;
- // i.e. Primax Electronics, Ltd HP Wireless Keyboard Mouse Kit Consumer Control
- if (strstr(joyname, "Keyboard"))
- return true;
+ if (strncmp(joyname, gSelectedJoystickName, strlen(gSelectedJoystickName)) == 0)
+ return false;
- return false;
+ return true;
+#endif
}
void _InputInitialiseJoys()
{
+ PSGLOBAL(joy1id) = -1;
+ PSGLOBAL(joy2id) = -1;
+
for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) {
if (PSGLOBAL(joy1id) == -1)
@@ -865,6 +873,9 @@ void _InputInitialiseJoys()
if (PSGLOBAL(joy1id) != -1) {
int count;
glfwGetJoystickButtons(PSGLOBAL(joy1id), &count);
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ strcpy(gSelectedJoystickName, glfwGetJoystickName(PSGLOBAL(joy1id)));
+#endif
ControlsManager.InitDefaultControlConfigJoyPad(count);
}
}
@@ -2070,18 +2081,19 @@ void CapturePad(RwInt32 padID)
void joysChangeCB(int jid, int event)
{
- if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid))
- {
- if (PSGLOBAL(joy1id) == -1)
+ if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) {
+ if (PSGLOBAL(joy1id) == -1) {
PSGLOBAL(joy1id) = jid;
- else if (PSGLOBAL(joy2id) == -1)
+#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
+ strcpy(gSelectedJoystickName, glfwGetJoystickName(jid));
+#endif
+ } else if (PSGLOBAL(joy2id) == -1)
PSGLOBAL(joy2id) = jid;
- }
- else if (event == GLFW_DISCONNECTED)
- {
- if (PSGLOBAL(joy1id) == jid)
+
+ } else if (event == GLFW_DISCONNECTED) {
+ if (PSGLOBAL(joy1id) == jid) {
PSGLOBAL(joy1id) = -1;
- else if (PSGLOBAL(joy2id) == jid)
+ } else if (PSGLOBAL(joy2id) == jid)
PSGLOBAL(joy2id) = -1;
}
}
diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp
index 119e666e..ac46d23a 100644
--- a/src/skel/win/win.cpp
+++ b/src/skel/win/win.cpp
@@ -3378,4 +3378,4 @@ int strcasecmp(const char *str1, const char *str2)
return _strcmpi(str1, str2);
}
#endif
-#endif \ No newline at end of file
+#endif
diff --git a/src/text/Text.cpp b/src/text/Text.cpp
index 1f6cda89..a4f2af7f 100644
--- a/src/text/Text.cpp
+++ b/src/text/Text.cpp
@@ -354,4 +354,4 @@ void
TextCopy(wchar *dst, const wchar *src)
{
while((*dst++ = *src++) != '\0');
-} \ No newline at end of file
+}
diff --git a/src/vehicles/CarGen.cpp b/src/vehicles/CarGen.cpp
index 5de478b7..338eaba4 100644
--- a/src/vehicles/CarGen.cpp
+++ b/src/vehicles/CarGen.cpp
@@ -74,11 +74,12 @@ void CCarGenerator::DoInternalProcessing()
}
m_nVehicleHandle = CPools::GetVehiclePool()->GetIndex(pBoat);
}else{
- bool groundFound = false;
+ bool groundFound;
CVector pos = m_vecPos;
if (pos.z > -100.0f){
pos.z = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &groundFound);
}else{
+ groundFound = false;
CColPoint cp;
CEntity* pEntity;
groundFound = CWorld::ProcessVerticalLine(CVector(pos.x, pos.y, 1000.0f), -1000.0f,
@@ -89,7 +90,12 @@ void CCarGenerator::DoInternalProcessing()
if (!groundFound) {
debug("CCarGenerator::DoInternalProcessing - can't find ground z for new car x = %f y = %f \n", m_vecPos.x, m_vecPos.y);
}else{
- CAutomobile* pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE);
+ CAutomobile* pCar;
+
+ // So game crashes if it's bike :D
+ if (((CVehicleModelInfo*)CModelInfo::GetModelInfo(m_nModelIndex))->m_vehicleType != VEHICLE_TYPE_BIKE)
+ pCar = new CAutomobile(m_nModelIndex, PARKED_VEHICLE);
+
pCar->bIsStatic = false;
pCar->bEngineOn = false;
pos.z += pCar->GetDistanceFromCentreOfMassToBaseOfModel();