>>Клацай<<

На правах рерайтинга

Вступление
Я никогда не использовал переключатели, за это мне стыдно. Они очень полезны. Павн с роду умеет использовать переключатели(так же известные как automata) которые позволяют подстраивать функции под нужные требования, которые могут менятся
На словах все трудно. Перейдем к делу

Пример №1
Что бы продемонстрировать суть переключателей, я написал очень простой мод(*да да, именно мод)
Используя стандартные способы, так что люди смогут понять что делает этот код:

Код:
#include <a_samp>

forward change();

enum
{
    end = 0,
    gmx
}

new
    gExitType;

main()
{
    gExitType = end;
    SetTimer("change", 10000, 0);
}

public OnGameModeExit()
{
    switch (gExitType)
    {
        case end:
            printf("This mode was ended by the server");
        case gmx:
            printf("This mode was ended by the timer");
    }
}

public change()
{
    gExitType = gmx;
    GameModeExit();
}
Код:
А теперь тоже самое но на переключателях:

#include <a_samp>

forward change();

main()
{
    state exitType:end;
    SetTimer("change", 10000, 0);
}

public OnGameModeExit() <exitType>
{
    printf("This mode was ended by the server");
}

public OnGameModeExit() <exitType>
{
    printf("This mode was ended by the timer");
}

public change()
{
    state exitType:gmx;
    GameModeExit();
}

Преимущества[

Какие же преимущества от этого способа? Ну, как вы можете заметить код МЕНЬШЕ; к тому же, я добавил enum к первой версии, чтобы коды выглядели как можно более похоже, но OnGameModeExit функция определенно меньше. Так же, оно намного полезнее - вам не нужны большие switch проверки в функции чтобы определить что же происходит.

Пример №2

Другой пример, в этот раз используем комманду /debug, чтобы быстро переключать вывод сообщении

Код:
#include <a_samp>

dprint(message[]) <printState>
{
    // Показываем сообщение
    print(message);
}

dprint(message[]) <printState>
{
    //Ничего не делаем
    #pragma unused message
}

forward output();

main()
{
    state printState:off;
    // Включаем таймер
    SetTimer("output", 1000, 1);
}

public OnPlayerCommandText(playerid, cmdtext[]) <printState>
{
    state (!strcmp(cmdtext, "/debug")) printState:off;
}

public OnPlayerCommandText(playerid, cmdtext[]) <printState>
{
    state (!strcmp(cmdtext, "/debug")) printState:on;
}

public output()
{
    static
        sCount = 0;
    if (++sCount == 5)
    {
        OnPlayerCommandText(0, "/debug");
        sCount = 0;
    }
    // Статично выводим сообщение дял примера
    dprint("Hello World");
}

Разбор полетов

Некоторые вещи которые необходимо учесть здесь:

Во-первых dprint не public функция, это обычная функция, но переключатели нормально работают с ней.

Во-вторых в переключателях могут быть условия. Как в этой строке

Код:
state (!strcmp(cmdtext, "/debug")) printState:on;[/php]

тоже самое что и

if (!strcmp(cmdtext, "/debug"))
{
    state printState:on;
}

В-третьих здесь 2 функции которые зависят от одного переключателя (OnPlayerCommandText and dprint). Это не проблема.

Разьяснения
Теперь, когда мы взглянули на примеры, вы наверно интересуетесь, что же происходит (конечно если вы не читали pawn-lang.pdf). Давайте, в таком случае, взглянем на код ближе

state:

Код:
state a:b

Это устанавливает переключатель a в положение b. Вам не надо обьявлять переключатели, по сравнению с переменными.
Как уже упоминалось в переключателях может быть условие

Код:
state (c == 1) a:b;

Это устанавливает переключатель а в положение б если с равно 1.

Функции:

Вы можете создавать множество копий одной и той же функции, которая должна будет вызываться в разных ситуациях, без проверок до вызова или в самой функции. Функция может содержать: 0 переключателей, 1 переключатель, множество переключателей, другие переключатели(*заметка от переводчика: взгляните на пример прежде чем понимать это)
Например:

Без переключателей

Код:
dprint(message[])
{
    print(message);
}

Эта функция вызывается всегда, неважно в каком положении любой переключатель находится

Один переключатель

Код:
dprint(message[]) <debugState>
{
print(message);
}

Эта функция будет вызываться когда debugstate в положении on

Несколько переключателей

Код:
dprint(message[]) <debugLevel>
{
    print(message);
}

Функция будет вызываться если debuglevel в положении _1 или _2 (переменные не могут иметь в названии лишь цифры или начинаться с них)

Другие переключатели

Код:
dprint(message[]) <>
{
    print(message);
}

Эта функция будет вызываться тогда когда другие функции dprint не вызвались, из-за того что переключатели не совпали

entry()

Это спец функция (похожая на main) которая вызывается в тех случаях, когда вы переключаете переключатель(sic). К сожалению работает лишь для одного переключателя

Код:
main ()
{
    printf("hello");
    state myState:moo;
    printf("world");
}

entry() <myState>
{
    printf("change");
}

Выведет в консоль

Код:
hello
change
world

Пример №3

Код:
CancelRace()
{
    state raceState:none; // Выключает гонку
    gEntrants = 0;
}

public OnPlayerEnterRaceCheckpoint(playerid) <raceState>
{
    // Вызывается когда ниодной гонки не запущено
    SendClientMessage(playerid, 0xFF0000AA, "Sorry, there's no race on at this time");
}

public OnPlayerEnterRaceCheckpoint(playerid) <raceState>
{
    // Вызывается когда кто-то из игроков входит в последний чекпоинт
    if (AtLastCheckpoint(playerid))
    {
        // Этот игрок вошел в последнюю точку первым
        SendClientMessage(playerid, 0xFF0000AA, "Congratulations, you won the race");
        DisablePlayerRaceCheckpoint(playerid);
        state raceState:won;
        --gEntrants;
    }
    else
    {
        // И тот который нет
        SetNextCheckpoint(playerid);
    }
}

public OnPlayerEnterRaceCheckpoint(playerid) <raceState>
{
    // Вызывается когда кто-то уже выйграл, а другие нет
    if (AtLastCheckpoint(playerid))
    {
        // Доехал до конца, но не выйграл
        SendClientMessage(playerid, 0xFF0000AA, "Sorry, somebody already won");
        DisablePlayerRaceCheckpoint(playerid);
        state (--gEntrants == 0) raceState:none;
    }
    else
    {
        // Еще не доехал
        SetNextCheckpoint(playerid);
    }
}

public OnPlayerEnterRaceCheckpoint(playerid) <>
{
    // Вызывается во время гонки, просто переставляем чекпоинты
    SetNextCheckpoint(playerid);
    if (AtLastCheckpoint(playerid))
    {
        // Кто-то доехал до финиша
        state raceState:finish;
    }
}

Автор: Y_Less Перевод: [A]Le[X]and[R]