mirror of
https://github.com/GTAmodding/re3.git
synced 2024-12-24 17:55:42 +00:00
implemented CSkidmarks
This commit is contained in:
parent
7eee938de2
commit
6288d36f34
4 changed files with 263 additions and 16 deletions
|
@ -16,12 +16,6 @@ such that we have a working game at all times.
|
|||
- Since re3 is a DLL that works with original GTA III for now, you need Simple DLL Loader. You can get it [here](https://github.com/aap/simpledllloader).
|
||||
- Build re3 or download it from one of the above links (Debug or Release).
|
||||
- Make sure you included the re3 in `plugins.cfg` or `dlls.cfg`.
|
||||
- re3 starts the script `main_freeroam.scm` that comes along with it by default, so you should copy it to from `gamefiles/` to your game's `data/` directory.
|
||||
|
||||
![#ffa500](https://placehold.it/15/ffa500/000000?text=+) **Notice**
|
||||
|
||||
If you want to load original script/story, press and hold G while game is loading.
|
||||
This includes both starting new game and loading save game.
|
||||
|
||||
![#ffa500](https://placehold.it/15/ffa500/000000?text=+) **Notice if you will build it**
|
||||
|
||||
|
@ -51,7 +45,6 @@ CPools - save/loading
|
|||
CRecordDataForChase
|
||||
CRecordDataForGame
|
||||
CRoadBlocks
|
||||
CSkidmarks
|
||||
CStats
|
||||
CTrafficLights
|
||||
CWeapon
|
||||
|
|
|
@ -79,6 +79,7 @@ enum Config {
|
|||
NUMPICKUPMESSAGES = 16,
|
||||
NUMBULLETTRACES = 16,
|
||||
NUMMBLURSTREAKS = 4,
|
||||
NUMSKIDMARKS = 32,
|
||||
|
||||
NUMONSCREENTIMERENTRIES = 1,
|
||||
NUMRADARBLIPS = 32,
|
||||
|
|
|
@ -1,12 +1,247 @@
|
|||
#include "common.h"
|
||||
#include "patcher.h"
|
||||
#include "main.h"
|
||||
#include "TxdStore.h"
|
||||
#include "Timer.h"
|
||||
#include "Replay.h"
|
||||
#include "Skidmarks.h"
|
||||
|
||||
WRAPPER void CSkidmarks::Clear(void) { EAXJMP(0x518130); }
|
||||
WRAPPER void CSkidmarks::Update() { EAXJMP(0x518200); }
|
||||
CSkidmark CSkidmarks::aSkidmarks[NUMSKIDMARKS];
|
||||
|
||||
WRAPPER void CSkidmarks::Render(void) { EAXJMP(0x5182E0); }
|
||||
WRAPPER void CSkidmarks::RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy) { EAXJMP(0x5185C0); }
|
||||
RwImVertexIndex SkidmarkIndexList[16 * 6];
|
||||
RwIm3DVertex SkidmarkVertices[16 * 2];
|
||||
RwTexture *gpSkidTex;
|
||||
RwTexture *gpSkidBloodTex;
|
||||
RwTexture *gpSkidMudTex;
|
||||
|
||||
WRAPPER void CSkidmarks::Init(void) { EAXJMP(0x517D70); }
|
||||
WRAPPER void CSkidmarks::Shutdown(void) { EAXJMP(0x518100); }
|
||||
void
|
||||
CSkidmarks::Init(void)
|
||||
{
|
||||
int i, ix, slot;
|
||||
CTxdStore::PushCurrentTxd();
|
||||
slot = CTxdStore::FindTxdSlot("particle");
|
||||
CTxdStore::SetCurrentTxd(slot);
|
||||
gpSkidTex = RwTextureRead("particleskid", nil);
|
||||
gpSkidBloodTex = RwTextureRead("particleskidblood", nil);
|
||||
gpSkidMudTex = RwTextureRead("particleskidmud", nil);
|
||||
CTxdStore::PopCurrentTxd();
|
||||
|
||||
for(i = 0; i < NUMSKIDMARKS; i++){
|
||||
aSkidmarks[i].m_state = 0;
|
||||
aSkidmarks[i].m_wasUpdated = false;
|
||||
}
|
||||
|
||||
ix = 0;
|
||||
for(i = 0; i < 16; i++){
|
||||
SkidmarkIndexList[i*6+0] = ix+0;
|
||||
SkidmarkIndexList[i*6+1] = ix+2;
|
||||
SkidmarkIndexList[i*6+2] = ix+1;
|
||||
SkidmarkIndexList[i*6+3] = ix+1;
|
||||
SkidmarkIndexList[i*6+4] = ix+2;
|
||||
SkidmarkIndexList[i*6+5] = ix+3;
|
||||
ix += 2;
|
||||
}
|
||||
|
||||
for(i = 0; i < 16; i++){
|
||||
RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 0], 0.0f);
|
||||
RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 0], i*5.01f);
|
||||
RwIm3DVertexSetU(&SkidmarkVertices[i*2 + 1], 1.0f);
|
||||
RwIm3DVertexSetV(&SkidmarkVertices[i*2 + 1], i*5.01f);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSkidmarks::Shutdown(void)
|
||||
{
|
||||
RwTextureDestroy(gpSkidTex);
|
||||
RwTextureDestroy(gpSkidBloodTex);
|
||||
RwTextureDestroy(gpSkidMudTex);
|
||||
}
|
||||
|
||||
void
|
||||
CSkidmarks::Clear(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < NUMSKIDMARKS; i++){
|
||||
aSkidmarks[i].m_state = 0;
|
||||
aSkidmarks[i].m_wasUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSkidmarks::Update(void)
|
||||
{
|
||||
int i;
|
||||
uint32 t1 = CTimer::GetTimeInMilliseconds() + 2500;
|
||||
uint32 t2 = CTimer::GetTimeInMilliseconds() + 5000;
|
||||
uint32 t3 = CTimer::GetTimeInMilliseconds() + 10000;
|
||||
uint32 t4 = CTimer::GetTimeInMilliseconds() + 20000;
|
||||
for(i = 0; i < NUMSKIDMARKS; i++){
|
||||
switch(aSkidmarks[i].m_state){
|
||||
case 1:
|
||||
if(!aSkidmarks[i].m_wasUpdated){
|
||||
// Didn't continue this one last time, so finish it and set fade times
|
||||
aSkidmarks[i].m_state = 2;
|
||||
if(aSkidmarks[i].m_last < 4){
|
||||
aSkidmarks[i].m_fadeStart = t1;
|
||||
aSkidmarks[i].m_fadeEnd = t2;
|
||||
}else if(aSkidmarks[i].m_last < 9){
|
||||
aSkidmarks[i].m_fadeStart = t2;
|
||||
aSkidmarks[i].m_fadeEnd = t3;
|
||||
}else{
|
||||
aSkidmarks[i].m_fadeStart = t3;
|
||||
aSkidmarks[i].m_fadeEnd = t4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(CTimer::GetTimeInMilliseconds() > aSkidmarks[i].m_fadeEnd)
|
||||
aSkidmarks[i].m_state = 0;
|
||||
break;
|
||||
}
|
||||
aSkidmarks[i].m_wasUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSkidmarks::Render(void)
|
||||
{
|
||||
int i, j;
|
||||
RwTexture *lastTex = nil;
|
||||
|
||||
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)FALSE);
|
||||
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE);
|
||||
RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA);
|
||||
RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA);
|
||||
|
||||
for(i = 0; i < NUMSKIDMARKS; i++){
|
||||
if(aSkidmarks[i].m_state == 0 || aSkidmarks[i].m_last < 1)
|
||||
continue;
|
||||
|
||||
if(aSkidmarks[i].m_isBloody){
|
||||
if(lastTex != gpSkidBloodTex){
|
||||
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidBloodTex));
|
||||
lastTex = gpSkidBloodTex;
|
||||
}
|
||||
}else if(aSkidmarks[i].m_isMuddy){
|
||||
if(lastTex != gpSkidMudTex){
|
||||
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidMudTex));
|
||||
lastTex = gpSkidMudTex;
|
||||
}
|
||||
}else{
|
||||
if(lastTex != gpSkidTex){
|
||||
RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpSkidTex));
|
||||
lastTex = gpSkidTex;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 fade, alpha;
|
||||
if(aSkidmarks[i].m_state == 1 || CTimer::GetTimeInMilliseconds() < aSkidmarks[i].m_fadeStart)
|
||||
fade = 255;
|
||||
else
|
||||
fade = 255*(aSkidmarks[i].m_fadeEnd - CTimer::GetTimeInMilliseconds()) / (aSkidmarks[i].m_fadeEnd - aSkidmarks[i].m_fadeStart);
|
||||
|
||||
for(j = 0; j <= aSkidmarks[i].m_last; j++){
|
||||
alpha = 128;
|
||||
if(j == 0 || j == aSkidmarks[i].m_last && aSkidmarks[i].m_state == 2)
|
||||
alpha = 0;
|
||||
alpha = alpha*fade/256;
|
||||
|
||||
CVector p1 = aSkidmarks[i].m_pos[j] + aSkidmarks[i].m_side[j];
|
||||
CVector p2 = aSkidmarks[i].m_pos[j] - aSkidmarks[i].m_side[j];
|
||||
RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+0], 255, 255, 255, alpha);
|
||||
RwIm3DVertexSetPos(&SkidmarkVertices[j*2+0], p1.x, p1.y, p1.z+0.1f);
|
||||
RwIm3DVertexSetRGBA(&SkidmarkVertices[j*2+1], 255, 255, 255, alpha);
|
||||
RwIm3DVertexSetPos(&SkidmarkVertices[j*2+1], p2.x, p2.y, p2.z+0.1f);
|
||||
}
|
||||
|
||||
LittleTest();
|
||||
if(RwIm3DTransform(SkidmarkVertices, 2*(aSkidmarks[i].m_last+1), nil, rwIM3D_VERTEXUV)){
|
||||
RwIm3DRenderIndexedPrimitive(rwPRIMTYPETRILIST, SkidmarkIndexList, 6*aSkidmarks[i].m_last);
|
||||
RwIm3DEnd();
|
||||
}
|
||||
}
|
||||
|
||||
RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE);
|
||||
RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE);
|
||||
RwRenderStateSet(rwRENDERSTATEZTESTENABLE, (void*)TRUE);
|
||||
}
|
||||
|
||||
void
|
||||
CSkidmarks::RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody)
|
||||
{
|
||||
int i;
|
||||
CVector2D fwd(fwdX, fwdY);
|
||||
|
||||
if(CReplay::IsPlayingBack())
|
||||
return;
|
||||
|
||||
// Find a skidmark to continue
|
||||
for(i = 0; i < NUMSKIDMARKS; i++)
|
||||
if(aSkidmarks[i].m_state == 1 && aSkidmarks[i].m_id == id)
|
||||
break;
|
||||
|
||||
if(i < NUMSKIDMARKS){
|
||||
// Continue this one
|
||||
|
||||
if(aSkidmarks[i].m_isBloody != *isBloody){
|
||||
// Blood-status changed, end this one
|
||||
aSkidmarks[i].m_state = 2;
|
||||
aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
|
||||
aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
|
||||
return;
|
||||
}
|
||||
|
||||
aSkidmarks[i].m_wasUpdated = true;
|
||||
|
||||
if(CTimer::GetTimeInMilliseconds() - aSkidmarks[i].m_lastUpdate <= 100){
|
||||
// Last update was recently, just change last coords
|
||||
aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
|
||||
return;
|
||||
}
|
||||
aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds();
|
||||
|
||||
if(aSkidmarks[i].m_last >= 15){
|
||||
// No space to continue, end it
|
||||
aSkidmarks[i].m_state = 2;
|
||||
aSkidmarks[i].m_fadeStart = CTimer::GetTimeInMilliseconds() + 10000;
|
||||
aSkidmarks[i].m_fadeEnd = CTimer::GetTimeInMilliseconds() + 20000;
|
||||
*isBloody = false; // stpo blood marks at end
|
||||
return;
|
||||
}
|
||||
aSkidmarks[i].m_last++;
|
||||
|
||||
aSkidmarks[i].m_pos[aSkidmarks[i].m_last] = pos;
|
||||
|
||||
CVector2D dist = aSkidmarks[i].m_pos[aSkidmarks[i].m_last] - aSkidmarks[i].m_pos[aSkidmarks[i].m_last-1];
|
||||
dist.Normalise();
|
||||
CVector2D right(dist.y, -dist.x);
|
||||
float turn = DotProduct2D(fwd, right);
|
||||
turn = Abs(turn) + 1.0f;
|
||||
aSkidmarks[i].m_side[aSkidmarks[i].m_last] = CVector(right.x, right.y, 0.0f) * turn * 0.125f;
|
||||
if(aSkidmarks[i].m_last == 1)
|
||||
aSkidmarks[i].m_side[0] = aSkidmarks[i].m_side[1];
|
||||
|
||||
if(aSkidmarks[i].m_last > 8)
|
||||
*isBloody = false; // stop blood marks after 8
|
||||
return;
|
||||
}
|
||||
|
||||
// Start a new one
|
||||
for(i = 0; i < NUMSKIDMARKS; i++)
|
||||
if(aSkidmarks[i].m_state == 0)
|
||||
break;
|
||||
if(i < NUMSKIDMARKS){
|
||||
// Found a free slot
|
||||
aSkidmarks[i].m_state = 1;
|
||||
aSkidmarks[i].m_id = id;
|
||||
aSkidmarks[i].m_pos[0] = pos;
|
||||
aSkidmarks[i].m_side[0] = CVector(0.0f, 0.0f, 0.0f);
|
||||
aSkidmarks[i].m_wasUpdated = true;
|
||||
aSkidmarks[i].m_last = 0;
|
||||
aSkidmarks[i].m_lastUpdate = CTimer::GetTimeInMilliseconds() - 1000;
|
||||
aSkidmarks[i].m_isBloody = *isBloody;
|
||||
aSkidmarks[i].m_isMuddy = *isMuddy;
|
||||
}else
|
||||
*isBloody = false; // stop blood marks if no space
|
||||
}
|
||||
|
|
|
@ -1,12 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
class CSkidmark
|
||||
{
|
||||
public:
|
||||
uint8 m_state;
|
||||
bool m_wasUpdated;
|
||||
bool m_isBloody;
|
||||
bool m_isMuddy;
|
||||
uintptr m_id;
|
||||
int16 m_last;
|
||||
uint32 m_lastUpdate;;
|
||||
uint32 m_fadeStart;
|
||||
uint32 m_fadeEnd;
|
||||
CVector m_pos[16];
|
||||
CVector m_side[16];
|
||||
};
|
||||
|
||||
class CSkidmarks
|
||||
{
|
||||
static CSkidmark aSkidmarks[NUMSKIDMARKS];
|
||||
public:
|
||||
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
static void Clear(void);
|
||||
static void Update(void);
|
||||
static void Render(void);
|
||||
static void RegisterOne(uint32 id, CVector pos, float fwdx, float fwdY, bool *isMuddy, bool *isBloddy);
|
||||
static void Init(void);
|
||||
static void Shutdown(void);
|
||||
static void RegisterOne(uintptr id, CVector pos, float fwdX, float fwdY, bool *isMuddy, bool *isBloody);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue