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
 

Vasto_Lorde - zdjęcie

Vasto_Lorde

Rejestracja: 12.05.2012
Aktualnie: Nieaktywny
Poza forum Ostatnio: 21.01.2020 15:51
*****

#583729 Ustawienie obrażeń z inteligencją

Napisane przez RasiaQ w 08.11.2013 21:49

Chciałem w tym temacie zaprezentować, jak ustawić danej klase x(+int) obrażeń z danej broni. (Nie znalazłem takowego w tym dziale ;_; )

 

1. Na sam początek dodajemy:

#include <hamsandwich>

i pod includami:

#define DMG_BULLET (1<<1)

i zmienna:

new bool:ma_klase[33];

2. do plugin_init() dodajemy:

RegisterHam(Ham_TakeDamage, "player", "TakeDamage");

3*. Jeśli nie masz to dodaj:

public cod_class_enabled(id)
    ma_klase[id] = true;

public cod_class_disabled(id)
    ma_klase[id] = false;

4. I na koniec .sma

public TakeDamage(this, idinflictor, idattacker, Float:damage, damagebits)
{
    if(!is_user_connected(idattacker))
        return HAM_IGNORED;
    
    if(!ma_klase[idattacker])
        return HAM_IGNORED;
    
    if(damagebits & DMG_BULLET)
    {
        new weapon = get_user_weapon(idattacker);
        

if(get_user_team(this) != get_user_team(idattacker) && get_user_weapon(idattacker) == CSW_BRON && damagebits & DMG_BULLET)
cod_inflict_damage(idattacker, this, 5.0, 0.1, idinflictor, damagebits);
                
    }
    
    return HAM_IGNORED;
}

 

CSW_BRON - BRON zmieniasz na nazwę swojej broni np. CSW_M4A1

 

W powyższym kodzie przyjrzyj się temu:

cod_inflict_damage(idattacker, this, 5.0, 0.1, idinflictor, damagebits);

 

5.0 oznacza ile obrażeń będziemy zadawali. W tym przypadku jest to 5(+int). Jeśli zmienimy np. na 50.0 to będziemy zadawać 50(+int) obrażeń więcej.

0.1 Jest to współczynnik/mnożnik tego, jak nasza inteligencja będzie się przekładała na obrażenia. Np.

0.1 - 10int = 1 DMG
0.2 - 5int = 1 DMG
0.15 - 6.(3)int = 1 DMG
0.14 - 7.14int = 1 DMG
0.066666 - 15int = 1 DMG
0.05 - 20int = 1 DMG

 

Sposób przeliczania tego jest bardzo prosty (nauczył mnie go dzisiaj rano Vasto_Lorde[btw. dzięki :D]), otóż 1(jeden) dzielimy przez tyle ile chcemy inteligencji na 1 DMG. Np.

