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
 

zryty - zdjęcie

zryty

Rejestracja: 15.07.2011
Aktualnie: Nieaktywny
Poza forum Ostatnio: 24.04.2019 18:06
-----

#284893 Piszemy pierwszy plugin

Napisane przez Nomaf w 18.08.2011 22:23

Nasz pierwszy plugin


Odpalamy Pawn Studio i wybieramy: File->New->SourcePawn Script. Naszym oczom ukaże się taki kod:
/* Plugin Template generated by Pawn Studio */

#include <sourcemod>

public Plugin:myinfo =
{
name = "New Plugin",
author = "Unknown",
description = "<- Description ->",
version = "1.0",
url = "<- URL ->"
}

public OnPluginStart()
{
// Add your own code here...
}


Na początku dołączamy moduły pluginu. W pierwszej funckji wypisujemy dane naszego pluginu, to chyba nie trzeba tłumaczyć, prawda? W kolejnej OnPluginStart() będziemy robić to, co będzie na potrzebne przy starcie serwera.

To był krótki wstęp. Najważniejszą rzeczą przy pisaniu jest świadomość tego co piszemy i tego co chcemy osiągnąć. W tym poradniku zrobimy pluginu, który będzie dawał x kasy na początek. Będę zamieszczał komentarze, aby ułatwić zrozumienie kodu.

1. Moduły i zmienne

Na początek musimy dodać moduł sdktools do naszego pluginu:
#include <sdktools>


Dodajemy także zmienne:
new g_iPlayer = -1

new Handle:iMoneyAmount


2. Funkcja OnPluginStart()

W skryptach SourceMod'a właściwości bytu należy pobierać z offsetów. Offset odpowiadający za ilość pieniędzy przypiszemy zmiennej g_iPlayer:
g_iPlayer = FindSendPropOffs("CCSPlayer", "m_iAccount")


Zdarzenia należy zhook'ować, przez HookEvent:
HookEvent("round_start", RoundStart, EventHookMode_Post)

(1 parametr to nazwa zdarzenia do hook'nięcia, 2 to nazwa funkcji, która będzie odpowiedzialna za zdarzenie, 3 ustala czy hook'nięcie ma nastąpić po (Post) czy przed zdarzeniem)

oraz przypisać iMoneyAmount wartość Var'a:
iMoneyAmount = CreateConVar("set_money_amount", "2500", "Ilosc dawanych pieniedzy", _, true, 0.0, true, 16000.0)

(1 parametr to nazwa Var'a, 2 to wartość, 3 - opis Var'a, 4 - flaga, 5 - czy ma mieć jakąś wartość minimalną?, 6 - jak tak to jaką?, 7 - czy ma mieć wartość maksymalną?, 8 - jak tak to jaką?)

3. Funkcja RoundStart(Handle:event, const String:name[], bool:dontBroadcast)

Tu zamieścimy kod, odpowiadający za hook'onięcie funkcji:
public RoundStart(Handle:event, const String:name[], bool:dontBroadcast)
{
for (new i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
{
if (g_iPlayer != -1)
{
new iCurrentMoney = GetEntData(i, g_iPlayer)
new iNewMoneyAmount = iCurrentMoney + GetConVarInt(iMoneyAmount)
if (iNewMoneyAmount > 16000)
iNewMoneyAmount = 16000

SetEntData(i, g_iPlayer, iNewMoneyAmount)
}
}
}
}


Czyli pobieramy id graczy, sprawdzamy czy są w grze, sprawdzamy czy offset jest prawidłowy i nadajemy wartość kasy.
GetEntData() - pobieramy wartość jakiegoś offsetu w naszym przypadku pieniędzy.
SetEntData() - ustawiamy wartość offsetowi

4. Ostateczny wygląd pluginu

/* Plugin Template generated by Pawn Studio */

#include <sourcemod>
#include <sdktools>

new g_iPlayer = -1

new Handle:iMoneyAmount

public Plugin:myinfo =
{
name = "Daj Kase",
author = "Nomaf",
description = "Ustawia wiecej kasy na poczatek rundy",
version = "1.0",
url = "http://amxx.pl/"
}

