Pular para o conteúdo principal

Palavras-chave: inicializadores

const

new const
MY_CONSTANT[] = {1, 2, 3};

const não é muito usado, mas serve para declarar variáveis que não podem ser alteradas em tempo de execução. Em funções, parâmetros de array marcados como const podem ser otimizados, e você pode criar algo parecido com um #define, só que baseado em arrays. Como const é um modificador, ele deve acompanhar new ou outro declarador de variável. Se tentar modificar uma variável constante, o compilador reclamará.

enum

Enums são úteis para agrupar dados relacionados, substituir longas listas de #defines e criar novas tags. Também facilitam o controle de índices de arrays.

Definição mais comum:

enum E_MY_ARRAY
{
E_MY_ARRAY_MONEY,
E_MY_ARRAY_GUN
}

new
gPlayerData[MAX_PLAYERS][E_MY_ARRAY];

public OnPlayerConnect(playerid)
{
gPlayerData[playerid][E_MY_ARRAY_MONEY] = 0;
gPlayerData[playerid][E_MY_ARRAY_GUN] = 5;
}

Isso cria dois slots por jogador. Sem enum, ficaria:

new
gPlayerData[MAX_PLAYERS][2];

public OnPlayerConnect(playerid)
{
gPlayerData[playerid][0] = 0;
gPlayerData[playerid][1] = 5;
}

Funciona, mas é menos legível. Se quiser inserir um slot entre 0 e 1, teria de renumerar tudo. Com enum basta adicionar o novo campo:

enum E_MY_ARRAY
{
E_MY_ARRAY_MONEY,
E_MY_ARRAY_AMMO,
E_MY_ARRAY_GUN
}

Ao recompilar, o compilador ajusta todos os índices.

A forma completa de um enum é:

enum NAME (modificador)
{
NAME_ENTRY_1 = valor,
...
}

Se você não definir um modificador, o padrão é += 1. Ou seja, cada item vale o item anterior + 1. Exemplo:

enum E_EXAMPLE
{
E_EXAMPLE_0,
E_EXAMPLE_1,
E_EXAMPLE_2
}

Aqui temos 0, 1, 2 e o valor do enum (E_EXAMPLE) é 3. Mudando o modificador para += 5 os valores passam a ser 0, 5, 10 e 15. Declarar um array com gEnumArray[E_EXAMPLE] reservá 15 células, mas os índices simbólicos atingem apenas 0, 5 e 10.

Também é possível usar outro modificador, como *= 2. Nesse caso, se não definir o primeiro valor manualmente, todos continuam 0. Para corrigir, basta atribuir um valor inicial:

enum E_EXAMPLE (*= 2)
{
E_EXAMPLE_0 = 1,
E_EXAMPLE_1,
E_EXAMPLE_2
}

Resultado: 1, 2, 4 e 8. Você pode definir quantos valores quiser:

enum E_EXAMPLE (*= 2)
{
E_EXAMPLE_0,
E_EXAMPLE_1 = 1,
E_EXAMPLE_2
} // 0, 1, 2, 4

Arrays também são suportados:

enum E_EXAMPLE
{
E_EXAMPLE_0[10],
E_EXAMPLE_1,
E_EXAMPLE_2
} // produz 0, 10, 11 e 12

Itens podem ter tags. No exemplo inicial:

enum E_MY_ARRAY
{
E_MY_ARRAY_MONEY,
E_MY_ARRAY_AMMO,
Float:E_MY_ARRAY_HEALTH,
E_MY_ARRAY_GUN
}

Assim evitamos tag mismatch ao armazenar floats.

Enums também podem servir como tags:

enum E_MY_TAG (<<= 1)
{
E_MY_TAG_NONE,
E_MY_TAG_VAL_1 = 1,
E_MY_TAG_VAL_2,
E_MY_TAG_VAL_3,
E_MY_TAG_VAL_4
}

new
E_MY_TAG:gMyTagVar = E_MY_TAG_VAL_2 | E_MY_TAG_VAL_3;

gMyTagVar terá valor 6 e tag personalizada. Atribuir um número puro gera aviso:

gMyTagVar = 7;          // warning
gMyTagVar = E_MY_TAG:7; // válido

Muito útil para flags ou dados combinados:

enum E_MY_TAG (<<= 1)
{
E_MY_TAG_NONE,
E_MY_TAG_MASK = 0xFF,
E_MY_TAG_VAL_1 = 0x100,
E_MY_TAG_VAL_2,
E_MY_TAG_VAL_3,
E_MY_TAG_VAL_4
}

