تغيير برمجة اللعبة

الدرس الأول: الأسمبلي – فكرة عامة جدا


ما رأيناه في الدروس السابقة جميل، لكن جله كان تغييرا لصور و نصوص اللعبة و ليس كافيا لعدة حالات.


ماذا لو كان اطار النص صغيرا جدا و أردنا توسعته؟

لو كان النص مكتوبا بحروف ضخمة، أو مكتوبا عموديا، بشكل يجعله بشعا لو ترجم؟

لو أردنا عكس اتجاه تدفق النص ليصير من اليمين لليسار؟

لو أردنا في لعبة أدوار أن يتم تصريف الأفعال "هجم الوحش، هجمت الغولة" وفقا للسياق؟

لو أردنا إضافة شاشة مقدمة للعبة فيها إسم المعرب إرضاء لغرورنا؟

لو أردنا معرفة طريقة فك ضغط الصور المضغوطة (كي نستطيع أن نعدلها)؟ لو أردنا ألا يكون هناك ضغط من الأساس؟


لو أردنا إضافة خاصية حفظ ملف في لعبة تستعمل كلمات سر طويلة؟

لو أردنا إضافة موسيقى أوركسترا أو دبلجة عربية للعبة لا تحتويها من الأساس؟

لو أردنا تغيير تصرفات بعض الأعداء في اللعبة، و اضافة مكافآت جديدة؟


كل هذا و أكثر...

ممكن جدا، لو تمكنا من تعديل برمجة اللعبة نفسها.

لكن. كيف نفعل هذا؟


في العادة عندما نصنع برنامجا على البيسك أو الباسكال أو C،

فنحن نكتب خوارزم برنامج (algorithm) و يكون فيه سطور التعليمات.

و هذا يكون النص المصدري (source code) الذي لدينا.

على سبيل المثال سنجرب عمل برنامج شهير جدا يكتب لنا "أهلا يا عالم" (Hello World!) على الشاشة،

و هو (عادة...) أول برنامج يبدأ المبتدئون بكتابته.


لغة سي (C)

لغة البيسك (BASIC)

لغة الباسكال (PASCAL)

#include<stdio.h>

main()

{

printf("Hello World!");

}

10 PRINT "Hello World!"


BEGIN

writeln('Hello World!');

END.


نلاحظ أن التعليمات المكتوبة في البرنامج

هي كلمات انكليزية فصيحة مفهومة معناها يطابق ما تفعله تقريبا:


كتابة write طباعة print

[البرنامج/الدالة] الرئيسي main

ابدأ begin انهه end

[هذا البرنامج] يشمل [المكتبة التالية لضمان حسن عمل تعليمة الكتابة] include


سبب خوف الكثيرين من البرمجة على هذه اللغات التي يفهمها البشر،

هو استخدامها الانكليزية.

لا شيء يمنع من ترجمة احدى لغات البرمجة، أو عمل لغة برمجة جديدة، تستعمل تعليمات عربية.

مثل (أكتب "أهلا يا عالم")

أظن أن هيئات التعليم في فرنسا و اليابان قامت بعمل لغات برمجة بلغتهم،

لتقريب فكرة البرمجة من تلاميذ المدارس.

كانت هناك إحدى المحاولات مؤخرا للغة برمجة كهذه لكن صاحبها تخلى عنها

لأنه كان يصر أن يكون كل الجهاز به "دعم كامل لعربية اليونيكود" و هذا طلب أقل ما يقال أنه غير واقعي أو ضروري.

لعله لم يقرأ دروس التعريب السابقة بعد؟ :P


هذه لغة برمجة عالية المستوى، لأنها تستخدم كلاما يفهمه الانسان.

و تجنبنا تفاصيلا مزعجة مثل البايتات و الصفر واحد التي يكتب بها كل شيء في الكمبيوتر، بما فيها هذا النص.


طبعا أشجعكم على تعلم أي لغة برمجة عالية المستوى

من قبيل الجافا (التي قد تكون عالية المستوى زيادة عن اللزوم بشكل يحد من نجاعتها)

أو C و أخواته (و هو لغة برمجة مفيدة جدا).


