Ooblets

Ooblets

Not enough ratings
Mouse 2 WASD Pseudo-Joystick Angling (M2WPJA) (can be adapted to other games)
By officer balls
a framework to translate mouse positioning into WASD movements, considering angle for ratio of key timing
>wtf that mean?
click to move instead of wasd
>oh ok
   
Award
Favorite
Favorited
Unfavorite
introduction
so you want to use a mouse to move in this game? i did too, bud. i spent countless hours trying to convert mouse movement into vjoy and losing my braincells before finally deciding it was unnecessary. all that needed to be written was a script to calculate the angle you were intending to move, based on the position of the mouse on the screen. the depth of how far the stick would extend, for this game and i'm sure many others, is irrelevant. now you, my fellow crack enjoyers, can control the game with mouse-only too.

i haven't written code in probably 15 years so keep that in mind, as there are likely shortcuts not taken, and a general "if it works, it works" attitude is in play.

ultimately i also wanted to have a framework to translate mouse click into wasd for more games than this. i'm not going to provide any assistance in changing this over to other games, and frankly, i'm not going to give a lot of support here, either. i've taken the time to write notes in the code itself so you can learn from it and do whatever you wish with the base. i would almost certainly disable the farming move speed changes in other games, as they would likely have zero use.

this has been revised several times (probably before anyone has seen any version) - i attempted to re-work the movement system but have not as of yet worked out a proper formula to determine wait (sleep) times directly from the angle given. hence, the original system remains, with pre-determined angle ranges. given that it has so far only been tested within this game, it is unclear whether the game itself can even benefit from higher definition 'wasd' timings - and this will certainly be a limitation in place in other games, as well.

8/23/24 - (possible spoilers) this does not work very well with the arcade machines in port forward. i will not be re-tooling towards this section of the gameplay as the minigames just feel natural on keyboard.