1/20 = 0.05 ( / zastępuje znak dzielenia ( patrz kod powyżej. Co wyszło ?)
1/15 = 0.66666

 

Łatwo sprawdzić na kalkulatorze ;P

 

5. A więc nasz finalny kod będzie wyglądał tak:

/* Plugin generated by AMXX-Studio */

#include <amxmodx>
#include <codmod>
#include <hamsandwich>

#define DMG_BULLET (1<<1) 

new bool:ma_klase[33];

new const nazwa[] = "TEST";
new const opis[] = "Zadajesz 5(+int) obrazen z xxx";
new const bronie = 1<<CSW_M3;
new const zdrowie = 20;
new const kondycja = 40;
new const inteligencja = 50;
new const wytrzymalosc = 60;

public plugin_init() 
{
    register_plugin(nazwa, "1.0", "Drizzt");
    
    cod_register_class(nazwa, opis, bronie, zdrowie, kondycja, inteligencja, wytrzymalosc);
    RegisterHam(Ham_TakeDamage, "player", "TakeDamage");
}

public cod_class_enabled(id)
    ma_klase[id] = true;

public cod_class_disabled(id)
    ma_klase[id] = false;

public TakeDamage(this, idinflictor, idattacker, Float:damage, damagebits)
{
    if(!is_user_connected(idattacker))
        return HAM_IGNORED;
    
    if(!ma_klase[idattacker])
        return HAM_IGNORED;
    
    if(damagebits & DMG_BULLET)
    {
        new weapon = get_user_weapon(idattacker);
        

if(get_user_team(this) != get_user_team(idattacker) && get_user_weapon(idattacker) == CSW_BRON && damagebits & DMG_BULLET)
cod_inflict_damage(idattacker, this, 5.0, 0.1, idinflictor, damagebits);
                
    }
    
    return HAM_IGNORED;
}

 

To chyba wszystko jasne ;>

Dziękuję za uwagę. Gdyby ktoś czegoś nie rozumiał, będę wyjaśniał.

 


  • +
  • -
  • 13


#759617 Włamania na serwerl pomocy!

Napisane przez janofer w 18.06.2019 07:20

Dproto czy reunion? Dobrze masz zrobioną konfigurację by nie mogli sobie generować takich samych SID'ów jak u adminów?


  • +
  • -
  • 1


#758965 SklepSMS

Napisane przez Eryk172 w 01.05.2019 15:29

Wszystko działa jak nalezy, potwierdzam. 

 

@O'Zone

Teraz Ci stworzy 10 osób issues z problemen braku połączenia z bazą MySQL  :wstyd:

 

Chętnie za drobną opłatą dokonam konfiguracji oraz instalacji sklepu. PW


  • +
  • -
  • -2


#757242 Proxy/VPN Check

Napisane przez DarkGL w 24.02.2019 02:35

opis
Plugin wykrywa graczy używających VPN / Proxy i kickuje ich serwera , mogą być to np. boty reklamujące inne serwery.

Link do oryginalnego repozytorium https://github.com/j...ice/proxy_check autor juicejuicejuice
 
instalacja
Plugin do działania wymaga pluginu HTTP:X
 
W plugins ini httpx umieszczamy przed proxy_check np.
 
httpx.amxx
proxy_check.amxx
 
download

Załączone pliki


  • +
  • -
  • 12


#748274 Pokemod - informacje

Napisane przez NiczegoWinien w 02.04.2018 11:11

Prace idą do przodu !!

Znalazłem osobę odpowiedzialną za modele. Wyglądają niesamowicie. Animacje są bardzo realne i płynne.

Na dzień dzisiejszy kod wygląda następująco:

- W menu mamy 6 PokeSlotów (można dodawać,wymieniać nasze Pokemony)

- Naciskając LPM ładuje sie pasek mocy rzucenia PokeBalla

- Drugie nacisnięcie LPM kończy ładowanie mocy i nasz PokeBall "leci"

- Po zetknięciu PokeBalla z powierzchnią odgrywana jest "animacja" wydostania/wyjścia Pokemona z PokeBalla

 

Jeżeli chodzi o Dzikie Pokemony :

- Ustawienie Respa Pokemona

- Odgyrwana animacja chodzenia a także samo porszuanie się Pokemona po mapie

 

Prace idą dość wolno ponieważ staram się uzyskać podobny efekt jaki był w anime.

 

Potrzebuję jeszcze jednej osoby która by zrobila dość prostą mapę dla mnie i wytłumaczyła pare rzeczy z tym związane.

Liczę na waszą pomoc.

 

Pozdrawiam


  • +
  • -
  • 2


#674401 Tworzenie i modyfikacja entity

Napisane przez grankee w 09.12.2014 15:20

Witam. Postanowiłem trochę się rozpisać o entitach. Poradnik ten z założenia ma być długi i obszerny, a mój system pracy nie sprzyja więc czego nie skończę dziś, dopiszę jutro.
 
Entity to nic innego jak byty na mapie. Mapa (widzialna i namacalna bryła, wewnątrz której toczymy rozgrywkę wraz z jej wszystkimi elementami, które nie są odrębnymi bytami) sama w sobie też jest bytem o numerze 0.
Każde entity ma swój unikalny numer, raz nadany podczas tworzenia entity nigdy nie ulega zmianie. Oczywiście jeśli dany ent zostanie usunięty to jego numer zostaje "zwolniony" i może zostać on nadany kolejnemu entowi podczas jego tworzenia.
 
Entity posiada wiele właściwości, które z grubsza postaram się objaśnić. Podstawową sprawą jest, że ma kształt prostopadłościanu i jakiś model, czyli jakoś wygląda, ale model nie musi wcale się pokrywać z kształtem i wymiarami bytu. Do tworzenia lub modyfikacji tych właściwości możemy używać dwóch modułów - <engine> oraz <fakemeta>, jednak w tym tutorialu skupię się na tym pierwszym z prostego powodu - jest łatwiejszy i bardziej przejrzysty. Na koniec postaram się nie zapomnieć przedstawić przykładów użycia fakemety z tym samym skutkiem.
 
Do ustawiania właściwości entity używamy funkcji:
 
entity_set_byte(index,klucz,wartość)
entity_set_edict(index,klucz,wartość)
entity_set_float(index,klucz,Float:wartość)
entity_set_int(index,klucz,wartość)
entity_set_string(index,klucz,const wartość[])//tablica string
entity_set_vector(index,klucz,wartość)
 
 
ponadto:
 
entity_set_model(index,const sciezka_do_modelu[])
entity_set_origin(index,const Float:fNewOrigin[3])
entity_set_size(index,const Float:mins[3],const Float:maxs[3])
 
 
Te 3 ostatnie różnią się tym, że aktualizują zmienione dane w silniku gry. Koniecznie trzeba ich użyć, aby poprawnie stworzyć entity.
 
 
Pobierać te właściwości można funkcjami:
 
entity_get_byte(index,klucz)//zwraca returnem wartość typu int
entity_get_edict(index,klucz)//zwraca returnem wartość typu int
entity_get_float(index,klucz)//zwraca returnem wartość typu float
entity_get_int(index,klucz)//zwraca returnem wartość typu int
entity_get_string(index,klucz,tablica_znakow[],dlugosc_tablicy_znakow)//zwrot przez referencję do tablicy znaków podanej jako argument
entity_get_vector(index,klucz,tablica_float[3])//zwrot przez referencję do tablicy trójelementowej typu float
 
 
No dobra, ale co to jest ten klucz?
Jest to liczba całkowita określająca, którą właściwość chcemy sprawdzić/zmienić. Dla ułatwienia skorzystajmy z przygotowanych do tego elementów typu wyliczeniowego, dzięki czemu będziemy wiedzieli z grubsza co dany klucz nam zmieni. 
Każda funkcja ma przygotowany dla siebie typ wyliczeniowy, osobny dla byte,edict,float,int,string i vector(postaram się uzupełniać, może ktoś coś podpowie):
Spoiler
 
 
 
 
Podzielmy entity ze względu na klasę.
Pierwsza podstawowa klasa bez jakiej gra nie zainstnieje to
player
Więcej o graczu:
Spoiler
Dalej mamy najczęściej spotykane byty:
info_player_start - miejsce spawnu CT
info_player_deathmatch- miejsce spawnu Terro
func_buyzone - w jego wnętrzu można kupować
func_bomb_target - w jego wnętrzu można podkładać pakę
weapon_usp, weapon_glock i cała reszta broni - broń posiadana przez gracza
func_wall - ściana, ale nie tylko, paradoksalnie chyba żadna ściana nie jest bytem tej klasy tylko częścią mapy. Praktycznie każdy obiekt może być tej klasy(np. skrzynka, barierka...), są to obiekty nie pełniące żadnej roli specjalnej a jedynie mają być i istnieć.
func_breakable - obiekt, który da się zniszczyć np. szyba, kratka do wentylacji, skrzynki niszczone wybuchem bomby i wiele innych
func_illusionary - ma model, czyli jakoś wygląda, ale nie zatrzymuje pocisków, nie blokuje ruchu.
trigger_multiple - byt o solidzie 1 czyli SOLID_TRIGGER, jego dotknięcie alarmuje go, ale nie blokuje ruchu, zwykle alarmuje inny byt do wykonania thinku, czyli jakiejś czynności, np drzwi do otwarcia się na de_prodigy.
func_door - drzwi
func_door_rotating - drzwi obrotowe
func_ladder - drabina
trigger_hurt - rani po dotknięciu go
 
 
Postaram się coś jeszcze dopisać.
 
 
 
No to trochę teorii za nami, teraz pora stworzyć nasze entity:
Załóżmy, że potrzebna nam ściana, której ścieżka do modelu to "models/wall/wall.mdl"
new byt=create_entity("func_wall")//funkcja tworzy byt klasy func_wall, zwracając numer powstałego entity, który przypisujemy zmiennej 'byt'
entity_set_model(ent,"models/wall/wall.mdl")
new Float:mins[3],Float:maxs[3]//aby powstał prostopadłościan (takiego kształtu jest entity) musimy rozciągnąć go w przestrzeni za przeciwległe rogi i to właśnie odległości od originu do tych rogów
//odpowiednio do rogu najbardziej wysuniętego w kierunku ujemnym
mins[0]=-112.0//oś x
mins[1]=-113.0//oś y
mins[2]=-1.0//oś z (góra-dół)
//oraz najbardziej wysniętego w kierunku dodatnim
maxs[0]=115.0
maxs[1]=116.0
maxs[2]=117.0
entity_set_size(ent,mins,maxs)//ustawia w/w odległości-czyli po prostu rozmiar
new Float:origin[3]
entity_get_vector(id,EV_VEC_origin,origin)//tu pobieram położenie gracza, aby z grubsza wiedzieć gdzie to entity umieścić, jeśli mam własne dane co do położenia, 
//a nie interesuje nas położenie gracza, to przypisujemy dane do zmiennej origin[3]
origin[0]+=350.0//tu zmieniam położenie względem jednej z osi, żeby byt nie został stworzony na mnie (graczu) tylko w pobliżu
entity_set_origin(ent,origin)//ustawiam położenie bytu. Należy uważać, aby byt nie został stworzony w mapie, tzn jego część nie była schowana w podłodze, bo byt zacznie nam opadać powoli w dół aż zniknie całkowicie z pola widzenia. Dobrze ustawiony origin poskutkuje pojawieniem się nieruchomego bytu, ew pojawieniem się bytu i opadnięciem na ziemie.


entity_set_int(ent,EV_INT_solid,SOLID_BBOX)//ustawiamy dotykalność bytu (bez ustawionego movetype ( MOVETYPE_NONE ) nie przynosi efektu)
entity_set_int(ent,EV_INT_movetype,MOVETYPE_TOSS)//ustawiamy sposób poruszania się bytu, wybrany tutaj to po prostu kolidowanie z entitami, grawitacja
 
ważne, model musimy precachować:
public plugin_precache()
{
precache_model("models/wall/wall.mdl") 
}
Możliwe SOLIDy:
#define SOLID_NOT 0 /* Brak interakcji z obiektami */
#define SOLID_TRIGGER 1 /* Tworzy dotyk (alarmując funkcje), ale nie blokuje (można przez niego przejść) */
#define SOLID_BBOX 2 /* Tworzy dotyk (alarmując funkcje), blokuje */
#define SOLID_SLIDEBOX 3 /* Tworzy dotyk, ale nie na ziemi(nie czaje o co chodzi:P-nie testowałem) */
#define SOLID_BSP 4 /* Część mapy, tworzy dotyk (alarmując funkcje), blokuje */
Możliwe movetype'y:
#define MOVETYPE_NONE 0 /* nie porusza się */
#define MOVETYPE_ANGLENOCLIP 1 /* nie mam pojęcia - crashuje serwer jak ustawię */
#define MOVETYPE_ANGLECLIP 2 /* nie porusza się */
#define MOVETYPE_WALK 3 /* Tylko gracz tego używa - chodzenie po ziemi - ustawisz innemu entity=crash */
#define MOVETYPE_STEP 4 /* gravity, special edge handling -- monsters use this */
#define MOVETYPE_FLY 5 /* Koliduje z elementami mapy/entami, ale nie działa nań grawitacja */
#define MOVETYPE_TOSS 6 /* Koliduje z elementami mapy/entami, działa nań grawitacja */
#define MOVETYPE_PUSH 7 /* no clip to world, push and crush - nie testowałem, ale entity z solid_bsp mają ten movetype */
#define MOVETYPE_NOCLIP 8 /* Może posiadać prędkość tzn poruszać się, ale nie koliduje i nie działa nań grawitacja */
#define MOVETYPE_FLYMISSILE 9 /* extra size to monsters */
#define MOVETYPE_BOUNCE 10 /* Tak jak TOSS, ale odbija się od wszystkiego */
#define MOVETYPE_BOUNCEMISSILE 11 /* Odbija się, ale nie działa nań grawitacja */
#define MOVETYPE_FOLLOW 12 /* Śledzi ruchy celu (EV_ENT_aiment ?) */
#define MOVETYPE_PUSHSTEP 13 /* BSP model that needs physics/world collisions (uses nearest hull for world collision) */
 
Na koniec przełożenie na fakemete, np:
entity_set_int(id,EV_ENT_owner,1)
set_pev(id,pev_owner,1)
to jest to samo w działaniu, albo
entity_get_int(id,EV_ENT_owner)
pev(id,pev_owner)
albo
new classname[32]
entity_get_string(id,EV_SZ_classname,classname,31)
pev(id,pev_classname,classname,31)
 
 
 

 

Teraz już wiecie jak stworzyć swoje entity. Postaram się uzupełniać w wolnych chwilach, a także po waszych sugestiach i uwagach, na które bardzo liczę. Jak zbierzemy do kupy wiedzę paru osób to może powstać z tego na prawdę dobry poradnik.

  • +
  • -
  • 16


#83575 Wpływanie na obrażenia

Napisane przez R3X w 21.09.2009 18:31

Wpływanie na obrażenia
używając modułu hamsandwich

Aby mieć możliwość edycji obrażeń należy złapać zdarzenie Ham_TakeDamage z post=0

#include <amxmodx>
#include <amxmisc>
#include <hamsandwich>

#define PLUGIN "HamSandwich Damage"
#define VERSION "1.0"
#define AUTHOR "R3X"


public plugin_init() {
	register_plugin(PLUGIN, VERSION, AUTHOR)
	
	RegisterHam(Ham_TakeDamage, "player","fwTakeDamage",0);
}

event łapiemy w funkcji (ja nazwałem ją "fwTakeDamage"), której parametry są następujące
public fwTakeDamage(this, idinflictor, idattacker, Float:damage, damagebits){
	return HAM_IGNORED;
}

this - atakowany gracz
idinflictor - byt zadający obrażenia
idattacker - byt powodujący obrażenia
damage - wielkość obrażeń
damagebits - typ obrażeń

jeśli idattacker to gracz zazwyczaj idinflictor to również id atakującego, wyjątek stanowi granat: w tym przypadku idinflictor to indeks bytu granatu
w przeciwnym razie (!is_user_connected(idattacker)), idinflictor może być bytem typu trigger_hurt lub po prostu 0

damagebits przekazuje informacje o obrażeniach na podstawie składowych flag:
#define DMG_GENERIC                     0           // Generic damage was done
#define DMG_CRUSH                       (1<<0)      // Crushed by falling or moving object
#define DMG_BULLET                      (1<<1)      // Shot
#define DMG_SLASH                       (1<<2)      // Cut, clawed, stabbed
#define DMG_BURN                        (1<<3)      // Heat burned
#define DMG_FREEZE                      (1<<4)      // Frozen
#define DMG_FALL                        (1<<5)      // Fell too far
#define DMG_BLAST                       (1<<6)      // Explosive blast damage
#define DMG_CLUB                        (1<<7)      // Crowbar, punch, headbutt
#define DMG_SHOCK                       (1<<8)      // Electric shock
#define DMG_SONIC                       (1<<9)      // Sound pulse shockwave
#define DMG_ENERGYBEAM                  (1<<10)     // Laser or other high energy beam 
#define DMG_NEVERGIB                    (1<<12)     // With this bit OR'd in, no damage type will be able to gib victims upon death
#define DMG_ALWAYSGIB                   (1<<13)     // With this bit OR'd in, any damage type can be made to gib victims upon death.
#define DMG_DROWN                       (1<<14)     // Drowning
#define DMG_PARALYZE                    (1<<15)     // Slows affected creature down
#define DMG_NERVEGAS                    (1<<16)     // Nerve toxins, very bad
#define DMG_POISON                      (1<<17)     // Blood poisioning
#define DMG_RADIATION                   (1<<18)     // Radiation exposure
#define DMG_DROWNRECOVER                (1<<19)     // Drowning recovery
#define DMG_ACID                        (1<<20)     // Toxic chemicals or acid burns
#define DMG_SLOWBURN                    (1<<21)     // In an oven
#define DMG_SLOWFREEZE                  (1<<22)     // In a subzero freezer
#define DMG_MORTAR                      (1<<23)     // Hit by air raid (done to distinguish grenade from mortar)
#define DMG_TIMEBASED                   (~(0x3fff)) // Mask for time-based damage
np.
if(damagebits&DMG_BLAST){ //gracz prawdopodobnie zginął od wybuchu bomby
}

Zarejestrowanie Ham_TakeDamage z post = 0 daje możliwość ingerencji w przebieg tego wydarzenia.

Możemy po prostu anulować obrażenia przez zwrócenie HAM_SUPERCEDE lub HAM_OVERRIDE
public fwTakeDamage(this, idinflictor, idattacker, Float:damage, damagebits){
	return HAM_SUPERCEDE;
}

albo zmienić dowolny parametr funkcji przy użyciu funkcji SetHamParam*, gdzie * to typ argumentu.

SetHamParamInteger - dla liczby całkowitej
SetHamParamFloat - dla liczby rzeczywistej
SetHamParamVector - dla wektora (Float:v[3])
SetHamParamEntity - dla bytu (np. id gracza)
SetHamParamString - tekst

Po operacjach zwracamy HAM_HANDLED, aby zatwierdzić zmiany.

Przykład:
public fwTakeDamage(this, idinflictor, idattacker, Float:damage, damagebits){
	SetHamParamFloat(4, 100.0);
	return HAM_HANDLED;
}
Zmieniamy czwarty argument (damage) typu Float: na 100.0, co spowoduje, że praktycznie każde uderzenie czy upadek skończy się śmiercią.

W połączeniu z warunkami daje to nam całkowitą kontrolę nad obrażeniami.


Uwaga:
Broń z jakiej zadane zostały obrażenia (przy podłączony idattacker) to:
- w przypadku idinflictor==idattacker
new bron = get_user_weapon(idattacker);
- w przypadku idinflictor!=idattacker
new bron = CSW_HEGRENADE;

  • +
  • -
  • 25


#675787 PAWN Pre-Processor Część 1

Napisane przez DarkGL w 19.12.2014 12:11

Jest to pierwsza część cyklu tutoriali na temat preprocesora autorstwa Y_Less przetłumaczona na język polski
Źródło http://forum.sa-mp.c...5175#post785175

 

http://darkgl.amxx.p...cessor-czesc-1/

Sam tutorial dotyczy preprocesora obecnego w wersji pawn'a dla sa:mp jednak wiele rzeczy jest wspólnych , niektóre niestety działają tylko w sa:mp ale postanowiłem zostawić ich opis jaką ciekawostkę. Wszelkie uwagi co do tlumaczenia mile widziane. Podczas tłumaczenia dodawałem / zmieniałem rzeczy od siebie.
Za wszystkie błędy lub nieścisłości przepraszam czasami ciężko było przenieść znaczenie zdań z języka angielskiego na polski.

Zawartość

Część 1 - Obejmuje wprowadzenie do preprocesora oraz kilka ważnych rzeczy przydatnych podczas pisania makr.
Część 2 - Wyjaśnienie dokładnie czego szuka kompilator oraz typowych zastosowań makr.
Część 3 - Opis innych dostępnych dyrektyw (oprócz"#define") oraz spojrzenie na definicje bez wartości podmiany.
Część 4 - Używanie stringów w preprocesorze.
Część 5 - Alternatywy dla preprocesora, wiele symboli i rekurencja.
Część 6 - Problemy z makrami oraz spacje.

Podstawowa podmiana

Na początek proste makra i jeszcze prostsze definicje. Idealny początek do wprowadzenia jak działa preprocesor.

Definicje

Definicja poniżej składa się tylko z tekstu do podmiany i tekstu na który podmieniasz.
 

#define MAX_PLAYERS                     500

Klasyka - definicja określa ilośc graczy na Twoim serwerze.Idealny przykład jak działają definicje. Preprocesor jak sama nazwa wskazuje wykonuje się przed głownym procesem ( kompilatorem ). Kompilator bierze napisany kod i konwertuje go do pliku AMXX, preprocesor generuje napisany kod. Przykład:
 

printf("%d", MAX_PLAYERS);

Preprocesor podczas wykonywania przekonwertuje ten kod do:
 

printf("%d", 500);

Jest to kod który zostanie przekazany głownemu kompilatorowi i to ten kod zostanie przekonwertowany do pliku wynikowego ( AMXX ). Jest to po prostu podmiana tekstu. Wszystkie makra są w tej samej formie:
 

#define <szukany text><spacja/spacje><text podmiany>

Warto zauważyć że spacja jest ważna - pierwsza spacja oznacza koniec stringu który będzie szukany, wszystko za spacją jest traktowane jako string na który preprocesor będzie podmieniał znalezione stringi! W przykładzie wyżej szukany string to "MAX_PLAYERS" a string podmiany to "500".

Makra

Makro to coś w rodzaju funkcji - posiada parametry. Nazwy parametrów zaczynają się od "%0" do "%9" ( "%0" , "%1" , "%2" itp. itd. ) - nie można im nadać własnych nazw. Funkcja zwracająca maksymalną ilośc graczy pomnożoną przez liczbę wyglądała by tak:
 

MaxPlayersTimesNumber(number)
{
    return MAX_PLAYERS * number;
    // Pamiętaj że "MAX_PLAYERS" jest definicją więc kompilator skompiluje te wyrażenie jako:
    //  return (500) * number;
}

Makro robiące to samo wyglądało by tak:
 

#define MAX_PLAYERS_TIMES_NUMBER(%0)    MAX_PLAYERS * %0

Tym razem szukanym stringiem jest "MAX_PLAYERS_TIMES_NUMBER(%0)" a stringiem podmiany jest "MAX_PLAYERS * %0". "%0" to specjalne wyrażenie - nie oznacza szukaj "%0", oznacza szukaj czegokolwiek pomiędzy dwoma nawiasami . "%0" otrzymują tą samą wartość która była pomiędzy nawiasami w stringu który był podmieniany.
Przykład:
 

#define MAX_PLAYERS                     500
#define MAX_PLAYERS_TIMES_NUMBER(%0)    MAX_PLAYERS * %0

printf("%d", MAX_PLAYERS_TIMES_NUMBER(7));

Po wykonaniu preprocesora ( podamiana "%0" na "7" ) otrzymujemy:
 

#define MAX_PLAYERS                     500

printf("%d", MAX_PLAYERS * 7);

"MAX_PLAYERS" jest dodatkowo makrem więc otrzymujemy:
 

printf("%d", 500 * 7);

Warto zauwayżyć że kompilator jest "inteligentny" - jeśli widzi takie wyrażenie jak to tutaj gdzie nie mamy żadnych zmiennych , wyliczy sobie wartość , więc kod który finalnie dostajemy do kompilacji wygląda tak ( kompilator nie umie formatować stringów ):
 

printf("%d", 3500);

Można by to też zrobić tak:
 

#define MAX_PLAYERS                     500
#define MAX_PLAYERS_TIMES_NUMBER(%0)    MAX_PLAYERS * %0

new value = 7;
printf("%d", MAX_PLAYERS_TIMES_NUMBER(value));

Po wykonaniu preprocesora ( podamiana "%0" na "value" ) otrzymujemy:
 

#define MAX_PLAYERS                     500

new value = 7;
printf("%d", MAX_PLAYERS * value);

"MAX_PLAYERS" jest makrem więc otrzymujemy:
 

new value = 7;
printf("%d", 500 * value);

Ponieważ te wyrażenie używa zmiennej kompilator nie umie go wyliczyć. Więc jest to finalny kod który zostaje skompilowany.

Dlaczego ?

Więc dlaczego używać makr zamiast funkcji ( lub dlaczego używać funkcji zamiast makr )? Makra podmieniają tekst - więc wszedzie gdzie umieścisz makro tam zostanie dodany twój tekst. Jeśli masz makro w kodzie użyte 100 razy , kod zostanie wygenerowany 100 razy. Z drugiej strony jeśli masz 100 wywołań funkcji w swoim kodzie , kod zostanie dodany tylko raz mimo 100 wywołań. Funkcje są prawdopodbnie bardziej użyteczne jeśli masz dużo kodu - duże bloki kodu występujące 100 razy utworzą bardzo duży plik AMXX ! Makra są raczej używane przy małej ilości kodu - wywołanie funkcji zajmuje pamieć i czas procesora więc jeśli masz mały blok kodu nie opłaca się wywoływać funkcji , ale to nie jest zasadą ! Jeśli użyłbyś funkcji zamiast makra powyżej , skompilowany kod wygląał by tak:
 

MaxPlayersTimesNumber(number)
{
    return (500) * number;
}

Przykład 1:
 

printf("%d", MaxPlayersTimesNumber(7));

Przykład 2:
 

new value = 7;
printf("%d", MaxPlayersTimesNumber(value));

W obu przypadkach kompilator nie wie jak zoptymalizować kod.

Konwencja

Jedną z rzeczy które mogłeś zauważyć czytając ten poradnik jest nazewnictwo ,funkcja została nazwana "MaxPlayersTimesNumber" to samo makro zostało nazwane "MAX_PLAYERS_TIMES_NUMBER".
To tylko konwencja - funkcje w tym poradnik będą miały nazwy pisane małymi literami oprócz pierwszych znaków wyrazów , makra za to będą miały nazwy pisane wielkimi literami z wyrazami oddzielonymi "_", jest to po to,aby łatwo można było zorientować się czego teraz używamy bez sprawdzania definicji.

Kolejna konwencja to ustawianie stringu podmiany na pozycji 40 ( kiedy to możliwe ) - jest to po to, aby ułatwić czytanie dużej ilości makr np.
 

#define DEFINITION_1                    1
#define MY_DEF                          2
#define SOME_OTHER_LONG_NAME_DEFINITION 3
#define A_MACRO(%0)                     3 * %0

Zamiast:
 

#define DEFINITION_1 1
#define MY_DEF 2
#define SOME_OTHER_LONG_NAME_DEFINITION 3
#define A_MACRO(%0) 3 * %0

Żadna z tych konwencji nie jest zasadą, więc masz wolną ręke przy używaniu ich, jeśli chcesz możesz je zignorować. Ale zachęcał bym Cie to posiadania naprawdę dobrych powodów zanim je zignorujesz.

Składnia / Semantyka

Szybkie przypomnienie. "Składnia" jest to wygląd kodu, "Semantyka" oznacza to co ten kod robi . Składnia pętli for to: "for (; ; ) {}", "semantyka" pętli for to: wykonaj się ileś razy na podstawie przekazanych parametrów. Wążna sprawą w następnej sekcji jest składnia i semantyka funkcji "printf". Składnia to: "printf(string[], ...);" - czyli string a następnie dowolna ilość parametrów, zawartość stringu nie wpływa na składnie - "printf("%d", 6, 7);" spełnia zasady składnie, ale 7 nie zostanie wyświetlona ponieważ string określa semantykę funkcji ( co ona naprawdę robi ).Kod się skompiluje ale nie będzie działał poprawnie , i jest to bardzo ważna różnica.

Parametry

Makro może posiadać kilka parametrów:
 

#define MULTIPLY_TWO_NUMBERS(%0,%1)     %0 * %1

W rzeczywistości makro może mieć nawet do 10 parametrów:
 

#define MULTIPLY_NUMBERS(%0,%1,%2,%3,%4,%5,%6,%7,%8,%9) %0 * %1 * %2 * %3 * %4 * %5 * %6 * %7 * %8 * %9

Niektórzy lubią stawiać spacje po przecinku w liście parametrów np.:
 

#define MULTIPLY_TWO_NUMBERS(%0, %1)     %0 * %1

Czegoś takiego nie można robić w makrach - tak jak było wcześniej powiedziane spacja oznacza koniec stringu do podmiany , więc preprocesor będzie szukał "MULTIPLY_TWO_NUMBERS(%0,", a nie "MULTIPLY_TWO_NUMBERS(%0, %1)" i podmieni to na "%1) %0 * %1".

Teraz kiedy wiesz już czym jest makro i czym są jego parametry możemy skupić się na różnicach parametrów makr i parametrów funkcji.

Po pierwsze - parametry makra i funkcji nie są tym samym i nie powinny być traktowane w ten sam sposób. Parametry funkcji są oddzielane przecinkami, parametry makr są oddzielone czymkolwiek chcesz.

Ten kod nie jest poprawny, podczas wywołania funkcji jest przekazywane za dużo parametrów:
 

MyFunc(a)
{
    return a;
}

main()
{
    printf("%d", MyFunc(1, 2));
}

Ten kod jest poprawny:
 

#define MY_FUNC(%0)                     %0

main()
{
    printf("%d", MY_FUNC(1, 2));
}

W przykładzie wyżej makro "MY_FUNC" szuka czegoś pomiędzy dwoma nawiasami poprzedzone "MY_FUNC". W tym przykładzie zawartością pomiędzy nawiasami jest "1, 2". Wyrażenie zawiera przecinek ale dla makra nie robi to różnicy. Kod po wykonynaniu preprocesora dla tego makra będzie wyglądał tak:
 

main()
{
    printf("%d", 1, 2);
}

Wygenerowany kod jest w pełni poprawny( oczywiście 2 nie zostanie wyświetlone ).

Jeśli parametry nie są odzielane przecinkami , jak móc używać więcej niż jednego ? Parametry są odzielane czymkolwiek chcesz żeby były odzielane np.:
 

#define MULTIPLY_TWO_NUMBERS(%0,%1)     %0 * %1

Kod wyżej będzie szukał "MULTIPLY_TWO_NUMBERS(" następnie wszystkiego do przecinka , przecinka , wszystkiego do zamykającego nawiasu.
 

printf("%d", MULTIPLY_TWO_NUMBERS(6, 7));

Kod wyżej zostanie podmieniony przez makro ( spacja tutaj jest dopuszczalna , nie jest dopuszczalna w deklaracji ) i otrzymamy taki kod:
 

printf("%d", 6 * 7);

Jednak przecinek nie jest zamykajacym nawiasem więc to też jest prawidłowe:
 

printf("%d", MULTIPLY_TWO_NUMBERS(6, 7, 8));

W tym przypadku parametr "%0" przyjmuje wartość 6 a parametr "%1" przyjmuje wartość "7,8" więc po wygenerowaniu kodu otrzymamy:
 

printf("%d", 6 * 7, 8);

Nawiasy

Skoro parametry są tak elastyczne jak możemy kontrolować to co generuje nam preprocesor ? Wszystkie makra wyżej były bardzo złe , nie używały nawiasów.

Przykład:






// Without brackets (first).
#define MULTIPLY_TWO_A(%0,%1)           %0 * %1

// With brackets (second).
#define MULTIPLY_TWO_B(%0,%1)           ((%0) * (%1))

main()
{
    // Two with first.
    printf("%d", MULTIPLY_TWO_A(6, 7));
    
    // Two with second.
    printf("%d", MULTIPLY_TWO_B(6, 7));
    
    // Three with first.
    printf("%d", MULTIPLY_TWO_A(6, 7, 8));
    
    // Three with second.
    printf("%d", MULTIPLY_TWO_B(6, 7, 8));
}

Po wygenerowaniu otrzymamy taki kod:
 

main()
{
    // VALID
    printf("%d", 6 * 7);
    
    // VALID
    printf("%d", ((6) * (7)));
    
    // VALID
    printf("%d", 6 * 7, 8));
    
    // INVALID!
    printf("%d", ((6) * (7, 8)));
}