public OnPluginStart()
{
g_iPlayer = FindSendPropOffs("CCSPlayer", "m_iAccount")
HookEvent("round_start", RoundStart, EventHookMode_Post)
iMoneyAmount = CreateConVar("set_money_amount", "2500", "Ilosc dawanych pieniedzy", _, true, 0.0, true, 16000.0)
}

public RoundStart(Handle:event, const String:name[], bool:dontBroadcast)
{
for (new i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
{
if (g_iPlayer != -1)
{
new iCurrentMoney = GetEntData(i, g_iPlayer)
new iNewMoneyAmount = iCurrentMoney + GetConVarInt(iMoneyAmount)
if (iNewMoneyAmount > 16000)
iNewMoneyAmount = 16000

SetEntData(i, g_iPlayer, iNewMoneyAmount)
}
}
}
}




Tak, to już jest koniec. Myślę, że przynajmniej trochę zapoznaliście się z SourceMod'em. Od razu zaznaczam - nie używamy Amxx-Studio, żeby później nie było żadnych pytań i problemów. Koniec, kropka. :P

Poradnik stworzony przez: Nomaf dla AMXX.pl - Support AMX Mod X
Kopiowanie bez mojej zgody jest zakazane!


  • +
  • -
  • 10


#151730 Forwardy

Napisane przez R3X w 14.07.2010 17:05

Forwardy1. Opis
Działają odwrotnie do natywów. Funkcja natywna jest udostępniana innym pluginom. Forwardy to abstrakcyjne funkcje, które biblioteka próbuje wywołać. Wykonując forward dajemy sygnał, że nastąpiło jakieś zdarzenie i plugin może na nie zareagować. Można to lepiej zrozumieć biorąc pod uwagę forwardy samego AMXX, takie jak:
forward plugin_init();
forward client_putinserver(id);
stąd powinieneś się domyślić je rozpowszechniać.

W pliku .inc podajemy nagłówek
forward nazwa(Float:para, met, ry[]);
a w pliku .sma
public nazwa(Float:para, met, ry[]){
	//nasz kod
}
Dalej tę funkcji publiczną nazywam 'funkcją oczekującą'.

O tym jak zaprojektować czytaj dalej ->

2. Tworzenie
Po pierwsze musimy zarejestrować forward.

MultiForward
Gdy użyjemy poniższej, oczekująca funkcja będzie wywoływana w każdym pluginie, który z niej korzysta.
/**
* Rejestruje forward dostępny dla wszystkich pluginów
*
* @param name[] Nazwa publicznej funkcji
* @param stop_type Typ zatrzymania
* @param ... Parametry
* @return Uchwyt (liczba całkowita)
*/
CreateMultiForward ( const name[], stop_type, ... )


Jako name[] podajemy nazwę, Typ zatrzymania określa sposób realizacji:
#define ET_IGNORE		0	//ignoruj zwracaną wartość
#define ET_STOP			1	//zatrzymuje przy PLUGIN_HANDLED
#define ET_STOP2		2	//to samo,tylko nie zwraca największej wartości
#define ET_CONTINUE		3	//bez stopu, zwraca największą wartość
forward z typem ingore i continue będzie wywołany zawsze we wszystkich pluginach
opcje stopu (STOP i STOP2) zatrzymują rozsyłanie forwardu po otrzymaniu PLUGIN_HANDLED

Jeśli na tym skończymy to powstaje forward bez parametrów, jak:
//sma biblioteki
CreateMultiForward ( "nic_sie_nie_stalo", ET_IGNORE);

//w pliku .inc
forward nic_sie_nie_stalo();


Aby dodać jakieś argumenty trzeba rozwinąć rejestrowanie o dodatkowe wartości. Do określenia typu parametru służą stałe (nazwy są sugestywne)
#define FP_CELL			0
#define FP_FLOAT		1
#define FP_STRING		2
#define FP_ARRAY		4
Dodanie argumentu forwardu polega na dopisniu jego typu po przecinku
//sma biblioteki
CreateMultiForward ( "nic_sie_nie_stalo", ET_IGNORE, FP_CELL, FP_FLOAT);

//w pliku .inc
forward nic_sie_nie_stalo(id, Float:fTime);


MultiForwardEx
Jest to wersja kompatybilna z pluginami AMX. Nie będę się tym zajmował, szczegóły w pliku amxmodx.inc.

