code:
 *** Mapster32 Help: Table of contents ***
1. 2D mode mouse reference
2. 2D mode keyboard reference
3. 3D mode mouse reference
4. 3D mode keyboard reference
5. 3D mode tile selector refrence
6. Sector effector reference
7. Sector tag reference
8. Long SE reference
9. Colors
^P
The purpose of mouse in 2D mode is pointing, selecting and
moving objects in a map.

^3Every time mouse is pointing at one of these:
1. Nothing
2. Sector
3. Sector and wall
4. Sector and sprite
5. Wall (wall without sector - map is corrupt)
6. Sprite (sprite without sector - map is corrupt)

Some commands work differently depending on the currently selected object.
Press ALT to work with a wall or sprite instead of any adjacent sectors.

^14RSHIFT^O        Select vertex/sprites
^14RALT^O          Select sectors
^14WHEEL^O         Zoom
^14WHEEL+ALT^O     Move camera and zoom
^14LEFT BUTTON^O   Drag sectors/vertex/sprites
^14RIGHT BUTTON^O  Move camera
^14RIGHT MIDDLE^O  Move camera
^P
LSHIFT   Show coordinates
F1       Show help
F9       Show the Sector Tags help
M        Set extra of sector
M+ALT    Set extra of wall/sprite
/        Reset panning, size and flags to defaults
/+SHIFT  Make square - set xrepeat to yrepeat

KP_4     Scaling sprite horizontally
KP_6     Scaling sprite horizontally
KP_2     Scaling sprite vertically
KP_8     Scaling sprite vertically
+KP_5    Speed up

R        Cycle sprite alignment
' S      Set sprite size
' F      Function menu
F7+ALT   Search sector lotag
F8+ALT   Search wall/sprite lotag
[        Search backward
]        Search forward
G        Cycle grid size
G+SHIFT  Cycle grid size backward
' L      Set sprite/wall coordinates
' 3      Cycle modes of showing object's name
' 7      Swap lotag and hitag of wall/sprite
' J      Goto X,Y

X        Flip selected sectors in x
Y        Flip selected sectors in y
X+ALT    Mirror selected sectors in x
Y+ALT    Mirror selected sectors in y

F12        Screenshot
F12+SHIFT  Inverted screenshot

B        Toggle blocking
B+SHIFT  Toggle one-sided blocking for a wall
F+ALT    Set the first wall of a sector
O        Ornament sprite flat onto wall

,   Rotate sprite/selected sectors
.   Rotate sprite/selected sectors
<   Slowly rotate sprite/selected sectors
>   Slowly rotate sprite/selected sectors

SCROLL LOCK  Set starting position
F5  Show item count
F6  Show actor count
F6  Show Sector Effector help when pointed at sprite
F7  Edit sector data
F8  Edit wall/sprite data

T             Set sector lotag
T+ALT         Set wall/sprite lotag
T+CTRL        Toggle show tags

H             Set sector hitag
H+ALT         Set wall/sprite hitag
H+CTRL        Toggle hitscan sensitivity

P             Set sector palette
E             Set sprite status list
TAB           Show sector data
TAB+SHIFT     Show wall/sprite data
TAB+CTRL      Show wall/sprite data

LCTRL+RSHIFT  Select all walls of the current sector
              (point at a wall and, holding CTRL, press SHIFT)

A          Zoom in
Z          Zoom out
L          Toggle grid lock
J          Join sectors
S          Insert sprite (see samples/tiles.cfg for customization)
S+ALT      Make inner sector
C          Duplicate sectors/sprites
C          Start circle attached to a wall
KP_+       Increase amount of walls in circle
KP_-       Decrease amount of walls in circle
SPACE      Start/end drawing of sector, end drawing of circle
LENTER               Check all pointers for the current sector
LSHIFT+LCTRL+LENTER  Check ALL pointers (manual attempt to recover map)
BACKSPACE  Remove the last wall during drawing sector
DEL        Delete sprite
DEL+CTRL   Delete sector
INS        Duplicate sectors/sprites
INS        Start circle attached to a wall
INS        Add vertex to wall
RENTER     Switch to 3D mode
ESC        Menu

' A        Toggle autosave (every 3 minutes)
' N        Toggle clipping
S+CTRL     Save map
L+CTRL     Load map
^P
^3The mouse pointer always points at one of these objects:
1. wall
2. ceiling of sector
3. floor of sector
4. sprite
5. masked wall (non-transparent or semi-transparent wall between sectors)

It's important to understand this concept.
Some commands work differently depending on the "current object",
the object the mouse points at.
Some commands only manipulate the "current object", but other commands
manipulate the sprites and sectors which are "selected" in 2D mode.
Other commands work globally.

^3Mouse buttons:
^14LEFT^O         Lock the current object. The current object won't
                  change as long as the button is pressed.
^14LEFT+MIDDLE^O  Toggle mouselook
^14WHEEL^O        Change shade/visibility
^14LEFT+WHEEL^O   Change tile
^14RIGHT+WHEEL^O  Move object up/down

Additionally, there is UnrealEd-style mouse navigation in 3D mode
(toggle it with ^14F5^O) with the following bindings:
^14RIGHT^O        mouselook
^14LEFT^O         x: turning, y: move forward/back
^14LEFT+RIGHT^O   x: strafe left/right, y: move up/down
^14MIDDLE^O       y: move in viewing direction
  The console variable 'pk_uedaccel' changes the speed
  of navigation exponentially (valid values are 0-5).

^14LEFT+ALT^O     Move object up/down
^14LEFT+SHIFT^O   Pan ceiling/floor/wall
^14LEFT+SHIFT^O   Move sprite in horizontal plane
^14LEFT+CTRL^O    Scale wall texture or size of sprite
^14LEFT+CTRL^O    Change slope of sector
^P
UP          Move forward
DOWN        Move backward
LEFT+RCTRL  Move left
RIGHT+RCTRL Move right
A           Move up
Z           Move down
F4+ALT      Toggle showing the first wall
+LSHIFT     Speed up movements

LEFT    Turn left
RIGHT   Turn right
A+CTRL  Look down
Z+CTRL  Look up

' V   Set sector visibility
; V   Set sector visibility on all selected sectors
V     Choose tile
3     Toggle "sector over sector".
F3    Toggle mouselook
' BACKSPACE  Clear all flags for wall/sprite
' P   Paste palette to all selected sectors
; P   Paste palette to all selected sectors & sprites
DEL   Delete sprite
F6    Toggle automatic Sector Effector help
F7    Toggle automatic sector tag help

,     Rotate sprite
.     Rotate sprite
<     Slowly rotate sprite
>     Slowly rotate sprite
.     Search & fix panning of the wall to the right

' L   Change the coordinates of the current object
CAPS LOCK  Cycle zmode
' Z   Cycle zmode
' M   Set the extra of the current object
1     Toggle one-sided flag of sprite/wall
2     Toggle bottom wall swapping
O     Set top or bottom orientation of wall
O     Ornament sprite flat onto wall
M     Toggle masked wall
H     Toggle hitscan sensitivity
H+SHIFT  Toggle one side hitscan sensitivity for the wall
' H   Set hitag of the current object

KP_MINUS            Darkens shade of individual sector/wall/sprite or selected sectors
KP_MINUS+ALT        Decreases visibility of sector or selected sectors
KP_MINUS+ALT+SHIFT  Slowly decreases visibility of sector or selected sectors
KP_MINUS+ALT+CTRL   Decreases global visibility
KP_PLUS             Lightens shade individual sector/wall/sprite or selected sectors
KP_PLUS+ALT         Increases visibility of sector or selected sectors
KP_PLUS+ALT+SHIFT   Slowly increases visibility of sector or selected sectors
KP_PLUS+ALT+CTRL    Increases global visibility
^3Note: ALT, CTRL, SHIFT are modifiers so they work with mouse too.

+/-    Cycle tile
E      Toggle sector texture expansion
R      Toggle sector texture relativity alignment
R      Cycle sprite aligment between: wall aligned, floor aligned, view aligned
'R     Toggle framerate
F      Flip the current object
F+ALT  Set the first wall of sector

PAGE UP      Move selected sprites or sectors up
PAGE DN      Move selected sprites or sectors down
PAGE UP+CTRL Move selected sprites to ceiling
PAGE DN+CTRL Move selected sprites to floor
+CTRL        Speed up movement
+END         Slow down movement
+HOME        Slow down movement even more
^3Note: CTRL, HOME, END are modifiers, so they work with the mouse too.

' D      Cycle skill level
' X      Toggle sprite shade preview
' W      Toggle sprite display
' Y      Toggle purple background
' C      Copy shade from the clipboard to all objects in the map which are the same
          tile as the tile of the object in the clipboard. It works separately for
          sectors/walls/sprites depending on the current object.
' T      Set lotag
' H      Set hitag
' S      Set shade
F2       Toggle clipboard preview
TAB      Copy to the clipboard
F1       Toggle help
G        Set picnum
B        Toggle blocking
B+SHIFT  Toggle one side blocking for the wall
T        Cycles translucence for sprites/masked walls

LENTER+CTRL+SHIFT  Autoshade wall
' LENTER           Paste picnum only
LENTER+SHIFT       Paste shade and palette onto the current object
LENTER+CTRL        Paste picnum, shading, and palette onto the current object
LENTER             Paste all properties onto the current object

' A  Toggle autosave. The interval is configurable in the .cfg.
     (by default: every 3 minutes)

' N        Toggle clipping for the camera
N+CTRL     Toggle clipping for sprites

S+CTRL     Save map
L+CTRL     Load map

ESC        Quit
F11        Brightness
F12        Screenshot
F12+SHIFT  Inverted screenshot
F9         Reload and activate maphacks
F10        Disable maphacks

C          Toggle center sprite (cstat 128)
ALT+C      Replace all tiles in the map with the clipboard

[          Increases slope quickly
[+RSHIFT   Increases slope with medium speed
[+LSHIFT   Increases slope slowly
[+ALT      Align slope to the floor of an adjoining sector
]          Decreases slope quickly
]+RSHIFT   Decreases slope with medium speed
]+LSHIFT   Decreases slope slowly
]+ALT      Align slope to the ceiling of an adjoining sector

KP_4       Pan floor/ceiling horizontally
KP_6       Pan floor/ceiling horizontally
KP_2       Pan floor/ceiling vertically
KP_8       Pan floor/ceiling vertically
KP_4       Scale wall/sprite horizontally
KP_6       Scale wall/sprite horizontally
KP_2       Scale wall/sprite vertically
KP_8       Scale wall/sprite vertically
+SHIFT     Force panning (for walls)
+KP_5      Increase speed

/          Reset panning, size and flags to defaults
/+SHIFT    Make square - set xrepeat to yrepeat

P          Enable/disable parallax
P+CTRL     Change parallax type (only in 8-bit classic renderer)
P+ALT      Change palette of sector/wall/sprite
D+ALT      Adjust clipping distance of the sprite
T          Translucence for sprites/masked walls
S          Insert sprite
KP_ENTER   Switch to 2D mode
^P
After pressing V in 3D mode, the editor enters tile browsing.

^3Keys:
KP_/  Zoom in
KP_*  Zoom out
UP/DOWN/LEFT/RIGHT/PAGE UP/PAGE DOWN movements
G  Go to specified tile
U  Go to start of user defined art (3584)
A  Go to start of Atomic edition's art (4096)
E  Go to start of extended art (6144, 9216)

