Система наблюдения в Pawn

Активный
Статус
Сообщения
516
Лайки
32

8

месяц на сайте

Руководство по созданию системы наблюдения за игроками для администраторов и модераторов.

Структура данных наблюдателя

Код:
enum SpectatorInfo
{
    sTarget,
    sMode,
    sInterior,
    sVirtualWorld
}

new SpectatorData[MAX_PLAYERS][SpectatorInfo];
new IsSpectating[MAX_PLAYERS];

Включение режима наблюдения

Код:
StartSpectating(playerid, targetid)
{
    if(!IsPlayerConnected(targetid))
    {
        SendClientMessage(playerid, -1, "Игрок не найден");
        return 0;
    }
    
    if(targetid == playerid)
    {
        SendClientMessage(playerid, -1, "Вы не можете наблюдать за собой");
        return 0;
    }
    
    if(IsSpectating[playerid])
    {
        StopSpectating(playerid);
    }
    
    IsSpectating[playerid] = 1;
    SpectatorData[playerid][sTarget] = targetid;
    SpectatorData[playerid][sMode] = 1;
    SpectatorData[playerid][sInterior] = GetPlayerInterior(playerid);
    SpectatorData[playerid][sVirtualWorld] = GetPlayerVirtualWorld(playerid);
    
    TogglePlayerSpectating(playerid, 1);
    PlayerSpectatePlayer(playerid, targetid);
    
    new string[128], name[MAX_PLAYER_NAME];
    GetPlayerName(targetid, name, sizeof(name));
    format(string, sizeof(string), "Вы наблюдаете за игроком %s (ID: %d)", name, targetid);
    SendClientMessage(playerid, -1, string);
    
    return 1;
}

Остановка наблюдения

Код:
StopSpectating(playerid)
{
    if(!IsSpectating[playerid])
    {
        return 0;
    }
    
    TogglePlayerSpectating(playerid, 0);
    
    new Float:x, Float:y, Float:z;
    GetPlayerPos(SpectatorData[playerid][sTarget], x, y, z);
    SetPlayerPos(playerid, x+2, y, z);
    SetPlayerInterior(playerid, SpectatorData[playerid][sInterior]);
    SetPlayerVirtualWorld(playerid, SpectatorData[playerid][sVirtualWorld]);
    
    IsSpectating[playerid] = 0;
    SpectatorData[playerid][sTarget] = INVALID_PLAYER_ID;
    
    SendClientMessage(playerid, -1, "Режим наблюдения отключен");
    return 1;
}

Наблюдение за транспортом

Код:
StartSpectatingVehicle(playerid, vehicleid)
{
    if(!IsValidVehicle(vehicleid))
    {
        SendClientMessage(playerid, -1, "Транспорт не найден");
        return 0;
    }
    
    if(IsSpectating[playerid])
    {
        StopSpectating(playerid);
    }
    
    IsSpectating[playerid] = 1;
    SpectatorData[playerid][sTarget] = vehicleid;
    SpectatorData[playerid][sMode] = 2;
    SpectatorData[playerid][sInterior] = GetPlayerInterior(playerid);
    SpectatorData[playerid][sVirtualWorld] = GetPlayerVirtualWorld(playerid);
    
    TogglePlayerSpectating(playerid, 1);
    PlayerSpectateVehicle(playerid, vehicleid);
    
    new string[128];
    format(string, sizeof(string), "Вы наблюдаете за транспортом ID: %d", vehicleid);
    SendClientMessage(playerid, -1, string);
    
    return 1;
}

Переключение между игроками

Код:
SwitchSpectateTarget(playerid, newtargetid)
{
    if(!IsSpectating[playerid])
    {
        return 0;
    }
    
    if(SpectatorData[playerid][sMode] != 1)
    {
        return 0;
    }
    
    if(!IsPlayerConnected(newtargetid))
    {
        SendClientMessage(playerid, -1, "Игрок не найден");
        return 0;
    }
    
    SpectatorData[playerid][sTarget] = newtargetid;
    PlayerSpectatePlayer(playerid, newtargetid);
    
    new string[128], name[MAX_PLAYER_NAME];
    GetPlayerName(newtargetid, name, sizeof(name));
    format(string, sizeof(string), "Теперь вы наблюдаете за игроком %s (ID: %d)", name, newtargetid);
    SendClientMessage(playerid, -1, string);
    
    return 1;
}

