diff --git a/src/audio/MusicManager.cpp b/src/audio/MusicManager.cpp index 1f1c343a..d840c57b 100644 --- a/src/audio/MusicManager.cpp +++ b/src/audio/MusicManager.cpp @@ -17,8 +17,6 @@ cMusicManager &MusicManager = *(cMusicManager *)0x8F3964; int32 &gNumRetunePresses = *(int32 *)0x650B80; -wchar *pCurrentStation = (wchar *)0x650B9C; -uint8 &cDisplay = *(uint8 *)0x650BA1; int32 &gRetuneCounter = *(int32*)0x650B84; bool& bHasStarted = *(bool*)0x650B7C; @@ -72,6 +70,8 @@ cMusicManager::DisplayRadioStationName() int8 pRetune; int8 gStreamedSound; int8 gRetuneCounter; + static wchar *pCurrentStation = nil; + static uint8 cDisplay = 0; if(!CTimer::GetIsPaused() && !TheCamera.m_WideScreenOn && PlayerInCar() && !CReplay::IsPlayingBack()) { diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 93857b14..68d58b10 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -2078,14 +2078,12 @@ void CGarage::CenterCarInGarage(CVehicle* pVehicle) return; if (IsAnyOtherPedTouchingGarage(FindPlayerPed())) return; - float posX = pVehicle->GetPosition().x; - float posY = pVehicle->GetPosition().y; - float posZ = pVehicle->GetPosition().z; + CVector pos = pVehicle->GetPosition(); float garageX = GetGarageCenterX(); float garageY = GetGarageCenterY(); - float offsetX = garageX - posX; - float offsetY = garageY - posY; - float offsetZ = posZ - posZ; + float offsetX = garageX - pos.x; + float offsetY = garageY - pos.y; + float offsetZ = pos.z - pos.z; float distance = CVector(offsetX, offsetY, offsetZ).Magnitude(); if (distance < RESPRAY_CENTERING_COEFFICIENT) { pVehicle->GetPosition().x = GetGarageCenterX(); @@ -2096,7 +2094,7 @@ void CGarage::CenterCarInGarage(CVehicle* pVehicle) pVehicle->GetPosition().y += offsetY * RESPRAY_CENTERING_COEFFICIENT / distance; } if (!IsEntityEntirelyInside3D(pVehicle, 0.1f)) - pVehicle->GetPosition() = CVector(posX, posY, posZ); + pVehicle->GetPosition() = pos; } void CGarages::CloseHideOutGaragesBeforeSave() diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index b1832f0e..3e3c2a48 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -20,6 +20,9 @@ #include "Fire.h" #include "PointLights.h" #include "Pools.h" +#ifdef FIX_BUGS +#include "Replay.h" +#endif #include "Script.h" #include "Shadows.h" #include "SpecialFX.h" @@ -642,32 +645,26 @@ CPickups::AddToCollectedPickupsArray(int32 index) void CPickups::Update() { -#ifndef FIX_BUGS - // BUG: this code can only reach 318 out of 320 pickups +#ifdef FIX_BUGS // RIP speedrunning (solution from SA) + if (CReplay::IsPlayingBack()) + return; +#endif #define PICKUPS_FRAME_SPAN (6) -#define PICKUPS_PER_FRAME (NUMGENERALPICKUPS/PICKUPS_FRAME_SPAN) - - for (uint32 i = PICKUPS_PER_FRAME * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < PICKUPS_PER_FRAME * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) { +#ifdef FIX_BUGS + for (uint32 i = NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN) / PICKUPS_FRAME_SPAN; i < NUMGENERALPICKUPS * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1) / PICKUPS_FRAME_SPAN; i++) { +#else // BUG: this code can only reach 318 out of 320 pickups + for (uint32 i = NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN); i < NUMGENERALPICKUPS / PICKUPS_FRAME_SPAN * (CTimer::GetFrameCounter() % PICKUPS_FRAME_SPAN + 1); i++) { +#endif if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) { AddToCollectedPickupsArray(i); } } - +#undef PICKUPS_FRAME_SPAN for (uint32 i = NUMGENERALPICKUPS; i < NUMPICKUPS; i++) { if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) { AddToCollectedPickupsArray(i); } } - -#undef PICKUPS_FRAME_SPAN -#undef PICKUPS_PER_FRAME -#else - for (uint32 i = 0; i < NUMPICKUPS; i++) { - if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].Update(FindPlayerPed(), FindPlayerVehicle(), CWorld::PlayerInFocus)) { - AddToCollectedPickupsArray(i); - } - } -#endif } void diff --git a/src/core/Radar.cpp b/src/core/Radar.cpp index 1c634760..f1d8ec96 100644 --- a/src/core/Radar.cpp +++ b/src/core/Radar.cpp @@ -1106,8 +1106,11 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D // Radar space goes from -1.0 to 1.0 in x and y, top right is (1.0, 1.0) void CRadar::TransformRadarPointToScreenSpace(CVector2D &out, const CVector2D &in) { - // FIX? scale RADAR_LEFT here somehow +#ifdef FIX_BUGS + out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + SCREEN_SCALE_X(RADAR_LEFT); +#else out.x = (in.x + 1.0f)*0.5f*SCREEN_SCALE_X(RADAR_WIDTH) + RADAR_LEFT; +#endif out.y = (1.0f - in.y)*0.5f*SCREEN_SCALE_Y(RADAR_HEIGHT) + SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT); } diff --git a/src/core/common.h b/src/core/common.h index 7b4ff4a0..b58b93af 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -215,6 +215,7 @@ void re3_assert(const char *expr, const char *filename, unsigned int lineno, con #define ABS(a) (((a) < 0) ? (-(a)) : (a)) #define norm(value, min, max) (((value) < (min)) ? 0 : (((value) > (max)) ? 1 : (((value) - (min)) / ((max) - (min))))) +#define lerp(norm, min, max) ( (norm) * ((max) - (min)) + (min) ) #define STRINGIFY(x) #x #define STR(x) STRINGIFY(x) diff --git a/src/core/config.h b/src/core/config.h index eb455de4..373fca2f 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -94,6 +94,8 @@ enum Config { NUM_GARAGES = 32, NUM_PROJECTILES = 32, + NUM_GLASSPANES = 45, + NUM_GLASSENTITIES = 32, NUM_WATERCANNONS = 3, NUMPEDROUTES = 200, diff --git a/src/objects/Object.cpp b/src/objects/Object.cpp index 89959975..aa366aa0 100644 --- a/src/objects/Object.cpp +++ b/src/objects/Object.cpp @@ -38,8 +38,8 @@ CObject::CObject(void) bIsPickup = false; m_obj_flag2 = false; bOutOfStock = false; - m_obj_flag8 = false; - m_obj_flag10 = false; + bGlassCracked = false; + bGlassBroken = false; bHasBeenDamaged = false; m_nRefModelIndex = -1; bUseVehicleColours = false; diff --git a/src/objects/Object.h b/src/objects/Object.h index 9fcf9c0c..27346e23 100644 --- a/src/objects/Object.h +++ b/src/objects/Object.h @@ -36,8 +36,8 @@ public: int8 bIsPickup : 1; int8 m_obj_flag2 : 1; int8 bOutOfStock : 1; - int8 m_obj_flag8 : 1; - int8 m_obj_flag10 : 1; + int8 bGlassCracked : 1; + int8 bGlassBroken : 1; int8 bHasBeenDamaged : 1; int8 bUseVehicleColours : 1; int8 m_obj_flag80 : 1; diff --git a/src/render/Font.cpp b/src/render/Font.cpp index 0d79eee3..6f336f1e 100644 --- a/src/render/Font.cpp +++ b/src/render/Font.cpp @@ -116,7 +116,7 @@ int16 CFont::Size[3][193] = { #endif }; -uint16 foreign_table[128] = { +wchar foreign_table[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -228,7 +228,7 @@ CFont::InitPerFrame(void) } void -CFont::PrintChar(float x, float y, uint16 c) +CFont::PrintChar(float x, float y, wchar c) { if(x <= 0.0f || x > SCREEN_WIDTH || y <= 0.0f || y > SCREEN_HEIGHT) // BUG: game uses SCREENW again @@ -274,14 +274,14 @@ CFont::PrintChar(float x, float y, uint16 c) } void -CFont::PrintString(float xstart, float ystart, uint16 *s) +CFont::PrintString(float xstart, float ystart, wchar *s) { CRect rect; int numSpaces; float lineLength; float x, y; bool first; - uint16 *start, *t; + wchar *start, *t; if(*s == '*') return; @@ -357,11 +357,11 @@ CFont::PrintString(float xstart, float ystart, uint16 *s) } int -CFont::GetNumberLines(float xstart, float ystart, uint16 *s) +CFont::GetNumberLines(float xstart, float ystart, wchar *s) { int n; float x, y; - uint16 *t; + wchar *t; n = 0; if(Details.centre || Details.rightJustify) @@ -400,12 +400,12 @@ CFont::GetNumberLines(float xstart, float ystart, uint16 *s) } void -CFont::GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s) +CFont::GetTextRect(CRect *rect, float xstart, float ystart, wchar *s) { int numLines; float x, y; int16 maxlength; - uint16 *t; + wchar *t; maxlength = 0; numLines = 0; @@ -469,9 +469,9 @@ CFont::GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s) } void -CFont::PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth) +CFont::PrintString(float x, float y, wchar *start, wchar *end, float spwidth) { - uint16 *s, c, unused; + wchar *s, c, unused; for(s = start; s < end; s++){ if(*s == '~') @@ -487,7 +487,7 @@ CFont::PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth) } float -CFont::GetCharacterWidth(uint16 c) +CFont::GetCharacterWidth(wchar c) { #ifdef MORE_LANGUAGES if (Details.proportional) @@ -503,7 +503,7 @@ CFont::GetCharacterWidth(uint16 c) } float -CFont::GetCharacterSize(uint16 c) +CFont::GetCharacterSize(wchar c) { #ifdef MORE_LANGUAGES if(Details.proportional) @@ -519,7 +519,7 @@ CFont::GetCharacterSize(uint16 c) } float -CFont::GetStringWidth(uint16 *s, bool spaces) +CFont::GetStringWidth(wchar *s, bool spaces) { float w; @@ -537,8 +537,8 @@ CFont::GetStringWidth(uint16 *s, bool spaces) return w; } -uint16* -CFont::GetNextSpace(uint16 *s) +wchar* +CFont::GetNextSpace(wchar *s) { for(; *s != ' ' && *s != '\0'; s++) if(*s == '~'){ @@ -551,8 +551,8 @@ CFont::GetNextSpace(uint16 *s) return s; } -uint16* -CFont::ParseToken(uint16 *s, uint16*) +wchar* +CFont::ParseToken(wchar *s, wchar*) { s++; if(Details.color.r || Details.color.g || Details.color.b) @@ -582,7 +582,7 @@ CFont::DrawFonts(void) CSprite2d::DrawBank(Details.bank+2); } -uint16 +wchar CFont::character_code(uint8 c) { if(c < 128) @@ -596,10 +596,10 @@ STARTPATCHES InjectHook(0x500BA0, CFont::Shutdown, PATCH_JUMP); InjectHook(0x500BE0, CFont::InitPerFrame, PATCH_JUMP); InjectHook(0x500C30, CFont::PrintChar, PATCH_JUMP); - InjectHook(0x500F50, (void (*)(float, float, uint16*))CFont::PrintString, PATCH_JUMP); + InjectHook(0x500F50, (void (*)(float, float, wchar*))CFont::PrintString, PATCH_JUMP); InjectHook(0x501260, CFont::GetNumberLines, PATCH_JUMP); InjectHook(0x5013B0, CFont::GetTextRect, PATCH_JUMP); - InjectHook(0x501730, (void (*)(float, float, uint16*, uint16*, float))CFont::PrintString, PATCH_JUMP); + InjectHook(0x501730, (void (*)(float, float, wchar*, wchar*, float))CFont::PrintString, PATCH_JUMP); InjectHook(0x5017E0, CFont::GetCharacterWidth, PATCH_JUMP); InjectHook(0x501840, CFont::GetCharacterSize, PATCH_JUMP); InjectHook(0x5018A0, CFont::GetStringWidth, PATCH_JUMP); diff --git a/src/render/Font.h b/src/render/Font.h index 26309377..0659dda1 100644 --- a/src/render/Font.h +++ b/src/render/Font.h @@ -64,18 +64,18 @@ public: static void Initialise(void); static void Shutdown(void); static void InitPerFrame(void); - static void PrintChar(float x, float y, uint16 c); - static void PrintString(float x, float y, uint16 *s); - static int GetNumberLines(float xstart, float ystart, uint16 *s); - static void GetTextRect(CRect *rect, float xstart, float ystart, uint16 *s); - static void PrintString(float x, float y, uint16 *start, uint16 *end, float spwidth); - static float GetCharacterWidth(uint16 c); - static float GetCharacterSize(uint16 c); - static float GetStringWidth(uint16 *s, bool spaces = false); - static uint16 *GetNextSpace(uint16 *s); - static uint16 *ParseToken(uint16 *s, uint16*); + static void PrintChar(float x, float y, wchar c); + static void PrintString(float x, float y, wchar *s); + static int GetNumberLines(float xstart, float ystart, wchar *s); + static void GetTextRect(CRect *rect, float xstart, float ystart, wchar *s); + static void PrintString(float x, float y, wchar *start, wchar *end, float spwidth); + static float GetCharacterWidth(wchar c); + static float GetCharacterSize(wchar c); + static float GetStringWidth(wchar *s, bool spaces = false); + static wchar *GetNextSpace(wchar *s); + static wchar *ParseToken(wchar *s, wchar*); static void DrawFonts(void); - static uint16 character_code(uint8 c); + static wchar character_code(uint8 c); static CFontDetails GetDetails() { return Details; } static void SetScale(float x, float y) { Details.scaleX = x; Details.scaleY = y; } diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp index ac04032b..41d31985 100644 --- a/src/render/Glass.cpp +++ b/src/render/Glass.cpp @@ -1,21 +1,721 @@ #include "common.h" #include "patcher.h" #include "Glass.h" +#include "Timer.h" +#include "Object.h" +#include "General.h" +#include "AudioScriptObject.h" +#include "World.h" +#include "TimeCycle.h" +#include "Particle.h" +#include "Camera.h" +#include "RenderBuffer.h" +#include "Shadows.h" +#include "ModelIndices.h" +#include "main.h" -WRAPPER void CGlass::AskForObjectToBeRenderedInGlass(CEntity *ent) { EAXJMP(0x5033F0); } -WRAPPER void -CGlass::WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo) +uint32 CGlass::NumGlassEntities; +CEntity *CGlass::apEntitiesToBeRendered[NUM_GLASSENTITIES]; +CFallingGlassPane CGlass::aGlassPanes[NUM_GLASSPANES]; + + +CVector2D CentersWithTriangle[NUM_GLASSTRIANGLES]; +const CVector2D CoorsWithTriangle[NUM_GLASSTRIANGLES][3] = { - EAXJMP(0x503F10); + { + CVector2D(0.0f, 0.0f), + CVector2D(0.0f, 1.0f), + CVector2D(0.4f, 0.5f) + }, + + { + CVector2D(0.0f, 1.0f), + CVector2D(1.0f, 1.0f), + CVector2D(0.4f, 0.5f) + }, + + { + CVector2D(0.0f, 0.0f), + CVector2D(0.4f, 0.5f), + CVector2D(0.7f, 0.0f) + }, + + { + CVector2D(0.7f, 0.0f), + CVector2D(0.4f, 0.5f), + CVector2D(1.0f, 1.0f) + }, + + { + CVector2D(0.7f, 0.0f), + CVector2D(1.0f, 1.0f), + CVector2D(1.0f, 0.0f) + } +}; + +#define TEMPBUFFERVERTHILIGHTOFFSET 0 +#define TEMPBUFFERINDEXHILIGHTOFFSET 0 +#define TEMPBUFFERVERTHILIGHTSIZE 128 +#define TEMPBUFFERINDEXHILIGHTSIZE 512 + +#define TEMPBUFFERVERTSHATTEREDOFFSET TEMPBUFFERVERTHILIGHTSIZE +#define TEMPBUFFERINDEXSHATTEREDOFFSET TEMPBUFFERINDEXHILIGHTSIZE +#define TEMPBUFFERVERTSHATTEREDSIZE 192 +#define TEMPBUFFERINDEXSHATTEREDSIZE 768 + +#define TEMPBUFFERVERTREFLECTIONOFFSET TEMPBUFFERVERTSHATTEREDSIZE +#define TEMPBUFFERINDEXREFLECTIONOFFSET TEMPBUFFERINDEXSHATTEREDSIZE +#define TEMPBUFFERVERTREFLECTIONSIZE 256 +#define TEMPBUFFERINDEXREFLECTIONSIZE 1024 + +int32 TempBufferIndicesStoredHiLight = 0; +int32 TempBufferVerticesStoredHiLight = 0; +int32 TempBufferIndicesStoredShattered = 0; +int32 TempBufferVerticesStoredShattered = 0; +int32 TempBufferIndicesStoredReflection = 0; +int32 TempBufferVerticesStoredReflection = 0; + +void +CFallingGlassPane::Update(void) +{ + if ( CTimer::GetTimeInMilliseconds() >= m_nTimer ) + { + // Apply MoveSpeed + GetPosition() += m_vecMoveSpeed * CTimer::GetTimeStep(); + + // Apply Gravity + m_vecMoveSpeed.z -= 0.02f * CTimer::GetTimeStep(); + + // Apply TurnSpeed + GetRight() += CrossProduct(m_vecTurn, GetRight()); + GetForward() += CrossProduct(m_vecTurn, GetForward()); + GetUp() += CrossProduct(m_vecTurn, GetUp()); + + if ( GetPosition().z < m_fGroundZ ) + { + CVector pos; + CVector dir; + + m_bActive = false; + + pos = CVector(GetPosition().x, GetPosition().y, m_fGroundZ); + + PlayOneShotScriptObject(_SCRSOUND_GLASS_SHARD, pos); + + RwRGBA color = { 255, 255, 255, 255 }; + + static int32 nFrameGen = 0; + + for ( int32 i = 0; i < 4; i++ ) + { + dir.x = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f); + dir.y = CGeneral::GetRandomNumberInRange(-0.35f, 0.35f); + dir.z = CGeneral::GetRandomNumberInRange(0.05f, 0.20f); + + CParticle::AddParticle(PARTICLE_CAR_DEBRIS, + pos, + dir, + nil, + CGeneral::GetRandomNumberInRange(0.02f, 0.2f), + color, + CGeneral::GetRandomNumberInRange(-40, 40), + 0, + ++nFrameGen & 3, + 500); + } + } + } } -WRAPPER void -CGlass::WindowRespondsToSoftCollision(CEntity *ent, float amount) +void +CFallingGlassPane::Render(void) { - EAXJMP(0x504630); + float distToCamera = (TheCamera.GetPosition() - GetPosition()).Magnitude(); + + CVector fwdNorm = GetForward(); + fwdNorm.Normalise(); + uint8 alpha = CGlass::CalcAlphaWithNormal(&fwdNorm); + + int32 time = clamp(CTimer::GetTimeInMilliseconds() - m_nTimer, 0, 500); + + uint8 color = int32( float(alpha) * (float(time) / 500) ); + + if ( TempBufferIndicesStoredHiLight >= TEMPBUFFERINDEXHILIGHTSIZE-7 || TempBufferVerticesStoredHiLight >= TEMPBUFFERVERTHILIGHTSIZE-4 ) + CGlass::RenderHiLightPolys(); + + // HiLight Polys + + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], color, color, color, color); + + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], 0.5f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], 0.5f); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], 0.5f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], 0.6f); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], 0.6f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], 0.6f); + + ASSERT(m_nTriIndex < NUM_GLASSTRIANGLES); + + CVector2D p0 = CoorsWithTriangle[m_nTriIndex][0] - CentersWithTriangle[m_nTriIndex]; + CVector2D p1 = CoorsWithTriangle[m_nTriIndex][1] - CentersWithTriangle[m_nTriIndex]; + CVector2D p2 = CoorsWithTriangle[m_nTriIndex][2] - CentersWithTriangle[m_nTriIndex]; + CVector v0 = *this * CVector(p0.x, 0.0f, p0.y); + CVector v1 = *this * CVector(p1.x, 0.0f, p1.y); + CVector v2 = *this * CVector(p2.x, 0.0f, p2.y); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 0], v0.x, v0.y, v0.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 1], v1.x, v1.y, v1.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredHiLight + 2], v2.x, v2.y, v2.z); + + TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 0] = TempBufferVerticesStoredHiLight + 0; + TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 1] = TempBufferVerticesStoredHiLight + 1; + TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 2] = TempBufferVerticesStoredHiLight + 2; + TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 3] = TempBufferVerticesStoredHiLight + 0; + TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 4] = TempBufferVerticesStoredHiLight + 2; + TempBufferRenderIndexList[TempBufferIndicesStoredHiLight + 5] = TempBufferVerticesStoredHiLight + 1; + + TempBufferVerticesStoredHiLight += 3; + TempBufferIndicesStoredHiLight += 6; + + if ( m_bShattered ) + { + if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-7 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-4 ) + CGlass::RenderShatteredPolys(); + + uint8 shatteredColor = 255; + if ( distToCamera > 30.0f ) + shatteredColor = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255); + + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], shatteredColor, shatteredColor, shatteredColor, shatteredColor); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], shatteredColor, shatteredColor, shatteredColor, shatteredColor); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], shatteredColor, shatteredColor, shatteredColor, shatteredColor); + + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 4.0f * CoorsWithTriangle[m_nTriIndex][0].x * m_fStep); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 4.0f * CoorsWithTriangle[m_nTriIndex][0].y * m_fStep); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 4.0f * CoorsWithTriangle[m_nTriIndex][1].x * m_fStep); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 4.0f * CoorsWithTriangle[m_nTriIndex][1].y * m_fStep); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 4.0f * CoorsWithTriangle[m_nTriIndex][2].x * m_fStep); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 4.0f * CoorsWithTriangle[m_nTriIndex][2].y * m_fStep); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], v0.x, v0.y, v0.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], v1.x, v1.y, v1.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], v2.x, v2.y, v2.z); + + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 0] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 0; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 1] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 1; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 2] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 2; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 3] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 0; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 4] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 2; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 5] = TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET + 1; + + TempBufferIndicesStoredShattered += 6; + TempBufferVerticesStoredShattered += 3; + } } -WRAPPER void CGlass::Render(void) { EAXJMP(0x502350); } -WRAPPER void CGlass::Update(void) { EAXJMP(0x502050); } -WRAPPER void CGlass::Init(void) { EAXJMP(0x501F20); } +void +CGlass::Init(void) +{ + for ( int32 i = 0; i < NUM_GLASSPANES; i++ ) + aGlassPanes[i].m_bActive = false; + + for ( int32 i = 0; i < NUM_GLASSTRIANGLES; i++ ) + CentersWithTriangle[i] = (CoorsWithTriangle[i][0] + CoorsWithTriangle[i][1] + CoorsWithTriangle[i][2]) / 3; +} + +void +CGlass::Update(void) +{ + for ( int32 i = 0; i < NUM_GLASSPANES; i++ ) + { + if ( aGlassPanes[i].m_bActive ) + aGlassPanes[i].Update(); + } +} + +void +CGlass::Render(void) +{ + TempBufferVerticesStoredHiLight = 0; + TempBufferIndicesStoredHiLight = 0; + + TempBufferVerticesStoredShattered = TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferIndicesStoredShattered = TEMPBUFFERINDEXSHATTEREDOFFSET; + + TempBufferVerticesStoredReflection = TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferIndicesStoredReflection = TEMPBUFFERINDEXREFLECTIONOFFSET; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATETEXTUREFILTER, (void *)rwFILTERLINEAR); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEFOGCOLOR, (void *)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255)); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); + + for ( int32 i = 0; i < NUM_GLASSPANES; i++ ) + { + if ( aGlassPanes[i].m_bActive ) + aGlassPanes[i].Render(); + } + + for ( uint32 i = 0; i < NumGlassEntities; i++ ) + RenderEntityInGlass(apEntitiesToBeRendered[i]); + + NumGlassEntities = 0; + + RenderHiLightPolys(); + RenderShatteredPolys(); + RenderReflectionPolys(); + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE); +} + +CFallingGlassPane * +CGlass::FindFreePane(void) +{ + for ( int32 i = 0; i < NUM_GLASSPANES; i++ ) + { + if ( !aGlassPanes[i].m_bActive ) + return &aGlassPanes[i]; + } + + return nil; +} + +void +CGlass::GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point, + float moveSpeed, bool cracked, bool explosion) +{ + float upLen = up.Magnitude(); + float rightLen = right.Magnitude(); + + float upSteps = upLen + 0.75f; + if ( upSteps < 1.0f ) upSteps = 1.0f; + + float rightSteps = rightLen + 0.75f; + if ( rightSteps < 1.0f ) rightSteps = 1.0f; + + uint32 ysteps = (uint32)upSteps; + if ( ysteps > 3 ) ysteps = 3; + + uint32 xsteps = (uint32)rightSteps; + if ( xsteps > 3 ) xsteps = 3; + + if ( explosion ) + { + if ( ysteps > 1 ) ysteps = 1; + if ( xsteps > 1 ) xsteps = 1; + } + + float upScl = upLen / float(ysteps); + float rightScl = rightLen / float(xsteps); + + bool bZFound; + float groundZ = CWorld::FindGroundZFor3DCoord(pos.x, pos.y, pos.z, &bZFound); + if ( !bZFound ) groundZ = pos.z - 2.0f; + + for ( uint32 y = 0; y < ysteps; y++ ) + { + for ( uint32 x = 0; x < xsteps; x++ ) + { + float stepy = float(y) * upLen / float(ysteps); + float stepx = float(x) * rightLen / float(xsteps); + + for ( int32 i = 0; i < NUM_GLASSTRIANGLES; i++ ) + { + CFallingGlassPane *pane = FindFreePane(); + if ( pane ) + { + pane->m_nTriIndex = i; + + pane->GetRight() = (right * rightScl) / rightLen; +#ifdef FIX_BUGS + pane->GetUp() = (up * upScl) / upLen; +#else + pane->GetUp() = (up * upScl) / rightLen; // copypaste bug +#endif + CVector fwd = CrossProduct(pane->GetRight(), pane->GetUp()); + fwd.Normalise(); + + pane->GetForward() = fwd; + + pane->GetPosition() = right / rightLen * (rightScl * CentersWithTriangle[i].x + stepx) + + up / upLen * (upScl * CentersWithTriangle[i].y + stepy) + + pos; + + pane->m_vecMoveSpeed.x = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0015f + speed.x; + pane->m_vecMoveSpeed.y = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.0015f + speed.y; + pane->m_vecMoveSpeed.z = 0.0f + speed.z; + + if ( moveSpeed != 0.0f ) + { + CVector dist = pane->GetPosition() - point; + dist.Normalise(); + + pane->m_vecMoveSpeed += moveSpeed * dist; + } + + pane->m_vecTurn.x = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f; + pane->m_vecTurn.y = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f; + pane->m_vecTurn.z = float((CGeneral::GetRandomNumber() & 127) - 64) * 0.002f; + + switch ( type ) + { + case 0: + pane->m_nTimer = CTimer::GetTimeInMilliseconds(); + break; + case 1: + float dist = (pane->GetPosition() - point).Magnitude(); + pane->m_nTimer = uint32(dist*100 + CTimer::GetTimeInMilliseconds()); + break; + } + + pane->m_fGroundZ = groundZ; + pane->m_bShattered = cracked; + pane->m_fStep = upLen / float(ysteps); + pane->m_bActive = true; + } + } + } + } +} + +void +CGlass::AskForObjectToBeRenderedInGlass(CEntity *entity) +{ +#ifdef FIX_BUGS + if ( NumGlassEntities < NUM_GLASSPANES ) +#else + if ( NumGlassEntities < NUM_GLASSPANES-1 ) +#endif + { + apEntitiesToBeRendered[NumGlassEntities++] = entity; + } +} + +void +CGlass::RenderEntityInGlass(CEntity *entity) +{ + CObject *object = (CObject *)entity; + + if ( object->bGlassBroken ) + return; + + float distToCamera = (TheCamera.GetPosition() - object->GetPosition()).Magnitude(); + + if ( distToCamera > 40.0f ) + return; + + CVector fwdNorm = object->GetForward(); + fwdNorm.Normalise(); + uint8 alpha = CalcAlphaWithNormal(&fwdNorm); + + CColModel *col = object->GetColModel(); + + if ( col->numTriangles >= 2 ) + { + CVector a = object->GetMatrix() * col->vertices[0]; + CVector b = object->GetMatrix() * col->vertices[1]; + CVector c = object->GetMatrix() * col->vertices[2]; + CVector d = object->GetMatrix() * col->vertices[3]; + + if ( object->bGlassCracked ) + { + uint8 color = 255; + if ( distToCamera > 30.0f ) + color = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 255); + + if ( TempBufferIndicesStoredShattered >= TEMPBUFFERINDEXSHATTEREDSIZE-13 || TempBufferVerticesStoredShattered >= TEMPBUFFERVERTSHATTEREDSIZE-5 ) + RenderShatteredPolys(); + + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], color, color, color, color); + + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 0.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], 0.0f); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 16.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], 0.0f); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 0.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], 16.0f); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], 16.0f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], 16.0f); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 0], a.x, a.y, a.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 1], b.x, b.y, b.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 2], c.x, c.y, c.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredShattered + 3], d.x, d.y, d.z); + + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 0] = col->triangles[0].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 1] = col->triangles[0].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 2] = col->triangles[0].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 3] = col->triangles[1].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 4] = col->triangles[1].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 5] = col->triangles[1].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 6] = col->triangles[0].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 7] = col->triangles[0].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 8] = col->triangles[0].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 9] = col->triangles[1].a + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 10] = col->triangles[1].c + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredShattered + 11] = col->triangles[1].b + TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET; + + TempBufferIndicesStoredShattered += 12; + TempBufferVerticesStoredShattered += 4; + } + + if ( TempBufferIndicesStoredReflection >= TEMPBUFFERINDEXREFLECTIONSIZE-13 || TempBufferVerticesStoredReflection >= TEMPBUFFERVERTREFLECTIONSIZE-5 ) + RenderReflectionPolys(); + + uint8 color = 100; + if ( distToCamera > 30.0f ) + color = int32((1.0f - (distToCamera - 30.0f) * 4.0f / 40.0f) * 100); + + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], color, color, color, color); + RwIm3DVertexSetRGBA (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], color, color, color, color); + + float FwdAngle = CGeneral::GetATanOfXY(TheCamera.GetForward().x, TheCamera.GetForward().y); + float v = 2.0f * TheCamera.GetForward().z * 0.2f; + float u = float(object->m_randomSeed & 15) * 0.02f + (FwdAngle / TWOPI); + + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], u); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], v); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], u+0.2f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], v); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], u); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], v+0.2f); + RwIm3DVertexSetU (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], u+0.2f); + RwIm3DVertexSetV (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], v+0.2f); + + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 0], a.x, a.y, a.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 1], b.x, b.y, b.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 2], c.x, c.y, c.z); + RwIm3DVertexSetPos (&TempBufferRenderVertices[TempBufferVerticesStoredReflection + 3], d.x, d.y, d.z); + + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 0] = col->triangles[0].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 1] = col->triangles[0].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 2] = col->triangles[0].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 3] = col->triangles[1].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 4] = col->triangles[1].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 5] = col->triangles[1].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 6] = col->triangles[0].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 7] = col->triangles[0].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 8] = col->triangles[0].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 9] = col->triangles[1].a + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 10] = col->triangles[1].c + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + TempBufferRenderIndexList[TempBufferIndicesStoredReflection + 11] = col->triangles[1].b + TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET; + + TempBufferIndicesStoredReflection += 12; + TempBufferVerticesStoredReflection += 4; + } +} + +int32 +CGlass::CalcAlphaWithNormal(CVector *normal) +{ + float fwdDir = 2.0f * DotProduct(*normal, TheCamera.GetForward()); + float fwdDot = DotProduct(TheCamera.GetForward()-fwdDir*(*normal), CVector(0.57f, 0.57f, -0.57f)); + return int32(lerp(fwdDot*fwdDot*fwdDot*fwdDot*fwdDot*fwdDot, 20.0f, 255.0f)); +} + +void +CGlass::RenderHiLightPolys(void) +{ + if ( TempBufferVerticesStoredHiLight != TEMPBUFFERVERTHILIGHTOFFSET ) + { + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpShadowExplosionTex)); + + LittleTest(); + + if ( RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStoredHiLight, nil, rwIM3D_VERTEXUV) ) + { + RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStoredHiLight); + RwIm3DEnd(); + } + + TempBufferVerticesStoredHiLight = TEMPBUFFERVERTHILIGHTOFFSET; + TempBufferIndicesStoredHiLight = TEMPBUFFERINDEXHILIGHTOFFSET; + } +} + +void +CGlass::RenderShatteredPolys(void) +{ + if ( TempBufferVerticesStoredShattered != TEMPBUFFERVERTSHATTEREDOFFSET ) + { + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpCrackedGlassTex)); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + + LittleTest(); + + if ( RwIm3DTransform(&TempBufferRenderVertices[TEMPBUFFERVERTSHATTEREDOFFSET], TempBufferVerticesStoredShattered - TEMPBUFFERVERTSHATTEREDOFFSET, nil, rwIM3D_VERTEXUV) ) + { + RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, &TempBufferRenderIndexList[TEMPBUFFERINDEXSHATTEREDOFFSET], TempBufferIndicesStoredShattered - TEMPBUFFERINDEXSHATTEREDOFFSET); + RwIm3DEnd(); + } + + TempBufferIndicesStoredShattered = TEMPBUFFERINDEXSHATTEREDOFFSET; + TempBufferVerticesStoredShattered = TEMPBUFFERVERTSHATTEREDOFFSET; + } +} + +void +CGlass::RenderReflectionPolys(void) +{ + if ( TempBufferVerticesStoredReflection != TEMPBUFFERVERTREFLECTIONOFFSET ) + { + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)RwTextureGetRaster(gpShadowHeadLightsTex)); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + + LittleTest(); + + if ( RwIm3DTransform(&TempBufferRenderVertices[TEMPBUFFERVERTREFLECTIONOFFSET], TempBufferVerticesStoredReflection - TEMPBUFFERVERTREFLECTIONOFFSET, nil, rwIM3D_VERTEXUV) ) + { + RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, &TempBufferRenderIndexList[TEMPBUFFERINDEXREFLECTIONOFFSET], TempBufferIndicesStoredReflection - TEMPBUFFERINDEXREFLECTIONOFFSET); + RwIm3DEnd(); + } + + TempBufferIndicesStoredReflection = TEMPBUFFERINDEXREFLECTIONOFFSET; + TempBufferVerticesStoredReflection = TEMPBUFFERVERTREFLECTIONOFFSET; + } +} + +void +CGlass::WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion) +{ + CObject *object = (CObject *)entity; + + if ( object->bGlassBroken ) + return; + + object->bGlassCracked = true; + + CColModel *col = object->GetColModel(); + + CVector a = object->GetMatrix() * col->vertices[0]; + CVector b = object->GetMatrix() * col->vertices[1]; + CVector c = object->GetMatrix() * col->vertices[2]; + CVector d = object->GetMatrix() * col->vertices[3]; + + float minx = min(min(a.x, b.x), min(c.x, d.x)); + float maxx = max(max(a.x, b.x), max(c.x, d.x)); + float miny = min(min(a.y, b.y), min(c.y, d.y)); + float maxy = max(max(a.y, b.y), max(c.y, d.y)); + float minz = min(min(a.z, b.z), min(c.z, d.z)); + float maxz = max(max(a.z, b.z), max(c.z, d.z)); + + + if ( amount > 300.0f ) + { + PlayOneShotScriptObject(_SCRSOUND_GLASS_SMASH_1, object->GetPosition()); + + GeneratePanesForWindow(0, + CVector(minx, miny, minz), + CVector(0.0f, 0.0f, maxz-minz), + CVector(maxx-minx, maxy-miny, 0.0f), + speed, point, 0.1f, !!object->bGlassCracked, explosion); + } + else + { + PlayOneShotScriptObject(_SCRSOUND_GLASS_SMASH_2, object->GetPosition()); + + GeneratePanesForWindow(1, + CVector(minx, miny, minz), + CVector(0.0f, 0.0f, maxz-minz), + CVector(maxx-minx, maxy-miny, 0.0f), + speed, point, 0.1f, !!object->bGlassCracked, explosion); + } + + object->bGlassBroken = true; + object->GetPosition().z = -100.0f; +} + +void +CGlass::WindowRespondsToSoftCollision(CEntity *entity, float amount) +{ + CObject *object = (CObject *)entity; + + if ( amount > 50.0f && !object->bGlassCracked ) + { + PlayOneShotScriptObject(_SCRSOUND_GLASS_CRACK, object->GetPosition()); + object->bGlassCracked = true; + } +} + +void +CGlass::WasGlassHitByBullet(CEntity *entity, CVector point) +{ + CObject *object = (CObject *)entity; + + if ( IsGlass(object->GetModelIndex()) ) + { + if ( !object->bGlassCracked ) + { + PlayOneShotScriptObject(_SCRSOUND_GLASS_CRACK, object->GetPosition()); + object->bGlassCracked = true; + } + else + { + if ( (CGeneral::GetRandomNumber() & 3) == 2 ) + WindowRespondsToCollision(object, 0.0f, CVector(0.0f, 0.0f, 0.0f), point, false); + } + } +} + +void +CGlass::WindowRespondsToExplosion(CEntity *entity, CVector point) +{ + CObject *object = (CObject *)entity; + + CVector distToGlass = object->GetPosition() - point; + + float fDistToGlass = distToGlass.Magnitude(); + + if ( fDistToGlass < 10.0f ) + { + distToGlass.Normalise(0.3f); + WindowRespondsToCollision(object, 10000.0f, distToGlass, object->GetPosition(), true); + } + else + { + if ( fDistToGlass < 30.0f ) + object->bGlassCracked = true; + } +} + +STARTPATCHES + InjectHook(0x501F20, CGlass::Init, PATCH_JUMP); + InjectHook(0x502050, CGlass::Update, PATCH_JUMP); + InjectHook(0x502080, &CFallingGlassPane::Update, PATCH_JUMP); + InjectHook(0x502350, CGlass::Render, PATCH_JUMP); + InjectHook(0x502490, CGlass::FindFreePane, PATCH_JUMP); + InjectHook(0x5024C0, &CFallingGlassPane::Render, PATCH_JUMP); + InjectHook(0x502AC0, CGlass::GeneratePanesForWindow, PATCH_JUMP); + InjectHook(0x5033F0, CGlass::AskForObjectToBeRenderedInGlass, PATCH_JUMP); + InjectHook(0x503420, CGlass::RenderEntityInGlass, PATCH_JUMP); + InjectHook(0x503C90, CGlass::CalcAlphaWithNormal, PATCH_JUMP); + InjectHook(0x503D60, CGlass::RenderHiLightPolys, PATCH_JUMP); + InjectHook(0x503DE0, CGlass::RenderShatteredPolys, PATCH_JUMP); + InjectHook(0x503E70, CGlass::RenderReflectionPolys, PATCH_JUMP); + InjectHook(0x503F10, CGlass::WindowRespondsToCollision, PATCH_JUMP); + InjectHook(0x504630, CGlass::WindowRespondsToSoftCollision, PATCH_JUMP); + InjectHook(0x504670, CGlass::WasGlassHitByBullet, PATCH_JUMP); + InjectHook(0x504790, CGlass::WindowRespondsToExplosion, PATCH_JUMP); + //InjectHook(0x504880, `global constructor keyed to'glass.cpp, PATCH_JUMP); + //InjectHook(0x5048D0, CFallingGlassPane::~CFallingGlassPane, PATCH_JUMP); + //InjectHook(0x5048E0, CFallingGlassPane::CFallingGlassPane, PATCH_JUMP); +ENDPATCHES diff --git a/src/render/Glass.h b/src/render/Glass.h index ad4d50f2..dccd9d3d 100644 --- a/src/render/Glass.h +++ b/src/render/Glass.h @@ -2,13 +2,52 @@ class CEntity; -class CGlass +class CFallingGlassPane : public CMatrix { public: - static void AskForObjectToBeRenderedInGlass(CEntity *ent); - static void WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo); - static void WindowRespondsToSoftCollision(CEntity *ent, float amount); - static void Render(void); - static void Update(void); - static void Init(void); + CVector m_vecMoveSpeed; + CVector m_vecTurn; + uint32 m_nTimer; + float m_fGroundZ; + float m_fStep; + uint8 m_nTriIndex; + bool m_bActive; + bool m_bShattered; + char _pad0[1]; + + CFallingGlassPane() { } + ~CFallingGlassPane() { } + + void Update(void); + void Render(void); }; + +VALIDATE_SIZE(CFallingGlassPane, 0x70); + +enum +{ + NUM_GLASSTRIANGLES = 5, +}; + +class CGlass +{ + static uint32 NumGlassEntities; + static CEntity *apEntitiesToBeRendered[NUM_GLASSENTITIES]; + static CFallingGlassPane aGlassPanes[NUM_GLASSPANES]; +public: + static void Init(void); + static void Update(void); + static void Render(void); + static CFallingGlassPane *FindFreePane(void); + static void GeneratePanesForWindow(uint32 type, CVector pos, CVector up, CVector right, CVector speed, CVector point, float moveSpeed, bool cracked, bool explosion); + static void AskForObjectToBeRenderedInGlass(CEntity *entity); + static void RenderEntityInGlass(CEntity *entity); + static int32 CalcAlphaWithNormal(CVector *normal); + static void RenderHiLightPolys(void); + static void RenderShatteredPolys(void); + static void RenderReflectionPolys(void); + static void WindowRespondsToCollision(CEntity *entity, float amount, CVector speed, CVector point, bool explosion); + static void WindowRespondsToSoftCollision(CEntity *entity, float amount); + static void WasGlassHitByBullet(CEntity *entity, CVector point); + static void WindowRespondsToExplosion(CEntity *entity, CVector point); +}; \ No newline at end of file diff --git a/src/render/Hud.cpp b/src/render/Hud.cpp index 2f523e17..c4aca8e4 100644 --- a/src/render/Hud.cpp +++ b/src/render/Hud.cpp @@ -793,8 +793,11 @@ void CHud::Draw() if (m_ItemToFlash == ITEM_RADAR && CTimer::GetFrameCounter() & 8 || m_ItemToFlash != ITEM_RADAR) { CRadar::DrawMap(); CRect rect(0.0f, 0.0f, SCREEN_SCALE_X(RADAR_WIDTH), SCREEN_SCALE_Y(RADAR_HEIGHT)); - // FIX? scale RADAR_LEFT here somehow +#ifdef FIX_BUGS + rect.Translate(SCREEN_SCALE_X(RADAR_LEFT), SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); +#else rect.Translate(RADAR_LEFT, SCREEN_SCALE_FROM_BOTTOM(RADAR_BOTTOM + RADAR_HEIGHT)); +#endif rect.Grow(4.0f); Sprites[HUD_RADARDISC].Draw(rect, CRGBA(0, 0, 0, 255)); CRadar::DrawBlips(); @@ -1094,7 +1097,6 @@ void CHud::DrawAfterFade() CFont::SetColor(CRGBA(175, 175, 175, 255)); CFont::PrintString(SCREEN_SCALE_X(26.0f), SCREEN_SCALE_Y(28.0f + (150.0f - PagerXOffset) * 0.6f), CHud::m_HelpMessageToPrint); CFont::SetAlphaFade(255.0f); - CFont::DrawFonts(); } } else diff --git a/src/render/Shadows.h b/src/render/Shadows.h index 66df0273..982cc463 100644 --- a/src/render/Shadows.h +++ b/src/render/Shadows.h @@ -182,3 +182,4 @@ extern RwTexture *&gpGoalTex; extern RwTexture *&gpOutline1Tex; extern RwTexture *&gpOutline2Tex; extern RwTexture *&gpOutline3Tex; +extern RwTexture *&gpCrackedGlassTex; diff --git a/src/vehicles/Vehicle.cpp b/src/vehicles/Vehicle.cpp index 1fe02953..adeba19e 100644 --- a/src/vehicles/Vehicle.cpp +++ b/src/vehicles/Vehicle.cpp @@ -31,10 +31,17 @@ void *CVehicle::operator new(size_t sz, int handle) { return CPools::GetVehicleP void CVehicle::operator delete(void *p, size_t sz) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } void CVehicle::operator delete(void *p, int handle) { CPools::GetVehiclePool()->Delete((CVehicle*)p); } -WRAPPER bool CVehicle::ShufflePassengersToMakeSpace(void) { EAXJMP(0x5528A0); } -// or Weapon.cpp? -WRAPPER void FireOneInstantHitRound(CVector *shotSource, CVector *shotTarget, int32 damage) { EAXJMP(0x563B00); } -WRAPPER void CVehicle::InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage) { EAXJMP(0x551950); } +#ifdef FIX_BUGS +// I think they meant that +#define DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE (MYRAND_MAX * 35 / 100) +#define DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE (MYRAND_MAX * 70 / 100) +#else +#define DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE (35000) +#define DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE (70000) +#endif +#define DAMAGE_HEALTH_TO_FLEE_ALWAYS (200.0f) +#define DAMAGE_HEALTH_TO_CATCH_FIRE (250.0f) + CVehicle::CVehicle(uint8 CreatedBy) { @@ -361,6 +368,119 @@ CVehicle::ProcessWheelRotation(tWheelState state, const CVector &fwd, const CVec return angularVelocity * CTimer::GetTimeStep(); } +void +CVehicle::InflictDamage(CEntity* damagedBy, eWeaponType weaponType, float damage) +{ + if (!bCanBeDamaged) + return; + if (bOnlyDamagedByPlayer && (damagedBy != FindPlayerPed() && damagedBy != FindPlayerVehicle())) + return; + bool bFrightensDriver = false; + switch (weaponType) { + case WEAPONTYPE_UNARMED: + case WEAPONTYPE_BASEBALLBAT: + if (bMeleeProof) + return; + break; + case WEAPONTYPE_COLT45: + case WEAPONTYPE_UZI: + case WEAPONTYPE_SHOTGUN: + case WEAPONTYPE_AK47: + case WEAPONTYPE_M16: + case WEAPONTYPE_SNIPERRIFLE: + case WEAPONTYPE_TOTAL_INVENTORY_WEAPONS: + case WEAPONTYPE_UZI_DRIVEBY: + if (bBulletProof) + return; + bFrightensDriver = true; + break; + case WEAPONTYPE_ROCKETLAUNCHER: + case WEAPONTYPE_MOLOTOV: + case WEAPONTYPE_GRENADE: + case WEAPONTYPE_EXPLOSION: + if (bExplosionProof) + return; + bFrightensDriver = true; + break; + case WEAPONTYPE_FLAMETHROWER: + if (bFireProof) + return; + break; + case WEAPONTYPE_RAMMEDBYCAR: + if (bCollisionProof) + return; + break; + default: + break; + } + if (m_fHealth > 0.0f) { + if (VehicleCreatedBy == RANDOM_VEHICLE && pDriver && + (m_status == STATUS_SIMPLE || m_status == STATUS_PHYSICS) && + AutoPilot.m_nCarMission == MISSION_CRUISE) { + if (m_randomSeed < DAMAGE_FLEE_IN_CAR_PROBABILITY_VALUE) { + CCarCtrl::SwitchVehicleToRealPhysics(this); + AutoPilot.m_nDrivingStyle = DRIVINGSTYLE_AVOID_CARS; + AutoPilot.m_nCruiseSpeed = GAME_SPEED_TO_CARAI_SPEED * pHandling->Transmission.fUnkMaxVelocity; + m_status = STATUS_PHYSICS; + } + } + m_nLastWeaponDamage = weaponType; + float oldHealth = m_fHealth; + if (m_fHealth > damage) { + m_fHealth -= damage; + if (VehicleCreatedBy == RANDOM_VEHICLE && + (m_fHealth < DAMAGE_HEALTH_TO_FLEE_ALWAYS || + bFrightensDriver && m_randomSeed > DAMAGE_FLEE_ON_FOOT_PROBABILITY_VALUE)) { + switch (m_status) { + case STATUS_SIMPLE: + case STATUS_PHYSICS: + if (pDriver) { + m_status = STATUS_ABANDONED; + pDriver->bFleeAfterExitingCar = true; + pDriver->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this); + } + for (int i = 0; i < m_nNumMaxPassengers; i++) { + if (pPassengers[i]) { + pPassengers[i]->bFleeAfterExitingCar = true; + pPassengers[i]->SetObjective(OBJECTIVE_LEAVE_VEHICLE, this); + } + } + break; + default: + break; + } + } + if (oldHealth > DAMAGE_HEALTH_TO_CATCH_FIRE && m_fHealth < DAMAGE_HEALTH_TO_CATCH_FIRE) { + if (IsCar()) { + CAutomobile* pThisCar = (CAutomobile*)this; + pThisCar->Damage.SetEngineStatus(ENGINE_STATUS_ON_FIRE); + pThisCar->m_pSetOnFireEntity = damagedBy; + if (damagedBy) + damagedBy->RegisterReference((CEntity**)&pThisCar->m_pSetOnFireEntity); + } + } + } + else { + m_fHealth = 0.0f; + if (weaponType == WEAPONTYPE_EXPLOSION) { + // between 1000 and 3047. Also not very nice: can't be saved by respray or cheat + m_nBombTimer = 1000 + CGeneral::GetRandomNumber() & 0x7FF; + m_pBlowUpEntity = damagedBy; + if (damagedBy) + damagedBy->RegisterReference((CEntity**)&m_pBlowUpEntity); + } + else + BlowUpCar(damagedBy); + } + } +#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) +#else + if (GetModelIndex() == MI_POLICE && damagedBy == FindPlayerPed()) +#endif + FindPlayerPed()->SetWantedLevelNoDrop(1); +} + void CVehicle::ExtinguishCarFire(void) { @@ -375,6 +495,65 @@ CVehicle::ExtinguishCarFire(void) } } +bool +CVehicle::ShufflePassengersToMakeSpace(void) +{ + if (m_nNumPassengers >= m_nNumMaxPassengers) + return false; + if (pPassengers[1] && + !(m_nGettingInFlags & CAR_DOOR_FLAG_LR) && + IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_LEFT, nil)) { + if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) { + pPassengers[2] = pPassengers[1]; + pPassengers[1] = nil; + pPassengers[2]->m_vehEnterType = CAR_DOOR_RR; + return true; + } + if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { + pPassengers[0] = pPassengers[1]; + pPassengers[1] = nil; + pPassengers[0]->m_vehEnterType = CAR_DOOR_RF; + return true; + } + return false; + } + if (pPassengers[2] && + !(m_nGettingInFlags & CAR_DOOR_FLAG_RR) && + IsRoomForPedToLeaveCar(COMPONENT_DOOR_REAR_RIGHT, nil)) { + if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) { + pPassengers[1] = pPassengers[2]; + pPassengers[2] = nil; + pPassengers[1]->m_vehEnterType = CAR_DOOR_LR; + return true; + } + if (!pPassengers[0] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RF)) { + pPassengers[0] = pPassengers[2]; + pPassengers[2] = nil; + pPassengers[0]->m_vehEnterType = CAR_DOOR_RF; + return true; + } + return false; + } + if (pPassengers[0] && + !(m_nGettingInFlags & CAR_DOOR_FLAG_RF) && + IsRoomForPedToLeaveCar(COMPONENT_DOOR_FRONT_RIGHT, nil)) { + if (!pPassengers[1] && !(m_nGettingInFlags & CAR_DOOR_FLAG_LR)) { + pPassengers[1] = pPassengers[0]; + pPassengers[0] = nil; + pPassengers[1]->m_vehEnterType = CAR_DOOR_LR; + return true; + } + if (!pPassengers[2] && !(m_nGettingInFlags & CAR_DOOR_FLAG_RR)) { + pPassengers[2] = pPassengers[0]; + pPassengers[0] = nil; + pPassengers[2]->m_vehEnterType = CAR_DOOR_RR; + return true; + } + return false; + } + return false; +} + void CVehicle::ProcessDelayedExplosion(void) { @@ -831,4 +1010,5 @@ STARTPATCHES InjectHook(0x551EB0, &CVehicle::RemovePassenger, PATCH_JUMP); InjectHook(0x5525A0, &CVehicle::ProcessCarAlarm, PATCH_JUMP); InjectHook(0x552620, &CVehicle::IsSphereTouchingVehicle, PATCH_JUMP); + InjectHook(0x551950, &CVehicle::InflictDamage, PATCH_JUMP); ENDPATCHES diff --git a/src/vehicles/Vehicle.h b/src/vehicles/Vehicle.h index 2ca97841..4639f3e1 100644 --- a/src/vehicles/Vehicle.h +++ b/src/vehicles/Vehicle.h @@ -4,6 +4,7 @@ #include "AutoPilot.h" #include "ModelIndices.h" #include "AnimManager.h" +#include "Weapon.h" class CPed; class CFire; @@ -266,7 +267,7 @@ public: void ProcessCarAlarm(void); bool IsSphereTouchingVehicle(float sx, float sy, float sz, float radius); bool ShufflePassengersToMakeSpace(void); - void InflictDamage(CEntity *damagedBy, uint32 weaponType, float damage); + void InflictDamage(CEntity *damagedBy, eWeaponType weaponType, float damage); bool IsAlarmOn(void) { return m_nAlarmState != 0 && m_nAlarmState != -1; } CVehicleModelInfo* GetModelInfo() { return (CVehicleModelInfo*)CModelInfo::GetModelInfo(GetModelIndex()); } diff --git a/src/weapons/Weapon.cpp b/src/weapons/Weapon.cpp index 09844c23..0f41264f 100644 --- a/src/weapons/Weapon.cpp +++ b/src/weapons/Weapon.cpp @@ -14,6 +14,7 @@ WRAPPER void CWeapon::AddGunshell(CEntity*, CVector const&, CVector2D const&, fl WRAPPER void CWeapon::Update(int32 audioEntity) { EAXJMP(0x563A10); } WRAPPER void CWeapon::DoTankDoomAiming(CEntity *playerVehicle, CEntity *playerPed, CVector *start, CVector *end) { EAXJMP(0x563200); } WRAPPER void CWeapon::InitialiseWeapons(void) { EAXJMP(0x55C2D0); } +WRAPPER void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage) { EAXJMP(0x563B00); } void CWeapon::Initialise(eWeaponType type, int ammo) diff --git a/src/weapons/Weapon.h b/src/weapons/Weapon.h index 74145564..84760550 100644 --- a/src/weapons/Weapon.h +++ b/src/weapons/Weapon.h @@ -81,3 +81,5 @@ public: static void UpdateWeapons(void); }; static_assert(sizeof(CWeapon) == 0x18, "CWeapon: error"); + +void FireOneInstantHitRound(CVector* shotSource, CVector* shotTarget, int32 damage); \ No newline at end of file