R1KO
fuck society
- Сообщения
- 9,457
- Реакции
- 7,786
- Команда форума
- #1
Небольшое содержание:
Для написания модуля нам понадобится всё что нужно для написания любого другого плагина + библиотека випа (vip_core.inc). Взять её можно в архиве с ядром.
Как пример будем писать модуль телепорта к игроку или куда смотрит прицел.
Подключаем необходимые библиотеки:
Первым делом нужно зарегистрировать функцию:
У нас есть 5 типов данных VIP-функций:
Поскольку в данном модуле мне нужно только разрешить/запретить использование логичнее всего было бы использовать BOOL, но я хочу позволить ограничивать количество телепортов за раунд, поэтому буду использовать INT, чтобы указывать количество раз.
Типы VIP-функций
Поскольку телепорт не имеет смысла включать выключать, а нужно при нажатии в меню на него сразу выводить список игроков буду использовать тип SELECTABLE.
И сразу создаем массив переменных для подсчета количества телепортаций.
Изначально я предполагаю что если "Teleport" указано:
0 - нет доступа
> 0 - кол-во использований за раунд.
-1 - безлимит
И так регистрируем функцию:
Нужно чтобы при нажатии на пункт открывался список игроков:
Помним что имя ф-и при нажатии OnSelectItem.
Исходя из прототипа:
Получаем:
Дальше я хочу чтобы отображении пункта показывалось сколько телепортаций осталось.
Смотрим прототип функции:
Помним что ф-я отображения текста пункта называлась OnDisplayItem
Теперь я хочу чтобы когда у игрока не осталось доступных телепортов то пункт становился не активным (белым, его нельзя будет нажать)
Согласно прототипу:
Получаем:
Далее мелочи.
Очищаем переменную при входе игрока:
Обнуляем кол-во телепортаций в начале раунда:
Работоспособность я не проверял. Кто хочет - соберите, проверьте, отпишитесь.
В дальнейшем прошу все вопросы связанные с созданием модулей задавать здесь.
Ссылки на другие мануалы:
Как привязать любой плагин к VIP плагину.
- Как написать модуль - описано в этом посте.
- Как прикрутить любой плагин к VIP - [MANUAL] Создание модулей
- Если есть хоть малейшая вероятность того что модуль будет выгружен/загружен/перезагружен во время работы сервера (например, при смене карты), а лучше вообще обязательно сделать пункт 1 из статьи VIP-Core/update.md at master-dev · R1KO/VIP-Core · GitHub
Для написания модуля нам понадобится всё что нужно для написания любого другого плагина + библиотека випа (vip_core.inc). Взять её можно в архиве с ядром.
Как пример будем писать модуль телепорта к игроку или куда смотрит прицел.
Подключаем необходимые библиотеки:
PHP:
#pragma semicolon 1
#include <sourcemod>
#include <sdktools>
#include <vip_core>
Первым делом нужно зарегистрировать функцию:
PHP:
native VIP_RegisterFeature(const String:sFeatureName[],
VIP_ValueType: ValType = VIP_NULL,
VIP_FeatureType: FeatureType = TOGGLABLE,
ItemSelectCallback: Item_select_callback = ItemSelectCallback: INVALID_FUNCTION,
ItemDisplayCallback: Item_display_callback = ItemDisplayCallback: INVALID_FUNCTION,
ItemDrawCallback: Item_draw_callback = ItemDrawCallback: INVALID_FUNCTION);
У нас есть 5 типов данных VIP-функций:
PHP:
enum VIP_ValueType
{
VIP_NULL = 0, // Нет данных
INT, // Целое число
FLOAT, // Число с запятой
BOOL, // 1/0
STRING // Строка
}
Поскольку в данном модуле мне нужно только разрешить/запретить использование логичнее всего было бы использовать BOOL, но я хочу позволить ограничивать количество телепортов за раунд, поэтому буду использовать INT, чтобы указывать количество раз.
Типы VIP-функций
PHP:
enum VIP_FeatureType
{
TOGGLABLE = 0, // Вкл/Выкл в меню
SELECTABLE, // Только нажатие
HIDE // Скрытый
}
Поскольку телепорт не имеет смысла включать выключать, а нужно при нажатии в меню на него сразу выводить список игроков буду использовать тип SELECTABLE.
И сразу создаем массив переменных для подсчета количества телепортаций.
Изначально я предполагаю что если "Teleport" указано:
0 - нет доступа
> 0 - кол-во использований за раунд.
-1 - безлимит
И так регистрируем функцию:
PHP:
new g_iClientTeleports[MAXPLAYERS+1]; // Массив переменных для подсчета количества телепортаций
#define VIP_TELEPORT "Teleport" // Создаем константу, которая будет уникальным именем нашей функции.
public VIP_OnVIPLoaded() // Событие когда ядро VIP-плагина загрузилось и готово к работе.
{
VIP_RegisterFeature(VIP_TELEPORT, INT, SELECTABLE, OnSelectItem, OnDisplayItem, OnDrawItem);
/*
OnSelectItem - Функция будет вызыватся при нажатии на пункт
OnDisplayItem - Функция будет вызыватся при отображении текста пункта
OnDrawItem - Функция будет вызыватся при отображении стиля пункта
*/
}
Нужно чтобы при нажатии на пункт открывался список игроков:
Помним что имя ф-и при нажатии OnSelectItem.
Исходя из прототипа:
PHP:
funcenum ItemSelectCallback
{
Action:public(iClient, const String:sFeatureName[], VIP_ToggleState:OldStatus, &VIP_ToggleState:NewStatus), // Используется когда тип ф-и TOGGLABLE
bool:public(iClient, const String:sFeatureName[]) // Используется когда тип ф-и SELECTABLE
};
Получаем:
PHP:
public bool:OnSelectItem(iClient, const String:sFeatureName[])
{
ShowTeleportMenu(iClient);
// Если вернуть true игроку снова откроется VIP-меню, нам это не нужно.
return false;
}
ShowTeleportMenu(iClient)
{
// Создаем меню с игроками
new Handle:hMenu = CreateMenu(MenuHandler_TeleportMenu);
SetMenuTitle(hMenu, "Телепорт");
SetMenuExitBackButton(hMenu, true);
AddMenuItem(hMenu, "", "На позицию прицела"); // Тут думаю всё ясно
AddMenuItem(hMenu, "", "К игроку под прицелом");
decl String:sUserId[12], String:sName[MAX_NAME_LENGTH], i;
for (i = 1; i <= MaxClients; ++i)
{
if (i != iClient && IsClientInGame(i) && IsPlayerAlive(i) && GetClientName(i, sName, sizeof(sName)))
{
IntToString(GetClientUserId(i), sUserId, sizeof(sUserId));
AddMenuItem(hMenu, sUserId, sName);
}
}
DisplayMenu(hMenu, iClient, MENU_TIME_FOREVER);
}
public MenuHandler_TeleportMenu(Handle:hMenu, MenuAction:action, iClient, Item)
{
switch(action)
{
case MenuAction_End: CloseHandle(hMenu);
case MenuAction_Cancel:
{
if(Item == MenuCancel_ExitBack)
{
// Если игрок нажал "Назад" открываем ему обратно VIP-меню
VIP_SendClientVIPMenu(iClient);
}
}
case MenuAction_Select:
{
switch(Item)
{
case 0: // Игрок выбрал 1-й пункт
{
decl Float:fPos[3];
GetAimPos(iClient, fPos);
TeleportEntity(iClient, fPos, NULL_VECTOR, NULL_VECTOR);
g_iClientTeleports[iClient]++;
}
case 1: // Игрок выбрал 2-й пункт
{
new iTarget = GetClientAimTarget(iClient, true);
if (iTarget > 0)
{
decl Float:fPos[3];
GetClientAbsOrigin(iTarget, fPos);
TeleportEntity(iClient, fPos, NULL_VECTOR, NULL_VECTOR);
g_iClientTeleports[iClient]++;
}
else
{
VIP_PrintToChatClient(iClient, "Наведите прицел на игрока!");
ShowTeleportMenu(iClient);
}
}
default: // Игрок выбрал другого игрока
{
decl String:sUserID[16], iTarget;
GetMenuItem(hMenu, Item, sUserID, sizeof(sUserID));
iTarget = GetClientOfUserId(StringToInt(sUserID));
if(iTarget != 0 && IsPlayerAlive(iTarget))
{
decl Float:fPos[3];
GetClientAbsOrigin(iTarget, fPos);
TeleportEntity(iClient, fPos, NULL_VECTOR, NULL_VECTOR);
g_iClientTeleports[iClient]++;
}
else
{
VIP_PrintToChatClient(iClient, "Игрок больше недоступен!");
}
}
}
VIP_SendClientVIPMenu(iClient);
}
}
}
GetAimPos(iClient, Float:fPos[3])
{
decl Float:fAngles[3], Float:fDirection[3];
GetClientEyeAngles(iClient, fAngles);
GetClientEyePosition(iClient, fPos);
TR_TraceRayFilter(fPos, fAngles, MASK_SOLID, RayType_Infinite, FilterGetAim, iClient);
TR_GetEndPosition(fPos);
GetVectorAngles(fPos, fAngles);
fAngles[0] = fAngles[2] = 0.0;
fAngles[1] += 180.0;
GetAngleVectors(fAngles, fDirection, NULL_VECTOR, NULL_VECTOR);
fPos[0] = fPos[0] + fDirection[0] * 30.0;
fPos[1] = fPos[1] + fDirection[1] * 30.0;
fPos[2] += 15.0;
}
public bool:FilterGetAim(iTraceEnt, iMask, any:iEntity)
{
return iTraceEnt != iEntity;
}
Дальше я хочу чтобы отображении пункта показывалось сколько телепортаций осталось.
Смотрим прототип функции:
PHP:
functag public bool:ItemDisplayCallback(iClient, const String:sFeatureName[], String:sDisplay[], maxlen);
Помним что ф-я отображения текста пункта называлась OnDisplayItem
PHP:
public bool:OnDisplayItem(iClient, const String:sFeatureName[], String:sDisplay[], maxlen)
{
if(VIP_IsClientFeatureUse(iClient, VIP_TELEPORT)) // Проверяем что функция включена у игрока
{
new iTeleports = VIP_GetClientFeatureInt(iClient, VIP_TELEPORT);
// VIP_GetClientFeatureInt(iClient, VIP_TELEPORT) - Получит количество доступных телепортов (То что в конфиге указано в "Teleport")
if(iTeleports > 0) // Если кол-во телепортов ограничено
{
// Выводим кол-во оставшихся телепортов.
Format(sDisplay, maxlen, "%s [Осталось: %i]", sDisplay, VIP_GetClientFeatureInt(iClient, VIP_TELEPORT)-g_iClientTeleports[iClient]);
// Если вернуть true то будет выводиться то что в sDisplay.
return true;
}
}
// А во всех остальных случаях нужно выводить без изменений
return false;
}
Теперь я хочу чтобы когда у игрока не осталось доступных телепортов то пункт становился не активным (белым, его нельзя будет нажать)
Согласно прототипу:
PHP:
functag public ItemDrawCallback(iClient, const String:sFeatureName[], style);
Получаем:
PHP:
public OnDrawItem(iClient, const String:sFeatureName[], iStyle)
{
if(VIP_IsClientFeatureUse(iClient, VIP_TELEPORT)) // Проверяем что функция включена у игрока
{
if(VIP_GetClientFeatureInt(iClient, VIP_TELEPORT) >= g_iClientTeleports[iClient]) // Если кол-во телепортов ограничено и достигнут лимит
{
return ITEMDRAW_DISABLED;
}
}
return iStyle;
}
Далее мелочи.
Очищаем переменную при входе игрока:
PHP:
public OnClientConnected(iClient)
{
g_iClientTeleports[iClient] = 0;
}
Обнуляем кол-во телепортаций в начале раунда:
PHP:
public OnPluginStart()
{
HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy);
}
public Event_RoundStart(Handle:hEvent, const String:sEvName[], bool:bDontBroadcast)
{
for (new i = 1; i <= MaxClients; ++i)
{
g_iClientTeleports[i] = 0;
}
}
Работоспособность я не проверял. Кто хочет - соберите, проверьте, отпишитесь.
В дальнейшем прошу все вопросы связанные с созданием модулей задавать здесь.
Ссылки на другие мануалы:
Как привязать любой плагин к VIP плагину.
Вложения
Последнее редактирование: