diff --git a/src/Camera.cpp b/src/Camera.cpp index 3af5d953..198dda0f 100644 --- a/src/Camera.cpp +++ b/src/Camera.cpp @@ -5,6 +5,7 @@ #include "World.h" #include "Vehicle.h" #include "Ped.h" +#include "PlayerPed.h" #include "Pad.h" #include "General.h" #include "CullZones.h" diff --git a/src/Collision.cpp b/src/Collision.cpp index 774caf9d..6189a3fc 100644 --- a/src/Collision.cpp +++ b/src/Collision.cpp @@ -1,7 +1,21 @@ #include "common.h" #include "patcher.h" +#include "main.h" +#include "Lists.h" #include "Game.h" +#include "Zones.h" #include "General.h" +#include "CullZones.h" +#include "World.h" +#include "Entity.h" +#include "Train.h" +#include "Streaming.h" +#include "Pad.h" +#include "DMAudio.h" +#include "Population.h" +#include "FileLoader.h" +#include "Replay.h" +#include "CutsceneMgr.h" #include "RenderBuffer.h" #include "SurfaceTable.h" #include "Collision.h" @@ -19,8 +33,6 @@ enum Direction eLevelName &CCollision::ms_collisionInMemory = *(eLevelName*)0x8F6250; CLinkList &CCollision::ms_colModelCache = *(CLinkList*)0x95CB58; -#if 0 - void CCollision::Init(void) { @@ -28,72 +40,205 @@ CCollision::Init(void) ms_collisionInMemory = LEVEL_NONE; } +void +CCollision::Shutdown(void) +{ + ms_colModelCache.Shutdown(); +} + void CCollision::Update(void) { - CVector pos = FindPlayerCoors(); + CVector playerCoors; + playerCoors = FindPlayerCoors(); eLevelName level = CTheZones::m_CurrLevel; - bool changeLevel = false; + bool forceLevelChange = false; + + if(CTimer::GetTimeInMilliseconds() < 2000 || CCutsceneMgr::IsCutsceneProcessing()) + return; // hardcode a level if there are no zones if(level == LEVEL_NONE){ if(CGame::currLevel == LEVEL_INDUSTRIAL && - pos.x < 400.0f){ + playerCoors.x < 400.0f){ level = LEVEL_COMMERCIAL; - changeLevel = true; + forceLevelChange = true; }else if(CGame::currLevel == LEVEL_SUBURBAN && - pos.x > -450.0f && pos.y < -1400.0f){ + playerCoors.x > -450.0f && playerCoors.y < -1400.0f){ level = LEVEL_COMMERCIAL; - changeLevel = true; + forceLevelChange = true; }else{ - if(pos.x > 800.0f){ + if(playerCoors.x > 800.0f){ level = LEVEL_INDUSTRIAL; - changeLevel = true; - }else if(pos.x < -800.0f){ + forceLevelChange = true; + }else if(playerCoors.x < -800.0f){ level = LEVEL_SUBURBAN; - changeLevel = true; + forceLevelChange = true; } } } - if(level != LEVEL_NONE && level != CGame::currLevel){ - debug("changing level %d -> %d\n", CGame::currLevel, level); + if(level != LEVEL_NONE && level != CGame::currLevel) CGame::currLevel = level; - } if(ms_collisionInMemory != CGame::currLevel) - LoadCollisionWhenINeedIt(changeLevel); + LoadCollisionWhenINeedIt(forceLevelChange); CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); } -void -CCollision::LoadCollisionWhenINeedIt(bool changeLevel) +eLevelName +GetCollisionInSectorList(CPtrList &list) { - eLevelName level; + CPtrNode *node; + CEntity *e; + int level; + + for(node = list.first; node; node = node->next){ + e = (CEntity*)node->item; + level = CModelInfo::GetModelInfo(e->GetModelIndex())->GetColModel()->level; + if(level != LEVEL_NONE) + return (eLevelName)level; + } + return LEVEL_NONE; +} + +// Get a level this sector is in based on collision models +eLevelName +GetCollisionInSector(CSector §) +{ + int level; + + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_BUILDINGS_OVERLAP]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_OBJECTS_OVERLAP]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES]); + if(level == LEVEL_NONE) + level = GetCollisionInSectorList(sect.m_lists[ENTITYLIST_DUMMIES_OVERLAP]); + return (eLevelName)level; +} + +void +CCollision::LoadCollisionWhenINeedIt(bool forceChange) +{ + eLevelName level, l; + bool multipleLevels; + CVector playerCoors; + CVehicle *veh; + CEntryInfoNode *ei; + int sx, sy; + int xmin, xmax, ymin, ymax; + int x, y; + level = LEVEL_NONE; - if(!changeLevel){ - //assert(0 && "unimplemented"); + + playerCoors = FindPlayerCoors(); + sx = CWorld::GetSectorIndexX(playerCoors.x); + sy = CWorld::GetSectorIndexY(playerCoors.y); + multipleLevels = false; + + veh = FindPlayerVehicle(); + if(veh && veh->IsTrain()){ + if(((CTrain*)veh)->m_doorState != TRAIN_DOOR_STATE2) + return ; + }else if(playerCoors.z < 4.0f && !CCullZones::DoINeedToLoadCollision()) + return; + + // Figure out whose level's collisions we're most likely to be interested in + if(!forceChange){ + if(veh && veh->IsBoat()){ + // on water we expect to be between levels + multipleLevels = true; + }else{ + xmin = max(sx - 1, 0); + xmax = min(sx + 1, NUMSECTORS_X-1); + ymin = max(sy - 1, 0); + ymax = min(sy + 1, NUMSECTORS_Y-1); + + for(x = xmin; x <= xmax; x++) + for(y = ymin; y <= ymax; y++){ + l = GetCollisionInSector(*CWorld::GetSector(x, y)); + if(l != LEVEL_NONE){ + if(level == LEVEL_NONE) + level = l; + if(level != l) + multipleLevels = true; + } + } + } + + if(multipleLevels && veh && veh->IsBoat()) + for(ei = veh->m_entryInfoList.first; ei; ei = ei->next){ + level = GetCollisionInSector(*ei->sector); + if(level != LEVEL_NONE) + break; + } } - if(level != CGame::currLevel || changeLevel){ + if(level == CGame::currLevel || forceChange){ CTimer::Stop(); + DMAudio.SetEffectsFadeVol(0); + CPad::StopPadsShaking(); + LoadCollisionScreen(CGame::currLevel); + DMAudio.Service(); + CPopulation::DealWithZoneChange(ms_collisionInMemory, CGame::currLevel, false); CStreaming::RemoveIslandsNotUsed(LEVEL_INDUSTRIAL); CStreaming::RemoveIslandsNotUsed(LEVEL_COMMERCIAL); CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); CStreaming::RemoveBigBuildings(LEVEL_INDUSTRIAL); CStreaming::RemoveBigBuildings(LEVEL_COMMERCIAL); CStreaming::RemoveBigBuildings(LEVEL_SUBURBAN); + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + CStreaming::RemoveUnusedModelsInLoadedList(); + CGame::TidyUpMemory(true, true); + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); ms_collisionInMemory = CGame::currLevel; + CReplay::EmptyReplayBuffer(); + if(CGame::currLevel != LEVEL_NONE) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); CStreaming::RemoveUnusedBigBuildings(CGame::currLevel); CStreaming::RemoveUnusedBuildings(CGame::currLevel); CStreaming::RequestBigBuildings(CGame::currLevel); - CStreaming::LoadAllRequestedModels(); + CStreaming::LoadAllRequestedModels(true); CStreaming::HaveAllBigBuildingsLoaded(CGame::currLevel); + CGame::TidyUpMemory(true, true); CTimer::Update(); + DMAudio.SetEffectsFadeVol(127); } } -#endif +void +CCollision::SortOutCollisionAfterLoad(void) +{ + if(ms_collisionInMemory == CGame::currLevel) + return; -WRAPPER void CCollision::SortOutCollisionAfterLoad(void) { EAXJMP(0x40B900); } + CModelInfo::RemoveColModelsFromOtherLevels(CGame::currLevel); + if(CGame::currLevel != LEVEL_NONE){ + CFileLoader::LoadCollisionFromDatFile(CGame::currLevel); + if(!CGame::playingIntro) + LoadSplash(GetLevelSplashScreen(CGame::currLevel)); + } + ms_collisionInMemory = CGame::currLevel; + CGame::TidyUpMemory(true, false); +} + +void +CCollision::LoadCollisionScreen(eLevelName level) +{ + static char *levelNames[4] = { + "", + "IND_ZON", + "COM_ZON", + "SUB_ZON" + }; + + // Why twice? + LoadingIslandScreen(levelNames[level]); + LoadingIslandScreen(levelNames[level]); +} // // Test @@ -1585,11 +1730,119 @@ CColModel::GetTrianglePoint(CVector &v, int i) const v = vertices[i]; } -WRAPPER CColModel& CColModel::operator=(const CColModel& other) { EAXJMP(0x411710); } +CColModel& +CColModel::operator=(const CColModel &other) +{ + int i; + int numVerts; + + assert(0); + + boundingSphere = other.boundingSphere; + boundingBox = other.boundingBox; + + // copy spheres + if(other.numSpheres){ + if(numSpheres != other.numSpheres){ + numSpheres = other.numSpheres; + if(spheres) + RwFree(spheres); + spheres = (CColSphere*)RwMalloc(numSpheres*sizeof(CColSphere)); + } + for(i = 0; i < numSpheres; i++) + spheres[i] = other.spheres[i]; + }else{ + numSpheres = 0; + if(spheres) + RwFree(spheres); + spheres = nil; + } + + // copy lines + if(other.numLines){ + if(numLines != other.numLines){ + numLines = other.numLines; + if(lines) + RwFree(lines); + lines = (CColLine*)RwMalloc(numLines*sizeof(CColLine)); + } + for(i = 0; i < numLines; i++) + lines[i] = other.lines[i]; + }else{ + numLines = 0; + if(lines) + RwFree(lines); + lines = nil; + } + + // copy boxes + if(other.numBoxes){ + if(numBoxes != other.numBoxes){ + numBoxes = other.numBoxes; + if(boxes) + RwFree(boxes); + boxes = (CColBox*)RwMalloc(numBoxes*sizeof(CColBox)); + } + for(i = 0; i < numBoxes; i++) + boxes[i] = other.boxes[i]; + }else{ + numBoxes = 0; + if(boxes) + RwFree(boxes); + boxes = nil; + } + + // copy mesh + if(other.numTriangles){ + // copy vertices + numVerts = 0; + for(i = 0; i < other.numTriangles; i++){ + if(other.triangles[i].a > numVerts) + other.triangles[i].a = numVerts; + if(other.triangles[i].b > numVerts) + other.triangles[i].b = numVerts; + if(other.triangles[i].c > numVerts) + other.triangles[i].c = numVerts; + } + numVerts++; + if(vertices) + RwFree(vertices); + if(numVerts){ + vertices = (CVector*)RwMalloc(numVerts*sizeof(CVector)); + for(i = 0; i < numVerts; i++) + vertices[i] = other.vertices[i]; + } + + // copy triangles + if(numTriangles != other.numTriangles){ + numTriangles = other.numTriangles; + if(triangles) + RwFree(triangles); + triangles = (CColTriangle*)RwMalloc(numTriangles*sizeof(CColTriangle)); + } + for(i = 0; i < numTriangles; i++) + triangles[i] = other.triangles[i]; + }else{ + numTriangles = 0; + if(triangles) + RwFree(triangles); + triangles = nil; + if(vertices) + RwFree(vertices); + vertices = nil; + } + return *this; +} STARTPATCHES InjectHook(0x4B9C30, (CMatrix& (*)(const CMatrix &src, CMatrix &dst))Invert, PATCH_JUMP); + InjectHook(0x40B380, CCollision::Init, PATCH_JUMP); + InjectHook(0x40B3A0, CCollision::Shutdown, PATCH_JUMP); + InjectHook(0x40B3B0, CCollision::Update, PATCH_JUMP); + InjectHook(0x40B5B0, CCollision::LoadCollisionWhenINeedIt, PATCH_JUMP); + InjectHook(0x40B900, CCollision::SortOutCollisionAfterLoad, PATCH_JUMP); + InjectHook(0x40BB70, CCollision::TestSphereBox, PATCH_JUMP); InjectHook(0x40E130, CCollision::TestLineBox, PATCH_JUMP); InjectHook(0x40E5C0, CCollision::TestVerticalLineBox, PATCH_JUMP); diff --git a/src/Collision.h b/src/Collision.h index aa125334..5a9058d3 100644 --- a/src/Collision.h +++ b/src/Collision.h @@ -118,9 +118,11 @@ public: static CLinkList &ms_colModelCache; static void Init(void); + static void Shutdown(void); static void Update(void); static void LoadCollisionWhenINeedIt(bool changeLevel); static void SortOutCollisionAfterLoad(void); + static void LoadCollisionScreen(eLevelName level); static void DrawColModel(const CMatrix &mat, const CColModel &colModel); static void DrawColModel_Coloured(const CMatrix &mat, const CColModel &colModel, int32 id); diff --git a/src/CullZones.cpp b/src/CullZones.cpp index f89d8256..6155ae57 100644 --- a/src/CullZones.cpp +++ b/src/CullZones.cpp @@ -2,6 +2,7 @@ #include "patcher.h" #include "Building.h" #include "Treadable.h" +#include "Train.h" #include "Pools.h" #include "Timer.h" #include "Camera.h" @@ -71,7 +72,6 @@ void CCullZones::Update(void) { bool invisible; - CVector v; if(bCullZonesDisabled) return; @@ -95,7 +95,7 @@ CCullZones::Update(void) case 6: /* Update player attributes */ - CurrentFlags_Player = FindAttributesForCoors(FindPlayerCoors(v), + CurrentFlags_Player = FindAttributesForCoors(FindPlayerCoors(), &CurrentWantedLevelDrop_Player); break; } @@ -152,7 +152,7 @@ CCullZones::FindZoneWithStairsAttributeForPlayer(void) int i; CVector coors; - FindPlayerCoors(coors); + coors = FindPlayerCoors(); for(i = 0; i < NumAttributeZones; i++) if(aAttributeZones[i].attributes & ATTRZONE_STAIRS && coors.x >= aAttributeZones[i].minx && coors.x <= aAttributeZones[i].maxx && @@ -162,9 +162,33 @@ CCullZones::FindZoneWithStairsAttributeForPlayer(void) return nil; } -WRAPPER void +void CCullZones::MarkSubwayAsInvisible(bool visible) -{ EAXJMP(0x525AF0); +{ + int i, n; + CEntity *e; + CVehicle *v; + + n = CPools::GetBuildingPool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetBuildingPool()->GetSlot(i); + if(e && e->bIsSubway) + e->bIsVisible = visible; + } + + n = CPools::GetTreadablePool()->GetSize(); + for(i = 0; i < n; i++){ + e = CPools::GetTreadablePool()->GetSlot(i); + if(e && e->bIsSubway) + e->bIsVisible = visible; + } + + n = CPools::GetVehiclePool()->GetSize(); + for(i = 0; i < n; i++){ + v = CPools::GetVehiclePool()->GetSlot(i); + if(v && v->IsTrain() && ((CTrain*)v)->m_trackId != 0) + v->bIsVisible = visible; + } } void diff --git a/src/FileLoader.cpp b/src/FileLoader.cpp index dd58614d..8213a5c7 100644 --- a/src/FileLoader.cpp +++ b/src/FileLoader.cpp @@ -46,7 +46,7 @@ CFileLoader::LoadLevel(const char *filename) { int fd; RwTexDictionary *savedTxd; - int savedLevel; + eLevelName savedLevel; bool objectsLoaded; char *line; char txdname[64]; @@ -79,7 +79,7 @@ CFileLoader::LoadLevel(const char *filename) }else if(strncmp(line, "COLFILE", 7) == 0){ int level; sscanf(line+8, "%d", &level); - CGame::currLevel = level; + CGame::currLevel = (eLevelName)level; LoadingScreenLoadingFile(line+10); LoadCollisionFile(line+10); CGame::currLevel = savedLevel; diff --git a/src/FileMgr.cpp b/src/FileMgr.cpp index d4e0b89b..954fcdef 100644 --- a/src/FileMgr.cpp +++ b/src/FileMgr.cpp @@ -265,10 +265,10 @@ CFileMgr::Seek(int fd, int offset, int whence) return !!myfseek(fd, offset, whence); } -char* +bool CFileMgr::ReadLine(int fd, char *buf, int len) { - return myfgets(buf, len, fd); + return myfgets(buf, len, fd) != nil; } int diff --git a/src/FileMgr.h b/src/FileMgr.h index f67056f1..bab86e38 100644 --- a/src/FileMgr.h +++ b/src/FileMgr.h @@ -15,7 +15,7 @@ public: static int Read(int fd, char *buf, int len); static int Write(int fd, char *buf, int len); static bool Seek(int fd, int offset, int whence); - static char *ReadLine(int fd, char *buf, int len); + static bool ReadLine(int fd, char *buf, int len); static int CloseFile(int fd); static int GetErrorReadWrite(int fd); }; diff --git a/src/Game.cpp b/src/Game.cpp index f158e9db..cbd55c48 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -2,7 +2,7 @@ #include "patcher.h" #include "Game.h" -int &CGame::currLevel = *(int*)0x941514; +eLevelName &CGame::currLevel = *(eLevelName*)0x941514; bool &CGame::bDemoMode = *(bool*)0x5F4DD0; bool &CGame::nastyGame = *(bool*)0x5F4DD4; bool &CGame::frenchGame = *(bool*)0x95CDCB; @@ -11,6 +11,7 @@ bool &CGame::noProstitutes = *(bool*)0x95CDCF; bool &CGame::playingIntro = *(bool*)0x95CDC2; char *CGame::aDatFile = (char*)0x773A48; +WRAPPER void CGame::Initialise(const char *datFile) { EAXJMP(0x48BED0); } WRAPPER void CGame::Process(void) { EAXJMP(0x48C850); } WRAPPER bool CGame::InitialiseOnceBeforeRW(void) { EAXJMP(0x48BB80); } WRAPPER bool CGame::InitialiseRenderWare(void) { EAXJMP(0x48BBA0); } diff --git a/src/Game.h b/src/Game.h index 6b071125..3bc3e633 100644 --- a/src/Game.h +++ b/src/Game.h @@ -11,7 +11,7 @@ enum eLevelName class CGame { public: - static int &currLevel; + static eLevelName &currLevel; static bool &bDemoMode; static bool &nastyGame; static bool &frenchGame; @@ -20,13 +20,18 @@ public: static bool &playingIntro; static char *aDatFile; //[32]; - static void Process(void); + static void Initialise(const char *datFile); static bool InitialiseOnceBeforeRW(void); static bool InitialiseRenderWare(void); + static bool InitialiseOnceAfterRW(void); + static void InitialiseWhenRestarting(void); + static void ShutDown(void); static void ShutdownRenderWare(void); static void FinalShutdown(void); - static void ShutDown(void); static void ShutDownForRestart(void); - static void InitialiseWhenRestarting(void); - static bool InitialiseOnceAfterRW(void); + static void Process(void); + + // NB: these do something on PS2 + static void TidyUpMemory(bool, bool) {} + static void DrasticTidyUpMemory(void) {} }; diff --git a/src/Radar.cpp b/src/Radar.cpp index 71f9aacd..839aa3af 100644 --- a/src/Radar.cpp +++ b/src/Radar.cpp @@ -279,7 +279,7 @@ void CRadar::DrawBlips() if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1) angle = PI + FindPlayerHeading(); else - angle = FindPlayerHeading() - (PI + atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y)); + angle = FindPlayerHeading() - (PI + TheCamera.GetForward().Heading()); DrawRotatingRadarSprite(CentreSprite, out.x, out.y, angle, 255); @@ -868,8 +868,8 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D { float s, c; - s = -sin(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y)); - c = cos(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y)); + s = -sin(TheCamera.GetForward().Heading()); + c = cos(TheCamera.GetForward().Heading()); if (TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWN1 || TheCamera.Cams[TheCamera.ActiveCam].Mode == CCam::MODE_TOPDOWNPED) { s = 0.0f; @@ -885,8 +885,8 @@ void CRadar::TransformRadarPointToRealWorldSpace(CVector2D &out, const CVector2D else forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; - s = -sin(atan2(-forward.x, forward.y)); - c = cos(atan2(-forward.x, forward.y)); + s = -sin(forward.Heading()); + c = cos(forward.Heading()); } out.x = s * in.y + c * in.x; @@ -915,8 +915,8 @@ void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D c = 1.0f; } else if (TheCamera.GetLookDirection() == LOOKING_FORWARD) { - s = sin(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y)); - c = cos(atan2(-TheCamera.GetForward().x, TheCamera.GetForward().y)); + s = sin(TheCamera.GetForward().Heading()); + c = cos(TheCamera.GetForward().Heading()); } else { CVector forward; @@ -928,8 +928,8 @@ void CRadar::TransformRealWorldPointToRadarSpace(CVector2D &out, const CVector2D else forward = TheCamera.Cams[TheCamera.ActiveCam].CamTargetEntity->GetPosition() - TheCamera.Cams[TheCamera.ActiveCam].SourceBeforeLookBehind; - s = sin(atan2(-forward.x, forward.y)); - c = cos(atan2(-forward.x, forward.y)); + s = sin(forward.Heading()); + c = cos(forward.Heading()); } float x = (in.x - vec2DRadarOrigin.x) * (1.0f / m_RadarRange); diff --git a/src/RwMatFX.cpp b/src/RwMatFX.cpp new file mode 100644 index 00000000..ca47e529 --- /dev/null +++ b/src/RwMatFX.cpp @@ -0,0 +1,212 @@ +#define WITHD3D +#include "common.h" +#include "patcher.h" + +struct MatFXNothing { int pad[5]; int effect; }; + +struct MatFXBump +{ + RwFrame *bumpFrame; + RwTexture *bumpedTex; + RwTexture *bumpTex; + float negBumpCoefficient; + int pad; + int effect; +}; + +struct MatFXEnv +{ + RwFrame *envFrame; + RwTexture *envTex; + float envCoeff; + int envFBalpha; + int pad; + int effect; +}; + +struct MatFXDual +{ + RwTexture *dualTex; + RwInt32 srcBlend; + RwInt32 dstBlend; +}; + + +struct MatFX +{ + union { + MatFXNothing n; + MatFXBump b; + MatFXEnv e; + MatFXDual d; + } fx[2]; + int effects; +}; + +int &MatFXMaterialDataOffset = *(int*)0x66188C; +int &MatFXAtomicDataOffset = *(int*)0x66189C; + +#ifdef PS2_MATFX + +void +_rpMatFXD3D8AtomicMatFXDefaultRender(RxD3D8InstanceData *inst, int flags, RwTexture *texture) +{ + if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) + RwD3D8SetTexture(texture, 0); + else + RwD3D8SetTexture(NULL, 0); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); + RwD3D8SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, inst->vertexAlpha != 0); + RwD3D8SetPixelShader(0); + RwD3D8SetVertexShader(inst->vertexShader); + RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); + + if(inst->indexBuffer){ + RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); + RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); + }else + RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); +} + +// map [-1; -1] -> [0; 1], flip V +static RwMatrix scalenormal = { + { 0.5f, 0.0f, 0.0f }, 0, + { 0.0f, -0.5f, 0.0f }, 0, + { 0.0f, 0.0f, 1.0f }, 0, + { 0.5f, 0.5f, 0.0f }, 0, + +}; + +// flipped U for PS2 +static RwMatrix scalenormal_flipU = { + { -0.5f, 0.0f, 0.0f }, 0, + { 0.0f, -0.5f, 0.0f }, 0, + { 0.0f, 0.0f, 1.0f }, 0, + { 0.5f, 0.5f, 0.0f }, 0, + +}; + +void +ApplyEnvMapTextureMatrix(RwTexture *tex, int n, RwFrame *frame) +{ + RwD3D8SetTexture(tex, n); + RwD3D8SetTextureStageState(n, D3DRS_ALPHAREF, 2); + RwD3D8SetTextureStageState(n, D3DTSS_TEXCOORDINDEX, D3DTSS_TCI_CAMERASPACENORMAL); + if(frame){ + RwMatrix *envframemat = RwMatrixCreate(); + RwMatrix *tmpmat = RwMatrixCreate(); + RwMatrix *envmat = RwMatrixCreate(); + + RwMatrixInvert(envframemat, RwFrameGetLTM(frame)); + // PS2 + // can this be simplified? + *tmpmat = *RwFrameGetLTM(RwCameraGetFrame((RwCamera*)RWSRCGLOBAL(curCamera))); + RwV3dNegate(&tmpmat->right, &tmpmat->right); + tmpmat->flags = 0; + tmpmat->pos.x = 0.0f; + tmpmat->pos.y = 0.0f; + tmpmat->pos.z = 0.0f; + RwMatrixMultiply(envmat, tmpmat, envframemat); + *tmpmat = *envmat; + // important because envframemat can have a translation that we don't like + tmpmat->pos.x = 0.0f; + tmpmat->pos.y = 0.0f; + tmpmat->pos.z = 0.0f; + // for some reason we flip in U as well + RwMatrixMultiply(envmat, tmpmat, &scalenormal_flipU); + + RwD3D8SetTransform(D3DTS_TEXTURE0+n, envmat); + + RwMatrixDestroy(envmat); + RwMatrixDestroy(tmpmat); + RwMatrixDestroy(envframemat); + }else + RwD3D8SetTransform(D3DTS_TEXTURE0+n, &scalenormal); +} + +void +_rpMatFXD3D8AtomicMatFXEnvRender_ps2(RxD3D8InstanceData *inst, int flags, int sel, RwTexture *texture, RwTexture *envMap) +{ + MatFX *matfx = *RWPLUGINOFFSET(MatFX*, inst->material, MatFXMaterialDataOffset); + MatFXEnv *env = &matfx->fx[sel].e; + + uint8 intens = (uint8)(env->envCoeff*255.0f); + + if(intens == 0 || envMap == nil){ + if(sel == 0) + _rpMatFXD3D8AtomicMatFXDefaultRender(inst, flags, texture); + return; + } + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)(inst->vertexAlpha || inst->material->color.alpha != 0xFF)); + if(flags & (rpGEOMETRYTEXTURED|rpGEOMETRYTEXTURED2) && texture) + RwD3D8SetTexture(texture, 0); + else + RwD3D8SetTexture(nil, 0); + RwD3D8SetVertexShader(inst->vertexShader); + RwD3D8SetStreamSource(0, inst->vertexBuffer, inst->stride); + RwD3D8SetIndices(inst->indexBuffer, inst->baseIndex); + if(inst->indexBuffer) + RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); + else + RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); + + // Effect pass + + ApplyEnvMapTextureMatrix(envMap, 0, env->envFrame); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwUInt32 src, dst, lighting, zwrite, fog, fogcol; + RwRenderStateGet(rwRENDERSTATESRCBLEND, &src); + RwRenderStateGet(rwRENDERSTATEDESTBLEND, &dst); + + // This is of course not using framebuffer alpha, + // but if the diffuse texture had no alpha, the result should actually be rather the same + if(env->envFBalpha) + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + else + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwD3D8GetRenderState(D3DRS_LIGHTING, &lighting); + RwD3D8GetRenderState(D3DRS_ZWRITEENABLE, &zwrite); + RwD3D8GetRenderState(D3DRS_FOGENABLE, &fog); + RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + if(fog){ + RwD3D8GetRenderState(D3DRS_FOGCOLOR, &fogcol); + RwD3D8SetRenderState(D3DRS_FOGCOLOR, 0); + } + + D3DCOLOR texfactor = D3DCOLOR_RGBA(intens, intens, intens, intens); + RwD3D8SetRenderState(D3DRS_TEXTUREFACTOR, texfactor); + RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE); + RwD3D8SetTextureStageState(1, D3DTSS_COLORARG1, D3DTA_CURRENT); + RwD3D8SetTextureStageState(1, D3DTSS_COLORARG2, D3DTA_TFACTOR); + // alpha unused + //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1); + //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG1, D3DTA_CURRENT); + //RwD3D8SetTextureStageState(1, D3DTSS_ALPHAARG2, D3DTA_TFACTOR); + + if(inst->indexBuffer) + RwD3D8DrawIndexedPrimitive(inst->primType, 0, inst->numVertices, 0, inst->numIndices); + else + RwD3D8DrawPrimitive(inst->primType, inst->baseIndex, inst->numVertices); + + // Reset states + + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)FALSE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)src); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)dst); + RwD3D8SetRenderState(D3DRS_LIGHTING, lighting); + RwD3D8SetRenderState(D3DRS_ZWRITEENABLE, zwrite); + if(fog) + RwD3D8SetRenderState(D3DRS_FOGCOLOR, fogcol); + RwD3D8SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + RwD3D8SetTextureStageState(1, D3DTSS_ALPHAOP, D3DTOP_DISABLE); + RwD3D8SetTextureStageState(0, D3DTSS_TEXTURETRANSFORMFLAGS, 0); + RwD3D8SetTextureStageState(0, D3DTSS_TEXCOORDINDEX, 0); +} + +STARTPATCHES + InjectHook(0x5CF6C0, _rpMatFXD3D8AtomicMatFXEnvRender_ps2, PATCH_JUMP); +ENDPATCHES + +#endif diff --git a/src/Streaming.cpp b/src/Streaming.cpp index f75f358a..08fd80f0 100644 --- a/src/Streaming.cpp +++ b/src/Streaming.cpp @@ -250,7 +250,6 @@ void CStreaming::Update(void) { CEntity *train; - CVector playerPos; CStreamingInfo *si, *prev; bool requestedSubway = false; @@ -280,8 +279,7 @@ CStreaming::Update(void) ms_numModelsRequested < 5 && !CRenderer::m_loadingPriority){ StreamVehiclesAndPeds(); - FindPlayerCoors(playerPos); - StreamZoneModels(playerPos); + StreamZoneModels(FindPlayerCoors()); } LoadRequestedModels(); diff --git a/src/Text.cpp b/src/Text.cpp index eeb46253..d7d63467 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -15,7 +15,7 @@ CText::CText(void) keyArray.numEntries = 0; data.chars = nil; data.numChars = 0; - unknown = 101; // What's this? version number? + encoding = 101; memset(WideErrorString, 0, sizeof(WideErrorString)); } @@ -96,6 +96,25 @@ CText::Get(const char *key) return keyArray.Search(key); } +wchar +CText::GetUpperCase(wchar c) +{ + // TODO: do this depending on encoding + if(islower(c)) + return toupper(c); + return c; +} + +void +CText::UpperCase(wchar *s) +{ + while(*s){ + *s = GetUpperCase(*s); + s++; + } +} + + void CKeyArray::Load(uint32 length, uint8 *data, int *offset) { @@ -186,9 +205,15 @@ CData::Unload(void) } void -AsciiToUnicode(const char *cs, uint16 *ws) +AsciiToUnicode(const char *src, uint16 *dst) { - while((*ws++ = *cs++) != '\0'); + while((*dst++ = *src++) != '\0'); +} + +void +TextCopy(wchar *dst, const wchar *src) +{ + while((*dst++ = *src++) != '\0'); } STARTPATCHES diff --git a/src/Text.h b/src/Text.h index 1aaef3b6..2592e6b8 100644 --- a/src/Text.h +++ b/src/Text.h @@ -1,6 +1,7 @@ #pragma once -void AsciiToUnicode(const char *cs, wchar *ws); +void AsciiToUnicode(const char *src, wchar *dst); +void TextCopy(wchar *dst, const wchar *src); struct CKeyEntry { @@ -37,13 +38,15 @@ class CText { CKeyArray keyArray; CData data; - int8 unknown; + int8 encoding; public: CText(void); ~CText(void); void Load(void); void Unload(void); wchar *Get(const char *key); + wchar GetUpperCase(wchar c); + void UpperCase(wchar *s); }; extern CText &TheText; diff --git a/src/World.cpp b/src/World.cpp index 0a83c595..538e15c5 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -2,13 +2,16 @@ #include "patcher.h" #include "Entity.h" #include "Ped.h" +#include "PlayerPed.h" +#include "Vehicle.h" #include "Object.h" +#include "Camera.h" +#include "DMAudio.h" +#include "CarCtrl.h" #include "Garages.h" #include "TempColModels.h" #include "World.h" -WRAPPER void CWorld::Add(CEntity *entity) { EAXJMP(0x4AE930); } - CPtrList *CWorld::ms_bigBuildingsList = (CPtrList*)0x6FAB60; CPtrList &CWorld::ms_listMovingEntityPtrs = *(CPtrList*)0x8F433C; CSector (*CWorld::ms_aSectors)[NUMSECTORS_X] = (CSector (*)[NUMSECTORS_Y])0x665608; @@ -23,6 +26,41 @@ bool &CWorld::bSecondShift = *(bool*)0x95CD54; bool &CWorld::bForceProcessControl = *(bool*)0x95CD6C; bool &CWorld::bProcessCutsceneOnly = *(bool*)0x95CD8B; +void +CWorld::Add(CEntity *ent) +{ + if(ent->IsVehicle() || ent->IsPed()) + DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, true); + + if(ent->bIsBIGBuilding) + ms_bigBuildingsList[ent->m_level].InsertItem(ent); + else + ent->Add(); + + if(ent->IsBuilding() || ent->IsDummy()) + return; + + if(!ent->bIsStatic) + ((CPhysical*)ent)->AddToMovingList(); +} + +void +CWorld::Remove(CEntity *ent) +{ + if(ent->IsVehicle() || ent->IsPed()) + DMAudio.SetEntityStatus(((CPhysical*)ent)->m_audioEntityId, false); + + if(ent->bIsBIGBuilding) + ms_bigBuildingsList[ent->m_level].RemoveItem(ent); + else + ent->Remove(); + + if(ent->IsBuilding() || ent->IsDummy()) + return; + + if(!ent->bIsStatic) + ((CPhysical*)ent)->RemoveFromMovingList(); +} void CWorld::ClearScanCodes(void) @@ -571,7 +609,98 @@ CWorld::FindRoofZFor3DCoord(float x, float y, float z, bool *found) } } +CPlayerPed* +FindPlayerPed(void) +{ + return CWorld::Players[CWorld::PlayerInFocus].m_pPed; +} + +CVehicle* +FindPlayerVehicle(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle; + else + return nil; +} + +CVehicle* +FindPlayerTrain(void) +{ + if(FindPlayerVehicle() && FindPlayerVehicle()->IsTrain()) + return FindPlayerVehicle(); + else + return nil; +} + +CEntity* +FindPlayerEntity(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle; + else + return ped; +} + +CVector +FindPlayerCoors(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle->GetPosition(); + else + return ped->GetPosition(); +} + +CVector& +FindPlayerSpeed(void) +{ + CPlayerPed *ped = CWorld::Players[CWorld::PlayerInFocus].m_pPed; + if(ped->bInVehicle && ped->m_pMyVehicle) + return ped->m_pMyVehicle->m_vecMoveSpeed; + else + return ped->m_vecMoveSpeed; +} + +CVector& +FindPlayerCentreOfWorld(int32 player) +{ + if(CCarCtrl::bCarsGeneratedAroundCamera) + return TheCamera.GetPosition(); + if(CWorld::Players[player].m_pRemoteVehicle) + return CWorld::Players[player].m_pRemoteVehicle->GetPosition(); + if(FindPlayerVehicle()) + return FindPlayerVehicle()->GetPosition(); + return CWorld::Players[player].m_pPed->GetPosition(); +} + +CVector& +FindPlayerCentreOfWorld_NoSniperShift(void) +{ + if(CCarCtrl::bCarsGeneratedAroundCamera) + return TheCamera.GetPosition(); + if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) + return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetPosition(); + if(FindPlayerVehicle()) + return FindPlayerVehicle()->GetPosition(); + return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetPosition(); +} + +float +FindPlayerHeading(void) +{ + if(CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle) + return CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle->GetForward().Heading(); + if(FindPlayerVehicle()) + return FindPlayerVehicle()->GetForward().Heading(); + return CWorld::Players[CWorld::PlayerInFocus].m_pPed->GetForward().Heading(); +} + STARTPATCHES + InjectHook(0x4AE930, CWorld::Add, PATCH_JUMP); + InjectHook(0x4AE9D0, CWorld::Remove, PATCH_JUMP); InjectHook(0x4B1F60, CWorld::ClearScanCodes, PATCH_JUMP); InjectHook(0x4AF970, CWorld::ProcessLineOfSight, PATCH_JUMP); InjectHook(0x4B0A80, CWorld::ProcessLineOfSightSector, PATCH_JUMP); @@ -587,11 +716,3 @@ STARTPATCHES InjectHook(0x4B3AE0, CWorld::FindGroundZFor3DCoord, PATCH_JUMP); InjectHook(0x4B3B50, CWorld::FindRoofZFor3DCoord, PATCH_JUMP); ENDPATCHES - -WRAPPER CPlayerPed *FindPlayerPed(void) { EAXJMP(0x4A1150); } -WRAPPER CVector &FindPlayerCoors(CVector &v) { EAXJMP(0x4A1030); } -WRAPPER CVehicle *FindPlayerVehicle(void) { EAXJMP(0x4A10C0); } -WRAPPER CVehicle *FindPlayerTrain(void) { EAXJMP(0x4A1120); } -WRAPPER CVector &FindPlayerSpeed(void) { EAXJMP(0x4A1090); } -WRAPPER CVector FindPlayerCentreOfWorld_NoSniperShift(void) { EAXJMP(0x4A11C0); } -WRAPPER float FindPlayerHeading(void) { EAXJMP(0x4A1220); } diff --git a/src/World.h b/src/World.h index e3a6a8f2..a2a6e3b2 100644 --- a/src/World.h +++ b/src/World.h @@ -68,6 +68,7 @@ public: static bool &bProcessCutsceneOnly; static void Add(CEntity *entity); + static void Remove(CEntity *ent); static CSector *GetSector(int x, int y) { return &ms_aSectors[y][x]; } static CPtrList &GetBigBuildingList(eLevelName i) { return ms_bigBuildingsList[i]; } @@ -108,9 +109,11 @@ public: class CPlayerPed; class CVehicle; CPlayerPed *FindPlayerPed(void); -CVector &FindPlayerCoors(CVector &v); CVehicle *FindPlayerVehicle(void); CVehicle *FindPlayerTrain(void); +CEntity *FindPlayerEntity(void); +CVector FindPlayerCoors(void); CVector &FindPlayerSpeed(void); -CVector FindPlayerCentreOfWorld_NoSniperShift(void); +CVector &FindPlayerCentreOfWorld(int32 player); +CVector &FindPlayerCentreOfWorld_NoSniperShift(void); float FindPlayerHeading(void); diff --git a/src/Zones.cpp b/src/Zones.cpp index d4ce07f6..4d2d9e5d 100644 --- a/src/Zones.cpp +++ b/src/Zones.cpp @@ -114,7 +114,7 @@ void CTheZones::Update(void) { CVector pos; - FindPlayerCoors(pos); + pos = FindPlayerCoors(); m_pPlayersZone = FindSmallestZonePosition(&pos); m_CurrLevel = GetLevelFromPosition(pos); } diff --git a/src/audio/DMAudio.cpp b/src/audio/DMAudio.cpp index 0bed8d4d..63f23c4a 100644 --- a/src/audio/DMAudio.cpp +++ b/src/audio/DMAudio.cpp @@ -25,5 +25,5 @@ WRAPPER uint8 cDMAudio::IsMP3RadioChannelAvailable() { EAXJMP(0x57C9F0); } WRAPPER void cDMAudio::SetEffectsFadeVol(uint8) { EAXJMP(0x57C8F0); } WRAPPER void cDMAudio::SetMusicFadeVol(uint8) { EAXJMP(0x57C920); } WRAPPER int32 cDMAudio::CreateEntity(int, void*) { EAXJMP(0x57C7C0); } -WRAPPER void cDMAudio::SetEntityStatus(int32, int8) { EAXJMP(0x57C810); } -WRAPPER void cDMAudio::SetRadioInCar(int32) { EAXJMP(0x57CE60); } \ No newline at end of file +WRAPPER void cDMAudio::SetEntityStatus(int32 id, uint8 enable) { EAXJMP(0x57C810); } +WRAPPER void cDMAudio::SetRadioInCar(int32) { EAXJMP(0x57CE60); } diff --git a/src/audio/DMAudio.h b/src/audio/DMAudio.h index 6df2ceea..646fa2ff 100644 --- a/src/audio/DMAudio.h +++ b/src/audio/DMAudio.h @@ -193,7 +193,7 @@ public: void SetEffectsFadeVol(uint8); void SetMusicFadeVol(uint8); int32 CreateEntity(int, void*); - void SetEntityStatus(int32, int8); + void SetEntityStatus(int32 id, uint8 enable); void SetRadioInCar(int32); uint8 IsMP3RadioChannelAvailable(); diff --git a/src/config.h b/src/config.h index 53a7ad11..61b4f9b6 100644 --- a/src/config.h +++ b/src/config.h @@ -77,3 +77,5 @@ enum Config { #define NO_MOVIES //#define USE_MY_DOCUMENTS #define NASTY_GAME +#define PS2_MATFX + diff --git a/src/control/CarCtrl.cpp b/src/control/CarCtrl.cpp index fe5b6dab..145c643c 100644 --- a/src/control/CarCtrl.cpp +++ b/src/control/CarCtrl.cpp @@ -3,6 +3,7 @@ #include "CarCtrl.h" int &CCarCtrl::NumLawEnforcerCars = *(int*)0x8F1B38; +bool &CCarCtrl::bCarsGeneratedAroundCamera = *(bool*)0x95CD8A; WRAPPER void CCarCtrl::SwitchVehicleToRealPhysics(CVehicle*) { EAXJMP(0x41F7F0); } WRAPPER void CCarCtrl::AddToCarArray(int32 id, int32 vehclass) { EAXJMP(0x4182F0); } diff --git a/src/control/CarCtrl.h b/src/control/CarCtrl.h index 27ea6293..3469dcf1 100644 --- a/src/control/CarCtrl.h +++ b/src/control/CarCtrl.h @@ -11,4 +11,5 @@ public: static int32 ChooseCarModel(int32 vehclass); static int32 &NumLawEnforcerCars; + static bool &bCarsGeneratedAroundCamera; }; diff --git a/src/control/Population.cpp b/src/control/Population.cpp index fd1a89f5..7b1acaaf 100644 --- a/src/control/Population.cpp +++ b/src/control/Population.cpp @@ -1,8 +1,10 @@ #include "common.h" #include "patcher.h" +#include "Game.h" #include "Population.h" PedGroup *CPopulation::ms_pPedGroups = (PedGroup*)0x6E9248; bool &CPopulation::ms_bGivePedsWeapons = *(bool*)0x95CCF6; WRAPPER void CPopulation::UpdatePedCount(uint32, bool) { EAXJMP(0x4F5A60); } +WRAPPER void CPopulation::DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool) { EAXJMP(0x4F6200); } diff --git a/src/control/Population.h b/src/control/Population.h index 76442442..e93e14fc 100644 --- a/src/control/Population.h +++ b/src/control/Population.h @@ -14,4 +14,5 @@ public: static bool &ms_bGivePedsWeapons; static void UpdatePedCount(uint32, bool); + static void DealWithZoneChange(eLevelName oldLevel, eLevelName newLevel, bool); }; diff --git a/src/control/Replay.cpp b/src/control/Replay.cpp index 8003b407..055c4ada 100644 --- a/src/control/Replay.cpp +++ b/src/control/Replay.cpp @@ -165,6 +165,8 @@ void CReplay::Init(void) bDoLoadSceneWhenDone = false; } +WRAPPER void CReplay::EmptyReplayBuffer(void) { EAXJMP(0x595BD0); } + void CReplay::DisableReplays(void) { bReplayEnabled = false; @@ -212,7 +214,7 @@ void CReplay::RecordThisFrame(void) tGeneralPacket* general = (tGeneralPacket*)&Record.m_pBase[Record.m_nOffset]; general->type = REPLAYPACKET_GENERAL; general->camera_pos.CopyOnlyMatrix(&TheCamera.GetMatrix()); - FindPlayerCoors(general->player_pos); + general->player_pos = FindPlayerCoors(); general->in_rcvehicle = CWorld::Players[CWorld::PlayerInFocus].m_pRemoteVehicle ? true : false; Record.m_nOffset += sizeof(*general); tClockPacket* clock = (tClockPacket*)&Record.m_pBase[Record.m_nOffset]; @@ -601,8 +603,8 @@ void CReplay::RestoreStuffFromMem(void) ped->m_modelIndex = -1; ped->SetModelIndex(mi); ped->m_pVehicleAnim = 0; - ped->uAudioEntityId = DMAudio.CreateEntity(0, ped); - DMAudio.SetEntityStatus(ped->uAudioEntityId, 1); + ped->m_audioEntityId = DMAudio.CreateEntity(0, ped); + DMAudio.SetEntityStatus(ped->m_audioEntityId, true); CPopulation::UpdatePedCount(ped->m_nPedType, false); if (ped->m_wepModelID >= 0) ped->AddWeaponModel(ped->m_wepModelID); @@ -639,8 +641,8 @@ void CReplay::RestoreStuffFromMem(void) car->SetDoorDamage(16, 4, true); /* DOOR_BACK_LEFT */ car->SetDoorDamage(12, 5, true); /* DOOR_BACK_RIGHT */ } - vehicle->uAudioEntityId = DMAudio.CreateEntity(0, vehicle); - DMAudio.SetEntityStatus(vehicle->uAudioEntityId, 1); + vehicle->m_audioEntityId = DMAudio.CreateEntity(0, vehicle); + DMAudio.SetEntityStatus(vehicle->m_audioEntityId, true); CCarCtrl::UpdateCarCount(vehicle, false); if ((mi == MI_AIRTRAIN || mi == MI_DEADDODO) && vehicle->m_rwObject){ CVehicleModelInfo* info = (CVehicleModelInfo*)CModelInfo::GetModelInfo(mi); diff --git a/src/control/Replay.h b/src/control/Replay.h index b622788f..c4f3b1a2 100644 --- a/src/control/Replay.h +++ b/src/control/Replay.h @@ -244,6 +244,7 @@ private: public: static void Init(void); + static void EmptyReplayBuffer(void); static void DisableReplays(void); static void EnableReplays(void); static void Update(void); diff --git a/src/entities/CopPed.h b/src/entities/CopPed.h index d41c2e9e..23d52ad0 100644 --- a/src/entities/CopPed.h +++ b/src/entities/CopPed.h @@ -4,18 +4,18 @@ enum eCrimeType { CRIME_NONE, - CRIME_SHOT_FIRED, - CRIME_PED_FIGHT, - CRIME_COP_FIGHT, - CRIME_DAMAGED_PED, - CRIME_DAMAGED_COP, - CRIME_CAR_THEFT, - CRIME_CRIME7, - CRIME_COP_EVASIVE_DIVE, - CRIME_COP_EVASIVE_DIVE2, - CRIME_PED_RUN_OVER, - CRIME_COP_RUN_OVER, - CRIME_DESTROYED_HELI, + CRIME_POSSESSION_GUN, + CRIME_HIT_PED, + CRIME_HIT_COP, + CRIME_SHOOT_PED, + CRIME_SHOOT_COP, + CRIME_STEAL_CAR, + CRIME_RUN_REDLIGHT, + CRIME_RECKLESS_DRIVING, + CRIME_SPEEDING, + CRIME_RUNOVER_PED, + CRIME_RUNOVER_COP, + CRIME_SHOOT_HELI, CRIME_PED_BURNED, CRIME_COP_BURNED, CRIME_VEHICLE_BURNED, diff --git a/src/entities/Dummy.cpp b/src/entities/Dummy.cpp index a4880175..68b67b5c 100644 --- a/src/entities/Dummy.cpp +++ b/src/entities/Dummy.cpp @@ -1,7 +1,57 @@ #include "common.h" #include "patcher.h" -#include "Dummy.h" #include "Pools.h" +#include "World.h" +#include "Dummy.h" void *CDummy::operator new(size_t sz) { return CPools::GetDummyPool()->New(); } void CDummy::operator delete(void *p, size_t sz) { CPools::GetDummyPool()->Delete((CDummy*)p); } + +void +CDummy::Add(void) +{ + int x, xstart, xmid, xend; + int y, ystart, ymid, yend; + CSector *s; + CPtrList *list; + + CRect bounds = GetBoundRect(); + xstart = CWorld::GetSectorIndexX(bounds.left); + xend = CWorld::GetSectorIndexX(bounds.right); + xmid = CWorld::GetSectorIndexX((bounds.left + bounds.right)/2.0f); + ystart = CWorld::GetSectorIndexY(bounds.top); + yend = CWorld::GetSectorIndexY(bounds.bottom); + ymid = CWorld::GetSectorIndexY((bounds.top + bounds.bottom)/2.0f); + assert(xstart >= 0); + assert(xend < NUMSECTORS_X); + assert(ystart >= 0); + assert(yend < NUMSECTORS_Y); + + for(y = ystart; y <= yend; y++) + for(x = xstart; x <= xend; x++){ + s = CWorld::GetSector(x, y); + if(x == xmid && y == ymid) + list = &s->m_lists[ENTITYLIST_OBJECTS]; + else + list = &s->m_lists[ENTITYLIST_DUMMIES_OVERLAP]; + CPtrNode *node = list->InsertItem(this); + assert(node); + m_entryInfoList.InsertItem(list, node, s); + } +} + +void +CDummy::Remove(void) +{ + CEntryInfoNode *node, *next; + for(node = m_entryInfoList.first; node; node = next){ + next = node->next; + node->list->DeleteNode(node->listnode); + m_entryInfoList.DeleteNode(node); + } +} + +STARTPATCHES + InjectHook(0x473860, &CDummy::Add_, PATCH_JUMP); + InjectHook(0x473AD0, &CDummy::Remove_, PATCH_JUMP); +ENDPATCHES diff --git a/src/entities/Dummy.h b/src/entities/Dummy.h index 034d4c57..4cfef2e2 100644 --- a/src/entities/Dummy.h +++ b/src/entities/Dummy.h @@ -9,9 +9,14 @@ public: CEntryInfoList m_entryInfoList; CDummy(void) { m_type = ENTITY_TYPE_DUMMY; } - // TODO: Add, Remove + void Add(void); + void Remove(void); static void *operator new(size_t); static void operator delete(void*, size_t); + + // to make patching virtual functions possible + void Add_(void) { CDummy::Add(); } + void Remove_(void) { CDummy::Remove(); } }; static_assert(sizeof(CDummy) == 0x68, "CDummy: error"); diff --git a/src/entities/Ped.cpp b/src/entities/Ped.cpp index 74cdab09..7f83ea84 100644 --- a/src/entities/Ped.cpp +++ b/src/entities/Ped.cpp @@ -771,9 +771,9 @@ CPed::Attack(void) } } else { if (weaponAnimAssoc->animId == ANIM_WEAPON_BAT_V || weaponAnimAssoc->animId == ANIM_WEAPON_BAT_H) { - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_BAT_ATTACK, 1.0f); } else if (weaponAnimAssoc->animId == ANIM_FIGHT_PPUNCH) { - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_PUNCH_ATTACK, 0.0f); } weaponAnimAssoc->speed = 0.5f; @@ -843,13 +843,13 @@ CPed::Attack(void) if (weaponAnimAssoc->currentTime - weaponAnimAssoc->timeStep <= ourWeapon->m_fAnimLoopEnd) { switch (ourWeaponType) { case WEAPONTYPE_UZI: - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_UZI_BULLET_ECHO, 0.0f); break; case WEAPONTYPE_AK47: - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_AK47_BULLET_ECHO, 0.0f); break; case WEAPONTYPE_M16: - DMAudio.PlayOneShot(uAudioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); + DMAudio.PlayOneShot(m_audioEntityId, SOUND_WEAPON_M16_BULLET_ECHO, 0.0f); break; default: break; @@ -1281,19 +1281,19 @@ CPed::LineUpPedWithCar(PedLineUpPhase phase) if (m_vehEnterType == VEHICLE_ENTER_FRONT_RIGHT || m_vehEnterType == VEHICLE_ENTER_REAR_RIGHT) { if (vehIsUpsideDown) { - m_fRotationDest = -PI + atan2(-veh->GetForward().x, veh->GetForward().y); + m_fRotationDest = -PI + veh->GetForward().Heading(); } else if (veh->bIsBus) { - m_fRotationDest = 0.5 * PI + atan2(-veh->GetForward().x, veh->GetForward().y); + m_fRotationDest = 0.5 * PI + veh->GetForward().Heading(); } else { - m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y); + m_fRotationDest = veh->GetForward().Heading(); } } else if (m_vehEnterType == VEHICLE_ENTER_FRONT_LEFT || m_vehEnterType == VEHICLE_ENTER_REAR_LEFT) { if (vehIsUpsideDown) { - m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y); + m_fRotationDest = veh->GetForward().Heading(); } else if (veh->bIsBus) { - m_fRotationDest = -0.5 * PI + atan2(-veh->GetForward().x, veh->GetForward().y); + m_fRotationDest = -0.5 * PI + veh->GetForward().Heading(); } else { - m_fRotationDest = atan2(-veh->GetForward().x, veh->GetForward().y); + m_fRotationDest = veh->GetForward().Heading(); } } @@ -1539,7 +1539,7 @@ CPed::PlayFootSteps(void) stepPart = 2; if (stepPart != 0) { - DMAudio.PlayOneShot(uAudioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); + DMAudio.PlayOneShot(m_audioEntityId, stepPart == 1 ? SOUND_STEP_START : SOUND_STEP_END, 1.0f); CVector footPos(0.0f, 0.0f, 0.0f); for (RwFrame *frame = GetNodeFrame(stepPart == 1 ? PED_FOOTL : PED_FOOTR); frame; frame = RwFrameGetParent(frame)) diff --git a/src/entities/Physical.cpp b/src/entities/Physical.cpp index 3e043a32..64e0fb8b 100644 --- a/src/entities/Physical.cpp +++ b/src/entities/Physical.cpp @@ -42,7 +42,7 @@ CPhysical::CPhysical(void) m_vecDamageNormal = CVector(0.0f, 0.0f, 0.0f); bUsesCollision = true; - uAudioEntityId = -5; + m_audioEntityId = -5; unk1 = 100.0f; m_vecCentreOfMass = CVector(0.0f, 0.0f, 0.0f); field_EC = 0; diff --git a/src/entities/Physical.h b/src/entities/Physical.h index 11d2a1f9..749e2dd8 100644 --- a/src/entities/Physical.h +++ b/src/entities/Physical.h @@ -14,7 +14,7 @@ class CPhysical : public CEntity public: // The not properly indented fields haven't been checked properly yet - int uAudioEntityId; + int32 m_audioEntityId; float unk1; CTreadable *m_carTreadable; CTreadable *m_pedTreadable; @@ -58,9 +58,8 @@ public: uint8 bHitByTrain : 1; // from nick uint8 m_phy_flagA80 : 1; - uint8 m_nLastCollType; - uint8 m_nZoneLevel; - uint8 pad[3]; + uint8 m_nLastCollType; + uint8 m_nZoneLevel; CPhysical(void); ~CPhysical(void); diff --git a/src/entities/PlayerInfo.h b/src/entities/PlayerInfo.h index abda1b23..79f379d5 100644 --- a/src/entities/PlayerInfo.h +++ b/src/entities/PlayerInfo.h @@ -1,6 +1,6 @@ #pragma once -#include "Automobile.h" -#include "PlayerPed.h" + +#include "Collision.h" enum eWastedBustedState { @@ -10,10 +10,9 @@ enum eWastedBustedState WBSTATE_FAILED_CRITICAL_MISSION, }; -struct CCivilianPed -{ - -}; +class CVehicle; +class CPlayerPed; +class CCivilianPed; class CPlayerInfo { @@ -22,10 +21,7 @@ public: CVehicle *m_pRemoteVehicle; CColModel m_ColModel; CVehicle *m_pVehicleEx; - char m_aszPlayerName[70]; -private: - int8 _pad0[2]; -public: + char m_aPlayerName[70]; int32 m_nMoney; int32 m_nVisibleMoney; int32 m_nCollectedPackages; @@ -40,7 +36,7 @@ public: int32 m_nNextSexMoneyUpdateTime; int32 m_nSexFrequency; CCivilianPed *m_pHooker; - int8 m_bWBState; // eWastedBustedState + int8 m_WBState; // eWastedBustedState int8 field_217; int8 field_218; int8 field_219; @@ -71,4 +67,4 @@ public: RwTexture *m_pSkinTexture; }; -static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerPed: error"); +static_assert(sizeof(CPlayerInfo) == 0x13C, "CPlayerInfo: error"); diff --git a/src/entities/Train.h b/src/entities/Train.h index e591239b..f3fb9a40 100644 --- a/src/entities/Train.h +++ b/src/entities/Train.h @@ -2,10 +2,19 @@ #include "Vehicle.h" +enum +{ + TRAIN_DOOR_STATE2 = 2 +}; + class CTrain : public CVehicle { public: // 0x288 - uint8 stuff[92]; + uint8 stuff1[20]; + uint8 m_trackId; + uint8 stuff2[7]; + int16 m_doorState; + uint8 stuff3[62]; }; static_assert(sizeof(CTrain) == 0x2E4, "CTrain: error"); diff --git a/src/main.cpp b/src/main.cpp index d1ffbe6b..c8af9ae0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -90,6 +90,13 @@ void PrintGameVersion(); RwRGBA gColourTop; +void +InitialiseGame(void) +{ + LoadingScreen(nil, nil, "loadsc0"); + CGame::Initialise("DATA\\GTA3.DAT"); +} + void Idle(void *arg) { @@ -591,6 +598,61 @@ ResetLoadingScreenBar(void) NumberOfChunksLoaded = 0.0f; } +void +LoadingIslandScreen(const char *levelName) +{ + CSprite2d *splash; + wchar *name; + char str[100]; + wchar wstr[80]; + CRGBA col; + + splash = LoadSplash(nil); + name = TheText.Get(levelName); + if(!DoRWStuffStartOfFrame(0, 0, 0, 0, 0, 0, 255)) + return; + + CSprite2d::SetRecipNearClip(); + CSprite2d::InitPerFrame(); + CFont::InitPerFrame(); + DefinedState(); + col = CRGBA(255, 255, 255, 255); + splash->Draw(CRect(0.0f, 0.0f, SCREENW, SCREENH), col, col, col, col); + CFont::SetBackgroundOff(); + CFont::SetScale(1.5f, 1.5f); + CFont::SetPropOn(); + CFont::SetRightJustifyOn(); + CFont::SetRightJustifyWrap(150.0f); + CFont::SetFontStyle(FONT_HEADING); + sprintf(str, "WELCOME TO"); + AsciiToUnicode(str, wstr); + CFont::SetDropColor(CRGBA(0, 0, 0, 255)); + CFont::SetDropShadowPosition(3); + CFont::SetColor(CRGBA(243, 237, 71, 255)); + CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); + CFont::PrintString(SCREENW - 20, SCREEN_STRETCH_FROM_BOTTOM(110.0f), TheText.Get("WELCOME")); + TextCopy(wstr, name); + TheText.UpperCase(wstr); + CFont::SetColor(CRGBA(243, 237, 71, 255)); + CFont::SetScale(SCREEN_STRETCH_X(1.2f), SCREEN_STRETCH_Y(1.2f)); + CFont::PrintString(SCREENW-20, SCREEN_STRETCH_FROM_BOTTOM(80.0f), wstr); + CFont::DrawFonts(); + DoRWStuffEndOfFrame(); +} + +char* +GetLevelSplashScreen(int level) +{ + static char *splashScreens[4] = { + nil, + "splash1", + "splash2", + "splash3", + }; + + return splashScreens[level]; +} + char* GetRandomSplashScreen(void) { diff --git a/src/main.h b/src/main.h index 45948b34..c7914549 100644 --- a/src/main.h +++ b/src/main.h @@ -13,6 +13,9 @@ extern wchar *gUString; class CSprite2d; +void InitialiseGame(void); void LoadingScreen(const char *str1, const char *str2, const char *splashscreen); +void LoadingIslandScreen(const char *levelName); CSprite2d *LoadSplash(const char *name); +char *GetLevelSplashScreen(int level); char *GetRandomSplashScreen(void); diff --git a/src/math/Vector.h b/src/math/Vector.h index 60fcdee5..2c431d0d 100644 --- a/src/math/Vector.h +++ b/src/math/Vector.h @@ -22,6 +22,7 @@ public: return *((RwV3d*)this); } #endif + float Heading(void) const { return atan2(-x, y); } float Magnitude(void) const { return sqrt(x*x + y*y + z*z); } float MagnitudeSqr(void) const { return x*x + y*y + z*z; } float Magnitude2D(void) const { return sqrt(x*x + y*y); } diff --git a/src/modelinfo/ModelInfo.cpp b/src/modelinfo/ModelInfo.cpp index acc40824..454a73f1 100644 --- a/src/modelinfo/ModelInfo.cpp +++ b/src/modelinfo/ModelInfo.cpp @@ -175,6 +175,23 @@ CModelInfo::IsBoatModel(int32 id) ((CVehicleModelInfo*)GetModelInfo(id))->m_vehicleType == VEHICLE_TYPE_BOAT; } +void +CModelInfo::RemoveColModelsFromOtherLevels(eLevelName level) +{ + int i; + CBaseModelInfo *mi; + CColModel *colmodel; + + for(i = 0; i < MODELINFOSIZE; i++){ + mi = GetModelInfo(i); + if(mi){ + colmodel = mi->GetColModel(); + if(colmodel && colmodel->level != LEVEL_NONE && colmodel->level != level) + colmodel->RemoveCollisionVolumes(); + } + } +} + STARTPATCHES InjectHook(0x50B310, CModelInfo::Initialise, PATCH_JUMP); InjectHook(0x50B5B0, CModelInfo::ShutDown, PATCH_JUMP); @@ -184,4 +201,5 @@ STARTPATCHES InjectHook(0x50BAD0, CModelInfo::AddPedModel, PATCH_JUMP); InjectHook(0x50BA60, CModelInfo::AddVehicleModel, PATCH_JUMP); InjectHook(0x50B860, (CBaseModelInfo *(*)(const char*, int*))CModelInfo::GetModelInfo, PATCH_JUMP); + InjectHook(0x50BBC0, CModelInfo::RemoveColModelsFromOtherLevels, PATCH_JUMP); ENDPATCHES diff --git a/src/modelinfo/ModelInfo.h b/src/modelinfo/ModelInfo.h index 30be96ca..d20367d1 100644 --- a/src/modelinfo/ModelInfo.h +++ b/src/modelinfo/ModelInfo.h @@ -36,4 +36,5 @@ public: } static bool IsBoatModel(int32 id); + static void RemoveColModelsFromOtherLevels(eLevelName level); }; diff --git a/src/modelinfo/VehicleModelInfo.cpp b/src/modelinfo/VehicleModelInfo.cpp index 36a6f301..2f1d2027 100644 --- a/src/modelinfo/VehicleModelInfo.cpp +++ b/src/modelinfo/VehicleModelInfo.cpp @@ -1006,7 +1006,9 @@ CVehicleModelInfo::SetEnvironmentMapCB(RpMaterial *material, void *data) if(RpMaterialGetTexture(material) == 0) RpMaterialSetTexture(material, gpWhiteTexture); RpMatFXMaterialSetEffects(material, rpMATFXEFFECTENVMAP); +#ifndef PS2_MATFX spec *= 0.5f; // Tone down a bit for PC +#endif RpMatFXMaterialSetupEnvMap(material, (RwTexture*)data, pMatFxIdentityFrame, false, spec); } return material; diff --git a/src/re3.cpp b/src/re3.cpp index ec4f4439..4bdb5469 100644 --- a/src/re3.cpp +++ b/src/re3.cpp @@ -344,6 +344,8 @@ patch() Patch(0x46BC61+6, 1.0f); // car distance InjectHook(0x59E460, printf, PATCH_JUMP); + InjectHook(0x475E00, printf, PATCH_JUMP); // _Error + // stolen from silentpatch (sorry) Patch(0x5382BF, 0x0EEB); diff --git a/src/skel/win/win.cpp b/src/skel/win/win.cpp index 814cac84..2943475b 100644 --- a/src/skel/win/win.cpp +++ b/src/skel/win/win.cpp @@ -114,18 +114,11 @@ DWORD _dwMemAvailVideo; DWORD &_dwOperatingSystemVersion = *(DWORD*)0x70F290; RwUInt32 &gGameState = *(RwUInt32*)0x8F5838; -WRAPPER bool InitialiseGame(void) { EAXJMP(0x48E7E0); } - -WRAPPER const char *GetLevelSplashScreen(int32 number) { EAXJMP(0x48D750); } -// - -void LoadingScreen(char const *msg1, char const *msg2, char const *screen); -CSprite2d *LoadSplash(const char *name); enum eJoypadState { - JOYPAD_UNUSED, - JOYPAD_ATTACHED, + JOYPAD_UNUSED, + JOYPAD_ATTACHED, }; struct tJoy