Skip to content

Instantly share code, notes, and snippets.

@H0neyBadger
Last active November 22, 2022 12:20
Show Gist options
  • Save H0neyBadger/26b616f04e8fa6b6836bac5f68d5b8fd to your computer and use it in GitHub Desktop.
Save H0neyBadger/26b616f04e8fa6b6836bac5f68d5b8fd to your computer and use it in GitHub Desktop.
cheats & notes for Pokemon Brilliant Diamond & Shining Pearl

Notes:

# search: prod.keys titlekek_0c
hactool -t pfs0 --pfs0dir=pfs0 ./0100000011D90000.nsp
hactool --exefsdir=exefsdir ./pfs0/69ab3424f037989d254df83040f4a02c.nca
hactool --romfsdir=romfs ./pfs0/69ab3424f037989d254df83040f4a02c.nca
# 1.1.1
hactool -t pfs0 --pfs0dir=pfs01.1.1 ./0100000011D90800.nsp
hexdump -C -s 384  ./pfs01.1.1/0100000011d90800000000000000000d.tik # title key
hactool --titlekey='***************' --exefsdir=exefsdir1.1.1 ./pfs01.1.1/d54c71db6f5283f385b5d05cb3971717.nca \
	--baseromfs=./pfs0/69ab3424f037989d254df83040f4a02c.nca
hactool --titlekey='***************' --romfsdir=romfs1.1.1 ./pfs01.1.1/d54c71db6f5283f385b5d05cb3971717.nca \
	--baseromfs=./pfs0/69ab3424f037989d254df83040f4a02c.nca
# rpm-ostree install dotnet-sdk-5.0 winehq-staging
wine Il2CppDumper.exe ./exefsdir/main ./romfs/Data/Managed/Metadata/global-metadata.dat ./Il2CppDumper
UABEAvalonia batchexport ./batch_pkm
+DIR ./romfs/Data/StreamingAssets/AssetAssistant/Pml/
+DIR ./romfs/Data/StreamingAssets/AssetAssistant/Dpr/
from keystone import Ks, KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN
from noexs import NoexesClient
# v 1.0.0
cheats = {
# 0x23b6ac4: 0xEB08011F, # shiny
# 0x23b6ad0: 0xEB08011F,
0x23b6ac4: "cmp x8,x8", # shiny
0x23b6ad0: "cmp x8,x8",
# randomizer ?
# 0x26a3fc0: "b #0x18",
# 0x26a3fd8: """
# strh w20,[x0]
# b #-0x14
# """,
# ; add w20, w20, #0x1
# 0x26a3fc0: """
# add w20, w20, #0xf
# strh w20,[x0]
# mov x0,x19
# ldp x29, x30, [sp, #0x20]
# ldp x20, x19, [sp, #0x10]
# ldr x21, [sp], #0x30
# b #-0x48A0
# """,
0x23b7508: 0x52800042, # hidden ability
0x23b74d0: 0x528003E0, # 31 iv SetTalentAgi
0x23b74b0: 0x528003E0, # 31 iv SetTalentSpDef
0x23b7490: 0x528003E0, # 31 iv SetTalentSpAtk
0x23b7470: 0x528003E0, # 31 iv SetTalentDef
0x23b7450: 0x528003E0, # 31 iv SetTalentAtk
0x23b7430: 0x528003E0, # 31 iv SetTalentHp
0x2384c44: 0x52800000, # GetCompetitor
0x2384d38: 0x52800000, # NeedReduleHighLev
0x2101804: 0xD65F03C0, # Dpr.Item.ItemInfo$$SubItem
0x210df84: 0x1F2003D5, # PlayerWork$$SetMoney
# 0x23b6984: "mov w8, 1", # set pokemon #1 *(undefined4 *)(param_1 + 0x38) = *(undefined4 *)(param_2 + 0x38);
}
def main():
ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)
client = NoexesClient("192.168.0.200")
count, pids = client.get_pids()
for pid in pids:
rc, tid = client.get_title_id(pid)
if tid == 72057594337361920:
print("process found", pid, tid)
client.attach(pid)
break
else:
print("process not found")
exit(1)
_, mem = client.query(0)
base_addr = mem["main"][0]["addr"]
client.pause()
for addr, value in cheats.items():
if isinstance(value, str):
print(value)
encoded, _ = ks.asm(value)
length = len(encoded)
print(encoded, length)
while length > 0:
length -= 4
chunk = bytes(encoded[length:length+4])
print(chunk, addr + base_addr + length)
client.poke32(
addr + base_addr + length,
chunk
)
continue
client.poke32(
addr + base_addr,
value
)
client.resume()
if __name__ == '__main__':
main()
[Pml.PokePara.CoreParam$$SetRare] KO
360000A0940BED02 -> 71023ad938 02ed0b94 bl Pml.PokePara.CalcTool$$IsRareColor -> 52800000 (mov w0, 0)
[FieldManager$$ResultSetUpWildBattle] OK
# SetRare
F94002E0340000E8(2nd) -> 7101ce5270 e8000034 cbz w8,LAB_7101ce528c -> 1F2003D5 (nop)
# SetTokusei3rd
F94002E0340000E8(2nd) -> 7101ce5290 e8000034 cbz w8,LAB_7101ce52ac -> 1F2003D5 (nop)
[Dpr.Field.FieldEncount$$SetEncountData]
5280002036000220 -> 7101e84fbc 20008052 mov w0,#0x1 -> 52800000 (mov w0, 0)
[CollisionUtility$$IsCollideObstacle]
97E95573AA1F03E2 -> 7102068e5c 00000012 and w0,w0,#0x1 -> 52800000 (mov w0, 0)
[CollisionUtility$$IsOverrapSphere]
7100001F6D42A3E9 -> 7102068f8c 1f000071 cmp w0,#0x0 -> 6B00001F (cmp w0,w0)
7102068f94 e0079f1a cset w0,ne -> 52800020 (mov w0, 1)
[CollisionUtility$$IsCollideGround]
6D4623E997E9519C -> 7102069358 00000012 and w0,w0,#0x1 -> 52800000 (mov w0, 0)
[CollisionUtility$$IsOverCollideGround]
97E950FDAA1F03E2 -> 71020695d4 00000012 and w0,w0,#0x1 -> 52800000 (mov w0, 0)
[FieldPlayerEntity$$CheckGridCollisionCore] OK
2A2003E894000052 -> 71021694fc e803202a mvn w8,w0 -> 52800028 (mov w8,1)
[FieldPlayerEntity.CheckGridCollisionFunc$$Check]
2A2003E897FFE050 -> 7102171504 e803202a (mvn w8,w0) -> 52800028 (mov w8,1)
[FieldPlayerEntity.CheckGridCollisionFunc$$Check v2]
360001C09418C18C -> 71021714e0 8cc11894 bl .... -> 52800000 (mov w0, 0)
[EnterCollision$$IsInCircle]
97DC6F314EA11C20 -> 7101fefc34 316fdc97 bl sqrtf -> 94000000 (bl 0)
[EnterCollision$$IsInCircle v2]
BD402E6A392F7688 ->
7101fefbbc 6a 2e 40 bd ldr s10,[x19, #0x2c]
7101fefbc0 e1 03 1f aa mov x1,xzr
mov w0, 0
ret
52800000
D65F03C0
[FieldPlayerEntity$$CheckColIceFloor]
710216bc50 ac 02 00 94 bl FieldPlayerEntity$$CheckColNpcIceFloor
710216bc54 e0 01 00 36 tbz w0,#0x0,LAB_710216bc90
01AEDDD8
AA1F03E294177AEA
[Pml.PokePara.Accessor$$SetTokuseiNo]
71023b7508 e203172a mov w2,w23 -> 52800042 (mov w2, #0x2)
[Pml.PokePara.CoreParam$$FlipTokuseiIndex]
71023abc6c e1031f2a mov w1,wzr -> 52800040 (mov w1, #0x2)
71023abc7c 21008052 mov w1,#0x1 -> 52800040 (mov w1, #0x2)
[shiny]
71023b6ac4 1f0109eb cmp x8,x9 -> EB08011F (cmp x8,x8)
71023b6ad0 1f0109eb cmp x8,x9 -> EB08011F (cmp x8,x8)
71023b6aa4 681640f9 ldr x8,[x19, #0x28] -> 92DFFFA8 (mov x8,#-0xfffd00000001) NOK
[SmartPoint.Rendering.DepthOfField$$set_blurry]
7102417bdc 085c40f9 ldr x8,[x0, #0xb8] -> D65F03C0 (ret)
[Dpr.SealPreview.SealPreviewViewSystem$$set_blurry]
710203b1e0 006001bd str s0,[x0, #0x160] -> D65F03C0 (ret)
[Dpr.Battle.View.Systems.BattleViewSystem$$set_blurry]
7102025e90 00c001bd str s0,[x0, #0x1c0] -> D65F03C0 (ret)
[Dpr.UI.UIManager$$SetActiveFadeBlur]
7101d72df0 61020012 and w1,w19,#0x1 -> 52800001 (mov w1,#0x0)
[Dpr.Rendering.RadialBlur$$UpdateShaderProperties]
7102033a88 c0000036 tbz w0,#0x0,LAB_7102033aa0 -> 1F2003D5 (nop)
[Dpr.Battle.Logic.Section_UseItem_Core$$useBallForbidden]
7102385734 3f150071 cmp w9,#0x5 -> 6B09013F (cmp w9,w9)
[Dpr.Battle.Logic.Handler.Item$$Remove]
7102271a58 22b3ec97 bl Dpr.Battle.Logic.Handler.Item$$Remove -> 1F2003D5 (nop)
7102260af0 fcf6ec17 b Dpr.Battle.Logic.Handler.Item$$Remove -> D65F03C0 (ret)
[Dpr.Battle.Logic.Section_FromEvent_ConsumeItem]
710207753c 395b0814 b Dpr.Battle.Logic.Section_FromEvent_ConsumeItem -> D65F03C0 (ret)
[Dpr.Battle.Logic.Section_FromEvent_ConsumeItem]
710228e290 20000094 bl Dpr.Battle.Logic.Section_FromEvent_ConsumeItem -> 1F2003D5 (nop)
710228e29c 01270494 bl Dpr.Battle.Logic.MainModule$$IsPokeItemConsume -> 52800000 (mov w0, 0)
[Dpr.Battle.Logic.Section_UseItem_Core$$useBall]
7102384c44 bb160194 bl Dpr.Battle.Logic.Section$$GetCompetitor -> 52800000 (mov w0, 0)
7102384d38 164c0094 blDpr.Battle.Logic.MainModule$$NeedReduleHighLev -> 52800000 (mov w0, 0)
7102384e1c 71b0fb97 bl Dpr.Battle.Logic.ServerCommandPutter$$Act_Ball -> 52800000 (mov w0, 0)
7102383720 b9ec0736 tbz w25,#0x0,LAB_71023834b4 -> 17FFFF65 (b #0xfffffffffffffd94)
[Dpr.Battle.Logic.Section_UseItem$$Execute]
7102382d60 845b0094 bl Dpr.Battle.Logic.MainModule$$DecrementPlayerItem -> 1F2003D5 (nop)
[Dpr.Item.ItemInfo$$SubItem]
7102101804 7bf50214 b Dpr.Item.ItemInfo$$SubItem -> -> D65F03C0 (ret)
[MoneyWork$$Sub]
710210df84 2bb1ea97 bl PlayerWork$$SetMoney -> 1F2003D5 (nop)
import socket
import struct
from enum import Enum
# https://github.com/mdbell/Noexes/blob/d425045e08a6b9f973aff74bacaf49a7fc3eb49f/client/src/me/mdbell/noexs/core/Debugger.java
COMMAND_STATUS = 0x01
COMMAND_POKE8 = 0x02
COMMAND_POKE16 = 0x03
COMMAND_POKE32 = 0x04
COMMAND_POKE64 = 0x05
COMMAND_READ = 0x06
COMMAND_WRITE = 0x07
COMMAND_CONTINUE = 0x08
COMMAND_PAUSE = 0x09
COMMAND_ATTACH = 0x0A
COMMAND_DETATCH = 0x0B
COMMAND_QUERY_MEMORY = 0x0C
COMMAND_QUERY_MEMORY_MULTI = 0x0D
COMMAND_CURRENT_PID = 0x0E
COMMAND_GET_ATTACHED_PID = 0x0F
COMMAND_GET_PIDS = 0x10
COMMAND_GET_TITLEID = 0x11
COMMAND_DISCONNECT = 0x12
COMMAND_READ_MULTI = 0x13
COMMAND_SET_BREAKPOINT = 0x14
class MemoryType(Enum):
UNMAPPED = 0
IO = 0x01
NORMAL = 0x02
CODE_STATIC = 0x03
CODE_MUTABLE = 0x04
HEAP = 0x05
SHARED = 0x06
WEIRD_MAPPED = 0x07
MODULE_CODE_STATIC = 0x08
MODULE_CODE_MUTABLE = 0x09
IPC_BUFFER_0 = 0x0A
MAPPED = 0xB
THREAD_LOCAL = 0x0C
ISOLATED_TRANSFER = 0x0D
TRANSFER = 0x0E
PROCESS = 0x0F
RESERVED = 0x10
IPC_BUFFER_1 = 0x11
IPB_BUFFER_3 = 0x12
KERNEL_STACH = 0x13
CODE_READ_ONLY = 0x14
CODE_WRITABLE = 0x15
class NoexesClient:
def __init__(self, server):
self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.conn.connect((server, 7331))
def __del__(self):
print("Bye")
self._send_command(COMMAND_DETATCH)
self._send_command(COMMAND_DISCONNECT)
self.conn.close()
def _send_command(self, cmd, *args):
raw_cmd = cmd.to_bytes(1, "little")
for arg in args:
raw_cmd += arg
# print("send: ", raw_cmd)
self.conn.sendall(raw_cmd)
def _recv(self, fmt="<i"):
size = struct.calcsize(fmt)
data = b""
while len(data) < size:
data += self.conn.recv(size - len(data))
# print("recieve: ", data, len(data))
return struct.unpack(fmt, data)
def get_pids(self):
self._send_command(COMMAND_GET_PIDS)
count = self._recv()[0]
data = []
while len(data) < count:
pid = self._recv(fmt="<q")[0]
data.append(pid)
return count, data
def get_title_id(self, pid):
self._send_command(COMMAND_GET_TITLEID, pid.to_bytes(8, "little"))
rc = self._recv()[0]
tid = self._recv(fmt="<q")[0]
return rc, tid
def attach(self, pid):
self._send_command(COMMAND_ATTACH, pid.to_bytes(8, "little"))
rc = self._recv()
return rc[0]
def pause(self):
self._send_command(COMMAND_PAUSE)
rc = self._recv()
return rc[0]
def resume(self):
self._send_command(COMMAND_CONTINUE)
rc = self._recv()
return rc[0]
def query(self, start, count=10000):
self._send_command(
COMMAND_QUERY_MEMORY_MULTI,
start.to_bytes(8, "little"),
count.to_bytes(4, "little")
)
subsdk_idx = 0
modules = [
"rtld",
"main",
"sdk",
]
ret = []
mem_code = {}
rc = self._recv()
while count > 0:
count -= 1
addr, size, tp, perm, rc = self._recv(fmt="<qqiii")
mem_type = MemoryType(tp)
if mem_type == MemoryType.RESERVED:
break
data = {
"addr": addr,
"size": size,
"type": mem_type,
"perm": perm
}
if mem_type in [MemoryType.CODE_STATIC, MemoryType.CODE_MUTABLE]:
if mem_type == MemoryType.CODE_STATIC and perm == 0b101:
try:
mod = modules.pop(0)
except IndexError:
mod = f"subsdk{subsdk_idx}"
subsdk_idx += 1
mod_map = mem_code.setdefault(mod, [])
mod_map.append(data)
if mem_type == MemoryType.HEAP:
mod_map = mem_code.setdefault("heap", [])
mod_map.append(data)
ret.append(data)
return ret, mem_code
def poke32(self, addr, value):
if isinstance(value, int):
value = value.to_bytes(4, "little")
self._send_command(
COMMAND_POKE32,
addr.to_bytes(8, "little"),
value
)
rc = self._recv()
return rc[0]
import sys
from lz4.block import decompress
# https://switchbrew.org/wiki/NSO
def load_file(path) -> bytes:
with open(path, "rb") as nso:
return nso.read()
def mod0(data):
# 0x00 4 Reserved
_reserved = data[:0x4]
# 0x04 4 MagicOffset (always 8, so it works when MOD is at image_base + 0)
magic_offset = data[0x4 : 0x4 + 0x4]
# print(magic_offset, data[0:200])
# 0x08 4 Magic "MOD0"
assert data[0x8 : 0x8 + 0x4] == b"MOD0", data[0x8 : 0x8 + 0x4]
# 0x0C 4 .dynamic offset
dynamic_offset = data[0xC : 0xC + 0x4]
print(f".dynamic offset: {dynamic_offset.hex()}")
# 0x10 4 .bss start offset
bss_start_offset = data[0x10 : 0x10 + 0x4]
print(f".bss start offset: {bss_start_offset.hex()}")
# 0x14 4 .bss end offset
bss_end_offset = data[0x14 : 0x14 + 0x4]
print(f".bss end offset: {bss_end_offset.hex()}")
# 0x18 4 .eh_frame_hdr start offset
eh_frame_hdr_start = data[0x18 : 0x18 + 0x4]
print(f".eh_frame_hdr start offset: {eh_frame_hdr_start.hex()}")
# 0x1C 4 .eh_frame_hdr end offset
eh_frame_hdr_end = data[0x1C : 0x1C + 0x4]
print(f".eh_frame_hdr end offset: {eh_frame_hdr_end.hex()}")
# 0x20 4 Offset to runtime-generated module object (typically equal to .bss base)
offset_to_runtime_generated_module = data[0x20 : 0x20 + 0x4]
print(
f"Offset to runtime-generated module object: {offset_to_runtime_generated_module.hex()}"
)
def segment_header(data):
return (
int.from_bytes(data[:0x4], "little"), # file offset
int.from_bytes(data[0x4 : 0x4 + 0x4], "little"), # memory offset
int.from_bytes(data[0x8 : 0x8 + 0x4], "little"), # decompressed size
)
def segment_header_relative(data):
return (
int.from_bytes(data[:0x4], "little"), # .rodata offset
int.from_bytes(data[0x4 : 0x4 + 0x4], "little"), # size
)
def segment(nso, header, file_size, compressed):
foffset, moffset, dlength = segment_header(header)
fsize = int.from_bytes(file_size, "little")
data = nso[foffset : foffset + fsize]
if compressed:
data = decompress(data, uncompressed_size=dlength)
return data
def nso(path):
nso = load_file(path)
assert nso[0:0x4] == b"NSO0", nso[0:0x4]
version = nso[0x4]
_reserved = nso[0x8]
flags = nso[0xC]
text_segment_header = nso[0x10 : 0x10 + 0xC]
module_name_offset = nso[0x1C : 0x1C + 0x4]
rodata_segment_header = nso[0x20 : 0x20 + 0xC]
module_name_size = nso[0x2C : 0x2C + 0x4]
data_segment_header = nso[0x30 : 0x30 + 0xC]
bss_size = nso[0x3C : 0x3C + 0x4]
module_Id = nso[0x40 : 0x40 + 0x20]
text_file_size = nso[0x60 : 0x60 + 0x4]
ro_file_size = nso[0x64 : 0x64 + 0x4]
data_file_size = nso[0x68 : 0x68 + 0x4]
_reserved = nso[0x6C : 0x6C + 0x1C]
api_info_segment_header_relative = nso[0x88 : 0x88 + 0x8]
dynstr_segment_header_relative = nso[0x90 : 0x90 + 0x8]
dynsym_segment_header_relative = nso[0x98 : 0x98 + 0x8]
text_hash = nso[0xA0 : 0xA0 + 0x20]
ro_hash = nso[0xC0 : 0xC0 + 0x20]
data_hash = nso[0xE0 : 0xE0 + 0x20]
# _ = nso[0x100:]
# sections
is_text_compress = flags & 0x1
is_ro_compress = flags & 0x10
is_data_compress = flags & 0x100
check_text_hash = flags & 0x1000
check_ro_hash = flags & 0x10000
check_data_hash = flags & 0x100000
print("####### text ########")
text = segment(
nso, text_segment_header, text_file_size, compressed=is_text_compress
)
mod0(text)
# print("####### rodata ########")
# segment(nso, rodata_segment_header, ro_file_size, compressed=is_ro_compress)
# print("####### data ########")
# segment(nso, data_segment_header, data_file_size, compressed=is_data_compress)
if __name__ == "__main__":
if len(sys.argv) == 1:
print(f"Usage: {sys.argv[0]} ./nso1 ./nso2 ...")
exit(1)
for path in sys.argv[1:]:
print(f"Read file {path}")
nso(path)
keystone-engine
UnityPy
import os
import json
import struct
import UnityPy
current_dir = os.path.abspath(os.path.dirname(__file__))
romfs_dir = f"{current_dir}/romfs"
data = {
"XLSXContent_FieldEncountTable": {
"file_path": "Data/StreamingAssets/AssetAssistant/Dpr/scriptableobjects/gamesettings",
"path_id": -9035030829162387677,
},
"XLSXContent_TrainerTable": {
"file_path": "Data/StreamingAssets/AssetAssistant/Dpr/masterdatas",
"path_id": 676024375065692598,
},
"fld_item": {
"file_path": "Data/StreamingAssets/AssetAssistant/Dpr/ev_script",
"path_id": -4074276362271022109,
},
"hide_item": {
"file_path": "Data/StreamingAssets/AssetAssistant/Dpr/ev_script",
"path_id": 4463973245290848484,
},
"XLSXContent_EvolveTable": {
"file_path": "Data/StreamingAssets/AssetAssistant/Pml/personal_masterdatas",
"path_id": 5139195221601552760,
},
"XLSXContent_GrowTable": {},
"XLSXContent_ItemTable": {
"file_path": "Data/StreamingAssets/AssetAssistant/Pml/personal_masterdatas",
"path_id": 252928009371549925,
},
# "XLSXContent_ItemTable": {
# "file_path": "Data/StreamingAssets/AssetAssistant/Pml/personal_masterdatas",
# "path": "assets/pml/data/itemtable.asset",
# },
"XLSXContent_UgItemTable": {
"file_path": "Data/StreamingAssets/AssetAssistant/Pml/personal_masterdatas",
"path_id": -5431921521366313060,
},
"english": {
"file_path": "Data/StreamingAssets/AssetAssistant/Message",
"path_id": 8474889802433302621,
},
}
def read(table: str):
conf = data[table]
file_path = conf["file_path"]
if "path_id" in conf:
path_id = conf["path_id"]
env = UnityPy.load(f"{romfs_dir}/{file_path}")
obj = [obj for obj in env.objects if obj.path_id == path_id][0]
else:
path = conf["path"]
env = UnityPy.load(f"{romfs_dir}/{file_path}", path) # FIXME
obj = env.objects[0]
return obj.read_typetree()
def check_evolve(table):
for entry in table["Evolve"]:
if len(entry["ar"]) > 0:
# ar.0
# 1 = frienship
# 2 = High Friendship (Day)
# 3 = High Friendship (Night)
# 4 = Lvl
# 5 = traide
# 6 = traide + object
# 8 = stone
# 9 = Lvl + (Atk > Def)
# 10 = Lvl + (Atk = Def)
# 11 = Lvl + (Atk < Def)
# 12 = Random
# 13 = Random
# 14 = Pokeball and space in the party -> Shedinja
# 16 = High Beauty Condition
# 17 = Lvl + male
# 18 = Lvl + female
# 19 = Day + object
# 20 = night + object
# 21 = attack (ar.1)
# 22 = Lvl + Pokemon in party
# 23 = Lvl + male
# 24 = Lvl + female
# 25 = Mt. Coronet
# ar.1 object id or attack id or pokemon id ?
# ar.2 next id?monsno
# ar.3 form ?
# ar.4 level
assert not entry["ar"][0] in [18, 7, 15, 17, 26], f"condition {entry}"
if len(entry["ar"]) > 5:
assert not entry["ar"][5] in [18, 7, 15, 17, 26], f"condition {entry}"
assert len(entry["ar"]) <= 10, f"size {entry}"
def build_item_table(table, itemnames):
for script in table["Scripts"]:
print(script["Label"])
for cmd in script["Commands"]:
for arg in cmd["Arg"]:
if arg["argType"] == 1:
f_data = struct.unpack('!f', arg["data"].to_bytes(4, "big"))[0]
arg["data"] = f_data
job, args = cmd["Arg"][0]["data"], cmd["Arg"][1:]
if job in [41, 187, 194]:
idx = int(args[0]["data"])
itemname = itemnames[idx]
print("WTF", job, args[0], script["Label"], itemname)
return table
def build_evolve_table(table):
def is_lvl_evolve(cond):
return cond in [24, 23, 22, 18, 17, 11, 10, 9, 4]
default = {
"prevmons": 0,
"prevlvl": 0,
"condition": 0,
}
evolve_table = [default.copy() for x in range(0, 493)]
for entry in table["Evolve"]:
curmon = entry["id"]
count = len(entry["ar"]) / 5
for idx in range(0, int(count)):
offset = idx * 5
condition = entry["ar"][0 + offset]
# element_id = entry["ar"][1+offset]
nextmons = entry["ar"][2 + offset]
# formno = entry["ar"][3+offset]
level = entry["ar"][4 + offset]
child = evolve_table[nextmons - 1]
child["condition"] = condition
if is_lvl_evolve(condition) and level > 0:
child["prevlvl"] = level
# assert curmon != 412, f"{entry}"
assert curmon < 493 or child["prevmons"] > 0, f"{entry}"
if curmon > 493:
continue
child["prevmons"] = curmon
# current = evolve_table[curmon-1]["level"] = level
# current["level"] = level
# child["prevmons"] = curmon
for entry in evolve_table:
parent = entry["prevmons"]
level = entry["prevlvl"]
condition = entry["condition"]
real_level = level
while parent != 0:
current = evolve_table[parent - 1]
if level and is_lvl_evolve(condition):
real_level = level
break
level = current["prevlvl"]
condition = current["condition"]
parent = current["prevmons"]
entry["prevlvl"] = real_level
return evolve_table
def format_evolve_table(table):
for idx, entry in enumerate(table):
print(
"{ .prevmons = %d, .prevlvl = %d }, // Pokémon: %d"
% (entry["prevmons"], entry["prevlvl"], idx + 1)
)
# out = read("XLSXContent_FieldEncountTable")
# out = read("XLSXContent_TrainerTable")
# items = read("XLSXContent_ItemTable")
# ugitems = read("XLSXContent_UgItemTable")
def get_str(wordDataArray):
if len(wordDataArray) <=0:
return None
return wordDataArray[0]["str"]
itemnames = [
get_str(label["wordDataArray"]) for label in read("english")["labelDataArray"]
]
# out = read("hide_item")
out = read("fld_item")
out = build_item_table(out, itemnames)
# out = read("XLSXContent_EvolveTable")
# out = build_evolve_table(out)
# format_evolve_table(out)
print(json.dumps(out, indent=2))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment