Merge pull request #385 from aap/master

implemented CRubbish, CShinyTexts, CBrightLights, CMotionBlurStreaks, CSpecialFX
This commit is contained in:
aap 2020-04-08 09:12:49 +02:00 committed by GitHub
commit f89df29001
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1296 additions and 129 deletions

View File

@ -40,14 +40,9 @@ to reverse at the time, calling the original functions is acceptable.
``` ```
cAudioManager - WIP cAudioManager - WIP
CBoat CBoat
CBrightLights
CBulletInfo CBulletInfo
CCullZone - only mobile stuff
CCullZones - only mobile stuff
CExplosion CExplosion
CFileLoader - almost done
CMenuManager - WIP CMenuManager - WIP
CMotionBlurStreaks
CObject CObject
CPacManPickups CPacManPickups
CPad - only cheats CPad - only cheats
@ -56,10 +51,7 @@ CPools - save/loading
CRecordDataForChase CRecordDataForChase
CRecordDataForGame CRecordDataForGame
CRoadBlocks CRoadBlocks
CRubbish
CSceneEdit
CSkidmarks CSkidmarks
CSpecialFX
CStats CStats
CTrafficLights CTrafficLights
CWeapon CWeapon
@ -68,6 +60,14 @@ CWorld
GenericLoad GenericLoad
``` ```
The following classes have only unused or practically unused code left:
```
CCullZone - only mobile stuff
CCullZones - only mobile stuff
CFileLoader - almost done
CSceneEdit
```
### Coding style ### Coding style
I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style), I started writing in [Plan 9 style](http://man.cat-v.org/plan_9/6/style),

View File

@ -73,9 +73,12 @@ enum Config {
NUMCORONAS = 56, NUMCORONAS = 56,
NUMPOINTLIGHTS = 32, NUMPOINTLIGHTS = 32,
NUM3DMARKERS = 32, NUM3DMARKERS = 32,
NUMBRIGHTLIGHTS = 32,
NUMSHINYTEXTS = 32,
NUMMONEYMESSAGES = 16, NUMMONEYMESSAGES = 16,
NUMPICKUPMESSAGES = 16, NUMPICKUPMESSAGES = 16,
NUMBULLETTRACES = 16, NUMBULLETTRACES = 16,
NUMMBLURSTREAKS = 4,
NUMONSCREENTIMERENTRIES = 1, NUMONSCREENTIMERENTRIES = 1,
NUMRADARBLIPS = 32, NUMRADARBLIPS = 32,

View File

@ -394,13 +394,13 @@ CEntity::PreRender(void)
}else if(GetModelIndex() == MI_GRENADE){ }else if(GetModelIndex() == MI_GRENADE){
CMotionBlurStreaks::RegisterStreak((uintptr)this, CMotionBlurStreaks::RegisterStreak((uintptr)this,
100, 100, 100, 100, 100, 100,
TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(), GetPosition() - 0.07f*TheCamera.GetRight(),
TheCamera.GetPosition() + 0.07f*TheCamera.GetRight()); GetPosition() + 0.07f*TheCamera.GetRight());
}else if(GetModelIndex() == MI_MOLOTOV){ }else if(GetModelIndex() == MI_MOLOTOV){
CMotionBlurStreaks::RegisterStreak((uintptr)this, CMotionBlurStreaks::RegisterStreak((uintptr)this,
0, 100, 0, 0, 100, 0,
TheCamera.GetPosition() - 0.07f*TheCamera.GetRight(), GetPosition() - 0.07f*TheCamera.GetRight(),
TheCamera.GetPosition() + 0.07f*TheCamera.GetRight()); GetPosition() + 0.07f*TheCamera.GetRight());
} }
}else if(GetModelIndex() == MI_MISSILE){ }else if(GetModelIndex() == MI_MISSILE){
CVector pos = GetPosition(); CVector pos = GetPosition();

View File

@ -1,10 +1,420 @@
#include "common.h" #include "common.h"
#include "main.h"
#include "patcher.h" #include "patcher.h"
#include "General.h"
#include "Timer.h"
#include "Weather.h"
#include "Camera.h"
#include "World.h"
#include "Vehicle.h"
#include "ZoneCull.h"
#include "TxdStore.h"
#include "RenderBuffer.h"
#include "Rubbish.h" #include "Rubbish.h"
WRAPPER void CRubbish::Render(void) { EAXJMP(0x512190); } #define RUBBISH_MAX_DIST (18.0f)
WRAPPER void CRubbish::StirUp(CVehicle *veh) { EAXJMP(0x512690); } #define RUBBISH_FADE_DIST (16.5f)
WRAPPER void CRubbish::Update(void) { EAXJMP(0x511B90); }
WRAPPER void CRubbish::SetVisibility(bool) { EAXJMP(0x512AA0); } RwTexture *gpRubbishTexture[4];
WRAPPER void CRubbish::Init(void) { EAXJMP(0x511940); } RwImVertexIndex RubbishIndexList[6];
WRAPPER void CRubbish::Shutdown(void) { EAXJMP(0x511B50); } RwImVertexIndex RubbishIndexList2[6]; // unused
RwIm3DVertex RubbishVertices[4];
bool CRubbish::bRubbishInvisible;
int CRubbish::RubbishVisibility;
COneSheet CRubbish::aSheets[NUM_RUBBISH_SHEETS];
COneSheet CRubbish::StartEmptyList;
COneSheet CRubbish::EndEmptyList;
COneSheet CRubbish::StartStaticsList;
COneSheet CRubbish::EndStaticsList;
COneSheet CRubbish::StartMoversList;
COneSheet CRubbish::EndMoversList;
void
COneSheet::AddToList(COneSheet *list)
{
this->m_next = list->m_next;
this->m_prev = list;
list->m_next = this;
this->m_next->m_prev = this;
}
void
COneSheet::RemoveFromList(void)
{
m_next->m_prev = m_prev;
m_prev->m_next = m_next;
}
void
CRubbish::Render(void)
{
int type;
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)TRUE);
for(type = 0; type < 4; type++){
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpRubbishTexture[type]));
TempBufferIndicesStored = 0;
TempBufferVerticesStored = 0;
COneSheet *sheet;
for(sheet = &aSheets[type*NUM_RUBBISH_SHEETS / 4];
sheet < &aSheets[(type+1)*NUM_RUBBISH_SHEETS / 4];
sheet++){
if(sheet->m_state == 0)
continue;
uint32 alpha = 128;
CVector pos;
if(sheet->m_state == 1){
pos = sheet->m_basePos;
if(!sheet->m_isVisible)
alpha = 0;
}else{
pos = sheet->m_animatedPos;
// Not fully visible during animation, calculate current alpha
if(!sheet->m_isVisible || !sheet->m_targetIsVisible){
float t = (float)(CTimer::GetTimeInMilliseconds() - sheet->m_moveStart)/sheet->m_moveDuration;
float f1 = sheet->m_isVisible ? 1.0f-t : 0.0f;
float f2 = sheet->m_targetIsVisible ? t : 0.0f;
alpha = 128 * (f1+f2);
}
}
float camDist = (pos - TheCamera.GetPosition()).Magnitude2D();
if(camDist < RUBBISH_MAX_DIST){
if(camDist >= RUBBISH_FADE_DIST)
alpha -= alpha*(camDist-RUBBISH_FADE_DIST)/(RUBBISH_MAX_DIST-RUBBISH_FADE_DIST);
alpha = (RubbishVisibility*alpha)/256;
float vx = Sin(sheet->m_angle) * 0.4f;
float vy = Cos(sheet->m_angle) * 0.4f;
int v = TempBufferVerticesStored;
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], pos.x + vx, pos.y + vy, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], pos.x - vy, pos.y + vx, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], pos.x + vy, pos.y - vx, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], 255, 255, 255, alpha);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], pos.x - vx, pos.y - vy, pos.z);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], 255, 255, 255, alpha);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], 0.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], 0.0f);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], 1.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], 0.0f);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], 0.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], 1.0f);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], 1.0f);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], 1.0f);
int i = TempBufferIndicesStored;
TempBufferRenderIndexList[i+0] = RubbishIndexList[0] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+1] = RubbishIndexList[1] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+2] = RubbishIndexList[2] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+3] = RubbishIndexList[3] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+4] = RubbishIndexList[4] + TempBufferVerticesStored;
TempBufferRenderIndexList[i+5] = RubbishIndexList[5] + TempBufferVerticesStored;
TempBufferVerticesStored += 4;
TempBufferIndicesStored += 6;
}
}
if(TempBufferIndicesStored != 0){
LittleTest();
if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
RwIm3DEnd();
}
}
}
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
}
void
CRubbish::StirUp(CVehicle *veh)
{
if((CTimer::GetFrameCounter() ^ (veh->m_randomSeed&3)) == 0)
return;
if(Abs(veh->GetPosition().x - TheCamera.GetPosition().x) < 20.0f &&
Abs(veh->GetPosition().y - TheCamera.GetPosition().y) < 20.0f)
if(Abs(veh->GetMoveSpeed().x) > 0.05f || Abs(veh->GetMoveSpeed().y) > 0.05f){
float speed = veh->GetMoveSpeed().Magnitude2D();
if(speed > 0.05f){
bool movingForward = DotProduct2D(veh->GetMoveSpeed(), veh->GetForward()) > 0.0f;
COneSheet *sheet = StartStaticsList.m_next;
CVector2D size = veh->GetColModel()->boundingBox.max;
// Check all static sheets
while(sheet != &EndStaticsList){
COneSheet *next = sheet->m_next;
CVector2D carToSheet = sheet->m_basePos - veh->GetPosition();
float distFwd = DotProduct2D(carToSheet, veh->GetForward());
// sheet has to be a bit behind car
if(movingForward && distFwd < -0.5f*size.y && distFwd > -1.5f*size.y ||
!movingForward && distFwd > 0.5f*size.y && distFwd < 1.5f*size.y){
float distSide = Abs(DotProduct2D(carToSheet, veh->GetRight()));
if(distSide < 1.5*size.x){
// Check with higher speed for sheet directly behind car
float speedToCheck = distSide < size.x ? speed : speed*0.5f;
if(speedToCheck > 0.05f){
sheet->m_state = 2;
if(speedToCheck > 0.15f)
sheet->m_animationType = 2;
else
sheet->m_animationType = 1;
sheet->m_moveDuration = 2000;
sheet->m_xDist = veh->GetMoveSpeed().x;
sheet->m_yDist = veh->GetMoveSpeed().y;
float dist = Sqrt(SQR(sheet->m_xDist)+SQR(sheet->m_yDist));
sheet->m_xDist *= 25.0f*speed/dist;
sheet->m_yDist *= 25.0f*speed/dist;
sheet->m_animHeight = 3.0f*speed;
sheet->m_moveStart = CTimer::GetTimeInMilliseconds();
float tx = sheet->m_basePos.x + sheet->m_xDist;
float ty = sheet->m_basePos.y + sheet->m_yDist;
float tz = sheet->m_basePos.z + 3.0f;
sheet->m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, nil) + 0.1f;
sheet->RemoveFromList();
sheet->AddToList(&StartMoversList);
}
}
}
sheet = next;
}
}
}
}
static float aAnimations[3][34] = {
{ 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f },
// Normal move
{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.86f, 0.9f, 0.93f, 0.95f, 0.96f, 0.97f, 0.98f, 0.99f, 1.0f, // XY movemnt
0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }, // Z movement
// Stirred up by fast vehicle
{ 0.0f, 0.05f, 0.12f, 0.25f, 0.42f, 0.57f, 0.68f, 0.8f, 0.95f, 1.1f, 1.15f, 1.18f, 1.15f, 1.1f, 1.05f, 1.03f, 1.0f,
0.15f, 0.35f, 0.6f, 0.9f, 1.2f, 1.25f, 1.3f, 1.2f, 1.1f, 0.95f, 0.8f, 0.6f, 0.45f, 0.3f, 0.2f, 0.1f, 0 }
};
void
CRubbish::Update(void)
{
bool foundGround;
// FRAMETIME
if(bRubbishInvisible)
RubbishVisibility = max(RubbishVisibility-5, 0);
else
RubbishVisibility = min(RubbishVisibility+5, 255);
// Spawn a new sheet
COneSheet *sheet = StartEmptyList.m_next;
if(sheet != &EndEmptyList){
float spawnDist;
float spawnAngle;
spawnDist = (CGeneral::GetRandomNumber()&0xFF)/256.0f + RUBBISH_MAX_DIST;
uint8 r = CGeneral::GetRandomNumber();
if(r&1)
spawnAngle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
else
spawnAngle = (r-128)/160.0f + TheCamera.Orientation;
sheet->m_basePos.x = TheCamera.GetPosition().x + spawnDist*Sin(spawnAngle);
sheet->m_basePos.y = TheCamera.GetPosition().y + spawnDist*Cos(spawnAngle);
sheet->m_basePos.z = CWorld::FindGroundZFor3DCoord(sheet->m_basePos.x, sheet->m_basePos.y, TheCamera.GetPosition().z, &foundGround) + 0.1f;
if(foundGround){
// Found ground, so add to statics list
sheet->m_angle = (CGeneral::GetRandomNumber()&0xFF)/256.0f * 6.28f;
sheet->m_state = 1;
if(CCullZones::FindAttributesForCoors(sheet->m_basePos, nil) & ATTRZONE_NORAIN)
sheet->m_isVisible = false;
else
sheet->m_isVisible = true;
sheet->RemoveFromList();
sheet->AddToList(&StartStaticsList);
}
}
// Process animation
sheet = StartMoversList.m_next;
while(sheet != &EndMoversList){
uint32 currentTime = CTimer::GetTimeInMilliseconds() - sheet->m_moveStart;
if(currentTime < sheet->m_moveDuration){
// Animation
int step = 16 * currentTime / sheet->m_moveDuration; // 16 steps in animation
int stepTime = sheet->m_moveDuration/16; // time in each step
float s = (float)(currentTime - stepTime*step) / stepTime; // position on step
float t = (float)currentTime / sheet->m_moveDuration; // position on total animation
// factors for xy and z-movment
float fxy = aAnimations[sheet->m_animationType][step]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1]*s;
float fz = aAnimations[sheet->m_animationType][step+17]*(1.0f-s) + aAnimations[sheet->m_animationType][step+1+17]*s;
sheet->m_animatedPos.x = sheet->m_basePos.x + fxy*sheet->m_xDist;
sheet->m_animatedPos.y = sheet->m_basePos.y + fxy*sheet->m_yDist;
sheet->m_animatedPos.z = (1.0f-t)*sheet->m_basePos.z + t*sheet->m_targetZ + fz*sheet->m_animHeight;
sheet->m_angle += CTimer::GetTimeStep()*0.04f;
if(sheet->m_angle > 6.28f)
sheet->m_angle -= 6.28f;
sheet = sheet->m_next;
}else{
// End of animation, back into statics list
sheet->m_basePos.x += sheet->m_xDist;
sheet->m_basePos.y += sheet->m_yDist;
sheet->m_basePos.z = sheet->m_targetZ;
sheet->m_state = 1;
sheet->m_isVisible = sheet->m_targetIsVisible;
COneSheet *next = sheet->m_next;
sheet->RemoveFromList();
sheet->AddToList(&StartStaticsList);
sheet = next;
}
}
// Stir up a sheet by wind
// FRAMETIME
int freq;
if(CWeather::Wind < 0.1f)
freq = 31;
else if(CWeather::Wind < 0.4f)
freq = 7;
else if(CWeather::Wind < 0.7f)
freq = 1;
else
freq = 0;
if((CTimer::GetFrameCounter() & freq) == 0){
// Pick a random sheet and set animation state if static
int i = CGeneral::GetRandomNumber() % NUM_RUBBISH_SHEETS;
if(aSheets[i].m_state == 1){
aSheets[i].m_moveStart = CTimer::GetTimeInMilliseconds();
aSheets[i].m_moveDuration = CWeather::Wind*1500.0f + 1000.0f;
aSheets[i].m_animHeight = 0.2f;
aSheets[i].m_xDist = 3.0f*CWeather::Wind;
aSheets[i].m_yDist = 3.0f*CWeather::Wind;
// Check if target position is ok
float tx = aSheets[i].m_basePos.x + aSheets[i].m_xDist;
float ty = aSheets[i].m_basePos.y + aSheets[i].m_yDist;
float tz = aSheets[i].m_basePos.z + 3.0f;
aSheets[i].m_targetZ = CWorld::FindGroundZFor3DCoord(tx, ty, tz, &foundGround) + 0.1f;
if(CCullZones::FindAttributesForCoors(CVector(tx, ty, aSheets[i].m_targetZ), nil) & ATTRZONE_NORAIN)
aSheets[i].m_targetIsVisible = false;
else
aSheets[i].m_targetIsVisible = true;
if(foundGround){
// start animation
aSheets[i].m_state = 2;
aSheets[i].m_animationType = 1;
aSheets[i].RemoveFromList();
aSheets[i].AddToList(&StartMoversList);
}
}
}
// Remove sheets that are too far away
int i = (CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4))*4;
int last = ((CTimer::GetFrameCounter()%(NUM_RUBBISH_SHEETS/4)) + 1)*4;
for(; i < last; i++){
if(aSheets[i].m_state == 1 &&
(aSheets[i].m_basePos - TheCamera.GetPosition()).MagnitudeSqr2D() > SQR(RUBBISH_MAX_DIST+1.0f)){
aSheets[i].m_state = 0;
aSheets[i].RemoveFromList();
aSheets[i].AddToList(&StartEmptyList);
}
}
}
void
CRubbish::SetVisibility(bool visible)
{
bRubbishInvisible = !visible;
}
void
CRubbish::Init(void)
{
int i;
for(i = 0; i < NUM_RUBBISH_SHEETS; i++){
aSheets[i].m_state = 0;
if(i < NUM_RUBBISH_SHEETS-1)
aSheets[i].m_next = &aSheets[i+1];
else
aSheets[i].m_next = &EndEmptyList;
if(i > 0)
aSheets[i].m_prev = &aSheets[i-1];
else
aSheets[i].m_prev = &StartEmptyList;
}
StartEmptyList.m_next = &aSheets[0];
StartEmptyList.m_prev = nil;
EndEmptyList.m_next = nil;
EndEmptyList.m_prev = &aSheets[NUM_RUBBISH_SHEETS-1];
StartStaticsList.m_next = &EndStaticsList;
StartStaticsList.m_prev = nil;
EndStaticsList.m_next = nil;
EndStaticsList.m_prev = &StartStaticsList;
StartMoversList.m_next = &EndMoversList;
StartMoversList.m_prev = nil;
EndMoversList.m_next = nil;
EndMoversList.m_prev = &StartMoversList;
// unused
RwIm3DVertexSetU(&RubbishVertices[0], 0.0f);
RwIm3DVertexSetV(&RubbishVertices[0], 0.0f);
RwIm3DVertexSetU(&RubbishVertices[1], 1.0f);
RwIm3DVertexSetV(&RubbishVertices[1], 0.0f);
RwIm3DVertexSetU(&RubbishVertices[2], 0.0f);
RwIm3DVertexSetV(&RubbishVertices[2], 1.0f);
RwIm3DVertexSetU(&RubbishVertices[3], 1.0f);
RwIm3DVertexSetV(&RubbishVertices[3], 1.0f);
// unused
RubbishIndexList2[0] = 0;
RubbishIndexList2[1] = 2;
RubbishIndexList2[2] = 1;
RubbishIndexList2[3] = 1;
RubbishIndexList2[4] = 2;
RubbishIndexList2[5] = 3;
RubbishIndexList[0] = 0;
RubbishIndexList[1] = 1;
RubbishIndexList[2] = 2;
RubbishIndexList[3] = 1;
RubbishIndexList[4] = 3;
RubbishIndexList[5] = 2;
CTxdStore::PushCurrentTxd();
int slot = CTxdStore::FindTxdSlot("particle");
CTxdStore::SetCurrentTxd(slot);
gpRubbishTexture[0] = RwTextureRead("gameleaf01_64", nil);
gpRubbishTexture[1] = RwTextureRead("gameleaf02_64", nil);
gpRubbishTexture[2] = RwTextureRead("newspaper01_64", nil);
gpRubbishTexture[3] = RwTextureRead("newspaper02_64", nil);
CTxdStore::PopCurrentTxd();
RubbishVisibility = 255;
bRubbishInvisible = false;
}
void
CRubbish::Shutdown(void)
{
RwTextureDestroy(gpRubbishTexture[0]);
RwTextureDestroy(gpRubbishTexture[1]);
RwTextureDestroy(gpRubbishTexture[2]);
RwTextureDestroy(gpRubbishTexture[3]);
}

