Code:
/*
[ZP] Extra Item: Tau Cannon
Copyright (C) 2009-2010 by NiHiLaNTh
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 3 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
In addition, as a special exception, the author gives permission to
link the code of this program with the Half-Life Game Engine ("HL
Engine") and Modified Game Libraries ("MODs") developed by Valve,
L.L.C ("Valve"). You must obey the GNU General Public License in all
respects for all of the code used other than the HL Engine and MODs
from Valve. If you modify this file, you may extend this exception
to your version of the file, but you are not obligated to do so. If
you do not wish to do so, delete this exception statement from your
version.
--- Introduction ---
This plugin adds new weapon - Tau Cannon.Basically, this is almost
the same weapon as in Half-Life.An experimental, highly unstable weapon.
One of the most important abilities is that it can shoot through walls,
making it so that you can't take cover against it. The gauss's primary
fire shoots out tiny spurts that are only effective in close to medium
range due to its erratic spread. You can charge up the gauss by holding
down alternate fire; the longer you charge it up, the stronger it gets.
The longer you charge it up is directly proportional to the thickness
of the wall you can shoot through. Lookout campers, retribution has come.
---CVARs---
zp_tcannon_oneround - Should Tau Cannon be in players inventory only for 1 round?
zp_tcannon_dmgprim - Primary attack damage
zp_tcannon_dmgsec - Maximal secondary attack damage
zp_tcannon_clip - Clip amount
--- Credits ---
Arkshine, HL SDK, meTaLiCroSS and more...
--- Changelog ---
1.0 - Initial release.
1.1 - Added some statics
1.2 - Fixed ammo buy bug
- Fixed possible server crash
*/
#include < amxmodx >
#include < cstrike >
#include < csx >
#include < engine >
#include < fakemeta >
#include < hamsandwich >
#include < fun >
#include < xs >
#include < zombieplague >
#include < zmvip >
// Plugin information
#define Plugin "[ZP] Extra Item: Tau Cannon"
#define Version "1.2"
#define Author "NiHiLaNTh"
// Maxplayers
const MaxPlayers = 32
// Weapon models
new const g_szModelGaussP[ ] = "models/p_gauss.mdl"
new const g_szModelGaussV[ ] = "models/v_alt_gauss.mdl"
new const g_szModelGaussW[ ] = "models/w_gauss.mdl"
// Weapon sounds
new const g_szSoundGaussFire[ ] = "weapons/gauss2.wav"
new const g_szSoundGaussSpin[ ] = "ambience/pulsemachine.wav"
new const g_szSoundElectro1[ ] = "weapons/electro4.wav"
new const g_szSoundElectro2[ ] = "weapons/electro5.wav"
new const g_szSoundElectro3[ ] = "weapons/electro6.wav"
// Some gauss/beam stuff
#define GAUSS_REFIRERATE 0.2 // Primary attack
#define GAUSS_REFIRERATE2 0.1 // Secondary attack(you shouldnt change this!)
#define GAUSS_RECOIL -2.0 // Only X axis!
#define GAUSS_CHARGETIME 4.0 // From HLSDK
#define GAUSS_RELOADTIME 2.0 // Reload time
#define BEAM_RED 255 // Red amount
#define BEAM_GREEN 128 // Green amount
#define BEAM_BLUE 0 // Blue amount
#define BEAM_ALPHA 255 // Brightness(Alpha)
#define BALL_AMOUNT 8 // How many balls should appear :p
// Ammo given when buy weapons
new const BUYAMMO[] = { -1, 13, -1, 30, -1, 8, -1, 12, 30, -1, 30, 50, 12, 30, 30, 30, 12, 30,
1, 30, 30, 8, 30, 30, 30, -1, 7, 30, 30, -1, 50 }
// Max. bp ammo amount
new const MAXBPAMMO[] = { -1, 52, -1, 90, 1, 32, 1, 100, 90, 1, 120, 100, 100, 90, 90, 90, 100, 120,
5, 120, 200, // This is gauss max bp ammo.Change it if you want!
32, 90, 120, 90, 2, 35, 90, 90, -1, 100 }
// Weapon ammo ID's
new const AMMOID[] = { -1, 9, -1, 2, 12, 5, 14, 6, 4, 13, 10, 7, 6, 4, 4, 4, 6, 10,
1, 10, 3, 5, 4, 10, 2, 11, 8, 4, 2, -1, 7 }
// Player variables
new g_iHasGauss[ MaxPlayers+1 ] // Whether player has gauss
new g_iSoundState[ MaxPlayers+1 ] // Weapon sound state
new g_bInAttack[ MaxPlayers+1 ] // Current gauss attack state
new g_iCurrentWeapon[ MaxPlayers+1 ] // Current weapon player is holding
new Float:g_flLastShotTime[ MaxPlayers+1 ] // Last shot time
new Float:g_fflPlayAfterShock[ MaxPlayers+1 ] // Play aftershock sound
new Float:g_flWeaponIdleTime[ MaxPlayers+1 ] // Weapon idle time
new Float:g_flNextAmmoBurn[ MaxPlayers+1 ] // Next ammo burn time
new Float:g_flStartCharge[ MaxPlayers+1 ] // Weapon start charge
new Float:g_flAmmoStartCharge[ MaxPlayers+1 ] // Ammo start charge
new bool:g_bIsAlive[ MaxPlayers+1 ] // Whether player is alive
new bool:g_bIsConnected[ MaxPlayers+1 ] // Whether player is connected
new bool:g_bPrimaryFire[ MaxPlayers+1 ] // Does this weapon is using primary attack ?
new bool:g_bKilledByLaser[ MaxPlayers+1 ] // Imma firin mah lazor O.o
// CVAR pointers
new cvar_oneround // Whether gun should be only for 1 round
new cvar_dmgprim // Primary attack damage
new cvar_dmgsec // Secondary attack damage
new cvar_clip // Clip amount
// Cached CVAR
new g_pOneRound
new Float:g_pDmgPrim
new Float:g_pDmgSec
new g_pClip
// Global varibles
new g_iMaxPlayers // Maxplayers
new bool:g_bGameRestart // Detect game restart
new g_iBeam // Beam sprite
new g_iBalls // Balls :p
new g_iGaussID // Item ID
new gmsgScreenFade // Screen fade
new gmsgAmmoPickup // Ammo pickup
// CS Offsets
const m_pPlayer = 41
const m_flNextPrimaryAttack = 46
const m_flNextSecondaryAttack = 47
const m_flTimeWeaponIdle = 48
const m_iPrimaryAmmoType = 49
const m_iClip = 51
const m_fInReload = 54
const m_flNextAttack = 83
const m_rgAmmo_player_Slot0 = 376
// Macro
#define is_user_valid_connected(%1) ( 1 <= %1 <= g_iMaxPlayers && g_bIsConnected [ %1 ] )
#define is_user_in_water(%1) ( pev ( %1, pev_waterlevel ) == 3 )
#define VectorSubtract(%1,%2,%3) ( %3[ 0 ] = %1[ 0 ] - %2[ 0 ], %3[ 1 ] = %1[ 1 ] - %2[ 1 ], %3[ 2 ] = %1[ 2 ] - %2[ 2
] )
#define VectorAdd(%1,%2,%3) ( %3[ 0 ] = %1[ 0 ] + %2[ 0 ], %3[ 1 ] = %1[ 1 ] + %2[ 2 ], %3[ 2 ] = %1[
2 ] + %2[ 2 ] )
#define VectorScale(%1,%2,%3) ( %3[ 0 ] = %2 * %1[ 0 ], %3[ 1 ] = %2 * %1[ 1 ], %3[ 2 ] = %2 * %1[ 2 ] )
#define VectorLength(%1) ( floatsqroot ( %1[ 0 ] * %1[ 0 ] + %1[ 1 ] * %1[ 1 ] + %1[ 2 ] * %1[ 2 ] ) )
// Hack!Custom fields
#define pev_weaponkey pev_impulse
#define pev_bpammo pev_iuser3
// Misc stuff
#define FCVAR_FLAGS ( FCVAR_SERVER | FCVAR_SPONLY | FCVAR_UNLOGGED )
#define GAUSS_WEAPONKEY 42856
#define NULLENT -1
#define FFADE_IN 0x0000
#define UNIT_SECOND (1<<12)
// Entity classnames
new const g_szClassPlayer[ ] = "player"
new const g_szClassM249[ ] = "weapon_m249"
// Primary weapon bitsum
const PRIMARY_WEAPONS_BITSUM =
(1<<CSW_SCOUT)|(1<<CSW_XM1014)|(1<<CSW_MAC10)|(1<<CSW_AUG)|(1<<CSW_UMP45)|(1<<CSW_SG550)|(1<<CSW_GA
LIL)|(1<<CSW_FAMAS)|(1<<CSW_AWP)|(1<<CSW_MP5NAVY)|(1<<CSW_M249)|(1<<CSW_M3)|(1<<CSW_M4A1)|(1<<CSW_TM
P)|(1<<CSW_G3SG1)|(1<<CSW_SG552)|(1<<CSW_AK47)|(1<<CSW_P90)
// Animation sequnces
enum
{
gauss_idle,
gauss_idle2,
gauss_fidget,
gauss_spinup,
gauss_spin,
gauss_fire,
gauss_fire2,
gauss_holster,
gauss_draw
}
// Precache
public plugin_precache( )
{
// Weapon models
precache_model( g_szModelGaussP )
precache_model( g_szModelGaussV )
precache_model( g_szModelGaussW )
// Sounds
precache_sound( g_szSoundGaussFire )
precache_sound( g_szSoundGaussSpin )
precache_sound( g_szSoundElectro1 )
precache_sound( g_szSoundElectro2 )
precache_sound( g_szSoundElectro3 )
precache_sound( "items/9mmclip1.wav" )
// Sprites
g_iBeam = precache_model( "sprites/smoke.spr" )
g_iBalls = precache_model( "sprites/hotglow.spr" )
}
// Initialization
public plugin_init( )
{
// New plugin
register_plugin( Plugin, Version, Author )
// For Game-Monitor support
register_cvar( "zp_tcannon_version", Version, FCVAR_FLAGS )
// New extra item
g_iGaussID = zv_register_extra_item( "Tau Cannon", 60, ZV_TEAM_HUMAN )
// Client commands
register_clcmd( "buyammo1", "fn_BuyAmmo" )
register_clcmd( "buyammo2", "fn_BuyAmmo" )
// Events
register_event( "CurWeapon", "EV_CurWeapon", "be", "1=1" )
register_event( "DeathMsg", "EV_DeathMsg", "a" )
register_event( "HLTV", "EV_RoundStart", "a", "1=0", "2=0" )
register_event( "TextMsg", "EV_GameRestart", "a", "2=#Game_Commencing", "2=#Game_will_restart_in" )
// FakeMeta forwards
register_forward( FM_SetModel, "fw_SetModel" )
register_forward( FM_CmdStart, "fw_CmdStart" )
register_forward( FM_UpdateClientData, "fw_UpdateClientData_Post", 1 )
register_forward( FM_PlayerPreThink, "fw_PlayerPreThink" )
// HamSandwich forwards
RegisterHam( Ham_Spawn, g_szClassPlayer, "fw_PlayerSpawn_Post", 1 )
RegisterHam( Ham_Item_Deploy, g_szClassM249, "fw_TCannonDeploy_Post", 1 )
RegisterHam( Ham_Item_Holster, g_szClassM249, "fw_TCannonHolster_Post", 1 )
RegisterHam( Ham_Item_AddToPlayer, g_szClassM249, "fw_TCannonAddToPlayer" )
RegisterHam( Ham_Item_PostFrame, g_szClassM249, "fw_TCannonPostFrame" )
RegisterHam( Ham_Weapon_Reload, g_szClassM249, "fw_TCannonReload_Post", 1 )
// CVARs are in Load_Cvars( ) function!
// Messages
register_message( get_user_msgid( "DeathMsg" ), "fn_DeathMsg" )
gmsgScreenFade = get_user_msgid( "ScreenFade" )
gmsgAmmoPickup = get_user_msgid( "AmmoPickup" )
// Store maxplayers in a global variable
g_iMaxPlayers = get_maxplayers( )
}
// Configuration
public plugin_cfg( )
{
// Cache CVARs
set_task( 1.5, "Load_Cvars" )
}
// ------------------------------- Game Events ----------------------------------------
// Client connected
public client_connect( Player )
{
// Make a lot of updates
g_iHasGauss[ Player ] = false
g_bInAttack[ Player ] = 0
g_fflPlayAfterShock[ Player ] = 0.0
g_flWeaponIdleTime[ Player ] = 0.0
g_bPrimaryFire[ Player ] = false
g_bIsAlive[ Player ] = false
g_bIsConnected[ Player ] = true
}
// Client disconnected
public client_disconnect( Player )
{
// Only few important updates
g_bIsAlive[ Player ] = false
g_bIsConnected[ Player ] = false
}
// Someone selected our extra item
public zv_extra_item_selected( Player, Item )
{
// Tau Cannon
if ( Item == g_iGaussID )
{
// Drop all primary weapons
UTIL_DropPrimary( Player )
// Update
g_iHasGauss[ Player ] = true
// Give m249
give_item( Player, "weapon_m249" )
// Find weapon entity
new iEnt = find_ent_by_owner( NULLENT, g_szClassM249, Player )
// Apply new clip
cs_set_weapon_ammo( iEnt, g_pClip )
// Back pack ammo
cs_set_user_bpammo( Player, CSW_M249, MAXBPAMMO[ 20 ] )
}
}
// Player is trying to buy something
public fn_BuyAmmo( Player )
{
// Not alive
if( !g_bIsAlive[ Player ] )
return PLUGIN_HANDLED
// Dont have Tau Cannon
if( !g_iHasGauss[ Player ] )
return PLUGIN_CONTINUE
// Retrieve ammo pack amount
static iAmmoPack
iAmmoPack = zp_get_user_ammo_packs( Player )
// Out of ammo packs
if( iAmmoPack <= 0 )
return PLUGIN_HANDLED
// Get players weapons
static weapons[ 32 ], num, i, currentammo, weaponid, refilled
num = 0 // reset passed weapons count (bugfix)
refilled = false
get_user_weapons( Player, weapons, num )
// Loop through them and give the right ammo type
for( i = 0; i < num; i++ )
{
// Prevents re-indexing the array
weaponid = weapons[ i ]
// Primary and secondary only
if( MAXBPAMMO[ weaponid ] > 2 )
{
// Get current ammo of the weapon
currentammo = cs_get_user_bpammo( Player, weaponid)
// Check if we are close to the BP ammo limit
if (currentammo < MAXBPAMMO[weaponid]-BUYAMMO[weaponid])
{
// Flash ammo in hud
message_begin(MSG_ONE_UNRELIABLE, gmsgAmmoPickup, _, Player )
write_byte(AMMOID[weaponid]) // ammo id
write_byte(BUYAMMO[weaponid]) // ammo amount
message_end()
// Increase BP ammo
cs_set_user_bpammo ( Player, weaponid, currentammo + BUYAMMO[weaponid])
refilled = true
}
else if (currentammo < MAXBPAMMO[weaponid])
{
// Flash ammo in hud
message_begin(MSG_ONE_UNRELIABLE, gmsgAmmoPickup, _, Player )
write_byte(AMMOID[weaponid]) // ammo id
write_byte(MAXBPAMMO[weaponid]-currentammo) // ammo amount
message_end()
// Reached the limit
cs_set_user_bpammo ( Player, weaponid, MAXBPAMMO[weaponid])
refilled = true
}
}
}
// Weapons already have full ammo
if (!refilled) return PLUGIN_HANDLED
// Deduce ammo packs, play clip purchase sound, and notify the player
zp_set_user_ammo_packs( Player, --iAmmoPack )
engfunc(EngFunc_EmitSound, Player, CHAN_ITEM, "items/9mmclip1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM)
client_print( Player, print_chat, "[ZP] You purchased extra ammo for your guns." )
return PLUGIN_HANDLED
}
// Current weapon player is holding
public EV_CurWeapon( Player )
{
// Not alive
if( !g_bIsAlive[ Player ] )
return PLUGIN_CONTINUE
// Update
g_iCurrentWeapon[ Player ] = read_data( 2 )
return PLUGIN_CONTINUE
}
// Someone died
public EV_DeathMsg( )
{
// Get victim
static iVictim
iVictim = read_data( 2 )
// Not connected
if( !is_user_valid_connected( iVictim ) )
return
// Update
g_bIsAlive[ iVictim ] = false
// Check if victim has gauss
if( g_iHasGauss[ iVictim ] && !is_user_bot( iVictim ) )
{
// Force to drop
engclient_cmd( iVictim, "drop weapon_m249" )
}
}
// Round started
public EV_RoundStart( )
{
// Restart/One round only
if( g_bGameRestart || g_pOneRound )
{
// Reset array value
arrayset( g_iHasGauss, false, MaxPlayers+1 )
}
// Update
g_bGameRestart = false
}
// Game restart
public EV_GameRestart( )
{
// Update
g_bGameRestart = true
}
// Hook death message
public fn_DeathMsg( Player, Dest, iEntity )
{
// Get victim
static iVictim, iKiller
iKiller = get_msg_arg_int( 1 )
iVictim = get_msg_arg_int( 2 )
// Not connected
if( !is_user_valid_connected( iVictim ) || iKiller == iVictim )
return PLUGIN_CONTINUE
// We were killed by laser
if ( g_bKilledByLaser[ iVictim ] )
{
// Replace name in console
set_msg_arg_string ( 4, "tau cannon" )
}
return PLUGIN_CONTINUE
}
// ------------------------------- Forwards ----------------------------------------
// Replace world model
public fw_SetModel ( Entity, const Model [ ] )
{
// Prevent invalid entity messages
if( !pev_valid( Entity ) )
return FMRES_IGNORED
// Not w_awp.mdl
if( !equal( Model, "models/w_m249.mdl" ) )
return FMRES_IGNORED
// Get entity classname
static szClassname[ 32 ]
pev( Entity, pev_classname, szClassname, charsmax( szClassname ) )
// Not weaponbox
if( !equal( szClassname, "weaponbox" ) )
return FMRES_IGNORED
// Get owner
static iOwner
iOwner = pev( Entity, pev_owner )
// Get awp ID
static iWeaponID
iWeaponID = find_ent_by_owner( NULLENT, g_szClassM249, Entity )
// Make sure that we have gauss
if( g_iHasGauss [ iOwner ] && is_valid_ent( iWeaponID ) )
{
// Hack! Store weaponkey
set_pev( iWeaponID, pev_weaponkey, GAUSS_WEAPONKEY )
// Hack! Store bp ammo
set_pev( iWeaponID, pev_bpammo, cs_get_user_bpammo( iOwner, CSW_M249 ) )
// Update
g_iHasGauss[ iOwner ] = false
// Replace models
engfunc( EngFunc_SetModel, Entity, g_szModelGaussW )
return FMRES_SUPERCEDE
}
return FMRES_IGNORED
}
// Command start
public fw_CmdStart( Player, UC_Handle, Seed )
{
// Not alive/dont have gauss/not m249
if( !g_bIsAlive[ Player ] || !g_iHasGauss[ Player ] || g_iCurrentWeapon[ Player ] != CSW_M249 )
return FMRES_IGNORED
// Retrieve pressed button bitsum
static iButtons
iButtons = get_uc( UC_Handle, UC_Buttons )
// Retrieve game time
static Float:flGameTime
flGameTime = get_gametime( )
// Retrieve weapon entity
static iEnt
iEnt = find_ent_by_owner( NULLENT, g_szClassM249, Player )
// Retrieve clip amount
static iClip
iClip = cs_get_weapon_ammo( iEnt )
// Primary attack
if( iButtons & IN_ATTACK )
{
// Remove attack buttons from their button mask
iButtons &= ~IN_ATTACK
set_uc( UC_Handle, UC_Buttons, iButtons )
// Prevent too fast shooting
if( flGameTime - g_flLastShotTime[ Player ] < GAUSS_REFIRERATE )
return FMRES_IGNORED
// Dont fire while reloading
if( get_pdata_int( iEnt, m_fInReload, 4 ) )
return FMRES_IGNORED
// Not enough clip/under water
if( iClip < 2 || is_user_in_water( Player ) )
{
// Emit empty sound
ExecuteHamB( Ham_Weapon_PlayEmptySound, iEnt )
return FMRES_IGNORED
}
// Update
g_bPrimaryFire[ Player ] = true
// Start to fire
StartFire( Player )
// Decrease clip
cs_set_weapon_ammo( iEnt, iClip-2 )
// Reset weapon attack status
g_bInAttack[ Player ] = 0
// Set time when idle animation should be played
g_flWeaponIdleTime[ Player ] = flGameTime + 1.0
// Remember last shot time
g_flLastShotTime[ Player ] = flGameTime
}
// Secondary attack
else if( iButtons & IN_ATTACK2 )
{
// Prevent too fast shooting
if( flGameTime - g_flLastShotTime[ Player ] < GAUSS_REFIRERATE2 )
return FMRES_IGNORED
// Dont fire while reloading
if( get_pdata_int( iEnt, m_fInReload, 4 ) )
return FMRES_IGNORED
// Are we swimming ?
if( is_user_in_water( Player ) )
{
// We are in a middle of attack
if( g_bInAttack[ Player ] != 0 )
{
// Stop attack
emit_sound( Player, CHAN_WEAPON, g_szSoundElectro1, VOL_NORM, ATTN_NORM, 0,
80 + random_num( 0, 0x3f ) )
// Gun idle
UTIL_PlayWeaponAnimation( Player, gauss_idle )
return FMRES_IGNORED
}
else
{
// Empty sound
ExecuteHamB( Ham_Weapon_PlayEmptySound, iEnt )
return FMRES_IGNORED
}
}
// Get player oldbuttons
static iOldButtons
iOldButtons = pev( Player, pev_oldbuttons )
// Make sure that we are holding secondary attack button
if( iOldButtons & IN_ATTACK2 )
{
// Which attack state do we have
switch ( g_bInAttack[ Player ] )
{
case 0: // Attack start
{
// Out of ammo
if ( iClip <= 0 )
{
ExecuteHamB( Ham_Weapon_PlayEmptySound, iEnt )
return FMRES_IGNORED
}
// We aren't using primary attack anymore
g_bPrimaryFire[ Player ] = false
// Decrease clip
cs_set_weapon_ammo( iEnt, --iClip )
// Update
g_flNextAmmoBurn[ Player ] = flGameTime
// Send spinup animation
UTIL_PlayWeaponAnimation( Player, gauss_spinup )
// Update attack state
g_bInAttack[ Player ] = 1
// Next idle time
g_flWeaponIdleTime[ Player ] = flGameTime + 0.5
// Update
g_flStartCharge[ Player ] = flGameTime
g_flAmmoStartCharge[ Player ] = flGameTime + GAUSS_CHARGETIME
// Update sound state
g_iSoundState[ Player ] = 0
// Spin sound
emit_sound( Player, CHAN_WEAPON, g_szSoundGaussSpin, VOL_NORM,
ATTN_NORM, g_iSoundState[Player ], 110 )
// Change sound state
g_iSoundState[ Player ] = SND_CHANGE_PITCH
}
case 1: // In a middle of attack
{
if( g_flWeaponIdleTime[ Player ] < flGameTime )
{
// Spin anim
UTIL_PlayWeaponAnimation( Player, gauss_spin )
// Update state
g_bInAttack[ Player ] = 2
}
}
default: // End of attack
{
// During the charging process, eat one bit of ammo every once in a while
if( flGameTime >= g_flNextAmmoBurn[ Player ] && g_flNextAmmoBurn[ Player ] !=
1000 )
{
// Decrease clip
cs_set_weapon_ammo( iEnt, --iClip )
// Next time when ammo should be decreased
g_flNextAmmoBurn[ Player ] = flGameTime + 0.1
}
// Shit!We run out of ammo
if( iClip <= 0 )
{
// Force gun to fire
StartFire( Player )
// Reset weapon state
g_bInAttack[ Player ] = 0
// Set next idle time
g_flWeaponIdleTime[ Player ] = flGameTime + 1.0
}
// Gun is fully charged up
if( flGameTime >= g_flAmmoStartCharge[ Player ] )
{
// Dont eat any more ammo!
g_flNextAmmoBurn[ Player ] = 1000.0
}
// Calculate pitch
static Float:flPitch
flPitch = ( flGameTime - g_flStartCharge[ Player ] ) * ( 150 /
GAUSS_CHARGETIME ) + 100
// Pitch shouldnt be THAT big
if ( flPitch > 250 )
{
flPitch = 250.0
}
// Spin sound
emit_sound( Player, CHAN_WEAPON, g_szSoundGaussSpin, VOL_NORM,
ATTN_NORM, ( g_iSoundState[ Player ] == SND_CHANGE_PITCH ) ? 1 : 0, floatround( flPitch ) )
// Hack for going through level transitions
g_iSoundState[ Player ] = SND_CHANGE_PITCH
// We are charing way too long!
if( g_flStartCharge[ Player ] < flGameTime - 10 )
{
// ZAP!
emit_sound( Player, CHAN_WEAPON, g_szSoundElectro1,
VOL_NORM, ATTN_NORM, 0, 80 + random_num( 0, 0x3f ) )
emit_sound( Player, CHAN_VOICE, g_szSoundElectro3, VOL_NORM,
ATTN_NORM, 0, 80 + random_num( 0, 0x3f ) )
// Reset fire state
g_bInAttack[ Player ] = 0
// Next idle time
g_flWeaponIdleTime[ Player ] = flGameTime + 1.0
// Damage player
ExecuteHamB( Ham_TakeDamage, Player, 0, Player, 50.0,
DMG_SHOCK )
// Make screen fade
UTIL_ScreenFade( Player, UNIT_SECOND*2, UNIT_SECOND/2,
FFADE_IN, 255, 128, 0, 128 )
// Idle animation
UTIL_PlayWeaponAnimation( Player, gauss_idle )
}
}
}
// Update
g_flLastShotTime[ Player ] = flGameTime
}
}
return FMRES_HANDLED
}
// Update client data post
public fw_UpdateClientData_Post ( Player, SendWeapons, CD_Handle )
{
// Not alive / dont have gauss/ not m249
if ( !g_bIsAlive [ Player ] || !g_iHasGauss [ Player ] || g_iCurrentWeapon [ Player ] != CSW_M249 )
return FMRES_IGNORED
// Block default sounds/animations
set_cd ( CD_Handle, CD_flNextAttack, halflife_time ( ) + 0.001 )
return FMRES_HANDLED
}
// Player pre think
public fw_PlayerPreThink( Player )
{
// Not alive / dont have gauss/ not m249
if ( !g_bIsAlive [ Player ] || !g_iHasGauss [ Player ] || g_iCurrentWeapon [ Player ] != CSW_M249 )
return
// Play aftershock discharge
if( g_fflPlayAfterShock[ Player ] && g_fflPlayAfterShock[ Player ] < get_gametime( ) )
{
// Randomly play sound
switch( random_num(0, 3 ) )
{
case 0: emit_sound( Player, CHAN_WEAPON, g_szSoundElectro1,random_float( 0.7, 0.8 ),
ATTN_NORM, 0, PITCH_NORM )
case 1: emit_sound( Player, CHAN_WEAPON, g_szSoundElectro2,random_float( 0.7, 0.8 ),
ATTN_NORM, 0, PITCH_NORM )
case 2: emit_sound( Player, CHAN_WEAPON, g_szSoundElectro3,random_float( 0.7, 0.8 ),
ATTN_NORM, 0, PITCH_NORM )
case 3: return // No sound
}
// Reset discharge
g_fflPlayAfterShock[ Player ] = 0.0
}
// Check if we are in a middle of attack
if( g_bInAttack[ Player ] != 0 )
{
// Check if have released attack2 button
if( get_gametime( ) - g_flLastShotTime[ Player ] > 0.2 )
{
// Start to fire
StartFire( Player )
// Reset attack state
g_bInAttack[ Player ] = 0
// Next idle time
g_flWeaponIdleTime[ Player ] = get_gametime( ) + 2.0
}
}
else
{
// Force to idle
WeaponIdle( Player )
}
}
// Player respawned
public fw_PlayerSpawn_Post( Player )
{
// Not alive
if( !is_user_alive( Player ) )
return
// Update
g_bIsAlive[ Player ] = true
}
// Guass deploy
public fw_TCannonDeploy_Post( iEnt )
{
// Get owner
static Player
Player = get_pdata_cbase( iEnt, m_pPlayer, 4 )
// Does this player has gauss?
if ( g_iHasGauss[ Player ] )
{
// Replace models
set_pev( Player, pev_viewmodel2, g_szModelGaussV )
set_pev( Player, pev_weaponmodel2, g_szModelGaussP )
// Deploy animation
UTIL_PlayWeaponAnimation( Player, gauss_draw )
// Reset aftershock
g_fflPlayAfterShock[ Player ] = 0.0
}
}
// Gauss holster
public fw_TCannonHolster_Post( iEnt )
{
// Get owner
static Player
Player = get_pdata_cbase( iEnt, m_pPlayer, 4 )
// Does this player has gauss?
if ( g_iHasGauss[ Player ] )
{
// Check if player is still attacking
if( g_bInAttack[ Player ] )
{
// Bug!Bug!Stop spin sound
emit_sound( Player, CHAN_WEAPON, g_szSoundGaussSpin, 0.0, 0.0, SND_STOP, 0 )
// Attack
StartFire( Player )
}
// Holster animation
UTIL_PlayWeaponAnimation( Player, gauss_holster )
// Reset attack status
g_bInAttack[ Player ] = 0
}
}
// Add Gauss to players inventory
public fw_TCannonAddToPlayer( iEnt, Player )
{
// Prevent run-time errors
if( is_valid_ent( iEnt ) && is_user_valid_connected( Player ) )
{
// Seems that player has picked up a gauss
if( pev( iEnt, pev_weaponkey ) == GAUSS_WEAPONKEY )
{
// Update variable
g_iHasGauss[ Player ] = true
// Update bp ammo
cs_set_user_bpammo( Player, CSW_M249, pev( iEnt, pev_bpammo ) )
// Reset weapon options
set_pev( iEnt, pev_weaponkey, 0 )
set_pev( iEnt, pev_bpammo, 0 )
return HAM_HANDLED
}
}
return HAM_IGNORED
}
// Gauss post frame
public fw_TCannonPostFrame( iEnt )
{
// Get owner
static iOwner
iOwner = get_pdata_cbase( iEnt, m_pPlayer, 4 )
// Does this player has gauss?
if ( g_iHasGauss[ iOwner ] )
{
// Reload offset
static fInReload
fInReload = get_pdata_int ( iEnt, m_fInReload,4 )
// Next attack time
static Float:flNextAttack
flNextAttack = get_pdata_float (iOwner, m_flNextAttack, 5 )
// Clip
static iClip
iClip = get_pdata_int ( iEnt, m_iClip, 4 )
// Ammo type
static iAmmoType
iAmmoType = m_rgAmmo_player_Slot0 + get_pdata_int ( iEnt, m_iPrimaryAmmoType, 4 )
// BP ammo
static iBpAmmo
iBpAmmo = get_pdata_int ( iOwner, iAmmoType, 5 )
// Reloading
if ( fInReload && flNextAttack <= 0.0 )
{
// Calculate the difference
static j
j = min ( g_pClip - iClip, iBpAmmo )
// Set new clip
set_pdata_int ( iEnt, m_iClip, iClip + j, 4 )
// Decrease 'x' bullets from backpack(depending on new clip)
set_pdata_int( iOwner, iAmmoType, iBpAmmo-j, 5 )
// Not reloding anymore
set_pdata_int ( iEnt, m_fInReload, 0, 4 )
fInReload = 0
}
// Get buttons
static iButton ; iButton = pev ( iOwner, pev_button)
// Attack/Attack2 buttons and next prim/sec attack time hasnt' come yet
if( ( iButton & IN_ATTACK2 && get_pdata_float ( iEnt, m_flNextSecondaryAttack, 4 ) <= 0.0)
|| ( iButton & IN_ATTACK && get_pdata_float ( iEnt, m_flNextPrimaryAttack, 4 ) <= 0.0) )
{
return
}
// Reload button / not reloading
if( iButton & IN_RELOAD && !fInReload )
{
// Old clip is more/equal than/to new
if( iClip >= g_pClip )
{
// Remove reload button
set_pev ( iOwner, pev_button, iButton & ~IN_RELOAD )
// Idle animation
UTIL_PlayWeaponAnimation ( iOwner, gauss_idle )
// Idle time
g_flWeaponIdleTime[ iOwner ] = get_gametime( ) + 0.5
}
else
{
// Out of ammo
if ( !iBpAmmo )
return
// Reload weapon
UTIL_WeaponReload ( iOwner, iEnt )
}
}
}
}
// Gauss reload post
public fw_TCannonReload_Post( iEnt )
{
// Get owner
static Player
Player = get_pdata_cbase( iEnt, m_pPlayer, 4 )
// Does this player has gauss and is he in a middle of reloading ?
if ( g_iHasGauss[ Player ] && get_pdata_int( iEnt, m_fInReload, 4 ) )
{
// Reload
UTIL_WeaponReload( Player, iEnt )
}
}
// ------------------------------- Internal Functions ----------------------------------------
// Gauss start fire
public StartFire( Player )
{
// This var holds damage
static Float:flDamage
// Make vectors
UTIL_MakeVectors( Player )
// Get gametime
static Float:flGameTime
flGameTime = get_gametime( )
// This is maximal possible damage from secondary attack!
if( flGameTime - g_flStartCharge[ Player ] > GAUSS_CHARGETIME )
{
flDamage = g_pDmgSec
}
else
{
// The longer you hold attack button - the bigger is damage
flDamage = g_pDmgSec * ( ( flGameTime - g_flStartCharge[ Player ] ) / GAUSS_CHARGETIME )
}
// Primary attack do less damage
if( g_bPrimaryFire[ Player ] )
{
flDamage = g_pDmgPrim
}
// Make sure that we are not ending attack
if( g_bInAttack[ Player ] != 3 )
{
// Secondary attack can pop you up in the air.Not primary attack!
if( !g_bPrimaryFire[ Player ] )
{
// Current players velocity
static Float:flVel[ 3 ], Float:v_forward[ 3 ]
pev( Player, pev_velocity, flVel )
global_get( glb_v_forward, v_forward )
// Try to affect only vertical velocity
VectorMS( flVel, flDamage * 5.0, v_forward, flVel )
// Jump!
set_pev( Player, pev_velocity, flVel )
}
}
// Recoil
static Float:flRecoil[ 3 ]
flRecoil[ 0 ] = GAUSS_RECOIL
set_pev( Player, pev_punchangle, flRecoil )
// Fire animation
UTIL_PlayWeaponAnimation( Player, gauss_fire2 )
// Fire sound
static Float:flResult
flResult = 0.5 + flDamage * ( 1.0 / 400.0 )
if( flResult > 1.0 )
{
flResult = 1.0
}
emit_sound( Player, CHAN_WEAPON, g_szSoundGaussFire, flResult, ATTN_NORM, 0, 85 + random_num( 0, 0x1f ) )
// Get players aimpoint position
static Float:vecDest[ 3 ]
global_get( glb_v_forward, vecDest )
// Calculate start position
static Float:vecSrc[ 3 ]
UTIL_GetGunPosition( Player, vecSrc )
// Time until aftershock 'static discharge' sound
g_fflPlayAfterShock[ Player ] = flGameTime + random_float( 0.3, 0.8 )
// Fire!
Fire( Player, vecSrc, vecDest, flDamage )
}
// Fire!
Fire( Player, Float:vecOrigSrc[ ], Float:vecDir[ ], Float:flDamage )
{
// Start position
static Float:vecSrc[ 3 ]
xs_vec_copy( vecOrigSrc, vecSrc )
// Calculate end position
static Float:vecDest[ 3 ]
VectorMA( vecSrc, 8192.0, vecDir, vecDest )
// Few trace handles
static tr, beam_tr
// Max fraction
static Float:flMaxFrac
flMaxFrac = 1.0
// Total
static nTotal
nTotal = 0
// Does this beam punched the wall ?
static bool:fHasPunched
fHasPunched = false
// Does this is first beam
static bool:fFirstBeam
fFirstBeam = true
// Max hits
static nMaxHits
nMaxHits = 10
// Entity whoch should be ignored
static pEntToIgnore
// Make sure that beam will'be able to cause damage
while( flDamage > 10 && nMaxHits > 0 )
{
// Decrease hit count
nMaxHits--
// Draw a trace line
engfunc( EngFunc_TraceLine, vecSrc, vecDest, DONT_IGNORE_MONSTERS, pEntToIgnore, tr )
// We'll never get outside!
if( get_tr2( tr, TR_AllSolid ) )
break
// Get entity which was hit
static pEntity
pEntity = Instance( get_tr2( tr, TR_pHit ) )
// Get vector end position
static Float:vecEnd[ 3 ]
get_tr2( tr, TR_vecEndPos, vecEnd )
// Its first beam
if( fFirstBeam )
{
// Add muzzleflash
set_pev( Player, pev_effects, pev(Player, pev_effects) | EF_MUZZLEFLASH )
// Its not first anymore
fFirstBeam = false
// Add
nTotal += 26
// Draw beam
engfunc( EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, vecSrc, 0 )
//message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
write_byte( TE_BEAMENTPOINT ) // Temp. entity ID
write_short( Player | 0x1000 ) // Start entity
engfunc( EngFunc_WriteCoord, vecEnd[ 0 ] ) // End position X
engfunc( EngFunc_WriteCoord, vecEnd[ 1 ] ) // End position Y
engfunc( EngFunc_WriteCoord, vecEnd[ 2 ] ) // End position Z
write_short( g_iBeam ) // Sprite index
write_byte( 0 ) // Start frame
write_byte( 1 ) // Frame rate
write_byte( 1 ) // Life
write_byte( g_bPrimaryFire[ Player ] ? 16 : 25 ) // Line width
write_byte( 0 ) // Noise amplitude
write_byte( 255 )
write_byte( 128 )
write_byte( 0 )
write_byte( 255 ) // Alpha
write_byte( 0 ) // Scroll speed
message_end( )
}
else
{
// Draw beam
engfunc( EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, vecSrc, 0 )
write_byte( TE_BEAMPOINTS ) // Temp. entity ID
engfunc( EngFunc_WriteCoord, vecSrc[ 0 ] ) // Start position X
engfunc( EngFunc_WriteCoord, vecSrc[ 1 ] ) // Start position Y
engfunc( EngFunc_WriteCoord, vecSrc[ 2 ] ) // Start position Z
engfunc( EngFunc_WriteCoord, vecEnd[ 0 ] ) // End position X
engfunc( EngFunc_WriteCoord, vecEnd[ 1 ] ) // End position Y
engfunc( EngFunc_WriteCoord, vecEnd[ 2 ] ) // End position Z
write_short( g_iBeam ) // Sprite index
write_byte( 0 ) // Start frame
write_byte( 1 ) // Frame rate
write_byte( 1 ) // Life
write_byte( g_bPrimaryFire[ Player ] ? 15 : 25 ) // Line width
write_byte( 0 ) // Noise amplitude
write_byte( 255 )
write_byte( 128 )
write_byte( 0 )
write_byte( 255 )
write_byte( 0 ) // Scroll speed
message_end( )
}
// Check if this entity should take any damage
if( pev( pEntity, pev_takedamage ) != DAMAGE_NO )
{
// Check if this is player and zombie
if( is_user_valid_connected( pEntity ) && zp_get_user_zombie( pEntity ) )
{
// Retrieve health
static iHealth
iHealth = get_user_health( pEntity )
// We should be alive
if( iHealth - flDamage >= 1 )
{
// Cause some damage
ExecuteHamB( Ham_TakeDamage, pEntity, 0, Player, flDamage, DMG_BULLET |
DMG_ALWAYSGIB )
}
else
{
// Die
g_bKilledByLaser[ pEntity ] = true
ExecuteHamB( Ham_Killed, pEntity, Player, 2 )
g_bKilledByLaser[ pEntity ] = false
}
}
}
// Check if this entity should reflect our beam
if( ReflectGauss( pEntity ) )
{
static Float:n
// Return normal vector in a spot we hit
static Float:vecPlaneNormal[ 3 ]
get_tr2( tr, TR_vecPlaneNormal, vecPlaneNormal )
// Calculate dot product
n = - xs_vec_dot( vecPlaneNormal, vecDir )
// 60 degrees
if ( 0 < n < 0.5 )
{
static Float:r[ 3 ]
VectorMA( vecDir, 2.0 * n, vecPlaneNormal, r )
// Get vector end position
get_tr2( tr, TR_vecEndPos, vecEnd )
// Get trace fraction
static Float:trflFraction
get_tr2( tr, TR_flFraction, trflFraction )
// Calculate fraction
flMaxFrac = flMaxFrac - trflFraction
// Copy vectors
xs_vec_copy( r, vecDir )
// Make more vector calculations
VectorMA( vecEnd, 8.0, vecDir, vecSrc )
VectorMA( vecSrc, 8192.0, vecDir, vecDest )
// Undone!Do radius damage
// Increase
nTotal += 34
if( n == 0 )
{
// Lose energy
n = 0.1
}
// Calculate new damage
flDamage = flDamage * ( 1 - n )
}
else
{
// Add gun shot decal on the world
FX_GunShotDecal( vecEnd, pEntity )
// Add glowing sprite on the world
FX_TempSprite( vecEnd, 6, floatround( flDamage / 255.0 ) )
// Increase
nTotal += 13
// Limit it to one hole punch
if( fHasPunched )
break
// Update
fHasPunched = true
// Try punching through wall if secondary attack (primary is incapable of
// breaking through)
if( !g_bPrimaryFire[ Player ] )
{
// Retrieve vector end position
get_tr2( tr, TR_vecEndPos, vecEnd )
// Modify start origin
static Float:vecStart[ 3 ]
VectorMA( vecEnd, 8.0, vecDir, vecStart )
// Draw another trace line
engfunc( EngFunc_TraceLine, vecSrc, vecDest, DONT_IGNORE_MONSTERS,
pEntToIgnore, beam_tr )
// We'll never get outside
if( !get_tr2( beam_tr, TR_AllSolid ) )
{
// Get end position
static Float:vecBeamEndPos[ 3 ]
get_tr2( beam_tr, TR_vecEndPos, vecBeamEndPos )
// Trace backwards to find exit point
engfunc( EngFunc_TraceLine, vecBeamEndPos, vecEnd,
DONT_IGNORE_MONSTERS, pEntToIgnore, beam_tr )
// Again get end position
get_tr2( beam_tr, TR_vecEndPos, vecBeamEndPos )
static Float:ns, Float:vecSub[ 3 ]
// Subtract vectors
xs_vec_sub( vecBeamEndPos, vecEnd, vecSub )
// Get vector length
ns = xs_vec_len( vecSub )
if( ns < flDamage )
{
// Lose enery
if( ns == 0 )
{
ns = 1.0
}
// Decrease damage
flDamage -= ns
// Subtract
static Float:vecCalc[ 3 ]
VectorSubtract( vecEnd, vecDir, vecCalc )
// Absorbtion balls
FX_SpriteTrail( vecEnd, vecCalc, BALL_AMOUNT, 15, 3, 25,
25 )
// Add gun shot decal on the world
FX_GunShotDecal( vecBeamEndPos, pEntity )
// And glowing sprite
FX_TempSprite( vecBeamEndPos, 6, floatround( flDamage /
255.0 ) )
// Subtract
VectorSubtract( vecBeamEndPos, vecDir, vecCalc )
// Absorbtion balls
FX_SpriteTrail( vecEnd, vecCalc, BALL_AMOUNT, 15, 3, 25,
25 )
// Increase shit
nTotal += 21
/*
// Calculate radius damage
static Float:flRadDmg
flRadDmg = flDamage * 1.75
// Undone.Do radius damage here!
floatradius( flDamage, flRadDmg, vecBeamEndPos )
*/
// Increase
nTotal += 53
VectorMA( vecBeamEndPos, 8.0, vecDir, vecSub )
// Add up vector
xs_vec_add( vecBeamEndPos, vecDir, vecSrc )
}
}
else
{
flDamage = 0.0
}
}
else
{
// Primary attack
if( g_bPrimaryFire [ Player ] )
{
// Slug doesn't punch through ever with primary
// fire, so leave a little glowy bit and make some balls
FX_TempSprite( vecEnd, 6, floatround( flDamage / 255.0 ) )
FX_SpriteTrail( vecEnd, vecDir, BALL_AMOUNT, 15, 3, 25, 25 )
}
flDamage = 0.0
}
}
}
else
{
// Add up vector
xs_vec_add( vecEnd, vecDir, vecSrc )
pEntToIgnore = pEntity
}
}
}
// Register and cache CVARs
public Load_Cvars( )
{
cvar_oneround = register_cvar( "zp_tcannon_oneround", "0" )
cvar_dmgprim = register_cvar( "zp_tcannon_dmgprim", "200" )
cvar_dmgsec = register_cvar( "zp_tcannon_dmgsec", "500" )
cvar_clip = register_cvar( "zp_tcannon_clip", "100" )
g_pOneRound = get_pcvar_num( cvar_oneround )
g_pDmgPrim = get_pcvar_float( cvar_dmgprim )
g_pDmgSec = get_pcvar_float( cvar_dmgsec )
g_pClip = get_pcvar_num( cvar_clip )
}
// Gauss weapon idle
WeaponIdle( Player )
{
// Get gametime
static Float:flGameTime
flGameTime = get_gametime( )
if( g_flWeaponIdleTime[ Player ] > flGameTime )
return
// Animation sequence variable
static iAnim
// Animation randomizer
static Float:flRand
flRand = random_float( 0.1, 1.0 )
if( flRand <= 0.5 )
{
iAnim = gauss_idle
g_flWeaponIdleTime[ Player ] = flGameTime + random_float( 10.0, 15.0 )
}
else if( flRand <= 0.75 )
{
iAnim = gauss_idle2
g_flWeaponIdleTime[ Player ] = flGameTime + random_float( 10.0, 15.0 )
}
else
{
iAnim = gauss_fidget
g_flWeaponIdleTime[ Player ] = flGameTime + 3
}
// Idle
UTIL_PlayWeaponAnimation( Player, iAnim )
}
// Play weapon animation
UTIL_PlayWeaponAnimation( const Player, const Sequence )
{
set_pev( Player, pev_weaponanim, Sequence )
message_begin( MSG_ONE_UNRELIABLE, SVC_WEAPONANIM, .player = Player )
write_byte( Sequence )
write_byte( pev( Player, pev_body ) )
message_end( )
}
// Make ScreenFade
UTIL_ScreenFade( Player, Duration, HoldTime, Flags, iRed, iGreen, iBlue, iAlpha )
{
message_begin( MSG_ONE, gmsgScreenFade, _, Player )
write_short( Duration )
write_short( HoldTime )
write_short( Flags )
write_byte( iRed )
write_byte( iGreen )
write_byte( iBlue )
write_byte( iAlpha )
message_end( )
}
// Reload gauss
UTIL_WeaponReload( Player, iEnt )
{
// Modify time until next attack
set_pdata_float( Player, m_flNextAttack, GAUSS_RELOADTIME+0.5, 5 )
// Reload animation
UTIL_PlayWeaponAnimation( Player, gauss_spin )
// Enable reload offset
set_pdata_int( iEnt, m_fInReload, 1, 4 )
// Modify next idle time
g_flWeaponIdleTime[ Player ] = get_gametime( ) + GAUSS_RELOADTIME + 1.0
}
// Drop all primary weapons
UTIL_DropPrimary( Player )
{
// Get user weapons
static weapons[ 32 ], num, i, weaponid
num = 0 // reset passed weapons count (bugfix)
get_user_weapons( Player, weapons, num )
// Loop through them and drop primaries
for( i = 0; i < num; i++ )
{
// Prevent re-indexing the array
weaponid = weapons[ i ]
// We definetely are holding primary gun
if(( (1<<weaponid) & PRIMARY_WEAPONS_BITSUM ) )
{
// Get weapon entity
static wname[32]
get_weaponname(weaponid, wname, charsmax(wname))
// Player drops the weapon and looses his bpammo
engclient_cmd( Player, "drop", wname)
}
}
}
// Get gun position
UTIL_GetGunPosition( Player, Float:flOrigin[ ] )
{
static Float:vf_Origin[ 3 ], Float:vf_ViewOfs[ 3 ]
pev( Player, pev_origin, vf_Origin )
pev( Player, pev_view_ofs, vf_ViewOfs )
xs_vec_add( vf_Origin, vf_ViewOfs, flOrigin )
}
// Make vectors
UTIL_MakeVectors ( Player )
{
static Float:flAngle[ 3 ], Float:flPunchAngle[ 3 ]
pev( Player, pev_v_angle, flAngle )
pev( Player, pev_punchangle, flPunchAngle )
xs_vec_add( flAngle, flPunchAngle, flAngle )
engfunc( EngFunc_MakeVectors, flAngle )
}
// From HL SDK.
VectorMA( Float:a[ ], Float:flScale, Float:b[ ], Float:c[ ] )
{
c[ 0 ] = a[ 0 ] + flScale * b[ 0 ]
c[ 1 ] = a[ 1 ] + flScale * b[ 1 ]
c[ 2 ] = a[ 2 ] + flScale * b[ 2 ]
}
VectorMS( const Float:flSource[ ], const Float:flScale, const Float:flMult[ ], Float:flOutput[ ] )
{
flOutput[ 0 ] = flSource[ 0 ] - flMult[ 0 ] * flScale
flOutput[ 1 ] = flSource[ 1 ] - flMult[ 1 ] * flScale
flOutput[ 2 ] = flSource[ 2 ] - flMult[ 2 ] * flScale
}
// Another stuff from HLSDK
Instance( iEnt )
{
return iEnt == -1 ? 0 : iEnt
}
// Does this entity should refect gauss?
ReflectGauss( iEnt )
{
return IsBSPModel( iEnt ) && pev( iEnt, pev_takedamage ) == DAMAGE_NO
}
// Does this entity is BSP model?
IsBSPModel( iEnt )
{
return pev( iEnt, pev_solid ) == SOLID_BSP || pev( iEnt, pev_movetype ) == MOVETYPE_PUSHSTEP
}
// Add gun shot decal on world!
FX_GunShotDecal( Float:flPos[ ], pEntity )
{
// Draw gunshot
engfunc( EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, flPos, 0 )
write_byte( TE_GUNSHOTDECAL ) // Temp.entity ID
engfunc( EngFunc_WriteCoord, flPos[ 0 ] ) // Position X
engfunc( EngFunc_WriteCoord, flPos[ 1 ] ) // Position Y
engfunc( EngFunc_WriteCoord, flPos[ 2 ] ) // Position Z
write_short( pEntity ) // Which entity to mark?
write_byte( 43 ) // Decal number
message_end( )
}
// Add glow sprite on world
FX_TempSprite( Float:flPos[ ], iScale, iSize )
{
engfunc( EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, flPos, 0 )
write_byte( TE_GLOWSPRITE ) // Temp.entity ID
engfunc( EngFunc_WriteCoord, flPos[ 0 ] ) // Position X
engfunc( EngFunc_WriteCoord, flPos[ 1 ] ) // Position Y
engfunc( EngFunc_WriteCoord, flPos[ 2 ] ) // Position Z
write_short( g_iBalls ) // Sprite index
write_byte( iScale ) // Scale
write_byte( iSize ) // Size
write_byte( 255 ) // Brightness
message_end( )
}
// Add sprite trail
FX_SpriteTrail( Float:vecStart[ ], Float:vecDest[ ], iCount, iLife, iScale, iVel, iRnd )
{
message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
write_byte( TE_SPRITETRAIL ) // Sprite trail
engfunc( EngFunc_WriteCoord, vecStart[ 0 ] ) // Position X
engfunc( EngFunc_WriteCoord, vecStart[ 1 ] ) // Position Y
engfunc( EngFunc_WriteCoord, vecStart[ 2 ] ) // Position Z
engfunc( EngFunc_WriteCoord, vecDest[ 0 ] ) // Position X
engfunc( EngFunc_WriteCoord, vecDest[ 1 ] ) // Position Y
engfunc( EngFunc_WriteCoord, vecDest[ 2 ] ) // Position Z
write_short( g_iBalls ) // SPrite index
write_byte( iCount ) // Amount
write_byte( iLife ) // Life
write_byte( iScale ) // Scale
write_byte( iVel ) // Velocity along vector
write_byte( iRnd ) // Randomness of velocity
message_end( )
}