Finalny kod pokazuje ważna różnice , po dodaniu nawiasów wygenerowany kod jest błędny ( składnia jest błędna ). Próbujemy mnożyć "6" przez "7,8" - co jest błędne więc użytkownik dostanie błąd przy kompilacji.

Inne użycie nawiasów to ustalanie priorytetów operatorów. Dzięki nawiasom możemy ustalać kolejność wykonywania operatorów np. "4 + 5 * 6" otrzymujemy "34", nie "54". Ponieważ * ma wyższy priorytet niż + więc "4 + 5 * 6" zostaje wykonane do "4 + 30" a potem "34". Jeśli parametry były by wykonywane po kolei "4 + 5 * 6" staje się "9 * 6" a następnie "54".

Przeanalizujmy taki kod
 

#define ADD_TWO(%0,%1)                  %0 + %1

main()
{
    printf("%d", ADD_TWO(3, 3) * 7);
}

3 + 3 to 6 , 6 * 7 to 42 prawda? Nie! Zobaczmy wygenerowany kod.
 

main()
{
    printf("%d", 3 + 3 * 7);
}

Wiemy co się stanie, mnożenie zostanie wykonane przed dodawaniem więc otrzymamy 24. Całość możemy naprawić dodając nawiasy:
 

#define ADD_TWO(%0,%1)                  (%0 + %1)

Kolejny przykład
 

#define MUL_TWO(%0,%1)                  (%0 * %1)

main()
{
    printf("%d", MUL_TWO(3 + 3, 7));
}

Dodaliśmy nawiasy więc wszystko powinno być ok ? Błąd ! Zobaczmy co wygenerował preprocesor:
 

main()
{
    printf("%d", (3 + 3 * 7));
}

Obliczenia są w nawiasach, ale znowu mnożenie zostanie wykonane przed dodawaniem. Powinniśmy dodać jeszcze jeden poziom nawiasów dzięki czemu wszystkie operacje będa wykonywane poprawnie:
 

#define MUL_TWO(%0,%1)                  ((%0) * (%1))

PAMIĘTAJ: Owijaj makro i parametry makra w nawiasy. Istnieją sytuację kiedy nie trzeba tego robić ale o nich opowiem później.

Makra kilku linijkowe

Makro może mieć kilka linii dzięki użyciu "\". Zasada jest prosta jeśli na końcu linii znajduje się znak \ makro jest kontynuowane w kolejnej linii. Makro nie może być kontynuowane w parametrach i nazwie z tych samych powodów z których nie możemy używać spacji. Uwaga: W tym poradniku znak kontynuacji jest umieszczany na pozycji 80:
 

#define MUL_TWO(%0,%1)                                                          \
    ((%0) * (%1))
#define MUL_TWO(%0,%1)                                                          \
    (                                                                           \
        (%0)                                                                    \
        *                                                                       \
        (%1)                                                                    \
    )
#define MUL_TWO(%0,%1)                                                          \
    (                                                                           \
        (                                                                       \
            %0                                                                  \
        )                                                                       \
        *                                                                       \
        (                                                                       \
            %1                                                                  \
        )                                                                       \
    )

Ostatnia linii makra nie posiada operatora konytnuacji.

Pułapka

Jest jeden bardzo ważny problem podczas używania makr zamiast funkcji:

Wersja funkcyjna:
 

PrintSquare(var)
{
    printf("%d", var * var);
}

main()
{
    new
        var = 2;
    PrintSquare(var++);
    printf("%d", var);
}

Wynik:
4
3

Wersja z makrami:
 

#define PRINT_SQUARE(%0)                printf("%d", (%0) * (%0))

main()
{
    new
        var = 2;
    PRINT_SQUARE(var++);
    printf("%d", var);
}

Możemy otrzymać:
4
4

Lub:
6
4

Ponieważ parametry przekazane do makra są inkrementowane , więc inkrementacja jest dodawana przy generowaniu kodu:
 

main()
{
    new
        var = 2;
    printf("%d", (var++) * (var++));
    printf("%d", var);
}