View File

@ -2,13 +2,50 @@
class CVehicle; class CVehicle;
enum {
// NB: not all values are allowed, check the code
NUM_RUBBISH_SHEETS = 64
};
class COneSheet
{
public:
CVector m_basePos;
CVector m_animatedPos;
float m_targetZ;
int8 m_state;
int8 m_animationType;
uint32 m_moveStart;
uint32 m_moveDuration;
float m_animHeight;
float m_xDist;
float m_yDist;
float m_angle;
bool m_isVisible;
bool m_targetIsVisible;
COneSheet *m_next;
COneSheet *m_prev;
void AddToList(COneSheet *list);
void RemoveFromList(void);
};
class CRubbish class CRubbish
{ {
static bool bRubbishInvisible;
static int RubbishVisibility;
static COneSheet aSheets[NUM_RUBBISH_SHEETS];
static COneSheet StartEmptyList;
static COneSheet EndEmptyList;
static COneSheet StartStaticsList;
static COneSheet EndStaticsList;
static COneSheet StartMoversList;
static COneSheet EndMoversList;
public: public:
static void Render(void); static void Render(void);
static void StirUp(CVehicle *veh); // CAutomobile on PS2 static void StirUp(CVehicle *veh); // CAutomobile on PS2
static void Update(void); static void Update(void);
static void SetVisibility(bool); static void SetVisibility(bool visible);
static void Init(void); static void Init(void);
static void Shutdown(void); static void Shutdown(void);
}; };

