From b5159ab74e40f527260b69c65917227e2d279fdf Mon Sep 17 00:00:00 2001 From: jacob1 Date: Sun, 31 Dec 2017 23:55:41 -0500 Subject: [PATCH] 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 --- src/Config.h | 6 +- src/client/Client.cpp | 6 +- src/client/GameSave.cpp | 78 +++++++++++++++++++--- src/client/GameSave.h | 2 + src/gui/game/GameView.cpp | 4 +- src/simulation/Elements.h | 2 +- src/simulation/Simulation.cpp | 106 ++++++++++++++++++++--------- src/simulation/Simulation.h | 8 ++- src/simulation/elements/PIPE.cpp | 111 +++++++++++++++++-------------- 9 files changed, 225 insertions(+), 98 deletions(-) diff --git a/src/Config.h b/src/Config.h index b5399d8e66..59a66c7d57 100644 --- a/src/Config.h +++ b/src/Config.h @@ -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 diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 6a6ebaf43b..4cece310dd 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -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 diff --git a/src/client/GameSave.cpp b/src/client/GameSave.cpp index 03a20a1ab6..c3b4e33949 100644 --- a/src/client/GameSave.cpp +++ b/src/client/GameSave.cpp @@ -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(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); diff --git a/src/client/GameSave.h b/src/client/GameSave.h index 89caaa11b6..c8abac340d 100644 --- a/src/client/GameSave.h +++ b/src/client/GameSave.h @@ -78,6 +78,8 @@ class GameSave // author information Json::Value authors; + int pmapbits; + GameSave(); GameSave(GameSave & save); GameSave(int width, int height); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index 73fb76b4a2..4e73a27a82 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -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 diff --git a/src/simulation/Elements.h b/src/simulation/Elements.h index bcd5ab576f..43dc34f9ce 100644 --- a/src/simulation/Elements.h +++ b/src/simulation/Elements.h @@ -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) #define TYP(r) ((r)&PMAPMASK) diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index 465f085f66..2cf88aae37 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -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<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) - { - tempPart.ctype = partMap[tempPart.ctype]; - } - if (tempPart.type == PT_PIPE || tempPart.type == PT_PPIP || tempPart.type == PT_STOR) + // 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]; + } + // 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(n, i)); + break; } + + /*if (save->pmapbits != PMAPBITS) + { + unsigned int pmapmask = (1<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 @@ void Simulation::UpdateParticles(int start, int end) } 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; diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h index f0acc51eb4..441dcb70fb 100644 --- a/src/simulation/Simulation.h +++ b/src/simulation/Simulation.h @@ -216,7 +216,13 @@ class Simulation return (x>=0 && y>=0 && x=0 ? 0 : y); diff --git a/src/simulation/elements/PIPE.cpp b/src/simulation/elements/PIPE.cpp index b2c1196e72..21c7e2bc9b 100644 --- a/src/simulation/elements/PIPE.cpp +++ b/src/simulation/elements/PIPE.cpp @@ -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; @@ -111,14 +116,13 @@ 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,11 +150,15 @@ 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 + if (parts[i].tmp&0x100)//is a single pixel pipe { parts[ID(r)].tmp |= 0x200;//will transfer to a single pixel pipe parts[ID(r)].tmp |= count<<10;//coords of where it came from @@ -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; + if (parts[i].life <= 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,15 +268,16 @@ 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) parts[i].tmp |= 0x100; } - else if (parts[i].life==2) + 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 && tsim->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);