#include <amxmodx>
#include <engine>
#include <fakemeta_util>
#include <fun>
#include <hamsandwich>
#include <nfvault>
#include <zombieplague>
#pragma semicolon 1
#define DISTANCE 120
new g_Zombie[33];
new bool:g_bSolid[33];
new bool:g_bHasSemiclip[33];
new Float:g_fOrigin[33][3];
new Float:g_fSpawnTime[33];
new stuck[33];
enum SEMICLIP{
SEMICLIP_NULL,
SEMICLIP_NONE,
SEMICLIP_AUTO,
SEMICLIP_ACTIVE,
}
new SEMICLIP:SemiClipType[33];
new gNotify[33];
new bool:g_bSemiclipEnabled;
new g_iForwardId[3];
new g_iMaxPlayers;
new g_iCvar[3];
public plugin_init( )
{
register_plugin( "(Team-)Semiclip", "1.2", "SchlumPF*" );
g_iCvar[0] = register_cvar( "semiclip_enabled", "1" );
g_iCvar[2] = register_cvar( "semiclip_transparancy", "1" );
set_task(0.1,"checkstuck",0,"",0,"b");
register_forward( FM_ClientCommand, "fwdClientCommand" );
RegisterHam(Ham_Spawn, "player", "fw_PlayerSpawn");
RegisterHam(Ham_Killed, "player", "fw_PlayerKilled");
register_touch("player", "player", "player_touch");
register_clcmd("say /semiclip","semiclip_menu", 0, "- select semiclip mode");
if( get_pcvar_num( g_iCvar[0] ) )
{
g_iForwardId[0] = register_forward( FM_PlayerPreThink, "fwdPlayerPreThink" );
g_iForwardId[1] = register_forward( FM_PlayerPostThink, "fwdPlayerPostThink" );
g_iForwardId[2] = register_forward( FM_AddToFullPack, "fwdAddToFullPack_Post", 1 );
g_bSemiclipEnabled = true;
}
else
g_bSemiclipEnabled = false;
}
public client_connect( id )
{
g_iMaxPlayers = max( id, g_iMaxPlayers );
SemiClipType[id] = SEMICLIP_NULL;
}
public client_authorized( id )
{
SemiClipType[id] = SEMICLIP:player_get_num( id, "SemiClip", "Type" );
gNotify[id] = 0;
}
public client_disconnect( id )
{
if( id == g_iMaxPlayers )
{
new old = g_iMaxPlayers;
for( new i=1; i<old; i++ )
{
if( is_user_connected(i) )
g_iMaxPlayers = i;
}
}
}
public player_touch(id, tid)
{
if( SemiClipType[id] == SEMICLIP_NULL )
semiclip_menu(id);
if( SemiClipType[tid] == SEMICLIP_NULL )
semiclip_menu(tid);
}
public semiclip_menu(id)
{
new trash;
if( player_menu_info(id, trash, trash) )
return;
new data[32], menu = menu_create( "Select Your SemiClip Mode. Say /semiclip to reselect", "semiclip_handler" );
formatex( data, 31, "%d", SEMICLIP_AUTO );
menu_additem(menu, "\yAuto SemiClip \w(careful around doors)", data);
formatex( data, 31, "%d", SEMICLIP_ACTIVE );
menu_additem(menu, "\yActive SemiClip \w(press +use to activate)", data);
formatex( data, 31, "%d", SEMICLIP_NONE );
menu_additem(menu, "\yNo SemiClip \w(people can block you)", data);
menu_addtext(menu, "^n\ySemiClip is used to prevent blocking.^n\wIf you don't know what to pick, just pick \yAuto SemiClip\w.", 0);
menu_display(id, menu);
}
public semiclip_handler(id, menu, item)
{
if( item == MENU_EXIT )
{
menu_destroy(menu);
return PLUGIN_HANDLED;
}
new access, data[128], iName[1], callback;
menu_item_getinfo(menu, item, access, data,127, iName,0, callback);
menu_destroy(menu);
switch( (SemiClipType[id] = SEMICLIP:str_to_num( data )) )
{
case SEMICLIP_NONE:
{
client_print(id, print_chat, "[SemiClip] No SemiClip. Players will always be solid." );
}
case SEMICLIP_AUTO:
{
client_print(id, print_chat, "[SemiClip] Auto SemiClip. SemiClip will auto activate. Be careful around doors." );
}
case SEMICLIP_ACTIVE:
{
client_print(id, print_chat, "[SemiClip] SemiClip Active. Press +use to activate semiclip." );
}
}
client_print(id, print_chat, "[SemiClip] Say /semiclip to reselect your SemiClip Mode." );
player_set_num( id, "SemiClip", "Type", _:SemiClipType[id] );
return PLUGIN_HANDLED;
}
public fw_PlayerSpawn(id)
{
// Not alive or didn't join a team yet
if( !is_user_alive(id) )
return;
g_fSpawnTime[id] = get_gametime();
if( !gNotify[id] && SemiClipType[id] != SEMICLIP_NULL )
{
gNotify[id] = 1;
client_print(id, print_chat, "[SemiClip] Say /semiclip to reselect your SemiClip Mode." );
}
}
public fw_PlayerKilled(victim, attacker, shouldgib)
{
if( get_gametime() - g_fSpawnTime[victim] <= 10.0 )
{
new Float:hp;
pev( victim, pev_health, hp );
if( hp <= 0 )
{
set_pev( victim, pev_health, 100.0 );
}
new Float:origin[3], Float:temp;
pev( victim, pev_origin, origin );
temp = random_float(-100.0,100.0);
origin[0] += temp;
origin[1] += (temp > 0.0) ? (100.0 - temp) : (100.0 + temp);
origin[2] += 100.0;
fm_entity_set_origin(victim, origin);
client_print(victim, print_center, "Moved to avoid Spawn Kill");
_UnStuck(victim, true);
return HAM_SUPERCEDE;
}
return HAM_IGNORED;
}
public fwdPlayerPreThink( plr )
{
static id, last_think;
if( last_think > plr )
{
for( id = 1 ; id <= g_iMaxPlayers ; id++ )
{
if( is_user_alive( id ) )
{
g_Zombie[id] = zp_get_user_zombie( id );
g_bSolid[id] = pev( id, pev_solid ) == SOLID_SLIDEBOX ? true : false;
pev( id, pev_origin, g_fOrigin[id] );
}
else
g_bSolid[id] = false;
}
}
last_think = plr;
switch( SemiClipType[plr] )
{
case SEMICLIP_NULL, SEMICLIP_NONE:
{
return FMRES_IGNORED;
}
case SEMICLIP_AUTO:
{
}
case SEMICLIP_ACTIVE:
{
if( !(entity_get_int(plr, EV_INT_button) & IN_USE) )
return FMRES_IGNORED;
}
}
if( g_bSolid[plr] && !g_Zombie[plr] )
{
for( id = 1 ; id <= g_iMaxPlayers ; id++ )
{
if( g_bSolid[id] && get_distance_f( g_fOrigin[plr], g_fOrigin[id] ) <= DISTANCE && id != plr )
{
if( g_Zombie[plr] != g_Zombie[id] )
return FMRES_IGNORED;
set_pev( id, pev_solid, SOLID_NOT );
g_bHasSemiclip[id] = true;
}
}
}
return FMRES_IGNORED;
}
public fwdPlayerPostThink( plr )
{
static id;
for( id = 1 ; id <= g_iMaxPlayers ; id++ )
{
if( g_bHasSemiclip[id] )
{
set_pev( id, pev_solid, SOLID_SLIDEBOX );
g_bHasSemiclip[id] = false;
}
}
}
public fwdAddToFullPack_Post( es_handle, e, ent, host, hostflags, player, pset )
{
if( player )
{
if( g_bSolid[host] && g_bSolid[ent] && !g_Zombie[host] && !g_Zombie[ent] )
{
switch( SemiClipType[host] )
{
case SEMICLIP_NULL, SEMICLIP_NONE:
{
return FMRES_IGNORED;
}
case SEMICLIP_AUTO:
{
}
case SEMICLIP_ACTIVE:
{
if( !(entity_get_int(host, EV_INT_button) & IN_USE) )
return FMRES_IGNORED;
}
}
if( get_distance_f( g_fOrigin[host], g_fOrigin[ent] ) <= DISTANCE )
{
set_es( es_handle, ES_Solid, SOLID_NOT ); // makes semiclip flawless
switch( get_pcvar_num( g_iCvar[2] ) )
{
case 1:
{
set_es( es_handle, ES_RenderMode, kRenderTransAlpha );
set_es( es_handle, ES_RenderAmt, 85 );
}
case 2:
{
set_es( es_handle, ES_Effects, EF_NODRAW );
set_es( es_handle, ES_Solid, SOLID_NOT );
}
}
}
}
}
return FMRES_IGNORED;
}
// is there a better way to detect changings of g_iCvar[0]?
public fwdClientCommand( plr )
{
// use the forwards just when needed, for good performance
if( !get_pcvar_num( g_iCvar[0] ) && g_bSemiclipEnabled )
{
unregister_forward( FM_PlayerPreThink, g_iForwardId[0] );
unregister_forward( FM_PlayerPostThink, g_iForwardId[1] );
unregister_forward( FM_AddToFullPack, g_iForwardId[2], 1 );
g_bSemiclipEnabled = false;
}
else if( get_pcvar_num( g_iCvar[0] ) && !g_bSemiclipEnabled )
{
g_iForwardId[0] = register_forward( FM_PlayerPreThink, "fwdPlayerPreThink" );
g_iForwardId[1] = register_forward( FM_PlayerPostThink, "fwdPlayerPostThink" );
g_iForwardId[2] = register_forward( FM_AddToFullPack, "fwdAddToFullPack_Post", 1 );
g_bSemiclipEnabled = true;
}
}
public checkstuck()
{
static players[32], pnum, player, i, bool:detect_players;
get_players(players, pnum);
static Float:origin[3], hull;
for( i=0; i<pnum; i++ )
{
player = players[i];
if( is_user_alive(player) )
{
if( !g_bSolid[player] )
{
stuck[player] = 0;
continue;
}
pev(player, pev_origin, origin);
hull = pev(player, pev_flags) & FL_DUCKING ? HULL_HEAD : HULL_HUMAN;
if( !is_hull_vacant(origin, hull,player) && !get_user_noclip(player) )
{
++stuck[player];
if( stuck[player] >= 10 )
{
detect_players = true;
if( !g_Zombie[player] )
{
switch( SemiClipType[player] )
{
case SEMICLIP_NULL, SEMICLIP_NONE:
{
detect_players = true;
}
case SEMICLIP_AUTO:
{
detect_players = false;
}
case SEMICLIP_ACTIVE:
{
if( entity_get_int(player, EV_INT_button) & IN_USE )
detect_players = false;
else
detect_players = true;
}
}
}
if( _UnStuck( player, detect_players ) == 1 )
{
effects(player);
}
stuck[player] = 0;
}
}
else
{
stuck[player] = 0;
}
}
}
}
stock _UnStuck(id, bool:detect_players)
{
new hullsize = (pev(id, pev_flags) & FL_DUCKING) ? HULL_HEAD : HULL_HUMAN;
new Float:origin[3], tr = 0;
pev(id, pev_origin, origin);
if( detect_players )
engfunc(EngFunc_TraceHull, origin, origin, 0, hullsize, id, tr);
else
engfunc(EngFunc_TraceHull, origin, origin, IGNORE_MONSTERS, hullsize, id, tr);
if( !get_tr2(tr,TR_StartSolid) && !get_tr2(tr,TR_AllSolid) && get_tr2(tr,TR_InOpen) )
return -1;
new Float:new_origin[3], distance, i, trace, Float:fraction;
const UNSTUCK_START_DISTANCE = 32;
const UNSTUCK_MAX_ATTEMPTS = 128;
distance = UNSTUCK_START_DISTANCE;
while( distance < 1000 ) { // 1000 is just incase, should never get anywhere near that
for( i = 0; i < UNSTUCK_MAX_ATTEMPTS; i++ ){
new_origin[0] = random_float(origin[0]-distance, origin[0]+distance);
new_origin[1] = random_float(origin[1]-distance, origin[1]+distance);
new_origin[2] = random_float(origin[2]-distance, origin[2]+distance);
if ( fm_trace_hull(new_origin, hullsize, id) == 0 ) {
engfunc(EngFunc_TraceLine, origin, new_origin, IGNORE_MONSTERS, id, trace);
get_tr2(trace, TR_flFraction, fraction);
if( fraction == 1.0 )
{
fm_entity_set_origin(id, new_origin);
return 1;
}
}
}
distance += UNSTUCK_START_DISTANCE;
}
return 0;
}
bool:is_hull_vacant(const Float:origin[3], hull,id) {
static tr;
engfunc(EngFunc_TraceHull, origin, origin, 0, hull, id, tr);
if( !get_tr2(tr, TR_StartSolid) || !get_tr2(tr, TR_AllSolid) ) //get_tr2(tr, TR_InOpen))
return true;
return false;
}
effects(id)
{
set_hudmessage(255,150,50, -1.0, 0.65, 0, 6.0, 1.5,0.1,0.7); // HUDMESSAGE
show_hudmessage(id,"Automatic Unstuck!"); // HUDMESSAGE
message_begin(MSG_ONE_UNRELIABLE,105,{0,0,0},id );
write_short(1<<10); // fade lasts this long duration
write_short(1<<10); // fade lasts this long hold time
write_short(1<<1); // fade type (in / out)
write_byte(20); // fade red
write_byte(255); // fade green
write_byte(255); // fade blue
write_byte(255); // fade alpha
message_end();
client_cmd(id,"spk fvox/blip.wav");
}