لأن ذلك قد يساعدكم في مشاريع التعريب على صنع أدوات تهكير توافق احتياجاتكم.

مثلما فعل أحمد لصنع محول الحروف مثلا، أو اكسترا لصنع مساعد الوهج قبل ذلك...

لكن ذلك ليس شرطا ضروريا لفهم و استيعاب ما سنراه في باقي الدرس.


الآن، لنجرب البرنامج نحتاج إلى مترجم Compiler

يقوم بتحويل النص المصدري source code إلى تطبيق executable.

في حالة الكمبيوتر مثلا يكون هذا التطبيق بصيغة exe.

هذا التطبيق هو النسخة الجاهزة للاستعمال من برنامجنا.



نحن قلنا مترجم قبل قليل.

لكن يترجم لماذا؟

الجواب هو: أنه يترجم النص المصدري من اللغة عالية المستوى (C,BASIC,PASCAL…)

إلى البايتات المكونة من الأصفار و الواحد، و هي اللغة الوحيدة التي تفهمها الآلة.


لغة الآلة هي لغة منخفضة المستوى

(لا نقول هذا تقليلا من احترامها :P ).

و هذا لكونها الأبعد عن إدراك بني آدم و الأقرب للآلة.

الأبعد من الكلام و الأقرب للأفعال (ما يجعلها محبذة لدى مبرمجي الألعاب نظرا أنها تتيح ما لا نجده عند غيرها).



وجب التنويه أن لغة الآلة تتغير حسب نوع المعالج CPU.

في حالة حاسوب يشغل الويندوز، سيكون على الأرجح معالج x86

في حالة حاسوب أبل، أو جهاز جيم كيوب أو وي... سنتحدث عن معالج PowerPC

في حالة هاتف أندرويد، أو جهاز جيم بوي أدفانس / دي اس / تري دي اس... سيكون ARM (طبعا هناك أنواع).

لذلك كل معالج لديه مترجم compiler خاص به.


على سبيل المثال، فالبرنامج الذي كتبناه، لو عملنا له ترجمة نحو حاسوب ويندوز (أي x86)

سنتحصل على تطبيع لو فتحناه ببرنامج هيكس فلن نتعرف على شيء من النص المصدري.


هناك مثلا في إحدى برامج "أهلا يا عالم" للويندوز فيه شيء كهذا.

عندما نفتح تطبيق exe في برنامج هيكس، (و هل لدينا حلول أخرى؟)

سنجد وسط بحر من البايتات هذا المقطع.

صدقوا أو لا تصدقوا، هذا جزء مما تحولت إليه البرمجة التي كتبناها قبل قليل بلغة البشر.


6A 00 68 00 30 40 00 68 17 30 40 00 6A 00 FF 15

70 20 40 00 6A 00 FF 15 68 20 40 00


بعد أن نسترجع أنفاسنا من هول هذه الصدمة.

الأحرى بنا أن نأخذ الأمور على مهل.

أولا، لو نتذكر من الدروس السابقة، كل شيء في الكمبيوتر يكتب بالصفر و الواحد.

ما يعني مثلا أن 6A التي لدينا في الأول، هي في الواقع 01101010

لكننا كتبناها على شكل بايتات و بالنظام الست عشري نظرا أننا لا نحتاج تعقيدا أكثر من الورطة التي نحن فيها.


هذا المقطع في الواقع تعليمات.

مكتوبة بلغة الآلة هنا (أصفار و واحد في الحقيقة، بايتات هيكس في برنامج الهيكس للتبسيط)،

و لغة الآلة التي في حالتنا هي: أسمبلي x86


6A 00

68 00 30 40 00

68 17 30 40 00

6A 00

FF 15 70 20 40 00

6A 00

FF 15 68 20 40 00


هذه التعليمات تتصرف في أشياء تكتب بعدها.

في حالتنا هذه، لو نأخذ السطر الأحمر:

العنوان 00403017 كتب فيه بترميز ASCII الجملة: Hello World!

و التعليمة 68 تتصرف في الأربعة بايتات التي كتبت بعدها و تتصرف بها بطريقة ما لن نخوض في تفاصيلها الآن

