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
 

BlackPerfum - zdjęcie

BlackPerfum

Rejestracja: 13.08.2012
Aktualnie: Nieaktywny
Poza forum Ostatnio: 24.03.2020 01:59
****-

Moje tematy

[Poprawione] Lepszy sposób zmiany prędkości gracza

15.07.2014 16:46

Uwaga: Poradnik poprawiony




Na tym forum już jest tutorial o zmianie prędkości gracza (link) lecz pokazuje nam tylko trzy opcje:
CurWeapon
Ham_CS_Player_ResetMaxSpeed
Ham_Item_PreFrame

Osobiście uważam że każda z nich jest w jakimś stopniu nie odpowiednia. Nawet to udowodnie. Wytłumaczenie dlaczego CurWeapon jest złe do ustawienia zmiany prędkości gracza znajdziecie tutaj. Zostały nam zatem jeszcze dwie opcje do wykluczenia.

Ham_Item_PreFrame
Ma tylko jedną wadę tzn. to jest think wykonuje się tyle samo ile gracz posiada fps. Zatem podczas 1 min gry może wykonać się 6000 razy nawet jeśli stoimy w miejscu i totalnie nic nie robimy  xD Czegoś tak nie optymalnego nie chcemy. Dlatego ta opcja od razu odpada.

Ham_CS_Player_ResetMaxSpeed
Patrząc na to teoretycznie to ta funkcja nie posiada wad ale jednak w praktyce się znajdują. Tzn:
• wykonuje sie parę razy więcej niż powinna gdyż nasza prędkość jest resetowana także podczas freeze time'u, śmierci, spawn'u
• W jakiś sposób trzeba rozróżnić wykonanie się tej funkcji w czasie freeze time'u i po nim :(
NAJWAŻNIEJSZE Ta funkcja jest dostepna dopiero w wersji 1.3 hamsandwich'a co jest jej największą wadą gdyż z wielu przyczyn nie każdy ma mozliwość jego aktualizacji :(

Zatem w jaki sposób ustawiać prędkość graczu? Zastanówmy się. Wszystkie dostępne sposoby jakie znalazłem na necie mówią o wymuszaniu prędkości gracza w jakimś evencie lecz po co mamy wymuszać nową wartość prędkości?? Nie lepiej sprawić by CS sam ustawił taką jaką chcemy? Jasne że lepiej to dlaczego nie xD Dlatego wykombinowałem coś swojego hihihi

Do zmiany wartości którą CS ustawia nam jako prędkość będziemy potrzebować:
• hamsanwich'a
• fakemet'y
• umiejętności myślenia

Uwaga jeśli nie masz choćby jednej z wyżej wymienionych rzeczy ten tutorial ci się nie przyda!!!

