Hey all, I’m Sodoj and I made Commutator, a snake game you can play in your Microsoft Paint window!

Last night I discovered a huge oversight in my game when @tyrannas mentioned in my comments that their game didn't really work. After some troubleshooting and tinkering with the source code, we realized what was causing the issue: their Windows was in French! Sacré bleu!
Now, in order to explain why that matters, I first need to explain how the game works. When you download Commutator and run the script, the game firsts open up a Microsoft Paint window. When the window is open, the script looks for the window called "Untitled - Paint", which is a default name of MSPaint window in order to focus it and maximize it. This is super important because I need to have the elements of the window such as brushes, brush sizes and canvas on the exact spots, so I could later choose the pencil tool, set it's size and, most importantly, define the boundaries of the game board. There are no hotkeys for picking brushes and canvas is not it's own separate window, so I had to:
- measure where pencil tool and brush size were,
- measure the offset from the top/bot and left/right side of the canvas,
- use the button combination (Left Alt + F, E) to open up Properties and set the canvas size
- script the mouse movement pointing to where the pencil tool is,
- clicking,
- pointing again to the spot where the brush size is,
- calculate where the canvas is by taking the offset into the account.
After all of that, the game draws the cute little border around the board and the game finally begins.
The code for this behavior is rather simple:
```python
pyautogui.hotkey('win', 'r')
pyautogui.write('mspaint')
pyautogui.press('enter')
time.sleep(2)
mspaint_window = gw.getWindowsWithTitle('Untitled - paint')[0]
win32gui.SetForegroundWindow(mspaintwindow.hWnd)
time.sleep(0.1)
win32gui.ShowWindow(mspaintwindow.hWnd, win32con.SW_MAXIMIZE)
pyautogui.hotkey('altleft', 'f')
pyautogui.press('e')
pyautogui.write('805')
pyautogui.press('tab')
pyautogui.write('607')
pyautogui.press('enter')
pyautogui.moveTo(250,75)
time.sleep(0.05)
pyautogui.click()
pyautogui.moveTo(393+247,9+74)
time.sleep(0.05)
pyautogui.click()
time.sleep(0.05)
pyautogui.moveTo(20+393+247,189+9+50)
time.sleep(0.05)
pyautogui.click()
cellsize = 20
score = 0
pyautogui.PAUSE = 0.035
pausechange = 0.001
def getcanvasposition():
paintwin = win32gui.FindWindow(None, 'Untitled - Paint')
rect = win32gui.GetWindowRect(paintwin)
x, y, w, h = rect
x_offset = 15
y_offset = 155
width_offset = 20
height_offset = 150
x += x_offset
y += y_offset
w -= width_offset
h -= height_offset
canvas_width = 800
canvas_height = 600
board_width = canvas_width // cell_size
board_height = canvas_height // cell_size
return x, y, canvas_width, canvas_height, board_width, board_height
canvasx, canvasy, canvaswidth, canvasheight, boardwidth, boardheight = getcanvasposition()
```
It's easy to guess where problems start to arise. In my infinite wisdom while I was developing this game, I assumed that no matter what display language of the system was, the Microsoft Paint window would always be named Untitled - Paint . Needless to say, that wasn't the case c:
Now, this problems seems very easy to fix, just search for the name of the process (mspaint.exe) and find the window that way. And yes, while this solutions resolves that issue, @tyrannas and I have discovered much bigger issue.
The layout of the MSPaint toolbar, as well as hotkeys, are different for each language!
What this means is that with my caveman methods of setting up the game, I would have to code a specific setup for every language, which would mean installing a dozens of language packs, measuring the new layouts, testing out the quirks, checking for keyboard layouts in case WASD wasn't default and writing a shit ton of new code to accommodate for the changes...
... so I tried to do just that. And I failed miserably, stopping after the French and Spanish.
The French was easy enough to implement thanks to @tyrannas 's efforts, and the Spanish needed very little adjusting. The rest of the languages were a total nightmare:
- German had a completely different hotkey combination for opening the Properties, which would additionally complicate the code
- Russian and Ukrainian would not run the hotkeys at all despite my best efforts
- Korean has a toggle between Hangul, the traditional Korean alphabet and the latin alphabet
- ... and so on.
So what did I do to solve the problem in the end, as long as some other miscellaneous quirks?
- I decided to keep the French and Spanish version with a support for French keyboard layout. The game now checks at the beginning which display language is on your Windows, and if it's not either English, French or Spanish, the message will be displayed notifying the player that their language is not supported. It sucks, but it is the best compromise I could come up with.
- I am also checking now if the user is actually running the script on Windows 10. If not, then they also get the message telling them that their system version is not supported. I plan on changing that in the future by releasing the Windows 11 version when I get my hands on it eventually. Speaking of which, those who use Win11, is it any good?
- I now check whether or not the screen resolution height is lower than 800px. If it is then I draw the canvas sized at 640x480, otherwise I draw the 800x600 canvas. This is because the 800x600 canvas size is too tall for some laptops and displays and it is the reason why the "Non Standard" version of the game exists. In retrospect, I should've done before, but as this post shows, I'm not really the sharpest tool in a shed sometimes :d
- I decided to remove the border visual. Playing the game and watching my friends play, I came to the conclusion that it was unnecessary. While it looks cool and it adds some visual flair, it may create confusion as to where the borders actually are. I also don't have to increase the canvas size by a couple of pixels to account for the border line thickness.
The updated version is released on the itch page as a Python script called Commutator_Updated.py. I have decided not to build an executable since I don't really like distributing Python executables. I will also remove the old executables after the jam.
Thank you so much for reading this and thank you for taking the interest in my game! I realize this is not the best written blog post about the game, but I hope you managed to find it interesting!