بطريقة ما تؤدي إلى ظهور كلمة Hello World! على الشاشة.


هذا كله لا ضرورة لنقلق أنفسنا بحفظه، هو مجرد شرح لما يحصل هنا لفهم الفكرة.


(وجدت صورة رائعة لتطبيق في الويندوز يبدأ من الهيكس و يفسر كل شيء فيه ماذا يفعل،

أرفقتها مع الدرس لمن هو مهتم).


لحظة.

كيف أتذكر كل هذه التعليمات؟

هل أقرأ الودع لأعرف أين تبدأ كل تعليمة؟

هل أحتاج قوى خارقة لقراءة هذه البرامج هكذا في خرابيط برنامج هيكس؟


الجواب هو، أنه عادة للتعديل على تطبيقات جاهزة، مثل برامج exe ، أو... الألعاب مثلا،

فلو كان لدينا النص المصدري source code فإن ذلك سيسهل علينا الكثير.

من ينشر هذه البرامج و لا يريد لأحد أن يعدل على برامجه أو يسرقها،

ينام عادة قرير العين لا لشيء إلا لأن التعديل على البرنامج الذي وزعه أمر صعب جدا و ليس متاحا للعوام من البشر.


هناك مثلا الكثير من شركات البرامج و الألعاب، عندما تفقد النص المصدري و يبقى لها فقط التطبيق الجاهز،

فإنه عادة يستحيل عليها تعديل أو إعادة نشر البرنامج الذي أصدرته من قبل.

مثلا هناك كابكوم ألغت انتاج اعادة اصدار لألعاب الجيم بوي للميغامان على الأدفانس،

و سيغا لا تستطيع إعادة نشر بانزر دراغون، لأنها أضاعت النص المصدري.


لكن.

التعديل على برمجة تطبيق جاهز ليس بالأمر المستحيل.


لغة الآلة التي كنا نراها قبل قليل نستطيع تمريرها على برنامج يدعى مفكك الأسمبلي Disassembler

و بالطبع كل لغة (أي كل معالج) لديه مفكك أسمبلي خاص به.

النتيجة ستكون:


push 0

push 0x00403000

push 0x00403017

push 0

call [0x00402070]

push 0

call [0x00402068]


هذه كلمات التذكر mnemotics طريقة أسهل (و يمكن حفظها) لكتابة البايتات الموافقة لهذه التعليمات.

رؤية التعليمات 60 و 6A مكتوبة بالانكليزي push ("ادفع للمكدس")

أفضل بكثير بالنسبة لنا من تعب هائل في فك طلاسم الهيكس بأنفسنا (و ذلك الجنون بعينه).


يمكننا كتابة برنامج أسمبلي بالانكليزي هكذا في برنامج نص،

تسجيله بصيغة asm ثم فتحه ببرنامج مجمّع الأسمبلي Assembler

و سيحول لنا التعليمات من الانكليزي إلى الهيكس،

و هذا يوفر علينا جهدا كبيرا و يسمح لنا بالتركيز... على البرمجة بحد ذاتها.


و عدا هذا هناك أدوات التقويم Debugger.

هذه الأدوات تراقب برنامجا اثناء عمله،

و تعطينا بالضبط ما هي التعليمات بلغة الآلة التي ينفذها في تلك اللحظة.


هناك عدد كبير من محاكيات أجهزة الألعاب فيها هذه الأدوات.

كما أن هناك بعضا من هذه الأدوات لبرامج الحواسيب

و من يعدلون على الألعاب، و منهم من يفكون برمجات مكافحة القرصنة في الألعاب يعشقونها!

لا بد أن الحديث عن Denuvo و قبله SecuROM قد بلغكم.

"البرمجات التي لا تقهر"... السبب أنه في وقت صدورها،

كانت أدوات التقويم لمعالجات x86 ليست متطورة كفاية لمجاراتها.


على سبيل المثال، هذا مثال في الصورة عن محاكي ميغادرايف به أداة تقويم

