Skocz do zawartości

Witamy w Nieoficjalnym polskim support'cie AMX Mod X

Witamy w Nieoficjalnym polskim support'cie AMX Mod X, jak w większości społeczności internetowych musisz się zarejestrować aby móc odpowiadać lub zakładać nowe tematy, ale nie bój się to jest prosty proces w którym wymagamy minimalnych informacji.
  • Rozpoczynaj nowe tematy i odpowiedaj na inne
  • Zapisz się do tematów i for, aby otrzymywać automatyczne uaktualnienia
  • Dodawaj wydarzenia do kalendarza społecznościowego
  • Stwórz swój własny profil i zdobywaj nowych znajomych
  • Zdobywaj nowe doświadczenia

Dołączona grafika Dołączona grafika

Guest Message by DevFuse
 

Zdjęcie
- - - - -

[Challenge] Gotowce i przykłady


  • Nie możesz napisać tematu
  • Zaloguj się, aby dodać odpowiedź
12 odpowiedzi w tym temacie

#1 R3X

    Godlike

  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 29.06.2011 19:33

*
Popularny

Odnośnie platformy Challenge

Za namową Kapuchy112 >> tworzę miejsce publikowania wyzwań. Zacznę od ogólnego wprowadzenia do pisania wyzwań, potem w miarę możliwości będę uzupełniał listę o to gotowe pluginy, czyli to co mi lub Wam przyjdzie do głowy. Propozycje ciekawych wyzwań i nagród można wysłać mi na PW z tagiem [Challenge] lub w tym temacie


Opisy na podstawie wersji 1.5, jednak zgodność z 1.4 jest prawie zupełna

Wprowadzenie

Gotowce

  • +
  • -
  • 5

#2 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 29.06.2011 20:33

*
Popularny

Szkielet


Krok 1

Na początku załączamy plik challenge.inc do naszego pluginu i rejestrujemy wyzwanie

#include <amxmodx>
#include <amxmisc>
#include <challenge>

#define PLUGIN "Challenge : Wprowadzenie"
#define VERSION "1.0"
#define AUTHOR "R3X"


public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR);
	
	register_challenge("Wykonaj zadanie", "to dostaniesz nagrode");
}
Efektem tej linijki jest dodanie nowego wyzwania do listy, jak na screenie poniżej
Dołączona grafika
Zadania nie można wykonać, postęp tym bardziej nie jest monitorowany, stąd czerwone "brak danych"




Krok 2

Teraz wymyślamy cel wyzwania. Na początek niech będzie to pewna ilość zabójstw z M4. Wygodnie jest użyć pomocniczej funkcji, której wynik decyduje wprost czy spełniliśmy wymagania.
stock hasAccess(id){
	return (ch_get_user_stats(id, CSW_M4A1) >= 100);
}
Taka funkcja zwraca prawdę tylko jeśli ilość zabójstw z M4 jest większa lub równa 100. (słowo kluczowe stock jest tu po to, żeby kod w obecnym stanie kompilował się bez ostrzeżeń)
jeśli jako 3 parametr ch_get_user_stats() podamy wartość różną od 0 to funkcja zwróci liczbę samych headshowtów

ch_get_user_stats() zwraca dane zapisane w bazie; sam pomysł dotyczył lekkiej wersji statystyk, z tego względu sam Challenge.amxx automatycznie zbiera informacje jedynie o czasie przebywania gracza na serwerze, pozostałe funkcje musimy włączyć ręcznie. Do zapisywania zabić ze standardowych broni służy funkcja
native challenge_uses_stats(wid);
gdzie wid jest identyfikatorem broni CSW_*

Póki co ch_get_user_stats() zawsze zwraca 0, w rezultacie hasAccess zawsze zwraca fałsz. Włączmy więc zapisywanie statystyk M4, a otrzymamy poniższy kod:
#include <amxmodx>
#include <amxmisc>
#include <challenge>

#define PLUGIN "Challenge : Wprowadzenie"
#define VERSION "1.0"
#define AUTHOR "R3X"


