├── sa2lua ├── .gitignore ├── objhelp │ ├── 6C0F80.txt │ ├── 6CFBF0.txt │ ├── 6C4480.txt │ ├── 6C4E90.txt │ ├── 6D9310.txt │ ├── 6C6180.txt │ ├── 6C5ED0.txt │ ├── 6D3C00.txt │ ├── 4FF990.txt │ ├── 6E5620.txt │ ├── 6D4EA0.txt │ ├── 4F8F90.txt │ ├── 6C7C10.txt │ ├── 6C8EF0.txt │ ├── 6DB030.txt │ ├── 6DBB90.txt │ ├── 501530.txt │ ├── 6DCDC0.txt │ └── 6E6EB0.txt ├── hook.bin ├── linedraw.bin ├── misc │ ├── ltphook.lua │ └── objlistcsv.lua ├── assemble.bat ├── teleport │ ├── stage25.loc │ ├── stage0.loc │ ├── stage44.loc │ ├── stage22.loc │ ├── stage28.loc │ ├── stage13.loc │ └── stage10.loc ├── functions.csv ├── physpresets.csv ├── init.lua ├── charsel.lua ├── linedraw.asm ├── bitwise.lua ├── objectlist.csv ├── stagelist.csv ├── lvlmixer.lua ├── lthook.lua ├── setexport.lua ├── remote.lua ├── physpresets.lua ├── infodisp.lua ├── spawnedlist.lua ├── objenum.lua ├── teleport.lua ├── callfunc.lua ├── objfile.lua ├── tweaks.lua ├── common.lua ├── hook.asm ├── linedraw.lua ├── objchain.lua ├── objspawn.lua └── objkeys.lua ├── Sample Object Lists ├── More switches in Aquatic Mine.bin ├── README.TXT ├── Load in City Escape.csv ├── Load in Final Rush.csv ├── More switches in Aquatic Mine.csv ├── Load in Metal Harbor.csv ├── Final Rush 2.csv ├── Dash Panel Loop (test level).csv ├── Tons of Springs.csv ├── Springs and Crates.csv ├── Metal Harbor Autopilot.csv ├── Cheat Engine.csv ├── Test Level Rail Rings.csv ├── Minecraft Village.csv ├── More Springs.csv └── Plant more trees in City Escape.csv └── README.md /sa2lua/.gitignore: -------------------------------------------------------------------------------- 1 | lastPID.txt -------------------------------------------------------------------------------- /sa2lua/objhelp/6C0F80.txt: -------------------------------------------------------------------------------- 1 | This is a ring. Big surprise there, right? :-) -------------------------------------------------------------------------------- /sa2lua/hook.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flarn2006/SA2CheatTable/HEAD/sa2lua/hook.bin -------------------------------------------------------------------------------- /sa2lua/linedraw.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flarn2006/SA2CheatTable/HEAD/sa2lua/linedraw.bin -------------------------------------------------------------------------------- /sa2lua/objhelp/6CFBF0.txt: -------------------------------------------------------------------------------- 1 | This is a genuine Dash Panel, courtesy of Dimps™ 2 | 3 | X scale = acceleration -------------------------------------------------------------------------------- /sa2lua/objhelp/6C4480.txt: -------------------------------------------------------------------------------- 1 | This is a spring of the type normally found on the floor. 2 | 3 | Y scale = bounce height -------------------------------------------------------------------------------- /sa2lua/objhelp/6C4E90.txt: -------------------------------------------------------------------------------- 1 | This is a taller spring, normally bouncing you at an angle. 2 | 3 | Y scale = bounce height -------------------------------------------------------------------------------- /sa2lua/objhelp/6D9310.txt: -------------------------------------------------------------------------------- 1 | This is a wider spring, about the size of three springs lined up horizontally. 2 | 3 | Y scale = bounce height -------------------------------------------------------------------------------- /Sample Object Lists/More switches in Aquatic Mine.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flarn2006/SA2CheatTable/HEAD/Sample Object Lists/More switches in Aquatic Mine.bin -------------------------------------------------------------------------------- /sa2lua/objhelp/6C6180.txt: -------------------------------------------------------------------------------- 1 | This is a group of rings that automatically spawns in a circle. 2 | 3 | X scale = Radius of circle 4 | Y scale = Height of arc (0 for line) 5 | Z scale = Number of rings -------------------------------------------------------------------------------- /sa2lua/objhelp/6C5ED0.txt: -------------------------------------------------------------------------------- 1 | This is a group of rings that automatically spawn in a line or an arc. 2 | 3 | X scale = Distance between rings 4 | Y scale = Height of arc (0 for line) 5 | Z scale = Number of rings -------------------------------------------------------------------------------- /sa2lua/objhelp/6D3C00.txt: -------------------------------------------------------------------------------- 1 | This is an axle with two rotating spiked balls. 2 | 3 | X scale = controls diameter (set to -1 for a single ball) 4 | Y scale = controls speed of rotation (set to -1 to disable rotation) -------------------------------------------------------------------------------- /sa2lua/misc/ltphook.lua: -------------------------------------------------------------------------------- 1 | debugProcess() 2 | debug_setBreakpoint(0x44C350) 3 | 4 | function debugger_onBreakpoint() 5 | print(readString(ECX) .. " : " .. num2hex(EDX)); 6 | debug_continueFromBreakpoint(co_run) 7 | return 1 8 | end -------------------------------------------------------------------------------- /sa2lua/objhelp/4FF990.txt: -------------------------------------------------------------------------------- 1 | This is a GUN Hunter (biped) robot. 2 | 3 | X Scale = Type 4 | 0 - Basic Hunter 5 | 1 - Hovering Hunter 6 | 2 - Laser Hunter 7 | 3 - Hovering Laser Hunter 8 | 4 - Freeze Hunter 9 | 5 - Shield Hunter 10 | 11 | Y Scale = Projectile Speed -------------------------------------------------------------------------------- /sa2lua/objhelp/6E5620.txt: -------------------------------------------------------------------------------- 1 | This is a pulley (one of those handles that takes you up and down.) 2 | 3 | X rotation = set to 1 to start at bottom, go up, and return 4 | 5 | X scale = distance to go down (float, multiples of 20) 6 | Y scale = distance to start at (float, 0-2) -------------------------------------------------------------------------------- /Sample Object Lists/README.TXT: -------------------------------------------------------------------------------- 1 | Many of these files specify a specific level to be loaded in. 2 | If you're not in that level when you load it, the game will most likely crash. 3 | 4 | The ones that don't specify a level should be loaded relative to the player. 5 | The ones that do should not be. -------------------------------------------------------------------------------- /sa2lua/objhelp/6D4EA0.txt: -------------------------------------------------------------------------------- 1 | This is a rocket which transports you to another part of the level. 2 | 3 | X rotation = switch ID (0 starts enabled) 4 | 5 | X scale = X coordinate of destination (float) 6 | Y scale = Y coordinate of destination (float) 7 | Z scale = Z coordinate of destination (float) -------------------------------------------------------------------------------- /sa2lua/objhelp/4F8F90.txt: -------------------------------------------------------------------------------- 1 | This is a GUN Hornet (annoying homing bomb) robot. 2 | 3 | X Rotation = Laser trail length 4 | Y Rotation = Delay between laser shots 5 | 6 | X Scale = Type 7 | 0 - 3 bomb variant 8 | 1 - 6 bomb variant 9 | 2 - 8 bomb variant 10 | 3 - 3 laser variant 11 | 12 | Y Scale = Laser speed -------------------------------------------------------------------------------- /sa2lua/objhelp/6C7C10.txt: -------------------------------------------------------------------------------- 1 | This is a standard item box. 2 | 3 | X scale = item to give (float) 4 | 5 | 0 - Speed Shoes 6 | 1 - 5 Rings 7 | 2 - Extra Life 8 | 3 - 10 Rings 9 | 4 - 20 Rings 10 | 5 - Bubble Shield 11 | 6 - Bomb 12 | 7 - First Aid Kit 13 | 8 - Magnetic Shield 14 | 9 - Empty 15 | 10 - Invincibility -------------------------------------------------------------------------------- /sa2lua/objhelp/6C8EF0.txt: -------------------------------------------------------------------------------- 1 | This is a floating item box. 2 | 3 | X scale = item to give (float) 4 | 5 | 0 - Speed Shoes 6 | 1 - 5 Rings 7 | 2 - Extra Life 8 | 3 - 10 Rings 9 | 4 - 20 Rings 10 | 5 - Bubble Shield 11 | 6 - Bomb 12 | 7 - First Aid Kit 13 | 8 - Magnetic Shield 14 | 9 - Empty 15 | 10 - Invincibility -------------------------------------------------------------------------------- /sa2lua/objhelp/6DB030.txt: -------------------------------------------------------------------------------- 1 | This is a balloon which contains an item. 2 | 3 | X scale = item to give (float) 4 | 5 | 0 - Speed Shoes 6 | 1 - 5 Rings 7 | 2 - Extra Life 8 | 3 - 10 Rings 9 | 4 - 20 Rings 10 | 5 - Bubble Shield 11 | 6 - Bomb 12 | 7 - First Aid Kit 13 | 8 - Magnetic Shield 14 | 9 - Empty 15 | 10 - Invincibility -------------------------------------------------------------------------------- /sa2lua/assemble.bat: -------------------------------------------------------------------------------- 1 | rem - This requires nasm (Netwide Assembler) to be in your path directory. 2 | rem - If you don't know what that means, you probably don't need this (no offense!) 3 | @echo off 4 | for %%F in (*.asm) do ( 5 | @nasm -o %%~nF.bin %%F 6 | if errorlevel 1 goto error 7 | ) 8 | goto end 9 | :error 10 | pause 11 | :end -------------------------------------------------------------------------------- /sa2lua/teleport/stage25.loc: -------------------------------------------------------------------------------- 1 | 5 2 | Red Chamber 3 | 870 4 | -10 5 | 870 6 | Pyramid Core 7 | 106.74533081055 8 | 175 9 | 108.95654296875 10 | Blue Chamber 11 | 866.2255859375 12 | -10 13 | -863.18206787109 14 | Green Chamber 15 | -865.48565673828 16 | -10 17 | 865.91418457031 18 | Lost Chao Room 19 | -838.49560546875 20 | -65 21 | -844.30572509766 22 | -------------------------------------------------------------------------------- /sa2lua/teleport/stage0.loc: -------------------------------------------------------------------------------- 1 | 5 2 | Start 3 | -1.6612516641617 4 | 0 5 | -4.2242112159729 6 | Top of steepest slope 7 | -149.90444946289 8 | 193.18516540527 9 | 422.60388183594 10 | Top of measuring pillar 11 | 389.63674926758 12 | 500 13 | -287.01171875 14 | Beginning of rail 15 | 506.70904541016 16 | 780 17 | -447.66891479492 18 | Inside the pit 19 | 61.28116607666 20 | -200 21 | -121.72701263428 22 | -------------------------------------------------------------------------------- /sa2lua/objhelp/6DBB90.txt: -------------------------------------------------------------------------------- 1 | This is a giant weight which rises into the air and drops periodically. 2 | 3 | Y rotation = actually controls Y rotation 4 | Z rotation = switch ID 5 | X scale = actually controls X scale 6 | Y scale = height of movement 7 | Z scale = actually controls Z scale 8 | 9 | X rotation: 10 | 0 - Normal behavior 11 | 1 - Trap (drops when nearby, then raises) 12 | 2 - Switch-controlled -------------------------------------------------------------------------------- /sa2lua/functions.csv: -------------------------------------------------------------------------------- 1 | 46F680,LoadObject,-,-,-,-,?,routine,&&name 2 | 46F610,LoadObject2,&&name,-,list,-,-,routine,flags 3 | 73AA70,LoadEmeraldManager,-,-,-,-,-,-,(none) 4 | 442CF0,PlayMusic,-,-,-,-,-,&&song,(none) 5 | 46B110,KillCharacter,-,player,-,-,-,-,(none) 6 | 44C350,LoadTexturePack,-,-,&&name,&&TexList,-,-,(none) 7 | 531B10,SpawnAllChaoInGarden,-,-,-,-,-,-,(none) 8 | 47BD30,LoadLandManager,-,-,-,-,-,-,&&LandTable -------------------------------------------------------------------------------- /sa2lua/objhelp/501530.txt: -------------------------------------------------------------------------------- 1 | This is a GUN Beetle (floating) robot. 2 | 3 | Z rotation = frequency of "hovering" 4 | 5 | X scale = type of robot 6 | 7 | 0 - Basic 8 | 1 - Basic (moves slowly) 9 | 2 - Electric (Y scale controls shield drop time) 10 | 3 - Electric (moves slowly when shield is down) 11 | 4 - Gun 12 | 5 - Cloaked (appears when you get close) 13 | 6 - Spring 14 | 7 - Bomb (Y scale controls delay between bombs) 15 | -------------------------------------------------------------------------------- /Sample Object Lists/Load in City Escape.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | BOARDCOL,5EA210,2,2,0,-443.94769287109,679.96478271484,0,0,0,1,1,1 3 | HAMMER,5EA9C0,6,2,-1.0181605815887,-1057.0260009766,1584.1004638672,0,0,0,1,1,1 4 | 3SPRING,6D9310,2,2,0.83916330337524,-996.5576171875,1513.8471679688,0,8000,0,1,1,1 5 | BIGJUMP ,6D7130,6,2,1.8023314476013,-958.02600097656,1616.3760986328,0,8000,0,10,1,1 6 | -------------------------------------------------------------------------------- /Sample Object Lists/Load in Final Rush.csv: -------------------------------------------------------------------------------- 1 | Name,Routine,Flags,List,XPos,YPos,ZPos,XRot,YRot,ZRot,XScl,YScl,ZScl 2 | FRSTAGE,4B31D0,6,2,3197.2236328125,-931.01037597656,83.718925476074,0,4000,0,1,1,1 3 | 3SPRING,6D9310,2,2,3197.0756835938,-931.01037597656,118.44876098633,0,8000,0,1,1,1 4 | GLIND_B,4B1B20,6,2,3195.3796386719,-763.21490478516,137.76788330078,0,4000,0,1,1,1 5 | ITEMBOX ,6C7C10,2,2,3195.0104980469,-683.21490478516,213.18792724609,0,8000,0,2,2565,1 6 | -------------------------------------------------------------------------------- /sa2lua/teleport/stage44.loc: -------------------------------------------------------------------------------- 1 | 6 2 | Start 3 | 0 4 | 620 5 | -0.40000152587891 6 | Capsule Planet 7 | -341.35601806641 8 | 2229.38671875 9 | 547.81018066406 10 | Spherical Planet 11 | -386.95013427734 12 | 1487.2365722656 13 | -594.37951660156 14 | "Holy" Planet 15 | 533.41973876953 16 | 2291.7180175781 17 | -558.68353271484 18 | Inverted Towers 19 | 1012.9026489258 20 | 4099 21 | -46.688007354736 22 | "ynoclab thgil eulb" 23 | 391.14453125 24 | 197.99786376953 25 | 1164.6260986328 26 | -------------------------------------------------------------------------------- /sa2lua/objhelp/6DCDC0.txt: -------------------------------------------------------------------------------- 1 | This is a generic switch, found in many levels. 2 | 3 | Spawned switches will not work if spawned on top of 4 | the player; therefore you must spawn switches by 5 | replacing an existing object (such as a movable cylinder) 6 | or duplicating a switch using the keyboard controls. 7 | 8 | X Scale = switch behavior 9 | 10 | 0 - toggle on/off 11 | 1 - momentary push (left over from SA1; kind of weird in SA2) 12 | 2 - timer switch (Z Scale controls delay, 30 units = 1 second) 13 | 3 - push once, stays on 14 | 15 | Y Scale = switch ID -------------------------------------------------------------------------------- /sa2lua/physpresets.csv: -------------------------------------------------------------------------------- 1 | Name,HangTime,HorizSpeedCap,VertSpeedCap,SpeedMod,InitJumpSpeed,AddWhileJumpHeld,GroundAccel,AirAccel,GroundDecel,BrakeSpeed,AirBrakeSpeed,AirDecel,RollingDecel,Gravity 2 | Default (S/S),60,16,16,3,1.66,0.076,0.05,0.031,-0.06,-0.18,-0.17,-0.028,-0.008,0.08 3 | Default (T/E),16,16,16,1,2.6,0.19,0.1,0.031,-0.1,-0.18,-0.17,-0.028,-0.014,0.2 4 | Default (K/R),60,16,16,2.5,1.66,0.076,0.05,0.031,-0.06,-0.18,-0.17,-0.028,-0.008,0.08 5 | No Friction,60,16,16,3,1.66,0.076,0.05,0.031,0,0,0,0,0,0.08 6 | Inverted,60,16,16,3,1.66,0.076,-0.05,-0.031,-0.06,-0.18,-0.17,-0.028,-0.008,0.08 7 | -------------------------------------------------------------------------------- /sa2lua/objhelp/6E6EB0.txt: -------------------------------------------------------------------------------- 1 | This is an invisible object which awards bonus points when you go through it. 2 | 3 | X rotation = delay (in frames) 4 | XYZ scale = size of collision detection 5 | 6 | Y rotation: 7 | 0 - No bonus awarded 8 | 1 - 100 points awarded ("Good!") 9 | 2 - 200 points awarded ("Nice!") 10 | 3 - 300 points awarded ("Great!") 11 | 4 - 400 points awarded ("Jammin'!") 12 | 5 - 500 points awarded ("Cool!") 13 | 6 - 600 points awarded ("Radical!") 14 | 7 - 800 points awarded ("Tight!") 15 | 8 - 1000 points awarded ("Awesome!") 16 | 9 - 1500 points awarded ("Extreme!") 17 | A - 2000 points awarded ("Perfect!") -------------------------------------------------------------------------------- /sa2lua/teleport/stage22.loc: -------------------------------------------------------------------------------- 1 | 8 2 | Start 3 | 0 4 | -30 5 | 340 6 | H.S.W.T. #1 Entrance 7 | -2025.1947021484 8 | 479 9 | -402.48913574219 10 | First Artificial Chaos P-100 11 | -4406.9584960938 12 | -828 13 | -2122.2097167969 14 | H.S.W.T. #2 Entrance 15 | -5961.3608398438 16 | -1238 17 | -3204.3034667969 18 | Light Dash in SPAAAACE 19 | -9716.49609375 20 | -1352 21 | -5510.2260742188 22 | H.S.W.T. #3 / Gold Beetle 23 | -10949.840820313 24 | -1652 25 | -4434.8251953125 26 | Narrow Path with Spikes 27 | -10951.301757813 28 | -1067 29 | -3777.5461425781 30 | Tetris Blocks 31 | -9801.455078125 32 | -1027 33 | -2902.7512207031 34 | -------------------------------------------------------------------------------- /sa2lua/teleport/stage28.loc: -------------------------------------------------------------------------------- 1 | 9 2 | Start (0,0,0) 3 | 0 4 | 0 5 | 0 6 | Bounce Bracelet 7 | -2562.8459472656 8 | -1835 9 | -8171.6298828125 10 | Locked Door #1 11 | -2559.8220214844 12 | -1670 13 | -9056.845703125 14 | Behind Locked Door #1 15 | -2559.7817382813 16 | -1679.1489257813 17 | -9259.3154296875 18 | Locked Door #2 19 | -2562.98046875 20 | -2250 21 | -11917.388671875 22 | Key #2 23 | -523.27087402344 24 | -2290 25 | -11927.72265625 26 | Behind Locked Door #2 27 | -2586.267578125 28 | -2259.6350097656 29 | -12249.37890625 30 | After Long Hallway 31 | -2556.9172363281 32 | -4260 33 | -17499.015625 34 | Goal Ring Platform 35 | 918.07421875 36 | -4060 37 | -22208.25390625 38 | -------------------------------------------------------------------------------- /sa2lua/teleport/stage13.loc: -------------------------------------------------------------------------------- 1 | 10 2 | Start 3 | 0 4 | -258.51223754883 5 | 406.49468994141 6 | Off the board 7 | -1553.0478515625 8 | -6260 9 | 9356.125 10 | Gold Beetle 11 | 5939.4482421875 12 | -10689.998046875 13 | 4394.642578125 14 | Loop 15 | 7706.5678710938 16 | -11751.255859375 17 | 5434.7631835938 18 | Down the building... 19 | 7619.4755859375 20 | -13533.970703125 21 | 5434.5 22 | Bottom of building 23 | 7620.57421875 24 | -14555 25 | 5757.7431640625 26 | Magic Hands 27 | 7630.94921875 28 | -14605 29 | 6082.7309570313 30 | Upper route (after building) 31 | 7642.3940429688 32 | -14355 33 | 6289.1884765625 34 | Before the truck 35 | 6434.8159179688 36 | -15915 37 | 9113.68359375 38 | GOAL 39 | 3952.5173339844 40 | -22175 41 | 16038.890625 42 | -------------------------------------------------------------------------------- /sa2lua/misc/objlistcsv.lua: -------------------------------------------------------------------------------- 1 | function SaveObjectList() 2 | local objlist = readInteger(0x1DDE268) 3 | local count = readInteger(objlist) 4 | objlist = readInteger(objlist + 0x04) 5 | 6 | local stage = readBytes(0x1934B70, 1, false) 7 | local file = io.open("objlist"..stage..".csv", "w+") 8 | file:write("name,flags,list,routine\n") 9 | 10 | for i=0,count-1 do 11 | local name = readString(readInteger(objlist + 0x0C), 64) 12 | local flags = readBytes(objlist, 1, false) 13 | local list = readBytes(objlist + 0x01, 1, false) 14 | local routine = readInteger(objlist + 0x08) 15 | if name == nil then name = "???" end 16 | file:write(name..","..num2hex(flags)..","..num2hex(list)..","..num2hex(routine).."\n") 17 | objlist = objlist + 0x10 18 | end 19 | 20 | file:close() 21 | end -------------------------------------------------------------------------------- /sa2lua/teleport/stage10.loc: -------------------------------------------------------------------------------- 1 | 10 2 | Past the "intro" part 3 | 147.54400634766 4 | -149 5 | -1702.2590332031 6 | First homing attack section 7 | 2120.7136230469 8 | -270 9 | -2909.6638183594 10 | Runway 11 | 2084.1376953125 12 | -160 13 | -4289.3178710938 14 | Second homing attack section 15 | 4294.0483398438 16 | -268.9992980957 17 | -9387.7607421875 18 | Missile launch platform 19 | 4755.6401367188 20 | -181 21 | -9854.9091796875 22 | Lower handle 23 | 4906.1733398438 24 | -31 25 | -10357.901367188 26 | Upper handle 27 | 5061.6821289063 28 | 219 29 | -10214.209960938 30 | GUN Top Secret Midair Vent Shaft 31 | 5355.4018554688 32 | 2199.7006835938 33 | -10214.796875 34 | GOAL Platform 35 | 8753.3056640625 36 | -170 37 | -10258.810546875 38 | Lost Chao Platform 39 | 1709.8000488281 40 | -170 41 | -6411.0922851563 42 | -------------------------------------------------------------------------------- /Sample Object Lists/More switches in Aquatic Mine.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | Switch,6DCDC0,2,2,-1.7793312072754,130.01452636719,320.59197998047,0,0,0,0,1,0 3 | Switch,6DCDC0,2,2,10.28805065155,-79.985458374023,248.60990905762,0,0,0,0,2,0 4 | Switch,6DCDC0,2,2,-249.46090698242,-79.985458374023,-1.7803726196289,0,0,0,0,2,0 5 | Switch,6DCDC0,2,2,249.34049987793,-79.985458374023,-71.712600708008,0,0,0,0,2,0 6 | Switch,6DCDC0,2,2,-314.52880859375,130.01452636719,-4.7193517684937,0,0,0,0,1,0 7 | Switch,6DCDC0,2,2,-98.992256164551,130.01452636719,-318.71026611328,0,0,0,0,1,0 8 | Switch,6DCDC0,2,2,322.82434082031,130.01452636719,11.787769317627,0,0,0,0,1,0 9 | Switch,6DCDC0,2,2,8.8874988555908,-249.98547363281,178.42597961426,0,0,0,0,3,0 10 | Switch,6DCDC0,2,2,-181.92041015625,-249.98547363281,0.31294441223145,0,0,0,0,3,0 11 | Switch,6DCDC0,2,2,-2.5539970397949,-233.98547363281,-109.08543395996,0,1000,0,0,3,0 12 | -------------------------------------------------------------------------------- /Sample Object Lists/Load in Metal Harbor.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | MSBRIMINI,6F67A0,6,2,1725.5620117188,-220.5,-2148.7458496094,0,4000,0,0,0,0 3 | ROCKET ,6D4EA0,6,2,1742.5933837891,-214.5,-2149.3298339844,0,FFFFD24E,0,2100,315,-1408 4 | MSBRILONG,6F6740,6,2,2099.7316894531,216.2449798584,-1444.8530273438,0,0,0,0,0,0 5 | E KUMI,501530,2,2,2131.310546875,246.2449798584,-1245.6451416016,0,E2AD,0,0,0,0 6 | E KUMI,501530,2,2,2172.09765625,258.17245483398,-1277.158203125,0,1B1F,0,0,0,0 7 | E KUMI,501530,2,2,2191.2683105469,280.62875366211,-1310.564453125,0,45B5,0,0,0,0 8 | E KUMI,501530,2,2,2207.4675292969,297.41937255859,-1324.7016601563,0,341,0,0,0,0 9 | E KUMI,501530,2,2,2233.5541992188,306.57250976563,-1334.4860839844,0,FF24,0,0,0,0 10 | ITEMBOXAIR ,6C8EF0,2,2,2267.3159179688,328.00796508789,-1337.8861083984,0,E5CC,0,2,9480,1 11 | MSBRIMINI,6F67A0,6,2,2293.9877929688,298.00796508789,-1373.3240966797,0,E5CC,0,2,0,0 12 | ROCKET ,6D4EA0,6,2,2280.1901855469,308.00796508789,-1354.7393798828,0,FFFF85D8,0,0,500,0 13 | -------------------------------------------------------------------------------- /sa2lua/init.lua: -------------------------------------------------------------------------------- 1 | -- This file is run when the cheat table is first loaded. 2 | 3 | -- Common stuff 4 | dofile("sa2lua/common.lua") 5 | 6 | -- Functions for the tweaks dialog 7 | dofile("sa2lua/tweaks.lua") 8 | 9 | -- Functions for saved locations dialog 10 | dofile("sa2lua/teleport.lua") 11 | 12 | -- Functions for object editing dialog 13 | dofile("sa2lua/linedraw.lua") 14 | dofile("sa2lua/objchain.lua") 15 | dofile("sa2lua/objspawn.lua") 16 | dofile("sa2lua/remote.lua") 17 | 18 | -- Functions for the character select dialog 19 | dofile("sa2lua/charsel.lua") 20 | 21 | -- Functions for the Call Function dialog 22 | dofile("sa2lua/callfunc.lua") 23 | 24 | -- Functions for the Level Mixer dialog 25 | dofile("sa2lua/lvlmixer.lua") 26 | 27 | -- Functions for the Land Table hook 28 | dofile("sa2lua/lthook.lua") 29 | 30 | -- Live Edit Mode 31 | dofile("sa2lua/objkeys.lua") 32 | 33 | -- Physics Presets dialog 34 | dofile("sa2lua/physpresets.lua") 35 | 36 | -- Info Display 37 | dofile("sa2lua/infodisp.lua") 38 | 39 | -- Initialization 40 | 41 | timer_setEnabled(ObjectChain_Update, true) 42 | form_show(Tools) -------------------------------------------------------------------------------- /sa2lua/charsel.lua: -------------------------------------------------------------------------------- 1 | function ShowCharSelectClick(sender) 2 | form_show(CharSelect) 3 | end 4 | 5 | function SelectCharClick(sender) 6 | local charload = {0x716E00, 0x740EB0, 0x728110, 0x717360, 0x740C50, 0x728460, 0x74CF00, 0x73C220, 0x7170E0, 0x717640, 0x7288B0, 0x728B60, 0x741110, 0x7412F0} 7 | local p1addr = {0x43D652, 0x43D664, 0x43D677, 0x43D68A, 0x43D69C, 0x43D6AC, 0x43D6BC, 0x43D6CE} 8 | local p2addr = {0x43D6FC, 0x43D70D, 0x43D71F, 0x43D731, 0x43D743, 0x43D753, 0x43D762, 0x43D773} 9 | local bossaddr = {0x4C710C, 0x4C7119, 0x6193E1, 0x6193EE, 0x62668D, 0x62669B, 0x64869D, 0x6486AB, 0x6486AB, 0x661CFD, 0x661D0B} 10 | local target = radiogroup_getItemIndex(CharSelect_SetCharFor) 11 | local tgtaddr = {} 12 | 13 | if target == 0 then --Player 1 14 | tgtaddr = p1addr 15 | elseif target == 1 then --Player 2 16 | tgtaddr = p2addr 17 | elseif target == 2 then --Boss 18 | tgtaddr = bossaddr 19 | end 20 | 21 | for i,v in ipairs(tgtaddr) do 22 | local char = listbox_getItemIndex(CharSelect_CharList) 23 | local val = (charload[char+1] - 4 - v) 24 | writeInteger(v, val) 25 | end 26 | 27 | BtnAltCharFixClick() 28 | 29 | form_hide(CharSelect) 30 | end -------------------------------------------------------------------------------- /Sample Object Lists/Final Rush 2.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | FRSTAGE,4B31D0,6,2,1955.6435546875,-295.88714599609,-25.761325836182,0,0,0,0,0,0 3 | Dash Panel,6CFBF0,2,2,1978.7816162109,-295.88714599609,-42.513877868652,0,6000,0,14,60,0 4 | FRSTAGE,4B31D0,6,2,2436.7985839844,-596.95086669922,-498.0319519043,1,6000,0,0,0,0 5 | ITEMBOXAIR ,6C8EF0,2,2,2488.1845703125,-592.95086669922,-463.61730957031,1,0,0,1,14810,1 6 | ITEMBOXAIR ,6C8EF0,2,2,2544.7724609375,-607.95086669922,-436.52780151367,1,0,0,1,11725,1 7 | ITEMBOXAIR ,6C8EF0,2,2,2594.7683105469,-622.95086669922,-417.05703735352,1,0,0,1,10495,1 8 | ITEMBOXAIR ,6C8EF0,2,2,2625.9970703125,-687.95086669922,-392.12194824219,1,0,0,1,9355,1 9 | ITEMBOXAIR ,6C8EF0,2,2,2701.9675292969,-722.95086669922,-406.95040893555,1,0,0,1,8515,1 10 | ITEMBOXAIR ,6C8EF0,2,2,2789.3811035156,-792.95086669922,-461.52401733398,1,0,0,1,6925,1 11 | ITEMBOXAIR ,6C8EF0,2,2,2861.9025878906,-822.95086669922,-495.08392333984,1,0,0,1,4905,1 12 | ITEMBOXAIR ,6C8EF0,2,2,2958.2282714844,-922.95086669922,-489.63311767578,1,0,0,1,3690,1 13 | ITEMBOX ,6C7C10,2,2,3022.7453613281,-927.18774414063,-589.47888183594,1,0,0,1,360,1 14 | -------------------------------------------------------------------------------- /sa2lua/linedraw.asm: -------------------------------------------------------------------------------- 1 | ; linedraw.asm 2 | ; Use as object routine, and manually set ObjectMaster+0x34 to an allocated address for the list of lines. 3 | DrawLine3D equ 0x44B770 4 | 5 | bits 32 6 | push eax 7 | mov eax,[esi+0x38] 8 | push dword [eax] 9 | call DrawLinesFromMemory 10 | add esp,4 11 | pop eax 12 | ret 13 | 14 | DrawLinesFromMemory: 15 | ; Save the values of the registers on the stack. 16 | push ebx 17 | push ecx 18 | push esi 19 | 20 | ; Get the address of the line data from the stack. 21 | mov esi,[esp+0x10] 22 | test esi,esi 23 | jz ExitFunction 24 | 25 | ; Loop through the lines. 26 | mov ecx,[esi] 27 | test ecx,ecx 28 | jz ExitFunction 29 | add esi,4 30 | 31 | DrawLinesLoop: 32 | push ecx ;the function overwrites ecx 33 | push 1 34 | ; Right now ESI contains the address of the first line's coordinates. 35 | ; But first we need to push the color pointer, which is 24 bytes away. 36 | lea ebx,[esi+24] 37 | push ebx 38 | push esi 39 | ; Now we'll call the function. 40 | mov ebx,DrawLine3D 41 | call ebx 42 | add esp,12 43 | pop ecx 44 | ; Now just shift ESI 28 bytes forward for the next line and loop. 45 | add esi,28 46 | loop DrawLinesLoop 47 | 48 | ExitFunction: 49 | pop esi 50 | pop ecx 51 | pop ebx 52 | ret 53 | -------------------------------------------------------------------------------- /sa2lua/bitwise.lua: -------------------------------------------------------------------------------- 1 | -- http://perforce.freebsd.org/fileLogView.cgi?FSPC=//depot/projects/soc2005/bsdinstaller/src/contrib/bsdinstaller/backend/lua/lib/bitwise.lua 2 | -- lib/bitwise.lua 3 | -- $Id: bitwise.lua,v 1.3 2005/04/11 02:21:37 cpressey Exp $ 4 | -- Package for (pure-Lua portable but extremely slow) bitwise arithmetic. 5 | 6 | -- BEGIN lib/bitwise.lua -- 7 | 8 | --[[---------]]-- 9 | --[[ Bitwise ]]-- 10 | --[[---------]]-- 11 | 12 | Bitwise = {} 13 | 14 | Bitwise.odd = function(x) 15 | return x ~= math.floor(x / 2) * 2 16 | end 17 | 18 | Bitwise.bw_and = function(a, b) 19 | local c, pow = 0, 1 20 | while a > 0 or b > 0 do 21 | if Bitwise.odd(a) and Bitwise.odd(b) then 22 | c = c + pow 23 | end 24 | a = math.floor(a / 2) 25 | b = math.floor(b / 2) 26 | pow = pow * 2 27 | end 28 | return c 29 | end 30 | 31 | Bitwise.bw_or = function(a, b) 32 | local c, pow = 0, 1 33 | while a > 0 or b > 0 do 34 | if Bitwise.odd(a) or Bitwise.odd(b) then 35 | c = c + pow 36 | end 37 | a = math.floor(a / 2) 38 | b = math.floor(b / 2) 39 | pow = pow * 2 40 | end 41 | return c 42 | end 43 | -------------------------------------------------------------------------------- /Sample Object Lists/Dash Panel Loop (test level).csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | KASOKU,6CFBF0,2,2,352.71258544922,0,-109.27864837646,0,383E,0,6,50,50 3 | KASOKU,6CFBF0,2,2,386.90386962891,0,-106.71752166748,0,1692,0,6,50,50 4 | KASOKU,6CFBF0,F,2,406.90386962891,0,-58.71752166748,0,FFFFF692,0,6,50,50 5 | KASOKU,6CFBF0,F,2,394.90386962891,0,-14.71752166748,0,FFFFC692,0,6,50,50 6 | KASOKU,6CFBF0,F,2,346.90386962891,0,1.2824783325195,0,FFFFE692,0,6,50,50 7 | KASOKU,6CFBF0,F,2,318.90386962891,0,37.28247833252,0,692,0,6,50,50 8 | KASOKU,6CFBF0,F,2,322.90386962891,0,81.28247833252,0,3692,0,6,50,50 9 | KASOKU,6CFBF0,F,2,362.90386962891,0,89.28247833252,0,6692,0,6,50,50 10 | KASOKU,6CFBF0,F,2,390.90386962891,0,53.28247833252,0,5692,0,6,50,50 11 | KASOKU,6CFBF0,F,2,438.90386962891,0,29.28247833252,0,7692,0,6,50,50 12 | KASOKU,6CFBF0,F,2,442.90386962891,0,-6.7175216674805,0,7692,0,6,50,50 13 | KASOKU,6CFBF0,F,2,454.90386962891,0,-50.71752166748,0,8692,0,6,50,50 14 | KASOKU,6CFBF0,F,2,454.90386962891,0,-102.71752166748,0,A692,0,6,50,50 15 | KASOKU,6CFBF0,F,2,394.90386962891,0,-154.71752929688,0,A692,0,6,50,50 16 | KASOKU,6CFBF0,F,2,362.90386962891,0,-178.71752929688,0,E692,0,6,50,50 17 | KASOKU,6CFBF0,F,2,342.90386962891,0,-138.71752929688,0,11692,0,6,50,50 18 | KASOKU,6CFBF0,2,2,430.64422607422,0,-125.87345123291,0,A78E,0,6,50,50 19 | KASOKU,6CFBF0,2,2,334.77130126953,0,-155.38293457031,0,118A,0,6,50,50 20 | -------------------------------------------------------------------------------- /sa2lua/objectlist.csv: -------------------------------------------------------------------------------- 1 | Ring,2,2,6C0F80 2 | Line of Rings,2,2,6C5ED0 3 | Circle of Rings,2,2,6C6180 4 | Item Box,2,2,6C7C10 5 | Floating Item Box,2,2,6C8EF0 6 | Balloon,2,2,6DB030 7 | Spring (Type A),2,2,6C4480 8 | Spring (Type B),2,2,6C4E90 9 | Triple Spring,2,2,6D9310 10 | Pulley,2,2,6E5620 11 | Dash Panel,2,2,6CFBF0 12 | Launch Panel,6,2,6D7130 13 | Point Marker,A,2,6D99A0 14 | Char Upgrade,2,2,6D8540 15 | Goal Ring,2,2,6C63C0 16 | Emerald Shard,2,2,6D00C0 17 | Rocket,6,2,6D4EA0 18 | Missile,6,2,6CE4C0 19 | Weight,6,2,6DBB90 20 | Switch,2,2,6DCDC0 21 | Dynamite Pack,2,2,6DA720 22 | Rotating Spikes,2,2,6D3C00 23 | Animal Pipe,2,2,6D95E0 24 | Wooden Cont.,2,2,6CD7F0 25 | Steel Container,2,2,6D63F0 26 | Chao Container,2,2,6DE3B0 27 | Unbreakable Cont.,2,2,6E70B0 28 | Cage,2,2,6D29F0 29 | Skull,2,2,6D4E30 30 | GUN Beetle,2,2,501530 31 | GUN Wing Beetle,2,2,505C20 32 | GUN Gold Beetle,2,2,506510 33 | GUN Rhino,2,2,4FDD00 34 | GUN Hunter,2,2,4FF990 35 | GUN Hawk,2,2,4FC700 36 | GUN Hornet,2,2,4F8F90 37 | GUN Phoenix,2,2,7A0D10 38 | Artificial Chaos,2,2,50A850 39 | Ghost,2,2,503140 40 | Unidus,2,2,50F150 41 | Kiki,2,2,50E4D0 42 | E-1000,2,2,50D790 43 | Buzz Bomber,2,2,7A21C0 44 | Chopper (Fish),2,2,7A1600 45 | Small Cylinder,3,2,6D6EE0 46 | Med. Cylinder,3,2,6D6F60 47 | Large Cylinder,3,2,6D6FB0 48 | Tall Cylinder,3,2,6D7030 49 | Uprootable Cyl.,3,2,6D70E0 50 | Gravity Cylinder,2,2,7A3760 51 | Collision Cube,2,2,6E54E0 52 | Collision Cylinder,2,2,6E5470 53 | Collision Wall,2,2,6E5550 54 | Collision Circle,2,2,6E55C0 -------------------------------------------------------------------------------- /sa2lua/stagelist.csv: -------------------------------------------------------------------------------- 1 | City Escape,13 2 | Wild Canyon,16 3 | Wild Canyon (2P),41 4 | Prison Lane,9 5 | Metal Harbor,10 6 | Metal Harbor (2P),57 7 | Green Forest,3 8 | Pumpkin Hill,5 9 | Mission Street,17 10 | Mission Street (2P),39 11 | Aquatic Mine,7 12 | Hidden Base,23 13 | Hidden Base (2P),48 14 | Pyramid Cave,28 15 | Death Chamber,25 16 | Death Chamber (2P),59 17 | Eternal Engine,24 18 | Eternal Engine (2P),56 19 | Meteor Herd,32 20 | Crazy Gadget,22 21 | Final Rush,30 22 | Iron Gate,11 23 | Iron Gate (2P),58 24 | Dry Lagoon,18 25 | Dry Lagoon (2P),46 26 | Sand Ocean,21 27 | Sand Ocean (2P),45 28 | Radical Highway,14 29 | Egg Quarters,26 30 | Lost Colony,27 31 | Lost Colony (2P),55 32 | Weapons Bed,12 33 | Weapons Bed (2P),15 34 | Security Hall,8 35 | White Jungle,4 36 | Sky Rail,6 37 | Mad Space,44 38 | Cosmic Wall,43 39 | Cosmic Wall (2P),53 40 | Final Chase,40 41 | Cannon's Core Act 1 (T),36 42 | Cannon's Core Act 2 (E),35 43 | Cannon's Core Act 3 (R),37 44 | Cannon's Core Act 4 (K),38 45 | Cannon's Core Act 5 (S),34 46 | Green Hill,31 47 | Chao Lobby,90,7 48 | Neutral Chao Garden,90,1 49 | Hero Chao Garden,90,2 50 | Dark Chao Garden,90,3 51 | Chao Kindergarten,90,6 52 | Chao Stadium Cave,90,9 53 | Chao Race Entrance,90,5 54 | Chao Race (broken),90,4 55 | Chao Karate,90,10 56 | Test Level,0 57 | Sonic vs. Shadow (Forest),19 58 | Sonic vs. Shadow (ARK),42 59 | Tails vs. Eggman (Runway),20 60 | Tails vs. Eggman (ARK),29 61 | Knuckles vs. Rouge,33 62 | F-6t BIG FOOT,60 63 | B-3x HOT SHOT,61 64 | R-1/A FLYING DOG,62 65 | King Boom Boo,63 66 | Egg Golem (Sonic),64 67 | Egg Golem (Eggman),67 68 | Biolizard,65 69 | Final Hazard,66 70 | Route 101/280,70 71 | Kart Race,71 72 | Pyramid Race,47 73 | Pool Quest,49 74 | Planet Quest,50 75 | Deck Race,51 76 | Downtown Race,52 77 | Grind Race,54 -------------------------------------------------------------------------------- /sa2lua/lvlmixer.lua: -------------------------------------------------------------------------------- 1 | function LMLoadLevelList() 2 | stagelist = {} 3 | local lbitems = listbox_getItems(LevelMixer_LMLevelList) 4 | strings_clear(lbitems) 5 | for s in io.lines("sa2lua/stagelist.csv") do 6 | local ltbl = s:split(",") 7 | local tbl = {} 8 | tbl.name = ltbl[1] 9 | tbl.id = ltbl[2] 10 | tbl.chaoarea = ltbl[3] 11 | table.insert(stagelist, tbl) 12 | strings_add(lbitems, tbl.name) 13 | end 14 | control_setEnabled(LevelMixer_LMLevelList, true) 15 | control_setEnabled(LevelMixer_LMLoadObjects, true) 16 | control_setEnabled(LevelMixer_LMCombineLevels, true) 17 | end 18 | 19 | function ShowLevelMixerClick(sender) 20 | form_show(LevelMixer) 21 | LMLoadLevelList() 22 | end 23 | 24 | function LMLoadObjectsClick(sender) 25 | local id = stagelist[listbox_getItemIndex(LevelMixer_LMLevelList) + 1].id 26 | local ca = stagelist[listbox_getItemIndex(LevelMixer_LMLevelList) + 1].chaoarea 27 | writeInteger(0x1934B70, id) 28 | if ca ~= nil then writeInteger(0x134062C, ca) end 29 | writeBytes(0x1934BE0, 0x02) 30 | end 31 | 32 | function LMCombineLevelsClick(sender) 33 | local id = stagelist[listbox_getItemIndex(LevelMixer_LMLevelList) + 1].id 34 | local ca = stagelist[listbox_getItemIndex(LevelMixer_LMLevelList) + 1].chaoarea 35 | writeInteger(0x1934B70, id) 36 | if ca ~= nil then writeInteger(0x134062C, ca) end 37 | writeBytes(0x1934BE0, 0x03) 38 | end 39 | 40 | function LMLevelListDblClick(sender) 41 | local id = stagelist[listbox_getItemIndex(LevelMixer_LMLevelList) + 1].id 42 | SetAndFreezeValue("Current Level", id) 43 | showMessage("Level value frozen until you click OK") 44 | UnfreezeValue("Current Level") 45 | end 46 | 47 | control_setEnabled(LevelMixer_LMLevelList, false) 48 | control_setEnabled(LevelMixer_LMLoadObjects, false) 49 | control_setEnabled(LevelMixer_LMCombineLevels, false) -------------------------------------------------------------------------------- /sa2lua/lthook.lua: -------------------------------------------------------------------------------- 1 | function LTHEnabledClick(sender) 2 | LTHHookEnabled = (checkbox_getState(sender) == cbChecked) 3 | if LTHHookEnabled then 4 | debugProcess() 5 | debug_setBreakpoint(0x47BD30) 6 | else 7 | debug_removeBreakpoint(0x47BD30) 8 | end 9 | end 10 | 11 | function LTHPauseClick(sender) 12 | LTHPause = (checkbox_getState(sender) == cbChecked) 13 | end 14 | 15 | function LTHTextureFileBtnClick(sender) 16 | LTHReplaceTexFile = (checkbox_getState(sender) == cbChecked) 17 | end 18 | 19 | function LTHMakeNonSolidClick(sender) 20 | LTHMakeNonSolid = (checkbox_getState(sender) == cbChecked) 21 | end 22 | 23 | function LTHReplaceModelClick(sender) 24 | LTHReplaceModel = (checkbox_getState(sender) == cbChecked) 25 | end 26 | 27 | function LTHHookTriggered() 28 | local ltaddr = 0x1DDA3C0 29 | if LTHHookEnabled then 30 | if LTHReplaceTexFile then 31 | local tfn = control_getCaption(LTHookConfig_LTHTextureFileName) 32 | local addr = AllocateString(tfn) 33 | writeInteger(ltaddr + 0x18, addr) 34 | end 35 | 36 | if LTHMakeNonSolid then 37 | local count = readWord(ltaddr) 38 | local pcol = readInteger(ltaddr + 0x10) 39 | for i=0,count-1 do 40 | local addr = pcol + 0x20*i 41 | local val = readInteger(addr) 42 | if val ~= nil then 43 | val = Bitwise.bw_and(val, 0xFFFFFFFE) 44 | writeInteger(addr + 0x1C, val) 45 | end 46 | end 47 | end 48 | 49 | if LTHPause then 50 | return 0 51 | else 52 | debug_continueFromBreakpoint() 53 | return 1 54 | end 55 | else 56 | return 0 57 | end 58 | end 59 | 60 | function ShowLTHCfgClick(sender) 61 | form_show(LTHookConfig) 62 | end 63 | 64 | LTHHookEnabled = false 65 | LTHReplaceTexFile = false 66 | LTHMakeNonSolid = false 67 | LTHReplaceModel = false --don't remember what this is; I imagine it didn't work or I wouldn't have removed it 68 | LTHPause = false 69 | 70 | BreakpointCallbackTbl[0x47BD30] = LTHHookTriggered -------------------------------------------------------------------------------- /sa2lua/setexport.lua: -------------------------------------------------------------------------------- 1 | function SETNumToByteStr(value, numbytes) 2 | local bytes = {} 3 | for i = 0, numbytes-1 do 4 | local byte = Bitwise.bw_and(value, 0xFF * 0x100^i) 5 | byte = byte / 0x100^i 6 | table.insert(bytes, byte) 7 | end 8 | return string.char(unpack(bytes)):reverse() 9 | end 10 | 11 | function SETWriteHeader(file, objcount) 12 | file:write(SETNumToByteStr(objcount, 4)) 13 | for i = 1, 28 do 14 | file:write(string.char(0)) 15 | end 16 | end 17 | 18 | function SETFindObjectType(routine, objlist) 19 | -- use GetStageObjList() for objlist 20 | for i,v in ipairs(objlist) do 21 | if v.routine == routine then return i end 22 | end 23 | return nil 24 | end 25 | 26 | function SETWriteEntry(file, addr, routine) 27 | local typeid = SETFindObjectType(routine, GetStageObjList()) 28 | if typeid == nil then return false end 29 | 30 | local rx = readInteger(GetObjData1(addr, 0x08)) 31 | local ry = readInteger(GetObjData1(addr, 0x0C)) 32 | local rz = readInteger(GetObjData1(addr, 0x10)) 33 | local px = readInteger(GetObjData1(addr, 0x14)) 34 | local py = readInteger(GetObjData1(addr, 0x18)) 35 | local pz = readInteger(GetObjData1(addr, 0x1C)) 36 | local sx = readInteger(GetObjData1(addr, 0x20)) 37 | local sy = readInteger(GetObjData1(addr, 0x24)) 38 | local sz = readInteger(GetObjData1(addr, 0x28)) 39 | 40 | file:write(SETNumToByteStr(typeid-1, 2)) 41 | file:write(SETNumToByteStr(rx, 2)) 42 | file:write(SETNumToByteStr(ry, 2)) 43 | file:write(SETNumToByteStr(rz, 2)) 44 | file:write(SETNumToByteStr(px, 4)) 45 | file:write(SETNumToByteStr(py, 4)) 46 | file:write(SETNumToByteStr(pz, 4)) 47 | file:write(SETNumToByteStr(sx, 4)) 48 | file:write(SETNumToByteStr(sy, 4)) 49 | file:write(SETNumToByteStr(sz, 4)) 50 | 51 | return true 52 | end 53 | 54 | function SETWriteFile(file, objects) 55 | local count = 0 56 | for i,v in ipairs(ol_spawned) do 57 | if SETFindObjectType(v.routine, GetStageObjList()) ~= nil then count = count + 1 end 58 | end 59 | SETWriteHeader(file, count) 60 | for i,v in ipairs(ol_spawned) do 61 | SETWriteEntry(file, v.addr, v.routine) 62 | end 63 | return count 64 | end 65 | -------------------------------------------------------------------------------- /sa2lua/remote.lua: -------------------------------------------------------------------------------- 1 | function ShowRemote() 2 | form_show(Remote) 3 | end 4 | 5 | function UpdateRemote() 6 | local btns = {Remote_Btn1, Remote_Btn2, Remote_Btn3, Remote_Btn4, Remote_Btn5, Remote_Btn6, Remote_Btn7, Remote_Btn8} 7 | 8 | SetRemoteText("Unrecognized") 9 | 10 | for i,v in ipairs(btns) do 11 | control_setEnabled(v, false) 12 | control_setCaption(v, "-") 13 | end 14 | 15 | rmtobjaddr = objaddr 16 | SetRemoteButtons() 17 | 18 | local count = #remote_btnfunc 19 | for i=1,count do 20 | control_setEnabled(btns[i], true) 21 | control_setCaption(btns[i], remote_btntext[i]) 22 | end 23 | end 24 | 25 | function RemoteButtonClick(sender) 26 | local index = component_getTag(sender) 27 | local func = remote_btnfunc[index] 28 | func() 29 | end 30 | 31 | function SetRemoteText(text) 32 | control_setCaption(Remote_TextBox, text) 33 | end 34 | 35 | function RmtSetScaleToMe() 36 | local x = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 37 | local y = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 38 | local z = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 39 | writeFloat(GetObjData1(rmtobjaddr, 0x20), x) 40 | writeFloat(GetObjData1(rmtobjaddr, 0x24), y) 41 | writeFloat(GetObjData1(rmtobjaddr, 0x28), z) 42 | end 43 | 44 | function RmtAddActionBtn(text, action) 45 | local funcstr = "writeBytes(GetObjData1(rmtobjaddr, 0x00), "..tostring(action)..")" 46 | local func = loadstring(funcstr) 47 | table.insert(remote_btntext, text) 48 | table.insert(remote_btnfunc, func) 49 | end 50 | 51 | function SetRemoteButtons() 52 | local rt = readInteger(rmtobjaddr + 0x10) -- main routine 53 | remote_btntext = {} 54 | remote_btnfunc = {} 55 | 56 | if rt == 0x6D50F0 then -- ROCKET 57 | SetRemoteText("Rocket") 58 | table.insert(remote_btntext, "Set Target to Me") 59 | table.insert(remote_btnfunc, RmtSetScaleToMe) 60 | elseif rt == 0x6BE2E0 then -- MSGER (Omochao) 61 | SetRemoteText("Omochao") 62 | RmtAddActionBtn("Self Destruct", 3) 63 | RmtAddActionBtn("\"Discipline\"", 4) 64 | RmtAddActionBtn("Bug Me", 6) 65 | RmtAddActionBtn("Disable", 8) 66 | elseif rt == 0x6DBEB0 then -- BUNCHIN (Weight) 67 | SetRemoteText("Weight") 68 | table.insert(remote_btntext, "(Un)Freeze") 69 | table.insert(remote_btnfunc, function() 70 | local sbf = readBytes(GetObjData1(rmtobjaddr, 0x01), 1, false) 71 | if Bitwise.bw_and(sbf, 0x04) > 0 then sbf = sbf - 0x04 else sbf = sbf + 0x04 end 72 | writeBytes(GetObjData1(rmtobjaddr, 0x01), sbf) 73 | end) 74 | end 75 | end 76 | 77 | remote_btntext = {} 78 | remote_btnfunc = {} 79 | rmtobjaddr = objaddr -------------------------------------------------------------------------------- /sa2lua/physpresets.lua: -------------------------------------------------------------------------------- 1 | function ShowPhysicsPresetsClick(sender) 2 | if tonumber_original == nil then 3 | tonumber_original = tonumber 4 | tonumber = tonumber_new 5 | end 6 | PPPresetList = PPLoadPresets() 7 | local lbitems = listbox_getItems(PhysicsPresets_List) 8 | strings_clear(lbitems) 9 | for i,v in ipairs(PPPresetList) do 10 | strings_add(lbitems, v.Name) 11 | end 12 | form_show(PhysicsPresets) 13 | end 14 | 15 | function PhysicsPresetsApplyClick(sender) 16 | local data2 = readInteger(readInteger(0x1DEA6E0) + 0x40) 17 | local sel = PPPresetList[listbox_getItemIndex(PhysicsPresets_List) + 1] 18 | 19 | if data2 ~= nil and sel ~= nil then 20 | writeInteger(data2 + 0xC0, sel.HangTime) 21 | writeFloat(data2 + 0xC8, sel.HorizSpeedCap) 22 | writeFloat(data2 + 0xCC, sel.VertSpeedCap) 23 | writeFloat(data2 + 0xD0, sel.SpeedMod) 24 | writeFloat(data2 + 0xD8, sel.InitJumpSpeed) 25 | writeFloat(data2 + 0xF8, sel.AddWhileJumpHeld) 26 | writeFloat(data2 + 0xFC, sel.GroundAccel) 27 | writeFloat(data2 + 0x100, sel.AirAccel) 28 | writeFloat(data2 + 0x104, sel.GroundDecel) 29 | writeFloat(data2 + 0x108, sel.BrakeSpeed) 30 | writeFloat(data2 + 0x10C, sel.AirBrakeSpeed) 31 | writeFloat(data2 + 0x110, sel.AirDecel) 32 | writeFloat(data2 + 0x114, sel.RollingDecel) 33 | writeFloat(data2 + 0x138, sel.Gravity) 34 | end 35 | end 36 | 37 | function PPLoadPresets() 38 | local result = {} 39 | local columns = {} 40 | local isHeader = true 41 | 42 | for line in io.lines("sa2lua/physpresets.csv") do 43 | if isHeader then 44 | for i,v in ipairs(line:split(",")) do 45 | columns[v] = i 46 | end 47 | isHeader = false 48 | else 49 | local colsToRead = {"Name", "HangTime", "HorizSpeedCap", "VertSpeedCap", "SpeedMod", "InitJumpSpeed", 50 | "AddWhileJumpHeld", "GroundAccel", "AirAccel", "GroundDecel", "BrakeSpeed", 51 | "AirBrakeSpeed", "AirDecel", "RollingDecel", "Gravity"} 52 | local preset = {} 53 | local s = line:split(",") 54 | for i,v in ipairs(colsToRead) do 55 | if v == "Name" then 56 | preset[v] = s[columns[v]] 57 | else 58 | preset[v] = tonumber(s[columns[v]]) 59 | end 60 | end 61 | table.insert(result, preset) 62 | end 63 | end 64 | 65 | return result 66 | end 67 | 68 | function tonumber_new(str) 69 | local n = tonumber_original(str) 70 | if n == nil then return nil end 71 | if type(n) == "number" then return n end 72 | if n > 0 then 73 | if str:sub(1, 1) == "-" then 74 | return -n 75 | else 76 | return n 77 | end 78 | else 79 | return n 80 | end 81 | end 82 | 83 | PPPresetList = {} -------------------------------------------------------------------------------- /sa2lua/infodisp.lua: -------------------------------------------------------------------------------- 1 | local textContainer = nil 2 | local textContainerBack = nil 3 | local active = false 4 | 5 | function InfoDispBtnChange(sender) 6 | if checkbox_getState(sender) == cbChecked then 7 | InfoDispEnable() 8 | else 9 | InfoDispDisable() 10 | end 11 | end 12 | 13 | function InfoDispEnable() 14 | OMKStart() 15 | active = true 16 | end 17 | 18 | function InfoDispDisable() 19 | if textContainer ~= nil then object_destroy(textContainer) end 20 | if textContainerBack ~= nil then object_destroy(textContainerBack) end 21 | active = false 22 | end 23 | 24 | local function BitfieldToString(num) 25 | local bit = 1 26 | local str = "" 27 | for i=1,16 do 28 | if Bitwise.bw_and(bit, num) > 0 then 29 | str = str.."1" 30 | else 31 | str = str.."." 32 | end 33 | if i == 8 then str = str.." " end 34 | bit = 2 * bit 35 | end 36 | return str 37 | end 38 | 39 | function InfoDispGetText() 40 | if IsPlayerValid() then 41 | local charBase = readInteger(0x1DEA6E0) 42 | local charData1 = readInteger(charBase + 0x34) 43 | local charData2 = readInteger(charBase + 0x40) 44 | 45 | local action = readBytes(charData1, 1) 46 | local status = readInteger(charData1 + 0x04) 47 | local xrot = readInteger(charData1 + 0x08) 48 | local yrot = readInteger(charData1 + 0x0C) 49 | local zrot = readInteger(charData1 + 0x10) 50 | local xpos = readFloat(charData1 + 0x14) 51 | local ypos = readFloat(charData1 + 0x18) 52 | local zpos = ReadFloat(charData1 + 0x1C) 53 | local hspeed = readFloat(charData2 + 0x64) 54 | local vspeed = readFloat(charData2 + 0x68) 55 | local ospeed = math.sqrt(hspeed * hspeed + vspeed * vspeed) 56 | 57 | local text = string.format("Action ID: 0x%02X (%03u) Status: %04X (%s)\n\n", action, action, status, BitfieldToString(status)) 58 | text = text.."Position:\n" 59 | text = text..string.format("X: %-15.5f Y: %-15.5f Z: %-15.5f\n", xpos, ypos, zpos) 60 | text = text.."Rotation:\n" 61 | text = text..string.format("X: %08X Y: %08X Z: %08X\n\n", xrot, yrot, zrot) 62 | text = text.."Speed: (Horizontal) (Vertical)\n" 63 | text = text..string.format("%-14.5f %-14.5f %-14.5f", ospeed, hspeed, vspeed) 64 | 65 | return text 66 | else 67 | return "" 68 | end 69 | end 70 | 71 | function InfoDispUpdate() 72 | if OMKD3DHook ~= nil and active then 73 | if textContainer ~= nil then object_destroy(textContainer) end 74 | if textContainerBack ~= nil then object_destroy(textContainerBack) end 75 | 76 | local text = InfoDispGetText() 77 | textContainerBack = OMKD3DHook.createTextContainer(OMKFontMapShadow, 17, OMKD3DHook.Height - 239, text) 78 | textContainer = OMKD3DHook.createTextContainer(OMKFontMap, 16, OMKD3DHook.Height - 240, text) 79 | end 80 | end -------------------------------------------------------------------------------- /sa2lua/spawnedlist.lua: -------------------------------------------------------------------------------- 1 | function ShowSpawnedObjListClick(sender) 2 | form_show(SpawnedObjList) 3 | end 4 | 5 | function ClearSpawnedObjectsClick(sender) 6 | local result = messageDialog("Really delete all spawned objects?", mtWarning, mbYes, mbNo) 7 | if result == mrYes then 8 | for i,v in ipairs(ol_spawned) do 9 | writeInteger(v.addr + 0x10, 0x46F720) 10 | end 11 | ol_spawned = {} 12 | OLUpdateList() 13 | end 14 | end 15 | 16 | function SpawnedObjListDblClick(sender) 17 | local index = listview_getItemIndex(sender) + 1 18 | if index >= 0 then 19 | objaddr = tonumber(ol_spawned[index].addr) 20 | OCUpdateControls() 21 | form_show(ObjectChain) 22 | end 23 | end 24 | 25 | function OLAddObject(addr, routine, flags, list) 26 | local obj = {} 27 | obj.name = readString(readInteger(addr + 0x44), 64) 28 | obj.addr = addr 29 | local player = readInteger(0x1DEA6E0) 30 | obj.x = readFloat(GetObjData1(addr, 0x14)) 31 | obj.y = readFloat(GetObjData1(addr, 0x18)) 32 | obj.z = readFloat(GetObjData1(addr, 0x1C)) 33 | obj.routine = routine 34 | obj.flags = flags 35 | obj.list = list 36 | table.insert(ol_spawned, obj) 37 | OLUpdateList() 38 | end 39 | 40 | function OLRemoveObject(addr) 41 | for i,v in ipairs(ol_spawned) do 42 | if v.addr == addr then 43 | table.remove(ol_spawned, i) 44 | break 45 | end 46 | end 47 | OLUpdateList() 48 | end 49 | 50 | function OLUpdateList() 51 | local lvitems = listview_getItems(SpawnedObjList_ObjList) 52 | listitems_clear(lvitems) 53 | for i,v in ipairs(ol_spawned) do 54 | local item = listitems_add(lvitems) 55 | local cols = listitem_getSubItems(item) 56 | listitem_setCaption(item, i) 57 | strings_add(cols, v.name) 58 | strings_add(cols, num2hex(v.addr)) 59 | strings_add(cols, "---") 60 | v.listitem = item 61 | end 62 | OLUpdateDistances() 63 | end 64 | 65 | function OLCheckForDeletedObjects() 66 | local shouldUpdate = false 67 | for i,v in ipairs(ol_spawned) do 68 | if readString(readInteger(v.addr + 0x44), 64) ~= v.name 69 | or readInteger(GetObjData1(v.addr, 0)) == nil then 70 | table.remove(ol_spawned, i) 71 | shouldUpdate = true 72 | end 73 | end 74 | if shouldUpdate then OLUpdateList() end 75 | end 76 | 77 | function OLUpdateDistances() 78 | local player = readInteger(0x1DEA6E0) 79 | if readInteger(GetObjData1(player, 0)) == nil then 80 | -- Level has been unloaded; spawned objects no longer exist 81 | ol_spawned = {} 82 | end 83 | for i,v in ipairs(ol_spawned) do 84 | local cols = listitem_getSubItems(v.listitem) 85 | if readFloat(GetObjData1(v.addr, 0x14)) ~= nil then 86 | local dx = math.abs(readFloat(GetObjData1(v.addr, 0x14)) - readFloat(GetObjData1(player, 0x14))) 87 | local dy = math.abs(readFloat(GetObjData1(v.addr, 0x18)) - readFloat(GetObjData1(player, 0x18))) 88 | local dz = math.abs(readFloat(GetObjData1(v.addr, 0x1C)) - readFloat(GetObjData1(player, 0x1C))) 89 | local dist = math.sqrt(dx^2 + dy^2 + dz^2) 90 | strings_setString(cols, 2, string.format("%.1f", dist)) 91 | else 92 | strings_setString(cols, 2, "---") 93 | end 94 | end 95 | end 96 | 97 | ol_spawned = {} 98 | OLUpdateList() -------------------------------------------------------------------------------- /Sample Object Lists/Tons of Springs.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | Spring (Type A),6C4480,2,2,201.53579711914,1,-266.39379882813,0,0,0,180,1,0 3 | Spring (Type A),6C4480,2,2,181.53579711914,1,-266.39379882813,0,0,0,180,1,0 4 | Spring (Type A),6C4480,2,2,161.53579711914,1,-266.39379882813,0,0,0,180,1,0 5 | Spring (Type A),6C4480,2,2,141.53579711914,1,-266.39379882813,0,0,0,180,1,0 6 | Spring (Type A),6C4480,2,2,121.53579711914,1,-266.39379882813,0,0,0,180,1,0 7 | Spring (Type A),6C4480,2,2,101.53579711914,1,-266.39379882813,0,0,0,180,1,0 8 | Spring (Type A),6C4480,2,2,81.535797119141,1,-266.39379882813,0,0,0,180,1,0 9 | Spring (Type A),6C4480,2,2,61.535797119141,1,-266.39379882813,0,0,0,180,1,0 10 | Spring (Type A),6C4480,2,2,41.535797119141,1,-266.39379882813,0,0,0,180,1,0 11 | Spring (Type A),6C4480,2,2,41.535797119141,1,-246.39379882813,0,0,0,180,1,0 12 | Spring (Type A),6C4480,2,2,61.535797119141,1,-246.39379882813,0,0,0,180,1,0 13 | Spring (Type A),6C4480,2,2,81.535797119141,1,-246.39379882813,0,0,0,180,1,0 14 | Spring (Type A),6C4480,2,2,101.53579711914,1,-246.39379882813,0,0,0,180,1,0 15 | Spring (Type A),6C4480,2,2,121.53579711914,1,-246.39379882813,0,0,0,180,1,0 16 | Spring (Type A),6C4480,2,2,141.53579711914,1,-246.39379882813,0,0,0,180,1,0 17 | Spring (Type A),6C4480,2,2,161.53579711914,1,-246.39379882813,0,0,0,180,1,0 18 | Spring (Type A),6C4480,2,2,181.53579711914,1,-246.39379882813,0,0,0,180,1,0 19 | Spring (Type A),6C4480,2,2,201.53579711914,1,-246.39379882813,0,0,0,180,1,0 20 | Spring (Type A),6C4480,2,2,81.535797119141,1,-286.39379882813,0,0,0,180,1,0 21 | Spring (Type A),6C4480,2,2,81.535797119141,1,-286.39379882813,0,0,0,180,1,0 22 | Spring (Type A),6C4480,2,2,61.535797119141,1,-286.39379882813,0,0,0,180,1,0 23 | Spring (Type A),6C4480,2,2,41.535797119141,1,-286.39379882813,0,0,0,180,1,0 24 | Spring (Type A),6C4480,2,2,101.53579711914,1,-286.39379882813,0,0,0,180,1,0 25 | Spring (Type A),6C4480,2,2,121.53579711914,1,-286.39379882813,0,0,0,180,1,0 26 | Spring (Type A),6C4480,2,2,121.53579711914,1,-286.39379882813,0,0,0,180,1,0 27 | Spring (Type A),6C4480,2,2,141.53579711914,1,-286.39379882813,0,0,0,180,1,0 28 | Spring (Type A),6C4480,2,2,141.53579711914,1,-286.39379882813,0,0,0,180,1,0 29 | Spring (Type A),6C4480,2,2,161.53579711914,1,-286.39379882813,0,0,0,180,1,0 30 | Spring (Type A),6C4480,2,2,181.53579711914,1,-286.39379882813,0,0,0,180,1,0 31 | Spring (Type A),6C4480,2,2,201.53579711914,1,-286.39379882813,0,0,0,180,1,0 32 | Spring (Type A),6C4480,2,2,201.53579711914,1,-306.39379882813,0,0,0,180,1,0 33 | Spring (Type A),6C4480,2,2,181.53579711914,1,-306.39379882813,0,0,0,180,1,0 34 | Spring (Type A),6C4480,2,2,161.53579711914,1,-306.39379882813,0,0,0,180,1,0 35 | Spring (Type A),6C4480,2,2,141.53579711914,1,-306.39379882813,0,0,0,180,1,0 36 | Spring (Type A),6C4480,2,2,121.53579711914,1,-306.39379882813,0,0,0,180,1,0 37 | Spring (Type A),6C4480,2,2,101.53579711914,1,-306.39379882813,0,0,0,180,1,0 38 | Spring (Type A),6C4480,2,2,101.53579711914,1,-306.39379882813,0,0,0,180,1,0 39 | Spring (Type A),6C4480,2,2,81.535797119141,1,-306.39379882813,0,0,0,180,1,0 40 | Spring (Type A),6C4480,2,2,61.535797119141,1,-306.39379882813,0,0,0,180,1,0 41 | Spring (Type A),6C4480,2,2,41.535797119141,1,-306.39379882813,0,0,0,180,1,0 42 | -------------------------------------------------------------------------------- /sa2lua/objenum.lua: -------------------------------------------------------------------------------- 1 | --[[function FindObjectByName(objlist, name) 2 | local originalAddr = readInteger(objlist) 3 | local addr = originalAddr 4 | if readInteger(addr) == nil then return nil end 5 | local limit = 5000 6 | repeat 7 | if addr == nil then return nil end 8 | if readString(readInteger(addr + 0x44), 64) == name then 9 | return addr 10 | end 11 | addr = readInteger(addr + 4) 12 | limit = limit - 1 13 | until addr == originalAddr or limit == 0 14 | return 0 15 | end]]-- 16 | 17 | function FindObjectByName(objlist, name) 18 | if allObjects[objlist] == nil then return nil end 19 | if #allObjects[objlist] == 0 then return nil end 20 | for i,v in ipairs(allObjects[objlist]) do 21 | if v.name == name then 22 | return obj 23 | end 24 | end 25 | return {} 26 | end 27 | 28 | function CheckForObjectWithName(objlist, name) 29 | local result = FindObjectByName(objlist, name) 30 | if result == nil then return nil end 31 | return #result ~= 0 32 | end 33 | 34 | function GenerateObjData(addr, listnum) 35 | if readInteger(addr) == nil then return nil end 36 | local objdata = {} 37 | 38 | objdata.address = addr 39 | objdata.routine = readInteger(addr + 0x10) 40 | objdata.name = readString(readInteger(addr + 0x44), 64) 41 | objdata.list = listnum 42 | objdata.flags = 15 --for SpawnFromObjData 43 | 44 | if readInteger(GetObjData1(addr, 0)) ~= nil then 45 | objdata.rx = readInteger(GetObjData1(addr, 0x8)) 46 | objdata.ry = readInteger(GetObjData1(addr, 0xC)) 47 | objdata.rz = readInteger(GetObjData1(addr, 0x10)) 48 | objdata.px = readFloat(GetObjData1(addr, 0x14)) 49 | objdata.py = readFloat(GetObjData1(addr, 0x18)) 50 | objdata.pz = readFloat(GetObjData1(addr, 0x1C)) 51 | objdata.sx = readFloat(GetObjData1(addr, 0x20)) 52 | objdata.sy = readFloat(GetObjData1(addr, 0x24)) 53 | objdata.sz = readFloat(GetObjData1(addr, 0x28)) 54 | end 55 | 56 | return objdata 57 | end 58 | 59 | function UpdateObjFromData(objdata) 60 | local addr = objdata.address 61 | if readInteger(GetObjData1(addr, 0)) ~= nil then 62 | writeInteger(GetObjData1(addr, 0x8), objdata.rx) 63 | writeInteger(GetObjData1(addr, 0xC), objdata.ry) 64 | writeInteger(GetObjData1(addr, 0x10), objdata.rz) 65 | writeFloat(GetObjData1(addr, 0x14), objdata.px) 66 | writeFloat(GetObjData1(addr, 0x18), objdata.py) 67 | writeFloat(GetObjData1(addr, 0x1C), objdata.pz) 68 | writeFloat(GetObjData1(addr, 0x20), objdata.sx) 69 | writeFloat(GetObjData1(addr, 0x24), objdata.sy) 70 | writeFloat(GetObjData1(addr, 0x28), objdata.sz) 71 | end 72 | end 73 | 74 | 75 | function EnumerateObjects(listnum) 76 | local found = {} 77 | 78 | local originalAddr = readInteger(0x1A5A254 + 4 * listnum) 79 | local addr = originalAddr 80 | if readInteger(addr) == nil or not IsPlayerValid() then return nil end 81 | local limit = 5000 82 | repeat 83 | if addr == nil then return nil end 84 | table.insert(found, GenerateObjData(addr, listnum)) 85 | addr = readInteger(addr + 4) 86 | limit = limit - 1 87 | until addr == originalAddr or limit == 0 88 | 89 | return found 90 | end 91 | 92 | function UpdateObjectListRecords() 93 | for i=0,6 do 94 | allObjects[i] = EnumerateObjects(i) or {} 95 | end 96 | selObj = GenerateObjData(objaddr, 2) 97 | end 98 | 99 | allObjects = {} -------------------------------------------------------------------------------- /sa2lua/teleport.lua: -------------------------------------------------------------------------------- 1 | function ShowSavedLocationsClick(sender) 2 | form_show(SavedLocations) 3 | end 4 | 5 | function TPUpdateControls() 6 | local lbi = listbox_getItems(SavedLocations_LocationList) 7 | strings_clear(lbi) 8 | for i,v in ipairs(locNt) do 9 | strings_add(lbi, v) 10 | end 11 | if stage < 0 then 12 | control_setCaption(SavedLocations_UpdateStageBtn, "Set Stage") 13 | control_setEnabled(SavedLocations_SaveListBtn, false) 14 | control_setEnabled(SavedLocations_SaveLocationBtn, false) 15 | control_setEnabled(SavedLocations_LocationNameBox, false) 16 | control_setCaption(SavedLocations_LocationNameBox, "") 17 | else 18 | control_setCaption(SavedLocations_UpdateStageBtn, "Stage: "..stage) 19 | control_setEnabled(SavedLocations_SaveListBtn, true) 20 | control_setEnabled(SavedLocations_LocationNameBox, true) 21 | if control_getCaption(SavedLocations_LocationNameBox) ~= "" then 22 | control_setEnabled(SavedLocations_SaveLocationBtn, true) 23 | else 24 | control_setEnabled(SavedLocations_SaveLocationBtn, false) 25 | end 26 | end 27 | end 28 | 29 | function UpdateStageBtnClick(sender) 30 | stage = readBytes(0x1934B70, 1, false) 31 | control_setCaption(sender, "Stage: " .. stage) 32 | locNt = {} 33 | locXt = {} 34 | locYt = {} 35 | locZt = {} 36 | LoadLocationFile() 37 | TPUpdateControls() 38 | end 39 | 40 | function TeleportBtnClick(sender) 41 | local charPtr = readInteger(readInteger(0x1DEA6E0) + 0x34) 42 | local sel = listbox_getItemIndex(SavedLocations_LocationList) + 1 43 | if locXt[sel] ~= nil then 44 | writeFloat(charPtr + 0x14, locXt[sel]) 45 | writeFloat(charPtr + 0x18, locYt[sel]) 46 | writeFloat(charPtr + 0x1C, locZt[sel]) 47 | end 48 | end 49 | 50 | function SaveLocationBtnClick(sender) 51 | local charPtr = readInteger(readInteger(0x1DEA6E0) + 0x34) 52 | local sel = listbox_getItemIndex(SavedLocations_LocationList) + 1 53 | table.insert(locNt, control_getCaption(SavedLocations_LocationNameBox)) 54 | control_setCaption(SavedLocations_LocationNameBox, "") 55 | table.insert(locXt, readFloat(charPtr + 0x14)) 56 | table.insert(locYt, readFloat(charPtr + 0x18)) 57 | table.insert(locZt, readFloat(charPtr + 0x1C)) 58 | TPUpdateControls() 59 | end 60 | 61 | function SaveListBtnClick(sender) 62 | lbitems = listbox_getItems(SavedLocations_LocationList) 63 | local file = io.open("sa2lua/teleport/stage"..stage..".loc", "w+") 64 | file:write(#locNt.."\n") 65 | for i,v in ipairs(locNt) do 66 | file:write(v.."\n") 67 | file:write(locXt[i].."\n") 68 | file:write(locYt[i].."\n") 69 | file:write(locZt[i].."\n") 70 | end 71 | file:close() 72 | end 73 | 74 | function LocationNameBoxChange(sender) 75 | TPUpdateControls() 76 | end 77 | 78 | function LoadLocationFile() 79 | local file = io.open("sa2lua/teleport/stage"..stage..".loc", "r") 80 | if file ~= nil then 81 | local count = tonumber(file:read()) 82 | for i=1,count do 83 | table.insert(locNt, file:read()) 84 | table.insert(locXt, tonumber(file:read())) 85 | table.insert(locYt, tonumber(file:read())) 86 | table.insert(locZt, tonumber(file:read())) 87 | end 88 | file:close() 89 | end 90 | end 91 | 92 | -- Initialization 93 | 94 | stage = -1 95 | locNt = {} 96 | locXt = {} 97 | locYt = {} 98 | locZt = {} 99 | TPUpdateControls() -------------------------------------------------------------------------------- /Sample Object Lists/Springs and Crates.csv: -------------------------------------------------------------------------------- 1 | Name,Routine,Flags,List,XPos,YPos,ZPos,XRot,YRot,ZRot,XScl,YScl,ZScl 2 | Obsidian,6E70B0,F,2,0,0,0,0,0,0,1,1,1 3 | Obsidian,6E70B0,F,2,40,0,0,0,0,0,1,1,1 4 | Iron Block,6D63F0,F,2,80,0,0,0,0,0,1,1,1 5 | Iron Block,6D63F0,F,2,120,0,0,0,0,0,1,1,1 6 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,0,0,0,0,1,1,1 7 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,0,0,0,0,1,1,1 8 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,0,0,0,0,1,1,1 9 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,0,0,0,0,1,1,1 10 | Wooden Plank,6CD7F0,F,2,20,0,60,0,0,0,1,1,1 11 | Wooden Plank,6CD7F0,F,2,120,0,60,0,0,0,1,1,1 12 | Wooden Plank,6CD7F0,F,2,20,20,60,0,0,0,1,1,1 13 | Wooden Plank,6CD7F0,F,2,120,20,60,0,0,0,1,1,1 14 | Wooden Plank,6CD7F0,F,2,20,40,60,0,0,0,1,1,1 15 | Wooden Plank,6CD7F0,F,2,120,40,60,0,0,0,1,1,1 16 | Wooden Plank,6CD7F0,F,2,20,60,60,0,0,0,1,1,1 17 | Wooden Plank,6CD7F0,F,2,120,60,60,0,0,0,1,1,1 18 | Wooden Plank,6CD7F0,F,2,20,80,60,0,0,0,1,1,1 19 | Wooden Plank,6CD7F0,F,2,40,80,60,0,0,0,1,1,1 20 | Wooden Plank,6CD7F0,F,2,60,80,60,0,0,0,1,1,1 21 | Wooden Plank,6CD7F0,F,2,80,80,60,0,0,0,1,1,1 22 | Wooden Plank,6CD7F0,F,2,100,80,60,0,0,0,1,1,1 23 | Wooden Plank,6CD7F0,F,2,120,80,60,0,0,0,1,1,1 24 | Weighted Pressure Plate (Light),6C4480,F,2,40,0,80,0,0,0,1,1,1 25 | Weighted Pressure Plate (Light),6C4480,F,2,60,0,80,0,0,0,1,1,1 26 | Weighted Pressure Plate (Light),6C4480,F,2,80,0,80,0,0,0,1,1,1 27 | Weighted Pressure Plate (Light),6C4480,F,2,100,0,80,0,0,0,1,1,1 28 | Glass,6D29F0,F,2,120,0,80,0,0,0,1,1,1 29 | Glass,6D29F0,F,2,120,20,80,0,0,0,1,1,1 30 | Glass,6D29F0,F,2,120,40,80,0,0,0,1,1,1 31 | Glass,6D29F0,F,2,120,60,80,0,0,0,1,1,1 32 | Wooden Plank,6CD7F0,F,2,20,80,80,0,0,0,1,1,1 33 | Wooden Plank,6CD7F0,F,2,120,80,80,0,0,0,1,1,1 34 | Weighted Pressure Plate (Light),6C4480,F,2,40,0,100,0,0,0,1,1,1 35 | Weighted Pressure Plate (Light),6C4480,F,2,60,0,100,0,0,0,1,1,1 36 | Weighted Pressure Plate (Light),6C4480,F,2,80,0,100,0,0,0,1,1,1 37 | Weighted Pressure Plate (Light),6C4480,F,2,100,0,100,0,0,0,1,1,1 38 | Glass,6D29F0,F,2,120,0,100,0,0,0,1,1,1 39 | Glass,6D29F0,F,2,120,20,100,0,0,0,1,1,1 40 | Glass,6D29F0,F,2,120,40,100,0,0,0,1,1,1 41 | Glass,6D29F0,F,2,120,60,100,0,0,0,1,1,1 42 | Wooden Plank,6CD7F0,F,2,20,80,100,0,0,0,1,1,1 43 | Wooden Plank,6CD7F0,F,2,120,80,100,0,0,0,1,1,1 44 | Weighted Pressure Plate (Light),6C4480,F,2,40,0,120,0,0,0,1,1,1 45 | Weighted Pressure Plate (Light),6C4480,F,2,60,0,120,0,0,0,1,1,1 46 | Weighted Pressure Plate (Light),6C4480,F,2,80,0,120,0,0,0,1,1,1 47 | Weighted Pressure Plate (Light),6C4480,F,2,100,0,120,0,0,0,1,1,1 48 | Glass,6D29F0,F,2,120,0,120,0,0,0,1,1,1 49 | Glass,6D29F0,F,2,120,20,120,0,0,0,1,1,1 50 | Glass,6D29F0,F,2,120,40,120,0,0,0,1,1,1 51 | Glass,6D29F0,F,2,120,60,120,0,0,0,1,1,1 52 | Wooden Plank,6CD7F0,F,2,20,80,120,0,0,0,1,1,1 53 | Wooden Plank,6CD7F0,F,2,120,80,120,0,0,0,1,1,1 54 | Wooden Plank,6CD7F0,F,2,20,0,140,0,0,0,1,1,1 55 | Wooden Plank,6CD7F0,F,2,120,0,140,0,0,0,1,1,1 56 | Wooden Plank,6CD7F0,F,2,20,20,140,0,0,0,1,1,1 57 | Wooden Plank,6CD7F0,F,2,120,20,140,0,0,0,1,1,1 58 | Wooden Plank,6CD7F0,F,2,20,40,140,0,0,0,1,1,1 59 | Wooden Plank,6CD7F0,F,2,120,40,140,0,0,0,1,1,1 60 | Wooden Plank,6CD7F0,F,2,20,60,140,0,0,0,1,1,1 61 | Wooden Plank,6CD7F0,F,2,120,60,140,0,0,0,1,1,1 62 | Wooden Plank,6CD7F0,F,2,20,80,140,0,0,0,1,1,1 63 | Wooden Plank,6CD7F0,F,2,40,80,140,0,0,0,1,1,1 64 | Wooden Plank,6CD7F0,F,2,60,80,140,0,0,0,1,1,1 65 | Wooden Plank,6CD7F0,F,2,80,80,140,0,0,0,1,1,1 66 | Wooden Plank,6CD7F0,F,2,100,80,140,0,0,0,1,1,1 67 | Wooden Plank,6CD7F0,F,2,120,80,140,0,0,0,1,1,1 68 | ,77A950,F,2,53,50,320,0,0,0,1,1,1 69 | Wooden Plank,77A950,F,2,73,50,320,0,0,0,1,1,1 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SA2 Cheat Table 2 | =============== 3 | 4 | This is a cheat table for the PC version of Sonic Adventure 2 that allows for many different types of hacks. 5 | It makes extensive use of Cheat Engine's Lua scripting engine to enable advanced hacks (like spawning items). 6 | 7 | Download Cheat Engine at http://www.cheatengine.org/ 8 | 9 | Features Overview 10 | ----------------- 11 | 12 | + Many addresses in the address list, including 13 | - Basic variables like rings, lives, etc. 14 | - Chao data 15 | - Character physics parameters 16 | - And more! 17 | + Teleportation interface that saves locations in levels 18 | + Interface for viewing and editing the parameters of all loaded level objects 19 | + Allows you to spawn additional objects into the level, and save them to a file to be loaded later 20 | - Now exports in the game's native SET format, for use with [SETMerge](https://github.com/flarn2006/SETMerge) 21 | - This enables the additional objects to easily be added to the game data, making it permanent 22 | + Play as any character in any level, including in 2-player mode and boss battles 23 | + Load elements from multiple levels at once, to have (for example) Metal Harbor's water and sky in Meteor Herd 24 | + Directly call any function in the game's code (for advanced users) 25 | + Load levels with any level's textures (usually looks horrible, but in some cases [looks awesome](http://www.youtube.com/watch?v=8nTvmtM9KxI)) 26 | + Skip logo screens by pressing Escape 27 | + Enable noclip mode (freely move character without being affected by gravity or walls) by pressing N 28 | + Many miscellaneous tweaks and hacks, including 29 | - Enable the test level and debug menu (debug menu can't actually be seen, but works) 30 | - Use Chao World character select on any level 31 | - Make levels load noticeably faster 32 | - Remove invisible walls from boss battles 33 | - And more! 34 | 35 | Live Edit Mode 36 | -------------- 37 | Live Edit Mode is a new feature that enables you to use the game pad to manipulate objects in-game (yes, I know I'm giving a lot of attention to that part!) with minimal window switching. It replaces the keyboard control feature, though the original keyboard controls still work when SA2 is active. 38 | 39 | Once Live Edit Mode is activated (use the button on the Object Editing dialog) you can press Down on the D-pad to enable the cursor. Use the right analog stick and the triggers to move the cursor. When the cursor is activated, the closest object to the cursor will automatically be selected. You can also press Left to place whatever item you have highlighted in the object placement dialog, similar to the debug mode in the Genesis games. When the cursor is enabled, press Down again to turn it off and keep the selection. 40 | 41 | With an object selected (and the cursor not active) you can also move and rotate the object using the controller. Hold Left to move the object around using the same controls as moving the cursor. Holding Up allows you to rotate the object. The triggers rotate around the Y (vertical) axis, and the right analog stick rotates around the X and Z (horizontal) axes. Keep in mind that some objects use the rotation values, especially the X and Z values, for different purposes. As a result, rotating these objects like this can cause different results, such as changing the rate at which it moves, or possibly crashing the game. 42 | 43 | Another feature you may notice is that some previously invisible objects (such as collision boxes) are made visible. For example, in City Escape, you may see cyan boxes around rails, which I believe have something to do with giving bonus points for "tricks", and cylinders surrounding tree trunks which otherwise have no collision. If you've ever seen that "debug mode" Gameshark code for Sonic Adventure on the Dreamcast that makes all those white boxes appear, this serves a similar purpose. 44 | 45 | If you quit and reload Cheat Engine without restarting SA2, and LEM's text display no longer functions, this is due to a limitation in Cheat Engine 6.3 and older. Upgrading to 6.4 should fix this. 46 | 47 | Miscellaneous Tips 48 | ------------------ 49 | 50 | + Double-click an object name in the spawning window to see help for its parameters. (only works with some objects) 51 | + Double-click on a level name in the Level Mixer dialog to freeze the level value. Then start any level and it will load that one instead. 52 | 53 | Licensing 54 | --------- 55 | This software is licensed under the [GNU General Public License v3.0](http://www.gnu.org/copyleft/gpl.html). 56 | 57 | ---------------------------------------------------------------------------------------------------------- 58 | *This could not have been made without the help of MainMemory from the Sonic Retro forums. Thank you! :-)* 59 | -------------------------------------------------------------------------------- /sa2lua/callfunc.lua: -------------------------------------------------------------------------------- 1 | function ShowCallFuncClick(sender) 2 | control_setCaption(CallFunc_EAX, "00000000") 3 | control_setCaption(CallFunc_EBX, "00000000") 4 | control_setCaption(CallFunc_ECX, "00000000") 5 | control_setCaption(CallFunc_EDX, "00000000") 6 | control_setCaption(CallFunc_ESI, "00000000") 7 | control_setCaption(CallFunc_EDI, "00000000") 8 | fc_stack = {} 9 | LoadFunctionList() 10 | FCUpdateControls() 11 | form_show(CallFunc) 12 | end 13 | 14 | function LoadFunctionList() 15 | fc_funclist = {} 16 | for s in io.lines("sa2lua/functions.csv") do 17 | local parsed = s:split(",") 18 | local addr 19 | local func = {} 20 | if #parsed >= 9 then 21 | addr = tonumber(parsed[1], 16) 22 | func.name = parsed[2] 23 | func.eax = parsed[3] 24 | func.ebx = parsed[4] 25 | func.ecx = parsed[5] 26 | func.edx = parsed[6] 27 | func.esi = parsed[7] 28 | func.edi = parsed[8] 29 | func.stack = parsed[9] 30 | fc_funclist[addr] = func 31 | end 32 | end 33 | local lbitems = combobox_getItems(CallFunc_Function) 34 | strings_clear(lbitems) 35 | for k,v in pairs(fc_funclist) do 36 | strings_add(lbitems, v.name) 37 | end 38 | end 39 | 40 | function StackAddClick(sender) 41 | local val = 0 42 | local str = control_getCaption(CallFunc_StackVal) 43 | local fmt = combobox_getItemIndex(CallFunc_StackType) 44 | if (fmt == 0) then 45 | val = tonumber(str, 16) 46 | str = "0x"..string.upper(str) 47 | elseif (fmt == 1) then 48 | val = tonumber(str) 49 | elseif (fmt == 2) then 50 | val = allocateSharedMemory(string.len(str) + 1) 51 | writeString(val, str) 52 | str = "\""..str.."\"" 53 | end 54 | if val ~= nil then 55 | local item = {} 56 | item.val = val 57 | item.str = str 58 | item.fmt = fmt 59 | table.insert(fc_stack, item) 60 | control_setCaption(CallFunc_StackVal, "") 61 | else 62 | messageDialog("Invalid input!", mtError, mbOK) 63 | end 64 | FCUpdateControls() 65 | end 66 | 67 | function StackRemClick(sender) 68 | local index = listbox_getItemIndex(CallFunc_StackList) + 1 69 | table.remove(fc_stack, index) 70 | FCUpdateControls() 71 | end 72 | 73 | function CallClick(sender) 74 | local eax = tonumber(control_getCaption(CallFunc_EAX), 16) 75 | local ebx = tonumber(control_getCaption(CallFunc_EBX), 16) 76 | local ecx = tonumber(control_getCaption(CallFunc_ECX), 16) 77 | local edx = tonumber(control_getCaption(CallFunc_EDX), 16) 78 | local esi = tonumber(control_getCaption(CallFunc_ESI), 16) 79 | local edi = tonumber(control_getCaption(CallFunc_EDI), 16) 80 | local stcount = #fc_stack 81 | writeInteger(hookcmd, 2) 82 | writeInteger(hookcmd + 0x04, GetSelectedFuncAddr()) 83 | writeInteger(hookcmd + 0x08, eax) 84 | writeInteger(hookcmd + 0x0C, ebx) 85 | writeInteger(hookcmd + 0x10, ecx) 86 | writeInteger(hookcmd + 0x14, edx) 87 | writeInteger(hookcmd + 0x18, esi) 88 | writeInteger(hookcmd + 0x1C, edi) 89 | writeInteger(hookcmd + 0x20, stcount) 90 | for i,v in ipairs(fc_stack) do 91 | local addr = hookcmd + 0x24 + 4*(i-1) 92 | WriteStackValue(addr, v) 93 | end 94 | local msg = "Some functions place a return value in register EAX.\n" 95 | msg = msg .. "Would you like this value to be shown when available?" 96 | local result = messageDialog(msg, mtQuestion, mbYes, mbNo, mbCancel) 97 | if result ~= mrCancel then 98 | form_close(CallFunc) 99 | end 100 | if result == mrYes then 101 | fc_show_retval = true 102 | end 103 | end 104 | 105 | function CheckForFCReturnValue() 106 | if readInteger(hookcmd) == -2 then 107 | writeInteger(hookcmd, 0) 108 | if fc_show_retval then 109 | local eax = readInteger(hookcmd + 0x08) 110 | msg = "Return value in EAX = "..num2hex(eax) 111 | messageDialog(msg, mtInformation, mbOK) 112 | fc_show_retval = false 113 | end 114 | end 115 | end 116 | 117 | function GetSelectedFuncAddr() 118 | local str = control_getCaption(CallFunc_Function) 119 | for k,v in pairs(fc_funclist) do 120 | if v.name == str then 121 | return k 122 | end 123 | end 124 | return tonumber(str, 16) 125 | end 126 | 127 | function WriteStackValue(addr, stackval) 128 | if stackval.fmt == 1 then 129 | writeFloat(addr, stackval.val) 130 | else 131 | writeInteger(addr, stackval.val) 132 | end 133 | end 134 | 135 | function FCUpdateControls() 136 | local lbitems = listbox_getItems(CallFunc_StackList) 137 | strings_clear(lbitems) 138 | for i,v in ipairs(fc_stack) do 139 | strings_add(lbitems, v.str) 140 | end 141 | local selfunc = fc_funclist[GetSelectedFuncAddr()] 142 | if selfunc ~= nil then 143 | control_setCaption(CallFunc_LblEAX, EmptyStrIfNil(selfunc.eax)) 144 | control_setCaption(CallFunc_LblEBX, EmptyStrIfNil(selfunc.ebx)) 145 | control_setCaption(CallFunc_LblECX, EmptyStrIfNil(selfunc.ecx)) 146 | control_setCaption(CallFunc_LblEDX, EmptyStrIfNil(selfunc.edx)) 147 | control_setCaption(CallFunc_LblESI, EmptyStrIfNil(selfunc.esi)) 148 | control_setCaption(CallFunc_LblEDI, EmptyStrIfNil(selfunc.edi)) 149 | control_setCaption(CallFunc_StackLbl, "Req: "..EmptyStrIfNil(selfunc.stack)) 150 | else 151 | control_setCaption(CallFunc_LblEAX, "???") 152 | control_setCaption(CallFunc_LblEBX, "???") 153 | control_setCaption(CallFunc_LblECX, "???") 154 | control_setCaption(CallFunc_LblEDX, "???") 155 | control_setCaption(CallFunc_LblESI, "???") 156 | control_setCaption(CallFunc_LblEDI, "???") 157 | control_setCaption(CallFunc_StackLbl, "Stack parameters unknown.") 158 | end 159 | end 160 | 161 | function EmptyStrIfNil(str) 162 | if str == nil then return "" else return str end 163 | end 164 | 165 | control_setEnabled(CallFunc_Call, false) 166 | LoadFunctionList() 167 | fc_stack = {} 168 | fc_show_retval = false -------------------------------------------------------------------------------- /sa2lua/objfile.lua: -------------------------------------------------------------------------------- 1 | function ReadSpawnListFromFile(file) 2 | local list = {} 3 | local cols = {} 4 | local req_cols = {"name", "routine", "flags", "list", "xpos", "ypos", "zpos", 5 | "xrot", "yrot", "zrot", "xscl", "yscl", "zscl"} 6 | local noerror = true 7 | local line1 = file:read() 8 | for i,v in ipairs(line1:split(",")) do 9 | cols[string.lower(v)] = i 10 | end 11 | for i,v in ipairs(req_cols) do 12 | if cols[v] == nil then 13 | messageDialog("Required column "..v.." is missing!", mtError, mbOK) 14 | noerror = false 15 | break 16 | end 17 | end 18 | while noerror do 19 | local line = file:read() 20 | if line == nil then break end -- check for eof 21 | local objdata = {} 22 | local linesplit = line:split(",") 23 | objdata.name = linesplit[cols["name"]] 24 | objdata.routine = tonumber(linesplit[cols["routine"]], 16) 25 | objdata.flags = tonumber(linesplit[cols["flags"]], 16) 26 | objdata.list = tonumber(linesplit[cols["list"]], 16) 27 | objdata.px = tonumber(linesplit[cols["xpos"]]) 28 | objdata.py = tonumber(linesplit[cols["ypos"]]) 29 | objdata.pz = tonumber(linesplit[cols["zpos"]]) 30 | objdata.rx = tonumber(linesplit[cols["xrot"]], 16) 31 | objdata.ry = tonumber(linesplit[cols["yrot"]], 16) 32 | objdata.rz = tonumber(linesplit[cols["zrot"]], 16) 33 | objdata.sx = tonumber(linesplit[cols["xscl"]]) 34 | objdata.sy = tonumber(linesplit[cols["yscl"]]) 35 | objdata.sz = tonumber(linesplit[cols["zscl"]]) 36 | table.insert(list, objdata) 37 | end 38 | return list 39 | end 40 | 41 | function WriteSpawnedObjListToFile(file) 42 | local count = 0 43 | file:write("name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl\n") 44 | for i,v in ipairs(ol_spawned) do 45 | local line = "" 46 | line = line..v.name.."," 47 | line = line..num2hex(v.routine).."," 48 | line = line..num2hex(v.flags).."," 49 | line = line..num2hex(v.list).."," 50 | line = line..readFloat(GetObjData1(v.addr, 0x14)).."," 51 | line = line..readFloat(GetObjData1(v.addr, 0x18)).."," 52 | line = line..readFloat(GetObjData1(v.addr, 0x1C)).."," 53 | line = line..num2hex(readInteger(GetObjData1(v.addr, 0x08))).."," 54 | line = line..num2hex(readInteger(GetObjData1(v.addr, 0x0C))).."," 55 | line = line..num2hex(readInteger(GetObjData1(v.addr, 0x10))).."," 56 | line = line..readFloat(GetObjData1(v.addr, 0x20)).."," 57 | line = line..readFloat(GetObjData1(v.addr, 0x24)).."," 58 | line = line..readFloat(GetObjData1(v.addr, 0x28)) 59 | file:write(line.."\n") 60 | count = count + 1 61 | end 62 | return count 63 | end 64 | 65 | function SpawnNextObject() 66 | if #spawnqueue > 0 then 67 | if spawnqueueRotationMode > 0 then 68 | local angle_bams = spawnqueueAngleBAMS 69 | local angle = angle_bams * (math.pi / 0x8000) 70 | angle = -angle 71 | local x = spawnqueue[1].px 72 | local z = spawnqueue[1].pz 73 | spawnqueue[1].px = x*math.cos(angle) - z*math.sin(angle) 74 | spawnqueue[1].pz = x*math.sin(angle) + z*math.cos(angle) 75 | if spawnqueueRotationMode == 1 then 76 | spawnqueue[1].ry = (spawnqueue[1].ry + angle_bams) % 0x100000000 77 | end 78 | end 79 | 80 | spawnqueue[1].px = spawnqueue[1].px + spawnqueueOffsetX 81 | spawnqueue[1].py = spawnqueue[1].py + spawnqueueOffsetY 82 | spawnqueue[1].pz = spawnqueue[1].pz + spawnqueueOffsetZ 83 | 84 | SpawnFromObjData(spawnqueue[1]) 85 | table.remove(spawnqueue, 1) 86 | end 87 | end 88 | 89 | function SpawnFromObjData(objdata) 90 | SpawnObject(objdata.routine, objdata.name, objdata.flags, objdata.list, true, 91 | objdata.px, objdata.py, objdata.pz, objdata.rx, objdata.ry, objdata.rz, 92 | objdata.sx, objdata.sy, objdata.sz, 0) 93 | end 94 | 95 | function LoadObjListClick(sender) 96 | local file = io.open(openDialog_execute(SpawnedObjList_OpenDlg)) 97 | if file ~= nil then 98 | spawnqueue = ReadSpawnListFromFile(file) 99 | file:close() 100 | 101 | if SpawnedObjList_spawnRelative.Checked then 102 | spawnqueueOffsetX = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 103 | spawnqueueOffsetY = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 104 | spawnqueueOffsetZ = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 105 | spawnqueueRotationMode = SpawnedObjList_spawnRotated.State 106 | spawnqueueAngleBAMS = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x0C)) 107 | else 108 | spawnqueueOffsetX = 0 109 | spawnqueueOffsetY = 0 110 | spawnqueueOffsetZ = 0 111 | spawnqueueRotationMode = 0 112 | spawnqueueAngleBAMS = 0 113 | end 114 | 115 | SpawnNextObject() 116 | end 117 | end 118 | 119 | function SaveObjListClick(sender) 120 | local count 121 | local filename = openDialog_execute(SpawnedObjList_SaveDlg) 122 | local file 123 | if SpawnedObjList_SaveDlg.FilterIndex == 2 then 124 | file = io.open(filename, "w+b") 125 | else 126 | file = io.open(filename, "w+") 127 | end 128 | if file ~= nil then 129 | if SpawnedObjList_SaveDlg.FilterIndex == 2 then 130 | count = SETWriteFile(file, ol_spawned) 131 | else 132 | count = WriteSpawnedObjListToFile(file) 133 | end 134 | file:close() 135 | messageDialog("Wrote "..count.." objects", mtInformation, mbOK) 136 | end 137 | end 138 | 139 | function spawnRelativeChange(sender) 140 | SpawnedObjList_spawnRotated.Enabled = SpawnedObjList_spawnRelative.Checked 141 | end 142 | 143 | function spawnRotatedChange(sender) 144 | 145 | end 146 | 147 | -- CE 6.3 broke this function 148 | function openDialog_execute(od) 149 | if od.execute() then 150 | return od.Filename 151 | else 152 | return nil 153 | end 154 | end 155 | 156 | spawnqueue = {} 157 | spawnqueueOffsetX = 0 158 | spawnqueueOffsetY = 0 159 | spawnqueueOffsetZ = 0 160 | spawnqueueRotationMode = 0 161 | spawnqueueAngleBAMS = 0 162 | dofile("sa2lua/setexport.lua") -------------------------------------------------------------------------------- /sa2lua/tweaks.lua: -------------------------------------------------------------------------------- 1 | function ShowTweaksClick(sender) 2 | form_show(Tweaks) 3 | end 4 | 5 | function BtnTestLevelClick(sender) 6 | writeBytes(0x43C983, 0xEB) 7 | end 8 | 9 | function BtnDebugMenuChange(sender) 10 | if checkbox_getState(sender) == cbChecked then 11 | writeBytes(0x434687, 0x98, 0x8F) 12 | else 13 | writeBytes(0x434687, 0xCC, 0x76) 14 | end 15 | end 16 | 17 | function BtnDebugHelpClick(sender) 18 | shellExecute("http://info.sonicretro.org/Game_Secrets:Sonic_Adventure_2#Debug_Menu") 19 | end 20 | 21 | function BtnAltCharFixClick() 22 | -- Somersault fix 23 | writeBytes(0x717F6A, 0x90, 0xE9) 24 | writeBytes(0x720BAE, 0xEB) 25 | -- Chao model fix 26 | writeBytes(0x44E63B, 0x90, 0x90) 27 | writeBytes(0x741690, 0xEB) 28 | writeBytes(0x7416DC, 0xEB) 29 | -- Tails/Eggman fix 30 | writeBytes(0x43CA0C, 0x07) 31 | writeBytes(0x43CA46, 0x06) 32 | writeBytes(0x43CA92, 0x03) 33 | writeBytes(0x43CAD6, 0x02) 34 | -- SFX/voice fixes 35 | writeBytes(0x459110, 0x90, 0x90) 36 | writeBytes(0x45913B, 0x90, 0x90) 37 | -- Enable characters in 1P 38 | writeBytes(0x716E13, 0x90, 0x90) -- Amy 39 | writeBytes(0x717373, 0x90, 0x90) -- Metal Sonic 40 | writeBytes(0x728123, 0x90, 0x90) -- Tikal 41 | writeBytes(0x728473, 0x90, 0x90) -- Chaos 0 42 | writeBytes(0x740C61, 0x90, 0x90) -- Dark Chao Walker 43 | writeBytes(0x740EC1, 0x90, 0x90) -- Chao Walker 44 | -- Amy Spin Dash 45 | writeBytes(0x723E1F, 0x90, 0x90) -- Amy Spindash 46 | writeBytes(0x725257, 0xEB) -- Ancient Light Off 47 | writeBytes(0x725E76, 0xEB) -- Ancient Light Off 48 | end 49 | 50 | function BossBoundsBtnChange(sender) 51 | if checkbox_getState(sender) == cbChecked then 52 | writeBytes(0x5C6650, 0xC3) -- big foot 53 | writeBytes(0x5C6260, 0xC3) -- hot shot / flying dog 54 | writeBytes(0x60ABE0, 0xC3) -- king boom boo 55 | writeBytes(0x4BB2F0, 0xC3) -- egg golem 56 | writeBytes(0x46C6D0, 0xC3) -- biolizard / final hazard 57 | else 58 | writeBytes(0x5C6650, 0x83) -- big foot 59 | writeBytes(0x5C6260, 0x8B) -- hot shot / flying dog 60 | writeBytes(0x60ABE0, 0x55) -- king boom boo 61 | writeBytes(0x4BB2F0, 0x83) -- egg golem 62 | writeBytes(0x46C6D0, 0x8B) -- biolizard / final hazard 63 | end 64 | end 65 | 66 | function ObjLayoutBtnClick(sender) 67 | if objLayout == "Default" then objLayout = "1P" 68 | elseif objLayout == "1P" then objLayout = "2P" 69 | elseif objLayout == "2P" then objLayout = "Hard" 70 | else objLayout = "Default" end 71 | SetObjectLayout() 72 | control_setCaption(sender, "* Object Layout ["..objLayout.."]") 73 | end 74 | 75 | function SetObjectLayout() 76 | if objLayout == "1P" then 77 | writeBytes(0x488FAB, 0x90, 0xE9, 0x85, 0x00, 0x00, 0x00) 78 | writeBytes(0x48903D, 0xEB, 0x4C) 79 | elseif objLayout == "2P" then 80 | writeBytes(0x488FAB, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90) 81 | writeBytes(0x48903D, 0xEB, 0x4C) 82 | elseif objLayout == "Hard" then 83 | writeBytes(0x488FAB, 0x90, 0xE9, 0x85, 0x00, 0x00, 0x00) 84 | writeBytes(0x48903D, 0x90, 0x90) 85 | else -- Default layout 86 | writeBytes(0x488FAB, 0x0F, 0x84, 0x85, 0x00, 0x00, 0x00) 87 | writeBytes(0x48903D, 0x75, 0x4C) 88 | end 89 | end 90 | 91 | function NoKillPlanesBtnChange(sender) 92 | if checkbox_getState(sender) == cbChecked then 93 | writeBytes(0x46AD50, 0xC3) 94 | else 95 | writeBytes(0x46AD50, 0x55) 96 | end 97 | end 98 | 99 | function DontUnloadObjectsBtnChange(sender) 100 | if checkbox_getState(sender) == cbChecked then 101 | writeBytes(0x488D83, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90) 102 | else 103 | writeBytes(0x488D83, 0xC7, 0x42, 0x10, 0x20, 0xF7, 0x46, 0x00) 104 | end 105 | end 106 | 107 | function SSSDChaoWorldBtnClick(sender) 108 | if checkbox_getState(sender) == cbChecked then 109 | writeBytes(0x7238EB, 0x90, 0x90) 110 | else 111 | writeBytes(0x7238EB, 0x74, 0xC0) 112 | end 113 | end 114 | 115 | function SSShowAllStagesBtnChange(sender) 116 | if checkbox_getState(sender) == cbChecked then 117 | writeBytes(0x6773BC, 0xB3, 0x01, 0x90) 118 | else 119 | writeBytes(0x6773BC, 0x0F, 0x95, 0xC3) 120 | end 121 | end 122 | 123 | function SSCharSelectBtnChange(sender) 124 | if checkbox_getState(sender) == cbChecked then 125 | writeBytes(0x676648, 0xEB) 126 | writeBytes(0x6782DA, 0x3D) 127 | else 128 | writeBytes(0x676648, 0x74) 129 | writeBytes(0x6782DA, 0x35) 130 | end 131 | end 132 | 133 | function AlwaysARankBtnChange(sender) 134 | if checkbox_getState(sender) == cbChecked then 135 | writeBytes(0x44F799, 0x90, 0x90) 136 | writeBytes(0x450688, 0x90, 0x90) 137 | else 138 | writeBytes(0x44F799, 0x72, 0x08) 139 | writeBytes(0x450688, 0x7F, 0x1C) 140 | end 141 | end 142 | 143 | function PreventValueChangeBtnChange(sender) 144 | if checkbox_getState(sender) == cbChecked then 145 | writeBytes(0x464DD8, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90) --ground accel 146 | writeBytes(0x459967, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90) --gravity 147 | writeBytes(0x52B035, 0x90, 0x90, 0x90, 0x90, 0x90) 148 | writeBytes(0x52B515, 0x90, 0x90, 0x90, 0x90, 0x90) 149 | writeBytes(0x52AE9E, 0x90, 0x90, 0x90, 0x90, 0x90) 150 | else 151 | writeBytes(0x464DD8, 0xD9, 0x82, 0x24, 0x92, 0x73, 0x01, 0xD9, 0x99, 0xFC, 0x00, 0x00, 0x00) --ground accel 152 | writeBytes(0x459967, 0xD9, 0x82, 0x60, 0x92, 0x73, 0x01, 0xD9, 0x99, 0x38, 0x01, 0x00, 0x00) --gravity 153 | writeBytes(0x52B035, 0xA3, 0x6C, 0x04, 0x34, 0x01) 154 | writeBytes(0x52B515, 0xA3, 0x6C, 0x04, 0x34, 0x01) 155 | writeBytes(0x52AE9E, 0xA3, 0x6C, 0x04, 0x34, 0x01) 156 | end 157 | end 158 | 159 | function FastLoadingBtnClick(sender) 160 | if checkbox_getState(sender) == cbChecked then 161 | writeBytes(0x43A889, 0x03) 162 | else 163 | writeBytes(0x43A889, 0x01) 164 | end 165 | end 166 | 167 | function FixLvlBoundariesBtnClick(sender) 168 | if checkbox_getState(sender) == cbChecked then 169 | writeBytes(0x737B50, 0x31, 0xC0, 0xC3) 170 | else 171 | writeBytes(0x737B50, 0x83, 0xEC, 0x54) 172 | end 173 | end 174 | 175 | function EnemiesDropRingsBtnChange(sender) 176 | if checkbox_getState(sender) == cbChecked then 177 | writeBytes(0x513FF1, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90) 178 | writeBytes(0x514015, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90) 179 | else 180 | writeBytes(0x513FF1, 0x0F, 0x85, 0xFC, 0x00, 0x00, 0x00) 181 | writeBytes(0x514015, 0x0F, 0x85, 0xD1, 0x00, 0x00, 0x00) 182 | end 183 | end 184 | 185 | objLayout = "Default" 186 | SetObjectLayout() -------------------------------------------------------------------------------- /sa2lua/common.lua: -------------------------------------------------------------------------------- 1 | dofile("sa2lua/bitwise.lua") 2 | 3 | function num2hex(num) 4 | -- Adapted from http://snipplr.com/view/13086/number-to-hex/ 5 | if num ~= nil then 6 | local hexstr = '0123456789ABCDEF' 7 | local s = '' 8 | if num < 0 then 9 | num = 0xFFFFFFFF - (math.abs(num) - 1) 10 | end 11 | while num > 0 do 12 | local mod = math.fmod(num, 16) 13 | s = string.sub(hexstr, mod+1, mod+1) .. s 14 | num = math.floor(num / 16) 15 | end 16 | if s == '' then s = '0' end 17 | return s 18 | else 19 | return "" 20 | end 21 | end 22 | 23 | function OpenCaptionAddress(sender) 24 | local addr = tonumber(control_getCaption(sender), 16) 25 | if addr ~= nil then 26 | local memview = getMemoryViewForm() 27 | local hexview = memoryview_getHexadecimalView(memview) 28 | hexadecimalview_setTopAddress(hexview, addr) 29 | form_show(memview) 30 | end 31 | end 32 | 33 | function LoadBinaryFile(filename, address) 34 | local file = io.open(filename, "rb") 35 | if file == nil then 36 | print("Error opening file "..filename.."!") 37 | return nil 38 | end 39 | local data = file:read("*all") 40 | local length = string.len(data) 41 | file:close() 42 | for i=1,length do 43 | local addr = address - 1 + i 44 | writeBytes(addr, string.byte(data, i)) 45 | end 46 | return length 47 | end 48 | 49 | function alloc(size, name) 50 | if name == nil then name = "luatemp" end 51 | autoAssemble([[ 52 | alloc(]]..name..[[, ]]..size..[[) 53 | registersymbol(]]..name..[[) 54 | ]]) 55 | return getAddress("luatemp") 56 | end 57 | 58 | --[[function AllocateString(str) 59 | local addr = allocateSharedMemory("String:"..str, string.len(str) + 1) 60 | writeString(addr, str) 61 | --print("Wrote \""..str.."\" to 0x"..num2hex(addr)) 62 | return addr 63 | end]] 64 | 65 | function AllocateString(str) 66 | local bytesNeeded = string.len(str) + 1 67 | if bytesNeeded > str_alloc_bytesLeft or readInteger(str_alloc_addr) == nil then 68 | str_alloc_reset() 69 | end 70 | str_alloc_bytesLeft = str_alloc_bytesLeft - bytesNeeded 71 | writeString(str_alloc_addr, str) 72 | str_alloc_addr = str_alloc_addr + bytesNeeded 73 | return str_alloc_addr - bytesNeeded 74 | end 75 | 76 | function string:split(delimiter) 77 | -- This function was written by krsk9999 on Stack Overflow 78 | -- http://stackoverflow.com/questions/1426954/split-string-in-lua 79 | local result = { } 80 | local from = 1 81 | local delim_from, delim_to = string.find( self, delimiter, from ) 82 | while delim_from do 83 | table.insert( result, string.sub( self, from , delim_from-1 ) ) 84 | from = delim_to + 1 85 | delim_from, delim_to = string.find( self, delimiter, from ) 86 | end 87 | table.insert( result, string.sub( self, from ) ) 88 | return result 89 | end 90 | 91 | function SetAndFreezeValue(desc, val) 92 | local alist = getAddressList() 93 | local mrec = addresslist_getMemoryRecordByDescription(alist, desc) 94 | memoryrecord_freeze(mrec, 0) 95 | memoryrecord_setValue(mrec, val) 96 | end 97 | 98 | function UnfreezeValue(desc) 99 | local alist = getAddressList() 100 | local mrec = addresslist_getMemoryRecordByDescription(alist, desc) 101 | memoryrecord_unfreeze(mrec) 102 | end 103 | 104 | function UpdateTimer(sender) 105 | local controls = readInteger(0x1A529EC) 106 | OLCheckForDeletedObjects() 107 | OLUpdateDistances() 108 | if checkbox_getState(ObjectChain_AutoUpdate) == cbUnchecked then 109 | OCUpdateControls() 110 | end 111 | if UpdateObjectSelCube ~= nil then UpdateObjectSelCube() end 112 | CheckForSpawnedObject() 113 | CheckForFCReturnValue() 114 | UpdateCollisionButtonCaption() 115 | if controls ~= nil then 116 | if Bitwise.bw_and(controls, 0x08080000) then 117 | local addr = readInteger(readInteger(0x1DEA6E0)) 118 | if addr ~= nil then 119 | writeBytes(readInteger(addr + 0x34), 58) 120 | end 121 | end 122 | end 123 | 124 | UpdateObjectListRecords() 125 | EnableLineDrawingIfNecessary() 126 | 127 | if IsLineDrawingEnabled() and IsPlayerValid() then 128 | local x = tonumber(control_getCaption(SpawnObjectDlg_OffX)) 129 | local y = tonumber(control_getCaption(SpawnObjectDlg_OffY)) 130 | local z = tonumber(control_getCaption(SpawnObjectDlg_OffZ)) 131 | local notZero = (x ~= 0 or y ~= 0 or z ~= 0) 132 | 133 | if x ~= nil and y ~= nil and z ~= nil then 134 | x = x + readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 135 | y = y + readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 136 | z = z + readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 137 | if notZero then 138 | DrawCursor3D("OffsetCursor", x, y, z, 5, ldcRed) 139 | else 140 | RemoveCursor("OffsetCursor") 141 | end 142 | end 143 | end 144 | 145 | UpdateControllerState() 146 | HandleControllerState() 147 | OMKDrawObjects() 148 | UpdateLineList() 149 | InfoDispUpdate() 150 | LDLineListTemp = {} 151 | end 152 | 153 | function IsPlayerValid() 154 | local addr = readInteger(readInteger(0x1DEA6E0)) 155 | return (addr ~= nil) 156 | end 157 | 158 | function readWord(addr) 159 | local lo = readBytes(addr, 1, false) 160 | local hi = readBytes(addr+1, 1, false) 161 | return 256*hi + lo 162 | end 163 | 164 | function round(num, idp) 165 | -- Taken from http://lua-users.org/wiki/SimpleRound 166 | local mult = 10^(idp or 0) 167 | return math.floor(num * mult + 0.5) / mult 168 | end 169 | 170 | function debugger_onBreakpoint() 171 | local func = BreakpointCallbackTbl[EIP] 172 | if func == nil then 173 | return 0 174 | else 175 | return func() 176 | end 177 | end 178 | 179 | -- Check for the correct version of Cheat Engine 180 | 181 | if getCEVersion() < 6.3 then 182 | local msg = [[You are currently running Cheat Engine ]]..tostring(getCEVersion())..[[. 183 | 184 | If you do not upgrade to Cheat Engine 6.3, certain functionality (object list load/save) will not work correctly. If you do not need this functionality, you may disregard this message. 185 | 186 | Open the Cheat Engine download page now?]] 187 | 188 | if messageDialog(msg, mtExclamation, mbYes, mbNo) == mrYes then 189 | shellExecute("http://www.cheatengine.org/downloads.php") 190 | end 191 | end 192 | 193 | function str_alloc_reset() 194 | str_alloc_bytesLeft = 0x10000 195 | str_alloc_addr = allocateSharedMemory("AllocateString", str_alloc_bytesLeft) 196 | end 197 | 198 | str_alloc_reset() 199 | 200 | if BreakpointCallbackTbl == nil then BreakpointCallbackTbl = {} end 201 | str_alloc_bytesLeft = 0x10000 202 | str_alloc_addr = allocateSharedMemory("AllocateString", str_alloc_bytesLeft) 203 | controller = {} 204 | 205 | dofile("sa2lua/objenum.lua") -------------------------------------------------------------------------------- /Sample Object Lists/Metal Harbor Autopilot.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | Dash Panel,6CFBF0,2,2,10.136569976807,-299,-1563.9920654297,0,8000,0,50,1,1 3 | Dash Panel,6CFBF0,2,2,42.597549438477,13.653718948364,-1739.6791992188,4800,FFFF8000,0,1,1,1 4 | Spring (Type B),6C4E90,2,2,5.1298828125,-25.397308349609,-1859.6534423828,E800,0,B000,1,10,0 5 | Spring (Type B),6C4E90,2,2,441.42471313477,-230.6291809082,-2176.6694335938,1000,0,A000,3,1,0 6 | Dash Panel,6CFBF0,2,2,488.22952270508,-269,-2129.6579589844,0,4000,0,4,1,1 7 | Dash Panel,6CFBF0,2,2,1210.9686279297,-149.56526184082,-2168.7404785156,0,4000,FDE7,3,1,1 8 | Dash Panel,6CFBF0,2,2,1453.1986083984,-299,-2163.5034179688,0,4000,0,3,1,1 9 | Dash Panel,6CFBF0,F,2,1453.1986083984,-299,-2163.5034179688,0,4000,0,3,1,1 10 | Dash Panel,6CFBF0,F,2,1517.1986083984,-299,-2163.5034179688,0,4000,0,3,1,1 11 | Dash Panel,6CFBF0,F,2,1597.1986083984,-299,-2163.5034179688,0,4000,0,3,1,1 12 | Dash Panel,6CFBF0,F,2,1597.1986083984,-299,-2163.5034179688,0,4000,0,3,1,1 13 | Dash Panel,6CFBF0,F,2,1657.1986083984,-299,-2163.5034179688,0,4000,0,5,1,1 14 | Dash Panel,6CFBF0,2,2,1170.0458984375,-149,-2132.3845214844,0,14FE4,0,3,1,1 15 | Spring (Type A),6C4480,2,2,1859.3765869141,-249,-2228.0412597656,0,F000,0,180,1,0 16 | Spring (Type B),6C4E90,2,2,1859.3765869141,-100.6329498291,-2228.0412597656,0,F000,C000,5,1,0 17 | Dash Panel,6CFBF0,2,2,2012.4809570313,-249,-2278.3981933594,0,3000,0,3,1,1 18 | Spring (Type B),6C4E90,2,2,2039.7037353516,-155.88354492188,-2269.2568359375,0,0,C000,1,1,0 19 | Rocket,6D4EA0,6,2,2152.7612304688,-209,-2269.2568359375,0,4184,0,2130.3762207031,-207,-2869.5827636719 20 | Launch Panel,6D7130,6,2,2130.7038574219,-270,-2862.0100097656,0,0,0,20,10,1 21 | Launch Panel,6D7130,6,2,2135.4711914063,-160,-3987.9904785156,0,2000,0,3,5,1 22 | Launch Panel,6D7130,6,2,1975.2679443359,-18.879964828491,-4125.2612304688,8000,8000,4000,3,5,1 23 | MSBRIMINI,6F67A0,6,2,1980,-330.27194213867,-3632,0,0,0,1,1,1 24 | SPRB ,6C4E90,2,2,1978.0899658203,406.94845581055,-3610.5107421875,0,0,0,1,50,0 25 | SPRB ,6C4E90,2,2,1978.0899658203,1168.7478027344,-3610.5107421875,A800,0,0,1,50,0 26 | SPRB ,6C4E90,2,2,1978.0899658203,-160.00018310547,-4960.4594726563,E000,0,F000,1,50,0 27 | SPRB ,6C4E90,2,2,2454.8225097656,890.14874267578,-6084.7065429688,C000,4000,2000,1,50,0 28 | MSBRISHORT,6F6770,6,2,2464,851.29193115234,-7292,0,0,0,1,50,1 29 | MSBRISHORT,6F6770,6,2,2464,853.29193115234,-7376,0,0,0,30,500,5 30 | KASOKU ,6CFBF0,2,2,2464.091796875,861.29193115234,-7256.630859375,0,8000,0,3,1,1 31 | KASOKU ,6CFBF0,2,2,2464.3649902344,863.29193115234,-7333.732421875,0,8000,0,3,1,1 32 | MSBRILONG,6F6740,6,2,2428.3649902344,695.1787109375,-7608.525390625,0,3000,0,1,1,1 33 | SPRB ,6C4E90,2,2,2465.6791992188,863.29193115234,-7370.8979492188,A800,0,0,1,1,0 34 | KASOKU ,6CFBF0,2,2,2465.794921875,705.1787109375,-7599.1723632813,0,3000,0,3,1,0 35 | KASOKU ,6CFBF0,F,2,2540,705.1787109375,-7568,0,3000,0,3,1,1 36 | KASOKU ,6CFBF0,2,2,2616,705.1787109375,-7536,0,3000,0,3,1,1 37 | SPRB ,6C4E90,2,2,2651.443359375,705.1787109375,-7521.75,0,0,F000,3,1,0 38 | MSBRISHORT,6F6770,6,2,2691.3996582031,638.06176757813,-7521.75,0,4000,0,3,1,1 39 | KASOKU ,6CFBF0,2,2,2705.4323730469,648.06176757813,-7514.2119140625,0,4000,0,3,1,1 40 | KASOKU ,6CFBF0,F,2,2705.4323730469,648.06176757813,-7514.2119140625,0,4000,0,3,1,1 41 | KASOKU ,6CFBF0,F,2,2705.4323730469,648.06176757813,-7530.2119140625,0,4000,0,3,1,1 42 | Rocket,6D4EA0,6,2,2754.1694335938,648.06176757813,-7521.8198242188,0,FFFFEB67,0,3568.029296875,258.06176757813,-7071.2661132813 43 | Dash Panel,6CFBF0,2,2,3564.90234375,215.5,-7073.9228515625,0,FFFF8000,0,6,1,1 44 | Launch Panel,6D7130,6,2,3566.6545410156,215.5,-7122.7333984375,0,0,0,3,1,1 45 | Dash Panel,6CFBF0,F,2,3566.6545410156,215.5,-7122.7333984375,0,0,0,3,1,1 46 | Dash Panel,6CFBF0,F,2,3548.90234375,215.5,-7073.9228515625,0,FFFF8000,0,6,1,1 47 | Launch Panel,6D7130,6,2,3560.5727539063,-223,-7771.224609375,0,E523,0,5,9,1 48 | Dash Panel,6CFBF0,2,2,3729.275390625,-73,-8005.98828125,0,9C15,0,4,1,1 49 | Dash Panel,6CFBF0,2,2,3703.9643554688,-73,-8039.689453125,0,7E6D,0,8,1,1 50 | Dash Panel,6CFBF0,2,2,3704.0671386719,-223,-8481.7998046875,0,8013,0,4,1,1 51 | Dash Panel,6CFBF0,2,2,3720.0671386719,-136.33395385742,-8986.3603515625,F000,8000,0,7,1,1 52 | Spring (Type B),6C4E90,2,2,3719.1381835938,-137.0343170166,-8902.8857421875,F000,0,0,1,1,0 53 | Dash Panel,6CFBF0,F,2,3700.0671386719,-136.33395385742,-8986.3603515625,F000,8000,0,7,1,1 54 | Dash Panel,6CFBF0,F,2,3740.0671386719,-136.33395385742,-8986.3603515625,F000,8000,0,7,1,1 55 | MSBRIMINI,6F67A0,6,2,1980,-330.27194213867,-3672,0,0,0,1,1,1 56 | Triple Spring,6D9310,2,2,1974.8421630859,-320.27194213867,-3629.978515625,0,4000,0,180,20,1 57 | Dash Panel,6CFBF0,F,2,3741.275390625,-73,-8013.98828125,0,9C15,0,4,1,1 58 | Spring (Type B),6C4E90,2,2,1986.8515625,409.86325073242,-3637.0393066406,4000,0,0,1,1,0 59 | Dash Panel,6CFBF0,F,2,3724.0671386719,-223,-8481.7998046875,0,8013,0,4,1,1 60 | Dash Panel,6CFBF0,F,2,3744.0671386719,-223,-8481.7998046875,0,8013,0,4,1,1 61 | Dash Panel,6CFBF0,2,2,3715.0324707031,-187.42970275879,-9262.09375,FA39,7545,E689,6,1,1 62 | Dash Panel,6CFBF0,2,2,3856.5766601563,-240.35639953613,-9389.4951171875,2B,379C,F5CF,6,1,1 63 | Triple Spring,6D9310,2,2,4056.7119140625,-269,-9389.82421875,0,FFFFC000,0,6,1,1 64 | Triple Spring,6D9310,2,2,4045.9382324219,74.821350097656,-9389.9541015625,8000,4000,1800,6,1,1 65 | Launch Panel,6D7130,6,2,4315.55078125,-268.9992980957,-9394.2255859375,0,DE23,0,6,8,1 66 | Dash Panel,6CFBF0,2,2,4759.623046875,-181,-9934.64453125,0,8000,0,7,1,1 67 | Dash Panel,6CFBF0,2,2,4763.5,-181,-10209.020507813,0,8000,0,7,1,1 68 | Dash Panel,6CFBF0,2,2,4756.5502929688,-181,-10371.581054688,0,4000,0,8,1,1 69 | Dash Panel,6CFBF0,2,2,5069.9301757813,-181,-10369.99609375,0,0,0,8,1,1 70 | Dash Panel,6CFBF0,2,2,4870.376953125,-76.943313598633,-10066.185546875,0,C000,E79F,5,1,1 71 | Dash Panel,6CFBF0,2,2,4760.048828125,-31,-10315.75,0,8000,0,5,1,1 72 | Dash Panel,6CFBF0,2,2,4760.7934570313,-31,-10373.852539063,0,4000,0,5,1,1 73 | Dash Panel,6CFBF0,2,2,4916.119140625,-31,-10374.99609375,0,0,0,5,1,1 74 | Triple Spring,6D9310,2,2,8268.6064453125,-231,-10409.278320313,0,FFFFB900,0,1,1,1 75 | Spring (Type B),6C4E90,2,2,8256.869140625,-75.847137451172,-10407.28515625,4000,0,0,1,5,0 76 | Spring (Type B),6C4E90,F,2,8252.869140625,-75.847137451172,-10327.28515625,0,0,C000,1,5,0 77 | Dash Panel,6CFBF0,2,2,8783.7451171875,-170,-10325.990234375,0,6AA,0,6,1,1 78 | LINKLINK,6E6EB0,2,2,2130.6391601563,-163.0654296875,-3373.2795410156,0,5,0,50,50,50 79 | LINKLINK,6E6EB0,2,2,1988.1081542969,145.81803894043,-3989.7983398438,0,2,0,50,50,50 80 | LINKLINK,6E6EB0,2,2,1978.0899658203,975.10333251953,-3610.5107421875,0,7,0,50,50,50 81 | LINKLINK,6E6EB0,2,2,1978.0899658203,345.21142578125,-4464.4697265625,0,8,0,50,50,50 82 | LINKLINK,6E6EB0,2,2,2326.30078125,609.74188232422,-5764.8950195313,0,0,A,50,50,50 83 | -------------------------------------------------------------------------------- /sa2lua/hook.asm: -------------------------------------------------------------------------------- 1 | ; Assemble with nasm 2 | bits 32 3 | LoadObject2: equ 0x46F610 4 | StackCountStorage: equ 0x42C645 ; Start address of four bytes unused by SA2 5 | 6 | ; Store the address of the command region in ebp 7 | push ebp 8 | mov ebp,0xDEADBEEF ;will be overwritten by Lua script 9 | 10 | ; Push some registers to be restored later 11 | push eax 12 | push ecx 13 | push esi 14 | push edi 15 | 16 | mov dword ebx,[ebp] ; Store the command to be executed in ebx 17 | cmp ebx,1 ; If the command = 1... 18 | je SpawnObject ; ...jump to the object spawning code. 19 | cmp ebx,2 ; If the command = 2... 20 | je CallFunction ; ...jump to the generic function calling code. 21 | 22 | Done: 23 | mov [ebp],ebx ; Change the opcode value in memory according to 24 | ; ebx, which is where the jumps above store it. 25 | 26 | ; Restore the registers from above 27 | pop edi 28 | pop esi 29 | pop ecx 30 | pop eax 31 | pop ebp 32 | 33 | jmp ReplacedCode ; Jump to the sonic2app.exe code that was replaced 34 | 35 | ; What follows are the sections of code for specific commands. 36 | ; Command for spawning objects: 37 | SpawnObject: 38 | push ebx ; Save the opcode value for later 39 | mov edi,[ebp+0x04] ; edi = object routine 40 | mov eax,[ebp+0x08] ; eax = pointer to object name 41 | mov ebx,[ebp+0x0C] ; Store the flags value... 42 | and ebx,0xFF ; (we only want one byte) 43 | push ebx ; ...and push it to the stack. 44 | mov ecx,[ebp+0x0D] ; ecx = object list ID 45 | mov ebx,LoadObject2 ; Spawn the object; now eax -> ObjectMaster 46 | call ebx ; (We need to put it in ebx so it's an absolute address.) 47 | add esp,4 ; Remove that flags value from the stack 48 | 49 | ; Now we need to add the object's parameters (rotation, position, scale.) 50 | mov edi,[eax+0x34] ; edi = location to store parameters 51 | test edi,edi ; Check if edi = 0... 52 | jz NoSpawnParams ; ...if so, skip this part. 53 | add edi,8 ; Rot/Pos/Scl start at ObjData1 + 0x08 54 | lea esi,[ebp+0x11] ; esi = source location for parameters 55 | 56 | mov ecx,9 ; Do the following 9 times: 57 | SetParamsLoop: 58 | mov ebx,[esi] ; Take the parameter from memory... 59 | mov [edi],ebx ; ...and copy it to the object's parameters. 60 | add esi,4 ; Now move to the next parameter. 61 | add edi,4 ; ^ 62 | loop SetParamsLoop ; ...and do it again. (end of loop) 63 | 64 | NoSpawnParams: ; we're done setting the parameters 65 | 66 | ; Many objects (such as enemies) require a certain structure pointed to by 67 | ; ObjectMaster + 0x30 or it will crash. This will take care of that: 68 | ; First, we'll allocate memory for the SETEntry structure it contains. 69 | 70 | mov edi,eax ; Save the ObjectMaster pointer; we still need it! 71 | mov eax,0x20 ; The SETEntry structure is 32 bytes. 72 | call AllocMem ; Allocate memory; store address in eax 73 | mov word [eax],0 ; Just set the object ID to zero 74 | xor ebx,ebx ; Set ebx to 00000000 75 | mov bx,[ebp+0x11] ; Take the X rotation value...(2 bytes) 76 | mov [eax+0x02],bx ; ...and put it in the SETEntry structure. 77 | mov bx,[ebp+0x15] ; Same with the Y rotation value. 78 | mov [eax+0x04],bx ; ^ 79 | mov bx,[ebp+0x19] ; Same with the Z rotation value. 80 | mov [eax+0x06],bx ; ^ 81 | mov ebx,[ebp+0x1D] ; Take the X position value...(4 bytes) 82 | mov [eax+0x08],ebx ; ...and put it in the SETEntry structure. 83 | mov ebx,[ebp+0x21] ; Same with the Y position value. 84 | mov [eax+0x0C],ebx ; ^ 85 | mov ebx,[ebp+0x25] ; Same with the Z position value. 86 | mov [eax+0x10],ebx ; ^ 87 | mov ebx,[ebp+0x29] ; Same with the X scale value. 88 | mov [eax+0x14],ebx ; ^ 89 | mov ebx,[ebp+0x2D] ; Same with the Y scale value. 90 | mov [eax+0x18],ebx ; ^ 91 | mov ebx,[ebp+0x31] ; Same with the Z scale value. 92 | mov [eax+0x1C],ebx ; ...and the structure is full. 93 | 94 | ; Now we'll allocate the actual structure at 0x30. Only the parts of the struct 95 | ; that actually change each time it's filled will be identified. 96 | mov esi,eax ; We'll need eax again, so save the SETEntry address. 97 | mov eax,0x10 ; This structure is 16 bytes. 98 | call AllocMem ; Allocate memory; store address in eax 99 | mov byte [eax],1 100 | mov byte [eax+0x01],0 101 | mov word [eax+0x02],0x8001 102 | mov [eax+0x04],edi ; Store the ObjectMaster address 103 | mov [eax+0x08],esi ; Store the SETEntry address 104 | mov dword [eax+0x0C],0 105 | mov [edi+0x30],eax ; And set ObjectMaster + 0x30 to point here. 106 | 107 | ; Done! Now we'll just finish up: 108 | mov [ebp+0x04],edi ; Store the ObjectMaster address in memory 109 | pop ebx ; Get our opcode back 110 | neg ebx ; Negate it to let Cheat Engine know the address is there 111 | jmp Done ; And jump back to the main code. 112 | 113 | ; Command for calling any function: 114 | CallFunction: 115 | push ebx ; Save the opcode value for later 116 | push edx ; Preserve the value of edx 117 | push ebp ; We'll also need to use ebp for another purpose. 118 | mov ecx,[ebp+0x20] ; Set the loop counter to the stack count 119 | mov [StackCountStorage],ecx ; Save the number of values we'll push 120 | test ecx,ecx ; Check if we don't have anything to push... 121 | jz NothingInStack ; ...if so, skip this part. 122 | lea esi,[ebp+0x24] ; Store the address of the stack array 123 | CFPushLoop: ; Stack-filling loop begins here 124 | push dword [esi] ; Push the value from memory 125 | add esi,4 ; Move the pointer to the next value 126 | loop CFPushLoop ; Loop according to ecx 127 | NothingInStack: ; If there wasn't anything to push, start here. 128 | 129 | ; Now we'll fill the registers according to the values in memory. 130 | mov eax,[ebp+0x08] 131 | mov ebx,[ebp+0x0C] 132 | mov ecx,[ebp+0x10] 133 | mov edx,[ebp+0x14] 134 | mov esi,[ebp+0x18] 135 | mov edi,[ebp+0x1C] 136 | 137 | ; Since eax, ebx, ecx, edx, esi, and edi are used, we need to overwrite ebp. 138 | mov ebp,[ebp+0x04] ; Store the function to call 139 | call ebp ; Actually call said function 140 | 141 | ; Now we'll get our parameters out of the stack, but first we need to get the number 142 | ; of values we pushed back from memory. 143 | mov ecx,[StackCountStorage] ; Put the stack count back in ecx 144 | lea ecx,[ecx*4] ; Multiply it by 4 145 | add esp,ecx ; Remove the values from the stack 146 | pop ebp ; Restore the value of ebp 147 | mov [ebp+0x08],eax ; Put the return value from calling the function in memory 148 | 149 | ; Now we'll just finish up. 150 | pop edx ; Restore the value of edx 151 | pop ebx ; Restore the opcode value (in ebx) 152 | neg ebx ; Negate it to tell Cheat Engine the return value is in memory 153 | jmp Done ; Jump back to the main code. 154 | 155 | ;------------------------------------------------------------------------------------- 156 | ReplacedCode: 157 | ; The following five lines are from SA2's main code, and need to be here since 158 | ; the jump to my hook code replaces them in their original location. 159 | push ecx 160 | push ebx 161 | push ebp 162 | push esi 163 | push edi 164 | ; And now jump back to sonic2app.exe 165 | mov ebx,0x77E785 166 | jmp ebx 167 | 168 | AllocMem: 169 | ; This code just calls a function in SA2 to allocate a section of memory. Just 170 | ; set eax to the number of bytes you need, "call AllocMem", and then the address 171 | ; of the allocated memory will be stored in eax. 172 | push ecx 173 | push ebx 174 | mov ebx,[0x1D19CAC] 175 | mov ecx,[ebx] 176 | push 0 177 | push 0x8B9528 178 | push eax 179 | call ecx 180 | add esp,12 181 | pop ebx 182 | pop ecx 183 | ret 184 | -------------------------------------------------------------------------------- /sa2lua/linedraw.lua: -------------------------------------------------------------------------------- 1 | function EnableLineDrawingIfNecessary() 2 | if IsPlayerValid() then 3 | if trace then print("EnableLineDrawingIfNecessary called") end 4 | if readInteger(hookcmd) == nil then 5 | if trace then print("EnableLineDrawingIfNecessary enabling object spawning") end 6 | EnableObjectSpawning() 7 | end 8 | if not IsLineDrawingEnabled() then 9 | if trace then print("EnableLineDrawingIfNecessary enabling line drawing") end 10 | LDLineCodeAddr = allocateSharedMemory("DrawLine3DCode", 4096) 11 | LDLineListAddr = allocateSharedMemory("DrawLine3DList", 65536) 12 | readRegionFromFile("sa2lua/linedraw.bin", LDLineCodeAddr) 13 | CreateLineDrawingObject() 14 | else 15 | if FindObjectByName(1, "$Lua$DrawLine3D") == 0 then 16 | CreateLineDrawingObject() 17 | end 18 | end 19 | end 20 | end 21 | 22 | function CreateLineDrawingObject() 23 | SpawnObject(LDLineCodeAddr, "$Lua$DrawLine3D", 1, 1, true, 0,0,0,0,0,0,0,0,0,0) 24 | LDWaitingForObj = true 25 | end 26 | 27 | function IsLineDrawingEnabled() 28 | if LDLineCodeAddr == nil or LDLineListAddr == nil then 29 | LDWaitingForObj = false 30 | return false 31 | end 32 | if LDWaitingForObj then return true end 33 | if readString(readInteger(linedraw_objaddr + 0x44), 64) == "$Lua$DrawLine3D" then 34 | return readInteger(linedraw_objaddr) ~= linedraw_objaddr 35 | else 36 | return false 37 | end 38 | end 39 | 40 | function UpdateLineList() 41 | if not IsLineDrawingEnabled() then return end 42 | if trace then print("UpdateLineList called") end 43 | local count = 0 44 | local addr = LDLineListAddr+4 45 | for k,v in pairs(LDLineList) do 46 | writeFloat(addr, v.x1) 47 | writeFloat(addr+4, v.y1) 48 | writeFloat(addr+8, v.z1) 49 | writeFloat(addr+12, v.x2) 50 | writeFloat(addr+16, v.y2) 51 | writeFloat(addr+20, v.z2) 52 | writeInteger(addr+24, v.color) 53 | addr = addr + 28 54 | count = count + 1 55 | end 56 | for k,v in pairs(LDLineListTemp) do 57 | writeFloat(addr, v.x1) 58 | writeFloat(addr+4, v.y1) 59 | writeFloat(addr+8, v.z1) 60 | writeFloat(addr+12, v.x2) 61 | writeFloat(addr+16, v.y2) 62 | writeFloat(addr+20, v.z2) 63 | writeInteger(addr+24, v.color) 64 | addr = addr + 28 65 | count = count + 1 66 | end 67 | writeInteger(LDLineListAddr, count) 68 | end 69 | 70 | function DrawLineObjectCallback(addr) 71 | if trace then print("DrawLineObjectCallback called") end 72 | writeInteger(readInteger(addr + 0x38), LDLineListAddr) 73 | linedraw_objaddr = addr 74 | LDWaitingForObj = false 75 | end 76 | 77 | function DrawLine3DPerformRotation(line, axis1, axis2, ctr1, ctr2, angle) 78 | --Internal function used by DrawLine3D 79 | if angle ~= 0 then 80 | for i=1,2 do 81 | local x = line[axis1..tonumber(i)] - ctr1 82 | local y = line[axis2..tonumber(i)] - ctr2 83 | local th = math.rad(angle * (360 / 0x10000)) 84 | line[axis1..tonumber(i)] = (x*math.cos(th) - y*math.sin(th)) + ctr1 85 | line[axis2..tonumber(i)] = (x*math.sin(th) + y*math.cos(th)) + ctr2 86 | end 87 | end 88 | end 89 | 90 | function DrawLine3D(identifier, x1, y1, z1, x2, y2, z2, color, temp) 91 | local line = {} 92 | line.x1 = x1 93 | line.y1 = y1 94 | line.z1 = z1 95 | line.x2 = x2 96 | line.y2 = y2 97 | line.z2 = z2 98 | 99 | DrawLine3DPerformRotation(line, "x", "z", LDRotateCtrX, LDRotateCtrZ, LDRotateY) 100 | DrawLine3DPerformRotation(line, "y", "z", LDRotateCtrY, LDRotateCtrZ, LDRotateX) 101 | DrawLine3DPerformRotation(line, "x", "y", LDRotateCtrX, LDRotateCtrY, LDRotateZ) 102 | 103 | line.color = color 104 | if temp then 105 | LDLineListTemp[identifier] = line 106 | else 107 | LDLineList[identifier] = line 108 | end 109 | --UpdateLineList() 110 | end 111 | 112 | function RemoveLine(identifier) 113 | LDLineList[identifier] = nil 114 | --UpdateLineList() 115 | end 116 | 117 | function ClearLines() 118 | LDLineList = {} 119 | LDLineListTemp = {} 120 | --UpdateLineList() 121 | end 122 | 123 | function DrawCube3D(identifier, x1, y1, z1, x2, y2, z2, color, temp) 124 | --[[ 125 | -----+pt1 126 | /| /| 127 | |----| | 128 | |/---|-| 129 | pt2+----|/ 130 | ]] 131 | 132 | -- Top edges 133 | DrawLine3D(identifier.."1", x1, y1, z1, x1, y1, z2, color, temp) 134 | DrawLine3D(identifier.."2", x1, y1, z2, x2, y1, z2, color, temp) 135 | DrawLine3D(identifier.."3", x2, y1, z2, x2, y1, z1, color, temp) 136 | DrawLine3D(identifier.."4", x2, y1, z1, x1, y1, z1, color, temp) 137 | 138 | -- Bottom edges 139 | DrawLine3D(identifier.."5", x1, y2, z1, x1, y2, z2, color, temp) 140 | DrawLine3D(identifier.."6", x1, y2, z2, x2, y2, z2, color, temp) 141 | DrawLine3D(identifier.."7", x2, y2, z2, x2, y2, z1, color, temp) 142 | DrawLine3D(identifier.."8", x2, y2, z1, x1, y2, z1, color, temp) 143 | 144 | -- Side edges 145 | DrawLine3D(identifier.."9", x1, y1, z1, x1, y2, z1, color, temp) 146 | DrawLine3D(identifier.."10", x1, y1, z2, x1, y2, z2, color, temp) 147 | DrawLine3D(identifier.."11", x2, y1, z2, x2, y2, z2, color, temp) 148 | DrawLine3D(identifier.."12", x2, y1, z1, x2, y2, z1, color, temp) 149 | end 150 | 151 | function DrawCylinder3D(identifier, x, y, z, r, h, sides, color, temp) 152 | for i=0,sides-1 do 153 | local twopi = math.rad(360) 154 | local x1 = r * math.cos(i * twopi/sides) + x 155 | local z1 = r * math.sin(i * twopi/sides) + z 156 | local x2 = r * math.cos((i + 1) * twopi/sides) + x 157 | local z2 = r * math.sin((i + 1) * twopi/sides) + z 158 | DrawLine3D(identifier..tonumber(i).."b", x1, y-h/2, z1, x2, y-h/2, z2, color, temp) --bottom 159 | DrawLine3D(identifier..tonumber(i).."t", x1, y+h/2, z1, x2, y+h/2, z2, color, temp) --top 160 | DrawLine3D(identifier..tonumber(i).."s", x1, y-h/2, z1, x1, y+h/2, z1, color, temp) --side 161 | end 162 | end 163 | 164 | function RemoveCylinder(identifier, sides) 165 | for i=0,sides-1 do 166 | RemoveLine(identifier..tonumber(i).."b") 167 | RemoveLine(identifier..tonumber(i).."t") 168 | RemoveLine(identifier..tonumber(i).."s") 169 | end 170 | end 171 | 172 | function DrawCursor3D(identifier, x, y, z, r, color, temp) 173 | DrawLine3D(identifier.."X", x-r, y, z, x+r, y, z, color, temp) 174 | DrawLine3D(identifier.."Y", x, y-r, z, x, y+r, z, color, temp) 175 | DrawLine3D(identifier.."Z", x, y, z-r, x, y, z+r, color, temp) 176 | end 177 | 178 | function RemoveCursor(identifier) 179 | RemoveLine(identifier.."X") 180 | RemoveLine(identifier.."Y") 181 | RemoveLine(identifier.."Z") 182 | end 183 | 184 | function DrawCircle3D(identifier, x, y, z, r, sides, color, temp) 185 | for i=0,sides-1 do 186 | local twopi = math.rad(360) 187 | local x1 = r * math.cos(i * twopi/sides) + x 188 | local z1 = r * math.sin(i * twopi/sides) + z 189 | local x2 = r * math.cos((i + 1) * twopi/sides) + x 190 | local z2 = r * math.sin((i + 1) * twopi/sides) + z 191 | DrawLine3D(identifier..tonumber(i), x1, y, z1, x2, y, z2, color, temp) 192 | end 193 | end 194 | 195 | function RemoveCube(identifier) 196 | for i=1,12 do 197 | RemoveLine(identifier..tostring(i)) 198 | end 199 | end 200 | 201 | function LDResetRotation() 202 | LDRotateX = 0 --units for these variables are BAMS 203 | LDRotateY = 0 --perform rotation in order Y, X, Z 204 | LDRotateZ = 0 205 | LDRotateCtrX = 0 206 | LDRotateCtrY = 0 207 | LDRotateCtrZ = 0 208 | end 209 | 210 | LDLineList = {} 211 | LDLineListTemp = {} 212 | LDLineListAddr = nil 213 | LDLineCodeAddr = nil 214 | LDWaitingForObj = false 215 | LDResetRotation() 216 | 217 | ldcBlack = 0xFF000000 218 | ldcRed = 0xFFFF0000 219 | ldcOrange = 0xFFFF8000 220 | ldcYellow = 0xFFFFFF00 221 | ldcGreen = 0xFF00FF00 222 | ldcCyan = 0xFF00FFFF 223 | ldcBlue = 0xFF0000FF 224 | ldcPurple = 0xFF8000C0 225 | ldcMagenta = 0xFFFF00FF 226 | ldcWhite = 0xFFFFFFFF -------------------------------------------------------------------------------- /Sample Object Lists/Cheat Engine.csv: -------------------------------------------------------------------------------- 1 | Name,Routine,Flags,List,XPos,YPos,ZPos,XRot,YRot,ZRot,XScl,YScl,ZScl 2 | Iron Block,6D63F0,F,2,80,20,60,0,0,0,1,1,1 3 | Iron Block,6D63F0,F,2,100,20,60,0,0,0,1,1,1 4 | Iron Block,6D63F0,F,2,120,20,60,0,0,0,1,1,1 5 | Iron Block,6D63F0,F,2,160,20,60,0,0,0,1,1,1 6 | Iron Block,6D63F0,F,2,200,20,60,0,0,0,1,1,1 7 | Iron Block,6D63F0,F,2,240,20,60,0,0,0,1,1,1 8 | Iron Block,6D63F0,F,2,260,20,60,0,0,0,1,1,1 9 | Iron Block,6D63F0,F,2,280,20,60,0,0,0,1,1,1 10 | Iron Block,6D63F0,F,2,320,20,60,0,0,0,1,1,1 11 | Iron Block,6D63F0,F,2,340,20,60,0,0,0,1,1,1 12 | Iron Block,6D63F0,F,2,400,20,60,0,0,0,1,1,1 13 | Iron Block,6D63F0,F,2,440,20,60,0,0,0,1,1,1 14 | Iron Block,6D63F0,F,2,480,20,60,0,0,0,1,1,1 15 | Iron Block,6D63F0,F,2,500,20,60,0,0,0,1,1,1 16 | Iron Block,6D63F0,F,2,520,20,60,0,0,0,1,1,1 17 | Iron Block,6D63F0,F,2,120,40,60,0,0,0,1,1,1 18 | Iron Block,6D63F0,F,2,160,40,60,0,0,0,1,1,1 19 | Iron Block,6D63F0,F,2,200,40,60,0,0,0,1,1,1 20 | Iron Block,6D63F0,F,2,260,40,60,0,0,0,1,1,1 21 | Iron Block,6D63F0,F,2,320,40,60,0,0,0,1,1,1 22 | Iron Block,6D63F0,F,2,360,40,60,0,0,0,1,1,1 23 | Iron Block,6D63F0,F,2,400,40,60,0,0,0,1,1,1 24 | Iron Block,6D63F0,F,2,440,40,60,0,0,0,1,1,1 25 | Iron Block,6D63F0,F,2,520,40,60,0,0,0,1,1,1 26 | Iron Block,6D63F0,F,2,100,60,60,0,0,0,1,1,1 27 | Iron Block,6D63F0,F,2,120,60,60,0,0,0,1,1,1 28 | Iron Block,6D63F0,F,2,160,60,60,0,0,0,1,1,1 29 | Iron Block,6D63F0,F,2,200,60,60,0,0,0,1,1,1 30 | Iron Block,6D63F0,F,2,260,60,60,0,0,0,1,1,1 31 | Iron Block,6D63F0,F,2,320,60,60,0,0,0,1,1,1 32 | Iron Block,6D63F0,F,2,360,60,60,0,0,0,1,1,1 33 | Iron Block,6D63F0,F,2,400,60,60,0,0,0,1,1,1 34 | Iron Block,6D63F0,F,2,440,60,60,0,0,0,1,1,1 35 | Iron Block,6D63F0,F,2,500,60,60,0,0,0,1,1,1 36 | Iron Block,6D63F0,F,2,520,60,60,0,0,0,1,1,1 37 | Iron Block,6D63F0,F,2,120,80,60,0,0,0,1,1,1 38 | Iron Block,6D63F0,F,2,160,80,60,0,0,0,1,1,1 39 | Iron Block,6D63F0,F,2,200,80,60,0,0,0,1,1,1 40 | Iron Block,6D63F0,F,2,260,80,60,0,0,0,1,1,1 41 | Iron Block,6D63F0,F,2,360,80,60,0,0,0,1,1,1 42 | Iron Block,6D63F0,F,2,400,80,60,0,0,0,1,1,1 43 | Iron Block,6D63F0,F,2,440,80,60,0,0,0,1,1,1 44 | Iron Block,6D63F0,F,2,520,80,60,0,0,0,1,1,1 45 | Iron Block,6D63F0,F,2,80,100,60,0,0,0,1,1,1 46 | Iron Block,6D63F0,F,2,100,100,60,0,0,0,1,1,1 47 | Iron Block,6D63F0,F,2,120,100,60,0,0,0,1,1,1 48 | Iron Block,6D63F0,F,2,180,100,60,0,0,0,1,1,1 49 | Iron Block,6D63F0,F,2,200,100,60,0,0,0,1,1,1 50 | Iron Block,6D63F0,F,2,240,100,60,0,0,0,1,1,1 51 | Iron Block,6D63F0,F,2,260,100,60,0,0,0,1,1,1 52 | Iron Block,6D63F0,F,2,280,100,60,0,0,0,1,1,1 53 | Iron Block,6D63F0,F,2,320,100,60,0,0,0,1,1,1 54 | Iron Block,6D63F0,F,2,340,100,60,0,0,0,1,1,1 55 | Iron Block,6D63F0,F,2,420,100,60,0,0,0,1,1,1 56 | Iron Block,6D63F0,F,2,440,100,60,0,0,0,1,1,1 57 | Iron Block,6D63F0,F,2,480,100,60,0,0,0,1,1,1 58 | Iron Block,6D63F0,F,2,500,100,60,0,0,0,1,1,1 59 | Iron Block,6D63F0,F,2,520,100,60,0,0,0,1,1,1 60 | Iron Block,6D63F0,F,2,140,140,60,0,0,0,1,1,1 61 | Iron Block,6D63F0,F,2,200,140,60,0,0,0,1,1,1 62 | Iron Block,6D63F0,F,2,240,140,60,0,0,0,1,1,1 63 | Iron Block,6D63F0,F,2,280,140,60,0,0,0,1,1,1 64 | Iron Block,6D63F0,F,2,300,140,60,0,0,0,1,1,1 65 | Iron Block,6D63F0,F,2,320,140,60,0,0,0,1,1,1 66 | Iron Block,6D63F0,F,2,360,140,60,0,0,0,1,1,1 67 | Iron Block,6D63F0,F,2,400,140,60,0,0,0,1,1,1 68 | Iron Block,6D63F0,F,2,440,140,60,0,0,0,1,1,1 69 | Iron Block,6D63F0,F,2,460,140,60,0,0,0,1,1,1 70 | Iron Block,6D63F0,F,2,140,160,60,0,0,0,1,1,1 71 | Iron Block,6D63F0,F,2,200,160,60,0,0,0,1,1,1 72 | Iron Block,6D63F0,F,2,240,160,60,0,0,0,1,1,1 73 | Iron Block,6D63F0,F,2,320,160,60,0,0,0,1,1,1 74 | Iron Block,6D63F0,F,2,360,160,60,0,0,0,1,1,1 75 | Iron Block,6D63F0,F,2,400,160,60,0,0,0,1,1,1 76 | Iron Block,6D63F0,F,2,480,160,60,0,0,0,1,1,1 77 | Iron Block,6D63F0,F,2,140,180,60,0,0,0,1,1,1 78 | Iron Block,6D63F0,F,2,200,180,60,0,0,0,1,1,1 79 | Iron Block,6D63F0,F,2,220,180,60,0,0,0,1,1,1 80 | Iron Block,6D63F0,F,2,240,180,60,0,0,0,1,1,1 81 | Iron Block,6D63F0,F,2,300,180,60,0,0,0,1,1,1 82 | Iron Block,6D63F0,F,2,320,180,60,0,0,0,1,1,1 83 | Iron Block,6D63F0,F,2,360,180,60,0,0,0,1,1,1 84 | Iron Block,6D63F0,F,2,380,180,60,0,0,0,1,1,1 85 | Iron Block,6D63F0,F,2,400,180,60,0,0,0,1,1,1 86 | Iron Block,6D63F0,F,2,480,180,60,0,0,0,1,1,1 87 | Iron Block,6D63F0,F,2,140,200,60,0,0,0,1,1,1 88 | Iron Block,6D63F0,F,2,200,200,60,0,0,0,1,1,1 89 | Iron Block,6D63F0,F,2,240,200,60,0,0,0,1,1,1 90 | Iron Block,6D63F0,F,2,320,200,60,0,0,0,1,1,1 91 | Iron Block,6D63F0,F,2,360,200,60,0,0,0,1,1,1 92 | Iron Block,6D63F0,F,2,400,200,60,0,0,0,1,1,1 93 | Iron Block,6D63F0,F,2,480,200,60,0,0,0,1,1,1 94 | Iron Block,6D63F0,F,2,120,220,60,0,0,0,1,1,1 95 | Iron Block,6D63F0,F,2,140,220,60,0,0,0,1,1,1 96 | Iron Block,6D63F0,F,2,160,220,60,0,0,0,1,1,1 97 | Iron Block,6D63F0,F,2,220,220,60,0,0,0,1,1,1 98 | Iron Block,6D63F0,F,2,280,220,60,0,0,0,1,1,1 99 | Iron Block,6D63F0,F,2,300,220,60,0,0,0,1,1,1 100 | Iron Block,6D63F0,F,2,320,220,60,0,0,0,1,1,1 101 | Iron Block,6D63F0,F,2,360,220,60,0,0,0,1,1,1 102 | Iron Block,6D63F0,F,2,400,220,60,0,0,0,1,1,1 103 | Iron Block,6D63F0,F,2,440,220,60,0,0,0,1,1,1 104 | Iron Block,6D63F0,F,2,460,220,60,0,0,0,1,1,1 105 | Glass,6D29F0,F,2,80,260,60,0,0,0,1,1,1 106 | Glass,6D29F0,F,2,100,260,60,0,0,0,1,1,1 107 | Glass,6D29F0,F,2,120,260,60,0,0,0,1,1,1 108 | Glass,6D29F0,F,2,140,260,60,0,0,0,1,1,1 109 | Glass,6D29F0,F,2,160,260,60,0,0,0,1,1,1 110 | Glass,6D29F0,F,2,180,260,60,0,0,0,1,1,1 111 | Glass,6D29F0,F,2,200,260,60,0,0,0,1,1,1 112 | Glass,6D29F0,F,2,220,260,60,0,0,0,1,1,1 113 | Glass,6D29F0,F,2,240,260,60,0,0,0,1,1,1 114 | Glass,6D29F0,F,2,260,260,60,0,0,0,1,1,1 115 | Glass,6D29F0,F,2,280,260,60,0,0,0,1,1,1 116 | Glass,6D29F0,F,2,300,260,60,0,0,0,1,1,1 117 | Glass,6D29F0,F,2,320,260,60,0,0,0,1,1,1 118 | Glass,6D29F0,F,2,340,260,60,0,0,0,1,1,1 119 | Glass,6D29F0,F,2,360,260,60,0,0,0,1,1,1 120 | Glass,6D29F0,F,2,380,260,60,0,0,0,1,1,1 121 | Glass,6D29F0,F,2,400,260,60,0,0,0,1,1,1 122 | Glass,6D29F0,F,2,420,260,60,0,0,0,1,1,1 123 | Glass,6D29F0,F,2,440,260,60,0,0,0,1,1,1 124 | Glass,6D29F0,F,2,460,260,60,0,0,0,1,1,1 125 | Glass,6D29F0,F,2,480,260,60,0,0,0,1,1,1 126 | Glass,6D29F0,F,2,500,260,60,0,0,0,1,1,1 127 | Glass,6D29F0,F,2,520,260,60,0,0,0,1,1,1 128 | Wooden Plank,6CD7F0,F,2,260,300,60,0,0,0,1,1,1 129 | Wooden Plank,6CD7F0,F,2,300,300,60,0,0,0,1,1,1 130 | Wooden Plank,6CD7F0,F,2,340,300,60,0,0,0,1,1,1 131 | Wooden Plank,6CD7F0,F,2,220,320,60,0,0,0,1,1,1 132 | Wooden Plank,6CD7F0,F,2,260,320,60,0,0,0,1,1,1 133 | Wooden Plank,6CD7F0,F,2,280,320,60,0,0,0,1,1,1 134 | Wooden Plank,6CD7F0,F,2,300,320,60,0,0,0,1,1,1 135 | Wooden Plank,6CD7F0,F,2,320,320,60,0,0,0,1,1,1 136 | Wooden Plank,6CD7F0,F,2,340,320,60,0,0,0,1,1,1 137 | Wooden Plank,6CD7F0,F,2,380,320,60,0,0,0,1,1,1 138 | Wooden Plank,6CD7F0,F,2,240,340,60,0,0,0,1,1,1 139 | Wooden Plank,6CD7F0,F,2,260,340,60,0,0,0,1,1,1 140 | Wooden Plank,6CD7F0,F,2,340,340,60,0,0,0,1,1,1 141 | Wooden Plank,6CD7F0,F,2,360,340,60,0,0,0,1,1,1 142 | Wooden Plank,6CD7F0,F,2,360,360,60,0,0,0,1,1,1 143 | Wooden Plank,6CD7F0,F,2,380,360,60,0,0,0,1,1,1 144 | Wooden Plank,6CD7F0,F,2,400,360,60,0,0,0,1,1,1 145 | Wooden Plank,6CD7F0,F,2,300,380,60,0,0,0,1,1,1 146 | Wooden Plank,6CD7F0,F,2,320,380,60,0,0,0,1,1,1 147 | Wooden Plank,6CD7F0,F,2,340,380,60,0,0,0,1,1,1 148 | Wooden Plank,6CD7F0,F,2,360,380,60,0,0,0,1,1,1 149 | Wooden Plank,6CD7F0,F,2,360,400,60,0,0,0,1,1,1 150 | Wooden Plank,6CD7F0,F,2,380,400,60,0,0,0,1,1,1 151 | Wooden Plank,6CD7F0,F,2,400,400,60,0,0,0,1,1,1 152 | Wooden Plank,6CD7F0,F,2,240,420,60,0,0,0,1,1,1 153 | Wooden Plank,6CD7F0,F,2,260,420,60,0,0,0,1,1,1 154 | Wooden Plank,6CD7F0,F,2,340,420,60,0,0,0,1,1,1 155 | Wooden Plank,6CD7F0,F,2,360,420,60,0,0,0,1,1,1 156 | Wooden Plank,6CD7F0,F,2,220,440,60,0,0,0,1,1,1 157 | Wooden Plank,6CD7F0,F,2,260,440,60,0,0,0,1,1,1 158 | Wooden Plank,6CD7F0,F,2,280,440,60,0,0,0,1,1,1 159 | Wooden Plank,6CD7F0,F,2,300,440,60,0,0,0,1,1,1 160 | Wooden Plank,6CD7F0,F,2,320,440,60,0,0,0,1,1,1 161 | Wooden Plank,6CD7F0,F,2,340,440,60,0,0,0,1,1,1 162 | Wooden Plank,6CD7F0,F,2,380,440,60,0,0,0,1,1,1 163 | Wooden Plank,6CD7F0,F,2,260,460,60,0,0,0,1,1,1 164 | Wooden Plank,6CD7F0,F,2,300,460,60,0,0,0,1,1,1 165 | Wooden Plank,6CD7F0,F,2,340,460,60,0,0,0,1,1,1 166 | -------------------------------------------------------------------------------- /Sample Object Lists/Test Level Rail Rings.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | Ring,6C0F80,2,2,475.63781738281,805.31652832031,-449.4912109375,2B6A,4F894,922,-2,795.31646728516,-4 3 | Ring,6C0F80,2,2,471.29568481445,804.32348632813,-449.48962402344,2B6A,4F00C,922,-2,794.32336425781,-4 4 | Ring,6C0F80,2,2,460.60177612305,801.87768554688,-449.48574829102,0,4DD90,929,-2,791.87774658203,-4 5 | Ring,6C0F80,2,2,454.11538696289,800.39459228516,-449.4833984375,BF,4D39C,927,-2,790.39459228516,-4 6 | Ring,6C0F80,2,2,448.15777587891,799.033203125,-449.48126220703,BF,4CB14,927,-2,789.03314208984,-4 7 | Ring,6C0F80,2,2,441.83544921875,797.58843994141,-449.47897338867,2C29,4C28C,920,-2,787.58837890625,-4 8 | Ring,6C0F80,2,2,435.14846801758,796.06030273438,-449.4765625,2C29,4BA04,920,-2,786.06030273438,-4 9 | Ring,6C0F80,2,2,420.68115234375,792.75427246094,-449.47137451172,2C29,4A8F4,920,-2,782.75427246094,-4 10 | Ring,6C0F80,2,2,411.56890869141,790.67236328125,-449.46810913086,17E,49F00,924,-2,780.67230224609,-4 11 | Ring,6C0F80,2,2,403.36492919922,788.80004882813,-449.46517944336,2CE8,49678,91D,-2,778.79998779297,-4 12 | Ring,6C0F80,2,2,394.79925537109,786.84521484375,-449.46215820313,17E,48DF0,924,-2,776.84521484375,-4 13 | Ring,6C0F80,2,2,384.34902954102,784.46026611328,-449.45843505859,2CE8,483FC,91D,-2,774.46026611328,-4 14 | Ring,6C0F80,2,2,363.63629150391,779.73785400391,-449.45111083984,23E,47180,91C,-2,769.73791503906,-4 15 | Ring,6C0F80,2,2,353.50698852539,777.43432617188,-449.4475402832,2DA7,468F8,914,-2,767.43426513672,-4 16 | Ring,6C0F80,2,2,343.02032470703,775.04949951172,-449.44387817383,23E,46070,91C,-2,765.04956054688,-4 17 | Ring,6C0F80,2,2,320.97503662109,770.03887939453,-449.43615722656,2E67,44F60,90F,-2,760.03881835938,-4 18 | Ring,6C0F80,2,2,295.50119018555,764.25982666016,-449.42733764648,2FD,43CE4,916,-2,754.25982666016,-4 19 | Ring,6C0F80,2,2,283.19027709961,761.46697998047,-449.42306518555,2FD,4345C,916,-2,751.46697998047,-4 20 | Ring,6C0F80,2,2,270.52920532227,758.609375,-449.41873168945,2F26,42BD4,902,-2,748.60949707031,-4 21 | Ring,6C0F80,2,2,244.17602539063,752.66351318359,-449.40972900391,3BC,41958,90A,-2,742.66345214844,-4 22 | Ring,6C0F80,2,2,211.69961547852,745.37670898438,-449.39874267578,2FE5,406DC,8F3,-2,735.37664794922,-4 23 | Ring,6C0F80,2,2,197.22015380859,742.13140869141,-449.39385986328,2FE5,3FE54,8F3,-2,732.13140869141,-4 24 | Ring,6C0F80,2,2,182.40478515625,738.82684326172,-449.38891601563,30A5,3F5CC,8E6,-2,728.82672119141,-4 25 | Ring,6C0F80,2,2,151.78993225098,732.00305175781,-449.37872314453,3164,3E4BC,8CE,-2,722.00305175781,-4 26 | Ring,6C0F80,2,2,117.22300720215,724.38262939453,-449.36740112305,3164,3D240,8CE,-2,714.38269042969,-4 27 | Ring,6C0F80,2,2,97.942779541016,720.16125488281,-449.36114501953,3223,3C84C,8B2,-2,710.16119384766,-4 28 | Ring,6C0F80,2,2,81.07487487793,716.48974609375,-449.35571289063,6B9,3BFC4,8BA,-2,706.48980712891,-4 29 | Ring,6C0F80,2,2,61.001804351807,712.13098144531,-449.34924316406,32E3,3B5D0,896,-2,702.13079833984,-4 30 | Ring,6C0F80,2,2,43.459384918213,708.36108398438,-449.34368896484,779,3AD48,89F,-2,698.36108398438,-4 31 | Ring,6C0F80,2,2,22.613777160645,703.88128662109,-449.33706665039,32E3,3A354,896,-2,693.88122558594,-4 32 | Ring,6C0F80,2,2,1.3515148162842,699.38104248047,-449.33044433594,838,39960,87C,-2,689.38098144531,-4 33 | Ring,6C0F80,2,2,-17.188386917114,695.46142578125,-449.32464599609,33A2,390D8,872,-2,685.46142578125,-4 34 | Ring,6C0F80,2,2,-39.20036315918,690.91101074219,-449.31787109375,8F7,386E4,83E,-2,680.91101074219,-4 35 | Ring,6C0F80,2,2,-58.375495910645,686.97546386719,-449.31198120117,3461,37E5C,834,-2,676.97534179688,-4 36 | Ring,6C0F80,2,2,-81.114364624023,682.41040039063,-449.30511474609,9B6,37468,7FA,-2,672.41040039063,-4 37 | Ring,6C0F80,2,2,-100.90153503418,678.48400878906,-449.29916381836,9B6,36BE0,7FA,-2,668.48400878906,-4 38 | Ring,6C0F80,2,2,-124.34658813477,673.95953369141,-449.28289794922,A76,361EC,79F,-2,663.95953369141,-4 39 | Ring,6C0F80,2,2,-148.17370605469,669.44207763672,-449.26055908203,A76,357F8,79F,-2,659.44207763672,-4 40 | Ring,6C0F80,2,2,-168.92097473145,665.67327880859,-449.17260742188,B35,34F70,725,-2,655.67327880859,-4 41 | Ring,6C0F80,2,2,-214.85530090332,657.67407226563,-448.69708251953,BF3,33CF4,67F,-2,647.67407226563,-4 42 | Ring,6C0F80,2,2,-236.39730834961,654.08782958984,-448.29837036133,BF3,3346C,67F,-2,644.08782958984,-4 43 | Ring,6C0F80,2,2,-261.73394775391,650.18365478516,-447.10708618164,37D1,32A78,FFFFFB3D,-2,640.18365478516,-4 44 | Ring,6C0F80,2,2,-287.20404052734,646.36492919922,-445.60809326172,3750,32084,FFFFED0F,-2,636.36468505859,-4 45 | Ring,6C0F80,2,2,-312.69189453125,642.90692138672,-442.46478271484,3750,31690,FFFFED0F,-2,632.90679931641,-4 46 | Ring,6C0F80,2,2,-337.96441650391,639.61859130859,-437.76431274414,D76,30C9C,9A,-2,629.61859130859,-4 47 | Ring,6C0F80,2,2,-359.2043762207,637.07958984375,-431.28051757813,D76,30414,9A,-2,627.07958984375,-4 48 | Ring,6C0F80,2,2,-381.73992919922,634.38049316406,-419.2555847168,2423,2FA20,FFFFCE37,-2,624.38043212891,-4 49 | Ring,6C0F80,2,2,-399.21612548828,632.28265380859,-405.28536987305,2423,2F198,FFFFCE37,-2,622.28259277344,-4 50 | Ring,6C0F80,2,2,-413.71276855469,629.69940185547,-384.10571289063,868,2E7A4,FFFFF824,-2,619.69940185547,-4 51 | Ring,6C0F80,2,2,-423.94512939453,627.43109130859,-364.09405517578,868,2DF1C,FFFFF824,-2,617.43109130859,-4 52 | Ring,6C0F80,2,2,-430.1897277832,623.19653320313,-338.88146972656,87F,2D528,FFFFF864,-2,613.19653320313,-4 53 | Ring,6C0F80,2,2,-435.01068115234,618.20935058594,-313.37951660156,6B1,2CB34,FFFFCC4B,-2,608.20928955078,-4 54 | Ring,6C0F80,2,2,-437.53408813477,610.04498291016,-284.20742797852,B89,2BFD4,FFFFF886,-2,600.04498291016,-4 55 | Ring,6C0F80,2,2,-438.66064453125,600.63061523438,-259.22259521484,1055,2B5E0,FFFFF7E8,-2,590.63055419922,-4 56 | Ring,6C0F80,2,2,-439.1598815918,591.49182128906,-237.85340881348,5DD,2AD58,FFFFCBD9,-2,581.49182128906,-4 57 | Ring,6C0F80,2,2,-439.27572631836,579.67767333984,-217.41897583008,15C1,2A4D0,FFFFF692,-2,569.67767333984,-4 58 | Ring,6C0F80,2,2,-439.31484985352,549.40350341797,-173.78324890137,70D,29254,FFFFC94E,-2,539.40356445313,-4 59 | Ring,6C0F80,2,2,-439.3056640625,530.38806152344,-150.52473449707,714,28860,FFFFC84E,-2,520.38812255859,-4 60 | Ring,6C0F80,2,2,-439.29776000977,512.89593505859,-130.39710998535,1C28,27FD8,FFFFF355,-2,502.89590454102,-4 61 | Ring,6C0F80,2,2,-439.28973388672,494.86111450195,-109.60047912598,696,27750,FFFFC7BC,-2,484.86087036133,-4 62 | Ring,6C0F80,2,2,-439.27871704102,470.38131713867,-80.465965270996,1A7A,26BF0,FFFFF1D4,-2,460.38128662109,-4 63 | Ring,6C0F80,2,2,-439.26873779297,449.07818603516,-53.341884613037,17AD,261FC,FFFFF19B,-2,439.07818603516,-4 64 | Ring,6C0F80,2,2,-439.25842285156,428.69091796875,-24.221878051758,4E6,25808,FFFFC717,-2,418.69079589844,-4 65 | Ring,6C0F80,2,2,-439.24948120117,412.76007080078,2.6435718536377,1474,24F80,FFFFF168,-2,402.76010131836,-4 66 | Ring,6C0F80,2,2,-439.24038696289,398.00128173828,30.859672546387,10CE,246F8,FFFFF134,-2,388.0012512207,-4 67 | Ring,6C0F80,2,2,-439.22952270508,382.82281494141,65.541107177734,D12,23D04,FFFFF0E6,-2,372.82281494141,-4 68 | Ring,6C0F80,2,2,-439.21755981445,370.19900512695,101.9368057251,9E6,23310,FFFFF06F,-2,360.19903564453,-4 69 | Ring,6C0F80,2,2,-439.20318603516,361.55950927734,134.24800109863,9E6,22A88,FFFFF06F,-2,351.55953979492,-4 70 | Ring,6C0F80,2,2,-439.17614746094,353.31903076172,172.77766418457,784,22094,FFFFEFD9,-2,343.31903076172,-4 71 | Ring,6C0F80,2,2,-439.13357543945,346.6926574707,211.95327758789,5B7,216A0,FFFFEF33,-2,336.6926574707,-4 72 | Ring,6C0F80,2,2,-439.07019042969,341.40490722656,251.58767700195,4C,20CAC,FFFFC32F,-2,331.40438842773,-4 73 | Ring,6C0F80,2,2,-438.98022460938,337.22650146484,291.54977416992,1B,202B8,FFFFC273,-2,327.22653198242,-4 74 | Ring,6C0F80,2,2,-438.85662841797,333.96231079102,331.74868774414,FFFFFFF7,1F8C4,FFFFC1B5,-2,323.9619140625,-4 75 | Ring,6C0F80,2,2,-438.6901550293,331.43707275391,372.11901855469,1B5,1EED0,FFFFEC5B,-2,321.43707275391,-4 76 | Ring,6C0F80,2,2,-438.50921630859,329.70526123047,406.82171630859,143,1E648,FFFFEB9E,-2,319.70529174805,-4 77 | Ring,6C0F80,2,2,-438.21813964844,328.11294555664,447.39904785156,143,1DC54,FFFFEB9E,-2,318.11294555664,-4 78 | Ring,6C0F80,2,2,-437.81671142578,326.62945556641,488.05236816406,113,1D260,FFFFEADF,-2,316.62942504883,-4 79 | Ring,6C0F80,2,2,-437.23889160156,324.86862182617,528.74792480469,FFFFFF55,1C86C,FFFFBEBE,-2,314.86923217773,-4 80 | Ring,6C0F80,2,2,-436.23272705078,322.3596496582,569.41369628906,0,1BE78,0,-2,-1000000,-4 81 | Ring,6C0F80,2,2,-433.99594116211,318.52124023438,609.93383789063,0,1B484,0,-2,-1000000,-4 82 | Ring,6C0F80,2,2,-429.19680786133,313.48135375977,644.07891845703,175,1ABFC,FFFFE810,-2,303.48138427734,-4 83 | Ring,6C0F80,2,2,-416.01284790039,305.21673583984,681.09210205078,FFFFE76F,1A208,FFFFC260,-2,295.21636962891,-4 84 | Ring,6C0F80,2,2,-395.42202758789,296.84860229492,707.91442871094,FFFFF765,19980,FFFFEFAA,-2,286.84860229492,-4 85 | Ring,6C0F80,2,2,-335.06967163086,282.11856079102,739.39569091797,FFFFD062,18870,FFFFD439,-2,272.11840820313,-4 86 | Ring,6C0F80,2,2,-295.59680175781,273.35708618164,744.08947753906,FFFFF53E,17D10,FFFFF6F1,-2,263.35708618164,-4 87 | Ring,6C0F80,2,2,-251.26329040527,262.845703125,735.05682373047,FFFFD0DC,1731C,1862,-2,252.84545898438,-4 88 | Ring,6C0F80,2,2,-217.58544921875,253.67680358887,714.22033691406,FFFFF762,16928,FFFFFB4C,-2,243.67680358887,-4 89 | Ring,6C0F80,2,2,-194.88079833984,246.33987426758,688.77618408203,FFFFF8EC,160A0,FFFFFC27,-2,236.33987426758,-4 90 | Ring,6C0F80,2,2,-166.40849304199,233.05804443359,619.79534912109,FFFFF6C1,14E24,28FF,-2,223.05804443359,-4 91 | Ring,6C0F80,2,2,-159.37057495117,227.17022705078,579.57720947266,FFFFF9AA,14430,2996,-2,217.17022705078,-4 92 | Ring,6C0F80,2,2,-155.1869354248,221.78060913086,538.87854003906,FFFFF9AA,13A3C,2996,-2,211.78059387207,-4 93 | Ring,6C0F80,2,2,-152.28065490723,215.93475341797,492.16220092773,FFFFFB23,12EDC,FFFFFF3B,-2,205.96716308594,-4 94 | -------------------------------------------------------------------------------- /sa2lua/objchain.lua: -------------------------------------------------------------------------------- 1 | function ShowObjectChainClick(sender) 2 | form_show(ObjectChain) 3 | end 4 | 5 | function OCUpdateControls() 6 | local valid = false 7 | control_setCaption(ObjectChain_Address, num2hex(objaddr)) 8 | if readInteger(objaddr) ~= nil then valid = true end 9 | if valid then 10 | local temp = readString(readInteger(objaddr + 0x44), 64) 11 | control_setCaption(ObjectChain_ObjectName, temp) 12 | temp = readFloat(GetObjData1(objaddr, 0x14)) 13 | control_setCaption(ObjectChain_ObjPosX, temp) 14 | temp = readFloat(GetObjData1(objaddr, 0x18)) 15 | control_setCaption(ObjectChain_ObjPosY, temp) 16 | temp = readFloat(GetObjData1(objaddr, 0x1C)) 17 | control_setCaption(ObjectChain_ObjPosZ, temp) 18 | temp = readInteger(GetObjData1(objaddr, 0x08)) 19 | control_setCaption(ObjectChain_ObjRotX, num2hex(temp)) 20 | temp = readInteger(GetObjData1(objaddr, 0x0C)) 21 | control_setCaption(ObjectChain_ObjRotY, num2hex(temp)) 22 | temp = readInteger(GetObjData1(objaddr, 0x10)) 23 | control_setCaption(ObjectChain_ObjRotZ, num2hex(temp)) 24 | if ocscalehex then 25 | temp = readInteger(GetObjData1(objaddr, 0x20)) 26 | control_setCaption(ObjectChain_ObjSclX, num2hex(temp)) 27 | temp = readInteger(GetObjData1(objaddr, 0x24)) 28 | control_setCaption(ObjectChain_ObjSclY, num2hex(temp)) 29 | temp = readInteger(GetObjData1(objaddr, 0x28)) 30 | control_setCaption(ObjectChain_ObjSclZ, num2hex(temp)) 31 | control_setCaption(ObjectChain_SclType, "Hex") 32 | else 33 | temp = readFloat(GetObjData1(objaddr, 0x20)) 34 | control_setCaption(ObjectChain_ObjSclX, temp) 35 | temp = readFloat(GetObjData1(objaddr, 0x24)) 36 | control_setCaption(ObjectChain_ObjSclY, temp) 37 | temp = readFloat(GetObjData1(objaddr, 0x28)) 38 | control_setCaption(ObjectChain_ObjSclZ, temp) 39 | control_setCaption(ObjectChain_SclType, "Float") 40 | end 41 | temp = readInteger(objaddr + 0x34) 42 | control_setCaption(AdvObjParams_ObjData1, num2hex(temp)) 43 | temp = readInteger(objaddr + 0x38) 44 | control_setCaption(AdvObjParams_ObjData2, num2hex(temp)) 45 | temp = readInteger(objaddr + 0x3C) 46 | control_setCaption(AdvObjParams_ObjData3, num2hex(temp)) 47 | temp = readInteger(objaddr + 0x40) 48 | control_setCaption(AdvObjParams_ObjData4, num2hex(temp)) 49 | temp = readInteger(objaddr + 0x10) 50 | control_setCaption(AdvObjParams_ObjMainRt, num2hex(temp)) 51 | temp = readInteger(objaddr + 0x14) 52 | control_setCaption(AdvObjParams_ObjDispRt, num2hex(temp)) 53 | temp = readBytes(GetObjData1(objaddr, 0), 1, false) 54 | control_setCaption(AdvObjParams_ObjAction, num2hex(temp)) 55 | else 56 | control_setCaption(ObjectChain_Address, "Click Reset") 57 | control_setCaption(ObjectChain_ObjectName, "") 58 | control_setCaption(ObjectChain_ObjPosX, "") 59 | control_setCaption(ObjectChain_ObjPosY, "") 60 | control_setCaption(ObjectChain_ObjPosZ, "") 61 | control_setCaption(ObjectChain_ObjRotX, "") 62 | control_setCaption(ObjectChain_ObjRotY, "") 63 | control_setCaption(ObjectChain_ObjRotZ, "") 64 | control_setCaption(ObjectChain_ObjSclX, "") 65 | control_setCaption(ObjectChain_ObjSclY, "") 66 | control_setCaption(ObjectChain_ObjSclZ, "") 67 | control_setCaption(AdvObjParams_ObjData1, "") 68 | control_setCaption(AdvObjParams_ObjData2, "") 69 | control_setCaption(AdvObjParams_ObjMainRt, "") 70 | control_setCaption(AdvObjParams_ObjDispRt, "") 71 | control_setCaption(AdvObjParams_ObjAction, "") 72 | end 73 | end 74 | 75 | function SclTypeClick(sender) 76 | ocscalehex = not ocscalehex 77 | OCUpdateControls() 78 | end 79 | 80 | function PrevObject() 81 | local addr = readInteger(objaddr) 82 | if addr ~= nil then objaddr = addr end 83 | OCUpdateControls() 84 | UpdateRemote() 85 | end 86 | 87 | function NextObject() 88 | local addr = readInteger(objaddr + 0x04) 89 | if addr ~= nil then objaddr = addr end 90 | OCUpdateControls() 91 | UpdateRemote() 92 | end 93 | 94 | function GetObjData1(object, offset) 95 | local addr = object 96 | if addr == nil then return nil end 97 | addr = readInteger(addr + 0x34) 98 | if addr == nil then return nil end 99 | return (addr + offset) 100 | end 101 | 102 | function ObjToMeClick(sender) 103 | local x = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 104 | local y = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 105 | local z = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 106 | writeFloat(GetObjData1(objaddr, 0x14), x) 107 | writeFloat(GetObjData1(objaddr, 0x18), y) 108 | writeFloat(GetObjData1(objaddr, 0x1C), z) 109 | OCUpdateControls() 110 | end 111 | 112 | function MeToObjClick(sender) 113 | local x = readFloat(GetObjData1(objaddr, 0x14)) 114 | local y = readFloat(GetObjData1(objaddr, 0x18)) 115 | local z = readFloat(GetObjData1(objaddr, 0x1C)) 116 | local oldaddr = ocaddr 117 | writeFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14), x) 118 | writeFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18), y) 119 | writeFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C), z) 120 | OCUpdateControls() 121 | end 122 | 123 | function ObjSetValuesClick(sender) 124 | local px = tonumber(control_getCaption(ObjectChain_ObjPosX)) 125 | local py = tonumber(control_getCaption(ObjectChain_ObjPosY)) 126 | local pz = tonumber(control_getCaption(ObjectChain_ObjPosZ)) 127 | local rx = tonumber(control_getCaption(ObjectChain_ObjRotX), 16) 128 | local ry = tonumber(control_getCaption(ObjectChain_ObjRotY), 16) 129 | local rz = tonumber(control_getCaption(ObjectChain_ObjRotZ), 16) 130 | writeFloat(GetObjData1(objaddr, 0x14), px) 131 | writeFloat(GetObjData1(objaddr, 0x18), py) 132 | writeFloat(GetObjData1(objaddr, 0x1C), pz) 133 | writeInteger(GetObjData1(objaddr, 0x08), rx) 134 | writeInteger(GetObjData1(objaddr, 0x0C), ry) 135 | writeInteger(GetObjData1(objaddr, 0x10), rz) 136 | if ocscalehex then 137 | local sx = tonumber(control_getCaption(ObjectChain_ObjSclX), 16) 138 | local sy = tonumber(control_getCaption(ObjectChain_ObjSclY), 16) 139 | local sz = tonumber(control_getCaption(ObjectChain_ObjSclZ), 16) 140 | writeInteger(GetObjData1(objaddr, 0x20), sx) 141 | writeInteger(GetObjData1(objaddr, 0x24), sy) 142 | writeInteger(GetObjData1(objaddr, 0x28), sz) 143 | else 144 | local sx = tonumber(control_getCaption(ObjectChain_ObjSclX)) 145 | local sy = tonumber(control_getCaption(ObjectChain_ObjSclY)) 146 | local sz = tonumber(control_getCaption(ObjectChain_ObjSclZ)) 147 | writeFloat(GetObjData1(objaddr, 0x20), sx) 148 | writeFloat(GetObjData1(objaddr, 0x24), sy) 149 | writeFloat(GetObjData1(objaddr, 0x28), sz) 150 | end 151 | OCUpdateControls() 152 | end 153 | 154 | function RotZeroClick(sender) 155 | writeInteger(GetObjData1(objaddr, 0x08), 0) 156 | writeInteger(GetObjData1(objaddr, 0x0C), 0) 157 | writeInteger(GetObjData1(objaddr, 0x10), 0) 158 | OCUpdateControls() 159 | end 160 | 161 | function SclOneClick(sender) 162 | writeFloat(GetObjData1(objaddr, 0x20), 1.0) 163 | writeFloat(GetObjData1(objaddr, 0x24), 1.0) 164 | writeFloat(GetObjData1(objaddr, 0x28), 1.0) 165 | OCUpdateControls() 166 | end 167 | 168 | function BaseAddressClick(sender) 169 | local sel = radiogroup_getItemIndex(ObjectChain_BaseAddress) 170 | ocaddr = 0x1A5A254 + sel * 4 171 | objaddr = readInteger(ocaddr) 172 | OCUpdateControls() 173 | end 174 | 175 | function ResetAddress() 176 | objaddr = readInteger(ocaddr) 177 | OCUpdateControls() 178 | end 179 | 180 | function ObjSetAdvValuesClick(sender) 181 | local rmain = tonumber(control_getCaption(AdvObjParams_ObjMainRt), 16) 182 | local rdisp = tonumber(control_getCaption(AdvObjParams_ObjDispRt), 16) 183 | local action = tonumber(control_getCaption(AdvObjParams_ObjAction), 16) 184 | writeInteger(objaddr + 0x10, rmain) 185 | writeInteger(objaddr + 0x14, rdisp) 186 | writeBytes(GetObjData1(objaddr, 0), action) 187 | end 188 | 189 | function ShowAdvObjParamsClick(sender) 190 | form_show(AdvObjParams) 191 | end 192 | 193 | function ShowFindDialogClick(sender) 194 | form_show(FindObjDlg) 195 | end 196 | 197 | function FindObjectClick(sender) 198 | local start = objaddr 199 | local back = false 200 | local query = control_getCaption(FindObjDlg_SearchQuery) 201 | if component_getTag(sender) == 0 then back = true end 202 | local count = 0 203 | while true do 204 | local oldaddr = objaddr 205 | if back then PrevObject() else NextObject() end 206 | local name = readString(readInteger(objaddr + 0x44), 64) 207 | local match = false 208 | if checkbox_getState(FindObjDlg_FindWholeObjName) == cbChecked then 209 | if name == query then match = true end 210 | else 211 | if string.find(name, query, 1, true) ~= nil then match = true end 212 | end 213 | if match then break end 214 | if objaddr == start or objaddr == oldaddr then 215 | messageDialog("No matching objects found.", mtInformation, mbOK) 216 | break 217 | end 218 | count = count + 1 219 | if count > 1000 then 220 | messageDialog("Infinite loop protection triggered!", mtError, mbOK) 221 | break 222 | end 223 | end 224 | OCUpdateControls() 225 | end 226 | 227 | function DeleteObjClick(sender) 228 | writeInteger(objaddr + 0x10, 0x46F720) 229 | OLRemoveObject(objaddr) 230 | OCUpdateControls() 231 | end 232 | 233 | function AutoUpdateChange(sender) 234 | local enable = checkbox_getState(ObjectChain_AutoUpdate) == cbChecked 235 | control_setEnabled(ObjectChain_ObjPosX, enable) 236 | control_setEnabled(ObjectChain_ObjPosY, enable) 237 | control_setEnabled(ObjectChain_ObjPosZ, enable) 238 | control_setEnabled(ObjectChain_ObjRotX, enable) 239 | control_setEnabled(ObjectChain_ObjRotY, enable) 240 | control_setEnabled(ObjectChain_ObjRotZ, enable) 241 | control_setEnabled(ObjectChain_ObjSclX, enable) 242 | control_setEnabled(ObjectChain_ObjSclY, enable) 243 | control_setEnabled(ObjectChain_ObjSclZ, enable) 244 | end 245 | 246 | -- Initialization 247 | 248 | endobjaddr = 0 249 | ocaddr = 0x1A5A254 250 | ocscalehex = false 251 | radiogroup_setItemIndex(ObjectChain_BaseAddress, 0) 252 | OCUpdateControls() 253 | 254 | timer_setEnabled(ObjectChain_Update, true) -------------------------------------------------------------------------------- /Sample Object Lists/Minecraft Village.csv: -------------------------------------------------------------------------------- 1 | Name,Routine,Flags,List,XPos,YPos,ZPos,XRot,YRot,ZRot,XScl,YScl,ZScl 2 | block,6D63F0,2,2,240,-40,40,0,0,0,1,1,1 3 | block,6D63F0,2,2,260,-40,40,0,0,0,1,1,1 4 | block,6D63F0,2,2,280,-40,40,0,0,0,1,1,1 5 | block,6D63F0,2,2,240,-20,40,0,0,0,1,1,1 6 | block,6D63F0,2,2,260,-20,40,0,0,0,1,1,1 7 | block,6D63F0,2,2,280,-20,40,0,0,0,1,1,1 8 | block,6D63F0,2,2,240,0,40,0,0,0,1,1,1 9 | block,6D63F0,2,2,260,0,40,0,0,0,1,1,1 10 | block,6D63F0,2,2,280,0,40,0,0,0,1,1,1 11 | block,6D63F0,2,2,240,20,40,0,0,0,1,1,1 12 | block,6D29F0,2,2,260,20,40,0,0,0,1,1,1 13 | block,6D63F0,2,2,280,20,40,0,0,0,1,1,1 14 | block,6D63F0,2,2,240,40,40,0,0,0,1,1,1 15 | block,6D63F0,2,2,260,40,40,0,0,0,1,1,1 16 | block,6D63F0,2,2,280,40,40,0,0,0,1,1,1 17 | block,6D63F0,2,2,220,-40,60,0,0,0,1,1,1 18 | block,6D63F0,2,2,240,-40,60,0,0,0,1,1,1 19 | block,6D63F0,2,2,260,-40,60,0,0,0,1,1,1 20 | block,6D63F0,2,2,280,-40,60,0,0,0,1,1,1 21 | block,6D63F0,2,2,300,-40,60,0,0,0,1,1,1 22 | block,6D63F0,2,2,220,-20,60,0,0,0,1,1,1 23 | block,6D63F0,2,2,240,-20,60,0,0,0,1,1,1 24 | block,6D63F0,2,2,260,-20,60,0,0,0,1,1,1 25 | block,6D63F0,2,2,280,-20,60,0,0,0,1,1,1 26 | block,6D63F0,2,2,300,-20,60,0,0,0,1,1,1 27 | block,6D63F0,2,2,220,0,60,0,0,0,1,1,1 28 | block,6D63F0,2,2,300,0,60,0,0,0,1,1,1 29 | block,6D63F0,2,2,220,20,60,0,0,0,1,1,1 30 | block,6D63F0,2,2,300,20,60,0,0,0,1,1,1 31 | block,6D63F0,2,2,220,40,60,0,0,0,1,1,1 32 | block,6D63F0,2,2,300,40,60,0,0,0,1,1,1 33 | block,6D63F0,2,2,240,60,60,0,0,0,1,1,1 34 | block,6D63F0,2,2,260,60,60,0,0,0,1,1,1 35 | block,6D63F0,2,2,280,60,60,0,0,0,1,1,1 36 | block,6D63F0,2,2,220,-40,80,0,0,0,1,1,1 37 | block,6D63F0,2,2,240,-40,80,0,0,0,1,1,1 38 | block,6D63F0,2,2,260,-40,80,0,0,0,1,1,1 39 | block,6D63F0,2,2,280,-40,80,0,0,0,1,1,1 40 | block,6D63F0,2,2,300,-40,80,0,0,0,1,1,1 41 | block,6D63F0,2,2,220,-20,80,0,0,0,1,1,1 42 | block,6D63F0,2,2,240,-20,80,0,0,0,1,1,1 43 | block,6D63F0,2,2,280,-20,80,0,0,0,1,1,1 44 | block,6D63F0,2,2,300,-20,80,0,0,0,1,1,1 45 | block,6D63F0,2,2,220,0,80,0,0,0,1,1,1 46 | block,6D63F0,2,2,300,0,80,0,0,0,1,1,1 47 | block,6D29F0,2,2,220,20,80,0,0,0,1,1,1 48 | block,6D29F0,2,2,300,20,80,0,0,0,1,1,1 49 | block,6D63F0,2,2,220,40,80,0,0,0,1,1,1 50 | block,6D63F0,2,2,300,40,80,0,0,0,1,1,1 51 | block,6D63F0,2,2,240,60,80,0,0,0,1,1,1 52 | block,6D63F0,2,2,260,60,80,0,0,0,1,1,1 53 | block,6D63F0,2,2,280,60,80,0,0,0,1,1,1 54 | block,6D63F0,2,2,220,-40,100,0,0,0,1,1,1 55 | block,6D63F0,2,2,240,-40,100,0,0,0,1,1,1 56 | block,6D63F0,2,2,260,-40,100,0,0,0,1,1,1 57 | block,6D63F0,2,2,280,-40,100,0,0,0,1,1,1 58 | block,6D63F0,2,2,300,-40,100,0,0,0,1,1,1 59 | block,6D63F0,2,2,220,-20,100,0,0,0,1,1,1 60 | block,6D63F0,2,2,300,-20,100,0,0,0,1,1,1 61 | block,6D63F0,2,2,220,0,100,0,0,0,1,1,1 62 | block,6D63F0,2,2,300,0,100,0,0,0,1,1,1 63 | block,6D63F0,2,2,220,20,100,0,0,0,1,1,1 64 | block,6D63F0,2,2,300,20,100,0,0,0,1,1,1 65 | block,6D63F0,2,2,220,40,100,0,0,0,1,1,1 66 | block,6D63F0,2,2,300,40,100,0,0,0,1,1,1 67 | block,6D63F0,2,2,240,60,100,0,0,0,1,1,1 68 | block,6D63F0,2,2,260,60,100,0,0,0,1,1,1 69 | block,6D63F0,2,2,280,60,100,0,0,0,1,1,1 70 | block,6D63F0,2,2,60,-40,120,0,0,0,1,1,1 71 | block,6D63F0,2,2,80,-40,120,0,0,0,1,1,1 72 | block,6D63F0,2,2,100,-40,120,0,0,0,1,1,1 73 | block,6D63F0,2,2,120,-40,120,0,0,0,1,1,1 74 | block,6D63F0,2,2,220,-40,120,0,0,0,1,1,1 75 | block,6D63F0,2,2,240,-40,120,0,0,0,1,1,1 76 | block,6D63F0,2,2,260,-40,120,0,0,0,1,1,1 77 | block,6D63F0,2,2,280,-40,120,0,0,0,1,1,1 78 | block,6D63F0,2,2,300,-40,120,0,0,0,1,1,1 79 | block,6CD7F0,2,2,60,-20,120,0,0,0,1,1,1 80 | block,6CD7F0,2,2,80,-20,120,0,0,0,1,1,1 81 | block,6CD7F0,2,2,100,-20,120,0,0,0,1,1,1 82 | block,6CD7F0,2,2,120,-20,120,0,0,0,1,1,1 83 | block,6D63F0,2,2,220,-20,120,0,0,0,1,1,1 84 | block,6D63F0,2,2,300,-20,120,0,0,0,1,1,1 85 | block,6CD7F0,2,2,60,0,120,0,0,0,1,1,1 86 | block,6CD7F0,2,2,80,0,120,0,0,0,1,1,1 87 | block,6CD7F0,2,2,100,0,120,0,0,0,1,1,1 88 | block,6CD7F0,2,2,120,0,120,0,0,0,1,1,1 89 | block,6D63F0,2,2,220,0,120,0,0,0,1,1,1 90 | block,6D63F0,2,2,300,0,120,0,0,0,1,1,1 91 | block,6CD7F0,2,2,60,20,120,0,0,0,1,1,1 92 | block,6CD7F0,2,2,80,20,120,0,0,0,1,1,1 93 | block,6CD7F0,2,2,100,20,120,0,0,0,1,1,1 94 | block,6CD7F0,2,2,120,20,120,0,0,0,1,1,1 95 | block,6D63F0,2,2,220,20,120,0,0,0,1,1,1 96 | block,6D63F0,2,2,300,20,120,0,0,0,1,1,1 97 | block,6CD7F0,2,2,80,40,120,0,0,0,1,1,1 98 | block,6CD7F0,2,2,100,40,120,0,0,0,1,1,1 99 | block,6D63F0,2,2,220,40,120,0,0,0,1,1,1 100 | block,6D63F0,2,2,240,40,120,0,0,0,1,1,1 101 | block,6D63F0,2,2,260,40,120,0,0,0,1,1,1 102 | block,6D63F0,2,2,280,40,120,0,0,0,1,1,1 103 | block,6D63F0,2,2,300,40,120,0,0,0,1,1,1 104 | block,6D63F0,2,2,240,60,120,0,0,0,1,1,1 105 | block,6D63F0,2,2,260,60,120,0,0,0,1,1,1 106 | block,6D63F0,2,2,280,60,120,0,0,0,1,1,1 107 | block,6D63F0,2,2,240,80,120,0,0,0,1,1,1 108 | block,6D29F0,2,2,260,80,120,0,0,0,1,1,1 109 | block,6D63F0,2,2,280,80,120,0,0,0,1,1,1 110 | block,6D63F0,2,2,240,100,120,0,0,0,1,1,1 111 | block,6D29F0,2,2,260,100,120,0,0,0,1,1,1 112 | block,6D63F0,2,2,280,100,120,0,0,0,1,1,1 113 | block,6D63F0,2,2,240,120,120,0,0,0,1,1,1 114 | block,6D63F0,2,2,260,120,120,0,0,0,1,1,1 115 | block,6D63F0,2,2,280,120,120,0,0,0,1,1,1 116 | block,6D63F0,2,2,220,140,120,0,0,0,1,1,1 117 | block,6D63F0,2,2,240,140,120,0,0,0,1,1,1 118 | block,6D63F0,2,2,260,140,120,0,0,0,1,1,1 119 | block,6D63F0,2,2,280,140,120,0,0,0,1,1,1 120 | block,6D63F0,2,2,300,140,120,0,0,0,1,1,1 121 | block,6D63F0,2,2,240,160,120,0,0,0,1,1,1 122 | block,6D63F0,2,2,260,160,120,0,0,0,1,1,1 123 | block,6D63F0,2,2,280,160,120,0,0,0,1,1,1 124 | block,6D63F0,2,2,260,180,120,0,0,0,1,1,1 125 | block,6D63F0,2,2,60,-40,140,0,0,0,1,1,1 126 | block,6D63F0,2,2,120,-40,140,0,0,0,1,1,1 127 | block,6D63F0,2,2,240,-40,140,0,0,0,1,1,1 128 | block,6D63F0,2,2,260,-40,140,0,0,0,1,1,1 129 | block,6D63F0,2,2,280,-40,140,0,0,0,1,1,1 130 | block,6CD7F0,2,2,60,-20,140,0,0,0,1,1,1 131 | block,6CD7F0,2,2,120,-20,140,0,0,0,1,1,1 132 | block,6D63F0,2,2,220,-20,140,0,0,0,1,1,1 133 | block,6D63F0,2,2,300,-20,140,0,0,0,1,1,1 134 | block,6CD7F0,2,2,60,0,140,0,0,0,1,1,1 135 | block,6CD7F0,2,2,120,0,140,0,0,0,1,1,1 136 | block,6D63F0,2,2,220,0,140,0,0,0,1,1,1 137 | block,6D63F0,2,2,300,0,140,0,0,0,1,1,1 138 | block,6CD7F0,2,2,60,20,140,0,0,0,1,1,1 139 | block,6CD7F0,2,2,120,20,140,0,0,0,1,1,1 140 | block,6D63F0,2,2,220,20,140,0,0,0,1,1,1 141 | block,6D63F0,2,2,300,20,140,0,0,0,1,1,1 142 | block,6CD7F0,2,2,60,40,140,0,0,0,1,1,1 143 | block,6CD7F0,2,2,120,40,140,0,0,0,1,1,1 144 | block,6D63F0,2,2,220,40,140,0,0,0,1,1,1 145 | block,6D63F0,2,2,240,40,140,0,0,0,1,1,1 146 | block,6D63F0,2,2,260,40,140,0,0,0,1,1,1 147 | block,6D63F0,2,2,300,40,140,0,0,0,1,1,1 148 | block,6CD7F0,2,2,80,60,140,0,0,0,1,1,1 149 | block,6CD7F0,2,2,100,60,140,0,0,0,1,1,1 150 | block,6D63F0,2,2,220,60,140,0,0,0,1,1,1 151 | block,6D63F0,2,2,300,60,140,0,0,0,1,1,1 152 | block,6D63F0,2,2,220,80,140,0,0,0,1,1,1 153 | block,6D63F0,2,2,300,80,140,0,0,0,1,1,1 154 | block,6D63F0,2,2,220,100,140,0,0,0,1,1,1 155 | block,6D63F0,2,2,300,100,140,0,0,0,1,1,1 156 | block,6D63F0,2,2,220,120,140,0,0,0,1,1,1 157 | block,6D63F0,2,2,300,120,140,0,0,0,1,1,1 158 | block,6D63F0,2,2,220,140,140,0,0,0,1,1,1 159 | block,6D63F0,2,2,240,140,140,0,0,0,1,1,1 160 | block,6D63F0,2,2,260,140,140,0,0,0,1,1,1 161 | block,6D63F0,2,2,300,140,140,0,0,0,1,1,1 162 | block,6D63F0,2,2,220,160,140,0,0,0,1,1,1 163 | block,6D63F0,2,2,300,160,140,0,0,0,1,1,1 164 | block,6D63F0,2,2,60,-40,160,0,0,0,1,1,1 165 | block,6D63F0,2,2,120,-40,160,0,0,0,1,1,1 166 | block,6D63F0,2,2,240,-40,160,0,0,0,1,1,1 167 | block,6D63F0,2,2,260,-40,160,0,0,0,1,1,1 168 | block,6D63F0,2,2,280,-40,160,0,0,0,1,1,1 169 | block,6CD7F0,2,2,60,-20,160,0,0,0,1,1,1 170 | block,6CD7F0,2,2,120,-20,160,0,0,0,1,1,1 171 | block,6D63F0,2,2,220,-20,160,0,0,0,1,1,1 172 | block,6D63F0,2,2,300,-20,160,0,0,0,1,1,1 173 | block,6D29F0,2,2,60,0,160,0,0,0,1,1,1 174 | block,6D29F0,2,2,120,0,160,0,0,0,1,1,1 175 | block,6D29F0,2,2,220,0,160,0,0,0,1,1,1 176 | block,6D29F0,2,2,300,0,160,0,0,0,1,1,1 177 | block,6CD7F0,2,2,60,20,160,0,0,0,1,1,1 178 | block,6CD7F0,2,2,120,20,160,0,0,0,1,1,1 179 | block,6D29F0,2,2,220,20,160,0,0,0,1,1,1 180 | block,6D29F0,2,2,300,20,160,0,0,0,1,1,1 181 | block,6CD7F0,2,2,60,40,160,0,0,0,1,1,1 182 | block,6CD7F0,2,2,120,40,160,0,0,0,1,1,1 183 | block,6D63F0,2,2,220,40,160,0,0,0,1,1,1 184 | block,6D63F0,2,2,240,40,160,0,0,0,1,1,1 185 | block,6D63F0,2,2,260,40,160,0,0,0,1,1,1 186 | block,6D63F0,2,2,280,40,160,0,0,0,1,1,1 187 | block,6D63F0,2,2,300,40,160,0,0,0,1,1,1 188 | block,6CD7F0,2,2,80,60,160,0,0,0,1,1,1 189 | block,6CD7F0,2,2,100,60,160,0,0,0,1,1,1 190 | block,6D63F0,2,2,220,60,160,0,0,0,1,1,1 191 | block,6D63F0,2,2,300,60,160,0,0,0,1,1,1 192 | block,6D29F0,2,2,220,80,160,0,0,0,1,1,1 193 | block,6D29F0,2,2,300,80,160,0,0,0,1,1,1 194 | block,6D29F0,2,2,220,100,160,0,0,0,1,1,1 195 | block,6D29F0,2,2,300,100,160,0,0,0,1,1,1 196 | block,6D63F0,2,2,220,120,160,0,0,0,1,1,1 197 | block,6D63F0,2,2,300,120,160,0,0,0,1,1,1 198 | block,6D63F0,2,2,220,140,160,0,0,0,1,1,1 199 | block,6D63F0,2,2,240,140,160,0,0,0,1,1,1 200 | block,6D63F0,2,2,260,140,160,0,0,0,1,1,1 201 | block,6D63F0,2,2,280,140,160,0,0,0,1,1,1 202 | block,6D63F0,2,2,300,140,160,0,0,0,1,1,1 203 | block,6D63F0,2,2,220,160,160,0,0,0,1,1,1 204 | block,6D63F0,2,2,300,160,160,0,0,0,1,1,1 205 | block,6D63F0,2,2,220,180,160,0,0,0,1,1,1 206 | block,6D63F0,2,2,300,180,160,0,0,0,1,1,1 207 | block,6D63F0,2,2,60,-40,180,0,0,0,1,1,1 208 | block,6D63F0,2,2,120,-40,180,0,0,0,1,1,1 209 | block,6D63F0,2,2,240,-40,180,0,0,0,1,1,1 210 | block,6D63F0,2,2,260,-40,180,0,0,0,1,1,1 211 | block,6D63F0,2,2,280,-40,180,0,0,0,1,1,1 212 | block,6CD7F0,2,2,60,-20,180,0,0,0,1,1,1 213 | block,6CD7F0,2,2,120,-20,180,0,0,0,1,1,1 214 | block,6D63F0,2,2,220,-20,180,0,0,0,1,1,1 215 | block,6D63F0,2,2,300,-20,180,0,0,0,1,1,1 216 | block,6CD7F0,2,2,60,0,180,0,0,0,1,1,1 217 | block,6CD7F0,2,2,120,0,180,0,0,0,1,1,1 218 | block,6D63F0,2,2,220,0,180,0,0,0,1,1,1 219 | block,6D63F0,2,2,300,0,180,0,0,0,1,1,1 220 | block,6CD7F0,2,2,60,20,180,0,0,0,1,1,1 221 | block,6CD7F0,2,2,120,20,180,0,0,0,1,1,1 222 | block,6D63F0,2,2,220,20,180,0,0,0,1,1,1 223 | block,6D63F0,2,2,300,20,180,0,0,0,1,1,1 224 | block,6CD7F0,2,2,60,40,180,0,0,0,1,1,1 225 | block,6CD7F0,2,2,120,40,180,0,0,0,1,1,1 226 | block,6D63F0,2,2,220,40,180,0,0,0,1,1,1 227 | block,6D63F0,2,2,240,40,180,0,0,0,1,1,1 228 | block,6D63F0,2,2,260,40,180,0,0,0,1,1,1 229 | block,6D63F0,2,2,280,40,180,0,0,0,1,1,1 230 | block,6D63F0,2,2,300,40,180,0,0,0,1,1,1 231 | block,6CD7F0,2,2,80,60,180,0,0,0,1,1,1 232 | block,6CD7F0,2,2,100,60,180,0,0,0,1,1,1 233 | block,6D63F0,2,2,220,60,180,0,0,0,1,1,1 234 | block,6D63F0,2,2,300,60,180,0,0,0,1,1,1 235 | block,6D63F0,2,2,220,80,180,0,0,0,1,1,1 236 | block,6D63F0,2,2,300,80,180,0,0,0,1,1,1 237 | block,6D63F0,2,2,220,100,180,0,0,0,1,1,1 238 | block,6D63F0,2,2,300,100,180,0,0,0,1,1,1 239 | block,6D63F0,2,2,220,120,180,0,0,0,1,1,1 240 | block,6D63F0,2,2,300,120,180,0,0,0,1,1,1 241 | block,6D63F0,2,2,220,140,180,0,0,0,1,1,1 242 | block,6D63F0,2,2,240,140,180,0,0,0,1,1,1 243 | block,6D63F0,2,2,260,140,180,0,0,0,1,1,1 244 | block,6D63F0,2,2,280,140,180,0,0,0,1,1,1 245 | block,6D63F0,2,2,300,140,180,0,0,0,1,1,1 246 | block,6D63F0,2,2,220,160,180,0,0,0,1,1,1 247 | block,6D63F0,2,2,300,160,180,0,0,0,1,1,1 248 | block,6D63F0,2,2,60,-40,200,0,0,0,1,1,1 249 | block,6D63F0,2,2,80,-40,200,0,0,0,1,1,1 250 | block,6D63F0,2,2,100,-40,200,0,0,0,1,1,1 251 | block,6D63F0,2,2,120,-40,200,0,0,0,1,1,1 252 | block,6D63F0,2,2,240,-40,200,0,0,0,1,1,1 253 | block,6D63F0,2,2,260,-40,200,0,0,0,1,1,1 254 | block,6D63F0,2,2,280,-40,200,0,0,0,1,1,1 255 | block,6CD7F0,2,2,60,-20,200,0,0,0,1,1,1 256 | block,6CD7F0,2,2,100,-20,200,0,0,0,1,1,1 257 | block,6CD7F0,2,2,120,-20,200,0,0,0,1,1,1 258 | block,6D63F0,2,2,240,-20,200,0,0,0,1,1,1 259 | block,6D63F0,2,2,280,-20,200,0,0,0,1,1,1 260 | block,6CD7F0,2,2,60,0,200,0,0,0,1,1,1 261 | block,6CD7F0,2,2,100,0,200,0,0,0,1,1,1 262 | block,6CD7F0,2,2,120,0,200,0,0,0,1,1,1 263 | block,6D63F0,2,2,240,0,200,0,0,0,1,1,1 264 | block,6D63F0,2,2,280,0,200,0,0,0,1,1,1 265 | block,6CD7F0,2,2,60,20,200,0,0,0,1,1,1 266 | block,6CD7F0,2,2,80,20,200,0,0,0,1,1,1 267 | block,6CD7F0,2,2,100,20,200,0,0,0,1,1,1 268 | block,6CD7F0,2,2,120,20,200,0,0,0,1,1,1 269 | block,6D63F0,2,2,240,20,200,0,0,0,1,1,1 270 | block,6D63F0,2,2,260,20,200,0,0,0,1,1,1 271 | block,6D63F0,2,2,280,20,200,0,0,0,1,1,1 272 | block,6CD7F0,2,2,80,40,200,0,0,0,1,1,1 273 | block,6CD7F0,2,2,100,40,200,0,0,0,1,1,1 274 | block,6D63F0,2,2,220,40,200,0,0,0,1,1,1 275 | block,6D63F0,2,2,240,40,200,0,0,0,1,1,1 276 | block,6D63F0,2,2,260,40,200,0,0,0,1,1,1 277 | block,6D63F0,2,2,280,40,200,0,0,0,1,1,1 278 | block,6D63F0,2,2,300,40,200,0,0,0,1,1,1 279 | block,6D63F0,2,2,240,60,200,0,0,0,1,1,1 280 | block,6D63F0,2,2,260,60,200,0,0,0,1,1,1 281 | block,6D63F0,2,2,280,60,200,0,0,0,1,1,1 282 | block,6D63F0,2,2,240,80,200,0,0,0,1,1,1 283 | block,6D29F0,2,2,260,80,200,0,0,0,1,1,1 284 | block,6D63F0,2,2,280,80,200,0,0,0,1,1,1 285 | block,6D63F0,2,2,240,100,200,0,0,0,1,1,1 286 | block,6D29F0,2,2,260,100,200,0,0,0,1,1,1 287 | block,6D63F0,2,2,280,100,200,0,0,0,1,1,1 288 | block,6D63F0,2,2,240,120,200,0,0,0,1,1,1 289 | block,6D63F0,2,2,260,120,200,0,0,0,1,1,1 290 | block,6D63F0,2,2,280,120,200,0,0,0,1,1,1 291 | block,6D63F0,2,2,220,140,200,0,0,0,1,1,1 292 | block,6D63F0,2,2,240,140,200,0,0,0,1,1,1 293 | block,6D63F0,2,2,260,140,200,0,0,0,1,1,1 294 | block,6D63F0,2,2,280,140,200,0,0,0,1,1,1 295 | block,6D63F0,2,2,300,140,200,0,0,0,1,1,1 296 | block,6D63F0,2,2,240,160,200,0,0,0,1,1,1 297 | block,6D63F0,2,2,260,160,200,0,0,0,1,1,1 298 | block,6D63F0,2,2,280,160,200,0,0,0,1,1,1 299 | block,6D63F0,2,2,260,180,200,0,0,0,1,1,1 300 | -------------------------------------------------------------------------------- /sa2lua/objspawn.lua: -------------------------------------------------------------------------------- 1 | function ShowSpawnObjectClick(sender) 2 | form_show(SpawnObjectDlg) 3 | end 4 | 5 | function EnableObjPlacementClick(sender) 6 | EnableObjectSpawning() 7 | --debugProcess() 8 | end 9 | 10 | function EnableObjectSpawning() 11 | local hookaddr = allocateSharedMemory(1024) 12 | hookcmd = LoadBinaryFile("sa2lua/hook.bin", hookaddr) + hookaddr 13 | writeInteger(hookaddr + 0x02, hookcmd) 14 | writeBytes(0x77E780, 0xE9) 15 | writeInteger(0x77E781, hookaddr - 0x77E785) 16 | writeInteger(hookcmd, 0) 17 | fullAccess(0x42C645, 4) 18 | control_setEnabled(SpawnObjectDlg_SpawnObject, true) 19 | control_setEnabled(SpawnObjectDlg_ReplaceObject, true) 20 | control_setEnabled(SpawnObjectDlg_SpawnCylinder, true) 21 | control_setEnabled(CallFunc_Call, true) 22 | control_setEnabled(ObjectChain_ObjManipKeysToggle, true) 23 | end 24 | 25 | function SpawnObject(routine, name, flags, list, customname, xpos, ypos, zpos, xrot, yrot, zrot, xscl, yscl, zscl, delay) 26 | local nameaddr = name 27 | if readInteger(hookcmd) == nil then 28 | print("Object spawning not enabled!") 29 | return nil 30 | end 31 | if customname then 32 | nameaddr = AllocateString(name) 33 | end 34 | 35 | writeInteger(hookcmd, 1) -- tell the injected code to spawn an object 36 | writeInteger(hookcmd + 0x04, routine) 37 | writeInteger(hookcmd + 0x08, nameaddr) 38 | writeBytes(hookcmd + 0x0C, flags) 39 | writeInteger(hookcmd + 0x0D, list) 40 | writeInteger(hookcmd + 0x11, xrot) 41 | writeInteger(hookcmd + 0x15, yrot) 42 | writeInteger(hookcmd + 0x19, zrot) 43 | writeFloat(hookcmd + 0x1D, xpos) 44 | writeFloat(hookcmd + 0x21, ypos) 45 | writeFloat(hookcmd + 0x25, zpos) 46 | writeFloat(hookcmd + 0x29, xscl) 47 | writeFloat(hookcmd + 0x2D, yscl) 48 | writeFloat(hookcmd + 0x31, zscl) 49 | 50 | sp_routine_storage = routine -- We'll need this later. 51 | 52 | if delay > 0 then sleep(delay) end 53 | 54 | if readBytes(hookcmd, 1, false) == 0 then 55 | return readInteger(hookcmd + 0x04) 56 | else 57 | return nil 58 | end 59 | end 60 | 61 | function SpawnCylinderClick(sender) 62 | local xpos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 63 | local ypos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 64 | local zpos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 65 | objaddr = SpawnObject(0x6D6EE0, "Movable Cylinder", 3, 2, true, xpos, ypos, zpos, 0,0,0,0,0,0, 0) 66 | OCUpdateControls() 67 | end 68 | 69 | function SpawnObjectClick(sender) 70 | local xrot local yrot local zrot 71 | local routine = tonumber(control_getCaption(SpawnObjectDlg_MainRoutine), 16) 72 | local flags = tonumber(control_getCaption(SpawnObjectDlg_Flags), 16) 73 | local list = tonumber(control_getCaption(SpawnObjectDlg_ListID), 16) 74 | local copyrot = (checkbox_getState(SpawnObjectDlg_UsePlayerRot) == cbChecked) 75 | local customname = (objname == 0) 76 | if copyrot then 77 | xrot = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x08)) 78 | yrot = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x0C)) 79 | zrot = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x10)) 80 | if routine == 0x6CFBF0 then 81 | yrot = 0xFFFF - yrot + 0x4000 82 | end 83 | else 84 | xrot = tonumber(control_getCaption(SpawnObjectDlg_RotX), 16) 85 | yrot = tonumber(control_getCaption(SpawnObjectDlg_RotY), 16) 86 | zrot = tonumber(control_getCaption(SpawnObjectDlg_RotZ), 16) 87 | end 88 | local xpos, ypos, zpos 89 | if OMKCursorMode then 90 | xpos = OMKCursorX 91 | ypos = OMKCursorY 92 | zpos = OMKCursorZ 93 | else 94 | xpos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 95 | ypos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 96 | zpos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 97 | xpos = xpos + tonumber(control_getCaption(SpawnObjectDlg_OffX)) 98 | ypos = ypos + tonumber(control_getCaption(SpawnObjectDlg_OffY)) 99 | zpos = zpos + tonumber(control_getCaption(SpawnObjectDlg_OffZ)) 100 | end 101 | local xscl = tonumber(control_getCaption(SpawnObjectDlg_SclX)) 102 | local yscl = tonumber(control_getCaption(SpawnObjectDlg_SclY)) 103 | local zscl = tonumber(control_getCaption(SpawnObjectDlg_SclZ)) 104 | if customname then name = control_getCaption(SpawnObjectDlg_ObjectName) else name = objname end 105 | objaddr = SpawnObject(routine, name, flags, list, customname, xpos, ypos, zpos, xrot, yrot, zrot, xscl, yscl, zscl, 0) 106 | spawnqueue = {} 107 | OCUpdateControls() 108 | end 109 | 110 | function SpawnObjectHere(routine, name, flags, list, customname, xscl, yscl, zscl) 111 | local xpos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 112 | local ypos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 113 | local zpos = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 114 | local xrot = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x08)) 115 | local yrot = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x0C)) 116 | local zrot = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x10)) 117 | SpawnObject(routine, name, flags, list, customname, xpos, ypos, zpos, xrot, yrot, zrot, xscl, yscl, zscl, 0) 118 | end 119 | 120 | function ReplaceObjectClick(sender) 121 | local xrot local yrot local zrot 122 | local routine = tonumber(control_getCaption(SpawnObjectDlg_MainRoutine), 16) 123 | local flags = tonumber(control_getCaption(SpawnObjectDlg_Flags), 16) 124 | local list = tonumber(control_getCaption(SpawnObjectDlg_ListID), 16) 125 | local copyrot = (checkbox_getState(SpawnObjectDlg_UsePlayerRot) == cbChecked) 126 | local customname = (objname == 0) 127 | if customname then name = control_getCaption(SpawnObjectDlg_ObjectName) else name = objname end 128 | if copyrot then 129 | xrot = readFloat(GetObjData1(objaddr, 0x08)) 130 | yrot = readFloat(GetObjData1(objaddr, 0x0C)) 131 | zrot = readFloat(GetObjData1(objaddr, 0x10)) 132 | else 133 | xrot = tonumber(control_getCaption(SpawnObjectDlg_RotX), 16) 134 | yrot = tonumber(control_getCaption(SpawnObjectDlg_RotY), 16) 135 | zrot = tonumber(control_getCaption(SpawnObjectDlg_RotZ), 16) 136 | end 137 | local xpos = readFloat(GetObjData1(objaddr, 0x14)) 138 | local ypos = readFloat(GetObjData1(objaddr, 0x18)) 139 | local zpos = readFloat(GetObjData1(objaddr, 0x1C)) 140 | local xscl = tonumber(control_getCaption(SpawnObjectDlg_SclX)) 141 | local yscl = tonumber(control_getCaption(SpawnObjectDlg_SclY)) 142 | local zscl = tonumber(control_getCaption(SpawnObjectDlg_SclZ)) 143 | writeInteger(objaddr + 0x10, 0x46F720) -- Delete the selected object 144 | OLRemoveObject(objaddr) 145 | local obj = SpawnObject(routine, name, flags, list, customname, xpos, ypos, zpos, xrot, yrot, zrot, xscl, yscl, zscl, 0) 146 | objaddr = obj 147 | OCUpdateControls() 148 | end 149 | 150 | function GetStageObjList() 151 | local list = {} 152 | local objlist = readInteger(0x1DDE268) 153 | local count = readInteger(objlist) 154 | objlist = readInteger(objlist + 0x04) 155 | 156 | for i=0,count-1 do 157 | local entry = {} 158 | entry.name = readInteger(objlist + 0x0C) 159 | entry.namestr = readString(entry.name, 64) 160 | entry.flags = readBytes(objlist, 1, false) 161 | entry.list = readBytes(objlist + 0x01, 1, false) 162 | entry.routine = readInteger(objlist + 0x08) 163 | table.insert(list, entry) 164 | objlist = objlist + 0x10 165 | end 166 | 167 | return list 168 | end 169 | 170 | function PopulateObjListClick(sender) 171 | local objlist = readInteger(0x1DDE268) 172 | local count = readInteger(objlist) 173 | objlist = readInteger(objlist + 0x04) 174 | ol_name = {} 175 | ol_namestr = {} 176 | ol_flags = {} 177 | ol_list = {} 178 | ol_routine = {} 179 | for i=0,count-1 do 180 | local name = readInteger(objlist + 0x0C) 181 | local flags = readBytes(objlist, 1, false) 182 | local list = readBytes(objlist + 0x01, 1, false) 183 | local routine = readInteger(objlist + 0x08) 184 | table.insert(ol_name, name) 185 | table.insert(ol_namestr, readString(name, 64)) 186 | table.insert(ol_flags, flags) 187 | table.insert(ol_list, list) 188 | table.insert(ol_routine, routine) 189 | objlist = objlist + 0x10 190 | end 191 | local lbitems = listbox_getItems(SpawnObjectDlg_ObjectList) 192 | strings_clear(lbitems) 193 | for i,v in ipairs(ol_namestr) do 194 | strings_add(lbitems, v) 195 | end 196 | end 197 | 198 | function ObjectListSelectionChange(sender, user) 199 | local index = listbox_getItemIndex(sender) + 1 200 | objname = ol_name[index] 201 | control_setCaption(SpawnObjectDlg_ObjectName, ol_namestr[index]) 202 | control_setCaption(SpawnObjectDlg_MainRoutine, num2hex(ol_routine[index])) 203 | control_setCaption(SpawnObjectDlg_Flags, num2hex(ol_flags[index])) 204 | control_setCaption(SpawnObjectDlg_ListID, num2hex(ol_list[index])) 205 | end 206 | 207 | function ObjectNameChange(sender) 208 | local index = listbox_getItemIndex(SpawnObjectDlg_ObjectList) + 1 209 | local defaultname = ol_namestr[index] 210 | if control_getCaption(sender) ~= defaultname then 211 | objname = 0 212 | else 213 | objname = ol_name[index] 214 | end 215 | end 216 | 217 | function CheckForSpawnedObject() 218 | if hookcmd ~= nil and readInteger(hookcmd) == -1 then 219 | writeInteger(hookcmd, 0) 220 | local flags = readBytes(hookcmd + 0x0C, 1, false) 221 | local list = readInteger(hookcmd + 0x0D) 222 | local addr = readInteger(hookcmd + 0x04) 223 | local objname = readString(readInteger(addr + 0x44), 64) 224 | if objname:sub(1,5) == "$Lua$" then 225 | object_callbacks[objname:sub(6)](addr) 226 | else 227 | objaddr = addr 228 | OCUpdateControls() 229 | UpdateRemote() 230 | OLAddObject(objaddr, sp_routine_storage, flags, list) 231 | SpawnNextObject() 232 | end 233 | end 234 | end 235 | 236 | function UsePlayerRotChange(sender) 237 | local enable = not (checkbox_getState(sender) == cbChecked) 238 | control_setEnabled(SpawnObjectDlg_RotX, enable) 239 | control_setEnabled(SpawnObjectDlg_RotY, enable) 240 | control_setEnabled(SpawnObjectDlg_RotZ, enable) 241 | control_setEnabled(SpawnObjectDlg_SpawnRotSetZero, enable) 242 | end 243 | 244 | function SpawnRotSetZeroClick(sender) 245 | control_setCaption(SpawnObjectDlg_RotX, "0") 246 | control_setCaption(SpawnObjectDlg_RotY, "0") 247 | control_setCaption(SpawnObjectDlg_RotZ, "0") 248 | end 249 | 250 | function SpawnSclSetOneClick(sender) 251 | control_setCaption(SpawnObjectDlg_SclX, "1") 252 | control_setCaption(SpawnObjectDlg_SclY, "1") 253 | control_setCaption(SpawnObjectDlg_SclZ, "1") 254 | end 255 | 256 | function SpawnSclSetZeroClick(sender) 257 | control_setCaption(SpawnObjectDlg_SclX, "0") 258 | control_setCaption(SpawnObjectDlg_SclY, "0") 259 | control_setCaption(SpawnObjectDlg_SclZ, "0") 260 | end 261 | 262 | function PopObjListCommonClick(sender) 263 | ol_name = {} 264 | ol_namestr = {} 265 | ol_flags = {} 266 | ol_list = {} 267 | ol_routine = {} 268 | for s in io.lines("sa2lua/objectlist.csv") do 269 | local tbl = s:split(",") 270 | table.insert(ol_name, 0) 271 | table.insert(ol_namestr, tbl[1]) 272 | table.insert(ol_flags, tonumber(tbl[2], 16)) 273 | table.insert(ol_list, tonumber(tbl[3], 16)) 274 | table.insert(ol_routine, tonumber(tbl[4], 16)) 275 | end 276 | local lbitems = listbox_getItems(SpawnObjectDlg_ObjectList) 277 | strings_clear(lbitems) 278 | for i,v in ipairs(ol_namestr) do 279 | strings_add(lbitems, v) 280 | end 281 | end 282 | 283 | function ObjectListDblClick(sender) 284 | local index = listbox_getItemIndex(sender) + 1 285 | if index > 0 then 286 | local helpstr = "" 287 | local rthex = num2hex(ol_routine[index]) 288 | local file = io.open("sa2lua/objhelp/"..rthex..".txt") 289 | if file == nil then 290 | helpstr = "No help is available for this object. (yet)" 291 | else 292 | helpstr = file:read("*a") 293 | file:close() 294 | end 295 | messageDialog(helpstr, mtInformation, mbOK) 296 | end 297 | end 298 | 299 | function ToggleCollisionBtnClick(sender) 300 | local addr = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x2C)) + 0x06 301 | if readBytes(addr, 1, false) == 0x00 then 302 | --Collision is currently off; turn it on 303 | writeBytes(addr, 0x02) 304 | UpdateCollisionButtonCaption(true) 305 | else 306 | --Collision is currently on; turn it off 307 | writeBytes(addr, 0x00) 308 | UpdateCollisionButtonCaption(false) 309 | end 310 | end 311 | 312 | function UpdateCollisionButtonCaption(isEnabled) 313 | if isEnabled == nil and IsPlayerValid() then 314 | local addr = readInteger(GetObjData1(readInteger(0x1DEA6E0), 0x2C)) + 0x06 315 | isEnabled = (readBytes(addr, 1, false) ~= 0x00) 316 | end 317 | 318 | if isEnabled then 319 | control_setCaption(SpawnObjectDlg_ToggleCollision, "Collision ON") 320 | else 321 | control_setCaption(SpawnObjectDlg_ToggleCollision, "Collision OFF") 322 | end 323 | end 324 | 325 | function OffsetSetZeroClick(sender) 326 | control_setCaption(SpawnObjectDlg_OffX, "0") 327 | control_setCaption(SpawnObjectDlg_OffY, "0") 328 | control_setCaption(SpawnObjectDlg_OffZ, "0") 329 | end 330 | 331 | dofile("sa2lua/spawnedlist.lua") 332 | dofile("sa2lua/objfile.lua") 333 | 334 | object_callbacks = {DrawLine3D = DrawLineObjectCallback} 335 | 336 | hookcmd = nil 337 | objname = 0 338 | ol_name = {} 339 | ol_namestr = {} 340 | ol_flags = {} 341 | ol_list = {} 342 | ol_routine = {} 343 | control_setEnabled(SpawnObjectDlg_SpawnObject, false) 344 | control_setEnabled(SpawnObjectDlg_ReplaceObject, false) 345 | control_setEnabled(SpawnObjectDlg_SpawnCylinder, false) 346 | strings_clear(listbox_getItems(SpawnObjectDlg_ObjectList)) -------------------------------------------------------------------------------- /Sample Object Lists/More Springs.csv: -------------------------------------------------------------------------------- 1 | Name,Routine,Flags,List,XPos,YPos,ZPos,XRot,YRot,ZRot,XScl,YScl,ZScl 2 | Iron Block,6D63F0,F,2,0,0,0,0,0,0,1,1,1 3 | Iron Block,6D63F0,F,2,20,0,0,0,0,0,1,1,1 4 | Iron Block,6D63F0,F,2,40,0,0,0,0,0,1,1,1 5 | Iron Block,6D63F0,F,2,60,0,0,0,0,0,1,1,1 6 | Iron Block,6D63F0,F,2,80,0,0,0,0,0,1,1,1 7 | Iron Block,6D63F0,F,2,100,0,0,0,0,0,1,1,1 8 | Iron Block,6D63F0,F,2,120,0,0,0,0,0,1,1,1 9 | Iron Block,6D63F0,F,2,140,0,0,0,0,0,1,1,1 10 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,0,0,0,0,1,1,1 11 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,0,0,0,0,1,1,1 12 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,0,0,0,0,1,1,1 13 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,0,0,0,0,1,1,1 14 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,0,0,0,0,1,1,1 15 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,0,0,0,0,1,1,1 16 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,0,0,0,0,1,1,1 17 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,0,0,0,0,1,1,1 18 | Wooden Plank,6CD7F0,F,2,0,100,0,0,0,0,1,1,1 19 | Wooden Plank,6CD7F0,F,2,20,100,0,0,0,0,1,1,1 20 | Wooden Plank,6CD7F0,F,2,40,100,0,0,0,0,1,1,1 21 | Wooden Plank,6CD7F0,F,2,60,100,0,0,0,0,1,1,1 22 | Wooden Plank,6CD7F0,F,2,80,100,0,0,0,0,1,1,1 23 | Wooden Plank,6CD7F0,F,2,100,100,0,0,0,0,1,1,1 24 | Wooden Plank,6CD7F0,F,2,120,100,0,0,0,0,1,1,1 25 | Wooden Plank,6CD7F0,F,2,140,100,0,0,0,0,1,1,1 26 | Iron Block,6D63F0,F,2,0,120,0,0,0,0,1,1,1 27 | Iron Block,6D63F0,F,2,20,120,0,0,0,0,1,1,1 28 | Iron Block,6D63F0,F,2,40,120,0,0,0,0,1,1,1 29 | Iron Block,6D63F0,F,2,60,120,0,0,0,0,1,1,1 30 | Iron Block,6D63F0,F,2,80,120,0,0,0,0,1,1,1 31 | Iron Block,6D63F0,F,2,100,120,0,0,0,0,1,1,1 32 | Iron Block,6D63F0,F,2,120,120,0,0,0,0,1,1,1 33 | Iron Block,6D63F0,F,2,140,120,0,0,0,0,1,1,1 34 | Iron Block,6D63F0,F,2,0,0,20,0,0,0,1,1,1 35 | Iron Block,6D63F0,F,2,20,0,20,0,0,0,1,1,1 36 | Iron Block,6D63F0,F,2,40,0,20,0,0,0,1,1,1 37 | Iron Block,6D63F0,F,2,60,0,20,0,0,0,1,1,1 38 | Iron Block,6D63F0,F,2,80,0,20,0,0,0,1,1,1 39 | Iron Block,6D63F0,F,2,100,0,20,0,0,0,1,1,1 40 | Iron Block,6D63F0,F,2,120,0,20,0,0,0,1,1,1 41 | Iron Block,6D63F0,F,2,140,0,20,0,0,0,1,1,1 42 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,20,0,0,0,1,1,1 43 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,20,0,0,0,1,1,1 44 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,20,0,0,0,1,1,1 45 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,20,0,0,0,1,1,1 46 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,20,0,0,0,1,1,1 47 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,20,0,0,0,1,1,1 48 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,20,0,0,0,1,1,1 49 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,20,0,0,0,1,1,1 50 | Wooden Plank,6CD7F0,F,2,0,100,20,0,0,0,1,1,1 51 | Weighted Pressure Plate (Light),6C4480,F,2,20,120,20,8000,0,0,1,1,1 52 | Weighted Pressure Plate (Light),6C4480,F,2,40,120,20,8000,0,0,1,1,1 53 | Weighted Pressure Plate (Light),6C4480,F,2,60,120,20,8000,0,0,1,1,1 54 | Weighted Pressure Plate (Light),6C4480,F,2,80,120,20,8000,0,0,1,1,1 55 | Weighted Pressure Plate (Light),6C4480,F,2,100,120,20,8000,0,0,1,1,1 56 | Weighted Pressure Plate (Light),6C4480,F,2,120,120,20,8000,0,0,1,1,1 57 | Wooden Plank,6CD7F0,F,2,140,100,20,0,0,0,1,1,1 58 | Iron Block,6D63F0,F,2,0,120,20,0,0,0,1,1,1 59 | Iron Block,6D63F0,F,2,20,120,20,0,0,0,1,1,1 60 | Iron Block,6D63F0,F,2,40,120,20,0,0,0,1,1,1 61 | Iron Block,6D63F0,F,2,60,120,20,0,0,0,1,1,1 62 | Iron Block,6D63F0,F,2,80,120,20,0,0,0,1,1,1 63 | Iron Block,6D63F0,F,2,100,120,20,0,0,0,1,1,1 64 | Iron Block,6D63F0,F,2,120,120,20,0,0,0,1,1,1 65 | Iron Block,6D63F0,F,2,140,120,20,0,0,0,1,1,1 66 | Iron Block,6D63F0,F,2,0,0,40,0,0,0,1,1,1 67 | Iron Block,6D63F0,F,2,20,0,40,0,0,0,1,1,1 68 | Iron Block,6D63F0,F,2,40,0,40,0,0,0,1,1,1 69 | Iron Block,6D63F0,F,2,60,0,40,0,0,0,1,1,1 70 | Iron Block,6D63F0,F,2,80,0,40,0,0,0,1,1,1 71 | Iron Block,6D63F0,F,2,100,0,40,0,0,0,1,1,1 72 | Iron Block,6D63F0,F,2,120,0,40,0,0,0,1,1,1 73 | Iron Block,6D63F0,F,2,140,0,40,0,0,0,1,1,1 74 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,40,0,0,0,1,1,1 75 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,40,0,0,0,1,1,1 76 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,40,0,0,0,1,1,1 77 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,40,0,0,0,1,1,1 78 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,40,0,0,0,1,1,1 79 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,40,0,0,0,1,1,1 80 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,40,0,0,0,1,1,1 81 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,40,0,0,0,1,1,1 82 | Wooden Plank,6CD7F0,F,2,0,100,40,0,0,0,1,1,1 83 | Weighted Pressure Plate (Light),6C4480,F,2,20,120,40,8000,0,0,1,1,1 84 | Weighted Pressure Plate (Light),6C4480,F,2,40,120,40,8000,0,0,1,1,1 85 | Weighted Pressure Plate (Light),6C4480,F,2,60,120,40,8000,0,0,1,1,1 86 | Weighted Pressure Plate (Light),6C4480,F,2,80,120,40,8000,0,0,1,1,1 87 | Weighted Pressure Plate (Light),6C4480,F,2,100,120,40,8000,0,0,1,1,1 88 | Weighted Pressure Plate (Light),6C4480,F,2,120,120,40,8000,0,0,1,1,1 89 | Wooden Plank,6CD7F0,F,2,140,100,40,0,0,0,1,1,1 90 | Iron Block,6D63F0,F,2,0,120,40,0,0,0,1,1,1 91 | Iron Block,6D63F0,F,2,20,120,40,0,0,0,1,1,1 92 | Iron Block,6D63F0,F,2,40,120,40,0,0,0,1,1,1 93 | Iron Block,6D63F0,F,2,60,120,40,0,0,0,1,1,1 94 | Iron Block,6D63F0,F,2,80,120,40,0,0,0,1,1,1 95 | Iron Block,6D63F0,F,2,100,120,40,0,0,0,1,1,1 96 | Iron Block,6D63F0,F,2,120,120,40,0,0,0,1,1,1 97 | Iron Block,6D63F0,F,2,140,120,40,0,0,0,1,1,1 98 | Iron Block,6D63F0,F,2,0,0,60,0,0,0,1,1,1 99 | Iron Block,6D63F0,F,2,20,0,60,0,0,0,1,1,1 100 | Iron Block,6D63F0,F,2,40,0,60,0,0,0,1,1,1 101 | Iron Block,6D63F0,F,2,60,0,60,0,0,0,1,1,1 102 | Iron Block,6D63F0,F,2,80,0,60,0,0,0,1,1,1 103 | Iron Block,6D63F0,F,2,100,0,60,0,0,0,1,1,1 104 | Iron Block,6D63F0,F,2,120,0,60,0,0,0,1,1,1 105 | Iron Block,6D63F0,F,2,140,0,60,0,0,0,1,1,1 106 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,60,0,0,0,1,1,1 107 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,60,0,0,0,1,1,1 108 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,60,0,0,0,1,1,1 109 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,60,0,0,0,1,1,1 110 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,60,0,0,0,1,1,1 111 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,60,0,0,0,1,1,1 112 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,60,0,0,0,1,1,1 113 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,60,0,0,0,1,1,1 114 | Wooden Plank,6CD7F0,F,2,0,100,60,0,0,0,1,1,1 115 | Weighted Pressure Plate (Light),6C4480,F,2,20,120,60,8000,0,0,1,1,1 116 | Weighted Pressure Plate (Light),6C4480,F,2,40,120,60,8000,0,0,1,1,1 117 | Weighted Pressure Plate (Light),6C4480,F,2,60,120,60,8000,0,0,1,1,1 118 | Weighted Pressure Plate (Light),6C4480,F,2,80,120,60,8000,0,0,1,1,1 119 | Weighted Pressure Plate (Light),6C4480,F,2,100,120,60,8000,0,0,1,1,1 120 | Weighted Pressure Plate (Light),6C4480,F,2,120,120,60,8000,0,0,1,1,1 121 | Wooden Plank,6CD7F0,F,2,140,100,60,0,0,0,1,1,1 122 | Iron Block,6D63F0,F,2,0,120,60,0,0,0,1,1,1 123 | Iron Block,6D63F0,F,2,20,120,60,0,0,0,1,1,1 124 | Iron Block,6D63F0,F,2,40,120,60,0,0,0,1,1,1 125 | Iron Block,6D63F0,F,2,60,120,60,0,0,0,1,1,1 126 | Iron Block,6D63F0,F,2,80,120,60,0,0,0,1,1,1 127 | Iron Block,6D63F0,F,2,100,120,60,0,0,0,1,1,1 128 | Iron Block,6D63F0,F,2,120,120,60,0,0,0,1,1,1 129 | Iron Block,6D63F0,F,2,140,120,60,0,0,0,1,1,1 130 | Iron Block,6D63F0,F,2,0,0,80,0,0,0,1,1,1 131 | Iron Block,6D63F0,F,2,20,0,80,0,0,0,1,1,1 132 | Iron Block,6D63F0,F,2,40,0,80,0,0,0,1,1,1 133 | Iron Block,6D63F0,F,2,60,0,80,0,0,0,1,1,1 134 | Iron Block,6D63F0,F,2,80,0,80,0,0,0,1,1,1 135 | Iron Block,6D63F0,F,2,100,0,80,0,0,0,1,1,1 136 | Iron Block,6D63F0,F,2,120,0,80,0,0,0,1,1,1 137 | Iron Block,6D63F0,F,2,140,0,80,0,0,0,1,1,1 138 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,80,0,0,0,1,1,1 139 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,80,0,0,0,1,1,1 140 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,80,0,0,0,1,1,1 141 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,80,0,0,0,1,1,1 142 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,80,0,0,0,1,1,1 143 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,80,0,0,0,1,1,1 144 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,80,0,0,0,1,1,1 145 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,80,0,0,0,1,1,1 146 | Wooden Plank,6CD7F0,F,2,0,100,80,0,0,0,1,1,1 147 | Weighted Pressure Plate (Light),6C4480,F,2,20,120,80,8000,0,0,1,1,1 148 | Weighted Pressure Plate (Light),6C4480,F,2,40,120,80,8000,0,0,1,1,1 149 | Weighted Pressure Plate (Light),6C4480,F,2,60,120,80,8000,0,0,1,1,1 150 | Weighted Pressure Plate (Light),6C4480,F,2,80,120,80,8000,0,0,1,1,1 151 | Weighted Pressure Plate (Light),6C4480,F,2,100,120,80,8000,0,0,1,1,1 152 | Weighted Pressure Plate (Light),6C4480,F,2,120,120,80,8000,0,0,1,1,1 153 | Wooden Plank,6CD7F0,F,2,140,100,80,0,0,0,1,1,1 154 | Iron Block,6D63F0,F,2,0,120,80,0,0,0,1,1,1 155 | Iron Block,6D63F0,F,2,20,120,80,0,0,0,1,1,1 156 | Iron Block,6D63F0,F,2,40,120,80,0,0,0,1,1,1 157 | Iron Block,6D63F0,F,2,60,120,80,0,0,0,1,1,1 158 | Iron Block,6D63F0,F,2,80,120,80,0,0,0,1,1,1 159 | Iron Block,6D63F0,F,2,100,120,80,0,0,0,1,1,1 160 | Iron Block,6D63F0,F,2,120,120,80,0,0,0,1,1,1 161 | Iron Block,6D63F0,F,2,140,120,80,0,0,0,1,1,1 162 | Iron Block,6D63F0,F,2,0,0,100,0,0,0,1,1,1 163 | Iron Block,6D63F0,F,2,20,0,100,0,0,0,1,1,1 164 | Iron Block,6D63F0,F,2,40,0,100,0,0,0,1,1,1 165 | Iron Block,6D63F0,F,2,60,0,100,0,0,0,1,1,1 166 | Iron Block,6D63F0,F,2,80,0,100,0,0,0,1,1,1 167 | Iron Block,6D63F0,F,2,100,0,100,0,0,0,1,1,1 168 | Iron Block,6D63F0,F,2,120,0,100,0,0,0,1,1,1 169 | Iron Block,6D63F0,F,2,140,0,100,0,0,0,1,1,1 170 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,100,0,0,0,1,1,1 171 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,100,0,0,0,1,1,1 172 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,100,0,0,0,1,1,1 173 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,100,0,0,0,1,1,1 174 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,100,0,0,0,1,1,1 175 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,100,0,0,0,1,1,1 176 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,100,0,0,0,1,1,1 177 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,100,0,0,0,1,1,1 178 | Wooden Plank,6CD7F0,F,2,0,100,100,0,0,0,1,1,1 179 | Weighted Pressure Plate (Light),6C4480,F,2,20,120,100,8000,0,0,1,1,1 180 | Weighted Pressure Plate (Light),6C4480,F,2,40,120,100,8000,0,0,1,1,1 181 | Weighted Pressure Plate (Light),6C4480,F,2,60,120,100,8000,0,0,1,1,1 182 | Weighted Pressure Plate (Light),6C4480,F,2,80,120,100,8000,0,0,1,1,1 183 | Weighted Pressure Plate (Light),6C4480,F,2,100,120,100,8000,0,0,1,1,1 184 | Weighted Pressure Plate (Light),6C4480,F,2,120,120,100,8000,0,0,1,1,1 185 | Wooden Plank,6CD7F0,F,2,140,100,100,0,0,0,1,1,1 186 | Iron Block,6D63F0,F,2,0,120,100,0,0,0,1,1,1 187 | Iron Block,6D63F0,F,2,20,120,100,0,0,0,1,1,1 188 | Iron Block,6D63F0,F,2,40,120,100,0,0,0,1,1,1 189 | Iron Block,6D63F0,F,2,60,120,100,0,0,0,1,1,1 190 | Iron Block,6D63F0,F,2,80,120,100,0,0,0,1,1,1 191 | Iron Block,6D63F0,F,2,100,120,100,0,0,0,1,1,1 192 | Iron Block,6D63F0,F,2,120,120,100,0,0,0,1,1,1 193 | Iron Block,6D63F0,F,2,140,120,100,0,0,0,1,1,1 194 | Iron Block,6D63F0,F,2,0,0,120,0,0,0,1,1,1 195 | Iron Block,6D63F0,F,2,20,0,120,0,0,0,1,1,1 196 | Iron Block,6D63F0,F,2,40,0,120,0,0,0,1,1,1 197 | Iron Block,6D63F0,F,2,60,0,120,0,0,0,1,1,1 198 | Iron Block,6D63F0,F,2,80,0,120,0,0,0,1,1,1 199 | Iron Block,6D63F0,F,2,100,0,120,0,0,0,1,1,1 200 | Iron Block,6D63F0,F,2,120,0,120,0,0,0,1,1,1 201 | Iron Block,6D63F0,F,2,140,0,120,0,0,0,1,1,1 202 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,120,0,0,0,1,1,1 203 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,120,0,0,0,1,1,1 204 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,120,0,0,0,1,1,1 205 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,120,0,0,0,1,1,1 206 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,120,0,0,0,1,1,1 207 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,120,0,0,0,1,1,1 208 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,120,0,0,0,1,1,1 209 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,120,0,0,0,1,1,1 210 | Wooden Plank,6CD7F0,F,2,0,100,120,0,0,0,1,1,1 211 | Weighted Pressure Plate (Light),6C4480,F,2,20,120,120,8000,0,0,1,1,1 212 | Weighted Pressure Plate (Light),6C4480,F,2,40,120,120,8000,0,0,1,1,1 213 | Weighted Pressure Plate (Light),6C4480,F,2,60,120,120,8000,0,0,1,1,1 214 | Weighted Pressure Plate (Light),6C4480,F,2,80,120,120,8000,0,0,1,1,1 215 | Weighted Pressure Plate (Light),6C4480,F,2,100,120,120,8000,0,0,1,1,1 216 | Weighted Pressure Plate (Light),6C4480,F,2,120,120,120,8000,0,0,1,1,1 217 | Wooden Plank,6CD7F0,F,2,140,100,120,0,0,0,1,1,1 218 | Iron Block,6D63F0,F,2,0,120,120,0,0,0,1,1,1 219 | Iron Block,6D63F0,F,2,20,120,120,0,0,0,1,1,1 220 | Iron Block,6D63F0,F,2,40,120,120,0,0,0,1,1,1 221 | Iron Block,6D63F0,F,2,60,120,120,0,0,0,1,1,1 222 | Iron Block,6D63F0,F,2,80,120,120,0,0,0,1,1,1 223 | Iron Block,6D63F0,F,2,100,120,120,0,0,0,1,1,1 224 | Iron Block,6D63F0,F,2,120,120,120,0,0,0,1,1,1 225 | Iron Block,6D63F0,F,2,140,120,120,0,0,0,1,1,1 226 | Iron Block,6D63F0,F,2,0,0,140,0,0,0,1,1,1 227 | Iron Block,6D63F0,F,2,20,0,140,0,0,0,1,1,1 228 | Iron Block,6D63F0,F,2,40,0,140,0,0,0,1,1,1 229 | Iron Block,6D63F0,F,2,60,0,140,0,0,0,1,1,1 230 | Iron Block,6D63F0,F,2,80,0,140,0,0,0,1,1,1 231 | Iron Block,6D63F0,F,2,100,0,140,0,0,0,1,1,1 232 | Iron Block,6D63F0,F,2,120,0,140,0,0,0,1,1,1 233 | Iron Block,6D63F0,F,2,140,0,140,0,0,0,1,1,1 234 | Weighted Pressure Plate (Light),6C4480,F,2,0,20,140,0,0,0,1,1,1 235 | Weighted Pressure Plate (Light),6C4480,F,2,20,20,140,0,0,0,1,1,1 236 | Weighted Pressure Plate (Light),6C4480,F,2,40,20,140,0,0,0,1,1,1 237 | Weighted Pressure Plate (Light),6C4480,F,2,60,20,140,0,0,0,1,1,1 238 | Weighted Pressure Plate (Light),6C4480,F,2,80,20,140,0,0,0,1,1,1 239 | Weighted Pressure Plate (Light),6C4480,F,2,100,20,140,0,0,0,1,1,1 240 | Weighted Pressure Plate (Light),6C4480,F,2,120,20,140,0,0,0,1,1,1 241 | Weighted Pressure Plate (Light),6C4480,F,2,140,20,140,0,0,0,1,1,1 242 | Wooden Plank,6CD7F0,F,2,0,100,140,0,0,0,1,1,1 243 | Wooden Plank,6CD7F0,F,2,20,100,140,0,0,0,1,1,1 244 | Wooden Plank,6CD7F0,F,2,40,100,140,0,0,0,1,1,1 245 | Wooden Plank,6CD7F0,F,2,60,100,140,0,0,0,1,1,1 246 | Wooden Plank,6CD7F0,F,2,80,100,140,0,0,0,1,1,1 247 | Wooden Plank,6CD7F0,F,2,100,100,140,0,0,0,1,1,1 248 | Wooden Plank,6CD7F0,F,2,120,100,140,0,0,0,1,1,1 249 | Wooden Plank,6CD7F0,F,2,140,100,140,0,0,0,1,1,1 250 | Iron Block,6D63F0,F,2,0,120,140,0,0,0,1,1,1 251 | Iron Block,6D63F0,F,2,20,120,140,0,0,0,1,1,1 252 | Iron Block,6D63F0,F,2,40,120,140,0,0,0,1,1,1 253 | Iron Block,6D63F0,F,2,60,120,140,0,0,0,1,1,1 254 | Iron Block,6D63F0,F,2,80,120,140,0,0,0,1,1,1 255 | Iron Block,6D63F0,F,2,100,120,140,0,0,0,1,1,1 256 | Iron Block,6D63F0,F,2,120,120,140,0,0,0,1,1,1 257 | Iron Block,6D63F0,F,2,140,120,140,0,0,0,1,1,1 258 | -------------------------------------------------------------------------------- /Sample Object Lists/Plant more trees in City Escape.csv: -------------------------------------------------------------------------------- 1 | name,routine,flags,list,xpos,ypos,zpos,xrot,yrot,zrot,xscl,yscl,zscl 2 | TREEST,5EB370,2,2,-1508.3133544922,-6260,9338.09765625,0,0,0,1,1,1 3 | TREEST,5EB370,2,2,-1496.8786621094,-6260,9411.3408203125,0,0,0,1,1,1 4 | TREEST,5EB370,2,2,-1450.4523925781,-6260,9412.490234375,0,0,0,1,1,1 5 | TREEST,5EB370,2,2,-1387.8610839844,-6260,9393.6513671875,0,0,0,1,1,1 6 | TREEST,5EB370,2,2,-1539.6619873047,-6260,9432.427734375,0,0,0,1,1,1 7 | TREEST,5EB370,2,2,-1586.1766357422,-6260,9404.2998046875,0,0,0,1,1,1 8 | TREEST,5EB370,2,2,-1226.9134521484,-6210,9392.97265625,0,0,0,1,1,1 9 | TREEST,5EB370,2,2,-1199.3826904297,-6210,9420.748046875,0,0,0,1,1,1 10 | TREEST,5EB370,2,2,-1158.8883056641,-6210,9432.427734375,0,0,0,1,1,1 11 | TREEST,5EB370,2,2,-1123.7438964844,-6210,9410.4130859375,0,0,0,1,1,1 12 | TREEST,5EB370,2,2,-1047.3190917969,-6210,9432.40625,0,0,0,1,1,1 13 | TREEST,5EB370,2,2,-986.99298095703,-6210,9428.494140625,0,0,0,1,1,1 14 | TREEST,5EB370,2,2,-928.35748291016,-6210,9412.6328125,0,0,0,1,1,1 15 | TREEST,5EB370,2,2,-893.43176269531,-6210,9439.4990234375,0,0,0,1,1,1 16 | TREEST,5EB370,2,2,-841.7880859375,-6210,9431.619140625,0,0,0,1,1,1 17 | TREEST,5EB370,2,2,-757.41583251953,-6352.0786132813,9744.876953125,0,0,0,1,1,1 18 | TREEST,5EB370,2,2,-756.61145019531,-6346.4731445313,9718.2509765625,0,0,0,1,1,1 19 | TREEST,5EB370,2,2,-755.19146728516,-6335.44921875,9665.8759765625,0,0,0,1,1,1 20 | TREEST,5EB370,2,2,-753.82427978516,-6324.7861328125,9615.2412109375,0,0,0,1,1,1 21 | TREEST,5EB370,2,2,-752.99725341797,-6320.47265625,9594.7470703125,0,0,0,1,1,1 22 | TREEST,5EB370,2,2,-750.23687744141,-6312.3891601563,9556.345703125,0,0,0,1,1,1 23 | TREEST,5EB370,2,2,-760.60900878906,-6296.1079101563,9479.015625,0,0,0,1,1,1 24 | TREEST,5EB370,2,2,-754.34405517578,-6290.8608398438,9454.09375,0,0,0,1,1,1 25 | TREEST,5EB370,2,2,-680.72967529297,-6307.5634765625,9533.4189453125,0,0,0,1,1,1 26 | TREEST,5EB370,2,2,-670.78558349609,-6319.36328125,9589.4765625,0,0,0,1,1,1 27 | TREEST,5EB370,2,2,-679.61004638672,-6332.134765625,9650.1328125,0,0,0,1,1,1 28 | TREEST,5EB370,2,2,-689.33477783203,-6342.9946289063,9701.72265625,0,0,0,1,1,1 29 | TREEST,5EB370,2,2,-606.45989990234,-6270,10069.758789063,0,0,0,1,1,1 30 | TREEST,5EB370,2,2,369.44201660156,-6570,9946.8388671875,0,0,0,1,1,1 31 | TREEST,5EB370,2,2,312.60940551758,-6570,9958.0341796875,0,0,0,1,1,1 32 | TREEST,5EB370,2,2,280.74166870117,-6570,10046.2734375,0,0,0,1,1,1 33 | TREEST,5EB370,2,2,336.15515136719,-6470,9744.81640625,0,0,0,1,1,1 34 | TREEST,5EB370,2,2,365.46014404297,-6470,9713.7802734375,0,0,0,1,1,1 35 | TREEST,5EB370,2,2,388.37637329102,-6470,9654.744140625,0,0,0,1,1,1 36 | TREEST,5EB370,2,2,2637.2905273438,-8662.6884765625,6188.0317382813,0,0,0,1,1,1 37 | TREEST,5EB370,2,2,2655.4011230469,-8662.6884765625,6148.3779296875,0,0,0,1,1,1 38 | TREEST,5EB370,2,2,2655.4296875,-8662.6884765625,6088.2900390625,0,0,0,1,1,1 39 | TREEST,5EB370,2,2,2649.7229003906,-8662.6884765625,6035.8618164063,0,0,0,1,1,1 40 | TREEST,5EB370,2,2,2653.9587402344,-8662.6884765625,5967.8833007813,0,0,0,1,1,1 41 | TREEST,5EB370,2,2,2652.2463378906,-8662.6884765625,5889.8393554688,0,0,0,1,1,1 42 | TREEST,5EB370,2,2,2646.1916503906,-8662.6884765625,5804.8422851563,0,0,0,1,1,1 43 | TREEST,5EB370,2,2,2693.7023925781,-8627.6884765625,5811.2036132813,0,0,0,1,1,1 44 | TREEST,5EB370,2,2,2690.3479003906,-8627.6884765625,5899.2905273438,0,0,0,1,1,1 45 | TREEST,5EB370,2,2,2692.6459960938,-8627.6884765625,5973.666015625,0,0,0,1,1,1 46 | TREEST,5EB370,2,2,2707.595703125,-8627.6884765625,6113.3940429688,0,0,0,1,1,1 47 | TREEST,5EB370,2,2,2781.0205078125,-8572.6884765625,6046.1635742188,0,0,0,1,1,1 48 | TREEST,5EB370,2,2,2789.1298828125,-8572.6884765625,6196.38671875,0,0,0,1,1,1 49 | TREEST,5EB370,2,2,2805.0161132813,-8572.6884765625,5902.7739257813,0,0,0,1,1,1 50 | TREEST,5EB370,2,2,2789.58203125,-8572.6884765625,5839.0029296875,0,0,0,1,1,1 51 | TREEST,5EB370,2,2,2760.0080566406,-8572.6884765625,5750.5766601563,0,0,0,1,1,1 52 | TREEST,5EB370,2,2,2771.177734375,-8572.6884765625,5636.453125,0,0,0,1,1,1 53 | TREEST,5EB370,2,2,2780.1076660156,-8572.6884765625,6482.2680664063,0,0,0,1,1,1 54 | TREEST,5EB370,2,2,2784.7612304688,-8572.6884765625,6570.3369140625,0,0,0,1,1,1 55 | TREEST,5EB370,2,2,2783.5971679688,-8572.6884765625,6658.2768554688,0,0,0,1,1,1 56 | TREEST,5EB370,2,2,2791.337890625,-8572.6884765625,6793.37109375,0,0,0,1,1,1 57 | TREEST,5EB370,2,2,2779.5744628906,-8572.6884765625,6911.1064453125,0,0,0,1,1,1 58 | TREEST,5EB370,2,2,2791.6977539063,-8572.6884765625,7007.2260742188,0,0,0,1,1,1 59 | TREEST,5EB370,2,2,2780.6767578125,-8572.6884765625,7201.5541992188,0,0,0,1,1,1 60 | TREEST,5EB370,2,2,2752.7348632813,-8597.6884765625,7141.6616210938,0,0,0,1,1,1 61 | TREEST,5EB370,2,2,2744.4992675781,-8597.6884765625,7088.3920898438,0,0,0,1,1,1 62 | TREEST,5EB370,2,2,2742.7834472656,-8597.6884765625,6989.3330078125,0,0,0,1,1,1 63 | TREEST,5EB370,2,2,2750.0795898438,-8597.6884765625,6857.4965820313,0,0,0,1,1,1 64 | TREEST,5EB370,2,2,2727.4194335938,-8597.6884765625,6760.5991210938,0,0,0,1,1,1 65 | TREEST,5EB370,2,2,2739.4611816406,-8597.6884765625,6628.8588867188,0,0,0,1,1,1 66 | TREEST,5EB370,2,2,2721.7487792969,-8612.6884765625,6550.1791992188,0,0,0,1,1,1 67 | TREEST,5EB370,2,2,2721.2770996094,-8612.6884765625,6696.5405273438,0,0,0,1,1,1 68 | TREEST,5EB370,2,2,2730.2260742188,-8612.6884765625,6793.5815429688,0,0,0,1,1,1 69 | TREEST,5EB370,2,2,2721.6481933594,-8612.6884765625,6904.1469726563,0,0,0,1,1,1 70 | TREEST,5EB370,2,2,2728.92578125,-8612.6884765625,6984.462890625,0,0,0,1,1,1 71 | TREEST,5EB370,2,2,2718.8266601563,-8612.6884765625,7063.287109375,0,0,0,1,1,1 72 | TREEST,5EB370,2,2,2718.9702148438,-8612.6884765625,7143.1474609375,0,0,0,1,1,1 73 | TREEST,5EB370,2,2,2689.5522460938,-8637.6884765625,6537.3686523438,0,0,0,1,1,1 74 | TREEST,5EB370,2,2,2675.2844238281,-8637.6884765625,6604.5146484375,0,0,0,1,1,1 75 | TREEST,5EB370,2,2,2652.0822753906,-8637.6884765625,6671.6547851563,0,0,0,1,1,1 76 | TREEST,5EB370,2,2,2700.1103515625,-8637.6884765625,6725.3955078125,0,0,0,1,1,1 77 | TREEST,5EB370,2,2,2653.8220214844,-8637.6884765625,6753.3935546875,0,0,0,1,1,1 78 | TREEST,5EB370,2,2,2677.9045410156,-8637.6884765625,6832.9663085938,0,0,0,1,1,1 79 | TREEST,5EB370,2,2,2635.841796875,-8637.6884765625,6849.9912109375,0,0,0,1,1,1 80 | TREEST,5EB370,2,2,2672.8757324219,-8637.6884765625,6935.6943359375,0,0,0,1,1,1 81 | TREEST,5EB370,2,2,2629.8010253906,-8637.6884765625,7161.6899414063,0,0,0,1,1,1 82 | TREEST,5EB370,2,2,2621.2998046875,-8637.6884765625,7081.80859375,0,0,0,1,1,1 83 | TREEST,5EB370,2,2,2584.2570800781,-8697.6884765625,6923.748046875,0,0,0,1,1,1 84 | TREEST,5EB370,2,2,2554.9028320313,-8697.6884765625,6838.5830078125,0,0,0,1,1,1 85 | TREEST,5EB370,2,2,2588.4841308594,-8697.6884765625,6806.0297851563,0,0,0,1,1,1 86 | TREEST,5EB370,2,2,2562.8801269531,-8697.6884765625,6700.4111328125,0,0,0,1,1,1 87 | TREEST,5EB370,2,2,2582.96484375,-8697.6884765625,6631.8989257813,0,0,0,1,1,1 88 | TREEST,5EB370,2,2,2595.61328125,-8697.6884765625,6547.806640625,0,0,0,1,1,1 89 | TREEST,5EB370,2,2,2581.6547851563,-8697.6884765625,6498.4594726563,0,0,0,1,1,1 90 | TREEST,5EB370,2,2,2603.3227539063,-8705,6421.015625,0,0,0,1,1,1 91 | TREEST,5EB370,2,2,2594.1823730469,-8705,6305,0,0,0,1,1,1 92 | TREEST,5EB370,2,2,2677.4426269531,-8655,6430.021484375,0,0,0,1,1,1 93 | TREEST,5EB370,2,2,2690.7934570313,-8655,6305,0,0,0,1,1,1 94 | TREEST,5EB370,2,2,5757.2133789063,-10740,4498.9448242188,0,0,0,1,1,1 95 | TREEST,5EB370,2,2,5764.669921875,-10740,4365.5908203125,0,0,0,1,1,1 96 | TREEST,5EB370,2,2,5778.0756835938,-10740,4362.5708007813,0,0,0,1,1,1 97 | TREEST,5EB370,2,2,5820.9780273438,-10740,4360.4125976563,0,0,0,1,1,1 98 | TREEST,5EB370,2,2,5868.8203125,-10740,4356.3627929688,0,0,0,1,1,1 99 | TREEST,5EB370,2,2,6305.7763671875,-10890,5051.3579101563,0,0,0,1,1,1 100 | TREEST,5EB370,2,2,6217.9291992188,-10890,5039.4423828125,0,0,0,1,1,1 101 | TREEST,5EB370,2,2,6165.3305664063,-10890,5033.4877929688,0,0,0,1,1,1 102 | TREEST,5EB370,2,2,6197.6118164063,-10890,4896.4248046875,0,0,0,1,1,1 103 | TREEST,5EB370,2,2,6218.1147460938,-10890,4906.81640625,0,0,0,1,1,1 104 | TREEST,5EB370,2,2,6257.431640625,-10890,4899.4658203125,0,0,0,1,1,1 105 | TREEST,5EB370,2,2,6299.8198242188,-10890,4877.466796875,0,0,0,1,1,1 106 | TREEST,5EB370,2,2,6615.1884765625,-11064.51171875,4829.046875,0,0,0,1,1,1 107 | TREEST,5EB370,2,2,6638.7041015625,-11070.633789063,4791.7153320313,0,0,0,1,1,1 108 | TREEST,5EB370,2,2,6698.4975585938,-11093.44921875,4799.8198242188,0,0,0,1,1,1 109 | TREEST,5EB370,2,2,6729.919921875,-11112.806640625,4834.3334960938,0,0,0,1,1,1 110 | TREEST,5EB370,2,2,6777.7280273438,-11136.661132813,4836.3979492188,0,0,0,1,1,1 111 | TREEST,5EB370,2,2,6795.8525390625,-11144.155273438,4821.6899414063,0,0,0,1,1,1 112 | TREEST,5EB370,2,2,6812.1557617188,-11150.954101563,4798.6264648438,0,0,0,1,1,1 113 | TREEST,5EB370,2,2,6825.2612304688,-11156.978515625,4777.2724609375,0,0,0,1,1,1 114 | TREEST,5EB370,2,2,6847.2333984375,-11170.20703125,4763.7016601563,0,0,0,1,1,1 115 | TREEST,5EB370,2,2,6890.1733398438,-11199.227539063,4755.9887695313,0,0,0,1,1,1 116 | TREEST,5EB370,2,2,6953.9331054688,-11240.05859375,4719.9692382813,0,0,0,1,1,1 117 | TREEST,5EB370,2,2,6998.0625,-11269.86328125,4706.5703125,0,0,0,1,1,1 118 | TREEST,5EB370,2,2,7041.0009765625,-11286.018554688,4724.58984375,0,0,0,1,1,1 119 | TREEST,5EB370,2,2,7064.6791992188,-11288.771484375,4764.556640625,0,0,0,1,1,1 120 | TREEST,5EB370,2,2,7082.4877929688,-11290.80078125,4808.1357421875,0,0,0,1,1,1 121 | TREEST,5EB370,2,2,7111.7607421875,-11289.133789063,4832.111328125,0,0,0,1,1,1 122 | TREEST,5EB370,2,2,7145.6137695313,-11297.575195313,4829.1796875,0,0,0,1,1,1 123 | TREEST,5EB370,2,2,7172.7592773438,-11312.8203125,4791.5170898438,0,0,0,1,1,1 124 | TREEST,5EB370,2,2,7224.4189453125,-11368.819335938,4732.0712890625,0,0,0,1,1,1 125 | TREEST,5EB370,2,2,7258.2202148438,-11388.227539063,4720.1206054688,0,0,0,1,1,1 126 | TREEST,5EB370,2,2,7306.2509765625,-11389.279296875,4729.0463867188,0,0,0,1,1,1 127 | TREEST,5EB370,2,2,7319.013671875,-11391.197265625,4757.3916015625,0,0,0,1,1,1 128 | TREEST,5EB370,2,2,7311.80859375,-11398.018554688,4806.0336914063,0,0,0,1,1,1 129 | TREEST,5EB370,2,2,7296.2978515625,-11403.55859375,4855.5419921875,0,0,0,1,1,1 130 | TREEST,5EB370,2,2,7295.708984375,-11407.884765625,4896.0546875,0,0,0,1,1,1 131 | TREEST,5EB370,2,2,7241.01171875,-11407.346679688,4948.6591796875,0,0,0,1,1,1 132 | TREEST,5EB370,2,2,7241.4130859375,-11404.512695313,5093.6938476563,0,0,0,1,1,1 133 | TREEST,5EB370,2,2,7257.5952148438,-11402.016601563,5128.1928710938,0,0,0,1,1,1 134 | TREEST,5EB370,2,2,7293.0556640625,-11396.125976563,5166.0795898438,0,0,0,1,1,1 135 | TREEST,5EB370,2,2,7325.119140625,-11405.700195313,5178.7177734375,0,0,0,1,1,1 136 | TREEST,5EB370,2,2,7376.2724609375,-11437.235351563,5180.3203125,0,0,0,1,1,1 137 | TREEST,5EB370,2,2,7403.0888671875,-11443.056640625,5180.3203125,0,0,0,1,1,1 138 | TREEST,5EB370,2,2,7372.5424804688,-11422.5859375,5233.45703125,0,0,0,1,1,1 139 | TREEST,5EB370,2,2,7345.8369140625,-11405.483398438,5230.0732421875,0,0,0,1,1,1 140 | TREEST,5EB370,2,2,7310.8540039063,-11385.0546875,5226.3872070313,0,0,0,1,1,1 141 | TREEST,5EB370,2,2,7251.2944335938,-11381.2109375,5227.8706054688,0,0,0,1,1,1 142 | TREEST,5EB370,2,2,7205.7592773438,-11372.254882813,5214.4404296875,0,0,0,1,1,1 143 | TREEST,5EB370,2,2,7188.9584960938,-11352.953125,5227.1684570313,0,0,0,1,1,1 144 | TREEST,5EB370,2,2,7143.9541015625,-11331.58203125,5241.9677734375,0,0,0,1,1,1 145 | TREEST,5EB370,2,2,7128.4130859375,-11321.495117188,5221.8315429688,0,0,0,1,1,1 146 | TREEST,5EB370,2,2,7119.3935546875,-11317.423828125,5190.3564453125,0,0,0,1,1,1 147 | TREEST,5EB370,2,2,7105.8520507813,-11310.190429688,5175.5581054688,0,0,0,1,1,1 148 | TREEST,5EB370,2,2,7105.7299804688,-11310.5234375,5167.5454101563,0,0,0,1,1,1 149 | TREEST,5EB370,2,2,6978.6762695313,-11238.094726563,5210.8251953125,0,0,0,1,1,1 150 | TREEST,5EB370,2,2,6997.4599609375,-11237.583007813,5281.021484375,0,0,0,1,1,1 151 | TREEST,5EB370,2,2,7032.0688476563,-11242.298828125,5290.6079101563,0,0,0,1,1,1 152 | TREEST,5EB370,2,2,7055.232421875,-11254.043945313,5276.1669921875,0,0,0,1,1,1 153 | TREEST,5EB370,2,2,7055.2973632813,-11259.006835938,5231.8935546875,0,0,0,1,1,1 154 | TREEST,5EB370,2,2,7035.2568359375,-11249.53125,5216.7465820313,0,0,0,1,1,1 155 | TREEST,5EB370,2,2,6979.3422851563,-11237.956054688,5234.2353515625,0,0,0,1,1,1 156 | TREEST,5EB370,2,2,6922.4663085938,-11225.076171875,5242.3012695313,0,0,0,1,1,1 157 | TREEST,5EB370,2,2,6875.5112304688,-11208.73828125,5192.865234375,0,0,0,1,1,1 158 | TREEST,5EB370,2,2,6844.8188476563,-11194.358398438,5190.5546875,0,0,0,1,1,1 159 | TREEST,5EB370,2,2,6831.1982421875,-11187.232421875,5216.6186523438,0,0,0,1,1,1 160 | TREEST,5EB370,2,2,6821.9458007813,-11180.427734375,5245.4140625,0,0,0,1,1,1 161 | TREEST,5EB370,2,2,6832.6420898438,-11187.376953125,5271.4243164063,0,0,0,1,1,1 162 | TREEST,5EB370,2,2,6836.837890625,-11189.16796875,5290.4453125,0,0,0,1,1,1 163 | TREEST,5EB370,2,2,6800.1567382813,-11160.930664063,5291.9619140625,0,0,0,1,1,1 164 | TREEST,5EB370,2,2,6801.171875,-11162.166015625,5283.5,0,0,0,1,1,1 165 | TREEST,5EB370,2,2,6798.4287109375,-11161.537109375,5244.00390625,0,0,0,1,1,1 166 | TREEST,5EB370,2,2,6788.0532226563,-11154.182617188,5209.2846679688,0,0,0,1,1,1 167 | TREEST,5EB370,2,2,6761.7260742188,-11135.108398438,5146.3588867188,0,0,0,1,1,1 168 | TREEST,5EB370,2,2,6732.68359375,-11118.299804688,5109.3364257813,0,0,0,1,1,1 169 | TREEST,5EB370,2,2,6724.8955078125,-11117.333984375,5076.6889648438,0,0,0,1,1,1 170 | TREEST,5EB370,2,2,6787.4965820313,-11156.053710938,5053.1328125,0,0,0,1,1,1 171 | TREEST,5EB370,2,2,7402.830078125,-11460.499023438,5090.4155273438,0,0,0,1,1,1 172 | TREEST,5EB370,2,2,7415.900390625,-11461.63671875,5115.2983398438,0,0,0,1,1,1 173 | TREEST,5EB370,2,2,7428.9892578125,-11466.310546875,5072.0561523438,0,0,0,1,1,1 174 | TREEST,5EB370,2,2,7364.7001953125,-11433.509765625,4891.8100585938,0,0,0,1,1,1 175 | TREEST,5EB370,2,2,7367.4829101563,-11408.971679688,4805.6328125,0,0,0,1,1,1 176 | TREEST,5EB370,2,2,7361.484375,-11390.172851563,4711.7856445313,0,0,0,1,1,1 177 | TREEST,5EB370,2,2,7288.6489257813,-11387.716796875,4656.2514648438,0,0,0,1,1,1 178 | TREEST,5EB370,2,2,7227.6572265625,-11368.614257813,4648.2641601563,0,0,0,1,1,1 179 | TREEST,5EB370,2,2,7670.3198242188,-14455,5975.896484375,0,0,0,1,1,1 180 | TREEST,5EB370,2,2,7686.95703125,-14455,6020.3701171875,0,0,0,1,1,1 181 | TREEST,5EB370,2,2,7682.3999023438,-14455,6145.1694335938,0,0,0,1,1,1 182 | TREEST,5EB370,2,2,7726.896484375,-14455,6137.1840820313,0,0,0,1,1,1 183 | TREEST,5EB370,2,2,7163.5991210938,-14455,6235.6953125,0,0,0,1,1,1 184 | TREEST,5EB370,2,2,7085.3188476563,-14455,6198.0805664063,0,0,0,1,1,1 185 | TREEST,5EB370,2,2,6415.3701171875,-15915,9024.353515625,0,0,0,1,1,1 186 | TREEST,5EB370,2,2,6400.5668945313,-15915,9058.63671875,0,0,0,1,1,1 187 | TREEST,5EB370,2,2,6488.6811523438,-15915,9101.154296875,0,0,0,1,1,1 188 | TREEST,5EB370,2,2,4025.2260742188,-22175,16171.48046875,0,0,0,1,1,1 189 | -------------------------------------------------------------------------------- /sa2lua/objkeys.lua: -------------------------------------------------------------------------------- 1 | -- objkeys.lua is an "Artifact Title". This file now contains most (if not all) of the code for Live Edit Mode. 2 | OMKHelpDlgText = [[Gamepad controls: 3 | Press DOWN to activate cursor 4 | Hold LEFT to move selected object 5 | Hold UP to rotate selected object 6 | Hold RIGHT for object-specific action 7 | 8 | Legacy keyboard controls: 9 | 10 | A/D - Move on X axis 11 | R/F - Move on Y axis 12 | W/S - Move on Z axis 13 | Q/E - Rotate around Y axis 14 | Z - Duplicate object 15 | X - Align to X/Z axes 16 | C - Same as "Spawn Object" button 17 | O/P - Select objects]] 18 | 19 | function ObjManipKeysToggleClick(sender) 20 | OMKActive = (checkbox_getState(sender) == cbChecked) 21 | if OMKActive then 22 | OMKHotkeyA = createHotkey(OMKKeyHandler, VK_A) 23 | OMKHotkeyD = createHotkey(OMKKeyHandler, VK_D) 24 | OMKHotkeyR = createHotkey(OMKKeyHandler, VK_R) 25 | OMKHotkeyF = createHotkey(OMKKeyHandler, VK_F) 26 | OMKHotkeyW = createHotkey(OMKKeyHandler, VK_W) 27 | OMKHotkeyS = createHotkey(OMKKeyHandler, VK_S) 28 | OMKHotkeyQ = createHotkey(OMKKeyHandler, VK_Q) 29 | OMKHotkeyE = createHotkey(OMKKeyHandler, VK_E) 30 | OMKHotkeyZ = createHotkey(OMKKeyHandler, VK_Z) 31 | OMKHotkeyX = createHotkey(OMKKeyHandler, VK_X) 32 | OMKHotkeyC = createHotkey(OMKKeyHandler, VK_C) 33 | OMKHotkeyO = createHotkey(OMKKeyHandler, VK_O) 34 | OMKHotkeyP = createHotkey(OMKKeyHandler, VK_P) 35 | EnableLineDrawingIfNecessary() 36 | OMKStart() 37 | else 38 | OMKStop() 39 | object_destroy(OMKHotkeyA) 40 | object_destroy(OMKHotkeyD) 41 | object_destroy(OMKHotkeyR) 42 | object_destroy(OMKHotkeyF) 43 | object_destroy(OMKHotkeyW) 44 | object_destroy(OMKHotkeyS) 45 | object_destroy(OMKHotkeyQ) 46 | object_destroy(OMKHotkeyE) 47 | object_destroy(OMKHotkeyZ) 48 | object_destroy(OMKHotkeyX) 49 | object_destroy(OMKHotkeyC) 50 | object_destroy(OMKHotkeyO) 51 | object_destroy(OMKHotkeyP) 52 | end 53 | end 54 | 55 | function UpdateObjectSelCube() 56 | if EnableObjectSpawning ~= nil and readInteger(linedraw_objaddr) ~= nil then 57 | if OMKActive and readFloat(GetObjData1(objaddr, 0x14)) ~= nil then 58 | local radius = OMKSelBoxRadiusOverride[readInteger(objaddr + 0x10)] or 10 59 | if radius ~= 0 then 60 | local x = readFloat(GetObjData1(objaddr, 0x14)) 61 | local y = readFloat(GetObjData1(objaddr, 0x18)) 62 | local z = readFloat(GetObjData1(objaddr, 0x1C)) 63 | local x1 = x - radius 64 | local y1 = y - radius 65 | local z1 = z - radius 66 | local x2 = x + radius 67 | local y2 = y + radius 68 | local z2 = z + radius 69 | DrawCube3D("SelectedObject", x1, y1, z1, x2, y2, z2, SelectionBoxColor) 70 | end 71 | else 72 | RemoveCube("SelectedObject") 73 | end 74 | end 75 | end 76 | 77 | function ObjManipKeysHelpClick(sender) 78 | messageDialog(OMKHelpDlgText, mtInformation, mbOK) 79 | end 80 | 81 | function OMKKeyHandler(sender) 82 | if getForegroundProcess() == getOpenedProcessID() then 83 | local inc = 4 84 | local x = readFloat(GetObjData1(objaddr, 0x14)) 85 | local y = readFloat(GetObjData1(objaddr, 0x18)) 86 | local z = readFloat(GetObjData1(objaddr, 0x1C)) 87 | local r = readInteger(GetObjData1(objaddr, 0x0C)) 88 | local curobj = objaddr 89 | 90 | if OMKActive then 91 | if x ~= nil then 92 | if isKeyPressed(VK_A) then x = x + inc 93 | elseif isKeyPressed(VK_D) then x = x - inc 94 | elseif isKeyPressed(VK_R) then y = y + inc 95 | elseif isKeyPressed(VK_F) then y = y - inc 96 | elseif isKeyPressed(VK_W) then z = z + inc 97 | elseif isKeyPressed(VK_S) then z = z - inc 98 | elseif isKeyPressed(VK_Q) then r = r + 0x1000 99 | elseif isKeyPressed(VK_E) then r = r - 0x1000 100 | elseif isKeyPressed(VK_Z) then OMKDuplicateObject() 101 | elseif isKeyPressed(VK_X) then 102 | x = 4 * round(x/4, 0) 103 | z = 4 * round(z/4, 0) 104 | end 105 | end 106 | 107 | -- The rest of the keys don't require a valid object selection to work. 108 | if isKeyPressed(VK_C) then 109 | SpawnObjectClick(SpawnObjectDlg_SpawnObject) --emulate button click 110 | elseif isKeyPressed(VK_O) then PrevObject() UpdateObjectSelCube() 111 | elseif isKeyPressed(VK_P) then NextObject() UpdateObjectSelCube() 112 | end 113 | end 114 | 115 | if curobj == objaddr then 116 | writeFloat(GetObjData1(objaddr, 0x14), x) 117 | writeFloat(GetObjData1(objaddr, 0x18), y) 118 | writeFloat(GetObjData1(objaddr, 0x1C), z) 119 | writeInteger(GetObjData1(objaddr, 0x0C), r) 120 | end 121 | end 122 | end 123 | 124 | function OMKDuplicateObject() 125 | local routine = readInteger(objaddr + 0x10) 126 | local nameaddr = readInteger(objaddr + 0x44) 127 | local xpos = readFloat(GetObjData1(objaddr, 0x14)) 128 | local ypos = readFloat(GetObjData1(objaddr, 0x18)) 129 | local zpos = readFloat(GetObjData1(objaddr, 0x1C)) 130 | local xrot = readInteger(GetObjData1(objaddr, 0x08)) 131 | local yrot = readInteger(GetObjData1(objaddr, 0x0C)) 132 | local zrot = readInteger(GetObjData1(objaddr, 0x10)) 133 | local xscl = readFloat(GetObjData1(objaddr, 0x20)) 134 | local yscl = readFloat(GetObjData1(objaddr, 0x24)) 135 | local zscl = readFloat(GetObjData1(objaddr, 0x28)) 136 | SpawnObject(routine, nameaddr, 0x0F, 0x02, false, xpos, ypos, zpos, xrot, yrot, zrot, xscl, yscl, zscl, 0) 137 | end 138 | 139 | function UpdateControllerState() 140 | local controller_last = {} 141 | 142 | for k,v in pairs(controller) do 143 | controller_last[k] = v 144 | end 145 | 146 | controller.buttons = readInteger(0x1A52C4C) or 0 147 | controller.leftX = readInteger(0x1A52C50) or 0 148 | controller.leftY = readInteger(0x1A52C54) or 0 149 | controller.rightX = readInteger(0x1A52C58) or 0 150 | controller.rightY = readInteger(0x1A52C5C) or 0 151 | controller.leftTrigger = readInteger(0x1A52C60) or 0 152 | controller.rightTrigger = readInteger(0x1A52C64) or 0 153 | controller.left = (Bitwise.bw_and(controller.buttons, 1) > 0) 154 | controller.right = (Bitwise.bw_and(controller.buttons, 2) > 0) 155 | controller.down = (Bitwise.bw_and(controller.buttons, 4) > 0) 156 | controller.up = (Bitwise.bw_and(controller.buttons, 8) > 0) 157 | controller.a = (Bitwise.bw_and(controller.buttons, 256) > 0) 158 | controller.b = (Bitwise.bw_and(controller.buttons, 512) > 0) 159 | controller.x = (Bitwise.bw_and(controller.buttons, 1024) > 0) 160 | controller.y = (Bitwise.bw_and(controller.buttons, 2048) > 0) 161 | controller.start = (Bitwise.bw_and(controller.buttons, 4096) > 0) 162 | 163 | controller.edge = {} 164 | for i,v in ipairs({"left", "right", "down", "up", "a", "b", "x", "y", "start"}) do 165 | controller.edge[v] = (controller_last[v] ~= controller[v]) 166 | end 167 | end 168 | 169 | function HandleControllerState() 170 | -- These first two lines enable independent detection of the triggers and the right analog stick. 171 | writeBytes(0x425910, 0x90, 0x90, 0x90) 172 | writeBytes(0x425A10, 0x90, 0x90, 0x90) 173 | SelectionBoxColor = ldcGreen 174 | if OMKActive then OMKCurrentMode = "default" else OMKCurrentMode = "off" end 175 | OMKHelpText = "- LIVE EDIT MODE -" 176 | if OMKActive and IsPlayerValid() then 177 | if readInteger(GetObjData1(objaddr, 0)) ~= nil then 178 | local cam = math.rad(readInteger(0x1DCFF1C) * (360 / 0x10000)) 179 | 180 | --[[local testX = readFloat(GetObjData1(objaddr, 0x14)) 181 | local testY = readFloat(GetObjData1(objaddr, 0x18)) 182 | local testZ = readFloat(GetObjData1(objaddr, 0x1C)) 183 | 184 | local offsetX = 50 185 | local offsetZ = 0 186 | local rotatedX = offsetX*math.cos(-cam) - offsetZ*math.sin(-cam) 187 | local rotatedZ = offsetX*math.sin(-cam) + offsetZ*math.cos(-cam) 188 | DrawLine3D("test1", testX, testY, testZ, testX+rotatedX, testY, testZ+rotatedZ, ldcRed) 189 | offsetX = 0 190 | offsetZ = 50 191 | rotatedX = offsetX*math.cos(-cam) - offsetZ*math.sin(-cam) 192 | rotatedZ = offsetX*math.sin(-cam) + offsetZ*math.cos(-cam) 193 | DrawLine3D("test2", testX, testY, testZ, testX+rotatedX, testY, testZ+rotatedZ, ldcBlue)]] 194 | 195 | if controller.left and not OMKCursorMode then --move mode 196 | OMKCurrentMode = "move" 197 | OMKHelpText = [[- LIVE EDIT MODE - 198 | MOVING SELECTION 199 | Use right analog stick to move horizontally 200 | Use triggers to move vertically]] 201 | OMKAppendObjDescription() 202 | SelectionBoxColor = ldcYellow 203 | writeBytes(0x174AFFE, 0) 204 | local speedMult = 1/64 205 | local x = controller.rightX 206 | local y = (controller.rightTrigger - controller.leftTrigger) / 2 207 | local z = -controller.rightY 208 | local rotated_x = x*math.cos(-cam) - z*math.sin(-cam) 209 | local rotated_z = x*math.sin(-cam) + z*math.cos(-cam) 210 | local objx = readFloat(GetObjData1(objaddr, 0x14)) + speedMult*rotated_x 211 | local objy = readFloat(GetObjData1(objaddr, 0x18)) + speedMult*y 212 | local objz = readFloat(GetObjData1(objaddr, 0x1C)) + speedMult*rotated_z 213 | writeFloat(GetObjData1(objaddr, 0x14), objx) 214 | writeFloat(GetObjData1(objaddr, 0x18), objy) 215 | writeFloat(GetObjData1(objaddr, 0x1C), objz) 216 | elseif controller.up and not OMKCursorMode then --rotate mode 217 | OMKCurrentMode = "rotate" 218 | OMKHelpText = [[- LIVE EDIT MODE - 219 | ROTATING SELECTION 220 | Use right analog stick to rotate around X/Z 221 | Use triggers to rotate around Y 222 | Press Y to set all angles to zero]] 223 | OMKAppendObjDescription() 224 | SelectionBoxColor = ldcMagenta 225 | writeBytes(0x174AFFE, 0) 226 | local speedMult = 16 227 | local x = controller.rightX 228 | local y = (controller.rightTrigger - controller.leftTrigger) / 2 229 | local z = controller.rightY 230 | local objx = readInteger(GetObjData1(objaddr, 0x08)) + speedMult*x 231 | local objy = readInteger(GetObjData1(objaddr, 0x0C)) + speedMult*y 232 | local objz = readInteger(GetObjData1(objaddr, 0x10)) + speedMult*z 233 | objx = Bitwise.bw_and(objx, 0xFFFF) 234 | objy = Bitwise.bw_and(objy, 0xFFFF) 235 | objz = Bitwise.bw_and(objz, 0xFFFF) 236 | writeInteger(GetObjData1(objaddr, 0x08), objx) 237 | writeInteger(GetObjData1(objaddr, 0x0C), objy) 238 | writeInteger(GetObjData1(objaddr, 0x10), objz) 239 | if controller.y then 240 | selObj.rx = 0 241 | selObj.ry = 0 242 | selObj.rz = 0 243 | UpdateObjFromData(selObj) 244 | end 245 | elseif controller.right and not OMKCursorMode then --special mode 246 | local Handler = OMKSpecialModeHandlers[selObj.routine] 247 | if Handler ~= nil then 248 | local helptext = Handler("getHelpText") 249 | OMKCurrentMode = "special" 250 | SelectionBoxColor = ldcRed 251 | writeBytes(0x174AFFE, 0) 252 | OMKHelpText = "- LIVE EDIT MODE -\n"..helptext 253 | OMKAppendObjDescription() 254 | local dX = controller.rightX 255 | local dY = (controller.rightTrigger - controller.leftTrigger) / 2 256 | local dZ = -controller.rightY 257 | local dXr = dX*math.cos(-cam) - dZ*math.sin(-cam) 258 | local dZr = dX*math.sin(-cam) + dZ*math.cos(-cam) 259 | Handler("handleState", dX, dY, dZ, dXr, dZr) 260 | end 261 | end 262 | end 263 | if controller.down and controller.edge.down then --toggle cursor mode 264 | OMKCursorMode = not OMKCursorMode 265 | if OMKCursorMode then 266 | OMKCurrentMode = "cursor" 267 | writeBytes(0x174AFFE, 0) 268 | OMKCursorX = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x14)) 269 | OMKCursorY = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x18)) 270 | OMKCursorZ = readFloat(GetObjData1(readInteger(0x1DEA6E0), 0x1C)) 271 | else 272 | OMKCurrentMode = "default" 273 | end 274 | end 275 | if OMKCursorMode then 276 | OMKHelpText = [[- LIVE EDIT MODE - 277 | CURSOR MODE 278 | Use right analog stick to move cursor horizontally 279 | Use triggers to move cursor vertically 280 | Press X to copy selected object for placement (may not work or crash for some objects) 281 | Press Y to center cursor on selected object 282 | Press LEFT to place object: ]]..control_getCaption(SpawnObjectDlg_ObjectName)..[[ 283 | 284 | Press DOWN again to confirm object selection 285 | 286 | X = ]]..tostring(OMKCursorX)..[[ 287 | 288 | Y = ]]..tostring(OMKCursorY)..[[ 289 | 290 | Z = ]]..tostring(OMKCursorZ) 291 | 292 | OMKAppendObjDescription() 293 | SelectionBoxColor = ldcBlue 294 | local speedMult = 1/64 295 | local x = controller.rightX 296 | local y = (controller.rightTrigger - controller.leftTrigger) / 2 297 | local z = -controller.rightY 298 | local cam = math.rad(readInteger(0x1DCFF1C) * (360 / 0x10000)) 299 | local rotated_x = x*math.cos(-cam) - z*math.sin(-cam) 300 | local rotated_z = x*math.sin(-cam) + z*math.cos(-cam) 301 | OMKCursorX = OMKCursorX + speedMult*rotated_x 302 | OMKCursorY = OMKCursorY + speedMult*y 303 | OMKCursorZ = OMKCursorZ + speedMult*rotated_z 304 | DrawCursor3D("OMKCursor", OMKCursorX, OMKCursorY, OMKCursorZ, 10, ldcCyan) 305 | 306 | local minDistObjAddr = 0 307 | local minDistance = -1 308 | for i,v in ipairs(allObjects[2]) do 309 | if v.px ~= nil then 310 | local dX = v.px - OMKCursorX 311 | local dY = v.py - OMKCursorY 312 | local dZ = v.pz - OMKCursorZ 313 | local distance = math.sqrt(dX*dX + dY*dY + dZ*dZ) 314 | if distance < minDistance or minDistance == -1 then 315 | minDistance = distance 316 | minDistObjAddr = v.address 317 | end 318 | end 319 | end 320 | if minDistObjAddr ~= 0 then objaddr = minDistObjAddr end 321 | 322 | if controller.left and controller.edge.left then 323 | SpawnObjectClick(SpawnObjectDlg_SpawnObject) --simulate button press 324 | end 325 | 326 | if controller.x and controller.edge.x then 327 | SpawnObjectDlg_MainRoutine:setCaption(num2hex(selObj.routine)) 328 | SpawnObjectDlg_Flags:setCaption("F") 329 | SpawnObjectDlg_ListID:setCaption(num2hex(selObj.list)) 330 | SpawnObjectDlg_ObjectName:setCaption(selObj.name or "???") 331 | SpawnObjectDlg_RotX:setCaption(tostring(selObj.rx)) 332 | SpawnObjectDlg_RotY:setCaption(tostring(selObj.ry)) 333 | SpawnObjectDlg_RotZ:setCaption(tostring(selObj.rz)) 334 | SpawnObjectDlg_SclX:setCaption(tostring(selObj.sx)) 335 | SpawnObjectDlg_SclY:setCaption(tostring(selObj.sy)) 336 | SpawnObjectDlg_SclZ:setCaption(tostring(selObj.sz)) 337 | end 338 | 339 | if controller.y and controller.edge.y then 340 | if readInteger(GetObjData1(objaddr, 0)) ~= nil then 341 | OMKCursorX = readFloat(GetObjData1(objaddr, 0x14)) 342 | OMKCursorY = readFloat(GetObjData1(objaddr, 0x18)) 343 | OMKCursorZ = readFloat(GetObjData1(objaddr, 0x1C)) 344 | end 345 | end 346 | else 347 | RemoveCursor("OMKCursor") 348 | end 349 | if not controller.left and not controller.up and not controller.right and not OMKCursorMode then 350 | SelectionBoxColor = ldcGreen 351 | writeBytes(0x174AFFE, 1) 352 | end 353 | if OMKTextContainer ~= nil then object_destroy(OMKTextContainer) end 354 | if OMKTextContainerBack ~= nil then object_destroy(OMKTextContainerBack) end 355 | if OMKD3DHook ~= nil then 356 | OMKTextContainerBack = OMKD3DHook.createTextContainer(OMKFontMapShadow, 17, 17, OMKHelpText) 357 | OMKTextContainer = OMKD3DHook.createTextContainer(OMKFontMap, 16, 16, OMKHelpText) 358 | end 359 | end 360 | end 361 | 362 | function OMKStart() 363 | OMKGetD3DHook() 364 | if OMKD3DHook ~= nil then 365 | local font = createFont() 366 | font.setName("Fixedsys") 367 | font.setSize(8) 368 | font.setColor(0xFFFF00) 369 | OMKFontMap = OMKD3DHook.createFontmap(font) 370 | local font_s = createFont() 371 | font_s.setName("Fixedsys") 372 | font_s.setSize(8) 373 | font_s.setColor(0x000000) 374 | OMKFontMapShadow = OMKD3DHook.createFontmap(font_s) 375 | end 376 | end 377 | 378 | function OMKStop() 379 | object_destroy(OMKTextContainer) 380 | object_destroy(OMKTextContainerBack) 381 | end 382 | 383 | function OMKGetD3DHook() 384 | -- UPDATE: Cheat Engine 6.4 supports reattaching the D3D hook. 385 | -- This function will now check for that and behave accordingly. 386 | 387 | -- Cheat Engine crashes if you call createD3DHook on a process if: 388 | -- 1) createD3DHook has already been called on the same process, and 389 | -- 2) Cheat Engine has been quit since the first time it was called. 390 | -- Unfortunately, this means it's not (yet) possible to save the D3D hook 391 | -- across CE sessions. Luckily, however, Cheat Engine is otherwise much 392 | -- less likely to crash than a hacked SA2, so it can still be useful. 393 | 394 | -- This function will read a previously-saved file to determine the PID 395 | -- of the last process it was called on. If OMKD3DHook is nil and the PID 396 | -- matches, it will proceed without the D3D hook. If OMKD3DHook is not nil 397 | -- and the PID matches, it will simply return the existing D3D hook. If 398 | -- the PID doesn't match, it will create a new hook, regardless of the 399 | -- status of OMKD3DHook. 400 | 401 | -- A non-existent file will be treated as a PID that doesn't match. 402 | 403 | local lastPID 404 | local thisPID = getOpenedProcessID() 405 | if thisPID == 0 then return nil end 406 | local file = io.open("sa2lua/lastPID.txt", "r") 407 | if (file == nil) then 408 | lastPID = nil 409 | else 410 | lastPID = file:read("*n") 411 | file:close() 412 | end 413 | 414 | file = io.open("sa2lua/lastPID.txt", "w+") 415 | file:write(tostring(thisPID)) 416 | file:close() 417 | 418 | if lastPID == thisPID then 419 | if OMKD3DHook == nil then 420 | if getCEVersion() < 6.4 then 421 | return nil 422 | else 423 | OMKD3DHook = createD3DHook() 424 | return OMKD3DHook 425 | end 426 | else 427 | return OMKD3DHook 428 | end 429 | else 430 | OMKD3DHook = createD3DHook() 431 | return OMKD3DHook 432 | end 433 | end 434 | 435 | function OMKDrawObjects() 436 | -- DrawHandler(objdata, defaultColor, prefix) 437 | if OMKActive then 438 | for i,v in ipairs(allObjects[2]) do 439 | if OMKDrawHandlers[v.routine] ~= nil then 440 | local defaultColor 441 | if objaddr == v.address then 442 | defaultColor = SelectionBoxColor 443 | else 444 | defaultColor = ldcCyan 445 | end 446 | OMKDrawHandlers[v.routine](v, defaultColor, "OBJ#"..tonumber(v.address)..":") 447 | end 448 | end 449 | end 450 | end 451 | 452 | function OMKDescribeSelection() 453 | return [[ 454 | Selected Object: ]]..(selObj.name or "[unknown]")..[[ 455 | 456 | Position: ]]..string.format("%4.5f | %4.5f | %4.5f", selObj.px, selObj.py, selObj.pz)..[[ 457 | 458 | Rotation: ]]..string.format("%08X | %08X | %08X", selObj.rx, selObj.ry, selObj.rz)..[[ 459 | 460 | Scale: ]]..string.format("%4.5f | %4.5f | %4.5f", selObj.sx, selObj.sy, selObj.sz) 461 | end 462 | 463 | function OMKAppendObjDescription() 464 | if selObj ~= nil then 465 | if selObj.px ~= nil then 466 | OMKHelpText = OMKHelpText.."\n\n"..OMKDescribeSelection() 467 | end 468 | end 469 | end 470 | 471 | function OMKDrawCube(obj, color, prefix) 472 | LDRotateY = -obj.ry 473 | LDRotateCtrX = obj.px 474 | LDRotateCtrY = obj.py 475 | LDRotateCtrZ = obj.pz 476 | -- rx, ry, and rz, starting here, mean radius, not rotation 477 | local rx = 11 + obj.sx 478 | local ry = 11 + obj.sy 479 | local rz = 11 + obj.sz 480 | local x1 = obj.px - rx 481 | local y1 = obj.py - ry 482 | local z1 = obj.pz - rz 483 | local x2 = obj.px + rx 484 | local y2 = obj.py + ry 485 | local z2 = obj.pz + rz 486 | DrawCube3D(prefix, x1, y1, z1, x2, y2, z2, color, true) 487 | LDResetRotation() 488 | end 489 | 490 | function OMKDrawCylinder(obj, color, prefix) 491 | DrawCylinder3D(prefix, obj.px, obj.py, obj.pz, 11+obj.sx, 11+obj.sy*2, 12, color, true) 492 | end 493 | 494 | function OMKDrawWall(obj, color, prefix) 495 | local temp = obj.sz 496 | obj.sz = 0 497 | OMKDrawCube(obj, color, prefix) 498 | obj.sz = temp 499 | LDRotateY = obj.ry 500 | LDRotateCtrX = obj.px 501 | LDRotateCtrY = obj.py 502 | LDRotateCtrZ = obj.pz 503 | -- Pushes in Z+ direction 504 | DrawLine3D(prefix.."arrow1", obj.px, obj.py, obj.pz, obj.px, obj.py, obj.pz + 30, color, true) 505 | DrawLine3D(prefix.."arrow2", obj.px, obj.py, obj.pz + 30, obj.px, obj.py + 5, obj.pz + 25, color, true) 506 | DrawLine3D(prefix.."arrow3", obj.px, obj.py, obj.pz + 30, obj.px, obj.py - 5, obj.pz + 25, color, true) 507 | LDResetRotation() 508 | end 509 | 510 | function OMKDrawScaleAsDestination(obj, color, prefix) 511 | local markerColor = ldcCyan 512 | if OMKCurrentMode == "special" then markerColor = ldcYellow end 513 | DrawLine3D(prefix.."connector", obj.px, obj.py, obj.pz, obj.sx, obj.sy, obj.sz, color, true) 514 | DrawCursor3D(prefix.."marker", obj.sx, obj.sy, obj.sz, 10, markerColor, true) 515 | end 516 | 517 | function OMKDrawSphereGravSw(obj, color, prefix) 518 | if objaddr == obj.address then --only draw if selected; drawing too many can cause lag in script 519 | local multiplier = 1/4 520 | DrawCircle3D(prefix.."1", obj.px, obj.py, obj.pz, obj.sx * multiplier, 25, color, true) 521 | LDRotateCtrX = obj.px 522 | LDRotateCtrY = obj.py 523 | LDRotateCtrZ = obj.pz 524 | LDRotateZ = 0x4000 525 | DrawCircle3D(prefix.."2", obj.px, obj.py, obj.pz, obj.sx * multiplier, 25, color, true) 526 | LDRotateZ = 0 527 | LDRotateX = 0x4000 528 | DrawCircle3D(prefix.."3", obj.px, obj.py, obj.pz, obj.sx * multiplier, 25, color, true) 529 | LDResetRotation() 530 | end 531 | end 532 | 533 | function OMKDrawSpringArrow(obj, color, prefix) 534 | if objaddr == obj.address or OMKDrawAllSpringArrows then 535 | local y2 = obj.py + 40 * obj.sy + 120 536 | local size = 10 537 | LDRotateCtrX = obj.px 538 | LDRotateCtrY = obj.py 539 | LDRotateCtrZ = obj.pz 540 | LDRotateX = obj.rx 541 | LDRotateY = obj.ry 542 | LDRotateZ = obj.rz 543 | DrawLine3D(prefix.."1", obj.px, obj.py, obj.pz, obj.px, y2, obj.pz, color, true) 544 | DrawLine3D(prefix.."2", obj.px, y2, obj.pz, obj.px - size, y2 - size, obj.pz, color, true) 545 | DrawLine3D(prefix.."3", obj.px, y2, obj.pz, obj.px + size, y2 - size, obj.pz, color, true) 546 | DrawLine3D(prefix.."4", obj.px, y2, obj.pz, obj.px, y2 - size, obj.pz - size, color, true) 547 | DrawLine3D(prefix.."5", obj.px, y2, obj.pz, obj.px, y2 - size, obj.pz + size, color, true) 548 | LDResetRotation() 549 | end 550 | end 551 | 552 | function OMKDrawGravTrigger(obj, color, prefix) 553 | LDRotateCtrX = obj.px 554 | LDRotateCtrY = obj.py 555 | LDRotateCtrZ = obj.pz 556 | LDRotateX = obj.rx 557 | LDRotateY = obj.ry 558 | LDRotateZ = obj.rz 559 | local arrowLength = 32 560 | local arrowHeadSize = 4 561 | local y2 = obj.py - arrowLength + arrowHeadSize 562 | DrawLine3D(prefix.."1", obj.px, obj.py, obj.pz, obj.px, obj.py - arrowLength, obj.pz, color, true) 563 | DrawLine3D(prefix.."2", obj.px, obj.py - arrowLength, obj.pz, obj.px - arrowHeadSize, y2, obj.pz, color, true) 564 | DrawLine3D(prefix.."3", obj.px, obj.py - arrowLength, obj.pz, obj.px + arrowHeadSize, y2, obj.pz, color, true) 565 | DrawLine3D(prefix.."4", obj.px, obj.py - arrowLength, obj.pz, obj.px, y2, obj.pz - arrowHeadSize, color, true) 566 | DrawLine3D(prefix.."5", obj.px, obj.py - arrowLength, obj.pz, obj.px, y2, obj.pz + arrowHeadSize, color, true) 567 | LDResetRotation() 568 | end 569 | 570 | function OMKSMHSetScaleLikePosition(request, dX, dY, dZ, dXr, dZr) 571 | -- Special mode handler that enables setting scale values in the same way as moving the object. 572 | -- Most useful if an object's scale values refer to a location on the map. (like rockets, etc.) 573 | SelectionBoxColor = ldcCyan 574 | if request == "getHelpText" then 575 | return [[ 576 | SETTING DESTINATION COORDINATES 577 | Use right analog stick to move horizontally 578 | Use triggers to move vertically 579 | Press Y to set to object coordinates]] 580 | 581 | elseif request == "handleState" then 582 | local speedMult = 1/64 583 | local x = selObj.sx + dXr * speedMult 584 | local y = selObj.sy + dY * speedMult 585 | local z = selObj.sz + dZr * speedMult 586 | 587 | if controller.y and controller.edge.y then 588 | x = selObj.px 589 | y = selObj.py 590 | z = selObj.pz 591 | end 592 | 593 | selObj.sx = x 594 | selObj.sy = y 595 | selObj.sz = z 596 | UpdateObjFromData(selObj) 597 | else 598 | return nil 599 | end 600 | end 601 | 602 | function OMKSMHSetScaleNormally(request, dX, dY, dZ, dXr, dZr) 603 | if request == "getHelpText" then 604 | return [[ 605 | SETTING SCALE OF SELECTION 606 | Use right analog stick to set X/Z scale 607 | Use triggers to set Y scale]] 608 | 609 | elseif request == "handleState" then 610 | local speedMult = 1/64 611 | selObj.sx = selObj.sx + dX * speedMult 612 | selObj.sy = selObj.sy + dY * speedMult 613 | selObj.sz = selObj.sz + dZ * speedMult 614 | UpdateObjFromData(selObj) 615 | else 616 | return nil 617 | end 618 | end 619 | 620 | function OMKSMHSetSpringStrength(request, dX, dY, dZ, dXr, dZr) 621 | if request == "getHelpText" then 622 | return [[ 623 | SETTING SPRING STRENGTH 624 | Use triggers to set strength]] 625 | 626 | elseif request == "handleState" then 627 | local speedMult = 1/256 628 | selObj.sy = selObj.sy + dY * speedMult 629 | UpdateObjFromData(selObj) 630 | else 631 | return nil 632 | end 633 | end 634 | 635 | OMKDrawHandlers = {} 636 | OMKDrawHandlers[0x6E54E0] = OMKDrawCube --CCUBE 637 | OMKDrawHandlers[0x6E6FC0] = OMKDrawCube --LINKLINK 638 | OMKDrawHandlers[0x6E5470] = OMKDrawCylinder --CCYL 639 | OMKDrawHandlers[0x6E5550] = OMKDrawWall --CWALL 640 | OMKDrawHandlers[0x6D50F0] = OMKDrawScaleAsDestination --ROCKET 641 | OMKDrawHandlers[0x640DB0] = OMKDrawScaleAsDestination --WARP (paintings in Death Chamber, etc.) 642 | OMKDrawHandlers[0x6542F0] = OMKDrawSphereGravSw --GRAV_SW 643 | OMKDrawHandlers[0x5AE140] = OMKDrawCube --SCOL 644 | OMKDrawHandlers[0x6C4480] = OMKDrawSpringArrow --SPRA 645 | OMKDrawHandlers[0x6C4E90] = OMKDrawSpringArrow --SPRB 646 | OMKDrawHandlers[0x6D9310] = OMKDrawSpringArrow --3SPRING 647 | OMKDrawHandlers[0x776730] = OMKDrawGravTrigger --SWDRNGC 648 | 649 | OMKSpecialModeHandlers = {} 650 | OMKSpecialModeHandlers[0x6D50F0] = OMKSMHSetScaleLikePosition --ROCKET 651 | OMKSpecialModeHandlers[0x640DB0] = OMKSMHSetScaleLikePosition --WARP (see above) 652 | OMKSpecialModeHandlers[0x6E54E0] = OMKSMHSetScaleNormally --CCUBE 653 | OMKSpecialModeHandlers[0x6E6FC0] = OMKSMHSetScaleNormally --LINKLINK 654 | OMKSpecialModeHandlers[0x6E5470] = OMKSMHSetScaleNormally --CCYL 655 | OMKSpecialModeHandlers[0x6E5550] = OMKSMHSetScaleNormally --CWALL 656 | OMKSpecialModeHandlers[0x5AE140] = OMKSMHSetScaleNormally --SCOL 657 | OMKSpecialModeHandlers[0x6C4480] = OMKSMHSetSpringStrength --SPRA 658 | OMKSpecialModeHandlers[0x6C4E90] = OMKSMHSetSpringStrength --SPRB 659 | OMKSpecialModeHandlers[0x6D9310] = OMKSMHSetSpringStrength --3SPRING 660 | 661 | OMKSelBoxRadiusOverride = {} 662 | OMKSelBoxRadiusOverride[0x6E54E0] = 3 663 | OMKSelBoxRadiusOverride[0x6E6FC0] = 3 664 | OMKSelBoxRadiusOverride[0x6E5550] = 3 665 | OMKSelBoxRadiusOverride[0x776730] = 3 666 | 667 | OMKActive = false 668 | OMKCursorMode = false 669 | OMKCurrentMode = "default" 670 | OMKCursorX = 0 671 | OMKCursorY = 0 672 | OMKCursorZ = 0 673 | OMKHelpText = "" 674 | OMKDrawAllSpringArrows = true 675 | SelectionBoxColor = 0xFF00FF00 --ldcGreen might not be defined yet 676 | --------------------------------------------------------------------------------