mirror of https://github.com/Nofated095/re-GTA.git
WaterCannon done, resource ico
This commit is contained in:
parent
9e49e5c2bd
commit
3366cd0ff8
|
@ -7533,8 +7533,8 @@ cAudioManager::ProcessVehicleSkidding(cVehicleParams *params)
|
||||||
void cAudioManager::ProcessWaterCannon(int32)
|
void cAudioManager::ProcessWaterCannon(int32)
|
||||||
{
|
{
|
||||||
for(int32 i = 0; i < NUM_WATERCANNONS; i++) {
|
for(int32 i = 0; i < NUM_WATERCANNONS; i++) {
|
||||||
if(aCannons[i].m_nId) {
|
if(CWaterCannons::aCannons[i].m_nId) {
|
||||||
m_sQueueSample.m_vecPos = aCannons[0].m_avecPos[aCannons[i].m_wIndex];
|
m_sQueueSample.m_vecPos = CWaterCannons::aCannons[0].m_avecPos[CWaterCannons::aCannons[i].m_nCur];
|
||||||
float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
|
float distSquared = GetDistanceSquared(&m_sQueueSample.m_vecPos);
|
||||||
if(distSquared < 900.f) {
|
if(distSquared < 900.f) {
|
||||||
m_sQueueSample.m_fDistance = Sqrt(distSquared);
|
m_sQueueSample.m_fDistance = Sqrt(distSquared);
|
||||||
|
|
|
@ -38,6 +38,14 @@ public:
|
||||||
}else
|
}else
|
||||||
x = 1.0f;
|
x = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Normalise(float norm) {
|
||||||
|
float sq = MagnitudeSqr();
|
||||||
|
float invsqrt = RecipSqrt(norm, sq);
|
||||||
|
x *= invsqrt;
|
||||||
|
y *= invsqrt;
|
||||||
|
z *= invsqrt;
|
||||||
|
}
|
||||||
|
|
||||||
const CVector &operator+=(CVector const &right) {
|
const CVector &operator+=(CVector const &right) {
|
||||||
x += right.x;
|
x += right.x;
|
||||||
|
|
|
@ -1,10 +1,320 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "patcher.h"
|
#include "patcher.h"
|
||||||
#include "WaterCannon.h"
|
#include "WaterCannon.h"
|
||||||
|
#include "Vector.h"
|
||||||
|
#include "General.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "Timer.h"
|
||||||
|
#include "Pools.h"
|
||||||
|
#include "Ped.h"
|
||||||
|
#include "AnimManager.h"
|
||||||
|
#include "Fire.h"
|
||||||
|
#include "WaterLevel.h"
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
CWaterCannon (&aCannons)[NUM_WATERCANNONS] = *(CWaterCannon(*)[NUM_WATERCANNONS])*(uintptr*)0x8F2CA8;
|
#define WATERCANNONVERTS 4
|
||||||
|
#define WATERCANNONINDEXES 12
|
||||||
|
|
||||||
WRAPPER void CWaterCannons::Update(void) { EAXJMP(0x522510); }
|
RwIm3DVertex WaterCannonVertices[WATERCANNONVERTS];
|
||||||
WRAPPER void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir) { EAXJMP(0x522470); }
|
RwImVertexIndex WaterCannonIndexList[WATERCANNONINDEXES];
|
||||||
WRAPPER void CWaterCannons::Render(void) { EAXJMP(0x522550); }
|
|
||||||
WRAPPER void CWaterCannons::Init(void) { EAXJMP(0x522440); }
|
CWaterCannon CWaterCannons::aCannons[NUM_WATERCANNONS];
|
||||||
|
|
||||||
|
void CWaterCannon::Init(void)
|
||||||
|
{
|
||||||
|
m_nId = 0;
|
||||||
|
m_nCur = 0;
|
||||||
|
m_nTimeCreated = CTimer::GetTimeInMilliseconds();
|
||||||
|
|
||||||
|
for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
|
||||||
|
m_abUsed[i] = false;
|
||||||
|
|
||||||
|
WaterCannonVertices[0].u = 0.0f;
|
||||||
|
WaterCannonVertices[0].v = 0.0f;
|
||||||
|
|
||||||
|
WaterCannonVertices[1].u = 1.0f;
|
||||||
|
WaterCannonVertices[1].v = 0.0f;
|
||||||
|
|
||||||
|
WaterCannonVertices[2].u = 0.0f;
|
||||||
|
WaterCannonVertices[2].v = 0.0f;
|
||||||
|
|
||||||
|
WaterCannonVertices[3].u = 1.0f;
|
||||||
|
WaterCannonVertices[3].v = 0.0f;
|
||||||
|
|
||||||
|
WaterCannonIndexList[0] = 0;
|
||||||
|
WaterCannonIndexList[1] = 1;
|
||||||
|
WaterCannonIndexList[2] = 2;
|
||||||
|
|
||||||
|
WaterCannonIndexList[3] = 1;
|
||||||
|
WaterCannonIndexList[4] = 3;
|
||||||
|
WaterCannonIndexList[5] = 2;
|
||||||
|
|
||||||
|
WaterCannonIndexList[6] = 0;
|
||||||
|
WaterCannonIndexList[7] = 2;
|
||||||
|
WaterCannonIndexList[8] = 1;
|
||||||
|
|
||||||
|
WaterCannonIndexList[9] = 1;
|
||||||
|
WaterCannonIndexList[10] = 2;
|
||||||
|
WaterCannonIndexList[11] = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannon::Update_OncePerFrame(int16 index)
|
||||||
|
{
|
||||||
|
ASSERT(index < NUM_WATERCANNONS);
|
||||||
|
|
||||||
|
if (CTimer::GetTimeInMilliseconds() > m_nTimeCreated + WATERCANNON_LIFETIME )
|
||||||
|
{
|
||||||
|
m_nCur = (m_nCur + 1) % -NUM_SEGMENTPOINTS;
|
||||||
|
m_abUsed[m_nCur] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
|
||||||
|
{
|
||||||
|
if ( m_abUsed[i] )
|
||||||
|
{
|
||||||
|
m_avecVelocity[i].z += -WATERCANNON_GRAVITY * CTimer::GetTimeStep();
|
||||||
|
m_avecPos[i] += m_avecVelocity[i] * CTimer::GetTimeStep();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32 extinguishingPoint = CGeneral::GetRandomNumber() & (NUM_SEGMENTPOINTS - 1);
|
||||||
|
if ( m_abUsed[extinguishingPoint] )
|
||||||
|
gFireManager.ExtinguishPoint(m_avecPos[extinguishingPoint], 3.0f);
|
||||||
|
|
||||||
|
if ( ((index + CTimer::GetFrameCounter()) & 3) == 0 )
|
||||||
|
PushPeds();
|
||||||
|
|
||||||
|
// free if unused
|
||||||
|
|
||||||
|
int32 i = 0;
|
||||||
|
while ( 1 )
|
||||||
|
{
|
||||||
|
if ( m_abUsed[i] )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( ++i >= NUM_SEGMENTPOINTS )
|
||||||
|
{
|
||||||
|
m_nId = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannon::Update_NewInput(CVector *pos, CVector *dir)
|
||||||
|
{
|
||||||
|
ASSERT(pos != NULL);
|
||||||
|
ASSERT(dir != NULL);
|
||||||
|
|
||||||
|
m_avecPos[m_nCur] = *pos;
|
||||||
|
m_avecVelocity[m_nCur] = *dir;
|
||||||
|
m_abUsed[m_nCur] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannon::Render(void)
|
||||||
|
{
|
||||||
|
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)gpWaterRaster);
|
||||||
|
|
||||||
|
float v = float(CGeneral::GetRandomNumber() & 255) / 256;
|
||||||
|
|
||||||
|
WaterCannonVertices[0].v = v;
|
||||||
|
WaterCannonVertices[1].v = v;
|
||||||
|
WaterCannonVertices[2].v = v;
|
||||||
|
WaterCannonVertices[3].v = v;
|
||||||
|
|
||||||
|
int16 pointA = m_nCur % -NUM_SEGMENTPOINTS;
|
||||||
|
|
||||||
|
int16 pointB = pointA - 1;
|
||||||
|
if ( (pointA - 1) < 0 )
|
||||||
|
pointB += NUM_SEGMENTPOINTS;
|
||||||
|
|
||||||
|
bool bInit = false;
|
||||||
|
CVector norm;
|
||||||
|
|
||||||
|
for ( int32 i = 0; i < NUM_SEGMENTPOINTS - 1; i++ )
|
||||||
|
{
|
||||||
|
if ( m_abUsed[pointA] && m_abUsed[pointB] )
|
||||||
|
{
|
||||||
|
if ( !bInit )
|
||||||
|
{
|
||||||
|
CVector cp = CrossProduct(m_avecPos[pointB] - m_avecPos[pointA], TheCamera.GetForward());
|
||||||
|
cp.Normalise(0.05f);
|
||||||
|
norm = cp;
|
||||||
|
bInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
float dist = float(i*i*i) / 300.0f + 1.0f;
|
||||||
|
float brightness = float(i) / NUM_SEGMENTPOINTS;
|
||||||
|
|
||||||
|
int32 color = (int32)((1.0f - brightness*brightness) * 255.0f);
|
||||||
|
CVector offset = dist * norm;
|
||||||
|
|
||||||
|
RwIm3DVertexSetRGBA(&WaterCannonVertices[0], color, color, color, color);
|
||||||
|
RwIm3DVertexSetPos (&WaterCannonVertices[0], m_avecPos[pointA].x - offset.x, m_avecPos[pointA].y - offset.y, m_avecPos[pointA].z - offset.z);
|
||||||
|
|
||||||
|
RwIm3DVertexSetRGBA(&WaterCannonVertices[1], color, color, color, color);
|
||||||
|
RwIm3DVertexSetPos (&WaterCannonVertices[1], m_avecPos[pointA].x + offset.x, m_avecPos[pointA].y + offset.y, m_avecPos[pointA].z + offset.z);
|
||||||
|
|
||||||
|
RwIm3DVertexSetRGBA(&WaterCannonVertices[2], color, color, color, color);
|
||||||
|
RwIm3DVertexSetPos (&WaterCannonVertices[2], m_avecPos[pointB].x - offset.x, m_avecPos[pointB].y - offset.y, m_avecPos[pointB].z - offset.z);
|
||||||
|
|
||||||
|
RwIm3DVertexSetRGBA(&WaterCannonVertices[3], color, color, color, color);
|
||||||
|
RwIm3DVertexSetPos (&WaterCannonVertices[3], m_avecPos[pointB].x + offset.x, m_avecPos[pointB].y + offset.y, m_avecPos[pointB].z + offset.z);
|
||||||
|
|
||||||
|
LittleTest();
|
||||||
|
|
||||||
|
if ( RwIm3DTransform(WaterCannonVertices, WATERCANNONVERTS, NULL, rwIM3D_VERTEXUV) )
|
||||||
|
{
|
||||||
|
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, WaterCannonIndexList, WATERCANNONINDEXES);
|
||||||
|
RwIm3DEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pointA = pointB--;
|
||||||
|
if ( pointB < 0 )
|
||||||
|
pointB += NUM_SEGMENTPOINTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE);
|
||||||
|
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannon::PushPeds(void)
|
||||||
|
{
|
||||||
|
float minx = 10000.0f;
|
||||||
|
float maxx = -10000.0f;
|
||||||
|
float miny = 10000.0f;
|
||||||
|
float maxy = -10000.0f;
|
||||||
|
float minz = 10000.0f;
|
||||||
|
float maxz = -10000.0f;
|
||||||
|
|
||||||
|
for ( int32 i = 0; i < NUM_SEGMENTPOINTS; i++ )
|
||||||
|
{
|
||||||
|
if ( m_abUsed[i] )
|
||||||
|
{
|
||||||
|
minx = min(minx, m_avecPos[i].x);
|
||||||
|
maxx = max(maxx, m_avecPos[i].x);
|
||||||
|
|
||||||
|
miny = min(miny, m_avecPos[i].y);
|
||||||
|
maxy = max(maxy, m_avecPos[i].y);
|
||||||
|
|
||||||
|
minz = min(minz, m_avecPos[i].z);
|
||||||
|
maxz = max(maxz, m_avecPos[i].z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( int32 i = CPools::GetPedPool()->GetSize() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
CPed *ped = CPools::GetPedPool()->GetSlot(i);
|
||||||
|
if ( ped )
|
||||||
|
{
|
||||||
|
if ( ped->GetPosition().x > minx && ped->GetPosition().x < maxx
|
||||||
|
&& ped->GetPosition().y > miny && ped->GetPosition().y < maxy
|
||||||
|
&& ped->GetPosition().z > minz && ped->GetPosition().z < maxz )
|
||||||
|
{
|
||||||
|
for ( int32 j = 0; j < NUM_SEGMENTPOINTS; j++ )
|
||||||
|
{
|
||||||
|
if ( m_abUsed[j] )
|
||||||
|
{
|
||||||
|
CVector dist = m_avecPos[j] - ped->GetPosition();
|
||||||
|
|
||||||
|
if ( dist.MagnitudeSqr() < 5.0f )
|
||||||
|
{
|
||||||
|
int32 localDir = ped->GetLocalDirection(CVector2D(1.0f, 0.0f));
|
||||||
|
|
||||||
|
ped->bIsStanding = false;
|
||||||
|
|
||||||
|
ped->ApplyMoveForce(0.0f, 0.0f, 2.0f * CTimer::GetTimeStep());
|
||||||
|
|
||||||
|
ped->m_vecMoveSpeed.x = (0.6f * m_avecVelocity[j].x + ped->m_vecMoveSpeed.x) * 0.5f;
|
||||||
|
ped->m_vecMoveSpeed.y = (0.6f * m_avecVelocity[j].y + ped->m_vecMoveSpeed.y) * 0.5f;
|
||||||
|
|
||||||
|
ped->SetFall(2000, AnimationId(ANIM_KO_SKID_FRONT + localDir), 0);
|
||||||
|
|
||||||
|
CFire *fire = ped->m_pFire;
|
||||||
|
if ( fire )
|
||||||
|
fire->Extinguish();
|
||||||
|
|
||||||
|
j = NUM_SEGMENTPOINTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannons::Init(void)
|
||||||
|
{
|
||||||
|
for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
|
||||||
|
aCannons[i].Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir)
|
||||||
|
{
|
||||||
|
ASSERT(pos != NULL);
|
||||||
|
ASSERT(dir != NULL);
|
||||||
|
|
||||||
|
// find the one by id
|
||||||
|
{
|
||||||
|
int32 n = 0;
|
||||||
|
while ( n < NUM_WATERCANNONS && id != aCannons[n].m_nId )
|
||||||
|
n++;
|
||||||
|
|
||||||
|
if ( n < NUM_WATERCANNONS )
|
||||||
|
{
|
||||||
|
aCannons[n].Update_NewInput(pos, dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no luck then find a free one
|
||||||
|
{
|
||||||
|
int32 n = 0;
|
||||||
|
while ( n < NUM_WATERCANNONS && 0 != aCannons[n].m_nId )
|
||||||
|
n++;
|
||||||
|
|
||||||
|
if ( n < NUM_WATERCANNONS )
|
||||||
|
{
|
||||||
|
aCannons[n].Init();
|
||||||
|
aCannons[n].m_nId = id;
|
||||||
|
aCannons[n].Update_NewInput(pos, dir);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannons::Update(void)
|
||||||
|
{
|
||||||
|
for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
|
||||||
|
{
|
||||||
|
if ( aCannons[i].m_nId != 0 )
|
||||||
|
aCannons[i].Update_OncePerFrame(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CWaterCannons::Render(void)
|
||||||
|
{
|
||||||
|
for ( int32 i = 0; i < NUM_WATERCANNONS; i++ )
|
||||||
|
{
|
||||||
|
if ( aCannons[i].m_nId != 0 )
|
||||||
|
aCannons[i].Render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTPATCHES
|
||||||
|
InjectHook(0x521A30, &CWaterCannon::Init, PATCH_JUMP);
|
||||||
|
InjectHook(0x521B80, &CWaterCannon::Update_OncePerFrame, PATCH_JUMP);
|
||||||
|
InjectHook(0x521CC0, &CWaterCannon::Update_NewInput, PATCH_JUMP);
|
||||||
|
InjectHook(0x521D30, &CWaterCannon::Render, PATCH_JUMP);
|
||||||
|
InjectHook(0x5220B0, &CWaterCannon::PushPeds, PATCH_JUMP);
|
||||||
|
InjectHook(0x522440, CWaterCannons::Init, PATCH_JUMP);
|
||||||
|
InjectHook(0x522470, CWaterCannons::UpdateOne, PATCH_JUMP);
|
||||||
|
InjectHook(0x522510, CWaterCannons::Update, PATCH_JUMP);
|
||||||
|
InjectHook(0x522550, CWaterCannons::Render, PATCH_JUMP);
|
||||||
|
//InjectHook(0x522B40, `global constructor keyed to'watercannon.cpp, PATCH_JUMP);
|
||||||
|
//InjectHook(0x522B60, CWaterCannon::CWaterCannon, PATCH_JUMP);
|
||||||
|
ENDPATCHES
|
|
@ -1,15 +1,29 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define WATERCANNON_GRAVITY (0.009f)
|
||||||
|
#define WATERCANNON_LIFETIME (150)
|
||||||
|
|
||||||
class CWaterCannon
|
class CWaterCannon
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
NUM_SEGMENTPOINTS = 16,
|
||||||
|
};
|
||||||
|
|
||||||
int32 m_nId;
|
int32 m_nId;
|
||||||
int16 m_wIndex;
|
int16 m_nCur;
|
||||||
char gap_6[2];
|
char _pad0[2];
|
||||||
int32 m_nTimeCreated;
|
uint32 m_nTimeCreated;
|
||||||
CVector m_avecPos[16];
|
CVector m_avecPos[NUM_SEGMENTPOINTS];
|
||||||
CVector m_avecVelocity[16];
|
CVector m_avecVelocity[NUM_SEGMENTPOINTS];
|
||||||
char m_abUsed[16];
|
bool m_abUsed[NUM_SEGMENTPOINTS];
|
||||||
|
|
||||||
|
void Init(void);
|
||||||
|
void Update_OncePerFrame(int16 index);
|
||||||
|
void Update_NewInput(CVector *pos, CVector *dir);
|
||||||
|
void Render(void);
|
||||||
|
void PushPeds(void);
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(CWaterCannon) == 412, "CWaterCannon: error");
|
static_assert(sizeof(CWaterCannon) == 412, "CWaterCannon: error");
|
||||||
|
@ -17,11 +31,10 @@ static_assert(sizeof(CWaterCannon) == 412, "CWaterCannon: error");
|
||||||
class CWaterCannons
|
class CWaterCannons
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Update();
|
static CWaterCannon aCannons[NUM_WATERCANNONS];
|
||||||
static void UpdateOne(uint32 id, CVector *pos, CVector *dir);
|
|
||||||
static void Render(void);
|
|
||||||
static void Init(void);
|
static void Init(void);
|
||||||
};
|
static void UpdateOne(uint32 id, CVector *pos, CVector *dir);
|
||||||
|
static void Update();
|
||||||
extern CWaterCannon (&aCannons)[NUM_WATERCANNONS];
|
static void Render(void);
|
||||||
|
};
|
|
@ -8,6 +8,7 @@
|
||||||
#define IDEXIT 1002
|
#define IDEXIT 1002
|
||||||
#define IDC_SELECTDEVICE 1005
|
#define IDC_SELECTDEVICE 1005
|
||||||
|
|
||||||
|
#define IDI_MAIN_ICON 1042
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
||||||
#ifdef APSTUDIO_INVOKED
|
#ifdef APSTUDIO_INVOKED
|
||||||
|
|
|
@ -30,8 +30,18 @@ BEGIN
|
||||||
WS_TABSTOP
|
WS_TABSTOP
|
||||||
DEFPUSHBUTTON "EXIT",IDEXIT,103,69,52,14
|
DEFPUSHBUTTON "EXIT",IDEXIT,103,69,52,14
|
||||||
DEFPUSHBUTTON "OK",IDOK,28,69,50,14
|
DEFPUSHBUTTON "OK",IDOK,28,69,50,14
|
||||||
LTEXT "Please select the device to use:",IDC_SELECTDEVICE,7,7,
|
LTEXT "Please select the Device To Use:",IDC_SELECTDEVICE,7,7,
|
||||||
137,8
|
137,8
|
||||||
END
|
END
|
||||||
|
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Icon
|
||||||
|
//
|
||||||
|
|
||||||
|
// Icon with lowest ID value placed first to ensure application icon
|
||||||
|
// remains consistent on all systems.
|
||||||
|
IDI_MAIN_ICON ICON DISCARDABLE "gta3.ico"
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////
|
Loading…
Reference in New Issue