1
0
Fork 0
mirror of https://git.rip/DMCA_FUCKER/re3.git synced 2024-11-14 06:39:17 +00:00

sync with upstream

This commit is contained in:
Nikolay Korolev 2020-10-11 12:58:11 +03:00
commit 552f308e9e
23 changed files with 871 additions and 222 deletions

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 ## Preparing the environment for building
- Clone the repo. - Clone the repo using the argument `--recursive`.
- Run `git submodule init` and `git submodule update`.
- Point GTA_III_RE_DIR environment variable to GTA3 root folder. - Point GTA_III_RE_DIR environment variable to GTA3 root folder.
- Run premake - Run premake
- On Windows: one of the `premake-vsXXXX.cmd` variants on root folder - 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. > :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 ## 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) ### Unreversed / incomplete classes (at least the ones we know)
The following classes have only unused or practically unused code left: The following classes have only unused or practically unused code left:
@ -44,110 +44,3 @@ CCullZone - only mobile stuff
CCullZones - 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

@ -185,7 +185,7 @@ project "librw"
includedirs {"/usr/local/include" } includedirs {"/usr/local/include" }
libdirs { "/opt/local/lib" } libdirs { "/opt/local/lib" }
libdirs { "/usr/local/lib" } libdirs { "/usr/local/lib" }
filter "platforms:*RW34*" filter "platforms:*RW34*"
flags { "ExcludeFromBuild" } flags { "ExcludeFromBuild" }
filter {} filter {}

View file

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

View file

