2. Zaczynamy programowanie

Uwaga! Informacje na tej stronie mają ponad 5 lat. Nadal je udostępniam, ale prawdopodobnie nie odzwierciedlają one mojej aktualnej wiedzy ani przekonań.

2. Zaczynamy programowanie

Po tym długim wprowadzeniu czas rozpocząć właściwe programowanie. A więc... do dzieła! Uczymy się :)

2.1. Pierwsze polecenia

Poznamy najpierw kilka podstawowych poleceń, którymi powinieneś umieć się posługiwać. Wywołania poleceń można pisać bezpośrednio w kodzie skryptu. Zostaną wtedy uruchomione w chwili wczytania skryptu podczas uruchomienia bota, wykonania polecenia .rehash lub .restart.

Niestety, kiedy w tak wpisanym poleceniu jest błąd, wysypie nam się cały Eggdrop. Trzeba wtedy zajrzeć na koniec loga (u mnie eggdrop\logs\eggdrop.log) by dowiedzieć się o przyczynie błędu, naprawić go i ponownie uruchomić bota. Bywa to bardzo uciążliwe. Z czasem jednak przyzwyczaisz się trochę i zmobilizuje cię to do uważania na literówki w kodzie.

2.1.1. Polecenia logujące

Pierwszym, co nauczymy się robić, będzie zapisywanie podanego tekstu do pliku loga. Myliłby się ten kto sądzi, że służy do tego tylko jedno proste polecenie. Możliwości są takie:

Polecenia logujące:

putlog <text>
putcmdlog <text>
putxferlog <text>
putloglev <level(s)> <channel> <text>

Nie przerażaj się jednak! Umieściłem tu listę wszystkich dostępnych poleceń logujących tylko po to, by trochę cię nastraszyć :) Tymczasem sprawa jest całkiem prosta. Eggdrop posiada nie jeden log, ale kilka. Różnego rodzaju informacje lądują w różnych logach zależnie od tego, z jakiego kanału pochodzą oraz przede wszystkim jaki mają poziom (ang. "level"). Możesz przypisywać poszczególne poziomy informacji do poszczególnych logów za pomocą pliku konfiguracyjnego. Jeśli uważnie go przerabiałeś to zapewne pamiętasz. Dokładne opisy tych poleceń znajdziesz w oryginalnej dokumentacji języka TCL lub (w tym przypadku) Eggdropa.

Jeśli nie możesz się w tym połapać, nie szkodzi. Wystarczy używać pierwszego z tych poleceń i odczytywać zapisywany przez nie tekst z odpowiedniego pliku.

Przykład logowania:

putlog "First... loaded"

Wywołanie podobne do powyższego (gdzie "First" to nazwa twojego skryptu) umieszcza się zwykle na końcu każdego skryptu. Dzięki temu po każdym uruchomieniu bota wiesz, że twój skrypt został załadowany. Podany w cudzysłowach tekst zapisuje się do loga o poziomie "o" ("misc") oraz na ekranie w sesji Telnet.

Spróbuj napisać skrypt składający się tylko z tej linijki i uruchom go. Nie powinieneś mieć z tym większych problemów.

Do czego służą te polecenia logujące?

Przeznaczone są do zapisywania różnych zdarzeń, które uznasz w swoim skrypcie za istotne. Szczególnie przydatne mogą być w celu debugowania, czyli szukania błędów w kodzie. Wstawiasz polecenia logujące w różne miejsca kodu i analizując log wiesz co, kiedy, ile razy i w jakiej kolejności było wykonywane.

Poza tym log ma tą zaletę, że bot prowadzi go sobie stale w czasie działania. Łącząc się ze swoim kontem shellowym od czasu do czasu możesz dowiedzieć się o wszystkim, co ważnego zaszło pod twoją nieobecność. Uważaj tylko by nie logować zbyt wiele, bo plik urośnie do ogromnych rozmiarów i będą problemy.

2.1.2. Polecenia wyjściowe

Jak się zapewne domyślasz, najważniejsza w programowaniu bota jest możliwość wysyłania różnych informacji na serwer celem ich przekazania jako wypowiedź lub inne polecenie do danej osoby czy na podany kanał.

Polecenia wyjściowe:

puthelp <text>
putserv <text>
putquick <text>
Wydaje się proste, tylko po co aż trzy?

Aby to wyjaśnić, powiedzieć musimy sobie o tym, w jaki sposób Eggdrop wysyła takie komunikaty. Nie są one wysyłane natychmiast, tylko trafiają do specjalnej kolejki. Wiąże się z tym kilka spraw:

Szczególną uwagę zwracam na to usuwanie powtarzających się komunikatów. Trzeba o tym pamiętać aby później nie dziwić się, dlaczego ten sam tekst wysyłany wiele razy pojawia się tylko jeden raz.

A teraz zdradzamy całą tajemnicę: Polecenia są aż trzy, ponieważ każde ma swoją kolejkę. Kolejki te różnią się szybkością.

puthelp
Działa najwolniej. Nazwa pochodzi zapewne od wyobrażenia bota jako programu wykonującego zaprogramowane czynności w reakcji na odpowiednie polecenia. Jakiekolwiek wysyłanie informacji miałoby wtedy charakter wyświetlania pomocy z opisem dostępnych możliwości. Polecenie to służy więc do normalnego wysyłania wypowiedzi na kanał czy do konkretnej osoby.
putserv
Jest trochę wolniejsze. Nazwa tego polecenia również może być trochę myląca. Przecież wszystkie trzy tak samo wysyłają komunikat do serwera. Pochodzi ona najprawdopodobniej od przewidzianego zastosowania do wysyłania komunikatów sterujących dla serwera IRC i nie będących wypowiedziami.
putquick
To polecenie jest najszybsze. Sam nigdy go nie używałem.
No dobrze... ale właściwie co za <text> można wysyłać? Skąd wiadomo, do kogo będzie adresowany?

Ten <text> to nie jest zwykły dowolny łańcuch. To jeden z dostępnych komunikatów IRC. Za ich pomocą możesz robić wszystko, np. pingować osoby czy kanały. Podam tutaj najprostsze zastosowania:

Przykłady wyjścia:

puthelp "PRIVMSG #lamerlandia :Czesc lamerzy!"
puthelp "PRIVMSG Lamer :cze Lamer"
puthelp "NOTICE Lamer :wassup?"

Polecenie pierwsze wypowiada podany po dwukropku tekst na podanym kanale. Drugie wypowiada podany tekst "na priv" (znany też jako "Query") do podanej osoby. Trzecie zaś wysyła do podanej osoby komunikat (ang. "message" - to ta funkcja, do której służy polecenie /msg w mIRCu).

Zwróć uwagę, że spacja musi być przed dwukropkiem, a nie za nim.

Zaraz zaraz... PRIVMSG to jest "priv", a NOTICE to jest "msg"?

No niestety. Znowu wszystko jest pokręcone i trzeba się tego nauczyć.

2.2. Procedury

Nie da się napisać niczego sensownego wywołując jedynie kolejne polecenia. W każdym języku programowanie istnieje możliwość tworzenia własnych podprogramów. W TCL nazywamy je zawsze procedurami.

Deklaracja procedury:

proc { [parametry] } {
  <kod>
}

Przykład procedury:

proc ZapiszBleDoLoga { } {
  putlog "Ble"
}

Procedurę wywołuje się dokładnie tak, jak wbudowane polecenia. Wywołanie składa się z nazwy procedury oraz oddzielonych od niej i od siebie nawzajem odstępami kolejnych parametrów w odpowiedniej ilości.

Kolejność deklaracji procedur nie ma wpływu na możliwość ich wywoływania. Procedura A może wywołać procedurę B nawet, jeśli ta zadeklarowana jest dopiero poniżej.

2.2.1. Parametry

Jako parametry należy podać listę oddzielonych przecinkami nazw. Dzięki nim procedura może odbierać dodatkowe informacje potrzebne do odpowiedniego wywołania. Parametry można wykorzystywać w kodzie procedury pobierając ich wartość za pomocą operatora $.

Przykład wykorzystania parametrów:

proc ZapiszDoLoga {a_sText} {
  putlog $a_sText
}

ZapiszBleLoga "Blebleble"

Na końcu listy parametrów mogą się znaleźć parametry domyślne. Deklaruje się je zapisując zamiast samej nazwy parametru taką konstrukcję:

Deklaracja parametru domyślnego:

{<nazwa> <wartość-domyślna>}

Przykład wykorzystania parametrów domyślnych:

proc ZapiszDoLoga2 {a_sText {a_iLiczba 7}} {
  putlog "Twoja $a_sText liczba to: $a_iLiczba"
}

Następujące wywołania tej procedury:

Wywołania procedury z parametrem domyślnym:

ZapiszDoLoga2 "szczesliwa"
ZapiszDoLoga2 "pechowa" 13