W takim przypadku w drugim printf zmienna var będzie zinkrementowana dwa razy - co jest błędne i nie wydarzy sie podczas użycia funkcji.

Kolejność wykonania dla operatora inkrementowania może zostać wykonana na dwa sposoby:
 

temp1 = var;
temp2 = var;
var   = var + 1;
var   = var + 1;
printf("%d", temp1 * temp2);

Lub:
 

temp1 = var;
var   = var + 1;
temp2 = var;
var   = var + 1;
printf("%d", temp1 * temp2);

Oba są technicznie prawidłowe - w obu przypadkach inkrementowanie jest wykonane po użyciu zmiennej , problemem jest tylko który sposób wybierze kompilator. Dlatego wynik może być "4" lub "6".

Bądź bardzo uważny podczas używania makr z parametrami które modyfikują zmienne - dlatego nazwy makr są pisane bardzo często z dużych liter aby użytkownik wiedział że jest to makro i był bardzo uważny podczas jego używania.


  • +
  • -
  • 12


#669674 [ROZWIĄZANE] Rejestracja eventów takich jak: przeładowanie, wyrzucenie broni...

Napisane przez G[o]Q w 10.11.2014 15:55

U mnie takie cos dzialalo ok

 

public Fwd_CmdStart(id, uc_handle, seed){
    if(!is_user_alive(id)) return;
    
    new buttons=get_uc(uc_handle,UC_Buttons);
    
    new old_buttons=pev(id,pev_oldbuttons);
    
    if(buttons & IN_RELOAD){
        new ret;
        if(!(old_buttons & IN_RELOAD))
            ExecuteForward(fwd_r_click,ret,id);
        else ExecuteForward(fwd_r_press,ret,id);
    }
}

 

