You are not logged in.

Read the FAQ and Knowledge Base before posting.
We won't make a 3DS/2DS emulator.



#1 2021-03-30 04:32:33

windwakr
Member
Registered: 2010-06-10
Posts: 18

Metroid Prime Hunters LUA script

I've been sitting on this for a while(years) now and decided to clean it up a bit and post it. This script allows you to play Metroid Prime hunters with a controller with smooth camera movement.
Some small snippets(like subweapon switching) were borrowed from https://forums.desmume.org/viewtopic.php?id=10957 .
This may only work on the Windows version of DeSmuME, I'm not sure.

Clear any controller input you may have set up in DeSmuME before using.
By default it's set up for an Xbox style controller but the controls are easily customizable.

left stick - move
right stick - aim
left or right trigger - shoot/scan
bumpers - cycle subweapon forward/back
start - start
d-pad up(hold) - scan visor
d-pad down - morphball
d-pad left - presses back arrow on messages
d-pad right - presses forward arrow on messages
B - presses OK on messages
A - jump
X - morphball boost
Y - cycle weapon(beam/missile/subweapon)
select(hold) - virtual stylus

while virtual stylus is active
  right stick - move the virtual stylus
  right bumper - tap the screen
  left bumper - toggle manual touchscreen input

The way aiming works is the center of the screen is continually pressed and the script injects stylus movement into the game's memory. If you need to manually use the touchscreen then use select+left bumper to toggle aiming on or off. That shouldn't be necessary with the existence of the virtual stylus, though.

Use with the U.S. version of the game.

joyid = 0 --change this if your preferred controller isn't being picked up
deadzone = 0.15 --Adjust analog stick deadzones

cooldown=0
weapon=0
subweapon=0
togglestylus=false
toggleaim=false
vcurx=128
vcury=96
key = {}
joy = {}

--Set the controls here
morphkey = "joy.down" --morph ball switch
visorkey = "joy.up" --scan visor switch(hold)
okkey = "joy.2" --ok button in messages
leftkey = "joy.left" --left arrow in messages
rightkey = "joy.right" --right arrow in messages
weaponkey = "joy.4" --weapon cycle
subweaponkey1 = "joy.5" --subweapon cycle back
subweaponkey2 = "joy.6" --subweapon cycle forward
leftstickx = "joy.x" --must be analog stick axis
leftsticky = "joy.y" --must be analog stick axis
rightstickx = "joy.u" --must be analog stick axis
rightsticky = "joy.r" --must be analog stick axis
shootkey = "joy.z" --may be either analog axis or button
boostkey = "joy.3" --morph ball boost
vstyluskey = "joy.7" --virtual stylus(hold)
jumpkey = "joy.1" --jump
startkey = "joy.8" --start


--https://www.lua.org/pil/14.1.html
function getfield (f)
  local v = _G    -- start with the table of globals
  for w in string.gfind(f, "[%w_]+") do
    v = v[w]
  end
  return v
end