- spowodują dopisanie do loga:

eggdrop.log:

Twoja szczesliwa liczba to: 7
Twoja pechowa liczba to: 13

Jak widać, parametr domyślny można pominąć w wywołaniu. Za jego wartość przyjęta zostanie wówczas wartość domyślna.

Jest też możliwość tworzenia procedur przyjmujących dowolną liczbę dodatkowych parametrów. Jako nazwę ostatniego parametru podać należy args. Po szczegóły odsyłam do podręcznika języka TCL, pod hasło proc.

Zapamiętaj, że pomiędzy nazwą procedury a nawiasem klamrowym otwierającym listę jej parametrów musi być odstęp!

2.2.2. Zwracanie wartości

Procedura może zwracać wartość, którą można potem wykorzystać dzięki zagnieżdżaniu poleceń. Służy do tego polecenie:

Polecenie do zwracania wartości:

return <wartość>

Wywołanie tego polecenia w dowolnym miejscu kodu procedury powoduje natychmiastowe zakończenie jej działania i wyjście z niej ze zwróceniem podanej wartości. Jeśli procedura zakończy się bez wywołania tego polecenia, jako zwracana wartość przyjęty zostanie łańcuch pusty.

2.2.3. Piszemy procedurę Debug

Nietrudno dojść do wniosku, że ciągłe zaglądanie do logów to nienajlepszy sposób debugowania. Dużo lepiej byłoby mieć polecenie, które niemal natychmiast poinformowałoby nas o tym, o czym chcielibyśmy się dowiedzieć. Idealnie nadaje się do tego przesyłanie prywatnych wiadomości na IRCu. Dlatego stworzyłem sobie kiedyś taką procedurkę:

Procedura Debug:

proc Debug {aText} {
  puthelp "PRIVMSG Nick :\[DEBUG\] $aText"
}

W miejsce Nick wpisz swoją ksywę z IRCa. Radzę wstawiać tą procedurę na początku każdego pisanego skryptu.

Jej użycie polega na wstawieniu w odpowiednich miejscach kodu jej wywołania z odpowiednim parametrem. Dzięki temu niemal od razu dostaniesz przez IRC od swojego bota prywatną informację, z której dowiesz się co, kiedy, w jakiej kolejności i z jakimi wartościami się w skrypcie wywołało. Pomoże to znajdować i usuwać błędy.

Nie zapomnij, że Eggdrop usuwa z kolejki wyjściowej powtarzające się komunikaty wysyłając je tylko raz!

2.2.4. Nazwy procedur

Nazwy procedur mogą być zupełnie dowolne. Często stosuje się w nich np. dwukropek :. Nazwy procedur z poszczególnych skryptów TCL używanych przez Eggdropa nie kolidują ze sobą.

Tak jak każda instrukcja TCL jest poleceniem, tak samo każdy łańcuch może zawierać znaki specjalne takie, jak [] czy $. Dzięki temu nazwę procedury do uruchomienia można nawet pobrać ze zmiennej czy złożyć z kilku członów. Jeśli zmienna $s1 przechowuje łańcuch Moja, a zmienna $s2 przechowuje łańcuch Procedura to wywołanie:

Dziwne wywołanie procedury:

$s2$s2 "Ble"

- spowoduje wywołanie procedury o nazwie MojaProcedura z parametrem "Ble".

2.3. Bindowanie

Teraz, kiedy znamy już procedury, możemy przejść do sedna sprawy. Bindowanie zdarzeń powoduje, że Eggdrop wywoła napisane przez nas procedury w reakcji na poszczególne zdarzenia.

Składnia polecenia do bindowania:

bind <type> <flags> <keyword/mask> <proc-name>
type
To typ zdarzenia np. wypowiedź na kanale, zmiana tematu kanału, wejście kogoś na kanał.
flags
To flagi, jakie posiadać musi powodujący zdarzenie użytkownik, by zdarzenie zaszło. Przypomnij sobie rozdział o użytkownikach i flagach. Najczęściej używane wartości to:
n
Zdarzenie może wywołać tylko właściciel (owner) tego bota, czyli ty. Przydatne, kiedy chodzi o jakieś polecenie sterujące botem.
-
Zdarzenie może wywołać każdy. Przydatne, kiedy chodzi o zwykłe zdarzenia IRC np. zareagowanie na każdą wypowiedź na kanale.
keyword/mask
To słowo kluczowe lub maska, którego wystąpienie w tekście będzie warunkiem zajścia zdarzenia. Szczegóły zależą od typu zdarzenia. W masce można używać znaków zastępczych (ang. "wildcards"):
?
Zastępuje dowolny, pojedynczy znak.
*
Zastępuje dowolną liczbę (także zero) dowolnych znaków.
Często używa się jako maski pojedynczej gwiazdki *, by zdarzenie zaszło dla każdego tekstu. Inne możliwe konstrukcje maski to np. *słowo*, która szuka wystąpienia podanego słowa w dowolnym miejscu tekstu.
proc-name
To nazwa procedury, która wywoływana będzie w reakcji na dane zdarzenie.

