Помощь и советы новичку :)

Сообщения
21
Реакции
1
Здравствуйте, уважаемые пользователи Dev-cs.ru
Хотел бы задавать несколько вопрос и получить совет от опытных скриптеров.
На данный момент практикуюсь в PAWN и есть первый плагин, но с небольшими недоработками.

C++:
#include <amxmodx>
#include <reapi>

new g_BlockRoundWeapon;

public plugin_init()
{
    register_plugin("[CSP] Vip Menu", "0.1", "Jony");
    register_clcmd("say /vipmenu", "ClCmd_VipMenu", ADMIN_LEVEL_H);
    RegisterHookChain(RG_CSGameRules_RestartRound, "RG_CSGameRules_RestartRound_Post", 1);
}

public RG_CSGameRules_RestartRound_Post(id)
{
    g_BlockRoundWeapon++;
}

public ClCmd_VipMenu(id, flags)
{
    if(get_user_flags(id) & flags)
    {
        show_menuvip(id);
        return PLUGIN_HANDLED;
    }
    
    client_print_color(id, print_team_default, "^4[CSP] ^3У вас нет доступа к этому меню");
    return PLUGIN_HANDLED;
}

show_menuvip(id)
{
    new V_Menu = menu_create("\y[CSP]\wВип меню", "vip_menu");
    if(g_BlockRoundWeapon < 3)
    {
        menu_additem(V_Menu, "\dВзять M4A1", "1", ADMIN_LEVEL_H);
    }
    else
    {
        menu_additem(V_Menu, "Взять M4A1", "1", ADMIN_LEVEL_H);
    }
    
    if(g_BlockRoundWeapon < 3)
    {
        menu_additem(V_Menu, "\dВзять АК47", "2", ADMIN_LEVEL_H);
    }
    else
    {
        menu_additem(V_Menu, "Взять АК47", "2", ADMIN_LEVEL_H);
    }
    
    if(g_BlockRoundWeapon < 3)
    {
        menu_additem(V_Menu, "\dВзять AWP", "3", ADMIN_LEVEL_H);
    }
    else
    {
        menu_additem(V_Menu, "Взять AWP", "3", ADMIN_LEVEL_H);
    }
    
    menu_setprop(V_Menu, MPROP_EXITNAME, "Выход");
    menu_display(id, V_Menu, 0)
}

public vip_menu(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }
    
    if(!is_user_connected(id))
    {
        return PLUGIN_HANDLED;
    }
    
    new info[64], name[64], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback)
    
    new key = str_to_num(info);
    switch(key)
    {
        case 1:
        {
            if(g_BlockRoundWeapon <= 3)
            {
                client_print_color(id, print_team_default, "^4[CSP] ^3Оружие можно взять только после 3 раунда!");
                menu_destroy(menu);
                return PLUGIN_HANDLED;
            }
            
            rg_give_item(id, "weapon_m4a1", GT_DROP_AND_REPLACE);
            rg_set_user_bpammo(id, WEAPON_M4A1, 90);
            client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4М4А1");
            menu_destroy(menu);
            return PLUGIN_HANDLED;
        }
        case 2:
        {
            if(g_BlockRoundWeapon <= 3)
            {
                client_print_color(id, print_team_default, "^4[CSP] ^3Оружие можно взять только после 3 раунда!");
                menu_destroy(menu);
                return PLUGIN_HANDLED;
            }
            
            rg_give_item(id, "weapon_ak47", GT_DROP_AND_REPLACE);
            rg_set_user_bpammo(id, WEAPON_AK47, 90);
            client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4АК47");
            menu_destroy(menu);
            return PLUGIN_HANDLED;
        }
        case 3:
        {
            if(g_BlockRoundWeapon <= 3)
            {
                client_print_color(id, print_team_default, "^4[CSP] ^3Оружие можно взять только после 3 раунда!");
                menu_destroy(menu);
                return PLUGIN_HANDLED;
            }
            
            rg_give_item(id, "weapon_awp", GT_DROP_AND_REPLACE);
            rg_set_user_bpammo(id, WEAPON_AWP, 90);
            client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4AWP");
            menu_destroy(menu);
            return PLUGIN_HANDLED;
        }
    }
    menu_destroy(menu);
    return PLUGIN_HANDLED;
}
Вопрос по блокировки взятия оружия
Есть отлов начала раунда, а как обнулить переменную если например произошел рестарт.
C++:
new g_BlockRoundWeapon;
RegisterHookChain(RG_CSGameRules_RestartRound, "RG_CSGameRules_RestartRound_Post", 1);
public RG_CSGameRules_RestartRound_Post(id)
{
    g_BlockRoundWeapon++;
}
Вопрос по if/else
Можно ли опускать else в условном выражении ?