a do wykrywania IN_USE używałem Emit_Sounda ale w cmdstart tez mozna


  • +
  • -
  • 1


#669604 [ROZWIĄZANE] Rejestracja eventów takich jak: przeładowanie, wyrzucenie broni...

Napisane przez GwynBleidD w 09.11.2014 21:19

1. Zamiast thinka możesz użyć FM_CmdStart lub Ham_ObjectCaps (przynajmniej dla IN_USE). FM_CmdStart będzie się wykonywać tylko, gdy gracz faktycznie "coś" robi. Ma jednak tą samą wadę, co think że coś może się wykonać wiele razy... Ale! To nie jest wcale taka wada, jeśli wiesz jak to działa :)

 

Otóż prócz sprawdzenia co gracz naciska poprzez get_user_button, możesz również sprawdzić co naciskaŁ przy poprzednim wywołaniu eventu, poprzez get_user_oldbutton lub po prostu cachując przyciski wewnątrz pluginu. W taki sposób: jeśli gracz nie naciskał poprzednio IN_USE, a teraz to robi, oznacza to ni mniej, ni więcej że zaczął naciskać. Więc w tym momencie możesz wywołać jakąś akcję. 


  • +
  • -
  • 2


#660301 Co obciąża CPU a co RAM

Napisane przez Rivit w 26.08.2014 14:36