anyway - read on for instructions and to get started.
instructions
install autohotkey from their website (latest version) and save the text from the code section as an .ahk file (i chose ooblets.ahk #woah). check the instructions, make sure your resolution is correct, and look at the hotkeys so you know what to expect. then launch the script once ooblets is open and you're good to go.

addendum: strongly recommend following instructions in 'final steps: automation' section to make things even easier

if you wish to adapt the project for another game, feel free - just please link to this guide as credit if shared publicly. i've left breadcrumb notes in the code aiming to clarify each function and its purpose as best as possible.
code
#Requires AutoHotkey v2.0 #SingleInstance force ; mouse 2 wasd pseudo-joystick angling (m2wpja) ; by officer balls ; NOTES (skip to INSTRUCTIONS if you can't read) ; this is coded for use with borderless fullscreen. changing CoordMode in the Move() function should allow for Windowed ! (un-tested) ! ; check resoX and resoY against window size if you do so. ! (un-tested) ! ; if you wish to change hotkeys from the defaults and combos, refer to https://www.autohotkey.com/docs/v2/KeyList.htm for key references ; INSTRUCTIONS: configure resoX and resoY to match your screen resolution. read HOTKEYS, make any necessary personalization changes. start the game, then start this. ; (alternatively read further in the steam guide to setup auto-launching) game:="ooblets.exe" ; change this if adapting to another game resoX:=1920 ; screen X resolution resoY:=1080 ; screen Y resolution CenterX:=0.5 ; character screen X position (0-1 range left-right) CenterY:=0.6 ; character screen Y position (0-1 range top-bottom) dz:=Float(0.05) ; deadzone % of each quadrant that ignores angle consideration (allows for cleaner linear snaps) moveMod:=10 ; variable for movement delays tries:=0 ; launch- retry: if !WinExist("ahk_exe " game) ; if the game isn't open, { if tries<12 { suspend 1 ; then disable hotkeys, sleep 5000 ; pause for 5 seconds, tries+=1 ; and increase "tries" counter (repeating up to 12x) Goto retry } else if tries==12 { ; if the game isn't open by the 1min mark, ExitApp ; then the script will exit. } } suspend 0 ; re-enables hotkeys ; HOTKEYS ; some are formatted differently to ensure proper triggering ; if you're modifying the code for other games, you may have to change simple hotkeys (i.e. Space) to the send type or vice-versa A_MaxHotkeysPerInterval:=800 ; prevents ahk pop-up when you scroll by increasing max hotkeys processed per interval - ; you will probably never come close to this limit, but my mouse has a free wheel, so... #HotIf WinActive("ahk_exe " game) ; checks that you are ingame to decide if hotkeys are processed ~LButton::Move() ; left click = movement ; if edited, ensure to modify all instances throughout the script ~RButton::Shift ; right click = shift (run) - only works when LMB already is held, otherwise prevents movement altogether MButton up::Enabler() ; middle click = toggle movement system (+ scroll wheel) - ***important to remember in certain menus*** ~XButton2::Space ; thumb forward button = spacebar ~RButton & ~LButton::E ; right click + left click = e XButton1::Tab ; thumb back button = tab (grumboire) ~RButton & XButton1::send "{b down}{b up}" ; right click + thumb back button = expand quest panel RButton & WheelUp::send "{t down}{t up}" ; right click + scroll upp = hide sidebar RButton & WheelDown::send "{Esc down}{Esc up}" ; right click + scroll down = escape ~WheelUp:: ; these will disable when the movement system is disabled, to prevent tab changing in grumboire { if canMove { send "{SC01A down}{SC01A up}" ; mousewheel up = [ (item bar) } } ~WheelDown:: { if canMove { send "{SC01B down}{SC01B up}" ; mousewheel down = ] (item bar) } } RButton & XButton2::ModeChange() ; right click + thumb forward button = toggles farming mode, + changes the movement send speed ; if triggered on wrong screen, just repeat the error to resume expected movement RButton & MButton::C ; right click + middle click = decoration mode MButton & WheelDown::send "{z down}{z up}" ; middle click + scroll down = rotate (decoration) #HotIf ; closing of the hotkey game window check ~^+p::Reload ; ctrl shift p = panic button to reload the script. works if game isn't focused. just a failsafe. ; END of HOTKEYS section ; farming variables+functions ; if adapting for another game, consider removing ModeChange and Siesta functions + hotkeys + any calls to those functions farm:=false ; boolean for checks if player is in farming mode, which requires greater delays to avoid becoming a-train sleepy:=50 ; defines the modified wait time for farming mode ModeChange() ; core function to toggle between precision states { global ; necessary to read/write global variables send "q" ; toggles farming mode in games farm:=!farm ; toggles the script's farming variable return } Siesta(mult) ; keypress delayer for farming with multiplier input for sync/consistency { if farm { Sleep sleepy*mult } } ; end of farming stuff canMove:=true ; variable switch for the movement system (to prevent bad menu input) Enabler() ; callable function to change the state of the switch above { global canMove:=!canMove return } Move() ; core movement function { if canMove { ; checks that the system shouldn't be disabled jumppoint: ; jumppoint label - each sub-block will return here afterwards to ensure mouse left is still being held if !GetKeyState("LButton") { return } while GetKeyState("LButton") { ; core 'while' loop to check that the key is still being held CoordMode "Mouse", "Screen" ; change "Screen" to "Window" if using windowed mode (allegedly) MouseGetPos &xpos, &ypos ; captures mouse coordinates newX := Float(xpos/resoX) ; aaand newY := Float(ypos/resoY) ; translates them to 0-1 range moveX := " " ; creates empty default keypress variable moveY := " " ; creates empty default keypress variable a:=Float(Abs(newX-CenterX)) ; relative x from center o:=Float(Abs(NewY-CenterY)) ; relative y from center if (a<dz) & (o<dz) { ; ignore any input that doesn't go outside deadzone Goto jumppoint } ; key select block ; determines keys from mouse position relative to the centerpoint if newY<CenterY { moveY:="w" } if newX<CenterX { moveX:="a" } if newY>CenterY { moveY:="s" } if newX>CenterX { moveX:="d" } if (a<dz) & (o>dz) { ; up/down deadzone send "{" moveY " down}" Sleep moveMod send "{" moveY " up}" Siesta(2) Goto jumppoint } if (a>dz) & (o<dz) { ; side/side deadzone send "{" moveX " down}" Sleep moveMod send "{" moveX " up}" Siesta(2) Goto jumppoint } angle := ATan(o/a) ; arctangent math - gets angle (in radians) from the mouse cursor relative to the defined centerpoint angle := angle * 57.2957795131 ; approximate conversion of radians to degrees ranging 0-90 ; angle block ; tldr: checks angle to decide timing ratio for x:y movement ; sends appropriate movement keys for the quadrant of the screen you click if angle<=15 { send "{" moveX " down}" send "{" moveY " down}" Sleep moveMod send "{" moveY " up}" Sleep moveMod*2 send "{" moveX " up}" Siesta(3) Goto jumppoint } if angle>15 and angle<=30 { send "{" moveX " down}" send "{" moveY " down}" Sleep moveMod send "{" moveY " up}" Sleep moveMod send "{" moveX " up}" Siesta(3) Goto jumppoint } if angle>30 and angle<=60 { send "{" moveX " down}" send "{" moveY " down}" Sleep moveMod send "{" moveX " up}" send "{" moveY " up}" Siesta(3) Goto jumppoint } if angle>60 and angle<=75 { send "{" moveX " down}" send "{" moveY " down}" Sleep moveMod send "{" moveX " up}" Sleep moveMod send "{" moveY " up}" Siesta(3) Goto jumppoint } if angle>75 { send "{" moveX " down}" send "{" moveY " down}" Sleep moveMod send "{" moveX " up}" Sleep moveMod*2 send "{" moveY " up}" Siesta(2) Goto jumppoint } Goto jumppoint ; insurance } } } WinWaitClose "ahk_exe " game ; detects when game is closed ExitApp ; closes script when ^
default hotkeys (i didn't read!)
left click = movement
right click = shift (run) - only works when LMB already is held, otherwise prevents movement altogether
((this -does- interfere with splitting item stacks, haven't ID'd any other issue areas))

middle click = toggle movement system + scroll wheel - ***important to remember in certain menus***

thumb forward button = spacebar
right click + left click = e

thumb back button = tab (grumboire)
right click + thumb back button = expand quest panel

right click + scroll down = escape

mousewheel up = [ (item bar)
mousewheel down = ] (item bar)

right click + thumb forward button = toggles farming mode, + changes the movement send speed
(if you trip up the speed toggle (i.e. use combo while in a menu), repeat the error to resume expected movement)

right click + middle click = decoration mode
middle click + scroll down = rotate (decoration)

ctrl+shift+p = panic button (reloads the script) (just a failsafe that you won't likely need to use)
final steps: automation
after a little extra consideration, i realized it's possible to make this launch by default with the game.

1. save the autohotkey script in the same folder with the game to simplify everything (right click ooblets in library > manage > browse local files, if you are unsure where this is)

2. save the following code block as launch.bat file in the same directory:
@echo off start ooblets.exe start ooblets.ahk exit

3. right click ooblets in your library again, this time enter properties. change the launch options to the following:
launch.bat %COMMAND%

the script will now launch with your game, and it will already automatically close when you exit.
have fun
1 Comments
officer balls  [author] 20 Aug, 2024 @ 8:17am 
*cleaned up the code somewhat, fixed it to work with normal alt-tabbing and not require re-enabling the script to block hotkey interference in other software; added a default hotkeys section for tiktok users that don't want to read

feel free to utilize/convert this for other games/projects, just please link to original posting if sharing modifications publicly.