تراقب تعليمات برمجة أسمبلي 68000 موتوريلا (الأسمبلي المستعمل للميغادرايف) أثناء تنفيذها عند تشغيل اللعبة.

كما نرى فهي تقوم أيضا بتفكيك الأسمبلي و تعطينا "تعريب" و معنى كل تعليمة للغة البشر.


أسماء التعليمات الموجودة هنا فيها شيء من الانكليزية يدلنا على معناها.

مثلا:

cmpi آتية من compare (قارن بين عددين).

beq آتية من branch if equal (اذهب الى فرع البرنامج كذا لو كانت نتيجة المقارنة مساواة)

rts آتية من return to subroutine (العودة للبرنامج الفرعي السابق)

و هكذا...

هذه كلمات التذكر mnemotics و استعمالها أسهل من حفظ البايتات الموافقة لهذه التعليمات.



طبعا، نحن هنا حرقنا على أنفسنا الأحداث قليلا و ذهبنا لقراءة الكتاب من منتصفه أو آخره.

سنعود على أعقابنا قليلا للبداية و نبدأ على مهل بالبداية.


لماذا قلنا كل هذا في الدرس؟

هدفنا الأول و الأساسي هو تغيير برمجة لعبة تجارية منشورة كما نشاء.

بالطبع نحن لسنا جزءا من الشركة الرسمية لذلك لا نمتلك معنا النص المصدري لهذه اللعبة.

(و لو أنه حتى الشركة الرسمية بعد سنوات غالبا ما تضيع النصوص المصدرية

عند التخلص من الحواسيب القديمة قبل فحص ما فيها– و تصبح تفعل مثلنا).


أي أننا سنأخذ البرنامج المنشور الجاهز للعبة (أي بعد أن ترجم للغة الآلة أو الأسمبلي)، و سنحاول أن نغيره.

لكن. من حسن حظنا، أن أجهزة الكونسول القديمة ضعيفة.

و ليتمكن المبرمجون من استنزاف قدرات الجهاز، فإن المترجمات compilers لم تكن كافية،

و الحل الوحيد أمامهم كان كتابة البرنامج مباشرة بالأسمبلي.

حتى من استخدم لغة برمجة عالية المستوى فضل لغة C التي هي قريبة أيضا من الأسمبلي.


نبدأ الآن مشروعا غريبا بعض الشيء.


المثال الأول – الافلات من العقاب في لعبة ماريو


سنختار لعبة على السوبر نيس. شهيرة بعض الشيء.

النسخة الأمريكية من Super Mario World.


لغة أسمبلي السوبر نيس هي 65c816

و هي نسخة مطورة من أسمبلي النيس 6502 (و أسمبلي ال PC-Engine أيضا و هو 65C02)

و هم كلهم من نفس العائلة لو لاحظتم تكرار 65 في أسماءها كلها.

كي نضرب بهذا الدرس 3 عصافير بحجر واحد.

ما يختلف هو كون بعض التعليمات حصرية للسوبر نيس.

عندما تعترضنا تعليمة حصرية سأعلمكم بذلك في الإبان،

و عدا هذا افترضوا أن أي تعليمة أذكرها تعمل حتى مع النيس و أخواته.


الآن.


فيم يتمثل مشروعنا؟

ماريو عندما يموت في اللعبة، فإن عدد أرواحه ينقص 1.

أليس هذا مزعجا.


سيكون هدفنا الأول أن نغير هذه البرمجة.

و في تصورنا الجديد للعبة ماريو هذه،

فعندما يموت ماريو، لن يحصل شيء.

أي أن عدد الأرواح لن يتغير.


الآن، نفتح اللعبة و نبحث عن عنوان الرام (الذاكرة التي تتغير أثناء عمل اللعبة)

الذي فيه خزن عدد أرواح ماريو.

سنعود إلى أول درس على الإطلاق عملناه معا، و سنجرب عمل كود غش يخص تلك القيمة.


في الوقت الحالي استعملوا أي محاكي تشاؤون.

مثلا في Snes9X للبحث عن كود الغش هذا.

ألعب و ماريو لديه 5 أرواح.

