#include <amxmodx>
#include <fakemeta>
#include <hamsandwich>
#include <engine>
#include <xs>
/* ==================================================
* [ Enums & Macros ]
* ================================================== */
#define GetPlayerBit(%1,%2) ( %1 & ( 1 << ( %2 & 31 ) ) )
#define SetPlayerBit(%1,%2) ( %1 |= ( 1 << ( %2 & 31 ) ) )
#define ClearPlayerBit(%1,%2) ( %1 &= ~( 1 << ( %2 & 31 ) ) )
#define isPlayerValid(%0) ( 1 <= %0 <= 32 )
#define GetPlayerTeam(%0) get_user_team( %0 )
#define write_coord_f(%0) engfunc( EngFunc_WriteCoord, %0 )
#define GetLaserBeam(%0) entity_get_int( %0, EV_INT_iuser4 )
#define hasRoundStarted() ( ( g_fLastRoundEnd + 5.0 ) < get_gametime( ) )
#define isEntityLaser(%0) ( %0[ 0 ] == 'L' && %0[ 5 ] == 'M' && %0[ 8 ] == 'e' )
#define isEnemy(%0,%1) ( get_user_team( %0 ) != entity_get_int( iEnt, EV_INT_iuser3 ) )
#define TASK_LASER 1111
#define ID_LASER ( iTask - TASK_LASER )
const Float:DAMAGE_PER_SECOND = 25.0;
enum _:Laser_Status {
LS_PowerUp,
LS_Active
}
enum _:Player_Lasers {
PL_Amount,
PL_Maximum,
PL_Deployed
}
new const g_szBreakableCache[ ] = "func_breakable";
new const g_szInfoTargetCache[ ] = "info_target";
new const g_szBeamClassname[ ] = "LaserBeam";
new const g_szLaserClassname[ ] = "LaserMine";
new const g_szLaserModel[ ] = "models/lasermines/laser.mdl";
new const g_szBuySound[ ] = "lasermines/buy.wav";
new const g_szHitSound[ ] = "lasermines/hit.wav";
new const g_szPowerUpSound[ ] = "lasermines/powerup.wav";
new const g_szDeploySound[ ] = "lasermines/deploy.wav";
new const g_szActiveSound[ ] = "lasermines/active.wav";
new const g_szBeamSprite[ ] = "sprites/lasermines/beam.spr";
new g_iPlayerLasers[ 33 ][ Player_Lasers ], g_iBarTime, g_iSayText, g_iBeamSpr, g_iAlive, g_iFrozen, g_iConnected, Float:g_fLastRoundEnd;
/* ===============================================================
* [ Plugin initialization ]
* =============================================================== */
public plugin_precache( )
{
precache_model( g_szLaserModel );
g_iBeamSpr = precache_model( g_szBeamSprite );
precache_sound( g_szBuySound );
precache_sound( g_szHitSound );
precache_sound( g_szPowerUpSound );
precache_sound( g_szDeploySound );
precache_sound( g_szActiveSound );
precache_sound( "debris/bustglass1.wav" );
precache_sound( "debris/bustglass2.wav" );
precache_model( "models/glassgibs.mdl" );
}
public plugin_init( )
{
register_plugin( "Minas Laser", "1.1", "Manu" );
register_clcmd( "say /lm", "CommandLaser" );
register_clcmd( "+setlaser", "CommandLaser" );
register_clcmd( "-setlaser", "CommandLaser" );
register_clcmd( "+dellaser", "CommandLaser" );
register_clcmd( "-dellaser", "CommandLaser" );
register_logevent( "ev_RoundEnd", 2, "1=Round_End" );
register_think( g_szLaserClassname, "fw_LaserThink" );
RegisterHam( Ham_Spawn, "player", "fw_PlayerSpawn_Post", true );
RegisterHam( Ham_Killed, "player", "fw_PlayerKilled_Post", true );
RegisterHam( Ham_Item_PreFrame, "player", "fw_PlayerSpeed_Post", true );
RegisterHam( Ham_TakeDamage, "func_breakable", "fw_BreakableDamage_Pre", false );
g_iBarTime = get_user_msgid( "BarTime" );
g_iSayText = get_user_msgid( "SayText" );
}
public ev_RoundEnd( )
{
new iEnt;
while( ( iEnt = find_ent_by_class( iEnt, g_szLaserClassname ) ) > 0 )
RemoveLaser( iEnt, entity_get_int( iEnt, EV_INT_iuser1 ) );
g_fLastRoundEnd = get_gametime( );
}
public CommandLaser( iId )
{
static szBuffer[ 4 ]; read_argv( 0, szBuffer, 3 );
if( isPlayerValid( iId ) && GetPlayerBit( g_iAlive, iId ) )
{
switch( szBuffer[ 0 ] )
{
case 's':
{
if( g_iPlayerLasers[ iId ][ PL_Amount ] < g_iPlayerLasers[ iId ][ PL_Maximum ] )
{
g_iPlayerLasers[ iId ][ PL_Amount ]++;
PrintColor( iId, "^x04[Lasers]^x01 Compraste un laser. [^x04 %d^x01 de^x04 %d^x01 ]", g_iPlayerLasers[ iId ][ PL_Amount ], g_iPlayerLasers[ iId ][ PL_Maximum ] );
emit_sound( iId, CHAN_ITEM, g_szBuySound, VOL_NORM, ATTN_IDLE, 0, PITCH_NORM );
}
else
PrintColor( iId, "^x04[Lasers]^x01 No puedes^x04 comprar^x01 lasers." );
}
case '+':
{
switch( szBuffer[ 1 ] )
{
case 's':
{
if( !isLaserPlaceable( iId ) )
{
PrintColor( iId,"^x04[Lasers]^x01 No puedes^x04 crear^x01 lasers." );
return PLUGIN_HANDLED;
}
set_task( 1.2, "CreateLaser", iId+TASK_LASER );
}
case 'd':
{
if( !isLaserRemoveable( iId ) )
{
PrintColor( iId, "^x04[Lasers]^x01 No puedes^x04 remover^x01 lasers." )
return PLUGIN_HANDLED;
}
set_task( 1.2, "RetrieveLaser", iId+TASK_LASER );
}
}
ShowUserBar( iId, .iDuration = 1 );
SetPlayerBit( g_iFrozen, iId );
set_pev( iId, pev_maxspeed, 1.0 );
}
case '-':
{
remove_task( iId+TASK_LASER );
ShowUserBar( iId, .iDuration = 0 );
ClearPlayerBit( g_iFrozen, iId );
set_pev( iId, pev_maxspeed, 250.0 );
}
}
}
return PLUGIN_HANDLED;
}
public client_putinserver( iId )
{
ClearPlayerBit( g_iAlive, iId );
ClearPlayerBit( g_iFrozen, iId );
SetPlayerBit( g_iConnected, iId );
g_iPlayerLasers[ iId ][ PL_Amount ] = 1;
g_iPlayerLasers[ iId ][ PL_Maximum ] = 3;
g_iPlayerLasers[ iId ][ PL_Deployed ] = 0;
}
public client_disconnect( iId )
{
ClearPlayerBit( g_iAlive, iId );
ClearPlayerBit( g_iFrozen, iId );
ClearPlayerBit( g_iConnected, iId );
RemoveLasersByOwner( iId );
remove_task( iId+TASK_LASER );
}
public fw_LaserThink( iEnt )
{
if( is_valid_ent( iEnt ) )
{
switch( entity_get_int( iEnt, EV_INT_iuser2 ) )
{
case LS_PowerUp:
{
entity_set_int( iEnt, EV_INT_iuser2, LS_Active );
entity_set_int( iEnt, EV_INT_solid, SOLID_BBOX );
entity_set_float( iEnt, EV_FL_takedamage, 1.0 );
entity_set_float( iEnt, EV_FL_nextthink, get_gametime( ) + 0.25 );
DrawLaserBeam( iEnt );
emit_sound( iEnt, CHAN_VOICE, g_szActiveSound, 0.5, ATTN_NORM, 1, 75 );
}
case LS_Active:
{
static iTrace, iOwner, iVictim, Float:fOrigin[ 3 ], Float:fEnd[ 3 ]; iTrace = create_tr2( );
entity_get_vector( iEnt, EV_VEC_origin, fOrigin );
entity_get_vector( iEnt, EV_VEC_vuser1, fEnd );
engfunc( EngFunc_TraceLine, fOrigin, fEnd, DONT_IGNORE_MONSTERS, iEnt, iTrace );
iVictim = get_tr2( iTrace, TR_pHit );
iOwner = entity_get_int( iEnt, EV_INT_iuser1 );
if( isPlayerValid( iVictim ) && isPlayerValid( iOwner ) && GetPlayerBit( g_iConnected, iOwner ) && GetPlayerBit( g_iAlive, iVictim ) && isEnemy( iVictim, iEnt ) )
{
ExecuteHamB( Ham_TakeDamage, iVictim, iEnt, iOwner, ( DAMAGE_PER_SECOND / 3.0 ), DMG_ENERGYBEAM );
emit_sound( iVictim, CHAN_WEAPON, g_szHitSound, VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
}
free_tr2( iTrace );
set_pev( iEnt, pev_nextthink, get_gametime( ) + 0.1 );
}
}
}
return PLUGIN_HANDLED;
}
public fw_PlayerSpeed_Post( iId )
{
if( GetPlayerBit( g_iFrozen, iId ) )
entity_set_float( iId, EV_FL_maxspeed, 1.0 );
return HAM_IGNORED;
}
public fw_PlayerSpawn_Post( iId )
{
if( is_user_alive( iId ) )
SetPlayerBit( g_iAlive, iId );
return HAM_IGNORED;
}
public fw_PlayerKilled_Post( iVictim, iAttacker, bShoudlgib )
{
ClearPlayerBit( g_iAlive, iVictim );
ClearPlayerBit( g_iFrozen, iVictim );
remove_task( iVictim + TASK_LASER );
}
public fw_BreakableDamage_Pre( iEnt, iInflictor, iAttacker, Float:fDamage, iDamageBits )
{
static szClassname[ 16 ]; entity_get_string( iEnt, EV_SZ_classname, szClassname, charsmax( szClassname ) );
if( isEntityLaser( szClassname ) )
{
if( isPlayerValid( iAttacker ) && GetPlayerBit( g_iAlive, iAttacker ) && !isEnemy( iAttacker, iEnt ) )
return HAM_SUPERCEDE;
if( entity_get_float( iEnt, EV_FL_health ) - fDamage <= 0.0 )
{
RemoveLaser( iEnt, entity_get_int( iEnt, EV_INT_iuser1 ) );
return HAM_SUPERCEDE;
}
}
return HAM_IGNORED;
}
public CreateLaser( iTask )
{
static iEnt;
if( isPlayerValid( ID_LASER ) && GetPlayerBit( g_iAlive, ID_LASER ) )
{
ClearPlayerBit( g_iFrozen, ID_LASER );
ExecuteHamB( Ham_Item_PreFrame, ID_LASER );
if( !hasRoundStarted( ) || !is_valid_ent( ( iEnt = create_entity( g_szBreakableCache ) ) ) )
return;
g_iPlayerLasers[ ID_LASER ][ PL_Amount ]--;
g_iPlayerLasers[ ID_LASER ][ PL_Deployed ]++;
entity_set_model( iEnt, g_szLaserModel );
entity_set_size( iEnt, Float:{ -4.0, -4.0, -4.0 }, Float:{ 4.0, 4.0, 4.0 } );
entity_set_string( iEnt, EV_SZ_classname, g_szLaserClassname );
entity_set_int( iEnt, EV_INT_solid, SOLID_NOT );
entity_set_int( iEnt, EV_INT_movetype, MOVETYPE_FLY );
entity_set_float( iEnt, EV_FL_health, 450.0 );
entity_set_float( iEnt, EV_FL_takedamage, DAMAGE_NO );
entity_set_int( iEnt, EV_INT_iuser1, ID_LASER );
entity_set_int( iEnt, EV_INT_iuser2, LS_PowerUp );
entity_set_int( iEnt, EV_INT_iuser3, GetPlayerTeam( ID_LASER ) );
SetLaserPosition( ID_LASER, iEnt );
entity_set_float( iEnt, EV_FL_frame, 0.0 );
entity_set_float( iEnt, EV_FL_framerate, 0.0 );
entity_set_int( iEnt, EV_INT_body, 3 );
entity_set_int( iEnt, EV_INT_sequence, 7 );
entity_set_float( iEnt, EV_FL_nextthink, get_gametime( ) + 3.0 );
emit_sound( iEnt, CHAN_VOICE, g_szDeploySound, VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
emit_sound( iEnt, CHAN_BODY, g_szPowerUpSound, 0.2, ATTN_NORM, 0, PITCH_NORM );
}
}
public RetrieveLaser( iTask )
{
static iEnt;
if( !is_valid_ent( ( iEnt = isLaserRemoveable( ID_LASER ) ) ) )
return;
RemoveLaser( iEnt, ID_LASER );
g_iPlayerLasers[ ID_LASER ][ PL_Amount ]++;
emit_sound( ID_LASER, CHAN_ITEM, g_szBuySound, VOL_NORM, ATTN_NORM, 0, PITCH_NORM );
}
isLaserPlaceable( iId )
{
if( !hasRoundStarted( ) || g_iPlayerLasers[ iId ][ PL_Amount ] <= 0 || g_iPlayerLasers[ iId ][ PL_Deployed ] >= g_iPlayerLasers[ iId ][ PL_Maximum ] )
return false;
static iTrace, Float:fDistance, Float:fOrigin[ 3 ], Float:fAngles[ 3 ], Float:fEnd[ 3 ]; iTrace = create_tr2( );
entity_get_vector( iId, EV_VEC_origin, fOrigin );
entity_get_vector( iId, EV_VEC_v_angle, fAngles );
angle_vector( fAngles, ANGLEVECTOR_FORWARD, fAngles );
xs_vec_mul_scalar( fAngles, 128.0, fAngles );
xs_vec_add( fOrigin, fAngles, fEnd );
engfunc( EngFunc_TraceLine, fOrigin, fEnd, DONT_IGNORE_MONSTERS, iId, iTrace );
get_tr2( iTrace, TR_flFraction, fDistance );
free_tr2( iTrace );
return ( fDistance < 1.0 ) ? true : false;
}
isLaserRemoveable( iId )
{
static iEnt, iNum;
if( get_user_aiming( iId, iEnt, iNum ) && entity_get_int( iEnt, EV_INT_iuser1 ) == iId && g_iPlayerLasers[ iId ][ PL_Amount ] < g_iPlayerLasers[ iId ][ PL_Maximum ] )
return iEnt;
return 0;
}
SetLaserPosition( const iId,const iEnt )
{
static iTrace, Float:fFraction, Float:fOrigin[ 3 ], Float:fAngles[ 3 ], Float:fEnd[ 3 ]; iTrace = create_tr2( );
entity_get_vector( iId, EV_VEC_origin, fOrigin );
entity_get_vector( iId, EV_VEC_v_angle, fAngles );
angle_vector( fAngles, ANGLEVECTOR_FORWARD, fAngles );
xs_vec_mul_scalar( fAngles, 128.0, fAngles );
xs_vec_add( fOrigin, fAngles, fEnd );
engfunc( EngFunc_TraceLine, fOrigin, fEnd, DONT_IGNORE_MONSTERS, iId, iTrace );
get_tr2( iTrace, TR_flFraction, fFraction );
get_tr2( iTrace, TR_vecEndPos, fEnd );
get_tr2( iTrace, TR_vecPlaneNormal, fOrigin );
free_tr2( iTrace ); iTrace = create_tr2( );
xs_vec_mul_scalar( fOrigin, 8.0, fOrigin );
xs_vec_add( fEnd, fOrigin, fEnd );
entity_set_origin( iEnt, fEnd );
vector_to_angle( fOrigin, fAngles );
entity_set_vector( iEnt, EV_VEC_angles, fAngles );
if( fFraction < 1.0 )
{
xs_vec_mul_scalar( fOrigin, 8192.0, fOrigin );
engfunc( EngFunc_TraceLine, fEnd, fOrigin, IGNORE_MONSTERS, iEnt, iTrace );
get_tr2( iTrace, TR_vecEndPos, fEnd );
free_tr2( iTrace );
}
entity_set_vector( iEnt, EV_VEC_vuser1, fEnd );
}
DrawLaserBeam( iEnt )
{
static iBeam, Float:fColor[ 3 ], Float:fEnd[ 3 ], Float:fOrigin[ 3 ], Float:fMins[ 3 ], Float:fMaxs[ 3 ];
fColor = ( entity_get_int( iEnt, EV_INT_iuser3 ) == 1 ) ? ( Float:{ 255.0,0.0,0.0 } ):( Float:{ 0.0,0.0,255.0 } );
if( !is_valid_ent( ( iBeam = create_entity( g_szInfoTargetCache ) ) ) )
return 0;
entity_set_string( iBeam, EV_SZ_classname, g_szBeamClassname );
entity_set_int( iBeam, EV_INT_flags, entity_get_int( iBeam, EV_INT_flags ) | FL_CUSTOMENTITY );
entity_set_model( iBeam, g_szBeamSprite );
entity_set_int( iBeam, EV_INT_modelindex, g_iBeamSpr );
entity_set_int( iBeam, EV_INT_body, 0 );
entity_set_float( iBeam, EV_FL_scale, 5.0 );
entity_set_float( iBeam, EV_FL_animtime, 255.0 );
entity_set_float( iBeam, EV_FL_renderamt, 255.0 );
entity_set_vector( iBeam, EV_VEC_rendercolor, fColor );
entity_get_vector( iEnt, EV_VEC_vuser1, fEnd );
entity_get_vector( iEnt, EV_VEC_origin, fOrigin );
entity_set_origin( iBeam, fEnd );
entity_set_vector( iBeam, EV_VEC_angles, fOrigin );
fMins[ 0 ] = floatmin( fEnd[ 0 ], fOrigin[ 0 ] ) - fEnd[ 0 ];
fMins[ 1 ] = floatmin( fEnd[ 1 ], fOrigin[ 1 ] ) - fEnd[ 1 ];
fMins[ 2 ] = floatmin( fEnd[ 2 ], fOrigin[ 2 ] ) - fEnd[ 2 ];
fMaxs[ 0 ] = floatmax( fEnd[ 0 ], fOrigin[ 0 ] ) - fEnd[ 0 ];
fMaxs[ 1 ] = floatmax( fEnd[ 1 ], fOrigin[ 1 ] ) - fEnd[ 1 ];
fMaxs[ 2 ] = floatmax( fEnd[ 2 ], fOrigin[ 2 ] ) - fEnd[ 2 ];
entity_set_size( iBeam, fMins, fMaxs );
entity_set_vector( iBeam, EV_VEC_mins, fMins );
entity_set_vector( iBeam, EV_VEC_maxs, fMaxs );
entity_set_int( iEnt, EV_INT_iuser4, iBeam );
return 1;
}
RemoveLasersByOwner( const iId )
{
new iEnt;
while( ( iEnt = find_ent_by_class( iEnt, g_szLaserClassname ) ) > 0 )
{
if( entity_get_int( iEnt, EV_INT_iuser1 ) != iId )
continue;
RemoveLaser( iEnt );
}
}
RemoveLaser( const iEnt, const iOwner = 0 )
{
static iBeam; iBeam = GetLaserBeam( iEnt );
if( is_valid_ent( iBeam ) ) remove_entity( iBeam );
if( isPlayerValid( iOwner ) ) g_iPlayerLasers[ iOwner ][ PL_Deployed ]--;
entity_set_int( iEnt, EV_INT_flags, entity_get_int( iEnt, EV_INT_flags ) | FL_KILLME );
}
ShowUserBar( const iId, const iDuration )
{
message_begin( MSG_ONE_UNRELIABLE, g_iBarTime, _, iId );
write_short( iDuration );
message_end( );
}
PrintColor( iId, szText[ ], any:... )
{
static szBuffer[ 192 ]; vformat( szBuffer, charsmax( szBuffer ), szText, 3 );
if( !iId )
{
message_begin( MSG_BROADCAST, g_iSayText, _, iId );
write_byte( 1 );
write_string( szBuffer );
message_end( );
}
else
{
message_begin( MSG_ONE_UNRELIABLE, g_iSayText, _, iId );
write_byte( iId );
write_string( szBuffer );
message_end( );
}
}