commit 68e9f04b4aa8f4e1c0f14f005204853aef8969f6 Author: Marisa the Magician Date: Sun Oct 8 22:27:33 2023 +0200 Funny proof of concept here. diff --git a/Pad_FX.ftx b/Pad_FX.ftx new file mode 100644 index 0000000..7a3b605 --- /dev/null +++ b/Pad_FX.ftx @@ -0,0 +1,25 @@ +Pad_FX 256 256 +Pad_FX +0 40 2750 +Wheel 255 127 130 88 204 200 12 +Wheel 255 125 124 136 204 200 12 +Wheel 255 126 130 144 204 200 12 +Wheel 255 126 124 136 204 200 12 +Wheel 255 125 125 80 204 200 12 +Wheel 255 126 127 200 204 200 12 +Wheel 255 128 128 248 204 200 12 +Wheel 255 124 129 248 204 200 12 +Wheel 255 125 127 168 204 200 12 +Wheel 255 127 126 0 204 200 12 +Wheel 255 127 124 192 204 200 12 +Wheel 255 125 128 24 204 200 12 +Wheel 255 128 127 192 204 200 12 +Wheel 255 125 124 72 204 200 12 +Wheel 255 127 129 56 204 200 12 +Wheel 255 125 124 104 204 200 12 +Wheel 255 124 126 216 204 200 12 +Wheel 255 123 125 16 204 200 12 +Wheel 255 126 127 224 204 200 12 +Wheel 255 123 126 48 204 200 12 +Wheel 255 125 129 112 204 200 12 +Wheel 255 126 126 160 204 200 12 diff --git a/animdefs.txt b/animdefs.txt new file mode 100644 index 0000000..5c8a9d8 --- /dev/null +++ b/animdefs.txt @@ -0,0 +1,2 @@ +// put ur canvas here +canvastexture Pad_FX 256 256 diff --git a/palettes/Pad_FX.pal b/palettes/Pad_FX.pal new file mode 100644 index 0000000..918bbc2 Binary files /dev/null and b/palettes/Pad_FX.pal differ diff --git a/zmapinfo.txt b/zmapinfo.txt new file mode 100644 index 0000000..ca2e74a --- /dev/null +++ b/zmapinfo.txt @@ -0,0 +1,4 @@ +GameInfo +{ + AddEventHandlers = "FireTextureTestHandler" +} diff --git a/zscript.txt b/zscript.txt new file mode 100644 index 0000000..5efe036 --- /dev/null +++ b/zscript.txt @@ -0,0 +1,4 @@ +version "4.11" + +#include "zscript/firetexture_m/include.zsc" +#include "zscript/ft_testhandler.zsc" diff --git a/zscript/firetexture_m/ft_baseclass.zsc b/zscript/firetexture_m/ft_baseclass.zsc new file mode 100644 index 0000000..342c4de --- /dev/null +++ b/zscript/firetexture_m/ft_baseclass.zsc @@ -0,0 +1,215 @@ +// This is a very awful and hacky and gross attempt at replicating Unreal's +// FireTexture class in ZScript using canvas drawing +// +// Abandon all hope ye who enter here + +class FireSpark +{ + int type; // see above enums + int heat; // heat of this spark + int x, y; // location + + int args[4]; // arguments + // 0: usually x speed + // 1: usually y speed + // 2: usually age or emitter frequency + // 3: usually expiration time +} + +class FireTexture +{ + enum EFireSpark + { + SPARK_Burn, // stationary spark with randomized intensity + SPARK_Sparkle, // sparks that jitter + SPARK_Pulse, // sparks that turn on and off + SPARK_Signal, // akin to burn but with some tweakable behavior (?) + SPARK_Blaze, // sparks emitted in random directions + SPARK_OzHasSpoken, // sparks that move up and fade out + SPARK_Cone, // akin to blaze but with gravity + SPARK_BlazeRight, // blaze but aiming to the right + SPARK_BlazeLeft, // blaze but aiming to the left + SPARK_Cylinder, // sparks that ping-pong horizontally + SPARK_Cylinder3D, // like above but sparks are invisible on their way back + SPARK_Lissajous, // sparks that ping-pong both horizontally and vertically at different frequencies + SPARK_Jugglers, // like cylinder but vertical + SPARK_Emit, // sparks that move in a random straight direction and fade out + SPARK_Fountain, // like emit but with gravity + SPARK_Flocks, // bunch of sparks that jitter smoothly in a circular area + SPARK_Eels, // like emit except not (?) + SPARK_Organic, // sparks that move up with slightly randomized angles + SPARK_WanderOrganic, // hell if I know + SPARK_RandomCloud, // ??????? + SPARK_CustomCloud, // ??????????????? + SPARK_LocalCloud, // ???????????????????? + SPARK_Stars, // single pixels of constant intensity + SPARK_LineLightning, // lightning bolts that zap between two spots + SPARK_RampLightning, // like above, but the intensity fades towards the endpoint + SPARK_SphereLightning, // like above, but the bolts spread out in all directions + SPARK_Wheel, // sparks that move in circles + SPARK_Gametes, // like Eels but sorta wriggly + SPARK_Sprinkler, // what it says on the tin + NUM_SPARK_TYPES + }; + + enum EFireSparkInternal + { + // special types + SPARK_LissajousX = NUM_SPARK_TYPES, + SPARK_LissajousY, + // spawned sparks (names are my own here, based on guesswork) + SSPARK_Unused, // not used at all, may have been some form of padding? + SSPARK_Ember, // ember from a Blaze type, constant speed, fades out + SSPARK_EmberCustom, // like above but fades based on args[3], used by OzHasSpoken and Emit + SSPARK_Gravity, // y speed is affected by gravity, dies after a set timeout, used by Cone and BlazeRight/Left + SSPARK_Rising, // fading out, constant upwards speed, used by Organic types + SSPARK_CloudY, // same but fades in instead of out, used by Random/LocalCloud + SSPARK_CloudXY, // this one moves in all directions, used by CustomCloud + SSPARK_Eel, // moves in a chosen direction and fades out very slowly, spawned by Eels + SSPARK_Twirl, // horizontal and vertical speed spin in a circle, used by Flocks and Wheel + SSPARK_Sprinkle, // rises up at constant speed, horizontal speed is sinusoidal, used by Sprinkler + SSPARK_EmberCustom2, // identical but uses args[2] instead, seemingly unused + SSPARK_GravityFade, // used by Fountain, has half gravity and fades out + SSPARK_Gamete // like eels but moving erratically, spawned by Gametes + }; + + private bool initd; // true if the texture has been initialized + + private int sparklimit; // maximum sparks allowed to be rendered + + private uint phase; // global timer + private Array sparks;// all the active sparks + private bool bhasstars; // true if any sparks with type SPARK_Stars exist + + // parses a fire texture from a file + static FireTexture Load( string path ) + { + static const String typetable[] = + { + "Burn", "Sparkle", "Pulse", "Signal", "Blaze", + "OzHasSpoken", "Cone", "BlazeRight", "BlazeLeft", + "Cylinder", "Cylinder3D", "Lissajous", "Jugglers", + "Emit", "Fountain", "Flocks", "Eels", "Organic", + "WanderOrganic", "RandomCloud", "CustomCloud", + "LocalCloud", "Stars", "LineLighting", "RampLighting", + "SphereLighting", "Wheel", "Gametes", "Sprinkler" + }; + int lmp = Wads.CheckNumForFullName(path); + if ( lmp == -1 ) ThrowAbortException("Could not find fire texture '%s'.",path); + String dat = Wads.ReadLump(lmp); + dat.Replace("\r",""); + Array lines, line; + dat.Split(lines,"\n",TOK_SKIPEMPTY); + String cname; + uint width, height; + lines[0].Split(line," "); + cname = line[0]; + width = line[1].ToInt(); + height = line[2].ToInt(); + FireTexture ftx = new("FireTexture"); + ftx.Init(width,height); + ftx.cv = TexMan.GetCanvas(cname); + if ( !ftx.cv ) ThrowAbortException("Could not find canvas '%s'",cname); + lmp = Wads.CheckNumForFullName("palettes/"..lines[1]..".pal"); + if ( lmp == -1 ) ThrowAbortException("Could not find palette '%s'",lines[1]); + dat = Wads.ReadLump(lmp); + for ( uint i=0; i<256; i++ ) + { + ftx.pal[i].a = 255; + ftx.pal[i].r = dat.ByteAt(i*3); + ftx.pal[i].g = dat.ByteAt(i*3+1); + ftx.pal[i].b = dat.ByteAt(i*3+2); + } + line.Clear(); + lines[2].Split(line," "); + ftx.brising = !!line[0].ToInt(); + ftx.renderheat = line[1].ToInt(); + ftx.sparklimit = line[2].ToInt(); + ftx.sparks.Clear(); + for ( int i=3; i 256 ) ThrowAbortException("Tried to init FireTexture with width above 256."); + if ( vsize > 256 ) ThrowAbortException("Tried to init FireTexture with height above 256."); + width = usize; + height = vsize; + umask = width-1; + vmask = height-1; + InitTables(); + initd = true; + } + + void Tick() + { + RedrawSparks(); + if ( bRising ) CalcWrapFire(); + else CalcSlowFire(); + PostDrawSparks(); + } + + void Render() + { + // blit to canvas, one pixel at a time (oof) + for ( uint y=0; y= w)) || ((w&1) && ((h*2) < w)) ) + { + x += (w&1)?-w:w; + y += (h&1)?-h:h; + w ^= 1; + h ^= 1; + uint tmp = fromcol; + fromcol = tocol; + tocol = tmp; + } + int longest = 1|((w>=h)?w:h); + uint fpos = 0; + for ( int f=0; f= h ) + { + int yz = (y<<6); + int bias = ((ylen<<6)-fpos)/longest; + for ( int f=0; f>6,(rcol+=cslope)>>23); + x += xstep; + } + } + else + { + int xz = (x<<6); + int bias = ((xlen<<6)-fpos)/longest; + for ( int f=0; f>6,y,(rcol+=cslope)>>23); + y += ystep; + } + } + } + + // handle all sparks (big heckin' function here) + private void RedrawSparks() + { + uint newx, newy, newh; + uint ns; + phase++; + for ( int i=0; i>8); + newy = s.y+((FastRand()*s.args[1])>>8); + PutPixel(newx,newy,s.heat); + break; + } + case SPARK_Pulse: + { + PutPixel(s.x,s.y,s.heat); + s.heat = (s.heat+s.args[3])&255; + break; + } + case SPARK_Signal: + { + if ( s.heat > s.args[2] ) + PutPixel(s.x,s.y,s.heat); + s.heat = (s.heat+s.args[3])&255; + if ( s.heat < s.args[3] ) + s.heat = FastRand(); + break; + } + case SPARK_Cylinder: + { + newh = min(phasetable[(s.args[0]+64)&255]+s.heat,255); + newx = s.x+((phasetable[s.args[0]]*s.args[1])>>8); + PutPixel(newx,s.y,newh); + s.args[0] = (s.args[0]+s.args[3])&255; + break; + } + case SPARK_Cylinder3D: + { + if ( ((s.args[0]+64)&255) < 128 ) + { + newh = min(phasetable[(s.args[0]+64)&255]+s.heat,255); + newx = s.x+((phasetable[s.args[0]]*s.args[1])>>8); + PutPixel(newx,s.y,newh); + } + s.args[0] = (s.args[0]+s.args[3])&255; + break; + } + case SPARK_Jugglers: + { + newh = min(phasetable[(s.args[0]+64)&255]+s.heat,255); + newy = s.y+((phasetable[s.args[0]]*s.args[1])>>8); + PutPixel(s.x,newy,newh); + s.args[0] = (s.args[0]+s.args[3])&255; + break; + } + case SPARK_Lissajous: + { + newh = lighttable[(s.args[0]+64)&255]; + newx = s.x+((phasetable[s.args[0]]*s.heat)>>8); + newy = s.y+((phasetable[s.args[1]]*s.heat)>>8); + PutPixel(newx,newy,newh); + s.args[0] = (s.args[0]+s.args[2])&255; + s.args[1] = (s.args[1]+s.args[3])&255; + break; + } + case SPARK_LissajousX: + { + newh = lighttable[(s.args[0]+64)&255]; + newx = s.x+((phasetable[s.args[0]]*s.heat)>>8); + PutPixel(newx,s.y,newh); + s.args[0] = (s.args[0]+s.args[2])&255; + break; + } + case SPARK_LissajousY: + { + newh = lighttable[(s.args[0]+64)&255]; + newy = s.y+((phasetable[s.args[1]]*s.heat)>>8); + PutPixel(s.x,newy,newh); + s.args[1] = (s.args[1]+s.args[3])&255; + break; + } + // emitter types + case SPARK_Blaze: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 128) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Ember; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = FastRand()-128; + ns.args[1] = FastRand()-128; + ns.args[2] = s.args[2]; + ns.args[3] = s.args[3]; + sparks.Push(ns); + break; + } + case SPARK_OzHasSpoken: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 128) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_EmberCustom; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = (FastRand()&127)-63; + ns.args[1] = -127; + ns.args[3] = 2; + sparks.Push(ns); + break; + } + case SPARK_Cone: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 64) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Gravity; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = (FastRand()&127)-63; + ns.args[1] = 0; + ns.args[2] = 50; + sparks.Push(ns); + break; + } + case SPARK_BlazeRight: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 128) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Gravity; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = (FastRand()&63)+63; + ns.args[1] = -29; + ns.args[2] = s.args[2]; + sparks.Push(ns); + break; + } + case SPARK_BlazeLeft: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 128) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Gravity; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = (FastRand()&63)-128; + ns.args[1] = -29; + ns.args[2] = s.args[2]; + sparks.Push(ns); + break; + } + case SPARK_Emit: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 64) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_EmberCustom; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = s.args[0]; + ns.args[1] = s.args[1]; + ns.args[2] = s.args[2]; + sparks.Push(ns); + break; + } + case SPARK_Fountain: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 64) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_GravityFade; + ns.heat = s.heat; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = s.args[0]; + ns.args[1] = s.args[1]; + ns.args[2] = s.args[2]; + sparks.Push(ns); + break; + } + case SPARK_Organic: + { + if ( (sparks.Size() >= sparklimit) || (FastRand() >= 128) ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Rising; + ns.x = (s.x+((FastRand()*s.args[2])>>8))&umask; + ns.y = (s.y+((FastRand()*s.args[2])>>8))&vmask; + ns.args[0] = FastRand()-128; + ns.args[1] = -1; + ns.args[2] = 255; + sparks.Push(ns); + break; + } + case SPARK_WanderOrganic: + { + if ( sparks.Size() < sparklimit ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Rising; + ns.x = (s.x+(FastRand()&31))&umask; + ns.y = (s.y+(FastRand()&31))&vmask; + ns.args[0] = FastRand()-128; + ns.args[1] = -1; + ns.args[2] = 255; + sparks.Push(ns); + } + if ( FastRand()&15 == 15 ) s.x = (s.x+(FastRand()&15)-7)&umask; + if ( FastRand()&15 == 15 ) s.y = (s.y+(FastRand()&15)-7)&vmask; + break; + } + case SPARK_RandomCloud: + { + if ( sparks.Size() < sparklimit ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_CloudY; + ns.x = (s.x+(FastRand()&31))&umask; + ns.y = (s.y+(FastRand()&31))&vmask; + ns.args[0] = (FastRand()&31)-15; + ns.args[1] = -1; + ns.args[2] = 0; + sparks.Push(ns); + } + if ( FastRand()&15 == 15 ) s.x = (s.x+(FastRand()&15)-7)&umask; + if ( FastRand()&15 == 15 ) s.y = (s.y+(FastRand()&15)-7)&vmask; + break; + } + case SPARK_Eels: + { + if ( (sparks.Size() < sparklimit) && (FastRand() < 20) ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Eel; + ns.heat = s.heat; + ns.x = (s.x+(FastRand()&31))&umask; + ns.y = (s.y+(FastRand()&31))&vmask; + ns.args[0] = FastRand(); + ns.args[1] = FastRand(); + ns.args[2] = s.args[2]; + sparks.Push(ns); + } + if ( FastRand()&15 == 15 ) s.x = (s.x+(FastRand()&15)-7)&umask; + if ( FastRand()&15 == 15 ) s.y = (s.y+(FastRand()&15)-7)&vmask; + break; + } + case SPARK_Gametes: + { + if ( (sparks.Size() < sparklimit) && (FastRand() < 20) ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Gamete; + ns.heat = s.heat; + ns.x = (s.x+(FastRand()&31))&umask; + ns.y = (s.y+(FastRand()&31))&vmask; + ns.args[0] = FastRand(); + ns.args[2] = s.args[2]; + ns.args[3] = FastRand(); + sparks.Push(ns); + } + if ( FastRand()&15 == 15 ) s.x = (s.x+(FastRand()&15)-7)&umask; + if ( FastRand()&15 == 15 ) s.y = (s.y+(FastRand()&15)-7)&vmask; + break; + } + case SPARK_CustomCloud: + { + if ( sparks.Size() < sparklimit ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_CloudXY; + ns.x = (s.x+(FastRand()&31))&umask; + ns.y = (s.y+(FastRand()&31))&vmask; + ns.args[0] = s.args[0]; + ns.args[1] = s.args[1]; + ns.args[2] = s.args[3]; + sparks.Push(ns); + } + // dunno why the wandering math was done like this here + s.x = (s.x+(FastRand()&7)-(FastRand()&7))&umask; + s.y = (s.y+(FastRand()&7)-(FastRand()&7))&vmask; + break; + } + case SPARK_LocalCloud: + { + if ( sparks.Size() < sparklimit ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_CloudXY; + ns.x = (s.x+((FastRand()*s.args[2])>>8))&umask; + ns.y = (s.y+((FastRand()*s.args[2])>>8))&vmask; + ns.args[0] = s.args[0]; + ns.args[1] = s.args[1]; + ns.args[2] = s.args[3]; + sparks.Push(ns); + } + break; + } + case SPARK_Flocks: + { + if ( sparks.Size() < sparklimit ) + { + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Twirl; + ns.x = (s.x+(FastRand()&31))&umask; + ns.y = (s.y+(FastRand()&31))&vmask; + ns.args[0] = 0; + ns.args[1] = s.args[0]; + ns.args[2] = s.args[1]; + ns.args[3] = s.args[3]; + ns.heat = s.heat; + s.args[0] = (s.args[0]+s.args[2])&255; + sparks.Push(ns); + } + // dunno why the wandering math was done like this here + s.x = (s.x+(FastRand()&7)-(FastRand()&7))&umask; + s.y = (s.y+(FastRand()&7)-(FastRand()&7))&vmask; + break; + } + case SPARK_Wheel: + { + if ( sparks.Size() >= sparklimit ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Twirl; + ns.x = s.x; + ns.y = s.y; + ns.args[0] = 0; + ns.args[1] = s.args[0]; + ns.args[2] = s.args[1]; + ns.args[3] = s.args[3]; + ns.heat = s.heat; + s.args[0] = (s.args[0]+s.args[2])&255; + sparks.Push(ns); + break; + } + case SPARK_Sprinkler: + { + if ( sparks.Size() >= sparklimit ) + break; + FireSpark ns = new("FireSpark"); + ns.type = SSPARK_Sprinkle; + ns.x = s.x; + ns.y = s.y; + ns.heat = s.heat; + ns.args[0] = s.args[0]; + ns.args[1] = s.args[1]; + ns.args[2] = s.args[2]; + ns.args[3] = 2; + ns.heat = s.heat; + s.args[0] = (s.args[0]+s.args[3])&255; + sparks.Push(ns); + break; + } + // stars are their own thing + case SPARK_Stars: + { + PutPixel(s.x,s.y,s.args[1]); + break; + } + // bolt types + case SPARK_LineLightning: + { + if ( !s.heat ) break; + if ( s.args[2] > 0 ) + { + s.args[2]--; + DrawBolt(s.x,s.y,s.args[0],s.args[1],s.heat,s.heat); + } + else if ( FastRand() >= uint(s.args[3]) ) + s.args[2] = 1+FastRand()&5; + break; + } + case SPARK_RampLightning: + { + if ( !s.heat ) break; + if ( s.args[2] > 0 ) + { + s.args[2]--; + DrawBolt(s.x,s.y,s.args[0],s.args[1],s.heat,s.heat>>3); + } + else if ( FastRand() >= uint(s.args[3]) ) + s.args[2] = 1+FastRand()&5; + break; + } + case SPARK_SphereLightning: + { + if ( FastRand() < uint(s.args[3]) ) break; + uint ang = FastRand(); + uint rad = s.args[2]; + uint sdispx = (rad*phasetable[ang])>>8; + uint sdispy = (rad*phasetable[(ang+64)&255])>>8; + DrawBolt(s.x,s.y,sdispx-rad/2,sdispy-rad/2,s.heat,s.heat>>2); + break; + } + // and now the spawned ones + case SSPARK_Ember: + { + if ( (s.heat -= 5) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + MoveSpark(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_EmberCustom: + { + if ( (s.heat -= s.args[3]) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + MoveSpark(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_EmberCustom2: // unused + { + if ( (s.heat -= s.args[2]) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + MoveSpark(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_Gravity: + { + if ( (s.args[2] -= 1) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + MoveSpark(s); + s.args[1] = min(s.args[1]+3,127); + } + else sparks.Delete(i--); + break; + } + case SSPARK_GravityFade: + { + if ( (s.heat -= s.args[3]) > 50 ) + { + PutPixel(s.x,s.y,s.heat); + MoveSpark(s); + if ( phase&1 ) s.args[1] = min(s.args[1]+3,127); + } + else sparks.Delete(i--); + break; + } + case SSPARK_Rising: + { + if ( (s.args[2] -= 3) > 190 ) + { + PutPixel(s.x,s.y,s.args[2]); + MoveSparkTwo(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_CloudY: + { + if ( (s.args[2] += 4) < 250 ) + { + PutPixel(s.x,s.y,s.args[2]); + MoveSparkTwo(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_CloudXY: + { + if ( (s.args[2] += 4) < 250 ) + { + PutPixel(s.x,s.y,s.args[2]); + MoveSpark(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_Eel: + { + if ( (s.args[2] -= 1) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + MoveSpark(s); + } + else sparks.Delete(i--); + break; + } + case SSPARK_Gamete: + { + if ( (s.args[2] -= 1) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + uint sawtooth = 127&(s.args[0]+=7); + if ( sawtooth>63 ) sawtooth = 127-sawtooth; + MoveSparkAngle(s,255&(sawtooth+s.args[3])); + } + else sparks.Delete(i--); + break; + } + case SSPARK_Twirl: + { + if ( (s.args[2] -= 1) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + int tempspeedx = signedtable[(s.args[1]+64)&255]; + int tempspeedy = signedtable[s.args[1]]; + // fixed point fuckery happening here + uint wtf = s.args[0]+(s.args[1]<<8)+(s.args[3]<<4); + s.args[0] = wtf&255; + s.args[1] = (wtf>>8)&255; + MoveSparkXY(s,tempspeedx,tempspeedy); + } + else sparks.Delete(i--); + break; + } + case SSPARK_Sprinkle: + { + if ( (s.args[2] -= 1) > 0 ) + { + PutPixel(s.x,s.y,s.heat); + int tempspeedx = -128+phasetable[(s.args[1]+64)&255]; + int tempspeedy = s.args[1]; + s.args[0] = (s.args[0]+s.args[3])&255; + MoveSparkXY(s,tempspeedx,tempspeedy); + } + else sparks.Delete(i--); + break; + } + } + } + } + + // handle stars + private void PostDrawSparks() + { + uint sparkdest; + if ( !bHasStars ) return; + bool bFoundStar = false; + for ( int i=0; i