Changes to save format and PIPE
Update save format to optionally store type as two bits PIPE now stores element in ctype Disallow uploading saves using two bytes in type or other fields update save format to store pmapbits and automatically convert data
This commit is contained in:
parent
0c8c4de125
commit
b5159ab74e
@ -34,9 +34,9 @@
|
||||
#define MOD_ID 0
|
||||
#endif
|
||||
|
||||
#ifdef SNAPSHOT
|
||||
#define FUTURE_SAVE_VERSION 92
|
||||
#define FUTURE_MINOR_VERSION 1
|
||||
#if defined(SNAPSHOT) || defined(DEBUG)
|
||||
#define FUTURE_SAVE_VERSION 93
|
||||
#define FUTURE_MINOR_VERSION 0
|
||||
#endif
|
||||
//VersionInfoEnd
|
||||
|
||||
|
@ -1021,10 +1021,10 @@ RequestStatus Client::UploadSave(SaveInfo & save)
|
||||
lastError = "Cannot serialize game save";
|
||||
return RequestFailure;
|
||||
}
|
||||
#ifdef SNAPSHOT
|
||||
else if (save.gameSave->fromNewerVersion && save.GetPublished())
|
||||
#if defined(SNAPSHOT) || defined(DEBUG)
|
||||
else if (save.gameSave->fromNewerVersion)
|
||||
{
|
||||
lastError = "Cannot publish save";
|
||||
lastError = "Cannot upload save, incompatible with latest release version";
|
||||
return RequestFailure;
|
||||
}
|
||||
#endif
|
||||
|
@ -28,6 +28,7 @@ GameSave::GameSave(GameSave & save):
|
||||
edgeMode(save.edgeMode),
|
||||
signs(save.signs),
|
||||
palette(save.palette),
|
||||
pmapbits(save.pmapbits),
|
||||
expanded(save.expanded),
|
||||
hasOriginalData(save.hasOriginalData),
|
||||
originalData(save.originalData)
|
||||
@ -141,6 +142,7 @@ GameSave::GameSave(char * data, int dataSize)
|
||||
//Collapse();
|
||||
}
|
||||
|
||||
// Called on every new GameSave, including the copy constructor
|
||||
void GameSave::InitData()
|
||||
{
|
||||
blockMap = NULL;
|
||||
@ -157,6 +159,7 @@ void GameSave::InitData()
|
||||
authors.clear();
|
||||
}
|
||||
|
||||
// Called on every new GameSave, except the copy constructor
|
||||
void GameSave::InitVars()
|
||||
{
|
||||
waterEEnabled = false;
|
||||
@ -168,6 +171,7 @@ void GameSave::InitVars()
|
||||
airMode = 0;
|
||||
edgeMode = 0;
|
||||
translated.x = translated.y = 0;
|
||||
pmapbits = 8; // default to 8 bits for older saves
|
||||
}
|
||||
|
||||
bool GameSave::Collapsed()
|
||||
@ -563,6 +567,7 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
unsigned partsCount = 0;
|
||||
unsigned int blockX, blockY, blockW, blockH, fullX, fullY, fullW, fullH;
|
||||
int savedVersion = inputData[4];
|
||||
bool fakeNewerVersion = false; // used for development builds only
|
||||
|
||||
bson b;
|
||||
b.data = NULL;
|
||||
@ -649,6 +654,7 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
CheckBsonFieldInt(iter, "gravityMode", &gravityMode);
|
||||
CheckBsonFieldInt(iter, "airMode", &airMode);
|
||||
CheckBsonFieldInt(iter, "edgeMode", &edgeMode);
|
||||
CheckBsonFieldInt(iter, "pmapbits", &pmapbits);
|
||||
if (!strcmp(bson_iterator_key(&iter), "signs"))
|
||||
{
|
||||
if (bson_iterator_type(&iter)==BSON_ARRAY)
|
||||
@ -739,7 +745,7 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
fprintf(stderr, "Wrong type for %s\n", bson_iterator_key(&iter));
|
||||
}
|
||||
}
|
||||
#ifdef SNAPSHOT
|
||||
#if defined(SNAPSHOT) || defined(DEBUG)
|
||||
if (major > FUTURE_SAVE_VERSION || (major == FUTURE_SAVE_VERSION && minor > FUTURE_MINOR_VERSION))
|
||||
#else
|
||||
if (major > SAVE_VERSION || (major == SAVE_VERSION && minor > MINOR_VERSION))
|
||||
@ -749,6 +755,10 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
errorMessage << "Save from a newer version: Requires version " << major << "." << minor;
|
||||
throw ParseException(ParseException::WrongVersion, errorMessage.str());
|
||||
}
|
||||
#if defined(SNAPSHOT) || defined(DEBUG)
|
||||
else if (major > SAVE_VERSION || (major == SAVE_VERSION && minor > MINOR_VERSION))
|
||||
fakeNewerVersion = true;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -956,6 +966,10 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
particles[newIndex].y = y;
|
||||
i+=3;
|
||||
|
||||
// Read type (2nd byte)
|
||||
if (fieldDescriptor & 0x4000)
|
||||
particles[newIndex].type |= (((unsigned)partsData[i++]) << 8);
|
||||
|
||||
//Read temp
|
||||
if(fieldDescriptor & 0x01)
|
||||
{
|
||||
@ -1185,6 +1199,16 @@ void GameSave::readOPS(char * data, int dataLength)
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PT_PIPE:
|
||||
case PT_PPIP:
|
||||
if (savedVersion < 93 && !fakeNewerVersion)
|
||||
{
|
||||
if (particles[newIndex].ctype == 1)
|
||||
particles[newIndex].tmp |= 0x00020000; //PFLAG_INITIALIZING
|
||||
particles[newIndex].tmp |= (particles[newIndex].ctype-1)<<18;
|
||||
particles[newIndex].ctype = particles[newIndex].tmp&0xFF;
|
||||
}
|
||||
break;
|
||||
}
|
||||
//note: PSv was used in version 77.0 and every version before, add something in PSv too if the element is that old
|
||||
newIndex++;
|
||||
@ -1841,6 +1865,14 @@ void GameSave::readPSv(char * saveDataChar, int dataLength)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Version 93.0
|
||||
if (particles[i-1].type == PT_PIPE || particles[i-1].type == PT_PPIP)
|
||||
{
|
||||
if (particles[i-1].ctype == 1)
|
||||
particles[i-1].tmp |= 0x00020000; //PFLAG_INITIALIZING
|
||||
particles[i-1].tmp |= (particles[i-1].ctype-1)<<18;
|
||||
particles[i-1].ctype = particles[i-1].tmp&0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2020,9 +2052,11 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
|
||||
|
||||
//Copy parts data
|
||||
/* Field descriptor format:
|
||||
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| pavg | tmp[3+4] | tmp2[2] | tmp2 | ctype[2] | vy | vx | dcololour | ctype[1] | tmp[2] | tmp[1] | life[2] | life[1] | temp dbl len|
|
||||
| 0 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||
| RESERVED | type[2] | pavg | tmp[3+4] | tmp2[2] | tmp2 | ctype[2] | vy | vx | decorations | ctype[1] | tmp[2] | tmp[1] | life[2] | life[1] | temp dbl len |
|
||||
life[2] means a second byte (for a 16 bit field) if life[1] is present
|
||||
last bit is reserved. If necessary, use it to signify that fieldDescriptor will have another byte
|
||||
That way, if we ever need a 17th bit, we won't have to change the save format
|
||||
*/
|
||||
auto partsData = std::unique_ptr<unsigned char[]>(new unsigned char[NPART * (sizeof(Particle)+1)]);
|
||||
unsigned int partsDataLen = 0;
|
||||
@ -2057,6 +2091,15 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
|
||||
fieldDescLoc = partsDataLen++;
|
||||
partsDataLen++;
|
||||
|
||||
// Extra type byte if necessary
|
||||
if (particles[i].type & 0xFF00)
|
||||
{
|
||||
partsData[partsDataLen++] = particles[i].type >> 8;
|
||||
fieldDesc |= 1 << 14;
|
||||
RESTRICTVERSION(93, 0);
|
||||
fromNewerVersion = true; // TODO: remove on 93.0 release
|
||||
}
|
||||
|
||||
//Extra Temperature (2nd byte optional, 1st required), 1 to 2 bytes
|
||||
//Store temperature as an offset of 21C(294.15K) or go into a 16byte int and store the whole thing
|
||||
if(fabs(particles[i].temp-294.15f)<127)
|
||||
@ -2193,12 +2236,33 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
|
||||
|| particles[i].type == PT_RFRG || particles[i].type == PT_RFGL || particles[i].type == PT_LSNS)
|
||||
{
|
||||
RESTRICTVERSION(92, 0);
|
||||
fromNewerVersion = true;
|
||||
}
|
||||
else if ((particles[i].type == PT_FRAY || particles[i].type == PT_INVIS) && particles[i].tmp)
|
||||
{
|
||||
RESTRICTVERSION(92, 0);
|
||||
fromNewerVersion = true;
|
||||
}
|
||||
else if (particles[i].type == PT_PIPE || particles[i].type == PT_PPIP)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
fromNewerVersion = true; // TODO: remove on 93.0 release
|
||||
}
|
||||
if (PMAPBITS > 8)
|
||||
{
|
||||
if (Simulation::TypeInCtype(particles[i].type) && particles[i].ctype > 0xFF)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
fromNewerVersion = true; // TODO: remove on 93.0 release
|
||||
}
|
||||
else if (Simulation::TypeInTmp(particles[i].type) && particles[i].tmp > 0xFF)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
fromNewerVersion = true; // TODO: remove on 93.0 release
|
||||
}
|
||||
else if (Simulation::TypeInTmp2(particles[i].type) && particles[i].tmp2 > 0xFF)
|
||||
{
|
||||
RESTRICTVERSION(93, 0);
|
||||
fromNewerVersion = true; // TODO: remove on 93.0 release
|
||||
}
|
||||
}
|
||||
|
||||
//Get the pmap entry for the next particle in the same position
|
||||
@ -2286,9 +2350,7 @@ char * GameSave::serialiseOPS(unsigned int & dataLength)
|
||||
bson_append_int(&b, "airMode", airMode);
|
||||
bson_append_int(&b, "edgeMode", edgeMode);
|
||||
|
||||
//bson_append_int(&b, "leftSelectedElement", sl);
|
||||
//bson_append_int(&b, "rightSelectedElement", sr);
|
||||
//bson_append_int(&b, "activeMenu", active_menu);
|
||||
bson_append_int(&b, "pmapbits", pmapbits);
|
||||
if (partsData && partsDataLen)
|
||||
{
|
||||
bson_append_binary(&b, "parts", BSON_BIN_USER, (const char *)partsData.get(), partsDataLen);
|
||||
|
@ -78,6 +78,8 @@ public:
|
||||
// author information
|
||||
Json::Value authors;
|
||||
|
||||
int pmapbits;
|
||||
|
||||
GameSave();
|
||||
GameSave(GameSave & save);
|
||||
GameSave(int width, int height);
|
||||
|
@ -2292,8 +2292,6 @@ void GameView::OnDraw()
|
||||
if (type)
|
||||
{
|
||||
int ctype = sample.particle.ctype;
|
||||
if (type == PT_PIPE || type == PT_PPIP)
|
||||
ctype = TYP(sample.particle.tmp);
|
||||
|
||||
if (type == PT_PHOT || type == PT_BIZR || type == PT_BIZRG || type == PT_BIZRS || type == PT_FILT || type == PT_BRAY || type == PT_C5)
|
||||
wavelengthGfx = (ctype&0x3FFFFFFF);
|
||||
@ -2322,7 +2320,7 @@ void GameView::OnDraw()
|
||||
sampleInfo << " (" << ctype << ")";
|
||||
// Some elements store extra LIFE info in upper bits of ctype, instead of tmp/tmp2
|
||||
else if (type == PT_CRAY || type == PT_DRAY || type == PT_CONV)
|
||||
sampleInfo << " (" << c->ElementResolve(TYP(type), ID(ctype)) << ")";
|
||||
sampleInfo << " (" << c->ElementResolve(TYP(ctype), ID(ctype)) << ")";
|
||||
else if (c->IsValidElement(ctype))
|
||||
sampleInfo << " (" << c->ElementResolve(ctype, -1) << ")";
|
||||
else
|
||||
|
@ -51,7 +51,7 @@
|
||||
#define OLD_PT_WIND 147
|
||||
|
||||
// Change this to change the amount of bits used to store type in pmap (and a few elements such as PIPE and CRAY)
|
||||
#define PMAPBITS 8
|
||||
#define PMAPBITS 9
|
||||
#define PMAPMASK ((1<<PMAPBITS)-1)
|
||||
#define ID(r) ((r)>>PMAPBITS)
|
||||
#define TYP(r) ((r)&PMAPMASK)
|
||||
|
@ -33,7 +33,7 @@ int Simulation::Load(GameSave * save, bool includePressure)
|
||||
|
||||
int Simulation::Load(int fullX, int fullY, GameSave * save, bool includePressure)
|
||||
{
|
||||
int blockX, blockY, x, y, r;
|
||||
int x, y, r;
|
||||
|
||||
if (!save)
|
||||
return 1;
|
||||
@ -47,10 +47,11 @@ int Simulation::Load(int fullX, int fullY, GameSave * save, bool includePressure
|
||||
}
|
||||
|
||||
//Align to blockMap
|
||||
blockX = (fullX + CELL/2)/CELL;
|
||||
blockY = (fullY + CELL/2)/CELL;
|
||||
int blockX = (fullX + CELL/2)/CELL;
|
||||
int blockY = (fullY + CELL/2)/CELL;
|
||||
fullX = blockX*CELL;
|
||||
fullY = blockY*CELL;
|
||||
unsigned int pmapmask = (1<<save->pmapbits)-1;
|
||||
|
||||
int partMap[PT_NUM];
|
||||
for(int i = 0; i < PT_NUM; i++)
|
||||
@ -102,16 +103,27 @@ int Simulation::Load(int fullX, int fullY, GameSave * save, bool includePressure
|
||||
if (!elements[tempPart.type].Enabled)
|
||||
continue;
|
||||
|
||||
if (tempPart.ctype > 0 && tempPart.ctype < PT_NUM)
|
||||
if (tempPart.type == PT_CLNE || tempPart.type == PT_PCLN || tempPart.type == PT_BCLN || tempPart.type == PT_PBCN || tempPart.type == PT_STOR || tempPart.type == PT_CONV || tempPart.type == PT_STKM || tempPart.type == PT_STKM2 || tempPart.type == PT_FIGH || tempPart.type == PT_LAVA || tempPart.type == PT_SPRK || tempPart.type == PT_PSTN || tempPart.type == PT_CRAY || tempPart.type == PT_DTEC || tempPart.type == PT_DRAY)
|
||||
// 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 (tempPart.ctype > 0 && tempPart.ctype < PT_NUM && TypeInCtype(tempPart.type))
|
||||
{
|
||||
tempPart.ctype = partMap[tempPart.ctype];
|
||||
}
|
||||
if (tempPart.type == PT_PIPE || tempPart.type == PT_PPIP || tempPart.type == PT_STOR)
|
||||
// also stores extra bits past type (only STOR right now)
|
||||
if (TypeInTmp(tempPart.type))
|
||||
{
|
||||
tempPart.tmp = partMap[TYP(tempPart.tmp)] | (tempPart.tmp&~PMAPMASK);
|
||||
int tmp = tempPart.tmp & pmapmask;
|
||||
int extra = tempPart.tmp >> save->pmapbits;
|
||||
tempPart.tmp = PMAP(extra, tmp);
|
||||
}
|
||||
if (tempPart.type == PT_VIRS || tempPart.type == PT_VRSG || tempPart.type == PT_VRSS)
|
||||
if (TypeInTmp2(tempPart.type))
|
||||
{
|
||||
if (tempPart.tmp2 > 0 && tempPart.tmp2 < PT_NUM)
|
||||
tempPart.tmp2 = partMap[tempPart.tmp2];
|
||||
@ -145,30 +157,27 @@ int Simulation::Load(int fullX, int fullY, GameSave * save, bool includePressure
|
||||
elementCount[tempPart.type]++;
|
||||
}
|
||||
|
||||
if (parts[i].type == PT_STKM)
|
||||
switch (parts[i].type)
|
||||
{
|
||||
case PT_STKM:
|
||||
Element_STKM::STKM_init_legs(this, &player, i);
|
||||
player.spwn = 1;
|
||||
player.elem = PT_DUST;
|
||||
player.rocketBoots = false;
|
||||
}
|
||||
else if (parts[i].type == PT_STKM2)
|
||||
{
|
||||
break;
|
||||
case PT_STKM2:
|
||||
Element_STKM::STKM_init_legs(this, &player2, i);
|
||||
player2.spwn = 1;
|
||||
player2.elem = PT_DUST;
|
||||
player2.rocketBoots = false;
|
||||
}
|
||||
else if (parts[i].type == PT_SPAWN)
|
||||
{
|
||||
break;
|
||||
case PT_SPAWN:
|
||||
player.spawnID = i;
|
||||
}
|
||||
else if (parts[i].type == PT_SPAWN2)
|
||||
{
|
||||
break;
|
||||
case PT_SPAWN2:
|
||||
player2.spawnID = i;
|
||||
}
|
||||
else if (parts[i].type == PT_FIGH)
|
||||
{
|
||||
break;
|
||||
case PT_FIGH:
|
||||
for (int fcount = 0; fcount < MAX_FIGHTERS; fcount++)
|
||||
{
|
||||
if(!fighters[fcount].spwn)
|
||||
@ -182,11 +191,28 @@ int Simulation::Load(int fullX, int fullY, GameSave * save, bool includePressure
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parts[i].type == PT_SOAP)
|
||||
{
|
||||
break;
|
||||
case PT_SOAP:
|
||||
soapList.insert(std::pair<unsigned int, unsigned int>(n, i));
|
||||
break;
|
||||
}
|
||||
|
||||
/*if (save->pmapbits != PMAPBITS)
|
||||
{
|
||||
unsigned int pmapmask = (1<<save->pmapbits)-1;
|
||||
if (parts[i].type == PT_CRAY || parts[i].type == PT_DRAY || parts[i].type == PT_CONV)
|
||||
{
|
||||
int type = parts[i].ctype & pmapmask;
|
||||
int data = parts[i].ctype >> save->pmapbits;
|
||||
parts[i].ctype = PMAP(data, type);
|
||||
}
|
||||
else if (parts[i].type == PT_PIPE || parts[i].type == PT_PPIP)
|
||||
{
|
||||
int type = parts[i].tmp & pmapmask;
|
||||
int data = parts[i].tmp >> save->pmapbits;
|
||||
parts[i].tmp = PMAP(data, type);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
parts_lastActiveIndex = NPART-1;
|
||||
force_stacking_check = true;
|
||||
@ -256,6 +282,25 @@ int Simulation::Load(int fullX, int fullY, GameSave * save, bool includePressure
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Simulation::TypeInCtype(int el)
|
||||
{
|
||||
return el == PT_CLNE || el == PT_PCLN || el == PT_BCLN || el == PT_PBCN ||
|
||||
el == PT_STOR || el == PT_CONV || el == PT_STKM || el == PT_STKM2 ||
|
||||
el == PT_FIGH || el == PT_LAVA || el == PT_SPRK || el == PT_PSTN ||
|
||||
el == PT_CRAY || el == PT_DTEC || el == PT_DRAY || el == PT_PIPE ||
|
||||
el == PT_PPIP;
|
||||
}
|
||||
|
||||
bool Simulation::TypeInTmp(int el)
|
||||
{
|
||||
return el == PT_STOR;
|
||||
}
|
||||
|
||||
bool Simulation::TypeInTmp2(int el)
|
||||
{
|
||||
return el == PT_VIRS || el == PT_VRSG || el == PT_VRSS;
|
||||
}
|
||||
|
||||
GameSave * Simulation::Save(bool includePressure)
|
||||
{
|
||||
return Save(0, 0, XRES-1, YRES-1, includePressure);
|
||||
@ -390,6 +435,7 @@ GameSave * Simulation::Save(int fullX, int fullY, int fullX2, int fullY2, bool i
|
||||
}
|
||||
|
||||
SaveSimOptions(newSave);
|
||||
newSave->pmapbits = PMAPBITS;
|
||||
return newSave;
|
||||
}
|
||||
|
||||
@ -2983,7 +3029,7 @@ void Simulation::part_change_type(int i, int x, int y, int t)//changes the type
|
||||
}
|
||||
|
||||
//the function for creating a particle, use p=-1 for creating a new particle, -2 is from a brush, or a particle number to replace a particle.
|
||||
//tv = Type (8 bits) + Var (24 bits), var is usually 0
|
||||
//tv = Type (PMAPBITS bits) + Var (32-PMAPBITS bits), var is usually 0
|
||||
int Simulation::create_part(int p, int x, int y, int t, int v)
|
||||
{
|
||||
int i;
|
||||
@ -4503,9 +4549,9 @@ killed:
|
||||
}
|
||||
r = pmap[fin_y][fin_x];
|
||||
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && !TYP(parts[ID(r)].tmp))
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && !TYP(parts[ID(r)].ctype))
|
||||
{
|
||||
parts[ID(r)].tmp = (parts[ID(r)].tmp&~PMAPMASK) | parts[i].type;
|
||||
parts[ID(r)].ctype = parts[i].type;
|
||||
parts[ID(r)].temp = parts[i].temp;
|
||||
parts[ID(r)].tmp2 = parts[i].life;
|
||||
parts[ID(r)].pavg[0] = parts[i].tmp;
|
||||
|
@ -216,7 +216,13 @@ public:
|
||||
return (x>=0 && y>=0 && x<XRES && y<YRES);
|
||||
}
|
||||
|
||||
// these don't really belong anywhere at the moment, so go here for loop edge mode
|
||||
// Element IDs can be stored in other properties
|
||||
// These functions return true if an element stores a particle type in a property
|
||||
static bool TypeInCtype(int el);
|
||||
static bool TypeInTmp(int el);
|
||||
static bool TypeInTmp2(int el);
|
||||
|
||||
// These don't really belong anywhere at the moment, so go here for loop edge mode
|
||||
static int remainder_p(int x, int y)
|
||||
{
|
||||
return (x % y) + (x>=0 ? 0 : y);
|
||||
|
@ -50,22 +50,27 @@ Element_PIPE::Element_PIPE()
|
||||
memset(&tpart, 0, sizeof(Particle));
|
||||
}
|
||||
|
||||
#define PFLAG_NORMALSPEED 0x00010000
|
||||
// parts[].tmp flags
|
||||
// trigger flags to be processed this frame (trigger flags for next frame are shifted 3 bits to the left):
|
||||
#define PPIP_TMPFLAG_TRIGGER_ON 0x10000000
|
||||
#define PPIP_TMPFLAG_TRIGGER_OFF 0x08000000
|
||||
#define PPIP_TMPFLAG_TRIGGER_REVERSE 0x04000000
|
||||
#define PPIP_TMPFLAG_TRIGGERS 0x1C000000
|
||||
// current status of the pipe
|
||||
#define PPIP_TMPFLAG_PAUSED 0x02000000
|
||||
#define PPIP_TMPFLAG_REVERSED 0x01000000
|
||||
// 0x000000FF element
|
||||
// 0x00000100 is single pixel pipe
|
||||
// 0x00000200 will transfer like a single pixel pipe when in forward mode
|
||||
// 0x00001C00 forward single pixel pipe direction
|
||||
// 0x00002000 will transfer like a single pixel pipe when in reverse mode
|
||||
// 0x0001C000 reverse single pixel pipe direction
|
||||
// 0x00060000 PIPE color data stored here
|
||||
|
||||
#define PFLAG_NORMALSPEED 0x00010000
|
||||
#define PFLAG_INITIALIZING 0x00020000 // colors haven't been set yet
|
||||
#define PFLAG_COLOR_RED 0x00040000
|
||||
#define PFLAG_COLOR_GREEN 0x00080000
|
||||
#define PFLAG_COLOR_BLUE 0x000C0000
|
||||
#define PFLAG_COLORS 0x000C0000
|
||||
|
||||
#define PPIP_TMPFLAG_REVERSED 0x01000000
|
||||
#define PPIP_TMPFLAG_PAUSED 0x02000000
|
||||
#define PPIP_TMPFLAG_TRIGGER_REVERSE 0x04000000
|
||||
#define PPIP_TMPFLAG_TRIGGER_OFF 0x08000000
|
||||
#define PPIP_TMPFLAG_TRIGGER_ON 0x10000000
|
||||
#define PPIP_TMPFLAG_TRIGGERS 0x1C000000
|
||||
|
||||
signed char pos_1_rx[] = {-1,-1,-1, 0, 0, 1, 1, 1};
|
||||
signed char pos_1_ry[] = {-1, 0, 1,-1, 1,-1, 0, 1};
|
||||
@ -75,8 +80,8 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
{
|
||||
int r, rx, ry, np;
|
||||
int rnd, rndstore;
|
||||
if (TYP(parts[i].tmp)>=PT_NUM || !sim->elements[TYP(parts[i].tmp)].Enabled)
|
||||
parts[i].tmp &= ~PMAPMASK;
|
||||
if (parts[i].ctype && !sim->elements[TYP(parts[i].ctype)].Enabled)
|
||||
parts[i].ctype = 0;
|
||||
if (parts[i].tmp & PPIP_TMPFLAG_TRIGGERS)
|
||||
{
|
||||
int pause_changed = 0;
|
||||
@ -115,10 +120,9 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
if (parts[i].tmp & PPIP_TMPFLAG_TRIGGER_REVERSE)
|
||||
{
|
||||
parts[i].tmp ^= PPIP_TMPFLAG_REVERSED;
|
||||
if (parts[i].ctype == 2) //Switch colors so it goes in reverse
|
||||
parts[i].ctype = 4;
|
||||
else if (parts[i].ctype == 4)
|
||||
parts[i].ctype = 2;
|
||||
// Switch colors so it goes in reverse
|
||||
if ((parts[i].tmp&PFLAG_COLORS) != PFLAG_COLOR_GREEN)
|
||||
parts[i].tmp ^= PFLAG_COLOR_GREEN;
|
||||
if (parts[i].tmp & 0x100) //Switch one pixel pipe direction
|
||||
{
|
||||
int coords = (parts[i].tmp>>13)&0xF;
|
||||
@ -131,7 +135,7 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
|
||||
parts[i].tmp &= ~PPIP_TMPFLAG_TRIGGERS;
|
||||
}
|
||||
if (parts[i].ctype>=2 && parts[i].ctype<=4 && !(parts[i].tmp & PPIP_TMPFLAG_PAUSED))
|
||||
if ((parts[i].tmp&PFLAG_COLORS) && !(parts[i].tmp & PPIP_TMPFLAG_PAUSED))
|
||||
{
|
||||
if (parts[i].life==3)
|
||||
{
|
||||
@ -146,9 +150,13 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
r = pmap[y+ry][x+rx];
|
||||
if (!r)
|
||||
continue;
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP)&&parts[ID(r)].ctype==1)
|
||||
if (TYP(r) != PT_PIPE && TYP(r) != PT_PPIP)
|
||||
continue;
|
||||
unsigned int nextColor = (((((parts[i].tmp&PFLAG_COLORS)>>18)+1)%3)+1)<<18;
|
||||
if (parts[ID(r)].tmp&PFLAG_INITIALIZING)
|
||||
{
|
||||
parts[ID(r)].ctype = (((parts[i].ctype)%3)+2);//reverse
|
||||
parts[ID(r)].tmp |= nextColor;
|
||||
parts[ID(r)].tmp &= ~PFLAG_INITIALIZING;
|
||||
parts[ID(r)].life = 6;
|
||||
if (parts[i].tmp&0x100)//is a single pixel pipe
|
||||
{
|
||||
@ -160,7 +168,7 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
neighborcount ++;
|
||||
lastneighbor = ID(r);
|
||||
}
|
||||
else if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP)&&parts[ID(r)].ctype!=(((parts[i].ctype-1)%3)+2))
|
||||
else if ((parts[ID(r)].tmp&PFLAG_COLORS) != nextColor)
|
||||
{
|
||||
neighborcount ++;
|
||||
lastneighbor = ID(r);
|
||||
@ -193,23 +201,23 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
r = pmap[y+ry][x+rx];
|
||||
if(!r)
|
||||
r = sim->photons[y+ry][x+rx];
|
||||
if (surround_space && !r && TYP(parts[i].tmp)!=0) //creating at end
|
||||
if (surround_space && !r && TYP(parts[i].ctype)) //creating at end
|
||||
{
|
||||
np = sim->create_part(-1, x+rx, y+ry, TYP(parts[i].tmp));
|
||||
np = sim->create_part(-1, x+rx, y+ry, TYP(parts[i].ctype));
|
||||
if (np!=-1)
|
||||
{
|
||||
transfer_pipe_to_part(sim, parts+i, parts+np);
|
||||
}
|
||||
}
|
||||
//try eating particle at entrance
|
||||
else if (TYP(parts[i].tmp) == 0 && (sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)))
|
||||
else if (!TYP(parts[i].ctype) && (sim->elements[TYP(r)].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)))
|
||||
{
|
||||
if (TYP(r)==PT_SOAP)
|
||||
Element_SOAP::detach(sim, ID(r));
|
||||
transfer_part_to_pipe(parts+(ID(r)), parts+i);
|
||||
sim->kill_part(ID(r));
|
||||
}
|
||||
else if (TYP(parts[i].tmp) == 0 && TYP(r)==PT_STOR && parts[ID(r)].tmp>0 && sim->IsValidElement(parts[ID(r)].tmp) && (sim->elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)))
|
||||
else if (!TYP(parts[i].ctype) && TYP(r)==PT_STOR && parts[ID(r)].tmp>0 && sim->IsValidElement(parts[ID(r)].tmp) && (sim->elements[parts[ID(r)].tmp].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)))
|
||||
{
|
||||
// STOR stores properties in the same places as PIPE does
|
||||
transfer_pipe_to_pipe(parts+(ID(r)), parts+i);
|
||||
@ -218,7 +226,7 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!parts[i].ctype && parts[i].life<=10)
|
||||
else if (!(parts[i].tmp&(PFLAG_COLORS|PFLAG_INITIALIZING)) && parts[i].life<=10)
|
||||
{
|
||||
// make a border
|
||||
for (rx=-2; rx<3; rx++)
|
||||
@ -229,16 +237,18 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
r = pmap[y+ry][x+rx];
|
||||
if (!r)
|
||||
{
|
||||
int index = sim->create_part(-1,x+rx,y+ry,PT_BRCK);//BRCK border, people didn't like DMND
|
||||
// BRCK border
|
||||
int index = sim->create_part(-1,x+rx,y+ry,PT_BRCK);
|
||||
if (parts[i].type == PT_PPIP && index != -1)
|
||||
parts[index].tmp = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (parts[i].life <= 1)
|
||||
parts[i].ctype = 1;
|
||||
parts[i].tmp |= PFLAG_INITIALIZING;
|
||||
}
|
||||
else if (parts[i].ctype==1)//wait for empty space before starting to generate automatic pipe pattern
|
||||
// Wait for empty space before starting to generate automatic pipe pattern
|
||||
else if (parts[i].tmp & PFLAG_INITIALIZING)
|
||||
{
|
||||
if (!parts[i].life)
|
||||
{
|
||||
@ -258,7 +268,7 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
if (BOUNDS_CHECK && (rx || ry))
|
||||
{
|
||||
r = pmap[y+ry][x+rx];
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && parts[i].ctype==1 && parts[i].life )
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && parts[i].life)
|
||||
issingle = 0;
|
||||
}
|
||||
if (issingle)
|
||||
@ -266,7 +276,8 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
}
|
||||
else if (parts[i].life == 2)
|
||||
{
|
||||
parts[i].ctype = 2;
|
||||
parts[i].tmp |= PFLAG_COLOR_RED;
|
||||
parts[i].tmp &= ~PFLAG_INITIALIZING;
|
||||
parts[i].life = 6;
|
||||
}
|
||||
}
|
||||
@ -278,7 +289,7 @@ int Element_PIPE::update(UPDATE_FUNC_ARGS)
|
||||
//#TPT-Directive ElementHeader Element_PIPE static int graphics(GRAPHICS_FUNC_ARGS)
|
||||
int Element_PIPE::graphics(GRAPHICS_FUNC_ARGS)
|
||||
{
|
||||
int t = TYP(cpart->tmp);
|
||||
int t = TYP(cpart->ctype);
|
||||
if (t>0 && t<PT_NUM && ren->sim->elements[t].Enabled)
|
||||
{
|
||||
if (t == PT_STKM || t == PT_STKM2 || t == PT_FIGH)
|
||||
@ -324,18 +335,19 @@ int Element_PIPE::graphics(GRAPHICS_FUNC_ARGS)
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (cpart->ctype){
|
||||
case 2:
|
||||
switch (cpart->tmp & PFLAG_COLORS)
|
||||
{
|
||||
case PFLAG_COLOR_RED:
|
||||
*colr = 50;
|
||||
*colg = 1;
|
||||
*colb = 1;
|
||||
break;
|
||||
case 3:
|
||||
case PFLAG_COLOR_GREEN:
|
||||
*colr = 1;
|
||||
*colg = 50;
|
||||
*colb = 1;
|
||||
break;
|
||||
case 4:
|
||||
case PFLAG_COLOR_BLUE:
|
||||
*colr = 1;
|
||||
*colg = 1;
|
||||
*colb = 50;
|
||||
@ -350,12 +362,12 @@ int Element_PIPE::graphics(GRAPHICS_FUNC_ARGS)
|
||||
//#TPT-Directive ElementHeader Element_PIPE static void transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part)
|
||||
void Element_PIPE::transfer_pipe_to_part(Simulation * sim, Particle *pipe, Particle *part)
|
||||
{
|
||||
part->type = TYP(pipe->tmp);
|
||||
part->type = TYP(pipe->ctype);
|
||||
part->temp = pipe->temp;
|
||||
part->life = pipe->tmp2;
|
||||
part->tmp = pipe->pavg[0];
|
||||
part->ctype = pipe->pavg[1];
|
||||
pipe->tmp &= ~PMAPMASK;
|
||||
pipe->ctype = 0;
|
||||
|
||||
if (!(sim->elements[part->type].Properties & TYPE_ENERGY))
|
||||
{
|
||||
@ -372,7 +384,7 @@ void Element_PIPE::transfer_pipe_to_part(Simulation * sim, Particle *pipe, Parti
|
||||
//#TPT-Directive ElementHeader Element_PIPE static void transfer_part_to_pipe(Particle *part, Particle *pipe)
|
||||
void Element_PIPE::transfer_part_to_pipe(Particle *part, Particle *pipe)
|
||||
{
|
||||
pipe->tmp = (pipe->tmp&~PMAPMASK) | part->type;
|
||||
pipe->ctype = part->type;
|
||||
pipe->temp = part->temp;
|
||||
pipe->tmp2 = part->life;
|
||||
pipe->pavg[0] = part->tmp;
|
||||
@ -382,19 +394,20 @@ void Element_PIPE::transfer_part_to_pipe(Particle *part, Particle *pipe)
|
||||
//#TPT-Directive ElementHeader Element_PIPE static void transfer_pipe_to_pipe(Particle *src, Particle *dest)
|
||||
void Element_PIPE::transfer_pipe_to_pipe(Particle *src, Particle *dest)
|
||||
{
|
||||
dest->tmp = (dest->tmp&~PMAPMASK) | TYP(src->tmp);
|
||||
dest->ctype = src->ctype;
|
||||
dest->temp = src->temp;
|
||||
dest->tmp2 = src->tmp2;
|
||||
dest->pavg[0] = src->pavg[0];
|
||||
dest->pavg[1] = src->pavg[1];
|
||||
src->tmp &= ~PMAPMASK;
|
||||
src->ctype = 0;
|
||||
}
|
||||
|
||||
//#TPT-Directive ElementHeader Element_PIPE static void pushParticle(Simulation * sim, int i, int count, int original)
|
||||
void Element_PIPE::pushParticle(Simulation * sim, int i, int count, int original)
|
||||
{
|
||||
int rndstore, rnd, rx, ry, r, x, y, np, q, notctype=(((sim->parts[i].ctype)%3)+2);
|
||||
if (TYP(sim->parts[i].tmp) == 0 || count >= 2)//don't push if there is nothing there, max speed of 2 per frame
|
||||
int rndstore, rnd, rx, ry, r, x, y, np, q;
|
||||
unsigned int notctype = (((((sim->parts[i].tmp&PFLAG_COLORS)>>18)+1)%3)+1)<<18;
|
||||
if (!TYP(sim->parts[i].ctype) || count >= 2)//don't push if there is nothing there, max speed of 2 per frame
|
||||
return;
|
||||
x = (int)(sim->parts[i].x+0.5f);
|
||||
y = (int)(sim->parts[i].y+0.5f);
|
||||
@ -415,7 +428,7 @@ void Element_PIPE::pushParticle(Simulation * sim, int i, int count, int original
|
||||
r = sim->pmap[y+ry][x+rx];
|
||||
if (!r)
|
||||
continue;
|
||||
else if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && sim->parts[ID(r)].ctype!=notctype && TYP(sim->parts[ID(r)].tmp)==0)
|
||||
else if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && (sim->parts[ID(r)].tmp&PFLAG_COLORS) != notctype && !TYP(sim->parts[ID(r)].ctype))
|
||||
{
|
||||
transfer_pipe_to_pipe(sim->parts+i, sim->parts+(ID(r)));
|
||||
if (ID(r) > original)
|
||||
@ -445,7 +458,7 @@ void Element_PIPE::pushParticle(Simulation * sim, int i, int count, int original
|
||||
{
|
||||
int coords = 7 - ((sim->parts[i].tmp>>10)&7);
|
||||
r = sim->pmap[y+ pos_1_ry[coords]][x+ pos_1_rx[coords]];
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && sim->parts[ID(r)].ctype!=notctype && TYP(sim->parts[ID(r)].tmp)==0)
|
||||
if ((TYP(r)==PT_PIPE || TYP(r) == PT_PPIP) && (sim->parts[ID(r)].tmp&PFLAG_COLORS) != notctype && !TYP(sim->parts[ID(r)].ctype))
|
||||
{
|
||||
transfer_pipe_to_pipe(sim->parts+i, sim->parts+(ID(r)));
|
||||
if (ID(r) > original)
|
||||
@ -472,7 +485,7 @@ void Element_PIPE::pushParticle(Simulation * sim, int i, int count, int original
|
||||
{
|
||||
rx = pos_1_rx[coords];
|
||||
ry = pos_1_ry[coords];
|
||||
np = sim->create_part(-1,x+rx,y+ry,TYP(sim->parts[i].tmp));
|
||||
np = sim->create_part(-1,x+rx,y+ry,TYP(sim->parts[i].ctype));
|
||||
if (np!=-1)
|
||||
{
|
||||
transfer_pipe_to_part(sim, sim->parts+i, sim->parts+np);
|
||||
|
Loading…
Reference in New Issue
Block a user