// *************************************************************************************//
// Плагин загружен с www.neugomon.ru //
// Автор: Neygomon [ https://neugomon.ru/members/1/ ] //
// Официальная тема поддержки: https://neugomon.ru/threads/2648/ //
// При копировании материала ссылка на сайт www.neugomon.ru ОБЯЗАТЕЛЬНА! //
// *************************************************************************************//
* AES: Bonus System v. 0.5
* by serfreeman1337 http://gf.hldm.org/
// мы передали тебе массив в массив
// чтобы ты мог работать с массивом пока работаешь с массивом
enum _:menuFieldsStruct {
// Мастер массивов 80 лвл
new Array:g_SpawnBonusItems
new Array:g_PointsBonusItems
new Trie:g_MenuCommandsValid
new bool:isLocked,iaNewForward
new bool:player_already_spawned[MAX_PLAYERS + 1]
new Float:player_spawn_time[MAX_PLAYERS + 1]
new itemName[128],itemInfo[10]
register_plugin(PLUGIN, VERSION, AUTHOR)
// Вкл/выкл системы бонусов
cvar[CVAR_BONUS_ENABLED] = register_cvar("aes_bonus_enable","1",FCVAR_SERVER)
// Выдача бонусов на спавне
// 0 - нет бонусов на спавне
// 2 - выдать только один раз за раунд
cvar[CVAR_BONUS_SPAWN] = register_cvar("aes_bonus_spawn","1")
register_srvcmd("aes_lockmap","Check_LockMap")
register_dictionary("aes.txt")
iaNewForward = CreateMultiForward("aes_on_anew_command",ET_STOP,FP_CELL)
RegisterHam(Ham_Spawn,"player","On_Player_Spawn",true)
items_CB = menu_makecallback("Format_ItemsCallback")
len += get_configsdir(fPath,charsmax(fPath))
len += formatex(fPath[len],charsmax(fPath) - len,"/aes/bonus.ini",fPath)
// читаем файл конфигурации
log_amx("[ERROR] configuration file not found")
set_fail_state("configuration file not found")
new buffer[1024],cfgBlock = -1,itemType,key[32],value[sizeof buffer - sizeof key],keyId,line
new itemData[itemFieldsStruct],menuData[menuFieldsStruct]
// карта ключей параметров
new Trie:keyMap = TrieCreate()
TrieSetCell(keyMap,"name",KEY_NAME)
TrieSetCell(keyMap,"levels",KEY_LEVELMAP)
TrieSetCell(keyMap,"item",KEY_ITEM)
TrieSetCell(keyMap,"plugin",KEY_PLUGIN)
TrieSetCell(keyMap,"function",KEY_FUNCTION)
TrieSetCell(keyMap,"points",KEY_POINTS)
TrieSetCell(keyMap,"chance",KEY_CHANCE)
TrieSetCell(keyMap,"sumlevels",KEY_SUMLEVELS)
TrieSetCell(keyMap,"title",KEY_MENU_TITLE)
TrieSetCell(keyMap,"say",KEY_MENU_SAY)
TrieSetCell(keyMap,"console",KEY_MENU_CONSOLE)
TrieSetCell(keyMap,"list",KEY_MENU_ITEMS)
TrieSetCell(keyMap,"exp",KEY_EXP)
TrieSetCell(keyMap,"level",KEY_LEVEL)
TrieSetCell(keyMap,"round",KEY_ROUND)
TrieSetCell(keyMap,"time",KEY_TIME)
TrieSetCell(keyMap,"flags",KEY_FLAGS)
TrieSetCell(keyMap,"days",KEY_DAYS)
// Я НИХУЯ НЕ ПОНИМАЮ ЧТО Я ТУТ НАПИСАЛ
// читаем содержимое файла конфигурации
fgets(f,buffer,charsmax(buffer))
if(!buffer[0] || buffer[0] == ';')
if(buffer[0] == '['){ // проверяем какой блок конфигурации сейчас читаем
case BONUS_ITEM_SPAWN,BONUS_ITEM_MENU:
if(RegisterBonusItem(itemData,cfgBlock,line))
arrayset(itemData,0,itemFieldsStruct)
if(RegisterMenuItem(menuData,line) >= 0)
arrayset(menuData,0,menuFieldsStruct)
if(strcmp(buffer,"[spawn]") == 0) // бонусы на спавне
cfgBlock = BONUS_ITEM_SPAWN
else if(strcmp(buffer,"[items]") == 0) // бонусы в меню
cfgBlock = BONUS_ITEM_MENU
else if(strcmp(buffer,"[menu]") == 0) // менюшки
if(buffer[0] == '<'){ // новый бонус
if(cfgBlock != BONUS_MENUS){
if(RegisterBonusItem(itemData,cfgBlock,line))
arrayset(itemData,0,itemFieldsStruct)
if(strcmp(buffer,"<give>") == 0) // узнаем тип бонуса
else if(strcmp(buffer,"<call>") == 0)
itemData[IB_TYPE] = itemType
if(RegisterMenuItem(menuData,line) >= 0)
arrayset(menuData,0,menuFieldsStruct)
if(strcmp(buffer,"<menu>") == 0)
strtok2(buffer,key,charsmax(key),value,charsmax(value),'=',TRIM_FULL)
strtok(buffer,key,charsmax(key),value,charsmax(value),'=',1)
replace(value,charsmax(value),"= ","")
if(!TrieGetCell(keyMap,key,keyId) || (cfgBlock == BONUS_MENUS && keyId < KEY_MENU_TITLE)){ // узнаем ID ключа
log_amx("[WARNING] unknown key ^"%s^" on line %d",
// парсинг значений ключей
case KEY_NAME: copy(itemData[IB_NAME],charsmax(itemData[IB_NAME]),value)
case KEY_LEVELMAP: itemData[IB_LEVELS] = _:parse_levels(value)
// предмет для конструкции <give>
case KEY_ITEM: copy(itemData[IB_ITEM],charsmax(itemData[IB_ITEM]),value)
case KEY_CHANCE: itemData[IB_CHANCE] = _:parse_levels(value)
// id плагина для конструкции <call>
itemData[IB_PLUGIN_ID] = find_plugin_byfile(value)
if(itemData[IB_PLUGIN_ID] == INVALID_PLUGIN_ID){
log_amx("[ERROR] can't find plugin ^"%s^" on line %d",value,line)
// убираем этот бонус из меню
// id функции для конструкции <call>
if(itemData[IB_PLUGIN_ID] == -1){ // плагин не найден
log_amx("[ERROR] plugin not found on line %d",line)
itemData[IB_FUNCTION_ID] = get_func_id(value,itemData[IB_PLUGIN_ID])
if(itemData[IB_FUNCTION_ID] == -1){ // проверка на валидность функции
log_amx("[ERROR] can't find function ^"%s^" on line %d",value,line)
// кол-во очков для этого бонуса в меню
case KEY_POINTS: itemData[IB_POINTS] = str_to_num(value)
// сумирование шанса за все уровни
case KEY_SUMLEVELS: itemData[IB_SUMCHANCE] = str_to_num(value) ? false : true
case KEY_MENU_TITLE: copy(menuData[MENU_TITLE],charsmax(menuData[MENU_TITLE]),value)
// команда в чат для вызова меню
case KEY_MENU_SAY: copy(menuData[MENU_SAYCMD],charsmax(menuData[MENU_SAYCMD]),value)
// команда в консоли для вызова этого меню
case KEY_MENU_CONSOLE: copy(menuData[MENU_CONCMD],charsmax(menuData[MENU_CONCMD]),value)
// список предметов в меню
case KEY_MENU_ITEMS: menuData[MENU_LIST] = _:parse_levels(value)
case KEY_EXP: itemData[IB_EXP] = _:str_to_float(value)
case KEY_LEVEL: itemData[IB_LEVEL] = str_to_num(value)
case KEY_ROUND: itemData[IB_ROUND] = str_to_num(value)
case KEY_TIME: itemData[IB_TIME] = _:str_to_float(value)
case KEY_FLAGS: copy(itemData[IB_FLAGS], charsmax(itemData[IB_FLAGS]), value);
case KEY_DAYS: itemData[IB_DAYS] = str_to_num(value);
switch(cfgBlock){ // разбираем последний предмет, если есть
case BONUS_ITEM_SPAWN,BONUS_ITEM_MENU:
if(RegisterBonusItem(itemData,cfgBlock,line))
arrayset(itemData,0,itemFieldsStruct)
if(RegisterMenuItem(menuData,line) >= 0)
arrayset(menuData,0,menuFieldsStruct)
g_SpawnBonusCount = ArraySize(g_SpawnBonusItems)
g_PointsBonusCount = ArraySize(g_PointsBonusItems)
// регистрация бонус менюшек
for(new i,length = ArraySize(g_BonusMenus) ; i < length ; i++){
ArrayGetArray(g_BonusMenus,i,menuData)
if(menuData[MENU_SAYCMD][0]){
if(!TrieKeyExists(callCmds,menuData[MENU_SAYCMD])){
formatex(sayCmd,charsmax(sayCmd),"say %s",menuData[MENU_SAYCMD])
register_clcmd(sayCmd,"Forward_CallCommand")
TrieSetCell(callCmds,menuData[MENU_SAYCMD],i)
log_amx("WARNING! ^"%s^" say command already in use on line %d!",menuData[MENU_CONCMD],line)
if(menuData[MENU_CONCMD][0]){
if(!TrieKeyExists(callCmds,menuData[MENU_CONCMD])){
register_clcmd(menuData[MENU_CONCMD],"Forward_CallCommand")
TrieSetCell(callCmds,menuData[MENU_CONCMD],i)
log_amx("WARNING ^"%s^" console command already in use on line %d!",menuData[MENU_CONCMD],line)
}else{ // дефолтное меню /anew
register_clcmd("say /anew","Forward_CallCommand")
register_clcmd("anew","Forward_CallCommand")
if(get_pcvar_num(cvar[CVAR_BONUS_SPAWN]) == 2)
register_logevent("ResetSpawn",2,"1=Round_End")
register_logevent("RoundStart",2,"0=World triggered","1=Round_Start")
register_logevent("RoundRestart",2,"0=World triggered","1=Game_Commencing")
register_event("TextMsg","RoundRestart","a","2&#Game_will_restart_in")
read_args(getmap,charsmax(getmap))
get_mapname(map,charsmax(map))
set_pcvar_num(cvar[CVAR_BONUS_ENABLED],0)
public client_disconnected(id)
player_already_spawned[id] = false
// Обработчик консольных команд
public Forward_ConsoleCommand(id){
return Format_BonusMenu(id,-1)
read_argv(0,consoleCmd,127)
// проверяем что сообщение содержит команду и узнаем её ID
if(!TrieGetCell(g_MenuCommandsValid,consoleCmd,cmdId))
Format_BonusMenu(id,cmdId)
// Обработчик say комманд
public Forward_CallCommand(id){
return Format_BonusMenu(id,-1)
read_args(cmd,charsmax(cmd))
read_argv(0,cmd,charsmax(cmd))
if(!TrieGetCell(callCmds,cmd,cmdId))
Format_BonusMenu(id,cmdId)
// Форматирование менюшек
public Format_BonusMenu(id,cmdId){
if(isLocked){ // проверка возможности использования бонусов на этой карте
client_print_color(id,0,"%L %L",id,"AES_TAG",id,"AES_ANEW_BLOCKED")
new player_bonus = aes_get_player_bonus(id)
num_to_str(player_bonus,player_bonus_str,charsmax(player_bonus_str))
if(player_bonus <= 0){ // еще какая-то проверка
client_print_color(id,0,"%L %L",id,"AES_TAG",id,"AES_ANEW_NOT")
ExecuteForward(iaNewForward,ret,id)
if(ret == PLUGIN_HANDLED) // блок вызова в другом плагине
new m,itemData[itemFieldsStruct]
if(cmdId == -1){ // строим дефолтное меню anew со списком всех предметов
formatex(itemName,charsmax(itemName),"%L %L",id,"AES_TAG_MENU",id,"AES_BONUS_MENU",player_bonus)
m = menu_create(itemName,"aNew_MenuHandler")
for(new i ; i < g_PointsBonusCount ; i++){
ArrayGetArray(g_PointsBonusItems,i,itemData)
num_to_str(i,itemInfo,charsmax(itemInfo))
aes_get_item_name(itemData[IB_NAME],itemName,charsmax(itemName),id)
menu_additem(m,itemName,itemInfo,.callback = items_CB)
new menuData[menuFieldsStruct],itemIndex
ArrayGetArray(g_BonusMenus,cmdId,menuData)
new len = formatex(itemName,charsmax(itemName),"%L ",id,"AES_TAG_MENU")
len += aes_get_item_name(menuData[MENU_TITLE],itemName[len],charsmax(itemName) - len,id)
replace_all(itemName,charsmax(itemName),"\n","^n")
replace_all(itemName,charsmax(itemName),"<p>",player_bonus_str)
m = menu_create(itemName,"aNew_MenuHandler")
for(new i,length = ArraySize(menuData[MENU_LIST]) ; i < length ; i++){
itemIndex = ArrayGetCell(menuData[MENU_LIST],i) - 1
if(!(0 <=itemIndex < g_PointsBonusCount)) // что ты мне подсунул, блеать
ArrayGetArray(g_PointsBonusItems,i,itemData)
num_to_str(i,itemInfo,charsmax(itemInfo))
aes_get_item_name(itemData[IB_NAME],itemName,charsmax(itemName),id)
menu_additem(m,itemName,itemInfo,.callback = items_CB)
F_Format_NavButtons(id,m)
public Format_ItemsCallback(id,menu,item)
new info[10],item_name[256],dummy
menu_item_getinfo(menu,item,dummy,info,charsmax(info),item_name,charsmax(item_name),dummy)
new itemData[itemFieldsStruct]
ArrayGetArray(g_PointsBonusItems,str_to_num(info),itemData)
new limit_fields = Bonus_CheckLimits(id,itemData)
for(new i = 1; i <= 5 ; i++)
if(limit_fields & (1<<i))
new tmpLang[128],lang_key[16]
formatex(lang_key,charsmax(lang_key),"AES_ANEW_INFO%d",i)
formatex(tmpLang,charsmax(tmpLang)," %L",id,lang_key,itemData[IB_POINTS + (i - 1)])
add(item_name,charsmax(item_name),tmpLang)
menu_item_setname(menu,item,item_name)
// Проверяем ограничения на бонусы
Bonus_CheckLimits(id,itemData[itemFieldsStruct])
// проверяем доступность по бонусам
new player_bonus = aes_get_player_bonus(id)
if(itemData[IB_POINTS] > player_bonus)
limit_fields |= LIMIT_POINTS
// проверяем доступность по обыту
new Float:player_exp = aes_get_player_exp(id)
if(itemData[IB_EXP] > player_exp)
limit_fields |= LIMIT_EXP
// проверяем доступность по уровню
new player_level = aes_get_player_level(id) + 1
if(itemData[IB_LEVEL] > player_level)
limit_fields |= LIMIT_LEVEL
// проверяем доступность по раунду
if(itemData[IB_ROUND] > iRound)
limit_fields |= LIMIT_ROUND
// проверяем на доступность по времени
if(itemData[IB_TIME] < (get_gametime() - player_spawn_time[id]))
limit_fields |= LIMIT_TIME
public F_Format_NavButtons(id,menu){
formatex(tmpLang,charsmax(tmpLang),"%L",id,"BACK")
menu_setprop(menu,MPROP_BACKNAME,tmpLang)
formatex(tmpLang,charsmax(tmpLang),"%L",id,"EXIT")
menu_setprop(menu,MPROP_EXITNAME,tmpLang)
formatex(tmpLang,charsmax(tmpLang),"%L",id,"MORE")
menu_setprop(menu,MPROP_NEXTNAME,tmpLang)
public aNew_MenuHandler(id,m,item){
if(Format_ItemsCallback(id,m,item) != ITEM_ENABLED)
menu_item_getinfo(m,item,itemName[0],itemInfo,charsmax(itemInfo),itemName,1,itemName[0])
new itemKey = str_to_num(itemInfo)
new itemData[itemFieldsStruct]
ArrayGetArray(g_PointsBonusItems,itemKey,itemData)
if(GiveBonus(itemData,id))
aes_add_player_bonus_f(id,-itemData[IB_POINTS])
aes_get_item_name(itemData[IB_NAME],itemName,charsmax(itemName),id)
strip_menu_codes(itemName,charsmax(itemName))
client_print_color(id,0,"%L %L",id,"AES_TAG",id,"AES_ANEW_GIVE",itemName,itemData[IB_POINTS])
// Назначение бонус предметов
// itemData- данные бонуса
// count - кол-во бонусов
// psh - пшш парень, значение в функцию передать не хочешь?
GiveBonus(itemData[itemFieldsStruct],id,count = 1,psh = 0){
switch(itemData[IB_TYPE])
for(new i ; i < count ; i++)
if(!give_item(id,itemData[IB_ITEM]))
client_print_color(id,print_team_default,"%L %L",id,"AES_TAG",id,"AES_ANEW_CALL_PROBLEM")
if(callfunc_begin_i(itemData[IB_FUNCTION_ID],itemData[IB_PLUGIN_ID]))
if(itemData[IB_FLAGS][0])
callfunc_push_str(itemData[IB_FLAGS]);
callfunc_push_int(itemData[IB_DAYS]);
else callfunc_push_int(count);
client_print_color(id,print_team_default,"%L %L",id,"AES_TAG",id,"AES_ANEW_CALL_PROBLEM")
// Очищение строки от символов меню
strip_menu_codes(itemName[],len)
replace_all(itemName,len,"\r","")
replace_all(itemName,len,"\y","")
replace_all(itemName,len,"\R","")
replace_all(itemName,len,"\w","")
// Выдача бонусов на спавнеы
public On_Player_Spawn(id)
if(isLocked || !get_pcvar_num(cvar[CVAR_BONUS_ENABLED]) || !is_user_alive(id))
player_spawn_time[id] = get_gametime()
new player_level = aes_get_player_level(id)
switch(get_pcvar_num(cvar[CVAR_BONUS_SPAWN]))
case 0: return HAM_IGNORED
case 2: // запоминаем спавн игрока
if(player_already_spawned[id])
player_already_spawned[id] = true
new itemData[itemFieldsStruct],actLevel = -1
new Array:assigned_bonuses
// проверяем бонусы на спавне
for(new i;i < g_SpawnBonusCount ; ++i)
arrayset(itemData,0,itemFieldsStruct)
ArrayGetArray(g_SpawnBonusItems,i,itemData)
if(Bonus_CheckLimits(id,itemData))
// считаем шанс выдачи бонуса
if(player_level >= ArraySize(itemData[IB_CHANCE])) // :D
actLevel = ArraySize(itemData[IB_CHANCE]) - 1
if(itemData[IB_SUMCHANCE]){
for(new z ; z <= actLevel ; z++) // складываем общий шанс за все уровни
chanceValue += ArrayGetCell(itemData[IB_CHANCE],i)
chanceValue = ArrayGetCell(itemData[IB_CHANCE],actLevel)
// проверяем что это наш шанс
if(chanceValue * 10 < random_num(0,1000))
continue // извини братюнь, в другой раз
// узнаем значение бонуса для определенного уровня
if(player_level >= ArraySize(itemData[IB_LEVELS])) // :D
actLevel = ArraySize(itemData[IB_LEVELS]) - 1
if(itemData[IB_SUMCHANCE])
for(new i ; i <= actLevel ; i++) // складываем значения за все уровни
levelValue += ArrayGetCell(itemData[IB_LEVELS],i)
levelValue = ArrayGetCell(itemData[IB_LEVELS],actLevel)
if(GiveBonus(itemData,id,levelValue))
assigned_bonuses = ArrayCreate(sizeof itemData[IB_NAME])
ArrayPushString(assigned_bonuses,itemData[IB_NAME])
len = formatex(bonus_info,charsmax(bonus_info),"%L %L ",id,"AES_TAG",
for(new i,length = ArraySize(assigned_bonuses) ; i < length ; i++)
ArrayGetString(assigned_bonuses,i,itemData[IB_NAME],charsmax(itemData[IB_NAME]))
len += formatex(bonus_info[len],charsmax(bonus_info) - len,", ")
len += formatex(bonus_info[len],charsmax(bonus_info) - len,"^4")
len += aes_get_item_name(itemData[IB_NAME],bonus_info[len],charsmax(bonus_info) - len,id)
len += formatex(bonus_info[len],charsmax(bonus_info) - len,"^1")
ArrayDestroy(assigned_bonuses)
client_print_color(id,print_team_default,bonus_info)
public Array:parse_levels(levelString[]){
new Array:which = ArrayCreate(1)
new stPos,ePos,rawPoint[20]
ePos = strfind(levelString[stPos]," ")
formatex(rawPoint,ePos,levelString[stPos])
ArrayPushCell(which,str_to_num(rawPoint))
public aes_get_item_name(itemString[],out[],len,id)
if(strfind(itemString,"LANG_") == 0)// формирование по словарю
replace(itemString,strlen(itemString),"LANG_","")
l = formatex(out,len,"%L",id,itemString)
l = copy(out,len,itemString)
// Регистрация бонус предмета
// cfgBlock - конфигурационный блок
public RegisterBonusItem(itemData[itemFieldsStruct],cfgBlock,line){
if(itemData[IB_TYPE]){ // записываем параметры предедущего бонуса
// проверки на валидность
switch(itemData[IB_TYPE]){
if(!itemData[IB_ITEM][0]){
log_amx("[ERROR] give item not set on line %d",line)
g_SpawnBonusItems = ArrayCreate(itemFieldsStruct)
itemArray = g_SpawnBonusItems
g_PointsBonusItems = ArrayCreate(itemFieldsStruct)
itemArray = g_PointsBonusItems
ArrayPushArray(itemArray,itemData)
public RegisterMenuItem(menuData[menuFieldsStruct],line){
if(!menuData[MENU_SAYCMD][0] && !menuData[MENU_CONCMD][0])
g_BonusMenus = ArrayCreate(menuFieldsStruct)
ArrayPushArray(g_BonusMenus,menuData)
return ArraySize(g_BonusMenus) - 1
arrayset(player_already_spawned,false,sizeof player_already_spawned)
arrayset(_:player_spawn_time,0,sizeof player_spawn_time)