diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp index b9aaff7c1..1bf12a9ce 100644 --- a/src/simulation/Simulation.cpp +++ b/src/simulation/Simulation.cpp @@ -1115,6 +1115,14 @@ int Simulation::eval_move(int pt, int nx, int ny, unsigned *rr) const return 0; } break; + case PT_PAPR: + // BCOL can always pass through PAPR in order to color it + // Most elements are blocked by marked PAPR, except for certified "weird" elements where it's inverse + if ((pt == PT_BCOL) || (parts[ID(r)].life ^ (pt != PT_ANAR && pt != PT_BIZR && pt != PT_BIZRG))) + result = 2; + else + result = 0; + break; default: // This should never happen // If it were to happen, try_move would interpret a 3 as a 1 @@ -3369,9 +3377,9 @@ void Simulation::RecalcFreeParticles(bool do_life_dec) photons[y][x] = PMAP(i, t); else { - // Particles are sometimes allowed to go inside INVS and FILT + // Particles are sometimes allowed to go inside INVS, FILT, and PAPR // To make particles collide correctly when inside these elements, these elements must not overwrite an existing pmap entry from particles inside them - if (!pmap[y][x] || (t!=PT_INVIS && t!= PT_FILT)) + if (!pmap[y][x] || (t!=PT_INVIS && t!= PT_FILT && t != PT_PAPR)) pmap[y][x] = PMAP(i, t); // (there are a few exceptions, including energy particles - currently no limit on stacking those) if (t!=PT_THDR && t!=PT_EMBR && t!=PT_FIGH && t!=PT_PLSM) diff --git a/src/simulation/SimulationData.cpp b/src/simulation/SimulationData.cpp index b380d0cc4..ce4fd1f9f 100644 --- a/src/simulation/SimulationData.cpp +++ b/src/simulation/SimulationData.cpp @@ -185,6 +185,10 @@ void SimulationData::init_can_move() //SAWD cannot be displaced by other powders if (elements[movingType].Properties & TYPE_PART) can_move[movingType][PT_SAWD] = 0; + + // Let most non-solids pass through unmarked PAPR + if (elements[movingType].Properties & (TYPE_GAS | TYPE_PART | TYPE_LIQUID) && (movingType != PT_FIRE && movingType != PT_SMKE)) + can_move[movingType][PT_PAPR] = 3; } //a list of lots of things PHOT can move through // TODO: replace with property diff --git a/src/simulation/elements/ARAY.cpp b/src/simulation/elements/ARAY.cpp index e101e3aac..b3832e366 100644 --- a/src/simulation/elements/ARAY.cpp +++ b/src/simulation/elements/ARAY.cpp @@ -165,6 +165,32 @@ static int update(UPDATE_FUNC_ARGS) { parts[r].life = 10; } + } + else if (rt == PT_PAPR) + { + // In reading/writing state? + if (parts[r].tmp) + { + if (parts[r].tmp & 0x10) // Reading state + { + // End reading state early + parts[r].tmp = 0; + if (parts[r].life) + { + break; + } + } + else // Writing state + { + parts[r].life = 1; + parts[r].dcolour = 0xFF1A2222; + } + } + else + { + // Enter writing state + parts[r].tmp = 0x03; + } // this if prevents BRAY from stopping on certain materials } else if (rt != PT_INWR && (rt != PT_SPRK || parts[r].ctype != PT_INWR) && rt != PT_ARAY && rt != PT_WIFI && !(rt == PT_SWCH && parts[r].life >= 10)) @@ -189,7 +215,7 @@ static int update(UPDATE_FUNC_ARGS) parts[r].dcolour = 0xFF000000; //this if prevents red BRAY from stopping on certain materials } - else if (rt==PT_STOR || rt==PT_INWR || (rt==PT_SPRK && parts[r].ctype==PT_INWR) || rt==PT_ARAY || rt==PT_WIFI || rt==PT_FILT || (rt==PT_SWCH && parts[r].life>=10)) + else if (rt==PT_STOR || rt==PT_INWR || (rt==PT_SPRK && parts[r].ctype==PT_INWR) || rt==PT_ARAY || rt==PT_WIFI || rt==PT_FILT || (rt==PT_SWCH && parts[r].life>=10) || rt==PT_PAPR) { if (rt == PT_STOR) { @@ -201,6 +227,32 @@ static int update(UPDATE_FUNC_ARGS) isBlackDeco = (parts[r].dcolour==0xFF000000); parts[r].life = 2; } + else if (rt == PT_PAPR) + { + // In reading/writing state? + if (parts[r].tmp) + { + if (parts[r].tmp & 0x10) // Reading state + { + // End reading state early + parts[r].tmp = 0; + if (parts[r].life) + { + break; + } + } + else // Writing state + { + parts[r].life = 0; + parts[r].dcolour = 0; + } + } + else + { + // Enter reading state + parts[r].tmp = 0x13; + } + } docontinue = 1; } else diff --git a/src/simulation/elements/FIRE.cpp b/src/simulation/elements/FIRE.cpp index 35b5b3372..e845d9b79 100644 --- a/src/simulation/elements/FIRE.cpp +++ b/src/simulation/elements/FIRE.cpp @@ -197,6 +197,11 @@ int Element_FIRE_update(UPDATE_FUNC_ARGS) } } } + // Make paper burn more reliably + if (rt==PT_PAPR) + { + parts[ID(r)].temp += 4; + } if (t == PT_LAVA) { diff --git a/src/simulation/elements/LDTC.cpp b/src/simulation/elements/LDTC.cpp index db52e2511..7f194b5b1 100644 --- a/src/simulation/elements/LDTC.cpp +++ b/src/simulation/elements/LDTC.cpp @@ -104,7 +104,7 @@ static int update(UPDATE_FUNC_ARGS) if (!r) continue; bool boolMode = accepted_conductor(sim, r); - bool filtMode = copyColor && TYP(r) == PT_FILT; + bool filtMode = copyColor && (TYP(r) == PT_FILT || TYP(r) == PT_PAPR); if (!boolMode && !filtMode) continue; @@ -147,21 +147,67 @@ static int update(UPDATE_FUNC_ARGS) if (filtMode) { - if (!phot_data_type(TYP(rr))) + if (!phot_data_type(TYP(rr)) && TYP(rr) != PT_PAPR) continue; int nx = x + rx, ny = y + ry; int photonWl = TYP(rr) == PT_FILT ? Element_FILT_getWavelengths(&parts[ID(rr)]) : parts[ID(rr)].ctype; - while (TYP(r) == PT_FILT) + if (TYP(rr) == PT_PAPR) { - parts[ID(r)].ctype = photonWl; - nx += rx; - ny += ry; - if (nx < 0 || ny < 0 || nx >= XRES || ny >= YRES) - break; - r = pmap[ny][nx]; + photonWl = 0x0; + int bit = 0x1; + // Read one bit of the wavelength from successive particles + while (TYP(rr) == PT_PAPR && bit <= 0x3FFFFFFF) + { + if (parts[ID(rr)].life) + { + photonWl |= bit; + } + xCurrent += xStep; + yCurrent += yStep; + if (xCurrent < 0 || yCurrent < 0 || xCurrent >= XRES || yCurrent >= YRES) + break; + rr = pmap[yCurrent][xCurrent]; + bit <<= 1; + } + } + if (TYP(r) == PT_FILT) + { + while (TYP(r) == PT_FILT) + { + parts[ID(r)].ctype = photonWl; + nx += rx; + ny += ry; + if (nx < 0 || ny < 0 || nx >= XRES || ny >= YRES) + break; + r = pmap[ny][nx]; + } + } + if (TYP(r) == PT_PAPR) + { + // Write each bit of the wavelength to successive particles + int bit = 0x1; + while (TYP(r) == PT_PAPR && bit <= 0x3FFFFFFF) + { + if (photonWl & bit) + { + parts[ID(r)].life = 1; + parts[ID(r)].dcolour = 0xFF1B133F; + } + else + { + parts[ID(r)].life = 0; + parts[ID(r)].dcolour = 0; + } + nx += rx; + ny += ry; + if (nx < 0 || ny < 0 || nx >= XRES || ny >= YRES) + break; + r = pmap[ny][nx]; + bit <<= 1; + } } break; } diff --git a/src/simulation/elements/PAPR.cpp b/src/simulation/elements/PAPR.cpp new file mode 100644 index 000000000..141a31039 --- /dev/null +++ b/src/simulation/elements/PAPR.cpp @@ -0,0 +1,162 @@ +#include "simulation/ElementCommon.h" + +static int update(UPDATE_FUNC_ARGS); +static int graphics(GRAPHICS_FUNC_ARGS); + +// Element overview: +// PAPR (Paper) is a flammable solid element that can be colored by certain other elements. +// Additionally, it can be read and written to by ARAY and LDTC. + +// Property usage: +// life: Whether or not the particle is marked +// tmp: Temporary read/write state for ARAY interaction +// tmp2: Singe level + +void Element::Element_PAPR() +{ + Identifier = "DEFAULT_PT_PAPR"; + Name = "PAPR"; + Colour = 0xF3F3CA_rgb; + MenuVisible = 1; + MenuSection = SC_SOLIDS; + Enabled = 1; + + Advection = 0.0f; + AirDrag = 0.00f * CFDS; + AirLoss = 0.995f; + Loss = 0.00f; + Collision = 0.0f; + Gravity = 0.0f; + Diffusion = 0.00f; + HotAir = 0.000f * CFDS; + Falldown = 0; + + Flammable = 0; + Explosive = 0; + Meltable = 0; + Hardness = 15; + + Weight = 100; + + HeatConduct = 80; + Description = "Paper. Flammable, can be marked by BCOL or deco. Lets non-solids through when unmarked."; + + Properties = TYPE_SOLID | PROP_NEUTPENETRATE; + + LowPressure = IPL; + LowPressureTransition = NT; + HighPressure = IPH; + HighPressureTransition = NT; + LowTemperature = ITL; + LowTemperatureTransition = NT; + HighTemperature = 700.0f; + HighTemperatureTransition = PT_NONE; + + Update = &update; + Graphics = &graphics; +} + +static int update(UPDATE_FUNC_ARGS) +{ + // Char when above burning temperature + if (parts[i].temp > 450 && parts[i].temp >= parts[i].tmp2) + { + parts[i].tmp2 = (int)parts[i].temp; + } + + // Auto-ignition temperature + if (parts[i].temp > (451.0f - 32.f) / 1.8f + 273.15f) + { + parts[i].temp += 1; + if (sim->rng.chance((int)parts[i].temp-450,400)) + { + int np = sim->create_part(-1, x + sim->rng.between(-1, 1), y + sim->rng.between(-1, 1), PT_FIRE); + if (np >= 0) + { + parts[np].life = 70; + } + } + } + + // Get marked by BCOL + if (TYP(pmap[y][x]) == PT_BCOL) + { + parts[i].life = 1; + parts[i].dcolour = 0xFF22222A; + } + + // Generally, these should correspond, but correct if they don't. + if (!parts[i].life != !parts[i].dcolour) + { + parts[i].life = parts[i].dcolour ? 1 : 0; + } + + // Decrement tmp counter for laser reading/writing + if (parts[i].tmp & 0xF) + { + parts[i].tmp--; + } + else + { + parts[i].tmp = 0; + } + return 0; +} + +static int graphics(GRAPHICS_FUNC_ARGS) +{ + // Don't render if there's a particle above you + int onTopOfMe = gfctx.sim->pmap[ny][nx]; + if (onTopOfMe && &gfctx.sim->parts[ID(onTopOfMe)] != cpart) + { + *pixel_mode = PMODE_NONE; + return 0; + } + float burnAmount = std::max((float)cpart->tmp2, cpart->temp); + if (cpart->life) + { + // Render deco color when marked + if(gfctx.ren->decorations_enable && !gfctx.ren->blackDecorations) + { + // Burnt paper has more faded colors + float alpha = restrict_flt(((cpart->dcolour >> 24) & 0xFF) - restrict_flt((burnAmount - 450) * 1.7f, 0, 255), 0, 255) / 255.f; + *colr = int(*colr * (1 - alpha) + ((cpart->dcolour >> 16) & 0xFF) * alpha); + *colg = int(*colg * (1 - alpha) + ((cpart->dcolour >> 8) & 0xFF) * alpha); + *colb = int(*colb * (1 - alpha) + ((cpart->dcolour) & 0xFF) * alpha); + } + else // If deco is disabled or blackDecorations is on, become a generic dark gray color + { + float alpha = 1 - restrict_flt((burnAmount - 450) * 1.7f, 0, 255) / 255.f; + *colr = int(*colr * (1 - alpha) + 20 * alpha); + *colg = int(*colg * (1 - alpha) + 20 * alpha); + *colb = int(*colb * (1 - alpha) + 20 * alpha); + } + } + // Darken when burnt + if (burnAmount > 450) + { + *colr -= (int)restrict_flt((burnAmount - 450) * 1.2f, 0, 220); + *colg -= (int)restrict_flt((burnAmount - 450) * 1.4f, 0, 230); + *colb -= (int)restrict_flt((burnAmount - 450) * 1.6f, 0, 197); + } + if (cpart->tmp) + { + *pixel_mode |= PMODE_GLOW; + float flash = (cpart->tmp & 0xF) / 3.f; + *cola = int(flash * 200); + *colr = int(*colr * (1 - flash)); + *colg = int(*colg * (1 - flash)); + *colb = int(*colb * (1 - flash)); + if (cpart->tmp & 0x10) + { + *colr += int(255 * flash); + } + else + { + *colg += int(255 * flash); + *colb += int(255 * flash); + } + } + *pixel_mode |= NO_DECO; + return 0; +} diff --git a/src/simulation/elements/meson.build b/src/simulation/elements/meson.build index 05cc5792f..f8ac7d7cf 100644 --- a/src/simulation/elements/meson.build +++ b/src/simulation/elements/meson.build @@ -191,6 +191,7 @@ simulation_elem_names = [ 'VSNS', 'ROCK', 'LITH', + 'PAPR', ] simulation_elem_src = []