OneForward
Druga możliwość to forward przeznaczony wyłącznie dla jednego pluginu.
/**
* Rejestruje forward dostępny dla pojedynczego pluginu
*
* @param plugin_id Id pluginu
* @param name[] Nazwa publicznej funkcji
* @param ... Parametry
* @return uchwyt (liczba całkowita)
*/
CreateOneForward ( plugin_id, const name[], ... )

Nie ma tu opcji stopu, bo tylko jeden, konkretny plugin może wykonać forward i zwróci on równie konkretną wartość.

plugin_id to id zwrócone przez funkcję
find_plugin_byfile(const pname[]);
albo....

Ciekawym rozwiązaniem jest połączenie funkcji natywnej z forwardem w ten sposób. Wyobraźmy sobie rdzeń modu, który pozwala dodawać itemy w osobnych pluginach. Rdzeń ten udostępnia natywną funkcję
register_item( /*parametry*/)
, która zapisuje informacje i tworzy właśnie pojedynczy forward powiedzmy:
forward get_item(id)
ten osobny plugin będzie czekał na sygnał, gdy gracz zdobędzie ten przedmiot. Wygodne prawda? Zwłaszcza, że id pluginu to jeden z parametrów funkcji obsługującej natyw.

Parametry jak przy MultiForward↵

3. Wywołanie
Pora wysłać sygnał wywołania forwardu.
/**
* Wywołuje wskazany forward
*
* @param forward_handle Wartość zwrócona przez Create(One|Multi)Forward
* @param &ret Wartość zwrócona przez wywołane forwardy przekazana przez referencję
* @param ... Dokładnie tyle parametrów i takich typów jak podaliśmy przy tworzeniu
* Dane zostaną przekazane do funkcji oczekujących na forward
* @return 1 jeśli wywołano jakąś funkcję oczekującą, 0 jeśli nie
*/
ExecuteForward ( forward_handle, &ret, ... )


Przykład:
new gFW;
public plugin_init(){
	gFW = CreateMultiForward("jakies_zdarzenie", ET_CONTINUE, FP_FLOAT, FP_CELL, FP_STRING);
}
public plugin_cfg(){
	new iRet;
	ExecuteForward(gFW, iRet, 3.14, -5, "Pi");
}
Tak podane parametry są jak najbardziej w porządku. Inaczej ma się sprawa z type FP_ARRAY. Nie podajemy bezpośrednio tablicy, ale rezultat funkcji
/**
* Przygotowuje tablicę do przekazania do forwardu
*
* @param array[] Tablica wejściowa
* @param size Ilość komórek
* @param copyback Czy tablica zmieniona przez funkcje oczekującą ma wrócić
*/
PrepareArray(array[], size, copyback=0 )


Ostatni parametr jest dosyć ciekawy. Wynika z niego, że oprócz podania danych do forwardu możemy także z niego uzyskać. Ustawiając 0 mamy normalne przekazanie, podając 1 funkcje oczekujące będą pracować niejako na tej tablicy.
 
new gFW;
public plugin_init(){
	gFW = CreateMultiForward("jakies_zdarzenie", ET_CONTINUE, FP_CELL, FP_ARRAY);
}
public plugin_cfg(){
	new data[2];
	data[0] = 0;
	data[1] = 1;	

	new iRet;
	ExecuteForward(gFW, iRet, 0, PrepareArray(data, 2, 1));
	
	//data[0] == 0? możliwe, że już nie!
}
4. Przykłady
w załączniku xD
plik udostępniający i korzystający z forwardu w jednym pliku odzielone kreskami

ex1 - tylko wywołanie
ex2 - z analizą z wyniku (istotne co funkcje oczekujące zwracają)
ex3 - przekazywanie tablicy
ex4 - przekazywanie tablicy i powrót wyniku

Załączone pliki

  • Załączony plik  ex.rar   2,48 KB  338 Ilość pobrań

  • +
  • -
  • 18


#255463 Info po smierci

Napisane przez DarkGL w 03.06.2011 04:59

opis.png
Plugin pozwala po zginięciu dać info swojemu teamowi poprzez mikrofon lub czat

 

http://darkgl.pl/201...nfo-po-smierci/

ss.png
info.jpg

cvary.png



//czas na danie infa po śmierci standard to 5 sekund

info_smierci_czas 5

download.png
Załączony plik  inf_smierc.amxx   5,62 KB  495 Ilość pobrań

