From 2e2c3181b568f4eb865de0c24ee188347ebf5273 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tam=C3=A1s=20B=C3=A1lint=20Misius?= Date: Tue, 28 Feb 2023 12:28:33 +0100 Subject: [PATCH] Fix custom elements disappearing on load (fixes #908) Some checks on particles, most importantly whether their element IDs refers to an enabled element, were done _before_ in-save element IDs are mapped to in-simulation element IDs. This resulted in some particles being removed if their IDs were unlucky enough. --- src/simulation/Simulation.cpp | 78 +++++++++++++++++------------------ 1 file changed, 38 insertions(+), 40 deletions(-) diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 13c3e8c82..55aef81df 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -74,39 +74,67 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu int x = int(tempPart->x + 0.5f); int y = int(tempPart->y + 0.5f); + auto &type = tempPart->type; + // Check various scenarios where we are unable to spawn the element, and set type to 0 to block spawning later if (!InBounds(x, y)) { - tempPart->type = 0; + type = 0; continue; } - int type = tempPart->type; if (type < 0 || type >= PT_NUM) { - tempPart->type = 0; + type = 0; continue; } + type = partMap[type]; + // These store type in ctype, but are special because they store extra information in the bits after type + if (type == PT_CRAY || type == PT_DRAY || type == PT_CONV) + { + int ctype = tempPart->ctype & pmapmask; + int extra = tempPart->ctype >> save->pmapbits; + if (ctype >= 0 && ctype < PT_NUM) + ctype = partMap[ctype]; + tempPart->ctype = PMAP(extra, ctype); + } + else if (GameSave::TypeInCtype(type, tempPart->ctype)) + { + tempPart->ctype = partMap[tempPart->ctype]; + } + // also stores extra bits past type (only STOR right now) + if (GameSave::TypeInTmp(type)) + { + int tmp = tempPart->tmp & pmapmask; + int extra = tempPart->tmp >> save->pmapbits; + tmp = partMap[TYP(tmp)]; + tempPart->tmp = PMAP(extra, tmp); + } + if (GameSave::TypeInTmp2(type, tempPart->tmp2)) + { + tempPart->tmp2 = partMap[tempPart->tmp2]; + } + // Ensure we can spawn this element - if ((player.spwn == 1 && tempPart->type==PT_STKM) || (player2.spwn == 1 && tempPart->type==PT_STKM2)) + if ((player.spwn == 1 && type==PT_STKM) || (player2.spwn == 1 && type==PT_STKM2)) { - tempPart->type = 0; + type = 0; continue; } - if ((tempPart->type == PT_SPAWN || tempPart->type == PT_SPAWN2) && elementCount[type]) + if ((type == PT_SPAWN || type == PT_SPAWN2) && elementCount[type]) { - tempPart->type = 0; + type = 0; continue; } bool Element_FIGH_CanAlloc(Simulation *sim); - if (tempPart->type == PT_FIGH && !Element_FIGH_CanAlloc(this)) + if (type == PT_FIGH && !Element_FIGH_CanAlloc(this)) { - tempPart->type = 0; + type = 0; continue; } if (!elements[type].Enabled) { - tempPart->type = 0; + type = 0; continue; } @@ -151,36 +179,6 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu for (int n = 0; n < NPART && n < save->particlesCount; n++) { Particle tempPart = save->particles[n]; - if (tempPart.type > 0 && tempPart.type < PT_NUM) - tempPart.type = partMap[tempPart.type]; - else - continue; - - // These store type in ctype, but are special because they store extra information in the bits after type - if (tempPart.type == PT_CRAY || tempPart.type == PT_DRAY || tempPart.type == PT_CONV) - { - int ctype = tempPart.ctype & pmapmask; - int extra = tempPart.ctype >> save->pmapbits; - if (ctype >= 0 && ctype < PT_NUM) - ctype = partMap[ctype]; - tempPart.ctype = PMAP(extra, ctype); - } - else if (GameSave::TypeInCtype(tempPart.type, tempPart.ctype)) - { - tempPart.ctype = partMap[tempPart.ctype]; - } - // also stores extra bits past type (only STOR right now) - if (GameSave::TypeInTmp(tempPart.type)) - { - int tmp = tempPart.tmp & pmapmask; - int extra = tempPart.tmp >> save->pmapbits; - tmp = partMap[TYP(tmp)]; - tempPart.tmp = PMAP(extra, tmp); - } - if (GameSave::TypeInTmp2(tempPart.type, tempPart.tmp2)) - { - tempPart.tmp2 = partMap[tempPart.tmp2]; - } // Allocate particle (this location is guaranteed to be empty due to "full scan" logic above) if (pfree == -1)