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/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 00000000..327d8cc7 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,32 @@ +{ + "configurations": [ + { + "name": "Mac", + "includePath": ["${default}"], + "defines": [], + "macFrameworkPath": [ + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks" + ], + "compilerPath": "/opt/local/bin/clang", + "compilerArgs": ["-g"], + "cStandard": "gnu11", + "cppStandard": "gnu++14", + "browse": { + "path": [ + "/opt/local/include", + "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include" + ] + } + }, + { + "name": "Linux", + "includePath": ["${default}"], + "defines": ["XDG_ROOT"], + "compilerPath": "/usr/bin/gcc", + "compilerArgs": ["-ggdb"], + "cStandard": "gnu11", + "cppStandard": "gnu++14" + } + ], + "version": 4 +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..82ce041f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,89 @@ +{ + "configurations": [ + { + "MIMode": "gdb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(gdb) Launch (Linux Debug)", + "preLaunchTask": "Compile (Debug Linux x64)", + "program": "${workspaceFolder}/bin/linux-amd64-librw_gl3_glfw-oal/Debug/re3", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + }, + { + "MIMode": "gdb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(gdb) Launch (Linux Release)", + "preLaunchTask": "Compile (Release Linux x64)", + "program": "${workspaceFolder}/bin/linux-amd64-librw_gl3_glfw-oal/Release/re3", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + }, + { + "MIMode": "lldb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(lldb) Launch (macOS Debug)", + "preLaunchTask": "Compile (Debug macOS x64)", + "program": "${workspaceFolder}/bin/macosx-amd64-librw_gl3_glfw-oal/Debug/re3.app", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for lldb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + }, + { + "MIMode": "lldb", + "args": [], + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "name": "(lldb) Launch (macOS Release)", + "preLaunchTask": "Compile (Release macOS x64)", + "program": "${workspaceFolder}/bin/macosx-amd64-librw_gl3_glfw-oal/Release/re3.app", + "request": "launch", + "setupCommands": [ + { + "description": "Enable pretty-printing for lldb", + "ignoreFailures": true, + "text": "-enable-pretty-printing" + } + ], + "stopAtEntry": false, + "targetArchitecture": "x64", + "type": "cppdbg" + } + ], + "version": "0.2.0" +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..10cb5627 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,30 @@ +{ + "C_Cpp.default.cStandard": "gnu11", + "C_Cpp.default.cppStandard": "gnu++14", + "C_Cpp.default.includePath": [ + "src/animation", + "src/audio", + "src/control", + "src/core", + "src/entities", + "src/extras", + "src/fakerw", + "src/math", + "src/modelinfo", + "src/objects", + "src/peds", + "src/render", + "src/rw", + "src/save", + "src/skel", + "src/text", + "src/vehicles", + "src/weapons", + "vendor/librw" + ], + "C_Cpp.vcFormat.indent.gotoLabels": "leftmostColumn", + "C_Cpp.vcFormat.space.pointerReferenceAlignment": "right", + "cSpell.enabled": false, + "files.trimFinalNewlines": false, + "files.trimTrailingWhitespace": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..0f610d5f --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,95 @@ +{ + "tasks": [ + { + "args": ["--with-librw", "gmake2"], + "command": "./premake5Linux", + "label": "Premake (Linux)", + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": ["--with-librw", "gmake2"], + "command": "premake5", + "label": "Premake (macOS)", + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=debug_linux-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (Linux)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Debug Linux x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=release_linux-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (Linux)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Release Linux x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=debug_macosx-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (macOS)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Debug macOS x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + }, + { + "args": [ + "-j5", + "config=release_macosx-amd64-librw_gl3_glfw-oal", + "verbose=1" + ], + "command": "make", + "dependsOn": "Premake (macOS)", + "group": { + "isDefault": true, + "kind": "build" + }, + "label": "Compile (Release macOS x64)", + "options": { + "cwd": "${workspaceFolder}/build" + }, + "problemMatcher": "$gcc", + "type": "shell" + } + ], + "version": "2.0.0" +} diff --git a/CODING_STYLE.md b/CODING_STYLE.md new file mode 100644 index 00000000..b8be02bc --- /dev/null +++ b/CODING_STYLE.md @@ -0,0 +1,107 @@ +# Coding style + +I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), +but realize that this is not the most popular style, so I'm willing to compromise. +Try not to deviate too much so the code will look similar across the whole project. + +To give examples, these two styles (or anything in between) are fine: + +``` +type +functionname(args) +{ + if(a == b){ + s1; + s2; + }else{ + s3; + s4; + } + if(x != y) + s5; +} + +type functionname(args) +{ + if (a == b) { + s1; + s2; + } else { + s3; + s4; + } + if (x != y) + s5; +} +``` + +This one (or anything more extreme) is heavily discouraged: + +``` +type functionname ( args ) +{ + if ( a == b ) + { + s1; + s2; + } + else + { + s3; + s4; + } + if ( x != y ) + { + s5; + } +} +``` + +i.e. + +* Put the brace on the same line as control statements + +* Put the brace on the next line after function definitions and structs/classes + +* Put an `else` on the same line with the braces + +* Don't put braces around single statements + +* Put the function return type on a separate line + +* Indent with TABS + +As for the less cosmetic choices, here are some guidelines how the code should look: + +* Don't use magic numbers where the original source code would have had an enum or similar. +Even if you don't know the exact meaning it's better to call something `FOOBAR_TYPE_4` than just `4`, +since `4` will be used in other places and you can't easily see where else the enum value is used. + +* Don't just copy paste code from IDA, make it look nice + +* Use the right types. In particular: + + * don't use types like `__int16`, we have `int16` for that + + * don't use `unsigned`, we have typedefs for that + + * don't use `char` for anything but actual characters, use `int8`, `uint8` or `bool` + + * don't even think about using win32 types (`BYTE`, `WORD`, &c.) unless you're writing win32 specific code + + * declare pointers like `int *ptr;`, not `int* ptr;` + +* As for variable names, the original gta source code was not written in a uniform style, +but here are some observations: + + * many variables employ a form of hungarian notation, i.e.: + + * `m_` may be used for class member variables (mostly those that are considered private) + + * `ms_` for (mostly private) static members + + * `f` is a float, `i` or `n` is an integer, `b` is a boolean, `a` is an array + + * do *not* use `dw` for `DWORD` or so, we're not programming win32 + +* Generally, try to make the code look as if R* could have written it diff --git a/README.md b/README.md index 9cb48c25..1bfe74d2 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,7 @@ such that we have a working game at all times. ## Preparing the environment for building -- Clone the repo. -- Run `git submodule init` and `git submodule update`. +- Clone the repo using the argument `--recursive`. - Point GTA_III_RE_DIR environment variable to GTA3 root folder. - Run premake - On Windows: one of the `premake-vsXXXX.cmd` variants on root folder @@ -36,6 +35,7 @@ such that we have a working game at all times. > :information_source: **Did you notice librw?** re3 uses completely homebrew RenderWare-replacement rendering engine; [librw](https://github.com/aap/librw/). librw comes as submodule of re3, but you also can use LIBRW enviorenment variable to specify path to your own librw. ## Contributing +Please read the [Coding Style](https://github.com/GTAmodding/re3/blob/master/CODING_STYLE.md) Document ### Unreversed / incomplete classes (at least the ones we know) The following classes have only unused or practically unused code left: @@ -44,110 +44,3 @@ CCullZone - only mobile stuff CCullZones - only mobile stuff ``` -### Coding style - -I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), -but realize that this is not the most popular style, so I'm willing to compromise. -Try not to deviate too much so the code will look similar across the whole project. - -To give examples, these two styles (or anything in between) are fine: - -``` -type -functionname(args) -{ - if(a == b){ - s1; - s2; - }else{ - s3; - s4; - } - if(x != y) - s5; -} - -type functionname(args) -{ - if (a == b) { - s1; - s2; - } else { - s3; - s4; - } - if (x != y) - s5; -} -``` - -This one (or anything more extreme) is heavily discouraged: - -``` -type functionname ( args ) -{ - if ( a == b ) - { - s1; - s2; - } - else - { - s3; - s4; - } - if ( x != y ) - { - s5; - } -} -``` - -i.e. - -* Put the brace on the same line as control statements - -* Put the brace on the next line after function definitions and structs/classes - -* Put an `else` on the same line with the braces - -* Don't put braces around single statements - -* Put the function return type on a separate line - -* Indent with TABS - -As for the less cosmetic choices, here are some guidelines how the code should look: - -* Don't use magic numbers where the original source code would have had an enum or similar. -Even if you don't know the exact meaning it's better to call something `FOOBAR_TYPE_4` than just `4`, -since `4` will be used in other places and you can't easily see where else the enum value is used. - -* Don't just copy paste code from IDA, make it look nice - -* Use the right types. In particular: - - * don't use types like `__int16`, we have `int16` for that - - * don't use `unsigned`, we have typedefs for that - - * don't use `char` for anything but actual characters, use `int8`, `uint8` or `bool` - - * don't even think about using win32 types (`BYTE`, `WORD`, &c.) unless you're writing win32 specific code - - * declare pointers like `int *ptr;`, not `int* ptr;` - -* As for variable names, the original gta source code was not written in a uniform style, -but here are some observations: - - * many variables employ a form of hungarian notation, i.e.: - - * `m_` may be used for class member variables (mostly those that are considered private) - - * `ms_` for (mostly private) static members - - * `f` is a float, `i` or `n` is an integer, `b` is a boolean, `a` is an array - - * do *not* use `dw` for `DWORD` or so, we're not programming win32 - -* Generally, try to make the code look as if R* could have written it diff --git a/premake5.lua b/premake5.lua index b61a9c4c..334c9c53 100644 --- a/premake5.lua +++ b/premake5.lua @@ -84,6 +84,12 @@ workspace "reVC" platforms { "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 "reVC" filter { "platforms:bsd*" } system "bsd" + + filter { "platforms:macosx*" } + system "macosx" filter { "platforms:*x86*" } architecture "x86" @@ -109,6 +118,13 @@ workspace "reVC" 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" } @@ -162,6 +178,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:*RW34*" flags { "ExcludeFromBuild" } @@ -277,6 +300,11 @@ project "reVC" 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 {} @@ -330,3 +358,11 @@ project "reVC" 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/DMAudio.cpp b/src/audio/DMAudio.cpp index 486daebf..a4db2862 100644 --- a/src/audio/DMAudio.cpp +++ b/src/audio/DMAudio.cpp @@ -5,6 +5,7 @@ #include "AudioManager.h" #include "AudioScriptObject.h" #include "sampman.h" +#include "Font.h" #include "Text.h" #include "crossplatform.h" diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index 74c4f006..93098d6d 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -3075,7 +3075,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/control/Darkel.cpp b/src/control/Darkel.cpp index 75d27e26..1191e8ad 100644 --- a/src/control/Darkel.cpp +++ b/src/control/Darkel.cpp @@ -14,6 +14,9 @@ #include "Text.h" #include "Vehicle.h" #include "GameLogic.h" +#ifdef FIX_BUGS +#include "Replay.h" +#endif #define FRENZY_ANY_PED -1 #define FRENZY_ANY_CAR -2 @@ -62,6 +65,10 @@ CDarkel::CalcFade(uint32 time, uint32 start, uint32 end) void CDarkel::DrawMessages() { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif switch (Status) { case KILLFRENZY_ONGOING: { @@ -167,6 +174,10 @@ CDarkel::ReadStatus() void CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif if (FrenzyOnGoing()) { int32 model = vehicle->GetModelIndex(); if (ModelToKill == FRENZY_ANY_CAR || ModelToKill == model || ModelToKill2 == model || ModelToKill3 == model || ModelToKill4 == model) { @@ -181,6 +192,10 @@ CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) void CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot) { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif if (FrenzyOnGoing() && (weapon == WeaponType || weapon == WEAPONTYPE_EXPLOSION || weapon == WEAPONTYPE_UZI_DRIVEBY && WeaponType == WEAPONTYPE_UZI @@ -206,6 +221,10 @@ CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot) void CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype) { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif CStats::PeopleKilledByOthers++; } @@ -299,6 +318,11 @@ CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 mode void CDarkel::Update() { +#ifdef FIX_BUGS + if (CReplay::IsPlayingBack()) + return; +#endif + if (Status != KILLFRENZY_ONGOING) return; diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 290bacad..dc07d142 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1462,7 +1462,7 @@ void CGarage::UpdateCrusherShake(float X, float Y) } // This is dumb but there is no way to avoid goto. What was there originally even? -static bool DoINeedToRefreshPointer(CEntity * pDoor, bool bIsDummy, int8 nIndex) +static bool DoINeedToRefreshPointer(CEntity * pDoor, bool bIsDummy, uint8 nIndex) { bool bNeedToFindDoorEntities = false; if (pDoor) { diff --git a/src/control/OnscreenTimer.cpp b/src/control/OnscreenTimer.cpp index d94e993e..52d00f43 100644 --- a/src/control/OnscreenTimer.cpp +++ b/src/control/OnscreenTimer.cpp @@ -7,29 +7,38 @@ #include "Timer.h" #include "Script.h" #include "OnscreenTimer.h" +#include "Camera.h" + +// --MIAMI: file done void COnscreenTimer::Init() { m_bDisabled = false; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - m_sEntries[i].m_nTimerOffset = 0; - m_sEntries[i].m_nCounterOffset = 0; + for(uint32 i = 0; i < NUMONSCREENCOUNTERS; i++) { + m_sCounters[i].m_nCounterOffset = 0; - for(uint32 j = 0; j < 10; j++) { - m_sEntries[i].m_aTimerText[j] = 0; - m_sEntries[i].m_aCounterText[j] = 0; + for(uint32 j = 0; j < ARRAY_SIZE(COnscreenCounterEntry::m_aCounterText); j++) { + m_sCounters[i].m_aCounterText[j] = 0; } - m_sEntries[i].m_nType = COUNTER_DISPLAY_NUMBER; - m_sEntries[i].m_bTimerProcessed = false; - m_sEntries[i].m_bCounterProcessed = false; - m_sEntries[i].m_bTimerGoingDown = true; + m_sCounters[i].m_nType = COUNTER_DISPLAY_NUMBER; + m_sCounters[i].m_bCounterProcessed = false; + } + for(uint32 i = 0; i < NUMONSCREENCLOCKS; i++) { + m_sClocks[i].m_nClockOffset = 0; + + for(uint32 j = 0; j < ARRAY_SIZE(COnscreenTimerEntry::m_aClockText); j++) { + m_sClocks[i].m_aClockText[j] = 0; + } + + m_sClocks[i].m_bClockProcessed = false; + m_sClocks[i].m_bClockGoingDown = true; } } void COnscreenTimer::Process() { if(!CReplay::IsPlayingBack() && !m_bDisabled) { - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - m_sEntries[i].Process(); + for(uint32 i = 0; i < NUMONSCREENCLOCKS; i++) { + m_sClocks[i].Process(); } } } @@ -37,8 +46,19 @@ void COnscreenTimer::Process() { void COnscreenTimer::ProcessForDisplay() { if(CHud::m_Wants_To_Draw_Hud) { m_bProcessed = false; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(m_sEntries[i].ProcessForDisplay()) { + for(uint32 i = 0; i < NUMONSCREENCLOCKS; i++) { + m_sClocks[i].m_bClockProcessed = false; + if (m_sClocks[i].m_nClockOffset != 0) { + m_sClocks[i].ProcessForDisplayClock(); + m_sClocks[i].m_bClockProcessed = true; + m_bProcessed = true; + } + } + for(uint32 i = 0; i < NUMONSCREENCOUNTERS; i++) { + m_sCounters[i].m_bCounterProcessed = false; + if (m_sCounters[i].m_nCounterOffset != 0) { + m_sCounters[i].ProcessForDisplayCounter(); + m_sCounters[i].m_bCounterProcessed = true; m_bProcessed = true; } } @@ -46,77 +66,81 @@ void COnscreenTimer::ProcessForDisplay() { } void COnscreenTimer::ClearCounter(uint32 offset) { - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(offset == m_sEntries[i].m_nCounterOffset) { - m_sEntries[i].m_nCounterOffset = 0; - m_sEntries[i].m_aCounterText[0] = 0; - m_sEntries[i].m_nType = COUNTER_DISPLAY_NUMBER; - m_sEntries[i].m_bCounterProcessed = 0; + for(uint32 i = 0; i < NUMONSCREENCOUNTERS; i++) { + if(offset == m_sCounters[i].m_nCounterOffset) { + m_sCounters[i].m_nCounterOffset = 0; + m_sCounters[i].m_aCounterText[0] = 0; + m_sCounters[i].m_nType = COUNTER_DISPLAY_NUMBER; + m_sCounters[i].m_bCounterProcessed = 0; } } } void COnscreenTimer::ClearClock(uint32 offset) { - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(offset == m_sEntries[i].m_nTimerOffset) { - m_sEntries[i].m_nTimerOffset = 0; - m_sEntries[i].m_aTimerText[0] = 0; - m_sEntries[i].m_bTimerProcessed = 0; + for(uint32 i = 0; i < NUMONSCREENCLOCKS; i++) { + if(offset == m_sClocks[i].m_nClockOffset) { + m_sClocks[i].m_nClockOffset = 0; + m_sClocks[i].m_aClockText[0] = 0; + m_sClocks[i].m_bClockProcessed = 0; + m_sClocks[i].m_bClockGoingDown = true; } } } void COnscreenTimer::AddCounter(uint32 offset, uint16 type, char* text, uint16 pos) { - m_sEntries[pos].m_nCounterOffset = offset; - if (m_sEntries[pos].m_aCounterText[0] != '\0') + if (m_sCounters[pos].m_aCounterText[0] != '\0') return; + + m_sCounters[pos].m_nCounterOffset = offset; if(text) { - strncpy(m_sEntries[pos].m_aCounterText, text, 10); + strncpy(m_sCounters[pos].m_aCounterText, text, ARRAY_SIZE(COnscreenCounterEntry::m_aCounterText)); } else { - m_sEntries[pos].m_aCounterText[0] = 0; + m_sCounters[pos].m_aCounterText[0] = 0; } - m_sEntries[pos].m_nType = type; + m_sCounters[pos].m_nType = type; } void COnscreenTimer::AddClock(uint32 offset, char* text, bool bGoingDown) { - uint32 i = 0; - for(uint32 i = 0; i < NUMONSCREENTIMERENTRIES; i++) { - if(m_sEntries[i].m_nTimerOffset == 0) { + + // dead code in here + uint32 i; + for(i = 0; i < NUMONSCREENCLOCKS; i++) { + if(m_sClocks[i].m_nClockOffset == 0) { break; } return; } - m_sEntries[i].m_nTimerOffset = offset; - m_sEntries[i].m_bTimerGoingDown = bGoingDown; + m_sClocks[i].m_nClockOffset = offset; + m_sClocks[i].m_bClockGoingDown = bGoingDown; if(text) { - strncpy(m_sEntries[i].m_aTimerText, text, 10); + strncpy(m_sClocks[i].m_aClockText, text, ARRAY_SIZE(COnscreenTimerEntry::m_aClockText)); } else { - m_sEntries[i].m_aTimerText[0] = 0; + m_sClocks[i].m_aClockText[0] = 0; } } void COnscreenTimerEntry::Process() { - if(m_nTimerOffset == 0) { + if(m_nClockOffset == 0) { return; } - int32* timerPtr = CTheScripts::GetPointerToScriptVariable(m_nTimerOffset); + int32* timerPtr = CTheScripts::GetPointerToScriptVariable(m_nClockOffset); int32 oldTime = *timerPtr; - if (m_bTimerGoingDown) { + if (m_bClockGoingDown) { int32 newTime = oldTime - int32(CTimer::GetTimeStepInMilliseconds()); + *timerPtr = newTime; if (newTime < 0) { *timerPtr = 0; - m_bTimerProcessed = 0; - m_nTimerOffset = 0; - m_aTimerText[0] = 0; + m_bClockProcessed = 0; + m_nClockOffset = 0; + m_aClockText[0] = 0; } else { - *timerPtr = newTime; int32 oldTimeSeconds = oldTime / 1000; - if (oldTimeSeconds < 12 && newTime / 1000 != oldTimeSeconds) { + if (oldTimeSeconds < 12 && newTime / 1000 != oldTimeSeconds && !TheCamera.m_WideScreenOn) { DMAudio.PlayFrontEndSound(SOUND_CLOCK_TICK, newTime / 1000); } } @@ -125,33 +149,13 @@ void COnscreenTimerEntry::Process() { *timerPtr = oldTime + int32(CTimer::GetTimeStepInMilliseconds()); } -bool COnscreenTimerEntry::ProcessForDisplay() { - m_bTimerProcessed = false; - m_bCounterProcessed = false; - - if(m_nTimerOffset == 0 && m_nCounterOffset == 0) { - return false; - } - - if(m_nTimerOffset != 0) { - m_bTimerProcessed = true; - ProcessForDisplayClock(); - } - - if(m_nCounterOffset != 0) { - m_bCounterProcessed = true; - ProcessForDisplayCounter(); - } - return true; -} - void COnscreenTimerEntry::ProcessForDisplayClock() { - uint32 time = *CTheScripts::GetPointerToScriptVariable(m_nTimerOffset); - sprintf(m_bTimerBuffer, "%02d:%02d", time / 1000 / 60, + uint32 time = *CTheScripts::GetPointerToScriptVariable(m_nClockOffset); + sprintf(m_aClockBuffer, "%02d:%02d", time / 1000 / 60 % 100, time / 1000 % 60); } -void COnscreenTimerEntry::ProcessForDisplayCounter() { +void COnscreenCounterEntry::ProcessForDisplayCounter() { uint32 counter = *CTheScripts::GetPointerToScriptVariable(m_nCounterOffset); - sprintf(m_bCounterBuffer, "%d", counter); + sprintf(m_aCounterBuffer, "%d", counter); } diff --git a/src/control/OnscreenTimer.h b/src/control/OnscreenTimer.h index 09473397..8c049d7d 100644 --- a/src/control/OnscreenTimer.h +++ b/src/control/OnscreenTimer.h @@ -9,30 +9,37 @@ enum class COnscreenTimerEntry { public: - uint32 m_nTimerOffset; - uint32 m_nCounterOffset; - char m_aTimerText[10]; - char m_aCounterText[10]; - uint16 m_nType; - char m_bCounterBuffer[42]; - char m_bTimerBuffer[42]; - bool m_bTimerProcessed; - bool m_bTimerGoingDown; - bool m_bCounterProcessed; + uint32 m_nClockOffset; + char m_aClockText[10]; + char m_aClockBuffer[40]; + bool m_bClockProcessed; + bool m_bClockGoingDown; void Process(); - bool ProcessForDisplay(); - void ProcessForDisplayClock(); +}; + +VALIDATE_SIZE(COnscreenTimerEntry, 0x3C); + +class COnscreenCounterEntry +{ +public: + uint32 m_nCounterOffset; + char m_aCounterText[10]; + uint16 m_nType; + char m_aCounterBuffer[40]; + bool m_bCounterProcessed; + void ProcessForDisplayCounter(); }; -VALIDATE_SIZE(COnscreenTimerEntry, 0x74); +VALIDATE_SIZE(COnscreenCounterEntry, 0x3C); class COnscreenTimer { public: - COnscreenTimerEntry m_sEntries[NUMONSCREENTIMERENTRIES]; + COnscreenTimerEntry m_sClocks[NUMONSCREENCLOCKS]; + COnscreenCounterEntry m_sCounters[NUMONSCREENCOUNTERS]; bool m_bProcessed; bool m_bDisabled; @@ -47,4 +54,4 @@ public: void AddClock(uint32 offset, char* text, bool bGoingDown); }; -VALIDATE_SIZE(COnscreenTimer, 0x78); +VALIDATE_SIZE(COnscreenTimer, 0xF4); diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 796e4cab..034cfe4d 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -51,6 +51,7 @@ #include "Camera.h" #include "Radar.h" #include "Fluff.h" +#include "WaterCreatures.h" uint8 CReplay::Mode; CAddressInReplayBuffer CReplay::Record; @@ -1300,7 +1301,7 @@ void CReplay::TriggerPlayback(uint8 cam_mode, float cam_x, float cam_y, float ca DMAudio.SetEffectsFadeVol(0); DMAudio.SetMusicFadeVol(0); CEscalators::Shutdown(); - // TODO(MIAMI): CWaterCreatures::RemoveAll(); + CWaterCreatures::RemoveAll(); int current; for (current = 0; current < NUM_REPLAYBUFFERS; current++) if (BufferStatus[current] == REPLAYBUFFER_RECORD) diff --git a/src/core/CdStreamPosix.cpp b/src/core/CdStreamPosix.cpp index e114a29a..a6ab62bc 100644 --- a/src/core/CdStreamPosix.cpp +++ b/src/core/CdStreamPosix.cpp @@ -34,11 +34,11 @@ struct CdReadInfo bool bReading; int32 nStatus; #ifdef ONE_THREAD_PER_CHANNEL - int8 nThreadStatus; // 0: created 1:initalized 2:abort now - pthread_t pChannelThread; - sem_t pStartSemaphore; + int8 nThreadStatus; // 0: created 1:priority set up 2:abort now + pthread_t pChannelThread; + sem_t *pStartSemaphore; #endif - sem_t pDoneSemaphore; // used for CdStreamSync + sem_t *pDoneSemaphore; // used for CdStreamSync int32 hFile; }; @@ -51,8 +51,8 @@ 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) -int8 gCdStreamThreadStatus; // 0: created 1:initalized 2:abort now +sem_t *gCdStreamSema; // released when we have new thing to read(so channel is set) +int8 gCdStreamThreadStatus; // 0: created 1:priority set up 2:abort now Queue gChannelRequestQ; bool _gbCdStreamOverlapped; #endif @@ -69,49 +69,50 @@ void CdStreamInitThread(void) { int status; - + char semName[20]; #ifndef ONE_THREAD_PER_CHANNEL gChannelRequestQ.items = (int32 *)calloc(gNumChannels + 1, sizeof(int32)); gChannelRequestQ.head = 0; gChannelRequestQ.tail = 0; gChannelRequestQ.size = gNumChannels + 1; ASSERT(gChannelRequestQ.items != nil ); - status = sem_init(&gCdStreamSema, 0, 0); -#endif + gCdStreamSema = sem_open("/semaphore_cd_stream", O_CREAT, 0644, 1); - if (status == -1) { + if (gCdStreamSema == SEM_FAILED) { CDTRACE("failed to create stream semaphore"); ASSERT(0); return; } - +#endif if ( gNumChannels > 0 ) { for ( int32 i = 0; i < gNumChannels; i++ ) { - status = sem_init(&gpReadInfo[i].pDoneSemaphore, 0, 0); + sprintf(semName,"/semaphore_done%d",i); + gpReadInfo[i].pDoneSemaphore = sem_open(semName, 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); + sprintf(semName,"/semaphore_start%d",i); + gpReadInfo[i].pStartSemaphore = sem_open(semName, O_CREAT, 0644, 1); - if (status == -1) + if (gpReadInfo[i].pStartSemaphore == SEM_FAILED) { CDTRACE("failed to create start semaphore"); ASSERT(0); return; } - gpReadInfo[i].nThreadStatus = 0; + gpReadInfo[i].nThreadStatus = 0; int *channelI = (int*)malloc(sizeof(int)); *channelI = i; - status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI); + status = pthread_create(&gpReadInfo[i].pChannelThread, NULL, CdStreamThread, (void*)channelI); if (status == -1) { @@ -124,32 +125,32 @@ CdStreamInitThread(void) } #ifndef ONE_THREAD_PER_CHANNEL - debug("Using one streaming thread for all channels\n"); - status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil); - gCdStreamThreadStatus = 0; + debug("Using one streaming thread for all channels\n"); + gCdStreamThreadStatus = 0; + status = pthread_create(&_gCdStreamThread, NULL, CdStreamThread, nil); - if (status == -1) - { - CDTRACE("failed to create sync thread"); - ASSERT(0); - return; - } + if (status == -1) + { + CDTRACE("failed to create sync thread"); + ASSERT(0); + return; + } #else - debug("Using seperate streaming threads for each channel\n"); + debug("Using separate streaming threads for each channel\n"); #endif } void CdStreamInit(int32 numChannels) { - struct statvfs fsInfo; + struct statvfs fsInfo; - if((statvfs("models/gta3.img", &fsInfo)) < 0) - { - CDTRACE("can't get filesystem info"); - ASSERT(0); - return; - } + if((statvfs("models/gta3.img", &fsInfo)) < 0) + { + CDTRACE("can't get filesystem info"); + ASSERT(0); + return; + } #ifdef __linux__ _gdwCdStreamFlags = O_RDONLY | O_NOATIME; #else @@ -163,7 +164,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; @@ -185,27 +186,27 @@ uint32 GetGTA3ImgSize(void) { ASSERT( gImgFiles[0] > 0 ); - struct stat statbuf; + struct stat statbuf; - char path[PATH_MAX]; - realpath(gImgNames[0], path); - if (stat(path, &statbuf) == -1) { + char path[PATH_MAX]; + realpath(gImgNames[0], path); + if (stat(path, &statbuf) == -1) { // Try case-insensitivity char* real = casepath(gImgNames[0], false); if (real) { realpath(real, path); free(real); - if (stat(path, &statbuf) != -1) + if (stat(path, &statbuf) != -1) goto ok; } - CDTRACE("can't get size of gta3.img"); - ASSERT(0); - return 0; - } -ok: - return statbuf.st_size; + CDTRACE("can't get size of gta3.img"); + ASSERT(0); + return 0; + } + ok: + return (uint32)statbuf.st_size; } void @@ -213,15 +214,13 @@ CdStreamShutdown(void) { // Destroying semaphores and free(gpReadInfo) will be done at threads #ifndef ONE_THREAD_PER_CHANNEL - gCdStreamThreadStatus = 2; - sem_post(&gCdStreamSema); -#endif - -#ifdef ONE_THREAD_PER_CHANNEL - for ( int32 i = 0; i < gNumChannels; i++ ) { - gpReadInfo[i].nThreadStatus = 2; - sem_post(&gpReadInfo[i].pStartSemaphore); - } + gCdStreamThreadStatus = 2; + sem_post(gCdStreamSema); +#else + for ( int32 i = 0; i < gNumChannels; i++ ) { + gpReadInfo[i].nThreadStatus = 2; + sem_post(gpReadInfo[i].pStartSemaphore); + } #endif } @@ -241,27 +240,33 @@ CdStreamRead(int32 channel, void *buffer, uint32 offset, uint32 size) CdReadInfo *pChannel = &gpReadInfo[channel]; ASSERT( pChannel != nil ); + + if ( pChannel->nSectorsToRead != 0 || pChannel->bReading ) { + if (pChannel->nSectorOffset == _GET_OFFSET(offset) && pChannel->nSectorsToRead >= size) + return STREAM_SUCCESS; + + flushStream[channel] = 1; + CdStreamSync(channel); + //return STREAM_NONE; + } + pChannel->hFile = hImage - 1; - - if ( pChannel->nSectorsToRead != 0 || pChannel->bReading ) - return STREAM_NONE; - - pChannel->nStatus = STREAM_NONE; - pChannel->nSectorOffset = _GET_OFFSET(offset); - pChannel->nSectorsToRead = size; - pChannel->pBuffer = buffer; - pChannel->bLocked = 0; + pChannel->nStatus = STREAM_NONE; + pChannel->nSectorOffset = _GET_OFFSET(offset); + pChannel->nSectorsToRead = size; + pChannel->pBuffer = buffer; + pChannel->bLocked = 0; #ifndef ONE_THREAD_PER_CHANNEL - AddToQueue(&gChannelRequestQ, channel); - if ( sem_post(&gCdStreamSema) != 0 ) - printf("Signal Sema Error\n"); + AddToQueue(&gChannelRequestQ, channel); + if ( sem_post(gCdStreamSema) != 0 ) + printf("Signal Sema Error\n"); #else - if ( sem_post(&gpReadInfo[channel].pStartSemaphore) != 0 ) - printf("Signal Sema Error\n"); + if ( sem_post(pChannel->pStartSemaphore) != 0 ) + printf("Signal Sema Error\n"); #endif - return STREAM_SUCCESS; + return STREAM_SUCCESS; } int32 @@ -272,29 +277,29 @@ CdStreamGetStatus(int32 channel) ASSERT( pChannel != nil ); #ifdef ONE_THREAD_PER_CHANNEL - if (pChannel->nThreadStatus == 2) - return STREAM_NONE; + if (pChannel->nThreadStatus == 2) + return STREAM_NONE; #else - if (gCdStreamThreadStatus == 2) - return STREAM_NONE; + if (gCdStreamThreadStatus == 2) + return STREAM_NONE; #endif - if ( pChannel->bReading ) - return STREAM_READING; + if ( pChannel->bReading ) + return STREAM_READING; - if ( pChannel->nSectorsToRead != 0 ) - return STREAM_WAITING; + if ( pChannel->nSectorsToRead != 0 ) + return STREAM_WAITING; - if ( pChannel->nStatus != STREAM_NONE ) - { - int32 status = pChannel->nStatus; + if ( pChannel->nStatus != STREAM_NONE ) + { + int32 status = pChannel->nStatus; - pChannel->nStatus = STREAM_NONE; + pChannel->nStatus = STREAM_NONE; - return status; - } + return status; + } - return STREAM_NONE; + return STREAM_NONE; } int32 @@ -314,30 +319,35 @@ CdStreamSync(int32 channel) if (flushStream[channel]) { #ifdef ONE_THREAD_PER_CHANNEL pChannel->nSectorsToRead = 0; - pthread_kill(gpReadInfo[channel].pChannelThread, SIGINT); -#else + pthread_kill(pChannel->pChannelThread, SIGUSR1); if (pChannel->bReading) { - pChannel->nSectorsToRead = 0; - pthread_kill(_gCdStreamThread, SIGINT); - } else { - pChannel->nSectorsToRead = 0; + pChannel->bLocked = true; + sem_wait(pChannel->pDoneSemaphore); + } +#else + pChannel->nSectorsToRead = 0; + if (pChannel->bReading) { + pChannel->bLocked = true; + pthread_kill(_gCdStreamThread, SIGUSR1); + sem_wait(pChannel->pDoneSemaphore); + } #endif pChannel->bReading = false; flushStream[channel] = false; - return STREAM_NONE; + return STREAM_NONE; } - if ( pChannel->nSectorsToRead != 0 ) - { - pChannel->bLocked = true; + if ( pChannel->nSectorsToRead != 0 ) + { + pChannel->bLocked = true; - sem_wait(&pChannel->pDoneSemaphore); - } + sem_wait(pChannel->pDoneSemaphore); + } - pChannel->bReading = false; + pChannel->bReading = false; - return pChannel->nStatus; + return pChannel->nStatus; } void @@ -382,53 +392,52 @@ void *CdStreamThread(void *param) debug("Created cdstream thread\n"); #ifndef ONE_THREAD_PER_CHANNEL - while (gCdStreamThreadStatus != 2) { - sem_wait(&gCdStreamSema); - int32 channel = GetFirstInQueue(&gChannelRequestQ); + while (gCdStreamThreadStatus != 2) { + sem_wait(gCdStreamSema); + int32 channel = GetFirstInQueue(&gChannelRequestQ); #else - int channel = *((int*)param); - while (gpReadInfo[channel].nThreadStatus != 2){ - sem_wait(&gpReadInfo[channel].pStartSemaphore); + int channel = *((int*)param); + while (gpReadInfo[channel].nThreadStatus != 2){ + sem_wait(gpReadInfo[channel].pStartSemaphore); #endif - ASSERT( channel < gNumChannels ); CdReadInfo *pChannel = &gpReadInfo[channel]; ASSERT( pChannel != nil ); -#ifdef ONE_THREAD_PER_CHANNEL - if (gpReadInfo[channel].nThreadStatus == 0){ - gpReadInfo[channel].nThreadStatus = 1; -#else - if (gCdStreamThreadStatus == 0){ - gCdStreamThreadStatus = 1; -#endif - -#ifdef __linux__ - pid_t tid = syscall(SYS_gettid); - int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1); -#endif - } - // spurious wakeup or we sent interrupt signal for flushing if(pChannel->nSectorsToRead == 0) - continue; + continue; pChannel->bReading = true; + // Not standard POSIX :shrug: +#ifdef __linux__ +#ifdef ONE_THREAD_PER_CHANNEL + if (gpReadInfo[channel].nThreadStatus == 0){ + gpReadInfo[channel].nThreadStatus = 1; +#else + if (gCdStreamThreadStatus == 0){ + gCdStreamThreadStatus = 1; +#endif + pid_t tid = syscall(SYS_gettid); + int ret = setpriority(PRIO_PROCESS, tid, getpriority(PRIO_PROCESS, getpid()) + 1); + } +#endif if ( pChannel->nStatus == STREAM_NONE ) { - ASSERT(pChannel->hFile >= 0); - ASSERT(pChannel->pBuffer != nil ); + ASSERT(pChannel->hFile >= 0); + ASSERT(pChannel->pBuffer != nil ); lseek(pChannel->hFile, pChannel->nSectorOffset * CDSTREAM_SECTOR_SIZE, SEEK_SET); - if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) { + if (read(pChannel->hFile, pChannel->pBuffer, pChannel->nSectorsToRead * CDSTREAM_SECTOR_SIZE) == -1) { // pChannel->nSectorsToRead == 0 at this point means we wanted to flush channel - pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_NONE : STREAM_ERROR; - } else { - pChannel->nStatus = STREAM_NONE; - } + // STREAM_WAITING is a little hack to make CStreaming not process this data + pChannel->nStatus = pChannel->nSectorsToRead == 0 ? STREAM_WAITING : STREAM_ERROR; + } else { + pChannel->nStatus = STREAM_NONE; + } } - + #ifndef ONE_THREAD_PER_CHANNEL RemoveFirstInQueue(&gChannelRequestQ); #endif @@ -437,22 +446,33 @@ void *CdStreamThread(void *param) if ( pChannel->bLocked ) { - sem_post(&pChannel->pDoneSemaphore); + sem_post(pChannel->pDoneSemaphore); } pChannel->bReading = false; } + char semName[20]; #ifndef ONE_THREAD_PER_CHANNEL - for ( int32 i = 0; i < gNumChannels; i++ ) - { - sem_destroy(&gpReadInfo[i].pDoneSemaphore); - } - sem_destroy(&gCdStreamSema); + for ( int32 i = 0; i < gNumChannels; i++ ) + { + sem_close(gpReadInfo[i].pDoneSemaphore); + sprintf(semName,"/semaphore_done%d",i); + sem_unlink(semName); + } + 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); + sprintf(semName,"/semaphore_start%d",channel); + sem_unlink(semName); + + sem_close(gpReadInfo[channel].pDoneSemaphore); + sprintf(semName,"/semaphore_done%d",channel); + sem_unlink(semName); #endif - free(gpReadInfo); + if (gpReadInfo) + free(gpReadInfo); + gpReadInfo = nil; pthread_exit(nil); } @@ -469,7 +489,7 @@ CdStreamAddImage(char const *path) char* real = casepath(path, false); if (real) { - gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags); + gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags); free(real); } } @@ -502,8 +522,10 @@ CdStreamGetImageName(int32 cd) void CdStreamRemoveImages(void) { - for ( int32 i = 0; i < gNumChannels; i++ ) + for ( int32 i = 0; i < gNumChannels; i++ ) { + flushStream[i] = 1; CdStreamSync(i); + } for ( int32 i = 0; i < gNumImages; i++ ) { diff --git a/src/core/FileLoader.cpp b/src/core/FileLoader.cpp index 635192ea..da678fd3 100644 --- a/src/core/FileLoader.cpp +++ b/src/core/FileLoader.cpp @@ -1052,7 +1052,11 @@ CFileLoader::Load2dEffect(const char *line) &effect->attractor.dir.z, &probability); effect->attractor.type = flags; +#ifdef FIX_BUGS + effect->attractor.probability = clamp(probability, 0, 255); +#else effect->attractor.probability = probability; +#endif break; case EFFECT_PED_ATTRACTOR: sscanf(line, "%d %f %f %f %d %d %d %d %d %d %f %f %f %f %f %f", diff --git a/src/core/FileMgr.cpp b/src/core/FileMgr.cpp index 4477a190..d3695cb4 100644 --- a/src/core/FileMgr.cpp +++ b/src/core/FileMgr.cpp @@ -142,17 +142,17 @@ static size_t myfread(void *buf, size_t elt, size_t n, int fd) { if(myfiles[fd].isText){ - char *p; + unsigned char *p; size_t i; int c; n *= elt; - p = (char*)buf; + p = (unsigned char*)buf; for(i = 0; i < n; i++){ c = myfgetc(fd); if(c == EOF) break; - *p++ = c; + *p++ = (unsigned char)c; } return i / elt; } @@ -163,12 +163,12 @@ static size_t myfwrite(void *buf, size_t elt, size_t n, int fd) { if(myfiles[fd].isText){ - char *p; + unsigned char *p; size_t i; int c; n *= elt; - p = (char*)buf; + p = (unsigned char*)buf; for(i = 0; i < n; i++){ c = *p++; myfputc(c, fd); diff --git a/src/core/Fire.cpp b/src/core/Fire.cpp index a6928def..5b57cb73 100644 --- a/src/core/Fire.cpp +++ b/src/core/Fire.cpp @@ -16,6 +16,9 @@ #include "Ped.h" #include "Fire.h" #include "GameLogic.h" +#include "CarAI.h" + +// --MIAMI: file done CFireManager gFireManager; @@ -26,14 +29,13 @@ CFire::CFire() m_bPropagationFlag = true; m_bAudioSet = true; m_vecPos = CVector(0.0f, 0.0f, 0.0f); - m_pEntity = nil; - m_pSource = nil; - m_nFiremenPuttingOut = 0; m_nExtinguishTime = 0; m_nStartTime = 0; - field_20 = 1; - m_nNextTimeToAddFlames = 0; + m_pEntity = nil; + m_pSource = nil; m_fStrength = 0.8f; + m_fWaterExtinguishCountdown = 1.0f; + m_bExtinguishedWithWater = false; } CFire::~CFire() {} @@ -52,6 +54,8 @@ CFire::ProcessFire(void) CPed *ped = (CPed *)m_pEntity; CVehicle *veh = (CVehicle*)m_pEntity; + m_fWaterExtinguishCountdown = Min(1.0f, 0.002f * CTimer::GetTimeStep() + m_fWaterExtinguishCountdown); + if (m_pEntity) { m_vecPos = m_pEntity->GetPosition(); @@ -109,7 +113,7 @@ CFire::ProcessFire(void) gFireManager.StartFire(FindPlayerPed(), m_pSource, 0.8f, 1); } if (CTimer::GetTimeInMilliseconds() > m_nNextTimeToAddFlames) { - m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + 80; + m_nNextTimeToAddFlames = CTimer::GetTimeInMilliseconds() + (m_fWaterExtinguishCountdown < 0.3f ? 400 : (m_fWaterExtinguishCountdown < 0.7f ? 200 : 80)); firePos = m_vecPos; if (veh && veh->IsVehicle() && veh->IsCar()) { @@ -170,11 +174,23 @@ CFire::Extinguish(void) m_nExtinguishTime = 0; m_bIsOngoing = false; + m_bExtinguishedWithWater = false; if (m_pEntity) { if (m_pEntity->IsPed()) { - ((CPed *)m_pEntity)->RestorePreviousState(); - ((CPed *)m_pEntity)->m_pFire = nil; + CPed *ped = (CPed*)m_pEntity; + if (ped->CanSetPedState()) { + if (ped->m_nPedState != PED_DRIVING && ped->m_nPedState != PED_FALL) { + if (ped->IsPlayer()) { + ped->SetIdle(); + } else { + ped->m_nLastPedState = PED_NONE; + ped->SetWanderPath(0); + ped->SetWaitState(WAITSTATE_FINISH_FLEE, 0); + } + } + } + ped->m_pFire = nil; } else if (m_pEntity->IsVehicle()) { ((CVehicle *)m_pEntity)->m_pCarFire = nil; } @@ -184,7 +200,7 @@ CFire::Extinguish(void) } void -CFireManager::StartFire(CVector pos, float size, bool propagation) +CFireManager::StartFire(CVector pos, float size, uint8 propagation) { CFire *fire = GetNextFreeFire(); @@ -201,11 +217,12 @@ CFireManager::StartFire(CVector pos, float size, bool propagation) fire->m_nNextTimeToAddFlames = 0; fire->ReportThisFire(); fire->m_fStrength = size; + fire->m_bExtinguishedWithWater = false; } } CFire * -CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation) +CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, uint8 propagation) { CPed *ped = (CPed *)entityOnFire; CVehicle *veh = (CVehicle *)entityOnFire; @@ -234,10 +251,11 @@ CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength ped->SetFlee(pos, 10000); ped->m_fleeFrom = nil; } + ped->m_fleeTimer = CTimer::GetTimeInMilliseconds() + 10000; ped->bDrawLast = false; ped->SetMoveState(PEDMOVE_SPRINT); ped->SetMoveAnim(); - ped->m_nPedState = PED_ON_FIRE; + ped->SetPedState(PED_ON_FIRE); } if (fleeFrom) { if (ped->m_nPedType == PEDTYPE_COP) { @@ -251,6 +269,9 @@ CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength } else { if (entityOnFire->IsVehicle()) { veh->m_pCarFire = fire; + if (CModelInfo::IsBikeModel(veh->GetModelIndex()) || CModelInfo::IsCarModel(veh->GetModelIndex())) + CCarAI::TellOccupantsToFleeCar(veh); + if (fleeFrom) { CEventList::RegisterEvent(EVENT_CAR_SET_ON_FIRE, EVENT_ENTITY_VEHICLE, entityOnFire, (CPed *)fleeFrom, 10000); @@ -259,6 +280,7 @@ CFireManager::StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength } fire->m_bIsOngoing = true; + fire->m_bExtinguishedWithWater = false; fire->m_bIsScriptFire = false; fire->m_vecPos = entityOnFire->GetPosition(); @@ -297,26 +319,23 @@ CFireManager::Update(void) CFire* CFireManager::FindNearestFire(CVector vecPos, float *pDistance) { - for (int i = 0; i < MAX_FIREMEN_ATTENDING; i++) { - int fireId = -1; - float minDistance = 999999; - for (int j = 0; j < NUM_FIRES; j++) { - if (!m_aFires[j].m_bIsOngoing) - continue; - if (m_aFires[j].m_bIsScriptFire) - continue; - if (m_aFires[j].m_nFiremenPuttingOut != i) - continue; - float distance = (m_aFires[j].m_vecPos - vecPos).Magnitude2D(); - if (distance < minDistance) { - minDistance = distance; - fireId = j; - } + int fireId = -1; + float minDistance = 999999; + for (int j = 0; j < NUM_FIRES; j++) { + if (!m_aFires[j].m_bIsOngoing) + continue; + if (m_aFires[j].m_bIsScriptFire) + continue; + float distance = (m_aFires[j].m_vecPos - vecPos).Magnitude2D(); + if (distance < minDistance) { + minDistance = distance; + fireId = j; } - *pDistance = minDistance; - if (fireId != -1) - return &m_aFires[fireId]; } + *pDistance = minDistance; + if (fireId != -1) + return &m_aFires[fireId]; + return nil; } @@ -369,8 +388,39 @@ CFireManager::ExtinguishPoint(CVector point, float range) } } +bool +CFireManager::ExtinguishPointWithWater(CVector point, float range) +{ + int fireI = 0; + for (int i = 0; i < NUM_FIRES; i++) { + if (m_aFires[i].m_bIsOngoing) { + if ((point - m_aFires[i].m_vecPos).MagnitudeSqr() < sq(range)) { + fireI = i; + break; + } + } + } + if (fireI == NUM_FIRES) + return false; + + CFire *fireToExtinguish = &m_aFires[fireI]; + fireToExtinguish->m_fWaterExtinguishCountdown -= 0.012f * CTimer::GetTimeStep(); + CVector steamPos = fireToExtinguish->m_vecPos + + CVector((CGeneral::GetRandomNumber() - 128) * 31.f / 200.f, + (CGeneral::GetRandomNumber() - 128) * 31.f / 200.f, + CGeneral::GetRandomNumber() / 200.f); + + CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, steamPos, CVector(0.f, 0.f, 0.2f), nil, 0.5f); + CParticle::AddParticle(PARTICLE_STEAM_NY_SLOWMOTION, steamPos, CVector(0.f, 0.f, 0.1f), nil, 0.8f); + fireToExtinguish->m_bExtinguishedWithWater = true; + if (fireToExtinguish->m_fWaterExtinguishCountdown < 0.0f ) + fireToExtinguish->Extinguish(); + + return true; +} + int32 -CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation) +CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strength, uint8 propagation) { CFire *fire; CPed *ped = (CPed *)target; @@ -397,12 +447,15 @@ CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strengt fire->m_vecPos = pos; fire->m_nStartTime = CTimer::GetTimeInMilliseconds() + 400; fire->m_pEntity = target; + fire->m_bExtinguishedWithWater = false; if (target) target->RegisterReference(&fire->m_pEntity); fire->m_pSource = nil; fire->m_nNextTimeToAddFlames = 0; fire->m_fStrength = strength; + fire->m_fWaterExtinguishCountdown = 1.0f; + if (target) { if (target->IsPed()) { ped->m_pFire = fire; @@ -410,7 +463,7 @@ CFireManager::StartScriptFire(const CVector &pos, CEntity *target, float strengt CVector2D pos = target->GetPosition(); ped->SetFlee(pos, 10000); ped->SetMoveAnim(); - ped->m_nPedState = PED_ON_FIRE; + ped->SetPedState(PED_ON_FIRE); } } else if (target->IsVehicle()) { veh->m_pCarFire = fire; @@ -430,8 +483,7 @@ CFireManager::RemoveAllScriptFires(void) { for (int i = 0; i < NUM_FIRES; i++) { if (m_aFires[i].m_bIsScriptFire) { - m_aFires[i].Extinguish(); - m_aFires[i].m_bIsScriptFire = false; + RemoveScriptFire(i); } } } diff --git a/src/core/Fire.h b/src/core/Fire.h index 85e53f61..8126f830 100644 --- a/src/core/Fire.h +++ b/src/core/Fire.h @@ -14,10 +14,10 @@ public: CEntity *m_pSource; uint32 m_nExtinguishTime; uint32 m_nStartTime; - int32 field_20; uint32 m_nNextTimeToAddFlames; - uint32 m_nFiremenPuttingOut; float m_fStrength; + float m_fWaterExtinguishCountdown; + bool m_bExtinguishedWithWater; CFire(); ~CFire(); @@ -34,15 +34,17 @@ class CFireManager public: uint32 m_nTotalFires; CFire m_aFires[NUM_FIRES]; - void StartFire(CVector pos, float size, bool propagation); - CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, bool propagation); + + void StartFire(CVector pos, float size, uint8 propagation); + CFire *StartFire(CEntity *entityOnFire, CEntity *fleeFrom, float strength, uint8 propagation); void Update(void); CFire *FindFurthestFire_NeverMindFireMen(CVector coords, float minRange, float maxRange); CFire *FindNearestFire(CVector vecPos, float *pDistance); CFire *GetNextFreeFire(void); uint32 GetTotalActiveFires() const; void ExtinguishPoint(CVector point, float range); - int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, bool propagation); + bool ExtinguishPointWithWater(CVector point, float range); + int32 StartScriptFire(const CVector &pos, CEntity *target, float strength, uint8 propagation); bool IsScriptFireExtinguish(int16 index); void RemoveAllScriptFires(void); void RemoveScriptFire(int16 index); diff --git a/src/core/Game.cpp b/src/core/Game.cpp index 6ba6b191..a8637980 100644 --- a/src/core/Game.cpp +++ b/src/core/Game.cpp @@ -90,6 +90,7 @@ #include "debugmenu.h" #include "Ropes.h" #include "WindModifiers.h" +#include "WaterCreatures.h" #include "postfx.h" #include "custompipes.h" @@ -478,8 +479,7 @@ bool CGame::ShutDown(void) CPlane::Shutdown(); CTrain::Shutdown(); CScriptPaths::Shutdown(); - // TODO(Miami) - // CWaterCreatures::RemoveAll(); + CWaterCreatures::RemoveAll(); CSpecialFX::Shutdown(); #ifndef PS2 CGarages::Shutdown(); @@ -650,7 +650,7 @@ void CGame::ShutDownForRestart(void) CRadar::RemoveRadarSections(); FrontEndMenuManager.UnloadTextures(); CParticleObject::RemoveAllExpireableParticleObjects(); - //CWaterCreatures::RemoveAll(); //TODO(Miami) + CWaterCreatures::RemoveAll(); CSetPieces::Init(); CPedType::Shutdown(); CSpecialFX::Shutdown(); diff --git a/src/core/General.h b/src/core/General.h index 7ab444a4..7e06b96e 100644 --- a/src/core/General.h +++ b/src/core/General.h @@ -2,6 +2,8 @@ #include +// --MIAMI: file done + class CGeneral { public: diff --git a/src/core/Pad.cpp b/src/core/Pad.cpp index aa6e5cc8..b723eb1d 100644 --- a/src/core/Pad.cpp +++ b/src/core/Pad.cpp @@ -3209,7 +3209,7 @@ int16 CPad::SniperModeLookLeftRight(void) if ( Abs(axis) > Abs(dpad) ) { if ( Abs(axis) > 35.0f ) { - return (axis > 0.f ? axis - 35.f : axis + 35.f) * 1.3763441f; + return (axis > 0.f ? axis - 35.f : axis + 35.f) * (128.f / (128 - 35)); } else { return 0; } @@ -3231,7 +3231,7 @@ int16 CPad::SniperModeLookUpDown(void) if ( Abs(axis) > Abs(dpad) ) { if ( Abs(axis) > 35.0f ) { - return (axis > 0.f ? axis - 35.f : axis + 35.f) * 1.3763441f; + return (axis > 0.f ? axis - 35.f : axis + 35.f) * (128.f / (128 - 35)); } else { return 0; } @@ -3573,4 +3573,4 @@ void CPad::FixPadsAfterSave(void) bObsoleteControllerMessage = false; GetPad(0)->Phase = 0; } -} \ No newline at end of file +} diff --git a/src/core/Streaming.cpp b/src/core/Streaming.cpp index d296496e..ddde4664 100644 --- a/src/core/Streaming.cpp +++ b/src/core/Streaming.cpp @@ -46,7 +46,11 @@ CStreamingInfo CStreaming::ms_endRequestedList; int32 CStreaming::ms_oldSectorX; int32 CStreaming::ms_oldSectorY; int32 CStreaming::ms_streamingBufferSize; +#ifndef ONE_THREAD_PER_CHANNEL int8 *CStreaming::ms_pStreamingBuffer[2]; +#else +int8 *CStreaming::ms_pStreamingBuffer[4]; +#endif size_t CStreaming::ms_memoryUsed; CStreamingChannel CStreaming::ms_channel[2]; int32 CStreaming::ms_channelError; @@ -197,6 +201,10 @@ CStreaming::Init2(void) ms_pStreamingBuffer[0] = (int8*)RwMallocAlign(ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE); ms_streamingBufferSize /= 2; ms_pStreamingBuffer[1] = ms_pStreamingBuffer[0] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE; +#ifdef ONE_THREAD_PER_CHANNEL + ms_pStreamingBuffer[2] = (int8*)RwMallocAlign(ms_streamingBufferSize*2*CDSTREAM_SECTOR_SIZE, CDSTREAM_SECTOR_SIZE); + ms_pStreamingBuffer[3] = ms_pStreamingBuffer[2] + ms_streamingBufferSize*CDSTREAM_SECTOR_SIZE; +#endif debug("Streaming buffer size is %d sectors", ms_streamingBufferSize); // PC only, figure out how much memory we got @@ -2196,6 +2204,110 @@ CStreaming::LoadRequestedModels(void) } } + +// Let's load models first, then process it. Unfortunately processing models are still single-threaded. +// Currently only supported on POSIX streamer. +#ifdef ONE_THREAD_PER_CHANNEL +void +CStreaming::LoadAllRequestedModels(bool priority) +{ + static bool bInsideLoadAll = false; + int imgOffset, streamId, status; + int i; + uint32 posn, size; + + if(bInsideLoadAll) + return; + bInsideLoadAll = true; + + FlushChannels(); + imgOffset = GetCdImageOffset(CdStreamGetLastPosn()); + + int streamIds[ARRAY_SIZE(ms_pStreamingBuffer)]; + int streamSizes[ARRAY_SIZE(ms_pStreamingBuffer)]; + int streamPoses[ARRAY_SIZE(ms_pStreamingBuffer)]; + bool first = true; + int processI = 0; + + while (true) { + // Enumerate files and start reading + for (int i=0; i (uint32)ms_streamingBufferSize) { + if (i + 1 == ARRAY_SIZE(ms_pStreamingBuffer)) + continue; + else if (!first && streamIds[i+1] != -1) + continue; + } else { + if (i != 0 && streamIds[i-1] != -1 && streamSizes[i-1] > (uint32)ms_streamingBufferSize) + continue; + } + ms_aInfoForModel[streamId].RemoveFromList(); + DecrementRef(streamId); + + streamIds[i] = streamId; + streamSizes[i] = size; + streamPoses[i] = posn; + CdStreamRead(i, ms_pStreamingBuffer[i], imgOffset+posn, size); + processI = i; + } else { + ms_aInfoForModel[streamId].RemoveFromList(); + DecrementRef(streamId); + + ms_aInfoForModel[streamId].m_loadState = STREAMSTATE_LOADED; + streamIds[i] = -1; + } + } else + streamIds[i] = -1; + } + + first = false; + + // Now process + if (streamIds[processI] == -1) + break; + + // Try again on error + while (CdStreamSync(processI) != STREAM_NONE) { + CdStreamRead(processI, ms_pStreamingBuffer[processI], imgOffset+streamPoses[processI], streamSizes[processI]); + } + ms_aInfoForModel[streamIds[processI]].m_loadState = STREAMSTATE_READING; + + MakeSpaceFor(streamSizes[processI] * CDSTREAM_SECTOR_SIZE); + ConvertBufferToObject(ms_pStreamingBuffer[processI], streamIds[processI]); + if(ms_aInfoForModel[streamIds[processI]].m_loadState == STREAMSTATE_STARTED) + FinishLoadingLargeFile(ms_pStreamingBuffer[processI], streamIds[processI]); + + if(streamIds[processI] < STREAM_OFFSET_TXD){ + CSimpleModelInfo *mi = (CSimpleModelInfo*)CModelInfo::GetModelInfo(streamIds[processI]); + if(mi->IsSimple()) + mi->m_alpha = 255; + } + streamIds[processI] = -1; + } + + ms_bLoadingBigModel = false; + for(i = 0; i < 4; i++){ + ms_channel[1].streamIds[i] = -1; + ms_channel[1].offsets[i] = -1; + } + ms_channel[1].state = CHANNELSTATE_IDLE; + bInsideLoadAll = false; +} +#else void CStreaming::LoadAllRequestedModels(bool priority) { @@ -2256,6 +2368,7 @@ CStreaming::LoadAllRequestedModels(bool priority) ms_channel[1].state = CHANNELSTATE_IDLE; bInsideLoadAll = false; } +#endif void CStreaming::FlushChannels(void) @@ -2287,6 +2400,14 @@ CStreaming::FlushRequestList(void) next = si->m_next; RemoveModel(si - ms_aInfoForModel); } +#ifndef _WIN32 + if(ms_channel[0].state == CHANNELSTATE_READING) { + flushStream[0] = 1; + } + if(ms_channel[1].state == CHANNELSTATE_READING) { + flushStream[1] = 1; + } +#endif FlushChannels(); } @@ -2815,10 +2936,15 @@ CStreaming::DeleteRwObjectsNotInFrustumInSectorList(CPtrList &list, size_t mem) void CStreaming::MakeSpaceFor(int32 size) { - // BUG: ms_memoryAvailable can be uninitialized - // the code still happens to work in that case because ms_memoryAvailable is unsigned - // but it's not nice.... - +#ifdef FIX_BUGS +#define MB (1024 * 1024) + if(ms_memoryAvailable == 0) { + extern size_t _dwMemAvailPhys; + ms_memoryAvailable = (_dwMemAvailPhys - 10 * MB) / 2; + if(ms_memoryAvailable < 65 * MB) ms_memoryAvailable = 65 * MB; + } +#undef MB +#endif while(ms_memoryUsed >= ms_memoryAvailable - size) if(!RemoveLeastUsedModel(STREAMFLAGS_20)){ DeleteRwObjectsBehindCamera(ms_memoryAvailable - size); diff --git a/src/core/User.cpp b/src/core/User.cpp index 53196d03..8d584b74 100644 --- a/src/core/User.cpp +++ b/src/core/User.cpp @@ -10,6 +10,8 @@ #include "World.h" #include "Zones.h" +// --MIAMI: file done + CPlaceName CUserDisplay::PlaceName; COnscreenTimer CUserDisplay::OnscnTimer; CPager CUserDisplay::Pager; diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp index 1eb1513e..288b975e 100644 --- a/src/core/Zones.cpp +++ b/src/core/Zones.cpp @@ -9,7 +9,7 @@ #include "World.h" #include "Timer.h" -//--MIAMI: file almost done (loading/saving will perhaps stay different) +//--MIAMI: file done eLevelName CTheZones::m_CurrLevel; int16 CTheZones::FindIndex; @@ -638,127 +638,132 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) + sizeof(int16) // padding + sizeof(NavigationZoneArray) + sizeof(InfoZoneArray) + sizeof(ZoneInfoArray) + sizeof(TotalNumberOfNavigationZones) + sizeof(TotalNumberOfInfoZones) + sizeof(TotalNumberOfZoneInfos) + + sizeof(int16) // padding + sizeof(MapZoneArray) + sizeof(AudioZoneArray) + sizeof(TotalNumberOfMapZones) + sizeof(NumberOfAudioZones); - WriteSaveHeader(buffer, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE); + uint32 length = 0; + WriteSaveHeaderWithLength(buffer, length, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE); - WriteSaveBuf(buffer, m_CurrLevel); - WriteSaveBuf(buffer, FindIndex); - WriteSaveBuf(buffer, (int16)0); // padding + WriteSaveBuf(buffer, length, m_CurrLevel); + WriteSaveBuf(buffer, length, FindIndex); + WriteSaveBuf(buffer, length, (int16)0); // padding -// TODO(MIAMI) ? implement SaveOneZone - for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++){ - CZone *zone = WriteSaveBuf(buffer, NavigationZoneArray[i]); - zone->child = (CZone*)GetIndexForZonePointer(NavigationZoneArray[i].child); - zone->parent = (CZone*)GetIndexForZonePointer(NavigationZoneArray[i].parent); - zone->next = (CZone*)GetIndexForZonePointer(NavigationZoneArray[i].next); - } + for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++) + SaveOneZone(&NavigationZoneArray[i], &buffer, &length, ZONE_NAVIG); - for(i = 0; i < ARRAY_SIZE(InfoZoneArray); i++){ - CZone *zone = WriteSaveBuf(buffer, InfoZoneArray[i]); - /* - The call of GetIndexForZonePointer is wrong, as it is - meant for a different array, but the game doesn't brake - if those fields are nil. Let's make sure they are. - */ - assert(InfoZoneArray[i].child == nil); - assert(InfoZoneArray[i].parent == nil); - assert(InfoZoneArray[i].next == nil); - zone->child = (CZone*)GetIndexForZonePointer(InfoZoneArray[i].child); - zone->parent = (CZone*)GetIndexForZonePointer(InfoZoneArray[i].parent); - zone->next = (CZone*)GetIndexForZonePointer(InfoZoneArray[i].next); - } + for(i = 0; i < ARRAY_SIZE(InfoZoneArray); i++) + SaveOneZone(&InfoZoneArray[i], &buffer, &length, ZONE_INFO); for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++) - WriteSaveBuf(buffer, ZoneInfoArray[i]); + WriteSaveBuf(buffer, length, ZoneInfoArray[i]); - WriteSaveBuf(buffer, TotalNumberOfNavigationZones); - WriteSaveBuf(buffer, TotalNumberOfInfoZones); - WriteSaveBuf(buffer, TotalNumberOfZoneInfos); + WriteSaveBuf(buffer, length, TotalNumberOfNavigationZones); + WriteSaveBuf(buffer, length, TotalNumberOfInfoZones); + WriteSaveBuf(buffer, length, TotalNumberOfZoneInfos); + WriteSaveBuf(buffer, length, (int16)0); // padding - for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++) { - CZone* zone = WriteSaveBuf(buffer, MapZoneArray[i]); - - // see above - assert(MapZoneArray[i].child == nil); - assert(MapZoneArray[i].parent == nil); - assert(MapZoneArray[i].next == nil); - zone->child = (CZone*)GetIndexForZonePointer(MapZoneArray[i].child); - zone->parent = (CZone*)GetIndexForZonePointer(MapZoneArray[i].parent); - zone->next = (CZone*)GetIndexForZonePointer(MapZoneArray[i].next); - } + for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++) + SaveOneZone(&MapZoneArray[i], &buffer, &length, ZONE_MAPZONE); for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++) - WriteSaveBuf(buffer, AudioZoneArray[i]); + WriteSaveBuf(buffer, length, AudioZoneArray[i]); - WriteSaveBuf(buffer, TotalNumberOfMapZones); - WriteSaveBuf(buffer, NumberOfAudioZones); + WriteSaveBuf(buffer, length, TotalNumberOfMapZones); + WriteSaveBuf(buffer, length, NumberOfAudioZones); VALIDATESAVEBUF(*size) } +void +CTheZones::SaveOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType) +{ + WriteSaveBuf(*buffer, *length, *(uint32*)&zone->name[0]); + WriteSaveBuf(*buffer, *length, *(uint32*)&zone->name[4]); + + WriteSaveBuf(*buffer, *length, zone->minx); + WriteSaveBuf(*buffer, *length, zone->miny); + WriteSaveBuf(*buffer, *length, zone->minz); + WriteSaveBuf(*buffer, *length, zone->maxx); + WriteSaveBuf(*buffer, *length, zone->maxy); + WriteSaveBuf(*buffer, *length, zone->maxz); + + WriteSaveBuf(*buffer, *length, zone->type); + WriteSaveBuf(*buffer, *length, zone->level); + WriteSaveBuf(*buffer, *length, zone->zoneinfoDay); + WriteSaveBuf(*buffer, *length, zone->zoneinfoNight); + + int32 zoneId; + zoneId = GetIndexForZonePointer(zone->child); + WriteSaveBuf(*buffer, *length, zoneId); + zoneId = GetIndexForZonePointer(zone->parent); + WriteSaveBuf(*buffer, *length, zoneId); + zoneId = GetIndexForZonePointer(zone->next); + WriteSaveBuf(*buffer, *length, zoneId); +} + void CTheZones::LoadAllZones(uint8 *buffer, uint32 size) { INITSAVEBUF int i; - CheckSaveHeader(buffer, 'Z', 'N', 'S', '\0', size - SAVE_HEADER_SIZE); + uint32 length = 0; + CheckSaveHeaderWithLength(buffer, length, 'Z', 'N', 'S', '\0', size - SAVE_HEADER_SIZE); - m_CurrLevel = ReadSaveBuf(buffer); - FindIndex = ReadSaveBuf(buffer); - ReadSaveBuf(buffer); + m_CurrLevel = ReadSaveBuf(buffer, length); + FindIndex = ReadSaveBuf(buffer, length); + ReadSaveBuf(buffer, length); -// TODO(MIAMI) ? implement LoadOneZone - for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++){ - NavigationZoneArray[i] = ReadSaveBuf(buffer); + for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++) + LoadOneZone(&NavigationZoneArray[i], &buffer, &length, ZONE_NAVIG); - NavigationZoneArray[i].child = GetPointerForZoneIndex((uintptr)NavigationZoneArray[i].child); - NavigationZoneArray[i].parent = GetPointerForZoneIndex((uintptr)NavigationZoneArray[i].parent); - NavigationZoneArray[i].next = GetPointerForZoneIndex((uintptr)NavigationZoneArray[i].next); - } - - for(i = 0; i < ARRAY_SIZE(InfoZoneArray); i++){ - InfoZoneArray[i] = ReadSaveBuf(buffer); - - /* - The call of GetPointerForZoneIndex is wrong, as it is - meant for a different array, but the game doesn't brake - if save data stored is -1. - */ - InfoZoneArray[i].child = GetPointerForZoneIndex((uintptr)InfoZoneArray[i].child); - InfoZoneArray[i].parent = GetPointerForZoneIndex((uintptr)InfoZoneArray[i].parent); - InfoZoneArray[i].next = GetPointerForZoneIndex((uintptr)InfoZoneArray[i].next); - assert(InfoZoneArray[i].child == nil); - assert(InfoZoneArray[i].parent == nil); - assert(InfoZoneArray[i].next == nil); - } + for (i = 0; i < ARRAY_SIZE(InfoZoneArray); i++) + LoadOneZone(&InfoZoneArray[i], &buffer, &length, ZONE_INFO); for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++) - ZoneInfoArray[i] = ReadSaveBuf(buffer); + ZoneInfoArray[i] = ReadSaveBuf(buffer, length); - TotalNumberOfNavigationZones = ReadSaveBuf(buffer); - TotalNumberOfInfoZones = ReadSaveBuf(buffer); - TotalNumberOfZoneInfos = ReadSaveBuf(buffer); + TotalNumberOfNavigationZones = ReadSaveBuf(buffer, length); + TotalNumberOfInfoZones = ReadSaveBuf(buffer, length); + TotalNumberOfZoneInfos = ReadSaveBuf(buffer, length); + ReadSaveBuf(buffer, length); - for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++){ - MapZoneArray[i] = ReadSaveBuf(buffer); - - // see above - MapZoneArray[i].child = GetPointerForZoneIndex((uintptr)MapZoneArray[i].child); - MapZoneArray[i].parent = GetPointerForZoneIndex((uintptr)MapZoneArray[i].parent); - MapZoneArray[i].next = GetPointerForZoneIndex((uintptr)MapZoneArray[i].next); - assert(MapZoneArray[i].child == nil); - assert(MapZoneArray[i].parent == nil); - assert(MapZoneArray[i].next == nil); - } + for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++) + LoadOneZone(&MapZoneArray[i], &buffer, &length, ZONE_MAPZONE); for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++) - AudioZoneArray[i] = ReadSaveBuf(buffer); + AudioZoneArray[i] = ReadSaveBuf(buffer, length); - TotalNumberOfMapZones = ReadSaveBuf(buffer); - NumberOfAudioZones = ReadSaveBuf(buffer); + TotalNumberOfMapZones = ReadSaveBuf(buffer, length); + NumberOfAudioZones = ReadSaveBuf(buffer, length); VALIDATESAVEBUF(size) } + +void +CTheZones::LoadOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType) +{ + *(uint32*)&zone->name[0] = ReadSaveBuf(*buffer, *length); + *(uint32*)&zone->name[4] = ReadSaveBuf(*buffer, *length); + + zone->minx = ReadSaveBuf(*buffer, *length); + zone->miny = ReadSaveBuf(*buffer, *length); + zone->minz = ReadSaveBuf(*buffer, *length); + zone->maxx = ReadSaveBuf(*buffer, *length); + zone->maxy = ReadSaveBuf(*buffer, *length); + zone->maxz = ReadSaveBuf(*buffer, *length); + + zone->type = ReadSaveBuf(*buffer, *length); + zone->level = ReadSaveBuf(*buffer, *length); + zone->zoneinfoDay = ReadSaveBuf(*buffer, *length); + zone->zoneinfoNight = ReadSaveBuf(*buffer, *length); + + int32 zoneId; + zoneId = ReadSaveBuf(*buffer, *length); + zone->child = GetPointerForZoneIndex(zoneId); + zoneId = ReadSaveBuf(*buffer, *length); + zone->parent = GetPointerForZoneIndex(zoneId); + zoneId = ReadSaveBuf(*buffer, *length); + zone->next = GetPointerForZoneIndex(zoneId); +} \ No newline at end of file diff --git a/src/core/Zones.h b/src/core/Zones.h index 92e292b8..3a74427d 100644 --- a/src/core/Zones.h +++ b/src/core/Zones.h @@ -108,5 +108,7 @@ public: static void AddZoneToAudioZoneArray(CZone *zone); static void InitialiseAudioZoneArray(void); static void SaveAllZones(uint8 *buffer, uint32 *length); + static void SaveOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType); static void LoadAllZones(uint8 *buffer, uint32 length); + static void LoadOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType); }; diff --git a/src/core/common.h b/src/core/common.h index 16d32b32..0e6bd60f 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -106,7 +106,7 @@ typedef uint16_t wchar; inline uint32 dpb(uint32 b, uint32 p, uint32 s, uint32 w) { uint32 m = MASK(p,s); - return w & ~m | b<

inline const T ReadSaveBuf(uint8 *&buf) { @@ -420,6 +429,14 @@ inline const T ReadSaveBuf(uint8 *&buf) return value; } +template +inline const T ReadSaveBuf(uint8 *&buf, uint32 &length) +{ + T &value = *(T*)buf; + SkipSaveBuf(buf, length, sizeof(T)); + return value; +} + template inline T *WriteSaveBuf(uint8 *&buf, const T &value) { @@ -429,6 +446,15 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value) return p; } +template +inline T *WriteSaveBuf(uint8 *&buf, uint32 &length, const T &value) +{ + T *p = (T*)buf; + *p = value; + SkipSaveBuf(buf, length, sizeof(T)); + return p; +} + #define SAVE_HEADER_SIZE (4*sizeof(char)+sizeof(uint32)) @@ -439,6 +465,13 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value) WriteSaveBuf(buf, d);\ WriteSaveBuf(buf, size); +#define WriteSaveHeaderWithLength(buf,len,a,b,c,d,size) \ + WriteSaveBuf(buf, len, a);\ + WriteSaveBuf(buf, len, b);\ + WriteSaveBuf(buf, len, c);\ + WriteSaveBuf(buf, len, d);\ + WriteSaveBuf(buf, len, size); + #define CheckSaveHeader(buf,a,b,c,d,size)\ assert(ReadSaveBuf(buf) == a);\ assert(ReadSaveBuf(buf) == b);\ @@ -446,5 +479,12 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value) assert(ReadSaveBuf(buf) == d);\ assert(ReadSaveBuf(buf) == size); +#define CheckSaveHeaderWithLength(buf,len,a,b,c,d,size)\ + assert(ReadSaveBuf(buf,len) == a);\ + assert(ReadSaveBuf(buf,len) == b);\ + assert(ReadSaveBuf(buf,len) == c);\ + assert(ReadSaveBuf(buf,len) == d);\ + assert(ReadSaveBuf(buf,len) == size); + void cprintf(char*, ...); \ No newline at end of file diff --git a/src/core/config.h b/src/core/config.h index 475a63f8..3f077f4c 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -87,7 +87,8 @@ enum Config { NUMMBLURSTREAKS = 4, NUMSKIDMARKS = 32, - NUMONSCREENTIMERENTRIES = 1, + NUMONSCREENCLOCKS = 1, + NUMONSCREENCOUNTERS = 3, NUMRADARBLIPS = 75, NUMGENERALPICKUPS = 320, NUMSCRIPTEDPICKUPS = 16, @@ -137,6 +138,7 @@ enum Config { NUM_CRANES = 8, NUM_ESCALATORS = 22, + NUM_WATER_CREATURES = 8, NUM_EXPLOSIONS = 48, @@ -248,6 +250,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 RESTORE_ALLCARSHELI_CHEAT @@ -257,7 +262,6 @@ enum Config { //#define BIND_VEHICLE_FIREWEAPON // Adds ability to rebind fire key for 'in vehicle' controls // Hud, frontend and radar -#define HUD_ENHANCEMENTS // Adjusts some aspects to make the HUD look/behave a little bit better. //#define BETA_SLIDING_TEXT #define TRIANGULAR_BLIPS // height indicating triangular radar blips, as in VC #define PC_MENU @@ -323,4 +327,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/entities/Dummy.cpp b/src/entities/Dummy.cpp index 92b69761..544e24a6 100644 --- a/src/entities/Dummy.cpp +++ b/src/entities/Dummy.cpp @@ -4,6 +4,8 @@ #include "World.h" #include "Dummy.h" +// --MIAMI: file done + void *CDummy::operator new(size_t sz) { return CPools::GetDummyPool()->New(); } void CDummy::operator delete(void *p, size_t sz) { CPools::GetDummyPool()->Delete((CDummy*)p); } diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index cf1dd9e7..2285c93f 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -1207,4 +1207,37 @@ bool CEntity::IsEntityOccluded(void) { } return false; +} + +/* +0x487A10 - SetAtomicAlphaCB +0x4879E0 - SetClumpAlphaCB +*/ + +RpMaterial* SetAtomicAlphaCB(RpMaterial *material, void *data) { + ((RwRGBA*)RpMaterialGetColor(material))->alpha = (uint8)(uintptr)data; + return material; +} + +RpAtomic* SetClumpAlphaCB(RpAtomic *atomic, void *data) { + RpGeometry *geometry = RpAtomicGetGeometry(atomic); + RpGeometrySetFlags(geometry, RpGeometryGetFlags(geometry) | rpGEOMETRYMODULATEMATERIALCOLOR); + RpGeometryForAllMaterials(geometry, SetAtomicAlphaCB, (void*)data); + return atomic; +} + +void CEntity::SetRwObjectAlpha(int32 alpha) { + if (m_rwObject != nil) { + switch (RwObjectGetType(m_rwObject)) { + case rpATOMIC: { + RpGeometry *geometry = RpAtomicGetGeometry((RpAtomic*)m_rwObject); + RpGeometrySetFlags(geometry, RpGeometryGetFlags(geometry) | rpGEOMETRYMODULATEMATERIALCOLOR); + RpGeometryForAllMaterials(geometry, SetAtomicAlphaCB, (void*)alpha); + break; + } + case rpCLUMP: + RpClumpForAllAtomics((RpClump*)m_rwObject, SetClumpAlphaCB, (void*)alpha); + break; + } + } } \ No newline at end of file diff --git a/src/entities/Entity.h b/src/entities/Entity.h index fd01b6f8..fbf5cb3b 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -179,6 +179,7 @@ public: void ModifyMatrixForTreeInWind(void); void ModifyMatrixForBannerInWind(void); void ProcessLightsForEntity(void); + void SetRwObjectAlpha(int32 alpha); static void AddSteamsFromGround(CPtrList& list); }; 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 + * + * 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 // for std::string +#include // for std::map +#include // for std::FILE +#include // for std::find_if +#include // 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, + class KeyContainer = std::map, + class SectionContainer = std::map + > 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(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(::isspace)))); + if(trimRight) + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::function(::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/objects/DummyObject.cpp b/src/objects/DummyObject.cpp index 8dd1643d..8656abbb 100644 --- a/src/objects/DummyObject.cpp +++ b/src/objects/DummyObject.cpp @@ -3,6 +3,8 @@ #include "DummyObject.h" #include "Pools.h" +// --MIAMI: file done + CDummyObject::CDummyObject(CObject *obj) { SetModelIndexNoCreate(obj->GetModelIndex()); diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp index daa48d98..9a9eaa73 100644 --- a/src/objects/Object.cpp +++ b/src/objects/Object.cpp @@ -36,6 +36,7 @@ CObject::CObject(void) m_colour2 = 0; m_colour1 = m_colour2; m_nBonusValue = 0; + // m_nCostValue = 0; // TODO(Miami) bIsPickup = false; bPickupObjWithMessage = false; bOutOfStock = false; @@ -44,8 +45,12 @@ CObject::CObject(void) bHasBeenDamaged = false; m_nRefModelIndex = -1; bUseVehicleColours = false; +// bIsStreetLight = false; // duplicate m_pCurSurface = nil; m_pCollidingEntity = nil; + m_nBeachballBounces = 0; + bIsStreetLight = false; + m_area = AREA_EVERYWHERE; } CObject::CObject(int32 mi, bool createRW) @@ -138,12 +143,16 @@ CObject::Render(void) bool CObject::SetupLighting(void) { - DeActivateDirectional(); - SetAmbientColours(); - if(bRenderScorched){ WorldReplaceNormalLightsWithScorched(Scene.world, 0.1f); return true; + } else if (bIsPickup) { + SetFullAmbient(); + return true; + } else if (bIsWeapon) { + ActivateDirectional(); + SetAmbientColoursForPedsCarsAndObjects(); + return true; } return false; } @@ -151,8 +160,10 @@ CObject::SetupLighting(void) void CObject::RemoveLighting(bool reset) { - if(reset) - WorldReplaceScorchedLightsWithNormal(Scene.world); + if(reset) { + SetAmbientColours(); + DeActivateDirectional(); + } } void @@ -363,6 +374,8 @@ CObject::CanBeDeleted(void) return true; case CUTSCENE_OBJECT: return false; + case CONTROLLED_SUB_OBJECT: + return false; default: return true; } diff --git a/src/objects/Object.h b/src/objects/Object.h index 5f0ec0ab..b81e84b6 100644 --- a/src/objects/Object.h +++ b/src/objects/Object.h @@ -8,7 +8,7 @@ enum { MISSION_OBJECT = 2, TEMP_OBJECT = 3, CUTSCENE_OBJECT = 4, - ESCALATOR_OBJECT = 5, + CONTROLLED_SUB_OBJECT = 5, }; enum CollisionSpecialResponseCase diff --git a/src/objects/Projectile.cpp b/src/objects/Projectile.cpp index fe8b0c68..fc4b25cf 100644 --- a/src/objects/Projectile.cpp +++ b/src/objects/Projectile.cpp @@ -2,6 +2,8 @@ #include "Projectile.h" +// --MIAMI: file done + CProjectile::CProjectile(int32 model) : CObject() { m_fMass = 1.0f; diff --git a/src/objects/Stinger.cpp b/src/objects/Stinger.cpp index f33125ee..b3660881 100644 --- a/src/objects/Stinger.cpp +++ b/src/objects/Stinger.cpp @@ -23,7 +23,7 @@ CStingerSegment::CStingerSegment() m_fBuoyancy = GRAVITY * m_fMass * 0.1f; bExplosionProof = true; SetModelIndex(MI_PLC_STINGER); - ObjectCreatedBy = ESCALATOR_OBJECT; + ObjectCreatedBy = CONTROLLED_SUB_OBJECT; NumOfStingerSegments++; } diff --git a/src/peds/EmergencyPed.cpp b/src/peds/EmergencyPed.cpp index a33e31f9..5b91daad 100644 --- a/src/peds/EmergencyPed.cpp +++ b/src/peds/EmergencyPed.cpp @@ -104,7 +104,6 @@ CEmergencyPed::FiremanAI(void) m_pAttendedFire = nearestFire; #ifdef FIX_BUGS bIsRunning = true; - ++nearestFire->m_nFiremenPuttingOut; #endif } break; @@ -116,10 +115,6 @@ CEmergencyPed::FiremanAI(void) SetMoveState(PEDMOVE_RUN); #ifdef FIX_BUGS bIsRunning = true; - if (m_pAttendedFire) { - --m_pAttendedFire->m_nFiremenPuttingOut; - } - ++nearestFire->m_nFiremenPuttingOut; m_pAttendedFire = nearestFire; } else if (!nearestFire) { #else @@ -153,10 +148,7 @@ CEmergencyPed::FiremanAI(void) case EMERGENCY_PED_STOP: #ifdef FIX_BUGS bIsRunning = false; - if (m_pAttendedFire) #endif - --m_pAttendedFire->m_nFiremenPuttingOut; - m_nPedState = PED_NONE; SetWanderPath(CGeneral::GetRandomNumber() & 7); m_pAttendedFire = nil; diff --git a/src/peds/PedRoutes.cpp b/src/peds/PedRoutes.cpp index 3ff080e6..2de90eae 100644 --- a/src/peds/PedRoutes.cpp +++ b/src/peds/PedRoutes.cpp @@ -3,6 +3,8 @@ #include "main.h" #include "PedRoutes.h" +// --MIAMI: file done + CRouteNode gaRoutes[NUMPEDROUTES]; void diff --git a/src/peds/PedStats.cpp b/src/peds/PedStats.cpp index 1f7a95b4..fe594bdf 100644 --- a/src/peds/PedStats.cpp +++ b/src/peds/PedStats.cpp @@ -4,6 +4,8 @@ #include "FileMgr.h" #include "PedStats.h" +// --MIAMI: file done + CPedStats *CPedStats::ms_apPedStats[NUM_PEDSTATS]; void diff --git a/src/render/Draw.cpp b/src/render/Draw.cpp index 131534a3..912399c9 100644 --- a/src/render/Draw.cpp +++ b/src/render/Draw.cpp @@ -24,12 +24,17 @@ float CDraw::CalculateAspectRatio(void) { if (FrontEndMenuManager.m_PrefsUseWideScreen) { +#ifdef ASPECT_RATIO_SCALE + if (TheCamera.m_WideScreenOn) + CDraw::ms_fAspectRatio = FrontEndMenuManager.m_PrefsUseWideScreen == AR_AUTO ? + (5.f / 3.f) * (SCREEN_WIDTH / SCREEN_HEIGHT) / (16.f / 9.f) : + 5.f / 3.f; // It's used on theatrical showings according to Wiki + else + CDraw::ms_fAspectRatio = FrontEndMenuManager.m_PrefsUseWideScreen == AR_AUTO ? SCREEN_WIDTH / SCREEN_HEIGHT : 16.f / 9.f; +#else if (TheCamera.m_WideScreenOn) CDraw::ms_fAspectRatio = 5.f / 3.f; // It's used on theatrical showings according to Wiki else -#ifdef ASPECT_RATIO_SCALE - CDraw::ms_fAspectRatio = FrontEndMenuManager.m_PrefsUseWideScreen == AR_AUTO ? SCREEN_WIDTH / SCREEN_HEIGHT : 16.f / 9.f; -#else CDraw::ms_fAspectRatio = 16.f / 9.f; #endif } else if (TheCamera.m_WideScreenOn) { diff --git a/src/render/Fluff.cpp b/src/render/Fluff.cpp index 31bf92a8..773561f3 100644 --- a/src/render/Fluff.cpp +++ b/src/render/Fluff.cpp @@ -1358,7 +1358,7 @@ CEscalator::Update(void) { if (m_pSteps[i]) { m_pSteps[i]->SetPosition(m_pos1); CWorld::Add(m_pSteps[i]); - m_pSteps[i]->ObjectCreatedBy = ESCALATOR_OBJECT; + m_pSteps[i]->ObjectCreatedBy = CONTROLLED_SUB_OBJECT; } } } @@ -1713,4 +1713,4 @@ void CScriptPaths::Save_ForReplay(void) { g_pScriptPathObjects[6 * i + j] = aArray[i].m_pObjects[j]; } } -} \ No newline at end of file +} diff --git a/src/render/Font.cpp b/src/render/Font.cpp index c0cc333a..f14e45cd 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -5,6 +5,46 @@ #include "Font.h" #include "Timer.h" +void +AsciiToUnicode(const char *src, wchar *dst) +{ + while((*dst++ = (unsigned char)*src++) != '\0'); +} + +void +UnicodeStrcat(wchar *dst, wchar *append) +{ + UnicodeStrcpy(&dst[UnicodeStrlen(dst)], append); +} + +void +UnicodeStrcpy(wchar *dst, const wchar *src) +{ + while((*dst++ = *src++) != '\0'); +} + +int +UnicodeStrlen(const wchar *str) +{ + int len; + for(len = 0; *str != '\0'; len++, str++); + return len; +} + +void +UnicodeMakeUpperCase(wchar *dst, const wchar *src) //idk what to do with it, seems to be incorrect implementation by R* +{ + while (*src != '\0') { + if (*src < 'a' || *src > 'z') + *dst = *src; + else + *dst = *src - 32; + dst++; + src++; + } + *dst = '\0'; +} + CFontDetails CFont::Details; int16 CFont::NewLine; CSprite2d CFont::Sprite[MAX_FONTS]; @@ -1102,6 +1142,7 @@ CFont::ParseToken(wchar *s) switch(*s){ case 'B': Details.bBold = !Details.bBold; + break; case 'N': case 'n': NewLine = 1; @@ -1109,7 +1150,7 @@ CFont::ParseToken(wchar *s) case 'b': SetColor(CRGBA(27, 89, 130, 255)); Details.anonymous_23 = true; break; case 'f': Details.bFlash = !Details.bFlash; - if (Details.bFlash) + if (!Details.bFlash) Details.color.a = 255; break; case 'g': SetColor(CRGBA(255, 150, 225, 255)); Details.anonymous_23 = true; break; diff --git a/src/render/Font.h b/src/render/Font.h index ca0ed7d0..47a39f73 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -1,5 +1,11 @@ #pragma once +void AsciiToUnicode(const char *src, wchar *dst); +void UnicodeStrcpy(wchar *dst, const wchar *src); +void UnicodeStrcat(wchar *dst, wchar *append); +int UnicodeStrlen(const wchar *str); +void UnicodeMakeUpperCase(wchar *dst, const wchar *src); + struct CFontDetails { CRGBA color; diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 36815ab5..3ea756fa 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -23,6 +23,9 @@ #include "CutsceneMgr.h" #include "Stats.h" #include "main.h" +#include "General.h" + +// --MIAMI: file done // Game has colors inlined in code. // For easier modification we collect them here: @@ -46,13 +49,14 @@ CRGBA ODDJOB_COLOR(0, 207, 133, 255); CRGBA ODDJOB2_COLOR(97, 194, 247, 255); CRGBA MISSIONTITLE_COLOR(220, 172, 2, 255); -wchar CHud::m_HelpMessage[256]; -wchar CHud::m_LastHelpMessage[256]; +wchar CHud::m_HelpMessage[HELP_MSG_LENGTH]; +wchar CHud::m_LastHelpMessage[HELP_MSG_LENGTH]; uint32 CHud::m_HelpMessageState; uint32 CHud::m_HelpMessageTimer; int32 CHud::m_HelpMessageFadeTimer; -wchar CHud::m_HelpMessageToPrint[256]; -float CHud::m_fHelpMessageTime; +wchar CHud::m_HelpMessageToPrint[HELP_MSG_LENGTH]; +float CHud::m_HelpMessageDisplayTime; +bool CHud::m_HelpMessageDisplayForever; bool CHud::m_HelpMessageQuick; uint32 CHud::m_ZoneState; int32 CHud::m_ZoneFadeTimer; @@ -73,16 +77,16 @@ bool CHud::m_Wants_To_Draw_3dMarkers; wchar CHud::m_BigMessage[6][128]; int16 CHud::m_ItemToFlash; bool CHud::m_HideRadar; -int32 CHud::m_DrawClock; +int32 CHud::m_ClockState; // These aren't really in CHud float CHud::BigMessageInUse[6]; float CHud::BigMessageAlpha[6]; float CHud::BigMessageX[6]; float CHud::OddJob2OffTimer; -bool CHud::CounterOnLastFrame; +bool CHud::CounterOnLastFrame[NUMONSCREENCOUNTERS]; float CHud::OddJob2XOffset; -uint16 CHud::CounterFlashTimer; +uint16 CHud::CounterFlashTimer[NUMONSCREENCOUNTERS]; uint16 CHud::OddJob2Timer; bool CHud::TimerOnLastFrame; int16 CHud::OddJob2On; @@ -110,6 +114,8 @@ uint32 CHud::m_WeaponTimer; uint32 CHud::m_LastDisplayScore; uint32 CHud::m_LastWanted; +uint32 CHud::m_LastWeapon; +uint32 CHud::m_LastTimeEnergyLost; CSprite2d CHud::Sprites[NUM_HUD_SPRITES]; @@ -118,33 +124,82 @@ struct const char *name; const char *mask; } WeaponFilenames[] = { - {"fist", "fistm"}, - {"bat", "batm"}, - {"pistol", "pistolm" }, - {"uzi", "uzim"}, - {"shotgun", "shotgunm"}, - {"ak47", "ak47m"}, - {"m16", "m16m"}, - {"sniper", "sniperm"}, - {"rocket", "rocketm"}, - {"flame", "flamem"}, - {"molotov", "molotovm"}, - {"grenade", "grenadem"}, - {"detonator", "detonator_mask"}, - {"", ""}, - {"", ""}, - {"radardisc", "radardisc"}, - {"pager", "pagerm"}, - {"", ""}, - {"", ""}, - {"bleeder", ""}, - {"sitesniper", "sitesniperm"}, - {"siteM16", "siteM16m"}, - {"siterocket", "siterocket"} + { "fist", "fistm" }, + { "brassk", "brasskA" }, + { "screw", "screwA" }, + { "golf", "golfA" }, + { "nightstick", "nightstickA" }, + { "knife", "knifeA" }, + { "bat", "batm" }, + { "hammer", "hammerA" }, + { "cleaver", "cleaverA" }, + { "machete", "macheteA" }, + { "sword", "swordA" }, + { "chainsaw", "chainsawA" }, + { "grenade", "grenadeA" }, + { "grenade", "grenadeA" }, + { "teargas", "teargasA" }, + { "molotov", "molotovA" }, + { "rocket", "rocketA" }, + { "handGun1", "handGun1A" }, + { "", "" }, + { "python", "pythonA" }, + { "chromegun", "chromegunA" }, + { "spasshotGun", "spasshotGunA" }, + { "stubshotGun", "stubshotGunA" }, + { "tec9", "tec9A" }, + { "uzi1", "uzi1A" }, + { "uzi2", "uzi2A" }, + { "mp5", "mp5A" }, + { "", "" }, + { "m4", "m4A" }, + { "ruger", "rugerA" }, + { "sniper", "sniperA" }, + { "laserscope", "laserscopeA" }, + { "", "" }, + { "rocket", "rocketA" }, + { "flamer", "flamerA" }, + { "m60", "m60A" }, + { "minigun", "minigunA" }, + { "bomb", "bombA" }, + { "", "" }, + { "camera", "cameraA" }, + { "", "" }, + { "siterocket", "siterocket" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "radardisc", "radardisc" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "", "" }, + { "sitesniper", "sitesniperm" }, + { "siteM16", "siteM16m" }, + { "sitelaser", "sitelaserm" }, + { "laserdot", "laserdotm" }, + { "viewfinder_128", "viewfinder_128m" }, + { "bleeder", "" } }; RwTexture *gpSniperSightTex; RwTexture *gpRocketSightTex; +RwTexture *gpLaserSightTex; +RwTexture *gpLaserDotTex; +RwTexture *gpViewFinderTex; void CHud::Draw() { @@ -160,7 +215,9 @@ void CHud::Draw() return; if (m_Wants_To_Draw_Hud && !TheCamera.m_WideScreenOn) { + // unused statics in here bool DrawCrossHair = false; + bool CrossHairHidesHud = false; bool DrawCrossHairPC = false; CPlayerPed *playerPed = FindPlayerPed(); @@ -251,38 +308,70 @@ void CHud::Draw() CSprite::RenderOneXLUSprite(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 1.0f, SCREEN_SCALE_X(40.0f), SCREEN_SCALE_Y(40.0f), (100.0f * fMultBright), (200.0f * fMultBright), (100.0f * fMultBright), 255, 1.0f, 255); RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); } else { + int sprite = HUD_SITESNIPER; + float xOffset = SCREEN_SCALE_X(210.0f); + float yOffset = SCREEN_SCALE_Y(210.0f); - // TODO(Miami) - // Sniper - rect.left = SCREEN_WIDTH/2 - SCREEN_SCALE_X(210.0f); - rect.top = SCREEN_HEIGHT/2 - SCREEN_SCALE_Y(210.0f); + if (FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_LASERSCOPE) + sprite = HUD_SITELASER; + + if (FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_CAMERA) { + sprite = HUD_VIEWFINDER; + CrossHairHidesHud = true; + xOffset = SCREEN_SCALE_X(256.0f); + yOffset = SCREEN_SCALE_Y(192.0f); + } + + rect.left = SCREEN_WIDTH/2 - xOffset; + rect.top = SCREEN_HEIGHT/2 - yOffset; rect.right = SCREEN_WIDTH/2; rect.bottom = SCREEN_HEIGHT/2; - Sprites[HUD_SITESNIPER].Draw(CRect(rect), CRGBA(255, 255, 255, 255), + Sprites[sprite].Draw(CRect(rect), CRGBA(255, 255, 255, 255), 0.01f, 0.01f, 1.0f, 0.0f, 0.01f, 1.0f, 1.0f, 1.0f); rect.left = SCREEN_WIDTH/2; - rect.top = SCREEN_HEIGHT/2 - SCREEN_SCALE_Y(210.0f); - rect.right = SCREEN_WIDTH/2 + SCREEN_SCALE_X(210.0f); + rect.top = SCREEN_HEIGHT/2 - yOffset; + rect.right = SCREEN_WIDTH/2 + xOffset; rect.bottom = SCREEN_HEIGHT/2; - Sprites[HUD_SITESNIPER].Draw(CRect(rect), CRGBA(255, 255, 255, 255), + Sprites[sprite].Draw(CRect(rect), CRGBA(255, 255, 255, 255), 0.99f, 0.0f, 0.01f, 0.01f, 0.99f, 1.0f, 0.01f, 1.0f); - rect.left = SCREEN_WIDTH/2 - SCREEN_SCALE_X(210.0f); + rect.left = SCREEN_WIDTH/2 - xOffset; rect.top = SCREEN_HEIGHT/2; rect.right = SCREEN_WIDTH/2; - rect.bottom = SCREEN_HEIGHT/2 + SCREEN_SCALE_Y(210.0f); - Sprites[HUD_SITESNIPER].Draw(CRect(rect), CRGBA(255, 255, 255, 255), + rect.bottom = SCREEN_HEIGHT/2 + yOffset; + Sprites[sprite].Draw(CRect(rect), CRGBA(255, 255, 255, 255), 0.01f, 0.99f, 1.0f, 0.99f, 0.01f, 0.01f, 1.0f, 0.01f); rect.left = SCREEN_WIDTH/2; rect.top = SCREEN_HEIGHT/2; - rect.right = SCREEN_WIDTH/2 + SCREEN_SCALE_X(210.0f); - rect.bottom = SCREEN_HEIGHT/2 + SCREEN_SCALE_Y(210.0f); - Sprites[HUD_SITESNIPER].Draw(CRect(rect), CRGBA(255, 255, 255, 255), + rect.right = SCREEN_WIDTH/2 + xOffset; + rect.bottom = SCREEN_HEIGHT/2 + yOffset; + Sprites[sprite].Draw(CRect(rect), CRGBA(255, 255, 255, 255), 0.99f, 0.99f, 0.01f, 0.99f, 0.99f, 0.01f, 0.1f, 0.01f); + + CVector dotPos; + float size = 25.0f; + if (FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_LASERSCOPE && FindPlayerPed()->GetWeapon()->LaserScopeDot(&dotPos, &size)) { + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVDESTALPHA); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpLaserDotTex)); +#ifdef FIX_BUGS + int intensity = CGeneral::GetRandomNumberInRange(0, 37); +#else + int intensity = CGeneral::GetRandomNumberInRange(0, 35); +#endif + CSprite::RenderOneXLUSprite(dotPos.x, dotPos.y, dotPos.z, + SCREEN_SCALE_X(size), SCREEN_SCALE_Y(size), intensity - 36, 0, 0, intensity - 36, 1.0f, 127); + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + } } } RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); @@ -293,6 +382,9 @@ void CHud::Draw() SpriteBrightness = 0; } + if (CrossHairHidesHud) + return; + /* DrawMoneyCounter */ @@ -303,9 +395,9 @@ void CHud::Draw() float alpha; if (m_LastDisplayScore == CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney) { - alpha = CHud::DrawFadeState(HUD_SCORE_FADING, 0); + alpha = DrawFadeState(HUD_SCORE_FADING, 0); } else { - alpha = CHud::DrawFadeState(HUD_SCORE_FADING, 1); + alpha = DrawFadeState(HUD_SCORE_FADING, 1); m_LastDisplayScore = CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney; } if (m_DisplayScoreState != FADED_OUT) { @@ -334,151 +426,168 @@ void CHud::Draw() /* DrawAmmo */ - CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo((eWeaponType)WeaponType); - CWeapon *weapon = playerPed->GetWeapon(); - uint32 AmmoAmount = weaponInfo->m_nAmountofAmmunition; - uint32 AmmoInClip = weapon->m_nAmmoInClip; - uint32 TotalAmmo = weapon->m_nAmmoTotal; - uint32 Ammo, Clip; - - if (AmmoAmount <= 1 || AmmoAmount >= 1000) - sprintf(sTemp, "%d", TotalAmmo); - else { - if (WeaponType == WEAPONTYPE_FLAMETHROWER) { - Clip = AmmoInClip / 10; - - if ((TotalAmmo - AmmoInClip) / 10 <= 9999) - Ammo = (TotalAmmo - AmmoInClip) / 10; - else - Ammo = 9999; - } - else { - Clip = AmmoInClip; - - if ((TotalAmmo - AmmoInClip) > 9999) - Ammo = 9999; - else - Ammo = TotalAmmo - AmmoInClip; - } - - sprintf(sTemp, "%d-%d", Ammo, Clip); - } - - AsciiToUnicode(sTemp, sPrint); - - /* - DrawWeaponIcon - */ - - if (weaponInfo->m_nModelId <= 0) { - RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - Sprites[WeaponType].Draw( - CRect(SCREEN_SCALE_FROM_RIGHT(99.0f), SCREEN_SCALE_Y(27.0f), SCREEN_SCALE_FROM_RIGHT(35.0f), SCREEN_SCALE_Y(91.0f)), - CRGBA(255, 255, 255, 255), - 0.015f, - 0.015f, - 1.0f, - 0.0f, - 0.015f, - 1.0f, - 1.0f, - 1.0f); + if (m_LastWeapon == playerPed->GetWeapon()->m_eWeaponType) { + alpha = CHud::DrawFadeState(HUD_WEAPON_FADING, 0); } else { - CBaseModelInfo *weaponModel = CModelInfo::GetModelInfo(weaponInfo->m_nModelId); - RwTexDictionary *weaponTxd = CTxdStore::GetSlot(weaponModel->GetTxdSlot())->texDict; - if (weaponTxd) { - RwTexture *weaponIcon = RwTexDictionaryFindNamedTexture(weaponTxd, weaponModel->GetName()); - if (weaponIcon) { + alpha = CHud::DrawFadeState(HUD_WEAPON_FADING, 1); + m_LastWeapon = playerPed->GetWeapon()->m_eWeaponType; + } + if (m_WeaponState != FADED_OUT) { + CWeapon *weapon = playerPed->GetWeapon(); + uint32 AmmoAmount = CWeaponInfo::GetWeaponInfo((eWeaponType)WeaponType)->m_nAmountofAmmunition; + uint32 AmmoInClip = weapon->m_nAmmoInClip; + uint32 TotalAmmo = weapon->m_nAmmoTotal; + uint32 Ammo, Clip; + + if (AmmoAmount <= 1 || AmmoAmount >= 1000) + sprintf(sTemp, "%d", TotalAmmo); + else { + if (WeaponType == WEAPONTYPE_FLAMETHROWER) { + Clip = AmmoInClip / 10; + + Ammo = Min((TotalAmmo - AmmoInClip) / 10, 9999); + } else { + Clip = AmmoInClip; + + Ammo = Min(TotalAmmo - AmmoInClip, 9999); + } + + sprintf(sTemp, "%d-%d", Ammo, Clip); + } + + AsciiToUnicode(sTemp, sPrint); + CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo((eWeaponType)WeaponType); + /* + DrawWeaponIcon + */ + + if (FrontEndMenuManager.m_PrefsShowHud) { + if (weaponInfo->m_nModelId <= 0) { RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); - RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(weaponIcon)); - const float xSize = SCREEN_SCALE_X(64.0f / 2.0f); - const float ySize = SCREEN_SCALE_X(64.0f / 2.0f); - CSprite::RenderOneXLUSprite(SCREEN_SCALE_FROM_RIGHT(99.0f) + xSize, SCREEN_SCALE_Y(25.0f) + ySize, 1.0f, xSize, ySize, - 255, 255, 255, 255, 1.0f, 255); - RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + if (FrontEndMenuManager.m_PrefsShowHud) + Sprites[WeaponType].Draw( + CRect(SCREEN_SCALE_FROM_RIGHT(99.0f), SCREEN_SCALE_Y(27.0f), SCREEN_SCALE_FROM_RIGHT(35.0f), SCREEN_SCALE_Y(91.0f)), + CRGBA(255, 255, 255, alpha), + 0.015f, + 0.015f, + 1.0f, + 0.0f, + 0.015f, + 1.0f, + 1.0f, + 1.0f); + } else { + CBaseModelInfo *weaponModel = CModelInfo::GetModelInfo(weaponInfo->m_nModelId); + RwTexDictionary *weaponTxd = CTxdStore::GetSlot(weaponModel->GetTxdSlot())->texDict; + if (weaponTxd) { + RwTexture *weaponIcon = RwTexDictionaryFindNamedTexture(weaponTxd, weaponModel->GetName()); + if (weaponIcon) { + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(weaponIcon)); + const float xSize = SCREEN_SCALE_X(64.0f / 2.0f); + const float ySize = SCREEN_SCALE_X(64.0f / 2.0f); + CSprite::RenderOneXLUSprite(SCREEN_SCALE_FROM_RIGHT(99.0f) + xSize, SCREEN_SCALE_Y(25.0f) + ySize, 1.0f, xSize, ySize, + 255, 255, 255, 255, 1.0f, 255); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE); + } + } + } + + CFont::SetBackgroundOff(); + CFont::SetScale(SCREEN_SCALE_X(0.5f), SCREEN_SCALE_Y(0.8f)); + CFont::SetJustifyOff(); + CFont::SetCentreOn(); + CFont::SetCentreSize(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetPropOn(); + CFont::SetDropShadowPosition(0); + CFont::SetFontStyle(FONT_STANDARD); + + if (Min(9999, TotalAmmo - AmmoInClip) != 9999 && !CDarkel::FrenzyOnGoing() && weaponInfo->m_nWeaponSlot > 1 && weapon->m_eWeaponType != WEAPONTYPE_DETONATOR) { + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, alpha)); + AMMO_COLOR.a = alpha; + CFont::SetColor(AMMO_COLOR); + if (FrontEndMenuManager.m_PrefsShowHud) + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(66.0f), SCREEN_SCALE_Y(90.0f), sPrint); + CFont::SetDropShadowPosition(0); } } } - CFont::SetBackgroundOff(); - CFont::SetScale(SCREEN_SCALE_X(0.5f), SCREEN_SCALE_Y(0.8f)); - CFont::SetJustifyOff(); - CFont::SetCentreOn(); - CFont::SetCentreSize(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); - CFont::SetPropOn(); - CFont::SetDropShadowPosition(0); - CFont::SetFontStyle(FONT_STANDARD); - - if (Min(9999, TotalAmmo - AmmoInClip) != 9999 && !CDarkel::FrenzyOnGoing() && weaponInfo->m_nWeaponSlot > 1 && weapon->m_eWeaponType != WEAPONTYPE_DETONATOR) { - CFont::SetDropShadowPosition(2); - CFont::SetDropColor(CRGBA(0, 0, 0, 255)); - CFont::SetColor(AMMO_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(66.0f), SCREEN_SCALE_Y(90.0f), sPrint); - CFont::SetDropShadowPosition(0); - } - /* DrawHealth */ - CFont::SetBackgroundOff(); - CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); - CFont::SetJustifyOff(); - CFont::SetCentreOff(); - CFont::SetRightJustifyWrap(0.0f); - CFont::SetRightJustifyOn(); - CFont::SetPropOff(); - CFont::SetFontStyle(FONT_HEADING); - CFont::SetDropShadowPosition(2); - CFont::SetDropColor(CRGBA(0, 0, 0, 255)); - - if (m_ItemToFlash == ITEM_HEALTH && CTimer::GetFrameCounter() & 8 - || m_ItemToFlash != ITEM_HEALTH - || playerPed->m_fHealth < 10 - && CTimer::GetFrameCounter() & 8) { - if (playerPed->m_fHealth >= 10 - || playerPed->m_fHealth < 10 && CTimer::GetFrameCounter() & 8) { - - AsciiToUnicode("{", sPrintIcon); -#ifdef FIX_BUGS - sprintf(sTemp, "%03d", int32(playerPed->m_fHealth + 0.5f)); -#else - sprintf(sTemp, "%03d", (int32)playerPed->m_fHealth); -#endif - AsciiToUnicode(sTemp, sPrint); - - CFont::SetColor(HEALTH_COLOR); - - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(110.0f), SCREEN_SCALE_Y(65.0f), sPrint); - - if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss + 2000 || CTimer::GetFrameCounter() & 4) { - // CFont::SetColor(HEALTH_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(110.0f + 54.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); - } - } + if ( m_LastTimeEnergyLost == CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss ) { + CHud::DrawFadeState(HUD_ENERGY_FADING, 0); + } else { + CHud::DrawFadeState(HUD_ENERGY_FADING, 1); + m_LastTimeEnergyLost = CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss; } - /* - DrawArmour - */ - if (m_ItemToFlash == ITEM_ARMOUR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_ARMOUR) { + if (m_EnergyLostState != FADED_OUT) { + CFont::SetBackgroundOff(); CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); - if (playerPed->m_fArmour > 1.0f) { - AsciiToUnicode("<", sPrintIcon); + CFont::SetJustifyOff(); + CFont::SetCentreOff(); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetRightJustifyOn(); + CFont::SetPropOff(); + CFont::SetFontStyle(FONT_HEADING); + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); + + if (m_ItemToFlash == ITEM_HEALTH && CTimer::GetFrameCounter() & 8 + || m_ItemToFlash != ITEM_HEALTH + || playerPed->m_fHealth < 10 + && CTimer::GetFrameCounter() & 8) { + if (playerPed->m_fHealth >= 10 + || playerPed->m_fHealth < 10 && CTimer::GetFrameCounter() & 8) { + + AsciiToUnicode("{", sPrintIcon); #ifdef FIX_BUGS - sprintf(sTemp, "%03d", int32(playerPed->m_fArmour + 0.5f)); + sprintf(sTemp, "%03d", int32(playerPed->m_fHealth + 0.5f)); #else - sprintf(sTemp, "%03d", (int32)playerPed->m_fArmour); + sprintf(sTemp, "%03d", (int32)playerPed->m_fHealth); #endif - AsciiToUnicode(sTemp, sPrint); + AsciiToUnicode(sTemp, sPrint); - CFont::SetColor(ARMOUR_COLOR); + CFont::SetColor(HEALTH_COLOR); + if (FrontEndMenuManager.m_PrefsShowHud) { + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(110.0f), SCREEN_SCALE_Y(65.0f), sPrint); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f), SCREEN_SCALE_Y(65.0f), sPrint); + if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss + 2000 || CTimer::GetFrameCounter() & 4) { + // CFont::SetColor(HEALTH_COLOR); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(110.0f + 54.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); + } + } + } + } - if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss + 2000 || CTimer::GetFrameCounter() & 1) { - // CFont::SetColor(ARMOUR_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f + 52.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); + /* + DrawArmour + */ + if (m_ItemToFlash == ITEM_ARMOUR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_ARMOUR) { + CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); + if (playerPed->m_fArmour > 1.0f) { + AsciiToUnicode("<", sPrintIcon); +#ifdef FIX_BUGS + sprintf(sTemp, "%03d", int32(playerPed->m_fArmour + 0.5f)); +#else + sprintf(sTemp, "%03d", (int32)playerPed->m_fArmour); +#endif + AsciiToUnicode(sTemp, sPrint); + + CFont::SetColor(ARMOUR_COLOR); + if (FrontEndMenuManager.m_PrefsShowHud) { + + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f), SCREEN_SCALE_Y(65.0f), sPrint); + + if (!CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss || CTimer::GetTimeInMilliseconds() > CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastArmourLoss + 2000 || CTimer::GetFrameCounter() & 1) { + // CFont::SetColor(ARMOUR_COLOR); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(182.0f + 52.0f), SCREEN_SCALE_Y(65.0f), sPrintIcon); + } + } } } } @@ -486,10 +595,10 @@ void CHud::Draw() /* DrawWantedLevel */ - if (m_LastWanted == playerPed->m_pWanted->m_nWantedLevel) - alpha = CHud::DrawFadeState(HUD_WANTED_FADING, 0); - else { - alpha = CHud::DrawFadeState(HUD_WANTED_FADING, 1); + if (m_LastWanted == playerPed->m_pWanted->m_nWantedLevel) { + alpha = DrawFadeState(HUD_WANTED_FADING, 0); + } else { + alpha = DrawFadeState(HUD_WANTED_FADING, 1); m_LastWanted = playerPed->m_pWanted->m_nWantedLevel; } @@ -745,11 +854,7 @@ void CHud::Draw() break; } -#ifndef HUD_ENHANCEMENTS if (!m_Message[0]) { -#else - if (!m_Message[0] && !m_BigMessage[2][0]) { // Hide vehicle name if wasted/busted text is displaying -#endif m_VehicleNameTimer += CTimer::GetTimeStepInMilliseconds(); CFont::SetJustifyOff(); CFont::SetPropOn(); @@ -787,7 +892,7 @@ void CHud::Draw() /* DrawClock */ - if (m_DrawClock) { + if (m_ClockState) { CFont::SetJustifyOff(); CFont::SetCentreOff(); CFont::SetBackgroundOff(); @@ -814,30 +919,28 @@ void CHud::Draw() wchar sTimer[16]; - if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerProcessed) + if (!CUserDisplay::OnscnTimer.m_sClocks[0].m_bClockProcessed) TimerOnLastFrame = false; - if (!CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterProcessed) - CounterOnLastFrame = false; -#ifdef FIX_BUGS -#define TIMER_RIGHT_OFFSET 34.0f // Taken from VC frenzy timer -#else -#define TIMER_RIGHT_OFFSET 27.0f -#endif + for(uint32 i = 0; i < NUMONSCREENCOUNTERS; i++) { + if (!CUserDisplay::OnscnTimer.m_sCounters[0].m_bCounterProcessed) + CounterOnLastFrame[i] = false; + } + if (CUserDisplay::OnscnTimer.m_bProcessed) { - if (CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerProcessed) { + if (CUserDisplay::OnscnTimer.m_sClocks[0].m_bClockProcessed) { if (!TimerOnLastFrame) TimerFlashTimer = 1; TimerOnLastFrame = true; - if (TimerFlashTimer) { + if (TimerFlashTimer != 0) { if (++TimerFlashTimer > 50) TimerFlashTimer = 0; } - if (CTimer::GetFrameCounter() & 4 || !TimerFlashTimer) { - AsciiToUnicode(CUserDisplay::OnscnTimer.m_sEntries[0].m_bTimerBuffer, sTimer); + if (CTimer::GetFrameCounter() & 4 || TimerFlashTimer == 0) { + AsciiToUnicode(CUserDisplay::OnscnTimer.m_sClocks[0].m_aClockBuffer, sTimer); CFont::SetPropOn(); CFont::SetBackgroundOff(); CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); @@ -846,126 +949,84 @@ void CHud::Draw() CFont::SetFontStyle(FONT_LOCALE(FONT_HEADING)); CFont::SetPropOff(); CFont::SetBackGroundOnlyTextOn(); - CFont::SetColor(CRGBA(0, 0, 0, 255)); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(110.0f) + SCREEN_SCALE_Y(2.0f), sTimer); + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); CFont::SetColor(TIMER_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET), SCREEN_SCALE_Y(110.0f), sTimer); - - if (CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText[0]) { - CFont::SetPropOn(); - CFont::SetColor(CRGBA(0, 0, 0, 255)); - CFont::SetScale(SCREEN_SCALE_X(0.64f), SCREEN_SCALE_Y(1.35f)); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(80.0f) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(110.0f) + SCREEN_SCALE_Y(2.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(37.0f), SCREEN_SCALE_Y(110.0f), sTimer); + CFont::SetPropOn(); + if (CUserDisplay::OnscnTimer.m_sClocks[0].m_aClockText[0]) { + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); CFont::SetColor(TIMER_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(80.0f), SCREEN_SCALE_Y(110.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aTimerText)); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(37.0f) - SCREEN_SCALE_X(80.0f), SCREEN_SCALE_Y(110.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sClocks[0].m_aClockText)); } } } - if (CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterProcessed) { - if (!CounterOnLastFrame) - CounterFlashTimer = 1; - CounterOnLastFrame = true; + for(uint32 i = 0; i < NUMONSCREENCOUNTERS; i++) { + if (CUserDisplay::OnscnTimer.m_sCounters[i].m_bCounterProcessed) { + if (!CounterOnLastFrame[i]) + CounterFlashTimer[i] = 1; - if (CounterFlashTimer) { - if (++CounterFlashTimer > 50) - CounterFlashTimer = 0; - } + CounterOnLastFrame[i] = true; - if (CTimer::GetFrameCounter() & 4 || !CounterFlashTimer) { - if (CUserDisplay::OnscnTimer.m_sEntries[0].m_nType == COUNTER_DISPLAY_NUMBER) { - AsciiToUnicode(CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterBuffer, sTimer); - CFont::SetPropOn(); - - CFont::SetBackgroundOff(); - CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); - CFont::SetCentreOff(); - CFont::SetRightJustifyOn(); - CFont::SetRightJustifyWrap(0.0f); - CFont::SetFontStyle(FONT_LOCALE(FONT_HEADING)); - CFont::SetColor(CRGBA(244, 20, 20, 255)); - CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); - CFont::SetPropOff(); - CFont::SetBackGroundOnlyTextOn(); - - CFont::SetColor(CRGBA(0, 0, 0, 255)); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X(2.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(2.0f), sTimer); - - CFont::SetColor(COUNTER_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET), SCREEN_SCALE_Y(132.0f), sTimer); - } else { - int counter = atoi(CUserDisplay::OnscnTimer.m_sEntries[0].m_bCounterBuffer); -#ifdef FIX_BUGS - counter = Min(counter, 100); -#endif - CSprite2d::DrawRect(CRect(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + SCREEN_SCALE_X(4.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(8.0f), SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) + SCREEN_SCALE_X(4.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(11.0f) + SCREEN_SCALE_Y(8.0f)), CRGBA(0, 106, 164, 80)); - CSprite2d::DrawRect(CRect(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(100.0f) / 2 + SCREEN_SCALE_X(4.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(8.0f), SCREEN_SCALE_X(counter) / 2.0f + SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET + 50.0f) + SCREEN_SCALE_X(4.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(11.0f) + SCREEN_SCALE_Y(8.0f)), CRGBA(0, 106, 164, 255)); + if (CounterFlashTimer[i] != 0) { + if (++CounterFlashTimer[i] > 50) + CounterFlashTimer[i] = 0; } - if (CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText[0]) { - CFont::SetPropOn(); - CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); - CFont::SetColor(CRGBA(0, 0, 0, 255)); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(61.0f) + SCREEN_SCALE_Y(2.0f), SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(2.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText)); + if (CTimer::GetFrameCounter() & 4 || CounterFlashTimer[i] == 0) { + if (CUserDisplay::OnscnTimer.m_sCounters[i].m_nType == COUNTER_DISPLAY_NUMBER) { + AsciiToUnicode(CUserDisplay::OnscnTimer.m_sCounters[i].m_aCounterBuffer, sTimer); + CFont::SetPropOn(); + CFont::SetBackgroundOff(); + CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); + CFont::SetCentreOff(); + CFont::SetRightJustifyOn(); + CFont::SetRightJustifyWrap(0.0f); + CFont::SetFontStyle(FONT_LOCALE(FONT_HEADING)); + CFont::SetWrapx(SCREEN_STRETCH_X(DEFAULT_SCREEN_WIDTH)); + CFont::SetPropOn(); + CFont::SetBackGroundOnlyTextOn(); + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); + CFont::SetColor(COUNTER_COLOR); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(37.0f), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y * 20.f * i) + SCREEN_SCALE_Y(132.0f), sTimer); + } else { + int counter = atoi(CUserDisplay::OnscnTimer.m_sCounters[i].m_aCounterBuffer); - CFont::SetColor(COUNTER_COLOR); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(TIMER_RIGHT_OFFSET) - SCREEN_SCALE_X(61.0f), SCREEN_SCALE_Y(132.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sEntries[0].m_aCounterText)); + const float barWidth = SCREEN_SCALE_X(100.f / 2.f); + const float right = SCREEN_SCALE_FROM_RIGHT(37.0f); + const float left = right - barWidth; + + const float barHeight = SCREEN_SCALE_Y(11.0f); + const float top = SCREEN_SCALE_Y(132.0f) + SCREEN_SCALE_Y(8.0f) + SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y * 20.f * i); + const float bottom = top + barHeight; + + // shadow + CSprite2d::DrawRect(CRect(left + SCREEN_SCALE_X(6.0f), top + SCREEN_SCALE_Y(2.0f), right + SCREEN_SCALE_X(6.0f), bottom + SCREEN_SCALE_Y(2.0f)), CRGBA(0, 0, 0, 255)); + + CSprite2d::DrawRect(CRect(left + SCREEN_SCALE_X(4.0f), top, right + SCREEN_SCALE_X(4.0f), bottom), CRGBA(27, 89, 130, 255)); + CSprite2d::DrawRect(CRect(left + SCREEN_SCALE_X(4.0f), top, left + SCREEN_SCALE_X(counter) / 2.0f + SCREEN_SCALE_X(4.0f), bottom), CRGBA(97, 194, 247, 255)); + } + + if (CUserDisplay::OnscnTimer.m_sCounters[i].m_aCounterText[0]) { + CFont::SetPropOn(); + CFont::SetFontStyle(FONT_LOCALE(FONT_HEADING)); + CFont::SetScale(SCREEN_SCALE_X(HUD_TEXT_SCALE_X), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y)); + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); + CFont::SetColor(COUNTER_COLOR); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(37.0f) - SCREEN_SCALE_X(61.0f), SCREEN_SCALE_Y(HUD_TEXT_SCALE_Y * 20.f * i) + SCREEN_SCALE_Y(132.0f), TheText.Get(CUserDisplay::OnscnTimer.m_sCounters[i].m_aCounterText)); + } + // unused/leftover color. I wonder what was it for + CFont::SetColor(CRGBA(244, 225, 91, 255)); } } } } -#undef TIMER_RIGHT_OFFSET - - /* - DrawPager - */ - if (!m_PagerMessage[0] && PagerOn == 1) { - PagerSoundPlayed = false; - PagerOn = 2; - } - if (m_PagerMessage[0] || PagerOn == 2) { - if (!PagerOn) { - PagerOn = 1; - PagerXOffset = 150.0f; - } - if (PagerOn == 1) { - if (PagerXOffset > 0.0f) { - float fStep = PagerXOffset * 0.1f; - if (fStep > 10.0f) - fStep = 10.0f; - PagerXOffset -= fStep * CTimer::GetTimeStep(); - } - if (!PagerSoundPlayed) { - DMAudio.PlayFrontEndSound(SOUND_PAGER, 0); - PagerSoundPlayed = 1; - } - } - else if (PagerOn == 2) { - float fStep = PagerXOffset * 0.1f; - if (fStep < 2.0f) - fStep = 2.0f; - PagerXOffset += fStep; - if (PagerXOffset > 150.0f) { - PagerXOffset = 150.0f; - PagerOn = 0; - } - } - - Sprites[HUD_PAGER].Draw(CRect(SCREEN_SCALE_X(26.0f - PagerXOffset), SCREEN_SCALE_Y(27.0f), SCREEN_SCALE_X(160.0 + 26.0f - PagerXOffset), SCREEN_SCALE_Y(80.0f + 27.0f)), CRGBA(255, 255, 255, 255)); - - CFont::SetBackgroundOff(); - CFont::SetScale(SCREEN_SCALE_X(0.84f), SCREEN_SCALE_Y(1.0f)); - CFont::SetColor(PAGER_COLOR); - CFont::SetRightJustifyOff(); - CFont::SetBackgroundOff(); - CFont::SetCentreOff(); - CFont::SetJustifyOff(); - CFont::SetPropOff(); - CFont::SetFontStyle(FONT_STANDARD); - CFont::PrintString(SCREEN_SCALE_X(52.0f - PagerXOffset), SCREEN_SCALE_Y(54.0f), m_PagerMessage); - } /* DrawRadar @@ -1126,14 +1187,14 @@ void CHud::Draw() */ if (m_HelpMessage[0]) { - if (!CMessages::WideStringCompare(m_HelpMessage, m_LastHelpMessage, 256)) { + if (!CMessages::WideStringCompare(m_HelpMessage, m_LastHelpMessage, HELP_MSG_LENGTH)) { switch (m_HelpMessageState) { case 0: m_HelpMessageFadeTimer = 0; m_HelpMessageState = 2; m_HelpMessageTimer = 0; - CMessages::WideStringCopy(m_HelpMessageToPrint, m_HelpMessage, 256); - m_fHelpMessageTime = CMessages::GetWideStringLength(m_HelpMessage) * 0.05f + 3.0f; + CMessages::WideStringCopy(m_HelpMessageToPrint, m_HelpMessage, HELP_MSG_LENGTH); + m_HelpMessageDisplayTime = CMessages::GetWideStringLength(m_HelpMessage) * 0.05f + 3.0f; if (TheCamera.m_ScreenReductionPercentage == 0.0f) DMAudio.PlayFrontEndSound(SOUND_HUD_SOUND, 0); @@ -1148,7 +1209,7 @@ void CHud::Draw() default: break; } - CMessages::WideStringCopy(m_LastHelpMessage, m_HelpMessage, 256); + CMessages::WideStringCopy(m_LastHelpMessage, m_HelpMessage, HELP_MSG_LENGTH); } float fAlpha = 225.0f; @@ -1158,7 +1219,9 @@ void CHud::Draw() case 1: fAlpha = 225.0f; m_HelpMessageFadeTimer = 600; - if (m_HelpMessageTimer > m_fHelpMessageTime * 1000.0f || m_HelpMessageQuick && m_HelpMessageTimer > 1500.0f) { + if (!m_HelpMessageDisplayForever && m_HelpMessageTimer > m_HelpMessageDisplayTime * 1000.0f || + m_HelpMessageQuick && m_HelpMessageTimer > 1500.0f) { + m_HelpMessageFadeTimer = 600; m_HelpMessageState = 3; } @@ -1187,7 +1250,7 @@ void CHud::Draw() if (m_HelpMessageFadeTimer < 0) { m_HelpMessageState = 2; m_HelpMessageFadeTimer = 0; - CMessages::WideStringCopy(m_HelpMessageToPrint, m_LastHelpMessage, 256); + CMessages::WideStringCopy(m_HelpMessageToPrint, m_LastHelpMessage, HELP_MSG_LENGTH); } fAlpha = m_HelpMessageFadeTimer * 0.001f * 225.0f; break; @@ -1212,7 +1275,7 @@ void CHud::Draw() CFont::SetScale(SCREEN_SCALE_X(0.52f), SCREEN_SCALE_Y(1.1f)); CFont::DrawFonts(); - // CFont::SetColor(CRGBA(175, 175, 175, 255)); + CFont::SetColor(CRGBA(175, 175, 175, 255)); CFont::SetJustifyOff(); #ifdef MORE_LANGUAGES if (CFont::IsJapanese()) @@ -1224,9 +1287,9 @@ void CHud::Draw() CFont::SetBackgroundOn(); CFont::SetBackGroundOnlyTextOff(); CFont::SetDropShadowPosition(0); - CFont::SetColor(CRGBA(175, 175, 175, 255)); CFont::SetBackgroundColor(CRGBA(0, 0, 0, fAlpha * 0.9f)); - CFont::PrintString(SCREEN_SCALE_X(34.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), CHud::m_HelpMessageToPrint); + CFont::SetColor(CRGBA(175, 175, 175, 255)); + CFont::PrintString(SCREEN_SCALE_X(34.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), m_HelpMessageToPrint); CFont::SetAlphaFade(255.0f); CFont::SetWrapx(SCREEN_WIDTH); } @@ -1311,19 +1374,19 @@ void CHud::Draw() CFont::SetRightJustifyOn(); CFont::SetFontStyle(FONT_HEADING); - CFont::SetColor(CRGBA(0, 0, 0, BigMessageAlpha[2])); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f - 4.0f), SCREEN_SCALE_FROM_BOTTOM(78.0f), m_BigMessage[2]); + CFont::SetDropShadowPosition(2); + CFont::SetDropColor(CRGBA(0, 0, 0, BigMessageAlpha[2])); CFont::SetColor(CRGBA(WASTEDBUSTED_COLOR.r, WASTEDBUSTED_COLOR.g, WASTEDBUSTED_COLOR.b, BigMessageAlpha[2])); - CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(82.0f), m_BigMessage[2]); + CFont::PrintString(SCREEN_SCALE_FROM_RIGHT(20.0f), SCREEN_SCALE_FROM_BOTTOM(90.0f), m_BigMessage[2]); } else { BigMessageInUse[2] = 1.0f; BigMessageAlpha[2] = 0.0f; - if (CHud::m_VehicleState != 0) - CHud::m_VehicleState = 0; - if (CHud::m_ZoneState != 0) - CHud::m_ZoneState = 0; + if (m_VehicleState != 0) // Hide vehicle name if wasted/busted text is displaying + m_VehicleState = 0; + if (m_ZoneState != 0) + m_ZoneState = 0; } } else { @@ -1332,7 +1395,6 @@ void CHud::Draw() } } -// --MIAMI: Done void CHud::DrawAfterFade() { RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void*)rwFILTERNEAREST); @@ -1522,7 +1584,7 @@ void CHud::DrawAfterFade() BigMessageInUse[1] = 120.0f; BigMessageAlpha[1] -= CTimer::GetTimeStepInMilliseconds(); } - if (BigMessageAlpha[1] <= 0) { + if (BigMessageAlpha[1] <= 0.0f) { m_BigMessage[1][0] = 0; BigMessageInUse[1] = 0.0f; BigMessageAlpha[1] = 0.0f; @@ -1558,12 +1620,11 @@ void CHud::DrawAfterFade() void CHud::GetRidOfAllHudMessages() { - m_ZoneState = 0; - m_pLastZoneName = nil; m_ZoneNameTimer = 0; m_pZoneName = nil; + m_ZoneState = 0; - for (int i = 0; i < 256; i++) { + for (int i = 0; i < HELP_MSG_LENGTH; i++) { m_HelpMessage[i] = 0; m_LastHelpMessage[i] = 0; m_HelpMessageToPrint[i] = 0; @@ -1573,15 +1634,15 @@ void CHud::GetRidOfAllHudMessages() m_HelpMessageFadeTimer = 0; m_HelpMessageState = 0; m_HelpMessageQuick = 0; - m_fHelpMessageTime = 1.0f; + m_HelpMessageDisplayForever = false; + m_HelpMessageDisplayTime = 1.0f; m_VehicleName = nil; - m_pLastVehicleName = nil; m_pVehicleNameToPrint = nil; m_VehicleNameTimer = 0; m_VehicleFadeTimer = 0; m_VehicleState = 0; - for (int i = 0; i < 256; i++) + for (int i = 0; i < ARRAY_SIZE(m_Message); i++) m_Message[i] = 0; for (int i = 0; i < 6; i++) { @@ -1631,21 +1692,34 @@ void CHud::Initialise() Sprites[i].SetTexture(WeaponFilenames[i].name, WeaponFilenames[i].mask); } + m_pLastZoneName = nil; GetRidOfAllHudMessages(); + m_pLastVehicleName = nil; if (gpSniperSightTex == nil) - gpSniperSightTex = RwTextureRead("sitesniper", nil); + gpSniperSightTex = RwTextureRead("sitesniper", nil); // unused if (gpRocketSightTex == nil) gpRocketSightTex = RwTextureRead("siterocket", nil); + if (gpLaserSightTex == nil) + gpLaserSightTex = RwTextureRead("sitelaser", nil); // unused + if (gpLaserDotTex == nil) + gpLaserDotTex = RwTextureRead("laserdot", "laserdotm"); + if (gpViewFinderTex == nil) + gpViewFinderTex = RwTextureRead("viewfinder_128", "viewfinder_128m"); // unused - m_DrawClock = 1; - CounterOnLastFrame = false; + m_ClockState = 1; + CounterOnLastFrame[0] = false; + CounterOnLastFrame[1] = false; + CounterOnLastFrame[2] = false; + m_ItemToFlash = ITEM_NONE; OddJob2Timer = 0; OddJob2OffTimer = 0.0f; OddJob2On = 0; OddJob2XOffset = 0.0f; - CounterFlashTimer = 0; + CounterFlashTimer[0] = 0; + CounterFlashTimer[1] = 0; + CounterFlashTimer[2] = 0; TimerOnLastFrame = false; TimerFlashTimer = 0; SpriteBrightness = 0; @@ -1676,7 +1750,9 @@ void CHud::Initialise() m_HideRadar = false; m_LastDisplayScore = CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney; + m_LastTimeEnergyLost = CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss; m_LastWanted = 0; + m_LastWeapon = 0; CTxdStore::PopCurrentTxd(); } @@ -1685,16 +1761,22 @@ void CHud::ReInitialise() { m_Wants_To_Draw_Hud = true; m_Wants_To_Draw_3dMarkers = true; + m_pLastZoneName = nil; GetRidOfAllHudMessages(); + m_pLastVehicleName = nil; - CounterOnLastFrame = false; + CounterOnLastFrame[0] = false; + CounterOnLastFrame[1] = false; + CounterOnLastFrame[2] = false; m_ItemToFlash = ITEM_NONE; - m_DrawClock = 1; + m_ClockState = 1; OddJob2Timer = 0; OddJob2OffTimer = 0.0f; OddJob2On = 0; OddJob2XOffset = 0.0f; - CounterFlashTimer = 0; + CounterFlashTimer[0] = 0; + CounterFlashTimer[1] = 0; + CounterFlashTimer[2] = 0; TimerOnLastFrame = false; TimerFlashTimer = 0; SpriteBrightness = 0; @@ -1725,15 +1807,20 @@ void CHud::ReInitialise() { m_HideRadar = false; m_LastDisplayScore = CWorld::Players[CWorld::PlayerInFocus].m_nVisibleMoney; + m_LastTimeEnergyLost = CWorld::Players[CWorld::PlayerInFocus].m_nTimeLastHealthLoss; m_LastWanted = 0; + m_LastWeapon = 0; } wchar LastBigMessage[6][128]; -void CHud::SetBigMessage(wchar *message, int16 style) +void CHud::SetBigMessage(wchar *message, uint16 style) { int i = 0; + if (BigMessageInUse[style] != 0.0f) + return; + if (style == 5) { for (i = 0; i < 128; i++) { if (message[i] == 0) @@ -1758,18 +1845,42 @@ void CHud::SetBigMessage(wchar *message, int16 style) m_BigMessage[style][i] = 0; } -void CHud::SetHelpMessage(wchar *message, bool quick) +void CHud::SetHelpMessage(wchar *message, bool quick, bool displayForever) { if (!CReplay::IsPlayingBack()) { - CMessages::WideStringCopy(m_HelpMessage, message, 256); - CMessages::InsertPlayerControlKeysInString(m_HelpMessage); - - for (int i = 0; i < 256; i++) { + for (int i = 0; i < HELP_MSG_LENGTH; i++) { + m_HelpMessage[i] = 0; + } + for (int i = 0; i < HELP_MSG_LENGTH; i++) { m_LastHelpMessage[i] = 0; } + for (int i = 0; i < HELP_MSG_LENGTH; i++) { + m_HelpMessageToPrint[i] = 0; + } + + CMessages::WideStringCopy(m_HelpMessage, message, HELP_MSG_LENGTH); + CMessages::InsertPlayerControlKeysInString(m_HelpMessage); + if (m_HelpMessageState == 0 || !CMessages::WideStringCompare(m_HelpMessage, m_HelpMessageToPrint, HELP_MSG_LENGTH)) { + for (int i = 0; i < HELP_MSG_LENGTH; i++) { + m_LastHelpMessage[i] = 0; + } + + if (!message) { + m_HelpMessage[0] = 0; + m_HelpMessageToPrint[0] = 0; + } + if (!displayForever) { + m_HelpMessageState = displayForever; + } else { + m_HelpMessageState = 1; + CMessages::WideStringCopy(m_HelpMessageToPrint, m_HelpMessage, HELP_MSG_LENGTH); + CMessages::WideStringCopy(m_LastHelpMessage, m_HelpMessage, HELP_MSG_LENGTH); + } + + m_HelpMessageQuick = quick; + m_HelpMessageDisplayForever = displayForever; + } - m_HelpMessageState = 0; - m_HelpMessageQuick = quick; } } @@ -1778,11 +1889,10 @@ bool CHud::IsHelpMessageBeingDisplayed(void) return m_HelpMessageState != 0; } - void CHud::SetMessage(wchar *message) { int i = 0; - for (i = 0; i < 256; i++) { + for (i = 0; i < ARRAY_SIZE(m_Message); i++) { if (message[i] == 0) break; @@ -1794,7 +1904,7 @@ void CHud::SetMessage(wchar *message) void CHud::SetPagerMessage(wchar *message) { int i = 0; - for (i = 0; i < 256; i++) { + for (i = 0; i < ARRAY_SIZE(m_PagerMessage); i++) { if (message[i] == 0) break; @@ -1825,6 +1935,15 @@ void CHud::Shutdown() RwTextureDestroy(gpRocketSightTex); gpRocketSightTex = nil; + RwTextureDestroy(gpLaserSightTex); + gpLaserSightTex = nil; + + RwTextureDestroy(gpLaserDotTex); + gpLaserDotTex = nil; + + RwTextureDestroy(gpViewFinderTex); + gpViewFinderTex = nil; + int HudTXD = CTxdStore::FindTxdSlot("hud"); CTxdStore::RemoveTxdSlot(HudTXD); } diff --git a/src/render/Hud.h b/src/render/Hud.h index f4c0d8c4..a4b9609a 100644 --- a/src/render/Hud.h +++ b/src/render/Hud.h @@ -1,6 +1,11 @@ #pragma once #include "Sprite2d.h" +#define HELP_MSG_LENGTH 256 + +#define HUD_TEXT_SCALE_X 0.7f +#define HUD_TEXT_SCALE_Y 1.25f + enum eItems { ITEM_NONE = -1, @@ -31,41 +36,29 @@ enum eFadeOperation enum eSprites { HUD_FIST, - HUD_BAT, - HUD_PISTOL, - HUD_UZI, - HUD_SHOTGUN, - HUD_AK47, - HUD_M16, - HUD_SNIPER, - HUD_ROCKET, - HUD_FLAME, - HUD_MOLOTOV, - HUD_GRENADE, - HUD_DETONATOR, - HUD_RADARDISC = 15, - HUD_PAGER = 16, - HUD_SITESNIPER = 20, + HUD_SITEROCKET = 41, + HUD_RADARDISC = 50, + HUD_SITESNIPER = 63, HUD_SITEM16, - HUD_SITEROCKET, - NUM_HUD_SPRITES, + HUD_SITELASER, + HUD_LASERDOT, + HUD_VIEWFINDER, + HUD_BLEEDER, + NUM_HUD_SPRITES = 69, }; -#define HUD_TEXT_SCALE_X 0.7f -#define HUD_TEXT_SCALE_Y 1.25f - class CHud { public: static CSprite2d Sprites[NUM_HUD_SPRITES]; - static wchar m_HelpMessage[256]; - static wchar m_LastHelpMessage[256]; + static wchar m_HelpMessage[HELP_MSG_LENGTH]; + static wchar m_LastHelpMessage[HELP_MSG_LENGTH]; static uint32 m_HelpMessageState; static uint32 m_HelpMessageTimer; static int32 m_HelpMessageFadeTimer; - static wchar m_HelpMessageToPrint[256]; - static float &m_HelpMessageDisplayTime; - static float m_fHelpMessageTime; + static wchar m_HelpMessageToPrint[HELP_MSG_LENGTH]; + static float m_HelpMessageDisplayTime; + static bool m_HelpMessageDisplayForever; static bool m_HelpMessageQuick; static uint32 m_ZoneState; static int32 m_ZoneFadeTimer; @@ -86,16 +79,16 @@ public: static wchar m_BigMessage[6][128]; static int16 m_ItemToFlash; static bool m_HideRadar; - static int32 m_DrawClock; + static int32 m_ClockState; // These aren't really in CHud static float BigMessageInUse[6]; static float BigMessageAlpha[6]; static float BigMessageX[6]; static float OddJob2OffTimer; - static bool CounterOnLastFrame; + static bool CounterOnLastFrame[NUMONSCREENCOUNTERS]; static float OddJob2XOffset; - static uint16 CounterFlashTimer; + static uint16 CounterFlashTimer[NUMONSCREENCOUNTERS]; static uint16 OddJob2Timer; static bool TimerOnLastFrame; static int16 OddJob2On; @@ -121,6 +114,8 @@ public: static uint32 m_LastDisplayScore; static uint32 m_LastWanted; + static uint32 m_LastWeapon; + static uint32 m_LastTimeEnergyLost; public: static void Draw(); @@ -131,8 +126,8 @@ public: #endif static void Initialise(); static void ReInitialise(); - static void SetBigMessage(wchar *message, int16 style); - static void SetHelpMessage(wchar *message, bool quick); + static void SetBigMessage(wchar *message, uint16 style); + static void SetHelpMessage(wchar *message, bool quick, bool displayForever = false); static bool IsHelpMessageBeingDisplayed(void); static void SetMessage(wchar *message); static void SetPagerMessage(wchar *message); diff --git a/src/render/Occlusion.cpp b/src/render/Occlusion.cpp index 1ea9da50..79ce0461 100644 --- a/src/render/Occlusion.cpp +++ b/src/render/Occlusion.cpp @@ -366,6 +366,12 @@ COcclusion::ProcessBeforeRendering(void) } NumActiveOccluders--; i--; + // Taken from Mobile! +#ifdef FIX_BUGS + if (i == -1) { + i = 0; + } +#endif } } } @@ -481,4 +487,4 @@ void COcclusion::Render() { DefinedState(); } -#endif \ No newline at end of file +#endif diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 2f0c3809..6a42bc4d 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -1220,8 +1220,11 @@ void CParticle::Update() if ( psystem->m_Type == PARTICLE_HEATHAZE || psystem->m_Type == PARTICLE_HEATHAZE_IN_DIST ) { +#ifdef FIX_BUGS + int32 nSinCosIndex = (int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) + SIN_COS_TABLE_SIZE) % SIN_COS_TABLE_SIZE; +#else int32 nSinCosIndex = int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) % SIN_COS_TABLE_SIZE; - +#endif vecMoveStep.x = Sin(nSinCosIndex); vecMoveStep.y = Sin(nSinCosIndex); @@ -1233,8 +1236,11 @@ void CParticle::Update() if ( psystem->m_Type == PARTICLE_BEASTIE ) { +#ifdef FIX_BUGS + int32 nSinCosIndex = (int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) + SIN_COS_TABLE_SIZE) % SIN_COS_TABLE_SIZE; +#else int32 nSinCosIndex = int32(DEGTORAD((float)particle->m_nRotation) * float(SIN_COS_TABLE_SIZE) / TWOPI) % SIN_COS_TABLE_SIZE; - +#endif particle->m_vecVelocity.x = 0.50f * Cos(nSinCosIndex); particle->m_vecVelocity.y = Cos(nSinCosIndex); particle->m_vecVelocity.z = 0.25f * Sin(nSinCosIndex); @@ -1750,7 +1756,11 @@ void CParticle::Update() } if ( particle->m_nRotationStep != 0 ) +#ifdef FIX_BUGS + particle->m_nRotation = CGeneral::LimitAngle(particle->m_nRotation + particle->m_nRotationStep); +#else particle->m_nRotation += particle->m_nRotationStep; +#endif if ( particle->m_fCurrentZRadius != 0.0f ) { @@ -2403,7 +2413,7 @@ void CParticle::HandleShootableBirdsStuff(CEntity *entity, CVector const&camPos) { float fHeadingRad = entity->GetForward().Heading(); float fHeading = RADTODEG(fHeadingRad); - float fBirdAngle = Cos(DEGTORAD(1.5f)); + float fBirdAngle = ::Cos(DEGTORAD(1.5f)); tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[PARTICLE_BIRD_FRONT]; CParticle *particle = psystem->m_pParticles; diff --git a/src/render/WaterCannon.cpp b/src/render/WaterCannon.cpp index 2b34db37..bd2b9a68 100644 --- a/src/render/WaterCannon.cpp +++ b/src/render/WaterCannon.cpp @@ -77,9 +77,13 @@ void CWaterCannon::Update_OncePerFrame(int16 index) } } - int32 extinguishingPoint = CGeneral::GetRandomNumber() & (NUM_SEGMENTPOINTS - 1); - if ( m_abUsed[extinguishingPoint] ) - gFireManager.ExtinguishPoint(m_avecPos[extinguishingPoint], 3.0f); + for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ ) + { + if ( m_abUsed[i] && gFireManager.ExtinguishPointWithWater(m_avecPos[i], 4.0f) ) + { + break; + } + } if ( ((index + CTimer::GetFrameCounter()) & 3) == 0 ) PushPeds(); diff --git a/src/render/WaterCreatures.cpp b/src/render/WaterCreatures.cpp new file mode 100644 index 00000000..90f24183 --- /dev/null +++ b/src/render/WaterCreatures.cpp @@ -0,0 +1,267 @@ +#include "WaterCreatures.h" +#include "ModelIndices.h" +#include "World.h" +#include "WaterLevel.h" +#include "Camera.h" +#include "PlayerPed.h" +#include "config.h" +#include "General.h" + +int CWaterCreatures::nNumActiveSeaLifeForms; +CWaterCreature CWaterCreatures::aWaterCreatures[NUM_WATER_CREATURES]; + +struct WaterCreatureProperties aProperties[65] = { + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_JELLYFISH, 0.01f, 2.2f, 0.0005f, 3.5f }, + { &MI_JELLYFISH01, 0.01f, 2.2f, 0.0005f, 3.5f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_TURTLE, 0.01f, 2.0f, 0.0005f, 4.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_DOLPHIN, 0.03f, 1.5f, 0.0005f, 4.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_SHARK, 0.03f, 0.4f, 0.0005f, 4.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH1SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH2SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH2S, 0.04f, 1.5f, 0.0008f, 3.0f }, + { &MI_FISH3SINGLE, 0.04f, 3.0f, 0.0008f, 3.0f }, + { &MI_FISH3S, 0.04f, 1.5f, 0.0008f, 3.0f }, +}; + +CWaterCreature::CWaterCreature() { + Free(); +} + +CWaterCreature::~CWaterCreature() { + //looks like unused +} + +void CWaterCreature::Initialise(CObject *pObj, float fRightMult, float fZTurnSpeed, float fWaterDepth, uint32 alpha, eFishSlotState state) { + this->m_pObj = pObj; + this->m_fRightMult = fRightMult; + this->m_fZTurnSpeed = fZTurnSpeed; + this->m_fWaterDepth = fWaterDepth; + this->m_alpha = alpha; + this->m_state = state; +} + +void CWaterCreature::Allocate(CObject *pObj, float fRightMult, float fZTurnSpeed, float fWaterDepth, uint32 alpha, eFishSlotState state) { + CWaterCreature::Initialise(pObj, fRightMult, fZTurnSpeed, fWaterDepth, alpha, state); +} + +void CWaterCreature::Free() { + CWaterCreature::Initialise(nil, 0.0f, 0.0f, 0.0f, 0, WATER_CREATURE_DISABLED); +} + +CWaterCreature *CWaterCreatures::GetFishStructSlot() { + for (int i = 0; i < NUM_WATER_CREATURES; i++) + if (aWaterCreatures[i].m_state == WATER_CREATURE_DISABLED) + return &aWaterCreatures[i]; + + return nil; +} + +CObject *CWaterCreatures::CreateSeaLifeForm(CVector const& pos, int16 modelID, int32 zRotAngle) { + if (CObject::nNoTempObjects >= 40) + return nil; + + CObject *pObj = new CObject(modelID, true); + + if (!pObj) return nil; + + pObj->GetMatrix().GetPosition() = pos; + pObj->GetMatrix().UpdateRW(); + pObj->m_vecMoveSpeed = CVector(0.0f, 0.0f, 0.0f); + pObj->m_vecTurnSpeed = CVector(0.0f, 0.0f, 0.0f); + pObj->GetMatrix().SetRotateZOnly(DEGTORAD(zRotAngle)); + pObj->GetMatrix().UpdateRW(); + pObj->ObjectCreatedBy = CONTROLLED_SUB_OBJECT; + pObj->bIsStatic = false; + + if (pObj->ObjectCreatedBy == TEMP_OBJECT) { + CObject::nNoTempObjects++; + pObj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 60000; + } + + pObj->bTouchingWater = true; + pObj->bUnderwater = true; + CWorld::Add(pObj); + + return pObj; +} + +bool CWaterCreatures::IsSpaceForMoreWaterCreatures() { + return nNumActiveSeaLifeForms < NUM_WATER_CREATURES; +} + +float CWaterCreatures::CalculateFishHeading(CVector const& pos1, CVector const& pos2) { + CVector delta = pos1 - pos2; + delta.Normalise(); + + return Atan2(-delta.x, delta.y); +} + +void CWaterCreatures::CreateOne(CVector const& pos, int32 modelID) { + if (!IsSpaceForMoreWaterCreatures()) + return; + + CVector storedPos = pos; + float fDepth, fLevelNoWaves; + if (!TheCamera.IsSphereVisible(storedPos, 3.0f) + && CWaterLevel::GetWaterDepth(storedPos, &fDepth, &fLevelNoWaves, nil) && fDepth > 4.5f) { + + if (modelID == -1 || modelID < 0 || modelID > 64) + modelID = CGeneral::GetRandomNumberInRange(0, 64); + + WaterCreatureProperties *creature = &aProperties[modelID]; + storedPos.z = fLevelNoWaves - creature->fLevel; + float fRightMult = CGeneral::GetRandomNumberInRange(0.0f, creature->fRightMult) + 0.01f; + float angle = CWaterCreatures::CalculateFishHeading(FindPlayerPed()->GetPosition(), storedPos); + + CObject *fish = CreateSeaLifeForm(storedPos, *(int16*)creature->modelID, angle); + if (!fish) return; + + fish->SetRwObjectAlpha(255); + CWaterCreature *wc = GetFishStructSlot(); + wc->Allocate(fish, fRightMult, 0.0f, creature->fWaterDepth, 255, WATER_CREATURE_ALLOCATED); + nNumActiveSeaLifeForms++; + } +} + +void CWaterCreatures::FreeFishStructSlot(CWaterCreature *wc) { + wc->Free(); +} + +void CWaterCreatures::UpdateAll() { + if (nNumActiveSeaLifeForms == 0) + return; + + CVector playerPos = FindPlayerPed()->GetPosition(); + for (int i = 0; i < NUM_WATER_CREATURES; i++) { + switch (aWaterCreatures[i].m_state) { + case WATER_CREATURE_ACTIVE: + aWaterCreatures[i].m_pObj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 40000; + if (!aWaterCreatures[i].m_pObj->GetIsOnScreen()) { + aWaterCreatures[i].m_pObj->SetRwObjectAlpha(0); + aWaterCreatures[i].m_state = WATER_CREATURE_TO_REMOVE; + break; + } + case WATER_CREATURE_ALLOCATED: { + if ((playerPos - aWaterCreatures[i].m_pObj->GetPosition()).Magnitude() < SQR(75.0f)) { + if (aWaterCreatures[i].m_alpha < 255) + aWaterCreatures[i].m_alpha = Min(aWaterCreatures[i].m_alpha + 4, 255); + aWaterCreatures[i].m_pObj->SetRwObjectAlpha(aWaterCreatures[i].m_alpha); + CVector newRight = aWaterCreatures[i].m_pObj->GetRight(); + newRight.Normalise(); + aWaterCreatures[i].m_pObj->m_vecMoveSpeed = newRight * aWaterCreatures[i].m_fRightMult; + aWaterCreatures[i].m_pObj->m_vecTurnSpeed = CVector(0.0f, 0.0f, aWaterCreatures[i].m_fZTurnSpeed); + aWaterCreatures[i].m_pObj->bIsStatic = false; + float fDepth = 0.0; + CWaterLevel::GetWaterDepth(aWaterCreatures[i].m_pObj->GetPosition(), &fDepth, nil, nil); + if (aWaterCreatures[i].m_fWaterDepth < fDepth) { + if (aWaterCreatures[i].m_pObj->m_nEndOfLifeTime - 40000 <= CTimer::GetTimeInMilliseconds()) + aWaterCreatures[i].m_state = WATER_CREATURE_ACTIVE; + } + else { + aWaterCreatures[i].m_state = WATER_CREATURE_UPDATE; + } + + } + else { + aWaterCreatures[i].m_state = WATER_CREATURE_TO_REMOVE; + } + break; + } + case WATER_CREATURE_UPDATE: { + aWaterCreatures[i].m_pObj->m_nEndOfLifeTime = CTimer::GetTimeInMilliseconds() + 40000; + if (aWaterCreatures[i].m_alpha <= 0) { + aWaterCreatures[i].m_state = WATER_CREATURE_TO_REMOVE; + } + else { + aWaterCreatures[i].m_alpha = Max(aWaterCreatures[i].m_alpha - 6, 0); + aWaterCreatures[i].m_pObj->SetRwObjectAlpha(aWaterCreatures[i].m_alpha); + CVector newRight = aWaterCreatures[i].m_pObj->GetRight(); + newRight.Normalise(); + newRight.x *= aWaterCreatures[i].m_fRightMult; + newRight.y *= aWaterCreatures[i].m_fRightMult; + newRight.z -= 0.015f; + aWaterCreatures[i].m_pObj->m_vecMoveSpeed = newRight; + + if (!aWaterCreatures[i].m_pObj->GetIsOnScreen()) + aWaterCreatures[i].m_state = WATER_CREATURE_TO_REMOVE; + } + break; + } + case WATER_CREATURE_TO_REMOVE: + if (aWaterCreatures[i].m_pObj) + CWorld::Remove(aWaterCreatures[i].m_pObj); + FreeFishStructSlot(&aWaterCreatures[i]); + nNumActiveSeaLifeForms--; + aWaterCreatures[i].m_state = WATER_CREATURE_DISABLED; + break; + default: + break; + } + } +} + +void CWaterCreatures::RemoveAll() { + for (int i = 0; i < NUM_WATER_CREATURES; i++) { + if (aWaterCreatures[i].m_state != WATER_CREATURE_DISABLED) { + CWorld::Remove(aWaterCreatures[i].m_pObj); + FreeFishStructSlot(&aWaterCreatures[i]); + aWaterCreatures[i].m_state = WATER_CREATURE_DISABLED; + nNumActiveSeaLifeForms--; + } + } +} \ No newline at end of file diff --git a/src/render/WaterCreatures.h b/src/render/WaterCreatures.h new file mode 100644 index 00000000..7dcaa288 --- /dev/null +++ b/src/render/WaterCreatures.h @@ -0,0 +1,49 @@ +#pragma once +#include "Object.h" + +enum eFishSlotState { + WATER_CREATURE_ALLOCATED = 0, + WATER_CREATURE_ACTIVE, + WATER_CREATURE_UPDATE, + WATER_CREATURE_TO_REMOVE, + WATER_CREATURE_DISABLED +}; + +class CWaterCreature { +public: + CObject *m_pObj; + float m_fRightMult; + float m_fZTurnSpeed; + int32 m_alpha; + float m_fWaterDepth; + int32 m_state; + + CWaterCreature(); + ~CWaterCreature(); + void Allocate(CObject *pObj, float fRightMult, float fZTurnSpeed, float fWaterDepth, uint32 alpha, eFishSlotState state); + void Free(); + void Initialise(CObject *pObj, float fRightMult, float fZTurnSpeed, float fWaterDepth, uint32 alpha, eFishSlotState state); +}; + +class CWaterCreatures { + +public: + static CWaterCreature aWaterCreatures[NUM_WATER_CREATURES]; + static int32 nNumActiveSeaLifeForms; + static CObject *CreateSeaLifeForm(CVector const& pos, int16 modelID, int32 zRotAngle); + static void CreateOne(CVector const& pos, int32 modelID); + static void UpdateAll(); + static void FreeFishStructSlot(CWaterCreature *wc); + static bool IsSpaceForMoreWaterCreatures(); + static float CalculateFishHeading(CVector const& pos1, CVector const& pos2); + static void RemoveAll(); + static CWaterCreature* GetFishStructSlot(); +}; + +struct WaterCreatureProperties { + int16 *modelID; + float fRightMult; + float fLevel; + float fUnknown; //unused + float fWaterDepth; +}; \ No newline at end of file diff --git a/src/render/WaterLevel.cpp b/src/render/WaterLevel.cpp index efcb6c14..ec9485d2 100644 --- a/src/render/WaterLevel.cpp +++ b/src/render/WaterLevel.cpp @@ -27,6 +27,7 @@ #include "Replay.h" #include "WaterLevel.h" #include "SurfaceTable.h" +#include "WaterCreatures.h" #define RwIm3DVertexSet_RGBA(vert, rgba) RwIm3DVertexSetRGBA(vert, rgba.red, rgba.green, rgba.blue, rgba.alpha) // (RwRGBAAssign(&(_dst)->color, &_src)) @@ -2821,8 +2822,7 @@ CWaterLevel::HandleSeaLifeForms() } else if ( (CTimer::GetTimeInMilliseconds() - timecounter) > 5000 ) { -//TODO(MIAMI) -// if ( CWaterCreatures::IsSpaceForMoreWaterCreatures() ) + if ( CWaterCreatures::IsSpaceForMoreWaterCreatures() ) { for ( int32 i = 0; i < 3; i++ ) { @@ -2838,14 +2838,12 @@ CWaterLevel::HandleSeaLifeForms() vecPos.x += (fCos - fSin) * fAngle; vecPos.y += (fSin + fCos) * fAngle; - //TODO(MIAMI) - //CWaterCreatures::CreateOne(vecPos, 0xFFFFFFFF); + CWaterCreatures::CreateOne(vecPos, -1); } } } - //TODO(MIAMI) - //CWaterCreatures::UpdateAll(); + CWaterCreatures::UpdateAll(); } void diff --git a/src/rw/Lights.h b/src/rw/Lights.h index b296816b..c3543d77 100644 --- a/src/rw/Lights.h +++ b/src/rw/Lights.h @@ -22,3 +22,4 @@ void SetAmbientColours(void); void SetAmbientColoursForPedsCarsAndObjects(void); void SetAmbientColoursToIndicateRoadGroup(int i); void SetAmbientColours(RwRGBAReal *color); +void SetFullAmbient(void); diff --git a/src/save/GenericGameStorage.cpp b/src/save/GenericGameStorage.cpp index b98b8243..18eecd95 100644 --- a/src/save/GenericGameStorage.cpp +++ b/src/save/GenericGameStorage.cpp @@ -11,6 +11,7 @@ #include "Clock.h" #include "Date.h" #include "FileMgr.h" +#include "Font.h" #include "Frontend.h" #include "GameLogic.h" #include "Gangs.h" diff --git a/src/save/PCSave.cpp b/src/save/PCSave.cpp index 6449d586..dd0926cf 100644 --- a/src/save/PCSave.cpp +++ b/src/save/PCSave.cpp @@ -3,6 +3,7 @@ #include "crossplatform.h" #include "FileMgr.h" +#include "Font.h" #ifdef MORE_LANGUAGES #include "Game.h" #endif 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 b40130c4..08e5c021 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 +#else +#include +#include +#endif #include #include #include #include #endif + +#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS +char gSelectedJoystickName[128] = ""; +#endif + /* ***************************************************************************** */ @@ -424,6 +433,10 @@ psInitialize(void) _dwOperatingSystemVersion = OS_WIN95; } } +#else + _dwOperatingSystemVersion = OS_WINXP; // To fool other classes +#endif + #ifndef PS2_MENU @@ -433,6 +446,8 @@ psInitialize(void) #endif + +#ifdef _WIN32 MEMORYSTATUS memstats; GlobalMemoryStatus(&memstats); @@ -440,26 +455,44 @@ 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; +#ifndef __APPLE__ + 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); - +#else + 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); #endif - TheText.Unload(); + _dwOperatingSystemVersion = OS_WINXP; // To fool other classes +#endif + + TheText.Unload(); return TRUE; } @@ -826,35 +859,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) @@ -869,6 +893,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); } } @@ -1211,7 +1238,9 @@ void terminateHandler(int sig, siginfo_t *info, void *ucontext) { } void dummyHandler(int sig){ + // Don't kill the app pls } + #endif void resizeCB(GLFWwindow* window, int width, int height) { @@ -1458,9 +1487,10 @@ main(int argc, char *argv[]) act.sa_flags = SA_SIGINFO; sigaction(SIGTERM, &act, NULL); struct sigaction sa; + sigemptyset(&sa.sa_mask); sa.sa_handler = dummyHandler; sa.sa_flags = 0; - sigaction(SIGINT, &sa, NULL); // Needed for CdStreamPosix + sigaction(SIGUSR1, &sa, NULL); // Needed for CdStreamPosix #endif /* @@ -2084,18 +2114,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 b98d5710..1d1037af 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -3414,4 +3414,4 @@ int strncasecmp(const char *str1, const char *str2, size_t len) return _strnicmp(str1, str2, len); } #endif -#endif \ No newline at end of file +#endif diff --git a/src/text/Text.cpp b/src/text/Text.cpp index 64f303eb..5adc576a 100644 --- a/src/text/Text.cpp +++ b/src/text/Text.cpp @@ -9,11 +9,12 @@ #include "Text.h" #include "Timer.h" +//--MIAMI: file done + static wchar WideErrorString[25]; CText TheText; -//--MIAMI: DONE CText::CText(void) { encoding = 'e'; @@ -23,7 +24,6 @@ CText::CText(void) memset(WideErrorString, 0, sizeof(WideErrorString)); } -//--MIAMI: DONE void CText::Load(void) { @@ -95,7 +95,6 @@ CText::Load(void) CFileMgr::SetDir(""); } -//--MIAMI: DONE void CText::Unload(void) { @@ -108,7 +107,6 @@ CText::Unload(void) memset(szMissionTableName, 0, sizeof(szMissionTableName)); } -//--MIAMI: DONE wchar* CText::Get(const char *key) { @@ -158,7 +156,6 @@ wchar FrenchUpperCaseTable[128] = { 253, 254, 255 }; -//--MIAMI: TODO (check tables) wchar CText::GetUpperCase(wchar c) { @@ -190,7 +187,6 @@ CText::GetUpperCase(wchar c) return c; } -//--MIAMI: DONE void CText::UpperCase(wchar *s) { @@ -200,27 +196,33 @@ CText::UpperCase(wchar *s) } } -//--MIAMI: DONE void CText::GetNameOfLoadedMissionText(char *outName) { strcpy(outName, szMissionTableName); } -//--MIAMI: DONE void CText::ReadChunkHeader(ChunkHeader *buf, int32 file, size_t *offset) { +#if DUMB + char *_buf = (char*)buf; + for (int i = 0; i < sizeof(ChunkHeader); i++) { + CFileMgr::Read(file, &_buf[i], 1); + (*offset)++; + } +#else // original code loops 8 times to read 1 byte with CFileMgr::Read, that's retarded CFileMgr::Read(file, (char*)buf, sizeof(ChunkHeader)); *offset += sizeof(ChunkHeader); +#endif } -//--MIAMI: DONE void CText::LoadMissionText(char *MissionTableName) { char filename[32]; + CMessages::ClearAllMessagesDisplayedByGame(); mission_keyArray.Unload(); mission_data.Unload(); @@ -306,7 +308,6 @@ CText::LoadMissionText(char *MissionTableName) } -//--MIAMI: DONE void CKeyArray::Load(size_t length, int file, size_t* offset) { @@ -318,14 +319,16 @@ CKeyArray::Load(size_t length, int file, size_t* offset) rawbytes = (char*)entries; #if DUMB - for (uint32 i = 0; i < length; i++) + for (uint32 i = 0; i < length; i++) { CFileMgr::Read(file, &rawbytes[i], 1); + (*offset)++; + } #else CFileMgr::Read(file, rawbytes, length); + *offset += length; #endif } -//--MIAMI: DONE void CKeyArray::Unload(void) { @@ -334,7 +337,6 @@ CKeyArray::Unload(void) numEntries = 0; } -//--MIAMI: DONE void CKeyArray::Update(wchar *chars) { @@ -345,7 +347,6 @@ CKeyArray::Update(wchar *chars) #endif } -//--MIAMI: DONE CKeyEntry* CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) { @@ -366,7 +367,6 @@ CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 hi return nil; } -//--MIAMI: DONE wchar* #ifdef FIX_BUGS CKeyArray::Search(const char *key, wchar *data, uint8 *result) @@ -402,7 +402,6 @@ CKeyArray::Search(const char *key, uint8 *result) return WideErrorString; } -//--MIAMI: DONE void CData::Load(size_t length, int file, size_t * offset) { @@ -414,14 +413,16 @@ CData::Load(size_t length, int file, size_t * offset) rawbytes = (char*)chars; #if DUMB - for(uint32 i = 0; i < length; i++) + for(uint32 i = 0; i < length; i++){ CFileMgr::Read(file, &rawbytes[i], 1); + (*offset)++; + } #else CFileMgr::Read(file, rawbytes, length); + *offset += length; #endif } -//--MIAMI: DONE void CData::Unload(void) { @@ -430,22 +431,31 @@ CData::Unload(void) numChars = 0; } -//--MIAMI: DONE void CMissionTextOffsets::Load(size_t table_size, int file, size_t *offset, int) { +#if DUMB + size_t num_of_entries = table_size / sizeof(CMissionTextOffsets::Entry); + for (size_t mi = 0; mi < num_of_entries; mi++) { + for (uint32 i = 0; i < sizeof(data[mi].szMissionName); i++) { + CFileMgr::Read(file, &data[i].szMissionName[i], 1); + (*offset)++; + } + char* _buf = (char*)&data[mi].offset; + for (uint32 i = 0; i < sizeof(data[mi].offset); i++) { + CFileMgr::Read(file, &_buf[i], 1); + (*offset)++; + } + } + size = (uint16)num_of_entries; +#else // not exact VC code but smaller and better :P // You can make this size_t if you want to exceed 32-bit boundaries, everything else should be ready. size = (uint16) (table_size / sizeof(CMissionTextOffsets::Entry)); CFileMgr::Read(file, (char*)data, sizeof(CMissionTextOffsets::Entry) * size); *offset += sizeof(CMissionTextOffsets::Entry) * size; -} - -void -AsciiToUnicode(const char *src, wchar *dst) -{ - while((*dst++ = (unsigned char)*src++) != '\0'); +#endif } char* @@ -460,8 +470,29 @@ UnicodeToAscii(wchar *src) if(*src < 128) #endif aStr[len] = *src; - else - aStr[len] = '#'; + // convert to CP1252 + else if(*src <= 131) + aStr[len] = *src + 64; + else if (*src <= 141) + aStr[len] = *src + 66; + else if (*src <= 145) + aStr[len] = *src + 68; + else if (*src <= 149) + aStr[len] = *src + 71; + else if (*src <= 154) + aStr[len] = *src + 73; + else if (*src <= 164) + aStr[len] = *src + 75; + else if (*src <= 168) + aStr[len] = *src + 77; + else if (*src <= 204) + aStr[len] = *src + 80; + else switch (*src) { + case 205: aStr[len] = 209; break; + case 206: aStr[len] = 241; break; + case 207: aStr[len] = 191; break; + default: aStr[len] = '#'; break; + } aStr[len] = '\0'; return aStr; } @@ -471,7 +502,7 @@ UnicodeToAsciiForSaveLoad(wchar *src) { static char aStr[256]; int len; - for(len = 0; *src != '\0' && len < 256-1; len++, src++) + for(len = 0; *src != '\0' && len < 256; len++, src++) if(*src < 256) aStr[len] = *src; else @@ -485,7 +516,7 @@ UnicodeToAsciiForMemoryCard(wchar *src) { static char aStr[256]; int len; - for(len = 0; *src != '\0' && len < 256-1; len++, src++) + for(len = 0; *src != '\0' && len < 256; len++, src++) if(*src < 256) aStr[len] = *src; else @@ -494,42 +525,8 @@ UnicodeToAsciiForMemoryCard(wchar *src) return aStr; } -void -UnicodeMakeUpperCase(wchar *dst, wchar *src) //idk what to do with it, seems to be incorrect implementation by R* -{ - while (*src != '\0') { - if (*src < 'a' || *src > 'z') - *dst = *src; - else - *dst = *src - 32; - dst++; - src++; - } - *dst = '\0'; -} - -void -UnicodeStrcpy(wchar *dst, const wchar *src) -{ - while((*dst++ = *src++) != '\0'); -} - -void -UnicodeStrcat(wchar *dst, wchar *append) -{ - UnicodeStrcpy(&dst[UnicodeStrlen(dst)], append); -} - -int -UnicodeStrlen(const wchar *str) -{ - int len; - for(len = 0; *str != '\0'; len++, str++); - return len; -} - void TextCopy(wchar *dst, const wchar *src) { while((*dst++ = *src++) != '\0'); -} \ No newline at end of file +} diff --git a/src/text/Text.h b/src/text/Text.h index 0bad9a83..33dc313e 100644 --- a/src/text/Text.h +++ b/src/text/Text.h @@ -1,14 +1,9 @@ #pragma once -void AsciiToUnicode(const char *src, wchar *dst); char *UnicodeToAscii(wchar *src); char *UnicodeToAsciiForSaveLoad(wchar *src); char *UnicodeToAsciiForMemoryCard(wchar *src); -void UnicodeStrcpy(wchar *dst, const wchar *src); -void UnicodeStrcat(wchar *dst, wchar *append); -int UnicodeStrlen(const wchar *str); void TextCopy(wchar *dst, const wchar *src); -void UnicodeMakeUpperCase(wchar *dst, wchar *src); struct CKeyEntry { diff --git a/src/vehicles/CarGen.cpp b/src/vehicles/CarGen.cpp index b0fa91a4..598b8342 100644 --- a/src/vehicles/CarGen.cpp +++ b/src/vehicles/CarGen.cpp @@ -28,8 +28,13 @@ uint32 CTheCarGenerators::CurrentActiveCount; void CCarGenerator::SwitchOff() { - m_nUsesRemaining = 0; - --CTheCarGenerators::CurrentActiveCount; +#ifdef FIX_BUGS + if (m_nUsesRemaining != 0) +#endif + { + m_nUsesRemaining = 0; + --CTheCarGenerators::CurrentActiveCount; + } } void CCarGenerator::SwitchOn() diff --git a/src/vehicles/Heli.cpp b/src/vehicles/Heli.cpp index a770f83d..2c2fb33c 100644 --- a/src/vehicles/Heli.cpp +++ b/src/vehicles/Heli.cpp @@ -1011,14 +1011,16 @@ CHeli::TestSniperCollision(CVector *line0, CVector *line1) bool hit = false; for(i = 0; i < NUM_HELIS; i++){ - CVector pilotPos = pHelis[i]->GetMatrix() * CVector(-0.43f, 1.49f, 1.5f); - if(pHelis[i] && !pHelis[i]->bBulletProof && CCollision::DistToLine(line0, line1, &pilotPos) < 0.8f){ - pHelis[i]->m_fAngularSpeed = CGeneral::GetRandomTrueFalse() ? 0.05f : -0.05f; - pHelis[i]->m_heliStatus = HELI_STATUS_SHOT_DOWN; - pHelis[i]->m_nExplosionTimer = CTimer::GetTimeInMilliseconds() + 9999999; - pHelis[i]->m_numSwat = 0; + if(pHelis[i] && !pHelis[i]->bBulletProof) { + CVector pilotPos = pHelis[i]->GetMatrix() * CVector(-0.43f, 1.49f, 1.5f); + if(CCollision::DistToLine(line0, line1, &pilotPos) < 0.8f){ + pHelis[i]->m_fAngularSpeed = CGeneral::GetRandomTrueFalse() ? 0.05f : -0.05f; + pHelis[i]->m_heliStatus = HELI_STATUS_SHOT_DOWN; + pHelis[i]->m_nExplosionTimer = CTimer::GetTimeInMilliseconds() + 9999999; + pHelis[i]->m_numSwat = 0; - hit = true; + hit = true; + } } } return hit; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 6e86dbe4..994f3c99 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -1303,7 +1303,7 @@ CVehicle::InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage } } #ifdef FIX_BUGS // removing dumb case when shooting police car in player's own garage gives wanted level - if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && !bHasBeenOwnedByPlayer) + if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed() && damagedBy != nil && !bHasBeenOwnedByPlayer) #else if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed()) #endif diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 705fca3a..004f1fd9 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -187,7 +187,7 @@ public: CAutoPilot AutoPilot; uint8 m_currentColour1; uint8 m_currentColour2; - uint8 m_aExtras[2]; + int8 m_aExtras[2]; int16 m_nAlarmState; int16 m_nRouteSeed; CPed *pDriver; diff --git a/src/weapons/WeaponInfo.cpp b/src/weapons/WeaponInfo.cpp index 6debf725..b911805d 100644 --- a/src/weapons/WeaponInfo.cpp +++ b/src/weapons/WeaponInfo.cpp @@ -249,28 +249,28 @@ CWeaponInfo::LoadWeaponData(void) ms_apWeaponInfos[weaponType].m_nModelId = modelId; ms_apWeaponInfos[weaponType].m_nModel2Id = modelId2; - ms_apWeaponInfos[weaponType].m_bUseGravity = flags; - ms_apWeaponInfos[weaponType].m_bSlowsDown = flags >> 1; - ms_apWeaponInfos[weaponType].m_bDissipates = flags >> 2; - ms_apWeaponInfos[weaponType].m_bRandSpeed = flags >> 3; - ms_apWeaponInfos[weaponType].m_bExpands = flags >> 4; - ms_apWeaponInfos[weaponType].m_bExplodes = flags >> 5; - ms_apWeaponInfos[weaponType].m_bCanAim = flags >> 6; - ms_apWeaponInfos[weaponType].m_bCanAimWithArm = flags >> 7; - ms_apWeaponInfos[weaponType].m_b1stPerson = flags >> 8; - ms_apWeaponInfos[weaponType].m_bHeavy = flags >> 9; - ms_apWeaponInfos[weaponType].m_bThrow = flags >> 10; - ms_apWeaponInfos[weaponType].m_bReloadLoop2Start = flags >> 11; - ms_apWeaponInfos[weaponType].m_bUse2nd = flags >> 12; - ms_apWeaponInfos[weaponType].m_bGround2nd = flags >> 13; - ms_apWeaponInfos[weaponType].m_bFinish3rd = flags >> 14; - ms_apWeaponInfos[weaponType].m_bReload = flags >> 15; - ms_apWeaponInfos[weaponType].m_bFightMode = flags >> 16; - ms_apWeaponInfos[weaponType].m_bCrouchFire = flags >> 17; - ms_apWeaponInfos[weaponType].m_bCop3rd = flags >> 18; - ms_apWeaponInfos[weaponType].m_bGround3rd = flags >> 19; - ms_apWeaponInfos[weaponType].m_bPartialAttack = flags >> 20; - ms_apWeaponInfos[weaponType].m_bAnimDetonate = flags >> 21; + ms_apWeaponInfos[weaponType].m_bUseGravity = flags & 1; + ms_apWeaponInfos[weaponType].m_bSlowsDown = (flags >> 1) & 1; + ms_apWeaponInfos[weaponType].m_bDissipates = (flags >> 2) & 1; + ms_apWeaponInfos[weaponType].m_bRandSpeed = (flags >> 3) & 1; + ms_apWeaponInfos[weaponType].m_bExpands = (flags >> 4) & 1; + ms_apWeaponInfos[weaponType].m_bExplodes = (flags >> 5) & 1; + ms_apWeaponInfos[weaponType].m_bCanAim = (flags >> 6) & 1; + ms_apWeaponInfos[weaponType].m_bCanAimWithArm = (flags >> 7) & 1; + ms_apWeaponInfos[weaponType].m_b1stPerson = (flags >> 8) & 1; + ms_apWeaponInfos[weaponType].m_bHeavy = (flags >> 9) & 1; + ms_apWeaponInfos[weaponType].m_bThrow = (flags >> 10) & 1; + ms_apWeaponInfos[weaponType].m_bReloadLoop2Start = (flags >> 11) & 1; + ms_apWeaponInfos[weaponType].m_bUse2nd = (flags >> 12) & 1; + ms_apWeaponInfos[weaponType].m_bGround2nd = (flags >> 13) & 1; + ms_apWeaponInfos[weaponType].m_bFinish3rd = (flags >> 14) & 1; + ms_apWeaponInfos[weaponType].m_bReload = (flags >> 15) & 1; + ms_apWeaponInfos[weaponType].m_bFightMode = (flags >> 16) & 1; + ms_apWeaponInfos[weaponType].m_bCrouchFire = (flags >> 17) & 1; + ms_apWeaponInfos[weaponType].m_bCop3rd = (flags >> 18) & 1; + ms_apWeaponInfos[weaponType].m_bGround3rd = (flags >> 19) & 1; + ms_apWeaponInfos[weaponType].m_bPartialAttack = (flags >> 20) & 1; + ms_apWeaponInfos[weaponType].m_bAnimDetonate = (flags >> 21) & 1; ms_apWeaponInfos[weaponType].m_nWeaponSlot = weaponSlot;