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
 

Owner123 - zdjęcie

Owner123

Rejestracja: 12.10.2009
Aktualnie: Nieaktywny
Poza forum Ostatnio: 18.12.2011 18:32
*----

#144797 MySQL - z czym to się je.

Napisane przez Owner123 w 17.06.2010 14:31

Witam.
Na wstępnie chciałbym powiedzieć, że nie będę opisywał tu zapytań MySQL ponieważ to mija się z celem. Jeśli ktoś chce się pouczyć zapytań MySQL zapraszam na uw-team.org (nie wiem czy taka reklama jest dozwolona, jeśli tak to prosiłbym o nie wlepianie mi warna). Szczerze polecam Wideotutorial Unknow'a na temat MySQL.
Życzę miłej lekturki.

MySQL, cóż to takiego ?

Edit. Thx 4 R3X
SQL - Structured Query Language (pl. strukturalny język zapytań), jest to nowoczesny język, dzięki któremu można posługiwać się bazami danych. MySQL to popularna odmiana serwera, które potrafi przetwarzać zapytania w tym języku.

Przejdźmy do sedna.
Aby móc zacząć pracować, musimy dołączyć do swojego pluginu dyrektywą #include odpowiednią biblioteke:

#include <sqlx>


Dobra mamy już odpowiednie narzędzia aby zacząć

Są 2 metody, pracy na bazach danych. Ja opiszę tutaj sposób, który używam osobiście i który sprawdza się w wielu przypadkach (m.in. Diablo Mod).
Ta metoda opiera się tylko na utworzeniu "pojemnika" który przechowuje dane dostępowe do bazy danych i odpowiednim użyciu go.
Możemy go stworzyć funkcją SQL_MakeDbTuple:
native Handle:SQL_MakeDbTuple(const host[], const user[], const pass[], const db[], timeout=0);

Po kolei:
const host[] - adres Hosta. Np. db4free.net, 127.0.0.1
const user[] - login. np. root
const pass[] - hasło.
const db[] - nazwa bazy danych. np. nauka
timeout=0 - tego parametru nie będę opisywał. Najlepiej zostawić tak jak jest.

Przykładowe użycie:
new Handle:Tuple = SQL_MakeDbTuple("127.0.0.1", "root", "", "nauka")

Najlepiej aby zmienne, które są właśnie "pojemnikiem" były globalne.

W jaki sposób wykonać jakieś zapytanie ?

A więc tak, są 2 metody wykonywania zapytań do bazy danych:

- Bezpośrednia (NON-Threaded)
- Pośrednia (Threaded)

Poniżej postaram się opisać obie metody.

Pośrednia / Threaded

Ta metoda przy dużej ilości wpisów w bazie (30k++) zaczyna działać z dużym opóźnieniem, nie ważne na jak dobrym hostingu mamy ulokowaną bazę danych. Jednak jest o wieele bezpieczniejsza. Na czym polega jej bezpieczeństwo?
Otóż tą metodą otrzymujemy wynik później, jednak nie powoduje ona lagów - w przeciwieństwie do NON-Threaded (w niektórych przypadkach, które potem opiszę).

Aby posłuzyć się tą metodą jest funkcja SQL_ThreadQuery:
native SQL_ThreadQuery(Handle:db_tuple, const handler[], const query[], const data[]="", dataSize=0);


Handle:db_tuple - uchwyt do "pojemnika"(nie wiedziałem jak to inaczej określić). Niezbędny aby cokolwiek zrobić.
const handler - nazwa funkcji publicznej która zostanie wywołana PO wykonaniu zapytania.
const query[] - treść zapytania. Jeśli jest skomplikowane lub wymaga użycia %d lub %s to wtedy należy to odpowiednio przygotować komendą format().
Podziękowania dla G[o]Q.
const data[]="" oraz dataSize=0 - parametry opcjonalne.

data to jakby tablica parametrow a dataSize to ich ilosc tak jak parametry w set_task o czym jest osobny poradnik


Przykładowe użycie:

new Handle:gTuple, bool:gConnected
[...]
//Tworzymy "pojemnik" i ustawiamy zmienną gConnected na true jeśli wszystko obeszło się bez przeszkód.

SaveData(id)
{
if(!gConnected) return

new Data[1]
Data[0] = id
new qCommand[512], szName[32]
get_user_name(id, szName, charsmax(szName))
format(qCommand, sizeof qCommand-1, "INSERT INTO nauka VALUES(%s, %i, %i);", szName, iPlayerXP[id], iPlayerLvl[id])
SQL_ThreadQuery(gTuple, "SaveHandler", qCommand, Data, 1)
}

public SaveHandler(FailState, Handle:Query, Error[], Errorcode, Data[], DataSize)
{
new id = Data[0]
if(Errorcode)
log_amx("Blad w zapytaniu: %s [SaveData]", Error)

if(FailState == TQUERY_CONNECT_FAILED)
{
log_amx("Nie mozna podlaczyc sie do bazy danych.")
return PLUGIN_CONTINUE
}
else if(FailState == TQUERY_QUERY_FAILED)
{
log_amx("Zapytanie anulowane [SaveData]")
return PLUGIN_CONTINUE
}

return PLUGIN_CONTINUE
}


Oczywiście zamiast funkcji log_amx, możemy posłużyć się funkcją log_to_file.
Przedstawiłem tu zapis Nicku, Xp i Levela graczy do bazy MySQL.

A co z odczytem ?
Powyższa instrukcja spowoduje, dodanie kolejnego wpisu do bazy danych. Nie ważne czy taki wpis już istnieje czy nie.
Aby sprawdzić czy dany wpis istnieje musimy posłużyć się kolejnym zapytaniem:
new Handle:gTuple, bool:gConnected
[...]
//Tworzymy "pojemnik" i ustawiamy zmienną gConnected na true jeśli wszystko obeszło się bez przeszkód.

CheckData(id)
{
if(!gConnected) return

new Data[1]
Data[0] = id
new qCommand[512], szName[32]
get_user_name(id, szName, charsmax(szName))
format(qCommand, sizeof qCommand-1, "SELECT * FROM `nauka` WHERE `nick` = '%s'", szName)
SQL_ThreadQuery(gTuple, "CheckHandler", qCommand, Data, 1)
}

public CheckHandler(FailState, Handle:Query, Error[], Errorcode, Data[], DataSize)
{
new id = Data[0]
if(Errorcode)
log_amx("Blad w zapytaniu: %s [CheckData]", Error)

if(FailState == TQUERY_CONNECT_FAILED)
{
log_amx("Nie mozna podlaczyc sie do bazy danych.")
return PLUGIN_CONTINUE
}
else if(FailState == TQUERY_QUERY_FAILED)
{
log_amx("Zapytanie anulowane [CheckData]")
return PLUGIN_CONTINUE
}

if(!SQL_MoreResults(Query)) // Nie znaleziono wpisów w bazie danych. Możemy spokojnie utworzyć.
DodajWpis(id)
else // A jednak coś znalazł ! Żeby nie robić kolejnej funkcji od razu odczytujemy.
{
iPlayerXp[id] = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "exp")) // Ponieważ funkcja SQL_ReadResult wymaga ID pola, a my go nie mamy musimy posłużyć się funkcją SQL_FieldNameToNum.
iPlayerLvl[id] = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "lvl")) // j/w
}

return PLUGIN_CONTINUE
}


Tutaj za wiele chyba tłumaczyć nie muszę. Sprawdzamy czy rekordy w bazie danych istnieją. Jeśli nie, to dodajemy, ale jak istnieje od razu odczytujemy dane.

Przechodzenie z jednego wpisu do drugiego
Załóżmy, że zapytanie SELECT zwróci nam kilka rekordów. Powyższa metoda nie zadziała poprawnie albo zadziała inaczej niż przewidywaliśmy.
Wtedy przydatna jest komenda SQL_NextRow(Handle:Query).
Przykład (zaczerpnięty z DiabloModa):
while(SQL_MoreResults(Query))
{
new i = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "klasa"))
srv_avg[i] = SQL_ReadResult(Query, SQL_FieldNameToNum(Query, "AVG"))
SQL_NextRow(Query)
}

Jak zapewne wiadomo - klas w Diablo Modzie jest 8. Zatem zapytanie powyższe zapytanie SELECT odczyta zawartość tylko dla Maga a dla reszty nic by to nie zmieniło. Tutaj zastosowano pętle while która sprawdza czy nadal są jakieś zapytania, jeśli już nie ma - przerwij. Jak już wspomniałem funkcja SQL_NextRow powoduje przeskoczenie z jednego zapytania na drugie, zmniejszając przy tym wartość zwracaną funkcji SQL_MoreResults().

Dla tych co nie rozumieją zbytnio mechanizmu działania
No dobrze. Zapytanie SELECT zwróciło nam 3 rekordy. Chcemy odczytać wszystkie 3, więc tutaj musimy użyć naszej funkcji - SQL_NextRow. Ponieważ, funkcja SQL_MoreResults zwraca ilość rekordów które zostały do odczytania jeśli nic nie zrobiliśmy ma obecnie wartość 3. Dla pomocy kod:
while(SQL_MoreResults(Query))
{
//kod
SQL_NextRow(Query)
}

Po pierwszym obrocie pętli przesuneliśmy się z rekordu pierwszego, na rekord drugi i już wartość zwracana przez funkcje SQL_MoreResults(Query) ma obecnie 2. Teraz możemy bez przeszkód odczytać zawartość kolejnego rekordu.

NOWE!!!
Bezpośrednia / NON-Threaded
Ta metoda daje natychmiastowy zwrot rezultatu ALE pod warunkiem że bazę danych mamy ulokowaną na tej samej maszynie co serwer. W przeciwnym wypadku na serwerze będą ściny serwera i masakryczne pingi.
Aby móc zacząć robić cokolwiek musimy się wpierw połączyć z bazą:

Handle:SQL_Connect(Handle:sqlTuple, &error, szError[], len);

I tutaj strzeżcie się! Pamiętajcie aby ZAWSZE użyc SQL_FreeHandle(Handle:db) jak skończycie majstrować z bazą ! Jak tego nie będziecie robić, serwer będzie crashować bez żadnych error logów. Przykładowe połączenie z bazą wygląda następująco:

public client_authorized(id)
{
new Handle:hConnection, iError, szError[256];

if((hConnection = SQL_Connect(g_hSqlTuple, iError, szError, 255)))
{
// operacje na bazie danych
}
else
{
log_error(AMX_ERR_GENERAL, "Brak polaczenia z baza danych !");
log_error(AMX_ERR_GENERAL, "Kod bledu: %i", iError);
log_error(AMX_ERR_GENERAL, "Tresc bledu: %s", szError);
}

SQL_FreeHandle(hConnection); // PAMIETAJ O TYM BO INACZEJ CZEKA CIE ZGUBA !!!
}


I co to daje ? W metodzie pośredniej takie coś było zbędne!
Otóż użycie tego daje nam możliwość bezpośredniego wprowadzania zapytań do bazy danych. Aby wprowadzić zapytanie musimy użyć 2 funkcji:

Handle:SQL_PrepareQuery(Handle:connection, fmt[], any:...);
bool:SQL_Execute(Handle:query);

Dla ścisłości: funkcja SQL_Execute naprawdę nie zwraca typu bool tylko typ int. Jednak napisałem bool aby uświadomić Tobie, Drogi czytelniku, aby ta funkcja zwraca tylko wartości 1 i 0 aby nas poinformować o tym czy wykonanie zapytania SQL przebiegło poprawnie.
Przejdźmy do małego opisu parametrów:
SQL_PrepareQuery:
Pierwszy parametr:
Uchwyt zwrócony przez funkcje SQL_Connect. Tak, właśnie dlatego było nam potrzebne ręczne połączenie się z bazą!
Drugi i reszta parametrów: Treść zapytania. Jest to w miarę elastyczne ponieważ możemy używać znacznikow %d, %s itd. Uwaga! Nie zalecam używanie tu zapytań typu UPDATE ! Zamiast tego polecam użycie zapytań REPLACE, jednak aby działały one poprawnie wymagane jest utworzenie klucza PRIMARY, UNIQUE lub INDEX. Dlaczego? Nawet jeśli kod jest w pełni zoptymalizowany i baza danych stoi na localhoscie, przy dużej ilości rekordów (100k+, czasem 50k+) powodowane są ścinki i lagi serwera.
Rezultat: Uchwyt do wykonania zapytania. Ta funkcja tylko przygotowuje zapytanie !!! Zapytanie jest wykonywane dopiero przy użyciu funkcji SQL_Execute()! I niech was ręka boska broni! Tutaj też uzywajcie funkcji SQL_FreeHandle()!!! Tak samo jak w przypadku SQL_Connect nie użycie tego powoduje crashe serwera bez żadnych logów!