View File

@ -175,11 +175,18 @@ public:
static void RenderIndicatorShadow (uint32 nID, uint8 ShadowType, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity); static void RenderIndicatorShadow (uint32 nID, uint8 ShadowType, RwTexture *pTexture, CVector *pPosn, float fFrontX, float fFrontY, float fSideX, float fSideY, int16 nIntensity);
}; };
extern RwTexture *&gpBloodPoolTex; extern RwTexture *&gpShadowCarTex;
extern RwTexture *&gpShadowPedTex;
extern RwTexture *&gpShadowHeliTex;
extern RwTexture *&gpShadowExplosionTex; extern RwTexture *&gpShadowExplosionTex;
extern RwTexture *&gpShadowHeadLightsTex; extern RwTexture *&gpShadowHeadLightsTex;
extern RwTexture *&gpGoalTex;
extern RwTexture *&gpOutline1Tex; extern RwTexture *&gpOutline1Tex;
extern RwTexture *&gpOutline2Tex; extern RwTexture *&gpOutline2Tex;
extern RwTexture *&gpOutline3Tex; extern RwTexture *&gpOutline3Tex;
extern RwTexture *&gpBloodPoolTex;
extern RwTexture *&gpReflectionTex;
extern RwTexture *&gpGoalMarkerTex;
extern RwTexture *&gpWalkDontTex;
extern RwTexture *&gpCrackedGlassTex; extern RwTexture *&gpCrackedGlassTex;
extern RwTexture *&gpPostShadowTex;
extern RwTexture *&gpGoalTex;

