Czy wiesz, że... możesz podsyłać newsy, artykuły, pliki i zdjęcia?
GTA Vice City
Statystyki
Dzisiaj: 770
On-Line: 9
Gości: 9
Użytkowników: 0
Sonda
Czy podobał Ci się zestaw misji "It Never Ends"?




Shoutbox
Archiwum
zmęczony już byłem jak to dodawałem, na następnego dnai bym o tym zapomniał
A nie lepiej napisać swój opis ?
spoko,
nie chciało mi się tłumaczyć, więc zrobiłem to an tlanslatorze
Na przyszłość nie tłumacz opisów programów/modów "Google translatorem" bo będą one odrzucane :)
proszę o zaakceptownie narzędzi które dodałem i kilku modów


Buttony
Witaj, nieznajomy!
Ładowanie...

Funkcje SCM
Korzystając z okazji, na forum pojawił się poradnik o jumpach i gosubach, chcę objaśnić coś, co jest używane dość rzadko, a ma ogromne możliwości i jest nieco spokrewnione z w/w opcodami. Mowa tu o funkcjach SCM (SCM functions). Można je porównać do gosubu, jednak taka funkcja posiada swoje własne zmienne, potrafi otrzymywać wartości z "macierzystego" wątku, a także je zwracać.

Standardowy opcode uruchamiający funkcję SCM wygląda tak:

Kod:
0AB1: call_scm_func @GetSQR 1 10 $result


Co jest czym? Więc po kolei:


  • @GetSQR - nagłówek, do którego funkcja ma skoczyć - podobnie jak w przypadku gosubu, funkcja wróci do miejsca, z którego została wywołana, poprzez opcode 0AB2 (w przypadku zwykłego gosubu było to 0051);
  • 1 - liczba wartości, które zostają przesłane do funkcji;
  • 10 - wartość przesyłana (może to być liczba całkowita [int], liczba zmiennoprzecinkowa [float], a także zmienna lokalna lub globalna);
  • $result - zmienna, do której funkcja zwraca określone wartości.





Tak, wszystko wydaje się niezrozumiałe, i na razie takie jest. A więc, na czym polega przesyłanie wartości do funkcji? Domyślnie, taka wywołana funkcja SCM wszystkie wartości ma wyzerowane (a przynajmniej powinien - zauważyłem, że CLEO3 nie zawsze to respektuje, CLEO4 nie ma tego błędu), a w większości przypadków chcemy je samemu ustawić już w momencie jej wywoływania. Z racji, że ta funkcja ma je wszystkie osobne i zmienne z normalnego wątku w żaden sposób nie są nadpisywane, trzeba to zrobić właśnie w opcodzie wywołującym, czyli 0AB1. Oznaczamy liczbą ilość wartości, które chcemy przekazać funkcji (w przykładzie powyżej jest to 1), a następnie definiujemy, co mamy przesłać (w przykładzie jest to zmienna 0@ zostanie ustawiona na 10; jeśli ustawilibyśmy np. 8 wartości do przekazania, przesłalibyśmy wartości do zmiennych 0@-7@). Po zdefiniowaniu tego możemy także ustalić, gdzie funkcja ma zwrócić swoje wartości - liczby nie ustawiamy w opcode 0AB1, ustalamy za to przy 0AB2, ale o tym za momencik.


Zastosowanie


Podam przykład funkcji SCM, która wyliczy nam długość przeciwprostokątnej trójkąta prostokątnego o znanych obu przyprostokątnych, czyli sławne twierdzenie Pitagorasa:

Gdzieś w skrypcie:

Kod:
0AB1: call_scm_func @Pitagoras 2 12.0 4@ 0@


12.0 i 4@ to długości przyprostokątnych, które w funkcji SCM będą odpowiednio w zmiennych 0@ i 1@.
0@, czyli zmienna wątku głównego, będzie zawierała zwróconą wartość przeciwprostokątnej.

Sama funkcja:

Kod:
:Pitagoras
006B: 0@ *= 0@  // (float)
006B: 1@ *= 1@  // (float)
005B: 0@ += 1@  // (float)
01FB: 2@ = square_root 0@ // pierwiastek
0AB2: ret 1 2@


Zakładając, że w zmiennej 4@ mamy wartość 5.0, funkcja wyliczy nam przeciwprostokątną równą 13.0. Ale jak ją zwróci? Robi to opcode 0AB2, w którym ustalamy, ile i jakie zmienne mają zostać zwrócone. Wartość pierwsza musi być równa liczbie zmiennych, które "przygotowaliśmy" w czasie wywoływania opcodu 0AB1. 2@ zawiera wartość, która z funkcji zostanie zwrócona do pierwszej zmiennej odbierającej (w tym przypadku pierwszej i jedynej, czyli 0@).

