# Forum BizHawk Adventures in Lua (BizHawk, DeSmuME, and others)

Post subject: Adventures in Lua (BizHawk, DeSmuME, and others)
###### Pokota
He/Him
E: Originally, this thread was BizHawk centric, but has since branched out to other emulators. NOTE: This thread isn't just for me to get help, but for everyone to show off and ask help for their BizHawk Lua scripts. ---- So because BizHawk has its own interpretation implementation of Lua, I figured I could write some Lua Scripts to use when I'm playing around. Then I realized that I've never actually scripted in Lua before. After a few quick lessons and some bugsquashing by the good people in IRC, I've managed to put together my first ever Lua HUD script.
```Language: lua```-- "Super Mario Bros. 2"
local cherryCount
local foeLifeA
local foeLifeB
local squatTimer
UI_GREEN = 0x00FF00;
UI_RED = 0xFF0000;
while (true) do

if (foeLifeA == 255) then
foeLifeA = -1;
end

if (foeLifeB == 255) then
foeLifeB = -1;
end

foeLifeA = foeLifeA + 1;
foeLifeB = foeLifeB + 1;

gui.drawRectangle(40,20,(foeLifeA*5),5);
gui.drawRectangle(40,25,(foeLifeB*5),5);

gui.drawRectangle(40,10,60,5);
gui.drawRectangle(40,10,squatTimer,5);

for i = 0, cherryCount, 1 do
gui.drawIcon("cherry.ico",0,(i*16)-8,16,16);
end

end
``````
Which yields this amended HUD: What I'm planning on doing next is fixing the Cherry Meter to show how many cherries have been collected instead of simply moving the cherry around, then converting the enemy health meters from bars to hearts, then coloring the squat meter.
###### Pokota
He/Him
So now this is a thing.
```Language: lua```-- "Zelda II: The Adventure of Link"

local bagCounter
local currentMP
local currentHP
local maxMP
local maxHP
local hearts
local jars
local armor
local intel
local skill
local xp
local toLevelTemp
local toLevel
local percentToLevel
local keys
local selector

while true do

percentToLevel = xp / toLevelTemp;
toLevel = percentToLevel*100;

maxMP = (jars*32)-1;
maxHP = (hearts*32)-1;

gui.drawBox(0,0,255,41,"White","Black");

gui.drawText(0,8,armor.."|HP: "..currentHP.."/"..maxHP,"Red",11);
gui.drawText(0,18,intel.."|MP: "..currentMP.."/"..maxMP,"White",11);
gui.drawText(0,28,skill.."|"..bagCounter.." enemies since last drop","Yellow",11);

gui.drawText(95,8," Keys: "..keys,"Aqua",11);
gui.drawText(95,18,"Spell: "..selector,"White",11);

gui.drawRectangle(235,8,20,(32*percentToLevel),"Green","Green");

gui.drawBox(235,8,255,40,"White");