SQL_Execute:
Jest tutaj tylko jeden parametr: Uchwyt zwrócony przez funkcje SQL_PrepareQuery. Wykonanie tej funkcji jest równoznaczne z wywołaniem zapytania, wcześniej przygotowanego przez funkcje SQL_PrepareQuery.

Dobra koniec teorii, czas na podanie przykładowego kodu:

public client_authorized(id)
{
new Handle:hConnection, iError, szError[256];

if((hConnection = SQL_Connect(g_hSqlTuple, iError, szError, 255)))
{
new szNick[32];
get_user_name(id, szNick, 31);

new Handle:hQuery = SQL_PrepareQuery(hConnection, "SELECT * FROM tabela WHERE `nick` = '%s'", szNick);

if(SQL_Execute(hQuery))
{
new num = 0;
while(SQL_MoreResults(hQuery))
{
num = SQL_ReadResult(hQuery, SQL_FieldNameToNum(hQuery, "klasa"));
g_iPlayerLvl[id][num] = SQL_ReadResult(hQuery, SQL_FieldNameToNum(hQuery, "lvl"));
g_iPlayerExp[id][num] = SQL_ReadResult(hQuery, SQL_FieldNameToNum(hQuery, "exp"));
SQL_NextRow(hQuery)
}
}
else
{
SQL_QueryError(hQuery, szError, 255);
log_error(AMX_ERR_GENERAL, "Blad w zapytaniu !");
log_error(AMX_ERR_GENERAL, "Kod bledu: %i", iError);
log_error(AMX_ERR_GENERAL, "Tresc bledu: %s", szError);
}

SQL_FreeHandle(hQuery); // Niech was reka boska broni, przed zapomnieniem o tym
}
else
{
log_error(AMX_ERR_GENERAL, "Brak polaczenia z baza danych !");
log_error(AMX_ERR_GENERAL, "Kod bledu: %i", iError);
log_error(AMX_ERR_GENERAL, "Tresc bledu: %s", szError);
}

SQL_FreeHandle(hConnection);
}


Dałem kod razem z SQL_Connect abyście dobrze widzieli w jaki sposób posługiwać się uchwytem do połączenia.

Jak zapewne widać zmian w korzystaniu z SQL_ReadResult i SQL_NextRow nie ma.

Na tym kończę ten tutorial!

Myślę że opisałem najważniejsze rzeczy. Jeśli ktoś chce poznać resztę funkcji które oferuję biblioteka sqlx wystarczy zajrzeć do pliku sqlx.inc który znajduję się w addons/amxmodx/scripting/include. Co prawda po angielsku, ale chyba z jakiejś przyczyny powstały tłumacze internetowe, prawda ? Dobrym punktem odniesienia jest Diablo Mod. Posiada on szereg funkcji dzięki którym możemy majstrować w bazie MySQL.

Wszelkie błędy, niedopowiedzenia oraz literówki lub inne badziewa, proszę zgłaszać w tym temacie.
Wszelka krytyka mile widziana smile.gif


  • +
  • -
  • 31


#137206 Tworzenie bytu.

Napisane przez Owner123 w 21.05.2010 21:22