أذهب إلى Search For New Cheats (البحث عن كودات غش جديدة) و أضغط Reset (بداية جديدة).

أوقع ماريو في مصيبة من المصائب و تصبح له 4 أرواح.

أعود لنفس نافذة البحث، أختار Less Than (أقل)، لأن عدد الأرواح قل عن آخر مرة نقرنا فيها زرا في هذه النافذة.

أضغط Search. ستتقلص قائمة عناوين الرام الممكنة قليلا.

أعود للعبة و أعيد العملية.

أستطيع أن أترك عدد الأرواح لا يتغير ثم أبحث عن القيم التي تساوي (Equal) القيمة السابقة.

أستطيع ان ازيد عدد الأرواح و أبحث عن القيم التي ارتفعت (Greater Than) مقارنة بالمرة السابقة...


إلى أن تتقلص احتمالاتنا لأبعد حد.



نجرب عمل كودات غش للعنوانين و نثبتهما في القيمة 9 مثلا،

و نبدأ في قتل ماريو لاختبار الكود.

النتيجة أن اللعبة تتجاهل واحدا منهما.

العنوان الصحيح نتوصل اليه بعد ذلك و سيكون 7E0DBE


انتهى عملنا بهذا المحاكي. نغلقه إذن.


الآن حان الوقت للتنصت على تعليمات البرمجة التي تعمل أي اتصال بهذا العنوان.

و لهذا الغرض ننزل محاكي Geiger's Snes9x Debugger أو أحدث نسخة منه.

أظن أنها 1.51 في وقت كتابة هذه السطور.

هذا المحاكي لائق نظرا لكونه يحتوي أدوات التقويم Debugger الضرورية كي نراقب البرمجة.


نحاول فتح لعبة Super Mario World فيه اذن.

شكل البرنامج سيكون مختلفا علينا قليلا...



من بين ما لدينا هنا في هذه النافذة المخيفة:


تشغيل اللعبة (Run) –

يشغلها عندما تكون متوقفة

اعادة فتح الجهاز (Reset) –

تقفل اللعبة و يعاد تشغيلها من جديد

كأنك ضغطت الزر الذي سمي نفس الإسم في الجهاز الأصلي.

تنظيف هذه النافذة (Clear Text) –

هناك نصوص تظهر في هذه النافذة (سطرين في الصورة هنا)

و أحيانا تكثر علينا. نمسحها بهذا الزر.


استخراج جدول الألوان (Palette) –

فائدة هذا أساسا مع برامج التايل لإظهار الصور بالألوان الصحيحة.

تغيير الهيكس (Show Hex) –

هذه النافذة برنامج هيكس مصغر يسمح لنا بتغيير محتويات الرام أثناء عمل اللعبة.

نقطة التعطيل (Breakpoint) –

يعطل عمل البرنامج مؤقتا عندما تتصرف اللعبة في عنوان رام معين و يحدد التعليمة المذنبة

تمشيط (Trace) –

يخزن في ملف نص (ضخم!!!) جميع تعليمات البرمجة التي نفذت منذ نقر هذا الزر.

تفكيك الأسمبلي (Disassemble) –

أهم شيء هنا. تعطيه عنوان بداية التعليمة و هو يعربها لك من الهيكس الى اسم التعليمة.


قبل أن نبدأ، أود لو نذهب الى Input/Customize Hotkeys

لغيير أزرار التشغيل السريع لبعض الوظائف.

ما يهمنا أساسا هو Pause (توقيف مؤقت للعبة)

و Frame Advance (توقيف مؤقت مع تقديم بصورة واحدة).

أود أن تختاروا لهما أزرار في لوحة المفاتيح سهلة و سريعة الاستعمال.


نعود للنافذة التي كنا فيها و نضغط Run و ستبدأ اللعبة في العمل.

أود أن يكون ماريو قد دخل في مستوى (يمكنه فيه الموت) قبل أن نبدأ.

لاحظوا أني وضعت ماريو في مكان قريب جدا من الموت المحتوم.

عندها نوقف اللعبة مؤقتا بزر لوحة المفاتيح الذي استعملناه ل Pause و نمر للتالي...