Załączony plik  inf_smierc.sma   1,77 KB  4804 Ilość pobrań
  inf_smierc.amxx


  • +
  • -
  • 57


#297366 Flagi

Napisane przez DarkGL w 18.09.2011 11:34

Flagi dostępne standardowo :
ADMIN_ALL - wszystkie
ADMIN_IMMUNITY - flaga "a"
ADMIN_RESERVATION - flaga "b"
ADMIN_KICK - flaga "c"
ADMIN_BAN - flaga "d"
ADMIN_SLAY - flaga "e"
ADMIN_MAP - flaga "f"
ADMIN_CVAR - flaga "g"
ADMIN_CFG - flaga "h"
ADMIN_CHAT - flaga "i" *
ADMIN_VOTE - flaga "j"
ADMIN_PASSWORD - flaga "k"
ADMIN_RCON - flaga "l"
ADMIN_LEVEL_A - flaga "m"
ADMIN_LEVEL_B - flaga "n"
ADMIN_LEVEL_C - flaga "o"
ADMIN_LEVEL_D - flaga "p"
ADMIN_LEVEL_E - flaga "q"
ADMIN_LEVEL_F - flaga "r"
ADMIN_LEVEL_G - flaga "s"
ADMIN_LEVEL_H - flaga "t"
ADMIN_MENU - flaga "u"
ADMIN_ADMIN - flaga "y"
ADMIN_USER - flaga "z"
Flagi dodatkowe :
ADMIN_FLAG_V - flaga "v"
ADMIN_FLAG_W - flaga "w"
ADMIN_FLAG_X - flaga "x"

żeby ich używać trzeba dodać do pluginu
#define ADMIN_FLAG_V (1<<21)
#define ADMIN_FLAG_W (1<<22)
#define ADMIN_FLAG_X (1<<23)

sprawdzenie czy gracz ma flage
if(get_user_flags(id) & ADMIN_LEVEL_A){
	//gracz ma flage m
}

sprawdzanie czy gracz nie ma flagi
if( !(get_user_flags(id) & ADMIN_LEVEL_A) ){
	//gracz nie ma flagi m
}

sprawdzanie czy gracz ma kilka flag
public has_flags(id,string[])
{
	new ret=1
	new byte
	
	new len = strlen(string)
	new p_flag = get_user_flags(id)
	
	for(new i=0;i<=len;i++)
	{
		if(string[i]>='a' && string[i]<='z') byte = (1<<(string[i]-'a'))
		else if(string[i]>='A' && string[i]<='Z') byte = (1<<(string[i]-'A'))
		else if(string[i]==',' && ret==1) return 1
		else if(string[i]==',') ret=1
		if(byte!=0 && !(p_flag & byte)) ret=0

		byte=0
	}
	
	return ret
}

Przyklady:
Jak ma dzialac na - a lub b lub c - to dajemy
has_flag(id,"a,b,c")
Jak ma dzialac tylko gdy user ma flage - a i b i c - to dajemy
has_flag(id,"abc")
Jak ma dzialac w przypadkach - a i b lub a i c lub b i c - to dajemy
has_flag(id,"ab,ac,bc")

Gracz musi mieć wszystkie 3 flagi
new flaga = (ADMIN_LEVEL_A | ADMIN_LEVEL_B | ADMIN_LEVEL_C)
if((get_user_flags(id) & flaga) == flaga) {
	// KOD
}
lub inaczej
new sprawdz = get_user_flags(id)
if(sprawdz & ADMIN_LEVEL_A && sprawdz & ADMIN_LEVEL_B && sprawdz & ADMIN_LEVEL_C) {
	// KOD
}

Inne przykłady:
if (get_user_flags(id) & DEFINICJA_FLAGI) {
	//osoba ma jakas tam flage
} else {
	//osoba nie ma jakies tam flagi
}

public client_authorized(id)
{
	if( get_user_flags(id) & ADMIN_BAN)
	client_print(0,print_chat,"Admin wchodzi na server")
}

  • +
  • -
  • 55


#118006 Troche o enum

Napisane przez destrojer w 11.03.2010 19:48

enum to jest sprytny sposob by zamiast korzystac z niewygodnych cyft, zmienic je w wiecej nam mowiace nazwy.