public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR);
	
	register_challenge("Zabij 100 graczy z M4", "to dostaniesz nagrode");
	challenge_uses_stats(CSW_M4A1);
}

stock hasAccess(id){
	return (ch_get_user_stats(id, CSW_M4A1) >= 100);
}




Krok 3

Monitorowanie postępu wymaga doklejenia do naszego kodu funkcji publicznej challenge_progress()
public challenge_progress(id, challenge, szProgress[], size){
}
to co wpiszemy do szProgress[] zostanie pokazane w tabelce
public challenge_progress(id, challenge, szProgress[], size){
	formatex(szProgress, size, "Wskaznik postepu");
}
wynikiem tego jest:Dołączona grafika


Jak umieścić tam coś sensownego? Na przykład dać łamańca

tylu zabiłeś/ tyle wymagamy

//Postep wyzwania
public challenge_progress(id, challenge, szProgress[], size){
	formatex(szProgress, size, "%d/%d", ch_get_user_stats(id, CSW_M4A1), 100);
}

Co jeśli gracz już zabił tych 100 graczy z emki? Do oznaczenia wyzwania jako zaliczonego służy funkcja
native challenge_done(id, chid, showinfo = 1);
id to indeks gracza, chid to indeks wyzwania a showinfo 1|0 decyduje o tym, czy pokazana zostanie informacja (0 oczywiście załatwia sprawę po cichu :))

chid jest zwracany przez register_challenge()


Są 2 przypadki zaliczonego zadania:
- gracz wszedł do gry z zaliczonym już zadaniem:

tuż po załadowaniu danych z bazy wykonywana jest funkcja
public client_data_loaded(id){
}
Tutaj wystarczy sprawdzić czy gracz spełnia warunki wyzwania i ewentualnie zaliczyć mu zadanie po cichu
//aktualizacja tabeli od razu przy podlaczeniu sie gracza
public client_data_loaded(id){
	if(hasAccess(id))
		challenge_done(id, chid, 0); //wykonanie bez informacji
}
Teraz bez pytania o postęp w tabelce pokaże się zielone OK.


- gracz zaliczył zadanie na tej mapie

tutaj sprawa się nieco komplikuje, podobnie jak moment odczytu także moment zdobycia punktu jest sygnalizowany, odpowiada za to funkcja
public client_gain_point(id, wid, hs){
}

Dodajmy zmienną pilnującą czy danych gracz wykonał już zadanie, żeby można było go poinformować o spełnieniu warunków od razu. Tablica typu bool:
new bool:gbDone[33];
czyszczona przy łączeniu się gracza z serwerem załatwi sprawę. Dobierzmy dobry warunek w tym forwardzie i gotowe. Po pierwsze czy gracz już wykonał zadanie, jeśli tak nic tu po nas. Potem warto sprawdzić id broni, bo jeśli dostał punkt od innej to na bank nie zdobył nagrody :) na końcu oczywiście hasAccess(id)
//Postep wyzwania w grze
public client_gain_point(id, wid, hs){
	if(!gbDone[id] && wid == CSW_M4A1 && hasAccess(id){
		challenge_done(id, chid); //wykonanie z informacja
		gbDone[id] = true;
	}
}


--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Cały kod wygląda teraz tak jak w załączniku
Te 50 linijek realizuje wszystko co potrzebne jest do podstawowego zadania....oprócz nagrody :) o tym wkrótce, bo jestem głodny

Załączone pliki


  • +
  • -
  • 5

#3 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 30.06.2011 12:13

Niestandardowe bronie

Plugin umożliwia zapisywanie statystyk dowolnej broni w grze. Fragi są zliczane przy każdej wiadomości DeathMsg (lista zabójstw w prawym, górnym rogu). Aby to działało plugin musi mieć możliwość złapania tej wiadomości. Dobrym sposobem jest skompilowanie Challenge z wykorzystaniem modułu Orpheu, jednak wtedy musi on być zainstalowany na serwerze.

znajdź
//#define USING_ORPHEU
zamień na
#define USING_ORPHEU
i przekompiluj