عنوان حيوات ماريو في الرام هو 7E0DBE

هناك من يفضل كتابته الكتابة الصحيحة و هي $7E:0DBE


مشروعنا هو منع اللعبة من عقابنا عندما يموت ماريو بتقليص قيمة هذا العنوان.

سنطلب من المحاكي أن يعلمنا عندما تقترب أية تعليمة من هذا العنوان.

أي تعليمة تمس هذا العنوان... ستستفز المحاكي.

و سيتعطل عمل اللعبة. مؤقتا (و يمكن اعادة التشغيل ب Run).


ما نفعله اذن هو.

أن نضع نقطة تعطيل Breakpoint متعلقة بالعنوان 7E0DBE.

نضغط اذن Breakpoint و نكتب العنوان في النافذة.



هناك 3 أنواع من مساس البرمجة بهذا العنوان حيث توجد قيمة الحيوات.

إما تقرأ منها شيئا دون تغييره (read)

و إما تكتب اليها و تغير محتوياتها (write)

و إما يكون في ذلك العنوان برمجة تنفذها (execute).


في حالتنا هذه، التعليمة المطلوبة تقوم بانقاص عدد الحيوات عند موت ماريو.

أي أنها تغير قيمة هذا العنوان. سنختار اذن write.

نضغط على الموافقة و نعود للعبة.

و الآن نقتل ماريو.


يقفز ماريو قفزة بهلوانية كبيرة عندما يموت، ثم ...

يتعطل المحاكي، و يظهر هذا السطر في النافذة.



$00/D0D8 CE BE 0D DEC $0DBE [$00:0DBE]


المعنى وراء هذا السطر؟

أولا، هذه أمامنا هي تعليمة أسمبلي.

و هي في الروم في العنوان 00D0D8 و سنغيرها بعد قليل.


تعليمة الأسمبلي عادة تكون من جزئين:

1/ التعليمة نفسها

في حالتنا CE

2/ العامل argument أي الشيء الذي تتصرف فيه هذه التعليمة

في حالتنا BE0D ...

لو لاحظتم، BE0D هو كتابة بالطرف الأصغر low endian للعنوان 0DBE

حيث خزن عدد حيوات ماريو كما رأينا منذ قليل.


أود التنويه (و لو أنه سنرى هذا بعد قليل) أنه ليس كل التعليمات بحاجة إلى عامل.


قام البرنامج بعمل تفكيك أسمبلي صغير لهذه التعليمة فقط.

و أعطانا معادلا قراءته أسهل لفهم معنى هذه التعليمة.

DEC $0DBE


DEC هذه كلمة انكليزية من كلمات التذكر mnemotics كتابتها و تذكرها أسهل من CE.

لأنها قريبة من decrease (انقاص) أو decrement (تعداد تنازلي).

في أسمبلي 65c816 (و عائلته) ... التعليمة DEC تقوم بانقاص 1 مما أمامها.


أود الملاحظة أن عدد البايتات التي تستخدمها كل تعليمة مهم للغاية.

مثلا النوع من DEC الذي يكتب ب CE في الهيكس يكون بعده عنوان طوله 2 بايت (مطلق Absolute).

هناك نوع آخر من DEC يكتب C6 يكون بعده عنوان طوله 1 بايت (صفحة مباشرة Direct Page)،

و حتى نوع آخر من DEC يكتب 3A لا يحتاج الى عامل (لأنه ينقص 1 من قيمة مكان معروف في الذاكرة اسمه المراكم Accumulator).

هناك جدول تعليمات (أوبكودات opcodes) لكل لغة أسمبلي

نعود اليه دائما لمعرفة معادل كل تعليمة بالهيكس، طولها بالبايتات، و معناها.


المستعمل في حالتنا كان المطلق Absolute، بالهيكس CE.


DEC هي الأخت التوأم لتعليمة اسمها INC (القريبة من increase يزيد).

في أسمبلي 65c816 (و عائلته) ... التعليمة INC تزيد 1 لما أمامها.


INC مستعملة مع عنوان 2 بايت (أي بالمطلق Absolute) تكتب بالهيكس EE.


