Kurs 01 -------- Jako pierwszą bierzemy na warsztat grę River Raid. Jest to wspaniała gra i napewno każdy z Was kiedyś się w nią zagrywał. Czy nie zastanawiało Was nigdy ile w tej grze jest etapów? Przeszkadzała Wam w tym znikoma liczba żyć? Od dzisiaj ten problem przestanie istnieć! Po pierwsze pokaże Wam jak ułatwić sobie życie w emulatorze. Jest to podstawa do prawdziwego łamania gier. A więc tak: Odpalamy emulator Atari800Win PLus z grą River Raid (grę ściągnijcie z naszego serwisu). Naszym oczom ukazuje się niebieska rzeka i masa statków przeplatana z helikopterkami. To jest po prostu wspaniałe, więc zanim zabierzecie się do pracy pograjcie trochę w ramach relaksu :). Zabawa, zabawą, a tu robota czeka, więc naciskamy Start i czekamy do momentu, kiedy plansza zjedzie na dół i życia zmienią się z 4 na 3. Oczywiście jeszcze nie startujcie. Z menu emulatora wybierzcie Misc->Cheat options... Naszym oczom ukaże się sympatyczny panelik, na którym można zdziałać naprawdę niesamowite rzeczy. Spróbójmy np. wcisnąć 'Disable sprite collisions detection'. Po małej zabawie z resztą przycisków bedziemy mogli latać dosłownie po wszystkim, ale to żadna frajda :). Bardziej interesuje nas dolna część paneliku. Zajmuję się ona przeszukiwaniem pamięci w celu znalezienia adresu, pod którym liczba nr 1 zmieniła sie na liczbę nr 2. Jak się zapewne bystrzy czytelnicy domyśleli w pierwszym okienku wprowadzimy aktualną liczbę naszych żyć, czyli 3. Wciśnijmy jeszcze 'Memo' i wracamy do gry. Wiem, że pierwszy most to niezbyt odpowiednie miejsce na stracenie naszego pierwszego życia, ale będziemy musieli się w tym wypadku poświecić. Gdy nasza liczba życ osiągnie wartość 2, wróćmy do naszego paneliku i w drugim okienku wpiszmy również 2. Teraz wciśniejcie 'Search'. I nagle coś pojawiło się w prawym okienku. Ktoś by mogł spytać - "Co to #@$@ jest?!", dlatego chciałbym to pokrótce wyjaśnić. $ - jest to znak oznaczający, że cyfry po tym znaku będą wchodziły w skład liczby szesnastkowej, a 006a oznacza liczbę szesnastkową. W nawiasie po prawej możemy zaobserwować tą samą liczbę tylko w systemie dziesiętnym. Atari posiada przeważnie 64Kb pamięci, więc i gry wykorzystują tylko ten przedział $0-$ffff. Ta liczba, która się nam ukazała przedstawia adres w pamięci, gdzie autorzy umieścili liczbę żyć. Zaznaczmy teraz ten adres i opcje 'Lock in' "ptaszkiem". W pole obok 'Lock in' wpiszcie np. 5 i powróćcie spowrotem do gry. O! Mamy 5 żyć! Spróbójcie się rozbić to zobaczycie, że liczba się nie zmniejszy. Pokazałem Wam jak bawić się w emulatorze, ale teraz dopiero zaczyna się kurs. Naszym następnym zadaniem jest zedytować grę w pamięci komputera, tak żeby nie ubywała nam liczba żyć. Po pierwsze musimy się trochę namyślić i przewidzieć jak autor gry zapisał operacje zmniejszania żyć w programie. Mi pierwsza rzecz jaka przychodzi do głowy to: DEC $6A ;zmniejszenie zawartości adresu o 1 Instrukcja zmniejsza po prostu wartość adresu $6A (czyli adres z liczbą żyć) o 1. Po przetłumaczeniu tej instrukcji na kod maszynowy otrzymujemy dwa bajty: C66A. Jeśli nie wiesz w tym momencie o czym mówie to odsyłam do lektury Tajemnic Atari i instrukcji Quick Assembler'a. Powinniśmy teraz przeszukać całą pamięć programu w poszukiwaniu tych bajtów. Jak już może się domyśliłeś po załadowaniu gry, cały jej kod jest przechowywany w pamięci dlatego znajdziemy w niej instrukcje zmniejszania liczby żyć o 1. Wracamy do emulatora i naciskamy F8. Ukaże się potężny monitor pamięci. Radzę się zaznajomić z jego opcjami bo jest naprawde bardzo przydatny. Żeby otrzymać listę wszystkich opcji wraz z opisem wpiszcie '?'. Teraz nagramy stan całej pamięci River Raid'a do pliku, żeby go potem spokojnie przeglądać. Piszemy: write 0 ffff rivermem.dat Ta komenda nagra pamięć z zakresu $0000 do $FFFF do pliku rivermem.dat w katalogu z grą. Chciałem jeszcze dodać, że wychodzi się z monitora poleceniem 'cont'. Otwórzmy powstały plik w Hex Workshop. Hoho, ile śmiesznych numerków - najciekawsze jest to, że każdy z nich spełnia w grze jakąś funkcję :). Dobra, zaciskamy kciuki i szukamy w hex'ach C66A... ... ... dupa! Hmmm, nie znalazl. Musicie być przygotowani na taką ewentualność, ale nie poddawajcie się. Pomyślmy zatem jeszcze raz. Autor wiedział, że pierwsza instrukcja jaka by nam wpadła do głowy byłoby to, dlatego troche ją zmodyfikował. Może najpierw wczytuje zawartość adresu $6A do rejestru, zmniejsza go o 1, a potem zwraca spowrotem na miejsce?! Tak, to by brzmiało sensownie. Załóżmy, że użyłby w tym celu akumulatora. Wyglądałoby to mniej więcej tak: LDA $6A ;wczytanie do akumulatora aktualnej liczby żyć SEC ;ustawienie znacznika C (niezbędne przed odejmowaniem za pomocą SBC) SBC #$01 ;odjęcie liczby 1 od akumulatora STA $6A ;wstawienie zawartości akumulatora pod adres l. żyć Kod: A56A38E901856A Szukamy, szukamy... nie ma :(. Programista mogł użyć tej metody, ale niekoniecznie akumulatora. Mógł użyć rejestru X lub Y, dlatego rozpatrzmy dwie możliwości: LDX $6A ;wczytanie do rejestru X aktualnej liczby żyć DEX ;zmniejszenie rejestru X o 1 STX $6A ;wstawienie zawartości rej. X pod adres l. żyć Kod: A66ACA856A LDY $6A DEY STY $6A Kod: A46A88846A Niektórzy pewnie zauważyli, że w pierwszym przykładzie użyłem intstukcji SBC, a w następnych DEX i DEY. Teraz wyjaśniam - SBC może być użyte tylko z akumulatorem, bo nie ma swojego odpowiednika jak DEX czy DEY, a rejestry X i Y nie mogą być użyte z SBC :) proste. Mam nadzieję, że wszystko co piszę jest jasne. Szukamy więc pierwszego kodu... nie ma :(. Szukamy drugiego... JEST! EUREKA! Teraz możemy być pewni, że jest to jedyna instrukcja w kodzie odpowiedzialna za zmniejszanie liczby żyć. Teraz, gdy najtrudniejsze jest już za nami, mamy czas na trochę własnej inwencji tzn. Jak zmodyfikować ten kawałek kodu, żeby nie ubywało nam żyć. Teraz pokaże Wam potęge instrukcji NOP - instrukcja ta zajmuje jeden bajt i robi... NIC! dlatego jest to takie piękne. Spójrzcie teraz na ten kod: LDY $6A NOP ;uprzednio było DEY STY $6A Co robi ten kod? Ładuje liczbę żyć do Y i bez zmian odstawia ją na miejsce :). Można oczywiście dla zabawy zamienić DEY np. na INY, co spowoduje dodanie jednego życia przy zderzeniu :), ale to już zależy od Waszego pomysłu. Wracając do tematu, musimy teraz zamienić bajt z instrukcją DEY ($88) na instrukcję NOP ($EA). Sprawdźmy jeszcze w Hex Workshopie pod jakim adresem znajduje się ta instrukcja - $A355. Wracamy do naszego monitora pamięci i wydajmy polecenie: f a355 a355 ea Spowoduje to wypełnienie przedziału pamięci od $A355 do $A355, czyli 1 bajta, bajtem $EA, czyli instrukcją NOP. Wracamy do gry i rozbijamy się. Ha, co się stało? Nic się nie stało! Liczba żyć cały czas niezmieniona :). Trainer'a od razu nie napiszemy, ale jako, że ta wersja River Raid'a nie jest w żaden sposób skompresowana, możemy poddać edycji cały plik z grą. Otwieramy go w Hex Workshop i szukamy kodu, zmniejszającego liczbę żyć o 1. Jest? Jest. Modyfikujemy go podobnie jak zrobiliśmy z nim w monitorze pamięci. Zapisz plik powiedzmy jako 'rrcrk.com' i gotowe! Gratulacje! Właśnie złamałeś swoją pierwszą grę!!! P.S. Trainer'ami zaczniemy się bawić trochę później jako, że jest to sprawa trochę bardziej skomplikowana. Po pierwsze musicie poznać język assemblera procesora 6502, żebyście mogli go napisać. Black Dot