Jeśli nie chcemy angażować orpheu równie skuteczne jest rozsyłanie wiadomości funkcją emessage_begin(), wtedy w naszym pluginie dodającym broń trzeba znaleźć fragment odpowiedzialny za DeathMsg. W przykładzie użyłem head_splash, a w nim znajduje się funkcja:
_make_deathmsg(pwnzor, pwned, hs, const szWeapon[]){
	static msgDeathMsg=0;
	if(!msgDeathMsg)
		msgDeathMsg = get_user_msgid("DeathMsg");
	message_begin(MSG_ALL, msgDeathMsg);
	write_byte(pwnzor);
	write_byte(pwned);
	write_byte(hs);
	write_string(szWeapon);
	message_end();
}
zamiast tych funkcji trzeba użyć ich odpowiedników z e na początku, czyli to
_make_deathmsg(pwnzor, pwned, hs, const szWeapon[]){
	static msgDeathMsg=0;
	if(!msgDeathMsg)
		msgDeathMsg = get_user_msgid("DeathMsg");
	emessage_begin(MSG_ALL, msgDeathMsg);
	ewrite_byte(pwnzor);
	ewrite_byte(pwned);
	ewrite_byte(hs);
	ewrite_string(szWeapon);
	emessage_end();
}


Dzięki jednemu i drugiemu wyjściu możemy być pewni, że statystyki będą liczone.



Jak to wykorzystać w wyzwaniu? Wystarczy przypisać nowej broni numer do statystyk funkcją
challenge_custom_weapon("nazwa broni");
to nam zwróci indeks, który potem używamy tak jak indeksy innych broni CSW_*; nazwa to parametr szWeapon[] z _make_deathmsg(), czyli to co się pokazuje w konsoli po zdobyciu fraga daną bronią
R3X killed SomeOne with <nazwa broni>

Zabójstwa z head_splasha mają nazwę broni "his/her feet :)", więc kod wygląda tak:
CSW_HEADSPLASH = challenge_custom_weapon("his/her feet <img src='http://img.amxx.pl/public/style_emoticons/<#EMO_DIR#>/smile.gif' class='bbc_emoticon' alt=':)' />");

Całość od szkieletu różni się tym fragmentem:
new CSW_HEADSPLASH;

public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR);
	
	chid = register_challenge("Zabij 100 graczy z HeadSplash", "to dostaniesz nagrodę");
	CSW_HEADSPLASH = challenge_custom_weapon("his/her feet <img src='http://img.amxx.pl/public/style_emoticons/<#EMO_DIR#>/smile.gif' class='bbc_emoticon' alt=':)' />");
	challenge_uses_stats(CSW_HEADSPLASH);
}

//czy spełnia wymagania
stock hasAccess(id){
	return (ch_get_user_stats(id, CSW_HEADSPLASH) >= 100);
}

Załączone pliki


  • +
  • -
  • 4

#4 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 30.06.2011 23:26

Samodzielne zliczanie

Jeśli chcemy zliczać punkty czegoś innego niż zabójstwa potrzebujemy zarezerwować indeks w statystykach. Robi się to tak samo jak w przypadku niestandardowych broni, funkcją:
challenge_custom_weapon(const szWeapon[])
zwraca ona odpowiedni indeks.

Jednak zamiast wyczekiwać na fragi z takiej broni, będziemy ręcznie dodawać punkty za pomocą:
ch_add_user_stats(id, wid, hs=0)
id to indeks gracza
wid to indeks broni
hs 1|0, z headshotem lub bez

W przypadku własnych statystyk możemy potraktować punkty z hs i bez jako 2 niezwiązane ze sobą pola.

Możemy np jako jedną broń zapisywać dane o podłożonych i rozbrojonych bomb:
new CSW_BOMBA;

public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR);
	
	chid = register_challenge("Rozbroj lub podloz 100 bomb", "to dostaniesz nagrodę");
	CSW_BOMBA= challenge_custom_weapon("paka");
}

//czy spełnia wymagania
stock hasAccess(id){
	return (ch_get_user_stats(id, CSW_BOMBA) + ch_get_user_stats(id, CSW_BOMBA, 1) >= 100);
}

