#include < amxmodx >
#include < reapi >
#include < fakemeta >
#include < xs >
new find_ent_hook;
new current_player;
new current_team;
new Float:best_place[3];
new num_iterations;
new bool:need_semiclip[33];
new orig_spawn_nums[2];
new max_players_on_spot[2];
new iMaxPlayers;
public player_spawn_pre( iPlayer )
{
need_semiclip[current_player] = false;
current_player = iPlayer;
current_team = get_member(iPlayer, m_iTeam) == TEAM_CT ? 0 : 1;
num_iterations = 0;
find_ent_hook = register_forward(FM_FindEntityInSphere, "find_entity_insphere", 0);
}
public player_spawn_post( iPlayer )
{
num_iterations = 0;
current_player = 0;
current_team = 0;
if(need_semiclip[iPlayer])
{
set_entvar(iPlayer, var_origin, best_place);
}
unregister_forward(FM_FindEntityInSphere, find_ent_hook, 0);
if(need_semiclip[iPlayer])
{
set_entvar(iPlayer, var_solid, SOLID_NOT);
SetThink(iPlayer, "PlayerThink");
set_entvar(iPlayer, var_nextthink, get_gametime() + 0.1);
}
}
public PlayerThink(iPlayer)
{
if(!is_stuck(iPlayer))
{
SetThink(iPlayer, "");
set_entvar(iPlayer, var_solid, SOLID_BBOX);
}
else
{
set_entvar(iPlayer, var_nextthink, get_gametime() + 0.1);
}
}
public find_entity_insphere(start, Float:origin[3], Float:radius)
{
if(radius != 64.0)
return FMRES_IGNORED;
num_iterations++;
new orig_start= engfunc(EngFunc_FindEntityInSphere, start , origin, 65.0);
if(orig_start)
{
new plrs_on_spot = 0;
start = -1;
while((start= engfunc(EngFunc_FindEntityInSphere, start , origin, 65.0)))
{
if(is_entity(start) && is_user_alive(start))
{
need_semiclip[current_player] = true;
plrs_on_spot++;
}
}
if(plrs_on_spot < max_players_on_spot[current_team])
{
xs_vec_copy(origin, best_place);
}
if(num_iterations >= orig_spawn_nums[current_team])
{
forward_return(FMV_CELL, 0);
return FMRES_SUPERCEDE;
}
forward_return(FMV_CELL, orig_start);
return FMRES_SUPERCEDE;
}
else
{
forward_return(FMV_CELL, orig_start);
return FMRES_SUPERCEDE;
}
}
public plugin_init()
{
if(orig_spawn_nums[0])
max_players_on_spot[0] = floatround(iMaxPlayers/float(orig_spawn_nums[0]), floatround_ceil);
else
max_players_on_spot[0] = iMaxPlayers;
if(orig_spawn_nums[1])
max_players_on_spot[1] = floatround(iMaxPlayers/float(orig_spawn_nums[1]), floatround_ceil);
else
max_players_on_spot[1] = iMaxPlayers;
RegisterHookChain( RG_CBasePlayer_Spawn, "player_spawn_pre", false );
RegisterHookChain( RG_CBasePlayer_Spawn, "player_spawn_post", true );
}
public plugin_precache()
{
iMaxPlayers = get_maxplayers();
enum _:SpawnsDatas
{
m_szAngles[64],
m_szOrigins[64]
}
new Array:aSpawns[2];
aSpawns[0] = ArrayCreate(SpawnsDatas);
aSpawns[1] = ArrayCreate(SpawnsDatas);
new mTempDatas[SpawnsDatas]
enum
{
iAngles,
iOrigins,
iClassName
}
new Trie:tKeyType = TrieCreate()
TrieSetCell(tKeyType, "angles", iAngles)
TrieSetCell(tKeyType, "origin", iOrigins)
TrieSetCell(tKeyType, "classname", iClassName)
new szMapFile[64]
get_mapname(szMapFile, charsmax(szMapFile))
format(szMapFile, charsmax(szMapFile), "maps/%s.bsp", szMapFile)
new szBuffer[64], szKey[16], szValue[32], iType
new bool:bInEntityDatas, bool:bIsCTSpawn;
new bool:bIsTTSpawn;
new fp = fopen(szMapFile, "rb")
new iOffset, iLength, iMaxPos
fseek(fp, 4, SEEK_SET)
fread(fp, iOffset, BLOCK_INT)
fread(fp, iLength, BLOCK_INT)
iMaxPos = iOffset + iLength
fseek(fp, iOffset, SEEK_SET)
while( ftell(fp) < iMaxPos )
{
fgets(fp, szBuffer, charsmax(szBuffer))
trim(szBuffer)
if( bInEntityDatas )
{
if( szBuffer[0] == '}' )
{
bInEntityDatas = false
if( bIsCTSpawn )
{
ArrayPushArray(aSpawns[0], mTempDatas)
}
if( bIsTTSpawn )
{
ArrayPushArray(aSpawns[1], mTempDatas)
}
}
else
{
parse(szBuffer, szKey, charsmax(szKey), szValue, charsmax(szValue))
if( TrieGetCell(tKeyType, szKey, iType) )
{
switch( iType )
{
case iAngles:
{
copy(mTempDatas[m_szAngles], charsmax(mTempDatas[m_szAngles]), szValue)
}
case iOrigins:
{
copy(mTempDatas[m_szOrigins], charsmax(mTempDatas[m_szOrigins]), szValue)
}
case iClassName:
{
if( equal(szValue, "info_player_start") )
{
bIsCTSpawn = true
}
else if ( equal(szValue, "info_player_deathmatch") )
{
bIsTTSpawn = true;
}
}
}
}
}
}
else if( szBuffer[0] == '{' )
{
bInEntityDatas = true
bIsCTSpawn = false
bIsTTSpawn = false;
}
}
fclose(fp)
for(new t = 0; t < 2; t++)
{
new iSpawnsNum = ArraySize( aSpawns[t] )
orig_spawn_nums [t] = iSpawnsNum;
new iNeededSpawns = max( iMaxPlayers - iSpawnsNum, 0)
if( iSpawnsNum > 0 && iNeededSpawns > 0 )
{
new iFactor = (iNeededSpawns / iSpawnsNum) + _:!!(iNeededSpawns % iSpawnsNum)
new iszClassName;
if(!t)
{
iszClassName = engfunc(EngFunc_AllocString, "info_player_start");
set_kvd(0, KV_ClassName, "info_player_start");
}
else
{
iszClassName = engfunc(EngFunc_AllocString, "info_player_deathmatch")
set_kvd(0, KV_ClassName, "info_player_deathmatch")
}
set_kvd(0, KV_fHandled, 0)
for(new i, j, iEnt; i<iSpawnsNum; i++)
{
ArrayGetArray(aSpawns[t], i, mTempDatas)
for(j=0; j<iFactor; j++)
{
iEnt = engfunc(EngFunc_CreateNamedEntity, iszClassName)
DispatchKeyValueCustom(iEnt, "angles", mTempDatas[m_szAngles])
DispatchKeyValueCustom(iEnt, "origin", mTempDatas[m_szOrigins])
dllfunc(DLLFunc_Spawn, iEnt)
if( --iNeededSpawns == 0 )
{
goto delete_datas
}
}
}
}
delete_datas:
ArrayDestroy( aSpawns[t] )
TrieDestroy( tKeyType )
}
}
DispatchKeyValueCustom(iEntity, szKey[], szValue[])
{
set_kvd(0, KV_KeyName, szKey)
set_kvd(0, KV_Value, szValue)
dllfunc(DLLFunc_KeyValue, iEntity, 0)
}
stock bool:is_stuck(id)
{
new Float:origin[3];
get_entvar(id, var_origin, origin);
new found;
while ( ( found = engfunc ( EngFunc_FindEntityInSphere, found, origin, 64.0 ) ) )
{
if(found == id)
continue;
if(is_entity(found) && is_user_alive(found))
{
return true;
}
}
return false;
}