Macie tutaj pewną funkcję do tworzenia bytów, z pełnymi parametrami(no, prawie ;>).
fm_spawn_ent(szClassname[] = "info_target", szModel[]="", Float:fMins[3] = {-1.0, -1.0, -1.0}, Float:fMaxs[3] = {1.0, 1.0, 1.0}, iSolid = SOLID_NOT, Float:fOrigin[3] = {0.0, 0.0, 0.0}, Float:fHealth = 100.0, Float:fTakedamage = DAMAGE_YES, iMovetype = MOVETYPE_NONE)
{
new ent = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target"))
if(!pev_valid(ent))
return 0;

set_pev(ent, pev_classname, classname)
engfunc(EngFunc_SetModel, ent, model)
dllfunc(DLLFunc_Spawn, ent)
set_pev(ent, pev_mins, mins)
set_pev(ent, pev_maxs, maxs)
set_pev(ent, pev_solid, solid)
set_pev(ent, pev_origin, fOrigin)
set_pev(ent, pev_health, health)
set_pev(ent, pev_takedamage, takedamage)
set_pev(ent, pev_movetype, movetype)

return ent;
}

Myślę że komuś może się przydać.
  • +
  • -
  • 3


#136048 AmxBans i Ultimate_ss

Napisane przez Owner123 w 17.05.2010 19:54

Zamień:
server_cmd("amx_ban ^"0^" ^"%s^" ^"Wrzuc 5 screeny na %s^"",name, forum)

na:
client_cmd(id, "amx_ban 0 ^"%s^" Wrzuc 5 screeny na %s",name, forum)

  • +
  • -
  • 1


#131987 Wieksze obrazenia z noza

Napisane przez Owner123 w 05.05.2010 14:03


#include <amxmodx>
#include <hamsandwich>

#define PLUGIN "One Hit KO Knife"
#define AUTHOR "Owner"
#define VERSION "1.0"

public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
RegisterHam(Ham_TakeDamage, "player", "fwHamTakeDamage")
}

public fwHamTakeDamage(victim, idinflictor, attacker, Float:damage, damagebits)
{
new weapon = get_user_weapon(attacker)
if(weapon == CSW_KNIFE)
SetHamParamFloat(4, 999.0)
}

Powinno dzialac.
  • +
  • -
  • 1


#131448 Respawn Gracza

Napisane przez Owner123 w 03.05.2010 20:41

Zrób minimalnego taska po jego śmierci i będzie śmigac. Ofc. dopisz jeszcze #include na początku ;d
  • +
  • -
  • 1


#125237 Przeniesienie z kompa na pukawka.pl

Napisane przez Owner123 w 11.04.2010 17:58

Tak to możesz spokojnie przerzucić. Jedyny wymóg do linuxa to inne biblioteki.
  • +
  • -
  • 1


#125088 Problem z napisaniem części skrypru!

Napisane przez Owner123 w 11.04.2010 12:29

Nie klikasz na napis "Reputacja" tylko na "+" nad nim ;)
  • +
  • -
  • 1


#125024 Kolor napisu

Napisane przez Owner123 w 11.04.2010 09:52

 ColorChat(0,GREEN,"Zabiles ^x03%s^x04 w tym ^x03%s^x04 Headow");


^x03 - Team Color
^x04 - Zielony
^x01 - Normalny
Jeśli dobrze pamiętam :F
  • +
  • -
  • 2


#118826 Problem z pluginem sma

Napisane przez Owner123 w 14.03.2010 21:06

/* AMX Mod X
* Descriptive 'Fire in the hole!'
*
* © Copyright 2006 by VEN
*
* This file is provided as is (no warranties)
*
* DESCRIPTION
* Plugin provides additional colored text for "Fire in the hole!" radio chat message.
* The color and the text is different for each grenade type and can be altered.
* This will help teammates to get the throwed grenade type and act accordingly.
* Search for "EDITABLE" mark in the plugin's source code to configure text and color.
*
* CREDITS
* Damaged Soul - colored chat text method
* p3tsin - team color override method
*/

#include <amxmodx>

#define PLUGIN_NAME "Descriptive 'Fire in the hole!'"
#define PLUGIN_VERSION "0.1"
#define PLUGIN_AUTHOR "VEN"

