From 69986dcd68e27f768176767612434381bb57276b Mon Sep 17 00:00:00 2001 From: Musi57 <254671545+Musi57@users.noreply.github.com> Date: Sun, 18 Jan 2026 16:33:58 +0100 Subject: [PATCH 1/2] add the house in fata morgana --- PC_Steam_The_House_in_Fata_Morgana.js | 78 +++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 PC_Steam_The_House_in_Fata_Morgana.js diff --git a/PC_Steam_The_House_in_Fata_Morgana.js b/PC_Steam_The_House_in_Fata_Morgana.js new file mode 100644 index 0000000..fca0183 --- /dev/null +++ b/PC_Steam_The_House_in_Fata_Morgana.js @@ -0,0 +1,78 @@ +// ==UserScript== +// @name The House in Fata Morgana +// @version 1.0.0.0 +// @author Musi +// @description Steam +// * NOVECT +// +// https://store.steampowered.com/app/303310/The_House_in_Fata_Morgana/ +// ==/UserScript== + +const __e = Process.enumerateModules()[0]; +console.warn('[Known Issue] Some inner dialogue is picked up even when not displayed in game. Recommend ignoring this for spoiler reasons.'); + +(function () { + const mainHandler = trans.send(handler, '250+'); + attach('DialogueHook', 'E8 33 DC E1 FF', 'edx'); + + let lastText = ''; + let sentenceBuffer = ''; + + function handler(text) { + return text; + } + + function cleanText(text) { + return text + .replace(/\[.*?\]/g, '') // remove [tags] + .replace(/@.*$/gm, '') // remove @ commands + .trim(); + } + + function endsWithPunctuation(text) { + return /[。!?…・]$/.test(text); + } + + function attach(name, pattern, register) { + const results = Memory.scanSync(__e.base, __e.size, pattern); + if (results.length === 0) { + console.error(`[${name}] Hook not found!`); + return; + } + const address = results[0].address; + console.log(`[${name}] Found hook at ${address}`); + Interceptor.attach(address, function (args) { + try { + const basePtr = this.context[register]; + + // const text = basePtr.readPointer().readUtf16String(); + const text = this.context[register].readUtf16String(); + + if (text && text.length > 0) { + const cleaned = cleanText(text); + + // only output japanese characters and no duplicates + if (cleaned.length > 0 && + /[\u3040-\u30FF\u4E00-\u9FAF]/.test(cleaned) && + cleaned !== lastText) { + + lastText = cleaned; + + if (sentenceBuffer.length > 0) { + sentenceBuffer += cleaned; + } else { + sentenceBuffer = cleaned; + } + + if (endsWithPunctuation(cleaned)) { + mainHandler('\n' + sentenceBuffer + '\n'); + sentenceBuffer = ''; + } + } + } + } catch (e) { + // silence errors for null pointers + } + }); + } +})(); \ No newline at end of file From 1506d1354cdf4caa41e2af73b946a893cb03be31 Mon Sep 17 00:00:00 2001 From: Musi57 <254671545+Musi57@users.noreply.github.com> Date: Mon, 19 Jan 2026 09:20:30 +0100 Subject: [PATCH 2/2] replace try-catch with explicit null checks and extract japanese text detection into named function --- PC_Steam_The_House_in_Fata_Morgana.js | 161 +++++++++++++------------- 1 file changed, 83 insertions(+), 78 deletions(-) diff --git a/PC_Steam_The_House_in_Fata_Morgana.js b/PC_Steam_The_House_in_Fata_Morgana.js index fca0183..fc3ee65 100644 --- a/PC_Steam_The_House_in_Fata_Morgana.js +++ b/PC_Steam_The_House_in_Fata_Morgana.js @@ -1,78 +1,83 @@ -// ==UserScript== -// @name The House in Fata Morgana -// @version 1.0.0.0 -// @author Musi -// @description Steam -// * NOVECT -// -// https://store.steampowered.com/app/303310/The_House_in_Fata_Morgana/ -// ==/UserScript== - -const __e = Process.enumerateModules()[0]; -console.warn('[Known Issue] Some inner dialogue is picked up even when not displayed in game. Recommend ignoring this for spoiler reasons.'); - -(function () { - const mainHandler = trans.send(handler, '250+'); - attach('DialogueHook', 'E8 33 DC E1 FF', 'edx'); - - let lastText = ''; - let sentenceBuffer = ''; - - function handler(text) { - return text; - } - - function cleanText(text) { - return text - .replace(/\[.*?\]/g, '') // remove [tags] - .replace(/@.*$/gm, '') // remove @ commands - .trim(); - } - - function endsWithPunctuation(text) { - return /[。!?…・]$/.test(text); - } - - function attach(name, pattern, register) { - const results = Memory.scanSync(__e.base, __e.size, pattern); - if (results.length === 0) { - console.error(`[${name}] Hook not found!`); - return; - } - const address = results[0].address; - console.log(`[${name}] Found hook at ${address}`); - Interceptor.attach(address, function (args) { - try { - const basePtr = this.context[register]; - - // const text = basePtr.readPointer().readUtf16String(); - const text = this.context[register].readUtf16String(); - - if (text && text.length > 0) { - const cleaned = cleanText(text); - - // only output japanese characters and no duplicates - if (cleaned.length > 0 && - /[\u3040-\u30FF\u4E00-\u9FAF]/.test(cleaned) && - cleaned !== lastText) { - - lastText = cleaned; - - if (sentenceBuffer.length > 0) { - sentenceBuffer += cleaned; - } else { - sentenceBuffer = cleaned; - } - - if (endsWithPunctuation(cleaned)) { - mainHandler('\n' + sentenceBuffer + '\n'); - sentenceBuffer = ''; - } - } - } - } catch (e) { - // silence errors for null pointers - } - }); - } -})(); \ No newline at end of file +// ==UserScript== +// @name The House in Fata Morgana +// @version 1.0.0.0 +// @author Musi +// @description Steam +// * NOVECT +// +// https://store.steampowered.com/app/303310/The_House_in_Fata_Morgana/ +// ==/UserScript== + +const __e = Process.enumerateModules()[0]; +console.warn('[Known Issue] Some inner dialogue is picked up even when not displayed in game. Recommend ignoring this for spoiler reasons.'); +(function () { + const mainHandler = trans.send(handler, '250+'); + attach('DialogueHook', 'E8 33 DC E1 FF', 'edx'); + + let lastText = ''; + let sentenceBuffer = ''; + + function handler(text) { + return text; + } + + function cleanText(text) { + return text + .replace(/\[.*?\]/g, '') // remove [tags] + .replace(/@.*$/gm, '') // remove @ commands + .trim(); + } + + function endsWithPunctuation(text) { + // check if text ends with punctuation + return /[。!?…・]$/.test(text); + } + + function hasJapaneseText(text) { + // check if text contains Japanese characters + return /[\u3040-\u30FF\u4E00-\u9FAF]/.test(text); + } + + function attach(name, pattern, register) { + const results = Memory.scanSync(__e.base, __e.size, pattern); + if (results.length === 0) { + console.error(`[${name}] Hook not found!`); + return; + } + const address = results[0].address; + console.log(`[${name}] Found hook at ${address}`); + Interceptor.attach(address, function (args) { + const basePtr = this.context[register]; + + // early return if pointer is null + if (!basePtr || basePtr.isNull()) { + return; + } + + const text = this.context[register].readUtf16String(); + + // early return if no text + if (!text || text.length === 0) { + return; + } + + const cleaned = cleanText(text); + + // only output japanese characters and no duplicates + if (cleaned.length > 0 && hasJapaneseText(cleaned) && cleaned !== lastText) { + lastText = cleaned; + + if (sentenceBuffer.length > 0) { + sentenceBuffer += cleaned; + } else { + sentenceBuffer = cleaned; + } + + if (endsWithPunctuation(cleaned)) { + mainHandler('\n' + sentenceBuffer + '\n'); + sentenceBuffer = ''; + } + } + }); + } +})();