poniedziałek, 23 lutego 2009

Finditem, czyli szukanie przedmiotów

Dzisiaj chciałem opisać polecenie finditem oraz wszystkie związane z tym zmienne. Postaram się dość szczegółowo omówić zagadnienie, gdyż jest to chyba jedno z najważniejszych zagadnień.

Składania brzmi:
findItem {{id} | {type} | *} [index] [[G] | [G_{dist}] | [C] | [C_{container id}]]

może teraz po kolei wytłumaczę co i jak bo domyślam się czytelniku, że patrząc na to, zastanawiasz się o co tutaj w ogóle chodzi.


Zacznijmy od tego co robi samo finditem.
Finditem szuka przedmioty. Jakie przedmioty? Takie i w takich miejscach jakie podamy jako parametry, czyli to co jest po słówku finditem.

Pierwsze musimy podać jedną z 3 rzeczy:

id - jest to id przedmiotu, unikalna dla każdej rzeczy w Ultimie. Jeżeli nie wiesz jak sprawdzić id przedmiotu już spieszę z pomocą. Klikamy 2 razy na dany przedmiot, a następnie w easyUO po prawej stronie, w zakładce Last Action szukamy zmiennej #lobjectid. Tam właśnie znajduje się id przedmiotu, który "użyliśmy" ostatnio.

typ - są to 2-3 litery które określają typ przedmiotu. Typ przedmiotu sprawdzamy tak samo jak id, jednak patrzymy na zmienną #lobjecttype. Dla przykładu na MW, serwerze na którym ja gram bandaże mają typ ZLF.

* - gwiazdka wyszukuje wszystkie przedmioty. Po prostu szuka wszystkiego.

Kolejnymi argumentami są argumenty, które określają gdzie chcemy szukać danych przedmiotów. Do wyboru mamy 2 różne rzeczy.

C - czyli container. Przedmioty będą szukany tylko i wyłącznie w plecakach, pojemnikach oraz w naszym paperdolu (jedynie w tych, które są aktualnie otwarte)
Dodatkowo możemy dokładnie określić w jakim pojemniku chcemy szukać. Wygląda to wtedy tak:
finditem * C_idpojemnika
lub
finditem * C_ , %zmienna
gdzie zmienna przechowuje id pojemnika. Ta druga składnia jest dość często stosowana. W tym przypadku, który widzimy wyżej, będą wyszukiwane wszystkie przedmioty z plecaka o podanym idpojemnika.

Przykładowo:
finditem * C_ , #backpackid
szuka wszystkich przedmiotów w naszym plecaku głównym.

G - druga opcja czyli ground. Ground czyli ziemia. Wyszukiwane są wszystkie przedmioty leżące na ziemi. Ale również i postacie i NPC. Dodatkowo możemy określić zasięg w jakim chcemy szukać przedmiotów poprzez podanie liczby po _ tak jak w przypadku wyżej.
Przykład:
finditem * G_5
szuka wszystkich przedmiotów, które znajdują się w promieniu 5 od naszej postaci.

Dodatkowo:
Z tego co wyczytałem w dokumentacji, można używać jeszcze 2 opcji, nie tylko C i G.
Są to:
A - szuka ukrytych przedmiotów. Ale są to przedmioty ukryte przez komendę hideitem
CA_pojemnik - szuka ukrytych przedmiotów w pojemniku. Tak jak w przypadku samego C, można podać id pojemnika.


Zmienne find item
Teraz koniecznie trzeba powiedzieć, gdzie znajdziemy informacje o tym co finditem znalazł, w końcu o to dokładnie nam chodzi.
Wszystkie te zmienne znajdują się w zakładce find item.
Postaram się teraz po kolei omówić każdą z tych zmiennych.

#FINDID - jest to ID znalezionego przedmiotu. Jest unikalne i niepowtarzalne dla danego przedmiotu.

#FINDTYPE - jest to typ przedmiotu, który został znaleziony. Określa grupę obiektów o tych samych właściwościach, czasami tylko grafice. Np butle nie maja rozróżnienia na duże i małe. Do ich odróżniania trzeba już używać property.

#FINDX, #FINDY, #FINDZ - są to 3 zmienne, które określają położenie przedmiotu.

#FINDDIST - określa odległość w jakiej znajdujemy się od przedmiotu

#FINDKIND - w zmiennej tej znajduje się gdzie znajduje się obiekt. Przyjmuje on 3 wartości.
0 - gdy obiekt znajduje się w pojemniku
1 - gdy obiekt znajduje się na ziemi
-1 - gdy obiekt nie został znaleziony
Z tego co można wyczytać w dokumentacji, nie jest zalecane sprawdzanie czy został znaleziony przedmiot przez sprawdanie if #findkind = -1 (aczkolwiek ja osobiscie spotykam sie najczęsciej z takim przypadkiem sprawdzania czy został znaleziony przedmiot). Tłumaczą to tym, że dla człowieka ciężej zrozumieć o co chodzi. Bardziej zalecane jest sprawdzanie zmiennej #findcnt

