From 50bccfa4e397d2c5bdb7cd6b8c09daf6d4db2e5f Mon Sep 17 00:00:00 2001 From: withmorten Date: Mon, 21 Jun 2021 19:30:06 +0200 Subject: [PATCH] COMPATIBLE_SAVES2_LOAD and SAVE --- src/control/Garages.cpp | 108 +++++++++++++++++++++++++++------ src/control/Garages.h | 15 +++-- src/control/Phones.cpp | 45 +++++++++++++- src/control/Pickups.cpp | 33 +++++++++- src/core/Zones.cpp | 78 +++++++++++++++++++++++- src/core/config.h | 2 + src/objects/ParticleObject.cpp | 107 ++++++++++++++++++++++++++++++-- src/vehicles/Cranes.cpp | 86 +++++++++++++++++++++++++- 8 files changed, 441 insertions(+), 33 deletions(-) diff --git a/src/control/Garages.cpp b/src/control/Garages.cpp index 3410c881c..10db4caef 100644 --- a/src/control/Garages.cpp +++ b/src/control/Garages.cpp @@ -1883,11 +1883,12 @@ void CStoredCar::StoreCar(CVehicle* pVehicle) m_nRadioStation = pVehicle->m_nRadioStation; m_nVariationA = pVehicle->m_aExtras[0]; m_nVariationB = pVehicle->m_aExtras[1]; - m_bBulletproof = pVehicle->bBulletProof; - m_bFireproof = pVehicle->bFireProof; - m_bExplosionproof = pVehicle->bExplosionProof; - m_bCollisionproof = pVehicle->bCollisionProof; - m_bMeleeproof = pVehicle->bMeleeProof; + m_nFlags = 0; + if (pVehicle->bBulletProof) m_nFlags |= FLAG_BULLETPROOF; + if (pVehicle->bFireProof) m_nFlags |= FLAG_FIREPROOF; + if (pVehicle->bExplosionProof) m_nFlags |= FLAG_EXPLOSIONPROOF; + if (pVehicle->bCollisionProof) m_nFlags |= FLAG_COLLISIONPROOF; + if (pVehicle->bMeleeProof) m_nFlags |= FLAG_MELEEPROOF; if (pVehicle->IsCar()) m_nCarBombType = ((CAutomobile*)pVehicle)->m_bombType; } @@ -1936,11 +1937,11 @@ CVehicle* CStoredCar::RestoreCar() } pVehicle->bHasBeenOwnedByPlayer = true; pVehicle->m_nDoorLock = CARLOCK_UNLOCKED; - pVehicle->bBulletProof = m_bBulletproof; - pVehicle->bFireProof = m_bFireproof; - pVehicle->bExplosionProof = m_bExplosionproof; - pVehicle->bCollisionProof = m_bCollisionproof; - pVehicle->bMeleeProof = m_bMeleeproof; + if (m_nFlags & FLAG_BULLETPROOF) pVehicle->bBulletProof = true; + if (m_nFlags & FLAG_FIREPROOF) pVehicle->bFireProof = true; + if (m_nFlags & FLAG_EXPLOSIONPROOF) pVehicle->bExplosionProof = true; + if (m_nFlags & FLAG_COLLISIONPROOF) pVehicle->bCollisionProof = true; + if (m_nFlags & FLAG_MELEEPROOF) pVehicle->bMeleeProof = true; return pVehicle; } @@ -2327,8 +2328,47 @@ void CGarages::Save(uint8 * buf, uint32 * size) WriteSaveBuf(buf, aCarsInSafeHouse2[i]); WriteSaveBuf(buf, aCarsInSafeHouse3[i]); } - for (int i = 0; i < NUM_GARAGES; i++) + for (int i = 0; i < NUM_GARAGES; i++) { +#ifdef COMPATIBLE_SAVES2 + WriteSaveBuf(buf, aGarages[i].m_eGarageType); + WriteSaveBuf(buf, aGarages[i].m_eGarageState); + WriteSaveBuf(buf, aGarages[i].field_2); + WriteSaveBuf(buf, aGarages[i].m_bClosingWithoutTargetCar); + WriteSaveBuf(buf, aGarages[i].m_bDeactivated); + WriteSaveBuf(buf, aGarages[i].m_bResprayHappened); + SkipSaveBuf(buf, 2); + WriteSaveBuf(buf, aGarages[i].m_nTargetModelIndex); + SkipSaveBuf(buf, 4 + 4); + WriteSaveBuf(buf, aGarages[i].m_bDoor1PoolIndex); + WriteSaveBuf(buf, aGarages[i].m_bDoor2PoolIndex); + WriteSaveBuf(buf, aGarages[i].m_bDoor1IsDummy); + WriteSaveBuf(buf, aGarages[i].m_bDoor2IsDummy); + WriteSaveBuf(buf, aGarages[i].m_bRecreateDoorOnNextRefresh); + WriteSaveBuf(buf, aGarages[i].m_bRotatedDoor); + WriteSaveBuf(buf, aGarages[i].m_bCameraFollowsPlayer); + SkipSaveBuf(buf, 1); + WriteSaveBuf(buf, aGarages[i].m_fX1); + WriteSaveBuf(buf, aGarages[i].m_fX2); + WriteSaveBuf(buf, aGarages[i].m_fY1); + WriteSaveBuf(buf, aGarages[i].m_fY2); + WriteSaveBuf(buf, aGarages[i].m_fZ1); + WriteSaveBuf(buf, aGarages[i].m_fZ2); + WriteSaveBuf(buf, aGarages[i].m_fDoorPos); + WriteSaveBuf(buf, aGarages[i].m_fDoorHeight); + WriteSaveBuf(buf, aGarages[i].m_fDoor1X); + WriteSaveBuf(buf, aGarages[i].m_fDoor1Y); + WriteSaveBuf(buf, aGarages[i].m_fDoor2X); + WriteSaveBuf(buf, aGarages[i].m_fDoor2Y); + WriteSaveBuf(buf, aGarages[i].m_fDoor1Z); + WriteSaveBuf(buf, aGarages[i].m_fDoor2Z); + WriteSaveBuf(buf, aGarages[i].m_nTimeToStartAction); + WriteSaveBuf(buf, aGarages[i].m_bCollectedCarsState); + SkipSaveBuf(buf, 3 + 4 + 4); + SkipSaveBuf(buf, sizeof(aGarages[i].m_sStoredCar)); +#else WriteSaveBuf(buf, aGarages[i]); +#endif + } #ifdef FIX_GARAGE_SIZE VALIDATESAVEBUF(*size); #endif @@ -2339,11 +2379,7 @@ const CStoredCar &CStoredCar::operator=(const CStoredCar & other) m_nModelIndex = other.m_nModelIndex; m_vecPos = other.m_vecPos; m_vecAngle = other.m_vecAngle; - m_bBulletproof = other.m_bBulletproof; - m_bFireproof = other.m_bFireproof; - m_bExplosionproof = other.m_bExplosionproof; - m_bCollisionproof = other.m_bCollisionproof; - m_bMeleeproof = other.m_bMeleeproof; + m_nFlags = other.m_nFlags; m_nPrimaryColor = other.m_nPrimaryColor; m_nSecondaryColor = other.m_nSecondaryColor; m_nRadioStation = other.m_nRadioStation; @@ -2357,7 +2393,7 @@ void CGarages::Load(uint8* buf, uint32 size) { #ifdef FIX_GARAGE_SIZE INITSAVEBUF - assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage)); + assert(size == (6 * sizeof(uint32) + TOTAL_COLLECTCARS_GARAGES * sizeof(*CarTypesCollected) + sizeof(uint32) + 3 * NUM_GARAGE_STORED_CARS * sizeof(CStoredCar) + NUM_GARAGES * sizeof(CGarage))); #else assert(size == 5484); #endif @@ -2380,7 +2416,45 @@ void CGarages::Load(uint8* buf, uint32 size) ReadSaveBuf(&aCarsInSafeHouse3[i], buf); } for (int i = 0; i < NUM_GARAGES; i++) { +#ifdef COMPATIBLE_SAVES2 + ReadSaveBuf(&aGarages[i].m_eGarageType, buf); + ReadSaveBuf(&aGarages[i].m_eGarageState, buf); + ReadSaveBuf(&aGarages[i].field_2, buf); + ReadSaveBuf(&aGarages[i].m_bClosingWithoutTargetCar, buf); + ReadSaveBuf(&aGarages[i].m_bDeactivated, buf); + ReadSaveBuf(&aGarages[i].m_bResprayHappened, buf); + SkipSaveBuf(buf, 2); + ReadSaveBuf(&aGarages[i].m_nTargetModelIndex, buf); + SkipSaveBuf(buf, 4 + 4); + ReadSaveBuf(&aGarages[i].m_bDoor1PoolIndex, buf); + ReadSaveBuf(&aGarages[i].m_bDoor2PoolIndex, buf); + ReadSaveBuf(&aGarages[i].m_bDoor1IsDummy, buf); + ReadSaveBuf(&aGarages[i].m_bDoor2IsDummy, buf); + ReadSaveBuf(&aGarages[i].m_bRecreateDoorOnNextRefresh, buf); + ReadSaveBuf(&aGarages[i].m_bRotatedDoor, buf); + ReadSaveBuf(&aGarages[i].m_bCameraFollowsPlayer, buf); + SkipSaveBuf(buf, 1); + ReadSaveBuf(&aGarages[i].m_fX1, buf); + ReadSaveBuf(&aGarages[i].m_fX2, buf); + ReadSaveBuf(&aGarages[i].m_fY1, buf); + ReadSaveBuf(&aGarages[i].m_fY2, buf); + ReadSaveBuf(&aGarages[i].m_fZ1, buf); + ReadSaveBuf(&aGarages[i].m_fZ2, buf); + ReadSaveBuf(&aGarages[i].m_fDoorPos, buf); + ReadSaveBuf(&aGarages[i].m_fDoorHeight, buf); + ReadSaveBuf(&aGarages[i].m_fDoor1X, buf); + ReadSaveBuf(&aGarages[i].m_fDoor1Y, buf); + ReadSaveBuf(&aGarages[i].m_fDoor2X, buf); + ReadSaveBuf(&aGarages[i].m_fDoor2Y, buf); + ReadSaveBuf(&aGarages[i].m_fDoor1Z, buf); + ReadSaveBuf(&aGarages[i].m_fDoor2Z, buf); + ReadSaveBuf(&aGarages[i].m_nTimeToStartAction, buf); + ReadSaveBuf(&aGarages[i].m_bCollectedCarsState, buf); + SkipSaveBuf(buf, 3 + 4 + 4); + SkipSaveBuf(buf, sizeof(aGarages[i].m_sStoredCar)); +#else ReadSaveBuf(&aGarages[i], buf); +#endif aGarages[i].m_pDoor1 = nil; aGarages[i].m_pDoor2 = nil; aGarages[i].m_pTarget = nil; diff --git a/src/control/Garages.h b/src/control/Garages.h index a7dfa4622..10d634486 100644 --- a/src/control/Garages.h +++ b/src/control/Garages.h @@ -51,14 +51,17 @@ enum class CStoredCar { + enum { + FLAG_BULLETPROOF = 0x1, + FLAG_FIREPROOF = 0x2, + FLAG_EXPLOSIONPROOF = 0x4, + FLAG_COLLISIONPROOF = 0x8, + FLAG_MELEEPROOF = 0x10, + }; int32 m_nModelIndex; CVector m_vecPos; CVector m_vecAngle; - int32 m_bBulletproof : 1; - int32 m_bFireproof : 1; - int32 m_bExplosionproof : 1; - int32 m_bCollisionproof : 1; - int32 m_bMeleeproof : 1; + int32 m_nFlags; int8 m_nPrimaryColor; int8 m_nSecondaryColor; int8 m_nRadioStation; @@ -87,7 +90,7 @@ class CGarage bool m_bClosingWithoutTargetCar; bool m_bDeactivated; bool m_bResprayHappened; - int m_nTargetModelIndex; + int32 m_nTargetModelIndex; CEntity *m_pDoor1; CEntity *m_pDoor2; uint8 m_bDoor1PoolIndex; diff --git a/src/control/Phones.cpp b/src/control/Phones.cpp index f9cb14212..4b8e76ef5 100644 --- a/src/control/Phones.cpp +++ b/src/control/Phones.cpp @@ -18,6 +18,12 @@ #include "Replay.h" #endif +#ifdef COMPATIBLE_SAVES2 +#define PHONEINFO_SAVE_SIZE 0xA30 +#else +#define PHONEINFO_SAVE_SIZE sizeof(CPhoneInfo) +#endif + CPhoneInfo gPhoneInfo; bool CPhoneInfo::bDisplayingPhoneMessage; // is phone picked up @@ -209,6 +215,22 @@ CPhoneInfo::IsMessageBeingDisplayed(int phoneId) return pPhoneDisplayingMessages == &m_aPhones[phoneId]; } +#ifdef COMPATIBLE_SAVES2 +static inline void +LoadPhone(CPhone &phone, uint8 *&buf) +{ + ReadSaveBuf(&phone.m_vecPos, buf); + SkipSaveBuf(buf, 6 * 4); + ReadSaveBuf(&phone.m_repeatedMessagePickupStart, buf); + uint32 tmp; + ReadSaveBuf(&tmp, buf); + phone.m_pEntity = (CEntity*)(uintptr)tmp; + ReadSaveBuf(&phone.m_nState, buf); + ReadSaveBuf(&phone.m_visibleToCam, buf); + SkipSaveBuf(buf, 3); +} +#endif + void CPhoneInfo::Load(uint8 *buf, uint32 size) { @@ -226,7 +248,12 @@ INITSAVEBUF // We can do it without touching saves. We'll only load script phones, others are already loaded in Initialise for (int i = 0; i < 50; i++) { CPhone phoneToLoad; +#ifdef COMPATIBLE_SAVES2 + phoneToLoad.m_apMessages[0]=phoneToLoad.m_apMessages[1]=phoneToLoad.m_apMessages[2]=phoneToLoad.m_apMessages[3]=phoneToLoad.m_apMessages[4]=phoneToLoad.m_apMessages[5] = nil; + LoadPhone(phoneToLoad, buf); +#else ReadSaveBuf(&phoneToLoad, buf); +#endif if (ignoreOtherPhones) continue; @@ -252,7 +279,11 @@ INITSAVEBUF m_nScriptPhonesMax = scriptPhonesMax; for (int i = 0; i < NUMPHONES; i++) { +#ifdef COMPATIBLE_SAVES2 + LoadPhone(m_aPhones[i], buf); +#else ReadSaveBuf(&m_aPhones[i], buf); +#endif // It's saved as building pool index in save file, convert it to true entity if (m_aPhones[i].m_pEntity) { m_aPhones[i].m_pEntity = CPools::GetBuildingPool()->GetSlot((uintptr)m_aPhones[i].m_pEntity - 1); @@ -376,7 +407,7 @@ CPhoneInfo::Initialise(void) void CPhoneInfo::Save(uint8 *buf, uint32 *size) { - *size = sizeof(CPhoneInfo); + *size = PHONEINFO_SAVE_SIZE; INITSAVEBUF WriteSaveBuf(buf, m_nMax); WriteSaveBuf(buf, m_nScriptPhonesMax); @@ -385,12 +416,24 @@ INITSAVEBUF #else for (int phoneId = 0; phoneId < NUMPHONES; phoneId++) { #endif +#ifdef COMPATIBLE_SAVES2 + WriteSaveBuf(buf, m_aPhones[phoneId].m_vecPos); + SkipSaveBuf(buf, 6 * 4); + WriteSaveBuf(buf, m_aPhones[phoneId].m_repeatedMessagePickupStart); + // Convert entity pointer to building pool index while saving + int32 tmp = m_aPhones[phoneId].m_pEntity ? CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)m_aPhones[phoneId].m_pEntity) + 1 : 0; + WriteSaveBuf(buf, tmp); + WriteSaveBuf(buf, m_aPhones[phoneId].m_nState); + WriteSaveBuf(buf, m_aPhones[phoneId].m_visibleToCam); + SkipSaveBuf(buf, 3); +#else CPhone* phone = WriteSaveBuf(buf, m_aPhones[phoneId]); // Convert entity pointer to building pool index while saving if (phone->m_pEntity) { phone->m_pEntity = (CEntity*) (CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert((CBuilding*)phone->m_pEntity) + 1); } +#endif } VALIDATESAVEBUF(*size) } diff --git a/src/control/Pickups.cpp b/src/control/Pickups.cpp index 10175fba7..309536655 100644 --- a/src/control/Pickups.cpp +++ b/src/control/Pickups.cpp @@ -32,6 +32,12 @@ #include "WaterLevel.h" #include "World.h" +#ifdef COMPATIBLE_SAVES2 +#define PICKUPS_SAVE_SIZE 0x24C0 +#else +#define PICKUPS_SAVE_SIZE sizeof(aPickUps) +#endif + CPickup CPickups::aPickUps[NUMPICKUPS]; int16 CPickups::NumMessages; int32 CPickups::aPickUpsCollected[NUMCOLLECTEDPICKUPS]; @@ -1000,10 +1006,23 @@ CPickups::Load(uint8 *buf, uint32 size) INITSAVEBUF for (int32 i = 0; i < NUMPICKUPS; i++) { +#ifdef COMPATIBLE_SAVES2 + ReadSaveBuf(&aPickUps[i].m_eType, buf); + ReadSaveBuf(&aPickUps[i].m_bRemoved, buf); + ReadSaveBuf(&aPickUps[i].m_nQuantity, buf); + int32 tmp; + ReadSaveBuf(&tmp, buf); + aPickUps[i].m_pObject = aPickUps[i].m_eType != PICKUP_NONE && tmp != 0 ? CPools::GetObjectPool()->GetSlot(tmp - 1) : nil; + ReadSaveBuf(&aPickUps[i].m_nTimer, buf); + ReadSaveBuf(&aPickUps[i].m_eModelIndex, buf); + ReadSaveBuf(&aPickUps[i].m_nIndex, buf); + ReadSaveBuf(&aPickUps[i].m_vecPos, buf); +#else ReadSaveBuf(&aPickUps[i], buf); if (aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil) aPickUps[i].m_pObject = CPools::GetObjectPool()->GetSlot((uintptr)aPickUps[i].m_pObject - 1); +#endif } ReadSaveBuf(&CollectedPickUpIndex, buf); @@ -1019,14 +1038,26 @@ VALIDATESAVEBUF(size) void CPickups::Save(uint8 *buf, uint32 *size) { - *size = sizeof(aPickUps) + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected); + *size = PICKUPS_SAVE_SIZE + sizeof(uint16) + sizeof(uint16) + sizeof(aPickUpsCollected); INITSAVEBUF for (int32 i = 0; i < NUMPICKUPS; i++) { +#ifdef COMPATIBLE_SAVES2 + WriteSaveBuf(buf, aPickUps[i].m_eType); + WriteSaveBuf(buf, aPickUps[i].m_bRemoved); + WriteSaveBuf(buf, aPickUps[i].m_nQuantity); + int32 tmp = aPickUps[i].m_eType != PICKUP_NONE && aPickUps[i].m_pObject != nil ? CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(aPickUps[i].m_pObject) + 1 : 0; + WriteSaveBuf(buf, tmp); + WriteSaveBuf(buf, aPickUps[i].m_nTimer); + WriteSaveBuf(buf, aPickUps[i].m_eModelIndex); + WriteSaveBuf(buf, aPickUps[i].m_nIndex); + WriteSaveBuf(buf, aPickUps[i].m_vecPos); +#else CPickup *buf_pickup = WriteSaveBuf(buf, aPickUps[i]); if (buf_pickup->m_eType != PICKUP_NONE && buf_pickup->m_pObject != nil) buf_pickup->m_pObject = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(buf_pickup->m_pObject) + 1); +#endif } WriteSaveBuf(buf, CollectedPickUpIndex); diff --git a/src/core/Zones.cpp b/src/core/Zones.cpp index 107b1db8f..9f011430a 100644 --- a/src/core/Zones.cpp +++ b/src/core/Zones.cpp @@ -10,6 +10,14 @@ #include "Timer.h" #include "SaveBuf.h" +#ifdef COMPATIBLE_SAVES2 +#define ZONEARRAY_SAVE_SIZE 0xAF0 +#define MAPZONEARRAY_SAVE_SIZE 0x578 +#else +#define ZONEARRAY_SAVE_SIZE sizeof(ZoneArray) +#define MAPZONEARRAY_SAVE_SIZE sizeof(MapZoneArray) +#endif + eLevelName CTheZones::m_CurrLevel; CZone *CTheZones::m_pPlayersZone; int16 CTheZones::FindIndex; @@ -633,6 +641,28 @@ CTheZones::InitialiseAudioZoneArray(void) } } +#ifdef COMPATIBLE_SAVES2 +static inline void +SaveOneZone(CZone &zone, uint8 *&buffer) +{ + memcpy(buffer, zone.name, sizeof(zone.name)); + SkipSaveBuf(buffer, sizeof(zone.name)); + WriteSaveBuf(buffer, zone.minx); + WriteSaveBuf(buffer, zone.miny); + WriteSaveBuf(buffer, zone.minz); + WriteSaveBuf(buffer, zone.maxx); + WriteSaveBuf(buffer, zone.maxy); + WriteSaveBuf(buffer, zone.maxz); + WriteSaveBuf(buffer, zone.type); + WriteSaveBuf(buffer, zone.level); + WriteSaveBuf(buffer, zone.zoneinfoDay); + WriteSaveBuf(buffer, zone.zoneinfoNight); + WriteSaveBuf(buffer, (int32)CTheZones::GetIndexForZonePointer(zone.child)); + WriteSaveBuf(buffer, (int32)CTheZones::GetIndexForZonePointer(zone.parent)); + WriteSaveBuf(buffer, (int32)CTheZones::GetIndexForZonePointer(zone.next)); +} +#endif + void CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) { @@ -643,9 +673,9 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) + sizeof(int32) // GetIndexForZonePointer + sizeof(m_CurrLevel) + sizeof(FindIndex) + sizeof(int16) // padding - + sizeof(ZoneArray) + sizeof(ZoneInfoArray) + + ZONEARRAY_SAVE_SIZE + sizeof(ZoneInfoArray) + sizeof(TotalNumberOfZones) + sizeof(TotalNumberOfZoneInfos) - + sizeof(MapZoneArray) + sizeof(AudioZoneArray) + + MAPZONEARRAY_SAVE_SIZE + sizeof(AudioZoneArray) + sizeof(TotalNumberOfMapZones) + sizeof(NumberOfAudioZones); WriteSaveHeader(buffer, 'Z', 'N', 'S', '\0', *size - SAVE_HEADER_SIZE); @@ -656,10 +686,14 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) WriteSaveBuf(buffer, (int16)0); // padding for(i = 0; i < ARRAY_SIZE(ZoneArray); i++){ +#ifdef COMPATIBLE_SAVES2 + SaveOneZone(ZoneArray[i], buffer); +#else CZone *zone = WriteSaveBuf(buffer, ZoneArray[i]); zone->child = (CZone*)GetIndexForZonePointer(ZoneArray[i].child); zone->parent = (CZone*)GetIndexForZonePointer(ZoneArray[i].parent); zone->next = (CZone*)GetIndexForZonePointer(ZoneArray[i].next); +#endif } for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++) @@ -669,7 +703,9 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) WriteSaveBuf(buffer, TotalNumberOfZoneInfos); for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++) { +#ifndef COMPATIBLE_SAVES2 CZone* zone = WriteSaveBuf(buffer, MapZoneArray[i]); +#endif /* The call of GetIndexForZonePointer is wrong, as it is @@ -679,9 +715,13 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) assert(MapZoneArray[i].child == nil); assert(MapZoneArray[i].parent == nil); assert(MapZoneArray[i].next == nil); +#ifndef COMPATIBLE_SAVES2 zone->child = (CZone*)GetIndexForZonePointer(MapZoneArray[i].child); zone->parent = (CZone*)GetIndexForZonePointer(MapZoneArray[i].parent); zone->next = (CZone*)GetIndexForZonePointer(MapZoneArray[i].next); +#else + SaveOneZone(MapZoneArray[i], buffer); +#endif } for(i = 0; i < ARRAY_SIZE(AudioZoneArray); i++) @@ -693,6 +733,32 @@ CTheZones::SaveAllZones(uint8 *buffer, uint32 *size) VALIDATESAVEBUF(*size) } +#ifdef COMPATIBLE_SAVES2 +static inline void +LoadOneZone(CZone &zone, uint8 *&buffer) +{ + memcpy(zone.name, buffer, sizeof(zone.name)); + SkipSaveBuf(buffer, sizeof(zone.name)); + ReadSaveBuf(&zone.minx, buffer); + ReadSaveBuf(&zone.miny, buffer); + ReadSaveBuf(&zone.minz, buffer); + ReadSaveBuf(&zone.maxx, buffer); + ReadSaveBuf(&zone.maxy, buffer); + ReadSaveBuf(&zone.maxz, buffer); + ReadSaveBuf(&zone.type, buffer); + ReadSaveBuf(&zone.level, buffer); + ReadSaveBuf(&zone.zoneinfoDay, buffer); + ReadSaveBuf(&zone.zoneinfoNight, buffer); + int32 tmp; + ReadSaveBuf(&tmp, buffer); + zone.child = CTheZones::GetPointerForZoneIndex(tmp); + ReadSaveBuf(&tmp, buffer); + zone.parent = CTheZones::GetPointerForZoneIndex(tmp); + ReadSaveBuf(&tmp, buffer); + zone.next = CTheZones::GetPointerForZoneIndex(tmp); +} +#endif + void CTheZones::LoadAllZones(uint8 *buffer, uint32 size) { @@ -708,11 +774,15 @@ CTheZones::LoadAllZones(uint8 *buffer, uint32 size) SkipSaveBuf(buffer, 2); for(i = 0; i < ARRAY_SIZE(ZoneArray); i++){ +#ifdef COMPATIBLE_SAVES2 + LoadOneZone(ZoneArray[i], buffer); +#else ReadSaveBuf(&ZoneArray[i], buffer); ZoneArray[i].child = GetPointerForZoneIndex((uintptr)ZoneArray[i].child); ZoneArray[i].parent = GetPointerForZoneIndex((uintptr)ZoneArray[i].parent); ZoneArray[i].next = GetPointerForZoneIndex((uintptr)ZoneArray[i].next); +#endif } for(i = 0; i < ARRAY_SIZE(ZoneInfoArray); i++) @@ -722,6 +792,9 @@ CTheZones::LoadAllZones(uint8 *buffer, uint32 size) ReadSaveBuf(&TotalNumberOfZoneInfos, buffer); for(i = 0; i < ARRAY_SIZE(MapZoneArray); i++){ +#ifdef COMPATIBLE_SAVES2 + LoadOneZone(MapZoneArray[i], buffer); +#else ReadSaveBuf(&MapZoneArray[i], buffer); /* @@ -732,6 +805,7 @@ CTheZones::LoadAllZones(uint8 *buffer, uint32 size) MapZoneArray[i].child = GetPointerForZoneIndex((uintptr)MapZoneArray[i].child); MapZoneArray[i].parent = GetPointerForZoneIndex((uintptr)MapZoneArray[i].parent); MapZoneArray[i].next = GetPointerForZoneIndex((uintptr)MapZoneArray[i].next); +#endif assert(MapZoneArray[i].child == nil); assert(MapZoneArray[i].parent == nil); assert(MapZoneArray[i].next == nil); diff --git a/src/core/config.h b/src/core/config.h index 8424f6ef3..cad2d3191 100644 --- a/src/core/config.h +++ b/src/core/config.h @@ -238,6 +238,7 @@ enum Config { #define FIX_BUGS // fixes bugs that we've came across during reversing. You can undefine this only on release builds. #define MORE_LANGUAGES // Add more translations to the game #define COMPATIBLE_SAVES // this allows changing structs while keeping saves compatible +#define COMPATIBLE_SAVES2 // just as differentation what was added after "release" #define LOAD_INI_SETTINGS // as the name suggests. fundamental for CUSTOM_FRONTEND_OPTIONS #define NO_MOVIES // add option to disable intro videos @@ -457,6 +458,7 @@ enum Config { #define THIS_IS_STUPID #undef MORE_LANGUAGES #undef COMPATIBLE_SAVES +#undef COMPATIBLE_SAVES2 #undef LOAD_INI_SETTINGS #undef ASPECT_RATIO_SCALE diff --git a/src/objects/ParticleObject.cpp b/src/objects/ParticleObject.cpp index 211a568cd..5f8d80151 100644 --- a/src/objects/ParticleObject.cpp +++ b/src/objects/ParticleObject.cpp @@ -10,6 +10,12 @@ #include "DMAudio.h" #include "screendroplets.h" +#ifdef COMPATIBLE_SAVES2 +#define PARTICLE_OBJECT_SIZEOF 0x88 +#else +#define PARTICLE_OBJECT_SIZEOF sizeof(CParticleObject) +#endif + CParticleObject gPObjectArray[MAX_PARTICLEOBJECTS]; @@ -1111,6 +1117,47 @@ CParticleObject::UpdateFar(void) } } +#ifdef COMPATIBLE_SAVES2 +static inline void +SaveOneParticle(CParticleObject *p, uint8 *&buffer) +{ +#define SkipBuf(buf, num) buf += num +#define CopyToBuf(buf, data) memcpy(buf, &data, sizeof(data)); SkipBuf(buf, sizeof(data)) + // CPlaceable + { + SkipBuf(buffer, 4); + CopyToBuf(buffer, p->GetMatrix().f); + SkipBuf(buffer, 4); + CopyToBuf(buffer, p->GetMatrix().m_hasRwMatrix); + SkipBuf(buffer, 3); + } + + // CParticleObject + { + SkipBuf(buffer, 4); + SkipBuf(buffer, 4); + SkipBuf(buffer, 4); + CopyToBuf(buffer, p->m_nRemoveTimer); + CopyToBuf(buffer, p->m_Type); + CopyToBuf(buffer, p->m_ParticleType); + CopyToBuf(buffer, p->m_nNumEffectCycles); + CopyToBuf(buffer, p->m_nSkipFrames); + CopyToBuf(buffer, p->m_nFrameCounter); + CopyToBuf(buffer, p->m_nState); + SkipBuf(buffer, 2); + CopyToBuf(buffer, p->m_vecTarget); + CopyToBuf(buffer, p->m_fRandVal); + CopyToBuf(buffer, p->m_fSize); + CopyToBuf(buffer, p->m_Color); + CopyToBuf(buffer, p->m_bRemove); + CopyToBuf(buffer, p->m_nCreationChance); + SkipBuf(buffer, 2); + } +#undef SkipBuf +#undef CopyToBuf +} +#endif + bool CParticleObject::SaveParticle(uint8 *buffer, uint32 *length) { @@ -1128,27 +1175,35 @@ CParticleObject::SaveParticle(uint8 *buffer, uint32 *length) *(int32 *)buffer = numObjects; buffer += sizeof(int32); - int32 objectsLength = sizeof(CParticleObject) * (numObjects + 1); + int32 objectsLength = PARTICLE_OBJECT_SIZEOF * (numObjects + 1); int32 dataLength = objectsLength + sizeof(int32); for ( CParticleObject *p = pCloseListHead; p != NULL; p = p->m_pNext ) { -#if 0 // todo better +#ifdef COMPATIBLE_SAVES2 + SaveOneParticle(p, buffer); +#else +#ifdef THIS_IS_STUPID *(CParticleObject*)buffer = *p; #else memcpy(buffer, p, sizeof(CParticleObject)); #endif buffer += sizeof(CParticleObject); +#endif } for ( CParticleObject *p = pFarListHead; p != NULL; p = p->m_pNext ) { -#if 0 // todo better +#ifdef COMPATIBLE_SAVES2 + SaveOneParticle(p, buffer); +#else +#ifdef THIS_IS_STUPID *(CParticleObject*)buffer = *p; #else memcpy(buffer, p, sizeof(CParticleObject)); #endif buffer += sizeof(CParticleObject); +#endif } *length = dataLength; @@ -1166,7 +1221,7 @@ CParticleObject::LoadParticle(uint8 *buffer, uint32 length) int32 numObjects = *(int32 *)buffer; buffer += sizeof(int32); - if ( length != sizeof(CParticleObject) * (numObjects + 1) + sizeof(int32) ) + if ( length != PARTICLE_OBJECT_SIZEOF * (numObjects + 1) + sizeof(int32) ) return false; if ( numObjects == 0 ) @@ -1177,14 +1232,17 @@ CParticleObject::LoadParticle(uint8 *buffer, uint32 length) while ( i < numObjects ) { CParticleObject *dst = pUnusedListHead; +#ifndef COMPATIBLE_SAVES2 CParticleObject *src = (CParticleObject *)buffer; buffer += sizeof(CParticleObject); +#endif if ( dst == NULL ) return false; MoveToList(&pUnusedListHead, &pCloseListHead, dst); +#ifndef COMPATIBLE_SAVES2 dst->m_nState = POBJECTSTATE_UPDATE_CLOSE; dst->m_Type = src->m_Type; dst->m_ParticleType = src->m_ParticleType; @@ -1200,6 +1258,47 @@ CParticleObject::LoadParticle(uint8 *buffer, uint32 length) dst->m_nNumEffectCycles = src->m_nNumEffectCycles; dst->m_nSkipFrames = src->m_nSkipFrames; dst->m_nCreationChance = src->m_nCreationChance; +#else + dst->m_nState = POBJECTSTATE_UPDATE_CLOSE; + dst->m_pParticle = NULL; + +#define SkipBuf(buf, num) buf += num +#define CopyFromBuf(buf, data) memcpy(&data, buf, sizeof(data)); SkipBuf(buf, sizeof(data)) + // CPlaceable + { + SkipBuf(buffer, 4); + CMatrix matrix; + CopyFromBuf(buffer, matrix.f); + SkipBuf(buffer, 4); + CopyFromBuf(buffer, matrix.m_hasRwMatrix); + SkipBuf(buffer, 3); + dst->SetPosition(matrix.GetPosition()); + } + + // CParticleObject + { + SkipBuf(buffer, 4); + SkipBuf(buffer, 4); + SkipBuf(buffer, 4); + CopyFromBuf(buffer, dst->m_nRemoveTimer); + CopyFromBuf(buffer, dst->m_Type); + CopyFromBuf(buffer, dst->m_ParticleType); + CopyFromBuf(buffer, dst->m_nNumEffectCycles); + CopyFromBuf(buffer, dst->m_nSkipFrames); + CopyFromBuf(buffer, dst->m_nFrameCounter); + SkipBuf(buffer, 2); + SkipBuf(buffer, 2); + CopyFromBuf(buffer, dst->m_vecTarget); + CopyFromBuf(buffer, dst->m_fRandVal); + CopyFromBuf(buffer, dst->m_fSize); + CopyFromBuf(buffer, dst->m_Color); + CopyFromBuf(buffer, dst->m_bRemove); + CopyFromBuf(buffer, dst->m_nCreationChance); + SkipBuf(buffer, 2); + } +#undef CopyFromBuf +#undef SkipBuf +#endif i++; } diff --git a/src/vehicles/Cranes.cpp b/src/vehicles/Cranes.cpp index 0f1b8b4c1..2c5adbac3 100644 --- a/src/vehicles/Cranes.cpp +++ b/src/vehicles/Cranes.cpp @@ -37,6 +37,12 @@ #define MIN_VALID_POSITION (-10000.0f) #define DEFAULT_OFFSET (20.0f) +#ifdef COMPATIBLE_SAVES2 +#define CRANES_SAVE_SIZE 0x400 +#else +#define CRANES_SAVE_SIZE sizeof(aCranes) +#endif + uint32 TimerForCamInterpolation; uint32 CCranes::CarsCollectedMilitaryCrane; @@ -634,10 +640,46 @@ void CCranes::Save(uint8* buf, uint32* size) { INITSAVEBUF - *size = 2 * sizeof(uint32) + sizeof(aCranes); + *size = 2 * sizeof(uint32) + CRANES_SAVE_SIZE; WriteSaveBuf(buf, NumCranes); WriteSaveBuf(buf, CarsCollectedMilitaryCrane); for (int i = 0; i < NUM_CRANES; i++) { +#ifdef COMPATIBLE_SAVES2 + int32 tmp = aCranes[i].m_pCraneEntity != nil ? CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(aCranes[i].m_pCraneEntity) + 1 : 0; + WriteSaveBuf(buf, tmp); + tmp = aCranes[i].m_pHook != nil ? CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(aCranes[i].m_pHook) + 1 : 0; + WriteSaveBuf(buf, tmp); + WriteSaveBuf(buf, aCranes[i].m_nAudioEntity); + WriteSaveBuf(buf, aCranes[i].m_fPickupX1); + WriteSaveBuf(buf, aCranes[i].m_fPickupX2); + WriteSaveBuf(buf, aCranes[i].m_fPickupY1); + WriteSaveBuf(buf, aCranes[i].m_fPickupY2); + WriteSaveBuf(buf, aCranes[i].m_vecDropoffTarget); + WriteSaveBuf(buf, aCranes[i].m_fDropoffHeading); + WriteSaveBuf(buf, aCranes[i].m_fPickupAngle); + WriteSaveBuf(buf, aCranes[i].m_fDropoffAngle); + WriteSaveBuf(buf, aCranes[i].m_fPickupDistance); + WriteSaveBuf(buf, aCranes[i].m_fDropoffDistance); + WriteSaveBuf(buf, aCranes[i].m_fPickupHeight); + WriteSaveBuf(buf, aCranes[i].m_fDropoffHeight); + WriteSaveBuf(buf, aCranes[i].m_fHookAngle); + WriteSaveBuf(buf, aCranes[i].m_fHookOffset); + WriteSaveBuf(buf, aCranes[i].m_fHookHeight); + WriteSaveBuf(buf, aCranes[i].m_vecHookInitPos); + WriteSaveBuf(buf, aCranes[i].m_vecHookCurPos); + WriteSaveBuf(buf, aCranes[i].m_vecHookVelocity); + tmp = aCranes[i].m_pVehiclePickedUp != nil ? CPools::GetVehiclePool()->GetJustIndex_NoFreeAssert(aCranes[i].m_pVehiclePickedUp) + 1 : 0; + WriteSaveBuf(buf, tmp); + WriteSaveBuf(buf, aCranes[i].m_nTimeForNextCheck); + WriteSaveBuf(buf, aCranes[i].m_nCraneStatus); + WriteSaveBuf(buf, aCranes[i].m_nCraneState); + WriteSaveBuf(buf, aCranes[i].m_nVehiclesCollected); + WriteSaveBuf(buf, aCranes[i].m_bIsCrusher); + WriteSaveBuf(buf, aCranes[i].m_bIsMilitaryCrane); + WriteSaveBuf(buf, aCranes[i].m_bWasMilitaryCrane); + WriteSaveBuf(buf, aCranes[i].m_bIsTop); + SkipSaveBuf(buf, 1); +#else CCrane *pCrane = WriteSaveBuf(buf, aCranes[i]); if (pCrane->m_pCraneEntity != nil) pCrane->m_pCraneEntity = (CBuilding*)(CPools::GetBuildingPool()->GetJustIndex_NoFreeAssert(pCrane->m_pCraneEntity) + 1); @@ -645,6 +687,7 @@ void CCranes::Save(uint8* buf, uint32* size) pCrane->m_pHook = (CObject*)(CPools::GetObjectPool()->GetJustIndex_NoFreeAssert(pCrane->m_pHook) + 1); if (pCrane->m_pVehiclePickedUp != nil) pCrane->m_pVehiclePickedUp = (CVehicle*)(CPools::GetVehiclePool()->GetJustIndex_NoFreeAssert(pCrane->m_pVehiclePickedUp) + 1); +#endif } VALIDATESAVEBUF(*size); @@ -656,8 +699,46 @@ void CCranes::Load(uint8* buf, uint32 size) ReadSaveBuf(&NumCranes, buf); ReadSaveBuf(&CarsCollectedMilitaryCrane, buf); - for (int i = 0; i < NUM_CRANES; i++) + for (int i = 0; i < NUM_CRANES; i++) { +#ifdef COMPATIBLE_SAVES2 + int32 tmp; + ReadSaveBuf(&tmp, buf); + aCranes[i].m_pCraneEntity = tmp != 0 ? CPools::GetBuildingPool()->GetSlot(tmp - 1) : nil; + ReadSaveBuf(&tmp, buf); + aCranes[i].m_pHook = tmp != 0 ? CPools::GetObjectPool()->GetSlot(tmp - 1) : nil; + ReadSaveBuf(&aCranes[i].m_nAudioEntity, buf); + ReadSaveBuf(&aCranes[i].m_fPickupX1, buf); + ReadSaveBuf(&aCranes[i].m_fPickupX2, buf); + ReadSaveBuf(&aCranes[i].m_fPickupY1, buf); + ReadSaveBuf(&aCranes[i].m_fPickupY2, buf); + ReadSaveBuf(&aCranes[i].m_vecDropoffTarget, buf); + ReadSaveBuf(&aCranes[i].m_fDropoffHeading, buf); + ReadSaveBuf(&aCranes[i].m_fPickupAngle, buf); + ReadSaveBuf(&aCranes[i].m_fDropoffAngle, buf); + ReadSaveBuf(&aCranes[i].m_fPickupDistance, buf); + ReadSaveBuf(&aCranes[i].m_fDropoffDistance, buf); + ReadSaveBuf(&aCranes[i].m_fPickupHeight, buf); + ReadSaveBuf(&aCranes[i].m_fDropoffHeight, buf); + ReadSaveBuf(&aCranes[i].m_fHookAngle, buf); + ReadSaveBuf(&aCranes[i].m_fHookOffset, buf); + ReadSaveBuf(&aCranes[i].m_fHookHeight, buf); + ReadSaveBuf(&aCranes[i].m_vecHookInitPos, buf); + ReadSaveBuf(&aCranes[i].m_vecHookCurPos, buf); + ReadSaveBuf(&aCranes[i].m_vecHookVelocity, buf); + ReadSaveBuf(&tmp, buf); + aCranes[i].m_pVehiclePickedUp = tmp != 0 ? CPools::GetVehiclePool()->GetSlot(tmp - 1) : nil; + ReadSaveBuf(&aCranes[i].m_nTimeForNextCheck, buf); + ReadSaveBuf(&aCranes[i].m_nCraneStatus, buf); + ReadSaveBuf(&aCranes[i].m_nCraneState, buf); + ReadSaveBuf(&aCranes[i].m_nVehiclesCollected, buf); + ReadSaveBuf(&aCranes[i].m_bIsCrusher, buf); + ReadSaveBuf(&aCranes[i].m_bIsMilitaryCrane, buf); + ReadSaveBuf(&aCranes[i].m_bWasMilitaryCrane, buf); + ReadSaveBuf(&aCranes[i].m_bIsTop, buf); + SkipSaveBuf(buf, 1); +#else ReadSaveBuf(&aCranes[i], buf); + } for (int i = 0; i < NUM_CRANES; i++) { CCrane *pCrane = &aCranes[i]; if (pCrane->m_pCraneEntity != nil) @@ -666,6 +747,7 @@ void CCranes::Load(uint8* buf, uint32 size) pCrane->m_pHook = CPools::GetObjectPool()->GetSlot((uintptr)pCrane->m_pHook - 1); if (pCrane->m_pVehiclePickedUp != nil) pCrane->m_pVehiclePickedUp = CPools::GetVehiclePool()->GetSlot((uintptr)pCrane->m_pVehiclePickedUp - 1); +#endif } for (int i = 0; i < NUM_CRANES; i++) { aCranes[i].m_nAudioEntity = DMAudio.CreateEntity(AUDIOTYPE_CRANE, &aCranes[i]);