View File

@ -1,6 +1,7 @@
#include "common.h" #include "common.h"
#include "patcher.h" #include "patcher.h"
#include "SpecialFX.h" #include "SpecialFX.h"
#include "RenderBuffer.h"
#include "Timer.h" #include "Timer.h"
#include "Sprite.h" #include "Sprite.h"
#include "Font.h" #include "Font.h"
@ -8,26 +9,260 @@
#include "TxdStore.h" #include "TxdStore.h"
#include "FileMgr.h" #include "FileMgr.h"
#include "FileLoader.h" #include "FileLoader.h"
#include "Timecycle.h"
#include "Lights.h" #include "Lights.h"
#include "ModelIndices.h"
#include "VisibilityPlugins.h" #include "VisibilityPlugins.h"
#include "World.h" #include "World.h"
#include "PlayerPed.h"
#include "Particle.h" #include "Particle.h"
#include "Shadows.h"
#include "General.h" #include "General.h"
#include "Camera.h" #include "Camera.h"
#include "Shadows.h" #include "Shadows.h"
#include "main.h" #include "main.h"
WRAPPER void CSpecialFX::Render(void) { EAXJMP(0x518DC0); } RxObjSpace3DVertex StreakVertices[4];
WRAPPER void CSpecialFX::Update(void) { EAXJMP(0x518D40); } RwImVertexIndex StreakIndexList[12];
WRAPPER void CSpecialFX::Init(void) { EAXJMP(0x5189E0); }
WRAPPER void CSpecialFX::Shutdown(void) { EAXJMP(0x518BE0); }
WRAPPER void CMotionBlurStreaks::RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2) { EAXJMP(0x519460); } RxObjSpace3DVertex TraceVertices[6];
RwImVertexIndex TraceIndexList[12];
CBulletTrace (&CBulletTraces::aTraces)[NUMBULLETTRACES] = *(CBulletTrace(*)[NUMBULLETTRACES])*(uintptr*)0x72B1B8; void
RxObjSpace3DVertex (&TraceVertices)[6] = *(RxObjSpace3DVertex(*)[6])*(uintptr*)0x649884; CSpecialFX::Init(void)
RwImVertexIndex (&TraceIndexList)[12] = *(RwImVertexIndex(*)[12])*(uintptr*)0x64986C; {
CBulletTraces::Init();
RwIm3DVertexSetU(&StreakVertices[0], 0.0f);
RwIm3DVertexSetV(&StreakVertices[0], 0.0f);
RwIm3DVertexSetU(&StreakVertices[1], 1.0f);
RwIm3DVertexSetV(&StreakVertices[1], 0.0f);
RwIm3DVertexSetU(&StreakVertices[2], 0.0f);
RwIm3DVertexSetV(&StreakVertices[2], 0.0f);
RwIm3DVertexSetU(&StreakVertices[3], 1.0f);
RwIm3DVertexSetV(&StreakVertices[3], 0.0f);
StreakIndexList[0] = 0;
StreakIndexList[1] = 1;
StreakIndexList[2] = 2;
StreakIndexList[3] = 1;
StreakIndexList[4] = 3;
StreakIndexList[5] = 2;
StreakIndexList[6] = 0;
StreakIndexList[7] = 2;
StreakIndexList[8] = 1;
StreakIndexList[9] = 1;
StreakIndexList[10] = 2;
StreakIndexList[11] = 3;
RwIm3DVertexSetRGBA(&TraceVertices[0], 20, 20, 20, 255);
RwIm3DVertexSetRGBA(&TraceVertices[1], 20, 20, 20, 255);
RwIm3DVertexSetRGBA(&TraceVertices[2], 70, 70, 70, 255);
RwIm3DVertexSetRGBA(&TraceVertices[3], 70, 70, 70, 255);
RwIm3DVertexSetRGBA(&TraceVertices[4], 10, 10, 10, 255);
RwIm3DVertexSetRGBA(&TraceVertices[5], 10, 10, 10, 255);
RwIm3DVertexSetU(&TraceVertices[0], 0.0);
RwIm3DVertexSetV(&TraceVertices[0], 0.0);
RwIm3DVertexSetU(&TraceVertices[1], 1.0);
RwIm3DVertexSetV(&TraceVertices[1], 0.0);
RwIm3DVertexSetU(&TraceVertices[2], 0.0);
RwIm3DVertexSetV(&TraceVertices[2], 0.5);
RwIm3DVertexSetU(&TraceVertices[3], 1.0);
RwIm3DVertexSetV(&TraceVertices[3], 0.5);
RwIm3DVertexSetU(&TraceVertices[4], 0.0);
RwIm3DVertexSetV(&TraceVertices[4], 1.0);
RwIm3DVertexSetU(&TraceVertices[5], 1.0);
RwIm3DVertexSetV(&TraceVertices[5], 1.0);
TraceIndexList[0] = 0;
TraceIndexList[1] = 2;
TraceIndexList[2] = 1;
TraceIndexList[3] = 1;
TraceIndexList[4] = 2;
TraceIndexList[5] = 3;
TraceIndexList[6] = 2;
TraceIndexList[7] = 4;
TraceIndexList[8] = 3;
TraceIndexList[9] = 3;
TraceIndexList[10] = 4;
TraceIndexList[11] = 5;
CMotionBlurStreaks::Init();
CBrightLights::Init();
CShinyTexts::Init();
CMoneyMessages::Init();
C3dMarkers::Init();
}
RwObject*
LookForBatCB(RwObject *object, void *data)
{
static CMatrix MatLTM;
if(CVisibilityPlugins::GetAtomicModelInfo((RpAtomic*)object) == (CSimpleModelInfo*)data){
MatLTM = CMatrix(RwFrameGetLTM(RpAtomicGetFrame((RpAtomic*)object)));
CVector p1 = MatLTM * CVector(0.02f, 0.05f, 0.07f);
CVector p2 = MatLTM * CVector(0.246f, 0.0325f, 0.796f);
CMotionBlurStreaks::RegisterStreak((uintptr)object, 100, 100, 100, p1, p2);
}
return nil;
}
void
CSpecialFX::Update(void)
{
CMotionBlurStreaks::Update();
CBulletTraces::Update();
if(FindPlayerPed() &&
FindPlayerPed()->GetWeapon()->m_eWeaponType == WEAPONTYPE_BASEBALLBAT &&
FindPlayerPed()->GetWeapon()->m_eWeaponState == WEAPONSTATE_FIRING)
RwFrameForAllObjects(FindPlayerPed()->GetNodeFrame(PED_HANDR), LookForBatCB, CModelInfo::GetModelInfo(MI_BASEBALL_BAT));
}
void
CSpecialFX::Shutdown(void)
{
C3dMarkers::Shutdown();
}
void
CSpecialFX::Render(void)
{
CMotionBlurStreaks::Render();
CBulletTraces::Render();
CBrightLights::Render();
CShinyTexts::Render();
CMoneyMessages::Render();
C3dMarkers::Render();
}
CRegisteredMotionBlurStreak CMotionBlurStreaks::aStreaks[NUMMBLURSTREAKS];
void
CRegisteredMotionBlurStreak::Update(void)
{
int i;
bool wasUpdated;
bool lastWasUpdated = false;
for(i = 2; i > 0; i--){
m_pos1[i] = m_pos1[i-1];
m_pos2[i] = m_pos2[i-1];
m_isValid[i] = m_isValid[i-1];
wasUpdated = true;
if(!lastWasUpdated && !m_isValid[i])
wasUpdated = false;
lastWasUpdated = wasUpdated;
}
m_isValid[0] = false;
if(!wasUpdated)
m_id = 0;
}
void
CRegisteredMotionBlurStreak::Render(void)
{
int i;
int a1, a2;
for(i = 0; i < 2; i++)
if(m_isValid[i] && m_isValid[i+1]){
a1 = (255/3)*(3-i)/3;
RwIm3DVertexSetRGBA(&StreakVertices[0], m_red, m_green, m_blue, a1);
RwIm3DVertexSetRGBA(&StreakVertices[1], m_red, m_green, m_blue, a1);
a2 = (255/3)*(3-(i+1))/3;
RwIm3DVertexSetRGBA(&StreakVertices[2], m_red, m_green, m_blue, a2);
RwIm3DVertexSetRGBA(&StreakVertices[3], m_red, m_green, m_blue, a2);
RwIm3DVertexSetPos(&StreakVertices[0], m_pos1[i].x, m_pos1[i].y, m_pos1[i].z);
RwIm3DVertexSetPos(&StreakVertices[1], m_pos2[i].x, m_pos2[i].y, m_pos2[i].z);
RwIm3DVertexSetPos(&StreakVertices[2], m_pos1[i+1].x, m_pos1[i+1].y, m_pos1[i+1].z);
RwIm3DVertexSetPos(&StreakVertices[3], m_pos2[i+1].x, m_pos2[i+1].y, m_pos2[i+1].z);
LittleTest();
if(RwIm3DTransform(StreakVertices, 4, nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, StreakIndexList, 12);
RwIm3DEnd();
}
}
}
void
CMotionBlurStreaks::Init(void)
{
int i;
for(i = 0; i < NUMMBLURSTREAKS; i++)
aStreaks[i].m_id = 0;
}
void
CMotionBlurStreaks::Update(void)
{
int i;
for(i = 0; i < NUMMBLURSTREAKS; i++)
if(aStreaks[i].m_id)
aStreaks[i].Update();
}
void
CMotionBlurStreaks::RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2)
{
int i;
for(i = 0; i < NUMMBLURSTREAKS; i++){
if(aStreaks[i].m_id == id){
// Found a streak from last frame, update
aStreaks[i].m_red = r;
aStreaks[i].m_green = g;
aStreaks[i].m_blue = b;
aStreaks[i].m_pos1[0] = p1;
aStreaks[i].m_pos2[0] = p2;
aStreaks[i].m_isValid[0] = true;
return;
}
}
// Find free slot
for(i = 0; aStreaks[i].m_id; i++)
if(i == NUMMBLURSTREAKS-1)
return;
// Create a new streak
aStreaks[i].m_id = id;
aStreaks[i].m_red = r;
aStreaks[i].m_green = g;
aStreaks[i].m_blue = b;
aStreaks[i].m_pos1[0] = p1;
aStreaks[i].m_pos2[0] = p2;
aStreaks[i].m_isValid[0] = true;
aStreaks[i].m_isValid[1] = false;
aStreaks[i].m_isValid[2] = false;
}
void
CMotionBlurStreaks::Render(void)
{
bool setRenderStates = false;
int i;
for(i = 0; i < NUMMBLURSTREAKS; i++)
if(aStreaks[i].m_id){
if(!setRenderStates){
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)TRUE);
RwRenderStateSet(rwRENDERSTATEFOGCOLOR,
(void*)RWRGBALONG(CTimeCycle::GetFogRed(), CTimeCycle::GetFogGreen(), CTimeCycle::GetFogBlue(), 255));
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, (void*)FALSE);
setRenderStates = true;
}
aStreaks[i].Render();
}
if(setRenderStates){
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEFOGENABLE, (void *)FALSE);
}
}
CBulletTrace CBulletTraces::aTraces[NUMBULLETTRACES];
void CBulletTraces::Init(void) void CBulletTraces::Init(void)
{ {
@ -115,8 +350,6 @@ void CBulletTrace::Update(void)
m_framesInUse++; m_framesInUse++;
} }
WRAPPER void CBrightLights::RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1, uint8 unk2, uint8 unk3) { EAXJMP(0x51A410); }
RpAtomic * RpAtomic *
MarkerAtomicCB(RpAtomic *atomic, void *data) MarkerAtomicCB(RpAtomic *atomic, void *data)
{ {
@ -201,9 +434,9 @@ C3dMarker::Render()
ReSetAmbientAndDirectionalColours(); ReSetAmbientAndDirectionalColours();
} }
C3dMarker(&C3dMarkers::m_aMarkerArray)[NUM3DMARKERS] = *(C3dMarker(*)[NUM3DMARKERS])*(uintptr*)0x72D408; C3dMarker C3dMarkers::m_aMarkerArray[NUM3DMARKERS];
int32 &C3dMarkers::NumActiveMarkers = *(int32*)0x8F2A08; int32 C3dMarkers::NumActiveMarkers;
RpClump* (&C3dMarkers::m_pRpClumpArray)[NUMMARKERTYPES] = *(RpClump*(*)[NUMMARKERTYPES])*(uintptr*)0x8E2888; RpClump* C3dMarkers::m_pRpClumpArray[NUMMARKERTYPES];
void void
C3dMarkers::Init() C3dMarkers::Init()
@ -402,6 +635,377 @@ C3dMarkers::Update()
{ {
} }
#define BRIGHTLIGHTS_MAX_DIST (60.0f) // invisible beyond this
#define BRIGHTLIGHTS_FADE_DIST (45.0f) // strongest between these two
#define CARLIGHTS_MAX_DIST (30.0f)
#define CARLIGHTS_FADE_DIST (15.0f) // 31 for close lights
int CBrightLights::NumBrightLights;
CBrightLight CBrightLights::aBrightLights[NUMBRIGHTLIGHTS];
void
CBrightLights::Init(void)
{
NumBrightLights = 0;
}
void
CBrightLights::RegisterOne(CVector pos, CVector up, CVector side, CVector front,
uint8 type, uint8 red, uint8 green, uint8 blue)
{
if(NumBrightLights >= NUMBRIGHTLIGHTS)
return;
aBrightLights[NumBrightLights].m_camDist = (pos - TheCamera.GetPosition()).Magnitude();
if(aBrightLights[NumBrightLights].m_camDist > BRIGHTLIGHTS_MAX_DIST)
return;
aBrightLights[NumBrightLights].m_pos = pos;
aBrightLights[NumBrightLights].m_up = up;
aBrightLights[NumBrightLights].m_side = side;
aBrightLights[NumBrightLights].m_front = front;
aBrightLights[NumBrightLights].m_type = type;
aBrightLights[NumBrightLights].m_red = red;
aBrightLights[NumBrightLights].m_green = green;
aBrightLights[NumBrightLights].m_blue = blue;
NumBrightLights++;
}
static float TrafficLightsSide[6] = { -0.09f, 0.09f, 0.162f, 0.09f, -0.09f, -0.162f };
static float TrafficLightsUp[6] = { 0.162f, 0.162f, 0.0f, -0.162f, -0.162f, 0.0f };
static float LongCarHeadLightsSide[8] = { -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f, -0.2f, 0.2f };
static float LongCarHeadLightsFront[8] = { 0.1f, 0.1f, -0.1f, -0.1f, 0.1f, 0.1f, -0.1f, -0.1f };
static float LongCarHeadLightsUp[8] = { 0.1f, 0.1f, 0.1f, 0.1f, -0.1f, -0.1f, -0.1f, -0.1f };
static float SmallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
static float SmallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
static float SmallCarHeadLightsUp[8] = { 0.08f, 0.08f, 0.08f, 0.08f, -0.08f, -0.08f, -0.08f, -0.08f };
static float BigCarHeadLightsSide[8] = { -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f, -0.15f, 0.15f };
static float BigCarHeadLightsFront[8] = { 0.15f, 0.15f, -0.15f, -0.15f, 0.15f, 0.15f, -0.15f, -0.15f };
static float BigCarHeadLightsUp[8] = { 0.15f, 0.15f, 0.15f, 0.15f, -0.15f, -0.15f, -0.15f, -0.15f };
static float TallCarHeadLightsSide[8] = { -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f, -0.08f, 0.08f };
static float TallCarHeadLightsFront[8] = { 0.08f, 0.08f, -0.08f, -0.08f, 0.08f, 0.08f, -0.08f, -0.08f };
static float TallCarHeadLightsUp[8] = { 0.2f, 0.2f, 0.2f, 0.2f, -0.2f, -0.2f, -0.2f, -0.2f };
static float SirenLightsSide[6] = { -0.04f, 0.04f, 0.06f, 0.04f, -0.04f, -0.06f };
static float SirenLightsUp[6] = { 0.06f, 0.06f, 0.0f, -0.06f, -0.06f, 0.0f };
static RwImVertexIndex TrafficLightIndices[4*3] = { 0, 1, 5, 1, 2, 3, 1, 3, 4, 1, 4, 5 };
static RwImVertexIndex CubeIndices[12*3] = {
0, 2, 1, 1, 2, 3, 3, 5, 1, 3, 7, 5,
2, 7, 3, 2, 6, 7, 4, 0, 1, 4, 1, 5,
6, 0, 4, 6, 2, 0, 6, 5, 7, 6, 4, 5
};
void
CBrightLights::Render(void)
{
int i, j;
CVector pos;
if(NumBrightLights == 0)
return;
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
for(i = 0; i < NumBrightLights; i++){
if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-40 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-40)
RenderOutGeometryBuffer();
int r, g, b, a;
float flicker = (CGeneral::GetRandomNumber()&0xFF) * 0.2f;
switch(aBrightLights[i].m_type){
case BRIGHTLIGHT_TRAFFIC_GREEN:
r = flicker; g = 255; b = flicker;
break;
case BRIGHTLIGHT_TRAFFIC_YELLOW:
r = 255; g = 128; b = flicker;
break;
case BRIGHTLIGHT_TRAFFIC_RED:
r = 255; g = flicker; b = flicker;
break;
case BRIGHTLIGHT_FRONT_LONG:
case BRIGHTLIGHT_FRONT_SMALL:
case BRIGHTLIGHT_FRONT_BIG:
case BRIGHTLIGHT_FRONT_TALL:
r = 255; g = 255; b = 255;
break;
case BRIGHTLIGHT_REAR_LONG:
case BRIGHTLIGHT_REAR_SMALL:
case BRIGHTLIGHT_REAR_BIG:
case BRIGHTLIGHT_REAR_TALL:
r = 255; g = flicker; b = flicker;
break;
case BRIGHTLIGHT_SIREN:
r = aBrightLights[i].m_red;
g = aBrightLights[i].m_green;
b = aBrightLights[i].m_blue;
break;
}
if(aBrightLights[i].m_camDist < BRIGHTLIGHTS_FADE_DIST)
a = 255;
else
a = 255*(1.0f - (aBrightLights[i].m_camDist-BRIGHTLIGHTS_FADE_DIST)/(BRIGHTLIGHTS_MAX_DIST-BRIGHTLIGHTS_FADE_DIST));
// fade car lights down to 31 as they come near
if(aBrightLights[i].m_type >= BRIGHTLIGHT_FRONT_LONG && aBrightLights[i].m_type <= BRIGHTLIGHT_REAR_TALL){
if(aBrightLights[i].m_camDist < CARLIGHTS_FADE_DIST)
a = 31;
else if(aBrightLights[i].m_camDist < CARLIGHTS_MAX_DIST)
a = 31 + (255-31)*((aBrightLights[i].m_camDist-CARLIGHTS_FADE_DIST)/(CARLIGHTS_MAX_DIST-CARLIGHTS_FADE_DIST));
}
switch(aBrightLights[i].m_type){
case BRIGHTLIGHT_TRAFFIC_GREEN:
case BRIGHTLIGHT_TRAFFIC_YELLOW:
case BRIGHTLIGHT_TRAFFIC_RED:
for(j = 0; j < 6; j++){
pos = TrafficLightsSide[j]*aBrightLights[i].m_side +
TrafficLightsUp[j]*aBrightLights[i].m_up +
aBrightLights[i].m_pos;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
}
for(j = 0; j < 4*3; j++)
TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
TempBufferVerticesStored += 6;
TempBufferIndicesStored += 4*3;
break;
case BRIGHTLIGHT_FRONT_LONG:
case BRIGHTLIGHT_REAR_LONG:
for(j = 0; j < 8; j++){
pos = LongCarHeadLightsSide[j]*aBrightLights[i].m_side +
LongCarHeadLightsUp[j]*aBrightLights[i].m_up +
LongCarHeadLightsFront[j]*aBrightLights[i].m_front +
aBrightLights[i].m_pos;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
}
for(j = 0; j < 12*3; j++)
TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
TempBufferVerticesStored += 8;
TempBufferIndicesStored += 12*3;
break;
case BRIGHTLIGHT_FRONT_SMALL:
case BRIGHTLIGHT_REAR_SMALL:
for(j = 0; j < 8; j++){
pos = SmallCarHeadLightsSide[j]*aBrightLights[i].m_side +
SmallCarHeadLightsUp[j]*aBrightLights[i].m_up +
SmallCarHeadLightsFront[j]*aBrightLights[i].m_front +
aBrightLights[i].m_pos;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
}
for(j = 0; j < 12*3; j++)
TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
TempBufferVerticesStored += 8;
TempBufferIndicesStored += 12*3;
break;
case BRIGHTLIGHT_FRONT_TALL:
case BRIGHTLIGHT_REAR_TALL:
for(j = 0; j < 8; j++){
pos = TallCarHeadLightsSide[j]*aBrightLights[i].m_side +
TallCarHeadLightsUp[j]*aBrightLights[i].m_up +
TallCarHeadLightsFront[j]*aBrightLights[i].m_front +
aBrightLights[i].m_pos;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
}
for(j = 0; j < 12*3; j++)
TempBufferRenderIndexList[TempBufferIndicesStored+j] = CubeIndices[j] + TempBufferVerticesStored;
TempBufferVerticesStored += 8;
TempBufferIndicesStored += 12*3;
break;
case BRIGHTLIGHT_SIREN:
for(j = 0; j < 6; j++){
pos = SirenLightsSide[j]*aBrightLights[i].m_side +
SirenLightsUp[j]*aBrightLights[i].m_up +
aBrightLights[i].m_pos;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[TempBufferVerticesStored+j], r, g, b, a);
RwIm3DVertexSetPos(&TempBufferRenderVertices[TempBufferVerticesStored+j], pos.x, pos.y, pos.z);
}
for(j = 0; j < 4*3; j++)
TempBufferRenderIndexList[TempBufferIndicesStored+j] = TrafficLightIndices[j] + TempBufferVerticesStored;
TempBufferVerticesStored += 6;
TempBufferIndicesStored += 4*3;
break;
}
}
RenderOutGeometryBuffer();
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
NumBrightLights = 0;
}
void
CBrightLights::RenderOutGeometryBuffer(void)
{
if(TempBufferIndicesStored != 0){
LittleTest();
if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
RwIm3DEnd();
}
TempBufferVerticesStored = 0;
TempBufferIndicesStored = 0;
}
}
int CShinyTexts::NumShinyTexts;
CShinyText CShinyTexts::aShinyTexts[NUMSHINYTEXTS];
void
CShinyTexts::Init(void)
{
NumShinyTexts = 0;
}
void
CShinyTexts::RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist)
{
if(NumShinyTexts >= NUMSHINYTEXTS)
return;
aShinyTexts[NumShinyTexts].m_camDist = (p0 - TheCamera.GetPosition()).Magnitude();
if(aShinyTexts[NumShinyTexts].m_camDist > maxDist)
return;
aShinyTexts[NumShinyTexts].m_verts[0] = p0;
aShinyTexts[NumShinyTexts].m_verts[1] = p1;
aShinyTexts[NumShinyTexts].m_verts[2] = p2;
aShinyTexts[NumShinyTexts].m_verts[3] = p3;
aShinyTexts[NumShinyTexts].m_texCoords[0].x = u0;
aShinyTexts[NumShinyTexts].m_texCoords[0].y = v0;
aShinyTexts[NumShinyTexts].m_texCoords[1].x = u1;
aShinyTexts[NumShinyTexts].m_texCoords[1].y = v1;
aShinyTexts[NumShinyTexts].m_texCoords[2].x = u2;
aShinyTexts[NumShinyTexts].m_texCoords[2].y = v2;
aShinyTexts[NumShinyTexts].m_texCoords[3].x = u3;
aShinyTexts[NumShinyTexts].m_texCoords[3].y = v3;
aShinyTexts[NumShinyTexts].m_type = type;
aShinyTexts[NumShinyTexts].m_red = red;
aShinyTexts[NumShinyTexts].m_green = green;
aShinyTexts[NumShinyTexts].m_blue = blue;
// Fade out at half the max dist
float halfDist = maxDist*0.5f;
if(aShinyTexts[NumShinyTexts].m_camDist > halfDist){
float f = 1.0f - (aShinyTexts[NumShinyTexts].m_camDist - halfDist)/halfDist;
aShinyTexts[NumShinyTexts].m_red *= f;
aShinyTexts[NumShinyTexts].m_green *= f;
aShinyTexts[NumShinyTexts].m_blue *= f;
}
NumShinyTexts++;
}
void
CShinyTexts::Render(void)
{
int i, ix, v;
RwTexture *lastTex = nil;
if(NumShinyTexts == 0)
return;
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE);
TempBufferVerticesStored = 0;
TempBufferIndicesStored = 0;
for(i = 0; i < NumShinyTexts; i++){
if(TempBufferIndicesStored > TEMPBUFFERINDEXSIZE-64 || TempBufferVerticesStored > TEMPBUFFERVERTSIZE-62)
RenderOutGeometryBuffer();
uint8 r = aShinyTexts[i].m_red;
uint8 g = aShinyTexts[i].m_green;
uint8 b = aShinyTexts[i].m_blue;
switch(aShinyTexts[i].m_type){
case SHINYTEXT_WALK:
if(lastTex != gpWalkDontTex){
RenderOutGeometryBuffer();
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpWalkDontTex));
lastTex = gpWalkDontTex;
}
quad:
v = TempBufferVerticesStored;
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+0], r, g, b, 255);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_verts[0].x, aShinyTexts[i].m_verts[0].y, aShinyTexts[i].m_verts[0].z);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].x);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+0], aShinyTexts[i].m_texCoords[0].y);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+1], r, g, b, 255);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_verts[1].x, aShinyTexts[i].m_verts[1].y, aShinyTexts[i].m_verts[1].z);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].x);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+1], aShinyTexts[i].m_texCoords[1].y);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+2], r, g, b, 255);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_verts[2].x, aShinyTexts[i].m_verts[2].y, aShinyTexts[i].m_verts[2].z);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].x);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+2], aShinyTexts[i].m_texCoords[2].y);
RwIm3DVertexSetRGBA(&TempBufferRenderVertices[v+3], r, g, b, 255);
RwIm3DVertexSetPos(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_verts[3].x, aShinyTexts[i].m_verts[3].y, aShinyTexts[i].m_verts[3].z);
RwIm3DVertexSetU(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].x);
RwIm3DVertexSetV(&TempBufferRenderVertices[v+3], aShinyTexts[i].m_texCoords[3].y);
ix = TempBufferIndicesStored;
TempBufferRenderIndexList[ix+0] = 0 + TempBufferVerticesStored;
TempBufferRenderIndexList[ix+1] = 1 + TempBufferVerticesStored;
TempBufferRenderIndexList[ix+2] = 2 + TempBufferVerticesStored;
TempBufferRenderIndexList[ix+3] = 2 + TempBufferVerticesStored;
TempBufferRenderIndexList[ix+4] = 1 + TempBufferVerticesStored;
TempBufferRenderIndexList[ix+5] = 3 + TempBufferVerticesStored;
TempBufferVerticesStored += 4;
TempBufferIndicesStored += 6;
break;
case SHINYTEXT_FLAT:
if(lastTex != nil){
RenderOutGeometryBuffer();
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, nil);
lastTex = nil;
}
goto quad;
}
}
RenderOutGeometryBuffer();
NumShinyTexts = 0;
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
}
void
CShinyTexts::RenderOutGeometryBuffer(void)
{
if(TempBufferIndicesStored != 0){
LittleTest();
if(RwIm3DTransform(TempBufferRenderVertices, TempBufferVerticesStored, nil, rwIM3D_VERTEXUV)){
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, TempBufferRenderIndexList, TempBufferIndicesStored);
RwIm3DEnd();
}
TempBufferVerticesStored = 0;
TempBufferIndicesStored = 0;
}
}
#define MONEY_MESSAGE_LIFETIME_MS 2000 #define MONEY_MESSAGE_LIFETIME_MS 2000
CMoneyMessage CMoneyMessages::aMoneyMessages[NUMMONEYMESSAGES]; CMoneyMessage CMoneyMessages::aMoneyMessages[NUMMONEYMESSAGES];
@ -564,6 +1168,16 @@ STARTPATCHES
InjectHook(0x51B400, C3dMarkers::Render, PATCH_JUMP); InjectHook(0x51B400, C3dMarkers::Render, PATCH_JUMP);
InjectHook(0x51B3B0, C3dMarkers::Shutdown, PATCH_JUMP); InjectHook(0x51B3B0, C3dMarkers::Shutdown, PATCH_JUMP);
InjectHook(0x5197A0, CBrightLights::Init, PATCH_JUMP);
InjectHook(0x51A410, CBrightLights::RegisterOne, PATCH_JUMP);
InjectHook(0x5197B0, CBrightLights::Render, PATCH_JUMP);
InjectHook(0x51A3B0, CBrightLights::RenderOutGeometryBuffer, PATCH_JUMP);
InjectHook(0x51A5A0, CShinyTexts::Init, PATCH_JUMP);
InjectHook(0x51AAB0, CShinyTexts::RegisterOne, PATCH_JUMP);
InjectHook(0x51A5B0, CShinyTexts::Render, PATCH_JUMP);
InjectHook(0x51AA50, CShinyTexts::RenderOutGeometryBuffer, PATCH_JUMP);
InjectHook(0x51AF70, CMoneyMessages::Init, PATCH_JUMP); InjectHook(0x51AF70, CMoneyMessages::Init, PATCH_JUMP);
InjectHook(0x51B030, CMoneyMessages::Render, PATCH_JUMP); InjectHook(0x51B030, CMoneyMessages::Render, PATCH_JUMP);
ENDPATCHES ENDPATCHES

