This repository has been archived by the owner. It is now read-only.
Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
with
362 additions
and 20 deletions.
- +2 −2 src/audio/AudioManager.cpp
- +8 −0 src/math/Vector.h
- +315 −5 src/render/WaterCannon.cpp
- +25 −12 src/render/WaterCannon.h
- +1 −0 src/skel/win/resource.h
- +11 −1 src/skel/win/win.rc
There are no files selected for viewing
| @@ -1,10 +1,320 @@ | ||
| #include "common.h" | ||
| #include "patcher.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); } | ||
| WRAPPER void CWaterCannons::UpdateOne(uint32 id, CVector *pos, CVector *dir) { EAXJMP(0x522470); } | ||
| WRAPPER void CWaterCannons::Render(void) { EAXJMP(0x522550); } | ||
| WRAPPER void CWaterCannons::Init(void) { EAXJMP(0x522440); } | ||
| RwIm3DVertex WaterCannonVertices[WATERCANNONVERTS]; | ||
| RwImVertexIndex WaterCannonIndexList[WATERCANNONINDEXES]; | ||
|
|
||
| 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 |
Oops, something went wrong.