كان هذا المستودع عبارة عن مجموعة من الأدوات للهندسة العكسية ألعاب Pokémon الجيل 1 و 2 في الأيام الأولى من التفكيك. تتراوح البرامج النصية هنا من أدوات بناء المستودع إلى برامج التعقيد المتغير لاستخراج بيانات ROM. لم يعد يتم الحفاظ على أي من الأدوات هنا وتم كتابتها في Python2 ، والبعض الآخر لا يركض على الإطلاق لأن الميناء إلى Python3 تم القيام به بتكاسل. لم تعد الأداة الرئيسية ذات الاهتمام ، GBZ80Disasm.py و gfx.py تستخدم ولديهما أدوات حديثة محدثة (انظر MGBDIs لاستبدال gbz80disasm.py والبرامج المختلفة في pokecrystal/أدوات لاستبدال gfx.py ).
نتيجة لذلك ، تم أرشفة هذا المستودع ومتاح فقط للأغراض التاريخية. أنت وحدك إذا اخترت استخدام أي نصوص هنا كقاعدة للأدوات. تم إصدار عدد قليل فقط من الأدوات هنا بموجب ترخيص مفتوح المصدر إذا كان ذلك مصدر قلق لك.
pokemontools هي وحدة بيثون توفر مكونات هندسية عكسية مختلفة لمختلف ألعاب بوكيمون. وهذا يشمل:
لتثبيت مكتبة Python هذه في site-packages :
pip install --upgrade pokemontools
ولعمل التنمية المحلية:
python setup.py develop
وبالطبع التثبيت المحلي:
python setup.py install
قم بإجراء الاختبارات مع:
nosetests-2.7
قد يكون هناك قدر كبير من الإخراج غير المرغوب فيه. إسقاط بعض البريد العشوائي مع:
nosetests-2.7 tests.integration.tests --nocapture --nologcapture
تقوم crystal.py بتوصيف ROM وتوفر فصولًا مريحة لتفريغ ASM القابلة للقراءة البشرية مع طريقة to_asm() العالمية. يمكن بعد ذلك تجميع ASM مرة أخرى في ROM الأصلي. في الوقت الحالي ، تحلل رؤوس الخريطة ، ورؤوس الخريطة "الثانية" ، ورؤوس الأحداث الخريطة ، ورؤوس البرامج النصية الخريطة ، ومشغلات الخريطة ، وخريطة "عمليات الاسترجاع" ، و MAP blockdata ، و XY Triggers ، و Warps ، و Affents ، والنصوص والبرامج النصية.
ملاحظة: من خلال هذه الأمثلة ، من الممكن استخدام reload(crystal) بدلاً من import pokemontools.crystal . بمجرد تحميل الوحدة في المرة الأولى ، يجب إعادة تحميلها إذا تغير الملف والتحديثات المطلوبة.
import pokemontools . crystal as crystal
# parse the ROM
crystal . run_main ()
# create a new dump
asm = crystal . Asm ()
# insert the first 10 maps
x = 10
asm . insert_with_dependencies ( crystal . all_map_headers [: x ])
# dump to extras/output.txt
asm . dump () بعد تشغيل هذه الخطوط ، cp extras/output.txt main.asm وتشغيل git diff main.asm لتأكيد أن التغييرات إلى main.asm قد حدثت. لاختبار ما إذا كان ASM الذي تم إدراجه حديثًا يجمع في نفس ROM ، استخدم: make clean && make . سيشتكي هذا بصوت عالٍ للغاية إذا تم كسر شيء ما.
تغطي اختبارات الوحدة معظم الفصول.
python tests.py فيما يلي عرض توضيحي لكيفية التحقيق في نص معين ، بدءًا من عنوان فقط إلى برنامج نصي معروف (0x58043). في هذه الحالة ، يستدعي البرنامج النصي أمر 2writetext لإظهار بعض الحوار. سيتم عرض مربع الحوار هذا في نهاية المثال.
import pokemontools . crystal as crystal
# parse the script at 0x58043 from the map event header at 0x584c3
# from the second map header at 0x958b8
# from the map header at 0x941ae
# for "Ruins of Alph Outside" (map_group=3 map_id=0x16)
script = Script ( 0x58043 )
# show the script
print script . to_asm ()
# what labels does it point to in the to_asm output?
# these must be present in the final asm file for rgbasm to compile the file
objdeps = script . get_dependencies ()
print str ( objdeps )
# the individual commands that make up the script
commands = script . commands
print str ( commands )
# the 3rd command is 2writetext and points to a text
thirdcommand = script . commands [ 2 ]
print thirdcommand
# <crystal.2writetextCommand instance at 0x8ad4c0c>
# look at the command parameters
params = thirdcommand . params
print params
# {0: <crystal.RawTextPointerLabelParam instance at 0x8ad4b0c>}
# 2writetext always has a single parameter
definition_param_count = len ( getattr ( crystal , "2writetextCommand" ). param_types . keys ())
current_param_count = len ( params . keys ())
assert definition_param_count == current_param_count , "this should never " +
"happen: instance of a command has more parameters than the " +
"definition of the command allows"
# get the first parameter (the text pointer)
param = params [ 0 ]
print param
# <crystal.RawTextPointerLabelParam instance at 0x8ad4b0c>
# RawTextPointerLabelParam instances point to their text
text = param . text
print text
# <crystal.TextScript instance at 0x8ad47ec>
# now investigate this text appearing in this script in "Ruins of Alph Outside"
print text . to_asm ()سيكون الإخراج النهائي هو النص التالي.
db $ 0 , "Hm? That' s a # - " , $ 4f
db "DEX, isn' t it?" , $ 55
; ... ومع ذلك ، فإن هذا ليس كيف سيظهر كائن TextScript في ASM النهائي. لمعرفة كيف سيظهر في main.asm بمجرد إدخاله ، ستقوم بتشغيل print crystal.to_asm(text) للحصول على ما يلي.
UnknownText_0x580c7: ; 0x580c7
db $ 0 , "Hm? That' s a # - " , $ 4f
db "DEX, isn' t it?" , $ 55
db "May I see it?" , $ 51
db "There are so many" , $ 4f
db "kinds of #MON." , $ 51
db "Hm? What' s this?" , $ 51
db "What is this" , $ 4f
db "#MON?" , $ 51
db "It looks like the" , $ 4f
db "strange writing on" , $ 51
db "the walls of the" , $ 4f
db "RUINS." , $ 51
db "If those drawings" , $ 4f
db "are really #-" , $ 55
db "MON, there should" , $ 55
db "be many more." , $ 51
db "I know! Let me up-" , $ 4f
db "grade your #-" , $ 55
db "DEX. Follow me." , $ 57
; 0x581e5 هناك نهج آخر هو تحليل ROM بأكمله ، ثم تحقق من البرنامج النصي في عنوان معين. هذا له ميزة مفادها أن كائن البرنامج النصي سيكون له مجموعة متغيرات map_group و map_id .
import pokemontools . crystal as crystal
# parse the ROM
crystal . run_main ()
# get the parsed script
script = crystal . script_parse_table [ 0x58043 ]
# read its attributes to figure out map group / map id
map_group = script . map_group
map_id = script . map_id
# MapHeader is not given all the info yet
# in the mean time "map_names" contains some metadata
map_dict = crystal . map_names [ map_group ][ map_id ]
map_header = map_dict [ "header_new" ]
print map_dict [ "name" ]
# Ruins of Alph Outside على الرغم من أن ما سبق لا يوضح هذا ، فقد اتضح أن البرنامج النصي في 0x58043 يشار إليه في MapEventHeader كحدث شخص.
print map_header . second_map_header . event_header . to_asm ()سيظهر هذا بنية مثل:
person_event $ 3c , 19 , 15 , $ 7 , $ 0 , 255 , 255 , $ 0 , 0 , UnknownScript_0x58043 , $ 0703ضمن هذا:
MapEventHeader_0x584c3: ; 0x584c3
; filler
db 0 , 0
; warps
db 11
warp_def $ 11 , $ 2 , 1 , GROUP_RUINS_OF_ALPH_HO_OH_CHAMBER , MAP_RUINS_OF_ALPH_HO_OH_CHAMBER
warp_def $ 7 , $ e , 1 , GROUP_RUINS_OF_ALPH_KABUTO_CHAMBER , MAP_RUINS_OF_ALPH_KABUTO_CHAMBER
warp_def $ 1d , $ 2 , 1 , GROUP_RUINS_OF_ALPH_OMANYTE_CHAMBER , MAP_RUINS_OF_ALPH_OMANYTE_CHAMBER
warp_def $ 21 , $ 10 , 1 , GROUP_RUINS_OF_ALPH_AERODACTYL_CHAMBER , MAP_RUINS_OF_ALPH_AERODACTYL_CHAMBER
warp_def $ d , $ a , 1 , GROUP_RUINS_OF_ALPH_INNER_CHAMBER , MAP_RUINS_OF_ALPH_INNER_CHAMBER
warp_def $ b , $ 11 , 1 , GROUP_RUINS_OF_ALPH_RESEARCH_CENTER , MAP_RUINS_OF_ALPH_RESEARCH_CENTER
warp_def $ 13 , $ 6 , 1 , GROUP_UNION_CAVE_B1F , MAP_UNION_CAVE_B1F
warp_def $ 1b , $ 6 , 2 , GROUP_UNION_CAVE_B1F , MAP_UNION_CAVE_B1F
warp_def $ 5 , $ 7 , 3 , GROUP_ROUTE_36_RUINS_OF_ALPH_GATE , MAP_ROUTE_36_RUINS_OF_ALPH_GATE
warp_def $ 14 , $ d , 1 , GROUP_ROUTE_32_RUINS_OF_ALPH_GATE , MAP_ROUTE_32_RUINS_OF_ALPH_GATE
warp_def $ 15 , $ d , 2 , GROUP_ROUTE_32_RUINS_OF_ALPH_GATE , MAP_ROUTE_32_RUINS_OF_ALPH_GATE
; xy triggers
db 2
xy_trigger 1 , $ e , $ b , $ 0 , UnknownScript_0x58031 , $ 0 , $ 0
xy_trigger 1 , $ f , $ a , $ 0 , UnknownScript_0x5803a , $ 0 , $ 0
; signposts
db 3
signpost 8 , 16 , $ 0 , UnknownScript_0x580b1
signpost 16 , 12 , $ 0 , UnknownScript_0x580b4
signpost 12 , 18 , $ 0 , UnknownScript_0x580b7
; people-events
db 5
person_event $ 27 , 24 , 8 , $ 6 , $ 0 , 255 , 255 , $ 2 , 1 , Trainer_0x58089 , $ ffff
person_event $ 3c , 19 , 15 , $ 7 , $ 0 , 255 , 255 , $ 0 , 0 , UnknownScript_0x58043 , $ 0703
person_event $ 3a , 21 , 17 , $ 3 , $ 0 , 255 , 255 , $ a0 , 0 , UnknownScript_0x58061 , $ 078e
person_event $ 27 , 15 , 18 , $ 2 , $ 11 , 255 , 255 , $ b0 , 0 , UnknownScript_0x58076 , $ 078f
person_event $ 27 , 12 , 16 , $ 7 , $ 0 , 255 , 255 , $ 80 , 0 , UnknownScript_0x5807e , $ 078f
; 0x58560 import pokemontools . crystal as crystal
# load the bytes
crystal . load_rom ()
# get a sequence of bytes
crystal . rom_interval ( 0x112116 , 10 )
# ['0x48', '0x54', '0x54', '0x50', '0x2f', '0x31', '0x2e', '0x30', '0xd', '0xa']
crystal . rom_interval ( 0x112116 , 10 , strings = False )
# [72, 84, 84, 80, 47, 49, 46, 48, 13, 10]
# get bytes until a certain byte
crystal . rom_until ( 0x112116 , 0x50 , strings = False )
# ['0x48', '0x54', '0x54']
# [72, 84, 84]
# or just look at the encoded characters directly
crystal . rom [ 0x112116 : 0x112116 + 10 ]
# 'HTTP/1.0rn'
# look at a text at 0x197186
text = crystal . parse_text_at2 ( 0x197186 , 601 , debug = False )
print textهذا النص الأخير في 0x197186 سيبدو مثل:
"""
OAK: Aha! So
you're !
I'm OAK! A #MON
researcher.
I was just visit-
ing my old friend
MR.#MON.
I heard you were
running an errand
for PROF.ELM, so I
waited here.
Oh! What's this?
A rare #MON!
...
"""