1
0
Fork 0
mirror of https://git.rip/DMCA_FUCKER/re3.git synced 2024-12-23 15:30:00 +00:00

Merge branch 'miami' of https://github.com/GTAmodding/re3 into miami

This commit is contained in:
Roman Masanin 2020-10-12 13:42:57 +03:00
commit 417646819c
67 changed files with 2558 additions and 1039 deletions

View file

@ -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
- 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
- CC=gcc-8 CXX=g++-8 make config=$TARGET -j4 verbose=1
- 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

32
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -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
}

89
.vscode/launch.json vendored Normal file
View file

@ -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"
}

30
.vscode/settings.json vendored Normal file
View file

@ -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
}

95
.vscode/tasks.json vendored Normal file
View file

@ -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"
}

107
CODING_STYLE.md Normal file
View file

@ -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

111
README.md
View file

@ -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

View file

@ -85,6 +85,12 @@ workspace "reVC"
"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" }
@ -101,6 +107,9 @@ workspace "reVC"
filter { "platforms:bsd*" }
system "bsd"
filter { "platforms:macosx*" }
system "macosx"
filter { "platforms:*x86*" }
architecture "x86"
@ -110,6 +119,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" }
if(not _OPTIONS["with-librw"]) then
@ -163,6 +179,13 @@ project "librw"
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" }
filter {}
@ -278,6 +301,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 {}
links { "libogg" }
@ -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" }

View file

@ -5,6 +5,7 @@
#include "AudioManager.h"
#include "AudioScriptObject.h"
#include "sampman.h"
#include "Font.h"
#include "Text.h"
#include "crossplatform.h"

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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);
}

View file

@ -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);

View file

@ -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)

View file

@ -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,51 +392,50 @@ 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
@ -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++ )
{

View file

@ -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",

View file

@ -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);

View file

@ -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);
}
}
}

View file

@ -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);

View file

@ -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();

View file

@ -2,6 +2,8 @@
#include <ctype.h>
// --MIAMI: file done
class CGeneral
{
public:

View file

@ -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;
}

View file

@ -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<ARRAY_SIZE(ms_pStreamingBuffer); i++) {
if (!first && streamIds[i] != -1) {
processI = i;
continue;
}
if(ms_endRequestedList.m_prev != &ms_startRequestedList){
streamId = GetNextFileOnCd(0, priority);
if(streamId == -1){
streamIds[i] = -1;
break;
}
if (ms_aInfoForModel[streamId].GetCdPosnAndSize(posn, size)) {
streamIds[i] = -1;
if (size > (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);

View file

@ -10,6 +10,8 @@
#include "World.h"
#include "Zones.h"
// --MIAMI: file done
CPlaceName CUserDisplay::PlaceName;
COnscreenTimer CUserDisplay::OnscnTimer;
CPager CUserDisplay::Pager;

View file

@ -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<eLevelName>(buffer);
FindIndex = ReadSaveBuf<int16>(buffer);
ReadSaveBuf<int16>(buffer);
m_CurrLevel = ReadSaveBuf<eLevelName>(buffer, length);
FindIndex = ReadSaveBuf<int16>(buffer, length);
ReadSaveBuf<int16>(buffer, length);
// TODO(MIAMI) ? implement LoadOneZone
for(i = 0; i < ARRAY_SIZE(NavigationZoneArray); i++){
NavigationZoneArray[i] = ReadSaveBuf<CZone>(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<CZone>(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<CZoneInfo>(buffer);
ZoneInfoArray[i] = ReadSaveBuf<CZoneInfo>(buffer, length);
TotalNumberOfNavigationZones = ReadSaveBuf<int16>(buffer);
TotalNumberOfInfoZones = ReadSaveBuf<int16>(buffer);
TotalNumberOfZoneInfos = ReadSaveBuf<int16>(buffer);
TotalNumberOfNavigationZones = ReadSaveBuf<int16>(buffer, length);
TotalNumberOfInfoZones = ReadSaveBuf<int16>(buffer, length);
TotalNumberOfZoneInfos = ReadSaveBuf<int16>(buffer, length);
ReadSaveBuf<int16>(buffer, length);
for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++){
MapZoneArray[i] = ReadSaveBuf<CZone>(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<int16>(buffer);
AudioZoneArray[i] = ReadSaveBuf<int16>(buffer, length);
TotalNumberOfMapZones = ReadSaveBuf<uint16>(buffer);
NumberOfAudioZones = ReadSaveBuf<uint16>(buffer);
TotalNumberOfMapZones = ReadSaveBuf<uint16>(buffer, length);
NumberOfAudioZones = ReadSaveBuf<uint16>(buffer, length);
VALIDATESAVEBUF(size)
}
void
CTheZones::LoadOneZone(CZone *zone, uint8 **buffer, uint32 *length, eZoneType zoneType)
{
*(uint32*)&zone->name[0] = ReadSaveBuf<uint32>(*buffer, *length);
*(uint32*)&zone->name[4] = ReadSaveBuf<uint32>(*buffer, *length);
zone->minx = ReadSaveBuf<float>(*buffer, *length);
zone->miny = ReadSaveBuf<float>(*buffer, *length);
zone->minz = ReadSaveBuf<float>(*buffer, *length);
zone->maxx = ReadSaveBuf<float>(*buffer, *length);
zone->maxy = ReadSaveBuf<float>(*buffer, *length);
zone->maxz = ReadSaveBuf<float>(*buffer, *length);
zone->type = ReadSaveBuf<eZoneType>(*buffer, *length);
zone->level = ReadSaveBuf<eLevelName>(*buffer, *length);
zone->zoneinfoDay = ReadSaveBuf<int16>(*buffer, *length);
zone->zoneinfoNight = ReadSaveBuf<int16>(*buffer, *length);
int32 zoneId;
zoneId = ReadSaveBuf<int32>(*buffer, *length);
zone->child = GetPointerForZoneIndex(zoneId);
zoneId = ReadSaveBuf<int32>(*buffer, *length);
zone->parent = GetPointerForZoneIndex(zoneId);
zoneId = ReadSaveBuf<int32>(*buffer, *length);
zone->next = GetPointerForZoneIndex(zoneId);
}

View file

@ -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);
};

View file

@ -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<<p & m;
return (w & ~m) | ((b<<p) & m);
}
inline uint32 ldb(uint32 p, uint32 s, uint32 w)
{
@ -412,6 +412,15 @@ inline void SkipSaveBuf(uint8 *&buf, int32 skip)
#endif
}
inline void SkipSaveBuf(uint8*& buf, uint32 &length, int32 skip)
{
buf += skip;
length += skip;
#ifdef VALIDATE_SAVE_SIZE
_saveBufCount += skip;
#endif
}
template<typename T>
inline const T ReadSaveBuf(uint8 *&buf)
{
@ -420,6 +429,14 @@ inline const T ReadSaveBuf(uint8 *&buf)
return value;
}
template<typename T>
inline const T ReadSaveBuf(uint8 *&buf, uint32 &length)
{
T &value = *(T*)buf;
SkipSaveBuf(buf, length, sizeof(T));
return value;
}
template<typename T>
inline T *WriteSaveBuf(uint8 *&buf, const T &value)
{
@ -429,6 +446,15 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
return p;
}
template<typename T>
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<uint32>(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<uint32>(buf, len, size);
#define CheckSaveHeader(buf,a,b,c,d,size)\
assert(ReadSaveBuf<char>(buf) == a);\
assert(ReadSaveBuf<char>(buf) == b);\
@ -446,5 +479,12 @@ inline T *WriteSaveBuf(uint8 *&buf, const T &value)
assert(ReadSaveBuf<char>(buf) == d);\
assert(ReadSaveBuf<uint32>(buf) == size);
#define CheckSaveHeaderWithLength(buf,len,a,b,c,d,size)\
assert(ReadSaveBuf<char>(buf,len) == a);\
assert(ReadSaveBuf<char>(buf,len) == b);\
assert(ReadSaveBuf<char>(buf,len) == c);\
assert(ReadSaveBuf<char>(buf,len) == d);\
assert(ReadSaveBuf<uint32>(buf,len) == size);
void cprintf(char*, ...);

View file

@ -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

View file

@ -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); }

View file

@ -1208,3 +1208,36 @@ 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;
}
}
}

View file

@ -179,6 +179,7 @@ public:
void ModifyMatrixForTreeInWind(void);
void ModifyMatrixForBannerInWind(void);
void ProcessLightsForEntity(void);
void SetRwObjectAlpha(int32 alpha);
static void AddSteamsFromGround(CPtrList& list);
};

314
src/extras/ini_parser.hpp Normal file
View file

