Skip to content

Commit

Permalink
7.0.0 changes (#182)
Browse files Browse the repository at this point in the history
- Fixes patterns for v7.0.0
- Fixes database lookups for NPC + monster names
  • Loading branch information
jmctune authored Mar 21, 2024
1 parent cc2ed84 commit a5ab3b1
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 43 deletions.
23 changes: 16 additions & 7 deletions app/clarity.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,33 +177,42 @@ def scan_for_npc_names():
"""Scan to look for NPC names, monster names and names above your party
member's heads and translates them into English."""
writer = MemWriter()
m00_strings = generate_m00_dict(files="'monsters', 'npcs', 'custom_npc_names', 'custom_player_names'")
monsters = generate_m00_dict(files="'monsters'")
npcs = generate_m00_dict(files="'npcs', 'custom_npc_names', 'custom_player_names'")

if npc_list := writer.pattern_scan(pattern=npc_monster_pattern, return_multiple=True):
for address in npc_list:
npc_type = writer.read_bytes(address + 36, 2)
if npc_type == b"\x74\x0A":
if npc_type == b"\x90\xF0":
data = "NPC"
elif npc_type == b"\x00\xF8":
elif npc_type == b"\x48\xDE":
data = "MONSTER"
elif npc_type == b"\x6C\xFA":
elif npc_type == b"\xBC\xE0":
data = "AI_NAME"
else:
continue

name_addr = address + 48 # jump to name
name = writer.read_string(name_addr)

if data == "NPC" or data == "MONSTER":
if value := m00_strings.get(name):
if data == "NPC":
if value := npcs.get(name):
try:
reread = writer.read_string(name_addr)
if reread == name:
writer.write_string(name_addr, value)
except Exception as e:
log.debug(f"Failed to write {data}. {e}")
elif data == "MONSTER":
if value := monsters.get(name):
try:
reread = writer.read_string(name_addr)
if reread == name:
writer.write_string(name_addr, value)
except Exception as e:
log.debug(f"Failed to write {data}. {e}")
elif data == "AI_NAME":
en_name = m00_strings.get(name)
en_name = npcs.get(name)
if not en_name:
en_name = convert_into_eng(name)
if en_name != name:
Expand Down
22 changes: 22 additions & 0 deletions app/common/db_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,28 @@ def sync_existing_tables():
conn.close()


def fix_m00_tables_schema():
"""Drops the primary key (if exists) for the m00_strings table."""
table = "m00_strings"

try:
conn, cursor = init_db()
query = f'SELECT l.name FROM pragma_table_info("{table}") as l WHERE l.pk <> 0'
cursor.execute(query)
results = cursor.fetchall()
for result in results:
if result[0] == "ja":
drop_m00_table = f"DROP TABLE IF EXISTS m00_strings"
drop_m00_index = f"DROP INDEX IF EXISTS m00_strings.m00_strings_index"
cursor.execute(drop_m00_table)
cursor.execute(drop_m00_index)
conn.commit()
except sqlite3.Error as e:
log.exception(f"Failed to drop existing column. {e}")
finally:
conn.close()


def db_query(query: str):
"""Executes a freeform query against the database.
Expand Down
7 changes: 3 additions & 4 deletions app/common/db_scripts/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,9 @@ CREATE TABLE IF NOT EXISTS "walkthrough" (
);

CREATE TABLE IF NOT EXISTS "m00_strings" (
"ja" TEXT NOT NULL UNIQUE,
"ja" TEXT NOT NULL,
"en" TEXT,
"file" TEXT,
PRIMARY KEY("ja")
"file" TEXT
);

CREATE TABLE IF NOT EXISTS "glossary" (
Expand All @@ -74,7 +73,7 @@ CREATE UNIQUE INDEX IF NOT EXISTS "walkthrough_index" ON "walkthrough" (
"ja"
);

CREATE UNIQUE INDEX IF NOT EXISTS "m00_strings_index" ON "m00_strings" (
CREATE INDEX IF NOT EXISTS "m00_strings_index" ON "m00_strings" (
"ja"
);

Expand Down
61 changes: 31 additions & 30 deletions app/common/signatures.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,23 +100,23 @@
network_text_trigger = rb"\x8D\x71\x01\x8B\xFF\x8A\x01\x41\x84\xC0\x75\xF9\x2B\xCE\x51\x51"

# player and sibling names on login. use this to figure out what the player is logged in as
# 55 8B EC 56 8B F1 57 8B 46 58 85 C0
# >> DQXGame.exe.text+4096C0 - 55 - push ebp
# DQXGame.exe.text+4096C1 - 8B EC - mov ebp,esp
# DQXGame.exe.text+4096C3 - 56 - push esi
# DQXGame.exe.text+4096C4 - 8B F1 - mov esi,ecx
# DQXGame.exe.text+4096C6 - 57 - push edi
# DQXGame.exe.text+4096C7 - 8B 46 58 - mov eax,[esi+58]
# DQXGame.exe.text+4096CA - 85 C0 - test eax,eax
# DQXGame.exe.text+4096CC - 74 10 - je DQXGame.exe.text+4096DE
# DQXGame.exe.text+4096CE - 50 - push eax
# DQXGame.exe.text+4096CF - E8 EC38C3FF - call DQXGame.exe.text+3CFC0
# DQXGame.exe.text+4096D4 - 83 C4 04 - add esp,04
# DQXGame.exe.text+4096D7 - C7 46 58 00000000 - mov [esi+58],00000000
# DQXGame.exe.text+4096DE - 6A 02 - push 02
# DQXGame.exe.text+4096E0 - 68 B0000000 - push 000000B0
# DQXGame.exe.text+4096E5 - E8 365FC3FF - call DQXGame.exe.text+3F620
player_sibling_name_trigger = rb"\x55\x8B\xEC\x56\x8B\xF1\x57\x8B\x46\x58\x85\xC0"
# 55 8B EC 56 8B F1 57 8B 46 60 85 C0
# DQXGame.exe.text+421150 - 55 - push ebp
# DQXGame.exe.text+421151 - 8B EC - mov ebp,esp
# DQXGame.exe.text+421153 - 56 - push esi
# DQXGame.exe.text+421154 - 8B F1 - mov esi,ecx
# DQXGame.exe.text+421156 - 57 - push edi
# DQXGame.exe.text+421157 - 8B 46 60 - mov eax,[esi+60]
# DQXGame.exe.text+42115A - 85 C0 - test eax,eax
# DQXGame.exe.text+42115C - 74 10 - je DQXGame.exe.text+42116E
# DQXGame.exe.text+42115E - 50 - push eax
# DQXGame.exe.text+42115F - E8 CCC1C1FF - call DQXGame.exe.text+3D330
# DQXGame.exe.text+421164 - 83 C4 04 - add esp,04
# DQXGame.exe.text+421167 - C7 46 60 00000000 - mov [esi+60],00000000
# DQXGame.exe.text+42116E - 6A 02 - push 02
# DQXGame.exe.text+421170 - 68 B0000000 - push 000000B0
# DQXGame.exe.text+421175 - E8 C6C1C1FF - call DQXGame.exe.text+3D340
player_sibling_name_trigger = rb"\x55\x8B\xEC\x56\x8B\xF1\x57\x8B\x46\x60\x85\xC0"

# party member data hits this code. used to detour and overwrite name.
# how it was found:
Expand Down Expand Up @@ -159,6 +159,7 @@
# DQXGame.exe.text+601030 - 0F84 A1010000 - je DQXGame.exe.text+6011D7
# >> DQXGame.exe.text+601036 - 8B D0 - mov edx,eax
# DQXGame.exe.text+601038 - 8D 7A 01 - lea edi,[edx+01]
# 8B D0 8D 7A 01 EB 03 8D 49 00 8A 0A 42 84 C9 75 F9 2B D7 0F 84 ?? ?? ?? ?? 51
corner_text_trigger = rb"\x8B\xD0\x8D\x7A\x01\xEB\x03\x8D\x49\x00\x8A\x0A\x42\x84\xC9\x75\xF9\x2B\xD7\x0F\x84....\x51"

#############################################
Expand All @@ -175,18 +176,18 @@
# - Monster names appearing in the battle menu
# - Party nameplates (don't confuse with party names on the right side of the screen)
# - Does not do the player's nameplate
# npc: B4 27 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 74 0A ?? ?? ?? ?? ?? ?? B0 0A ?? ?? E?
# monster: B4 27 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 00 F8 ?? ?? ?? ?? ?? ?? B0 0A ?? ?? E?
# party: B4 27 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 6C FA ?? ?? ?? ?? ?? ?? B0 0A ?? ?? E?
npc_monster_pattern = rb"\xB4\x27..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00.......\x00\x00\x00\x00.\x00\x00\x00[\x74\x00\x6C][\x0A\xF8\xFA]......\xB0\x0A..[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]"
# npc: 0C 8A ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 90 F0 ?? ?? ?? ?? ?? ?? CC F0 ?? ?? E?
# monster: 0C 8A ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 48 DE ?? ?? ?? ?? ?? ?? CC F0 ?? ?? E?
# party: 0C 8A ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 ?? 00 00 00 BC E0 ?? ?? ?? ?? ?? ?? CC F0 ?? ?? E?
npc_monster_pattern = rb"\x0C\x8A..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00.......\x00\x00\x00\x00.\x00\x00\x00[\x90\x48\xBC][\xF0\xDE\xE0]..........[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]"

# pattern for concierge names (13 bytes)
# 50 F0 ?? ?? ?? ?? ?? ?? B0 0A ?? ?? E?
concierge_name_pattern = rb"\x50\xF0......\xB0\x0A..[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]"
# 2C D7 ?? ?? ?? ?? ?? ?? CC F0 ?? ?? E?
concierge_name_pattern = rb"\x2C\xD7......\xCC\xF0..[\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEF]"

# pattern for player names to rename. (49 bytes)
# B4 27 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 48 7A ?? 0? ?? ?? ?? ?? ?? ?? ?? 0? E?
player_name_pattern = rb"\xB4\x27..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\x7A.[\x01\x02].......[\x01\x02][\xE3\xEF]"
# 0C 8A ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 48 C6 ?? 0? ?? ?? ?? ?? ?? ?? ?? 0? E?
player_name_pattern = rb"\x0C\x8A..\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00....\x00...\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x48\xC6.[\x01\x02].......[\x01\x02][\xE3\xEF]"
# pattern for sibling names to rename. (52 bytes)
# 0? ?? 00 ?? 00 00 00 ?? ?? 00 02 ?? 00 ?? 00 ?? 00 00 00 00 00 ?? 00 ?? ?? 00 00 ?? ?? ?? 00 ?? 00 ?? ?? ?? 00 ?? 00 ?? ?? 00 00 00 00 ?? ?? 00 00 00 00 E?
sibling_name_pattern = rb"[\x01\x02].\x00.\x00\x00\x00..\x00\x02.\x00.\x00.\x00\x00\x00\x00\x00.\x00..\x00\x00...\x00.\x00...\x00.\x00..\x00\x00\x00\x00..\x00\x00\x00\x00[\xE3\xEF]"
Expand All @@ -203,13 +204,13 @@

# Main walkthrough text that loads on login. I can't figure out what function loads this on login,
# so scanning for this for now. AC is also preventing this from just being accessible via hooks. (17 bytes)
# 90 ?? ?? ?? 00 00 00 00 04 02 00 00 10 00 00 00 E?
walkthrough_pattern = rb"\x90...\x00\x00\x00\x00\x04\x02\x00\x00\x10\x00\x00\x00[\xE3\xE4\xE5\xE6\xE7\xE8\xE9]"
# 30 ?? ?? ?? 00 00 00 00 04 02 00 00 10 00 00 00 E?
walkthrough_pattern = rb"\x30...\x00\x00\x00\x00\x04\x02\x00\x00\x10\x00\x00\x00[\xE3\xE4\xE5\xE6\xE7\xE8\xE9]"

# player name in cutscenes. not used at the moment, but holding onto it for now.
# EF ?? 01 ?? ?? ?? ?? 3C EF ?? 01
player_name_cutscenes = rb"\xEF.\x01....\x3C\xEF.\x01"

# "『ドラゴンクエストX" found in notice box on login. Bytes are just the words encoded into utf-8
# E3 80 8E E3 83 89 E3 83 A9 E3 82 B4 E3 83 B3 E3 82 AF E3 82 A8 E3 82 B9 E3 83 88 58
notice_string = rb"\xE3\x80\x8E\xE3\x83\x89\xE3\x83\xA9\xE3\x82\xB4\xE3\x83\xB3\xE3\x82\xAF\xE3\x82\xA8\xE3\x82\xB9\xE3\x83\x88\x58"
# "動画・生配信・画像投稿" found in notice box on login. Bytes are just the words encoded into utf-8
# E5 8B 95 E7 94 BB E3 83 BB E7 94 9F E9 85 8D E4 BF A1 E3 83 BB E7 94 BB E5 83 8F E6 8A 95 E7 A8 BF
notice_string = rb"\xE5\x8B\x95\xE7\x94\xBB\xE3\x83\xBB\xE7\x94\x9F\xE9\x85\x8D\xE4\xBF\xA1\xE3\x83\xBB\xE7\x94\xBB\xE5\x83\x8F\xE6\x8A\x95\xE7\xA8\xBF"
2 changes: 1 addition & 1 deletion app/common/update.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def read_custom_json_and_import(name: str, data: str):
query_list.append(query_value)

insert_values = ','.join(query_list)
query = f"INSERT OR REPLACE INTO m00_strings (ja, en, file) VALUES {insert_values};"
query = f"INSERT INTO m00_strings (ja, en, file) VALUES {insert_values};"
db_query(query)


Expand Down
7 changes: 6 additions & 1 deletion app/main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from clarity import loop_scan_for_walkthrough, run_scans
from common.db_ops import create_db_schema, sync_existing_tables
from common.db_ops import (
create_db_schema,
fix_m00_tables_schema,
sync_existing_tables,
)
from common.lib import get_project_root, setup_logging
from common.process import wait_for_dqx_to_launch
from common.translate import determine_translation_service
Expand Down Expand Up @@ -53,6 +57,7 @@ def blast_off(
log.info("Getting started. DO NOT TOUCH THE GAME OR REMOVE YOUR MEMORY CARD.",)

log.info("Ensuring db structure.")
fix_m00_tables_schema()
create_db_schema()
sync_existing_tables()

Expand Down

0 comments on commit a5ab3b1

Please sign in to comment.