while true do
    joysend = {}
    key=input.get()
    joy = controller.get(joyid)
    
    if getfield(vstyluskey) then
        toggleaim = true --this exists to just delay the pressing of the screen when you release the virtual stylus key
        if vcury>0 then
            gui.drawbox(vcurx-1, vcury-1, vcurx+1, vcury+1, "#000000", "#FFFFFF")
        else
            gui.drawbox(vcurx-1, vcury, vcurx+1, vcury+1, "#FFFFFF") --workaround for vcury=0, as it would draw to the top screen
            gui.pixel(vcurx, vcury, "#000000")
        end
        
        if getfield(subweaponkey2) then
            stylus.set{x=vcurx, y=vcury, touch=true}
        end
        if getfield(subweaponkey1) and cooldown==0 then
            togglestylus = not togglestylus
            print('Touchscreen input allowed = ' .. tostring(togglestylus))
            cooldown = 20
        end
        tmp = getfield(rightstickx)
        if tmp and math.abs(tmp)>deadzone then
            vcurx = vcurx + (tmp * 5)
        end
        tmp = getfield(rightsticky)
        if tmp and math.abs(tmp)>deadzone then
            vcury = vcury + (tmp * 5)
        end
        
        if vcurx<0 then vcurx=0 end
        if vcurx>255 then vcurx=255 end
        if vcury<0 then vcury=0 end
        if vcury>191 then vcury=191 end
    else
        if getfield(morphkey) then --Morph
            stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            stylus.set{x=231, y=167, touch=true} emu.frameadvance() emu.frameadvance()
        end
        if getfield(visorkey) then --Visor
            if cooldown == 0 then
                stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            end
            cooldown = 10
            stylus.set{x=128, y=173, touch=true}
        end
        if getfield(okkey) then --OK (in scans and messages)
            stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            stylus.set{x=128, y=142, touch=true} emu.frameadvance() emu.frameadvance()
        end
        if getfield(leftkey) then --Left arrow (in scans and messages)
            stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            stylus.set{x=71, y=141, touch=true} emu.frameadvance() emu.frameadvance()
        end
        if getfield(rightkey) then --Right arrow (in scans and messages)
            stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            stylus.set{x=185, y=141, touch=true} emu.frameadvance() emu.frameadvance()
        end
        if getfield(weaponkey) and cooldown==0 then --Switch weapon (beam->missile->subweapon->beam)
            cooldown=20
            weapon=(weapon+1)%3
            stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            stylus.set{x=85+40*weapon, y=32, touch=true} emu.frameadvance()
            stylus.set{x=85+40*weapon, y=32, touch=true}
        end
        if (getfield(subweaponkey1) or getfield(subweaponkey2)) and cooldown==0 then --Switch subweapon (previous and next)
            cooldown=20
            weapon=2
            if getfield(subweaponkey1) then subweapon=(subweapon-1)%6 end --previous
            if getfield(subweaponkey2) then subweapon=(subweapon+1)%6 end --next
            subX=93+25*subweapon subY=48+25*subweapon
            stylus.set{touch=false} emu.frameadvance() emu.frameadvance()
            stylus.set{x=232, y=34, touch=true} emu.frameadvance()
            stylus.set{x=232, y=34, touch=true} emu.frameadvance()
            stylus.set{x=subX, y=subY, touch=true} emu.frameadvance()
            stylus.set{x=subX, y=subY, touch=true}
        end
        tmp = getfield(leftstickx)
        if tmp and tmp < -deadzone then
            joysend.left = true
        elseif tmp and tmp > deadzone then
            joysend.right = true
        end
        tmp = getfield(leftsticky)
        if tmp and tmp < -deadzone then
            joysend.up = true
        elseif tmp and tmp > deadzone then
            joysend.down = true
        end
        tmp = getfield(rightstickx)
        if tmp and math.abs(tmp)>deadzone and togglestylus==false then
            memory.writedword(0x020DE526, (tmp * 4))
            toggleaim=false
        end
        tmp = getfield(rightsticky)
        if tmp and math.abs(tmp)>deadzone and togglestylus==false then
            memory.writedword(0x020DE52E, (tmp * 6))
            toggleaim=false
        end
        if getfield(boostkey) then
            joysend.R = true
        end
        
        tmp = getfield(shootkey)
        if tmp then
            if type(tmp) == "number" then
                if math.abs(tmp) > deadzone then
                    joysend.L = true
                end
            elseif type(tmp) == "boolean" then
                joysend.L = true
            end
        end
        
        if getfield(jumpkey) then
            joysend.B = true
        end
        if getfield(startkey) then
            joysend.start = true
        end
    end
    
    if cooldown>0 then
        cooldown=cooldown-1
    else
        ball = memory.readbyte(0x020DA818) == 0x02 --Is this a good way of detecting morph ball status??
        if ball==false and togglestylus==false and toggleaim==false then
            stylus.set{x=128, y=96, touch=true} --Required for aiming
        end
    end
    
    joypad.set(1,joysend)
    emu.frameadvance()
end

video recorded while using this script: https://files.catbox.moe/o6r3r5.webm

Last edited by windwakr (2021-04-02 20:18:02)

Offline

#2 2021-04-02 01:45:01

windwakr
Member
Registered: 2010-06-10
Posts: 18

Re: Metroid Prime Hunters LUA script

Updated the script to include a "virtual stylus" for navigating stuff like your ship and the main menu. When holding select(on an xbox style controller) a virtual stylus will be displayed. It can be moved with the right stick and touch the screen with the right bumper. You can still toggle manual touchscreen input if needed with select + left bumper.

Last edited by windwakr (2021-04-02 01:47:21)