لو عوضنا DEC ب INC ماذا سيحصل؟

ستكافئنا اللعبة على موت ماريو بزيادة حياة.

سنجرب هذا الآن.


أولا نعود لنافذة نقطة التعطيل Breakpoint

و افرغ كل مربعات الأعمدة الثلاثة (التي فعلنا فقط منها الواحد الذي تحت "الكتابة" write)

لأننا لم نعد بحاجة له.

نذهب الآن إلى نافذة الهيكس Show Hex.

و نختار ROM و نذهب الى العنوان الذي قال لنا المحاكي أن التعليمة أتت منه.


$00/D0D8 CE BE 0D DEC $0DBE [$00:0DBE]


00D0D8

نستطيع الذهاب الى هناك في محاكي خارجي على الروم.

لكن لو كنا نستعمل محاكي البرنامج فهو يستخدم مؤشرات السوبر نيس بنظام LoRom (Slow)

الذي استخدم في هذه اللعبة.

لو نطبق درس تحويل المؤشرات السابق سنحصل على 80D0D8.

نذهب الى هناك و بالفعل سنجد ظالتنا.




وجدنا التعليمة التي نبحث عنها.

ماذا نفعل الآن؟

لدينا برنامج هيكس تحت تصرفنا الآن.

نعوض اذن البايت الذي فيه رأس التعليمة CE ب EE كي تصبح التعليمة INC.

نضغط Save ROM لحفظ تغييراتنا و نواصل اللعبة.


على فكرة، ستضيع التعديلات عند اقفال المحاكي لأنه لا يتصرف في ملف الروم الأصلي،

بل يتصرف في نسخة من الروم يستعملها المحاكي أثناء عمله و تختفي بعد اغلاقه (لأن تلك النسخة في الواقع في... ليس هذا مهما :P).


لكن الاختيار Dump (استخراج) يسمح لنا بالاحتفاظ بنسخة دائمة و حفظ ملف منها.

لو غيرنا ROM الى

RAM (الذاكرة الحية، حيث وجدنا حيوات ماريو مثلا)

أو SRAM (ذاكرة حفظ اللعبة، حيث تسجل اللعبة لنا تقدمنا، كي لا نبدأ من أول مستوى في الخريطة عندما نفتحها مرة أخرى)

أو VRAM (الذاكرة البصرية، حيث توجد الصور التي تظهر على شاشة اللعبة، بعد فك ضغطها من الروم)

نستطيع بالاختيار Dump استخراج مناطق الذاكرة تلك لملفات خارجية يمكننا فتحها ببرامج هيكس و تايل خارجية لفحصها على راحتنا.


نحاول الآن قتل ماريو. هل سيتغير عداد الحيوات؟

أدعوكم للتجربة بأنفسكم.

على كل، هذه النتيجة بعد دقيقة من تجربة الهاك الجديد الذي قمنا به.

لم يعد هناك معنى للموت في هذه اللعبة.



أما الآن، سنجرب شيئا آخر.


التعليمة NOP.

هذه التعليمة NOP في أسمبلي 65c18 و عائلته ... لا تفعل شيئا.

بما أننا بصدد تصميم هاك يشجع على الفشل،

فلا أظن الدرس يكتمل من دونها.


في أسمبلي 65c18 تكتب هذه التعليمة بالهيكس ببايت واحد، دون أي عامل. و تكتب EA

(أي تشابه مع شركات شريرة أمريكية ليس سوى صدفة بحتة).


و على ذكر التعليمات الفاشلة، لدينا أيضا STP. (بالهيكس DB)

مغزى وجودها... أن هناك من قال أن السوبر نيس لا يكتمل من دون زر تدمير ذاتي.

هذه التعليمة STP في أسمبلي 65c18 و عائلته ... توقف عمل ساعة الوحدة المركزية و تظل صورة اللعبة متجمدة.

استخدامها الوحيد كان في شاشات "النهاية" في آخر اللعبة عندما لا يبقى هناك ما تريه لنا،

أو شاشات عقاب من قام بقرصنة الألعاب