Thinki
u siebie na serwerze mam tylko 2 pluginy z thinkiem.

A jakby rejestrowac to tak: jak gracz ma klase to RegisterHamFromEntity i to by rejestrowalo think dla jednego gracza, a nie dla wszystkich.
  • +
  • -
  • 1


#566591 witam ma problem z stwozenie modela

Napisane przez d0naciak w 23.08.2013 21:50

Coś o modelach

http://mrl.nyu.edu/~...22/modeling.pdf


  • +
  • -
  • 1


#502770 Dziwne error logi

Napisane przez MarWit w 17.01.2013 22:16

Spróbuj:


UstawPerk(id, 0, 0, 0);
obroty[id] = 0;

->

obroty[id] = 0;
UstawPerk(id, 0, 0, 0);


Linie 991 i 992
  • +
  • -
  • 1


#480752 [Klasa] & [Perk] Mini Gunner v1.0 !

Napisane przez DEADP00L w 19.11.2012 16:03

Pobrałem - jestem zadowolony. Przerobiłem i dodałem parę bajerów (podczerwień, rakiety itp). Ale jest problem. Mam 2 kompy, na 1 z nich Wszystko działa poprawnie, na drugim jest jeden problem. Gdy wypadają łuski niektóre normalnie a połowa z nich lewituje w powietrzu i kręci się w różne strony. Powoduje to straszny spadek fps. Czym to jest spowodowane?


Spróbuj zwiększyć odświeżanie w tej linijce:

z

entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.01)

na

entity_set_float(ent, EV_FL_nextthink, get_gametime() + 2.00)

## Musisz to zmienić w dwóch publicach: make_shell(id) oraz make_shell2(id)



Nie gwarantuję, że to pomoże ale widocznie drugiego kompa masz słabszego i po prostu za dużo naraz łusek wylatuje :)

Za tworzenie łusek odpowiadają te funkcje:

public make_shell(id) oraz public make_shell2(id)
  • +
  • -
  • 2


#460995 [ROZWIĄZANE] client_putinserver(id) - nie ma id?

Napisane przez GT Team w 24.09.2012 10:05

nie pisze glupot!

Daj set taska po tym tak gdzieś 10 s. Albo. Po odrodzeniu i tylko raz pokaże ta wiadomosc