Код
/*
* Ban Disconnected Player Menu
*
* Displays a menu that allows admins to ban recently
* disconnected players.
*
*
* Usage:
*
* banmenu_show
* Displays ban menu.
*
* discon_list
* Prints current disconnected list in console.
*
*
* Copyright (C) 2007 M R Gray
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* To receive a copy of the GNU General Public License, write to:
*
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301, USA.
*/
#include <amxmodx>
#include <amxmisc>
/* Must keep track of menu data for each player.
*/
new bantimes[33]
new pages[33]
/* The new menu system doesn't map the Back, More, and Exit items
* to 8, 9, and 0. Therefore menu paging is dome manually.
*
* When padding the new menus, the addblank() would make the menu
* look better but it does not seem to be working now. If used, it
* will screw-up the item numbering for the Back, Next, and Exit items.
* So for now, just add items with no text and ignore them when they
* are selected.
*/
#define ITEM_CNT 7
#define ITEM_BACK 7
#define ITEM_MORE 8
#define ITEM_EXIT 9
new datafile_name[225]
#define DCON_MAX 203 // max number of ids stored
#define DCON_NAME_MAX 37 // max name length
#define DCON_SID_MAX 23 // max steamid length
#define DCON_CHECK 17 // number of ids to check for duplicates
#define DCON_RESET 51 // number of ids to save when max ids reached
new dcons_names[DCON_MAX][32], dcons_sids[DCON_MAX][DCON_SID_MAX], dcon_cnt
/* If you want to make the datafile a little easier to read,
* define this:
*/
//#define PAD_DCON_FILE
public plugin_init()
{
register_plugin("Ban Disconnected Menu", "2.0.1", "MRG")
register_concmd("banmenu_show", "banmenu_cmd", ADMIN_BAN, "- displays ban menu")
register_concmd("discon_list", "discon_list", ADMIN_BAN, "- prints disconnected list in console")
datafile_load()
}
///////////////////////////////////////////////////////////////////////////////
public client_disconnect(idx)
{
new name[33], sid[36]
/* Don't add players with immunity to the list of
* disconnected players. Once a player disconnects,
* I don't know of an easy way to determine the access
* level of an admin just knowing his steam id.
*/
if(access(idx, ADMIN_IMMUNITY))
return
get_user_authid(idx, sid, 35)
get_user_name(idx, name, 32)
// check if player already in list
if(player_find(name, sid, DCON_CHECK) < 0)
{
player_add(name, sid)
datafile_add(name, sid)
}
}
///////////////////////////////////////////////////////////////////////////////
datafile_load()
{
new file, line[127], name[DCON_NAME_MAX], sid[DCON_SID_MAX]
dcon_cnt = 0
get_basedir(line, 126)
format(datafile_name, 224, "%s/disconndata.txt", line)
// read player list from file
file = fopen(datafile_name, "r")
if(file)
{
while(fgets(file, line, 126))
{
if(equal(line, "STEAM", 5))
{
strtok(line, sid, DCON_SID_MAX - 1, name, DCON_NAME_MAX - 1, ' ', 1)
trim(sid)
trim(name)
player_add(name, sid)
}
}
fclose(file)
}
// clear data file
file = fopen(datafile_name, "w")
if(file)
{
format_time(line, 126, "%m/%d/%y - %I:%M:%S %p")
get_mapname(name, DCON_NAME_MAX - 1)
fprintf(file, "# Generated by Ban Disconnected Menu plugin^n")
fprintf(file, "# DO NOT EDIT!!!^n")
fprintf(file, "# %s^n", line)
fprintf(file, "# %s^n", name)
fclose(file)
}
}
datafile_add(name[], sid[])
{
new file, i
file = fopen(datafile_name, "a")
if(file)
{
#if defined PAD_DCON_FILE
fprintf(file, "%s", sid)
for(i = strlen(sid); i < DCON_SID_MAX + 3; i++)
fputc(file, ' ')
#else
fprintf(file, "%s ", sid)
#endif
fprintf(file, "%s^n", name)
fclose(file)
}
}
public discon_list(idx, lvl, cid)
{
new i
// check access
if(!cmd_access(idx, lvl, cid, 1))
return PLUGIN_HANDLED
for(i = 0; i < dcon_cnt; i++)
client_print(idx, print_console, "%s %s", dcons_sids[i], dcons_names[i])
client_print(idx, print_console, "%i total", dcon_cnt)
return PLUGIN_HANDLED
}
///////////////////////////////////////////////////////////////////////////////
player_find(name[], sid[], cnt)
{
new i, j
/* Search from the end of the list because that is where
* the most recent disconnects are stored.
*/
for(i = dcon_cnt - 1, j = 0; i >= 0 && j < cnt; i--, j++)
if(equal(sid, dcons_sids[i]))
if(equal(name, dcons_names[i]))
return i
return -1
}
player_add(name[], sid[])
{
new i
// check if max reached
if(dcon_cnt >= DCON_MAX)
{
for(i = 0; i < DCON_RESET; i++)
{
copy(dcons_sids[i], 35, dcons_sids[i + (DCON_MAX - DCON_RESET)])
copy(dcons_names[i], 32, dcons_names[i + (DCON_MAX - DCON_RESET)])
}
dcon_cnt = DCON_RESET
}
copy(dcons_sids[dcon_cnt], 34, sid)
copy(dcons_names[dcon_cnt], 31, name)
return ++dcon_cnt
}
///////////////////////////////////////////////////////////////////////////////
/* Adds the Back, More, and Exit items to menu. Uses
* page and cnt to determine if to show Back or More.
*/
menu_bme(menu, page, cnt)
{
// check if on first page
if(page > 0)
menu_additem(menu, "Back", "-1")
else
{
menu_additem(menu, " ", "-1")
//menu_addblank(menu)
}
/* Normally it would be just ITEM_CNT instead of
* (ITEM_CNT - 1), but must take into account
* that the bantime entry is always the first item
* listed (which could get very annoying).
*/
// check if on last page
if(cnt > ((page + 1) * (ITEM_CNT - 1)))
menu_additem(menu, "More", "-1")
else
{
menu_additem(menu, " ", "-1")
//menu_addblank(menu)
}
menu_additem(menu, "Exit", "-1")
}
/* Adds blank entries to menu so that Back, More, and Exit items
* are always at end.
*/
menu_pad(menu, cnt)
{
new i, pad
pad = ITEM_CNT - (cnt % ITEM_CNT)
if(pad < ITEM_CNT)
for(i = 0; i < pad; i++)
{
menu_additem(menu, " ", "-1")
//menu_addblank(menu)
}
return (pad < ITEM_CNT) ? pad : 0
}
/* Add players from disconnected list to menu based on what
* page is to be displayed.
*/
menu_players(menu, page)
{
new i, j, crs, cnt
/* Like before, must take into account that the
* bantime entry is always the first item listed.
*/
crs = page * (ITEM_CNT - 1)
cnt = 1;
/* Start from the end of the list because that
* is where the most recent disconnects are stored.
*/
for(i = dcon_cnt - 1 - crs, j = 0; i >= 0 && j < (ITEM_CNT - 1); i--, j++)
{
menu_additem(menu, dcons_names[i], dcons_sids[i])
cnt++
}
menu_pad(menu, cnt)
menu_bme(menu, page, dcon_cnt)
return cnt
}
///////////////////////////////////////////////////////////////////////////////
public banmenu_cmd(idx, lvl, cid)
{
// check access
if(!cmd_access(idx, lvl, cid, 1))
return PLUGIN_HANDLED
bantimes[idx] = 0
pages[idx] = 0
banmenu_display(idx)
return PLUGIN_HANDLED
}
public banmenu_display(idx)
{
new menu
switch(bantimes[idx])
{
case 0: menu = menu_create("Ban Permanent", "banmenu_handler")
case 1: menu = menu_create("Ban Month", "banmenu_handler")
case 2: menu = menu_create("Ban Week", "banmenu_handler")
case 3: menu = menu_create("Ban Day", "banmenu_handler")
case 4: menu = menu_create("Ban Hour", "banmenu_handler")
default: return
}
// no paging
menu_setprop(menu, MPROP_PERPAGE, 0)
// add change bantime item
menu_additem(menu, "Change Ban Time", "bantime")
menu_players(menu, pages[idx])
menu_display(idx, menu, 0)
}
public banmenu_handler(idx, menu, item)
{
static const ban_strs[][] =
{
"permanently",
"for a month",
"for a week",
"for a day",
"for an hour"
}
static const ban_mins[] = {0, 40320, 10080, 1440, 60}
new sid[36], tag[32], name[32], sdx[36], nil
menu_item_getinfo(menu, item, nil, sid, 35, tag, 31, nil)
/* When checking for the Back, More, and Exit items,
* if the menu was on the first page, then the Back
* item's tag will be blank. The same goes for the
* last page and the More item's tag.
*/
if(item == ITEM_EXIT)
{
menu_destroy(menu)
return PLUGIN_HANDLED
}
if(item == ITEM_BACK)
{
if(tag[0] == 'B')
pages[idx]--
goto redisplay
}
if(item == ITEM_MORE)
{
if(tag[0] == 'M')
pages[idx]++
goto redisplay
}
// check if bantime selected
if(sid[0] == 'b')
{
bantimes[idx]++
if(bantimes[idx] > 4)
bantimes[idx] = 0
goto redisplay
}
// make sure the item's command is a steam id
if(sid[0] != 'S')
{
menu_destroy(menu)
return PLUGIN_HANDLED
}
get_user_name(idx, name, 31)
get_user_ip(idx, sdx, 15, 1)
/* Players with immunity should not have been on the
* list in the first place.
*/
log_amx("Ban: ^"%s^" <%s> banned ^"%s^" <%s> %s", name, sdx, tag, sid, ban_strs[bantimes[idx]])
server_cmd("addip %i %s", ban_mins[bantimes[idx]], sdx)
server_cmd("writeip")
server_exec()
switch(get_cvar_num("amx_show_activity"))
{
case 1: client_print(0, print_console, "ADMIN: ban %s <%s>", tag, sid)
case 2: client_print(0, print_chat, "Админ %s: забанил %s <%s>", name, tag, sid)
}
redisplay:
menu_destroy(menu)
banmenu_display(idx)
return PLUGIN_HANDLED
}