@ -0,0 +1,314 @@
/*
* Copyright (c) 2013-2015 Denilson das Mercês Amorim <dma_2012@hotmail.com>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
*/
#ifndef LINB_INI_PARSER_HPP
#define LINB_INI_PARSER_HPP
/*
* STL-like INI Container
*/
#include <string> // for std::string
#include <map> // for std::map
#include <cstdio> // for std::FILE
#include <algorithm> // for std::find_if
#include <functional> // for std::function
namespace linb
{
template<
class CharT = char, /* Not compatible with other type here, since we're using C streams */
class StringType = std::basic_string<CharT>,
class KeyContainer = std::map<StringType, StringType>,
class SectionContainer = std::map<StringType, KeyContainer>
> class basic_ini
{
public:
typedef CharT char_type;
typedef StringType string_type;
typedef KeyContainer key_container;
typedef SectionContainer section_container;
// Typedef container values types
typedef typename section_container::value_type value_type;
typedef typename section_container::key_type key_type;
typedef typename section_container::mapped_type mapped_type;
// Typedef common types
typedef typename section_container::size_type size_type;
typedef typename section_container::difference_type difference_type;
// Typedef iterators
typedef typename section_container::iterator iterator;
typedef typename section_container::const_iterator const_iterator;
typedef typename section_container::reverse_iterator reverse_iterator;
typedef typename section_container::const_reverse_iterator const_reverse_iterator;
// typedef References and pointers
typedef typename section_container::reference reference;
typedef typename section_container::const_reference const_reference;
typedef typename section_container::pointer pointer;
typedef typename section_container::const_pointer const_pointer;
private:
section_container data;
public:
basic_ini()
{ }
basic_ini(const char_type* filename)
{ this->read_file(filename); }
/* Iterator methods */
iterator begin()
{ return data.begin(); }
const_iterator begin() const
{ return data.begin(); }
iterator end()
{ return data.end(); }
const_iterator end() const
{ return data.end(); }
const_iterator cbegin() const
{ return data.cbegin(); }
const_iterator cend() const
{ return data.cend(); }
/* Reverse iterator methods */
reverse_iterator rbegin()
{ return data.rbegin(); }
const_reverse_iterator rbegin() const
{ return data.rbegin(); }
reverse_iterator rend()
{ return data.rend(); }
const_reverse_iterator rend() const
{ return data.rend(); }
const_reverse_iterator crbegin() const
{ return data.crbegin(); }
const_reverse_iterator crend() const
{ return data.crend(); }
/* Acessing index methods */
mapped_type& operator[](const string_type& sect)
{ return data[sect]; }
mapped_type& operator[](string_type&& sect)
{ return data[std::forward<string_type>(sect)]; }
mapped_type& at( const string_type& sect)
{ return data.at(sect); }
const mapped_type& at(const string_type& sect) const
{ return data.at(sect); }
/* Capacity information */
bool empty() const
{ return data.empty(); }
size_type size() const
{ return data.size(); }
size_type max_size() const
{ return data.max_size(); }
/* Modifiers */
void clear()
{ return data.clear(); }
/* Lookup */
size_type count(const string_type& sect)
{ return data.count(sect); }
iterator find(const string_type& sect)
{ return data.find(sect); }
/* Gets a value from the specified section & key, default_value is returned if the sect & key doesn't exist */
string_type get(const string_type& sect, const key_type& key, const string_type& default_value)
{
auto it = this->find(sect);
if(it != this->end())
{
auto itv = it->second.find(key);
if(itv != it->second.end())
return itv->second;
}
return default_value;
}
/* Sets the value of a value in the ini */
void set(const string_type& sect, const key_type& key, const string_type& value)
{
(*this)[sect][key] = value; // no emplace since overwrite!
}
/* Too lazy to continue this container... If you need more methods, just add it */
#if 1
bool read_file(const char_type* filename)
{
/* Using C stream in a STL-like container, funny?
*/
if(FILE* f = fopen(filename, "r"))
{
key_container* keys = nullptr;
char_type buf[2048];
string_type line;
string_type key;
string_type value;
string_type null_string;
size_type pos;
// Trims an string
auto trim = [](string_type& s, bool trimLeft, bool trimRight) -> string_type&
{
if(s.size())
{
// Ignore UTF-8 BOM
while(s.size() >= 3 && s[0] == (char)(0xEF) && s[1] == (char)(0xBB) && s[2] == (char)(0xBF))
s.erase(s.begin(), s.begin() + 3);
if(trimLeft)
s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::function<int(int)>(::isspace))));
if(trimRight)
s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::function<int(int)>(::isspace))).base(), s.end());
}
return s;
};
// Start parsing
while(fgets(buf, sizeof(buf), f))
{
// What a thing, reading into a char buffer and then putting in the string...
line = buf;
// Find comment and remove anything after it from the line
if((pos = line.find_first_of(';')) != line.npos)
line.erase(pos);
// Trim the string, and if it gets empty, skip this line
if(trim(line, true, true).empty())
continue;
// Find section name
if(line.front() == '[' && line.back() == ']')
{
pos = line.length() - 1; //line.find_first_of(']');
if(pos != line.npos)
{
trim(key.assign(line, 1, pos-1), true, true);
keys = &data[std::move(key)]; // Create section
}
else
keys = nullptr;
}
else
{
// Find key and value positions
pos = line.find_first_of('=');
if(pos == line.npos)
{
// There's only the key
key = line; // No need for trim, line is already trimmed
value.clear();
}
else
{
// There's the key and the value
trim(key.assign(line, 0, pos), false, true); // trim the right
trim(value.assign(line, pos + 1, line.npos), true, false); // trim the left
}
// Put the key/value into the current keys object, or into the section "" if no section has been found
#if __cplusplus >= 201103L || _MSC_VER >= 1800
(keys ? *keys : data[null_string]).emplace(std::move(key), std::move(value));
#else
(keys ? *keys : data[null_string])[key] = value;
key.clear(); value.clear();
#endif
}
}
fclose(f);
return true;
}
return false;
}
/*
* Dumps the content of this container into an ini file
*/
bool write_file(const char_type* filename)
{
if(FILE* f = fopen(filename, "w"))
{
bool first = true;
for(auto& sec : this->data)
{
fprintf(f, first? "[%s]\n" : "\n[%s]\n", sec.first.c_str());
first = false;
for(auto& kv : sec.second)
{
if(kv.second.empty())
fprintf(f, "%s\n", kv.first.c_str());
else
fprintf(f, "%s = %s\n", kv.first.c_str(), kv.second.c_str());
}
}
fclose(f);
return true;
}
return false;
}
/*
*/
bool load_file(const char_type* filename)
{
return read_file(filename);
}
bool load_file(const StringType& filename)
{
return load_file(filename.c_str());
}
bool write_file(const StringType& filename)
{
return write_file(filename.c_str());
}
#endif
};
/* Use default basic_ini
*
* Limitations:
* * Not unicode aware
* * Case sensitive
* * Sections must have unique keys
*/
typedef basic_ini<> ini;
}
#endif