end``````
I need to flip the direction of the experience bar, but other than that this is about where I like it. And now that I know how to handle color (passing a name string instead of any sort of number? Sure, let's go with that), I can make forward progress on the SMB2 one. A little bit of reinventing the wheel here, but it's FUN ^^ EDIT: Thanks to Scepheo, I now know that colors are passed in through four bytes instead of three. 0xFF00FF00 is Green - this declares 255 Alpha, 0 Red, 255 Green, and 0 Blue. Now to use this as intended...
###### feos
```Language: lua```function stuff()
x = memory.reawword(0x100)
gui.text(10,10,string.format("Xpos: %d",x))
end

gui.register(stuff) -- obsoletes the "while true do emu.frameadvance() end" loop
``````
[code=sample.lua] function stuff() x = memory.reawword(0x100) gui.text(10,10,string.format("%d",x)) end gui.register(stuff) -- obsoletes the "while true do emu.frameadvance() end" loop [/code] However when using scripts with < and >, make sure to "Disable HTML in this post". I'm also pretty sure using "local" for globally declared variables is unnecessary. As is declaring them without instantly using, as is ";".
###### zeromus
Editor, Emulator Coder
It's good practice to type local everywhere in lua, in fact there's strict.lua to enforce it. Even at the global level it still makes sense, because it isn't actually global but instead 'script-level' and a local declared there wouldn't be accessible to other scripts, and would run faster than a true global. That's what I remember, anyway.
###### Pokota
He/Him
C# habits are hard to break. With that said, I'll update the scripts to account for gui.register today, and I'll modify the posts above for syntax highlighting. Link to video Link to video
###### feos
Brackets around conditions (unless they're complicated) also aren't required.
###### Pokota
He/Him
It broke once and putting the condition in brackets fixed it, so I'm going with what I know. Besides, I'm using Notepad++ as my editor, which lets me spot missing brackets quickly. Most of what I end up screwing up is stray characters like out of place commas and punkts. EDIT: The sample you posted yields this error:
``LuaInterface.LuaScriptException: E:\Games\Emulation\Lua\sample.lua:7: attempt to call field 'register' (a nil value)``
###### Amaraticando
It/Its
Editor, Player (159)
This error signals that there's no field register in the table gui. This is a function in Snes9x API. Instead of gui.register, try event.onframeend(stuff). More events are listed here http://tasvideos.org/Bizhawk/LuaFunctions.html
###### Pokota
He/Him
Taking that information, I was able to clean up the Zelda II script quite quickly. When I try to apply the same idea to the SMB2 script, it breaks citing unable to find cherry.png - which is in the same folder that I'm running the script out of. (Code block below actually does work, it's when I convert from this to on frame end that it breaks)
```Language: lua```-- "Super Mario Bros. 2"
local cherryCount
local foeLifeA
local foeLifeB
local foeLifeC
local foeLifeD
local foeLifeE
local squatTimer
local carpetTimer
local starTimer
local dreamTimer
local bigVegCount
local stopTimer
local starPercent
local carpetPercent
local dreamPercent
local stopPercent

TIMER = 100;

while (true) do

carpetPercent = carpetTimer / 160;
dreamPercent = dreamTimer / 96;
starPercent = starTimer / 62;
stopPercent = stopTimer / 255;

gui.drawRectangle(100,8,squatTimer,4,"Cyan","Cyan");
gui.drawRectangle(100,8,60,4,"RED");

gui.drawRectangle(100,15,TIMER*carpetPercent,5,"Red","Red");
gui.drawRectangle(100,15,TIMER*dreamPercent,5,"CYAN","CYAN");
gui.drawRectangle(100,15,TIMER*starPercent,5,"MAGENTA","MAGENTA");
gui.drawRectangle(100,15,TIMER*stopPercent,5,"Yellow","Yellow");

gui.drawRectangle(100,15,TIMER,5,"White");

for i = 0, cherryCount, 1 do
gui.drawImage("cherry.png",(i*8)-8,16);
end

for j = 0, bigVegCount, 1 do
gui.drawImage("veg.png",(j*8)-8,8);
end

for k = 0, foeLifeA, 1 do
gui.drawImage("heart.png",(k*8)-8,144);
end

for l = 0, foeLifeB, 1 do
gui.drawImage("heart.png",(l*8)-8,160);
end

for m = 0, foeLifeC, 1 do
gui.drawImage("heart.png",(m*8)-8,176);
end

for n = 0, foeLifeD, 1 do
gui.drawImage("heart.png",(n*8)-8,184);
end

for o = 0, foeLifeE, 1 do
gui.drawImage("heart.png",(o*8)-8,192);
end

end
``````
Lua HUD Package for SMB2, v2
###### Amaraticando
It/Its
Editor, Player (159)
I write a script for lsnes and try to adapt it to run in BizHawk. To facilitate things, I use:
```Language: lua```-- Compatibility

-- Example
local RNG = u8(WRAM.RNG)
``````
So, in the other emulator, I just do the same thing with the proper functions. Another good side of this is that I don't have to memorize a big name like "mainmemory.read_s16_le".
###### mz
Emulator Coder, Player (79)
I wrote this unnecessarily long and messy script for Tails Adventure to create maps, view hitboxes, take screenshots, and other stuff: http://pastebin.com/XZfwkwDe I used it mainly just to take a screenshot for each frame and write the X and Y coordinates of the game camera, so I could make some videos: https://www.youtube.com/watch?v=FOmlQk8X0UQ I also liked how the maps looked after Tails had gone all over them: (Sorry for the long image, I can change it to a link if anyone finds it annoying.)
###### Scepheo
Player (145)
Pokota: as you probably know from C#, it's always a good idea to look for repeating structures in your script, and convert them to simpler code. For example, all of the "foeLife" related code can be made a lot simpler and cleaner:
```Language: lua```for i = 0, 5 do
local hp = memory.read_s8(0x0465 + i)
local y = 144 + 16 * i

for j = 0, hp do
gui.drawImage("heart.png", j * 8 - 8, y)
end
end``````
###### feos
There's also a way to display some huge string of numbers, breaking it into lines where it fits the best. Bonus points for displaying slot numbers over object sprites.
```Language: lua```-- SolarJetman objects
function DrawTable()
for Slot = 0, 0x1f do
local ID = memory.readbyte(0x317 + Slot)
local X  = memory.readwordsigned(0x200 + Slot, 0x21f + Slot) - Xcam
local Y  = memory.readwordsigned(0x25d + Slot, 0x27c + Slot) - Ycam
local CellWidth   = 32
local CellHeight  = 8
local ScreenWidth = 256
local RowLength   = 8
local OffsetX     = 1
local OffsetY     = 9
local Color       = "white"
if ID == 0 then Color = "red" end
gui.text(
Slot * CellWidth % ScreenWidth + OffsetX,	-- text X
math.floor(Slot / RowLength) * CellHeight + OffsetY,	-- text Y
string.format("%2d:%02X", Slot, ID),	-- output string
Color	-- you guess
)
gui.text(X, Y, Slot)
end
end``````
###### ventuz
He/Him
Player (125)
Is there way to get rom crc32 hash? current lua in BizHawk seem to only return SHA-1 hash.
###### zeromus
Editor, Emulator Coder
write which platform you want it for, since the code to do the hashes differs by platform, and consider it a feature request.
###### Pokota
He/Him
I've been experimenting with a partial hud replacement for the Zelda Oracles games - nothing fancy, just a replaced health meter and an added Maple meter. I've just run into the issue that Seasons stores the bytes I need in a different location from Ages, so either I make two flavors or I actually study case/switch flow control. The reason Gasha Tree progress isn't included? Each tree has its own byte.
Can't you just check the title at ROM offset 0x134 for that? Oracle of Ages is "ZELDA NAYRU" and Oracle of Seasons is "ZELDA DIN"
###### Pokota
He/Him
@Sappharad: The actual offsets for the ram values I need to pull for the Maple Meter and health meter are in different places between the two games. Probably because of the difference in titles, now that I think about it. And it's more "I haven't played with the case/switch flow control yet" than anything else.
###### Scepheo
Player (145)
Pseudocode below:
```Language: Lua```checkCharacter = read_from_rom(0x140);

if (checkCharacter == "N") then
offset = someValue;
else
offset = someOtherValue;
end

Obviously these aren't the correct function names and you'd have to check against the numeric value for 'D' (ZELDA DIN) vs. 'N' (ZELDA NAYRU), but walking through a switch/case every time instead of just setting the offsets correct at the beginning is a needless performance hit.
Sorry, I read the posts linearly without paying attention to the poster names. So I thought the answer to the "Why do you need crc32?" question was for telling the two oracle games apart, and provided an answer for how to tell the two games apart. After looking up again, I see those were two different conversations. But hopefully my suggestion is at least somewhat useful.
Post subject: Metroid II - Return of Samus - HUD: Metroid Queen HP
###### CrazyTerabyte
He/Him
This small code shows the HP of the last boss in Metroid II game for GameBoy. This code most likely won't work inside Super GameBoy, though. Having this health bar gives useful feedback to the player. For me (my first playthrough of this game), the last fight was frustrating and near-impossible. After seeing the boss health bar, and seeing it going down, the fight became a lot more fun! It also gave me clear feedback on which attacks work, and how to defeat the boss faster.
```Language: lua```while true do

MAX = 150;

if HP > 0 and HP <= MAX then
-- Color is 0xAARRGGBB.
gui.drawRectangle(0,144-16, HP,8, 0, 0xFFFF0000);
gui.drawRectangle(0,144-16, MAX,7, 0xFFFFFFFF, 0);
end;

end``````
###### Pokota
He/Him
I'll poke around in ram and see if I can't adapt that to work for all metroids and not just the queen. I know Zetas will be a lot less stressful with visual progress being made.
###### CrazyTerabyte
He/Him
@Pokota: for the first Metroid game (the NES one), there is already a fairly comprehensive RAM map. However, there is none for Metroid II (GB). Maybe you could write down your findings in that wiki? http://datacrystal.romhacking.net/wiki/Metroid:RAM_map http://datacrystal.romhacking.net/wiki/Metroid_II:_Return_of_Samus
###### CrazyTerabyte
He/Him
For Disney's Aladdin (U) [!] (SEGA Mega Drive/Genesis), I've written the following script. It allows hiding the HUD, and can also move sprites in front of the other layers (now we can see hidden items).
```Language: lua```-- Sprite Table for Disney's Aladdin
SPRITE_TABLE = 0xF400
-- Information about sprite table layout: http://md.squee.co/wiki/VDP#Sprites

function get_sprite_pattern(index)
local data

memory.usememorydomain("VRAM")
data = memory.read_u16_be(SPRITE_TABLE + 8*index + 2*2)
return bit.band(data, 0x7FF)
end

function set_sprite_x(index, pos)
memory.usememorydomain("VRAM")
pos = bit.band(pos, 0x1FF)
memory.write_u16_be(SPRITE_TABLE + 8*index + 3*2, pos)
end

function set_sprite_priority(index, priority)
local data
memory.usememorydomain("VRAM")
data = memory.read_u16_be(SPRITE_TABLE + 8*index + 2*2)
if priority == 1 then
data = bit.bor(data, 0x8000)
elseif priority == 0 then
data = bit.band(data, 0x7FFF)
end
memory.write_u16_be(SPRITE_TABLE + 8*index + 2*2, data)
end

CHECK_HUD = forms.checkbox(FORM, "Hide HUD", 0, 0)
CHECK_TOP = forms.checkbox(FORM, "Sprites on-top", 0, 24)

while true do

for i = 0, 128, 1 do
local pat = get_sprite_pattern(i)
if
(pat >= 0x680 and pat <= 0x6FF)  -- Health, Lives, Apples, Gems
or (pat >= 0x7C0 and pat <= 0x7E4)  -- Score
then
if forms.ischecked(CHECK_HUD) then
-- 32 is to the left, outside the screen
set_sprite_x(i, 32)
end
else
if forms.ischecked(CHECK_TOP) then
-- Set all other sprites above the layers
set_sprite_priority(i, 1)
end
end
end

end
``````
I've also built this RAM Watch map:
``````Domain 68K RAM
SystemID GEN
7E29	b	h	1	68K RAM	Score - 0x30~0x39
7E2A	b	h	1	68K RAM	Score - 0x30~0x39
7E2B	b	h	1	68K RAM	Score - 0x30~0x39 - thousands
7E2C	b	h	1	68K RAM	Score - 0x30~0x39 - hundreds
7E2D	b	h	1	68K RAM	Score - 0x30~0x39 - tens
7E2E	b	h	1	68K RAM	Score - 0x30~0x39 - units
7E3C	b	h	1	68K RAM	Lives - 0x30~0x39 - units
7E3F	b	h	1	68K RAM	Continues - 0~unlimited
EFE0	b	h	1	68K RAM	Apples - 0x30~0x39 - tens
EFE1	b	h	1	68K RAM	Apples - 0x30~0x39 - units
EFE2	b	h	1	68K RAM	Gems - 0x30~0x39 - tens
EFE3	b	h	1	68K RAM	Gems - 0x30~0x39 - units
EFFA	b	h	1	68K RAM	Health - 00~08
F003	b	h	1	68K RAM	Genies - 00~unlimited
F400	w	h	1	VRAM	Sprite Table
``````
###### Pokota
He/Him
Okay, question time. Do the readbyte family of commands accept decimal numbers or just hex numbers?