Вопрос по menu_destroy
Обязательно ли выполнять его если выполнена какая-та задача в меню ?
 
Сообщения
1,275
Реакции
2,257
Помог
57 раз(а)
MurJonyBoy, рестарт/гк распознаётся по гейм-мемберу m_bCompleteReset

В данном случае if/else можно заменить на menu_makecallback() + возврат ITEM_DISABLED / ITEM_IGNORE от условия.

По поводу menu_destroy()
Код:
 * This must be called if you create menus dynamically, otherwise you will 
 * leak memory.  For normal dynamic menus, you will destroy the menu in the 
 * handler function (remembering to handle the case of a menu being cancelled, 
 * it must still be destroyed).
 
Сообщения
594
Реакции
350
Предупреждения
1
Помог
9 раз(а)
RG_CSGameRules_RestartRound_Post(id)
->
RG_CSGameRules_RestartRound_Post()
 
Сообщения
21
Реакции
1
BlackSignature, Не могу понять как работать с menu_makecallback

C++:
Получается создается глобальная переменная ?
new g_WeapCallback
и в Plugin_init
g_WeapCallback = menu_makecallback(vip_menu);
и пятым аргументом написать эту переменную в меню ?
И if/else убрать в меню ?
 
Сообщения
21
Реакции
1
BlackSignature, Теперь все стало понятно. Спасибо за помощь :)
31 Дек 2018
BlackSignature,
Ну что-то вроде получилось из этого всего
Так и не понял как по m_bCompleteReset в member_game отловить рестарт
C++:
#include <amxmodx>
#include <reapi>

new g_BlockRoundWeapon;

public plugin_init()
{
    register_plugin("[CSP] Vip Menu", "0.1", "Jony");
    register_clcmd("say /vipmenu", "ClCmd_VipMenu", ADMIN_LEVEL_H);
    RegisterHookChain(RG_CSGameRules_RestartRound, "RG_CSGameRules_NewRound_Post", .post=true);
    register_event("TextMsg", "Event_NewGame", "a", "2=#Game_will_restart_in", "2=#Game_Commencing");
}

public RG_CSGameRules_NewRound_Post()
{
   g_BlockRoundWeapon++;
}

public Event_NewGame()
{
    g_BlockRoundWeapon = 0;
}

public ClCmd_VipMenu(id, flags)
{
    if(get_user_flags(id) & flags)
    {
        show_menuvip(id);
        return PLUGIN_HANDLED;
    }
    
    client_print_color(id, print_team_default, "^4[CSP] ^3У вас нет доступа к этому меню");
    return PLUGIN_HANDLED;
}

show_menuvip(id)
{
    new V_Menu = menu_create("\y[CSP]\wВип меню", "vip_menu");
    new WeapCallback = menu_makecallback("menucallback");

    menu_additem(V_Menu, "Взять M4A1", "1", ADMIN_LEVEL_H, WeapCallback);
    
    menu_additem(V_Menu, "Взять AK47", "2", ADMIN_LEVEL_H, WeapCallback);
    
    menu_additem(V_Menu, "Взять AWP", "3", ADMIN_LEVEL_H, WeapCallback);
    
    menu_setprop(V_Menu, MPROP_EXITNAME, "Выход");
    menu_display(id, V_Menu, 0)
}

public vip_menu(id, menu, item)
{
    if(item == MENU_EXIT)
    {
        menu_destroy(menu);
        return PLUGIN_HANDLED;
    }
    
    if(!is_user_connected(id))
    {
        return PLUGIN_HANDLED;
    }
    
    new info[64], name[64], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback)
    
    new key = str_to_num(info);
    switch(key)
    {
        case 1:
        {   
            rg_give_item(id, "weapon_m4a1", GT_DROP_AND_REPLACE);
            rg_set_user_bpammo(id, WEAPON_M4A1, 90);
            client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4М4А1");
            menu_destroy(menu);
            return PLUGIN_HANDLED;
        }
        case 2:
        {
            rg_give_item(id, "weapon_ak47", GT_DROP_AND_REPLACE);
            rg_set_user_bpammo(id, WEAPON_AK47, 90);
            client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4АК47");
            menu_destroy(menu);
            return PLUGIN_HANDLED;
        }
        case 3:
        {
            rg_give_item(id, "weapon_awp", GT_DROP_AND_REPLACE);
            rg_set_user_bpammo(id, WEAPON_AWP, 90);
            client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4AWP");
            menu_destroy(menu);
            return PLUGIN_HANDLED;
        }
    }
    menu_destroy(menu);
    return PLUGIN_HANDLED;
}