Offline

#3 2021-04-02 23:37:09

Legacy
Member
Registered: 2021-04-02
Posts: 1

Re: Metroid Prime Hunters LUA script

I'm actually new to adjusting scripts in DesMume and I'm a visual learner, so I was wondering if you could post of video of how to do this? (I'm sure you would get a lot of views on youtube as well considering no one has done this.)
I always wanted to play Metroid prime hunters but trying to use my right hand for my laptop's mouse and my left hand for the controller is a horrible gaming experience.

Thank you in advance for your time!

Offline

#4 2021-04-05 19:49:14

windwakr
Member
Registered: 2010-06-10
Posts: 18

Re: Metroid Prime Hunters LUA script

Legacy wrote:

I'm actually new to adjusting scripts in DesMume and I'm a visual learner, so I was wondering if you could post of video of how to do this? (I'm sure you would get a lot of views on youtube as well considering no one has done this.)
I always wanted to play Metroid prime hunters but trying to use my right hand for my laptop's mouse and my left hand for the controller is a horrible gaming experience.

Thank you in advance for your time!

What are you having trouble with?

To run Lua scripts you will need the correct dlls in the folder with your DeSmuME exe. A Lua setup guide copied from here:

Download the Lua DLL that matches your Desmume: - https://sourceforge.net/projects/luabin … s/Dynamic/

lua-5.1.5_Win32_dll14_lib.zip for x86 Desmume
lua-5.1.5_Win64_dll14_lib.zip for x86-64 Desmume

Extract lua5.1.dll from the .zip file to the same folder where your DeSmuME_0.9.11_x86.exe or DeSmuME_0.9.11_x64.exe is

Rename lua5.1.dll to lua51.dll

Copy the script from my post into a text file and rename the extension to ".lua". In DeSmuME once the game is running go to "Tools -> Lua Scripting -> New Lua Script Window...". In the new window that pops up hit browse and select the script you saved and it will start running.


If you want to adjust the controls then use this lua script to identify your controller and its buttons

dpad = {"up", "down", "left", "right"}
sticks = {"x", "y", "z", "r", "u", "v"}

function showControllers()
    gui.box(0, 0, 256, 192, "#808080")
    gui.box(0, -192, 256, 0, "#808080")
    for i=0,15 do
        cont = controller.get(i)
        if type(next(cont)) ~= "nil" then
            gui.text(0, (18*i)-143, i)
            xoffs = 14
            for ii=0,32 do
                col = "#606060"
                tmp = tostring(ii)
                if cont[tmp] ~= nil then
                    if cont[tmp] == true then col = "#FF0000" end
                    gui.text(xoffs, (18*i)-143, tmp, col) --goes off screen if controller has more than ~20 buttons.
                    xoffs = xoffs + string.len(tmp)*6 + 2
                end
            end
            xoffs = 14
            for idx, name in ipairs(dpad) do
                col = "#606060"
                if cont[name] ~= nil then
                    if cont[name] == true then col = "#FF0000" end
                    gui.text(xoffs, (18*i)-143+9, name, col)
                    xoffs = xoffs + string.len(name)*6 + 4
                end
            end
            for idx, name in ipairs(sticks) do
                col = "#606060"
                if cont[name] ~= nil then
                    if math.abs(cont[name]) > 0.25 then col = "#FF0000" end
                    gui.text(xoffs, (18*i)-143+9, name, col)
                    xoffs = xoffs + string.len(name)*6 + 2
                end
            end
        end
    end
end
gui.register(showControllers)

CzzpAOV.png
You should see output similar to this, but different depending on your controller and how many of them you have hooked up.
The white number on the left is the controller id. When you press a button it will turn red to help you identify which button corresponds to which number.
In the main script you can then adjust joyid and the controls with the values you find here.

Last edited by windwakr (2021-04-05 19:55:15)

Offline

#5 2021-04-06 02:26:32

windwakr
Member
Registered: 2010-06-10
Posts: 18

Re: Metroid Prime Hunters LUA script

Also, it looks like input in Lua was broken for the last month in DeSmuME builds, but is now fixed. If you get an error when trying to run one of the scripts then make sure you have an up-to-date build of the emulator.

Last edited by windwakr (2021-04-06 06:06:50)

Offline

Board footer

Powered by FluxBB