Strona główna
Witaj, nieznajomy!

Pętle wysokiego poziomu

Skrypty SCM i CLEO we wszystkich GTA trzeciej ery (GTA III, GTA VC, GTA SA, a także niezbyt modowalne GTA LCS i GTA VCS) opierają się wyłącznie na opcodach. Część z nich pozwala tworzyć struktury, pętle i różne sprawdzenia. Sanny Builder posiada wbudowane kilka komend, które imitują struktury języków wysokopoziomowych (dlatego też nazywane są one konstrukcjami wysokiego poziomu, lub z angielskiego high-level constructs), oraz przy kompilacji zostają zamienione na zwykłe opcody.

Pętla while...end

Są dwa typy tej konstrukcji. Jedna z nich, while true powtarza akcję w nieskończoność:

Kod:
while true
    
wait 1000
    0109: player $PLAYER_CHAR money += 1000
end


Taka pętla po prostu dodaje graczowi 1000 dolarów co sekundę (1000 milisekund). Przy kompilacji konstrukcja jest zamieniana na:

Kod:
:LABEL
0001: wait 1000 ms
0109: player $PLAYER_CHAR money += 1000
0002: jump @LABEL



Drugi typ tej konstrukcji to while [warunek]. Jest ona wykonywana w czasie, gdy dany warunek zwraca wartość true.

Kod:
while 0AB0:  key_pressed 0x9 // Tab

    0001: wait 1000 ms
    0109: player $PLAYER_CHAR money += 1000
end


Analogicznie do pierwszej konstrukcji, ta dodaje graczowi 1000$ co sekundę, ale tylko w momencie, gdy wciska on klawisz Tab. Jeśli gracz zwolni przycisk, gra wychodzi z pętli i odpala dalsze partie kodu. Przy kompilacji konstrukcja jest zamieniana na:

Kod:
:LABEL
0AB0:  key_pressed 0x9
004D: jump_if_false @LABEL_2
0001: wait 1000 ms
0109: player $PLAYER_CHAR money += 1000
0002: jump @LABEL

:LABEL_2
// Dalsze partie kodu...



Nie, brak if nie jest tu błędem, gra działa bez tego normalnie.

Co jednak mamy zrobić w wypadku, gdy chcemy wyjść z któreś z tych pętli? Sanny Builder obsługuje jeszcze dwa kody - continue oraz break. Ten pierwszy przeskakuje na sam koniec pętli:

Kod:
while true
    
wait 1000
    0AB0:  key_pressed 0x9
    else_jump 
continue
    0109: player $PLAYER_CHAR money += 1000
end


Kompiluje się to jako:

Kod:
:LABEL
0001: wait 1000 ms
0AB0:  key_pressed 0x9
004D: jump_if_false @LABEL_2
0109: player $PLAYER_CHAR money += 1000

:LABEL_2
0002: jump @LABEL


break za to po prostu wyskakuje z pętli, tak samo jak while [warunek]:

Kod:
while true
    
wait 1000
    0AB0:  key_pressed 0x9
    else_jump 
break
    0109: player $PLAYER_CHAR money += 1000
end


-->

Kod:
:LABEL
0001: wait 1000 ms
0AB0:  key_pressed 0x9
004D: jump_if_false @LABEL_2
0109: player $PLAYER_CHAR money += 1000
0002: jump @LABEL

:LABEL_2
// Dalsze partie kodu...



Nic nie stoi na przeszkodzie, aby napisać ręczny skok do innego nagłówka w środku tej pętli (oraz każdej innej pętli wysokiego poziomu).


Pętla for...end


Ta pętla jest już bardziej zaawansowana i ma więcej typów. Prościej w tym wypadku jest objaśnić ją na przykładzie z main.scm:

Kod:
for 6@ = 0 to 2 step 1
    092B: 8@ = group $PLAYER_GROUP member 6@ 
    01C2: remove_references_to_actor 8@
end


Kompiluje się to jako:

Kod:
0006: 6@ = 0

:LABEL
092B: 8@ = group $PLAYER_GROUP member 6@ 
01C2: remove_references_to_actor 8@
000A: 6@ += 1
0019:   6@ > 2
004D: jump_if_false @LABEL

// Dalsze partie kodu...



Po kolei:
  • 6@ - zmienna, która ma pełnić funkcję licznika pętli
  • 0 - początkowa wartość licznika. Może to być inna zmienna.
  • to - oznacza, że pętla ma się zwiększać o określona wartość. Zamiana tego na downto spowoduje odejmowanie wartości, zamiast jej dodawania
  • 2 - końcowa wartość licznika. Może to być inna zmienna.
  • step 1 - określenie, o ile ma się zwiększać pętla przy każdej iteracji. Domyślnie 1 - wtedy ręczne określenie tego nie jest konieczne


Ta pętla obsługuje też operacje na liczbach zmiennoprzecinkowych. Ponadto, tak samo jak w poprzedniej pętli, można używać w niej komend continue (przeskakuje na koniec pętli, zwiększając licznik) i break (wyskakuje z pętli):

Kod:
for 0@ = 0 to 15
    0109: player $PLAYER_CHAR money += 1000
    if
        
010A:   player $PLAYER_CHAR money > 10000
    then
        
break
    end
end


->

Kod:
0006: 0@ = 0

:LABEL
0109: player $PLAYER_CHAR money += 1000
00D6: if
010A:   player $PLAYER_CHAR money > 10000
004D: jump_if_false @LABEL_2
0002: jump @LABEL_3

:LABEL_2
000A: 0@ += 1
0019:   0@ > 15
004D: jump_if_false @LABEL

:LABEL_3
// Dalsza część kodu...




Pętla repeat...until


Działa ona dość podobnie do pętli while. Tak samo jak ta pierwsza, obsługuje dwa typy. Pierwszy to repeat...until false, który powtarza operację w nieskończoność:

Kod:
repeat
    wait 
1000
    0109: player $PLAYER_CHAR money += 1000
until 
false


Kompiluje się to tak samo jak pętla while true.


Drugi typ to pętla repeat...until [warunek]. Jak sama nazwa wskazuje, powtarza ona działanie...do czasu aż [warunek zwróci Prawda].

Kod:
repeat
    wait 
1000
    0109: player $PLAYER_CHAR money += 1000
until 
8AB0:  not key_pressed 0x9


Taka pętla wykonuje działanie do czasu aż gracz zwolni przycisk Tab. Kompiluje się ona jako:

Kod:
:LABEL
0001: wait 1000 ms
0109: player $PLAYER_CHAR money += 1000
8AB0:  not key_pressed 0x9
004D: jump_if_false @LABEL




Podsumowując - konstrukcje wysokiego poziomu to rzecz bardzo przydatna. Wymagają one przyzwyczajenia, ale dzięki nim skrypt jest dużo czytelniejszy, często też wydajniejszy, a sam mod pisze się krócej (w moim przypadku).
Dodane przez: Silent
Created & Powered by MakG
Wszelkie prawa zastrzeżone