// m32 script editor extensions. // to load, enter "include samples/a" (without quotes) in the console // or into a file named m32_autoexec.cfg for automatic loading on startup. // to enable all events, "enableevents all" ////////// USER SETTINGS ////////// // settings for the tweaking of Polymer pr_override*-variables with the keypad keys define MINPARALLAXSCALE -10 // minimum pr_parallaxscale value define MAXPARALLAXSCALE 10 define MINPARALLAXBIAS -10 define MAXPARALLAXBIAS 10 define PSCALESTEPS 1000 // 0..1 is mapped to 0..PSCALESTEPS define PBIASSTEPS 1000 define MINSPECULARPOWER -10 define MAXSPECULARPOWER 1000 define MINSPECULARFACTOR -10 define MAXSPECULARFACTOR 1000 define SPOWERSTEPS 100 define SFACTORSTEPS 100 ////////// END USER SETTINGS ////////// include names.h // flag 1: per-block (top-level, event, or state) variable gamevar i 0 1 gamevar j 0 1 gamevar k 0 1 gamevar p 0 1 gamevar r 0 1 gamevar x 0 0 gamevar y 0 0 gamevar z 0 0 gamevar dx 0 0 gamevar dy 0 0 gamevar dz 0 0 gamevar dang 0 0 gamevar tmp 0 0 gamevar cnt 0 0 gamevar davr 65536 0 gamevar dayx 65536 0 gamevar drawcol 9 0 define TQUOTE 0 definequote TQUOTE >>> write on me! <<< //light define LIGHTQUOTE 1 // x y z r g b mins maxs definequote LIGHTQUOTE light %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d // sec range radius fade ang horiz prio tile // Corruption checker definequote 19 PANIC!!! SECTOR OR WALL LIMIT EXCEEDED!!! definequote 20 SECTOR[%d].WALLPTR=%d out of range: numwalls=%d!!! definequote 21 SECTOR[%d].WALLPTR=%d inconsistent, expected %d!!! definequote 22 SECTOR[%d]: wallptr+wallnum=%d out of range: numwalls=%d!!! definequote 23 WALL[%d].POINT2=%d out of range: sector[%d].wallptr=%d, endwall=%d!!! definequote 24 WALL[%d].NEXTWALL=%d out of range: numwalls=%d!!! definequote 25 WALL[%d].NEXTSECTOR=%d out of range: numsectors=%d!!! define PRSCALE 1000 define MAXSPECULAR 100000 gamearray ar 128 gamearray parm 8 // prints out maphack light definitions based on SE lights in map defstate printlights var flags print "--PRLIGHTS--" for i allsprites, ifactor SECTOREFFECTOR, ifge .lotag 49, ifle .lotag 50 { ife .lotag 50 { set j 128, sub j .shade, shiftl j 1 set k j, mul k 3, div k 4 } else { set j 0, set k 0 } set flags 0 ifand .cstat 2 { ifand .cstat 512 set flags 4 else set flags 2 } // range r g b qsprintf TQUOTE LIGHTQUOTE .sectnum .x .y .z .hitag .xvel .yvel .zvel j k .ang .extra .xoffset .yoffset flags .owner // radius fade horiz minshade maxshade prio tile print TQUOTE } print "--ENDPRLIGHTS--" ends // convenient polymer SE light manipulation with keypad keys // when aiming at light SE (49 or 50): // KP 4,5,6,8: angle/horiz // KP 7,9: range // KP+/-: radius // KP 1,2,3: RGB color (Shift inverts) // // when aiming at wall or sector: // Ctrl-Shift-KP/ enable/disable parallax override // Ctrl-Shift-KP* enable/disable bias override // when overrides are on: // KP 5,8: parallaxscale // KP 4,6: parallaxbias // KP /,*: specularfactor // KP 7,9: specularpower // // Also try Shift and/or Ctrl modifiers for different increments defstate fiddlewithlights var minval maxval ifaimingsprite nullop else { ifeitheralt ifhitkey KEY_gSLASH { xor pr_overrideparallax 1, and pr_overrideparallax 1 ife pr_overrideparallax 1 quote "OVERRIDE POLYMER PARALLAX: ON" else quote "OVERRIDE POLYMER PARALLAX: OFF" } else ifeitheralt ifhitkey KEY_gSTAR { xor pr_overridespecular 1, and pr_overridespecular 1 ife pr_overridespecular 1 quote "OVERRIDE POLYMER SPECULAR: ON" else quote "OVERRIDE POLYMER SPECULAR: OFF" } } // if aiming at sector or wall ifaimingsprite nullop else ifn pr_overrideparallax 0 { set j 0 set k 0 ifhitkey KEY_KP5 set j -1, ifhitkey KEY_KP8 set j 1 ifn j 0 set k 1 ifhitkey KEY_KP4 set j -1, ifhitkey KEY_KP6 set j 1 ife k 0 ifn j 0 set k 2 ifeithershift mul j 10 ifeitherctrl mul j 10 switch k case 0: break; case 1: { set k pr_parallaxscale ftoi k PSCALESTEPS // must convert to scaled integer, maps 0..1 to 0..PARALLAXSTEPS set minval MINPARALLAXSCALE, mul minval PSCALESTEPS set maxval MAXPARALLAXSCALE, mul maxval PSCALESTEPS add k j, al k, clamp k minval maxval, al k itof k PSCALESTEPS // convert back qsprintf TQUOTE "PARALLAX SCALE: %f" k, quote TQUOTE set pr_parallaxscale k break; } case 2: { set k pr_parallaxbias ftoi k PBIASSTEPS set minval MINPARALLAXBIAS, mul minval PBIASSTEPS set maxval MAXPARALLAXBIAS, mul maxval PBIASSTEPS add k j, clamp k minval maxval itof k PBIASSTEPS qsprintf TQUOTE "PARALLAX BIAS: %f" k, quote TQUOTE set pr_parallaxbias k break; } endswitch } // if aiming at sector or wall ifaimingsprite nullop else ifn pr_overridespecular 0 { set j 0 set k 0 ifhitkey KEY_gSLASH set j -1, ifhitkey KEY_gSTAR set j 1 ifn j 0 set k 3 ifhitkey KEY_KP7 set j -1, ifhitkey KEY_KP9 set j 1 ife k 0 ifn j 0 set k 4 ifeithershift mul j 10 ifeitherctrl mul j 10 switch k case 0: break; case 3: { set k pr_specularfactor ftoi k SFACTORSTEPS set minval MINSPECULARFACTOR, mul minval SFACTORSTEPS set maxval MAXSPECULARFACTOR, mul maxval SFACTORSTEPS add k j, clamp k minval maxval itof k SFACTORSTEPS qsprintf TQUOTE "SPECULAR FACTOR: %f" k, quote TQUOTE set pr_specularfactor k break; } case 4: { set k pr_specularpower ftoi k SPOWERSTEPS set minval MINSPECULARPOWER, mul minval SPOWERSTEPS set maxval MAXSPECULARPOWER, mul maxval SPOWERSTEPS add k j, clamp k minval maxval itof k SPOWERSTEPS qsprintf TQUOTE "SPECULAR POWER: %f" k, quote TQUOTE set pr_specularpower k break; } endswitch } // if aiming at a sprite that's not a Polymer light ifaimingsprite set k 1 else set k 0 ife k 1 ife sprite[searchwall].picnum SECTOREFFECTOR ifge sprite[searchwall].lotag 49 ifle sprite[searchwall].lotag 50 set k 0 ife k 1 { seti searchwall // [xyz]vel / owner ifeitheralt { ifhitkey KEY_KP1 { getnumber256 .xvel "XVEL: " 0 getnumber256 .yvel "YVEL: " 0 getnumber256 .zvel "ZVEL: " 0 } else ifhitkey KEY_KP2 { getnumber256 .owner "OWNER: " 0 ifl .owner 0 set .owner -1 } } } // if aiming at an SE with lotag 49 or 50 (Polymer light) ifaimingsprite ife sprite[searchwall].picnum SECTOREFFECTOR ifge sprite[searchwall].lotag 49 ifle sprite[searchwall].lotag 50 { set i searchwall, seti i // set current sprite = targeted sprite ife .lotag 50 { // horiz ifeithershift set j 1 else set j 10 ifhitkey KEY_gUP add .extra j else ifhitkey KEY_gKP5 sub .extra j clamp .extra -500 500 // angle set j 128 ifeitherctrl set j 4 ifeithershift { ifeitherctrl set j 1 else set j 32 } ifhitkey KEY_gLEFT sub .ang j else ifhitkey KEY_gRIGHT add .ang j // radius ifeitherctrl { ifholdkey KEY_gMINUS add .shade 9 else ifholdkey KEY_gPLUS sub .shade 9 clamp .shade -118 117 } } // range ifeithershift set j 10 else ifeitherctrl set j 1000 else set j 100 ifhitkey KEY_KP9 add .hitag j else ifhitkey KEY_KP7 sub .hitag j clamp .hitag 0 16000 // min/max shade ifeithershift set j -1 else set j 1 ifeitherctrl { ifhitkey KEY_gSLASH { set .xoffset 0 set .yoffset 0 quote "Reset X and Y OFFSET (min/max shade) to 0" } } else { set k 0 ifhitkey KEY_gSLASH { add .xoffset j, set k 1 } else ifhitkey KEY_gSTAR { add .yoffset j, set k 1 } ife k 1 { qsprintf TQUOTE "XY OFFSET (min/max shade): %d %d" .xoffset .yoffset quote TQUOTE } } // color/picnum ifeitheralt { ifhitkey KEY_KP1 { getnumber256 .xvel "XVEL (red): " 255 getnumber256 .yvel "YVEL (green): " 255 getnumber256 .zvel "ZVEL (blue): " 255 } else ifhitkey KEY_KP2 { getnumber256 .owner "OWNER (projection picnum): " -MAXTILES ifl .owner 0 set .owner -1 } } else { ifeitherctrl set j 1 else set j 10 ifeithershift inv j set k 0 ifhitkey KEY_KP1 { add .xvel j, set k 1 } ifhitkey KEY_KP2 { add .yvel j, set k 1 } ifhitkey KEY_KP3 { add .zvel j, set k 1 } ife k 1 { clamp .xvel 1 255 clamp .yvel 1 255 clamp .zvel 1 255 qsprintf TQUOTE "XYZ VEL (RGB color): %d %d %d" .xvel .yvel .zvel quote TQUOTE } } } ends // rotate highlighted sprites around selected (closest to mouse) sprite // global parameter: dang defstate rotselspr ifg highlightcnt 0 ifge pointhighlight 16384, ifl pointhighlight 32768 { ife dang 0 return set p pointhighlight, and p 16383 add sprite[p].ang dang for i selsprites, ifn i p { rotatepoint sprite[p].x sprite[p].y .x .y dang (x y) add .ang dang bsetsprite I x y .z } } ends onevent EVENT_PREKEYS2D // state testkeyavail set j 0 ifeitherctrl { ifhitkey KEY_COMMA set j -1 ifhitkey KEY_PERIOD set j 1 } ifn j 0 { mul j 512 set dang j state rotselspr } endevent onevent EVENT_PREKEYS3D // state testkeyavail state fiddlewithlights endevent defstate setas set j dayx mul j ydim mul j 8 div j xdim div j 5 setaspect davr j ends onevent EVENT_ENTER3DMODE state setas endevent defstate cmp_by_lotag // comparator subroutine for sorting set RETURN sprite[SV2].lotag sub RETURN sprite[SV1].lotag ends onevent EVENT_DRAW2DSCREEN ifl cursectnum 0 return // connect LOCATORS in a sector by lines getarraysize ar tmp set j 0 for i spritesofsector cursectnum { ifge j tmp nullop else ifactor LOCATORS { set ar[j] i add j 1 } } set tmp j sort ar tmp cmp_by_lotag sub tmp 1 for i range tmp { set j ar[i] set k i, add k 1, set k ar[k] drawline16b sprite[j].x sprite[j].y sprite[k].x sprite[k].y drawcol } ////////// polymer light 2d projections ////////// var c d h r x2 y2 oldpat array xx 2 array yy 2 set oldpat drawlinepat set drawlinepat 0x11111111 for i spritesofsector cursectnum { ifactor SECTOREFFECTOR { ife .lotag 49 // point light { set d .hitag // light distance mul d d, mul d 2, sqrt d d, div d 2 getclosestcol .xvel .yvel .zvel c // light color inv c set x .x, set x2 .x, set y .y, set y2 .y add x d, add y d, sub x2 d, sub y2 d drawline16b x y x2 y2 c set x .x, set x2 .x, set y .y, set y2 .y add x d, sub y d, sub x2 d, add y2 d drawline16b x y x2 y2 c drawcircle16b .x .y .hitag c } else ife .lotag 50 // spot light { set d .hitag // light distance and d 65535 set r 128, sub r .shade, shiftl r 1 // light cone radius (BUILD angles) getclosestcol .xvel .yvel .zvel c // light color inv c set x .x, set y .y, add x d rotatepoint .x .y x y .ang x y set h .extra // horiz sub h 100 set tmp h, mul tmp tmp, add tmp 40000 sqrt tmp tmp divscale h 200 tmp 15 // h: horizontal distance fraction set dx .x, sub dx x set dy .y, sub dy y set tmp 32768, sub tmp h mulscale dx dx tmp 15 mulscale dy dy tmp 15 set tmp 0, sub tmp r rotatepoint .x .y x y tmp xx[0] yy[0] set tmp 0, add tmp r rotatepoint .x .y x y tmp xx[1] yy[1] add xx[0] dx, add yy[0] dy add xx[1] dx, add yy[1] dy drawline16b .x .y xx[0] yy[0] c drawline16b .x .y xx[1] yy[1] c } } } set drawlinepat oldpat endevent // LOCATORS auto-incrementer onevent EVENT_INSERTSPRITE2D set k I set j -1 for i spritesofsector .sectnum { ifn i k, ifactor LOCATORS, ifg .lotag j set j .lotag } ifg j -1 { add j 1 set .lotag j } endevent //////////////////// SPRITE DUPLICATORS //////////////////// defstate transcnt ifle cnt 0 { inv cnt, add cnt 128 } ends define DUP_ROT_MAGIC 123 // duplicates and rotates selected sprites around // pivot sprite with fields // .extra=123 (magic) // .ang: angle delta // .yrepeat*32: z delta (positive if pal!=0, i.e. going down) // .shade: count (-128 to 0 -> 255 to 128) defstate duprot ifaimingsprite nullop else return ifn sprite[searchwall].extra DUP_ROT_MAGIC return set p searchwall // pivot sprite set cnt sprite[p].shade, state transcnt set sprite[p].extra -1 for i range cnt { for j selsprites, ifn j p { dupsprite j // duplicate sprite j, I becomes index of newly created sprite set dang i, add dang 1, mul dang sprite[p].ang rotatepoint sprite[p].x sprite[p].y .x .y dang (x y) add .ang dang set z i, add z 1, mul z sprite[p].yrepeat, shiftl z 5 ife sprite[p].pal 0, inv z add z .z bsetsprite I x y z } } ends // same as above but with tsprite[], as a kind of preview defstate tduprot ifaimingsprite nullop else return ifn sprite[searchwall].extra DUP_ROT_MAGIC return set p searchwall // pivot sprite set cnt sprite[p].shade, state transcnt for i range cnt { for j selsprites, ifn j p { set k spritesortcnt tdupsprite j set dang i, add dang 1, mul dang sprite[p].ang rotatepoint sprite[p].x sprite[p].y tsprite[k].x tsprite[k].y dang (x y) add tsprite[k].ang dang set z i, add z 1, mul z sprite[p].yrepeat, shiftl z 5 ife sprite[p].pal 0 inv z add z tsprite[k].z set tsprite[k].x x set tsprite[k].y y set tsprite[k].z z or tsprite[k].cstat 514 } } ends define DUP_LIN_MAGIC 234 define DUP_LIN_MAGIC2 345 // duplicates and translates selected sprites in the direction between two // reference sprites with fields // .extra=234 (1st sprite), =345 (2nd, aimed at sprite) // .shade: count (-128 to 0 -> 255 to 128) defstate duplin ifaimingsprite nullop else return ifn sprite[searchwall].extra DUP_LIN_MAGIC2 return set r searchwall // 2nd reference point set cnt sprite[r].shade, state transcnt set p -1 // 1st reference point for i selsprites, ifn i r { ife .extra DUP_LIN_MAGIC { set p i, break } } ifl p 0 return set sprite[p].extra -1 set sprite[r].extra -1 set dx sprite[r].x, sub dx sprite[p].x set dy sprite[r].y, sub dy sprite[p].y set dz sprite[r].z, sub dz sprite[p].z for i range cnt { for j selsprites, ifn j r { dupsprite j set x i, add x 1, mul x dx, add x .x set y i, add y 1, mul y dy, add y .y set z i, add z 1, mul z dz, add z .z bsetsprite I x y z } } ends defstate tduplin ifaimingsprite nullop else return ifn sprite[searchwall].extra DUP_LIN_MAGIC2 return set r searchwall // 2nd reference point set cnt sprite[r].shade, state transcnt set p -1 // 1st reference point for i selsprites, ifn i r { ife .extra DUP_LIN_MAGIC { set p i, break } } ifl p 0 return set dx sprite[r].x, sub dx sprite[p].x set dy sprite[r].y, sub dy sprite[p].y set dz sprite[r].z, sub dz sprite[p].z for i range cnt { for j selsprites, ifn j r { set k spritesortcnt tdupsprite j set tmp i, add tmp 1, mul tmp dx add tsprite[k].x tmp set tmp i, add tmp 1, mul tmp dy add tsprite[k].y tmp set tmp i, add tmp 1, mul tmp dz add tsprite[k].z tmp or tsprite[k].cstat 514 // bsetsprite I x y z } } ends onevent EVENT_ANALYZESPRITES state tduprot state tduplin endevent onevent EVENT_KEYS3D var l m // door sound tester ifaimingwall ifholdkey KEY_SPACE { set k wall[searchwall].nextsector ifl k 0 set k searchsector ife sector[k].lotag 0 return for i spritesofsector k { ifactor MUSICANDSFX ifge .lotag 0 ifl .lotag MAXSOUNDS { getsoundflags .lotag m ifand m 1 nullop else soundonce .lotag } } } // swinging doors tester -- hit space on a door wall ifaimingwall ifhitkey KEY_SPACE // SE11 ST23 up:ccw { set k wall[searchwall].nextsector ifl k 0 return ifn sector[k].lotag 23 return set tmp 0 for i loopofwall searchwall { ifl wall[i].nextsector 0 set tmp 1 else ifn wall[i].nextsector k set tmp 1 } // a weaker condition // for i loopofwall wall[searchwall].nextwall // { // ifl wall[i].nextsector 0 set tmp 1 else // ifn wall[i].nextsector searchsector set tmp 1 // } ifn tmp 0 { quote "door sector not an island sector!" return } set l -1 for i spritesofsector k { ifactor SECTOREFFECTOR ife sprite[i].lotag 11 { set l i ifn sprite[i].ang 512 ifn sprite[i].ang 1024 ifn sprite[i].ang 1536 set l -1 } } ifl l 0 { quote "door sector has no SE sprite!" return } for tmp wallsofsector k { rotatepoint (sprite[l].x sprite[l].y) (wall[tmp].x wall[tmp].y) sprite[l].ang (i j) dragpoint tmp i j } for tmp spritesofsector k { ifn tmp l { rotatepoint (sprite[l].x sprite[l].y) (sprite[tmp].x sprite[tmp].y) sprite[l].ang (i j) bsetsprite tmp i j sprite[tmp].z } } inv sprite[l].ang } // teleporter -- works on SE7 and SE17 (elevator) ifaimingsprite ifhitkey KEY_SPACE { ife sprite[searchwall].picnum SECTOREFFECTOR { set tmp 0 ife sprite[searchwall].lotag 7 set tmp 1 ife sprite[searchwall].lotag 17 set tmp 1 ife tmp 0 return for i allsprites { ifn i searchwall, ifactor SECTOREFFECTOR, ife sprite[i].lotag sprite[searchwall].lotag ife sprite[i].hitag sprite[searchwall].hitag { add posx sprite[i].x, sub posx sprite[searchwall].x add posy sprite[i].y, sub posy sprite[searchwall].y add posz sprite[i].z, sub posz sprite[searchwall].z updatecursectnum return } } } else ife sprite[searchwall].extra DUP_ROT_MAGIC { state duprot } else ife sprite[searchwall].extra DUP_LIN_MAGIC2 { state duplin } } ifholdkey KEY_0 // ife 0 1 { ifeithershift sub davr 512 else add davr 512 ifl davr 32768 set davr 32768 ifg davr 256000 set davr 256000 setaspect davr yxaspect qsprintf TQUOTE "ASPECT: VR=%d, YX=%d" davr yxaspect quote TQUOTE } endevent defstate replacestuff for i spritesofsector searchsector // ife sprite[i].picnum AMMO set sprite[i].picnum BATTERYAMMO ifactor parm[0] cactor parm[1] ends defstate convlights // convert (0,0,0) lights to (255,255,255)-ones for i allsprites ifactor 1 ifge .lotag 49 ifle .lotag 50 ife .xvel 0 ife .yvel 0 ife .zvel 0 { set .xvel 255 set .yvel 255 set .zvel 255 } ends defstate resetallws // reset all sprites and walls to default repeat/panning for i allsprites { set .xrepeat 64 set .yrepeat 64 } for i allwalls { set wall[i].cstat 0 set wall[i].xpanning 0 set wall[i].ypanning 0 set wall[i].yrepeat 8 fixrepeats i } ends defstate js // jump to current sprite set posx .x set posy .y set posz .z updatecursectnum ends defstate jumptosec // (tmp) ifge tmp 0 ifl tmp numsectors nullop else return set j sector[tmp].wallptr set posx wall[j].x set posy wall[j].y updatecursectnum ends // Map corruption checker defstate corruptchk var ewall var endwall ifle numsectors MAXSECTORS ifle numwalls MAXWALLS nullop else { quote 19 printmessage16 19 return } set ewall 0 // expected wall index for i allsectors { set k 1 ifge sector[i].wallptr 0 ifl sector[i].wallptr numwalls nullop else { qsprintf TQUOTE 20 i sector[i].wallptr numwalls quote TQUOTE printmessage16 TQUOTE set k 0 } ifn ewall sector[i].wallptr { qsprintf TQUOTE 21 i sector[i].wallptr ewall quote TQUOTE printmessage16 TQUOTE set ewall sector[i].wallptr } add ewall sector[i].wallnum set endwall sector[i].wallptr add endwall sector[i].wallnum ifg endwall numwalls { qsprintf TQUOTE 22 i endwall numwalls quote TQUOTE printmessage16 TQUOTE set k 0 } ifn k 0 { for j wallsofsector i { ifge wall[j].point2 sector[i].wallptr ifl wall[i].point2 endwall nullop else { qsprintf TQUOTE 23 j wall[j].point2 i sector[i].wallptr endwall quote TQUOTE printmessage16 TQUOTE } ifge wall[i].nextwall numwalls { qsprintf TQUOTE 24 j wall[j].nextwall numwalls quote TQUOTE printmessage16 TQUOTE } ifge wall[i].nextsector numsectors { qsprintf TQUOTE 25 j wall[j].nextsector numsectors quote TQUOTE printmessage16 TQUOTE } } } } ends