Bindowana procedura musi mieć odpowiednie parametry zależnie od rodzaju bindowanego zdarzenia. Dostępne typy zdarzeń oraz odpowiadające im wymagane parametry procedur znajdziesz w dokumentacji dołączonej do Eggdropa, w dokumencie "Eggdrop TCL Commands", w rozdziale 11.

W dokumentacji niektórych rodzajów zdarzeń pisze (stackable). Oznacza to, że na dane zdarzenie zakładać można wiele bindów, a odkładane będą one na specjalny stos i wywoływane wszystkie po kolei.

Mam jeszcze dobrą wiadomość. Jeśli podczas wykonywania kodu reagującego na zbindowane zdarzenie wystąpi błąd, Eggdrop nie wysypie się. Po prostu wykonywanie kodu zostanie przerwane, a do loga i w sesji Telnet dopisany zostanie komunikat o błędzie. Nie przeszkadza to możliwości dalszego zachodzenia tego samego lub innych zdarzeń.

2.3.1. MSG i PUB

Te zdarzenia służą do wydawania poleceń. Wypowiadany odpowiednio na "pirv" lub za pomocą /msg (MSG) oraz publicznie na kanale (PUB) tekst dzielony jest na pierwsze słowo (do pierwszego odstępu) traktowane jako nazwa polecenia oraz pozostałą część traktowaną jako parametry polecenia. Wielkość liter nie ma znaczenia dla rozpoznania lub nierozpoznania danego polecenia.

Przykład dla zdarzenia MSG:

proc OnLoguj {a_sNick a_sUserHost a_hHandle, a_sText} {
  putlog $a_sText
}

bind msg n "loguj" OnLoguj

Kiedy napiszesz do swojego bota np. loguj Tralalala, wywołana w reakcji na zdarzenie przypisane poleceniu loguj procedura dopisze do loga tekst Tralalala.

Parametry przekazywane do procedury obsługującego tego rodzaju zdarzenie mają następujące znaczenie:

a_sNick
To nick osoby, która wydała polecenie.
a_sUserHost
To łańcuch o budowie <user>@<host> również odnoszący się do osoby wydającej polecenie, np. w moim przypadku jest to ~sawickiap@frodo.i.czest.pl.
a_hHandle
Specjalny uchwyt do konta użytkownika, jeśli osoba, która wydała polecenie, zidentyfikowana została przez bota jako jego zarejestrowany użytkownik.
a_sText
To parametry polecenia, czyli część wypowiedzianego tekstu rozpoczynająca się po pierwszym odstępie.

2.3.2. MSGM i PUBM

Poprzednie zdarzenia służyły do reagowania na konkretne polecenia. Te natomiast pozwalają reagować na dowolny wypowiadany tekst pasujący do podanej maski. W przypadku PUBM dopasowywany do maski tekst składa się z nazwy kanału oraz następującej po nim pełnej treści wypowiedzi.

Przykład dla zdarzenia PUBM:

proc OnPubm {a_sNick a_sUserHost a_hHandle a_sChannel a_sText} {
  puthelp "NOTICE Nick :Hej, na kanale $a_sChannel mowia o tobie!"
}

bind pubm - "*Nick*" OnPubm

W powyższym kodzie w miejsce Nick wstaw swój pseudonim, a będziesz informowany poprzez wiadomość, kiedy na jednym z kanałów, na których przebywa bot, ktoś go wypowie.

2.3.3. TOPC

To zdarzenie zachodzi, kiedy ktoś zmienia temat kanału. Wspomniałem o nim by zaznaczyć, że chcąc katalogować kolejne tematy nie musisz osobno zajmować się tematem, jaki jest w momencie wchodzenia bota na kanał. Zdarzenie to bowiem wykonuje się także w momencie wchodzenia na kanał.

2.4. Timery

Timer (lub jak kto woli: licznik, zegar) pozwala wywołać podane polecenie po podanym czasie.

