diff --git a/src/General.h b/src/General.h index 8e1a2521..d67b1ff0 100644 --- a/src/General.h +++ b/src/General.h @@ -1,3 +1,6 @@ + + + class CGeneral { public: @@ -43,5 +46,8 @@ public: { return myrand() & 0xFFFF; } // Probably don't want to ever reach high static float GetRandomNumberInRange(float low, float high) - { return low + (high - low)*(GetRandomNumber()/65536.0f); } + { return low + (high - low)*(GetRandomNumber()/float(MY_RAND_MAX + 1)); } + + static Int32 GetRandomNumberInRange(Int32 low, Int32 high) + { return low + (high - low)*(GetRandomNumber()/float(MY_RAND_MAX + 1)); } }; diff --git a/src/ParticleMgr.cpp b/src/ParticleMgr.cpp new file mode 100644 index 00000000..d259c4b4 --- /dev/null +++ b/src/ParticleMgr.cpp @@ -0,0 +1,252 @@ +#include "common.h" +#include "patcher.h" +#include "FileMgr.h" +#include "ParticleMgr.h" + +_TODO("work_buff"); +UInt8 work_buff[55000]; + +cParticleSystemMgr mod_ParticleSystemManager; + +const Char *ParticleFilename = "PARTICLE.CFG"; + +//cParticleSystemMgr::cParticleSystemMgr() +void cParticleSystemMgr::ctor() +{ + memset(this, 0, sizeof(*this)); +} + +void cParticleSystemMgr::Initialise() +{ + LoadParticleData(); + + for ( Int32 i = 0; i < MAX_PARTICLES; i++ ) + m_aParticles[i].m_pParticles = NULL; +} + +void cParticleSystemMgr::LoadParticleData() +{ + CFileMgr::SetDir("DATA"); + CFileMgr::LoadFile(ParticleFilename, work_buff, ARRAY_SIZE(work_buff), "r"); + CFileMgr::SetDir(""); + + tParticleSystemData *entry = NULL; + Int32 type = PARTICLE_FIRST; + + Char *lineStart = (Char *)work_buff; + Char *lineEnd = lineStart + 1; + + Char line[500]; + Char delims[4]; + + while ( true ) + { + ASSERT(lineStart != NULL); + ASSERT(lineEnd != NULL); + + while ( *lineEnd != '\n' ) + ++lineEnd; + + Int32 lineLength = lineEnd - lineStart; + + ASSERT(lineLength < 500); + + strncpy(line, lineStart, lineLength); + + line[lineLength] = '\0'; + + if ( !strcmp(line, ";the end") ) + break; + + if ( *line != ';' ) + { + Int32 param = CFG_PARAM_FIRST; + + strcpy(delims, " \t"); + + Char *value = strtok(line, delims); + + ASSERT(value != NULL); + + do + { + switch ( param ) + { + case CFG_PARAM_PARTICLE_TYPE_NAME: + ASSERT(type < MAX_PARTICLES); + entry = &m_aParticles[type]; + ASSERT(entry != NULL); + entry->m_Type = (tParticleType)type++; + strcpy(entry->m_aName, value); + break; + + case CFG_PARAM_RENDER_COLOURING_R: + entry->m_RenderColouring.red = atoi(value); + break; + + case CFG_PARAM_RENDER_COLOURING_G: + entry->m_RenderColouring.green = atoi(value); + break; + + case CFG_PARAM_RENDER_COLOURING_B: + entry->m_RenderColouring.blue = atoi(value); + break; + + case CFG_PARAM_INITIAL_COLOR_VARIATION: + entry->m_InitialColorVariation = min(atoi(value), 100); + break; + + case CFG_PARAM_FADE_DESTINATION_COLOR_R: + entry->m_FadeDestinationColor.red = atoi(value); + break; + + case CFG_PARAM_FADE_DESTINATION_COLOR_G: + entry->m_FadeDestinationColor.green = atoi(value); + break; + + case CFG_PARAM_FADE_DESTINATION_COLOR_B: + entry->m_FadeDestinationColor.blue = atoi(value); + break; + + case CFG_PARAM_COLOR_FADE_TIME: + entry->m_ColorFadeTime = atoi(value); + break; + + case CFG_PARAM_DEFAULT_INITIAL_RADIUS: + entry->m_fDefaultInitialRadius = atof(value); + break; + + case CFG_PARAM_EXPANSION_RATE: + entry->m_fExpansionRate = atof(value); + break; + + case CFG_PARAM_INITIAL_INTENSITY: + entry->m_nFadeToBlackInitialIntensity = atoi(value); + break; + + case CFG_PARAM_FADE_TIME: + entry->m_nFadeToBlackTime = atoi(value); + break; + + case CFG_PARAM_FADE_AMOUNT: + entry->m_nFadeToBlackAmount = atoi(value); + break; + + case CFG_PARAM_INITIAL_ALPHA_INTENSITY: + entry->m_nFadeAlphaInitialIntensity = atoi(value); + break; + + case CFG_PARAM_FADE_ALPHA_TIME: + entry->m_nFadeAlphaTime = atoi(value); + break; + + case CFG_PARAM_FADE_ALPHA_AMOUNT: + entry->m_nFadeAlphaAmount = atoi(value); + break; + + case CFG_PARAM_INITIAL_ANGLE: + entry->m_nZRotationInitialAngle = atoi(value); + break; + + case CFG_PARAM_CHANGE_TIME: + entry->m_nZRotationChangeTime = atoi(value); + break; + + case CFG_PARAM_ANGLE_CHANGE_AMOUNT: + entry->m_nZRotationAngleChangeAmount = atoi(value); + break; + + case CFG_PARAM_INITIAL_Z_RADIUS: + entry->m_fInitialZRadius = atof(value); + break; + + case CFG_PARAM_Z_RADIUS_CHANGE_TIME: + entry->m_nZRadiusChangeTime = atoi(value); + break; + + case CFG_PARAM_Z_RADIUS_CHANGE_AMOUNT: + entry->m_fZRadiusChangeAmount = atof(value); + break; + + case CFG_PARAM_ANIMATION_SPEED: + entry->m_nAnimationSpeed = atoi(value); + break; + + case CFG_PARAM_START_ANIMATION_FRAME: + entry->m_nStartAnimationFrame = atoi(value); + break; + + case CFG_PARAM_FINAL_ANIMATION_FRAME: + entry->m_nFinalAnimationFrame = atoi(value); + break; + + case CFG_PARAM_ROTATION_SPEED: + entry->m_nRotationSpeed = atoi(value); + break; + + case CFG_PARAM_GRAVITATIONAL_ACCELERATION: + entry->m_fGravitationalAcceleration = atof(value); + break; + + case CFG_PARAM_FRICTION_DECCELERATION: + entry->m_nFrictionDecceleration = atoi(value); + break; + + case CFG_PARAM_LIFE_SPAN: + entry->m_nLifeSpan = atoi(value); + break; + + case CFG_PARAM_POSITION_RANDOM_ERROR: + entry->m_fPositionRandomError = atof(value); + break; + + case CFG_PARAM_VELOCITY_RANDOM_ERROR: + entry->m_fVelocityRandomError = atof(value); + break; + + case CFG_PARAM_EXPANSION_RATE_ERROR: + entry->m_fExpansionRateError = atof(value); + break; + + case CFG_PARAM_ROTATION_RATE_ERROR: + entry->m_nRotationRateError = atoi(value); + break; + + case CFG_PARAM_LIFE_SPAN_ERROR_SHAPE: + entry->m_nLifeSpanErrorShape = atoi(value); + break; + + case CFG_PARAM_TRAIL_LENGTH_MULTIPLIER: + entry->m_fTrailLengthMultiplier = atof(value); + break; + + case CFG_PARAM_PARTICLE_CREATE_RANGE: + entry->m_fCreateRange = SQR(atof(value)); + break; + + case CFG_PARAM_FLAGS: + entry->Flags = atoi(value); + break; + } + + value = strtok(NULL, delims); + + param++; + + if ( param > CFG_PARAM_LAST ) + param = CFG_PARAM_FIRST; + + } while ( value != NULL ); + } + + lineEnd++; + lineStart = lineEnd; + lineEnd++; + } +} + +STARTPATCHES + InjectHook(0x50FCB0, &cParticleSystemMgr::ctor, PATCH_JUMP); + InjectHook(0x50FCD0, &cParticleSystemMgr::Initialise, PATCH_JUMP); + InjectHook(0x50FDF0, &cParticleSystemMgr::LoadParticleData, PATCH_JUMP); +ENDPATCHES \ No newline at end of file diff --git a/src/ParticleMgr.h b/src/ParticleMgr.h new file mode 100644 index 00000000..a2dcbdb5 --- /dev/null +++ b/src/ParticleMgr.h @@ -0,0 +1,206 @@ +#pragma once + +class CParticle; + +enum tParticleType +{ + PARTICLE_SPARK = 0, + PARTICLE_SPARK_SMALL, + PARTICLE_WHEEL_DIRT, + PARTICLE_WHEEL_WATER, + PARTICLE_BLOOD, + PARTICLE_BLOOD_SMALL, + PARTICLE_BLOOD_SPURT, + PARTICLE_DEBRIS, + PARTICLE_DEBRIS2, + PARTICLE_WATER, + PARTICLE_FLAME, + PARTICLE_FIREBALL, + PARTICLE_GUNFLASH, + PARTICLE_GUNFLASH_NOANIM, + PARTICLE_GUNSMOKE, + PARTICLE_GUNSMOKE2, + PARTICLE_SMOKE, + PARTICLE_SMOKE_SLOWMOTION, + PARTICLE_GARAGEPAINT_SPRAY, + PARTICLE_SHARD, + PARTICLE_SPLASH, + PARTICLE_CARFLAME, + PARTICLE_STEAM, + PARTICLE_STEAM2, + PARTICLE_STEAM_NY, + PARTICLE_STEAM_NY_SLOWMOTION, + PARTICLE_ENGINE_STEAM, + PARTICLE_RAINDROP, + PARTICLE_RAINDROP_SMALL, + PARTICLE_RAIN_SPLASH, + PARTICLE_RAIN_SPLASH_BIGGROW, + PARTICLE_RAIN_SPLASHUP, + PARTICLE_WATERSPRAY, + PARTICLE_EXPLOSION_MEDIUM, + PARTICLE_EXPLOSION_LARGE, + PARTICLE_EXPLOSION_MFAST, + PARTICLE_EXPLOSION_LFAST, + PARTICLE_CAR_SPLASH, + PARTICLE_BOAT_SPLASH, + PARTICLE_BOAT_THRUSTJET, + PARTICLE_BOAT_WAKE, + PARTICLE_WATER_HYDRANT, + PARTICLE_WATER_CANNON, + PARTICLE_EXTINGUISH_STEAM, + PARTICLE_PED_SPLASH, + PARTICLE_PEDFOOT_DUST, + PARTICLE_HELI_DUST, + PARTICLE_HELI_ATTACK, + PARTICLE_ENGINE_SMOKE, + PARTICLE_ENGINE_SMOKE2, + PARTICLE_CARFLAME_SMOKE, + PARTICLE_FIREBALL_SMOKE, + PARTICLE_PAINT_SMOKE, + PARTICLE_TREE_LEAVES, + PARTICLE_CARCOLLISION_DUST, + PARTICLE_CAR_DEBRIS, + PARTICLE_HELI_DEBRIS, + PARTICLE_EXHAUST_FUMES, + PARTICLE_RUBBER_SMOKE, + PARTICLE_BURNINGRUBBER_SMOKE, + PARTICLE_BULLETHIT_SMOKE, + PARTICLE_GUNSHELL_FIRST, + PARTICLE_GUNSHELL, + PARTICLE_GUNSHELL_BUMP1, + PARTICLE_GUNSHELL_BUMP2, + PARTICLE_TEST, + PARTICLE_BIRD_FRONT, + PARTICLE_RAINDROP_2D, + + MAX_PARTICLES, + PARTICLE_FIRST = PARTICLE_SPARK, + PARTICLE_LAST = PARTICLE_RAINDROP_2D +}; + +enum +{ + ZCHECK_FIRST = BIT(0), + ZCHECK_STEP = BIT(1), + DRAW_OPAQUE = BIT(2), + SCREEN_TRAIL = BIT(3), + SPEED_TRAIL = BIT(4), + RAND_VERT_V = BIT(5), + CYCLE_ANIM = BIT(6), + DRAW_DARK = BIT(7), + VERT_TRAIL = BIT(8), + _FLAG9 = BIT(9), // unused + DRAWTOP2D = BIT(10), + CLIPOUT2D = BIT(11), + ZCHECK_BUMP = BIT(12), + ZCHECK_BUMP_FIRST = BIT(13) +}; + + +struct tParticleSystemData +{ + tParticleType m_Type; + Char m_aName[20]; + Float m_fCreateRange; + Float m_fDefaultInitialRadius; + Float m_fExpansionRate; + UInt16 m_nZRotationInitialAngle; + Int16 m_nZRotationAngleChangeAmount; + UInt16 m_nZRotationChangeTime; + UInt16 m_nZRadiusChangeTime; + Float m_fInitialZRadius; + Float m_fZRadiusChangeAmount; + UInt16 m_nFadeToBlackTime; + Int16 m_nFadeToBlackAmount; + UInt8 m_nFadeToBlackInitialIntensity; + UInt8 m_nFadeAlphaInitialIntensity; + UInt16 m_nFadeAlphaTime; + Int16 m_nFadeAlphaAmount; + UInt16 m_nStartAnimationFrame; + UInt16 m_nFinalAnimationFrame; + UInt16 m_nAnimationSpeed; + UInt16 m_nRotationSpeed; + char _pad1[2]; + Float m_fGravitationalAcceleration; + Int32 m_nFrictionDecceleration; + Int32 m_nLifeSpan; + Float m_fPositionRandomError; + Float m_fVelocityRandomError; + Float m_fExpansionRateError; + Int32 m_nRotationRateError; + UInt32 m_nLifeSpanErrorShape; + Float m_fTrailLengthMultiplier; + UInt32 Flags; + RwRGBA m_RenderColouring; + UInt8 m_InitialColorVariation; + RwRGBA m_FadeDestinationColor; + char _pad2[3]; + UInt32 m_ColorFadeTime; + + RwRaster **m_ppRaster; + CParticle *m_pParticles; +}; +VALIDATE_SIZE(tParticleSystemData, 0x88); + + +class cParticleSystemMgr +{ + enum + { + CFG_PARAM_PARTICLE_TYPE_NAME = 0, + CFG_PARAM_RENDER_COLOURING_R, + CFG_PARAM_RENDER_COLOURING_G, + CFG_PARAM_RENDER_COLOURING_B, + CFG_PARAM_INITIAL_COLOR_VARIATION, + CFG_PARAM_FADE_DESTINATION_COLOR_R, + CFG_PARAM_FADE_DESTINATION_COLOR_G, + CFG_PARAM_FADE_DESTINATION_COLOR_B, + CFG_PARAM_COLOR_FADE_TIME, + CFG_PARAM_DEFAULT_INITIAL_RADIUS, + CFG_PARAM_EXPANSION_RATE, + CFG_PARAM_INITIAL_INTENSITY, + CFG_PARAM_FADE_TIME, + CFG_PARAM_FADE_AMOUNT, + CFG_PARAM_INITIAL_ALPHA_INTENSITY, + CFG_PARAM_FADE_ALPHA_TIME, + CFG_PARAM_FADE_ALPHA_AMOUNT, + CFG_PARAM_INITIAL_ANGLE, + CFG_PARAM_CHANGE_TIME, + CFG_PARAM_ANGLE_CHANGE_AMOUNT, + CFG_PARAM_INITIAL_Z_RADIUS, + CFG_PARAM_Z_RADIUS_CHANGE_TIME, + CFG_PARAM_Z_RADIUS_CHANGE_AMOUNT, + CFG_PARAM_ANIMATION_SPEED, + CFG_PARAM_START_ANIMATION_FRAME, + CFG_PARAM_FINAL_ANIMATION_FRAME, + CFG_PARAM_ROTATION_SPEED, + CFG_PARAM_GRAVITATIONAL_ACCELERATION, + CFG_PARAM_FRICTION_DECCELERATION, + CFG_PARAM_LIFE_SPAN, + CFG_PARAM_POSITION_RANDOM_ERROR, + CFG_PARAM_VELOCITY_RANDOM_ERROR, + CFG_PARAM_EXPANSION_RATE_ERROR, + CFG_PARAM_ROTATION_RATE_ERROR, + CFG_PARAM_LIFE_SPAN_ERROR_SHAPE, + CFG_PARAM_TRAIL_LENGTH_MULTIPLIER, + CFG_PARAM_PARTICLE_CREATE_RANGE, + CFG_PARAM_FLAGS, + + MAX_CFG_PARAMS, + CFG_PARAM_FIRST = CFG_PARAM_PARTICLE_TYPE_NAME, + CFG_PARAM_LAST = CFG_PARAM_FLAGS + }; + +public: + tParticleSystemData m_aParticles[MAX_PARTICLES]; + + cParticleSystemMgr() { ctor(); } void ctor(); + + void Initialise(); + void LoadParticleData(); + //void RangeCheck(tParticleSystemData *pData); +}; + +VALIDATE_SIZE(cParticleSystemMgr, 0x2420); + +extern cParticleSystemMgr mod_ParticleSystemManager; \ No newline at end of file diff --git a/src/ParticleObject.cpp b/src/ParticleObject.cpp index 5ed82995..bd5e6b0a 100644 --- a/src/ParticleObject.cpp +++ b/src/ParticleObject.cpp @@ -3,3 +3,16 @@ #include "ParticleObject.h" WRAPPER void CParticleObject::AddObject(uint16, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); } + + +// Converted from static void __cdecl CParticleObject::Initialise() 0x42C760 +void CParticleObject::Initialise() +{ + ((void (__cdecl *)())0x4BC440)(); +} + +// Converted from static void __cdecl CParticleObject::UpdateAll() 0x4BCA30 +void CParticleObject::UpdateAll() +{ + ((void (__cdecl *)())0x4BCA30)(); +} \ No newline at end of file diff --git a/src/ParticleObject.h b/src/ParticleObject.h index b2cfadb8..d6b48810 100644 --- a/src/ParticleObject.h +++ b/src/ParticleObject.h @@ -28,4 +28,6 @@ class CParticleObject { public: static void AddObject(uint16, const CVector &pos, bool remove); + static void Initialise(); + static void UpdateAll(); }; diff --git a/src/RecordDataForChase.cpp b/src/RecordDataForChase.cpp new file mode 100644 index 00000000..6bff623e --- /dev/null +++ b/src/RecordDataForChase.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "RecordDataForChase.h" + + +UInt8 &CRecordDataForChase::Status = *(UInt8*)0x95CDCE; \ No newline at end of file diff --git a/src/RecordDataForChase.h b/src/RecordDataForChase.h new file mode 100644 index 00000000..0dc72bed --- /dev/null +++ b/src/RecordDataForChase.h @@ -0,0 +1,7 @@ +#pragma once + +class CRecordDataForChase +{ +public: + static UInt8 &Status; +}; \ No newline at end of file diff --git a/src/RecordDataForGame.cpp b/src/RecordDataForGame.cpp new file mode 100644 index 00000000..05b4223c --- /dev/null +++ b/src/RecordDataForGame.cpp @@ -0,0 +1,4 @@ +#include "common.h" +#include "RecordDataForGame.h" + +UInt16 &CRecordDataForGame::RecordingState = *(UInt16 *)0x95CC24; \ No newline at end of file diff --git a/src/RecordDataForGame.h b/src/RecordDataForGame.h new file mode 100644 index 00000000..5d007ce5 --- /dev/null +++ b/src/RecordDataForGame.h @@ -0,0 +1,7 @@ +#pragma once + +class CRecordDataForGame +{ +public: + static UInt16 &RecordingState; +}; \ No newline at end of file diff --git a/src/Timer.cpp b/src/Timer.cpp index 9cc35e42..02dbf55a 100644 --- a/src/Timer.cpp +++ b/src/Timer.cpp @@ -1,6 +1,10 @@ #include "common.h" #include "patcher.h" +#include "DMAudio.h" #include "Timer.h" +#include "RecordDataForGame.h" +#include "RecordDataForChase.h" +#include uint32 &CTimer::m_snTimeInMilliseconds = *(uint32*)0x885B48; uint32 &CTimer::m_snTimeInMillisecondsPauseMode = *(uint32*)0x5F7614; @@ -12,3 +16,217 @@ float &CTimer::ms_fTimeStep = *(float*)0x8E2CB4; float &CTimer::ms_fTimeStepNonClipped = *(float*)0x8E2C4C; bool &CTimer::m_UserPause = *(bool*)0x95CD7C; bool &CTimer::m_CodePause = *(bool*)0x95CDB1; + +UInt32 oldPcTimer; +UInt32 suspendPcTimer; + +UInt32 _nCyclesPerMS = 1; + +LARGE_INTEGER _oldPerfCounter; +LARGE_INTEGER perfSuspendCounter; + +UInt32 suspendDepth; + +_TODO("We need skeleton.c for RsTimer()"); + +RwUInt32 RsTimer(void) +{ + return ((RwUInt32 (__cdecl *)())0x584890)(); +} + +void CTimer::Initialise(void) +{ + debug("Initialising CTimer...\n"); + + ms_fTimeScale = 1.0f; + ms_fTimeStep = 1.0f; + suspendDepth = 0; + m_UserPause = false; + m_CodePause = false; + m_snTimeInMillisecondsNonClipped = 0; + m_snPreviousTimeInMilliseconds = 0; + m_snTimeInMilliseconds = 1; + + LARGE_INTEGER perfFreq; + if ( QueryPerformanceFrequency(&perfFreq) ) + { + OutputDebugString("Performance counter available\n"); + _nCyclesPerMS = UInt32(perfFreq.QuadPart / 1000); + QueryPerformanceCounter(&_oldPerfCounter); + } + else + { + OutputDebugString("Performance counter not available, using millesecond timer\n"); + _nCyclesPerMS = 0; + oldPcTimer = RsTimer(); + } + + m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds; + + m_FrameCounter = 0; + + DMAudio.ResetTimers(m_snPreviousTimeInMilliseconds); + + debug("CTimer ready\n"); +} + +void CTimer::Shutdown(void) +{ + ; +} + +void CTimer::Update(void) +{ + m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; + + if ( (Double)_nCyclesPerMS != 0.0 ) + { + LARGE_INTEGER pc; + QueryPerformanceCounter(&pc); + + Int64 updInCycles = (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF; + + _oldPerfCounter = pc; + + Double updInCyclesScaled = (Double)updInCycles * ms_fTimeScale; + + Double upd = updInCyclesScaled / (Double)_nCyclesPerMS; + + m_snTimeInMillisecondsPauseMode += Int64(upd); + + if ( GetIsPaused() ) + ms_fTimeStep = 0.0f; + else + { + m_snTimeInMilliseconds = Int64(upd); + m_snTimeInMillisecondsNonClipped += Int64(upd); + ms_fTimeStep = updInCyclesScaled / (Double)_nCyclesPerMS / 20.0; + } + } + else + { + UInt32 timer = RsTimer(); + + UInt32 updInMs = timer - oldPcTimer; + + Double upd = (Double)updInMs * ms_fTimeScale; + + oldPcTimer = timer; + + m_snTimeInMillisecondsPauseMode += Int64(upd); + + if ( GetIsPaused() ) + ms_fTimeStep = 0.0f; + else + { + m_snTimeInMilliseconds += Int64(upd); + m_snTimeInMillisecondsNonClipped += Int64(upd); + ms_fTimeStep = upd / 1000.0f * 50.0f; + } + } + + if ( ms_fTimeStep < 0.01f && !GetIsPaused() ) + ms_fTimeStep = 0.01f; + + ms_fTimeStepNonClipped = ms_fTimeStep; + + if ( CRecordDataForGame::RecordingState != _TODOCONST(2) ) + { + ms_fTimeStep = min(3.0f, ms_fTimeStep); + + if ( (m_snTimeInMilliseconds - m_snPreviousTimeInMilliseconds) > 60 ) + m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 60; + } + + if ( CRecordDataForChase::Status == _TODOCONST(1) ) + { + ms_fTimeStep = 1.0f; + m_snTimeInMilliseconds = m_snPreviousTimeInMilliseconds + 16; + } + + m_FrameCounter++; +} + +void CTimer::Suspend(void) +{ + if ( ++suspendDepth > 1 ) + return; + + if ( (Double)_nCyclesPerMS != 0.0 ) + QueryPerformanceCounter(&perfSuspendCounter); + else + suspendPcTimer = RsTimer(); +} + +void CTimer::Resume(void) +{ + if ( --suspendDepth != 0 ) + return; + + if ( (Double)_nCyclesPerMS != 0.0 ) + { + LARGE_INTEGER pc; + QueryPerformanceCounter(&pc); + + _oldPerfCounter.LowPart += pc.LowPart - perfSuspendCounter.LowPart; + } + else + oldPcTimer += RsTimer() - suspendPcTimer; +} + +UInt32 CTimer::GetCyclesPerMillisecond(void) +{ + if (_nCyclesPerMS != 0) + return _nCyclesPerMS; + else + return 1; +} + +UInt32 CTimer::GetCurrentTimeInCycles(void) +{ + if ( _nCyclesPerMS != 0 ) + { + LARGE_INTEGER pc; + QueryPerformanceCounter(&pc); + return (pc.LowPart - _oldPerfCounter.LowPart) & 0x7FFFFFFF; + } + else + return RsTimer() - oldPcTimer; +} + +Bool CTimer::GetIsSlowMotionActive(void) +{ + return ms_fTimeScale < 1.0f; +} + +void CTimer::Stop(void) +{ + m_snPreviousTimeInMilliseconds = m_snTimeInMilliseconds; +} + +void CTimer::StartUserPause(void) +{ + m_UserPause = true; +} + +void CTimer::EndUserPause(void) +{ + m_UserPause = false; +} + +#if 0 +STARTPATCHES + InjectHook(0x4ACE60, CTimer::Initialise, PATCH_JUMP); + InjectHook(0x4ACF60, CTimer::Shutdown, PATCH_JUMP); + InjectHook(0x4ACF70, CTimer::Update, PATCH_JUMP); + InjectHook(0x4AD310, CTimer::Suspend, PATCH_JUMP); + InjectHook(0x4AD370, CTimer::Resume, PATCH_JUMP); + InjectHook(0x4AD3F0, CTimer::GetCyclesPerMillisecond, PATCH_JUMP); + InjectHook(0x4AD410, CTimer::GetCurrentTimeInCycles, PATCH_JUMP); + InjectHook(0x4AD450, CTimer::GetIsSlowMotionActive, PATCH_JUMP); + InjectHook(0x4AD480, CTimer::Stop, PATCH_JUMP); + InjectHook(0x4AD490, CTimer::StartUserPause, PATCH_JUMP); + InjectHook(0x4AD4A0, CTimer::EndUserPause, PATCH_JUMP); +ENDPATCHES +#endif + diff --git a/src/Timer.h b/src/Timer.h index e92fe9e1..d5e51dfc 100644 --- a/src/Timer.h +++ b/src/Timer.h @@ -17,4 +17,18 @@ public: static void SetTimeStep(float ts) { ms_fTimeStep = ts; } static uint32 GetFrameCounter(void) { return m_FrameCounter; } static uint32 GetTimeInMilliseconds(void) { return m_snTimeInMilliseconds; } + + static inline Bool GetIsPaused() { return m_UserPause || m_CodePause; } + + static void Initialise(void); + static void Shutdown(void); + static void Update(void); + static void Suspend(void); + static void Resume(void); + static UInt32 GetCyclesPerMillisecond(void); + static UInt32 GetCurrentTimeInCycles(void); + static Bool GetIsSlowMotionActive(void); + static void Stop(void); + static void StartUserPause(void); + static void EndUserPause(void); }; diff --git a/src/audio/AudioScriptObject.cpp b/src/audio/AudioScriptObject.cpp new file mode 100644 index 00000000..7cb81f7a --- /dev/null +++ b/src/audio/AudioScriptObject.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "AudioScriptObject.h" + +void PlayOneShotScriptObject(UInt8 id, CVector const &pos) +{ + ((void (__cdecl *)(UInt8, CVector const &))0x57C5F0)(id, pos); +} \ No newline at end of file diff --git a/src/audio/AudioScriptObject.h b/src/audio/AudioScriptObject.h new file mode 100644 index 00000000..a30af679 --- /dev/null +++ b/src/audio/AudioScriptObject.h @@ -0,0 +1,131 @@ +#pragma once + +enum /*eSounds*/ +{ + SOUND_TEST_1 = 0, + _SOUND_UNK_1 = 1, + _SOUND_UNK_2 = 2, + _SOUND_UNK_3 = 3, + _SOUND_CLUB_1_S = 4, + _SOUND_CLUB_1_L = 5, + _SOUND_CLUB_2_S = 6, + _SOUND_CLUB_2_L = 7, + _SOUND_CLUB_3_S = 8, + _SOUND_CLUB_3_L = 9, + _SOUND_CLUB_4_S = 10, + _SOUND_CLUB_4_L = 11, + _SOUND_CLUB_5_S = 12, + _SOUND_CLUB_5_L = 13, + _SOUND_CLUB_6_S = 14, + _SOUND_CLUB_6_L = 15, + _SOUND_CLUB_7_S = 16, + _SOUND_CLUB_7_L = 17, + _SOUND_CLUB_8_S = 18, + _SOUND_CLUB_8_L = 19, + _SOUND_CLUB_9_S = 20, + _SOUND_CLUB_9_L = 21, + _SOUND_CLUB_10_S = 22, + _SOUND_CLUB_10_L = 23, + _SOUND_CLUB_11_S = 24, + _SOUND_CLUB_11_L = 25, + _SOUND_CLUB_12_S = 26, + _SOUND_CLUB_12_L = 27, + _SOUND_CLUB_RAGGA_S = 28, + _SOUND_CLUB_RAGGA_L = 29, + SOUND_STRIP_CLUB_LOOP_1_S = 30, + _SOUND_STRIP_CLUB_LOOP_1_L = 31, + SOUND_STRIP_CLUB_LOOP_2_S = 32, + _SOUND_STRIP_CLUB_LOOP_2_L = 33, + _SOUND_SFX_WORKSHOP_1 = 34, + _SOUND_SFX_WORKSHOP_2 = 35, + _SOUND_SAWMILL_LOOP_S = 36, + SOUND_SAWMILL_LOOP_L = 37, + _SOUND_DOG_FOOD_FACTORY_S = 38, + _SOUND_DOG_FOOD_FACTORY_L = 39, + _SOUND_LAUNDERETTE_1 = 40, + _SOUND_LAUNDERETTE_2 = 41, + _SOUND_RESTAURANT_CHINATOWN_S = 42, + _SOUND_RESTAURANT_CHINATOWN_L = 43, + _SOUND_RESTAURANT_ITALY_S = 44, + _SOUND_RESTAURANT_ITALY_L = 45, + _SOUND_RESTAURANT_GENERIC_1_S = 46, + _SOUND_RESTAURANT_GENERIC_1_L = 47, + _SOUND_RESTAURANT_GENERIC_2_S = 48, + _SOUND_RESTAURANT_GENERIC_2_L = 49, + _SOUND_AIRPORT_ANNOUNCEMENT_S = 50, + _SOUND_AIRPORT_ANNOUNCEMENT_L = 51, + _SOUND_SHOP_LOOP_1 = 52, + _SOUND_SHOP_LOOP_2 = 53, + _SOUND_CINEMA_S = 54, + _SOUND_CINEMA_L = 55, + _SOUND_DOCKS_FOGHORN_S = 56, + _SOUND_DOCKS_FOGHORN_L = 57, + _SOUND_HOME_S = 58, + _SOUND_HOME_L = 59, + _SOUND_PIANO_BAR = 60, + _SOUND_CLUB = 61, + SOUND_PORN_CINEMA_1_S = 62, + _SOUND_PORN_CINEMA_1_L = 63, + SOUND_PORN_CINEMA_2_S = 64, + _SOUND_PORN_CINEMA_2_L = 65, + SOUND_PORN_CINEMA_3_S = 66, + _SOUND_PORN_CINEMA_3_L = 67, + _SOUND_BANK_ALARM_LOOP_S = 68, + SOUND_BANK_ALARM_LOOP_L = 69, + _SOUND_POLICE_BALL_LOOP_S = 70, + SOUND_POLICE_BALL_LOOP_L = 71, + _SOUND_RAVE_LOOP_INDUSTRIAL_S = 72, + SOUND_RAVE_LOOP_INDUSTRIAL_L = 73, + _SOUND_UNK_74 = 74, + _SOUND_UNK_75 = 75, + _SOUND_POLICE_CELL_BEATING_LOOP_S = 76, + SOUND_POLICE_CELL_BEATING_LOOP_L = 77, + SOUND_INJURED_PED_MALE_OUCH_S = 78, + SOUND_INJURED_PED_MALE_OUCH_L = 79, + SOUND_INJURED_PED_FEMALE_OUCH_S = 80, + SOUND_INJURED_PED_FEMALE_OUCH_L = 81, + SOUND_EVIDENCE_PICKUP = 82, + SOUND_UNLOAD_GOLD = 83, + _SOUND_RAVE_INDUSTRIAL_S = 84, + _SOUND_RAVE_INDUSTRIAL_L = 85, + _SOUND_RAVE_COMMERCIAL_S = 86, + _SOUND_RAVE_COMMERCIAL_L = 87, + _SOUND_RAVE_SUBURBAN_S = 88, + _SOUND_RAVE_SUBURBAN_L = 89, + _SOUND_GROAN_S = 90, + _SOUND_GROAN_L = 91, + SOUND_GATE_START_CLUNK = 92, + SOUND_GATE_STOP_CLUNK = 93, + SOUND_PART_MISSION_COMPLETE = 94, + SOUND_CHUNKY_RUN_SHOUT = 95, + SOUND_SECURITY_GUARD_RUN_AWAY_SHOUT = 96, + SOUND_RACE_START_1 = 97, + SOUND_RACE_START_2 = 98, + SOUND_RACE_START_3 = 99, + SOUND_RACE_START_GO = 100, + SOUND_SWAT_PED_SHOUT = 101, + SOUND_PRETEND_FIRE_LOOP = 102, + SOUND_AMMUNATION_CHAT_1 = 103, + SOUND_AMMUNATION_CHAT_2 = 104, + SOUND_AMMUNATION_CHAT_3 = 105, + _SOUND_BULLET_WALL_1 = 106, + _SOUND_BULLET_WALL_2 = 107, + _SOUND_BULLET_WALL_3 = 108, + _SOUND_UNK_109 = 109, + _SOUND_GLASSFX2_1 = 110, + _SOUND_GLASSFX2_2 = 111, + _SOUND_PHONE_RING = 112, + _SOUND_UNK_113 = 113, + _SOUND_GLASS_SMASH_1 = 114, + _SOUND_GLASS_SMASH_2 = 115, + _SOUND_GLASS_CRACK = 116, + _SOUND_GLASS_SHARD = 117, + _SOUND_WOODEN_BOX_SMASH = 118, + _SOUND_CARDBOARD_BOX_SMASH = 119, + _SOUND_COL_CAR = 120, + _SOUND_TYRE_BUMP = 121, + _SOUND_BULLET_SHELL_HIT_GROUND_1 = 122, + _SOUND_BULLET_SHELL_HIT_GROUND_2 = 123, +}; + +extern void PlayOneShotScriptObject(UInt8 id, CVector const &pos); \ No newline at end of file diff --git a/src/audio/DMAudio.cpp b/src/audio/DMAudio.cpp index 1ab5a52f..400f3fdc 100644 --- a/src/audio/DMAudio.cpp +++ b/src/audio/DMAudio.cpp @@ -5,3 +5,9 @@ cDMAudio &DMAudio = *(cDMAudio*)0x95CDBE; WRAPPER void cDMAudio::ReportCollision(CEntity *A, CEntity *B, uint8 surfA, uint8 surfB, float impulse, float speed) { EAXJMP(0x57CBE0); } + + +void cDMAudio::ResetTimers(UInt32 timerval) +{ + ((void (__thiscall *)(cDMAudio *, UInt32))0x57CCD0)(this, timerval); +} \ No newline at end of file diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h index 140c6493..b6d5fc64 100644 --- a/src/audio/DMAudio.h +++ b/src/audio/DMAudio.h @@ -6,5 +6,6 @@ class cDMAudio { public: void ReportCollision(CEntity *A, CEntity *B, uint8 surfA, uint8 surfB, float impulse, float speed); + void ResetTimers(UInt32 timerval); }; extern cDMAudio &DMAudio; diff --git a/src/common.h b/src/common.h index 083f4257..89c031fe 100644 --- a/src/common.h +++ b/src/common.h @@ -26,6 +26,24 @@ typedef uint32_t uint32; typedef int32_t int32; typedef uintptr_t uintptr; +typedef char Int8; +typedef unsigned char UInt8; +typedef signed char SInt8; +typedef short Int16; +typedef unsigned short UInt16; +typedef signed short SInt16; +typedef int Int32; +typedef unsigned int UInt32; +typedef signed int SInt32; +typedef float Float; +typedef double Double; +typedef Int8 Bool; //typedef bool Bool; +typedef char Char; + +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +typedef signed __int64 SInt64; + #define nil NULL #include "config.h" @@ -63,6 +81,15 @@ extern RsGlobalType &RsGlobal; #define SCREENW (RsGlobal.maximumWidth) #define SCREENH (RsGlobal.maximumHeight) +#define DEFAULT_SCREEN_WIDTH (640) +#define DEFAULT_SCREEN_HEIGHT (448) +#define SCREEN_WIDTH Float(RsGlobal.width) +#define SCREEN_HEIGHT Float(RsGlobal.height) +#define SCREEN_STRETCH_X(a) Float( a * ( SCREEN_WIDTH / Float(DEFAULT_SCREEN_WIDTH) ) ) +#define SCREEN_STRETCH_Y(a) Float( a * ( SCREEN_HEIGHT / Float(DEFAULT_SCREEN_HEIGHT) ) ) +#define SCREEN_FROM_RIGHT(a) Float( SCREEN_WIDTH - SCREEN_STRETCH_X(a) ) +#define SCREEN_FROM_BOTTOM(a) Float( SCREEN_HEIGHT - SCREEN_STRETCH_Y(a) ) + char *GetUserDirectory(void); struct GlobalScene @@ -80,22 +107,70 @@ extern GlobalScene &Scene; class CRGBA { public: - uint8 r, g, b, a; + union + { + uint32 color32; + struct { uint8 r, g, b, a; }; + struct { uint8 red, green, blue, alpha; }; +#ifdef RWCORE_H + struct { RwRGBA rwRGBA; }; +#endif + }; + CRGBA(void) { } CRGBA(uint8 r, uint8 g, uint8 b, uint8 a) : r(r), g(g), b(b), a(a) { } +#ifdef RWCORE_H + operator RwRGBA &(void) + { + return rwRGBA; + } + + operator RwRGBA *(void) + { + return &rwRGBA; + } + + operator RwRGBA (void) const + { + return rwRGBA; + } +#endif }; -inline float -clamp(float v, float min, float max){ return vmax ? max : v; } +// inline float clamp(float v, float min, float max){ return vmax ? max : v; } + inline float sq(float x) { return x*x; } + +#define SQR(x) ( x * x ) + #define PI M_PI -#define DEGTORAD(d) (d/180.0f*PI) +#define DEGTORAD(x) ((x) * PI / 180.0f) +#define RADTODEG(x) ((x) * 180.0f / PI) + + +#if USE_PS2_RAND == TRUE +#define MY_RAND_MAX 65535 +#else +#define MY_RAND_MAX 32767 +#endif int myrand(void); void mysrand(unsigned int seed); #define debug printf +#define ASSERT assert +#define _TODO(x) +#define _TODOCONST(x) (x) + +#define VALIDATE_SIZE(struc, size) static_assert(sizeof(struc) == size, "Invalid structure size of " #struc) +#define VALIDATE_OFFSET(struc, member, offset) static_assert(offsetof(struc, member) == offset, "The offset of " #member " in " #struc " is not " #offset "...") + +#define clamp(v, a, b) (max(min(v, b), a)) //#define min(a, b) ((a) < (b) ? (a) : (b)) //#define max(a, b) ((a) > (b) ? (a) : (b)) + +#define PERCENT(x, p) ( ( Float(x) * ( Float(p) / 100.0f ) ) ) +#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0])) +#define BIT(num) (1<<(num)) \ No newline at end of file diff --git a/src/config.h b/src/config.h index df99487f..8637814d 100644 --- a/src/config.h +++ b/src/config.h @@ -53,4 +53,6 @@ enum Config { NUMHOURS = 24, }; +#define USE_PS2_RAND TRUE + #endif diff --git a/src/main.cpp b/src/main.cpp index 4f125098..853308a1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,17 +24,37 @@ void operator delete(void *ptr) noexcept { gtadelete(ptr); } unsigned __int64 myrand_seed = 1; -int -myrand(void) + +int _cwrand() // original codewarrior rand { + return ((int (__cdecl *)())0x5A41D0)(); +} + +int +myps2rand(void) +{ + return _cwrand(); myrand_seed = 0x5851F42D4C957F2D * myrand_seed + 1; return ((myrand_seed >> 32) & 0x7FFFFFFF); } +int myrand(void) +{ +#if USE_PS2_RAND == TRUE + return myps2rand(); +#else + return _cwrand(); +#endif +} + void mysrand(unsigned int seed) { +#if USE_PS2_RAND == TRUE myrand_seed = seed; +#else + ; +#endif } // platform stuff diff --git a/src/math/Vector.cpp b/src/math/Vector.cpp new file mode 100644 index 00000000..d9cc590f --- /dev/null +++ b/src/math/Vector.cpp @@ -0,0 +1,78 @@ +#include "common.h" +#include "Vector.h" + +void CVector::Normalise() +{ + float sq = MagnitudeSqr(); + if(sq > 0.0f){ + float invsqrt = 1.0f/sqrt(sq); // CMaths::RecipSqrt + x *= invsqrt; + y *= invsqrt; + z *= invsqrt; + }else + x = 1.0f; +} + +// operator + +CVector operator + (CVector const &refLeft, CVector const &refRight) +{ + return CVector(refLeft.x + refRight.x, refLeft.y + refRight.y, refLeft.z + refRight.z); +} + +CVector operator + (CVector const &refLeft, float fRight) +{ + return CVector(refLeft.x + fRight, refLeft.y + fRight, refLeft.z + fRight); +} + +CVector operator + (float fLeft, CVector const &refRight) +{ + return CVector(fLeft + refRight.x, fLeft + refRight.y, fLeft + refRight.z); +} + +// operator - +CVector operator - (CVector const &refLeft, CVector const &refRight) +{ + return CVector(refLeft.x - refRight.x, refLeft.y - refRight.y, refLeft.z - refRight.z); +} + +CVector operator - (CVector const &refLeft, float fRight) +{ + return CVector(refLeft.x - fRight, refLeft.y - fRight, refLeft.z - fRight); +} + +CVector operator - (float fLeft, CVector const &refRight) +{ + return CVector(fLeft - refRight.x, fLeft - refRight.y, fLeft - refRight.z); +} + +// operator * +CVector operator * (CVector const &refLeft, CVector const &refRight) +{ + return CVector(refLeft.x * refRight.x, refLeft.y * refRight.y, refLeft.z * refRight.z); +} + +CVector operator * (CVector const &refLeft, float fRight) +{ + return CVector(refLeft.x * fRight, refLeft.y * fRight, refLeft.z * fRight); +} + +CVector operator * (float fLeft, CVector const &refRight) +{ + return CVector(fLeft * refRight.x, fLeft * refRight.y, fLeft * refRight.z); +} + +// operator / +CVector operator / (CVector const &refLeft, CVector const &refRight) +{ + return CVector(refLeft.x / refRight.x, refLeft.y / refRight.y, refLeft.z / refRight.z); +} + +CVector operator / (CVector const &refLeft, float fRight) +{ + return CVector(refLeft.x / fRight, refLeft.y / fRight, refLeft.z / fRight); +} + +CVector operator / (float fLeft, CVector const &refRight) +{ + return CVector(fLeft / refRight.x, fLeft / refRight.y, fLeft / refRight.z); +} \ No newline at end of file diff --git a/src/math/Vector.h b/src/math/Vector.h index fbc59832..e45906c8 100644 --- a/src/math/Vector.h +++ b/src/math/Vector.h @@ -6,67 +6,128 @@ public: float x, y, z; CVector(void) {} CVector(float x, float y, float z) : x(x), y(y), z(z) {} -// CVector(rw::V3d const &v) : x(v.x), y(v.y), z(v.z) {} +// CVector(CVector &refVector) : x(refVector.x), y(refVector.y), z(refVector.z) { } +// CVector(const CVector &refVector) : x(refVector.x), y(refVector.y), z(refVector.z) {} +// CVector(CVector2D &refVector, float _z = 0.0f) : x(refVector.x), y(refVector.y), z(_z) {} +#ifdef RWCORE_H + CVector(RwV3d const &v) : x(v.x), y(v.y), z(v.z) {} + + operator RwV3d (void) const { + RwV3d vecRw = { this->x, this->y, this->z }; + return vecRw; + } + + operator RwV3d *(void) + { + return (RwV3d *)this; + } + + operator RwV3d &(void) + { + return *((RwV3d *)this); + } +#endif float Magnitude(void) const { return sqrt(x*x + y*y + z*z); } float MagnitudeSqr(void) const { return x*x + y*y + z*z; } float Magnitude2D(void) const { return sqrt(x*x + y*y); } - void Normalise(void){ - float sq = MagnitudeSqr(); - if(sq > 0.0f){ - float invsqrt = 1.0f/sqrt(sq); - x *= invsqrt; - y *= invsqrt; - z *= invsqrt; - }else - x = 1.0f; - } -// rw::V3d ToRW(void){ -// return rw::makeV3d(x, y, z); -// } -// void operator=(rw::V3d const &rhs){ -// x = rhs.x; -// y = rhs.y; -// z = rhs.z; -// } - CVector operator-(const CVector &rhs) const { - return CVector(x-rhs.x, y-rhs.y, z-rhs.z); - } - CVector operator+(const CVector &rhs) const { - return CVector(x+rhs.x, y+rhs.y, z+rhs.z); - } - CVector operator*(float t) const { - return CVector(x*t, y*t, z*t); - } - CVector operator/(float t) const { - return CVector(x/t, y/t, z/t); - } - CVector &operator-=(const CVector &rhs) { - this->x -= rhs.x; - this->y -= rhs.y; - this->z -= rhs.z; + void Normalise(void); + + + // operator = + inline CVector const& operator = (CVector const &refRight) + { + x = refRight.x; + y = refRight.y; + z = refRight.z; return *this; } - CVector &operator+=(const CVector &rhs) { - this->x += rhs.x; - this->y += rhs.y; - this->z += rhs.z; + + inline CVector const& operator = (float fRight) + { + x = fRight; + y = fRight; + z = fRight; return *this; } - CVector &operator*=(float t) { - this->x *= t; - this->y *= t; - this->z *= t; + + // operator += + inline CVector const& operator += (CVector const &refRight) + { + x += refRight.x; + y += refRight.y; + z += refRight.z; return *this; } - CVector &operator/=(float t) { - this->x /= t; - this->y /= t; - this->z /= t; + + inline CVector const& operator += (float fRight) + { + x += fRight; + y += fRight; + z += fRight; return *this; } + + // operator -= + inline CVector const& operator -= (CVector const &refRight) + { + x -= refRight.x; + y -= refRight.y; + z -= refRight.z; + return *this; + } + + inline CVector const& operator -= (float fRight) + { + x -= fRight; + y -= fRight; + z -= fRight; + return *this; + } + + // operator *= + inline CVector const& operator *= (CVector const &refRight) + { + x *= refRight.x; + y *= refRight.y; + z *= refRight.z; + return *this; + } + + inline CVector const& operator *= (float fRight) + { + x *= fRight; + y *= fRight; + z *= fRight; + return *this; + } + + // operator /= + inline CVector const& operator /= (CVector const &refRight) + { + x /= refRight.x; + y /= refRight.y; + z /= refRight.z; + return *this; + } + + inline CVector const& operator /= (float fRight) + { + x /= fRight; + y /= fRight; + z /= fRight; + return *this; + } + + inline CVector operator - () const + { + return CVector(-x, -y, -z); + } + bool IsZero(void) { return x == 0.0f && y == 0.0f && z == 0.0f; } }; +//extern CVector operator*(CMatrix const& matrix, CVector const& vector); + inline float DotProduct(const CVector &v1, const CVector &v2) { @@ -81,3 +142,23 @@ CrossProduct(const CVector &v1, const CVector &v2) v1.z*v2.x - v1.x*v2.z, v1.x*v2.y - v1.y*v2.x); } + +// operator + +extern CVector operator + (CVector const &refLeft, CVector const &refRight); +extern CVector operator + (CVector const &refLeft, float fRight); +extern CVector operator + (float fLeft, CVector const &refRight); + +// operator - +extern CVector operator - (CVector const &refLeft, CVector const &refRight); +extern CVector operator - (CVector const &refLeft, float fRight); +extern CVector operator - (float fLeft, CVector const &refRight); + +// operator * +extern CVector operator * (CVector const &refLeft, CVector const &refRight); +extern CVector operator * (CVector const &refLeft, float fRight); +extern CVector operator * (float fLeft, CVector const &refRight); + +// operator / +extern CVector operator / (CVector const &refLeft, CVector const &refRight); +extern CVector operator / (CVector const &refLeft, float fRight); +extern CVector operator / (float fLeft, CVector const &refRight); \ No newline at end of file diff --git a/src/render/Particle.cpp b/src/render/Particle.cpp index 9bbc4587..aade3578 100644 --- a/src/render/Particle.cpp +++ b/src/render/Particle.cpp @@ -1,10 +1,1868 @@ #include "common.h" #include "patcher.h" +#include "General.h" +#include "Timer.h" +#include "TxdStore.h" +#include "Sprite.h" +#include "Camera.h" +#include "Collision.h" +#include "World.h" +#include "Shadows.h" +#include "AudioScriptObject.h" +#include "ParticleObject.h" #include "Particle.h" -WRAPPER void -CParticle::AddParticle(tParticleType, const CVector &pos, const CVector &velocity, CEntity *ent, - float size, int32 rotationStep, int32 rotation, int startFrame, int lifeSpan) +#define MAX_PARTICLES_ON_SCREEN (1000) + + +//(5) +#define MAX_SMOKE_FILES ARRAY_SIZE(SmokeFiles) + +//(5) +#define MAX_SMOKE2_FILES ARRAY_SIZE(Smoke2Files) +//(5) +#define MAX_RUBBER_FILES ARRAY_SIZE(RubberFiles) +//(5) +#define MAX_RAINSPLASH_FILES ARRAY_SIZE(RainSplashFiles) +//(3) +#define MAX_WATERSPRAY_FILES ARRAY_SIZE(WatersprayFiles) +//(6) +#define MAX_EXPLOSIONMEDIUM_FILES ARRAY_SIZE(ExplosionMediumFiles) +//(4) +#define MAX_GUNFLASH_FILES ARRAY_SIZE(GunFlashFiles) +//(2) +#define MAX_RAINSPLASHUP_FILES ARRAY_SIZE(RainSplashupFiles) +//(4) +#define MAX_BIRDFRONT_FILES ARRAY_SIZE(BirdfrontFiles) +//(4) +#define MAX_CARDEBRIS_FILES ARRAY_SIZE(CardebrisFiles) +//(4) +#define MAX_CARSPLASH_FILES ARRAY_SIZE(CarsplashFiles) + +//(4) +#define MAX_RAINDROP_FILES ARRAY_SIZE(RaindropFiles) + + + +const Char SmokeFiles[][6+1] = { - EAXJMP(0x50D140); + "smoke1", + "smoke2", + "smoke3", + "smoke4", + "smoke5" +}; + + +const Char Smoke2Files[][9+1] = +{ + "smokeII_1", + "smokeII_2", + "smokeII_3", + "smokeII_4", + "smokeII_5" +}; + +const Char RubberFiles[][7+1] = +{ + "rubber1", + "rubber2", + "rubber3", + "rubber4", + "rubber5" +}; + +const Char RainSplashFiles[][7+1] = +{ + "splash1", + "splash2", + "splash3", + "splash4", + "splash5" +}; + +const Char WatersprayFiles[][11+1] = +{ + "waterspray1", + "waterspray2", + "waterspray3" +}; + +const Char ExplosionMediumFiles[][7+1] = +{ + "explo01", + "explo02", + "explo03", + "explo04", + "explo05", + "explo06" +}; + +const Char GunFlashFiles[][9+1] = +{ + "gunflash1", + "gunflash2", + "gunflash3", + "gunflash4" +}; + +const Char RaindropFiles[][9+1] = +{ + "raindrop1", + "raindrop2", + "raindrop3", + "raindrop4" +}; + +const Char RainSplashupFiles[][10+1] = +{ + "splash_up1", + "splash_up2" +}; + +const Char BirdfrontFiles[][8+1] = +{ + "birdf_01", + "birdf_02", + "birdf_03", + "birdf_04" +}; + +const Char CardebrisFiles[][12+1] = +{ + "cardebris_01", + "cardebris_02", + "cardebris_03", + "cardebris_04" +}; + +const Char CarsplashFiles[][12+1] = +{ + "carsplash_01", + "carsplash_02", + "carsplash_03", + "carsplash_04" +}; + +CParticle gParticleArray[MAX_PARTICLES_ON_SCREEN]; + +RwTexture *gpSmokeTex[MAX_SMOKE_FILES]; +RwTexture *gpSmoke2Tex[MAX_SMOKE2_FILES]; +RwTexture *gpRubberTex[MAX_RUBBER_FILES]; +RwTexture *gpRainSplashTex[MAX_RAINSPLASH_FILES]; +RwTexture *gpWatersprayTex[MAX_WATERSPRAY_FILES]; +RwTexture *gpExplosionMediumTex[MAX_EXPLOSIONMEDIUM_FILES]; +RwTexture *gpGunFlashTex[MAX_GUNFLASH_FILES]; +RwTexture *gpRainSplashupTex[MAX_RAINSPLASHUP_FILES]; +RwTexture *gpBirdfrontTex[MAX_BIRDFRONT_FILES]; +RwTexture *gpCarDebrisTex[MAX_CARDEBRIS_FILES]; +RwTexture *gpCarSplashTex[MAX_CARSPLASH_FILES]; + +RwTexture *gpFlame1Tex; +RwTexture *gpFlame5Tex; +RwTexture *gpRainDropSmallTex; +RwTexture *gpBloodTex; +RwTexture *gpLeafTex; +RwTexture *gpCloudTex1; // unused +RwTexture *gpCloudTex4; +RwTexture *gpBloodSmallTex; +RwTexture *gpGungeTex; +RwTexture *gpCollisionSmokeTex; +RwTexture *gpBulletHitTex; +RwTexture *gpGunShellTex; +RwTexture *gpWakeOldTex; +RwTexture *gpPointlightTex; + +RwRaster *gpSmokeRaster[MAX_SMOKE_FILES]; +RwRaster *gpSmoke2Raster[MAX_SMOKE2_FILES]; +RwRaster *gpRubberRaster[MAX_RUBBER_FILES]; +RwRaster *gpRainSplashRaster[MAX_RAINSPLASH_FILES]; +RwRaster *gpWatersprayRaster[MAX_WATERSPRAY_FILES]; +RwRaster *gpExplosionMediumRaster[MAX_EXPLOSIONMEDIUM_FILES]; +RwRaster *gpGunFlashRaster[MAX_GUNFLASH_FILES]; +RwRaster *gpRainSplashupRaster[MAX_RAINSPLASHUP_FILES]; +RwRaster *gpBirdfrontRaster[MAX_BIRDFRONT_FILES]; +RwRaster *gpCarDebrisRaster[MAX_CARDEBRIS_FILES]; +RwRaster *gpCarSplashRaster[MAX_CARSPLASH_FILES]; + +RwRaster *gpFlame1Raster; +RwRaster *gpFlame5Raster; +RwRaster *gpRainDropSmallRaster; +RwRaster *gpBloodRaster; +RwRaster *gpLeafRaster; +RwRaster *gpCloudRaster1; // unused +RwRaster *gpCloudRaster4; +RwRaster *gpBloodSmallRaster; +RwRaster *gpGungeRaster; +RwRaster *gpCollisionSmokeRaster; +RwRaster *gpBulletHitRaster; +RwRaster *gpGunShellRaster; +RwRaster *gpWakeOldRaster; + + +//RwRaster *gpPointlightRaster; // CPointLights::RenderFogEffect +RwRaster *&gpPointlightRaster = *(RwRaster **)0x8F5FE0; + +//RwTexture *gpRainDropTex[MAX_RAINDROP_FILES]; // CWeather::RenderRainStreaks +RwTexture * (&gpRainDropTex)[MAX_RAINDROP_FILES] = *(RwTexture * (*)[MAX_RAINDROP_FILES])*(int *)0x880660; + + +RwRaster *gpRainDropRaster[MAX_RAINDROP_FILES]; + +//Float CParticle::ms_afRandTable[CParticle::RAND_TABLE_SIZE]; // +Float (&CParticle::ms_afRandTable)[CParticle::RAND_TABLE_SIZE] = *(Float (*)[CParticle::RAND_TABLE_SIZE])*(int *)0x6E9878; + + +CParticle *CParticle::m_pUnusedListHead; + + +//Float CParticle::m_SinTable[CParticle::SIN_COS_TABLE_SIZE]; // +//Float CParticle::m_CosTable[CParticle::SIN_COS_TABLE_SIZE]; / +Float (&CParticle::m_SinTable)[CParticle::SIN_COS_TABLE_SIZE] = *(Float (*)[CParticle::SIN_COS_TABLE_SIZE])*(int *)0x877358; +Float (&CParticle::m_CosTable)[CParticle::SIN_COS_TABLE_SIZE] = *(Float (*)[CParticle::SIN_COS_TABLE_SIZE])*(int *)0x70DA18; + +Int32 Randomizer; + +Int32 nParticleCreationInterval = 1; +Float fParticleScaleLimit = 0.5f; + + + +RwTexture *&gpBloodPoolTex = *(RwTexture **)0x9415F8; + + +void CParticle::ReloadConfig() +{ + debug("Initialising CParticleMgr..."); + + mod_ParticleSystemManager.Initialise(); + + debug("Initialising CParticle..."); + + m_pUnusedListHead = gParticleArray; + + for ( Int32 i = 0; i < MAX_PARTICLES_ON_SCREEN; i++ ) + { + if ( i == MAX_PARTICLES_ON_SCREEN - 1 ) + gParticleArray[i].m_pNext = NULL; + else + gParticleArray[i].m_pNext = &gParticleArray[i + 1]; + + gParticleArray[i].m_vecPosition = CVector(0.0f, 0.0f, 0.0f); + + gParticleArray[i].m_vecVelocity = CVector(0.0f, 0.0f, 0.0f); + + gParticleArray[i].m_nTimeWhenWillBeDestroyed = 0; + + gParticleArray[i].m_nTimeWhenColorWillBeChanged = 0; + + gParticleArray[i].m_fSize = 0.2f; + + gParticleArray[i].m_fExpansionRate = 0.0f; + + gParticleArray[i].m_nColorIntensity = 255; + + gParticleArray[i].m_nFadeToBlackTimer = 0; + + gParticleArray[i].m_nAlpha = 255; + + gParticleArray[i].m_nFadeAlphaTimer = 0; + + gParticleArray[i].m_nCurrentZRotation = 0; + + gParticleArray[i].m_nZRotationTimer = 0; + + gParticleArray[i].m_fCurrentZRadius = 0.0f; + + gParticleArray[i].m_nZRadiusTimer = 0; + + gParticleArray[i].m_nCurrentFrame = 0; + + gParticleArray[i].m_nAnimationSpeedTimer = 0; + + gParticleArray[i].m_nRotation = 0; + + gParticleArray[i].m_nRotationStep = 0; + } } + +void CParticle::Initialise() +{ + ReloadConfig(); + + CParticleObject::Initialise(); + + Float randVal = -1.0f; + for ( Int32 i = 0; i < RAND_TABLE_SIZE; i++ ) + { + ms_afRandTable[i] = randVal; + randVal += 0.1f; + } + + for ( Int32 i = 0; i < SIN_COS_TABLE_SIZE; i++ ) + { + Float angle = DEGTORAD(Float(i) * Float(360.0f / SIN_COS_TABLE_SIZE)); + + m_SinTable[i] = sin(angle); + m_CosTable[i] = cos(angle); + } + + Int32 slot = CTxdStore::FindTxdSlot("particle"); + + CTxdStore::PushCurrentTxd(); + CTxdStore::SetCurrentTxd(slot); + + for ( Int32 i = 0; i < MAX_SMOKE_FILES; i++ ) + { + gpSmokeTex[i] = RwTextureRead(SmokeFiles[i], NULL); + gpSmokeRaster[i] = RwTextureGetRaster(gpSmokeTex[i]); + } + + for ( Int32 i = 0; i < MAX_SMOKE2_FILES; i++ ) + { + gpSmoke2Tex[i] = RwTextureRead(Smoke2Files[i], NULL); + gpSmoke2Raster[i] = RwTextureGetRaster(gpSmoke2Tex[i]); + } + + for ( Int32 i = 0; i < MAX_RUBBER_FILES; i++ ) + { + gpRubberTex[i] = RwTextureRead(RubberFiles[i], NULL); + gpRubberRaster[i] = RwTextureGetRaster(gpRubberTex[i]); + } + + for ( Int32 i = 0; i < MAX_RAINSPLASH_FILES; i++ ) + { + gpRainSplashTex[i] = RwTextureRead(RainSplashFiles[i], NULL); + gpRainSplashRaster[i] = RwTextureGetRaster(gpRainSplashTex[i]); + } + + for ( Int32 i = 0; i < MAX_WATERSPRAY_FILES; i++ ) + { + gpWatersprayTex[i] = RwTextureRead(WatersprayFiles[i], NULL); + gpWatersprayRaster[i] = RwTextureGetRaster(gpWatersprayTex[i]); + } + + for ( Int32 i = 0; i < MAX_EXPLOSIONMEDIUM_FILES; i++ ) + { + gpExplosionMediumTex[i] = RwTextureRead(ExplosionMediumFiles[i], NULL); + gpExplosionMediumRaster[i] = RwTextureGetRaster(gpExplosionMediumTex[i]); + } + + for ( Int32 i = 0; i < MAX_GUNFLASH_FILES; i++ ) + { + gpGunFlashTex[i] = RwTextureRead(GunFlashFiles[i], NULL); + gpGunFlashRaster[i] = RwTextureGetRaster(gpGunFlashTex[i]); + } + + for ( Int32 i = 0; i < MAX_RAINDROP_FILES; i++ ) + { + gpRainDropTex[i] = RwTextureRead(RaindropFiles[i], NULL); + gpRainDropRaster[i] = RwTextureGetRaster(gpRainDropTex[i]); + } + + for ( Int32 i = 0; i < MAX_RAINSPLASHUP_FILES; i++ ) + { + gpRainSplashupTex[i] = RwTextureRead(RainSplashupFiles[i], NULL); + gpRainSplashupRaster[i] = RwTextureGetRaster(gpRainSplashupTex[i]); + } + + for ( Int32 i = 0; i < MAX_BIRDFRONT_FILES; i++ ) + { + gpBirdfrontTex[i] = RwTextureRead(BirdfrontFiles[i], NULL); + gpBirdfrontRaster[i] = RwTextureGetRaster(gpBirdfrontTex[i]); + } + + for ( Int32 i = 0; i < MAX_CARDEBRIS_FILES; i++ ) + { + gpCarDebrisTex[i] = RwTextureRead(CardebrisFiles[i], NULL); + gpCarDebrisRaster[i] = RwTextureGetRaster(gpCarDebrisTex[i]); + } + + for ( Int32 i = 0; i < MAX_CARSPLASH_FILES; i++ ) + { + gpCarSplashTex[i] = RwTextureRead(CarsplashFiles[i], NULL); + gpCarSplashRaster[i] = RwTextureGetRaster(gpCarSplashTex[i]); + } + + gpFlame1Tex = RwTextureRead("flame1", NULL); + gpFlame1Raster = RwTextureGetRaster(gpFlame1Tex); + + gpFlame5Tex = RwTextureRead("flame5", NULL); + + gpFlame5Raster = RwTextureGetRaster(gpFlame1Tex); // copy-paste bug ? + + gpRainDropSmallTex = RwTextureRead("rainsmall", NULL); + gpRainDropSmallRaster = RwTextureGetRaster(gpRainDropSmallTex); + + gpBloodTex = RwTextureRead("blood", NULL); + gpBloodRaster = RwTextureGetRaster(gpBloodTex); + + gpLeafTex = RwTextureRead("gameleaf01_64", NULL); + gpLeafRaster = RwTextureGetRaster(gpLeafTex); + + gpCloudTex1 = RwTextureRead("cloud3", NULL); + gpCloudRaster1 = RwTextureGetRaster(gpCloudTex1); + + gpCloudTex4 = RwTextureRead("cloudmasked", NULL); + gpCloudRaster4 = RwTextureGetRaster(gpCloudTex4); + + gpBloodSmallTex = RwTextureRead("bloodsplat2", NULL); + gpBloodSmallRaster = RwTextureGetRaster(gpBloodSmallTex); + + gpGungeTex = RwTextureRead("gunge", NULL); + gpGungeRaster = RwTextureGetRaster(gpGungeTex); + + gpCollisionSmokeTex = RwTextureRead("collisionsmoke", NULL); + gpCollisionSmokeRaster = RwTextureGetRaster(gpCollisionSmokeTex); + + gpBulletHitTex = RwTextureRead("bullethitsmoke", NULL); + gpBulletHitRaster = RwTextureGetRaster(gpBulletHitTex); + + gpGunShellTex = RwTextureRead("gunshell", NULL); + gpGunShellRaster = RwTextureGetRaster(gpGunShellTex); + + gpWakeOldTex = RwTextureRead("wake_old", NULL); + gpWakeOldRaster = RwTextureGetRaster(gpWakeOldTex); + + gpPointlightTex = RwTextureRead("pointlight", NULL); + gpPointlightRaster = RwTextureGetRaster(gpPointlightTex); + + CTxdStore::PopCurrentTxd(); + + for ( Int32 i = 0; i < MAX_PARTICLES; i++ ) + { + tParticleSystemData *entry = &mod_ParticleSystemManager.m_aParticles[i]; + + switch ( i ) + { + case PARTICLE_BLOOD: + entry->m_ppRaster = &gpBloodRaster; + break; + + case PARTICLE_BLOOD_SMALL: + case PARTICLE_BLOOD_SPURT: + entry->m_ppRaster = &gpBloodSmallRaster; + break; + + case PARTICLE_DEBRIS2: + entry->m_ppRaster = &gpGungeRaster; + break; + + case PARTICLE_GUNFLASH: + case PARTICLE_GUNFLASH_NOANIM: + entry->m_ppRaster = gpGunFlashRaster; + break; + + case PARTICLE_GUNSMOKE: + case PARTICLE_SPLASH: + entry->m_ppRaster = NULL; + break; + + case PARTICLE_FLAME: + case PARTICLE_CARFLAME: + entry->m_ppRaster = &gpFlame1Raster; + break; + + case PARTICLE_FIREBALL: + entry->m_ppRaster = &gpFlame5Raster; + break; + + case PARTICLE_RAIN_SPLASH: + case PARTICLE_RAIN_SPLASH_BIGGROW: + entry->m_ppRaster = gpRainSplashRaster; + break; + + case PARTICLE_RAIN_SPLASHUP: + entry->m_ppRaster = gpRainSplashupRaster; + break; + + case PARTICLE_WATERSPRAY: + entry->m_ppRaster = gpWatersprayRaster; + break; + + case PARTICLE_SHARD: + case PARTICLE_RAINDROP: + case PARTICLE_RAINDROP_2D: + entry->m_ppRaster = gpRainDropRaster; + break; + + case PARTICLE_EXPLOSION_MEDIUM: + case PARTICLE_EXPLOSION_LARGE: + case PARTICLE_EXPLOSION_MFAST: + case PARTICLE_EXPLOSION_LFAST: + entry->m_ppRaster = gpExplosionMediumRaster; + break; + + case PARTICLE_BOAT_WAKE: + entry->m_ppRaster = &gpWakeOldRaster; + break; + + case PARTICLE_CAR_SPLASH: + case PARTICLE_WATER_HYDRANT: + case PARTICLE_PED_SPLASH: + entry->m_ppRaster = gpCarSplashRaster; + break; + + case PARTICLE_SPARK: + case PARTICLE_SPARK_SMALL: + case PARTICLE_RAINDROP_SMALL: + case PARTICLE_HELI_ATTACK: + entry->m_ppRaster = &gpRainDropSmallRaster; + break; + + case PARTICLE_DEBRIS: + case PARTICLE_TREE_LEAVES: + entry->m_ppRaster = &gpLeafRaster; + break; + + case PARTICLE_CAR_DEBRIS: + case PARTICLE_HELI_DEBRIS: + entry->m_ppRaster = gpCarDebrisRaster; + break; + + case PARTICLE_WHEEL_DIRT: + case PARTICLE_STEAM2: + case PARTICLE_STEAM_NY: + case PARTICLE_STEAM_NY_SLOWMOTION: + case PARTICLE_ENGINE_STEAM: + case PARTICLE_BOAT_THRUSTJET: + case PARTICLE_PEDFOOT_DUST: + case PARTICLE_EXHAUST_FUMES: + entry->m_ppRaster = gpSmoke2Raster; + break; + + case PARTICLE_GUNSMOKE2: + case PARTICLE_RUBBER_SMOKE: + entry->m_ppRaster = gpRubberRaster; + break; + + case PARTICLE_CARCOLLISION_DUST: + case PARTICLE_BURNINGRUBBER_SMOKE: + entry->m_ppRaster = &gpCollisionSmokeRaster; + break; + + case PARTICLE_WHEEL_WATER: + case PARTICLE_WATER: + case PARTICLE_SMOKE: + case PARTICLE_SMOKE_SLOWMOTION: + case PARTICLE_GARAGEPAINT_SPRAY: + case PARTICLE_STEAM: + case PARTICLE_BOAT_SPLASH: + case PARTICLE_WATER_CANNON: + case PARTICLE_EXTINGUISH_STEAM: + case PARTICLE_HELI_DUST: + case PARTICLE_PAINT_SMOKE: + case PARTICLE_BULLETHIT_SMOKE: + entry->m_ppRaster = gpSmokeRaster; + break; + + case PARTICLE_GUNSHELL_FIRST: + case PARTICLE_GUNSHELL: + case PARTICLE_GUNSHELL_BUMP1: + case PARTICLE_GUNSHELL_BUMP2: + entry->m_ppRaster = &gpGunShellRaster; + break; + + case PARTICLE_ENGINE_SMOKE: + case PARTICLE_ENGINE_SMOKE2: + case PARTICLE_CARFLAME_SMOKE: + case PARTICLE_FIREBALL_SMOKE: + case PARTICLE_TEST: + entry->m_ppRaster = &gpCloudRaster4; + break; + + case PARTICLE_BIRD_FRONT: + entry->m_ppRaster = gpBirdfrontRaster; + break; + } + } + + debug("CParticle ready"); +} + +void CParticle::Shutdown() +{ + debug("Shutting down CParticle..."); + + for ( Int32 i = 0; i < MAX_SMOKE_FILES; i++ ) + { + RwTextureDestroy(gpSmokeTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpSmokeTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_SMOKE2_FILES; i++ ) + { + RwTextureDestroy(gpSmoke2Tex[i]); +#if GTA3_1_1_PATCH == TRUE + gpSmoke2Tex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_RUBBER_FILES; i++ ) + { + RwTextureDestroy(gpRubberTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpRubberTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_RAINSPLASH_FILES; i++ ) + { + RwTextureDestroy(gpRainSplashTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpRainSplashTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_WATERSPRAY_FILES; i++ ) + { + RwTextureDestroy(gpWatersprayTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpWatersprayTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_EXPLOSIONMEDIUM_FILES; i++ ) + { + RwTextureDestroy(gpExplosionMediumTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpExplosionMediumTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_GUNFLASH_FILES; i++ ) + { + RwTextureDestroy(gpGunFlashTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpGunFlashTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_RAINDROP_FILES; i++ ) + { + RwTextureDestroy(gpRainDropTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpRainDropTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_RAINSPLASHUP_FILES; i++ ) + { + RwTextureDestroy(gpRainSplashupTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpRainSplashupTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_BIRDFRONT_FILES; i++ ) + { + RwTextureDestroy(gpBirdfrontTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpBirdfrontTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_CARDEBRIS_FILES; i++ ) + { + RwTextureDestroy(gpCarDebrisTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpCarDebrisTex[i] = NULL; +#endif + } + + for ( Int32 i = 0; i < MAX_CARSPLASH_FILES; i++ ) + { + RwTextureDestroy(gpCarSplashTex[i]); +#if GTA3_1_1_PATCH == TRUE + gpCarSplashTex[i] = NULL; +#endif + } + + RwTextureDestroy(gpFlame1Tex); +#if GTA3_1_1_PATCH == TRUE + gpFlame1Tex = NULL; +#endif + + RwTextureDestroy(gpFlame5Tex); +#if GTA3_1_1_PATCH == TRUE + gpFlame5Tex = NULL; +#endif + + RwTextureDestroy(gpRainDropSmallTex); +#if GTA3_1_1_PATCH == TRUE + gpRainDropSmallTex = NULL; +#endif + + RwTextureDestroy(gpBloodTex); +#if GTA3_1_1_PATCH == TRUE + gpBloodTex = NULL; +#endif + + RwTextureDestroy(gpLeafTex); +#if GTA3_1_1_PATCH == TRUE + gpLeafTex = NULL; +#endif + + RwTextureDestroy(gpCloudTex1); +#if GTA3_1_1_PATCH == TRUE + gpCloudTex1 = NULL; +#endif + + RwTextureDestroy(gpCloudTex4); +#if GTA3_1_1_PATCH == TRUE + gpCloudTex4 = NULL; +#endif + + RwTextureDestroy(gpBloodSmallTex); +#if GTA3_1_1_PATCH == TRUE + gpBloodSmallTex = NULL; +#endif + + RwTextureDestroy(gpGungeTex); +#if GTA3_1_1_PATCH == TRUE + gpGungeTex = NULL; +#endif + + RwTextureDestroy(gpCollisionSmokeTex); +#if GTA3_1_1_PATCH == TRUE + gpCollisionSmokeTex = NULL; +#endif + + RwTextureDestroy(gpBulletHitTex); +#if GTA3_1_1_PATCH == TRUE + gpBulletHitTex = NULL; +#endif + + RwTextureDestroy(gpGunShellTex); +#if GTA3_1_1_PATCH == TRUE + gpGunShellTex = NULL; +#endif + + RwTextureDestroy(gpWakeOldTex); +#if GTA3_1_1_PATCH == TRUE + gpWakeOldTex = NULL; +#endif + + RwTextureDestroy(gpPointlightTex); +#if GTA3_1_1_PATCH == TRUE + gpPointlightTex = NULL; +#endif + + Int32 slot; + + slot = CTxdStore::FindTxdSlot("particle"); + CTxdStore::RemoveTxdSlot(slot); + + debug("CParticle shut down"); +} + +CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity, Float fSize, Int32 nRotationSpeed, Int32 nRotation, Int32 nCurFrame, Int32 nLifeSpan) +{ + CRGBA color(0, 0, 0, 0); + return AddParticle(type, vecPos, vecDir, pEntity, fSize, color, nRotationSpeed, nRotation, nCurFrame, nLifeSpan); +} + +CParticle *CParticle::AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity, Float fSize, RwRGBA const &color, Int32 nRotationSpeed, Int32 nRotation, Int32 nCurFrame, Int32 nLifeSpan) +{ + if ( CTimer::GetIsPaused() ) + return NULL; + + if ( ( type == PARTICLE_ENGINE_SMOKE + || type == PARTICLE_ENGINE_SMOKE2 + || type == PARTICLE_ENGINE_STEAM + || type == PARTICLE_CARFLAME_SMOKE + || type == PARTICLE_RUBBER_SMOKE + || type == PARTICLE_BURNINGRUBBER_SMOKE + || type == PARTICLE_EXHAUST_FUMES + || type == PARTICLE_CARCOLLISION_DUST ) + && nParticleCreationInterval & CTimer::GetFrameCounter() ) + { + return NULL; + } + + CParticle *pParticle = m_pUnusedListHead; + + if ( pParticle == NULL ) + return NULL; + + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[type]; + + if ( psystem->m_fCreateRange != 0.0f && psystem->m_fCreateRange < ( TheCamera.GetPosition() - vecPos ).MagnitudeSqr() ) + return NULL; + + + pParticle->m_fSize = psystem->m_fDefaultInitialRadius; + pParticle->m_fExpansionRate = psystem->m_fExpansionRate; + + if ( nLifeSpan != 0 ) + pParticle->m_nTimeWhenWillBeDestroyed = CTimer::GetTimeInMilliseconds() + nLifeSpan; + else + pParticle->m_nTimeWhenWillBeDestroyed = CTimer::GetTimeInMilliseconds() + psystem->m_nLifeSpan; + + pParticle->m_nColorIntensity = psystem->m_nFadeToBlackInitialIntensity; + pParticle->m_nAlpha = psystem->m_nFadeAlphaInitialIntensity; + pParticle->m_nCurrentZRotation = psystem->m_nZRotationInitialAngle; + pParticle->m_fCurrentZRadius = psystem->m_fInitialZRadius; + + if ( nCurFrame != 0 ) + pParticle->m_nCurrentFrame = nCurFrame; + else + pParticle->m_nCurrentFrame = psystem->m_nStartAnimationFrame; + + pParticle->m_nFadeToBlackTimer = 0; + pParticle->m_nFadeAlphaTimer = 0; + pParticle->m_nZRotationTimer = 0; + pParticle->m_nZRadiusTimer = 0; + pParticle->m_nAnimationSpeedTimer = 0; + pParticle->m_fZGround = 0.0f; + pParticle->m_vecPosition = vecPos; + pParticle->m_vecVelocity = vecDir; + pParticle->m_vecParticleMovementOffset = CVector(0.0f, 0.0f, 0.0f); + pParticle->m_nTimeWhenColorWillBeChanged = 0; + + if ( color.alpha != 0 ) + RwRGBAAssign(&pParticle->m_Color, &color); + else + { + RwRGBAAssign(&pParticle->m_Color, &psystem->m_RenderColouring); + + if ( psystem->m_ColorFadeTime != 0 ) + pParticle->m_nTimeWhenColorWillBeChanged = CTimer::GetTimeInMilliseconds() + psystem->m_ColorFadeTime; + + if ( psystem->m_InitialColorVariation != 0 ) + { + Int32 ColorVariation = CGeneral::GetRandomNumberInRange(-psystem->m_InitialColorVariation, psystem->m_InitialColorVariation); + //Float ColorVariation = CGeneral::GetRandomNumberInRange((Float)-psystem->m_InitialColorVariation, (Float)psystem->m_InitialColorVariation); + + pParticle->m_Color.red = clamp(pParticle->m_Color.red + + PERCENT(pParticle->m_Color.red, ColorVariation), + 0, 255); + + pParticle->m_Color.green = clamp(pParticle->m_Color.green + + PERCENT(pParticle->m_Color.green, ColorVariation), + 0, 255); + + pParticle->m_Color.blue = clamp(pParticle->m_Color.blue + + PERCENT(pParticle->m_Color.blue, ColorVariation), + 0, 255); + } + } + + pParticle->m_nRotation = nRotation; + + if ( pParticle->m_nRotation >= 360 ) + pParticle->m_nRotation -= 360; + else if ( pParticle->m_nRotation < 0 ) + pParticle->m_nRotation += 360; + + if ( nRotationSpeed != 0 ) + pParticle->m_nRotationStep = nRotationSpeed; + else + pParticle->m_nRotationStep = psystem->m_nRotationSpeed; + + if ( CGeneral::GetRandomNumber() & 1 ) + pParticle->m_nRotationStep = -pParticle->m_nRotationStep; + + pParticle->m_vecScreenPosition.x = 0.0f; // bug ? + + if ( psystem->m_fPositionRandomError != 0.0f ) + { + pParticle->m_vecPosition.x += psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + pParticle->m_vecPosition.y += psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + + if ( psystem->Flags & RAND_VERT_V ) + pParticle->m_vecPosition.z += psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + } + + if ( psystem->m_fVelocityRandomError != 0.0f ) + { + pParticle->m_vecVelocity.x += psystem->m_fVelocityRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + pParticle->m_vecVelocity.y += psystem->m_fVelocityRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + + if ( psystem->Flags & RAND_VERT_V ) + pParticle->m_vecVelocity.z += psystem->m_fVelocityRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + } + + if ( psystem->m_fExpansionRateError != 0.0f ) + pParticle->m_fExpansionRate += psystem->m_fExpansionRateError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE] + psystem->m_fExpansionRateError; + + if ( psystem->m_nRotationRateError != 0 ) + pParticle->m_nRotationStep += CGeneral::GetRandomNumberInRange(-psystem->m_nRotationRateError, psystem->m_nRotationRateError); + + if ( psystem->m_nLifeSpanErrorShape != 0 ) + { + Float randVal = ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + if ( randVal > 0.0f ) + pParticle->m_nTimeWhenWillBeDestroyed += Int32(Float(psystem->m_nLifeSpan) * randVal * Float(psystem->m_nLifeSpanErrorShape)); + else + pParticle->m_nTimeWhenWillBeDestroyed += Int32(Float(psystem->m_nLifeSpan) * randVal / Float(psystem->m_nLifeSpanErrorShape)); + } + + if ( psystem->Flags & ZCHECK_FIRST ) + { + static Bool bValidGroundFound = false; + static CVector LastTestCoors; + static Float LastTestGroundZ; + + if ( bValidGroundFound + && vecPos.x == LastTestCoors.x + && vecPos.y == LastTestCoors.y + && vecPos.z == LastTestCoors.z ) + { + pParticle->m_fZGround = LastTestGroundZ; + } + else + { + bValidGroundFound = false; + + CColPoint point; + CEntity *entity; + + if ( !CWorld::ProcessVerticalLine( + pParticle->m_vecPosition + CVector(0.0f, 0.0f, 0.5f), + -100.0f, point, entity, true, true, false, false, true, false, NULL) ) + { + return NULL; + } + + if ( point.point.z >= pParticle->m_vecPosition.z ) + return NULL; + + pParticle->m_fZGround = point.point.z; + bValidGroundFound = true; + LastTestCoors = vecPos; + LastTestGroundZ = point.point.z; + } + } + + if ( psystem->Flags & ZCHECK_BUMP ) + { + static Float Z_Ground = 0.0f; + + if ( psystem->Flags & ZCHECK_BUMP_FIRST ) + { + Bool bZFound = false; + + Z_Ground = CWorld::FindGroundZFor3DCoord(vecPos.x, vecPos.y, vecPos.z, (bool *)&bZFound); + + if ( bZFound == false ) + return NULL; + + pParticle->m_fZGround = Z_Ground; + } + + pParticle->m_fZGround = Z_Ground; + } + + switch ( type ) + { + case PARTICLE_DEBRIS: + pParticle->m_vecVelocity.z *= CGeneral::GetRandomNumberInRange(0.5f, 3.0f); + break; + + case PARTICLE_EXPLOSION_MEDIUM: + pParticle->m_nColorIntensity -= 30 * (CGeneral::GetRandomNumber() & 1); // mb "+= -30 * rand" here ? + pParticle->m_nAnimationSpeedTimer = CGeneral::GetRandomNumber() & 7; + pParticle->m_fSize = CGeneral::GetRandomNumberInRange(0.3f, 0.8f); + pParticle->m_vecPosition.z -= CGeneral::GetRandomNumberInRange(-0.1f, 0.1f); + break; + + case PARTICLE_EXPLOSION_LARGE: + pParticle->m_nColorIntensity -= 30 * (CGeneral::GetRandomNumber() & 1); // mb "+= -30 * rand" here ? + pParticle->m_nAnimationSpeedTimer = CGeneral::GetRandomNumber() & 7; + pParticle->m_fSize = CGeneral::GetRandomNumberInRange(0.8f, 1.4f); + pParticle->m_vecPosition.z -= CGeneral::GetRandomNumberInRange(-0.3f, 0.3f); + break; + + case PARTICLE_WATER_HYDRANT: + pParticle->m_vecPosition.z += 20.0f * psystem->m_fPositionRandomError * ms_afRandTable[CGeneral::GetRandomNumber() % RAND_TABLE_SIZE]; + break; + } + + if ( fSize != 0.0f ) + pParticle->m_fSize = fSize; + + m_pUnusedListHead = pParticle->m_pNext; + + pParticle->m_pNext = psystem->m_pParticles; + + psystem->m_pParticles = pParticle; + + return pParticle; +} + +void CParticle::Update() +{ + if ( CTimer::GetIsPaused() ) + return; + + CRGBA color(0, 0, 0, 0); + + Float fFricDeccel50 = pow(0.50f, CTimer::GetTimeStep()); + Float fFricDeccel80 = pow(0.80f, CTimer::GetTimeStep()); + Float fFricDeccel90 = pow(0.90f, CTimer::GetTimeStep()); + Float fFricDeccel95 = pow(0.95f, CTimer::GetTimeStep()); + Float fFricDeccel96 = pow(0.96f, CTimer::GetTimeStep()); + Float fFricDeccel99 = pow(0.99f, CTimer::GetTimeStep()); + + CParticleObject::UpdateAll(); + + for ( Int32 i = 0; i < MAX_PARTICLES; i++ ) + { + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[i]; + CParticle *particle = psystem->m_pParticles; + CParticle *prevParticle = NULL; + Bool bRemoveParticle; + + if ( particle == NULL ) + continue; + + for ( ; particle != NULL; _Next(particle, prevParticle, psystem, bRemoveParticle) ) + { + bRemoveParticle = false; + + CVector moveStep = particle->m_vecPosition + ( particle->m_vecVelocity * CTimer::GetTimeStep() ); + + if ( CTimer::GetTimeInMilliseconds() > particle->m_nTimeWhenWillBeDestroyed || particle->m_nAlpha == 0 ) + { + bRemoveParticle = true; + continue; + } + + if ( particle->m_nTimeWhenColorWillBeChanged != 0 ) + { + if ( particle->m_nTimeWhenColorWillBeChanged > CTimer::GetTimeInMilliseconds() ) + { + Float colorMul = 1.0f - Float(particle->m_nTimeWhenColorWillBeChanged - CTimer::GetTimeInMilliseconds()) / Float(psystem->m_ColorFadeTime); + + particle->m_Color.red = clamp( + psystem->m_RenderColouring.red + Int32(Float(psystem->m_FadeDestinationColor.red - psystem->m_RenderColouring.red) * colorMul), + 0, 255); + + particle->m_Color.green = clamp( + psystem->m_RenderColouring.green + Int32(Float(psystem->m_FadeDestinationColor.green - psystem->m_RenderColouring.green) * colorMul), + 0, 255); + + particle->m_Color.blue = clamp( + psystem->m_RenderColouring.blue + Int32(Float(psystem->m_FadeDestinationColor.blue - psystem->m_RenderColouring.blue) * colorMul), + 0, 255); + } + else + RwRGBAAssign(&particle->m_Color, &psystem->m_FadeDestinationColor); + } + + if ( psystem->Flags & CLIPOUT2D ) + { + if ( particle->m_vecPosition.x < -10.0f || particle->m_vecPosition.x > SCREEN_WIDTH + 10.0f + || particle->m_vecPosition.y < -10.0f || particle->m_vecPosition.y > SCREEN_HEIGHT + 10.0f ) + { + bRemoveParticle = true; + continue; + } + } + + Float size = particle->m_fSize + particle->m_fExpansionRate; + + if ( size < 0.0f ) + { + bRemoveParticle = true; + continue; + } + + particle->m_fSize = size; + + switch ( psystem->m_nFrictionDecceleration ) + { + case 50: + particle->m_vecVelocity *= fFricDeccel50; + break; + + case 80: + particle->m_vecVelocity *= fFricDeccel80; + break; + + case 90: + particle->m_vecVelocity *= fFricDeccel90; + break; + + case 95: + particle->m_vecVelocity *= fFricDeccel95; + break; + + case 96: + particle->m_vecVelocity *= fFricDeccel96; + break; + + case 99: + particle->m_vecVelocity *= fFricDeccel99; + break; + } + + if ( psystem->m_fGravitationalAcceleration > 0.0f ) + { + if ( -50.0f * psystem->m_fGravitationalAcceleration < particle->m_vecVelocity.z ) + particle->m_vecVelocity.z -= psystem->m_fGravitationalAcceleration * CTimer::GetTimeStep(); + + if ( psystem->Flags & ZCHECK_FIRST ) + { + if ( particle->m_vecPosition.z < particle->m_fZGround ) + { + switch ( psystem->m_Type ) + { + case PARTICLE_RAINDROP: + case PARTICLE_RAINDROP_SMALL: + { + bRemoveParticle = true; + + if ( CGeneral::GetRandomNumber() & 1 ) + { + AddParticle(PARTICLE_RAIN_SPLASH, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), NULL, 0.0f, 0, 0, 0, 0); + } + else + { + AddParticle(PARTICLE_RAIN_SPLASHUP, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), NULL, 0.0f, 0, 0, 0, 0); + } + + continue; + } + break; + + case PARTICLE_WHEEL_WATER: + { + bRemoveParticle = true; + + Int32 randVal = Int32(CGeneral::GetRandomNumber()); + + if ( randVal & 1 ) + { + if ( (randVal % 5) == 0 ) + { + AddParticle(PARTICLE_RAIN_SPLASH, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), NULL, 0.0f, 0, 0, 0, 0); + } + else + { + AddParticle(PARTICLE_RAIN_SPLASHUP, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, 0.0f), NULL, 0.0f, 0, 0, 0, 0); + } + + } + continue; + } + break; + + case PARTICLE_BLOOD: + case PARTICLE_BLOOD_SMALL: + { + bRemoveParticle = true; + + CVector vecPosn = particle->m_vecPosition; + vecPosn.z += 1.0f; + + Randomizer++; + Int32 randVal = Int32(Randomizer & 7); + + if ( randVal == 5 ) + { + Int32 randTime = Int32(CGeneral::GetRandomNumber()); + + CShadows::AddPermanentShadow(1, gpBloodPoolTex, &vecPosn, + 0.1f, 0.0f, 0.0f, -0.1f, + 255, + 255, 0, 0, + 4.0f, (randTime & 0xFFF) + 2000, 1.0f); + } + else if ( randVal == 2 ) + { + Int32 randTime = Int32(CGeneral::GetRandomNumber()); + + CShadows::AddPermanentShadow(1, gpBloodPoolTex, &vecPosn, + 0.2f, 0.0f, 0.0f, -0.2f, + 255, + 255, 0, 0, + 4.0f, (randTime & 0xFFF) + 8000, 1.0f); + } + continue; + } + break; + } + } + } + else if ( psystem->Flags & ZCHECK_STEP ) + { + CColPoint point; + CEntity *entity; + + if ( CWorld::ProcessVerticalLine(particle->m_vecPosition, moveStep.z, point, entity, + true, true, false, false, true, false, NULL) ) + { + if ( moveStep.z <= point.point.z ) + { + moveStep.z = point.point.z; + if ( psystem->m_Type == PARTICLE_DEBRIS2 ) + { + particle->m_vecVelocity *= CVector(0.8f, 0.8f, -0.4f); + if ( particle->m_vecVelocity.z < 0.005f ) + particle->m_vecVelocity.z = 0.0f; + } + } + } + } + else if ( psystem->Flags & ZCHECK_BUMP ) + { + if ( particle->m_vecPosition.z < particle->m_fZGround ) + { + switch ( psystem->m_Type ) + { + case PARTICLE_GUNSHELL_FIRST: + case PARTICLE_GUNSHELL: + { + bRemoveParticle = true; + + AddParticle(PARTICLE_GUNSHELL_BUMP1, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector + ( + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(-0.02f, 0.02f), + CGeneral::GetRandomNumberInRange(0.05f, 0.1f) + ), + NULL, + particle->m_fSize, color, particle->m_nRotationStep, 0, 0, 0); + + PlayOneShotScriptObject(_SOUND_BULLET_SHELL_HIT_GROUND_1, particle->m_vecPosition); + } + break; + + case PARTICLE_GUNSHELL_BUMP1: + { + bRemoveParticle = true; + + AddParticle(PARTICLE_GUNSHELL_BUMP2, + CVector + ( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + 0.05f + particle->m_fZGround + ), + CVector(0.0f, 0.0f, CGeneral::GetRandomNumberInRange(0.03f, 0.06f)), + NULL, + particle->m_fSize, color, 0, 0, 0, 0); + + PlayOneShotScriptObject(_SOUND_BULLET_SHELL_HIT_GROUND_2, particle->m_vecPosition); + } + break; + + case PARTICLE_GUNSHELL_BUMP2: + { + bRemoveParticle = true; + continue; + } + break; + } + } + } + } + else + { + if ( psystem->m_fGravitationalAcceleration < 0.0f ) + { + if ( -5.0f * psystem->m_fGravitationalAcceleration > particle->m_vecVelocity.z ) + particle->m_vecVelocity.z -= psystem->m_fGravitationalAcceleration * CTimer::GetTimeStep(); + } + else + { + if ( psystem->Flags & ZCHECK_STEP ) + { + CColPoint point; + CEntity *entity; + + if ( CWorld::ProcessVerticalLine(particle->m_vecPosition, moveStep.z, point, entity, + true, false, false, false, true, false, NULL) ) + { + if ( moveStep.z <= point.point.z ) + { + moveStep.z = point.point.z; + if ( psystem->m_Type == PARTICLE_HELI_ATTACK ) + { + bRemoveParticle = true; + AddParticle(PARTICLE_STEAM, moveStep, CVector(0.0f, 0.0f, 0.05f), NULL, 0.2f, 0, 0, 0, 0); + continue; + } + } + } + } + } + } + + if ( psystem->m_nFadeToBlackAmount != 0 ) + { + if ( particle->m_nFadeToBlackTimer >= psystem->m_nFadeToBlackTime ) + { + particle->m_nFadeToBlackTimer = 0; + + particle->m_nColorIntensity = clamp(particle->m_nColorIntensity - psystem->m_nFadeToBlackAmount, + 0, 255); + } + else + ++particle->m_nFadeToBlackTimer; + } + + if ( psystem->m_nFadeAlphaAmount != 0 ) + { + if ( particle->m_nFadeAlphaTimer >= psystem->m_nFadeAlphaTime ) + { + particle->m_nFadeAlphaTimer = 0; + + particle->m_nAlpha = clamp(particle->m_nAlpha - psystem->m_nFadeAlphaAmount, + 0, 255); + + if ( particle->m_nAlpha == 0 ) + { + bRemoveParticle = true; + continue; + } + } + else + ++particle->m_nFadeAlphaTimer; + } + + if ( psystem->m_nZRotationAngleChangeAmount != 0 ) + { + if ( particle->m_nZRotationTimer >= psystem->m_nZRotationChangeTime ) + { + particle->m_nZRotationTimer = 0; + particle->m_nCurrentZRotation += psystem->m_nZRotationAngleChangeAmount; + } + else + ++particle->m_nZRotationTimer; + } + + if ( psystem->m_fZRadiusChangeAmount != 0.0f ) + { + if ( particle->m_nZRadiusTimer >= psystem->m_nZRadiusChangeTime ) + { + particle->m_nZRadiusTimer = 0; + particle->m_fCurrentZRadius += psystem->m_fZRadiusChangeAmount; + } + else + ++particle->m_nZRadiusTimer; + } + + if ( psystem->m_nAnimationSpeed != 0 ) + { + if ( particle->m_nAnimationSpeedTimer > psystem->m_nAnimationSpeed ) + { + particle->m_nAnimationSpeedTimer = 0; + + if ( ++particle->m_nCurrentFrame > psystem->m_nFinalAnimationFrame ) + { + if ( psystem->Flags & CYCLE_ANIM ) + particle->m_nCurrentFrame = psystem->m_nStartAnimationFrame; + else + --particle->m_nCurrentFrame; + } + } + else + ++particle->m_nAnimationSpeedTimer; + } + + if ( particle->m_nRotationStep != 0 ) + { + particle->m_nRotation += particle->m_nRotationStep; + + if ( particle->m_nRotation >= 360 ) + particle->m_nRotation -= 360; + else if ( particle->m_nRotation < 0 ) + particle->m_nRotation += 360; + } + + if ( particle->m_fCurrentZRadius != 0.0f ) + { + Int32 nSinCosIndex = particle->m_nCurrentZRotation % (SIN_COS_TABLE_SIZE - 1); + + Float fX = (m_CosTable[nSinCosIndex] - m_SinTable[nSinCosIndex]) + * particle->m_fCurrentZRadius; + + Float fY = (m_SinTable[nSinCosIndex] + m_CosTable[nSinCosIndex]) + * particle->m_fCurrentZRadius; + + moveStep -= particle->m_vecParticleMovementOffset; + + moveStep += CVector(fX, fY, 0.0f); + + particle->m_vecParticleMovementOffset = CVector(fX, fY, 0.0f); + } + + particle->m_vecPosition = moveStep; + } + } +} + +void CParticle::Render() +{ + RwRenderStateSet(rwRENDERSTATETEXTUREADDRESS, (void *)rwTEXTUREADDRESSWRAP); + RwRenderStateSet(rwRENDERSTATETEXTUREPERSPECTIVE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + + CSprite::InitSpriteBuffer2D(); + + UInt32 flags = DRAW_OPAQUE; + + RwRaster *prevFrame = NULL; + + for ( Int32 i = 0; i < MAX_PARTICLES; i++ ) + { + tParticleSystemData *psystem = &mod_ParticleSystemManager.m_aParticles[i]; + + Bool particleBanned = false; + + CParticle *particle = psystem->m_pParticles; + + RwRaster **frames = psystem->m_ppRaster; + + tParticleType type = psystem->m_Type; + + if ( type == PARTICLE_ENGINE_SMOKE + || type == PARTICLE_ENGINE_SMOKE2 + || type == PARTICLE_ENGINE_STEAM + || type == PARTICLE_CARFLAME_SMOKE + || type == PARTICLE_RUBBER_SMOKE + || type == PARTICLE_BURNINGRUBBER_SMOKE + || type == PARTICLE_EXHAUST_FUMES + || type == PARTICLE_CARCOLLISION_DUST ) + { + particleBanned = true; + } + + if ( particle ) + { + if ( (flags & DRAW_OPAQUE) != (psystem->Flags & DRAW_OPAQUE) + || (flags & DRAW_DARK) != (psystem->Flags & DRAW_DARK) ) + { + CSprite::FlushSpriteBuffer(); + + if ( psystem->Flags & DRAW_OPAQUE ) + { + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); + } + else + { + if ( psystem->Flags & DRAW_DARK ) + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + else + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDONE); + + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDONE); + } + + flags = psystem->Flags; + } + + if ( frames != NULL ) + { + RwRaster *curFrame = *frames; + if ( curFrame != prevFrame ) + { + CSprite::FlushSpriteBuffer(); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)curFrame); + prevFrame = curFrame; + } + } + } + + while ( particle != NULL ) + { + Bool canDraw = true; + + if ( particle->m_nAlpha == 0 ) + canDraw = false; + + if ( canDraw && psystem->m_nFinalAnimationFrame != 0 && frames != NULL ) + { + RwRaster *curFrame = frames[particle->m_nCurrentFrame]; + if ( prevFrame != curFrame ) + { + CSprite::FlushSpriteBuffer(); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void *)curFrame); + prevFrame = curFrame; + } + } + + if ( canDraw && psystem->Flags & DRAWTOP2D ) + { + if ( particle->m_nRotation != 0 ) + { + CSprite::RenderBufferedOneXLUSprite2D_Rotate_Dimension( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + particle->m_fSize * 63.0f, + particle->m_fSize * 63.0f, + particle->m_Color, + particle->m_nColorIntensity, + (Float)particle->m_nRotation, + particle->m_nAlpha); + } + else + { + CSprite::RenderBufferedOneXLUSprite2D( + particle->m_vecPosition.x, + particle->m_vecPosition.y, + particle->m_fSize * 63.0f, + particle->m_fSize * 63.0f, + particle->m_Color, + particle->m_nColorIntensity, + particle->m_nAlpha); + } + + canDraw = false; + } + + if ( canDraw ) + { + CVector coors; + Float w; + Float h; + + if ( CSprite::CalcScreenCoors(particle->m_vecPosition, coors, &w, &h, true) ) + { + if ( (!particleBanned || SCREEN_WIDTH * fParticleScaleLimit >= w) + && SCREEN_HEIGHT * fParticleScaleLimit >= h ) + { + if ( particle->m_nRotation != 0 ) + { + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(coors.x, coors.y, coors.z, + particle->m_fSize * w, particle->m_fSize * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + Float(particle->m_nRotation), + particle->m_nAlpha); + } + else if ( psystem->Flags & SCREEN_TRAIL ) + { + Float fRotation; + Float fTrailLength; + + if ( particle->m_vecScreenPosition.x == 0.0f ) + { + fTrailLength = 0.0f; + fRotation = 0.0f; + } + else + { + CVector2D vecDist + ( + coors.x - particle->m_vecScreenPosition.x, + coors.y - particle->m_vecScreenPosition.y + ); + + Float fDist = vecDist.Magnitude(); + + fTrailLength = fDist; + + //Float fRot = atan2( vecDist.x / fDist, sqrtf(1.0f - vecDist.x / fDist * (vecDist.x / fDist)) ); + Float fRot = asinf(vecDist.x / fDist); + + fRotation = fRot; + + if ( vecDist.y < 0.0f ) + fRotation = -1.0f * fRot + DEGTORAD(180.0f); + + fRotation = RADTODEG(fRotation); + + if ( fRotation < 0.0f ) + fRotation += 360.0f; + + Float fSpeed = particle->m_vecVelocity.Magnitude(); + + Float fNewTrailLength = fSpeed * CTimer::GetTimeStep() * w * 2.0f; + + if ( fDist > fNewTrailLength ) + fTrailLength = fNewTrailLength; + } + + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(coors.x, coors.y, coors.z, + particle->m_fSize * w, + particle->m_fSize * h + fTrailLength * psystem->m_fTrailLengthMultiplier, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + fRotation, + particle->m_nAlpha); + + particle->m_vecScreenPosition = coors; + } + else if ( psystem->Flags & SPEED_TRAIL ) + { + CVector vecPrevPos = particle->m_vecPosition - particle->m_vecVelocity; + Float fRotation; + Float fTrailLength; + + if ( CSprite::CalcScreenCoors(vecPrevPos, particle->m_vecScreenPosition, &fTrailLength, &fRotation, true) ) + { + CVector2D vecDist + ( + coors.x - particle->m_vecScreenPosition.x, + coors.y - particle->m_vecScreenPosition.y + ); + + Float fDist = vecDist.Magnitude(); + + fTrailLength = fDist; + + //Float fRot = atan2(vecDist.x / fDist, sqrt(1.0f - vecDist.x / fDist * (vecDist.x / fDist))); + Float fRot = asinf(vecDist.x / fDist); + + fRotation = fRot; + + if ( vecDist.y < 0.0f ) + fRotation = -1.0f * fRot + DEGTORAD(180.0f); + + fRotation = RADTODEG(fRotation); + + if ( fRotation < 0.0f ) + fRotation += 360.0f; + } + else + { + fRotation = 0.0f; + fTrailLength = 0.0f; + } + + CSprite::RenderBufferedOneXLUSprite_Rotate_Dimension(coors.x, coors.y, coors.z, + particle->m_fSize * w, + particle->m_fSize * h + fTrailLength * psystem->m_fTrailLengthMultiplier, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + fRotation, + particle->m_nAlpha); + } + else if ( psystem->Flags & VERT_TRAIL ) + { + Float fTrailLength = fabsf(particle->m_vecVelocity.z * 10.0f); + + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w, + (particle->m_fSize + fTrailLength * psystem->m_fTrailLengthMultiplier) * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + else if ( i == PARTICLE_RAINDROP_SMALL ) + { + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w * 0.05f, + particle->m_fSize * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + else if ( i == PARTICLE_BOAT_WAKE ) + { + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w, + psystem->m_fDefaultInitialRadius * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + else + { + CSprite::RenderBufferedOneXLUSprite(coors.x, coors.y, coors.z, + particle->m_fSize * w, + particle->m_fSize * h, + particle->m_Color.red, + particle->m_Color.green, + particle->m_Color.blue, + particle->m_nColorIntensity, + 1.0f / coors.z, + particle->m_nAlpha); + } + } + } + } + + particle = particle->m_pNext; + } + + CSprite::FlushSpriteBuffer(); + + } + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void *)FALSE); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void *)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void *)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void *)rwBLENDINVSRCALPHA); +} + +void CParticle::RemovePSystem(tParticleType type) +{ + tParticleSystemData *psystemdata = &mod_ParticleSystemManager.m_aParticles[type]; + + for ( CParticle *particle = psystemdata->m_pParticles; particle; particle = psystemdata->m_pParticles ) + RemoveParticle(particle, NULL, psystemdata); +} + +void CParticle::RemoveParticle(CParticle *pParticle, CParticle *pPrevParticle, tParticleSystemData *pPSystemData) +{ + if ( pPrevParticle ) + pPrevParticle->m_pNext = pParticle->m_pNext; + else + pPSystemData->m_pParticles = pParticle->m_pNext; + + pParticle->m_pNext = m_pUnusedListHead; + m_pUnusedListHead = pParticle; +} + +void CParticle::AddJetExplosion(CVector const &vecPos, Float fPower, Float fSize) +{ + CRGBA color(240, 240, 240, 255); + + if ( fPower < 1.0f ) + fPower = 1.0f; + + CVector vecRandOffset + ( + CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), + CGeneral::GetRandomNumberInRange(-0.4f, 0.4f), + CGeneral::GetRandomNumberInRange(0.1f, 0.3f) + ); + + vecRandOffset *= 2.0f; + + CVector vecStepPos = vecPos; + + for ( Int32 i = 0; i < Int32(fPower * 4.0f); i++ ) + { + AddParticle(PARTICLE_EXPLOSION_MFAST, + vecStepPos, + CVector + ( + CGeneral::GetRandomNumberInRange(-0.2f, 0.2f), + CGeneral::GetRandomNumberInRange(-0.2f, 0.2f), + CGeneral::GetRandomNumberInRange(-0.2f, 0.0f) + ), + NULL, + fSize, color, 0, 0, 0, 0); + + AddParticle(PARTICLE_EXPLOSION_MFAST, + vecStepPos, + CVector + ( + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(0.0f, 0.07f) + ), + NULL, + fSize, color, 0, 0, 0, 0); + + AddParticle(PARTICLE_EXPLOSION_MFAST, + vecStepPos, + CVector + ( + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(-0.04f, 0.04f), + CGeneral::GetRandomNumberInRange(0.0f, 0.07f) + ), + NULL, + fSize, color, 0, 0, 0, 0); + + vecStepPos += vecRandOffset; + } +} + +void CParticle::AddYardieDoorSmoke(CVector const &vecPos, CMatrix const &matMatrix) +{ + CRGBA color(0, 0, 0, 0); + + CMatrix invMat(Invert(matMatrix)); + + CVector vecBasePos = matMatrix * (invMat * vecPos + CVector(0.0f, -1.0f, 0.5f)); + + for ( Int32 i = 0; i < 5; i++ ) + { + CVector pos = vecBasePos; + + pos.x += CGeneral::GetRandomNumberInRange(-0.5f, 0.5f); + pos.y += CGeneral::GetRandomNumberInRange(-0.5f, 0.5f); + + AddParticle(PARTICLE_CARCOLLISION_DUST, + pos, + CVector(0.0f, 0.0f, 0.0f), + NULL, + 0.3f, color, 0, 0, 0, 0); + } +} + +STARTPATCHES + //InjectHook(0x50C410, &CParticle::ctor, PATCH_JUMP); + //InjectHook(0x50C420, &CParticle::dtor, PATCH_JUMP); + InjectHook(0x50C430, CParticle::ReloadConfig, PATCH_JUMP); + InjectHook(0x50C570, CParticle::Initialise, PATCH_JUMP); + InjectHook(0x50CF40, CParticle::Shutdown, PATCH_JUMP); + //InjectHook(0x50D140, CParticle::AddParticle, PATCH_JUMP); + InjectHook(0x50D190, (CParticle* (__cdecl *)(tParticleType, CVector const&, CVector const&, CEntity*, float, RwRGBA const&, int, int, int, int))CParticle::AddParticle, PATCH_JUMP); + InjectHook(0x50DCF0, CParticle::Update, PATCH_JUMP); + InjectHook(0x50EE20, CParticle::Render, PATCH_JUMP); + InjectHook(0x50F6E0, CParticle::RemovePSystem, PATCH_JUMP); + InjectHook(0x50F720, CParticle::RemoveParticle, PATCH_JUMP); + InjectHook(0x50F760, CParticle::AddJetExplosion, PATCH_JUMP); + InjectHook(0x50FAA0, CParticle::AddYardieDoorSmoke, PATCH_JUMP); + +ENDPATCHES \ No newline at end of file diff --git a/src/render/Particle.h b/src/render/Particle.h index f711ecf1..68e01879 100644 --- a/src/render/Particle.h +++ b/src/render/Particle.h @@ -1,82 +1,100 @@ #pragma once +#include "ParticleMgr.h" -enum tParticleType -{ - PARTICLE_SPARK, - PARTICLE_SPARK_SMALL, - PARTICLE_WHEEL_DIRT, - PARTICLE_WHEEL_WATER, - PARTICLE_BLOOD, - PARTICLE_BLOOD_SMALL, - PARTICLE_BLOOD_SPURT, - PARTICLE_DEBRIS, - PARTICLE_DEBRIS2, - PARTICLE_WATER, - PARTICLE_FLAME, - PARTICLE_FIREBALL, - PARTICLE_GUNFLASH, - PARTICLE_GUNFLASH_NOANIM, - PARTICLE_GUNSMOKE, - PARTICLE_GUNSMOKE2, - PARTICLE_SMOKE, - PARTICLE_SMOKE_SLOWMOTION, - PARTICLE_GARAGEPAINT_SPRAY, - PARTICLE_SHARD, - PARTICLE_SPLASH, - PARTICLE_CARFLAME, - PARTICLE_STEAM, - PARTICLE_STEAM2, - PARTICLE_STEAM_NY, - PARTICLE_STEAM_NY_SLOWMOTION, - PARTICLE_ENGINE_STEAM, - PARTICLE_RAINDROP, - PARTICLE_RAINDROP_SMALL, - PARTICLE_RAIN_SPLASH, - PARTICLE_RAIN_SPLASH_BIGGROW, - PARTICLE_RAIN_SPLASHUP, - PARTICLE_WATERSPRAY, - PARTICLE_EXPLOSION_MEDIUM, - PARTICLE_EXPLOSION_LARGE, - PARTICLE_EXPLOSION_MFAST, - PARTICLE_EXPLOSION_LFAST, - PARTICLE_CAR_SPLASH, - PARTICLE_BOAT_SPLASH, - PARTICLE_BOAT_THRUSTJET, - PARTICLE_BOAT_WAKE, - PARTICLE_WATER_HYDRANT, - PARTICLE_WATER_CANNON, - PARTICLE_EXTINGUISH_STEAM, - PARTICLE_PED_SPLASH, - PARTICLE_PEDFOOT_DUST, - PARTICLE_HELI_DUST, - PARTICLE_HELI_ATTACK, - PARTICLE_ENGINE_SMOKE, - PARTICLE_ENGINE_SMOKE2, - PARTICLE_CARFLAME_SMOKE, - PARTICLE_FIREBALL_SMOKE, - PARTICLE_PAINT_SMOKE, - PARTICLE_TREE_LEAVES, - PARTICLE_CARCOLLISION_DUST, - PARTICLE_CAR_DEBRIS, - PARTICLE_HELI_DEBRIS, - PARTICLE_EXHAUST_FUMES, - PARTICLE_RUBBER_SMOKE, - PARTICLE_BURNINGRUBBER_SMOKE, - PARTICLE_BULLETHIT_SMOKE, - PARTICLE_GUNSHELL_FIRST, - PARTICLE_GUNSHELL, - PARTICLE_GUNSHELL_BUMP1, - PARTICLE_GUNSHELL_BUMP2, - PARTICLE_TEST, - PARTICLE_BIRD_FRONT, - PARTICLE_RAINDROP_2D, -}; class CEntity; class CParticle { + enum + { + RAND_TABLE_SIZE = 20, + SIN_COS_TABLE_SIZE = 1024 + }; + public: - static void AddParticle(tParticleType, const CVector &pos, const CVector &velocity, CEntity *ent = nil, - float size = 0.0, int32 rotationStep = 0, int32 rotation = 0, int startFrame = 0, int lifeSpan = 0); + CVector m_vecPosition; + CVector m_vecVelocity; + CVector m_vecScreenPosition; + UInt32 m_nTimeWhenWillBeDestroyed; + UInt32 m_nTimeWhenColorWillBeChanged; + Float m_fZGround; + CVector m_vecParticleMovementOffset; + Int16 m_nCurrentZRotation; + UInt16 m_nZRotationTimer; + Float m_fCurrentZRadius; + UInt16 m_nZRadiusTimer; + char _pad0[2]; + Float m_fSize; + Float m_fExpansionRate; + UInt16 m_nFadeToBlackTimer; + UInt16 m_nFadeAlphaTimer; + UInt8 m_nColorIntensity; + UInt8 m_nAlpha; + UInt16 m_nCurrentFrame; + Int16 m_nAnimationSpeedTimer; + Int16 m_nRotationStep; + Int16 m_nRotation; + RwRGBA m_Color; + char _pad1[2]; + CParticle *m_pNext; + + CParticle() + { + ; + } + + ~CParticle() + { + ; + } + + //static Float ms_afRandTable[RAND_TABLE_SIZE]; + static Float (&ms_afRandTable)[RAND_TABLE_SIZE]; + static CParticle *m_pUnusedListHead; + + /* + static Float m_SinTable[SIN_COS_TABLE_SIZE]; + static Float m_CosTable[SIN_COS_TABLE_SIZE]; + */ + static Float (&m_SinTable)[SIN_COS_TABLE_SIZE]; + static Float (&m_CosTable)[SIN_COS_TABLE_SIZE]; + + + static void ReloadConfig(); + static void Initialise(); + static void Shutdown(); + + static CParticle *AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity = NULL, Float fSize = 0.0f, Int32 nRotationSpeed = 0, Int32 nRotation = 0, Int32 nCurFrame = 0, Int32 nLifeSpan = 0); + static CParticle *AddParticle(tParticleType type, CVector const &vecPos, CVector const &vecDir, CEntity *pEntity, Float fSize, RwRGBA const &color, Int32 nRotationSpeed = 0, Int32 nRotation = 0, Int32 nCurFrame = 0, Int32 nLifeSpan = 0); + + static void Update(); + static void Render(); + + static void RemovePSystem(tParticleType type); + static void RemoveParticle(CParticle *pParticle, CParticle *pPrevParticle, tParticleSystemData *pPSystemData); + + static inline void _Next(CParticle *&pParticle, CParticle *&pPrevParticle, tParticleSystemData *pPSystemData, Bool bRemoveParticle) + { + if ( bRemoveParticle ) + { + RemoveParticle(pParticle, pPrevParticle, pPSystemData); + + if ( pPrevParticle ) + pParticle = pPrevParticle->m_pNext; + else + pParticle = pPSystemData->m_pParticles; + } + else + { + pPrevParticle = pParticle; + pParticle = pParticle->m_pNext; + } + } + + static void AddJetExplosion(CVector const &vecPos, Float fPower, Float fSize); + static void AddYardieDoorSmoke(CVector const &vecPos, CMatrix const &matMatrix); + }; + +VALIDATE_SIZE(CParticle, 0x68); \ No newline at end of file diff --git a/src/render/Shadows.cpp b/src/render/Shadows.cpp new file mode 100644 index 00000000..ead84e92 --- /dev/null +++ b/src/render/Shadows.cpp @@ -0,0 +1,7 @@ +#include "common.h" +#include "Shadows.h" + +void CShadows::AddPermanentShadow(unsigned char ShadowType, RwTexture* pTexture, CVector* pPosn, float fX1, float fY1, float fX2, float fY2, short nTransparency, unsigned char nRed, unsigned char nGreen, unsigned char nBlue, float fZDistance, unsigned int nTime, float fScale) +{ + ((void (__cdecl *)(unsigned char, RwTexture*, CVector*, float, float, float, float, short, unsigned char, unsigned char, unsigned char, float, unsigned int, float))0x56EC50)(ShadowType, pTexture, pPosn, fX1, fY1, fX2, fY2, nTransparency, nRed, nGreen, nBlue, fZDistance, nTime, fScale); +} diff --git a/src/render/Shadows.h b/src/render/Shadows.h new file mode 100644 index 00000000..3c7b4981 --- /dev/null +++ b/src/render/Shadows.h @@ -0,0 +1,9 @@ +#pragma once + +struct RwTexture; + +class CShadows +{ +public: + static void AddPermanentShadow(unsigned char ShadowType, RwTexture* pTexture, CVector* pPosn, float fX1, float fY1, float fX2, float fY2, short nTransparency, unsigned char nRed, unsigned char nGreen, unsigned char nBlue, float fZDistance, unsigned int nTime, float fScale); +}; \ No newline at end of file