Enum to odpowiednik typu wyliczeniowego z np. takiego C++. To o czym napisałeś można odnieść do stałych ewentualnie makrodefinicji.

PAWN ma wiele wlasnych enum'ow ktore pozwalaja nam np. zamiast stosowac niewygodnych id broni 22, stosowac CSW_M4A1.


Ja optuje za tym, ze są to stałe, ew. makrodefinicji (mogę się mylić ponieważ nigdy na oczy nie widziałem zawartości bibliotek CS'a).

Mogłeś dodać, że enum'a można połączyć z tablicą co pozwoli na przyjemne jej indeksowanie.

enum  nazwa
{
    //nazwy_stalych
}
new tablica[nazwa];

Jest to możliwe ponieważ enum zwraca taki rozmiar co jego ostatnia wartość powiększona domyślnie o jeden (można to zmienić stosownym poleceniem). Można to sprawdzić za pomocą sizeof'a.
enum  nazwa
{
    //nazwy_stalych
}
new tablica[nazwa];
printf("%d", sizeof(tablica));

Co więcej możliwe jest użycie w enumie różnych tagów (umożliwia to przechowywanie wielu typów danych w jednej tablicy bez zbędnych ostrzeżeń ze strony kompilatora). To jest chyba jedyny przykład zastosowania "obiektowości" w PAWN.

Jest to oczywiste, ze dziesiec ma wartosc 10, dwadziescia ma wartosc 20 i czterdziesci ma wartosc 40. Ale na co trzeba zwrocic uwage, to trzydziesci ma wartosc 21!. enum nie dziala jak exel, ze sam wie o ile sie zmieniaja kolejne wartosci.

Ale można "pokazac" o ile ma zmieniać sie domniemana wartość stałych (domyślnie jest to += 1).
enum (+=10)
{
	z,
	x,
	c,
	v
};
printf("%d", c);

enum zamienia liczby na słowa ...
Nie możesz dać tam liczb.

enum nadaje wartość stałym (nie słowom, samo słowo to tylko odwołanie do komórki pamięci) poprzez domniemanie.

Można używać liczb w nazwach jednakże nie mogą one jednak być pierwszym znakiem w nazwie. To jest 123a jest niedozwolone, ale a123 już tak.
  • +
  • -
  • 7


#29755 Operacje bitowe

Napisane przez R3X w 23.12.2008 15:48

Operacje bitowe

Co to jest?
Działania na grupach bitów. Z powodu sposobu przedstawienia w pamięci sens ma dla liczb całkowitych (w tym znaków).
Dane są przechowywane w pamięci w systemie dwójkowym. Przykłady wprowadzające:

0010
1001
0110

Dalej będę się opierał tylko na 4 bitach. W pamięci komputera bajty składają się z 8. W pawnie wszystkie zmienne są 4 lub 8 bajtowe (32 lub 64 bity), zależnie od serwera.
Ilość dostępnych bitów określa definicja cellbits

1. Przesunięcia
Zmienia kolejność bitów przenosząc na miejsce sąsiednie.
a) w lewo
Operator: <<
1<<3
Bity liczby jeden (0001) przesuwa w lewo o trzy pozycje. W brakujące miejsca dopisywane są zera, bity wykraczające poza zakres są tracone.

0001 - początkowo
0010 - po przesunięciu o 1
0100 - po przesunięciu o 2
1000 - po przesunięciu o 3

Zatem 1<<3 = '1000' co po przeliczeniu na system dziesiętny daje liczbę 8.

Efekt: przesunięcie w lewo o n pozycji równoznaczne jest z mnożeniem przez (2 do potęgi n).

b)w prawo arytmetycznie
Operator: >>
7>>1
Bity liczby siedem (0111) przesuwa w prawo o jedną pozycje. W brakujące miejsca dopisywane bity o wartości najstarszego bitu pierwotnej liczby, bity wykraczające poza zakres są tracone.

0111 - początkowo
0011 - po przesunięciu o 1

Zatem 7>>1 = '0011' co po przeliczeniu na system dziesiętny daje liczbę 3.

Braki są uzupełniane bitem znaku.
15>>1

1111 - początkowo
1111 - po przesunięciu o 1



Efekt: przesunięcie w prawo o n pozycji równoznaczne jest z dzieleniem całkowitym przez (2 do potęgi n).

