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.
This commit is contained in:
Tamás Bálint Misius 2023-02-28 12:28:33 +01:00
parent ed8ec51f95
commit 2e2c3181b5
No known key found for this signature in database
GPG Key ID: 5B472A12F6ECA9F2

View File

@ -74,39 +74,67 @@ int Simulation::Load(const GameSave * originalSave, bool includePressure, int fu
int x = int(tempPart->x + 0.5f); int x = int(tempPart->x + 0.5f);
int y = int(tempPart->y + 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 // Check various scenarios where we are unable to spawn the element, and set type to 0 to block spawning later
if (!InBounds(x, y)) if (!InBounds(x, y))
{ {
tempPart->type = 0; type = 0;
continue; continue;
} }
int type = tempPart->type;
if (type < 0 || type >= PT_NUM) if (type < 0 || type >= PT_NUM)
{ {
tempPart->type = 0; type = 0;
continue; 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 // 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; 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; continue;
} }
bool Element_FIGH_CanAlloc(Simulation *sim); 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; continue;
} }
if (!elements[type].Enabled) if (!elements[type].Enabled)
{ {
tempPart->type = 0; type = 0;
continue; 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++) for (int n = 0; n < NPART && n < save->particlesCount; n++)
{ {
Particle tempPart = save->particles[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) // Allocate particle (this location is guaranteed to be empty due to "full scan" logic above)
if (pfree == -1) if (pfree == -1)