Posts for CrazyTerabyte

CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
There is very little interaction in this (mini)game: wait for the game to allow input (takes seconds); warp the pointer to the desired place, click-drag, warp to destination (takes milliseconds); rinse repeat. Not sure if this qualifies according to the movie rules, also because this mini-game is essentially a simplified jigsaw puzzle, which can be considered a board game, and board games are usually not accepted. Yes, there is super-human play in the TAS, but I did not find it interesting. Sidenote/off-topic: A game with a similar mechanic (jigsaw puzzle), but more interesting and longer is SNES Pieces. I wonder if that would be an interesting TAS to watch.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Masterjun wrote:
For reference, Lua 5.1 doesn't have bitwise operators (they were implemented in Lua 5.3). So the two functions MUGG posted are the workaround for that. At the end it's the same solution.
Oops, my mistake, I should have checked, sorry about that!
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
MUGG wrote:
For my love2d project I need a function that checks if a bit is set in a hex number. It needs to be a pure Lua implementation (Lua 5.1). The lua documentation wasn't much help so far. (...)
There is a simple solution, using bitwise arithmetic (the same solution can be implemented in essentially any programming language):
function hasbit(number, bit)
  return (number & (1 << bit)) ~= 0
end
If you do a bitwise-AND between two numbers, only the bits that were set on both inputs will be set on the output. In special, if you do AND against a number that only has one bit set, then effectively you are testing that single bit. If the result is zero, that bit was zero; otherwise that bit was one. And how can you address one single bit? By powers of 2, which can be written by exponentiation or by doing doing bit shifts.
2**0  ==  1 << 0  == 1
2**1  ==  1 << 1  == 2
2**2  ==  1 << 2  == 4
2**3  ==  1 << 3  == 8
2**4  ==  1 << 4  == 16
...
If you are curious to learn more, watch this video: https://www.youtube.com/watch?v=F8kx56OZQhg And have fun while coding! :)
Post subject: Re: #6428: Lobsterzelda & ViGadeomes's A2600 Smurfs: Rescue in Gargamel's Castle in 03:29.1
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
TASVideoAgent wrote:
The B button is pressed to start the game, but after that, it serves no purpose.
Nitpick: Atari 2600 doesn't have a B button. It only has one nameless red button on the controller, and select/reset buttons on the console. You might want to fix/update the description. ;)
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
creaothceann wrote:
brunovalads wrote:
the resolution of you computer
What if there's more than one screen and the program is partly on both? :)
What if each display has a different resolution? Or if one of the displays is portrait? (like this: ▄▄█)
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
FatRatKnight wrote:
[…] I don't know the internals that lua goes through to locate table elements, but I'm hoping the search is fast enough to not care too much how many things are in that table. […]
Lua tables behave as both array/lists and as hash_map/dict. And the Lua interpreter is supposed to be smart enough to use the best implementation based on your usage. I don't know enough of the internals, but I wouldn't worry about the cache size, as it shouldn't affect performance. (Unless it starts eating too much memory, or if you try to list all of its elements; then the size matters.) Another idea: You may look at http://lua-users.org/wiki/ProfilingLuaCode to use a profiler to identify performance bottlenecks on your code.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
According to: http://www.gamefaqs.com/nes/563396-clu-clu-land/faqs/72591
Once you successfully complete all four of the patterns from the gold stage (completing 21 stages in total, including the bonus stages), […] if you cross over a revealed gold bar, it now flips over to reveal its dull, non-reflective side. Crossing over it again will toggle the gold bar between its regular shiny side and its dull, bland side.
In other words, an improvement to this movie would be to actually complete all patterns without resetting (or maybe reset only after the first level, since the first level doesn't repeat). That way, when the patterns start repeating, they will be in a "hard" difficulty (passing through a revealed gold bar will flip it). The movie would then re-complete the levels with this extra challenge. Tha means the movie would be twice as long for "true" completion of the game. Maybe a bit too boring.
Post subject: ZForms (proof of concept) - and my other lua scripts
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Over time, I've written some Lua scripts and posted some of them here in the forums. Then, one day I decided to follow zeromus's suggestion and collected all my scripts in a repository: https://github.com/denilsonsa/bizhawk-lua-scripts In special, I want to share something I started working on, but stopped mid-way: ZForms. ZForms was my pet project that I wanted to fully implement before posting here. However, given that nowadays I'm not using a Windows machine anymore, and thus I haven't touched BizHawk in a while, I realized that it is unlikely I'll finish this project anytime soon. ZForms idea was to provide a simple (and almost declarative) API for building user interfaces. Have you ever used forms module to create a nice window for your script? When I did, it felt like it required too much manual work. It required positioning each widget, calculating new positions manually… It was cumbersome to use. ZForms was supposed to make building UIs fun again. It was supposed to simplify the creation of windows with several controls, automatically calculating the size and position of each widget. It could even automatically position the window itself. The current version (which is untouched since August 2015) has some features, but it is still incomplete and probably not ready for production. Consider it as a "tech demo", or as a "proof of concept". Feel free to get inspired by this project and build a better and more complete library than what I've written. I'd be very happy and glad to see a full library that was inspired by my project! :)
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Pokota wrote:
Ah crap, you're right. How I wrote it would break without iterating if it ever comes up false, which isn't the desired behavior. This is what I get for writing code without testing it.
Hey, just an idea, maybe you want to edit your previous code adding a comment saying the code does not work; just to avoid confusing people who are still learning programming that might end up reading it.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
I don't know of any specific tutorial or article about it, but it is common design for several pieces of hardware. Let's imagine an hypothetical hardware with 2KB of RAM and 2KB of video memory. In this imaginary hardware, the CPU has a 16-bit address space, which means it can address at most 65536 addresses (on most architectures, each address contains a single byte; but it is possible to design hardware where each address contains whatever amount is convenient). However, even though 64KB is the maximum addressable memory, only 2KB of RAM is actually installed (for whatever reason). What do we do with the remaining 62K addresses? Well, we can map other pieces of the hardware into the same address space. We can map the sound chip in there. We can map the video memory in there. We can map the cartridge ROM in there. We can map the expansion slot in there. So, in this imaginary hardware, we can say we have 2KB of main RAM, which is mapped from position 0 to position 2K; and we have 2KB of video RAM, which is mapped (almost arbitrarily) from position 8K to 10K. This means the second VRAM address is actually the (8K+2)th address in the address space. This also means that when the CPU reads/writes the address 9K, it is actually accessing the address 1K from the VRAM. (Why mapping the VRAM at 8K? Because the people who designed this imaginary hardware chose so. It could have been at 16K, at 4K, or almost anywhere else.) I hope you could follow this description of this imaginary hardware. You will find out that several pieces of hardware (microcontrollers, video-games…) have the same design principles. And just remember that we are talking binary here: 1K means 1024, 2K means 2048,…
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Anty-Lemon wrote:
Vanilla lua can write files using its io library
Thanks for pointing it out! I just tried and indeed the "io" module is available within BizHawk, and I could write a file using Lua. Today I learned that I can inspect all available modules by just looking at the symbols from the "_G" variable.
waterise wrote:
That message (console output) gets pushed through a LuaSocket, then to some Java bridge (which connects with the chat bot)
On Linux or most unixes, it is easy to create a "named pipe", or a "socket" file, which allows writing to it using like if it was writing to any file. So, for Linux or unixes, probably you don't even need LuaSocket. On Windows, however, I don't believe there is such thing (feel free to prove me wrong!); which means you need to add the LuaSocket C code into BizHawk before you can use LuaSocket. At least that's where I would start.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
waterise wrote:
Basically: How do I code a Twitch bot that receives commands from a Java bridge and then posts in the Channel chat based on the commands it receives?
EDIT: I was wrong about writing to files. See the message(s) just after this one. AFAIK, there is no Lua binding in BizHawk to communicate with the outer world. So, it is impossible to write to files or to sockets. Solution for this? Maybe propose a good API for a new Lua module, and even implement it in BizHawk. The only I/O it seems to have is capturing screenshots or savestates, which can optionally take a pathname. So, as a very very very ugly workaround, you could write some kind of code outside BizHawk that monitors a specific directory for new files, and then you use your Lua script inside BizHawk to write savestates or screenshots with specific filenames. That would be a very hacky way to do one-way communication from BizHawk Lua to the outer world. Have I already told you it is very ugly? Other than that awful workaround, I'm afraid you need to modify BizHawk itself. Either to implement a new API, or maybe to make "console.write" write stuff into your JavaBridge (in addition to the console screen).
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Pokota wrote:
I'm looking at the lua functions, and there's gui.DrawNew(string name). What sort of shenanigans can I do with this?
It calls "LockLuaSurface()", which is defined at "BizHawk.Client.EmuHawk\DisplayManager\DisplayManager.cs". There are only two available surfaces: "emu" and "native". I've toyed with it only once. Let me try to explain... Suppose you emulating a GameBoy game. Since the 160x144 is very small, you configure the emulator to 3x zoom. Then, for all Lua gui functions, the coordinate system is the emulator one, which is just 160x144. However, if you call DrawNew("native"), all gui functions will now use the native coordinate system, which will be 480x432 (= 160x144 times 3). As I said, I only tried it once, discovered what happened, and never tried again. I don't even know what side-effects it has. I guess one small "issue" to be aware is that the "emu" surface always gets cleared and redrawn on each frame (by the emulation itself), while the "native" surface doesn't. Which means if you draw something on it once, it will stay there until it is overwritten. Again, I'm not 100% sure about it. And I'm not sure how it interacts with other built-in features (such as messages at the bottom, on-screen input indicators and frame counters).
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
waterise wrote:
This Lua script provides me with a "Lua Console" that gives me output of the things that are happening in real-time within the game as it plays. Ok, now, Each output has a number next to it (the red square box in the pic in the console)...my question is: How can I take each output it gives me throughout the game and send that to my Twitch.tv Channel (via a chat bot)?
Suggestion: use the "forms" module create a new form window. In that window, add one or more labels. Then, instead of (or in addition to) printing to the console, you update the label text using settext(). Then, in your stream, you just capture this new window. If you want to see examples of using the forms module, look at one of my scripts (either from this thread, or from here), or maybe also some sample scripts shipped with BizHawk.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Oh, well... I tried refreshing a bit more, and now it worked. Sorry for the noise. And thanks for fixing this!
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Nach wrote:
CrazyTerabyte, I also put in the CSS change you requested. Please force refresh and confirm the fix.
Not yet. I tried using Chrome Developer tools, forcing a hard reload, and disabling cache. Not fixed yet. Check by yourself:
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
zeromus wrote:
you need to setup a source code repository somewhere
That's a nice idea, but I also like the idea of having a collaborative repository of lua scripts for BizHawk. What do you people think about it? A repository in GitHub (or somewhere else) where the community can keep the scripts. Kind of "next step" after this forum thread.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Once a moderator edits it, I cannot edit anymore. Anyway, here is the image, in case anyone wants:
Post subject: SNES Push-Over Lua script
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Push-Over, for SNES This script has the following features:
  • Level select.
  • Show the passcode for the current level.
  • Show the passcode using a sprite sheet image to draw the digits (instead of built-in text rendering). Requires latest SVN version; but the script also has a fallback code for text rendering.
  • Automatically takes screenshots of all levels. Since some levels take a bit longer to load, the script detects when the main character is at a specific animation frame, so he looks the same in all screenshots.
  • Bruteforce passcode testing. It will likely take 10 or 20 hours to bruteforce all passcodes (nope, I have not left it running for so long). Fun fact: for each passcode, the game also accepts the same passcode added by 2.
  • Since it is impossible to call emu.frameadvance() in a button handler function, this script implements a work around.
Language: lua

-- How to install: -- 1. Make sure the directory containing this lua script is writable. -- 2. Save the PNG image from the comment below into the same directory as the lua script. -- Must be placed in the same directory of the lua script. NUMBERS_PNG = "SNES_Push-Over_numbers.png" -- The contents of this image are: -- -- Will be saved at the same directory of the lua script. MAINMENU_SAVESTATE = "SNES_Push-Over_MainMenu.State" -- Some constants. PASSCODE_BASE = 0x001100 TIME_TICK = 0x000303 -- 1/50 of second TIME_SECOND = 0x000304 -- seconds -- Tables in Lua start counting from 1. -- Number literals starting with zero are still represented in base 10. PASSCODES = { 00512, -- Level 01 01536, -- Level 02 01024, -- Level 03 03072, -- Level 04 03584, -- Level 05 02560, -- Level 06 02048, -- Level 07 06144, -- Level 08 06656, -- Level 09 07680, -- Level 10 07168, -- Level 11 05122, -- Level 12 05634, -- Level 13 04610, -- Level 14 04098, -- Level 15 12290, -- Level 16 12802, -- Level 17 13826, -- Level 18 13314, -- Level 19 15362, -- Level 20 15878, -- Level 21 14854, -- Level 22 14342, -- Level 23 10246, -- Level 24 10758, -- Level 25 11782, -- Level 26 11270, -- Level 27 09222, -- Level 28 09734, -- Level 29 08718, -- Level 30 08206, -- Level 31 24590, -- Level 32 25102, -- Level 33 26126, -- Level 34 25614, -- Level 35 27662, -- Level 36 28174, -- Level 37 27150, -- Level 38 26638, -- Level 39 30734, -- Level 40 31246, -- Level 41 32270, -- Level 42 31758, -- Level 43 29726, -- Level 44 30238, -- Level 45 29214, -- Level 46 28702, -- Level 47 20510, -- Level 48 21022, -- Level 49 22046, -- Level 50 21534, -- Level 51 23582, -- Level 52 24094, -- Level 53 23070, -- Level 54 22558, -- Level 55 18494, -- Level 56 19006, -- Level 57 20030, -- Level 58 19518, -- Level 59 17470, -- Level 60 17982, -- Level 61 16958, -- Level 62 16510, -- Level 63 16511, -- Level 64 17023, -- Level 65 18047, -- Level 66 17535, -- Level 67 19583, -- Level 68 20095, -- Level 69 19071, -- Level 70 18559, -- Level 71 22655, -- Level 72 23167, -- Level 73 24191, -- Level 74 23679, -- Level 75 21631, -- Level 76 22143, -- Level 77 21247, -- Level 78 20735, -- Level 79 28927, -- Level 80 29439, -- Level 81 30463, -- Level 82 29951, -- Level 83 31999, -- Level 84 32511, -- Level 85 31487, -- Level 86 30975, -- Level 87 26879, -- Level 88 27647, -- Level 89 28671, -- Level 90 28159, -- Level 91 26111, -- Level 92 26623, -- Level 93 25599, -- Level 94 25087, -- Level 95 08703, -- Level 96 09215, -- Level 97 10239, -- Level 98 09727, -- Level 99 44543 -- Level 00? } function input_passcode(passcode) for index = 8, 0, -2 do local digit = passcode % 10 passcode = (passcode-digit) / 10 mainmemory.write_u16_le(PASSCODE_BASE + index, digit) end end function get_passcode_digit(index) return mainmemory.read_u16_le(PASSCODE_BASE + 2 * index) % 10 end function draw_passcode() for i = 0, 4, 1 do local value = get_passcode_digit(i) if gui.drawImageRegion then -- Implemented in BizHawk revision 9265, fixed a few revisions later. gui.drawImageRegion(NUMBERS_PNG, 0, value * 16, 16, 16, 128 - 40 + i * 16, -1) else gui.drawText(128 - 40 + i * 16, 0, value, 0xFFFFFFFF, 16) end end end -- joypad.set sets the value for a single frame function reset() joypad.set({Reset = true}) end function start() joypad.set({Start = true}, 1) end function wait_until(domain, address, byte_value) memory.usememorydomain(domain) while memory.readbyte(address) ~= byte_value do emu.frameadvance() end memory.usememorydomain("WRAM") end function wait_until_tick_equals_to(value) wait_until("WRAM", TIME_TICK, value) end function wait_main_character_is_getting_out() wait_until("VRAM", 0xC08A, 195) end function is_incorrect_code_screen() local BASE = 0x0022D0 local text = "incorrect code" for i = 1, 14, 1 do local ascii = string.byte(text, i) local value = mainmemory.readbyte(BASE + i*2) if ascii ~= 32 then -- Ignore space if value ~= ascii then return false end end end return true end function go_to_main_screen() reset() client.unpause() input_passcode(00000) client.speedmode(400) -- Waiting until the game resets to the passcode of the first level. -- wait_until("WRAM", PASSCODE_BASE + 4, 5) -- Waiting and auto-firing the Start button. while mainmemory.readbyte(PASSCODE_BASE + 4) ~= 5 do start() emu.frameadvance() emu.frameadvance() end -- Waiting one more frame to let the screen be drawn. emu.frameadvance() client.speedmode(100) savestate.save(MAINMENU_SAVESTATE) client.pause() end function go_to_level(level_number) savestate.load(MAINMENU_SAVESTATE) client.unpause() input_passcode(PASSCODES[level_number]) start() -- Setting the TICK to a known, arbitrary value. mainmemory.writebyte(TIME_TICK, 33) -- Waiting until it gets reset when the level starts. client.speedmode(400) wait_until_tick_equals_to(0) wait_main_character_is_getting_out() client.speedmode(100) client.pause() end function take_screenshots_of_all_levels() for level_number = 1, 100, 1 do go_to_level(level_number) -- Drawing the passcode at the top of the level. -- It is only captured in screenshots if "File->Screenshot->Capture OSD" is enabled. client.unpause() for i = 0, 32, 1 do -- Clearing OSD messages. gui.addmessage("") end if forms.ischecked(CHCK_SHOWPASSCODE) then draw_passcode() emu.frameadvance() end client.screenshot(string.format("Push-Over_level_%02d_passcode_%05d.png", level_number, PASSCODES[level_number])) end end function bruteforce_all_passcodes() client.speedmode(800) for passcode = 0, 99999, 1 do local passcode_string = string.format("%05d", passcode) savestate.load(MAINMENU_SAVESTATE) client.unpause() input_passcode(passcode) gui.addmessage(passcode_string) start() -- Setting the TICK to a known, arbitrary value. mainmemory.writebyte(TIME_TICK, 33) -- Waiting until it gets reset when the level starts. wait_until_tick_equals_to(0) if not is_incorrect_code_screen() then print(passcode_string) end end client.speedmode(100) client.pause() end -- GUI-related functions below. function button_mainmenu_click() SHOULD_GO_TO_LEVEL = -1 client.unpause() end function button_goToLevel_click() local level_number = forms.gettext(TEXT_LEVELNUM) level_number = tonumber(level_number) if level_number == nil then return; end level_number = math.floor(level_number) if level_number <= 0 or level_number > 100 then return; end SHOULD_GO_TO_LEVEL = level_number client.unpause() end function button_previousLevel_click() local level_number = forms.gettext(TEXT_LEVELNUM) forms.settext(TEXT_LEVELNUM, level_number - 1) button_goToLevel_click() end function button_nextLevel_click() local level_number = forms.gettext(TEXT_LEVELNUM) forms.settext(TEXT_LEVELNUM, level_number + 1) button_goToLevel_click() end function button_screenshots_click() SHOULD_GO_TO_LEVEL = -2 client.unpause() end function button_findpasscodes_click() SHOULD_GO_TO_LEVEL = -3 client.unpause() end FORM = forms.newform(128, 240, "Push-Over") BUTT_MAINMENU = forms.button(FORM, "Initialize Save State", button_mainmenu_click, 0, 0, 120, 20) LABL_LEVELNUM = forms.label(FORM, "Level:", 0, 30, 40, 20, false) TEXT_LEVELNUM = forms.textbox(FORM, "1", 40, 20, "UNSIGNED", 40, 30, false, true) BUTT_GOTOLEVEL = forms.button(FORM, "Go to level", button_goToLevel_click, 80, 30, 40, 20) BUTT_PREVLEVEL = forms.button(FORM, "< Prev", button_previousLevel_click, 0, 50, 60, 20) BUTT_NEXTLEVEL = forms.button(FORM, "Next >", button_nextLevel_click, 60, 50, 60, 20) CHCK_SHOWPASSCODE = forms.checkbox(FORM, "Show passcode", 0, 80) BUTT_SCREENSHOTS = forms.button(FORM, "Take screenshots of all levels", button_screenshots_click, 0, 110, 120, 40) BUTT_FINDPASSCODES = forms.button(FORM, "Bruteforce passcodes (very slow!)", button_findpasscodes_click, 0, 150, 120, 40) -- This is needed because we can't call emu.frameadvance from the GUI thread. SHOULD_GO_TO_LEVEL = nil while true do if SHOULD_GO_TO_LEVEL ~= nil then if SHOULD_GO_TO_LEVEL == -1 then go_to_main_screen() elseif SHOULD_GO_TO_LEVEL == -2 then take_screenshots_of_all_levels() elseif SHOULD_GO_TO_LEVEL == -3 then bruteforce_all_passcodes() elseif SHOULD_GO_TO_LEVEL > 0 and SHOULD_GO_TO_LEVEL <= 100 then go_to_level(SHOULD_GO_TO_LEVEL) end SHOULD_GO_TO_LEVEL = nil end if forms.ischecked(CHCK_SHOWPASSCODE) then draw_passcode() end emu.frameadvance() end
Moderators Note: The PNG Text Data was removed due to breaking the forums' layout. Please refrain from posting long single line strings.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
1-line improvement to TASVideos CSS:
Language: css

ul.tabbernav li { display: inline-block; /* was inline */ }
Why? Open http://tasvideos.org/Bizhawk/LuaFunctions.html in a browser window with narrow width. In my case, I decided to leave that reference page open in a second monitor, which is in portrait mode (800x1280 resolution). Before that CSS change, there is horizontal scrolling at the tabs. With that change, there is no need to scroll anymore.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
FractalFusion wrote:
Games do weird things with memory sometimes so that it appears as if there are enemies with 0 max health (even if there aren't supposed to be enemies).
The game code might be just reusing the same memory region for other data. For instance, the Game Over screen might run a completely unrelated chunk of code that just happens to use the same memory region. Anyway, checking for sane values before using them is always a good idea. :)
Post subject: BizHawk crashes when using Pokota Lua script
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
I tried the Pokota Lua script. I opened the game and went to the savestate right before the Metroid Queen (at the corridor with spikes). However, as soon as Samus descends into the boss lair, BizHawk crashes with this message:
LuaInterface.LuaScriptException: [string "main"]:107: A .NET exception occured in user-code
Inner Exception:
System.OverflowException: Overflow error.
   at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
   at System.Drawing.Graphics.FillRectangle(Brush brush, Int32 x, Int32 y, Int32 width, Int32 height)
   at BizHawk.Client.EmuHawk.GuiLuaLibrary.DrawRectangle(Int32 x, Int32 y, Int32 width, Int32 height, Nullable`1 line, Nullable`1 background)
StackTrace:
   at LuaInterface.Lua.ThrowExceptionFromError(Int32 oldTop)
   at LuaInterface.Lua.callFunction(Object function, Object[] args, Type[] returnTypes)
   at LuaInterface.Lua.callFunction(Object function, Object[] args)
   at LuaInterface.LuaFunction.Call(Object[] args)
   at BizHawk.Client.Common.EventLuaLibrary.CallFrameAfterEvent()
   at BizHawk.Client.EmuHawk.MainForm.StepRunLoop_Core(Boolean force)
   at BizHawk.Client.EmuHawk.MainForm.ProgramRunLoop()
   at BizHawk.Client.EmuHawk.Program.SubMain(String[] args)
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
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 FORM = forms.newform(128, 80, "Aladdin") 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 emu.frameadvance() 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
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Damn, I spoke too soon. It seems that the X position can be changed, as well as which pattern and which palette is used to draw the sprite, but the Y position is fixed. Even changing the VRAM does not change the rendered sprite position. I don't know if I'm missing something technical here, or if this is actually a bug.
CrazyTerabyte
He/Him
Experienced Forum User
Joined: 5/7/2005
Posts: 74
Yep! I hadn't realized version 1.9.2 was released a couple of days ago. Which makes me wonder... Maybe a "auto-check for updates" feature might be useful in BizHawk. Just check for updates, but don't download them (just point the user to the URL). Of course, only if it is easy to implement.