Команды для наблюдения

Код:
CMD:spec(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 1)
    {
        SendClientMessage(playerid, -1, "У вас нет доступа к этой команде");
        return 1;
    }
    
    if(IsSpectating[playerid])
    {
        StopSpectating(playerid);
        return 1;
    }
    
    new targetid;
    if(sscanf(params, "u", targetid))
    {
        SendClientMessage(playerid, -1, "Использование: /spec [id игрока]");
        return 1;
    }
    
    StartSpectating(playerid, targetid);
    return 1;
}

CMD:specoff(playerid, params[])
{
    if(!IsSpectating[playerid])
    {
        SendClientMessage(playerid, -1, "Вы не находитесь в режиме наблюдения");
        return 1;
    }
    
    StopSpectating(playerid);
    return 1;
}

CMD:specnext(playerid, params[])
{
    if(!IsSpectating[playerid] || SpectatorData[playerid][sMode] != 1)
    {
        SendClientMessage(playerid, -1, "Вы не наблюдаете за игроком");
        return 1;
    }
    
    new currentTarget = SpectatorData[playerid][sTarget];
    new nextTarget = INVALID_PLAYER_ID;
    new found = 0;
    
    for(new i = currentTarget + 1; i < MAX_PLAYERS; i++)
    {
        if(IsPlayerConnected(i) && i != playerid)
        {
            nextTarget = i;
            found = 1;
            break;
        }
    }
    
    if(!found)
    {
        for(new i = 0; i < currentTarget; i++)
        {
            if(IsPlayerConnected(i) && i != playerid)
            {
                nextTarget = i;
                found = 1;
                break;
            }
        }
    }
    
    if(found)
    {
        SwitchSpectateTarget(playerid, nextTarget);
    }
    else
    {
        SendClientMessage(playerid, -1, "Нет других игроков для наблюдения");
    }
    
    return 1;
}

CMD:specprev(playerid, params[])
{
    if(!IsSpectating[playerid] || SpectatorData[playerid][sMode] != 1)
    {
        SendClientMessage(playerid, -1, "Вы не наблюдаете за игроком");
        return 1;
    }
    
    new currentTarget = SpectatorData[playerid][sTarget];
    new prevTarget = INVALID_PLAYER_ID;
    new found = 0;
    
    for(new i = currentTarget - 1; i >= 0; i--)
    {
        if(IsPlayerConnected(i) && i != playerid)
        {
            prevTarget = i;
            found = 1;
            break;
        }
    }
    
    if(!found)
    {
        for(new i = MAX_PLAYERS - 1; i > currentTarget; i--)
        {
            if(IsPlayerConnected(i) && i != playerid)
            {
                prevTarget = i;
                found = 1;
                break;
            }
        }
    }
    
    if(found)
    {
        SwitchSpectateTarget(playerid, prevTarget);
    }
    else
    {
        SendClientMessage(playerid, -1, "Нет других игроков для наблюдения");
    }
    
    return 1;
}

Информация о наблюдаемом игроке

Код:
ShowSpectateInfo(playerid)
{
    if(!IsSpectating[playerid] || SpectatorData[playerid][sMode] != 1)
    {
        return 0;
    }
    
    new targetid = SpectatorData[playerid][sTarget];
    if(!IsPlayerConnected(targetid))
    {
        return 0;
    }
    
    new string[256], name[MAX_PLAYER_NAME];
    GetPlayerName(targetid, name, sizeof(name));
    
    new Float:health, Float:armour;
    GetPlayerHealth(targetid, health);
    GetPlayerArmour(targetid, armour);
    
    new Float:x, Float:y, Float:z;
    GetPlayerPos(targetid, x, y, z);
    
    format(string, sizeof(string),
        "~w~Наблюдение: ~y~%s~n~\
        ~w~ID: ~g~%d~n~\
        ~w~Здоровье: ~r~%.0f~n~\
        ~w~Броня: ~b~%.0f~n~\
        ~w~Деньги: ~g~$%d~n~\
        ~w~Оружие: ~y~%s",
        name,
        targetid,
        health,
        armour,
        GetPlayerMoney(targetid),
        GetWeaponName(GetPlayerWeapon(targetid))
    );
    
    GameTextForPlayer(playerid, string, 2000, 3);
    return 1;
}