public menucallback(id, menu, item)
{   
    if(item < 0)
    {
        return PLUGIN_HANDLED;
    }
    
    new info[64], name[64], access, callback;
    menu_item_getinfo(menu, item, access, info, charsmax(info), name, charsmax(name), callback);
    
    switch(info[0])
    {
        case '1':
        {
            if(g_BlockRoundWeapon <= 3)
            {
                menu_item_setname(menu, item, "Недоступно");
                return ITEM_DISABLED;
            }
        }
        case '2':
        {
            if(g_BlockRoundWeapon <= 3)
            {
                menu_item_setname(menu, item, "Недоступно");
                return ITEM_DISABLED;
            }
        }
        case '3':
        {
            if(g_BlockRoundWeapon <= 3)
            {
                menu_item_setname(menu, item, "Недоступно");
                return ITEM_DISABLED;
            }
        }
    }
    return ITEM_IGNORE;
}
 
Сообщения
1,275
Реакции
2,257
Помог
57 раз(а)
MurJonyBoy,
Код:
public RG_CSGameRules_NewRound_Post()
{
	if(get_member_game(m_bCompleteReset) == true) {
		// some code
	}

	g_BlockRoundWeapon++;
}
31 Дек 2018
И зачем наплодили идентичного кода в каллбеке (да и не только в нём)?
 
Сообщения
21
Реакции
1
BlackSignature, аааа, можно ведь было записать case и по другом
преобразовать их в строку и сделать case 1..3
если я правильно понял
 

hajimura

Е777КХ05
Сообщения
290
Реакции
228
Помог
6 раз(а)
[BGCOLOR=transparent]MurJonyBoy, не надо показывать меню игроку, если не прошло более, чем 3 раунда:[/BGCOLOR]
Код:
public ClCmd_VipMenu(id, flags)
{
    if(get_user_flags(id) & flags && g_BlockRoundWeapon > 3)
    {
        show_menuvip(id);
        return PLUGIN_HANDLED;
    }
    client_print_color(id, print_team_default, "^4[CSP] ^3У вас нет доступа к этому меню");
    return PLUGIN_HANDLED;
}
А уже в функции show_menuvip выводишь нормально меню без лишнего:
Код:
menu_additem(V_Menu, "Взять M4A1", "1", ADMIN_LEVEL_H);
menu_additem(V_Menu, "Взять АК47", "2", ADMIN_LEVEL_H);
menu_additem(V_Menu, "Взять AWP", "3", ADMIN_LEVEL_H);
 
Сообщения
1,275
Реакции
2,257
Помог
57 раз(а)
MurJonyBoy,
Код:
#include <amxmodx>
#include <reapi>

const ACCESS_FLAG = ADMIN_LEVEL_H

enum _:MENU_ITEMS_ENUM {
	MENU_ITEM__M4A1,
	MENU_ITEM__AK47,
	MENU_UTEM__AWP
}

new const MENU_ITEMS[MENU_ITEMS_ENUM][] = {
	"Взять M4A1",
	"Взять AK47",
	"Взять AWP"
}

new const CHAT_NAMES[MENU_ITEMS_ENUM][] = {
	"M4A1",
	"AK47",
	"AWP"
}

new g_iCurrentRound

public plugin_init() {
	register_clcmd("say /vipmenu", "clcmd_OpenMenu")

	// Нужен Pre. в Post m_bCompleteReset уже будет равен false
	RegisterHookChain(RG_CSGameRules_RestartRound, "OnRestartRound_Pre")
}

public OnRestartRound_Pre() {
	if(get_member_game(m_bCompleteReset)) {
		g_iCurrentRound = 0
	}

	g_iCurrentRound++
}

public clcmd_OpenMenu(id) {
    if(get_user_flags(id) & ACCESS_FLAG) {
        return func_VipMenu(id)
    }

    client_print_color(id, print_team_default, "^4[CSP] ^3У вас нет доступа к этому меню")
    return PLUGIN_HANDLED
}