View file

@ -3,6 +3,8 @@
#include "DummyObject.h"
#include "Pools.h"
// --MIAMI: file done
CDummyObject::CDummyObject(CObject *obj)
{
SetModelIndexNoCreate(obj->GetModelIndex());

View file

@ -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;
}

View file

@ -8,7 +8,7 @@ enum {
MISSION_OBJECT = 2,
TEMP_OBJECT = 3,
CUTSCENE_OBJECT = 4,
ESCALATOR_OBJECT = 5,
CONTROLLED_SUB_OBJECT = 5,
};
enum CollisionSpecialResponseCase

View file

@ -2,6 +2,8 @@
#include "Projectile.h"
// --MIAMI: file done
CProjectile::CProjectile(int32 model) : CObject()
{
m_fMass = 1.0f;

View file

@ -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++;
}

View file

@ -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;

View file

@ -3,6 +3,8 @@
#include "main.h"
#include "PedRoutes.h"
// --MIAMI: file done
CRouteNode gaRoutes[NUMPEDROUTES];
void

View file

@ -4,6 +4,8 @@
#include "FileMgr.h"
#include "PedStats.h"
// --MIAMI: file done
CPedStats *CPedStats::ms_apPedStats[NUM_PEDSTATS];
void

View file

@ -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) {

View file

@ -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;
}
}
}

View file

@ -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;

View file

@ -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;

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -366,6 +366,12 @@ COcclusion::ProcessBeforeRendering(void)
}
NumActiveOccluders--;
i--;
// Taken from Mobile!
#ifdef FIX_BUGS
if (i == -1) {
i = 0;
}
#endif
}
}
}

View file

@ -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;

View file

@ -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();

View file

@ -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--;
}
}
}

View file

@ -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;
};

View file

@ -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

View file

@ -22,3 +22,4 @@ void SetAmbientColours(void);
void SetAmbientColoursForPedsCarsAndObjects(void);
void SetAmbientColoursToIndicateRoadGroup(int i);
void SetAmbientColours(RwRGBAReal *color);
void SetFullAmbient(void);

View file

@ -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"

View file

@ -3,6 +3,7 @@
#include "crossplatform.h"
#include "FileMgr.h"
#include "Font.h"
#ifdef MORE_LANGUAGES
#include "Game.h"
#endif

View file

@ -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) {

View file

@ -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,

View file

@ -41,7 +41,6 @@
#include "AnimViewer.h"
#include "Font.h"
#define MAX_SUBSYSTEMS (16)
@ -81,12 +80,22 @@ DWORD _dwOperatingSystemVersion;
#include "resource.h"
#else
long _dwOperatingSystemVersion;
#ifndef __APPLE__
#include <sys/sysinfo.h>
#else
#include <mach/mach_host.h>
#include <sys/sysctl.h>
#endif
#include <stddef.h>
#include <locale.h>
#include <signal.h>
#include <errno.h>
#endif
#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
char gSelectedJoystickName[128] = "";
#endif
/*
*****************************************************************************
*/
@ -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;
}
}

View file

@ -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,40 +525,6 @@ 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)
{

View file

@ -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
{

View file

@ -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()

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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;