enum grenade {
GRENADE_HE,
GRENADE_FLASH,
GRENADE_SMOKE
}

// EDITABLE: grenade description
new const g_grenade_description[_:grenade][] = {
" [HE !!] "
" [Oslepiajacy !!] "
" [Mrozonka !!] "
}

enum color {
COLOR_NORMAL,
COLOR_RED,
COLOR_BLUE,
COLOR_GRAY,
COLOR_GREEN
}

// EDITABLE: grenade description text color
new const g_grenade_desccolor[_:grenade] = {
COLOR_RED,
COLOR_GRAY,
COLOR_GREEN
}

new const g_grenade_weaponid[_:grenade] = {
CSW_HEGRENADE,
CSW_FLASHBANG,
CSW_SMOKEGRENADE
}

#define COLORCODE_NORMAL 0x01
#define COLORCODE_TEAM 0x03
#define COLORCODE_LOCATION 0x04

new const g_color_code[_:color] = {
COLORCODE_NORMAL,
COLORCODE_TEAM,
COLORCODE_TEAM,
COLORCODE_TEAM,
COLORCODE_LOCATION
}

new const g_color_teamname[_:color][] = {
"",
"TERRORIST",
"CT",
"SPECTATOR",
""
}

#define RADIOTEXT_MSGARG_NUMBER 5

enum radiotext_msgarg {
RADIOTEXT_MSGARG_PRINTDEST = 1,
RADIOTEXT_MSGARG_CALLERID,
RADIOTEXT_MSGARG_TEXTTYPE,
RADIOTEXT_MSGARG_CALLERNAME,
RADIOTEXT_MSGARG_RADIOTYPE,
}

new const g_required_radiotype[] = "#Fire_in_the_hole"
new const g_radiotext_template[] = "%s (RADIO): Fire in the hole!"

new g_msgid_saytext
new g_msgid_teaminfo

public plugin_init() {
register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

register_message(get_user_msgid("TextMsg"), "message_text")

g_msgid_saytext = get_user_msgid("SayText")
g_msgid_teaminfo = get_user_msgid("TeamInfo")
}

public message_text(msgid, dest, id) {
if (get_msg_args() != RADIOTEXT_MSGARG_NUMBER || get_msg_argtype(RADIOTEXT_MSGARG_RADIOTYPE) != ARG_STRING)
return PLUGIN_CONTINUE

static arg[32]
get_msg_arg_string(RADIOTEXT_MSGARG_RADIOTYPE, arg, sizeof arg - 1)
if (!equal(arg, g_required_radiotype))
return PLUGIN_CONTINUE

get_msg_arg_string(RADIOTEXT_MSGARG_CALLERID, arg, sizeof arg - 1)
new caller = str_to_num(arg)
if (!is_user_alive(caller))
return PLUGIN_CONTINUE

new clip, ammo, weapon
weapon = get_user_weapon(caller, clip, ammo)
for (new i; i < sizeof g_grenade_weaponid; ++i) {
if (g_grenade_weaponid[i] == weapon) {
static text[192]
new pos = 0
text[pos++] = g_color_code[COLOR_NORMAL]

get_msg_arg_string(RADIOTEXT_MSGARG_CALLERNAME, arg, sizeof arg - 1)
pos += formatex(text[pos], sizeof text - pos - 1, g_radiotext_template, arg)
copy(text[++pos], sizeof text - pos - 1, g_grenade_description[i])

new desccolor = g_grenade_desccolor[i]
if ((text[--pos] = g_color_code[desccolor]) == COLORCODE_TEAM) {
static teamname[12]
get_user_team(id, teamname, sizeof teamname - 1)

if (!equal(teamname, g_color_teamname[desccolor])) {
msg_teaminfo(id, g_color_teamname[desccolor])
msg_saytext(id, text)
msg_teaminfo(id, teamname)

return PLUGIN_HANDLED
}
}

msg_saytext(id, text)

return PLUGIN_HANDLED
}
}

return PLUGIN_CONTINUE
}