b)w prawo logicznie
Operator: >>>
15>>>1
Bity liczby piętnaście(1111) przesuwa w prawo o jedną pozycje. W brakujące miejsca dopisywane są zera, bity wykraczające poza zakres są tracone.

1111 - początkowo
0111 - po przesunięciu o 1

Zatem 15>>>1 = '0111' co po przeliczeniu na system dziesiętny daje liczbę 7.

Braki są uzupełniane zerami.


2. Operacje logiczne
Działania logiczne wykonywane między odpowiednimi bitami obu liczb.
a) koniunkcja inaczej iloczyn
Operator: &
8&2
Zapis dziesiętny na binarny:
1000 //8
0010 //2
Teraz bierzemy kolejne bity, wyznaczając ich iloczyn. Rozpiska:
1&1=1
1&0=0
0&1=0
0&0=0

1000
0010
Wykonujemy działanie 1&0 =0 zatem od lewej strony pierwszy bit wyniku=0
1000
0010
Wykonujemy działanie 0&0 = 0 zatem od lewej strony drugi bit wyniku=0
1000
0010
Wykonujemy działanie 0&1 = 0 zatem od lewej strony trzeci bit wyniku=0
1000
0010
I wykonujemy działanie 0&0 = 0 zatem od lewej strony czwarty bit wyniku=0

Zatem 8&2= '0000' co po przeliczeniu na system dziesiętny daje liczbę 0.

B) alternatywa inaczej suma
Operator: |
5|3
Zapis dziesiętny na binarny:
0101 //5
0011 //3
Teraz bierzemy kolejne bity, wyznaczając ich sumę. Rozpiska:
1|1=1
1|0=1
0|1=1
0|0=0

0101
0011
Wykonujemy działanie 0|0 = 0 zatem od lewej strony pierwszy bit wyniku=0
0101
0011
Wykonujemy działanie 1|0 = 1 zatem od lewej strony drugi bit wyniku=1
0101
0011
Wykonujemy działanie 0|1 = 1 zatem od lewej strony trzeci bit wyniku=1
0101
0011
I wykonujemy działanie 1&1 = 1 zatem od lewej strony czwarty bit wyniku=1

Zatem 5|3 = '0111' co po przeliczeniu na system dziesiętny daje liczbę 7.

c) różnica symetryczna inaczej XOR
Operator: ^
3^1
Zapis dziesiętny na binarny:
0011 //3
0001 //1
Teraz bierzemy kolejne bity, wyznaczając ich różnicę symetryczną. Rozpiska:
1^1=0
1^0=1
0^1=1
0^0=0

0011
0001
Wykonujemy działanie 0^0 = 0 zatem od lewej strony pierwszy bit wyniku=0
0011
0001
Wykonujemy działanie 0^0 = 0 zatem od lewej strony drugi bit wyniku=1
0011
0001
Wykonujemy działanie 1^0 = 1 zatem od lewej strony trzeci bit wyniku=1
0011
0001
I wykonujemy działanie 1^1 = 0 zatem od lewej strony czwarty bit wyniku=1

Zatem 3^1 = '0010' co po przeliczeniu na system dziesiętny daje liczbę 2.

d) negacja
Operator: ~
~1
Zapis dziesiętny na binarny:
0001 //1
Operacja jednoargumentowa - nie porównujemy bitów ze wzorcem, a jedynie zamieniamy każde 0 na 1 i odwrotnie. Stąd:
~0001
1110
Przykład ukazuję ideę - nie ma sensu przeliczać na system dziesiętny, bo w Pawnie nie spotkamy 4bitowego typu int.

3. Używanie:
Gdy na liczbę w pamięci komputera spojrzymy jak na zbiór wartości logicznych (1 lub 0) to w prosty sposób wykorzystać możemy operacje bitowe do przechowywania i sprawdzania zawartości składowej w całości.
Dokładniej chodzi o to, że każdej wartości 0 lub 1 przypisana jest jakaś funkcja (znaczenie). Mamy ciąg

0101

Możemy przeliczyć to na system dziesiętny, ale łatwiej pracować w takiej postaci. Każda liczba to informacja czy dana funkcja składowa jest aktywna (1) lub nie (0).

Przykład:

Do zaprezentowania możliwego użycia wybrałem prawa dostępu - chmod.
Określa jakie operacje wykonać można na danych pliku/katalogu. Składa się z 3 wartości. Każda z operacja ma swój odpowiednik literowy i liczbowy.

"wykonywanie" "x" 1
"zapis" "w" 2
"odczyt" "r" 4

Ograniczam zagadnienie do 1 grupy (zwykle określa się chmod dla 3 grup) pokażę jak zamienić zapis literowy na liczbowy i odwrotnie.

Pierwsze co musimy zrobić to zdecydować, które bity za co odpowiadają:
#define CHNONE 	001>>1	//000=0
#define CHEXEC 	001	//001=1
#define CHWRITE 001<<1	//010=2
#define CHREAD 	001<<2	//100=4
W tym wypadku kolejność ma znaczenie. Gdy będziemy tworzyć własne zestawy już nie będzie to takie ważne.

Napiszmy teraz funkcję, która przeliczy liczbę na skrót literowy. Pomijam sprawdzanie poprawności danych wejściowych, bo nie to jest tutaj istotne.
Funkcja strcat() dodaję podany ciąg na koniec wskazanego tekstu.
#include <amxmodx>
#include <amxmisc>

#define PLUGIN "Chmod"
#define VERSION "1.0"
#define AUTHOR "R3X"

#define CHNONE 	001>>1	//000=0
#define CHEXEC 	001	//001=1
#define CHWRITE 001<<1	//010=2
#define CHREAD 	001<<2	//100=4

public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR)
register_concmd("chmod_num2str","chmod_num2str",-1,"<chmod num>");
}
public chmod_num2str(id,level,cid)
{
	//sprawdzenie prawa dostępu komendy i liczby argumentów
	if (!cmd_access(id,level,cid,2))
		return PLUGIN_HANDLED; 
	//deklaracja zmiennych
	new chmod_num,tekst[2],chmod_str[4]="";
	//pobranie argumentu
	read_argv(1, tekst, 1); 
	//konwersja na liczbę
	chmod_num=str_to_num(tekst); 
	//sprawdzenie bitu odpowiadającego za odczyt
	if(chmod_num & CHREAD)
	{
		//dodaje 'r'
		strcat(chmod_str,"r",3);
	}
	//sprawdzenie bitu odpowiadającego za zapis
	if(chmod_num & CHWRITE)
	{
		//dodaje 'w'
		strcat(chmod_str,"w",3);
	}
	//sprawdzenie bitu odpowiadającego za wykonywanie
	if(chmod_num & CHEXEC)
	{
		//dodaje 'x'
		strcat(chmod_str,"x",3);
	}	
	console_print(id,"chmod[%d] -> ^"%s^"",chmod_num,chmod_str);
	return PLUGIN_HANDLED;
}

Dlaczego używamy tutaj iloczynu?
Wyzerują się wszystkie nieistotne w danym przypadku bity i zostanie do porównania ten, o który nam chodzi.
chmod_num2str 6
Przejdźmy fragment drogi chmod_num.

Przypisanie wartości z argumentu. Przyjmijmy, że będzie to 6 (110).
Pierwsze sprawdzenie:
chmod_num & CHREAD
(szukamy więc iloczynu takich liczb:)
110
100
Kolejno od lewej:

1&1=1

1&0=0

0&0=0

Ostatecznie wynik = 100 - nie jest równy 0 i przejdzie pozytywnie test logiczny if().

Spróbuj samodzielnie wykonać test logiczny nr 2 i 3.
  • +
  • -
  • 19


#34248 Dobry nawyk - średnik

Napisane przez FakeNick w 11.01.2009 11:36

Trudność : Bardzo łatwy

W tym jakże krótkim tutorialu postaram się wykształcić w Was dobry nawyk, jakim jest kończenie każdego wywołania jakieś funkcji średnikiem (;). Kompilator sam w sobie nie wymaga stawiania średników na końcu każdej linijki, ale jest to dobry nawyk, wymagany przy nauce innych języków programowania.

Jeżeli na początku kodu pluginu dodamy :

#pragma semicolon 1

kompilator pokaże nam, w którym miejscu powinien znajdować się średnik. Może to wydłużyć trochę czas pisania skryptu, ale przecież chcemy być "profesjonalistami" ;).
  • +
  • -
  • 9