public bomb_planted(id){
	ch_add_user_stats(id, CSW_BOMBA);//dodaj punkt
}

public bomb_defused(id){
	ch_add_user_stats(id, CSW_BOMBA, 1);//dodaj punkt
}

I w ten sposób 'zabicia z paki' oznaczają podłożone, a 'zabicia z paki headshotem' oznaczają rozbrojone paki


Funkcja ch_add_user_stats() działa dla wszystkich dostępnych statystyk, więc można nią rozdawać bonusy/nieco oszukiwać :P

Załączone pliki


  • +
  • -
  • 3

#5 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 30.06.2011 23:43

Nagrody (ogólnie)

No i najciekawsza część wyzwania - nagroda. Tutaj w końcu można się wykazać. Nagrodą może być wszystko, jeśli przejdzie test funkcji hasAccess(), przypominam:
stock hasAccess(id){
	return (ch_get_user_stats(id, CSW_M4A1) >= 100);
}
to właśnie hasAccess() decydowało o tym, czy przyznać gracz zaliczył zadanie. Jeśli używasz szkieletu sprzed kilku postów to globalna tablica w kodzie była zsynchronizowana ze stanem tej funkcji.
new bool:gbDone[33];

Zanim przyznamy nagrodę wystarczy sprawdzić hasAccess() lub wartość gbDone[] (jeśli mamy ją w kodzie). I tyle.

Możemy wykorzystać np.:

Zdobycie wyzwania (jednorazowo)
public client_gain_point(id, wid, hs){
	if(!gbDone[id] && hasAccess(id)){

		//Daj nagrodę	

		challenge_done(id, chid); //wykonanie z informacja
		gbDone[id] = true;
	}
}

Spawn
#include <hamsandwich>

public plugin_init(){
	RegisterHam(Ham_Spawn, "player", "fwSpawn", 1);
}

public fwSpawn(id){
	if(is_user_alive(id) && hasAccess(id)){
		//Daj nagrodę	
	}
}

Bonus z innego pluginu
jeśli np. mamy plugin dający spadochron lub dodatkowe obrażenia to

public uzyjBonusu(){
	if(!hasAccess(id)) return;
	
	//..
	//Normalny przebieg bonusowej funkcji <img src='http://img.amxx.pl/public/style_emoticons/<#EMO_DIR#>/smile.gif' class='bbc_emoticon' alt=':)' />
}

  • +
  • -
  • 2

#6 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 30.06.2011 23:48

Dobra skończyłem wprowadzenie, teraz się zaczną gotowe wyzwania :) Lista będzie w 1 poście, więc chyba temat może być otwarty na sugestie
  • +
  • -
  • 0

#7 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 01.07.2011 21:33

Kasa co runde

W nagrodę co rundę gracz dostaje tyle dolarów na ile ustawiony jest cvar

amx_challenge_money_bonus


To co trzeba dodać (plugin_init() przekopiować zawartość do istniejącej funkcji):
#include <cstrike>

new gcvarMoneyBonus;

public plugin_init() {
	register_logevent( "eventRoundStart",2, "1=Round_Start");
	gcvarMoneyBonus = register_cvar("amx_challenge_money_bonus", "1000");
}


public eventRoundStart(){
	static iMaxPlayers = 0;
	if(iMaxPlayers == 0)
		iMaxPlayers = get_maxplayers();
	
	new iMoneyBonus = get_pcvar_num(gcvarMoneyBonus);
	for(new id = 1; id <= iMaxPlayers; id++)
		if(is_user_alive(id) && hasAccess(id)){
			cs_set_user_money(id, cs_get_user_money(id)+iMoneyBonus);
			
			//Odkomentuj jesli chcesz pokazywac graczowi info
			//challenge_done(id, chid);
		}
}

W załączniku pełen przykład

Załączone pliki


  • +
  • -
  • 1

#8 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 01.07.2011 21:46

Ciche chodzenie do końca mapy

Po ukończeniu wyzwania gracz do końca mapy będzie chodził cicho