(اللعبة تتفطن لهذا بمحاولة تغيير ذاكرة حفظ اللعبة SRAM عندما يكون الكارتردج الحقيقي لا وجود لها فيه أصلا،

و لو نجحت في ذلك فهي تكتشف فورا من يلعب اللعبة على المحاكيات أو بطاقات نسخ الألعاب).

و هي من احدى الطرق لتنفير اللاعب من اللعبة و اجباره على اعادة تشغيلها أو التخلص منها.

لذلك، رجاء لا تستخدموها بصفة عامة.


نعود الى NOP.

لو نعود لنافذة الهيكس قبل قليل و نضع 3 منها مكان كامل التعليمة.

أي أن CE BE 0D تصبح EA EA EA

فإننا قد نكون تخلصنا من تلك التعليمة و اللعبة تواصل كأن شيئا لم يكن.

يعني، أن عدد الحيوات لن يتغير. لن يزداد، و لن ينقص.

أو بعبارة أدق، لن يحصل شيء.



بالفعل، فإن تعليمة NOP هذه كانت محبوبة جدا لدى المبرمجين

الذين أرادوا التخلص من سطور برمجة لم يعودوا بحاجة إليها.


نجرب شيئا آخر.

التعليمة STZ (حصرية للسوبر نيس) تقوم بوضع القيمة صفر لما بعدها.

نجرب جعل عنوان الحيوات يصبح 0.



النتيجة أن عدد الحيوات يصبح 1 كلما مات ماريو.

لأن العداد الذي يظهر على الشاشة هو القيمة الداخلية في ذاكرة اللعبة مع زيادة واحد.



لكن هناك أمر... مزعج قليلا، أليس كذلك؟

نحن لدينا هنا فقط 3 بايتات نستطيع التصرف فيها لتعويض التعليمة الأصلية.

ماذا لو أردت أن ينتقل ماريو للمستوى الأخير لو مات؟

سأحتاج لبرمجة طويلة، و 3 بايتات لا تكفي بتاتا.


لعلكم تتساءلون لماذا سمي تعديل الرومات بالتهكير أو الهاك.

الهاك... يوحي بشكل صنارة.

وراءها خيط أحيانا يكون وراءه ترقيع او تكملة للآلة أو.. البرنامج في حالتنا.


الصنارة هي تعليمة القفز Jump.

و هي تشير الى مكان، عادة كان فارغ في الروم

لكننا وضعنا فيه برمجتنا الجديدة (التي هي أطول من الثلاثة بايتات التي عندنا هنا)

عندما تصلها اللعبة، تذهب لتلك البرمجة البعيدة، تنفذها، ثم تعود إلى هنا و تكمل بصفة عادية.


تعليمة القفز هذه (التي فيها القفز الى برمجة فرعية ثم العودة) اسمها JSR

و تكون متبوعة بعنوان البرمجة الفرعية في الروم.

لكن هذا كله سنراه لاحقا في الدرس القادم بما أننا لا نعرف أصلا كيف نعمل تلك البرمجة الفرعية.


سنرى أشياء مشوقة أخرى أيضا.

مثل تفرعات البرنامج بناء على شرط معين.

في حالتنا، هناك تفرع مباشرة بعد تعليمة الطرح التي غيرناها.

و هي تعليمة BPL (اذهب الى الفرع اذا كانت نتيجة المقارنة موجبة) و كتبت بالهيكس 10 09

حيث 10 هو التعليمة. و لو عوضناه ب BRA (انس المقارنة و اذهب دائما للفرع) أي بتعويض 10 ب 80...



فإن اللعبة ستتجاهل اختبار ان كان عدد حيوات ماريو بلغ الصفر،

و السماح لنا بمواصلة اللعبة يكون في كل الحالات،

و يمكننا اللعب بشبح ماريو (و المفروض أن هذا مستحيل.. و حتى كود الغش لا يقدر أن يسمح لنا بهذا)



سنحاول في الدرس القادم تعلم المزيد حول أسمبلي السوبر نيس،

و المثال الجديد الذي سنراه سيكون طريقة عكس الحروف في الألعاب لتناسب العربية أفضل.