Round Non-Stop: Боты не считают спектраторов игроками и не уходят с сервера.

Сообщения
619
Реакции
130
Предупреждения
5
Помог
10 раз(а)
Ошибка
Боты не считают спектраторов игроками.
ОС
Linux
Amx Mod X
AMX Mod X 1.9.0.5271
Билд
Protocol version 48
Exe version 1.1.2.7/Stdio (cstrike)
ReHLDS version: 3.8.0.711-dev
Build date: 13:13:38 Feb 6 2021 (2492)
ReGamedll
ReGameDLL version: 5.20.0.492-dev
Build date: 15:26:35 Jan 4 2021
Версия Metamod
Metamod-r v1.3.0.128, API (5:13)
Metamod-r build: 17:47:54 Aug 24 2018
Metamod-r from: https://github.com/theAsmodai/metamod-r/commit/0cf2f70
Список метамодулей
[ 1] AMX Mod X        RUN   -    amxmodx_mm_i386.  v1.9.0.5  ini   Start ANY  
[ 2] dproto_EF RUN - dproto.so v0.9.582 ini Start Never
[ 3] LocalizeBug Fix RUN - localizebugfix.s v2.4 ini Start Never
[ 4] VoiceTranscoder RUN - VoiceTranscoder. v2017RC5 ini ANY
[ 5] hackdetector RUN - hackdetector_amx v0.15.32 pl1 ANY
[ 6] CStrike RUN - cstrike_amxx_i38 v1.9.0.5 pl1 ANY
[ 7] Engine RUN - engine_amxx_i386 v1.9.0.5 pl1 ANY
[ 8] FakeMeta RUN - fakemeta_amxx_i3 v1.9.0.5 pl1 ANY
[9] Ham Sandwich RUN - hamsandwich_amxx v1.9.0.5 pl1 ANY ANY
[10] MySQL RUN - mysql_amxx_i386. v1.9.0.5 pl1 ANY ANY
[11] CSX RUN - csx_amxx_i386.so v1.9.0.5 pl1 ANY ANY
[12] Fun RUN - fun_amxx_i386.so v1.9.0.5 pl1 ANY ANY
[13] ReAPI RUN - reapi_amxx_i386.so v5.19.0.211-dev pl2 ANY
Список плагинов
[1] AIM detector            v0.9.2cs     kanagava          aim_detector.am  running  
[ 2] FreshBans v1.4.2b kanagava fresh_bans.amxx running
[ 3] Admin Loader v3.5 neygomon admin_loader.am running
[ 4] StatsX (MastaMan Editi v1.8.0.3660 AMXX Dev Team statsx_shell.am running
[ 5] Admin Chat v1.9.0.5271 AMXX Dev Team adminchat.amxx running
[ 6] Admin Commands v1.9.0.5271 AMXX Dev Team admincmd.amxx running
[ 7] Admin Votes v1.9.0.5271 AMXX Dev Team adminvote.amxx running
[ 8] Menus Front-End v1.9.0.5271 AMXX Dev Team menufront.amxx running
[ 9] Commands Menu v1.9.0.5271 AMXX Dev Team cmdmenu.amxx running
[ 10] Players Menu v1.9.0.5271 AMXX Dev Team plmenu.amxx running
[ 11] Maps Menu v1.9.0.5271 AMXX Dev Team mapsmenu.amxx running
[ 12] Plugin Menu v1.9.0.5271 AMXX Dev Team pluginmenu.amxx running
[ 13] Scrolling Message v1.9.0.5271 AMXX Dev Team scrollmsg.amxx running
[ 14] Info. Messages v1.9.0.5271 AMXX Dev Team imessage.amxx running
[ 15] Map Manager v2.5.61 Mistrick mapmanager.amxx running
[ 16] Map Manager: Sub Plugi v0.1 Mistrick mapmanager_subp running
[ 17] TimeLeft v1.9.0.5271 AMXX Dev Team timeleft.amxx running
[ 18] Stats Configuration v1.9.0.5271 AMXX Dev Team statscfg.amxx running
[ 19] GGAMXX v2.12 Avalanche gg.amxx running
[ 20] Auto Team Balance Adva v1.5.1 Radius auto_team_balan running
[ 21] Autoresponder/Advertis v0.5 MaximusBrood ad_manager.amxx running
[ 22] Blue Fade v0.1 Stimul Blue_Fade.amxx running
[ 23] Auto recording demo v2.0 IzI | Bonaqua (R amx_autodemorec running
[ 24] Admin Gag v1.0 AndrewZ admin_gag.amxx running
[ 25] mute v1.0 Aziz mute.amxx running
[ 26] AFK v2.3 rapara13/Nordic afk.amxx running
[ 27] Admin Prefixes v4.1 m0skVi4a ;] admin_prefixes. running
[ 28] Spawn Protection v7.0 Peli spawnprotection running
[ 29] Custom Models v1.3.2 neugomon custom_models.a running
[ 30] Round Non-Stop v0.3.6 Simon Logic round_nonstop.a running
Автор плагина
simon logic
Версия плагина
0.3.6
Исходный код
/*  AMX Mod X script.

Round Non-Stop Plugin

(c) Copyright 2006-2007, Simon Logic ([email protected])
This file is provided as is (no warranties).


Preamble:
This plugin is intended to replace old & buggy Fake Team Bot plugin
(by OneEyed).

Info:
This plugin allows you to play a map without round restart.

Attention! Using this plugin has sense only when free for all mode
is enabled (e.g. by CSDM) and/or there is a registered client command
or server time-function which respawns dead players. Such
a command/function is usually provided by another plugin.

By this time plugin has autodetect feature to be activated only
if the following plugins have been detected:
* amx_respawn by f117bomb
* CSDM by CSDM Team

Still you have a chance to test this plugin on your own without having
above plugins by using a command 'amx_force_round_nonstop' or cvar
'amx_round_nonstop'.

Note:
This plugin will not 100% stop round restart because it does not
remove map CS specific objectives. Use should use another plugin
(e.g CSDM) in conjunction with this one.

Requirements:
* CS/CZ mod
* Fakemeta & CStrike modules

New commands:
amx_force_round_nonstop <on|off|auto>
turns round non-stop on/off/autodetect immediately
amx_round_nonstop_state
prints plugin status

New cvars:
amx_round_nonstop <-1|0|1> (default=-1)
controls plugin behaviour:
-1 - autodetect
0 - always off
1 - always on
amx_round_nonstop_flags <flags> (default=abdfg)
customize plugin:
a - hide system bots (visually); turning this flag off is ususally
useful for testing or fun
b - move system bots high enough to free up spawn area
(recommended)
c - activate anti-idle-kick mechanism (recommended when
'mp_autokick' is on); feature is activated on bot spawn only
d - kick system bots when server is full (actually max players per
each team is considered)
e - kick system bots when server is empty; otherwise system bots
will enter the server before any player
f - show bots as spectators on Score Table; this flag also
makes bots totally be hidden on the radar
g - show bots ping as BOT on Score Table
amx_round_nonstop_botname_t <string> (default='.')
customize system bot name for TERRORIST team (applied on bot
respawn only)
amx_round_nonstop_botname_ct <string> (default=':')
customize system bot name for CT team (applied on bot
respawn only)

Known issues:
* make sure a map has at least two spawn points for each side,
otherwise you may get troubles on game commencing

Credits:
* OneEyed for the plugin main idea
* Space Headed Productions team for their BotAPI
* VEN for his discovery of CBasePlayer::m_fLastMovement offset
* jim_yang for the idea of showing system bots as spectators on Score
Table (idea has been taken from Roundend Blocker plugin)

TODO:
* introduce plugin management via menu
* fix a bug with round restart absence when system bot enters the
opposite team and becomes the first & only player per team

History:
0.3.6 [2007-11-16]
! bots won't left the server when there were no real players &
'amx_round_nonstop_flags' had 'e' flag
0.3.5 [2007-10-04]
! fixed bot creating attempts when there are no spawn points per team
at all
0.3.4 [2007-06-24]
! fixed absence of METAMOD return result within onStartFrame()
+ system bots get ADMIN_IMMUNITY privilege now
! fixed an issue with senseless of moving bots high on DE maps
! fixed description of flag 'e'
* plugin does not scramble radar now
* plugin does not block timer ticking now
0.3.3 [2007-02-26]
! fixed a bug with incorrect detecting of full server using 'maxplayers'
value
! fixed bad porting of BotAPI partial functionality (system bots won't
hidden at all on respawn; they were hidden on round restart only)
+ added new flag 'g' for 'amx_round_nonstop_flags' cvar (see description
above)
* only one generic task (taskCheckCvar) is allowed (optimization)
0.3.2 [2007-02-22]
+ cvar 'amx_round_nonstop_botnamet'
+ cvar 'amx_round_nonstop_botnamect'
+ extended 'amx_force_round_nonstop' command
- avoid using of BotAPI (too many complains on compiling, sorry)
- removed redundant mod validation because CStrike module is required
! forgot to check 'maxplayers' on detecting a full server (spawn points
quantity was previously used)
0.3.1 [2007-02-16]
+ added possibilty to show system bots as spectators on Score Table
(see new flag 'f' for 'amx_round_nonstop_flags' cvar)
0.3.0 [2007-02-15]
! many fixes
+ added anti-idle-kick mechanism for system bots
* renamed cvar 'amx_round_nonstop_safety' to 'amx_round_nonstop_flags'
+ added more flag values for cvar 'amx_round_nonstop_flags' to extend
plugin features
* plugins is rewritten from task-driven to event-driven mechanism (as i
planned long ago)
0.2.0 [2006-12-21]
* ported from AMX Mod 0.9.9 to AMX Mod X
+ system bots now hidden on a radar
+ replaced 'Game commencing' with 'Round Non-Stop commencing'
0.1.2 [2006-11-26]
+ added 'amx_round_nonstop_safety' cvar
0.1.1 [2006-11-16]
* first public beta release
0.1.0 [2006-11-12]
* internal release for testing
*/

#include <amxmodx>
#include <amxmisc> // is_running()
#include <fakemeta>
#include <fakemeta_stocks>
#include <cstrike>
//#include <bot_api>

#pragma tabsize 4

#define MY_PLUGIN_NAME "Round Non-Stop"
#define MY_PLUGIN_VERSION "0.3.6"
#define MY_PLUGIN_AUTHOR "Simon Logic"

#define MAX_CLIENTS 32
// max number of players on server
#define MAX_BOT_NAME 31
// max length of the bot name
#define MAX_TEAMS 3
// max number of teams in game + one for index padding

#define MAX_MAP_COORD_Z 4095.0

#define TASK_ANTIIDLEKICK_BASE 65
#define TASK_CHECKCVAR_ID 70

#define OFFSET_LAST_MOVEMENT 124
// for 32bit cpu only

// plugin flags...
#define SFL_HIDE (1<<0)
#define SFL_TAKEOFFSPAWNAREA (1<<1)
#define SFL_ANTIIDLEKICK (1<<2)
#define SFL_KICKONSERVERFULL (1<<3)
#define SFL_KICKONSERVEREMPTY (1<<4)
#define SFL_SHOWASSPECTATORS (1<<5)
#define SFL_SHOWBOTPINGASBOT (1<<6)

// spawn IDs (first two must match CS_TEAM_X)...
#define SPID_T 1
#define SPID_CT 2
#define SPID_VIP 3

// compilation options...
//#define _DEBUG
// compile with debug messages
//#define _ASSERT
// compile with assertions


enum t_bot
{
i_id,
i_task_antikick
// s_name[MAX_BOT_NAME+1]
}

new const g_arrBotNameDef[MAX_TEAMS][] = { // default names
"", // a pad to match array index to team index
".", // terrorist bot name
":" // ct bot name
}
new const g_arrSpawnClasses[][] = { // index must match SPID_*
"",
"info_player_deathmatch", // CS_TEAM_T
"info_player_start", // CS_TEAM_CT
"info_vip_start"
}
new const // other resource strings
g_sClassname[] = "classname",
g_sGameCommencing[] = "#Game_Commencing"
new g_sSpectator[] = "SPECTATOR"

new bool:g_bAMD64
new bool:g_bFalseRespawn[MAX_CLIENTS+1]
new g_iRoundTime
new g_iMaxPlayers
new g_iSpawnCount[MAX_TEAMS]
new g_tBots[MAX_TEAMS][t_bot] // 1st element is dummy element
new Float:g_fGenericTaskTime
new g_cvarState, g_cvarFlags, g_cvarAmxRespawn, g_cvarCsdmActive
new g_cvarBotNames[MAX_TEAMS]
new g_fmSetOrigin

forward bool:existsRespawnEngine()
forward bool:isActive()
//-----------------------------------------------------------------------------
public plugin_init()
{
g_bAMD64 = bool:is_amd64_server()
g_iMaxPlayers = get_maxplayers()
g_tBots[_:CS_TEAM_T][i_id] = 0
g_tBots[_:CS_TEAM_CT][i_id] = 0

register_plugin(MY_PLUGIN_NAME, MY_PLUGIN_VERSION, MY_PLUGIN_AUTHOR)

g_iRoundTime = 1

g_cvarState = register_cvar("amx_round_nonstop", "-1")
g_cvarFlags = register_cvar("amx_round_nonstop_flags", "abdfg")
g_cvarBotNames[_:CS_TEAM_T] = register_cvar("amx_round_nonstop_botname_t", ".")
g_cvarBotNames[_:CS_TEAM_CT] = register_cvar("amx_round_nonstop_botname_ct", ":")

register_concmd("amx_force_round_nonstop", "cmdForce", ADMIN_CFG, "Sets Round Non-Stop state immediately")
register_clcmd("amx_round_nonstop_state", "cmdState", ADMIN_ALL, "Prints Round Non-Stop state")
register_event("ResetHUD", "onPlayerSpawn", "be")
register_event("TextMsg", "onRestartNotify", "a", "2=#Game_will_restart_in")
register_event("HLTV", "onNewRound", "a", "1=0", "2=0")
register_logevent("onRoundStart", 2, "1=Round_Start")

register_message(get_user_msgid("TextMsg"), "msgTextMsg")
register_message(get_user_msgid("TeamInfo"), "msgTeamInfo")

register_forward(FM_StartFrame, "onStartFrame")

server_print("[AMXX] Plugin %s initialized", MY_PLUGIN_NAME)
}
//-----------------------------------------------------------------------------
public plugin_cfg()
{
g_cvarAmxRespawn = get_cvar_pointer("amx_respawn")
g_cvarCsdmActive = get_cvar_pointer("csdm_active")

// NOTE: PSP Fixer plugin balances spawn points within plugin_cfg(),
// thus we need to put a small delay to count _proper_ spawn points
set_task(0.1, "taskCountSP")

//launchGenericTask(0.2)

hookSetOrigin()
}
//-----------------------------------------------------------------------------
public taskCountSP()
{
g_iSpawnCount[SPID_T] = countSP(SPID_T)
g_iSpawnCount[SPID_CT] = countSP(SPID_CT)

g_iRoundTime = get_cvar_num("mp_roundtime")
}
//-----------------------------------------------------------------------------
stock launchGenericTask(Float:interval)
{
if(task_exists(TASK_CHECKCVAR_ID))
{
static Float:fTime; fTime = get_gametime()
if((fTime - g_fGenericTaskTime) > interval)
{
remove_task(TASK_CHECKCVAR_ID)
set_task(interval, "taskCheckCvar", TASK_CHECKCVAR_ID)
g_fGenericTaskTime = fTime
#if defined _DEBUG
log_amx("re-launchGenericTask(interval=%.1f)", interval)
#endif
}
}
else
{
set_task(interval, "taskCheckCvar", TASK_CHECKCVAR_ID)
g_fGenericTaskTime = get_gametime()
#if defined _DEBUG
log_amx("launchGenericTask(interval=%.1f)", interval)
#endif
}
}
//-----------------------------------------------------------------------------
public client_disconnect(id)
{
#if defined _DEBUG
log_amx("client_disconnect(%d)::begin", id)
#endif
if(isFakeBot(id))
cleanupBotData(id)
else
{
// NOTE: thus we can avoid simultaneous bots creation & kick during
// server shutdown
launchGenericTask(0.5)
}
#if defined _DEBUG
log_amx("client_disconnect(%d)::end", id)
#endif
}
//-----------------------------------------------------------------------------
public msgTextMsg(msg_id, msg_dest, msg_entity)
{
if(get_msg_arg_int(1) == 4 && isActive()
&& (g_tBots[_:CS_TEAM_CT][i_id] || g_tBots[_:CS_TEAM_T][i_id]))
{
static sTemp[sizeof(g_sGameCommencing)]

get_msg_arg_string(2, sTemp, sizeof(sTemp))
if(equal(sTemp, g_sGameCommencing))
set_msg_arg_string(2, "Round Non-Stop Commencing!")
}

return PLUGIN_CONTINUE
}
//-----------------------------------------------------------------------------
public msgTeamInfo(msg_id, msg_dest, msg_entity)
{
static id

id = get_msg_arg_int(1)

if(id && (id == g_tBots[_:CS_TEAM_CT][i_id] || id == g_tBots[_:CS_TEAM_T][i_id])
&& (SFL_SHOWASSPECTATORS & getPCvarAsFlags(g_cvarFlags)))
set_msg_arg_string(2, g_sSpectator)

return PLUGIN_CONTINUE
}
//-----------------------------------------------------------------------------
public onStartFrame()
{
if(g_tBots[_:CS_TEAM_T][i_id])
updateBotMarker(g_tBots[_:CS_TEAM_T][i_id])
if(g_tBots[_:CS_TEAM_CT][i_id])
updateBotMarker(g_tBots[_:CS_TEAM_CT][i_id])

return FMRES_IGNORED
}
//-----------------------------------------------------------------------------
public updateBotMarker(id)
{
if(pev_valid(id))
{
static Float:fMSec

set_pev(id, pev_flags, pev(id, pev_flags) | FL_FAKECLIENT)
global_get(glb_frametime, fMSec)
fMSec *= 1000.0
// NOTE: without that a bot will not receive in-game events
EF_RunPlayerMove(id, Float:{0.0,0.0,0.0}, 0.0, 0.0, 0.0, 0, 0, floatround(fMSec))
}
}
//-----------------------------------------------------------------------------
stock hookSetOrigin()
{
if(SFL_TAKEOFFSPAWNAREA & getPCvarAsFlags(g_cvarFlags)) {
if(!g_fmSetOrigin)
{
g_fmSetOrigin = register_forward(FM_SetOrigin, "onSetOrigin")
#if defined _DEBUG
log_amx("SetOrigin is hooked")
#endif
}
}
else {
if(g_fmSetOrigin)
{
unregister_forward(FM_SetOrigin, g_fmSetOrigin)
g_fmSetOrigin = 0
#if defined _DEBUG
log_amx("SetOrigin is unhooked")
#endif
}
}

}
//-----------------------------------------------------------------------------
public onNewRound()
{
#if defined _DEBUG
log_amx("onNewRound()::begin")
#endif
hookSetOrigin()

// NOTE: after new round is triggered onPlayerSpawn does not
// called on system bots, thus i make a fix; it's long enough
// to make sure a double respawn is gone (double respawn is
// specific for CSDM)
if(SFL_TAKEOFFSPAWNAREA & getPCvarAsFlags(g_cvarFlags))
set_task(1.0, "taskMoveBotsHigh")

#if defined _DEBUG
new arr[1]
arr[0] = g_tBots[1][i_id]
set_task(0.2, "taskShowBotOrigin", 700, arr, sizeof(arr), "a", 10)

log_amx("onNewRound()::end")
#endif
}
//-----------------------------------------------------------------------------
public taskMoveBotsHigh()
{
new pid

for(new i=1; i<MAX_TEAMS; i++)
{
pid = g_tBots[i][i_id]
if(pid && isFakeBot(pid))
moveBotHigh(pid)
}
}
//-----------------------------------------------------------------------------
#if defined _DEBUG
public taskShowBotOrigin(arr[])
{
new id = arr[0]

if(is_user_connected(id))
{
new Float:vecOrigin[3]
pev(id, pev_origin, vecOrigin)
log_amx("FakeBot[%d].origin = {%.3f, %.3f, %.3f}", id, vecOrigin[0], vecOrigin[1], vecOrigin[2])
}
}
#endif
//-----------------------------------------------------------------------------
public onRoundStart()
{
#if defined _DEBUG
log_amx("onRoundStart()::begin")
#endif
g_iRoundTime = get_cvar_num("mp_roundtime")

if(!(SFL_KICKONSERVEREMPTY & getPCvarAsFlags(g_cvarFlags)))
launchGenericTask(0.1)
#if defined _DEBUG
log_amx("onRoundStart()::end")
#endif
}
//-----------------------------------------------------------------------------
public onSetOrigin(id, const Float:vecOrigin[3])
{
if(id && (id == g_tBots[_:CS_TEAM_CT][i_id] || id == g_tBots[_:CS_TEAM_T][i_id]))
{
static Float:vecTemp[3]

vecTemp[0] = vecOrigin[0]
vecTemp[1] = vecOrigin[1]
vecTemp[2] = MAX_MAP_COORD_Z

EF_SetOrigin(id, vecTemp)

return FMRES_SUPERCEDE
}

return FMRES_IGNORED
}
//-----------------------------------------------------------------------------
public onRestartNotify()
{
#if defined _DEBUG
log_amx("onRestartNotify()")
#endif
new arrPlayers[MAX_CLIENTS], iCount

get_players(arrPlayers, iCount, "a") // alive_only

for(new i=0; i<iCount; i++)
g_bFalseRespawn[arrPlayers[i]] = true
}
//-----------------------------------------------------------------------------
public onPlayerSpawn(id)
{
if(g_bFalseRespawn[id]) {
g_bFalseRespawn[id] = false
return PLUGIN_CONTINUE
}
#if defined _DEBUG
log_amx("onPlayerSpawn(id=%d)::begin", id)
#endif
if(isFakeBot(id))
{
new arr[1]; arr[0] = id

if(task_exists(id))
remove_task(id)
set_task(0.1, "taskHideBot", id, arr, sizeof(arr))
}
else
{
launchGenericTask(0.5)
}
#if defined _DEBUG
log_amx("onPlayerSpawn(id=%d)::end", id)
#endif
return PLUGIN_CONTINUE
}
//-----------------------------------------------------------------------------
public cmdState(pid, acl, cid)
{
console_print(pid, "[AMXX] Round Non-Stop is %s", isActive() ? "ACTIVE": "INACTIVE")
return PLUGIN_HANDLED
}
//-----------------------------------------------------------------------------
public cmdForce(pid, acl, cid)
{
if(!access(pid, acl)) {
console_print(pid, "[AMXX] You have no access to that command")
return PLUGIN_HANDLED
}
if(read_argc() != 2) {
printForceHelp(pid)
return PLUGIN_HANDLED
}

new sArg[5]; read_argv(1, sArg, sizeof(sArg)-1); strtolower(sArg)
if(equal(sArg, "on")) {
set_pcvar_num(g_cvarState, 1)
//taskCheckCvar()
launchGenericTask(0.1)
}
else if(equal(sArg, "off")) {
set_pcvar_num(g_cvarState, 0)
//taskCheckCvar()
launchGenericTask(0.1)
}
else if(equal(sArg, "auto")) {
set_pcvar_num(g_cvarState, -1)
//taskCheckCvar()
launchGenericTask(0.1)
}
else {
printForceHelp(pid)
}

return PLUGIN_HANDLED
}
//-----------------------------------------------------------------------------
printForceHelp(id)
{
console_print(id, "[AMXX] Usage: amx_force_round_nonstop <on|off|auto>")
}
//-----------------------------------------------------------------------------
bool:isActive()
{
new bool:bResult

switch(get_pcvar_num(g_cvarState))
{
case -1:
bResult = existsRespawnEngine()
case 0:
bResult = false
case 1:
bResult = true
default: {
new i
for(i=1; i<MAX_TEAMS; i++)
if(!isFakeBot(g_tBots[i][i_id]))
break
bResult = i == MAX_TEAMS // actually it's suspended state
}
}

return bResult
}
//-----------------------------------------------------------------------------
public taskCheckCvar()
{
new bool:bActive
#if defined _DEBUG
log_amx("taskCheckCvar()::begin")
#endif
switch(get_pcvar_num(g_cvarState))
{
case -1:
bActive = existsRespawnEngine()
case 0:
bActive = false
case 1:
bActive = true
default:
// do nothing (it's a hidden feature)
return
}

if(bActive) {
new bool:arrEnableBot[MAX_TEAMS] = {true, ...} // by default create bots
new i, iFlags
new arrCount[MAX_TEAMS], arrPlayers[MAX_CLIENTS]

// count real players on server...
get_players(arrPlayers, i, "ce", "CT") // skip_bots|team_match
arrCount[_:CS_TEAM_CT] = i
get_players(arrPlayers, i, "ce", "TERRORIST") // skip_bots|team_match
arrCount[_:CS_TEAM_T] = i

iFlags = getPCvarAsFlags(g_cvarFlags)

// check if there are any spawn points available per team
if(!g_iSpawnCount[_:CS_TEAM_CT])
arrEnableBot[_:CS_TEAM_CT] = false
if(!g_iSpawnCount[_:CS_TEAM_T])
arrEnableBot[_:CS_TEAM_T] = false

if(!arrCount[_:CS_TEAM_CT] && !arrCount[_:CS_TEAM_T])
{ // server is empty
if(SFL_KICKONSERVEREMPTY & iFlags) {
arrEnableBot[_:CS_TEAM_CT] = false
arrEnableBot[_:CS_TEAM_T] = false
}
}
else if(SFL_KICKONSERVERFULL & iFlags)
{
for(i=1; i<MAX_TEAMS; i++)
{
#if defined _DEBUG
log_amx("arrCount[%d] = %d", i, arrCount[i])
log_amx("g_iSpawnCount[%d] = %d", i, g_iSpawnCount[i])
#endif
if(g_iSpawnCount[i] > 1)
{
// TODO: i don't like this method, think up smth better
if(arrCount[i] && (g_iSpawnCount[i] - arrCount[i]) <= 1)
// server is full according to spawn points quantity
// available on map
arrEnableBot[i] = false
}
}

// TODO: get total number of clients instead of current shit
if((g_iMaxPlayers - arrCount[_:CS_TEAM_CT] - arrCount[_:CS_TEAM_T]) < 3)
{ // server is full according to 'maxplayers'
arrEnableBot[_:CS_TEAM_T] = false
arrEnableBot[_:CS_TEAM_CT] = false
}
}

updateBots(arrEnableBot)
}
else {
// kick them all
updateBots(bool:{false, false, false})
}
#if defined _DEBUG
log_amx("taskCheckCvar()::end")
#endif
return
}
//-----------------------------------------------------------------------------
bool:createBot(team_id)
{
new pid
#if defined _DEBUG
log_amx("createBot(team_id=%d)", team_id)
#endif
//pid = find_player("ali", g_arrBotNameDef[team_id]) // name match, case insensitive, skip real players
pid = g_tBots[team_id][i_id]
if(pid)
{
if(is_user_bot(pid)) {
// fakebot is already in game
if(CS_TEAM_T <= cs_get_user_team(pid) <= CS_TEAM_CT)
return false
#if defined _DEBUG
// TODO: discover whether it happens
log_amx("bot has invalid team")
#endif
}
else
// NOTE: normally this shoud never happen
pid = 0
}

if(!pid)
{
new sName[MAX_BOT_NAME+1]

get_pcvar_string(g_cvarBotNames[team_id], sName, MAX_BOT_NAME)

if(!sName[0])
pid = create_bot(g_arrBotNameDef[team_id])
else
pid = create_bot(sName)

// store fake bot's id
g_tBots[team_id][i_id] = pid
}

if(pid > 0) {
new sNum[2]

num_to_str(team_id, sNum, sizeof(sNum)-1)
// set bot's team & model
//setTeam(pid, team_id)
engclient_cmd(pid, "jointeam", sNum) // this is more proper than setTeam()

// spawn a bot right here
cs_user_spawn(pid)

// NOTE: a bot will be hidden on respawn event

return true
}

return false
}
//-----------------------------------------------------------------------------
updateBots(bool:flags[MAX_TEAMS])
{
#if defined _DEBUG
log_amx("updateBots(StateT=%d, StateCS=%d)", flags[_:CS_TEAM_T], flags[_:CS_TEAM_CT])
#endif
for(new i=1; i<MAX_TEAMS; i++)
if(flags[i])
createBot(i)
else
{
new id = g_tBots[i][i_id]

if(id && is_user_connected(id))
server_cmd("kick #%d", get_user_userid(id))
}
}
//-----------------------------------------------------------------------------
cleanupBotData(id)
{
#if defined _DEBUG
log_amx("cleanupBot(id=%d)", id)
#endif
new i

for(i=1; i<MAX_TEAMS; i++)
if(g_tBots[i][i_id] == id)
{
new id_task = g_tBots[i][i_task_antikick]

if(task_exists(id_task))
{
#if defined _ASSERT
assert id_task != 0
#endif
remove_task(id_task)
}

g_tBots[i][i_id] = 0
g_tBots[i][i_task_antikick] = 0

break
}
}
//-----------------------------------------------------------------------------
stock moveBotHigh(id)
{
// take the bot off the spawn area to allow real players
// to be spawned here
new Float:vecOrigin[3]

pev(id, pev_origin, vecOrigin)
vecOrigin[2] = MAX_MAP_COORD_Z
#if defined _DEBUG
log_amx("new origin for FakeBot[%d]: {%.3f, %.3f, %.3f}", id, vecOrigin[0], vecOrigin[1], vecOrigin[2])
#endif
EF_SetOrigin(id, vecOrigin)
}
//-----------------------------------------------------------------------------
public taskHideBot(arr[1])
{
new id = arr[0]
if(pev_valid(id))
hideBot(id)
}
//-----------------------------------------------------------------------------
hideBot(pid, forced=false) // NOTE: pid must be validated before this call
{
#if defined _DEBUG
log_amx("hideBot(%d)", pid)
#endif
if(!forced && pev(pid, pev_solid) == SOLID_NOT) {
#if defined _DEBUG
log_amx("FakeBot[%d] is already hidden", pid)
#endif
return
}

new iFlags = getPCvarAsFlags(g_cvarFlags)

// NOTE: see HLSDK client.cpp::ClientDisconnect() for more info

if(SFL_HIDE & iFlags)
{
// make invisible (actually until hit)
//set_pev(pid, pev_effects, pev(pid, pev_effects) | EF_NODRAW | EF_NOINTERP)
set_pev(pid, pev_effects, pev(pid, pev_effects) | EF_NODRAW)
}
// do not attract autoaim (a bot can escape grenade damage)
set_pev(pid, pev_takedamage, DAMAGE_NO)
// not solid (a bot can escape bullet hit)
set_pev(pid, pev_solid, SOLID_NOT)
// do not attract homing weapons
set_pev(pid, pev_flags, pev(pid, pev_flags) | FL_NOTARGET)
// make a bot hang in the air + noclip for reliability
set_pev(pid, pev_movetype, MOVETYPE_NOCLIP)

/*
if(SFL_TAKEOFFSPAWNAREA & iFlags)
moveBotHigh(pid)
*/

new id_team = _:cs_get_user_team(pid)
new id_task = g_tBots[id_team][i_task_antikick]

if(id_task && task_exists(id_task))
remove_task(id_task)

if(SFL_ANTIIDLEKICK & iFlags && g_iRoundTime)
{
new arr[1]; arr[0] = pid; /*arr[1] = team_id*/

id_task = genTaskID(pid + TASK_ANTIIDLEKICK_BASE)
set_task(g_iRoundTime * 60.0, "taskResetLastMovementTime", id_task, arr, sizeof(arr), "b")
g_tBots[id_team][i_task_antikick] = id_task
}

set_user_flags(pid, ADMIN_IMMUNITY)
}
//-----------------------------------------------------------------------------
public taskResetLastMovementTime(arr[1])
{
new id = arr[0]
#if defined _DEBUG
log_amx("taskResetLastMovementTime(id=%d)", id)
#endif
if(!is_user_connected(id) || !is_user_alive(id))
return

#if defined _DEBUG
log_amx("reset last movement time on FakeBot[%d]", id)
#endif
if(!g_bAMD64)
set_pdata_float(id, OFFSET_LAST_MOVEMENT, get_gametime())
}
//-----------------------------------------------------------------------------
stock setTeam(id, team_id) // NOTE: id must be valdated before this call
{
// NOTE: bot is dead here because he hasn't selected a team yet
#if defined _DEBUG
log_amx("setTeam(id=%d, team_id=%d)", id, team_id)
#endif
switch(team_id)
{
case 1: cs_set_user_team(id, CS_TEAM_T, CS_T_TERROR)
case 2: cs_set_user_team(id, CS_TEAM_CT, CS_CT_URBAN)
}
}
//-----------------------------------------------------------------------------
stock genTaskID(base_id=1, max_id=9999)
{
new iTaskId = base_id

while(task_exists(iTaskId) && iTaskId <= max_id)
iTaskId++
if(iTaskId > max_id)
return 0
return iTaskId
}
//-----------------------------------------------------------------------------
bool:existsRespawnEngine()
{
return (g_cvarAmxRespawn && get_pcvar_num(g_cvarAmxRespawn))
|| (g_cvarCsdmActive && get_pcvar_num(g_cvarCsdmActive))
}
//-----------------------------------------------------------------------------
bool:isFakeBot(pid)
{
if(pid && is_user_connected(pid) && is_user_bot(pid))
{
return (pid == g_tBots[_:CS_TEAM_T][i_id] || pid == g_tBots[_:CS_TEAM_CT][i_id])
}

return false
}
//-----------------------------------------------------------------------------
getPCvarAsFlags(pcvar)
{
static sValue[27]

get_pcvar_string(pcvar, sValue, sizeof(sValue) - 1)

return read_flags(sValue)
}
//-----------------------------------------------------------------------------
// count spawn points on current map
countSP(type, bool:check_origin = true)
{
new iCount = 0, iID = 0
#if defined _ASSERT
assert type != 0
#endif
if(check_origin) {
new Float:vecOrigin[3]
do {
iID = EF_FindEntityByString(iID, g_sClassname, g_arrSpawnClasses[type])
if(iID > 0) {
pev(iID, pev_origin, vecOrigin)
if(vecOrigin[0] || vecOrigin[1] || vecOrigin[2]) iCount++
}
} while(iID > 0)
} else {
while(0 < (iID = EF_FindEntityByString(iID, g_sClassname, g_arrSpawnClasses[type])))
iCount++

}

return iCount
}
//-----------------------------------------------------------------------------
public create_bot(const name[]) // taken from BotAPI 0.5.1
{
new id

id = EF_CreateFakeClient(name)

if (pev_valid(id))
{
EF_FreeEntPrivateData(id)

DF_MetaFunc_CallGameEntity("player", id)
set_user_info(id, "rate", "3500")
set_user_info(id, "cl_updaterate", "25")
set_user_info(id, "cl_lw", "1")
set_user_info(id, "cl_lc", "1")
set_user_info(id, "cl_dlmax", "128")
set_user_info(id, "cl_righthand", "1")
set_user_info(id, "_vgui_menus", "0")
set_user_info(id, "_ah", "0")
set_user_info(id, "dm", "0")
set_user_info(id, "tracker", "0")
set_user_info(id, "friends", "0")
if(SFL_SHOWBOTPINGASBOT & getPCvarAsFlags(g_cvarFlags))
set_user_info(id, "*bot", "1")
set_pev(id, pev_flags, pev(id, pev_flags) | FL_FAKECLIENT)
set_pev(id, pev_colormap, id)

new msg[128]

DF_ClientConnect(id, name, "127.0.0.1", msg)
DF_ClientPutInServer(id)
EF_RunPlayerMove(id, Float:{0.0,0.0,0.0}, 0.0, 0.0, 0.0, 0, 0, 76)

return id
}

return 0
}
//-----------------------------------------------------------------------------
Плагин нужен для бесконечного раунда: 2 бота находятся в спектрах за тт и кт.
У меня слотов 24.
Если на сервере игроков становится 22 (за 2 слота до полного заполнения сервера), то боты уходят с серва, освобождая слоты другим игрокам .
Но если при заполненных 22х слотах кто-то из игроков сидит в спектрах, то боты не выходят, слоты не освобождаются. Как бы боты не считают спектраторов игроками))
Пытался сделать так, чтобы боты выходили за 4 слота до полного заполнения, т.е. при 20 игроках на серве через #define MAX_CLIENTS 20, но результата никакого.
Хотел спросить у автора плагина simon logic, (русскоговорящий скриптер), но форум, где он выкладывал свой плагин в 2006 году уже мертв Round Non-Stop 0.3.6 - Страница 2 - AMX Mod X Форум
 

Вложения

Сообщения
2,833
Реакции
1,666
Помог
75 раз(а)
wood-grouse, зачем использовать этот плагин, если в регейме есть квар на бесконечный раунд?
 
Сообщения
619
Реакции
130
Предупреждения
5
Помог
10 раз(а)
Алексеич, знаю, но хочется использовать именно этот плагин + боты создают видимость, что на серве минимум 2 человека играют))
 

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

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