new
E_MY_TAG:gMyTagVar = E_MY_TAG_VAL_2 | E_MY_TAG_VAL_3 | (E_MY_TAG:7 & E_MY_TAG_MASK);

Valor final: 0x0607 (1543).

Enums também podem substituir blocos de #define:

enum
{
TEAM_NONE,
TEAM_COP,
TEAM_ROBBER,
TEAM_CIV,
TEAM_CLERK,
TEAM_DRIVER
}

Os valores continuam 0–5 e o uso é idêntico. Você pode ainda transformá-los em bitmasks para permitir múltiplos times:

enum (<<= 1)
{
TEAM_NONE,
TEAM_COP = 1,
TEAM_ROBBER,
TEAM_CIV,
TEAM_CLERK,
TEAM_DRIVER,
TEAM_ADMIN
}

Operações básicas:

  • Adicionar: gPlayerTeam[playerid] |= TEAM_COP
  • Remover: gPlayerTeam[playerid] &= ~TEAM_COP
  • Verificar: if (gPlayerTeam[playerid] & TEAM_COP)

forward

Informa ao compilador que uma função será declarada depois. Obrigatório para todas as public, mas útil em outros casos, como funções que retornam tags.

forward MyPublicFunction(playerid, const string[]);

public MyPublicFunction(playerid, const string[])
{
}

Sem o forward, o compilador precisa “reprocessar” quando encontra uma função que retorna, por exemplo, Float: antes da definição. Outra alternativa é declarar a função antes do uso, mas o forward evita reorganizar o arquivo.

native

Nativas são funções implementadas fora do script (no servidor ou em plugins). Você só pode declará-las se já existir uma implementação; porém, pode criar “falsas” nativas para listar funções no painel do Pawno.

native printf(const format[], {Float,_}:...);

Para exibir uma função personalizada na lista sem declará-la de fato:

/*
native MyFunction(playerid);
*/

O Pawno não interpreta comentários e adiciona o símbolo na lista, enquanto o compilador ignora a linha.

Também é possível renomear ou encapsular nativas:

native my_print(const string[]) = print;

print(const string[])
{
my_print("Someone called print()");
my_print(string);
}

Agora toda chamada a print passa pelo wrapper.

new

Declara variáveis; por padrão começam em 0.

new
myVar = 5;

O escopo depende das chaves onde é declarado. Variáveis globais (new fora de funções) podem ser usadas em qualquer ponto após a declaração. Se o arquivo incluir outros, eles também terão acesso, a menos que você use static.

operator

Permite sobrecarregar operadores para tags personalizadas. Exemplo para armazenar números em big endian:

stock BigEndian:operator=(value)
{
return BigEndian:(((value >>> 24) & 0x000000FF) |
((value >>> 8) & 0x0000FF00) |
((value << 8) & 0x00FF0000) |
((value << 24) & 0xFF000000));
}

Operadores suportados: +, -, *, /, %, ++, --, ==, !=, <, >, <=, >=, ! e =.

Eles podem executar qualquer lógica, inclusive ignorar o comportamento padrão.

public

Transforma funções (ou variáveis) em símbolos acessíveis pelo servidor. Todas as callbacks do SA:MP são public. O nome textual da função é armazenado no AMX, o que permite chamá-la por CallLocalFunction, SetTimerEx, etc. Para isso é obrigatório declarar um forward.

forward MyPublicFunc();

main()
{
CallLocalFunction("MyPublicFunc", "");
}

public MyPublicFunc()
{
printf("Hello");
}

Funções públicas também podem ser chamadas normalmente dentro do script (MyPublicFunc();), o que é bem mais rápido do que invoques por string.

static

static aplicado globalmente cria variáveis visíveis apenas no arquivo (ou #section) onde foram declaradas. Diferente de new, a visibilidade não se estende a arquivos incluídos.

Localmente, static mantém o valor entre chamadas:

MyFunc()
{
static
counter = 0;
printf("%d", counter);
counter++;
}

A primeira chamada imprime 0, a segunda 1 e assim por diante. Com new, o valor seria reiniciado em cada execução. Também é possível declarar funções static para “privatizá-las”.

stock

stock serve para declarar funções ou variáveis opcionais, sem gerar avisos de “unused”. Se o símbolo for usado, o compilador o inclui; caso contrário, ele é descartado.

stock Func1()
{
printf("Hello");
}

stock Func2()
{
printf("Hi");
}

Útil para bibliotecas, onde você não sabe quais funções o usuário vai chamar. Diferentemente de #pragma unused, o código nem chega a ser emitido se não houver uso.