msg_teaminfo(id, teamname[]) {
message_begin(MSG_ONE, g_msgid_teaminfo, _, id)
write_byte(id)
write_string(teamname)
message_end()
}

msg_saytext(id, text[]) {
message_begin(MSG_ONE, g_msgid_saytext, _, id)
write_byte(id)
write_string(text)
message_end()
}

Łap ;)
  • +
  • -
  • 1


#118377 Wpływanie na obrażenia

Napisane przez Owner123 w 13.03.2010 12:36

public fwTakeDamage(victim, inflictor, attacker, Float:damage, damagebits)
{
if(damagebits & DMG_SHOCK)
SetHamParamFloat(4, 90.0);
return HAM_IGNORED;
}

  • +
  • -
  • 2


#117757 co dodać do tego pluginu?

Napisane przez Owner123 w 10.03.2010 14:43

public plugin_init()
{
register_plugin(PLUG_NAME, PLUG_VERS, PLUG_AUTH)
register_concmd("amx_givehat", "Give_Hat", ADMIN_RCON, "<nick> <mdl #>")
register_concmd("amx_removehats", "Remove_Hat", ADMIN_RCON, " - Removes hats from everyone.")
register_menucmd(register_menuid("\yMenu Czapeczek: [Strona"),(1<<0|1<<1|1<<2|1<<3|1<<4|1<<5|1<<6|1<<7|1<<8|1<<9),"MenuCommand")
register_clcmd("say /czapki", "ShowMenu", ADMIN_KICK, "Shows Knife menu")
}

public ShowMenu(id,level,cid)
{
if (!cmd_access(id,level,cid,1)){
client_print(id, print_chat, "[Czapki] Tylko admini moga nosic czapki!")
return PLUGIN_HANDLED // check access
}
CurrentMenu[id] = 1
ShowHats(id)
return PLUGIN_HANDLED
}

Łap ;F
  • +
  • -
  • 1


#112979 Prosba o lekką modyfikacje "bloodyknife"

Napisane przez Owner123 w 18.02.2010 17:03

#include <amxmodx>
#include <fakemeta>

#pragma semicolon 1

#define MAX_PLAYERS 32

new const CHUCKY_KNIFE_WOB[] = "models/v_knife_r.mdl";
new const CHUCKY_KNIFE[] = "models/chucky_knife.mdl";

new bool:g_bloody[MAX_PLAYERS+1];
new g_max_clients;
new g_bk_enabled, g_bk_rndreset;

public plugin_precache() {
engfunc(EngFunc_PrecacheModel, CHUCKY_KNIFE);
engfunc(EngFunc_PrecacheModel, CHUCKY_KNIFE_WOB);
}

public plugin_init() {
register_plugin("Bloody Knife", "1.0", "Dontask-jello/connor");

g_bk_enabled = register_cvar("bk_enabled", "1");
g_bk_rndreset = register_cvar("bk_rndreset", "0");

register_forward(FM_EmitSound, "fwEmitSound");

register_event("HLTV", "eNewRound", "a", "1=0", "2=0");
register_event("CurWeapon", "eCurWeapon", "be", "1=1", "2=29");
register_event("DeathMsg", "eDeathMsg", "a");
}

public plugin_cfg() {
g_max_clients = global_get(glb_maxClients);
}

public client_putinserver(id) {
g_bloody[id] = false;
}

public eCurWeapon(id) {
if(!get_pcvar_num(g_bk_enabled))
return;

if(!g_bloody[id])
set_pev(id, pev_viewmodel2, CHUCKY_KNIFE_WOB);
else
set_pev(id, pev_viewmodel2, CHUCKY_KNIFE);
}

public fwEmitSound(id, channel, sample[], float:volume, float:attenuation, fFlags, pitch) {
if(!(1 <= id <= g_max_clients))
return FMRES_IGNORED;
if(!get_pcvar_num(g_bk_enabled))
return FMRES_IGNORED;

if(g_bloody[id])
return FMRES_IGNORED;
if( sample[0] == 'w' && sample[8] == 'k' && ( sample[17] == 'b' || (sample[14] == 'h' && sample[17] != 'w') ) )
{
g_bloody[id] = true;
eCurWeapon(id);
return FMRES_SUPERCEDE;
}
return FMRES_IGNORED;
}