stock func_VipMenu(id) {
	new iMenu = menu_create("\y[CSP] \wВип меню", "func_VipMenu_Handler")
	new iMenuCallBack = menu_makecallback("func_VipMenu_CallBack")

	for(new i = MENU_ITEM__M4A1; i <= MENU_UTEM__AWP; i++) {
		menu_additem(iMenu, MENU_ITEMS[i], "", ACCESS_FLAG, iMenuCallBack)
	}

	menu_setprop(iMenu, MPROP_EXITNAME, "Выход")
	menu_display(id, iMenu, 0)
	return PLUGIN_HANDLED
}

public func_VipMenu_Handler(id, iMenu, iItem) {
	if(iItem < MENU_ITEM__M4A1 || !is_user_connected(id)) {
		menu_destroy(iMenu)
		return PLUGIN_HANDLED
	}

	new const szWeaponName[][] = { "weapon_m4a1", "weapon_ak47", "weapon_awp" }
	new const WeaponIdType:iWeaponID[] = { WEAPON_M4A1, WEAPON_AK47, WEAPON_AWP }
	new const iBpAmmo[] = { 90, 90, 30 }

	rg_give_item(id, szWeaponName[iItem], GT_DROP_AND_REPLACE)
	rg_set_user_bpammo(id, iWeaponID[iItem], iBpAmmo[iItem])

	client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4%s", CHAT_NAMES[iItem])

	menu_destroy(iMenu)
	return PLUGIN_HANDLED
}

public func_VipMenu_CallBack(id, iMenu, iItem) {
	if(g_iCurrentRound < 4) {
		menu_item_setname(iMenu, iItem, "Недоступно")
		return ITEM_DISABLED
	}

	return ITEM_IGNORE
}
31 Дек 2018
Или вообще без каллбека, да. Не показывать меню совсем, либо показывать меню с другим содержимым.
 
Сообщения
21
Реакции
1
@shadow,BlackSignature, stock func_VipMenu(id) Почему именно stock ? , а не public
31 Дек 2018
shadow, а если нужно показать меню с какими пунктами ?
 
Сообщения
584
Реакции
1,006
Помог
18 раз(а)
Сообщения
1,275
Реакции
2,257
Помог
57 раз(а)
MurJonyBoy, Mistrick имеет ввиду, что каллбек нужно создать всего один раз.

Объявлять func_VipMenu() как public нет нужды. Паблики у нас clcmd_OpenMenu() и func_VipMenu_Handler(), т.к. мы их имена передаём в ядро, и оно у нас должно иметь возможность с этими функциями связаться, когда произойдёт отлов. Т.е. они должны быть public. А вот func_VipMenu() у нас вызывается уже из clcmd_OpenMenu(), самим плагином, так сказать, "на своей территории".
Другими словами, всякие register_...cmd(), RegisterHookChain(), RegisterHam(), и т.п., а так же форварды событий, вроде client_putinserver() - их функции нужно публиковать, т.к. они вызываются "снаружи". А то что у нас крутится внутри, и вызова снаружи не подразумевает - то публиковать нет необходимости.

С учётом замечаний получается вот так. Но вообще лучше вовсе без каллбека обойтись. Просто не давать открывать меню если раунд не подходящий (+инфа) ну и в хендлере меню ту же самую проверку (можно глухую, т.е. без инфы). Либо же переделать логику на генерацию меню один раз, глобально, т.к. конкретно в этом случае генерация отдельного меню для каждого клиента никакого смысла не имеет. Ну вы и сами должны понимать, что это всего лишь пример по вашим условиям.

Код:
#include <amxmodx>
#include <reapi>

const MIN_ROUND = 3

const ACCESS_FLAG = ADMIN_LEVEL_H

enum _:MENU_ITEMS_ENUM {
	MENU_ITEM__M4A1,
	MENU_ITEM__AK47,
	MENU_UTEM__AWP
}

new const MENU_ITEMS[MENU_ITEMS_ENUM][] = {
	"Взять M4A1",
	"Взять AK47",
	"Взять AWP"
}

new const CHAT_NAMES[MENU_ITEMS_ENUM][] = {
	"M4A1",
	"AK47",
	"AWP"
}

new const WEAPON_NAMES[MENU_ITEMS_ENUM][] = {
	"weapon_m4a1",
	"weapon_ak47",
	"weapon_awp"
}

new const WEAPON_IDS[MENU_ITEMS_ENUM] = {
	any:WEAPON_M4A1,
	any:WEAPON_AK47,
	any:WEAPON_AWP
}

new const BP_AMMO[MENU_ITEMS_ENUM] = {
	90,
	90,
	30
}

new g_iMenuCallBack

