summaryrefslogtreecommitdiff
path: root/src/simulation
diff options
context:
space:
mode:
authorSimon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
committer Simon Robertshaw <simon@hardwired.org.uk>2012-11-17 19:44:09 (GMT)
commit058a2edd75debbd0297f92572316daa704bd379f (patch)
treead303f091f9a08b209b91eb34a9fcad996a3de69 /src/simulation
parente3594aba9e05c6865d396418c028049cda92c2f3 (diff)
parent7a21ae192fe19868539956f3fe28e62b2c7c4429 (diff)
downloadpowder-058a2edd75debbd0297f92572316daa704bd379f.zip
powder-058a2edd75debbd0297f92572316daa704bd379f.tar.gz
Merge branch 'master' of github.com:FacialTurd/PowderToypp
Diffstat (limited to 'src/simulation')
-rw-r--r--src/simulation/Air.cpp321
-rw-r--r--src/simulation/Air.h37
-rw-r--r--src/simulation/Element.h23
-rw-r--r--src/simulation/ElementGraphics.h55
-rw-r--r--src/simulation/Elements.h100
-rw-r--r--src/simulation/GOLMenu.h20
-rw-r--r--src/simulation/Gravity.cpp527
-rw-r--r--src/simulation/Gravity.h123
-rw-r--r--src/simulation/MenuSection.h20
-rw-r--r--src/simulation/Particle.cpp27
-rw-r--r--src/simulation/Particle.h31
-rw-r--r--src/simulation/Player.h23
-rw-r--r--src/simulation/Sample.h29
-rw-r--r--src/simulation/SaveRenderer.cpp183
-rw-r--r--src/simulation/SaveRenderer.h37
-rw-r--r--src/simulation/Sign.cpp55
-rw-r--r--src/simulation/Sign.h26
-rw-r--r--src/simulation/Simulation.cpp4835
-rw-r--r--src/simulation/Simulation.h214
-rw-r--r--src/simulation/SimulationData.cpp344
-rw-r--r--src/simulation/SimulationData.h178
-rw-r--r--src/simulation/Snapshot.h55
-rw-r--r--src/simulation/StorageClasses.h54
-rw-r--r--src/simulation/StructProperty.h39
-rw-r--r--src/simulation/Tools.h7
-rw-r--r--src/simulation/WallType.h25
-rw-r--r--src/simulation/elements/116.cpp49
-rw-r--r--src/simulation/elements/146.cpp49
-rw-r--r--src/simulation/elements/ACEL.cpp85
-rw-r--r--src/simulation/elements/ACID.cpp144
-rw-r--r--src/simulation/elements/AMTR.cpp79
-rw-r--r--src/simulation/elements/ANAR.cpp78
-rw-r--r--src/simulation/elements/ARAY.cpp154
-rw-r--r--src/simulation/elements/BANG.cpp131
-rw-r--r--src/simulation/elements/BCLN.cpp99
-rw-r--r--src/simulation/elements/BCOL.cpp146
-rw-r--r--src/simulation/elements/BGLA.cpp49
-rw-r--r--src/simulation/elements/BHOL.cpp49
-rw-r--r--src/simulation/elements/BIZR.cpp124
-rw-r--r--src/simulation/elements/BIZRG.cpp124
-rw-r--r--src/simulation/elements/BIZRS.cpp124
-rw-r--r--src/simulation/elements/BMTL.cpp80
-rw-r--r--src/simulation/elements/BOMB.cpp113
-rw-r--r--src/simulation/elements/BOYL.cpp94
-rw-r--r--src/simulation/elements/BRAY.cpp109
-rw-r--r--src/simulation/elements/BRCK.cpp65
-rw-r--r--src/simulation/elements/BREC.cpp64
-rw-r--r--src/simulation/elements/BRMT.cpp85
-rw-r--r--src/simulation/elements/BTRY.cpp75
-rw-r--r--src/simulation/elements/BVBR.cpp50
-rw-r--r--src/simulation/elements/C5.cpp75
-rw-r--r--src/simulation/elements/CAUS.cpp86
-rw-r--r--src/simulation/elements/CBNW.cpp153
-rw-r--r--src/simulation/elements/CLNE.cpp91
-rw-r--r--src/simulation/elements/CLST.cpp101
-rw-r--r--src/simulation/elements/CNCT.cpp49
-rw-r--r--src/simulation/elements/CO2.cpp106
-rw-r--r--src/simulation/elements/COAL.cpp153
-rw-r--r--src/simulation/elements/CONV.cpp96
-rw-r--r--src/simulation/elements/DESL.cpp49
-rw-r--r--src/simulation/elements/DEST.cpp121
-rw-r--r--src/simulation/elements/DEUT.cpp149
-rw-r--r--src/simulation/elements/DLAY.cpp111
-rw-r--r--src/simulation/elements/DMG.cpp118
-rw-r--r--src/simulation/elements/DMND.cpp49
-rw-r--r--src/simulation/elements/DRIC.cpp49
-rw-r--r--src/simulation/elements/DSTW.cpp92
-rw-r--r--src/simulation/elements/DTEC.cpp99
-rw-r--r--src/simulation/elements/DUST.cpp49
-rw-r--r--src/simulation/elements/DYST.cpp49
-rw-r--r--src/simulation/elements/ELEC.cpp160
-rw-r--r--src/simulation/elements/EMBR.cpp126
-rw-r--r--src/simulation/elements/EMP.cpp183
-rw-r--r--src/simulation/elements/ETRD.cpp49
-rw-r--r--src/simulation/elements/EXOT.cpp211
-rw-r--r--src/simulation/elements/Element.cpp225
-rw-r--r--src/simulation/elements/Element.h63
-rw-r--r--src/simulation/elements/FIGH.cpp140
-rw-r--r--src/simulation/elements/FILT.cpp77
-rw-r--r--src/simulation/elements/FIRE.cpp201
-rw-r--r--src/simulation/elements/FIRW.cpp134
-rw-r--r--src/simulation/elements/FOG.cpp73
-rw-r--r--src/simulation/elements/FRAY.cpp80
-rw-r--r--src/simulation/elements/FRZW.cpp81
-rw-r--r--src/simulation/elements/FRZZ.cpp76
-rw-r--r--src/simulation/elements/FSEP.cpp86
-rw-r--r--src/simulation/elements/FUSE.cpp92
-rw-r--r--src/simulation/elements/FWRK.cpp120
-rw-r--r--src/simulation/elements/GAS.cpp49
-rw-r--r--src/simulation/elements/GBMB.cpp93
-rw-r--r--src/simulation/elements/GEL.cpp155
-rw-r--r--src/simulation/elements/GLAS.cpp62
-rw-r--r--src/simulation/elements/GLOW.cpp96
-rw-r--r--src/simulation/elements/GOO.cpp64
-rw-r--r--src/simulation/elements/GPMP.cpp94
-rw-r--r--src/simulation/elements/GRAV.cpp111
-rw-r--r--src/simulation/elements/GUNP.cpp49
-rw-r--r--src/simulation/elements/H2.cpp124
-rw-r--r--src/simulation/elements/HFLM.cpp75
-rw-r--r--src/simulation/elements/HSWC.cpp87
-rw-r--r--src/simulation/elements/ICEI.cpp76
-rw-r--r--src/simulation/elements/IGNT.cpp95
-rw-r--r--src/simulation/elements/INSL.cpp49
-rw-r--r--src/simulation/elements/INST.cpp49
-rw-r--r--src/simulation/elements/INVIS.cpp75
-rw-r--r--src/simulation/elements/INWR.cpp49
-rw-r--r--src/simulation/elements/IRON.cpp76
-rw-r--r--src/simulation/elements/ISOZ.cpp65
-rw-r--r--src/simulation/elements/ISZS.cpp65
-rw-r--r--src/simulation/elements/LAVA.cpp71
-rw-r--r--src/simulation/elements/LCRY.cpp154
-rw-r--r--src/simulation/elements/LIFE.cpp125
-rw-r--r--src/simulation/elements/LIGH.cpp359
-rw-r--r--src/simulation/elements/LNTG.cpp49
-rw-r--r--src/simulation/elements/LO2.cpp49
-rw-r--r--src/simulation/elements/LOLZ.cpp71
-rw-r--r--src/simulation/elements/LOVE.cpp71
-rw-r--r--src/simulation/elements/LRBD.cpp49
-rw-r--r--src/simulation/elements/MERC.cpp121
-rw-r--r--src/simulation/elements/METL.cpp49
-rw-r--r--src/simulation/elements/MORT.cpp57
-rw-r--r--src/simulation/elements/MWAX.cpp49
-rw-r--r--src/simulation/elements/NBHL.cpp60
-rw-r--r--src/simulation/elements/NBLE.cpp93
-rw-r--r--src/simulation/elements/NEUT.cpp207
-rw-r--r--src/simulation/elements/NICE.cpp49
-rw-r--r--src/simulation/elements/NITR.cpp49
-rw-r--r--src/simulation/elements/NONE.cpp66
-rw-r--r--src/simulation/elements/NSCN.cpp49
-rw-r--r--src/simulation/elements/NTCT.cpp58
-rw-r--r--src/simulation/elements/NWHL.cpp57
-rw-r--r--src/simulation/elements/O2.cpp104
-rw-r--r--src/simulation/elements/OIL.cpp49
-rw-r--r--src/simulation/elements/PBCN.cpp164
-rw-r--r--src/simulation/elements/PCLN.cpp154
-rw-r--r--src/simulation/elements/PHOT.cpp141
-rw-r--r--src/simulation/elements/PIPE.cpp516
-rw-r--r--src/simulation/elements/PLEX.cpp49
-rw-r--r--src/simulation/elements/PLNT.cpp126
-rw-r--r--src/simulation/elements/PLSM.cpp70
-rw-r--r--src/simulation/elements/PLUT.cpp60
-rw-r--r--src/simulation/elements/PPIP.cpp160
-rw-r--r--src/simulation/elements/PQRT.cpp168
-rw-r--r--src/simulation/elements/PRTI.cpp140
-rw-r--r--src/simulation/elements/PRTO.cpp177
-rw-r--r--src/simulation/elements/PSCN.cpp49
-rw-r--r--src/simulation/elements/PSTE.cpp49
-rw-r--r--src/simulation/elements/PSTS.cpp49
-rw-r--r--src/simulation/elements/PTCT.cpp58
-rw-r--r--src/simulation/elements/PUMP.cpp98
-rw-r--r--src/simulation/elements/PVOD.cpp91
-rw-r--r--src/simulation/elements/QRTZ.cpp168
-rw-r--r--src/simulation/elements/RBDM.cpp49
-rw-r--r--src/simulation/elements/REPL.cpp73
-rw-r--r--src/simulation/elements/RIME.cpp77
-rw-r--r--src/simulation/elements/SALT.cpp49
-rw-r--r--src/simulation/elements/SAND.cpp49
-rw-r--r--src/simulation/elements/SHLD1.cpp88
-rw-r--r--src/simulation/elements/SHLD2.cpp91
-rw-r--r--src/simulation/elements/SHLD3.cpp101
-rw-r--r--src/simulation/elements/SHLD4.cpp92
-rw-r--r--src/simulation/elements/SING.cpp155
-rw-r--r--src/simulation/elements/SLTW.cpp81
-rw-r--r--src/simulation/elements/SMKE.cpp68
-rw-r--r--src/simulation/elements/SNOW.cpp74
-rw-r--r--src/simulation/elements/SOAP.cpp291
-rw-r--r--src/simulation/elements/SPAWN.cpp60
-rw-r--r--src/simulation/elements/SPAWN2.cpp60
-rw-r--r--src/simulation/elements/SPNG.cpp198
-rw-r--r--src/simulation/elements/SPRK.cpp290
-rw-r--r--src/simulation/elements/STKM.cpp557
-rw-r--r--src/simulation/elements/STKM2.cpp56
-rw-r--r--src/simulation/elements/STNE.cpp49
-rw-r--r--src/simulation/elements/STOR.cpp112
-rw-r--r--src/simulation/elements/SWCH.cpp113
-rw-r--r--src/simulation/elements/TESC.cpp49
-rw-r--r--src/simulation/elements/THDR.cpp102
-rw-r--r--src/simulation/elements/THRM.cpp80
-rw-r--r--src/simulation/elements/TRON.cpp236
-rw-r--r--src/simulation/elements/TSNS.cpp93
-rw-r--r--src/simulation/elements/TTAN.cpp76
-rw-r--r--src/simulation/elements/URAN.cpp61
-rw-r--r--src/simulation/elements/VIBR.cpp235
-rw-r--r--src/simulation/elements/VINE.cpp91
-rw-r--r--src/simulation/elements/VOID.cpp49
-rw-r--r--src/simulation/elements/WARP.cpp95
-rw-r--r--src/simulation/elements/WATR.cpp89
-rw-r--r--src/simulation/elements/WAX.cpp49
-rw-r--r--src/simulation/elements/WHOL.cpp49
-rw-r--r--src/simulation/elements/WIFI.cpp101
-rw-r--r--src/simulation/elements/WIRE.cpp127
-rw-r--r--src/simulation/elements/WOOD.cpp70
-rw-r--r--src/simulation/elements/WTRV.cpp73
-rw-r--r--src/simulation/elements/YEST.cpp72
-rw-r--r--src/simulation/elements/dcel.cpp85
-rw-r--r--src/simulation/tools/AirTool.cpp22
-rw-r--r--src/simulation/tools/Cool.cpp23
-rw-r--r--src/simulation/tools/GravTool.cpp18
-rw-r--r--src/simulation/tools/Heat.cpp23
-rw-r--r--src/simulation/tools/NGrv.cpp18
-rw-r--r--src/simulation/tools/SimTool.cpp10
-rw-r--r--src/simulation/tools/SimTool.h23
-rw-r--r--src/simulation/tools/Vac.cpp22
203 files changed, 24763 insertions, 0 deletions
diff --git a/src/simulation/Air.cpp b/src/simulation/Air.cpp
new file mode 100644
index 0000000..10c4569
--- /dev/null
+++ b/src/simulation/Air.cpp
@@ -0,0 +1,321 @@
+#include <cmath>
+#include <algorithm>
+#include "Config.h"
+#include "Air.h"
+#include "Simulation.h"
+//#include <powder.h>
+//#include <defines.h>
+#include "Gravity.h"
+
+/*float kernel[9];
+
+float vx[YRES/CELL][XRES/CELL], ovx[YRES/CELL][XRES/CELL];
+float vy[YRES/CELL][XRES/CELL], ovy[YRES/CELL][XRES/CELL];
+float pv[YRES/CELL][XRES/CELL], opv[YRES/CELL][XRES/CELL];
+unsigned char bmap_blockair[YRES/CELL][XRES/CELL];
+
+float cb_vx[YRES/CELL][XRES/CELL];
+float cb_vy[YRES/CELL][XRES/CELL];
+float cb_pv[YRES/CELL][XRES/CELL];
+float cb_hv[YRES/CELL][XRES/CELL];
+
+float fvx[YRES/CELL][XRES/CELL], fvy[YRES/CELL][XRES/CELL];
+
+float hv[YRES/CELL][XRES/CELL], ohv[YRES/CELL][XRES/CELL]; // For Ambient Heat */
+
+void Air::make_kernel(void) //used for velocity
+{
+ int i, j;
+ float s = 0.0f;
+ for (j=-1; j<2; j++)
+ for (i=-1; i<2; i++)
+ {
+ kernel[(i+1)+3*(j+1)] = expf(-2.0f*(i*i+j*j));
+ s += kernel[(i+1)+3*(j+1)];
+ }
+ s = 1.0f / s;
+ for (j=-1; j<2; j++)
+ for (i=-1; i<2; i++)
+ kernel[(i+1)+3*(j+1)] *= s;
+}
+
+void Air::Clear()
+{
+ std::fill(&hv[0][0], &hv[0][0]+((XRES/CELL)*(YRES/CELL)), 273.15f + 22.0f);
+ std::fill(&pv[0][0], &pv[0][0]+((XRES/CELL)*(YRES/CELL)), 0.0f);
+ std::fill(&vy[0][0], &vy[0][0]+((XRES/CELL)*(YRES/CELL)), 0.0f);
+ std::fill(&vx[0][0], &vx[0][0]+((XRES/CELL)*(YRES/CELL)), 0.0f);
+}
+
+void Air::update_airh(void)
+{
+ int x, y, i, j;
+ float odh, dh, dx, dy, f, tx, ty;
+ for (i=0; i<YRES/CELL; i++) //reduces pressure/velocity on the edges every frame
+ {
+ hv[i][0] = 295.15f;
+ hv[i][1] = 295.15f;
+ hv[i][XRES/CELL-3] = 295.15f;
+ hv[i][XRES/CELL-2] = 295.15f;
+ hv[i][XRES/CELL-1] = 295.15f;
+ }
+ for (i=0; i<XRES/CELL; i++) //reduces pressure/velocity on the edges every frame
+ {
+ hv[0][i] = 295.15f;
+ hv[1][i] = 295.15f;
+ hv[YRES/CELL-3][i] = 295.15f;
+ hv[YRES/CELL-2][i] = 295.15f;
+ hv[YRES/CELL-1][i] = 295.15f;
+ }
+ for (y=0; y<YRES/CELL; y++) //update velocity and pressure
+ {
+ for (x=0; x<XRES/CELL; x++)
+ {
+ dh = 0.0f;
+ dx = 0.0f;
+ dy = 0.0f;
+ for (j=-1; j<2; j++)
+ {
+ for (i=-1; i<2; i++)
+ {
+ if (y+j>0 && y+j<YRES/CELL-2 &&
+ x+i>0 && x+i<XRES/CELL-2 &&
+ !bmap_blockairh[y+j][x+i])
+ {
+ f = kernel[i+1+(j+1)*3];
+ dh += hv[y+j][x+i]*f;
+ dx += vx[y+j][x+i]*f;
+ dy += vy[y+j][x+i]*f;
+ }
+ else
+ {
+ f = kernel[i+1+(j+1)*3];
+ dh += hv[y][x]*f;
+ dx += vx[y][x]*f;
+ dy += vy[y][x]*f;
+ }
+ }
+ }
+ tx = x - dx*0.7f;
+ ty = y - dy*0.7f;
+ i = (int)tx;
+ j = (int)ty;
+ tx -= i;
+ ty -= j;
+ if (i>=2 && i<XRES/CELL-3 && j>=2 && j<YRES/CELL-3)
+ {
+ odh = dh;
+ dh *= 1.0f - AIR_VADV;
+ dh += AIR_VADV*(1.0f-tx)*(1.0f-ty)*(bmap_blockairh[j][i] ? odh : hv[j][i]);
+ dh += AIR_VADV*tx*(1.0f-ty)*(bmap_blockairh[j][i+1] ? odh : hv[j][i+1]);
+ dh += AIR_VADV*(1.0f-tx)*ty*(bmap_blockairh[j+1][i] ? odh : hv[j+1][i]);
+ dh += AIR_VADV*tx*ty*(bmap_blockairh[j+1][i+1] ? odh : hv[j+1][i+1]);
+ }
+ if(!sim.gravityMode)
+ { //Vertical gravity only for the time being
+ float airdiff = hv[y-1][x]-hv[y][x];
+ if(airdiff>0 && !bmap_blockairh[y-1][x])
+ vy[y][x] -= airdiff/5000.0f;
+ }
+ ohv[y][x] = dh;
+ }
+ }
+ memcpy(hv, ohv, sizeof(hv));
+}
+
+void Air::update_air(void)
+{
+ int x = 0, y = 0, i = 0, j = 0;
+ float dp = 0.0f, dx = 0.0f, dy = 0.0f, f = 0.0f, tx = 0.0f, ty = 0.0f;
+
+ if (airMode != 4) { //airMode 4 is no air/pressure update
+
+ for (i=0; i<YRES/CELL; i++) //reduces pressure/velocity on the edges every frame
+ {
+ pv[i][0] = pv[i][0]*0.8f;
+ pv[i][1] = pv[i][1]*0.8f;
+ pv[i][2] = pv[i][2]*0.8f;
+ pv[i][XRES/CELL-2] = pv[i][XRES/CELL-2]*0.8f;
+ pv[i][XRES/CELL-1] = pv[i][XRES/CELL-1]*0.8f;
+ vx[i][0] = vx[i][1]*0.9f;
+ vx[i][1] = vx[i][2]*0.9f;
+ vx[i][XRES/CELL-2] = vx[i][XRES/CELL-3]*0.9f;
+ vx[i][XRES/CELL-1] = vx[i][XRES/CELL-2]*0.9f;
+ vy[i][0] = vy[i][1]*0.9f;
+ vy[i][1] = vy[i][2]*0.9f;
+ vy[i][XRES/CELL-2] = vy[i][XRES/CELL-3]*0.9f;
+ vy[i][XRES/CELL-1] = vy[i][XRES/CELL-2]*0.9f;
+ }
+ for (i=0; i<XRES/CELL; i++) //reduces pressure/velocity on the edges every frame
+ {
+ pv[0][i] = pv[0][i]*0.8f;
+ pv[1][i] = pv[1][i]*0.8f;
+ pv[2][i] = pv[2][i]*0.8f;
+ pv[YRES/CELL-2][i] = pv[YRES/CELL-2][i]*0.8f;
+ pv[YRES/CELL-1][i] = pv[YRES/CELL-1][i]*0.8f;
+ vx[0][i] = vx[1][i]*0.9f;
+ vx[1][i] = vx[2][i]*0.9f;
+ vx[YRES/CELL-2][i] = vx[YRES/CELL-3][i]*0.9f;
+ vx[YRES/CELL-1][i] = vx[YRES/CELL-2][i]*0.9f;
+ vy[0][i] = vy[1][i]*0.9f;
+ vy[1][i] = vy[2][i]*0.9f;
+ vy[YRES/CELL-2][i] = vy[YRES/CELL-3][i]*0.9f;
+ vy[YRES/CELL-1][i] = vy[YRES/CELL-2][i]*0.9f;
+ }
+
+ for (j=1; j<YRES/CELL; j++) //clear some velocities near walls
+ {
+ for (i=1; i<XRES/CELL; i++)
+ {
+ if (bmap_blockair[j][i])
+ {
+ vx[j][i] = 0.0f;
+ vx[j][i-1] = 0.0f;
+ vy[j][i] = 0.0f;
+ vy[j-1][i] = 0.0f;
+ }
+ }
+ }
+
+ for (y=1; y<YRES/CELL; y++) //pressure adjustments from velocity
+ for (x=1; x<XRES/CELL; x++)
+ {
+ dp = 0.0f;
+ dp += vx[y][x-1] - vx[y][x];
+ dp += vy[y-1][x] - vy[y][x];
+ pv[y][x] *= AIR_PLOSS;
+ pv[y][x] += dp*AIR_TSTEPP;
+ }
+
+ for (y=0; y<YRES/CELL-1; y++) //velocity adjustments from pressure
+ for (x=0; x<XRES/CELL-1; x++)
+ {
+ dx = dy = 0.0f;
+ dx += pv[y][x] - pv[y][x+1];
+ dy += pv[y][x] - pv[y+1][x];
+ vx[y][x] *= AIR_VLOSS;
+ vy[y][x] *= AIR_VLOSS;
+ vx[y][x] += dx*AIR_TSTEPV;
+ vy[y][x] += dy*AIR_TSTEPV;
+ if (bmap_blockair[y][x] || bmap_blockair[y][x+1])
+ vx[y][x] = 0;
+ if (bmap_blockair[y][x] || bmap_blockair[y+1][x])
+ vy[y][x] = 0;
+ }
+
+ for (y=0; y<YRES/CELL; y++) //update velocity and pressure
+ for (x=0; x<XRES/CELL; x++)
+ {
+ dx = 0.0f;
+ dy = 0.0f;
+ dp = 0.0f;
+ for (j=-1; j<2; j++)
+ for (i=-1; i<2; i++)
+ if (y+j>0 && y+j<YRES/CELL-1 &&
+ x+i>0 && x+i<XRES/CELL-1 &&
+ !bmap_blockair[y+j][x+i])
+ {
+ f = kernel[i+1+(j+1)*3];
+ dx += vx[y+j][x+i]*f;
+ dy += vy[y+j][x+i]*f;
+ dp += pv[y+j][x+i]*f;
+ }
+ else
+ {
+ f = kernel[i+1+(j+1)*3];
+ dx += vx[y][x]*f;
+ dy += vy[y][x]*f;
+ dp += pv[y][x]*f;
+ }
+
+ tx = x - dx*0.7f;
+ ty = y - dy*0.7f;
+ i = (int)tx;
+ j = (int)ty;
+ tx -= i;
+ ty -= j;
+ if (i>=2 && i<XRES/CELL-3 &&
+ j>=2 && j<YRES/CELL-3)
+ {
+ dx *= 1.0f - AIR_VADV;
+ dy *= 1.0f - AIR_VADV;
+
+ dx += AIR_VADV*(1.0f-tx)*(1.0f-ty)*vx[j][i];
+ dy += AIR_VADV*(1.0f-tx)*(1.0f-ty)*vy[j][i];
+
+ dx += AIR_VADV*tx*(1.0f-ty)*vx[j][i+1];
+ dy += AIR_VADV*tx*(1.0f-ty)*vy[j][i+1];
+
+ dx += AIR_VADV*(1.0f-tx)*ty*vx[j+1][i];
+ dy += AIR_VADV*(1.0f-tx)*ty*vy[j+1][i];
+
+ dx += AIR_VADV*tx*ty*vx[j+1][i+1];
+ dy += AIR_VADV*tx*ty*vy[j+1][i+1];
+ }
+
+ if (bmap[y][x] == WL_FAN)
+ {
+ dx += fvx[y][x];
+ dy += fvy[y][x];
+ }
+ // pressure/velocity caps
+ if (dp > 256.0f) dp = 256.0f;
+ if (dp < -256.0f) dp = -256.0f;
+ if (dx > 256.0f) dx = 256.0f;
+ if (dx < -256.0f) dx = -256.0f;
+ if (dy > 256.0f) dy = 256.0f;
+ if (dy < -256.0f) dy = -256.0f;
+
+
+ switch (airMode)
+ {
+ default:
+ case 0: //Default
+ break;
+ case 1: //0 Pressure
+ dp = 0.0f;
+ break;
+ case 2: //0 Velocity
+ dx = 0.0f;
+ dy = 0.0f;
+ break;
+ case 3: //0 Air
+ dx = 0.0f;
+ dy = 0.0f;
+ dp = 0.0f;
+ break;
+ case 4: //No Update
+ break;
+ }
+
+ ovx[y][x] = dx;
+ ovy[y][x] = dy;
+ opv[y][x] = dp;
+ }
+ memcpy(vx, ovx, sizeof(vx));
+ memcpy(vy, ovy, sizeof(vy));
+ memcpy(pv, opv, sizeof(pv));
+ }
+}
+
+void Air::Invert()
+{
+ int nx, ny;
+ for (nx = 0; nx<XRES/CELL; nx++)
+ for (ny = 0; ny<YRES/CELL; ny++)
+ {
+ pv[ny][nx] = -pv[ny][nx];
+ vx[ny][nx] = -vx[ny][nx];
+ vy[ny][nx] = -vy[ny][nx];
+ }
+}
+
+Air::Air(Simulation & simulation):
+ airMode(0),
+ sim(simulation)
+{
+ //Simulation should do this.
+ make_kernel();
+
+
+}
diff --git a/src/simulation/Air.h b/src/simulation/Air.h
new file mode 100644
index 0000000..936f54b
--- /dev/null
+++ b/src/simulation/Air.h
@@ -0,0 +1,37 @@
+#ifndef AIR_H
+#define AIR_H
+#include "Config.h"
+
+class Simulation;
+
+class Air
+{
+public:
+ Simulation & sim;
+ int airMode;
+ //Arrays from the simulation
+ unsigned char (*bmap)[XRES/CELL];
+ unsigned char (*emap)[XRES/CELL];
+ float (*fvx)[XRES/CELL];
+ float (*fvy)[XRES/CELL];
+ //
+ float vx[YRES/CELL][XRES/CELL];
+ float ovx[YRES/CELL][XRES/CELL];
+ float vy[YRES/CELL][XRES/CELL];
+ float ovy[YRES/CELL][XRES/CELL];
+ float pv[YRES/CELL][XRES/CELL];
+ float opv[YRES/CELL][XRES/CELL];
+ float hv[YRES/CELL][XRES/CELL];
+ float ohv[YRES/CELL][XRES/CELL]; // Ambient Heat
+ unsigned char bmap_blockair[YRES/CELL][XRES/CELL];
+ unsigned char bmap_blockairh[YRES/CELL][XRES/CELL];
+ float kernel[9];
+ void make_kernel(void);
+ void update_airh(void);
+ void update_air(void);
+ void Clear();
+ void Invert();
+ Air(Simulation & sim);
+};
+
+#endif
diff --git a/src/simulation/Element.h b/src/simulation/Element.h
new file mode 100644
index 0000000..3c28e2f
--- /dev/null
+++ b/src/simulation/Element.h
@@ -0,0 +1,23 @@
+#ifndef ELEMENT_H
+#define ELEMENT_H
+// This header should be included by all files in src/elements/
+
+#include <cmath>
+#include "Simulation.h"
+#include "graphics/Renderer.h"
+#include "Gravity.h"
+#include "Misc.h"
+#include "ElementGraphics.h"
+
+#define IPL -257.0f
+#define IPH 257.0f
+#define ITL MIN_TEMP-1
+#define ITH MAX_TEMP+1
+
+// no transition (PT_NONE means kill part)
+#define NT -1
+
+// special transition - lava ctypes etc need extra code, which is only found and run if ST is given
+#define ST PT_NUM
+
+#endif
diff --git a/src/simulation/ElementGraphics.h b/src/simulation/ElementGraphics.h
new file mode 100644
index 0000000..0f3723c
--- /dev/null
+++ b/src/simulation/ElementGraphics.h
@@ -0,0 +1,55 @@
+#ifndef PGRAPHICS_H
+#define PGRAPHICS_H
+
+#define PMODE 0x00000FFF
+#define PMODE_NONE 0x00000000
+#define PMODE_FLAT 0x00000001
+#define PMODE_BLOB 0x00000002
+#define PMODE_BLUR 0x00000004
+#define PMODE_GLOW 0x00000008
+#define PMODE_SPARK 0x00000010
+#define PMODE_FLARE 0x00000020
+#define PMODE_LFLARE 0x00000040
+#define PMODE_ADD 0x00000080
+#define PMODE_BLEND 0x00000100
+#define PSPEC_STICKMAN 0x00000200
+
+#define OPTIONS 0x0000F000
+#define NO_DECO 0x00001000
+#define DECO_FIRE 0x00002000
+
+#define FIREMODE 0x00FF0000
+#define FIRE_ADD 0x00010000
+#define FIRE_BLEND 0x00020000
+
+#define EFFECT 0xFF000000
+#define EFFECT_GRAVIN 0x01000000
+#define EFFECT_GRAVOUT 0x02000000
+#define EFFECT_LINES 0x04000000
+#define EFFECT_DBGLINES 0x08000000
+
+#define RENDER_EFFE OPTIONS | PSPEC_STICKMAN | EFFECT | PMODE_SPARK | PMODE_FLARE | PMODE_LFLARE
+#define RENDER_FIRE OPTIONS | PSPEC_STICKMAN | /*PMODE_FLAT |*/ PMODE_ADD | PMODE_BLEND | FIREMODE
+#define RENDER_GLOW OPTIONS | PSPEC_STICKMAN | /*PMODE_FLAT |*/ PMODE_GLOW | PMODE_ADD | PMODE_BLEND
+#define RENDER_BLUR OPTIONS | PSPEC_STICKMAN | /*PMODE_FLAT |*/ PMODE_BLUR | PMODE_ADD | PMODE_BLEND
+#define RENDER_BLOB OPTIONS | PSPEC_STICKMAN | /*PMODE_FLAT |*/ PMODE_BLOB | PMODE_ADD | PMODE_BLEND
+#define RENDER_BASC OPTIONS | PSPEC_STICKMAN | PMODE_FLAT | PMODE_ADD | PMODE_BLEND
+#define RENDER_NONE OPTIONS | PSPEC_STICKMAN | PMODE_FLAT
+
+#define COLOUR_HEAT 0x00000001
+#define COLOUR_LIFE 0x00000002
+#define COLOUR_GRAD 0x00000004
+#define COLOUR_BASC 0x00000008
+
+#define COLOUR_DEFAULT 0x00000000
+
+#define DISPLAY_AIRC 0x00000001
+#define DISPLAY_AIRP 0x00000002
+#define DISPLAY_AIRV 0x00000004
+#define DISPLAY_AIRH 0x00000008
+#define DISPLAY_AIR 0x0000000F
+#define DISPLAY_WARP 0x00000010
+#define DISPLAY_PERS 0x00000020
+#define DISPLAY_EFFE 0x00000040
+
+#endif
diff --git a/src/simulation/Elements.h b/src/simulation/Elements.h
new file mode 100644
index 0000000..781a8f8
--- /dev/null
+++ b/src/simulation/Elements.h
@@ -0,0 +1,100 @@
+/*
+ * Elements.h
+ *
+ * Created on: Jan 5, 2012
+ * Author: Simon
+ */
+
+#ifndef ELEMENTS_H_
+#define ELEMENTS_H_
+
+//#include "Config.h"
+//#include "Simulation.h"
+
+#define R_TEMP 22
+#define MAX_TEMP 9999
+#define MIN_TEMP 0
+#define O_MAX_TEMP 3500
+#define O_MIN_TEMP -273
+
+#define TYPE_PART 0x00001 //1 Powders
+#define TYPE_LIQUID 0x00002 //2 Liquids
+#define TYPE_SOLID 0x00004 //4 Solids
+#define TYPE_GAS 0x00008 //8 Gasses (Includes plasma)
+#define TYPE_ENERGY 0x00010 //16 Energy (Thunder, Light, Neutrons etc.)
+#define PROP_CONDUCTS 0x00020 //32 Conducts electricity
+#define PROP_BLACK 0x00040 //64 Absorbs Photons (not currently implemented or used, a photwl attribute might be better)
+#define PROP_NEUTPENETRATE 0x00080 //128 Penetrated by neutrons
+#define PROP_NEUTABSORB 0x00100 //256 Absorbs neutrons, reflect is default
+#define PROP_NEUTPASS 0x00200 //512 Neutrons pass through, such as with glass
+#define PROP_DEADLY 0x00400 //1024 Is deadly for stickman
+#define PROP_HOT_GLOW 0x00800 //2048 Hot Metal Glow
+#define PROP_LIFE 0x01000 //4096 Is a GoL type
+#define PROP_RADIOACTIVE 0x02000 //8192 Radioactive
+#define PROP_LIFE_DEC 0x04000 //2^14 Life decreases by one every frame if > zero
+#define PROP_LIFE_KILL 0x08000 //2^15 Kill when life value is <= zero
+#define PROP_LIFE_KILL_DEC 0x10000 //2^16 Kill when life value is decremented to <= zero
+#define PROP_SPARKSETTLE 0x20000 //2^17 Allow Sparks/Embers to settle
+#define PROP_NOAMBHEAT 0x40000 //2^18 Don't transfer or receive heat from ambient heat.
+
+#define FLAG_STAGNANT 1
+#define FLAG_SKIPMOVE 0x2 // skip movement for one frame, only implemented for PHOT
+#define FLAG_MOVABLE 0x4 // if can move
+
+#define ST_NONE 0
+#define ST_SOLID 1
+#define ST_LIQUID 2
+#define ST_GAS 3
+
+#define UPDATE_FUNC_ARGS Simulation* sim, int i, int x, int y, int surround_space, int nt, Particle *parts, int pmap[YRES][XRES]
+#define UPDATE_FUNC_SUBCALL_ARGS sim, i, x, y, surround_space, nt, parts, pmap
+
+#define GRAPHICS_FUNC_ARGS Renderer * ren, Particle *cpart, int nx, int ny, int *pixel_mode, int* cola, int *colr, int *colg, int *colb, int *firea, int *firer, int *fireg, int *fireb
+#define GRAPHICS_FUNC_SUBCALL_ARGS ren, cpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb
+
+#define SPC_AIR 236
+#define SPC_HEAT 237
+#define SPC_COOL 238
+#define SPC_VACUUM 239
+#define SPC_WIND 241
+#define SPC_PGRV 243
+#define SPC_NGRV 244
+#define SPC_PROP 246
+
+
+#define NGT_GOL 0
+#define NGT_HLIF 1
+#define NGT_ASIM 2
+#define NGT_2x2 3
+#define NGT_DANI 4
+#define NGT_AMOE 5
+#define NGT_MOVE 6
+#define NGT_PGOL 7
+#define NGT_DMOE 8
+#define NGT_34 9
+#define NGT_LLIF 10
+#define NGT_STAN 11
+#define NGT_SEED 12
+#define NGT_MAZE 13
+#define NGT_COAG 14
+#define NGT_WALL 15
+#define NGT_GNAR 16
+#define NGT_REPL 17
+#define NGT_MYST 18
+#define NGT_LOTE 19
+#define NGT_FRG2 20
+#define NGT_STAR 21
+#define NGT_FROG 22
+#define NGT_BRAN 23
+
+#define OLD_PT_WIND 147
+
+//#define PT_NUM 161
+#define PT_NUM 256
+
+struct playerst;
+
+#include "ElementClasses.h"
+
+
+#endif /* ELEMENTS_H_ */
diff --git a/src/simulation/GOLMenu.h b/src/simulation/GOLMenu.h
new file mode 100644
index 0000000..36bb5dd
--- /dev/null
+++ b/src/simulation/GOLMenu.h
@@ -0,0 +1,20 @@
+//
+// GOLMenu.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_GOLMenu_h
+#define The_Powder_Toy_GOLMenu_h
+
+struct gol_menu
+{
+ const char *name;
+ pixel colour;
+ int goltype;
+ const char *description;
+};
+
+#endif
diff --git a/src/simulation/Gravity.cpp b/src/simulation/Gravity.cpp
new file mode 100644
index 0000000..552c02d
--- /dev/null
+++ b/src/simulation/Gravity.cpp
@@ -0,0 +1,527 @@
+#include <cmath>
+#include <sys/types.h>
+#include <pthread.h>
+#undef GetUserName //God dammit microsoft!
+#include "Config.h"
+#include "Gravity.h"
+//#include "powder.h"
+
+void Gravity::bilinear_interpolation(float *src, float *dst, int sw, int sh, int rw, int rh)
+{
+ int y, x, fxceil, fyceil;
+ float fx, fy, fyc, fxc;
+ double intp;
+ float tr, tl, br, bl;
+ //Bilinear interpolation for upscaling
+ for (y=0; y<rh; y++)
+ for (x=0; x<rw; x++)
+ {
+ fx = ((float)x)*((float)sw)/((float)rw);
+ fy = ((float)y)*((float)sh)/((float)rh);
+ fxc = modf(fx, &intp);
+ fyc = modf(fy, &intp);
+ fxceil = (int)ceil(fx);
+ fyceil = (int)ceil(fy);
+ if (fxceil>=sw) fxceil = sw-1;
+ if (fyceil>=sh) fyceil = sh-1;
+ tr = src[sw*(int)floor(fy)+fxceil];
+ tl = src[sw*(int)floor(fy)+(int)floor(fx)];
+ br = src[sw*fyceil+fxceil];
+ bl = src[sw*fyceil+(int)floor(fx)];
+ dst[rw*y+x] = ((tl*(1.0f-fxc))+(tr*(fxc)))*(1.0f-fyc) + ((bl*(1.0f-fxc))+(br*(fxc)))*(fyc);
+ }
+}
+
+void Gravity::Clear()
+{
+ std::fill(gravy, gravy+((XRES/CELL)*(YRES/CELL)), 0.0f);
+ std::fill(gravx, gravx+((XRES/CELL)*(YRES/CELL)), 0.0f);
+ std::fill(gravp, gravp+((XRES/CELL)*(YRES/CELL)), 0.0f);
+ std::fill(gravmap, gravmap+((XRES/CELL)*(YRES/CELL)), 0.0f);
+ std::fill(gravmask, gravmask+((XRES/CELL)*(YRES/CELL)), 0xFFFFFFFF);
+}
+
+void Gravity::gravity_init()
+{
+ ngrav_enable = 0;
+ //Allocate full size Gravmaps
+ th_ogravmap = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ th_gravmap = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ th_gravy = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ th_gravx = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ th_gravp = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ gravmap = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ gravy = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ gravx = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ gravp = (float *)calloc((XRES/CELL)*(YRES/CELL), sizeof(float));
+ gravmask = (unsigned int *)calloc((XRES/CELL)*(YRES/CELL), sizeof(unsigned));
+}
+
+void Gravity::gravity_cleanup()
+{
+#ifdef GRAVFFT
+ grav_fft_cleanup();
+#endif
+ //Free gravity info
+ free(th_ogravmap);
+ free(th_gravmap);
+ free(th_gravy);
+ free(th_gravx);
+ free(th_gravp);
+ free(gravmap);
+ free(gravy);
+ free(gravx);
+ free(gravp);
+ free(gravmask);
+}
+
+void Gravity::gravity_update_async()
+{
+ int result;
+ if(ngrav_enable)
+ {
+ pthread_mutex_lock(&gravmutex);
+ result = grav_ready;
+ if(result) //Did the gravity thread finish?
+ {
+ //if (!sys_pause||framerender){ //Only update if not paused
+ //Switch the full size gravmaps, we don't really need the two above any more
+ float *tmpf;
+
+ if(th_gravchanged)
+ {
+ #if !defined(GRAVFFT) && defined(GRAV_DIFF)
+ memcpy(gravy, th_gravy, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memcpy(gravx, th_gravx, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memcpy(gravp, th_gravp, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ #else
+ tmpf = gravy;
+ gravy = th_gravy;
+ th_gravy = tmpf;
+
+ tmpf = gravx;
+ gravx = th_gravx;
+ th_gravx = tmpf;
+
+ tmpf = gravp;
+ gravp = th_gravp;
+ th_gravp = tmpf;
+ #endif
+ }
+
+ tmpf = gravmap;
+ gravmap = th_gravmap;
+ th_gravmap = tmpf;
+
+ grav_ready = 0; //Tell the other thread that we're ready for it to continue
+ pthread_cond_signal(&gravcv);
+ //}
+ }
+ pthread_mutex_unlock(&gravmutex);
+ //Apply the gravity mask
+ membwand(gravy, gravmask, (XRES/CELL)*(YRES/CELL)*sizeof(float), (XRES/CELL)*(YRES/CELL)*sizeof(unsigned));
+ membwand(gravx, gravmask, (XRES/CELL)*(YRES/CELL)*sizeof(float), (XRES/CELL)*(YRES/CELL)*sizeof(unsigned));
+ memset(gravmap, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ }
+}
+
+void *Gravity::update_grav_async_helper(void * context)
+{
+ ((Gravity *)context)->update_grav_async();
+ return NULL;
+}
+
+void Gravity::update_grav_async()
+{
+ int done = 0;
+ int thread_done = 0;
+ memset(th_ogravmap, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(th_gravmap, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(th_gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(th_gravx, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(th_gravp, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ //memset(th_gravy, 0, XRES*YRES*sizeof(float));
+ //memset(th_gravx, 0, XRES*YRES*sizeof(float));
+ //memset(th_gravp, 0, XRES*YRES*sizeof(float));
+ while(!thread_done){
+ if(!done){
+ update_grav();
+ done = 1;
+ pthread_mutex_lock(&gravmutex);
+
+ grav_ready = done;
+ thread_done = gravthread_done;
+
+ pthread_mutex_unlock(&gravmutex);
+ } else {
+ pthread_mutex_lock(&gravmutex);
+ pthread_cond_wait(&gravcv, &gravmutex);
+
+ done = grav_ready;
+ thread_done = gravthread_done;
+
+ pthread_mutex_unlock(&gravmutex);
+ }
+ }
+ pthread_exit(NULL);
+}
+
+void Gravity::start_grav_async()
+{
+ if(ngrav_enable) //If it's already enabled, restart it
+ stop_grav_async();
+
+ gravthread_done = 0;
+ grav_ready = 0;
+ pthread_mutex_init (&gravmutex, NULL);
+ pthread_cond_init(&gravcv, NULL);
+ pthread_create(&gravthread, NULL, &Gravity::update_grav_async_helper, this); //Start asynchronous gravity simulation
+ ngrav_enable = 1;
+
+ memset(gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(gravx, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(gravp, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(gravmap, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+}
+
+void Gravity::stop_grav_async()
+{
+ if(ngrav_enable){
+ pthread_mutex_lock(&gravmutex);
+ gravthread_done = 1;
+ pthread_cond_signal(&gravcv);
+ pthread_mutex_unlock(&gravmutex);
+ pthread_join(gravthread, NULL);
+ pthread_mutex_destroy(&gravmutex); //Destroy the mutex
+ ngrav_enable = 0;
+ }
+ //Clear the grav velocities
+ memset(gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(gravx, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(gravp, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(gravmap, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+}
+
+#ifdef GRAVFFT
+
+void Gravity::grav_fft_init()
+{
+ int xblock2 = XRES/CELL*2;
+ int yblock2 = YRES/CELL*2;
+ int x, y, fft_tsize = (xblock2/2+1)*yblock2;
+ float distance, scaleFactor;
+ fftwf_plan plan_ptgravx, plan_ptgravy;
+ if (grav_fft_status) return;
+
+ //use fftw malloc function to ensure arrays are aligned, to get better performance
+ th_ptgravx = (float*)fftwf_malloc(xblock2*yblock2*sizeof(float));
+ th_ptgravy = (float*)fftwf_malloc(xblock2*yblock2*sizeof(float));
+ th_ptgravxt = (fftwf_complex*)fftwf_malloc(fft_tsize*sizeof(fftwf_complex));
+ th_ptgravyt = (fftwf_complex*)fftwf_malloc(fft_tsize*sizeof(fftwf_complex));
+ th_gravmapbig = (float*)fftwf_malloc(xblock2*yblock2*sizeof(float));
+ th_gravmapbigt = (fftwf_complex*)fftwf_malloc(fft_tsize*sizeof(fftwf_complex));
+ th_gravxbig = (float*)fftwf_malloc(xblock2*yblock2*sizeof(float));
+ th_gravybig = (float*)fftwf_malloc(xblock2*yblock2*sizeof(float));
+ th_gravxbigt = (fftwf_complex*)fftwf_malloc(fft_tsize*sizeof(fftwf_complex));
+ th_gravybigt = (fftwf_complex*)fftwf_malloc(fft_tsize*sizeof(fftwf_complex));
+
+ //select best algorithm, could use FFTW_PATIENT or FFTW_EXHAUSTIVE but that increases the time taken to plan, and I don't see much increase in execution speed
+ plan_ptgravx = fftwf_plan_dft_r2c_2d(yblock2, xblock2, th_ptgravx, th_ptgravxt, FFTW_MEASURE);
+ plan_ptgravy = fftwf_plan_dft_r2c_2d(yblock2, xblock2, th_ptgravy, th_ptgravyt, FFTW_MEASURE);
+ plan_gravmap = fftwf_plan_dft_r2c_2d(yblock2, xblock2, th_gravmapbig, th_gravmapbigt, FFTW_MEASURE);
+ plan_gravx_inverse = fftwf_plan_dft_c2r_2d(yblock2, xblock2, th_gravxbigt, th_gravxbig, FFTW_MEASURE);
+ plan_gravy_inverse = fftwf_plan_dft_c2r_2d(yblock2, xblock2, th_gravybigt, th_gravybig, FFTW_MEASURE);
+
+ //(XRES/CELL)*(YRES/CELL)*4 is size of data array, scaling needed because FFTW calculates an unnormalized DFT
+ scaleFactor = -M_GRAV/((XRES/CELL)*(YRES/CELL)*4);
+ //calculate velocity map caused by a point mass
+ for (y=0; y<yblock2; y++)
+ {
+ for (x=0; x<xblock2; x++)
+ {
+ if (x==XRES/CELL && y==YRES/CELL) continue;
+ distance = sqrtf(pow(x-(XRES/CELL), 2.0f) + pow(y-(YRES/CELL), 2.0f));
+ th_ptgravx[y*xblock2+x] = scaleFactor*(x-(XRES/CELL)) / pow(distance, 3.0f);
+ th_ptgravy[y*xblock2+x] = scaleFactor*(y-(YRES/CELL)) / pow(distance, 3.0f);
+ }
+ }
+ th_ptgravx[yblock2*xblock2/2+xblock2/2] = 0.0f;
+ th_ptgravy[yblock2*xblock2/2+xblock2/2] = 0.0f;
+
+ //transform point mass velocity maps
+ fftwf_execute(plan_ptgravx);
+ fftwf_execute(plan_ptgravy);
+ fftwf_destroy_plan(plan_ptgravx);
+ fftwf_destroy_plan(plan_ptgravy);
+ fftwf_free(th_ptgravx);
+ fftwf_free(th_ptgravy);
+
+ //clear padded gravmap
+ memset(th_gravmapbig,0,xblock2*yblock2*sizeof(float));
+
+ grav_fft_status = true;
+}
+
+void Gravity::grav_fft_cleanup()
+{
+ if (!grav_fft_status) return;
+ fftwf_free(th_ptgravxt);
+ fftwf_free(th_ptgravyt);
+ fftwf_free(th_gravmapbig);
+ fftwf_free(th_gravmapbigt);
+ fftwf_free(th_gravxbig);
+ fftwf_free(th_gravybig);
+ fftwf_free(th_gravxbigt);
+ fftwf_free(th_gravybigt);
+ fftwf_destroy_plan(plan_gravmap);
+ fftwf_destroy_plan(plan_gravx_inverse);
+ fftwf_destroy_plan(plan_gravy_inverse);
+ grav_fft_status = false;
+}
+
+void Gravity::update_grav()
+{
+ int x, y, changed = 0;
+ int xblock2 = XRES/CELL*2, yblock2 = YRES/CELL*2;
+ int i, fft_tsize = (xblock2/2+1)*yblock2;
+ float mr, mc, pr, pc, gr, gc;
+ for (y=0; y<YRES/CELL; y++)
+ {
+ if(changed)
+ break;
+ for (x=0; x<XRES/CELL; x++)
+ {
+ if(th_ogravmap[y*(XRES/CELL)+x]!=th_gravmap[y*(XRES/CELL)+x]){
+ changed = 1;
+ break;
+ }
+ }
+ }
+ if(changed)
+ {
+ th_gravchanged = 1;
+ if (!grav_fft_status) grav_fft_init();
+
+ //copy gravmap into padded gravmap array
+ for (y=0; y<YRES/CELL; y++)
+ {
+ for (x=0; x<XRES/CELL; x++)
+ {
+ th_gravmapbig[(y+YRES/CELL)*xblock2+XRES/CELL+x] = th_gravmap[y*(XRES/CELL)+x];
+ }
+ }
+ //transform gravmap
+ fftwf_execute(plan_gravmap);
+ //do convolution (multiply the complex numbers)
+ for (i=0; i<fft_tsize; i++)
+ {
+ mr = th_gravmapbigt[i][0];
+ mc = th_gravmapbigt[i][1];
+ pr = th_ptgravxt[i][0];
+ pc = th_ptgravxt[i][1];
+ gr = mr*pr-mc*pc;
+ gc = mr*pc+mc*pr;
+ th_gravxbigt[i][0] = gr;
+ th_gravxbigt[i][1] = gc;
+ pr = th_ptgravyt[i][0];
+ pc = th_ptgravyt[i][1];
+ gr = mr*pr-mc*pc;
+ gc = mr*pc+mc*pr;
+ th_gravybigt[i][0] = gr;
+ th_gravybigt[i][1] = gc;
+ }
+ //inverse transform, and copy from padded arrays into normal velocity maps
+ fftwf_execute(plan_gravx_inverse);
+ fftwf_execute(plan_gravy_inverse);
+ for (y=0; y<YRES/CELL; y++)
+ {
+ for (x=0; x<XRES/CELL; x++)
+ {
+ th_gravx[y*(XRES/CELL)+x] = th_gravxbig[y*xblock2+x];
+ th_gravy[y*(XRES/CELL)+x] = th_gravybig[y*xblock2+x];
+ th_gravp[y*(XRES/CELL)+x] = sqrtf(pow(th_gravxbig[y*xblock2+x],2)+pow(th_gravybig[y*xblock2+x],2));
+ }
+ }
+ }
+ else
+ {
+ th_gravchanged = 0;
+ }
+ memcpy(th_ogravmap, th_gravmap, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+}
+
+#else
+// gravity without fast Fourier transforms
+
+void Gravity::update_grav(void)
+{
+ int x, y, i, j, changed = 0;
+ float val, distance;
+ th_gravchanged = 0;
+#ifndef GRAV_DIFF
+ //Find any changed cells
+ for (i=0; i<YRES/CELL; i++)
+ {
+ if(changed)
+ break;
+ for (j=0; j<XRES/CELL; j++)
+ {
+ if(th_ogravmap[i*(XRES/CELL)+j]!=th_gravmap[i*(XRES/CELL)+j]){
+ changed = 1;
+ break;
+ }
+ }
+ }
+ if(!changed)
+ goto fin;
+ memset(th_gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+ memset(th_gravx, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+#endif
+ th_gravchanged = 1;
+ for (i = 0; i < YRES / CELL; i++) {
+ for (j = 0; j < XRES / CELL; j++) {
+#ifdef GRAV_DIFF
+ if (th_ogravmap[i*(XRES/CELL)+j] != th_gravmap[i*(XRES/CELL)+j])
+ {
+#else
+ if (th_gravmap[i*(XRES/CELL)+j] > 0.0001f || th_gravmap[i*(XRES/CELL)+j]<-0.0001f) //Only calculate with populated or changed cells.
+ {
+#endif
+ for (y = 0; y < YRES / CELL; y++) {
+ for (x = 0; x < XRES / CELL; x++) {
+ if (x == j && y == i)//Ensure it doesn't calculate with itself
+ continue;
+ distance = sqrt(pow(j - x, 2.0f) + pow(i - y, 2.0f));
+#ifdef GRAV_DIFF
+ val = th_gravmap[i*(XRES/CELL)+j] - th_ogravmap[i*(XRES/CELL)+j];
+#else
+ val = th_gravmap[i*(XRES/CELL)+j];
+#endif
+ th_gravx[y*(XRES/CELL)+x] += M_GRAV * val * (j - x) / pow(distance, 3.0f);
+ th_gravy[y*(XRES/CELL)+x] += M_GRAV * val * (i - y) / pow(distance, 3.0f);
+ th_gravp[y*(XRES/CELL)+x] += M_GRAV * val / pow(distance, 2.0f);
+ }
+ }
+ }
+ }
+ }
+fin:
+ memcpy(th_ogravmap, th_gravmap, (XRES/CELL)*(YRES/CELL)*sizeof(float));
+}
+#endif
+
+
+
+void Gravity::grav_mask_r(int x, int y, char checkmap[YRES/CELL][XRES/CELL], char shape[YRES/CELL][XRES/CELL], char *shapeout)
+{
+ if(x < 0 || x >= XRES/CELL || y < 0 || y >= YRES/CELL)
+ return;
+ if(x == 0 || y ==0 || y == (YRES/CELL)-1 || x == (XRES/CELL)-1)
+ *shapeout = 1;
+
+ int x1 = x, x2 = x;
+ while (x1 >= 1)
+ {
+ if(checkmap[y][x1-1] || bmap[y][x1-1]==WL_GRAV)
+ break;
+ x1--;
+ }
+ while (x2 < (XRES/CELL)-1)
+ {
+ if(checkmap[y][x2+1] || bmap[y][x2+1]==WL_GRAV)
+ break;
+ x2++;
+ }
+
+ // fill span
+ for (x = x1; x <= x2; x++)
+ checkmap[y][x] = shape[y][x] = 1;
+
+ if(y >= 1)
+ for(x = x1; x <= x2; x++)
+ if(!checkmap[y-1][x] && bmap[y-1][x]!=WL_GRAV)
+ grav_mask_r(x, y-1, checkmap, shape, shapeout);
+ if(y < (YRES/CELL)-1)
+ for(x = x1; x <= x2; x++)
+ if(!checkmap[y+1][x] && bmap[y+1][x]!=WL_GRAV)
+ grav_mask_r(x, y+1, checkmap, shape, shapeout);
+ return;
+}
+void Gravity::mask_free(mask_el *c_mask_el){
+ if(c_mask_el==NULL)
+ return;
+ if(c_mask_el->next!=NULL)
+ mask_free((mask_el*)c_mask_el->next);
+ free(c_mask_el->shape);
+ free(c_mask_el);
+}
+void Gravity::gravity_mask()
+{
+ char checkmap[YRES/CELL][XRES/CELL];
+ int x = 0, y = 0, i, j;
+ unsigned maskvalue;
+ mask_el *t_mask_el = NULL;
+ mask_el *c_mask_el = NULL;
+ if(!gravmask)
+ return;
+ memset(checkmap, 0, sizeof(checkmap));
+ for(x = 0; x < XRES/CELL; x++)
+ {
+ for(y = 0; y < YRES/CELL; y++)
+ {
+ if(bmap[y][x]!=WL_GRAV && checkmap[y][x] == 0)
+ {
+ //Create a new shape
+ if(t_mask_el==NULL){
+ t_mask_el = (mask_el *)malloc(sizeof(mask_el));
+ t_mask_el->shape = (char *)malloc((XRES/CELL)*(YRES/CELL));
+ memset(t_mask_el->shape, 0, (XRES/CELL)*(YRES/CELL));
+ t_mask_el->shapeout = 0;
+ t_mask_el->next = NULL;
+ c_mask_el = t_mask_el;
+ } else {
+ c_mask_el->next = (mask_el *)malloc(sizeof(mask_el));
+ c_mask_el = (mask_el *)c_mask_el->next;
+ c_mask_el->shape = (char *)malloc((XRES/CELL)*(YRES/CELL));
+ memset(c_mask_el->shape, 0, (XRES/CELL)*(YRES/CELL));
+ c_mask_el->shapeout = 0;
+ c_mask_el->next = NULL;
+ }
+ //Fill the shape
+ grav_mask_r(x, y, (char (*)[XRES/CELL])checkmap, (char (*)[XRES/CELL])c_mask_el->shape, (char*)&c_mask_el->shapeout);
+ }
+ }
+ }
+ c_mask_el = t_mask_el;
+ memset(gravmask, 0, (XRES/CELL)*(YRES/CELL)*sizeof(unsigned));
+ while(c_mask_el!=NULL)
+ {
+ char *cshape = c_mask_el->shape;
+ for(x = 0; x < XRES/CELL; x++)
+ {
+ for(y = 0; y < YRES/CELL; y++)
+ {
+ if(cshape[y*(XRES/CELL)+x]){
+ if(c_mask_el->shapeout)
+ maskvalue = 0xFFFFFFFF;
+ else
+ maskvalue = 0x00000000;
+ gravmask[y*(XRES/CELL)+x] = maskvalue;
+ }
+ }
+ }
+ c_mask_el = (mask_el*)c_mask_el->next;
+ }
+ mask_free(t_mask_el);
+}
+
+Gravity::Gravity():
+ grav_fft_status(false)
+{
+ gravity_init();
+}
+
+Gravity::~Gravity()
+{
+ gravity_cleanup();
+}
diff --git a/src/simulation/Gravity.h b/src/simulation/Gravity.h
new file mode 100644
index 0000000..ec31b6a
--- /dev/null
+++ b/src/simulation/Gravity.h
@@ -0,0 +1,123 @@
+#ifndef GRAVITY_H
+#define GRAVITY_H
+
+#include <pthread.h>
+#undef GetUserName //God dammit microsoft!
+#include "Config.h"
+#include "Simulation.h"
+
+#ifdef GRAVFFT
+#include <fftw3.h>
+#endif
+
+class Simulation;
+
+struct mask_el {
+ char *shape;
+ char shapeout;
+ void *next;
+};
+typedef struct mask_el mask_el;
+
+
+/*
+ * float *gravmap = NULL;//Maps to be used by the main thread
+ float *gravp = NULL;
+ float *gravy = NULL;
+ float *gravx = NULL;
+ unsigned *gravmask = NULL;
+
+ float *th_ogravmap = NULL;// Maps to be processed by the gravity thread
+ float *th_gravmap = NULL;
+ float *th_gravx = NULL;
+ float *th_gravy = NULL;
+ float *th_gravp = NULL;
+
+ int th_gravchanged = 0;
+
+ pthread_t gravthread;
+ pthread_mutex_t gravmutex;
+ pthread_cond_t gravcv;
+ int grav_ready = 0;
+ int gravthread_done = 0;
+ */
+class Gravity
+{
+private:
+
+ float *th_ogravmap;
+ float *th_gravmap;
+ float *th_gravx;
+ float *th_gravy;
+ float *th_gravp;
+
+ int th_gravchanged;
+
+ pthread_t gravthread;
+ pthread_mutex_t gravmutex;
+ pthread_cond_t gravcv;
+ int grav_ready;
+ int gravthread_done;
+
+#ifdef GRAVFFT
+ bool grav_fft_status;
+ float *th_ptgravx, *th_ptgravy, *th_gravmapbig, *th_gravxbig, *th_gravybig;
+ fftwf_complex *th_ptgravxt, *th_ptgravyt, *th_gravmapbigt, *th_gravxbigt, *th_gravybigt;
+ fftwf_plan plan_gravmap, plan_gravx_inverse, plan_gravy_inverse;
+#endif
+
+ //Simulation * sim;
+public:
+ unsigned *gravmask;
+ float *gravmap;
+ float *gravp;
+ float *gravy;
+ float *gravx;
+ unsigned char (*bmap)[XRES/CELL];
+ int ngrav_enable;
+ void grav_mask_r(int x, int y, char checkmap[YRES/CELL][XRES/CELL], char shape[YRES/CELL][XRES/CELL], char *shapeout);
+ void mask_free(mask_el *c_mask_el);
+
+ void Clear();
+
+ void gravity_init();
+ void gravity_cleanup();
+ void gravity_update_async();
+
+ static void *update_grav_async_helper(void * context);
+ void update_grav_async();
+
+ void start_grav_async();
+ void stop_grav_async();
+ void update_grav();
+ void gravity_mask();
+
+ void bilinear_interpolation(float *src, float *dst, int sw, int sh, int rw, int rh);
+
+ #ifdef GRAVFFT
+ void grav_fft_init();
+ void grav_fft_cleanup();
+ #endif
+
+ Gravity();
+ ~Gravity();
+};
+
+/*extern int ngrav_enable; //Newtonian gravity
+extern int gravwl_timeout;
+extern int gravityMode;*/
+
+/*float *gravmap;//Maps to be used by the main thread
+float *gravp;
+float *gravy;
+float *gravx;
+unsigned *gravmask;
+
+float *th_ogravmap;// Maps to be processed by the gravity thread
+float *th_gravmap;
+float *th_gravx;
+float *th_gravy;
+float *th_gravp;*/
+
+
+#endif
diff --git a/src/simulation/MenuSection.h b/src/simulation/MenuSection.h
new file mode 100644
index 0000000..b8e16fe
--- /dev/null
+++ b/src/simulation/MenuSection.h
@@ -0,0 +1,20 @@
+//
+// MenuSection.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_MenuSection_h
+#define The_Powder_Toy_MenuSection_h
+
+struct menu_section
+{
+ char *icon;
+ const char *name;
+ int itemcount;
+ int doshow;
+};
+
+#endif
diff --git a/src/simulation/Particle.cpp b/src/simulation/Particle.cpp
new file mode 100644
index 0000000..115ed95
--- /dev/null
+++ b/src/simulation/Particle.cpp
@@ -0,0 +1,27 @@
+/*
+ * Particle.cpp
+ *
+ * Created on: Jun 6, 2012
+ * Author: Simon
+ */
+
+#include <cstddef>
+#include "Particle.h"
+
+std::vector<StructProperty> Particle::GetProperties()
+{
+ std::vector<StructProperty> properties;
+ properties.push_back(StructProperty("type", StructProperty::ParticleType, offsetof(Particle, type)));
+ properties.push_back(StructProperty("life", StructProperty::ParticleType, offsetof(Particle, life)));
+ properties.push_back(StructProperty("ctype", StructProperty::ParticleType, offsetof(Particle, ctype)));
+ properties.push_back(StructProperty("x", StructProperty::Float, offsetof(Particle, x)));
+ properties.push_back(StructProperty("y", StructProperty::Float, offsetof(Particle, y)));
+ properties.push_back(StructProperty("vx", StructProperty::Float, offsetof(Particle, vx)));
+ properties.push_back(StructProperty("vy", StructProperty::Float, offsetof(Particle, vy)));
+ properties.push_back(StructProperty("temp", StructProperty::Float, offsetof(Particle, temp)));
+ properties.push_back(StructProperty("flags", StructProperty::UInteger, offsetof(Particle, flags)));
+ properties.push_back(StructProperty("tmp", StructProperty::Integer, offsetof(Particle, tmp)));
+ properties.push_back(StructProperty("tmp2", StructProperty::Integer, offsetof(Particle, tmp2)));
+ properties.push_back(StructProperty("dcolour", StructProperty::UInteger, offsetof(Particle, dcolour)));
+ return properties;
+}
diff --git a/src/simulation/Particle.h b/src/simulation/Particle.h
new file mode 100644
index 0000000..bb0297e
--- /dev/null
+++ b/src/simulation/Particle.h
@@ -0,0 +1,31 @@
+//
+// Particle.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_Particle_h
+#define The_Powder_Toy_Particle_h
+
+#include <vector>
+#include "StructProperty.h"
+
+struct Particle
+{
+ int type;
+ int life, ctype;
+ float x, y, vx, vy;
+ float temp;
+ float pavg[2];
+ int flags;
+ int tmp;
+ int tmp2;
+ unsigned int dcolour;
+ /** Returns a list of properties, their type and offset within the structure that can be changed
+ by higher-level processes refering to them by name such as Lua or the property tool **/
+ static std::vector<StructProperty> GetProperties();
+};
+
+#endif
diff --git a/src/simulation/Player.h b/src/simulation/Player.h
new file mode 100644
index 0000000..af2b68e
--- /dev/null
+++ b/src/simulation/Player.h
@@ -0,0 +1,23 @@
+//
+// Player.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_Player_h
+#define The_Powder_Toy_Player_h
+
+struct playerst
+{
+ char comm; //command cell
+ char pcomm; //previous command
+ int elem; //element power
+ float legs[16]; //legs' positions
+ float accs[8]; //accelerations
+ char spwn; //if stick man was spawned
+ unsigned int frames; //frames since last particle spawn - used when spawning LIGH
+};
+
+#endif
diff --git a/src/simulation/Sample.h b/src/simulation/Sample.h
new file mode 100644
index 0000000..3605a5d
--- /dev/null
+++ b/src/simulation/Sample.h
@@ -0,0 +1,29 @@
+
+
+#ifndef The_Powder_Toy_Sample_h
+#define The_Powder_Toy_Sample_h
+
+#include "Particle.h"
+
+class SimulationSample
+{
+public:
+ Particle particle;
+ int ParticleID;
+ int PositionX, PositionY;
+ float AirPressure;
+ float AirTemperature;
+ float AirVelocityX;
+ float AirVelocityY;
+
+ int WallType;
+ float Gravity;
+ float GravityVelocityX;
+ float GravityVelocityY;
+
+ int NumParts;
+
+ SimulationSample() : PositionX(0), PositionY(0), ParticleID(0), particle(), AirPressure(0), AirVelocityX(0), AirVelocityY(0), WallType(0), Gravity(0), GravityVelocityX(0), GravityVelocityY(0), AirTemperature(0), NumParts(0) {}
+};
+
+#endif \ No newline at end of file
diff --git a/src/simulation/SaveRenderer.cpp b/src/simulation/SaveRenderer.cpp
new file mode 100644
index 0000000..fc30a28
--- /dev/null
+++ b/src/simulation/SaveRenderer.cpp
@@ -0,0 +1,183 @@
+/*
+ * SaveRenderer.cpp
+ *
+ * Created on: Apr 3, 2012
+ * Author: Simon
+ */
+
+#include "SaveRenderer.h"
+#include "client/GameSave.h"
+#include "graphics/Graphics.h"
+#include "Simulation.h"
+#include "graphics/Renderer.h"
+#include "search/Thumbnail.h"
+
+
+SaveRenderer::SaveRenderer(){
+ g = new Graphics();
+ sim = new Simulation();
+ ren = new Renderer(g, sim);
+ ren->decorations_enable = true;
+ ren->blackDecorations = true;
+
+#if defined(OGLR) || defined(OGLI)
+ glEnable(GL_TEXTURE_2D);
+ glGenTextures(1, &fboTex);
+ glBindTexture(GL_TEXTURE_2D, fboTex);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, XRES, YRES, 0, GL_RGBA, GL_FLOAT, NULL);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
+
+ //FBO
+ glGenFramebuffers(1, &fbo);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+ glEnable(GL_BLEND);
+ glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fboTex, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Reset framebuffer binding
+ glDisable(GL_TEXTURE_2D);
+#endif
+}
+
+Thumbnail * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
+{
+ int width, height;
+ Thumbnail * tempThumb;
+ width = save->blockWidth;
+ height = save->blockHeight;
+ bool doCollapse = save->Collapsed();
+
+ g->Acquire();
+ g->Clear();
+ sim->clear_sim();
+
+ if(!sim->Load(save))
+ {
+ ren->decorations_enable = true;
+ ren->blackDecorations = !decorations;
+#if defined(OGLR) || defined(OGLI)
+ pixel * pData = NULL;
+ unsigned char * texData = NULL;
+
+ glTranslated(0, MENUSIZE, 0);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ ren->clearScreen(1.0f);
+ ren->ClearAccumulation();
+
+#ifdef OGLR
+ ren->RenderBegin();
+ ren->RenderEnd();
+#else
+ if (fire)
+ {
+ int frame = 15;
+ while(frame)
+ {
+ frame--;
+ ren->render_parts();
+ ren->render_fire();
+ ren->clearScreen(1.0f);
+ }
+ }
+
+ ren->RenderBegin();
+ ren->RenderEnd();
+#endif
+
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glTranslated(0, -MENUSIZE, 0);
+
+ glEnable( GL_TEXTURE_2D );
+ glBindTexture(GL_TEXTURE_2D, fboTex);
+
+ pData = new pixel[XRES*YRES];
+ texData = new unsigned char[(XRES*YRES)*PIXELSIZE];
+ std::fill(texData, texData+(XRES*YRES)*PIXELSIZE, 0xDD);
+ glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, texData);
+ glDisable(GL_TEXTURE_2D);
+
+ for(int x = 0; x < width*CELL; x++)
+ {
+ for(int y = 0; y < height*CELL; y++)
+ {
+ unsigned char red = texData[((((YRES-1-y)*XRES)+x)*4)];
+ unsigned char green = texData[((((YRES-1-y)*XRES)+x)*4)+1];
+ unsigned char blue = texData[((((YRES-1-y)*XRES)+x)*4)+2];
+
+ pData[(y*(width*CELL))+x] = PIXRGBA(red, green, blue, 255);
+ }
+ }
+
+ tempThumb = new Thumbnail(0, 0, pData, ui::Point(width*CELL, height*CELL));
+ delete[] pData;
+ delete[] texData;
+ pData = NULL;
+#else
+ pixel * pData = NULL;
+ pixel * dst;
+ pixel * src = g->vid;
+
+ ren->ClearAccumulation();
+
+ if (fire)
+ {
+ int frame = 15;
+ while(frame)
+ {
+ frame--;
+ ren->render_parts();
+ ren->render_fire();
+ ren->clearScreen(1.0f);
+ }
+ }
+
+ ren->RenderBegin();
+ ren->RenderEnd();
+
+
+ pData = (pixel *)malloc(PIXELSIZE * ((width*CELL)*(height*CELL)));
+ dst = pData;
+ for(int i = 0; i < height*CELL; i++)
+ {
+ memcpy(dst, src, (width*CELL)*PIXELSIZE);
+ dst+=(width*CELL);///PIXELSIZE;
+ src+=XRES+BARSIZE;
+ }
+ tempThumb = new Thumbnail(0, 0, pData, ui::Point(width*CELL, height*CELL));
+ if(pData)
+ free(pData);
+#endif
+ }
+ if(doCollapse)
+ save->Collapse();
+ g->Release();
+ return tempThumb;
+}
+
+Thumbnail * SaveRenderer::Render(unsigned char * saveData, int dataSize, bool decorations, bool fire)
+{
+ GameSave * tempSave;
+ try {
+ tempSave = new GameSave((char*)saveData, dataSize);
+ } catch (std::exception & e) {
+
+ //Todo: make this look a little less shit
+ VideoBuffer buffer(64, 64);
+ buffer.BlendCharacter(32, 32, 'x', 255, 255, 255, 255);
+
+ Thumbnail * thumb = new Thumbnail(0, 0, buffer.Buffer, ui::Point(64, 64));
+
+ return thumb;
+ }
+ Thumbnail * thumb = Render(tempSave, decorations, fire);
+ delete tempSave;
+ return thumb;
+}
+
+SaveRenderer::~SaveRenderer() {
+ // TODO Auto-generated destructor stub
+}
+
diff --git a/src/simulation/SaveRenderer.h b/src/simulation/SaveRenderer.h
new file mode 100644
index 0000000..be4a83b
--- /dev/null
+++ b/src/simulation/SaveRenderer.h
@@ -0,0 +1,37 @@
+/*
+ * SaveRenderer.h
+ *
+ * Created on: Apr 3, 2012
+ * Author: Simon
+ */
+
+#ifndef SAVERENDERER_H_
+#define SAVERENDERER_H_
+#ifdef OGLI
+#include "graphics/OpenGLHeaders.h"
+#endif
+#include "Singleton.h"
+
+class GameSave;
+class Thumbnail;
+class Graphics;
+class Simulation;
+class Renderer;
+
+class SaveRenderer: public Singleton<SaveRenderer> {
+ Graphics * g;
+ Simulation * sim;
+ Renderer * ren;
+public:
+ SaveRenderer();
+ Thumbnail * Render(GameSave * save, bool decorations = true, bool fire = true);
+ Thumbnail * Render(unsigned char * saveData, int saveDataSize, bool decorations = true, bool fire = true);
+ virtual ~SaveRenderer();
+
+private:
+#if defined(OGLR) || defined(OGLI)
+ GLuint fboTex, fbo;
+#endif
+};
+
+#endif /* SAVERENDERER_H_ */
diff --git a/src/simulation/Sign.cpp b/src/simulation/Sign.cpp
new file mode 100644
index 0000000..2caf6c3
--- /dev/null
+++ b/src/simulation/Sign.cpp
@@ -0,0 +1,55 @@
+/*
+ * Sign.cpp
+ *
+ * Created on: Jun 25, 2012
+ * Author: Simon
+ */
+
+#include "Sign.h"
+#include "graphics/Graphics.h"
+#include "Misc.h"
+
+sign::sign(std::string text_, int x_, int y_, Justification justification_):
+ text(text_),
+ x(x_),
+ y(y_),
+ ju(justification_)
+{
+}
+
+void sign::pos(int & x0, int & y0, int & w, int & h)
+{
+ //Changing width if sign have special content
+ if (text == "{p}")
+ {
+ w = Graphics::textwidth("Pressure: -000.00");
+ }
+ else if (text == "{t}")
+ {
+ w = Graphics::textwidth("Temp: 0000.00");
+ }
+ else if (sregexp(text.c_str(), "^{[c|t]:[0-9]*|.*}$")==0)
+ {
+ int sldr, startm;
+ char buff[256];
+ memset(buff, 0, sizeof(buff));
+ for (sldr=3; text[sldr-1] != '|'; sldr++)
+ startm = sldr + 1;
+
+ sldr = startm;
+ while (text[sldr] != '}')
+ {
+ buff[sldr - startm] = text[sldr];
+ sldr++;
+ }
+ w = Graphics::textwidth(buff) + 5;
+ }
+ else
+ {
+ w = Graphics::textwidth(text.c_str()) + 5;
+ }
+ h = 14;
+ x0 = (ju == 2) ? x - w :
+ (ju == 1) ? x - w/2 : x;
+ y0 = (y > 18) ? y - 18 : y + 4;
+}
diff --git a/src/simulation/Sign.h b/src/simulation/Sign.h
new file mode 100644
index 0000000..14b7dac
--- /dev/null
+++ b/src/simulation/Sign.h
@@ -0,0 +1,26 @@
+//
+// Sign.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_Sign_h
+#define The_Powder_Toy_Sign_h
+
+#include <string>
+
+class sign
+{
+public:
+ enum Justification { Left = 0, Centre = 1, Right = 2 };
+ sign(std::string text_, int x_, int y_, Justification justification_);
+ int x, y;
+ Justification ju;
+ std::string text;
+
+ void pos(int & x0, int & y0, int & w, int & h);
+};
+
+#endif
diff --git a/src/simulation/Simulation.cpp b/src/simulation/Simulation.cpp
new file mode 100644
index 0000000..cfe39ac
--- /dev/null
+++ b/src/simulation/Simulation.cpp
@@ -0,0 +1,4835 @@
+//#include <cstdlib>
+#include <cmath>
+#include <math.h>
+#if !defined(_MSC_VER)
+#include <strings.h>
+#else
+#include <windows.h>
+#endif
+#include "Config.h"
+#include "Simulation.h"
+#include "Elements.h"
+//#include "ElementFunctions.h"
+#include "Air.h"
+#include "Gravity.h"
+#include "elements/Element.h"
+
+//#include "graphics/Renderer.h"
+//#include "graphics/Graphics.h"
+#include "Misc.h"
+#include "Tools.h"
+#include "game/Brush.h"
+#include "client/GameSave.h"
+#include "Sample.h"
+#include "Snapshot.h"
+//#include "StorageClasses.h"
+
+#undef LUACONSOLE
+//#include "cat/LuaScriptHelper.h"
+
+int Simulation::Load(GameSave * save)
+{
+ return Load(0, 0, save);
+}
+
+int Simulation::Load(int fullX, int fullY, GameSave * save)
+{
+ int blockX, blockY, x, y, r;
+
+ if(!save) return 0;
+ save->Expand();
+
+ //Align to blockMap
+ blockX = fullX/CELL;
+ blockY = fullY/CELL;
+ fullX = blockX*CELL;
+ fullY = blockY*CELL;
+
+ int partMap[PT_NUM];
+ for(int i = 0; i < PT_NUM; i++)
+ {
+ partMap[i] = i;
+ }
+ if(save->palette.size())
+ {
+ for(std::vector<GameSave::PaletteItem>::iterator iter = save->palette.begin(), end = save->palette.end(); iter != end; ++iter)
+ {
+ GameSave::PaletteItem pi = *iter;
+ if(pi.second >= 0 && pi.second < PT_NUM)
+ {
+ int myId = 0;//pi.second;
+ for(int i = 0; i < PT_NUM; i++)
+ {
+ if(elements[i].Enabled && elements[i].Identifier == pi.first)
+ myId = i;
+ }
+ partMap[pi.second] = myId;
+ }
+ }
+ }
+
+ int i;
+ for(int n = 0; n < NPART && n < save->particlesCount; n++)
+ {
+ Particle tempPart = save->particles[n];
+ tempPart.x += (float)fullX;
+ tempPart.y += (float)fullY;
+ x = int(tempPart.x + 0.5f);
+ y = int(tempPart.y + 0.5f);
+
+ if(tempPart.type >= 0 && tempPart.type < PT_NUM)
+ tempPart.type = partMap[tempPart.type];
+
+ if ((player.spwn == 1 && tempPart.type==PT_STKM) || (player2.spwn == 1 && tempPart.type==PT_STKM2))
+ continue;
+ if (!elements[tempPart.type].Enabled)
+ continue;
+
+ if(r = pmap[y][x])
+ {
+ //Replace existing
+ parts[r>>8] = tempPart;
+ i = r>>8;
+ pmap[y][x] = 0;
+ elementCount[parts[r>>8].type]--;
+ elementCount[tempPart.type]++;
+ }
+ else
+ {
+ //Allocate new particle
+ if (pfree == -1)
+ break;
+ i = pfree;
+ pfree = parts[i].life;
+ if (i>parts_lastActiveIndex) parts_lastActiveIndex = i;
+ parts[i] = tempPart;
+
+ elementCount[tempPart.type]++;
+ }
+
+ if (parts[i].type == PT_STKM)
+ {
+ Element_STKM::STKM_init_legs(this, &player, i);
+ player.spwn = 1;
+ player.elem = PT_DUST;
+ }
+ else if (parts[i].type == PT_STKM2)
+ {
+ Element_STKM::STKM_init_legs(this, &player2, i);
+ player2.spwn = 1;
+ player2.elem = PT_DUST;
+ }
+ else if (parts[i].type == PT_FIGH)
+ {
+ //TODO: 100 should be replaced with a macro
+ for(int fcount = 0; fcount < 100; fcount++)
+ {
+ if(!fighters[fcount].spwn)
+ {
+ fighcount++;
+ //currentPart.tmp = fcount;
+ parts[i].tmp = fcount;
+ Element_STKM::STKM_init_legs(this, &(fighters[fcount]), i);
+ fighters[fcount].spwn = 1;
+ fighters[fcount].elem = PT_DUST;
+ break;
+ }
+ }
+ }
+ }
+ parts_lastActiveIndex = NPART-1;
+ force_stacking_check = 1;
+ Element_PPIP::ppip_changed = 1;
+ for(int i = 0; i < save->signs.size() && signs.size() < MAXSIGNS; i++)
+ {
+ sign tempSign = save->signs[i];
+ tempSign.x += fullX;
+ tempSign.y += fullY;
+ signs.push_back(tempSign);
+ }
+ for(int saveBlockX = 0; saveBlockX < save->blockWidth; saveBlockX++)
+ {
+ for(int saveBlockY = 0; saveBlockY < save->blockHeight; saveBlockY++)
+ {
+ if(save->blockMap[saveBlockY][saveBlockX])
+ {
+ bmap[saveBlockY+blockY][saveBlockX+blockX] = save->blockMap[saveBlockY][saveBlockX];
+ fvx[saveBlockY+blockY][saveBlockX+blockX] = save->fanVelX[saveBlockY][saveBlockX];
+ fvy[saveBlockY+blockY][saveBlockX+blockX] = save->fanVelY[saveBlockY][saveBlockX];
+ }
+ }
+ }
+
+ gravWallChanged = true;
+
+ return 0;
+}
+
+GameSave * Simulation::Save()
+{
+ return Save(0, 0, XRES, YRES);
+}
+
+GameSave * Simulation::Save(int fullX, int fullY, int fullX2, int fullY2)
+{
+ int blockX, blockY, blockX2, blockY2, fullW, fullH, blockW, blockH;
+ //Normalise incoming coords
+ int swapTemp;
+ if(fullY>fullY2)
+ {
+ swapTemp = fullY;
+ fullY = fullY2;
+ fullY2 = swapTemp;
+ }
+ if(fullX>fullX2)
+ {
+ swapTemp = fullX;
+ fullX = fullX2;
+ fullX2 = swapTemp;
+ }
+
+ //Align coords to blockMap
+ blockX = fullX/CELL;
+ blockY = fullY/CELL;
+
+ blockX2 = fullX2/CELL;
+ blockY2 = fullY2/CELL;
+
+ fullX = blockX*CELL;
+ fullY = blockY*CELL;
+
+ fullX2 = blockX2*CELL;
+ fullY2 = blockY2*CELL;
+
+ blockW = blockX2-blockX;
+ blockH = blockY2-blockY;
+ fullW = fullX2-fullX;
+ fullH = fullY2-fullY;
+
+ GameSave * newSave = new GameSave(blockW, blockH);
+
+ int storedParts = 0;
+ int elementCount[PT_NUM];
+ std::fill(elementCount, elementCount+PT_NUM, 0);
+ for(int i = 0; i < NPART; i++)
+ {
+ int x, y;
+ x = int(parts[i].x + 0.5f);
+ y = int(parts[i].y + 0.5f);
+ if(parts[i].type && x >= fullX && y >= fullY && x < fullX2 && y < fullY2)
+ {
+ Particle tempPart = parts[i];
+ tempPart.x -= fullX;
+ tempPart.y -= fullY;
+ if(elements[tempPart.type].Enabled)
+ {
+ *newSave << tempPart;
+ storedParts++;
+ elementCount[tempPart.type]++;
+ }
+ }
+ }
+
+ if(storedParts)
+ {
+ for(int i = 0; i < PT_NUM; i++)
+ {
+ if(elements[i].Enabled && elementCount[i])
+ {
+ newSave->palette.push_back(GameSave::PaletteItem(elements[i].Identifier, i));
+ }
+ }
+ }
+
+ for(int i = 0; i < MAXSIGNS && i < signs.size(); i++)
+ {
+ if(signs[i].text.length() && signs[i].x >= fullX && signs[i].y >= fullY && signs[i].x < fullX2 && signs[i].y < fullY2)
+ {
+ sign tempSign = signs[i];
+ tempSign.x -= fullX;
+ tempSign.y -= fullY;
+ *newSave << tempSign;
+ }
+ }
+
+ for(int saveBlockX = 0; saveBlockX < newSave->blockWidth; saveBlockX++)
+ {
+ for(int saveBlockY = 0; saveBlockY < newSave->blockHeight; saveBlockY++)
+ {
+ if(bmap[saveBlockY+blockY][saveBlockX+blockX])
+ {
+ newSave->blockMap[saveBlockY][saveBlockX] = bmap[saveBlockY+blockY][saveBlockX+blockX];
+ newSave->fanVelX[saveBlockY][saveBlockX] = fvx[saveBlockY+blockY][saveBlockX+blockX];
+ newSave->fanVelY[saveBlockY][saveBlockX] = fvy[saveBlockY+blockY][saveBlockX+blockX];
+ }
+ }
+ }
+
+ return newSave;
+}
+
+Snapshot * Simulation::CreateSnapshot()
+{
+ Snapshot * snap = new Snapshot();
+ snap->AirPressure.insert(snap->AirPressure.begin(), &pv[0][0], &pv[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->AirVelocityX.insert(snap->AirVelocityX.begin(), &vx[0][0], &vx[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->AirVelocityY.insert(snap->AirVelocityY.begin(), &vy[0][0], &vy[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->AmbientHeat.insert(snap->AmbientHeat.begin(), &hv[0][0], &hv[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->Particles.insert(snap->Particles.begin(), parts, parts+NPART);
+ snap->PortalParticles.insert(snap->PortalParticles.begin(), &portalp[0][0][0], &portalp[CHANNELS-1][8-1][80-1]);
+ snap->WirelessData.insert(snap->WirelessData.begin(), &wireless[0][0], &wireless[CHANNELS-1][2-1]);
+ snap->GravVelocityX.insert(snap->GravVelocityX.begin(), gravx, gravx+((XRES/CELL)*(YRES/CELL)));
+ snap->GravVelocityY.insert(snap->GravVelocityY.begin(), gravy, gravy+((XRES/CELL)*(YRES/CELL)));
+ snap->GravValue.insert(snap->GravValue.begin(), gravp, gravp+((XRES/CELL)*(YRES/CELL)));
+ snap->GravMap.insert(snap->GravMap.begin(), gravmap, gravmap+((XRES/CELL)*(YRES/CELL)));
+ snap->BlockMap.insert(snap->BlockMap.begin(), &bmap[0][0], &bmap[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->ElecMap.insert(snap->ElecMap.begin(), &emap[0][0], &emap[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->FanVelocityX.insert(snap->FanVelocityX.begin(), &fvx[0][0], &fvx[0][0]+((XRES/CELL)*(YRES/CELL)));
+ snap->FanVelocityY.insert(snap->FanVelocityY.begin(), &fvy[0][0], &fvy[0][0]+((XRES/CELL)*(YRES/CELL)));
+ return snap;
+}
+
+void Simulation::Restore(const Snapshot & snap)
+{
+ parts_lastActiveIndex = NPART-1;
+ std::copy(snap.AirPressure.begin(), snap.AirPressure.end(), &pv[0][0]);
+ std::copy(snap.AirVelocityX.begin(), snap.AirVelocityX.end(), &vx[0][0]);
+ std::copy(snap.AirVelocityY.begin(), snap.AirVelocityY.end(), &vy[0][0]);
+ std::copy(snap.AmbientHeat.begin(), snap.AmbientHeat.end(), &hv[0][0]);
+ std::copy(snap.Particles.begin(), snap.Particles.end(), parts);
+ std::copy(snap.PortalParticles.begin(), snap.PortalParticles.end(), &portalp[0][0][0]);
+ std::copy(snap.WirelessData.begin(), snap.WirelessData.end(), &wireless[0][0]);
+ std::copy(snap.GravVelocityX.begin(), snap.GravVelocityX.end(), gravx);
+ std::copy(snap.GravVelocityY.begin(), snap.GravVelocityY.end(), gravy);
+ std::copy(snap.GravValue.begin(), snap.GravValue.end(), gravp);
+ std::copy(snap.GravMap.begin(), snap.GravMap.end(), gravmap);
+ std::copy(snap.BlockMap.begin(), snap.BlockMap.end(), &bmap[0][0]);
+ std::copy(snap.ElecMap.begin(), snap.ElecMap.end(), &emap[0][0]);
+ std::copy(snap.FanVelocityX.begin(), snap.FanVelocityX.end(), &fvx[0][0]);
+ std::copy(snap.FanVelocityY.begin(), snap.FanVelocityY.end(), &fvy[0][0]);
+}
+
+/*int Simulation::Load(unsigned char * data, int dataLength)
+{
+ return SaveLoader::Load(data, dataLength, this, true, 0, 0);
+}
+
+int Simulation::Load(int x, int y, unsigned char * data, int dataLength)
+{
+ return SaveLoader::Load(data, dataLength, this, false, x, y);
+}
+
+unsigned char * Simulation::Save(int & dataLength)
+{
+ return SaveLoader::Build(dataLength, this, 0, 0, XRES, YRES);
+}
+
+unsigned char * Simulation::Save(int x1, int y1, int x2, int y2, int & dataLength)
+{
+ return SaveLoader::Build(dataLength, this, x1, y1, x2-x1, y2-y1);
+}*/
+
+void Simulation::clear_area(int area_x, int area_y, int area_w, int area_h)
+{
+ int cx = 0;
+ int cy = 0;
+ for (cy=0; cy<area_h; cy++)
+ {
+ for (cx=0; cx<area_w; cx++)
+ {
+ if(bmap[(cy+area_y)/CELL][(cx+area_x)/CELL] == WL_GRAV)
+ gravWallChanged = true;
+ bmap[(cy+area_y)/CELL][(cx+area_x)/CELL] = 0;
+ delete_part(cx+area_x, cy+area_y, 0);
+ }
+ }
+}
+
+void Simulation::CreateBox(int x1, int y1, int x2, int y2, int c, int flags)
+{
+ int i, j;
+ if (c==SPC_PROP)
+ return;
+ if (x1>x2)
+ {
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ if (y1>y2)
+ {
+ j = y2;
+ y2 = y1;
+ y1 = j;
+ }
+ for (j=y1; j<=y2; j++)
+ for (i=x1; i<=x2; i++)
+ CreateParts(i, j, 0, 0, c, flags);
+}
+
+void Simulation::CreateWallBox(int x1, int y1, int x2, int y2, int c, int flags)
+{
+ int i, j;
+ if (x1>x2)
+ {
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ if (y1>y2)
+ {
+ j = y2;
+ y2 = y1;
+ y1 = j;
+ }
+ for (j=y1; j<=y2; j++)
+ for (i=x1; i<=x2; i++)
+ CreateWalls(i, j, 0, 0, c, flags);
+}
+
+int Simulation::flood_prop_2(int x, int y, size_t propoffset, void * propvalue, StructProperty::PropertyType proptype, int parttype, char * bitmap)
+{
+ int x1, x2, i, dy = 1;
+ x1 = x2 = x;
+ while (x1>=CELL)
+ {
+ if ((pmap[y][x1-1]&0xFF)!=parttype || bitmap[(y*XRES)+x1-1])
+ {
+ break;
+ }
+ x1--;
+ }
+ while (x2<XRES-CELL)
+ {
+ if ((pmap[y][x2+1]&0xFF)!=parttype || bitmap[(y*XRES)+x2+1])
+ {
+ break;
+ }
+ x2++;
+ }
+ for (x=x1; x<=x2; x++)
+ {
+ i = pmap[y][x]>>8;
+ switch (proptype) {
+ case StructProperty::Float:
+ *((float*)(((char*)&parts[i])+propoffset)) = *((float*)propvalue);
+ break;
+
+ case StructProperty::ParticleType:
+ case StructProperty::Integer:
+ *((int*)(((char*)&parts[i])+propoffset)) = *((int*)propvalue);
+ break;
+
+ case StructProperty::UInteger:
+ *((unsigned int*)(((char*)&parts[i])+propoffset)) = *((unsigned int*)propvalue);
+ break;
+
+ default:
+ break;
+ }
+ bitmap[(y*XRES)+x] = 1;
+ }
+ if (y>=CELL+dy)
+ for (x=x1; x<=x2; x++)
+ if ((pmap[y-dy][x]&0xFF)==parttype && !bitmap[((y-dy)*XRES)+x])
+ if (!flood_prop_2(x, y-dy, propoffset, propvalue, proptype, parttype, bitmap))
+ return 0;
+ if (y<YRES-CELL-dy)
+ for (x=x1; x<=x2; x++)
+ if ((pmap[y+dy][x]&0xFF)==parttype && !bitmap[((y+dy)*XRES)+x])
+ if (!flood_prop_2(x, y+dy, propoffset, propvalue, proptype, parttype, bitmap))
+ return 0;
+ return 1;
+}
+
+int Simulation::flood_prop(int x, int y, size_t propoffset, void * propvalue, StructProperty::PropertyType proptype)
+{
+ int r = 0;
+ char * bitmap = (char *)malloc(XRES*YRES); //Bitmap for checking
+ memset(bitmap, 0, XRES*YRES);
+ r = pmap[y][x];
+ flood_prop_2(x, y, propoffset, propvalue, proptype, r&0xFF, bitmap);
+ free(bitmap);
+ return 0;
+}
+
+SimulationSample Simulation::Get(int x, int y)
+{
+ SimulationSample sample;
+ sample.PositionX = x;
+ sample.PositionY = y;
+ if(pmap[y][x])
+ {
+ sample.particle = parts[pmap[y][x]>>8];
+ sample.ParticleID = pmap[y][x]>>8;
+ }
+ else if(photons[y][x])
+ {
+ sample.particle = parts[photons[y][x]>>8];
+ sample.ParticleID = photons[y][x]>>8;
+ }
+ if (bmap[y/CELL][x/CELL])
+ {
+ sample.WallType = bmap[y/CELL][x/CELL];
+ }
+ sample.AirPressure = pv[y/CELL][x/CELL];
+ sample.AirTemperature = hv[y/CELL][x/CELL];
+ sample.AirVelocityX = vx[y/CELL][x/CELL];
+ sample.AirVelocityY = vy[y/CELL][x/CELL];
+
+ if(grav->ngrav_enable)
+ {
+ sample.Gravity = gravp[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ sample.GravityVelocityX = gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ sample.GravityVelocityY = gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ }
+
+ sample.NumParts = NUM_PARTS;
+ return sample;
+}
+
+#define PMAP_CMP_CONDUCTIVE(pmap, t) (((pmap)&0xFF)==(t) || (((pmap)&0xFF)==PT_SPRK && parts[(pmap)>>8].ctype==(t)))
+
+int Simulation::FloodINST(int x, int y, int fullc, int cm)
+{
+ int c = fullc&0xFF;
+ int x1, x2, dy = (c<PT_NUM)?1:CELL;
+ int co = c;
+ int coord_stack_limit = XRES*YRES;
+ unsigned short (*coord_stack)[2];
+ int coord_stack_size = 0;
+ int created_something = 0;
+
+ if (c>=PT_NUM)
+ return 0;
+
+ if (cm==-1)
+ {
+ if (c==0)
+ {
+ cm = pmap[y][x]&0xFF;
+ if (!cm)
+ return 0;
+ }
+ else
+ cm = 0;
+ }
+
+ if ((pmap[y][x]&0xFF)!=cm || parts[pmap[y][x]>>8].life!=0)
+ return 1;
+
+ coord_stack = (short unsigned int (*)[2])malloc(sizeof(unsigned short)*2*coord_stack_limit);
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y;
+ coord_stack_size++;
+
+ do
+ {
+ coord_stack_size--;
+ x = coord_stack[coord_stack_size][0];
+ y = coord_stack[coord_stack_size][1];
+ x1 = x2 = x;
+ // go left as far as possible
+ while (x1>=CELL)
+ {
+ if ((pmap[y][x1-1]&0xFF)!=cm || parts[pmap[y][x1-1]>>8].life!=0)
+ {
+ break;
+ }
+ x1--;
+ }
+ // go right as far as possible
+ while (x2<XRES-CELL)
+ {
+ if ((pmap[y][x2+1]&0xFF)!=cm || parts[pmap[y][x2+1]>>8].life!=0)
+ {
+ break;
+ }
+ x2++;
+ }
+ // fill span
+ for (x=x1; x<=x2; x++)
+ {
+ if (create_part(-1, x, y, fullc)>=0)
+ created_something = 1;
+ }
+
+ // add vertically adjacent pixels to stack
+ // (wire crossing for INST)
+ if (y>=CELL+1 && x1==x2 &&
+ PMAP_CMP_CONDUCTIVE(pmap[y-1][x1-1], cm) && PMAP_CMP_CONDUCTIVE(pmap[y-1][x1], cm) && PMAP_CMP_CONDUCTIVE(pmap[y-1][x1+1], cm) &&
+ !PMAP_CMP_CONDUCTIVE(pmap[y-2][x1-1], cm) && PMAP_CMP_CONDUCTIVE(pmap[y-2][x1], cm) && !PMAP_CMP_CONDUCTIVE(pmap[y-2][x1+1], cm))
+ {
+ // travelling vertically up, skipping a horizontal line
+ if ((pmap[y-2][x1]&0xFF)==cm && !parts[pmap[y-2][x1]>>8].life)
+ {
+ coord_stack[coord_stack_size][0] = x1;
+ coord_stack[coord_stack_size][1] = y-2;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ free(coord_stack);
+ return -1;
+ }
+ }
+ }
+ else if (y>=CELL+1)
+ {
+ for (x=x1; x<=x2; x++)
+ {
+ if ((pmap[y-1][x]&0xFF)==cm && !parts[pmap[y-1][x]>>8].life)
+ {
+ if (x==x1 || x==x2 || y>=YRES-CELL-1 || !PMAP_CMP_CONDUCTIVE(pmap[y+1][x], cm))
+ {
+ // if at the end of a horizontal section, or if it's a T junction
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y-1;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ free(coord_stack);
+ return -1;
+ }
+ }
+ }
+ }
+ }
+
+ if (y<YRES-CELL-1 && x1==x2 &&
+ PMAP_CMP_CONDUCTIVE(pmap[y+1][x1-1], cm) && PMAP_CMP_CONDUCTIVE(pmap[y+1][x1], cm) && PMAP_CMP_CONDUCTIVE(pmap[y+1][x1+1], cm) &&
+ !PMAP_CMP_CONDUCTIVE(pmap[y+2][x1-1], cm) && PMAP_CMP_CONDUCTIVE(pmap[y+2][x1], cm) && !PMAP_CMP_CONDUCTIVE(pmap[y+2][x1+1], cm))
+ {
+ // travelling vertically down, skipping a horizontal line
+ if ((pmap[y+2][x1]&0xFF)==cm && !parts[pmap[y+2][x1]>>8].life)
+ {
+ coord_stack[coord_stack_size][0] = x1;
+ coord_stack[coord_stack_size][1] = y+2;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ free(coord_stack);
+ return -1;
+ }
+ }
+ }
+ else if (y<YRES-CELL-1)
+ {
+ for (x=x1; x<=x2; x++)
+ {
+ if ((pmap[y+1][x]&0xFF)==cm && !parts[pmap[y+1][x]>>8].life)
+ {
+ if (x==x1 || x==x2 || y<0 || !PMAP_CMP_CONDUCTIVE(pmap[y-1][x], cm))
+ {
+ // if at the end of a horizontal section, or if it's a T junction
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y+1;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ free(coord_stack);
+ return -1;
+ }
+ }
+
+ }
+ }
+ }
+ } while (coord_stack_size>0);
+ free(coord_stack);
+ return created_something;
+}
+
+
+int Simulation::FloodParts(int x, int y, int fullc, int cm, int bm, int flags)
+{
+ int c = fullc&0xFF;
+ int x1, x2, dy = (c<PT_NUM)?1:CELL;
+ int co = c;
+ int coord_stack_limit = XRES*YRES;
+ unsigned short (*coord_stack)[2];
+ int coord_stack_size = 0;
+ int created_something = 0;
+
+ if (c==SPC_PROP)
+ return 0;
+ if (cm==-1)
+ {
+ if (c==0)
+ {
+ cm = pmap[y][x]&0xFF;
+ if (!cm)
+ return 0;
+ }
+ else
+ cm = 0;
+ }
+ if (bm==-1)
+ {
+ bm = bmap[y/CELL][x/CELL];
+ }
+
+ if (((pmap[y][x]&0xFF)!=cm || bmap[y/CELL][x/CELL]!=bm ))
+ return 1;
+
+ coord_stack = (short unsigned int (*)[2])malloc(sizeof(unsigned short)*2*coord_stack_limit);
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y;
+ coord_stack_size++;
+
+ do
+ {
+ coord_stack_size--;
+ x = coord_stack[coord_stack_size][0];
+ y = coord_stack[coord_stack_size][1];
+ x1 = x2 = x;
+ // go left as far as possible
+ while (x1>=CELL)
+ {
+ if ((pmap[y][x1-1]&0xFF)!=cm || bmap[y/CELL][(x1-1)/CELL]!=bm)
+ {
+ break;
+ }
+ x1--;
+ }
+ // go right as far as possible
+ while (x2<XRES-CELL)
+ {
+ if ((pmap[y][x2+1]&0xFF)!=cm || bmap[y/CELL][(x2+1)/CELL]!=bm)
+ {
+ break;
+ }
+ x2++;
+ }
+ // fill span
+ for (x=x1; x<=x2; x++)
+ {
+ if (CreateParts(x, y, 0, 0, fullc, flags))
+ created_something = 1;
+ }
+
+ if (y>=CELL+dy)
+ for (x=x1; x<=x2; x++)
+ if ((pmap[y-dy][x]&0xFF)==cm && bmap[(y-dy)/CELL][x/CELL]==bm)
+ {
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y-dy;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ free(coord_stack);
+ return -1;
+ }
+ }
+
+ if (y<YRES-CELL-dy)
+ for (x=x1; x<=x2; x++)
+ if ((pmap[y+dy][x]&0xFF)==cm && bmap[(y+dy)/CELL][x/CELL]==bm)
+ {
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y+dy;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ free(coord_stack);
+ return -1;
+ }
+ }
+ } while (coord_stack_size>0);
+ free(coord_stack);
+ return created_something;
+}
+
+int Simulation::FloodWalls(int x, int y, int c, int cm, int bm, int flags)
+{
+ int x1, x2, dy = CELL;
+ int co = c;
+ if (cm==-1)
+ {
+ cm = pmap[y][x]&0xFF;
+ }
+ if (bm==-1)
+ {
+ if (c==WL_ERASE)
+ {
+ bm = bmap[y/CELL][x/CELL];
+ if (!bm)
+ return 0;
+ }
+ else
+ bm = 0;
+ }
+
+ if (((pmap[y][x]&0xFF)!=cm || bmap[y/CELL][x/CELL]!=bm )/*||( (flags&BRUSH_SPECIFIC_DELETE) && cm!=SLALT)*/)
+ return 1;
+
+ // go left as far as possible
+ x1 = x2 = x;
+ while (x1>=CELL)
+ {
+ if ((pmap[y][x1-1]&0xFF)!=cm || bmap[y/CELL][(x1-1)/CELL]!=bm)
+ {
+ break;
+ }
+ x1--;
+ }
+ while (x2<XRES-CELL)
+ {
+ if ((pmap[y][x2+1]&0xFF)!=cm || bmap[y/CELL][(x2+1)/CELL]!=bm)
+ {
+ break;
+ }
+ x2++;
+ }
+
+ // fill span
+ for (x=x1; x<=x2; x++)
+ {
+ if (!CreateWalls(x, y, 0, 0, c, flags))
+ return 0;
+ }
+ // fill children
+ if (y>=CELL+dy)
+ for (x=x1; x<=x2; x++)
+ if ((pmap[y-dy][x]&0xFF)==cm && bmap[(y-dy)/CELL][x/CELL]==bm)
+ if (!FloodWalls(x, y-dy, c, cm, bm, flags))
+ return 0;
+ if (y<YRES-CELL-dy)
+ for (x=x1; x<=x2; x++)
+ if ((pmap[y+dy][x]&0xFF)==cm && bmap[(y+dy)/CELL][x/CELL]==bm)
+ if (!FloodWalls(x, y+dy, c, cm, bm, flags))
+ return 0;
+ return 1;
+}
+int Simulation::flood_water(int x, int y, int i, int originaly, int check)
+{
+ int x1 = 0,x2 = 0;
+ // go left as far as possible
+ x1 = x2 = x;
+ if (!pmap[y][x])
+ return 1;
+
+ while (x1>=CELL)
+ {
+ if ((elements[(pmap[y][x1-1]&0xFF)].Falldown)!=2)
+ {
+ break;
+ }
+ x1--;
+ }
+ while (x2<XRES-CELL)
+ {
+ if ((elements[(pmap[y][x2+1]&0xFF)].Falldown)!=2)
+ {
+ break;
+ }
+ x2++;
+ }
+
+ // fill span
+ for (x=x1; x<=x2; x++)
+ {
+ parts[pmap[y][x]>>8].tmp2 = !check;//flag it as checked, maybe shouldn't use .tmp2
+ //check above, maybe around other sides too?
+ if ( ((y-1) > originaly) && !pmap[y-1][x] && eval_move(parts[i].type, x, y-1, NULL))
+ {
+ int oldx = (int)(parts[i].x + 0.5f);
+ int oldy = (int)(parts[i].y + 0.5f);
+ pmap[y-1][x] = pmap[oldy][oldx];
+ pmap[oldy][oldx] = 0;
+ parts[i].x = x;
+ parts[i].y = y-1;
+ return 0;
+ }
+ }
+ // fill children
+
+ if (y>=CELL+1)
+ for (x=x1; x<=x2; x++)
+ if ((elements[(pmap[y-1][x]&0xFF)].Falldown)==2 && parts[pmap[y-1][x]>>8].tmp2 == check)
+ if (!flood_water(x, y-1, i, originaly, check))
+ return 0;
+ if (y<YRES-CELL-1)
+ for (x=x1; x<=x2; x++)
+ if ((elements[(pmap[y+1][x]&0xFF)].Falldown)==2 && parts[pmap[y+1][x]>>8].tmp2 == check)
+ if (!flood_water(x, y+1, i, originaly, check))
+ return 0;
+ return 1;
+}
+
+//wrapper around create_part to create TESC with correct tmp value
+int Simulation::create_part_add_props(int p, int x, int y, int tv, int rx, int ry)
+{
+ p=create_part(p, x, y, tv);
+ if (tv==PT_TESC)
+ {
+ parts[p].tmp=rx*4+ry*4+7;
+ if (parts[p].tmp>300)
+ parts[p].tmp=300;
+ }
+ return p;
+}
+
+void Simulation::SetEdgeMode(int newEdgeMode)
+{
+ edgeMode = newEdgeMode;
+ switch(edgeMode)
+ {
+ case 0:
+ for(int i = 0; i<(XRES/CELL); i++)
+ {
+ bmap[0][i] = 0;
+ bmap[YRES/CELL-1][i] = 0;
+ }
+ for(int i = 1; i<((YRES/CELL)-1); i++)
+ {
+ bmap[i][0] = 0;
+ bmap[i][XRES/CELL-1] = 0;
+ }
+ break;
+ case 1:
+ int i;
+ for(i=0; i<(XRES/CELL); i++)
+ {
+ bmap[0][i] = WL_WALL;
+ bmap[YRES/CELL-1][i] = WL_WALL;
+ }
+ for(i=1; i<((YRES/CELL)-1); i++)
+ {
+ bmap[i][0] = WL_WALL;
+ bmap[i][XRES/CELL-1] = WL_WALL;
+ }
+ break;
+ default:
+ SetEdgeMode(0);
+ }
+}
+
+void Simulation::ApplyDecoration(int x, int y, int colR_, int colG_, int colB_, int colA_, int mode)
+{
+ int rp;
+ float tr, tg, tb, ta, colR = colR_, colG = colG_, colB = colB_, colA = colA_;
+ float strength = 0.01f;
+ rp = pmap[y][x];
+ if (!rp)
+ return;
+
+ ta = (parts[rp>>8].dcolour>>24)&0xFF;
+ tr = (parts[rp>>8].dcolour>>16)&0xFF;
+ tg = (parts[rp>>8].dcolour>>8)&0xFF;
+ tb = (parts[rp>>8].dcolour)&0xFF;
+
+ ta /= 255.0f; tr /= 255.0f; tg /= 255.0f; tb /= 255.0f;
+ colR /= 255.0f; colG /= 255.0f; colB /= 255.0f; colA /= 255.0f;
+
+ if (mode == DECO_DRAW)
+ {
+ ta = colA;
+ tr = colR;
+ tg = colG;
+ tb = colB;
+ }
+ else if (mode == DECO_CLEAR)
+ {
+ ta = tr = tg = tb = 0.0f;
+ }
+ else if (mode == DECO_ADD)
+ {
+ //ta += (colA*strength)*colA;
+ tr += (colR*strength)*colA;
+ tg += (colG*strength)*colA;
+ tb += (colB*strength)*colA;
+ }
+ else if (mode == DECO_SUBTRACT)
+ {
+ //ta -= (colA*strength)*colA;
+ tr -= (colR*strength)*colA;
+ tg -= (colG*strength)*colA;
+ tb -= (colB*strength)*colA;
+ }
+ else if (mode == DECO_MULTIPLY)
+ {
+ tr *= 1.0f+(colR*strength)*colA;
+ tg *= 1.0f+(colG*strength)*colA;
+ tb *= 1.0f+(colB*strength)*colA;
+ }
+ else if (mode == DECO_DIVIDE)
+ {
+ tr /= 1.0f+(colR*strength)*colA;
+ tg /= 1.0f+(colG*strength)*colA;
+ tb /= 1.0f+(colB*strength)*colA;
+ }
+ else if (mode == DECO_SMUDGE)
+ {
+ float tas = 0.0f, trs = 0.0f, tgs = 0.0f, tbs = 0.0f;
+
+ int rx, ry;
+ float num = 0;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ {
+ if ((pmap[y+ry][x+rx]&0xFF) && parts[pmap[y+ry][x+rx]>>8].dcolour)
+ {
+ Particle part = parts[pmap[y+ry][x+rx]>>8];
+ num += 1.0f;
+ tas += ((float)((part.dcolour>>24)&0xFF))/255.0f;
+ trs += ((float)((part.dcolour>>16)&0xFF))/255.0f;
+ tgs += ((float)((part.dcolour>>8)&0xFF))/255.0f;
+ tbs += ((float)((part.dcolour)&0xFF))/255.0f;
+ }
+ }
+ if (num == 0)
+ return;
+ ta = ((tas/num));//*0.8f) + (ta*0.2f);
+ tr = ((trs/num));//*0.8f) + (tr*0.2f);
+ tg = ((tgs/num));//*0.8f) + (tg*0.2f);
+ tb = ((tbs/num));//*0.8f) + (tb*0.2f);
+ }
+
+ ta *= 255.0f; tr *= 255.0f; tg *= 255.0f; tb *= 255.0f;
+ ta += .5f; tr += .5f; tg += .5f; tb += .5f;
+
+ colA_ = ta;
+ colR_ = tr;
+ colG_ = tg;
+ colB_ = tb;
+
+ if(colA_ > 255)
+ colA_ = 255;
+ else if(colA_ < 0)
+ colA_ = 0;
+ if(colR_ > 255)
+ colR_ = 255;
+ else if(colR_ < 0)
+ colR_ = 0;
+ if(colG_ > 255)
+ colG_ = 255;
+ else if(colG_ < 0)
+ colG_ = 0;
+ if(colB_ > 255)
+ colB_ = 255;
+ else if(colB_ < 0)
+ colB_ = 0;
+ parts[rp>>8].dcolour = ((colA_<<24)|(colR_<<16)|(colG_<<8)|colB_);
+}
+
+void Simulation::ApplyDecorationPoint(int positionX, int positionY, int colR, int colG, int colB, int colA, int mode, Brush * cBrush)
+{
+ int i, j;
+
+ if(cBrush)
+ {
+ int radiusX, radiusY, sizeX, sizeY;
+
+ radiusX = cBrush->GetRadius().X;
+ radiusY = cBrush->GetRadius().Y;
+
+ sizeX = cBrush->GetSize().X;
+ sizeY = cBrush->GetSize().Y;
+
+ unsigned char *bitmap = cBrush->GetBitmap();
+ for(int y = 0; y < sizeY; y++)
+ {
+ for(int x = 0; x < sizeX; x++)
+ {
+ if(bitmap[(y*sizeX)+x] && (positionX+(x-radiusX) >= 0 && positionY+(y-radiusY) >= 0 && positionX+(x-radiusX) < XRES && positionY+(y-radiusY) < YRES))
+ {
+ ApplyDecoration(positionX+(x-radiusX), positionY+(y-radiusY), colR, colG, colB, colA, mode);
+ }
+ }
+ }
+ }
+}
+
+void Simulation::ApplyDecorationBox(int x1, int y1, int x2, int y2, int colR, int colG, int colB, int colA, int mode)
+{
+ int i, j;
+
+ if (x1>x2)
+ {
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ if (y1>y2)
+ {
+ j = y2;
+ y2 = y1;
+ y1 = j;
+ }
+ for (j=y1; j<=y2; j++)
+ for (i=x1; i<=x2; i++)
+ ApplyDecoration(i, j, colR, colG, colB, colA, mode);
+}
+
+void Simulation::ApplyDecorationLine(int x1, int y1, int x2, int y2, int colR, int colG, int colB, int colA, int mode, Brush * cBrush)
+{
+ int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy, rx, ry;
+ float e, de;
+
+ if(cBrush)
+ {
+ rx = cBrush->GetRadius().X;
+ ry = cBrush->GetRadius().Y;
+ }
+
+ if (cp)
+ {
+ y = x1;
+ x1 = y1;
+ y1 = y;
+ y = x2;
+ x2 = y2;
+ y2 = y;
+ }
+ if (x1 > x2)
+ {
+ y = x1;
+ x1 = x2;
+ x2 = y;
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+ e = 0.0f;
+ if (dx)
+ de = dy/(float)dx;
+ else
+ de = 0.0f;
+ y = y1;
+ sy = (y1<y2) ? 1 : -1;
+ for (x=x1; x<=x2; x++)
+ {
+ if (cp)
+ ApplyDecorationPoint(y, x, colR, colG, colB, colA, mode, cBrush);
+ else
+ ApplyDecorationPoint(x, y, colR, colG, colB, colA, mode, cBrush);
+ e += de;
+ if (e >= 0.5f)
+ {
+ y += sy;
+ if (!(rx+ry))
+ {
+ if (cp)
+ ApplyDecorationPoint(y, x, colR, colG, colB, colA, mode, cBrush);
+ else
+ ApplyDecorationPoint(x, y, colR, colG, colB, colA, mode, cBrush);
+ }
+ e -= 1.0f;
+ }
+ }
+}
+
+int Simulation::Tool(int x, int y, int tool, float strength)
+{
+ if(tools[tool])
+ {
+ Particle * cpart = NULL;
+ int r;
+ if(r = pmap[y][x])
+ cpart = &(parts[r>>8]);
+ else if(r = photons[y][x])
+ cpart = &(parts[r>>8]);
+ return tools[tool]->Perform(this, cpart, x, y, strength);
+ }
+ return 0;
+}
+
+int Simulation::ToolBrush(int positionX, int positionY, int tool, Brush * cBrush, float strength)
+{
+ if(cBrush)
+ {
+ int radiusX, radiusY, sizeX, sizeY;
+
+ radiusX = cBrush->GetRadius().X;
+ radiusY = cBrush->GetRadius().Y;
+
+ sizeX = cBrush->GetSize().X;
+ sizeY = cBrush->GetSize().Y;
+ unsigned char *bitmap = cBrush->GetBitmap();
+ for(int y = 0; y < sizeY; y++)
+ for(int x = 0; x < sizeX; x++)
+ if(bitmap[(y*sizeX)+x] && (positionX+(x-radiusX) >= 0 && positionY+(y-radiusY) >= 0 && positionX+(x-radiusX) < XRES && positionY+(y-radiusY) < YRES))
+ Tool(positionX+(x-radiusX), positionY+(y-radiusY), tool, strength);
+ }
+ return 0;
+}
+
+void Simulation::ToolLine(int x1, int y1, int x2, int y2, int tool, Brush * cBrush, float strength)
+{
+ int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy, rx, ry;
+ float e, de;
+ rx = cBrush->GetRadius().X;
+ ry = cBrush->GetRadius().Y;
+ if (cp)
+ {
+ y = x1;
+ x1 = y1;
+ y1 = y;
+ y = x2;
+ x2 = y2;
+ y2 = y;
+ }
+ if (x1 > x2)
+ {
+ y = x1;
+ x1 = x2;
+ x2 = y;
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+ e = 0.0f;
+ if (dx)
+ de = dy/(float)dx;
+ else
+ de = 0.0f;
+ y = y1;
+ sy = (y1<y2) ? 1 : -1;
+ for (x=x1; x<=x2; x++)
+ {
+ if (cp)
+ ToolBrush(y, x, tool, cBrush, strength);
+ else
+ ToolBrush(x, y, tool, cBrush, strength);
+ e += de;
+ if (e >= 0.5f)
+ {
+ y += sy;
+ if ((!(rx+ry)) && ((y1<y2) ? (y<=y2) : (y>=y2)))
+ {
+ if (cp)
+ ToolBrush(y, x, tool, cBrush, strength);
+ else
+ ToolBrush(x, y, tool, cBrush, strength);
+ }
+ e -= 1.0f;
+ }
+ }
+}
+void Simulation::ToolBox(int x1, int y1, int x2, int y2, int tool, Brush * cBrush, float strength)
+{
+ int i, j;
+ if (x1>x2)
+ {
+ i = x2;
+ x2 = x1;
+ x1 = i;
+ }
+ if (y1>y2)
+ {
+ j = y2;
+ y2 = y1;
+ y1 = j;
+ }
+ for (j=y1; j<=y2; j++)
+ for (i=x1; i<=x2; i++)
+ Tool(i, j, tool, strength);
+}
+
+int Simulation::CreateParts(int positionX, int positionY, int c, Brush * cBrush)
+{
+ if(cBrush)
+ {
+ int radiusX, radiusY, sizeX, sizeY;
+
+ radiusX = cBrush->GetRadius().X;
+ radiusY = cBrush->GetRadius().Y;
+
+ sizeX = cBrush->GetSize().X;
+ sizeY = cBrush->GetSize().Y;
+
+ unsigned char *bitmap = cBrush->GetBitmap();
+
+ if(c == PT_NONE)
+ {
+ for(int y = 0; y < sizeY; y++)
+ {
+ for(int x = 0; x < sizeX; x++)
+ {
+ if(bitmap[(y*sizeX)+x] && (positionX+(x-radiusX) >= 0 && positionY+(y-radiusY) >= 0 && positionX+(x-radiusX) < XRES && positionY+(y-radiusY) < YRES))
+ {
+ delete_part(positionX+(x-radiusX), positionY+(y-radiusY), 0);
+ }
+ }
+ }
+ }
+ else
+ {
+ for(int y = 0; y < sizeY; y++)
+ {
+ for(int x = 0; x < sizeX; x++)
+ {
+ if(bitmap[(y*sizeX)+x] && (positionX+(x-radiusX) >= 0 && positionY+(y-radiusY) >= 0 && positionX+(x-radiusX) < XRES && positionY+(y-radiusY) < YRES))
+ {
+ create_part(-2, positionX+(x-radiusX), positionY+(y-radiusY), c);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int Simulation::CreateParts(int x, int y, int rx, int ry, int c, int flags)
+{
+ int i, j, r, f = 0, u, v, oy, ox, b = 0, dw = 0, stemp = 0, p;
+ int wall = c - 100;
+ if (c==SPC_WIND || c==PT_FIGH)
+ return 0;
+
+ if (c==PT_LIGH)
+ {
+ if (lighting_recreate>0 && rx+ry>0)
+ return 0;
+ p=create_part(-2, x, y, c);
+ if (p!=-1)
+ {
+ parts[p].life=rx+ry;
+ if (parts[p].life>55)
+ parts[p].life=55;
+ parts[p].temp=parts[p].life*150; // temperature of the lighting shows the power of the lighting
+ lighting_recreate+=parts[p].life/2+1;
+ return 1;
+ }
+ else return 0;
+ }
+
+ //eraser
+ if (c == 0)
+ {
+ if (rx==0&&ry==0)
+ {
+ delete_part(x, y, 0);
+ }
+ else
+ {
+ for (j=-ry; j<=ry; j++)
+ for (i=-rx; i<=rx; i++)
+ delete_part(x+i, y+j, 0);
+ }
+ return 1;
+ }
+
+ if (c == SPC_AIR || c == SPC_HEAT || c == SPC_COOL || c == SPC_VACUUM || c == SPC_PGRV || c == SPC_NGRV)
+ {
+ if (rx==0&&ry==0)
+ {
+ create_part(-2, x, y, c);
+ }
+ else
+ {
+ for (j=-ry; j<=ry; j++)
+ for (i=-rx; i<=rx; i++)
+ {
+ if ( x+i<0 || y+j<0 || x+i>=XRES || y+j>=YRES)
+ continue;
+ create_part(-2, x+i, y+j, c);
+ }
+ }
+ return 1;
+ }
+
+ //else, no special modes, draw element like normal.
+ if (rx==0&&ry==0)//workaround for 1pixel brush/floodfill crashing. todo: find a better fix later.
+ {
+ if (create_part_add_props(-2, x, y, c, rx, ry)==-1)
+ f = 1;
+ }
+ else
+ {
+ for (j=-ry; j<=ry; j++)
+ for (i=-rx; i<=rx; i++)
+ if (create_part_add_props(-2, x+i, y+j, c, rx, ry)==-1)
+ f = 1;
+ }
+ return !f;
+}
+
+int Simulation::CreateWalls(int x, int y, int rx, int ry, int c, int flags, Brush * cBrush)
+{
+ int i, j, r, f = 0, u, v, oy, ox, b = 0, dw = 0, stemp = 0, p;//n;
+
+ if(cBrush)
+ {
+ rx = cBrush->GetRadius().X;
+ ry = cBrush->GetRadius().Y;
+ }
+
+ int wall = c;
+
+ if (wall == WL_ERASE)
+ b = 0;
+ else
+ b = wall;
+
+ ry = ry/CELL;
+ rx = rx/CELL;
+ x = x/CELL;
+ y = y/CELL;
+ x -= rx;///2;
+ y -= ry;///2;
+ for (ox=x; ox<=x+rx+rx; ox++)
+ {
+ for (oy=y; oy<=y+ry+ry; oy++)
+ {
+ if (ox>=0&&ox<XRES/CELL&&oy>=0&&oy<YRES/CELL)
+ {
+ i = ox;
+ j = oy;
+ if (b==WL_FAN)
+ {
+ fvx[j][i] = 0.0f;
+ fvy[j][i] = 0.0f;
+ }
+ if (b==WL_GRAV || bmap[j][i]==WL_GRAV)
+ {
+ gravWallChanged = true;
+ }
+ if (b==WL_STREAM)
+ {
+ i = x + rx;///2;
+ j = y + ry;///2;
+ for (v=-1; v<2; v++)
+ for (u=-1; u<2; u++)
+ if (i+u>=0 && i+u<XRES/CELL &&
+ j+v>=0 && j+v<YRES/CELL &&
+ bmap[j+v][i+u] == WL_STREAM)
+ return 1;
+ bmap[j][i] = WL_STREAM;
+ continue;
+ }
+ bmap[j][i] = b;
+ }
+ }
+ }
+ return 1;
+}
+
+void Simulation::CreateLine(int x1, int y1, int x2, int y2, int c, Brush * cBrush)
+{
+ int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy, rx, ry;
+ rx = cBrush->GetRadius().X;
+ ry = cBrush->GetRadius().Y;
+ float e, de;
+ if (c==SPC_PROP)
+ return;
+ if (cp)
+ {
+ y = x1;
+ x1 = y1;
+ y1 = y;
+ y = x2;
+ x2 = y2;
+ y2 = y;
+ }
+ if (x1 > x2)
+ {
+ y = x1;
+ x1 = x2;
+ x2 = y;
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+ e = 0.0f;
+ if (dx)
+ de = dy/(float)dx;
+ else
+ de = 0.0f;
+ y = y1;
+ sy = (y1<y2) ? 1 : -1;
+ for (x=x1; x<=x2; x++)
+ {
+ if (cp)
+ CreateParts(y, x, c, cBrush);
+ else
+ CreateParts(x, y, c, cBrush);
+ e += de;
+ if (e >= 0.5f)
+ {
+ y += sy;
+ if ((c==WL_EHOLE+100 || c==WL_ALLOWGAS+100 || c==WL_ALLOWENERGY+100 || c==WL_ALLOWALLELEC+100 || c==WL_ALLOWSOLID+100 || c==WL_ALLOWAIR+100 || c==WL_WALL+100 || c==WL_DESTROYALL+100 || c==WL_ALLOWLIQUID+100 || c==WL_FAN+100 || c==WL_STREAM+100 || c==WL_DETECT+100 || c==WL_EWALL+100 || c==WL_WALLELEC+100 || !(rx+ry))
+ && ((y1<y2) ? (y<=y2) : (y>=y2)))
+ {
+ if (cp)
+ CreateParts(y, x, c, cBrush);
+ else
+ CreateParts(x, y, c, cBrush);
+ }
+ e -= 1.0f;
+ }
+ }
+}
+
+void Simulation::CreateLine(int x1, int y1, int x2, int y2, int rx, int ry, int c, int flags)
+{
+ int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy;
+ float e, de;
+ if (c==SPC_PROP)
+ return;
+ if (cp)
+ {
+ y = x1;
+ x1 = y1;
+ y1 = y;
+ y = x2;
+ x2 = y2;
+ y2 = y;
+ }
+ if (x1 > x2)
+ {
+ y = x1;
+ x1 = x2;
+ x2 = y;
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+ e = 0.0f;
+ if (dx)
+ de = dy/(float)dx;
+ else
+ de = 0.0f;
+ y = y1;
+ sy = (y1<y2) ? 1 : -1;
+ for (x=x1; x<=x2; x++)
+ {
+ if (cp)
+ CreateParts(y, x, rx, ry, c, flags);
+ else
+ CreateParts(x, y, rx, ry, c, flags);
+ e += de;
+ if (e >= 0.5f)
+ {
+ y += sy;
+ if ((c==WL_EHOLE+100 || c==WL_ALLOWGAS+100 || c==WL_ALLOWENERGY+100 || c==WL_ALLOWALLELEC+100 || c==WL_ALLOWSOLID+100 || c==WL_ALLOWAIR+100 || c==WL_WALL+100 || c==WL_DESTROYALL+100 || c==WL_ALLOWLIQUID+100 || c==WL_FAN+100 || c==WL_STREAM+100 || c==WL_DETECT+100 || c==WL_EWALL+100 || c==WL_WALLELEC+100 || !(rx+ry))
+ && ((y1<y2) ? (y<=y2) : (y>=y2)))
+ {
+ if (cp)
+ CreateParts(y, x, rx, ry, c, flags);
+ else
+ CreateParts(x, y, rx, ry, c, flags);
+ }
+ e -= 1.0f;
+ }
+ }
+}
+
+void Simulation::CreateWallLine(int x1, int y1, int x2, int y2, int rx, int ry, int c, int flags, Brush * cBrush)
+{
+ int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy;
+ float e, de;
+ if (cp)
+ {
+ y = x1;
+ x1 = y1;
+ y1 = y;
+ y = x2;
+ x2 = y2;
+ y2 = y;
+ }
+ if (x1 > x2)
+ {
+ y = x1;
+ x1 = x2;
+ x2 = y;
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+ e = 0.0f;
+ if (dx)
+ de = dy/(float)dx;
+ else
+ de = 0.0f;
+ y = y1;
+ sy = (y1<y2) ? 1 : -1;
+ for (x=x1; x<=x2; x++)
+ {
+ if (cp)
+ CreateWalls(y, x, rx, ry, c, flags, cBrush);
+ else
+ CreateWalls(x, y, rx, ry, c, flags, cBrush);
+ e += de;
+ if (e >= 0.5f)
+ {
+ y += sy;
+ if (!(rx+ry) && ((y1<y2) ? (y<=y2) : (y>=y2)))
+ {
+ if (cp)
+ CreateWalls(y, x, rx, ry, c, flags, cBrush);
+ else
+ CreateWalls(x, y, rx, ry, c, flags, cBrush);
+ }
+ e -= 1.0f;
+ }
+ }
+}
+
+void *Simulation::transform_save(void *odata, int *size, matrix2d transform, vector2d translate)
+{
+ void *ndata;
+ unsigned char (*bmapo)[XRES/CELL] = (unsigned char (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(unsigned char));
+ unsigned char (*bmapn)[XRES/CELL] = (unsigned char (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(unsigned char));
+ Particle *partst = (Particle*)calloc(sizeof(Particle), NPART);
+ sign *signst = (sign*)calloc(MAXSIGNS, sizeof(sign));
+ unsigned (*pmapt)[XRES] = (unsigned (*)[XRES])calloc(YRES*XRES, sizeof(unsigned));
+ float (*fvxo)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*fvyo)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*fvxn)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*fvyn)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*vxo)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*vyo)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*vxn)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*vyn)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*pvo)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ float (*pvn)[XRES/CELL] = (float (*)[XRES/CELL])calloc((YRES/CELL)*(XRES/CELL), sizeof(float));
+ int i, x, y, nx, ny, w, h, nw, nh;
+ vector2d pos, tmp, ctl, cbr;
+ vector2d vel;
+ vector2d cornerso[4];
+ unsigned char *odatac = (unsigned char *)odata;
+ //if (parse_save(odata, *size, 0, 0, 0, bmapo, vxo, vyo, pvo, fvxo, fvyo, signst, partst, pmapt)) //TODO: Implement
+ {
+ free(bmapo);
+ free(bmapn);
+ free(partst);
+ free(signst);
+ free(pmapt);
+ free(fvxo);
+ free(fvyo);
+ free(fvxn);
+ free(fvyn);
+ free(vxo);
+ free(vyo);
+ free(vxn);
+ free(vyn);
+ free(pvo);
+ free(pvn);
+ return odata;
+ }
+ w = odatac[6]*CELL;
+ h = odatac[7]*CELL;
+ // undo any translation caused by rotation
+ cornerso[0] = v2d_new(0,0);
+ cornerso[1] = v2d_new(w-1,0);
+ cornerso[2] = v2d_new(0,h-1);
+ cornerso[3] = v2d_new(w-1,h-1);
+ for (i=0; i<4; i++)
+ {
+ tmp = m2d_multiply_v2d(transform,cornerso[i]);
+ if (i==0) ctl = cbr = tmp; // top left, bottom right corner
+ if (tmp.x<ctl.x) ctl.x = tmp.x;
+ if (tmp.y<ctl.y) ctl.y = tmp.y;
+ if (tmp.x>cbr.x) cbr.x = tmp.x;
+ if (tmp.y>cbr.y) cbr.y = tmp.y;
+ }
+ // casting as int doesn't quite do what we want with negative numbers, so use floor()
+ tmp = v2d_new(floor(ctl.x+0.5f),floor(ctl.y+0.5f));
+ translate = v2d_sub(translate,tmp);
+ nw = floor(cbr.x+0.5f)-floor(ctl.x+0.5f)+1;
+ nh = floor(cbr.y+0.5f)-floor(ctl.y+0.5f)+1;
+ if (nw>XRES) nw = XRES;
+ if (nh>YRES) nh = YRES;
+ // rotate and translate signs, parts, walls
+ for (i=0; i<MAXSIGNS; i++)
+ {
+ if (!signst[i].text[0]) continue;
+ pos = v2d_new(signst[i].x, signst[i].y);
+ pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
+ nx = floor(pos.x+0.5f);
+ ny = floor(pos.y+0.5f);
+ if (nx<0 || nx>=nw || ny<0 || ny>=nh)
+ {
+ signst[i].text[0] = 0;
+ continue;
+ }
+ signst[i].x = nx;
+ signst[i].y = ny;
+ }
+ for (i=0; i<NPART; i++)
+ {
+ if (!partst[i].type) continue;
+ pos = v2d_new(partst[i].x, partst[i].y);
+ pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
+ nx = floor(pos.x+0.5f);
+ ny = floor(pos.y+0.5f);
+ if (nx<0 || nx>=nw || ny<0 || ny>=nh)
+ {
+ partst[i].type = PT_NONE;
+ continue;
+ }
+ partst[i].x = nx;
+ partst[i].y = ny;
+ vel = v2d_new(partst[i].vx, partst[i].vy);
+ vel = m2d_multiply_v2d(transform, vel);
+ partst[i].vx = vel.x;
+ partst[i].vy = vel.y;
+ }
+ for (y=0; y<YRES/CELL; y++)
+ for (x=0; x<XRES/CELL; x++)
+ {
+ pos = v2d_new(x*CELL+CELL*0.4f, y*CELL+CELL*0.4f);
+ pos = v2d_add(m2d_multiply_v2d(transform,pos),translate);
+ nx = pos.x/CELL;
+ ny = pos.y/CELL;
+ if (nx<0 || nx>=nw/CELL || ny<0 || ny>=nh/CELL)
+ continue;
+ if (bmapo[y][x])
+ {
+ bmapn[ny][nx] = bmapo[y][x];
+ if (bmapo[y][x]==WL_FAN)
+ {
+ vel = v2d_new(fvxo[y][x], fvyo[y][x]);
+ vel = m2d_multiply_v2d(transform, vel);
+ fvxn[ny][nx] = vel.x;
+ fvyn[ny][nx] = vel.y;
+ }
+ }
+ vel = v2d_new(vxo[y][x], vyo[y][x]);
+ vel = m2d_multiply_v2d(transform, vel);
+ vxn[ny][nx] = vel.x;
+ vyn[ny][nx] = vel.y;
+ pvn[ny][nx] = pvo[y][x];
+ }
+ //ndata = build_save(size,0,0,nw,nh,bmapn,vxn,vyn,pvn,fvxn,fvyn,signst,partst); //TODO: IMPLEMENT
+ free(bmapo);
+ free(bmapn);
+ free(partst);
+ free(signst);
+ free(pmapt);
+ free(fvxo);
+ free(fvyo);
+ free(fvxn);
+ free(fvyn);
+ free(vxo);
+ free(vyo);
+ free(vxn);
+ free(vyn);
+ free(pvo);
+ free(pvn);
+ return ndata;
+}
+
+TPT_NO_INLINE void Simulation::orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[])
+{
+ resblock1[0] = (block1&0x000000FF);
+ resblock1[1] = (block1&0x0000FF00)>>8;
+ resblock1[2] = (block1&0x00FF0000)>>16;
+ resblock1[3] = (block1&0xFF000000)>>24;
+
+ resblock2[0] = (block2&0x000000FF);
+ resblock2[1] = (block2&0x0000FF00)>>8;
+ resblock2[2] = (block2&0x00FF0000)>>16;
+ resblock2[3] = (block2&0xFF000000)>>24;
+}
+
+TPT_NO_INLINE void Simulation::orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[])
+{
+ int block1tmp = 0;
+ int block2tmp = 0;
+
+ block1tmp = (resblock1[0]&0xFF);
+ block1tmp |= (resblock1[1]&0xFF)<<8;
+ block1tmp |= (resblock1[2]&0xFF)<<16;
+ block1tmp |= (resblock1[3]&0xFF)<<24;
+
+ block2tmp = (resblock2[0]&0xFF);
+ block2tmp |= (resblock2[1]&0xFF)<<8;
+ block2tmp |= (resblock2[2]&0xFF)<<16;
+ block2tmp |= (resblock2[3]&0xFF)<<24;
+
+ *block1 = block1tmp;
+ *block2 = block2tmp;
+}
+
+inline int Simulation::is_wire(int x, int y)
+{
+ return bmap[y][x]==WL_DETECT || bmap[y][x]==WL_EWALL || bmap[y][x]==WL_ALLOWLIQUID || bmap[y][x]==WL_WALLELEC || bmap[y][x]==WL_ALLOWALLELEC || bmap[y][x]==WL_EHOLE;
+}
+
+inline int Simulation::is_wire_off(int x, int y)
+{
+ return (bmap[y][x]==WL_DETECT || bmap[y][x]==WL_EWALL || bmap[y][x]==WL_ALLOWLIQUID || bmap[y][x]==WL_WALLELEC || bmap[y][x]==WL_ALLOWALLELEC || bmap[y][x]==WL_EHOLE) && emap[y][x]<8;
+}
+
+int Simulation::get_wavelength_bin(int *wm)
+{
+ int i, w0=30, wM=0;
+
+ if (!*wm)
+ return -1;
+
+ for (i=0; i<30; i++)
+ if (*wm & (1<<i)) {
+ if (i < w0)
+ w0 = i;
+ if (i > wM)
+ wM = i;
+ }
+
+ if (wM-w0 < 5)
+ return (wM+w0)/2;
+
+ i = rand() % (wM-w0-3);
+ i += w0;
+
+ *wm &= 0x1F << i;
+ return i + 2;
+}
+
+void Simulation::set_emap(int x, int y)
+{
+ int x1, x2;
+
+ if (!is_wire_off(x, y))
+ return;
+
+ // go left as far as possible
+ x1 = x2 = x;
+ while (x1>0)
+ {
+ if (!is_wire_off(x1-1, y))
+ break;
+ x1--;
+ }
+ while (x2<XRES/CELL-1)
+ {
+ if (!is_wire_off(x2+1, y))
+ break;
+ x2++;
+ }
+
+ // fill span
+ for (x=x1; x<=x2; x++)
+ emap[y][x] = 16;
+
+ // fill children
+
+ if (y>1 && x1==x2 &&
+ is_wire(x1-1, y-1) && is_wire(x1, y-1) && is_wire(x1+1, y-1) &&
+ !is_wire(x1-1, y-2) && is_wire(x1, y-2) && !is_wire(x1+1, y-2))
+ set_emap(x1, y-2);
+ else if (y>0)
+ for (x=x1; x<=x2; x++)
+ if (is_wire_off(x, y-1))
+ {
+ if (x==x1 || x==x2 || y>=YRES/CELL-1 ||
+ is_wire(x-1, y-1) || is_wire(x+1, y-1) ||
+ is_wire(x-1, y+1) || !is_wire(x, y+1) || is_wire(x+1, y+1))
+ set_emap(x, y-1);
+ }
+
+ if (y<YRES/CELL-2 && x1==x2 &&
+ is_wire(x1-1, y+1) && is_wire(x1, y+1) && is_wire(x1+1, y+1) &&
+ !is_wire(x1-1, y+2) && is_wire(x1, y+2) && !is_wire(x1+1, y+2))
+ set_emap(x1, y+2);
+ else if (y<YRES/CELL-1)
+ for (x=x1; x<=x2; x++)
+ if (is_wire_off(x, y+1))
+ {
+ if (x==x1 || x==x2 || y<0 ||
+ is_wire(x-1, y+1) || is_wire(x+1, y+1) ||
+ is_wire(x-1, y-1) || !is_wire(x, y-1) || is_wire(x+1, y-1))
+ set_emap(x, y+1);
+ }
+}
+
+int Simulation::parts_avg(int ci, int ni,int t)
+{
+ if (t==PT_INSL)//to keep electronics working
+ {
+ int pmr = pmap[((int)(parts[ci].y+0.5f) + (int)(parts[ni].y+0.5f))/2][((int)(parts[ci].x+0.5f) + (int)(parts[ni].x+0.5f))/2];
+ if (pmr)
+ return parts[pmr>>8].type;
+ else
+ return PT_NONE;
+ }
+ else
+ {
+ int pmr2 = pmap[(int)((parts[ci].y + parts[ni].y)/2+0.5f)][(int)((parts[ci].x + parts[ni].x)/2+0.5f)];//seems to be more accurate.
+ if (pmr2)
+ {
+ if (parts[pmr2>>8].type==t)
+ return t;
+ }
+ else
+ return PT_NONE;
+ }
+ return PT_NONE;
+}
+
+
+int Simulation::nearest_part(int ci, int t, int max_d)
+{
+ int distance = (max_d!=-1)?max_d:MAX_DISTANCE;
+ int ndistance = 0;
+ int id = -1;
+ int i = 0;
+ int cx = (int)parts[ci].x;
+ int cy = (int)parts[ci].y;
+ for (i=0; i<=parts_lastActiveIndex; i++)
+ {
+ if ((parts[i].type==t||(t==-1&&parts[i].type))&&!parts[i].life&&i!=ci)
+ {
+ ndistance = abs(cx-parts[i].x)+abs(cy-parts[i].y);// Faster but less accurate Older: sqrt(pow(cx-parts[i].x, 2)+pow(cy-parts[i].y, 2));
+ if (ndistance<distance)
+ {
+ distance = ndistance;
+ id = i;
+ }
+ }
+ }
+ return id;
+}
+
+void Simulation::create_arc(int sx, int sy, int dx, int dy, int midpoints, int variance, int type, int flags)
+{
+ int i;
+ float xint, yint;
+ int *xmid, *ymid;
+ int voffset = variance/2;
+ xmid = (int *)calloc(midpoints + 2, sizeof(int));
+ ymid = (int *)calloc(midpoints + 2, sizeof(int));
+ xint = (float)(dx-sx)/(float)(midpoints+1.0f);
+ yint = (float)(dy-sy)/(float)(midpoints+1.0f);
+ xmid[0] = sx;
+ xmid[midpoints+1] = dx;
+ ymid[0] = sy;
+ ymid[midpoints+1] = dy;
+
+ for(i = 1; i <= midpoints; i++)
+ {
+ ymid[i] = ymid[i-1]+yint;
+ xmid[i] = xmid[i-1]+xint;
+ }
+
+ for(i = 0; i <= midpoints; i++)
+ {
+ if(i!=midpoints)
+ {
+ xmid[i+1] += (rand()%variance)-voffset;
+ ymid[i+1] += (rand()%variance)-voffset;
+ }
+ CreateLine(xmid[i], ymid[i], xmid[i+1], ymid[i+1], 0, 0, type, flags);
+ }
+ free(xmid);
+ free(ymid);
+}
+
+void Simulation::clear_sim(void)
+{
+ int i, x, y;
+ emp_decor = 0;
+ signs.clear();
+ memset(bmap, 0, sizeof(bmap));
+ memset(emap, 0, sizeof(emap));
+ memset(parts, 0, sizeof(Particle)*NPART);
+ for (i=0; i<NPART-1; i++)
+ parts[i].life = i+1;
+ parts[NPART-1].life = -1;
+ pfree = 0;
+ parts_lastActiveIndex = 0;
+ memset(pmap, 0, sizeof(pmap));
+ if(fvx)
+ memset(fvx, 0, sizeof(fvx));
+ if(fvy)
+ memset(fvy, 0, sizeof(fvy));
+ memset(photons, 0, sizeof(photons));
+ memset(wireless, 0, sizeof(wireless));
+ memset(gol2, 0, sizeof(gol2));
+ memset(portalp, 0, sizeof(portalp));
+ memset(fighters, 0, sizeof(fighters));
+ std::fill(elementCount, elementCount+PT_NUM, 0);
+ fighcount = 0;
+ player.spwn = 0;
+ player2.spwn = 0;
+ //memset(pers_bg, 0, (XRES+BARSIZE)*YRES*PIXELSIZE);
+ //memset(fire_r, 0, sizeof(fire_r));
+ //memset(fire_g, 0, sizeof(fire_g));
+ //memset(fire_b, 0, sizeof(fire_b));
+ //if(gravmask)
+ //memset(gravmask, 0xFFFFFFFF, (XRES/CELL)*(YRES/CELL)*sizeof(unsigned));
+ if(grav)
+ grav->Clear();
+ if(air)
+ air->Clear();
+ SetEdgeMode(edgeMode);
+}
+void Simulation::init_can_move()
+{
+ // can_move[moving type][type at destination]
+ // 0 = No move/Bounce
+ // 1 = Swap
+ // 2 = Both particles occupy the same space.
+ // 3 = Varies, go run some extra checks
+ int t, rt, stkm_move;
+ for (rt=0;rt<PT_NUM;rt++)
+ can_move[0][rt] = 0; // particles that don't exist shouldn't move...
+ for (t=1;t<PT_NUM;t++)
+ for (rt=0;rt<PT_NUM;rt++)
+ can_move[t][rt] = 1;
+ for (rt=1;rt<PT_NUM;rt++)
+ {
+ can_move[PT_PHOT][rt] = 2;
+ }
+ for (t=1;t<PT_NUM;t++)
+ {
+ for (rt=1;rt<PT_NUM;rt++)
+ {
+ // weight check, also prevents particles of same type displacing each other
+ if (elements[t].Weight <= elements[rt].Weight || rt==PT_GEL) can_move[t][rt] = 0;
+ if (t==PT_NEUT && (elements[rt].Properties&PROP_NEUTPASS))
+ can_move[t][rt] = 2;
+ if (t==PT_NEUT && (elements[rt].Properties&PROP_NEUTABSORB))
+ can_move[t][rt] = 1;
+ if (t==PT_NEUT && (elements[rt].Properties&PROP_NEUTPENETRATE))
+ can_move[t][rt] = 1;
+ if ((elements[t].Properties&PROP_NEUTPENETRATE) && rt==PT_NEUT)
+ can_move[t][rt] = 0;
+ if ((elements[t].Properties&TYPE_ENERGY) && (elements[rt].Properties&TYPE_ENERGY))
+ can_move[t][rt] = 2;
+ }
+ }
+ can_move[PT_DEST][PT_DMND] = 0;
+ can_move[PT_DEST][PT_CLNE] = 0;
+ can_move[PT_DEST][PT_PCLN] = 0;
+ can_move[PT_DEST][PT_BCLN] = 0;
+ can_move[PT_DEST][PT_PBCN] = 0;
+ can_move[PT_BIZR][PT_FILT] = 2;
+ can_move[PT_BIZRG][PT_FILT] = 2;
+ for (t=0;t<PT_NUM;t++)
+ {
+ //spark shouldn't move
+ can_move[PT_SPRK][t] = 0;
+ stkm_move = 0;
+ if (elements[t].Properties & (TYPE_LIQUID | TYPE_GAS))
+ stkm_move = 2;
+ if (!t || t==PT_PRTO || t==PT_SPAWN || t==PT_SPAWN2)
+ stkm_move = 2;
+ can_move[PT_STKM][t] = stkm_move;
+ can_move[PT_STKM2][t] = stkm_move;
+ can_move[PT_FIGH][t] = stkm_move;
+ }
+ for (t=1;t<PT_NUM;t++)
+ {
+ // make them eat things
+ can_move[t][PT_BHOL] = 1;
+ can_move[t][PT_NBHL] = 1;
+ can_move[t][PT_STKM] = 0;
+ can_move[t][PT_STKM2] = 0;
+ can_move[t][PT_FIGH] = 0;
+ //INVIS behaviour varies with pressure
+ can_move[t][PT_INVIS] = 3;
+ //stop CNCT being displaced by other particles
+ can_move[t][PT_CNCT] = 0;
+ //void behaviour varies with powered state and ctype
+ can_move[t][PT_PVOD] = 3;
+ can_move[t][PT_VOID] = 3;
+ can_move[t][PT_EMBR] = 0;
+ can_move[PT_EMBR][t] = 0;
+ if (elements[t].Properties&TYPE_ENERGY)
+ {
+ can_move[t][PT_VIBR] = 1;
+ can_move[t][PT_BVBR] = 1;
+ }
+ }
+ for (t=0;t<PT_NUM;t++)
+ {
+ if (t==PT_GLAS || t==PT_PHOT || t==PT_CLNE || t==PT_PCLN
+ || t==PT_GLOW || t==PT_WATR || t==PT_DSTW || t==PT_SLTW
+ || t==PT_ISOZ || t==PT_ISZS || t==PT_FILT || t==PT_INVIS
+ || t==PT_QRTZ || t==PT_PQRT)
+ can_move[PT_PHOT][t] = 2;
+ }
+ can_move[PT_ELEC][PT_LCRY] = 2;
+ can_move[PT_ELEC][PT_EXOT] = 2;
+ can_move[PT_NEUT][PT_EXOT] = 2;
+ can_move[PT_PHOT][PT_LCRY] = 3;//varies according to LCRY life
+
+ can_move[PT_PHOT][PT_BIZR] = 2;
+ can_move[PT_ELEC][PT_BIZR] = 2;
+ can_move[PT_PHOT][PT_BIZRG] = 2;
+ can_move[PT_ELEC][PT_BIZRG] = 2;
+ can_move[PT_PHOT][PT_BIZRS] = 2;
+ can_move[PT_ELEC][PT_BIZRS] = 2;
+
+ can_move[PT_NEUT][PT_INVIS] = 2;
+ //whol eats anar
+ can_move[PT_ANAR][PT_WHOL] = 1;
+ can_move[PT_ANAR][PT_NWHL] = 1;
+ can_move[PT_ELEC][PT_DEUT] = 1;
+ can_move[PT_THDR][PT_THDR] = 2;
+ can_move[PT_EMBR][PT_EMBR] = 2;
+}
+
+/*
+ RETURN-value explenation
+1 = Swap
+0 = No move/Bounce
+2 = Both particles occupy the same space.
+ */
+int Simulation::eval_move(int pt, int nx, int ny, unsigned *rr)
+{
+ unsigned r;
+ int result;
+
+ if (nx<0 || ny<0 || nx>=XRES || ny>=YRES)
+ return 0;
+
+ r = pmap[ny][nx];
+ if (r)
+ r = (r&~0xFF) | parts[r>>8].type;
+ if (rr)
+ *rr = r;
+ if (pt>=PT_NUM || (r&0xFF)>=PT_NUM)
+ return 0;
+ result = can_move[pt][r&0xFF];
+ if (result==3)
+ {
+ if ((pt==PT_PHOT || pt==PT_ELEC) && (r&0xFF)==PT_LCRY)
+ result = (parts[r>>8].life > 5)? 2 : 0;
+ if ((r&0xFF)==PT_INVIS)
+ {
+ if (pv[ny/CELL][nx/CELL]>4.0f || pv[ny/CELL][nx/CELL]<-4.0f) result = 2;
+ else result = 0;
+ }
+ if ((r&0xFF)==PT_PVOD)
+ {
+ if (parts[r>>8].life == 10)
+ {
+ if(!parts[r>>8].ctype || (parts[r>>8].ctype==pt)!=(parts[r>>8].tmp&1))
+ result = 1;
+ else
+ result = 0;
+ }
+ else result = 0;
+ }
+ if ((r&0xFF)==PT_VOID)
+ {
+ if(!parts[r>>8].ctype || (parts[r>>8].ctype==pt)!=(parts[r>>8].tmp&1))
+ result = 1;
+ else
+ result = 0;
+ }
+ }
+ if (bmap[ny/CELL][nx/CELL])
+ {
+ if (bmap[ny/CELL][nx/CELL]==WL_ALLOWGAS && !(elements[pt].Properties&TYPE_GAS))// && elements[pt].Falldown!=0 && pt!=PT_FIRE && pt!=PT_SMKE)
+ return 0;
+ if (bmap[ny/CELL][nx/CELL]==WL_ALLOWENERGY && !(elements[pt].Properties&TYPE_ENERGY))// && elements[pt].Falldown!=0 && pt!=PT_FIRE && pt!=PT_SMKE)
+ return 0;
+ if (bmap[ny/CELL][nx/CELL]==WL_ALLOWLIQUID && elements[pt].Falldown!=2)
+ return 0;
+ if (bmap[ny/CELL][nx/CELL]==WL_ALLOWSOLID && elements[pt].Falldown!=1)
+ return 0;
+ if (bmap[ny/CELL][nx/CELL]==WL_ALLOWAIR || bmap[ny/CELL][nx/CELL]==WL_WALL || bmap[ny/CELL][nx/CELL]==WL_WALLELEC)
+ return 0;
+ if (bmap[ny/CELL][nx/CELL]==WL_EWALL && !emap[ny/CELL][nx/CELL])
+ return 0;
+ if (bmap[ny/CELL][nx/CELL]==WL_EHOLE && !emap[ny/CELL][nx/CELL] && !(elements[pt].Properties&TYPE_SOLID) && !(elements[r&0xFF].Properties&TYPE_SOLID))
+ return 2;
+ }
+ return result;
+}
+
+int Simulation::try_move(int i, int x, int y, int nx, int ny)
+{
+ unsigned r, e;
+
+ if (x==nx && y==ny)
+ return 1;
+ if (nx<0 || ny<0 || nx>=XRES || ny>=YRES)
+ return 1;
+
+ e = eval_move(parts[i].type, nx, ny, &r);
+
+ /* half-silvered mirror */
+ if (!e && parts[i].type==PT_PHOT &&
+ (((r&0xFF)==PT_BMTL && rand()<RAND_MAX/2) ||
+ (pmap[y][x]&0xFF)==PT_BMTL))
+ e = 2;
+
+ if (!e) //if no movement
+ {
+ if (!(elements[parts[i].type].Properties & TYPE_ENERGY))
+ return 0;
+ if (!legacy_enable && parts[i].type==PT_PHOT && r)//PHOT heat conduction
+ {
+ if ((r & 0xFF) == PT_COAL || (r & 0xFF) == PT_BCOL)
+ parts[r>>8].temp = parts[i].temp;
+
+ if ((r & 0xFF) < PT_NUM && elements[r&0xFF].HeatConduct && ((r&0xFF)!=PT_HSWC||parts[r>>8].life==10) && (r&0xFF)!=PT_FILT)
+ parts[i].temp = parts[r>>8].temp = restrict_flt((parts[r>>8].temp+parts[i].temp)/2, MIN_TEMP, MAX_TEMP);
+ }
+ if ((parts[i].type==PT_NEUT || parts[i].type==PT_ELEC) && ((r&0xFF)==PT_CLNE || (r&0xFF)==PT_PCLN || (r&0xFF)==PT_BCLN || (r&0xFF)==PT_PBCN)) {
+ if (!parts[r>>8].ctype)
+ parts[r>>8].ctype = parts[i].type;
+ }
+ if ((r&0xFF)==PT_PRTI && (elements[parts[i].type].Properties & TYPE_ENERGY))
+ {
+ int nnx, count;
+ for (count=0; count<8; count++)
+ {
+ if (isign(x-nx)==isign(portal_rx[count]) && isign(y-ny)==isign(portal_ry[count]))
+ break;
+ }
+ count = count%8;
+ parts[r>>8].tmp = (int)((parts[r>>8].temp-73.15f)/100+1);
+ if (parts[r>>8].tmp>=CHANNELS) parts[r>>8].tmp = CHANNELS-1;
+ else if (parts[r>>8].tmp<0) parts[r>>8].tmp = 0;
+ for ( nnx=0; nnx<80; nnx++)
+ if (!portalp[parts[r>>8].tmp][count][nnx].type)
+ {
+ portalp[parts[r>>8].tmp][count][nnx] = parts[i];
+ parts[i].type=PT_NONE;
+ break;
+ }
+ }
+ return 0;
+ }
+
+ if (e == 2) //if occupy same space
+ {
+ if (parts[i].type == PT_PHOT && (r&0xFF)==PT_GLOW && !parts[r>>8].life)
+ if (rand() < RAND_MAX/30)
+ {
+ parts[r>>8].life = 120;
+ create_gain_photon(i);
+ }
+ if (parts[i].type == PT_PHOT && (r&0xFF)==PT_FILT)
+ {
+ int temp_bin = (int)((parts[r>>8].temp-273.0f)*0.025f);
+ if (temp_bin < 0) temp_bin = 0;
+ if (temp_bin > 25) temp_bin = 25;
+ if(!parts[r>>8].tmp){
+ parts[i].ctype = 0x1F << temp_bin; //Assign Colour
+ } else if(parts[r>>8].tmp==1){
+ parts[i].ctype &= 0x1F << temp_bin; //Filter Colour
+ } else if(parts[r>>8].tmp==2){
+ parts[i].ctype |= 0x1F << temp_bin; //Add Colour
+ } else if(parts[r>>8].tmp==3){
+ parts[i].ctype &= ~(0x1F << temp_bin); //Subtract Colour
+ }
+ }
+ if (parts[i].type == PT_NEUT && (r&0xFF)==PT_GLAS) {
+ if (rand() < RAND_MAX/10)
+ create_cherenkov_photon(i);
+ }
+ if (parts[i].type == PT_PHOT && (r&0xFF)==PT_INVIS && pv[ny/CELL][nx/CELL]<=4.0f && pv[ny/CELL][nx/CELL]>=-4.0f) {
+ part_change_type(i,x,y,PT_NEUT);
+ parts[i].ctype = 0;
+ }
+ if ((parts[i].type==PT_BIZR||parts[i].type==PT_BIZRG) && (r&0xFF)==PT_FILT)
+ {
+ int temp_bin = (int)((parts[r>>8].temp-273.0f)*0.025f);
+ if (temp_bin < 0) temp_bin = 0;
+ if (temp_bin > 25) temp_bin = 25;
+ parts[i].ctype = 0x1F << temp_bin;
+ }
+ if (((r&0xFF)==PT_BIZR || (r&0xFF)==PT_BIZRG || (r&0xFF)==PT_BIZRS) && parts[i].type==PT_PHOT)
+ {
+ part_change_type(i, x, y, PT_ELEC);
+ parts[i].ctype = 0;
+ }
+ return 1;
+ }
+ //else e=1 , we are trying to swap the particles, return 0 no swap/move, 1 is still overlap/move, because the swap takes place later
+
+ if (parts[i].type == PT_NEUT && (elements[r & 0xFF].Properties & PROP_NEUTABSORB))
+ {
+ kill_part(i);
+ return 0;
+ }
+ if ((r&0xFF)==PT_VOID || (r&0xFF)==PT_PVOD) //this is where void eats particles
+ {
+ //void ctype already checked in eval_move
+ kill_part(i);
+ return 0;
+ }
+ if ((r&0xFF)==PT_BHOL || (r&0xFF)==PT_NBHL) //this is where blackhole eats particles
+ {
+ if (!legacy_enable)
+ {
+ parts[r>>8].temp = restrict_flt(parts[r>>8].temp+parts[i].temp/2, MIN_TEMP, MAX_TEMP);//3.0f;
+ }
+ kill_part(i);
+ return 0;
+ }
+ if (((r&0xFF)==PT_WHOL||(r&0xFF)==PT_NWHL) && parts[i].type==PT_ANAR) //whitehole eats anar
+ {
+ if (!legacy_enable)
+ {
+ parts[r>>8].temp = restrict_flt(parts[r>>8].temp- (MAX_TEMP-parts[i].temp)/2, MIN_TEMP, MAX_TEMP);
+ }
+ kill_part(i);
+ return 0;
+ }
+ if ((r&0xFF)==PT_DEUT && parts[i].type==PT_ELEC)
+ {
+ if(parts[r>>8].life < 6000)
+ parts[r>>8].life += 1;
+ parts[r>>8].temp = 0;
+ kill_part(i);
+ return 0;
+ }
+ if (((r&0xFF)==PT_VIBR || (r&0xFF)==PT_BVBR) && (elements[parts[i].type].Properties & TYPE_ENERGY))
+ {
+ parts[r>>8].tmp += 20;
+ kill_part(i);
+ return 0;
+ }
+
+ if (parts[i].type==PT_CNCT && y<ny && (pmap[y+1][x]&0xFF)==PT_CNCT)//check below CNCT for another CNCT
+ return 0;
+
+ if ((bmap[y/CELL][x/CELL]==WL_EHOLE && !emap[y/CELL][x/CELL]) && !(bmap[ny/CELL][nx/CELL]==WL_EHOLE && !emap[ny/CELL][nx/CELL]))
+ return 0;
+
+ if(parts[i].type==PT_GBMB&&parts[i].life>0)
+ return 0;
+
+ e = r >> 8; //e is now the particle number at r (pmap[ny][nx])
+ if (r)//the swap part, if we make it this far, swap
+ {
+ if (parts[i].type==PT_NEUT) {
+ // target material is NEUTPENETRATE, meaning it gets moved around when neutron passes
+ unsigned s = pmap[y][x];
+ if (s && !(elements[s&0xFF].Properties&PROP_NEUTPENETRATE))
+ return 1; // if the element currently underneath neutron isn't NEUTPENETRATE, don't move anything except the neutron
+ // if nothing is currently underneath neutron, only move target particle
+ if (s)
+ {
+ pmap[ny][nx] = (s&~(0xFF))|parts[s>>8].type;
+ parts[s>>8].x = nx;
+ parts[s>>8].y = ny;
+ }
+ else pmap[ny][nx] = 0;
+ parts[e].x = x;
+ parts[e].y = y;
+ pmap[y][x] = (e<<8)|parts[e].type;
+ return 1;
+ }
+
+ if ((pmap[ny][nx]>>8)==e) pmap[ny][nx] = 0;
+ parts[e].x += x-nx;
+ parts[e].y += y-ny;
+ pmap[(int)(parts[e].y+0.5f)][(int)(parts[e].x+0.5f)] = (e<<8)|parts[e].type;
+ }
+ return 1;
+}
+
+// try to move particle, and if successful update pmap and parts[i].x,y
+int Simulation::do_move(int i, int x, int y, float nxf, float nyf)
+{
+ int nx = (int)(nxf+0.5f), ny = (int)(nyf+0.5f), result;
+ if (parts[i].type == PT_NONE)
+ return 0;
+ result = try_move(i, x, y, nx, ny);
+ if (result)
+ {
+ int t = parts[i].type;
+ parts[i].x = nxf;
+ parts[i].y = nyf;
+ if (ny!=y || nx!=x)
+ {
+ if ((pmap[y][x]>>8)==i) pmap[y][x] = 0;
+ else if ((photons[y][x]>>8)==i) photons[y][x] = 0;
+ if (nx<CELL || nx>=XRES-CELL || ny<CELL || ny>=YRES-CELL)//kill_part if particle is out of bounds
+ {
+ kill_part(i);
+ return -1;
+ }
+ if (elements[t].Properties & TYPE_ENERGY)
+ photons[ny][nx] = t|(i<<8);
+ else if (t)
+ pmap[ny][nx] = t|(i<<8);
+ }
+ }
+ return result;
+}
+
+int Simulation::pn_junction_sprk(int x, int y, int pt)
+{
+ unsigned r = pmap[y][x];
+ if ((r & 0xFF) != pt)
+ return 0;
+ r >>= 8;
+ if (parts[r].type != pt)
+ return 0;
+ if (parts[r].life != 0)
+ return 0;
+
+ parts[r].ctype = pt;
+ part_change_type(r,x,y,PT_SPRK);
+ parts[r].life = 4;
+ return 1;
+}
+
+void Simulation::photoelectric_effect(int nx, int ny)//create sparks from PHOT when hitting PSCN and NSCN
+{
+ unsigned r = pmap[ny][nx];
+
+ if ((r&0xFF) == PT_PSCN) {
+ if ((pmap[ny][nx-1] & 0xFF) == PT_NSCN ||
+ (pmap[ny][nx+1] & 0xFF) == PT_NSCN ||
+ (pmap[ny-1][nx] & 0xFF) == PT_NSCN ||
+ (pmap[ny+1][nx] & 0xFF) == PT_NSCN)
+ pn_junction_sprk(nx, ny, PT_PSCN);
+ }
+}
+
+unsigned Simulation::direction_to_map(float dx, float dy, int t)
+{
+ // TODO:
+ // Adding extra directions causes some inaccuracies.
+ // Not adding them causes problems with some diagonal surfaces (photons absorbed instead of reflected).
+ // For now, don't add them.
+ // Solution may involve more intelligent setting of initial i0 value in find_next_boundary?
+ // or rewriting normal/boundary finding code
+
+ return (dx >= 0) |
+ (((dx + dy) >= 0) << 1) | /* 567 */
+ ((dy >= 0) << 2) | /* 4+0 */
+ (((dy - dx) >= 0) << 3) | /* 321 */
+ ((dx <= 0) << 4) |
+ (((dx + dy) <= 0) << 5) |
+ ((dy <= 0) << 6) |
+ (((dy - dx) <= 0) << 7);
+ /*
+ return (dx >= -0.001) |
+ (((dx + dy) >= -0.001) << 1) | // 567
+ ((dy >= -0.001) << 2) | // 4+0
+ (((dy - dx) >= -0.001) << 3) | // 321
+ ((dx <= 0.001) << 4) |
+ (((dx + dy) <= 0.001) << 5) |
+ ((dy <= 0.001) << 6) |
+ (((dy - dx) <= 0.001) << 7);
+ }*/
+}
+
+int Simulation::is_blocking(int t, int x, int y)
+{
+ if (t & REFRACT) {
+ if (x<0 || y<0 || x>=XRES || y>=YRES)
+ return 0;
+ if ((pmap[y][x] & 0xFF) == PT_GLAS)
+ return 1;
+ return 0;
+ }
+
+ return !eval_move(t, x, y, NULL);
+}
+
+int Simulation::is_boundary(int pt, int x, int y)
+{
+ if (!is_blocking(pt,x,y))
+ return 0;
+ if (is_blocking(pt,x,y-1) && is_blocking(pt,x,y+1) && is_blocking(pt,x-1,y) && is_blocking(pt,x+1,y))
+ return 0;
+ return 1;
+}
+
+int Simulation::find_next_boundary(int pt, int *x, int *y, int dm, int *em)
+{
+ static int dx[8] = {1,1,0,-1,-1,-1,0,1};
+ static int dy[8] = {0,1,1,1,0,-1,-1,-1};
+ static int de[8] = {0x83,0x07,0x0E,0x1C,0x38,0x70,0xE0,0xC1};
+ int i, ii, i0;
+
+ if (*x <= 0 || *x >= XRES-1 || *y <= 0 || *y >= YRES-1)
+ return 0;
+
+ if (*em != -1) {
+ i0 = *em;
+ dm &= de[i0];
+ } else
+ i0 = 0;
+
+ for (ii=0; ii<8; ii++) {
+ i = (ii + i0) & 7;
+ if ((dm & (1 << i)) && is_boundary(pt, *x+dx[i], *y+dy[i])) {
+ *x += dx[i];
+ *y += dy[i];
+ *em = i;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int Simulation::get_normal(int pt, int x, int y, float dx, float dy, float *nx, float *ny)
+{
+ int ldm, rdm, lm, rm;
+ int lx, ly, lv, rx, ry, rv;
+ int i, j;
+ float r, ex, ey;
+
+ if (!dx && !dy)
+ return 0;
+
+ if (!is_boundary(pt, x, y))
+ return 0;
+
+ ldm = direction_to_map(-dy, dx, pt);
+ rdm = direction_to_map(dy, -dx, pt);
+ lx = rx = x;
+ ly = ry = y;
+ lv = rv = 1;
+ lm = rm = -1;
+
+ j = 0;
+ for (i=0; i<SURF_RANGE; i++) {
+ if (lv)
+ lv = find_next_boundary(pt, &lx, &ly, ldm, &lm);
+ if (rv)
+ rv = find_next_boundary(pt, &rx, &ry, rdm, &rm);
+ j += lv + rv;
+ if (!lv && !rv)
+ break;
+ }
+
+ if (j < NORMAL_MIN_EST)
+ return 0;
+
+ if ((lx == rx) && (ly == ry))
+ return 0;
+
+ ex = rx - lx;
+ ey = ry - ly;
+ r = 1.0f/hypot(ex, ey);
+ *nx = ey * r;
+ *ny = -ex * r;
+
+ return 1;
+}
+
+int Simulation::get_normal_interp(int pt, float x0, float y0, float dx, float dy, float *nx, float *ny)
+{
+ int x, y, i;
+
+ dx /= NORMAL_FRAC;
+ dy /= NORMAL_FRAC;
+
+ for (i=0; i<NORMAL_INTERP; i++) {
+ x = (int)(x0 + 0.5f);
+ y = (int)(y0 + 0.5f);
+ if (is_boundary(pt, x, y))
+ break;
+ x0 += dx;
+ y0 += dy;
+ }
+ if (i >= NORMAL_INTERP)
+ return 0;
+
+ if (pt == PT_PHOT)
+ photoelectric_effect(x, y);
+
+ return get_normal(pt, x, y, dx, dy, nx, ny);
+}
+
+//For soap only
+void Simulation::detach(int i)
+{
+ if ((parts[i].ctype&2) == 2)
+ {
+ if ((parts[parts[i].tmp].ctype&4) == 4)
+ parts[parts[i].tmp].ctype ^= 4;
+ }
+
+ if ((parts[i].ctype&4) == 4)
+ {
+ if ((parts[parts[i].tmp2].ctype&2) == 2)
+ parts[parts[i].tmp2].ctype ^= 2;
+ }
+
+ parts[i].ctype = 0;
+}
+
+void Simulation::kill_part(int i)//kills particle number i
+{
+ int x, y;
+
+ // Remove from pmap even if type==0, otherwise infinite recursion occurs when flood fill deleting
+ // a particle which sets type to 0 without calling kill_part (such as LIFE)
+ x = (int)(parts[i].x+0.5f);
+ y = (int)(parts[i].y+0.5f);
+ if (x>=0 && y>=0 && x<XRES && y<YRES) {
+ if ((pmap[y][x]>>8)==i)
+ pmap[y][x] = 0;
+ else if ((photons[y][x]>>8)==i)
+ photons[y][x] = 0;
+ }
+
+ if (parts[i].type == PT_NONE)
+ return;
+
+ if(parts[i].type > 0 && parts[i].type < PT_NUM && elementCount[parts[i].type])
+ elementCount[parts[i].type]--;
+ if (parts[i].type == PT_STKM)
+ {
+ player.spwn = 0;
+ }
+ if (parts[i].type == PT_STKM2)
+ {
+ player2.spwn = 0;
+ }
+ if (parts[i].type == PT_FIGH)
+ {
+ fighters[(unsigned char)parts[i].tmp].spwn = 0;
+ fighcount--;
+ }
+ if (parts[i].type == PT_SOAP)
+ {
+ detach(i);
+ }
+
+ parts[i].type = PT_NONE;
+ parts[i].life = pfree;
+ pfree = i;
+}
+
+void Simulation::part_change_type(int i, int x, int y, int t)//changes the type of particle number i, to t. This also changes pmap at the same time.
+{
+ if (x<0 || y<0 || x>=XRES || y>=YRES || i>=NPART || t<0 || t>=PT_NUM)
+ return;
+ if (!elements[t].Enabled)
+ t = PT_NONE;
+
+ if (parts[i].type == PT_STKM)
+ player.spwn = 0;
+
+ if (parts[i].type == PT_STKM2)
+ player2.spwn = 0;
+
+ if (parts[i].type == PT_FIGH)
+ {
+ fighters[(unsigned char)parts[i].tmp].spwn = 0;
+ fighcount--;
+ }
+
+ parts[i].type = t;
+ if (elements[t].Properties & TYPE_ENERGY)
+ {
+ photons[y][x] = t|(i<<8);
+ if ((pmap[y][x]>>8)==i)
+ pmap[y][x] = 0;
+ }
+ else
+ {
+ pmap[y][x] = t|(i<<8);
+ if ((photons[y][x]>>8)==i)
+ photons[y][x] = 0;
+ }
+}
+
+//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
+int Simulation::create_part(int p, int x, int y, int tv)
+{
+ int i;
+
+ int t = tv & 0xFF;
+ int v = (tv >> 8) & 0xFFFFFF;
+
+ if (x<0 || y<0 || x>=XRES || y>=YRES || ((t<=0 || t>=PT_NUM)&&t!=SPC_HEAT&&t!=SPC_COOL&&t!=SPC_AIR&&t!=SPC_VACUUM&&t!=SPC_PGRV&&t!=SPC_NGRV))
+ return -1;
+ if (t>=0 && t<PT_NUM && !elements[t].Enabled)
+ return -1;
+ if(t==SPC_PROP) {
+ return -1; //Prop tool works on a mouse click basic, make sure it doesn't do anything here
+ }
+
+ /*if (t==SPC_HEAT||t==SPC_COOL)
+ {
+ if ((pmap[y][x]&0xFF)!=PT_NONE&&(pmap[y][x]&0xFF)<PT_NUM)
+ {
+ if (t==SPC_HEAT&&parts[pmap[y][x]>>8].temp<MAX_TEMP)
+ {
+ if ((pmap[y][x]&0xFF)==PT_PUMP || (pmap[y][x]&0xFF)==PT_GPMP) {
+ parts[pmap[y][x]>>8].temp = restrict_flt(parts[pmap[y][x]>>8].temp + 0.1f, MIN_TEMP, MAX_TEMP);
+ } else if ((sdl_mod & (KMOD_SHIFT)) && (sdl_mod & (KMOD_CTRL))) {
+ parts[pmap[y][x]>>8].temp = restrict_flt(parts[pmap[y][x]>>8].temp + 50.0f, MIN_TEMP, MAX_TEMP);
+ } else {
+ parts[pmap[y][x]>>8].temp = restrict_flt(parts[pmap[y][x]>>8].temp + 4.0f, MIN_TEMP, MAX_TEMP);
+ }
+ }
+ if (t==SPC_COOL&&parts[pmap[y][x]>>8].temp>MIN_TEMP)
+ {
+ if ((pmap[y][x]&0xFF)==PT_PUMP || (pmap[y][x]&0xFF)==PT_GPMP) {
+ parts[pmap[y][x]>>8].temp = restrict_flt(parts[pmap[y][x]>>8].temp - 0.1f, MIN_TEMP, MAX_TEMP);
+ } else if ((sdl_mod & (KMOD_SHIFT)) && (sdl_mod & (KMOD_CTRL))) {
+ parts[pmap[y][x]>>8].temp = restrict_flt(parts[pmap[y][x]>>8].temp - 50.0f, MIN_TEMP, MAX_TEMP);
+ } else {
+ parts[pmap[y][x]>>8].temp = restrict_flt(parts[pmap[y][x]>>8].temp - 4.0f, MIN_TEMP, MAX_TEMP);
+ }
+ }
+ return pmap[y][x]>>8;
+ }
+ else
+ {
+ return -1;
+ }
+ }*/
+ if (t==SPC_AIR)
+ {
+ pv[y/CELL][x/CELL] += 0.03f;
+ if (y+CELL<YRES)
+ pv[y/CELL+1][x/CELL] += 0.03f;
+ if (x+CELL<XRES)
+ {
+ pv[y/CELL][x/CELL+1] += 0.03f;
+ if (y+CELL<YRES)
+ pv[y/CELL+1][x/CELL+1] += 0.03f;
+ }
+ return -1;
+ }
+ if (t==SPC_VACUUM)
+ {
+ pv[y/CELL][x/CELL] -= 0.03f;
+ if (y+CELL<YRES)
+ pv[y/CELL+1][x/CELL] -= 0.03f;
+ if (x+CELL<XRES)
+ {
+ pv[y/CELL][x/CELL+1] -= 0.03f;
+ if (y+CELL<YRES)
+ pv[y/CELL+1][x/CELL+1] -= 0.03f;
+ }
+ return -1;
+ }
+ if (t==SPC_PGRV)
+ {
+ gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] = 5;
+ return -1;
+ }
+ if (t==SPC_NGRV)
+ {
+ gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] = -5;
+ return -1;
+ }
+
+
+ if (t==PT_SPRK)
+ {
+ int type = pmap[y][x]&0xFF;
+ int index = pmap[y][x]>>8;
+ if(type == PT_WIRE)
+ {
+ parts[index].ctype = PT_DUST;
+ }
+ if (!(type == PT_INST || (elements[type].Properties&PROP_CONDUCTS)))
+ return -1;
+ if (parts[index].life!=0)
+ return -1;
+ if (p == -2 && type == PT_INST)
+ {
+ FloodINST(x, y, PT_SPRK, PT_INST);
+ return index;
+ }
+ parts[index].type = PT_SPRK;
+ parts[index].life = 4;
+ parts[index].ctype = type;
+ pmap[y][x] = (pmap[y][x]&~0xFF) | PT_SPRK;
+ if (parts[index].temp+10.0f < 673.0f && !legacy_enable && (type==PT_METL || type == PT_BMTL || type == PT_BRMT || type == PT_PSCN || type == PT_NSCN || type == PT_ETRD || type == PT_NBLE || type == PT_IRON))
+ parts[index].temp = parts[index].temp+10.0f;
+ return index;
+ }
+ if (t==PT_SPAWN&&elementCount[PT_SPAWN])
+ return -1;
+ if (t==PT_SPAWN2&&elementCount[PT_SPAWN2])
+ return -1;
+ if (p==-1)//creating from anything but brush
+ {
+ // If there is a particle, only allow creation if the new particle can occupy the same space as the existing particle
+ // If there isn't a particle but there is a wall, check whether the new particle is allowed to be in it
+ // (not "!=2" for wall check because eval_move returns 1 for moving into empty space)
+ // If there's no particle and no wall, assume creation is allowed
+ if (pmap[y][x] ? (eval_move(t, x, y, NULL)!=2) : (bmap[y/CELL][x/CELL] && eval_move(t, x, y, NULL)==0))
+ {
+ if ((pmap[y][x]&0xFF)!=PT_SPAWN&&(pmap[y][x]&0xFF)!=PT_SPAWN2)
+ {
+ if (t!=PT_STKM&&t!=PT_STKM2&&t!=PT_FIGH)
+ {
+ return -1;
+ }
+ }
+ }
+ if (pfree == -1)
+ return -1;
+ i = pfree;
+ pfree = parts[i].life;
+ }
+ else if (p==-2)//creating from brush
+ {
+ if (pmap[y][x])
+ {
+ if ((
+ ((pmap[y][x]&0xFF)==PT_STOR&&!(elements[t].Properties&TYPE_SOLID))||
+ (pmap[y][x]&0xFF)==PT_CLNE||
+ (pmap[y][x]&0xFF)==PT_BCLN||
+ (pmap[y][x]&0xFF)==PT_CONV||
+ ((pmap[y][x]&0xFF)==PT_PCLN&&t!=PT_PSCN&&t!=PT_NSCN)||
+ ((pmap[y][x]&0xFF)==PT_PBCN&&t!=PT_PSCN&&t!=PT_NSCN)
+ )&&(
+ t!=PT_CLNE&&t!=PT_PCLN&&
+ t!=PT_BCLN&&t!=PT_STKM&&
+ t!=PT_STKM2&&t!=PT_PBCN&&
+ t!=PT_STOR&&t!=PT_FIGH)
+ )
+ {
+ parts[pmap[y][x]>>8].ctype = t;
+ if (t==PT_LIFE && v<NGOLALT && (pmap[y][x]&0xFF)!=PT_STOR) parts[pmap[y][x]>>8].tmp = v;
+ }
+ else if ((pmap[y][x]&0xFF) == PT_DTEC && (pmap[y][x]&0xFF) != t)
+ {
+ parts[pmap[y][x]>>8].ctype = t;
+ if (t==PT_LIFE && v<NGOLALT)
+ parts[pmap[y][x]>>8].tmp = v;
+ }
+ return -1;
+ }
+ if (photons[y][x] && (elements[t].Properties & TYPE_ENERGY))
+ return -1;
+ if (pfree == -1)
+ return -1;
+ i = pfree;
+ pfree = parts[i].life;
+ }
+ else if (p==-3)//skip pmap checks, e.g. for sing explosion
+ {
+ if (pfree == -1)
+ return -1;
+ i = pfree;
+ pfree = parts[i].life;
+ }
+ else
+ {
+ int oldX = (int)(parts[p].x+0.5f);
+ int oldY = (int)(parts[p].y+0.5f);
+ if ((pmap[oldY][oldX]>>8)==p)
+ pmap[oldY][oldX] = 0;
+ if ((photons[oldY][oldX]>>8)==p)
+ photons[oldY][oldX] = 0;
+ i = p;
+ }
+
+ if (i>parts_lastActiveIndex) parts_lastActiveIndex = i;
+
+ parts[i].dcolour = 0;
+ parts[i].flags = 0;
+ if (t==PT_GLAS)
+ {
+ parts[i].pavg[1] = pv[y/CELL][x/CELL];
+ }
+ else if (t==PT_QRTZ)
+ {
+ parts[i].pavg[1] = pv[y/CELL][x/CELL];
+ }
+ else
+ {
+ parts[i].pavg[0] = 0.0f;
+ parts[i].pavg[1] = 0.0f;
+ }
+ if (t!=PT_STKM&&t!=PT_STKM2&&t!=PT_FIGH)//set everything to default values first, except for stickman.
+ {
+ parts[i].x = (float)x;
+ parts[i].y = (float)y;
+ parts[i].type = t;
+ parts[i].vx = 0;
+ parts[i].vy = 0;
+ parts[i].life = 0;
+ parts[i].ctype = 0;
+ parts[i].temp = elements[t].Temperature;
+ parts[i].tmp = 0;
+ parts[i].tmp2 = 0;
+ }
+ switch (t)
+ {
+ case PT_SOAP:
+ parts[i].tmp = -1;
+ parts[i].tmp2 = -1;
+ break;
+ case PT_ACID: case PT_CAUS:
+ parts[i].life = 75;
+ break;
+ /*Testing
+ case PT_WOOD:
+ parts[i].life = 150;
+ break;
+ End Testing*/
+ case PT_WARP:
+ parts[i].life = rand()%95+70;
+ break;
+ case PT_FUSE:
+ parts[i].life = 50;
+ parts[i].tmp = 50;
+ break;
+ case PT_LIFE:
+ if (v<NGOLALT)
+ {
+ parts[i].tmp = grule[v+1][9] - 1;
+ parts[i].ctype = v;
+ }
+ break;
+ case PT_DEUT:
+ parts[i].life = 10;
+ break;
+ case PT_MERC:
+ parts[i].tmp = 10;
+ break;
+ case PT_BRAY:
+ parts[i].life = 30;
+ break;
+ case PT_GPMP: case PT_PUMP:
+ parts[i].life = 10;
+ break;
+ case PT_SING:
+ parts[i].life = rand()%50+60;
+ break;
+ case PT_QRTZ:
+ parts[i].tmp = (rand()%11);
+ break;
+ case PT_PQRT:
+ parts[i].tmp = (rand()%11);
+ break;
+ case PT_CLST:
+ parts[i].tmp = (rand()%7);
+ break;
+ case PT_FSEP:
+ parts[i].life = 50;
+ break;
+ case PT_COAL:
+ parts[i].life = 110;
+ parts[i].tmp = 50;
+ break;
+ case PT_IGNT:
+ parts[i].life = 3;
+ break;
+ case PT_FRZW:
+ parts[i].life = 100;
+ break;
+ case PT_PPIP:
+ case PT_PIPE:
+ parts[i].life = 60;
+ break;
+ case PT_BCOL:
+ parts[i].life = 110;
+ break;
+ case PT_FIRE:
+ parts[i].life = rand()%50+120;
+ break;
+ case PT_PLSM:
+ parts[i].life = rand()%150+50;
+ break;
+ case PT_HFLM:
+ parts[i].life = rand()%150+50;
+ break;
+ case PT_LAVA:
+ parts[i].life = rand()%120+240;
+ break;
+ case PT_NBLE:
+ parts[i].life = 0;
+ break;
+ case PT_ICEI:
+ parts[i].ctype = PT_WATR;
+ break;
+ case PT_MORT:
+ parts[i].vx = 2;
+ break;
+ case PT_EXOT:
+ parts[i].life = 1000;
+ parts[i].tmp = 244;
+ break;
+ case PT_EMBR:
+ parts[i].life = 50;
+ break;
+ case PT_TESC:
+ parts[i].tmp = v;
+ if (parts[i].tmp > 300)
+ parts[i].tmp=300;
+ break;
+ case PT_STKM:
+ if (player.spwn==0)
+ {
+ parts[i].x = (float)x;
+ parts[i].y = (float)y;
+ parts[i].type = PT_STKM;
+ parts[i].vx = 0;
+ parts[i].vy = 0;
+ parts[i].life = 100;
+ parts[i].ctype = 0;
+ parts[i].temp = elements[t].Temperature;
+ Element_STKM::STKM_init_legs(this, &player, i);
+ player.spwn = 1;
+ player.elem = PT_DUST;
+ }
+ else
+ {
+ return -1;
+ }
+ create_part(-3,x,y,PT_SPAWN);
+ elementCount[PT_SPAWN] = 1;
+ break;
+ case PT_STKM2:
+ if (player2.spwn==0)
+ {
+ parts[i].x = (float)x;
+ parts[i].y = (float)y;
+ parts[i].type = PT_STKM2;
+ parts[i].vx = 0;
+ parts[i].vy = 0;
+ parts[i].life = 100;
+ parts[i].ctype = 0;
+ parts[i].temp = elements[t].Temperature;
+ Element_STKM::STKM_init_legs(this, &player2, i);
+ player2.spwn = 1;
+ player2.elem = PT_DUST;
+ }
+ else
+ {
+ return -1;
+ }
+ create_part(-3,x,y,PT_SPAWN2);
+ elementCount[PT_SPAWN2] = 1;
+ break;
+ case PT_BIZR: case PT_BIZRG: case PT_BIZRS:
+ parts[i].ctype = 0x47FFFF;
+ break;
+ case PT_DTEC:
+ parts[i].tmp2 = 2;
+ case PT_TSNS:
+ parts[i].tmp2 = 2;
+ break;
+ default:
+ if (t==PT_FIGH)
+ {
+ unsigned char fcount = 0;
+ while (fcount < 100 && fcount < (fighcount+1) && fighters[fcount].spwn==1) fcount++;
+ if (fcount < 100 && fighters[fcount].spwn==0)
+ {
+ parts[i].x = (float)x;
+ parts[i].y = (float)y;
+ parts[i].type = PT_FIGH;
+ parts[i].vx = 0;
+ parts[i].vy = 0;
+ parts[i].life = 100;
+ parts[i].ctype = 0;
+ parts[i].tmp = fcount;
+ parts[i].temp = elements[t].Temperature;
+ Element_STKM::STKM_init_legs(this, &fighters[fcount], i);
+ fighters[fcount].spwn = 1;
+ fighters[fcount].elem = PT_DUST;
+ fighcount++;
+
+ return i;
+ }
+ return -1;
+ }
+ if (t==PT_PHOT)
+ {
+ float a = (rand()%8) * 0.78540f;
+ parts[i].life = 680;
+ parts[i].ctype = 0x3FFFFFFF;
+ parts[i].vx = 3.0f*cosf(a);
+ parts[i].vy = 3.0f*sinf(a);
+ }
+ if (t==PT_ELEC)
+ {
+ float a = (rand()%360)*3.14159f/180.0f;
+ parts[i].life = 680;
+ parts[i].vx = 2.0f*cosf(a);
+ parts[i].vy = 2.0f*sinf(a);
+ }
+ if (t==PT_NEUT)
+ {
+ float r = (rand()%128+128)/127.0f;
+ float a = (rand()%360)*3.14159f/180.0f;
+ parts[i].life = rand()%480+480;
+ parts[i].vx = r*cosf(a);
+ parts[i].vy = r*sinf(a);
+ }
+ if (t==PT_TRON)
+ {
+ int randhue = rand()%360;
+ int randomdir = rand()%4;
+ parts[i].tmp = 1|(randomdir<<5)|(randhue<<7);//set as a head and a direction
+ parts[i].tmp2 = 4;//tail
+ parts[i].life = 5;
+ }
+ if (t==PT_LIGH)
+ {
+ float gx, gy, gsize;
+ if (p!=-2)
+ {
+ parts[i].life=30;
+ parts[i].temp=parts[i].life*150.0f; // temperature of the lighting shows the power of the lighting
+ }
+ GetGravityField(x, y, 1.0f, 1.0f, gx, gy);
+ gsize = gx*gx+gy*gy;
+ if (gsize<0.0016f)
+ {
+ float angle = (rand()%6284)*0.001f;//(in radians, between 0 and 2*pi)
+ gsize = sqrtf(gsize);
+ // randomness in weak gravity fields (more randomness with weaker fields)
+ gx += cosf(angle)*(0.04f-gsize);
+ gy += sinf(angle)*(0.04f-gsize);
+ }
+ parts[i].tmp = (((int)(atan2f(-gy, gx)*(180.0f/M_PI)))+rand()%40-20+360)%360;
+ parts[i].tmp2 = 4;
+ }
+ break;
+ }
+ //and finally set the pmap/photon maps to the newly created particle
+ if (elements[t].Properties & TYPE_ENERGY)
+ photons[y][x] = t|(i<<8);
+ else if (t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH)
+ pmap[y][x] = t|(i<<8);
+
+ //Fancy dust effects for powder types
+ if((elements[t].Properties & TYPE_PART) && pretty_powder)
+ {
+ int colr, colg, colb, randa;
+ randa = (rand()%30)-15;
+ colr = (PIXR(elements[t].Colour)+sandcolour+(rand()%20)-10+randa);
+ colg = (PIXG(elements[t].Colour)+sandcolour+(rand()%20)-10+randa);
+ colb = (PIXB(elements[t].Colour)+sandcolour+(rand()%20)-10+randa);
+ colr = colr>255 ? 255 : (colr<0 ? 0 : colr);
+ colg = colg>255 ? 255 : (colg<0 ? 0 : colg);
+ colb = colb>255 ? 255 : (colb<0 ? 0 : colb);
+ parts[i].dcolour = 0xFF000000 | (colr<<16) | (colg<<8) | colb;
+ }
+ elementCount[t]++;
+ return i;
+}
+
+void Simulation::GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY)
+{
+ pGravX = newtonGrav*gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ pGravY = newtonGrav*gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ switch (gravityMode)
+ {
+ default:
+ case 0: //normal, vertical gravity
+ pGravY += particleGrav;
+ break;
+ case 1: //no gravity
+ break;
+ case 2: //radial gravity
+ if (x-XCNTR != 0 || y-YCNTR != 0)
+ {
+ float pGravMult = particleGrav/sqrtf((x-XCNTR)*(x-XCNTR) + (y-YCNTR)*(y-YCNTR));
+ pGravX -= pGravMult * (float)(x - XCNTR);
+ pGravY -= pGravMult * (float)(y - YCNTR);
+ }
+ }
+}
+
+void Simulation::create_gain_photon(int pp)//photons from PHOT going through GLOW
+{
+ float xx, yy;
+ int i, lr, temp_bin, nx, ny;
+
+ if (pfree == -1)
+ return;
+ i = pfree;
+
+ lr = rand() % 2;
+
+ if (lr) {
+ xx = parts[pp].x - 0.3*parts[pp].vy;
+ yy = parts[pp].y + 0.3*parts[pp].vx;
+ } else {
+ xx = parts[pp].x + 0.3*parts[pp].vy;
+ yy = parts[pp].y - 0.3*parts[pp].vx;
+ }
+
+ nx = (int)(xx + 0.5f);
+ ny = (int)(yy + 0.5f);
+
+ if (nx<0 || ny<0 || nx>=XRES || ny>=YRES)
+ return;
+
+ if ((pmap[ny][nx] & 0xFF) != PT_GLOW)
+ return;
+
+ pfree = parts[i].life;
+ if (i>parts_lastActiveIndex) parts_lastActiveIndex = i;
+
+ parts[i].type = PT_PHOT;
+ parts[i].life = 680;
+ parts[i].x = xx;
+ parts[i].y = yy;
+ parts[i].vx = parts[pp].vx;
+ parts[i].vy = parts[pp].vy;
+ parts[i].temp = parts[pmap[ny][nx] >> 8].temp;
+ parts[i].tmp = 0;
+ parts[i].pavg[0] = parts[i].pavg[1] = 0.0f;
+ photons[ny][nx] = PT_PHOT|(i<<8);
+
+ temp_bin = (int)((parts[i].temp-273.0f)*0.25f);
+ if (temp_bin < 0) temp_bin = 0;
+ if (temp_bin > 25) temp_bin = 25;
+ parts[i].ctype = 0x1F << temp_bin;
+}
+
+void Simulation::create_cherenkov_photon(int pp)//photons from NEUT going through GLAS
+{
+ int i, lr, nx, ny;
+ float r, eff_ior;
+
+ if (pfree == -1)
+ return;
+ i = pfree;
+
+ nx = (int)(parts[pp].x + 0.5f);
+ ny = (int)(parts[pp].y + 0.5f);
+ if ((pmap[ny][nx] & 0xFF) != PT_GLAS)
+ return;
+
+ if (hypotf(parts[pp].vx, parts[pp].vy) < 1.44f)
+ return;
+
+ pfree = parts[i].life;
+ if (i>parts_lastActiveIndex) parts_lastActiveIndex = i;
+
+ lr = rand() % 2;
+
+ parts[i].type = PT_PHOT;
+ parts[i].ctype = 0x00000F80;
+ parts[i].life = 680;
+ parts[i].x = parts[pp].x;
+ parts[i].y = parts[pp].y;
+ parts[i].temp = parts[pmap[ny][nx] >> 8].temp;
+ parts[i].tmp = 0;
+ parts[i].pavg[0] = parts[i].pavg[1] = 0.0f;
+ photons[ny][nx] = PT_PHOT|(i<<8);
+
+ if (lr) {
+ parts[i].vx = parts[pp].vx - 2.5f*parts[pp].vy;
+ parts[i].vy = parts[pp].vy + 2.5f*parts[pp].vx;
+ } else {
+ parts[i].vx = parts[pp].vx + 2.5f*parts[pp].vy;
+ parts[i].vy = parts[pp].vy - 2.5f*parts[pp].vx;
+ }
+
+ /* photons have speed of light. no discussion. */
+ r = 1.269 / hypotf(parts[i].vx, parts[i].vy);
+ parts[i].vx *= r;
+ parts[i].vy *= r;
+}
+
+void Simulation::delete_part(int x, int y, int flags)//calls kill_part with the particle located at x,y
+{
+ unsigned i;
+
+ if (x<0 || y<0 || x>=XRES || y>=YRES)
+ return;
+ if (photons[y][x]) {
+ i = photons[y][x];
+ } else {
+ i = pmap[y][x];
+ }
+
+ if (!i)
+ return;
+ kill_part(i>>8);
+}
+
+void Simulation::update_particles_i(int start, int inc)
+{
+ int i, j, x, y, t, nx, ny, r, surround_space, s, lt, rt, nt, nnx, nny, q, golnum, goldelete, z, neighbors, createdsomething;
+ float mv, dx, dy, ix, iy, lx, ly, nrx, nry, dp, ctemph, ctempl, gravtot;
+ int fin_x, fin_y, clear_x, clear_y, stagnant;
+ float fin_xf, fin_yf, clear_xf, clear_yf;
+ float nn, ct1, ct2, swappage;
+ float pt = R_TEMP;
+ float c_heat = 0.0f;
+ int h_count = 0;
+ int starti = (start*-1);
+ int surround[8];
+ int surround_hconduct[8];
+ int lighting_ok=1;
+ unsigned int elem_properties;
+ float pGravX, pGravY, pGravD;
+ int excessive_stacking_found = 0;
+
+ currentTick++;
+
+ if (lighting_recreate>0)
+ {
+ for (i=0; i<=parts_lastActiveIndex; i++)
+ {
+ if (parts[i].type==PT_LIGH && parts[i].tmp2>0)
+ {
+ lighting_ok=0;
+ break;
+ }
+ }
+ }
+
+ if (lighting_ok)
+ lighting_recreate--;
+
+ if (lighting_recreate<0)
+ lighting_recreate=1;
+
+ if (lighting_recreate>21)
+ lighting_recreate=21;
+
+ //if (sys_pause&&!framerender)//do nothing if paused
+ // return;
+
+ if (force_stacking_check || (rand()%10)==0)
+ {
+ force_stacking_check = 0;
+ excessive_stacking_found = 0;
+ for (y=0; y<YRES; y++)
+ {
+ for (x=0; x<XRES; x++)
+ {
+ // Use a threshold, since some particle stacking can be normal (e.g. BIZR + FILT)
+ // Setting pmap_count[y][x] > NPART means BHOL will form in that spot
+ if (pmap_count[y][x]>5)
+ {
+ if (bmap[y/CELL][x/CELL]==WL_EHOLE)
+ {
+ // Allow more stacking in E-hole
+ if (pmap_count[y][x]>1500)
+ {
+ pmap_count[y][x] = pmap_count[y][x] + NPART;
+ excessive_stacking_found = 1;
+ }
+ }
+ else if (pmap_count[y][x]>1500 || (rand()%1600)<=(pmap_count[y][x]+100))
+ {
+ pmap_count[y][x] = pmap_count[y][x] + NPART;
+ excessive_stacking_found = 1;
+ }
+ }
+ }
+ }
+ if (excessive_stacking_found)
+ {
+ for (i=0; i<=parts_lastActiveIndex; i++)
+ {
+ if (parts[i].type)
+ {
+ t = parts[i].type;
+ x = (int)(parts[i].x+0.5f);
+ y = (int)(parts[i].y+0.5f);
+ if (x>=0 && y>=0 && x<XRES && y<YRES && !(elements[t].Properties&TYPE_ENERGY))
+ {
+ if (pmap_count[y][x]>=NPART)
+ {
+ if (pmap_count[y][x]>NPART)
+ {
+ create_part(i, x, y, PT_NBHL);
+ parts[i].temp = MAX_TEMP;
+ parts[i].tmp = pmap_count[y][x]-NPART;//strength of grav field
+ if (parts[i].tmp>51200) parts[i].tmp = 51200;
+ pmap_count[y][x] = NPART;
+ }
+ else
+ {
+ kill_part(i);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (ISLOVE || ISLOLZ) //LOVE and LOLZ element handling
+ {
+ int nx, nnx, ny, nny, r, rt;
+ ISLOVE = 0;
+ ISLOLZ = 0;
+ for (ny=0; ny<YRES-4; ny++)
+ {
+ for (nx=0; nx<XRES-4; nx++)
+ {
+ r=pmap[ny][nx];
+ if (!r)
+ {
+ continue;
+ }
+ else if ((ny<9||nx<9||ny>YRES-7||nx>XRES-10)&&(parts[r>>8].type==PT_LOVE||parts[r>>8].type==PT_LOLZ))
+ kill_part(r>>8);
+ else if (parts[r>>8].type==PT_LOVE)
+ {
+ love[nx/9][ny/9] = 1;
+ }
+ else if (parts[r>>8].type==PT_LOLZ)
+ {
+ lolz[nx/9][ny/9] = 1;
+ }
+ }
+ }
+ for (nx=9; nx<=XRES-18; nx++)
+ {
+ for (ny=9; ny<=YRES-7; ny++)
+ {
+ if (love[nx/9][ny/9]==1)
+ {
+ for ( nnx=0; nnx<9; nnx++)
+ for ( nny=0; nny<9; nny++)
+ {
+ if (ny+nny>0&&ny+nny<YRES&&nx+nnx>=0&&nx+nnx<XRES)
+ {
+ rt=pmap[ny+nny][nx+nnx];
+ if (!rt&&Element_LOVE::RuleTable[nnx][nny]==1)
+ create_part(-1,nx+nnx,ny+nny,PT_LOVE);
+ else if (!rt)
+ continue;
+ else if (parts[rt>>8].type==PT_LOVE&&Element_LOVE::RuleTable[nnx][nny]==0)
+ kill_part(rt>>8);
+ }
+ }
+ }
+ love[nx/9][ny/9]=0;
+ if (lolz[nx/9][ny/9]==1)
+ {
+ for ( nnx=0; nnx<9; nnx++)
+ for ( nny=0; nny<9; nny++)
+ {
+ if (ny+nny>0&&ny+nny<YRES&&nx+nnx>=0&&nx+nnx<XRES)
+ {
+ rt=pmap[ny+nny][nx+nnx];
+ if (!rt&&Element_LOLZ::RuleTable[nny][nnx]==1)
+ create_part(-1,nx+nnx,ny+nny,PT_LOLZ);
+ else if (!rt)
+ continue;
+ else if (parts[rt>>8].type==PT_LOLZ&&Element_LOLZ::RuleTable[nny][nnx]==0)
+ kill_part(rt>>8);
+
+ }
+ }
+ }
+ lolz[nx/9][ny/9]=0;
+ }
+ }
+ }
+
+ //wire!
+ if(elementCount[PT_WIRE] > 0)
+ {
+ for (nx=0; nx<XRES; nx++)
+ {
+ for (ny=0; ny<YRES; ny++)
+ {
+ r = pmap[ny][nx];
+ if (!r)
+ continue;
+ if(parts[r>>8].type==PT_WIRE)
+ parts[r>>8].tmp=parts[r>>8].ctype;
+ }
+ }
+ }
+
+ if (Element_PPIP::ppip_changed)
+ {
+ for (i=0; i<=parts_lastActiveIndex; i++)
+ {
+ if (parts[i].type==PT_PPIP)
+ {
+ parts[i].tmp |= (parts[i].tmp&0xE0000000)>>3;
+ parts[i].tmp &= ~0xE0000000;
+ }
+ }
+ Element_PPIP::ppip_changed = 0;
+ }
+
+ //game of life!
+ if (elementCount[PT_LIFE]>0&&++CGOL>=GSPEED)//GSPEED is frames per generation
+ {
+ int createdsomething = 0;
+ CGOL=0;
+ ISGOL=0;
+ for (ny=CELL; ny<YRES-CELL; ny++)
+ {//go through every particle and set neighbor map
+ for (nx=CELL; nx<XRES-CELL; nx++)
+ {
+ r = pmap[ny][nx];
+ if (!r)
+ {
+ gol[ny][nx] = 0;
+ continue;
+ }
+ else
+ {
+ //for ( golnum=1; golnum<=NGOL; golnum++) //This shouldn't be necessary any more.
+ //{
+ if (parts[r>>8].type==PT_LIFE/* && parts[r>>8].ctype==golnum-1*/)
+ {
+ golnum = parts[r>>8].ctype+1;
+ if (golnum<=0 || golnum>NGOLALT) {
+ parts[r>>8].type = PT_NONE;
+ continue;
+ }
+ if (parts[r>>8].tmp == grule[golnum][9]-1) {
+ gol[ny][nx] = golnum;
+ for ( nnx=-1; nnx<2; nnx++)
+ {
+ for ( nny=-1; nny<2; nny++)//it will count itself as its own neighbor, which is needed, but will have 1 extra for delete check
+ {
+ rt = pmap[((ny+nny+YRES-3*CELL)%(YRES-2*CELL))+CELL][((nx+nnx+XRES-3*CELL)%(XRES-2*CELL))+CELL];
+ if (!rt || (rt&0xFF)==PT_LIFE)
+ {
+ gol2[((ny+nny+YRES-3*CELL)%(YRES-2*CELL))+CELL][((nx+nnx+XRES-3*CELL)%(XRES-2*CELL))+CELL][golnum] ++;
+ gol2[((ny+nny+YRES-3*CELL)%(YRES-2*CELL))+CELL][((nx+nnx+XRES-3*CELL)%(XRES-2*CELL))+CELL][0] ++;
+ }
+ }
+ }
+ } else {
+ parts[r>>8].tmp --;
+ if (parts[r>>8].tmp<=0)
+ parts[r>>8].type = PT_NONE;//using kill_part makes it not work
+ }
+ }
+ //}
+ }
+ }
+ }
+ for (ny=CELL; ny<YRES-CELL; ny++)
+ { //go through every particle again, but check neighbor map, then update particles
+ for (nx=CELL; nx<XRES-CELL; nx++)
+ {
+ r = pmap[ny][nx];
+ neighbors = gol2[ny][nx][0];
+ if (neighbors==0 || !((r&0xFF)==PT_LIFE || !(r&0xFF)))
+ continue;
+ for ( golnum = 1; golnum<=NGOL; golnum++)
+ {
+ goldelete = neighbors;
+ if (gol[ny][nx]==0&&grule[golnum][goldelete]>=2&&gol2[ny][nx][golnum]>=(goldelete%2)+goldelete/2)
+ {
+ if (create_part(-1, nx, ny, PT_LIFE|((golnum-1)<<8)))
+ createdsomething = 1;
+ }
+ else if (gol[ny][nx]==golnum&&(grule[golnum][goldelete-1]==0||grule[golnum][goldelete-1]==2))//subtract 1 because it counted itself
+ {
+ if (parts[r>>8].tmp==grule[golnum][9]-1)
+ parts[r>>8].tmp --;
+ }
+ if (r && parts[r>>8].tmp<=0)
+ parts[r>>8].type = PT_NONE;//using kill_part makes it not work
+ }
+ for ( z = 0; z<=NGOL; z++)
+ gol2[ny][nx][z] = 0;//this improves performance A LOT compared to the memset, i was getting ~23 more fps with this.
+ }
+ }
+ //memset(gol2, 0, sizeof(gol2));
+ }
+ if (ISWIRE>0)//wifi channel reseting
+ {
+ for ( q = 0; q<(int)(MAX_TEMP-73.15f)/100+2; q++)
+ {
+ wireless[q][0] = wireless[q][1];
+ wireless[q][1] = 0;
+ }
+ ISWIRE--;
+ }
+
+ bool elementRecount = !(currentTick%180);
+ if(elementRecount)
+ {
+ std::fill(elementCount, elementCount+PT_NUM, 0);
+ }
+
+ for (i=0; i<=parts_lastActiveIndex; i++)
+ if (parts[i].type)
+ {
+ t = parts[i].type;
+ if (t<0 || t>=PT_NUM || !elements[t].Enabled)
+ {
+ kill_part(i);
+ continue;
+ }
+
+
+ elementCount[t]++;
+
+ elem_properties = elements[t].Properties;
+ if (parts[i].life>0 && (elem_properties&PROP_LIFE_DEC))
+ {
+ // automatically decrease life
+ parts[i].life--;
+ if (parts[i].life<=0 && (elem_properties&(PROP_LIFE_KILL_DEC|PROP_LIFE_KILL)))
+ {
+ // kill on change to no life
+ kill_part(i);
+ continue;
+ }
+ }
+ else if (parts[i].life<=0 && (elem_properties&PROP_LIFE_KILL))
+ {
+ // kill if no life
+ kill_part(i);
+ continue;
+ }
+ }
+ //the main particle loop function, goes over all particles.
+
+ for (i=0; i<=parts_lastActiveIndex; i++)
+ if (parts[i].type)
+ {
+ t = parts[i].type;
+
+ x = (int)(parts[i].x+0.5f);
+ y = (int)(parts[i].y+0.5f);
+
+ //this kills any particle out of the screen, or in a wall where it isn't supposed to go
+ if (x<CELL || y<CELL || x>=XRES-CELL || y>=YRES-CELL ||
+ (bmap[y/CELL][x/CELL] &&
+ (bmap[y/CELL][x/CELL]==WL_WALL ||
+ bmap[y/CELL][x/CELL]==WL_WALLELEC ||
+ bmap[y/CELL][x/CELL]==WL_ALLOWAIR ||
+ (bmap[y/CELL][x/CELL]==WL_DESTROYALL) ||
+ (bmap[y/CELL][x/CELL]==WL_ALLOWLIQUID && elements[t].Falldown!=2) ||
+ (bmap[y/CELL][x/CELL]==WL_ALLOWSOLID && elements[t].Falldown!=1) ||
+ (bmap[y/CELL][x/CELL]==WL_ALLOWGAS && !(elements[t].Properties&TYPE_GAS)) || //&& elements[t].Falldown!=0 && parts[i].type!=PT_FIRE && parts[i].type!=PT_SMKE && parts[i].type!=PT_HFLM) ||
+ (bmap[y/CELL][x/CELL]==WL_ALLOWENERGY && !(elements[t].Properties&TYPE_ENERGY)) ||
+ (bmap[y/CELL][x/CELL]==WL_DETECT && (t==PT_METL || t==PT_SPRK)) ||
+ (bmap[y/CELL][x/CELL]==WL_EWALL && !emap[y/CELL][x/CELL])) && (t!=PT_STKM) && (t!=PT_STKM2) && (t!=PT_FIGH)))
+ {
+ kill_part(i);
+ continue;
+ }
+ if (bmap[y/CELL][x/CELL]==WL_DETECT && emap[y/CELL][x/CELL]<8)
+ set_emap(x/CELL, y/CELL);
+
+ //adding to velocity from the particle's velocity
+ vx[y/CELL][x/CELL] = vx[y/CELL][x/CELL]*elements[t].AirLoss + elements[t].AirDrag*parts[i].vx;
+ vy[y/CELL][x/CELL] = vy[y/CELL][x/CELL]*elements[t].AirLoss + elements[t].AirDrag*parts[i].vy;
+
+ if (t==PT_GAS||t==PT_NBLE)
+ {
+ if (pv[y/CELL][x/CELL]<3.5f)
+ pv[y/CELL][x/CELL] += elements[t].HotAir*(3.5f-pv[y/CELL][x/CELL]);
+ if (y+CELL<YRES && pv[y/CELL+1][x/CELL]<3.5f)
+ pv[y/CELL+1][x/CELL] += elements[t].HotAir*(3.5f-pv[y/CELL+1][x/CELL]);
+ if (x+CELL<XRES)
+ {
+ if (pv[y/CELL][x/CELL+1]<3.5f)
+ pv[y/CELL][x/CELL+1] += elements[t].HotAir*(3.5f-pv[y/CELL][x/CELL+1]);
+ if (y+CELL<YRES && pv[y/CELL+1][x/CELL+1]<3.5f)
+ pv[y/CELL+1][x/CELL+1] += elements[t].HotAir*(3.5f-pv[y/CELL+1][x/CELL+1]);
+ }
+ }
+ else//add the hotair variable to the pressure map, like black hole, or white hole.
+ {
+ pv[y/CELL][x/CELL] += elements[t].HotAir;
+ if (y+CELL<YRES)
+ pv[y/CELL+1][x/CELL] += elements[t].HotAir;
+ if (x+CELL<XRES)
+ {
+ pv[y/CELL][x/CELL+1] += elements[t].HotAir;
+ if (y+CELL<YRES)
+ pv[y/CELL+1][x/CELL+1] += elements[t].HotAir;
+ }
+ }
+
+ //Gravity mode by Moach
+ switch (gravityMode)
+ {
+ default:
+ case 0:
+ pGravX = 0.0f;
+ pGravY = elements[t].Gravity;
+ break;
+ case 1:
+ pGravX = pGravY = 0.0f;
+ break;
+ case 2:
+ pGravD = 0.01f - hypotf((x - XCNTR), (y - YCNTR));
+ pGravX = elements[t].Gravity * ((float)(x - XCNTR) / pGravD);
+ pGravY = elements[t].Gravity * ((float)(y - YCNTR) / pGravD);
+ break;
+ }
+ //Get some gravity from the gravity map
+ if (t==PT_ANAR)
+ {
+ // perhaps we should have a ptypes variable for this
+ pGravX -= gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ pGravY -= gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ }
+ else if(t!=PT_STKM && t!=PT_STKM2 && t!=PT_FIGH && !(elements[t].Properties & TYPE_SOLID))
+ {
+ pGravX += gravx[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ pGravY += gravy[(y/CELL)*(XRES/CELL)+(x/CELL)];
+ }
+ //velocity updates for the particle
+ if (!(parts[i].flags&FLAG_MOVABLE))
+ {
+ parts[i].vx *= elements[t].Loss;
+ parts[i].vy *= elements[t].Loss;
+ }
+ //particle gets velocity from the vx and vy maps
+ parts[i].vx += elements[t].Advection*vx[y/CELL][x/CELL] + pGravX;
+ parts[i].vy += elements[t].Advection*vy[y/CELL][x/CELL] + pGravY;
+
+
+ if (elements[t].Diffusion)//the random diffusion that gasses have
+ {
+#ifdef REALISTIC
+ //The magic number controlls diffusion speed
+ parts[i].vx += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(rand()/(0.5f*RAND_MAX)-1.0f);
+ parts[i].vy += 0.05*sqrtf(parts[i].temp)*elements[t].Diffusion*(rand()/(0.5f*RAND_MAX)-1.0f);
+#else
+ parts[i].vx += elements[t].Diffusion*(rand()/(0.5f*RAND_MAX)-1.0f);
+ parts[i].vy += elements[t].Diffusion*(rand()/(0.5f*RAND_MAX)-1.0f);
+#endif
+ }
+
+ j = surround_space = nt = 0;//if nt is greater than 1 after this, then there is a particle around the current particle, that is NOT the current particle's type, for water movement.
+ for (nx=-1; nx<2; nx++)
+ for (ny=-1; ny<2; ny++) {
+ if (nx||ny) {
+ surround[j] = r = pmap[y+ny][x+nx];
+ j++;
+ if (!(r&0xFF))
+ surround_space++;//there is empty space
+ if ((r&0xFF)!=t)
+ nt++;//there is nothing or a different particle
+ }
+ }
+
+ float gel_scale = 1.0f;
+ if (t==PT_GEL)
+ gel_scale = parts[i].tmp*2.55f;
+
+ if (!legacy_enable)
+ {
+ if (y-2 >= 0 && y-2 < YRES && (elements[t].Properties&TYPE_LIQUID) && (t!=PT_GEL || gel_scale>(1+rand()%255))) {//some heat convection for liquids
+ r = pmap[y-2][x];
+ if (!(!r || parts[i].type != (r&0xFF))) {
+ if (parts[i].temp>parts[r>>8].temp) {
+ swappage = parts[i].temp;
+ parts[i].temp = parts[r>>8].temp;
+ parts[r>>8].temp = swappage;
+ }
+ }
+ }
+
+ //heat transfer code
+ h_count = 0;
+#ifdef REALISTIC
+ if (t&&(t!=PT_HSWC||parts[i].life==10)&&(elements[t].HeatConduct*gel_scale))
+ {
+ float c_Cm = 0.0f;
+#else
+ if (t&&(t!=PT_HSWC||parts[i].life==10)&&(elements[t].HeatConduct*gel_scale)>(rand()%250))
+ {
+ float c_Cm = 0.0f;
+#endif
+ if (aheat_enable && !(elements[t].Properties&PROP_NOAMBHEAT))
+ {
+#ifdef REALISTIC
+ c_heat = parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + hv[y/CELL][x/CELL]*100*(pv[y/CELL][x/CELL]+273.15f)/256;
+ c_Cm = 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight) + 100*(pv[y/CELL][x/CELL]+273.15f)/256;
+ pt = c_heat/c_Cm;
+ pt = restrict_flt(pt, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP);
+ parts[i].temp = pt;
+ //Pressure increase from heat (temporary)
+ pv[y/CELL][x/CELL] += (pt-hv[y/CELL][x/CELL])*0.004;
+ hv[y/CELL][x/CELL] = pt;
+#else
+ c_heat = (hv[y/CELL][x/CELL]-parts[i].temp)*0.04;
+ c_heat = restrict_flt(c_heat, -MAX_TEMP+MIN_TEMP, MAX_TEMP-MIN_TEMP);
+ parts[i].temp += c_heat;
+ hv[y/CELL][x/CELL] -= c_heat;
+#endif
+ }
+ c_heat = 0.0f;
+ c_Cm = 0.0f;
+ for (j=0; j<8; j++)
+ {
+ surround_hconduct[j] = i;
+ r = surround[j];
+ if (!r)
+ continue;
+ rt = r&0xFF;
+ if (rt&&elements[rt].HeatConduct&&(rt!=PT_HSWC||parts[r>>8].life==10)
+ &&(t!=PT_FILT||(rt!=PT_BRAY&&rt!=PT_BIZR&&rt!=PT_BIZRG))
+ &&(rt!=PT_FILT||(t!=PT_BRAY&&t!=PT_PHOT&&t!=PT_BIZR&&t!=PT_BIZRG))
+ &&(t!=PT_ELEC||rt!=PT_DEUT)
+ &&(t!=PT_DEUT||rt!=PT_ELEC))
+ {
+ surround_hconduct[j] = r>>8;
+#ifdef REALISTIC
+ if (rt==PT_GEL)
+ gel_scale = parts[r>>8].tmp*2.55f;
+ else gel_scale = 1.0f;
+
+ c_heat += parts[r>>8].temp*96.645/elements[rt].HeatConduct*gel_scale*fabs(elements[rt].Weight);
+ c_Cm += 96.645/elements[rt].HeatConduct*gel_scale*fabs(elements[rt].Weight);
+#else
+ c_heat += parts[r>>8].temp;
+#endif
+ h_count++;
+ }
+ }
+#ifdef REALISTIC
+ if (t==PT_GEL)
+ gel_scale = parts[i].tmp*2.55f;
+ else gel_scale = 1.0f;
+
+ if (t == PT_PHOT)
+ pt = (c_heat+parts[i].temp*96.645)/(c_Cm+96.645);
+ else
+ pt = (c_heat+parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight))/(c_Cm+96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight));
+
+ c_heat += parts[i].temp*96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight);
+ c_Cm += 96.645/elements[t].HeatConduct*gel_scale*fabs(elements[t].Weight);
+ parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP);
+#else
+ pt = (c_heat+parts[i].temp)/(h_count+1);
+ pt = parts[i].temp = restrict_flt(pt, MIN_TEMP, MAX_TEMP);
+ for (j=0; j<8; j++)
+ {
+ parts[surround_hconduct[j]].temp = pt;
+ }
+#endif
+
+ ctemph = ctempl = pt;
+ // change boiling point with pressure
+ if ((elements[t].State==ST_LIQUID && elements[t].HighTemperatureTransition>-1 && elements[t].HighTemperatureTransition<PT_NUM && elements[elements[t].HighTemperatureTransition].State==ST_GAS)
+ || t==PT_LNTG || t==PT_SLTW)
+ ctemph -= 2.0f*pv[y/CELL][x/CELL];
+ else if ((elements[t].State==ST_GAS && elements[t].LowTemperatureTransition>-1 && elements[t].LowTemperatureTransition<PT_NUM && elements[elements[t].LowTemperatureTransition].State==ST_LIQUID)
+ || t==PT_WTRV)
+ ctempl -= 2.0f*pv[y/CELL][x/CELL];
+ s = 1;
+
+ //A fix for ice with ctype = 0
+ if ((t==PT_ICEI || t==PT_SNOW) && (parts[i].ctype==0 || parts[i].ctype>=PT_NUM || parts[i].ctype==PT_ICEI || parts[i].ctype==PT_SNOW))
+ parts[i].ctype = PT_WATR;
+
+ if (ctemph>elements[t].HighTemperature&&elements[t].HighTemperatureTransition>-1) {
+ // particle type change due to high temperature
+#ifdef REALISTIC
+ float dbt = ctempl - pt;
+ if (elements[t].HighTemperatureTransition!=PT_NUM)
+ {
+ if (platent[t] <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm))
+ {
+ pt = (c_heat - platent[t])/c_Cm;
+ t = elements[t].HighTemperatureTransition;
+ }
+ else
+ {
+ parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP);
+ s = 0;
+ }
+ }
+ #else
+ if (elements[t].HighTemperatureTransition!=PT_NUM)
+ t = elements[t].HighTemperatureTransition;
+#endif
+ else if (t==PT_ICEI || t==PT_SNOW) {
+ if (parts[i].ctype<PT_NUM&&parts[i].ctype!=t) {
+ if (elements[parts[i].ctype].LowTemperatureTransition==t&&pt<=elements[parts[i].ctype].LowTemperature) s = 0;
+ else {
+#ifdef REALISTIC
+ //One ice table value for all it's kinds
+ if (platent[t] <= (c_heat - (elements[parts[i].ctype].LowTemperature - dbt)*c_Cm))
+ {
+ pt = (c_heat - platent[t])/c_Cm;
+ t = parts[i].ctype;
+ parts[i].ctype = PT_NONE;
+ parts[i].life = 0;
+ }
+ else
+ {
+ parts[i].temp = restrict_flt(elements[parts[i].ctype].LowTemperature - dbt, MIN_TEMP, MAX_TEMP);
+ s = 0;
+ }
+ #else
+ t = parts[i].ctype;
+ parts[i].ctype = PT_NONE;
+ parts[i].life = 0;
+#endif
+ }
+ }
+ else s = 0;
+ }
+ else if (t==PT_SLTW) {
+#ifdef REALISTIC
+ if (platent[t] <= (c_heat - (elements[t].HighTemperature - dbt)*c_Cm))
+ {
+ pt = (c_heat - platent[t])/c_Cm;
+
+ if (rand()%4==0) t = PT_SALT;
+ else t = PT_WTRV;
+ }
+ else
+ {
+ parts[i].temp = restrict_flt(elements[t].HighTemperature - dbt, MIN_TEMP, MAX_TEMP);
+ s = 0;
+ }
+#else
+ if (rand()%4==0) t = PT_SALT;
+ else t = PT_WTRV;
+#endif
+ }
+ else s = 0;
+ } else if (ctempl<elements[t].LowTemperature&&elements[t].LowTemperatureTransition>-1) {
+ // particle type change due to low temperature
+#ifdef REALISTIC
+ float dbt = ctempl - pt;
+ if (elements[t].LowTemperatureTransition!=PT_NUM)
+ {
+ if (platent[elements[t].LowTemperatureTransition] >= (c_heat - (elements[t].LowTemperature - dbt)*c_Cm))
+ {
+ pt = (c_heat + platent[elements[t].LowTemperatureTransition])/c_Cm;
+ t = elements[t].LowTemperatureTransition;
+ }
+ else
+ {
+ parts[i].temp = restrict_flt(elements[t].LowTemperature - dbt, MIN_TEMP, MAX_TEMP);
+ s = 0;
+ }
+ }
+#else
+ if (elements[t].LowTemperatureTransition!=PT_NUM)
+ t = elements[t].LowTemperatureTransition;
+#endif
+ else if (t==PT_WTRV) {
+ if (pt<273.0f) t = PT_RIME;
+ else t = PT_DSTW;
+ }
+ else if (t==PT_LAVA) {
+ if (parts[i].ctype>0 && parts[i].ctype<PT_NUM && parts[i].ctype!=PT_LAVA) {
+ if (parts[i].ctype==PT_THRM&&pt>=elements[PT_BMTL].HighTemperature) s = 0;
+ else if ((parts[i].ctype==PT_VIBR || parts[i].ctype==PT_BVBR) && pt>=273.15f) s = 0;
+ else if (elements[parts[i].ctype].HighTemperatureTransition==PT_LAVA) {
+ if (pt>=elements[parts[i].ctype].HighTemperature) s = 0;
+ }
+ else if (pt>=973.0f) s = 0; // freezing point for lava with any other (not listed in ptransitions as turning into lava) ctype
+ if (s) {
+ t = parts[i].ctype;
+ parts[i].ctype = PT_NONE;
+ if (t==PT_THRM) {
+ parts[i].tmp = 0;
+ t = PT_BMTL;
+ }
+ if (t==PT_PLUT)
+ {
+ parts[i].tmp = 0;
+ t = PT_LAVA;
+ }
+ }
+ }
+ else if (pt<973.0f) t = PT_STNE;
+ else s = 0;
+ }
+ else s = 0;
+ }
+ else s = 0;
+#ifdef REALISTIC
+ pt = restrict_flt(pt, MIN_TEMP, MAX_TEMP);
+ for (j=0; j<8; j++)
+ {
+ parts[surround_hconduct[j]].temp = pt;
+ }
+#endif
+ if (s) { // particle type change occurred
+ if (t==PT_ICEI||t==PT_LAVA||t==PT_SNOW)
+ parts[i].ctype = parts[i].type;
+ if (!(t==PT_ICEI&&parts[i].ctype==PT_FRZW)) parts[i].life = 0;
+ if (elements[t].State==ST_GAS&&elements[parts[i].type].State!=ST_GAS)
+ pv[y/CELL][x/CELL] += 0.50f;
+ part_change_type(i,x,y,t);
+ if (t==PT_FIRE||t==PT_PLSM||t==PT_HFLM)
+ parts[i].life = rand()%50+120;
+ if (t==PT_LAVA) {
+ if (parts[i].ctype==PT_BRMT) parts[i].ctype = PT_BMTL;
+ else if (parts[i].ctype==PT_SAND) parts[i].ctype = PT_GLAS;
+ else if (parts[i].ctype==PT_BGLA) parts[i].ctype = PT_GLAS;
+ else if (parts[i].ctype==PT_PQRT) parts[i].ctype = PT_QRTZ;
+ parts[i].life = rand()%120+240;
+ }
+ if (t==PT_NONE) {
+ kill_part(i);
+ goto killed;
+ }
+ }
+
+ pt = parts[i].temp = restrict_flt(parts[i].temp, MIN_TEMP, MAX_TEMP);
+ if (t==PT_LAVA) {
+ parts[i].life = restrict_flt((parts[i].temp-700)/7, 0.0f, 400.0f);
+ if (parts[i].ctype==PT_THRM&&parts[i].tmp>0)
+ {
+ parts[i].tmp--;
+ parts[i].temp = 3500;
+ }
+ if (parts[i].ctype==PT_PLUT&&parts[i].tmp>0)
+ {
+ parts[i].tmp--;
+ parts[i].temp = MAX_TEMP;
+ }
+ }
+#ifdef REALISTIC //needed to fix update_particles_i parsing
+ }
+#else
+ }
+#endif
+ else parts[i].temp = restrict_flt(parts[i].temp, MIN_TEMP, MAX_TEMP);
+ }
+
+ if (t==PT_LIFE)
+ {
+ parts[i].temp = restrict_flt(parts[i].temp-50.0f, MIN_TEMP, MAX_TEMP);
+ //ISGOL=1;//means there is a life particle on screen
+ }
+ if (t==PT_WIRE)
+ {
+ //wire_placed = 1;
+ }
+ //spark updates from walls
+ if ((elements[t].Properties&PROP_CONDUCTS) || t==PT_SPRK)
+ {
+ nx = x % CELL;
+ if (nx == 0)
+ nx = x/CELL - 1;
+ else if (nx == CELL-1)
+ nx = x/CELL + 1;
+ else
+ nx = x/CELL;
+ ny = y % CELL;
+ if (ny == 0)
+ ny = y/CELL - 1;
+ else if (ny == CELL-1)
+ ny = y/CELL + 1;
+ else
+ ny = y/CELL;
+ if (nx>=0 && ny>=0 && nx<XRES/CELL && ny<YRES/CELL)
+ {
+ if (t!=PT_SPRK)
+ {
+ if (emap[ny][nx]==12 && !parts[i].life)
+ {
+ part_change_type(i,x,y,PT_SPRK);
+ parts[i].life = 4;
+ parts[i].ctype = t;
+ t = PT_SPRK;
+ }
+ }
+ else if (bmap[ny][nx]==WL_DETECT || bmap[ny][nx]==WL_EWALL || bmap[ny][nx]==WL_ALLOWLIQUID || bmap[ny][nx]==WL_WALLELEC || bmap[ny][nx]==WL_ALLOWALLELEC || bmap[ny][nx]==WL_EHOLE)
+ set_emap(nx, ny);
+ }
+ }
+
+ //the basic explosion, from the .explosive variable
+ if ((elements[t].Explosive&2) && pv[y/CELL][x/CELL]>2.5f)
+ {
+ parts[i].life = rand()%80+180;
+ parts[i].temp = restrict_flt(elements[PT_FIRE].Temperature + (elements[t].Flammable/2), MIN_TEMP, MAX_TEMP);
+ t = PT_FIRE;
+ part_change_type(i,x,y,t);
+ pv[y/CELL][x/CELL] += 0.25f * CFDS;
+ }
+
+
+ s = 1;
+ gravtot = fabs(gravy[(y/CELL)*(XRES/CELL)+(x/CELL)])+fabs(gravx[(y/CELL)*(XRES/CELL)+(x/CELL)]);
+ if (pv[y/CELL][x/CELL]>elements[t].HighPressure&&elements[t].HighPressureTransition>-1) {
+ // particle type change due to high pressure
+ if (elements[t].HighPressureTransition!=PT_NUM)
+ t = elements[t].HighPressureTransition;
+ else if (t==PT_BMTL) {
+ if (pv[y/CELL][x/CELL]>2.5f)
+ t = PT_BRMT;
+ else if (pv[y/CELL][x/CELL]>1.0f && parts[i].tmp==1)
+ t = PT_BRMT;
+ else s = 0;
+ }
+ else s = 0;
+ } else if (pv[y/CELL][x/CELL]<elements[t].LowPressure&&elements[t].LowPressureTransition>-1) {
+ // particle type change due to low pressure
+ if (elements[t].LowPressureTransition!=PT_NUM)
+ t = elements[t].LowPressureTransition;
+ else s = 0;
+ } else if (gravtot>(elements[t].HighPressure/4.0f)&&elements[t].HighPressureTransition>-1) {
+ // particle type change due to high gravity
+ if (elements[t].HighPressureTransition!=PT_NUM)
+ t = elements[t].HighPressureTransition;
+ else if (t==PT_BMTL) {
+ if (gravtot>0.625f)
+ t = PT_BRMT;
+ else if (gravtot>0.25f && parts[i].tmp==1)
+ t = PT_BRMT;
+ else s = 0;
+ }
+ else s = 0;
+ } else s = 0;
+ if (s) { // particle type change occurred
+ parts[i].life = 0;
+ part_change_type(i,x,y,t);
+ if (t==PT_FIRE)
+ parts[i].life = rand()%50+120;
+ if (t==PT_NONE) {
+ kill_part(i);
+ goto killed;
+ }
+ }
+
+ //call the particle update function, if there is one
+#ifdef LUACONSOLE
+ if (elements[t].Update && lua_el_mode[t] != 2)
+#else
+ if (elements[t].Update)
+#endif
+ {
+ if ((*(elements[t].Update))(this, i,x,y,surround_space,nt, parts, pmap))
+ continue;
+ else if (t==PT_WARP)
+ {
+ // Warp does some movement in its update func, update variables to avoid incorrect data in pmap
+ x = (int)(parts[i].x+0.5f);
+ y = (int)(parts[i].y+0.5f);
+ }
+ }
+#ifdef LUACONSOLE
+ if(lua_el_mode[t])
+ {
+ if(luacon_part_update(t,i,x,y,surround_space,nt))
+ continue;
+ // Need to update variables, in case they've been changed by Lua
+ x = (int)(parts[i].x+0.5f);
+ y = (int)(parts[i].y+0.5f);
+ }
+#endif
+
+
+ if(legacy_enable)//if heat sim is off
+ Element::legacyUpdate(this, i,x,y,surround_space,nt, parts, pmap);
+
+killed:
+ if (parts[i].type == PT_NONE)//if its dead, skip to next particle
+ continue;
+
+ if (!parts[i].vx&&!parts[i].vy)//if its not moving, skip to next particle, movement code it next
+ continue;
+
+ mv = fmaxf(fabsf(parts[i].vx), fabsf(parts[i].vy));
+ if (mv < ISTP)
+ {
+ clear_x = x;
+ clear_y = y;
+ clear_xf = parts[i].x;
+ clear_yf = parts[i].y;
+ fin_xf = clear_xf + parts[i].vx;
+ fin_yf = clear_yf + parts[i].vy;
+ fin_x = (int)(fin_xf+0.5f);
+ fin_y = (int)(fin_yf+0.5f);
+ }
+ else
+ {
+ // interpolate to see if there is anything in the way
+ dx = parts[i].vx*ISTP/mv;
+ dy = parts[i].vy*ISTP/mv;
+ fin_xf = parts[i].x;
+ fin_yf = parts[i].y;
+ while (1)
+ {
+ mv -= ISTP;
+ fin_xf += dx;
+ fin_yf += dy;
+ fin_x = (int)(fin_xf+0.5f);
+ fin_y = (int)(fin_yf+0.5f);
+ if (mv <= 0.0f)
+ {
+ // nothing found
+ fin_xf = parts[i].x + parts[i].vx;
+ fin_yf = parts[i].y + parts[i].vy;
+ fin_x = (int)(fin_xf+0.5f);
+ fin_y = (int)(fin_yf+0.5f);
+ clear_xf = fin_xf-dx;
+ clear_yf = fin_yf-dy;
+ clear_x = (int)(clear_xf+0.5f);
+ clear_y = (int)(clear_yf+0.5f);
+ break;
+ }
+ if (fin_x<CELL || fin_y<CELL || fin_x>=XRES-CELL || fin_y>=YRES-CELL || pmap[fin_y][fin_x] || (bmap[fin_y/CELL][fin_x/CELL] && (bmap[fin_y/CELL][fin_x/CELL]==WL_DESTROYALL || !eval_move(t,fin_x,fin_y,NULL))))
+ {
+ // found an obstacle
+ clear_xf = fin_xf-dx;
+ clear_yf = fin_yf-dy;
+ clear_x = (int)(clear_xf+0.5f);
+ clear_y = (int)(clear_yf+0.5f);
+ break;
+ }
+ if (bmap[fin_y/CELL][fin_x/CELL]==WL_DETECT && emap[fin_y/CELL][fin_x/CELL]<8)
+ set_emap(fin_x/CELL, fin_y/CELL);
+ }
+ }
+
+ stagnant = parts[i].flags & FLAG_STAGNANT;
+ parts[i].flags &= ~FLAG_STAGNANT;
+
+ if (t==PT_STKM || t==PT_STKM2 || t==PT_FIGH)
+ {
+ int nx, ny;
+ //head movement, let head pass through anything
+ parts[i].x += parts[i].vx;
+ parts[i].y += parts[i].vy;
+ nx = (int)((float)parts[i].x+0.5f);
+ ny = (int)((float)parts[i].y+0.5f);
+ if (ny!=y || nx!=x)
+ {
+ if ((pmap[y][x]>>8)==i) pmap[y][x] = 0;
+ else if ((photons[y][x]>>8)==i) photons[y][x] = 0;
+ if (nx<CELL || nx>=XRES-CELL || ny<CELL || ny>=YRES-CELL)
+ {
+ kill_part(i);
+ continue;
+ }
+ if (elements[t].Properties & TYPE_ENERGY)
+ photons[ny][nx] = t|(i<<8);
+ else if (t)
+ pmap[ny][nx] = t|(i<<8);
+ }
+ }
+ else if (elements[t].Properties & TYPE_ENERGY)
+ {
+ if (t == PT_PHOT) {
+ if (parts[i].flags&FLAG_SKIPMOVE)
+ {
+ parts[i].flags &= ~FLAG_SKIPMOVE;
+ continue;
+ }
+
+ rt = pmap[fin_y][fin_x] & 0xFF;
+ lt = pmap[y][x] & 0xFF;
+
+ r = eval_move(PT_PHOT, fin_x, fin_y, NULL);
+ if (((rt==PT_GLAS && lt!=PT_GLAS) || (rt!=PT_GLAS && lt==PT_GLAS)) && r) {
+ if (!get_normal_interp(REFRACT|t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy, &nrx, &nry)) {
+ kill_part(i);
+ continue;
+ }
+
+ r = get_wavelength_bin(&parts[i].ctype);
+ if (r == -1) {
+ kill_part(i);
+ continue;
+ }
+ nn = GLASS_IOR - GLASS_DISP*(r-15)/15.0f;
+ nn *= nn;
+ nrx = -nrx;
+ nry = -nry;
+ if (rt==PT_GLAS && lt!=PT_GLAS)
+ nn = 1.0f/nn;
+ ct1 = parts[i].vx*nrx + parts[i].vy*nry;
+ ct2 = 1.0f - (nn*nn)*(1.0f-(ct1*ct1));
+ if (ct2 < 0.0f) {
+ // total internal reflection
+ parts[i].vx -= 2.0f*ct1*nrx;
+ parts[i].vy -= 2.0f*ct1*nry;
+ fin_xf = parts[i].x;
+ fin_yf = parts[i].y;
+ fin_x = x;
+ fin_y = y;
+ } else {
+ // refraction
+ ct2 = sqrtf(ct2);
+ ct2 = ct2 - nn*ct1;
+ parts[i].vx = nn*parts[i].vx + ct2*nrx;
+ parts[i].vy = nn*parts[i].vy + ct2*nry;
+ }
+ }
+ }
+ if (stagnant)//FLAG_STAGNANT set, was reflected on previous frame
+ {
+ // cast coords as int then back to float for compatibility with existing saves
+ if (!do_move(i, x, y, (float)fin_x, (float)fin_y) && parts[i].type) {
+ kill_part(i);
+ continue;
+ }
+ }
+ else if (!do_move(i, x, y, fin_xf, fin_yf))
+ {
+ if (parts[i].type == PT_NONE)
+ continue;
+ // reflection
+ parts[i].flags |= FLAG_STAGNANT;
+ if (t==PT_NEUT && 100>(rand()%1000))
+ {
+ kill_part(i);
+ continue;
+ }
+ r = pmap[fin_y][fin_x];
+
+ if (((r&0xFF)==PT_PIPE || (r&0xFF) == PT_PPIP) && !(parts[r>>8].tmp&0xFF))
+ {
+ parts[r>>8].tmp = (parts[r>>8].tmp&~0xFF) | parts[i].type;
+ parts[r>>8].temp = parts[i].temp;
+ parts[r>>8].tmp2 = parts[i].life;
+ parts[r>>8].pavg[0] = parts[i].tmp;
+ parts[r>>8].pavg[1] = parts[i].ctype;
+ kill_part(i);
+ continue;
+ }
+
+ // this should be replaced with a particle type attribute ("photwl" or something)
+ if ((r & 0xFF) == PT_PSCN) parts[i].ctype = 0x00000000;
+ if ((r & 0xFF) == PT_NSCN) parts[i].ctype = 0x00000000;
+ if ((r & 0xFF) == PT_SPRK) parts[i].ctype = 0x00000000;
+ if ((r & 0xFF) == PT_COAL) parts[i].ctype = 0x00000000;
+ if ((r & 0xFF) == PT_BCOL) parts[i].ctype = 0x00000000;
+ if ((r & 0xFF) == PT_PLEX) parts[i].ctype &= 0x1F00003E;
+ if ((r & 0xFF) == PT_NITR) parts[i].ctype &= 0x0007C000;
+ if ((r & 0xFF) == PT_NBLE) parts[i].ctype &= 0x3FFF8000;
+ if ((r & 0xFF) == PT_LAVA) parts[i].ctype &= 0x3FF00000;
+ if ((r & 0xFF) == PT_ACID) parts[i].ctype &= 0x1FE001FE;
+ if ((r & 0xFF) == PT_DUST) parts[i].ctype &= 0x3FFFFFC0;
+ if ((r & 0xFF) == PT_SNOW) parts[i].ctype &= 0x03FFFFFF;
+ if ((r & 0xFF) == PT_GOO) parts[i].ctype &= 0x3FFAAA00;
+ if ((r & 0xFF) == PT_PLNT) parts[i].ctype &= 0x0007C000;
+ if ((r & 0xFF) == PT_PLUT) parts[i].ctype &= 0x001FCE00;
+ if ((r & 0xFF) == PT_URAN) parts[i].ctype &= 0x003FC000;
+
+ if (get_normal_interp(t, parts[i].x, parts[i].y, parts[i].vx, parts[i].vy, &nrx, &nry)) {
+ dp = nrx*parts[i].vx + nry*parts[i].vy;
+ parts[i].vx -= 2.0f*dp*nrx;
+ parts[i].vy -= 2.0f*dp*nry;
+ // leave the actual movement until next frame so that reflection of fast particles and refraction happen correctly
+ } else {
+ if (t!=PT_NEUT)
+ kill_part(i);
+ continue;
+ }
+ if (!(parts[i].ctype&0x3FFFFFFF)&&t!=PT_NEUT&&t!=PT_ELEC) {
+ kill_part(i);
+ continue;
+ }
+ }
+ }
+ else if (elements[t].Falldown==0)
+ {
+ // gasses and solids (but not powders)
+ if (!do_move(i, x, y, fin_xf, fin_yf))
+ {
+ if (parts[i].type == PT_NONE)
+ continue;
+ // can't move there, so bounce off
+ // TODO
+ // TODO: Work out what previous TODO was for
+ if (fin_x>x+ISTP) fin_x=x+ISTP;
+ if (fin_x<x-ISTP) fin_x=x-ISTP;
+ if (fin_y>y+ISTP) fin_y=y+ISTP;
+ if (fin_y<y-ISTP) fin_y=y-ISTP;
+ if (do_move(i, x, y, 0.25f+(float)(2*x-fin_x), 0.25f+fin_y))
+ {
+ parts[i].vx *= elements[t].Collision;
+ }
+ else if (do_move(i, x, y, 0.25f+fin_x, 0.25f+(float)(2*y-fin_y)))
+ {
+ parts[i].vy *= elements[t].Collision;
+ }
+ else
+ {
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ }
+ }
+ }
+ else
+ {
+ if (water_equal_test && elements[t].Falldown == 2 && 1>= rand()%400)//checking stagnant is cool, but then it doesn't update when you change it later.
+ {
+ if (!flood_water(x,y,i,y, parts[i].tmp2))
+ goto movedone;
+ }
+ // liquids and powders
+ if (!do_move(i, x, y, fin_xf, fin_yf))
+ {
+ if (parts[i].type == PT_NONE)
+ continue;
+ if (fin_x!=x && do_move(i, x, y, fin_xf, clear_yf))
+ {
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ }
+ else if (fin_y!=y && do_move(i, x, y, clear_xf, fin_yf))
+ {
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ }
+ else
+ {
+ s = 1;
+ r = (rand()%2)*2-1;
+ if ((clear_x!=x || clear_y!=y || nt || surround_space) &&
+ (fabsf(parts[i].vx)>0.01f || fabsf(parts[i].vy)>0.01f))
+ {
+ // allow diagonal movement if target position is blocked
+ // but no point trying this if particle is stuck in a block of identical particles
+ dx = parts[i].vx - parts[i].vy*r;
+ dy = parts[i].vy + parts[i].vx*r;
+ if (fabsf(dy)>fabsf(dx))
+ mv = fabsf(dy);
+ else
+ mv = fabsf(dx);
+ dx /= mv;
+ dy /= mv;
+ if (do_move(i, x, y, clear_xf+dx, clear_yf+dy))
+ {
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ goto movedone;
+ }
+ swappage = dx;
+ dx = dy*r;
+ dy = -swappage*r;
+ if (do_move(i, x, y, clear_xf+dx, clear_yf+dy))
+ {
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ goto movedone;
+ }
+ }
+ if (elements[t].Falldown>1 && !grav->ngrav_enable && gravityMode==0 && parts[i].vy>fabsf(parts[i].vx))
+ {
+ s = 0;
+ // stagnant is true if FLAG_STAGNANT was set for this particle in previous frame
+ if (!stagnant || nt) //nt is if there is an something else besides the current particle type, around the particle
+ rt = 30;//slight less water lag, although it changes how it moves a lot
+ else
+ rt = 10;
+
+ if (t==PT_GEL)
+ rt = parts[i].tmp*0.20f+5.0f;
+
+ for (j=clear_x+r; j>=0 && j>=clear_x-rt && j<clear_x+rt && j<XRES; j+=r)
+ {
+ if (((pmap[fin_y][j]&0xFF)!=t || bmap[fin_y/CELL][j/CELL])
+ && (s=do_move(i, x, y, (float)j, fin_yf)))
+ {
+ nx = (int)(parts[i].x+0.5f);
+ ny = (int)(parts[i].y+0.5f);
+ break;
+ }
+ if (fin_y!=clear_y && ((pmap[clear_y][j]&0xFF)!=t || bmap[clear_y/CELL][j/CELL])
+ && (s=do_move(i, x, y, (float)j, clear_yf)))
+ {
+ nx = (int)(parts[i].x+0.5f);
+ ny = (int)(parts[i].y+0.5f);
+ break;
+ }
+ if ((pmap[clear_y][j]&0xFF)!=t || (bmap[clear_y/CELL][j/CELL] && bmap[clear_y/CELL][j/CELL]!=WL_STREAM))
+ break;
+ }
+ if (parts[i].vy>0)
+ r = 1;
+ else
+ r = -1;
+ if (s==1)
+ for (j=ny+r; j>=0 && j<YRES && j>=ny-rt && j<ny+rt; j+=r)
+ {
+ if (((pmap[j][nx]&0xFF)!=t || bmap[j/CELL][nx/CELL]) && do_move(i, nx, ny, (float)nx, (float)j))
+ break;
+ if ((pmap[j][nx]&255)!=t || (bmap[j/CELL][nx/CELL] && bmap[j/CELL][nx/CELL]!=WL_STREAM))
+ break;
+ }
+ else if (s==-1) {} // particle is out of bounds
+ else if ((clear_x!=x||clear_y!=y) && do_move(i, x, y, clear_xf, clear_yf)) {}
+ else parts[i].flags |= FLAG_STAGNANT;
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ }
+ else if (elements[t].Falldown>1 && fabsf(pGravX*parts[i].vx+pGravY*parts[i].vy)>fabsf(pGravY*parts[i].vx-pGravX*parts[i].vy))
+ {
+ float nxf, nyf, prev_pGravX, prev_pGravY, ptGrav = elements[t].Gravity;
+ s = 0;
+ // stagnant is true if FLAG_STAGNANT was set for this particle in previous frame
+ if (!stagnant || nt) //nt is if there is an something else besides the current particle type, around the particle
+ rt = 30;//slight less water lag, although it changes how it moves a lot
+ else
+ rt = 10;
+ nxf = clear_xf;
+ nyf = clear_yf;
+ for (j=0;j<rt;j++)
+ {
+ switch (gravityMode)
+ {
+ default:
+ case 0:
+ pGravX = 0.0f;
+ pGravY = ptGrav;
+ break;
+ case 1:
+ pGravX = pGravY = 0.0f;
+ break;
+ case 2:
+ pGravD = 0.01f - hypotf((nx - XCNTR), (ny - YCNTR));
+ pGravX = ptGrav * ((float)(nx - XCNTR) / pGravD);
+ pGravY = ptGrav * ((float)(ny - YCNTR) / pGravD);
+ break;
+ }
+ pGravX += gravx[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
+ pGravY += gravy[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
+ if (fabsf(pGravY)>fabsf(pGravX))
+ mv = fabsf(pGravY);
+ else
+ mv = fabsf(pGravX);
+ if (mv<0.0001f) break;
+ pGravX /= mv;
+ pGravY /= mv;
+ if (j)
+ {
+ nxf += r*(pGravY*2.0f-prev_pGravY);
+ nyf += -r*(pGravX*2.0f-prev_pGravX);
+ }
+ else
+ {
+ nxf += r*pGravY;
+ nyf += -r*pGravX;
+ }
+ prev_pGravX = pGravX;
+ prev_pGravY = pGravY;
+ nx = (int)(nxf+0.5f);
+ ny = (int)(nyf+0.5f);
+ if (nx<0 || ny<0 || nx>=XRES || ny >=YRES)
+ break;
+ if ((pmap[ny][nx]&0xFF)!=t || bmap[ny/CELL][nx/CELL])
+ {
+ s = do_move(i, x, y, nxf, nyf);
+ if (s)
+ {
+ nx = (int)(parts[i].x+0.5f);
+ ny = (int)(parts[i].y+0.5f);
+ break;
+ }
+ if (bmap[ny/CELL][nx/CELL]!=WL_STREAM)
+ break;
+ }
+ }
+ if (s==1)
+ {
+ clear_x = nx;
+ clear_y = ny;
+ for (j=0;j<rt;j++)
+ {
+ switch (gravityMode)
+ {
+ default:
+ case 0:
+ pGravX = 0.0f;
+ pGravY = ptGrav;
+ break;
+ case 1:
+ pGravX = pGravY = 0.0f;
+ break;
+ case 2:
+ pGravD = 0.01f - hypotf((nx - XCNTR), (ny - YCNTR));
+ pGravX = ptGrav * ((float)(nx - XCNTR) / pGravD);
+ pGravY = ptGrav * ((float)(ny - YCNTR) / pGravD);
+ break;
+ }
+ pGravX += gravx[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
+ pGravY += gravy[(ny/CELL)*(XRES/CELL)+(nx/CELL)];
+ if (fabsf(pGravY)>fabsf(pGravX))
+ mv = fabsf(pGravY);
+ else
+ mv = fabsf(pGravX);
+ if (mv<0.0001f) break;
+ pGravX /= mv;
+ pGravY /= mv;
+ nxf += pGravX;
+ nyf += pGravY;
+ nx = (int)(nxf+0.5f);
+ ny = (int)(nyf+0.5f);
+ if (nx<0 || ny<0 || nx>=XRES || ny>=YRES)
+ break;
+ if ((pmap[ny][nx]&0xFF)!=t || bmap[ny/CELL][nx/CELL])
+ {
+ s = do_move(i, clear_x, clear_y, nxf, nyf);
+ if (s || bmap[ny/CELL][nx/CELL]!=WL_STREAM)
+ break;
+ }
+ }
+ }
+ else if (s==-1) {} // particle is out of bounds
+ else if ((clear_x!=x||clear_y!=y) && do_move(i, x, y, clear_xf, clear_yf)) {}
+ else parts[i].flags |= FLAG_STAGNANT;
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ }
+ else
+ {
+ // if interpolation was done, try moving to last clear position
+ if ((clear_x!=x||clear_y!=y) && do_move(i, x, y, clear_xf, clear_yf)) {}
+ else parts[i].flags |= FLAG_STAGNANT;
+ parts[i].vx *= elements[t].Collision;
+ parts[i].vy *= elements[t].Collision;
+ }
+ }
+ }
+ }
+movedone:
+ continue;
+ }
+}
+
+int Simulation::GetParticleType(std::string type)
+{
+ int i = -1;
+ char * txt = (char*)type.c_str();
+
+ // alternative names for some elements
+ if (strcasecmp(txt,"C4")==0) i = PT_PLEX;
+ else if (strcasecmp(txt,"C5")==0) i = PT_C5;
+ else if (strcasecmp(txt,"NONE")==0) i = PT_NONE;
+ for (i=1; i<PT_NUM; i++) {
+ if (strcasecmp(txt, elements[i].Name)==0 && strlen(elements[i].Name) && elements[i].Enabled)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+void Simulation::update_particles()//doesn't update the particles themselves, but some other things
+{
+ int i, j, x, y, t, nx, ny, r, cr,cg,cb, l = -1;
+ float lx, ly;
+ int lastPartUsed = 0;
+ int lastPartUnused = -1;
+#ifdef MT
+ int pt = 0, pc = 0;
+ pthread_t *InterThreads;
+#endif
+
+ if(!sys_pause||framerender)
+ {
+ air->update_air();
+
+ if(aheat_enable)
+ air->update_airh();
+
+ if(grav->ngrav_enable)
+ {
+ grav->gravity_update_async();
+
+ //Get updated buffer pointers for gravity
+ gravx = grav->gravx;
+ gravy = grav->gravy;
+ gravp = grav->gravp;
+ gravmap = grav->gravmap;
+
+ if(gravWallChanged)
+ {
+ grav->gravity_mask();
+ gravWallChanged = false;
+ }
+ }
+ if(emp_decor>0)
+ emp_decor -= emp_decor/25+2;
+ if(emp_decor < 0)
+ emp_decor = 0;
+ }
+ sandcolour = (int)(20.0f*sin((float)sandcolour_frame*(M_PI/180.0f)));
+ sandcolour_frame = (sandcolour_frame++)%360;
+
+ memset(pmap, 0, sizeof(pmap));
+ memset(pmap_count, 0, sizeof(pmap_count));
+ memset(photons, 0, sizeof(photons));
+ NUM_PARTS = 0;
+ for (i=0; i<=parts_lastActiveIndex; i++)//the particle loop that resets the pmap/photon maps every frame, to update them.
+ {
+ if (parts[i].type)
+ {
+ t = parts[i].type;
+ x = (int)(parts[i].x+0.5f);
+ y = (int)(parts[i].y+0.5f);
+ if (x>=0 && y>=0 && x<XRES && y<YRES)
+ {
+ if (elements[t].Properties & TYPE_ENERGY)
+ photons[y][x] = t|(i<<8);
+ else
+ {
+ // Particles are sometimes allowed to go inside INVS and FILT
+ // 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))
+ pmap[y][x] = t|(i<<8);
+ // (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)
+ pmap_count[y][x]++;
+ }
+ }
+ lastPartUsed = i;
+ NUM_PARTS ++;
+ }
+ else
+ {
+ if (lastPartUnused<0) pfree = i;
+ else parts[lastPartUnused].life = i;
+ lastPartUnused = i;
+ }
+ }
+ if (lastPartUnused==-1)
+ {
+ if (parts_lastActiveIndex>=NPART-1) pfree = -1;
+ else pfree = parts_lastActiveIndex+1;
+ }
+ else
+ {
+ if (parts_lastActiveIndex>=NPART-1) parts[lastPartUnused].life = -1;
+ else parts[lastPartUnused].life = parts_lastActiveIndex+1;
+ }
+ parts_lastActiveIndex = lastPartUsed;
+ if (!sys_pause||framerender)
+ {
+ for (y=0; y<YRES/CELL; y++)
+ {
+ for (x=0; x<XRES/CELL; x++)
+ {
+ if (emap[y][x])
+ emap[y][x] --;
+ air->bmap_blockair[y][x] = (bmap[y][x]==WL_WALL || bmap[y][x]==WL_WALLELEC || (bmap[y][x]==WL_EWALL && !emap[y][x]));
+ air->bmap_blockairh[y][x] = (bmap[y][x]==WL_WALL || bmap[y][x]==WL_WALLELEC || bmap[y][x]==WL_GRAV || (bmap[y][x]==WL_EWALL && !emap[y][x]));
+ }
+ }
+ }
+
+ if(!sys_pause||framerender)
+ update_particles_i(0, 1);
+
+ if(framerender)
+ framerender--;
+ // this should probably be elsewhere
+ /*for (y=0; y<YRES/CELL; y++)
+ for (x=0; x<XRES/CELL; x++)
+ if (bmap[y][x]==WL_STREAM)
+ {
+ lx = x*CELL + CELL*0.5f;
+ ly = y*CELL + CELL*0.5f;
+ for (t=0; t<1024; t++)
+ {
+ nx = (int)(lx+0.5f);
+ ny = (int)(ly+0.5f);
+ if (nx<0 || nx>=XRES || ny<0 || ny>=YRES)
+ break;
+ addpixel(vid, nx, ny, 255, 255, 255, 64);
+ i = nx/CELL;
+ j = ny/CELL;
+ lx += vx[j][i]*0.125f;
+ ly += vy[j][i]*0.125f;
+ if (bmap[j][i]==WL_STREAM && i!=x && j!=y)
+ break;
+ }
+ drawtext(vid, x*CELL, y*CELL-2, "\x8D", 255, 255, 255, 128);
+ }
+*/
+}
+
+Simulation::~Simulation()
+{
+ delete[] platent;
+ delete grav;
+ delete air;
+ for(int i = 0; i < tools.size(); i++)
+ delete tools[i];
+}
+
+Simulation::Simulation():
+ sys_pause(0),
+ framerender(false),
+ pretty_powder(0),
+ sandcolour_frame(0)
+{
+
+ int tportal_rx[] = {-1, 0, 1, 1, 1, 0,-1,-1};
+ int tportal_ry[] = {-1,-1,-1, 0, 1, 1, 1, 0};
+
+ memcpy(portal_rx, tportal_rx, sizeof(tportal_rx));
+ memcpy(portal_ry, tportal_ry, sizeof(tportal_ry));
+
+ currentTick = 0;
+ std::fill(elementCount, elementCount+PT_NUM, 0);
+
+ //Create and attach gravity simulation
+ grav = new Gravity();
+ //Give air sim references to our data
+ grav->bmap = bmap;
+ //Gravity sim gives us maps to use
+ gravx = grav->gravx;
+ gravy = grav->gravy;
+ gravp = grav->gravp;
+ gravmap = grav->gravmap;
+
+ //Create and attach air simulation
+ air = new Air(*this);
+ //Give air sim references to our data
+ air->bmap = bmap;
+ air->emap = emap;
+ air->fvx = fvx;
+ air->fvy = fvy;
+ //Air sim gives us maps to use
+ vx = air->vx;
+ vy = air->vy;
+ pv = air->pv;
+ hv = air->hv;
+
+ int menuCount;
+ menu_section * msectionsT = LoadMenus(menuCount);
+ memcpy(msections, msectionsT, menuCount * sizeof(menu_section));
+ free(msectionsT);
+
+ int wallCount;
+ wall_type * wtypesT = LoadWalls(wallCount);
+ memcpy(wtypes, wtypesT, wallCount * sizeof(wall_type));
+ free(wtypesT);
+
+ platent = new unsigned[PT_NUM];
+ int latentCount;
+ unsigned int * platentT = LoadLatent(latentCount);
+ memcpy(platent, platentT, latentCount * sizeof(unsigned int));
+ free(platentT);
+
+ //elements = new Element[PT_NUM];
+ std::vector<Element> elementList = GetElements();
+ for(int i = 0; i < PT_NUM; i++)
+ {
+ if(i < elementList.size())
+ elements[i] = elementList[i];
+ else
+ elements[i] = Element();
+ }
+
+ tools = GetTools();
+
+ int golRulesCount;
+ int * golRulesT = LoadGOLRules(golRulesCount);
+ memcpy(grule, golRulesT, sizeof(int) * (golRulesCount*10));
+ free(golRulesT);
+
+ int golTypesCount;
+ int * golTypesT = LoadGOLTypes(golTypesCount);
+ memcpy(goltype, golTypesT, sizeof(int) * (golTypesCount));
+ free(golTypesT);
+
+ int golMenuCount;
+ gol_menu * golMenuT = LoadGOLMenu(golMenuCount);
+ memcpy(gmenu, golMenuT, sizeof(gol_menu) * golMenuCount);
+ free(golMenuT);
+
+ init_can_move();
+ clear_sim();
+
+ grav->gravity_mask();
+}
diff --git a/src/simulation/Simulation.h b/src/simulation/Simulation.h
new file mode 100644
index 0000000..9cdd3a7
--- /dev/null
+++ b/src/simulation/Simulation.h
@@ -0,0 +1,214 @@
+/*
+ * Simulation.h
+ *
+ * Created on: Jan 2, 2012
+ * Author: Simon
+ */
+
+#ifndef SIMULATION_H_
+#define SIMULATION_H_
+#include <cstring>
+#include <cstddef>
+#include <vector>
+
+#include "Config.h"
+#include "Elements.h"
+#include "SimulationData.h"
+#include "Sign.h"
+#include "Particle.h"
+#include "Player.h"
+#include "WallType.h"
+#include "GOLMenu.h"
+#include "MenuSection.h"
+#include "elements/Element.h"
+
+#define CHANNELS ((int)(MAX_TEMP-73)/100+2)
+
+class Snapshot;
+class SimTool;
+class Brush;
+struct SimulationSample;
+struct matrix2d;
+struct vector2d;
+
+class Simulation;
+class Renderer;
+class Gravity;
+class Air;
+class GameSave;
+
+//#ifdef _cplusplus
+class Simulation
+{
+private:
+public:
+
+ Gravity * grav;
+ Air * air;
+
+ std::vector<sign> signs;
+ Element elements[PT_NUM];
+ //Element * elements;
+ std::vector<SimTool*> tools;
+ unsigned int * platent;
+ wall_type wtypes[UI_WALLCOUNT];
+ gol_menu gmenu[NGOL];
+ int goltype[NGOL];
+ int grule[NGOL+1][10];
+ menu_section msections[SC_TOTAL];
+
+ int currentTick;
+
+ playerst player;
+ playerst player2;
+ playerst fighters[256]; //255 is the maximum number of fighters
+ unsigned char fighcount; //Contains the number of fighters
+ int lighting_recreate;
+ bool gravWallChanged;
+ Particle portalp[CHANNELS][8][80];
+ Particle emptyparticle;
+ int portal_rx[8];
+ int portal_ry[8];
+ int wireless[CHANNELS][2];
+ char can_move[PT_NUM][PT_NUM];
+ int parts_lastActiveIndex;// = NPART-1;
+ int pfree;
+ int NUM_PARTS;
+ int elementCount[PT_NUM];
+ int ISWIRE;
+ int force_stacking_check;
+ int emp_decor;
+ //Gol sim
+ int CGOL;
+ int ISGOL;
+ int GSPEED;
+ unsigned char gol[YRES][XRES];
+ unsigned char gol2[YRES][XRES][NGOL+1];
+ //Air sim
+ float (*vx)[XRES/CELL];
+ float (*vy)[XRES/CELL];
+ float (*pv)[XRES/CELL];
+ float (*hv)[XRES/CELL];
+ //Gravity sim
+ float *gravx;//gravx[(YRES/CELL) * (XRES/CELL)];
+ float *gravy;//gravy[(YRES/CELL) * (XRES/CELL)];
+ float *gravp;//gravp[(YRES/CELL) * (XRES/CELL)];
+ float *gravmap;//gravmap[(YRES/CELL) * (XRES/CELL)];
+ //Walls
+ unsigned char bmap[YRES/CELL][XRES/CELL];
+ unsigned char emap[YRES/CELL][XRES/CELL];
+ float fvx[YRES/CELL][XRES/CELL];
+ float fvy[YRES/CELL][XRES/CELL];
+ //Particles
+ Particle parts[NPART];
+ int pmap[YRES][XRES];
+ int photons[YRES][XRES];
+ int pmap_count[YRES][XRES];
+ //
+ int edgeMode;
+ int gravityMode;
+ //int airMode;
+ int legacy_enable;
+ int aheat_enable;
+ int VINE_MODE;
+ int water_equal_test;
+ int sys_pause;
+ int framerender;
+ int pretty_powder;
+ int sandcolour;
+ int sandcolour_frame;
+ bool ISLOVE;
+ int love[XRES/9][YRES/9];
+ bool ISLOLZ;
+ int lolz[XRES/9][YRES/9];
+
+ int Load(GameSave * save);
+ int Load(int x, int y, GameSave * save);
+ GameSave * Save();
+ GameSave * Save(int x1, int y1, int x2, int y2);
+ SimulationSample Get(int x, int y);
+
+ Snapshot * CreateSnapshot();
+ void Restore(const Snapshot & snap);
+
+ TPT_NO_INLINE int is_blocking(int t, int x, int y);
+ TPT_NO_INLINE int is_boundary(int pt, int x, int y);
+ TPT_NO_INLINE int find_next_boundary(int pt, int *x, int *y, int dm, int *em);
+ TPT_NO_INLINE int pn_junction_sprk(int x, int y, int pt);
+ TPT_NO_INLINE void photoelectric_effect(int nx, int ny);
+ TPT_NO_INLINE unsigned direction_to_map(float dx, float dy, int t);
+ TPT_NO_INLINE int do_move(int i, int x, int y, float nxf, float nyf);
+ TPT_NO_INLINE int try_move(int i, int x, int y, int nx, int ny);
+ TPT_NO_INLINE int eval_move(int pt, int nx, int ny, unsigned *rr);
+ void init_can_move();
+ void create_cherenkov_photon(int pp);
+ void create_gain_photon(int pp);
+ TPT_NO_INLINE void kill_part(int i);
+ int flood_prop(int x, int y, size_t propoffset, void * propvalue, StructProperty::PropertyType proptype);
+ int flood_prop_2(int x, int y, size_t propoffset, void * propvalue, StructProperty::PropertyType proptype, int parttype, char * bitmap);
+ int flood_water(int x, int y, int i, int originaly, int check);
+ TPT_NO_INLINE void detach(int i);
+ TPT_NO_INLINE void part_change_type(int i, int x, int y, int t);
+ TPT_NO_INLINE int create_part_add_props(int p, int x, int y, int tv, int rx, int ry);
+ //int InCurrentBrush(int i, int j, int rx, int ry);
+ //int get_brush_flags();
+ TPT_NO_INLINE int create_part(int p, int x, int y, int t);
+ TPT_NO_INLINE void delete_part(int x, int y, int flags);
+ void get_sign_pos(int i, int *x0, int *y0, int *w, int *h);
+ TPT_NO_INLINE int is_wire(int x, int y);
+ TPT_NO_INLINE int is_wire_off(int x, int y);
+ TPT_NO_INLINE void set_emap(int x, int y);
+ TPT_NO_INLINE int parts_avg(int ci, int ni, int t);
+ void create_arc(int sx, int sy, int dx, int dy, int midpoints, int variance, int type, int flags);
+ int nearest_part(int ci, int t, int max_d);
+ void update_particles_i(int start, int inc);
+ void update_particles();
+ void rotate_area(int area_x, int area_y, int area_w, int area_h, int invert);
+ void clear_area(int area_x, int area_y, int area_w, int area_h);
+
+ void SetEdgeMode(int newEdgeMode);
+
+ int Tool(int x, int y, int tool, float strength = 1.0f);
+ int ToolBrush(int x, int y, int tool, Brush * cBrush, float strength = 1.0f);
+ void ToolLine(int x1, int y1, int x2, int y2, int tool, Brush * cBrush, float strength = 1.0f);
+ void ToolBox(int x1, int y1, int x2, int y2, int tool, Brush * cBrush, float strength = 1.0f);
+
+ void CreateBox(int x1, int y1, int x2, int y2, int c, int flags);
+ int FloodINST(int x, int y, int fullc, int cm);
+ int FloodParts(int x, int y, int c, int cm, int bm, int flags);
+ //Create particles from brush/mask
+ int CreateParts(int positionX, int positionY, int c, Brush * cBrush);
+ //Old particle creation, will create a crappy square, do not use
+ int CreateParts(int x, int y, int rx, int ry, int c, int flags);
+ void CreateLine(int x1, int y1, int x2, int y2, int c, Brush * cBrush);
+ void CreateLine(int x1, int y1, int x2, int y2, int rx, int ry, int c, int flags);
+
+ void CreateWallBox(int x1, int y1, int x2, int y2, int c, int flags);
+ int FloodWalls(int x, int y, int c, int cm, int bm, int flags);
+ int CreateWalls(int x, int y, int rx, int ry, int c, int flags, Brush * cBrush = NULL);
+ void CreateWallLine(int x1, int y1, int x2, int y2, int rx, int ry, int c, int flags, Brush * cBrush = NULL);
+
+ void ApplyDecoration(int x, int y, int colR, int colG, int colB, int colA, int mode);
+ void ApplyDecorationPoint(int x, int y, int colR, int colG, int colB, int colA, int mode, Brush * cBrush = NULL);
+ void ApplyDecorationLine(int x1, int y1, int x2, int y2, int colR, int colG, int colB, int colA, int mode, Brush * cBrush = NULL);
+ void ApplyDecorationBox(int x1, int y1, int x2, int y2, int colR, int colG, int colB, int colA, int mode);
+
+ void GetGravityField(int x, int y, float particleGrav, float newtonGrav, float & pGravX, float & pGravY);
+
+ int GetParticleType(std::string type);
+
+ void *transform_save(void *odata, int *size, matrix2d transform, vector2d translate);
+ TPT_NO_INLINE void orbitalparts_get(int block1, int block2, int resblock1[], int resblock2[]);
+ TPT_NO_INLINE void orbitalparts_set(int *block1, int *block2, int resblock1[], int resblock2[]);
+ TPT_NO_INLINE int get_wavelength_bin(int *wm);
+ TPT_NO_INLINE int get_normal(int pt, int x, int y, float dx, float dy, float *nx, float *ny);
+ TPT_NO_INLINE int get_normal_interp(int pt, float x0, float y0, float dx, float dy, float *nx, float *ny);
+ void clear_sim();
+ void UpdateParticles();
+ Simulation();
+ ~Simulation();
+};
+
+//#endif
+
+#endif /* SIMULATION_H_ */
diff --git a/src/simulation/SimulationData.cpp b/src/simulation/SimulationData.cpp
new file mode 100644
index 0000000..e338e2f
--- /dev/null
+++ b/src/simulation/SimulationData.cpp
@@ -0,0 +1,344 @@
+#/*
+ * SimulationData.cpp
+ *
+ * Created on: Jan 24, 2012
+ * Author: Simon
+ */
+#include "SimulationData.h"
+//#include "ElementFunctions.h"
+#include "ElementGraphics.h"
+#include "Elements.h"
+
+gol_menu * LoadGOLMenu(int & golMenuCount)
+{
+ gol_menu golMenu[NGOL] =
+ {
+ {"GOL", PIXPACK(0x0CAC00), 0, "Game Of Life: Begin 3/Stay 23"},
+ {"HLIF", PIXPACK(0xFF0000), 1, "High Life: B36/S23"},
+ {"ASIM", PIXPACK(0x0000FF), 2, "Assimilation: B345/S4567"},
+ {"2x2", PIXPACK(0xFFFF00), 3, "2x2: B36/S125"},
+ {"DANI", PIXPACK(0x00FFFF), 4, "Day and Night: B3678/S34678"},
+ {"AMOE", PIXPACK(0xFF00FF), 5, "Amoeba: B357/S1358"},
+ {"MOVE", PIXPACK(0xFFFFFF), 6, "'Move' particles. Does not move things.. it is a life type: B368/S245"},
+ {"PGOL", PIXPACK(0xE05010), 7, "Pseudo Life: B357/S238"},
+ {"DMOE", PIXPACK(0x500000), 8, "Diamoeba: B35678/S5678"},
+ {"34", PIXPACK(0x500050), 9, "34: B34/S34"},
+ {"LLIF", PIXPACK(0x505050), 10, "Long Life: B345/S5"},
+ {"STAN", PIXPACK(0x5000FF), 11, "Stains: B3678/S235678"},
+ {"SEED", PIXPACK(0xFBEC7D), 12, "Seeds: B2/S"},
+ {"MAZE", PIXPACK(0xA8E4A0), 13, "Maze: B3/S12345"},
+ {"COAG", PIXPACK(0x9ACD32), 14, "Coagulations: B378/S235678"},
+ {"WALL", PIXPACK(0x0047AB), 15, "Walled cities: B45678/S2345"},
+ {"GNAR", PIXPACK(0xE5B73B), 16, "Gnarl: B1/S1"},
+ {"REPL", PIXPACK(0x259588), 17, "Replicator: B1357/S1357"},
+ {"MYST", PIXPACK(0x0C3C00), 18, "Mystery: B3458/S05678"},
+ {"LOTE", PIXPACK(0xFF0000), 19, "Living on the Edge: B37/S3458/4"},
+ {"FRG2", PIXPACK(0x00FF00), 20, "Like Frogs rule: B3/S124/3"},
+ {"STAR", PIXPACK(0x0000FF), 21, "Like Star Wars rule: B278/S3456/6"},
+ {"FROG", PIXPACK(0x00AA00), 22, "Frogs: B34/S12/3"},
+ {"BRAN", PIXPACK(0xCCCC00), 23, "Brian 6: B246/S6/3"}
+ };
+ golMenuCount = NGOL;
+ gol_menu * golMenuT = (gol_menu*)malloc(NGOL*sizeof(gol_menu));
+ memcpy(golMenuT, golMenu, NGOL*sizeof(gol_menu));
+ return golMenuT;
+}
+
+int * LoadGOLRules(int & golRuleCount)
+{
+ int golRules[NGOL+1][10] =
+ {
+ // 0,1,2,3,4,5,6,7,8,STATES live=1 spawn=2 spawn&live=3 States are kind of how long until it dies, normal ones use two states(living,dead) for others the intermediate states live but do nothing
+ {0,0,0,0,0,0,0,0,0,2},//blank
+ {0,0,1,3,0,0,0,0,0,2},//GOL
+ {0,0,1,3,0,0,2,0,0,2},//HLIF
+ {0,0,0,2,3,3,1,1,0,2},//ASIM
+ {0,1,1,2,0,1,2,0,0,2},//2x2
+ {0,0,0,3,1,0,3,3,3,2},//DANI
+ {0,1,0,3,0,3,0,2,1,2},//AMOE
+ {0,0,1,2,1,1,2,0,2,2},//MOVE
+ {0,0,1,3,0,2,0,2,1,2},//PGOL
+ {0,0,0,2,0,3,3,3,3,2},//DMOE
+ {0,0,0,3,3,0,0,0,0,2},//34
+ {0,0,0,2,2,3,0,0,0,2},//LLIF
+ {0,0,1,3,0,1,3,3,3,2},//STAN
+ {0,0,2,0,0,0,0,0,0,2},//SEED
+ {0,1,1,3,1,1,0,0,0,2},//MAZE
+ {0,0,1,3,0,1,1,3,3,2},//COAG
+ {0,0,1,1,3,3,2,2,2,2},//WALL
+ {0,3,0,0,0,0,0,0,0,2},//GNAR
+ {0,3,0,3,0,3,0,3,0,2},//REPL
+ {1,0,0,2,2,3,1,1,3,2},//MYST
+ {0,0,0,3,1,1,0,2,1,4},//LOTE
+ {0,1,1,2,1,0,0,0,0,3},//FRG2
+ {0,0,2,1,1,1,1,2,2,6},//STAR
+ {0,1,1,2,2,0,0,0,0,3},//FROG
+ {0,0,2,0,2,0,3,0,0,3},//BRAN
+ };
+ golRuleCount = NGOL+1;
+ int * golRulesT = (int*)malloc((golRuleCount*10)*sizeof(int));
+ memcpy(golRulesT, golRules, (golRuleCount*10)*sizeof(int));
+ return golRulesT;
+}
+
+int * LoadGOLTypes(int & golTypeCount)
+{
+ int golTypes[NGOL] =
+ {
+ GT_GOL,
+ GT_HLIF,
+ GT_ASIM,
+ GT_2x2,
+ GT_DANI,
+ GT_AMOE,
+ GT_MOVE,
+ GT_PGOL,
+ GT_DMOE,
+ GT_34,
+ GT_LLIF,
+ GT_STAN,
+ GT_SEED,
+ GT_MAZE,
+ GT_COAG,
+ GT_WALL,
+ GT_GNAR,
+ GT_REPL,
+ GT_MYST,
+ GT_LOTE,
+ GT_FRG2,
+ GT_STAR,
+ GT_FROG,
+ GT_BRAN,
+ };
+ golTypeCount = NGOL;
+ int * golTypesT = (int*)malloc((golTypeCount)*sizeof(int));
+ memcpy(golTypesT, golTypes, (golTypeCount)*sizeof(int));
+ return golTypesT;
+}
+
+wall_type * LoadWalls(int & wallCount)
+{
+ wall_type wtypes[] =
+ {
+ {PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, "ERASE", "Erases walls."},
+ {PIXPACK(0xC0C0C0), PIXPACK(0x101010), 0, Renderer::WallIcon, "CONDUCTIVE WALL","Wall. Indestructible. Blocks everything. Conductive."},
+ {PIXPACK(0x808080), PIXPACK(0x808080), 0, Renderer::WallIcon, "EWALL", "E-Wall. Becomes transparent when electricity is connected."},
+ {PIXPACK(0xFF8080), PIXPACK(0xFF2008), 1, Renderer::WallIcon, "DETECTOR", "Detector. Generates electricity when a particle is inside."},
+ {PIXPACK(0x808080), PIXPACK(0x000000), 0, Renderer::WallIcon, "STREAMLINE", "Streamline. Set start point of a streamline."},
+ {PIXPACK(0x8080FF), PIXPACK(0x000000), 1, Renderer::WallIcon, "FAN", "Fan. Accelerates air. Use line tool to set direction and strength."},
+ {PIXPACK(0xC0C0C0), PIXPACK(0x101010), 2, Renderer::WallIcon, "LIQUID WALL", "Wall. Blocks most particles but lets liquids through. Conductive."},
+ {PIXPACK(0x808080), PIXPACK(0x000000), 1, Renderer::WallIcon, "ABSORB WALL", "Wall. Absorbs particles but lets air currents through."},
+ {PIXPACK(0x808080), PIXPACK(0x000000), 3, Renderer::WallIcon, "WALL", "Wall. Indestructible. Blocks everything."},
+ {PIXPACK(0x3C3C3C), PIXPACK(0x000000), 1, Renderer::WallIcon, "AIRONLY WALL", "Wall. Indestructible. Blocks particles, allows air"},
+ {PIXPACK(0x575757), PIXPACK(0x000000), 1, Renderer::WallIcon, "POWDER WALL", "Wall. Indestructible. Blocks liquids and gasses, allows powders"},
+ {PIXPACK(0xFFFF22), PIXPACK(0x101010), 2, Renderer::WallIcon, "CONDUCTOR", "Conductor, allows particles, conducts electricity"},
+ {PIXPACK(0x242424), PIXPACK(0x101010), 0, Renderer::WallIcon, "EHOLE", "E-Hole, absorbs particles, release them when powered"},
+ {PIXPACK(0x579777), PIXPACK(0x000000), 1, Renderer::WallIcon, "GAS WALL", "Wall. Indestructible. Blocks liquids and solids, allows gasses"},
+ {PIXPACK(0xFFEE00), PIXPACK(0xAA9900), 4, Renderer::WallIcon, "GRAVITY WALL", "Gravity wall"},
+ {PIXPACK(0xFFAA00), PIXPACK(0xAA5500), 4, Renderer::WallIcon, "ENERGY WALL", "Energy wall, allows only energy type particles to pass"},
+ };
+ wallCount = UI_WALLCOUNT;
+ wall_type * wtypesT = (wall_type*)malloc(UI_WALLCOUNT*sizeof(wall_type));
+ memcpy(wtypesT, wtypes, UI_WALLCOUNT*sizeof(wall_type));
+ return wtypesT;
+}
+
+menu_section * LoadMenus(int & menuCount)
+{
+ menu_section msections[] = //doshow does not do anything currently.
+ {
+ {"\xC1", "Walls", 0, 1},
+ {"\xC2", "Electronics", 0, 1},
+ {"\xD6", "Powered Materials", 0, 1},
+ {"\x99", "Sensors", 0, 1},
+ {"\xE2", "Force", 0, 1},
+ {"\xC3", "Explosives", 0, 1},
+ {"\xC5", "Gasses", 0, 1},
+ {"\xC4", "Liquids", 0, 1},
+ {"\xD0", "Powders", 0, 1},
+ {"\xD1", "Solids", 0, 1},
+ {"\xC6", "Radioactive", 0, 1},
+ {"\xCC", "Special", 0, 1},
+ {"\xD2", "Game Of Life", 0, 1},
+ {"\xD7", "Tools", 0, 1},
+ {"\xE4", "Decoration tools", 0, 1},
+ {"\xC8", "Cracker", 0, 0},
+ {"\xC8", "Cracker!", 0, 0},
+ };
+ menuCount = SC_TOTAL;
+ menu_section * msectionsT = (menu_section*)malloc(SC_TOTAL*sizeof(menu_section));
+ memcpy(msectionsT, msections, SC_TOTAL*sizeof(menu_section));
+ return msectionsT;
+}
+
+unsigned int * LoadLatent(int & elementCount)
+{
+ unsigned int platent[PT_NUM] =
+ {
+ /* NONE */ 0,
+ /* DUST */ 0,
+ /* WATR */ 7500,
+ /* OIL */ 0,
+ /* FIRE */ 0,
+ /* STNE */ 0,
+ /* LAVA */ 0,
+ /* GUN */ 0,
+ /* NITR */ 0,
+ /* CLNE */ 0,
+ /* GAS */ 0,
+ /* C-4 */ 0,
+ /* GOO */ 0,
+ /* ICE */ 1095,
+ /* METL */ 919,
+ /* SPRK */ 0,
+ /* SNOW */ 1095,
+ /* WOOD */ 0,
+ /* NEUT */ 0,
+ /* PLUT */ 0,
+ /* PLNT */ 0,
+ /* ACID */ 0,
+ /* VOID */ 0,
+ /* WTRV */ 0,
+ /* CNCT */ 0,
+ /* DSTW */ 7500,
+ /* SALT */ 0,
+ /* SLTW */ 7500,
+ /* DMND */ 0,
+ /* BMTL */ 0,
+ /* BRMT */ 0,
+ /* PHOT */ 0,
+ /* URAN */ 0,
+ /* WAX */ 0,
+ /* MWAX */ 0,
+ /* PSCN */ 0,
+ /* NSCN */ 0,
+ /* LN2 */ 0,
+ /* INSL */ 0,
+ /* VACU */ 0,
+ /* VENT */ 0,
+ /* RBDM */ 0,
+ /* LRBD */ 0,
+ /* NTCT */ 0,
+ /* SAND */ 0,
+ /* GLAS */ 0,
+ /* PTCT */ 0,
+ /* BGLA */ 0,
+ /* THDR */ 0,
+ /* PLSM */ 0,
+ /* ETRD */ 0,
+ /* NICE */ 0,
+ /* NBLE */ 0,
+ /* BTRY */ 0,
+ /* LCRY */ 0,
+ /* STKM */ 0,
+ /* SWCH */ 0,
+ /* SMKE */ 0,
+ /* DESL */ 0,
+ /* COAL */ 0,
+ /* LO2 */ 0,
+ /* O2 */ 0,
+ /* INWR */ 0,
+ /* YEST */ 0,
+ /* DYST */ 0,
+ /* THRM */ 0,
+ /* GLOW */ 0,
+ /* BRCK */ 0,
+ /* CFLM */ 0,
+ /* FIRW */ 0,
+ /* FUSE */ 0,
+ /* FSEP */ 0,
+ /* AMTR */ 0,
+ /* BCOL */ 0,
+ /* PCLN */ 0,
+ /* HSWC */ 0,
+ /* IRON */ 0,
+ /* MORT */ 0,
+ /* LIFE */ 0,
+ /* DLAY */ 0,
+ /* CO2 */ 0,
+ /* DRIC */ 0,
+ /* CBNW */ 7500,
+ /* STOR */ 0,
+ /* STOR */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* SPNG */ 0,
+ /* RIME */ 0,
+ /* FOG */ 0,
+ /* BCLN */ 0,
+ /* LOVE */ 0,
+ /* DEUT */ 0,
+ /* WARP */ 0,
+ /* PUMP */ 0,
+ /* FWRK */ 0,
+ /* PIPE */ 0,
+ /* FRZZ */ 0,
+ /* FRZW */ 0,
+ /* GRAV */ 0,
+ /* BIZR */ 0,
+ /* BIZRG*/ 0,
+ /* BIZRS*/ 0,
+ /* INST */ 0,
+ /* ISOZ */ 0,
+ /* ISZS */ 0,
+ /* PRTI */ 0,
+ /* PRTO */ 0,
+ /* PSTE */ 0,
+ /* PSTS */ 0,
+ /* ANAR */ 0,
+ /* VINE */ 0,
+ /* INVS */ 0,
+ /* EQVE */ 0,
+ /* SPWN2*/ 0,
+ /* SPAWN*/ 0,
+ /* SHLD1*/ 0,
+ /* SHLD2*/ 0,
+ /* SHLD3*/ 0,
+ /* SHLD4*/ 0,
+ /* LOlZ */ 0,
+ /* WIFI */ 0,
+ /* FILT */ 0,
+ /* ARAY */ 0,
+ /* BRAY */ 0,
+ /* STKM2*/ 0,
+ /* BOMB */ 0,
+ /* C-5 */ 0,
+ /* SING */ 0,
+ /* QRTZ */ 0,
+ /* PQRT */ 0,
+ /* EMP */ 0,
+ /* BREL */ 0,
+ /* ELEC */ 0,
+ /* ACEL */ 0,
+ /* DCEL */ 0,
+ /* TNT */ 0,
+ /* IGNP */ 0,
+ /* BOYL */ 0,
+ /* GEL */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* FREE */ 0,
+ /* WIND */ 0,
+ /* H2 */ 0,
+ /* SOAP */ 0,
+ /* NBHL */ 0,
+ /* NWHL */ 0,
+ /* MERC */ 0,
+ /* PBCN */ 0,
+ /* GPMP */ 0,
+ /* CLST */ 0,
+ /* WIRE */ 0,
+ /* GBMB */ 0,
+ /* FIGH */ 0,
+ /* FRAY */ 0,
+ /* REPL */ 0,
+ };
+ elementCount = PT_NUM;
+ unsigned int * platentT = (unsigned int*)malloc(PT_NUM*sizeof(unsigned int));
+ memcpy(platentT, platent, PT_NUM*sizeof(unsigned int));
+ return platentT;
+}
diff --git a/src/simulation/SimulationData.h b/src/simulation/SimulationData.h
new file mode 100644
index 0000000..1d47813
--- /dev/null
+++ b/src/simulation/SimulationData.h
@@ -0,0 +1,178 @@
+/*
+ * SimulationData.h
+ *
+ * Created on: Jan 24, 2012
+ * Author: Simon
+ */
+
+#include <vector>
+
+#define SC_WALL 0
+#define SC_ELEC 1
+#define SC_POWERED 2
+#define SC_SENSOR 3
+#define SC_FORCE 4
+#define SC_EXPLOSIVE 5
+#define SC_GAS 6
+#define SC_LIQUID 7
+#define SC_POWDERS 8
+#define SC_SOLIDS 9
+#define SC_NUCLEAR 10
+#define SC_SPECIAL 11
+#define SC_LIFE 12
+#define SC_TOOL 13
+#define SC_DECO 14
+#define SC_CRACKER 15
+#define SC_CRACKER2 16
+#define SC_TOTAL 15
+
+#define UI_WALLSTART 222
+#define UI_ACTUALSTART 122
+#define UI_WALLCOUNT 16
+
+#define O_WL_WALLELEC 122
+#define O_WL_EWALL 123
+#define O_WL_DETECT 124
+#define O_WL_STREAM 125
+#define O_WL_SIGN 126
+#define O_WL_FAN 127
+#define O_WL_FANHELPER 255
+#define O_WL_ALLOWLIQUID 128
+#define O_WL_DESTROYALL 129
+#define O_WL_ERASE 130
+#define O_WL_WALL 131
+#define O_WL_ALLOWAIR 132
+#define O_WL_ALLOWSOLID 133
+#define O_WL_ALLOWALLELEC 134
+#define O_WL_EHOLE 135
+#define O_WL_ALLOWGAS 140
+#define O_WL_GRAV 142
+#define O_WL_ALLOWENERGY 145
+
+
+#define WL_ERASE 0
+#define WL_WALLELEC 1
+#define WL_EWALL 2
+#define WL_DETECT 3
+#define WL_STREAM 4
+#define WL_FAN 5
+#define WL_ALLOWLIQUID 6
+#define WL_DESTROYALL 7
+#define WL_WALL 8
+#define WL_ALLOWAIR 9
+#define WL_ALLOWSOLID 10
+#define WL_ALLOWALLELEC 11
+#define WL_EHOLE 12
+#define WL_ALLOWGAS 13
+#define WL_GRAV 14
+#define WL_ALLOWENERGY 15
+#define WL_FLOODHELPER 255
+
+#define SPC_AIR 236
+#define SPC_HEAT 237
+#define SPC_COOL 238
+#define SPC_VACUUM 239
+#define SPC_WIND 241
+#define SPC_PGRV 243
+#define SPC_NGRV 244
+#define SPC_PROP 246
+
+#define DECO_DRAW 0
+#define DECO_ADD 1
+#define DECO_SUBTRACT 2
+#define DECO_MULTIPLY 3
+#define DECO_DIVIDE 4
+#define DECO_SMUDGE 5
+#define DECO_CLEAR 6
+
+//Old IDs for GOL types
+#define GT_GOL 78
+#define GT_HLIF 79
+#define GT_ASIM 80
+#define GT_2x2 81
+#define GT_DANI 82
+#define GT_AMOE 83
+#define GT_MOVE 84
+#define GT_PGOL 85
+#define GT_DMOE 86
+#define GT_34 87
+#define GT_LLIF 88
+#define GT_STAN 89
+#define GT_SEED 134
+#define GT_MAZE 135
+#define GT_COAG 136
+#define GT_WALL 137
+#define GT_GNAR 138
+#define GT_REPL 139
+#define GT_MYST 140
+#define GT_LOTE 142
+#define GT_FRG2 143
+#define GT_STAR 144
+#define GT_FROG 145
+#define GT_BRAN 146
+
+//New IDs for GOL types
+#define NGT_GOL 0
+#define NGT_HLIF 1
+#define NGT_ASIM 2
+#define NGT_2x2 3
+#define NGT_DANI 4
+#define NGT_AMOE 5
+#define NGT_MOVE 6
+#define NGT_PGOL 7
+#define NGT_DMOE 8
+#define NGT_34 9
+#define NGT_LLIF 10
+#define NGT_STAN 11
+#define NGT_SEED 12
+#define NGT_MAZE 13
+#define NGT_COAG 14
+#define NGT_WALL 15
+#define NGT_GNAR 16
+#define NGT_REPL 17
+#define NGT_MYST 18
+#define NGT_LOTE 19
+#define NGT_FRG2 20
+#define NGT_STAR 21
+#define NGT_FROG 22
+#define NGT_BRAN 23
+
+#ifndef SIMULATIONDATA_H_
+#define SIMULATIONDATA_H_
+
+//#include "elements/NULLElement.h"
+//#include "Simulation.h"
+
+/*class Simulation;
+class Renderer;
+struct Particle;*/
+
+struct part_type;
+
+struct part_transition;
+
+struct wall_type;
+
+struct gol_menu;
+
+struct menu_section;
+
+struct wall_type;
+
+class SimTool;
+
+class Element;
+
+gol_menu * LoadGOLMenu(int & golMenuCount);
+
+int * LoadGOLTypes(int & golTypeCount);
+
+int * LoadGOLRules(int & golRuleCount);
+
+wall_type * LoadWalls(int & wallCount);
+
+menu_section * LoadMenus(int & menuCount);
+
+unsigned int * LoadLatent(int & elementCount);
+
+#endif /* SIMULATIONDATA_H_ */
diff --git a/src/simulation/Snapshot.h b/src/simulation/Snapshot.h
new file mode 100644
index 0000000..d47f363
--- /dev/null
+++ b/src/simulation/Snapshot.h
@@ -0,0 +1,55 @@
+#pragma once
+
+#include <vector>
+
+#include "Particle.h"
+
+class Snapshot
+{
+public:
+ std::vector<float> AirPressure;
+ std::vector<float> AirVelocityX;
+ std::vector<float> AirVelocityY;
+ std::vector<float> AmbientHeat;
+
+ std::vector<Particle> Particles;
+ std::vector<Particle> PortalParticles;
+
+ std::vector<int> WirelessData;
+
+ std::vector<float> GravVelocityX;
+ std::vector<float> GravVelocityY;
+ std::vector<float> GravValue;
+ std::vector<float> GravMap;
+
+ std::vector<unsigned char> BlockMap;
+ std::vector<unsigned char> ElecMap;
+
+ std::vector<float> FanVelocityX;
+ std::vector<float> FanVelocityY;
+
+ Snapshot() :
+ AirPressure(),
+ AirVelocityX(),
+ AirVelocityY(),
+ AmbientHeat(),
+ Particles(),
+ PortalParticles(),
+ WirelessData(),
+ GravVelocityX(),
+ GravVelocityY(),
+ GravValue(),
+ GravMap(),
+ BlockMap(),
+ ElecMap(),
+ FanVelocityX(),
+ FanVelocityY()
+ {
+
+ }
+
+ virtual ~Snapshot()
+ {
+
+ }
+}; \ No newline at end of file
diff --git a/src/simulation/StorageClasses.h b/src/simulation/StorageClasses.h
new file mode 100644
index 0000000..45b9b00
--- /dev/null
+++ b/src/simulation/StorageClasses.h
@@ -0,0 +1,54 @@
+#ifndef STORAGECLASSES_H_
+#define STORAGECLASSES_H_
+
+#include <string>
+#include "Elements.h"
+
+class Renderer;
+class Simulation;
+
+/*struct part_type
+{
+ char *name;
+ pixel pcolors;
+ float advection;
+ float airdrag;
+ float airloss;
+ float loss;
+ float collision;
+ float gravity;
+ float diffusion;
+ float hotair;
+ int falldown;
+ int flammable;
+ int explosive;
+ int meltable;
+ int hardness;
+ int menu;
+ int enabled;
+ int weight;
+ int menusection;
+ float heat;
+ unsigned char hconduct;
+ char *descs;
+ char state;
+ unsigned int properties;
+ int (*update_func) (UPDATE_FUNC_ARGS);
+ int (*graphics_func) (GRAPHICS_FUNC_ARGS);
+};
+typedef struct part_type part_type;*/
+
+/*struct part_transition
+{
+ float plv; // transition occurs if pv is lower than this
+ int plt;
+ float phv; // transition occurs if pv is higher than this
+ int pht;
+ float tlv; // transition occurs if t is lower than this
+ int tlt;
+ float thv; // transition occurs if t is higher than this
+ int tht;
+};
+typedef struct part_transition part_transition;*/
+
+#endif \ No newline at end of file
diff --git a/src/simulation/StructProperty.h b/src/simulation/StructProperty.h
new file mode 100644
index 0000000..5c46c7e
--- /dev/null
+++ b/src/simulation/StructProperty.h
@@ -0,0 +1,39 @@
+//
+// StructProperty.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_StructProperty_h
+#define The_Powder_Toy_StructProperty_h
+
+#include <string>
+#include <stdint.h>
+
+struct StructProperty
+{
+ enum PropertyType { ParticleType, Colour, Integer, UInteger, Float, String, Char, UChar };
+ std::string Name;
+ PropertyType Type;
+ intptr_t Offset;
+
+ StructProperty(std::string name, PropertyType type, intptr_t offset):
+ Name(name),
+ Type(type),
+ Offset(offset)
+ {
+
+ }
+
+ StructProperty():
+ Name(""),
+ Type(Char),
+ Offset(0)
+ {
+
+ }
+};
+
+#endif
diff --git a/src/simulation/Tools.h b/src/simulation/Tools.h
new file mode 100644
index 0000000..525701e
--- /dev/null
+++ b/src/simulation/Tools.h
@@ -0,0 +1,7 @@
+#ifndef TOOLS_H_
+#define TOOLS_H_
+
+#include "ToolClasses.h"
+
+
+#endif
diff --git a/src/simulation/WallType.h b/src/simulation/WallType.h
new file mode 100644
index 0000000..c2d916a
--- /dev/null
+++ b/src/simulation/WallType.h
@@ -0,0 +1,25 @@
+//
+// WallType.h
+// The Powder Toy
+//
+// Created by Simon Robertshaw on 04/06/2012.
+// Copyright (c) 2012 __MyCompanyName__. All rights reserved.
+//
+
+#ifndef The_Powder_Toy_WallType_h
+#define The_Powder_Toy_WallType_h
+
+#include "graphics/Graphics.h"
+class VideoBuffer;
+
+struct wall_type
+{
+ pixel colour;
+ pixel eglow; // if emap set, add this to fire glow
+ int drawstyle;
+ VideoBuffer * (*textureGen)(int, int, int);
+ const char *name;
+ const char *descs;
+};
+
+#endif
diff --git a/src/simulation/elements/116.cpp b/src/simulation/elements/116.cpp
new file mode 100644
index 0000000..9697c97
--- /dev/null
+++ b/src/simulation/elements/116.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_116 PT_116 116
+Element_116::Element_116()
+{
+ Identifier = "DEFAULT_PT_116";
+ Name = "EQVE";
+ Colour = PIXPACK(0xFFE0A0);
+ MenuVisible = 0;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 85;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Shared velocity test";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_116::~Element_116() {} \ No newline at end of file
diff --git a/src/simulation/elements/146.cpp b/src/simulation/elements/146.cpp
new file mode 100644
index 0000000..51f4d3b
--- /dev/null
+++ b/src/simulation/elements/146.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_146 PT_146 146
+Element_146::Element_146()
+{
+ Identifier = "DEFAULT_PT_146";
+ Name = "BRAN";
+ Colour = PIXPACK(0xCCCC00);
+ MenuVisible = 0;
+ MenuSection = SC_LIFE;
+ Enabled = 0;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = 9000.0f;
+ HeatConduct = 40;
+ Description = "Brian 6 S6/B246/3";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID|PROP_LIFE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_146::~Element_146() {} \ No newline at end of file
diff --git a/src/simulation/elements/ACEL.cpp b/src/simulation/elements/ACEL.cpp
new file mode 100644
index 0000000..8dfad79
--- /dev/null
+++ b/src/simulation/elements/ACEL.cpp
@@ -0,0 +1,85 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ACEL PT_ACEL 137
+Element_ACEL::Element_ACEL()
+{
+ Identifier = "DEFAULT_PT_ACEL";
+ Name = "ACEL";
+ Colour = PIXPACK(0x0099CC);
+ MenuVisible = 1;
+ MenuSection = SC_FORCE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Accelerator";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_ACEL::update;
+ Graphics = &Element_ACEL::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_ACEL static int update(UPDATE_FUNC_ARGS)
+int Element_ACEL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ parts[i].tmp = 0;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry) && !(rx && ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if(!r)
+ r = sim->photons[y+ry][x+rx];
+ if ((r>>8)>=NPART || !r)
+ continue;
+ if(sim->elements[r&0xFF].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))
+ {
+ parts[r>>8].vx *= 1.1f;
+ parts[r>>8].vy *= 1.1f;
+ parts[i].tmp = 1;
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_ACEL static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_ACEL::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->tmp)
+ *pixel_mode |= PMODE_GLOW;
+ return 0;
+}
+
+
+Element_ACEL::~Element_ACEL() {} \ No newline at end of file
diff --git a/src/simulation/elements/ACID.cpp b/src/simulation/elements/ACID.cpp
new file mode 100644
index 0000000..fb6cb81
--- /dev/null
+++ b/src/simulation/elements/ACID.cpp
@@ -0,0 +1,144 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ACID PT_ACID 21
+Element_ACID::Element_ACID()
+{
+ Identifier = "DEFAULT_PT_ACID";
+ Name = "ACID";
+ Colour = PIXPACK(0xED55FF);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 40;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 10;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 34;
+ Description = "Dissolves almost everything.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_DEADLY;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_ACID::update;
+ Graphics = &Element_ACID::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_ACID static int update(UPDATE_FUNC_ARGS)
+int Element_ACID::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, trade, np;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_ACID && (r&0xFF)!=PT_CAUS)
+ {
+ if ((r&0xFF)==PT_PLEX || (r&0xFF)==PT_NITR || (r&0xFF)==PT_GUNP || (r&0xFF)==PT_RBDM || (r&0xFF)==PT_LRBD)
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_FIRE);
+ parts[i].life = 4;
+ parts[r>>8].life = 4;
+ }
+ else if ((r&0xFF)==PT_WTRV)
+ {
+ if(!(rand()%250))
+ {
+ sim->part_change_type(i, x, y, PT_CAUS);
+ parts[i].life = (rand()%50)+25;
+ sim->kill_part(r>>8);
+ }
+ }
+ else if (((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN && sim->elements[r&0xFF].Hardness>(rand()%1000))&&parts[i].life>=50)
+ {
+ if (sim->parts_avg(i, r>>8,PT_GLAS)!= PT_GLAS)//GLAS protects stuff from acid
+ {
+ float newtemp = ((60.0f-(float)sim->elements[r&0xFF].Hardness))*7.0f;
+ if(newtemp < 0){
+ newtemp = 0;
+ }
+ parts[i].temp += newtemp;
+ parts[i].life--;
+ sim->kill_part(r>>8);
+ }
+ }
+ else if (parts[i].life<=50)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ for ( trade = 0; trade<2; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r>>8)>=NPART || !r)
+ continue;
+ if ((r&0xFF)==PT_ACID&&(parts[i].life>parts[r>>8].life)&&parts[i].life>0)//diffusion
+ {
+ int temp = parts[i].life - parts[r>>8].life;
+ if (temp ==1)
+ {
+ parts[r>>8].life ++;
+ parts[i].life --;
+ }
+ else if (temp>0)
+ {
+ parts[r>>8].life += temp/2;
+ parts[i].life -= temp/2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_ACID static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_ACID::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int s = cpart->life;
+ if (s>75) s = 75; //These two should not be here.
+ if (s<49) s = 49;
+ s = (s-49)*3;
+ if (s==0) s = 1;
+ *colr += s*4;
+ *colg += s*1;
+ *colb += s*2;
+ *pixel_mode |= PMODE_BLUR;
+ return 0;
+}
+
+
+Element_ACID::~Element_ACID() {} \ No newline at end of file
diff --git a/src/simulation/elements/AMTR.cpp b/src/simulation/elements/AMTR.cpp
new file mode 100644
index 0000000..ff25bb6
--- /dev/null
+++ b/src/simulation/elements/AMTR.cpp
@@ -0,0 +1,79 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_AMTR PT_AMTR 72
+Element_AMTR::Element_AMTR()
+{
+ Identifier = "DEFAULT_PT_AMTR";
+ Name = "AMTR";
+ Colour = PIXPACK(0x808080);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.00f;
+ Gravity = 0.10f;
+ Diffusion = 1.00f;
+ HotAir = 0.0000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Anti-Matter, Destroys a majority of particles";
+
+ State = ST_NONE;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_AMTR::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_AMTR static int update(UPDATE_FUNC_ARGS)
+int Element_AMTR::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_AMTR && (r&0xFF)!=PT_DMND && (r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN && (r&0xFF)!=PT_NONE && (r&0xFF)!=PT_PHOT && (r&0xFF)!=PT_VOID && (r&0xFF)!=PT_BHOL && (r&0xFF)!=PT_NBHL && (r&0xFF)!=PT_PRTI && (r&0xFF)!=PT_PRTO)
+ {
+ parts[i].life++;
+ if (parts[i].life==4)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ if (10>(rand()/(RAND_MAX/100)))
+ sim->create_part(r>>8, x+rx, y+ry, PT_PHOT);
+ else
+ sim->kill_part(r>>8);
+ sim->pv[y/CELL][x/CELL] -= 2.0f;
+ }
+ }
+ return 0;
+}
+
+
+Element_AMTR::~Element_AMTR() {} \ No newline at end of file
diff --git a/src/simulation/elements/ANAR.cpp b/src/simulation/elements/ANAR.cpp
new file mode 100644
index 0000000..f8bcd49
--- /dev/null
+++ b/src/simulation/elements/ANAR.cpp
@@ -0,0 +1,78 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ANAR PT_ANAR 113
+Element_ANAR::Element_ANAR()
+{
+ Identifier = "DEFAULT_PT_ANAR";
+ Name = "ANAR";
+ Colour = PIXPACK(0xFFFFEE);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = -0.7f;
+ AirDrag = -0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.1f;
+ Gravity = -0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 85;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Very light dust. Behaves opposite gravity";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_ANAR::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_ANAR static int update(UPDATE_FUNC_ARGS)
+int Element_ANAR::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+
+ //if (parts[i].temp >= 0.23)
+ // parts[i].temp --;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_HFLM)
+ {
+ if (1>rand()%22)
+ {
+ sim->part_change_type(i,x,y,PT_HFLM);
+ parts[i].life = rand()%150+50;
+ parts[r>>8].temp = parts[i].temp = 0;
+ sim->pv[y/CELL][x/CELL] -= 0.5;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_ANAR::~Element_ANAR() {} \ No newline at end of file
diff --git a/src/simulation/elements/ARAY.cpp b/src/simulation/elements/ARAY.cpp
new file mode 100644
index 0000000..2794bef
--- /dev/null
+++ b/src/simulation/elements/ARAY.cpp
@@ -0,0 +1,154 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ARAY PT_ARAY 126
+Element_ARAY::Element_ARAY()
+{
+ Identifier = "DEFAULT_PT_ARAY";
+ Name = "ARAY";
+ Colour = PIXPACK(0xFFBB00);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Ray Emitter. Rays create points when they collide";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_ARAY::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_ARAY static int update(UPDATE_FUNC_ARGS)
+int Element_ARAY::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nxx, nyy, docontinue, nxi, nyi, rx, ry, nr, ry1, rx1;
+ if (parts[i].life==0) {
+ int colored =0;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK && parts[r>>8].life==3) {
+ int destroy = (parts[r>>8].ctype==PT_PSCN)?1:0;
+ int nostop = (parts[r>>8].ctype==PT_INST)?1:0;
+ for (docontinue = 1, nxx = 0, nyy = 0, nxi = rx*-1, nyi = ry*-1; docontinue; nyy+=nyi, nxx+=nxi) {
+ if (!(x+nxi+nxx<XRES && y+nyi+nyy<YRES && x+nxi+nxx >= 0 && y+nyi+nyy >= 0)) {
+ break;
+ }
+ r = pmap[y+nyi+nyy][x+nxi+nxx];
+ if (!r) {
+ int nr = sim->create_part(-1, x+nxi+nxx, y+nyi+nyy, PT_BRAY);
+ if (nr!=-1) {
+ if (destroy) {//if it came from PSCN
+ parts[nr].tmp = 2;
+ parts[nr].life = 2;
+ } else
+ parts[nr].ctype = colored;
+ parts[nr].temp = parts[i].temp;
+ }
+ } else if (!destroy) {
+ if ((r&0xFF)==PT_BRAY&&parts[r>>8].tmp==0) {//if it hits another BRAY that isn't red
+ if (nyy!=0 || nxx!=0) {
+ parts[r>>8].life = 1020;//makes it last a while
+ parts[r>>8].tmp = 1;
+ if (!parts[r>>8].ctype)//and colors it if it isn't already
+ parts[r>>8].ctype = colored;
+ }
+ docontinue = 0;//then stop it
+ } else if ((r&0xFF)==PT_BRAY&&parts[r>>8].tmp==1) {//if it hits one that already was a long life, reset it
+ parts[r>>8].life = 1020;
+ //docontinue = 1;
+ } else if ((r&0xFF)==PT_FILT) {//get color if passed through FILT
+ colored = parts[r>>8].ctype;
+ //this if prevents BRAY from stopping on certain materials
+ } else if ((r&0xFF)!=PT_STOR && (r&0xFF)!=PT_INWR && ((r&0xFF)!=PT_SPRK || parts[r>>8].ctype!=PT_INWR) && (r&0xFF)!=PT_ARAY && (r&0xFF)!=PT_WIFI && !((r&0xFF)==PT_SWCH && parts[r>>8].life>=10)) {
+ if (nyy!=0 || nxx!=0) {
+ sim->create_part(-1, x+nxi+nxx, y+nyi+nyy, PT_SPRK);
+ }
+ if (!(nostop && parts[r>>8].type==PT_SPRK && parts[r>>8].ctype >= 0 && parts[r>>8].ctype < PT_NUM && (sim->elements[parts[r>>8].ctype].Properties&PROP_CONDUCTS))) {
+ docontinue = 0;
+ } else {
+ docontinue = 1;
+ }
+ } else if((r&0xFF)==PT_STOR) {
+ if(parts[r>>8].tmp)
+ {
+ //Cause STOR to release
+ for(ry1 = 1; ry1 >= -1; ry1--){
+ for(rx1 = 0; rx1 >= -1 && rx1 <= 1; rx1 = -rx1-rx1+1){
+ int np = sim->create_part(-1, x+nxi+nxx+rx1, y+nyi+nyy+ry1, parts[r>>8].tmp);
+ if (np!=-1)
+ {
+ parts[np].temp = parts[r>>8].temp;
+ parts[np].life = parts[r>>8].tmp2;
+ parts[np].tmp = parts[r>>8].pavg[0];
+ parts[np].ctype = parts[r>>8].pavg[1];
+ parts[r>>8].tmp = 0;
+ parts[r>>8].life = 10;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ parts[r>>8].life = 10;
+ }
+ }
+ } else if (destroy) {
+ if ((r&0xFF)==PT_BRAY) {
+ parts[r>>8].life = 1;
+ docontinue = 1;
+ //this if prevents red BRAY from stopping on certain materials
+ } else if ((r&0xFF)==PT_STOR || (r&0xFF)==PT_INWR || ((r&0xFF)==PT_SPRK && parts[r>>8].ctype==PT_INWR) || (r&0xFF)==PT_ARAY || (r&0xFF)==PT_WIFI || (r&0xFF)==PT_FILT || ((r&0xFF)==PT_SWCH && parts[r>>8].life>=10)) {
+ if((r&0xFF)==PT_STOR)
+ {
+ parts[r>>8].tmp = 0;
+ parts[r>>8].life = 0;
+ }
+ docontinue = 1;
+ } else {
+ docontinue = 0;
+ }
+ }
+ }
+ }
+ //parts[i].life = 4;
+ }
+ }
+ return 0;
+}
+
+
+Element_ARAY::~Element_ARAY() {} \ No newline at end of file
diff --git a/src/simulation/elements/BANG.cpp b/src/simulation/elements/BANG.cpp
new file mode 100644
index 0000000..8922e0e
--- /dev/null
+++ b/src/simulation/elements/BANG.cpp
@@ -0,0 +1,131 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BANG PT_BANG 139
+Element_BANG::Element_BANG()
+{
+ Identifier = "DEFAULT_PT_BANG";
+ Name = "TNT";
+ Colour = PIXPACK(0xC05050);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 88;
+ Description = "Explosive.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BANG::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BANG static int update(UPDATE_FUNC_ARGS)
+int Element_BANG::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, nb;
+ if(parts[i].tmp==0)
+ {
+ if(parts[i].temp>=673.0f)
+ parts[i].tmp = 1;
+ else
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_FIRE || (r&0xFF)==PT_PLSM)
+ {
+ parts[i].tmp = 1;
+ }
+ else if ((r&0xFF)==PT_SPRK || (r&0xFF)==PT_LIGH)
+ {
+ parts[i].tmp = 1;
+ }
+ }
+
+ }
+ else if(parts[i].tmp==1)
+ {
+ if ((pmap[y][x]>>8 == i))
+ {
+ int tempvalue = 2;
+ sim->flood_prop(x, y, offsetof(Particle, tmp), &tempvalue, StructProperty::Integer);
+ }
+ parts[i].tmp = 2;
+ }
+ else if(parts[i].tmp==2)
+ {
+ parts[i].tmp = 3;
+ }
+ else if(parts[i].tmp>=3)
+ {
+ float otemp = parts[i].temp-275.13f;
+ //Explode!!
+ sim->pv[y/CELL][x/CELL] += 0.5f;
+ parts[i].tmp = 0;
+ if(!(rand()%3))
+ {
+ if(!(rand()%2))
+ {
+ sim->create_part(i, x, y, PT_FIRE);
+ parts[i].temp = restrict_flt((MAX_TEMP/4)+otemp, MIN_TEMP, MAX_TEMP);
+ }
+ else
+ {
+ sim->create_part(i, x, y, PT_SMKE);
+ parts[i].life = rand()%50+500;
+ parts[i].temp = restrict_flt((MAX_TEMP/4)+otemp, MIN_TEMP, MAX_TEMP);
+ }
+ }
+ else
+ {
+ if(!(rand()%15))
+ {
+ sim->create_part(i, x, y, PT_EMBR);
+ parts[i].tmp = 0;
+ parts[i].life = 50;
+ parts[i].temp = restrict_flt((MAX_TEMP/3)+otemp, MIN_TEMP, MAX_TEMP);
+ parts[i].vx = rand()%20-10;
+ parts[i].vy = rand()%20-10;
+ }
+ else
+ {
+ sim->kill_part(i);
+ }
+ }
+ return 1;
+ }
+ return 0;
+}
+
+
+Element_BANG::~Element_BANG() {}
diff --git a/src/simulation/elements/BCLN.cpp b/src/simulation/elements/BCLN.cpp
new file mode 100644
index 0000000..80a5d44
--- /dev/null
+++ b/src/simulation/elements/BCLN.cpp
@@ -0,0 +1,99 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BCLN PT_BCLN 93
+Element_BCLN::Element_BCLN()
+{
+ Identifier = "DEFAULT_PT_BCLN";
+ Name = "BCLN";
+ Colour = PIXPACK(0xFFD040);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.50f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 12;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Breakable Clone.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BCLN::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BCLN static int update(UPDATE_FUNC_ARGS)
+int Element_BCLN::update(UPDATE_FUNC_ARGS)
+ {
+ if (!parts[i].life && sim->pv[y/CELL][x/CELL]>4.0f)
+ parts[i].life = rand()%40+80;
+ if (parts[i].life)
+ {
+ float advection = 0.1f;
+ parts[i].vx += advection*sim->vx[y/CELL][x/CELL];
+ parts[i].vy += advection*sim->vy[y/CELL][x/CELL];
+ }
+ if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled || (parts[i].ctype==PT_LIFE && (parts[i].tmp<0 || parts[i].tmp>=NGOLALT)))
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN &&
+ (r&0xFF)!=PT_BCLN && (r&0xFF)!=PT_STKM &&
+ (r&0xFF)!=PT_PBCN && (r&0xFF)!=PT_STKM2 &&
+ (r&0xFF)<PT_NUM)
+ {
+ parts[i].ctype = r&0xFF;
+ if ((r&0xFF)==PT_LIFE || (r&0xFF)==PT_LAVA)
+ parts[i].tmp = parts[r>>8].ctype;
+ }
+ }
+ }
+ else {
+ if (parts[i].ctype==PT_LIFE) sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, parts[i].ctype|(parts[i].tmp<<8));
+ else if (parts[i].ctype!=PT_LIGH || (rand()%30)==0)
+ {
+ int np = sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, parts[i].ctype);
+ if (np>=0)
+ {
+ if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
+ parts[np].ctype = parts[i].tmp;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_BCLN::~Element_BCLN() {}
diff --git a/src/simulation/elements/BCOL.cpp b/src/simulation/elements/BCOL.cpp
new file mode 100644
index 0000000..1fb6f82
--- /dev/null
+++ b/src/simulation/elements/BCOL.cpp
@@ -0,0 +1,146 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BCOL PT_BCOL 73
+Element_BCOL::Element_BCOL()
+{
+ Identifier = "DEFAULT_PT_BCOL";
+ Name = "BCOL";
+ Colour = PIXPACK(0x333333);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 5;
+ Hardness = 2;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 150;
+ Description = "Broken Coal. Heavy particles. See COAL";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BCOL::update;
+ Graphics = &Element_BCOL::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BCOL static int update(UPDATE_FUNC_ARGS)
+int Element_BCOL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, trade, temp;
+ if (parts[i].life<=0) {
+ sim->create_part(i, x, y, PT_FIRE);
+ return 1;
+ } else if (parts[i].life < 100) {
+ parts[i].life--;
+ sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, PT_FIRE);
+ }
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_FIRE || (r&0xFF)==PT_PLSM) && 1>(rand()%500))
+ {
+ if (parts[i].life>100) {
+ parts[i].life = 99;
+ }
+ }
+ if ((r&0xFF)==PT_LAVA && 1>(rand()%500))
+ {
+ if (parts[r>>8].ctype == PT_IRON) {
+ parts[r>>8].ctype = PT_METL;
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ /*if(100-parts[i].life > parts[i].tmp2)
+ parts[i].tmp2 = 100-parts[i].life;
+ if(parts[i].tmp2 < 0) parts[i].tmp2 = 0;
+ for ( trade = 0; trade<4; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_COAL || (r&0xFF)==PT_BCOL)&&(parts[i].tmp2>parts[r>>8].tmp2)&&parts[i].tmp2>0)//diffusion
+ {
+ int temp = parts[i].tmp2 - parts[r>>8].tmp2;
+ if(temp < 10)
+ continue;
+ if (temp ==1)
+ {
+ parts[r>>8].tmp2 ++;
+ parts[i].tmp2 --;
+ }
+ else if (temp>0)
+ {
+ parts[r>>8].tmp2 += temp/2;
+ parts[i].tmp2 -= temp/2;
+ }
+ }
+ }
+ }*/
+ if(parts[i].temp > parts[i].tmp2)
+ parts[i].tmp2 = parts[i].temp;
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_BCOL static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BCOL::graphics(GRAPHICS_FUNC_ARGS)
+ //Both COAL and Broken Coal
+{
+ *colr += (cpart->tmp2-295.15f)/3;
+
+ if (*colr > 170)
+ *colr = 170;
+ if (*colr < *colg)
+ *colr = *colg;
+
+ *colg = *colb = *colr;
+
+ if((cpart->temp-295.15f) > 300.0f-200.0f)
+ {
+ float frequency = 3.1415/(2*300.0f-(300.0f-200.0f));
+ int q = ((cpart->temp-295.15f)>300.0f)?300.0f-(300.0f-200.0f):(cpart->temp-295.15f)-(300.0f-200.0f);
+
+ *colr += sin(frequency*q) * 226;
+ *colg += sin(frequency*q*4.55 +3.14) * 34;
+ *colb += sin(frequency*q*2.22 +3.14) * 64;
+ }
+ return 0;
+}
+
+
+
+Element_BCOL::~Element_BCOL() {} \ No newline at end of file
diff --git a/src/simulation/elements/BGLA.cpp b/src/simulation/elements/BGLA.cpp
new file mode 100644
index 0000000..79e7fe2
--- /dev/null
+++ b/src/simulation/elements/BGLA.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BGLA PT_BGLA 47
+Element_BGLA::Element_BGLA()
+{
+ Identifier = "DEFAULT_PT_BGLA";
+ Name = "BGLA";
+ Colour = PIXPACK(0x606060);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 5;
+ Hardness = 0;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 150;
+ Description = "Broken Glass, Heavy particles. Meltable. Bagels.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART | PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1973.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_BGLA::~Element_BGLA() {} \ No newline at end of file
diff --git a/src/simulation/elements/BHOL.cpp b/src/simulation/elements/BHOL.cpp
new file mode 100644
index 0000000..35eda8c
--- /dev/null
+++ b/src/simulation/elements/BHOL.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BHOL PT_BHOL 39
+Element_BHOL::Element_BHOL()
+{
+ Identifier = "DEFAULT_PT_BHOL";
+ Name = "VACU";
+ Colour = PIXPACK(0x303030);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.01f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+70.0f+273.15f;
+ HeatConduct = 255;
+ Description = "Vacuum, sucks in other particles and heats up.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_BHOL::~Element_BHOL() {} \ No newline at end of file
diff --git a/src/simulation/elements/BIZR.cpp b/src/simulation/elements/BIZR.cpp
new file mode 100644
index 0000000..13df996
--- /dev/null
+++ b/src/simulation/elements/BIZR.cpp
@@ -0,0 +1,124 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BIZR PT_BIZR 103
+Element_BIZR::Element_BIZR()
+{
+ Identifier = "DEFAULT_PT_BIZR";
+ Name = "BIZR";
+ Colour = PIXPACK(0x00FF77);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Bizarre... contradicts the normal state changes.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 100.0f;
+ LowTemperatureTransition = PT_BIZRG;
+ HighTemperature = 400.0f;
+ HighTemperatureTransition = PT_BIZRS;
+
+ Update = &Element_BIZR::update;
+ Graphics = &Element_BIZR::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BIZR static int update(UPDATE_FUNC_ARGS)
+int Element_BIZR::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, nr, ng, nb, na;
+ float tr, tg, tb, ta, mr, mg, mb, ma;
+ float blend;
+ if(parts[i].dcolour){
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_BIZR && (r&0xFF)!=PT_BIZRG && (r&0xFF)!=PT_BIZRS)
+ {
+ blend = 0.95f;
+ tr = (parts[r>>8].dcolour>>16)&0xFF;
+ tg = (parts[r>>8].dcolour>>8)&0xFF;
+ tb = (parts[r>>8].dcolour)&0xFF;
+ ta = (parts[r>>8].dcolour>>24)&0xFF;
+
+ mr = (parts[i].dcolour>>16)&0xFF;
+ mg = (parts[i].dcolour>>8)&0xFF;
+ mb = (parts[i].dcolour)&0xFF;
+ ma = (parts[i].dcolour>>24)&0xFF;
+
+ nr = (tr*blend) + (mr*(1-blend));
+ ng = (tg*blend) + (mg*(1-blend));
+ nb = (tb*blend) + (mb*(1-blend));
+ na = (ta*blend) + (ma*(1-blend));
+
+ parts[r>>8].dcolour = nr<<16 | ng<<8 | nb | na<<24;
+ }
+ }
+ }
+ if(((r = sim->photons[y][x])&0xFF)==PT_PHOT || ((r = pmap[y][x])&0xFF)==PT_PHOT)
+ {
+ sim->part_change_type(r>>8, x, y, PT_ELEC);
+ parts[r>>8].ctype = 0;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_BIZR static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BIZR::graphics(GRAPHICS_FUNC_ARGS)
+ //BIZR, BIZRG, BIZRS
+{
+ int x = 0;
+ *colg = 0;
+ *colb = 0;
+ *colr = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+ if(fabs(cpart->vx)+fabs(cpart->vy)>0)
+ {
+ *firea = 255;
+ *fireg = *colg/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *fireb = *colb/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *firer = *colr/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *pixel_mode |= FIRE_ADD;
+ }
+ return 0;
+}
+
+
+Element_BIZR::~Element_BIZR() {} \ No newline at end of file
diff --git a/src/simulation/elements/BIZRG.cpp b/src/simulation/elements/BIZRG.cpp
new file mode 100644
index 0000000..1e5f27f
--- /dev/null
+++ b/src/simulation/elements/BIZRG.cpp
@@ -0,0 +1,124 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BIZRG PT_BIZRG 104
+Element_BIZRG::Element_BIZRG()
+{
+ Identifier = "DEFAULT_PT_BIZRG";
+ Name = "BIZG";
+ Colour = PIXPACK(0x00FFBB);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 1.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 2.75f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 1;
+
+ Temperature = R_TEMP-200.0f+273.15f;
+ HeatConduct = 42;
+ Description = "Bizarre gas";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 100.0f;
+ HighTemperatureTransition = PT_BIZR;
+
+ Update = &Element_BIZRG::update;
+ Graphics = &Element_BIZRG::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BIZRG static int update(UPDATE_FUNC_ARGS)
+int Element_BIZRG::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, nr, ng, nb, na;
+ float tr, tg, tb, ta, mr, mg, mb, ma;
+ float blend;
+ if(parts[i].dcolour){
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_BIZR && (r&0xFF)!=PT_BIZRG && (r&0xFF)!=PT_BIZRS)
+ {
+ blend = 0.95f;
+ tr = (parts[r>>8].dcolour>>16)&0xFF;
+ tg = (parts[r>>8].dcolour>>8)&0xFF;
+ tb = (parts[r>>8].dcolour)&0xFF;
+ ta = (parts[r>>8].dcolour>>24)&0xFF;
+
+ mr = (parts[i].dcolour>>16)&0xFF;
+ mg = (parts[i].dcolour>>8)&0xFF;
+ mb = (parts[i].dcolour)&0xFF;
+ ma = (parts[i].dcolour>>24)&0xFF;
+
+ nr = (tr*blend) + (mr*(1-blend));
+ ng = (tg*blend) + (mg*(1-blend));
+ nb = (tb*blend) + (mb*(1-blend));
+ na = (ta*blend) + (ma*(1-blend));
+
+ parts[r>>8].dcolour = nr<<16 | ng<<8 | nb | na<<24;
+ }
+ }
+ }
+ if(((r = sim->photons[y][x])&0xFF)==PT_PHOT || ((r = pmap[y][x])&0xFF)==PT_PHOT)
+ {
+ sim->part_change_type(r>>8, x, y, PT_ELEC);
+ parts[r>>8].ctype = 0;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_BIZRG static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BIZRG::graphics(GRAPHICS_FUNC_ARGS)
+ //BIZR, BIZRG, BIZRS
+{
+ int x = 0;
+ *colg = 0;
+ *colb = 0;
+ *colr = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+ if(fabs(cpart->vx)+fabs(cpart->vy)>0)
+ {
+ *firea = 255;
+ *fireg = *colg/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *fireb = *colb/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *firer = *colr/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *pixel_mode |= FIRE_ADD;
+ }
+ return 0;
+}
+
+
+Element_BIZRG::~Element_BIZRG() {} \ No newline at end of file
diff --git a/src/simulation/elements/BIZRS.cpp b/src/simulation/elements/BIZRS.cpp
new file mode 100644
index 0000000..439a723
--- /dev/null
+++ b/src/simulation/elements/BIZRS.cpp
@@ -0,0 +1,124 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BIZRS PT_BIZRS 105
+Element_BIZRS::Element_BIZRS()
+{
+ Identifier = "DEFAULT_PT_BIZRS";
+ Name = "BIZS";
+ Colour = PIXPACK(0x00E455);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+300.0f+273.15f;
+ HeatConduct = 251;
+ Description = "Bizarre solid";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 400.0f;
+ LowTemperatureTransition = PT_BIZR;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BIZRS::update;
+ Graphics = &Element_BIZRS::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BIZRS static int update(UPDATE_FUNC_ARGS)
+int Element_BIZRS::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, nr, ng, nb, na;
+ float tr, tg, tb, ta, mr, mg, mb, ma;
+ float blend;
+ if(parts[i].dcolour){
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_BIZR && (r&0xFF)!=PT_BIZRG && (r&0xFF)!=PT_BIZRS)
+ {
+ blend = 0.95f;
+ tr = (parts[r>>8].dcolour>>16)&0xFF;
+ tg = (parts[r>>8].dcolour>>8)&0xFF;
+ tb = (parts[r>>8].dcolour)&0xFF;
+ ta = (parts[r>>8].dcolour>>24)&0xFF;
+
+ mr = (parts[i].dcolour>>16)&0xFF;
+ mg = (parts[i].dcolour>>8)&0xFF;
+ mb = (parts[i].dcolour)&0xFF;
+ ma = (parts[i].dcolour>>24)&0xFF;
+
+ nr = (tr*blend) + (mr*(1-blend));
+ ng = (tg*blend) + (mg*(1-blend));
+ nb = (tb*blend) + (mb*(1-blend));
+ na = (ta*blend) + (ma*(1-blend));
+
+ parts[r>>8].dcolour = nr<<16 | ng<<8 | nb | na<<24;
+ }
+ }
+ }
+ if(((r = sim->photons[y][x])&0xFF)==PT_PHOT || ((r = pmap[y][x])&0xFF)==PT_PHOT)
+ {
+ sim->part_change_type(r>>8, x, y, PT_ELEC);
+ parts[r>>8].ctype = 0;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_BIZRS static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BIZRS::graphics(GRAPHICS_FUNC_ARGS)
+ //BIZR, BIZRG, BIZRS
+{
+ int x = 0;
+ *colg = 0;
+ *colb = 0;
+ *colr = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+ if(fabs(cpart->vx)+fabs(cpart->vy)>0)
+ {
+ *firea = 255;
+ *fireg = *colg/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *fireb = *colb/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *firer = *colr/5 * fabs(cpart->vx)+fabs(cpart->vy);
+ *pixel_mode |= FIRE_ADD;
+ }
+ return 0;
+}
+
+
+Element_BIZRS::~Element_BIZRS() {} \ No newline at end of file
diff --git a/src/simulation/elements/BMTL.cpp b/src/simulation/elements/BMTL.cpp
new file mode 100644
index 0000000..adc5289
--- /dev/null
+++ b/src/simulation/elements/BMTL.cpp
@@ -0,0 +1,80 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BMTL PT_BMTL 29
+Element_BMTL::Element_BMTL()
+{
+ Identifier = "DEFAULT_PT_BMTL";
+ Name = "BMTL";
+ Colour = PIXPACK(0x505070);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Breakable metal.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 1.0f;
+ HighPressureTransition = ST;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1273.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_BMTL::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BMTL static int update(UPDATE_FUNC_ARGS)
+int Element_BMTL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt, tempFactor;
+ if (parts[i].tmp>1)
+ {
+ parts[i].tmp--;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ if ((rt==PT_METL || rt==PT_IRON) && 1>(rand()/(RAND_MAX/100)))
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_BMTL);
+ parts[r>>8].tmp=(parts[i].tmp<=7)?parts[i].tmp=1:parts[i].tmp-(rand()%5);//rand()/(RAND_MAX/300)+100;
+ }
+ }
+ }
+ else if (parts[i].tmp==1 && 1>rand()%1000)
+ {
+ parts[i].tmp = 0;
+ sim->part_change_type(i,x,y,PT_BRMT);
+ }
+ return 0;
+}
+
+
+Element_BMTL::~Element_BMTL() {} \ No newline at end of file
diff --git a/src/simulation/elements/BOMB.cpp b/src/simulation/elements/BOMB.cpp
new file mode 100644
index 0000000..0335e59
--- /dev/null
+++ b/src/simulation/elements/BOMB.cpp
@@ -0,0 +1,113 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BOMB PT_BOMB 129
+Element_BOMB::Element_BOMB()
+{
+ Identifier = "DEFAULT_PT_BOMB";
+ Name = "BOMB";
+ Colour = PIXPACK(0xFFF288);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Bomb.";
+
+ State = ST_NONE;
+ Properties = TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC|PROP_SPARKSETTLE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BOMB::update;
+ Graphics = &Element_BOMB::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BOMB static int update(UPDATE_FUNC_ARGS)
+int Element_BOMB::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, nb;
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_BOMB && (r&0xFF)!=PT_EMBR && (r&0xFF)!=PT_DMND && (r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN && (r&0xFF)!=PT_BCLN && (r&0xFF)!=PT_VIBR)
+ {
+ int rad = 8;
+ int nxi;
+ int nxj;
+ pmap[y][x] = 0;
+ for (nxj=-rad; nxj<=rad; nxj++)
+ for (nxi=-rad; nxi<=rad; nxi++)
+ if ((pow((float)nxi,2))/(pow((float)rad,2))+(pow((float)nxj,2))/(pow((float)rad,2))<=1)
+ if ((pmap[y+nxj][x+nxi]&0xFF)!=PT_DMND && (pmap[y+nxj][x+nxi]&0xFF)!=PT_CLNE && (pmap[y+nxj][x+nxi]&0xFF)!=PT_PCLN && (pmap[y+nxj][x+nxi]&0xFF)!=PT_BCLN && (pmap[y+nxj][x+nxi]&0xFF)!=PT_VIBR)
+ {
+ sim->delete_part(x+nxi, y+nxj, 0);
+ sim->pv[(y+nxj)/CELL][(x+nxi)/CELL] += 0.1f;
+ nb = sim->create_part(-3, x+nxi, y+nxj, PT_EMBR);
+ if (nb!=-1)
+ {
+ parts[nb].tmp = 2;
+ parts[nb].life = 2;
+ parts[nb].temp = MAX_TEMP;
+ }
+ }
+ for (nxj=-(rad+1); nxj<=(rad+1); nxj++)
+ for (nxi=-(rad+1); nxi<=(rad+1); nxi++)
+ if ((pow((float)nxi,2))/(pow((float)(rad+1),2))+(pow((float)nxj,2))/(pow((float)(rad+1),2))<=1 && !(pmap[y+nxj][x+nxi]&0xFF))
+ {
+ nb = sim->create_part(-3, x+nxi, y+nxj, PT_EMBR);
+ if (nb!=-1)
+ {
+ parts[nb].tmp = 0;
+ parts[nb].life = 50;
+ parts[nb].temp = MAX_TEMP;
+ parts[nb].vx = rand()%40-20;
+ parts[nb].vy = rand()%40-20;
+ }
+ }
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_BOMB static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BOMB::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *pixel_mode |= PMODE_FLARE;
+ return 1;
+}
+
+
+Element_BOMB::~Element_BOMB() {}
diff --git a/src/simulation/elements/BOYL.cpp b/src/simulation/elements/BOYL.cpp
new file mode 100644
index 0000000..18ebee8
--- /dev/null
+++ b/src/simulation/elements/BOYL.cpp
@@ -0,0 +1,94 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BOYL PT_BOYL 141
+Element_BOYL::Element_BOYL()
+{
+ Identifier = "DEFAULT_PT_BOYL";
+ Name = "BOYL";
+ Colour = PIXPACK(0x0A3200);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 1.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 0.18f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+2.0f +273.15f;
+ HeatConduct = 42;
+ Description = "Boyle, variable pressure gas. Expands when heated.";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BOYL::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BOYL static int update(UPDATE_FUNC_ARGS)
+int Element_BOYL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (sim->pv[y/CELL][x/CELL]<(parts[i].temp/100))
+ sim->pv[y/CELL][x/CELL] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL][x/CELL]);
+ if (y+CELL<YRES && sim->pv[y/CELL+1][x/CELL]<(parts[i].temp/100))
+ sim->pv[y/CELL+1][x/CELL] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL+1][x/CELL]);
+ if (x+CELL<XRES)
+ {
+ sim->pv[y/CELL][x/CELL+1] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL][x/CELL+1]);
+ if (y+CELL<YRES)
+ sim->pv[y/CELL+1][x/CELL+1] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL+1][x/CELL+1]);
+ }
+ if (y-CELL>=0 && sim->pv[y/CELL-1][x/CELL]<(parts[i].temp/100))
+ sim->pv[y/CELL-1][x/CELL] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL-1][x/CELL]);
+ if (x-CELL>=0)
+ {
+ sim->pv[y/CELL][x/CELL-1] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL][x/CELL-1]);
+ if (y-CELL>=0)
+ sim->pv[y/CELL-1][x/CELL-1] += 0.001f*((parts[i].temp/100)-sim->pv[y/CELL-1][x/CELL-1]);
+ }
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 &&
+ x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR && 1>rand()%30)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_FOG);
+ }
+ else if ((r&0xFF)==PT_O2 && 1>rand()%9)
+ {
+ sim->kill_part(r>>8);
+ sim->part_change_type(i,x,y,PT_WATR);
+ sim->pv[y/CELL][x/CELL] += 4.0;
+ }
+ }
+ return 0;
+}
+
+
+Element_BOYL::~Element_BOYL() {} \ No newline at end of file
diff --git a/src/simulation/elements/BRAY.cpp b/src/simulation/elements/BRAY.cpp
new file mode 100644
index 0000000..dfcd080
--- /dev/null
+++ b/src/simulation/elements/BRAY.cpp
@@ -0,0 +1,109 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BRAY PT_BRAY 127
+Element_BRAY::Element_BRAY()
+{
+ Identifier = "DEFAULT_PT_BRAY";
+ Name = "BRAY";
+ Colour = PIXPACK(0xFFFFFF);
+ MenuVisible = 0;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Ray Point. Rays create points when they collide";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+ Graphics = &Element_BRAY::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BRAY static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BRAY::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int x, trans = 255;
+ if(cpart->tmp==0)
+ {
+ trans = cpart->life * 7;
+ if (trans>255) trans = 255;
+ if (cpart->ctype) {
+ *colg = 0;
+ *colb = 0;
+ *colr = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+ }
+ }
+ else if(cpart->tmp==1)
+ {
+ trans = cpart->life/4;
+ if (trans>255) trans = 255;
+ if (cpart->ctype) {
+ *colg = 0;
+ *colb = 0;
+ *colr = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+ }
+ }
+ else if(cpart->tmp==2)
+ {
+ trans = cpart->life*100;
+ if (trans>255) trans = 255;
+ *colr = 255;
+ *colg = 150;
+ *colb = 50;
+ }
+ *cola = trans;
+ *pixel_mode &= ~PMODE;
+ *pixel_mode |= PMODE_BLEND | PMODE_GLOW;
+ return 0;
+}
+
+
+Element_BRAY::~Element_BRAY() {} \ No newline at end of file
diff --git a/src/simulation/elements/BRCK.cpp b/src/simulation/elements/BRCK.cpp
new file mode 100644
index 0000000..6769aa3
--- /dev/null
+++ b/src/simulation/elements/BRCK.cpp
@@ -0,0 +1,65 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BRCK PT_BRCK 67
+Element_BRCK::Element_BRCK()
+{
+ Identifier = "DEFAULT_PT_BRCK";
+ Name = "BRCK";
+ Colour = PIXPACK(0x808080);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Brick, breakable building material.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 8.8f;
+ HighPressureTransition = PT_STNE;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1223.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+ Graphics = &Element_BRCK::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_BRCK static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_BRCK::graphics(GRAPHICS_FUNC_ARGS)
+{
+ if (cpart->tmp == 1)
+ {
+ *pixel_mode |= FIRE_ADD;
+ *colb += 100;
+
+ *firea = 40;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+ }
+ return 0;
+}
+
+Element_BRCK::~Element_BRCK() {} \ No newline at end of file
diff --git a/src/simulation/elements/BREC.cpp b/src/simulation/elements/BREC.cpp
new file mode 100644
index 0000000..e260a7c
--- /dev/null
+++ b/src/simulation/elements/BREC.cpp
@@ -0,0 +1,64 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BREC PT_BREC 135
+Element_BREC::Element_BREC()
+{
+ Identifier = "DEFAULT_PT_BREC";
+ Name = "BREL";
+ Colour = PIXPACK(0x707060);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.18f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 2;
+ Hardness = 2;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 211;
+ Description = "Broken electronics";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_BREC::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BREC static int update(UPDATE_FUNC_ARGS)
+int Element_BREC::update(UPDATE_FUNC_ARGS)
+{
+ int np;
+ if (1>rand()%200 && (sim->pv[y/CELL][x/CELL] > 30.0f) && parts[i].temp>9000 && parts[i].life>0)
+ {
+ sim->part_change_type(i, x ,y ,PT_EXOT);
+ parts[i].life = 1000;
+ }
+ if ((sim->pv[y/CELL][x/CELL] > 10.0f) && (parts[i].life>0)) {
+ parts[i].temp = parts[i].temp + (sim->pv[y/CELL][x/CELL])/8;
+ }
+ return 0;
+}
+
+Element_BREC::~Element_BREC() {}
diff --git a/src/simulation/elements/BRMT.cpp b/src/simulation/elements/BRMT.cpp
new file mode 100644
index 0000000..55eb243
--- /dev/null
+++ b/src/simulation/elements/BRMT.cpp
@@ -0,0 +1,85 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BRMT PT_BRMT 30
+Element_BRMT::Element_BRMT()
+{
+ Identifier = "DEFAULT_PT_BRMT";
+ Name = "BRMT";
+ Colour = PIXPACK(0x705060);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 2;
+ Hardness = 2;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 211;
+ Description = "Broken metal.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1273.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_BRMT::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BRMT static int update(UPDATE_FUNC_ARGS)
+int Element_BRMT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt, tempFactor;
+ if (parts[i].temp > (250.0f+273.15f))
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ tempFactor = 1000 - (((250.0f+273.15f)-parts[i].temp)*2);
+ if(tempFactor < 2)
+ tempFactor = 2;
+ if ((rt==PT_BREC) && 1 > (rand()%tempFactor))
+ {
+ if(rand()%2)
+ {
+ sim->create_part(r>>8, x+rx, y+ry, PT_THRM);
+ }
+ else
+ { sim->create_part(i, x, y, PT_THRM);
+ }
+ return 1;
+ //part_change_type(r>>8,x+rx,y+ry,PT_BMTL);
+ //parts[r>>8].tmp=(parts[i].tmp<=7)?parts[i].tmp=1:parts[i].tmp-(rand()%5);//rand()/(RAND_MAX/300)+100;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_BRMT::~Element_BRMT() {} \ No newline at end of file
diff --git a/src/simulation/elements/BTRY.cpp b/src/simulation/elements/BTRY.cpp
new file mode 100644
index 0000000..efbb3d2
--- /dev/null
+++ b/src/simulation/elements/BTRY.cpp
@@ -0,0 +1,75 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BTRY PT_BTRY 53
+Element_BTRY::Element_BTRY()
+{
+ Identifier = "DEFAULT_PT_BTRY";
+ Name = "BTRY";
+ Colour = PIXPACK(0x858505);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. Generates Electricity.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 2273.0f;
+ HighTemperatureTransition = PT_PLSM;
+
+ Update = &Element_BTRY::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_BTRY static int update(UPDATE_FUNC_ARGS)
+int Element_BTRY::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ if (sim->parts_avg(i,r>>8,PT_INSL) != PT_INSL)
+ {
+ if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[r>>8].life==0 && abs(rx)+abs(ry) < 4)
+ {
+ parts[r>>8].life = 4;
+ parts[r>>8].ctype = rt;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_BTRY::~Element_BTRY() {} \ No newline at end of file
diff --git a/src/simulation/elements/BVBR.cpp b/src/simulation/elements/BVBR.cpp
new file mode 100644
index 0000000..dfff186
--- /dev/null
+++ b/src/simulation/elements/BVBR.cpp
@@ -0,0 +1,50 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_BVBR PT_BVBR 166
+Element_BVBR::Element_BVBR()
+{
+ Identifier = "DEFAULT_PT_BVBR";
+ Name = "BVBR";
+ Colour = PIXPACK(0x005000);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.3f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.15f;
+ Diffusion = 0.00f;
+ HotAir = 0.0000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 67;
+
+ Temperature = 273.15f;
+ HeatConduct = 164;
+ Description = "Broken vibranium.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_VIBR::update;
+ Graphics = &Element_VIBR::graphics;
+
+}
+
+Element_BVBR::~Element_BVBR() {} \ No newline at end of file
diff --git a/src/simulation/elements/C5.cpp b/src/simulation/elements/C5.cpp
new file mode 100644
index 0000000..28e2055
--- /dev/null
+++ b/src/simulation/elements/C5.cpp
@@ -0,0 +1,75 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_C5 PT_C5 130
+Element_C5::Element_C5()
+{
+ Identifier = "DEFAULT_PT_C5";
+ Name = "C-5";
+ Colour = PIXPACK(0x2050E0);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 88;
+ Description = "Cold explosive";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_C5::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_C5 static int update(UPDATE_FUNC_ARGS)
+int Element_C5::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)!=PT_C5 && parts[r>>8].temp<100 && sim->elements[r&0xFF].HeatConduct && ((r&0xFF)!=PT_HSWC||parts[r>>8].life==10)) || (r&0xFF)==PT_HFLM)
+ {
+ if (1>rand()%6)
+ {
+ sim->part_change_type(i,x,y,PT_HFLM);
+ parts[r>>8].temp = parts[i].temp = 0;
+ parts[i].life = rand()%150+50;
+ sim->pv[y/CELL][x/CELL] += 1.5;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_C5::~Element_C5() {} \ No newline at end of file
diff --git a/src/simulation/elements/CAUS.cpp b/src/simulation/elements/CAUS.cpp
new file mode 100644
index 0000000..a8fc0da
--- /dev/null
+++ b/src/simulation/elements/CAUS.cpp
@@ -0,0 +1,86 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CAUS PT_CAUS 86
+Element_CAUS::Element_CAUS()
+{
+ Identifier = "DEFAULT_PT_CAUS";
+ Name = "CAUS";
+ Colour = PIXPACK(0x80FFA0);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 2.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 1.50f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Caustic Gas, acts like Acid";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS|PROP_DEADLY;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_CAUS::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_CAUS static int update(UPDATE_FUNC_ARGS)
+int Element_CAUS::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, trade, np;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_ACID && (r&0xFF)!=PT_CAUS)
+ {
+ if (((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN && sim->elements[r&0xFF].Hardness>(rand()%1000))&&parts[i].life>=50)
+ {
+ if (sim->parts_avg(i, r>>8,PT_GLAS)!= PT_GLAS)//GLAS protects stuff from acid
+ {
+ float newtemp = ((60.0f-(float)sim->elements[r&0xFF].Hardness))*7.0f;
+ if(newtemp < 0){
+ newtemp = 0;
+ }
+ parts[i].temp += newtemp;
+ parts[i].life--;
+ sim->kill_part(r>>8);
+ }
+ }
+ else if (parts[i].life<=50)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_CAUS::~Element_CAUS() {} \ No newline at end of file
diff --git a/src/simulation/elements/CBNW.cpp b/src/simulation/elements/CBNW.cpp
new file mode 100644
index 0000000..4331750
--- /dev/null
+++ b/src/simulation/elements/CBNW.cpp
@@ -0,0 +1,153 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CBNW PT_CBNW 82
+Element_CBNW::Element_CBNW()
+{
+ Identifier = "DEFAULT_PT_CBNW";
+ Name = "BUBW";
+ Colour = PIXPACK(0x2030D0);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Carbonated water. Conducts electricity. Freezes. Extinguishes fires.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 273.15f;
+ LowTemperatureTransition = PT_ICEI;
+ HighTemperature = 373.0f;
+ HighTemperatureTransition = PT_WTRV;
+
+ Update = &Element_CBNW::update;
+ Graphics = &Element_CBNW::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_CBNW static int update(UPDATE_FUNC_ARGS)
+int Element_CBNW::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, oldt;
+ oldt = parts[i].tmp;
+ if (sim->pv[y/CELL][x/CELL]<=3)
+ {
+ if(20>(rand()%80000))
+ {
+ sim->part_change_type(i,x,y,PT_CO2);
+ parts[i].ctype = 5;
+ sim->pv[y/CELL][x/CELL] += 0.5f;
+ }
+ else if(sim->pv[y/CELL][x/CELL]<=-0.5)
+ {
+ sim->part_change_type(i,x,y,PT_CO2);
+ parts[i].ctype = 5;
+ sim->pv[y/CELL][x/CELL] += 0.5f;
+ }
+ }
+ if (parts[i].tmp>0)
+ parts[i].tmp--;
+ if(!(rand()%200))
+ {
+ parts[i].tmp2 = rand()%40;
+ } else if(parts[i].tmp2!=20) {
+ parts[i].tmp2 -= (parts[i].tmp2>20)?1:-1;
+ }
+ if(oldt==1)
+ {
+ //Explode
+ if(rand()%4)
+ {
+ sim->part_change_type(i,x,y,PT_CO2);
+ parts[i].ctype = 5;
+ sim->pv[y/CELL][x/CELL] += 0.2f;
+ }
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((sim->elements[r&0xFF].Properties&TYPE_PART) && parts[i].tmp == 0 && 1>(rand()%250))
+ {
+ //Start explode
+ parts[i].tmp = rand()%25;//(rand()%100)+50;
+ }
+ else if((sim->elements[r&0xFF].Properties&TYPE_SOLID) && (r&0xFF)!=PT_DMND && (r&0xFF)!=PT_GLAS && parts[i].tmp == 0 && (2-sim->pv[y/CELL][x/CELL])>(rand()%20000))
+ {
+ if(rand()%2)
+ {
+ sim->part_change_type(i,x,y,PT_CO2);
+ parts[i].ctype = 5;
+ sim->pv[y/CELL][x/CELL] += 0.2f;
+ }
+ }
+ if ((r&0xFF)==PT_CBNW)
+ {
+ if(!parts[i].tmp && parts[r>>8].tmp)
+ {
+ parts[i].tmp = parts[r>>8].tmp;
+ if((r>>8)>i) //If the other particle hasn't been life updated
+ parts[i].tmp--;
+ }
+ else if(parts[i].tmp && !parts[r>>8].tmp)
+ {
+ parts[r>>8].tmp = parts[i].tmp;
+ if((r>>8)>i) //If the other particle hasn't been life updated
+ parts[r>>8].tmp++;
+ }
+ }
+ if (((r&0xFF)==PT_RBDM||(r&0xFF)==PT_LRBD) && (sim->legacy_enable||parts[i].temp>(273.15f+12.0f)) && 1>(rand()%500))
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = 4;
+ parts[i].ctype = PT_WATR;
+ }
+ if ((r&0xFF)==PT_FIRE && parts[r>>8].ctype!=PT_WATR){
+ sim->kill_part(r>>8);
+ if(1>(rand()%150)){
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_CBNW static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_CBNW::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int z = cpart->tmp2 - 20;//speckles!
+ *colr += z * 1;
+ *colg += z * 2;
+ *colb += z * 8;
+ return 0;
+}
+
+
+Element_CBNW::~Element_CBNW() {} \ No newline at end of file
diff --git a/src/simulation/elements/CLNE.cpp b/src/simulation/elements/CLNE.cpp
new file mode 100644
index 0000000..6ffe4f1
--- /dev/null
+++ b/src/simulation/elements/CLNE.cpp
@@ -0,0 +1,91 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CLNE PT_CLNE 9
+Element_CLNE::Element_CLNE()
+{
+ Identifier = "DEFAULT_PT_CLNE";
+ Name = "CLNE";
+ Colour = PIXPACK(0xFFD010);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. Duplicates any particles it touches.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_CLNE::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_CLNE static int update(UPDATE_FUNC_ARGS)
+int Element_CLNE::update(UPDATE_FUNC_ARGS)
+ {
+ if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled || (parts[i].ctype==PT_LIFE && (parts[i].tmp<0 || parts[i].tmp>=NGOLALT)))
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN &&
+ (r&0xFF)!=PT_BCLN && (r&0xFF)!=PT_STKM &&
+ (r&0xFF)!=PT_PBCN && (r&0xFF)!=PT_STKM2 &&
+ (r&0xFF)<PT_NUM)
+ {
+ parts[i].ctype = r&0xFF;
+ if ((r&0xFF)==PT_LIFE || (r&0xFF)==PT_LAVA)
+ parts[i].tmp = parts[r>>8].ctype;
+ }
+ }
+ }
+ else {
+ if (parts[i].ctype==PT_LIFE) sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, parts[i].ctype|(parts[i].tmp<<8));
+ else if (parts[i].ctype!=PT_LIGH || (rand()%30)==0)
+ {
+ int np = sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, parts[i].ctype);
+ if (np>=0)
+ {
+ if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
+ parts[np].ctype = parts[i].tmp;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_CLNE::~Element_CLNE() {}
diff --git a/src/simulation/elements/CLST.cpp b/src/simulation/elements/CLST.cpp
new file mode 100644
index 0000000..3cab1f7
--- /dev/null
+++ b/src/simulation/elements/CLST.cpp
@@ -0,0 +1,101 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CLST PT_CLST 155
+Element_CLST::Element_CLST()
+{
+ Identifier = "DEFAULT_PT_CLST";
+ Name = "CLST";
+ Colour = PIXPACK(0xE4A4A4);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.2f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 2;
+ Hardness = 2;
+
+ Weight = 55;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Clay dust. Produces paste when mixed with water.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1256.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_CLST::update;
+ Graphics = &Element_CLST::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_CLST static int update(UPDATE_FUNC_ARGS)
+int Element_CLST::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ float cxy;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR && 1>(rand()%1500))
+ {
+ sim->part_change_type(i,x,y,PT_PSTS);
+ sim->kill_part(r>>8);
+ }
+ if ((r&0xFF)==PT_NITR)
+ {
+ sim->create_part(i, x, y, PT_BANG);
+ sim->create_part(r>>8, x+rx, y+ry, PT_BANG);
+ }
+ if ((r&0xFF)==PT_CLST)
+ {
+ if(parts[i].temp <195)
+ cxy = 0.05;
+ if(parts[i].temp >= 195 && parts[i].temp <295)
+ cxy = 0.015;
+ if(parts[i].temp >= 295 && parts[i].temp <350)
+ cxy = 0.01;
+ if(parts[i].temp > 350)
+ cxy = 0.005;
+ parts[i].vx += cxy*rx;
+ parts[i].vy += cxy*ry;//These two can be set not to calculate over 350 later. They do virtually nothing over 0.005.
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_CLST static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_CLST::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int z = cpart->tmp - 5;//speckles!
+ *colr += z * 16;
+ *colg += z * 16;
+ *colb += z * 16;
+ return 0;
+}
+
+
+Element_CLST::~Element_CLST() {} \ No newline at end of file
diff --git a/src/simulation/elements/CNCT.cpp b/src/simulation/elements/CNCT.cpp
new file mode 100644
index 0000000..77f70be
--- /dev/null
+++ b/src/simulation/elements/CNCT.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CNCT PT_CNCT 24
+Element_CNCT::Element_CNCT()
+{
+ Identifier = "DEFAULT_PT_CNCT";
+ Name = "CNCT";
+ Colour = PIXPACK(0xC0C0C0);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 2;
+ Hardness = 2;
+
+ Weight = 55;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 100;
+ Description = "Concrete, stronger than stone.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1123.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_CNCT::~Element_CNCT() {} \ No newline at end of file
diff --git a/src/simulation/elements/CO2.cpp b/src/simulation/elements/CO2.cpp
new file mode 100644
index 0000000..49614fb
--- /dev/null
+++ b/src/simulation/elements/CO2.cpp
@@ -0,0 +1,106 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CO2 PT_CO2 80
+Element_CO2::Element_CO2()
+{
+ Identifier = "DEFAULT_PT_CO2";
+ Name = "CO2";
+ Colour = PIXPACK(0x666666);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 2.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.1f;
+ Diffusion = 1.0f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+273.15f;
+ HeatConduct = 88;
+ Description = "Carbon Dioxide";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 194.65f;
+ LowTemperatureTransition = PT_DRIC;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_CO2::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_CO2 static int update(UPDATE_FUNC_ARGS)
+int Element_CO2::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (parts[i].ctype==5 && 20>(rand()%40000))
+ {
+ if (sim->create_part(-1, x+rx, y+ry, PT_WATR)>=0)
+ parts[i].ctype = 0;
+ }
+ if ((r>>8)>=NPART || !r)
+ continue;
+ if ((r&0xFF)==PT_FIRE){
+ sim->kill_part(r>>8);
+ if(1>(rand()%150)){
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ if (((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW) && 1>(rand()%250))
+ {
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_CBNW);
+ if (parts[i].ctype==5) //conserve number of water particles - ctype=5 means this CO2 hasn't released the water particle from BUBW yet
+ sim->create_part(i, x, y, PT_WATR);
+ else
+ sim->kill_part(i);
+ }
+ }
+ if (parts[i].temp > 9773.15 && sim->pv[y/CELL][x/CELL] > 200.0f)
+ {
+ if (rand()%5 < 1)
+ {
+ int j;
+ sim->create_part(i,x,y,PT_O2);
+
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_NEUT);
+ if (j != -1)
+ parts[j].temp = 15000;
+ if (!(rand()%50))
+ {
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_ELEC);
+ if (j != -1)
+ parts[j].temp = 15000;
+ }
+
+ parts[i].temp = 15000;
+ sim->pv[y/CELL][x/CELL] += 100;
+ }
+ }
+ return 0;
+}
+
+
+Element_CO2::~Element_CO2() {}
diff --git a/src/simulation/elements/COAL.cpp b/src/simulation/elements/COAL.cpp
new file mode 100644
index 0000000..eae7450
--- /dev/null
+++ b/src/simulation/elements/COAL.cpp
@@ -0,0 +1,153 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_COAL PT_COAL 59
+Element_COAL::Element_COAL()
+{
+ Identifier = "DEFAULT_PT_COAL";
+ Name = "COAL";
+ Colour = PIXPACK(0x222222);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.0f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 200;
+ Description = "Solid. Burns slowly.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_COAL::update;
+ Graphics = &Element_COAL::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_COAL static int update(UPDATE_FUNC_ARGS)
+int Element_COAL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, trade, temp;
+ if (parts[i].life<=0) {
+ sim->create_part(i, x, y, PT_FIRE);
+ return 1;
+ } else if (parts[i].life < 100) {
+ parts[i].life--;
+ sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, PT_FIRE);
+ }
+ if ((sim->pv[y/CELL][x/CELL] > 4.3f)&&parts[i].tmp>40)
+ parts[i].tmp=39;
+ else if (parts[i].tmp<40&&parts[i].tmp>0)
+ parts[i].tmp--;
+ else if (parts[i].tmp<=0) {
+ sim->create_part(i, x, y, PT_BCOL);
+ return 1;
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_FIRE || (r&0xFF)==PT_PLSM) && 1>(rand()%500))
+ {
+ if (parts[i].life>100) {
+ parts[i].life = 99;
+ }
+ }
+ if ((r&0xFF)==PT_LAVA && 1>(rand()%500))
+ {
+ if (parts[r>>8].ctype == PT_IRON) {
+ parts[r>>8].ctype = PT_METL;
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ /*if(100-parts[i].life > parts[i].tmp2)
+ parts[i].tmp2 = 100-parts[i].life;
+ if(parts[i].tmp2 < 0) parts[i].tmp2 = 0;
+ for ( trade = 0; trade<4; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_COAL || (r&0xFF)==PT_BCOL)&&(parts[i].tmp2>parts[r>>8].tmp2)&&parts[i].tmp2>0)//diffusion
+ {
+ int temp = parts[i].tmp2 - parts[r>>8].tmp2;
+ if(temp < 10)
+ continue;
+ if (temp ==1)
+ {
+ parts[r>>8].tmp2 ++;
+ parts[i].tmp2 --;
+ }
+ else if (temp>0)
+ {
+ parts[r>>8].tmp2 += temp/2;
+ parts[i].tmp2 -= temp/2;
+ }
+ }
+ }
+ }*/
+ if(parts[i].temp > parts[i].tmp2)
+ parts[i].tmp2 = parts[i].temp;
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_COAL static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_COAL::graphics(GRAPHICS_FUNC_ARGS)
+ //Both COAL and Broken Coal
+{
+ *colr += (cpart->tmp2-295.15f)/3;
+
+ if (*colr > 170)
+ *colr = 170;
+ if (*colr < *colg)
+ *colr = *colg;
+
+ *colg = *colb = *colr;
+
+ if((cpart->temp-295.15f) > 300.0f-200.0f)
+ {
+ float frequency = 3.1415/(2*300.0f-(300.0f-200.0f));
+ int q = ((cpart->temp-295.15f)>300.0f)?300.0f-(300.0f-200.0f):(cpart->temp-295.15f)-(300.0f-200.0f);
+
+ *colr += sin(frequency*q) * 226;
+ *colg += sin(frequency*q*4.55 +3.14) * 34;
+ *colb += sin(frequency*q*2.22 +3.14) * 64;
+ }
+ return 0;
+}
+
+
+
+Element_COAL::~Element_COAL() {} \ No newline at end of file
diff --git a/src/simulation/elements/CONV.cpp b/src/simulation/elements/CONV.cpp
new file mode 100644
index 0000000..6ad1336
--- /dev/null
+++ b/src/simulation/elements/CONV.cpp
@@ -0,0 +1,96 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_CONV PT_CONV 85
+Element_CONV::Element_CONV()
+{
+ Identifier = "DEFAULT_PT_CONV";
+ Name = "CONV";
+ Colour = PIXPACK(0x0AAB0A);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. Converts whatever touches it into its ctype.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_CONV::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_CONV static int update(UPDATE_FUNC_ARGS)
+int Element_CONV::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled || (parts[i].ctype==PT_LIFE && (parts[i].tmp<0 || parts[i].tmp>=NGOLALT)))
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN &&
+ (r&0xFF)!=PT_BCLN && (r&0xFF)!=PT_STKM &&
+ (r&0xFF)!=PT_PBCN && (r&0xFF)!=PT_STKM2 &&
+ (r&0xFF)!=PT_CONV && (r&0xFF)<PT_NUM)
+ {
+ parts[i].ctype = r&0xFF;
+ if ((r&0xFF)==PT_LIFE)
+ parts[i].tmp = parts[r>>8].ctype;
+ }
+ }
+ }
+ else if(parts[i].ctype>0 && parts[i].ctype<PT_NUM && sim->elements[parts[i].ctype].Enabled && parts[i].ctype!=PT_CONV) {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if((r&0xFF)!=PT_CONV && (r&0xFF)!=PT_DMND && (r&0xFF)!=parts[i].ctype)
+ {
+ if (parts[i].ctype==PT_LIFE) sim->create_part(r>>8, x+rx, y+ry, parts[i].ctype|(parts[i].tmp<<8));
+ else sim->create_part(r>>8, x+rx, y+ry, parts[i].ctype);
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_CONV::~Element_CONV() {} \ No newline at end of file
diff --git a/src/simulation/elements/DESL.cpp b/src/simulation/elements/DESL.cpp
new file mode 100644
index 0000000..a79086d
--- /dev/null
+++ b/src/simulation/elements/DESL.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DESL PT_DESL 58
+Element_DESL::Element_DESL()
+{
+ Identifier = "DEFAULT_PT_DESL";
+ Name = "DESL";
+ Colour = PIXPACK(0x440000);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 1.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.0f;
+ HotAir = 0.0f * CFDS;
+ Falldown = 2;
+
+ Flammable = 2;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 5;
+
+ Weight = 15;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 42;
+ Description = "Liquid. Explodes under high pressure and temperatures";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 5.0f;
+ HighPressureTransition = PT_FIRE;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 335.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_DESL::~Element_DESL() {} \ No newline at end of file
diff --git a/src/simulation/elements/DEST.cpp b/src/simulation/elements/DEST.cpp
new file mode 100644
index 0000000..a4f7891
--- /dev/null
+++ b/src/simulation/elements/DEST.cpp
@@ -0,0 +1,121 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DEST PT_DEST 89
+Element_DEST::Element_DEST()
+{
+ Identifier = "DEFAULT_PT_DEST";
+ Name = "DEST";
+ Colour = PIXPACK(0xFF3311);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = -0.05f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.4f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 101;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 150;
+ Description = "More destructive Bomb.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_DEST::update;
+ Graphics = &Element_DEST::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_DEST static int update(UPDATE_FUNC_ARGS)
+int Element_DEST::update(UPDATE_FUNC_ARGS)
+ {
+ int r,rx,ry,topv;
+ rx=rand()%5-2;
+ ry=rand()%5-2;
+
+ r = pmap[y+ry][x+rx];
+ if (!r || (r&0xFF)==PT_DEST || (r&0xFF)==PT_DMND || (r&0xFF)==PT_BCLN || (r&0xFF)==PT_CLNE || (r&0xFF)==PT_PCLN || (r&0xFF)==PT_PBCN)
+ return 0;
+
+ if (parts[i].life<=0 || parts[i].life>37)
+ {
+ parts[i].life=30+rand()%20;
+ parts[i].temp+=20000;
+ sim->pv[y/CELL][x/CELL]+=60.0f;
+ }
+ parts[i].temp+=10000;
+ if ((r&0xFF)==PT_PLUT || (r&0xFF)==PT_DEUT)
+ {
+ sim->pv[y/CELL][x/CELL]+=20.0f;
+ parts[i].temp+=18000;
+ if (rand()%2==0)
+ {
+ float orig_temp = parts[r>>8].temp;
+ sim->create_part(r>>8, x+rx, y+ry, PT_NEUT);
+ parts[r>>8].temp = restrict_flt(orig_temp+40000.0f, MIN_TEMP, MAX_TEMP);
+ sim->pv[y/CELL][x/CELL] += 10.0f;
+ parts[i].life-=4;
+ }
+ }
+ else if ((r&0xFF)==PT_INSL)
+ {
+ sim->create_part(r>>8, x+rx, y+ry, PT_PLSM);
+ }
+ else if (rand()%3==0)
+ {
+ sim->kill_part(r>>8);
+ parts[i].life -= 4*((sim->elements[r&0xFF].Properties&TYPE_SOLID)?3:1);
+ if (parts[i].life<=0)
+ parts[i].life=1;
+ parts[i].temp+=10000;
+ }
+ else
+ {
+ if (sim->elements[r&0xFF].HeatConduct) parts[r>>8].temp = restrict_flt(parts[r>>8].temp+10000.0f, MIN_TEMP, MAX_TEMP);
+ }
+ topv=sim->pv[y/CELL][x/CELL]/9+parts[r>>8].temp/900;
+ if (topv>40.0f)
+ topv=40.0f;
+ sim->pv[y/CELL][x/CELL]+=40.0f+topv;
+ parts[i].temp = restrict_flt(parts[i].temp, MIN_TEMP, MAX_TEMP);
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_DEST static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_DEST::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->life)
+ {
+ *pixel_mode |= PMODE_LFLARE;
+ }
+ else
+ {
+ *pixel_mode |= PMODE_SPARK;
+ }
+ return 0;
+}
+
+
+Element_DEST::~Element_DEST() {} \ No newline at end of file
diff --git a/src/simulation/elements/DEUT.cpp b/src/simulation/elements/DEUT.cpp
new file mode 100644
index 0000000..b8209e4
--- /dev/null
+++ b/src/simulation/elements/DEUT.cpp
@@ -0,0 +1,149 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DEUT PT_DEUT 95
+Element_DEUT::Element_DEUT()
+{
+ Identifier = "DEFAULT_PT_DEUT";
+ Name = "DEUT";
+ Colour = PIXPACK(0x00153F);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 31;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Deuterium oxide. Volume changes with temp, radioactive with neutrons.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_DEUT::update;
+ Graphics = &Element_DEUT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_DEUT static int update(UPDATE_FUNC_ARGS)
+int Element_DEUT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, trade, np;
+ float gravtot = fabs(sim->gravy[(y/CELL)*(XRES/CELL)+(x/CELL)])+fabs(sim->gravx[(y/CELL)*(XRES/CELL)+(x/CELL)]);
+ int maxlife = ((10000/(parts[i].temp + 1))-1);
+ if ((10000%((int)parts[i].temp+1))>rand()%((int)parts[i].temp+1))
+ maxlife ++;
+ // Compress when Newtonian gravity is applied
+ // multiplier=1 when gravtot=0, multiplier -> 5 as gravtot -> inf
+ maxlife = maxlife*(5.0f - 8.0f/(gravtot+2.0f));
+ if (parts[i].life < maxlife)
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r || (parts[i].life >=maxlife))
+ continue;
+ if ((r&0xFF)==PT_DEUT&&33>=rand()/(RAND_MAX/100)+1)
+ {
+ if ((parts[i].life + parts[r>>8].life + 1) <= maxlife)
+ {
+ parts[i].life += parts[r>>8].life + 1;
+ sim->kill_part(r>>8);
+ }
+ }
+ }
+ }
+ else
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (parts[i].life<=maxlife)
+ continue;
+ if ((!r)&&parts[i].life>=1)//if nothing then create deut
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_DEUT);
+ if (np<0) continue;
+ parts[i].life--;
+ parts[np].temp = parts[i].temp;
+ parts[np].life = 0;
+ }
+ }
+ for ( trade = 0; trade<4; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_DEUT&&(parts[i].life>parts[r>>8].life)&&parts[i].life>0)//diffusion
+ {
+ int temp = parts[i].life - parts[r>>8].life;
+ if (temp ==1)
+ {
+ parts[r>>8].life ++;
+ parts[i].life --;
+ }
+ else if (temp>0)
+ {
+ parts[r>>8].life += temp/2;
+ parts[i].life -= temp/2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_DEUT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_DEUT::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->life>=700)
+ {
+ *firea = 60;
+ *firer = *colr += cpart->life*1;
+ *fireg = *colg += cpart->life*2;
+ *fireb = *colb += cpart->life*3;
+ *pixel_mode |= PMODE_GLOW | FIRE_ADD;
+ }
+ else
+ {
+ *colr += cpart->life*1;
+ *colg += cpart->life*2;
+ *colb += cpart->life*3;
+ *pixel_mode |= PMODE_BLUR;
+ }
+ return 0;
+}
+
+
+Element_DEUT::~Element_DEUT() {} \ No newline at end of file
diff --git a/src/simulation/elements/DLAY.cpp b/src/simulation/elements/DLAY.cpp
new file mode 100644
index 0000000..e69c202
--- /dev/null
+++ b/src/simulation/elements/DLAY.cpp
@@ -0,0 +1,111 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DLAY PT_DLAY 79
+Element_DLAY::Element_DLAY()
+{
+ Identifier = "DEFAULT_PT_DLAY";
+ Name = "DLAY";
+ Colour = PIXPACK(0x753590);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = 4.0f+273.15f;
+ HeatConduct = 0;
+ Description = "Conducts with temperature-dependent delay. (use HEAT/COOL).";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_DLAY::update;
+ Graphics = &Element_DLAY::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_DLAY static int update(UPDATE_FUNC_ARGS)
+int Element_DLAY::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, oldl;
+ oldl = parts[i].life;
+ if (parts[i].life>0)
+ parts[i].life--;
+ //if (parts[i].life==1)
+ //{
+ if (parts[i].temp>=MAX_TEMP+273.15f)
+ parts[i].temp = MAX_TEMP+273.15f;
+ if (parts[i].temp<= 1.0f+273.15f)
+ parts[i].temp = 1.0f+273.15f;
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r || sim->parts_avg(r>>8, i,PT_INSL)==PT_INSL)
+ continue;
+ if ((r&0xFF)==PT_SPRK && parts[i].life==0 && parts[r>>8].life>0 && parts[r>>8].life<4 && parts[r>>8].ctype==PT_PSCN)
+ {
+ parts[i].life = (int)(parts[i].temp-273.15);
+ }
+ else if ((r&0xFF)==PT_DLAY)
+ {
+ if(!parts[i].life && parts[r>>8].life)
+ {
+ parts[i].life = parts[r>>8].life;
+ if((r>>8)>i) //If the other particle hasn't been life updated
+ parts[i].life--;
+ }
+ else if(parts[i].life && !parts[r>>8].life)
+ {
+ parts[r>>8].life = parts[i].life;
+ if((r>>8)>i) //If the other particle hasn't been life updated
+ parts[r>>8].life++;
+ }
+ }
+ else if((r&0xFF)==PT_NSCN && oldl==1)
+ {
+ sim->create_part(-1, x+rx, y+ry, PT_SPRK);
+ }
+ }
+ //}
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_DLAY static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_DLAY::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int stage = (int)(((float)cpart->life/(cpart->temp-273.15))*100.0f);
+ *colr += stage;
+ *colg += stage;
+ *colb += stage;
+ return 0;
+}
+
+
+Element_DLAY::~Element_DLAY() {} \ No newline at end of file
diff --git a/src/simulation/elements/DMG.cpp b/src/simulation/elements/DMG.cpp
new file mode 100644
index 0000000..9c19199
--- /dev/null
+++ b/src/simulation/elements/DMG.cpp
@@ -0,0 +1,118 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DMG PT_DMG 163
+Element_DMG::Element_DMG()
+{
+ Identifier = "DEFAULT_PT_DMG";
+ Name = "DMG";
+ Colour = PIXPACK(0x88FF88);
+ MenuVisible = 1;
+ MenuSection = SC_FORCE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "DMG.";
+
+ State = ST_NONE;
+ Properties = TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC|PROP_SPARKSETTLE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_DMG::update;
+ Graphics = &Element_DMG::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_DMG static int update(UPDATE_FUNC_ARGS)
+int Element_DMG::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rr, rx, ry, nb, nxi, nxj, t, dist;
+ int rad = 25;
+ float angle, fx, fy;
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_DMG && (r&0xFF)!=PT_EMBR && (r&0xFF)!=PT_DMND && (r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN && (r&0xFF)!=PT_BCLN)
+ {
+ sim->kill_part(i);
+ for (nxj=-rad; nxj<=rad; nxj++)
+ for (nxi=-rad; nxi<=rad; nxi++)
+ if (x+nxi>=0 && y+nxj>=0 && x+nxi<XRES && y+nxj<YRES && (nxi || nxj))
+ {
+ dist = sqrt(pow(nxi, 2.0f)+pow(nxj, 2.0f));//;(pow((float)nxi,2))/(pow((float)rad,2))+(pow((float)nxj,2))/(pow((float)rad,2));
+ if (!dist || (dist <= rad))
+ {
+ rr = pmap[y+nxj][x+nxi];
+ if (rr)
+ {
+ angle = atan2((float)nxj, nxi);
+ fx = cos(angle) * 7.0f;
+ fy = sin(angle) * 7.0f;
+
+ parts[rr>>8].vx += fx;
+ parts[rr>>8].vy += fy;
+
+ sim->vx[(y+nxj)/CELL][(x+nxi)/CELL] += fx;
+ sim->vy[(y+nxj)/CELL][(x+nxi)/CELL] += fy;
+
+ sim->pv[(y+nxj)/CELL][(x+nxi)/CELL] += 1.0f;
+
+ t = parts[rr>>8].type;
+ if(t && sim->elements[t].HighPressureTransition>-1 && sim->elements[t].HighPressureTransition<PT_NUM)
+ sim->part_change_type(rr>>8, x+nxi, y+nxj, sim->elements[t].HighPressureTransition);
+ else if(t == PT_BMTL)
+ sim->part_change_type(rr>>8, x+nxi, y+nxj, PT_BRMT);
+ else if(t == PT_GLAS)
+ sim->part_change_type(rr>>8, x+nxi, y+nxj, PT_BGLA);
+ else if(t == PT_COAL)
+ sim->part_change_type(rr>>8, x+nxi, y+nxj, PT_BCOL);
+ else if(t == PT_QRTZ)
+ sim->part_change_type(rr>>8, x+nxi, y+nxj, PT_PQRT);
+ }
+ }
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_DMG static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_DMG::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *pixel_mode |= PMODE_FLARE;
+ return 1;
+}
+
+
+Element_DMG::~Element_DMG() {}
diff --git a/src/simulation/elements/DMND.cpp b/src/simulation/elements/DMND.cpp
new file mode 100644
index 0000000..3c6d24a
--- /dev/null
+++ b/src/simulation/elements/DMND.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DMND PT_DMND 28
+Element_DMND::Element_DMND()
+{
+ Identifier = "DEFAULT_PT_DMND";
+ Name = "DMND";
+ Colour = PIXPACK(0xCCFFFF);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 186;
+ Description = "Diamond. Indestructible.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_DMND::~Element_DMND() {} \ No newline at end of file
diff --git a/src/simulation/elements/DRIC.cpp b/src/simulation/elements/DRIC.cpp
new file mode 100644
index 0000000..ea2a3c8
--- /dev/null
+++ b/src/simulation/elements/DRIC.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DRIC PT_DRIC 81
+Element_DRIC::Element_DRIC()
+{
+ Identifier = "DEFAULT_PT_DRIC";
+ Name = "DRIC";
+ Colour = PIXPACK(0xE0E0E0);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.0005f* CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 100;
+
+ Temperature = 172.65f;
+ HeatConduct = 2;
+ Description = "Dry Ice.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 195.65f;
+ HighTemperatureTransition = PT_CO2;
+
+ Update = NULL;
+
+}
+
+Element_DRIC::~Element_DRIC() {} \ No newline at end of file
diff --git a/src/simulation/elements/DSTW.cpp b/src/simulation/elements/DSTW.cpp
new file mode 100644
index 0000000..8b16107
--- /dev/null
+++ b/src/simulation/elements/DSTW.cpp
@@ -0,0 +1,92 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DSTW PT_DSTW 25
+Element_DSTW::Element_DSTW()
+{
+ Identifier = "DEFAULT_PT_DSTW";
+ Name = "DSTW";
+ Colour = PIXPACK(0x1020C0);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 23;
+ Description = "Distilled water, does not conduct electricity.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 273.15f;
+ LowTemperatureTransition = PT_ICEI;
+ HighTemperature = 373.0f;
+ HighTemperatureTransition = PT_WTRV;
+
+ Update = &Element_DSTW::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_DSTW static int update(UPDATE_FUNC_ARGS)
+int Element_DSTW::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SALT && 1>(rand()%250))
+ {
+ sim->part_change_type(i,x,y,PT_SLTW);
+ // on average, convert 3 DSTW to SLTW before SALT turns into SLTW
+ if (rand()%3==0)
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SLTW);
+ }
+ if (((r&0xFF)==PT_WATR||(r&0xFF)==PT_SLTW) && 1>(rand()%500))
+ {
+ sim->part_change_type(i,x,y,PT_WATR);
+ }
+ if ((r&0xFF)==PT_SLTW && 1>(rand()%10000))
+ {
+ sim->part_change_type(i,x,y,PT_SLTW);
+ }
+ if (((r&0xFF)==PT_RBDM||(r&0xFF)==PT_LRBD) && (sim->legacy_enable||parts[i].temp>12.0f) && 1>(rand()%500))
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = 4;
+ }
+ if ((r&0xFF)==PT_FIRE){
+ sim->kill_part(r>>8);
+ if(1>(rand()%150)){
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_DSTW::~Element_DSTW() {} \ No newline at end of file
diff --git a/src/simulation/elements/DTEC.cpp b/src/simulation/elements/DTEC.cpp
new file mode 100644
index 0000000..6d67cf2
--- /dev/null
+++ b/src/simulation/elements/DTEC.cpp
@@ -0,0 +1,99 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DTEC PT_DTEC 162
+Element_DTEC::Element_DTEC()
+{
+ Identifier = "DEFAULT_PT_DTEC";
+ Name = "DTEC";
+ Colour = PIXPACK(0xFD9D18);
+ MenuVisible = 1;
+ MenuSection = SC_SENSOR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.96f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Creates a spark when something with its ctype is nearby";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_DTEC::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_DTEC static int in_radius(int rd, int x, int y)
+int Element_DTEC::in_radius(int rd, int x, int y)
+{
+ return (pow((double)x,2)*pow((double)rd,2)+pow((double)y,2)*pow((double)rd,2)<=pow((double)rd,2)*pow((double)rd,2));
+}
+
+//#TPT-Directive ElementHeader Element_DTEC static int update(UPDATE_FUNC_ARGS)
+int Element_DTEC::update(UPDATE_FUNC_ARGS)
+{
+ int r, rx, ry, rt, rd = parts[i].tmp2;
+ if (rd > 25) parts[i].tmp2 = rd = 25;
+ if (parts[i].life)
+ {
+ parts[i].life = 0;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ if (sim->parts_avg(i,r>>8,PT_INSL) != PT_INSL)
+ {
+ if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[r>>8].life==0 && in_radius(rd, rx, ry))
+ {
+ parts[r>>8].life = 4;
+ parts[r>>8].ctype = rt;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ }
+ }
+ }
+ }
+ for (rx=-rd; rx<rd+1; rx++)
+ for (ry=-rd; ry<rd+1; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if(!r)
+ r = sim->photons[y+ry][x+rx];
+ if(!r)
+ continue;
+ if (parts[r>>8].type == parts[i].ctype && (parts[i].ctype != PT_LIFE || parts[i].tmp == parts[r>>8].tmp))
+ parts[i].life = 1;
+ }
+ return 0;
+}
+
+
+
+Element_DTEC::~Element_DTEC() {}
diff --git a/src/simulation/elements/DUST.cpp b/src/simulation/elements/DUST.cpp
new file mode 100644
index 0000000..924dabb
--- /dev/null
+++ b/src/simulation/elements/DUST.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DUST PT_DUST 1
+Element_DUST::Element_DUST()
+{
+ Identifier = "DEFAULT_PT_DUST";
+ Name = "DUST";
+ Colour = PIXPACK(0xFFE0A0);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 10;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 85;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Very light dust. Flammable.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+ Graphics = NULL;
+}
+
+Element_DUST::~Element_DUST() {} \ No newline at end of file
diff --git a/src/simulation/elements/DYST.cpp b/src/simulation/elements/DYST.cpp
new file mode 100644
index 0000000..fdf16bb
--- /dev/null
+++ b/src/simulation/elements/DYST.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DYST PT_DYST 64
+Element_DYST::Element_DYST()
+{
+ Identifier = "DEFAULT_PT_DYST";
+ Name = "DYST";
+ Colour = PIXPACK(0xBBB0A0);
+ MenuVisible = 0;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 20;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 80;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Dead Yeast.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 473.0f;
+ HighTemperatureTransition = PT_DUST;
+
+ Update = NULL;
+
+}
+
+Element_DYST::~Element_DYST() {} \ No newline at end of file
diff --git a/src/simulation/elements/ELEC.cpp b/src/simulation/elements/ELEC.cpp
new file mode 100644
index 0000000..c602da8
--- /dev/null
+++ b/src/simulation/elements/ELEC.cpp
@@ -0,0 +1,160 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ELEC PT_ELEC 136
+Element_ELEC::Element_ELEC()
+{
+ Identifier = "DEFAULT_PT_ELEC";
+ Name = "ELEC";
+ Colour = PIXPACK(0xDFEFFF);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ Loss = 1.00f;
+ Collision = -0.99f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = -1;
+
+ Temperature = R_TEMP+200.0f+273.15f;
+ HeatConduct = 251;
+ Description = "Electrons";
+
+ State = ST_GAS;
+ Properties = TYPE_ENERGY|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_ELEC::update;
+ Graphics = &Element_ELEC::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_ELEC static int update(UPDATE_FUNC_ARGS)
+int Element_ELEC::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rt, rx, ry, nb, rrx, rry;
+ float rr, rrr;
+ parts[i].pavg[0] = x;
+ parts[i].pavg[1] = y;
+ if(pmap[y][x]==PT_GLOW)
+ {
+ sim->part_change_type(i, x, y, PT_PHOT);
+ }
+ for (rx=-2; rx<=2; rx++)
+ for (ry=-2; ry<=2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES) {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_GLAS)
+ {
+ for (rrx=-1; rrx<=1; rrx++)
+ {
+ for (rry=-1; rry<=1; rry++)
+ {
+ if (x+rx+rrx>=0 && y+ry+rry>=0 && x+rx+rrx<XRES && y+ry+rry<YRES) {
+ nb = sim->create_part(-1, x+rx+rrx, y+ry+rry, PT_EMBR);
+ if (nb!=-1) {
+ parts[nb].tmp = 0;
+ parts[nb].life = 50;
+ parts[nb].temp = parts[i].temp*0.8f;
+ parts[nb].vx = rand()%20-10;
+ parts[nb].vy = rand()%20-10;
+ }
+ }
+ }
+ }
+ //fire_r[y/CELL][x/CELL] += rand()%200; //D: Doesn't work with OpenGL, also shouldn't be here
+ //fire_g[y/CELL][x/CELL] += rand()%200;
+ //fire_b[y/CELL][x/CELL] += rand()%200;
+ /* possible alternative, but doesn't work well at the moment because FIRE_ADD divides firea by 8, so the glow isn't strong enough
+ create_part(i, x, y, PT_EMBR);
+ parts[i].tmp = 2;
+ parts[i].life = 2;
+ parts[i].ctype = ((rand()%200)<<16) | ((rand()%200)<<8) | (rand()%200);
+ */
+ sim->kill_part(i);
+ return 1;
+ }
+ if ((r&0xFF)==PT_LCRY)
+ {
+ parts[r>>8].tmp2 = 5+rand()%5;
+ }
+ if ((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW || (r&0xFF)==PT_SLTW || (r&0xFF)==PT_CBNW)
+ {
+ if(rand()<RAND_MAX/3)
+ {
+ sim->create_part(r>>8, x+rx, y+ry, PT_O2);
+ return 1;
+ }
+ else
+ {
+ sim->create_part(r>>8, x+rx, y+ry, PT_H2);
+ return 1;
+ }
+ }
+ if ((r&0xFF)==PT_NEUT && !pmap[y+ry][x+rx])
+ {
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_H2);
+ parts[r>>8].life = 0;
+ parts[r>>8].ctype = 0;
+ }
+ if ((r&0xFF)==PT_DEUT)
+ {
+ if(parts[r>>8].life < 6000)
+ parts[r>>8].life += 1;
+ parts[r>>8].temp = 0;
+ sim->kill_part(i);
+ return 1;
+ }
+ if ((r&0xFF)==PT_EXOT)
+ {
+ parts[r>>8].tmp2 += 5;
+ parts[r>>8].life = 1000;
+ }
+ if ((sim->elements[r&0xFF].Properties & PROP_CONDUCTS) && ((r&0xFF)!=PT_NBLE||parts[i].temp<2273.15))
+ {
+ sim->create_part(-1, x+rx, y+ry, PT_SPRK);
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_ELEC static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_ELEC::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 70;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+
+ *pixel_mode |= FIRE_ADD;
+ return 0;
+}
+
+
+Element_ELEC::~Element_ELEC() {}
diff --git a/src/simulation/elements/EMBR.cpp b/src/simulation/elements/EMBR.cpp
new file mode 100644
index 0000000..5ba37c2
--- /dev/null
+++ b/src/simulation/elements/EMBR.cpp
@@ -0,0 +1,126 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_EMBR PT_EMBR 147
+Element_EMBR::Element_EMBR()
+{
+
+ //{"EMBR", PIXPACK(0xFFF288), 0.4f, 0.001f * CFDS, 0.99f, 0.90f, 0.0f, 0.07f, 0.00f, 0.000f * CFDS, 1, 0, 0, 0, 20, 0, 1, 30, SC_EXPLOSIVE, 500.0f +273.15f, 29, "Sparks. Formed by explosions.", ST_NONE, TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL|PROP_SPARKSETTLE, &update_EMBR, &graphics_EMBR},
+
+ Identifier = "DEFAULT_PT_EMBR";
+ Name = "EMBR";
+ Colour = PIXPACK(0xFFF288);
+ MenuVisible = 0;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.001f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.90f;
+ Collision = 0.0f;
+ Gravity = 0.07f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = 500.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Sparks. Formed by explosions.";
+
+ State = ST_NONE;
+ Properties = TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL|PROP_SPARKSETTLE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_EMBR::update;
+ Graphics = &Element_EMBR::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_EMBR static int update(UPDATE_FUNC_ARGS)
+int Element_EMBR::update(UPDATE_FUNC_ARGS) {
+ int r, rx, ry, nb;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((sim->elements[r&0xFF].Properties & (TYPE_SOLID | TYPE_PART | TYPE_LIQUID)) && !(sim->elements[r&0xFF].Properties & PROP_SPARKSETTLE))
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_EMBR static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_EMBR::graphics(GRAPHICS_FUNC_ARGS)
+{
+ if (cpart->ctype&0xFFFFFF)
+ {
+ int maxComponent;
+ *colr = (cpart->ctype&0xFF0000)>>16;
+ *colg = (cpart->ctype&0x00FF00)>>8;
+ *colb = (cpart->ctype&0x0000FF);
+ maxComponent = *colr;
+
+ if (*colg>maxComponent) maxComponent = *colg;
+ if (*colb>maxComponent) maxComponent = *colb;
+ if (maxComponent<60)//make sure it isn't too dark to see
+ {
+ float multiplier = 60.0f/maxComponent;
+ *colr *= multiplier;
+ *colg *= multiplier;
+ *colb *= multiplier;
+ }
+ }
+ else if (cpart->tmp != 0)
+ {
+ *colr = *colg = *colb = 255;
+ }
+
+ if (ren->decorations_enable && cpart->dcolour)
+ {
+ int a = (cpart->dcolour>>24)&0xFF;
+ *colr = (a*((cpart->dcolour>>16)&0xFF) + (255-a)**colr) >> 8;
+ *colg = (a*((cpart->dcolour>>8)&0xFF) + (255-a)**colg) >> 8;
+ *colb = (a*((cpart->dcolour)&0xFF) + (255-a)**colb) >> 8;
+ }
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+ if (cpart->tmp==1)
+ {
+ *pixel_mode = FIRE_ADD | PMODE_BLEND | PMODE_GLOW;
+ *firea = (cpart->life-15)*4;
+ *cola = (cpart->life+15)*4;
+ }
+ else if (cpart->tmp==2)
+ {
+ *pixel_mode = PMODE_FLAT | FIRE_ADD;
+ *firea = 255;
+ }
+ else
+ {
+ *pixel_mode = PMODE_SPARK | PMODE_ADD;
+ if (cpart->life<64) *cola = 4*cpart->life;
+ }
+ return 0;
+}
+
+Element_EMBR::~Element_EMBR() {}
diff --git a/src/simulation/elements/EMP.cpp b/src/simulation/elements/EMP.cpp
new file mode 100644
index 0000000..e21f69c
--- /dev/null
+++ b/src/simulation/elements/EMP.cpp
@@ -0,0 +1,183 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_EMP PT_EMP 134
+Element_EMP::Element_EMP()
+{
+ Identifier = "DEFAULT_PT_EMP";
+ Name = "EMP";
+ Colour = PIXPACK(0x66AAFF);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.0f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 3;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 121;
+ Description = "Breaks activated electronics.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_EMP::update;
+ Graphics = &Element_EMP::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_EMP static int update(UPDATE_FUNC_ARGS)
+int Element_EMP::update(UPDATE_FUNC_ARGS)
+ {
+ int r,rx,ry,ok=0,t,n,nx,ny;
+ if (parts[i].life)
+ return 0;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK && parts[r>>8].life>0 && parts[r>>8].life<4)
+ {
+ ok=1;
+ break;
+ }
+ }
+ if (!ok)
+ return 0;
+ parts[i].life=220;
+ sim->emp_decor += 3;
+ if (sim->emp_decor > 40)
+ sim->emp_decor = 40;
+ for (r=0; r<=sim->parts_lastActiveIndex; r++)
+ {
+ t=parts[r].type;
+ rx=parts[r].x;
+ ry=parts[r].y;
+ if (t==PT_SPRK || (t==PT_SWCH && parts[r].life!=0 && parts[r].life!=10) || (t==PT_WIRE && parts[r].ctype>0))
+ {
+ int is_elec=0;
+ if ((parts[r].ctype==PT_PSCN || parts[r].ctype==PT_NSCN || parts[r].ctype==PT_PTCT ||
+ parts[r].ctype==PT_NTCT || parts[r].ctype==PT_INST || parts[r].ctype==PT_SWCH) || t==PT_WIRE || t==PT_SWCH)
+ {
+ is_elec=1;
+ if (sim->elements[parts[r].type].HeatConduct && rand()%100==0)
+ parts[r].temp = restrict_flt(parts[r].temp+3000.0f, MIN_TEMP, MAX_TEMP);
+ if (rand()%80==0)
+ sim->part_change_type(r, rx, ry, PT_BREC);
+ else if (rand()%120==0)
+ sim->part_change_type(r, rx, ry, PT_NTCT);
+ }
+
+ for (nx=-2; nx<3; nx++)
+ for (ny=-2; ny<3; ny++)
+ if (rx+nx>=0 && ry+ny>=0 && rx+nx<XRES && ry+ny<YRES && (rx || ry))
+ {
+ n = pmap[ry+ny][rx+nx];
+ if (!n)
+ continue;
+ /*if ((n&0xFF)==PT_BTRY && rand()%60==0)
+ {
+ part_change_type(n>>8, rx+nx, ry+ny, PT_PLSM);
+ parts[n>>8].life=rand()%100+70;
+ parts[n>>8].temp+=3000;
+ }*/
+
+ //Some elements should only be affected by wire/swch, or by a spark on inst/semiconductor
+ //So not affected by spark on metl, watr etc
+ if (is_elec)
+ {
+ if (((n&0xFF)==PT_METL || (n&0xFF)==PT_BMTL) && rand()%280==0)
+ {
+ parts[n>>8].temp = restrict_flt(parts[n>>8].temp+3000.0f, MIN_TEMP, MAX_TEMP);
+ }
+ if ((n&0xFF)==PT_BMTL && rand()%160==0)
+ {
+ sim->part_change_type(n>>8, rx+nx, ry+ny, PT_BMTL);//TODO: Redundant, was this meant to be BRMT or something?
+ parts[n>>8].temp = restrict_flt(parts[n>>8].temp+1000.0f, MIN_TEMP, MAX_TEMP);
+ }
+ if ((n&0xFF)==PT_METL && rand()%300==0)
+ {
+ sim->part_change_type(n>>8, rx+nx, ry+ny, PT_BMTL);
+ }
+ if ((n&0xFF)==PT_WIFI && rand()%8==0)
+ {
+ //Randomise channel
+ parts[n>>8].temp = rand()%MAX_TEMP;
+ }
+ if ((n&0xFF)==PT_WIFI && rand()%16==0)
+ {
+ sim->create_part(n>>8, rx+nx, ry+ny, PT_BREC);
+ parts[n>>8].temp = restrict_flt(parts[n>>8].temp+1000.0f, MIN_TEMP, MAX_TEMP);
+ }
+ }
+ if ((n&0xFF)==PT_SWCH && rand()%100==0)
+ {
+ sim->part_change_type(n>>8, rx+nx, ry+ny, PT_BREC);
+ }
+ if ((n&0xFF)==PT_SWCH && rand()%100==0)
+ {
+ parts[n>>8].temp = restrict_flt(parts[n>>8].temp+2000.0f, MIN_TEMP, MAX_TEMP);
+ }
+ if ((n&0xFF)==PT_ARAY && rand()%60==0)
+ {
+ sim->create_part(n>>8, rx+nx, ry+ny, PT_BREC);
+ parts[n>>8].temp = restrict_flt(parts[n>>8].temp+1000.0f, MIN_TEMP, MAX_TEMP);
+ }
+ if (t==PT_DLAY && rand()%70==0)
+ {
+ //Randomise delay
+ parts[n>>8].temp = (rand()%256) + 273.15f;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_EMP static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_EMP::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->life)
+ {
+ *colr = cpart->life*1.5;
+ *colg = cpart->life*1.5;
+ *colb = 200-(cpart->life);
+ if (*colr>255)
+ *colr = 255;
+ if (*colg>255)
+ *colg = 255;
+ if (*colb>255)
+ *colb = 255;
+ if (*colb<=0)
+ *colb = 0;
+ }
+ return 0;
+}
+
+
+Element_EMP::~Element_EMP() {} \ No newline at end of file
diff --git a/src/simulation/elements/ETRD.cpp b/src/simulation/elements/ETRD.cpp
new file mode 100644
index 0000000..3a63f6f
--- /dev/null
+++ b/src/simulation/elements/ETRD.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ETRD PT_ETRD 50
+Element_ETRD::Element_ETRD()
+{
+ Identifier = "DEFAULT_PT_ETRD";
+ Name = "ETRD";
+ Colour = PIXPACK(0x404040);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Electrode. Creates a surface that allows Plasma arcs. (Use sparingly)";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_ETRD::~Element_ETRD() {} \ No newline at end of file
diff --git a/src/simulation/elements/EXOT.cpp b/src/simulation/elements/EXOT.cpp
new file mode 100644
index 0000000..03eca2f
--- /dev/null
+++ b/src/simulation/elements/EXOT.cpp
@@ -0,0 +1,211 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_EXOT PT_EXOT 145
+Element_EXOT::Element_EXOT()
+{
+ Identifier = "DEFAULT_PT_EXOT";
+ Name = "EXOT";
+ Colour = PIXPACK(0x404040);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.3f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.15f;
+ Diffusion = 0.00f;
+ HotAir = 0.0003f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 2;
+
+ Weight = 46;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 250;
+ Description = "Exotic matter. Explodes with excess exposure to electrons.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_EXOT::update;
+ Graphics = &Element_EXOT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_EXOT static int update(UPDATE_FUNC_ARGS)
+int Element_EXOT::update(UPDATE_FUNC_ARGS) {
+ int r, rt, rx, ry, nb, rrx, rry, trade, tym, t;
+ t = parts[i].type;
+ for (rx=-2; rx<=2; rx++)
+ for (ry=-2; ry<=2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES) {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF) == PT_WARP)
+ {
+ if (parts[r>>8].tmp2>2000)
+ if (1>rand()%100)
+ {
+ parts[i].tmp2 += 100;
+ }
+ }
+ else if ((r&0xFF) == PT_EXOT && parts[r>>8].life == 1500 && 1>rand()%1000)
+ parts[i].life = 1500;
+ else if ((r&0xFF) == PT_LAVA)
+ {
+ if (parts[r>>8].ctype == PT_TTAN && 1>rand()%10)
+ {
+ parts[r>>8].ctype = PT_VIBR;
+ sim->kill_part(i);
+ return 1;
+ }
+ /*else if (parts[r>>8].ctype == PT_VIBR && 1>rand()%1000)
+ {
+ sim->kill_part(i);
+ return 1;
+ }*/
+ }
+ if ((parts[i].tmp>245) && (parts[i].life>1000))
+ if ((r&0xFF)!=PT_EXOT && (r&0xFF)!=PT_BREC && (r&0xFF)!=PT_DMND && (r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PRTI && (r&0xFF)!=PT_PRTO && (r&0xFF)!=PT_PCLN && (r&0xFF)!=PT_PHOT && (r&0xFF)!=PT_VOID && (r&0xFF)!=PT_NBHL && (r&0xFF)!=PT_WARP && (r&0xFF)!=PT_NEUT)
+ {
+ sim->create_part(i, x, y, parts[r>>8].type);
+ return 0;
+ }
+ }
+ parts[i].tmp--;
+ parts[i].tmp2--;
+ if (parts[i].tmp<1 || parts[i].tmp>250)
+ parts[i].tmp = 250;
+ if (parts[i].tmp2<1)
+ parts[i].tmp2 = 1;
+ else if (parts[i].tmp2>6000)
+ {
+ parts[i].tmp2 = 10000;
+ if (parts[i].life<1001)
+ {
+ sim->part_change_type(i, x, y, PT_WARP);
+ return 0;
+ }
+ }
+ else if(parts[i].life<1001)
+ sim->pv[y/CELL][x/CELL] += (parts[i].tmp2*CFDS)/160000;
+ if (sim->pv[y/CELL][x/CELL]>200 && parts[i].temp>9000 && parts[i].tmp2>200)
+ {
+ parts[i].tmp2 = 6000;
+ sim->part_change_type(i, x, y, PT_WARP);
+ return 0;
+ }
+ if (parts[i].tmp2>100)
+ {
+ for ( trade = 0; trade<9; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==t && (parts[i].tmp2>parts[r>>8].tmp2) && parts[r>>8].tmp2>=0 )//diffusion
+ {
+ tym = parts[i].tmp2 - parts[r>>8].tmp2;
+ if (tym ==1)
+ {
+ parts[r>>8].tmp2 ++;
+ parts[i].tmp2 --;
+ break;
+ }
+ if (tym>0)
+ {
+ parts[r>>8].tmp2 += tym/2;
+ parts[i].tmp2 -= tym/2;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (parts[i].temp<273.15f)
+ {
+ parts[i].vx = 0;
+ parts[i].vy = 0;
+ sim->pv[y/CELL][x/CELL] -= 0.01;
+ parts[i].tmp--;
+ }
+ return 0;
+
+}
+
+//#TPT-Directive ElementHeader Element_EXOT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_EXOT::graphics(GRAPHICS_FUNC_ARGS)
+{
+ int q = cpart->temp;
+ int b = cpart->tmp;
+ int c = cpart->tmp2;
+ if (cpart->life < 1001)
+ {
+ if ((cpart->tmp2 - 1)>rand()%1000)
+ {
+ float frequency = 0.04045;
+ *colr = (sin(frequency*c + 4) * 127 + 150);
+ *colg = (sin(frequency*c + 6) * 127 + 150);
+ *colb = (sin(frequency*c + 8) * 127 + 150);
+
+ *firea = 100;
+ *firer = 0;
+ *fireg = 0;
+ *fireb = 0;
+
+ *pixel_mode |= PMODE_FLAT;
+ *pixel_mode |= PMODE_FLARE;
+ }
+ else
+ {
+ float frequency = 0.00045;
+ *colr = (sin(frequency*q + 4) * 127 + (b/1.7));
+ *colg = (sin(frequency*q + 6) * 127 + (b/1.7));
+ *colb = (sin(frequency*q + 8) * 127 + (b/1.7));
+ *cola = cpart->tmp / 6;
+
+ *firea = *cola;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+
+ *pixel_mode |= FIRE_ADD;
+ *pixel_mode |= PMODE_BLUR;
+ }
+ }
+ else
+ {
+ float frequency = 0.01300;
+ *colr = (sin(frequency*q + 6.00) * 127 + ((b/2.9) + 80));
+ *colg = (sin(frequency*q + 6.00) * 127 + ((b/2.9) + 80));
+ *colb = (sin(frequency*q + 6.00) * 127 + ((b/2.9) + 80));
+ *cola = cpart->tmp / 6;
+ *firea = *cola;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+ *pixel_mode |= FIRE_ADD;
+ *pixel_mode |= PMODE_BLUR;
+ }
+ return 0;
+}
+
+Element_EXOT::~Element_EXOT() {}
diff --git a/src/simulation/elements/Element.cpp b/src/simulation/elements/Element.cpp
new file mode 100644
index 0000000..9c1002a
--- /dev/null
+++ b/src/simulation/elements/Element.cpp
@@ -0,0 +1,225 @@
+#include "simulation/Elements.h"
+#include "simulation/StructProperty.h"
+
+Element::Element():
+ Identifier("DEFAULT_INVALID"),
+ Name(""),
+ Colour(PIXPACK(0xFF00FF)),
+ MenuVisible(0),
+ MenuSection(0),
+ Enabled(0),
+
+ Advection(0.0f),
+ AirDrag(-0.0f * CFDS),
+ AirLoss(1.0f),
+ Loss(1.0f),
+ Collision(0.0f),
+ Gravity(0.0f),
+ Diffusion(0.0f),
+ HotAir(0.0f * CFDS),
+ Falldown(0),
+
+ Flammable(0),
+ Explosive(0),
+ Meltable(0),
+ Hardness(30),
+
+ Weight(50),
+
+ Temperature(273.15f),
+ HeatConduct(128),
+ Description("No description"),
+
+ State(ST_SOLID),
+ Properties(TYPE_SOLID),
+
+ LowPressure(IPL),
+ LowPressureTransition(NT),
+ HighPressure(IPH),
+ HighPressureTransition(NT),
+ LowTemperature(ITL),
+ LowTemperatureTransition(NT),
+ HighTemperature(ITH),
+ HighTemperatureTransition(NT),
+
+ Update(NULL),
+ Graphics(&Element::defaultGraphics),
+ IconGenerator(NULL)
+{
+}
+
+std::vector<StructProperty> Element::GetProperties()
+{
+ std::vector<StructProperty> properties;
+ properties.push_back(StructProperty("Name", StructProperty::String, offsetof(Element, Name)));
+ properties.push_back(StructProperty("Colour", StructProperty::Colour, offsetof(Element, Colour)));
+ properties.push_back(StructProperty("MenuVisible", StructProperty::Integer, offsetof(Element, MenuVisible)));
+ properties.push_back(StructProperty("MenuSection", StructProperty::Integer, offsetof(Element, MenuSection)));
+ properties.push_back(StructProperty("Advection", StructProperty::Float, offsetof(Element, Advection)));
+ properties.push_back(StructProperty("AirDrag", StructProperty::Float, offsetof(Element, AirDrag)));
+ properties.push_back(StructProperty("AirLoss", StructProperty::Float, offsetof(Element, AirLoss)));
+ properties.push_back(StructProperty("Loss", StructProperty::Float, offsetof(Element, Loss)));
+ properties.push_back(StructProperty("Collision", StructProperty::Float, offsetof(Element, Collision)));
+ properties.push_back(StructProperty("Gravity", StructProperty::Float, offsetof(Element, Gravity)));
+ properties.push_back(StructProperty("Diffusion", StructProperty::Float, offsetof(Element, Diffusion)));
+ properties.push_back(StructProperty("HotAir", StructProperty::Float, offsetof(Element, HotAir)));
+ properties.push_back(StructProperty("Falldown", StructProperty::Integer, offsetof(Element, Falldown)));
+ properties.push_back(StructProperty("Flammable", StructProperty::Integer, offsetof(Element, Flammable)));
+ properties.push_back(StructProperty("Explosive", StructProperty::Integer, offsetof(Element, Explosive)));
+ properties.push_back(StructProperty("Meltable", StructProperty::Integer, offsetof(Element, Meltable)));
+ properties.push_back(StructProperty("Hardness", StructProperty::Integer, offsetof(Element, Hardness)));
+ properties.push_back(StructProperty("Weight", StructProperty::Integer, offsetof(Element, Weight)));
+ properties.push_back(StructProperty("Temperature", StructProperty::Float, offsetof(Element, Temperature)));
+ properties.push_back(StructProperty("HeatConduct", StructProperty::UChar, offsetof(Element, HeatConduct)));
+ properties.push_back(StructProperty("Description", StructProperty::String, offsetof(Element, Description)));
+ properties.push_back(StructProperty("State", StructProperty::Char, offsetof(Element, State)));
+ properties.push_back(StructProperty("Properties", StructProperty::Integer, offsetof(Element, Properties)));
+ properties.push_back(StructProperty("LowPressure", StructProperty::Float, offsetof(Element, LowPressure)));
+ properties.push_back(StructProperty("LowPressureTransition", StructProperty::Integer, offsetof(Element, LowPressureTransition)));
+ properties.push_back(StructProperty("HighPressure", StructProperty::Float, offsetof(Element, HighPressure)));
+ properties.push_back(StructProperty("HighPressureTransition", StructProperty::Integer, offsetof(Element, HighPressureTransition)));
+ properties.push_back(StructProperty("LowTemperature", StructProperty::Float, offsetof(Element, LowTemperature)));
+ properties.push_back(StructProperty("LowTemperatureTransition", StructProperty::Integer, offsetof(Element, LowTemperatureTransition)));
+ properties.push_back(StructProperty("HighTemperature", StructProperty::Float, offsetof(Element, HighTemperature)));
+ properties.push_back(StructProperty("HighTemperatureTransition", StructProperty::Integer, offsetof(Element, HighTemperatureTransition)));
+ return properties;
+}
+
+int Element::legacyUpdate(UPDATE_FUNC_ARGS) {
+ int r, rx, ry, rt;
+ int t = parts[i].type;
+ if (t==PT_WTRV) {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 &&
+ x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_WATR||(r&0xFF)==PT_DSTW||(r&0xFF)==PT_SLTW) && 1>(rand()%1000))
+ {
+ sim->part_change_type(i,x,y,PT_WATR);
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_WATR);
+ }
+ if (((r&0xFF)==PT_ICEI || (r&0xFF)==PT_SNOW) && 1>(rand()%1000))
+ {
+ sim->part_change_type(i,x,y,PT_WATR);
+ if (1>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_WATR);
+ }
+ }
+ }
+ else if (t==PT_WATR) {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 &&
+ x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_FIRE || (r&0xFF)==PT_LAVA) && 1>(rand()%10))
+ {
+ sim->part_change_type(i,x,y,PT_WTRV);
+ }
+ }
+ }
+ else if (t==PT_SLTW) {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 &&
+ x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_FIRE || (r&0xFF)==PT_LAVA) && 1>(rand()%10))
+ {
+ if (rand()%4==0) sim->part_change_type(i,x,y,PT_SALT);
+ else sim->part_change_type(i,x,y,PT_WTRV);
+ }
+ }
+ }
+ else if (t==PT_DSTW) {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 &&
+ x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_FIRE || (r&0xFF)==PT_LAVA) && 1>(rand()%10))
+ {
+ sim->part_change_type(i,x,y,PT_WTRV);
+ }
+ }
+ }
+ else if (t==PT_ICEI) {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW) && 1>(rand()%1000))
+ {
+ sim->part_change_type(i,x,y,PT_ICEI);
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_ICEI);
+ }
+ }
+ }
+ else if (t==PT_SNOW) {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW) && 1>(rand()%1000))
+ {
+ sim->part_change_type(i,x,y,PT_ICEI);
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_ICEI);
+ }
+ if (((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW) && 15>(rand()%1000))
+ sim->part_change_type(i,x,y,PT_WATR);
+ }
+ }
+ if (t==PT_WTRV && sim->pv[y/CELL][x/CELL]>4.0f)
+ sim->part_change_type(i,x,y,PT_DSTW);
+ if (t==PT_OIL && sim->pv[y/CELL][x/CELL]<-6.0f)
+ sim->part_change_type(i,x,y,PT_GAS);
+ if (t==PT_GAS && sim->pv[y/CELL][x/CELL]>6.0f)
+ sim->part_change_type(i,x,y,PT_OIL);
+ if (t==PT_DESL && sim->pv[y/CELL][x/CELL]>12.0f)
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = rand()%50+120;
+ }
+ return 0;
+}
+
+int Element::defaultGraphics(GRAPHICS_FUNC_ARGS)
+{
+ int t = cpart->type;
+ //Property based defaults
+ if(ren->sim->elements[t].Properties & PROP_RADIOACTIVE) *pixel_mode |= PMODE_GLOW;
+ if(ren->sim->elements[t].Properties & TYPE_LIQUID)
+ {
+ *pixel_mode |= PMODE_BLUR;
+ }
+ if(ren->sim->elements[t].Properties & TYPE_GAS)
+ {
+ *pixel_mode &= ~PMODE;
+ *pixel_mode |= FIRE_BLEND;
+ *firer = *colr/2;
+ *fireg = *colg/2;
+ *fireb = *colb/2;
+ *firea = 125;
+ *pixel_mode |= DECO_FIRE;
+ }
+ return 1;
+}
diff --git a/src/simulation/elements/Element.h b/src/simulation/elements/Element.h
new file mode 100644
index 0000000..b51bddc
--- /dev/null
+++ b/src/simulation/elements/Element.h
@@ -0,0 +1,63 @@
+#ifndef ELEMENTCLASS_H
+#define ELEMENTCLASS_H
+
+#include "simulation/Simulation.h"
+#include "graphics/Renderer.h"
+#include "simulation/Elements.h"
+#include "simulation/StructProperty.h"
+
+class Simulation;
+class Renderer;
+struct Particle;
+class Element
+{
+public:
+ char *Identifier;
+ char *Name;
+ pixel Colour;
+ float Advection;
+ float AirDrag;
+ float AirLoss;
+ float Loss;
+ float Collision;
+ float Gravity;
+ float Diffusion;
+ float HotAir;
+ int Falldown;
+ int Flammable;
+ int Explosive;
+ int Meltable;
+ int Hardness;
+ int MenuVisible;
+ int Enabled;
+ int Weight;
+ int MenuSection;
+ float Temperature;
+ unsigned char HeatConduct;
+ char *Description;
+ char State;
+ unsigned int Properties;
+ int (*Update) (UPDATE_FUNC_ARGS);
+ int (*Graphics) (GRAPHICS_FUNC_ARGS);
+ VideoBuffer * (*IconGenerator)(int, int, int);
+
+ float HighPressure;
+ int HighPressureTransition;
+ float LowPressure;
+ int LowPressureTransition;
+ float HighTemperature;
+ int HighTemperatureTransition;
+ float LowTemperature;
+ int LowTemperatureTransition;
+
+ Element();
+ virtual ~Element() {}
+ static int defaultGraphics(GRAPHICS_FUNC_ARGS);
+ static int legacyUpdate(UPDATE_FUNC_ARGS);
+
+ /** Returns a list of properties, their type and offset within the structure that can be changed
+ by higher-level processes refering to them by name such as Lua or the property tool **/
+ static std::vector<StructProperty> GetProperties();
+};
+
+#endif
diff --git a/src/simulation/elements/FIGH.cpp b/src/simulation/elements/FIGH.cpp
new file mode 100644
index 0000000..66be5bd
--- /dev/null
+++ b/src/simulation/elements/FIGH.cpp
@@ -0,0 +1,140 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FIGH PT_FIGH 158
+Element_FIGH::Element_FIGH()
+{
+ Identifier = "DEFAULT_PT_FIGH";
+ Name = "FIGH";
+ Colour = PIXPACK(0xFFE0A0);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.5f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.2f;
+ Loss = 1.0f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.00f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 50;
+
+ Temperature = R_TEMP+14.6f+273.15f;
+ HeatConduct = 0;
+ Description = "Fighter. Tries to kill stickmen.";
+
+ State = ST_NONE;
+ Properties = 0;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 620.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_FIGH::update;
+ Graphics = &Element_STKM::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_FIGH static int update(UPDATE_FUNC_ARGS)
+int Element_FIGH::update(UPDATE_FUNC_ARGS)
+
+{
+ playerst* figh = &sim->fighters[(unsigned char)parts[i].tmp];
+
+ unsigned int tarx, tary;
+
+ parts[i].tmp2 = 0; //0 - stay in place, 1 - seek a stick man
+
+ //Set target cords
+ if (sim->player.spwn && sim->player2.spwn)
+ {
+ if ((pow((float)sim->player.legs[2]-x, 2) + pow((float)sim->player.legs[3]-y, 2))<=
+ (pow((float)sim->player2.legs[2]-x, 2) + pow((float)sim->player2.legs[3]-y, 2)))
+ {
+ tarx = (unsigned int)sim->player.legs[2];
+ tary = (unsigned int)sim->player.legs[3];
+ }
+ else
+ {
+ tarx = (unsigned int)sim->player2.legs[2];
+ tary = (unsigned int)sim->player2.legs[3];
+ }
+ parts[i].tmp2 = 1;
+ }
+ else
+ {
+ if (sim->player.spwn)
+ {
+ tarx = (unsigned int)sim->player.legs[2];
+ tary = (unsigned int)sim->player.legs[3];
+ parts[i].tmp2 = 1;
+ }
+ if (sim->player2.spwn)
+ {
+ tarx = (unsigned int)sim->player2.legs[2];
+ tary = (unsigned int)sim->player2.legs[3];
+ parts[i].tmp2 = 1;
+ }
+ }
+
+ switch (parts[i].tmp2)
+ {
+ case 1:
+ if ((pow(float(tarx-x), 2) + pow(float(tary-y), 2))<600)
+ {
+ if (figh->elem == PT_LIGH || figh->elem == PT_NEUT
+ || sim->elements[figh->elem].Properties&(PROP_DEADLY|PROP_RADIOACTIVE)
+ || sim->elements[figh->elem].Temperature>=323 || sim->elements[figh->elem].Temperature<=243)
+ figh->comm = (int)figh->comm | 0x08;
+ }
+ else
+ if (tarx<x)
+ {
+ if(!(sim->eval_move(PT_FIGH, figh->legs[4]-10, figh->legs[5]+6, NULL)
+ && sim->eval_move(PT_FIGH, figh->legs[4]-10, figh->legs[5]+3, NULL)))
+ figh->comm = 0x01;
+ else
+ figh->comm = 0x02;
+
+ if (!sim->eval_move(PT_FIGH, figh->legs[4]-4, figh->legs[5]-1, NULL)
+ || !sim->eval_move(PT_FIGH, figh->legs[12]-4, figh->legs[13]-1, NULL)
+ || sim->eval_move(PT_FIGH, 2*figh->legs[4]-figh->legs[6], figh->legs[5]+5, NULL))
+ figh->comm = (int)figh->comm | 0x04;
+ }
+ else
+ {
+ if (!(sim->eval_move(PT_FIGH, figh->legs[12]+10, figh->legs[13]+6, NULL)
+ && sim->eval_move(PT_FIGH, figh->legs[12]+10, figh->legs[13]+3, NULL)))
+ figh->comm = 0x02;
+ else
+ figh->comm = 0x01;
+
+ if (!sim->eval_move(PT_FIGH, figh->legs[4]+4, figh->legs[5]-1, NULL)
+ || !sim->eval_move(PT_FIGH, figh->legs[4]+4, figh->legs[5]-1, NULL)
+ || sim->eval_move(PT_FIGH, 2*figh->legs[12]-figh->legs[14], figh->legs[13]+5, NULL))
+ figh->comm = (int)figh->comm | 0x04;
+ }
+ break;
+ default:
+ figh->comm = 0;
+ break;
+ }
+
+ figh->pcomm = figh->comm;
+
+ Element_STKM::run_stickman(figh, UPDATE_FUNC_SUBCALL_ARGS);
+ return 0;
+}
+
+Element_FIGH::~Element_FIGH() {} \ No newline at end of file
diff --git a/src/simulation/elements/FILT.cpp b/src/simulation/elements/FILT.cpp
new file mode 100644
index 0000000..58501c2
--- /dev/null
+++ b/src/simulation/elements/FILT.cpp
@@ -0,0 +1,77 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FILT PT_FILT 125
+Element_FILT::Element_FILT()
+{
+ Identifier = "DEFAULT_PT_FILT";
+ Name = "FILT";
+ Colour = PIXPACK(0x000056);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Filter for photons, changes the color.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NOAMBHEAT;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+ Graphics = &Element_FILT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_FILT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_FILT::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int x, temp_bin = (int)((cpart->temp-273.0f)*0.025f);
+ if (temp_bin < 0) temp_bin = 0;
+ if (temp_bin > 25) temp_bin = 25;
+ cpart->ctype = 0x1F << temp_bin;
+ *colg = 0;
+ *colb = 0;
+ *colr = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *cola = 127;
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+ *pixel_mode &= ~PMODE;
+ *pixel_mode |= PMODE_BLEND;
+ return 0;
+}
+
+
+Element_FILT::~Element_FILT() {}
diff --git a/src/simulation/elements/FIRE.cpp b/src/simulation/elements/FIRE.cpp
new file mode 100644
index 0000000..f9313fa
--- /dev/null
+++ b/src/simulation/elements/FIRE.cpp
@@ -0,0 +1,201 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FIRE PT_FIRE 4
+Element_FIRE::Element_FIRE()
+{
+ Identifier = "DEFAULT_PT_FIRE";
+ Name = "FIRE";
+ Colour = PIXPACK(0xFF1000);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.9f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.20f;
+ Collision = 0.0f;
+ Gravity = -0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.001f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 2;
+
+ Temperature = R_TEMP+400.0f+273.15f;
+ HeatConduct = 88;
+ Description = "Ignites flammable materials. Heats air.";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS|PROP_LIFE_DEC|PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 2773.0f;
+ HighTemperatureTransition = PT_PLSM;
+
+ Update = &Element_FIRE::update;
+ Graphics = &Element_FIRE::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_FIRE static int update(UPDATE_FUNC_ARGS)
+int Element_FIRE::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt, t = parts[i].type;
+ if (t==PT_PLSM&&parts[i].ctype == PT_NBLE&&parts[i].life <=1)
+ {
+ t = PT_NBLE;
+ sim->part_change_type(i,x,y,t);
+ parts[i].life = 0;
+ }
+ if(t==PT_FIRE && parts[i].life <=1)
+ {
+ if ((parts[i].tmp&0x3) == 3){
+ t = PT_DSTW;
+ sim->part_change_type(i,x,y,t);
+ parts[i].life = 0;
+ parts[i].ctype = PT_FIRE;
+ }
+ else if (parts[i].temp<625)
+ {
+ t = PT_SMKE;
+ sim->part_change_type(i,x,y,t);
+ parts[i].life = rand()%20+250;
+ }
+ }
+ if(t==PT_PLSM && parts[i].life <=1)
+ {
+ if ((parts[i].tmp&0x3) == 3){
+ t = PT_DSTW;
+ sim->part_change_type(i,x,y,t);
+ parts[i].life = 0;
+ parts[i].ctype = PT_FIRE;
+ }
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (sim->bmap[(y+ry)/CELL][(x+rx)/CELL] && sim->bmap[(y+ry)/CELL][(x+rx)/CELL]!=WL_STREAM)
+ continue;
+ rt = parts[r>>8].type;
+ if ((surround_space || sim->elements[rt].Explosive) &&
+ (t!=PT_SPRK || (rt!=PT_RBDM && rt!=PT_LRBD && rt!=PT_INSL)) &&
+ (t!=PT_PHOT || rt!=PT_INSL) &&
+ (rt!=PT_SPNG || parts[r>>8].life==0) &&
+ sim->elements[rt].Flammable && (sim->elements[rt].Flammable + (int)(sim->pv[(y+ry)/CELL][(x+rx)/CELL]*10.0f))>(rand()%1000))
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_FIRE);
+ parts[r>>8].temp = restrict_flt(sim->elements[PT_FIRE].Temperature + (sim->elements[rt].Flammable/2), MIN_TEMP, MAX_TEMP);
+ parts[r>>8].life = rand()%80+180;
+ parts[r>>8].tmp = parts[r>>8].ctype = 0;
+ if (sim->elements[rt].Explosive)
+ sim->pv[y/CELL][x/CELL] += 0.25f * CFDS;
+ }
+ }
+ if (sim->legacy_enable) updateLegacy(UPDATE_FUNC_SUBCALL_ARGS);
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_FIRE static int updateLegacy(UPDATE_FUNC_ARGS)
+int Element_FIRE::updateLegacy(UPDATE_FUNC_ARGS) {
+ int r, rx, ry, rt, lpv, t = parts[i].type;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (sim->bmap[(y+ry)/CELL][(x+rx)/CELL] && sim->bmap[(y+ry)/CELL][(x+rx)/CELL]!=WL_STREAM)
+ continue;
+ rt = r&0xFF;
+ lpv = (int)sim->pv[(y+ry)/CELL][(x+rx)/CELL];
+ if (lpv < 1) lpv = 1;
+ if (t!=PT_SPRK && sim->elements[rt].Meltable && ((rt!=PT_RBDM && rt!=PT_LRBD) || t!=PT_SPRK) && ((t!=PT_FIRE&&t!=PT_PLSM) || (rt!=PT_METL && rt!=PT_IRON && rt!=PT_ETRD && rt!=PT_PSCN && rt!=PT_NSCN && rt!=PT_NTCT && rt!=PT_PTCT && rt!=PT_BMTL && rt!=PT_BRMT && rt!=PT_SALT && rt!=PT_INWR)) &&
+ sim->elements[rt].Meltable*lpv>(rand()%1000))
+ {
+ if (t!=PT_LAVA || parts[i].life>0)
+ {
+ parts[r>>8].ctype = (rt==PT_BRMT)?PT_BMTL:parts[r>>8].type;
+ parts[r>>8].ctype = (parts[r>>8].ctype==PT_SAND)?PT_GLAS:parts[r>>8].ctype;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_LAVA);
+ parts[r>>8].life = rand()%120+240;
+ }
+ else
+ {
+ parts[i].life = 0;
+ t = parts[i].type = (parts[i].ctype)?parts[i].ctype:PT_STNE;
+ parts[i].ctype = PT_NONE;//rt;
+ sim->part_change_type(i,x,y,t);
+ return 1;
+ }
+ }
+ if (t!=PT_SPRK && (rt==PT_ICEI || rt==PT_SNOW))
+ {
+ parts[r>>8].type = PT_WATR;
+ if (t==PT_FIRE)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ if (t==PT_LAVA)
+ {
+ parts[i].life = 0;
+ t = parts[i].type = PT_STNE;
+ sim->part_change_type(i,x,y,t);
+ }
+ }
+ if (t!=PT_SPRK && (rt==PT_WATR || rt==PT_DSTW || rt==PT_SLTW))
+ {
+ sim->kill_part(r>>8);
+ if (t==PT_FIRE)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ if (t==PT_LAVA)
+ {
+ parts[i].life = 0;
+ t = parts[i].type = (parts[i].ctype)?parts[i].ctype:PT_STNE;
+ parts[i].ctype = PT_NONE;
+ sim->part_change_type(i,x,y,t);
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_FIRE static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_FIRE::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int caddress = restrict_flt(restrict_flt((float)cpart->life, 0.0f, 200.0f)*3, 0.0f, (200.0f*3)-3);
+ *colr = (unsigned char)ren->flm_data[caddress];
+ *colg = (unsigned char)ren->flm_data[caddress+1];
+ *colb = (unsigned char)ren->flm_data[caddress+2];
+
+ *firea = 255;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+
+ *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel
+ *pixel_mode |= FIRE_ADD;
+ //Returning 0 means dynamic, do not cache
+ return 0;
+}
+
+Element_FIRE::~Element_FIRE() {} \ No newline at end of file
diff --git a/src/simulation/elements/FIRW.cpp b/src/simulation/elements/FIRW.cpp
new file mode 100644
index 0000000..bc047df
--- /dev/null
+++ b/src/simulation/elements/FIRW.cpp
@@ -0,0 +1,134 @@
+#include "simulation/Elements.h"
+extern "C"
+{
+ #include "hmap.h"
+}
+//#TPT-Directive ElementClass Element_FIRW PT_FIRW 69
+Element_FIRW::Element_FIRW()
+{
+ Identifier = "DEFAULT_PT_FIRW";
+ Name = "FIRW";
+ Colour = PIXPACK(0xFFA040);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.2f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 55;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Fireworks!";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FIRW::update;
+ Graphics = &Element_FIRW::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_FIRW static int update(UPDATE_FUNC_ARGS)
+int Element_FIRW::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt, np;
+ if (parts[i].tmp<=0) {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ if (rt==PT_FIRE||rt==PT_PLSM||rt==PT_THDR)
+ {
+ float gx, gy, multiplier;
+ sim->GetGravityField(x, y, sim->elements[PT_FIRW].Gravity, 1.0f, gx, gy);
+ if (gx*gx+gy*gy < 0.001f)
+ {
+ float angle = (rand()%6284)*0.001f;//(in radians, between 0 and 2*pi)
+ gx += sinf(angle)*sim->elements[PT_FIRW].Gravity*0.5f;
+ gy += cosf(angle)*sim->elements[PT_FIRW].Gravity*0.5f;
+ }
+ parts[i].tmp = 1;
+ parts[i].life = rand()%10+20;
+ multiplier = (parts[i].life+20)*0.2f/sqrtf(gx*gx+gy*gy);
+ parts[i].vx -= gx*multiplier;
+ parts[i].vy -= gy*multiplier;
+ return 0;
+ }
+ }
+ }
+ else if (parts[i].tmp==1) {
+ if (parts[i].life<=0) {
+ parts[i].tmp=2;
+ } else {
+ parts[i].flags &= ~FLAG_STAGNANT;
+ }
+ }
+ else if (parts[i].tmp>=2)
+ {
+ float angle, magnitude;
+ int caddress = (rand()%200)*3;
+ int n;
+ unsigned col = (((unsigned char)(firw_data[caddress]))<<16) | (((unsigned char)(firw_data[caddress+1]))<<8) | ((unsigned char)(firw_data[caddress+2]));
+ for (n=0; n<40; n++)
+ {
+ np = sim->create_part(-3, x, y, PT_EMBR);
+ if (np>-1)
+ {
+ magnitude = ((rand()%60)+40)*0.05f;
+ angle = (rand()%6284)*0.001f;//(in radians, between 0 and 2*pi)
+ parts[np].vx = parts[i].vx*0.5f + cosf(angle)*magnitude;
+ parts[np].vy = parts[i].vy*0.5f + sinf(angle)*magnitude;
+ parts[np].ctype = col;
+ parts[np].tmp = 1;
+ parts[np].life = rand()%40+70;
+ parts[np].temp = (rand()%500)+5750.0f;
+ parts[np].dcolour = parts[i].dcolour;
+ }
+ }
+ sim->pv[y/CELL][x/CELL] += 8.0f;
+ sim->kill_part(i);
+ return 1;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_FIRW static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_FIRW::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->tmp > 0)
+ {
+ *pixel_mode |= PMODE_GLOW;
+ }
+ return 0;
+}
+
+
+Element_FIRW::~Element_FIRW() {} \ No newline at end of file
diff --git a/src/simulation/elements/FOG.cpp b/src/simulation/elements/FOG.cpp
new file mode 100644
index 0000000..9cfbe62
--- /dev/null
+++ b/src/simulation/elements/FOG.cpp
@@ -0,0 +1,73 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FOG PT_FOG 92
+Element_FOG::Element_FOG()
+{
+ Identifier = "DEFAULT_PT_FOG";
+ Name = "FOG";
+ Colour = PIXPACK(0xAAAAAA);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.8f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.4f;
+ Loss = 0.70f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 0.99f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 1;
+
+ Temperature = 243.15f;
+ HeatConduct = 100;
+ Description = "Not quite Steam";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 373.15f;
+ HighTemperatureTransition = PT_WTRV;
+
+ Update = &Element_FOG::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FOG static int update(UPDATE_FUNC_ARGS)
+int Element_FOG::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (sim->elements[r&0xFF].State==ST_SOLID&&5>=rand()%50&&parts[i].life==0&&!((r&0xFF)==PT_CLNE||(r&0xFF)==PT_PCLN)) // TODO: should this also exclude BCLN?
+ {
+ sim->part_change_type(i,x,y,PT_RIME);
+ }
+ if ((r&0xFF)==PT_SPRK)
+ {
+ parts[i].life += rand()%20;
+ }
+ }
+ return 0;
+}
+
+
+Element_FOG::~Element_FOG() {} \ No newline at end of file
diff --git a/src/simulation/elements/FRAY.cpp b/src/simulation/elements/FRAY.cpp
new file mode 100644
index 0000000..57e2b22
--- /dev/null
+++ b/src/simulation/elements/FRAY.cpp
@@ -0,0 +1,80 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FRAY PT_FRAY 159
+Element_FRAY::Element_FRAY()
+{
+ Identifier = "DEFAULT_PT_FRAY";
+ Name = "FRAY";
+ Colour = PIXPACK(0x00BBFF);
+ MenuVisible = 1;
+ MenuSection = SC_FORCE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = 20.0f+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Force Emitter. Push or pull objects based on temp value, use like ARAY";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FRAY::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FRAY static int update(UPDATE_FUNC_ARGS)
+int Element_FRAY::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nxx, nyy, docontinue, len, nxi, nyi, rx, ry, nr, ry1, rx1;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK) {
+ for (docontinue = 1, nxx = 0, nyy = 0, nxi = rx*-1, nyi = ry*-1, len = 0; docontinue; nyy+=nyi, nxx+=nxi, len++) {
+ if (!(x+nxi+nxx<XRES && y+nyi+nyy<YRES && x+nxi+nxx >= 0 && y+nyi+nyy >= 0) || len>10) {
+ break;
+ }
+ r = pmap[y+nyi+nyy][x+nxi+nxx];
+ if (!r)
+ r = sim->photons[y+nyi+nyy][x+nxi+nxx];
+
+ if (r && !(sim->elements[r&0xFF].Properties & TYPE_SOLID)){
+ parts[r>>8].vx += nxi*((parts[i].temp-273.15)/10.0f);
+ parts[r>>8].vy += nyi*((parts[i].temp-273.15)/10.0f);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_FRAY::~Element_FRAY() {} \ No newline at end of file
diff --git a/src/simulation/elements/FRZW.cpp b/src/simulation/elements/FRZW.cpp
new file mode 100644
index 0000000..5bdbb21
--- /dev/null
+++ b/src/simulation/elements/FRZW.cpp
@@ -0,0 +1,81 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FRZW PT_FRZW 101
+Element_FRZW::Element_FRZW()
+{
+ Identifier = "DEFAULT_PT_FRZW";
+ Name = "FRZW";
+ Colour = PIXPACK(0x1020C0);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = 120.0f;
+ HeatConduct = 29;
+ Description = "Freeze water. Hybrid liquid formed when Freeze powder melts.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID||PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 53.0f;
+ HighTemperatureTransition = PT_ICEI;
+
+ Update = &Element_FRZW::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FRZW static int update(UPDATE_FUNC_ARGS)
+int Element_FRZW::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR&&5>rand()%70)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_FRZW);
+ }
+ }
+ if (parts[i].life==0&&13>rand()%2500)
+ {
+ sim->part_change_type(i,x,y,PT_ICEI);
+ parts[i].ctype=PT_FRZW;
+ parts[i].temp = restrict_flt(parts[i].temp-200.0f, MIN_TEMP, MAX_TEMP);
+ }
+ else if ((100-(parts[i].life))>rand()%50000)
+ {
+ sim->part_change_type(i,x,y,PT_ICEI);
+ parts[i].ctype=PT_FRZW;
+ parts[i].temp = restrict_flt(parts[i].temp-200.0f, MIN_TEMP, MAX_TEMP);
+ }
+ return 0;
+}
+
+
+Element_FRZW::~Element_FRZW() {} \ No newline at end of file
diff --git a/src/simulation/elements/FRZZ.cpp b/src/simulation/elements/FRZZ.cpp
new file mode 100644
index 0000000..47a5c0f
--- /dev/null
+++ b/src/simulation/elements/FRZZ.cpp
@@ -0,0 +1,76 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FRZZ PT_FRZZ 100
+Element_FRZZ::Element_FRZZ()
+{
+ Identifier = "DEFAULT_PT_FRZZ";
+ Name = "FRZZ";
+ Colour = PIXPACK(0xC0E0FF);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.90f;
+ Collision = -0.1f;
+ Gravity = 0.05f;
+ Diffusion = 0.01f;
+ HotAir = -0.00005f* CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 50;
+
+ Temperature = 253.15f;
+ HeatConduct = 46;
+ Description = "Freeze powder. When melted, forms ice that always cools. Spreads with regular water.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 1.8f;
+ HighPressureTransition = PT_SNOW;
+ LowTemperature = 50.0f;
+ LowTemperatureTransition = PT_ICEI;
+ HighTemperature = 273.15;
+ HighTemperatureTransition = PT_WATR;
+
+ Update = &Element_FRZZ::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FRZZ static int update(UPDATE_FUNC_ARGS)
+int Element_FRZZ::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR&&5>rand()%100)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_FRZW);
+ parts[r>>8].life = 100;
+ parts[i].type = PT_NONE;
+ }
+
+ }
+ if (parts[i].type==PT_NONE) {
+ sim->kill_part(i);
+ return 1;
+ }
+ return 0;
+}
+
+
+Element_FRZZ::~Element_FRZZ() {} \ No newline at end of file
diff --git a/src/simulation/elements/FSEP.cpp b/src/simulation/elements/FSEP.cpp
new file mode 100644
index 0000000..52e4a67
--- /dev/null
+++ b/src/simulation/elements/FSEP.cpp
@@ -0,0 +1,86 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FSEP PT_FSEP 71
+Element_FSEP::Element_FSEP()
+{
+ Identifier = "DEFAULT_PT_FSEP";
+ Name = "FSEP";
+ Colour = PIXPACK(0x63AD5F);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 70;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Fuse Powder. See FUSE.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FSEP::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FSEP static int update(UPDATE_FUNC_ARGS)
+int Element_FSEP::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life<=0) {
+ r = sim->create_part(i, x, y, PT_PLSM);
+ if (r!=-1)
+ parts[r].life = 50;
+ return 1;
+ } else if (parts[i].life < 40) {
+ parts[i].life--;
+ if ((rand()%10)==0) {
+ r = sim->create_part(-1, (rx=x+rand()%3-1), (ry=y+rand()%3-1), PT_PLSM);
+ if (r!=-1)
+ parts[r].life = 50;
+ }
+ }
+ else {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_SPRK || (parts[i].temp>=(273.15+400.0f))) && 1>(rand()%15))
+ {
+ if (parts[i].life>40) {
+ parts[i].life = 39;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_FSEP::~Element_FSEP() {} \ No newline at end of file
diff --git a/src/simulation/elements/FUSE.cpp b/src/simulation/elements/FUSE.cpp
new file mode 100644
index 0000000..946e86b
--- /dev/null
+++ b/src/simulation/elements/FUSE.cpp
@@ -0,0 +1,92 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FUSE PT_FUSE 70
+Element_FUSE::Element_FUSE()
+{
+ Identifier = "DEFAULT_PT_FUSE";
+ Name = "FUSE";
+ Colour = PIXPACK(0x0A5706);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.0f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 200;
+ Description = "Solid. Burns slowly. Ignites at somewhat high temperatures and electricity.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FUSE::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FUSE static int update(UPDATE_FUNC_ARGS)
+int Element_FUSE::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life<=0) {
+ r = sim->create_part(i, x, y, PT_PLSM);
+ if (r!=-1)
+ parts[r].life = 50;
+ return 1;
+ } else if (parts[i].life < 40) {
+ parts[i].life--;
+ if ((rand()%100)==0) {
+ r = sim->create_part(-1, (rx=x+rand()%3-1), (ry=y+rand()%3-1), PT_PLSM);
+ if (r!=-1)
+ parts[r].life = 50;
+ }
+ }
+ if ((sim->pv[y/CELL][x/CELL] > 2.7f)&&parts[i].tmp>40)
+ parts[i].tmp=39;
+ else if (parts[i].tmp<40&&parts[i].tmp>0)
+ parts[i].tmp--;
+ else if (parts[i].tmp<=0) {
+ sim->create_part(i, x, y, PT_FSEP);
+ return 1;
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK || ((parts[i].temp>=(273.15+700.0f)) && 1>(rand()%20)))
+ {
+ if (parts[i].life>40) {
+ parts[i].life = 39;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_FUSE::~Element_FUSE() {} \ No newline at end of file
diff --git a/src/simulation/elements/FWRK.cpp b/src/simulation/elements/FWRK.cpp
new file mode 100644
index 0000000..f05db69
--- /dev/null
+++ b/src/simulation/elements/FWRK.cpp
@@ -0,0 +1,120 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_FWRK PT_FWRK 98
+Element_FWRK::Element_FWRK()
+{
+ Identifier = "DEFAULT_PT_FWRK";
+ Name = "FWRK";
+ Colour = PIXPACK(0x666666);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.4f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 97;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 100;
+ Description = "First fireworks made, activated by heat/neutrons.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FWRK::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_FWRK static int update(UPDATE_FUNC_ARGS)
+int Element_FWRK::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, np;
+ if (parts[i].life==0 && ((parts[i].temp>400&&(9+parts[i].temp/40)>rand()%100000&&surround_space)||parts[i].ctype==PT_DUST))
+ {
+ float gx, gy, multiplier, gmax;
+ int randTmp;
+ sim->GetGravityField(x, y, sim->elements[PT_FWRK].Gravity, 1.0f, gx, gy);
+ if (gx*gx+gy*gy < 0.001f)
+ {
+ float angle = (rand()%6284)*0.001f;//(in radians, between 0 and 2*pi)
+ gx += sinf(angle)*sim->elements[PT_FWRK].Gravity*0.5f;
+ gy += cosf(angle)*sim->elements[PT_FWRK].Gravity*0.5f;
+ }
+ gmax = std::max(fabsf(gx), fabsf(gy));
+ if (sim->eval_move(PT_FWRK, (int)(x-(gx/gmax)+0.5f), (int)(y-(gy/gmax)+0.5f), NULL))
+ {
+ multiplier = 15.0f/sqrtf(gx*gx+gy*gy);
+
+ //Some variation in speed parallel to gravity direction
+ randTmp = (rand()%200)-100;
+ gx += gx*randTmp*0.002f;
+ gy += gy*randTmp*0.002f;
+ //and a bit more variation in speed perpendicular to gravity direction
+ randTmp = (rand()%200)-100;
+ gx += -gy*randTmp*0.005f;
+ gy += gx*randTmp*0.005f;
+
+ parts[i].life=rand()%10+18;
+ parts[i].ctype=0;
+ parts[i].vx -= gx*multiplier;
+ parts[i].vy -= gy*multiplier;
+ parts[i].dcolour = parts[i].dcolour;
+ return 0;
+ }
+ }
+ if (parts[i].life>=45)
+ parts[i].life=0;
+ if (parts[i].life<3&&parts[i].life>0)
+ {
+ int r = (rand()%245+11);
+ int g = (rand()%245+11);
+ int b = (rand()%245+11);
+ int n;
+ float angle, magnitude;
+ unsigned col = (r<<16) | (g<<8) | b;
+ for (n=0; n<40; n++)
+ {
+ np = sim->create_part(-3, x, y, PT_EMBR);
+ if (np>-1)
+ {
+ magnitude = ((rand()%60)+40)*0.05f;
+ angle = (rand()%6284)*0.001f;//(in radians, between 0 and 2*pi)
+ parts[np].vx = parts[i].vx*0.5f + cosf(angle)*magnitude;
+ parts[np].vy = parts[i].vy*0.5f + sinf(angle)*magnitude;
+ parts[np].ctype = col;
+ parts[np].tmp = 1;
+ parts[np].life = rand()%40+70;
+ parts[np].temp = (rand()%500)+5750.0f;
+ parts[np].dcolour = parts[i].dcolour;
+ }
+ }
+ sim->pv[y/CELL][x/CELL] += 8.0f;
+ sim->kill_part(i);
+ return 1;
+ }
+ return 0;
+}
+
+
+Element_FWRK::~Element_FWRK() {} \ No newline at end of file
diff --git a/src/simulation/elements/GAS.cpp b/src/simulation/elements/GAS.cpp
new file mode 100644
index 0000000..4e87b76
--- /dev/null
+++ b/src/simulation/elements/GAS.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GAS PT_GAS 10
+Element_GAS::Element_GAS()
+{
+ Identifier = "DEFAULT_PT_GAS";
+ Name = "GAS";
+ Colour = PIXPACK(0xE0FF20);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 1.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 0.75f;
+ HotAir = 0.001f * CFDS;
+ Falldown = 0;
+
+ Flammable = 600;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+2.0f +273.15f;
+ HeatConduct = 42;
+ Description = "Gas. Diffuses. Flammable. Liquefies under pressure.";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 6.0f;
+ HighPressureTransition = PT_OIL;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 573.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_GAS::~Element_GAS() {} \ No newline at end of file
diff --git a/src/simulation/elements/GBMB.cpp b/src/simulation/elements/GBMB.cpp
new file mode 100644
index 0000000..827f062
--- /dev/null
+++ b/src/simulation/elements/GBMB.cpp
@@ -0,0 +1,93 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GBMB PT_GBMB 157
+Element_GBMB::Element_GBMB()
+{
+ Identifier = "DEFAULT_PT_GBMB";
+ Name = "GBMB";
+ Colour = PIXPACK(0x1144BB);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Sticks to first object it touches then produces strong gravity push.";
+
+ State = ST_NONE;
+ Properties = TYPE_PART|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_GBMB::update;
+ Graphics = &Element_GBMB::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_GBMB static int update(UPDATE_FUNC_ARGS)
+int Element_GBMB::update(UPDATE_FUNC_ARGS)
+ {
+ int rx,ry,r;
+ if (parts[i].life<=0)
+ {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ {
+ r = pmap[y+ry][x+rx];
+ if(!r)
+ continue;
+ if((r&0xFF)!=PT_BOMB && (r&0xFF)!=PT_GBMB &&
+ (r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN &&
+ (r&0xFF)!=PT_DMND)
+ {
+ parts[i].life=60;
+ break;
+ }
+ }
+ }
+ if(parts[i].life>20)
+ sim->gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] = 20;
+ if(parts[i].life<20 && parts[i].life>=1)
+ sim->gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] = -80;
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_GBMB static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_GBMB::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if (cpart->life <= 0) {
+ *pixel_mode |= PMODE_FLARE;
+ }
+ else
+ {
+ *pixel_mode |= PMODE_SPARK;
+ }
+ return 0;
+}
+
+
+Element_GBMB::~Element_GBMB() {} \ No newline at end of file
diff --git a/src/simulation/elements/GEL.cpp b/src/simulation/elements/GEL.cpp
new file mode 100644
index 0000000..5a139db
--- /dev/null
+++ b/src/simulation/elements/GEL.cpp
@@ -0,0 +1,155 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GEL PT_GEL 142
+Element_GEL::Element_GEL()
+{
+ Identifier = "DEFAULT_PT_GEL";
+ Name = "GEL";
+ Colour = PIXPACK(0xFF9900);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 35;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Gel. A liquid with variable viscosity and heat conductivity";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_LIFE_DEC|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_GEL::update;
+ Graphics = &Element_GEL::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_GEL static int update(UPDATE_FUNC_ARGS)
+int Element_GEL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ int absorbChanceDenom;
+ if (parts[i].tmp>100) parts[i].tmp = 100;
+ if (parts[i].tmp<0) parts[i].tmp = 0;
+ absorbChanceDenom = parts[i].tmp*10 + 500;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+
+ //Desaturation
+ if (((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW || (r&0xFF)==PT_FRZW) && parts[i].tmp<100 && 500>rand()%absorbChanceDenom)
+ {
+ parts[i].tmp++;
+ sim->kill_part(r>>8);
+ }
+ if (((r&0xFF)==PT_PSTE) && parts[i].tmp<100 && 20>rand()%absorbChanceDenom)
+ {
+ parts[i].tmp++;
+ sim->create_part(r>>8, x+rx, y+ry, PT_CLST);
+ }
+ if (((r&0xFF)==PT_SLTW) && parts[i].tmp<100 && 50>rand()%absorbChanceDenom)
+ {
+ parts[i].tmp++;
+ if (rand()%4)
+ sim->kill_part(r>>8);
+ else
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_SALT);
+ }
+ if (((r&0xFF)==PT_CBNW) && parts[i].tmp<100 && 100>rand()%absorbChanceDenom)
+ {
+ parts[i].tmp++;
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_CO2);
+ }
+
+ if ((r&0xFF)==PT_SPNG && parts[i].tmp<100 && ((parts[r>>8].life+1)>parts[i].tmp))
+ {
+ parts[r>>8].life--;
+ parts[i].tmp++;
+ }
+
+ char gel = 0;
+ if ((r&0xFF)==PT_GEL)
+ gel = 1;
+
+ //Concentration diffusion
+ if (gel && (parts[r>>8].tmp+1)<parts[i].tmp)
+ {
+ parts[r>>8].tmp++;
+ parts[i].tmp--;
+ }
+
+ if ((r&0xFF)==PT_SPNG && (parts[r>>8].life+1)<parts[i].tmp)
+ {
+ parts[r>>8].life++;
+ parts[i].tmp--;
+ }
+
+ float dx, dy;
+ dx = parts[i].x - parts[r>>8].x;
+ dy = parts[i].y - parts[r>>8].y;
+
+ //Stickness
+ if ((dx*dx + dy*dy)>1.5 && (gel || !sim->elements[r&0xFF].Falldown || (fabs((float)rx)<2 && fabs((float)ry)<2)))
+ {
+ float per, nd;
+ nd = dx*dx + dy*dy - 0.5;
+
+ per = 5*(1 - parts[i].tmp/100)*(nd/(dx*dx + dy*dy + nd) - 0.5);
+ if (sim->elements[r&0xFF].State==ST_LIQUID)
+ per *= 0.1;
+
+ dx *= per; dy *= per;
+ parts[i].vx += dx;
+ parts[i].vy += dy;
+ if ((sim->elements[r&0xFF].Properties&TYPE_PART) || (r&0xFF)==PT_GOO)
+ {
+ parts[r>>8].vx -= dx;
+ parts[r>>8].vy -= dy;
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_GEL static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_GEL::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int q = cpart->tmp;
+ *colr = q*(32-255)/120+255;
+ *colg = q*(48-186)/120+186;
+ *colb = q*208/120;
+ return 0;
+}
+
+
+
+Element_GEL::~Element_GEL() {}
diff --git a/src/simulation/elements/GLAS.cpp b/src/simulation/elements/GLAS.cpp
new file mode 100644
index 0000000..b752a0b
--- /dev/null
+++ b/src/simulation/elements/GLAS.cpp
@@ -0,0 +1,62 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GLAS PT_GLAS 45
+Element_GLAS::Element_GLAS()
+{
+ Identifier = "DEFAULT_PT_GLAS";
+ Name = "GLAS";
+ Colour = PIXPACK(0x404040);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 150;
+ Description = "Solid. Meltable. Shatters under pressure";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPASS | PROP_HOT_GLOW | PROP_SPARKSETTLE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1973.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_GLAS::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_GLAS static int update(UPDATE_FUNC_ARGS)
+int Element_GLAS::update(UPDATE_FUNC_ARGS)
+ {
+ parts[i].pavg[0] = parts[i].pavg[1];
+ parts[i].pavg[1] = sim->pv[y/CELL][x/CELL];
+ if (parts[i].pavg[1]-parts[i].pavg[0] > 0.25f || parts[i].pavg[1]-parts[i].pavg[0] < -0.25f)
+ {
+ sim->part_change_type(i,x,y,PT_BGLA);
+ }
+ return 0;
+}
+
+
+Element_GLAS::~Element_GLAS() {} \ No newline at end of file
diff --git a/src/simulation/elements/GLOW.cpp b/src/simulation/elements/GLOW.cpp
new file mode 100644
index 0000000..775e188
--- /dev/null
+++ b/src/simulation/elements/GLOW.cpp
@@ -0,0 +1,96 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GLOW PT_GLOW 66
+Element_GLOW::Element_GLOW()
+{
+ Identifier = "DEFAULT_PT_GLOW";
+ Name = "GLOW";
+ Colour = PIXPACK(0x445464);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.3f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.15f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 2;
+
+ Weight = 40;
+
+ Temperature = R_TEMP+20.0f+273.15f;
+ HeatConduct = 44;
+ Description = "Glow, Glows under pressure";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_GLOW::update;
+ Graphics = &Element_GLOW::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_GLOW static int update(UPDATE_FUNC_ARGS)
+int Element_GLOW::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR&&5>(rand()%2000))
+ {
+ parts[i].type = PT_NONE;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_DEUT);
+ parts[r>>8].life = 10;
+ }
+ }
+ parts[i].ctype = sim->pv[y/CELL][x/CELL]*16;
+
+ parts[i].tmp = abs((int)((sim->vx[y/CELL][x/CELL]+sim->vy[y/CELL][x/CELL])*16.0f)) + abs((int)((parts[i].vx+parts[i].vy)*64.0f));
+ //printf("%f %f\n", parts[i].vx, parts[i].vy);
+ if (parts[i].type==PT_NONE) {
+ sim->kill_part(i);
+ return 1;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_GLOW static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_GLOW::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firer = restrict_flt(cpart->temp-(275.13f+32.0f), 0, 128)/50.0f;
+ *fireg = restrict_flt(cpart->ctype, 0, 128)/50.0f;
+ *fireb = restrict_flt(cpart->tmp, 0, 128)/50.0f;
+
+ *colr = restrict_flt(64.0f+cpart->temp-(275.13f+32.0f), 0, 255);
+ *colg = restrict_flt(64.0f+cpart->ctype, 0, 255);
+ *colb = restrict_flt(64.0f+cpart->tmp, 0, 255);
+
+ *pixel_mode |= FIRE_ADD;
+ return 0;
+}
+
+
+Element_GLOW::~Element_GLOW() {} \ No newline at end of file
diff --git a/src/simulation/elements/GOO.cpp b/src/simulation/elements/GOO.cpp
new file mode 100644
index 0000000..3dcef31
--- /dev/null
+++ b/src/simulation/elements/GOO.cpp
@@ -0,0 +1,64 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GOO PT_GOO 12
+Element_GOO::Element_GOO()
+{
+ Identifier = "DEFAULT_PT_GOO";
+ Name = "GOO";
+ Colour = PIXPACK(0x804000);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.50f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 12;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 75;
+ Description = "Solid. Deforms and disappears under pressure.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPENETRATE|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_GOO::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_GOO static int update(UPDATE_FUNC_ARGS)
+int Element_GOO::update(UPDATE_FUNC_ARGS)
+ {
+ if (!parts[i].life && sim->pv[y/CELL][x/CELL]>1.0f)
+ parts[i].life = rand()%80+300;
+ if (parts[i].life)
+ {
+ float advection = 0.1f;
+ parts[i].vx += advection*sim->vx[y/CELL][x/CELL];
+ parts[i].vy += advection*sim->vy[y/CELL][x/CELL];
+ }
+ return 0;
+}
+
+
+Element_GOO::~Element_GOO() {} \ No newline at end of file
diff --git a/src/simulation/elements/GPMP.cpp b/src/simulation/elements/GPMP.cpp
new file mode 100644
index 0000000..3cf51a3
--- /dev/null
+++ b/src/simulation/elements/GPMP.cpp
@@ -0,0 +1,94 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GPMP PT_GPMP 154
+Element_GPMP::Element_GPMP()
+{
+ Identifier = "DEFAULT_PT_GPMP";
+ Name = "GPMP";
+ Colour = PIXPACK(0x0A3B3B);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = 0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Changes gravity to its temp when activated. (use HEAT/COOL).";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_GPMP::update;
+ Graphics = &Element_GPMP::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_GPMP static int update(UPDATE_FUNC_ARGS)
+int Element_GPMP::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ if (parts[i].life==10)
+ {
+ if (parts[i].temp>=256.0+273.15)
+ parts[i].temp=256.0+273.15;
+ if (parts[i].temp<= -256.0+273.15)
+ parts[i].temp = -256.0+273.15;
+
+ sim->gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] = 0.2f*(parts[i].temp-273.15);
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_GPMP)
+ {
+ if (parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[r>>8].life==0)
+ parts[r>>8].life = 10;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_GPMP static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_GPMP::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int lifemod = ((cpart->life>10?10:cpart->life)*19);
+ *colg += lifemod;
+ *colb += lifemod;
+ return 0;
+}
+
+
+Element_GPMP::~Element_GPMP() {}
diff --git a/src/simulation/elements/GRAV.cpp b/src/simulation/elements/GRAV.cpp
new file mode 100644
index 0000000..b913a28
--- /dev/null
+++ b/src/simulation/elements/GRAV.cpp
@@ -0,0 +1,111 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GRAV PT_GRAV 102
+Element_GRAV::Element_GRAV()
+{
+ Identifier = "DEFAULT_PT_GRAV";
+ Name = "GRAV";
+ Colour = PIXPACK(0xFFE0A0);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ Loss = 1.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 10;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 85;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Very light dust. Changes colour based on velocity.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_GRAV::update;
+ Graphics = &Element_GRAV::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_GRAV static int update(UPDATE_FUNC_ARGS)
+int Element_GRAV::update(UPDATE_FUNC_ARGS)
+ {
+ /*int t = parts[i].type;
+ if (t==PT_LOVE)
+ ISLOVE=1;
+ else if (t==PT_LOLZ)
+ ISLOLZ=1;
+ else if (t==PT_GRAV)
+ ISGRAV=1;*/
+ return 0;
+}
+
+int lastIndex;
+
+//#TPT-Directive ElementHeader Element_GRAV static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_GRAV::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int GRAV_R, GRAV_B, GRAV_G, GRAV_R2, GRAV_B2, GRAV_G2;
+
+ GRAV_R = std::abs((ren->sim->currentTick%120)-60);
+ GRAV_G = std::abs(((ren->sim->currentTick+60)%120)-60);
+ GRAV_B = std::abs(((ren->sim->currentTick+120)%120)-60);
+ GRAV_R2 = std::abs((ren->sim->currentTick%60)-30);
+ GRAV_G2 = std::abs(((ren->sim->currentTick+30)%60)-30);
+ GRAV_B2 = std::abs(((ren->sim->currentTick+60)%60)-30);
+
+
+ *colr = 20;
+ *colg = 20;
+ *colb = 20;
+ if (cpart->vx>0)
+ {
+ *colr += (cpart->vx)*GRAV_R;
+ *colg += (cpart->vx)*GRAV_G;
+ *colb += (cpart->vx)*GRAV_B;
+ }
+ if (cpart->vy>0)
+ {
+ *colr += (cpart->vy)*GRAV_G;
+ *colg += (cpart->vy)*GRAV_B;
+ *colb += (cpart->vy)*GRAV_R;
+
+ }
+ if (cpart->vx<0)
+ {
+ *colr -= (cpart->vx)*GRAV_B;
+ *colg -= (cpart->vx)*GRAV_R;
+ *colb -= (cpart->vx)*GRAV_G;
+
+ }
+ if (cpart->vy<0)
+ {
+ *colr -= (cpart->vy)*GRAV_R2;
+ *colg -= (cpart->vy)*GRAV_G2;
+ *colb -= (cpart->vy)*GRAV_B2;
+ }
+ return 0;
+}
+
+
+Element_GRAV::~Element_GRAV() {} \ No newline at end of file
diff --git a/src/simulation/elements/GUNP.cpp b/src/simulation/elements/GUNP.cpp
new file mode 100644
index 0000000..798e0f7
--- /dev/null
+++ b/src/simulation/elements/GUNP.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_GUNP PT_GUNP 7
+Element_GUNP::Element_GUNP()
+{
+ Identifier = "DEFAULT_PT_GUNP";
+ Name = "GUN";
+ Colour = PIXPACK(0xC0C0D0);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.80f;
+ Collision = -0.1f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 600;
+ Explosive = 1;
+ Meltable = 0;
+ Hardness = 10;
+
+ Weight = 85;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 97;
+ Description = "Light dust. Explosive.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 673.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_GUNP::~Element_GUNP() {} \ No newline at end of file
diff --git a/src/simulation/elements/H2.cpp b/src/simulation/elements/H2.cpp
new file mode 100644
index 0000000..2b6c31b
--- /dev/null
+++ b/src/simulation/elements/H2.cpp
@@ -0,0 +1,124 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_H2 PT_H2 148
+Element_H2::Element_H2()
+{
+ Identifier = "DEFAULT_PT_H2";
+ Name = "HYGN";
+ Colour = PIXPACK(0x5070FF);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 2.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.10f;
+ Gravity = 0.00f;
+ Diffusion = 3.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Combines with O2 to make WATR";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_H2::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_H2 static int update(UPDATE_FUNC_ARGS)
+int Element_H2::update(UPDATE_FUNC_ARGS)
+{
+ int r,rx,ry,rt;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ rt = (r&0xFF);
+ if (!r)
+ continue;
+ if (sim->pv[y/CELL][x/CELL] > 8.0f && rt == PT_DESL) // This will not work. DESL turns to fire above 5.0 pressure
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_WATR);
+ sim->part_change_type(i,x,y,PT_OIL);
+ }
+ if (parts[r>>8].temp > 2273.15 && sim->pv[y/CELL][x/CELL] > 45.0f)
+ continue;
+ if (sim->pv[y/CELL][x/CELL] <= 45.0f)
+ {
+ if (rt==PT_FIRE)
+ {
+ parts[r>>8].temp=2473.15;
+ if(parts[r>>8].tmp&0x02)
+ parts[r>>8].temp=3473;
+ parts[r>>8].tmp |= 1;
+ }
+ if (rt==PT_FIRE || (rt==PT_PLSM && !(parts[r>>8].tmp&4)) || (rt==PT_LAVA && parts[r>>8].ctype != PT_BMTL))
+ {
+ sim->create_part(i,x,y,PT_FIRE);
+ parts[i].temp+=(rand()/(RAND_MAX/100));
+ parts[i].tmp |= 1;
+ }
+ }
+ }
+ if (parts[i].temp > 2273.15 && sim->pv[y/CELL][x/CELL] > 50.0f)
+ {
+ if (rand()%5 < 1)
+ {
+ int j;
+ float temp = parts[i].temp;
+ sim->create_part(i,x,y,PT_NBLE);
+
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_NEUT);
+ if (j != -1)
+ parts[j].temp = temp;
+ if (!(rand()%10))
+ {
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_ELEC);
+ if (j != -1)
+ parts[j].temp = temp;
+ }
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_PHOT);
+ if (j != -1)
+ {
+ parts[j].ctype = 0x7C0000;
+ parts[j].temp = temp;
+ }
+
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_PLSM);
+ if (j != -1)
+ {
+ parts[j].temp = temp;
+ parts[j].tmp |= 4;
+ }
+
+ parts[i].temp = temp+750+rand()%500;
+ sim->pv[y/CELL][x/CELL] += 30;
+ }
+ }
+ return 0;
+}
+
+
+Element_H2::~Element_H2() {}
diff --git a/src/simulation/elements/HFLM.cpp b/src/simulation/elements/HFLM.cpp
new file mode 100644
index 0000000..e4fb3b4
--- /dev/null
+++ b/src/simulation/elements/HFLM.cpp
@@ -0,0 +1,75 @@
+#include "simulation/Elements.h"
+extern "C"
+{
+ #include "hmap.h"
+}
+
+//#TPT-Directive ElementClass Element_HFLM PT_HFLM 68
+Element_HFLM::Element_HFLM()
+{
+ Identifier = "DEFAULT_PT_HFLM";
+ Name = "CFLM";
+ Colour = PIXPACK(0x8080FF);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.9f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.20f;
+ Collision = 0.0f;
+ Gravity = -0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.0005f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 2;
+
+ Temperature = 0.0f;
+ HeatConduct = 88;
+ Description = "Sub-zero flame.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_GAS|PROP_LIFE_DEC|PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+ Graphics = &Element_HFLM::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_HFLM static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_HFLM::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int caddress = restrict_flt(restrict_flt((float)((int)(cpart->life/2)), 0.0f, 200.0f)*3, 0.0f, (200.0f*3)-3);
+ *colr = (unsigned char)hflm_data[caddress];
+ *colg = (unsigned char)hflm_data[caddress+1];
+ *colb = (unsigned char)hflm_data[caddress+2];
+
+ *firea = 255;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+
+ *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel
+ *pixel_mode |= FIRE_ADD;
+ //Returning 0 means dynamic, do not cache
+ return 0;
+}
+
+
+Element_HFLM::~Element_HFLM() {} \ No newline at end of file
diff --git a/src/simulation/elements/HSWC.cpp b/src/simulation/elements/HSWC.cpp
new file mode 100644
index 0000000..0f3c7e7
--- /dev/null
+++ b/src/simulation/elements/HSWC.cpp
@@ -0,0 +1,87 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_HSWC PT_HSWC 75
+Element_HSWC::Element_HSWC()
+{
+ Identifier = "DEFAULT_PT_HSWC";
+ Name = "HSWC";
+ Colour = PIXPACK(0x3B0A0A);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Heat switch. Conducts Heat only when activated";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_HSWC::update;
+ Graphics = &Element_HSWC::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_HSWC static int update(UPDATE_FUNC_ARGS)
+int Element_HSWC::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ if (parts[i].life==10)
+ {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_HSWC)
+ {
+ if (parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[r>>8].life==0)
+ parts[r>>8].life = 10;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_HSWC static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_HSWC::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int lifemod = ((cpart->life>10?10:cpart->life)*19);
+ *colr += lifemod;
+ return 0;
+}
+
+
+Element_HSWC::~Element_HSWC() {} \ No newline at end of file
diff --git a/src/simulation/elements/ICEI.cpp b/src/simulation/elements/ICEI.cpp
new file mode 100644
index 0000000..3624877
--- /dev/null
+++ b/src/simulation/elements/ICEI.cpp
@@ -0,0 +1,76 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ICEI PT_ICEI 13
+Element_ICEI::Element_ICEI()
+{
+ Identifier = "DEFAULT_PT_ICEI";
+ Name = "ICE";
+ Colour = PIXPACK(0xA0C0FF);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.0003f* CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 100;
+
+ Temperature = R_TEMP-50.0f+273.15f;
+ HeatConduct = 46;
+ Description = "Solid. Freezes water. Crushes under pressure. Cools down air.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 0.8f;
+ HighPressureTransition = PT_SNOW;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 252.05f;
+ HighTemperatureTransition = ST;
+
+ Update = &Element_ICEI::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_ICEI static int update(UPDATE_FUNC_ARGS)
+int Element_ICEI::update(UPDATE_FUNC_ARGS)
+ { //currently used for snow as well
+ int r, rx, ry;
+ if (parts[i].ctype==PT_FRZW)//get colder if it is from FRZW
+ {
+ parts[i].temp = restrict_flt(parts[i].temp-1.0f, MIN_TEMP, MAX_TEMP);
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_SALT || (r&0xFF)==PT_SLTW) && parts[i].temp > sim->elements[PT_SLTW].LowTemperature && 1>(rand()%1000))
+ {
+ sim->part_change_type(i,x,y,PT_SLTW);
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SLTW);
+ }
+ if (((r&0xFF)==PT_FRZZ) && (parts[i].ctype=PT_FRZW) && 1>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_ICEI);
+ }
+ return 0;
+}
+
+
+Element_ICEI::~Element_ICEI() {} \ No newline at end of file
diff --git a/src/simulation/elements/IGNT.cpp b/src/simulation/elements/IGNT.cpp
new file mode 100644
index 0000000..de26eb7
--- /dev/null
+++ b/src/simulation/elements/IGNT.cpp
@@ -0,0 +1,95 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_IGNT PT_IGNT 140
+Element_IGNT::Element_IGNT()
+{
+ Identifier = "DEFAULT_PT_IGNT";
+ Name = "IGNC";
+ Colour = PIXPACK(0xC0B050);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 88;
+ Description = "Ignition cord.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPENETRATE | PROP_SPARKSETTLE | PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 673.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_IGNT::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_IGNT static int update(UPDATE_FUNC_ARGS)
+int Element_IGNT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if(parts[i].tmp==0)
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_FIRE || (r&0xFF)==PT_PLSM)
+ {
+ parts[i].tmp = 1;
+ }
+ else if ((r&0xFF)==PT_SPRK || (r&0xFF)==PT_LIGH || ((r&0xFF)==PT_IGNT && parts[r>>8].life==1))
+ {
+ parts[i].tmp = 1;
+ }
+ }
+ }
+ else if(parts[i].life > 0)
+ {
+ if(rand()%3)
+ {
+ int nb = sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, PT_EMBR);
+ if (nb!=-1) {
+ parts[nb].tmp = 0;
+ parts[nb].life = 30;
+ parts[nb].vx = rand()%20-10;
+ parts[nb].vy = rand()%20-10;
+ parts[nb].temp = restrict_flt(400.0f+parts[i].temp-273.15, MIN_TEMP, MAX_TEMP);
+ }
+ }
+ else
+ {
+ sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, PT_FIRE);
+ }
+ parts[i].life--;
+ }
+ return 0;
+}
+
+
+Element_IGNT::~Element_IGNT() {} \ No newline at end of file
diff --git a/src/simulation/elements/INSL.cpp b/src/simulation/elements/INSL.cpp
new file mode 100644
index 0000000..8685775
--- /dev/null
+++ b/src/simulation/elements/INSL.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_INSL PT_INSL 38
+Element_INSL::Element_INSL()
+{
+ Identifier = "DEFAULT_PT_INSL";
+ Name = "INSL";
+ Colour = PIXPACK(0x9EA3B6);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 7;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 10;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Insulator, does not conduct heat or electricity.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_INSL::~Element_INSL() {} \ No newline at end of file
diff --git a/src/simulation/elements/INST.cpp b/src/simulation/elements/INST.cpp
new file mode 100644
index 0000000..a8a8d3e
--- /dev/null
+++ b/src/simulation/elements/INST.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_INST PT_INST 106
+Element_INST::Element_INST()
+{
+ Identifier = "DEFAULT_PT_INST";
+ Name = "INST";
+ Colour = PIXPACK(0x404039);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Instantly conducts, PSCN to charge, NSCN to take.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_INST::~Element_INST() {} \ No newline at end of file
diff --git a/src/simulation/elements/INVIS.cpp b/src/simulation/elements/INVIS.cpp
new file mode 100644
index 0000000..54d722d
--- /dev/null
+++ b/src/simulation/elements/INVIS.cpp
@@ -0,0 +1,75 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_INVIS PT_INVIS 115
+Element_INVIS::Element_INVIS()
+{
+ Identifier = "DEFAULT_PT_INVIS";
+ Name = "INVS";
+ Colour = PIXPACK(0x00CCCC);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 164;
+ Description = "Invisible to everything while under pressure.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPASS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_INVIS::update;
+ Graphics = &Element_INVIS::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_INVIS static int update(UPDATE_FUNC_ARGS)
+int Element_INVIS::update(UPDATE_FUNC_ARGS)
+{
+ if (sim->pv[y/CELL][x/CELL]>4.0f || sim->pv[y/CELL][x/CELL]<-4.0f)
+ parts[i].tmp = 1;
+ else
+ parts[i].tmp = 0;
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_INVIS static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_INVIS::graphics(GRAPHICS_FUNC_ARGS)
+{
+ //pv[ny/CELL][nx/CELL]>4.0f || pv[ny/CELL][nx/CELL]<-4.0f
+ if(cpart->tmp)
+ {
+ *cola = 100;
+ *colr = 15;
+ *colg = 0;
+ *colb = 150;
+ *pixel_mode = PMODE_BLEND;
+ }
+ return 0;
+}
+
+
+Element_INVIS::~Element_INVIS() {}
diff --git a/src/simulation/elements/INWR.cpp b/src/simulation/elements/INWR.cpp
new file mode 100644
index 0000000..35d57ec
--- /dev/null
+++ b/src/simulation/elements/INWR.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_INWR PT_INWR 62
+Element_INWR::Element_INWR()
+{
+ Identifier = "DEFAULT_PT_INWR";
+ Name = "INWR";
+ Colour = PIXPACK(0x544141);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Insulated Wire. Doesn't conduct to metal or semiconductors.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1687.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_INWR::~Element_INWR() {} \ No newline at end of file
diff --git a/src/simulation/elements/IRON.cpp b/src/simulation/elements/IRON.cpp
new file mode 100644
index 0000000..1542da9
--- /dev/null
+++ b/src/simulation/elements/IRON.cpp
@@ -0,0 +1,76 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_IRON PT_IRON 76
+Element_IRON::Element_IRON()
+{
+ Identifier = "DEFAULT_PT_IRON";
+ Name = "IRON";
+ Colour = PIXPACK(0x707070);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 50;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Rusts with salt, can be used for electrolysis of WATR";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1687.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_IRON::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_IRON static int update(UPDATE_FUNC_ARGS)
+int Element_IRON::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((((r&0xFF) == PT_SALT && 15>(rand()/(RAND_MAX/700))) ||
+ ((r&0xFF) == PT_SLTW && 30>(rand()/(RAND_MAX/2000))) ||
+ ((r&0xFF) == PT_WATR && 5 >(rand()/(RAND_MAX/6000))) ||
+ ((r&0xFF) == PT_O2 && 2 >(rand()/(RAND_MAX/500))) ||
+ ((r&0xFF) == PT_LO2))&&
+ (!(parts[i].life))
+ )
+ {
+ sim->part_change_type(i,x,y,PT_BMTL);
+ parts[i].tmp=(rand()/(RAND_MAX/10))+20;
+ }
+ }
+ return 0;
+}
+
+
+Element_IRON::~Element_IRON() {} \ No newline at end of file
diff --git a/src/simulation/elements/ISOZ.cpp b/src/simulation/elements/ISOZ.cpp
new file mode 100644
index 0000000..05df489
--- /dev/null
+++ b/src/simulation/elements/ISOZ.cpp
@@ -0,0 +1,65 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ISOZ PT_ISOZ 107
+Element_ISOZ::Element_ISOZ()
+{
+ Identifier = "DEFAULT_PT_ISOZ";
+ Name = "ISOZ";
+ Colour = PIXPACK(0xAA30D0);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 24;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Radioactive liquid";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 160.0f;
+ LowTemperatureTransition = PT_ISZS;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_ISOZ::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_ISOZ static int update(UPDATE_FUNC_ARGS)
+int Element_ISOZ::update(UPDATE_FUNC_ARGS)
+ { // for both ISZS and ISOZ
+ float rr, rrr;
+ if (1>rand()%200 && ((int)(-4.0f*(sim->pv[y/CELL][x/CELL])))>(rand()%1000))
+ {
+ sim->create_part(i, x, y, PT_PHOT);
+ rr = (rand()%228+128)/127.0f;
+ rrr = (rand()%360)*3.14159f/180.0f;
+ parts[i].vx = rr*cosf(rrr);
+ parts[i].vy = rr*sinf(rrr);
+ }
+ return 0;
+}
+
+
+Element_ISOZ::~Element_ISOZ() {} \ No newline at end of file
diff --git a/src/simulation/elements/ISZS.cpp b/src/simulation/elements/ISZS.cpp
new file mode 100644
index 0000000..b12f34c
--- /dev/null
+++ b/src/simulation/elements/ISZS.cpp
@@ -0,0 +1,65 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_ISZS PT_ISZS 108
+Element_ISZS::Element_ISZS()
+{
+ Identifier = "DEFAULT_PT_ISZS";
+ Name = "ISZS";
+ Colour = PIXPACK(0x662089);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.0007f* CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = 140.00f;
+ HeatConduct = 251;
+ Description = "Solid form of ISOZ, slowly decays.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 300.0f;
+ HighTemperatureTransition = PT_ISOZ;
+
+ Update = &Element_ISZS::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_ISZS static int update(UPDATE_FUNC_ARGS)
+int Element_ISZS::update(UPDATE_FUNC_ARGS)
+ { // for both ISZS and ISOZ
+ float rr, rrr;
+ if (1>rand()%200 && ((int)(-4.0f*(sim->pv[y/CELL][x/CELL])))>(rand()%1000))
+ {
+ sim->create_part(i, x, y, PT_PHOT);
+ rr = (rand()%228+128)/127.0f;
+ rrr = (rand()%360)*3.14159f/180.0f;
+ parts[i].vx = rr*cosf(rrr);
+ parts[i].vy = rr*sinf(rrr);
+ }
+ return 0;
+}
+
+
+Element_ISZS::~Element_ISZS() {} \ No newline at end of file
diff --git a/src/simulation/elements/LAVA.cpp b/src/simulation/elements/LAVA.cpp
new file mode 100644
index 0000000..35eefec
--- /dev/null
+++ b/src/simulation/elements/LAVA.cpp
@@ -0,0 +1,71 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LAVA PT_LAVA 6
+Element_LAVA::Element_LAVA()
+{
+ Identifier = "DEFAULT_PT_LAVA";
+ Name = "LAVA";
+ Colour = PIXPACK(0xE05010);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.3f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.15f;
+ Diffusion = 0.00f;
+ HotAir = 0.0003f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 2;
+
+ Weight = 45;
+
+ Temperature = R_TEMP+1500.0f+273.15f;
+ HeatConduct = 60;
+ Description = "Heavy liquid. Ignites flammable materials. Solidifies when cold.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 2573.15f;
+ LowTemperatureTransition = ST;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FIRE::update;
+ Graphics = &Element_LAVA::graphics;
+}
+
+
+//#TPT-Directive ElementHeader Element_LAVA static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_LAVA::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *colr = cpart->life * 2 + 0xE0;
+ *colg = cpart->life * 1 + 0x50;
+ *colb = cpart->life / 2 + 0x10;
+ if (*colr>255) *colr = 255;
+ if (*colg>192) *colg = 192;
+ if (*colb>128) *colb = 128;
+ *firea = 40;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+ *pixel_mode |= FIRE_ADD;
+ *pixel_mode |= PMODE_BLUR;
+ //Returning 0 means dynamic, do not cache
+ return 0;
+}
+
+
+Element_LAVA::~Element_LAVA() {} \ No newline at end of file
diff --git a/src/simulation/elements/LCRY.cpp b/src/simulation/elements/LCRY.cpp
new file mode 100644
index 0000000..7cd4def
--- /dev/null
+++ b/src/simulation/elements/LCRY.cpp
@@ -0,0 +1,154 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LCRY PT_LCRY 54
+Element_LCRY::Element_LCRY()
+{
+ Identifier = "DEFAULT_PT_LCRY";
+ Name = "LCRY";
+ Colour = PIXPACK(0x505050);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Liquid Crystal. Changes colour when charged. (PSCN Charges, NSCN Discharges)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1273.0f;
+ HighTemperatureTransition = PT_BGLA;
+
+ Update = &Element_LCRY::update;
+ Graphics = &Element_LCRY::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_LCRY static int update(UPDATE_FUNC_ARGS)
+int Element_LCRY::update(UPDATE_FUNC_ARGS)
+
+{
+ int r, rx, ry;
+ if(parts[i].tmp==1 || parts[i].tmp==0)
+ {
+ if(parts[i].tmp==1)
+ {
+ if(parts[i].life<=0)
+ parts[i].tmp = 0;
+ else
+ {
+ parts[i].life-=2;
+ if(parts[i].life < 0)
+ parts[i].life = 0;
+ parts[i].tmp2 = parts[i].life;
+ }
+ }
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_LCRY && parts[r>>8].tmp == 3)
+ {
+ parts[r>>8].tmp = 1;
+ }
+ }
+ }
+ else if(parts[i].tmp==2 || parts[i].tmp==3)
+ {
+ if(parts[i].tmp==2)
+ {
+ if(parts[i].life>=10)
+ parts[i].tmp = 3;
+ else
+ {
+ parts[i].life+=2;
+ if(parts[i].life > 10)
+ parts[i].life = 10;
+ parts[i].tmp2 = parts[i].life;
+ }
+ }
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_LCRY && parts[r>>8].tmp == 0)
+ {
+ parts[r>>8].tmp = 2;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_LCRY static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_LCRY::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(ren->decorations_enable && cpart->dcolour && (cpart->dcolour&0xFF000000))
+ {
+ *colr = (cpart->dcolour>>16)&0xFF;
+ *colg = (cpart->dcolour>>8)&0xFF;
+ *colb = (cpart->dcolour)&0xFF;
+
+ if(cpart->tmp2<10){
+ *colr /= 10-cpart->tmp2;
+ *colg /= 10-cpart->tmp2;
+ *colb /= 10-cpart->tmp2;
+ }
+
+ }
+ else
+ {
+ *colr = *colg = *colb = 0x50+((cpart->tmp2>10?10:cpart->tmp2)*10);
+ }
+ *pixel_mode |= NO_DECO;
+ return 0;
+
+ /*int lifemod = ((cpart->tmp2>10?10:cpart->tmp2)*10);
+ *colr += lifemod;
+ *colg += lifemod;
+ *colb += lifemod;
+ if(decorations_enable && cpart->dcolour && cpart->dcolour&0xFF000000)
+ {
+ lifemod *= 2.5f;
+ if(lifemod < 40)
+ lifemod = 40;
+ *colr = (lifemod*((cpart->dcolour>>16)&0xFF) + (255-lifemod)**colr) >> 8;
+ *colg = (lifemod*((cpart->dcolour>>8)&0xFF) + (255-lifemod)**colg) >> 8;
+ *colb = (lifemod*((cpart->dcolour)&0xFF) + (255-lifemod)**colb) >> 8;
+ }
+ *pixel_mode |= NO_DECO;
+ return 0;*/
+}
+
+
+Element_LCRY::~Element_LCRY() {} \ No newline at end of file
diff --git a/src/simulation/elements/LIFE.cpp b/src/simulation/elements/LIFE.cpp
new file mode 100644
index 0000000..4207931
--- /dev/null
+++ b/src/simulation/elements/LIFE.cpp
@@ -0,0 +1,125 @@
+#include "simulation/Elements.h"
+
+bool Element_GOL_colourInit = false;
+pixel Element_GOL_colour[NGOL];
+
+//#TPT-Directive ElementClass Element_LIFE PT_LIFE 78
+Element_LIFE::Element_LIFE()
+{
+ Identifier = "DEFAULT_PT_LIFE";
+ Name = "LIFE";
+ Colour = PIXPACK(0x0CAC00);
+ MenuVisible = 0;
+ MenuSection = SC_LIFE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = 9000.0f;
+ HeatConduct = 40;
+ Description = "Game Of Life! B3/S23";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID|PROP_LIFE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+ Graphics = &Element_LIFE::graphics;
+
+ if(!Element_GOL_colourInit)
+ {
+ Element_GOL_colourInit = true;
+
+
+ int golMenuCount;
+ gol_menu * golMenuT = LoadGOLMenu(golMenuCount);
+ for(int i = 0; i < golMenuCount && i < NGOL; i++)
+ {
+ Element_GOL_colour[i] = golMenuT[i].colour;
+ }
+ free(golMenuT);
+ }
+}
+
+
+//#TPT-Directive ElementHeader Element_LIFE static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_LIFE::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ pixel pc;
+ if (cpart->ctype==NGT_LOTE)//colors for life states
+ {
+ if (cpart->tmp==2)
+ pc = PIXRGB(255, 128, 0);
+ else if (cpart->tmp==1)
+ pc = PIXRGB(255, 255, 0);
+ else
+ pc = PIXRGB(255, 0, 0);
+ }
+ else if (cpart->ctype==NGT_FRG2)//colors for life states
+ {
+ if (cpart->tmp==2)
+ pc = PIXRGB(0, 100, 50);
+ else
+ pc = PIXRGB(0, 255, 90);
+ }
+ else if (cpart->ctype==NGT_STAR)//colors for life states
+ {
+ if (cpart->tmp==4)
+ pc = PIXRGB(0, 0, 128);
+ else if (cpart->tmp==3)
+ pc = PIXRGB(0, 0, 150);
+ else if (cpart->tmp==2)
+ pc = PIXRGB(0, 0, 190);
+ else if (cpart->tmp==1)
+ pc = PIXRGB(0, 0, 230);
+ else
+ pc = PIXRGB(0, 0, 70);
+ }
+ else if (cpart->ctype==NGT_FROG)//colors for life states
+ {
+ if (cpart->tmp==2)
+ pc = PIXRGB(0, 100, 0);
+ else
+ pc = PIXRGB(0, 255, 0);
+ }
+ else if (cpart->ctype==NGT_BRAN)//colors for life states
+ {
+ if (cpart->tmp==1)
+ pc = PIXRGB(150, 150, 0);
+ else
+ pc = PIXRGB(255, 255, 0);
+ } else {
+ pc = Element_GOL_colour[cpart->ctype];
+ }
+ *colr = PIXR(pc);
+ *colg = PIXG(pc);
+ *colb = PIXB(pc);
+ return 0;
+}
+
+
+Element_LIFE::~Element_LIFE() {} \ No newline at end of file
diff --git a/src/simulation/elements/LIGH.cpp b/src/simulation/elements/LIGH.cpp
new file mode 100644
index 0000000..c0c723e
--- /dev/null
+++ b/src/simulation/elements/LIGH.cpp
@@ -0,0 +1,359 @@
+#include "simulation/Elements.h"
+
+//#TPT-Directive ElementClass Element_LIGH PT_LIGH 87
+Element_LIGH::Element_LIGH()
+{
+ Identifier = "DEFAULT_PT_LIGH";
+ Name = "LIGH";
+ Colour = PIXPACK(0xFFFFC0);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "More realistic lightning. Set pen size to set the size of the lightning.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_LIGH::update;
+ Graphics = &Element_LIGH::graphics;
+}
+
+#define LIGHTING_POWER 0.65
+
+//#TPT-Directive ElementHeader Element_LIGH static int update(UPDATE_FUNC_ARGS)
+int Element_LIGH::update(UPDATE_FUNC_ARGS)
+
+{
+ /*
+ *
+ * tmp2:
+ * -1 - part will be removed
+ * 0 - "branches" of the lightning
+ * 1 - bending
+ * 2 - branching
+ * 3 - transfer spark or make destruction
+ * 4 - first pixel
+ *
+ * life - "thickness" of lighting (but anyway one pixel)
+ *
+ * tmp - angle of lighting, measured in degrees anticlockwise from the positive x direction
+ *
+ */
+ int r,rx,ry, multipler, powderful;
+ float angle, angle2=-1;
+ int pNear = 0;
+ powderful = powderful = parts[i].temp*(1+parts[i].life/40)*LIGHTING_POWER;
+ Element_FIRE::update(UPDATE_FUNC_SUBCALL_ARGS);
+ if (sim->aheat_enable)
+ {
+ sim->hv[y/CELL][x/CELL]+=powderful/50;
+ if (sim->hv[y/CELL][x/CELL]>MAX_TEMP)
+ sim->hv[y/CELL][x/CELL]=MAX_TEMP;
+ }
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_LIGH && (r&0xFF)!=PT_TESC)
+ {
+ if ((r&0xFF)!=PT_CLNE&&(r&0xFF)!=PT_THDR&&(r&0xFF)!=PT_DMND&&(r&0xFF)!=PT_FIRE&&(r&0xFF)!=PT_NEUT&&(r&0xFF)!=PT_PHOT)
+ {
+ if ((sim->elements[r&0xFF].Properties&PROP_CONDUCTS) && parts[r>>8].life==0)
+ {
+ sim->create_part(r>>8,x+rx,y+ry,PT_SPRK);
+ }
+ sim->pv[y/CELL][x/CELL] += powderful/400;
+ if (sim->elements[r&0xFF].HeatConduct) parts[r>>8].temp = restrict_flt(parts[r>>8].temp+powderful/1.5, MIN_TEMP, MAX_TEMP);
+ }
+ if ((r&0xFF)==PT_DEUT || (r&0xFF)==PT_PLUT) // start nuclear reactions
+ {
+ parts[r>>8].temp = restrict_flt(parts[r>>8].temp+powderful, MIN_TEMP, MAX_TEMP);
+ sim->pv[y/CELL][x/CELL] +=powderful/35;
+ if (rand()%3==0)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_NEUT);
+ parts[r>>8].life = rand()%480+480;
+ parts[r>>8].vx=rand()%10-5;
+ parts[r>>8].vy=rand()%10-5;
+ }
+ }
+ if ((r&0xFF)==PT_COAL || (r&0xFF)==PT_BCOL) // ignite coal
+ {
+ if (parts[r>>8].life>100) {
+ parts[r>>8].life = 99;
+ }
+ }
+ if (sim->elements[r&0xFF].HeatConduct)
+ parts[r>>8].temp = restrict_flt(parts[r>>8].temp+powderful/10, MIN_TEMP, MAX_TEMP);
+ if (((r&0xFF)==PT_STKM && sim->player.elem!=PT_LIGH) || ((r&0xFF)==PT_STKM2 && sim->player2.elem!=PT_LIGH))
+ {
+ parts[r>>8].life-=powderful/100;
+ }
+ }
+ }
+ if (parts[i].tmp2==3)
+ {
+ parts[i].tmp2=0;
+ return 1;
+ }
+
+ if (parts[i].tmp2==-1)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ if (parts[i].tmp2<=0 || parts[i].life<=1)
+ {
+ if (parts[i].tmp2>0)
+ parts[i].tmp2=0;
+ parts[i].tmp2--;
+ return 1;
+ }
+ if (parts[i].tmp2<=-2)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+
+ angle2=-1;
+
+ pNear = LIGH_nearest_part(sim, i, parts[i].life*2.5);
+ if (pNear!=-1)
+ {
+ int t=parts[pNear].type;
+ float n_angle; // angle to nearest part
+ float angle_diff;
+ rx=parts[pNear].x-x;
+ ry=parts[pNear].y-y;
+ if (rx!=0 || ry!=0)
+ n_angle = atan2f(-ry, rx);
+ else
+ n_angle = 0;
+ if (n_angle<0)
+ n_angle+=M_PI*2;
+ angle_diff = fabsf(n_angle-parts[i].tmp*M_PI/180);
+ if (angle_diff>M_PI)
+ angle_diff = M_PI*2 - angle_diff;
+ if (parts[i].life<5 || angle_diff<M_PI*0.8) // lightning strike
+ {
+ create_line_par(sim, x, y, x+rx, y+ry, PT_LIGH, parts[i].temp, parts[i].life, parts[i].tmp-90, 0);
+
+ if (t!=PT_TESC)
+ {
+ pNear=contact_part(sim, pNear, PT_LIGH);
+ if (pNear!=-1)
+ {
+ parts[pNear].tmp2=3;
+ parts[pNear].life=(int)(1.0*parts[i].life/2-1);
+ parts[pNear].tmp=parts[i].tmp-180;
+ parts[pNear].temp=parts[i].temp;
+ }
+ }
+ }
+ else pNear=-1;
+ }
+
+ //if (parts[i].tmp2==1/* || near!=-1*/)
+ //angle=0;//parts[i].tmp-30+rand()%60;
+ angle = parts[i].tmp-30+rand()%60;
+ if (angle<0)
+ angle+=360;
+ if (angle>=360)
+ angle-=360;
+ if (parts[i].tmp2==2 && pNear==-1)
+ {
+ angle2=angle+100-rand()%200;
+ if (angle2<0)
+ angle2+=360;
+ if (angle2>=360)
+ angle-=360;
+ }
+
+ multipler=parts[i].life*1.5+rand()%((int)(parts[i].life+1));
+ rx=cos(angle*M_PI/180)*multipler;
+ ry=-sin(angle*M_PI/180)*multipler;
+ create_line_par(sim, x, y, x+rx, y+ry, PT_LIGH, parts[i].temp, parts[i].life, angle, 0);
+
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r&0xFF)==PT_LIGH)
+ {
+ parts[r>>8].tmp2=1+(rand()%200>parts[i].tmp2*parts[i].tmp2/10+60);
+ parts[r>>8].life=(int)(1.0*parts[i].life/1.5-rand()%2);
+ parts[r>>8].tmp=angle;
+ parts[r>>8].temp=parts[i].temp;
+ }
+ }
+
+ if (angle2!=-1)
+ {
+ multipler=parts[i].life*1.5+rand()%((int)(parts[i].life+1));
+ rx=cos(angle2*M_PI/180)*multipler;
+ ry=-sin(angle2*M_PI/180)*multipler;
+ create_line_par(sim, x, y, x+rx, y+ry, PT_LIGH, parts[i].temp, parts[i].life, angle2, 0);
+
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r&0xFF)==PT_LIGH)
+ {
+ parts[r>>8].tmp2=1+(rand()%200>parts[i].tmp2*parts[i].tmp2/10+40);
+ parts[r>>8].life=(int)(1.0*parts[i].life/1.5-rand()%2);
+ parts[r>>8].tmp=angle;
+ parts[r>>8].temp=parts[i].temp;
+ }
+ }
+ }
+
+ parts[i].tmp2=-1;
+ return 1;
+}
+
+//#TPT-Directive ElementHeader Element_LIGH static int LIGH_nearest_part(Simulation * sim, int ci, int max_d)
+int Element_LIGH::LIGH_nearest_part(Simulation * sim, int ci, int max_d)
+{
+ int distance = (max_d!=-1)?max_d:MAX_DISTANCE;
+ int ndistance = 0;
+ int id = -1;
+ int i = 0;
+ int cx = (int)sim->parts[ci].x;
+ int cy = (int)sim->parts[ci].y;
+ for (i=0; i<=sim->parts_lastActiveIndex; i++)
+ {
+ if (sim->parts[i].type && sim->parts[i].life && i!=ci && sim->parts[i].type!=PT_LIGH && sim->parts[i].type!=PT_THDR && sim->parts[i].type!=PT_NEUT && sim->parts[i].type!=PT_PHOT)
+ {
+ ndistance = abs(cx-sim->parts[i].x)+abs(cy-sim->parts[i].y);// Faster but less accurate Older: sqrt(pow(cx-parts[i].x, 2)+pow(cy-parts[i].y, 2));
+ if (ndistance<distance)
+ {
+ distance = ndistance;
+ id = i;
+ }
+ }
+ }
+ return id;
+}
+
+//#TPT-Directive ElementHeader Element_LIGH static int contact_part(Simulation * sim, int i, int tp)
+int Element_LIGH::contact_part(Simulation * sim, int i, int tp)
+{
+ int x=sim->parts[i].x, y=sim->parts[i].y;
+ int r,rx,ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = sim->pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==tp)
+ return r>>8;
+ }
+ return -1;
+}
+
+//#TPT-Directive ElementHeader Element_LIGH static void create_line_par(Simulation * sim, int x1, int y1, int x2, int y2, int c, int temp, int life, int tmp, int tmp2)
+void Element_LIGH::create_line_par(Simulation * sim, int x1, int y1, int x2, int y2, int c, int temp, int life, int tmp, int tmp2)
+{
+ int cp=abs(y2-y1)>abs(x2-x1), x, y, dx, dy, sy;
+ float e, de;
+ if (c==WL_EHOLE || c==WL_ALLOWGAS || c==WL_ALLOWALLELEC || c==WL_ALLOWSOLID || c==WL_ALLOWAIR || c==WL_WALL || c==WL_DESTROYALL || c==WL_ALLOWLIQUID || c==WL_FAN || c==WL_STREAM || c==WL_DETECT || c==WL_EWALL || c==WL_WALLELEC)
+ return; // this function only for particles, no walls
+ if (cp)
+ {
+ y = x1;
+ x1 = y1;
+ y1 = y;
+ y = x2;
+ x2 = y2;
+ y2 = y;
+ }
+ if (x1 > x2)
+ {
+ y = x1;
+ x1 = x2;
+ x2 = y;
+ y = y1;
+ y1 = y2;
+ y2 = y;
+ }
+ dx = x2 - x1;
+ dy = abs(y2 - y1);
+ e = 0.0f;
+ if (dx)
+ de = dy/(float)dx;
+ else
+ de = 0.0f;
+ y = y1;
+ sy = (y1<y2) ? 1 : -1;
+ for (x=x1; x<=x2; x++)
+ {
+ int p;
+ if (cp)
+ p = sim->create_part(-1, y, x, c);
+ else
+ p = sim->create_part(-1, x, y,c);
+ if (p!=-1)
+ {
+ sim->parts[p].life = life;
+ sim->parts[p].temp = temp;
+ sim->parts[p].tmp = tmp;
+ sim->parts[p].tmp2 = tmp2;
+ }
+ e += de;
+ if (e >= 0.5f)
+ {
+ y += sy;
+ e -= 1.0f;
+ }
+ }
+}
+
+
+//#TPT-Directive ElementHeader Element_LIGH static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_LIGH::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 120;
+ *firer = *colr = 235;
+ *fireg = *colg = 245;
+ *fireb = *colb = 255;
+ *pixel_mode |= PMODE_GLOW | FIRE_ADD;
+ return 1;
+}
+
+
+Element_LIGH::~Element_LIGH() {} \ No newline at end of file
diff --git a/src/simulation/elements/LNTG.cpp b/src/simulation/elements/LNTG.cpp
new file mode 100644
index 0000000..ac97191
--- /dev/null
+++ b/src/simulation/elements/LNTG.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LNTG PT_LNTG 37
+Element_LNTG::Element_LNTG()
+{
+ Identifier = "DEFAULT_PT_LNTG";
+ Name = "LN2";
+ Colour = PIXPACK(0x80A0DF);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 30;
+
+ Temperature = 70.15f;
+ HeatConduct = 70;
+ Description = "Liquid Nitrogen. Very cold.";
+
+ State = ST_SOLID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 63.0f;
+ LowTemperatureTransition = PT_NICE;
+ HighTemperature = 77.0f;
+ HighTemperatureTransition = PT_NONE;
+
+ Update = NULL;
+
+}
+
+Element_LNTG::~Element_LNTG() {} \ No newline at end of file
diff --git a/src/simulation/elements/LO2.cpp b/src/simulation/elements/LO2.cpp
new file mode 100644
index 0000000..e032b9e
--- /dev/null
+++ b/src/simulation/elements/LO2.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LO2 PT_LO2 60
+Element_LO2::Element_LO2()
+{
+ Identifier = "DEFAULT_PT_LO2";
+ Name = "LOXY";
+ Colour = PIXPACK(0x80A0EF);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 5000;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 30;
+
+ Temperature = 80.0f;
+ HeatConduct = 70;
+ Description = "Liquid Oxygen. Very cold. Reacts with fire";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 90.1f;
+ HighTemperatureTransition = PT_O2;
+
+ Update = NULL;
+
+}
+
+Element_LO2::~Element_LO2() {} \ No newline at end of file
diff --git a/src/simulation/elements/LOLZ.cpp b/src/simulation/elements/LOLZ.cpp
new file mode 100644
index 0000000..a5e8371
--- /dev/null
+++ b/src/simulation/elements/LOLZ.cpp
@@ -0,0 +1,71 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LOLZ PT_LOLZ 123
+Element_LOLZ::Element_LOLZ()
+{
+ Identifier = "DEFAULT_PT_LOLZ";
+ Name = "LOLZ";
+ Colour = PIXPACK(0x569212);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.00f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = 373.0f;
+ HeatConduct = 40;
+ Description = "Lolz";
+
+ State = ST_GAS;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_LOLZ::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_LOLZ static int RuleTable[9][9]
+int Element_LOLZ::RuleTable[9][9] =
+{
+ {0,0,0,0,0,0,0,0,0},
+ {1,0,0,0,0,0,1,0,0},
+ {1,0,0,0,0,0,1,0,0},
+ {1,0,0,1,1,0,0,1,0},
+ {1,0,1,0,0,1,0,1,0},
+ {1,0,1,0,0,1,0,1,0},
+ {0,1,0,1,1,0,0,1,0},
+ {0,1,0,0,0,0,0,1,0},
+ {0,1,0,0,0,0,0,1,0},
+};
+
+//#TPT-Directive ElementHeader Element_LOLZ static int update(UPDATE_FUNC_ARGS)
+int Element_LOLZ::update(UPDATE_FUNC_ARGS)
+ {
+ sim->ISLOLZ = true;
+ return 0;
+}
+
+
+Element_LOLZ::~Element_LOLZ() {} \ No newline at end of file
diff --git a/src/simulation/elements/LOVE.cpp b/src/simulation/elements/LOVE.cpp
new file mode 100644
index 0000000..3e7b3d4
--- /dev/null
+++ b/src/simulation/elements/LOVE.cpp
@@ -0,0 +1,71 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LOVE PT_LOVE 94
+Element_LOVE::Element_LOVE()
+{
+ Identifier = "DEFAULT_PT_LOVE";
+ Name = "LOVE";
+ Colour = PIXPACK(0xFF30FF);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.00f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = 373.0f;
+ HeatConduct = 40;
+ Description = "Love...";
+
+ State = ST_GAS;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_LOVE::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_LOVE static int RuleTable[9][9]
+int Element_LOVE::RuleTable[9][9] =
+{
+ {0,0,1,1,0,0,0,0,0},
+ {0,1,0,0,1,1,0,0,0},
+ {1,0,0,0,0,0,1,0,0},
+ {1,0,0,0,0,0,0,1,0},
+ {0,1,0,0,0,0,0,0,1},
+ {1,0,0,0,0,0,0,1,0},
+ {1,0,0,0,0,0,1,0,0},
+ {0,1,0,0,1,1,0,0,0},
+ {0,0,1,1,0,0,0,0,0},
+};
+
+//#TPT-Directive ElementHeader Element_LOVE static int update(UPDATE_FUNC_ARGS)
+int Element_LOVE::update(UPDATE_FUNC_ARGS)
+ {
+ sim->ISLOVE = true;
+ return 0;
+}
+
+
+Element_LOVE::~Element_LOVE() {} \ No newline at end of file
diff --git a/src/simulation/elements/LRBD.cpp b/src/simulation/elements/LRBD.cpp
new file mode 100644
index 0000000..f609cce
--- /dev/null
+++ b/src/simulation/elements/LRBD.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_LRBD PT_LRBD 42
+Element_LRBD::Element_LRBD()
+{
+ Identifier = "DEFAULT_PT_LRBD";
+ Name = "LRBD";
+ Colour = PIXPACK(0xAAAAAA);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.3f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.15f;
+ Diffusion = 0.00f;
+ HotAir = 0.000001f* CFDS;
+ Falldown = 2;
+
+ Flammable = 1000;
+ Explosive = 1;
+ Meltable = 0;
+ Hardness = 2;
+
+ Weight = 45;
+
+ Temperature = R_TEMP+45.0f+273.15f;
+ HeatConduct = 170;
+ Description = "Liquid Rubidium.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 311.0f;
+ LowTemperatureTransition = PT_RBDM;
+ HighTemperature = 961.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_LRBD::~Element_LRBD() {} \ No newline at end of file
diff --git a/src/simulation/elements/MERC.cpp b/src/simulation/elements/MERC.cpp
new file mode 100644
index 0000000..1fec32a
--- /dev/null
+++ b/src/simulation/elements/MERC.cpp
@@ -0,0 +1,121 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_MERC PT_MERC 152
+Element_MERC::Element_MERC()
+{
+ Identifier = "DEFAULT_PT_MERC";
+ Name = "MERC";
+ Colour = PIXPACK(0x736B6D);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 91;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Mercury. Volume changes with temperature, Conductive.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_NEUTABSORB|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_MERC::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_MERC static int update(UPDATE_FUNC_ARGS)
+int Element_MERC::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, trade, np;
+ int maxtmp = ((10000/(parts[i].temp + 1))-1);
+ if ((10000%((int)parts[i].temp+1))>rand()%((int)parts[i].temp+1))
+ maxtmp ++;
+ if (parts[i].tmp < maxtmp)
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r || (parts[i].tmp >=maxtmp))
+ continue;
+ if ((r&0xFF)==PT_MERC&&33>=rand()/(RAND_MAX/100)+1)
+ {
+ if ((parts[i].tmp + parts[r>>8].tmp + 1) <= maxtmp)
+ {
+ parts[i].tmp += parts[r>>8].tmp + 1;
+ sim->kill_part(r>>8);
+ }
+ }
+ }
+ }
+ else
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (parts[i].tmp<=maxtmp)
+ continue;
+ if ((!r)&&parts[i].tmp>=1)//if nothing then create deut
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_MERC);
+ if (np<0) continue;
+ parts[i].tmp--;
+ parts[np].temp = parts[i].temp;
+ parts[np].tmp = 0;
+ }
+ }
+ for ( trade = 0; trade<4; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_MERC&&(parts[i].tmp>parts[r>>8].tmp)&&parts[i].tmp>0)//diffusion
+ {
+ int temp = parts[i].tmp - parts[r>>8].tmp;
+ if (temp ==1)
+ {
+ parts[r>>8].tmp ++;
+ parts[i].tmp --;
+ }
+ else if (temp>0)
+ {
+ parts[r>>8].tmp += temp/2;
+ parts[i].tmp -= temp/2;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_MERC::~Element_MERC() {} \ No newline at end of file
diff --git a/src/simulation/elements/METL.cpp b/src/simulation/elements/METL.cpp
new file mode 100644
index 0000000..17b09d0
--- /dev/null
+++ b/src/simulation/elements/METL.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_METL PT_METL 14
+Element_METL::Element_METL()
+{
+ Identifier = "DEFAULT_PT_METL";
+ Name = "METL";
+ Colour = PIXPACK(0x404060);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. Conducts electricity. Meltable.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1273.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_METL::~Element_METL() {} \ No newline at end of file
diff --git a/src/simulation/elements/MORT.cpp b/src/simulation/elements/MORT.cpp
new file mode 100644
index 0000000..f8f1d8c
--- /dev/null
+++ b/src/simulation/elements/MORT.cpp
@@ -0,0 +1,57 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_MORT PT_MORT 77
+Element_MORT::Element_MORT()
+{
+ Identifier = "DEFAULT_PT_MORT";
+ Name = "MORT";
+ Colour = PIXPACK(0xE0E0E0);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ Loss = 1.00f;
+ Collision = -0.99f;
+ Gravity = 0.0f;
+ Diffusion = 0.01f;
+ HotAir = 0.002f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = -1;
+
+ Temperature = R_TEMP+4.0f +273.15f;
+ HeatConduct = 60;
+ Description = "Steam Train.";
+
+ State = ST_NONE;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_MORT::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_MORT static int update(UPDATE_FUNC_ARGS)
+int Element_MORT::update(UPDATE_FUNC_ARGS)
+ {
+ sim->create_part(-1, x, y-1, PT_SMKE);
+ return 0;
+}
+
+
+Element_MORT::~Element_MORT() {} \ No newline at end of file
diff --git a/src/simulation/elements/MWAX.cpp b/src/simulation/elements/MWAX.cpp
new file mode 100644
index 0000000..4153893
--- /dev/null
+++ b/src/simulation/elements/MWAX.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_MWAX PT_MWAX 34
+Element_MWAX::Element_MWAX()
+{
+ Identifier = "DEFAULT_PT_MWAX";
+ Name = "MWAX";
+ Colour = PIXPACK(0xE0E0AA);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.3f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.15f;
+ Diffusion = 0.00f;
+ HotAir = 0.000001f* CFDS;
+ Falldown = 2;
+
+ Flammable = 5;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 2;
+
+ Weight = 25;
+
+ Temperature = R_TEMP+28.0f+273.15f;
+ HeatConduct = 44;
+ Description = "Liquid Wax.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 318.0f;
+ LowTemperatureTransition = PT_WAX;
+ HighTemperature = 673.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_MWAX::~Element_MWAX() {} \ No newline at end of file
diff --git a/src/simulation/elements/NBHL.cpp b/src/simulation/elements/NBHL.cpp
new file mode 100644
index 0000000..2ccb864
--- /dev/null
+++ b/src/simulation/elements/NBHL.cpp
@@ -0,0 +1,60 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NBHL PT_NBHL 150
+Element_NBHL::Element_NBHL()
+{
+ Identifier = "DEFAULT_PT_NBHL";
+ Name = "BHOL";
+ Colour = PIXPACK(0x202020);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 186;
+ Description = "Black hole (Requires newtonian gravity)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_NBHL::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_NBHL static int update(UPDATE_FUNC_ARGS)
+int Element_NBHL::update(UPDATE_FUNC_ARGS)
+ {
+ if (parts[i].tmp)
+ sim->gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] += restrict_flt(0.001f*parts[i].tmp, 0.1f, 51.2f);
+ else
+ sim->gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] += 0.1f;
+ return 0;
+}
+
+
+Element_NBHL::~Element_NBHL() {}
diff --git a/src/simulation/elements/NBLE.cpp b/src/simulation/elements/NBLE.cpp
new file mode 100644
index 0000000..3093d45
--- /dev/null
+++ b/src/simulation/elements/NBLE.cpp
@@ -0,0 +1,93 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NBLE PT_NBLE 52
+Element_NBLE::Element_NBLE()
+{
+ Identifier = "DEFAULT_PT_NBLE";
+ Name = "NBLE";
+ Colour = PIXPACK(0xEB4917);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 1.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 0.75f;
+ HotAir = 0.001f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+2.0f +273.15f;
+ HeatConduct = 106;
+ Description = "Noble Gas. Diffuses. Conductive. Ionizes into plasma when introduced to electricity";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_NBLE::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_NBLE static int update(UPDATE_FUNC_ARGS)
+int Element_NBLE::update(UPDATE_FUNC_ARGS)
+
+{
+ if (parts[i].temp > 5273.15 && sim->pv[y/CELL][x/CELL] > 100.0f)
+ {
+ parts[i].tmp = 1;
+ if (rand()%5 < 1)
+ {
+ int j;
+ float temp = parts[i].temp;
+ sim->create_part(i,x,y,PT_CO2);
+
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_NEUT);
+ if (j != -1)
+ parts[j].temp = temp;
+ if (!(rand()%25))
+ {
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_ELEC);
+ if (j != -1)
+ parts[j].temp = temp;
+ }
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_PHOT);
+ if (j != -1)
+ {
+ parts[j].ctype = 0xF800000;
+ parts[j].temp = temp;
+ }
+
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_PLSM);
+ if (j != -1)
+ {
+ parts[j].temp = temp;
+ parts[j].tmp |= 4;
+ }
+
+ parts[i].temp = temp+1750+rand()%500;
+ sim->pv[y/CELL][x/CELL] += 50;
+ }
+ }
+ return 0;
+}
+
+
+Element_NBLE::~Element_NBLE() {} \ No newline at end of file
diff --git a/src/simulation/elements/NEUT.cpp b/src/simulation/elements/NEUT.cpp
new file mode 100644
index 0000000..4641370
--- /dev/null
+++ b/src/simulation/elements/NEUT.cpp
@@ -0,0 +1,207 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NEUT PT_NEUT 18
+Element_NEUT::Element_NEUT()
+{
+ Identifier = "DEFAULT_PT_NEUT";
+ Name = "NEUT";
+ Colour = PIXPACK(0x20E0FF);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ Loss = 1.00f;
+ Collision = -0.99f;
+ Gravity = 0.0f;
+ Diffusion = 0.01f;
+ HotAir = 0.002f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = -1;
+
+ Temperature = R_TEMP+4.0f +273.15f;
+ HeatConduct = 60;
+ Description = "Neutrons. Interact with matter in odd ways.";
+
+ State = ST_GAS;
+ Properties = TYPE_ENERGY|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_NEUT::update;
+ Graphics = &Element_NEUT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_NEUT static int update(UPDATE_FUNC_ARGS)
+int Element_NEUT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt;
+ int pressureFactor = 3 + (int)sim->pv[y/CELL][x/CELL];
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR || (r&0xFF)==PT_ICEI || (r&0xFF)==PT_SNOW)
+ {
+ parts[i].vx *= 0.995;
+ parts[i].vy *= 0.995;
+ }
+ if ((r&0xFF)==PT_PLUT && pressureFactor>(rand()%1000))
+ {
+ if (33>rand()%100)
+ {
+ sim->create_part(r>>8, x+rx, y+ry, rand()%3 ? PT_LAVA : PT_URAN);
+ parts[r>>8].temp = MAX_TEMP;
+ if (parts[r>>8].type==PT_LAVA) {
+ parts[r>>8].tmp = 100;
+ parts[r>>8].ctype = PT_PLUT;
+ }
+ }
+ else
+ {
+ sim->create_part(r>>8, x+rx, y+ry, PT_NEUT);
+ parts[r>>8].vx = 0.25f*parts[r>>8].vx + parts[i].vx;
+ parts[r>>8].vy = 0.25f*parts[r>>8].vy + parts[i].vy;
+ }
+ sim->pv[y/CELL][x/CELL] += 10.0f * CFDS; //Used to be 2, some people said nukes weren't powerful enough
+ Element_FIRE::update(UPDATE_FUNC_SUBCALL_ARGS);
+ }
+#ifdef SDEUT
+ else if ((r&0xFF)==PT_DEUT && (pressureFactor+1+(parts[r>>8].life/100))>(rand()%1000))
+ {
+ create_n_parts(sim, parts[r>>8].life, x+rx, y+ry, parts[i].vx, parts[i].vy, restrict_flt(parts[r>>8].temp + parts[r>>8].life*500, MIN_TEMP, MAX_TEMP), PT_NEUT);
+ sim->kill_part(r>>8);
+ }
+#else
+ else if ((r&0xFF)==PT_DEUT && (pressureFactor+1)>(rand()%1000))
+ {
+ create_part(r>>8, x+rx, y+ry, PT_NEUT);
+ parts[r>>8].vx = 0.25f*parts[r>>8].vx + parts[i].vx;
+ parts[r>>8].vy = 0.25f*parts[r>>8].vy + parts[i].vy;
+ if (parts[r>>8].life>0)
+ {
+ parts[r>>8].life --;
+ parts[r>>8].temp = restrict_flt(parts[r>>8].temp + parts[r>>8].life*17, MIN_TEMP, MAX_TEMP);
+ pv[y/CELL][x/CELL] += 6.0f * CFDS;
+ }
+ else
+ sim.kill_part(r>>8);
+ }
+#endif
+ else if ((r&0xFF)==PT_GUNP && 15>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_DUST);
+ else if ((r&0xFF)==PT_DYST && 15>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_YEST);
+ else if ((r&0xFF)==PT_YEST)
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_DYST);
+ else if ((r&0xFF)==PT_WATR && 15>(rand()%100))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_DSTW);
+ else if ((r&0xFF)==PT_PLEX && 15>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_GOO);
+ else if ((r&0xFF)==PT_NITR && 15>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_DESL);
+ else if ((r&0xFF)==PT_PLNT && 5>(rand()%100))
+ sim->create_part(r>>8, x+rx, y+ry, PT_WOOD);
+ else if ((r&0xFF)==PT_DESL && 15>(rand()%1000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_GAS);
+ else if ((r&0xFF)==PT_COAL && 5>(rand()%100))
+ sim->create_part(r>>8, x+rx, y+ry, PT_WOOD);
+ else if ((r&0xFF)==PT_DUST && 5>(rand()%100))
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_FWRK);
+ else if ((r&0xFF)==PT_FWRK && 5>(rand()%100))
+ parts[r>>8].ctype = PT_DUST;
+ else if ((r&0xFF)==PT_ACID && 5>(rand()%100))
+ sim->create_part(r>>8, x+rx, y+ry, PT_ISOZ);
+ else if ((r&0xFF)==PT_TTAN && 5>(rand()%100))
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ else if ((r&0xFF)==PT_EXOT && 5>(rand()%100))
+ parts[r>>8].life = 1500;
+ /*if(parts[r>>8].type>1 && parts[r>>8].type!=PT_NEUT && parts[r>>8].type-1!=PT_NEUT && parts[r>>8].type-1!=PT_STKM &&
+ (elements[parts[r>>8].type-1].menusection==SC_LIQUID||
+ elements[parts[r>>8].type-1].menusection==SC_EXPLOSIVE||
+ elements[parts[r>>8].type-1].menusection==SC_GAS||
+ elements[parts[r>>8].type-1].menusection==SC_POWDERS) && 15>(rand()%1000))
+ parts[r>>8].type--;*/
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_NEUT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_NEUT::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 120;
+ *firer = 10;
+ *fireg = 80;
+ *fireb = 120;
+
+ *pixel_mode |= FIRE_ADD;
+ return 1;
+}
+
+//#TPT-Directive ElementHeader Element_NEUT static int create_n_parts(Simulation * sim, int n, int x, int y, float vx, float vy, float temp, int t)
+int Element_NEUT::create_n_parts(Simulation * sim, int n, int x, int y, float vx, float vy, float temp, int t)//testing a new deut create part
+{
+ int i, c;
+ n = (n/50);
+ if (n<1) {
+ n = 1;
+ }
+ if (n>340) {
+ n = 340;
+ }
+ if (x<0 || y<0 || x>=XRES || y>=YRES || t<0 || t>=PT_NUM || !sim->elements[t].Enabled)
+ return -1;
+
+ for (c=0; c<n; c++) {
+ float r = (rand()%128+128)/127.0f;
+ float a = (rand()%360)*M_PI/180.0f;
+ if (sim->pfree == -1)
+ return -1;
+ i = sim->pfree;
+ sim->pfree = sim->parts[i].life;
+ if (i>sim->parts_lastActiveIndex) sim->parts_lastActiveIndex = i;
+
+ sim->parts[i].x = (float)x;
+ sim->parts[i].y = (float)y;
+ sim->parts[i].type = t;
+ sim->parts[i].life = rand()%480+480;
+ sim->parts[i].vx = r*cosf(a);
+ sim->parts[i].vy = r*sinf(a);
+ sim->parts[i].ctype = 0;
+ sim->parts[i].temp = temp;
+ sim->parts[i].tmp = 0;
+ if (t!=PT_STKM&&t!=PT_STKM2 && t!=PT_PHOT && t!=PT_NEUT && !sim->pmap[y][x])
+ sim->pmap[y][x] = t|(i<<8);
+ else if ((t==PT_PHOT||t==PT_NEUT) && !sim->photons[y][x])
+ sim->photons[y][x] = t|(i<<8);
+
+ sim->pv[y/CELL][x/CELL] += 6.0f * CFDS;
+ }
+ return 0;
+}
+
+
+Element_NEUT::~Element_NEUT() {}
diff --git a/src/simulation/elements/NICE.cpp b/src/simulation/elements/NICE.cpp
new file mode 100644
index 0000000..8a6086e
--- /dev/null
+++ b/src/simulation/elements/NICE.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NICE PT_NICE 51
+Element_NICE::Element_NICE()
+{
+ Identifier = "DEFAULT_PT_NICE";
+ Name = "NICE";
+ Colour = PIXPACK(0xC0E0FF);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.0005f* CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 100;
+
+ Temperature = 35.0f;
+ HeatConduct = 46;
+ Description = "Nitrogen Ice.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 63.1f;
+ HighTemperatureTransition = PT_LNTG;
+
+ Update = NULL;
+
+}
+
+Element_NICE::~Element_NICE() {} \ No newline at end of file
diff --git a/src/simulation/elements/NITR.cpp b/src/simulation/elements/NITR.cpp
new file mode 100644
index 0000000..bf0feee
--- /dev/null
+++ b/src/simulation/elements/NITR.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NITR PT_NITR 8
+Element_NITR::Element_NITR()
+{
+ Identifier = "DEFAULT_PT_NITR";
+ Name = "NITR";
+ Colour = PIXPACK(0x20E010);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.5f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.92f;
+ Loss = 0.97f;
+ Collision = 0.0f;
+ Gravity = 0.2f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 1000;
+ Explosive = 2;
+ Meltable = 0;
+ Hardness = 3;
+
+ Weight = 23;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 50;
+ Description = "Liquid. Pressure sensitive explosive.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 673.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_NITR::~Element_NITR() {} \ No newline at end of file
diff --git a/src/simulation/elements/NONE.cpp b/src/simulation/elements/NONE.cpp
new file mode 100644
index 0000000..95d9d3e
--- /dev/null
+++ b/src/simulation/elements/NONE.cpp
@@ -0,0 +1,66 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NONE PT_NONE 0
+Element_NONE::Element_NONE()
+{
+ Identifier = "DEFAULT_PT_NONE";
+ Name = "";
+ Colour = PIXPACK(0x000000);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Erases particles.";
+
+ State = ST_NONE;
+ Properties = 0;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+ IconGenerator = &Element_NONE::iconGen;
+}
+
+//#TPT-Directive ElementHeader Element_NONE static VideoBuffer * iconGen(int, int, int)
+VideoBuffer * Element_NONE::iconGen(int wallID, int width, int height)
+{
+ VideoBuffer * newTexture = new VideoBuffer(width, height);
+
+ for (int j=3; j<(width-4)/2; j++)
+ {
+ newTexture->SetPixel(j+6, j, 0xFF, 0, 0, 255);
+ newTexture->SetPixel(j+7, j, 0xFF, 0, 0, 255);
+ newTexture->SetPixel(-j+19, j, 0xFF, 0, 0, 255);
+ newTexture->SetPixel(-j+20, j, 0xFF, 0, 0, 255);
+ }
+
+ return newTexture;
+}
+
+
+Element_NONE::~Element_NONE() {} \ No newline at end of file
diff --git a/src/simulation/elements/NSCN.cpp b/src/simulation/elements/NSCN.cpp
new file mode 100644
index 0000000..c16e9c4
--- /dev/null
+++ b/src/simulation/elements/NSCN.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NSCN PT_NSCN 36
+Element_NSCN::Element_NSCN()
+{
+ Identifier = "DEFAULT_PT_NSCN";
+ Name = "NSCN";
+ Colour = PIXPACK(0x505080);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "N-Type Silicon, Will not transfer current to P-Type Silicon.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1687.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_NSCN::~Element_NSCN() {} \ No newline at end of file
diff --git a/src/simulation/elements/NTCT.cpp b/src/simulation/elements/NTCT.cpp
new file mode 100644
index 0000000..2241468
--- /dev/null
+++ b/src/simulation/elements/NTCT.cpp
@@ -0,0 +1,58 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NTCT PT_NTCT 43
+Element_NTCT::Element_NTCT()
+{
+ Identifier = "DEFAULT_PT_NTCT";
+ Name = "NTCT";
+ Colour = PIXPACK(0x505040);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Semi-conductor. Only conducts electricity when hot (More than 100C)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1687.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_NTCT::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_NTCT static int update(UPDATE_FUNC_ARGS)
+int Element_NTCT::update(UPDATE_FUNC_ARGS)
+ {
+ if (parts[i].temp>295.0f)
+ parts[i].temp -= 2.5f;
+ return 0;
+}
+
+
+Element_NTCT::~Element_NTCT() {} \ No newline at end of file
diff --git a/src/simulation/elements/NWHL.cpp b/src/simulation/elements/NWHL.cpp
new file mode 100644
index 0000000..7fcda4a
--- /dev/null
+++ b/src/simulation/elements/NWHL.cpp
@@ -0,0 +1,57 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_NWHL PT_NWHL 151
+Element_NWHL::Element_NWHL()
+{
+ Identifier = "DEFAULT_PT_NWHL";
+ Name = "WHOL";
+ Colour = PIXPACK(0xFFFFFF);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 186;
+ Description = "White hole (Requires newtonian gravity)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_NWHL::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_NWHL static int update(UPDATE_FUNC_ARGS)
+int Element_NWHL::update(UPDATE_FUNC_ARGS)
+ {
+ sim->gravmap[(y/CELL)*(XRES/CELL)+(x/CELL)] -= 0.1f;
+ return 0;
+}
+
+
+Element_NWHL::~Element_NWHL() {} \ No newline at end of file
diff --git a/src/simulation/elements/O2.cpp b/src/simulation/elements/O2.cpp
new file mode 100644
index 0000000..20bd902
--- /dev/null
+++ b/src/simulation/elements/O2.cpp
@@ -0,0 +1,104 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_O2 PT_O2 61
+Element_O2::Element_O2()
+{
+ Identifier = "DEFAULT_PT_O2";
+ Name = "OXYG";
+ Colour = PIXPACK(0x80A0FF);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 2.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 3.0f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Gas. Ignites easily.";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 90.0f;
+ LowTemperatureTransition = PT_LO2;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_O2::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_O2 static int update(UPDATE_FUNC_ARGS)
+int Element_O2::update(UPDATE_FUNC_ARGS)
+{
+ int r,rx,ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+
+ if ((r&0xFF)==PT_FIRE)
+ {
+ parts[r>>8].temp+=(rand()/(RAND_MAX/100));
+ if(parts[r>>8].tmp&0x01)
+ parts[r>>8].temp=3473;
+ parts[r>>8].tmp |= 2;
+ }
+ if ((r&0xFF)==PT_FIRE || ((r&0xFF)==PT_PLSM && !(parts[r>>8].tmp&4)))
+ {
+ sim->create_part(i,x,y,PT_FIRE);
+ parts[i].temp+=(rand()/(RAND_MAX/100));
+ parts[i].tmp |= 2;
+ }
+
+ }
+ if (parts[i].temp > 9973.15 && sim->pv[y/CELL][x/CELL] > 250.0f && abs(sim->gravx[((y/CELL)*(XRES/CELL))+(x/CELL)]) + abs(sim->gravy[((y/CELL)*(XRES/CELL))+(x/CELL)]) > 20)
+ {
+ if (rand()%5 < 1)
+ {
+ int j;
+ sim->create_part(i,x,y,PT_BRMT);
+
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_NEUT);
+ if (j != -1)
+ parts[j].temp = 15000;
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_PHOT);
+ if (j != -1)
+ parts[j].temp = 15000;
+ j = sim->create_part(-3,x+rand()%3-1,y+rand()%3-1,PT_PLSM);
+ if (j != -1)
+ {
+ parts[j].temp = 15000;
+ parts[j].tmp |= 4;
+ }
+
+ parts[i].temp = 15000;
+ sim->pv[y/CELL][x/CELL] += 300;
+ }
+ }
+ return 0;
+}
+
+
+Element_O2::~Element_O2() {}
diff --git a/src/simulation/elements/OIL.cpp b/src/simulation/elements/OIL.cpp
new file mode 100644
index 0000000..5dd7595
--- /dev/null
+++ b/src/simulation/elements/OIL.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_OIL PT_OIL 3
+Element_OIL::Element_OIL()
+{
+ Identifier = "DEFAULT_PT_OIL";
+ Name = "OIL";
+ Colour = PIXPACK(0x404010);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 20;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 5;
+
+ Weight = 20;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 42;
+ Description = "Liquid. Flammable.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 333.0f;
+ HighTemperatureTransition = PT_GAS;
+
+ Update = NULL;
+
+}
+
+Element_OIL::~Element_OIL() {} \ No newline at end of file
diff --git a/src/simulation/elements/PBCN.cpp b/src/simulation/elements/PBCN.cpp
new file mode 100644
index 0000000..e3bc7ce
--- /dev/null
+++ b/src/simulation/elements/PBCN.cpp
@@ -0,0 +1,164 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PBCN PT_PBCN 153
+Element_PBCN::Element_PBCN()
+{
+ Identifier = "DEFAULT_PT_PBCN";
+ Name = "PBCN";
+ Colour = PIXPACK(0x3B1D0A);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.50f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 12;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Powered breakable clone";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PBCN::update;
+ Graphics = &Element_PBCN::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PBCN static int update(UPDATE_FUNC_ARGS)
+int Element_PBCN::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ if (!parts[i].tmp2 && sim->pv[y/CELL][x/CELL]>4.0f)
+ parts[i].tmp2 = rand()%40+80;
+ if (parts[i].tmp2)
+ {
+ float advection = 0.1f;
+ parts[i].vx += advection*sim->vx[y/CELL][x/CELL];
+ parts[i].vy += advection*sim->vy[y/CELL][x/CELL];
+ parts[i].tmp2--;
+ if(!parts[i].tmp2){
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled || (parts[i].ctype==PT_LIFE && (parts[i].tmp<0 || parts[i].tmp>=NGOLALT)))
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN &&
+ (r&0xFF)!=PT_BCLN && (r&0xFF)!=PT_SPRK &&
+ (r&0xFF)!=PT_NSCN && (r&0xFF)!=PT_PSCN &&
+ (r&0xFF)!=PT_STKM && (r&0xFF)!=PT_STKM2 &&
+ (r&0xFF)!=PT_PBCN && (r&0xFF)<PT_NUM)
+ {
+ parts[i].ctype = r&0xFF;
+ if ((r&0xFF)==PT_LIFE || (r&0xFF)==PT_LAVA)
+ parts[i].tmp = parts[r>>8].ctype;
+ }
+ }
+ if (parts[i].life==10)
+ {
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_PBCN)
+ {
+ if (parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[r>>8].life==0)
+ parts[r>>8].life = 10;
+ }
+ }
+ }
+ if (parts[i].ctype>0 && parts[i].ctype<PT_NUM && sim->elements[parts[i].ctype].Enabled && parts[i].life==10) {
+ if (parts[i].ctype==PT_PHOT) {//create photons a different way
+ for (rx=-1; rx<2; rx++)
+ {
+ for (ry = -1; ry < 2; ry++)
+ {
+ if (rx || ry)
+ {
+ int r = sim->create_part(-1, x + rx, y + ry,
+ parts[i].ctype);
+ if (r != -1)
+ {
+ parts[r].vx = rx * 3;
+ parts[r].vy = ry * 3;
+ if (r>i)
+ {
+ // Make sure movement doesn't happen until next frame, to avoid gaps in the beams of photons produced
+ parts[r].flags |= FLAG_SKIPMOVE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (parts[i].ctype==PT_LIFE) {//create life a different way
+ for (rx=-1; rx<2; rx++) {
+ for (ry=-1; ry<2; ry++) {
+ sim->create_part(-1, x+rx, y+ry, parts[i].ctype|(parts[i].tmp<<8));
+ }
+ }
+ }
+ else if (parts[i].ctype!=PT_LIGH || (rand()%30)==0)
+ {
+ int np = sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, parts[i].ctype);
+ if (np>=0)
+ {
+ if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
+ parts[np].ctype = parts[i].tmp;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PBCN static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PBCN::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int lifemod = ((cpart->life>10?10:cpart->life)*10);
+ *colr += lifemod;
+ *colg += lifemod/2;
+ return 0;
+}
+
+
+Element_PBCN::~Element_PBCN() {}
diff --git a/src/simulation/elements/PCLN.cpp b/src/simulation/elements/PCLN.cpp
new file mode 100644
index 0000000..7e6b3d7
--- /dev/null
+++ b/src/simulation/elements/PCLN.cpp
@@ -0,0 +1,154 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PCLN PT_PCLN 74
+Element_PCLN::Element_PCLN()
+{
+ Identifier = "DEFAULT_PT_PCLN";
+ Name = "PCLN";
+ Colour = PIXPACK(0x3B3B0A);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. When activated, duplicates any particles it touches.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PCLN::update;
+ Graphics = &Element_PCLN::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PCLN static int update(UPDATE_FUNC_ARGS)
+int Element_PCLN::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK && parts[r>>8].life>0 && parts[r>>8].life<4)
+ {
+ if (parts[r>>8].ctype==PT_PSCN)
+ parts[i].life = 10;
+ else if (parts[r>>8].ctype==PT_NSCN)
+ parts[i].life = 9;
+ }
+ if ((r&0xFF)==PT_PCLN)
+ {
+ if (parts[i].life==10&&parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[i].life==0&&parts[r>>8].life==10)
+ parts[i].life = 10;
+ }
+ }
+ if (parts[i].ctype<=0 || parts[i].ctype>=PT_NUM || !sim->elements[parts[i].ctype].Enabled || (parts[i].ctype==PT_LIFE && (parts[i].tmp<0 || parts[i].tmp>=NGOLALT)))
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_CLNE && (r&0xFF)!=PT_PCLN &&
+ (r&0xFF)!=PT_BCLN && (r&0xFF)!=PT_SPRK &&
+ (r&0xFF)!=PT_NSCN && (r&0xFF)!=PT_PSCN &&
+ (r&0xFF)!=PT_STKM && (r&0xFF)!=PT_STKM2 &&
+ (r&0xFF)!=PT_PBCN && (r&0xFF)<PT_NUM)
+ {
+ parts[i].ctype = r&0xFF;
+ if ((r&0xFF)==PT_LIFE || (r&0xFF)==PT_LAVA)
+ parts[i].tmp = parts[r>>8].ctype;
+ }
+ }
+ if (parts[i].ctype>0 && parts[i].ctype<PT_NUM && sim->elements[parts[i].ctype].Enabled && parts[i].life==10) {
+ if (parts[i].ctype==PT_PHOT) {//create photons a different way
+ for (rx=-1; rx<2; rx++)
+ {
+ for (ry = -1; ry < 2; ry++)
+ {
+ if (rx || ry)
+ {
+ int r = sim->create_part(-1, x + rx, y + ry,
+ parts[i].ctype);
+ if (r != -1)
+ {
+ parts[r].vx = rx * 3;
+ parts[r].vy = ry * 3;
+ if (r>i)
+ {
+ // Make sure movement doesn't happen until next frame, to avoid gaps in the beams of photons produced
+ parts[r].flags |= FLAG_SKIPMOVE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (parts[i].ctype==PT_LIFE) {//create life a different way
+ for (rx=-1; rx<2; rx++) {
+ for (ry=-1; ry<2; ry++) {
+ sim->create_part(-1, x+rx, y+ry, parts[i].ctype|(parts[i].tmp<<8));
+ }
+ }
+ }
+ else if (parts[i].ctype!=PT_LIGH || (rand()%30)==0)
+ {
+ int np = sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, parts[i].ctype);
+ if (np>=0)
+ {
+ if (parts[i].ctype==PT_LAVA && parts[i].tmp>0 && parts[i].tmp<PT_NUM && sim->elements[parts[i].tmp].HighTemperatureTransition==PT_LAVA)
+ parts[np].ctype = parts[i].tmp;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PCLN static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PCLN::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int lifemod = ((cpart->life>10?10:cpart->life)*10);
+ *colr += lifemod;
+ *colg += lifemod;
+ return 0;
+}
+
+
+Element_PCLN::~Element_PCLN() {}
diff --git a/src/simulation/elements/PHOT.cpp b/src/simulation/elements/PHOT.cpp
new file mode 100644
index 0000000..ac8c5c8
--- /dev/null
+++ b/src/simulation/elements/PHOT.cpp
@@ -0,0 +1,141 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PHOT PT_PHOT 31
+Element_PHOT::Element_PHOT()
+{
+ Identifier = "DEFAULT_PT_PHOT";
+ Name = "PHOT";
+ Colour = PIXPACK(0xFFFFFF);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ Loss = 1.00f;
+ Collision = -0.99f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = -1;
+
+ Temperature = R_TEMP+900.0f+273.15f;
+ HeatConduct = 251;
+ Description = "Photons. Travel in straight lines.";
+
+ State = ST_GAS;
+ Properties = TYPE_ENERGY|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PHOT::update;
+ Graphics = &Element_PHOT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PHOT static int update(UPDATE_FUNC_ARGS)
+int Element_PHOT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rt, rx, ry;
+ float rr, rrr;
+ parts[i].pavg[0] = x;
+ parts[i].pavg[1] = y;
+ if (!(parts[i].ctype&0x3FFFFFFF)) {
+ sim->kill_part(i);
+ return 1;
+ }
+ if (parts[i].temp > 506)
+ if (1>rand()%10) Element_FIRE::update(UPDATE_FUNC_SUBCALL_ARGS);
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES && (rx || ry)) {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_ISOZ && 5>(rand()%2000))
+ {
+ parts[i].vx *= 0.90;
+ parts[i].vy *= 0.90;
+ sim->create_part(r>>8, x+rx, y+ry, PT_PHOT);
+ rrr = (rand()%360)*3.14159f/180.0f;
+ rr = (rand()%128+128)/127.0f;
+ parts[r>>8].vx = rr*cosf(rrr);
+ parts[r>>8].vy = rr*sinf(rrr);
+ sim->pv[y/CELL][x/CELL] -= 15.0f * CFDS;
+ }
+ if ((r&0xFF)==PT_ISZS && 5>(rand()%2000))
+ {
+ parts[i].vx *= 0.90;
+ parts[i].vy *= 0.90;
+ sim->create_part(r>>8, x+rx, y+ry, PT_PHOT);
+ rr = (rand()%228+128)/127.0f;
+ rrr = (rand()%360)*3.14159f/180.0f;
+ parts[r>>8].vx = rr*cosf(rrr);
+ parts[r>>8].vy = rr*sinf(rrr);
+ sim->pv[y/CELL][x/CELL] -= 15.0f * CFDS;
+ }
+ }
+ r = pmap[y][x];
+ if((r&0xFF) == PT_QRTZ && r)// && parts[i].ctype==0x3FFFFFFF)
+ {
+ float a = (rand()%360)*3.14159f/180.0f;
+ parts[i].vx = 3.0f*cosf(a);
+ parts[i].vy = 3.0f*sinf(a);
+ if(parts[i].ctype == 0x3FFFFFFF)
+ parts[i].ctype = 0x1F<<(rand()%26);
+ parts[i].life++; //Delay death
+ }
+ //r = pmap[y][x];
+ //rt = r&0xFF;
+ /*if (rt==PT_CLNE || rt==PT_PCLN || rt==PT_BCLN || rt==PT_PBCN) {
+ if (!parts[r>>8].ctype)
+ parts[r>>8].ctype = PT_PHOT;
+ }*/
+
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_PHOT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PHOT::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int x = 0;
+ *colr = *colg = *colb = 0;
+ for (x=0; x<12; x++) {
+ *colr += (cpart->ctype >> (x+18)) & 1;
+ *colb += (cpart->ctype >> x) & 1;
+ }
+ for (x=0; x<12; x++)
+ *colg += (cpart->ctype >> (x+9)) & 1;
+ x = 624/(*colr+*colg+*colb+1);
+ *colr *= x;
+ *colg *= x;
+ *colb *= x;
+
+ *firea = 100;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+
+ *pixel_mode &= ~PMODE_FLAT;
+ *pixel_mode |= FIRE_ADD | PMODE_ADD;
+ return 0;
+}
+
+
+Element_PHOT::~Element_PHOT() {} \ No newline at end of file
diff --git a/src/simulation/elements/PIPE.cpp b/src/simulation/elements/PIPE.cpp
new file mode 100644
index 0000000..3d631a1
--- /dev/null
+++ b/src/simulation/elements/PIPE.cpp
@@ -0,0 +1,516 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PIPE PT_PIPE 99
+Element_PIPE::Element_PIPE()
+{
+ Identifier = "DEFAULT_PT_PIPE";
+ Name = "PIPE";
+ Colour = PIXPACK(0x444444);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = 273.15f;
+ HeatConduct = 0;
+ Description = "Moves elements around, read FAQ on website for help.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 10.0f;
+ HighPressureTransition = PT_BRMT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PIPE::update;
+ Graphics = &Element_PIPE::graphics;
+}
+
+#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
+
+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};
+
+//#TPT-Directive ElementHeader Element_PIPE static int update(UPDATE_FUNC_ARGS)
+int Element_PIPE::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, np;
+ int rnd, rndstore;
+ if (parts[i].tmp & PPIP_TMPFLAG_TRIGGERS)
+ {
+ int pause_changed = 0;
+ if (parts[i].tmp & PPIP_TMPFLAG_TRIGGER_ON) // TRIGGER_ON overrides TRIGGER_OFF
+ {
+ if (parts[i].tmp & PPIP_TMPFLAG_PAUSED)
+ pause_changed = 1;
+ parts[i].tmp &= ~PPIP_TMPFLAG_PAUSED;
+ }
+ else if (parts[i].tmp & PPIP_TMPFLAG_TRIGGER_OFF)
+ {
+ if (!(parts[i].tmp & PPIP_TMPFLAG_PAUSED))
+ pause_changed = 1;
+ parts[i].tmp |= PPIP_TMPFLAG_PAUSED;
+ }
+ if (pause_changed)
+ {
+ int rx, ry, r;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ {
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r&0xFF) == PT_BRCK)
+ {
+ if (parts[i].tmp & PPIP_TMPFLAG_PAUSED)
+ parts[r>>8].tmp = 0;
+ else
+ parts[r>>8].tmp = 1; //make surrounding BRCK glow
+ }
+ }
+ }
+ }
+
+ 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;
+ if (parts[i].tmp & 0x100) //Switch one pixel pipe direction
+ {
+ int coords = (parts[i].tmp>>13)&0xF;
+ int coords2 = (parts[i].tmp>>9)&0xF;
+ parts[i].tmp &= ~0x1FE00;
+ parts[i].tmp |= coords<<9;
+ parts[i].tmp |= coords2<<13;
+ }
+ }
+
+ parts[i].tmp &= ~PPIP_TMPFLAG_TRIGGERS;
+ }
+ if (parts[i].ctype>=2 && parts[i].ctype<=4 && !(parts[i].tmp & PPIP_TMPFLAG_PAUSED))
+ {
+ if (parts[i].life==3)
+ {
+ int lastneighbor = -1;
+ int neighborcount = 0;
+ int count = 0;
+ // make automatic pipe pattern
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_PIPE || (r&0xFF) == PT_PPIP)&&parts[r>>8].ctype==1)
+ {
+ parts[r>>8].ctype = (((parts[i].ctype)%3)+2);//reverse
+ parts[r>>8].life = 6;
+ if ( parts[i].tmp&0x100)//is a single pixel pipe
+ {
+ parts[r>>8].tmp |= 0x200;//will transfer to a single pixel pipe
+ parts[r>>8].tmp |= count<<10;//coords of where it came from
+ parts[i].tmp |= ((7-count)<<14);
+ parts[i].tmp |= 0x2000;
+ }
+ neighborcount ++;
+ lastneighbor = r>>8;
+ }
+ else if (((r&0xFF)==PT_PIPE || (r&0xFF) == PT_PPIP)&&parts[r>>8].ctype!=(((parts[i].ctype-1)%3)+2))
+ {
+ neighborcount ++;
+ lastneighbor = r>>8;
+ }
+ count++;
+ }
+ if(neighborcount == 1)
+ parts[lastneighbor].tmp |= 0x100;
+ }
+ else
+ {
+ if (parts[i].flags&PFLAG_NORMALSPEED)//skip particle push to prevent particle number being higher causing speed up
+ {
+ parts[i].flags &= ~PFLAG_NORMALSPEED;
+ }
+ else
+ {
+ pushParticle(sim, i,0,i);
+ }
+
+ if (nt)//there is something besides PIPE around current particle
+ {
+ rndstore = rand();
+ rnd = rndstore&7;
+ rndstore = rndstore>>3;
+ rx = pos_1_rx[rnd];
+ ry = pos_1_ry[rnd];
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = pmap[y+ry][x+rx];
+ if(!r)
+ r = sim->photons[y+ry][x+rx];
+ if (surround_space && !r && (parts[i].tmp&0xFF)!=0) //creating at end
+ {
+ np = sim->create_part(-1,x+rx,y+ry,parts[i].tmp&0xFF);
+ if (np!=-1)
+ {
+ transfer_pipe_to_part(parts+i, parts+np);
+ }
+ }
+ //try eating particle at entrance
+ else if ((parts[i].tmp&0xFF) == 0 && (sim->elements[r&0xFF].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)))
+ {
+ if ((r&0xFF)==PT_SOAP)
+ sim->detach(r>>8);
+ transfer_part_to_pipe(parts+(r>>8), parts+i);
+ sim->kill_part(r>>8);
+ }
+ else if ((parts[i].tmp&0xFF) == 0 && (r&0xFF)==PT_STOR && parts[r>>8].tmp && (sim->elements[parts[r>>8].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+(r>>8), parts+i);
+ }
+ }
+ }
+ }
+ }
+ else if (!parts[i].ctype && parts[i].life<=10)
+ {
+ if (parts[i].temp<272.15)//manual pipe colors
+ {
+ if (parts[i].temp>173.25&&parts[i].temp<273.15)
+ {
+ parts[i].ctype = 2;
+ parts[i].life = 0;
+ }
+ if (parts[i].temp>73.25&&parts[i].temp<=173.15)
+ {
+ parts[i].ctype = 3;
+ parts[i].life = 0;
+ }
+ if (parts[i].temp>=0&&parts[i].temp<=73.15)
+ {
+ parts[i].ctype = 4;
+ parts[i].life = 0;
+ }
+ }
+ else
+ {
+ // make a border
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ {
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ 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
+ if (parts[i].type == PT_PPIP && index != -1)
+ parts[index].tmp = 1;
+ }
+ }
+ }
+ if (parts[i].life<=1)
+ parts[i].ctype = 1;
+ }
+ }
+ else if (parts[i].ctype==1)//wait for empty space before starting to generate automatic pipe pattern
+ {
+ if (!parts[i].life)
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ if (!pmap[y+ry][x+rx] && sim->bmap[(y+ry)/CELL][(x+rx)/CELL]!=WL_ALLOWAIR && sim->bmap[(y+ry)/CELL][(x+rx)/CELL]!=WL_WALL && sim->bmap[(y+ry)/CELL][(x+rx)/CELL]!=WL_WALLELEC && (sim->bmap[(y+ry)/CELL][(x+rx)/CELL]!=WL_EWALL || sim->emap[(y+ry)/CELL][(x+rx)/CELL]))
+ parts[i].life=50;
+ }
+ }
+ else if (parts[i].life==5)//check for beginning of pipe single pixel
+ {
+ int issingle = 1;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (((r&0xFF)==PT_PIPE || (r&0xFF) == PT_PPIP) && parts[i].ctype==1 && parts[i].life )
+ issingle = 0;
+ }
+ if (issingle)
+ parts[i].tmp |= 0x100;
+ }
+ else if (parts[i].life==2)
+ {
+ parts[i].ctype = 2;
+ parts[i].life = 6;
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_PIPE static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PIPE::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+
+ if ((cpart->tmp&0xFF)>0 && (cpart->tmp&0xFF)<PT_NUM)
+ {
+ //Create a temp. particle and do a subcall.
+ Particle tpart;
+ int t;
+ memset(&tpart, 0, sizeof(Particle));
+ tpart.type = cpart->tmp&0xFF;
+ tpart.temp = cpart->temp;
+ tpart.life = cpart->tmp2;
+ tpart.tmp = cpart->pavg[0];
+ tpart.ctype = cpart->pavg[1];
+ if (tpart.type == PT_PHOT && tpart.ctype == 0x40000000)
+ tpart.ctype = 0x3FFFFFFF;
+ t = tpart.type;
+ if (ren->graphicscache[t].isready)
+ {
+ *pixel_mode = ren->graphicscache[t].pixel_mode;
+ *cola = ren->graphicscache[t].cola;
+ *colr = ren->graphicscache[t].colr;
+ *colg = ren->graphicscache[t].colg;
+ *colb = ren->graphicscache[t].colb;
+ *firea = ren->graphicscache[t].firea;
+ *firer = ren->graphicscache[t].firer;
+ *fireg = ren->graphicscache[t].fireg;
+ *fireb = ren->graphicscache[t].fireb;
+ }
+ else
+ {
+ *colr = PIXR(ren->sim->elements[t].Colour);
+ *colg = PIXG(ren->sim->elements[t].Colour);
+ *colb = PIXB(ren->sim->elements[t].Colour);
+ if (ren->sim->elements[t].Graphics)
+ {
+ (*(ren->sim->elements[t].Graphics))(ren, &tpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb);
+ }
+ else
+ {
+ Element::defaultGraphics(ren, &tpart, nx, ny, pixel_mode, cola, colr, colg, colb, firea, firer, fireg, fireb);
+ }
+ }
+ //*colr = PIXR(elements[cpart->tmp&0xFF].pcolors);
+ //*colg = PIXG(elements[cpart->tmp&0xFF].pcolors);
+ //*colb = PIXB(elements[cpart->tmp&0xFF].pcolors);
+ }
+ else
+ {
+ if (cpart->ctype==2)
+ {
+ *colr = 50;
+ *colg = 1;
+ *colb = 1;
+ }
+ else if (cpart->ctype==3)
+ {
+ *colr = 1;
+ *colg = 50;
+ *colb = 1;
+ }
+ else if (cpart->ctype==4)
+ {
+ *colr = 1;
+ *colg = 1;
+ *colb = 50;
+ }
+ else if (cpart->temp<272.15&&cpart->ctype!=1)
+ {
+ if (cpart->temp>173.25&&cpart->temp<273.15)
+ {
+ *colr = 50;
+ *colg = 1;
+ *colb = 1;
+ }
+ if (cpart->temp>73.25&&cpart->temp<=173.15)
+ {
+ *colr = 1;
+ *colg = 50;
+ *colb = 1;
+ }
+ if (cpart->temp>=0&&cpart->temp<=73.15)
+ {
+ *colr = 1;
+ *colg = 1;
+ *colb = 50;
+ }
+ }
+ }
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_PIPE static void transfer_pipe_to_part(Particle *pipe, Particle *part)
+void Element_PIPE::transfer_pipe_to_part(Particle *pipe, Particle *part)
+{
+ part->type = (pipe->tmp & 0xFF);
+ part->temp = pipe->temp;
+ part->life = pipe->tmp2;
+ part->tmp = pipe->pavg[0];
+ part->ctype = pipe->pavg[1];
+ pipe->tmp &= ~0xFF;
+
+ if (part->type != PT_PHOT && part->type != PT_ELEC && part->type != PT_NEUT)
+ {
+ part->vx = 0.0f;
+ part->vy = 0.0f;
+ }
+ else if (part->type == PT_PHOT && part->ctype == 0x40000000)
+ part->ctype = 0x3FFFFFFF;
+ part->tmp2 = 0;
+ part->flags = 0;
+ part->dcolour = 0;
+}
+
+//#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&~0xFF) | part->type;
+ pipe->temp = part->temp;
+ pipe->tmp2 = part->life;
+ pipe->pavg[0] = part->tmp;
+ pipe->pavg[1] = part->ctype;
+}
+
+//#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&~0xFF) | (src->tmp&0xFF);
+ dest->temp = src->temp;
+ dest->tmp2 = src->tmp2;
+ dest->pavg[0] = src->pavg[0];
+ dest->pavg[1] = src->pavg[1];
+ src->tmp &= ~0xFF;
+}
+
+//#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 ((sim->parts[i].tmp&0xFF) == 0 || 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);
+ if( !(sim->parts[i].tmp&0x200) )
+ {
+ //normal random push
+ rndstore = rand();
+ // RAND_MAX is at least 32767 on all platforms i.e. pow(8,5)-1
+ // so can go 5 cycles without regenerating rndstore
+ for (q=0; q<3; q++)//try to push 3 times
+ {
+ rnd = rndstore&7;
+ rndstore = rndstore>>3;
+ rx = pos_1_rx[rnd];
+ ry = pos_1_ry[rnd];
+ if (x+rx>=0 && y+ry>=0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = sim->pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ else if (((r&0xFF)==PT_PIPE || (r&0xFF) == PT_PPIP) && sim->parts[r>>8].ctype!=notctype && (sim->parts[r>>8].tmp&0xFF)==0)
+ {
+ transfer_pipe_to_pipe(sim->parts+i, sim->parts+(r>>8));
+ if (r>>8 > original)
+ sim->parts[r>>8].flags |= PFLAG_NORMALSPEED;//skip particle push, normalizes speed
+ count++;
+ pushParticle(sim, r>>8,count,original);
+ }
+ else if ((r&0xFF) == PT_PRTI) //Pass particles into PRTI for a pipe speed increase
+ {
+ int nnx;
+ for (nnx=0; nnx<80; nnx++)
+ if (!sim->portalp[sim->parts[r>>8].tmp][count][nnx].type)
+ {
+ transfer_pipe_to_part(sim->parts+i, &(sim->portalp[sim->parts[r>>8].tmp][count][nnx]));
+ count++;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else //predefined 1 pixel thick pipe movement
+ {
+ int coords = 7 - ((sim->parts[i].tmp>>10)&7);
+ r = sim->pmap[y+ pos_1_ry[coords]][x+ pos_1_rx[coords]];
+ if (((r&0xFF)==PT_PIPE || (r&0xFF) == PT_PPIP) && sim->parts[r>>8].ctype!=notctype && (sim->parts[r>>8].tmp&0xFF)==0)
+ {
+ transfer_pipe_to_pipe(sim->parts+i, sim->parts+(r>>8));
+ if (r>>8 > original)
+ sim->parts[r>>8].flags |= PFLAG_NORMALSPEED;//skip particle push, normalizes speed
+ count++;
+ pushParticle(sim, r>>8,count,original);
+ }
+ else if ((r&0xFF) == PT_PRTI) //Pass particles into PRTI for a pipe speed increase
+ {
+ int nnx;
+ for (nnx=0; nnx<80; nnx++)
+ if (!sim->portalp[sim->parts[r>>8].tmp][count][nnx].type)
+ {
+ transfer_pipe_to_part(sim->parts+i, &(sim->portalp[sim->parts[r>>8].tmp][count][nnx]));
+ count++;
+ break;
+ }
+ }
+ else if ((r&0xFF) == PT_NONE) //Move particles out of pipe automatically, much faster at ends
+ {
+ rx = pos_1_rx[coords];
+ ry = pos_1_ry[coords];
+ np = sim->create_part(-1,x+rx,y+ry,sim->parts[i].tmp&0xFF);
+ if (np!=-1)
+ {
+ transfer_pipe_to_part(sim->parts+i, sim->parts+np);
+ }
+ }
+
+ }
+ return;
+}
+
+
+Element_PIPE::~Element_PIPE() {}
diff --git a/src/simulation/elements/PLEX.cpp b/src/simulation/elements/PLEX.cpp
new file mode 100644
index 0000000..c2f157b
--- /dev/null
+++ b/src/simulation/elements/PLEX.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PLEX PT_PLEX 11
+Element_PLEX::Element_PLEX()
+{
+ Identifier = "DEFAULT_PT_PLEX";
+ Name = "C-4";
+ Colour = PIXPACK(0xD080E0);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 1000;
+ Explosive = 2;
+ Meltable = 50;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 88;
+ Description = "Solid. Pressure sensitive explosive.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 673.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+
+}
+
+Element_PLEX::~Element_PLEX() {} \ No newline at end of file
diff --git a/src/simulation/elements/PLNT.cpp b/src/simulation/elements/PLNT.cpp
new file mode 100644
index 0000000..6e8202c
--- /dev/null
+++ b/src/simulation/elements/PLNT.cpp
@@ -0,0 +1,126 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PLNT PT_PLNT 20
+Element_PLNT::Element_PLNT()
+{
+ Identifier = "DEFAULT_PT_PLNT";
+ Name = "PLNT";
+ Colour = PIXPACK(0x0CAC00);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 20;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 10;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 65;
+ Description = "Plant, drinks water and grows.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_NEUTPENETRATE|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 573.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_PLNT::update;
+ Graphics = &Element_PLNT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PLNT static int update(UPDATE_FUNC_ARGS)
+int Element_PLNT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, np;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_WATR && 1>(rand()%250))
+ {
+ np = sim->create_part(r>>8,x+rx,y+ry,PT_PLNT);
+ if (np<0) continue;
+ parts[np].life = 0;
+ }
+ else if ((r&0xFF)==PT_LAVA && 1>(rand()%250))
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = 4;
+ }
+ else if (((r&0xFF)==PT_SMKE || (r&0xFF)==PT_CO2) && (1>rand()%250))
+ {
+ sim->kill_part(r>>8);
+ parts[i].life = rand()%60 + 60;
+ }
+ else if (surround_space && ((r&0xFF)==PT_WOOD) && (1>rand()%20) && (abs(rx+ry)<=2) && (sim->VINE_MODE || parts[i].tmp==1) )
+ {
+ int nnx = rand()%3 -1;
+ int nny = rand()%3 -1;
+ if (x+rx+nnx>=0 && y+ry+nny>0 && x+rx+nnx<XRES && y+ry+nny<YRES && (nnx || nny))
+ {
+ if (pmap[y+ry+nny][x+rx+nnx])
+ continue;
+ np = sim->create_part(-1,x+rx+nnx,y+ry+nny,PT_VINE);
+ if (np<0) continue;
+ parts[np].temp = parts[i].temp;
+ }
+ }
+ }
+ if (parts[i].life==2)
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ sim->create_part(-1,x+rx,y+ry,PT_O2);
+ }
+ parts[i].life = 0;
+ }
+ if (parts[i].temp > 350 && parts[i].temp > parts[i].tmp2)
+ parts[i].tmp2 = (int)parts[i].temp;
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_PLNT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PLNT::graphics(GRAPHICS_FUNC_ARGS)
+{
+ float maxtemp = std::max((float)cpart->tmp2, cpart->temp);
+ if (maxtemp > 300)
+ {
+ *colr += (int)restrict_flt((maxtemp-300)/5,0,58);
+ *colg -= (int)restrict_flt((maxtemp-300)/2,0,102);
+ *colb += (int)restrict_flt((maxtemp-300)/5,0,70);
+ }
+ if (maxtemp < 273)
+ {
+ *colg += (int)restrict_flt((273-maxtemp)/4,0,255);
+ *colb += (int)restrict_flt((273-maxtemp)/1.5,0,255);
+ }
+ return 0;
+}
+
+
+Element_PLNT::~Element_PLNT() {} \ No newline at end of file
diff --git a/src/simulation/elements/PLSM.cpp b/src/simulation/elements/PLSM.cpp
new file mode 100644
index 0000000..4812b84
--- /dev/null
+++ b/src/simulation/elements/PLSM.cpp
@@ -0,0 +1,70 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PLSM PT_PLSM 49
+Element_PLSM::Element_PLSM()
+{
+ Identifier = "DEFAULT_PT_PLSM";
+ Name = "PLSM";
+ Colour = PIXPACK(0xBB99FF);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 0.9f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.20f;
+ Collision = 0.0f;
+ Gravity = -0.1f;
+ Diffusion = 0.30f;
+ HotAir = 0.001f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 1;
+
+ Temperature = 10000.0f +273.15f;
+ HeatConduct = 5;
+ Description = "Plasma, extremely hot.";
+
+ State = ST_NONE;
+ Properties = TYPE_GAS|PROP_LIFE_DEC|PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_FIRE::update;
+ Graphics = &Element_PLSM::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PLSM static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PLSM::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int caddress = restrict_flt(restrict_flt((float)cpart->life, 0.0f, 200.0f)*3, 0.0f, (200.0f*3)-3);
+ *colr = (unsigned char)ren->plasma_data[caddress];
+ *colg = (unsigned char)ren->plasma_data[caddress+1];
+ *colb = (unsigned char)ren->plasma_data[caddress+2];
+
+ *firea = 255;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+
+ *pixel_mode = PMODE_GLOW | PMODE_ADD; //Clear default, don't draw pixel
+ *pixel_mode |= FIRE_ADD;
+ //Returning 0 means dynamic, do not cache
+ return 0;
+}
+
+
+Element_PLSM::~Element_PLSM() {} \ No newline at end of file
diff --git a/src/simulation/elements/PLUT.cpp b/src/simulation/elements/PLUT.cpp
new file mode 100644
index 0000000..c9b759a
--- /dev/null
+++ b/src/simulation/elements/PLUT.cpp
@@ -0,0 +1,60 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PLUT PT_PLUT 19
+Element_PLUT::Element_PLUT()
+{
+ Identifier = "DEFAULT_PT_PLUT";
+ Name = "PLUT";
+ Colour = PIXPACK(0x407020);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.4f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+4.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Heavy particles. Fissile. Generates neutrons under pressure.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_NEUTPENETRATE|PROP_RADIOACTIVE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PLUT::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_PLUT static int update(UPDATE_FUNC_ARGS)
+int Element_PLUT::update(UPDATE_FUNC_ARGS)
+ {
+ if (1>rand()%100 && ((int)(5.0f*sim->pv[y/CELL][x/CELL]))>(rand()%1000))
+ {
+ sim->create_part(i, x, y, PT_NEUT);
+ }
+ return 0;
+}
+
+
+Element_PLUT::~Element_PLUT() {} \ No newline at end of file
diff --git a/src/simulation/elements/PPIP.cpp b/src/simulation/elements/PPIP.cpp
new file mode 100644
index 0000000..03830a7
--- /dev/null
+++ b/src/simulation/elements/PPIP.cpp
@@ -0,0 +1,160 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PPIP PT_PPIP 161
+Element_PPIP::Element_PPIP()
+{
+ Identifier = "DEFAULT_PT_PPIP";
+ Name = "PPIP";
+ Colour = PIXPACK(0x444466);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = 273.15f;
+ HeatConduct = 0;
+ Description = "Powered version of PIPE, use PSCN/NSCN to Activate/Deactivate.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PIPE::update;
+ Graphics = &Element_PIPE::graphics;
+}
+
+#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
+
+//#TPT-Directive ElementHeader Element_PPIP static int ppip_changed
+int Element_PPIP::ppip_changed = 0;
+
+//#TPT-Directive ElementHeader Element_PPIP static void flood_trigger(Simulation * sim, int x, int y, int sparkedBy)
+void Element_PPIP::flood_trigger(Simulation * sim, int x, int y, int sparkedBy)
+{
+ int coord_stack_limit = XRES*YRES;
+ unsigned short (*coord_stack)[2];
+ int coord_stack_size = 0;
+ int x1, x2;
+
+ Particle * parts = sim->parts;
+ int (*pmap)[XRES] = sim->pmap;
+
+ // Separate flags for on and off in case PPIP is sparked by PSCN and NSCN on the same frame
+ // - then PSCN can override NSCN and behaviour is not dependent on particle order
+ int prop = 0;
+ if (sparkedBy==PT_PSCN) prop = PPIP_TMPFLAG_TRIGGER_ON << 3;
+ else if (sparkedBy==PT_NSCN) prop = PPIP_TMPFLAG_TRIGGER_OFF << 3;
+ else if (sparkedBy==PT_INST) prop = PPIP_TMPFLAG_TRIGGER_REVERSE << 3;
+
+ if (prop==0 || (pmap[y][x]&0xFF)!=PT_PPIP || (parts[pmap[y][x]>>8].tmp & prop))
+ return;
+
+ coord_stack = new unsigned short[coord_stack_limit][2];
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y;
+ coord_stack_size++;
+
+ do
+ {
+ coord_stack_size--;
+ x = coord_stack[coord_stack_size][0];
+ y = coord_stack[coord_stack_size][1];
+ x1 = x2 = x;
+ // go left as far as possible
+ while (x1>=CELL)
+ {
+ if ((pmap[y][x1-1]&0xFF)!=PT_PPIP)
+ {
+ break;
+ }
+ x1--;
+ }
+ // go right as far as possible
+ while (x2<XRES-CELL)
+ {
+ if ((pmap[y][x2+1]&0xFF)!=PT_PPIP)
+ {
+ break;
+ }
+ x2++;
+ }
+ // fill span
+ for (x=x1; x<=x2; x++)
+ {
+ if (!(parts[pmap[y][x]>>8].tmp & prop))
+ ppip_changed = 1;
+ parts[pmap[y][x]>>8].tmp |= prop;
+ }
+
+ // add adjacent pixels to stack
+ // +-1 to x limits to include diagonally adjacent pixels
+ // Don't need to check x bounds here, because already limited to [CELL, XRES-CELL]
+ if (y>=CELL+1)
+ for (x=x1-1; x<=x2+1; x++)
+ if ((pmap[y-1][x]&0xFF)==PT_PPIP && !(parts[pmap[y-1][x]>>8].tmp & prop))
+ {
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y-1;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ delete[] coord_stack;
+ return;
+ }
+ }
+ if (y<YRES-CELL-1)
+ for (x=x1-1; x<=x2+1; x++)
+ if ((pmap[y+1][x]&0xFF)==PT_PPIP && !(parts[pmap[y+1][x]>>8].tmp & prop))
+ {
+ coord_stack[coord_stack_size][0] = x;
+ coord_stack[coord_stack_size][1] = y+1;
+ coord_stack_size++;
+ if (coord_stack_size>=coord_stack_limit)
+ {
+ delete[] coord_stack;
+ return;
+ }
+ }
+ } while (coord_stack_size>0);
+ delete[] coord_stack;
+}
+
+Element_PPIP::~Element_PPIP() {}
diff --git a/src/simulation/elements/PQRT.cpp b/src/simulation/elements/PQRT.cpp
new file mode 100644
index 0000000..8c51947
--- /dev/null
+++ b/src/simulation/elements/PQRT.cpp
@@ -0,0 +1,168 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PQRT PT_PQRT 133
+Element_PQRT::Element_PQRT()
+{
+ Identifier = "DEFAULT_PT_PQRT";
+ Name = "PQRT";
+ Colour = PIXPACK(0x88BBBB);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.27f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 3;
+ Description = "Broken quartz.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART| PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 2573.15f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_PQRT::update;
+ Graphics = &Element_PQRT::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PQRT static int update(UPDATE_FUNC_ARGS)
+int Element_PQRT::update(UPDATE_FUNC_ARGS)
+ {
+ int r, tmp, trade, rx, ry, np, t;
+ t = parts[i].type;
+ if (t == PT_QRTZ)
+ {
+ parts[i].pavg[0] = parts[i].pavg[1];
+ parts[i].pavg[1] = sim->pv[y/CELL][x/CELL];
+ if (parts[i].pavg[1]-parts[i].pavg[0] > 0.05*(parts[i].temp/3) || parts[i].pavg[1]-parts[i].pavg[0] < -0.05*(parts[i].temp/3))
+ {
+ sim->part_change_type(i,x,y,PT_PQRT);
+ }
+ }
+ // absorb SLTW
+ if (parts[i].ctype!=-1)
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ else if ((r&0xFF)==PT_SLTW && (1>rand()%2500))
+ {
+ sim->kill_part(r>>8);
+ parts[i].ctype ++;
+ }
+ }
+ // grow if absorbed SLTW
+ if (parts[i].ctype>0)
+ {
+ for ( trade = 0; trade<5; trade ++)
+ {
+ rx = rand()%3-1;
+ ry = rand()%3-1;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r && parts[i].ctype!=0)
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_QRTZ);
+ if (np>-1)
+ {
+ parts[np].tmp = parts[i].tmp;
+ parts[i].ctype--;
+ if (5>rand()%10)
+ {
+ parts[np].ctype=-1;//dead qrtz
+ }
+ else if (!parts[i].ctype && 1>rand()%15)
+ {
+ parts[i].ctype=-1;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ // diffuse absorbed SLTW
+ if (parts[i].ctype>0)
+ {
+ for ( trade = 0; trade<9; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==t && (parts[i].ctype>parts[r>>8].ctype) && parts[r>>8].ctype>=0 )//diffusion
+ {
+ tmp = parts[i].ctype - parts[r>>8].ctype;
+ if (tmp ==1)
+ {
+ parts[r>>8].ctype ++;
+ parts[i].ctype --;
+ break;
+ }
+ if (tmp>0)
+ {
+ parts[r>>8].ctype += tmp/2;
+ parts[i].ctype -= tmp/2;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PQRT static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PQRT::graphics(GRAPHICS_FUNC_ARGS)
+ //QRTZ and PQRT
+{
+ int t = cpart->type, z = cpart->tmp - 5;//speckles!
+ /*if (cpart->temp>(ptransitions[t].thv-800.0f))//hotglow for quartz
+ {
+ float frequency = 3.1415/(2*ptransitions[t].thv-(ptransitions[t].thv-800.0f));
+ int q = (cpart->temp>ptransitions[t].thv)?ptransitions[t].thv-(ptransitions[t].thv-800.0f):cpart->temp-(ptransitions[t].thv-800.0f);
+ *colr += sin(frequency*q) * 226 + (z * 16);
+ *colg += sin(frequency*q*4.55 +3.14) * 34 + (z * 16);
+ *colb += sin(frequency*q*2.22 +3.14) * 64 + (z * 16);
+ }
+ else*/
+ {
+ *colr += z * 16;
+ *colg += z * 16;
+ *colb += z * 16;
+ }
+ return 0;
+}
+
+
+Element_PQRT::~Element_PQRT() {} \ No newline at end of file
diff --git a/src/simulation/elements/PRTI.cpp b/src/simulation/elements/PRTI.cpp
new file mode 100644
index 0000000..8383d90
--- /dev/null
+++ b/src/simulation/elements/PRTI.cpp
@@ -0,0 +1,140 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PRTI PT_PRTI 109
+Element_PRTI::Element_PRTI()
+{
+ Identifier = "DEFAULT_PT_PRTI";
+ Name = "PRTI";
+ Colour = PIXPACK(0xEB5917);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.005f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Portal IN. Things go in here, now with channels (same as WIFI)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PRTI::update;
+ Graphics = &Element_PRTI::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PRTI static int update(UPDATE_FUNC_ARGS)
+int Element_PRTI::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nnx, rx, ry, fe = 0;
+ int count =0;
+ parts[i].tmp = (int)((parts[i].temp-73.15f)/100+1);
+ if (parts[i].tmp>=CHANNELS) parts[i].tmp = CHANNELS-1;
+ else if (parts[i].tmp<0) parts[i].tmp = 0;
+ for (count=0; count<8; count++)
+ {
+ rx = sim->portal_rx[count];
+ ry = sim->portal_ry[count];
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ fe = 1;
+ if (!r || (r&0xFF)==PT_PRTI || (r&0xFF)==PT_PRTO || (!(sim->elements[r&0xFF].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) && (r&0xFF)!=PT_SPRK))
+ {
+ r = sim->photons[y+ry][x+rx];
+ if (!r || (r&0xFF)==PT_PRTI || (r&0xFF)==PT_PRTO || (!(sim->elements[r&0xFF].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY)) && (r&0xFF)!=PT_SPRK))
+ continue;
+ }
+
+ if ((r&0xFF)==PT_STKM || (r&0xFF)==PT_STKM2 || (r&0xFF)==PT_FIGH)
+ continue;// Handling these is a bit more complicated, and is done in STKM_interact()
+
+ if ((r&0xFF) == PT_SOAP)
+ sim->detach(r>>8);
+
+ for ( nnx=0; nnx<80; nnx++)
+ if (!sim->portalp[parts[i].tmp][count][nnx].type)
+ {
+ sim->portalp[parts[i].tmp][count][nnx] = parts[r>>8];
+ if ((r&0xFF)==PT_SPRK)
+ sim->part_change_type(r>>8,x+rx,y+ry,parts[r>>8].ctype);
+ else
+ sim->kill_part(r>>8);
+ fe = 1;
+ break;
+ }
+ }
+ }
+
+
+ if (fe) {
+ int orbd[4] = {0, 0, 0, 0}; //Orbital distances
+ int orbl[4] = {0, 0, 0, 0}; //Orbital locations
+ if (!sim->parts[i].life) parts[i].life = rand()*rand()*rand();
+ if (!sim->parts[i].ctype) parts[i].ctype = rand()*rand()*rand();
+ sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl);
+ for (r = 0; r < 4; r++) {
+ if (orbd[r]>1) {
+ orbd[r] -= 12;
+ if (orbd[r]<1) {
+ orbd[r] = (rand()%128)+128;
+ orbl[r] = rand()%255;
+ } else {
+ orbl[r] += 2;
+ orbl[r] = orbl[r]%255;
+ }
+ } else {
+ orbd[r] = (rand()%128)+128;
+ orbl[r] = rand()%255;
+ }
+ }
+ sim->orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl);
+ } else {
+ parts[i].life = 0;
+ parts[i].ctype = 0;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PRTI static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PRTI::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 8;
+ *firer = 255;
+ *fireg = 0;
+ *fireb = 0;
+ *pixel_mode |= EFFECT_DBGLINES;
+ *pixel_mode |= EFFECT_GRAVIN;
+ *pixel_mode &= ~PMODE;
+ *pixel_mode |= PMODE_ADD;
+ return 1;
+}
+
+
+Element_PRTI::~Element_PRTI() {}
diff --git a/src/simulation/elements/PRTO.cpp b/src/simulation/elements/PRTO.cpp
new file mode 100644
index 0000000..b4554ec
--- /dev/null
+++ b/src/simulation/elements/PRTO.cpp
@@ -0,0 +1,177 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PRTO PT_PRTO 110
+Element_PRTO::Element_PRTO()
+{
+ Identifier = "DEFAULT_PT_PRTO";
+ Name = "PRTO";
+ Colour = PIXPACK(0x0020EB);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.005f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Portal OUT. Things come out here, now with channels (same as WIFI)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PRTO::update;
+ Graphics = &Element_PRTO::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PRTO static int update(UPDATE_FUNC_ARGS)
+int Element_PRTO::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nnx, rx, ry, np, fe = 0;
+ int count = 0;
+ parts[i].tmp = (int)((parts[i].temp-73.15f)/100+1);
+ if (parts[i].tmp>=CHANNELS) parts[i].tmp = CHANNELS-1;
+ else if (parts[i].tmp<0) parts[i].tmp = 0;
+ for (count=0; count<8; count++)
+ {
+ rx = sim->portal_rx[count];
+ ry = sim->portal_ry[count];
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ fe = 1;
+ if (r)
+ continue;
+ if (!r)
+ {
+ for ( nnx =0 ; nnx<80; nnx++)
+ {
+ int randomness = (count + rand()%3-1 + 4)%8;//add -1,0,or 1 to count
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_SPRK)// TODO: make it look better, spark creation
+ {
+ sim->create_part(-1,x+1,y,PT_SPRK);
+ sim->create_part(-1,x+1,y+1,PT_SPRK);
+ sim->create_part(-1,x+1,y-1,PT_SPRK);
+ sim->create_part(-1,x,y-1,PT_SPRK);
+ sim->create_part(-1,x,y+1,PT_SPRK);
+ sim->create_part(-1,x-1,y+1,PT_SPRK);
+ sim->create_part(-1,x-1,y,PT_SPRK);
+ sim->create_part(-1,x-1,y-1,PT_SPRK);
+ sim->portalp[parts[i].tmp][randomness][nnx] = sim->emptyparticle;
+ break;
+ }
+ else if (sim->portalp[parts[i].tmp][randomness][nnx].type)
+ {
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_STKM)
+ sim->player.spwn = 0;
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_STKM2)
+ sim->player2.spwn = 0;
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_FIGH)
+ {
+ sim->fighcount--;
+ sim->fighters[(unsigned char)sim->portalp[parts[i].tmp][randomness][nnx].tmp].spwn = 0;
+ }
+ np = sim->create_part(-1, x+rx, y+ry, sim->portalp[parts[i].tmp][randomness][nnx].type);
+ if (np<0)
+ {
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_STKM)
+ sim->player.spwn = 1;
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_STKM2)
+ sim->player2.spwn = 1;
+ if (sim->portalp[parts[i].tmp][randomness][nnx].type==PT_FIGH)
+ {
+ sim->fighcount++;
+ sim->fighters[(unsigned char)sim->portalp[parts[i].tmp][randomness][nnx].tmp].spwn = 1;
+ }
+ continue;
+ }
+ if (parts[np].type==PT_FIGH)
+ {
+ // Release the fighters[] element allocated by create_part, the one reserved when the fighter went into the portal will be used
+ sim->fighters[(unsigned char)parts[np].tmp].spwn = 0;
+ sim->fighters[(unsigned char)sim->portalp[parts[i].tmp][randomness][nnx].tmp].spwn = 1;
+ }
+ parts[np] = sim->portalp[parts[i].tmp][randomness][nnx];
+ parts[np].x = x+rx;
+ parts[np].y = y+ry;
+ sim->portalp[parts[i].tmp][randomness][nnx] = sim->emptyparticle;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (fe) {
+ int orbd[4] = {0, 0, 0, 0}; //Orbital distances
+ int orbl[4] = {0, 0, 0, 0}; //Orbital locations
+ if (!sim->parts[i].life) parts[i].life = rand()*rand()*rand();
+ if (!sim->parts[i].ctype) parts[i].ctype = rand()*rand()*rand();
+ sim->orbitalparts_get(parts[i].life, parts[i].ctype, orbd, orbl);
+ for (r = 0; r < 4; r++) {
+ if (orbd[r]<254) {
+ orbd[r] += 16;
+ if (orbd[r]>254) {
+ orbd[r] = 0;
+ orbl[r] = rand()%255;
+ }
+ else
+ {
+ orbl[r] += 1;
+ orbl[r] = orbl[r]%255;
+ }
+ //orbl[r] += 1;
+ //orbl[r] = orbl[r]%255;
+ } else {
+ orbd[r] = 0;
+ orbl[r] = rand()%255;
+ }
+ }
+ sim->orbitalparts_set(&parts[i].life, &parts[i].ctype, orbd, orbl);
+ } else {
+ parts[i].life = 0;
+ parts[i].ctype = 0;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PRTO static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PRTO::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 8;
+ *firer = 0;
+ *fireg = 0;
+ *fireb = 255;
+ *pixel_mode |= EFFECT_DBGLINES;
+ *pixel_mode |= EFFECT_GRAVOUT;
+ *pixel_mode &= ~PMODE;
+ *pixel_mode |= PMODE_ADD;
+ return 1;
+}
+
+
+Element_PRTO::~Element_PRTO() {} \ No newline at end of file
diff --git a/src/simulation/elements/PSCN.cpp b/src/simulation/elements/PSCN.cpp
new file mode 100644
index 0000000..b074f7b
--- /dev/null
+++ b/src/simulation/elements/PSCN.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PSCN PT_PSCN 35
+Element_PSCN::Element_PSCN()
+{
+ Identifier = "DEFAULT_PT_PSCN";
+ Name = "PSCN";
+ Colour = PIXPACK(0x805050);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "P-Type Silicon, Will transfer current to any conductor.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1687.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_PSCN::~Element_PSCN() {} \ No newline at end of file
diff --git a/src/simulation/elements/PSTE.cpp b/src/simulation/elements/PSTE.cpp
new file mode 100644
index 0000000..6efea51
--- /dev/null
+++ b/src/simulation/elements/PSTE.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PSTE PT_PSTE 111
+Element_PSTE::Element_PSTE()
+{
+ Identifier = "DEFAULT_PT_PSTE";
+ Name = "PSTE";
+ Colour = PIXPACK(0xAA99AA);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 31;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Colloid, Hardens under pressure";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 0.5f;
+ HighPressureTransition = PT_PSTS;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 747.0f;
+ HighTemperatureTransition = PT_BRCK;
+
+ Update = NULL;
+
+}
+
+Element_PSTE::~Element_PSTE() {} \ No newline at end of file
diff --git a/src/simulation/elements/PSTS.cpp b/src/simulation/elements/PSTS.cpp
new file mode 100644
index 0000000..5dd331c
--- /dev/null
+++ b/src/simulation/elements/PSTS.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PSTS PT_PSTS 112
+Element_PSTS::Element_PSTS()
+{
+ Identifier = "DEFAULT_PT_PSTS";
+ Name = "PSTS";
+ Colour = PIXPACK(0x776677);
+ MenuVisible = 0;
+ MenuSection = SC_CRACKER;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.00f;
+ 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 = 20;
+
+ Weight = 100;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Solid form of PSTE, temporary";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = 0.5f;
+ LowPressureTransition = PT_PSTE;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_PSTS::~Element_PSTS() {} \ No newline at end of file
diff --git a/src/simulation/elements/PTCT.cpp b/src/simulation/elements/PTCT.cpp
new file mode 100644
index 0000000..bda58c7
--- /dev/null
+++ b/src/simulation/elements/PTCT.cpp
@@ -0,0 +1,58 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PTCT PT_PTCT 46
+Element_PTCT::Element_PTCT()
+{
+ Identifier = "DEFAULT_PT_PTCT";
+ Name = "PTCT";
+ Colour = PIXPACK(0x405050);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Semi-conductor. Only conducts electricity when cold (Less than 100C)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1414.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_PTCT::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_PTCT static int update(UPDATE_FUNC_ARGS)
+int Element_PTCT::update(UPDATE_FUNC_ARGS)
+ {
+ if (parts[i].temp>295.0f)
+ parts[i].temp -= 2.5f;
+ return 0;
+}
+
+
+Element_PTCT::~Element_PTCT() {} \ No newline at end of file
diff --git a/src/simulation/elements/PUMP.cpp b/src/simulation/elements/PUMP.cpp
new file mode 100644
index 0000000..2d62799
--- /dev/null
+++ b/src/simulation/elements/PUMP.cpp
@@ -0,0 +1,98 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PUMP PT_PUMP 97
+Element_PUMP::Element_PUMP()
+{
+ Identifier = "DEFAULT_PT_PUMP";
+ Name = "PUMP";
+ Colour = PIXPACK(0x0A0A3B);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ 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 = 10;
+
+ Weight = 100;
+
+ Temperature = 273.15f;
+ HeatConduct = 0;
+ Description = "Changes pressure to its temp when activated. (use HEAT/COOL).";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PUMP::update;
+ Graphics = &Element_PUMP::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PUMP static int update(UPDATE_FUNC_ARGS)
+int Element_PUMP::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ if (parts[i].life==10)
+ {
+ if (parts[i].temp>=256.0+273.15)
+ parts[i].temp=256.0+273.15;
+ if (parts[i].temp<= -256.0+273.15)
+ parts[i].temp = -256.0+273.15;
+
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if ((x+rx)-CELL>=0 && (y+ry)-CELL>0 && (x+rx)+CELL<XRES && (y+ry)+CELL<YRES && !(rx && ry))
+ {
+ sim->pv[(y/CELL)+ry][(x/CELL)+rx] += 0.1f*((parts[i].temp-273.15)-sim->pv[(y/CELL)+ry][(x/CELL)+rx]);
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_PUMP)
+ {
+ if (parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[r>>8].life==0)
+ parts[r>>8].life = 10;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PUMP static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PUMP::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int lifemod = ((cpart->life>10?10:cpart->life)*19);
+ *colb += lifemod;
+ return 0;
+}
+
+
+Element_PUMP::~Element_PUMP() {}
diff --git a/src/simulation/elements/PVOD.cpp b/src/simulation/elements/PVOD.cpp
new file mode 100644
index 0000000..267c7bd
--- /dev/null
+++ b/src/simulation/elements/PVOD.cpp
@@ -0,0 +1,91 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_PVOD PT_PVOD 84
+Element_PVOD::Element_PVOD()
+{
+ Identifier = "DEFAULT_PT_PVOD";
+ Name = "PVOD";
+ Colour = PIXPACK(0x792020);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. When activated, destroys entering particles";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_PVOD::update;
+ Graphics = &Element_PVOD::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_PVOD static int update(UPDATE_FUNC_ARGS)
+int Element_PVOD::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK && parts[r>>8].life>0 && parts[r>>8].life<4)
+ {
+ if (parts[r>>8].ctype==PT_PSCN)
+ parts[i].life = 10;
+ else if (parts[r>>8].ctype==PT_NSCN)
+ parts[i].life = 9;
+ }
+ if ((r&0xFF)==PT_PVOD)
+ {
+ if (parts[i].life==10&&parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[i].life==0&&parts[r>>8].life==10)
+ parts[i].life = 10;
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_PVOD static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_PVOD::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ int lifemod = ((cpart->life>10?10:cpart->life)*16);
+ *colr += lifemod;
+ return 0;
+}
+
+
+Element_PVOD::~Element_PVOD() {} \ No newline at end of file
diff --git a/src/simulation/elements/QRTZ.cpp b/src/simulation/elements/QRTZ.cpp
new file mode 100644
index 0000000..20aa97d
--- /dev/null
+++ b/src/simulation/elements/QRTZ.cpp
@@ -0,0 +1,168 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_QRTZ PT_QRTZ 132
+Element_QRTZ::Element_QRTZ()
+{
+ Identifier = "DEFAULT_PT_QRTZ";
+ Name = "QRTZ";
+ Colour = PIXPACK(0xAADDDD);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 3;
+ Description = "Quartz, breakable mineral. Conducts but becomes brittle at lower temperatures.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_HOT_GLOW|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 2573.15f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_QRTZ::update;
+ Graphics = &Element_QRTZ::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_QRTZ static int update(UPDATE_FUNC_ARGS)
+int Element_QRTZ::update(UPDATE_FUNC_ARGS)
+ {
+ int r, tmp, trade, rx, ry, np, t;
+ t = parts[i].type;
+ if (t == PT_QRTZ)
+ {
+ parts[i].pavg[0] = parts[i].pavg[1];
+ parts[i].pavg[1] = sim->pv[y/CELL][x/CELL];
+ if (parts[i].pavg[1]-parts[i].pavg[0] > 0.05*(parts[i].temp/3) || parts[i].pavg[1]-parts[i].pavg[0] < -0.05*(parts[i].temp/3))
+ {
+ sim->part_change_type(i,x,y,PT_PQRT);
+ }
+ }
+ // absorb SLTW
+ if (parts[i].ctype!=-1)
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ else if ((r&0xFF)==PT_SLTW && (1>rand()%2500))
+ {
+ sim->kill_part(r>>8);
+ parts[i].ctype ++;
+ }
+ }
+ // grow if absorbed SLTW
+ if (parts[i].ctype>0)
+ {
+ for ( trade = 0; trade<5; trade ++)
+ {
+ rx = rand()%3-1;
+ ry = rand()%3-1;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r && parts[i].ctype!=0)
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_QRTZ);
+ if (np>-1)
+ {
+ parts[np].tmp = parts[i].tmp;
+ parts[i].ctype--;
+ if (5>rand()%10)
+ {
+ parts[np].ctype=-1;//dead qrtz
+ }
+ else if (!parts[i].ctype && 1>rand()%15)
+ {
+ parts[i].ctype=-1;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+ // diffuse absorbed SLTW
+ if (parts[i].ctype>0)
+ {
+ for ( trade = 0; trade<9; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==t && (parts[i].ctype>parts[r>>8].ctype) && parts[r>>8].ctype>=0 )//diffusion
+ {
+ tmp = parts[i].ctype - parts[r>>8].ctype;
+ if (tmp ==1)
+ {
+ parts[r>>8].ctype ++;
+ parts[i].ctype --;
+ break;
+ }
+ if (tmp>0)
+ {
+ parts[r>>8].ctype += tmp/2;
+ parts[i].ctype -= tmp/2;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_QRTZ static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_QRTZ::graphics(GRAPHICS_FUNC_ARGS)
+ //QRTZ and PQRT
+{
+ int t = cpart->type, z = cpart->tmp - 5;//speckles!
+ /*if (cpart->temp>(ptransitions[t].thv-800.0f))//hotglow for quartz
+ {
+ float frequency = 3.1415/(2*ptransitions[t].thv-(ptransitions[t].thv-800.0f));
+ int q = (cpart->temp>ptransitions[t].thv)?ptransitions[t].thv-(ptransitions[t].thv-800.0f):cpart->temp-(ptransitions[t].thv-800.0f);
+ *colr += sin(frequency*q) * 226 + (z * 16);
+ *colg += sin(frequency*q*4.55 +3.14) * 34 + (z * 16);
+ *colb += sin(frequency*q*2.22 +3.14) * 64 + (z * 16);
+ }
+ else*/
+ {
+ *colr += z * 16;
+ *colg += z * 16;
+ *colb += z * 16;
+ }
+ return 0;
+}
+
+
+Element_QRTZ::~Element_QRTZ() {} \ No newline at end of file
diff --git a/src/simulation/elements/RBDM.cpp b/src/simulation/elements/RBDM.cpp
new file mode 100644
index 0000000..90a332b
--- /dev/null
+++ b/src/simulation/elements/RBDM.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_RBDM PT_RBDM 41
+Element_RBDM::Element_RBDM()
+{
+ Identifier = "DEFAULT_PT_RBDM";
+ Name = "RBDM";
+ Colour = PIXPACK(0xCCCCCC);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 1000;
+ Explosive = 1;
+ Meltable = 50;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 240;
+ Description = "Rubidium, explosive, especially on contact with water, low melting point";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 312.0f;
+ HighTemperatureTransition = PT_LRBD;
+
+ Update = NULL;
+
+}
+
+Element_RBDM::~Element_RBDM() {} \ No newline at end of file
diff --git a/src/simulation/elements/REPL.cpp b/src/simulation/elements/REPL.cpp
new file mode 100644
index 0000000..b2deaee
--- /dev/null
+++ b/src/simulation/elements/REPL.cpp
@@ -0,0 +1,73 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_REPL PT_REPL 160
+Element_REPL::Element_REPL()
+{
+ Identifier = "DEFAULT_PT_REPL";
+ Name = "RPEL";
+ Colour = PIXPACK(0x99CC00);
+ MenuVisible = 1;
+ MenuSection = SC_FORCE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = 20.0f+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Repel or attract particles based on temp value.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_REPL::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_REPL static int update(UPDATE_FUNC_ARGS)
+int Element_REPL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, ri;
+ for(ri = 0; ri <= 10; ri++)
+ {
+ rx = (rand()%20)-10;
+ ry = (rand()%20)-10;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ r = sim->photons[y+ry][x+rx];
+
+ if (r && !(sim->elements[r&0xFF].Properties & TYPE_SOLID)){
+ parts[r>>8].vx += isign(rx)*((parts[i].temp-273.15)/10.0f);
+ parts[r>>8].vy += isign(ry)*((parts[i].temp-273.15)/10.0f);
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_REPL::~Element_REPL() {} \ No newline at end of file
diff --git a/src/simulation/elements/RIME.cpp b/src/simulation/elements/RIME.cpp
new file mode 100644
index 0000000..1ff2fad
--- /dev/null
+++ b/src/simulation/elements/RIME.cpp
@@ -0,0 +1,77 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_RIME PT_RIME 91
+Element_RIME::Element_RIME()
+{
+ Identifier = "DEFAULT_PT_RIME";
+ Name = "RIME";
+ Colour = PIXPACK(0xCCCCCC);
+ MenuVisible = 1;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.00f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.00f;
+ Loss = 1.00f;
+ Collision = 0.00f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 100;
+
+ Temperature = 243.15f;
+ HeatConduct = 100;
+ Description = "Not quite Ice";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 273.15f;
+ HighTemperatureTransition = PT_WATR;
+
+ Update = &Element_RIME::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_RIME static int update(UPDATE_FUNC_ARGS)
+int Element_RIME::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ parts[i].vx = 0;
+ parts[i].vy = 0;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPRK)
+ {
+ sim->part_change_type(i,x,y,PT_FOG);
+ parts[i].life = rand()%50 + 60;
+ }
+ else if ((r&0xFF)==PT_FOG&&parts[r>>8].life>0)
+ {
+ sim->part_change_type(i,x,y,PT_FOG);
+ parts[i].life = parts[r>>8].life;
+ }
+ }
+ return 0;
+}
+
+
+Element_RIME::~Element_RIME() {} \ No newline at end of file
diff --git a/src/simulation/elements/SALT.cpp b/src/simulation/elements/SALT.cpp
new file mode 100644
index 0000000..a2e6274
--- /dev/null
+++ b/src/simulation/elements/SALT.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SALT PT_SALT 26
+Element_SALT::Element_SALT()
+{
+ Identifier = "DEFAULT_PT_SALT";
+ Name = "SALT";
+ Colour = PIXPACK(0xFFFFFF);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 5;
+ Hardness = 1;
+
+ Weight = 75;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 110;
+ Description = "Salt, dissolves in water.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1173.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_SALT::~Element_SALT() {} \ No newline at end of file
diff --git a/src/simulation/elements/SAND.cpp b/src/simulation/elements/SAND.cpp
new file mode 100644
index 0000000..a1d9c00
--- /dev/null
+++ b/src/simulation/elements/SAND.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SAND PT_SAND 44
+Element_SAND::Element_SAND()
+{
+ Identifier = "DEFAULT_PT_SAND";
+ Name = "SAND";
+ Colour = PIXPACK(0xFFD090);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 5;
+ Hardness = 1;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 150;
+ Description = "Sand, Heavy particles. Meltable.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1973.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_SAND::~Element_SAND() {} \ No newline at end of file
diff --git a/src/simulation/elements/SHLD1.cpp b/src/simulation/elements/SHLD1.cpp
new file mode 100644
index 0000000..605180a
--- /dev/null
+++ b/src/simulation/elements/SHLD1.cpp
@@ -0,0 +1,88 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SHLD1 PT_SHLD1 119
+Element_SHLD1::Element_SHLD1()
+{
+ Identifier = "DEFAULT_PT_SHLD1";
+ Name = "SHLD";
+ Colour = PIXPACK(0xAAAAAA);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Shield, spark it to grow";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 7.0f;
+ HighPressureTransition = PT_NONE;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SHLD1::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SHLD1 static int update(UPDATE_FUNC_ARGS)
+int Element_SHLD1::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nnx, nny, rx, ry;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ else if ((r&0xFF)==PT_SPRK&&parts[i].life==0)
+ {
+ if (55>rand()%200&&parts[i].life==0)
+ {
+ sim->part_change_type(i,x,y,PT_SHLD2);
+ parts[i].life = 7;
+ }
+ for ( nnx=-1; nnx<2; nnx++)
+ for ( nny=-1; nny<2; nny++)
+ {
+ if (!pmap[y+ry+nny][x+rx+nnx])
+ {
+ sim->create_part(-1,x+rx+nnx,y+ry+nny,PT_SHLD1);
+ //parts[pmap[y+ny+nny][x+nx+nnx]>>8].life=7;
+ }
+ }
+ }
+ else if ((r&0xFF)==PT_SHLD3&&4>rand()%10)
+ {
+ sim->part_change_type(i,x,y,PT_SHLD2);
+ parts[i].life = 7;
+ }
+ }
+ return 0;
+}
+
+
+
+Element_SHLD1::~Element_SHLD1() {} \ No newline at end of file
diff --git a/src/simulation/elements/SHLD2.cpp b/src/simulation/elements/SHLD2.cpp
new file mode 100644
index 0000000..c00e4c9
--- /dev/null
+++ b/src/simulation/elements/SHLD2.cpp
@@ -0,0 +1,91 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SHLD2 PT_SHLD2 120
+Element_SHLD2::Element_SHLD2()
+{
+ Identifier = "DEFAULT_PT_SHLD2";
+ Name = "SHD2";
+ Colour = PIXPACK(0x777777);
+ MenuVisible = 0;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Shield lvl 2";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 15.0f;
+ HighPressureTransition = PT_NONE;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SHLD2::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SHLD2 static int update(UPDATE_FUNC_ARGS)
+int Element_SHLD2::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nnx, nny, rx, ry, np;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r && parts[i].life>0)
+ sim->create_part(-1,x+rx,y+ry,PT_SHLD1);
+ if (!r)
+ continue;
+ else if ((r&0xFF)==PT_SPRK&&parts[i].life==0)
+ {
+ if (25>rand()%200&&parts[i].life==0)
+ {
+ sim->part_change_type(i,x,y,PT_SHLD3);
+ parts[i].life = 7;
+ }
+ for ( nnx=-1; nnx<2; nnx++)
+ for ( nny=-1; nny<2; nny++)
+ {
+ if (!pmap[y+ry+nny][x+rx+nnx])
+ {
+ np = sim->create_part(-1,x+rx+nnx,y+ry+nny,PT_SHLD1);
+ if (np<0) continue;
+ parts[np].life=7;
+ }
+ }
+ }
+ else if ((r&0xFF)==PT_SHLD4&&4>rand()%10)
+ {
+ sim->part_change_type(i,x,y,PT_SHLD3);
+ parts[i].life = 7;
+ }
+ }
+ return 0;
+}
+
+
+
+Element_SHLD2::~Element_SHLD2() {} \ No newline at end of file
diff --git a/src/simulation/elements/SHLD3.cpp b/src/simulation/elements/SHLD3.cpp
new file mode 100644
index 0000000..633a8c4
--- /dev/null
+++ b/src/simulation/elements/SHLD3.cpp
@@ -0,0 +1,101 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SHLD3 PT_SHLD3 121
+Element_SHLD3::Element_SHLD3()
+{
+ Identifier = "DEFAULT_PT_SHLD3";
+ Name = "SHD3";
+ Colour = PIXPACK(0x444444);
+ MenuVisible = 0;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Shield lvl 3";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 25.0f;
+ HighPressureTransition = PT_NONE;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SHLD3::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SHLD3 static int update(UPDATE_FUNC_ARGS)
+int Element_SHLD3::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nnx, nny, rx, ry, np;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ {
+ if (1>rand()%2500)
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_SHLD1);
+ if (np<0) continue;
+ parts[np].life=7;
+ sim->part_change_type(i,x,y,PT_SHLD2);
+ }
+ else
+ continue;
+
+ }
+ if ((r&0xFF)==PT_SHLD1 && parts[i].life>3)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SHLD2);
+ parts[r>>8].life=7;
+ }
+ else if ((r&0xFF)==PT_SPRK&&parts[i].life==0)
+ {
+ if (18>rand()%3000&&parts[i].life==0)
+ {
+ sim->part_change_type(i,x,y,PT_SHLD4);
+ parts[i].life = 7;
+ }
+ for ( nnx=-1; nnx<2; nnx++)
+ for ( nny=-1; nny<2; nny++)
+ {
+
+ if (!pmap[y+ry+nny][x+rx+nnx])
+ {
+ np = sim->create_part(-1,x+rx+nnx,y+ry+nny,PT_SHLD1);
+ if (np<0) continue;
+ parts[np].life=7;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+Element_SHLD3::~Element_SHLD3() {} \ No newline at end of file
diff --git a/src/simulation/elements/SHLD4.cpp b/src/simulation/elements/SHLD4.cpp
new file mode 100644
index 0000000..95c8ae4
--- /dev/null
+++ b/src/simulation/elements/SHLD4.cpp
@@ -0,0 +1,92 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SHLD4 PT_SHLD4 122
+Element_SHLD4::Element_SHLD4()
+{
+ Identifier = "DEFAULT_PT_SHLD4";
+ Name = "SHD4";
+ Colour = PIXPACK(0x212121);
+ MenuVisible = 0;
+ MenuSection = SC_CRACKER2;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Shield lvl 4";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 40.0f;
+ HighPressureTransition = PT_NONE;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SHLD4::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SHLD4 static int update(UPDATE_FUNC_ARGS)
+int Element_SHLD4::update(UPDATE_FUNC_ARGS)
+ {
+ int r, nnx, nny, rx, ry, np;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ {
+ if (1>rand()%5500)
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_SHLD1);
+ if (np<0) continue;
+ parts[np].life=7;
+ sim->part_change_type(i,x,y,PT_SHLD2);
+ }
+ else
+ continue;
+
+ }
+ if ((r&0xFF)==PT_SHLD2 && parts[i].life>3)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SHLD3);
+ parts[r>>8].life = 7;
+ }
+ else if ((r&0xFF)==PT_SPRK&&parts[i].life==0)
+ for ( nnx=-1; nnx<2; nnx++)
+ for ( nny=-1; nny<2; nny++)
+ {
+ if (!pmap[y+ry+nny][x+rx+nnx])
+ {
+ np = sim->create_part(-1,x+rx+nnx,y+ry+nny,PT_SHLD1);
+ if (np<0) continue;
+ parts[np].life=7;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_SHLD4::~Element_SHLD4() {} \ No newline at end of file
diff --git a/src/simulation/elements/SING.cpp b/src/simulation/elements/SING.cpp
new file mode 100644
index 0000000..78641a8
--- /dev/null
+++ b/src/simulation/elements/SING.cpp
@@ -0,0 +1,155 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SING PT_SING 131
+Element_SING::Element_SING()
+{
+ Identifier = "DEFAULT_PT_SING";
+ Name = "SING";
+ Colour = PIXPACK(0x242424);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.36f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.1f;
+ Gravity = 0.12f;
+ Diffusion = 0.00f;
+ HotAir = -0.001f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 86;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Singularity";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SING::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SING static int update(UPDATE_FUNC_ARGS)
+int Element_SING::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, cry, crx, rad, nxi, nxj, nb, j, spawncount;
+ int singularity = -parts[i].life;
+ float angle, v;
+
+ if (sim->pv[y/CELL][x/CELL]<singularity)
+ sim->pv[y/CELL][x/CELL] += 0.1f*(singularity-sim->pv[y/CELL][x/CELL]);
+ if (y+CELL<YRES && sim->pv[y/CELL+1][x/CELL]<singularity)
+ sim->pv[y/CELL+1][x/CELL] += 0.1f*(singularity-sim->pv[y/CELL+1][x/CELL]);
+ if (x+CELL<XRES)
+ {
+ sim->pv[y/CELL][x/CELL+1] += 0.1f*(singularity-sim->pv[y/CELL][x/CELL+1]);
+ if (y+CELL<YRES)
+ sim->pv[y/CELL+1][x/CELL+1] += 0.1f*(singularity-sim->pv[y/CELL+1][x/CELL+1]);
+ }
+ if (y-CELL>=0 && sim->pv[y/CELL-1][x/CELL]<singularity)
+ sim->pv[y/CELL-1][x/CELL] += 0.1f*(singularity-sim->pv[y/CELL-1][x/CELL]);
+ if (x-CELL>=0)
+ {
+ sim->pv[y/CELL][x/CELL-1] += 0.1f*(singularity-sim->pv[y/CELL][x/CELL-1]);
+ if (y-CELL>=0)
+ sim->pv[y/CELL-1][x/CELL-1] += 0.1f*(singularity-sim->pv[y/CELL-1][x/CELL-1]);
+ }
+ if (parts[i].life<1) {
+ //Pop!
+ for (rx=-1; rx<2; rx++) {
+ crx = (x/CELL)+rx;
+ for (ry=-1; ry<2; ry++) {
+ cry = (y/CELL)+ry;
+ if (cry >= 0 && crx >= 0 && crx < (XRES/CELL) && cry < (YRES/CELL)) {
+ sim->pv[cry][crx] += (float)parts[i].tmp;
+ }
+ }
+ }
+ spawncount = (parts[i].tmp>255)?255:parts[i].tmp;
+ if (spawncount>=1)
+ spawncount = spawncount/8;
+ spawncount = spawncount*spawncount*M_PI;
+ for (j=0;j<spawncount;j++)
+ {
+ switch(rand()%3)
+ {
+ case 0:
+ nb = sim->create_part(-3, x, y, PT_PHOT);
+ break;
+ case 1:
+ nb = sim->create_part(-3, x, y, PT_NEUT);
+ break;
+ case 2:
+ nb = sim->create_part(-3, x, y, PT_ELEC);
+ break;
+ }
+ if (nb!=-1) {
+ parts[nb].life = (rand()%300);
+ parts[nb].temp = MAX_TEMP/2;
+ angle = rand()*2.0f*M_PI/RAND_MAX;
+ v = (float)(rand())*5.0f/RAND_MAX;
+ parts[nb].vx = v*cosf(angle);
+ parts[nb].vy = v*sinf(angle);
+ }
+ else if (sim->pfree==-1)
+ break;//if we've run out of particles, stop trying to create them - saves a lot of lag on "sing bomb" saves
+ }
+ sim->kill_part(i);
+ return 1;
+ }
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_DMND&&33>=rand()/(RAND_MAX/100)+1)
+ {
+ if ((r&0xFF)==PT_SING && parts[r>>8].life >10)
+ {
+ if (parts[i].life+parts[r>>8].life > 255)
+ continue;
+ parts[i].life += parts[r>>8].life;
+ }
+ else
+ {
+ if (parts[i].life+3 > 255)
+ {
+ if (parts[r>>8].type!=PT_SING && 1>rand()%100)
+ {
+ int np;
+ np = sim->create_part(r>>8,x+rx,y+ry,PT_SING);
+ parts[np].life = rand()%50+60;
+ }
+ continue;
+ }
+ parts[i].life += 3;
+ parts[i].tmp++;
+ }
+ parts[i].temp = restrict_flt(parts[r>>8].temp+parts[i].temp, MIN_TEMP, MAX_TEMP);
+ sim->kill_part(r>>8);
+ }
+ }
+ return 0;
+}
+
+
+Element_SING::~Element_SING() {}
diff --git a/src/simulation/elements/SLTW.cpp b/src/simulation/elements/SLTW.cpp
new file mode 100644
index 0000000..c422a9f
--- /dev/null
+++ b/src/simulation/elements/SLTW.cpp
@@ -0,0 +1,81 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SLTW PT_SLTW 27
+Element_SLTW::Element_SLTW()
+{
+ Identifier = "DEFAULT_PT_SLTW";
+ Name = "SLTW";
+ Colour = PIXPACK(0x4050F0);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 35;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 75;
+ Description = "Saltwater, conducts electricity, difficult to freeze.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 252.05f;
+ LowTemperatureTransition = PT_ICEI;
+ HighTemperature = 383.0f;
+ HighTemperatureTransition = ST;
+
+ Update = &Element_SLTW::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SLTW static int update(UPDATE_FUNC_ARGS)
+int Element_SLTW::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SALT && 1>(rand()%10000))
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SLTW);
+ if ((r&0xFF)==PT_PLNT&&5>(rand()%1000))
+ sim->kill_part(r>>8);
+ if (((r&0xFF)==PT_RBDM||(r&0xFF)==PT_LRBD) && !sim->legacy_enable && parts[i].temp>(273.15f+12.0f) && 1>(rand()%500))
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = 4;
+ }
+ if ((r&0xFF)==PT_FIRE){
+ sim->kill_part(r>>8);
+ if(1>(rand()%150)){
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_SLTW::~Element_SLTW() {}
diff --git a/src/simulation/elements/SMKE.cpp b/src/simulation/elements/SMKE.cpp
new file mode 100644
index 0000000..a00eca2
--- /dev/null
+++ b/src/simulation/elements/SMKE.cpp
@@ -0,0 +1,68 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SMKE PT_SMKE 57
+Element_SMKE::Element_SMKE()
+{
+ Identifier = "DEFAULT_PT_SMKE";
+ Name = "SMKE";
+ Colour = PIXPACK(0x222222);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 0.9f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.97f;
+ Loss = 0.20f;
+ Collision = 0.0f;
+ Gravity = -0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.001f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+320.0f+273.15f;
+ HeatConduct = 88;
+ Description = "Smoke";
+
+ State = ST_SOLID;
+ Properties = TYPE_GAS|PROP_LIFE_DEC|PROP_LIFE_KILL_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 625.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+ Graphics = &Element_SMKE::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_SMKE static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_SMKE::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *colr = 55;
+ *colg = 55;
+ *colb = 55;
+
+ *firea = 75;
+ *firer = 55;
+ *fireg = 55;
+ *fireb = 55;
+
+ *pixel_mode = PMODE_NONE; //Clear default, don't draw pixel
+ *pixel_mode |= FIRE_BLEND;
+ //Returning 1 means static, cache as we please
+ return 1;
+}
+
+Element_SMKE::~Element_SMKE() {} \ No newline at end of file
diff --git a/src/simulation/elements/SNOW.cpp b/src/simulation/elements/SNOW.cpp
new file mode 100644
index 0000000..4e592f7
--- /dev/null
+++ b/src/simulation/elements/SNOW.cpp
@@ -0,0 +1,74 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SNOW PT_SNOW 16
+Element_SNOW::Element_SNOW()
+{
+ Identifier = "DEFAULT_PT_SNOW";
+ Name = "SNOW";
+ Colour = PIXPACK(0xC0E0FF);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.90f;
+ Collision = -0.1f;
+ Gravity = 0.05f;
+ Diffusion = 0.01f;
+ HotAir = -0.00005f* CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 50;
+
+ Temperature = R_TEMP-30.0f+273.15f;
+ HeatConduct = 46;
+ Description = "Light particles.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 273.0f;
+ HighTemperatureTransition = ST;
+
+ Update = &Element_SNOW::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SNOW static int update(UPDATE_FUNC_ARGS)
+int Element_SNOW::update(UPDATE_FUNC_ARGS)
+ { //currently used for snow as well
+ int r, rx, ry;
+ if (parts[i].ctype==PT_FRZW)//get colder if it is from FRZW
+ {
+ parts[i].temp = restrict_flt(parts[i].temp-1.0f, MIN_TEMP, MAX_TEMP);
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_SALT || (r&0xFF)==PT_SLTW) && 1>(rand()%1000))
+ {
+ sim->part_change_type(i,x,y,PT_SLTW);
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SLTW);
+ }
+ }
+ return 0;
+}
+
+
+Element_SNOW::~Element_SNOW() {}
diff --git a/src/simulation/elements/SOAP.cpp b/src/simulation/elements/SOAP.cpp
new file mode 100644
index 0000000..1d3a55b
--- /dev/null
+++ b/src/simulation/elements/SOAP.cpp
@@ -0,0 +1,291 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SOAP PT_SOAP 149
+Element_SOAP::Element_SOAP()
+{
+ Identifier = "DEFAULT_PT_SOAP";
+ Name = "SOAP";
+ Colour = PIXPACK(0xF5F5DC);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 35;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Soap. Creates bubbles.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_NEUTPENETRATE|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITL;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SOAP::update;
+ Graphics = &Element_SOAP::graphics;
+
+}
+
+//#TPT-Directive ElementHeader Element_SOAP static void attach(Particle * parts, int i1, int i2)
+void Element_SOAP::attach(Particle * parts, int i1, int i2)
+{
+ if (!(parts[i2].ctype&4))
+ {
+ parts[i1].ctype |= 2;
+ parts[i1].tmp = i2;
+
+ parts[i2].ctype |= 4;
+ parts[i2].tmp2 = i1;
+ }
+ else if (!(parts[i2].ctype&2))
+ {
+ parts[i1].ctype |= 4;
+ parts[i1].tmp2= i2;
+
+ parts[i2].ctype |= 2;
+ parts[i2].tmp = i1;
+ }
+}
+
+//#TPT-Directive ElementHeader Element_SOAP static int update(UPDATE_FUNC_ARGS)
+int Element_SOAP::update(UPDATE_FUNC_ARGS)
+
+{
+ int r, rx, ry, nr, ng, nb, na;
+ float tr, tg, tb, ta;
+ float blend;
+
+ //0x01 - bubble on/off
+ //0x02 - first mate yes/no
+ //0x04 - "back" mate yes/no
+
+ if (parts[i].ctype&1)
+ {
+ if (parts[i].temp>0)
+ {
+ if (parts[i].life<=0)
+ {
+ if ((parts[i].ctype&6) != 6 && (parts[i].ctype&6))
+ {
+ int target;
+
+ target = i;
+
+ while((parts[target].ctype&6) != 6 && (parts[target].ctype&6))
+ {
+ if (parts[target].ctype&2)
+ {
+ target = parts[target].tmp;
+ sim->detach(target);
+ }
+
+ if (parts[target].ctype&4)
+ {
+ target = parts[target].tmp2;
+ sim->detach(target);
+ }
+ }
+ }
+
+ if ((parts[i].ctype&6) != 6)
+ parts[i].ctype = 0;
+
+ if ((parts[i].ctype&6) == 6 && (parts[parts[i].tmp].ctype&6) == 6 && parts[parts[i].tmp].tmp == i)
+ sim->detach(i);
+ }
+
+ parts[i].vy -= 0.1f;
+
+ parts[i].vy *= 0.5f;
+ parts[i].vx *= 0.5f;
+ }
+
+ if(!(parts[i].ctype&2))
+ {
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+
+ if ((parts[r>>8].type == PT_SOAP) && (parts[r>>8].ctype&1) && !(parts[r>>8].ctype&4))
+ Element_SOAP::attach(parts, i, r>>8);
+ }
+ }
+ else
+ {
+ if (parts[i].life<=0)
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r && !sim->bmap[(y+ry)/CELL][(x+rx)/CELL])
+ continue;
+
+ if (parts[i].temp>0)
+ {
+ if (sim->bmap[(y+ry)/CELL][(x+rx)/CELL]
+ || (r && sim->elements[r&0xFF].State != ST_GAS
+ && (r&0xFF) != PT_SOAP && (r&0xFF) != PT_GLAS))
+ {
+ sim->detach(i);
+ continue;
+ }
+ }
+
+ if ((r&0xFF) == PT_SOAP && parts[r>>8].ctype == 1)
+ {
+ int buf;
+
+ buf = parts[i].tmp;
+
+ parts[i].tmp = r>>8;
+ parts[buf].tmp2 = r>>8;
+ parts[r>>8].tmp2 = i;
+ parts[r>>8].tmp = buf;
+ parts[r>>8].ctype = 7;
+ }
+
+ if ((r&0xFF) == PT_SOAP && parts[r>>8].ctype == 7 && parts[i].tmp != r>>8 && parts[i].tmp2 != r>>8)
+ {
+ int buf;
+
+ parts[parts[i].tmp].tmp2 = parts[r>>8].tmp2;
+ parts[parts[r>>8].tmp2].tmp = parts[i].tmp;
+ parts[r>>8].tmp2 = i;
+ parts[i].tmp = r>>8;
+ }
+ }
+ }
+
+ if(parts[i].ctype&2)
+ {
+ float d, dx, dy;
+
+ dx = parts[i].x - parts[parts[i].tmp].x;
+ dy = parts[i].y - parts[parts[i].tmp].y;
+
+ d = 9/(pow(dx, 2)+pow(dy, 2)+9)-0.5;
+
+ parts[parts[i].tmp].vx -= dx*d;
+ parts[parts[i].tmp].vy -= dy*d;
+
+ parts[i].vx += dx*d;
+ parts[i].vy += dy*d;
+
+ if ((parts[parts[i].tmp].ctype&2) && (parts[parts[i].tmp].ctype&1)
+ && (parts[parts[parts[i].tmp].tmp].ctype&2) && (parts[parts[parts[i].tmp].tmp].ctype&1))
+ {
+ int ii;
+
+ ii = parts[parts[parts[i].tmp].tmp].tmp;
+
+ dx = parts[ii].x - parts[parts[i].tmp].x;
+ dy = parts[ii].y - parts[parts[i].tmp].y;
+
+ d = 81/(pow(dx, 2)+pow(dy, 2)+81)-0.5;
+
+ parts[parts[i].tmp].vx -= dx*d*0.5f;
+ parts[parts[i].tmp].vy -= dy*d*0.5f;
+
+ parts[ii].vx += dx*d*0.5f;
+ parts[ii].vy += dy*d*0.5f;
+ }
+ }
+ }
+ else
+ {
+ if (sim->pv[y/CELL][x/CELL]>0.5f || sim->pv[y/CELL][x/CELL]<(-0.5f))
+ {
+ parts[i].ctype = 1;
+ parts[i].life = 10;
+ }
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+
+ if ((r&0xFF) == PT_OIL)
+ {
+ float ax, ay;
+
+ parts[i].vy -= 0.1f;
+
+ parts[i].vy *= 0.5f;
+ parts[i].vx *= 0.5f;
+
+ ax = (parts[i].vx + parts[r>>8].vx)/2;
+ ay = (parts[i].vy + parts[r>>8].vy)/2;
+
+ parts[i].vx = ax;
+ parts[i].vy = ay;
+ parts[r>>8].vx = ax;
+ parts[r>>8].vy = ay;
+ }
+ }
+ }
+
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_SOAP)
+ {
+ blend = 0.85f;
+ tr = (parts[r>>8].dcolour>>16)&0xFF;
+ tg = (parts[r>>8].dcolour>>8)&0xFF;
+ tb = (parts[r>>8].dcolour)&0xFF;
+ ta = (parts[r>>8].dcolour>>24)&0xFF;
+
+ nr = (tr*blend);
+ ng = (tg*blend);
+ nb = (tb*blend);
+ na = (ta*blend);
+
+ parts[r>>8].dcolour = nr<<16 | ng<<8 | nb | na<<24;
+ }
+ }
+
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_SOAP static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_SOAP::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *pixel_mode |= EFFECT_LINES;
+ return 1;
+}
+
+Element_SOAP::~Element_SOAP() {}
diff --git a/src/simulation/elements/SPAWN.cpp b/src/simulation/elements/SPAWN.cpp
new file mode 100644
index 0000000..85295f2
--- /dev/null
+++ b/src/simulation/elements/SPAWN.cpp
@@ -0,0 +1,60 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SPAWN PT_SPAWN 118
+Element_SPAWN::Element_SPAWN()
+{
+ Identifier = "DEFAULT_PT_SPAWN";
+ Name = "SPWN";
+ Colour = PIXPACK(0xAAAAAA);
+ MenuVisible = 0;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "STKM spawn point";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SPAWN::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SPAWN static int update(UPDATE_FUNC_ARGS)
+int Element_SPAWN::update(UPDATE_FUNC_ARGS)
+ {
+ if (!sim->player.spwn)
+ sim->create_part(-1, x, y, PT_STKM);
+
+ return 0;
+}
+
+
+
+Element_SPAWN::~Element_SPAWN() {} \ No newline at end of file
diff --git a/src/simulation/elements/SPAWN2.cpp b/src/simulation/elements/SPAWN2.cpp
new file mode 100644
index 0000000..3cc048b
--- /dev/null
+++ b/src/simulation/elements/SPAWN2.cpp
@@ -0,0 +1,60 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SPAWN2 PT_SPAWN2 117
+Element_SPAWN2::Element_SPAWN2()
+{
+ Identifier = "DEFAULT_PT_SPAWN2";
+ Name = "SPWN2";
+ Colour = PIXPACK(0xAAAAAA);
+ MenuVisible = 0;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "STK2 spawn point";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SPAWN2::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_SPAWN2 static int update(UPDATE_FUNC_ARGS)
+int Element_SPAWN2::update(UPDATE_FUNC_ARGS)
+ {
+ if (!sim->player2.spwn)
+ sim->create_part(-1, x, y, PT_STKM2);
+
+ return 0;
+}
+
+
+
+Element_SPAWN2::~Element_SPAWN2() {} \ No newline at end of file
diff --git a/src/simulation/elements/SPNG.cpp b/src/simulation/elements/SPNG.cpp
new file mode 100644
index 0000000..95dd12f
--- /dev/null
+++ b/src/simulation/elements/SPNG.cpp
@@ -0,0 +1,198 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SPNG PT_SPNG 90
+Element_SPNG::Element_SPNG()
+{
+ Identifier = "DEFAULT_PT_SPNG";
+ Name = "SPNG";
+ Colour = PIXPACK(0xFFBE30);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.00f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.00f;
+ Loss = 0.00f;
+ Collision = 0.00f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 20;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "A sponge, absorbs water.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 2730.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_SPNG::update;
+ Graphics = &Element_SPNG::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_SPNG static int update(UPDATE_FUNC_ARGS)
+int Element_SPNG::update(UPDATE_FUNC_ARGS)
+ {
+ int r, trade, rx, ry, tmp, np;
+ int limit = 50;
+ if (parts[i].life<limit && sim->pv[y/CELL][x/CELL]<=3&&sim->pv[y/CELL][x/CELL]>=-3&&parts[i].temp<=374.0f)
+ {
+ int absorbChanceDenom = parts[i].life*10000/limit + 500;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_WATR || (r&0xFF)==PT_DSTW || (r&0xFF)==PT_FRZW) && parts[i].life<limit && 500>rand()%absorbChanceDenom)
+ {
+ parts[i].life++;
+ sim->kill_part(r>>8);
+ }
+ if ((r&0xFF)==PT_SLTW && parts[i].life<limit && 50>rand()%absorbChanceDenom)
+ {
+ parts[i].life++;
+ if (rand()%4)
+ sim->kill_part(r>>8);
+ else
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_SALT);
+ }
+ if ((r&0xFF)==PT_CBNW && parts[i].life<limit && 100>rand()%absorbChanceDenom)
+ {
+ parts[i].life++;
+ sim->part_change_type(r>>8, x+rx, y+ry, PT_CO2);
+ }
+ if ((r&0xFF)==PT_PSTE && parts[i].life<limit && 20>rand()%absorbChanceDenom)
+ {
+ parts[i].life++;
+ sim->create_part(r>>8, x+rx, y+ry, PT_CLST);
+ }
+ }
+ }
+ else
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((!r)&&parts[i].life>=1)//if nothing then create water
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_WATR);
+ if (np>-1) parts[i].life--;
+ }
+ }
+ for ( trade = 0; trade<9; trade ++)
+ {
+ rx = rand()%5-2;
+ ry = rand()%5-2;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SPNG&&(parts[i].life>parts[r>>8].life)&&parts[i].life>0)//diffusion
+ {
+ tmp = parts[i].life - parts[r>>8].life;
+ if (tmp ==1)
+ {
+ parts[r>>8].life ++;
+ parts[i].life --;
+ trade = 9;
+ }
+ else if (tmp>0)
+ {
+ parts[r>>8].life += tmp/2;
+ parts[i].life -= tmp/2;
+ trade = 9;
+ }
+ }
+ }
+ }
+ tmp = 0;
+ if (parts[i].life>0)
+ {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_FIRE)
+ {
+ tmp++;
+ if (parts[r>>8].life>60)
+ parts[r>>8].life -= parts[r>>8].life/60;
+ else if (parts[r>>8].life>2)
+ parts[r>>8].life--;
+ }
+ }
+ }
+ if (tmp && parts[i].life>3)
+ parts[i].life -= parts[i].life/3;
+ if (tmp>1)
+ tmp = tmp/2;
+ if (tmp || parts[i].temp>=374)
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((!r)&&parts[i].life>=1)//if nothing then create steam
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_WTRV);
+ if (np>-1)
+ {
+ parts[np].temp = parts[i].temp;
+ tmp--;
+ parts[i].life--;
+ parts[i].temp -= 20.0f;
+ }
+ }
+ }
+ if (tmp>0)
+ {
+ if (parts[i].life>tmp)
+ parts[i].life -= tmp;
+ else
+ parts[i].life = 0;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_SPNG static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_SPNG::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *colr -= cpart->life*15;
+ *colg -= cpart->life*15;
+ *colb -= cpart->life*15;
+ if (*colr<=50)
+ *colr = 50;
+ if (*colg<=50)
+ *colg = 50;
+ if (*colb<=20)
+ *colb = 20;
+ return 0;
+}
+
+
+Element_SPNG::~Element_SPNG() {}
diff --git a/src/simulation/elements/SPRK.cpp b/src/simulation/elements/SPRK.cpp
new file mode 100644
index 0000000..09638ff
--- /dev/null
+++ b/src/simulation/elements/SPRK.cpp
@@ -0,0 +1,290 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SPRK PT_SPRK 15
+Element_SPRK::Element_SPRK()
+{
+ Identifier = "DEFAULT_PT_SPRK";
+ Name = "SPRK";
+ Colour = PIXPACK(0xFFFF80);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.001f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Electricity. Conducted by metal and water.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SPRK::update;
+ Graphics = &Element_SPRK::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_SPRK static int update(UPDATE_FUNC_ARGS)
+int Element_SPRK::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, rt, conduct_sprk, nearp, pavg, ct = parts[i].ctype;
+ Element_FIRE::update(UPDATE_FUNC_SUBCALL_ARGS);
+
+ if (parts[i].life<=0)
+ {
+ if (ct==PT_WATR||ct==PT_SLTW||ct==PT_PSCN||ct==PT_NSCN||ct==PT_ETRD||ct==PT_INWR)
+ parts[i].temp = R_TEMP + 273.15f;
+ if (ct<=0 || ct>=PT_NUM || !sim->elements[parts[i].ctype].Enabled)
+ ct = PT_METL;
+ sim->part_change_type(i,x,y,ct);
+ parts[i].ctype = PT_NONE;
+ parts[i].life = 4;
+ if (ct == PT_WATR)
+ parts[i].life = 64;
+ if (ct == PT_SLTW)
+ parts[i].life = 54;
+ if (ct == PT_SWCH)
+ parts[i].life = 14;
+ return 0;
+ }
+ if (ct==PT_SPRK)
+ {
+ sim->kill_part(i);
+ return 1;
+ }
+ else if (ct==PT_NTCT || ct==PT_PTCT)
+ {
+ Element_NTCT::update(UPDATE_FUNC_SUBCALL_ARGS);
+ }
+ else if (ct==PT_ETRD&&parts[i].life==1)
+ {
+ nearp = sim->nearest_part(i, PT_ETRD, -1);
+ if (nearp!=-1 && sim->parts_avg(i, nearp, PT_INSL)!=PT_INSL)
+ {
+ sim->CreateLine(x, y, (int)(parts[nearp].x+0.5f), (int)(parts[nearp].y+0.5f), 0, 0, PT_PLSM, 0);
+ sim->part_change_type(i,x,y,ct);
+ ct = parts[i].ctype = PT_NONE;
+ parts[i].life = 20;
+ sim->part_change_type(nearp,(int)(parts[nearp].x+0.5f),(int)(parts[nearp].y+0.5f),PT_SPRK);
+ parts[nearp].life = 9;
+ parts[nearp].ctype = PT_ETRD;
+ }
+ }
+ else if (ct==PT_NBLE&&parts[i].life<=1&&parts[i].tmp!=1)
+ {
+ parts[i].life = rand()%150+50;
+ sim->part_change_type(i,x,y,PT_PLSM);
+ parts[i].ctype = PT_NBLE;
+ if (parts[i].temp > 5273.15)
+ parts[i].tmp |= 4;
+ parts[i].temp = 3500;
+ sim->pv[y/CELL][x/CELL] += 1;
+ }
+ else if (ct==PT_TESC) // tesla coil code
+ {
+ if (parts[i].tmp>300)
+ parts[i].tmp=300;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (r)
+ continue;
+ if (parts[i].tmp>4 && rand()%(parts[i].tmp*parts[i].tmp/20+6)==0)
+ {
+ int p = sim->create_part(-1, x+rx*2, y+ry*2, PT_LIGH);
+ if (p!=-1)
+ {
+ parts[p].life=rand()%(2+parts[i].tmp/15)+parts[i].tmp/7;
+ if (parts[i].life>60)
+ parts[i].life=60;
+ parts[p].temp=parts[p].life*parts[i].tmp/2.5;
+ parts[p].tmp2=1;
+ parts[p].tmp=atan2(-ry, (float)rx)/M_PI*360;
+ parts[i].temp-=parts[i].tmp*2+parts[i].temp/5; // slight self-cooling
+ if (fabs(sim->pv[y/CELL][x/CELL])!=0.0f)
+ {
+ if (fabs(sim->pv[y/CELL][x/CELL])<=0.5f)
+ sim->pv[y/CELL][x/CELL]=0;
+ else
+ sim->pv[y/CELL][x/CELL]-=(sim->pv[y/CELL][x/CELL]>0)?0.5:-0.5;
+ }
+ }
+ }
+ }
+ }
+ else if (ct==PT_IRON) {
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF) == PT_DSTW && 30>(rand()/(RAND_MAX/1000))) ||
+ ((r&0xFF) == PT_SLTW && 30>(rand()/(RAND_MAX/1000))) ||
+ ((r&0xFF) == PT_WATR && 30>(rand()/(RAND_MAX/1000))))
+ {
+ if (rand()<RAND_MAX/3)
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_O2);
+ else
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_H2);
+ }
+ }
+ }
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ conduct_sprk = 1;
+
+
+ pavg = sim->parts_avg(r>>8, i,PT_INSL);
+ if ((rt==PT_SWCH||(rt==PT_SPRK&&parts[r>>8].ctype==PT_SWCH)) && pavg!=PT_INSL && parts[i].life<4) // make sparked SWCH turn off correctly
+ {
+ if (rt==PT_SWCH&&ct==PT_PSCN&&parts[r>>8].life<10) {
+ parts[r>>8].life = 10;
+ }
+ if (ct==PT_NSCN) {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SWCH);
+ parts[r>>8].ctype = PT_NONE;
+ parts[r>>8].life = 9;
+ }
+ }
+ else if ((ct==PT_PSCN||ct==PT_NSCN) && (rt==PT_PUMP||rt==PT_GPMP||rt==PT_HSWC||rt==PT_PBCN) && parts[i].life<4) // PROP_PTOGGLE, Maybe? We seem to use 2 different methods for handling actived elements, this one seems better. Yes, use this one for new elements, PCLN is different for compatibility with existing saves
+ {
+ if (ct==PT_PSCN) parts[r>>8].life = 10;
+ else if (ct==PT_NSCN && parts[r>>8].life>=10) parts[r>>8].life = 9;
+ }
+ else if ((ct==PT_PSCN||ct==PT_NSCN) && (rt==PT_LCRY&&abs(rx)<2&&abs(ry)<2) && parts[i].life<4)
+ {
+ if (ct==PT_PSCN && parts[r>>8].tmp == 0) parts[r>>8].tmp = 2;
+ else if (ct==PT_NSCN && parts[r>>8].tmp == 3) parts[r>>8].tmp = 1;
+ }
+
+ if (rt == PT_PPIP && parts[i].life == 3 && pavg!=PT_INSL)
+ {
+ if (ct == PT_NSCN || ct == PT_PSCN || ct == PT_INST)
+ Element_PPIP::flood_trigger(sim, x+rx, y+ry, ct);
+ }
+
+ // ct = spark from material, rt = spark to material. Make conduct_sprk = 0 if conduction not allowed
+
+ if (pavg == PT_INSL) conduct_sprk = 0;
+ if (!((sim->elements[rt].Properties&PROP_CONDUCTS)||rt==PT_INST||rt==PT_QRTZ)) conduct_sprk = 0;
+ if (abs(rx)+abs(ry)>=4 &&ct!=PT_SWCH&&rt!=PT_SWCH)
+ conduct_sprk = 0;
+
+
+ if (ct==PT_METL && (rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR||(rt==PT_SPRK&&(parts[r>>8].ctype==PT_NTCT||parts[r>>8].ctype==PT_PTCT))) && pavg!=PT_INSL && parts[i].life<4)
+ {
+ parts[r>>8].temp = 473.0f;
+ if (rt==PT_NTCT||rt==PT_PTCT)
+ conduct_sprk = 0;
+ }
+ if (ct==PT_NTCT && !(rt==PT_PSCN || rt==PT_NTCT || (rt==PT_NSCN&&parts[i].temp>373.0f)))
+ conduct_sprk = 0;
+ if (ct==PT_PTCT && !(rt==PT_PSCN || rt==PT_PTCT || (rt==PT_NSCN&&parts[i].temp<373.0f)))
+ conduct_sprk = 0;
+ if (ct==PT_INWR && !(rt==PT_NSCN || rt==PT_INWR || rt==PT_PSCN))
+ conduct_sprk = 0;
+ if (ct==PT_NSCN && rt==PT_PSCN)
+ conduct_sprk = 0;
+ if (ct==PT_ETRD && !(rt==PT_METL||rt==PT_ETRD||rt==PT_BMTL||rt==PT_BRMT||rt==PT_LRBD||rt==PT_RBDM||rt==PT_PSCN||rt==PT_NSCN))
+ conduct_sprk = 0;
+ if (ct==PT_INST&&rt!=PT_NSCN) conduct_sprk = 0;
+ if (ct==PT_SWCH && (rt==PT_PSCN||rt==PT_NSCN||rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR))
+ conduct_sprk = 0;
+ if (rt==PT_QRTZ && !((ct==PT_NSCN||ct==PT_METL||ct==PT_PSCN||ct==PT_QRTZ) && (parts[r>>8].temp<173.15||sim->pv[(y+ry)/CELL][(x+rx)/CELL]>8)))
+ conduct_sprk = 0;
+ if (rt==PT_NTCT && !(ct==PT_NSCN || ct==PT_NTCT || (ct==PT_PSCN&&parts[r>>8].temp>373.0f)))
+ conduct_sprk = 0;
+ if (rt==PT_PTCT && !(ct==PT_NSCN || ct==PT_PTCT || (ct==PT_PSCN&&parts[r>>8].temp<373.0f)))
+ conduct_sprk = 0;
+ if (rt==PT_INWR && !(ct==PT_NSCN || ct==PT_INWR || ct==PT_PSCN))
+ conduct_sprk = 0;
+ if (rt==PT_INST&&ct!=PT_PSCN)
+ conduct_sprk = 0;
+ if (rt == PT_NBLE && parts[r>>8].tmp == 1)
+ conduct_sprk = 0;
+
+ if (conduct_sprk) {
+ if (rt==PT_WATR||rt==PT_SLTW) {
+ if (parts[r>>8].life==0 && parts[i].life<3)
+ {
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ if (rt==PT_WATR) parts[r>>8].life = 6;
+ else parts[r>>8].life = 5;
+ parts[r>>8].ctype = rt;
+ }
+ }
+ else if (rt==PT_INST) {
+ if (parts[r>>8].life==0 && parts[i].life<4)
+ {
+ sim->FloodINST(x+rx,y+ry,PT_SPRK,PT_INST);//spark the wire
+ }
+ }
+ else if (parts[r>>8].life==0 && parts[i].life<4) {
+ parts[r>>8].life = 4;
+ parts[r>>8].ctype = rt;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ if (parts[r>>8].temp+10.0f<673.0f&&!sim->legacy_enable&&(rt==PT_METL||rt==PT_BMTL||rt==PT_BRMT||rt==PT_PSCN||rt==PT_NSCN||rt==PT_ETRD||rt==PT_NBLE||rt==PT_IRON))
+ parts[r>>8].temp = parts[r>>8].temp+10.0f;
+ }
+ else if (ct==PT_ETRD && parts[i].life==5)
+ {
+ sim->part_change_type(i,x,y,ct);
+ parts[i].ctype = PT_NONE;
+ parts[i].life = 20;
+ parts[r>>8].life = 4;
+ parts[r>>8].ctype = rt;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ }
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_SPRK static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_SPRK::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 80;
+ *firer = 170;
+ *fireg = 200;
+ *fireb = 220;
+ *pixel_mode |= FIRE_ADD;
+ return 1;
+}
+
+
+Element_SPRK::~Element_SPRK() {} \ No newline at end of file
diff --git a/src/simulation/elements/STKM.cpp b/src/simulation/elements/STKM.cpp
new file mode 100644
index 0000000..081720e
--- /dev/null
+++ b/src/simulation/elements/STKM.cpp
@@ -0,0 +1,557 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_STKM PT_STKM 55
+Element_STKM::Element_STKM()
+{
+ Identifier = "DEFAULT_PT_STKM";
+ Name = "STKM";
+ Colour = PIXPACK(0xFFE0A0);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.5f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.2f;
+ Loss = 1.0f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.00f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 50;
+
+ Temperature = R_TEMP+14.6f+273.15f;
+ HeatConduct = 0;
+ Description = "Stickman. Don't kill him!";
+
+ State = ST_NONE;
+ Properties = 0;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 620.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_STKM::update;
+ Graphics = &Element_STKM::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_STKM static int update(UPDATE_FUNC_ARGS)
+int Element_STKM::update(UPDATE_FUNC_ARGS)
+
+{
+ run_stickman(&sim->player, UPDATE_FUNC_SUBCALL_ARGS);
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_STKM static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_STKM::graphics(GRAPHICS_FUNC_ARGS)
+{
+ *colr = *colg = *colb = *cola = 0;
+ *pixel_mode = PSPEC_STICKMAN;
+ return 1;
+}
+
+#define INBOND(x, y) ((x)>=0 && (y)>=0 && (x)<XRES && (y)<YRES)
+
+//#TPT-Directive ElementHeader Element_STKM static int run_stickman(playerst* playerp, UPDATE_FUNC_ARGS)
+int Element_STKM::run_stickman(playerst* playerp, UPDATE_FUNC_ARGS) {
+ int r, rx, ry;
+ int t = parts[i].type;
+ float pp, d;
+ float dt = 0.9;///(FPSB*FPSB); //Delta time in square
+ float gvx, gvy;
+ float gx, gy, dl, dr;
+
+ if ((parts[i].ctype>0 && parts[i].ctype<PT_NUM && sim->elements[parts[i].ctype].Enabled && sim->elements[parts[i].ctype].Falldown>0) || parts[i].ctype==SPC_AIR || parts[i].ctype == PT_NEUT || parts[i].ctype == PT_PHOT || parts[i].ctype == PT_LIGH)
+ playerp->elem = parts[i].ctype;
+ playerp->frames++;
+
+ //Temperature handling
+ if (parts[i].temp<243)
+ parts[i].life -= 1;
+ if ((parts[i].temp<309.6f) && (parts[i].temp>=243))
+ parts[i].temp += 1;
+
+ //Death
+ if (parts[i].life<1 || (sim->pv[y/CELL][x/CELL]>=4.5f && playerp->elem != SPC_AIR) ) //If his HP is less that 0 or there is very big wind...
+ {
+ for (r=-2; r<=1; r++)
+ {
+ sim->create_part(-1, x+r, y-2, playerp->elem);
+ sim->create_part(-1, x+r+1, y+2, playerp->elem);
+ sim->create_part(-1, x-2, y+r+1, playerp->elem);
+ sim->create_part(-1, x+2, y+r, playerp->elem);
+ }
+ sim->kill_part(i); //Kill him
+ return 1;
+ }
+
+ //Follow gravity
+ gvx = gvy = 0.0f;
+ switch (sim->gravityMode)
+ {
+ default:
+ case 0:
+ gvy = 1;
+ break;
+ case 1:
+ gvy = gvx = 0.0f;
+ break;
+ case 2:
+ {
+ float gravd;
+ gravd = 0.01f - hypotf((parts[i].x - XCNTR), (parts[i].y - YCNTR));
+ gvx = ((float)(parts[i].x - XCNTR) / gravd);
+ gvy = ((float)(parts[i].y - YCNTR) / gravd);
+ }
+ break;
+ }
+
+ gvx += sim->gravx[((int)parts[i].y/CELL)*(XRES/CELL)+((int)parts[i].x/CELL)];
+ gvy += sim->gravy[((int)parts[i].y/CELL)*(XRES/CELL)+((int)parts[i].x/CELL)];
+
+ parts[i].vx -= gvx*dt; //Head up!
+ parts[i].vy -= gvy*dt;
+
+ //Verlet integration
+ pp = 2*playerp->legs[0]-playerp->legs[2]+playerp->accs[0]*dt*dt;
+ playerp->legs[2] = playerp->legs[0];
+ playerp->legs[0] = pp;
+ pp = 2*playerp->legs[1]-playerp->legs[3]+playerp->accs[1]*dt*dt;
+ playerp->legs[3] = playerp->legs[1];
+ playerp->legs[1] = pp;
+
+ pp = 2*playerp->legs[4]-playerp->legs[6]+(playerp->accs[2]+gvx)*dt*dt;
+ playerp->legs[6] = playerp->legs[4];
+ playerp->legs[4] = pp;
+ pp = 2*playerp->legs[5]-playerp->legs[7]+(playerp->accs[3]+gvy)*dt*dt;
+ playerp->legs[7] = playerp->legs[5];
+ playerp->legs[5] = pp;
+
+ pp = 2*playerp->legs[8]-playerp->legs[10]+playerp->accs[4]*dt*dt;
+ playerp->legs[10] = playerp->legs[8];
+ playerp->legs[8] = pp;
+ pp = 2*playerp->legs[9]-playerp->legs[11]+playerp->accs[5]*dt*dt;
+ playerp->legs[11] = playerp->legs[9];
+ playerp->legs[9] = pp;
+
+ pp = 2*playerp->legs[12]-playerp->legs[14]+(playerp->accs[6]+gvx)*dt*dt;
+ playerp->legs[14] = playerp->legs[12];
+ playerp->legs[12] = pp;
+ pp = 2*playerp->legs[13]-playerp->legs[15]+(playerp->accs[7]+gvy)*dt*dt;
+ playerp->legs[15] = playerp->legs[13];
+ playerp->legs[13] = pp;
+
+ //Setting accseleration to 0
+ playerp->accs[0] = 0;
+ playerp->accs[1] = 0;
+
+ playerp->accs[2] = 0;
+ playerp->accs[3] = 0;
+
+ playerp->accs[4] = 0;
+ playerp->accs[5] = 0;
+
+ playerp->accs[6] = 0;
+ playerp->accs[7] = 0;
+
+ gx = (playerp->legs[4] + playerp->legs[12])/2 - gvy;
+ gy = (playerp->legs[5] + playerp->legs[13])/2 + gvx;
+ dl = pow(gx - playerp->legs[4], 2) + pow(gy - playerp->legs[5], 2);
+ dr = pow(gx - playerp->legs[12], 2) + pow(gy - playerp->legs[13], 2);
+
+ //Go left
+ if (((int)(playerp->comm)&0x01) == 0x01)
+ {
+ if (dl>dr)
+ {
+ if (!sim->eval_move(t, playerp->legs[4], playerp->legs[5], NULL))
+ {
+ playerp->accs[2] = -3*gvy-3*gvx;
+ playerp->accs[3] = 3*gvx-3*gvy;
+ playerp->accs[0] = -gvy;
+ playerp->accs[1] = gvx;
+ }
+ }
+ else
+ {
+ if (!sim->eval_move(t, playerp->legs[12], playerp->legs[13], NULL))
+ {
+ playerp->accs[6] = -3*gvy-3*gvx;
+ playerp->accs[7] = 3*gvx-3*gvy;
+ playerp->accs[0] = -gvy;
+ playerp->accs[1] = gvx;
+ }
+ }
+ }
+
+ //Go right
+ if (((int)(playerp->comm)&0x02) == 0x02)
+ {
+ if (dl<dr)
+ {
+ if (!sim->eval_move(t, playerp->legs[4], playerp->legs[5], NULL))
+ {
+ playerp->accs[2] = 3*gvy-3*gvx;
+ playerp->accs[3] = -3*gvx-3*gvy;
+ playerp->accs[0] = gvy;
+ playerp->accs[1] = -gvx;
+ }
+ }
+ else
+ {
+ if (!sim->eval_move(t, playerp->legs[12], playerp->legs[13], NULL))
+ {
+ playerp->accs[6] = 3*gvy-3*gvx;
+ playerp->accs[7] = -3*gvx-3*gvy;
+ playerp->accs[0] = gvy;
+ playerp->accs[1] = -gvx;
+ }
+ }
+ }
+
+ //Jump
+ if (((int)(playerp->comm)&0x04) == 0x04 &&
+ (!sim->eval_move(t, playerp->legs[4], playerp->legs[5], NULL) || !sim->eval_move(t, playerp->legs[12], playerp->legs[13], NULL)))
+ {
+ parts[i].vy -= 4*gvy;
+ playerp->accs[3] -= gvy;
+ playerp->accs[7] -= gvy;
+ }
+
+ //Charge detector wall if foot inside
+ if (sim->bmap[(int)(playerp->legs[5]+0.5)/CELL][(int)(playerp->legs[4]+0.5)/CELL]==WL_DETECT)
+ sim->set_emap((int)playerp->legs[4]/CELL, (int)playerp->legs[5]/CELL);
+ if (sim->bmap[(int)(playerp->legs[13]+0.5)/CELL][(int)(playerp->legs[12]+0.5)/CELL]==WL_DETECT)
+ sim->set_emap((int)(playerp->legs[12]+0.5)/CELL, (int)(playerp->legs[13]+0.5)/CELL);
+
+ //Searching for particles near head
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ r = sim->photons[y+ry][x+rx];
+
+ if (!r && !sim->bmap[(y+ry)/CELL][(x+rx)/CELL])
+ continue;
+
+ if (sim->elements[r&0xFF].Falldown!=0 || sim->elements[r&0xFF].State == ST_GAS
+ || sim->elements[r&0xFF].Properties&TYPE_GAS
+ || sim->elements[r&0xFF].Properties&TYPE_LIQUID
+ || (r&0xFF) == PT_NEUT || (r&0xFF) == PT_PHOT)
+ {
+ playerp->elem = r&0xFF; //Current element
+ }
+ if ((r&0xFF)==PT_TESC || (r&0xFF)==PT_LIGH)
+ playerp->elem = PT_LIGH;
+ if ((r&0xFF) == PT_PLNT && parts[i].life<100) //Plant gives him 5 HP
+ {
+ if (parts[i].life<=95)
+ parts[i].life += 5;
+ else
+ parts[i].life = 100;
+ sim->kill_part(r>>8);
+ }
+
+ if ((r&0xFF) == PT_NEUT)
+ {
+ if (parts[i].life<=100) parts[i].life -= (102-parts[i].life)/2;
+ else parts[i].life *= 0.9f;
+ sim->kill_part(r>>8);
+ }
+ if (sim->bmap[(ry+y)/CELL][(rx+x)/CELL]==WL_FAN)
+ playerp->elem = SPC_AIR;
+ if ((r&0xFF)==PT_PRTI)
+ Element_STKM::STKM_interact(sim, playerp, i, rx, ry);
+ if (!parts[i].type)//STKM_interact may kill STKM
+ return 1;
+ }
+
+ //Head position
+ rx = x + 3*((((int)playerp->pcomm)&0x02) == 0x02) - 3*((((int)playerp->pcomm)&0x01) == 0x01);
+ ry = y - 3*(playerp->pcomm == 0);
+
+ //Spawn
+ if (((int)(playerp->comm)&0x08) == 0x08)
+ {
+ ry -= 2*(rand()%2)+1;
+ r = pmap[ry][rx];
+ if (sim->elements[r&0xFF].State == ST_SOLID)
+ {
+ sim->create_part(-1, rx, ry, PT_SPRK);
+ playerp->frames = 0;
+ }
+ else
+ {
+ int np = -1;
+ if (playerp->elem == SPC_AIR)
+ sim->CreateParts(rx + 3*((((int)playerp->pcomm)&0x02) == 0x02) - 3*((((int)playerp->pcomm)&0x01) == 0x01), ry, 4, 4, SPC_AIR, 0);
+ else if (playerp->elem==PT_LIGH && playerp->frames<30)//limit lightning creation rate
+ np = -1;
+ else
+ np = sim->create_part(-1, rx, ry, playerp->elem);
+ if ( (np < NPART) && np>=0)
+ {
+ if (playerp->elem == PT_PHOT)
+ {
+ int random = abs(rand()%3-1)*3;
+ if (random==0)
+ {
+ sim->kill_part(np);
+ }
+ else
+ {
+ parts[np].vy = 0;
+ if (((int)playerp->pcomm)&(0x01|0x02))
+ parts[np].vx = (((((int)playerp->pcomm)&0x02) == 0x02) - (((int)(playerp->pcomm)&0x01) == 0x01))*random;
+ else
+ parts[np].vx = random;
+ }
+ }
+ else if (playerp->elem == PT_LIGH)
+ {
+ float angle;
+ int power = 100;
+ if (gvx!=0 || gvy!=0)
+ angle = atan2(gvx, gvy)*180.0f/M_PI;
+ else
+ angle = rand()%360;
+ if (((int)playerp->comm)&0x01)
+ angle += 180;
+ if (angle>360)
+ angle-=360;
+ if (angle<0)
+ angle+=360;
+ parts[np].tmp = angle;
+ parts[np].life=rand()%(2+power/15)+power/7;
+ parts[np].temp=parts[np].life*power/2.5;
+ parts[np].tmp2=1;
+ }
+ else if (playerp->elem != SPC_AIR)
+ {
+ parts[np].vx -= -gvy*(5*((((int)playerp->pcomm)&0x02) == 0x02) - 5*(((int)(playerp->pcomm)&0x01) == 0x01));
+ parts[np].vy -= gvx*(5*((((int)playerp->pcomm)&0x02) == 0x02) - 5*(((int)(playerp->pcomm)&0x01) == 0x01));
+ parts[i].vx -= (sim->elements[(int)playerp->elem].Weight*parts[np].vx)/1000;
+ }
+ playerp->frames = 0;
+ }
+
+ }
+ }
+
+ //Simulation of joints
+ d = 25/(pow((playerp->legs[0]-playerp->legs[4]), 2) + pow((playerp->legs[1]-playerp->legs[5]), 2)+25) - 0.5; //Fast distance
+ playerp->legs[4] -= (playerp->legs[0]-playerp->legs[4])*d;
+ playerp->legs[5] -= (playerp->legs[1]-playerp->legs[5])*d;
+ playerp->legs[0] += (playerp->legs[0]-playerp->legs[4])*d;
+ playerp->legs[1] += (playerp->legs[1]-playerp->legs[5])*d;
+
+ d = 25/(pow((playerp->legs[8]-playerp->legs[12]), 2) + pow((playerp->legs[9]-playerp->legs[13]), 2)+25) - 0.5;
+ playerp->legs[12] -= (playerp->legs[8]-playerp->legs[12])*d;
+ playerp->legs[13] -= (playerp->legs[9]-playerp->legs[13])*d;
+ playerp->legs[8] += (playerp->legs[8]-playerp->legs[12])*d;
+ playerp->legs[9] += (playerp->legs[9]-playerp->legs[13])*d;
+
+ d = 36/(pow((playerp->legs[0]-parts[i].x), 2) + pow((playerp->legs[1]-parts[i].y), 2)+36) - 0.5;
+ parts[i].vx -= (playerp->legs[0]-parts[i].x)*d;
+ parts[i].vy -= (playerp->legs[1]-parts[i].y)*d;
+ playerp->legs[0] += (playerp->legs[0]-parts[i].x)*d;
+ playerp->legs[1] += (playerp->legs[1]-parts[i].y)*d;
+
+ d = 36/(pow((playerp->legs[8]-parts[i].x), 2) + pow((playerp->legs[9]-parts[i].y), 2)+36) - 0.5;
+ parts[i].vx -= (playerp->legs[8]-parts[i].x)*d;
+ parts[i].vy -= (playerp->legs[9]-parts[i].y)*d;
+ playerp->legs[8] += (playerp->legs[8]-parts[i].x)*d;
+ playerp->legs[9] += (playerp->legs[9]-parts[i].y)*d;
+
+ if (INBOND(playerp->legs[4], playerp->legs[5]) && !sim->eval_move(t, playerp->legs[4], playerp->legs[5], NULL))
+ {
+ playerp->legs[4] = playerp->legs[6];
+ playerp->legs[5] = playerp->legs[7];
+ }
+
+ if (INBOND(playerp->legs[12], playerp->legs[13]) && !sim->eval_move(t, playerp->legs[12], playerp->legs[13], NULL))
+ {
+ playerp->legs[12] = playerp->legs[14];
+ playerp->legs[13] = playerp->legs[15];
+ }
+
+ //This makes stick man "pop" from obstacles
+ if (INBOND(playerp->legs[4], playerp->legs[5]) && !sim->eval_move(t, playerp->legs[4], playerp->legs[5], NULL))
+ {
+ float t;
+ t = playerp->legs[4]; playerp->legs[4] = playerp->legs[6]; playerp->legs[6] = t;
+ t = playerp->legs[5]; playerp->legs[5] = playerp->legs[7]; playerp->legs[7] = t;
+ }
+
+ if (INBOND(playerp->legs[12], playerp->legs[13]) && !sim->eval_move(t, playerp->legs[12], playerp->legs[13], NULL))
+ {
+ float t;
+ t = playerp->legs[12]; playerp->legs[12] = playerp->legs[14]; playerp->legs[14] = t;
+ t = playerp->legs[13]; playerp->legs[13] = playerp->legs[15]; playerp->legs[15] = t;
+ }
+
+ //Keeping legs distance
+ if ((pow((playerp->legs[4] - playerp->legs[12]), 2) + pow((playerp->legs[5]-playerp->legs[13]), 2))<16)
+ {
+ float tvx, tvy;
+ tvx = -gvy;
+ tvy = gvx;
+
+ if (tvx || tvy)
+ {
+ playerp->accs[2] -= 0.2*tvx/hypot(tvx, tvy);
+ playerp->accs[3] -= 0.2*tvy/hypot(tvx, tvy);
+
+ playerp->accs[6] += 0.2*tvx/hypot(tvx, tvy);
+ playerp->accs[7] += 0.2*tvy/hypot(tvx, tvy);
+ }
+ }
+
+ if ((pow((playerp->legs[0] - playerp->legs[8]), 2) + pow((playerp->legs[1]-playerp->legs[9]), 2))<16)
+ {
+ float tvx, tvy;
+ tvx = -gvy;
+ tvy = gvx;
+
+ if (tvx || tvy)
+ {
+ playerp->accs[0] -= 0.2*tvx/hypot(tvx, tvy);
+ playerp->accs[1] -= 0.2*tvy/hypot(tvx, tvy);
+
+ playerp->accs[4] += 0.2*tvx/hypot(tvx, tvy);
+ playerp->accs[5] += 0.2*tvy/hypot(tvx, tvy);
+ }
+ }
+
+ //If legs touch something
+ Element_STKM::STKM_interact(sim, playerp, i, (int)(playerp->legs[4]+0.5), (int)(playerp->legs[5]+0.5));
+ Element_STKM::STKM_interact(sim, playerp, i, (int)(playerp->legs[12]+0.5), (int)(playerp->legs[13]+0.5));
+ Element_STKM::STKM_interact(sim, playerp, i, (int)(playerp->legs[4]+0.5), (int)playerp->legs[5]);
+ Element_STKM::STKM_interact(sim, playerp, i, (int)(playerp->legs[12]+0.5), (int)playerp->legs[13]);
+ if (!parts[i].type)
+ return 1;
+
+ parts[i].ctype = playerp->elem;
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_STKM static void STKM_interact(Simulation * sim, playerst* playerp, int i, int x, int y)
+void Element_STKM::STKM_interact(Simulation * sim, playerst* playerp, int i, int x, int y)
+{
+ int r;
+ if (x<0 || y<0 || x>=XRES || y>=YRES || !sim->parts[i].type)
+ return;
+ r = sim->pmap[y][x];
+ if (r)
+ {
+ if ((r&0xFF)==PT_SPRK && playerp->elem!=PT_LIGH) //If on charge
+ {
+ sim->parts[i].life -= (int)(rand()*20/RAND_MAX)+32;
+ }
+
+ if (sim->elements[r&0xFF].HeatConduct && ((playerp->elem!=PT_LIGH && sim->parts[r>>8].temp>=323) || sim->parts[r>>8].temp<=243))
+ {
+ sim->parts[i].life -= 2;
+ playerp->accs[3] -= 1;
+ }
+
+ if (sim->elements[r&0xFF].Properties&PROP_DEADLY)
+ switch (r&0xFF)
+ {
+ case PT_ACID:
+ sim->parts[i].life -= 5;
+ break;
+ default:
+ sim->parts[i].life -= 1;
+ break;
+ }
+
+ if (sim->elements[r&0xFF].Properties&PROP_RADIOACTIVE)
+ sim->parts[i].life -= 1;
+
+ if ((r&0xFF)==PT_PRTI && sim->parts[i].type)
+ {
+ int nnx, count=1;//gives rx=0, ry=1 in update_PRTO
+ sim->parts[r>>8].tmp = (int)((sim->parts[r>>8].temp-73.15f)/100+1);
+ if (sim->parts[r>>8].tmp>=CHANNELS) sim->parts[r>>8].tmp = CHANNELS-1;
+ else if (sim->parts[r>>8].tmp<0) sim->parts[r>>8].tmp = 0;
+ for (nnx=0; nnx<80; nnx++)
+ if (!sim->portalp[sim->parts[r>>8].tmp][count][nnx].type)
+ {
+ sim->portalp[sim->parts[r>>8].tmp][count][nnx] = sim->parts[i];
+ sim->kill_part(i);
+ //stop new STKM/fighters being created to replace the ones in the portal:
+ playerp->spwn = 1;
+ if (sim->portalp[sim->parts[r>>8].tmp][count][nnx].type==PT_FIGH)
+ sim->fighcount++;
+ break;
+ }
+ }
+ if (((r&0xFF)==PT_BHOL || (r&0xFF)==PT_NBHL) && sim->parts[i].type)
+ {
+ if (!sim->legacy_enable)
+ {
+ sim->parts[r>>8].temp = restrict_flt(sim->parts[r>>8].temp+sim->parts[i].temp/2, MIN_TEMP, MAX_TEMP);
+ }
+ sim->kill_part(i);
+ }
+ if (((r&0xFF)==PT_VOID || ((r&0xFF)==PT_PVOD && sim->parts[r>>8].life==10)) && (!sim->parts[r>>8].ctype || (sim->parts[r>>8].ctype==sim->parts[i].type)!=(sim->parts[r>>8].tmp&1)) && sim->parts[i].type)
+ {
+ sim->kill_part(i);
+ }
+ }
+}
+
+//#TPT-Directive ElementHeader Element_STKM static void STKM_init_legs(Simulation * sim, playerst* playerp, int i)
+void Element_STKM::STKM_init_legs(Simulation * sim, playerst* playerp, int i)
+{
+ int x, y;
+
+ x = (int)(sim->parts[i].x+0.5f);
+ y = (int)(sim->parts[i].y+0.5f);
+
+ playerp->legs[0] = x-1;
+ playerp->legs[1] = y+6;
+ playerp->legs[2] = x-1;
+ playerp->legs[3] = y+6;
+
+ playerp->legs[4] = x-3;
+ playerp->legs[5] = y+12;
+ playerp->legs[6] = x-3;
+ playerp->legs[7] = y+12;
+
+ playerp->legs[8] = x+1;
+ playerp->legs[9] = y+6;
+ playerp->legs[10] = x+1;
+ playerp->legs[11] = y+6;
+
+ playerp->legs[12] = x+3;
+ playerp->legs[13] = y+12;
+ playerp->legs[14] = x+3;
+ playerp->legs[15] = y+12;
+
+ for (int i = 0; i < 8; i++)
+ playerp->accs[i] = 0;
+ playerp->comm = 0;
+ playerp->pcomm = 0;
+ playerp->frames = 0;
+}
+
+
+Element_STKM::~Element_STKM() {}
diff --git a/src/simulation/elements/STKM2.cpp b/src/simulation/elements/STKM2.cpp
new file mode 100644
index 0000000..a2c0073
--- /dev/null
+++ b/src/simulation/elements/STKM2.cpp
@@ -0,0 +1,56 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_STKM2 PT_STKM2 128
+Element_STKM2::Element_STKM2()
+{
+ Identifier = "DEFAULT_PT_STKM2";
+ Name = "STK2";
+ Colour = PIXPACK(0x6464FF);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.5f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.2f;
+ Loss = 1.0f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.0f;
+ HotAir = 0.00f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 50;
+
+ Temperature = R_TEMP+14.6f+273.15f;
+ HeatConduct = 0;
+ Description = "Stickman. Don't kill him!";
+
+ State = ST_NONE;
+ Properties = 0;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 620.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_STKM2::update;
+ Graphics = &Element_STKM::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_STKM2 static int update(UPDATE_FUNC_ARGS)
+int Element_STKM2::update(UPDATE_FUNC_ARGS)
+ {
+ Element_STKM::run_stickman(&sim->player2, UPDATE_FUNC_SUBCALL_ARGS);
+ return 0;
+}
+
+Element_STKM2::~Element_STKM2() {} \ No newline at end of file
diff --git a/src/simulation/elements/STNE.cpp b/src/simulation/elements/STNE.cpp
new file mode 100644
index 0000000..ff5251d
--- /dev/null
+++ b/src/simulation/elements/STNE.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_STNE PT_STNE 5
+Element_STNE::Element_STNE()
+{
+ Identifier = "DEFAULT_PT_STNE";
+ Name = "STNE";
+ Colour = PIXPACK(0xA0A0A0);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 5;
+ Hardness = 1;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 150;
+ Description = "Heavy particles. Meltable.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 983.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = NULL;
+
+}
+
+Element_STNE::~Element_STNE() {} \ No newline at end of file
diff --git a/src/simulation/elements/STOR.cpp b/src/simulation/elements/STOR.cpp
new file mode 100644
index 0000000..c6064cd
--- /dev/null
+++ b/src/simulation/elements/STOR.cpp
@@ -0,0 +1,112 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_STOR PT_STOR 83
+Element_STOR::Element_STOR()
+{
+ Identifier = "DEFAULT_PT_STOR";
+ Name = "STOR";
+ Colour = PIXPACK(0x50DFDF);
+ MenuVisible = 1;
+ MenuSection = SC_POWERED;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Solid. Stores a single particle, releases when charged with PSCN, also passes to PIPE";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_STOR::update;
+ Graphics = &Element_STOR::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_STOR static int update(UPDATE_FUNC_ARGS)
+int Element_STOR::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, np, rx1, ry1;
+ if(parts[i].life && !parts[i].tmp)
+ parts[i].life--;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r>>8)>=NPART || !r)
+ continue;
+ if (!parts[i].tmp && !parts[i].life && (r&0xFF)!=PT_STOR && !(sim->elements[(r&0xFF)].Properties&TYPE_SOLID) && (!parts[i].ctype || (r&0xFF)==parts[i].ctype))
+ {
+ parts[i].tmp = parts[r>>8].type;
+ parts[i].temp = parts[r>>8].temp;
+ parts[i].tmp2 = parts[r>>8].life;
+ parts[i].pavg[0] = parts[r>>8].tmp;
+ parts[i].pavg[1] = parts[r>>8].ctype;
+ sim->kill_part(r>>8);
+ }
+ if(parts[i].tmp && (r&0xFF)==PT_SPRK && parts[r>>8].ctype==PT_PSCN && parts[r>>8].life>0 && parts[r>>8].life<4)
+ {
+ for(ry1 = 1; ry1 >= -1; ry1--){
+ for(rx1 = 0; rx1 >= -1 && rx1 <= 1; rx1 = -rx1-rx1+1){ // Oscilate the X starting at 0, 1, -1, 3, -5, etc (Though stop at -1)
+ np = sim->create_part(-1,x+rx1,y+ry1,parts[i].tmp);
+ if (np!=-1)
+ {
+ parts[np].temp = parts[i].temp;
+ parts[np].life = parts[i].tmp2;
+ parts[np].tmp = parts[i].pavg[0];
+ parts[np].ctype = parts[i].pavg[1];
+ parts[i].tmp = 0;
+ parts[i].life = 10;
+ break;
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_STOR static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_STOR::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->tmp){
+ *pixel_mode |= PMODE_GLOW;
+ *colr = 0x50;
+ *colg = 0xDF;
+ *colb = 0xDF;
+ } else {
+ *colr = 0x20;
+ *colg = 0xAF;
+ *colb = 0xAF;
+ }
+ return 0;
+}
+
+
+Element_STOR::~Element_STOR() {}
diff --git a/src/simulation/elements/SWCH.cpp b/src/simulation/elements/SWCH.cpp
new file mode 100644
index 0000000..818af27
--- /dev/null
+++ b/src/simulation/elements/SWCH.cpp
@@ -0,0 +1,113 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_SWCH PT_SWCH 56
+Element_SWCH::Element_SWCH()
+{
+ Identifier = "DEFAULT_PT_SWCH";
+ Name = "SWCH";
+ Colour = PIXPACK(0x103B11);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Solid. Only conducts when switched on. (PSCN switches on, NSCN switches off)";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_SWCH::update;
+ Graphics = &Element_SWCH::graphics;
+}
+
+bool isRedBRAY(UPDATE_FUNC_ARGS, int xc, int yc)
+{
+ return (pmap[yc][xc]&0xFF) == PT_BRAY && parts[pmap[yc][xc]>>8].tmp == 2;
+}
+
+//#TPT-Directive ElementHeader Element_SWCH static int update(UPDATE_FUNC_ARGS)
+int Element_SWCH::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rt, rx, ry;
+ if (parts[i].life>0 && parts[i].life!=10)
+ parts[i].life--;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (sim->parts_avg(i,r>>8,PT_INSL)!=PT_INSL) {
+ rt = r&0xFF;
+ if (rt==PT_SWCH)
+ {
+ if (parts[i].life>=10&&parts[r>>8].life<10&&parts[r>>8].life>0)
+ parts[i].life = 9;
+ else if (parts[i].life==0&&parts[r>>8].life>=10)
+ {
+ //Set to other particle's life instead of 10, otherwise spark loops form when SWCH is sparked while turning on
+ parts[i].life = parts[r>>8].life;
+ }
+ }
+ else if (rt==PT_SPRK&&parts[i].life==10&&parts[r>>8].ctype!=PT_PSCN&&parts[r>>8].ctype!=PT_NSCN) {
+ sim->part_change_type(i,x,y,PT_SPRK);
+ parts[i].ctype = PT_SWCH;
+ parts[i].life = 4;
+ }
+ }
+ }
+ //turn SWCH on/off from two red BRAYS. There must be one either above or below, and one either left or right to work, and it can't come from the side, it must be a diagonal beam
+ if (!(pmap[y-1][x-1]&0xFF) && !(pmap[y-1][x+1]&0xFF) && (isRedBRAY(UPDATE_FUNC_SUBCALL_ARGS, x, y-1) || isRedBRAY(UPDATE_FUNC_SUBCALL_ARGS, x, y+1)) && (isRedBRAY(UPDATE_FUNC_SUBCALL_ARGS, x+1, y) || isRedBRAY(UPDATE_FUNC_SUBCALL_ARGS, x-1, y)))
+ {
+ if (parts[i].life == 10)
+ parts[i].life = 9;
+ else if (parts[i].life <= 5)
+ parts[i].life = 14;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_SWCH static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_SWCH::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->life >= 10)
+ {
+ *colr = 17;
+ *colg = 217;
+ *colb = 24;
+ *pixel_mode |= PMODE_GLOW;
+ }
+ return 0;
+}
+
+
+Element_SWCH::~Element_SWCH() {} \ No newline at end of file
diff --git a/src/simulation/elements/TESC.cpp b/src/simulation/elements/TESC.cpp
new file mode 100644
index 0000000..d8b4e9f
--- /dev/null
+++ b/src/simulation/elements/TESC.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_TESC PT_TESC 88
+Element_TESC::Element_TESC()
+{
+ Identifier = "DEFAULT_PT_TESC";
+ Name = "TESC";
+ Colour = PIXPACK(0x707040);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Tesla coil!";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_HOT_GLOW;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_TESC::~Element_TESC() {} \ No newline at end of file
diff --git a/src/simulation/elements/THDR.cpp b/src/simulation/elements/THDR.cpp
new file mode 100644
index 0000000..6ee1dea
--- /dev/null
+++ b/src/simulation/elements/THDR.cpp
@@ -0,0 +1,102 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_THDR PT_THDR 48
+Element_THDR::Element_THDR()
+{
+ Identifier = "DEFAULT_PT_THDR";
+ Name = "THDR";
+ Colour = PIXPACK(0xFFFFA0);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.0f;
+ Loss = 0.30f;
+ Collision = -0.99f;
+ Gravity = 0.6f;
+ Diffusion = 0.62f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 1;
+
+ Temperature = 9000.0f +273.15f;
+ HeatConduct = 1;
+ Description = "Lightning! Very hot, inflicts damage upon most materials, transfers current to metals.";
+
+ State = ST_NONE;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_THDR::update;
+ Graphics = &Element_THDR::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_THDR static int update(UPDATE_FUNC_ARGS)
+int Element_THDR::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((sim->elements[r&0xFF].Properties&PROP_CONDUCTS) && parts[r>>8].life==0 && !((r&0xFF)==PT_WATR||(r&0xFF)==PT_SLTW) && parts[r>>8].ctype!=PT_SPRK)
+ {
+ parts[i].type = PT_NONE;
+ parts[r>>8].ctype = parts[r>>8].type;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ parts[r>>8].life = 4;
+ }
+ else if ((r&0xFF)!=PT_CLNE&&(r&0xFF)!=PT_THDR&&(r&0xFF)!=PT_SPRK&&(r&0xFF)!=PT_DMND&&(r&0xFF)!=PT_FIRE&&(r&0xFF)!=PT_NEUT&&(r&0xFF)!=PT_PHOT&&(r&0xFF))
+ {
+ sim->pv[y/CELL][x/CELL] += 100.0f;
+ if (sim->legacy_enable&&1>(rand()%200))
+ {
+ parts[i].life = rand()%50+120;
+ sim->part_change_type(i,x,y,PT_FIRE);
+ }
+ else
+ {
+ parts[i].type = PT_NONE;
+ }
+ }
+ }
+ if (parts[i].type==PT_NONE) {
+ sim->kill_part(i);
+ return 1;
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_THDR static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_THDR::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ *firea = 160;
+ *fireg = 192;
+ *fireb = 255;
+ *firer = 144;
+ *pixel_mode |= FIRE_ADD;
+ return 1;
+}
+
+
+Element_THDR::~Element_THDR() {}
diff --git a/src/simulation/elements/THRM.cpp b/src/simulation/elements/THRM.cpp
new file mode 100644
index 0000000..e7d1dde
--- /dev/null
+++ b/src/simulation/elements/THRM.cpp
@@ -0,0 +1,80 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_THRM PT_THRM 65
+Element_THRM::Element_THRM()
+{
+ Identifier = "DEFAULT_PT_THRM";
+ Name = "THRM";
+ Colour = PIXPACK(0xA08090);
+ MenuVisible = 1;
+ MenuSection = SC_EXPLOSIVE;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.04f * CFDS;
+ AirLoss = 0.94f;
+ Loss = 0.95f;
+ Collision = -0.1f;
+ Gravity = 0.3f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 2;
+ Hardness = 2;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 211;
+ Description = "Thermite. Burns at extremely high temperature.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_THRM::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_THRM static int update(UPDATE_FUNC_ARGS)
+int Element_THRM::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_FIRE || (r&0xFF)==PT_PLSM || (r&0xFF)==PT_LAVA)) // TODO: could this go in update_PYRO?
+ {
+ if (1>(rand()%500)) {
+ sim->part_change_type(i,x,y,PT_LAVA);
+ parts[i].ctype = PT_BMTL;
+ parts[i].temp = 3500.0f;
+ sim->pv[y/CELL][x/CELL] += 50.0f;
+ } else {
+ sim->part_change_type(i,x,y,PT_LAVA);
+ parts[i].life = 400;
+ parts[i].ctype = PT_THRM;
+ parts[i].temp = 3500.0f;
+ parts[i].tmp = 20;
+ }
+ }
+ }
+ return 0;
+}
+
+
+Element_THRM::~Element_THRM() {} \ No newline at end of file
diff --git a/src/simulation/elements/TRON.cpp b/src/simulation/elements/TRON.cpp
new file mode 100644
index 0000000..36493a7
--- /dev/null
+++ b/src/simulation/elements/TRON.cpp
@@ -0,0 +1,236 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_TRON PT_TRON 143
+Element_TRON::Element_TRON()
+{
+ Identifier = "DEFAULT_PT_TRON";
+ Name = "TRON";
+ Colour = PIXPACK(0xA9FF00);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = 0.0f;
+ HeatConduct = 40;
+ Description = "Smart particles, Travels in straight lines and avoids obstacles. Grows with time.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC|PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_TRON::update;
+ Graphics = &Element_TRON::graphics;
+
+ Element_TRON::init_graphics();
+}
+
+#define TRON_HEAD 1
+#define TRON_NOGROW 2
+#define TRON_WAIT 4 //it was just created, so WAIT a frame
+#define TRON_NODIE 8
+#define TRON_DEATH 16 //Crashed, now dying
+int tron_rx[4] = {-1, 0, 1, 0};
+int tron_ry[4] = { 0,-1, 0, 1};
+unsigned int tron_colours[32];
+
+//#TPT-Directive ElementHeader Element_TRON static void init_graphics()
+void Element_TRON::init_graphics()
+{
+ int i;
+ int r, g, b;
+ for (i=0; i<32; i++)
+ {
+ HSV_to_RGB(i<<4,255,255,&r,&g,&b);
+ tron_colours[i] = r<<16 | g<<8 | b;
+ }
+}
+
+//#TPT-Directive ElementHeader Element_TRON static int update(UPDATE_FUNC_ARGS)
+int Element_TRON::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry, np;
+ if (parts[i].tmp&TRON_WAIT)
+ {
+ parts[i].tmp &= ~TRON_WAIT;
+ return 0;
+ }
+ if (parts[i].tmp&TRON_HEAD)
+ {
+ int firstdircheck = 0,seconddir,seconddircheck = 0,lastdir,lastdircheck = 0;
+ int direction = (parts[i].tmp>>5 & 0x3);
+ int originaldir = direction;
+
+ //random turn
+ int random = rand()%340;
+ if (random==1 || random==3)
+ {
+ //randomly turn left(3) or right(1)
+ direction = (direction + random)%4;
+ }
+
+ //check infront
+ //do sight check
+ firstdircheck = Element_TRON::trymovetron(sim,x,y,direction,i,parts[i].tmp2);
+ if (firstdircheck < parts[i].tmp2)
+ {
+ if (originaldir != direction) //if we just tried a random turn, don't pick random again
+ {
+ seconddir = originaldir;
+ lastdir = (direction + 2)%4;
+ }
+ else
+ {
+ seconddir = (direction + ((rand()%2)*2)+1)% 4;
+ lastdir = (seconddir + 2)%4;
+ }
+ seconddircheck = trymovetron(sim,x,y,seconddir,i,parts[i].tmp2);
+ lastdircheck = trymovetron(sim,x,y,lastdir,i,parts[i].tmp2);
+ }
+ //find the best move
+ if (seconddircheck > firstdircheck)
+ direction = seconddir;
+ if (lastdircheck > seconddircheck && lastdircheck > firstdircheck)
+ direction = lastdir;
+ //now try making new head, even if it fails
+ if (Element_TRON::new_tronhead(sim,x + tron_rx[direction],y + tron_ry[direction],i,direction) == -1)
+ {
+ //ohgod crash
+ parts[i].tmp |= TRON_DEATH;
+ //trigger tail death for TRON_NODIE, or is that mode even needed? just set a high tail length(but it still won't start dying when it crashes)
+ }
+
+ //set own life and clear .tmp (it dies if it can't move anyway)
+ parts[i].life = parts[i].tmp2;
+ parts[i].tmp &= parts[i].tmp&0xF818;
+ }
+ else // fade tail deco, or prevent tail from dieing
+ {
+ if (parts[i].tmp&TRON_NODIE)
+ parts[i].life++;
+ //parts[i].dcolour = clamp_flt((float)parts[i].life/(float)parts[i].tmp2,0,1.0f) << 24 | parts[i].dcolour&0x00FFFFFF;
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_TRON static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_TRON::graphics(GRAPHICS_FUNC_ARGS)
+ {
+ unsigned int col = tron_colours[(cpart->tmp&0xF800)>>11];
+ if(cpart->tmp & TRON_HEAD)
+ *pixel_mode |= PMODE_GLOW;
+ *colr = (col & 0xFF0000)>>16;
+ *colg = (col & 0x00FF00)>>8;
+ *colb = (col & 0x0000FF);
+ if(cpart->tmp & TRON_DEATH)
+ {
+ *pixel_mode |= FIRE_ADD | PMODE_FLARE;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+ *firea = 255;
+ }
+ if(cpart->life < cpart->tmp2 && !(cpart->tmp & TRON_HEAD))
+ {
+ *pixel_mode |= PMODE_BLEND;
+ *pixel_mode &= ~PMODE_FLAT;
+ *cola = (int)((((float)cpart->life)/((float)cpart->tmp2))*255.0f);
+ }
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_TRON static int new_tronhead(Simulation * sim, int x, int y, int i, int direction)
+int Element_TRON::new_tronhead(Simulation * sim, int x, int y, int i, int direction)
+{
+ int np = sim->create_part(-1, x , y ,PT_TRON);
+ if (np==-1)
+ return -1;
+ if (sim->parts[i].life >= 100) // increase tail length
+ {
+ if (!(sim->parts[i].tmp&TRON_NOGROW))
+ sim->parts[i].tmp2++;
+ sim->parts[i].life = 5;
+ }
+ //give new head our properties
+ sim->parts[np].tmp = 1 | direction<<5 | sim->parts[i].tmp&(TRON_NOGROW|TRON_NODIE) | (sim->parts[i].tmp&0xF800);
+ if (np > i)
+ sim->parts[np].tmp |= TRON_WAIT;
+
+ sim->parts[np].ctype = sim->parts[i].ctype;
+ sim->parts[np].tmp2 = sim->parts[i].tmp2;
+ sim->parts[np].life = sim->parts[i].life + 2;
+ return 1;
+}
+
+//#TPT-Directive ElementHeader Element_TRON static int trymovetron(Simulation * sim, int x, int y, int dir, int i, int len)
+int Element_TRON::trymovetron(Simulation * sim, int x, int y, int dir, int i, int len)
+{
+ int k,j,r,rx,ry,tx,ty,count;
+ count = 0;
+ rx = x;
+ ry = y;
+ for (k = 1; k <= len; k ++)
+ {
+ rx += tron_rx[dir];
+ ry += tron_ry[dir];
+ r = sim->pmap[ry][rx];
+ if (!r && !sim->bmap[(ry)/CELL][(rx)/CELL] && ry > CELL && rx > CELL && ry < YRES-CELL && rx < XRES-CELL)
+ {
+ count++;
+ for (tx = rx - tron_ry[dir] , ty = ry - tron_rx[dir], j=1; abs(tx-rx) < (len-k) && abs(ty-ry) < (len-k); tx-=tron_ry[dir],ty-=tron_rx[dir],j++)
+ {
+ r = sim->pmap[ty][tx];
+ if (!r && !sim->bmap[(ty)/CELL][(tx)/CELL] && ty > CELL && tx > CELL && ty < YRES-CELL && tx < XRES-CELL)
+ {
+ if (j == (len-k))//there is a safe path, so we can break out
+ return len+1;
+ count++;
+ }
+ else //we hit a block so no need to check farther here
+ break;
+ }
+ for (tx = rx + tron_ry[dir] , ty = ry + tron_rx[dir], j=1; abs(tx-rx) < (len-k) && abs(ty-ry) < (len-k); tx+=tron_ry[dir],ty+=tron_rx[dir],j++)
+ {
+ r = sim->pmap[ty][tx];
+ if (!r && !sim->bmap[(ty)/CELL][(tx)/CELL] && ty > CELL && tx > CELL && ty < YRES-CELL && tx < XRES-CELL)
+ {
+ if (j == (len-k))
+ return len+1;
+ count++;
+ }
+ else
+ break;
+ }
+ }
+ else //a block infront, no need to continue
+ break;
+ }
+ return count;
+}
+
+Element_TRON::~Element_TRON() {}
diff --git a/src/simulation/elements/TSNS.cpp b/src/simulation/elements/TSNS.cpp
new file mode 100644
index 0000000..d5c8aa7
--- /dev/null
+++ b/src/simulation/elements/TSNS.cpp
@@ -0,0 +1,93 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_TSNS PT_TSNS 164
+Element_TSNS::Element_TSNS()
+{
+ Identifier = "DEFAULT_PT_TSNS";
+ Name = "TSNS";
+ Colour = PIXPACK(0xFD9D18);
+ MenuVisible = 1;
+ MenuSection = SC_SENSOR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.96f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Creates a spark when there's a nearby particle with a greater temperature";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_TSNS::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_TSNS static int update(UPDATE_FUNC_ARGS)
+int Element_TSNS::update(UPDATE_FUNC_ARGS)
+{
+ int r, rx, ry, rt, rd = parts[i].tmp2;
+ if (rd > 25) parts[i].tmp2 = rd = 25;
+ if (parts[i].life)
+ {
+ parts[i].life = 0;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ rt = parts[r>>8].type;
+ if (sim->parts_avg(i,r>>8,PT_INSL) != PT_INSL)
+ {
+ if ((sim->elements[rt].Properties&PROP_CONDUCTS) && !(rt==PT_WATR||rt==PT_SLTW||rt==PT_NTCT||rt==PT_PTCT||rt==PT_INWR) && parts[r>>8].life==0 && Element_DTEC::in_radius(rd, rx, ry))
+ {
+ parts[r>>8].life = 4;
+ parts[r>>8].ctype = rt;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ }
+ }
+ }
+ }
+ for (rx=-rd; rx<rd+1; rx++)
+ for (ry=-rd; ry<rd+1; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if(!r)
+ r = sim->photons[y+ry][x+rx];
+ if(!r)
+ continue;
+ if (parts[r>>8].temp > parts[i].temp && parts[r>>8].type != PT_TSNS)
+ parts[i].life = 1;
+ }
+ return 0;
+}
+
+
+
+Element_TSNS::~Element_TSNS() {}
diff --git a/src/simulation/elements/TTAN.cpp b/src/simulation/elements/TTAN.cpp
new file mode 100644
index 0000000..c51319d
--- /dev/null
+++ b/src/simulation/elements/TTAN.cpp
@@ -0,0 +1,76 @@
+#include "simulation/Elements.h"
+#include "simulation/Air.h"
+//#TPT-Directive ElementClass Element_TTAN PT_TTAN 144
+Element_TTAN::Element_TTAN()
+{
+ Identifier = "DEFAULT_PT_TTAN";
+ Name = "TTAN";
+ Colour = PIXPACK(0x909090);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 1;
+ Hardness = 50;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Titanium, Higher melting temperature than other metals, blocks all air pressure";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_CONDUCTS|PROP_HOT_GLOW|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 1941.0f;
+ HighTemperatureTransition = PT_LAVA;
+
+ Update = &Element_TTAN::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_TTAN static int update(UPDATE_FUNC_ARGS)
+int Element_TTAN::update(UPDATE_FUNC_ARGS)
+ {
+ int nx, ny, ttan = 0;
+ if(nt<=2)
+ ttan = 2;
+ else if(parts[i].tmp)
+ ttan = 2;
+ else if(nt<=6)
+ for (nx=-1; nx<2; nx++) {
+ for (ny=-1; ny<2; ny++) {
+ if ((!nx != !ny) && x+nx>=0 && y+ny>=0 && x+nx<XRES && y+ny<YRES) {
+ if((pmap[y+ny][x+nx]&0xFF)==PT_TTAN)
+ ttan++;
+ }
+ }
+ }
+
+ if(ttan>=2) {
+ sim->air->bmap_blockair[y/CELL][x/CELL] = 1;
+ sim->air->bmap_blockairh[y/CELL][x/CELL] = 1;
+ }
+ return 0;
+}
+
+
+Element_TTAN::~Element_TTAN() {}
diff --git a/src/simulation/elements/URAN.cpp b/src/simulation/elements/URAN.cpp
new file mode 100644
index 0000000..a988bf3
--- /dev/null
+++ b/src/simulation/elements/URAN.cpp
@@ -0,0 +1,61 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_URAN PT_URAN 32
+Element_URAN::Element_URAN()
+{
+ Identifier = "DEFAULT_PT_URAN";
+ Name = "URAN";
+ Colour = PIXPACK(0x707020);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.4f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.4f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 90;
+
+ Temperature = R_TEMP+30.0f+273.15f;
+ HeatConduct = 251;
+ Description = "Heavy particles. Generates heat under pressure.";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART | PROP_RADIOACTIVE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_URAN::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_URAN static int update(UPDATE_FUNC_ARGS)
+int Element_URAN::update(UPDATE_FUNC_ARGS)
+ {
+ if (!sim->legacy_enable && sim->pv[y/CELL][x/CELL]>0.0f)
+ {
+ float atemp = parts[i].temp + (-MIN_TEMP);
+ parts[i].temp = restrict_flt((atemp*(1+(sim->pv[y/CELL][x/CELL]/2000)))+MIN_TEMP, MIN_TEMP, MAX_TEMP);
+ }
+ return 0;
+}
+
+
+Element_URAN::~Element_URAN() {} \ No newline at end of file
diff --git a/src/simulation/elements/VIBR.cpp b/src/simulation/elements/VIBR.cpp
new file mode 100644
index 0000000..68119f7
--- /dev/null
+++ b/src/simulation/elements/VIBR.cpp
@@ -0,0 +1,235 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_VIBR PT_VIBR 165
+Element_VIBR::Element_VIBR()
+{
+ Identifier = "DEFAULT_PT_VIBR";
+ Name = "VIBR";
+ Colour = PIXPACK(0x005000);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.85f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = 273.15f;
+ HeatConduct = 251;
+ Description = "Vibranium. Stores energy and releases it in violent explosions.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID|PROP_LIFE_DEC;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_VIBR::update;
+ Graphics = &Element_VIBR::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_VIBR static int update(UPDATE_FUNC_ARGS)
+int Element_VIBR::update(UPDATE_FUNC_ARGS) {
+ int r, rx, ry;
+ int trade, transfer;
+ if (parts[i].ctype == 1) //leaving in, just because
+ {
+ if (sim->pv[y/CELL][x/CELL] > -2.5 || parts[i].tmp)
+ {
+ parts[i].ctype = 0;
+ sim->part_change_type(i, x, y, PT_VIBR);
+ }
+ }
+ else if (!parts[i].life) //if not exploding
+ {
+ //Heat absorption code
+ if (parts[i].temp > 274.65f)
+ {
+ parts[i].tmp++;
+ parts[i].temp -= 3;
+ }
+ if (parts[i].temp < 271.65f)
+ {
+ parts[i].tmp--;
+ parts[i].temp += 3;
+ }
+ //Pressure absorption code
+ if (sim->pv[y/CELL][x/CELL] > 2.5)
+ {
+ parts[i].tmp += 7;
+ sim->pv[y/CELL][x/CELL]--;
+ }
+ if (sim->pv[y/CELL][x/CELL] < -2.5)
+ {
+ parts[i].tmp -= 2;
+ sim->pv[y/CELL][x/CELL]++;
+ }
+ //initiate explosion counter
+ if (parts[i].tmp > 1000)
+ parts[i].life = 750;
+ }
+ else //if it is exploding
+ {
+ //Release sparks before explode
+ if (parts[i].life < 300)
+ {
+ rx = rand()%3-1;
+ ry = rand()%3-1;
+ r = pmap[y+ry][x+rx];
+ if ((r&0xFF) && (r&0xFF) != PT_BREC && (sim->elements[r&0xFF].Properties&PROP_CONDUCTS) && !parts[r>>8].life)
+ {
+ parts[r>>8].life = 4;
+ parts[r>>8].ctype = r&0xFF;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ }
+ }
+ //Release all heat
+ if (parts[i].life < 500)
+ {
+ int random = rand();
+ rx = random%7-3;
+ ry = (random>>3)%7-3;
+ if(x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES)
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r&0xFF) && (r&0xFF)!=PT_VIBR && (r&0xFF)!=PT_BVBR && sim->elements[r&0xFF].HeatConduct && ((r&0xFF)!=PT_HSWC||parts[r>>8].life==10))
+ {
+ parts[r>>8].temp += parts[i].tmp*3;
+ parts[i].tmp = 0;
+ }
+ }
+ }
+ //Explosion code
+ if (parts[i].life == 1)
+ {
+ int random = rand(), index;
+ sim->create_part(i, x, y, PT_EXOT);
+ parts[i].tmp2 = rand()%1000;
+ index = sim->create_part(-3,x+((random>>4)&3)-1,y+((random>>6)&3)-1,PT_ELEC);
+ if (index != -1)
+ parts[index].temp = 7000;
+ index = sim->create_part(-3,x+((random>>8)&3)-1,y+((random>>10)&3)-1,PT_PHOT);
+ if (index != -1)
+ parts[index].temp = 7000;
+ index = sim->create_part(-1,x+((random>>12)&3)-1,y+rand()%3-1,PT_BREC);
+ if (index != -1)
+ parts[index].temp = 7000;
+ parts[i].temp=9000;
+ sim->pv[y/CELL][x/CELL] += 50;
+
+ return 1;
+ }
+ }
+ //Neighbor check loop
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ r = sim->photons[y+ry][x+rx];
+ if (!r)
+ continue;
+ //Melts into EXOT
+ if ((r&0xFF) == PT_EXOT && !(rand()%250))
+ {
+ sim->create_part(i, x, y, PT_EXOT);
+ }
+ else if ((r&0xFF) == PT_ANAR)
+ {
+ sim->part_change_type(i,x,y,PT_BVBR);
+ sim->pv[y/CELL][x/CELL] -= 1;
+ }
+ else if (parts[i].life && ((r&0xFF)==PT_VIBR || (r&0xFF)==PT_BVBR) && !parts[r>>8].life)
+ {
+ parts[r>>8].tmp += 10;
+ }
+ //Absorbs energy particles
+ if ((sim->elements[r&0xFF].Properties & TYPE_ENERGY))
+ {
+ parts[i].tmp += 20;
+ sim->kill_part(r>>8);
+ }
+ }
+ for (trade = 0; trade < 9; trade++)
+ {
+ int random = rand();
+ rx = random%7-3;
+ ry = (random>>3)%7-3;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if ((r&0xFF) != PT_VIBR && (r&0xFF) != PT_BVBR)
+ continue;
+ if (parts[i].tmp > parts[r>>8].tmp)
+ {
+ transfer = parts[i].tmp - parts[r>>8].tmp;
+ if (transfer == 1)
+ {
+ parts[r>>8].tmp += 1;
+ parts[i].tmp -= 1;
+ trade = 9;
+ }
+ else if (transfer > 0)
+ {
+ parts[r>>8].tmp += transfer/2;
+ parts[i].tmp -= transfer/2;
+ trade = 9;
+ }
+ }
+ }
+ }
+ if (parts[i].tmp < 0)
+ parts[i].tmp = 0; // only preventing because negative tmp doesn't save
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_VIBR static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_VIBR::graphics(GRAPHICS_FUNC_ARGS)
+{
+ int gradient = cpart->tmp/10;
+ if (gradient >= 100 || cpart->life)
+ {
+ *colr = (int)(fabs(sin(exp((750.0f-cpart->life)/170)))*200.0f);
+ *colg = 255;
+ *colb = (int)(fabs(sin(exp((750.0f-cpart->life)/170)))*200.0f);
+ *firea = 90;
+ *firer = *colr;
+ *fireg = *colg;
+ *fireb = *colb;
+ *pixel_mode = PMODE_NONE;
+ *pixel_mode |= FIRE_BLEND;
+ }
+ else if (gradient < 100)
+ {
+ *colr += (int)restrict_flt(gradient*2.0f,0,255);
+ *colg += (int)restrict_flt(gradient*2.0f,0,175);
+ *colb += (int)restrict_flt(gradient*2.0f,0,255);
+ *firea = (int)restrict_flt(gradient*.6f,0,60);
+ *firer = *colr/2;
+ *fireg = *colg/2;
+ *fireb = *colb/2;
+ *pixel_mode |= FIRE_BLEND;
+ }
+ return 0;
+}
+
+Element_VIBR::~Element_VIBR() {}
diff --git a/src/simulation/elements/VINE.cpp b/src/simulation/elements/VINE.cpp
new file mode 100644
index 0000000..e31c8cd
--- /dev/null
+++ b/src/simulation/elements/VINE.cpp
@@ -0,0 +1,91 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_VINE PT_VINE 114
+Element_VINE::Element_VINE()
+{
+ Identifier = "DEFAULT_PT_VINE";
+ Name = "VINE";
+ Colour = PIXPACK(0x079A00);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 20;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 10;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 65;
+ Description = "Vine, grows";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 573.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = &Element_VINE::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_VINE static int update(UPDATE_FUNC_ARGS)
+int Element_VINE::update(UPDATE_FUNC_ARGS)
+ {
+ int r, np, rx =(rand()%3)-1, ry=(rand()%3)-1;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (1>rand()%15)
+ sim->part_change_type(i,x,y,PT_PLNT);
+ else if (!r)
+ {
+ np = sim->create_part(-1,x+rx,y+ry,PT_VINE);
+ if (np<0) return 0;
+ parts[np].temp = parts[i].temp;
+ parts[i].tmp = 1;
+ sim->part_change_type(i,x,y,PT_PLNT);
+ }
+ }
+ if (parts[i].temp > 350 && parts[i].temp > parts[i].tmp2)
+ parts[i].tmp2 = (int)parts[i].temp;
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_VINE static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_VINE::graphics(GRAPHICS_FUNC_ARGS)
+{
+ float maxtemp = std::max((float)cpart->tmp2, cpart->temp);
+ if (maxtemp > 300)
+ {
+ *colr += (int)restrict_flt((maxtemp-300)/5,0,58);
+ *colg -= (int)restrict_flt((maxtemp-300)/2,0,102);
+ *colb += (int)restrict_flt((maxtemp-300)/5,0,70);
+ }
+ if (maxtemp < 273)
+ {
+ *colg += (int)restrict_flt((273-maxtemp)/4,0,255);
+ *colb += (int)restrict_flt((273-maxtemp)/1.5,0,255);
+ }
+ return 0;
+}
+
+
+Element_VINE::~Element_VINE() {} \ No newline at end of file
diff --git a/src/simulation/elements/VOID.cpp b/src/simulation/elements/VOID.cpp
new file mode 100644
index 0000000..05eb872
--- /dev/null
+++ b/src/simulation/elements/VOID.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_VOID PT_VOID 22
+Element_VOID::Element_VOID()
+{
+ Identifier = "DEFAULT_PT_VOID";
+ Name = "VOID";
+ Colour = PIXPACK(0x790B0B);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 1.00f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = -0.0003f* CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Hole, will drain away any particles.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_VOID::~Element_VOID() {} \ No newline at end of file
diff --git a/src/simulation/elements/WARP.cpp b/src/simulation/elements/WARP.cpp
new file mode 100644
index 0000000..bb8f8e1
--- /dev/null
+++ b/src/simulation/elements/WARP.cpp
@@ -0,0 +1,95 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WARP PT_WARP 96
+Element_WARP::Element_WARP()
+{
+ Identifier = "DEFAULT_PT_WARP";
+ Name = "WARP";
+ Colour = PIXPACK(0x101010);
+ MenuVisible = 1;
+ MenuSection = SC_NUCLEAR;
+ Enabled = 1;
+
+ Advection = 0.8f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.9f;
+ Loss = 0.70f;
+ Collision = -0.1f;
+ Gravity = 0.0f;
+ Diffusion = 3.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 1;
+
+ Temperature = R_TEMP +273.15f;
+ HeatConduct = 100;
+ Description = "Displaces other elements.";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS|PROP_LIFE_DEC|PROP_LIFE_KILL;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_WARP::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_WARP static int update(UPDATE_FUNC_ARGS)
+int Element_WARP::update(UPDATE_FUNC_ARGS)
+ {
+ int trade, r, rx, ry;
+ if (parts[i].tmp2>2000)
+ {
+ parts[i].temp = 10000;
+ sim->pv[y/CELL][x/CELL] += (parts[i].tmp2/5000) * CFDS;
+ if (2>rand()%100)
+ sim->create_part(-3, x, y, PT_ELEC);
+ }
+ for ( trade = 0; trade<5; trade ++)
+ {
+ rx = rand()%3-1;
+ ry = rand()%3-1;
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)!=PT_WARP&&(r&0xFF)!=PT_STKM&&(r&0xFF)!=PT_STKM2&&(r&0xFF)!=PT_DMND&&(r&0xFF)!=PT_CLNE&&(r&0xFF)!=PT_BCLN&&(r&0xFF)!=PT_PCLN)
+ {
+ parts[i].x = parts[r>>8].x;
+ parts[i].y = parts[r>>8].y;
+ parts[r>>8].x = x;
+ parts[r>>8].y = y;
+ parts[r>>8].vx = (rand()%4)-1.5;
+ parts[r>>8].vy = (rand()%4)-2;
+ parts[i].life += 4;
+ pmap[y][x] = r;
+ pmap[y+ry][x+rx] = (i<<8)|parts[i].type;
+ trade = 5;
+ }
+ }
+ }
+ return 0;
+}
+
+//#TPT-Directive ElementHeader Element_WARP static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_WARP::graphics(GRAPHICS_FUNC_ARGS)
+{
+ *colr = *colg = *colb = *cola = 0;
+ *pixel_mode &= ~PMODE;
+ return 0;
+}
+
+Element_WARP::~Element_WARP() {}
diff --git a/src/simulation/elements/WATR.cpp b/src/simulation/elements/WATR.cpp
new file mode 100644
index 0000000..f0fde66
--- /dev/null
+++ b/src/simulation/elements/WATR.cpp
@@ -0,0 +1,89 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WATR PT_WATR 2
+Element_WATR::Element_WATR()
+{
+ Identifier = "DEFAULT_PT_WATR";
+ Name = "WATR";
+ Colour = PIXPACK(0x2030D0);
+ MenuVisible = 1;
+ MenuSection = SC_LIQUID;
+ Enabled = 1;
+
+ Advection = 0.6f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.98f;
+ Loss = 0.95f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 2;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 20;
+
+ Weight = 30;
+
+ Temperature = R_TEMP-2.0f +273.15f;
+ HeatConduct = 29;
+ Description = "Liquid. Conducts electricity. Freezes. Extinguishes fires.";
+
+ State = ST_LIQUID;
+ Properties = TYPE_LIQUID|PROP_CONDUCTS|PROP_LIFE_DEC|PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 273.15f;
+ LowTemperatureTransition = PT_ICEI;
+ HighTemperature = 373.0f;
+ HighTemperatureTransition = PT_WTRV;
+
+ Update = &Element_WATR::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_WATR static int update(UPDATE_FUNC_ARGS)
+int Element_WATR::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_SALT && 1>(rand()%250))
+ {
+ sim->part_change_type(i,x,y,PT_SLTW);
+ // on average, convert 3 WATR to SLTW before SALT turns into SLTW
+ if (rand()%3==0)
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SLTW);
+ }
+ if (((r&0xFF)==PT_RBDM||(r&0xFF)==PT_LRBD) && (sim->legacy_enable||parts[i].temp>(273.15f+12.0f)) && 1>(rand()%500))
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = 4;
+ parts[i].ctype = PT_WATR;
+ }
+ if ((r&0xFF)==PT_FIRE && parts[r>>8].ctype!=PT_WATR){
+ sim->kill_part(r>>8);
+ if(1>(rand()%150)){
+ sim->kill_part(i);
+ return 1;
+ }
+ }
+ /*if ((r&0xFF)==PT_CNCT && 1>(rand()%500)) Concrete+Water to paste, not very popular
+ {
+ part_change_type(i,x,y,PT_PSTE);
+ sim.kill_part(r>>8);
+ }*/
+ }
+ return 0;
+}
+
+Element_WATR::~Element_WATR() {}
diff --git a/src/simulation/elements/WAX.cpp b/src/simulation/elements/WAX.cpp
new file mode 100644
index 0000000..5f9a113
--- /dev/null
+++ b/src/simulation/elements/WAX.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WAX PT_WAX 33
+Element_WAX::Element_WAX()
+{
+ Identifier = "DEFAULT_PT_WAX";
+ Name = "WAX";
+ Colour = PIXPACK(0xF0F0BB);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 10;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 44;
+ Description = "Wax. Melts at moderately high temperatures.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 319.0f;
+ HighTemperatureTransition = PT_MWAX;
+
+ Update = NULL;
+
+}
+
+Element_WAX::~Element_WAX() {} \ No newline at end of file
diff --git a/src/simulation/elements/WHOL.cpp b/src/simulation/elements/WHOL.cpp
new file mode 100644
index 0000000..3007960
--- /dev/null
+++ b/src/simulation/elements/WHOL.cpp
@@ -0,0 +1,49 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WHOL PT_WHOL 40
+Element_WHOL::Element_WHOL()
+{
+ Identifier = "DEFAULT_PT_WHOL";
+ Name = "VENT";
+ Colour = PIXPACK(0xEFEFEF);
+ MenuVisible = 1;
+ MenuSection = SC_SPECIAL;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.95f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.010f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP-16.0f+273.15f;
+ HeatConduct = 255;
+ Description = "Air vent, creates pressure and pushes other particles away.";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = NULL;
+
+}
+
+Element_WHOL::~Element_WHOL() {} \ No newline at end of file
diff --git a/src/simulation/elements/WIFI.cpp b/src/simulation/elements/WIFI.cpp
new file mode 100644
index 0000000..4cbf0d5
--- /dev/null
+++ b/src/simulation/elements/WIFI.cpp
@@ -0,0 +1,101 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WIFI PT_WIFI 124
+Element_WIFI::Element_WIFI()
+{
+ Identifier = "DEFAULT_PT_WIFI";
+ Name = "WIFI";
+ Colour = PIXPACK(0x40A060);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 2;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 0;
+ Description = "Wireless transmitter, color coded.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = 15.0f;
+ HighPressureTransition = PT_BRMT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_WIFI::update;
+ Graphics = &Element_WIFI::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_WIFI static int update(UPDATE_FUNC_ARGS)
+int Element_WIFI::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ parts[i].tmp = (int)((parts[i].temp-73.15f)/100+1);
+ if (parts[i].tmp>=CHANNELS) parts[i].tmp = CHANNELS-1;
+ else if (parts[i].tmp<0) parts[i].tmp = 0;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ // wireless[][0] - whether channel is active on this frame
+ // wireless[][1] - whether channel should be active on next frame
+ if (sim->wireless[parts[i].tmp][0])
+ {
+ if (((r&0xFF)==PT_NSCN||(r&0xFF)==PT_PSCN||(r&0xFF)==PT_INWR)&&parts[r>>8].life==0 && sim->wireless[parts[i].tmp][0])
+ {
+ parts[r>>8].ctype = r&0xFF;
+ sim->part_change_type(r>>8,x+rx,y+ry,PT_SPRK);
+ parts[r>>8].life = 4;
+ }
+ }
+ else
+ {
+ if ((r&0xFF)==PT_SPRK && parts[r>>8].ctype!=PT_NSCN && parts[r>>8].life>=3)
+ {
+ sim->wireless[parts[i].tmp][1] = 1;
+ sim->ISWIRE = 2;
+ }
+ }
+ }
+ return 0;
+}
+
+
+//#TPT-Directive ElementHeader Element_WIFI static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_WIFI::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ float frequency = 0.0628;
+ int q = cpart->tmp;
+ *colr = sin(frequency*q + 0) * 127 + 128;
+ *colg = sin(frequency*q + 2) * 127 + 128;
+ *colb = sin(frequency*q + 4) * 127 + 128;
+ *pixel_mode |= EFFECT_DBGLINES;
+ return 0;
+}
+
+
+Element_WIFI::~Element_WIFI() {} \ No newline at end of file
diff --git a/src/simulation/elements/WIRE.cpp b/src/simulation/elements/WIRE.cpp
new file mode 100644
index 0000000..4f59060
--- /dev/null
+++ b/src/simulation/elements/WIRE.cpp
@@ -0,0 +1,127 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WIRE PT_WIRE 156
+Element_WIRE::Element_WIRE()
+{
+ Identifier = "DEFAULT_PT_WIRE";
+ Name = "WIRE";
+ Colour = PIXPACK(0xFFCC00);
+ MenuVisible = 1;
+ MenuSection = SC_ELEC;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.00f;
+ 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 = 0;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 250;
+ Description = "WireWorld wires.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_WIRE::update;
+ Graphics = &Element_WIRE::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_WIRE static int update(UPDATE_FUNC_ARGS)
+int Element_WIRE::update(UPDATE_FUNC_ARGS)
+ {
+ int s,r,rx,ry,count;
+ /*
+ 0: wire
+ 1: spark head
+ 2: spark tail
+
+ tmp is previous state, ctype is current state
+ */
+ //parts[i].tmp=parts[i].ctype;
+ parts[i].ctype=0;
+ if(parts[i].tmp==1)
+ {
+ parts[i].ctype=2;
+ }
+ if(parts[i].tmp==2)
+ {
+ parts[i].ctype=0;
+ }
+
+ count=0;
+ for(rx=-1; rx<2; rx++)
+ for(ry=-1; ry<2; ry++)
+ {
+ if(x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if((r&0xFF)==PT_SPRK && parts[r>>8].life==3 && parts[r>>8].ctype==PT_PSCN)
+ {
+ parts[i].ctype=1;
+ return 0;
+ }
+ else if((r&0xFF)==PT_NSCN && parts[i].tmp==1){sim->create_part(-1, x+rx, y+ry, PT_SPRK);}
+ else if((r&0xFF)==PT_WIRE && parts[r>>8].tmp==1 && !parts[i].tmp){count++;}
+ }
+ }
+ if(count==1 || count==2)
+ parts[i].ctype=1;
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_WIRE static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_WIRE::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if (cpart->ctype==0)
+ {
+ *colr = 255;
+ *colg = 204;
+ *colb = 0;
+ return 0;
+ }
+ if (cpart->ctype==1)
+ {
+ *colr = 50;
+ *colg = 100;
+ *colb = 255;
+ //*pixel_mode |= PMODE_GLOW;
+ return 0;
+ }
+ if (cpart->ctype==2)
+ {
+ *colr = 255;
+ *colg = 100;
+ *colb = 50;
+ //*pixel_mode |= PMODE_GLOW;
+ return 0;
+ }
+ return 0;
+}
+
+
+Element_WIRE::~Element_WIRE() {} \ No newline at end of file
diff --git a/src/simulation/elements/WOOD.cpp b/src/simulation/elements/WOOD.cpp
new file mode 100644
index 0000000..54e2e50
--- /dev/null
+++ b/src/simulation/elements/WOOD.cpp
@@ -0,0 +1,70 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WOOD PT_WOOD 17
+Element_WOOD::Element_WOOD()
+{
+ Identifier = "DEFAULT_PT_WOOD";
+ Name = "WOOD";
+ Colour = PIXPACK(0xC0A040);
+ MenuVisible = 1;
+ MenuSection = SC_SOLIDS;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ Loss = 0.00f;
+ Collision = 0.0f;
+ Gravity = 0.0f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 0;
+
+ Flammable = 20;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 15;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 164;
+ Description = "Solid. Flammable.";
+
+ State = ST_SOLID;
+ Properties = TYPE_SOLID | PROP_NEUTPENETRATE;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 873.0f;
+ HighTemperatureTransition = PT_FIRE;
+
+ Update = NULL;
+ Graphics = &Element_WOOD::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_WOOD static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_WOOD::graphics(GRAPHICS_FUNC_ARGS)
+{
+ float maxtemp = std::max((float)cpart->tmp, cpart->temp);
+ if (maxtemp > 400)
+ {
+ *colr -= (int)restrict_flt((maxtemp-400)/3,0,172);
+ *colg -= (int)restrict_flt((maxtemp-400)/4,0,140);
+ *colb -= (int)restrict_flt((maxtemp-400)/20,0,44);
+ if (maxtemp > 450)
+ cpart->tmp = (int)maxtemp;
+ }
+ if (maxtemp < 273)
+ {
+ *colr -= (int)restrict_flt((273-maxtemp)/5,0,40);
+ *colg += (int)restrict_flt((273-maxtemp)/4,0,40);
+ *colb += (int)restrict_flt((273-maxtemp)/1.5,0,150);
+ }
+ return 0;
+}
+
+Element_WOOD::~Element_WOOD() {} \ No newline at end of file
diff --git a/src/simulation/elements/WTRV.cpp b/src/simulation/elements/WTRV.cpp
new file mode 100644
index 0000000..fb72db8
--- /dev/null
+++ b/src/simulation/elements/WTRV.cpp
@@ -0,0 +1,73 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_WTRV PT_WTRV 23
+Element_WTRV::Element_WTRV()
+{
+ Identifier = "DEFAULT_PT_WTRV";
+ Name = "WTRV";
+ Colour = PIXPACK(0xA0A0FF);
+ MenuVisible = 1;
+ MenuSection = SC_GAS;
+ Enabled = 1;
+
+ Advection = 1.0f;
+ AirDrag = 0.01f * CFDS;
+ AirLoss = 0.99f;
+ Loss = 0.30f;
+ Collision = -0.1f;
+ Gravity = -0.1f;
+ Diffusion = 0.75f;
+ HotAir = 0.0003f * CFDS;
+ Falldown = 0;
+
+ Flammable = 0;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 4;
+
+ Weight = 1;
+
+ Temperature = R_TEMP+100.0f+273.15f;
+ HeatConduct = 48;
+ Description = "Steam, heats up air, produced from hot water.";
+
+ State = ST_GAS;
+ Properties = TYPE_GAS;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = 371.0f;
+ LowTemperatureTransition = ST;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_WTRV::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_WTRV static int update(UPDATE_FUNC_ARGS)
+int Element_WTRV::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if (((r&0xFF)==PT_RBDM||(r&0xFF)==PT_LRBD) && !sim->legacy_enable && parts[i].temp>(273.15f+12.0f) && 1>(rand()%500))
+ {
+ sim->part_change_type(i,x,y,PT_FIRE);
+ parts[i].life = 4;
+ parts[i].ctype = PT_WATR;
+ }
+ }
+ if(parts[i].temp>1273&&parts[i].ctype==PT_FIRE)
+ parts[i].temp-=parts[i].temp/1000;
+ return 0;
+}
+
+
+Element_WTRV::~Element_WTRV() {} \ No newline at end of file
diff --git a/src/simulation/elements/YEST.cpp b/src/simulation/elements/YEST.cpp
new file mode 100644
index 0000000..99df265
--- /dev/null
+++ b/src/simulation/elements/YEST.cpp
@@ -0,0 +1,72 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_YEST PT_YEST 63
+Element_YEST::Element_YEST()
+{
+ Identifier = "DEFAULT_PT_YEST";
+ Name = "YEST";
+ Colour = PIXPACK(0xEEE0C0);
+ MenuVisible = 1;
+ MenuSection = SC_POWDERS;
+ Enabled = 1;
+
+ Advection = 0.7f;
+ AirDrag = 0.02f * CFDS;
+ AirLoss = 0.96f;
+ Loss = 0.80f;
+ Collision = 0.0f;
+ Gravity = 0.1f;
+ Diffusion = 0.00f;
+ HotAir = 0.000f * CFDS;
+ Falldown = 1;
+
+ Flammable = 15;
+ Explosive = 0;
+ Meltable = 0;
+ Hardness = 30;
+
+ Weight = 80;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 70;
+ Description = "Yeast, grows when warm (~37C).";
+
+ State = ST_SOLID;
+ Properties = TYPE_PART;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = 373.0f;
+ HighTemperatureTransition = PT_DYST;
+
+ Update = &Element_YEST::update;
+
+}
+
+//#TPT-Directive ElementHeader Element_YEST static int update(UPDATE_FUNC_ARGS)
+int Element_YEST::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ for (rx=-2; rx<3; rx++)
+ for (ry=-2; ry<3; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if (!r)
+ continue;
+ if ((r&0xFF)==PT_DYST && 1>(rand()%30) && !sim->legacy_enable)
+ {
+ sim->part_change_type(i,x,y,PT_DYST);
+ }
+ }
+ if (parts[i].temp>303&&parts[i].temp<317) {
+ sim->create_part(-1, x+rand()%3-1, y+rand()%3-1, PT_YEST);
+ }
+ return 0;
+}
+
+
+Element_YEST::~Element_YEST() {} \ No newline at end of file
diff --git a/src/simulation/elements/dcel.cpp b/src/simulation/elements/dcel.cpp
new file mode 100644
index 0000000..07f930b
--- /dev/null
+++ b/src/simulation/elements/dcel.cpp
@@ -0,0 +1,85 @@
+#include "simulation/Elements.h"
+//#TPT-Directive ElementClass Element_DCEL PT_DCEL 138
+Element_DCEL::Element_DCEL()
+{
+ Identifier = "DEFAULT_PT_DCEL";
+ Name = "DCEL";
+ Colour = PIXPACK(0x99CC00);
+ MenuVisible = 1;
+ MenuSection = SC_FORCE;
+ Enabled = 1;
+
+ Advection = 0.0f;
+ AirDrag = 0.00f * CFDS;
+ AirLoss = 0.90f;
+ 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 = 1;
+
+ Weight = 100;
+
+ Temperature = R_TEMP+0.0f +273.15f;
+ HeatConduct = 251;
+ Description = "Decelerator";
+
+ State = ST_NONE;
+ Properties = TYPE_SOLID;
+
+ LowPressure = IPL;
+ LowPressureTransition = NT;
+ HighPressure = IPH;
+ HighPressureTransition = NT;
+ LowTemperature = ITL;
+ LowTemperatureTransition = NT;
+ HighTemperature = ITH;
+ HighTemperatureTransition = NT;
+
+ Update = &Element_DCEL::update;
+ Graphics = &Element_DCEL::graphics;
+}
+
+//#TPT-Directive ElementHeader Element_DCEL static int update(UPDATE_FUNC_ARGS)
+int Element_DCEL::update(UPDATE_FUNC_ARGS)
+ {
+ int r, rx, ry;
+ parts[i].tmp = 0;
+ for (rx=-1; rx<2; rx++)
+ for (ry=-1; ry<2; ry++)
+ if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry) && !(rx && ry))
+ {
+ r = pmap[y+ry][x+rx];
+ if(!r)
+ r = sim->photons[y+ry][x+rx];
+ if ((r>>8)>=NPART || !r)
+ continue;
+ if(sim->elements[r&0xFF].Properties & (TYPE_PART | TYPE_LIQUID | TYPE_GAS | TYPE_ENERGY))
+ {
+ parts[r>>8].vx *= 0.9f;
+ parts[r>>8].vy *= 0.9f;
+ parts[i].tmp = 1;
+ }
+ }
+ return 0;
+}
+
+
+
+//#TPT-Directive ElementHeader Element_DCEL static int graphics(GRAPHICS_FUNC_ARGS)
+int Element_DCEL::graphics(GRAPHICS_FUNC_ARGS)
+
+{
+ if(cpart->tmp)
+ *pixel_mode |= PMODE_GLOW;
+ return 0;
+}
+
+
+Element_DCEL::~Element_DCEL() {} \ No newline at end of file
diff --git a/src/simulation/tools/AirTool.cpp b/src/simulation/tools/AirTool.cpp
new file mode 100644
index 0000000..9fd7f79
--- /dev/null
+++ b/src/simulation/tools/AirTool.cpp
@@ -0,0 +1,22 @@
+#include "simulation/Tools.h"
+#include "simulation/Air.h"
+//#TPT-Directive ToolClass Tool_Air TOOL_AIR 3
+Tool_Air::Tool_Air()
+{
+ Identifier = "DEFAULT_TOOL_AIR";
+ Name = "AIR";
+ Colour = PIXPACK(0xFFFFFF);
+ Description = "Creates air pressure";
+}
+
+int Tool_Air::Perform(Simulation * sim, Particle * cpart, int x, int y, float strength)
+{
+ sim->air->pv[y/CELL][x/CELL] += 0.03f*strength;
+ if(sim->air->pv[y/CELL][x/CELL] > 256.0f)
+ sim->air->pv[y/CELL][x/CELL] = 256.0f;
+ if(sim->air->pv[y/CELL][x/CELL] < -256.0f)
+ sim->air->pv[y/CELL][x/CELL] = -256.0f;
+ return 1;
+}
+
+Tool_Air::~Tool_Air() {} \ No newline at end of file
diff --git a/src/simulation/tools/Cool.cpp b/src/simulation/tools/Cool.cpp
new file mode 100644
index 0000000..b1b57b1
--- /dev/null
+++ b/src/simulation/tools/Cool.cpp
@@ -0,0 +1,23 @@
+#include "simulation/Tools.h"
+//#TPT-Directive ToolClass Tool_Cool TOOL_COOL 1
+Tool_Cool::Tool_Cool()
+{
+ Identifier = "DEFAULT_TOOL_COOL";
+ Name = "COOL";
+ Colour = PIXPACK(0x00DDFF);
+ Description = "Cools particles";
+}
+
+int Tool_Cool::Perform(Simulation * sim, Particle * cpart, int x, int y, float strength)
+{
+ if(!cpart)
+ return 0;
+ cpart->temp -= strength;
+ if(cpart->temp > MAX_TEMP)
+ cpart->temp = MAX_TEMP;
+ if(cpart->temp < 0)
+ cpart->temp = 0;
+ return 1;
+}
+
+Tool_Cool::~Tool_Cool() {} \ No newline at end of file
diff --git a/src/simulation/tools/GravTool.cpp b/src/simulation/tools/GravTool.cpp
new file mode 100644
index 0000000..630ba12
--- /dev/null
+++ b/src/simulation/tools/GravTool.cpp
@@ -0,0 +1,18 @@
+#include "simulation/Tools.h"
+#include "simulation/Simulation.h"
+//#TPT-Directive ToolClass Tool_Grav TOOL_GRAV 4
+Tool_Grav::Tool_Grav()
+{
+ Identifier = "DEFAULT_TOOL_GRAV";
+ Name = "GRAV";
+ Colour = PIXPACK(0xCCCCFF);
+ Description = "Creates a short-lasting gravity well";
+}
+
+int Tool_Grav::Perform(Simulation * sim, Particle * cpart, int x, int y, float strength)
+{
+ sim->gravmap[((y/CELL)*(XRES/CELL))+(x/CELL)] += 0.03f*strength;
+ return 1;
+}
+
+Tool_Grav::~Tool_Grav() {} \ No newline at end of file
diff --git a/src/simulation/tools/Heat.cpp b/src/simulation/tools/Heat.cpp
new file mode 100644
index 0000000..f28274c
--- /dev/null
+++ b/src/simulation/tools/Heat.cpp
@@ -0,0 +1,23 @@
+#include "simulation/Tools.h"
+//#TPT-Directive ToolClass Tool_Heat TOOL_HEAT 0
+Tool_Heat::Tool_Heat()
+{
+ Identifier = "DEFAULT_TOOL_HEAT";
+ Name = "HEAT";
+ Colour = PIXPACK(0xFFDD00);
+ Description = "Heats particles";
+}
+
+int Tool_Heat::Perform(Simulation * sim, Particle * cpart, int x, int y, float strength)
+{
+ if(!cpart)
+ return 0;
+ cpart->temp += strength;
+ if(cpart->temp > MAX_TEMP)
+ cpart->temp = MAX_TEMP;
+ if(cpart->temp < 0)
+ cpart->temp = 0;
+ return 1;
+}
+
+Tool_Heat::~Tool_Heat() {} \ No newline at end of file
diff --git a/src/simulation/tools/NGrv.cpp b/src/simulation/tools/NGrv.cpp
new file mode 100644
index 0000000..525d697
--- /dev/null
+++ b/src/simulation/tools/NGrv.cpp
@@ -0,0 +1,18 @@
+#include "simulation/Tools.h"
+#include "simulation/Simulation.h"
+//#TPT-Directive ToolClass Tool_NGrv TOOL_NGRV 5
+Tool_NGrv::Tool_NGrv()
+{
+ Identifier = "DEFAULT_TOOL_NGRV";
+ Name = "NGRV";
+ Colour = PIXPACK(0xAACCFF);
+ Description = "Creates a short-lasting negative gravity well";
+}
+
+int Tool_NGrv::Perform(Simulation * sim, Particle * cpart, int x, int y, float strength)
+{
+ sim->gravmap[((y/CELL)*(XRES/CELL))+(x/CELL)] -= 0.03f*strength;
+ return 1;
+}
+
+Tool_NGrv::~Tool_NGrv() {} \ No newline at end of file
diff --git a/src/simulation/tools/SimTool.cpp b/src/simulation/tools/SimTool.cpp
new file mode 100644
index 0000000..d7015fa
--- /dev/null
+++ b/src/simulation/tools/SimTool.cpp
@@ -0,0 +1,10 @@
+#include "simulation/Element.h"
+#include "simulation/Tools.h"
+
+SimTool::SimTool():
+Identifier("DEFAULT_TOOL_INVALID"),
+Name(""),
+Colour(PIXPACK(0xFFFFFF)),
+Description("NULL Tool, does NOTHING")
+{
+} \ No newline at end of file
diff --git a/src/simulation/tools/SimTool.h b/src/simulation/tools/SimTool.h
new file mode 100644
index 0000000..c32ba5b
--- /dev/null
+++ b/src/simulation/tools/SimTool.h
@@ -0,0 +1,23 @@
+#ifndef SIMTOOL_H
+#define SIMTOOL_H
+
+#include "simulation/Simulation.h"
+#include "graphics/Renderer.h"
+#include "simulation/Elements.h"
+
+class Simulation;
+struct Particle;
+class SimTool
+{
+public:
+ char *Identifier;
+ char *Name;
+ pixel Colour;
+ char *Description;
+
+ SimTool();
+ virtual ~SimTool() {}
+ virtual int Perform(Simulation * sim, Particle * cpart, int x, int y, float strength) { return 0; }
+};
+
+#endif \ No newline at end of file
diff --git a/src/simulation/tools/Vac.cpp b/src/simulation/tools/Vac.cpp
new file mode 100644
index 0000000..aa319e2
--- /dev/null
+++ b/src/simulation/tools/Vac.cpp
@@ -0,0 +1,22 @@
+#include "simulation/Tools.h"
+#include "simulation/Air.h"
+//#TPT-Directive ToolClass Tool_Vac TOOL_VAC 2
+Tool_Vac::Tool_Vac()
+{
+ Identifier = "DEFAULT_TOOL_VAC";
+ Name = "VAC";
+ Colour = PIXPACK(0x303030);
+ Description = "Removes air pressure";
+}
+
+int Tool_Vac::Perform(Simulation * sim, Particle * cpart, int x, int y, float strength)
+{
+ sim->air->pv[y/CELL][x/CELL] -= 0.03f*strength;
+ if(sim->air->pv[y/CELL][x/CELL] > 256.0f)
+ sim->air->pv[y/CELL][x/CELL] = 256.0f;
+ if(sim->air->pv[y/CELL][x/CELL] < -256.0f)
+ sim->air->pv[y/CELL][x/CELL] = -256.0f;
+ return 1;
+}
+
+Tool_Vac::~Tool_Vac() {}