Devil Connection Demo Decomp

I had been seeing video clips of a super cute game called Devil Connection. I believe it’s the same artist responsible for Makemon. For a while I thought it was a fan animation or a music video all the way up until I saw the announcement video for a Steam demo.

However, the game is a visual novel. The game is entirely in Japanese. And while I had taken some college courses for Elementary Japanese around 2011/2012 at Columbus State University, I did not learn enough vocabulary to be able to work my way through a Japanese VN without a lot of struggle.

BUT! Translation tools are very strong right now, and they can even piece together context from screencaps without a perfect manual transcription of the text on screen. These tools are NOT ready for sensitive tasks like handling medicine orders or preparing official legal documents , but for a low risk task like playing a videogame, a handful of missed cultural notes and some completely wrong translations here and there is low risk.

So I started trying to figure out what it would take if I wanted to do a soft translation of the demo. I browse to the install location Steam put the game at.

v8 javascript engine? The Chromium license? So this must be a browser-based game engine like Electron!

I see a lot of .pak files in locales that seems like it might be the game pre-translated! …wait no that doesn’t make sense, the game has only ever been shown in Japanese. those must be translation files for Chrome itself. In resources I see app.asar. I don’t remember what an asar file is, but it sure feels familiar. Is it a zip file? No. Renaming it to .zip and extracting with Ark does not work. So back to google. And sure enough, more confirmation that this is almost certainly an Electron app. Doesn’t take long to find the info on how to pack and extract an asar file.

cd resources
npx asar extract app.asar custom-unpack
and boom, now I can explore the files. I’ll have to remember to repack it to run it.

From here, I wasn’t entirely sure what to do next. I notice the folder named tyrano and was curious about that. But I first open index.html in a text editor and take a look around. Immediately see the text “Loading TyranoScript” and a short web search later I find out that TyranoBuilder Visual Novel Studio is a visual-editor based visual novel game making engine similar to Ren Py. Neat! I had been toying around a little with RenPy recently so seeing there’s other options like this that are already up and available on Steam seemed quite promising.

https://tyranobuilder.com

So my immediate goal is “Find where the dialogue text is stored”. At the moment I feel like searching with my own eyes rather than relying on grep or “find in files” in Fleet, partly because I’m curious to get my bearings on how this game is packaged in general more than I am eager to translate the texts.

Roughly 10 minutes of skimming the files in the root directory for the asar, I realize the most obvious place to put the Data for a game would probably be the Data folder, so I take and peek

Oh hey a Scenarios folder, that sure sounds like where one might put the scenario text for the various scenes in their game.

I open up Chapter1.ks and quickly notice that the ratio of instructional commands to dialogue and scene text is actually quite a bit higher than I was expecting. I also quickly realize that my plan of translating things has made no room for interactive buttons that are drawn as graphics, or any of the signposts or jokes that are in the background images.

Jump forward about 2 hours. I now have a TSV file with a preliminary auto-translation of the most important texts in Chapter1.ks to reasonably followable (if unflavorful and not very regionalized) English text. I’ve also taken the un-modified copy of the extract .asar file and renamed it to /app and renamed the original app.asar to app.asar.ignore. The existing app.asar.unpacked is left untouched. Doing a short test run to ensure I can still run the game without having to repack everything.

Devil Connection (Devil Connection)
Start from the Beginning
Start from Continue
Option
Collection

Looks like it at least loads from the /app folder. After clicking start it didn’t go straight into chapter 1, the text I’m seeing here is something else. Looks like it’s from scene1.ks

(omg wow the game looks much prettier in action than it does in the videos \=OuuO=/ )

Quick smoke check to see if it’s gonna blow up if I just put in any old text here.

Oh… I didn’t planned for text overflows. And that’s going to be a _constant_ issue as the romanization of any given Japanese text is going to be roughly 2-3 times the characters used on average and Kanji that might only take two or three characters might instead be words that take as many as 12 or more characters… Oh well. It’s something I might be willing to fix if I were more devoted, but for now I just want to see if this’ll even work.


Now I’m going to use a short python script to replace the relevant texts in Chapter1.ks based on my Translation.tsv.

Another hour later. Had a change of plans. Rather than manually doing an excel file for each file to translate, I concatenated all of the .ks files into one big text blob and went through all of them looking for lines that needed translating. Feed the lines through auto-translate to populate the translation column like we did with the proof of concept. And use another python script to automatically go through all of the .js files and replace each matched line with their corresponding translated text.

Translation is going OKish with this approach, but there’s certain sections that the LLM refuses to parse due to sensitive content. As far as I can tell it’s something involving tickling or clothing? Or both? Either way, I got worried I wouldn’t be able to continue, but I gave it the text to continue from and skipped over that section, so maybe it’ll be fine…

Guess I’m taking a break on this now, I am frustrated and want to play videogames and eat and stuff.

It’s tomorrow and I’m doing a quick followup on this:

1, there are a _ton_ of text lines in the file that I’m not sure are actually used in the demo and might have been intended for the full game or something?

2, because it’s so much longer than I expected, it’s a lot harder to automate the process of translating the relevant sections. I can do some basic filtering like ignoring lines that start with known control characters like # or [, but that means quite a number of lines that require an effect to happen first will get skipped unless additional processing is done to skip over matching bracket pairs and focus on only text that might be contained within.

3, I tried messing about with only translating the Chapter 1 file instead of trying to translate everything. And it mostly works, particularly if I go in and manually insert the lines myself. However, the automated injection I wrote is failing resulting in the game failing to even _boot_, and Steam continues to show it as “Running” despite there never being a window for it visible.

I might experiment more with this later if I come up with a better way to automate out the parts I don’t want to do manually, or if I limit the scope to only translating the parts I am encountering my own playthrough. But for now the old and familiar method of screenreader+side translator is probably the better option than translation injection. It’s *definitely* doable, but it’s enough tedium that I wouldn’t do it for fun.

Edit: I think the answer to “why the total text so HUGE!?” is because the “System” folder under Scenario also have their own scenarios, and I accidentally included the Scenario1 file twice???? oops.

If I take another crack at this, what I’d do is along the lines of writing a script to:

Iterate every line of the file. For each line,

1: if the line starts with #, delete the line (Sets the character name, I believe. Since it’s a command, I’m reluctant to mess with it.).

2: If the line starts with *, delete the line (I’m not sure, but I believe these are for numbered labels to jump execution around).

3: If the line starts with //, delete the line (ECMAScript Comment).

4: If the line starts with {, delete everything up until the closing } (this may need to span multiple lines).

5: If the line starts with ;, delete the line (It’s a Tyranoscript comment).

6: if the line starts with [, we assume every pair of [ and ] is a command tag, First, we temporarily store an array of each text entry that exists outside of any command tags in the line. Then, we discard the original line, and insert each of the found text entries as a new separate line. (The idea is that we don’t lose any of the important narrative/dialogue text and keep those on separate lines so they’ll be easy to translate/inject later without risk of touching the commands.)

7: Once we’ve gone through the entire file, we save the file as “all-chapter-texts-no-metadata.txt”
8: make a translation table for every line in _that_ file, with column 0 being the source line, column 1 being the translated line.
9: use that translation table to run a find and replace on every text from that file. It may be best to run it against one file at a time and ensure the game still runs after updating the one file. That way if something gets replaced that shouldn’t be, it’ll be easier to catch. And if we kept a safe backup copy of the extracted files, we can use a diff-tool to check for the offending unintended changes.

okay I’m gonna go eat stuff and play game now bye ^O^