diff --git a/src/FileLoader.cpp b/src/FileLoader.cpp index 8bc6ad11..d87964ac 100644 --- a/src/FileLoader.cpp +++ b/src/FileLoader.cpp @@ -855,7 +855,7 @@ CFileLoader::Load2dEffect(const char *line) int id, r, g, b, a, type; float x, y, z; char corona[32], shadow[32]; - int shadowIntens, flash, roadReflection, flare, flags, probability; + int shadowIntens, lightType, roadReflection, flare, flags, probability; CBaseModelInfo *mi; C2dEffect *effect; char *p; @@ -888,14 +888,14 @@ CFileLoader::Load2dEffect(const char *line) sscanf(line, "%f %f %f %f %d %d %d %d %d", &effect->light.dist, - &effect->light.outerRange, + &effect->light.range, &effect->light.size, - &effect->light.innerRange, - &shadowIntens, &flash, &roadReflection, &flare, &flags); + &effect->light.shadowRange, + &shadowIntens, &lightType, &roadReflection, &flare, &flags); effect->light.corona = RwTextureRead(corona, nil); effect->light.shadow = RwTextureRead(shadow, nil); effect->light.shadowIntensity = shadowIntens; - effect->light.flash = flash; + effect->light.lightType = lightType; effect->light.roadReflection = roadReflection; effect->light.flareType = flare; // TODO: check out the flags diff --git a/src/ParticleObject.cpp b/src/ParticleObject.cpp index 58f2cfcb..cf6e84bf 100644 --- a/src/ParticleObject.cpp +++ b/src/ParticleObject.cpp @@ -2,7 +2,9 @@ #include "patcher.h" #include "ParticleObject.h" -WRAPPER void CParticleObject::AddObject(uint16, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); } +WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, bool remove) { EAXJMP(0x4BC4D0); } +WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, float size, bool remove) { EAXJMP(0x4BC520); } +WRAPPER void CParticleObject::AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove) { EAXJMP(0x4BC570); } // Converted from static void __cdecl CParticleObject::Initialise() 0x42C760 void CParticleObject::Initialise() diff --git a/src/ParticleObject.h b/src/ParticleObject.h index 34debbfd..def7b7de 100644 --- a/src/ParticleObject.h +++ b/src/ParticleObject.h @@ -29,7 +29,9 @@ enum eParticleObjectType class CParticleObject : CPlaceable { public: - static void AddObject(uint16, const CVector &pos, bool remove); + static void AddObject(uint16 type, const CVector &pos, bool remove); + static void AddObject(uint16 type, const CVector &pos, float size, bool remove); + static void AddObject(uint16 type, const CVector &pos, const CVector &dir, float size, bool remove); static void Initialise(); static void UpdateAll(); diff --git a/src/Pickup.h b/src/Pickup.h deleted file mode 100644 index efef15fe..00000000 --- a/src/Pickup.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "common.h" -#include "Object.h" - -enum ePickupType -{ - PICKUP_NONE = 0, - PICKUP_IN_SHOP = 1, - PICKUP_ON_STREET = 2, - PICKUP_ONCE = 3, - PICKUP_ONCE_TIMEOUT = 4, - PICKUP_COLLECTABLE1 = 5, - PICKUP_IN_SHOP_OUT_OF_STOCK = 6, - PICKUP_MONEY = 7, - PICKUP_MINE_INACTIVE = 8, - PICKUP_MINE_ARMED = 9, - PICKUP_NAUTICAL_MINE_INACTIVE = 10, - PICKUP_NAUTICAL_MINE_ARMED = 11, - PICKUP_FLOATINGPACKAGE = 12, - PICKUP_FLOATINGPACKAGE_FLOATING = 13, - PICKUP_ON_STREET_SLOW = 14, -}; - -class CPickup -{ - ePickupType m_eType; - uint16 m_wQuantity; - CObject *m_pObject; - uint32 m_nTimer; - int16 m_eModelIndex; - int16 m_wIndex; - CVector m_vecPos; -}; diff --git a/src/Timecycle.h b/src/Timecycle.h index 546e6e0f..71ddedb7 100644 --- a/src/Timecycle.h +++ b/src/Timecycle.h @@ -118,6 +118,7 @@ public: static int GetSunCoronaGreen(void) { return m_nCurrentSunCoronaGreen; } static int GetSunCoronaBlue(void) { return m_nCurrentSunCoronaBlue; } static float GetSunSize(void) { return m_fCurrentSunSize; } + static float GetSpriteBrightness(void) { return m_fCurrentSpriteBrightness; } static float GetFarClip(void) { return m_fCurrentFarClip; } static float GetFogStart(void) { return m_fCurrentFogStart; } diff --git a/src/control/Bridge.cpp b/src/control/Bridge.cpp new file mode 100644 index 00000000..91f3c788 --- /dev/null +++ b/src/control/Bridge.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "Bridge.h" + +WRAPPER bool CBridge::ShouldLightsBeFlashing(void) { EAXJMP(0x413D10); } diff --git a/src/control/Bridge.h b/src/control/Bridge.h new file mode 100644 index 00000000..64b85c1d --- /dev/null +++ b/src/control/Bridge.h @@ -0,0 +1,7 @@ +#pragma once + +class CBridge +{ +public: + static bool ShouldLightsBeFlashing(void); +}; diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index cec13c8a..56254d56 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -5,5 +5,9 @@ CPickup(&CPickups::aPickUps)[NUMPICKUPS] = *(CPickup(*)[NUMPICKUPS])*(uintptr*)0x878C98; WRAPPER void CPickups::RenderPickUpText(void) { EAXJMP(0x432440); } +WRAPPER void CPickups::DoCollectableEffects(CEntity *ent) { EAXJMP(0x431C30); } +WRAPPER void CPickups::DoMoneyEffects(CEntity *ent) { EAXJMP(0x431F40); } +WRAPPER void CPickups::DoMineEffects(CEntity *ent) { EAXJMP(0x4321C0); } +WRAPPER void CPickups::DoPickUpEffects(CEntity *ent) { EAXJMP(0x431520); } WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); } diff --git a/src/control/Pickups.h b/src/control/Pickups.h index 3ae2764c..9cf485d0 100644 --- a/src/control/Pickups.h +++ b/src/control/Pickups.h @@ -1,14 +1,48 @@ #pragma once -#include "config.h" -#include "Pickup.h" +enum ePickupType +{ + PICKUP_NONE = 0, + PICKUP_IN_SHOP = 1, + PICKUP_ON_STREET = 2, + PICKUP_ONCE = 3, + PICKUP_ONCE_TIMEOUT = 4, + PICKUP_COLLECTABLE1 = 5, + PICKUP_IN_SHOP_OUT_OF_STOCK = 6, + PICKUP_MONEY = 7, + PICKUP_MINE_INACTIVE = 8, + PICKUP_MINE_ARMED = 9, + PICKUP_NAUTICAL_MINE_INACTIVE = 10, + PICKUP_NAUTICAL_MINE_ARMED = 11, + PICKUP_FLOATINGPACKAGE = 12, + PICKUP_FLOATINGPACKAGE_FLOATING = 13, + PICKUP_ON_STREET_SLOW = 14, +}; + +class CEntity; +class CObject; + +class CPickup +{ + ePickupType m_eType; + uint16 m_wQuantity; + CObject *m_pObject; + uint32 m_nTimer; + int16 m_eModelIndex; + int16 m_wIndex; + CVector m_vecPos; +}; class CPickups { public: static void RenderPickUpText(void); + static void DoCollectableEffects(CEntity *ent); + static void DoMoneyEffects(CEntity *ent); + static void DoMineEffects(CEntity *ent); + static void DoPickUpEffects(CEntity *ent); - static CPickup(&aPickUps)[NUMPICKUPS]; + static CPickup (&aPickUps)[NUMPICKUPS]; }; class CPacManPickups diff --git a/src/control/Replay.h b/src/control/Replay.h index 18701293..d0f55839 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -3,7 +3,6 @@ #include "Camera.h" #include "Ped.h" #include "Pools.h" -#include "Pickup.h" #include "Radar.h" #include "References.h" #include "Vehicle.h" diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp new file mode 100644 index 00000000..73ff6118 --- /dev/null +++ b/src/control/TrafficLights.cpp @@ -0,0 +1,5 @@ +#include "common.h" +#include "patcher.h" +#include "TrafficLights.h" + +WRAPPER void CTrafficLights::DisplayActualLight(CEntity *ent) { EAXJMP(0x455800); } diff --git a/src/control/TrafficLights.h b/src/control/TrafficLights.h new file mode 100644 index 00000000..eec3e1e3 --- /dev/null +++ b/src/control/TrafficLights.h @@ -0,0 +1,9 @@ +#pragma once + +class CEntity; + +class CTrafficLights +{ +public: + static void DisplayActualLight(CEntity *ent); +}; diff --git a/src/entities/Entity.cpp b/src/entities/Entity.cpp index a5fbe92d..fac7f17f 100644 --- a/src/entities/Entity.cpp +++ b/src/entities/Entity.cpp @@ -1,14 +1,29 @@ #include "common.h" -#include "rpworld.h" +#include "patcher.h" +#include "General.h" +#include "ModelIndices.h" +#include "Timer.h" #include "Placeable.h" #include "Entity.h" +#include "Object.h" +#include "ParticleObject.h" #include "Lights.h" #include "World.h" #include "Camera.h" +#include "Glass.h" +#include "Clock.h" +#include "Weather.h" +#include "TimeCycle.h" +#include "Bridge.h" +#include "TrafficLights.h" +#include "Coronas.h" +#include "Pointlights.h" +#include "Shadows.h" +#include "Pickups.h" +#include "SpecialFX.h" #include "References.h" #include "TxdStore.h" #include "Zones.h" -#include "patcher.h" int gBuildings; @@ -59,7 +74,7 @@ CEntity::CEntity(void) m_scanCode = 0; m_modelIndex = -1; m_rwObject = nil; - m_randomSeed = rand(); + m_randomSeed = CGeneral::GetRandomNumber(); m_pFirstReference = nil; } @@ -339,9 +354,105 @@ CEntity::GetBoundRect(void) return rect; } -WRAPPER void +void CEntity::PreRender(void) -{ EAXJMP(0x474350); +{ + switch(m_type){ + case ENTITY_TYPE_BUILDING: + if(GetModelIndex() == MI_RAILTRACKS){ + CShadows::StoreShadowForPole(this, 0.0f, -10.949f, 5.0f, 8.0f, 1.0f, 0); + CShadows::StoreShadowForPole(this, 0.0f, 10.949f, 5.0f, 8.0f, 1.0f, 1); + }else if(IsTreeModel(GetModelIndex())){ + CShadows::StoreShadowForTree(this); + ModifyMatrixForTreeInWind(); + }else if(IsBannerModel(GetModelIndex())){ + ModifyMatrixForBannerInWind(); + } + break; + case ENTITY_TYPE_OBJECT: + if(GetModelIndex() == MI_COLLECTABLE1){ + CPickups::DoCollectableEffects(this); + GetMatrix().UpdateRW(); + UpdateRwFrame(); + }else if(GetModelIndex() == MI_MONEY){ + CPickups::DoMoneyEffects(this); + GetMatrix().UpdateRW(); + UpdateRwFrame(); + }else if(GetModelIndex() == MI_NAUTICALMINE || + GetModelIndex() == MI_CARMINE || + GetModelIndex() == MI_BRIEFCASE){ + if(((CObject*)this)->bIsPickup){ + CPickups::DoMineEffects(this); + GetMatrix().UpdateRW(); + UpdateRwFrame(); + } + }else if(IsPickupModel(GetModelIndex())){ + if(((CObject*)this)->bIsPickup){ + CPickups::DoPickUpEffects(this); + GetMatrix().UpdateRW(); + UpdateRwFrame(); + }else if(GetModelIndex() == MI_GRENADE){ + CMotionBlurStreaks::RegisterStreak((uintptr)this, + 100, 100, 100, + TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(), + TheCamera.GetPosition() + 0.07f*TheCamera.GetRight()); + }else if(GetModelIndex() == MI_MOLOTOV){ + CMotionBlurStreaks::RegisterStreak((uintptr)this, + 0, 100, 0, + TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(), + TheCamera.GetPosition() + 0.07f*TheCamera.GetRight()); + } + }else if(GetModelIndex() == MI_MISSILE){ + CVector pos = GetPosition(); + float flicker = (CGeneral::GetRandomNumber() & 0xF)/(float)0x10; + CShadows::StoreShadowToBeRendered(SHADOWTYPE_2, + gpShadowExplosionTex, &pos, + 8.0f, 0.0f, 0.0f, -8.0f, + 255, 200.0f*flicker, 160.0f*flicker, 120.0f*flicker, + 20.0f, false, 1.0f); + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + 8.0f, + 1.0f*flicker, + 0.8f*flicker, + 0.6f*flicker, + CPointLights::FOG_NONE, true); + CCoronas::RegisterCorona((uintptr)this, + 255.0f*flicker, 220.0f*flicker, 190.0f*flicker, 255, + pos, 6.0f*flicker, 80.0f, gpCoronaTexture[CCoronas::TYPE_STAR], + CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, + CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); + }else if(IsGlass(GetModelIndex())){ + PreRenderForGlassWindow(); + } + // fall through + case ENTITY_TYPE_DUMMY: + if(GetModelIndex() == MI_TRAFFICLIGHTS){ + CTrafficLights::DisplayActualLight(this); + CShadows::StoreShadowForPole(this, 2.957f, 0.147f, 0.0f, 16.0f, 0.4f, 0); + }else if(GetModelIndex() == MI_SINGLESTREETLIGHTS1) + CShadows::StoreShadowForPole(this, 0.744f, 0.0f, 0.0f, 16.0f, 0.4f, 0); + else if(GetModelIndex() == MI_SINGLESTREETLIGHTS2) + CShadows::StoreShadowForPole(this, 0.043f, 0.0f, 0.0f, 16.0f, 0.4f, 0); + else if(GetModelIndex() == MI_SINGLESTREETLIGHTS3) + CShadows::StoreShadowForPole(this, 1.143f, 0.145f, 0.0f, 16.0f, 0.4f, 0); + else if(GetModelIndex() == MI_DOUBLESTREETLIGHTS) + CShadows::StoreShadowForPole(this, 0.0f, -0.048f, 0.0f, 16.0f, 0.4f, 0); + else if(GetModelIndex() == MI_STREETLAMP1 || + GetModelIndex() == MI_STREETLAMP2) + CShadows::StoreShadowForPole(this, 0.0f, 0.0f, 0.0f, 16.0f, 0.4f, 0); + break; + } + + if(CModelInfo::GetModelInfo(GetModelIndex())->m_num2dEffects != 0) + ProcessLightsForEntity(); +} + +void +CEntity::PreRenderForGlassWindow(void) +{ + CGlass::AskForObjectToBeRenderedInGlass(this); + bIsVisible = false; } void @@ -447,6 +558,313 @@ CEntity::PruneReferences(void) } } +void +CEntity::AddSteamsFromGround(CVector *unused) +{ + int i, n; + C2dEffect *effect; + CVector pos; + + n = CModelInfo::GetModelInfo(GetModelIndex())->m_num2dEffects; + for(i = 0; i < n; i++){ + effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i); + if(effect->type != EFFECT_PARTICLE) + continue; + + pos = GetMatrix() * effect->pos; + switch(effect->particle.particleType){ + case 0: + CParticleObject::AddObject(POBJECT_PAVEMENT_STEAM, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 1: + CParticleObject::AddObject(POBJECT_WALL_STEAM, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 2: + CParticleObject::AddObject(POBJECT_DRY_ICE, pos, effect->particle.scale, false); + break; + case 3: + CParticleObject::AddObject(POBJECT_SMALL_FIRE, pos, effect->particle.dir, effect->particle.scale, false); + break; + case 4: + CParticleObject::AddObject(POBJECT_DARK_SMOKE, pos, effect->particle.dir, effect->particle.scale, false); + break; + } + } +} + +void +CEntity::ProcessLightsForEntity(void) +{ + int i, n; + C2dEffect *effect; + CVector pos; + bool lightOn, lightFlickering; + uint32 flashTimer1, flashTimer2, flashTimer3; + + if(bRenderDamaged || !bIsVisible || GetUp().z < 0.96f) + return; + + flashTimer1 = 0; + flashTimer2 = 0; + flashTimer3 = 0; + + n = CModelInfo::GetModelInfo(GetModelIndex())->m_num2dEffects; + for(i = 0; i < n; i++, flashTimer1 += 0x80, flashTimer2 += 0x100, flashTimer3 += 0x200){ + effect = CModelInfo::GetModelInfo(GetModelIndex())->Get2dEffect(i); + + if(effect->type != EFFECT_LIGHT) + continue; + + pos = GetMatrix() * effect->pos; + + lightOn = false; + lightFlickering = false; + switch(effect->light.lightType){ + case LIGHT_ON: + lightOn = true; + break; + case LIGHT_ON_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + lightOn = true; + break; + case LIGHT_FLICKER: + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed) & 3) + lightOn = true; + break; + case LIGHT_FLICKER_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7){ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed) & 3) + lightOn = true; + } + break; + case LIGHT_FLASH1: + if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200) + lightOn = true; + break; + case LIGHT_FLASH1_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer1) & 0x200) + lightOn = true; + break; + case LIGHT_FLASH2: + if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400) + lightOn = true; + break; + case LIGHT_FLASH2_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer2) & 0x400) + lightOn = true; + break; + case LIGHT_FLASH3: + if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800) + lightOn = true; + break; + case LIGHT_FLASH3_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7) + if((CTimer::GetTimeInMilliseconds() + flashTimer3) & 0x800) + lightOn = true; + break; + case LIGHT_RANDOM_FLICKER: + if(m_randomSeed > 16) + lightOn = true; + else{ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed*8) & 3) + lightOn = true; + } + break; + case LIGHT_RANDOM_FLICKER_NIGHT: + if(CClock::GetHours() > 18 || CClock::GetHours() < 7){ + if(m_randomSeed > 16) + lightOn = true; + else{ + if((CTimer::GetTimeInMilliseconds() ^ m_randomSeed*8) & 0x60) + lightOn = true; + else + lightFlickering = true; + if((CTimer::GetTimeInMilliseconds()>>1 ^ m_randomSeed*8) & 3) + lightOn = true; + } + } + break; + case LIGHT_BRIDGE_FLASH1: + if(CBridge::ShouldLightsBeFlashing() && CTimer::GetTimeInMilliseconds() & 0x200) + lightOn = true; + break; + case LIGHT_BRIDGE_FLASH2: + if(CBridge::ShouldLightsBeFlashing() && (CTimer::GetTimeInMilliseconds() & 0x1FF) < 60) + lightOn = true; + break; + } + + // Corona + if(lightOn) + CCoronas::RegisterCorona((uintptr)this + i, + effect->col.r, effect->col.g, effect->col.b, 255, + pos, effect->light.size, effect->light.dist, + effect->light.corona, effect->light.flareType, effect->light.roadReflection, + effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f); + else if(lightFlickering) + CCoronas::RegisterCorona((uintptr)this + i, + 0, 0, 0, 255, + pos, effect->light.size, effect->light.dist, + effect->light.corona, effect->light.flareType, effect->light.roadReflection, + effect->light.flags&LIGHTFLAG_LOSCHECK, CCoronas::STREAK_OFF, 0.0f); + + // Pointlight + if(effect->light.flags & LIGHTFLAG_FOG_ALWAYS){ + CPointLights::AddLight(CPointLights::LIGHT_FOGONLY_ALWAYS, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f, + CPointLights::FOG_ALWAYS, true); + }else if(effect->light.flags & LIGHTFLAG_FOG_NORMAL && lightOn && effect->light.range == 0.0f){ + CPointLights::AddLight(CPointLights::LIGHT_FOGONLY, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r/255.0f, effect->col.g/255.0f, effect->col.b/255.0f, + CPointLights::FOG_NORMAL, true); + }else if(lightOn && effect->light.range != 0.0f){ + if(effect->col.r == 0 && effect->col.g == 0 && effect->col.b == 0){ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + 0.0f, 0.0f, 0.0f, + CPointLights::FOG_NONE, true); + }else{ + CPointLights::AddLight(CPointLights::LIGHT_POINT, + pos, CVector(0.0f, 0.0f, 0.0f), + effect->light.range, + effect->col.r*CTimeCycle::GetSpriteBrightness()/255.0f, + effect->col.g*CTimeCycle::GetSpriteBrightness()/255.0f, + effect->col.b*CTimeCycle::GetSpriteBrightness()/255.0f, + // half-useless because LIGHTFLAG_FOG_ALWAYS can't be on + (effect->light.flags & LIGHTFLAG_FOG) >> 1, + true); + } + } + + // Light shadow + if(effect->light.shadowRange != 0.0f){ + if(lightOn){ + CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_2, + effect->light.shadow, &pos, + effect->light.shadowRange, 0.0f, + 0.0f, -effect->light.shadowRange, + 128, + effect->col.r*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + effect->col.g*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + effect->col.b*CTimeCycle::GetSpriteBrightness()*effect->light.shadowIntensity/255.0f, + 15.0f, 1.0f, 40.0f, false, 0.0f); + }else if(lightFlickering){ + CShadows::StoreStaticShadow((uintptr)this + i, SHADOWTYPE_2, + effect->light.shadow, &pos, + effect->light.shadowRange, 0.0f, + 0.0f, -effect->light.shadowRange, + 0, 0.0f, 0.0f, 0.0f, + 15.0f, 1.0f, 40.0f, false, 0.0f); + } + } + } +} + +float WindTabel[] = { + 1.0f, 0.5f, 0.2f, 0.7f, 0.4f, 1.0f, 0.5f, 0.3f, + 0.2f, 0.1f, 0.7f, 0.6f, 0.3f, 1.0f, 0.5f, 0.2f, +}; + +void +CEntity::ModifyMatrixForTreeInWind(void) +{ + uint16 t; + float f; + float strength, flutter; + + if(CTimer::GetIsPaused()) + return; + + CMatrix mat(GetMatrix().m_attachment); + + if(CWeather::Wind >= 0.5){ + t = m_randomSeed + 16*CTimer::GetTimeInMilliseconds(); + f = (t & 0xFFF)/(float)0x1000; + flutter = f * WindTabel[(t>>12)+1 & 0xF] + + (1.0f - f) * WindTabel[(t>>12) & 0xF] + + 1.0f; + strength = CWeather::Wind < 0.8f ? 0.008f : 0.014f; + }else if(CWeather::Wind >= 0.2){ + t = (uintptr)this + CTimer::GetTimeInMilliseconds(); + f = (t & 0xFFF)/(float)0x1000; + flutter = sin(f * 6.28f); + strength = 0.008f; + }else{ + t = (uintptr)this + CTimer::GetTimeInMilliseconds(); + f = (t & 0xFFF)/(float)0x1000; + flutter = sin(f * 6.28f); + strength = 0.005f; + } + + mat.GetUp()->x = strength * flutter; + mat.GetUp()->y = mat.GetUp()->x; + + mat.UpdateRW(); + UpdateRwFrame(); +} + +float BannerWindTabel[] = { + 0.0f, 0.3f, 0.6f, 0.85f, 0.99f, 0.97f, 0.65f, 0.15f, + -0.1f, 0.0f, 0.35f, 0.57f, 0.55f, 0.35f, 0.45f, 0.67f, + 0.73f, 0.45f, 0.25f, 0.35f, 0.35f, 0.11f, 0.13f, 0.21f, + 0.28f, 0.28f, 0.22f, 0.1f, 0.0f, -0.1f, -0.17f, -0.12f +}; + +void +CEntity::ModifyMatrixForBannerInWind(void) +{ + uint16 t; + float f; + float strength, flutter; + CVector right, up; + + if(CTimer::GetIsPaused()) + return; + + if(CWeather::Wind < 0.1f) + strength = 0.2f; + else if(CWeather::Wind < 0.8f) + strength = 0.43f; + else + strength = 0.66f; + + t = ((int)(GetMatrix().GetPosition()->x + GetMatrix().GetPosition()->y) << 10) + 16*CTimer::GetTimeInMilliseconds(); + f = (t & 0x7FF)/(float)0x800; + flutter = f * BannerWindTabel[(t>>11)+1 & 0x1F] + + (1.0f - f) * BannerWindTabel[(t>>11) & 0x1F]; + flutter *= strength; + + right = CrossProduct(GetForward(), GetUp()); + right.z = 0.0f; + right.Normalise(); + up = right * flutter; + up.z = sqrt(sq(1.0f) - sq(flutter)); + GetRight() = CrossProduct(GetForward(), up); + GetUp() = up; + + GetMatrix().UpdateRW(); + UpdateRwFrame(); +} + STARTPATCHES InjectHook(0x473C30, &CEntity::ctor, PATCH_JUMP); InjectHook(0x473E40, &CEntity::dtor, PATCH_JUMP); @@ -466,11 +884,18 @@ STARTPATCHES InjectHook(0x473F10, &CEntity::AttachToRwObject, PATCH_JUMP); InjectHook(0x473F60, &CEntity::DetachFromRwObject, PATCH_JUMP); + InjectHook(0x475A20, &CEntity::PreRenderForGlassWindow, PATCH_JUMP); + InjectHook(0x50CE40, &CEntity::AddSteamsFromGround, PATCH_JUMP); + InjectHook(0x475670, &CEntity::ModifyMatrixForTreeInWind, PATCH_JUMP); + InjectHook(0x475830, &CEntity::ModifyMatrixForBannerInWind, PATCH_JUMP); + InjectHook(0x4FA530, &CEntity::ProcessLightsForEntity, PATCH_JUMP); + InjectHook(0x475080, &CEntity::Add_, PATCH_JUMP); InjectHook(0x475310, &CEntity::Remove_, PATCH_JUMP); InjectHook(0x473EA0, &CEntity::CreateRwObject_, PATCH_JUMP); InjectHook(0x473F90, &CEntity::DeleteRwObject_, PATCH_JUMP); InjectHook(0x474000, &CEntity::GetBoundRect_, PATCH_JUMP); + InjectHook(0x474350, &CEntity::PreRender_, PATCH_JUMP); InjectHook(0x474BD0, &CEntity::Render_, PATCH_JUMP); InjectHook(0x4A7C60, &CEntity::SetupLighting_, PATCH_JUMP); ENDPATCHES diff --git a/src/entities/Entity.h b/src/entities/Entity.h index 26a6e46b..3e100879 100644 --- a/src/entities/Entity.h +++ b/src/entities/Entity.h @@ -5,19 +5,6 @@ struct CReference; -enum eEntityFlags -{ - IS_UNK = 0, - CONTROL_POSTPONED, - IS_EXPLOSIONPROOF, - IS_VISIBLE, - IS_ON_GROUND, - REQUIRES_SCORCHED_LIGHTS, - HAS_BLIP, - IS_BIG_BUILDING, - HAS_BEEN_DAMAGED, -}; - enum eEntityType { ENTITY_TYPE_NOTHING = 0, @@ -153,6 +140,12 @@ public: void ResolveReferences(void); void PruneReferences(void); + void PreRenderForGlassWindow(void); + void AddSteamsFromGround(CVector *unused); + void ModifyMatrixForTreeInWind(void); + void ModifyMatrixForBannerInWind(void); + void ProcessLightsForEntity(void); + // to make patching virtual functions possible CEntity *ctor(void) { return ::new (this) CEntity(); } @@ -163,6 +156,7 @@ public: void CreateRwObject_(void) { CEntity::CreateRwObject(); } void DeleteRwObject_(void) { CEntity::DeleteRwObject(); } CRect GetBoundRect_(void) { return CEntity::GetBoundRect(); } + void PreRender_(void) { CEntity::PreRender(); } void Render_(void) { CEntity::Render(); } bool SetupLighting_(void) { return CEntity::SetupLighting(); } }; diff --git a/src/entities/Object.cpp b/src/entities/Object.cpp index 1feecbdf..dbc38b9d 100644 --- a/src/entities/Object.cpp +++ b/src/entities/Object.cpp @@ -25,7 +25,7 @@ CObject::CObject(void) m_colour2 = 0; m_colour1 = m_colour2; field_172 = 0; - m_obj_flag1 = false; + bIsPickup = false; m_obj_flag2 = false; m_obj_flag4 = false; m_obj_flag8 = false; diff --git a/src/entities/Object.h b/src/entities/Object.h index 0cb951e2..3a8d62f2 100644 --- a/src/entities/Object.h +++ b/src/entities/Object.h @@ -32,7 +32,7 @@ public: CMatrix m_objectMatrix; float m_fUprootLimit; int8 ObjectCreatedBy; - int8 m_obj_flag1 : 1; + int8 bIsPickup : 1; int8 m_obj_flag2 : 1; int8 m_obj_flag4 : 1; int8 m_obj_flag8 : 1; diff --git a/src/modelinfo/ModelIndices.h b/src/modelinfo/ModelIndices.h index feafcd40..3a37ac23 100644 --- a/src/modelinfo/ModelIndices.h +++ b/src/modelinfo/ModelIndices.h @@ -315,6 +315,21 @@ enum MI_TOYZ, MI_GHOST, + MI_GRENADE = 170, + MI_AK47, + MI_BASEBALL_BAT, + MI_COLT, + MI_MOLOTOV, + MI_ROCKETLAUNCHER, + MI_SHOTGUN, + MI_SNIPER, + MI_UZI, + MI_MISSILE, + MI_M16, + MI_FLAMETHROWER, + MI_BOMB, + MI_FINGERS, + MI_CAR_DOOR = 190, MI_CAR_BUMPER, MI_CAR_PANEL, @@ -377,3 +392,65 @@ IsPedModel(int16 id) { return id >= 0 && id <= 89; } + +inline bool +IsTreeModel(int16 id) +{ + return id == MI_TREE1 || + id == MI_TREE2 || + id == MI_TREE3 || + id == MI_TREE4 || + id == MI_TREE5 || + id == MI_TREE6 || + id == MI_TREE7 || + id == MI_TREE8 || + id == MI_TREE9 || + id == MI_TREE10 || + id == MI_TREE11 || + id == MI_TREE12 || + id == MI_TREE13 || + id == MI_TREE14; +} + +inline bool +IsBannerModel(int16 id) +{ + return id == MI_CHINABANNER1 || + id == MI_CHINABANNER2 || + id == MI_CHINABANNER3 || + id == MI_CHINABANNER4 || + id == MI_CHINABANNER5 || + id == MI_CHINABANNER6 || + id == MI_CHINABANNER7 || + id == MI_CHINABANNER8 || + id == MI_CHINABANNER9 || + id == MI_CHINABANNER10 || + id == MI_CHINABANNER11 || + id == MI_CHINABANNER12 || + id == MI_ITALYBANNER1 || + id == MI_CHINALANTERN; +} +inline bool +IsPickupModel(int16 id) +{ + return id == MI_GRENADE || + id == MI_AK47 || + id == MI_BASEBALL_BAT || + id == MI_COLT || + id == MI_MOLOTOV || + id == MI_ROCKETLAUNCHER || + id == MI_SHOTGUN || + id == MI_SNIPER || + id == MI_UZI || + id == MI_M16 || + id == MI_FLAMETHROWER || + id >= MI_M16 && id <= MI_FLAMETHROWER || + id == MI_PICKUP_ADRENALINE || + id == MI_PICKUP_BODYARMOUR || + id == MI_PICKUP_INFO || + id == MI_PICKUP_HEALTH || + id == MI_PICKUP_BONUS || + id == MI_PICKUP_BRIBE || + id == MI_PICKUP_KILLFRENZY || + id == MI_PICKUP_CAMERA; +} diff --git a/src/re3.cpp b/src/re3.cpp index 3df44620..87552214 100644 --- a/src/re3.cpp +++ b/src/re3.cpp @@ -188,6 +188,7 @@ DebugMenuPopulate(void) DebugMenuEntrySetWrap(e, true); e = DebugMenuAddVar("Time & Weather", "New Weather", (int16*)&CWeather::NewWeatherType, nil, 1, 0, 3, weathers); DebugMenuEntrySetWrap(e, true); + DebugMenuAddVar("Time & Weather", "Wind", (float*)&CWeather::Wind, nil, 0.1f, 0.0f, 1.0f); DebugMenuAddVar("Time & Weather", "Time scale", (float*)0x8F2C20, nil, 0.1f, 0.0f, 10.0f); DebugMenuAddCmd("Cheats", "Weapons", WeaponCheat); diff --git a/src/render/2dEffect.h b/src/render/2dEffect.h index 780d9b4f..1610f908 100644 --- a/src/render/2dEffect.h +++ b/src/render/2dEffect.h @@ -4,19 +4,45 @@ enum { EFFECT_ATTRACTOR }; +enum { + LIGHT_ON, + LIGHT_ON_NIGHT, + LIGHT_FLICKER, + LIGHT_FLICKER_NIGHT, + LIGHT_FLASH1, + LIGHT_FLASH1_NIGHT, + LIGHT_FLASH2, + LIGHT_FLASH2_NIGHT, + LIGHT_FLASH3, + LIGHT_FLASH3_NIGHT, + LIGHT_RANDOM_FLICKER, + LIGHT_RANDOM_FLICKER_NIGHT, + LIGHT_SPECIAL, + LIGHT_BRIDGE_FLASH1, + LIGHT_BRIDGE_FLASH2, +}; + +enum { + LIGHTFLAG_LOSCHECK = 1, + // same order as CPointLights flags, must start at 2 + LIGHTFLAG_FOG_NORMAL = 2, // can have light and fog + LIGHTFLAG_FOG_ALWAYS = 4, // fog only + LIGHTFLAG_FOG = (LIGHTFLAG_FOG_NORMAL|LIGHTFLAG_FOG_ALWAYS) +}; + class C2dEffect { public: struct Light { float dist; - float outerRange; + float range; // of pointlight float size; - float innerRange; - uint8 flash; + float shadowRange; + uint8 lightType; // LIGHT_ uint8 roadReflection; uint8 flareType; uint8 shadowIntensity; - uint8 flags; + uint8 flags; // LIGHTFLAG_ RwTexture *corona; RwTexture *shadow; }; diff --git a/src/render/Glass.cpp b/src/render/Glass.cpp index aba8f9e0..9a233584 100644 --- a/src/render/Glass.cpp +++ b/src/render/Glass.cpp @@ -2,6 +2,8 @@ #include "patcher.h" #include "Glass.h" +WRAPPER void CGlass::AskForObjectToBeRenderedInGlass(CEntity *ent) { EAXJMP(0x5033F0); } + WRAPPER void CGlass::WindowRespondsToCollision(CEntity *ent, float amount, CVector speed, CVector point, bool foo) { diff --git a/src/render/Glass.h b/src/render/Glass.h index 460c4548..60592c39 100644 --- a/src/render/Glass.h +++ b/src/render/Glass.h @@ -5,6 +5,7 @@ class CEntity; class CGlass { 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); diff --git a/src/render/PointLights.cpp b/src/render/PointLights.cpp index 2b840314..9e98a327 100644 --- a/src/render/PointLights.cpp +++ b/src/render/PointLights.cpp @@ -13,8 +13,6 @@ int16 &CPointLights::NumLights = *(int16*)0x95CC3E; CRegisteredPointLight *CPointLights::aLights = (CRegisteredPointLight*)0x7096D0; -//WRAPPER void CPointLights::RenderFogEffect(void) { EAXJMP(0x510C30); } - void CPointLights::InitPerFrame(void) { @@ -69,7 +67,7 @@ CPointLights::GenerateLightsAffectingObject(CVector *objCoors) ret = 1.0f; for(i = 0; i < NumLights; i++){ - if(aLights[i].type == LIGHT_FOGONLY_3 || aLights[i].type == LIGHT_FOGONLY_4) + if(aLights[i].type == LIGHT_FOGONLY || aLights[i].type == LIGHT_FOGONLY_ALWAYS) continue; // same weird distance calculation. simplified here @@ -235,7 +233,7 @@ CPointLights::RenderFogEffect(void) } } - }else if(aLights[i].type == LIGHT_POINT || aLights[i].type == LIGHT_FOGONLY_3 || aLights[i].type == LIGHT_FOGONLY_4){ + }else if(aLights[i].type == LIGHT_POINT || aLights[i].type == LIGHT_FOGONLY || aLights[i].type == LIGHT_FOGONLY_ALWAYS){ if(CWorld::ProcessVerticalLine(aLights[i].coors, aLights[i].coors.z - 20.0f, point, entity, true, false, false, false, true, false, nil)){ diff --git a/src/render/PointLights.h b/src/render/PointLights.h index 288571d0..c350e4c8 100644 --- a/src/render/PointLights.h +++ b/src/render/PointLights.h @@ -26,8 +26,10 @@ public: LIGHT_DIRECTIONAL, LIGHT_DARKEN, // no effects at all // these have only fog, otherwise no difference? - LIGHT_FOGONLY_3, - LIGHT_FOGONLY_4, + // only used by CEntity::ProcessLightsForEntity it seems + // and there used together with fog type + LIGHT_FOGONLY_ALWAYS, + LIGHT_FOGONLY, }; enum { FOG_NONE, diff --git a/src/render/Shadows.cpp b/src/render/Shadows.cpp index cb5cedfb..0852938f 100644 --- a/src/render/Shadows.cpp +++ b/src/render/Shadows.cpp @@ -7,6 +7,16 @@ WRAPPER void CShadows::RenderStaticShadows(void) { EAXJMP(0x5145F0); } WRAPPER void CShadows::RenderStoredShadows(void) { EAXJMP(0x514010); } WRAPPER void CShadows::RenderExtraPlayerShadows(void) { EAXJMP(0x516F90); } WRAPPER void CShadows::CalcPedShadowValues(CVector light, float *frontX, float *frontY, float *sideX, float *sideY, float *dispX, float *dispY) { EAXJMP(0x516EB0); } +WRAPPER void CShadows::StoreShadowForPole(CEntity *ent, float offsetX, float offsetY, float offsetZ, float poleHeight, float poleWidth, uint32 subId) { EAXJMP(0x513E10); } WRAPPER void CShadows::StoreShadowForPedObject(CEntity *ent, float dispX, float dispY, float frontX, float frontY, float sideX, float sideY) { EAXJMP(0x513CB0); } +WRAPPER void CShadows::StoreStaticShadow(uint32 id, uint8 type, RwTexture *texture, CVector *coors, float frontX, float frontY, float sideX, float sideY, int16 intensity, uint8 red, uint8 green, uint8 blue, float zDistance, float scale, float drawDistance, bool temporaryShadow, float upDistance) { EAXJMP(0x5130A0); } +WRAPPER void CShadows::StoreShadowToBeRendered(uint8 type, RwTexture *texture, CVector *coors, float frontX, float frontY, float sideX, float sideY, int16 intensity, uint8 red, uint8 green, uint8 blue, float zDistance, bool drawOnWater, float upDistance) { EAXJMP(0x513750); } -RwTexture*& gpBloodPoolTex = *(RwTexture * *)0x9415F8; \ No newline at end of file +RwTexture *&gpBloodPoolTex = *(RwTexture**)0x9415F8; +RwTexture *&gpShadowExplosionTex = *(RwTexture**)0x8F2A00; + +void +CShadows::StoreShadowForTree(CEntity *ent) +{ + // empty +} diff --git a/src/render/Shadows.h b/src/render/Shadows.h index 2a41f81e..37749de4 100644 --- a/src/render/Shadows.h +++ b/src/render/Shadows.h @@ -3,6 +3,11 @@ struct RwTexture; class CEntity; +enum +{ + SHADOWTYPE_2 = 2 +}; + class CShadows { public: @@ -11,7 +16,12 @@ public: static void RenderStoredShadows(void); static void RenderExtraPlayerShadows(void); static void CalcPedShadowValues(CVector light, float *frontX, float *frontY, float *sideX, float *sideY, float *dispX, float *dispY); + static void StoreShadowForTree(CEntity *ent); + static void StoreShadowForPole(CEntity *ent, float offsetX, float offsetY, float offsetZ, float poleHeight, float poleWidth, uint32 subId); static void StoreShadowForPedObject(CEntity *ent, float dispX, float dispY, float frontX, float frontY, float sideX, float sideY); + static void StoreStaticShadow(uint32 id, uint8 type, RwTexture *texture, CVector *coors, float frontX, float frontY, float sideX, float sideY, int16 intensity, uint8 red, uint8 green, uint8 blue, float zDistance, float scale, float drawDistance, bool temporaryShadow, float upDistance);; + static void StoreShadowToBeRendered(uint8 type, RwTexture *texture, CVector *coors, float frontX, float frontY, float sideX, float sideY, int16 intensity, uint8 red, uint8 green, uint8 blue, float zDistance, bool drawOnWater, float upDistance); }; -extern RwTexture*& gpBloodPoolTex; +extern RwTexture *&gpBloodPoolTex; +extern RwTexture *&gpShadowExplosionTex; diff --git a/src/render/SpecialFX.cpp b/src/render/SpecialFX.cpp index 3aa60f2f..32923b12 100644 --- a/src/render/SpecialFX.cpp +++ b/src/render/SpecialFX.cpp @@ -3,3 +3,5 @@ #include "SpecialFX.h" WRAPPER void CSpecialFX::Render(void) { EAXJMP(0x518DC0); } + +WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); } diff --git a/src/render/SpecialFX.h b/src/render/SpecialFX.h index ffa2a90a..1a1a4c1e 100644 --- a/src/render/SpecialFX.h +++ b/src/render/SpecialFX.h @@ -5,3 +5,9 @@ class CSpecialFX public: static void Render(void); }; + +class CMotionBlurStreaks +{ +public: + static void RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2); +};