#FINDSTACK - zmienna ta przechowuje ile jednostek znajduje się w kupce. Jeżeli mamy przedmioty które sie grupują (stackują) to wtedy zmienna ta mówi nam ile jest rzeczy w danej kupce. Np: złoto, zioła. W przeciwnym wypadku jak łatwo sie domyslić zmienna ta ma wartość 1.

#FINDBAGID - zmienna ta przechowuje ID pojemnika, w którym znaleziony został przedmiot.

#FINDMOD - przechowuje X i Y znalezionego przedmiotu w formie: X_Y. Szczerze nigdy nie używałem.

#FINDREP - zwraca reputacje. Jeżeli szukamy osoby, NPCa to wtedy zmienna ta przechowuje reputacje, czyli jedną z 7 wartości:
1 - Niewinny (Niebieski)
2 - Przyjaciel (Zielony)
3 - Zwierzęta (Szary)
4 - Kryminalista (Szary)
5 - Wróg (Pomarańczowy)
6 - Morderca (Czerwony)
7 - Invulnerable (nietykalny) (żółty)

#FINDCOL - zwraca kolor znalezionego przedmiotu. Warto zobaczyć to na systemie rudy, gdy mamy takie samo #FINDTYPE. Różne rudy róznią się właśnie kolorem.

#FINDINDEX - jest to index znalezionego przedmiotu. Jeżeli szukamy przedmiotów po np typie, możemy znaleźć ich więcej niż tylko jedną. Zmieniając wartość tej zmiennej, możemy dostać się do informacji o kolejnych przedmiotach. Może mieć wartości od 0 do #findcnt

Przyklad:

Finditem *
for %i 1 #findcnt
{
event sysmessage Znalazlem przedmiot o id: #findid
wait 5
}

#FINDCNT - zmienna ta przechowuje ile przedmiotów zostało znalezionych. Jeżeli nie zostało nic znalezione to mamy wartość 0.


W sumie tyle na dziś. Dla ciekawskich chciałbym dać jeszcze tylko jeden przykład, dość żartobliwy. Można dać swoim kolegom.

finditem *
for %i 1 #findcnt
{
hideitem #findid
}

sami domyślcie się lub sprawdzcie co ten skrypt robi.

W przypadku jakichkolwiek niejasności proszę o pytania w komentarzach

poniedziałek, 16 lutego 2009

Last action, last object

Dziś pomówimy już trochę na temat sterowania postacią, czyli wykonywania przez nią jakiś czynności. W końcu o to chodzi w całym easyUO.

Last object
czyli wykonanie użycie ostatnio używanego przedmiotu. W easyUO realizowane jest to przez komendę event macro 17. Co robi ona dokładnie? Dokładnie bierze wartość #lobjectid ze zmiennych systemowych a następnie symuluje podwójne kliknięcie (czyli użycie) na dany przedmiot.

Last target
czyli wskazanie ostatnio wskazywanego przedmiotu.
Komenda: event macro 22
Opis: Dokładnie pobierana jest wartość ze zmiennej #ltargetid a następnie jest wybierany przedmiot o takim ID. Jeżeli nie można wybrać przedmiotu o takim ID, dość często dochodzi do zawieszenia klienta.
Oczywiście, aby wszystko dobrze działało poprawnie, powinniśmy mieć w kliencie celownik.

Do czekania na celownik można wykorzystać 2 sposoby:
Komenda target czas
Opis: komenda ta czeka określoną ilość czasu. Jeżeli kursor jest celownikiem to przechodzi dalej, w przeciwnym wypadku, gdy po upłynięciu czasu celownik się nie pojawi również przechodzi dalej.
Ja osobiście stosuję tę komendę bardzo często, ale tylko wtedy gdy mam pewność, że celownik się pojawi i w czasie czekania na celownik nie potrzebuję sprawdzać innych warunków.

Sposób drugi to pętla z warunkiem sprawdzającym zmienną #TARGCURS. Jeżeli zmienna ta ustawiona jest na wartość 1, wtedy kursor jest celownikiem.
Przykład:
repeat
{
...
tutaj można sprawdzać jakieś warunki
}
until #TARGCURS = 1

Pragę oczywiście powiedzieć, że zmienne #LTARGETID oraz #LOBJECTID można ustawiać komenda set.

piątek, 13 lutego 2009

Debugowanie oraz pare komend