Polecenia do tworzenia timera:

timer <czas> <polecenie>
utimer <czas> <polecenie>

Czas to liczba wyrażona w minutach (timer) lub sekundach (utimer). Po podanym czasie jednorazowo wykonane zostanie podane polecenie. Po jego wykonaniu timer znika, a nie wywołuje się cyklicznie co jakiś czas.

Warto podkreślić pewną różnicę: Podczas bindowania zdarzeń jako ostatni parametr podawaliśmy samą nazwę procedury. Procedura musiała mieć odpowiednie parametry i te parametry były wypełniane przez Eggdropa różnymi ciekawymi informacjami. W przypadku timerów podaje się całe polecenie do wykonania. Musi to być sama nazwa procedury, jeśli procedura nie ma parametrów lub wywołanie razem ze wszystkimi potrzebnymi parametrami.

Powyższe funkcje zwracają wartość będącą identyfikatorem utworzonego timera. Timer taki można, o ile nie zdążył jeszcze się wykonać i tym samym nie zniknął, usunąć poleceniem:

Polecenia do usuwania timera:

killtimer <TimerID>
killutimer <TimerID>

Warto wiedzieć, że są też polecenia timers i utimers, które zwracają listy utworzonych timerów.

2.4.1. Problem

W związku z podawaniem całego polecenia do wykonania istnieje pewien problem. Chodzi o znaki specjalne rozpoznawane w łańcuchach.

Wyobraź sobie, że chciałbyś, aby za jakiś czas wykonana została procedura Costam z parametrem w postaci łańcucha o treści [NIC]. Łańcuch zawiera nawiasy kwadratowe i chcielibyśmy, aby potraktowane zostały jako zwykłe znaki a nie jako znaki specjalne powodujące wykonanie (nieistniejącego przecież) polecenia.

W tym celu polecenie wywoływane przez timer powinno mieć postać: Costam \[NIC\]. Aby jednak ukośnik nie spowodował zintepretowania nawiasów już podczas deklaracji timera i nie w efekcie nie poskutkował zinterpretowaniem tych nawiasów jako znaków specjalnych już podczas wywoływania polecenia przez timer, dołożyć trzeba dodatkowe ukośniki.

Ostatecznie polecenie tworzące timer wyglądałoby więc tak: timer 60 "Costam \\\[NIC\\\]"

Ale to bez sensu! Naprawdę muszę się zajmować takimi głupotami?

Niekoniecznie. Dużo prościej jest wywoływać jako polecenia timera zawsze tylko zwykłe bezparametrowe procedury. Zazwyczaj to wystarcza.

2.4.2. Przykład - cykliczne timery

Spróbujemy teraz zrobić timer, który będzie wykonywał się cyklicznie co minutę. W tym celu trzeba tworzyć nowy timer na końcu procedury wywołanej przez stary.

Przykład timera cyklicznego:

proc SetTimer { } {
  timer 1 OnTimer
}

proc OnTimer { } {
  Debug "Minela kolejna minuta"
  SetTimer
}

SetTimer

Utworzenie timera potrzebne jest w dwóch miejscach: w samej treści skryptu (w momencie jego uruchamiania) oraz na końcu procedury OnTimer. Rozsądne było więc wydzielenie tego kodu do osobnej procedury zamiast jego powielania.

Powyższy przykład posłuży nam do zaznaczenia dwóch istotnych rzeczy. Po pierwsze: Jeśli podczas wykonywania kodu procedury OnTimer (lub dowolnej przez nią wywołanej) wystąpi błąd, Eggdrop podobnie jak w przypadku bidnowanych zdarzeń nie wysypie się, a tylko przerwie wykonywanie tej procedury. Oczywistą konsekwencją będzie niewykonanie ostatniej instrukcji, która tworzy nowy timer. Dzięki temu błędny kod nie będzie więcej razy wykonywany.

Po drugie: Zapamiętać musisz, że timery nie są usuwane po .rehash. Tymczasem ostatnia instrukcja powyższego kodu za każdym razem utworzy nowy. Powstanie wtedy, niestety, wiele cyklicznie wykonujących się timerów. W efekcie procedura OnTimer wywoływana będzie dużo częściej, niż co minutę.

Jak temu zaradzić?

Rozwiązaniem jest usuwanie bieżącego timera przed .rehash. Wymagałoby to jednak zapamiętania jego uchwytu w zmiennej. Zrobimy to, ale w następnej części, jak tylko poznamy zmienne.

