Problem z timerem
Najlepsza odpowiedź Gargamel 14.06.2014 17:01
Bardzo dziękuję, teraz wszystko działa
Przejdź do postu
Gargamel
13.06.2014
Dzisiaj zacząłem pisać swój pierwszy plugin do CS'a.
Wraz z poradnikami, i z dawniejszymi doświadczeniami z Pawn (pisałem skrypty do gry SAMP), napisałem coś takiego:
#include <amxmodx> #include <amxmisc> #define PLUGIN "KickBots" #define VERSION "0.1" #define AUTHOR "Pan_Gargamel" new g_kickmenu; // tworzymy zmienną globalną, uchwyt dla menu new g_kickmenu_tak; new g_kickmenu_nie; public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR); register_clcmd("say /kickbots", "kickmenu"); } public plugin_cfg() { // tworzymy menu, np. w tej funkcji, bo wykonuje się ona tylko raz na mapę g_kickmenu = menu_create("Jestes za wyrzuceniem botow?", "kickmenuhandle"); menu_additem(g_kickmenu, "Tak"); // item = 0 menu_additem(g_kickmenu, "Nie"); // item = 1 menu_setprop(g_kickmenu, MPROP_EXITNAME, "Wyjscie"); } public kickmenu(id) { for(new i=0; i<32; i++) { if(!is_user_alive(i)) continue; menu_display(i, g_kickmenu) client_print(i, print_chat, "Gracz %id% rozpoczal glosowanie o wyrzucenie botow z serwera."); CreateTimer(30.0, kickmenu_wyniki); } return PLUGIN_HANDLED; } public kickmenuhandle(id, menu, item) { // funkcja posiada trzy parametry, id gracza, uchwyt menu oraz klawisz/item/opcję, która została wybrana if(item == MENU_EXIT) { return PLUGIN_HANDLED; // zamykamy menu, generalnie nie trzeba dodawać tutaj tego warunku, ale z przyzwyczajenia ja go tutaj dodaję, zresztą czasami nawet lepiej to robić na samej górze funkcji } switch(item) { // używamy switcha, pamiętamy, że wartość klawisza/itemu/opcji zaczyna się od 0 case 0: { client_print(id, print_chat, "Zaglosowales za wyrzuceniem botow."); g_kickmenu_tak = g_kickmenu_tak + 1 } case 1: { client_print(id, print_chat, "Zaglosowales przeciwko wyrzuceniu botow."); g_kickmenu_nie = g_kickmenu_nie + 1 } } public Action:kickmenu_wyniki(Handle:timer) { if(g_kickmenu_tak > g_kickmenu_nie || g_kickmenu_nie == g_kickmenu_tak) { amx_exec @SERVER "epb_removebots" for(new i=0; i<32; i++) { if(!is_user_alive(i)) continue; client_print(i, print_chat, "[Glosowanie] Boty zostaly wyrzucone z serwera!"); } } } return PLUGIN_HANDLED; }Skrypt ma na celu robienie głosowania dla wszystkich graczy po wpisaniu /kickbots. Każdemu graczowi powinno się wyświetlić pytanie czy boty mają być wyrzucone, a jeśli po trzydziestu sekundach od startu głosowania suma głosów na tak będzie większa niż suma głosów na nie, boty zostaną wyrzucone.
Niektóre błędy udało mi się naprawić, ale kilku nie udało mi się rozwiązać:
VertekS
14.06.2014
1. Nie ma takiej funkcji jak CreateTimer. Użyj set_task.
2.
Action:kickmenu_wyniki(Handle:timer)
Zamień na:
public kickmenu_wyniki()
3. Funkcja kickmenuhandle nie jest zamknięta (brakuje nawiasu klamrowego na końcu funkcji).
4. W ten sposób nie wyrzuca się botów na serwerach CS'a. Najpierw musisz sprawdzić, czy gracz jest botem i wtedy wykonać na nim komendę AMXX - kick:
server_cmd("kick #%d ^"Gracz jest botem!^"", get_user_userid(id));
5. Po funkcji kickmenu_wyniki jest o jedna klamra za dużo.
6. Funkcja kickmenuhandle powinna zwracać wartość na końcu. Najlepiej zwrócić PLUGIN_HANDLED (i tak już nic nie robisz z tym menu po wybraniu opcji). Dodatkowo jeżeli wartość wybrana w menu to MENU_EXIT, zniszcz menu za pomocą:
menu_destroy(menu)
Kod jest brzydko napisany, ale to będziesz potrafił zoptymalizować sam p przeczytaniu artykułów w dziale tutoriale na tym forum (nie zawsze się operuje na 32 graczach / używa do tego pętli for).
GwynBleidD
14.06.2014
A to zależy od botów Niektóre po kicknięciu ich z serwera po prostu wrócą i należy wykonać komendę, która wyłącza całkowicie boty, a nie je kickować. Ale to:4. W ten sposób nie wyrzuca się botów na serwerach CS'a. Najpierw musisz sprawdzić, czy gracz jest botem i wtedy wykonać na nim komendę AMXX - kick:
amx_exec @SERVER "epb_removebots"nie jest poprawnym wykonaniem jakiejkolwiek komendy. Do tego używamy server_exec.
server_cmd("kick #%d ^"Gracz jest botem!^"", get_user_userid(id));
NIE NIE I JESZCZE RAZ NIE!! W tym przypadku menu_destroy NIE UŻYWAMY !!Dodatkowo jeżeli wartość wybrana w menu to MENU_EXIT, zniszcz menu za pomocą:
menu_destroy(menu)
menu_destroy używamy, gdy generujemy menu tuż przed jego wyświetleniem dla pojedynczego gracza i nie mamy zamiaru wyświetlać tego samego menu drugi raz. W tym przypadku menu jest generowane na początku działania pluginu i jest wyświetlane jedno dla wszystkich graczy, więc po użyciu menu_destroy będzie mógł zagłosować TYLKO JEDEN GRACZ, bo po zagłosowaniu menu już nie będzie istnieć!
Gargamel
14.06.2014
Teraz plugin kompiluje się bez żadnych błędów, lecz timer się nie uruchamia, a przynajmniej nie wykonuje się to co powinno po upłynięciu czasu.
Tutaj dałem set_task:
public kickmenu(id) { for(new i=0; i<32; i++) { if(!is_user_alive(i)) continue; menu_display(i, g_kickmenu) client_print(i, print_chat, "Gracz %id% rozpoczal glosowanie o wyrzucenie botow z serwera."); set_task(30.0, "kickmenu_wyniki", 666); } return PLUGIN_HANDLED; }
A tutaj jest to co powinno się wykonać po 30 sekundach:
public kickmenu_wyniki() { if(g_kickmenu_tak > g_kickmenu_nie || g_kickmenu_nie == g_kickmenu_tak) { server_cmd("pb removebots"); for(new i=0; i<32; i++) { if(!is_user_alive(i)) continue; client_print(i, print_chat, "[Glosowanie] Boty zostaly wyrzucone z serwera!"); } } else { for(new i=0; i<32; i++) { if(!is_user_alive(i)) continue; client_print(i, print_chat, "[Glosowanie] Boty nie zostaly wyrzucone z serwera!"); } } return PLUGIN_HANDLED; }
Użytkownik Gargamel edytował ten post 14.06.2014 13:47
VertekS
14.06.2014
Więc tak...
To co napisze poniżej piszesz w public kickmenu(id).
Tworzysz 31 elementową tablicę na nick gracza (31 elementów = 31 znaków):
new voteplayer[31];
Następnie pobierasz nick gracza, który wpisał komendę:
get_user_name(id, voteplayer, sizeof(voteplayer));
Natyw register_clcmd przekazuje ID gracza jako parametr, więc warto to wykorzystać. Parametry funkcji zobacz w dokumentacji. Operator sizeof sprawdza wielkość łańcucha znaków (i nie tylko jego), co można w tym wypadku użyć do poinformowania get_user_name, ile liter nicku gracza ma pobrać. Warto pamiętać, że nick gracza w CS może mieć maksymalnie 31 liter.
Następnie przejdź do linii:
client_print(i, print_chat, "Gracz %id% rozpoczal glosowanie o wyrzucenie botow z serwera.");
...która była powodem błędów. ID gracza w CS jest traktowane jak zwykła liczba całkowita. Trzeba tylko pamiętać, że to musi być liczba z zakresu 1 - 32.
W celu wyświetlenia, kto zaczął głosowanie wykorzystaj wcześniej przygotowaną zmienną na nick. Poprawny zapis wygląda tak:
client_print(i, print_chat, "Gracz %s rozpoczal glosowanie o wyrzucenie botow z serwera.", voteplayer);
Plugin będzie działać w 99% poprawnie. Podczas testów zauważyłem, że musisz się zabezpieczyć przed sytuacją, kiedy żaden gracz nie głosuje (obecnie w takiej sytuacji boty są wyrzucane z serwera).
Użytkownik VertekS edytował ten post 14.06.2014 16:41