Tak jak pisałem i obiecałem w poprzedniej lekcji chciałbym dziś przybliżyć problem debugowania czyli szukania błędów. Sposobów jest kilka a sam program easyUO, który interpretuje nasze skrypty ma bardzo przydatne do tego narzędzie. Nazywają się "step over", "step into" oraz "step out". Jak można domyślić się po nazwach wykonują nasze skrypty linijka po linijce w takiej szybkości i tak jak chcemy. Wszystkie je można znaleźć w zakładce control na górze.

Step over (f8)
Czyli wykonanie kolejnej linii. Wciskając f8 klient wykonuje kolejna linijkę po czym zatrzymuje skrypt. My w tym czasie możemy spokojnie zobaczyć efekty, co się stało, oraz gdzie znajdujemy się w tym momencie. Trzeba tutaj powiedzieć coś na temat subów. Czyli wydzielonych bloków w kodzie programu do których można skoczyć czy nawet przekazać im parametry. Step over nie pokazuje co dokładnie dzieje się w takich subach. Jeżeli natrafi na linijkę gosub xxx to wykona całość zawartości suba i przejdzie do kolejnej linijki. To w sumie odróżnia step over od step into

Step into (f7)
Tak jak pisałem wyżej, ta komenda również wykonuje skrypt linijka po linijce, jednak jeżeli natrafia na fragment dotyczący suba, to skacze do miejsca w kodzie, gdzie on się znajduje i możemy dokładnie widzieć co dzieje się w danej chwili w subie do którego skoczyliśmy. O subach, które są odpowiednikami funkcji z innych języków programowania opowiem później, gdyż warto jednak omówić to szerzej.

Step out (f6)
Na samym początku myślałem, że działa to nieco inaczej, lecz jak się przekonałem myliłem się. A dokładnie step over powoduje wyjście z suba. Czyli, jeżeli używaliśmy step into przy naszym szukaniu błędów, to gdy znajdujemy się w jakimś subie, step over wykonuje go do końca i wychodzi, tak iż w następnym kroku jesteśmy już poza subem

Polecam bardzo przetestowanie samemu jak dokładnie działają te 3 proste rzeczy w praktyce. Zamieszczam poniżej bardzo prosty skrypt, na którym dobrze widać czym różnią sie od siebie te 3 funkcjonalności.

start:
wait 1
event sysmessage b
wait 1
gosub a
wait 1
goto start

sub a
event sysmessage a
wait 1
return


Na temat debugowania słów kilka
Chciałem jeszcze napisać jak ja szukam błędów w moich skryptach. Zazwyczaj umieszczam w ważnych miejscach linijkę event sysmessage 1 lub inny numer. Bardzo przydatne to jest gdy chcemy sprawdzać szybkość reakcji skryptu (chociaż tutaj można zastosować lesze techniki związane z czasem) oraz czy dany skrypt wchodzi do jakiejś pętli lub spełniony jest jakiś warunek. Myślę, że sam podczas pisania skryptów, oraz szukania w nich błędu znajdziesz jak Tobie najlepiej się ich szuka. Jednak step over lub step into są chyba najlepszą metodą, ponieważ możemy śledzić powoli linijka po linijce w trakcie wykonywania pliku kod i widzimy na bierząco co się dzieje. Gorąco polecam zaznajomienie się z tym tematem w praktyce.

Parę innych przydatnych komend
Zanim przejdę do konkretnych komend, które sprawiają, że nasze postacie zaczynają robić coś w Ultimie, chcę jeszcze przedstawić komendy, które służą do zarządzania wykonywaniem skryptu.

exit - komenda ta użyta w skrypcie powoduje zakończenie wykonywania skryptu.
halt - dokładnie to samo co exit. Nie wiem dlaczego są 2 komendy do tego samego

call - powoduje wykonanie skryptu w podanej lokalizacji
dokładnie składnia wygląda:
call plik parametry
Jak można przeczytać w dokumentacji plik musi być podany w formacie C:\MyDocu~\blabla.txt a nie C:\My Documents\blabla.txt
Można również przekazywać parametry (tak jak w gosub)

pasue - powoduje zatrzymanie skryptu. Jeżeli damy po tej komendzie play to zacznie ona od miejsca w którym skończyło się wykonywanie.

tym sposobem omówiłem wszystkie komendy (oprócz subów, czyli sub oraz gosub), które zaliczane są do grupy komend zwanej "Flow Control". Nie wiem jak dobrze przetłumaczyć na język polski tą frazę, gdyż przepływ kontroli ani kontrola przepływu jakoś do mnie nie przemawiają.

Jeżeli chcesz, możesz poczytać w dokumentacji angielskiej. Z tego co własnie patrze, niestety dokumentacja Polska nie obejmuje tego fragmentu.

I jeszcze raz zachęcam wszystkich czytających tego bloga do pisania komentarzy oraz pytania, gdy coś jest niezrozumiałe.