Główne pytanie - czemu nie gosub? Odpowiedź jest prosta - gosub naruszy nam nasze zmienne z normalnego wątku. Twierdzenie Pitagorasa nie wymagało ich wiele, więc nie jest to najlepszy przykład - najlepiej te funkcje sprawdzają się w przypadku, gdy mamy niewiele wolnych zmiennych lokalnych, a potrzebujemy obliczyć coś naprawdę skomplikowanego (bez funkcji SCM GPS nie mógłby istnieć :) ).

Może wydawać się to trudne. Na początku takie jest, ale należy przeczytać to minimum parę razy - to się naprawdę da opanować.


Funkcja SCM jako warunek


SA ma sporo możliwości tworzenia skryptów SCM w sposób, w jaki Rockstar nigdy nie działał. Jednym z takich trików jest użycie gosubu i funkcji SCM jako warunku.

Użycie tego jest bardzo, bardzo proste. Wszystko można objaśnić, używając kawałku funkcji z modu GPS.

Kod:
 [...]
        if 
            0AB1: call_scm_func @GPS_2407 3 RequestedCoordsOffset RequestedCoordsY 0@ 
        then
[...]

:GPS_2407
[...]
        if and 
            3.0 > DistanceXY
            10.0 > DistanceZ
        then
            0485:  return_true 
        else
            059A:  return_false 
        end
[...]




Jak nietrudno się domyśleć na podstawie tego przykładu, o tym, czy gosub zwróci prawdę lub fałsz decydują dwa opcody. I tak 0485 ustawia "wynik" na "prawda", a 059A na "fałsz". One mogą się wzajemnie nadpisywać, więc możliwa jest wielokrotna zmiana wyniku w trakcie jednego sprawdzenia.

Funkcja, której wyżej kawałek został użyty jako przykład, podczas sprawdzania używa prawie 20 zmiennych. Dzięki temu widać, jak opłacalne są funkcje SCM - bez nich taka rozrzutność byłaby niemożliwa.




Jedna adnotacja do tej metody: z racji, że gosub i funkcja SCM same z siebie nie są warunkami, to nie można używać ich w jednym sprawdzeniu razem z normalnymi opcodami lub dwóch gosubów na raz. W takim razie odpadają sprawdzenia typu:

Kod:
if and
0050: gosub @A
0050: gosub @B


lub

Kod:
if or
00DF:   actor $PLAYER_ACTOR driving
0050: gosub @C


Takie konstrukcje muszą być rozłożone na oddzielne sprawdzenia.


Dla ciekawych - dlaczego tak?


W jaki sposób działa warunek złożony z funkcji SCM/gosubu?
Ten trik wykorzystuje specyficzny sposób pojmowania warunków poprzez GTA. A mianowicie, rezultat sprawdzenia takiego warunku jest przechowywany w nieskończoność (więcej informacji w języku angielskim TUTAJ) - tak więc gosuby w ogóle nie są warunkami, jedynie opcody return_true i return_false ustawiają rezultat sprawdzenia w odpowiedni sposób.
To wyjaśnia też, czemu gosuby/funkcje SCM nie mogą być użyte w "if and" oraz w "if or" - nie są one parsowane jako warunkowe.

Idąc tym tropem, w niektórych przypadkach możliwe jest pozbycie się opcodów 0485 i 059A. Kiedy można ich nie używać? Na przykład wtedy:
Kod:
if
    0019: 0@ > 0
then
    0485: return_true
else
    059A: return_false
end
0051: return


Tłumacząc na "ludzki", powyższy kod wygląda tak jakby

Kod:
jeśli TAK
to TAK
inaczej NIE


Opcody ustawiające sprawdzenie są w tym momencie zbędne, gdyż wynik sprawdzenia 0019 będzie identyczny z ustawieniami return_true i return_false (powyższy kod wygląda po prostu idiotycznie, a ten SCMowy jest dokładnie tak samo idiotyczny dla gry ;) ). Możemy więc to skrócić do:

Kod:
0019: 0@ > 0
0051: return


Jeszcze jedna ciekawostka - działanie opcodów 0485 i 059A może być symulowane przez niewielki hack pamięci wątku, np.

Kod:
0A9F: 0@ = current_thread_pointer
000A: 0@ += 0xC5 // IF result
0A8C: write_memory 0@ size 1 value true virtual_protect 0


Wpisanie wartości true spowoduje oznaczenie sprawdzenia jako "prawda", a false - "fałsz". Ta operacja nie ma jednak zbyt dużego sensu (zajmuje więcej miejsca w pliku CS/SCM i jest wolniejsza).
Dodane przez: Silent
2011-02-08 12:57:03
Ile razy bym to nie czytał nic a nic nie rozumiem.
Poprzednia 1 Następna
Created & Powered by MakG
Wszelkie prawa zastrzeżone