public eDeathMsg() {
new victim = read_data(2);
if(g_bloody[victim])
g_bloody[victim] = false;
}

public eNewRound() {
if(!get_pcvar_num(g_bk_enabled))
return;
if(!get_pcvar_num(g_bk_rndreset))
return;

new players[MAX_PLAYERS], inum;
get_players(players, inum, "h");
for(new i; i<inum; ++i)
{
if(g_bloody[players[i]])
g_bloody[players[i]] = false;
}
}

Powinno działać.
  • +
  • -
  • 1


#112342 Dodanie hitboxa

Napisane przez Owner123 w 15.02.2010 20:11

set_pev(ent, pev_takedamage, DAMAGE_YES)

RegisterHam(Ham_TakeDamage/Ham_TraceAttack, "Nazwa_bytu", "fwdHamAttack")

  • +
  • -
  • 1


#111220 problem

Napisane przez Owner123 w 11.02.2010 19:17

Zamiast TE_BEAMENTPOINTS zalecam użyć TE_BEAMENT, różnica jest w tym że linia jest tworzona między 2 bytami, a nie bytem i punktem.
Fragment z message_const.inc:
// write_byte(TE_BEAMENTS)
// write_short(start entity)
// write_short(end entity)
// write_short(sprite index)
// write_byte(starting frame)
// write_byte(frame rate in 0.1's)
// write_byte(life in 0.1's)
// write_byte(line width in 0.1's)
// write_byte(noise amplitude in 0.01's)
// write_byte(red)
// write_byte(green)
// write_byte(blue)
// write_byte(brightness)
// write_byte(scroll speed in 0.1's)


Edit.
new body 
get_user_aiming(id, cel, body)
if(cel != 0 && is_user_alive(id)&&(get_user_button(id)& IN_USE)&&(get_user_flags(id) &ADMIN_KICK))
{
//new button = get_user_button(id)
//if(button & IN_USE)
pokaz(id,cel)


}

A zmienna cel to gdzie ? Też musi być zadeklarowana.

Edit2.
new sprite_lgt = 0
new g_msg_screenfade

Zrobiłeś zmienne a nie przypisałeś im odpowiednich wartosci ...
  • +
  • -
  • 1


#110842 Prośba o napisanie pluginu

Napisane przez Owner123 w 09.02.2010 21:58

#include <amxmodx>

public plugin_init() {
	register_plugin("Admin Chat", "1.0", "Owner")
	register_logevent("NewRound", 2, "1=Round_Start")
}

fnGreenChat( plr, const message[], {Float,Sql,Result,_}:... )
{
static max_players, svc_saytext;
if( !max_players )
{
	max_players = get_maxplayers( );
}
if( !svc_saytext )
{
	svc_saytext = get_user_msgid( "SayText" );
}

static msg[192];
msg[0] = 0x04;

vformat( msg[1], sizeof msg - 2, message, 3 );

if( plr > 0 && plr <= max_players )
{
	message_begin( MSG_ONE, svc_saytext, { 0, 0, 0 }, plr );
	write_byte( plr );
	write_string( msg );
	message_end( );
}
else if( plr == 0 )
{
	for( new i = 1 ; i <= max_players ; i++ )
	{
		if( is_user_connected( i ) )
		{
			message_begin( MSG_ONE, svc_saytext, { 0, 0, 0 }, i );
			write_byte( i );
			write_string( msg );
			message_end( );
		}
	}
}

return 1;
}

public NewRound()
{
new num, playerz[32], i
get_players(playerz, num, "h")
for(i = 0; i < num; i++)
{
	new id = playerz[i]
	if(is_user_admin(id))
		fnGreenChat(id, "Tez was lubie <img src='https://amxx.pl/public/style_emoticons/default/smile.gif' class='bbc_emoticon' alt=':)' />)")
	}
}
Nie jestem pewien czy event nowej rundy jest wywołany poprawnie ...
  • +
  • -
  • 1