V      Select from all tiles
T      Select from pre-defined tileset (tiles.cfg)
Z      Tile zoom
ESC    Cancel
ENTER  Accept

^3Mouse:
LEFT        select
CTRL+WHEEL  zoom
WHEEL       scroll
RIGHT       smooth scrolling
^P
 0  : Rotating Sector
 1  : Pivot Sprite for SE 0
 2  : Earthquake
 3  : Random Lights After Shot Out
 4  : Random Lights
 6  : Subway
 7  : Teleporter
 8  : Up Open Door Lights
 9  : Down Open Door Lights
 10 : Door Auto Close (Hitag = Delay)
 11 : Rotate Sector Door
 12 : Light Switch
 13 : C-9 Explosive
 14 : Subway Car
 15 : Slide Door (ST 25)
 16 : Rotate Reactor Sector
 17 : Elevator Transport (ST 15)
 18 : Incremental Sector Rise/Fall
 19 : Explosion Lowers Ceiling
 20 : Stretch (ST 27)
 21 : Drop Floor (ST 28)
 22 : Teeth Door Prong (ST 29)
 23 : One-Way Teleporter Destination
 24 : Conveyor Belt or Water Current
 25 : Engine Piston
 27 : Demo Camera
 28 : Lightning
 29 : Float (for Waves)
 30 : Two-Way Train (ST 31)
 31 : Floor Rise/Fall
 32 : Ceiling Rise/Fall
 33 : Earthquake Debris
 36 : Projectile Shooter
^P
 1  : Above Water (SE 7)
 2  : Underwater (SE 7)
 9  : Sliding Star Trek Doors
 15 : Elevator Transport (SE 17)
 16 : Elevator Platform Down
 17 : Elevator Platform Up
 18 : Elevator Down
 19 : Elevator Up
 20 : Ceiling Door
 21 : Floor Door
 22 : Splitting Door
 23 : Swinging Door
 25 : Sliding Door (SE 15)
 26 : Splitting Star Trek Door
 27 : Stretch (SE 20)
 28 : Drop Floor (SE 21)
 29 : Teeth Door Prong (SE 22)
 30 : Rotate and Rise Bridge
 31 : Two-Way Train (SE 30)
 10+++ : One-Time Sound
 32767 : Secret Room
 65534 : End Of Level with Message (sector hitag: sound #)
 65535 : End Of Level
^P
^3SE 0/1: ROTATED SECTOR
   SE1: pivot
      Ang: up--clockwise, down--counterclockwise
   SE0: a sector to rotate
      Hi = SE1 Hi

^3SE 2: EARTHQUAKE
   In quake sector, modeled as after the quake, insert additionally:
      MASTERSWITCH
         Lo=X
   In other sector:
      TOUCHPLATE
         Lo=X
   Anywhere:
      SE33: scraps
         Hi=X

^3SE 3: RANDOM LIGHTS AFTER SHOT OUT
   Light is wall:
      2-way, blockable?
      Lo=X
   Light is ceiling:
      sector Hi=X
   SE 3 in affected sector:
      Hi=X
   Shades/pals:
      sectors/walls: when off
      SE: when on

^3SE 4: RANDOM LIGHTS
   Hi: random blink num. ^0(research!)
   Shades/pals:
      sectors/walls: when off
      SE: when on

^3SE 5: ?

^3SE 6/14: SUBWAY
   subway sectors:
      Hi=unique per train
   SE 6: SUBWAY FRONT CAR
      Ang: direction of first movement
      GPSPEED:
          Lo: speed (default: 256)
   SE 14: SUBWAY PULLED CARS
   Locators:
      starting with Lo=0, ascending
      Hi=1: train stops here

^3SE 7: TRANSPORT
   Hi=X link

^3SE 8: UP OPEN DOOR LIGHTS (with ST 20)
   SE 8 also in door sector
   Hi=X links with other SE8 sprites
   Shades:
      sectors/walls: when closed
      SE: when open
   Walls:
      Hi=1 means exclude this wall from changing shade

^3SE 9: DOWN OPEN DOOR LIGHTS (with ST 21)
   analogous SE 8

^3SE 10: ?

^3SE 11: ROTATE SECTOR DOOR
   Ang: up--clockwise, down--counterclockwise
   Hi: link doors to be opened simulataneously
   ST=23

^3SE 12: LIGHT SWITCH  (preview with 'X)
   Hi=X
   Shades:
      sectors/walls: when off
      SE: when on
   [switch]:
      Lo=X

^3SEENINE: C-9 BARREL
      Hi=X
      Lo=delay ^0(>0? game ticks?)
   In all sectors with SEENINEs:
      MASTERSWITCH Lo=X
   [switch]:
      Lo=X

^3SE 13: C-9 EXPLOSIVE/BLASTABLE WALL
   CRACKs/SEENINEs: Hi=X
   SE 13: Hi=X
   other SEENINEs:
      Hi=X
      Lo=delay

^3SE 15: SLIDING DOOR (ST=25)
   Ang: opposite of direction of first movement
   GPSPEED:
      2*Lo: how far (BUILD units)

^3SE 17: ELEVATOR TRANSPORT
   Shade: darker on SE of starting sector
   Sectors:
      ST=15
      Top floor sector Hi=1

^3SE 18: INCREMENTAL SECTOR RISE/FALL
   Hi: units moved per activation (min: 1024?)
   Ang:
      up--floor affected
      down--ceiling affected
   Pal:
      0: start at floor/ceiling height
      not 0: start at SE height
   [switch] & ACTIVATOR ^0(in same sector as SE?):
      Lo=X

^3SE 19: SHOT TOUCHPLATE CIELING DOWN

^3SE 20: BRIDGE/STRETCH SECTOR (ST 27)
   Ang: direction
   ACTIVATOR
      Hi = SE Hi = [switch] Lo
   GPSPEED
      Lo: how far (BUILD units)

^3SE 21: DROP FLOOR (ST 28)
   Ang:
      up: drop ceiling
      down: drop floor
   z: end z ^0(())
   Sector:
      z: start z ^0(())
   GPSPEED
      Lo: rate ^0(units?)
   ACTIVATOR
      Lo = [switch] Lo

^3SE 24: CONVEYOR BELT
   Ang: direction
   GPSPEED:
      Lo=speed

^3SE 25: ENGINE PISTON (CRUSHER)
   z: starting z
   Sector:
      piston travels between ceiling z and floor z

^3SE 27: CAMERA FOR PLAYBACK
   Hi: radius (BUILD units?)

^3SE 28: LIGHTNING
   Hi = tile #4890 Hi

^3SE 29: WAVES
   Hi: start height (phase)
   GPSPEED Lo: amplitude (default: 256)

^0 Based on
^0  * MAP EDITING FAQ v1.3 BY JONAH BISHOP
^0  * The Duke Nukem 3D Informational Suite by Ryan Lennox
^0  * code research
^P
Foreground colors:
^0,15 0 ^1,0 1 ^2 2 ^3 3 ^4 4 ^5 5 ^6 6 ^7 7
^8 8 ^9 9 ^10 10^11 11^12 12^13 13^14 14^15 15

Background colors:
^15,0 0 ^0,1 1 ^0,2 2 ^0,3 3 ^0,4 4 ^0,5 5 ^0,6 6 ^0,7 7
^0,8 8 ^0,9 9 ^0,10 10^0,11 11^0,12 12^0,13 13^0,14 14^0,15 15


code:
//-------------------------------------------------------------------------
/*
Copyright (C) 2010 EDuke32 developers and contributors

This file is part of EDuke32.

EDuke32 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 2
as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
//-------------------------------------------------------------------------

#define SECTOREFFECTOR 1
#define ACTIVATOR 2
#define TOUCHPLATE 3
#define ACTIVATORLOCKED 4
#define MUSICANDSFX 5
#define LOCATORS 6
#define CYCLER 7
#define MASTERSWITCH 8
#define RESPAWN 9
#define GPSPEED 10
#define FOF 13
#define ARROW 20
#define FIRSTGUNSPRITE 21
#define CHAINGUNSPRITE 22
#define RPGSPRITE 23
#define FREEZESPRITE 24
#define SHRINKERSPRITE 25
#define HEAVYHBOMB 26
#define TRIPBOMBSPRITE 27
#define SHOTGUNSPRITE 28
#define DEVISTATORSPRITE 29
#define HEALTHBOX 30
#define AMMOBOX 31
#define GROWSPRITEICON 32
#define INVENTORYBOX 33
#define FREEZEAMMO 37
#define AMMO 40
#define BATTERYAMMO 41
#define DEVISTATORAMMO 42
#define RPGAMMO 44
#define GROWAMMO 45
#define CRYSTALAMMO 46
#define HBOMBAMMO 47
#define AMMOLOTS 48
#define SHOTGUNAMMO 49
#define COLA 51
#define SIXPAK 52
#define FIRSTAID 53
#define SHIELD 54
#define STEROIDS 55
#define AIRTANK 56
#define JETPACK 57
#define HEATSENSOR 59
#define ACCESSCARD 60
#define BOOTS 61
#define MIRRORBROKE 70
#define CLOUDYOCEAN 78
#define CLOUDYSKIES 79
#define MOONSKY1 80
#define MOONSKY2 81
#define MOONSKY3 82
#define MOONSKY4 83
#define BIGORBIT1 84
#define BIGORBIT2 85
#define BIGORBIT3 86
#define BIGORBIT4 87
#define BIGORBIT5 88
#define LA 89
#define REDSKY1 98
#define REDSKY2 99
#define ATOMICHEALTH 100
#define TECHLIGHT2 120
#define TECHLIGHTBUST2 121
#define TECHLIGHT4 122
#define TECHLIGHTBUST4 123
#define WALLLIGHT4 124
#define WALLLIGHTBUST4 125
#define ACCESSSWITCH 130
#define SLOTDOOR 132
#define LIGHTSWITCH 134
#define SPACEDOORSWITCH 136
#define SPACELIGHTSWITCH 138
#define FRANKENSTINESWITCH 140
#define NUKEBUTTON 142
#define MULTISWITCH 146
#define DOORTILE5 150
#define DOORTILE6 151
#define DOORTILE1 152
#define DOORTILE2 153
#define DOORTILE3 154
#define DOORTILE4 155
#define DOORTILE7 156
#define DOORTILE8 157
#define DOORTILE9 158
#define DOORTILE10 159
#define DOORSHOCK 160
#define DIPSWITCH 162
#define DIPSWITCH2 164
#define TECHSWITCH 166
#define DIPSWITCH3 168
#define ACCESSSWITCH2 170
#define REFLECTWATERTILE 180
#define FLOORSLIME 200
#define BIGFORCE 230
#define EPISODE 247
#define MASKWALL9 255
#define W_LIGHT 260
#define SCREENBREAK1 263
#define SCREENBREAK2 264
#define SCREENBREAK3 265
#define SCREENBREAK4 266
#define SCREENBREAK5 267
#define SCREENBREAK6 268
#define SCREENBREAK7 269
#define SCREENBREAK8 270
#define SCREENBREAK9 271
#define SCREENBREAK10 272
#define SCREENBREAK11 273
#define SCREENBREAK12 274
#define SCREENBREAK13 275
#define MASKWALL1 285
#define W_TECHWALL1 293
#define W_TECHWALL2 297
#define W_TECHWALL15 299
#define W_TECHWALL3 301
#define W_TECHWALL4 305
#define W_TECHWALL10 306
#define W_TECHWALL16 307
#define WATERTILE2 336
#define BPANNEL1 341
#define PANNEL1 342
#define PANNEL2 343
#define WATERTILE 344
#define STATIC 351
#define W_SCREENBREAK 357
#define W_HITTECHWALL3 360
#define W_HITTECHWALL4 361
#define W_HITTECHWALL2 362
#define W_HITTECHWALL1 363
#define MASKWALL10 387
#define MASKWALL11 391
#define DOORTILE22 395
#define FANSPRITE 407
#define FANSPRITEBROKE 411
#define FANSHADOW 412
#define FANSHADOWBROKE 416
#define DOORTILE18 447
#define DOORTILE19 448
#define DOORTILE20 449
#define SPACESHUTTLE 487
#define SATELLITE 489
#define VIEWSCREEN2 499
#define VIEWSCREENBROKE 501
#define VIEWSCREEN 502
#define GLASS 503
#define GLASS2 504
#define STAINGLASS1 510
#define MASKWALL5 514
#define SATELITE 516
#define FUELPOD 517
#define SLIMEPIPE 538
#define CRACK1 546
#define CRACK2 547
#define CRACK3 548
#define CRACK4 549
#define FOOTPRINTS 550
#define DOMELITE 551
#define CAMERAPOLE 554
#define CHAIR1 556
#define CHAIR2 557
#define BROKENCHAIR 559
#define MIRROR 560
#define WATERFOUNTAIN 563
#define WATERFOUNTAINBROKE 567
#define FEMMAG1 568
#define TOILET 569
#define STALL 571
#define STALLBROKE 573
#define FEMMAG2 577
#define REACTOR2 578
#define REACTOR2BURNT 579
#define REACTOR2SPARK 580
#define GRATE1 595
#define BGRATE1 596
#define SOLARPANNEL 602
#define NAKED1 603
#define ANTENNA 607
#define MASKWALL12 609
#define TOILETBROKE 615
#define PIPE2 616
#define PIPE1B 617
#define PIPE3 618
#define PIPE1 619
#define CAMERA1 621
#define BRICK 626
#define SPLINTERWOOD 630
#define PIPE2B 633
#define BOLT1 634
#define W_NUMBERS 640
#define WATERDRIP 660
#define WATERBUBBLE 661
#define WATERBUBBLEMAKER 662
#define W_FORCEFIELD 663
#define VACUUM 669
#define FOOTPRINTS2 672
#define FOOTPRINTS3 673
#define FOOTPRINTS4 674
#define EGG 675
#define SCALE 678
#define CHAIR3 680
#define CAMERALIGHT 685
#define MOVIECAMERA 686
#define IVUNIT 689
#define POT1 694
#define POT2 695
#define POT3 697
#define PIPE3B 700
#define WALLLIGHT3 701
#define WALLLIGHTBUST3 702
#define WALLLIGHT1 703
#define WALLLIGHTBUST1 704
#define WALLLIGHT2 705
#define WALLLIGHTBUST2 706
#define LIGHTSWITCH2 712
#define WAITTOBESEATED 716
#define DOORTILE14 717
#define STATUE 753
#define MIKE 762
#define VASE 765
#define SUSHIPLATE1 768
#define SUSHIPLATE2 769
#define SUSHIPLATE3 774
#define SUSHIPLATE4 779
#define DOORTILE16 781
#define SUSHIPLATE5 792
#define OJ 806
#define MASKWALL13 830
#define HURTRAIL 859
#define POWERSWITCH1 860
#define LOCKSWITCH1 862
#define POWERSWITCH2 864
#define ATM 867
#define STATUEFLASH 869
#define ATMBROKE 888
#define BIGHOLE2 893
#define STRIPEBALL 901
#define QUEBALL 902
#define POCKET 903
#define WOODENHORSE 904
#define TREE1 908
#define TREE2 910
#define CACTUS 911
#define MASKWALL2 913
#define MASKWALL3 914
#define MASKWALL4 915
#define FIREEXT 916
#define TOILETWATER 921
#define NEON1 925
#define NEON2 926
#define CACTUSBROKE 939
#define BOUNCEMINE 940
#define BROKEFIREHYDRENT 950
#define BOX 951
#define BULLETHOLE 952
#define BOTTLE1 954
#define BOTTLE2 955
#define BOTTLE3 956
#define BOTTLE4 957
#define FEMPIC5 963
#define FEMPIC6 964
#define FEMPIC7 965
#define HYDROPLANT 969
#define OCEANSPRITE1 971
#define OCEANSPRITE2 972
#define OCEANSPRITE3 973
#define OCEANSPRITE4 974
#define OCEANSPRITE5 975
#define GENERICPOLE 977
#define CONE 978
#define HANGLIGHT 979
#define HYDRENT 981
#define MASKWALL14 988
#define TIRE 990
#define PIPE5 994
#define PIPE6 995
#define PIPE4 996
#define PIPE4B 997
#define BROKEHYDROPLANT 1003
#define PIPE5B 1005
#define NEON3 1007
#define NEON4 1008
#define NEON5 1009
#define BOTTLE5 1012
#define BOTTLE6 1013
#define BOTTLE8 1014
#define SPOTLITE 1020
#define HANGOOZ 1022
#define MASKWALL15 1024
#define BOTTLE7 1025
#define HORSEONSIDE 1026
#define GLASSPIECES 1031
#define HORSELITE 1034
#define DONUTS 1045
#define NEON6 1046
#define MASKWALL6 1059
#define CLOCK 1060
#define RUBBERCAN 1062
#define BROKENCLOCK 1067
#define PLUG 1069
#define OOZFILTER 1079
#define FLOORPLASMA 1082
#define REACTOR 1088
#define REACTORSPARK 1092
#define REACTORBURNT 1096
#define DOORTILE15 1102
#define HANDSWITCH 1111
#define CIRCLEPANNEL 1113
#define CIRCLEPANNELBROKE 1114
#define PULLSWITCH 1122
#define MASKWALL8 1124
#define BIGHOLE 1141
#define ALIENSWITCH 1142
#define DOORTILE21 1144
#define HANDPRINTSWITCH 1155
#define BOTTLE10 1157
#define BOTTLE11 1158
#define BOTTLE12 1159
#define BOTTLE13 1160
#define BOTTLE14 1161
#define BOTTLE15 1162
#define BOTTLE16 1163
#define BOTTLE17 1164
#define BOTTLE18 1165
#define BOTTLE19 1166
#define DOORTILE17 1169
#define MASKWALL7 1174
#define JAILBARBREAK 1175
#define DOORTILE11 1178
#define DOORTILE12 1179
#define VENDMACHINE 1212
#define VENDMACHINEBROKE 1214
#define COLAMACHINE 1215
#define COLAMACHINEBROKE 1217
#define CRANEPOLE 1221
#define CRANE 1222
#define BARBROKE 1225
#define BLOODPOOL 1226
#define NUKEBARREL 1227
#define NUKEBARRELDENTED 1228
#define NUKEBARRELLEAKED 1229
#define CANWITHSOMETHING 1232
#define MONEY 1233
#define BANNER 1236
#define EXPLODINGBARREL 1238
#define EXPLODINGBARREL2 1239
#define FIREBARREL 1240
#define SEENINE 1247
#define SEENINEDEAD 1248
#define STEAM 1250
#define CEILINGSTEAM 1255
#define PIPE6B 1260
#define TRANSPORTERBEAM 1261
#define RAT 1267
#define TRASH 1272
#define FEMPIC1 1280
#define FEMPIC2 1289
#define BLANKSCREEN 1293
#define PODFEM1 1294
#define FEMPIC3 1298
#define FEMPIC4 1306
#define FEM1 1312
#define FEM2 1317
#define FEM3 1321
#define FEM5 1323
#define BLOODYPOLE 1324
#define FEM4 1325
#define FEM6 1334
#define FEM6PAD 1335
#define FEM8 1336
#define HELECOPT 1346
#define FETUSJIB 1347
#define HOLODUKE 1348
#define SPACEMARINE 1353
#define INDY 1355
#define FETUS 1358
#define FETUSBROKE 1359
#define MONK 1352
#define LUKE 1354
#define COOLEXPLOSION1 1360
#define WATERSPLASH2 1380
#define FIREVASE 1390
#define SCRATCH 1393
#define FEM7 1395
#define APLAYERTOP 1400
#define APLAYER 1405
#define PLAYERONWATER 1420
#define DUKELYINGDEAD 1518
#define DUKETORSO 1520
#define DUKEGUN 1528
#define DUKELEG 1536
#define SHARK 1550
#define BLOOD 1620
#define FIRELASER 1625
#define TRANSPORTERSTAR 1630
#define SPIT 1636
#define LOOGIE 1637
#define FIST 1640
#define FREEZEBLAST 1641
#define DEVISTATORBLAST 1642
#define SHRINKSPARK 1646
#define TONGUE 1647
#define MORTER 1650
#define SHRINKEREXPLOSION 1656
#define RADIUSEXPLOSION 1670
#define FORCERIPPLE 1671
#define LIZTROOP 1680
#define LIZTROOPRUNNING 1681
#define LIZTROOPSTAYPUT 1682
#define LIZTOP 1705
#define LIZTROOPSHOOT 1715
#define LIZTROOPJETPACK 1725
#define LIZTROOPDSPRITE 1734
#define LIZTROOPONTOILET 1741
#define LIZTROOPJUSTSIT 1742
#define LIZTROOPDUCKING 1744
#define HEADJIB1 1768
#define ARMJIB1 1772
#define LEGJIB1 1776
#define CANNON 1810
#define CANNONBALL 1817
#define CANNONBALLS 1818
#define OCTABRAIN 1820
#define OCTABRAINSTAYPUT 1821
#define OCTATOP 1845
#define OCTADEADSPRITE 1855
#define INNERJAW 1860
#define DRONE 1880
#define EXPLOSION2 1890
#define COMMANDER 1920
#define COMMANDERSTAYPUT 1921
#define RECON 1960
#define TANK 1975
#define PIGCOP 2000
#define PIGCOPSTAYPUT 2001
#define PIGCOPDIVE 2045
#define PIGCOPDEADSPRITE 2060
#define PIGTOP 2061
#define LIZMAN 2120
#define LIZMANSTAYPUT 2121
#define LIZMANSPITTING 2150
#define LIZMANFEEDING 2160
#define LIZMANJUMP 2165
#define LIZMANDEADSPRITE 2185
#define FECES 2200
#define LIZMANHEAD1 2201
#define LIZMANARM1 2205
#define LIZMANLEG1 2209
#define EXPLOSION2BOT 2219
#define USERWEAPON 2235
#define HEADERBAR 2242
#define JIBS1 2245
#define JIBS2 2250
#define JIBS3 2255
#define JIBS4 2260
#define JIBS5 2265
#define BURNING 2270
#define FIRE 2271
#define JIBS6 2286
#define BLOODSPLAT1 2296
#define BLOODSPLAT3 2297
#define BLOODSPLAT2 2298
#define BLOODSPLAT4 2299
#define OOZ 2300
#define OOZ2 2309
#define WALLBLOOD1 2301
#define WALLBLOOD2 2302
#define WALLBLOOD3 2303
#define WALLBLOOD4 2304
#define WALLBLOOD5 2305
#define WALLBLOOD6 2306
#define WALLBLOOD7 2307
#define WALLBLOOD8 2308
#define BURNING2 2310
#define FIRE2 2311
#define CRACKKNUCKLES 2324
#define SMALLSMOKE 2329
#define SMALLSMOKEMAKER 2330
#define FLOORFLAME 2333
#define ROTATEGUN 2360
#define GREENSLIME 2370
#define WATERDRIPSPLASH 2380
#define SCRAP6 2390
#define SCRAP1 2400
#define SCRAP2 2404
#define SCRAP3 2408
#define SCRAP4 2412
#define SCRAP5 2416
#define ORGANTIC 2420
#define BETAVERSION 2440
#define PLAYERISHERE 2442
#define PLAYERWASHERE 2443
#define SELECTDIR 2444
#define F1HELP 2445
#define NOTCHON 2446
#define NOTCHOFF 2447
#define GROWSPARK 2448
#define DUKEICON 2452
#define BADGUYICON 2453
#define FOODICON 2454
#define GETICON 2455
#define MENUSCREEN 2456
#define MENUBAR 2457
#define KILLSICON 2458
#define FIRSTAID_ICON 2460
#define HEAT_ICON 2461
#define BOTTOMSTATUSBAR 2462
#define BOOT_ICON 2463
#define FRAGBAR 2465
#define JETPACK_ICON 2467
#define AIRTANK_ICON 2468
#define STEROIDS_ICON 2469
#define HOLODUKE_ICON 2470
#define ACCESS_ICON 2471
#define DIGITALNUM 2472
#define DUKECAR 2491
#define CAMCORNER 2482
#define CAMLIGHT 2484
#define LOGO 2485
#define TITLE 2486
#define NUKEWARNINGICON 2487
#define MOUSECURSOR 2488
#define SLIDEBAR 2489
#define DREALMS 2492
#define BETASCREEN 2493
#define WINDOWBORDER1 2494
#define TEXTBOX 2495
#define WINDOWBORDER2 2496
#define DUKENUKEM 2497
#define THREEDEE 2498
#define INGAMEDUKETHREEDEE 2499
#define TENSCREEN 2500
#define PLUTOPAKSPRITE 2501
#define DEVISTATOR 2510
#define KNEE 2521
#define CROSSHAIR 2523
#define FIRSTGUN 2524
#define FIRSTGUNRELOAD 2528
#define FALLINGCLIP 2530
#define CLIPINHAND 2531
#define HAND 2532
#define SHELL 2533
#define SHOTGUNSHELL 2535
#define CHAINGUN 2536
#define RPGGUN 2544
#define RPGMUZZLEFLASH 2545
#define FREEZE 2548
#define CATLITE 2552
#define SHRINKER 2556
#define HANDHOLDINGLASER 2563
#define TRIPBOMB 2566
#define LASERLINE 2567
#define HANDHOLDINGACCESS 2568
#define HANDREMOTE 2570
#define HANDTHROW 2573
#define TIP 2576
#define GLAIR 2578
#define SCUBAMASK 2581
#define SPACEMASK 2584
#define FORCESPHERE 2590
#define SHOTSPARK1 2595
#define RPG 2605
#define LASERSITE 2612
#define SHOTGUN 2613
#define BOSS1 2630
#define BOSS1STAYPUT 2631
#define BOSS1SHOOT 2660
#define BOSS1LOB 2670
#define BOSSTOP 2696
#define BOSS2 2710
#define BOSS3 2760
#define SPINNINGNUKEICON 2813
#define BIGFNTCURSOR 2820
#define SMALLFNTCURSOR 2821
#define STARTALPHANUM 2822
#define ENDALPHANUM 2915
#define BIGALPHANUM 2940
#define BIGPERIOD 3002
#define BIGCOMMA 3003
#define BIGX 3004
#define BIGQ 3005
#define BIGSEMI 3006
#define BIGCOLIN 3007
#define THREEBYFIVE 3010
#define BIGAPPOS 3022
#define BLANK 3026
#define MINIFONT 3072
#define BUTTON1 3164
#define GLASS3 3187
#define RESPAWNMARKERRED 3190
#define RESPAWNMARKERYELLOW 3200
#define RESPAWNMARKERGREEN 3210
#define BONUSSCREEN 3240
#define VIEWBORDER 3250
#define VICTORY1 3260
#define ORDERING 3270
#define TEXTSTORY 3280
#define LOADSCREEN 3281
#define BORNTOBEWILDSCREEN 3370
#define BLIMP 3400
#define FEM9 3450
#define FOOTPRINT 3701
#define FRAMEEFFECT1_13 3999
#define POOP 4094
#define FRAMEEFFECT1 4095
#define PANNEL3 4099
#define SCREENBREAK14 4120
#define SCREENBREAK15 4123
#define SCREENBREAK19 4125
#define SCREENBREAK16 4127
#define SCREENBREAK17 4128
#define SCREENBREAK18 4129
#define W_TECHWALL11 4130
#define W_TECHWALL12 4131
#define W_TECHWALL13 4132
#define W_TECHWALL14 4133
#define W_TECHWALL5 4134
#define W_TECHWALL6 4136
#define W_TECHWALL7 4138
#define W_TECHWALL8 4140
#define W_TECHWALL9 4142
#define BPANNEL3 4100
#define W_HITTECHWALL16 4144
#define W_HITTECHWALL10 4145
#define W_HITTECHWALL15 4147
#define W_MILKSHELF 4181
#define W_MILKSHELFBROKE 4203
#define PURPLELAVA 4240
#define LAVABUBBLE 4340
#define DUKECUTOUT 4352
#define TARGET 4359
#define GUNPOWDERBARREL 4360
#define DUCK 4361
#define HATRACK 4367
#define DESKLAMP 4370
#define COFFEEMACHINE 4372
#define CUPS 4373
#define GAVALS 4374
#define GAVALS2 4375
#define POLICELIGHTPOLE 4377
#define FLOORBASKET 4388
#define PUKE 4389
#define DOORTILE23 4391
#define TOPSECRET 4396
#define SPEAKER 4397
#define TEDDYBEAR 4400
#define ROBOTDOG 4402
#define ROBOTPIRATE 4404
#define ROBOTMOUSE 4407
#define MAIL 4410
#define MAILBAG 4413
#define HOTMEAT 4427
#define COFFEEMUG 4438
#define DONUTS2 4440
#define TRIPODCAMERA 4444
#define METER 4453
#define DESKPHONE 4454
#define GUMBALLMACHINE 4458
#define GUMBALLMACHINEBROKE 4459
#define PAPER 4460
#define MACE 4464
#define GENERICPOLE2 4465
#define XXXSTACY 4470
#define WETFLOOR 4495
#define BROOM 4496
#define MOP 4497
#define LETTER 4502
#define PIRATE1A 4510
#define PIRATE4A 4511
#define PIRATE2A 4512
#define PIRATE5A 4513
#define PIRATE3A 4514
#define PIRATE6A 4515
#define PIRATEHALF 4516
#define CHESTOFGOLD 4520
#define SIDEBOLT1 4525
#define FOODOBJECT1 4530
#define FOODOBJECT2 4531
#define FOODOBJECT3 4532
#define FOODOBJECT4 4533
#define FOODOBJECT5 4534
#define FOODOBJECT6 4535
#define FOODOBJECT7 4536
#define FOODOBJECT8 4537
#define FOODOBJECT9 4538
#define FOODOBJECT10 4539
#define FOODOBJECT11 4540
#define FOODOBJECT12 4541
#define FOODOBJECT13 4542
#define FOODOBJECT14 4543
#define FOODOBJECT15 4544
#define FOODOBJECT16 4545
#define FOODOBJECT17 4546
#define FOODOBJECT18 4547
#define FOODOBJECT19 4548
#define FOODOBJECT20 4549
#define HEADLAMP 4550
#define TAMPON 4557
#define SKINNEDCHICKEN 4554
#define FEATHEREDCHICKEN 4555
#define ROBOTDOG2 4560
#define JOLLYMEAL 4569
#define DUKEBURGER 4570
#define SHOPPINGCART 4576
#define CANWITHSOMETHING2 4580
#define CANWITHSOMETHING3 4581
#define CANWITHSOMETHING4 4582
#define SNAKEP 4590
#define DOLPHIN1 4591
#define DOLPHIN2 4592
#define NEWBEAST 4610
#define NEWBEASTSTAYPUT 4611
#define NEWBEASTJUMP 4690
#define NEWBEASTHANG 4670
#define NEWBEASTHANGDEAD 4671
#define BOSS4 4740
#define BOSS4STAYPUT 4741
#define FEM10 4864
#define TOUGHGAL 4866
#define MAN 4871
#define MAN2 4872
#define WOMAN 4874
#define PLEASEWAIT 4887
#define NATURALLIGHTNING 4890
#define WEATHERWARN 4893
#define DUKETAG 4900
#define SIGN1 4909
#define SIGN2 4912
#define JURYGUY 4943

// These tile positions are reserved!
#define RESERVEDSLOT1 6132
#define RESERVEDSLOT2 6133
#define RESERVEDSLOT3 6134
#define RESERVEDSLOT4 6135
#define RESERVEDSLOT5 6136
#define RESERVEDSLOT6 6137
#define RESERVEDSLOT7 6138
#define RESERVEDSLOT8 6139
#define RESERVEDSLOT9 6140
#define RESERVEDSLOT10 6141
#define RESERVEDSLOT11 6142
#define RESERVEDSLOT12 6143

repo_name: orochi/nblood

license: mit


code:
// 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, "enableevent 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

// color of various drawing enhancements
define PREVIEW_DRAW_COLOR 11
gamevar showpal 0 0

// whether to use overridden aspect/range values when entering 3d mode (software/Polymost).
// tweak with keys 7,8,9,0 on the top row
gamevar use_custom_aspect 0 0  // this is now the same as r_usenewaspect
gamevar davr 65536 0
gamevar dayx 65536 0

// whether to remap certain widely-available keys to rare ones
// (notebook/netbook convenience, see EVENT_KEYPRESS for details)
gamevar use_notebook_keys 0 0

// Whether RESPAWN sprites show the respawned sprite picnum unconditionally instead of
// only when aimed at (and locked onto) the RESPAWN sprite in 3D mode.
gamevar showrespawn_always 0 0
// When set to 1, previewed sprites are 66% translucent instead of 33%:
gamevar showrespawn_fulltrans 0 0

// Set to basepal index to override
gamevar override_basepal -1 0

gamevar move_by_one 0 0

// Polymer "head" light
gamevar headlight_enabled 0 0
gamevar headlight_range 4000 0

// see end of file for more user settings and examples

////////// 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 sec 0 0
gamevar wal 0 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

define PRSCALE 1000
define MAXSPECULAR 100000

define TMPARLEN 128
gamearray ar TMPARLEN
gamearray xx TMPARLEN
gamearray yy TMPARLEN

gamearray parm 8

// prints out maphack light definitions based on SE lights in map
defstate printlights
    "Print Polymer lights"
    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

defstate insertlights
    "Insert active SE lights"
    var sectnum

    set k 0
    for i activelights
    {
        insertsprite light[i].sector

        // I is the inserted sprites' index now
        set .picnum 1

        set .x light[i].x
        set .y light[i].y
        set .z light[i].z

        set .hitag light[i].range
        set .xvel light[i].r
        set .yvel light[i].g
        set .zvel light[i].b

        set .extra light[i].horiz

        set .xoffset light[i].minshade
        set .yoffset light[i].maxshade

        set .owner light[i].tilenum

        set .xrepeat 48
        set .yrepeat 48

        // now those that are calculated
        ifge light[i].priority 4 or .cstat 512
        ifge light[i].priority 2 or .cstat 2

        ife light[i].radius 0
        {
            set .lotag 49
        }
        else
        {
            set .lotag 50
            set j light[i].radius, shiftr j 1, sub j 128, inv j
            clamp j -128 127
            set .shade j
        }

        add k 1
    }

    qsprintf TQUOTE "* Inserted %d SE sprites based on active lights." k
    print TQUOTE
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 and the respective 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
    var val

    // 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

        ifeitheralt 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..PSCALESTEPS
            set minval MINPARALLAXSCALE, mul minval PSCALESTEPS
            set maxval MAXPARALLAXSCALE, mul maxval PSCALESTEPS
            add k j, clamp k minval maxval
            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
//quote "zxczxc"
    }
//quote "asdasd"
    // 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

        ifeitheralt 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
    }

//quote "qweqwe"
    // 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 ifeithershift ifhitkey KEY_KP2 // alt-kp2 collides with KP* replacement
            {
                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
        {
            // KP8/KP5: horiz
            ifeithershift set j 1 else set j 10

            ifhitkey KEY_gUP nullop
            else ifhitkey KEY_gKP5 mul j -1
            else set j 0

            ifvarn j 0
            {
                // change it
                set val .extra
                add val j
                clamp val -32768 32767
                set .extra val
            }

            // KP4/KP6: 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

            // KP+/KP-: 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

        set k .hitag
        ifhitkey KEY_KP9 add k j
        else ifhitkey KEY_KP7 sub k j
        clamp k 0 32767
        set .hitag k

        // 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_B { add .xvel j, set k 1 }
            ifhitkey KEY_N { add .yvel j, set k 1 }
            ifhitkey KEY_M { add .zvel j, set k 1 }

            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
            }
        }
    }
    else
    {
        // not aiming at sprite

        ifeitherctrl ifeithershift ifhitkey KEY_gMINUS
        {
            ife headlight_enabled 0
            {
                set headlight_enabled 1
                quote "head light enabled"
            }
            else
            {
                set headlight_enabled 0
                quote "head light disabled"
            }
        }
    }
ends

defstate do_move_by_one
    ifeithershift
    {
        ifhitkey KEY_UP sub horiz 1
        ifhitkey KEY_DOWN add horiz 1
        ifhitkey KEY_LEFT sub ang 1
        ifhitkey KEY_RIGHT add ang 1
        and ang 2047
    }
    else
    {
        // absolute x/y/z navigation
        ifhitkey KEY_LEFT sub posx 1
        ifhitkey KEY_RIGHT add posx 1
        ifhitkey KEY_DOWN sub posy 1
        ifhitkey KEY_UP add posy 1
        ifhitkey KEY_A sub posz 1
        ifhitkey KEY_Z add posz 1
    }
ends

defstate check_move_by_one
    ifn move_by_one 0
        set hardcoded_movement 0
    else
        set hardcoded_movement 1
ends

// forward refs
defstate userkeys_3d ends
defstate userdrawlabel ends

onevent EVENT_PREKEYS3D
//    state testkeyavail

    state check_move_by_one
    ifn move_by_one 0
        state do_move_by_one

    state fiddlewithlights
    state userkeys_3d
endevent

// 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

gamevar do_batch_extension 0 0
gamevar batch_ohl_i -1 0
gamevar batch_tmp 0 0

////// sector collecting stuff
gamearray collectedsectors MAXSECTORS  // shared with 'old-highlighted sectors'
gamevar ohlsecs 0 0

// save or restore highlighted sectors
defstate save_restore_hlsectors
    "Save/restore hl. sectors"

    ifge highlightsectorcnt 0
    {
        // save
        for i range highlightsectorcnt
            set collectedsectors[i] highlightsector[i]
        set ohlsecs highlightsectorcnt
        quote "Highlighted sectors saved"
    }
    else ifl highlightcnt 0
    {
        for i range ohlsecs
            sethighlightsector collectedsectors[i] 1
        quote "Highlighted sectors restored"
    }
ends

defstate extendhlsectors
    "Extend all hl. sectors"

    ifvarle highlightsectorcnt 0 return

    state save_restore_hlsectors  // will save them
    for i range highlightsectorcnt
        sethighlightsector highlightsector[i] 0

    set do_batch_extension 1
    set batch_ohl_i 0
ends

onevent EVENT_PREKEYS2D
    state check_move_by_one
    ifn move_by_one 0
        state do_move_by_one

    ifvare do_batch_extension 1
        set do_batch_extension 2
    else ifvare do_batch_extension 2
    {
        ifge batch_ohl_i ohlsecs
        {
            // done!
            set do_batch_extension 0
            set batch_ohl_i -1

            set keystatus[0x1d] 0
            set keystatus[0x12] 0
        }
        else
        {
            ifvare batch_tmp 0
            {
                // highlight that sector
                sethighlightsector collectedsectors[batch_ohl_i] 1
                set batch_tmp 1
            }
            else  // ... skip a mainloop iteration so that a frame can be displayed
            {
                set batch_tmp 0
                add batch_ohl_i 1

                // fake a Ctrl-E
                set keystatus[0x1d] 1
                set keystatus[0x12] 1
            }
        }

        break
    }

//    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

gamevar fyx 0 0
gamevar fvr 0 0

defstate setas
    set fyx dayx
    mul fyx 4 mul fyx 100  // the correction factor 100/107 has been found
    div fyx 3 div fyx 107  // out experimentally. squares ftw!
    set fvr davr
    mul fvr xdim mul fvr 3
    div fvr ydim div fvr 4
    setaspect fvr fyx //davr dayx
ends

onevent EVENT_ENTER3DMODE
    ifn use_custom_aspect 0
        state setas
endevent

defstate try_nextsector_teleporting
    var nexts
    set nexts RETURN

    set RETURN 0
    for i spritesofsector nexts
    {
        ife .picnum SECTOREFFECTOR ife .lotag 7
        {
            set RETURN 1
            break
        }
    }
ends

defstate try_nextsector_ceilingsky
    ifand sector[RETURN].ceilingstat 1
        set RETURN 1
    else
        set RETURN 0
ends

defstate collect_teleporting_sectors // (sec)
    "Collect telep. sectors"
    var numsects

    set numsects numsectors, sub numsects 1
    ifinteractive
    {
        set sec searchsector
        getnumberfromuser sec "starting sectnum: " numsects 8
        ifl sec 0, return
    }

    set ohlsecs 0  // reset old hl'd sectors

    collectsectors collectedsectors sec numsects try_nextsector_teleporting
    for i range numsects
        sethighlightsector collectedsectors[i] 1
ends

// XXX: CODEDUP
defstate collect_ceilsky_sectors // (sec)
    "Collect sky ceilings"
    var numsects

    set numsects numsectors, sub numsects 1
    ifinteractive
    {
        set sec searchsector
        getnumberfromuser sec "starting sectnum: " numsects 8
        ifl sec 0, return
    }

    set ohlsecs 0  // reset old hl'd sectors

    collectsectors collectedsectors sec numsects try_nextsector_ceilingsky
    for i range numsects
        sethighlightsector collectedsectors[i] 1
ends

////// show LOCATORS
defstate cmp_by_lotag  // comparator subroutine for sorting
    set RETURN sprite[SV2].lotag
    sub RETURN sprite[SV1].lotag
ends

defstate connectlocators
    // connect LOCATORS in a sector with 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]
        drawline16z sprite[j].x sprite[j].y sprite[j].z sprite[k].x sprite[k].y sprite[k].z drawcol
    }
ends

defstate draw_prlightprojections
////////// 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
                drawline16z x y .z x2 y2 .z 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
                drawline16z x y .z x2 y2 .z c
                drawcircle16z .x .y .z .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

                drawline16z .x .y .z xx[0] yy[0] .z c
                drawline16z .x .y .z xx[1] yy[1] .z c
            }
        }
    }
    set drawlinepat oldpat
ends

defstate previewdoors2d
    // preview swinging and sliding doors in 2d mode
    var valid sect lo
    var i j w numw ang trange dx dy

    set valid 0
    set sect searchsector

    ifge sect 0 ifl sect numsectors
    {
        set lo sector[sect].lotag
        ife lo 23 set valid 1
        else ife lo 25 set valid 1
    }

    ife valid 1
    {
        set valid 0
        for i spritesofsector sect
            ifactor SECTOREFFECTOR
            {
                ife .lotag 11 ife lo 23 set valid 1  // swinging door
                ife .lotag 15 ife lo 25 set valid 1  // slide door
                ife valid 1 { set j i, break }
            }

        ife valid 1
            seti j
        else return

        ife .lotag 15
        {
            set trange 256
            for i spritesofsector sect
                ifactor GPSPEED { set trange .lotag, break }
            mul trange 2  // now equals distance of sliding door to travel
        }

        set i 0
        for w loopofwall sector[sect].wallptr
        {
            ifge i TMPARLEN break
            set xx[i] wall[w].x
            set yy[i] wall[w].y
            add i 1
        }
        ifl i TMPARLEN
        {
            set xx[i] xx[0]
            set yy[i] yy[0]
            add i 1
        }
        set numw i

        ife .lotag 11
        {
            ifg .ang 1024 set ang -512 else set ang 512
            for i range numw
                rotatepoint .x .y xx[i] yy[i] ang xx[i] yy[i]
        }
        else  // if .lotag 15
        {
            set ang .ang, add ang 1024
            a2xy ang dx dy
            mulscale dx trange dx 14
            mulscale dy trange dy 14

            for i range numw
            {
                add xx[i] dx
                add yy[i] dy
            }
        }

        set drawlinepat 0x33333333
        sub numw 1
        for i range numw
        {
            set j i, add j 1
            drawline16z xx[i] yy[i] sector[sect].floorz xx[j] yy[j] sector[sect].floorz PREVIEW_DRAW_COLOR
        }
        set drawlinepat 0xffffffff
    }
ends

// 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

defstate print_parallel_midpts  // print the midpoints of parallel wall-lines
    var p0 p1 p2 s1dx s1dy s2dx s2dy tmp nw

    quote "----------------"
    for p1 allwalls
    {
        lastwall p1 p0  // get the 'inverse point2'
        set p2 wall[p1].point2  // ... and the forward one

        set tmp 0

        // both white: OK  (may be false positive due to TROR)
        ifl wall[p0].nextwall 0 ifl wall[p1].nextwall 0 set tmp 1

        // both red and no wall originating from midpoint on the other side: OK
        ifge wall[p0].nextwall 0 ifge wall[p1].nextwall 0
        {
            set nw wall[p1].nextwall
            ifl p1 nw, ife wall[p0].nextwall wall[nw].point2, set tmp 1
        }

        ife tmp 1
        {
            set s1dx wall[p1].x, sub s1dx wall[p0].x
            set s1dy wall[p1].y, sub s1dy wall[p0].y

            set s2dx wall[p2].x, sub s2dx wall[p1].x
            set s2dy wall[p2].y, sub s2dy wall[p1].y

            // now have segment dx/dy's

            mul s1dx -s2dy
            mul s1dy s2dx
            set tmp s1dx, add tmp s1dy  // tmp = (s1dx, s1dy) . (-s2dy, s2dx)

            ife tmp 0
            {
                qsprintf TQUOTE "%d" p1
                quote TQUOTE
            }
        }
    }
ends

//////////////////// 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
    ifl searchwall 0 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

defstate respawnpreview
    var ts ow pic z
    var k onumtspr

    ife showrespawn_always 0
    {
        ifaimingsprite ife sprite[searchwall].picnum RESPAWN nullop
        else return
    }

    set onumtspr spritesortcnt

    for ts range onumtspr
    {
        set ow tsprite[ts].owner
        ife showrespawn_always 0 ifn ow searchwall nullop else
        {
            ife sprite[ow].picnum RESPAWN
            {
                set k spritesortcnt
                tdupsprite ow

                // XXX: doesn't work with E1L5 boss RESPAWN...
                // Something's wrong with setting tsprite[] members.
                sub tsprite[k].z 4096

                set tsprite[k].xrepeat 16
                set tsprite[k].yrepeat 16

                set pic sprite[ow].hitag
                ifge pic 0 ifl pic MAXTILES
                    set tsprite[k].picnum pic

                and tsprite[k].cstat 0xfffffdff  // clear bit 512 (reverse translucency)
                or tsprite[k].cstat 2  // set bit 2 (33% translucency)
                ifvarn showrespawn_fulltrans 0
                    or tsprite[k].cstat 512
            }
        }
    }
ends

onevent EVENT_ANALYZESPRITES
    state respawnpreview
    state tduprot
    state tduplin
endevent

defstate update_headlight
    var li hrz
    set li 0

    ifvare headlight_enabled 0
        break

    ifvarl cursectnum 0
        break

    ifvarn light[li].active 1
        break

    set light[li].x posx
    set light[li].y posy
    set light[li].z posz
    set light[li].sector cursectnum
    set hrz horiz
    set light[li].horiz hrz
    set light[li].angle ang

    set light[li].range headlight_range
    set light[li].radius 256
    set light[li].faderadius 128

    set light[li].r 255
    set light[li].g 255
    set light[li].b 255
    set light[li].priority 0

    set light[li].tilenum 0
ends

onevent EVENT_PREDRAW3DSCREEN
    state update_headlight
endevent

onevent EVENT_KEYS3D
    var l m

    ifvarge override_basepal 0
        setgamepalette override_basepal

    // door sound tester
    ifeitherctrl ifeithershift 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
                resetkey KEY_SPACE
            }
        }
    }

    // swinging doors tester -- hit Ctrl-Shift-SPACE on a door wall
    ifeitherctrl ifeithershift ifaimingwall
    ifholdkey KEY_SPACE  // SE11 ST23 up:ccw
    {
        set k wall[searchwall].nextsector
        ifl k 0 return
        ifn sector[k].lotag 23 return

        resetkey KEY_SPACE

        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)
    ifeitheralt ifaimingsprite
    ifholdkey 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

            resetkey KEY_SPACE

            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
            resetkey KEY_SPACE
        }
        else ife sprite[searchwall].extra DUP_LIN_MAGIC2
        {
            state duplin
            resetkey KEY_SPACE
        }
    }

    set j 0

    set k 0
    ifholdkey KEY_7 set k -1
    ifholdkey KEY_0 set k 1
    ifn k 0
    {
        set j 1
        ifeithershift nullop else mul k 256
        add davr k
        ifl davr 32768 set davr 32768
        ifg davr 256000 set davr 256000
    }

    set k 0
    ifholdkey KEY_8 set k -1
    ifholdkey KEY_9 set k 1
    ifn k 0
    {
        set j 1
        ifeithershift nullop else mul k 256
        add dayx k
        ifl dayx 32768 set dayx 32768
        ifg dayx 256000 set dayx 256000
    }
    ife j 1
    {
//        setaspect davr dayx
        state setas
        qsprintf TQUOTE "ASPECT: davr=%d, dayx=%d | FVR=%d, FYX=%d" davr dayx fvr fyx
        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 jumptowal  // (wal)
    ifge wal 0 ifl wal numwalls nullop else return
    set posx wall[wal].x
    set posy wall[wal].y
    updatecursectnum
ends

defstate jumptosec  // (sec)
    ifge sec 0 ifl sec numsectors nullop else return
    set wal sector[sec].wallptr
    state jumptowal
ends

onevent EVENT_DRAW2DSCREEN
    var tmp tmp2
    var xx xx2 yy

    state userdrawlabel

    ifge cursectnum 0
    {
        state connectlocators
        state draw_prlightprojections
    }

    state previewdoors2d

    ifn showpal 0
    {
        set xx 100
        for tmp range 256
        {
            set tmp2 tmp
            mod tmp2 64
            ife tmp2 32
            {
                drawline16 xx 95 xx 99 15
                qsprintf TQUOTE "%d" tmp
                printext16 TQUOTE xx 80 23 0 0
            }
            else ife tmp2 0
            {
                drawline16 xx 90 xx 99 15
                qsprintf TQUOTE "%d" tmp
                printext16 TQUOTE xx 80 15 0 0
            }

            drawline16 xx 100 xx 200 -tmp
            add xx 1
            drawline16 xx 100 xx 200 -tmp
            add xx 1
            ifge tmp 240
            {
                drawline16 xx 100 xx 200 -tmp
                add xx 1
                drawline16 xx 100 xx 200 -tmp
                add xx 1
            }
        }

        set xx 100, set xx2 260
        set yy 208
        for tmp range 256
        {
            qsprintf TQUOTE "editor color %d" tmp
            printext16 TQUOTE xx yy tmp 0 0
            printext16 TQUOTE xx2 yy 0 tmp 0

            add yy 8

            set tmp2 tmp
            mod tmp2 64

            ife tmp2 63
            {
                set yy 208
                add xx 320
                add xx2 320
            }
        }
    }
endevent

defstate mkterrain
    var w2 w3 idx bit tmp sec
    var warned

    set warned 0

    for i selwalls
    {
        sectorofwall j i
        set tmp 0, ifand sector[j].floorstat 2, set tmp 1  // already handled
        ife tmp 0 ife sector[j].wallnum 3
        {
            set w2 wall[i].point2
            set idx w2, shiftr idx 3
            set tmp w2, and tmp 7, set bit 1, shiftl bit tmp
            ifand show2dwall[idx] bit
            {
                setfirstwall j i

                set z 0x7ffffff
                ifin3dmode
                {
                    ife searchstat 2  // floor
                        set z sector[searchsector].floorz
                }
                else
                {
                    for k allsectors
                    {
                        ifinside mousxplc mousyplc k
                        {
                            set z sector[k].floorz
                            break
                        }
                    }
                }

                ife z 0x7ffffff
                {
                    ife warned 0
                    {
                        quote "Mouse pointer must be aiming at sector floor."
                        set warned 1
                    }
                }
                else
                {
                    set w3 wall[w2].point2
                    set sec wall[i].nextsector
                    ifge sec 0
                        set sector[j].floorz sector[sec].floorz
                    alignflorslope j wall[w3].x wall[w3].y z
                }
            }
        }
    }
ends

defstate chselshade
    for i selsectors
    {
        set sector[i].floorshade tempshade
        set sector[i].ceilingshade tempshade

        for j spritesofsector i
            set .shade tempshade

        for j wallsofsector i
            set wall[j].shade tempshade
    }
ends

defstate listusedtags
    for i allsprites
    {
        getspritelinktype i k

        ifn k 0
        {
            ife k 1
                qsprintf TQUOTE "sprite %d lotag %d" i sprite[i].lotag
            else ife k 2
                qsprintf TQUOTE "sprite %d hitag %d" i sprite[i].hitag
            quote TQUOTE
        }
    }
ends

defstate moveselsects
    var p1 dx dy

    for i selsectors
    {
        set p1 sector[i].wallptr
        set dx wall[p1].x, set dy wall[p1].y
        for j wallsofsector i
        {
            sub wall[j].x dx
            sub wall[j].y dy
        }
        for j spritesofsector i
        {
            sub .x dx
            sub .y dy
        }
    }
ends

defstate sanitize_underwater_sprites
    "Xvel=1 for wall/flr spr."
    for i selsprites
    {
        set j .cstat
        and j 49
        ife j 17 set .xvel 1
        ife j 33 set .xvel 1
    }
    printmessage16 "Set xvel=1 on highlighted wall/floor sprites"
ends

define BZ_MAX 8388608

defstate uniformceil
    var avgz n

    for i selsectors
    {
        ifand sector[i].ceilingstat 2 xor sector[i].ceilingstat 2
        add avgz sector[i].ceilingz
        add n 1
    }

    ife n 0 break

    div avgz n
    and avgz 0xfffffc00  // round to one PGUP/PNDN unit (1024 z units)

    ifvarge avgz -BZ_MAX ifvarle avgz BZ_MAX nullop
    else quote "ERROR: average z value outside [-8388608 .. 8388608]"  // BZ_MAX

    for i selsectors
        set sector[i].ceilingz avgz
ends

// XXX: CODEDUP
defstate uniformfloor
    var avgz n

    for i selsectors
    {
        ifand sector[i].floorstat 2 xor sector[i].floorstat 2
        add avgz sector[i].floorz
        add n 1
    }

    ife n 0 break

    div avgz n
    and avgz 0xfffffc00  // round to one PGUP/PNDN unit (1024 z units)

    ifvarge avgz -BZ_MAX ifvarle avgz BZ_MAX nullop
    else quote "ERROR: average z value outside [-8388608 .. 8388608]"  // BZ_MAX

    for i selsectors
        set sector[i].floorz avgz
ends

defstate for_sprites_near_picnum
    "Ch. lotag for near spr."

    var ii dst
    var picnumi picnumj maxldist lotag

    getnumberfromuser picnumi "picnum i: " MAXTILES 10
    ifvarl picnumi 0 break
    getnumberfromuser picnumj "picnum j: " MAXTILES 10
    ifvarl picnumj 0 break

    getnumberfromuser maxldist "max ldist: " 65536 8
    ifvarl maxldist 0 break

    getnumberfromuser lotag "lotag (unsigned) to change to: " 65536 8
    ifvarl lotag 0 break

    for i allsprites ife sprite[i].picnum picnumi
        for j allsprites ife sprite[j].picnum picnumj
        {
            ldist dst i j
            ifle dst maxldist
                set sprite[j].lotag lotag
        }

    qsprintf TQUOTE "changed lotag of sprites w/ tile %d near those w/ tile %d to %d" picnumj picnumi lotag
    quote TQUOTE
ends

// This must be *compiled* with script_expertmode
/*
defstate setstartpos
    "Set start pos. from spr."
    var spr
    getnumberfromuser spr "sprite number: " MAXSPRITES 8

    seti spr
    set startposx .x
    set startposy .y
    set startposz .z
    set startsector .sectnum
    set startang .ang
ends
*/

////////// USER AREA //////////

// key settings
defstate userkeys_3d
/*
    ifge searchwall 0 ifl searchwall MAXWALLS
    ifholdkey KEY_KP5
    {
        add wall[searchwall].ypanning 1
        set DOSCRSHOT 1
    }
*/
    ifholdkey KEY_SEMI ifhitkey KEY_C state chselshade
ends

gamevar scrshot 0 1

////////// DRAW TILE (ROTATESPRITE) TESTING //////////
gamevar dt_t -1 0  // tilenum
gamevar dt_x 160 0 // x
gamevar dt_y 100 0 // y
gamevar dt_z 65536 0  // zoom
gamevar dt_a 0 0  // angle
gamevar dt_s 0 0  // shade
gamevar dt_p 0 0  // pal
gamevar dt_o 0 0  // orientation
gamevar dt_A 0 0  // alpha

onevent EVENT_DRAW3DSCREEN
    ifge dt_t 0
        rotatespritea dt_x dt_y dt_z dt_a dt_t dt_s dt_p dt_o dt_A 0 0 xdim ydim

    ifn move_by_one 0
    {
        qsprintf TQUOTE "x,y,z = %d, %d, %d" posx posy posz
        printext256 TQUOTE 30 30 -15 0 0

        qsprintf TQUOTE "horiz,ang = %d, %d" horiz ang
        printext256 TQUOTE 30 40 -15 0 0
    }

/*
    ifge searchwall 0, ifl searchwall MAXWALLS
    {
        // Which wall is considered targeted?
        qsprintf TQUOTE "searchwall = %d" searchwall
        printext256 TQUOTE 30 30 -15 0 0

        qsprintf TQUOTE "y panning = %d" wall[searchwall].ypanning
        printext256 TQUOTE 30 40 -15 0 0
    }
*/
endevent

// convenience rebindings for notebooks:
//  Alt-F11 --> SCROLL LOCK (set first position)
//  Alt-arrows --> KP arrows (change pan/repeat in 3D mode)
onevent EVENT_KEYPRESS
    var thekey
    set thekey RETURN

    ifvare use_notebook_keys 0, return
/*
    ifholdkey thekey
        qsprintf TQUOTE "pressed %d" thekey
    else
        qsprintf TQUOTE "released %d" thekey
    print TQUOTE
*/
    ifholdkey thekey  // if the callback key was pressed (and not released)
    {
        ifholdkey KEY_LALT
        {
            ifhitkey KEY_F11, setkey KEY_SCROLL

            ifhitkey KEY_UP, setkey KEY_KP8
            ifhitkey KEY_DOWN, setkey KEY_KP2
            ifhitkey KEY_LEFT, setkey KEY_KP4
            ifhitkey KEY_RIGHT, setkey KEY_KP6

// would be 'cleaner' (only checking cb key) but is too much code for my taste:
/*
            switch (thekey)
            {
                case KEY_F11: setkey KEY_SCROLL; resetkey thekey; break;

                // and so on with the rest...
            }
            endswitch
*/
        }
    }
    else  // cb key was released
    {
        switch (thekey)
        {
            case KEY_LALT:
            {
                resetkey KEY_KP8;
                resetkey KEY_KP2;
                resetkey KEY_KP4;
                resetkey KEY_KP6;
                break;
            }

            case KEY_UP: resetkey KEY_KP8; break;
            case KEY_DOWN: resetkey KEY_KP2; break;
            case KEY_LEFT: resetkey KEY_KP4; break;
            case KEY_RIGHT: resetkey KEY_KP6; break;
        }
        endswitch
    }
endevent

/*
// example for custom labels
defstate userdrawlabel
    for i allsprites
    {
        ifactor 2978
        {
            qsprintf TQUOTE "MOVABLE EX:%d OW:%d", sprite[i].owner, sprite[i].extra
            drawlabel TQUOTE .x .y .z 0 31
        }
    }
ends
*/


code:
/*
    To begin, type in the console:

    include dump_used_assets
    enableevent all

    Open your map.
    In 2D mode, press CTRL+V to search for the tiles and sounds used in the current map.
    You can set the gamevar "verbose" to 1 if you want verbose .csv formatted information that would normally clog up the output.
    Tip: With pk_quickmapcycling enabled, Ctrl-(LShift-)X loads the next (previous) map in a directory.

    The results from every map will be accumulated into master lists.
    When you have searched for tiles in all desired maps, press CTRL+D to print the finished lists.

    The results will be printed in mapster32.log.
*/

include names.h

gamearray usedTiles MAXTILES
gamearray usedSounds MAXSOUNDS

definequote 0
definequote 1 %ld

definequote 11 sprite,%ld,
definequote 12 floor,%ld,
definequote 13 ceiling,%ld,
definequote 14 wall,%ld,
definequote 15 overwall,%ld,

definequote 21 MUSICANDSFX triggered,%ld,
definequote 22 MUSICANDSFX ambient,%ld,
definequote 23 sector one-time,%ld,
definequote 24 MIKE,%ld,
definequote 25 switch,%ld,
definequote 26 MIRROR,%ld,
definequote 27 sector 65534,%ld,
definequote 28 doortile,%ld,

definequote 101 Searching for tiles used in current map...
definequote 102 Tile search finished.
definequote 103 Dumping tiles, cumulatively...
definequote 104 Tile dump finished.
definequote 105 Searching for sounds used in current map...
definequote 106 Sound search finished.
definequote 107 Dumping sounds, cumulatively...
definequote 108 Sound dump finished.
definequote 109 Search finished.
definequote 110 Dump finished.

gamevar variable 0 0

gamevar verbose 0 0

gamevar index 0 0

gamevar flag 0 0
gamevar input 0 0

defstate tile_search
    quote 101

    for variable allsprites
    {
        set index .picnum
        ifge index 0 ifle index MAXTILES set usedTiles[index] 1
        ife verbose 1
        {
            qsprintf 0 11 .picnum
            quote 0
        }
    }
    for variable allsectors
    {
        set index sector[variable].floorpicnum
        ifge index 0 ifle index MAXTILES set usedTiles[index] 2
        set index sector[variable].ceilingpicnum
        ifge index 0 ifle index MAXTILES set usedTiles[index] 3
        ife verbose 1
        {
            qsprintf 0 12 sector[variable].floorpicnum
            quote 0
            qsprintf 0 13 sector[variable].ceilingpicnum
            quote 0
        }
    }
    for variable allwalls
    {
        set index wall[variable].picnum
        ifge index 0 ifle index MAXTILES set usedTiles[index] 4
        set index wall[variable].overpicnum
        ifge index 0 ifle index MAXTILES set usedTiles[index] 5
        ife verbose 1
        {
            qsprintf 0 14 wall[variable].picnum
            quote 0
            qsprintf 0 15 wall[variable].overpicnum
            quote 0
        }
    }

    quote 102
ends

defstate tile_dump
    quote 103

    for variable range MAXTILES
        ifn usedTiles[variable] 0
        {
            qsprintf 0 1 variable
            quote 0
        }

    quote 104
ends

// these long "ife" lists exist because switch/case is broken/was broken at the original time of writing

// the three commented switches do not play sounds because their hitag is used for setting a multi-switch combination
defstate switch_identify
    ife input ACCESSSWITCH set flag 1
    ife input SLOTDOOR set flag 1 ife input 133 set flag 1
    ife input LIGHTSWITCH set flag 1 ife input 135 set flag 1
    ife input SPACEDOORSWITCH set flag 1 ife input 137 set flag 1
    ife input SPACELIGHTSWITCH set flag 1 ife input 139 set flag 1
    ife input FRANKENSTINESWITCH set flag 1 ife input 141 set flag 1
    ife input MULTISWITCH set flag 1 ife input 147 set flag 1 ife input 148 set flag 1 ife input 149 set flag 1
    // ife input DIPSWITCH set flag 1 ife input 163 set flag 1
    ife input DIPSWITCH2 set flag 1 ife input 165 set flag 1
    // ife input TECHSWITCH set flag 1 ife input 167 set flag 1
    ife input DIPSWITCH3 set flag 1 ife input 169 set flag 1
    ife input ACCESSSWITCH2 set flag 1
    ife input LIGHTSWITCH2 set flag 1 ife input 713 set flag 1
    ife input POWERSWITCH1 set flag 1 ife input 861 set flag 1
    ife input LOCKSWITCH1 set flag 1 ife input 863 set flag 1
    ife input POWERSWITCH2 set flag 1 ife input 865 set flag 1
    ife input HANDSWITCH set flag 1 ife input 1112 set flag 1
    ife input PULLSWITCH set flag 1 ife input 1123 set flag 1
    // ife input ALIENSWITCH set flag 1 ife input 1143 set flag 1
ends

defstate doortile_identify
    ife input DOORTILE1 set flag 1
    ife input DOORTILE2 set flag 1
    ife input DOORTILE3 set flag 1
    ife input DOORTILE4 set flag 1
    ife input DOORTILE5 set flag 1
    ife input DOORTILE6 set flag 1
    ife input DOORTILE7 set flag 1
    ife input DOORTILE8 set flag 1
    ife input DOORTILE9 set flag 1
    ife input DOORTILE10 set flag 1
    ife input DOORTILE11 set flag 1
    ife input DOORTILE12 set flag 1
    ife input DOORTILE14 set flag 1
    ife input DOORTILE15 set flag 1
    ife input DOORTILE16 set flag 1
    ife input DOORTILE17 set flag 1
    ife input DOORTILE18 set flag 1
    ife input DOORTILE19 set flag 1
    ife input DOORTILE20 set flag 1
    ife input DOORTILE21 set flag 1
    ife input DOORTILE22 set flag 1
    ife input DOORTILE23 set flag 1
ends

defstate sound_search
    quote 105

    for variable allsprites, ifactor MUSICANDSFX, ifl .lotag 1000 // rule out echo effect
    {
// This is how the code SHOULD be:
// activation sounds / triggered sounds (e.g. elevators)
        sectgetlotag
        ifn LOTAG 0, ifl LOTAG 10000
        {
            ifn .lotag 0 ifl .lotag 500
            {
                set index .lotag
                ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 1
                ife verbose 1
                {
                    qsprintf 0 21 .lotag
                    quote 0
                }
            }
            ifn .hitag 0 ifl .hitag 500
            {
                set index .hitag
                ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 1
                ife verbose 1
                {
                    qsprintf 0 21 .hitag
                    quote 0
                }
            }
        }
// ambient sounds
        else
        {
            ifn .lotag 0 ifl .lotag 500
            {
                set index .lotag
                ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 2
                ife verbose 1
                {
                    qsprintf 0 22 .lotag
                    quote 0
                }
            }
        }
    }

// one-time sector sounds
    for variable allsectors, ifge sector[variable].lotag 10000, ifl sector[variable].lotag 16383
    {
        set index sector[variable].lotag
        subvar index 10000
        ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 3
        ife verbose 1
        {
            qsprintf 0 23 index
            quote 0
        }
    }

// mikesnd
    for variable allsprites, ifactor MIKE
    {
        set index .hitag // this one's clever -- by default it will play sound 0, as seen in E4L7
        ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 4
        ife verbose 1
        {
            qsprintf 0 24 .hitag
            quote 0
        }
    }

// switches
    for variable allsprites
    {
        set flag 0
        set input .picnum
        state switch_identify
        ife flag 1, ifn .hitag 0
        {
            set index .hitag
            ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 5
            ife verbose 1
            {
                qsprintf 0 25 .hitag
                quote 0
            }
        }
    }

// mirror
    for variable allwalls
    {
        set index 0
        ife wall[variable].picnum MIRROR set index wall[variable].lotag
        ife wall[variable].overpicnum MIRROR set index wall[variable].lotag
        ifn index 0
        {
            ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 6
            ife verbose 1
            {
                qsprintf 0 26 index
                quote 0
            }
        }
    }

// sector lotag 65534 (E1L2 ending) customexitsound
    for variable allsectors, ife sector[variable].lotag 65534
    {
        set index sector[variable].hitag
        ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 7
        ife verbose 1
        {
            qsprintf 0 27 sector[variable].hitag
            quote 0
        }
    }

// doortiles
    for variable allsprites
    {
        set flag 0
        set input .picnum
        state doortile_identify
        ife flag 1, ifn .hitag 0
        {
            set index .hitag
            ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 8
            ife verbose 1
            {
                qsprintf 0 28 .hitag
                quote 0
            }
        }
    }
    for variable allwalls
    {
        set flag 0
        set input wall[variable].picnum
        state doortile_identify
        set input wall[variable].overpicnum
        state doortile_identify
        ife flag 1, ifn wall[variable].lotag 0, ifn wall[variable].hitag 0
        {
            set index wall[variable].hitag
            ifge index 0 ifle index MAXSOUNDS set usedSounds[index] 8
            ife verbose 1
            {
                qsprintf 0 28 wall[variable].hitag
                quote 0
            }
        }
    }

    quote 106
ends

defstate sound_dump
    quote 107

    for variable range MAXSOUNDS
        ifn usedSounds[variable] 0
        {
            qsprintf 0 1 variable
            quote 0
        }

    quote 108
ends

onevent EVENT_KEYS2D
    ifeitherctrl
    {
        ifhitkey KEY_V // find
        {
            state tile_search
            state sound_search
            quote 109
        }
        ifhitkey KEY_D // dump
        {
            state tile_dump
            state sound_dump
            quote 110
        }
    }
endevent


code:
/*
--------------------------------------------------------------------------------
Duke Nukem 3D SplitScreen mod
Beta 1
By Bloodclaw

Modified from original for use with EDuke32 SVN.
Requires an EDuke32 binary built with SPLITSCREEN_MOD_HACKS preprocessor flag.
Usage: eduke32 -mx splitscr.con -q2
--------------------------------------------------------------------------------
*/

// Key name definitions
definegamefuncname 11 P2_Move_Forward
definegamefuncname 12 P2_Move_Backward
definegamefuncname 13 P2_Turn_Left
definegamefuncname 14 P2_Turn_Right
definegamefuncname 17 P2_Aim_Up
definegamefuncname 18 P2_Aim_Down
definegamefuncname 19 P2_Fire
definegamefuncname 20 P2_Open
definegamefuncname 21 P2_Jump
definegamefuncname 22 P2_Crouch
definegamefuncname 23 P2_Inventory
definegamefuncname 24 P2_Inventory_Left
definegamefuncname 25 P2_Inventory_Right
definegamefuncname 26 P2_Quick_Kick
definegamefuncname 27 P2_Previous_Weapon
definegamefuncname 28 P2_Next_Weapon

gamevar pid 1 0 // This hold player 2 id
gamevar pnum 0 0 // This is set to player 2 sprite number

// Temp variables
gamevar tmp 0 0
gamevar px 0 0 // Player (both 1 and 2) X coordinate
gamevar py 0 0 // Player Y coordinate
gamevar pz 0 0 // Player Z coordinate
gamevar psect 0 0 // Player sector number
gamevar pang 0 0 // Player angle
gamevar phoriz 0 0 // Player vertical angle
gamevar phorizoff 0 0 // Something similar
gamevar pangcos 0 0 // Cosinus of player angle (used for player 2 movements)
gamevar pangsin 0 0 // Sinus of player angle
gamevar pinput 0 0 // Set to input, used in the PROCESSINPUT event

gamevar pcrosshair 0 0 // Do you like crosshairs? Game options will tell.
gamevar crossscale 0 0 // crosshair scale
gamevar pweapon 0 0 // Player weapon

gamevar p1heat 0 0 // Common night vision googles
gamevar p2heat 0 0

// Crosshair need to be redone for two players
onevent EVENT_DISPLAYCROSSHAIR
  setvar RETURN -1
endevent

define KNEE_WEAPON 0
define PISTOL_WEAPON 1
define SHOTGUN_WEAPON 2
define CHAINGUN_WEAPON 3
define RPG_WEAPON 4
define HANDBOMB_WEAPON 5
define SHRINKER_WEAPON 6
define DEVISTATOR_WEAPON 7
define TRIPBOMB_WEAPON 8
define FREEZE_WEAPON 9
define HANDREMOTE_WEAPON 10
define GROW_WEAPON 11

// Next and previous weapon actions will never pick the expander.
onevent EVENT_NEXTWEAPON
  getplayer[THISACTOR].curr_weapon pweapon
  ifvare pweapon HANDBOMB_WEAPON  // XXX: HANDREMOTE_WEAPON?
  {
      getplayer[THISACTOR].subweapon tmp
      andvar tmp 0xfffff7ff
      setplayer[THISACTOR].subweapon tmp
  }
  else ifvare pweapon SHRINKER_WEAPON
  {
    ifvarg player[THISACTOR].ammo_amount GROW_WEAPON 0
      setvar RETURN SHRINKER_WEAPON  // select expander
    // else select next weapon
  }
endevent

onevent EVENT_PREVIOUSWEAPON
  getplayer[THISACTOR].curr_weapon pweapon

  ifvare pweapon DEVISTATOR_WEAPON
  {
    ifvarg player[THISACTOR].ammo_amount GROW_WEAPON 0
    {
      getplayer[THISACTOR].subweapon tmp
      orvar tmp 0x800
      setplayer[THISACTOR].subweapon tmp
      // select previous weapon
    }
  }
  ifvare pweapon GROW_WEAPON
  {
    ifvarg player[THISACTOR].ammo_amount SHRINKER_WEAPON 0
      setvar RETURN SHRINKER_WEAPON  // select shrinker
    // else select previous weapon
  }
endevent

// Disable all the following keys, need room for player 2
onevent EVENT_LOOKUP // Move Forward
  setvar RETURN -1
endevent

onevent EVENT_LOOKDOWN // Move Backward
  setvar RETURN -1
endevent

onevent EVENT_LOOKLEFT // Turn Left
  setvar RETURN -1
endevent

onevent EVENT_LOOKRIGHT // Turn Right
  setvar RETURN -1
endevent

onevent EVENT_AIMUP // Aim Up
  setvar RETURN -1
endevent

onevent EVENT_AIMDOWN // Aim Down
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY1 // Fire
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY2 // Open
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY3 // Jump
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY4 // Crouch
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY5 // Inventory
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY6 // Inventory Left
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY7 // Inventory Right
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY8 // Quick Kick
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY9 // Previous Weapon
  setvar RETURN -1
endevent

onevent EVENT_WEAPKEY10 // Next Weapon
  setvar RETURN -1
endevent

// Controls for player 2
onevent EVENT_PROCESSINPUT // I had to use this event in case player 1 die
  getinput[THISACTOR].bits pinput

  ifvarand pinput 8
  {
    setinput[pid].bits 8
    ifvarl phoriz 199 addvar phoriz 14
    setplayer[pid].horiz phoriz // For some reasons, only setting the bits won't work
  }
  ifvarand pinput 16
  {
    setinput[pid].bits 16
    ifvarg phoriz 1  subvar phoriz 14
    setplayer[pid].horiz phoriz
  }
  ifvarand pinput 64
  {
    setinput[pid].avel -20
  }
  ifvarand pinput 128
  {
    setinput[pid].avel 20
  }
  ifvarand pinput 8192 // This block and the following one are for moving forward and backward, with X and Y speeds set with help of sinus and cosinus
  {
    setvar RETURN -1
    getplayer[pid].i pnum
    getactor[pnum].ang pang
    cos pangcos pang
    mulvar pangcos 10
    divvar pangcos 64
    sin pangsin pang
    mulvar pangsin 10
    divvar pangsin 64
    setinput[pid].fvel pangcos
    setinput[pid].svel pangsin
  }
  ifvarand pinput 16384
  {
    setvar RETURN -1
    getplayer[pid].i pnum
    getactor[pnum].ang pang
    cos pangcos pang
    mulvar pangcos -10
    divvar pangcos 64
    sin pangsin pang
    mulvar pangsin -10
    divvar pangsin 64
    setinput[pid].fvel pangcos
    setinput[pid].svel pangsin
  }
  // Following code come from Eduke32 wiki
  shiftvarr pinput 8
  andvar pinput 0xF
  switch pinput
  case 1:
    setinput[pid].bits 4
    break
  case 2:
    setinput[pid].bits 536870912
    break
  case 3:
    setinput[pid].bits 1
    break
  case 4:
    setinput[pid].bits 2
    break
  case 5:
    setinput[pid].bits 1073741824
    break
  case 6:
    setinput[pid].bits 1048576
    break
  case 7:
    setinput[pid].bits 134217728
    break
  case 8:
    setinput[pid].bits 4194304
    break
  case 9:
    setinput[pid].bits 2816
    break
  case 10:
    setinput[pid].bits 3072
    break
  endswitch
endevent

// NOTE: status bar is displayed for both players (EDuke32 splitscreen hack)

// orientation bits for the crosshairs for left/right split
define ORIENT 1032  // 26

// gametext args
define P1X 4
define P2X 164

gamevar arg_player_id 0 0

state show_player_view
  getplayer[arg_player_id].posx px
  getplayer[arg_player_id].posy py
  getplayer[arg_player_id].posz pz
  getplayer[arg_player_id].ang pang
  getplayer[arg_player_id].horiz phoriz
  getplayer[arg_player_id].horizoff phorizoff
  addvarvar phoriz phorizoff

  // simulate corresponding part in G_DrawRooms (almost)
  ifvarvare player[arg_player_id].spritebridge 0
  {
    setvarvar tmp player[arg_player_id].truecz
    addvar tmp 1024
    ifvarvarl pz tmp
      setvarvar pz tmp
    else
    {
      setvarvar tmp player[arg_player_id].truefz
      subvar tmp 1024
      ifvarvarg pz tmp
        setvarvar pz tmp
    }
  }

  getplayer[arg_player_id].cursectnum psect

  ifvarg psect -1
  {
    getuserdef .screen_size tmp

    ifvare tmp 0
    {
        // above/below split: first player is above
        ifvare arg_player_id 0
            showviewunbiased px py pz pang phoriz psect 0 0 319 100
        else
            showviewunbiased px py pz pang phoriz psect 0 100 319 199
    }
    else
    {
        // side by side split: first player is left
        ifvare arg_player_id 0
            showviewunbiased px py pz pang phoriz psect 0 0 160 199
        else
            showviewunbiased px py pz pang phoriz psect 160 0 319 199
    }
  }
ends

onevent EVENT_DISPLAYROOMS
    setvar RETURN 1  // don't draw them

    // an EDuke32 hack now:
//    setplayer[THISACTOR].rotscrnang 0 // (almost) Prevent the screen rotation when player 1 die

  // DRAW THE PLAYER VIEWS!
  setvar arg_player_id 0
  state show_player_view
  setvar arg_player_id 1
  state show_player_view

// Draw crosshairs if they are enabled
  getuserdef[THISACTOR].crosshair pcrosshair
  ifvare pcrosshair 1
  {
      getuserdef .crosshairscale crossscale
      shiftvarl crossscale 16, divvar crossscale 100

      getuserdef .screen_size tmp
      ifvarn tmp 0
      {
          // left/right

          rotatesprite 80 100 crossscale 0 CROSSHAIR 0 0 ORIENT 0 0 xdim ydim
          rotatesprite 240 100 crossscale 0 CROSSHAIR 0 0 ORIENT 0 0 xdim ydim
      }
      else
      {
          // above/below
          setvar tmp 8
          rotatesprite 160 50 crossscale 0 CROSSHAIR 0 0 tmp 0 0 xdim ydim
          rotatesprite 160 150 crossscale 0 CROSSHAIR 0 0 tmp 0 0 xdim ydim
      }
  }

  // NOTE: weapons are drawn for both players now (EDuke32 hack)
endevent