W teorii pomyślałem tak: złapmy Ham_Item_Deploy pre/post i podmieńmy tam wartość prędkości na swoją własną lecz niestety w praktyce się przekonałem że offsety między Ham_Item_Deploy pre a Ham_Item_Deploy post są przeładowywane :( Dlatego będziemy zmuszeni do operowania tylko na Ham_Item_Deploy post ale na szczęście niczemu to nie wadzi xD

Niestety musimy zmierzyć się jeszcze z jedną acz ostatnią przeszkodą tzn. classname do RegisterHam :( Funkcja Ham_Item_Deploy ma to w sobie że wykonuje się dla broni nie dla gracza dlatego nie można złapać momęt pokazania broni za pomocą classname == player, trzeba używać każdego z osobna classname broni. Ma to swoją wadę i zaletę:
Zaleta: w przypadku chęci zwiększenia prędkości np. tylko na nożu wystarczy złapać tylko classname == weapon_knife
Wada: jesli chce się zmieniać prędkość na wszystkich boniach trzeba złapać ten event dla wszystkich classname standardowych broni

Lista classname standardowych broni: klik

Ogółem to wada jest tak mizerna że nie ma co się o nią fapać xD Bo wystarczy raz na całą mapę przejechać po 31 classname

Ham_CS_Item_GetMaxSpeed posłuży nam jako event zmiany prędkości (ale tylko pre)

Wystarczy gadania. Zróbmy kod:
#include <amxmodx>
#include <hamsandwich>
#include <fakemeta>
//Wymagane moduły
//fakemeta tylko do sprawdzania id gracza/broni (opcjonalny moduł)

const m_pPlayer = 41
const m_iId = 43

public plugin_init()
{
	new classname[32] // Zmienna do której będziemy pobierać classname poszczególnych broni
	for(new i=1;i<31;++i)	if(i!=2)
	{
		//Pętelka na wszystkie bronie

		get_weaponname(i,classname,31) //Pobieram classname danej broni
		
		RegisterHam( Ham_CS_Item_GetMaxSpeed, classname, "GetItemMaxSpeed") //Rejestruje uchwyt na event Ham_CS_Item_GetMaxSpeed dla danego classname broni
		//Ważne 4 arg musi == 0 by to był event typu pre
	}
}

public GetItemMaxSpeed(wid) // tutaj łapie event
{
	//Pamiętajcie wid to id bytu broni (nie mylić z CSW_*)
	
	new weapon,id,Float:Speed // robie zmiennej na id gracza i id z CSW_*
	
	id = get_pdata_cbase(wid,m_pPlayer,4) //Ważne tylko takim sposobem pobierać id gracza który trzyma broń
	// Gdyż użycie pev/entity_get_edict może zwrócić -1 nawet jeśli gracz trzyma broń w momęcie startu/końca pracy serwera gdyż
	// Dane z pev/entity_get_edict są czasami (pod dużym obciążeniem) aktualizowane później niż dane pod offsetem m_pPlayer
	//Tak w ogóle to pobieram id gracza xD
	
	weapon = get_pdata_int(wid,m_iId,4) // Pobieram id broni to z CSW_*
	
	
	//Zeby przytoczyć trochę praktyki to dajmy graczu który posiada flagę ADMIN_LEVEL_H prędkość równą 500 na wszystkich broniach
	// oprócz C4 bo na nim ustawimy 900 xD
	
	//Najpierw sprawdzamy czy posiada flagę ADMIN_LEVEL_H
	if(get_user_flags(id) & ADMIN_LEVEL_H)
	{
		//Teraz muzimy sprawdzić czy aktywna broń to nie C4
		if(weapon != CSW_C4)
		{
			//Jeśli to nie C4
			//Ustawiamy prędkość równą 500.0
			Speed = 500.0
		}
		else
		{
			//Lecz jeśli to C4 to 900
			Speed = 900.0
		}
	}
	//Zmieniam zwracana wartosc
	SetHamReturnFloat(Speed)
	//Informuje o zmianie zwracanej wartosci
	return HAM_OVERRIDE
}
Ten sposób zmiany prędkości nie ma większych wad bo:
• uruchamia się tylko prawie tylko wtedy kiedy naprawdę jest to nam potrzebne niepotrzebnie uruchamia sie podczas: włączania/wyłączania zoom'a, startu/zakończenia rozbrajania paki, startu/zakończenia plantowania paki, pod koniec freeze time (Ham_CS_Player_ResetMaxSpeed uruchamia się częściej)
• nie trzeba bawić sie freeze time'em bo CS robi to za nas!!
• możliwość kożystania już od pierwszej (oficjalnej w amxmodx'ie) wersji hamsandwich'a xD
• nie da się tego zbugować od strony clienta

Opis offset'ów:
m_pPlayer - Typ edict(int). Przechowuje coś w stylu ownera dla danej broni lub byt do którego jest aktualnie przyczepiona (jedno i to samo)
m_iId - Typ int. Przechowuje id broni (to z CSW_*)

To chyba na tyle. Prosty, łatwy i optymalny sposób na zmiane prędkości gracza xD

Zabijanie gracza + Zarządzanie broniami

03.07.2014 18:27

Przeglądając swój komputer a dokładnie śmietnik (większość mojego kompa to śmietnik) trafiłem na bardzo ciekawe funkcje dotyczące broni, dlatego wpadłem na pomysł by się z wami nimi podzielić. Może ułatwią wam życie (może utrudnia :D). Na pewno komuś się to przyda a u mnie zalega.

Ostatnio był temat w którym się spierałem czym zabijać gracza dlatego zrobiłem ciekawą funkcję która byłaby która jest idealna do zabijania graczy. Dlaczego idealna? Bo fragi lecą do rankingu,samemu ustawiasz jaką bronią zabijasz (nie ma problemów z tą ikonką czachy), nie zabijam zadając dmg dlatego żaden plugin modyfikujący dmg lub leczący gracza w chwili otrzymania dmg nie koliduje z tą funkcją. Ta funkcja wyznaje kompatybilność ponad wszystko tzn. można śmierć wyłapać w Ham_Killed jak i event DeathMsg xD

KillPlayer:
KillPlayer(id,inflictor,attacker,weapon,body,shouldgib,damagebits)
{
	if(weapon > 30 || !is_user_alive(id) || !is_user_connected(attacker))	return
	
	const GrenadeWeapon = 1<<CSW_HEGRENADE | 1<<CSW_C4 | 1<<CSW_SMOKEGRENADE | 1<<CSW_FLASHBANG
	const m_LastHitGroup = 75
	const m_bitsDamageType = 76
	const m_fHasTakenHighDamage = 107
	static DeathMsgId
	new msgblock,weaponname[32],effect
	if (!DeathMsgId)	DeathMsgId = get_user_msgid("DeathMsg")
	
	set_pdata_int(id,m_LastHitGroup,body,5)
	set_pdata_int(id,m_bitsDamageType,damagebits,5)
	set_pdata_int(id,m_fHasTakenHighDamage,1,5)
	set_pev(id,pev_dmg_inflictor,inflictor)
	msgblock = get_msg_block(DeathMsgId)
	set_msg_block(DeathMsgId, BLOCK_SET)
	ExecuteHamB(Ham_Killed,id,attacker,shouldgib)
	set_msg_block(DeathMsgId, msgblock)
	if(is_user_alive(id))	return
	
	effect = pev(id,pev_effects)
	if(effect & 128)	set_pev(id,pev_effects,effect-128)
	
	new len
	if(get_weaponname(weapon,weaponname,31))
	{
		if(~GrenadeWeapon & 1<<weapon) len = 7
		else weaponname = "grenade"
	}
	else if(weapon == 2)	weaponname = "tracktrain"
	else	weaponname = "world"
	
	emessage_begin(MSG_ALL, DeathMsgId)
	ewrite_byte(attacker)
	ewrite_byte(id)
	ewrite_byte(body == HIT_HEAD ? 1:0)
	ewrite_string(weaponname[len])
	emessage_end()
}
Działanie: Zabija gracza

Zalety: Poprawnie dodaje nam fraga do ranku, do tablicy wyników, poprawnie wyskakuje ikonka zabicia w prawym górnym rogu. Nie zadaje dmg a poprostu zabija a zatem żaden inny plugin modyfikujący dmg nie przerwie procesu zabijania gracza. Taki kill na 100% (99,(9)%) Dodatkowo: usuwa zbędne efekty,ustawia byt jakim zabijamy (inflictor), część ciała w którą trafiliśmy śmiertelnym ciosem, ustawia takie jakie chcemy damagebits xD

Wady: Brak

Parametry:
id - osoba którą chcemy zabić (1~32)
inflictor - byt którym zabijamy (przy broniach z cs'a inflictor == attacker jedynie przy he to byt)
attacker - osoba która ma zabić osobe id (1~32)
weapon - numer broni (to z CSW_*) którą mamy zabić gracza. W przypadku weapon == 0 broń zabijająca to "world" czyli pokaże nam czache w prawym górnym rogu
body - część ciała w którą trafiliśmy (części ciała te z HIT_*) w przypadku wybuchów (np. he) body == 0
shouldgib - sposób w jaki ma zostać pokazane ciało po śmierci (typy GIB_*)
damagebits - damagebits które spowodowało śmierć (DMG_*)

Przykładowe użycie:


KillPlayer(1,124,2,CSW_HEGRENADE,HIT_GENERIC,0,1<24)
Gracz o id 2 zabija gracza o id 1 za pomocą granatu HE o id 124.W taki sam sposób cs zabija graczy z HE xD



Teraz funkcje operujące na broniach:
SetUserWeaponInHand:
SetUserWeaponInHand(id,weapon)
{
	const m_pActiveItem = 373
	const m_pPlayer = 41
	new classname[32]
	if(is_user_alive(id) && get_weaponname(weapon,classname,31) && weapon !=2 && weapon <= 30)
	{
		while((weapon = engfunc(EngFunc_FindEntityByString,weapon,"classname",classname)))
		{
			if(pev_valid(weapon) == 2 && get_pdata_cbase(weapon,m_pPlayer,4) == id)
			{
				set_pdata_cbase(id,m_pActiveItem,weapon,5)
				ExecuteHam(Ham_Item_Deploy, weapon)
				return weapon
			}
		}
	}
	return 0
}
Działanie: Ustawia graczu broń w dłoni. Zwróci 0 jeśli gracz nie posiada danej broni. Dodatkowo zwraca id bytu nowo trzymanej broni

Zalety: Nie wysyła graczu komendy do konsoli aby zmienić broń a po prostu informuje gracza która broń teraz trzyma. Szybsze działanie funkcji niż client_cmd/engclient_cmd nawet przy 300 ent'ach o tym samym classname (sam się zdziwiłem) (sprawdzane w profilerze xD).

Wady: Brak

Parametry:
id - osoba której zmieniamy broń (1~32)
weapon - numer broni (to z CSW_*) na która chcemy zmienić

Przykładowe użycie:


SetUserWeaponInHand(id,CSW_KNIFE)
Gracz o id równym id wyciągnie nóż.


GetUserWeapon:
GetUserWeapon(id,&wid=0)
{
	const m_pActiveItem = 373
	const m_iId = 43
	if(!is_user_alive(id) || pev_valid((wid = get_pdata_cbase(id,m_pActiveItem,5))) != 2)	return 0
	
	return get_pdata_int(wid,m_iId,4)
}
Działanie: Zwraca id broni którą aktualnie mamy wyciągniętą (id z CSW_* poprzez return i id bytu broni poprzez referencję w opcjonalnym drugim parametrze)

Zalety: Funkcja zwróci poprawne id (CSW_*/bytu) nawet podczas wyciągania broni lub jej chowania. Po co to komu? Przeciez jest get_user_weapon a próbowaliście kiedyś pobrać id za pomocą get_user_weapon w Ham_ItemDeploy albo Ham_CS_Player_ResetMaxSpeed jeśli tak to będziecie wiedzieć że zwróci niepoprawny wynik tzn. zwróci broń jaką mieliśmy ostatnio a moja funkcja zwróci prawidłowy wynik dodatkowo jeśli chcecie to możecie pobrać id bytu broni w drugim opcjonalnym argumncie

Wady: Brak

Parametry:
id - osoba której sprawdzamy broń (1~32)
wid* - do tego argumentu zostanie wpakowane id bytu aktualnie posiadanej broni poprzez referencję
* - argument opcjonalny tzn. argument niewymagany można go pominąc jeśli się go nie chce

Przykładowe użycie:


new weapon = GetUserWeapon(id)
Do zmiennej weapon zostanie wpakowane id (to z CSW_*) broni którą aktualnie trzymamy
Lub:
new wid
new weapon = GetUserWeapon(id,wid)
Do zmiennej weapon zostanie wpakowane id (to z CSW_*) broni którą aktualnie trzymamy oraz do zmiennej wid zostanie wpakowane id bytu naszej broni


GetUserAmmo:
GetUserAmmo(id,&ammo=0,&bpammo=0,weapon=0)
{
	const m_iPrimaryAmmoType = 49
	const m_rgAmmo = 376
	const m_iClip = 51
	const m_pActiveItem = 373
	const m_pPlayer = 41
	if(!is_user_alive(id) || (!weapon && pev_valid((weapon = get_pdata_cbase(id,m_pActiveItem,5))) != 2))	return 0
	
	new classname[32]
	if(weapon <= 30 && get_weaponname(weapon,classname,31))
	{
		while((weapon = engfunc(EngFunc_FindEntityByString,weapon,"classname",classname)))
		{
			if(pev_valid(weapon) == 2 && get_pdata_cbase(weapon,m_pPlayer,4) == id)	goto GetAmmo
		}
		return 0
	}
	
	GetAmmo:
	ammo = get_pdata_int(weapon,m_iClip,4)
	bpammo = get_pdata_int(id,m_rgAmmo+get_pdata_int(weapon,m_iPrimaryAmmoType,4),5)
	return weapon
}
Działanie: Pobiera do drugiego argumentu (opcjonalnego) ilość ammo nabitego, do trzeciego argumentu (opcjonalnego) ilośc ammo w plecaku gracza, oraz zwraca id bytu broni (dla broni wyciągniętej w przypadku weapon == 0 lub dla danej broni weapon == CSW_*). Zwróci 0 w przypadku gdy broń zawarta w argumencie weapon nie zostanie odnaleziona

Zalety: Funkcja działa jak ty chcesz możesz pobrać tylko ammo w plecaku lub tylko ammo nabite, możesz pobrac ammo dla wyciągniętej broni lub dla jakiejś której aktualnie nie trzymamy ale ją posiadamy

Wady: Nie da się pobrać ammo w plecaku jeśli gracz nie posiada danej broni :(

Parametry:
id - osoba której sprawdzamy ammo (1~32)
ammo* - do tego argumentu zostanie wpakowana ilość ammo, która jest nabita w broni
bpammo* - do tego argumentu zostanie wpakowana ilość ammo, która jest w plecaku dla danej broni
weapon* - ten argument decyduje czy ma pobrać ammo dla broni aktualnie wyciągniętej (weapon == 0) czy dla broni posiadanej (weapon == CSW_*)
* - argument opcjonalny tzn. argument niewymagany można go pominąc jeśli się go nie chce

Przykładowe użycie:


new weapon,ammo,bpammo
weapon = GetUserAmmo(id,ammo,bpammo)
Do zmiennej weapon zostanie wpakowane id bytu broni którą aktualnie trzymamy, do zmiennej ammo zostanie wpakowana ilośc ammo nabitego w broni oraz do zmiennej bpammo zostanie wpakowana ilośc ammo posiadanego w plecaku przez gracza do tej broni
Lub:
new bpammo
GetUserAmmo(id,.bpammo=bpammo,.weapon=CSW_AK47)
O ile gracz posiada AK47 to do zmiennej bpammo zostanie zwrócona ilość ammo posiadanego w plecaku do AK47


SetUserAmmo:
SetUserAmmo(id,ammo=-2,bpammo=-2,weapon=0)
{
	const m_iPrimaryAmmoType = 49
	const m_rgAmmo = 376
	const m_iClip = 51
	const m_pActiveItem = 373
	const m_pPlayer = 41
	const m_fWeapon = 351
	if(!is_user_alive(id) || (!weapon && pev_valid((weapon = get_pdata_cbase(id,m_pActiveItem,5))) != 2))	return 0
	
	new classname[32]
	if(weapon <= 30 && get_weaponname(weapon,classname,31))
	{
		while((weapon = engfunc(EngFunc_FindEntityByString,weapon,"classname",classname)))
		{
			if(pev_valid(weapon) == 2 && get_pdata_cbase(weapon,m_pPlayer,4) == id)	goto SetAmmo
		}
		return 0
	}
	
	SetAmmo:
	if(ammo > -2)	set_pdata_int(weapon,m_iClip,ammo,4)
	if(bpammo > -2)	set_pdata_int(id,m_rgAmmo+get_pdata_int(weapon,m_iPrimaryAmmoType,4),bpammo,5)
	
	set_pdata_int(id,m_fWeapon,0,5)
	return weapon
}
Działanie: Ustawia graczu ilość ammo nabitego i/lub w plecaku dla aktualnej broni lub wybranej. Można także ustawić by z którejś broni nie dało się strzelać (ammo == -1 i bpammo == -1) efekt bardzo ciekawy. Odświeża hud.

Zalety: Odświeża hud po zmianie ilości ammo. Możliwośc zablokowania strzelania z danej broni. Możliwość ustawienia tyle i takie ammo jakie chcemy.

Wady: Nie da się ustawić ammo w plecaku jeśli gracz nie posiada danej broni :(

Parametry:
id - osoba której ustawiamy ammo (1~32)
ammo* - ilośc ammo nabita jaka zostanie ustawiona
bpammo* - ilośc ammo w plecaku jaka zostanie ustawiona
weapon* - ten argument decyduje czy ma ustawić ammo dla broni aktualnie wyciągniętej (weapon == 0) czy dla broni posiadanej (weapon == CSW_*)
* - argument opcjonalny tzn. argument niewymagany można go pominąc jeśli się go nie chce

Przykładowe użycie:


SetUserAmmo(id,0,0)
Zabranie wszystkiego ammo aktualnie trzymanej broni.
Lub:
SetUserAmmo(id,100,.weapon=CSW_USP)
O ile gracz posiada USP to ilośc nabitego ammo w USP zostanie zmieniona na 100 (no to sobie można postrzelać xD)
Lub:
SetUserAmmo(id,-1,-1,CSW_M4A1)
Zablokowanie możliwości strzelanie (nie widać ilości ammo w hud, nie słychac pykania pustego magazynku). Efekt do przeładowania.


GetWeaponAmmo:
GetWeaponAmmo(wid)
{
	const m_iClip = 51
	if(pev_valid(wid) != 2)	return 0

	return get_pdata_int(wid,m_iClip,4)
}
Działanie: Zwraca ilośc ammo w danej broni

Zalety: Możliwośc sprawdzenia ilości ammo nawet jeśli broń leży na ziemi

Wady: Brak

Parametry:
wid - id bytu broni (nie mylić z CSW_*)

Przykładowe użycie:


new ammo = GetWeaponAmmo(wid)
Do zmiennej ammo zostanie wpakowana ilość ammo nabitego w broni o id równym wid



SetWeaponAmmo:
SetWeaponAmmo(wid,ammo)
{
	const m_fWeapon = 351
	const m_iClip = 51
	const m_pActiveItem = 373
	const m_pPlayer = 41
	if(pev_valid(wid) != 2)	return
	
	set_pdata_int(wid,m_iClip,ammo,4)
	new id = get_pdata_cbase(wid,m_pPlayer,4)
	if(is_user_alive(id) && get_pdata_cbase(id,m_pActiveItem,5) == wid)	set_pdata_int(id,m_fWeapon,0,5)
}
Działanie: Ustawia ilość ammo nabitego w danej broni. Jeśli trzyma tą broń gracz to odświeża mu hud

Zalety: Możliwośc ustawienia ilości ammo nawet jeśli broń leży na ziemi

Wady: Brak

Parametry:
wid - id bytu broni (nie mylić z CSW_*)
ammo - ilośc ammo która zostanie ustawiona

Przykładowe użycie:


SetWeaponAmmo(wid,5)
Broni o id równym wid zostanie ustawiona ilośc ammo równa 5



GetUserWeaponsId:
GetUserWeaponsId(id,wid,slot=0)
{
	static const m_rgpPlayerItems[6] = { 367 , 368 , ... }
	const m_pPlayer = 41
	const m_pNext = 42
	if(pev_valid(wid) != 2)
	{
		if(slot)
		{
			wid = get_pdata_cbase(id,m_rgpPlayerItems[slot],5)
			return pev_valid(wid) == 2 ? wid:0
		}
	}
	else if(get_pdata_cbase(wid,m_pPlayer,4) == id)
	{
		new numslot = ExecuteHam(Ham_Item_ItemSlot,wid)+1
		wid = get_pdata_cbase(wid,m_pNext,4)
		if(pev_valid(wid) == 2)	return wid
		else if(slot)	return 0
		
		slot = numslot
		
	}
	for(new i = slot;i<6;i++)
	{
		wid = get_pdata_cbase(id,m_rgpPlayerItems[i],5)
		if(pev_valid(wid) == 2)	return wid
	}
	return 0
}
Działanie: Zwraca id bytu następnej posiadanej broni (lub pierwszej w przypadku wid == 0). W danym slocie lub we wszystkich slotach. Działa na podobnej zasadzie do find_ent_by_owner lub engfunc+EngFunc_FindEntityByString.

Zalety: W łatwy sposób można przelecieć po wszystkich broniach gracza lub z danego slota

Wady: Brak

Parametry:
id - id gracza z którego zostanie pobrana broń (1~32)
wid - id poprzedniej broni (nie mylić z CSW_*)
slot* - ten argument decyduje czy pobierać bronie ze wszystkich slotów (slot == 0) czy z danego (slot == x)
* - argument opcjonalny tzn. argument niewymagany można go pominąc jeśli się go nie chce

Przykładowe użycie:


new wid
while((wid = GetUserWeaponsId(id,wid)))
{
	SetWeaponAmmo(wid,0)
}
Wszystkim broniom gracza zostanie zabrane nabite ammo tzn. nabite ammo we wszystkich broniach == 0 xD
Lub:
new wid
while((wid = GetUserWeaponsId(id,wid,1)))
{
	SetWeaponAmmo(wid,GetWeaponAmmo(wid)+10)
}
Do każdej broni gracza w slocie nr. 1 (primary weapon) zostanie dodane 10 ammo



GetUserWeaponId:
GetUserWeaponId(id,weapon)
{
	static const m_rgpPlayerItems[6] = { 367 , 368 , ... }
	const m_pNext = 42
	const m_pNext = 42
	const m_iId = 43
	static const iWeaponsSlots[] = { -1, 2, -1, 1, 4, 1, 5, 1, 1, 4, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 4, 2, 1, 1, 3, 1 }
	
	if(weapon == 2 || !(0 < weapon < 31))	return 0
	
	new wid = get_pdata_cbase(id,m_rgpPlayerItems[iWeaponsSlots[weapon]],5)
	while(pev_valid(wid) == 2)
	{
		if(get_pdata_int(wid,m_iId,4) == weapon)	return wid
		
		wid = get_pdata_cbase(wid,m_pNext,4)
	}
	return 0
}
Działanie: Zwraca id bytu wybranej broni o ile ją posiadamy.

Zalety: Zwróci id nawet jeśli danej broni nie trzymamy w rękach a mamy ją w plecaku

Wady: Brak

Parametry:
id - id gracza z którego zostanie pobrana broń (1~32)
weapon - numer broni (to z CSW_*)

Przykładowe użycie:


new wid = GetUserWeaponId(id,CSW_AK47)
Do zmiennej wid zostanie wpakowane id bytu nszego AK47 (o ile go posiadamy)


GetWeaponId:
 
GetWeaponId(wid)
{
	const m_iId = 43
	if(pev_valid(wid) != 2)	return 0
	
	return get_pdata_int(wid,m_iId,4)
}
Działanie: Zwraca numer broni (to z CSW_*) na podstawie id bytu broni

Zalety: Brak

Wady: Brak

Parametry:
wid - id bytu broni

Przykładowe użycie:


new weapon = GetWeaponId(wid)
Do zmiennej weapon wpakowaliśmy numer (ten z CSW_*) broni o id równym wid

To tyle nie chcemi się już więcej tego pisać. Powiem jeszcze że sume bitowa wszystkich broni gracza można pobrać za pomocą pev_weapons. Czemu czasem używam szukania za pomocą FindEntByString a czasem przeszukuje bronie gracza? By pokazać wam dwa sposoby 1 jest szybszy o ile nie ma na mapie powyżej 30 entów o tym samym classname. Mam nadzieję że nigdzie offsetu nie pomyliłem. Szczególnie polecam zabijania gracza za pomocą KillPlayer ;D

[ROZWIĄZANE] Przesylanie danych o graczu miedzy serwerami

08.06.2014 20:20

Witam, aktualnie jestem w trakcie pisania dosyć wielkiego mod'a ale muszę być świadom czy nie pisze bez sensu. Dlatego mam do was pytanie ale najpierw was wtajemniczę. (Uwaga dalej są informacje ściśle tajne) Mod ma możliwość wysyłania danych pośrednio między serwerami za pomocą socket'ów (oczywiście dane o graczu tzn. położenie,vector,kierunek wzroku,itd). To już zrobione ale nasuwa mi się pytanie ile takich graczy mógł by wytrzymać serwer (zakładamy że mam 10 serwerów każdy 32 sloty, 0 hltv, dosyć wydajne maszyny). Oczywiście wysyłam po to dane o graczy by na innym serwerze widzieć jego poczynania (taki fake (byt ale nie player) gracz co nie zabiera slotów :D

 

Testowałem przy 2 graczach i wszystko pięknie śmiga ale nwm ilu coś takiego wytrzyma. Dlatego proszę o info ;D

Przydatne funkcje + Ciekawostki o nich

04.05.2014 01:09

Witam dawno tu mnie nie było dlatego na powrót chciał bym wam przekazać w użytek parę ciekawych i uproszczających życie funkcji
 
Dobrze zaczynajmy
 
Pierwszą taką funkcją będzie nikomu nie znane SearchKey. Tak to wygląda:
SearchKey(value,keys)
{
	return floatround(floatlog(float(value & keys),2.0))
}
Taka mała niepozorna funkcja zastępuje całkiem dużo kodu.
 
value - wartość w której szukamy
keys - suma bitowa
 
Co ona robi takiego? Hmm najprościej ujmując szuka w zmiennej value bitów ze zmiennej keys i zwraca nr znalezionego bitu (Standardowy logarytm).
Jest pewna uwaga co do zastosowania, gdyż tylko jeden bit może byc taki sam w obu zmiennych (inaczej zwróci nie pożądane wyniki)
 
Teraz pewnie wiele waszych mózgów przetworzyło taką oto informację: na co mi to?
 
Zarzucę pięknym przykładem:
 
Chcemy sprawdzić jaki gracz ma pistolet (broń drugorzędna),ten w plecaku lub aktualnie wyciągnięty.(zakładamy że gracz ma tylko jeden pistolet)
 
Normalnie większość z was zrobiła by tak:
new SB = 1<<CSW_ELITE | 1<<CSW_FIVESEVEN | 1<<CSW_USP | 1<<CSW_GLOCK18 | 1<<CSW_DEAGLE | 1<<CSW_P228
new weapons[32], numweapons,weapon;
get_user_weapons(id, weapons, numweapons);
	
for(new i=0; i<numweapons; i++)
	if((1<<weapons[i]) & SB)
		weapon = weapons[i];

//Jupii znaleźliśmy nasz pistolet :D
Oczywiście nie biorę pod uwagę gorszych przypadków szukania broni
 
Ja za to zrobił bym to tak:
new SB = 1<<CSW_ELITE | 1<<CSW_FIVESEVEN | 1<<CSW_USP | 1<<CSW_GLOCK18 | 1<<CSW_DEAGLE | 1<<CSW_P228
new weapons,weaponlist[32],num,weapon
weapons = get_user_weapons(id,weaponlist,num)
weapon = SearchKey(weapons,SB)

//I tak oto znaleźliśmy pistolet
Zastrzegam prawa do gnębienia tego przykładu gdyż jest dosyć głupi (nie widać dużej różnicy kodu ani 100% poprawności) bo na połowie aktualnych serwerów można mieć wiele broni na raz (także tego samego typu(typ tzn. pierwszorzędne/drugorzędne/itd))
 
Ale np. gdy mamy info o graczu:
enum {Latam=1,Plywam,Biegam,Chodze,Stoje,NicSieZeMnaNieDzieje,PosiadamC4,Pisze,WidzeHud,WidzeMotd,WidzeSay}
new Player[33]
To gdy chcemy sprawdzić co się z ziomkiem (ale tylko rzeczy między Latam a NicSieZeMnaNieDzieje) dzieje to musimy zrobić tak:
new CoRobiGracz
if(Player[id] & 1<<Latam) CoRobiGracz = Latam               //Ja latam jeee
else if(Player[id] & 1<<Plywam) CoRobiGracz = Plywam        // Plywam :D
else if(Player[id] & 1<<Biegam) CoRobiGracz = Biegam        // A jednak biegam
else if(Player[id] & 1<<Chodze) CoRobiGracz = Chodze        // Spacerek
else if(Player[id] & 1<<Stoje) CoRobiGracz = Stoje          // Zmeczylem sie
else if(Player[id] & 1<<NicSieZeMnaNieDzieje) CoRobiGracz = NicSieZeMnaNieDzieje // Totalny odpoczynek
Pamiętajmy iż może być więcej niż jeden bit aktywny!!!

Podalem 6 możliwości a czasem jest ich 31 no nie fajnie tak wypisywać 31 instrukcji dlatego z pomocą przychodzi nam ta funkcja:
new CoRobiGracz = SearchKey(Player[id],Player[id] & (1<<Latam|1<<Plywam|1<<Biegam|1<<Chodze|1<<Stoje|1<<NicSieZeMnaNieDzieje))

// I tak w oto sposob sie dowiedzielismy co sie dzieje z graczem (pewnie to ostatnie)
Ten przykład tez nie pokazuje prawdziwego potencjału tej funkcji ale co zrobić jak brakuje nam weny.
Różnicę tu akurat widać dużą. Z 6 instrukcji na 0 to jest dużo.
Teraz pytania: dlaczego użyłem:
float
floatlog
floatround
 
A bo nie ma logarytmu pracującego nie na floacie (w amxx'ie)
Jeśli się mylę to proszę o wskazanie mi poprawnego toku myślenia.
 
Jedziemy dalej. Kolejnym całkiem sprytnym trikiem użycia funkcji dostępnych w amxx'ie jest coś takiego:
 
Wycinek z pluginu nr. 1:
public Wywolaj()
{
	new R,X,text[6]
	formatex(text,5,"Zjem")
	X = CreateMultiForward("Tutorial",ET_IGNORE,FP_CELL,FP_STRING);
	ExecuteForward(X, R, X, text);
}

public Tutorial(id,text[])
{
        DestroyForward(id)
        server_print("%s noge tu byl",text)
}
A teraz drugi plugin:
public Tutorial(id,text[])
{
	new PolowaTekstu[10]
	formatex(PolowaTekstu,9,"%s ci",text)
	ExecuteForward(id, R, id, PolowaTekstu);
}
To wcale nie jakies wiekopomne odkrycie ale ciekawe. Wywołanie funkcji Wywolaj sprawi że plugin nr. 1 napisze w konsoli serwera Zjem ci noge tu byl. Prawda że ciekawe rzeczy robi ta funkcja, a najciekawsze jest to że przerzucam sobie po pluginach uchwyt do multi forwardu :D
 
I to działa o dziwo. Nie wiem czy ze wszystkimi uchwytami z modułu amxmodx tak sie da bo nigdy nie miałem powodów by to sprawdzać :D
 
Kolejna rzecz to pokazanie wam wszystkim czego nie powinno się robić.
public Menu(id)
{
	new menu = menu_create( "Menu" , "Menu_Zwrot");
	if(is_user_alive(id))	menu_additem(menu,"+ 50Hp")
	else	menu_additem(menu,"Ozyw")
	menu_additem(menu,"Pusta opcja")
	menu_setprop(menu, MPROP_PERPAGE, 1)
	menu_display(id, menu);
} 
Załóżmy że to menu samo się otwiera co 1 min. W pewnym przypadku graczu zostało otworzone te menu kiedy żył ale przez jego głupotę zginą i po śmierci widzi opcje +50Hp i nie kliknie jej (bo według niego ona nic mu nie da)
 
Niestety jako ludzie rozumni nie możemy go za nic winić i co tu zrobić nie każdy zna amxx'a i wie że w hook'u menu jest jeszcze raz sprawdzane czy zyje.
Dlatego trzeba by menu odświeżać ale nam się niee chce. Tyle kodu by gracz widział inną opcję. Za nic!!! Niech się potrudzi i zmieni stronę menu :D
Moje rozwiązanie :D (Całkiem głupie, ale przydaje sie gdy nie chcemy marnowac wysyłanych pakietow na durne menu, a czasem menu trzeba by odswiezyc ze 100 razy na 5 sek)
new const NameMenuItem[][] = {"+ 50Hp ","Ozyw"}

public Menu2(id)
{
	new menu = menu_create( "Menu" , "Menu_Zwrot");
	new cb = menu_makecallback("Menu_Callback");
	menu_additem(menu,"Taki tam tekst",_,_,cb)
	menu_additem(menu,"Pusta opcja",_,_,cb)
	menu_setprop(menu, MPROP_PERPAGE, 1)
	menu_display(id, menu);
}

public Menu_Callback(id,menu,item)
{
	static acces,callback,name[100],tryb,data[2]
	menu_item_getinfo(menu,item,acces,data,1,name,99,callback)
	
	switch(item)
        {
		case 0:
		{
			if(is_user_alive(id))	tryb = 0
			else tryb = 1
		}
		case 1:	return ITEM_DISABLED
	}

	if(contain(name, NameMenuItem[tryb]) == -1)
	{
		formatex(name,99,"%s^n^n Aby odswiezyc menu zmien strone",NameMenuItem[tryb])
		menu_item_setname(menu,item,name)
	}
	
	return ITEM_ENABLED
}
Funkcja contain jest tu bardzo ale to bardzo ważna. Dlaczego? A bo zmieniając cały czas w menu nazwy przyciskow nasze cudne menu sie buguje i powoli zjada nam text (nie zawsze do gracza dochodzi opcja multipart ale czemu?? nie mam pojęcia) na szczęście ten bug występuje kiedy menu ma więcej znaków niż 1000 czy 1024 nie mam pojęcia bo nie sprawdzałem dokładnie. Ale grunt że po zmianie strony odświeża + nie trzeba używać jakichś rozległych funkcji
 
Więcej wam nie powiem bo wyjdzie na to że dzisiaj opiszę wam wszystkie znane mi ciekawostki / funkcje (taak mam coś jeszcze w zanadrzu) a ja chcę jeszcze was czymś w przyszłości zaskoczyć :D

Podmiana znakówk

29.08.2013 00:18

A więc niedawno pewien użytkownik tego forum poprosił mnie o zrobienie pluginu dzięki któremu będzie możliwa podmiana tekstu nie ingerując w jakiś plugin.

A o to rezultaty mojego główkowania :D

 

opis

Plugin umożliwia ingerowanie w wyświetlany tekst u gracza Menu/Hud/Say/DHud/Motd/Tutor.

Przydatne np. gdy nie posiadamy pliku .sma pluginu a chcemy w nim zmienić/usunąć jakieś napisy :D

 

wymagane moduly

 Orpheu klik

 

konfiguracja

Tekst do podmiany konfigurujemy w pliku pod ścieżką: addons/amxmodx/configs/BlokowanyTekst.ini

Spoiler

 

instalacja

Rozpakowujemy i wrzucamy do naszego folderu "cstrike"

 

inne informacje

- Tekst podmieniający nie powinien być równy dłuższy od podmienianego (czasu brak ale jak będzie to usunę to ograniczenie)

- Tekst podmieniany i podmieniający nie mogą przekroczyć 100 znaków

 

download

Załączony plik  PodmianaZnakow.rar   10,41 KB  189 Ilość pobrań