To należy dodać/ ew. uzupełnić jeśli funkcje już istnieją
#include <fun>
#include <hamsandwich>

new bool:gbSilent[33];

public plugin_init() {
	RegisterHam(Ham_Spawn, "player", "fwSpawn", 1);
}

public client_connect(id){
	gbSilent[id] = false;
}

//Postep wyzwania w grze
public client_gain_point(id, wid, hs){
	if(!gbDone[id] && wid == CSW_M4A1 && hasAccess(id)){

		//Te 2 linijki
		set_user_footsteps(id);
		gbSilent[id] = true;

		
		challenge_done(id, chid); //wykonanie z informacja
		gbDone[id] = true;
	}
}

public fwSpawn(id){
	if(is_user_alive(id) && gbSilent[id])
		set_user_footsteps(id);
}

W załączniku pełen przykład

Załączone pliki


  • +
  • -
  • 1

#9 Nomaf

    Wszechpomocny

  • Użytkownik

Reputacja: 157
Profesjonalista

  • Postów:344
  • GG:
  • Imię:Mateusz
  • Lokalizacja:Polska
Offline

Napisano 03.07.2011 22:20

Ja bym proponował dodać nowe natywy: czy ktoś wykonał jakieś, konkretne zadanie, no i też jakieś ograniczenie info o zadaniach. Ja zrobiłem, że osoba, która wykonała osiągnięcie to dostaje dodatkowy damage i cały czas mi spamuje hud takimi wiadomościami, że zaliczyłem osiągnięcie.
  • +
  • -
  • 0

#10 R3X

    Godlike

  • Autor tematu
  • Przyjaciel

Reputacja: 2 987
Godlike

  • Postów:4 248
  • Lokalizacja:Nie
Offline

Napisano 03.07.2011 22:31

challenge_done ma trzeci parametr, który jak ustawisz na 0 to nie będzie spamu :)
natywów kilka dodam przy następnym wydaniu
  • +
  • -
  • 0

#11 Nomaf

    Wszechpomocny

  • Użytkownik

Reputacja: 157
Profesjonalista

  • Postów:344
  • GG:
  • Imię:Mateusz
  • Lokalizacja:Polska
Offline

Napisano 04.07.2011 19:31

Myślę jednak, że lepiej dodać forward, np: challenge_end i tam dać info o wykonaniu zadania oraz też zmianę w kodzie, że np. co 5 minut wyświetla wszystkie wykonane osiągnięcia w dHUD'zie.
  • +
  • -
  • 0

#12 Kapucha112

    Zaawansowany

  • Użytkownik

Reputacja: 92
Zaawansowany

  • Postów:135
  • Imię:Łukasz
  • Lokalizacja:Polska
Offline

Napisano 18.07.2011 18:38

Ja tam czekam na nagrodę w formie expa do war3ft , gdy zobaczymy jak to wygląda w danym modzie to łatwiej będzie edytować pod resztę.
  • +
  • -
  • 0
DiabloMod Reloaded? [90%]
Testowanie integracji poszczególnych sub-pluginów. Zwiększanie możliwości i optymalizacja kodu.
CodMod MW2 [100%]
Całkowicie nowy silnik z tworzeniem własnych klas z własnymi nazwami! Proste w obsłudze API, nie nawiązuje niczym do Codów podróbek [OGóLNODOSTĘPNYCH]. Nowy system killstreak, misje, rewardy xp, samochody, samoloty, bombowce, ekwipunek, zrzuty zaopatrzenia, npc
Testować można na moim forum :)

#13 Syczaj

    Profesjonalista

  • Użytkownik

Reputacja: 32
Życzliwy

  • Postów:156
  • Lokalizacja:Plock
Offline

Napisano 25.07.2011 13:17

Kapucha, jeśli masz komendę na dodawanie expa w war3ft, to po prostu wykonujesz ją jako nagrode przez server_cmd. (na diablo smiga)
  • +
  • -
  • 0
Dołączona grafika




Użytkownicy przeglądający ten temat: 0

0 użytkowników, 0 gości, 0 anonimowych