public plugin_init() {
	register_clcmd("say /vipmenu", "clcmd_OpenMenu")

	g_iMenuCallBack = menu_makecallback("func_VipMenu_CallBack")
}

public clcmd_OpenMenu(id) {
    if(get_user_flags(id) & ACCESS_FLAG) {
        return func_VipMenu(id)
    }

    client_print_color(id, print_team_default, "^4[CSP] ^3У вас нет доступа к этому меню")
    return PLUGIN_HANDLED
}

stock func_VipMenu(id) {
	new iMenu = menu_create("\y[CSP] \wВип меню", "func_VipMenu_Handler")

	for(new i; i < MENU_ITEMS_ENUM; i++) {
		menu_additem(iMenu, MENU_ITEMS[i], "", ACCESS_FLAG, g_iMenuCallBack)
	}

	menu_setprop(iMenu, MPROP_EXITNAME, "Выход")
	menu_display(id, iMenu, 0)
	return PLUGIN_HANDLED
}

public func_VipMenu_Handler(id, iMenu, iItem) {
	menu_destroy(iMenu)

	if(iItem < 0 || !bIsAvailable() || !is_user_alive(id)) {
		return PLUGIN_HANDLED
	}

	rg_give_item(id, WEAPON_NAMES[iItem], GT_DROP_AND_REPLACE)
	rg_set_user_bpammo(id, WeaponIdType:WEAPON_IDS[iItem], BP_AMMO[iItem])

	client_print_color(id, print_team_default, "^4[CSP] ^3Вы взяли себе ^4%s", CHAT_NAMES[iItem])

	return PLUGIN_HANDLED
}

public func_VipMenu_CallBack(id, iMenu, iItem) {
	if(!bIsAvailable()) {
		menu_item_setname(iMenu, iItem, "Недоступно")
		return ITEM_DISABLED
	}

	return ITEM_IGNORE
}

stock bool:bIsAvailable() return (get_member_game(m_iTotalRoundsPlayed) >= MIN_ROUND)
 
Последнее редактирование:
Сообщения
21
Реакции
1
BlackSignature, Теперь все понятно и расставлено по полочкам
Спасибо за помощь и объяснения
Жаль, что не могу пока лайки ставить
 
Сообщения
29
Реакции
62
BlackSignature, с наступающим (или может уже и наступившим) Новым годом :derisive:

Я не в коем случае не придираюсь, просто меня зацепило)
for(new i = MENU_ITEM__M4A1; i <= MENU_UTEM__AWP; i++) {
Если начали использовать перечисления, то используйте их уж тогда сполна. с использованием sizeof(enumname) (ой лол, сам enumname же отдает размер, кажись), меню можно сделать максимально гибким (в других местах наверно тоже следует поубирать пункты с перечислителя, их тоже могут захотеть заменить). Хотя эта "структура" тут вообще лишняя, можно же просто айди оружия, патроны и его имена объявлять в массивах и тех же перечислительных - глобально. Иначе какой смысл последнего варианта? Все "удобство" загнется когда захочется добавить еще одно оружие.
 
Последнее редактирование:
Сообщения
1,275
Реакции
2,257
Помог
57 раз(а)
SerGrib, спасибо, и вас с наступающим. И спасибо за замечание. Да, вы правы, это логично. Обычно я так и делаю. Но в данном случае это лишь пример (о чём я упомянул выше), отталкивающийся от уже имеющихся условий (три оружия, newmenus, использование каллбека), созданный с целью показать ТС'у, как при данных им условиях можно избежать дубляжа идентичных кусков кода. Закладывать в пример расширяемость у меня и в мыслях не было, это само собой обычно выходит уже, по привычке. Конкретно в цикле я использовал перечисления исключительно ради наглядности. И, если честно, особых проблем я не вижу. Несколько правок, вынос массивов с шапку - и пример в полной мере поддерживает расширяемость.

Поправил код.
 
Последнее редактирование:

d3m37r4

111111
Сообщения
1,449
Реакции
1,175
Помог
10 раз(а)
g_iCurrentRound это же get_member_game(m_iTotalRoundsPlayed)
Не совсем то, название мембера же ж намекает. В каких то моментах мб и m_iTotalRoundsPlayed можно применить.
Если играется первый раунд, то мембер вернет 0, а нам циферка текущего нужна т.е. 1, поправьте меня, если не так.
 
Последнее редактирование:

Пользователи, просматривающие эту тему

Сейчас на форуме нет ни одного пользователя.
Сверху Снизу