2.5. Strefy nazw

TCL jest językiem strukturalnym i bardzo brakuje w nim programowania obiektowego. Pewną organizację kodu można sobie jednak zapewnić dzięki strefom nazw (ang. "namespaces").

2.5.1. Deklaracja strefy nazw

Deklaracja strefy nazw:

namespace eval <nazwa> {
  <treść>
}

Treścią może być wszystko to, co mogło być napisane w zwykłej treści skryptu. Dopuszczalne są więc wywołania poleceń, a także deklaracje własnych procedur.

Kod (wywołania poleceń) umieszczony bezpośrednio wewnątrz namespace (nie jako treść procedur) zostanie w danym miejscu wywołany tak samo, jak zostałby, gdyby tej strefy w ogóle nie było.

2.5.2. Operator zakresu

Operatorem zakresu pozwalającym na dostęp do składników strefy (procedur i zmiennych) jest tzw. czterokropek zapisywany jako dwa dwukropki ::. Może wydawać się dziwny, ale miłośnicy języka C++ doskonale go znają.

Aby uzyskać dostęp do składnika strefy nazw, trzeba napisać jakby ścieżkę do niego. Namespaces można w sobie zagnieżdżać, więc ścieżka może składać się z szeregu elementów. Zapisujemy ją jako nazwę strefy, operator zakresu, nazwę podstrefy, znowu operator itd., a w końcu po operatorze nazwę elementu, o który nam chodzi. Operator zakresu można też wstawić na początku takiej "ścieżki".

Z kodu procedury zawartej w strefie nazw można bez użycia operatora zakresu wywoływać zarówno inne procedury z tej samej strefy, jak i procedury globalne (nie zawarte w żadnej strefie). Z kodu procedury globalnej można wywołać procedurę zawartą w strefie używając operatora zakresu.

2.5.3. Przykład

Przykład strefy nazw:

namespace eval MyNS {
  proc Proc2 { } {
    # W procedurze w namespace wywołuję procedurę globalną
    Debug "No i sie wykonalo :)"
  }

  proc Proc1 { } {
    # W procedurze w namespace wywołuję procedurę z tej samej namespace
    Proc2
  }
}

proc OnTest {a_sNick a_sUserHost a_hHandle, a_sText} {
  # W procedurze globalnej wywołuję procedurę z namespace
  MyNS::Proc1
}

bind msg n "test" OnTest

2.6. PROJEKT - identify

Umiemy już wystarczająco dużo, by napisać pierwszy kompletny i naprawdę użyteczny skrypt.

W sieciach IRC posiadających usługi (jak PolNet) nicki można rejestrować. Zarejestrowanego nicka nikt nam nie odbierze, a bycie zarejestrowanym i zidentyfikowanym może być warunkiem otrzymywania auto-opa od ChanServa.

Najpierw trzeba zarejestrować ksywę. Sam nie możesz tego zrobić, musi to zrobić twój bot. W tym celu połącz się do niego Telnetem i wydaj polecenie podobne do tego:

Bot rejestruje swój nick:

.msg NickServ register moje-haslo

Teraz pora napisanie właściwego skryptu. Jego zadaniem będzie identyfikacja bota po każdym uruchomieniu.

Jest jeszcze jedna sprawa. Chcielibyśmy, by bot dzięki byciu zidentyfikowanym mógł dostać auto-opa po wejściu na twój kanał. Problem w tym, że wchodzenie na zapisane w konfiguracji kanały oraz wykonywanie skryptów dzieje się jednocześnie i nigdy nie wiadomo, co będzie pierwsze. Zapewne zależy to od fazy księżyca :) Tak więc może się zdarzyć, że w chwili wchodzenia na kanał bot nie będzie jeszcze zidentyfikowany.

Jak sobie z tym poradzić?

Możnaby pomyśleć coś w kierunku wyjścia i ponownego wejścia na kanał, ale to chyba raczej na pewno nienajlepsze rozwiązanie :) Dużo lepiej wydać po zidentyfikowaniu się polecenie przyznania opa przez ChanServa. Jeśli bot nie miał opa, to go wtedy dostanie.

identify.tcl:

bind evnt - init-server identify

proc identify {a_sType} {
  putserv "PRIVMSG NickServ :identify moje-haslo"
  putserv "PRIVMSG ChanServ :op #moj-kanal"
}
Adam Sawicki
[Download] [Dropbox] [pub] [Mirror] [Privacy policy]
Copyright © 2004-2021