@ -3075,7 +3075,7 @@ void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle* pVehicle)
void CCarCtrl::JoinCarWithRoadSystem(CVehicle* pVehicle) void CCarCtrl::JoinCarWithRoadSystem(CVehicle* pVehicle)
{ {
pVehicle->AutoPilot.m_nPrevRouteNode = pVehicle->AutoPilot.m_nCurrentRouteNode = pVehicle->AutoPilot.m_nNextRouteNode = 0; 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); int nodeId = ThePaths.FindNodeClosestToCoorsFavourDirection(pVehicle->GetPosition(), 0, pVehicle->GetForward().x, pVehicle->GetForward().y);
CPathNode* pNode = &ThePaths.m_pathNodes[nodeId]; CPathNode* pNode = &ThePaths.m_pathNodes[nodeId];
int prevNodeId = -1; int prevNodeId = -1;

View file

@ -15,6 +15,9 @@
#include "Text.h" #include "Text.h"
#include "Vehicle.h" #include "Vehicle.h"
#include "GameLogic.h" #include "GameLogic.h"
#ifdef FIX_BUGS
#include "Replay.h"
#endif
//--MIAMI: file done except TODO //--MIAMI: file done except TODO
@ -173,6 +176,10 @@ CDarkel::ReadStatus()
void void
CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle) CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle)
{ {
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return;
#endif
if (FrenzyOnGoing()) { if (FrenzyOnGoing()) {
int32 model = vehicle->GetModelIndex(); int32 model = vehicle->GetModelIndex();
if (ModelToKill == FRENZY_ANY_CAR || ModelToKill == model || ModelToKill2 == model || ModelToKill3 == model || ModelToKill4 == model) { if (ModelToKill == FRENZY_ANY_CAR || ModelToKill == model || ModelToKill2 == model || ModelToKill3 == model || ModelToKill4 == model) {
@ -200,6 +207,10 @@ CDarkel::RegisterCarBlownUpByPlayer(CVehicle *vehicle)
void void
CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot) CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot)
{ {
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return;
#endif
if (FrenzyOnGoing() && (weapon == WeaponType if (FrenzyOnGoing() && (weapon == WeaponType
|| weapon == WEAPONTYPE_EXPLOSION || weapon == WEAPONTYPE_EXPLOSION
|| weapon == WEAPONTYPE_UZI_DRIVEBY && WeaponType == WEAPONTYPE_UZI || weapon == WEAPONTYPE_UZI_DRIVEBY && WeaponType == WEAPONTYPE_UZI
@ -225,6 +236,10 @@ CDarkel::RegisterKillByPlayer(CPed *victim, eWeaponType weapon, bool headshot)
void void
CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype) CDarkel::RegisterKillNotByPlayer(CPed* victim, eWeaponType weapontype)
{ {
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return;
#endif
CStats::PeopleKilledByOthers++; CStats::PeopleKilledByOthers++;
} }
@ -305,6 +320,11 @@ CDarkel::StartFrenzy(eWeaponType weaponType, int32 time, uint16 kill, int32 mode
void void
CDarkel::Update() CDarkel::Update()
{ {
#ifdef FIX_BUGS
if (CReplay::IsPlayingBack())
return;
#endif
if (Status != KILLFRENZY_ONGOING) if (Status != KILLFRENZY_ONGOING)
return; return;

View file

@ -249,6 +249,9 @@ enum Config {
#if !defined(RW_GL3) && defined(_WIN32) #if !defined(RW_GL3) && defined(_WIN32)
#define XINPUT #define XINPUT
#endif #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 DETECT_PAD_INPUT_SWITCH // Adds automatic switch of pad related stuff between controller and kb/m
#define KANGAROO_CHEAT #define KANGAROO_CHEAT
#define RESTORE_ALLCARSHELI_CHEAT #define RESTORE_ALLCARSHELI_CHEAT
@ -324,4 +327,4 @@ enum Config {
#undef NO_ISLAND_LOADING #undef NO_ISLAND_LOADING
#define PC_PARTICLE #define PC_PARTICLE
#define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial #define VC_PED_PORTS // To not process collisions always. But should be tested if that's really beneficial
#endif #endif

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

@ -5,6 +5,46 @@
#include "Font.h" #include "Font.h"
#include "Timer.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; CFontDetails CFont::Details;
int16 CFont::NewLine; int16 CFont::NewLine;
CSprite2d CFont::Sprite[MAX_FONTS]; CSprite2d CFont::Sprite[MAX_FONTS];

View file

@ -1,5 +1,11 @@
#pragma once #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 struct CFontDetails
{ {
CRGBA color; CRGBA color;

View file

@ -11,6 +11,7 @@
#include "Clock.h" #include "Clock.h"
#include "Date.h" #include "Date.h"
#include "FileMgr.h" #include "FileMgr.h"
#include "Font.h"
#include "Frontend.h" #include "Frontend.h"
#include "GameLogic.h" #include "GameLogic.h"
#include "Gangs.h" #include "Gangs.h"

View file

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

View file

@ -84,6 +84,16 @@ void FileTimeToSystemTime(time_t* writeTime, SYSTEMTIME* out) {
} }
#endif #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 // Funcs/features from Windows that we need on other platforms
#ifndef _WIN32 #ifndef _WIN32
char *strupr(char *s) { char *strupr(char *s) {

View file

@ -67,6 +67,10 @@ void CapturePad(RwInt32 padID);
void joysChangeCB(int jid, int event); void joysChangeCB(int jid, int event);
#endif #endif
#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
extern char gSelectedJoystickName[128];
#endif
enum eGameState enum eGameState
{ {
GS_START_UP = 0, GS_START_UP = 0,

View file

@ -41,7 +41,6 @@
#include "AnimViewer.h" #include "AnimViewer.h"
#include "Font.h" #include "Font.h"
#define MAX_SUBSYSTEMS (16) #define MAX_SUBSYSTEMS (16)
@ -92,6 +91,11 @@ long _dwOperatingSystemVersion;
#include <signal.h> #include <signal.h>
#include <errno.h> #include <errno.h>
#endif #endif
#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
char gSelectedJoystickName[128] = "";
#endif
/* /*
***************************************************************************** *****************************************************************************
*/ */
@ -429,6 +433,10 @@ psInitialize(void)
_dwOperatingSystemVersion = OS_WIN95; _dwOperatingSystemVersion = OS_WIN95;
} }
} }
#else
_dwOperatingSystemVersion = OS_WINXP; // To fool other classes
#endif
#ifndef PS2_MENU #ifndef PS2_MENU
@ -438,6 +446,8 @@ psInitialize(void)
#endif #endif
#ifdef _WIN32
MEMORYSTATUS memstats; MEMORYSTATUS memstats;
GlobalMemoryStatus(&memstats); GlobalMemoryStatus(&memstats);
@ -445,17 +455,22 @@ psInitialize(void)
debug("Physical memory size %u\n", memstats.dwTotalPhys); debug("Physical memory size %u\n", memstats.dwTotalPhys);
debug("Available physical memory %u\n", memstats.dwAvailPhys); 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 #else
#ifndef PS2_MENU
#ifdef GTA3_1_1_PATCH
FrontEndMenuManager.LoadSettings();
#endif
#endif
#ifndef __APPLE__ #ifndef __APPLE__
struct sysinfo systemInfo; struct sysinfo systemInfo;
sysinfo(&systemInfo); sysinfo(&systemInfo);
_dwMemAvailPhys = systemInfo.freeram; _dwMemAvailPhys = systemInfo.freeram;
debug("Physical memory size %u\n", systemInfo.totalram); debug("Physical memory size %u\n", systemInfo.totalram);
@ -476,7 +491,8 @@ psInitialize(void)
#endif #endif
_dwOperatingSystemVersion = OS_WINXP; // To fool other classes _dwOperatingSystemVersion = OS_WINXP; // To fool other classes
#endif #endif
TheText.Unload();
TheText.Unload();
return TRUE; return TRUE;
} }
@ -843,35 +859,26 @@ void joysChangeCB(int jid, int event);
bool IsThisJoystickBlacklisted(int i) bool IsThisJoystickBlacklisted(int i)
{ {
#ifndef DONT_TRUST_RECOGNIZED_JOYSTICKS
return false;
#else
if (glfwJoystickIsGamepad(i)) if (glfwJoystickIsGamepad(i))
return false; return false;
const char* joyname = glfwGetJoystickName(i); const char* joyname = glfwGetJoystickName(i);
// this is just a keyboard and mouse if (strncmp(joyname, gSelectedJoystickName, strlen(gSelectedJoystickName)) == 0)
// Microsoft Microsoft® 2.4GHz Transceiver v8.0 Consumer Control return false;
// 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;
return false; return true;
#endif
} }
void _InputInitialiseJoys() void _InputInitialiseJoys()
{ {
PSGLOBAL(joy1id) = -1;
PSGLOBAL(joy2id) = -1;
for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) { for (int i = 0; i <= GLFW_JOYSTICK_LAST; i++) {
if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) { if (glfwJoystickPresent(i) && !IsThisJoystickBlacklisted(i)) {
if (PSGLOBAL(joy1id) == -1) if (PSGLOBAL(joy1id) == -1)
@ -886,6 +893,9 @@ void _InputInitialiseJoys()
if (PSGLOBAL(joy1id) != -1) { if (PSGLOBAL(joy1id) != -1) {
int count; int count;
glfwGetJoystickButtons(PSGLOBAL(joy1id), &count); glfwGetJoystickButtons(PSGLOBAL(joy1id), &count);
#ifdef DONT_TRUST_RECOGNIZED_JOYSTICKS
strcpy(gSelectedJoystickName, glfwGetJoystickName(PSGLOBAL(joy1id)));
#endif
ControlsManager.InitDefaultControlConfigJoyPad(count); ControlsManager.InitDefaultControlConfigJoyPad(count);
} }
} }
@ -2104,18 +2114,19 @@ void CapturePad(RwInt32 padID)
void joysChangeCB(int jid, int event) void joysChangeCB(int jid, int event)
{ {
if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) if (event == GLFW_CONNECTED && !IsThisJoystickBlacklisted(jid)) {
{ if (PSGLOBAL(joy1id) == -1) {
if (PSGLOBAL(joy1id) == -1)
PSGLOBAL(joy1id) = jid; 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; PSGLOBAL(joy2id) = jid;
}
else if (event == GLFW_DISCONNECTED) } else if (event == GLFW_DISCONNECTED) {
{ if (PSGLOBAL(joy1id) == jid) {
if (PSGLOBAL(joy1id) == jid)
PSGLOBAL(joy1id) = -1; PSGLOBAL(joy1id) = -1;
else if (PSGLOBAL(joy2id) == jid) } else if (PSGLOBAL(joy2id) == jid)
PSGLOBAL(joy2id) = -1; PSGLOBAL(joy2id) = -1;
} }
} }

View file

@ -3414,4 +3414,4 @@ int strncasecmp(const char *str1, const char *str2, size_t len)
return _strnicmp(str1, str2, len); return _strnicmp(str1, str2, len);
} }
#endif #endif
#endif #endif

View file

@ -9,11 +9,12 @@
#include "Text.h" #include "Text.h"
#include "Timer.h" #include "Timer.h"
//--MIAMI: file done
static wchar WideErrorString[25]; static wchar WideErrorString[25];
CText TheText; CText TheText;
//--MIAMI: DONE
CText::CText(void) CText::CText(void)
{ {
encoding = 'e'; encoding = 'e';
@ -23,7 +24,6 @@ CText::CText(void)
memset(WideErrorString, 0, sizeof(WideErrorString)); memset(WideErrorString, 0, sizeof(WideErrorString));
} }
//--MIAMI: DONE
void void
CText::Load(void) CText::Load(void)
{ {
@ -95,7 +95,6 @@ CText::Load(void)
CFileMgr::SetDir(""); CFileMgr::SetDir("");
} }
//--MIAMI: DONE
void void
CText::Unload(void) CText::Unload(void)
{ {
@ -108,7 +107,6 @@ CText::Unload(void)
memset(szMissionTableName, 0, sizeof(szMissionTableName)); memset(szMissionTableName, 0, sizeof(szMissionTableName));
} }
//--MIAMI: DONE
wchar* wchar*
CText::Get(const char *key) CText::Get(const char *key)
{ {
@ -158,7 +156,6 @@ wchar FrenchUpperCaseTable[128] = {
253, 254, 255 253, 254, 255
}; };
//--MIAMI: TODO (check tables)
wchar wchar
CText::GetUpperCase(wchar c) CText::GetUpperCase(wchar c)
{ {
@ -190,7 +187,6 @@ CText::GetUpperCase(wchar c)
return c; return c;
} }
//--MIAMI: DONE
void void
CText::UpperCase(wchar *s) CText::UpperCase(wchar *s)
{ {
@ -200,27 +196,33 @@ CText::UpperCase(wchar *s)
} }
} }
//--MIAMI: DONE
void void
CText::GetNameOfLoadedMissionText(char *outName) CText::GetNameOfLoadedMissionText(char *outName)
{ {
strcpy(outName, szMissionTableName); strcpy(outName, szMissionTableName);
} }
//--MIAMI: DONE
void void
CText::ReadChunkHeader(ChunkHeader *buf, int32 file, size_t *offset) 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 // original code loops 8 times to read 1 byte with CFileMgr::Read, that's retarded
CFileMgr::Read(file, (char*)buf, sizeof(ChunkHeader)); CFileMgr::Read(file, (char*)buf, sizeof(ChunkHeader));
*offset += sizeof(ChunkHeader); *offset += sizeof(ChunkHeader);
#endif
} }
//--MIAMI: DONE
void void
CText::LoadMissionText(char *MissionTableName) CText::LoadMissionText(char *MissionTableName)
{ {
char filename[32]; char filename[32];
CMessages::ClearAllMessagesDisplayedByGame();
mission_keyArray.Unload(); mission_keyArray.Unload();
mission_data.Unload(); mission_data.Unload();
@ -306,7 +308,6 @@ CText::LoadMissionText(char *MissionTableName)
} }
//--MIAMI: DONE
void void
CKeyArray::Load(size_t length, int file, size_t* offset) 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; rawbytes = (char*)entries;
#if DUMB #if DUMB
for (uint32 i = 0; i < length; i++) for (uint32 i = 0; i < length; i++) {
CFileMgr::Read(file, &rawbytes[i], 1); CFileMgr::Read(file, &rawbytes[i], 1);
(*offset)++;
}
#else #else
CFileMgr::Read(file, rawbytes, length); CFileMgr::Read(file, rawbytes, length);
*offset += length;
#endif #endif
} }
//--MIAMI: DONE
void void
CKeyArray::Unload(void) CKeyArray::Unload(void)
{ {
@ -334,7 +337,6 @@ CKeyArray::Unload(void)
numEntries = 0; numEntries = 0;
} }
//--MIAMI: DONE
void void
CKeyArray::Update(wchar *chars) CKeyArray::Update(wchar *chars)
{ {
@ -345,7 +347,6 @@ CKeyArray::Update(wchar *chars)
#endif #endif
} }
//--MIAMI: DONE
CKeyEntry* CKeyEntry*
CKeyArray::BinarySearch(const char *key, CKeyEntry *entries, int16 low, int16 high) 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; return nil;
} }
//--MIAMI: DONE
wchar* wchar*
#ifdef FIX_BUGS #ifdef FIX_BUGS
CKeyArray::Search(const char *key, wchar *data, uint8 *result) CKeyArray::Search(const char *key, wchar *data, uint8 *result)
@ -402,7 +402,6 @@ CKeyArray::Search(const char *key, uint8 *result)
return WideErrorString; return WideErrorString;
} }
//--MIAMI: DONE
void void
CData::Load(size_t length, int file, size_t * offset) 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; rawbytes = (char*)chars;
#if DUMB #if DUMB
for(uint32 i = 0; i < length; i++) for(uint32 i = 0; i < length; i++){
CFileMgr::Read(file, &rawbytes[i], 1); CFileMgr::Read(file, &rawbytes[i], 1);
(*offset)++;
}
#else #else
CFileMgr::Read(file, rawbytes, length); CFileMgr::Read(file, rawbytes, length);
*offset += length;
#endif #endif
} }
//--MIAMI: DONE
void void
CData::Unload(void) CData::Unload(void)
{ {
@ -430,22 +431,31 @@ CData::Unload(void)
numChars = 0; numChars = 0;
} }
//--MIAMI: DONE
void void
CMissionTextOffsets::Load(size_t table_size, int file, size_t *offset, int) 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 // 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. // 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)); size = (uint16) (table_size / sizeof(CMissionTextOffsets::Entry));
CFileMgr::Read(file, (char*)data, sizeof(CMissionTextOffsets::Entry) * size); CFileMgr::Read(file, (char*)data, sizeof(CMissionTextOffsets::Entry) * size);
*offset += sizeof(CMissionTextOffsets::Entry) * size; *offset += sizeof(CMissionTextOffsets::Entry) * size;
} #endif
void
AsciiToUnicode(const char *src, wchar *dst)
{
while((*dst++ = (unsigned char)*src++) != '\0');
} }
char* char*
@ -460,8 +470,29 @@ UnicodeToAscii(wchar *src)
if(*src < 128) if(*src < 128)
#endif #endif
aStr[len] = *src; aStr[len] = *src;
else // convert to CP1252
aStr[len] = '#'; 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'; aStr[len] = '\0';
return aStr; return aStr;
} }
@ -471,7 +502,7 @@ UnicodeToAsciiForSaveLoad(wchar *src)
{ {
static char aStr[256]; static char aStr[256];
int len; int len;
for(len = 0; *src != '\0' && len < 256-1; len++, src++) for(len = 0; *src != '\0' && len < 256; len++, src++)
if(*src < 256) if(*src < 256)
aStr[len] = *src; aStr[len] = *src;
else else
@ -485,7 +516,7 @@ UnicodeToAsciiForMemoryCard(wchar *src)
{ {
static char aStr[256]; static char aStr[256];
int len; int len;
for(len = 0; *src != '\0' && len < 256-1; len++, src++) for(len = 0; *src != '\0' && len < 256; len++, src++)
if(*src < 256) if(*src < 256)
aStr[len] = *src; aStr[len] = *src;
else else
@ -494,42 +525,8 @@ UnicodeToAsciiForMemoryCard(wchar *src)
return aStr; 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 void
TextCopy(wchar *dst, const wchar *src) TextCopy(wchar *dst, const wchar *src)
{ {
while((*dst++ = *src++) != '\0'); while((*dst++ = *src++) != '\0');
} }

View file

@ -1,14 +1,9 @@
#pragma once #pragma once
void AsciiToUnicode(const char *src, wchar *dst);
char *UnicodeToAscii(wchar *src); char *UnicodeToAscii(wchar *src);
char *UnicodeToAsciiForSaveLoad(wchar *src); char *UnicodeToAsciiForSaveLoad(wchar *src);
char *UnicodeToAsciiForMemoryCard(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 TextCopy(wchar *dst, const wchar *src);
void UnicodeMakeUpperCase(wchar *dst, wchar *src);
struct CKeyEntry struct CKeyEntry
{ {

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 #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 #else
if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed()) if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed())
#endif #endif