1+ if type (ScriptHawk ) ~= " table" then
2+ print (" This script is not designed to run by itself" );
3+ print (" Please run ScriptHawk.lua from the parent directory instead" );
4+ print (" Thanks for using ScriptHawk :)" );
5+ return ;
6+ end
7+
8+ local Game = {
9+ max_rot_units = 4096 ,
10+ rot_speed = 16 ,
11+ speedy_index = 7 ,
12+ speedy_speeds = {
13+ 0.001 , 0.01 , 0.1 , 1 , 5 , 10 , 20 , 50 , 100
14+ },
15+ squish_memory_table = true ,
16+ Memory = { -- Version order: USA, Europe
17+ -- global_timer = {0x4E0D8, 0x4EA2C},
18+ global_timer = {0x5B690 , 0x5D274 },
19+ warp_room_2_unlocked = {0x5A780 , 0x5C564 },
20+ warp_room_3_unlocked = {0x5A792 , 0x5C576 },
21+ warp_room_4_unlocked = {0x5A785 , 0x5C569 },
22+ warp_room_5_unlocked = {0x5A79B , 0x5C57F },
23+ p1_x_position_warp_room = {0x9EEA0 , nil }, -- Fixed point
24+ p1_z_position_warp_room = {0x9EEA4 , nil }, -- Fixed point
25+ -- PLAYER 1
26+ p1_pointer = {0x9D530 , 0x9BA6C }, -- Game.minigamePlayer
27+ p1_health = {0x9D562 , 0x9BA9E },
28+ p1_tank_health = {0xCAD50 , 0xC9638 },
29+ p1_mines = {0xCAD78 , 0xC9660 },
30+ -- PLAYER 2
31+ p2_pointer = {0x9D59C , 0x9BAD8 }, -- Game.minigamePlayer
32+ p2_health = {0x9D5CE , 0x9BB0A },
33+ p2_tank_health = {0xCADF4 , 0xC96DC },
34+ p2_mines = {0xCAE1C , 0xC9704 },
35+ -- PLAYER 3
36+ p3_pointer = {0x9D608 , 0x9BB44 }, -- Game.minigamePlayer
37+ p3_health = {0x9D63A , 0x9BB76 },
38+ p3_tank_health = {0xCAE98 , 0xC9780 },
39+ p3_mines = {0xCAEC0 , 0xC97A8 },
40+ -- PLAYER 4
41+ p4_pointer = {0x9D674 , 0x9BBB0 }, -- Game.minigamePlayer
42+ p4_health = {0x9D6A6 , 0x9BBE2 },
43+ p4_tank_health = {0xCAF3C , 0xC9824 },
44+ p4_mines = {0xCAF64 , 0xC984C },
45+ },
46+ minigamePlayer = {
47+ x_pos = 0x10 , -- Signed fixed point 16.16 little endian
48+ y_pos = 0x14 , -- Signed fixed point 16.16 little endian
49+ z_pos = 0x18 , -- Signed fixed point 16.16 little endian
50+ -- TODO: Rotation
51+ -- TODO: Velocity
52+ },
53+ };
54+
55+ local global_timer = {
56+ current = 0 ,
57+ previous = 0 ,
58+ };
59+
60+ function mainmemory .read_s1616_le (address ) -- Signed fixed point 16.16 little endian
61+ return mainmemory .read_s32_le (address ) / 0x10000 ;
62+ end
63+
64+ function mainmemory .write_s1616_le (address , value ) -- Signed fixed point 16.16 little endian
65+ return mainmemory .write_u32_le (address , value * 0x10000 );
66+ end
67+
68+ function mainmemory .read_s2012_le (address ) -- Signed fixed point 20.12 little endian
69+ return mainmemory .read_s32_le (address ) / 0x1000 ;
70+ end
71+
72+ function mainmemory .write_s2012_le (address , value ) -- Signed fixed point 20.12 little endian
73+ return mainmemory .write_u32_le (address , value * 0x1000 );
74+ end
75+
76+ function mainmemory .read_s248_le (address ) -- Signed fixed point 24.8 little endian
77+ return mainmemory .read_s32_le (address ) / 0x100 ;
78+ end
79+
80+ function mainmemory .write_s248_le (address , value ) -- Signed fixed point 24.8 little endian
81+ return mainmemory .write_u32_le (address , value * 0x100 );
82+ end
83+
84+ function Game .unlockWarpRooms ()
85+ mainmemory .writebyte (Game .Memory .warp_room_2_unlocked , 1 );
86+ mainmemory .writebyte (Game .Memory .warp_room_3_unlocked , 1 );
87+ mainmemory .writebyte (Game .Memory .warp_room_4_unlocked , 1 );
88+ mainmemory .writebyte (Game .Memory .warp_room_5_unlocked , 1 );
89+ end
90+
91+ function Game .applyInfinites ()
92+ local max_health = 0x14 ;
93+ local max_tank_health = 0x63 ;
94+ local max_mines = 0x03 ;
95+
96+ mainmemory .writebyte (Game .Memory .p1_health , max_health );
97+ mainmemory .writebyte (Game .Memory .p1_tank_health , max_tank_health );
98+ mainmemory .writebyte (Game .Memory .p1_mines , max_mines );
99+
100+ --[[
101+ mainmemory.writebyte(Game.Memory.p2_health, max_health);
102+ mainmemory.writebyte(Game.Memory.p2_tank_health, max_tank_health);
103+ mainmemory.writebyte(Game.Memory.p2_mines, max_mines);
104+
105+ mainmemory.writebyte(Game.Memory.p3_health, max_health);
106+ mainmemory.writebyte(Game.Memory.p3_tank_health, max_tank_health);
107+ mainmemory.writebyte(Game.Memory.p3_mines, max_mines);
108+
109+ mainmemory.writebyte(Game.Memory.p4_health, max_health);
110+ mainmemory.writebyte(Game.Memory.p4_tank_health, max_tank_health);
111+ mainmemory.writebyte(Game.Memory.p4_mines, max_mines);
112+ --]]
113+ end
114+
115+ function Game .getMinigamePlayer (playerIndex )
116+ playerIndex = playerIndex or 0 ;
117+ return dereferencePointer (Game .Memory .p1_pointer + playerIndex * 0x6C );
118+ end
119+
120+ function Game .getXPosition (playerIndex )
121+ local minigamePlayer = Game .getMinigamePlayer (playerIndex );
122+ if isRAM (minigamePlayer ) then
123+ return mainmemory .read_s248_le (minigamePlayer + Game .minigamePlayer .x_pos );
124+ end
125+ return 0 ;
126+ end
127+
128+ function Game .getYPosition (playerIndex )
129+ local minigamePlayer = Game .getMinigamePlayer (playerIndex );
130+ if isRAM (minigamePlayer ) then
131+ return mainmemory .read_s248_le (minigamePlayer + Game .minigamePlayer .y_pos );
132+ end
133+ return 0 ;
134+ end
135+
136+ function Game .getZPosition (playerIndex )
137+ local minigamePlayer = Game .getMinigamePlayer (playerIndex );
138+ if isRAM (minigamePlayer ) then
139+ return mainmemory .read_s248_le (minigamePlayer + Game .minigamePlayer .z_pos );
140+ end
141+ return 0 ;
142+ end
143+
144+ function Game .setXPosition (value , playerIndex )
145+ local minigamePlayer = Game .getMinigamePlayer (playerIndex );
146+ if isRAM (minigamePlayer ) then
147+ mainmemory .write_s248_le (minigamePlayer + Game .minigamePlayer .x_pos , value );
148+ end
149+ end
150+
151+ function Game .setYPosition (value , playerIndex )
152+ local minigamePlayer = Game .getMinigamePlayer (playerIndex );
153+ if isRAM (minigamePlayer ) then
154+ mainmemory .write_s248_le (minigamePlayer + Game .minigamePlayer .y_pos , value );
155+ end
156+ end
157+
158+ function Game .setZPosition (value , playerIndex )
159+ local minigamePlayer = Game .getMinigamePlayer (playerIndex );
160+ if isRAM (minigamePlayer ) then
161+ mainmemory .write_s248_le (minigamePlayer + Game .minigamePlayer .z_pos , value );
162+ end
163+ end
164+
165+ function Game .detectVersion (romName , romHash )
166+ ScriptHawk .dpad .joypad .enabled = false ;
167+ ScriptHawk .dpad .key .enabled = false ;
168+ return true ;
169+ end
170+
171+ function Game .initUI ()
172+ ScriptHawk .UI .button (0 , 6 , {4 , 10 }, nil , nil , " Unlock Rooms" , Game .unlockWarpRooms );
173+ end
174+
175+ function Game .eachFrame ()
176+ global_timer .previous = global_timer .current ;
177+ global_timer .current = mainmemory .read_u32_le (Game .Memory .global_timer );
178+ end
179+
180+ function Game .isPhysicsFrame ()
181+ return global_timer .current ~= global_timer .previous ;
182+ end
183+
184+ Game .OSD = {
185+ {" P1" , hexifyOSD (function () return Game .getMinigamePlayer (0 ) end )},
186+ {" P1 X" , function () return Game .getXPosition (0 ) end },
187+ {" P1 Y" , function () return Game .getYPosition (0 ) end },
188+ {" P1 Z" , function () return Game .getZPosition (0 ) end },
189+ {" Separator" },
190+ {" dY" },
191+ {" dXZ" },
192+ {" Separator" },
193+ {" P2" , hexifyOSD (function () return Game .getMinigamePlayer (1 ) end )},
194+ {" P2 X" , function () return Game .getXPosition (1 ) end },
195+ {" P2 Y" , function () return Game .getYPosition (1 ) end },
196+ {" P2 Z" , function () return Game .getZPosition (1 ) end },
197+ {" Separator" },
198+ {" P3" , hexifyOSD (function () return Game .getMinigamePlayer (2 ) end )},
199+ {" P3 X" , function () return Game .getXPosition (2 ) end },
200+ {" P3 Y" , function () return Game .getYPosition (2 ) end },
201+ {" P3 Z" , function () return Game .getZPosition (2 ) end },
202+ {" Separator" },
203+ {" P4" , hexifyOSD (function () return Game .getMinigamePlayer (3 ) end )},
204+ {" P4 X" , function () return Game .getXPosition (3 ) end },
205+ {" P4 Y" , function () return Game .getYPosition (3 ) end },
206+ {" P4 Z" , function () return Game .getZPosition (3 ) end },
207+ };
208+
209+ return Game ;
0 commit comments