Skip to content

Commit 6b3b9a7

Browse files
committed
Land of Illusion (SMS) Module
1 parent fb69d23 commit 6b3b9a7

2 files changed

Lines changed: 240 additions & 6 deletions

File tree

ScriptHawk.lua

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,10 +388,9 @@ local supportedGames = {
388388
["93BF2FAC1387320AD07251CB4B64FD36BAC1D7A6"] = {moduleName="games.bt", friendlyName="Banjo-Tooie (Europe) (En,Fr,De,Es)", version=2},
389389
["AF1A89E12B638B8D82CC4C085C8E01D4CBA03FB3"] = {moduleName="games.bt", friendlyName="Banjo-Tooie (USA)", version=4},
390390

391-
-- Brother Bear (GBA)
392-
["89E6903500F62E11483402B76C1454AF788646C0"] = {moduleName="games.GBA_brother_bear", friendlyName="Brother Bear (USA)", version=1},
391+
-- Brother Bear (GBA)
392+
["89E6903500F62E11483402B76C1454AF788646C0"] = {moduleName="games.GBA_brother_bear", friendlyName="Brother Bear (USA)", version=1},
393393

394-
395394
-- Conker's Bad Fur Day
396395
["EE7BC6656FD1E1D9FFB3D19ADD759F28B88DF710"] = {moduleName="games.cbfd", friendlyName="Conker's Bad Fur Day (Europe)", version=1},
397396
["4CBADD3C4E0729DEC46AF64AD018050EADA4F47A"] = {moduleName="games.cbfd", friendlyName="Conker's Bad Fur Day (USA)", version=2},
@@ -443,9 +442,9 @@ local supportedGames = {
443442
["B4717E602F07CA9BE0D4822813C658CD8B99F993"] = {moduleName="games.dk64", friendlyName="Donkey Kong 64 (USA) (Demo) (Kiosk)", version=4},
444443
["CF806FF2603640A748FCA5026DED28802F1F4A50"] = {moduleName="games.dk64", friendlyName="Donkey Kong 64 (USA)", version=1},
445444

446-
-- Donkey Kong Country 2 (GBA)
447-
["B0A4D59447C8D7C321BEA4DC7253B0F581129EDE"] = {moduleName="games.GBA_dkc2", friendlyName="Donkey Kong Country 2 (USA)", version=1},
448-
445+
-- Donkey Kong Country 2 (GBA)
446+
["B0A4D59447C8D7C321BEA4DC7253B0F581129EDE"] = {moduleName="games.GBA_dkc2", friendlyName="Donkey Kong Country 2 (USA)", version=1},
447+
449448
-- Drill Dozer
450449
["C1058CC2482B91204100CC8515DA99AEB06773F5"] = {moduleName="games.GBA_DrillDozer", friendlyName="Drill Dozer (USA)", version=1},
451450
["84AFA7108E4D604E7B1A6D105DF5760869A247FA"] = {moduleName="games.GBA_DrillDozer", friendlyName="Screw Breaker Goushin Dorirurero (Japan)", version=2},
@@ -485,6 +484,9 @@ local supportedGames = {
485484
["AF51AB03A173DEC28C9241532227CD64"] = {moduleName="games.impossible_mission", friendlyName="Impossible Mission (E)"},
486485
["A26D40B6B7646C22D1F2DB7F746F0391"] = {moduleName="games.impossible_mission", friendlyName="Impossible Mission (E) (Beta)"},
487486

487+
-- Land of Illusion
488+
["07FAC1D61BC20CF6EB298F66EC2FFE49"] = {moduleName="games.land_of_illusion", friendlyName="Land of Illusion Starring Mickey Mouse (E)"},
489+
488490
-- Lord of the Sword
489491
["6A08D913FD92A213B1ECF5AA7C5630362CCCC6B4"] = {moduleName="games.lots", friendlyName="Lord of the Sword (J)"},
490492
["A5736126ED7E8569A189065EC20ADF72"] = {moduleName="games.lots", friendlyName="Lord of the Sword (J)"},

games/land_of_illusion.lua

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
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+
Memory = {
10+
screen_x_position = 0x70, -- Fixed u16.8 LE
11+
level_width = 0x7C, -- Single byte, measured in tiles
12+
max_health = 0x98,
13+
health = 0x99,
14+
lives = 0x9F,
15+
time_paused = 0xA0,
16+
time_frames = 0xA1, -- u8, maxes at 0x19 and counts down
17+
time_seconds = 0xA2, -- BCD
18+
time_hundred_seconds = 0xA3, -- BCD - Anything with 0xA-F in the upper digit is instakill, weird
19+
grabbed_object_pointer = 0x11A, -- 2 byte pointer onto system bus
20+
x_position_level = 0x214, -- Fixed u16.8 LE
21+
x_position = 0x20C, -- Fixed u8.8 LE
22+
y_position = 0x20A, -- Fixed u8.8 LE
23+
x_velocity = 0x210, -- Fixed s8.8 LE
24+
y_velocity = 0x20E, -- Fixed s8.8 LE
25+
level_index = 0x9FF, -- Single byte
26+
--[[
27+
Tornados RNG (Level 2) 0x04BA
28+
Boss Health 0x041F
29+
Boss Cycle and RNG 0x041A
30+
--]]
31+
},
32+
};
33+
34+
local enemy_array = 0x200;
35+
local enemy_array_capacity = 32;
36+
local enemy_size = 0x20;
37+
local enemy = {
38+
x_screen = 0x0C,
39+
y_screen = 0x12, -- Single byte?
40+
x = 0x14,
41+
y = 0x0A,
42+
};
43+
44+
function Game.read_u16_8(base)
45+
local major = mainmemory.read_u16_le(base + 1);
46+
local sub = mainmemory.readbyte(base) / 256;
47+
return major + sub;
48+
end
49+
50+
function Game.read_s16_8(base)
51+
local major = mainmemory.read_s16_le(base + 1);
52+
local sub = mainmemory.readbyte(base) / 256;
53+
return major + sub;
54+
end
55+
56+
function Game.read_hitbox_y(base)
57+
local major = mainmemory.read_s8(base + enemy.y_screen) * 256;
58+
local minor = mainmemory.read_u16_le(base + enemy.y) / 256;
59+
return major + minor;
60+
end
61+
62+
function Game.write_hitbox_y(base, value)
63+
local major = math.floor(value / 256);
64+
local minor = (value * 256) % 0xFFFF;
65+
mainmemory.write_s8(base + enemy.y_screen, major);
66+
mainmemory.write_u16_le(base + enemy.y, minor);
67+
end
68+
69+
function Game.write_u16_8(base, value)
70+
local major = math.floor(value);
71+
local sub = value - major;
72+
mainmemory.writebyte(base, sub * 256);
73+
mainmemory.write_u16_le(base + 1, major);
74+
end
75+
76+
function Game.detectVersion(romName, romHash)
77+
ScriptHawk.dpad.joypad.enabled = false;
78+
ScriptHawk.dpad.key.enabled = false;
79+
ScriptHawk.hitboxDefaultMode = ScriptHawk.hitboxModeWHCentered;
80+
return true;
81+
end
82+
83+
function Game.getXPosition()
84+
return Game.read_u16_8(Game.Memory.x_position_level);
85+
end
86+
87+
function Game.getYPosition()
88+
return Game.read_hitbox_y(0x200);
89+
end
90+
91+
function Game.getScreenXPosition()
92+
return Game.read_u16_8(Game.Memory.screen_x_position);
93+
end
94+
95+
function Game.getXVelocity()
96+
return mainmemory.read_s16_le(Game.Memory.x_velocity) / 256;
97+
end
98+
99+
function Game.getYVelocity()
100+
return mainmemory.read_s16_le(Game.Memory.y_velocity) / 256;
101+
end
102+
103+
function Game.blueWhenInfinites()
104+
if ScriptHawk.UI.ischecked("Toggle Infinites Checkbox") then
105+
return colors.blue;
106+
end
107+
end
108+
109+
function Game.applyInfinites()
110+
-- Set lives to max
111+
mainmemory.writebyte(Game.Memory.lives, 0x10);
112+
113+
-- Set health to max
114+
mainmemory.writebyte(Game.Memory.health, mainmemory.readbyte(Game.Memory.max_health));
115+
116+
-- Set time to max
117+
mainmemory.writebyte(Game.Memory.time_seconds, 0x00);
118+
mainmemory.writebyte(Game.Memory.time_hundred_seconds, 0x10);
119+
end
120+
121+
function Game.getIGT()
122+
local frames = mainmemory.readbyte(Game.Memory.time_frames);
123+
local seconds = toHexString(mainmemory.readbyte(Game.Memory.time_seconds), 2, "");
124+
local hundredSeconds = toHexString(mainmemory.readbyte(Game.Memory.time_hundred_seconds), 2, "");
125+
return hundredSeconds..seconds.."."..frames;
126+
end
127+
128+
function Game.getHealth()
129+
return mainmemory.readbyte(Game.Memory.health);
130+
end
131+
132+
function Game.getMaxHealth()
133+
return mainmemory.readbyte(Game.Memory.max_health);
134+
end
135+
136+
function Game.getHealthOSD()
137+
return Game.getHealth().."/"..Game.getMaxHealth();
138+
end
139+
140+
function Game.getBossHealth()
141+
return 0; -- TODO
142+
end
143+
144+
function Game.getHitboxes()
145+
local hitboxes = {};
146+
147+
local screenX = Game.getScreenXPosition();
148+
ScriptHawk.hitboxDefaultXOffset = -screenX;
149+
150+
for base = enemy_array, enemy_array + enemy_array_capacity * enemy_size, enemy_size do
151+
local enemyType = mainmemory.readbyte(base);
152+
if enemyType ~= 0 then
153+
local hitbox = {
154+
base = base,
155+
dragTag = base,
156+
enemyType = enemyType,
157+
x = Game.read_u16_8(base + enemy.x),
158+
y = Game.read_hitbox_y(base),
159+
width = 16,
160+
height = 16,
161+
};
162+
table.insert(hitboxes, hitbox);
163+
end
164+
end
165+
return hitboxes;
166+
end
167+
168+
function Game.getHitboxListText(hitbox)
169+
return round(hitbox.x)..", "..round(hitbox.y).." - "..toHexString(hitbox.base);
170+
end
171+
172+
function Game.getHitboxStaticText(hitbox)
173+
return toHexString(hitbox.base);
174+
end
175+
176+
function Game.setHitboxPosition(hitbox, x, y)
177+
Game.write_u16_8(hitbox.base + enemy.x, x);
178+
Game.write_hitbox_y(hitbox.base, y);
179+
end
180+
181+
function Game.getGrabbedObject()
182+
return mainmemory.read_u16_le(Game.Memory.grabbed_object_pointer);
183+
end
184+
185+
-- Map Data
186+
local tilemap_start = 0x1600;
187+
local screen_height = 0x0A; -- tiles
188+
local tile_size = 16;
189+
190+
function Game.drawMap()
191+
local screenXPos = Game.getScreenXPosition();
192+
local startX = math.floor(screenXPos / tile_size);
193+
local endX = startX + 16;
194+
local levelWidth = mainmemory.readbyte(Game.Memory.level_width);
195+
local xOffset = ScriptHawk.overscan_compensation.x + (tile_size - screenXPos % tile_size) - tile_size;
196+
local yOffset = ScriptHawk.overscan_compensation.y;
197+
for x = startX, endX do
198+
for y = 0x00, screen_height - 1 do
199+
local tile = tilemap_start + y * levelWidth + x;
200+
local tileValue = mainmemory.readbyte(tile);
201+
ScriptHawk.drawText((x - startX) * tile_size + xOffset, y * tile_size + yOffset, toHexString(tileValue, 2, ""), nil, 0, true);
202+
end
203+
end
204+
--print_deferred();
205+
end
206+
207+
function Game.drawUI()
208+
if (ScriptHawk.UI.isChecked("Draw Map Checkbox")) then
209+
Game.drawMap();
210+
end
211+
end
212+
213+
function Game.initUI()
214+
ScriptHawk.UI.checkbox(10, 4, "Draw Map Checkbox", "Draw Map");
215+
end
216+
217+
Game.OSD = {
218+
{"IGT", Game.getIGT, Game.blueWhenInfinites},
219+
{"Health", Game.getHealthOSD, Game.blueWhenInfinites},
220+
{"Separator"},
221+
{"X"},
222+
{"Y"},
223+
{"dX"},
224+
{"dY"},
225+
{"X Velocity", Game.getXVelocity},
226+
{"Y Velocity", Game.getYVelocity},
227+
{"Separator"},
228+
{"Screen X", Game.getScreenXPosition},
229+
{"Grabbed", hexifyOSD(Game.getGrabbedObject)},
230+
};
231+
232+
return Game;

0 commit comments

Comments
 (0)