diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 9f00a17..4d7671a 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [master] + branches: [master, feature/**, fix/**] paths-ignore: - "**.md" @@ -14,8 +14,11 @@ on: env: PACKAGE_NAME: VipModular STORE_README: 0 - GENERATE_PLUGINS_INI: 1 + PLUGINS_INI_GENERATE: 1 PLUGINS_INI_POSTFIX: vipm + DEPS_LIST: | + AmxxModularEcosystem/ParamsController@1.3.3 + AmxxModularEcosystem/CommandAliases@1.0.1 jobs: build: @@ -52,6 +55,7 @@ jobs: - name: Setup latest ReAPI includes env: REPO: "rehlds/ReAPI" + OUTPUT_VAR_NAME: REAPI_INCLUDE_PATH run: | mkdir -p dep/reapi cd dep/reapi @@ -64,7 +68,12 @@ jobs: 7z x *.zip - echo "REAPI_INCLUDE_PATH=$(pwd)/addons/amxmodx/scripting/include" >> $GITHUB_ENV + echo "${OUTPUT_VAR_NAME}=$(pwd)/addons/amxmodx/scripting/include" >> $GITHUB_ENV + + - uses: AmxxModularEcosystem/install-amxmodx-deps@master + with: + deps_list: ${{ env.DEPS_LIST }} + output_var_name: DEPS_COMPILER_ARGS - name: Setup AMXXPawn Compiler uses: wopox1337/setup-amxxpawn@v1.1.0 @@ -75,8 +84,9 @@ jobs: working-directory: amxmodx/scripting/ env: REAPI_INCLUDE: ${{ env.REAPI_INCLUDE_PATH }} - GENERATE_PLUGINS_INI: ${{ env.GENERATE_PLUGINS_INI }} + PLUGINS_INI_GENERATE: ${{ env.PLUGINS_INI_GENERATE }} PLUGINS_INI_POSTFIX: ${{ env.PLUGINS_INI_POSTFIX }} + DEPS_COMPILER_ARGS: ${{ env.DEPS_COMPILER_ARGS }} run: | compile() { sourcefile=$1 @@ -85,13 +95,14 @@ jobs: mkdir -p $(dirname $output_path) - echo -n "Compiling $sourcefile ... " + echo "Compiling $sourcefile... " amxxpc $sourcefile -o"$output_path" \ -i"include" \ -i"$REAPI_INCLUDE" \ - -i"$PARAMS_CONRTOLLER_INCLUDE" + $DEPS_COMPILER_ARGS \ + GITHUB_ACTIONS_USED=1 - if [ ! -z "${GENERATE_PLUGINS_INI}" ]; then + if [ ! -z "${PLUGINS_INI_GENERATE}" ]; then plugin_ini_path="../configs/plugins-${PLUGINS_INI_POSTFIX}.ini" touch $plugin_ini_path echo $amxxfile >> $plugin_ini_path diff --git a/.vscode/vipm-src.code-snippets b/.vscode/vipm-src.code-snippets deleted file mode 100644 index fa7cda3..0000000 --- a/.vscode/vipm-src.code-snippets +++ /dev/null @@ -1,22 +0,0 @@ -{ - "[VipM] AMXX Once Including": { - "scope": "amxxpawn", - "prefix": "onceincv", - "body": [ - "#if defined _vipmodular_$0_included", - " #endinput", - "#endif", - "#define _vipmodular_$0_included" - ] - }, - "[VipM src] AMXX Once Including": { - "scope": "amxxpawn", - "prefix": "onceincvs", - "body": [ - "#if defined _vipmodular_src_$0_included", - " #endinput", - "#endif", - "#define _vipmodular_src_$0_included" - ] - } -} \ No newline at end of file diff --git a/README.md b/README.md index de777c7..970ff9e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ -# Modular Vip System +# Vip Modular Модульная система привилегий. +## Требования + +- [ParamsController](https://github.com/AmxxModularEcosystem/ParamsController) версии [1.3.2](https://github.com/AmxxModularEcosystem/ParamsController/releases/tag/1.3.2) или [выше](https://github.com/AmxxModularEcosystem/ParamsController/releases/latest). +- [CommandAliases](https://github.com/AmxxModularEcosystem/CommandAliases) версии [1.0.1](https://github.com/AmxxModularEcosystem/CommandAliases/releases/tag/1.0.1-fix1) или [выше](https://github.com/AmxxModularEcosystem/CommandAliases/releases/latest). +- [ReAPI](https://github.com/rehlds/ReAPI) версии [5.24.0.300](https://github.com/rehlds/ReAPI/releases/tag/5.24.0.300) или [выше](https://github.com/rehlds/ReAPI/releases/latest). + ## Инструкции по настройке - [Основные настройки](readme/configs.md) @@ -15,18 +21,12 @@ | :-------------------------------- | :---------------------------------------------------------- | | `vipm_update_users` | Обновляет привилегии у всех игроков | | `vipm_info` | Выводит информацию о системе привилегий | -| | | | `vipm_modules` | Выводит таблицу модулей и их статусов | -| `vipm_module_params ` | Выводит таблицу параметров указанного модуля | -| | | | `vipm_limits` | Выводит таблицу типов проверок и некоторую информацию о них | -| `vipm_limit_params ` | Выводит таблицу параметров указанного типа проверки | -| | | -| `vipm_ic_types` | Выводит таблицу типов предметов | +| `ic_item_types` | Выводит таблицу типов предметов | ## Идеи - _\[Configs\]_ Добавить глобальные настройки типа ключ-значение, на которые можно ссылаться из основных конфигов как на файлы, только с префиксом Var: - _\[Modules\]_ Переработать обьедининение параметров модулей -- _\[ReadMe\]_ Нарисовать схему взаимодействия компонентов системы -- _\[IC\]_ Придумать как норм отвязать IC от ядра и, возможно, вынести его в отдельный репо +- _\[IC\]_ Придумать как норм отвязать IC от ядра и, возможно, вынести его в отдельный репо (WIP) diff --git a/amxmodx/configs/plugins/CommandAliases/VipM-M-WeaponMenu.json b/amxmodx/configs/plugins/CommandAliases/VipM-M-WeaponMenu.json new file mode 100644 index 0000000..8794f60 --- /dev/null +++ b/amxmodx/configs/plugins/CommandAliases/VipM-M-WeaponMenu.json @@ -0,0 +1,34 @@ +[ + { + "Command": "vipm_m_weaponmenu_menu", + "Alias": [ + "vm", + "say /vm", + "say_team /vm", + "vipmenu", + "say /vipmenu", + "say_team /vipmenu" + ] + }, + { + "Command": "vipm_m_weaponmenu_menu_silent", + "Alias": [ + "vm_silent", + "vipmenu_silent" + ] + }, + { + "Command": "vipm_m_weaponmenu_autoopen_toggle", + "Alias": [ + "vm_autoopen", + "say /vm_autoopen", + "say_team /vm_autoopen", + "vm_ao", + "say /vm_ao", + "say_team /vm_ao", + "vipmenu_autoopen", + "say /vipmenu_autoopen", + "say_team /vipmenu_autoopen" + ] + } +] \ No newline at end of file diff --git a/amxmodx/configs/plugins/VipModular/Cmds/WeaponMenu.json b/amxmodx/configs/plugins/VipModular/Cmds/WeaponMenu.json deleted file mode 100644 index cce069f..0000000 --- a/amxmodx/configs/plugins/VipModular/Cmds/WeaponMenu.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - /* - Тут указываются все возможные варианты - клиенских команд модуля WeaponMenu - */ - - // Команда открытия меню - "vipmenu": [ - "vm", - "say /vm", - "say_team /vm", - - "vipmenu", - "say /vipmenu", - "say_team /vipmenu" - ], - - // Команда открытия меню без вывода сообщения в случае недоступности - // Нужна для внутреннего использования, но можно и снаружи использовать - "vipmenu_silent": [ - "vm_silent", - "vipmenu_silent" - ], - - // Команда включения/отключения автооткрытия меню - // Состояние сбрасывается при выходе с сервера - "vipmenu_autoopen": [ - "vm_autoopen", - "say /vm_autoopen", - "say_team /vm_autoopen", - - "vm_ao", - "say /vm_ao", - "say_team /vm_ao", - - "vipmenu_autoopen", - "say /vipmenu_autoopen", - "say_team /vipmenu_autoopen" - ] -} \ No newline at end of file diff --git a/amxmodx/configs/plugins/VipModular/Items/AllGrenades.json b/amxmodx/configs/plugins/VipModular/Items/AllGrenades.json index 4f94441..bd683ad 100644 --- a/amxmodx/configs/plugins/VipModular/Items/AllGrenades.json +++ b/amxmodx/configs/plugins/VipModular/Items/AllGrenades.json @@ -1,20 +1,20 @@ { // Выдаёт все гранаты (1 разрывную, 1 дымовую, 2 световые) - "Type": "ItemsList", + "Item": "ItemsList", "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_hegrenade", "GiveType": "Add" }, { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_smokegrenade", "GiveType": "Add" }, { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_flashbang", "BpAmmo": 2, "GiveType": "Add" diff --git a/amxmodx/configs/plugins/VipModular/Items/DefuseKit.json b/amxmodx/configs/plugins/VipModular/Items/DefuseKit.json index 5e99f36..758f665 100644 --- a/amxmodx/configs/plugins/VipModular/Items/DefuseKit.json +++ b/amxmodx/configs/plugins/VipModular/Items/DefuseKit.json @@ -1,3 +1,3 @@ { - "Type": "DefuseKit" + "Item": "DefuseKit" } \ No newline at end of file diff --git a/amxmodx/configs/plugins/VipModular/SpawnItems/Premium.json b/amxmodx/configs/plugins/VipModular/SpawnItems/Premium.json index 002ac8a..2705609 100644 --- a/amxmodx/configs/plugins/VipModular/SpawnItems/Premium.json +++ b/amxmodx/configs/plugins/VipModular/SpawnItems/Premium.json @@ -9,16 +9,16 @@ "Items": [ { // Дигл - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_deagle", "GiveType": "Replace" }, { // Осколочная граната - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_hegrenade" }, { - "Type": "Money", + "Item": "Money", "Amount": 500 }, // Набор сапёра diff --git a/amxmodx/configs/plugins/VipModular/SpawnItems/Vip.json b/amxmodx/configs/plugins/VipModular/SpawnItems/Vip.json index fad5f0d..d38205a 100644 --- a/amxmodx/configs/plugins/VipModular/SpawnItems/Vip.json +++ b/amxmodx/configs/plugins/VipModular/SpawnItems/Vip.json @@ -9,12 +9,12 @@ "Items": [ { // Дигл - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_deagle", "GiveType": "Replace" }, { // Осколочная граната - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_hegrenade" }, // Набор сапёра diff --git a/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Premium.json b/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Premium.json index fa9ed88..e90cb75 100644 --- a/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Premium.json +++ b/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Premium.json @@ -7,7 +7,7 @@ "Title": "АК-47", "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_ak47" } ] @@ -16,7 +16,7 @@ "Title": "M4A1", "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_m4a1" } ] @@ -25,7 +25,7 @@ "Title": "AUG", "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_aug" } ] @@ -34,7 +34,7 @@ "Title": "SG552", "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_sg552" } ] @@ -45,7 +45,7 @@ "FakeInactive": true, "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_awp" } ] diff --git a/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Vip.json b/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Vip.json index faa860b..11a65f2 100644 --- a/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Vip.json +++ b/amxmodx/configs/plugins/VipModular/WeaponMenu/Menus/Vip.json @@ -21,7 +21,7 @@ /* Предметы, выдаваемые при выборе этого пункта */ "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_ak47" } ] @@ -31,7 +31,7 @@ "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_m4a1" } ] @@ -46,7 +46,7 @@ "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_awp" } ] diff --git a/amxmodx/scripting/ItemsController.sma b/amxmodx/scripting/ItemsController.sma new file mode 100644 index 0000000..2852817 --- /dev/null +++ b/amxmodx/scripting/ItemsController.sma @@ -0,0 +1,59 @@ +#include +#include +#include +#include "VipM/Utils" +#include "VipM/Forwards" + +public stock const PluginName[] = "Items Controller"; +public stock const PluginVersion[] = IC_VERSION; +public stock const PluginAuthor[] = "ArKaNeMaN"; +public stock const PluginURL[] = "https://github.com/ArKaNeMaN/amxx-VipModular-pub"; +public stock const PluginDescription[] = "Unified interface for items giving."; + +#include "ItemsController/Objects/Items/Instance" +#include "ItemsController/DefaultObjects/Registrar" + +public plugin_precache() { + PluginInit(); +} + +PluginInit() { + CallOnce(); + + register_plugin(PluginName, PluginVersion, PluginAuthor); + register_library(IC_LIBRARY); + PCCvar_Const(IC_VERSION_CVAR, IC_VERSION); + ParamsController_Init(); + Forwards_Init(); + + ItemInstance_Init(); + Forwards_RegAndCall("VipM_IC_OnInitTypes", ET_IGNORE); // deprecated +} + +#include "ItemsController/API/ItemType" +#include "ItemsController/API/Item" +#include "ItemsController/API/Compat" + +public plugin_natives() { + set_native_filter("@NativeFilter"); + + register_native("IC_Init", "@_Init"); + register_native("VipM_IC_Init", "@_Init"); // deprecated + + API_ItemType_Register(); + API_Item_Register(); + API_Compat_Register(); +} + +@_Init() { + PluginInit(); +} + +@NativeFilter(const name[], index, trap) { + new bool:handled = false; + if (DefaultObjects_HandleNativeFilter(name, trap)) { + handled = true; + } + + return handled ? PLUGIN_HANDLED : PLUGIN_CONTINUE; +} diff --git a/amxmodx/scripting/ItemsController/API/Compat.inc b/amxmodx/scripting/ItemsController/API/Compat.inc new file mode 100644 index 0000000..89046ec --- /dev/null +++ b/amxmodx/scripting/ItemsController/API/Compat.inc @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "ItemsController/Objects/Items/Type" +#include "ItemsController/Objects/Items/Instance" + +// API для совместимости со старой версией +// Все зарегистрированные тут нативы устаревшие. + +API_Compat_Register() { + register_native("VipM_IC_RegisterType", "@_VipM_IC_RegisterType"); + register_native("VipM_IC_RegisterTypeEvent", "@_VipM_IC_RegisterTypeEvent"); + register_native("VipM_IC_JsonGetItem", "@_VipM_IC_JsonGetItem"); + register_native("VipM_IC_GiveItem", "@_VipM_IC_GiveItem"); +} + +T_IC_ItemType:@_VipM_IC_RegisterType() { + enum {Arg_Name = 1} + + new name[IC_ITEM_TYPE_NAME_MAX_LEN]; + get_string(Arg_Name, name, charsmax(name)); + + return ItemType_Construct(name); +} + +@_VipM_IC_RegisterTypeEvent(const pluginIndex) { + enum {Arg_Type = 1, Arg_Event, Arg_FuncName} + + new typeName[IC_ITEM_TYPE_NAME_MAX_LEN]; + get_string(Arg_Type, typeName, charsmax(typeName)); + new T_IC_ItemType:type = ItemType_Find(typeName, .orFail = true); + + new E_ItemTypeEvent:event = E_ItemTypeEvent:get_param(Arg_Event); + new funcName[IC_EVENT_LISTENER_FUNCTION_NAME_MAX_LEN]; + get_string(Arg_FuncName, funcName, charsmax(funcName)); + + new listener = ItemType_MakeEventListener(event, pluginIndex, funcName); + ItemType_SetEventListener(type, event, listener); +} + +T_IC_Item:@_VipM_IC_JsonGetItem() { + enum {Arg_InstanceJson = 1} + + new JSON:isntanceJson = JSON:get_param_byref(Arg_InstanceJson); + + new T_IC_Item:item = ItemInstance_ReadFromJsonObject(isntanceJson); + json_free(isntanceJson); + return item; +} + + +bool:@_VipM_IC_GiveItem() { + enum {Arg_PlayerIndex = 1, Arg_Item} + + new playerIndex = get_param(Arg_PlayerIndex); + new T_IC_Item:item = T_IC_Item:get_param(Arg_Item); + + return ItemInstance_Give(playerIndex, item); +} diff --git a/amxmodx/scripting/ItemsController/API/Item.inc b/amxmodx/scripting/ItemsController/API/Item.inc new file mode 100644 index 0000000..482b347 --- /dev/null +++ b/amxmodx/scripting/ItemsController/API/Item.inc @@ -0,0 +1,52 @@ +#include +#include +#include + +#include "ItemsController/Objects/Items/Instance" + +API_Item_Register() { + register_native("IC_Item_ReadFromJson", "@_Item_ReadFromJson"); + register_native("IC_Item_ReadArrayFromJson", "@_Item_ReadArrayFromJson"); + register_native("IC_Item_Give", "@_Item_Give"); + register_native("IC_Item_Free", "@_Item_Free"); +} + +T_IC_Item:@_Item_ReadFromJson() { + enum {Arg_InstanceJson = 1} + + new JSON:isntanceJson = JSON:get_param(Arg_InstanceJson); + + return ItemInstance_ReadFromJsonObject(isntanceJson); +} + + +Array:@_Item_ReadArrayFromJson() { + enum {Arg_InstancesJson = 1, Arg_Array} + + new JSON:isntancesJson = JSON:get_param(Arg_InstancesJson); + new Array:array = Array:get_param_byref(Arg_Array); + + array = ItemInstance_ReadArrayFromJsonValue(isntancesJson, array); + set_param_byref(Arg_Array, _:array); + + return array; +} + + +bool:@_Item_Give() { + enum {Arg_PlayerIndex = 1, Arg_Item} + + new playerIndex = get_param(Arg_PlayerIndex); + new T_IC_Item:item = T_IC_Item:get_param(Arg_Item); + + return ItemInstance_Give(playerIndex, item); +} + + +T_IC_Item:@_Item_Free() { + enum {Arg_Item = 1} + + new T_IC_Item:item = T_IC_Item:get_param(Arg_Item); + + return ItemInstance_Free(item); +} diff --git a/amxmodx/scripting/ItemsController/API/ItemType.inc b/amxmodx/scripting/ItemsController/API/ItemType.inc new file mode 100644 index 0000000..b4afe45 --- /dev/null +++ b/amxmodx/scripting/ItemsController/API/ItemType.inc @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "ItemsController/Objects/Items/Type" + +API_ItemType_Register() { + register_native("IC_ItemType_Register", "@_ItemType_Register"); + register_native("IC_ItemType_SetEventListener", "@_ItemType_SetEventListener"); + register_native("IC_ItemType_AddParams", "@_ItemType_AddParams"); +} + +T_IC_ItemType:@_ItemType_Register() { + enum {Arg_Name = 1} + + new name[IC_ITEM_TYPE_NAME_MAX_LEN]; + get_string(Arg_Name, name, charsmax(name)); + + return ItemType_Construct(name); +} + +@_ItemType_SetEventListener(const pluginIndex) { + enum {Arg_Type = 1, Arg_Event, Arg_FuncName} + + new T_IC_ItemType:type = T_IC_ItemType:get_param(Arg_Type); + new E_ItemTypeEvent:event = E_ItemTypeEvent:get_param(Arg_Event); + new funcName[IC_EVENT_LISTENER_FUNCTION_NAME_MAX_LEN]; + get_string(Arg_FuncName, funcName, charsmax(funcName)); + + new listener = ItemType_MakeEventListener(event, pluginIndex, funcName); + ItemType_SetEventListener(type, event, listener); +} + +@_ItemType_AddParams(const pluginIndex, const paramsCount) { + enum {Arg_Type = 1, Arg_Params} + + new T_IC_ItemType:type = T_IC_ItemType:get_param(Arg_Type); + new Array:params = ParamsController_Param_ListFromNativeParams(Arg_Params, paramsCount); + + ItemType_AddParams(type, params); + + ArrayDestroy(params); +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Armor.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Armor.inc new file mode 100644 index 0000000..f645986 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Armor.inc @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_Armor_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Armor", + .onGive = "@OnArmorGive" + ); + IC_ItemType_AddParams(type, + "Armor", "Integer", true, + "MaxArmor", "Integer", false, + "SetArmor", "Boolean", false, + "Helmet", "Boolean", false + ); +} + +@OnArmorGive(const playerIndex, const Trie:p) { + new armor = PCGet_Int(p, "Armor"); + new ArmorType:helm = PCGet_Bool(p, "Helmet", false) ? ARMOR_VESTHELM : ARMOR_KEVLAR; + + if (!PCGet_Bool(p, "SetArmor", false)) { + armor = min(rg_get_user_armor(playerIndex) + armor, PCGet_Int(p, "MaxArmor", 100)); + } + + rg_set_user_armor(playerIndex, armor, helm); +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Command.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Command.inc new file mode 100644 index 0000000..1766dfc --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Command.inc @@ -0,0 +1,28 @@ +#include +#include +#include + +DefaultObjects_ItemType_Command_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Command", + .onGive = "@OnCommandGive" + ); + IC_ItemType_AddParams(type, + "Command", "String", true, + "ByServer", "Boolean", false + ); +} + +@OnCommandGive(const playerIndex, const Trie:p) { + static Command[128]; + PCGet_Str(p, "Command", Command, charsmax(Command)); + + replace_all(Command, charsmax(Command), "{UserId}", IntToStr(playerIndex)); + replace_all(Command, charsmax(Command), "{playerIndex}", IntToStr(playerIndex)); + + if (PCGet_Bool(p, "ByServer", false)) { + server_cmd(Command); + } else { + client_cmd(playerIndex, Command); + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/CustomWeapon.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/CustomWeapon.inc new file mode 100644 index 0000000..9016b2b --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/CustomWeapon.inc @@ -0,0 +1,211 @@ +#include +#include +#include +#include + +#if !defined _cwapi_included +enum T_CustomWeapon { Invalid_CustomWeapon = -1 } +enum CWeapon_GiveType { + CWAPI_GT_SMART = -1, + CWAPI_GT_APPEND, + CWAPI_GT_REPLACE, + CWAPI_GT_DROP, +} +native T_CustomWeapon:CWAPI_Weapons_Find(const sWeaponName[]); +native CWAPI_Weapons_Give( + const UserId, + const T_CustomWeapon:iWeapon, + const CWeapon_GiveType:iGiveType = CWAPI_GT_SMART, + const bool:bForceActive = false, + const initBpAmmo = -1 +); +#endif + +#if !defined _auw_included +native __auw__native__auw_give_weapon(iPlayer, const sWeaponName[], const bool: notification = true, const uid = -1, const iUidWithOffset = true, const iBuy = 0); +#endif + +#if !defined _ultimate_weapons_included +native weapons_give_user_ultimate(id, uid=-1, buy_name[]="", replace=0, ammo=-1, bpammo=-1); +#endif + +enum E_ItemType_CustomWeapon_Controller { + ItemType_CustomWeapon_Controller_None, + + ItemType_CustomWeapon_Controller_Cwapi, + ItemType_CustomWeapon_Controller_Auw, + ItemType_CustomWeapon_Controller_Uw, +} + +enum E_ItemType_CustomWeapon_GiveType { + ItemType_CustomWeapon_GiveType_Default, + ItemType_CustomWeapon_GiveType_Append, + ItemType_CustomWeapon_GiveType_Replace, + ItemType_CustomWeapon_GiveType_DropAndReplace, +} + +static E_ItemType_CustomWeapon_Controller:UsingController = ItemType_CustomWeapon_Controller_None; + +// Почему-то через {true, ...} всё кроме первой ячейки ставится в false. +static bool:AvailableControllers[E_ItemType_CustomWeapon_Controller] = {true, true, true, true}; + +bool:DefaultObjects_ItemType_CustomWeapon_NativeFilter(const name[], const trap) { + if (equal(name, "CWAPI_Weapons_Give")) { + AvailableControllers[ItemType_CustomWeapon_Controller_Cwapi] = !!trap; + return true; + } + if (equal(name, "CWAPI_Weapons_Find")) { + AvailableControllers[ItemType_CustomWeapon_Controller_Cwapi] = !!trap; + return true; + } + + if (equal(name, "__auw__native__auw_give_weapon")) { + AvailableControllers[ItemType_CustomWeapon_Controller_Auw] = !!trap; + return true; + } + + if (equal(name, "weapons_give_user_ultimate")) { + AvailableControllers[ItemType_CustomWeapon_Controller_Uw] = !!trap; + return true; + } + + return false; +} + +DefaultObjects_ItemType_CustomWeapon_Register() { + UsingController = ItemType_CustomWeapon_Controller_None; + for (new i = _:ItemType_CustomWeapon_Controller_Cwapi; i < _:E_ItemType_CustomWeapon_Controller; ++i) { + if (AvailableControllers[E_ItemType_CustomWeapon_Controller:i]) { + UsingController = E_ItemType_CustomWeapon_Controller:i; + } + } + + IC_ItemType_SimpleRegister( + .name = "CustomWeapon", + .onRead = "@ItemType_CustomWeapon_OnRead", + .onGive = "@ItemType_CustomWeapon_OnGive" + ); +} + +@ItemType_CustomWeapon_OnRead(const JSON:instanceJson, const Trie:p) { + if (UsingController == ItemType_CustomWeapon_Controller_None) { + log_amx("[WARNING] Custom weapons controller is not set. Item type `CustomWeapon` is not available."); + return IC_RET_READ_FAIL; + } + + new name[64]; + json_object_get_string(instanceJson, "Name", name, charsmax(name)); + TrieSetString(p, "Name", name); + + TrieSetCell(p, "GiveType", _:ItemType_CustomWeapon_ReadGiveTypeFromJsonObject(instanceJson, "GiveType")); + + return IC_RET_READ_SUCCESS; +} + +@ItemType_CustomWeapon_OnGive(const playerIndex, const Trie:p) { + if (UsingController == ItemType_CustomWeapon_Controller_None) { + log_amx("[ERROR] Custom weapons controller is not set."); + return IC_RET_GIVE_FAIL; + } + + static name[64]; + PCGet_Str(p, "Name", name, charsmax(name)); + if (!name[0]) { + log_amx("[WARNING] Custom weapon name is empty."); + return IC_RET_GIVE_FAIL; + } + + new E_ItemType_CustomWeapon_GiveType:giveType = E_ItemType_CustomWeapon_GiveType:PCGet_Int(p, "GiveType", _:ItemType_CustomWeapon_GiveType_Default); + + new bool:res = false; + switch (UsingController) { + case ItemType_CustomWeapon_Controller_Cwapi: + res = ItemType_CustomWeapon_GiveViaCwapi(playerIndex, name, giveType); + case ItemType_CustomWeapon_Controller_Auw: + res = ItemType_CustomWeapon_GiveViaAuw(playerIndex, name); + case ItemType_CustomWeapon_Controller_Uw: + res = ItemType_CustomWeapon_GiveViaUw(playerIndex, name, giveType); + default: + log_amx("[WARNING] Unknown custom weapons controller."); + } + + return res ? IC_RET_GIVE_SUCCESS : IC_RET_GIVE_FAIL; +} + +static bool:ItemType_CustomWeapon_GiveViaCwapi( + const playerIndex, + const weaponName[], + const E_ItemType_CustomWeapon_GiveType:giveType = ItemType_CustomWeapon_GiveType_Default +) { + new CWeapon_GiveType:gtype; + switch (giveType) { + case ItemType_CustomWeapon_GiveType_Append: + gtype = CWAPI_GT_APPEND; + case ItemType_CustomWeapon_GiveType_Replace: + gtype = CWAPI_GT_REPLACE; + case ItemType_CustomWeapon_GiveType_DropAndReplace: + gtype = CWAPI_GT_DROP; + default: + gtype = CWAPI_GT_SMART; + } + + new T_CustomWeapon:weapon = CWAPI_Weapons_Find(weaponName); + if (weapon == Invalid_CustomWeapon) { + abort(AMX_ERR_PARAMS, "Weapon '%s' not found in Custom Wepaons API.", weaponName); + return false; + } + + return CWAPI_Weapons_Give(playerIndex, weapon, gtype) > 0; +} + +static bool:ItemType_CustomWeapon_GiveViaAuw( + const playerIndex, + const weaponName[] +) { + return !!__auw__native__auw_give_weapon(playerIndex, weaponName); +} + +static bool:ItemType_CustomWeapon_GiveViaUw( + const playerIndex, + const weaponName[], + const E_ItemType_CustomWeapon_GiveType:giveType = ItemType_CustomWeapon_GiveType_Default +) { + new replace; + switch (giveType) { + case ItemType_CustomWeapon_GiveType_Append: + replace = 0; + case ItemType_CustomWeapon_GiveType_Replace: + replace = 2; + case ItemType_CustomWeapon_GiveType_DropAndReplace: + replace = 1; + default: + replace = 0; + } + + new nonConstName[32]; + copy(nonConstName, charsmax(nonConstName), weaponName); + + // Не понятно что оно возвращает, поэтому в любом случае будет успех. + weapons_give_user_ultimate( + playerIndex, + .buy_name = nonConstName, + .replace = replace + ); + + return true; +} + +static E_ItemType_CustomWeapon_GiveType:ItemType_CustomWeapon_ReadGiveTypeFromJsonObject(const JSON:Obj, const Key[], const bool:DotNot = false) { + new Str[32]; + json_object_get_string(Obj, Key, Str, charsmax(Str), DotNot); + + if (equali(Str, "GT_APPEND") || equali(Str, "Append") || equali(Str, "Add")) { + return ItemType_CustomWeapon_GiveType_Append; + } else if (equali(Str, "GT_REPLACE") || equali(Str, "Replace")) { + return ItemType_CustomWeapon_GiveType_Replace; + } else if (equali(Str, "GT_DROP_AND_REPLACE") || equali(Str, "Drop") || equali(Str, "DropAndReplace")) { + return ItemType_CustomWeapon_GiveType_DropAndReplace; + } else { + return ItemType_CustomWeapon_GiveType_Default; + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/DamageMult.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/DamageMult.inc new file mode 100644 index 0000000..4629635 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/DamageMult.inc @@ -0,0 +1,44 @@ +#include +#include +#include +#include + +static Float:PlayerGivenDmgMult[MAX_PLAYERS + 1] = {1.0, ...}; +static Float:PlayerTakenDmgMult[MAX_PLAYERS + 1] = {1.0, ...}; + +DefaultObjects_ItemType_DamageMult_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "DamageMult", + .onGive = "@ItemType_DamageMult_OnGive" + ); + IC_ItemType_AddParams(type, + "Given", "Float", false, + "Taken", "Float", false + ); + + RegisterHookChain(RG_CBasePlayer_Spawn, "@ItemType_DamageMult_OnPlayerSpawnPre", false); + RegisterHookChain(RG_CBasePlayer_TakeDamage, "@ItemType_DamageMult_OnPlayerTakeDamage", false); +} + +@ItemType_DamageMult_OnGive(const playerIndex, const Trie:p) { + PlayerGivenDmgMult[playerIndex] = PCGet_Float(p, "Given", 1.0); + PlayerTakenDmgMult[playerIndex] = PCGet_Float(p, "Taken", 1.0); +} + +@ItemType_DamageMult_OnPlayerSpawnPre(const playerIndex) { + PlayerGivenDmgMult[playerIndex] = 1.0; + PlayerTakenDmgMult[playerIndex] = 1.0; +} + +@ItemType_DamageMult_OnPlayerTakeDamage(const victimIndex, inflictorIndex, attackerInde, Float:damage, damageType) { + if (is_user_connected(attackerInde)) { + damage *= PlayerGivenDmgMult[attackerInde]; + } + + if (is_user_connected(victimIndex)) { + damage *= PlayerTakenDmgMult[victimIndex]; + } + + SetHookChainArg(4, ATYPE_FLOAT, damage); + return HC_CONTINUE; +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/DefuseKit.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/DefuseKit.inc new file mode 100644 index 0000000..010c297 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/DefuseKit.inc @@ -0,0 +1,17 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_DefuseKit_Register() { + IC_ItemType_SimpleRegister( + .name = "DefuseKit", + .onGive = "@OnDefuseKitGive" + ); +} + +@OnDefuseKitGive(const playerIndex, const Trie:p) { + if (get_member(playerIndex, m_iTeam) == TEAM_CT) { + rg_give_defusekit(playerIndex); + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Function.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Function.inc new file mode 100644 index 0000000..63198cf --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Function.inc @@ -0,0 +1,99 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_Function_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Function", + .onGive = "@OnFunctionGive" + ); + IC_ItemType_AddParams(type, + "Plugin", "String", true, + "Function", "String", true + ); + + // For AES-Bonuses compat + IC_ItemType_AddParams(type, + "Value", "Integer", false, + "Flags", "ShortString", false, + "Days", "Integer", false + ); +} + +@OnFunctionGive(const playerIndex, const Trie:p) { + if (callfunc_begin(PCGet_iStr(p, "Function"), PCGet_iStr(p, "Plugin")) > 0) { + callfunc_push_int(playerIndex); + + new flags[PARAM_SHORT_STRING_MAX_LEN]; // В AES 30, но почему бы не расширить до 64) + PCGet_Str(p, "Flags", flags, charsmax(flags)); + if (flags[0] != EOS) { + callfunc_push_str(flags); + + new days = PCGet_Int(p, "Days", 0); + if (days > 0) { + callfunc_push_int(days); + } + } else { + callfunc_push_int(PCGet_Int(p, "Value", 0)); + } + + // Вообще не используется в AES + // if (psh) { + // callfunc_push_int(psh); + // } + + return callfunc_end() > 0 ? IC_RET_GIVE_SUCCESS : IC_RET_GIVE_FAIL; + } + + abort(AMX_ERR_PARAMS, "Can't call function '%s' in plugin '%s'.", PCGet_iStr(p, "Function"), PCGet_iStr(p, "Plugin")); + return IC_RET_GIVE_FAIL; +} + +/** + * { + * "Item": "Function", + * "Plugin": "ItemsController.amxx", + * "Function": "@IC_ItemType_Function_TestFunc_Base" + * } + */ +@IC_ItemType_Function_TestFunc_Base(const playerIndex) { + client_print_color(playerIndex, print_team_default, "@IC_ItemType_Function_TestFunc_Base(%n)", playerIndex); +} + +/** + * { + * "Item": "Function", + * "Plugin": "ItemsController.amxx", + * "Function": "@IC_ItemType_Function_TestFunc_Value", + * "Value": 123 + * } + */ +@IC_ItemType_Function_TestFunc_Value(const playerIndex, const value) { + client_print_color(playerIndex, print_team_default, "@IC_ItemType_Function_TestFunc_Value(%n, %d)", playerIndex, value); +} + +/** + * { + * "Item": "Function", + * "Plugin": "ItemsController.amxx", + * "Function": "@IC_ItemType_Function_TestFunc_Flags", + * "Flags": "qwe" + * } + */ +@IC_ItemType_Function_TestFunc_Flags(const playerIndex, const flags[]) { + client_print_color(playerIndex, print_team_default, "@IC_ItemType_Function_TestFunc_Flags(%n, %s)", playerIndex, flags); +} + +/** + * { + * "Item": "Function", + * "Plugin": "ItemsController.amxx", + * "Function": "@IC_ItemType_Function_TestFunc_FlagsDays", + * "Flags": "qwe", + * "Days": 321 + * } + */ +@IC_ItemType_Function_TestFunc_FlagsDays(const playerIndex, const flags[], const days) { + client_print_color(playerIndex, print_team_default, "@IC_ItemType_Function_TestFunc_FlagsDays(%n, %s, %d)", playerIndex, flags, days); +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Health.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Health.inc new file mode 100644 index 0000000..3b31ee9 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Health.inc @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +DefaultObjects_ItemType_Health_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Health", + .onGive = "@OnHealthGive" + ); + IC_ItemType_AddParams(type, + "Health", "Float", true, + "MaxHealth", "Float", false, + "SetHealth", "Boolean", false + ); +} + +@OnHealthGive(const playerIndex, const Trie:p) { + if (PCGet_Bool(p, "SetHealth", false)) { + set_entvar(playerIndex, var_health, PCGet_Float(p, "Health")); + } else { + new Float:fHealth = Float:get_entvar(playerIndex, var_health); + new Float:fMaxHealth = PCGet_Float(p, "MaxHealth", 100.0); + new Float:fAddHealth = floatclamp(PCGet_Float(p, "Health"), 0.0, floatmax(0.0, fMaxHealth - fHealth)); + new Float:fMaxHealthCurrent = Float:get_entvar(playerIndex, var_max_health); + new bool:bNeedOverrideMaxHealth = (fHealth < fMaxHealth && fMaxHealthCurrent < fMaxHealth); + + if (bNeedOverrideMaxHealth) { + set_entvar(playerIndex, var_max_health, fMaxHealth); + } + + ExecuteHamB(Ham_TakeHealth, playerIndex, fAddHealth, DMG_GENERIC); + + if (bNeedOverrideMaxHealth) { + set_entvar(playerIndex, var_max_health, fMaxHealthCurrent); + } + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/If.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/If.inc new file mode 100644 index 0000000..845b56c --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/If.inc @@ -0,0 +1,41 @@ +#include +#include +#include +#include +#include +#include + +static bool:IsVipModularInstalled = true; + +DefaultObjects_ItemType_If_Register() { + if (!IsVipModularInstalled) { + return; + } + + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "If", + .onGive = "@OnIfGive" + ); + IC_ItemType_AddParams(type, + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, true, + "Items", IC_PARAM_TYPE_ITEMS_NAME, false, + "ElseItems", IC_PARAM_TYPE_ITEMS_NAME, false + ); +} + +@OnIfGive(const playerIndex, const Trie:p) { + if (!PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND)) { + return PCGet_IcItemsGive(p, "ElseItems", playerIndex) ? IC_RET_GIVE_SUCCESS : IC_RET_GIVE_FAIL; + } + + return PCGet_IcItemsGive(p, "Items", playerIndex) ? IC_RET_GIVE_SUCCESS : IC_RET_GIVE_FAIL; +} + +bool:DefaultObjects_ItemType_If_NativeFilter(const name[], const trap) { + if (equal(name, "VipM_Limits_ExecuteList")) { + IsVipModularInstalled = !!trap; + return true; + } + + return false; +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/InstantReload.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/InstantReload.inc new file mode 100644 index 0000000..5b52689 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/InstantReload.inc @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_InstantReload_Register() { + IC_ItemType_SimpleRegister( + .name = "InstantReload", + .onGive = "@OnInstantReloadGive" + ); +} + +@OnInstantReloadGive(const playerIndex, const Trie:p) { + InstantReloadActiveWeapon(playerIndex); +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/InstantReloadAllWeapons.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/InstantReloadAllWeapons.inc new file mode 100644 index 0000000..f7ebd10 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/InstantReloadAllWeapons.inc @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_InstantReloadAllWeapons_Register() { + IC_ItemType_SimpleRegister( + .name = "InstantReloadAllWeapons", + .onGive = "@OnInstantReloadAllWeaponsGive" + ); +} + +@OnInstantReloadAllWeaponsGive(const playerIndex, const Trie:p) { + InstantReloadAllWeapons(playerIndex); +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/ItemsList.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/ItemsList.inc new file mode 100644 index 0000000..5ee1cd8 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/ItemsList.inc @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_ItemsList_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "ItemsList", + .onGive = "@OnItemsListGive" + ); + IC_ItemType_AddParams(type, + "Items", IC_PARAM_TYPE_ITEMS_NAME, true + ); +} + +@OnItemsListGive(const playerIndex, const Trie:p) { + return PCGet_IcItemsGive(p, "Items", playerIndex) ? IC_RET_GIVE_SUCCESS : IC_RET_GIVE_FAIL; +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Money.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Money.inc new file mode 100644 index 0000000..cab2243 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Money.inc @@ -0,0 +1,50 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_Money_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Money", + .onRead = "@OnMoneyRead", + .onGive = "@OnMoneyGive" + ); + IC_ItemType_AddParams(type, + "Amount", "Integer", true, + "TrackChange", "Boolean", false + ); +} + +@OnMoneyRead(const JSON:instanceJson, const Trie:p) { + if (json_object_has_value(instanceJson, "GiveType", JSONString)) { + new sBuffer[32]; + json_object_get_string(instanceJson, "GiveType", sBuffer, charsmax(sBuffer)); + new accountSet = ItemType_Money_StrToAccountSet(sBuffer); + if (accountSet < 0) { + PCJson_LogForFile(instanceJson, "ERROR", "Invalid `GiveType` value (%s). Expected `Set` or `Add`.", sBuffer); + } else { + TrieSetCell(p, "GiveType", accountSet); + } + } + + return IC_RET_READ_SUCCESS; +} + +@OnMoneyGive(const playerIndex, const Trie:p) { + rg_add_account( + playerIndex, + PCGet_Int(p, "Amount"), + PCGet_Cell(p, "GiveType", AS_ADD), + PCGet_Bool(p, "TrackChanges", true) + ); +} + +static ItemType_Money_StrToAccountSet(const Str[]) { + if (equali(Str, "Set")) { + return _:AS_SET; + } else if (equali(Str, "Add")) { + return _:AS_ADD; + } else { + return -1; + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Random.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Random.inc new file mode 100644 index 0000000..74e5f85 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Random.inc @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_Random_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Random", + .onGive = "@OnRandomGive" + ); + IC_ItemType_AddParams(type, + "Items", IC_PARAM_TYPE_ITEMS_NAME, true + ); +} + +@OnRandomGive(const playerIndex, const Trie:p) { + new Array:items = PCGet_IcItems(p, "Items"); + new iRandomIndex = random_num(0, ArraySizeSafe(items) - 1); + new T_IC_Item:iRandomItem = ArrayGetCell(items, iRandomIndex); + + return IC_Item_Give(playerIndex, iRandomItem) ? IC_RET_GIVE_SUCCESS : IC_RET_GIVE_FAIL; +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/RefillBpAmmo.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/RefillBpAmmo.inc new file mode 100644 index 0000000..41796d5 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/RefillBpAmmo.inc @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_RefillBpAmmo_Register() { + IC_ItemType_SimpleRegister( + .name = "RefillBpAmmo", + .onGive = "@OnRefillBpAmmoGive" + ); +} + +@OnRefillBpAmmoGive(const playerIndex, const Trie:p) { + new iMaxAmmos[32] = {-1, ...}; + + // Получение дефолтных значений + for (new WeaponIdType:iWpnId = WEAPON_P228; iWpnId < WEAPON_P90; iWpnId++) { + switch (iWpnId) { + case WEAPON_KNIFE, WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_FLASHBANG, WEAPON_SHIELDGUN: + iMaxAmmos[rg_get_weapon_info(iWpnId, WI_AMMO_TYPE)] = -1; + default: + iMaxAmmos[rg_get_weapon_info(iWpnId, WI_AMMO_TYPE)] = rg_get_weapon_info(iWpnId, WI_MAX_ROUNDS); + } + } + + // Получение актуальных значений исходя из пушек в инвентаре + for (new InventorySlotType:iSlot = PRIMARY_WEAPON_SLOT; iSlot <= PISTOL_SLOT; iSlot++) { + new ItemId = get_member(playerIndex, m_rgpPlayerItems, iSlot); + while (ItemId > 0 && !is_nullent(ItemId)) { + new iAmmoType = get_member(ItemId, m_Weapon_iPrimaryAmmoType); + if (iAmmoType >= 0) { + iMaxAmmos[iAmmoType] = max(iMaxAmmos[iAmmoType], rg_get_iteminfo(ItemId, ItemInfo_iMaxAmmo1)); + } + ItemId = get_member(ItemId, m_pNext); + } + } + + for (new iAmmoType = 0; iAmmoType < 32; iAmmoType++) { + if (iMaxAmmos[iAmmoType] >= 0) { + set_member(playerIndex, m_rgAmmo, iMaxAmmos[iAmmoType], iAmmoType); + } + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Speed.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Speed.inc new file mode 100644 index 0000000..8747288 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Speed.inc @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +static Float:PlayerSpeedMult[MAX_PLAYERS + 1] = {1.0, ...}; + +DefaultObjects_ItemType_Speed_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Speed", + .onGive = "@ItemType_Speed_OnGive" + ); + IC_ItemType_AddParams(type, + "Multiplier", "Float", true + ); + + RegisterHookChain(RG_CBasePlayer_ResetMaxSpeed, "@ItemType_Speed_OnPlayerResetSpeedPost", true); + RegisterHookChain(RG_CBasePlayer_Spawn, "@ItemType_Speed_OnPlayerSpawnPre", false); +} + +@ItemType_Speed_OnGive(const playerIndex, const Trie:p) { + PlayerSpeedMult[playerIndex] = PCGet_Float(p, "Multiplier", 1.0); + ItemType_Speed_MultUserSpeed(playerIndex, PlayerSpeedMult[playerIndex]); +} + +@ItemType_Speed_OnPlayerSpawnPre(const playerIndex) { + PlayerSpeedMult[playerIndex] = 1.0; +} + +@ItemType_Speed_OnPlayerResetSpeedPost(const playerIndex) { + ItemType_Speed_MultUserSpeed(playerIndex, PlayerSpeedMult[playerIndex]); +} + +static ItemType_Speed_MultUserSpeed(const playerIndex, const Float:mult) { + if (mult != 1.0) { + set_entvar(playerIndex, var_maxspeed, Float:get_entvar(playerIndex, var_maxspeed) * mult); + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Weapon.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Weapon.inc new file mode 100644 index 0000000..6ec4503 --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ItemType/Weapon.inc @@ -0,0 +1,81 @@ +#include +#include +#include +#include + +DefaultObjects_ItemType_Weapon_Register() { + new T_IC_ItemType:type = IC_ItemType_SimpleRegister( + .name = "Weapon", + .onRead = "@OnWeaponRead", + .onGive = "@OnWeaponGive" + ); + IC_ItemType_AddParams(type, + "Name", "String", true, + "BpAmmo", "Integer", false + ); +} + +@OnWeaponRead(const JSON:instanceJson, const Trie:p) { + TrieSetCell(p, "GiveType", _:Json_Object_GetGiveType(instanceJson, "GiveType")); + + return IC_RET_READ_SUCCESS; +} + +@OnWeaponGive(const playerIndex, const Trie:p) { + static WeaponName[32]; + PCGet_Str(p, "Name", WeaponName, charsmax(WeaponName)); + if (!WeaponName[0]) { + return IC_RET_GIVE_FAIL; + } + + if (!get_weaponid(WeaponName)) { + log_amx("[WARNING] Default weapon `%s` not found.", WeaponName); + return IC_RET_GIVE_FAIL; + } + + new GiveType:iGiveType = GiveType:PCGet_Int(p, "GiveType", _:GT_DROP_AND_REPLACE); + new iBpAmmo = PCGet_Int(p, "BpAmmo", -1); + + new ItemId = rg_give_item(playerIndex, WeaponName, iGiveType); + if (ItemId < 0) { + return IC_RET_GIVE_FAIL; + } + + new WeaponIdType:iWpnId = rg_get_weapon_info(WeaponName, WI_ID); + new iWpnSlot = rg_get_iteminfo(ItemId, ItemInfo_iSlot); + + if ( + iBpAmmo < 0 + && !( + iWpnSlot == 0 + || iWpnSlot == 1 + ) + ) { + return IC_RET_GIVE_SUCCESS; + } + + new def_BpAmmo = (rg_get_weapon_info(iWpnId, WI_MAX_ROUNDS)); + if (def_BpAmmo >= 0) { + rg_set_user_bpammo(playerIndex, iWpnId, iBpAmmo < 0 ? def_BpAmmo : iBpAmmo); + } + + return IC_RET_GIVE_SUCCESS; +} + +GiveType:Json_Object_GetGiveType(const JSON:Obj, const Key[], const bool:DotNot = false) { + new Str[32]; + json_object_get_string(Obj, Key, Str, charsmax(Str), DotNot); + return ItemType_Weapon_StrToGiveType(Str); +} + +GiveType:ItemType_Weapon_StrToGiveType(const Str[]) { + if (equali(Str, "GT_APPEND") || equali(Str, "Append") || equali(Str, "Add")) { + return GT_APPEND; + } else if (equali(Str, "GT_REPLACE") || equali(Str, "Replace")) { + return GT_REPLACE; + } else if (equali(Str, "GT_DROP_AND_REPLACE") || equali(Str, "Drop") || equali(Str, "DropAndReplace")) { + return GT_DROP_AND_REPLACE; + } else { + return GT_DROP_AND_REPLACE; + } +} diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ParamType/Item.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ParamType/Item.inc new file mode 100644 index 0000000..ab1b3bf --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ParamType/Item.inc @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +DefaultObjects_ParamType_Item_Register() { + ParamsController_RegSimpleType(IC_PARAM_TYPE_ITEM_NAME, "@OnItemParamTypeRead"); +} + +bool:@OnItemParamTypeRead(const JSON:valueJson) { + new T_IC_Item:item = IC_Item_ReadFromJson(valueJson); + + if (item == Invalid_IC_Item) { + return false; + } + + return ParamsController_SetCell(item); +} \ No newline at end of file diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/ParamType/Items.inc b/amxmodx/scripting/ItemsController/DefaultObjects/ParamType/Items.inc new file mode 100644 index 0000000..f20a23b --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/ParamType/Items.inc @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +DefaultObjects_ParamType_Items_Register() { + ParamsController_RegSimpleType(IC_PARAM_TYPE_ITEMS_NAME, "@OnItemsParamTypeRead"); +} + +@OnItemsParamTypeRead(const JSON:valueJson) { + new Array:items = IC_Item_ReadArrayFromJson(valueJson); + + if (items == Invalid_Array) { + return false; + } + + if ( + ( + json_is_object(valueJson) + || (json_is_array(valueJson) && json_array_get_count(valueJson) == 0) + ) && ArraySize(items) < 1 + ) { + PCJson_LogForFile(valueJson, "WARNING", "All items are invalid."); + return false; + } + + return ParamsController_SetCell(items); +} \ No newline at end of file diff --git a/amxmodx/scripting/ItemsController/DefaultObjects/Registrar.inc b/amxmodx/scripting/ItemsController/DefaultObjects/Registrar.inc new file mode 100644 index 0000000..dc4520b --- /dev/null +++ b/amxmodx/scripting/ItemsController/DefaultObjects/Registrar.inc @@ -0,0 +1,62 @@ +#include + +DefaultObjects_HandleNativeFilter(const name[], const trap) { + new handled = false; + + if (DefaultObjects_ItemType_CustomWeapon_NativeFilter(name, trap)) { + handled = true; + } + + if (DefaultObjects_ItemType_If_NativeFilter(name, trap)) { + handled = true; + } + + return handled; +} + +#include "ItemsController/DefaultObjects/ItemType/Armor" +#include "ItemsController/DefaultObjects/ItemType/Command" +#include "ItemsController/DefaultObjects/ItemType/DamageMult" +#include "ItemsController/DefaultObjects/ItemType/DefuseKit" +#include "ItemsController/DefaultObjects/ItemType/Health" +#include "ItemsController/DefaultObjects/ItemType/InstantReload" +#include "ItemsController/DefaultObjects/ItemType/InstantReloadAllWeapons" +#include "ItemsController/DefaultObjects/ItemType/ItemsList" +#include "ItemsController/DefaultObjects/ItemType/Money" +#include "ItemsController/DefaultObjects/ItemType/Random" +#include "ItemsController/DefaultObjects/ItemType/RefillBpAmmo" +#include "ItemsController/DefaultObjects/ItemType/Speed" +#include "ItemsController/DefaultObjects/ItemType/Weapon" +#include "ItemsController/DefaultObjects/ItemType/CustomWeapon" +#include "ItemsController/DefaultObjects/ItemType/Function" +#include "ItemsController/DefaultObjects/ItemType/If" + +public IC_ItemType_OnInited() { + // Затычка для тех мест, где при отсутствии предметов вылезает ошибка/варн + IC_ItemType_SimpleRegister(.name = "None"); + + DefaultObjects_ItemType_Armor_Register(); + DefaultObjects_ItemType_Command_Register(); + DefaultObjects_ItemType_DamageMult_Register(); + DefaultObjects_ItemType_DefuseKit_Register(); + DefaultObjects_ItemType_Health_Register(); + DefaultObjects_ItemType_InstantReload_Register(); + DefaultObjects_ItemType_InstantReloadAllWeapons_Register(); + DefaultObjects_ItemType_ItemsList_Register(); + DefaultObjects_ItemType_Money_Register(); + DefaultObjects_ItemType_Random_Register(); + DefaultObjects_ItemType_RefillBpAmmo_Register(); + DefaultObjects_ItemType_Speed_Register(); + DefaultObjects_ItemType_Weapon_Register(); + DefaultObjects_ItemType_CustomWeapon_Register(); + DefaultObjects_ItemType_Function_Register(); + DefaultObjects_ItemType_If_Register(); +} + +#include "ItemsController/DefaultObjects/ParamType/Item" +#include "ItemsController/DefaultObjects/ParamType/Items" + +public ParamsController_OnRegisterTypes() { + DefaultObjects_ParamType_Item_Register(); + DefaultObjects_ParamType_Items_Register(); +} \ No newline at end of file diff --git a/amxmodx/scripting/ItemsController/Objects/Items/Instance.inc b/amxmodx/scripting/ItemsController/Objects/Items/Instance.inc new file mode 100644 index 0000000..483c47a --- /dev/null +++ b/amxmodx/scripting/ItemsController/Objects/Items/Instance.inc @@ -0,0 +1,167 @@ +#if defined __ic__objects__items_instance__included + #endinput +#endif +// Два кванта +#define __ic__objects__items_instance__included + +#include +#include +#include +#include "VipM/Forwards" +#include "VipM/Utils" + +#include "ItemsController/Objects/Items/Type" + +enum _:S_ItemInstance { + T_IC_ItemType:Item_Type, + Trie:Item_Params, +} + +static Array:ItemInstances = Invalid_Array; +static Stack:FreeItemInstanceHandlers = Invalid_Stack; +static ActiveItemInstancesCount = 0; + +ItemInstance_Init() { + CallOnce(); + log_amx("Init item instances..."); + + ItemType_Init(); + + ItemInstances = ArrayCreate(S_ItemInstance, 1); + FreeItemInstanceHandlers = CreateStack(); + ActiveItemInstancesCount = 0; + + Forwards_RegAndCall("IC_Item_OnInited", ET_IGNORE); + log_amx("Item instances inited."); +} + +T_IC_Item:ItemInstance_Construct(const T_IC_ItemType:type, const Trie:params) { + if (ItemInstances == Invalid_Array) { + abort(AMX_ERR_GENERAL, "Attempt to create item instance before items controller init."); + return Invalid_IC_Item; + } + + new instanceObject[S_ItemInstance]; + instanceObject[Item_Type] = type; + instanceObject[Item_Params] = params; + + ActiveItemInstancesCount++; + if (IsStackEmpty(FreeItemInstanceHandlers)) { + return T_IC_Item:ArrayPushArray(ItemInstances, instanceObject); + } else { + new freeInstanceHandler; + PopStackCell(FreeItemInstanceHandlers, freeInstanceHandler); + + ArraySetArray(ItemInstances, freeInstanceHandler, instanceObject); + return T_IC_Item:freeInstanceHandler; + } +} + +bool:ItemInstance_Get(const T_IC_Item:instance, instanceObject[S_ItemInstance], const bool:orFail = true) { + if (_:instance < 0 || _:instance >= ArraySize(ItemInstances)) { + if (orFail) { + abort(AMX_ERR_NOTFOUND, "Invalid item instance handler (%d, out of bounds).", instance); + } + return false; + } + + ArrayGetArray(ItemInstances, _:instance, instanceObject); + + if (instanceObject[Item_Type] == Invalid_IC_ItemType) { + if (orFail) { + abort(AMX_ERR_NOTFOUND, "Invalid item instance handler (%d, deleted).", instance); + } + return false; + } + + return true; +} + +bool:ItemInstance_Give(const playerIndex, const T_IC_Item:instance) { + new instanceObject[S_ItemInstance]; + ItemInstance_Get(instance, instanceObject); + + return ItemType_Give(playerIndex, instanceObject[Item_Type], instanceObject[Item_Params]); +} + +T_IC_Item:ItemInstance_Free(&T_IC_Item:instance, const bool:orFail = false) { + new instanceObject[S_ItemInstance]; + if (!ItemInstance_Get(instance, instanceObject, .orFail = orFail)) { + return instance = Invalid_IC_Item; + } + + instanceObject[Item_Type] = Invalid_IC_ItemType; + TrieDestroy(instanceObject[Item_Params]); // TODO: Надо что-то придумать на случай вложенных динамических штук + + ArraySetArray(ItemInstances, _:instance, instanceObject); + PushStackCell(FreeItemInstanceHandlers, instance); + + ActiveItemInstancesCount--; + return instance = Invalid_IC_Item; +} + +T_IC_Item:ItemInstance_ReadFromJsonObject(const JSON:instanceJson) { + if (!json_is_object(instanceJson)) { + PCJson_ErrorForFile(instanceJson, "Invalid item object (json value is not an object)."); + return Invalid_IC_Item; + } + + new typeName[IC_ITEM_TYPE_NAME_MAX_LEN]; + if (json_object_has_value(instanceJson, "Item", JSONString)) { + json_object_get_string(instanceJson, "Item", typeName, charsmax(typeName)); + } else if (json_object_has_value(instanceJson, "Type", JSONString)) { + PCJson_LogForFile(instanceJson, "WARNING", "Item object with field `Type` is deprecated, use `Item` field instead."); + json_object_get_string(instanceJson, "Type", typeName, charsmax(typeName)); + } else { + PCJson_ErrorForFile(instanceJson, "Invalid item object (must contains `Item` field)."); + return Invalid_IC_Item; + } + + trim(typeName); + if (!typeName[0]) { + PCJson_ErrorForFile(instanceJson, "Item type is empty."); + return Invalid_IC_Item; + } + + new T_IC_ItemType:type = ItemType_Find(typeName); + if (type == Invalid_IC_ItemType) { + PCJson_ErrorForFile(instanceJson, "Item type '%s' not found.", typeName); + return Invalid_IC_Item; + } + + new Trie:params = TrieCreate(); + if (!ItemType_ReadParamsFromJsonObject(type, instanceJson, params)) { + TrieDestroy(params); + return Invalid_IC_Item; + } + + return ItemInstance_Construct(type, params); +} + +Array:ItemInstance_ReadArrayFromJsonValue(const JSON:instancesJson, &Array:array = Invalid_Array) { + if (array == Invalid_Array) { + array = ArrayCreate(1, 1); + } + + new JSON:linkedJson; + PCJson_HandleLinkedValue(instancesJson, linkedJson); + + if (json_is_array(linkedJson)) { + for (new i = 0, ii = json_array_get_count(linkedJson); i < ii; i++) { + new JSON:instanceJson = json_array_get_value(linkedJson, i); + ItemInstance_ReadArrayFromJsonValue(instanceJson, array); + json_free(instanceJson); + } + } else if (json_is_object(linkedJson)) { + new T_IC_Item:instance = ItemInstance_ReadFromJsonObject(linkedJson); + if (instance != Invalid_IC_Item) { + ArrayPushCell(array, instance); + } + } else { + PCJson_ErrorForFile(linkedJson, "Json value must be an array or an object."); + } + + PCJson_FreeLinked(linkedJson, instancesJson); + + return array; +} diff --git a/amxmodx/scripting/ItemsController/Objects/Items/Type.inc b/amxmodx/scripting/ItemsController/Objects/Items/Type.inc new file mode 100644 index 0000000..7465ce6 --- /dev/null +++ b/amxmodx/scripting/ItemsController/Objects/Items/Type.inc @@ -0,0 +1,169 @@ +#if defined __ic__objects__items_type__included + #endinput +#endif +#define __ic__objects__items_type__included + +#include +#include +#include "VipM/Forwards" +#include "VipM/Utils" + +enum _:S_ItemType { + ItemType_Name[IC_ITEM_TYPE_NAME_MAX_LEN], + ItemType_Events[E_ItemTypeEvent], + Array:ItemType_Params, +} + +static Array:ItemTypes = Invalid_Array; +static Trie:ItemTypesMap = Invalid_Trie; + +ItemType_Init() { + CallOnce(); + log_amx("Init item types..."); + + ItemTypes = ArrayCreate(S_ItemType, 1); + ItemTypesMap = TrieCreate(); + + Forwards_RegAndCall("IC_ItemType_OnInited", ET_IGNORE); + log_amx("Item types inited."); +} + +T_IC_ItemType:ItemType_Construct(const name[]) { + if (ItemTypes == Invalid_Array) { + abort(AMX_ERR_GENERAL, "Attempt to create item type before items controller init."); + return Invalid_IC_ItemType; + } + + if (ItemType_Find(name) != Invalid_IC_ItemType) { + abort(AMX_ERR_PARAMS, "Item type '%s' already exists.", name); + return Invalid_IC_ItemType; + } + + new typeObject[S_ItemType]; + copy(typeObject[ItemType_Name], charsmax(typeObject[ItemType_Name]), name); + arrayset(typeObject[ItemType_Events], INVALID_HANDLE, sizeof(typeObject[ItemType_Events])); + typeObject[ItemType_Params] = ArrayCreate(1, 1); + + new T_IC_ItemType:type = T_IC_ItemType:ArrayPushArray(ItemTypes, typeObject); + TrieSetCell(ItemTypesMap, typeObject[ItemType_Name], type); + + log_amx("Item type '%s' registered.", typeObject[ItemType_Name]); + + return type; +} + +T_IC_ItemType:ItemType_UpdateObject(const typeObject[S_ItemType]) { + new T_IC_ItemType:type = ItemType_Find(typeObject[ItemType_Name], .orFail = true); + ArraySetArray(ItemTypes, _:type, typeObject); + return type; +} + +T_IC_ItemType:ItemType_Find(const name[], const bool:orFail = false) { + new T_IC_ItemType:type = Invalid_IC_ItemType; + TrieGetCell(ItemTypesMap, name, type); + + if (orFail && type == Invalid_IC_ItemType) { + abort(AMX_ERR_NOTFOUND, "Invalid item type '%s'.", name); + } + + return type; +} + +bool:ItemType_Get(const T_IC_ItemType:type, typeObject[S_ItemType], const bool:orFail = true) { + if (_:type < 0 || _:type >= ArraySize(ItemTypes)) { + if (orFail) { + abort(AMX_ERR_NOTFOUND, "Invalid item type handler (%d, out of bounds).", type); + } + return false; + } + + ArrayGetArray(ItemTypes, _:type, typeObject); + return true; +} + +ItemType_SetEventListener(const T_IC_ItemType:type, const E_ItemTypeEvent:event, const listener) { + new typeObject[S_ItemType]; + ItemType_Get(type, typeObject); + + if (typeObject[ItemType_Events][event] >= 0) { + abort(AMX_ERR_GENERAL, "Item type '%s' already has listener for event #%d.", typeObject[ItemType_Name], event); + return; + } + + typeObject[ItemType_Events][event] = listener; + ItemType_UpdateObject(typeObject); +} + +ItemType_MakeEventListener(const E_ItemTypeEvent:event, const pluginIndex, const functionName[]) { + new listener = INVALID_HANDLE; + switch (event) { + case ItemType_OnRead: // IC_RET_READ_*:(const JSON:itemJson, Trie:params) + listener = CreateOneForward(pluginIndex, functionName, FP_CELL, FP_CELL); + + case ItemType_OnGive: // IC_RET_GIVE_*:(const playerIndex, const Trie:params) + listener = CreateOneForward(pluginIndex, functionName, FP_CELL, FP_CELL); + } + + if (listener == INVALID_HANDLE) { + abort(AMX_ERR_PARAMS, "Can't create forward for func '%s' in plugin #%d.", functionName, pluginIndex); + } + + return listener; +} + +ItemType_AddParams(const T_IC_ItemType:type, const Array:params) { + new typeObject[S_ItemType]; + ItemType_Get(type, typeObject); + + for (new i = 0, ii = ArraySize(params); i < ii; ++i) { + ArrayPushCell(typeObject[ItemType_Params], ArrayGetCell(params, i)); + } +} + +bool:ItemType_Give(const playerIndex, const T_IC_ItemType:type, const Trie:params) { + new typeObject[S_ItemType]; + ItemType_Get(type, typeObject); + + if (typeObject[ItemType_Events][ItemType_OnGive] == INVALID_HANDLE) { + return true; + } + + new ret = IC_RET_GIVE_FAIL; + ExecuteForward(typeObject[ItemType_Events][ItemType_OnGive], ret, playerIndex, params); + + return ret == IC_RET_GIVE_SUCCESS; +} + +bool:ItemType_ReadParamsFromJsonObject(const T_IC_ItemType:type, const JSON:paramsJson, &Trie:params) { + new typeObject[S_ItemType]; + ItemType_Get(type, typeObject); + + new errField[PARAM_KEY_MAX_LEN], E_ParamsReadErrorType:errType; + ParamsController_Param_ReadList(typeObject[ItemType_Params], paramsJson, params, errType, errField, charsmax(errField)); + if (errType != ParamsReadError_None) { + switch (errType) { + case ParamsReadError_RequiredParamNotPresented: + PCJson_ErrorForFile(paramsJson, "Param '%s' is required for item type '%s'.", errField, typeObject[ItemType_Name]); + case ParamsReadError_ParamValueIsInvalid: + PCJson_ErrorForFile(paramsJson, "Param '%s' has invalid value.", errField); + } + return false; + } + + // deprecated + if (!TrieKeyExists(params, "Name")) { + new nameParam[256]; + json_object_get_string(paramsJson, "Name", nameParam, charsmax(nameParam)); + TrieSetString(params, "Name", nameParam); + } + + // deprecated? + if (typeObject[ItemType_Events][ItemType_OnRead] != INVALID_HANDLE) { + new ret = IC_RET_READ_SUCCESS; + ExecuteForward(typeObject[ItemType_Events][ItemType_OnRead], ret, paramsJson, params); + + return ret == IC_RET_READ_SUCCESS; + } + + return true; +} \ No newline at end of file diff --git a/amxmodx/scripting/VipM-I-Default.sma b/amxmodx/scripting/VipM-I-Default.sma deleted file mode 100644 index 3f53d3e..0000000 --- a/amxmodx/scripting/VipM-I-Default.sma +++ /dev/null @@ -1,497 +0,0 @@ -#include -#include -#include -#include -#include -#include "VipM/Utils" -#include "VipM/DebugMode" - -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM][I] Default"; -public stock const PluginVersion[] = _VIPM_VERSION; -public stock const PluginAuthor[] = "ArKaNeMaN"; -public stock const PluginURL[] = _VIPM_PLUGIN_URL; -public stock const PluginDescription[] = "[VipModular][Item] Default items."; - -new Float:g_fSpeedMult[MAX_PLAYERS + 1] = {1.0, ...}; -new Float:g_fGivenDmgMult[MAX_PLAYERS + 1] = {1.0, ...}; -new Float:g_fTakenDmgMult[MAX_PLAYERS + 1] = {1.0, ...}; - -new HookChain:g_iHook_ResetMaxSpeed_Post = INVALID_HOOKCHAIN; -new HookChain:g_iHook_TakeDamage_Pre = INVALID_HOOKCHAIN; -new HookChain:g_iHook_Spawn_Pre = INVALID_HOOKCHAIN; - -public VipM_IC_OnInitTypes() { - RegisterPluginByVars(); - - // Затычка для тех мест, где при отсутствии предметов вылезает ошибка/варн - VipM_IC_RegisterType("None"); - - VipM_IC_RegisterType("Random"); - VipM_IC_RegisterTypeEvent("Random", ItemType_OnRead, "@OnRandomRead"); - VipM_IC_RegisterTypeEvent("Random", ItemType_OnGive, "@OnRandomGive"); - - VipM_IC_RegisterType("InstantReloadAllWeapons"); - VipM_IC_RegisterTypeEvent("InstantReloadAllWeapons", ItemType_OnGive, "@OnInstantReloadAllWeaponsGive"); - - VipM_IC_RegisterType("InstantReload"); - VipM_IC_RegisterTypeEvent("InstantReload", ItemType_OnGive, "@OnInstantReloadGive"); - - VipM_IC_RegisterType("RefillBpAmmo"); - VipM_IC_RegisterTypeEvent("RefillBpAmmo", ItemType_OnGive, "@OnRefillBpAmmoGive"); - - VipM_IC_RegisterType("Speed"); - VipM_IC_RegisterTypeEvent("Speed", ItemType_OnRead, "@OnSpeedRead"); - VipM_IC_RegisterTypeEvent("Speed", ItemType_OnGive, "@OnSpeedGive"); - - VipM_IC_RegisterType("Money"); - VipM_IC_RegisterTypeEvent("Money", ItemType_OnRead, "@OnMoneyRead"); - VipM_IC_RegisterTypeEvent("Money", ItemType_OnGive, "@OnMoneyGive"); - - VipM_IC_RegisterType("Weapon"); - VipM_IC_RegisterTypeEvent("Weapon", ItemType_OnRead, "@OnWeaponRead"); - VipM_IC_RegisterTypeEvent("Weapon", ItemType_OnGive, "@OnWeaponGive"); - - VipM_IC_RegisterType("ItemsList"); - VipM_IC_RegisterTypeEvent("ItemsList", ItemType_OnRead, "@OnItemsListRead"); - VipM_IC_RegisterTypeEvent("ItemsList", ItemType_OnGive, "@OnItemsListGive"); - - VipM_IC_RegisterType("Command"); - VipM_IC_RegisterTypeEvent("Command", ItemType_OnRead, "@OnCommandRead"); - VipM_IC_RegisterTypeEvent("Command", ItemType_OnGive, "@OnCommandGive"); - - VipM_IC_RegisterType("DefuseKit"); - VipM_IC_RegisterTypeEvent("DefuseKit", ItemType_OnGive, "@OnDefuseKitGive"); - - VipM_IC_RegisterType("Health"); - VipM_IC_RegisterTypeEvent("Health", ItemType_OnRead, "@OnHealthRead"); - VipM_IC_RegisterTypeEvent("Health", ItemType_OnGive, "@OnHealthGive"); - - VipM_IC_RegisterType("DamageMult"); - VipM_IC_RegisterTypeEvent("DamageMult", ItemType_OnRead, "@OnDamageMultRead"); - VipM_IC_RegisterTypeEvent("DamageMult", ItemType_OnGive, "@OnDamageMultGive"); - - VipM_IC_RegisterType("Armor"); - VipM_IC_RegisterTypeEvent("Armor", ItemType_OnRead, "@OnArmorRead"); - VipM_IC_RegisterTypeEvent("Armor", ItemType_OnGive, "@OnArmorGive"); - - DisableHookChain(g_iHook_ResetMaxSpeed_Post = RegisterHookChain(RG_CBasePlayer_ResetMaxSpeed, "@OnPlayerResetSpeedPost", true)); - DisableHookChain(g_iHook_Spawn_Pre = RegisterHookChain(RG_CBasePlayer_Spawn, "@OnPlayerSpawnPre", false)); - DisableHookChain(g_iHook_TakeDamage_Pre = RegisterHookChain(RG_CBasePlayer_TakeDamage, "@OnPlayerTakeDamage", false)); -} - -@OnPlayerSpawnPre(const UserId) { - g_fSpeedMult[UserId] = 1.0; - g_fGivenDmgMult[UserId] = 1.0; - g_fTakenDmgMult[UserId] = 1.0; -} - -@OnPlayerResetSpeedPost(const UserId) { - if (g_fSpeedMult[UserId] != 1.0) { - MultUserSpeed(UserId, g_fSpeedMult[UserId]); - } -} - -@OnPlayerTakeDamage(const VictimId, InflictorId, AttackerId, Float:fDamage, bitsDamageType) { - if (is_user_connected(AttackerId)) { - fDamage *= g_fGivenDmgMult[AttackerId]; - } - - if (is_user_connected(VictimId)) { - fDamage *= g_fTakenDmgMult[VictimId]; - } - - SetHookChainArg(4, ATYPE_FLOAT, fDamage); - return HC_CONTINUE; -} - -@OnDamageMultRead(const JSON:jItem, const Trie:tParams) { - TrieDeleteKey(tParams, "Name"); - - if (json_object_has_value(jItem, "Given", JSONNumber)) { - TrieSetCell(tParams, "Given", json_object_get_real(jItem, "Given")); - } - - if (json_object_has_value(jItem, "Taken", JSONNumber)) { - TrieSetCell(tParams, "Taken", json_object_get_real(jItem, "Taken")); - } - - CallOnceR(VIPM_CONTINUE); // Чтобы лишний раз не дёргать натив активации хука - - EnableHookChain(g_iHook_Spawn_Pre); - EnableHookChain(g_iHook_TakeDamage_Pre); - - return VIPM_CONTINUE; -} - -@OnDamageMultGive(const UserId, const Trie:tParams) { - g_fGivenDmgMult[UserId] = VipM_Params_GetFloat(tParams, "Given", 1.0); - g_fTakenDmgMult[UserId] = VipM_Params_GetFloat(tParams, "Taken", 1.0); -} - -@OnHealthRead(const JSON:jItem, const Trie:tParams) { - TrieDeleteKey(tParams, "Name"); - - if (!json_object_has_value(jItem, "Health", JSONNumber)) { - Json_LogForFile(jItem, "ERROR", "Param `Health` required for `Health` item."); - return VIPM_STOP; - } - TrieSetCell(tParams, "Health", json_object_get_real(jItem, "Health")); - - if (json_object_has_value(jItem, "MaxHealth", JSONNumber)) { - TrieSetCell(tParams, "MaxHealth", json_object_get_real(jItem, "MaxHealth")); - } - - if (json_object_has_value(jItem, "SetHealth", JSONBoolean)) { - TrieSetCell(tParams, "SetHealth", json_object_get_bool(jItem, "SetHealth")); - } - - return VIPM_CONTINUE; -} - -@OnHealthGive(const UserId, const Trie:tParams) { - if (VipM_Params_GetBool(tParams, "SetHealth", false)) { - set_entvar(UserId, var_health, VipM_Params_GetFloat(tParams, "Health")); - } else { - new Float:fHealth = Float:get_entvar(UserId, var_health); - new Float:fMaxHealth = VipM_Params_GetFloat(tParams, "MaxHealth", 100.0); - new Float:fAddHealth = floatclamp(VipM_Params_GetFloat(tParams, "Health"), 0.0, floatmax(0.0, fMaxHealth - fHealth)); - new Float:fMaxHealthCurrent = Float:get_entvar(UserId, var_max_health); - new bool:bNeedOverrideMaxHealth = (fHealth < fMaxHealth && fMaxHealthCurrent < fMaxHealth); - - if (bNeedOverrideMaxHealth) { - set_entvar(UserId, var_max_health, fMaxHealth); - } - - ExecuteHamB(Ham_TakeHealth, UserId, fAddHealth, DMG_GENERIC); - - if (bNeedOverrideMaxHealth) { - set_entvar(UserId, var_max_health, fMaxHealthCurrent); - } - } -} - -@OnArmorRead(const JSON:jItem, const Trie:tParams) { - TrieDeleteKey(tParams, "Name"); - - if (!json_object_has_value(jItem, "Armor", JSONNumber)) { - Json_LogForFile(jItem, "ERROR", "Param `Armor` required for `Armor` item."); - return VIPM_STOP; - } - TrieSetCell(tParams, "Armor", json_object_get_number(jItem, "Armor")); - - if (json_object_has_value(jItem, "MaxArmor", JSONNumber)) { - TrieSetCell(tParams, "MaxArmor", json_object_get_number(jItem, "MaxArmor")); - } - - if (json_object_has_value(jItem, "SetArmor", JSONBoolean)) { - TrieSetCell(tParams, "SetArmor", json_object_get_bool(jItem, "SetArmor")); - } - - if (json_object_has_value(jItem, "Helmet", JSONBoolean)) { - TrieSetCell(tParams, "Helmet", json_object_get_bool(jItem, "Helmet")); - } - - return VIPM_CONTINUE; -} - -@OnArmorGive(const UserId, const Trie:tParams) { - if (VipM_Params_GetBool(tParams, "SetArmor", false)) { - rg_set_user_armor(UserId, VipM_Params_GetInt(tParams, "Armor"), VipM_Params_GetBool(tParams, "Helmet", false) ? ARMOR_VESTHELM : ARMOR_KEVLAR); - } else { - new iSetArmor = min(rg_get_user_armor(UserId) + VipM_Params_GetInt(tParams, "Armor"), VipM_Params_GetInt(tParams, "MaxArmor", 100)); - - rg_set_user_armor(UserId, iSetArmor, VipM_Params_GetBool(tParams, "Helmet", false) ? ARMOR_VESTHELM : ARMOR_KEVLAR); - } -} - -@OnRandomRead(const JSON:jItem, const Trie:tParams) { - TrieDeleteKey(tParams, "Name"); - - // TODO: Сделать как-то разные шансы - if (!json_object_has_value(jItem, "Items")) { - Json_LogForFile(jItem, "ERROR", "Param `Items` required for item `Random`."); - return VIPM_STOP; - } - - new Array:aItems = VipM_IC_JsonGetItems(json_object_get_value(jItem, "Items")); - if (ArraySizeSafe(aItems) <= 1) { - Json_LogForFile(jItem, "ERROR", "Param `Items` must have >1 items."); - ArrayDestroy(aItems); - return VIPM_STOP; - } - - TrieSetCell(tParams, "Items", aItems); - - return VIPM_CONTINUE; -} - -@OnRandomGive(const UserId, const Trie:tParams) { - new Array:aItems = VipM_Params_GetArr(tParams, "Items"); - new iRandomIndex = random_num(0, ArraySizeSafe(aItems) - 1); - new VipM_IC_T_Item:iRandomItem = ArrayGetCell(aItems, iRandomIndex); - - return VipM_IC_GiveItem(UserId, iRandomItem) ? VIPM_CONTINUE : VIPM_STOP; -} - -@OnInstantReloadGive(const UserId, const Trie:Params) { - InstantReloadActiveWeapon(UserId); - - return VIPM_CONTINUE; -} - -@OnInstantReloadAllWeaponsGive(const UserId, const Trie:Params) { - InstantReloadAllWeapons(UserId); - - return VIPM_CONTINUE; -} - -@OnRefillBpAmmoGive(const UserId, const Trie:Params) { - new iMaxAmmos[32] = {-1, ...}; - - // Получение дефолтных значений - for (new WeaponIdType:iWpnId = WEAPON_P228; iWpnId < WEAPON_P90; iWpnId++) { - switch (iWpnId) { - case WEAPON_KNIFE, WEAPON_HEGRENADE, WEAPON_SMOKEGRENADE, WEAPON_FLASHBANG, WEAPON_SHIELDGUN: - iMaxAmmos[rg_get_weapon_info(iWpnId, WI_AMMO_TYPE)] = -1; - default: - iMaxAmmos[rg_get_weapon_info(iWpnId, WI_AMMO_TYPE)] = rg_get_weapon_info(iWpnId, WI_MAX_ROUNDS); - } - } - - // Получение актуальных значений исходя из пушек в инвентаре - for (new InventorySlotType:iSlot = PRIMARY_WEAPON_SLOT; iSlot <= PISTOL_SLOT; iSlot++) { - new ItemId = get_member(UserId, m_rgpPlayerItems, iSlot); - while (ItemId > 0 && !is_nullent(ItemId)) { - new iAmmoType = get_member(ItemId, m_Weapon_iPrimaryAmmoType); - if (iAmmoType >= 0) { - iMaxAmmos[iAmmoType] = max(iMaxAmmos[iAmmoType], rg_get_iteminfo(ItemId, ItemInfo_iMaxAmmo1)); - } - ItemId = get_member(ItemId, m_pNext); - } - } - - for (new iAmmoType = 0; iAmmoType < 32; iAmmoType++) { - if (iMaxAmmos[iAmmoType] >= 0) { - set_member(UserId, m_rgAmmo, iMaxAmmos[iAmmoType], iAmmoType); - } - } - - return VIPM_CONTINUE; -} - -@OnSpeedRead(const JSON:jItem, const Trie:Params) { - TrieDeleteKey(Params, "Name"); - - if (!json_object_has_value(jItem, "Multiplier", JSONNumber)) { - Json_LogForFile(jItem, "ERROR", "Param `Multiplier` required for item `Speed`."); - return VIPM_STOP; - } - TrieSetCell(Params, "Multiplier", json_object_get_real(jItem, "Multiplier")); - - CallOnceR(VIPM_CONTINUE); // Чтобы лишний раз не дёргать натив активации хука - - EnableHookChain(g_iHook_Spawn_Pre); - EnableHookChain(g_iHook_ResetMaxSpeed_Post); - - return VIPM_CONTINUE; -} - -@OnSpeedGive(const UserId, const Trie:Params) { - g_fSpeedMult[UserId] = VipM_Params_GetFloat(Params, "Multiplier", 1.0); - MultUserSpeed(UserId, g_fSpeedMult[UserId]); - - return VIPM_CONTINUE; -} - -@OnMoneyRead(const JSON:jItem, const Trie:Params) { - TrieDeleteKey(Params, "Name"); - - if (!json_object_has_value(jItem, "Amount", JSONNumber)) { - Json_LogForFile(jItem, "ERROR", "Param `Amount` required for item `Money`."); - return VIPM_STOP; - } - TrieSetCell(Params, "Amount", json_object_get_number(jItem, "Amount")); - - if (json_object_has_value(jItem, "GiveType", JSONString)) { - new sBuffer[32]; - json_object_get_string(jItem, "GiveType", sBuffer, charsmax(sBuffer)); - new accountSet = StrToAccountSet(sBuffer); - if (accountSet < 0) { - Json_LogForFile(jItem, "ERROR", "Invalid `GiveType` value (%s). Expected `Set` or `Add`.", sBuffer); - } else { - TrieSetCell(Params, "GiveType", accountSet); - } - } - - if (json_object_has_value(jItem, "TrackChange", JSONBoolean)) { - TrieSetCell(Params, "TrackChange", json_object_get_bool(jItem, "TrackChange")); - } - - return VIPM_CONTINUE; -} - -@OnMoneyGive(const UserId, const Trie:Params) { - rg_add_account( - UserId, - VipM_Params_GetInt(Params, "Amount"), - VipM_Params_GetCell(Params, "GiveType", AS_ADD), - VipM_Params_GetBool(Params, "TrackChanges", true) - ); - return VIPM_CONTINUE; -} - -@OnItemsListRead(const JSON:jItem, const Trie:Params) { - TrieDeleteKey(Params, "Name"); - - if (!json_object_has_value(jItem, "Items")) { - Json_LogForFile(jItem, "ERROR", "Param `Items` required for item `ItemsList`."); - return VIPM_STOP; - } - - TrieSetCell(Params, "Items", VipM_IC_JsonGetItems(json_object_get_value(jItem, "Items"))); - - return VIPM_CONTINUE; -} - -@OnItemsListGive(const UserId, const Trie:Params) { - new Array:aItems = VipM_Params_GetCell(Params, "Items", Invalid_Array); - - return VipM_IC_GiveItems(UserId, aItems) ? VIPM_CONTINUE : VIPM_STOP; -} - -@OnCommandRead(const JSON:jItem, const Trie:Params) { - TrieDeleteKey(Params, "Name"); - - if (!json_object_has_value(jItem, "Command", JSONString)) { - Json_LogForFile(jItem, "ERROR", "Param `Command` required for item `Command`."); - return VIPM_STOP; - } - - new Command[128]; - json_object_get_string(jItem, "Command", Command, charsmax(Command)); - TrieSetString(Params, "Command", Command); - - if (json_object_has_value(jItem, "ByServer", JSONBoolean)) { - TrieSetCell(Params, "ByServer", json_object_get_bool(jItem, "ByServer")); - } - - return VIPM_CONTINUE; -} - -@OnCommandGive(const UserId, const Trie:Params) { - static Command[128]; - VipM_Params_GetStr(Params, "Command", Command, charsmax(Command)); - new bool:ByServer = VipM_Params_GetBool(Params, "ByServer", false); - - replace_all(Command, charsmax(Command), "{UserId}", IntToStr(UserId)); - - if (ByServer) { - server_cmd(Command); - } else { - client_cmd(UserId, Command); - } -} - -@OnDefuseKitGive(const UserId, const Trie:Params) { - if (get_member(UserId, m_iTeam) == TEAM_CT) { - rg_give_defusekit(UserId); - } - - return VIPM_CONTINUE; -} - -@OnWeaponRead(const JSON:jItem, const Trie:Params) { - new Name[32]; - json_object_get_string(jItem, "Name", Name, charsmax(Name)); - - // if(get_weaponid(Name) == 0){ - // log_amx("[WARNING] Weapon `%s` not found.", Name); - // return VIPM_STOP; - // } - - TrieSetCell(Params, "GiveType", _:Json_Object_GetGiveType(jItem, "GiveType")); - - if (json_object_has_value(jItem, "BpAmmo", JSONNumber)) { - TrieSetCell(Params, "BpAmmo", json_object_get_number(jItem, "BpAmmo")); - } - - TrieSetString(Params, "Name", Name); - - return VIPM_CONTINUE; -} - -@OnWeaponGive(const UserId, const Trie:Params) { - static WeaponName[32]; - VipM_Params_GetStr(Params, "Name", WeaponName, charsmax(WeaponName)); - if (!WeaponName[0]) { - return VIPM_STOP; - } - - if (!get_weaponid(WeaponName)) { - log_amx("[WARNING] Default weapon `%s` not found.", WeaponName); - return VIPM_STOP; - } - - new GiveType:iGiveType = GiveType:VipM_Params_GetInt(Params, "GiveType", _:GT_DROP_AND_REPLACE); - new iBpAmmo = VipM_Params_GetInt(Params, "BpAmmo", -1); - - new ItemId = rg_give_item(UserId, WeaponName, iGiveType); - if (ItemId < 0) { - return VIPM_STOP; - } - - new WeaponIdType:iWpnId = rg_get_weapon_info(WeaponName, WI_ID); - new iWpnSlot = rg_get_iteminfo(ItemId, ItemInfo_iSlot); - - if ( - iBpAmmo < 0 - && !( - iWpnSlot == 0 - || iWpnSlot == 1 - ) - ) { - return VIPM_CONTINUE; - } - - new def_BpAmmo = (rg_get_weapon_info(iWpnId, WI_MAX_ROUNDS)); - if (def_BpAmmo >= 0) { - rg_set_user_bpammo(UserId, iWpnId, iBpAmmo < 0 ? def_BpAmmo : iBpAmmo); - } - - return VIPM_CONTINUE; -} - -GiveType:Json_Object_GetGiveType(const JSON:Obj, const Key[], const bool:DotNot = false) { - new Str[32]; - json_object_get_string(Obj, Key, Str, charsmax(Str), DotNot); - return StrToGiveType(Str); -} - -GiveType:StrToGiveType(const Str[]) { - if (equali(Str, "GT_APPEND") || equali(Str, "Append") || equali(Str, "Add")) { - return GT_APPEND; - } else if (equali(Str, "GT_REPLACE") || equali(Str, "Replace")) { - return GT_REPLACE; - } else if (equali(Str, "GT_DROP_AND_REPLACE") || equali(Str, "Drop") || equali(Str, "DropAndReplace")) { - return GT_DROP_AND_REPLACE; - } else { - return GT_DROP_AND_REPLACE; - } -} - -StrToAccountSet(const Str[]) { - if (equali(Str, "Set")) { - return _:AS_SET; - } else if (equali(Str, "Add")) { - return _:AS_ADD; - } else { - return -1; - } -} - -MultUserSpeed(const UserId, const Float:fMultiplier) { - set_entvar(UserId, var_maxspeed, Float:get_entvar(UserId, var_maxspeed) * fMultiplier); -} diff --git a/amxmodx/scripting/VipM-I-Limits.sma b/amxmodx/scripting/VipM-I-Limits.sma deleted file mode 100644 index 4b3802f..0000000 --- a/amxmodx/scripting/VipM-I-Limits.sma +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include "VipM/Utils" - -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM-I] Limits"; -public stock const PluginVersion[] = _VIPM_VERSION; -public stock const PluginAuthor[] = "ArKaNeMaN"; -public stock const PluginURL[] = _VIPM_PLUGIN_URL; -public stock const PluginDescription[] = "[VipModular-Item] Items using limtis."; - -public VipM_IC_OnInitTypes() { - RegisterPluginByVars(); - - VipM_IC_RegisterType("If"); - VipM_IC_RegisterTypeEvent("If", ItemType_OnRead, "@OnIfRead"); - VipM_IC_RegisterTypeEvent("If", ItemType_OnGive, "@OnIfGive"); -} - -@OnIfRead(const JSON:jItem, const Trie:tParams) { - TrieDeleteKey(tParams, "Name"); - - if (!json_object_has_value(jItem, "Items")) { - Json_LogForFile(jItem, "ERROR", "Param `Items` required for item `If`."); - return VIPM_STOP; - } - - if (!json_object_has_value(jItem, "Limits")) { - Json_LogForFile(jItem, "ERROR", "Limits `Items` required for item `If`."); - return VIPM_STOP; - } - - TrieSetCell(tParams, "Items", VipM_IC_JsonGetItems(json_object_get_value(jItem, "Items"))); - TrieSetCell(tParams, "ElseItems", VipM_IC_JsonGetItems(json_object_get_value(jItem, "ElseItems"))); - TrieSetCell(tParams, "Limits", VipM_Limits_ReadListFromJson(json_object_get_value(jItem, "Limits"))); - - return VIPM_CONTINUE; -} - -@OnIfGive(const UserId, const Trie:tParams) { - if (VipM_Params_ExecuteLimitsList(tParams, "Limits", UserId, Limit_Exec_AND)) { - VipM_IC_GiveItems(UserId, VipM_Params_GetArr(tParams, "Items")); - return VIPM_CONTINUE; - } - - new Array:aElseItems = VipM_Params_GetArr(tParams, "ElseItems"); - if (ArraySizeSafe(aElseItems)) { - VipM_IC_GiveItems(UserId, aElseItems); - return VIPM_CONTINUE; - } - - return VIPM_STOP; -} diff --git a/amxmodx/scripting/VipM-ItemsController.sma b/amxmodx/scripting/VipM-ItemsController.sma deleted file mode 100644 index c7f427a..0000000 --- a/amxmodx/scripting/VipM-ItemsController.sma +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include "VipM/ArrayTrieUtils" -#include "VipM/ArrayMap" -#include "VipM/Utils" -#include "VipM/Forwards" - -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM] Items Controller"; -public stock const PluginVersion[] = _VIPM_VERSION; -public stock const PluginAuthor[] = "ArKaNeMaN"; -public stock const PluginURL[] = _VIPM_PLUGIN_URL; -public stock const PluginDescription[] = "Vip Modular`s items controller"; - -#include "VipM/ItemsController/Structs" -#include "VipM/ItemsController/Utils" - -DefineArrayMap(Types); // S_ItemType -new Array:Items; - -public plugin_precache() { - PluginInit(); -} - -PluginInit() { - CallOnce(); - - RegisterPluginByVars(); - CreateConstCvar("vipm_ic_version", PluginVersion); - SrvCmds_Init(); - - Forwards_Init("VipM_IC"); - Forwards_Reg("GiveItem", ET_STOP, FP_CELL, FP_CELL); - Forwards_Reg("ReadItem", ET_STOP, FP_CELL, FP_CELL); - - InitArrayMap(Types, S_ItemType, 8); - Forwards_RegAndCall("InitTypes", ET_IGNORE); - - Items = ArrayCreate(S_Item, 16); - Forwards_RegAndCall("Loaded", ET_IGNORE); -} - -#include "VipM/ItemsController/Natives" -#include "VipM/ItemsController/Configs" -#include "VipM/ItemsController/SrvCmds" diff --git a/amxmodx/scripting/VipM-L-Default.sma b/amxmodx/scripting/VipM-L-Default.sma deleted file mode 100644 index 9df4339..0000000 --- a/amxmodx/scripting/VipM-L-Default.sma +++ /dev/null @@ -1,420 +0,0 @@ -#include -#include -#include -#include "VipM/Utils" -#include "VipM/DebugMode" - -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM][L] Default"; -public stock const PluginVersion[] = _VIPM_VERSION; -public stock const PluginAuthor[] = "ArKaNeMaN"; -public stock const PluginURL[] = _VIPM_PLUGIN_URL; - -new g_sSteamIds[MAX_PLAYERS + 1][64]; -new g_sIps[MAX_PLAYERS + 1][32]; -new g_sRealMapName[32]; - -new Trie:g_tUsedInRound = Invalid_Trie; -new Trie:g_tUsedInMap = Invalid_Trie; -new Trie:g_tUsedInGame = Invalid_Trie; - -new Float:g_fPlayerSpawnTime[MAX_PLAYERS + 1]; - -public VipM_OnInitModules(){ - RegisterPluginByVars(); - - VipM_Limits_RegisterType("ForAll", false, true); - VipM_Limits_SetStaticValue("ForAll", true); - VipM_Limits_RegisterType("Always", false, true); - VipM_Limits_SetStaticValue("Always", true); - - VipM_Limits_RegisterType("Never", false, true); - VipM_Limits_SetStaticValue("Never", false); - - VipM_Limits_RegisterType("Steam", true, true); - - VipM_Limits_RegisterType("Alive", true, false); - VipM_Limits_RegisterTypeEvent("Alive", Limit_OnCheck, "@OnAliveCheck"); - - VipM_Limits_RegisterType("Bot", true, true); - - VipM_Limits_RegisterType("Name", true, false); - VipM_Limits_AddTypeParams("Name", - "Name", ptString, true - ); - VipM_Limits_RegisterTypeEvent("Name", Limit_OnCheck, "@OnNameCheck"); - - VipM_Limits_RegisterType("Flags", true, false); - VipM_Limits_AddTypeParams("Flags", - "Flags", ptString, true, - "Strict", ptBoolean, false - ); - VipM_Limits_RegisterTypeEvent("Flags", Limit_OnCheck, "@OnFlagsCheck"); - - VipM_Limits_RegisterType("SteamId", true, false); - VipM_Limits_AddTypeParams("SteamId", - "SteamId", ptString, true - ); - VipM_Limits_RegisterTypeEvent("SteamId", Limit_OnCheck, "@OnSteamIdCheck"); - - VipM_Limits_RegisterType("Ip", true, false); - VipM_Limits_AddTypeParams("Ip", - "Ip", ptString, true - ); - VipM_Limits_RegisterTypeEvent("Ip", Limit_OnCheck, "@OnIpCheck"); - - VipM_Limits_RegisterType("Map", false, false); - VipM_Limits_AddTypeParams("Map", - "Map", ptString, true, - "Real", ptBoolean, false, - "Prefix", ptBoolean, false - ); - VipM_Limits_RegisterTypeEvent("Map", Limit_OnCheck, "@OnMapCheck"); - rh_get_mapname(g_sRealMapName, charsmax(g_sRealMapName), MNT_TRUE); - - VipM_Limits_RegisterType("HasPrimaryWeapon", true, false); - VipM_Limits_AddTypeParams("HasPrimaryWeapon", - "HasNot", ptBoolean, false - ); - VipM_Limits_RegisterTypeEvent("HasPrimaryWeapon", Limit_OnCheck, "@OnHasPrimaryWeaponCheck"); - - VipM_Limits_RegisterType("Round", false, false); - VipM_Limits_AddTypeParams("Round", - "Min", ptInteger, false, - "Max", ptInteger, false - ); - VipM_Limits_RegisterTypeEvent("Round", Limit_OnCheck, "@OnRoundCheck"); - - VipM_Limits_RegisterType("WeekDay", false, false); - VipM_Limits_AddTypeParams("WeekDay", - "Day", ptString, true - ); - VipM_Limits_RegisterTypeEvent("WeekDay", Limit_OnRead, "@OnWeekDayRead"); - VipM_Limits_RegisterTypeEvent("WeekDay", Limit_OnCheck, "@OnWeekDayCheck"); - - VipM_Limits_RegisterType("RoundTime", false, false); - VipM_Limits_AddTypeParams("RoundTime", - "Min", ptInteger, false, - "Max", ptInteger, false - ); - VipM_Limits_RegisterTypeEvent("RoundTime", Limit_OnCheck, "@OnRoundTimeCheck"); - - VipM_Limits_RegisterType("LifeTime", true, false); - VipM_Limits_AddTypeParams("LifeTime", - "Min", ptInteger, false, - "Max", ptInteger, false - ); - VipM_Limits_RegisterTypeEvent("LifeTime", Limit_OnCheck, "@OnLifeTimeCheck"); - - VipM_Limits_RegisterType("InFreezyTime", false, false); - VipM_Limits_AddTypeParams("InFreezyTime", - "Reverse", ptBoolean, false - ); - VipM_Limits_RegisterTypeEvent("InFreezyTime", Limit_OnCheck, "@OnInFreezyTimeCheck"); - - // thx for idea: https://dev-cs.ru/members/7658/ - VipM_Limits_RegisterType("InBuyZone", true, false); - VipM_Limits_AddTypeParams("InBuyZone", - "Reverse", ptBoolean, false - ); - VipM_Limits_RegisterTypeEvent("InBuyZone", Limit_OnCheck, "@OnInBuyZoneCheck"); - - VipM_Limits_RegisterType("OncePerRound", true, false); - VipM_Limits_RegisterTypeEvent("OncePerRound", Limit_OnCheck, "@OnOncePerRoundCheck"); - - // thx for idea: https://dev-cs.ru/threads/24759/page-2#post-141912 - VipM_Limits_RegisterType("OncePerMap", true, false); - VipM_Limits_RegisterTypeEvent("OncePerMap", Limit_OnCheck, "@OnOncePerMapCheck"); - - VipM_Limits_RegisterType("OncePerGame", true, false); - VipM_Limits_RegisterTypeEvent("OncePerGame", Limit_OnCheck, "@OnOncePerGameCheck"); - - VipM_Limits_RegisterType("Time", false, false); - VipM_Limits_AddTypeParams("Time", - "Before", ptString, false, - "After", ptString, false - ); - VipM_Limits_RegisterTypeEvent("Time", Limit_OnRead, "@OnTimeRead"); - VipM_Limits_RegisterTypeEvent("Time", Limit_OnCheck, "@OnTimeCheck"); - - VipM_Limits_RegisterType("Frags", true, false); - VipM_Limits_AddTypeParams("Frags", - "Min", ptInteger, false, - "Max", ptInteger, false - ); - VipM_Limits_RegisterTypeEvent("Frags", Limit_OnCheck, "@OnFragsCheck"); - - VipM_Limits_RegisterType("GameTime", true, false); - VipM_Limits_AddTypeParams("GameTime", - "Min", ptFloat, false, - "Max", ptFloat, false - ); - VipM_Limits_RegisterTypeEvent("GameTime", Limit_OnCheck, "@OnGameTimeCheck"); - - RegisterHookChain(RG_CSGameRules_RestartRound, "@OnRestartRound", true); - RegisterHookChain(RG_CBasePlayer_Spawn, "@OnPlayerSpawn", true); - - g_tUsedInRound = TrieCreate(); - g_tUsedInMap = TrieCreate(); - g_tUsedInGame = TrieCreate(); -} - -public client_authorized(UserId, const AuthId[]){ - VipM_Limits_SetStaticValue("Steam", is_user_steam(UserId), UserId); - VipM_Limits_SetStaticValue("Bot", bool:is_user_bot(UserId), UserId); - - copy(g_sSteamIds[UserId], charsmax(g_sSteamIds[]), AuthId); - get_user_ip(UserId, g_sIps[UserId], charsmax(g_sIps[]), true); -} - -@OnRestartRound() { - TrieClear(g_tUsedInRound); - if (get_member_game(m_bCompleteReset)) { - TrieClear(g_tUsedInGame); - } -} - -@OnPlayerSpawn(const UserId) { - g_fPlayerSpawnTime[UserId] = get_gametime(); -} - -@OnGameTimeCheck(const Trie:params) { - new Float:gameTime = get_gametime(); - - new Float:min; - if (TrieGetCell(params, "Min", min) && gameTime < min) { - return false; - } - - new Float:max; - if (TrieGetCell(params, "Max", max) && gameTime > max) { - return false; - } - - return true; -} - -@OnFragsCheck(const Trie:params, const playerIndex) { - new frags = get_user_frags(playerIndex); - - new min; - if (TrieGetCell(params, "Min", min) && frags < min) { - return false; - } - - new max; - if (TrieGetCell(params, "Max", max) && frags > max) { - return false; - } - - return true; -} - -@OnTimeRead(const JSON:jCfg, const Trie:tParams) { - new sTime[8]; - - TrieGetString(tParams, "Before", sTime, charsmax(sTime)); - TrieSetCell(tParams, "Before", ParseColonTime(sTime), .replace = true); - - TrieGetString(tParams, "After", sTime, charsmax(sTime)); - TrieSetCell(tParams, "After", ParseColonTime(sTime), .replace = true); - - return VIPM_CONTINUE; -} - -@OnTimeCheck(const Trie:tParams) { - new iBefore = VipM_Params_GetInt(tParams, "Before", 0); - new iAfter = VipM_Params_GetInt(tParams, "After", 0); - new iCurrent = GetTime(); - - Dbg_Log("@OnTimeCheck(%d):", tParams); - Dbg_Log(" iBefore = %d", iBefore); - Dbg_Log(" iAfter = %d", iAfter); - Dbg_Log(" iCurrent = %d", iCurrent); - - if (!iBefore && !iAfter) { - return true; - } - - if (!iBefore) { - return iCurrent > iAfter; - } - - if (!iAfter) { - return iCurrent < iBefore; - } - - if (iBefore == iAfter) { - return iBefore == iCurrent; - } - - if (iAfter < iBefore) { - return ( - iCurrent > iAfter - && iCurrent < iBefore - ); - } - - if (iAfter > iBefore) { - return ( - iCurrent > iAfter - || iCurrent < iBefore - ); - } - - return false; -} - -@OnOncePerGameCheck(const Trie:tParams, const UserId) { - static sTrieKey[64]; - formatex(sTrieKey, charsmax(sTrieKey), "%s|%d", g_sSteamIds[UserId], tParams); - // В случае лимитов, хендлер Trie параметров можно считать уникальным для каждого инстанса лимита - // Нужно чтобы можно было указать этот лимит в двух местах и чтобы они при этом не пересекались - // Ну а SteamID для того, чтобы после перезахода оно не сбрасывалось - // - // P.S. Или лучше всё же пихать в параметры идентификатор, по котому их разделять? - // Или оба сразу?) - - if (TrieKeyExists(g_tUsedInGame, sTrieKey)) { - return false; - } - - TrieSetCell(g_tUsedInGame, sTrieKey, true); - return true; -} - -@OnOncePerMapCheck(const Trie:tParams, const UserId) { - static sTrieKey[64]; - formatex(sTrieKey, charsmax(sTrieKey), "%s|%d", g_sSteamIds[UserId], tParams); - - if (TrieKeyExists(g_tUsedInMap, sTrieKey)) { - return false; - } - - TrieSetCell(g_tUsedInMap, sTrieKey, true); - return true; -} - -@OnOncePerRoundCheck(const Trie:tParams, const UserId) { - static sTrieKey[64]; - formatex(sTrieKey, charsmax(sTrieKey), "%s|%d", g_sSteamIds[UserId], tParams); - - if (TrieKeyExists(g_tUsedInRound, sTrieKey)) { - return false; - } - - TrieSetCell(g_tUsedInRound, sTrieKey, true); - return true; -} - -@OnInBuyZoneCheck(const Trie:Params, const UserId) { - new bool:bInBuyZone = IsUserInBuyZone(UserId); - return VipM_Params_GetBool(Params, "Reverse", false) ? !bInBuyZone : bInBuyZone; -} - -@OnInFreezyTimeCheck(const Trie:Params) { - new bool:bFreezyPeriod = get_member_game(m_bFreezePeriod); - return VipM_Params_GetBool(Params, "Reverse", false) ? !bFreezyPeriod : bFreezyPeriod; -} - -@OnRoundTimeCheck(const Trie:Params) { - new iMin = VipM_Params_GetInt(Params, "Min", 0); - new iMax = VipM_Params_GetInt(Params, "Max", 0); - new iRoundTime = floatround(get_gametime() - Float:get_member_game(m_fRoundStartTime)); - - return ( - (!iMin || iRoundTime >= iMin) - && (!iMax || iRoundTime <= iMax) - ); -} - -@OnLifeTimeCheck(const Trie:Params, const UserId) { - new iMin = VipM_Params_GetInt(Params, "Min", 0); - new iMax = VipM_Params_GetInt(Params, "Max", 0); - new iLifeTime = floatround(get_gametime() - g_fPlayerSpawnTime[UserId]); - - return ( - (!iMin || iLifeTime >= iMin) - && (!iMax || iLifeTime <= iMax) - ); -} - -@OnWeekDayRead(const JSON:jCfg, const Trie:Params) { - new sWeekDayName[32]; - json_object_get_string(jCfg, "Day", sWeekDayName, charsmax(sWeekDayName)); - new iWeekDayIndex = GetWeekDayIdByName(sWeekDayName); - if (iWeekDayIndex < 0) { - log_amx("[WARNING] Undefined week day '%s'.", sWeekDayName); - return VIPM_STOP; - } - - TrieSetCell(Params, "Day", iWeekDayIndex); - return VIPM_CONTINUE; -} - -@OnWeekDayCheck(const Trie:Params) { - new sWeekDay[4]; - get_time("%w", sWeekDay, charsmax(sWeekDay)); - return str_to_num(sWeekDay) == VipM_Params_GetInt(Params, "Day", -1); -} - -@OnAliveCheck(const Trie:Params, const UserId) { - return is_user_alive(UserId); -} - -@OnNameCheck(const Trie:Params, const UserId) { - static sName[32]; - VipM_Params_GetStr(Params, "Name", sName, charsmax(sName)); - - return IsEqualUserName(UserId, sName); -} - -bool:@OnFlagsCheck(const Trie:Params, const UserId) { - static sFlags[16]; - VipM_Params_GetStr(Params, "Flags", sFlags, charsmax(sFlags)); - - return HasUserFlagsStr(UserId, sFlags, VipM_Params_GetBool(Params, "Strict", false)); -} - -@OnSteamIdCheck(const Trie:Params, const UserId) { - static sSteamId[64]; - VipM_Params_GetStr(Params, "SteamId", sSteamId, charsmax(sSteamId)); - - return equali(g_sSteamIds[UserId], sSteamId); -} - -@OnIpCheck(const Trie:Params, const UserId) { - static sIp[32]; - VipM_Params_GetStr(Params, "SteamId", sIp, charsmax(sIp)); - - return equali(g_sIps[UserId], sIp); -} - -@OnMapCheck(const Trie:Params) { - static sMap[32]; - VipM_Params_GetStr(Params, "Map", sMap, charsmax(sMap)); - - new iCount = VipM_Params_GetBool(Params, "Prefix", false) ? strlen(sMap) : 0; - - if (VipM_Params_GetBool(Params, "Real", false)) { - return equali(sMap, g_sRealMapName, iCount); - } else { - static sSetMapName[32]; - rh_get_mapname(sSetMapName, charsmax(sSetMapName), MNT_SET); - return equali(sMap, sSetMapName, iCount); - } -} - -@OnHasPrimaryWeaponCheck(const Trie:Params, const UserId) { - new bool:res = get_member(UserId, m_bHasPrimary); - return VipM_Params_GetBool(Params, "HasNot", false) ? !res : res; -} - -@OnRoundCheck(const Trie:Params, const UserId){ - return ( - GetRound() >= VipM_Params_GetInt(Params, "Min", -1) - && GetRound() <= VipM_Params_GetInt(Params, "Max", cellmax) - ); -} diff --git a/amxmodx/scripting/VipM-L-Logic.sma b/amxmodx/scripting/VipM-L-Logic.sma deleted file mode 100644 index 4e5dfff..0000000 --- a/amxmodx/scripting/VipM-L-Logic.sma +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include "VipM/Utils" - -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM][L] Logic"; -public stock const PluginVersion[] = _VIPM_VERSION; -public stock const PluginAuthor[] = "ArKaNeMaN"; -public stock const PluginURL[] = _VIPM_PLUGIN_URL; - -public VipM_OnInitModules(){ - RegisterPluginByVars(); - - VipM_Limits_RegisterType("Logic-OR", false, false); - VipM_Limits_AddTypeParams("Logic-OR", - "Limits", ptLimits, true - ); - VipM_Limits_RegisterTypeEvent("Logic-OR", Limit_OnCheck, "@OnOrCheck"); - - VipM_Limits_RegisterType("Logic-XOR", false, false); - VipM_Limits_AddTypeParams("Logic-XOR", - "Limits", ptLimits, true - ); - VipM_Limits_RegisterTypeEvent("Logic-XOR", Limit_OnCheck, "@OnXorCheck"); - - VipM_Limits_RegisterType("Logic-AND", false, false); - VipM_Limits_AddTypeParams("Logic-AND", - "Limits", ptLimits, true - ); - VipM_Limits_RegisterTypeEvent("Logic-AND", Limit_OnCheck, "@OnAndCheck"); - - VipM_Limits_RegisterType("Logic-NOT", false, false); - VipM_Limits_AddTypeParams("Logic-NOT", - "Limits", ptLimits, true - ); - VipM_Limits_RegisterTypeEvent("Logic-NOT", Limit_OnCheck, "@OnNotCheck"); -} - -@OnOrCheck(const Trie:Params, const UserId){ - return VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_OR); -} - -@OnXorCheck(const Trie:Params, const UserId){ - return VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_XOR); -} - -@OnAndCheck(const Trie:Params, const UserId){ - return VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_AND); -} - -@OnNotCheck(const Trie:Params, const UserId){ - return !VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_AND); -} diff --git a/amxmodx/scripting/VipM-M-SpawnHealth.sma b/amxmodx/scripting/VipM-M-SpawnHealth.sma index a14fdad..236b31b 100644 --- a/amxmodx/scripting/VipM-M-SpawnHealth.sma +++ b/amxmodx/scripting/VipM-M-SpawnHealth.sma @@ -1,14 +1,8 @@ #include #include #include -#include "VipM/Utils" -#include "VipM/DebugMode" -#include "VipM/ArrayTrieUtils" -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM][M] Spawn Health"; +public stock const PluginName[] = "[VipM-M] Spawn Health"; public stock const PluginVersion[] = _VIPM_VERSION; public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; @@ -16,70 +10,64 @@ public stock const PluginDescription[] = "Vip modular`s module - SpawnHealth"; new const MODULE_NAME[] = "SpawnHealth"; -public VipM_OnInitModules(){ - RegisterPluginByVars(); +public VipM_Modules_OnInited() { + register_plugin(PluginName, PluginVersion, PluginAuthor); - VipM_Modules_Register(MODULE_NAME, true); - VipM_Modules_AddParams(MODULE_NAME, - "Health", ptInteger, false, - "SetHealth", ptBoolean, false, - "MaxHealth", ptInteger, false + VipM_Modules_Register(MODULE_NAME); + VipM_Modules_AddParamsEx(MODULE_NAME, + "Health", DEFAULT_PARAMS_INT_NAME, false, + "SetHealth", DEFAULT_PARAMS_BOOL_NAME, false, + "MaxHealth", DEFAULT_PARAMS_INT_NAME, false ); - VipM_Modules_AddParams(MODULE_NAME, - "Armor", ptInteger, false, - "SetArmor", ptBoolean, false, - "MaxArmor", ptInteger, false + VipM_Modules_AddParamsEx(MODULE_NAME, + "Armor", DEFAULT_PARAMS_INT_NAME, false, + "SetArmor", DEFAULT_PARAMS_BOOL_NAME, false, + "MaxArmor", DEFAULT_PARAMS_INT_NAME, false ); - VipM_Modules_AddParams(MODULE_NAME, - "Helmet", ptBoolean, false, - "Limits", ptLimits, false + VipM_Modules_AddParamsEx(MODULE_NAME, + "Helmet", DEFAULT_PARAMS_BOOL_NAME, false, + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, false ); VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnActivated, "@Event_ModuleActivate"); } -@Event_ModuleActivate(){ +@Event_ModuleActivate() { RegisterHookChain(RG_CBasePlayer_Spawn, "@Event_PlayerSpawned", true); } -@Event_PlayerSpawned(const UserId){ - if (!is_user_alive(UserId)) { +@Event_PlayerSpawned(const playerIndex) { + if (!is_user_alive(playerIndex)) { return; } - - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); - if (Params == Invalid_Trie) { + + if (!VipM_Modules_HasModule(MODULE_NAME, playerIndex)) { return; } + + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); - Dbg_Log("@Event_PlayerSpawned(%d): Limits Count = %d", UserId, ArraySizeSafe(VipM_Params_GetCell(Params, "Limits", Invalid_Array))); - if (!VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_AND)) { + if (!PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND)) { return; } - Dbg_Log("@Event_PlayerSpawned(%d): Round №%d -> Passed", UserId, get_member_game(m_iTotalRoundsPlayed) + 1); - new Health; - if (TrieGetCell(Params, "Health", Health) && Health > 0) { - if (!VipM_Params_GetBool(Params, "SetHealth", true)) { - Health += floatround(get_entvar(UserId, var_health)); + new maxHealth = PCGet_Int(p, "MaxHealth", floatround(get_entvar(playerIndex, var_max_health))); + set_entvar(playerIndex, var_max_health, float(maxHealth)); - new MaxHealth; - if (TrieGetCell(Params, "MaxHealth", MaxHealth) && MaxHealth > 0) { - Health = min(Health, MaxHealth); - } + new health = PCGet_Int(p, "Health", 0); + if (health > 0) { + if (!PCGet_Bool(p, "SetHealth", true)) { + health = min(floatround(get_entvar(playerIndex, var_health)) + health, maxHealth); } - set_entvar(UserId, var_health, float(Health)); - } - new Armor; - if (TrieGetCell(Params, "Armor", Armor) && Armor > 0) { - if (!VipM_Params_GetBool(Params, "SetArmor", true)) { - Health += rg_get_user_armor(UserId); + set_entvar(playerIndex, var_health, float(health)); + } - new MaxHealth; - if (TrieGetCell(Params, "MaxArmor", MaxHealth) && MaxHealth > 0) { - Health = min(Health, MaxHealth); - } + new armor = PCGet_Int(p, "Armor", 0); + if (armor > 0) { + if (!PCGet_Bool(p, "SetArmor", true)) { + armor = min(rg_get_user_armor(playerIndex) + armor, PCGet_Int(p, "MaxArmor", 100)); } - rg_set_user_armor(UserId, Armor, VipM_Params_GetBool(Params, "Helmet", false) ? ARMOR_VESTHELM : ARMOR_KEVLAR); + + rg_set_user_armor(playerIndex, armor, PCGet_Bool(p, "Helmet", false) ? ARMOR_VESTHELM : ARMOR_KEVLAR); } } diff --git a/amxmodx/scripting/VipM-M-SpawnItems.sma b/amxmodx/scripting/VipM-M-SpawnItems.sma index d77d591..dca64a1 100644 --- a/amxmodx/scripting/VipM-M-SpawnItems.sma +++ b/amxmodx/scripting/VipM-M-SpawnItems.sma @@ -2,14 +2,7 @@ #include #include #include -#include "VipM/Utils" -#include "VipM/DebugMode" - -#include "VipM/Utils" -#include "VipM/ArrayTrieUtils" - -#pragma semicolon 1 -#pragma compress 1 +#include public stock const PluginName[] = "[VipM-M] Spawn Items"; public stock const PluginVersion[] = _VIPM_VERSION; @@ -19,73 +12,40 @@ public stock const PluginDescription[] = "Vip modular`s module - Spawn Items"; new const MODULE_NAME[] = "SpawnItems"; -public VipM_OnInitModules(){ - RegisterPluginByVars(); - - VipM_IC_Init(); +public VipM_Modules_OnInited() { + register_plugin(PluginName, PluginVersion, PluginAuthor); + IC_Init(); - VipM_Modules_Register(MODULE_NAME, true); - VipM_Modules_AddParams(MODULE_NAME, - "Items", ptCustom, false, - "Limits", ptLimits, false + VipM_Modules_Register(MODULE_NAME); + VipM_Modules_AddParamsEx(MODULE_NAME, + "Items", IC_PARAM_TYPE_ITEMS_NAME, true, + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, false ); - VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnRead, "@OnReadConfig"); VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnActivated, "@OnModuleActivate"); } -@OnReadConfig(const JSON:jCfg, Trie:Params){ - if(!json_object_has_value(jCfg, "Items")){ - log_amx("[WARNING] Field `Items` required."); - return VIPM_STOP; - } - - new JSON:jItems = json_object_get_value(jCfg, "Items"); - new Array:aItems = VipM_IC_JsonGetItems(jItems); - json_free(jItems); - - if(ArraySizeSafe(aItems) < 1){ - ArrayDestroySafe(aItems); - log_amx("[WARNING] Field `Items` is empty."); - return VIPM_STOP; - } - TrieSetCell(Params, "Items", aItems); - - return VIPM_CONTINUE; -} - -@OnModuleActivate(){ +@OnModuleActivate() { RegisterHookChain(RG_CBasePlayer_Spawn, "@OnPlayerSpawned", true); } -@OnPlayerSpawned(const UserId){ - RequestFrame("@GivePlayerItems", UserId); +@OnPlayerSpawned(const playerIndex) { + RequestFrame("@GivePlayerItems", playerIndex); } -@GivePlayerItems(const UserId) { - if (!is_user_alive(UserId)) { +@GivePlayerItems(const playerIndex) { + if (!is_user_alive(playerIndex)) { return; } - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); - if (Params == Invalid_Trie) { - Dbg_Log("@GivePlayerItems(%n) Has not access", UserId); - return; - } - - if (!VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_AND)) { - Dbg_Log("@GivePlayerItems(%n) Limits not passed", UserId); + if (!VipM_Modules_HasModule(MODULE_NAME, playerIndex)) { return; } + + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); - new Array:aItems = Array:VipM_Params_GetInt(Params, "Items", _:Invalid_Array); - if (aItems == Invalid_Array) { - Dbg_Log("@GivePlayerItems(%n) Items array is empty", UserId); + if (!PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND)) { return; } - if (VipM_IC_GiveItems(UserId, aItems)) { - Dbg_Log("@GivePlayerItems(%n) Items given", UserId); - } else { - Dbg_Log("@GivePlayerItems(%n) Items not given", UserId); - } + PCGet_IcItemsGive(p, "Items", playerIndex); } diff --git a/amxmodx/scripting/VipM-M-Vampire.sma b/amxmodx/scripting/VipM-M-Vampire.sma index 39e2ca7..e52c847 100644 --- a/amxmodx/scripting/VipM-M-Vampire.sma +++ b/amxmodx/scripting/VipM-M-Vampire.sma @@ -1,12 +1,8 @@ #include #include #include -#include "VipM/Utils" -#pragma semicolon 1 -#pragma compress 1 - -public stock const PluginName[] = "[VipM][M] Vampire"; +public stock const PluginName[] = "[VipM-M] Vampire"; public stock const PluginVersion[] = _VIPM_VERSION; public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; @@ -14,74 +10,76 @@ public stock const PluginDescription[] = "Vip modular`s module - Vampire"; new const MODULE_NAME[] = "Vampire"; -public VipM_OnInitModules(){ - RegisterPluginByVars(); +public VipM_Modules_OnInited() { + register_plugin(PluginName, PluginVersion, PluginAuthor); register_dictionary("VipM-Vampire.ini"); - VipM_Modules_Register(MODULE_NAME, true); - VipM_Modules_AddParams(MODULE_NAME, - "MaxHealth", ptInteger, false, - "ByKill", ptInteger, false, - "ByHead", ptInteger, false, - "ByKnife", ptInteger, false, - "ByGrenade", ptInteger, false + VipM_Modules_Register(MODULE_NAME); + VipM_Modules_AddParamsEx(MODULE_NAME, + "ByKill", DEFAULT_PARAMS_INT_NAME, false, + "ByHead", DEFAULT_PARAMS_INT_NAME, false, + "ByKnife", DEFAULT_PARAMS_INT_NAME, false, + "ByGrenade", DEFAULT_PARAMS_INT_NAME, false ); - VipM_Modules_AddParams(MODULE_NAME, - "Limits", ptLimits, false + VipM_Modules_AddParamsEx(MODULE_NAME, + "MaxHealth", DEFAULT_PARAMS_INT_NAME, false, + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, false ); VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnActivated, "@Event_ModuleActivate"); } -@Event_ModuleActivate(){ +@Event_ModuleActivate() { RegisterHookChain(RG_CBasePlayer_Killed, "@Event_PlayerKilled", true); } -@Event_PlayerKilled(const VictimId, UserId, InflictorId){ +@Event_PlayerKilled(const victimIndex, playerIndex, inflictorIndex) { if ( - UserId == VictimId - || !is_user_alive(UserId) - || !is_user_connected(VictimId) + playerIndex == victimIndex + || !is_user_alive(playerIndex) + || !is_user_connected(victimIndex) ) { return; } - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); - if (Params == Invalid_Trie) { + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); + if (p == Invalid_Trie) { return; } - if (!VipM_Limits_ExecuteList(VipM_Params_GetCell(Params, "Limits", Invalid_Array), UserId)) { + if (!PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND)) { return; } - new MaxHealth = VipM_Params_GetInt(Params, "MaxHealth", 100); - new Health = floatround(get_entvar(UserId, var_health)); - if (Health >= MaxHealth) { + new maxHealth = PCGet_Int(p, "MaxHealth", floatround(get_entvar(playerIndex, var_max_health))); + new currentHealth = floatround(get_entvar(playerIndex, var_health)); + if (currentHealth >= maxHealth) { return; } - new ByKill = VipM_Params_GetInt(Params, "ByKill", 0); - new VampHealth = 0; - new ActiveItem; ActiveItem = get_member(UserId, m_pActiveItem); + new healthByKill = PCGet_Int(p, "ByKill", 0); + new addHealth = 0; + new activeItem = get_member(playerIndex, m_pActiveItem); + if ( - !(get_member(VictimId, m_bitsDamageType) & DMG_SLASH) - && is_entity(ActiveItem) - && rg_get_iteminfo(ActiveItem, ItemInfo_iId) == CSW_KNIFE + !(get_member(victimIndex, m_bitsDamageType) & DMG_SLASH) + && is_entity(activeItem) + && rg_get_iteminfo(activeItem, ItemInfo_iId) == CSW_KNIFE ) { - VampHealth = VipM_Params_GetInt(Params, "ByKnife", ByKill); - } else if(get_member(VictimId, m_bHeadshotKilled)) { - VampHealth = VipM_Params_GetInt(Params, "ByHead", ByKill); - } else if (get_member(VictimId, m_bKilledByGrenade)) { - VampHealth = VipM_Params_GetInt(Params, "ByGrenade", ByKill); + addHealth = PCGet_Int(p, "ByKnife", healthByKill); + } else if(get_member(victimIndex, m_bHeadshotKilled)) { + addHealth = PCGet_Int(p, "ByHead", healthByKill); + } else if (get_member(victimIndex, m_bKilledByGrenade)) { + addHealth = PCGet_Int(p, "ByGrenade", healthByKill); } else { - VampHealth = ByKill; + addHealth = healthByKill; } - if (ByKill <= 0) { + if (addHealth <= 0) { return; } - client_print(UserId, print_center, "%L", UserId, "VAMPIRE_HEALTH_MESSAGE", VampHealth); - Health = clamp(Health + VampHealth, 1, MaxHealth < 1 ? cellmax : MaxHealth); - set_entvar(UserId, var_health, float(Health)); + new newHealth = clamp(currentHealth + addHealth, 1, maxHealth < 1 ? cellmax : maxHealth); + set_entvar(playerIndex, var_health, float(newHealth)); + + client_print(playerIndex, print_center, "%L", playerIndex, "VAMPIRE_HEALTH_MESSAGE", addHealth); } diff --git a/amxmodx/scripting/VipM-M-VipInTab.sma b/amxmodx/scripting/VipM-M-VipInTab.sma index c01ab46..2b0e7bd 100644 --- a/amxmodx/scripting/VipM-M-VipInTab.sma +++ b/amxmodx/scripting/VipM-M-VipInTab.sma @@ -1,9 +1,5 @@ #include #include -#include "VipM/Utils" - -#pragma semicolon 1 -#pragma compress 1 enum E_ModuleParams { Param_Enabled = 0, @@ -14,42 +10,42 @@ public stock const PluginName[] = "[VipM-M] Vip in TAB"; public stock const PluginVersion[] = _VIPM_VERSION; public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; -public stock const PluginDescription[] = "Vip modular`s module - VipInTab"; +public stock const PluginDescription[] = "[VipModular-Module] Show VIP status in TAB."; new const MODULE_NAME[] = "VipInTab"; -new bool:gHasTag[MAX_PLAYERS + 1][E_ModuleParams]; +new bool:PlayerSettings[MAX_PLAYERS + 1][E_ModuleParams]; -public VipM_OnInitModules() { - RegisterPluginByVars(); +public VipM_Modules_OnInited() { + register_plugin(PluginName, PluginVersion, PluginAuthor); - VipM_Modules_Register(MODULE_NAME, true); - VipM_SetModuleParams(MODULE_NAME, - "Enabled", ptBoolean, true, - "Override", ptBoolean, false + VipM_Modules_Register(MODULE_NAME); + VipM_Modules_AddParamsEx(MODULE_NAME, + "Enabled", DEFAULT_PARAMS_BOOL_NAME, true, + "Override", DEFAULT_PARAMS_BOOL_NAME, false ); VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnActivated, "@OnModuleActivate"); } -public VipM_OnUserUpdated(const UserId) { - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); +public VipM_OnUserUpdated(const playerIndex) { + new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, playerIndex); - gHasTag[UserId][Param_Enabled] = VipM_Params_GetBool(Params, "Enabled", false); - gHasTag[UserId][Param_Override] = VipM_Params_GetBool(Params, "Override", false); + PlayerSettings[playerIndex][Param_Enabled] = PCGet_Bool(Params, "Enabled", false); + PlayerSettings[playerIndex][Param_Override] = PCGet_Bool(Params, "Override", false); } @OnModuleActivate() { register_message(get_user_msgid("ScoreAttrib"), "@OnMsgScoreAttrib"); } -@OnMsgScoreAttrib(const MsgId, const MsgType, const MsgDest) { - new UserId = get_msg_arg_int(1); - if (!gHasTag[UserId][Param_Enabled]) { +@OnMsgScoreAttrib(const messageIndex, const messageType, const messageDestination) { + new playerIndex = get_msg_arg_int(1); + if (!PlayerSettings[playerIndex][Param_Enabled]) { return; } if ( - !gHasTag[UserId][Param_Override] + !PlayerSettings[playerIndex][Param_Override] && get_msg_arg_int(2) != 0 ) { return; diff --git a/amxmodx/scripting/VipM-M-WeaponMenu.sma b/amxmodx/scripting/VipM-M-WeaponMenu.sma index 804699f..a57429b 100644 --- a/amxmodx/scripting/VipM-M-WeaponMenu.sma +++ b/amxmodx/scripting/VipM-M-WeaponMenu.sma @@ -1,13 +1,15 @@ #include #include #include +#include +#include + #include "VipM/Utils" -#include "VipM/DebugMode" -#pragma semicolon 1 -#pragma compress 1 +#include "VipM/WeaponMenu/Objects/WeaponMenu" +#include "VipM/WeaponMenu/Objects/MenuItem" -public stock const PluginName[] = "[VipM][M] Weapon Menu"; +public stock const PluginName[] = "[VipM-M] Weapon Menu"; public stock const PluginVersion[] = _VIPM_VERSION; public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; @@ -15,14 +17,6 @@ public stock const PluginDescription[] = "Vip modular`s module - Weapon Menu"; new const MODULE_NAME[] = "WeaponMenu"; -new const CMD_WEAPON_MENU[] = "vipmenu"; -new const CMD_WEAPON_MENU_SILENT[] = "vipmenu_silent"; -new const CMD_SWITCH_AUTOOPEN[] = "vipmenu_autoopen"; - -#include "VipM/ArrayTrieUtils" -#include "VipM/Utils" -#include "VipM/CommandAliases" - enum { TASK_OFFSET_AUTO_OPEN = 100, TASK_OFFSET_AUTO_CLOSE = 200, @@ -36,51 +30,50 @@ new bool:gUserAutoOpen[MAX_PLAYERS + 1] = {true, ...}; new gUserExpireStatus[MAX_PLAYERS + 1][VIPM_M_WEAPONMENU_EXPIRE_STATUS_MAX_LEN]; #include "VipM/WeaponMenu/KeyValueCounter" -#include "VipM/WeaponMenu/Structs" -#include "VipM/WeaponMenu/Configs" #include "VipM/WeaponMenu/Menus" -public VipM_OnInitModules() { - RegisterPluginByVars(); +public VipM_Modules_OnInited() { + register_plugin(PluginName, PluginVersion, PluginAuthor); register_dictionary("VipM-WeaponMenu.ini"); + IC_Init(); - VipM_IC_Init(); - - VipM_Modules_Register(MODULE_NAME, true); - VipM_Modules_AddParams(MODULE_NAME, - "MainMenuTitle", ptString, false, - "Menus", ptCustom, true, - "Count", ptInteger, false + VipM_Modules_Register(MODULE_NAME); + VipM_Modules_AddParamsEx(MODULE_NAME, + // TODO: Read "Menus" as param + "MainMenuTitle", DEFAULT_PARAMS_STR_NAME, false, + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, false ); - VipM_Modules_AddParams(MODULE_NAME, - "Limits", ptLimits, false + VipM_Modules_AddParamsEx(MODULE_NAME, + "Count", DEFAULT_PARAMS_INT_NAME, false, + "CounterType", VIPM_L_COUNTER_PARAM_TYPE, false, + "CounterKey", DEFAULT_PARAMS_SHORT_STR_NAME, false, + "ResetCountOnSpawn", DEFAULT_PARAMS_BOOL_NAME, false // deprecated ); - VipM_Modules_AddParams(MODULE_NAME, - "AutoopenLimits", ptLimits, false, - "AutoopenDelay", ptFloat, false, - "AutoopenCloseDelay", ptFloat, false, - "AutoopenMenuNum", ptInteger, false + VipM_Modules_AddParamsEx(MODULE_NAME, + "AutoopenLimits", VIPM_PARAM_TYPE_LIMITS_NAME, false, + "AutoopenDelay", DEFAULT_PARAMS_FLOAT_NAME, false, + "AutoopenCloseDelay", DEFAULT_PARAMS_FLOAT_NAME, false, + "AutoopenMenuNum", DEFAULT_PARAMS_INT_NAME, false ); - VipM_Modules_AddParams(MODULE_NAME, - "StayOpen", ptBoolean, false, - "StayOpen_CheckCounter", ptBoolean, false + VipM_Modules_AddParamsEx(MODULE_NAME, + "StayOpen", DEFAULT_PARAMS_BOOL_NAME, false, + "StayOpen_CheckCounter", DEFAULT_PARAMS_BOOL_NAME, false, + "StayOpen_WhenRestricted", DEFAULT_PARAMS_BOOL_NAME, false ); VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnActivated, "@OnModuleActivate"); VipM_Modules_RegisterEvent(MODULE_NAME, Module_OnRead, "@OnReadConfig"); } -@OnReadConfig(const JSON:jCfg, Trie:Params) { - if (!json_object_has_value(jCfg, "Menus", JSONArray)) { - log_amx("[WARNING] Param `Menus` required for module `%s`.", MODULE_NAME); +@OnReadConfig(const JSON:jCfg, Trie:tParams) { + if (!json_object_has_value(jCfg, "Menus")) { + PCJson_LogForFile(jCfg, "WARNING", "Param 'Menus' required for module '%s'.", MODULE_NAME); return VIPM_STOP; } + + TrieSetCell(tParams, "Menus", Json_Object_GetWeaponMenusList(jCfg, "Menus")); - new JSON:jMenus = json_object_get_value(jCfg, "Menus"); - new Array:aMenus = Cfg_ReadMenus(jMenus); - TrieSetCell(Params, "Menus", aMenus); - - if (!TrieKeyExists(Params, "MainMenuTitle")) { - TrieSetString(Params, "MainMenuTitle", Lang("MENU_MAIN_TITLE")); + if (!TrieKeyExists(tParams, "MainMenuTitle")) { + TrieSetString(tParams, "MainMenuTitle", Lang("MENU_MAIN_TITLE")); } return VIPM_CONTINUE; @@ -89,284 +82,271 @@ public VipM_OnInitModules() { @OnModuleActivate() { RegisterHookChain(RG_CBasePlayer_Spawn, "@OnPlayerSpawn", true); RegisterHookChain(RG_CSGameRules_RestartRound, "@OnRestartRound", false); - - CommandAliases_Open(GET_FILE_JSON_PATH("Cmds/WeaponMenu"), true); - CommandAliases_RegisterClient(CMD_WEAPON_MENU, "@Cmd_Menu"); // vipmenu - CommandAliases_RegisterClient(CMD_WEAPON_MENU_SILENT, "@Cmd_MenuSilent"); - CommandAliases_RegisterClient(CMD_SWITCH_AUTOOPEN, "@Cmd_SwitchAutoOpen"); - CommandAliases_Close(); -} -ResetUserMenuCounters(const UserId) { - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); + register_clcmd(VIPM_M_WEAPONMENU_CMD_MENU, "@Cmd_Menu"); + register_clcmd(VIPM_M_WEAPONMENU_CMD_MENU_SILENT, "@Cmd_MenuSilent"); + register_clcmd(VIPM_M_WEAPONMENU_CMD_AUTOOPEN_TOGGLE, "@Cmd_SwitchAutoOpen"); +} - gUserLeftItems[UserId] = VipM_Params_GetInt(Params, "Count", -1); - g_tUserMenuItemsCounter[UserId] = KeyValueCounter_Reset(g_tUserMenuItemsCounter[UserId]); +ResetUserMenuCounters(const playerIndex) { + new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, playerIndex); - gUserShouldResetCounters[UserId] = false; + gUserLeftItems[playerIndex] = PCGet_Int(Params, "Count", -1); + g_tUserMenuItemsCounter[playerIndex] = KeyValueCounter_Reset(g_tUserMenuItemsCounter[playerIndex]); - Dbg_Log("ResetUserMenuCounters(%n): gUserLeftItems[UserId] = %d", UserId, gUserLeftItems[UserId]); + gUserShouldResetCounters[playerIndex] = false; } -public client_putinserver(UserId) { - gUserShouldResetCounters[UserId] = true; - gUserExpireStatus[UserId][0] = 0; +public client_putinserver(playerIndex) { + gUserShouldResetCounters[playerIndex] = true; + gUserExpireStatus[playerIndex][0] = 0; } -public client_disconnected(UserId) { - AbortAutoCloseMenu(UserId); +public client_disconnected(playerIndex) { + AbortAutoCloseMenu(playerIndex); } @OnRestartRound() { - for (new UserId = 1; UserId <= MAX_PLAYERS; UserId++) { - gUserShouldResetCounters[UserId] = true; + for (new playerIndex = 1; playerIndex <= MAX_PLAYERS; playerIndex++) { + gUserShouldResetCounters[playerIndex] = true; } - Dbg_Log("@OnRestartRound(): Should reset all counters."); } -@OnPlayerSpawn(const UserId) { - if (!IsUserValidA(UserId)) { - Dbg_Log("@OnPlayerSpawn(%n): Invalid (or dead) player", UserId); +@OnPlayerSpawn(const playerIndex) { + if (!is_user_alive(playerIndex)) { return; } - if (gUserShouldResetCounters[UserId]) { - ResetUserMenuCounters(UserId); - } else { - Dbg_Log("@OnPlayerSpawn(%n): Shouldn't reset counter", UserId); + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); + + if (gUserShouldResetCounters[playerIndex] || PCGet_Bool(p, "ResetCountOnSpawn", false)) { + ResetUserMenuCounters(playerIndex); } // TODO: Добавить квар для отключения авто-открытия - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); - - if (!gUserAutoOpen[UserId]) { + if (!gUserAutoOpen[playerIndex]) { return; } - if (VipM_Params_GetArr(Params, "Menus") == Invalid_Array) { + if (VipM_Params_GetArr(p, "Menus") == Invalid_Array) { return; } - if (!VipM_Params_ExecuteLimitsList(Params, "AutoopenLimits", UserId, Limit_Exec_AND)) { + if (!PCGet_VipmLimitsCheck(p, "AutoopenLimits", playerIndex, Limit_Exec_AND)) { return; } - set_task(VipM_Params_GetFloat(Params, "AutoopenDelay", 0.0), "@Task_AutoOpen", TASK_OFFSET_AUTO_OPEN + UserId); + set_task(PCGet_Float(p, "AutoopenDelay", 0.0), "@Task_AutoOpen", TASK_OFFSET_AUTO_OPEN + playerIndex); } -@Task_AutoOpen(UserId) { - UserId -= TASK_OFFSET_AUTO_OPEN; +@Task_AutoOpen(playerIndex) { + playerIndex -= TASK_OFFSET_AUTO_OPEN; - new Trie:tParams = VipM_Modules_GetParams(MODULE_NAME, UserId); - new Float:fAutoCloseDelay = VipM_Params_GetFloat(tParams, "AutoopenCloseDelay", 0.0); - new iMenuNum = VipM_Params_GetInt(tParams, "AutoopenMenuNum", -1); + new Trie:tParams = VipM_Modules_GetParams(MODULE_NAME, playerIndex); + new Float:fAutoCloseDelay = PCGet_Float(tParams, "AutoopenCloseDelay", 0.0); + new iMenuNum = PCGet_Int(tParams, "AutoopenMenuNum", -1); if (iMenuNum > 0) { - CommandAliases_ClientCmd(UserId, CMD_WEAPON_MENU_SILENT, IntToStr(iMenuNum - 1)); + client_cmd(playerIndex, "%s %d", VIPM_M_WEAPONMENU_CMD_MENU_SILENT, iMenuNum - 1); } else { - CommandAliases_ClientCmd(UserId, CMD_WEAPON_MENU_SILENT); + client_cmd(playerIndex, VIPM_M_WEAPONMENU_CMD_MENU_SILENT); } - Dbg_PrintServer("@Task_AutoOpen(%d): fAutoCloseDelay = %.2f", UserId, fAutoCloseDelay); if (fAutoCloseDelay > 0.0) { - Dbg_PrintServer("@Task_AutoOpen(%d): Start auto close task", UserId); - set_task(fAutoCloseDelay, "@Task_AutoClose", TASK_OFFSET_AUTO_CLOSE + UserId); + set_task(fAutoCloseDelay, "@Task_AutoClose", TASK_OFFSET_AUTO_CLOSE + playerIndex); } } -@Task_AutoClose(UserId) { - Dbg_PrintServer("@Task_AutoClose(%d)", UserId); - UserId -= TASK_OFFSET_AUTO_CLOSE; - menu_cancel(UserId); - show_menu(UserId, 0, ""); +@Task_AutoClose(playerIndex) { + playerIndex -= TASK_OFFSET_AUTO_CLOSE; + menu_cancel(playerIndex); + show_menu(playerIndex, 0, ""); } -AbortAutoCloseMenu(const UserId) { - remove_task(TASK_OFFSET_AUTO_CLOSE + UserId); +AbortAutoCloseMenu(const playerIndex) { + remove_task(TASK_OFFSET_AUTO_CLOSE + playerIndex); } -@Cmd_SwitchAutoOpen(const UserId) { - gUserAutoOpen[UserId] = !gUserAutoOpen[UserId]; - ChatPrintL(UserId, gUserAutoOpen[UserId] ? "MSG_AUTOOPEN_TURNED_ON" : "MSG_AUTOOPEN_TURNED_OFF"); +@Cmd_SwitchAutoOpen(const playerIndex) { + gUserAutoOpen[playerIndex] = !gUserAutoOpen[playerIndex]; + ChatPrintL(playerIndex, gUserAutoOpen[playerIndex] ? "MSG_AUTOOPEN_TURNED_ON" : "MSG_AUTOOPEN_TURNED_OFF"); return PLUGIN_HANDLED; } -@Cmd_Menu(const UserId) { - _Cmd_Menu(UserId); +@Cmd_Menu(const playerIndex) { + _Cmd_Menu(playerIndex); return PLUGIN_HANDLED; } -@Cmd_MenuSilent(const UserId) { - _Cmd_Menu(UserId, true); +@Cmd_MenuSilent(const playerIndex) { + _Cmd_Menu(playerIndex, true); return PLUGIN_HANDLED; } -_Cmd_Menu(const UserId, const bool:bSilent = false) { - if (!IsUserValid(UserId)) { - Dbg_Log("_Cmd_Menu(%d, %s): Invalid player", UserId, bSilent ? "true" : "false"); +_Cmd_Menu(const playerIndex, const bool:bSilent = false) { + if (!is_user_connected(playerIndex)) { return; } - if (!is_user_alive(UserId)) { - if (!bSilent) { - ChatPrintL(UserId, "MSG_YOU_DEAD"); - } - - Dbg_Log("_Cmd_Menu(%n, %s): Player is dead", UserId, bSilent ? "true" : "false"); + if (!is_user_alive(playerIndex)) { + ChatPrintLIf(!bSilent, playerIndex, "MSG_YOU_DEAD"); return; } - new Trie:Params = VipM_Modules_GetParams(MODULE_NAME, UserId); - new Array:aMenus = VipM_Params_GetArr(Params, "Menus"); + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); + new Array:aMenus = VipM_Params_GetArr(p, "Menus"); if (ArraySizeSafe(aMenus) < 1) { - if (!bSilent) { - ChatPrintL(UserId, "MSG_NO_ACCESS"); - } - - Dbg_Log("_Cmd_Menu(%n, %s): No access", UserId, bSilent ? "true" : "false"); + ChatPrintLIf(!bSilent, playerIndex, "MSG_NO_ACCESS"); return; } - if (!VipM_Params_ExecuteLimitsList(Params, "Limits", UserId, Limit_Exec_AND)) { - if (!bSilent) { - ChatPrintL(UserId, "MSG_MAIN_NOT_PASSED_LIMIT"); - } - - Dbg_Log("_Cmd_Menu(%n, %s): Not passed main limits", UserId, bSilent ? "true" : "false"); + if (!PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND)) { + ChatPrintLIf(!bSilent, playerIndex, "MSG_MAIN_NOT_PASSED_LIMIT"); return; } - CMD_INIT_PARAMS(); - - if (CMD_ARG_NUM() < 1) { + if (read_argc() < 2) { if (ArraySizeSafe(aMenus) == 1) { - CommandAliases_ClientCmd(UserId, CMD_WEAPON_MENU, "0"); + client_cmd(playerIndex, "%s %d", VIPM_M_WEAPONMENU_CMD_MENU, 0); } else { - static MainMenuTitle[128]; - VipM_Params_GetStr(Params, "MainMenuTitle", MainMenuTitle, charsmax(MainMenuTitle)); - Menu_MainMenu(UserId, MainMenuTitle, aMenus); + Menu_MainMenu(playerIndex, PCGet_iStr(p, "MainMenuTitle", uLang(playerIndex, "MENU_MAIN_TITLE")), aMenus); } + return; } - new MenuId = read_argv_int(CMD_ARG(1)); - if ( - ArraySizeSafe(aMenus) <= MenuId - || MenuId < 0 - ) { - Dbg_Log("_Cmd_Menu(%n, %s): Invalid menu id (%d)", UserId, bSilent ? "true" : "false", MenuId); + new menuIndex = read_argv_int(1); + if (menuIndex >= ArraySizeSafe(aMenus) || menuIndex < 0) { return; } static Menu[S_WeaponMenu]; - ArrayGetArray(aMenus, MenuId, Menu); + ArrayGetArray(aMenus, menuIndex, Menu); - if (!VipM_Limits_ExecuteList(Menu[WeaponMenu_Limits], UserId)) { - if (!bSilent) { - ChatPrintL(UserId, "MSG_MENU_NOT_PASSED_LIMIT"); + if (Menu[WeaponMenu_Limits] != Invalid_Array && !VipM_Limits_ExecuteList(Menu[WeaponMenu_Limits], playerIndex, Limit_Exec_AND)) { + ChatPrintLIf(!bSilent, playerIndex, "MSG_MENU_NOT_PASSED_LIMIT"); + + if (PCGet_Bool(p, "StayOpen_WhenRestricted", false)) { + client_cmd(playerIndex, VIPM_M_WEAPONMENU_CMD_MENU_SILENT); } - Dbg_Log("_Cmd_Menu(%n, %s): Not passed menu limits", UserId, bSilent ? "true" : "false"); return; } - if (Menu[WeaponMenu_Fake]) { - if (Menu[WeaponMenu_FakeMessage][0]) { - ChatPrint(UserId, Menu[WeaponMenu_FakeMessage]); - } - Dbg_Log("_Cmd_Menu(%n, %s): Fake menu (%s)", UserId, bSilent ? "true" : "false", Menu[WeaponMenu_FakeMessage]); + if (Menu[WeaponMenu_FakeMessage][0]) { + ChatPrint(playerIndex, Menu[WeaponMenu_FakeMessage]); return; } - if (CMD_ARG_NUM() < 2) { - Menu_WeaponsMenu(UserId, MenuId, Menu); + if (read_argc() < 3) { + Menu_WeaponsMenu(playerIndex, menuIndex, Menu); return; } - new ItemId = read_argv_int(CMD_ARG(2)); + new itemIndex = read_argv_int(2); if ( - ArraySizeSafe(Menu[WeaponMenu_Items]) <= ItemId - || ItemId < 0 + ArraySizeSafe(Menu[WeaponMenu_Items]) <= itemIndex + || itemIndex < 0 ) { - Dbg_Log("_Cmd_Menu(%n, %s): Invalid item id (%d)", UserId, bSilent ? "true" : "false", ItemId); return; } - static MenuItem[S_MenuItem]; - ArrayGetArray(Menu[WeaponMenu_Items], ItemId, MenuItem); + static itemObject[S_MenuItem]; + ArrayGetArray(Menu[WeaponMenu_Items], itemIndex, itemObject); - new iItemsLeft = GetUserLeftItems(UserId, MenuId, Menu); + new leftItems = GetUserLeftItems(playerIndex, Menu); if ( - MenuItem[MenuItem_UseCounter] - && iItemsLeft == 0 + itemObject[MenuItem_UseCounter] + && leftItems == 0 ) { - if (!bSilent) { - ChatPrintL(UserId, "MSG_NO_LEFT_ITEMS"); - } - - Dbg_Log("_Cmd_Menu(%n, %s): No left items", UserId, bSilent ? "true" : "false"); + ChatPrintLIf(!bSilent, playerIndex, "MSG_NO_LEFT_ITEMS"); return; } if ( - !VipM_Limits_ExecuteList(MenuItem[MenuItem_ShowLimits], UserId) - || !VipM_Limits_ExecuteList(MenuItem[MenuItem_ActiveLimits], UserId) - || !VipM_Limits_ExecuteList(MenuItem[MenuItem_Limits], UserId) + !VipM_Limits_ExecuteList(itemObject[MenuItem_ShowLimits], playerIndex, Limit_Exec_AND) + || !VipM_Limits_ExecuteList(itemObject[MenuItem_ActiveLimits], playerIndex, Limit_Exec_AND) + || !VipM_Limits_ExecuteList(itemObject[MenuItem_Limits], playerIndex, Limit_Exec_AND) ) { - if (!bSilent) { - ChatPrintL(UserId, "MSG_MENUITEM_NOT_PASSED_LIMIT"); + ChatPrintLIf(!bSilent, playerIndex, "MSG_MENUITEM_NOT_PASSED_LIMIT"); + + if (PCGet_Bool(p, "StayOpen_WhenRestricted", false)) { + client_cmd(playerIndex, "%s %d", VIPM_M_WEAPONMENU_CMD_MENU_SILENT, menuIndex); } - Dbg_Log("_Cmd_Menu(%n, %s): Not passed item limits", UserId, bSilent ? "true" : "false"); return; } if ( - VipM_IC_GiveItems(UserId, MenuItem[MenuItem_Items]) - && MenuItem[MenuItem_UseCounter] + IC_Item_GiveArray(playerIndex, itemObject[MenuItem_Items]) + && itemObject[MenuItem_UseCounter] ) { - gUserLeftItems[UserId]--; - - if (Menu[WeaponMenu_Count]) { - KeyValueCounter_Inc(g_tUserMenuItemsCounter[UserId], IntToStr(MenuId)); - } + IncUserMenuCounters(playerIndex, Menu); } if ( - VipM_Params_GetBool(Params, "StayOpen", false) + PCGet_Bool(p, "StayOpen", false) && ( - !VipM_Params_GetBool(Params, "StayOpen_CheckCounter", true) - || iItemsLeft != 0 + !PCGet_Bool(p, "StayOpen_CheckCounter", true) + || leftItems != 0 ) ) { - CommandAliases_ClientCmd(UserId, CMD_WEAPON_MENU, "%d", MenuId); + client_cmd(playerIndex, "%s %d", VIPM_M_WEAPONMENU_CMD_MENU, menuIndex); } } -GetUserLeftItems(const UserId, const MenuId, const Menu[S_WeaponMenu]) { - new iUserItemsLeft = gUserLeftItems[UserId]; - new iMenuItemsLeft = Menu[WeaponMenu_Count] - KeyValueCounter_Get(g_tUserMenuItemsCounter[UserId], IntToStr(MenuId)); - - Dbg_Log("GetUserLeftItems(%n, %d, %d): iUserItemsLeft = %d", UserId, MenuId, Menu[WeaponMenu_Name], iUserItemsLeft); - Dbg_Log("GetUserLeftItems(%n, %d, %d): iMenuItemsLeft = %d", UserId, MenuId, Menu[WeaponMenu_Name], iMenuItemsLeft); - Dbg_Log("GetUserLeftItems(%n, %d, %d): Menu[WeaponMenu_Count] = %d", UserId, MenuId, Menu[WeaponMenu_Name], Menu[WeaponMenu_Count]); - Dbg_Log("GetUserLeftItems(%n, %d, %d): g_tUserMenuItemsCounter[UserId] = %d", UserId, MenuId, Menu[WeaponMenu_Name], KeyValueCounter_Get(g_tUserMenuItemsCounter[UserId], IntToStr(MenuId))); - - if (iUserItemsLeft < 0) { - Dbg_Log("GetUserLeftItems(%n, %d, %d): return %d (no global limit)", UserId, MenuId, Menu[WeaponMenu_Name], iMenuItemsLeft); - return iMenuItemsLeft; +IncUserMenuCounters(const playerIndex, const menuObject[S_WeaponMenu]) { + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); + + VipM_L_Counter_Inc( + PCGet_VipmCounterType(p, "CounterType", VipM_L_Counter_PerLife), + PCGet_iStr(p, "CounterKey", VIPM_M_WEAPONMENU_PLAYER_COUNTER_KEY), + playerIndex + ); + + VipM_L_Counter_Inc( + menuObject[WeaponMenu_CounterType], + menuObject[WeaponMenu_CounterKey], + playerIndex + ); +} + +GetUserLeftItems(const playerIndex, const menuObject[S_WeaponMenu]) { + new Trie:p = VipM_Modules_GetParams(MODULE_NAME, playerIndex); + + new maxPlayer = PCGet_Int(p, "Count", -1); + new maxMenu = menuObject[WeaponMenu_Count]; + + if (maxPlayer < 0 && maxMenu < 0) { + return -1; } - if (Menu[WeaponMenu_Count] < 0) { - Dbg_Log("GetUserLeftItems(%n, %d, %d): return %d (no menu limit)", UserId, MenuId, Menu[WeaponMenu_Name], iUserItemsLeft); - return iUserItemsLeft; + new usedPlayer = VipM_L_Counter_Get( + PCGet_VipmCounterType(p, "CounterType", VipM_L_Counter_PerLife), + PCGet_iStr(p, "CounterKey", VIPM_M_WEAPONMENU_PLAYER_COUNTER_KEY), + playerIndex + ); + + new usedMenu = VipM_L_Counter_Get( + menuObject[WeaponMenu_CounterType], + menuObject[WeaponMenu_CounterKey], + playerIndex + ); + + + if (maxPlayer < 0) { + return maxMenu - usedMenu; + } else if (maxMenu < 0) { + return maxPlayer - usedPlayer; + } else { + return min( + maxPlayer - usedPlayer, + maxMenu - usedMenu + ); } - - Dbg_Log("GetUserLeftItems(%n, %d, %d): return %d (has both limits)", UserId, MenuId, Menu[WeaponMenu_Name], min(iUserItemsLeft, iMenuItemsLeft)); - return min(iUserItemsLeft, iMenuItemsLeft); } #include "VipM/WeaponMenu/Natives" diff --git a/amxmodx/scripting/VipM-Misc.sma b/amxmodx/scripting/VipM-Misc.sma index 2319fcf..cd7cdf0 100644 --- a/amxmodx/scripting/VipM-Misc.sma +++ b/amxmodx/scripting/VipM-Misc.sma @@ -3,31 +3,66 @@ #include #include "VipM/Utils" -#pragma semicolon 1 -#pragma compress 1 +#define RELOAD_ON_PLAYER_SPAWN 1 +#define RELOAD_ON_ROUND_START 1 +#define RELOAD_ON_ROUND_END 1 public stock const PluginName[] = "[VipM] Misc"; public stock const PluginVersion[] = _VIPM_VERSION; public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; -public stock const PluginDescription[] = "Some extentions for Vip Modular."; +public stock const PluginDescription[] = "Auto reload player's privilegies."; -public VipM_OnLoaded(){ - RegisterPluginByVars(); +public VipM_OnLoaded() { + register_plugin(PluginName, PluginVersion, PluginAuthor); - RegisterHookChain(RG_CBasePlayer_Spawn, "@OnPlayerSpawned", false); + #if RELOAD_ON_PLAYER_SPAWN + RegisterHookChain(RG_CBasePlayer_Spawn, "@ReloadPlayer", false); + #endif + + #if RELOAD_ON_ROUND_START + RegisterHookChain(RG_CSGameRules_RestartRound, "@ReloadAllPlayers", false); + #endif + + #if RELOAD_ON_ROUND_END + RegisterHookChain(RG_RoundEnd, "@ReloadAllPlayers", false); + #endif - register_srvcmd("vipm_update_users", "@SrvCmd_UpdateUsers"); + register_srvcmd("vipm_update_users", "@SrvCmd_ReloadPlayers"); + register_srvcmd("vipm_reload_players", "@SrvCmd_ReloadPlayers"); + register_srvcmd("vipm_reload_player", "@SrvCmd_ReloadPlayer"); } -@OnPlayerSpawned(const UserId){ - VipM_UserUpdate(UserId); +@ReloadPlayer(const playerIndex) { + VipM_UserUpdate(playerIndex); } -@SrvCmd_UpdateUsers() { - for (new UserId = 1; UserId <= MAX_PLAYERS; UserId++) { - if (is_user_connected(UserId) && !is_user_bot(UserId)) { - VipM_UserUpdate(UserId); +@ReloadAllPlayers() { + for (new playerIndex = 1; playerIndex <= MAX_PLAYERS; ++playerIndex) { + if ( + is_user_connected(playerIndex) + && !is_user_bot(playerIndex) + && !is_user_hltv(playerIndex) + ) { + @ReloadPlayer(playerIndex); } } } + +@SrvCmd_ReloadPlayers() { + @ReloadAllPlayers(); +} + +@SrvCmd_ReloadPlayer() { + enum {Arg_PlayerIndex = 1} + + if (read_argc() < Arg_PlayerIndex) { + server_print("Invalid command params."); + server_print("Usage: vipm_reload_players "); + return; + } + + new playerIndex = read_argv_int(Arg_PlayerIndex); + + @ReloadPlayer(playerIndex); +} diff --git a/amxmodx/scripting/VipM-ModulesLimiter.sma b/amxmodx/scripting/VipM-ModulesLimiter.sma index 80b8607..94d4537 100644 --- a/amxmodx/scripting/VipM-ModulesLimiter.sma +++ b/amxmodx/scripting/VipM-ModulesLimiter.sma @@ -1,7 +1,9 @@ #include #include +#include +#include #include "VipM/Utils" -#include "VipM/DebugMode" +#include "VipM/ArrayTrieUtils" public stock const PluginName[] = "[VipM] Modules Limiter"; public stock const PluginVersion[] = _VIPM_VERSION; @@ -9,35 +11,77 @@ public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; public stock const PluginDescription[] = "Modules activation controller"; -#include "VipM/ModulesLimiter/Configs" +new const CONFIG_FILE_PATH[] = "Modules.json"; -new const MODULES_CONFIG_FILE[] = "Modules"; +new Trie:ModulesLimits = Invalid_Trie; -new Trie:g_tModulesLimits = Invalid_Trie; - -public VipM_OnLoaded() { - RegisterPluginByVars(); +public VipM_Modules_OnInited() { + register_plugin(PluginName, PluginVersion, PluginAuthor); - g_tModulesLimits = Configs_LoadModulesLimitsFromFile(MODULES_CONFIG_FILE, g_tModulesLimits); + ModulesLimits = LoadModulesLimitsFromFile(PCPath_iMakePath(fmt("%s/%s", VIPM_CONFIGS_FOLDER_NAME, CONFIG_FILE_PATH))); } -public VipM_OnActivateModule(const sModuleName[]) { +public VipM_Modules_OnActivate(const moduleName[]) { if ( - g_tModulesLimits == Invalid_Trie - || !TrieKeyExists(g_tModulesLimits, sModuleName) + ModulesLimits == Invalid_Trie + || !TrieKeyExists(ModulesLimits, moduleName) ) { - Dbg_Log("Module `%s` activated. (!TrieKeyExists)", sModuleName); + log_amx("Module `%s` is not limited.", moduleName); return VIPM_CONTINUE; } - new Array:aLimits; - TrieGetCell(g_tModulesLimits, sModuleName, aLimits); - if (!VipM_Limits_ExecuteList(aLimits)) { - Dbg_Log("Module `%s` not ativated.", sModuleName); + new Array:limits; + TrieGetCell(ModulesLimits, moduleName, limits); + if (!VipM_Limits_ExecuteList(limits)) { + log_amx("Module `%s` is disabled by limits.", moduleName); return VIPM_STOP; + } else { + log_amx("Module `%s` is enabled by limits.", moduleName); } - Dbg_Log("Module `%s` activated. (Limits passed)", sModuleName); - return VIPM_CONTINUE; } + +Trie:LoadModulesLimitsFromFile(const filePath[], &Trie:modules = Invalid_Trie) { + if (modules == Invalid_Trie) { + modules = TrieCreate(); + } + + new JSON:fileJson = PCJson_ParseFile(filePath); + if (fileJson == Invalid_JSON) { + log_error(0, "Invalid JSON syntax. File `%s`.", filePath); + return modules; + } + + if (!json_is_array(fileJson)) { + PCJson_LogForFile(fileJson, "WARNING", "Root value must be an array."); + PCJson_Free(fileJson); + return modules; + } + + json_array_foreach_value (fileJson: i => itemJson) { + if (!json_is_object(itemJson)) { + PCJson_LogForFile(itemJson, "WARNING", "Array item #%d isn`t object.", i); + json_free(itemJson); + continue; + } + + new Array:limits = PCSingle_ObjVipmLimits(itemJson, "Limits"); + new Array:moduleNames = json_object_get_strings_list(itemJson, "Modules", VIPM_MODULES_TYPE_NAME_MAX_LEN); + + ArrayForeachString (moduleNames: j => moduleName[VIPM_MODULES_TYPE_NAME_MAX_LEN]) { + if (TrieKeyExists(modules, moduleName)) { + PCJson_LogForFile(itemJson, "WARNING", "Duplicate limits for module `%s`.", moduleName); + continue; + } + + TrieSetCell(modules, moduleName, limits); + } + + json_free(itemJson); + ArrayDestroy(moduleNames); + } + + PCJson_Free(fileJson); + return modules; +} diff --git a/amxmodx/scripting/VipM/ArrayMap.inc b/amxmodx/scripting/VipM/ArrayMap.inc index 8dd3d76..dc42317 100644 --- a/amxmodx/scripting/VipM/ArrayMap.inc +++ b/amxmodx/scripting/VipM/ArrayMap.inc @@ -3,103 +3,125 @@ #endif #define _vipmodular_src_ArrayMap_included -#include amxmodx +#include -enum ArrayMap{ +enum ArrayMap { Array:AM_Arr, Trie:AM_Map, } -#define ArrayMap(%1) \ - %1[ArrayMap] +#define ArrayMap(%1) %1[ArrayMap] -#define DefineArrayMap(%1) \ - new ArrayMap(%1) - -#define DefineStaticArrayMap(%1) \ - static ArrayMap(%1) +stock ArrayMapCreate(ArrayMap(am), const CellSize = 1, const Reserved = 1) { + am[AM_Arr] = ArrayCreate(CellSize, Reserved); + am[AM_Map] = TrieCreate(); +} -stock InitArrayMap(AM[ArrayMap], const CellSize = 1, const Reserved = 32){ - AM[AM_Arr] = ArrayCreate(CellSize, Reserved); - AM[AM_Map] = TrieCreate(); +stock bool:ArrayMapCreated(const ArrayMap(am)) { + return am[AM_Arr] != Invalid_Array; } -stock ArrayMapPushArray(AM[ArrayMap], const any:Input[], const Key[], Size = -1){ - new Id = ArrayPushArray(AM[AM_Arr], Input, Size); - TrieSetCell(AM[AM_Map], Key, Id, true); - return Id; +stock ArrayMapDestroy(ArrayMap(am)) { + if (ArrayMapCreated(am)) { + ArrayDestroy(am[AM_Arr]); + TrieDestroy(am[AM_Map]); + } } -stock ArrayMapPushString(AM[ArrayMap], const Input[], const Key[]){ - new Id = ArrayPushString(AM[AM_Arr], Input); - TrieSetCell(AM[AM_Map], Key, Id, true); - return Id; +stock ArrayMapSize(const ArrayMap(am)) { + if (ArrayMapCreated(am)) { + return ArraySize(am[AM_Arr]); + } + + return 0; } -stock ArrayMapPushCell(AM[ArrayMap], any:Input, const Key[]){ - new Id = ArrayPushCell(AM[AM_Arr], Input); - TrieSetCell(AM[AM_Map], Key, Id, true); - return Id; +stock bool:ArrayMapKeyExists(const ArrayMap(am), const key[]) { + return TrieKeyExists(am[AM_Map], key); } -stock ArrayMapGetIndex(AM[ArrayMap], const Key[]){ - new Id = -1; - TrieGetCell(AM[AM_Map], Key, Id); - return Id; +stock ArrayMapGetIndex(const ArrayMap(am), const key[]) { + new index = -1; + TrieGetCell(am[AM_Map], key, index); + + return index; } +// cell -#define ArrayMapForeach(%1,%2) \ - if(ArrayMapCreated(%1))\ - for(new %2 = 0; %2 < ArrayMapSize(%1); %2++) +stock ArrayMapPushCell(const ArrayMap(am), any:index, const key[]) { + new index = ArrayPushCell(am[AM_Arr], index); + TrieSetCell(am[AM_Map], key, index, .replace = false); -#define ArrayMapForeachArray(%1=>%2[%3]) \ - ArrayMapForeachArrayEx(%1=>%2[%3], __i__) + return index; +} -#define ArrayMapForeachArrayEx(%1=>%2[%3],%4) \ - if(ArrayMapCreated(%1))\ - for(new %2[%3], %4 = 0; %4 < ArrayMapSize(%1); %4++)\ - if(ArrayMapGetiArray(%1, %4, %2)) +stock ArrayMapGetCell(const ArrayMap(am), const any:index, const block = 0, const bool:asChar = false) { + return ArrayGetCell(am[AM_Arr], index, block, asChar); +} -#define ArrayMapForeachArray2(%1:%4=>%2[%3]) \ - if(ArrayMapCreated(%1)) \ - for(new %2[%3], %4 = 0; %4 < ArrayMapSize(%1); %4++) \ - if(ArrayMapGetiArray(%1, %4, %2)) +stock ArrayMapGetCellByKey(const ArrayMap(am), const key[], const block = 0, const bool:asChar = false) { + return ArrayGetCell(am[AM_Arr], ArrayMapGetIndex(am, key), block, asChar); +} +stock ArrayMapSetCell(const ArrayMap(am), const any:index, const in, const block = 0, const bool:asChar = false) { + return ArraySetCell(am[AM_Arr], index, in, block, asChar); +} -#define ArrayMapCreated(%1) \ - (%1[AM_Arr] != Invalid_Array) +stock ArrayMapSetCellByKey(const ArrayMap(am), const key[], const in, const block = 0, const bool:asChar = false) { + return ArraySetCell(am[AM_Arr], ArrayMapGetIndex(am, key), in, block, asChar); +} -#define ArrayMapDestroy(%1) \ - if(ArrayMapCreated(%1)){\ - ArrayDestroy(%1[AM_Arr]); TrieDestroy(%1[AM_Map]);\ - } +// string -#define ArrayMapSize(%1) \ - (ArrayMapCreated(%1) ? ArraySize(%1[AM_Arr]) : 0) +stock ArrayMapPushString(const ArrayMap(am), const Input[], const sKey[]) { + new index = ArrayPushString(am[AM_Arr], Input); + TrieSetCell(am[AM_Map], sKey, index, .replace = false); -#define ArrayMapHasKey(%1,%2) \ - (%2[0] && TrieKeyExists(%1[AM_Map], %2)) - + return index; +} -#define ArrayMapGetiArray(%1,%2,%3) \ - ArrayGetArray(%1[AM_Arr], %2, %3) +stock ArrayMapGetString(const ArrayMap(am), const any:index, out[], const outLen) { + return ArrayGetString(am[AM_Arr], index, out, outLen); +} -#define ArrayMapGetArray(%1,%2,%3) \ - ArrayMapGetiArray(%1, ArrayMapGetIndex(%1, %2), %3) +stock ArrayMapGetStringByKey(const ArrayMap(am), const key[], out[], const outLen) { + return ArrayGetString(am[AM_Arr], ArrayMapGetIndex(am, key), out, outLen); +} + +stock ArrayMapSetString(const ArrayMap(am), const any:index, const in[]) { + return ArraySetString(am[AM_Arr], index, in); +} + +stock ArrayMapSetStringByKey(const ArrayMap(am), const key[], const in[]) { + return ArraySetString(am[AM_Arr], ArrayMapGetIndex(am, key), in); +} + +// array -#define ArrayMapSetArray(%1,%2,%3) \ - ArraySetArray(%1[AM_Arr], ArrayMapGetIndex(%1, %2), %3) - +stock ArrayMapPushArray(const ArrayMap(am), const any:Input[], const sKey[], size = -1) { + new index = ArrayPushArray(am[AM_Arr], Input, size); + TrieSetCell(am[AM_Map], sKey, index, .replace = false); -#define ArrayMapGetCell(%1,%2) \ - ArrayGetCell(%1[AM_Arr], ArrayMapGetIndex(%1, %2)) + return index; +} + +stock ArrayMapGetArray(const ArrayMap(am), const any:index, out[], const size = -1) { + return ArrayGetArray(am[AM_Arr], index, out, size); +} -#define ArrayMapSetCell(%1,%2) \ - ArraySetCell(%1[AM_Arr], ArrayMapGetIndex(%1, %2), %3) +stock ArrayMapGetArrayByKey(const ArrayMap(am), const key[], out[], const size = -1) { + return ArrayGetArray(am[AM_Arr], ArrayMapGetIndex(am, key), out, size); +} +stock ArrayMapSetArray(const ArrayMap(am), const any:index, const in[], const size = -1) { + return ArraySetArray(am[AM_Arr], index, in, size); +} -#define ArrayMapGetString(%1,%2,%3) \ - ArrayGetString(%1[AM_Arr], ArrayMapGetIndex(%1, %2), %3) +stock ArrayMapSetArrayByKey(const ArrayMap(am), const key[], const in[], const size = -1) { + return ArraySetArray(am[AM_Arr], ArrayMapGetIndex(am, key), in, size); +} -#define ArrayMapSetString(%1,%2,%3) \ - ArraySetString(%1[AM_Arr], ArrayMapGetIndex(%1, %2), %3) +#define ArrayMapForeachArray(%1:%4=>%2[%3]) \ + if (ArrayMapCreated(%1)) \ + for (new %2[%3], any:%4 = 0; %4 < ArrayMapSize(%1); %4++) \ + if (ArrayMapGetArray(%1, %4, %2)) diff --git a/amxmodx/scripting/VipM/ArrayTrieUtils.inc b/amxmodx/scripting/VipM/ArrayTrieUtils.inc index 6af950d..be6bc53 100644 --- a/amxmodx/scripting/VipM/ArrayTrieUtils.inc +++ b/amxmodx/scripting/VipM/ArrayTrieUtils.inc @@ -3,71 +3,26 @@ #endif #define _vipmodular_src_ArrayTrieUtils_included -#include amxmodx +#include -#define ArraySizeSafe(%1) \ - (%1 == Invalid_Array ? 0 : ArraySize(%1)) - -#define TrieSizeSafe(%1) \ - (%1 == Invalid_Trie ? 0 : TrieGetSize(%1)) - -stock ArrayDestroySafe(Array:a) { - if (a != Invalid_Array) { - ArrayDestroy(a); - } -} - -stock TrieDestroySafe(Trie:t) { - if (t != Invalid_Trie) { - TrieDestroy(t); - } +stock ArraySizeSafe(const Array:h) { + return h == Invalid_Array ? 0 : ArraySize(h); } -#define ArrayForeachArray(%1=>%2[%3]) \ - ArrayForeachArrayEx(%1 => %2[%3], __i__) - -#define ArrayForeachArrayEx(%1=>%2[%3],%4) \ - if(%1 != Invalid_Array)\ - for(new %2[%3], %4 = 0; %4 < ArraySizeSafe(%1); %4++)\ - if(ArrayGetArray(%1, %4, %2)) - #define ArrayForeachArray2(%1:%4=>%2[%3]) \ - if(%1 != Invalid_Array) \ - for(new %2[%3], %4 = 0; %4 < ArraySizeSafe(%1); %4++) \ - if(ArrayGetArray(%1, %4, %2)) + if (%1 != Invalid_Array) \ + for (new %2[%3], %4 = 0; %4 < ArraySizeSafe(%1); %4++) \ + if (ArrayGetArray(%1, %4, %2)) #define ArrayForeachString(%1:%4=>%2[%3]) \ - if(%1 != Invalid_Array) \ - for(new %2[%3], %4 = 0; %4 < ArraySizeSafe(%1); %4++) \ - if(ArrayGetString(%1, %4, %2, charsmax(%2))) + if (%1 != Invalid_Array) \ + for (new %2[%3], %4 = 0; %4 < ArraySizeSafe(%1); %4++) \ + if (ArrayGetString(%1, %4, %2, charsmax(%2))) -#define ArrayCreateIfNotCreated(%1,%2) \ - %1 = (%1 == Invalid_Array) \ - ? ArrayCreate(%2) \ - : %1 - -#define TrieCreateIfNotCreated(%1) \ - %1 = (%1 == Invalid_Trie) \ - ? TrieCreate() \ - : %1 - -#define ArrayDestroyIfEmpty(%1) \ - CompositeMacros( \ - if(!ArraySizeSafe(%1)) \ - ArrayDestroy(%1); \ - ) - -stock Array:ArrayMergeCells(const Array:a1, const Array:a2) { - new Array:aMerged = ArrayClone(a1); - ArrayResize(aMerged, ArraySizeSafe(a1) + ArraySizeSafe(a2)); - - if (a2 == Invalid_Array) { - return aMerged; - } - - for (mew i = 0; iSize = ArraySizeSafe(a2); i < iSize; i++) { - ArrayPushCell(aMerged, ArrayGetCell(a2, i)); - } +stock Array:ArrayCreateIfNotCreated(&Array:h, const cellsize = 1, const reserved = 1) { + return h = (h == Invalid_Array) ? ArrayCreate(cellsize, reserved) : h; +} - return aMerged; +stock Trie:TrieCreateIfNotCreated(&Trie:h) { + return h = (h == Invalid_Trie) ? TrieCreate() : h; } diff --git a/amxmodx/scripting/VipM/CommandAliases.inc b/amxmodx/scripting/VipM/CommandAliases.inc deleted file mode 100644 index 08070cf..0000000 --- a/amxmodx/scripting/VipM/CommandAliases.inc +++ /dev/null @@ -1,154 +0,0 @@ -#if defined _command_aliases_included - #endinput -#endif -#define _command_aliases_included - -#include -#include - -#define COMMAND_ALIASES_COMMAND_MAX_LENGTH 64 -static const DEFAULT_TEMPLATE_PLACEHOLDER[] = ""; -static const DEFAULT_TEMPLATES[][] = { - "say /", - "say_team /", -}; - -enum _:{ - CommandAliases_CmdType_Client = (1 << 0), - CommandAliases_CmdType_Console = (1 << 1), - CommandAliases_CmdType_Server = (1 << 2), -} - -static JSON:jFile = Invalid_JSON; -static Trie:g_tMainCmd = Invalid_Trie; - -stock bool:CommandAliases_Open(const sFilePath[], const bool:bCreateIfNotExists = false) { - jFile = Invalid_JSON; - - if (!file_exists(sFilePath)) { - if (bCreateIfNotExists) { - new JSON:jObj = json_init_object(); - json_serial_to_file(jObj, sFilePath, true); - json_free(jObj); - } else { - return false; - } - } - - jFile = json_parse(sFilePath, true, true); - - if (jFile == Invalid_JSON) { - log_amx("[CommandAliases][Warn] Can't read from file: %s", sFilePath); - return false; - } - - if (!json_is_object(jFile)) { - jFile = Invalid_JSON; - log_amx("[CommandAliases][Warn] Invalid file format: %s", sFilePath); - return false; - } - - return true; -} - -stock CommandAliases_Close() { - json_free(jFile); -} - -static stock Array:ReadCommandsByKey(const sCmdKey[]) { - new Array:aCmds = Invalid_Array; - - if (jFile == Invalid_JSON) { - aCmds = ArrayCreate(COMMAND_ALIASES_COMMAND_MAX_LENGTH, sizeof DEFAULT_TEMPLATES); - ArrayPushString(aCmds, sCmdKey); - - for (new i = 0; i < sizeof DEFAULT_TEMPLATES; i++) { - new sCmd[COMMAND_ALIASES_COMMAND_MAX_LENGTH]; - copy(sCmd, charsmax(sCmd), DEFAULT_TEMPLATES[i]); - replace(sCmd, charsmax(sCmd), DEFAULT_TEMPLATE_PLACEHOLDER, sCmdKey); - ArrayPushString(aCmds, sCmd); - } - } else { - new JSON:jCmds = json_object_get_value(jFile, sCmdKey); - if (!json_is_array(jCmds)) { - log_amx("[CommandAliases][Warn] Invalid file format. Commands list must be an array."); - return aCmds; - } - - aCmds = ArrayCreate(COMMAND_ALIASES_COMMAND_MAX_LENGTH, json_array_get_count(jCmds)); - - for (new i = 0; i < json_array_get_count(jCmds); i++) { - new sCmd[COMMAND_ALIASES_COMMAND_MAX_LENGTH]; - json_array_get_string(jCmds, i, sCmd, charsmax(sCmd)); - ArrayPushString(aCmds, sCmd); - } - json_free(jCmds); - } - - return aCmds; -} - -stock CommandAliases_Register(const sCmdKey[], const sCallback[], const bitCmdTypes) { - new Array:aCmds = ReadCommandsByKey(sCmdKey); - if (aCmds == Invalid_Array || !ArraySize(aCmds)) { - return; - } - - if (g_tMainCmd == Invalid_Trie) { - g_tMainCmd = TrieCreate(); - } - - new sCmd[COMMAND_ALIASES_COMMAND_MAX_LENGTH]; - ArrayGetString(aCmds, 0, sCmd, charsmax(sCmd)); - TrieSetString(g_tMainCmd, sCmdKey, sCmd); - - for (new i = 0; i < ArraySize(aCmds); i++) { - ArrayGetString(aCmds, i, sCmd, charsmax(sCmd)); - - if (bitCmdTypes & CommandAliases_CmdType_Client) { - register_clcmd(sCmd, sCallback); - } - - if (bitCmdTypes & CommandAliases_CmdType_Console) { - register_concmd(sCmd, sCallback); - } - - if (bitCmdTypes & CommandAliases_CmdType_Server) { - register_srvcmd(sCmd, sCallback); - } - } - ArrayDestroy(aCmds); -} - -stock CommandAliases_RegisterClient(const sCmdKey[], const sCallback[]) { - CommandAliases_Register(sCmdKey, sCallback, CommandAliases_CmdType_Client); -} - -stock CommandAliases_RegisterConsole(const sCmdKey[], const sCallback[]) { - CommandAliases_Register(sCmdKey, sCallback, CommandAliases_CmdType_Console); -} - -stock CommandAliases_RegisterServer(const sCmdKey[], const sCallback[]) { - CommandAliases_Register(sCmdKey, sCallback, CommandAliases_CmdType_Server); -} - -stock CommandAliases_RegisterAll(const sCmdKey[], const sCallback[]) { - CommandAliases_Register(sCmdKey, sCallback, CommandAliases_CmdType_Client|CommandAliases_CmdType_Console|CommandAliases_CmdType_Server); -} - -stock bool:CommandAliases_GetMainCmd(const sCmdKey[], sOut[], const iOutLen) { - return TrieGetString(g_tMainCmd, sCmdKey, sOut, iOutLen); -} - -stock bool:CommandAliases_ClientCmd(const UserId, const sCmdKey[], const sArgsFmt[] = "", any:...) { - static sCmd[COMMAND_ALIASES_COMMAND_MAX_LENGTH], sFormattedArgs[256]; - if (CommandAliases_GetMainCmd(sCmdKey, sCmd, charsmax(sCmd))) { - if (sArgsFmt[0]) { - sFormattedArgs[0] = 0; - vformat(sFormattedArgs, charsmax(sFormattedArgs), sArgsFmt, 4); - client_cmd(UserId, "%s %s", sCmd, sFormattedArgs); - } else { - client_cmd(UserId, "%s", sCmd); - } - } -} diff --git a/amxmodx/scripting/VipM/Core/API/Limits.inc b/amxmodx/scripting/VipM/Core/API/Limits.inc new file mode 100644 index 0000000..ba83539 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/API/Limits.inc @@ -0,0 +1,142 @@ +#include +#include +#include + +#include "VipM/Core/Objects/Limits/Type" +#include "VipM/Core/Objects/Limits/Unit" +#include "VipM/Core/Objects/Param" + +API_Limits_Init() { + register_native("VipM_Limits_RegisterType", "@_Limits_RegisterType"); + register_native("VipM_Limits_AddTypeParams", "@_Limits_AddTypeParams"); + register_native("VipM_Limits_AddParamsEx", "@VipM_Limits_AddParamsEx"); + register_native("VipM_Limits_RegisterTypeEvent", "@_Limits_RegisterTypeEvent"); + + register_native("VipM_Limits_ReadFromJson", "@_Limits_ReadFromJson"); + register_native("VipM_Limits_ReadListFromJson", "@_Limits_ReadListFromJson"); + + register_native("VipM_Limits_SetStaticValue", "@_Limits_SetStaticValue"); + + register_native("VipM_Limits_Execute", "@_Limits_Execute"); + register_native("VipM_Limits_ExecuteList", "@_Limits_ExecuteList"); +} + +static T_LimitType:API_Limits_GetTypeParam(const param) { + new limitName[VIPM_LIMITS_TYPE_NAME_MAX_LEN]; + get_string(param, limitName, charsmax(limitName)); + + new T_LimitType:type = LimitType_Find(limitName); + if (type == Invalid_LimitType) { + abort(AMX_ERR_PARAMS, "Limit type '%s' not found.", limitName); + } + + return type; +} + +// native VipM_Limits_RegisterType(const limitName[], const bool:isForPlayer = true, const bool:isStatic = false); +T_LimitType:@_Limits_RegisterType() { + enum {Arg_LimitName = 1, Arg_IsForPlayer, Arg_IsStatic} + + new limitName[VIPM_LIMITS_TYPE_NAME_MAX_LEN]; + get_string(Arg_LimitName, limitName, charsmax(limitName)); + + new bool:isForPlayer = bool:get_param(Arg_IsForPlayer); + new bool:isStatic = bool:get_param(Arg_IsStatic); + + new T_LimitType:type = LimitType_Construct(limitName, isForPlayer, isStatic); + if (type == Invalid_LimitType) { + log_error(0, "Can't create limit type '%s'.", limitName); + return Invalid_LimitType; + } + + return type; +} + +// native VipM_Limits_AddTypeParams(const limitName[], any:...); +@_Limits_AddTypeParams(const pluginIndex, const paramsCount) { + enum {Arg_LimitName = 1, Arg_Params} + + new T_LimitType:type = API_Limits_GetTypeParam(Arg_LimitName); + new Array:params = CfgParam_GetFromNative(Arg_Params, paramsCount); + + if (params == Invalid_Array) { + return; + } + + LimitType_AddParams(type, params); +} + +// native VipM_Limits_AddParamsEx(const limitName[], any:...); +@VipM_Limits_AddParamsEx(const pluginIndex, const paramsCount) { + enum {Arg_LimitName = 1, Arg_Params} + + new T_LimitType:type = API_Limits_GetTypeParam(Arg_LimitName); + new Array:params = ParamsController_Param_ListFromNativeParams(Arg_Params, paramsCount); + + LimitType_AddParams(type, params); + ArrayDestroy(params); +} + +// native VipM_Limits_RegisterTypeEvent(const limitName[], const E_LimitEvent:event, const func[]); +@_Limits_RegisterTypeEvent(const pluginIndex) { + enum {Arg_LimitName = 1, Arg_Event, Arg_Func} + + new T_LimitType:type = API_Limits_GetTypeParam(Arg_LimitName); + new E_LimitEvent:event = E_LimitEvent:get_param(Arg_Event); + + new func[64]; + get_string(Arg_Func, func, charsmax(func)); + + LimitType_SetEventListener(type, event, pluginIndex, func); +} + +// native VipM_Limits_Execute(const limitName[], const bool:value, const playerIndex = 0); +@_Limits_SetStaticValue() { + enum {Arg_LimitName = 1, Arg_Value, Arg_PlayerIndex} + + new T_LimitType:type = API_Limits_GetTypeParam(Arg_LimitName); + new bool:value = bool:get_param(Arg_Value); + new playerIndex = get_param(Arg_PlayerIndex); + + LimitType_SetStaticValue(type, value, playerIndex); +} + +// native T_LimitUnit:VipM_Limits_ReadFromJson(const JSON:limitJson); +T_LimitUnit:@_Limits_ReadFromJson() { + enum {Arg_JsonValue = 1} + + new JSON:limitJson = JSON:get_param(Arg_JsonValue); + + return LimitUnit_Read(limitJson); +} + +// native Array:VipM_Limits_ReadListFromJson(const JSON:limitsJson, Array:limits = Invalid_Array); +Array:@_Limits_ReadListFromJson() { + enum {Arg_JsonValue = 1, Arg_Array} + + new JSON:limitsJson = JSON:get_param(Arg_JsonValue); + new Array:limits = Array:get_param(Arg_Array); + + return LimitUnit_ReadList(limitsJson, limits); +} + +// native bool:VipM_Limits_Execute(const T_LimitUnit:limit, const playerIndex = 0); +bool:@_Limits_Execute() { + enum {Arg_LimitUnit = 1, Arg_PlayerIndex} + + new T_LimitUnit:limit = T_LimitUnit:get_param(Arg_LimitUnit); + new playerIndex = get_param(Arg_PlayerIndex); + + return LimitUnit_Execute(limit, playerIndex); +} + +// native bool:VipM_Limits_ExecuteList(const Array:limits, const playerIndex = 0, const E_LimitsExecType:type = Limit_Exec_OR); +bool:@_Limits_ExecuteList() { + enum {Arg_LimitUnitList = 1, Arg_PlayerIndex, Arg_Type} + + new Array:limits = Array:get_param(Arg_LimitUnitList); + new playerIndex = get_param(Arg_PlayerIndex); + new E_LimitsExecType:type = E_LimitsExecType:get_param(Arg_Type); + + return LimitUnit_ExecuteList(limits, playerIndex, type); +} diff --git a/amxmodx/scripting/VipM/Core/API/Main.inc b/amxmodx/scripting/VipM/Core/API/Main.inc new file mode 100644 index 0000000..7d5efd9 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/API/Main.inc @@ -0,0 +1,30 @@ +#include +#include "VipM/Utils" +#include "VipM/Core/VipsManager" + +API_Main_Init() { + register_native("VipM_UserUpdate", "@_UserUpdate"); + register_native("VipM_Json_LogForFile", "@_Json_LogForFile"); +} + +@_UserUpdate() { + enum {Arg_UserId = 1} + + new UserId = get_param(Arg_UserId); + if (!is_user_connected(UserId)) { + return; + } + + VipsManager_UserReload(UserId); +} + +// native VipM_Json_LogForFile(const JSON:jValue, const sPrefix[], const sMessage[], any:...); +@_Json_LogForFile() { + enum {Arg_jValue = 1, Arg_sPrefix, Arg_sMessage, Arg_fmtArgs} + + static sMessage[512], sPrefix[32]; + vdformat(sMessage, charsmax(sMessage), Arg_sMessage, Arg_fmtArgs); + get_string(Arg_sPrefix, sPrefix, charsmax(sPrefix)); + + PCJson_LogForFile(JSON:get_param(Arg_jValue), sPrefix, sMessage); +} diff --git a/amxmodx/scripting/VipM/Core/API/Modules.inc b/amxmodx/scripting/VipM/Core/API/Modules.inc new file mode 100644 index 0000000..ae829f8 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/API/Modules.inc @@ -0,0 +1,123 @@ +#include +#include + +#include "VipM/DebugMode" +#include "VipM/Core/Objects/Param" + +API_Modules_Init(){ + register_native("VipM_Modules_Register", "@_Modules_Register"); + register_native("VipM_Modules_AddParams", "@_Modules_AddParams"); + register_native("VipM_Modules_AddParamsEx", "@VipM_Modules_AddParamsEx"); + register_native("VipM_Modules_RegisterEvent", "@_Modules_RegisterEvent"); + + register_native("VipM_Modules_IsActive", "@_Modules_IsActive"); + register_native("VipM_Modules_GetParams", "@_Modules_GetParams"); + +} + +T_ModuleType:@_Modules_Register(const pluginIndex) { + enum {Arg_TypeName = 1} + + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + get_string(Arg_TypeName, typeName, charsmax(typeName)); + + new T_ModuleType:type = ModuleType_Construct(typeName); + if (type == Invalid_ModuleType) { + log_error(0, "Can't create module type '%s'.", typeName); + return Invalid_ModuleType; + } + + return type; +} + +@_Modules_AddParams(const pluginIndex, const iParamsNum) { + enum {Arg_TypeName = 1, Arg_Params} + + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + get_string(Arg_TypeName, typeName, charsmax(typeName)); + + new T_ModuleType:type = ModuleType_Find(typeName); + if (type == Invalid_ModuleType) { + log_error(0, "Module type '%s' not found.", typeName); + return; + } + + new Array:params = CfgParam_GetFromNative(Arg_Params, iParamsNum); + if (params == Invalid_Array) { + return; + } + + ModuleType_AddParams(type, params); + ArrayDestroy(params); +} + +@VipM_Modules_AddParamsEx(const pluginIndex, const paramsCount) { + enum {Arg_TypeName = 1, Arg_Params} + + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + get_string(Arg_TypeName, typeName, charsmax(typeName)); + + new T_ModuleType:type = ModuleType_Find(typeName); + if (type == Invalid_ModuleType) { + log_error(0, "Module type '%s' not found.", typeName); + return; + } + + new Array:params = ParamsController_Param_ListFromNativeParams(Arg_Params, paramsCount); + ModuleType_AddParams(type, params); + ArrayDestroy(params); +} + +bool:@_Modules_RegisterEvent(const pluginIndex) { + enum {Arg_TypeName = 1, Arg_iEvent, Arg_sFuncName} + + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + get_string(Arg_TypeName, typeName, charsmax(typeName)); + + new T_ModuleType:type = ModuleType_Find(typeName); + if (type == Invalid_ModuleType) { + log_error(0, "Module type '%s' not found.", typeName); + return false; + } + + new E_ModuleEvent:event = E_ModuleEvent:get_param(Arg_iEvent); + + new funcName[64]; + get_string(Arg_sFuncName, funcName, charsmax(funcName)); + + ModuleType_SetEventListener(type, event, pluginIndex, funcName); + return true; +} + +bool:@_Modules_IsActive() { + enum {Arg_TypeName = 1} + + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + get_string(Arg_TypeName, typeName, charsmax(typeName)); + + new T_ModuleType:type = ModuleType_Find(typeName); + if (type == Invalid_ModuleType) { + log_error(0, "Module type '%s' not found.", typeName); + return false; + } + + return ModuleType_IsActive(type); +} + +Trie:@_Modules_GetParams() { + enum {Arg_TypeName = 1, Arg_PlayerIndex} + + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + get_string(Arg_TypeName, typeName, charsmax(typeName)); + + // TODO: Потом переделать сразу на хендлеры + new T_ModuleType:type = ModuleType_Find(typeName); + if (type == Invalid_ModuleType) { + log_error(AMX_ERR_PARAMS, "Module type '%s' not found.", typeName); + return Invalid_Trie; + } + + new playerIndex = get_param(Arg_PlayerIndex); + + return VipsManager_GetUserParams(playerIndex, type); +} diff --git a/amxmodx/scripting/VipM/Core/Configs/Main.inc b/amxmodx/scripting/VipM/Core/Configs/Main.inc deleted file mode 100644 index 3812e2a..0000000 --- a/amxmodx/scripting/VipM/Core/Configs/Main.inc +++ /dev/null @@ -1,137 +0,0 @@ -#if defined _vipmodular_src_Configs_included - #endinput -#endif -#define _vipmodular_src_Configs_included - -/** - * Vip Modular: Configs - */ - -#include amxmodx -#include json - -enum _:S_CfgUnit{ - Array:CfgUnit_LimitUnits, // S_AccessUnit - Array:CfgUnit_ModuleUnits, // S_ModuleUnit -} - -#include "VipM/Core/Configs/Vips" - -// Utils - -bool:Cfg_ReadParams( - const JSON:jParams, - Trie:Params, - const Array:List = Invalid_Array, - ErrParam[] = "", - const Len = 0 -) { - if (!json_is_object(jParams)) { - return false; - } - - if (Params == Invalid_Trie) { - Params = TrieCreate(); - } - - if (List == Invalid_Array) { - new ParamName[32]; - for (new i = 0; i < json_object_get_count(jParams); i++) { - - json_object_get_name(jParams, i, ParamName, charsmax(ParamName)); - new JSON:jParam = json_object_get_value_at(jParams, i); - - switch (json_get_type(jParam)) { - case JSONString: { - new sParam[128]; - json_get_string(jParam, sParam, charsmax(sParam)); - TrieSetString(Params, ParamName, sParam); - } - - case JSONNumber: - TrieSetCell(Params, ParamName, json_get_number(jParam)); - - case JSONBoolean: - TrieSetCell(Params, ParamName, json_get_bool(jParam)); - - } - json_free(jParam); - } - } else { - ArrayForeachArray (List => Param[S_CfgParam]) { - if (!json_object_has_value(jParams, Param[CfgParam_Name])) { - if ( - Param[CfgParam_Required] - && Param[CfgParam_Type] != ptCustom - ) { - formatex(ErrParam, Len, Param[CfgParam_Name]); - TrieDestroy(Params); - return false; - } else { - continue; - } - } - - switch (Param[CfgParam_Type]) { - case ptCustom: - continue; - - case ptInteger: - TrieSetCell(Params, Param[CfgParam_Name], json_object_get_number(jParams, Param[CfgParam_Name])); - - case ptFloat: - TrieSetCell(Params, Param[CfgParam_Name], json_object_get_real(jParams, Param[CfgParam_Name])); - - case ptBoolean: - TrieSetCell(Params, Param[CfgParam_Name], json_object_get_bool(jParams, Param[CfgParam_Name])); - - case ptString: { - new sParam[128]; - json_object_get_string(jParams, Param[CfgParam_Name], sParam, charsmax(sParam)); - TrieSetString(Params, Param[CfgParam_Name], sParam); - } - - case ptColor: { - new JSON:jColor = json_object_get_value(jParams, Param[CfgParam_Name]); - new Color[3]; - for(new i = 0; i < 3; i++) - Color[i] = json_array_get_number(jColor, i); - TrieSetArray(Params, Param[CfgParam_Name], Color, 3); - json_free(jColor); - } - - case ptVector2: { - new JSON:jVec = json_object_get_value(jParams, Param[CfgParam_Name]); - new Float:Vec[2]; - for(new i = 0; i < 2; i++) - Vec[i] = json_array_get_real(jVec, i); - TrieSetArray(Params, Param[CfgParam_Name], Vec, 2); - json_free(jVec); - } - case ptVector3: { - new JSON:jVec = json_object_get_value(jParams, Param[CfgParam_Name]); - new Float:Vec[3]; - for(new i = 0; i < 3; i++) - Vec[i] = json_array_get_real(jVec, i); - TrieSetArray(Params, Param[CfgParam_Name], Vec, 3); - json_free(jVec); - } - - case ptLimit: { - new JSON:jLimit = json_object_get_value(jParams, Param[CfgParam_Name]); - new T_LimitUnit:iLimit = Limits_LoadUnitFromJson(jLimit); - TrieSetCell(Params, Param[CfgParam_Name], iLimit); - json_free(jLimit); - } - case ptLimits: { - new JSON:jLimits = json_object_get_value(jParams, Param[CfgParam_Name]); - new Array:aLimits = Limits_LoadUnitListFromJson(jLimits, aLimits); - TrieSetCell(Params, Param[CfgParam_Name], aLimits); - json_free(jLimits); - } - } - } - } - - return true; -} diff --git a/amxmodx/scripting/VipM/Core/Configs/Vips.inc b/amxmodx/scripting/VipM/Core/Configs/Vips.inc deleted file mode 100644 index aa1de88..0000000 --- a/amxmodx/scripting/VipM/Core/Configs/Vips.inc +++ /dev/null @@ -1,93 +0,0 @@ -#include amxmodx -#include json -#include regex - -static stock const VIPS_CFG_FILE[] = "Vips"; -static stock const VIPS_CFGS_DIR[] = "Vips"; - -Array:Cfg_LoadVipsConfigs(Array:aList = Invalid_Array) { - if (JSON_FILE_EXTSTS(VIPS_CFG_FILE)) { - aList = Cfg_LoadVipsConfigFromFile(VIPS_CFG_FILE, aList); - } - - new sFilePath[PLATFORM_MAX_PATH], iDirHandler, FileType:Type; - iDirHandler = open_dir(GET_FILE(VIPS_CFGS_DIR), sFilePath, charsmax(sFilePath), Type); - if (!iDirHandler) { - return aList; - } - - new ret, Regex:RegEx_FileName = regex_compile("(.+).json$", ret, "", 0, "i"); - do { - if ( - sFilePath[0] == '!' - || Type != FileType_File - || regex_match_c(sFilePath, RegEx_FileName) <= 0 - ) { - continue; - } - - new sFileName[64]; - regex_substr(RegEx_FileName, 1, sFileName, charsmax(sFileName)); - - aList = Cfg_LoadVipsConfigFromFile(fmt("%s/%s", VIPS_CFGS_DIR, sFileName), aList); - } while (next_file(iDirHandler, sFilePath, charsmax(sFilePath), Type)); - - return aList; -} - -Array:Cfg_LoadVipsConfigFromFile(const sFileName[], Array:aList = Invalid_Array) { - if (!JSON_FILE_EXTSTS(sFileName)) { - set_fail_state("[ERROR] Vips config '%s' not found.", GET_FILE_JSON_PATH(sFileName)); - return Invalid_Array; - } - - new JSON:jVips = GET_FILE_JSON(sFileName); - if (!json_is_array(jVips)) { - set_fail_state("[ERROR] JSON syntax error in file '%s'.", GET_FILE_JSON_PATH(sFileName)); - return Invalid_Array; - } - - ArrayCreateIfNotCreated(aList, S_CfgUnit, json_array_get_count(jVips)); - new CfgUnit[S_CfgUnit]; - json_array_foreach_value (jVips: i => jCfgUnit) { - if (Cfg_ReadVipConfig(jCfgUnit, CfgUnit)) { - ArrayPushArray(aList, CfgUnit); - } - json_free(jCfgUnit); - } - - Json_DeepFree(jVips); - return aList; -} - -bool:Cfg_ReadVipConfig(const JSON:jCfgUnit, CfgUnit[S_CfgUnit]) { - new JSON:jAccess = json_object_get_value(jCfgUnit, "Access"); - if (jAccess == Invalid_JSON) { - return false; - } - - CfgUnit[CfgUnit_LimitUnits] = Limits_LoadUnitListFromJson(jAccess); - json_free(jAccess); - if (!ArraySizeSafe(CfgUnit[CfgUnit_LimitUnits])) { - ArrayDestroy(CfgUnit[CfgUnit_LimitUnits]); - return false; - } - - new JSON:jModules = json_object_get_value(jCfgUnit, "Modules"); - if (jModules == Invalid_JSON) { - ArrayDestroy(CfgUnit[CfgUnit_LimitUnits]); - return false; - } - - CfgUnit[CfgUnit_ModuleUnits] = ModuleUnits_LoadListFromJson(jModules); - json_free(jModules); - if (!ArraySizeSafe(CfgUnit[CfgUnit_ModuleUnits])) { - // TODO: Тут нужен специальный дестрой для ограничений, иначе утечка говна) - // Но эта штука случается только при кривых конфигах, так что не критично))) - ArrayDestroy(CfgUnit[CfgUnit_LimitUnits]); - ArrayDestroy(CfgUnit[CfgUnit_ModuleUnits]); - return false; - } - - return true; -} diff --git a/amxmodx/scripting/VipM/Core/Limits/Main.inc b/amxmodx/scripting/VipM/Core/Limits/Main.inc deleted file mode 100644 index bd399f3..0000000 --- a/amxmodx/scripting/VipM/Core/Limits/Main.inc +++ /dev/null @@ -1,22 +0,0 @@ -#if defined _vipmodular_src_Limits_included - #endinput -#endif -#define _vipmodular_src_Limits_included - -#include amxmodx -#include json - -#define NATIVE_CHECK_LIMIT_TYPE(%1) \ - if(!LIMIT_TYPE_EXISTS(%1)){ \ - log_error(0, "[ERROR] Limit type '%s' not found.", %1); \ - } - -#include "VipM/Core/Limits/Types.inc" -#include "VipM/Core/Limits/Units.inc" - -Limits_Init(){ - InitArrayMap(Limits, S_Limit, 8); - - LimitUnits = ArrayCreate(S_LimitUnit, 16); - __cache_LimitUnits = TrieCreate(); -} diff --git a/amxmodx/scripting/VipM/Core/Limits/Types.inc b/amxmodx/scripting/VipM/Core/Limits/Types.inc deleted file mode 100644 index d0c86bf..0000000 --- a/amxmodx/scripting/VipM/Core/Limits/Types.inc +++ /dev/null @@ -1,184 +0,0 @@ -#include amxmodx -#include "VipM/ArrayMap" -#include "VipM/Utils" -#include "VipM/DebugMode" - -enum T_Limit {Invalid_Limit = -1} - -enum _:S_Limit{ - Limit_PluginId, - Limit_Name[32], - - bool:Limit_Static, - Limit_StaticValue, - - bool:Limit_ForPlayer, - - Array:Limit_Params, - Trie:Limit_Events, -} - -new ArrayMap(Limits); - -#define LIMIT_TYPE_PUSH(%1) \ - T_Limit:ArrayMapPushArray(Limits, %1, %1[Limit_Name]) - -#define LIMIT_TYPE_EXISTS(%1) \ - ArrayMapHasKey(Limits, %1) - -#define LIMIT_TYPE_GET_ID(%1) \ - T_Limit:ArrayMapGetIndex(Limits, %1) - -#define LIMIT_TYPE_GET_BY_ID(%1,%2) \ - ArrayMapGetiArray(Limits, _:(%1), %2) - -#define LIMIT_TYPE_GET(%1,%2) \ - ArrayMapGetArray(Limits, %1, %2) - -#define SET_LIMIT_TYPE(%1) \ - ArrayMapSetArray(Limits, %1[Limit_Name], %1) - -new const __CHECK_LIMIT_FOR_PLAYER_errmsg[] = "[ERROR] Limit `%s` must used for player."; -#define CHECK_LIMIT_FOR_PLAYER(%1,%2,%3) CompositeMacros( \ - if ( \ - !IsUserIdValid(%2) \ - && %1[Limit_ForPlayer] \ - ) { \ - log_error(1, __CHECK_LIMIT_FOR_PLAYER_errmsg, %1[Limit_Name]); \ - return %3; \ - } \ -) - -new const __CHECK_LIMIT_STATIC_errmsg[] = "[ERROR] Limit type `%s` isn`t static."; -#define CHECK_LIMIT_STATIC(%1,%2) \ - if (!%1[Limit_Static]) { \ - log_error(1, __CHECK_LIMIT_STATIC_errmsg, %1[Limit_Name]); \ - return %2; \ - } - -// EMIT_LIMIT_TYPE_EVENT(LimitType, E_LimitEvent:Event, Return, ...Params) -#define EMIT_LIMIT_TYPE_EVENT(%1,%2,%3) \ - if ( \ - %1[Limit_Events] != Invalid_Trie \ - && TrieKeyExists(%1[Limit_Events], IntToStr(%2)) \ - ) { \ - new ___EVENT_FWD; \ - TrieGetCell(%1[Limit_Events], IntToStr(%2), ___EVENT_FWD); \ - ExecuteForward(___EVENT_FWD, %3); \ - } - -// SET_LIMIT_TYPE_EVENT(AccessMode, E_LimitEvent:Event, FwdId) -#define SET_LIMIT_TYPE_EVENT(%1,%2,%3) \ - if (%3 >= 0) { \ - if(%1[Limit_Events] == Invalid_Trie) \ - %1[Limit_Events] = TrieCreate(); \ - TrieSetCell(%1[Limit_Events], IntToStr(%2), %3); \ - } else TrieDeleteKey(%1[Limit_Events], IntToStr(%2)) - - -T_Limit:Limits_AddType(const sName[], const bool:bForPlayer, const bool:bStatic = false, const iPluginId = -1){ - new Limit[S_Limit]; - - Limit[Limit_PluginId] = iPluginId; - copy(Limit[Limit_Name], charsmax(Limit[Limit_Name]), sName); - Limit[Limit_Static] = bStatic; - Limit[Limit_StaticValue] = 0; - Limit[Limit_ForPlayer] = bForPlayer; - - return LIMIT_TYPE_PUSH(Limit); -} - -Limits_RegisterEvent(const PluginId, const sLimitName[], const E_LimitEvent:Event, const Func[]){ - new LimitType[S_Limit]; - LIMIT_TYPE_GET(sLimitName, LimitType); - - new FwdId = -1; - switch (Event) { - case Limit_OnRead: // (const JSON:Cfg, Trie:Params) - FwdId = CreateOneForward(PluginId, Func, FP_CELL, FP_CELL); - - case Limit_OnCheck: // (const Trie:Params, const UserId) - FwdId = CreateOneForward(PluginId, Func, FP_CELL, FP_CELL); - } - - if (FwdId < 0) { - return false; - } - - SET_LIMIT_TYPE_EVENT(LimitType, Event, FwdId); - SET_LIMIT_TYPE(LimitType); - - return FwdId >= 0; -} - -Limits_SetStaticValue(const sLimitName[], const bool:bValue, const UserId = 0){ - static LimitType[S_Limit]; - LIMIT_TYPE_GET(sLimitName, LimitType); - - CHECK_LIMIT_STATIC(LimitType, 0) - CHECK_LIMIT_FOR_PLAYER(LimitType, UserId, 0); - - if (UserId > 0) { - Dbg_Log("Limits_SetStaticValue(%s, %n):", sLimitName, UserId); - } else { - Dbg_Log("Limits_SetStaticValue(%s, %d):", sLimitName, UserId); - } - - Dbg_Log(" sLimitName[] = %s", sLimitName); - Dbg_Log(" LimitType[Limit_ForPlayer] = %s", LimitType[Limit_ForPlayer] ? "true" : "false"); - Dbg_Log(" LimitType[Limit_StaticValue] (before set) = %d", LimitType[Limit_StaticValue]); - Dbg_Log(" bValue = %d", bValue); - - if (LimitType[Limit_ForPlayer]) { - BitSetIf(LimitType[Limit_StaticValue], UserId - 1, bValue); - Dbg_Log(" BitIs(LimitType[Limit_StaticValue], UserId - 1) = %d", BitIs(LimitType[Limit_StaticValue], UserId - 1)); - } else { - LimitType[Limit_StaticValue] = _:bValue; - Dbg_Log(" LimitType[Limit_StaticValue] (after set) = %d", LimitType[Limit_StaticValue]); - } - - SET_LIMIT_TYPE(LimitType); - - return 0; -} - -bool:Limits_GetStaticValue(const sLimitName[], const UserId = 0){ - static LimitType[S_Limit]; - LIMIT_TYPE_GET(sLimitName, LimitType); - - CHECK_LIMIT_STATIC(LimitType, false) - CHECK_LIMIT_FOR_PLAYER(LimitType, UserId, false); - - if (UserId > 0) { - Dbg_Log("Limits_GetStaticValue(%s, %n):", sLimitName, UserId); - } else { - Dbg_Log("Limits_GetStaticValue(%s, %d):", sLimitName, UserId); - } - - Dbg_Log(" LimitType[Limit_ForPlayer] = %s", LimitType[Limit_ForPlayer] ? "true" : "false"); - Dbg_Log(" LimitType[Limit_StaticValue] = %d", LimitType[Limit_StaticValue]); - - if (UserId > 0) { - Dbg_Log(" BitIs(LimitType[Limit_StaticValue], UserId - 1) = %d", BitIs(LimitType[Limit_StaticValue], UserId - 1)); - } - - return LimitType[Limit_ForPlayer] - ? BitIs(LimitType[Limit_StaticValue], UserId - 1) - : (bool:LimitType[Limit_StaticValue]); -} - -bool:Limits_Execute(const T_Limit:iLimitType, const Trie:Params = Invalid_Trie, const UserId = 0){ - static LimitType[S_Limit]; - LIMIT_TYPE_GET_BY_ID(iLimitType, LimitType); - - CHECK_LIMIT_FOR_PLAYER(LimitType, UserId, false); - - if (LimitType[Limit_Static]) { - return Limits_GetStaticValue(LimitType[Limit_Name], UserId); - } - - new bool:ret; - EMIT_LIMIT_TYPE_EVENT(LimitType, Limit_OnCheck, ret, Params, UserId) - - return bool:ret; -} diff --git a/amxmodx/scripting/VipM/Core/Limits/Units.inc b/amxmodx/scripting/VipM/Core/Limits/Units.inc deleted file mode 100644 index fc5048e..0000000 --- a/amxmodx/scripting/VipM/Core/Limits/Units.inc +++ /dev/null @@ -1,215 +0,0 @@ -#include -#include - -// Structs - -enum _:S_LimitUnit{ - T_Limit:LimitUnit_LimitId, - Trie:LimitUnit_Params, // S_CfgParam -} -new Array:LimitUnits; - -// Array utils - -#define Limits_PushUnit(%1) \ - T_LimitUnit:(ArrayPushArray(LimitUnits, %1)) - -#define Limits_GetUnit(%1,%2) \ - ArrayGetArray(LimitUnits, _:%1, %2) - -#define Limits_IsUnitValid(%1) \ - (_:%1 >= 0 && _:%1 < ArraySizeSafe(LimitUnits)) - -// Cache - -new Trie:__cache_LimitUnits; - -T_LimitUnit:Limits_AddUnitToCache(const T_LimitUnit:iLimit, const CacheKey[] = ""){ - if (CacheKey[0]) { - TrieSetCell(__cache_LimitUnits, CacheKey, iLimit); - } - return iLimit; -} - -T_LimitUnit:Limits_GetUnitFromCache(const CacheKey[]){ - new T_LimitUnit:iLimit; - return TrieGetCell(__cache_LimitUnits, CacheKey, iLimit) - ? iLimit - : Invalid_LimitUnit; -} - -#define Limits_CacheExists(%1) \ - TrieKeyExists(__cache_LimitUnits, %1) - -// Reader - -bool:Limits_ReadUnitFromJson(const JSON:jUnit, Unit[S_LimitUnit]){ - new LimitName[32]; - json_object_get_string(jUnit, "Limit", LimitName, charsmax(LimitName)); - json_object_remove(jUnit, "Limit"); - - if (!LIMIT_TYPE_EXISTS(LimitName)) { - log_amx("[WARNING] Limit type `%s` not found.", LimitName); - return false; - } - - new LimitType[S_Limit]; - LIMIT_TYPE_GET(LimitName, LimitType); - - Unit[LimitUnit_LimitId] = LIMIT_TYPE_GET_ID(LimitName); - Unit[LimitUnit_Params] = TrieCreate(); - if (!LimitType[Limit_Static]) { - new ErrParam[32]; - if (!Cfg_ReadParams(jUnit, Unit[LimitUnit_Params], LimitType[Limit_Params], ErrParam, charsmax(ErrParam))) { - log_amx("[WARNING] Param `%s` required for limit `%s`, but not found.", ErrParam, LimitType[Limit_Name]); - return false; - } - } - - Forwards_DefaultReturn(VIPM_CONTINUE); - if ( - Forwards_CallP("ReadUnit", jUnit, Unit[LimitUnit_Params]) == VIPM_STOP - || Forwards_CallP("ReadLimitUnit", jUnit, Unit[LimitUnit_Params]) == VIPM_STOP - ) { - TrieDestroySafe(Unit[LimitUnit_Params]); - return false; - } - - new ret; - EMIT_LIMIT_TYPE_EVENT(LimitType, Limit_OnRead, ret, jUnit, Unit[LimitUnit_Params]) - - if (ret == VIPM_STOP) { - TrieDestroySafe(Unit[LimitUnit_Params]); - return false; - } - - return true; -} - -// Loaders - -T_LimitUnit:Limits_LoadUnitFromFile(const FileName[]){ - if (Limits_CacheExists(FileName)) { - return Limits_GetUnitFromCache(FileName); - } - - if (!JSON_FILE_EXTSTS(FileName)) { - log_amx("[WARNING] File `%s` not found.", FileName); - return Invalid_LimitUnit; - } - - new JSON:jUnit = GET_FILE_JSON(FileName); - new T_LimitUnit:iLimit = Limits_LoadUnitFromJson(jUnit); - json_free(jUnit); - - return Limits_AddUnitToCache(iLimit, FileName); -} - -T_LimitUnit:Limits_LoadUnitFromJson(const JSON:jUnit){ - if (jUnit == Invalid_JSON) { - return Invalid_LimitUnit; - } - - new Ref[128]; - if (Json_IsRef(jUnit, Ref, charsmax(Ref))) { - return Limits_LoadUnitFromFile(Ref); - } - - new Unit[S_LimitUnit]; - if (Limits_ReadUnitFromJson(jUnit, Unit)) { - return Limits_PushUnit(Unit); - } - - return Invalid_LimitUnit; -} - -Array:Limits_LoadUnitListFromJson(const JSON:jLimits, Array:aLimits = Invalid_Array){ - new T_LimitUnit:iLimit; - if (!json_is_array(jLimits)) { - ArrayCreateIfNotCreated(aLimits, 1, 1); - - iLimit = Limits_LoadUnitFromJson(jLimits); - if (iLimit != Invalid_LimitUnit) { - ArrayPushCell(aLimits, iLimit); - } - } else { - ArrayCreateIfNotCreated(aLimits, 1, json_array_get_count(jLimits)); - - json_array_foreach_value(jLimits: i => jLimit){ - iLimit = Limits_LoadUnitFromJson(jLimit); - if (iLimit != Invalid_LimitUnit) { - ArrayPushCell(aLimits, iLimit); - } - json_free(jLimit); - } - } - - if (ArraySizeSafe(aLimits) < 1) { - // log_amx("[WARNING] Limit units list not loaded (invalid or empty)."); - ArrayDestroy(aLimits); - } - - return aLimits; -} - -// Usage - -bool:Limits_ExecuteUnit(const T_LimitUnit:iLimit, const UserId = 0){ - if (!Limits_IsUnitValid(iLimit)) { - log_error(0, "[ERROR] Invalid limit unit index (%d).", iLimit); - return true; - } - - new Limit[S_LimitUnit]; - Limits_GetUnit(iLimit, Limit); - - return Limits_Execute(Limit[LimitUnit_LimitId], Limit[LimitUnit_Params], UserId); -} - -bool:Limits_ExecuteUnitList(const Array:aLimits, const UserId = 0, const E_LimitsExecType:Type = Limit_Exec_OR){ - new cLimits = ArraySizeSafe(aLimits); - if (!cLimits) { - return true; - } - - new __xor_counter = 0; - for (new i = 0; i < cLimits; i++) { - new T_LimitUnit:iLimit = T_LimitUnit:ArrayGetCell(aLimits, i); - switch (Type) { - case Limit_Exec_OR: { - if (Limits_ExecuteUnit(iLimit, UserId)) { - return true; - } - } - - case Limit_Exec_AND: { - if (!Limits_ExecuteUnit(iLimit, UserId)) { - return false; - } - } - - case Limit_Exec_XOR: { - if (Limits_ExecuteUnit(iLimit, UserId)) { - __xor_counter++; - } - - if (__xor_counter > 1) { - return false; - } - } - } - } - - switch(Type){ - case Limit_Exec_OR: - return false; - - case Limit_Exec_AND: - return true; - - case Limit_Exec_XOR: - return bool:__xor_counter; - } - - return false; -} diff --git a/amxmodx/scripting/VipM/Core/Modules/Main.inc b/amxmodx/scripting/VipM/Core/Modules/Main.inc deleted file mode 100644 index c1f964f..0000000 --- a/amxmodx/scripting/VipM/Core/Modules/Main.inc +++ /dev/null @@ -1,17 +0,0 @@ -#if defined _vipmodular_src_Modules_included - #endinput -#endif -#define _vipmodular_src_Modules_included - -#define NATIVE_CHECK_MODULE(%1) \ - if (!MODULE_EXISTS(%1)) {\ - log_error(1, "[ERROR] Module '%s' not found.", %1);\ - } - -#include "VipM/Core/Modules/Modules.inc" -#include "VipM/Core/Modules/Units.inc" - -Modules_Init() { - Modules_InitModules(); - Modules_InitUnits(); -} diff --git a/amxmodx/scripting/VipM/Core/Modules/Modules.inc b/amxmodx/scripting/VipM/Core/Modules/Modules.inc deleted file mode 100644 index 8cab0b5..0000000 --- a/amxmodx/scripting/VipM/Core/Modules/Modules.inc +++ /dev/null @@ -1,85 +0,0 @@ -#include -#include "VipM/ArrayMap" -#include "VipM/Utils" -#include "VipM/Forwards" - -enum _:S_Module { - Module_PluginId, - Module_Name[32], - bool:Module_Once, - bool:Module_Enabled, - - Array:Module_Params, // S_CfgParam - Trie:Module_Events, - - bool:Module_Used, -} - -#define MODULE_EXISTS(%1) \ - ArrayMapHasKey(Modules, %1) - -#define GET_MODULE(%1,%2) \ - ArrayMapGetArray(Modules, %1, %2) - -#define GET_MODULE_ID(%1) \ - ArrayMapGetIndex(Modules, %1) - -#define GET_MODULE_BY_ID(%1,%2) \ - ArrayMapGetiArray(Modules, %1, %2) - -#define SET_MODULE(%1) \ - ArrayMapSetArray(Modules, %1[Module_Name], %1) - -// EMIT_MODULE_EVENT(Module, E_ModuleEvent:Event, Return, ...Params) -#define EMIT_MODULE_EVENT(%1,%2,%3) CompositeMacros( \ - if( \ - %1[Module_Events] != Invalid_Trie \ - && TrieKeyExists(%1[Module_Events], IntToStr(%2)) \ - ){ \ - new ___EVENT_FWD; \ - TrieGetCell(%1[Module_Events], IntToStr(%2), ___EVENT_FWD); \ - ExecuteForward(___EVENT_FWD, %3); \ - } \ -) - -// SET_MODULE_EVENT(Module, E_ModuleEvent:Event, FwdId) -#define SET_MODULE_EVENT(%1,%2,%3) CompositeMacros( \ - if(%3 >= 0){ \ - if(%1[Module_Events] == Invalid_Trie) \ - %1[Module_Events] = TrieCreate(); \ - \ - TrieSetCell(%1[Module_Events], IntToStr(%2), %3); \ - } \ - else TrieDeleteKey(%1[Module_Events], IntToStr(%2)); \ -) - -new ArrayMap(Modules); // S_Module - -Modules_Enable(const iModule) { - new Module[S_Module]; - GET_MODULE_BY_ID(iModule, Module); - - Forwards_DefaultReturn(VIPM_CONTINUE); - new ret = VIPM_CONTINUE; - - if ((ret = Forwards_CallP("ActivateModule", Module[Module_Name])) != VIPM_STOP) { - EMIT_MODULE_EVENT(Module, Module_OnActivated, ret); - } - - Module[Module_Enabled] = (ret == VIPM_CONTINUE); - SET_MODULE(Module); - - // Dbg_Log("Modules_Enable(%d): Module_Enabled = %d", iModule, Module[Module_Enabled]); -} - -Modules_EnableAllUsed() { - ArrayMapForeachArray2 (Modules: iModule => Module[S_Module]) { - if (Module[Module_Used]) { - Modules_Enable(iModule); - } - } -} - -Modules_InitModules(){ - InitArrayMap(Modules, S_Module, 8); -} \ No newline at end of file diff --git a/amxmodx/scripting/VipM/Core/Modules/Units.inc b/amxmodx/scripting/VipM/Core/Modules/Units.inc deleted file mode 100644 index b8552df..0000000 --- a/amxmodx/scripting/VipM/Core/Modules/Units.inc +++ /dev/null @@ -1,251 +0,0 @@ -#include -#include -#include "VipM/ArrayMap" -#include "VipM/DebugMode" - -const MODULE_UNITS_PRESERVED_SIZE = 8; -new const MODULE_PARAMS_ISTEMP_KEY[] = "__IsTemp"; - -enum T_ModuleUnit { Invalid_ModuleUnit = -1 } - -enum _:S_ModuleUnit { - ModuleUnit_ModuleId, - Trie:ModuleUnit_Params, -} - -new Array:ModuleUnits; - -#define ModuleUnits_Push(%1) \ - T_ModuleUnit:ArrayPushArray(ModuleUnits, %1) - -#define ModuleUnits_Get(%1,%2) \ - ArrayGetArray(ModuleUnits, _:%1, %2) - - -// Cache - -new Trie:__cache_ModuleUnits; - -T_ModuleUnit:ModuleUnits_AddToCache(const T_ModuleUnit:iMUnit, const CacheKey[] = "") { - if (CacheKey[0]) { - TrieSetCell(__cache_ModuleUnits, CacheKey, iMUnit); - } - - return iMUnit; -} - -T_ModuleUnit:ModuleUnits_GetFromCache(const CacheKey[]){ - new T_ModuleUnit:iMUnit; - return TrieGetCell(__cache_ModuleUnits, CacheKey, iMUnit) - ? iMUnit - : Invalid_ModuleUnit; -} - -#define ModuleUnits_CacheExists(%1) \ - TrieKeyExists(__cache_ModuleUnits, %1) - - -// Init - -Modules_InitUnits() { - ModuleUnits = ArrayCreate(S_ModuleUnit, MODULE_UNITS_PRESERVED_SIZE); - __cache_ModuleUnits = TrieCreate(); -} - - -// Actions - -ModuleUnits_ResetUser(const UserId) { - if (gUserVip[UserId] == Invalid_Trie) { - return; - } - - new TrieIter:Iter = TrieIterCreate(gUserVip[UserId]); - while (!TrieIterEnded(Iter)) { - new Trie:Params = Invalid_Trie; - if ( - TrieIterGetCell(Iter, Params) - && TrieKeyExists(Params, MODULE_PARAMS_ISTEMP_KEY) - && Params != Invalid_Trie - ) { - TrieDestroy(Params); - } - - TrieIterNext(Iter); - } - TrieIterDestroy(Iter); - - TrieDestroy(gUserVip[UserId]); -} - -ModuleUnits_AddListToUser(const UserId, const Array:aUnits) { - if (aUnits == Invalid_Array) { - return; - } - - for (new i = 0; i < ArraySize(aUnits); i++) { - ModuleUnits_AddToUser(UserId, T_ModuleUnit:ArrayGetCell(aUnits, i)); - } -} - -ModuleUnits_AddToUser(const UserId, const T_ModuleUnit:iMUnit) { - if (gUserVip[UserId] == Invalid_Trie) { - gUserVip[UserId] = TrieCreate(); - } - - new Unit[S_ModuleUnit]; - ModuleUnits_Get(iMUnit, Unit); - - new Module[S_Module]; - GET_MODULE_BY_ID(Unit[ModuleUnit_ModuleId], Module); - - if (TrieKeyExists(gUserVip[UserId], Module[Module_Name])) { - if (Module[Module_Once]) { - return; - } - - new Trie:Params; - TrieGetCell(gUserVip[UserId], Module[Module_Name], Params); - - new Trie:Ret = Invalid_Trie; - EMIT_MODULE_EVENT(Module, Module_OnCompareParams, _:Ret, Params, Unit[ModuleUnit_Params]); - if (Ret == Invalid_Trie) { - return; - } - - if (TrieKeyExists(Params, MODULE_PARAMS_ISTEMP_KEY)) { - TrieDestroy(Params); - } - - TrieSetCell(Ret, MODULE_PARAMS_ISTEMP_KEY, true); - TrieSetCell(gUserVip[UserId], Module[Module_Name], Ret); - Dbg_Log("ModuleUnits_AddToUser(#%d, '%s'): Compared", UserId, Module[Module_Name]); - } else { - TrieSetCell(gUserVip[UserId], Module[Module_Name], Unit[ModuleUnit_Params], false); - - if (IS_DEBUG) { - // А то мешает когда в консоль срёт такими сообщениями для каждого бота - if (!is_user_bot(UserId)) { - Dbg_Log("ModuleUnits_AddToUser(#%d, '%s'): First add", UserId, Module[Module_Name]); - } - } - } -} - - -// Readers - -bool:ModuleUnits_ReadFromJson(const JSON:jMUnit, sMUnit[S_ModuleUnit]) { - new ModuleName[32]; - json_object_get_string(jMUnit, "Module", ModuleName, charsmax(ModuleName)); - json_object_remove(jMUnit, "Module"); - - if (!MODULE_EXISTS(ModuleName)) { - Json_LogForFile(jMUnit, "WARNING", "Module `%s` not found.", ModuleName); - return false; - } - - new iModule = GET_MODULE_ID(ModuleName); - // Modules_Enable(iModule); - - new sModule[S_Module]; - GET_MODULE_BY_ID(iModule, sModule); - - // Пусть юниты модулей читаются вне зависимости от состояния модуля - // Чтобы позже можно было на лету переключать состояние - - sMUnit[ModuleUnit_ModuleId] = iModule; - sMUnit[ModuleUnit_Params] = TrieCreate(); - - new ErrParam[32]; - if (!Cfg_ReadParams(jMUnit, sMUnit[ModuleUnit_Params], sModule[Module_Params], ErrParam, charsmax(ErrParam))) { - Json_LogForFile(jMUnit, "WARNING", "Param `%s` required for module `%s`, but not found.", ErrParam, sModule[Module_Name]); - return false; - } - - Forwards_DefaultReturn(VIPM_CONTINUE); - if ( - Forwards_CallP("ReadUnit", jMUnit, sMUnit[ModuleUnit_Params]) == VIPM_STOP - || Forwards_CallP("ReadModuleUnit", jMUnit, sMUnit[ModuleUnit_Params]) == VIPM_STOP - ) { - TrieDestroySafe(sMUnit[ModuleUnit_Params]); - return false; - } - - new ret; - EMIT_MODULE_EVENT(sModule, Module_OnRead, ret, jMUnit, sMUnit[ModuleUnit_Params]); - - if (ret == VIPM_STOP) { - TrieDestroySafe(sMUnit[ModuleUnit_Params]); - return false; - } - - if (!sModule[Module_Used]) { - sModule[Module_Used] = true; - SET_MODULE(sModule); - Dbg_Log("Module `%s` marked as used.", ModuleName); - } - - return true; -} - - -// Loaders - -T_ModuleUnit:ModuleUnits_LoadFromFile(const FileName[]) { - if (ModuleUnits_CacheExists(FileName)) { - return ModuleUnits_GetFromCache(FileName); - } - - if (!JSON_FILE_EXTSTS(FileName)) { - log_amx("[WARNING] File `%s` not found.", FileName); - return Invalid_ModuleUnit; - } - - new JSON:jMUnit = GET_FILE_JSON(FileName); - new T_ModuleUnit:iModuleUnit = ModuleUnits_LoadFromJson(jMUnit); - json_free(jMUnit); - - return ModuleUnits_AddToCache(iModuleUnit, FileName); -} - -T_ModuleUnit:ModuleUnits_LoadFromJson(const JSON:jModuleUnit) { - if (jModuleUnit == Invalid_JSON) { - return Invalid_ModuleUnit; - } - - new Ref[128]; - if (Json_IsRef(jModuleUnit, Ref, charsmax(Ref))) { - return ModuleUnits_LoadFromFile(Ref); - } - - new sModuleUnit[S_ModuleUnit]; - if (ModuleUnits_ReadFromJson(jModuleUnit, sModuleUnit)) { - return ModuleUnits_Push(sModuleUnit); - } - - return Invalid_ModuleUnit; -} - -Array:ModuleUnits_LoadListFromJson(const JSON:jModules, Array:aModules = Invalid_Array) { - new T_ModuleUnit:iMUnit; - ArrayCreateIfNotCreated(aModules, 1, json_get_count(jModules)); - - if (!json_is_array(jModules)) { - iMUnit = ModuleUnits_LoadFromJson(jModules); - if (iMUnit != Invalid_ModuleUnit) { - ArrayPushCell(aModules, iMUnit); - } - } else { - json_array_foreach_value(jModules: i => jModule) { - iMUnit = ModuleUnits_LoadFromJson(jModule); - if (iMUnit != Invalid_ModuleUnit) { - ArrayPushCell(aModules, iMUnit); - } - json_free(jModule); - } - } - - ArrayDestroyIfEmpty(aModules); - return aModules; -} diff --git a/amxmodx/scripting/VipM/Core/Natives.inc b/amxmodx/scripting/VipM/Core/Natives.inc deleted file mode 100644 index a7ac0a5..0000000 --- a/amxmodx/scripting/VipM/Core/Natives.inc +++ /dev/null @@ -1,72 +0,0 @@ -#if defined _vipmodular_src_Natives_included - #endinput -#endif -#define _vipmodular_src_Natives_included - -/** - * Vip Modular: Natives - */ - -#include -#include "VipM/Natives" -#include "VipM/Utils" - -Array:Native_GetParamsList(const NullArg, const ParamsCount, Array:aParams = Invalid_Array) { - const ARGS_NUM_PER_PARAM = 3; - - if ((ParamsCount - NullArg) % ARGS_NUM_PER_PARAM != 0) { - log_error(1, "[ERROR] Invalid parameters num."); - return Invalid_Array; - } - - if (aParams == Invalid_Array) { - aParams = ArrayCreate(S_CfgParam, max(1, (ParamsCount - NullArg) / ARGS_NUM_PER_PARAM)); - } - - new Param[S_CfgParam]; - for (new i = NullArg+1; i < ParamsCount; i += ARGS_NUM_PER_PARAM) { - get_string(i, Param[CfgParam_Name], charsmax(Param[CfgParam_Name])); - Param[CfgParam_Type] = E_ParamType:get_param_byref(i+1); - Param[CfgParam_Required] = bool:get_param_byref(i+2); - - // Dbg_PrintServer("^t- %s: %d, %s", Param[CfgParam_Name], _:Param[CfgParam_Type], Param[CfgParam_Required] ? "+" : "-"); - - ArrayPushArray(aParams, Param); - } - return aParams; -} - -#include "VipM/Core/Natives/Limits.inc" -#include "VipM/Core/Natives/Modules.inc" - -public plugin_natives() { - Natives_Init("VipM"); - - Natives_Reg("UserUpdate"); - Natives_Reg("Json_LogForFile"); - - Natives_Modules_Init(); - Natives_Limits_Init(); -} - -// native VipM_Json_LogForFile(const JSON:jValue, const sPrefix[], const sMessage[], any:...); -@_Json_LogForFile() { - enum {Arg_jValue = 1, Arg_sPrefix, Arg_sMessage, Arg_fmtArgs} - - static sMessage[512], sPrefix[32]; - vdformat(sMessage, charsmax(sMessage), Arg_sMessage, Arg_fmtArgs); - get_string(Arg_sPrefix, sPrefix, charsmax(sPrefix)); - - Json_LogForFile(JSON:get_param(Arg_jValue), sPrefix, sMessage); -} - -@_UserUpdate() { - enum {Arg_UserId = 1} - - new UserId = get_param(Arg_UserId); - if (!is_user_connected(UserId)) { - return; - } - - Vips_UserUpdate(UserId); -} diff --git a/amxmodx/scripting/VipM/Core/Natives/Limits.inc b/amxmodx/scripting/VipM/Core/Natives/Limits.inc deleted file mode 100644 index f6fa36a..0000000 --- a/amxmodx/scripting/VipM/Core/Natives/Limits.inc +++ /dev/null @@ -1,112 +0,0 @@ -#include amxmodx -#include "VipM/Natives" - -Natives_Limits_Init(){ - Natives_Reg("Limits_RegisterType"); - Natives_Reg("Limits_AddTypeParams"); - Natives_Reg("Limits_RegisterTypeEvent"); - - Natives_Reg("Limits_ReadFromJson"); - Natives_Reg("Limits_ReadListFromJson"); - - Natives_Reg("Limits_SetStaticValue"); - - Natives_Reg("Limits_Execute"); - Natives_Reg("Limits_ExecuteList"); -} - -// native VipM_Limits_RegisterType(const sName[], const bool:bForPlayer = true, const bool:bStatic = false); -@_Limits_RegisterType(const PluginId) { - enum {Arg_LimitName = 1, Arg_ForPlayer, Arg_Static} - - new sName[32]; - get_string(Arg_LimitName, sName, charsmax(sName)); - - new bool:bForPlayer = bool:get_param(Arg_ForPlayer); - new bool:bStatic = bool:get_param(Arg_Static); - - Limits_AddType(sName, bForPlayer, bStatic, PluginId); -} - -// native VipM_Limits_AddTypeParams(const sName[], any:...); -@_Limits_AddTypeParams(const PluginId, const cParams) { - enum {Arg_LimitName = 1, Arg_Params} - - new sName[32]; - get_string(Arg_LimitName, sName, charsmax(sName)); - - NATIVE_CHECK_LIMIT_TYPE(sName) - - new LimitType[S_Limit]; - LIMIT_TYPE_GET(sName, LimitType); - LimitType[Limit_Params] = Native_GetParamsList(Arg_Params - 1, cParams, LimitType[Limit_Params]); - SET_LIMIT_TYPE(LimitType); -} - -// native VipM_Limits_RegisterTypeEvent(const sName[], const E_LimitEvent:iEvent, const sFunc[]); -@_Limits_RegisterTypeEvent(const PluginId) { - enum {Arg_LimitName = 1, Arg_Event, Arg_FuncName} - - new sName[32], E_LimitEvent:iEvent, sFunc[64]; - get_string(Arg_LimitName, sName, charsmax(sName)); - iEvent = E_LimitEvent:get_param(Arg_Event); - get_string(Arg_FuncName, sFunc, charsmax(sFunc)); - - NATIVE_CHECK_LIMIT_TYPE(sName) - - Limits_RegisterEvent(PluginId, sName, iEvent, sFunc); -} - -// native T_LimitUnit:VipM_Limits_ReadFromJson(const JSON:jLimit); -T_LimitUnit:@_Limits_ReadFromJson() { - enum {Arg_JsonValue = 1} - - new JSON:jLimit = JSON:get_param(Arg_JsonValue); - - return Limits_LoadUnitFromJson(jLimit); -} - -// native Array:VipM_Limits_ReadListFromJson(const JSON:jLimits, Array:aLimits = Invalid_Array); -Array:@_Limits_ReadListFromJson() { - enum {Arg_JsonValue = 1, Arg_Array} - - new JSON:jLimits = JSON:get_param(Arg_JsonValue); - new Array:aLimits = Array:get_param(Arg_Array); - - return Limits_LoadUnitListFromJson(jLimits, aLimits); -} - -// native VipM_Limits_Execute(const sName[], const bool:bNewValue, const UserId = 0); -@_Limits_SetStaticValue() { - enum {Arg_LimitName = 1, Arg_NewValue, Arg_UserId} - - static sName[32]; - get_string(Arg_LimitName, sName, charsmax(sName)); - new bool:bNewValue = bool:get_param(Arg_NewValue); - new UserId = get_param(Arg_UserId); - - NATIVE_CHECK_LIMIT_TYPE(sName) - - Limits_SetStaticValue(sName, bNewValue, UserId); -} - -// native bool:VipM_Limits_Execute(const T_LimitUnit:iLimit, const UserId = 0); -bool:@_Limits_Execute() { - enum {Arg_LimitUnit = 1, Arg_UserId} - - new T_LimitUnit:iLimit = T_LimitUnit:get_param(Arg_LimitUnit); - new UserId = get_param(Arg_UserId); - - return Limits_ExecuteUnit(iLimit, UserId); -} - -// native bool:VipM_Limits_ExecuteList(const Array:aLimits, const UserId = 0, const E_LimitsExecType:iType = Limit_Exec_OR); -bool:@_Limits_ExecuteList() { - enum {Arg_LimitUnitList = 1, Arg_UserId, Arg_Type} - - new Array:aLimits = Array:get_param(Arg_LimitUnitList); - new UserId = get_param(Arg_UserId); - new E_LimitsExecType:Type = E_LimitsExecType:get_param(Arg_Type); - - return Limits_ExecuteUnitList(aLimits, UserId, Type); -} diff --git a/amxmodx/scripting/VipM/Core/Natives/Modules.inc b/amxmodx/scripting/VipM/Core/Natives/Modules.inc deleted file mode 100644 index adf1c02..0000000 --- a/amxmodx/scripting/VipM/Core/Natives/Modules.inc +++ /dev/null @@ -1,127 +0,0 @@ -#include -#include "VipM/DebugMode" -#include "VipM/Natives" - -Natives_Modules_Init(){ - Natives_Reg("Modules_Register"); - Natives_Reg("Modules_AddParams"); - Natives_Reg("Modules_RegisterEvent"); - Natives_Reg("Modules_IsActive"); - Natives_Reg("Modules_GetParams"); -} - -@_Modules_Register(const PluginId) { - enum {Arg_Module = 1, Arg_Once} - - new Module[S_Module]; - - get_string(Arg_Module, Module[Module_Name], charsmax(Module[Module_Name])); - Module[Module_PluginId] = PluginId; - Module[Module_Enabled] = false; - Module[Module_Once] = bool:get_param(Arg_Once); - - Module[Module_Params] = Invalid_Array; - Module[Module_Events] = Invalid_Trie; - - Module[Module_Used] = false; - - ArrayMapPushArray(Modules, Module, Module[Module_Name]); -} - -@_Modules_AddParams(const PluginId, const ParamsCount) { - enum {Arg_Module = 1, Arg_Params} - - new ModuleName[32], Module[S_Module]; - get_string(Arg_Module, ModuleName, charsmax(ModuleName)); - - NATIVE_CHECK_MODULE(ModuleName) - GET_MODULE(ModuleName, Module); - new bool:bSave = (Module[Module_Params] == Invalid_Array); - - // Dbg_PrintServer("Module_AddParams(%s): bSave = %s", ModuleName, bSave ? "+" : "-"); - - Module[Module_Params] = Native_GetParamsList(Arg_Params - 1, ParamsCount, Module[Module_Params]); - - // Dbg_PrintServer(":---"); - - if (bSave) { - SET_MODULE(Module); - } -} - -bool:@_Modules_RegisterEvent(const PluginId) { - enum {Arg_Module = 1, Arg_Event, Arg_Func} - - new ModuleName[32], Module[S_Module]; - get_string(Arg_Module, ModuleName, charsmax(ModuleName)); - - NATIVE_CHECK_MODULE(ModuleName) - GET_MODULE(ModuleName, Module); - - new E_ModuleEvent:Event = E_ModuleEvent:get_param(Arg_Event); - - new FuncName[64]; - get_string(Arg_Func, FuncName, charsmax(FuncName)); - - new FwdId = -1; - switch (Event) { - case Module_OnRead: // (const JSON:jCfg, Trie:Params) - FwdId = CreateOneForward(PluginId, FuncName, FP_CELL, FP_CELL); - - case Module_OnActivated: // () - FwdId = CreateOneForward(PluginId, FuncName); - - case Module_OnCompareParams: // (Trie:MainParams, const Trie:NewParams) - FwdId = CreateOneForward(PluginId, FuncName, FP_CELL, FP_CELL); - } - - if (FwdId < 0) { - return false; - } - - SET_MODULE_EVENT(Module, Event, FwdId); - SET_MODULE(Module); - - return FwdId >= 0; -} - -@_Modules_IsActive() { - enum {Arg_Module = 1} - - static ModuleName[32], Module[S_Module]; - get_string(Arg_Module, ModuleName, charsmax(ModuleName)); - - NATIVE_CHECK_MODULE(ModuleName) - GET_MODULE(ModuleName, Module); - - return Module[Module_Enabled]; -} - -Trie:@_Modules_GetParams() { - enum {Arg_Module = 1, Arg_UserId, Arg_Forced} - - static ModuleName[32]; - get_string(Arg_Module, ModuleName, charsmax(ModuleName)); - NATIVE_CHECK_MODULE(ModuleName) - - new UserId = get_param(Arg_UserId); - - new bool:bCanGetParams = true; - if (!get_param(Arg_Forced)) { - static Module[S_Module]; - GET_MODULE(ModuleName, Module); - bCanGetParams = Module[Module_Enabled]; - } - - new Trie:Params = Invalid_Trie; - if ( - !is_user_connected(UserId) - || gUserVip[UserId] == Invalid_Trie - || !TrieGetCell(gUserVip[UserId], ModuleName, Params) - || !bCanGetParams - ) { - return Invalid_Trie; - } - - return Params; -} diff --git a/amxmodx/scripting/VipM/Core/Objects/Limits/Type.inc b/amxmodx/scripting/VipM/Core/Objects/Limits/Type.inc new file mode 100644 index 0000000..17ffeae --- /dev/null +++ b/amxmodx/scripting/VipM/Core/Objects/Limits/Type.inc @@ -0,0 +1,235 @@ +#if defined __vipm_core_objects_limits_type_included + #endinput +#endif +#define __vipm_core_objects_limits_type_included + +#include +#include +#include +#include +#include "VipM/Utils" +#include "VipM/ArrayMap" +#include "VipM/ArrayTrieUtils" +#include "VipM/Core/Objects/Param" + +enum _:S_LimitType { + LimitType_Name[VIPM_LIMITS_TYPE_NAME_MAX_LEN], + Array:LimitType_Params, + + bool:LimitType_Static, + LimitType_StaticValue, + + bool:LimitType_ForPlayer, + + LimitType_Events[E_LimitEvent], +} + +enum T_LimitType { Invalid_LimitType = -1 } + +static ArrayMap(LimitTypes); // S_LimitType + +LimitType_Init() { + CallOnce(); + log_amx("Init limit types..."); + + ArrayMapCreate(LimitTypes, S_LimitType); + + log_amx("Limit types inited."); +} + +Array:LimitType_GetAll() { + return ArrayClone(LimitTypes[AM_Arr]); +} + +LimitType_GetCount() { + return ArraySizeSafe(LimitTypes[AM_Arr]); +} + +T_LimitType:LimitType_Construct(const sName[], const bool:bForPlayer = false, const bool:bStatic = false) { + if (!ArrayMapCreated(LimitTypes)) { + abort(AMX_ERR_GENERAL, "Attempt to create limit type before limits controller init."); + return Invalid_LimitType; + } + + if (LimitType_Find(sName) != Invalid_LimitType) { + abort(AMX_ERR_PARAMS, "Limit type '%s' already exists.", sName); + return Invalid_LimitType; + } + + new typeObject[S_LimitType]; + + copy(typeObject[LimitType_Name], charsmax(typeObject[LimitType_Name]), sName); + typeObject[LimitType_Params] = ArrayCreate(1, 1); + + typeObject[LimitType_Static] = bStatic; + typeObject[LimitType_StaticValue] = 0; + + typeObject[LimitType_ForPlayer] = bForPlayer; + + arrayset(typeObject[LimitType_Events], -1, sizeof(typeObject[LimitType_Events])); + + log_amx("Limit type '%s' registered.", typeObject[LimitType_Name]); + + return T_LimitType:ArrayMapPushArray(LimitTypes, typeObject, typeObject[LimitType_Name]); +} + +T_LimitType:LimitType_Find(const sName[]) { + if (ArrayMapKeyExists(LimitTypes, sName)) { + return T_LimitType:ArrayMapGetIndex(LimitTypes, sName); + } else { + return Invalid_LimitType; + } +} + +static LimitType__Get(const T_LimitType:type, typeObject[S_LimitType]) { + ArrayMapGetArray(LimitTypes, _:type, typeObject); +} + +static LimitType__Set(const typeObject[S_LimitType]) { + ArrayMapSetArrayByKey(LimitTypes, typeObject[LimitType_Name], typeObject); +} + +LimitType_AddParams(const T_LimitType:type, const Array:params) { + if (params == Invalid_Array) { + return; + } + + new typeObject[S_LimitType]; + LimitType__Get(type, typeObject); + + for (new i = 0, ii = ArraySize(params); i < ii; ++i) { + ArrayPushCell(typeObject[LimitType_Params], ArrayGetCell(params, i)); + } +} + +Trie:LimitType_ReadParams(const T_LimitType:type, const JSON:paramsJson) { + new typeObject[S_LimitType]; + LimitType__Get(type, typeObject); + + // У статических лимитов не может быть параметров + if (typeObject[LimitType_Static]) { + return Invalid_Trie; + } + + new E_ParamsReadErrorType:errType, errParam[PARAM_KEY_MAX_LEN]; + new Trie:params = ParamsController_Param_ReadList( + typeObject[LimitType_Params], paramsJson, + .iErrType = errType, + .sErrParamName = errParam, + .iErrParamNameLen = charsmax(errParam) + ); + + if (errType != ParamsReadError_None) { + TrieDestroy(params); + + switch (errType) { + case ParamsReadError_RequiredParamNotPresented: { + PCJson_ErrorForFile(paramsJson, "Param '%s' required for '%s' limit.", errParam, typeObject[LimitType_Name]); + } + case ParamsReadError_ParamValueIsInvalid: { + PCJson_ErrorForFile(paramsJson, "Param '%s' has invalid value.", errParam); + } + } + + return Invalid_Trie; + } + + if (typeObject[LimitType_Events][Limit_OnRead] >= 0) { + new ret = VIPM_STOP; + ExecuteForward(typeObject[LimitType_Events][Limit_OnRead], ret, paramsJson, params); + + if (ret == VIPM_STOP) { + TrieDestroy(params); + return Invalid_Trie; + } + } + + return params; +} + +LimitType_SetEventListener( + const T_LimitType:type, + const E_LimitEvent:event, + const pluginIndex, + const func[] +) { + new typeObject[S_LimitType]; + LimitType__Get(type, typeObject); + + if (typeObject[LimitType_Events][event] >= 0) { + DestroyForward(typeObject[LimitType_Events][event]); + } + + typeObject[LimitType_Events][event] = LimitType__MakeEventForward(event, pluginIndex, func); + + if (typeObject[LimitType_Events][event] < 0) { + abort(AMX_ERR_PARAMS, "[ERROR] Can't create forward for func '%s' in plugin #%d.", func, pluginIndex); + } + + LimitType__Set(typeObject); +} + +static LimitType__MakeEventForward(const E_LimitEvent:event, const pluginIndex, const func[]) { + switch (event) { + case Limit_OnRead: // (const JSON:jCfg, Trie:p) + return CreateOneForward(pluginIndex, func, FP_CELL, FP_CELL); + + case Limit_OnCheck: // (const Trie:p, const playerIndex) + return CreateOneForward(pluginIndex, func, FP_CELL, FP_CELL); + } + + abort(AMX_ERR_GENERAL, "[ERROR] Invalid event index (%d).", event); + return -1; +} + +bool:LimitType_IsStatic(const T_LimitType:type) { + new typeObject[S_LimitType]; + LimitType__Get(type, typeObject); + + return typeObject[LimitType_Static]; +} + +LimitType_SetStaticValue(const T_LimitType:type, const bool:value, const playerIndex = 0) { + new typeObject[S_LimitType]; + LimitType__Get(type, typeObject); + + if (!typeObject[LimitType_Static]) { + abort(AMX_ERR_PARAMS, "Trying to set static value for a non-static limit."); + return; + } + + if (playerIndex > 0) { + BitSetIf(typeObject[LimitType_StaticValue], playerIndex - 1, value); + } else { + typeObject[LimitType_StaticValue] = value; + } + + LimitType__Set(typeObject); +} + +bool:LimitType_Execute(const T_LimitType:type, const Trie:p, const playerIndex = 0) { + new typeObject[S_LimitType]; + LimitType__Get(type, typeObject); + + new bool:res = false; + if (typeObject[LimitType_Static]) { + if (typeObject[LimitType_ForPlayer]) { + res = BitIs(typeObject[LimitType_StaticValue], playerIndex - 1); + } else { + res = !!typeObject[LimitType_StaticValue]; + } + } else { + if (typeObject[LimitType_Events][Limit_OnCheck] < 0) { + abort(AMX_ERR_GENERAL, "'Limit_OnCheck' event listener for non-static limit type '%s' must be implemented.", typeObject[LimitType_Name]); + res = false; + } else { + ExecuteForward(typeObject[LimitType_Events][Limit_OnCheck], res, p, playerIndex); + } + } + + return res; +} + +T_LimitType:PCSingle_ObjVipmLimitType(const JSON:objectJson, const key[], const T_LimitType:def = Invalid_LimitType, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, VIPM_PARAM_TYPE_LIMIT_TYPE_NAME, def, dotNot, orFail); +} diff --git a/amxmodx/scripting/VipM/Core/Objects/Limits/Unit.inc b/amxmodx/scripting/VipM/Core/Objects/Limits/Unit.inc new file mode 100644 index 0000000..2509916 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/Objects/Limits/Unit.inc @@ -0,0 +1,170 @@ +#if defined __vipm_core_objects_limits_unit_included + #endinput +#endif +// Два кванта +#define __vipm_core_objects_limits_unit_included + +#include +#include +#include "VipM/Utils" +#include "VipM/ArrayTrieUtils" + +#include "VipM/Core/Objects/Limits/Type" + +// T_LimitUnit + +enum _:S_LimitUnit { + T_LimitType:LimitUnit_Type, + Trie:LimitUnit_Params, +} + +static Array:LimitUnits = Invalid_Array; + +LimitUnit_Init() { + CallOnce(); + log_amx("Init limit units..."); + + LimitType_Init(); + + LimitUnits = ArrayCreate(S_LimitUnit, 1); + + Forwards_RegAndCall("VipM_Limits_OnInited", ET_IGNORE); + log_amx("Limit units inited."); +} + +LimitUnit_GetCount() { + return ArraySizeSafe(LimitUnits); +} + +static T_LimitUnit:LimitUnit__Construct(const T_LimitType:type, const Trie:p) { + if (LimitUnits == Invalid_Array) { + abort(AMX_ERR_GENERAL, "Attempt to create limit unit before init."); + return Invalid_LimitUnit; + } + + new unitObject[S_LimitUnit]; + + unitObject[LimitUnit_Type] = type; + unitObject[LimitUnit_Params] = p; + + return T_LimitUnit:ArrayPushArray(LimitUnits, unitObject); +} + +static bool:LimitUnit__Get(const T_LimitUnit:limit, unitObject[S_LimitUnit], const bool:orFail = true) { + if (_:limit < 0 || _:limit >= LimitUnit_GetCount()) { + if (orFail) { + abort(AMX_ERR_NOTFOUND, "Invalid limit unit index (%d).", limit); + } + + return false; + } + + ArrayGetArray(LimitUnits, _:limit, unitObject); + return true; +} + +T_LimitUnit:LimitUnit_Read(const JSON:valueJson) { + static Trie:cache = Invalid_Trie; + TrieCreateIfNotCreated(cache); + + new JSON:linked, T_LimitUnit:cached = Invalid_LimitUnit, linkPath[PLATFORM_MAX_PATH]; + if (PCJson_HandleCachedLinkedValue(cache, valueJson, linked, cached, linkPath, charsmax(linkPath)) == PCJson_CachedLinkedValue_Cached) { + return cached; + } + + new T_LimitType:type = PCSingle_ObjVipmLimitType(linked, "Limit", .orFail = true); + if (type == Invalid_LimitType) { + PCJson_FreeLinked(linked, valueJson); + return Invalid_LimitUnit; + } + + new Trie:p = Invalid_Trie; + if (!LimitType_IsStatic(type)) { + p = LimitType_ReadParams(type, linked); + if (p == Invalid_Trie) { + PCJson_FreeLinked(linked, valueJson); + return Invalid_LimitUnit; + } + } + + cached = LimitUnit__Construct(type, p); + if (linkPath[0] != EOS && cached != Invalid_LimitUnit) { + TrieSetCell(cache, linkPath, cached); + } + + PCJson_FreeLinked(linked, valueJson); + return cached; +} + +Array:LimitUnit_ReadList(const JSON:limitsJson, &Array:append = Invalid_Array) { + if (append == Invalid_Array) { + append = ArrayCreate(1, 1); + } + + if (!json_is_array(limitsJson)) { + new T_LimitUnit:limit = LimitUnit_Read(limitsJson); + if (limit != Invalid_LimitUnit) { + ArrayPushCell(append, limit); + } + } else { + json_array_foreach_value (limitsJson: i => limitJson) { + append = LimitUnit_ReadList(limitJson, append); + json_free(limitJson); + } + } + + return append; +} + +bool:LimitUnit_Execute(const T_LimitUnit:limit, const UserId = 0) { + new unitObject[S_LimitUnit]; + LimitUnit__Get(limit, unitObject); + + return LimitType_Execute(unitObject[LimitUnit_Type], unitObject[LimitUnit_Params], UserId); +} + +bool:LimitUnit_ExecuteList( + const Array:aLimitUnits, + const UserId = 0, + const E_LimitsExecType:iOperator +) { + new bool:bXor = false; + + for (new i = 0, ii = ArraySizeSafe(aLimitUnits); i < ii; ++i) { + new T_LimitUnit:limit = T_LimitUnit:ArrayGetCell(aLimitUnits, i); + new bool:bRes = LimitUnit_Execute(limit, UserId); + + switch (iOperator) { + case Limit_Exec_OR: { + if (bRes) { + return true; + } + } + case Limit_Exec_AND: { + if (!bRes) { + return false; + } + } + case Limit_Exec_XOR: { + if (bRes && bXor) { + return false; + } + bXor = bXor || bRes; + } + } + } + + switch (iOperator) { + case Limit_Exec_OR: { + return false; + } + case Limit_Exec_AND: { + return true; + } + case Limit_Exec_XOR: { + return bXor; + } + } + + return false; +} diff --git a/amxmodx/scripting/VipM/Core/Objects/Modules/Type.inc b/amxmodx/scripting/VipM/Core/Objects/Modules/Type.inc new file mode 100644 index 0000000..04d2680 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/Objects/Modules/Type.inc @@ -0,0 +1,258 @@ +#if defined __vipm_core_objects_modules_type_included + #endinput +#endif +#define __vipm_core_objects_modules_type_included + +#include +#include +#include +#include "VipM/Forwards" +#include "VipM/Utils" +#include "VipM/ArrayMap" +#include "VipM/ArrayTrieUtils" +#include "VipM/Core/Objects/Param" + +enum _:S_ModuleType { + ModuleType_Name[VIPM_MODULES_TYPE_NAME_MAX_LEN], + Array:ModuleType_Params, + + bool:ModuleType_Used, + bool:ModuleType_Active, + + ModuleType_Events[E_ModuleEvent], +} + +enum T_ModuleType { Invalid_ModuleType = -1 } + +static ArrayMap(ModuleTypes); // S_ModuleType + +ModuleType_Init() { + CallOnce(); + log_amx("Init module types..."); + + ArrayMapCreate(ModuleTypes, S_ModuleType); + + Forwards_Reg("VipM_Modules_OnActivate", ET_STOP, FP_STRING); + + log_amx("Module types inited."); +} + +Array:ModuleType_GetAll() { + return ArrayClone(ModuleTypes[AM_Arr]); +} + +ModuleType_GetCount() { + return ArrayMapSize(ModuleTypes); +} + +T_ModuleType:ModuleType_Construct(const sName[]) { + if (!ArrayMapCreated(ModuleTypes)) { + abort(AMX_ERR_GENERAL, "Attempt to create module type before modules init."); + return Invalid_ModuleType; + } + + if (ModuleType_Find(sName) != Invalid_ModuleType) { + abort(AMX_ERR_PARAMS, "Module type '%s' already exists.", sName); + return Invalid_ModuleType; + } + + new ModuleType[S_ModuleType]; + + copy(ModuleType[ModuleType_Name], charsmax(ModuleType[ModuleType_Name]), sName); + ModuleType[ModuleType_Params] = ArrayCreate(1, 1); + + ModuleType[ModuleType_Used] = false; + ModuleType[ModuleType_Active] = false; + + arrayset(ModuleType[ModuleType_Events], -1, sizeof(ModuleType[ModuleType_Events])); + + log_amx("Module type '%s' registered.", ModuleType[ModuleType_Name]); + + return T_ModuleType:ArrayMapPushArray(ModuleTypes, ModuleType, ModuleType[ModuleType_Name]); +} + +T_ModuleType:ModuleType_Find(const sName[]) { + if (ArrayMapKeyExists(ModuleTypes, sName)) { + return T_ModuleType:ArrayMapGetIndex(ModuleTypes, sName); + } else { + return Invalid_ModuleType; + } +} + +static ModuleType__Get(const T_ModuleType:iModuleType, ModuleType[S_ModuleType]) { + ArrayMapGetArray(ModuleTypes, _:iModuleType, ModuleType); +} + +static ModuleType__Save(const ModuleType[S_ModuleType]) { + ArrayMapSetArrayByKey(ModuleTypes, ModuleType[ModuleType_Name], ModuleType); +} + +static ModuleType__SetValue(const T_ModuleType:iModuleType, const iCell, const any:iValue) { + return ArrayMapSetCell(ModuleTypes, iModuleType, iValue, iCell); +} + +static any:ModuleType__GetValue(const T_ModuleType:iModuleType, const iCell) { + return ArrayMapGetCell(ModuleTypes, iModuleType, iCell); +} + +ModuleType_GetName(const T_ModuleType:iModuleType, sOut[], const iOutLen) { + new ModuleType[S_ModuleType]; + ModuleType__Get(iModuleType, ModuleType); + + return copy(sOut, iOutLen, ModuleType[ModuleType_Name]); +} + +ModuleType_iGetName(const T_ModuleType:iModuleType) { + new sName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + ModuleType_GetName(iModuleType, sName, charsmax(sName)); + return sName; +} + +bool:ModuleType_IsActive(const T_ModuleType:iModuleType) { + return ModuleType__GetValue(iModuleType, ModuleType_Active); +} + +Trie:ModuleType_ReadParams(const T_ModuleType:type, const JSON:paramsJson) { + new typeObject[S_ModuleType]; + ModuleType__Get(type, typeObject); + + new E_ParamsReadErrorType:errType, errParam[PARAM_KEY_MAX_LEN]; + new Trie:params = ParamsController_Param_ReadList( + typeObject[ModuleType_Params], paramsJson, + .iErrType = errType, + .sErrParamName = errParam, + .iErrParamNameLen = charsmax(errParam) + ); + + if (errType != ParamsReadError_None) { + TrieDestroy(params); + + switch (errType) { + case ParamsReadError_RequiredParamNotPresented: { + PCJson_ErrorForFile(paramsJson, "Param '%s' required for '%s' module.", errParam, typeObject[ModuleType_Name]); + } + case ParamsReadError_ParamValueIsInvalid: { + PCJson_ErrorForFile(paramsJson, "Param '%s' has invalid value.", errParam); + } + } + + return Invalid_Trie; + } + + if (typeObject[ModuleType_Events][Module_OnRead] >= 0) { + new iRet = VIPM_STOP; + ExecuteForward(typeObject[ModuleType_Events][Module_OnRead], iRet, paramsJson, params); + + if (iRet == VIPM_STOP) { + TrieDestroy(params); + return Invalid_Trie; + } + } + + return params; +} + +ModuleType_AddParams(const T_ModuleType:module, const Array:params) { + if (params == Invalid_Array) { + return; + } + + new Array:currentParams = ModuleType__GetValue(module, ModuleType_Params); + + for (new i = 0, ii = ArraySize(params); i < ii; ++i) { + ArrayPushCell(currentParams, ArrayGetCell(params, i)); + } +} + +ModuleType_SetEventListener( + const T_ModuleType:type, + const E_ModuleEvent:event, + const pluginIndex, + const func[] +) { + new typeObject[S_ModuleType]; + ModuleType__Get(type, typeObject); + + if (typeObject[ModuleType_Events][event] >= 0) { + DestroyForward(typeObject[ModuleType_Events][event]); + } + + typeObject[ModuleType_Events][event] = ModuleType__MakeEventForward(event, pluginIndex, func); + + if (typeObject[ModuleType_Events][event] < 0) { + abort(AMX_ERR_PARAMS, "[ERROR] Can't create forward for func '%s' in plugin #%d.", func, pluginIndex); + return; + } + + ModuleType__Save(typeObject); +} + +static ModuleType__MakeEventForward(const E_ModuleEvent:event, const pluginIndex, const func[]) { + switch (event) { + case Module_OnRead: // (const JSON:jCfg, Trie:Params) + return CreateOneForward(pluginIndex, func, FP_CELL, FP_CELL); + + case Module_OnActivated: // () + return CreateOneForward(pluginIndex, func); + + case Module_OnMergeParams: // (const Trie:tParams1, const Trie:tParams2) + return CreateOneForward(pluginIndex, func, FP_CELL, FP_CELL); + } + + abort(AMX_ERR_GENERAL, "[ERROR] Invalid event index (%d).", event); + return -1; +} + +ModuleType_MarkAsUsed(const T_ModuleType:type, const bool:bState = true) { + ModuleType__SetValue(type, ModuleType_Used, bState); +} + +bool:ModuleType_Activate(const T_ModuleType:type) { + new ModuleType[S_ModuleType]; + ModuleType__Get(type, ModuleType); + + if (!ModuleType[ModuleType_Active]) { + Forwards_DefaultReturn(VIPM_CONTINUE); + if (Forwards_CallP("VipM_Modules_OnActivate", ModuleType[ModuleType_Name]) != VIPM_CONTINUE) { + return false; + } + + ModuleType[ModuleType_Active] = true; + + if (ModuleType[ModuleType_Events][Module_OnActivated] >= 0) { + ExecuteForward(ModuleType[ModuleType_Events][Module_OnActivated]); + } + + ModuleType__Save(ModuleType); + } + + return ModuleType[ModuleType_Active]; +} + +ModuleType_ActivateUsed() { + ArrayMapForeachArray (ModuleTypes: type => ModuleType[S_ModuleType]) { + if (ModuleType[ModuleType_Used]) { + ModuleType_Activate(type); + } + } +} + +Trie:ModuleType_MergeParams(const T_ModuleType:type, const Trie:tParams1, const Trie:tParams2) { + new ModuleType[S_ModuleType]; + ModuleType__Get(type, ModuleType); + + new Trie:tRes = tParams1; + if (ModuleType[ModuleType_Events][Module_OnMergeParams] >= 0) { + ExecuteForward(ModuleType[ModuleType_Events][Module_OnMergeParams], _:tRes, tParams1, tParams2); + + if (tRes != tParams1 && tRes != tParams2) { + TrieSetCell(tRes, VIPM_MODULES_PARAMS_TEMP_MARK_KEY, true); + } + } + + return tRes; +} + +T_ModuleType:PCSingle_ObjVipmModuleType(const JSON:objectJson, const key[], const T_ModuleType:def = Invalid_ModuleType, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, VIPM_PARAM_TYPE_MODULE_TYPE_NAME, def, dotNot, orFail); +} diff --git a/amxmodx/scripting/VipM/Core/Objects/Modules/Unit.inc b/amxmodx/scripting/VipM/Core/Objects/Modules/Unit.inc new file mode 100644 index 0000000..00ab969 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/Objects/Modules/Unit.inc @@ -0,0 +1,147 @@ +#if defined __vipm_core_objects_modules_unit_included + #endinput +#endif +#define __vipm_core_objects_modules_unit_included + +#include +#include "VipM/Utils" +#include "VipM/Forwards" +#include +#include "VipM/ArrayTrieUtils" + +#include "VipM/Core/Objects/Modules/Type" + +enum T_ModuleUnit { Invalid_ModuleUnit = -1 } + +enum _:S_ModuleUnit { + T_ModuleType:ModuleUnit_Type, + Trie:ModuleUnit_Params, +} + +static Array:ModuleUnits = Invalid_Array; + +ModuleUnit_Init() { + CallOnce(); + log_amx("Init module units..."); + + ModuleType_Init(); + + ModuleUnits = ArrayCreate(S_ModuleUnit, 1); + + Forwards_RegAndCall("VipM_Modules_OnInited", ET_IGNORE); + log_amx("Module units inited."); +} + +ModuleUnit_GetCount() { + return ArraySizeSafe(ModuleUnits); +} + +static T_ModuleUnit:ModuleUnit__Construct(const T_ModuleType:type, const Trie:p) { + if (ModuleUnits == Invalid_Array) { + abort(AMX_ERR_GENERAL, "Attempt to create module unit before init."); + return Invalid_ModuleUnit; + } + + new unitObject[S_ModuleUnit]; + + unitObject[ModuleUnit_Type] = type; + unitObject[ModuleUnit_Params] = p; + + ModuleType_MarkAsUsed(type); + + return T_ModuleUnit:ArrayPushArray(ModuleUnits, unitObject); +} + +static any:ModuleUnit__GetValue(const T_ModuleUnit:iModuleUnit, const iCell) { + return ArrayGetCell(ModuleUnits, _:iModuleUnit, iCell); +} + +T_ModuleUnit:ModuleUnit_Read(const JSON:valueJson) { + static Trie:cache = Invalid_Trie; + TrieCreateIfNotCreated(cache); + + new JSON:linked, T_ModuleUnit:cached = Invalid_ModuleUnit, linkPath[PLATFORM_MAX_PATH]; + if (PCJson_HandleCachedLinkedValue(cache, valueJson, linked, cached, linkPath, charsmax(linkPath)) == PCJson_CachedLinkedValue_Cached) { + return cached; + } + + new T_ModuleType:type = PCSingle_ObjVipmModuleType(linked, "Module", .orFail = true); + if (type == Invalid_ModuleType) { + PCJson_FreeLinked(linked, valueJson); + return Invalid_ModuleUnit; + } + + new Trie:p = ModuleType_ReadParams(type, linked); + if (p == Invalid_Trie) { + PCJson_FreeLinked(linked, valueJson); + return Invalid_ModuleUnit; + } + + cached = ModuleUnit__Construct(type, p); + if (linkPath[0] != EOS && cached != Invalid_ModuleUnit) { + TrieSetCell(cache, linkPath, cached); + } + + PCJson_FreeLinked(linked, valueJson); + return cached; +} + +Array:ModuleUnit_ReadList(const JSON:jModuleUnits, &Array:aModuleUnits = Invalid_Array) { + ArrayCreateIfNotCreated(aModuleUnits); + + if (!json_is_array(jModuleUnits)) { + new T_ModuleUnit:iModuleUnit = ModuleUnit_Read(jModuleUnits); + if (iModuleUnit != Invalid_ModuleUnit) { + ArrayPushCell(aModuleUnits, iModuleUnit); + } + } else { + json_array_foreach_value (jModuleUnits: i => jModuleUnit) { + aModuleUnits = ModuleUnit_ReadList(jModuleUnit, aModuleUnits); + json_free(jModuleUnit); + } + } + + return aModuleUnits; +} + +Array:JsonObject_GetModuleUnits(const JSON:jObj, const sKey[], const bool:bDotNot = false, &Array:aModuleUnits = Invalid_Array) { + if (!json_object_has_value(jObj, sKey, .dot_not = bDotNot)) { + return aModuleUnits; + } + + new JSON:jModuleUnits = json_object_get_value(jObj, sKey, bDotNot); + aModuleUnits = ModuleUnit_ReadList(jModuleUnits, aModuleUnits); + json_free(jModuleUnits); + + return aModuleUnits; +} + +Trie:ModuleUnit_GetParams(const T_ModuleUnit:iModuleUnit) { + return ModuleUnit__GetValue(iModuleUnit, ModuleUnit_Params); +} + +ModuleUnit_GetTypeName(const T_ModuleUnit:iModuleUnit, sOut[], const iOutLen) { + return ModuleType_GetName(ModuleUnit__GetValue(iModuleUnit, ModuleUnit_Type), sOut, iOutLen); +} + +// ModuleUnit_iGetTypeName(const T_ModuleUnit:iModuleUnit) { +// new sName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; +// ModuleUnit_GetModuleName(iModuleUnit, sName, charsmax(sName)); +// return sName; +// } + +Trie:ModuleUnit_FreeParamsIfTemp(&Trie:p) { + if (p == Invalid_Trie) { + return p; + } + + if (TrieKeyExists(p, VIPM_MODULES_PARAMS_TEMP_MARK_KEY)) { + TrieDestroy(p); + } + + return p; +} + +Trie:ModuleUnit_Merge(const T_ModuleUnit:iModuleUnit, const Trie:tParams1, const Trie:tParams2) { + return ModuleType_MergeParams(ModuleUnit__GetValue(iModuleUnit, ModuleUnit_Type), tParams1, tParams2); +} diff --git a/amxmodx/scripting/VipM/Core/Objects/Param.inc b/amxmodx/scripting/VipM/Core/Objects/Param.inc new file mode 100644 index 0000000..dd1e45f --- /dev/null +++ b/amxmodx/scripting/VipM/Core/Objects/Param.inc @@ -0,0 +1,81 @@ +#if defined __vipm_core_objects_param_included + #endinput +#endif +#define __vipm_core_objects_param_included + +#include +#include +#include +#include + +Array:CfgParam_GetFromNative(const iStartParam, const iNativeParamsCount, &Array:params = Invalid_Array) { + const ARGS_NUM_PER_PARAM = 3; + + new NullArg = iStartParam - 1; + + if ((iNativeParamsCount - NullArg) % ARGS_NUM_PER_PARAM != 0) { + log_error(0, "[ERROR] Invalid parameters num."); + return Invalid_Array; + } + + new iParamsCount = max(1, (iNativeParamsCount - NullArg) / ARGS_NUM_PER_PARAM); + if (params == Invalid_Array) { + params = ArrayCreate(1, iParamsCount); + } else { + ArrayResize(params, ArraySize(params) + iParamsCount); + } + + for (new i = NullArg + 1; i < iNativeParamsCount; i += ARGS_NUM_PER_PARAM) { + new paramType[PARAM_TYPE_NAME_MAX_LEN]; + switch (E_ParamType:get_param_byref(i + 1)) { + case ptInteger: { + paramType = DEFAULT_PARAMS_INT_NAME; + } + case ptFloat: { + paramType = DEFAULT_PARAMS_FLOAT_NAME; + } + case ptBoolean: { + paramType = DEFAULT_PARAMS_BOOL_NAME; + } + case ptString: { + paramType = DEFAULT_PARAMS_STR_NAME; + } + case ptColor: { + paramType = DEFAULT_PARAMS_RGB_NAME; + } + case ptVector2: { + log_amx("[WARNING] Param type ptVector2 is deprecated and will be ignored."); + continue; + } + case ptVector3: { + log_amx("[WARNING] Param type ptVector3 is deprecated and will be ignored."); + continue; + } + case ptLimit: { + paramType = VIPM_PARAM_TYPE_LIMIT_NAME; + } + case ptLimits: { + paramType = VIPM_PARAM_TYPE_LIMITS_NAME; + } + case ptCustom: { + // Чтоб не ругалось + continue; + } + default: { + log_amx("[WARNING] Invalid param type (%d).", get_param_byref(i + 1)); + continue; + } + } + + new paramName[PARAM_KEY_MAX_LEN]; + get_string(i, paramName, charsmax(paramName)); + + new bool:required = bool:get_param_byref(i + 2); + + new T_Param:param = ParamsController_Param_Construct(paramName, paramType, required); + + ArrayPushCell(params, param); + } + + return params; +} diff --git a/amxmodx/scripting/VipM/Core/Objects/VipUnit.inc b/amxmodx/scripting/VipM/Core/Objects/VipUnit.inc new file mode 100644 index 0000000..4708107 --- /dev/null +++ b/amxmodx/scripting/VipM/Core/Objects/VipUnit.inc @@ -0,0 +1,122 @@ +#if defined __vipm_core_objects_vip_unit_included + #endinput +#endif +#define __vipm_core_objects_vip_unit_included + +#include +#include +#include "VipM/Utils" +#include "VipM/ArrayTrieUtils" + +#include "VipM/Core/Objects/Modules/Unit" +#include "VipM/Core/Objects/Limits/Unit" + +enum _:S_VipUnit { + Array:VipUnit_Access, // T_LimitUnit[] + Array:VipUnit_Modules, // T_ModuleUnit[] +} + +enum T_VipUnit { Invalid_VipUnit = -1 } + +new Array:g_aVipUnits = Invalid_Array; + +VipUnit_Init() { + CallOnce(); + log_amx("Init vip units..."); + + // Пока что лимиты обязательно должны быть перед модулями + // После поломки интерфейса будет отдельный форвард для лимитов, а пока только для модулей + LimitUnit_Init(); + ModuleUnit_Init(); + + g_aVipUnits = ArrayCreate(S_VipUnit, 1); + log_amx("Vip units inited."); +} + +VipUnit_GetCount() { + return ArraySizeSafe(g_aVipUnits); +} + +static T_VipUnit:VipUnit__Construct( + const Array:aAccess, + const Array:aModules +) { + if (g_aVipUnits == Invalid_Array) { + abort(AMX_ERR_GENERAL, "Attempt to create vip unit before init."); + return Invalid_VipUnit; + } + + new VipUnit[S_VipUnit]; + + VipUnit[VipUnit_Access] = aAccess; + VipUnit[VipUnit_Modules] = aModules; + + return T_VipUnit:ArrayPushArray(g_aVipUnits, VipUnit); +} + +static any:VipUnit__GetValue(const T_VipUnit:iVipUnit, const iCell) { + return ArrayGetCell(g_aVipUnits, _:iVipUnit, iCell); +} + +VipUnit_CheckUserAccess(const T_VipUnit:vip, const playerIndex) { + Dbg_Log("VipUnit_CheckUserAccess(%d, %n) start", vip, playerIndex); + + new Array:limits = VipUnit__GetValue(vip, VipUnit_Access); + Dbg_Log("VipUnit_CheckUserAccess(%d, %n) limits = %d (side: %d)", vip, playerIndex, limits, ArraySizeSafe(limits)); + + return VipM_Limits_ExecuteList(limits, playerIndex, Limit_Exec_OR); +} + +Array:VipUnit_GetModules(const T_VipUnit:vip) { + return VipUnit__GetValue(vip, VipUnit_Modules); +} + +T_VipUnit:VipUnit_Read(const JSON:valueJson) { + static Trie:cache = Invalid_Trie; + TrieCreateIfNotCreated(cache); + + new JSON:linked, T_VipUnit:cached = Invalid_VipUnit, linkPath[PLATFORM_MAX_PATH]; + if (PCJson_HandleCachedLinkedValue(cache, valueJson, linked, cached, linkPath, charsmax(linkPath)) == PCJson_CachedLinkedValue_Cached) { + return cached; + } + + new Array:accessLimits = PCSingle_ObjVipmLimits(linked, "Access"); + if (accessLimits == Invalid_Array) { + PCJson_ErrorForFile(linked, "Field 'Access' is required in vip object."); + PCJson_FreeLinked(linked, valueJson); + return Invalid_VipUnit; + } + + new Array:modules = JsonObject_GetModuleUnits(linked, "Modules"); + if (modules == Invalid_Array) { + PCJson_ErrorForFile(linked, "Field 'Modules' is required in vip object."); + PCJson_FreeLinked(linked, valueJson); + return Invalid_VipUnit; + } + + cached = VipUnit__Construct(accessLimits, modules); + if (linkPath[0] != EOS && cached != Invalid_VipUnit) { + TrieSetCell(cache, linkPath, cached); + } + + PCJson_FreeLinked(linked, valueJson); + return cached; +} + +Array:VipUnit_ReadList(const JSON:jVipUnits, &Array:aVipUnits = Invalid_Array) { + ArrayCreateIfNotCreated(aVipUnits); + + if (!json_is_array(jVipUnits)) { + new T_VipUnit:iVipUnit = VipUnit_Read(jVipUnits); + if (iVipUnit != Invalid_VipUnit) { + ArrayPushCell(aVipUnits, iVipUnit); + } + } else { + json_array_foreach_value (jVipUnits: i => jVipUnit) { + aVipUnits = VipUnit_ReadList(jVipUnit, aVipUnits); + json_free(jVipUnit); + } + } + + return aVipUnits; +} diff --git a/amxmodx/scripting/VipM/Core/SrvCmds.inc b/amxmodx/scripting/VipM/Core/SrvCmds.inc index 942dd82..4de945b 100644 --- a/amxmodx/scripting/VipM/Core/SrvCmds.inc +++ b/amxmodx/scripting/VipM/Core/SrvCmds.inc @@ -4,74 +4,95 @@ #define _vipmodular_src_SrvCmds_included #include +#include "VipM/ArrayTrieUtils" -SrvCmds_Init(){ +#include "VipM/Core/Objects/Modules/Type" +#include "VipM/Core/Objects/Modules/Unit" +#include "VipM/Core/Objects/Limits/Type" +#include "VipM/Core/Objects/Limits/Unit" +#include "VipM/Core/Objects/Param" + +#if !defined GITHUB_ACTIONS_USED +new bool:__VIPM_INFO_COMPILED_BY_GH_ACTIONS = false; +#else +new bool:__VIPM_INFO_COMPILED_BY_GH_ACTIONS = bool:(GITHUB_ACTIONS_USED); +#endif + +SrvCmds_Init() { register_srvcmd("vipm_info", "@SrvCmd_Info"); - register_srvcmd("vipm_modules", "@SrvCmd_Modules"); - register_srvcmd("vipm_module_params", "@SrvCmd_ModuleParams"); - register_srvcmd("vipm_limits", "@SrvCmd_Limits"); - register_srvcmd("vipm_limit_params", "@SrvCmd_LimitParams"); } @SrvCmd_Info() { + new amxxVersion[32]; + get_amxx_verstring(amxxVersion, charsmax(amxxVersion)); + server_print("╓─────────"); server_print("║ %s v%s by %s:", PluginName, VIPM_VERSION, PluginAuthor); server_print("║ │"); server_print("║ ├─Contacts:"); - server_print("║ │ ├─GitHub: github.com/akraneman"); - server_print("║ │ ├─DevCS: dev-cs.ru/members/949/"); - server_print("║ │ ├─VK: vk.com/akraneman"); - server_print("║ │ └─TG: t.me/arkaneman"); + server_print("║ │ ├─GitHub Acc: https://github.com/arkaneman"); + server_print("║ │ ├─GitHub Org: https://github.com/AmxxModularEcosystem"); + server_print("║ │ ├─hlds.run: https://hlds.run/members/26/"); + server_print("║ │ └─TG: https://t.me/arkaneman"); + server_print("║ ├─Support:"); + server_print("║ │ ├─GitHub Issues: https://github.com/AmxxModularEcosystem/VipModular/issues"); + server_print("║ │ ├─hlds.run Resource: https://hlds.run/resources/2/"); + server_print("║ │ └─TG Forum: https://t.me/arkanaplugins/5"); server_print("║ │"); server_print("║ ├─Stats:"); server_print("║ │ ├─Modules:"); - server_print("║ │ │ ├─Modules count: %d", ArrayMapSize(Modules)); - server_print("║ │ │ └─Module units count: %d", ArraySizeSafe(ModuleUnits)); + server_print("║ │ │ ├─Modules count: %d", ModuleType_GetCount()); + server_print("║ │ │ └─Module units count: %d", ModuleUnit_GetCount()); server_print("║ │ ├─Limits:"); - server_print("║ │ │ ├─Types count: %d", ArrayMapSize(Limits)); - server_print("║ │ │ └─Limit units count: %d", ArraySizeSafe(LimitUnits)); + server_print("║ │ │ ├─Types count: %d", LimitType_GetCount()); + server_print("║ │ │ └─Limit units count: %d", LimitUnit_GetCount()); server_print("║ │ ├─Vips:"); - server_print("║ │ │ └─Vips count: %d", ArraySizeSafe(Vips)); - server_print("║ │ └─Compiled by AmxModX v%s:", AMXX_VERSION_STR); + server_print("║ │ │ └─Vips count: %d", VipUnit_GetCount()); + server_print("║ │ ├─Compiled by AmxModX v%s", AMXX_VERSION_STR); + server_print("║ │ ├─Runned by AmxModX v%s", amxxVersion); + server_print("║ │ └─Builded by GitHub Actions?: %s", __VIPM_INFO_COMPILED_BY_GH_ACTIONS ? "Yes" : "No"); server_print("║ │"); - server_print("║ └─GitHub repo: https://github.com/ArKaNeMaN/amxx-VipModular-pub"); + server_print("║ └─GitHub repo: https://github.com/AmxxModularEcosystem/VipModular"); server_print("╙─────────"); } -@SrvCmd_Modules(){ - PrintModulesData(Modules); -} - -@SrvCmd_ModuleParams(){ - new Module[S_Module], ModuleName[32]; - read_argv(1, ModuleName, charsmax(ModuleName)); - - if (!MODULE_EXISTS(ModuleName)) { - server_print("Module `%s` not found.", ModuleName); - return; +@SrvCmd_Modules() { + server_print("╔═════╤══════════════════════════════════╤════════╗"); + server_print("║ # │ Module name │ Status ║"); + server_print("╟─────┼──────────────────────────────────┼────────╢"); + new Array:types = ModuleType_GetAll(); + ArrayForeachArray2 (types: i => typeObject[S_ModuleType]) { + server_print("║ %03d │ %-32s │ %-6s ║", i + 1, typeObject[ModuleType_Name], typeObject[ModuleType_Active] ? "On" : "Off"); } + ArrayDestroy(types); + server_print("╟─────┴──────────────────────────────────┴────────╢"); + server_print("║ Total: %-4d ║", ModuleType_GetCount()); + server_print("╚═════════════════════════════════════════════════╝"); - GET_MODULE(ModuleName, Module); - - PrintConfigParams(Module[Module_Params]); + return PLUGIN_HANDLED; } -@SrvCmd_Limits(){ - PrintLimitsData(Limits); -} +@SrvCmd_Limits() { + server_print("╔═════╤══════════════════════════════════╤════════╤════════╤════════════╗"); + server_print("║ # │ Limit name │ Params │ Static │ For player ║"); + server_print("╟─────┼──────────────────────────────────┼────────┼────────┼────────────╢"); -@SrvCmd_LimitParams(){ - new LimitType[S_Limit], LimitName[32]; - read_argv(1, LimitName, charsmax(LimitName)); - - if (!LIMIT_TYPE_EXISTS(LimitName)) { - server_print("Limit `%s` not found.", LimitName); - return; + new Array:types = LimitType_GetAll(); + ArrayForeachArray2 (types: i => typeObject[S_LimitType]) { + server_print("║ %03d │ %-32s │ %-6d │ %-6s │ %-10s ║", + i + 1, typeObject[LimitType_Name], + ArraySizeSafe(typeObject[LimitType_Params]), + typeObject[LimitType_Static] ? "Yes" : "No", + typeObject[LimitType_ForPlayer] ? "Yes" : "No" + ); } + ArrayDestroy(types); + + server_print("╟─────┴──────────────────────────────────┴────────┴────────┴────────────╢"); + server_print("║ Total: %-4d ║", LimitType_GetCount()); + server_print("╚═══════════════════════════════════════════════════════════════════════╝"); - LIMIT_TYPE_GET(LimitName, LimitType); - - PrintConfigParams(LimitType[Limit_Params]); + return PLUGIN_HANDLED; } diff --git a/amxmodx/scripting/VipM/Core/Structs.inc b/amxmodx/scripting/VipM/Core/Structs.inc deleted file mode 100644 index 4234e0c..0000000 --- a/amxmodx/scripting/VipM/Core/Structs.inc +++ /dev/null @@ -1,14 +0,0 @@ -#if defined _vipmodular_src_Structs_included - #endinput -#endif -#define _vipmodular_src_Structs_included - -/** - * Vip Modular: Structs - */ - -enum _:S_CfgParam{ - CfgParam_Name[32], - E_ParamType:CfgParam_Type, - bool:CfgParam_Required, -} diff --git a/amxmodx/scripting/VipM/Core/Utils.inc b/amxmodx/scripting/VipM/Core/Utils.inc deleted file mode 100644 index de0dd98..0000000 --- a/amxmodx/scripting/VipM/Core/Utils.inc +++ /dev/null @@ -1,61 +0,0 @@ -#if defined _vipmodular_src_locUtils_included - #endinput -#endif -#define _vipmodular_src_locUtils_included - -/** - * Vip Modular: Utils - */ - -#include amxmodx -#include "VipM/ArrayTrieUtils" -#include "VipM/ArrayMap" - -#include "VipM/Core/Modules/Main" -#include "VipM/Core/Limits/Main" -#include "VipM/Core/Structs" - -PrintModulesData(const ArrayMap(amModules)) { - server_print("╔═════╤══════════════════════════════════╤════════╗"); - server_print("║ # │ Module name │ Status ║"); - server_print("╟─────┼──────────────────────────────────┼────────╢"); - ArrayMapForeachArray2 (amModules: i => Module[S_Module]) { - server_print("║ %03d │ %-32s │ %-6s ║", i, Module[Module_Name], Module[Module_Enabled] ? "On" : "Off"); - } - server_print("╟─────┴──────────────────────────────────┴────────╢"); - server_print("║ Total: %-5d ║", ArrayMapSize(amModules)); - server_print("╚═════════════════════════════════════════════════╝"); -} - -PrintLimitsData(const ArrayMap(amLimits)) { - server_print("╔═════╤══════════════════════════════════╤════════╤════════╤════════════╗"); - server_print("║ # │ Limit name │ Params │ Static │ For player ║"); - server_print("╟─────┼──────────────────────────────────┼────────┼────────┼────────────╢"); - ArrayMapForeachArray2 (amLimits: i => Limit[S_Limit]) { - server_print("║ %03d │ %-32s │ %-6d │ %-6s │ %-10s ║", - i, Limit[Limit_Name], - ArraySizeSafe(Limit[Limit_Params]), - Limit[Limit_Static] ? "Yes" : "No", - Limit[Limit_ForPlayer] ? "Yes" : "No" - ); - } - server_print("╟─────┴──────────────────────────────────┴────────┴────────┴────────────╢"); - server_print("║ Total: %-5d ║", ArrayMapSize(amLimits)); - server_print("╚═══════════════════════════════════════════════════════════════════════╝"); -} - -PrintConfigParams(const Array:Params) { - server_print("╔═════╤══════════════════════════════════╤══════════╤══════════╗"); - server_print("║ # │ Param name │ Type │ Required ║"); - server_print("╟─────┼──────────────────────────────────┼──────────┼──────────╢"); - ArrayForeachArray2 (Params: i => Param[S_CfgParam]) { - server_print("║ %3d │ %-32s │ %-8s │ %-8s ║", - i, Param[CfgParam_Name], - VIPM_PARAM_TYPE_NAMES[Param[CfgParam_Type]], - Param[CfgParam_Required] ? "Yes" : "No" - ); - } - server_print("╟─────┴──────────────────────────────────┴──────────┴──────────╢"); - server_print("║ Total: %-5d ║", ArraySizeSafe(Params)); - server_print("╚══════════════════════════════════════════════════════════════╝"); -} \ No newline at end of file diff --git a/amxmodx/scripting/VipM/Core/Vips.inc b/amxmodx/scripting/VipM/Core/Vips.inc deleted file mode 100644 index 0b7b39b..0000000 --- a/amxmodx/scripting/VipM/Core/Vips.inc +++ /dev/null @@ -1,51 +0,0 @@ -#if defined _vipmodular_src_Vips_included - #endinput -#endif -#define _vipmodular_src_Vips_included - -/** - * Vip Modular: Vips - */ - -#include - -#define Vips_CheckAndAdd(%1) \ - CfgUnits_CheckAndAdd(%1, Vips) - -#define Vips_Reset(%1) \ - ModuleUnits_ResetUser(%1) - -Vips_UserUpdate(const UserId) { - Vips_Reset(UserId); - Vips_CheckAndAdd(UserId); - - Forwards_CallP("UserUpdated", UserId); -} - -#define CfgUnit_CheckAccess(%1,%2) \ - Limits_ExecuteUnitList(%2[CfgUnit_LimitUnits], %1, Limit_Exec_OR) - -#define CfgUnit_AddToUser(%1,%2) \ - ModuleUnits_AddListToUser(%1, %2[CfgUnit_ModuleUnits]) - -CfgUnits_CheckAndAdd(const UserId, const Array:aUnits) { - if (aUnits == Invalid_Array) { - return; - } - - new Unit[S_CfgUnit]; - for (new i = 0; i < ArraySize(aUnits); i++) { - ArrayGetArray(aUnits, i, Unit); - - CfgUnit_CheckAndAdd(UserId, Unit); - } -} - -bool:CfgUnit_CheckAndAdd(const UserId, const Unit[S_CfgUnit]) { - if (!CfgUnit_CheckAccess(UserId, Unit)) { - return false; - } - - CfgUnit_AddToUser(UserId, Unit); - return true; -} diff --git a/amxmodx/scripting/VipM/Core/VipsManager.inc b/amxmodx/scripting/VipM/Core/VipsManager.inc new file mode 100644 index 0000000..a26900a --- /dev/null +++ b/amxmodx/scripting/VipM/Core/VipsManager.inc @@ -0,0 +1,142 @@ +#if defined __vipm__core__vips_manager__included + #endinput +#endif +#define __vipm__core__vips_manager__included + +#include +#include +#include "VipM/Forwards" +#include "VipM/ArrayTrieUtils" +#include "VipM/Core/Objects/VipUnit" + +static Array:g_aVips = Invalid_Array; // T_VipUnit[] +static g_sRootDir[PLATFORM_MAX_PATH] = ""; +static Trie:g_tUserModules[MAX_PLAYERS + 1] = {Invalid_Trie, ...}; + +VipsManager_Init() { + CallOnce(); + + VipUnit_Init(); + + g_aVips = ArrayCreate(1, 1); + Forwards_Reg("VipM_OnUserUpdated", ET_IGNORE, FP_CELL); +} + +VipsManager_VipsCount() { + return ArraySize(g_aVips); +} + +VipsManager_SetRootDir(const sRootDir[]) { + copy(g_sRootDir, charsmax(g_sRootDir), sRootDir); +} + +bool:VipsManager_LoadFromFile(const filePath[]) { + if (!file_exists(filePath)) { + return false; + } + + new JSON:unitsJson = PCJson_ParseFile(filePath, g_sRootDir); + g_aVips = VipUnit_ReadList(unitsJson, g_aVips); + PCJson_Free(unitsJson); + + return true; +} + +bool:VipsManager_LoadFromFolder(dirPath[]) { + if (!dir_exists(dirPath)) { + return false; + } + + new filePath[PLATFORM_MAX_PATH], dirHandler, FileType:fileType; + dirHandler = open_dir(dirPath, filePath, charsmax(filePath), fileType); + if (!dirHandler) { + return false; + } + + new Regex:iRegEx_FileName, ret; + iRegEx_FileName = regex_compile("(.+).json$", ret, "", 0, "i"); + + do { + if (fileType != FileType_File || regex_match_c(filePath, iRegEx_FileName) <= 0) { + continue; + } + + VipsManager_LoadFromFile(fmt("%s/%s", dirPath, filePath)); + } while (next_file(dirHandler, filePath, charsmax(filePath), fileType)); + + regex_free(iRegEx_FileName); + close_dir(dirHandler); + + return true; +} + +VipsManager_UserReload(const playerIndex) { + VipsManager_UserReset(playerIndex); + + Dbg_Log("VipsManager_UserReload(%n) start", playerIndex); + + g_tUserModules[playerIndex] = TrieCreate(); + for (new i = 0, ii = ArraySize(g_aVips); i < ii; ++i) { + Dbg_Log("VipsManager_UserReload(%n) - vip #%d", playerIndex, i); + + new T_VipUnit:vip = ArrayGetCell(g_aVips, i); + if (!VipUnit_CheckUserAccess(vip, playerIndex)) { + Dbg_Log("VipsManager_UserReload(%n) - - no access", playerIndex); + continue; + } + Dbg_Log("VipsManager_UserReload(%n) - - has access", playerIndex); + + new Array:modules = VipUnit_GetModules(vip); + for (new j = 0, jj = ArraySize(modules); j < jj; ++j) { + new T_ModuleUnit:module = ArrayGetCell(modules, j); + + new moduleName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; // TODO: Посмотреть можно ли юзать просто хендлер + ModuleUnit_GetTypeName(module, moduleName, charsmax(moduleName)); + + Dbg_Log("VipsManager_UserReload(%n) - - - module %s (#%d)", playerIndex, moduleName, j); + + new Trie:params = ModuleUnit_GetParams(module); + if (TrieKeyExists(g_tUserModules[playerIndex], moduleName)) { + Dbg_Log("VipsManager_UserReload(%n) - - - - merge", playerIndex); + new Trie:oldParams; + TrieGetCell(g_tUserModules[playerIndex], moduleName, oldParams); + + TrieSetCell(g_tUserModules[playerIndex], moduleName, ModuleUnit_Merge(module, oldParams, params)); + } else { + Dbg_Log("VipsManager_UserReload(%n) - - - - add", playerIndex); + TrieSetCell(g_tUserModules[playerIndex], moduleName, params); + } + } + } + + Forwards_CallP("VipM_OnUserUpdated", playerIndex); +} + +VipsManager_UserReset(const playerIndex) { + if (g_tUserModules[playerIndex] == Invalid_Trie) { + return; + } + + new TrieIter:iter = TrieIterCreate(g_tUserModules[playerIndex]); + while (!TrieIterEnded(iter)) { + new Trie:tParams = Invalid_Trie; + if (TrieIterGetCell(iter, tParams)) { + ModuleUnit_FreeParamsIfTemp(tParams); + } + TrieIterNext(iter); + } + TrieIterDestroy(iter); + + TrieDestroy(g_tUserModules[playerIndex]); +} + +Trie:VipsManager_GetUserParams(const playerIndex, const T_ModuleType:type) { + if (g_tUserModules[playerIndex] == Invalid_Trie) { + return Invalid_Trie; + } + + new Trie:p = Invalid_Trie; + TrieGetCell(g_tUserModules[playerIndex], ModuleType_iGetName(type), p); + + return p; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Alive.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Alive.inc new file mode 100644 index 0000000..4a00de2 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Alive.inc @@ -0,0 +1,21 @@ +#include +#include + +DefaultObjects_Limit_Alive_Register() { + VipM_Limits_RegisterType("Alive", true, true); + + RegisterHookChain(RG_CBasePlayer_Spawn, "@DefaultObjects_Limit_Alive_OnPlayerSpawn", true); + RegisterHookChain(RG_CBasePlayer_Killed, "@DefaultObjects_Limit_Alive_OnPlayerKilled", true); +} + +@DefaultObjects_Limit_Alive_OnPlayerSpawn(const playerIndex) { + VipM_Limits_SetStaticValue("Alive", true, playerIndex); +} + +@DefaultObjects_Limit_Alive_OnPlayerKilled(const playerIndex) { + VipM_Limits_SetStaticValue("Alive", false, playerIndex); +} + +DefaultObjects_Limit_Alive_OnClientPutInServer(const playerIndex) { + VipM_Limits_SetStaticValue("Alive", false, playerIndex); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Always.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Always.inc new file mode 100644 index 0000000..2569162 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Always.inc @@ -0,0 +1,9 @@ +#include +#include + +DefaultObjects_Limit_Always_Register() { + VipM_Limits_RegisterType("ForAll", false, true); + VipM_Limits_SetStaticValue("ForAll", true); + VipM_Limits_RegisterType("Always", false, true); + VipM_Limits_SetStaticValue("Always", true); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Bot.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Bot.inc new file mode 100644 index 0000000..408f814 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Bot.inc @@ -0,0 +1,10 @@ +#include +#include + +DefaultObjects_Limit_Bot_Register() { + VipM_Limits_RegisterType("Bot", true, true); +} + +DefaultObjects_Limit_Bot_OnClientAuth(const playerIndex) { + VipM_Limits_SetStaticValue("Bot", !!is_user_bot(playerIndex), playerIndex); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Counter.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Counter.inc new file mode 100644 index 0000000..caed960 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Counter.inc @@ -0,0 +1,153 @@ +#include +#include +#include +#include +#include + +static Trie:CounterTypes[VipM_L_Counter_Type]; + +DefaultObjects_Limit_Counter_Register() { + VipM_Limits_RegisterType("Counter", true, false); + VipM_Limits_AddParamsEx("Counter", + "Type", VIPM_L_COUNTER_PARAM_TYPE, true, + "Key", DEFAULT_PARAMS_SHORT_STR_NAME, true, + "Max", DEFAULT_PARAMS_INT_NAME, false, + "Inc", DEFAULT_PARAMS_INT_NAME, false + ); + VipM_Limits_RegisterTypeEvent("Counter", Limit_OnCheck, "@DefaultObjects_Limit_Counter_OnCheck"); + + RegisterHookChain(RG_CBasePlayer_Spawn, "@DefaultObjects_Limit_Counter_OnPlayerSpawn", false); + RegisterHookChain(RG_CSGameRules_RestartRound, "@DefaultObjects_Limit_Counter_OnRestartRound", false); +} + +static DefaultObjects_Limit_Counter_ResetCounters(const VipM_L_Counter_Type:type) { + if (CounterTypes[type] == Invalid_Trie) { + return; + } + + new TrieIter:iter = TrieIterCreate(CounterTypes[type]); + while (!TrieIterEnded(iter)) { + new Trie:countersByKey; + if (TrieIterGetCell(iter, countersByKey)) { + TrieDestroy(countersByKey); + } + TrieIterNext(iter); + } + TrieIterDestroy(iter); + + TrieDestroy(CounterTypes[type]); +} + +static DefaultObjects_Limit_Counter_ResetCountersForPlayer(const VipM_L_Counter_Type:type, const playerIndex) { + if (CounterTypes[type] == Invalid_Trie) { + return; + } + + new TrieIter:iter = TrieIterCreate(CounterTypes[type]); + while (!TrieIterEnded(iter)) { + new Trie:countersByKey; + if (TrieIterGetCell(iter, countersByKey)) { + TrieDeleteKey(countersByKey, DefaultObjects_Limit_Counter_GetPlayerKey(playerIndex)); + } + TrieIterNext(iter); + } + TrieIterDestroy(iter); +} + +static Trie:DefaultObjects_Limit_Counter_PrepareKey(const VipM_L_Counter_Type:type, const key[]) { + if (CounterTypes[type] == Invalid_Trie) { + CounterTypes[type] = TrieCreate(); + } + + new Trie:countersByKey = Invalid_Trie; + if (!TrieGetCell(CounterTypes[type], key, countersByKey)) { + countersByKey = TrieCreate(); + TrieSetCell(CounterTypes[type], key, countersByKey); + } + + return countersByKey; +} + +static DefaultObjects_Limit_Counter_GetPlayerKey(const playerIndex) { + new str[MAX_AUTHID_LENGTH]; + get_user_authid(playerIndex, str, charsmax(str)); + return str; +} + +@DefaultObjects_Limit_Counter_OnCheck(const Trie:p, const playerIndex) { + new Trie:counter = DefaultObjects_Limit_Counter_PrepareKey( + .type = PCGet_Cell(p, "Type"), + .key = PCGet_iStr(p, "Key") + ); + + new value; + if (!TrieGetCell(counter, DefaultObjects_Limit_Counter_GetPlayerKey(playerIndex), value)) { + value = 0; + } + + if (value >= PCGet_Int(p, "Max")) { + return false; + } + + value += PCGet_Int(p, "Inc", 1); + + TrieSetCell(counter, DefaultObjects_Limit_Counter_GetPlayerKey(playerIndex), value); + + return true; +} + +DefaultObjects_Limit_Counter_OnClientPutInServer(const playerIndex) { + DefaultObjects_Limit_Counter_ResetCountersForPlayer(VipM_L_Counter_PerSession, playerIndex); +} + +@DefaultObjects_Limit_Counter_OnPlayerSpawn(const playerIndex) { + DefaultObjects_Limit_Counter_ResetCountersForPlayer(VipM_L_Counter_PerLife, playerIndex); +} + +@DefaultObjects_Limit_Counter_OnRestartRound(const playerIndex) { + DefaultObjects_Limit_Counter_ResetCounters(VipM_L_Counter_PerRound); + if (get_member_game(m_bCompleteReset)) { + DefaultObjects_Limit_Counter_ResetCounters(VipM_L_Counter_PerGame); + } +} + +DefaultObjects_Limit_Counter_RegsiterNatives() { + register_native("VipM_L_Counter_Get", "@VipM_L_Counter_Get"); + register_native("VipM_L_Counter_Set", "@VipM_L_Counter_Set"); +} + +@VipM_L_Counter_Get() { + enum {Arg_Type = 1, Arg_Key, Arg_PlayerIndex} + + new VipM_L_Counter_Type:type = VipM_L_Counter_Type:get_param(Arg_Type); + new key[VIPM_L_COUNTER_KEY_MAX_LEN]; + get_string(Arg_Key, key, charsmax(key)); + new playerIndex = get_param(Arg_PlayerIndex); + + new value = 0; + TrieGetCell( + DefaultObjects_Limit_Counter_PrepareKey(type, key), + DefaultObjects_Limit_Counter_GetPlayerKey(playerIndex), + value + ); + + return value; +} + +@VipM_L_Counter_Set() { + enum {Arg_Type = 1, Arg_Key, Arg_PlayerIndex, Arg_Value} + + new VipM_L_Counter_Type:type = VipM_L_Counter_Type:get_param(Arg_Type); + new key[VIPM_L_COUNTER_KEY_MAX_LEN]; + get_string(Arg_Key, key, charsmax(key)); + new playerIndex = get_param(Arg_PlayerIndex); + new value = get_param(Arg_Value); + + TrieSetCell( + DefaultObjects_Limit_Counter_PrepareKey(type, key), + DefaultObjects_Limit_Counter_GetPlayerKey(playerIndex), + value + ); + + return value; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Flags.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Flags.inc new file mode 100644 index 0000000..328465b --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Flags.inc @@ -0,0 +1,23 @@ +#include +#include +#include + +DefaultObjects_Limit_Flags_Register() { + VipM_Limits_RegisterType("Flags", true, false); + VipM_Limits_AddParamsEx("Flags", + "Flags", DEFAULT_PARAMS_FLAGS_NAME, true, + "Strict", DEFAULT_PARAMS_BOOL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("Flags", Limit_OnCheck, "@DefaultObjects_Limit_Flags_OnCheck"); +} + +@DefaultObjects_Limit_Flags_OnCheck(const Trie:p, const playerIndex) { + new playerFlags = get_user_flags(playerIndex); + new flags = PCGet_Int(p, "Flags"); + + if (PCGet_Bool(p, "Strict", false)) { + return (playerFlags & flags) == flags; + } else { + return playerFlags & flags; + } +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Frags.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Frags.inc new file mode 100644 index 0000000..78d6700 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Frags.inc @@ -0,0 +1,21 @@ +#include +#include +#include + +DefaultObjects_Limit_Frags_Register() { + VipM_Limits_RegisterType("Frags", true, false); + VipM_Limits_AddParamsEx("Frags", + "Min", DEFAULT_PARAMS_INT_NAME, false, + "Max", DEFAULT_PARAMS_INT_NAME, false + ); + VipM_Limits_RegisterTypeEvent("Frags", Limit_OnCheck, "@DefaultObjects_Limit_Frags_OnCheck"); +} + +@DefaultObjects_Limit_Frags_OnCheck(const Trie:p, const playerIndex) { + new frags = get_user_frags(playerIndex); + + return ( + frags >= PCGet_Int(p, "Min", cellmin) + && frags <= PCGet_Int(p, "Max", cellmax) + ); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/GameTime.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/GameTime.inc new file mode 100644 index 0000000..cdec24f --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/GameTime.inc @@ -0,0 +1,22 @@ +#include +#include +#include + +DefaultObjects_Limit_GameTime_Register() { + VipM_Limits_RegisterType("GameTime", false, false); + VipM_Limits_AddParamsEx("GameTime", + "Min", DEFAULT_PARAMS_TIME_INTERVAL_NAME, false, + "Max", DEFAULT_PARAMS_TIME_INTERVAL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("GameTime", Limit_OnCheck, "@DefaultObjects_Limit_GameTime_OnCheck"); +} + + +@DefaultObjects_Limit_GameTime_OnCheck(const Trie:p) { + new gameTime = floatround(get_gametime()); + + return ( + gameTime >= PCGet_Int(p, "Min", cellmin) + && gameTime <= PCGet_Int(p, "Max", cellmax) + ); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/HasPrimaryWeapon.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/HasPrimaryWeapon.inc new file mode 100644 index 0000000..bec98a6 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/HasPrimaryWeapon.inc @@ -0,0 +1,17 @@ +#include +#include +#include + +DefaultObjects_Limit_HasPrimaryWeapon_Register() { + VipM_Limits_RegisterType("HasPrimaryWeapon", true, false); + VipM_Limits_AddParamsEx("HasPrimaryWeapon", + "HasNot", DEFAULT_PARAMS_BOOL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("HasPrimaryWeapon", Limit_OnCheck, "@DefaultObjects_Limit_HasPrimaryWeapon_OnCheck"); +} + +@DefaultObjects_Limit_HasPrimaryWeapon_OnCheck(const Trie:p, const playerIndex) { + new bool:res = get_member(playerIndex, m_bHasPrimary); + + return PCGet_Bool(p, "HasNot", false) ? !res : res; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/InBuyZone.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/InBuyZone.inc new file mode 100644 index 0000000..6c52132 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/InBuyZone.inc @@ -0,0 +1,19 @@ +#include +#include +#include + +#include "VipM/Utils" + +DefaultObjects_Limit_InBuyZone_Register() { + VipM_Limits_RegisterType("InBuyZone", true, false); + VipM_Limits_AddParamsEx("InBuyZone", + "Reverse", DEFAULT_PARAMS_BOOL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("InBuyZone", Limit_OnCheck, "@DefaultObjects_Limit_InBuyZone_OnCheck"); +} + +@DefaultObjects_Limit_InBuyZone_OnCheck(const Trie:p, const playerIndex) { + new bool:res = IsUserInBuyZone(playerIndex); + + return PCGet_Bool(p, "Reverse", false) ? !res : res; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/InFreezyTime.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/InFreezyTime.inc new file mode 100644 index 0000000..7b56d24 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/InFreezyTime.inc @@ -0,0 +1,16 @@ +#include +#include +#include + +DefaultObjects_Limit_InFreezyTime_Register() { + VipM_Limits_RegisterType("InFreezyTime", false, false); + VipM_Limits_AddParamsEx("InFreezyTime", + "Reverse", DEFAULT_PARAMS_BOOL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("InFreezyTime", Limit_OnCheck, "@DefaultObjects_Limit_InFreezyTime_OnCheck"); +} + +@DefaultObjects_Limit_InFreezyTime_OnCheck(const Trie:p) { + new bool:bFreezyPeriod = get_member_game(m_bFreezePeriod); + return PCGet_Bool(p, "Reverse", false) ? !bFreezyPeriod : bFreezyPeriod; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Ip.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Ip.inc new file mode 100644 index 0000000..24f7363 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Ip.inc @@ -0,0 +1,24 @@ +#include +#include +#include + +static PlayerIps[MAX_PLAYERS + 1][MAX_IP_LENGTH]; + +DefaultObjects_Limit_Ip_Register() { + VipM_Limits_RegisterType("Ip", true, false); + VipM_Limits_AddParamsEx("Ip", + "Ip", DEFAULT_PARAMS_SHORT_STR_NAME, true + ); + VipM_Limits_RegisterTypeEvent("Ip", Limit_OnCheck, "@DefaultObjects_Limit_Ip_OnCheck"); +} + +DefaultObjects_Limit_Ip_OnClientAuth(const playerIndex) { + get_user_ip(playerIndex, PlayerIps[playerIndex], charsmax(PlayerIps[]), true); +} + +@DefaultObjects_Limit_Ip_OnCheck(const Trie:p, const playerIndex) { + static ip[MAX_IP_LENGTH]; + PCGet_Str(p, "SteamId", ip, charsmax(ip)); + + return equali(PlayerIps[playerIndex], ip); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/LifeTime.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/LifeTime.inc new file mode 100644 index 0000000..8271523 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/LifeTime.inc @@ -0,0 +1,29 @@ +#include +#include +#include + +static Float:PlayerSpawnTime[MAX_PLAYERS + 1] = {0.0, ...}; + +DefaultObjects_Limit_LifeTime_Register() { + VipM_Limits_RegisterType("LifeTime", true, false); + VipM_Limits_AddParamsEx("LifeTime", + "Min", DEFAULT_PARAMS_TIME_INTERVAL_NAME, false, + "Max", DEFAULT_PARAMS_TIME_INTERVAL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("LifeTime", Limit_OnCheck, "@DefaultObjects_Limit_LifeTime_OnCheck"); + + RegisterHookChain(RG_CBasePlayer_Spawn, "@DefaultObjects_Limit_LifeTime_OnPlayerSpawn", true); +} + +@DefaultObjects_Limit_LifeTime_OnPlayerSpawn(const playerIndex) { + PlayerSpawnTime[playerIndex] = get_gametime(); +} + +@DefaultObjects_Limit_LifeTime_OnCheck(const Trie:p, const playerIndex) { + new lifeTime = floatround(get_gametime() - PlayerSpawnTime[playerIndex]); + + return ( + lifeTime >= PCGet_Int(p, "Min", cellmin) + && lifeTime <= PCGet_Int(p, "Max", cellmax) + ); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Logic.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Logic.inc new file mode 100644 index 0000000..866ed86 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Logic.inc @@ -0,0 +1,44 @@ +#include +#include + +DefaultObjects_Limit_Logic_Register() { + VipM_Limits_RegisterType("Logic-OR", false, false); + VipM_Limits_AddParamsEx("Logic-OR", + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, true + ); + VipM_Limits_RegisterTypeEvent("Logic-OR", Limit_OnCheck, "@DefaultObjects_Limit_Logic_OnOrCheck"); + + VipM_Limits_RegisterType("Logic-XOR", false, false); + VipM_Limits_AddParamsEx("Logic-XOR", + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, true + ); + VipM_Limits_RegisterTypeEvent("Logic-XOR", Limit_OnCheck, "@DefaultObjects_Limit_Logic_OnXorCheck"); + + VipM_Limits_RegisterType("Logic-AND", false, false); + VipM_Limits_AddParamsEx("Logic-AND", + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, true + ); + VipM_Limits_RegisterTypeEvent("Logic-AND", Limit_OnCheck, "@DefaultObjects_Limit_Logic_OnAndCheck"); + + VipM_Limits_RegisterType("Logic-NOT", false, false); + VipM_Limits_AddParamsEx("Logic-NOT", + "Limits", VIPM_PARAM_TYPE_LIMITS_NAME, true + ); + VipM_Limits_RegisterTypeEvent("Logic-NOT", Limit_OnCheck, "@DefaultObjects_Limit_Logic_OnNotCheck"); +} + +@DefaultObjects_Limit_Logic_OnOrCheck(const Trie:p, const playerIndex){ + return PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_OR); +} + +@DefaultObjects_Limit_Logic_OnXorCheck(const Trie:p, const playerIndex){ + return PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_XOR); +} + +@DefaultObjects_Limit_Logic_OnAndCheck(const Trie:p, const playerIndex){ + return PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND); +} + +@DefaultObjects_Limit_Logic_OnNotCheck(const Trie:p, const playerIndex){ + return !PCGet_VipmLimitsCheck(p, "Limits", playerIndex, Limit_Exec_AND); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Map.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Map.inc new file mode 100644 index 0000000..9402e85 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Map.inc @@ -0,0 +1,37 @@ +#include +#include +#include + +new RealCurrentMapName[32]; + +// TODO: Указывание нескольких карт/префиксов. Возможно отдельным лимитом. + +DefaultObjects_Limit_Map_Register() { + VipM_Limits_RegisterType("Map", true, false); + VipM_Limits_AddParamsEx("Map", + "Map", DEFAULT_PARAMS_SHORT_STR_NAME, true, + "Real", DEFAULT_PARAMS_BOOL_NAME, false, + "Prefix", DEFAULT_PARAMS_BOOL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("Map", Limit_OnCheck, "@DefaultObjects_Limit_Map_OnCheck"); + + rh_get_mapname(RealCurrentMapName, charsmax(RealCurrentMapName), MNT_TRUE); +} + +@DefaultObjects_Limit_Map_OnCheck(const Trie:p, const playerIndex) { + static map[32]; + new len = PCGet_Str(p, "Map", map, charsmax(map)); + + if (!PCGet_Bool(p, "Prefix", false)) { + len = 0; + } + + if (PCGet_Bool(p, "Real", false)) { + return equali(map, RealCurrentMapName, len); + } else { + static currentMapName[32]; + rh_get_mapname(currentMapName, charsmax(currentMapName), MNT_SET); + + return equali(map, currentMapName, len); + } +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Name.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Name.inc new file mode 100644 index 0000000..a444a3a --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Name.inc @@ -0,0 +1,19 @@ +#include +#include +#include +#include "VipM/Utils" + +DefaultObjects_Limit_Name_Register() { + VipM_Limits_RegisterType("Name", true, false); + VipM_Limits_AddParamsEx("Name", + "Name", DEFAULT_PARAMS_SHORT_STR_NAME, true + ); + VipM_Limits_RegisterTypeEvent("Name", Limit_OnCheck, "@DefaultObjects_Limit_Name_OnCheck"); +} + +@DefaultObjects_Limit_Name_OnCheck(const Trie:p, const playerIndex) { + static name[MAX_NAME_LENGTH]; + get_user_name(playerIndex, name, charsmax(name)); + + return equal(name, PCGet_iStr(p, "Name")); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Never.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Never.inc new file mode 100644 index 0000000..62281b0 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Never.inc @@ -0,0 +1,7 @@ +#include +#include + +DefaultObjects_Limit_Never_Register() { + VipM_Limits_RegisterType("Never", false, true); + VipM_Limits_SetStaticValue("Never", false); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/OncePer.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/OncePer.inc new file mode 100644 index 0000000..ead80b3 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/OncePer.inc @@ -0,0 +1,74 @@ +#include +#include + +static Trie:UsedInRound = Invalid_Trie; +static Trie:UsedInMap = Invalid_Trie; +static Trie:UsedInGame = Invalid_Trie; + +DefaultObjects_Limit_OncePer_Register() { + UsedInRound = TrieCreate(); + UsedInMap = TrieCreate(); + UsedInGame = TrieCreate(); + RegisterHookChain(RG_CSGameRules_RestartRound, "@DefaultObjects_Limit_OncePer_OnRestartRound", true); + + VipM_Limits_RegisterType("OncePerRound", true, false); + VipM_Limits_RegisterTypeEvent("OncePerRound", Limit_OnCheck, "@DefaultObjects_Limit_OncePer_OnOncePerRoundCheck"); + + // thx for idea: https://dev-cs.ru/threads/24759/page-2#post-141912 + VipM_Limits_RegisterType("OncePerMap", true, false); + VipM_Limits_RegisterTypeEvent("OncePerMap", Limit_OnCheck, "@DefaultObjects_Limit_OncePer_OnOncePerMapCheck"); + + VipM_Limits_RegisterType("OncePerGame", true, false); + VipM_Limits_RegisterTypeEvent("OncePerGame", Limit_OnCheck, "@DefaultObjects_Limit_OncePer_OnOncePerGameCheck"); +} + +@DefaultObjects_Limit_OncePer_OnRestartRound() { + TrieClear(UsedInRound); + if (get_member_game(m_bCompleteReset)) { + TrieClear(UsedInGame); + } +} + +@DefaultObjects_Limit_OncePer_OnOncePerGameCheck(const Trie:p, const playerIndex) { + static sTrieKey[MAX_AUTHID_LENGTH + 12]; + formatex(sTrieKey, charsmax(sTrieKey), "%d|%d", get_user_userid(playerIndex), p); + // В случае лимитов, хендлер Trie параметров можно считать уникальным для каждого инстанса лимита + // Нужно чтобы можно было указать этот лимит в двух местах и чтобы они при этом не пересекались + // Ну а SteamID для того, чтобы после перезахода оно не сбрасывалось + // + // P.S. Или лучше всё же пихать в параметры идентификатор, по котому их разделять? + // Или оба сразу?) + // + // UPD: Устарело, не стоит рассчитывать на кэширование ссылок. + + if (TrieKeyExists(UsedInGame, sTrieKey)) { + return false; + } + + TrieSetCell(UsedInGame, sTrieKey, true); + return true; +} + +@DefaultObjects_Limit_OncePer_OnOncePerMapCheck(const Trie:p, const playerIndex) { + static sTrieKey[MAX_AUTHID_LENGTH + 12]; + formatex(sTrieKey, charsmax(sTrieKey), "%d|%d", get_user_userid(playerIndex), p); + + if (TrieKeyExists(UsedInMap, sTrieKey)) { + return false; + } + + TrieSetCell(UsedInMap, sTrieKey, true); + return true; +} + +@DefaultObjects_Limit_OncePer_OnOncePerRoundCheck(const Trie:p, const playerIndex) { + static sTrieKey[MAX_AUTHID_LENGTH + 12]; + formatex(sTrieKey, charsmax(sTrieKey), "%d|%d", get_user_userid(playerIndex), p); + + if (TrieKeyExists(UsedInRound, sTrieKey)) { + return false; + } + + TrieSetCell(UsedInRound, sTrieKey, true); + return true; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Round.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Round.inc new file mode 100644 index 0000000..fc71201 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Round.inc @@ -0,0 +1,22 @@ +#include +#include +#include +#include + +DefaultObjects_Limit_Round_Register() { + VipM_Limits_RegisterType("Round", false, false); + VipM_Limits_AddParamsEx("Round", + "Min", DEFAULT_PARAMS_INT_NAME, false, + "Max", DEFAULT_PARAMS_INT_NAME, false + ); + VipM_Limits_RegisterTypeEvent("Round", Limit_OnCheck, "@DefaultObjects_Limit_Round_OnCheck"); +} + +@DefaultObjects_Limit_Round_OnCheck(const Trie:Params, const UserId) { + new currentRound = get_member_game(m_iTotalRoundsPlayed) + 1; + + return ( + currentRound >= PCGet_Int(Params, "Min", cellmin) + && currentRound <= PCGet_Int(Params, "Max", cellmax) + ); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/RoundTime.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/RoundTime.inc new file mode 100644 index 0000000..64c170e --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/RoundTime.inc @@ -0,0 +1,21 @@ +#include +#include +#include + +DefaultObjects_Limit_RoundTime_Register() { + VipM_Limits_RegisterType("RoundTime", false, false); + VipM_Limits_AddParamsEx("RoundTime", + "Min", DEFAULT_PARAMS_TIME_INTERVAL_NAME, false, + "Max", DEFAULT_PARAMS_TIME_INTERVAL_NAME, false + ); + VipM_Limits_RegisterTypeEvent("RoundTime", Limit_OnCheck, "@DefaultObjects_Limit_RoundTime_OnCheck"); +} + +@DefaultObjects_Limit_RoundTime_OnCheck(const Trie:p) { + new roundTime = floatround(get_gametime() - Float:get_member_game(m_fRoundStartTime)); + + return ( + roundTime >= PCGet_Int(p, "Min", cellmin) + && roundTime <= PCGet_Int(p, "Max", cellmax) + ); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Steam.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Steam.inc new file mode 100644 index 0000000..358a26d --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Steam.inc @@ -0,0 +1,26 @@ +#include +#include +#include + +static bool:IsSteamLimitAvailable = false; + +DefaultObjects_Limit_Steam_Register() { + VipM_Limits_RegisterType("Steam", true, true); +} + +DefaultObjects_Limit_Steam_NativeFilter(const name[], const bool:trap) { + if (equal(name, "REU_GetAuthtype")) { + IsSteamLimitAvailable = trap; + return true; + } + + return false; +} + +DefaultObjects_Limit_Steam_OnClientAuth(const playerIndex) { + if (IsSteamLimitAvailable) { + VipM_Limits_SetStaticValue("Steam", is_user_steam(playerIndex), playerIndex); + } else { + VipM_Limits_SetStaticValue("Steam", true, playerIndex); + } +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/SteamId.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/SteamId.inc new file mode 100644 index 0000000..12610d4 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/SteamId.inc @@ -0,0 +1,24 @@ +#include +#include +#include + +static PlayerSteamIds[MAX_PLAYERS + 1][MAX_AUTHID_LENGTH]; + +DefaultObjects_Limit_SteamId_Register() { + VipM_Limits_RegisterType("SteamId", true, false); + VipM_Limits_AddParamsEx("SteamId", + "SteamId", DEFAULT_PARAMS_SHORT_STR_NAME, true + ); + VipM_Limits_RegisterTypeEvent("SteamId", Limit_OnCheck, "@DefaultObjects_Limit_SteamId_OnCheck"); +} + +DefaultObjects_Limit_SteamId_OnClientAuth(const playerIndex, const steamId[]) { + copy(PlayerSteamIds[playerIndex], charsmax(PlayerSteamIds[]), steamId); +} + +@DefaultObjects_Limit_SteamId_OnCheck(const Trie:p, const playerIndex) { + static steamId[MAX_AUTHID_LENGTH]; + PCGet_Str(p, "SteamId", steamId, charsmax(steamId)); + + return equali(PlayerSteamIds[playerIndex], steamId); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/Time.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/Time.inc new file mode 100644 index 0000000..8e2d9d5 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/Time.inc @@ -0,0 +1,51 @@ +#include +#include +#include + +DefaultObjects_Limit_Time_Register() { + VipM_Limits_RegisterType("Time", false, false); + VipM_Limits_AddParamsEx("Time", + "Before", DEFAULT_PARAMS_TIME_NAME, false, + "After", DEFAULT_PARAMS_TIME_NAME, false + ); + VipM_Limits_RegisterTypeEvent("Time", Limit_OnCheck, "@DefaultObjects_Limit_Time_OnCheck"); +} + +@DefaultObjects_Limit_Time_OnCheck(const Trie:p) { + new before = PCGet_Int(p, "Before", 0); + new after = PCGet_Int(p, "After", 0); + + if (!before && !after) { + return true; + } + + new currentTime = get_systime() % (24 * 60 * 60); + + if (!before) { + return currentTime > after; + } + + if (!after) { + return currentTime < before; + } + + if (before == after) { + return before == currentTime; + } + + if (after < before) { + return ( + currentTime > after + && currentTime < before + ); + } + + if (after > before) { + return ( + currentTime > after + || currentTime < before + ); + } + + return false; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/WasKilled.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/WasKilled.inc new file mode 100644 index 0000000..f791051 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/WasKilled.inc @@ -0,0 +1,19 @@ +#include +#include + +DefaultObjects_Limit_WasAlive_Register() { + VipM_Limits_RegisterType("WasAlive", true, true); + VipM_Limits_RegisterType("WasKilled", true, true); + + RegisterHookChain(RG_CBasePlayer_Spawn, "@DefaultObjects_Limit_WasAlive_OnPlayerSpawn", false); +} + +@DefaultObjects_Limit_WasAlive_OnPlayerSpawn(const playerIndex) { + VipM_Limits_SetStaticValue("WasAlive", !!is_user_alive(playerIndex), playerIndex); + VipM_Limits_SetStaticValue("WasKilled", !is_user_alive(playerIndex), playerIndex); +} + +DefaultObjects_Limit_WasAlive_OnClientPutInServer(const playerIndex) { + VipM_Limits_SetStaticValue("WasAlive", false, playerIndex); + VipM_Limits_SetStaticValue("WasKilled", true, playerIndex); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Limit/WeekDay.inc b/amxmodx/scripting/VipM/DefaultObjects/Limit/WeekDay.inc new file mode 100644 index 0000000..9e64a10 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Limit/WeekDay.inc @@ -0,0 +1,19 @@ +#include +#include +#include +#include "VipM/Utils" + +DefaultObjects_Limit_WeekDay_Register() { + VipM_Limits_RegisterType("WeekDay", false, false); + VipM_Limits_AddParamsEx("WeekDay", + "Day", DEFAULT_PARAMS_WEEK_DAY_NAME, true + ); + VipM_Limits_RegisterTypeEvent("WeekDay", Limit_OnCheck, "@DefaultObjects_Limit_WeekDay_OnCheck"); +} + +@DefaultObjects_Limit_WeekDay_OnCheck(const Trie:p) { + new sWeekDay[4]; + get_time("%w", sWeekDay, charsmax(sWeekDay)); + + return str_to_num(sWeekDay) == PCGet_Int(p, "Day", -1); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/ParamType/CounterType.inc b/amxmodx/scripting/VipM/DefaultObjects/ParamType/CounterType.inc new file mode 100644 index 0000000..4a952e7 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/ParamType/CounterType.inc @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include + +DefaultObjects_ParamType_CounterType_Register() { + ParamsController_RegSimpleType(VIPM_L_COUNTER_PARAM_TYPE, "@DefaultObjects_ParamType_CounterType_OnRead"); +} + +bool:@DefaultObjects_ParamType_CounterType_OnRead(const JSON:valueJson) { + if (!json_is_string(valueJson)) { + PCJson_LogForFile(valueJson, "WARNING", "Counter type must be a string (PerRound, PerLife, PerSession, PerGame, PerMap)."); + return false; + } + + new str[VIPM_L_COUNTER_KEY_MAX_LEN]; + json_get_string(valueJson, str, charsmax(str)); + + if (equali(str, "Round") || equali(str, "PerRound")) { + return ParamsController_SetCell(VipM_L_Counter_PerRound); + } else if (equali(str, "Life") || equali(str, "PerLife")) { + return ParamsController_SetCell(VipM_L_Counter_PerLife); + } else if (equali(str, "Session") || equali(str, "PerSession")) { + return ParamsController_SetCell(VipM_L_Counter_PerSession); + } else if (equali(str, "Game") || equali(str, "PerGame")) { + return ParamsController_SetCell(VipM_L_Counter_PerGame); + } else if (equali(str, "Map") || equali(str, "PerMap")) { + return ParamsController_SetCell(VipM_L_Counter_PerMap); + } + + PCJson_LogForFile(valueJson, "WARNING", "Counter type `%s` is not defined. Available types: PerRound, PerLife, PerSession, PerGame, PerMap.", str); + return false; +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/ParamType/Limit.inc b/amxmodx/scripting/VipM/DefaultObjects/ParamType/Limit.inc new file mode 100644 index 0000000..b6d0f5b --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/ParamType/Limit.inc @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +DefaultObjects_ParamType_Limit_Register() { + ParamsController_RegSimpleType(VIPM_PARAM_TYPE_LIMIT_NAME, "@DefaultObjects_ParamType_Limit_OnRead"); +} + +bool:@DefaultObjects_ParamType_Limit_OnRead(const JSON:valueJson) { + new T_LimitUnit:limit = VipM_Limits_ReadFromJson(valueJson); + + if (limit == Invalid_LimitUnit) { + return false; + } + + return ParamsController_SetCell(limit); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/ParamType/LimitType.inc b/amxmodx/scripting/VipM/DefaultObjects/ParamType/LimitType.inc new file mode 100644 index 0000000..5e631ad --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/ParamType/LimitType.inc @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +#include "VipM/Core/Objects/Limits/Type" + +DefaultObjects_ParamType_LimitType_Register() { + ParamsController_RegSimpleType(VIPM_PARAM_TYPE_LIMIT_TYPE_NAME, "@DefaultObjects_ParamType_LimitType_OnRead"); +} + +bool:@DefaultObjects_ParamType_LimitType_OnRead(const JSON:valueJson) { + new typeName[VIPM_LIMITS_TYPE_NAME_MAX_LEN]; + PCSingle_ShortString(valueJson, typeName, charsmax(typeName)); + trim(typeName); + + if (typeName[0] == EOS) { + return PCJson_LogForFile(valueJson, "WARNING", "Limit type name not specified."); + } + + new T_LimitType:type = LimitType_Find(typeName); + if (type == Invalid_LimitType) { + return PCJson_LogForFile(valueJson, "WARNING", "Limit type '%s' not found.", typeName); + } + + return ParamsController_SetCell(type); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/ParamType/Limits.inc b/amxmodx/scripting/VipM/DefaultObjects/ParamType/Limits.inc new file mode 100644 index 0000000..6eba2b7 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/ParamType/Limits.inc @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +DefaultObjects_ParamType_Limits_Register() { + ParamsController_RegSimpleType(VIPM_PARAM_TYPE_LIMITS_NAME, "@DefaultObjects_ParamType_Limits_OnRead"); +} + +@DefaultObjects_ParamType_Limits_OnRead(const JSON:valueJson) { + if (json_is_array(valueJson) && json_array_get_count(valueJson) < 1) { + PCJson_LogForFile(valueJson, "WARNING", "Limits array is empty."); + return false; + } + + new Array:limits = VipM_Limits_ReadListFromJson(valueJson); + if (limits == Invalid_Array || ArraySize(limits) < 1) { + PCJson_LogForFile(valueJson, "WARNING", "All limits are invalid."); + ArrayDestroy(limits); + return false; + } + + return ParamsController_SetCell(limits); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/ParamType/ModuleType.inc b/amxmodx/scripting/VipM/DefaultObjects/ParamType/ModuleType.inc new file mode 100644 index 0000000..fd08e45 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/ParamType/ModuleType.inc @@ -0,0 +1,27 @@ +#include +#include +#include +#include + +#include "VipM/Core/Objects/Modules/Type" + +DefaultObjects_ParamType_ModuleType_Register() { + ParamsController_RegSimpleType(VIPM_PARAM_TYPE_MODULE_TYPE_NAME, "@DefaultObjects_ParamType_ModuleType_OnRead"); +} + +bool:@DefaultObjects_ParamType_ModuleType_OnRead(const JSON:valueJson) { + new typeName[VIPM_MODULES_TYPE_NAME_MAX_LEN]; + PCSingle_ShortString(valueJson, typeName, charsmax(typeName)); + trim(typeName); + + if (typeName[0] == EOS) { + return PCJson_LogForFile(valueJson, "WARNING", "Module type name not specified."); + } + + new T_ModuleType:type = ModuleType_Find(typeName); + if (type == Invalid_ModuleType) { + return PCJson_LogForFile(valueJson, "WARNING", "Module type '%s' not found.", typeName); + } + + return ParamsController_SetCell(type); +} diff --git a/amxmodx/scripting/VipM/DefaultObjects/Registrar.inc b/amxmodx/scripting/VipM/DefaultObjects/Registrar.inc new file mode 100644 index 0000000..1370160 --- /dev/null +++ b/amxmodx/scripting/VipM/DefaultObjects/Registrar.inc @@ -0,0 +1,93 @@ +#include + +#include "VipM/DefaultObjects/ParamType/Limit" +#include "VipM/DefaultObjects/ParamType/Limits" +#include "VipM/DefaultObjects/ParamType/LimitType" +#include "VipM/DefaultObjects/ParamType/ModuleType" +#include "VipM/DefaultObjects/ParamType/CounterType" + +public ParamsController_OnRegisterTypes() { + DefaultObjects_ParamType_Limit_Register(); + DefaultObjects_ParamType_Limits_Register(); + DefaultObjects_ParamType_LimitType_Register(); + DefaultObjects_ParamType_ModuleType_Register(); + DefaultObjects_ParamType_CounterType_Register(); +} + +#include + +#include "VipM/DefaultObjects/Limit/Always" +#include "VipM/DefaultObjects/Limit/GameTime" +#include "VipM/DefaultObjects/Limit/InFreezyTime" +#include "VipM/DefaultObjects/Limit/Ip" +#include "VipM/DefaultObjects/Limit/Logic" +#include "VipM/DefaultObjects/Limit/Name" +#include "VipM/DefaultObjects/Limit/Never" +#include "VipM/DefaultObjects/Limit/OncePer" +#include "VipM/DefaultObjects/Limit/Round" +#include "VipM/DefaultObjects/Limit/RoundTime" +#include "VipM/DefaultObjects/Limit/Steam" +#include "VipM/DefaultObjects/Limit/SteamId" +#include "VipM/DefaultObjects/Limit/Time" +#include "VipM/DefaultObjects/Limit/WeekDay" +#include "VipM/DefaultObjects/Limit/Counter" +#include "VipM/DefaultObjects/Limit/Alive" +#include "VipM/DefaultObjects/Limit/LifeTime" +#include "VipM/DefaultObjects/Limit/Bot" +#include "VipM/DefaultObjects/Limit/Flags" +#include "VipM/DefaultObjects/Limit/Frags" +#include "VipM/DefaultObjects/Limit/InBuyZone" +#include "VipM/DefaultObjects/Limit/HasPrimaryWeapon" +#include "VipM/DefaultObjects/Limit/Map" + +public VipM_Limits_OnInited() { + DefaultObjects_Limit_Always_Register(); + DefaultObjects_Limit_GameTime_Register(); + DefaultObjects_Limit_InFreezyTime_Register(); + DefaultObjects_Limit_Ip_Register(); + DefaultObjects_Limit_Logic_Register(); + DefaultObjects_Limit_Name_Register(); + DefaultObjects_Limit_Never_Register(); + DefaultObjects_Limit_OncePer_Register(); + DefaultObjects_Limit_Round_Register(); + DefaultObjects_Limit_RoundTime_Register(); + DefaultObjects_Limit_Steam_Register(); + DefaultObjects_Limit_SteamId_Register(); + DefaultObjects_Limit_Time_Register(); + DefaultObjects_Limit_WeekDay_Register(); + DefaultObjects_Limit_Counter_Register(); + DefaultObjects_Limit_Alive_Register(); + DefaultObjects_Limit_LifeTime_Register(); + DefaultObjects_Limit_Bot_Register(); + DefaultObjects_Limit_Flags_Register(); + DefaultObjects_Limit_Frags_Register(); + DefaultObjects_Limit_InBuyZone_Register(); + DefaultObjects_Limit_HasPrimaryWeapon_Register(); + DefaultObjects_Limit_Map_Register(); +} + +bool:DefaultObjects_NativeFilter(const name[], const bool:trap) { + new bool:ret = false; + + if (DefaultObjects_Limit_Steam_NativeFilter(name, trap)) { + ret = true; + } + + return ret; +} + +DefaultObjects_OnClientAuth(const playerIndex, const steamId[]) { + DefaultObjects_Limit_SteamId_OnClientAuth(playerIndex, steamId); + DefaultObjects_Limit_Ip_OnClientAuth(playerIndex); + DefaultObjects_Limit_Steam_OnClientAuth(playerIndex); + DefaultObjects_Limit_Bot_OnClientAuth(playerIndex); +} + +DefaultObjects_OnClientPutInServer(const playerIndex) { + DefaultObjects_Limit_Counter_OnClientPutInServer(playerIndex); + DefaultObjects_Limit_Alive_OnClientPutInServer(playerIndex); +} + +DefaultObjects_RegsiterNatives() { + DefaultObjects_Limit_Counter_RegsiterNatives(); +} \ No newline at end of file diff --git a/amxmodx/scripting/VipM/Forwards.inc b/amxmodx/scripting/VipM/Forwards.inc index 90b4d3c..b1cc400 100644 --- a/amxmodx/scripting/VipM/Forwards.inc +++ b/amxmodx/scripting/VipM/Forwards.inc @@ -6,79 +6,73 @@ /* Functions & Macroses: - Forwards_Init(const sPrefix[]); - []Forwards_GetFullName(const sName[]); - Forwards_Reg(const sName[], const iStopType, const ...?param_types); + Forwards_Init(); + Forwards_Reg(const name[], const stopType, const ...?param_types); Forwards_DefaultReturn(const iDefaultReturnValue); - Forwards_Call(const sName[]); - Forwards_CallP(const sName[], ...param_values); - Forwards_GetHandler(const sName[]); - Forwards_RegAndCallP(const sName[], const iStopType, [...param_types], [...param_values]); - Forwards_RegAndCall(const sName[], const iStopType); + Forwards_Call(const name[]); + Forwards_CallP(const name[], ...param_values); + Forwards_GetHandler(const name[]); + Forwards_RegAndCallP(const name[], const stopType, [...param_types], [...param_values]); + Forwards_RegAndCall(const name[], const stopType); */ -#include amxmodx +#include -stock const FORWARDS_NAME_TEMPLATE[] = "%s_On%s"; +stock static Trie:Forwards_gMap = Invalid_Trie; -stock Trie:Forwards_gMap = Invalid_Trie; -stock Forwards_gPrefix[32]; +stock __Forwards_Call_ret; +stock __Forwards_RegAndCall_handler; -stock Forwards_Init(const sPrefix[]) { +stock Forwards_Init() { Forwards_gMap = TrieCreate(); - copy(Forwards_gPrefix, charsmax(Forwards_gPrefix), sPrefix); } -// []Forwards_GetFullName(const sName[]); -#define Forwards_GetFullName(%1) \ - fmt(FORWARDS_NAME_TEMPLATE, Forwards_gPrefix, %1) +stock Forwards_AddHandler(const name[], const handler) { + TrieSetCell(Forwards_gMap, name, handler, false); + return handler; +} -// Forwards_Reg(const sName[], const iStopType, const ...?param_types); -#define Forwards_Reg(%1,%2) \ - TrieSetCell(Forwards_gMap, %1, CreateMultiForward(Forwards_GetFullName(%1), %2), false) +stock Forwards_GetHandler(const name[]) { + new handler; + TrieGetCell(Forwards_gMap, name, handler); + return handler; +} -stock __Forwards_Call_ret; +stock Forwards_DefaultReturn(const val) { + __Forwards_Call_ret = val; +} -// Forwards_DefaultReturn(const iDefaultReturnValue); -#define Forwards_DefaultReturn(%1) \ - __Forwards_Call_ret = %1 +stock Forwards_GetReturn(any:...) { + return __Forwards_Call_ret; +} + +// Forwards_Reg(const name[], const stopType, const ...?param_types); +#define Forwards_Reg(%1,%2) \ + Forwards_AddHandler(%1, CreateMultiForward(%1, %2)) +#define Forwards_RegP Forwards_Reg -// Forwards_CallP(const sName[], ...param_values); +// Forwards_CallP(const name[], ...param_values); #define Forwards_CallP(%1,%2) \ - (ExecuteForward(Forwards_GetHandler(%1), __Forwards_Call_ret, %2) ? __Forwards_Call_ret : __Forwards_Call_ret) + Forwards_GetReturn(ExecuteForward(Forwards_GetHandler(%1), __Forwards_Call_ret, %2)) -// Forwards_Call(const sName[]); +// Forwards_Call(const name[]); #define Forwards_Call(%1) \ - (ExecuteForward(Forwards_GetHandler(%1), __Forwards_Call_ret) ? __Forwards_Call_ret : __Forwards_Call_ret) - -stock Forwards_GetHandler(const sName[]) { - new iHandler; - TrieGetCell(Forwards_gMap, sName, iHandler); - return iHandler; -} - -stock __Forwards_RegAndCall_handler; + Forwards_GetReturn(ExecuteForward(Forwards_GetHandler(%1), __Forwards_Call_ret)) -// Forwards_RegAndCallP(const sName[], const iStopType, [...param_types], [...param_values]); +// Forwards_RegAndCallP(const name[], const stopType, [...param_types], [...param_values]); #define Forwards_RegAndCallP(%1,%2,[%3],[%4]) \ - (DestroyForward( \ + Forwards_GetReturn(DestroyForward( \ ExecuteForward( \ - __Forwards_RegAndCall_handler = CreateMultiForward( \ - Forwards_GetFullName(%1), \ - %2, %3 \ - ), \ + __Forwards_RegAndCall_handler = CreateMultiForward(%1, %2, %3), \ __Forwards_Call_ret, %4 \ ) ? __Forwards_RegAndCall_handler : __Forwards_RegAndCall_handler \ - ) ? __Forwards_Call_ret : __Forwards_Call_ret) + )) -// Forwards_RegAndCall(const sName[], const iStopType); +// Forwards_RegAndCall(const name[], const stopType); #define Forwards_RegAndCall(%1,%2) \ - (DestroyForward( \ + Forwards_GetReturn(DestroyForward( \ ExecuteForward( \ - __Forwards_RegAndCall_handler = CreateMultiForward( \ - Forwards_GetFullName(%1), \ - %2 \ - ), \ + __Forwards_RegAndCall_handler = CreateMultiForward(%1, %2), \ __Forwards_Call_ret \ ) ? __Forwards_RegAndCall_handler : __Forwards_RegAndCall_handler \ - ) ? __Forwards_Call_ret : __Forwards_Call_ret) + )) \ No newline at end of file diff --git a/amxmodx/scripting/VipM/ItemsController/Configs.inc b/amxmodx/scripting/VipM/ItemsController/Configs.inc deleted file mode 100644 index 2274ab0..0000000 --- a/amxmodx/scripting/VipM/ItemsController/Configs.inc +++ /dev/null @@ -1,86 +0,0 @@ -#include amxmodx -#include json - -new Trie:__JsonFileCache = Invalid_Trie; - -Cfg_JsonGetItem(&JSON:jItem){ - if (__JsonFileCache == Invalid_Trie) { - __JsonFileCache = TrieCreate(); - } - - // Use `Json_IsRef` instead deprecated `JSON_GET_FILE_OR_OBJECT` - jItem = JSON_GET_FILE_OR_OBJECT(jItem); - if (jItem == Invalid_JSON) { - return -1; - } - - new NewItemIndex = -1; - if ( - HasLastJsonObjectFile() - && TrieGetCell(__JsonFileCache, GetLastJsonObjectFile(), NewItemIndex) - && NewItemIndex >= 0 - ) { - json_free(jItem); - return NewItemIndex; - } - - SaveLastJsonObjectFile(__FILE_NAME); - - if ( - !json_is_object(jItem) - || !json_object_has_value(jItem, "Type", JSONString) - ) { - log_amx("[WARNING] Invalid item format."); - return -1; - } - - new TypeName[32]; - json_object_get_string(jItem, "Type", TypeName, charsmax(TypeName)); - json_object_remove(jItem, "Type"); - - if (!TYPE_EXISTS(TypeName)) { - log_amx("[WARNING] Item type `%s` not found.", TypeName); - return -1; - } - - new Item[S_Item]; - Item[Item_Type] = GET_TYPE_ID(TypeName); - - new Type[S_ItemType]; - GET_TYPE_BY_ID(Item[Item_Type], Type); - - Item[Item_Params] = TrieCreate(); - - if (json_object_has_value(jItem, "Name", JSONString)) { - new ItemName[32]; - json_object_get_string(jItem, "Name", ItemName, charsmax(ItemName)); - TrieSetString(Item[Item_Params], "Name", ItemName); - } - - Forwards_DefaultReturn(VIPM_CONTINUE); - if (Forwards_CallP("ReadItem", jItem, Item[Item_Params]) == VIPM_STOP) { - TrieDestroySafe(Item[Item_Params]); - return -1; - } - - new Ret = VIPM_CONTINUE; - EMIT_TYPE_EVENT(Type, ItemType_OnRead, Ret, jItem, Item[Item_Params]) - if (Ret == VIPM_STOP) { - TrieDestroySafe(Item[Item_Params]); - return -1; - } - - if (TrieSizeSafe(Item[Item_Params]) < 1) { - TrieDestroySafe(Item[Item_Params]); - } - - NewItemIndex = ADD_ITEM(Item); - - if (__FILE_NAME[0]) { - TrieSetCell(__JsonFileCache, __FILE_NAME, NewItemIndex); - } - - json_free(jItem); - - return NewItemIndex; -} diff --git a/amxmodx/scripting/VipM/ItemsController/Natives.inc b/amxmodx/scripting/VipM/ItemsController/Natives.inc deleted file mode 100644 index 46c225f..0000000 --- a/amxmodx/scripting/VipM/ItemsController/Natives.inc +++ /dev/null @@ -1,118 +0,0 @@ -#include amxmodx -#include json -#include "VipM/Utils" -#include "VipM/Natives" - -enum { - ERROR_TYPE_NOT_FOUND, - ERROR_ITEM_NOT_FOUND, -} - -#define NATIVE_CHECK_ITEM(%1) CompositeMacros( \ - if (!ITEM_EXISTS(%1)) { \ - log_error(ERROR_ITEM_NOT_FOUND, "[ERROR] Item #%d not found.", %1); \ - } \ -) - -#define NATIVE_CHECK_TYPE(%1) CompositeMacros( \ - if (!TYPE_EXISTS(%1)) { \ - log_error(ERROR_TYPE_NOT_FOUND, "[ERROR] Item type '%s' not found.", %1); \ - } \ -) - -public plugin_natives() { - Natives_Init("VipM_IC"); - - Natives_Reg("Init"); - Natives_Reg("RegisterType"); - Natives_Reg("RegisterTypeEvent"); - Natives_Reg("JsonGetItem"); - Natives_Reg("GiveItem"); -} - -@_Init() { - PluginInit(); -} - -// TODO: Вынести логику из нативов в соответствующий файл - -@_RegisterType(const PluginId) { - enum {Arg_Type = 1} - - new Type[S_ItemType]; - get_string(Arg_Type, Type[ItemType_Name], charsmax(Type[ItemType_Name])); - - Type[ItemType_PluginId] = PluginId; - Type[ItemType_Events] = Invalid_Trie; - - return ADD_TYPE(Type); -} - -@_RegisterTypeEvent(const PluginId) { - enum {Arg_Type = 1, Arg_Event, Arg_Func} - - new TypeName[32], Type[S_ItemType]; - get_string(Arg_Type, TypeName, charsmax(TypeName)); - - NATIVE_CHECK_TYPE(TypeName); - GET_TYPE(TypeName, Type); - - new E_ItemTypeEvent:Event = E_ItemTypeEvent:get_param(Arg_Event); - - new FuncName[64]; - get_string(Arg_Func, FuncName, charsmax(FuncName)); - - new FwdId = -1; - switch (Event) { - case ItemType_OnRead: // VipM_FwdReturn:(const JSON:jItem, Trie:Params) - FwdId = CreateOneForward(PluginId, FuncName, FP_CELL, FP_CELL); - - case ItemType_OnGive: // VipM_FwdReturn:(const UserId, const Trie:Params) - FwdId = CreateOneForward(PluginId, FuncName, FP_CELL, FP_CELL); - } - - if (FwdId < 0) { - return false; - } - - SET_TYPE_EVENT(Type, Event, FwdId); - SET_TYPE(Type); - - return FwdId >= 0; -} - -@_JsonGetItem() { - enum {Arg_jItem = 1} - - new JSON:jItem = JSON:get_param_byref(Arg_jItem); - new ItemId = Cfg_JsonGetItem(jItem); - set_param_byref(Arg_jItem, _:Invalid_JSON); - return ItemId; -} - -bool:@_GiveItem() { - enum {Arg_UserId = 1, Arg_ItemId} - - new UserId = get_param(Arg_UserId); - new ItemId = get_param(Arg_ItemId); - - NATIVE_CHECK_ITEM(ItemId); - new Item[S_Item]; - GET_ITEM(ItemId, Item); - - new Type[S_ItemType]; - GET_ITEM_TYPE(Item, Type); - - Forwards_DefaultReturn(VIPM_CONTINUE); - if (Forwards_CallP("GiveItem", UserId, Item[Item_Params]) == VIPM_STOP) { - return false; - } - - new Ret = VIPM_CONTINUE; - EMIT_TYPE_EVENT(Type, ItemType_OnGive, Ret, UserId, Item[Item_Params]) - if (Ret == VIPM_STOP) { - return false; - } - - return true; -} diff --git a/amxmodx/scripting/VipM/ItemsController/SrvCmds.inc b/amxmodx/scripting/VipM/ItemsController/SrvCmds.inc deleted file mode 100644 index 983e9ee..0000000 --- a/amxmodx/scripting/VipM/ItemsController/SrvCmds.inc +++ /dev/null @@ -1,7 +0,0 @@ -SrvCmds_Init(){ - register_srvcmd("vipm_ic_types", "@SrvCmd_Types"); -} - -@SrvCmd_Types(){ - PrintTypesData(Types); -} \ No newline at end of file diff --git a/amxmodx/scripting/VipM/ItemsController/Structs.inc b/amxmodx/scripting/VipM/ItemsController/Structs.inc deleted file mode 100644 index 3ebdf7b..0000000 --- a/amxmodx/scripting/VipM/ItemsController/Structs.inc +++ /dev/null @@ -1,12 +0,0 @@ - -enum _:S_ItemType{ - ItemType_Name[32], - ItemType_PluginId, - - Trie:ItemType_Events, -} - -enum _:S_Item{ - Item_Type, - Trie:Item_Params, -} diff --git a/amxmodx/scripting/VipM/ItemsController/Utils.inc b/amxmodx/scripting/VipM/ItemsController/Utils.inc deleted file mode 100644 index 577f015..0000000 --- a/amxmodx/scripting/VipM/ItemsController/Utils.inc +++ /dev/null @@ -1,64 +0,0 @@ -#include amxmodx - -#define GET_ITEM(%1,%2) \ - ArrayGetArray(Items, %1, %2) - -#define ADD_ITEM(%1) \ - ArrayPushArray(Items, %1) - -#define ITEM_EXISTS(%1) \ - (%1 >= 0 && %1 < ArraySizeSafe(Items)) - - -#define TYPE_EXISTS(%1) \ - ArrayMapHasKey(Types, %1) - -#define GET_TYPE(%1,%2) \ - ArrayMapGetArray(Types, %1, %2) - -#define GET_TYPE_ID(%1) \ - ArrayMapGetIndex(Types, %1) - -#define GET_TYPE_BY_ID(%1,%2) \ - ArrayMapGetiArray(Types, %1, %2) - -#define GET_ITEM_TYPE(%1,%2) \ - GET_TYPE_BY_ID(%1[Item_Type], %2) - -#define SET_TYPE(%1) \ - ArrayMapSetArray(Types, %1[ItemType_Name], %1) - -#define ADD_TYPE(%1) \ - ArrayMapPushArray(Types, %1, %1[ItemType_Name]) - - -// EMIT_TYPE_EVENT(Type, E_ItemTypeEvent:Event, Return, ...Params) -#define EMIT_TYPE_EVENT(%1,%2,%3) \ - if ( \ - %1[ItemType_Events] != Invalid_Trie \ - && TrieKeyExists(%1[ItemType_Events], IntToStr(%2)) \ - ) { \ - new ___EVENT_FWD; \ - TrieGetCell(%1[ItemType_Events], IntToStr(%2), ___EVENT_FWD); \ - ExecuteForward(___EVENT_FWD, %3); \ - } - -// SET_TYPE_EVENT(Type, E_ItemTypeEvent:Event, FwdId) -#define SET_TYPE_EVENT(%1,%2,%3) \ - if (%3 >= 0) { \ - if(%1[ItemType_Events] == Invalid_Trie) \ - %1[ItemType_Events] = TrieCreate(); \ - TrieSetCell(%1[ItemType_Events], IntToStr(%2), %3); \ - } \ - else TrieDeleteKey(%1[ItemType_Events], IntToStr(%2)) - - -PrintTypesData(const am[ArrayMap]){ - server_print("╔═════╤══════════════════════════════════╗"); - server_print("║ # │ Type name ║"); - server_print("╟─────┼──────────────────────────────────╢"); - ArrayMapForeachArray (am => Type[S_ItemType]) { - server_print("║ %03d │ %-32s ║", __i__, Type[ItemType_Name]); - } - server_print("╚═════╧══════════════════════════════════╝"); -} \ No newline at end of file diff --git a/amxmodx/scripting/VipM/ModulesLimiter/Configs.inc b/amxmodx/scripting/VipM/ModulesLimiter/Configs.inc deleted file mode 100644 index 8594636..0000000 --- a/amxmodx/scripting/VipM/ModulesLimiter/Configs.inc +++ /dev/null @@ -1,60 +0,0 @@ -#include -#include -#include -#include "VipM/Utils" -#include "VipM/ArrayTrieUtils" - -Trie:Configs_LoadModulesLimitsFromFile(const sFileName[], Trie:tModules = Invalid_Trie) { - TrieCreateIfNotCreated(tModules); - - new JSON:jFile = GET_FILE_JSON(sFileName); - if (jFile == Invalid_JSON) { - log_error(0, "Invalid JSON syntax. File `%s`.", GET_FILE_JSON_PATH(sFileName)); - return tModules; - } - - if (!json_is_array(jFile)) { - Json_LogForFile(jFile, "WARNING", "Root value must be an array."); - Json_DeepFree(jFile); - return tModules; - } - - json_array_foreach_value (jFile: i => jItem) { - if (!json_is_object(jItem)) { - Json_LogForFile(jItem, "WARNING", "Array item #%d isn`t object.", i); - json_free(jItem); - continue; - } - - new JSON:jLimits = json_object_get_value(jItem, "Limits"); - new Array:aLimits = VipM_Limits_ReadListFromJson(jLimits); - json_free(jLimits); - if (!ArraySizeSafe(aLimits)) { - Json_LogForFile(jItem, "WARNING", "Field `Limits` must have 1 or more items."); - json_free(jItem); - continue; - } - - - new Array:aModuleNames = json_object_get_strings_list(jItem, "Modules", VIPM_MODULE_MAX_NAME); - if (!ArraySizeSafe(aModuleNames)) { - Json_LogForFile(jItem, "WARNING", "Field `Modules` must have 1 or more items."); - continue; - } - - ArrayForeachString (aModuleNames: j => sModuleName[VIPM_MODULE_MAX_NAME]) { - if (TrieKeyExists(tModules, sModuleName)) { - Json_LogForFile(jItem, "WARNING", "Duplicate limits for module `%s`.", sModuleName); - continue; - } - - TrieSetCell(tModules, sModuleName, aLimits); - } - - json_free(jItem); - ArrayDestroy(aModuleNames); - } - - Json_DeepFree(jFile); - return tModules; -} diff --git a/amxmodx/scripting/VipM/Natives.inc b/amxmodx/scripting/VipM/Natives.inc deleted file mode 100644 index bba3f9f..0000000 --- a/amxmodx/scripting/VipM/Natives.inc +++ /dev/null @@ -1,25 +0,0 @@ -#if defined _UTILS_src_Natives_included - #endinput -#endif -#define _UTILS_src_Natives_included - -/* -Functions & Macroses: - - Natives_Init(const sPrefix[]); - Natives_Reg(const sName[]); - Natives_AutoReg(const sPrefix[], const aNativeNames[][]); -*/ - -#include amxmodx - -stock const __NATIVE_NAME_TPL[] = "%s_%s"; -stock const __NATIVE_FUNC_TPL[] = "@_%s"; -stock Natives_gPrefix[32]; - -#define Natives_Init(%1) \ - copy(Natives_gPrefix, charsmax(Natives_gPrefix), %1) - -// Natives_Reg(const sName[]); -#define Natives_Reg(%1) \ - register_native(fmt(__NATIVE_NAME_TPL, Natives_gPrefix, %1), fmt(__NATIVE_FUNC_TPL, %1)) diff --git a/amxmodx/scripting/VipM/Utils.inc b/amxmodx/scripting/VipM/Utils.inc index d323396..ffc7a21 100644 --- a/amxmodx/scripting/VipM/Utils.inc +++ b/amxmodx/scripting/VipM/Utils.inc @@ -6,40 +6,29 @@ // Надо наверное как-то их обьединить) #include "VipM/ArrayTrieUtils" -#include amxmodx -#include json -#include reapi -#include VipModular +#include +#include +#include +#include -stock const __INT_TEMPLATE_STR[] = "%d"; stock const __SLANG_TEMPLATE_STR[] = "%l"; stock const __CLANG_TEMPLATE_STR[] = "%L"; -stock const __JSON_FILE_TEMPLATE_STR[] = "%s.json"; -stock const __USER_NAME_TEMPLATE_STR[] = "%n"; +stock const __LANG_MSG_LAYOUT_KEY[] = "MSG_LAYOUT"; +stock const bool:__CompositeMacros_AlwaysFalse = false; #define CompositeMacros(%1) \ - do { %1 } while(is_linux_server() == 0xDEADBEEF) + do { %1 } while(__CompositeMacros_AlwaysFalse) -#define GetRound() \ - get_member_game(m_iTotalRoundsPlayed)+1 +stock IntToStr(const int) { + new str[11]; + num_to_str(int, str, charsmax(str)); -#define IntToStr(%1) \ - fmt(__INT_TEMPLATE_STR, %1) - -#define IsUserIdValid(%1) \ - (%1 >= 1 && %1 <= 32) - -#define IsUserValid(%1) \ - ( \ - IsUserIdValid(%1) \ - && is_user_connected(%1) \ - ) + return str; +} -#define IsUserValidA(%1) \ - ( \ - IsUserIdValid(%1) \ - && is_user_alive(%1) \ - ) +stock IsPlayerIndexValid(const playerIndex) { + return playerIndex >= 1 && playerIndex <= 32; +} #define Lang(%1) \ fmt(__SLANG_TEMPLATE_STR, %1) @@ -48,188 +37,21 @@ stock const __USER_NAME_TEMPLATE_STR[] = "%n"; fmt(__CLANG_TEMPLATE_STR, %1) #define ChatPrint(%1,%2) \ - client_print_color(%1, print_team_default, __CLANG_TEMPLATE_STR, IsUserIdValid(%1) ? %1 : -1, "MSG_LAYOUT", fmt(%2)) + client_print_color(%1, print_team_default, __CLANG_TEMPLATE_STR, IsPlayerIndexValid(%1) ? %1 : -1, __LANG_MSG_LAYOUT_KEY, fmt(%2)) #define ChatPrintL(%1,%2) \ ChatPrint(%1, __CLANG_TEMPLATE_STR, %1, %2) -#define GET_FILE(%1) \ - inl_VipM_GetCfgPath(%1) - -#define GET_FILE_JSON_PATH(%1) \ - GET_FILE(fmt(__JSON_FILE_TEMPLATE_STR, %1)) - -#define GET_FILE_JSON(%1) \ - Json_ParseFromFileEx(GET_FILE_JSON_PATH(%1)) - -#define JSON_FILE_EXTSTS(%1) \ - file_exists(GET_FILE_JSON_PATH(%1)) - - -stock const __JSON_WRAPPER_FIELD_FILE[] = "_file"; -stock const __JSON_WRAPPER_FIELD_VALUE[] = "_value"; - -#define Json_IsWrapper(%1) \ - ( \ - %1 != Invalid_JSON \ - && json_object_has_value(%1, __JSON_WRAPPER_FIELD_FILE, JSONString) \ - && json_object_has_value(%1, __JSON_WRAPPER_FIELD_VALUE) \ - && json_get_parent(%1) == Invalid_JSON \ - ) - -stock JSON:Json_ParseFromFileEx(const Path[]) { - new JSON:jFile = json_parse(Path, true, true); - - if (jFile == Invalid_JSON) { - log_amx("[ERROR] Can't read JSON from file '%s'.", Path); - return Invalid_JSON; - } - - new JSON:jWrapper = json_init_object(); - json_object_set_string(jWrapper, __JSON_WRAPPER_FIELD_FILE, Path); - json_object_set_value(jWrapper, __JSON_WRAPPER_FIELD_VALUE, jFile); - return jFile; -} - -stock JSON:Json_DeepFree(&JSON:jValue) { - new JSON:jParent; - while (jValue != Invalid_JSON) { - jParent = json_get_parent(jValue); - json_free(jValue); - jValue = jParent; - } - return jValue; -} - -stock JSON:Json_GetRoot(const JSON:jValue) { - if (jValue == Invalid_JSON) { - return Invalid_JSON; - } - - new JSON:jParent; - new JSON:jIterator = json_get_parent(jValue); - while (jIterator != Invalid_JSON) { - jParent = json_get_parent(jIterator); - if (jParent == Invalid_JSON) { - break; - } - json_free(jIterator); - jIterator = jParent; - } - return jIterator; -} - -stock Json_GetFilePath(const JSON:jValue, Out[], const OutLen) { - new JSON:jRoot = Json_GetRoot(jValue); - if (!Json_IsWrapper(jRoot)) { - return formatex(Out, OutLen, "unknown_file"); - } - - return json_object_get_string(jRoot, __JSON_WRAPPER_FIELD_FILE, Out, OutLen); -} - -new stock const __Json_LogForFile_templateFile[] = "[JSON][%s] File: %s"; -new stock const __Json_LogForFile_templateMessage[] = "[JSON][%s] Message: %s"; -stock Json_LogForFile(const JSON:jValue, const sPrefix[], const sMessage[], any:...) { - static sFilePath[PLATFORM_MAX_PATH]; - Json_GetFilePath(jValue, sFilePath, charsmax(sFilePath)); - log_amx(__Json_LogForFile_templateFile, sPrefix, sFilePath); - - static sFormattedMessage[1024]; - if (numargs() >= 4) { - vformat(sFormattedMessage, charsmax(sFormattedMessage), sMessage, 4); - log_amx(__Json_LogForFile_templateMessage, sPrefix, sFormattedMessage); - } else { - log_amx(__Json_LogForFile_templateMessage, sPrefix, sMessage); - } -} - -stock __CMD_NULL_ARG = 0; -stock CMD_INIT_PARAMS() { - __CMD_NULL_ARG = 0; - static Cmd[32]; - read_argv(__CMD_NULL_ARG, Cmd, charsmax(Cmd)); - if (equali(Cmd, "say", 3)) { - __CMD_NULL_ARG++; - } -} - -#define CMD_ARG(%1) \ - (__CMD_NULL_ARG + %1) - -#define CMD_ARG_NUM() \ - (read_argc() - __CMD_NULL_ARG - 1) - -stock static const JSON_FILE_VALUE_PREFIX[] = "File:"; -stock __JSON_LAST_FILE_OBJECT[PLATFORM_MAX_PATH]; -stock JSON:JSON_GET_FILE_OR_OBJECT(JSON:Value) { - __JSON_LAST_FILE_OBJECT[0] = 0; - - if (Value == Invalid_JSON) { - return Value; - } - - if (!json_is_string(Value)) { - return Value; - } - - new FileName[PLATFORM_MAX_PATH]; - json_get_string(Value, FileName, charsmax(FileName)); - if (!equali(JSON_FILE_VALUE_PREFIX, FileName, charsmax(JSON_FILE_VALUE_PREFIX))) { - return Value; - } - - json_free(Value); - - formatex(__JSON_LAST_FILE_OBJECT, charsmax(__JSON_LAST_FILE_OBJECT), FileName[charsmax(JSON_FILE_VALUE_PREFIX)]); - - Value = GET_FILE_JSON(__JSON_LAST_FILE_OBJECT); - if (Value == Invalid_JSON) { - log_amx("[WARNING] JSON syntax error in file `%s`.", __JSON_LAST_FILE_OBJECT); - } - - return Value; -} - -#define GetLastJsonObjectFile() \ - __JSON_LAST_FILE_OBJECT - -#define HasLastJsonObjectFile() \ - bool:(GetLastJsonObjectFile()[0]) - -#define SaveLastJsonObjectFile(%1) \ - new %1[PLATFORM_MAX_PATH];copy(%1, charsmax(%1), GetLastJsonObjectFile()) - -stock bool:Json_IsRef(const JSON:jValue, FileName[] = NULL_STRING, const Len = 0) { - if (!json_is_string(jValue)) { - return false; - } - - new Str[128]; - json_get_string(jValue, Str, charsmax(Str)); - if (!equali(JSON_FILE_VALUE_PREFIX, Str, charsmax(JSON_FILE_VALUE_PREFIX))) { - return false; - } - - if (Len > 0) { - copy(FileName, Len, Str[charsmax(JSON_FILE_VALUE_PREFIX)]); - } - - return true; -} - - -#define json_array_foreach(%1:%2) \ - if(json_is_array(%1)) \ - for(new %2 = 0; %2 < json_array_get_count(%1); %2++) +#define ChatPrintLIf(%3,%1,%2) \ + ((%3) && ChatPrint(%1, __CLANG_TEMPLATE_STR, %1, %2)) #define json_array_foreach_vars(%1:%2,[%3]) \ - if(json_is_array(%1)) \ - for(new %3, %2 = 0; %2 < json_array_get_count(%1); %2++) + if (json_is_array(%1)) \ + for (new %3, %2 = 0; %2 < json_array_get_count(%1); %2++) #define json_array_foreach_value(%1:%2=>%3) \ json_array_foreach_vars(%1: %2, [JSON:%3]) \ - if((%3 = json_array_get_value(%1, %2)) != Invalid_JSON) + if ((%3 = json_array_get_value(%1, %2)) != Invalid_JSON) #define json_get_count(%1) \ (json_is_array(%1) ? json_array_get_count(%1) : 1) @@ -265,10 +87,10 @@ stock Array:json_object_get_strings_list( } #define BitSet(%1,%2) \ - %1 |= (1 << (%2 - 1)) + %1 |= (1 << %2) #define BitReset(%1,%2) \ - %1 &= ~(1 << (%2 - 1)) + %1 &= ~(1 << %2) // by @the_hunter1 :)) #define BitSetIf(%1,%2,%3) ( \ @@ -280,119 +102,12 @@ stock Array:json_object_get_strings_list( #define BitIs(%1,%2) \ (bool:(%1 & (1 << %2))) -stock bool:HasUserFlagsStr(const UserId, const sFlags[], const bool:bStrict = false) { - return HasUserFlags(UserId, read_flags(sFlags), bStrict); -} - -stock bool:HasUserFlags(const UserId, const bitFlags, const bool:bStrict = false) { - return HasBits(get_user_flags(UserId), bitFlags, bStrict); -} - -stock bool:HasBits(const bits, const bitSearch, const bool:bStrict = false) { - new bitRes = bits & bitSearch; - return bStrict - ? bitRes == bitSearch - : bitRes != 0 -} - -// []GetUserName(const UserId) -#define GetUserName(%1) \ - fmt(__USER_NAME_TEMPLATE_STR,%1) - -// bool:IsEqualUserName(const UserId, const sName[]) -#define IsEqualUserName(%1,%2) \ - equal(GetUserName(%1), %2) - -stock GetWeekDayIdByName(const sWeekDayName[]) { - if (equali("Вс", sWeekDayName) || equali("Воскресенье", sWeekDayName) || equali("Sun", sWeekDayName) || equali("Sunday", sWeekDayName)) { - return 0; - } else if (equali("Пн", sWeekDayName) || equali("Понедельник", sWeekDayName) || equali("Mon", sWeekDayName) || equali("Monday", sWeekDayName)) { - return 1; - } else if (equali("Вт", sWeekDayName) || equali("Вторник", sWeekDayName) || equali("Tue", sWeekDayName) || equali("Tuesday", sWeekDayName)) { - return 2; - } else if (equali("Ср", sWeekDayName) || equali("Среда", sWeekDayName) || equali("Wed", sWeekDayName) || equali("Wednesday", sWeekDayName)) { - return 3; - } else if (equali("Чт", sWeekDayName) || equali("Четверг", sWeekDayName) || equali("Thu", sWeekDayName) || equali("Thursday", sWeekDayName)) { - return 4; - } else if (equali("Пт", sWeekDayName) || equali("Пятница", sWeekDayName) || equali("Fri", sWeekDayName) || equali("Friday", sWeekDayName)) { - return 5; - } else if (equali("Сб", sWeekDayName) || equali("Суббота", sWeekDayName) || equali("Sat", sWeekDayName) || equali("Saturday", sWeekDayName)) { - return 6; - } else { - return -1; - } -} - -stock CreateConstCvar(const sCvarName[], const sCvarValue[], const iFlags = FCVAR_SERVER) { - set_pcvar_string(create_cvar(sCvarName, sCvarValue, iFlags), sCvarValue); -} - #define CallOnce() CompositeMacros( \ static bool:__CallOnce_bCalled; \ if (__CallOnce_bCalled) return; \ __CallOnce_bCalled = true; \ ) -#define CallOnceR(%1) CompositeMacros( \ - static bool:__CallOnce_bCalled; \ - if (__CallOnce_bCalled) return %1; \ - __CallOnce_bCalled = true; \ -) - -// https://github.com/Nord1cWarr1or/Universal-AFK-Manager/blob/6272afbb8c27f8b7ad770e3036b5960042001e6b/scripting/UAFKManager.sma#L298-L321 -stock GetAmxxVersionNum() { - static iRes; - if (iRes) { - return iRes; - } - - new sAmxxVer[16]; - get_amxx_verstring(sAmxxVer, charsmax(sAmxxVer)); - - if (strfind(sAmxxVer, "1.10.0") != -1) { - iRes = 1100; - } else if (strfind(sAmxxVer, "1.9.0") != -1) { - iRes = 190; - } else if (strfind(sAmxxVer, "1.8.3") != -1) { - iRes = 183; - } else if (strfind(sAmxxVer, "1.8.2") != -1) { - iRes = 182; - } else { - iRes = 1; - } - - return iRes; -} - -stock RegisterPlugin( - const sName[], - const sVersion[], - const sAuthor[], - const sUrl[] = "", - const sDescription[] = "" -) { - #if AMXX_VERSION_NUM >= 1100 - if (GetAmxxVersionNum() >= 1100) { - register_plugin(sName, sVersion, sAuthor, sUrl, sDescription); - return; - } - #endif - register_plugin(sName, sVersion, sAuthor); -} - -#define RegisterPluginByVars() CompositeMacros( \ - if (GetAmxxVersionNum() < 1100) { \ - register_plugin(PluginName, PluginVersion, PluginAuthor); \ - } \ -) - -// Надо чтобы переменные были определены раньше, что может быть неудобно:) -// stock RegisterPluginByVars() { -// if (GetAmxxVersionNum() < 1100) { -// register_plugin(PluginName, PluginVersion, PluginAuthor); -// } -// } - stock ItemHasClip(const ItemId) { new WeaponIdType:WeaponId = get_member(ItemId, m_iId); switch (WeaponId) { @@ -427,25 +142,8 @@ stock InstantReloadActiveWeapon(const UserId) { } } -stock bool:StrEqualEx(const sA[], const sB[], const iCount = 0, const bool:bIgnoreCase = false) { - return bIgnoreCase - ? equali(sA, sB, iCount) - : equal(sA, sB, iCount); -} - stock bool:IsUserInBuyZone(const UserId) { new Signal[UnifiedSignals]; get_member(UserId, m_signals, Signal); return ((SignalState:Signal[US_State] & SIGNAL_BUY) == SIGNAL_BUY); } - -stock ParseColonTime(const sTime[], const sColon[] = ":") { - new sHours[3], sMinutes[3]; - split(sTime, sHours, charsmax(sHours), sMinutes, charsmax(sMinutes), sColon); - - return ((clamp(str_to_num(sHours), 0, 23) * 60) + clamp(str_to_num(sMinutes), 0, 59)) * 60; -} - -stock GetTime() { - return get_systime() % (24 * 60 * 60); -} diff --git a/amxmodx/scripting/VipM/WeaponMenu/Configs.inc b/amxmodx/scripting/VipM/WeaponMenu/Configs.inc deleted file mode 100644 index 1136dc9..0000000 --- a/amxmodx/scripting/VipM/WeaponMenu/Configs.inc +++ /dev/null @@ -1,189 +0,0 @@ -#include amxmodx -#include json -#include VipModular - -Array:Cfg_ReadMenus(&JSON:jMenus){ - new Array:aMenus = Invalid_Array; - new Menu[S_WeaponMenu]; - - // TODO: Заменить на Json_IsRef - jMenus = JSON_GET_FILE_OR_OBJECT(jMenus); - - switch (json_get_type(jMenus)) { - case JSONArray: { - new cMenus = json_array_get_count(jMenus); - aMenus = ArrayCreate(S_WeaponMenu, cMenus); - - for (new i = 0; i < cMenus; i++) { - new JSON:jMenu = json_array_get_value(jMenus, i); - if (Cfg_ReadMenu(jMenu, Menu)) { - ArrayPushArray(aMenus, Menu); - } - } - json_free(jMenus); - } - - case JSONObject, JSONString: { - if (Cfg_ReadMenu(jMenus, Menu)) { - aMenus = ArrayCreate(S_WeaponMenu, 1); - ArrayPushArray(aMenus, Menu); - } - } - default: - json_free(jMenus); - } - return aMenus; -} - -bool:Cfg_ReadMenu(&JSON:jMenu, Menu[S_WeaponMenu]){ - static Trie:_FileCache; - if (_FileCache == Invalid_Trie) { - _FileCache = TrieCreate(); - } - - jMenu = JSON_GET_FILE_OR_OBJECT(jMenu); - if (jMenu == Invalid_JSON) { - return false; - } - - json_object_get_string(jMenu, "Name", Menu[WeaponMenu_Name], charsmax(Menu[WeaponMenu_Name])); - - Menu[WeaponMenu_Fake] = false; - if (json_object_has_value(jMenu, "Fake", JSONBoolean)) { - Menu[WeaponMenu_Fake] = json_object_get_bool(jMenu, "Fake"); - } - - // Возможно странное решение, но пока норм) - // Один хер потом переделывать на нормальную систему меню)) - if (Menu[WeaponMenu_Fake]) { - json_object_get_string(jMenu, "FakeMessage", Menu[WeaponMenu_FakeMessage], charsmax(Menu[WeaponMenu_FakeMessage])); - replace_all(Menu[WeaponMenu_FakeMessage], charsmax(Menu[WeaponMenu_FakeMessage]), "^^1", "^1"); - replace_all(Menu[WeaponMenu_FakeMessage], charsmax(Menu[WeaponMenu_FakeMessage]), "^^3", "^3"); - replace_all(Menu[WeaponMenu_FakeMessage], charsmax(Menu[WeaponMenu_FakeMessage]), "^^4", "^4"); - - json_free(jMenu); - return true; - } - - json_object_get_string(jMenu, "Title", Menu[WeaponMenu_Title], charsmax(Menu[WeaponMenu_Title])); - - Menu[WeaponMenu_Count] = -1; - if (json_object_has_value(jMenu, "Count", JSONNumber)) { - Menu[WeaponMenu_Count] = json_object_get_number(jMenu, "Count"); - } - - Menu[WeaponMenu_BackOnExit] = false; - if (json_object_has_value(jMenu, "BackOnExit", JSONBoolean)) { - Menu[WeaponMenu_BackOnExit] = json_object_get_bool(jMenu, "BackOnExit"); - } - - Menu[WeaponMenu_PerPage] = -1; - if (json_object_has_value(jMenu, "PerPage", JSONNumber)) { - Menu[WeaponMenu_PerPage] = json_object_get_number(jMenu, "PerPage"); - } - - Menu[WeaponMenu_ShowPage] = true; - if (json_object_has_value(jMenu, "ShowPage", JSONBoolean)) { - Menu[WeaponMenu_ShowPage] = json_object_get_bool(jMenu, "ShowPage"); - } - - Menu[WeaponMenu_Limits] = VipM_Limits_ReadListFromJson(json_object_get_value(jMenu, "Limits")); - - new JSON:jMenuItems = JsonObjectGetItemsValue(jMenu); - Menu[WeaponMenu_Items] = Cfg_ReadMenuItems(jMenuItems); - - json_free(jMenu); - - if (Menu[WeaponMenu_Items] == Invalid_Array) { - log_amx("[WARNING] Menu items are not specified."); - return false; - } - - return true; -} - -Array:Cfg_ReadMenuItems(&JSON:jMenuItems){ - new Array:aMenuItems = Invalid_Array; - new MenuItem[S_MenuItem]; - - jMenuItems = JSON_GET_FILE_OR_OBJECT(jMenuItems); - - switch (json_get_type(jMenuItems)) { - case JSONArray: { - new cMenuItems = json_array_get_count(jMenuItems); - aMenuItems = ArrayCreate(S_MenuItem, cMenuItems); - - for (new i = 0; i < cMenuItems; i++) { - new JSON:jMenuItem = json_array_get_value(jMenuItems, i); - if(Cfg_ReadMenuItem(jMenuItem, MenuItem)) - ArrayPushArray(aMenuItems, MenuItem); - } - json_free(jMenuItems); - } - - case JSONObject: { - if (Cfg_ReadMenuItem(jMenuItems, MenuItem)) { - aMenuItems = ArrayCreate(S_MenuItem, 1); - ArrayPushArray(aMenuItems, MenuItem); - } - } - default: - json_free(jMenuItems); - } - return aMenuItems; -} - -bool:Cfg_ReadMenuItem(&JSON:jMenuItem, MenuItem[S_MenuItem]){ - if (!json_is_object(jMenuItem)) { - log_amx("[WARNING] Invalid weapon menu item format."); - return false; - } - - if (!json_object_get_string(jMenuItem, "Title", MenuItem[MenuItem_Title], charsmax(MenuItem[MenuItem_Title]))) { - MenuItem[MenuItem_Type] = MenuItemType_Blank; - return true; - } - - new JSON:jItems = JsonObjectGetItemsValue(jMenuItem); - if (jItems == Invalid_JSON) { - MenuItem[MenuItem_Type] = MenuItemType_Text; - return true; - } - - MenuItem[MenuItem_Type] = MenuItemType_Default; - - MenuItem[MenuItem_ShowLimits] = VipM_Limits_ReadListFromJson(json_object_get_value(jMenuItem, "ShowLimits")); - MenuItem[MenuItem_ActiveLimits] = VipM_Limits_ReadListFromJson(json_object_get_value(jMenuItem, "ActiveLimits")); - MenuItem[MenuItem_Limits] = VipM_Limits_ReadListFromJson(json_object_get_value(jMenuItem, "Limits")); - - MenuItem[MenuItem_FakeInactive] = false; - if (json_object_has_value(jMenuItem, "FakeInactive", JSONBoolean)) { - MenuItem[MenuItem_FakeInactive] = json_object_get_bool(jMenuItem, "FakeInactive"); - } - - MenuItem[MenuItem_UseCounter] = true; - if (json_object_has_value(jMenuItem, "UseCounter", JSONBoolean)) { - MenuItem[MenuItem_UseCounter] = json_object_get_bool(jMenuItem, "UseCounter"); - } - - json_free(jMenuItem); - - MenuItem[MenuItem_Items] = VipM_IC_JsonGetItems(jItems); - if (MenuItem[MenuItem_Items] == Invalid_Array) { - log_amx("[WARNING] Invalid weapon menu item format. Empty items list."); - return false; - } - - return true; -} - -// TODO: Надо бы удалить и смотреть только на Items -JSON:JsonObjectGetItemsValue(const JSON:jObj){ - if (json_object_has_value(jObj, "Items")) { - return json_object_get_value(jObj, "Items"); - } else if (json_object_has_value(jObj, "Item")) { - return json_object_get_value(jObj, "Item"); - } else { - return Invalid_JSON; - } -} \ No newline at end of file diff --git a/amxmodx/scripting/VipM/WeaponMenu/Menus.inc b/amxmodx/scripting/VipM/WeaponMenu/Menus.inc index 60817c9..b7a4c29 100644 --- a/amxmodx/scripting/VipM/WeaponMenu/Menus.inc +++ b/amxmodx/scripting/VipM/WeaponMenu/Menus.inc @@ -1,133 +1,139 @@ -#include amxmodx -#include VipModular +#include +#include +#include + #include "VipM/Utils" #include "VipM/ArrayTrieUtils" -#include "VipM/DebugMode" -Menu_GetUserMenusCount(const UserId) { - return ArraySizeSafe(VipM_Params_GetArr(VipM_Modules_GetParams(MODULE_NAME, UserId), "Menus")); +#include "VipM/WeaponMenu/Objects/WeaponMenu" + +Menu_GetUserMenusCount(const playerIndex) { + return ArraySizeSafe(VipM_Params_GetArr(VipM_Modules_GetParams(MODULE_NAME, playerIndex), "Menus")); } -Menu_MainMenu(const UserId, const MainMenuTitle[], const Array:aMenus) { - new iMenu = menu_create(MainMenuTitle, "@MenuHandler_Command"); +Menu_MainMenu(const playerIndex, const MainMenuTitle[], const Array:menus) { + new menuHandler = menu_create(MainMenuTitle, "@MenuHandler_Command"); - ArrayForeachArray(aMenus => Menu[S_WeaponMenu]) { - static Cmd[128]; - CommandAliases_GetMainCmd(CMD_WEAPON_MENU, Cmd, charsmax(Cmd)); - menu_additem(iMenu, Menu[WeaponMenu_Name], fmt("%s %d", Cmd, __i__)); + ArrayForeachArray2 (menus: i => menuObject[S_WeaponMenu]) { + menu_additem(menuHandler, menuObject[WeaponMenu_Name], fmt("%s %d", VIPM_M_WEAPONMENU_CMD_MENU, i)); } - menu_setprop(iMenu, MPROP_BACKNAME, Lang("VIPM_M_WM_MENU_BACK")); - menu_setprop(iMenu, MPROP_NEXTNAME, Lang("VIPM_M_WM_MENU_NEXT")); - menu_setprop(iMenu, MPROP_EXITNAME, Lang("VIPM_M_WM_MENU_EXIT")); + menu_setprop(menuHandler, MPROP_BACKNAME, Lang("VIPM_M_WM_MENU_BACK")); + menu_setprop(menuHandler, MPROP_NEXTNAME, Lang("VIPM_M_WM_MENU_NEXT")); + menu_setprop(menuHandler, MPROP_EXITNAME, Lang("VIPM_M_WM_MENU_EXIT")); - menu_display(UserId, iMenu); + menu_display(playerIndex, menuHandler); } -Menu_WeaponsMenu(const UserId, const MenuId, const Menu[S_WeaponMenu]) { - new iItemsLeft = GetUserLeftItems(UserId, MenuId, Menu); - new iMenusCount = Menu_GetUserMenusCount(UserId); +Menu_WeaponsMenu(const playerIndex, const menuIndex, const menuObject[S_WeaponMenu]) { + new iItemsLeft = GetUserLeftItems(playerIndex, menuObject); + new iMenusCount = Menu_GetUserMenusCount(playerIndex); static sItemsLeft[128] = ""; if (iItemsLeft >= 0) { - formatex(sItemsLeft, charsmax(sItemsLeft), "\w%L^n", UserId, "VIPM_M_WM_MENU_MAIN_ITEMS_LEFT", iItemsLeft); + formatex(sItemsLeft, charsmax(sItemsLeft), "\w%L^n", playerIndex, "VIPM_M_WM_MENU_MAIN_ITEMS_LEFT", iItemsLeft); } else { sItemsLeft[0] = 0; } static sExpireStatus[128]; - if (gUserExpireStatus[UserId][0]) { - formatex(sExpireStatus, charsmax(sExpireStatus), "\w%L^n", UserId, "VIPM_M_WM_MENU_EXPIRE_STATUS", gUserExpireStatus[UserId]); + if (gUserExpireStatus[playerIndex][0]) { + formatex(sExpireStatus, charsmax(sExpireStatus), "\w%L^n", playerIndex, "VIPM_M_WM_MENU_EXPIRE_STATUS", gUserExpireStatus[playerIndex]); } else { sExpireStatus[0] = 0; } static sMenu[512]; - formatex(sMenu, charsmax(sMenu), "%s^n%s%s", Menu[WeaponMenu_Title], sExpireStatus, sItemsLeft); + formatex(sMenu, charsmax(sMenu), "%s^n%s%s", menuObject[WeaponMenu_Title], sExpireStatus, sItemsLeft); - new iMenu = menu_create( - sMenu, - Menu[WeaponMenu_BackOnExit] && iMenusCount > 1 - ? "@MenuHandler_Weapons" - : "@MenuHandler_Command" - ); + new menuHandler = menu_create(sMenu, "@MenuHandler_Command"); - if (Menu[WeaponMenu_BackOnExit] && iMenusCount > 1) { - menu_setprop(iMenu, MPROP_EXITNAME, uLang(UserId, "VIPM_M_WM_MENU_WEAPONS_BACK_TO_MAIN_TEXT")); + if (menuObject[WeaponMenu_BackOnExit] && iMenusCount > 1) { + menu_setprop(menuHandler, MPROP_EXITNAME, uLang(playerIndex, "VIPM_M_WM_MENU_WEAPONS_BACK_TO_MAIN_TEXT")); } - if (Menu[WeaponMenu_PerPage] >= 0) { - menu_setprop(iMenu, MPROP_PERPAGE, Menu[WeaponMenu_PerPage]); + if (menuObject[WeaponMenu_PerPage] >= 0) { + menu_setprop(menuHandler, MPROP_PERPAGE, menuObject[WeaponMenu_PerPage]); } - menu_setprop(iMenu, MPROP_SHOWPAGE, Menu[WeaponMenu_ShowPage]); + menu_setprop(menuHandler, MPROP_SHOWPAGE, menuObject[WeaponMenu_ShowPage]); - menu_setprop(iMenu, MPROP_BACKNAME, Lang("VIPM_M_WM_MENU_BACK")); - menu_setprop(iMenu, MPROP_NEXTNAME, Lang("VIPM_M_WM_MENU_NEXT")); - menu_setprop(iMenu, MPROP_EXITNAME, Lang("VIPM_M_WM_MENU_EXIT")); + menu_setprop(menuHandler, MPROP_BACKNAME, Lang("VIPM_M_WM_MENU_BACK")); + menu_setprop(menuHandler, MPROP_NEXTNAME, Lang("VIPM_M_WM_MENU_NEXT")); + menu_setprop(menuHandler, MPROP_EXITNAME, Lang("VIPM_M_WM_MENU_EXIT")); static iInactiveItemHandler; if (!iInactiveItemHandler) { iInactiveItemHandler = menu_makecallback("@MenuItemHandler_Inactive"); } - new iItemIndex = 0; - ArrayForeachArray(Menu[WeaponMenu_Items] => MenuItem[S_MenuItem]) { - if (!VipM_Limits_ExecuteList(MenuItem[MenuItem_ShowLimits], UserId)) { + new itemIndex = 0; + ArrayForeachArray2 (menuObject[WeaponMenu_Items]: i => itemObject[S_MenuItem]) { + if ( + itemObject[MenuItem_ShowLimits] != Invalid_Array + && !VipM_Limits_ExecuteList(itemObject[MenuItem_ShowLimits], playerIndex, Limit_Exec_AND) + ) { continue; } + + new bool:isItemActive = ( + itemObject[MenuItem_ActiveLimits] == Invalid_Array + || VipM_Limits_ExecuteList(itemObject[MenuItem_ActiveLimits], playerIndex, Limit_Exec_AND) + ); + + static title[64]; + if (isItemActive) { + copy(title, charsmax(title), itemObject[MenuItem_Title]); + } else { + copy(title, charsmax(title), itemObject[MenuItem_InactiveTitle]); + } - switch (MenuItem[MenuItem_Type]) { + switch (itemObject[MenuItem_Type]) { case MenuItemType_Default: { - static Cmd[128]; - CommandAliases_GetMainCmd(CMD_WEAPON_MENU, Cmd, charsmax(Cmd)); + static cmd[128]; + formatex(cmd, charsmax(cmd), "%s %d %d", VIPM_M_WEAPONMENU_CMD_MENU, menuIndex, i); + if (menuObject[WeaponMenu_BackOnExit]) { + add(cmd, charsmax(cmd), fmt(";%s %d", VIPM_M_WEAPONMENU_CMD_MENU, menuIndex)); + } + + menu_additem(menuHandler, title, cmd); - new bool:bIsActive = VipM_Limits_ExecuteList(MenuItem[MenuItem_ActiveLimits], UserId); - menu_additem(iMenu, fmt("%s%s", bIsActive ? "" : "\d", MenuItem[MenuItem_Title]), fmt("%s %d %d", Cmd, MenuId, __i__)); - if (!bIsActive && !MenuItem[MenuItem_FakeInactive]) { - menu_item_setcall(iMenu, iItemIndex, iInactiveItemHandler); + if (!isItemActive && !itemObject[MenuItem_FakeInactive]) { + menu_item_setcall(menuHandler, itemIndex, iInactiveItemHandler); } } case MenuItemType_Text: { - menu_addtext2(iMenu, MenuItem[MenuItem_Title]); + menu_addtext2(menuHandler, itemObject[MenuItem_Title]); } case MenuItemType_Blank: { - menu_addblank2(iMenu); + menu_addblank2(menuHandler); } } - iItemIndex++; + itemIndex++; } - menu_display(UserId, iMenu); + menu_display(playerIndex, menuHandler); } @MenuItemHandler_Inactive() { return ITEM_DISABLED; } -@MenuHandler_Weapons(const UserId, const MenuId, const ItemId) { - @MenuHandler_Command(UserId, MenuId, ItemId); - - if (ItemId == MENU_EXIT) { - CommandAliases_ClientCmd(UserId, CMD_WEAPON_MENU); - } -} - -@MenuHandler_Command(const UserId, const MenuId, const ItemId){ - AbortAutoCloseMenu(UserId); +@MenuHandler_Command(const playerIndex, const menuIndex, const ItemId){ + AbortAutoCloseMenu(playerIndex); if (ItemId == MENU_EXIT) { - menu_destroy(MenuId); + menu_destroy(menuIndex); return; } static sCmd[128]; - menu_item_getinfo(MenuId, ItemId, _, sCmd, charsmax(sCmd)); + menu_item_getinfo(menuIndex, ItemId, _, sCmd, charsmax(sCmd)); if (sCmd[0]) { - client_cmd(UserId, sCmd); + client_cmd(playerIndex, sCmd); } - menu_destroy(MenuId); + menu_destroy(menuIndex); } \ No newline at end of file diff --git a/amxmodx/scripting/VipM/WeaponMenu/Natives.inc b/amxmodx/scripting/VipM/WeaponMenu/Natives.inc index 50a333c..8974cdf 100644 --- a/amxmodx/scripting/VipM/WeaponMenu/Natives.inc +++ b/amxmodx/scripting/VipM/WeaponMenu/Natives.inc @@ -1,10 +1,7 @@ #include -#include "VipM/Natives" public plugin_natives() { - Natives_Init("VipM_WeaponMenu"); - - Natives_Reg("SetExpireStatus"); + register_native("VipM_WeaponMenu_SetExpireStatus", "@_SetExpireStatus"); } @_SetExpireStatus() { diff --git a/amxmodx/scripting/VipM/WeaponMenu/Objects/MenuItem.inc b/amxmodx/scripting/VipM/WeaponMenu/Objects/MenuItem.inc new file mode 100644 index 0000000..c60b90d --- /dev/null +++ b/amxmodx/scripting/VipM/WeaponMenu/Objects/MenuItem.inc @@ -0,0 +1,105 @@ +#if defined __vipm_weaponmenu_objects_menuitem_included + #endinput +#endif +#define __vipm_weaponmenu_objects_menuitem_included + +#include +#include +#include + +enum MenuItemType { + MenuItemType_Default = 0, + MenuItemType_Text, + MenuItemType_Blank, +} + +enum _:S_MenuItem { + MenuItemType:MenuItem_Type, + + MenuItem_Title[64], + MenuItem_InactiveTitle[64], + Array:MenuItem_Items, // T_IC_Item[] + bool:MenuItem_UseCounter, + bool:MenuItem_FakeInactive, + + Array:MenuItem_ShowLimits, // T_LimitUnit[] + Array:MenuItem_ActiveLimits, // T_LimitUnit[] + Array:MenuItem_Limits, // T_LimitUnit[] +} + +bool:MenuItem_Read(const JSON:itemJson, item[S_MenuItem]) { + if (!json_is_object(itemJson)) { + PCJson_LogForFile(itemJson, "WARNING", "Invalid menu item format."); + return false; + } + + if (!PCSingle_ObjShortString(itemJson, "Title", item[MenuItem_Title], charsmax(item[MenuItem_Title]))) { + item[MenuItem_Type] = MenuItemType_Blank; + return true; + } + + item[MenuItem_ShowLimits] = PCSingle_ObjVipmLimits(itemJson, "ShowLimits"); + item[MenuItem_ActiveLimits] = PCSingle_ObjVipmLimits(itemJson, "ActiveLimits"); + + if (!PCSingle_ObjShortString(itemJson, "InactiveTitle", item[MenuItem_InactiveTitle], charsmax(item[MenuItem_InactiveTitle]))) { + formatex(item[MenuItem_InactiveTitle], charsmax(item[MenuItem_InactiveTitle]), "\d%s", item[MenuItem_Title]); + } + + item[MenuItem_Items] = PCSingle_ObjIcItems(itemJson, "Items"); + if (item[MenuItem_Items] == Invalid_Array) { + item[MenuItem_Type] = MenuItemType_Text; + return true; + } + + item[MenuItem_Type] = MenuItemType_Default; + item[MenuItem_Limits] = PCSingle_ObjVipmLimits(itemJson, "Limits"); + item[MenuItem_FakeInactive] = PCSingle_ObjBool(itemJson, "FakeInactive", false); + item[MenuItem_UseCounter] = PCSingle_ObjBool(itemJson, "UseCounter", true); + + return true; +} + +Array:MenuItem_ReadList(const JSON:itemsJson, &Array:items = Invalid_Array) { + ArrayCreateIfNotCreated(items, S_MenuItem); + + new JSON:linkedJson; + PCJson_HandleLinkedValue(itemsJson, linkedJson); + + switch (json_get_type(linkedJson)) { + case JSONObject: { + new MenuItem[S_MenuItem]; + if (MenuItem_Read(linkedJson, MenuItem)) { + ArrayPushArray(items, MenuItem); + } + } + case JSONArray: { + json_array_foreach_value (linkedJson: i => itemJson) { + MenuItem_ReadList(itemJson, items); + json_free(itemJson); + } + } + default: { + PCJson_LogForFile(linkedJson, "WARNING", "Invalid menu items format."); + } + } + + PCJson_FreeLinked(linkedJson, itemsJson); + return items; +} + +Array:Json_Object_GetMenuItemsList( + const JSON:jObj, + const sKey[], + &Array:aMenuItems = Invalid_Array, + const bool:bDotNot = false +) { + if (!json_object_has_value(jObj, sKey, .dot_not = bDotNot)) { + return Invalid_Array; + } + + new JSON:jMenuItems = json_object_get_value(jObj, sKey, bDotNot); + aMenuItems = MenuItem_ReadList(jMenuItems, aMenuItems); + json_free(jMenuItems); + + return aMenuItems; +} diff --git a/amxmodx/scripting/VipM/WeaponMenu/Objects/WeaponMenu.inc b/amxmodx/scripting/VipM/WeaponMenu/Objects/WeaponMenu.inc new file mode 100644 index 0000000..ab35c8e --- /dev/null +++ b/amxmodx/scripting/VipM/WeaponMenu/Objects/WeaponMenu.inc @@ -0,0 +1,109 @@ +#if defined __vipm_weaponmenu_objects_weaponmenu_included + #endinput +#endif +#define __vipm_weaponmenu_objects_weaponmenu_included + +#include +#include +#include +#include +#include + +#include "VipM/WeaponMenu/Objects/MenuItem" + +enum _:S_WeaponMenu { + WeaponMenu_Name[64], + WeaponMenu_Title[128], + + Array:WeaponMenu_Items, // S_MenuItem[] + WeaponMenu_Count, + VipM_L_Counter_Type:WeaponMenu_CounterType, + WeaponMenu_CounterKey[VIPM_L_COUNTER_KEY_MAX_LEN], + + Array:WeaponMenu_Limits, // T_LimitUnit[] + + bool:WeaponMenu_BackOnExit, + WeaponMenu_PerPage, + bool:WeaponMenu_ShowPage, + + WeaponMenu_FakeMessage[256], +} + +static WeaponMenuCounterKeysCount = 0; + +bool:WeaponMenu_Read(const JSON:menuJson, menuObject[S_WeaponMenu]) { + PCSingle_ObjString(menuJson, "Name", menuObject[WeaponMenu_Name], charsmax(menuObject[WeaponMenu_Name])); + + if (PCSingle_ObjChatMessage( + menuJson, "FakeMessage", + menuObject[WeaponMenu_FakeMessage], charsmax(menuObject[WeaponMenu_FakeMessage]) + )) { + return true; + } + + menuObject[WeaponMenu_Items] = Json_Object_GetMenuItemsList(menuJson, "Items"); + if (menuObject[WeaponMenu_Items] == Invalid_Array) { + PCJson_LogForFile(menuJson, "WARNING", "menuObject items list are empty."); + return false; + } + + PCSingle_ObjString(menuJson, "Title", menuObject[WeaponMenu_Title], charsmax(menuObject[WeaponMenu_Title]), menuObject[WeaponMenu_Name]); + + menuObject[WeaponMenu_BackOnExit] = PCSingle_ObjBool(menuJson, "BackOnExit", false); + menuObject[WeaponMenu_PerPage] = PCSingle_ObjInt(menuJson, "PerPage", -1); + menuObject[WeaponMenu_ShowPage] = PCSingle_ObjBool(menuJson, "ShowPage", true); + menuObject[WeaponMenu_Limits] = PCSingle_ObjVipmLimits(menuJson, "Limits"); + + menuObject[WeaponMenu_Count] = PCSingle_ObjInt(menuJson, "Count", -1); + menuObject[WeaponMenu_CounterType] = PCSingle_ObjVipmCounterType(menuJson, "CounterType", VipM_L_Counter_PerLife); + if (!PCSingle_ObjShortString(menuJson, "CounterKey", menuObject[WeaponMenu_CounterKey], charsmax(menuObject[WeaponMenu_CounterKey]))) { + formatex(menuObject[WeaponMenu_CounterKey], charsmax(menuObject[WeaponMenu_CounterKey]), "%s-%d", VIPM_M_WEAPONMENU_MENU_COUNTER_KEY_PREFIX, ++WeaponMenuCounterKeysCount); + } + + return true; +} + +Array:WeaponMenu_ReadList(const JSON:jWeaponMenus, &Array:aWeaponMenus = Invalid_Array) { + ArrayCreateIfNotCreated(aWeaponMenus, S_WeaponMenu); + + new JSON:linkedJson; + PCJson_HandleLinkedValue(jWeaponMenus, linkedJson); + + switch (json_get_type(linkedJson)) { + case JSONObject: { + new WeaponMenu[S_WeaponMenu]; + if (WeaponMenu_Read(linkedJson, WeaponMenu)) { + ArrayPushArray(aWeaponMenus, WeaponMenu); + } + } + case JSONArray: { + json_array_foreach_value (linkedJson: i => jWeaponMenu) { + aWeaponMenus = WeaponMenu_ReadList(jWeaponMenu, aWeaponMenus); + json_free(jWeaponMenu); + } + } + default: { + PCJson_LogForFile(linkedJson, "WARNING", "Invalid weapon menus format."); + } + } + + PCJson_FreeLinked(linkedJson, jWeaponMenus); + return aWeaponMenus; +} + +Array:Json_Object_GetWeaponMenusList( + const JSON:jObj, + const sKey[], + &Array:aWeaponMenus = Invalid_Array, + const bool:bDotNot = false +) { + if (!json_object_has_value(jObj, sKey, .dot_not = bDotNot)) { + return Invalid_Array; + } + + new JSON:jWeaponMenus = json_object_get_value(jObj, sKey, bDotNot); + aWeaponMenus = WeaponMenu_ReadList(jWeaponMenus, aWeaponMenus); + json_free(jWeaponMenus); + + return aWeaponMenus; +} diff --git a/amxmodx/scripting/VipM/WeaponMenu/Structs.inc b/amxmodx/scripting/VipM/WeaponMenu/Structs.inc deleted file mode 100644 index d219376..0000000 --- a/amxmodx/scripting/VipM/WeaponMenu/Structs.inc +++ /dev/null @@ -1,31 +0,0 @@ - -enum _:S_WeaponMenu{ - WeaponMenu_Name[64], - WeaponMenu_Title[128], - Array:WeaponMenu_Items, - Array:WeaponMenu_Limits, - WeaponMenu_Count, - bool:WeaponMenu_BackOnExit, - bool:WeaponMenu_Fake, - WeaponMenu_FakeMessage[256], - WeaponMenu_PerPage, - bool:WeaponMenu_ShowPage, -} - -enum MenuItemType{ - MenuItemType_Default = 0, - MenuItemType_Text, - MenuItemType_Blank, -} - -enum _:S_MenuItem{ - MenuItem_Title[64], - Array:MenuItem_Items, - bool:MenuItem_UseCounter, - MenuItemType:MenuItem_Type, - bool:MenuItem_FakeInactive, - - Array:MenuItem_ShowLimits, - Array:MenuItem_ActiveLimits, - Array:MenuItem_Limits, -} diff --git a/amxmodx/scripting/VipModular.sma b/amxmodx/scripting/VipModular.sma index c759aa4..a369051 100644 --- a/amxmodx/scripting/VipModular.sma +++ b/amxmodx/scripting/VipModular.sma @@ -1,79 +1,85 @@ #include #include +#include #include "VipM/DebugMode" #include "VipM/ArrayTrieUtils" #include "VipM/Utils" #include "VipM/Forwards" -#pragma semicolon 1 -#pragma compress 1 - public stock const PluginName[] = "Vip Modular"; public stock const PluginVersion[] = _VIPM_VERSION; public stock const PluginAuthor[] = "ArKaNeMaN"; public stock const PluginURL[] = _VIPM_PLUGIN_URL; public stock const PluginDescription[] = "Modular vip system"; -new Array:Vips; // S_CfgUnit -new Trie:gUserVip[MAX_PLAYERS + 1] = {Invalid_Trie, ...}; // ModuleName => Trie:Params - -#include "VipM/Core/Utils" - -#include "VipM/Core/Structs" -#include "VipM/Core/Modules/Main" -#include "VipM/Core/Limits/Main" -#include "VipM/Core/Configs/Main" -#include "VipM/Core/Vips" - +#include "VipM/Core/Objects/Modules/Type" +#include "VipM/Core/Objects/Limits/Type" +#include "VipM/Core/VipsManager" #include "VipM/Core/SrvCmds" -#include "VipM/Core/Natives" +#include "VipM/DefaultObjects/Registrar" public plugin_precache() { - RegisterPluginByVars(); + register_plugin(PluginName, PluginVersion, PluginAuthor); register_library(VIPM_LIBRARY); - CreateConstCvar("vipm_version", VIPM_VERSION); + PCCvar_Const("vipm_version", PluginVersion); + ParamsController_Init(); - RegisterForwards(); - SrvCmds_Init(); - Limits_Init(); - Modules_Init(); - Forwards_RegAndCall("InitModules", ET_IGNORE); - - Vips = Cfg_LoadVipsConfigs(); + Forwards_Init(); - server_print("[%s v%s] Loaded %d config units.", PluginName, VIPM_VERSION, ArraySizeSafe(Vips)); - Forwards_RegAndCall("Loaded", ET_IGNORE); + VipsManager_Init(); + ModuleType_Init(); + SrvCmds_Init(); + Forwards_RegAndCall("VipM_OnInitModules", ET_IGNORE); // deprecated + + VipsManager_SetRootDir(PCPath_iMakePath(VIPM_CONFIGS_FOLDER_NAME)); + VipsManager_LoadFromFile(PCPath_iMakePath(fmt("%s/%s", VIPM_CONFIGS_FOLDER_NAME, VIPM_VIPS_CONFIG_FILE_PATH))); + VipsManager_LoadFromFolder(PCPath_iMakePath(fmt("%s/%s", VIPM_CONFIGS_FOLDER_NAME, VIPM_VIPS_CONFIG_DIR_PATH))); - Modules_EnableAllUsed(); + ModuleType_ActivateUsed(); + Forwards_RegAndCall("VipM_OnLoaded", ET_IGNORE); + server_print("[%s v%s] Loaded %d config units.", PluginName, PluginVersion, VipsManager_VipsCount()); Dbg_PrintServer("Vip Modular run in debug mode!"); } -RegisterForwards() { - Forwards_Init("VipM"); - Forwards_Reg("UserUpdated", ET_IGNORE, FP_CELL); - Forwards_Reg("ReadUnit", ET_IGNORE, FP_CELL, FP_CELL); - Forwards_Reg("ActivateModule", ET_STOP, FP_STRING); - Forwards_Reg("ReadModuleUnit", ET_IGNORE, FP_CELL, FP_CELL); - Forwards_Reg("ReadLimitUnit", ET_IGNORE, FP_CELL, FP_CELL); +public client_authorized(playerIndex, const steamId[]) { + DefaultObjects_OnClientAuth(playerIndex, steamId); } -public client_disconnected(UserId) { - Vips_Reset(UserId); +public client_putinserver(playerIndex) { + DefaultObjects_OnClientPutInServer(playerIndex); + RequestFrame("@CallUserUpdate", playerIndex); } -public client_putinserver(UserId) { - if (is_user_bot(UserId)) { - return; +@CallUserUpdate(const playerIndex) { + if (is_user_connected(playerIndex)) { + VipsManager_UserReload(playerIndex); } +} + +public client_disconnected(playerIndex) { + VipsManager_UserReset(playerIndex); +} - RequestFrame("@CallUserUpdate", UserId); +#include "VipM/Core/API/Main" +#include "VipM/Core/API/Limits" +#include "VipM/Core/API/Modules" +public plugin_natives() { + API_Main_Init(); + API_Limits_Init(); + API_Modules_Init(); + + DefaultObjects_RegsiterNatives(); + + set_native_filter("@NativeFilter"); } -@CallUserUpdate(UserId) { - if (!is_user_connected(UserId)) { - return; +@NativeFilter(const name[], const index, const trap) { + new ret = PLUGIN_CONTINUE; + + if (DefaultObjects_NativeFilter(name, !!trap)) { + ret = PLUGIN_HANDLED; } - Vips_UserUpdate(UserId); + return ret; } diff --git a/amxmodx/scripting/include/ItemsController.inc b/amxmodx/scripting/include/ItemsController.inc new file mode 100644 index 0000000..828f496 --- /dev/null +++ b/amxmodx/scripting/include/ItemsController.inc @@ -0,0 +1,416 @@ +#if defined __items_controller_included + #endinput +#endif +#define __items_controller_included + +#include +#include +#include + +#define IC_VERSION "1.0.0-rc4f1" +stock const IC_LIBRARY[] = "items-controller"; +stock const IC_VERSION_CVAR[] = "ic_version"; + +stock const IC_PARAM_TYPE_ITEM_NAME[] = "IC-Item"; +stock const IC_PARAM_TYPE_ITEMS_NAME[] = "IC-Items"; + +#define IC_ITEM_TYPE_NAME_MAX_LEN 64 +#define IC_EVENT_LISTENER_FUNCTION_NAME_MAX_LEN 64 + +#define IC_RET_READ_SUCCESS 0 +#define IC_RET_READ_FAIL 1 + +#define IC_RET_GIVE_SUCCESS 0 +#define IC_RET_GIVE_FAIL 1 + +enum T_IC_ItemType { Invalid_IC_ItemType = -1 } +enum T_IC_Item {Invalid_IC_Item = -1} + +// Deprecated names! +#define VipM_IC_T_Item T_IC_Item +#define VipM_IC_Invalid_Item Invalid_IC_Item +#define VIPM_IC_ITEM_TYPE_NAME_MAX_LEN IC_ITEM_TYPE_NAME_MAX_LEN + +enum E_ItemTypeEvent{ + /* + * Описание: Вызывается, когда читаются параметры предмета. + * Возв. тип: IC_RET_READ_* + * Параметры: (const JSON:instanceJson, Trie:params): + * instanceJson - JSON-обьект с параметрами предмета. + * params - key-value хранилище для записи прочитанных параметров. + * + * Примечание: Вызывается в момент чтения оружия нативом IC_Item_ReadFromJson. Скорее всего в plugin_precache. + * Примечание: Если возвращено IC_RET_READ_FAIL, предмет будет пропущен. + */ + ItemType_OnRead, + + /* + * Описание: Вызывается, когда предмет выдаётся игроку (При вызове натива IC_Item_Give). + * Возв. тип: IC_RET_GIVE_* + * Параметры: (const playerIndex, const Trie:params): + * playerIndex - Индекс игрока, которому выдаётся предмет. + * params - key-value хранилище параметров. + * + * Примечание: Если возвращено IC_RET_GIVE_FAIL, предмет не будет считаться выданным (Натив IC_Item_Give вернёт false). + */ + ItemType_OnGive, + + /* + * Описание: Вызывается, при освобождении хендлера предмета. + * Возв. тип: void + * Параметры: (const T_IC_Item:item, const Trie:p): + * item - Хендлер предмета. + * p - key-value хранилище параметров. + * + * // TODO + */ + ItemType_OnFree, +} + +/** + * Вызывается после инициализации компонента типов предметов. + * После вызова этого форварда можно регистрировать типы предметов. + * + * @note Вызывается не позже plugin_precache. + * + * @noreturn + */ +forward IC_ItemType_OnInited(); + +/** + * Вызывается после инициализации компонента предметов. + * После вызова этого форварда можно создавать экземпляры предметов (в т.ч. читать их из JSON). + * + * @note Вызывается не позже plugin_precache. + * + * @noreturn + */ +forward IC_Item_OnInited(); + +/** + * Принудительно инициализирует контроллер предметов. + * + * @noreturn + */ +native IC_Init(); + +/** + * Регистрирует новый тип предмета. + * + * @param name Название типа. + * + * @return Хендлер зарегистрированного типа. + */ +native T_IC_ItemType:IC_ItemType_Register(const name[]); + +/** + * Регистрирует новый тип предмета. + * + * @param type Хендлер типа. + * @param event Событие, для которого устанавливается обработчик. + * @param functionName Название функции-обработчика. + * + * @noreturn + */ +native IC_ItemType_SetEventListener(const T_IC_ItemType:type, const E_ItemTypeEvent:event, const functionName[]); + +/** + * Добавляет параметры для типа предмета. + * + * @param type Хендлер типа. + * @param any:... Перечисление параметров. + * + * @note Формат перечисления параметров: + * IC_ItemType_AddParams(..., const paramName[], const paramType[], const bool:paramRequired, ...); + * + * Где: + * - paramName - Название параметра; + * - paramType - Название типа параметра; + * - paramRequired - Обязателен ли параметр. + * + * Пример: + * IC_ItemType_AddParams(type, + * "Param1", "String", true, + * "Param2", "Integer", false + * ); + * + * @noreturn + */ +native IC_ItemType_AddParams(const T_IC_ItemType:type, any:...); + +/** + * Регистрирует новый тип предмета с обработчиками событий. + * + * @param name Название типа. + * @param onRead Название функции-обработчика для события ItemType_OnRead. + * @param onGive Название функции-обработчика для события ItemType_OnGive. + * + * @return Хендлер зарегистрированного типа. + */ +stock T_IC_ItemType:IC_ItemType_SimpleRegister(const name[], const onRead[] = "", const onGive[] = "") { + new T_IC_ItemType:type = IC_ItemType_Register(name); + + if (onRead[0] != EOS) { + IC_ItemType_SetEventListener(type, ItemType_OnRead, onRead); + } + + if (onGive[0] != EOS) { + IC_ItemType_SetEventListener(type, ItemType_OnGive, onGive); + } + + return type; +} + +/** + * Читает предмет из JSON-значения. + * + * @param isntanceJson JSON-значение, содержажее предмет или ссылку на него. + * + * @return Хендлер прочитанного экземпляра предмета. Invalid_IC_Item в случае ошибки. + */ +native T_IC_Item:IC_Item_ReadFromJson(const JSON:isntanceJson); + +/** + * Читает массив предметов из JSON-значения. + * + * @param isntancesJson JSON-значение, содержажее массив предметов, один предмет или ссылку. + * @param array Хендлер динамического массива, в который нужно дописать прочитанные предметы. + * + * @return Хендлер динамического массива с прочитанными предметами. Если был передан параметр array, то вернётся то же значение. + */ +native Array:IC_Item_ReadArrayFromJson(const JSON:isntancesJson, &Array:array = Invalid_Array); + +#pragma deprecated Use PCSingle_ObjIcItems() instead. +stock Array:Json_Object_IC_GetItems(const JSON:jObj, const sKey[], const bool:bDotNot = false) { + return PCSingle_ObjIcItems(jObj, sKey, .dotNot = bDotNot); +} + +/** + * Выдача предмета игроку. + * + * @param playerIndex Индекс игрока. + * @param item Хендлер экземпляра предмета. + * + * @return true, если предмет успешно выдан, иначе false. + */ +native bool:IC_Item_Give(const playerIndex, const T_IC_Item:item); + +/** + * Удаление экземпляра предмета из памяти (освобождение хендлера). + * + * @note На данный момент может вызывать утечку памяти при некоторых обстоятельствах. + * Если в параметрах предмета находятся хендлеры каких-либо хранилищ (Array, Trie и т.п.), они не будут очищены. + * В будущем планируется решить это через ParamsController, но там пока нет нужного функционала. + * + * @param item Хендлер экземпляра предмета. Значение будет изменено на Invalid_IC_Item. + * + * @return Всегда Invalid_IC_Item. + */ +native T_IC_Item:IC_Item_Free(&T_IC_Item:item); + +/** + * Выдача игроку всех предметов из массива. + * + * @param playerIndex Индекс игрока. + * @param array Хендлер динамического массива с хендлерами экземпляров предметов. + * + * @return true, если хотя бы один предмет успешно выдан, иначе false. + */ +stock bool:IC_Item_GiveArray(const playerIndex, const Array:array) { + if (array == Invalid_Array) { + return false; + } + + new bool:success = false; + for (new i = 0; i < ArraySize(array); i++) { + if (IC_Item_Give(playerIndex, ArrayGetCell(array, i))) { + success = true; + } + } + + return success; +} + +/** + * Вызывается в момент инициалзиации типов предметов. + * + * @note Вызывается не позже plugin_precache. + * + * @noreturn + * + * @deprecated Use IC_ItemType_OnInited() instead. + */ +#pragma deprecated Use IC_ItemType_OnInited() instead. +forward VipM_IC_OnInitTypes(); + +/** + * Инициализирует контроллер предметов. + * + * @noreturn + * + * @deprecated Use IC_Init() instead. + */ +#pragma deprecated Use IC_Init() instead. +native VipM_IC_Init(); + +/** + * Регистрирует новый тип предмета. + * + * @param Type Название типа. + * + * @return Индекс зарегистрированного типа + * + * @deprecated Use IC_ItemType_Register() instead. + */ +#pragma deprecated Use IC_ItemType_Register() instead. +native VipM_IC_RegisterType(const Type[]); + +/** + * Регистрирует обработчик события для указанного типа предмета. + * + * @param Type Название типа. + * @param Event Событие. + * @param Func Название функции-обработчика. + * + * @return Вернёт true, если обработчик успешно зарегистрирован. + * + * @deprecated Use IC_ItemType_SetEventListener() instead. + */ +#pragma deprecated Use IC_ItemType_SetEventListener() instead. +native VipM_IC_RegisterTypeEvent(const Type[], const E_ItemTypeEvent:Event, const Func[]); + +/** + * Загрузка предмета из JSON-обьекта. + * + * @param jItem JSON-объект, содержащий информацию о предмете. + * + * @note После загрузки предмета, JSON-объект уничтожается. + * @note Структура объекта: + * { + * "Item": "НазваниеТипа", + * "НазваниеПараметра1": "ЗначениеПараметра1", + * "НазваниеПараметра2": "ЗначениеПараметра2", + * ... + * } + * + * @return Индекс загруженного предмета. Invalid_IC_Item, если что-то пошло не так. + * + * @deprecated Use IC_Item_ReadFromJson() instead. + */ +#pragma deprecated Use IC_Item_ReadFromJson() instead. +native VipM_IC_T_Item:VipM_IC_JsonGetItem(&JSON:jItem); + +/** + * Выдача предмета игроку. + * + * @param UserId Индекс игрока. + * @param ItemId Индекс предмета, возвращённый нативом VipM_IC_JsonGetItem. + * + * @return true, если предмет успешно выдан, иначе false. + * + * @deprecated Use IC_Item_Give() instead. + */ +#pragma deprecated Use IC_Item_Give() instead. +native bool:VipM_IC_GiveItem(const UserId, const VipM_IC_T_Item:ItemId); + +#pragma deprecated Use IC_Item_ReadArrayFromJson() instead. +stock Array:VipM_IC_JsonGetItems(JSON:jItems) { + // TODO: Не удалять хендлер (то же относится и к нативу) + + new Array:aItems = Invalid_Array; + if (jItems == Invalid_JSON) { + return aItems; + } + + switch (json_get_type(jItems)) { + case JSONArray: { + new cItems = json_array_get_count(jItems); + if (cItems < 1) { + return Invalid_Array; + } + + aItems = ArrayCreate(1, cItems); + for (new i = 0; i < cItems; i++) { + new JSON:jItem = json_array_get_value(jItems, i); + new VipM_IC_T_Item:ItemId = VipM_IC_JsonGetItem(jItem); + if (ItemId != Invalid_IC_Item) { + ArrayPushCell(aItems, ItemId); + } + } + json_free(jItems); + } + + case JSONObject, JSONString: { + new VipM_IC_T_Item:ItemId = VipM_IC_JsonGetItem(jItems); + if (ItemId == Invalid_IC_Item) { + return Invalid_Array; + } + + aItems = ArrayCreate(1, 1); + ArrayPushCell(aItems, ItemId); + } + } + return aItems; +} + +#pragma deprecated Use IC_Item_GiveArray() instead. +stock bool:VipM_IC_GiveItems(const UserId, const Array:aItems) { + if (aItems == Invalid_Array) { + return false; + } + + new bool:bRes = false; + for (new i = 0; i < ArraySize(aItems); i++) { + if (VipM_IC_GiveItem(UserId, VipM_IC_T_Item:ArrayGetCell(aItems, i))) { + bRes = true; + } + } + + return bRes; +} + +stock bool:VipM_Params_GiveItems(const UserId, const Trie:tParams, const sParam[]) { + return IC_Item_GiveArray(UserId, VipM_Params_GetArr(tParams, sParam)); +} + +stock bool:VipM_Params_GiveItem(const UserId, const Trie:tParams, const sParam[]) { + return IC_Item_Give(UserId, PCGet_Cell(tParams, sParam)); +} + +#pragma deprecated Use Json_Object_IC_GetItems() instead. +stock Array:Json_Object_GetItemsIC(const JSON:jObj, const sKey[], const bool:bDotNot = false) { + if (!json_object_has_value(jObj, sKey, .dot_not = bDotNot)) { + return Invalid_Array; + } + + new JSON:jItems = json_object_get_value(jObj, sKey, bDotNot); + new Array:aItems = VipM_IC_JsonGetItems(jItems); + json_free(jItems); + + return aItems; +} + +stock T_IC_Item:PCSingle_ObjIcItem(const JSON:objectJson, const key[], const T_IC_Item:def = Invalid_IC_Item, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, IC_PARAM_TYPE_ITEM_NAME, def, dotNot, orFail); +} + +stock Array:PCSingle_ObjIcItems(const JSON:objectJson, const key[], const Array:def = Invalid_Array, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, IC_PARAM_TYPE_ITEMS_NAME, def, dotNot, orFail); +} + +stock T_IC_Item:PCGet_IcItem(const Trie:p, const key[], const T_IC_Item:def = Invalid_IC_Item) { + return PCGet_Cell(p, key, def); +} + +stock Array:PCGet_IcItems(const Trie:p, const key[], const Array:def = Invalid_Array) { + return PCGet_Cell(p, key, def); +} + +stock bool:PCGet_IcItemGive(const Trie:p, const key[], const playerIndex) { + new T_IC_Item:item = PCGet_IcItem(p, key); + return item != Invalid_IC_Item && IC_Item_Give(0playerIndex, item); +} + +stock bool:PCGet_IcItemsGive(const Trie:p, const key[], const playerIndex) { + return IC_Item_GiveArray(playerIndex, PCGet_IcItems(p, key)); +} diff --git a/amxmodx/scripting/include/VipM/ItemsController.inc b/amxmodx/scripting/include/VipM/ItemsController.inc index 0eaa7d5..2f9cf38 100644 --- a/amxmodx/scripting/include/VipM/ItemsController.inc +++ b/amxmodx/scripting/include/VipM/ItemsController.inc @@ -1,175 +1,3 @@ -#if defined _vipmodular_ic_included - #endinput -#endif -#define _vipmodular_ic_included +// for compat with old vipm versions -#include -#include - -/** - * Vip Modular: Items Controller -*/ - -enum VipM_IC_T_Item {VipM_IC_Invalid_Item = -1} - -enum E_ItemTypeEvent{ - - /* - * Описание: Вызывается, когда читаются параметры предмета. - * Возв. тип: VipM_FwdReturn - * Параметры: (const JSON:jCfg, Trie:Params): - * jCfg - JSON-обьект с параметрами предмета. - * Params - Хеш-карта с прочитанными параметрами. Может быть изменена. - * - * Примечание: Вызывается в момент чтения оружия нативом VipM_IC_JsonGetItem. Скорее всего в plugin_precache. - * Примечание: Если возвращено VIPM_STOP, предмет будет пропущен. - */ - ItemType_OnRead, - - /* - * Описание: Вызывается, когда предмет выдаётся игроку (При вызове натива VipM_IC_GiveItem). - * Возв. тип: VipM_FwdReturn - * Параметры: (const UserId, const Trie:Params): - * UserId - Индекс игрока, которому выдаётся предмет. - * Params - Хеш-карта с параметрами. Для извлечения отдельных значений можно использовать стоковые функции VipM_Params_*. - * - * Примечание: Если возвращено VIPM_STOP, предмет не будет считаться выданным (Натив VipM_IC_GiveItem вернёт false). - */ - ItemType_OnGive, -} - -/** - * Вызывается в момент инициалзиации типов предметов. - * - * @note Вызывается из VipM_OnInitModules - * - * @noreturn - */ -forward VipM_IC_OnInitTypes(); - -/** - * Вызывается после чтения предмета из JSON. - * - * @param jItem JSON-обьект с параметрами предмета. - * @param Params Хеш-карта с прочитанными параметрами. - * - * @return Если вернёт VIPM_STOP, предмет не будет загружен. - */ -forward VipM_IC_OnReadItem(const JSON:jItem, Trie:Params); - -/** - * Вызывается перед выдачей предмета игроку. - * - * @param UserId Индекс игрока, которому выдаётся предмет. - * @param Params Хеш-карта с параметрами предмета. - * - * @return Если вернёт VIPM_STOP, предмет не будет выдан. - */ -forward VipM_IC_OnGiveItem(const UserId, const Trie:Params); - -/** - * Инициализирует контроллер предметов. - * - * @noreturn - */ -native VipM_IC_Init(); - -/** - * Регистрирует новый тип предмета. - * - * @param Type Название типа. - * - * @return Индекс зарегистрированного типа - */ -native VipM_IC_RegisterType(const Type[]); - -/** - * Регистрирует обработчик события для указанного типа предмета. - * - * @param Type Название типа. - * @param Event Событие. - * @param Func Название функции-обработчика. - * - * @return Вернёт true, если обработчик успешно зарегистрирован. - */ -native VipM_IC_RegisterTypeEvent(const Type[], const E_ItemTypeEvent:Event, const Func[]); - -/** - * Загрузка предмета из JSON-обьекта. - * - * @param jItem JSON-объект, содержащий информацию о предмете. - * - * @note После загрузки предмета, JSON-объект уничтожается. - * @note Структура объекта: - * { - * "Type": "НазваниеТипа", - * "НазваниеПараметра1": "ЗначениеПараметра1", - * "НазваниеПараметра2": "ЗначениеПараметра2", - * ... - * } - * - * @return Индекс загруженного предмета. VipM_IC_Invalid_Item, если что-то пошло не так. - */ -native VipM_IC_T_Item:VipM_IC_JsonGetItem(&JSON:jItem); - -/** - * Выдача предмета игроку. - * - * @param UserId Индекс игрока. - * @param ItemId Индекс предмета, возвращённый нативом VipM_IC_JsonGetItem. - * - * @return true, если предмет успешно выдан, иначе false. - */ -native bool:VipM_IC_GiveItem(const UserId, const VipM_IC_T_Item:ItemId); - -stock Array:VipM_IC_JsonGetItems(JSON:jItems) { - new Array:aItems = Invalid_Array; - if (jItems == Invalid_JSON) { - return aItems; - } - - switch (json_get_type(jItems)) { - case JSONArray: { - new cItems = json_array_get_count(jItems); - if (cItems < 1) { - return Invalid_Array; - } - - aItems = ArrayCreate(1, cItems); - for (new i = 0; i < cItems; i++) { - new JSON:jItem = json_array_get_value(jItems, i); - new VipM_IC_T_Item:ItemId = VipM_IC_JsonGetItem(jItem); - if (ItemId != VipM_IC_Invalid_Item) { - ArrayPushCell(aItems, ItemId); - } - } - json_free(jItems); - } - - case JSONObject, JSONString: { - new VipM_IC_T_Item:ItemId = VipM_IC_JsonGetItem(jItems); - if (ItemId == VipM_IC_Invalid_Item) { - return Invalid_Array; - } - - aItems = ArrayCreate(1, 1); - ArrayPushCell(aItems, ItemId); - } - } - return aItems; -} - -stock bool:VipM_IC_GiveItems(const UserId, const Array:aItems) { - if (aItems == Invalid_Array) { - return false; - } - - new bool:bRes = false; - for (new i = 0; i < ArraySize(aItems); i++) { - if (VipM_IC_GiveItem(UserId, VipM_IC_T_Item:ArrayGetCell(aItems, i))) { - bRes = true; - } - } - - return bRes; -} +#include diff --git a/amxmodx/scripting/include/VipM/L/Counter.inc b/amxmodx/scripting/include/VipM/L/Counter.inc new file mode 100644 index 0000000..5b65371 --- /dev/null +++ b/amxmodx/scripting/include/VipM/L/Counter.inc @@ -0,0 +1,86 @@ +#if defined _vipmodular_l_counter_included + #endinput +#endif +#define _vipmodular_l_counter_included + +#include + +#define VIPM_L_COUNTER_KEY_MAX_LEN 64 + +new const VIPM_L_COUNTER_PARAM_TYPE[] = "VipM-L-CounterType"; + +enum VipM_L_Counter_Type { + /** + * Сбрасывается при спавне игрока + */ + VipM_L_Counter_PerLife, + + /** + * Сбрасывается в начале раунда + */ + VipM_L_Counter_PerRound, + + /** + * Сбрасывается при звходе игрока на сервер + */ + VipM_L_Counter_PerSession, + + /** + * Сбрасывается в начале игры (начало карты или sv_restart) + */ + VipM_L_Counter_PerGame, + + /** + * Сбрасывается в начале карты + */ + VipM_L_Counter_PerMap, +} + +/** + * Получение текущего значения счётчика. + * + * @param type Тип счётчика (см. VipM_L_Counter_Type). + * @param key Ключ счётчика, уникальный для каждого типа. + * @param playerIndex Индекс игрока. + * + * @return Текущее значение счётчика. + */ +native VipM_L_Counter_Get(const VipM_L_Counter_Type:type, const key[], const playerIndex); + +/** + * Перезапись текущего значения счётчика. + * + * @param type Тип счётчика (см. VipM_L_Counter_Type). + * @param key Ключ счётчика, уникальный для каждого типа. + * @param playerIndex Индекс игрока. + * @param value Новое значение счётчика. + * + * @return Новое значение счётчика. + */ +native VipM_L_Counter_Set(const VipM_L_Counter_Type:type, const key[], const playerIndex, const value); + +/** + * Инкрементация значения счётчика. + * + * @param type Тип счётчика (см. VipM_L_Counter_Type). + * @param key Ключ счётчика, уникальный для каждого типа. + * @param playerIndex Индекс игрока. + * @param add Добавляемое значение. + * + * @return Новое значение счётчика. + */ +stock VipM_L_Counter_Inc(const VipM_L_Counter_Type:type, const key[], const playerIndex, const add = 1) { + return VipM_L_Counter_Set(type, key, playerIndex, VipM_L_Counter_Get(type, key, playerIndex) + add); +} + +stock VipM_L_Counter_Type:PCGet_VipmCounterType(const Trie:p, const key[], const VipM_L_Counter_Type:def = VipM_L_Counter_PerLife) { + return PCGet_Cell(p, key, def); +} + +stock VipM_L_Counter_Type:PCSingle_VipmCounterType(const JSON:valueJson, const key[], const VipM_L_Counter_Type:def = VipM_L_Counter_PerLife, const orFailKey[] = "") { + return PCSingle_Cell(valueJson, key, VIPM_L_COUNTER_PARAM_TYPE, def, orFailKey); +} + +stock VipM_L_Counter_Type:PCSingle_ObjVipmCounterType(const JSON:objectJson, const key[], const VipM_L_Counter_Type:def = VipM_L_Counter_PerLife, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, VIPM_L_COUNTER_PARAM_TYPE, def, dotNot, orFail); +} diff --git a/amxmodx/scripting/include/VipM/Limits.inc b/amxmodx/scripting/include/VipM/Limits.inc index b5a4348..245098b 100644 --- a/amxmodx/scripting/include/VipM/Limits.inc +++ b/amxmodx/scripting/include/VipM/Limits.inc @@ -1,25 +1,33 @@ -#if defined _vipmodular_l_included +#if defined __vipm_limits_included #endinput #endif -#define _vipmodular_l_included +#define __vipm_limits_included + +#include +#include /** * Vip Modular: Limits */ +#define VIPM_LIMITS_TYPE_NAME_MAX_LEN 64 + +stock const VIPM_PARAM_TYPE_LIMIT_TYPE_NAME[] = "VipM-LimitType"; +stock const VIPM_PARAM_TYPE_LIMIT_NAME[] = "VipM-Limit"; +stock const VIPM_PARAM_TYPE_LIMITS_NAME[] = "VipM-Limits"; + enum T_LimitUnit {Invalid_LimitUnit = -1} enum E_LimitEvent{ - /* - * Описание: Вызывается после прочтения параметров условного элемента. + * Описание: Вызывается после прочтения параметров лимита. * Возв. тип: VipM_FwdReturn * Параметры: (const JSON:jUnit, Trie:tParams): * jUnit - JSON-обьект с параметрами. * tParams - Хэш-карта с прочитанными параметрами. Может быть изменена. * * Примечание: Вызывается в plugin_precache - * Примечание: Если возвращено VIPM_STOP, условный элемент будет пропущен. + * Примечание: Если возвращено VIPM_STOP, лимит будет пропущен. */ Limit_OnRead, @@ -28,16 +36,15 @@ enum E_LimitEvent{ * Возв. тип: bool * Параметры: (const Trie:tParams, const UserId): * tParams - Хэш-карта с параметрами. Для извлечения отдельных значений можно использовать стоковые функции VipM_Params_*. - * UserId - Индекс игрока. 0, если условный элемент не зависит от игрока. + * UserId - Индекс игрока. 0, если лимит не зависит от игрока. * * Примечание: Если возвращено true, условие выполняется. - * Примечание: Не вызывается для статических условных элементов. + * Примечание: Не вызывается для статических лимитов. */ Limit_OnCheck, } enum E_LimitsExecType { - /* ИЛИ */ Limit_Exec_OR, @@ -49,17 +56,30 @@ enum E_LimitsExecType { } /** - * Вызывается перед чтением параметров условного элемента. + * Вызывается в момент, когда нужно регистрировать типы лимитов. + * Типы лимитов должны регистрироваться строго в рамках этого форварда. + * + * @note Вызывается в рамках plugin_precache. + * + * @deprecated Use VipM_Limits_OnInited instead. + * + * @noreturn + */ +#pragma deprecated Use VipM_Limits_OnInited instead. +forward VipM_OnInitLimits(); + +/** + * Вызывается в момент, когда нужно регистрировать типы лимитов. + * Типы лимитов должны регистрироваться строго в рамках этого форварда. * - * @param jUnit JSON-обьект с параметрами. - * @param tParams Хэш-карта с прочитанными параметрами. Может быть изменена. + * @note Вызывается в рамках plugin_precache. * - * @return Если возвращено VIPM_STOP, условный элемент будет пропущен. + * @noreturn */ -forward VipM_OnReadLimitUnit(const JSON:jUnit, const Trie:tParams); +forward VipM_Limits_OnInited(); /** - * Регистрирует в системе тип условного элемента. + * Регистрирует в системе тип лимита. * * @param jUnit Название регистрируемого типа. * @param tParams Относится ли регистрируемый тип к игрокам. @@ -74,7 +94,7 @@ forward VipM_OnReadLimitUnit(const JSON:jUnit, const Trie:tParams); native VipM_Limits_RegisterType(const sName[], const bool:bForPlayer = true, const bool:bStatic = false); /** - * Регистрирует обработчик события для указанного типа условного элемента. + * Регистрирует обработчик события для указанного типа лимита. * * @param sName Название типа. * @param iEvent Событие. @@ -85,7 +105,7 @@ native VipM_Limits_RegisterType(const sName[], const bool:bForPlayer = true, con native VipM_Limits_RegisterTypeEvent(const sName[], const E_LimitEvent:iEvent, const sFunc[]); /** - * Добавляет параметр(ы) для типа условного элемента. + * Добавляет параметр(ы) для типа лимита. * * @param sName Название типа. * @param any:... Перечисление параметров. @@ -99,18 +119,42 @@ native VipM_Limits_RegisterTypeEvent(const sName[], const E_LimitEvent:iEvent, c native VipM_Limits_AddTypeParams(const sName[], any:...); /** - * Читает условный элемент из JSON-обьекта. + * Добавляет параметры для лимита. + * + * @param moduleName Название лимита. + * @param any:... Перечисление параметров. + * + * @note Формат перечисления параметров: + * VipM_Modules_AddParamsEx(..., const paramName[], const paramType[], const bool:paramRequired, ...); + * + * Где: + * - paramName - Название параметра; + * - paramType - Название типа параметра; + * - paramRequired - Обязателен ли параметр. + * + * Пример: + * VipM_Limits_AddParamsEx(limitName, + * "Param1", "String", true, + * "Param2", "Integer", false + * ); + * + * @noreturn + */ +native VipM_Limits_AddParamsEx(const limitName[], const any:...); + +/** + * Читает лимит из JSON-обьекта. * * @param jLimit JSON-обьект. * * @note После вызова натива, JSON-обьект не очищается. * - * @return Индекс прочтённого условного элемента. Invalid_LimitUnit, если что-то пошло не так. + * @return Индекс прочтённого лимита. Invalid_LimitUnit, если что-то пошло не так. */ native T_LimitUnit:VipM_Limits_ReadFromJson(const JSON:jLimit); /** - * Читает список условных элементов из JSON-обьекта. + * Читает список лимитов из JSON-значения. * * @param jLimits JSON-обьект. * @param aLimits Динамический массив, в который надо добавить прочтённые элементы, либо Invalid_Array, если надо создать новый. @@ -118,12 +162,12 @@ native T_LimitUnit:VipM_Limits_ReadFromJson(const JSON:jLimit); * @note После вызова натива, JSON-обьект не очищается. * @note При передаче параметра aLimits, функция вернёт этот же массив с новыми элементами. * - * @return Динамический массив с индексами прочтённых условных элементов. Invalid_Array, если не было прочтено ни одного элемента. + * @return Динамический массив с хендлерами прочтённых лимитов. Invalid_Array, если не было прочтено ни одного элемента. */ native Array:VipM_Limits_ReadListFromJson(const JSON:jLimits, Array:aLimits = Invalid_Array); /** - * Устанавливает значение для статического типа условного элемента. + * Устанавливает значение для статического лимита. * * @param sName Название типа. * @param bNewValue Новое значение. @@ -136,12 +180,12 @@ native Array:VipM_Limits_ReadListFromJson(const JSON:jLimits, Array:aLimits = In native VipM_Limits_SetStaticValue(const sName[], const bool:bNewValue, const UserId = 0); /** - * Выполняет проверку условного элемента. + * Выполняет проверку лимита. * - * @param iLimit Индекс условного элемента. + * @param iLimit Индекс лимита. * @param UserId Индекс игрока. * - * @note Если индекс игрока не передан, попытка использовать относящийся к игроку условный оператор вызовет ошибку. + * @note Если индекс игрока не передан, попытка использовать относящийся к игроку лимит вызовет ошибку. * Но это уже ошибка конфигурации. * * @return true, если условие выполняется, иначе false. @@ -149,15 +193,61 @@ native VipM_Limits_SetStaticValue(const sName[], const bool:bNewValue, const Use native bool:VipM_Limits_Execute(const T_LimitUnit:iLimit, const UserId = 0); /** - * Выполняет проверку списка условных элементов. + * Выполняет проверку списка лимитов. * - * @param aLimits Динамический массив условных элементов. + * @param aLimits Динамический массив хендлеров лимитов. * @param UserId Индекс игрока. * @param iType Логический оператор. См. перечисление E_LimitsExecType. * - * @note Если индекс игрока не передан, попытка использовать относящийся к игроку условный оператор вызовет ошибку. + * @note Если индекс игрока не передан, попытка использовать относящийся к игроку лимит вызовет ошибку. * Но это уже ошибка конфигурации. * * @return true, если условие выполняется, иначе false. */ native bool:VipM_Limits_ExecuteList(const Array:aLimits, const UserId = 0, const E_LimitsExecType:iType = Limit_Exec_OR); + +stock Array:Json_Object_GetLimits(const JSON:jObj, const sKey[], const bool:bDotNot = false) { + if (!json_object_has_value(jObj, sKey, .dot_not = bDotNot)) { + return Invalid_Array; + } + + new JSON:jLimits = json_object_get_value(jObj, sKey, bDotNot); + new Array:aLimits = VipM_Limits_ReadListFromJson(jLimits); + json_free(jLimits); + + return aLimits; +} + +stock T_LimitUnit:PCGet_VipmLimit(const Trie:p, const key[], const T_LimitUnit:def = Invalid_LimitUnit) { + return PCGet_Cell(p, key, def); +} + +stock Array:PCGet_VipmLimits(const Trie:p, const key[], const Array:def = Invalid_Array) { + return PCGet_Cell(p, key, def); +} + +stock bool:PCGet_VipmLimitCheck(const Trie:p, const key[], const playerIndex = 0, const bool:def = true) { + new T_LimitUnit:limit = PCGet_VipmLimit(p, key); + if (limit == Invalid_LimitUnit) { + return def; + } + + return VipM_Limits_Execute(limit, playerIndex); +} + +stock bool:PCGet_VipmLimitsCheck(const Trie:p, const key[], const playerIndex = 0, const E_LimitsExecType:type = Limit_Exec_OR, const bool:def = true) { + new Array:limits = PCGet_VipmLimits(p, key); + if (limits == Invalid_Array || ArraySize(limits) < 1) { + return def; + } + + return VipM_Limits_ExecuteList(limits, playerIndex, type); +} + +stock T_LimitUnit:PCSingle_ObjVipmLimit(const JSON:objectJson, const key[], const T_LimitUnit:def = Invalid_LimitUnit, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, VIPM_PARAM_TYPE_LIMIT_NAME, def, dotNot, orFail); +} + +stock Array:PCSingle_ObjVipmLimits(const JSON:objectJson, const key[], const Array:def = Invalid_Array, const bool:dotNot = false, const bool:orFail = false) { + return PCSingle_ObjCell(objectJson, key, VIPM_PARAM_TYPE_LIMITS_NAME, def, dotNot, orFail); +} diff --git a/amxmodx/scripting/include/VipM/M/WeaponMenu.inc b/amxmodx/scripting/include/VipM/M/WeaponMenu.inc index 870f650..e9a5067 100644 --- a/amxmodx/scripting/include/VipM/M/WeaponMenu.inc +++ b/amxmodx/scripting/include/VipM/M/WeaponMenu.inc @@ -5,6 +5,13 @@ #define VIPM_M_WEAPONMENU_EXPIRE_STATUS_MAX_LEN 64 +stock const VIPM_M_WEAPONMENU_CMD_MENU[] = "vipm_m_weaponmenu_menu"; +stock const VIPM_M_WEAPONMENU_CMD_MENU_SILENT[] = "vipm_m_weaponmenu_menu_silent"; +stock const VIPM_M_WEAPONMENU_CMD_AUTOOPEN_TOGGLE[] = "vipm_m_weaponmenu_autoopen_toggle"; + +stock const VIPM_M_WEAPONMENU_PLAYER_COUNTER_KEY[] = "VipM-M-WeaponMenu-Player"; +stock const VIPM_M_WEAPONMENU_MENU_COUNTER_KEY_PREFIX[] = "VipM-M-WeaponMenu-Menu"; + /** * Устанавливает статус окончания привилегий, выводимый игроку в оружейном меню. * diff --git a/amxmodx/scripting/include/VipM/Modules.inc b/amxmodx/scripting/include/VipM/Modules.inc index 89b5f58..4b41730 100644 --- a/amxmodx/scripting/include/VipM/Modules.inc +++ b/amxmodx/scripting/include/VipM/Modules.inc @@ -7,9 +7,13 @@ * Vip Modular: Modules */ -#define VIPM_MODULE_MAX_NAME 32 +#define VIPM_MODULES_TYPE_NAME_MAX_LEN 64 -enum E_ModuleEvent{ +stock const VIPM_MODULES_PARAMS_TEMP_MARK_KEY[] = "___temp_module_params___"; + +stock const VIPM_PARAM_TYPE_MODULE_TYPE_NAME[] = "VipM-ModuleType"; + +enum E_ModuleEvent { /* * Описание: Вызывается, когда модуль был активирован. @@ -24,9 +28,9 @@ enum E_ModuleEvent{ /* * Описание: Вызывается, когда читаются параметры модуля. * Возв. тип: VipM_FwdReturn - * Параметры: (const JSON:jCfg, Trie:Params): - * jCfg - JSON-обьект с параметрами. - * Params - Хэш-карта с прочитанными параметрами. Может быть изменена. + * Параметры: (const JSON:moduleJson, Trie:p): + * moduleJson - JSON-обьект с параметрами. + * p - Хэш-карта с прочитанными параметрами. Может быть изменена. * * Примечание: Вызывается в plugin_precache * Примечание: Если возвращено VIPM_STOP, элемент модуля будет пропущен. @@ -34,45 +38,68 @@ enum E_ModuleEvent{ Module_OnRead, /* - * Описание: Вызывается, когда надо обьединить два набора параметров модуля. Только для модулей с Once = false. + * Описание: Вызывается при добавлении игроку второго и последующих модулей одного типа. * Возв. тип: Trie - * Параметры: (const Trie:MainParams, const Trie:NewParams): - * MainParams - Основной набор параметров модуля. - * NewParams - Добавляемый набор параметров модуля. + * Параметры: (const Trie:p1, const Trie:p2): + * p1 - Первый набор параметров. + * p2 - Второй набор параметров. + * + * Примечание: Если обработчик для этого события не зарегистрирован, + * всегда будет выбираться p1 (модуль, добавленный первым) без изменений. * - * Примечание: Результат обьединения должен быть возвращён обработчиком события. + * Примечание: Очищение/изменение переданных в параметры Trie недопустимо. + * + * Примечание: Обработчик может вернуть один из полученных Trie или создать новый. + * При содании нового Trie ядро само позаботится о его очищении в будущем. */ - Module_OnCompareParams, + Module_OnMergeParams, } -forward VipM_OnReadModuleUnit(const JSON:jUnit, const Trie:tParams); +/** + * Вызывается в момент, когда нужно регистрировать модули. + * Модули должны регистрироваться строго в рамках этого форварда. + * + * @note Вызывается в рамках plugin_precache. + * + * @noreturn + */ +forward VipM_Modules_OnInited(); + +/** + * Вызывается перед активацией модуля. + * + * @param moduleName Название модуля. + * + * @return VIPM_CONTINUE - модуль будет активирован, VIPM_STOP - активация модуля будет прервана. + */ +forward VipM_Modules_OnActivate(const moduleName[]); /** * Регистрирует новый модуль. * - * @param Module Название модуля. - * @param Once Обьединять ли параметры элементов модуля. true - Нет, false - Да. Подразумевает использование события OnCompareParams. + * @param moduleName Название модуля. + * @param Once Обьединять ли параметры элементов модуля. true - Нет, false - Да. Подразумевает использование события OnCompareParams. * * @noreturn */ -native VipM_Modules_Register(const Module[], const bool:Once = true); +native VipM_Modules_Register(const moduleName[], const bool:Once = true); /** * Регистрирует обработчик события для указанного модуля. * - * @param Module Название модуля. - * @param Event Событие. - * @param Func Название функции-обработчика. + * @param moduleName Название модуля. + * @param event Событие. + * @param func Название функции-обработчика. * * @return Вернёт true, если обработчик успешно зарегистрирован. */ -native bool:VipM_Modules_RegisterEvent(const Module[], const E_ModuleEvent:Event, const Func[]); +native bool:VipM_Modules_RegisterEvent(const moduleName[], const E_ModuleEvent:event, const func[]); /** * Добавляет набор параметров для указанного модуля. * - * @param Module Название модуля. - * @param any:... Перечисление параметров. + * @param moduleName Название модуля. + * @param any:... Перечисление параметров. * * @note Формат указания параметров: VipM_Modules_AddParams(..., const ParamName[], const E_ParamType:ParamType, const bool:ParamRequired, ...); * @note ParamName - Название параметра / ParamType - Тип параметра / ParamRequired - Обязателен ли параметр. @@ -80,36 +107,59 @@ native bool:VipM_Modules_RegisterEvent(const Module[], const E_ModuleEvent:Event * * @noreturn */ -native VipM_Modules_AddParams(const Module[], const any:...); -#define VipM_SetModuleParams VipM_Modules_AddParams +native VipM_Modules_AddParams(const moduleName[], const any:...); + +/** + * Добавляет параметры для модуля. + * + * @param moduleName Название модуля. + * @param any:... Перечисление параметров. + * + * @note Формат перечисления параметров: + * VipM_Modules_AddParamsEx(..., const paramName[], const paramType[], const bool:paramRequired, ...); + * + * Где: + * - paramName - Название параметра; + * - paramType - Название типа параметра; + * - paramRequired - Обязателен ли параметр. + * + * Пример: + * VipM_Modules_AddParamsEx(moduleName, + * "Param1", "String", true, + * "Param2", "Integer", false + * ); + * + * @noreturn + */ +native VipM_Modules_AddParamsEx(const moduleName[], const any:...); /** * Активен ли указанный модуль. * - * @param Module Название модуля. + * @param moduleName Название модуля. * * @return true, если модуль активен, иначе false. */ -native bool:VipM_Modules_IsActive(const Module[]); +native bool:VipM_Modules_IsActive(const moduleName[]); /** * Получение набора параметров модуля для указанного игрока. * - * @param Module Название модуля. - * @param UserId Индекс игрока. + * @param moduleName Название модуля. + * @param playerIndex Индекс игрока. * - * @return Хэш-карту с параметрами. + * @return Trie с параметрами. */ -native Trie:VipM_Modules_GetParams(const Module[], const UserId); +native Trie:VipM_Modules_GetParams(const moduleName[], const playerIndex); /** * Проверка наличия у игрока доступа к указанному модулю. * - * @param sModuleName Название модуля. - * @param UserId Индекс игрока. + * @param moduleName Название модуля. + * @param playerIndex Индекс игрока. * * @return true, если у игрока имеется доступ к модулю, иначе false. */ -stock bool:VipM_Modules_HasModule(const sModuleName[], const UserId) { - return VipM_Modules_GetParams(sModuleName, UserId) != Invalid_Trie; +stock bool:VipM_Modules_HasModule(const moduleName[], const playerIndex) { + return VipM_Modules_GetParams(moduleName, playerIndex) != Invalid_Trie; } diff --git a/amxmodx/scripting/include/VipM/Params.inc b/amxmodx/scripting/include/VipM/Params.inc index fbb9f26..ad3dbfd 100644 --- a/amxmodx/scripting/include/VipM/Params.inc +++ b/amxmodx/scripting/include/VipM/Params.inc @@ -3,108 +3,123 @@ #endif #define _vipmodular_params_included -#include amxmodx +#include +#include + +#define VIPM_PARAM_NAME_MAX_LEN PARAM_KEY_MAX_LEN /** * Vip Modular: Parameters */ +#pragma deprecated Use params controller instead enum E_ParamType { /* * Пользовательский тип параметра. Подразумевает использование события OnRead. * Обязательность таких параметров игнорируется. */ + #pragma deprecated Use params controller instead ptCustom = 0, /* * Целое число. */ + #pragma deprecated Use params controller instead ptInteger, /* * Дробное число. */ + #pragma deprecated Use params controller instead ptFloat, /* * true/false. */ + #pragma deprecated Use params controller instead ptBoolean, /* * Строка. */ + #pragma deprecated Use params controller instead ptString, /* * Цвет (Массив из трёх целых чисел). */ + #pragma deprecated Use params controller instead ptColor, /* * Двумерный вектор (Массив из двух дробных чисел). */ + #pragma deprecated Use params controller instead ptVector2, /* * Трёхмерный вектор (Массив из трёх дробных чисел). */ + #pragma deprecated Use params controller instead ptVector3, /* * Условный элемент. */ + #pragma deprecated Use params controller instead ptLimit, /* * Массив условных элементов. */ + #pragma deprecated Use params controller instead ptLimits, } stock const VIPM_PARAM_TYPE_NAMES[E_ParamType][] = {"Custom", "Integer", "Float", "Bool", "String", "Color", "Vector2", "Vector3", "Limit", "Limits"}; +#pragma deprecated Use PCGet_*() stocks from ParamsController instead. stock any:VipM_Params_GetCell(const Trie:tParams, const sKey[], const any:iDef = 0) { - if (tParams == Invalid_Trie) { - return iDef; - } - - new any:iVal; - return TrieGetCell(tParams, sKey, iVal) ? iVal : iDef; + return PCGet_Cell(tParams, sKey, iDef); } +#pragma deprecated Use PCGet_*() stocks from ParamsController instead. stock VipM_Params_GetInt(const Trie:tParams, const sKey[], const iDef = 0) { - return _:VipM_Params_GetCell(tParams, sKey, iDef); + return PCGet_Int(tParams, sKey, iDef); } +#pragma deprecated Use PCGet_*() stocks from ParamsController instead. stock bool:VipM_Params_GetBool(const Trie:tParams, const sKey[], const bool:bDef = false) { - return !!VipM_Params_GetCell(tParams, sKey, bDef); + return PCGet_Bool(tParams, sKey, bDef) ? true : false; } +#pragma deprecated Use PCGet_*() stocks from ParamsController instead. stock Float:VipM_Params_GetFloat(const Trie:tParams, const sKey[], const Float:fDef = 0.0) { - return Float:VipM_Params_GetCell(tParams, sKey, fDef); + return PCGet_Float(tParams, sKey, fDef); } +#pragma deprecated Use PCGet_*() stocks from ParamsController instead. stock VipM_Params_GetStr(const Trie:tParams, const sKey[], sOut[], const iOutLen, const sDef[] = NULL_STRING) { - new iWrittenLen = 0; - if ( - tParams != Invalid_Trie - && TrieGetString(tParams, sKey, sOut, iOutLen, iWrittenLen) - ) { - return iWrittenLen; - } + return PCGet_Str(tParams, sKey, sOut, iOutLen, sDef); +} - return copy(sOut, iOutLen, sDef); +#pragma deprecated Use PCGet_*() stocks from ParamsController instead. +stock VipM_Params_GetStri(const Trie:tParams, const sKey[], const sDef[] = NULL_STRING) { + new str[PARAM_VALUE_MAX_LEN]; + PCGet_Str(p, key, str, charsmax(str), def); + return str; } stock Array:VipM_Params_GetArr(const Trie:tParams, const sKey[]) { - return Array:VipM_Params_GetCell(tParams, sKey, Invalid_Array); + return Array:PCGet_Cell(tParams, sKey, Invalid_Array); } +#pragma deprecated Use PCGet_VipmLimit() instead stock T_LimitUnit:VipM_Params_GetLimit(const Trie:tParams, const sKey[], const T_LimitUnit:iDef = Invalid_LimitUnit) { - return T_LimitUnit:VipM_Params_GetCell(tParams, sKey, iDef); + return T_LimitUnit:PCGet_Cell(tParams, sKey, iDef); } +#pragma deprecated Use PCGet_VipmLimitCheck() instead stock bool:VipM_Params_ExecuteLimit( const Trie:tParams, const sKey[] = "Limit", @@ -119,6 +134,7 @@ stock bool:VipM_Params_ExecuteLimit( return VipM_Limits_Execute(iLimit, UserId); } +#pragma deprecated Use PCGet_VipmLimitsCheck() instead stock bool:VipM_Params_ExecuteLimitsList( const Trie:tParams, const sKey[] = "Limits", diff --git a/amxmodx/scripting/include/VipModular.inc b/amxmodx/scripting/include/VipModular.inc index 76c53ff..16d9027 100644 --- a/amxmodx/scripting/include/VipModular.inc +++ b/amxmodx/scripting/include/VipModular.inc @@ -7,10 +7,16 @@ #include json stock const VIPM_LIBRARY[] = "VipModular"; -#define _VIPM_VERSION "5.0.0-b12" +#define _VIPM_VERSION "5.0.0-rc4f1" stock const VIPM_VERSION[] = _VIPM_VERSION; +#define _VIPM_PLUGIN_URL "https://github.com/AmxxModularEcosystem/VipModular" + +// deprecated stock const VIPM_CFG_PATH[] = "plugins/VipModular"; -#define _VIPM_PLUGIN_URL "https://github.com/ArKaNeMaN/amxx-VipModular-pub" +// new +stock const VIPM_CONFIGS_FOLDER_NAME[] = "VipModular"; +stock const VIPM_VIPS_CONFIG_FILE_PATH[] = "Vips.json"; +stock const VIPM_VIPS_CONFIG_DIR_PATH[] = "Vips"; /** * Получение пути, относительно папки с конфигами вип-системы или AmxModX. @@ -19,32 +25,49 @@ stock const VIPM_CFG_PATH[] = "plugins/VipModular"; * Иначе из папки вип-системы (см. константу VIPM_CFG_PATH). * * @param Path Путь / Название файла. - * @param Out Буффер для записи полученного пути. - * @param Len Размер буфера. + * @param sOut Буффер для записи полученного пути. + * @param iOutLen Размер буфера. + * + * @deprecated Use PCPath_MakePath() from ParamsController instead * * @return Кол-во записанных в буфер ячеек. */ -stock VipM_GetCfgPath(const Path[], Out[], const Len){ +#pragma deprecated Use PCPath_MakePath() from ParamsController instead +stock VipM_GetCfgPath(const sPath[] = "", sOut[], const iOutLen){ static __amxx_configsdir[PLATFORM_MAX_PATH]; if (!__amxx_configsdir[0]) { get_localinfo("amxx_configsdir", __amxx_configsdir, charsmax(__amxx_configsdir)); } + + if (!sPath[0]) { + return formatex(sOut, iOutLen, "%s/%s", __amxx_configsdir, VIPM_CFG_PATH); + } - return (Path[0] == '/') - ? formatex(Out, Len, "%s%s", __amxx_configsdir, Path) - : formatex(Out, Len, "%s/%s/%s", __amxx_configsdir, VIPM_CFG_PATH, Path); + return (sPath[0] == '/') + ? formatex(sOut, iOutLen, "%s%s", __amxx_configsdir, sPath) + : formatex(sOut, iOutLen, "%s/%s/%s", __amxx_configsdir, VIPM_CFG_PATH, sPath); } -// Инлайн версия предыдущего стока. -// Сорян за извращения :)) -// TODO: Заменить на сток, возвращающий строку -stock __inl_VipM_GetCfgPath[PLATFORM_MAX_PATH] = ""; -#define inl_VipM_GetCfgPath(%1) \ - ( \ - VipM_GetCfgPath(%1, __inl_VipM_GetCfgPath, charsmax(__inl_VipM_GetCfgPath)) \ - ? __inl_VipM_GetCfgPath \ - : NULL_STRING \ - ) +/** + * Получение пути, относительно папки с конфигами вип-системы или AmxModX. + * + * @note Если название файла начинается со слеша `/`, файл будет взят из папки amxmodx/configs. + * Иначе из папки вип-системы (см. константу VIPM_CFG_PATH). + * + * @param Path Путь / Название файла. + * + * @deprecated Use PCPath_iMakePath() from ParamsController instead + * + * @return Полученный путь. + */ +#pragma deprecated Use PCPath_iMakePath() from ParamsController instead +stock VipM_iGetCfgPath(const sPath[] = "") { + new sRetPath[PLATFORM_MAX_PATH]; + VipM_GetCfgPath(sPath, sRetPath, charsmax(sRetPath)); + return sRetPath; +} +// inl_VipM_GetCfgPath is deprecated +#define inl_VipM_GetCfgPath VipM_iGetCfgPath enum _:VipM_FwdReturn{ /* @@ -59,38 +82,32 @@ enum _:VipM_FwdReturn{ } /** - * Вызывается в момент инициалзиации модулей, типов условных элементов и режимов доступа. + * Вызывается после инициалзиации модулей и лимитов. * * @note Вызывается из plugin_precache * * @noreturn */ +#pragma deprecated Use VipM_Modules_OnInited() or VipM_Limits_OnInited() instead. forward VipM_OnInitModules(); /** - * Вызывается в момент чтения элемента конфига (модуля или ограничения). - * - * @param jUnit JSON-обьект с параметрами - * @param tParams Хэш-карта с прочитанными параметрами. Может быть изменена. + * Вызывается после полной загрузки системы привилегий. * - * @note Параметр tParams содержит только прочитанные ядром параметры. - * - * @note Соответствует событиям Limit_OnRead и Module_OnRead, - * и форвардам VipM_OnReadLimitUnit и VipM_OnReadModuleUnit. - * Вызывается перед ними. + * @note Вызывается из plugin_precache * - * @return По умолчанию VIPM_CONTINUE. Если вернуть VIPM_STOP, элемент конфига будет проигнорирован. + * @noreturn */ -forward VipM_OnReadUnit(const JSON:jUnit, const Trie:tParams); +forward VipM_OnLoaded(); /** - * Вызывается после полной загрузки вип-системы. + * Обновляет привилегии указанного пользователя. * - * @note Вызывается из plugin_precache + * @param UserId Индекс игрока, чьи привилегии надо обновить. * * @noreturn */ -forward VipM_OnLoaded(); +native VipM_UserUpdate(const UserId); /** * Вызывается после загрузки привилегий игрока. @@ -103,17 +120,10 @@ forward VipM_OnLoaded(); */ forward VipM_OnUserUpdated(const UserId); -/** - * Обновляет привилегии указанного пользователя. - * - * @param UserId Индекс игрока, чьи привилегии надо обновить. - * - * @noreturn - */ -native VipM_UserUpdate(const UserId); - /** * Выводит лог с указанием JSON-файла, из которого было прочитано указанное значене. + * + * @deprecated * * @param jValue Значение, для которого надо вывести лог. * @param sPrefix Префикс лога. Например: ERROR, WARNING, INFO @@ -122,10 +132,11 @@ native VipM_UserUpdate(const UserId); * * @noreturn */ +#pragma deprecated Use PCJson_*ForFile() instead. native VipM_Json_LogForFile(const JSON:jValue, const sPrefix[], const sMessage[], any:...); #include #include -#include +#include #include #include diff --git a/readme/default-extensions.md b/readme/default-extensions.md index 3d27dea..f5a806a 100644 --- a/readme/default-extensions.md +++ b/readme/default-extensions.md @@ -10,95 +10,8 @@ ## Ограничения -Ограничения и их параметры (при наличии). - -- ForAll/Always - Условие всегда верно -- Never - Условие всегда ложно -- Steam - Условие верно для Steam-игроков -- Alive - Условие верно для живых игроков -- Bot - Условие верно для ботов -- Name - Условие верно для игроков с указанным ником - - `Name` - ник игрока -- Flags - Условие верно для игрков, имеющих указанные флаги - - `Flags` - требуемые флаги - - `Strict` - если `true`, будет срабатывать при наличии всех указанных флагов, иначе сработает при наличии хотя бы одного флага -- SteamId - Усовие верно для игроков с указанным SteamID - - `SteamId` - SteamID игрока -- Ip - Условие верно для игроков с указанным IP-адресом - - `Ip` - IP-адрес игрока -- Map - Условие верно на указанной карте - - `Map` - Название/префикс карты - - `Real` - если `true`, проверяться будет реальное название карты, а не установленное другими плагинами. - - `Prefix` - если `true`, будет проверяться наличие значения параметра `Map` в начале названия карты. -- HasPrimaryWeapon - Условие верно для игроков имеющих основное оружие - - `HasNot` - если `true`, условие сработает для игроков, НЕ имеющих основное оружие -- Round - Условие верно в указанные раунды - - `Min` - раунд, с которого начнёт срабатывать условие - - `Max` - раунд, с которого условие перестанет срабатывать -- WeekDay - Условие верно в указанный день недели - - `Day` - название дня недели (Пн, Вт, Ср, Чт, Пт, Сб, Вс) -- RoundTime - Условие верно в указанный интервал времени от начала раунда - - `Min` - секунда, с которой начнёт срабатывать условие - - `Max` - секунда, с которой условие перестанет срабатывать -- InFreezyTime - Условие верно во время freezy time - - `Reverse` - если `true`, результат проверки будет обращён в обратную сторону -- InBuyZone - Условие верно для игроков, находящихся в зоне закупки - - `Reverse` - если `true`, результат проверки будет обращён в обратную сторону - -- Logic-OR - Условие верно, когда верно хотя бы одно из указанных условий - - `Limits` - список условий -- Logic-XOR - Условие верно, когда верно только одно из указанных условий - - `Limits` - список условий -- Logic-AND - Условие верно, когда верно все указанные условия - - `Limits` - список условий -- Logic-NOT - Условие верно, когда указанное условие не верное - - `Limits` - список условий - -- OncePerMap - Условие верно только при первой проверке за карту - - _Рекомендуется ставить последним в списке условий, чтобы лишний раз не проверялось, хотя зависит от задачи_ - - Указанные в разных местах лимиты не пересекаются друг с другом - - ... но если лимит проброшен через ссылку, то он везде один и будет пересекаться - - Примечание относится ко всем лимитам типа `OncePer*` -- OncePerGame - Условие верно только при первой проверке за игру (сбрасывается при рестарте, например через sv_restart) -- OncePerRound - Условие верно только при первой проверке за раунд - -- Time - Условие верно в указанном интервале времени - - `Before` - Время ДО которого условие будет верно. Формат HH:MM - - `After` - Время ПОСЛЕ которого условие будет верно. Формат HH:MM -- GameTime - Условие верно в указанном интервале времени от начала карты - - `Min` - секунда, с которой начнёт срабатывать условие - - `Max` - секунда, с которой условие перестанет срабатывать -- Frags - Проверка на кол-во фрагов у игрока - - `Min` - минимальное кол-во для срабатывания - - `Max` - максимальное кол-во для срабатывания +Список переехал [сюда](/wiki/Встроенные-лимиты). ## Типы предметов -- [Weapon](extensions/items/weapon.md) - Стандартное оружие -- [ItemsList](extensions/items/items-list.md) - Несколько предметов -- [Command](extensions/items/command.md) - Клиентская/серверная команда -- [DefuseKit](extensions/items/defuse-kit.md) - Набор сапёра -- If - Выдаёт предметы только при выполнении условия - - `Items` - Предметы, которые будут выданы при выполнении условий из параметра `Limits` - - `Limits` - Условия, при выполнении которых будут выданы предметы из параметра `Items` - - `ElseItems` - Предметы, которые будут выданы при НЕвыполнении условий из параметра `Limits` -- Random - Выдаёт случайный предмет из списка - - `Items` - Предметы, из которых будет выдан один случайный -- InstantReloadAllWeapons - Мгновенная перезарядка всего оружия -- InstantReload - Мгновенная перезарядка текущего оружия -- RefillBpAmmo - Пополнение всех видов патронов -- Speed - Умножение скорости до конца раунда - - `Multiplier` - Множитель скорости относительно изначальной -- DamageMult - Умножение получаемого и/или наносимого урона - - `Given` - Множитель наносимого урона - - `Taken` - Множитель получаемого урона -- Money - Игровые деньги - - `Amount` - Сумма, которая будет выдана - - `GiveType` - Тип выдачи - - `Add` - добавить - - `Set` - установить - - `TrackChange` - Показать ли игроку анимацию зачисления денег -- Health - Очки здоровья - - `Health` - Сколько очков здоровья будет выдано - - `MaxHealth` - Максимальное число очков здоровья, выше которого выдано не будет - - `SetHealth` - Если `true` - значение `Health` будет установлено, иначе оно будет добавлено (при `true` параметр `MaxHealth` игнорируется) +Список переехал [сюда](/wiki/Встроенные-типы-предметов). diff --git a/readme/extensions/items.md b/readme/extensions/items.md index 7b558b5..b1ed828 100644 --- a/readme/extensions/items.md +++ b/readme/extensions/items.md @@ -6,11 +6,11 @@ TODO: Переписать ## Структура обьекта предмета -*[Памятка по JSON](/readme/json.md)* +*[Памятка по JSON](/wiki/Памятка-по-JSON)* ```jsonc { - "Type": "", + "Item": "", "": "", // ... diff --git a/readme/extensions/items/command.md b/readme/extensions/items/command.md index c2d3593..33c089f 100644 --- a/readme/extensions/items/command.md +++ b/readme/extensions/items/command.md @@ -1,25 +1 @@ -# Command - -Выполнение команды от имени игрока или сервера. - -## Параметры - -| Название | Тип | По умолчанию\* | Описание | -| :------- | :------------- | :------------- | :-------------------------------------------- | -| Command | Строка | - | Текст команды, которая будет вызываться | -| ByServer | `true`/`false` | `false` | Должна ли команда вызываться от имени сервера | - -_\* - если указано "-", то параметр является обязательным._ - -Параметр `Command` может содержать плейсхолдер `{UserId}`, который при вызове команды будет заменён на индекс игрока. - -## Пример - -```jsonc -{ - "Type": "Command", - - "Command": "HealthNade_Give {UserId}", - "ByServer": true -} -``` +Документация переехала в [раздел WIKI](/wiki/Встроенные-типы-предметов#command). diff --git a/readme/extensions/items/defuse-kit.md b/readme/extensions/items/defuse-kit.md index 5af8197..d7b9b39 100644 --- a/readme/extensions/items/defuse-kit.md +++ b/readme/extensions/items/defuse-kit.md @@ -1,15 +1 @@ -# DefuseKit - -Набор сапёра (Только для команды CT, для TT будет игнорироваться). - -## Пример - -```jsonc -{ - "Type": "DefuseKit" -} -``` - -## Параметры - -_Параметры отсутствуют._ +Документация переехала в [раздел WIKI](/wiki/Встроенные-типы-предметов#defusekit). diff --git a/readme/extensions/items/items-list.md b/readme/extensions/items/items-list.md index b564e41..f21ff14 100644 --- a/readme/extensions/items/items-list.md +++ b/readme/extensions/items/items-list.md @@ -1,31 +1 @@ -# ItemsList - -Список любых предметов. - -## Пример - -```jsonc -{ - "Type": "ItemsList", - - "Items": [ - { - "Type": "Cwapi", - - "Name": "Vip_Ak47", - "GiveType": "Replace" - }, - { - "Type": "Cwapi", - - "Name": "Vip_Deagle", - "GiveType": "Replace" - } - ] -} -``` - -## Параметры - -- `Items` - - Массив обьектов предметов. +Документация переехала в [раздел WIKI](/wiki/Встроенные-типы-предметов#itemslist). diff --git a/readme/extensions/items/weapon.md b/readme/extensions/items/weapon.md index 1e16967..09753ab 100644 --- a/readme/extensions/items/weapon.md +++ b/readme/extensions/items/weapon.md @@ -1,28 +1 @@ -# Weapon - -Стандартное оружие из игры с префиксом `weapon_`. - -## Пример - -```jsonc -{ - "Type": "Weapon", - - "Name": "weapon_ak47", - "GiveType": "Replace", - "BpAmmo": 30 -} -``` - -## Параметры - -- `Name` - - Название оружия из CWAPI. -- `BpAmmo` - - Количество запасных патронов. -- `GiveType` - - Тип выдачи оружия. - - Доступные типы: - - `GT_APPEND` или `Append` или `Add` - Добавить к текущему в соответствующем слоте - - `GT_REPLACE` или `Replace` - Заменить оружие из соответствующего слота на новое - - `GT_DROP_AND_REPLACE` или `Drop` или `DropAndReplace` - Выбросить текущее в соответствующем слоте и выдать новое +Документация переехала в [раздел WIKI](/wiki/Встроенные-типы-предметов#weapon). diff --git a/readme/extensions/limits.md b/readme/extensions/limits.md index c9ca523..87ceebd 100644 --- a/readme/extensions/limits.md +++ b/readme/extensions/limits.md @@ -25,7 +25,7 @@ ## Структура обьекта лимита -_[Памятка по JSON](/readme/json.md)_ +_[Памятка по JSON](/wiki/Памятка-по-JSON)_ ```jsonc { diff --git a/readme/extensions/modules/spawn-items.md b/readme/extensions/modules/spawn-items.md index 1ad280b..35117c6 100644 --- a/readme/extensions/modules/spawn-items.md +++ b/readme/extensions/modules/spawn-items.md @@ -26,12 +26,12 @@ _\* - если указано "-", то параметр является обя "Items": [ { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_deagle", "GiveType": "Replace" }, { - "Type": "Weapon", + "Item": "Weapon", "Name": "weapon_hegrenade", "GiveType": "Add" } diff --git a/readme/extensions/modules/weapon-menu.md b/readme/extensions/modules/weapon-menu.md index d91d87d..54b5394 100644 --- a/readme/extensions/modules/weapon-menu.md +++ b/readme/extensions/modules/weapon-menu.md @@ -11,12 +11,13 @@ _Данный модуль использует [контроллер предм | MainMenuTitle | Нет | Строка | Загловок главного меню. По умолчанию будет `MENU_MAIN_TITLE` из ланг-файла | | Menus | Да | [Массив обьектов меню](#поля-обьекта-меню) | Обьекты доступных меню. Поддерживает ссылки. | | Count | Нет | Ц.Число | Сколько предметов за раунд можно взять из всех меню. По умолчанию неограничено | +| ResetCountOnSpawn | Нет | `true`/`false` | Сбрасывать ли счётчик предметов при спавне, иначе в начале раунда. По умолчанию `false` | | Limits | Нет | Массив [лимитов](/readme/extensions/limits.md) | Условия, при которых меню будет доступно | | | | | | | AutoopenLimits | Нет | Массив [лимитов](/readme/extensions/limits.md) | Условия, при которых будет срабатывать автоматическое открытие меню | -| AutoopenDelay | Нет | Д.Число | Задержка перед автоматическим открытием меню в секундах. По умолчанию `0.0` | +| AutoopenDelay | Нет | Д.Число | Задержка перед автоматическим открытием меню в секундах. По умолчанию `0.0` | | AutoopenCloseDelay | Нет | Д.Число | Время перед автоматическим закрытием после автоматического открытия меню в секундах | -| AutoopenMenuNum | Нет | Ц.Число | Порядковый номер оружейного меню из параметра `Menus`, которое будет открыто при автоматическом открытии. Если | +| AutoopenMenuNum | Нет | Ц.Число | Порядковый номер оружейного меню из параметра `Menus`, которое будет открыто при автоматическом открытии. Если | | | | | | | StayOpen | Нет | `true`/`false` | Оставлять ли оружейное меню открытым после выбора пункта. По умолчанию `false` | | StayOpen_CheckCounter | Нет | `true`/`false` | Проверять ли остаток предметов при повторном открытии оружейного меню при `StayOpen: true`. По умолчанию `false` | diff --git a/readme/json.md b/readme/json.md deleted file mode 100644 index 18a0a2b..0000000 --- a/readme/json.md +++ /dev/null @@ -1,96 +0,0 @@ -# Памятка по формату JSON - -Ниже приведена некоторая информация про JSON, которая поможет при настройке системы привилегий и не только. - -## Типы данных - -JSON поддерживает следующие типы данных: - -- Числа (целые и дробные) - `123` или `1.23`; -- Строки - `"qwe"`; -- Булевые - `true`/`false`; -- Массивы - `[1, 2]`, могут содержать в себе значения любого типа разделённые запятой; -- Обьекты - `{"k1": "v1", "k2": 2}`, могут содержать в себе пары типа ключ:значение, где ключ - строка, а значение может быть любого типа. - -Примеры: - -```jsonc -{ - "Строка": "qwe", - "Целое число": 123, - "Дробное число": 1.23, - "Булево значение": false, - "Массив": [ - "ewq", - 321, - { - "Булево значение 2": true - } - ], - "Обьект": { - "Строка 2": "rty", - "Целое число 2": 456 - } -} -``` - -_Примечание: периодически возникают ошибки из-за лишних или недостающих скобок у обьектов и массивов, следите за тем, чтобы все открытые скобки были закрыты._ - -_Примечание: Значения типа `123` и `"123"` не являются взаимозаменяемыми, то есть, если ожидается числовое значение, то при указании второго варианта может возникнуть непредвиденная ошибка. Подобные ситуации могут обрабатываться на уровне кода, но в любом случае лучше использовать типы правильно._ - -## Запятые - -**Очень важно!** - -Формат JSON очень чувствителен к запятым. Их не должно быть там, где они не нужны, и они обязательно должны быть там, где они нужны. - -Где запятые **нужны**: - -- Между элементами массивов `[1, 2]` -- Между парами ключ:значение в обьектах `{"k1": 1, "k2": "v2"}` - -Где запятые **не нужны**: - -- После последнего элемента массива `[1, 2,]` -- После последней пары ключ:значение в обьекте `{"k1": 1, "k2": "v2",}` - -## Отступы и пробелы - -Формат JSON абсолютно не чувствителен к отступам, пробелам и пустым строкам. - -```jsonc -// Пример 1: -{ - "key1": "value 1", - "Key2": true, - - "key3": 321 -} - -// Пример 2: -{"key1":"value 1","Key2":true,"key3":321} -``` - -Оба примера спарсятся абсолютно одинаково. Разница лишь в том, что первый пример более удобен для восприятия человеком. - -Хоть сам формат JSON не чувствителен к отсупам, но очень желательно соблюдать отступы для вложенных значений, так как это - -Единственное место, где JSON учитывает пробелы - внутри строковых значений. - -## Инструменты - -Ниже приведены некоторые инструменты, которые позволят найти или не допустить ошибок при работе с JSON. - -### Visual Studio Code - -[Скачать](https://code.visualstudio.com/) - -Бесплатный мощный текстовый редактор, предназначенный для редактирования кода. Из коробки имеет поддержку многих языков, в том числе JSON. - -В ходе редактирования JSON-файла будет подсвечивать допущенные синтаксические ошибки, а также, при нажатии сочетания Shift+Alt+F может отформатировать файл, исправив в нём отступы. - -### JSONLint - -[Открыть](https://jsonlint.com/) - -Если нет желания скачивать VSCode, можно проверять JSON-файл на наличие синтаксических ошибок при помощи этого сайта. Также, сайт может помочь исправить отступы. diff --git a/readme/thirdparty-extensions.md b/readme/thirdparty-extensions.md index 761b042..24de0e3 100644 --- a/readme/thirdparty-extensions.md +++ b/readme/thirdparty-extensions.md @@ -12,30 +12,8 @@ ## Ограничения -- [VipTest](https://github.com/AmxxModularEcosystem/VipM-L-VipTest) - Позволяет игрокам временно получить доступ к привилегиям. -- [RWW-InProgress](https://github.com/AmxxModularEcosystem/VipM-L-RandomWeaponsWarmUP) - Добавляет условие, которое верно во время разминки из плагина [Random Weapons WarmUP](https://github.com/ArKaNeMaN/amxx-RandomWeaponsWarmUP). -- [SnipersRBS-CanTakeAwp](https://github.com/AmxxModularEcosystem/VipM-L-SnipersRBS) - Интеграция с [Snipers RBS](https://fungun.net/shop/?p=show&id=48) от SKAJIbnEJIb. Добавляет условие, которое верно только тогда, когда игрок может взять АВП. -- [GCMS-Service & GCMS-Member](https://github.com/AmxxModularEcosystem/VipM-L-GameCMS) - Интеграция с [GameCMS API](https://cs-games.club/index.php?resources/gamecms-api.4/) от [zhorzh78](https://dev-cs.ru/members/326/). -- [AWPLimiter-CanTakeAwp](https://gist.github.com/ArKaNeMaN/db60225785d7e5bac1a73bf7a8466ab2) - Интеграция с [AWP Limiter](https://github.com/Nord1cWarr1or/AWP-Limiter) от [Nordic Warrior](https://dev-cs.ru/members/3093/). -- [MMM-VoteStarted](https://gist.github.com/ArKaNeMaN/a5607b74e991646fb0754e7dd8ba3a0c) - Интеграция с [MapManager Modular](https://github.com/Mistrick/MapManagerModular) от [Mistrick](https://dev-cs.ru/members/76/). -- [AwpOFF-Restricted](https://gist.github.com/ArKaNeMaN/f3c53992b0f041a647068d74b63aeb54) - Интеграция с [Awp OFF](https://dev-cs.ru/resources/225/) от [paffgame](https://dev-cs.ru/members/124/). -- [Radius-AwpRestricted](https://gist.github.com/ArKaNeMaN/42c7201e1bb19e2d2e3a72782c695f7b) - Интеграция с [AWP Restrictions](https://goldsrc.ru/resources/137/) от Radius. +Список переехал в [раздел WIKI](/wiki/Доступные-лимиты#сторонние-лимиты) ## Типы предметов -- Системы кастомного оружия: - - [Cwapi](https://github.com/AmxxModularEcosystem/IC-I-Cwapi) - Кастомное оружие из плагина [Custom Weapons API](https://github.com/AmxxModularEcosystem/CustomWeaponsAPI). - - [AUW-Weapon](https://github.com/AmxxModularEcosystem/VipM-I-AdvancedUltimateWeapons) - Позволяет выдавать кастомное оружие из плагина [Advanced Ultimate Weapons](https://dev-cs.ru/resources/945/) от [steelzzz](https://dev-cs.ru/members/19/). - - [UW-Weapon](https://gist.github.com/ArKaNeMaN/8720ae20f87245c0fe00d28c387065e0) - Интеграция с [Ultimate Weapons](https://fungun.net/shop/?p=show&id=82) от SKAJIbnEJIb. -- Различные реализации коктейля молотова: - - [BlackSignature-Molotov](https://github.com/ArKaNeMaN/VipM-I-BlackSignature-Molotov) - Позволяет выдавать [коктейль молотова](https://shorturl.at/jtzGZ) от [BlackSignature](https://dev-cs.ru/members/1111/). - - [Medusa-Molotov](https://gist.github.com/ArKaNeMaN/13bdfa31b2262c61b3adce9845c9e893) - Интеграция с [[GRENADE] Molotov](https://dev-cs.ru/resources/1160/) От [medusa](https://dev-cs.ru/members/65/). - - [WellAsGood-Molotov](https://gist.github.com/ArKaNeMaN/970685239663cb1b7a7791c0d2c55c6e) - Интеграция с [[Reapi] Molotov](https://dev-cs.ru/resources/1166/) От [wellasgood](https://dev-cs.ru/members/1657/). -- Кастомное оружие от CHEL74 (плагины-расширения поставляются в архиве после покупки): - - [Artifact](https://dev-cs.ru/threads/43339/) - Артефакт из S.T.A.L.K.E.R. - - [GaussRifle](https://dev-cs.ru/threads/42873/) - Гаусс пушка из S.T.A.L.K.E.R. - - [BananaBomb](https://dev-cs.ru/threads/30559/) - Banana Bomb - - [DecoyGrenade](https://github.com/AmxxModularEcosystem/VipM-I-Chel74Nades) - Ложная граната - - [HolyGrenade](https://dev-cs.ru/threads/35089/) - Holy Grenade -- [HealthNade](https://github.com/AmxxModularEcosystem/VipM-I-HealthNade) - Позволяет выдавать лечащую гранату из плагина [[fork] Healthnade](https://dev-cs.ru/resources/1271/) от [BlackSignature](https://dev-cs.ru/members/1111/). -- [ACS-Injection](https://gist.github.com/ArKaNeMaN/14d46548bbdbc7dacec5425e20315abd) - Интеграция с [[ACS] INJECTION](https://dev-cs.ru/resources/1582/) от [Refresh](https://dev-cs.ru/members/10396/). +Список переехал в [раздел WIKI](/wiki/Доступные-типы-предметов#сторонние-типы)