diff options
Diffstat (limited to 'src/control')
-rw-r--r-- | src/control/Cranes.cpp | 4 | ||||
-rw-r--r-- | src/control/Garages.cpp | 2 | ||||
-rw-r--r-- | src/control/Pickups.cpp | 469 | ||||
-rw-r--r-- | src/control/Pickups.h | 25 | ||||
-rw-r--r-- | src/control/Record.cpp | 526 | ||||
-rw-r--r-- | src/control/Record.h | 90 | ||||
-rw-r--r-- | src/control/TrafficLights.cpp | 4 |
7 files changed, 1062 insertions, 58 deletions
diff --git a/src/control/Cranes.cpp b/src/control/Cranes.cpp index 021a5c19..33385dae 100644 --- a/src/control/Cranes.cpp +++ b/src/control/Cranes.cpp @@ -410,6 +410,8 @@ void CCrane::FindCarInSectorList(CPtrList* pList) if (pVehicle->GetPosition().x < m_fPickupX1 || pVehicle->GetPosition().x > m_fPickupX2 || pVehicle->GetPosition().y < m_fPickupY1 || pVehicle->GetPosition().y > m_fPickupY2) continue; + if (pVehicle->pDriver) + continue; if (Abs(pVehicle->GetMoveSpeed().x) >= CAR_MOVING_SPEED_THRESHOLD || Abs(pVehicle->GetMoveSpeed().y) >= CAR_MOVING_SPEED_THRESHOLD || Abs(pVehicle->GetMoveSpeed().z) >= CAR_MOVING_SPEED_THRESHOLD) @@ -674,4 +676,4 @@ void CranesLoad(uint8* buf, uint32 size) STARTPATCHES InjectHook(0x5454D0, CranesLoad, PATCH_JUMP); // GenericLoad -ENDPATCHES
\ No newline at end of file +ENDPATCHES diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 84d49bee..d971d453 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -2108,7 +2108,7 @@ void CGarages::CloseHideOutGaragesBeforeSave() aGarages[i].m_eGarageType != GARAGE_HIDEOUT_THREE) continue; if (aGarages[i].m_eGarageState != GS_FULLYCLOSED && - aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor()) { + (aGarages[i].m_eGarageType != GARAGE_HIDEOUT_ONE || !aGarages[i].IsAnyCarBlockingDoor())) { aGarages[i].m_eGarageState = GS_FULLYCLOSED; switch (aGarages[i].m_eGarageType) { case GARAGE_HIDEOUT_ONE: diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 774abd8c..eb561670 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -54,23 +54,6 @@ uint8 aWeaponGreens[] = { 0, 255, 128, 255, 0, 255, 128, 255, 0, 255, 255, 0, 25 uint8 aWeaponBlues[] = { 0, 0, 255, 0, 255, 255, 0, 128, 255, 0, 255, 0, 128, 255, 0, 0 }; float aWeaponScale[] = { 1.0f, 2.0f, 1.5f, 1.0f, 1.0f, 1.5f, 1.0f, 2.0f, 1.0f, 2.0f, 2.5f, 1.0f, 1.0f, 1.0f, 1.0f }; -WRAPPER void CPacManPickups::Init(void) { EAXJMP(0x432760); } -WRAPPER void CPacManPickups::Update(void) { EAXJMP(0x432800); } -WRAPPER void CPacManPickups::GeneratePMPickUps(CVector, float, int16, uint8) { EAXJMP(0x432AE0); } -WRAPPER void CPacManPickups::GeneratePMPickUpsForRace(int32) { EAXJMP(0x432D50); } -WRAPPER void CPacManPickups::GenerateOnePMPickUp(CVector) { EAXJMP(0x432F20); } -WRAPPER void CPacManPickups::Render(void) { EAXJMP(0x432F60); } -WRAPPER void CPacManPickups::DoCleanUpPacManStuff(void) { EAXJMP(0x433150); } -WRAPPER void CPacManPickups::StartPacManRace(int32) { EAXJMP(0x433340); } -WRAPPER void CPacManPickups::StartPacManRecord(void) { EAXJMP(0x433360); } -WRAPPER uint32 CPacManPickups::QueryPowerPillsEatenInRace(void) { EAXJMP(0x4333A0); } -WRAPPER void CPacManPickups::ResetPowerPillsEatenInRace(void) { EAXJMP(0x4333B0); } -WRAPPER void CPacManPickups::CleanUpPacManStuff(void) { EAXJMP(0x4333C0); } -WRAPPER void CPacManPickups::StartPacManScramble(CVector, float, int16) { EAXJMP(0x4333D0); } -WRAPPER uint32 CPacManPickups::QueryPowerPillsCarriedByPlayer(void) { EAXJMP(0x4333F0); } -WRAPPER void CPacManPickups::ResetPowerPillsCarriedByPlayer(void) { EAXJMP(0x433410); } - - void CPickup::RemoveKeepType() { @@ -111,7 +94,7 @@ CPickup::GiveUsAPickUpObject(int32 handle) object->bUsesCollision = false; object->bIsPickup = true; - object->field_172 = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0; + object->m_nBonusValue = m_eModelIndex == MI_PICKUP_BONUS ? m_nQuantity : 0; switch (m_eType) { @@ -289,13 +272,6 @@ CPickup::Update(CPlayerPed *player, CVehicle *vehicle, int playerId) Remove(); DMAudio.PlayFrontEndSound(SOUND_PICKUP_MONEY, 0); return true; - //case PICKUP_IN_SHOP_OUT_OF_STOCK: - //case PICKUP_MINE_INACTIVE: - //case PICKUP_MINE_ARMED: - //case PICKUP_NAUTICAL_MINE_INACTIVE: - //case PICKUP_NAUTICAL_MINE_ARMED: - //case PICKUP_FLOATINGPACKAGE: - //case PICKUP_FLOATINGPACKAGE_FLOATING: default: break; } @@ -530,14 +506,12 @@ CPickups::GenerateNewOne(CVector pos, uint32 modelIndex, uint8 type, uint32 quan } } - if (!bFreeFound) - { + if (!bFreeFound) { for (slot = 0; slot < NUMGENERALPICKUPS; slot++) { if (aPickUps[slot].m_eType == PICKUP_MONEY) break; } - if (slot >= NUMGENERALPICKUPS) - { + if (slot >= NUMGENERALPICKUPS) { for (slot = 0; slot < NUMGENERALPICKUPS; slot++) { if (aPickUps[slot].m_eType == PICKUP_ONCE_TIMEOUT) break; } @@ -671,9 +645,9 @@ void CPickups::DoPickUpEffects(CEntity *entity) { if (entity->GetModelIndex() == MI_PICKUP_KILLFRENZY) - entity->m_flagD80 = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame; + entity->bDoNotRender = CTheScripts::IsPlayerOnAMission() || CDarkel::FrenzyOnGoing() || !CGame::nastyGame; - if (!entity->m_flagD80) { + if (!entity->bDoNotRender) { float s = Sin((float)((CTimer::GetTimeInMilliseconds() + (uintptr)entity) & 0x7FF) * DEGTORAD(360.0f / 0x800)); float modifiedSin = 0.3f * (s + 1.0f); @@ -716,7 +690,7 @@ CPickups::DoPickUpEffects(CEntity *entity) size, 65.0f, CCoronas::TYPE_RING, CCoronas::FLARE_NONE, CCoronas::REFLECTION_OFF, CCoronas::LOSCHECK_OFF, CCoronas::STREAK_OFF, 0.0f); CObject *object = (CObject*)entity; - if (object->m_obj_flag2 || object->bOutOfStock || object->field_172) { + if (object->m_obj_flag2 || object->bOutOfStock || object->m_nBonusValue) { float dist = (TheCamera.GetPosition() - pos).Magnitude(); const float MAXDIST = 12.0f; @@ -734,7 +708,7 @@ CPickups::DoPickUpEffects(CEntity *entity) aMessages[NumMessages].m_color.blue = aWeaponBlues[colorId]; aMessages[NumMessages].m_color.alpha = (1.0f - dist / MAXDIST) * 128.0f; aMessages[NumMessages].m_bOutOfStock = object->bOutOfStock; - aMessages[NumMessages].m_quantity = object->field_172; + aMessages[NumMessages].m_quantity = object->m_nBonusValue; NumMessages++; } } @@ -1021,6 +995,418 @@ INITSAVEBUF VALIDATESAVEBUF(*size) } +void +CPacManPickup::Update() +{ + if (FindPlayerVehicle() == nil) return; + + CVehicle *veh = FindPlayerVehicle(); + + if (DistanceSqr2D(FindPlayerVehicle()->GetPosition(), m_vecPosn.x, m_vecPosn.y) < 100.0f && veh->IsSphereTouchingVehicle(m_vecPosn.x, m_vecPosn.y, m_vecPosn.z, 1.5f)) { + switch (m_eType) + { + case PACMAN_SCRAMBLE: + { + veh->m_nPacManPickupsCarried++; + veh->m_vecMoveSpeed *= 0.65f; + float massMult = (veh->m_fMass + 250.0f) / veh->m_fMass; + veh->m_fMass *= massMult; + veh->m_fTurnMass *= massMult; + veh->m_fForceMultiplier *= massMult; + FindPlayerPed()->m_pWanted->m_nChaos += 10; + FindPlayerPed()->m_pWanted->UpdateWantedLevel(); + DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PACKAGE, 0); + break; + } + case PACMAN_RACE: + CPacManPickups::PillsEatenInRace++; + DMAudio.PlayFrontEndSound(SOUND_PICKUP_PACMAN_PILL, 0); + break; + default: + break; + } + m_eType = PACMAN_NONE; + if (m_pObject != nil) { + CWorld::Remove(m_pObject); + delete m_pObject; + m_pObject = nil; + } + } +} + +int32 CollectGameState; +int16 ThingsToCollect; + +CPacManPickup CPacManPickups::aPMPickUps[NUMPACMANPICKUPS]; +CVector CPacManPickups::LastPickUpCoors; +int32 CPacManPickups::PillsEatenInRace; +bool CPacManPickups::bPMActive; + +void +CPacManPickups::Init() +{ + for (int i = 0; i < NUMPACMANPICKUPS; i++) + aPMPickUps[i].m_eType = PACMAN_NONE; + bPMActive = false; +} + +void +CPacManPickups::Update() +{ + if (FindPlayerVehicle()) { + float dist = Distance(FindPlayerCoors(), CVector(1072.0f, -948.0f, 14.5f)); + switch (CollectGameState) { + case 1: + if (dist < 10.0f) { + ThingsToCollect -= FindPlayerVehicle()->m_nPacManPickupsCarried; + FindPlayerVehicle()->m_nPacManPickupsCarried = 0; + FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier; + FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier; + FindPlayerVehicle()->m_fForceMultiplier = 1.0f; + } + if (ThingsToCollect <= 0) { + CollectGameState = 2; + ClearPMPickUps(); + } + break; + case 2: + if (dist > 11.0f) + CollectGameState = 0; + break; + case 20: + if (Distance(FindPlayerCoors(), LastPickUpCoors) > 30.0f) { + LastPickUpCoors = FindPlayerCoors(); + printf("%f, %f, %f,\n", LastPickUpCoors.x, LastPickUpCoors.y, LastPickUpCoors.z); + } + break; + default: + break; + } + } + if (bPMActive) { +#define PACMANPICKUPS_FRAME_SPAN (4) + for (uint32 i = (CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i < ((CTimer::GetFrameCounter() % PACMANPICKUPS_FRAME_SPAN) + 1) * (NUMPACMANPICKUPS / PACMANPICKUPS_FRAME_SPAN); i++) { + if (aPMPickUps[i].m_eType != PACMAN_NONE) + aPMPickUps[i].Update(); + } +#undef PACMANPICKUPS_FRAME_SPAN + } +} + +void +CPacManPickups::GeneratePMPickUps(CVector pos, float scrambleMult, int16 count, uint8 type) +{ + int i = 0; + while (count > 0) { + while (aPMPickUps[i].m_eType != PACMAN_NONE) + i++; + + bool bPickupCreated = false; + while (!bPickupCreated) { + CVector newPos = pos; + CColPoint colPoint; + CEntity *pRoad; + uint16 nRand = CGeneral::GetRandomNumber(); + newPos.x += ((nRand & 0xFF) - 128) * scrambleMult / 128.0f; + newPos.y += (((nRand >> 8) & 0xFF) - 128) * scrambleMult / 128.0f; + newPos.z = 1000.0f; + if (CWorld::ProcessVerticalLine(newPos, -1000.0f, colPoint, pRoad, true, false, false, false, true, false, nil) && pRoad->IsBuilding() && ((CBuilding*)pRoad)->GetIsATreadable()) { + newPos.z = 0.7f + colPoint.point.z; + aPMPickUps[i].m_eType = type; + aPMPickUps[i].m_vecPosn = newPos; + CObject *obj = new CObject(MI_BULLION, true); + if (obj != nil) { + obj->ObjectCreatedBy = MISSION_OBJECT; + obj->GetPosition() = aPMPickUps[i].m_vecPosn; + obj->SetOrientation(0.0f, 0.0f, -HALFPI); + obj->GetMatrix().UpdateRW(); + obj->UpdateRwFrame(); + + obj->bAffectedByGravity = false; + obj->bExplosionProof = true; + obj->bUsesCollision = false; + obj->bIsPickup = false; + CWorld::Add(obj); + } + aPMPickUps[i].m_pObject = obj; + bPickupCreated = true; + } + } + count--; + } + bPMActive = true; +} + +// diablo porn mission pickups +static const CVector aRacePoints1[] = { + CVector(913.62219f, -155.13692f, 4.9699469f), + CVector(913.92401f, -124.12943f, 4.9692569f), + CVector(913.27899f, -93.524231f, 7.4325991f), + CVector(912.60852f, -63.15905f, 7.4533591f), + CVector(934.22144f, -42.049122f, 7.4511471f), + CVector(958.88092f, -23.863735f, 7.4652338f), + CVector(978.50812f, -0.78458798f, 5.13515f), + CVector(1009.4175f, -2.1041219f, 2.4461579f), + CVector(1040.6313f, -2.0793829f, 2.293175f), + CVector(1070.7863f, -2.084095f, 2.2789791f), + CVector(1100.5773f, -8.468729f, 5.3248072f), + CVector(1119.9341f, -31.738031f, 7.1913071f), + CVector(1122.1664f, -62.762737f, 7.4703908f), + CVector(1122.814f, -93.650566f, 8.5577497f), + CVector(1125.8253f, -124.26616f, 9.9803305f), + CVector(1153.8727f, -135.47169f, 14.150617f), + CVector(1184.0831f, -135.82845f, 14.973998f), + CVector(1192.0432f, -164.57816f, 19.18627f), + CVector(1192.7761f, -194.28871f, 24.799675f), + CVector(1215.1527f, -215.0714f, 25.74975f), + CVector(1245.79f, -215.39304f, 28.70726f), + CVector(1276.2477f, -216.39485f, 33.71236f), + CVector(1306.5535f, -216.71007f, 39.711472f), + CVector(1335.0244f, -224.59329f, 46.474979f), + CVector(1355.4879f, -246.27664f, 49.934841f), + CVector(1362.6003f, -276.47064f, 49.96265f), + CVector(1363.027f, -307.30847f, 49.969173f), + CVector(1365.343f, -338.08609f, 49.967789f), + CVector(1367.5957f, -368.01105f, 50.092304f), + CVector(1368.2749f, -398.38049f, 50.061268f), + CVector(1366.9034f, -429.98483f, 50.057545f), + CVector(1356.8534f, -459.09259f, 50.035545f), + CVector(1335.5819f, -481.13544f, 47.217903f), + CVector(1306.7552f, -491.07443f, 40.202629f), + CVector(1275.5978f, -491.33194f, 33.969223f), + CVector(1244.702f, -491.46451f, 29.111021f), + CVector(1213.2222f, -491.8754f, 25.771168f), + CVector(1182.7729f, -492.19995f, 24.749964f), + CVector(1152.6874f, -491.42221f, 21.70038f), + CVector(1121.5352f, -491.94604f, 20.075182f), + CVector(1090.7056f, -492.63751f, 17.585758f), + CVector(1059.6008f, -491.65762f, 14.848632f), + CVector(1029.113f, -489.66031f, 14.918498f), + CVector(998.20679f, -486.78107f, 14.945688f), + CVector(968.00555f, -484.91266f, 15.001229f), + CVector(937.74939f, -492.09015f, 14.958629f), + CVector(927.17352f, -520.97736f, 14.972308f), + CVector(929.29749f, -552.08643f, 14.978855f), + CVector(950.69525f, -574.47778f, 14.972788f), + CVector(974.02826f, -593.56024f, 14.966445f), + CVector(989.04779f, -620.12854f, 14.951016f), + CVector(1014.1639f, -637.3905f, 14.966736f), + CVector(1017.5961f, -667.3736f, 14.956415f), + CVector(1041.9735f, -685.94391f, 15.003841f), + CVector(1043.3064f, -716.11298f, 14.974236f), + CVector(1043.5337f, -746.63855f, 14.96919f), + CVector(1044.142f, -776.93823f, 14.965424f), + CVector(1044.2657f, -807.29395f, 14.97171f), + CVector(1017.0797f, -820.1076f, 14.975431f), + CVector(986.23865f, -820.37103f, 14.972883f), + CVector(956.10065f, -820.23291f, 14.981133f), + CVector(925.86914f, -820.19049f, 14.976553f), + CVector(897.69702f, -831.08734f, 14.962709f), + CVector(868.06586f, -835.99237f, 14.970685f), + CVector(836.93054f, -836.84387f, 14.965049f), + CVector(811.63586f, -853.7915f, 15.067576f), + CVector(811.46344f, -884.27368f, 12.247812f), + CVector(811.60651f, -914.70959f, 9.2393751f), + CVector(811.10425f, -945.16272f, 5.817255f), + CVector(816.54584f, -975.64587f, 4.998558f), + CVector(828.2951f, -1003.3685f, 5.0471172f), + CVector(852.28839f, -1021.5963f, 4.9371028f), + CVector(882.50067f, -1025.4459f, 5.14077f), + CVector(912.84821f, -1026.7874f, 8.3415451f), + CVector(943.68274f, -1026.6914f, 11.341879f), + CVector(974.4129f, -1027.3682f, 14.410345f), + CVector(1004.1079f, -1036.0778f, 14.92961f), + CVector(1030.1144f, -1051.1224f, 14.850387f), + CVector(1058.7585f, -1060.342f, 14.821624f), + CVector(1087.7797f, -1068.3263f, 14.800561f), + CVector(1099.8807f, -1095.656f, 11.877907f), + CVector(1130.0005f, -1101.994f, 11.853914f), + CVector(1160.3809f, -1101.6355f, 11.854824f), + CVector(1191.8524f, -1102.1577f, 11.853843f), + CVector(1223.3307f, -1102.7448f, 11.852233f), + CVector(1253.564f, -1098.1045f, 11.853944f), + CVector(1262.0203f, -1069.1785f, 14.8147f), + CVector(1290.9998f, -1059.1882f, 14.816016f), + CVector(1316.246f, -1041.0635f, 14.81109f), + CVector(1331.7539f, -1013.835f, 14.81207f), + CVector(1334.0579f, -983.55402f, 14.827253f), + CVector(1323.2429f, -954.23083f, 14.954678f), + CVector(1302.7495f, -932.21216f, 14.962917f), + CVector(1317.418f, -905.89325f, 14.967506f), + CVector(1337.9503f, -883.5025f, 14.969675f), + CVector(1352.6929f, -855.96954f, 14.967854f), + CVector(1357.2388f, -826.26971f, 14.97295f), + CVector(1384.8668f, -812.47693f, 12.907736f), + CVector(1410.8983f, -795.39056f, 12.052228f), + CVector(1433.901f, -775.55811f, 11.96265f), + CVector(1443.8615f, -746.92511f, 11.976114f), + CVector(1457.7015f, -720.00903f, 11.971177f), + CVector(1481.5685f, -701.30237f, 11.977908f), + CVector(1511.4004f, -696.83295f, 11.972709f), + CVector(1542.1796f, -695.61676f, 11.970441f), + CVector(1570.3301f, -684.6239f, 11.969202f), + CVector(0.0f, 0.0f, 0.0f), +}; + +void +CPacManPickups::GeneratePMPickUpsForRace(int32 race) +{ + const CVector *pPos = nil; + int i = 0; + + if (race == 0) pPos = aRacePoints1; // there's only one available + assert(pPos != nil); + + while (!pPos->IsZero()) { + while (aPMPickUps[i].m_eType != PACMAN_NONE) + i++; + + aPMPickUps[i].m_eType = PACMAN_RACE; + aPMPickUps[i].m_vecPosn = *(pPos++); + if (race == 0) { + CObject* obj = new CObject(MI_DONKEYMAG, true); + if (obj != nil) { + obj->ObjectCreatedBy = MISSION_OBJECT; + + obj->GetPosition() = aPMPickUps[i].m_vecPosn; + obj->SetOrientation(0.0f, 0.0f, -HALFPI); + obj->GetMatrix().UpdateRW(); + obj->UpdateRwFrame(); + + obj->bAffectedByGravity = false; + obj->bExplosionProof = true; + obj->bUsesCollision = false; + obj->bIsPickup = false; + + CWorld::Add(obj); + } + aPMPickUps[i].m_pObject = obj; + } else + aPMPickUps[i].m_pObject = nil; + } + bPMActive = true; +} + +void +CPacManPickups::GenerateOnePMPickUp(CVector pos) +{ + bPMActive = true; + aPMPickUps[0].m_eType = PACMAN_RACE; + aPMPickUps[0].m_vecPosn = pos; +} + +void +CPacManPickups::Render() +{ + if (!bPMActive) return; + + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, FALSE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDONE); + RwRenderStateSet(rwRENDERSTATETEXTURERASTER, RwTextureGetRaster(gpCoronaTexture[6])); + + RwV3d pos; + float w, h; + + for (int i = 0; i < NUMPACMANPICKUPS; i++) { + switch (aPMPickUps[i].m_eType) + { + case PACMAN_SCRAMBLE: + case PACMAN_RACE: + if (CSprite::CalcScreenCoors(aPMPickUps[i].m_vecPosn, &pos, &w, &h, true) && pos.z < 100.0f) { + if (aPMPickUps[i].m_pObject != nil) { + aPMPickUps[i].m_pObject->GetMatrix().SetRotateZOnly((CTimer::GetTimeInMilliseconds() % 1024) * TWOPI / 1024.0f); + aPMPickUps[i].m_pObject->GetMatrix().UpdateRW(); + aPMPickUps[i].m_pObject->UpdateRwFrame(); + } + float fsin = Sin((CTimer::GetTimeInMilliseconds() % 1024) * 6.28f / 1024.0f); // yes, it is 6.28f when it was TWOPI just now... + CSprite::RenderOneXLUSprite(pos.x, pos.y, pos.z, 0.8f * w * fsin, 0.8f * h, 100, 50, 5, 255, 1.0f / pos.z, 255); + } + break; + default: + break; + } + } + + RwRenderStateSet(rwRENDERSTATESRCBLEND, (void*)rwBLENDSRCALPHA); + RwRenderStateSet(rwRENDERSTATEDESTBLEND, (void*)rwBLENDINVSRCALPHA); + RwRenderStateSet(rwRENDERSTATEZWRITEENABLE, (void*)TRUE); + RwRenderStateSet(rwRENDERSTATEVERTEXALPHAENABLE, FALSE); +} + +void +CPacManPickups::ClearPMPickUps() +{ + bPMActive = false; + + for (int i = 0; i < NUMPACMANPICKUPS; i++) { + if (aPMPickUps[i].m_pObject != nil) { + CWorld::Remove(aPMPickUps[i].m_pObject); + delete aPMPickUps[i].m_pObject; + aPMPickUps[i].m_pObject = nil; + } + aPMPickUps[i].m_eType = PACMAN_NONE; + } +} + +void +CPacManPickups::StartPacManRace(int32 race) +{ + GeneratePMPickUpsForRace(race); + PillsEatenInRace = 0; +} + +void +CPacManPickups::StartPacManRecord() +{ + CollectGameState = 20; + LastPickUpCoors = FindPlayerCoors(); +} + +uint32 +CPacManPickups::QueryPowerPillsEatenInRace() +{ + return PillsEatenInRace; +} + +void +CPacManPickups::ResetPowerPillsEatenInRace() +{ + PillsEatenInRace = 0; +} + +void +CPacManPickups::CleanUpPacManStuff() +{ + ClearPMPickUps(); +} + +void +CPacManPickups::StartPacManScramble(CVector pos, float scrambleMult, int16 count) +{ + GeneratePMPickUps(pos, scrambleMult, count, PACMAN_SCRAMBLE); +} + +uint32 +CPacManPickups::QueryPowerPillsCarriedByPlayer() +{ + if (FindPlayerVehicle()) + return FindPlayerVehicle()->m_nPacManPickupsCarried; + return 0; +} + +void +CPacManPickups::ResetPowerPillsCarriedByPlayer() +{ + if (FindPlayerVehicle() != nil) { + FindPlayerVehicle()->m_nPacManPickupsCarried = 0; + FindPlayerVehicle()->m_fMass /= FindPlayerVehicle()->m_fForceMultiplier; + FindPlayerVehicle()->m_fTurnMass /= FindPlayerVehicle()->m_fForceMultiplier; + FindPlayerVehicle()->m_fForceMultiplier = 1.0f; + } +} + STARTPATCHES InjectHook(0x430220, CPickups::Init, PATCH_JUMP); InjectHook(0x4303D0, CPickups::Update, PATCH_JUMP); @@ -1046,4 +1432,21 @@ STARTPATCHES InjectHook(0x433E40, CPickups::Save, PATCH_JUMP); InjectHook(0x433BA0, &CPickup::GiveUsAPickUpObject, PATCH_JUMP); InjectHook(0x430860, &CPickup::Update, PATCH_JUMP); + InjectHook(0x4331B0, &CPacManPickup::Update, PATCH_JUMP); + InjectHook(0x432760, CPacManPickups::Init, PATCH_JUMP); + InjectHook(0x432800, CPacManPickups::Update, PATCH_JUMP); + InjectHook(0x432AE0, CPacManPickups::GeneratePMPickUps, PATCH_JUMP); + InjectHook(0x432D50, CPacManPickups::GeneratePMPickUpsForRace, PATCH_JUMP); + InjectHook(0x432F20, CPacManPickups::GenerateOnePMPickUp, PATCH_JUMP); + InjectHook(0x432F60, CPacManPickups::Render, PATCH_JUMP); + InjectHook(0x433150, CPacManPickups::ClearPMPickUps, PATCH_JUMP); + InjectHook(0x433340, CPacManPickups::StartPacManRace, PATCH_JUMP); + InjectHook(0x433360, CPacManPickups::StartPacManRecord, PATCH_JUMP); + InjectHook(0x4333A0, CPacManPickups::QueryPowerPillsEatenInRace, PATCH_JUMP); + InjectHook(0x4333B0, CPacManPickups::ResetPowerPillsEatenInRace, PATCH_JUMP); + InjectHook(0x4333C0, CPacManPickups::CleanUpPacManStuff, PATCH_JUMP); + InjectHook(0x4333D0, CPacManPickups::StartPacManScramble, PATCH_JUMP); + InjectHook(0x4333F0, CPacManPickups::QueryPowerPillsCarriedByPlayer, PATCH_JUMP); + InjectHook(0x433410, CPacManPickups::ResetPowerPillsCarriedByPlayer, PATCH_JUMP); + ENDPATCHES diff --git a/src/control/Pickups.h b/src/control/Pickups.h index 3e075b24..b5b4f396 100644 --- a/src/control/Pickups.h +++ b/src/control/Pickups.h @@ -102,8 +102,31 @@ extern uint16 AmmoForWeapon[20]; extern uint16 AmmoForWeapon_OnStreet[20]; extern uint16 CostOfWeapon[20]; +enum ePacmanPickupType +{ + PACMAN_NONE, + PACMAN_SCRAMBLE, + PACMAN_RACE, +}; + +class CPacManPickup +{ +public: + CVector m_vecPosn; + CObject *m_pObject; + uint8 m_eType; + + void Update(); +}; + class CPacManPickups { + friend CPacManPickup; + + static CPacManPickup aPMPickUps[NUMPACMANPICKUPS]; + static CVector LastPickUpCoors; + static int PillsEatenInRace; + static bool bPMActive; public: static void Init(void); static void Update(void); @@ -111,11 +134,11 @@ public: static void GeneratePMPickUpsForRace(int32); static void GenerateOnePMPickUp(CVector); static void Render(void); - static void DoCleanUpPacManStuff(void); static void StartPacManRace(int32); static void StartPacManRecord(void); static uint32 QueryPowerPillsEatenInRace(void); static void ResetPowerPillsEatenInRace(void); + static void ClearPMPickUps(void); static void CleanUpPacManStuff(void); static void StartPacManScramble(CVector, float, int16); static uint32 QueryPowerPillsCarriedByPlayer(void); diff --git a/src/control/Record.cpp b/src/control/Record.cpp index 7c330311..ca4128e3 100644 --- a/src/control/Record.cpp +++ b/src/control/Record.cpp @@ -2,18 +2,522 @@ #include "patcher.h" #include "Record.h" +#include "FileMgr.h" +#include "Pad.h" +#include "Pools.h" +#include "Streaming.h" +#include "Timer.h" +#include "VehicleModelInfo.h" +#include "World.h" + uint16 &CRecordDataForGame::RecordingState = *(uint16*)0x95CC24; +uint8*& CRecordDataForGame::pDataBuffer = *(uint8**)0x8F1B70; +uint8*& CRecordDataForGame::pDataBufferPointer = *(uint8**)0x8F1AB0; +int& CRecordDataForGame::FId = *(int*)0x885BA4; +tGameBuffer& CRecordDataForGame::pDataBufferForFrame = *(tGameBuffer*)0x72CED0; + +#define MEMORY_FOR_GAME_RECORD (150000) + +void CRecordDataForGame::Init(void) +{ + RecordingState = STATE_NONE; + delete[] pDataBuffer; + pDataBufferPointer = nil; + pDataBuffer = nil; +#ifndef GTA_PS2 // this stuff is not present on PS2 + FId = CFileMgr::OpenFile("playback.dat", "r"); + if (FId <= 0) { + if ((FId = CFileMgr::OpenFile("record.dat", "r")) <= 0) + RecordingState = STATE_NONE; + else { + CFileMgr::CloseFile(FId); + FId = CFileMgr::OpenFileForWriting("record.dat"); + RecordingState = STATE_RECORD; + } + } + else { + RecordingState = STATE_PLAYBACK; + } + if (RecordingState == STATE_PLAYBACK) { + pDataBufferPointer = new uint8[MEMORY_FOR_GAME_RECORD]; + pDataBuffer = pDataBufferPointer; + pDataBuffer[CFileMgr::Read(FId, (char*)pDataBufferPointer, MEMORY_FOR_GAME_RECORD) + 8] = (uint8)-1; + CFileMgr::CloseFile(FId); + } +#else + RecordingState = STATE_NONE; // second time to make sure +#endif +} + +void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void) +{ + switch (RecordingState) { + case STATE_RECORD: + { + pDataBufferForFrame.m_fTimeStep = CTimer::GetTimeStep(); + pDataBufferForFrame.m_nTimeInMilliseconds = CTimer::GetTimeInMilliseconds(); + pDataBufferForFrame.m_nSizeOfPads[0] = 0; + pDataBufferForFrame.m_nSizeOfPads[1] = 0; + pDataBufferForFrame.m_nChecksum = CalcGameChecksum(); + uint8* pController1 = PackCurrentPadValues(pDataBufferForFrame.m_ControllerBuffer, &CPad::GetPad(0)->OldState, &CPad::GetPad(0)->NewState); + pDataBufferForFrame.m_nSizeOfPads[0] = (pController1 - pDataBufferForFrame.m_ControllerBuffer) / 2; + uint8* pController2 = PackCurrentPadValues(pController1, &CPad::GetPad(1)->OldState, &CPad::GetPad(1)->NewState); + pDataBufferForFrame.m_nSizeOfPads[1] = (pController2 - pController1) / 2; + uint8* pEndPtr = pController2; + if ((pDataBufferForFrame.m_nSizeOfPads[0] + pDataBufferForFrame.m_nSizeOfPads[1]) & 1) + pEndPtr += 2; + CFileMgr::Write(FId, (char*)&pDataBufferForFrame, pEndPtr - (uint8*)&pDataBufferForFrame); + break; + } + case STATE_PLAYBACK: + if (pDataBufferPointer[8] == (uint8)-1) + CPad::GetPad(0)->NewState.Clear(); + else { + tGameBuffer* pData = (tGameBuffer*)pDataBufferPointer; + CTimer::SetTimeInMilliseconds(pData->m_nTimeInMilliseconds); + CTimer::SetTimeStep(pData->m_fTimeStep); + uint8 size1 = pData->m_nSizeOfPads[0]; + uint8 size2 = pData->m_nSizeOfPads[1]; + pDataBufferPointer = (uint8*)&pData->m_ControllerBuffer; + pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size1, &CPad::GetPad(0)->NewState); + pDataBufferPointer = UnPackCurrentPadValues(pDataBufferPointer, size2, &CPad::GetPad(1)->NewState); + if ((size1 + size2) & 1) + pDataBufferPointer += 2; + if (pData->m_nChecksum != CalcGameChecksum()) + printf("Playback out of sync\n"); + } + } +} + +#define PROCESS_BUTTON_STATE_STORE(buf, os, ns, field, id) \ + do { \ + if (os->field != ns->field){ \ + *buf++ = id; \ + *buf++ = ns->field; \ + } \ + } while (0); + +uint8* CRecordDataForGame::PackCurrentPadValues(uint8* buf, CControllerState* os, CControllerState* ns) +{ + PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickX, 0); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftStickY, 1); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickX, 2); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightStickY, 3); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder1, 4); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShoulder2, 5); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder1, 6); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShoulder2, 7); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadUp, 8); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadDown, 9); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadLeft, 10); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, DPadRight, 11); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, Start, 12); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, Select, 13); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, Square, 14); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, Triangle, 15); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, Cross, 16); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, Circle, 17); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, LeftShock, 18); + PROCESS_BUTTON_STATE_STORE(buf, os, ns, RightShock, 19); + return buf; +} +#undef PROCESS_BUTTON_STATE_STORE + +#define PROCESS_BUTTON_STATE_RESTORE(buf, state, field, id) case id: state->field = *buf++; break; + +uint8* CRecordDataForGame::UnPackCurrentPadValues(uint8* buf, uint8 total, CControllerState* state) +{ + for (uint8 i = 0; i < total; i++) { + switch (*buf++) { + PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickX, 0); + PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftStickY, 1); + PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickX, 2); + PROCESS_BUTTON_STATE_RESTORE(buf, state, RightStickY, 3); + PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder1, 4); + PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShoulder2, 5); + PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder1, 6); + PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShoulder2, 7); + PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadUp, 8); + PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadDown, 9); + PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadLeft, 10); + PROCESS_BUTTON_STATE_RESTORE(buf, state, DPadRight, 11); + PROCESS_BUTTON_STATE_RESTORE(buf, state, Start, 12); + PROCESS_BUTTON_STATE_RESTORE(buf, state, Select, 13); + PROCESS_BUTTON_STATE_RESTORE(buf, state, Square, 14); + PROCESS_BUTTON_STATE_RESTORE(buf, state, Triangle, 15); + PROCESS_BUTTON_STATE_RESTORE(buf, state, Cross, 16); + PROCESS_BUTTON_STATE_RESTORE(buf, state, Circle, 17); + PROCESS_BUTTON_STATE_RESTORE(buf, state, LeftShock, 18); + PROCESS_BUTTON_STATE_RESTORE(buf, state, RightShock, 19); + } + } + return buf; +} + +#undef PROCESS_BUTTON_STATE_RESTORE + +uint16 CRecordDataForGame::CalcGameChecksum(void) +{ + uint32 checksum = 0; + int i = CPools::GetPedPool()->GetSize(); + while (i--) { + CPed* pPed = CPools::GetPedPool()->GetSlot(i); + if (!pPed) + continue; + checksum ^= pPed->GetModelIndex() ^ *(uint32*)&pPed->GetPosition().z ^ *(uint32*)&pPed->GetPosition().y ^ *(uint32*)&pPed->GetPosition().x; + } + i = CPools::GetVehiclePool()->GetSize(); + while (i--) { + CVehicle* pVehicle = CPools::GetVehiclePool()->GetSlot(i); + if (!pVehicle) + continue; + checksum ^= pVehicle->GetModelIndex() ^ *(uint32*)&pVehicle->GetPosition().z ^ *(uint32*)&pVehicle->GetPosition().y ^ *(uint32*)&pVehicle->GetPosition().x; + } + return checksum ^ checksum >> 16; +} + +uint8& CRecordDataForChase::Status = *(uint8*)0x95CDCE; +int& CRecordDataForChase::PositionChanges = *(int*)0x8F59C8; +uint8& CRecordDataForChase::CurrentCar = *(uint8*)0x95CDC9; +CAutomobile* (&CRecordDataForChase::pChaseCars)[NUM_CHASE_CARS] = *(CAutomobile * (*)[NUM_CHASE_CARS])*(uintptr*)0x6F46A8; +uint32& CRecordDataForChase::AnimStartTime = *(uint32*)0x8F1AEC; +float& CRecordDataForChase::AnimTime = *(float*)0x880F88; +CCarStateEachFrame* (&CRecordDataForChase::pBaseMemForCar)[NUM_CHASE_CARS] = *(CCarStateEachFrame * (*)[NUM_CHASE_CARS])*(uintptr*)0x70EA18; +float& CRecordDataForChase::TimeMultiplier = *(float*)0x8E2A94; +int& CRecordDataForChase::FId2 = *(int*)0x8E2C18; + +#define CHASE_SCENE_LENGTH_IN_SECONDS (80) +#define CHASE_SCENE_FRAMES_PER_SECOND (15) // skipping every second frame +#define CHASE_SCENE_FRAMES_IN_RECORDING (CHASE_SCENE_LENGTH_IN_SECONDS * CHASE_SCENE_FRAMES_PER_SECOND) +#define CHASE_SCENE_LENGTH_IN_FRAMES (CHASE_SCENE_FRAMES_IN_RECORDING * 2) + +void CRecordDataForChase::Init(void) +{ + Status = STATE_NONE; + PositionChanges = 0; + CurrentCar = 0; + for (int i = 0; i < NUM_CHASE_CARS; i++) + pChaseCars[i] = nil; + AnimStartTime = 0; +} + +void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void) +{ + switch (Status) { + case STATE_NONE: + return; + case STATE_RECORD: + { + if ((CTimer::GetFrameCounter() & 1) == 0) + StoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2]); + if (CTimer::GetFrameCounter() < CHASE_SCENE_LENGTH_IN_FRAMES * 2) + return; + CFileMgr::SetDir("data\\paths"); + sprintf(gString, "chase%d.dat", CurrentCar); + int fid = CFileMgr::OpenFileForWriting(gString); + uint32 fs = CHASE_SCENE_LENGTH_IN_FRAMES * sizeof(CCarStateEachFrame); + printf("FileSize:%d\n", fs); + CFileMgr::Write(fid, (char*)pBaseMemForCar[CurrentCar], fs); + CFileMgr::CloseFile(fid); + CFileMgr::SetDir(""); + sprintf(gString, "car%d.max", CurrentCar); + int fid2 = CFileMgr::OpenFileForWriting(gString); + for (int i = 0; i < CHASE_SCENE_FRAMES_IN_RECORDING; i++) { + // WTF? Was it ever used? +#ifdef FIX_BUGS + CCarStateEachFrame* pState = pBaseMemForCar[CurrentCar]; +#else + CCarStateEachFrame* pState = (CCarStateEachFrame*)pChaseCars[CurrentCar]; +#endif + CVector right = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX; + CVector forward = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX; + CVector up = CrossProduct(right, forward); + sprintf(gString, "%f %f %f\n", pState->pos.x, pState->pos.y, pState->pos.z); + CFileMgr::Write(fid2, gString, strlen(gString) - 1); + sprintf(gString, "%f %f %f\n", right.x, right.y, right.z); + CFileMgr::Write(fid2, gString, strlen(gString) - 1); + sprintf(gString, "%f %f %f\n", forward.x, forward.y, forward.z); + CFileMgr::Write(fid2, gString, strlen(gString) - 1); + sprintf(gString, "%f %f %f\n", up.x, up.y, up.z); + CFileMgr::Write(fid2, gString, strlen(gString) - 1); + } + CFileMgr::CloseFile(fid2); + } + case STATE_PLAYBACK: + case STATE_PLAYBACK_BEFORE_RECORDING: + case STATE_PLAYBACK_INIT: + break; + } +} + +struct tCoors { + CVector pos; + float angle; +}; + +// I guess developer was filling this with actual data before running the game +tCoors NewCoorsForRecordedCars[7]; + +void CRecordDataForChase::SaveOrRetrieveCarPositions(void) +{ + switch (Status) { + case STATE_NONE: + return; + case STATE_RECORD: + case STATE_PLAYBACK_BEFORE_RECORDING: + for (int i = 0; i < NUM_CHASE_CARS; i++) { + if (i != CurrentCar && CTimer::GetFrameCounter()) { + RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CTimer::GetFrameCounter() / 2], false); + pChaseCars[i]->GetMatrix().UpdateRW(); + pChaseCars[i]->UpdateRwFrame(); + } + } + if (Status == STATE_PLAYBACK_BEFORE_RECORDING && CTimer::GetFrameCounter()) { + RestoreInfoForCar(pChaseCars[CurrentCar], &pBaseMemForCar[CurrentCar][CTimer::GetFrameCounter() / 2], false); + pChaseCars[CurrentCar]->GetMatrix().UpdateRW(); + pChaseCars[CurrentCar]->UpdateRwFrame(); + } + if (CPad::GetPad(0)->GetLeftShockJustDown() && CPad::GetPad(0)->GetRightShockJustDown()) { + if (!CPad::GetPad(0)->GetRightShockJustDown()) { + pChaseCars[CurrentCar]->GetPosition() = NewCoorsForRecordedCars[PositionChanges].pos; + pChaseCars[CurrentCar]->SetMoveSpeed(0.0f, 0.0f, 0.0f); + pChaseCars[CurrentCar]->GetMatrix().SetRotateZOnly(DEGTORAD(NewCoorsForRecordedCars[PositionChanges].angle)); + ++PositionChanges; + } + if (Status == STATE_PLAYBACK_BEFORE_RECORDING) { + Status = STATE_RECORD; + pChaseCars[CurrentCar]->m_status = STATUS_PLAYER; + } + } + break; + case STATE_PLAYBACK_INIT: + Status = STATE_PLAYBACK; + break; + case STATE_PLAYBACK: + { + TimeMultiplier += CTimer::GetTimeStepNonClippedInSeconds(); + float EndOfFrameTime = CHASE_SCENE_FRAMES_PER_SECOND * min(CHASE_SCENE_LENGTH_IN_SECONDS, TimeMultiplier); + for (int i = 0; i < NUM_CHASE_CARS; i++) { + if (!pBaseMemForCar[i]) + continue; + if (!pChaseCars[i]) + continue; + if (EndOfFrameTime < CHASE_SCENE_FRAMES_IN_RECORDING - 1) { + int FlooredEOFTime = EndOfFrameTime; + RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][FlooredEOFTime], false); + CMatrix tmp; + float dp = EndOfFrameTime - FlooredEOFTime; + RestoreInfoForMatrix(tmp, &pBaseMemForCar[i][FlooredEOFTime + 1]); + pChaseCars[i]->GetRight() += (tmp.GetRight() - pChaseCars[i]->GetRight()) * dp; + pChaseCars[i]->GetForward() += (tmp.GetForward() - pChaseCars[i]->GetForward()) * dp; + pChaseCars[i]->GetUp() += (tmp.GetUp() - pChaseCars[i]->GetUp()) * dp; + pChaseCars[i]->GetPosition() += (tmp.GetPosition() - pChaseCars[i]->GetPosition()) * dp; + } + else{ + RestoreInfoForCar(pChaseCars[i], &pBaseMemForCar[i][CHASE_SCENE_FRAMES_IN_RECORDING - 1], true); + if (i == 0) + pChaseCars[i]->GetPosition().z += 0.2f; + } + pChaseCars[i]->GetMatrix().UpdateRW(); + pChaseCars[i]->UpdateRwFrame(); + pChaseCars[i]->RemoveAndAdd(); + } + break; + } + } +} + +void CRecordDataForChase::StoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState) +{ + pState->rightX = INT8_MAX * pCar->GetRight().x; + pState->rightY = INT8_MAX * pCar->GetRight().y; + pState->rightZ = INT8_MAX * pCar->GetRight().z; + pState->forwardX = INT8_MAX * pCar->GetForward().x; + pState->forwardY = INT8_MAX * pCar->GetForward().y; + pState->forwardZ = INT8_MAX * pCar->GetForward().z; + pState->pos = pCar->GetPosition(); + pState->velX = 0.5f * INT16_MAX * pCar->GetMoveSpeed().x; + pState->velY = 0.5f * INT16_MAX * pCar->GetMoveSpeed().y; + pState->velZ = 0.5f * INT16_MAX * pCar->GetMoveSpeed().z; + pState->wheel = 20 * pCar->m_fSteerAngle; + pState->gas = 100 * pCar->m_fGasPedal; + pState->brake = 100 * pCar->m_fBrakePedal; + pState->handbrake = pCar->bIsHandbrakeOn; +} + +void CRecordDataForChase::RestoreInfoForMatrix(CMatrix& matrix, CCarStateEachFrame* pState) +{ + matrix.GetRight() = CVector(pState->rightX, pState->rightY, pState->rightZ) / INT8_MAX; + matrix.GetForward() = CVector(pState->forwardX, pState->forwardY, pState->forwardZ) / INT8_MAX; + matrix.GetUp() = CrossProduct(matrix.GetRight(), matrix.GetForward()); + matrix.GetPosition() = pState->pos; +} + +void CRecordDataForChase::RestoreInfoForCar(CAutomobile* pCar, CCarStateEachFrame* pState, bool stop) +{ + CVector oldPos = pCar->GetPosition(); + RestoreInfoForMatrix(pCar->GetMatrix(), pState); + pCar->SetMoveSpeed(CVector(pState->velX, pState->velY, pState->velZ) / INT16_MAX / 0.5f); + pCar->SetTurnSpeed(0.0f, 0.0f, 0.0f); + pCar->m_fSteerAngle = pState->wheel / 20.0f; + pCar->m_fGasPedal = pState->gas / 100.0f; + pCar->m_fBrakePedal = pState->brake / 100.0f; + pCar->bIsHandbrakeOn = pState->handbrake; + if ((oldPos - pCar->GetPosition()).Magnitude() > 15.0f) { + if (pCar == pChaseCars[14]) { + pCar->m_currentColour1 = 58; + pCar->m_currentColour2 = 1; + } + else + pCar->GetModelInfo()->ChooseVehicleColour(pCar->m_currentColour1, pCar->m_currentColour2); + } + pCar->m_fHealth = min(pCar->m_fHealth, 500.0f); + if (stop) { + pCar->m_fGasPedal = 0.0f; + pCar->m_fBrakePedal = 0.0f; + pCar->SetMoveSpeed(0.0f, 0.0f, 0.0f); + pCar->bIsHandbrakeOn = false; + } +} + +void CRecordDataForChase::ProcessControlCars(void) +{ + if (Status != STATE_PLAYBACK) + return; + for (int i = 0; i < NUM_CHASE_CARS; i++) { + if (pChaseCars[i]) + pChaseCars[i]->ProcessControl(); + } +} + +#if (defined(GTA_PS2) || defined(FIX_BUGS)) +bool CRecordDataForChase::ShouldThisPadBeLeftAlone(uint8 pad) +{ + // may be wrong + if (Status == STATE_NONE || Status == STATE_PLAYBACK) + return false; + return pad != 0; +} +#endif + +void CRecordDataForChase::GiveUsACar(int32 mi, CVector pos, float angle, CAutomobile** ppCar, uint8 colour1, uint8 colour2) +{ + CStreaming::RequestModel(mi, STREAMFLAGS_DEPENDENCY); + CStreaming::LoadAllRequestedModels(false); + if (!CStreaming::HasModelLoaded(mi)) + return; + CAutomobile* pCar = new CAutomobile(mi, MISSION_VEHICLE); + pCar->GetPosition() = pos; + pCar->m_status = STATUS_PLAYER_PLAYBACKFROMBUFFER; + pCar->GetMatrix().SetRotateZOnly(DEGTORAD(angle)); + pCar->pDriver = nil; + pCar->m_currentColour1 = colour1; + pCar->m_currentColour2 = colour2; + CWorld::Add(pCar); + *ppCar = pCar; +} + +void RemoveUnusedCollision(void) +{ + static const char* dontDeleteArray[] = { + "rd_SrRoad2A50", "rd_SrRoad2A20", "rd_CrossRda1w22", "rd_CrossRda1rw22", + "road_broadway02", "road_broadway01", "com_21way5", "com_21way50", + "cm1waycrosscom", "com_21way20", "com_21way10", "road_broadway04", + "com_rvroads52", "com_roadsrv", "com_roadkb23", "com_roadkb22" + }; + for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++) + CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_NONE; + CModelInfo::RemoveColModelsFromOtherLevels(LEVEL_NONE); + for (int i = 0; i < ARRAY_SIZE(dontDeleteArray); i++) + CModelInfo::GetModelInfo(dontDeleteArray[i], nil)->GetColModel()->level = LEVEL_COMMERCIAL; +} + +void CRecordDataForChase::StartChaseScene(float startTime) +{ + char filename[28]; + SetUpCarsForChaseScene(); + Status = STATE_PLAYBACK; + AnimTime = startTime; + AnimStartTime = CTimer::GetTimeInMilliseconds(); + RemoveUnusedCollision(); + CStreaming::RemoveIslandsNotUsed(LEVEL_SUBURBAN); + CGame::TidyUpMemory(true, true); + CStreaming::ImGonnaUseStreamingMemory(); + CFileMgr::SetDir("data\\paths"); + for (int i = 0; i < NUM_CHASE_CARS; i++) { + if (!pChaseCars[i]) { + pBaseMemForCar[i] = nil; + continue; + } + sprintf(filename, "chase%d.dat", i); + FId2 = CFileMgr::OpenFile(filename, "rb"); + if (FId2 <= 0) { + pBaseMemForCar[i] = nil; + continue; + } + pBaseMemForCar[i] = new CCarStateEachFrame[CHASE_SCENE_FRAMES_IN_RECORDING]; + for (int j = 0; j < CHASE_SCENE_FRAMES_IN_RECORDING; j++) { + CFileMgr::Read(FId2, (char*)&pBaseMemForCar[i][j], sizeof(CCarStateEachFrame)); + CFileMgr::Seek(FId2, sizeof(CCarStateEachFrame), 1); + } + CFileMgr::CloseFile(FId2); + } + CFileMgr::SetDir(""); + CStreaming::IHaveUsedStreamingMemory(); + TimeMultiplier = 0.0f; +} + +void CRecordDataForChase::CleanUpChaseScene(void) +{ + if (Status != STATE_PLAYBACK_INIT && Status != STATE_PLAYBACK) + return; + Status = STATE_NONE; + CleanUpCarsForChaseScene(); + for (int i = 0; i < NUM_CHASE_CARS; i++) { + if (pBaseMemForCar[i]) { + delete[] pBaseMemForCar[i]; + pBaseMemForCar[i] = nil; + } + } +} + +void CRecordDataForChase::SetUpCarsForChaseScene(void) +{ + GiveUsACar(MI_POLICE, CVector(273.54221f, -1167.1907f, 24.880601f), 63.0f, &pChaseCars[0], 2, 1); + GiveUsACar(MI_ENFORCER, CVector(231.1783f, -1388.8322f, 25.978201f), 90.0f, &pChaseCars[1], 2, 1); + GiveUsACar(MI_TAXI, CVector(184.3156f, -1473.251f, 25.978201f), 0.0f, &pChaseCars[4], 6, 6); + GiveUsACar(MI_CHEETAH, CVector(173.8868f, -1377.6514f, 25.978201f), 0.0f, &pChaseCars[6], 4, 5); + GiveUsACar(MI_STINGER, CVector(102.5946f, -943.93628f, 25.9781f), 270.0f, &pChaseCars[7], 53, 53); + GiveUsACar(MI_CHEETAH, CVector(-177.7157f, -862.18652f, 25.978201f), 155.0f, &pChaseCars[10], 41, 1); + GiveUsACar(MI_STINGER, CVector(-170.56979f, -889.02362f, 25.978201f), 154.0f, &pChaseCars[11], 10, 10); + GiveUsACar(MI_KURUMA, CVector(402.60809f, -917.49628f, 37.381001f), 90.0f, &pChaseCars[14], 34, 1); + GiveUsACar(MI_TAXI, CVector(-33.496201f, -938.4563f, 25.9781f), 266.0f, &pChaseCars[16], 6, 6); + GiveUsACar(MI_KURUMA, CVector(49.363098f, -987.60498f, 25.9781f), 0.0f, &pChaseCars[18], 51, 1); + GiveUsACar(MI_TAXI, CVector(179.0049f, -1154.6686f, 25.9781f), 0.0f, &pChaseCars[19], 6, 76); + GiveUsACar(MI_RUMPO, CVector(-28.9762f, -1031.3367f, 25.990601f), 242.0f, &pChaseCars[2], 1, 75); + GiveUsACar(MI_PATRIOT, CVector(114.1564f, -796.69379f, 24.978201f), 180.0f, &pChaseCars[3], 0, 0); +} + +void CRecordDataForChase::CleanUpCarsForChaseScene(void) +{ + for (int i = 0; i < NUM_CHASE_CARS; i++) + RemoveCarFromChase(i); +} -uint8 &CRecordDataForChase::Status = *(uint8*)0x95CDCE; +void CRecordDataForChase::RemoveCarFromChase(int32 i) +{ + if (!pChaseCars[i]) + return; + CWorld::Remove(pChaseCars[i]); + delete pChaseCars[i]; + pChaseCars[i] = nil; +} -WRAPPER void CRecordDataForGame::SaveOrRetrieveDataForThisFrame(void) { EAXJMP(0x4341F0); } -WRAPPER void CRecordDataForGame::Init(void) { EAXJMP(0x4340F0); } +CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32 i) +{ + CVehicle* pVehicle = pChaseCars[i]; + pChaseCars[i] = nil; + pVehicle->m_status = STATUS_PHYSICS; + return pVehicle; +} -WRAPPER void CRecordDataForChase::SaveOrRetrieveDataForThisFrame(void) { EAXJMP(0x4347F0); } -WRAPPER void CRecordDataForChase::ProcessControlCars(void) { EAXJMP(0x435540); } -WRAPPER void CRecordDataForChase::SaveOrRetrieveCarPositions(void) { EAXJMP(0x434B20); } -WRAPPER void CRecordDataForChase::StartChaseScene(float) { EAXJMP(0x435690); } -WRAPPER void CRecordDataForChase::CleanUpChaseScene() { EAXJMP(0x4357C0); } -WRAPPER void CRecordDataForChase::RemoveCarFromChase(int32) { EAXJMP(0x435BC0); } -WRAPPER CVehicle* CRecordDataForChase::TurnChaseCarIntoScriptCar(int32) { EAXJMP(0x435C00); } -WRAPPER void CRecordDataForChase::Init(void) { EAXJMP(0x434780); } diff --git a/src/control/Record.h b/src/control/Record.h index e52a623e..4abeb68a 100644 --- a/src/control/Record.h +++ b/src/control/Record.h @@ -1,34 +1,106 @@ #pragma once +class CAutomobile; class CVehicle; +class CControllerState; -enum { - RECORDSTATE_0, - RECORDSTATE_1, - RECORDSTATE_2, +class CCarStateEachFrame +{ +public: + int16 velX; + int16 velY; + int16 velZ; + int8 rightX; + int8 rightY; + int8 rightZ; + int8 forwardX; + int8 forwardY; + int8 forwardZ; + int8 wheel; + uint8 gas; + uint8 brake; + bool handbrake; + CVector pos; }; +extern char* gString; + class CRecordDataForChase { -public: + enum { + NUM_CHASE_CARS = 20 + }; + enum { + STATE_NONE = 0, + STATE_RECORD = 1, + STATE_PLAYBACK_INIT = 2, + STATE_PLAYBACK = 3, + STATE_PLAYBACK_BEFORE_RECORDING = 4 + }; static uint8 &Status; + static int &PositionChanges; + static uint8 &CurrentCar; + static CAutomobile*(&pChaseCars)[NUM_CHASE_CARS]; + static float &AnimTime; + static uint32 &AnimStartTime; + static CCarStateEachFrame* (&pBaseMemForCar)[NUM_CHASE_CARS]; + static float &TimeMultiplier; + static int &FId2; +public: + + static bool IsRecording(void) { return Status == STATE_RECORD; } + static void Init(void); static void SaveOrRetrieveDataForThisFrame(void); - static void ProcessControlCars(void); static void SaveOrRetrieveCarPositions(void); + static void StoreInfoForCar(CAutomobile*, CCarStateEachFrame*); + static void RestoreInfoForMatrix(CMatrix&, CCarStateEachFrame*); + static void RestoreInfoForCar(CAutomobile*, CCarStateEachFrame*, bool); + static void ProcessControlCars(void); +#if (defined(GTA_PS2) || defined(FIX_BUGS)) + static bool ShouldThisPadBeLeftAlone(uint8 pad); +#endif + static void GiveUsACar(int32, CVector, float, CAutomobile**, uint8, uint8); static void StartChaseScene(float); - static void CleanUpChaseScene(); + static void CleanUpChaseScene(void); + static void SetUpCarsForChaseScene(void); + static void CleanUpCarsForChaseScene(void); static void RemoveCarFromChase(int32); static CVehicle* TurnChaseCarIntoScriptCar(int32); - static void Init(void); + }; +struct tGameBuffer +{ + float m_fTimeStep; + uint32 m_nTimeInMilliseconds; + uint8 m_nSizeOfPads[2]; + uint16 m_nChecksum; + uint8 m_ControllerBuffer[116]; +}; class CRecordDataForGame { + enum { + STATE_NONE = 0, + STATE_RECORD = 1, + STATE_PLAYBACK = 2, + }; + static uint16& RecordingState; + static uint8* &pDataBuffer; + static uint8* &pDataBufferPointer; + static int &FId; + static tGameBuffer &pDataBufferForFrame; + public: - static uint16 &RecordingState; + static bool IsRecording() { return RecordingState == STATE_RECORD; } + static bool IsPlayingBack() { return RecordingState == STATE_PLAYBACK; } static void SaveOrRetrieveDataForThisFrame(void); static void Init(void); + +private: + static uint16 CalcGameChecksum(void); + static uint8* PackCurrentPadValues(uint8*, CControllerState*, CControllerState*); + static uint8* UnPackCurrentPadValues(uint8*, uint8, CControllerState*); }; diff --git a/src/control/TrafficLights.cpp b/src/control/TrafficLights.cpp index e4416965..ab9cd92d 100644 --- a/src/control/TrafficLights.cpp +++ b/src/control/TrafficLights.cpp @@ -40,9 +40,9 @@ CTrafficLights::DisplayActualLight(CEntity *ent) for(i = 1; i < 6; i++){ assert(mi->Get2dEffect(i)); yMin = min(yMin, mi->Get2dEffect(i)->pos.y); - yMax = min(yMax, mi->Get2dEffect(i)->pos.y); + yMax = max(yMax, mi->Get2dEffect(i)->pos.y); zMin = min(zMin, mi->Get2dEffect(i)->pos.z); - zMax = min(zMax, mi->Get2dEffect(i)->pos.z); + zMax = max(zMax, mi->Get2dEffect(i)->pos.z); } CVector pos1, pos2; |