View File

@ -9,10 +9,29 @@ public:
static void Shutdown(void); static void Shutdown(void);
}; };
class CMotionBlurStreaks class CRegisteredMotionBlurStreak
{ {
public: public:
static void RegisterStreak(int32 id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2); uintptr m_id;
uint8 m_red;
uint8 m_green;
uint8 m_blue;
CVector m_pos1[3];
CVector m_pos2[3];
bool m_isValid[3];
void Update(void);
void Render(void);
};
class CMotionBlurStreaks
{
static CRegisteredMotionBlurStreak aStreaks[NUMMBLURSTREAKS];
public:
static void Init(void);
static void Update(void);
static void RegisterStreak(uintptr id, uint8 r, uint8 g, uint8 b, CVector p1, CVector p2);
static void Render(void);
}; };
struct CBulletTrace struct CBulletTrace
@ -29,7 +48,7 @@ struct CBulletTrace
class CBulletTraces class CBulletTraces
{ {
public: public:
static CBulletTrace (&aTraces)[NUMBULLETTRACES]; static CBulletTrace aTraces[NUMBULLETTRACES];
static void Init(void); static void Init(void);
static void AddTrace(CVector*, CVector*); static void AddTrace(CVector*, CVector*);
@ -37,12 +56,6 @@ public:
static void Update(void); static void Update(void);
}; };
class CBrightLights
{
public:
static void RegisterOne(CVector pos, CVector up, CVector right, CVector fwd, uint8 type, uint8 unk1 = 0, uint8 unk2 = 0, uint8 unk3 = 0);
};
enum enum
{ {
MARKERTYPE_0 = 0, MARKERTYPE_0 = 0,
@ -90,9 +103,92 @@ public:
static void Render(); static void Render();
static void Update(); static void Update();
static C3dMarker(&m_aMarkerArray)[NUM3DMARKERS]; static C3dMarker m_aMarkerArray[NUM3DMARKERS];
static int32 &NumActiveMarkers; static int32 NumActiveMarkers;
static RpClump* (&m_pRpClumpArray)[NUMMARKERTYPES]; static RpClump* m_pRpClumpArray[NUMMARKERTYPES];
};
enum
{
BRIGHTLIGHT_INVALID,
BRIGHTLIGHT_TRAFFIC_GREEN,
BRIGHTLIGHT_TRAFFIC_YELLOW,
BRIGHTLIGHT_TRAFFIC_RED,
// white
BRIGHTLIGHT_FRONT_LONG,
BRIGHTLIGHT_FRONT_SMALL,
BRIGHTLIGHT_FRONT_BIG,
BRIGHTLIGHT_FRONT_TALL,
// red
BRIGHTLIGHT_REAR_LONG,
BRIGHTLIGHT_REAR_SMALL,
BRIGHTLIGHT_REAR_BIG,
BRIGHTLIGHT_REAR_TALL,
BRIGHTLIGHT_SIREN, // unused
BRIGHTLIGHT_FRONT = BRIGHTLIGHT_FRONT_LONG,
BRIGHTLIGHT_REAR = BRIGHTLIGHT_REAR_LONG,
};
class CBrightLight
{
public:
CVector m_pos;
CVector m_up;
CVector m_side;
CVector m_front;
float m_camDist;
uint8 m_type;
uint8 m_red;
uint8 m_green;
uint8 m_blue;
};
class CBrightLights
{
static int NumBrightLights;
static CBrightLight aBrightLights[NUMBRIGHTLIGHTS];
public:
static void Init(void);
static void RegisterOne(CVector pos, CVector up, CVector side, CVector front,
uint8 type, uint8 red = 0, uint8 green = 0, uint8 blue = 0);
static void Render(void);
static void RenderOutGeometryBuffer(void);
};
enum
{
SHINYTEXT_WALK = 1,
SHINYTEXT_FLAT
};
class CShinyText
{
public:
CVector m_verts[4];
CVector2D m_texCoords[4];
float m_camDist;
uint8 m_type;
uint8 m_red;
uint8 m_green;
uint8 m_blue;
};
class CShinyTexts
{
static int NumShinyTexts;
static CShinyText aShinyTexts[NUMSHINYTEXTS];
public:
static void Init(void);
static void RegisterOne(CVector p0, CVector p1, CVector p2, CVector p3,
float u0, float v0, float u1, float v1, float u2, float v2, float u3, float v3,
uint8 type, uint8 red, uint8 green, uint8 blue, float maxDist);
static void Render(void);
static void RenderOutGeometryBuffer(void);
}; };
class CMoneyMessage class CMoneyMessage

View File

@ -253,7 +253,7 @@ CAutomobile::ProcessControl(void)
ProcessCarAlarm(); ProcessCarAlarm();
// Scan if this car is committing a crime that the police can see // Scan if this car sees the player committing any crimes
if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED && if(m_status != STATUS_ABANDONED && m_status != STATUS_WRECKED &&
m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){ m_status != STATUS_PLAYER && m_status != STATUS_PLAYER_REMOTE && m_status != STATUS_PLAYER_DISABLED){
switch(GetModelIndex()) switch(GetModelIndex())
@ -1727,9 +1727,9 @@ CAutomobile::PreRender(void)
// bright lights // bright lights
if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK && !bNoBrightHeadLights) if(Damage.GetLightStatus(VEHLIGHT_FRONT_LEFT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4); CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + BRIGHTLIGHT_FRONT);
if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK && !bNoBrightHeadLights) if(Damage.GetLightStatus(VEHLIGHT_FRONT_RIGHT) == LIGHT_STATUS_OK && !bNoBrightHeadLights)
CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + 4); CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->FrontLights + BRIGHTLIGHT_FRONT);
// Taillights // Taillights
@ -1798,9 +1798,9 @@ CAutomobile::PreRender(void)
// bright lights // bright lights
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8); CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8); CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
// Light shadows // Light shadows
if(!alarmOff){ if(!alarmOff){
@ -1873,9 +1873,9 @@ CAutomobile::PreRender(void)
CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f); CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4); CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_FRONT);
if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 4); CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_FRONT);
}else{ }else{
// braking // braking
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
@ -1889,9 +1889,9 @@ CAutomobile::PreRender(void)
CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON, CCoronas::TYPE_STAR, CCoronas::FLARE_NONE, CCoronas::REFLECTION_ON,
CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f); CCoronas::LOSCHECK_OFF, CCoronas::STREAK_ON, 0.0f);
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)
CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8); CBrightLights::RegisterOne(lightL, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_RIGHT) == LIGHT_STATUS_OK)
CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + 8); CBrightLights::RegisterOne(lightR, GetUp(), GetRight(), GetForward(), pHandling->RearLights + BRIGHTLIGHT_REAR);
} }
}else{ }else{
if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK) if(Damage.GetLightStatus(VEHLIGHT_REAR_LEFT) == LIGHT_STATUS_OK)