mirror of
https://git.rip/DMCA_FUCKER/re3.git
synced 2024-12-23 23:50:00 +00:00
Merge branch 'miami' of github.com:GTAmodding/re3 into miami
This commit is contained in:
commit
fb4de46626
|
@ -255,15 +255,11 @@ CStream::CStream(char *filename, ALuint &source, ALuint (&buffers)[NUM_STREAMBUF
|
||||||
{
|
{
|
||||||
// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
|
// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
FILE *test = fopen(filename, "r");
|
char *real = casepath(filename);
|
||||||
if (!test) {
|
if (real) {
|
||||||
char *r = (char*)alloca(strlen(filename) + 2);
|
strcpy(m_aFilename, real);
|
||||||
if (casepath(filename, r))
|
free(real);
|
||||||
{
|
|
||||||
strcpy(m_aFilename, r);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
fclose(test);
|
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -189,10 +189,11 @@ GetGTA3ImgSize(void)
|
||||||
realpath(gImgNames[0], path);
|
realpath(gImgNames[0], path);
|
||||||
if (stat(path, &statbuf) == -1) {
|
if (stat(path, &statbuf) == -1) {
|
||||||
// Try case-insensitivity
|
// Try case-insensitivity
|
||||||
char *r = (char*)alloca(strlen(gImgNames[0]) + 2);
|
char* real = casepath(gImgNames[0], false);
|
||||||
if (casepath(gImgNames[0], r))
|
if (real)
|
||||||
{
|
{
|
||||||
realpath(r, path);
|
realpath(real, path);
|
||||||
|
free(real);
|
||||||
if (stat(path, &statbuf) != -1)
|
if (stat(path, &statbuf) != -1)
|
||||||
goto ok;
|
goto ok;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +211,6 @@ CdStreamShutdown(void)
|
||||||
{
|
{
|
||||||
// Destroying semaphores and free(gpReadInfo) will be done at threads
|
// Destroying semaphores and free(gpReadInfo) will be done at threads
|
||||||
#ifndef ONE_THREAD_PER_CHANNEL
|
#ifndef ONE_THREAD_PER_CHANNEL
|
||||||
free(gChannelRequestQ.items);
|
|
||||||
gCdStreamThreadStatus = 2;
|
gCdStreamThreadStatus = 2;
|
||||||
sem_post(&gCdStreamSema);
|
sem_post(&gCdStreamSema);
|
||||||
#endif
|
#endif
|
||||||
|
@ -442,6 +442,7 @@ void *CdStreamThread(void *param)
|
||||||
sem_destroy(&gpReadInfo[i].pDoneSemaphore);
|
sem_destroy(&gpReadInfo[i].pDoneSemaphore);
|
||||||
}
|
}
|
||||||
sem_destroy(&gCdStreamSema);
|
sem_destroy(&gCdStreamSema);
|
||||||
|
free(gChannelRequestQ.items);
|
||||||
#else
|
#else
|
||||||
sem_destroy(&gpReadInfo[channel].pStartSemaphore);
|
sem_destroy(&gpReadInfo[channel].pStartSemaphore);
|
||||||
sem_destroy(&gpReadInfo[channel].pDoneSemaphore);
|
sem_destroy(&gpReadInfo[channel].pDoneSemaphore);
|
||||||
|
@ -460,10 +461,11 @@ CdStreamAddImage(char const *path)
|
||||||
|
|
||||||
// Fix case sensitivity and backslashes.
|
// Fix case sensitivity and backslashes.
|
||||||
if (gImgFiles[gNumImages] == -1) {
|
if (gImgFiles[gNumImages] == -1) {
|
||||||
char *r = (char*)alloca(strlen(path) + 2);
|
char* real = casepath(path, false);
|
||||||
if (casepath(path, r))
|
if (real)
|
||||||
{
|
{
|
||||||
gImgFiles[gNumImages] = open(r, _gdwCdStreamFlags);
|
gImgFiles[gNumImages] = open(real, _gdwCdStreamFlags);
|
||||||
|
free(real);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
#endif
|
#endif
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "crossplatform.h"
|
||||||
|
|
||||||
#include "FileMgr.h"
|
#include "FileMgr.h"
|
||||||
|
|
||||||
|
@ -31,19 +32,16 @@ static myFILE myfiles[NUMFILES];
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include "crossplatform.h"
|
|
||||||
#define _getcwd getcwd
|
#define _getcwd getcwd
|
||||||
|
|
||||||
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
|
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
|
||||||
void mychdir(char const *path)
|
void mychdir(char const *path)
|
||||||
{
|
{
|
||||||
char *r = (char*)alloca(strlen(path) + 2);
|
char* r = casepath(path, false);
|
||||||
if (casepath(path, r))
|
if (r) {
|
||||||
{
|
|
||||||
chdir(r);
|
chdir(r);
|
||||||
}
|
free(r);
|
||||||
else
|
} else {
|
||||||
{
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,30 +71,7 @@ found:
|
||||||
*p++ = 'b';
|
*p++ = 'b';
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
myfiles[fd].file = fcaseopen(filename, realmode);
|
||||||
char *newPath = strdup(filename);
|
|
||||||
// Normally casepath() fixes backslashes, but if the mode is sth other than r/rb it will create new file with backslashes on linux, so fix backslashes here
|
|
||||||
char *nextBs;
|
|
||||||
while(nextBs = strstr(newPath, "\\")){
|
|
||||||
*nextBs = '/';
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
const char *newPath = filename;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
myfiles[fd].file = fopen(newPath, realmode);
|
|
||||||
// Be case-insensitive on linux (from https://github.com/OneSadCookie/fcaseopen/)
|
|
||||||
#if !defined(_WIN32)
|
|
||||||
if (!myfiles[fd].file) {
|
|
||||||
char *r = (char*)alloca(strlen(newPath) + 2);
|
|
||||||
if (casepath(newPath, r))
|
|
||||||
{
|
|
||||||
myfiles[fd].file = fopen(r, realmode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
free(newPath);
|
|
||||||
#endif
|
|
||||||
if(myfiles[fd].file == nil)
|
if(myfiles[fd].file == nil)
|
||||||
return 0;
|
return 0;
|
||||||
return fd;
|
return fd;
|
||||||
|
|
|
@ -88,6 +88,7 @@
|
||||||
#include "Zones.h"
|
#include "Zones.h"
|
||||||
#include "Occlusion.h"
|
#include "Occlusion.h"
|
||||||
#include "debugmenu.h"
|
#include "debugmenu.h"
|
||||||
|
#include "Ropes.h"
|
||||||
|
|
||||||
eLevelName CGame::currLevel;
|
eLevelName CGame::currLevel;
|
||||||
int32 CGame::currArea;
|
int32 CGame::currArea;
|
||||||
|
@ -403,9 +404,11 @@ bool CGame::Initialise(const char* datFile)
|
||||||
CRubbish::Init();
|
CRubbish::Init();
|
||||||
CClouds::Init();
|
CClouds::Init();
|
||||||
CSpecialFX::Init();
|
CSpecialFX::Init();
|
||||||
|
CRopes::Init();
|
||||||
CWaterCannons::Init();
|
CWaterCannons::Init();
|
||||||
CBridge::Init();
|
CBridge::Init();
|
||||||
CGarages::Init();
|
CGarages::Init();
|
||||||
|
LoadingScreen("Loading the Game", "Position dynamic objects", nil);
|
||||||
LoadingScreen("Loading the Game", "Initialise vehicle paths", nil);
|
LoadingScreen("Loading the Game", "Initialise vehicle paths", nil);
|
||||||
CTrain::InitTrains();
|
CTrain::InitTrains();
|
||||||
CPlane::InitPlanes();
|
CPlane::InitPlanes();
|
||||||
|
@ -416,6 +419,7 @@ bool CGame::Initialise(const char* datFile)
|
||||||
if ( !TheMemoryCard.m_bWantToLoad )
|
if ( !TheMemoryCard.m_bWantToLoad )
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
LoadingScreen("Loading the Game", "Start script", nil);
|
||||||
CTheScripts::StartTestScript();
|
CTheScripts::StartTestScript();
|
||||||
CTheScripts::Process();
|
CTheScripts::Process();
|
||||||
TheCamera.Process();
|
TheCamera.Process();
|
||||||
|
@ -426,6 +430,9 @@ bool CGame::Initialise(const char* datFile)
|
||||||
CCollision::ms_collisionInMemory = currLevel;
|
CCollision::ms_collisionInMemory = currLevel;
|
||||||
for (int i = 0; i < MAX_PADS; i++)
|
for (int i = 0; i < MAX_PADS; i++)
|
||||||
CPad::GetPad(i)->Clear(true);
|
CPad::GetPad(i)->Clear(true);
|
||||||
|
// TODO(Miami)
|
||||||
|
// DMAudio.SetStartingTrackPositions(1);
|
||||||
|
DMAudio.ChangeMusicMode(MUSICMODE_GAME);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,6 +553,7 @@ void CGame::ReInitGameObjectVariables(void)
|
||||||
CRemote::Init();
|
CRemote::Init();
|
||||||
#endif
|
#endif
|
||||||
CSpecialFX::Init();
|
CSpecialFX::Init();
|
||||||
|
CRopes::Init();
|
||||||
CWaterCannons::Init();
|
CWaterCannons::Init();
|
||||||
CParticle::ReloadConfig();
|
CParticle::ReloadConfig();
|
||||||
|
|
||||||
|
@ -718,6 +726,7 @@ void CGame::Process(void)
|
||||||
CGarages::Update();
|
CGarages::Update();
|
||||||
CRubbish::Update();
|
CRubbish::Update();
|
||||||
CSpecialFX::Update();
|
CSpecialFX::Update();
|
||||||
|
CRopes::Update();
|
||||||
CTimeCycle::Update();
|
CTimeCycle::Update();
|
||||||
if (CReplay::ShouldStandardCameraBeProcessed())
|
if (CReplay::ShouldStandardCameraBeProcessed())
|
||||||
TheCamera.Process();
|
TheCamera.Process();
|
||||||
|
|
|
@ -31,14 +31,14 @@ CRope::Update(void)
|
||||||
for(i = 1; i < ARRAY_SIZE(m_pos); i++){
|
for(i = 1; i < ARRAY_SIZE(m_pos); i++){
|
||||||
CVector prevPos = m_pos[i];
|
CVector prevPos = m_pos[i];
|
||||||
m_pos[i] += m_speed[i]*step*CTimer::GetTimeStep();
|
m_pos[i] += m_speed[i]*step*CTimer::GetTimeStep();
|
||||||
m_pos[0].z -= 0.05f*CTimer::GetTimeStep();
|
m_pos[i].z -= 0.05f*CTimer::GetTimeStep();
|
||||||
CVector dist = m_pos[i] - m_pos[i-1];
|
CVector dist = m_pos[i] - m_pos[i-1];
|
||||||
m_pos[i] = m_pos[i-1] + dist/dist.Magnitude()*0.625f;
|
m_pos[i] = m_pos[i-1] + (0.625f/dist.Magnitude())*dist;
|
||||||
m_speed[i] = (m_pos[i] - prevPos)/CTimer::GetTimeStep();
|
m_speed[i] = (m_pos[i] - prevPos)/CTimer::GetTimeStep();
|
||||||
}
|
}
|
||||||
if(!m_bWasRegistered && m_pos[0].z < 0.0f)
|
if(!m_bWasRegistered && m_pos[0].z < 0.0f)
|
||||||
m_bActive = false;
|
m_bActive = false;
|
||||||
m_bWasRegistered = true;
|
m_bWasRegistered = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -60,7 +60,11 @@ CRope::Render(void)
|
||||||
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
|
||||||
|
|
||||||
if(RwIm3DTransform(TempBufferRenderVertices, ARRAY_SIZE(m_pos), nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXRGBA)){
|
if(RwIm3DTransform(TempBufferRenderVertices, ARRAY_SIZE(m_pos), nil, rwIM3D_VERTEXXYZ|rwIM3D_VERTEXRGBA)){
|
||||||
|
#ifdef FIX_BUGS
|
||||||
RwIm3DRenderIndexedPrimitive(rwPRIMTYPELINELIST, RopeIndices, 2*(ARRAY_SIZE(m_pos)-1));
|
RwIm3DRenderIndexedPrimitive(rwPRIMTYPELINELIST, RopeIndices, 2*(ARRAY_SIZE(m_pos)-1));
|
||||||
|
#else
|
||||||
|
RwIm3DRenderIndexedPrimitive(rwPRIMTYPEPOLYLINE, RopeIndices, 2*(ARRAY_SIZE(m_pos)-1));
|
||||||
|
#endif
|
||||||
RwIm3DEnd();
|
RwIm3DEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +163,7 @@ CRopes::CreateRopeWithSwatComingDown(CVector pos)
|
||||||
|
|
||||||
if(!CStreaming::HasModelLoaded(MI_SWAT) || !RegisterRope(ropeId+100, pos, true))
|
if(!CStreaming::HasModelLoaded(MI_SWAT) || !RegisterRope(ropeId+100, pos, true))
|
||||||
return false;
|
return false;
|
||||||
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_ARMY, pos);
|
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_HELI_SWAT, pos);
|
||||||
swat->bUsesCollision = false;
|
swat->bUsesCollision = false;
|
||||||
swat->m_pRopeEntity = (CEntity*)1;
|
swat->m_pRopeEntity = (CEntity*)1;
|
||||||
swat->m_nRopeID = 100 + ropeId;
|
swat->m_nRopeID = 100 + ropeId;
|
||||||
|
|
|
@ -62,6 +62,7 @@
|
||||||
#include "SceneEdit.h"
|
#include "SceneEdit.h"
|
||||||
#include "debugmenu.h"
|
#include "debugmenu.h"
|
||||||
#include "Occlusion.h"
|
#include "Occlusion.h"
|
||||||
|
#include "Ropes.h"
|
||||||
|
|
||||||
GlobalScene Scene;
|
GlobalScene Scene;
|
||||||
|
|
||||||
|
@ -873,6 +874,7 @@ RenderEffects(void)
|
||||||
CGlass::Render();
|
CGlass::Render();
|
||||||
CWaterCannons::Render();
|
CWaterCannons::Render();
|
||||||
CSpecialFX::Render();
|
CSpecialFX::Render();
|
||||||
|
CRopes::Render();
|
||||||
CShadows::RenderStaticShadows();
|
CShadows::RenderStaticShadows();
|
||||||
CShadows::RenderStoredShadows();
|
CShadows::RenderStoredShadows();
|
||||||
CSkidmarks::Render();
|
CSkidmarks::Render();
|
||||||
|
|
|
@ -376,23 +376,19 @@ RwStream *RwStreamOpen(RwStreamType type, RwStreamAccessType accessType, const v
|
||||||
file = rwNewT(StreamFile, 1, 0);
|
file = rwNewT(StreamFile, 1, 0);
|
||||||
memcpy(file, &fakefile, sizeof(StreamFile));
|
memcpy(file, &fakefile, sizeof(StreamFile));
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
// Be case-insensitive and fix backslashes (from https://github.com/OneSadCookie/fcaseopen/)
|
char *r = casepath((char*)pData);
|
||||||
FILE* first = fopen((char*)pData, "r");
|
if (r) {
|
||||||
char *r;
|
if (file->open((char*)r, mode)) {
|
||||||
if (!first) {
|
free(r);
|
||||||
r = (char*)alloca(strlen((char*)pData) + 2);
|
|
||||||
// Use default path(and pass error handling to librw) if we can't find any match
|
|
||||||
if (!casepath((char*)pData, r))
|
|
||||||
r = (char*)pData;
|
|
||||||
} else
|
|
||||||
fclose(first);
|
|
||||||
|
|
||||||
if(file->open((char*)r, mode))
|
|
||||||
return file;
|
return file;
|
||||||
#else
|
}
|
||||||
|
free(r);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
if (file->open((char*)pData, mode))
|
if (file->open((char*)pData, mode))
|
||||||
return file;
|
return file;
|
||||||
#endif
|
}
|
||||||
rwFree(file);
|
rwFree(file);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
@ -856,12 +852,41 @@ RpSkin *RpSkinGeometryGetSkin( RpGeometry *geometry ) { return Skin::get(geometr
|
||||||
RpAtomic *RpSkinAtomicSetHAnimHierarchy( RpAtomic *atomic, RpHAnimHierarchy *hierarchy ) { Skin::setHierarchy(atomic, hierarchy); return atomic; }
|
RpAtomic *RpSkinAtomicSetHAnimHierarchy( RpAtomic *atomic, RpHAnimHierarchy *hierarchy ) { Skin::setHierarchy(atomic, hierarchy); return atomic; }
|
||||||
RpHAnimHierarchy *RpSkinAtomicGetHAnimHierarchy( const RpAtomic *atomic ) { return Skin::getHierarchy(atomic); }
|
RpHAnimHierarchy *RpSkinAtomicGetHAnimHierarchy( const RpAtomic *atomic ) { return Skin::getHierarchy(atomic); }
|
||||||
|
|
||||||
|
RwImage *
|
||||||
|
RtBMPImageWrite(RwImage *image, const RwChar *imageName)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
char *r = casepath(imageName);
|
||||||
|
if (r) {
|
||||||
|
rw::writeBMP(image, r);
|
||||||
|
free(r);
|
||||||
|
} else {
|
||||||
|
rw::writeBMP(image, imageName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
rw::writeBMP(image, imageName);
|
||||||
|
#endif
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
RwImage *
|
||||||
|
RtBMPImageRead(const RwChar *imageName)
|
||||||
|
{
|
||||||
|
#ifndef _WIN32
|
||||||
|
RwImage *image;
|
||||||
|
char *r = casepath(imageName);
|
||||||
|
if (r) {
|
||||||
|
image = rw::readBMP(r);
|
||||||
|
free(r);
|
||||||
|
} else {
|
||||||
|
image = rw::readBMP(imageName);
|
||||||
|
}
|
||||||
|
return image;
|
||||||
|
|
||||||
|
#else
|
||||||
|
return rw::readBMP(imageName);
|
||||||
RwImage *RtBMPImageWrite(RwImage * image, const RwChar * imageName) { rw::writeBMP(image, imageName); return image; }
|
#endif
|
||||||
RwImage *RtBMPImageRead(const RwChar * imageName) { return rw::readBMP(imageName); }
|
}
|
||||||
|
|
||||||
#include "rtquat.h"
|
#include "rtquat.h"
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
#include "CarCtrl.h"
|
#include "CarCtrl.h"
|
||||||
#include "Renderer.h"
|
#include "Renderer.h"
|
||||||
#include "Camera.h"
|
#include "Camera.h"
|
||||||
|
#include "PedPlacement.h"
|
||||||
|
#include "Ropes.h"
|
||||||
|
|
||||||
CCopPed::CCopPed(eCopType copType, int32 modifier) : CPed(PEDTYPE_COP)
|
CCopPed::CCopPed(eCopType copType, int32 modifier) : CPed(PEDTYPE_COP)
|
||||||
{
|
{
|
||||||
|
@ -39,12 +41,13 @@ CCopPed::CCopPed(eCopType copType, int32 modifier) : CPed(PEDTYPE_COP)
|
||||||
m_wepAccuracy = 76;
|
m_wepAccuracy = 76;
|
||||||
break;
|
break;
|
||||||
case COP_SWAT:
|
case COP_SWAT:
|
||||||
|
case COP_HELI_SWAT:
|
||||||
SetModelIndex(MI_SWAT);
|
SetModelIndex(MI_SWAT);
|
||||||
GiveDelayedWeapon(WEAPONTYPE_UZI, 1000);
|
GiveDelayedWeapon(WEAPONTYPE_UZI, 1000);
|
||||||
SetCurrentWeapon(WEAPONTYPE_UZI);
|
SetCurrentWeapon(WEAPONTYPE_UZI);
|
||||||
m_fArmour = 50.0f;
|
m_fArmour = 50.0f;
|
||||||
m_wepSkills = 32; /* TODO: what is this? seems unused */
|
m_wepSkills = 32; /* TODO: what is this? seems unused */
|
||||||
m_wepAccuracy = 64;
|
m_wepAccuracy = 68;
|
||||||
break;
|
break;
|
||||||
case COP_ARMY:
|
case COP_ARMY:
|
||||||
SetModelIndex(MI_ARMY);
|
SetModelIndex(MI_ARMY);
|
||||||
|
@ -77,18 +80,21 @@ CCopPed::CCopPed(eCopType copType, int32 modifier) : CPed(PEDTYPE_COP)
|
||||||
field_5FE = 1;
|
field_5FE = 1;
|
||||||
m_bIsDisabledCop = false;
|
m_bIsDisabledCop = false;
|
||||||
m_attackTimer = 0;
|
m_attackTimer = 0;
|
||||||
|
m_bBeatingSuspect = false;
|
||||||
m_bStopAndShootDisabledZone = false;
|
m_bStopAndShootDisabledZone = false;
|
||||||
field_601 = false;
|
field_601 = false;
|
||||||
m_bZoneDisabled = false;
|
m_bZoneDisabled = false;
|
||||||
field_628 = -1;
|
field_628 = -1;
|
||||||
m_nRoadblockNode = -1; // TODO(Miami): this will be nil
|
m_nRoadblockNode = -1; // TODO(Miami): this will be nil
|
||||||
m_bThrowsSpikeTrap = false;
|
m_bThrowsSpikeTrap = false;
|
||||||
field_5FF = 0;
|
|
||||||
m_pRopeEntity = nil;
|
m_pRopeEntity = nil;
|
||||||
m_fAbseilPos = 0.0f;
|
m_fAbseilPos = 0.0f;
|
||||||
m_bBeatingSuspect = false;
|
m_nHassleTimer = 0;
|
||||||
m_pPointGunAt = nil;
|
field_61C = 0;
|
||||||
field_624 = 0;
|
field_624 = 0;
|
||||||
|
if (m_pPointGunAt)
|
||||||
|
m_pPointGunAt->CleanUpOldReference((CEntity**)&m_pPointGunAt);
|
||||||
|
m_pPointGunAt = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
CCopPed::~CCopPed()
|
CCopPed::~CCopPed()
|
||||||
|
@ -96,24 +102,17 @@ CCopPed::~CCopPed()
|
||||||
ClearPursuit();
|
ClearPursuit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done
|
||||||
// Parameter should always be CPlayerPed, but it seems they considered making civilians arrestable at some point
|
// Parameter should always be CPlayerPed, but it seems they considered making civilians arrestable at some point
|
||||||
void
|
void
|
||||||
CCopPed::SetArrestPlayer(CPed *player)
|
CCopPed::SetArrestPlayer(CPed *player)
|
||||||
{
|
{
|
||||||
if (!IsPedInControl() || !player)
|
if (!IsPedInControl() || !player)
|
||||||
return;
|
return;
|
||||||
/*
|
|
||||||
switch (m_nCopType) {
|
player->Say(SOUND_PED_PLAYER_REACTTOCOP);
|
||||||
case COP_FBI:
|
|
||||||
Say(SOUND_PED_ARREST_FBI);
|
|
||||||
break;
|
|
||||||
case COP_SWAT:
|
|
||||||
Say(SOUND_PED_ARREST_SWAT);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
Say(SOUND_PED_ARREST_COP);
|
Say(SOUND_PED_ARREST_COP);
|
||||||
break;
|
|
||||||
} */
|
|
||||||
if (player->EnteringCar()) {
|
if (player->EnteringCar()) {
|
||||||
if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer)
|
if (CTimer::GetTimeInMilliseconds() > m_nPedStateTimer)
|
||||||
return;
|
return;
|
||||||
|
@ -128,14 +127,14 @@ CCopPed::SetArrestPlayer(CPed *player)
|
||||||
|
|
||||||
} else if (player->m_nPedState != PED_DIE && player->m_nPedState != PED_DEAD && player->m_nPedState != PED_ARRESTED) {
|
} else if (player->m_nPedState != PED_DIE && player->m_nPedState != PED_DEAD && player->m_nPedState != PED_ARRESTED) {
|
||||||
player->m_nLastPedState = player->m_nPedState;
|
player->m_nLastPedState = player->m_nPedState;
|
||||||
player->m_nPedState = PED_ARRESTED;
|
player->SetPedState(PED_ARRESTED);
|
||||||
|
|
||||||
FindPlayerPed()->m_bCanBeDamaged = false;
|
FindPlayerPed()->m_bCanBeDamaged = false;
|
||||||
((CPlayerPed*)player)->m_pArrestingCop = this;
|
((CPlayerPed*)player)->m_pArrestingCop = this;
|
||||||
this->RegisterReference((CEntity**) &((CPlayerPed*)player)->m_pArrestingCop);
|
this->RegisterReference((CEntity**) &((CPlayerPed*)player)->m_pArrestingCop);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_nPedState = PED_ARREST_PLAYER;
|
SetPedState(PED_ARREST_PLAYER);
|
||||||
SetObjective(OBJECTIVE_NONE);
|
SetObjective(OBJECTIVE_NONE);
|
||||||
m_prevObjective = OBJECTIVE_NONE;
|
m_prevObjective = OBJECTIVE_NONE;
|
||||||
bIsPointingGunAt = false;
|
bIsPointingGunAt = false;
|
||||||
|
@ -148,10 +147,11 @@ CCopPed::SetArrestPlayer(CPed *player)
|
||||||
player->m_pMyVehicle->bIsHandbrakeOn = true;
|
player->m_pMyVehicle->bIsHandbrakeOn = true;
|
||||||
player->m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED);
|
player->m_pMyVehicle->SetStatus(STATUS_PLAYER_DISABLED);
|
||||||
}
|
}
|
||||||
if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
|
if (GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED || GetWeapon()->m_eWeaponType == WEAPONTYPE_BRASSKNUCKLE)
|
||||||
SetCurrentWeapon(WEAPONTYPE_COLT45);
|
SetCurrentWeapon(WEAPONTYPE_COLT45);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done
|
||||||
void
|
void
|
||||||
CCopPed::ClearPursuit(void)
|
CCopPed::ClearPursuit(void)
|
||||||
{
|
{
|
||||||
|
@ -190,6 +190,7 @@ CCopPed::ClearPursuit(void)
|
||||||
bNotAllowedToDuck = false;
|
bNotAllowedToDuck = false;
|
||||||
bKindaStayInSamePlace = false;
|
bKindaStayInSamePlace = false;
|
||||||
m_bStopAndShootDisabledZone = false;
|
m_bStopAndShootDisabledZone = false;
|
||||||
|
field_601 = false;
|
||||||
m_bZoneDisabled = false;
|
m_bZoneDisabled = false;
|
||||||
ClearObjective();
|
ClearObjective();
|
||||||
if (IsPedInControl()) {
|
if (IsPedInControl()) {
|
||||||
|
@ -207,10 +208,14 @@ CCopPed::ClearPursuit(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done
|
||||||
// TODO: I don't know why they needed that parameter.
|
// TODO: I don't know why they needed that parameter.
|
||||||
void
|
void
|
||||||
CCopPed::SetPursuit(bool ignoreCopLimit)
|
CCopPed::SetPursuit(bool ignoreCopLimit)
|
||||||
{
|
{
|
||||||
|
if (CTimer::GetTimeInMilliseconds() < field_61C)
|
||||||
|
return;
|
||||||
|
|
||||||
CWanted *wanted = FindPlayerPed()->m_pWanted;
|
CWanted *wanted = FindPlayerPed()->m_pWanted;
|
||||||
if (m_bIsInPursuit || !IsPedInControl())
|
if (m_bIsInPursuit || !IsPedInControl())
|
||||||
return;
|
return;
|
||||||
|
@ -236,6 +241,7 @@ CCopPed::SetPursuit(bool ignoreCopLimit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done
|
||||||
void
|
void
|
||||||
CCopPed::ArrestPlayer(void)
|
CCopPed::ArrestPlayer(void)
|
||||||
{
|
{
|
||||||
|
@ -301,6 +307,7 @@ CCopPed::ScanForCrimes(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done
|
||||||
void
|
void
|
||||||
CCopPed::CopAI(void)
|
CCopPed::CopAI(void)
|
||||||
{
|
{
|
||||||
|
@ -318,11 +325,6 @@ CCopPed::CopAI(void)
|
||||||
if (bHitSomethingLastFrame) {
|
if (bHitSomethingLastFrame) {
|
||||||
m_bZoneDisabled = true;
|
m_bZoneDisabled = true;
|
||||||
m_bIsDisabledCop = true;
|
m_bIsDisabledCop = true;
|
||||||
#ifdef FIX_BUGS
|
|
||||||
m_nRoadblockNode = -1;
|
|
||||||
#else
|
|
||||||
m_nRoadblockNode = 0;
|
|
||||||
#endif
|
|
||||||
bKindaStayInSamePlace = true;
|
bKindaStayInSamePlace = true;
|
||||||
bIsRunning = false;
|
bIsRunning = false;
|
||||||
bNotAllowedToDuck = false;
|
bNotAllowedToDuck = false;
|
||||||
|
@ -349,6 +351,27 @@ CCopPed::CopAI(void)
|
||||||
}
|
}
|
||||||
if (wantedLevel > 0) {
|
if (wantedLevel > 0) {
|
||||||
if (!m_bIsDisabledCop) {
|
if (!m_bIsDisabledCop) {
|
||||||
|
// Turn and shoot the player's vehicle, if possible
|
||||||
|
if (!m_bIsInPursuit && !GetWeapon()->IsTypeMelee() && FindPlayerVehicle() && m_fDistanceToTarget < CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange) {
|
||||||
|
if (FindPlayerVehicle()->m_vecMoveSpeed.Magnitude2D() > 0.1f) {
|
||||||
|
CVector2D distToVeh = GetPosition() - FindPlayerVehicle()->GetPosition();
|
||||||
|
distToVeh.Normalise();
|
||||||
|
CVector2D vehSpeed = FindPlayerVehicle()->m_vecMoveSpeed;
|
||||||
|
vehSpeed.Normalise();
|
||||||
|
|
||||||
|
if (DotProduct2D(distToVeh, vehSpeed) > 0.8f) {
|
||||||
|
SetLookFlag(playerOrHisVeh, true);
|
||||||
|
SetMoveState(PEDMOVE_STILL);
|
||||||
|
if (TurnBody()) {
|
||||||
|
SetAttack(FindPlayerVehicle());
|
||||||
|
SetShootTimer(CGeneral::GetRandomNumberInRange(500.0f, 1000.0f));
|
||||||
|
SetAttackTimer(CGeneral::GetRandomNumberInRange(200.0f, 300.0f));
|
||||||
|
}
|
||||||
|
} else if (m_nPedState == PED_ATTACK)
|
||||||
|
RestorePreviousState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) {
|
if (!m_bIsInPursuit || wanted->m_CurrentCops > wanted->m_MaxCops) {
|
||||||
CCopPed *copFarthestToTarget = nil;
|
CCopPed *copFarthestToTarget = nil;
|
||||||
float copFarthestToTargetDist = m_fDistanceToTarget;
|
float copFarthestToTargetDist = m_fDistanceToTarget;
|
||||||
|
@ -391,11 +414,14 @@ CCopPed::CopAI(void)
|
||||||
|
|
||||||
if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
|
if (wantedLevel > 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED)
|
||||||
SetCurrentWeapon(WEAPONTYPE_COLT45);
|
SetCurrentWeapon(WEAPONTYPE_COLT45);
|
||||||
else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType != WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) {
|
else if (wantedLevel == 1 && GetWeapon()->m_eWeaponType == WEAPONTYPE_UNARMED && !FindPlayerPed()->m_pCurrentPhysSurface) {
|
||||||
// i.e. if player is on top of car, cop will still use colt45.
|
// i.e. if player is on top of car, cop will still use colt45.
|
||||||
SetCurrentWeapon(WEAPONTYPE_UNARMED);
|
SetCurrentWeapon(GetWeaponSlot(WEAPONTYPE_NIGHTSTICK) >= 0 ? WEAPONTYPE_NIGHTSTICK : WEAPONTYPE_UNARMED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_bBeatingSuspect && GetWeapon()->m_eWeaponType == WEAPONTYPE_NIGHTSTICK)
|
||||||
|
Say(SOUND_PED_PULLOUTWEAPON);
|
||||||
|
|
||||||
if (FindPlayerVehicle()) {
|
if (FindPlayerVehicle()) {
|
||||||
if (m_bBeatingSuspect) {
|
if (m_bBeatingSuspect) {
|
||||||
--wanted->m_CopsBeatingSuspect;
|
--wanted->m_CopsBeatingSuspect;
|
||||||
|
@ -406,18 +432,18 @@ CCopPed::CopAI(void)
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float weaponRange = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType)->m_fRange;
|
SetCurrentWeapon(WEAPONTYPE_COLT45);
|
||||||
|
CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
||||||
|
float weaponRange = weaponInfo->m_fRange;
|
||||||
SetLookFlag(playerOrHisVeh, true);
|
SetLookFlag(playerOrHisVeh, true);
|
||||||
TurnBody();
|
TurnBody();
|
||||||
SetCurrentWeapon(WEAPONTYPE_COLT45);
|
if (!bIsDucking || bCrouchWhenShooting && GetCrouchFireAnim(weaponInfo)) {
|
||||||
if (!bIsDucking) {
|
|
||||||
if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) {
|
if (m_attackTimer >= CTimer::GetTimeInMilliseconds()) {
|
||||||
if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) {
|
if (m_nPedState != PED_ATTACK && m_nPedState != PED_FIGHT && !m_bZoneDisabled) {
|
||||||
CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition();
|
CVector targetDist = playerOrHisVeh->GetPosition() - GetPosition();
|
||||||
if (m_fDistanceToTarget > 30.0f) {
|
if (m_fDistanceToTarget > 30.0f) {
|
||||||
CAnimBlendAssociation* crouchShootAssoc = RpAnimBlendClumpGetAssociation(GetClump(), ANIM_RBLOCK_CSHOOT);
|
if (bIsDucking)
|
||||||
if (crouchShootAssoc)
|
ClearDuck();
|
||||||
crouchShootAssoc->blendDelta = -1000.0f;
|
|
||||||
|
|
||||||
// Target is coming onto us
|
// Target is coming onto us
|
||||||
if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) {
|
if (DotProduct(playerOrHisVeh->m_vecMoveSpeed, targetDist) > 0.0f) {
|
||||||
|
@ -435,42 +461,23 @@ CCopPed::CopAI(void)
|
||||||
bNotAllowedToDuck = false;
|
bNotAllowedToDuck = false;
|
||||||
bDuckAndCover = false;
|
bDuckAndCover = false;
|
||||||
} else {
|
} else {
|
||||||
// VC checks for != nil compared to buggy behaviour of III. I check for != -1 here.
|
// TODO(Miami): Roadblock system is still III
|
||||||
#ifdef VC_PED_PORTS
|
|
||||||
float dotProd;
|
float dotProd;
|
||||||
if (m_nRoadblockNode != -1) {
|
if (m_nRoadblockNode != -1) {
|
||||||
// TODO(MIAMI): check this, i'm only getting this compile here....
|
|
||||||
CPathNode *roadBlockNode = &ThePaths.m_pathNodes[CRoadBlocks::RoadBlockNodes[m_nRoadblockNode]];
|
CPathNode *roadBlockNode = &ThePaths.m_pathNodes[CRoadBlocks::RoadBlockNodes[m_nRoadblockNode]];
|
||||||
dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockNode->GetPosition(), GetPosition() - roadBlockNode->GetPosition());
|
dotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockNode->GetPosition(), GetPosition() - roadBlockNode->GetPosition());
|
||||||
} else
|
} else
|
||||||
dotProd = -1.0f;
|
dotProd = -1.0f;
|
||||||
|
|
||||||
if(dotProd >= 0.0f) {
|
if(dotProd >= 0.0f) {
|
||||||
#else
|
|
||||||
|
|
||||||
#ifndef FIX_BUGS
|
|
||||||
float copRoadDotProd, targetRoadDotProd;
|
|
||||||
#else
|
|
||||||
float copRoadDotProd = 1.0f, targetRoadDotProd = 1.0f;
|
|
||||||
if (m_nRoadblockNode != -1)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
CTreadable* roadBlockRoad = ThePaths.m_mapObjects[CRoadBlocks::RoadBlockObjects[m_nRoadblockNode]];
|
|
||||||
CVector2D roadFwd = roadBlockRoad->GetForward();
|
|
||||||
copRoadDotProd = DotProduct2D(GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
|
|
||||||
targetRoadDotProd = DotProduct2D(playerOrHisVeh->GetPosition() - roadBlockRoad->GetPosition(), roadFwd);
|
|
||||||
}
|
|
||||||
// Roadblock may be towards road's fwd or opposite, so check both
|
|
||||||
if ((copRoadDotProd >= 0.0f || targetRoadDotProd >= 0.0f)
|
|
||||||
&& (copRoadDotProd <= 0.0f || targetRoadDotProd <= 0.0f)) {
|
|
||||||
#endif
|
|
||||||
bIsPointingGunAt = true;
|
bIsPointingGunAt = true;
|
||||||
} else {
|
} else {
|
||||||
|
if (bIsDucking)
|
||||||
|
ClearDuck();
|
||||||
m_bIsDisabledCop = false;
|
m_bIsDisabledCop = false;
|
||||||
bKindaStayInSamePlace = false;
|
bKindaStayInSamePlace = false;
|
||||||
bNotAllowedToDuck = false;
|
bNotAllowedToDuck = false;
|
||||||
bCrouchWhenShooting = false;
|
bCrouchWhenShooting = false;
|
||||||
bIsDucking = false;
|
|
||||||
bDuckAndCover = false;
|
bDuckAndCover = false;
|
||||||
SetPursuit(false);
|
SetPursuit(false);
|
||||||
}
|
}
|
||||||
|
@ -478,7 +485,6 @@ CCopPed::CopAI(void)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (m_fDistanceToTarget < weaponRange) {
|
if (m_fDistanceToTarget < weaponRange) {
|
||||||
CWeaponInfo *weaponInfo = CWeaponInfo::GetWeaponInfo(GetWeapon()->m_eWeaponType);
|
|
||||||
CVector gunPos = weaponInfo->m_vecFireOffset;
|
CVector gunPos = weaponInfo->m_vecFireOffset;
|
||||||
TransformToNode(gunPos, PED_HANDR);
|
TransformToNode(gunPos, PED_HANDR);
|
||||||
|
|
||||||
|
@ -487,6 +493,9 @@ CCopPed::CopAI(void)
|
||||||
if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt,
|
if (!CWorld::ProcessLineOfSight(gunPos, playerOrHisVeh->GetPosition(), foundCol, foundEnt,
|
||||||
false, true, false, false, true, false, false)
|
false, true, false, false, true, false, false)
|
||||||
|| foundEnt && foundEnt == playerOrHisVeh) {
|
|| foundEnt && foundEnt == playerOrHisVeh) {
|
||||||
|
|
||||||
|
if (m_pPointGunAt)
|
||||||
|
m_pPointGunAt->CleanUpOldReference((CEntity**) &m_pPointGunAt);
|
||||||
m_pPointGunAt = playerOrHisVeh;
|
m_pPointGunAt = playerOrHisVeh;
|
||||||
if (playerOrHisVeh)
|
if (playerOrHisVeh)
|
||||||
playerOrHisVeh->RegisterReference((CEntity**) &m_pPointGunAt);
|
playerOrHisVeh->RegisterReference((CEntity**) &m_pPointGunAt);
|
||||||
|
@ -494,7 +503,7 @@ CCopPed::CopAI(void)
|
||||||
SetAttack(playerOrHisVeh);
|
SetAttack(playerOrHisVeh);
|
||||||
SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000));
|
SetShootTimer(CGeneral::GetRandomNumberInRange(500, 1000));
|
||||||
}
|
}
|
||||||
SetAttackTimer(CGeneral::GetRandomNumberInRange(100, 300));
|
SetAttackTimer(CGeneral::GetRandomNumberInRange(200, 300));
|
||||||
}
|
}
|
||||||
SetMoveState(PEDMOVE_STILL);
|
SetMoveState(PEDMOVE_STILL);
|
||||||
}
|
}
|
||||||
|
@ -524,10 +533,8 @@ CCopPed::CopAI(void)
|
||||||
ClearObjective();
|
ClearObjective();
|
||||||
SetWanderPath(CGeneral::GetRandomNumber() & 7);
|
SetWanderPath(CGeneral::GetRandomNumber() & 7);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
#ifdef VC_PED_PORTS
|
if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && m_objective != OBJECTIVE_HASSLE_CHAR && CharCreatedBy == RANDOM_CHAR) {
|
||||||
else {
|
|
||||||
if (m_objective != OBJECTIVE_KILL_CHAR_ON_FOOT && CharCreatedBy == RANDOM_CHAR) {
|
|
||||||
for (int i = 0; i < m_numNearPeds; i++) {
|
for (int i = 0; i < m_numNearPeds; i++) {
|
||||||
CPed *nearPed = m_nearPeds[i];
|
CPed *nearPed = m_nearPeds[i];
|
||||||
if (nearPed->CharCreatedBy == RANDOM_CHAR) {
|
if (nearPed->CharCreatedBy == RANDOM_CHAR) {
|
||||||
|
@ -547,12 +554,30 @@ CCopPed::CopAI(void)
|
||||||
nearPed->bBeingChasedByPolice = true;
|
nearPed->bBeingChasedByPolice = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (nearPed->m_nPedType != PEDTYPE_COP && !nearPed->IsPlayer()
|
||||||
|
&& nearPed->IsPedInControl() && m_nHassleTimer < CTimer::GetTimeInMilliseconds()) {
|
||||||
|
|
||||||
|
if (nearPed->m_objective == OBJECTIVE_NONE && nearPed->m_nPedState == PED_WANDER_PATH
|
||||||
|
&& !nearPed->m_pLookTarget && nearPed->m_lookTimer < CTimer::GetTimeInMilliseconds()) {
|
||||||
|
|
||||||
|
if ((GetPosition() - nearPed->GetPosition()).MagnitudeSqr() < sq(5.0f)) {
|
||||||
|
|
||||||
|
if (CWorld::GetIsLineOfSightClear(GetPosition(), nearPed->GetPosition(),
|
||||||
|
true, false, false, false, false, false, false)) {
|
||||||
|
Say(SOUND_PED_COP_REACTION);
|
||||||
|
SetObjective(OBJECTIVE_HASSLE_CHAR, nearPed);
|
||||||
|
nearPed->SetObjective(OBJECTIVE_WAIT_ON_FOOT_FOR_COP, this);
|
||||||
|
m_nHassleTimer = CTimer::GetTimeInMilliseconds() + 100000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -563,18 +588,35 @@ CCopPed::CopAI(void)
|
||||||
bKindaStayInSamePlace = false;
|
bKindaStayInSamePlace = false;
|
||||||
bNotAllowedToDuck = false;
|
bNotAllowedToDuck = false;
|
||||||
bCrouchWhenShooting = false;
|
bCrouchWhenShooting = false;
|
||||||
bIsDucking = false;
|
|
||||||
bDuckAndCover = false;
|
bDuckAndCover = false;
|
||||||
|
if (bIsDucking)
|
||||||
|
ClearDuck();
|
||||||
if (m_pMyVehicle)
|
if (m_pMyVehicle)
|
||||||
SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
|
SetObjective(OBJECTIVE_ENTER_CAR_AS_DRIVER, m_pMyVehicle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done except commented things
|
||||||
void
|
void
|
||||||
CCopPed::ProcessControl(void)
|
CCopPed::ProcessControl(void)
|
||||||
{
|
{
|
||||||
|
if (m_nCopType == COP_HELI_SWAT)
|
||||||
|
ProcessHeliSwat();
|
||||||
|
|
||||||
CPed::ProcessControl();
|
CPed::ProcessControl();
|
||||||
|
|
||||||
|
if (m_bThrowsSpikeTrap) {
|
||||||
|
// TODO(Miami)
|
||||||
|
/*
|
||||||
|
if (CGame::currArea != AREA_MALL)
|
||||||
|
ProcessStingerCop();
|
||||||
|
*/
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(Miami): CStinger::Process
|
||||||
|
|
||||||
if (bWasPostponed)
|
if (bWasPostponed)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -606,25 +648,36 @@ CCopPed::ProcessControl(void)
|
||||||
if (IsPedInControl())
|
if (IsPedInControl())
|
||||||
SetIdle();
|
SetIdle();
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
if (m_bIsInPursuit) {
|
if (m_bIsInPursuit) {
|
||||||
if (player->m_nPedState != PED_ARRESTED && !player->DyingOrDead()) {
|
if (player->m_nPedState != PED_ARRESTED && !player->DyingOrDead()) {
|
||||||
switch (m_nCopType) {
|
if (player->m_pWanted->m_CurrentCops == 1) {
|
||||||
case COP_FBI:
|
Say(SOUND_PED_COP_ALONE);
|
||||||
Say(SOUND_PED_PURSUIT_FBI);
|
} else {
|
||||||
break;
|
int numCopsNear = 0;
|
||||||
case COP_SWAT:
|
for (int i = 0; i < player->m_numNearPeds; ++i) {
|
||||||
Say(SOUND_PED_PURSUIT_SWAT);
|
CPed *nearPed = player->m_nearPeds[i];
|
||||||
break;
|
if (nearPed->m_nPedType == PEDTYPE_COP && nearPed->m_nPedState != PED_DEAD)
|
||||||
case COP_ARMY:
|
++numCopsNear;
|
||||||
Say(SOUND_PED_PURSUIT_ARMY);
|
}
|
||||||
break;
|
if (numCopsNear <= 3) {
|
||||||
default:
|
Say(SOUND_PED_COP_LITTLECOPSAROUND);
|
||||||
Say(SOUND_PED_PURSUIT_COP);
|
if (!player->bInVehicle) {
|
||||||
break;
|
CVector distToPlayer = player->GetPosition() - GetPosition();
|
||||||
|
if (distToPlayer.MagnitudeSqr() < sq(20.0f)) {
|
||||||
|
player->Say(SOUND_PED_PLAYER_FARFROMCOPS);
|
||||||
|
if (player->m_nPedState != PED_ATTACK && player->m_nPedState != PED_AIM_GUN) {
|
||||||
|
player->SetLookFlag(this, false);
|
||||||
|
player->SetLookTimer(1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((CGeneral::GetRandomNumber() % 16) == 1) {
|
||||||
|
Say(SOUND_PED_COP_MANYCOPSAROUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} */
|
|
||||||
|
|
||||||
if (IsPedInControl()) {
|
if (IsPedInControl()) {
|
||||||
CopAI();
|
CopAI();
|
||||||
|
@ -671,23 +724,10 @@ CCopPed::ProcessControl(void)
|
||||||
RestorePreviousObjective();
|
RestorePreviousObjective();
|
||||||
} else {
|
} else {
|
||||||
if (player->m_pMyVehicle && player->m_pMyVehicle->m_nNumGettingIn != 0) {
|
if (player->m_pMyVehicle && player->m_pMyVehicle->m_nNumGettingIn != 0) {
|
||||||
// This is 1.3f when arresting in car without seeking first (in above)
|
|
||||||
#if defined(VC_PED_PORTS) || defined(FIX_BUGS)
|
|
||||||
m_distanceToCountSeekDone = 1.3f;
|
m_distanceToCountSeekDone = 1.3f;
|
||||||
#else
|
|
||||||
m_distanceToCountSeekDone = 2.0f;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bDuckAndCover) {
|
if (!bDuckAndCover && Seek()) {
|
||||||
#if !defined(GTA3_1_1_PATCH) && !defined(VC_PED_PORTS)
|
|
||||||
if (!bNotAllowedToDuck && Seek()) {
|
|
||||||
SetMoveState(PEDMOVE_STILL);
|
|
||||||
SetMoveAnim();
|
|
||||||
SetPointGunAt(m_pedInObjective);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else if (Seek()) {
|
|
||||||
CVehicle *playerVeh = FindPlayerVehicle();
|
CVehicle *playerVeh = FindPlayerVehicle();
|
||||||
if (!playerVeh && player && player->EnteringCar()) {
|
if (!playerVeh && player && player->EnteringCar()) {
|
||||||
SetArrestPlayer(player);
|
SetArrestPlayer(player);
|
||||||
|
@ -718,9 +758,11 @@ CCopPed::ProcessControl(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_bStopAndShootDisabledZone)
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
if (m_pPointGunAt)
|
||||||
|
Say(SOUND_PED_COP_UNK_129);
|
||||||
|
|
||||||
|
if (m_bStopAndShootDisabledZone) {
|
||||||
bool dontShoot = false;
|
bool dontShoot = false;
|
||||||
if (GetIsOnScreen()) {
|
if (GetIsOnScreen()) {
|
||||||
if (((CTimer::GetFrameCounter() + m_randomSeed) & 0x1F) == 17) {
|
if (((CTimer::GetFrameCounter() + m_randomSeed) & 0x1F) == 17) {
|
||||||
|
@ -750,3 +792,66 @@ CCopPed::ProcessControl(void)
|
||||||
SetAttack(m_pedInObjective);
|
SetAttack(m_pedInObjective);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (field_624 >= 2 && m_objective == OBJECTIVE_KILL_CHAR_ON_FOOT) {
|
||||||
|
CVector centre = GetPosition() + CVector(0.f, 0.f, 0.65f);
|
||||||
|
if (CWorld::TestSphereAgainstWorld(centre, 0.35f, this, true, false, false, false, false, false)) {
|
||||||
|
field_624 = 0;
|
||||||
|
m_bStopAndShootDisabledZone = true;
|
||||||
|
ClearPursuit();
|
||||||
|
SetObjective(OBJECTIVE_NONE);
|
||||||
|
SetWanderPath(CGeneral::GetRandomNumberInRange(0,8));
|
||||||
|
field_61C = CTimer::GetTimeInMilliseconds() + 30000;
|
||||||
|
} else {
|
||||||
|
field_624 = 0;
|
||||||
|
if (GetWeapon()->IsTypeMelee()) {
|
||||||
|
// TODO(Miami): enum
|
||||||
|
for (int i = 3; i < 7; i++) {
|
||||||
|
if (HasWeaponSlot(i)) {
|
||||||
|
SetCurrentWeapon(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetMoveState(PEDMOVE_STILL);
|
||||||
|
bStopAndShoot = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (CTimer::GetTimeStep() / 100.f <= m_fDistanceTravelled)
|
||||||
|
field_624 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --MIAMI: Done
|
||||||
|
void
|
||||||
|
CCopPed::ProcessHeliSwat(void)
|
||||||
|
{
|
||||||
|
CVector bestPos = GetPosition();
|
||||||
|
SetPedState(PED_ABSEIL);
|
||||||
|
CPedPlacement::FindZCoorForPed(&bestPos);
|
||||||
|
if (GetPosition().z - 2.0f >= bestPos.z && m_pRopeEntity) {
|
||||||
|
m_fAbseilPos += 0.003f * CTimer::GetTimeStep();
|
||||||
|
m_vecMoveSpeed.z = -0.03f;
|
||||||
|
m_vecTurnSpeed = CVector(0.f, 0.f, (m_randomSeed % 32) * 0.003f - 0.05f);
|
||||||
|
CPhysical::ApplyTurnSpeed();
|
||||||
|
GetMatrix().Reorthogonalise();
|
||||||
|
CVector posOnRope;
|
||||||
|
|
||||||
|
if (CRopes::FindCoorsAlongRope(m_nRopeID, m_fAbseilPos, &posOnRope)) {
|
||||||
|
SetPosition(posOnRope);
|
||||||
|
} else {
|
||||||
|
bUsesCollision = true;
|
||||||
|
m_vecMoveSpeed = CVector(0.f, 0.f, 0.f);
|
||||||
|
SetPedState(PED_IDLE);
|
||||||
|
m_nCopType = COP_SWAT;
|
||||||
|
SetInTheAir();
|
||||||
|
bKnockedUpIntoAir = true;
|
||||||
|
}
|
||||||
|
Say(SOUND_PED_COP_HELIPILOTPHRASE);
|
||||||
|
} else {
|
||||||
|
bUsesCollision = true;
|
||||||
|
m_vecMoveSpeed = CVector(0.f, 0.f, 0.f);
|
||||||
|
SetPedState(PED_IDLE);
|
||||||
|
m_nCopType = COP_SWAT;
|
||||||
|
SetInTheAir();
|
||||||
|
bKnockedUpIntoAir = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,7 +6,8 @@ enum eCopType
|
||||||
COP_STREET = 0,
|
COP_STREET = 0,
|
||||||
COP_FBI = 1,
|
COP_FBI = 1,
|
||||||
COP_SWAT = 2,
|
COP_SWAT = 2,
|
||||||
COP_ARMY = 3,
|
COP_HELI_SWAT = 3,
|
||||||
|
COP_ARMY = 4,
|
||||||
COP_MIAMIVICE = 5
|
COP_MIAMIVICE = 5
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,7 +19,6 @@ public:
|
||||||
bool m_bIsInPursuit;
|
bool m_bIsInPursuit;
|
||||||
bool m_bIsDisabledCop;
|
bool m_bIsDisabledCop;
|
||||||
int8 field_5FE;
|
int8 field_5FE;
|
||||||
int8 field_5FF;
|
|
||||||
bool m_bBeatingSuspect;
|
bool m_bBeatingSuspect;
|
||||||
bool m_bStopAndShootDisabledZone;
|
bool m_bStopAndShootDisabledZone;
|
||||||
bool field_601; // set when police dragging player from car
|
bool field_601; // set when police dragging player from car
|
||||||
|
@ -28,6 +28,8 @@ public:
|
||||||
bool m_bThrowsSpikeTrap;
|
bool m_bThrowsSpikeTrap;
|
||||||
CEntity *m_pRopeEntity; // CHeli or 1
|
CEntity *m_pRopeEntity; // CHeli or 1
|
||||||
uintptr m_nRopeID;
|
uintptr m_nRopeID;
|
||||||
|
uint32 m_nHassleTimer;
|
||||||
|
uint32 field_61C;
|
||||||
int32 field_624;
|
int32 field_624;
|
||||||
int8 field_628;
|
int8 field_628;
|
||||||
|
|
||||||
|
@ -41,6 +43,7 @@ public:
|
||||||
void ArrestPlayer(void);
|
void ArrestPlayer(void);
|
||||||
void ScanForCrimes(void);
|
void ScanForCrimes(void);
|
||||||
void CopAI(void);
|
void CopAI(void);
|
||||||
|
void ProcessHeliSwat(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef PED_SKIN
|
#ifndef PED_SKIN
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
#include "PedPlacement.h"
|
#include "PedPlacement.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
|
|
||||||
void
|
// --MIAMI: Done
|
||||||
|
bool
|
||||||
CPedPlacement::FindZCoorForPed(CVector* pos)
|
CPedPlacement::FindZCoorForPed(CVector* pos)
|
||||||
{
|
{
|
||||||
float zForPed;
|
float zForPed;
|
||||||
|
@ -32,8 +33,11 @@ CPedPlacement::FindZCoorForPed(CVector* pos)
|
||||||
|
|
||||||
zForPed = Max(foundColZ, foundColZ2);
|
zForPed = Max(foundColZ, foundColZ2);
|
||||||
|
|
||||||
if (zForPed > -99.0f)
|
if (zForPed > -99.0f) {
|
||||||
pos->z = FEET_OFFSET + zForPed;
|
pos->z = FEET_OFFSET + zForPed;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
CEntity*
|
CEntity*
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
class CPedPlacement {
|
class CPedPlacement {
|
||||||
public:
|
public:
|
||||||
static void FindZCoorForPed(CVector* pos);
|
static bool FindZCoorForPed(CVector* pos);
|
||||||
static CEntity* IsPositionClearOfCars(Const CVector*);
|
static CEntity* IsPositionClearOfCars(Const CVector*);
|
||||||
static bool IsPositionClearForPed(const CVector& pos, float radius = -1.0f, int total = -1, CEntity** entities = nil);
|
static bool IsPositionClearForPed(const CVector& pos, float radius = -1.0f, int total = -1, CEntity** entities = nil);
|
||||||
};
|
};
|
|
@ -116,86 +116,117 @@ char *trim(char *s) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
|
FILE* _fcaseopen(char const* filename, char const* mode)
|
||||||
// r must have strlen(path) + 2 bytes
|
|
||||||
int casepath(char const *path, char *r)
|
|
||||||
{
|
{
|
||||||
|
FILE* result;
|
||||||
|
char* real = casepath(filename);
|
||||||
|
if (!real)
|
||||||
|
result = fopen(filename, mode);
|
||||||
|
else {
|
||||||
|
result = fopen(real, mode);
|
||||||
|
free(real);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Case-insensitivity on linux (from https://github.com/OneSadCookie/fcaseopen)
|
||||||
|
// Returned string should freed manually (if exists)
|
||||||
|
char* casepath(char const* path, bool checkPathFirst)
|
||||||
|
{
|
||||||
|
if (checkPathFirst && access(path, F_OK) != -1) {
|
||||||
|
// File path is correct
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
size_t l = strlen(path);
|
size_t l = strlen(path);
|
||||||
char* p = (char*)alloca(l + 1);
|
char* p = (char*)alloca(l + 1);
|
||||||
|
char* out = (char*)malloc(l + 3); // for extra ./
|
||||||
strcpy(p, path);
|
strcpy(p, path);
|
||||||
|
|
||||||
// my addon: change \'s with /
|
|
||||||
char *nextBs;
|
|
||||||
while(nextBs = strstr(p, "\\")){
|
|
||||||
*nextBs = '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
// my addon: linux doesn't handle filenames with spaces at the end nicely
|
// my addon: linux doesn't handle filenames with spaces at the end nicely
|
||||||
p = trim(p);
|
p = trim(p);
|
||||||
|
|
||||||
size_t rl = 0;
|
size_t rl = 0;
|
||||||
|
|
||||||
DIR* d;
|
DIR* d;
|
||||||
if (p[0] == '/')
|
if (p[0] == '/' || p[0] == '\\')
|
||||||
{
|
{
|
||||||
d = opendir("/");
|
d = opendir("/");
|
||||||
p = p + 1;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
d = opendir(".");
|
d = opendir(".");
|
||||||
r[0] = '.';
|
out[0] = '.';
|
||||||
r[1] = 0;
|
out[1] = 0;
|
||||||
rl = 1;
|
rl = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int last = 0;
|
bool cantProceed = false; // just convert slashes in what's left in string, not case sensitivity
|
||||||
char *c = strsep(&p, "/");
|
bool mayBeTrailingSlash = false;
|
||||||
while (c)
|
char* c;
|
||||||
|
while (c = strsep(&p, "/\\"))
|
||||||
{
|
{
|
||||||
if (!d)
|
// May be trailing slash(allow), slash at the start(avoid), or multiple slashes(avoid)
|
||||||
|
if (*c == '\0')
|
||||||
{
|
{
|
||||||
return 0;
|
mayBeTrailingSlash = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
mayBeTrailingSlash = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (last)
|
out[rl] = '/';
|
||||||
{
|
|
||||||
closedir(d);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
r[rl] = '/';
|
|
||||||
rl += 1;
|
rl += 1;
|
||||||
r[rl] = 0;
|
out[rl] = 0;
|
||||||
|
|
||||||
struct dirent *e = readdir(d);
|
if (cantProceed)
|
||||||
while (e)
|
{
|
||||||
|
strcpy(out + rl, c);
|
||||||
|
rl += strlen(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent* e;
|
||||||
|
while (e = readdir(d))
|
||||||
{
|
{
|
||||||
if (strcasecmp(c, e->d_name) == 0)
|
if (strcasecmp(c, e->d_name) == 0)
|
||||||
{
|
{
|
||||||
strcpy(r + rl, e->d_name);
|
strcpy(out + rl, e->d_name);
|
||||||
rl += strlen(e->d_name);
|
int reportedLen = (int)strlen(e->d_name);
|
||||||
|
rl += reportedLen;
|
||||||
|
assert(reportedLen == strlen(c) && "casepath: This is not good at all");
|
||||||
|
|
||||||
closedir(d);
|
closedir(d);
|
||||||
d = opendir(r);
|
d = opendir(out);
|
||||||
|
|
||||||
|
// Either it wasn't a folder, or permission error, I/O error etc.
|
||||||
|
if (!d) {
|
||||||
|
cantProceed = true;
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
e = readdir(d);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!e)
|
if (!e)
|
||||||
{
|
{
|
||||||
strcpy(r + rl, c);
|
printf("casepath couldn't find dir/file \"%s\", full path was %s\n", c, path);
|
||||||
|
// No match, add original name and continue converting further slashes.
|
||||||
|
strcpy(out + rl, c);
|
||||||
rl += strlen(c);
|
rl += strlen(c);
|
||||||
last = 1;
|
cantProceed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
c = strsep(&p, "/");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d) closedir(d);
|
if (d) closedir(d);
|
||||||
return 1;
|
if (mayBeTrailingSlash) {
|
||||||
|
out[rl] = '/'; rl += 1;
|
||||||
|
out[rl] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rl > l + 2) {
|
||||||
|
printf("\n\ncasepath: Corrected path length is longer then original+2:\n\tOriginal: %s (%d chars)\n\tCorrected: %s (%d chars)\n\n", path, l, out, rl);
|
||||||
|
}
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,7 +23,7 @@ enum eWinVersion
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#endif
|
#endif
|
||||||
extern DWORD _dwOperatingSystemVersion;
|
extern DWORD _dwOperatingSystemVersion;
|
||||||
|
#define fcaseopen fopen
|
||||||
#else
|
#else
|
||||||
char *strupr(char *str);
|
char *strupr(char *str);
|
||||||
char *strlwr(char *str);
|
char *strlwr(char *str);
|
||||||
|
@ -43,7 +43,9 @@ enum {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern long _dwOperatingSystemVersion;
|
extern long _dwOperatingSystemVersion;
|
||||||
int casepath(char const *path, char *r);
|
char *casepath(char const *path, bool checkPathFirst = true);
|
||||||
|
FILE *_fcaseopen(char const *filename, char const *mode);
|
||||||
|
#define fcaseopen _fcaseopen
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RW_GL3
|
#ifdef RW_GL3
|
||||||
|
|
|
@ -731,12 +731,12 @@ CHeli::SendDownSwat(void)
|
||||||
|
|
||||||
float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, nil);
|
float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, nil);
|
||||||
if(Abs(FindPlayerCoors().z - groundZ) < 2.5f && CRopes::RegisterRope((uintptr)this + m_numSwat-1, pos, false)){
|
if(Abs(FindPlayerCoors().z - groundZ) < 2.5f && CRopes::RegisterRope((uintptr)this + m_numSwat-1, pos, false)){
|
||||||
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_ARMY, pos);
|
CCopPed *swat = (CCopPed*)CPopulation::AddPed(PEDTYPE_COP, COP_HELI_SWAT, pos);
|
||||||
swat->bUsesCollision = false;
|
swat->bUsesCollision = false;
|
||||||
swat->m_pRopeEntity = this;
|
swat->m_pRopeEntity = this;
|
||||||
RegisterReference(&swat->m_pRopeEntity);
|
RegisterReference(&swat->m_pRopeEntity);
|
||||||
m_numSwat--;
|
m_numSwat--;
|
||||||
swat->m_nRopeID = m_numSwat;
|
swat->m_nRopeID = (uintptr)this + m_numSwat;
|
||||||
m_aSwatState[m_numSwat] = 255;
|
m_aSwatState[m_numSwat] = 255;
|
||||||
CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
|
CAnimManager::BlendAnimation(swat->GetClump(), ASSOCGRP_STD, ANIM_ABSEIL, 4.0f);
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue