⚠️ WARNING: At most cases it’s not allowed to redistribute modified package files without owner’s consent! And also, this note will only give general advice, and NOT focus on any specific game.

NOTE: At most cases it’s a better idea to run your games with wine in Linux or macOS.

https://github.com/krkrsdl2/krkrsdl2 is an open source implementation of the krkr engine.

Why bother use this? There are always some people (including me) unsatisfied with visual novels which support Windows only. Running a full Windows virtual machine is always a challenge for low-memory (≤ 8GB) devices. And although wine is going great recent years, it requires a lot of 32-bit components and is somewhat energy-consuming when running these games. There should be a better solution, isn’t it?

Unpacking xp3 files

https://github.com/UserUnknownFactor/krkr-xp3 works well with unencrypted xp3 package. It’s written in Python and thus cross-platform.

python -m xp3.xp3 -u ~/path/to/game/data.xp3 exported_folder_name

Install MenuItem stub to unpacked files

See https://github.com/krkrsdl2/kag3/tree/krkrsdl2/data

As krkrsdl2 does not implement MenuItem, MenuItem_stub.tjs, font.ttf** and startup.tjs** are required to be placed in unpacked root folder.

*: There was an implementation for macOS Cocoa (https://github.com/krkrsdl2/krkrsdl2/pull/12‣), but it got removed in main branch.

**: Krkrsdl2 may have some issues when your system does not have Noto Sans JP. And it seems that the exceptions about fonts will not be thrown out if you load a font in startup.tjs.

***: Check game’s original startup.tjs to make sure if something (like a global.xxx definition) should be added.

Compile and run

After all submodules get downloaded, compile krkrsdl2 (Refer to .github/workflow/ci.yml for building instructions):

meson setup build/
meson compile -C build

Test game with krkrsdl2:

./build/krkrsdl2 path/to/exported_folder_name

For simple games most functionalities are usable. Game will be stopped when uncaught exceptions occurred. You may see things like this in terminal:

==== An exception occured at yesnodialog.tjs(16)[(function) YesNoDialogWindow], VM ip = 17 ====
-- Disassembled VM code --
#(16) 		drawDevice.preferredDrawer = global.Window.PassThroughDrawDevice.dtDrawDib;
00000011 global %1
00000013 gpd %2, %1.*0	// *0 = (string)"Window"
00000017 gpd %3, %2.*1	// *1 = (string)"PassThroughDrawDevice"
-- Register dump --
%-11=(void)  %-10=(object)(object 0x7fb99c542b40:0x7fb99c542b40)  %-9=(void)  %-8=(int)0
%-7=(int)0  %-6=(int)0  %-5=(void)  %-4=(string)"Confirmation"
%-3=(string)"Are you sure you want to exit?"  %-2=(object)(object 0x7ffee7eee7d0:0x0)
%-1=(object)(object 0x7fb99c542b40:0x7fb99c542b40)  %0=(void)
%1=(object)(object 0x7fb997e07390:0x0)  %2=(object)(object 0x7fb997c161d0:0x0)  %3=(void)
%4=(object)(object 0x7fb99c5c6890:0x7fb99c5c6890)  %5=(void)  %6=(void)  %7=(void)  %8=(void)
%9=(void)
-----------------------------------------------------------------------------------------------
Script exception raised
Member "PassThroughDrawDevice" does not exist
trace : yesnodialog.tjs(211)[(function) askYesNo] <-- mainwindow.tjs(739)[(function) onCloseQuery] <-- immediate event