Operacje na obrażeniach
Fili:P
18.02.2013
W tym poradniku postaram się opisać kilka operacji związanych z obrażeniami.
Wstęp
- Opis argumentów funkcji RegisterHam
- Argument 1 = Ham_TakeDamage: Ten argument oznacza jakie zdarzenie chcemy "złapać". Skoro chcemy przechwycić zadawanie obrażeń, będzie to Ham_TakeDamage.
- Argument 2 = "player": Drugi argument oznacza klasę u której chcemy "złapać" zdarzenie, w tym wypadku zadanie obrażeń. Ta wartość oznacza gracza.
- Argument 3 = "fw_TakeDamagePre": Jest to po prostu nazwa funkcji, za pomocą której będziemy "łapać" zdarzenie.
- Argument 4: W tym wypadku nie podaje jego wartości, ponieważ jego domniemana wartość to 0. 0 oznacza, iż chcemy złapać moment przed zdarzeniem ( daje to możliwość modyfikacji parametrów zdarzenia ). 1 oznacza, że nie mamy już wpływu na przebieg zdarzenia.
2. Opis argumentów zdarzenia Ham_TakeDamage
- this - identyfikator istoty ( bytu, entu, etc. ), która otrzyma/ła obrażenia
- idinflictor - identyfikator bytu zadającego obrażenia, zwykle idinflictor == idattacker, jednak kiedy obrażenia zadaje przykładowo granat to w tym argumencie właśnie będzie jego identyfikator.
- idattacker - identyfikator osoby, istoty, bytu, etc. która atakuje this-a
- Float:damage - ilość zadawanych obrażeń ( zwróć uwagę iż jest to liczba typu float )
- damagebits - bit typ/ów zadanych obrażeń ( więcej: http://amxx.pl/topic/28881-damagebits/ )
a) Natychmiastowe zabicie z X broni:
hamsandwich amxmodx
1. Zarejestruj w plugin_init zdarzenie z modułu hamsandwich, Ham_TakeDamage.
RegisterHam( Ham_TakeDamage, "player", "fw_TakeDamagePre" );
2. "Utwórz" funkcję:
public fw_TakeDamagePre( this, idinflictor, idattacker, Float:damage, damagebits )
{
// tu będzie kod
}
3. Wewnątrz funkcji, sprawdź czy this i idattacker żyją:
if( !is_user_alive( idattacker ) || !is_user_alive( this ) )
return HAM_IGNORED;
4. Jeżeli chcesz, aby było natychmiastowe zabicie z granatu dodaj taki warunek:
if( idinflictor == idattacker )
return HAM_IGNORED;
if( !(damagebits & (1<<24) ) )
return HAM_IGNORED;
- Teraz dodajemy natychmiastowe zabicie z HE:
SetHamParamFloat( 4, float( get_user_health( this ) + 1) );
return HAM_HANDLED;
- Jeżeli chcesz mieć ułamkową szansę na natychmiastowe zabicie przed powyższym kodem dodaj:
if( !random( X ))
return HAM_IGNORED;
Jako x należy podstawić wartość zakresu, np. jeżeli dasz 5, to szansa będzie 1/5.
4. Jeżeli chcesz, aby było natychmiastowe zabicie z innej broni niż granat dodaj warunek:
if( idifnlictor != idattacker )
return HAM_IGNORED;
- Teraz sprawdźmy z jakiej broni zabito:
if( get_user_weapon( idattacker ) != Y )
Jako Y należy podstawić definicje identyfikatora naszej broni.
return HAM_IGNORED; - Teraz dodajemy natychmiastowe zabicie z naszej broni:
SetHamParamFloat( 4, float( get_user_health( this ) + 1) );
return HAM_HANDLED; - Jeżeli chcesz mieć ułamkową szansę na natychmiastowe zabicie przed powyższym kodem dodaj:
if( !random( X ))
return HAM_IGNORED;
Jako x należy podstawić wartość zakresu, np. jeżeli dasz 5, to szansa będzie 1/5.
B) Odporność ( % ) na obrażenia
1. Zarejestruj w plugin_init zdarzenie z modułu hamsandwich, Ham_TakeDamage.
RegisterHam( Ham_TakeDamage, "player", "fw_TakeDamagePre" );
2. "Utwórz" funkcję:
public fw_TakeDamagePre( this, idinflictor, idattacker, Float:damage, damagebits )
{
// tu będzie kod
}
3. Wewnątrz funkcji, sprawdź czy this i idattacker żyją:
if( !is_user_alive( idattacker ) || !is_user_alive( this ) )
return HAM_IGNORED;
4. Teraz dodajemy już ostatnie 2 linie:
SetHamParamFloat( 4, damage * ( 1.00 - ( O_ILE_PROCENT_ZMNIEJSZAMY_OBRAZENIA / 100 ) ) );
return HAM_HANDLED;
Chyba nie muszę tłumaczyć co podstawiamy za O_ILE_PROCENT_ZMNIEJSZAMY_OBRAZENIA.
c) Obrażenia większe o %
1. Zarejestruj w plugin_init zdarzenie z modułu hamsandwich, Ham_TakeDamage.
RegisterHam( Ham_TakeDamage, "player", "fw_TakeDamagePre" );
2. "Utwórz" funkcję:
public fw_TakeDamagePre( this, idinflictor, idattacker, Float:damage, damagebits )
{
// tu będzie kod
}
3. Wewnątrz funkcji, sprawdź czy this i idattacker żyją:
if( !is_user_alive( idattacker ) || !is_user_alive( this ) )
return HAM_IGNORED;
4. Teraz dodajemy już ostatnie 2 linie:
SetHamParamFloat( 4, damage * ( 1.00 + ( O_ILE_PROCENT_ZWIĘKSZAMY_OBRAZENIA / 100 ) ) );
return HAM_HANDLED;
Chyba nie muszę tłumaczyć co podstawiamy za O_ILE_PROCENT_ZWIĘKSZAMY_OBRAZENIA.
d) Szansa na pełną absorpcję obrażeń
1. Zarejestruj w plugin_init zdarzenie z modułu hamsandwich, Ham_TakeDamage.
RegisterHam( Ham_TakeDamage, "player", "fw_TakeDamagePre" );
2. "Utwórz" funkcję:
public fw_TakeDamagePre( this, idinflictor, idattacker, Float:damage, damagebits )
{
// tu będzie kod
}
3. Wewnątrz funkcji, sprawdź czy this i idattacker żyją:
if( !is_user_alive( this ) )
return HAM_IGNORED;
4. W poniższym kodzie jako X wstaw szansę na absorpcję ( 1/X ):
if( !random( X ))
return HAM_IGNORED;
5. Teraz dodajemy już ostatnie 2 linie:
return HAM_SUPERCEDE;
Jeżeli macie jeszcze jakieś pomysły na nowe podpunkty dotyczące operacji na obrażeniach, proszę pisać śmiało w komentarzach :)
sebul
19.02.2013
SetHamParamFloat( 4, float( get_user_health( this ) + 1) );
To nie zabija natychmiast, a przynajmniej nie w każdym przypadku.
Fili:P
20.02.2013
Masz na myśli brak wliczonego współczynniku pancerza ?SetHamParamFloat( 4, float( get_user_health( this ) + 1) );
To nie zabija natychmiast, a przynajmniej nie w każdym przypadku.
Jak się nazwać
20.02.2013
random_num( 1, x ) != 1-->
!random(x)
SetHamParamFloat( 4, 0.0 ); return HAM_HANDLED;-->
return HAM_SUPERCODE
sebul
20.02.2013
if( !random( X ))
return HAM_IGNORED;
na
if(random( X ))
return HAM_IGNORED;
dopiero teraz będzie 1/x szansy na brak obrażeń.
Jeśli zmieniasz obrażenia, czy coś tam jeszcze, to wtedy piszesz HAM_HANDLED, ale skoro ma blokować całe obrażenia, to należy zwrócić HAM_SUPERCODE, bez żadnego zmieniania obrażeń na 0.Po operacjach zwracamy HAM_HANDLED, aby zatwierdzić zmiany.
Tak.Masz na myśli brak wliczonego współczynniku pancerza ?SetHamParamFloat( 4, float( get_user_health( this ) + 1) );
To nie zabija natychmiast, a przynajmniej nie w każdym przypadku.
Jak się nazwać
20.02.2013
Niby tak napisał, ale z moich testów wynika że ham_ignored też modyfikuje obrażenia, co do supercode to właśnie o to mi chodziło, żeby nie zmieniać obrażeń na 0.0 tylko po prostu zablokowaćPo operacjach zwracamy HAM_HANDLED, aby zatwierdzić zmiany.
dasiek
20.02.2013
Ten temat został przeniesiony z forum
Scripting AMXX → Tutoriale
do
Scripting AMXX → Gotowe funkcje
Gość_21977_* 20.02.2013
Zmiana obrażeń na 0, a następnie zwrócenie HAM_HANDLED, nie zada, co prawda, obrażeń, ale nie zablokuje eventu obrażeń.
Innymi słowy, gracz dalej będzie odpychany (pomimo pozornej absorpcji obrażeń), a event TakeDamage Post zostanie wykonany.
Jeśli będę dodawał np. amunicję za każde trafienie wroga, zostanie ona dodana pomimo właśnie pozornej absorpcji obrażeń.
Dlatego też, w przypadku chęci absorpcji obrażeń, należy zwrócić HAM_SUPERCEDE, by całkowicie zablokować event.
!random(x) ma faktycznie 1/x procent szans na wywołanie, jednak w użytej przez autora tematu formie, ma to być
szansa na zablokowanie wydarzenia, z powodu stojącej za funkcją pseudo-losową, instrukcji return HAM_IGNORED.
Jeśli chodzi zaś o natychmiastowe zabicie gracza, to zdejmijmy mu kamizelkę przed wywołaniem operacji, by mieć pewność, że nie uratuje ona mu życia:
cs_set_user_armor(id, 0, CS_ARMOR_NONE);
Użytkownik Benio101 edytował ten post 20.02.2013 21:18
lit., drobne stylistyczne
sebul
20.02.2013
To też nie zawsze może pomóc, najlepiej jest gdzieś po zadaniu obrażeń sprawdzać, czy dany gracz miał być od razu zabity i jeśli tak, to wtedy gdy jest dalej żywy, zadać jeszcze raz takie same obrażenia jak wcześniej (lub jakiekolwiek obrażenia) i tak oczywiście aż dany gracz nie zostanie zabity.Jeśli chodzi zaś o natychmiastowe zabicie gracza, to zdejmijmy mu armor przed wywołaniem operacji, by mieć pewność, że nie uratuje ona mu życia:
cs_set_user_armor(id, 0, CS_ARMOR_NONE);
Jeszcze co do zmieniania obrażeń przed ich zadaniem, to niestety, ale takie coś może powodować tzw. bug z 0hp, bo gdy gracz będzie miał hp pomiędzy 0, a 1 (czyli wartość zmiennoprzecinkową 0 < hp < 1), to wtedy ekran przekręca się na bok i wyświetla 0hp. Chyba najlepszym sposobem jest po prostu sprawdzanie po zadaniu obrażeń ile hp ma gracz oraz czy żyje, jeśli hp ma mniej od 1 i żyje, to zadać mu jakieś tam obrażenia lub po prostu zabić go za pomocą "kanapki".
Gość_21977_* 20.02.2013
btw. Teraz mnie jeszcze zaciekawiłeś, w jakim wypadku zdjęcie kamizelki będzie niewystarczające (uzględniając to +1 dodawane do liczby odejmowanych punktów życia gracza)?
sebul
20.02.2013
Do czego to się odnosi?W przypadku stosowania systemu żyć bądź natychmiastowego autoodradzania (typu DM) dla rozgrywki na rundy, gracz natychmiast straci wszystkie swoje życia, zamiast tylko jednego.
Z moich testów wynika (czyli na podstawie logów), że nie zawsze pomaga zabranie kamizelki, czemu tak jest, nie wiem, ale po prostu w logach miałem coś takiego, że graczowi zostawało trochę hp (liczę sytuację, gdy gracz miał hp >= 1) i był żywy. Testy robiłem właśnie dlatego, bo szukałem przyczyny bugu z 0hp.btw. Teraz mnie jeszcze zaciekawiłeś, w jakim wypadku zdjęcie kamizelki będzie niewystarczające (uzględniając to +1 dodawane do liczby odejmowanych punktów życia gracza)?
Gość_21977_* 20.02.2013
Do tego:Do czego to się odnosi?
Za to dobicie na to kilka HP, będzie dobrym pomysłem (nie sądziłem, że właśnie może gracz takie "zabicie" przeżyć), szczerze powiedziawszy, nigdy z tej opcji jeszcze nie korzystałem.najlepiej jest gdzieś po zadaniu obrażeń sprawdzać, czy dany gracz miał być od razu zabity i jeśli tak, to wtedy gdy jest dalej żywy, zadać jeszcze raz takie same obrażenia jak wcześniej (lub jakiekolwiek obrażenia) i tak oczywiście aż dany gracz nie zostanie zabity.
sebul
20.02.2013
Skoro gracz jest żywy (nawet mając mniej niż 1 hp, ale więcej niż 0), to raczej nie jest to liczone jako zabójstwo i nic nie będzie zabierane kilka razy, nawet zadając jeszcze raz 100 (lub więcej) dmg. W każdym razie, natychmiastowe zabijanie można też robić bez usuwania kamizelki, wystarczy dobrze to napisać.Do tego:Do czego to się odnosi?
Za to dobicie na to kilka HP, będzie dobrym pomysłem (nie sądziłem, że właśnie może gracz takie "zabicie" przeżyć), szczerze powiedziawszy, nigdy z tej opcji jeszcze nie korzystałem.najlepiej jest gdzieś po zadaniu obrażeń sprawdzać, czy dany gracz miał być od razu zabity i jeśli tak, to wtedy gdy jest dalej żywy, zadać jeszcze raz takie same obrażenia jak wcześniej (lub jakiekolwiek obrażenia) i tak oczywiście aż dany gracz nie zostanie zabity.
MarWit
21.02.2013
Jeśli chodzi zaś o natychmiastowe zabicie gracza, to zdejmijmy mu kamizelkę przed wywołaniem operacji, by mieć pewność, że nie uratuje ona mu życia:
cs_set_user_armor(id, 0, CS_ARMOR_NONE);
Nie szybciej użyć po prostu ( z zablokowaniem obrażeń przez HAM_SUPERCEDE ) ?:
ExecuteHam( Ham_Killed, ... );
sebul
21.02.2013
Też można (ale lepiej używać "ExecuteHamB" w tym przypadku, przynajmniej tak mi się wydaję), zresztą sam zastanawiałem się nad tym, żeby z tego korzystać, ale tutaj nie da się ustawić inflictora (tak jak to w przypadku Ham_TakeDamage), czyli bytu co zabija (zadaje obrażenia), chyba że ja o czymś nie wiem.Jeśli chodzi zaś o natychmiastowe zabicie gracza, to zdejmijmy mu kamizelkę przed wywołaniem operacji, by mieć pewność, że nie uratuje ona mu życia:
cs_set_user_armor(id, 0, CS_ARMOR_NONE);
Nie szybciej użyć po prostu ( z zablokowaniem obrażeń przez HAM_SUPERCEDE ) ?:ExecuteHam( Ham_Killed, ... );
Gość_21977_* 21.02.2013
Jak się nazwać
21.02.2013
Z tego co wiem, to przy godmode TakeDamagePre nie zostanie wykonane (tak mi się wydaje) więc to trzeba byłoby sprawdzić (chyba że już sprawdzałeś, jak tak to zwracam honor)do tego trzeba sprawdzić, czy gracz nie ma godmoda.
MarWit
21.02.2013
"inflictorem" jest broń aktualnie trzymana przez gracza, lub jeżeli byt nie jest graczem to "inflictorem" jest właśnie byt atakujący.ale tutaj nie da się ustawić inflictora
sebul
21.02.2013
O tym to ja wiem, chodzi mi po prostu o ustawienie "inflictora" bez względu na to, kto jest atakującym, co zresztą pisałem, że chodzi mi o coś takiego jak można ustawić przy "Ham_TakeDamage", czyli jeszcze dokładniej, w "Ham_Killed" nie da się ustawić gracza jako atakującego, a jakiś byt jako to coś, co zadaje obrażenia."inflictorem" jest broń aktualnie trzymana przez gracza, lub jeżeli byt nie jest graczem to "inflictorem" jest właśnie byt atakujący.ale tutaj nie da się ustawić inflictora