public OnPlayerUpdate(playerid)
{
    if(IsSpectating[playerid] && SpectatorData[playerid][sMode] == 1)
    {
        static lastUpdate[MAX_PLAYERS];
        if(GetTickCount() - lastUpdate[playerid] > 1000)
        {
            ShowSpectateInfo(playerid);
            lastUpdate[playerid] = GetTickCount();
        }
    }
    return 1;
}

Автоматическое переключение при отключении

Код:
public OnPlayerDisconnect(playerid, reason)
{
    // Остановка наблюдения за отключившимся игроком
    for(new i = 0; i < MAX_PLAYERS; i++)
    {
        if(IsSpectating[i] && SpectatorData[i][sTarget] == playerid)
        {
            StopSpectating(i);
            SendClientMessage(i, -1, "Игрок, за которым вы наблюдали, отключился");
        }
    }
    
    // Остановка наблюдения отключившегося игрока
    if(IsSpectating[playerid])
    {
        StopSpectating(playerid);
    }
    
    return 1;
}

Наблюдение за транспортом игрока

Код:
CMD:specvehicle(playerid, params[])
{
    if(PlayerInfo[playerid][pAdmin] < 1)
    {
        SendClientMessage(playerid, -1, "У вас нет доступа к этой команде");
        return 1;
    }
    
    new targetid;
    if(sscanf(params, "u", targetid))
    {
        SendClientMessage(playerid, -1, "Использование: /specvehicle [id игрока]");
        return 1;
    }
    
    if(!IsPlayerConnected(targetid))
    {
        SendClientMessage(playerid, -1, "Игрок не найден");
        return 1;
    }
    
    if(!IsPlayerInAnyVehicle(targetid))
    {
        SendClientMessage(playerid, -1, "Игрок не находится в транспорте");
        return 1;
    }
    
    new vehicleid = GetPlayerVehicleID(targetid);
    StartSpectatingVehicle(playerid, vehicleid);
    
    return 1;
}

Список наблюдающих

Код:
GetSpectatorsCount(targetid)
{
    new count = 0;
    for(new i = 0; i < MAX_PLAYERS; i++)
    {
        if(IsSpectating[i] && SpectatorData[i][sTarget] == targetid)
        {
            count++;
        }
    }
    return count;
}

CMD:specinfo(playerid, params[])
{
    new count = GetSpectatorsCount(playerid);
    if(count > 0)
    {
        new string[128];
        format(string, sizeof(string), "За вами наблюдают %d администраторов", count);
        SendClientMessage(playerid, -1, string);
    }
    return 1;
}

Ограничение действий в режиме наблюдения

Код:
public OnPlayerCommandText(playerid, cmdtext[])
{
    if(IsSpectating[playerid])
    {
        new allowedCommands[][] = {
            "spec", "specoff", "specnext", "specprev", "specvehicle", "specinfo"
        };
        
        new cmd[32];
        sscanf(cmdtext, "s[32]", cmd);
        
        new allowed = 0;
        for(new i = 0; i < sizeof(allowedCommands); i++)
        {
            if(strcmp(cmd, allowedCommands[i], true) == 0)
            {
                allowed = 1;
                break;
            }
        }
        
        if(!allowed)
        {
            SendClientMessage(playerid, -1, "Вы не можете использовать команды в режиме наблюдения");
            return 1;
        }
    }
    return 0;
}

Система наблюдения - важный инструмент для администраторов. Эти примеры показывают полный функционал наблюдения за игроками и транспортом.
 

1 человек читают эту тему (Всего: 1, Пользователей: 0, Гостей: 1)

Сверху