[Half-Life AMXX] / grab_plus.sma Repository:
ViewVC logotype

View of /grab_plus.sma

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (download) (annotate)
Fri Nov 2 01:14:09 2007 UTC (16 years, 5 months ago) by ian
File size: 18830 byte(s)
/*
Grab+ v1.2
Copyright (C) 2007 Ian (Juan) Cammarata

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 2 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; go to http://www.opensource.org/licenses/gpl-license.php
--------------------------------------------------------------------------------

http://ian.cammarata.us/projects/grab_plus
Nov 01 04:16


Description:
This is a remake from scratch of SpaceDude's Jedi Force Grab plugin.  It has many additional features and optimizations, is less spammy, multilingual and requires fewer binds. 


See it in Action:
http://www.game-monitor.com/search.php?search=grab_plus_version&type=variable&game=all&location=all


Features:
Multilingual
Screenfade to indicate grab activity instead of chat spam.
Can grab players off a ladder.
Automatically choke by holding down +pull while at min distance.
Choke with use key.
Throw with drop.
Can't have mutliple admins grabbing the same player.
Auto drop on death.
Grab entities other than players, such as bombs, weapons, and hostages.


Commands:

+grab : Grab something for as long as you hold down the key.
grab_toggle : Same as +grab but toggles.
amx_grab <name> : Grab client by name or id and teleport them to you.  Use +grab or grab_toggle key to release.

+pull/+push (or invnext/invprev): Pulls/pushes the grabbed towards/away from you as you hold the button.

+use : Chokes the grabbed (it damages the grabbed with 5 (cvar: gp_chokedmg) hp per 1.5 (cvar: gp_choketime) seconds)
drop - Throws the grabbed with 1500 velocity. (cvar: gp_throwforce)


Cvars (First value is default):
gp_enabled <1|0> Enables all plugin functionality.
gp_playersonly <0|1> Disables admins grabbing entities other than players.

gp_min_dist <90|...> Min distance between the grabber and grabbed.
gp_grabforce <8|...> Sets the amount of force used when grabbing players.
gp_throwforce <1500|...> Sets the power used when throwing players.
gp_speed <5|...> How fast the grabbed moves when using push and pull.

gp_choketime <1.5|...> Time frequency for choking.
gp_chokedmg <5|...> Amount of damage done with each choke.

gp_screenfade <1|0> Enables/disables screenfade when grabbing.
gp_glow <1|0> Enables/disables glowing for grabbed objects.

gp_glow_r <50|0-255> Sets red amount for glow and screenfade.
gp_glow_g <0|0-255> Sets green amount for glow and screenfade.
gp_glow_b <0|0-255> Sets blue amount for glow and screenfade.
gp_glow_a <0|0-255> Sets alpha for glow and screenfade.


Notes:
Make sure you place the grab_plus.txt file in addons\amxmodx\data\lang


Credits:
Thanks to vittu for contributing code (changed all engine/fun module stuff to fakemeta).
 
Thanks to all the coders who worked on the original Jedi Force Grab plugin for all their ideas:
SpaceDude
KCE
KRoTaL
BOB_SLAYER
kosmo111


Supported Languages:
1337 (100%) - Thanks to l337newb
Brazilian Portuguese (100%) - Thanks to Arion
Danish (100%) - Thanks to nellerbabz
Dutch (100%) - Thanks to BlackMilk
English (100%)
Finnish (100%) - Thanks to Pro Patria Finland
French (100%) - Thanks to connorr
German (100%) - Thanks to SchlumPF*
Russian (100%) - Thanks to `666
Spanish (100%) - Hope these don't suck.
Swedish (100%) - Thanks to Bend3r


Change Log:
Key (+ added | - removed | c changed | f fixed)

v1.2 (Nov ??, 2007)
+: Cvars gp_screenfade and gp_glow to enable/disable these features.
+: Cvar gp_glow_a controls to control alpha of screenfade and glow.
c: Removed dependency of engine and fun modules.  Thanks to vittu for doing all the work.
f: Fixed compile bug with amxx 1.8.0 (Compiles with 1.7x as well).

v1.1 (Oct 16, 2007)
+: Grab a few types of entities other than players.
+: Cvar gp_playersonly.

v1.0 (Oct 13, 2007)
!: Initial release

*/

#include <amxmodx>
#include <amxmisc>
#include <fakemeta>

#define VERSION "1.2b5"
#define ADMIN ADMIN_LEVEL_A

#define TSK_CHKE 50

#define SVC_DAMAGE 19
#define SF_FADEOUT 0

new client_data[33][4]
#define GRABBED  0
#define GRABBER  1
#define GRAB_LEN 2
#define FLAGS    3

#define CDF_IN_PUSH   (1<<0)
#define CDF_IN_PULL   (1<<1)
#define CDF_NO_CHOKE  (1<<2)

//Cvar Pointers
new p_enabled, p_playersonly
new p_throwforce, p_mindist, p_speed, p_grabforce
new p_choketime, p_chokedmg
new p_glow_r, p_glow_b, p_glow_g, p_glow_a
new p_fade, p_glow

//Pseudo Constants
new MAXPLAYERS
new SVC_SCREENFADE, SVC_SCREENSHAKE

public plugin_init( )
{
	register_plugin( "Grab+", VERSION, "Ian Cammarata" )
	register_cvar( "grab_plus_version", VERSION, FCVAR_SERVER )
	set_cvar_string( "grab_plus_version", VERSION )
	
	p_enabled = register_cvar( "gp_enabled", "1" )
	p_playersonly = register_cvar( "gp_playersonly", "0" )
	
	p_mindist = register_cvar ( "gp_min_dist", "90" )
	p_throwforce = register_cvar( "gp_throwforce", "1500" )
	p_grabforce = register_cvar( "gp_grabforce", "8" )
	p_speed = register_cvar( "gp_speed", "5" )
	
	p_choketime = register_cvar( "gp_choketime", "1.5" )
	p_chokedmg = register_cvar( "gp_chokedmg", "5" )
	
	p_glow_r = register_cvar( "gp_glow_r", "50" )
	p_glow_g = register_cvar( "gp_glow_g", "0" )
	p_glow_b = register_cvar( "gp_glow_b", "0" )
	p_glow_a = register_cvar( "gp_glow_a", "200" )
	
	p_fade = register_cvar( "gp_screenfade", "1" )
	p_glow = register_cvar( "gp_glow", "1" )
	
	register_clcmd( "amx_grab", "force_grab", ADMIN, "Grab client & teleport to you." )
	register_clcmd( "grab_toggle", "grab_toggle", ADMIN, "press once to grab and again to release" )
	register_clcmd( "+grab", "grab", ADMIN, "bind a key to +grab" )
	register_clcmd( "-grab", "unset_grabbed" )
	
	register_clcmd( "+push", "push", ADMIN, "bind a key to +push" )
	register_clcmd( "-push", "push" )
	register_clcmd( "+pull", "pull", ADMIN, "bind a key to +pull" )
	register_clcmd( "-pull", "pull" )
	register_clcmd( "push", "push2" )
	register_clcmd( "pull", "pull2" )
	
	register_clcmd( "drop" ,"throw" )
	
	register_event( "DeathMsg", "DeathMsg", "a" )
	
	register_forward( FM_PlayerPreThink, "fm_player_prethink" )
	
	register_dictionary( "grab_plus.txt" )
	
	MAXPLAYERS = get_maxplayers()
	
	SVC_SCREENFADE = get_user_msgid( "ScreenFade" )
	SVC_SCREENSHAKE = get_user_msgid( "ScreenShake" )
	
	return PLUGIN_CONTINUE
}

public plugin_precache( )
{
	precache_sound( "player/PL_PAIN2.WAV" )
	return PLUGIN_CONTINUE
} 

public fm_player_prethink( id )
{
	//Search for a target
	if ( client_data[id][GRABBED] == -1 )
	{
		new Float:orig[3], Float:ret[3]
		pev( id, pev_origin, orig )
		pev( id, pev_view_ofs, ret )
		
		for( new i = 0; i < 3; i++ ) orig[i] += ret[i]
		velocity_by_aim( id, 1, ret )
		for( new i = 0; i < 3; i++ ) ret[i] = orig[i] + ( ret[i] * 9999 )
		
		engfunc( EngFunc_TraceLine, orig, ret, 0, id, 0 )
		new target = get_tr2( 0, TR_pHit )
		get_tr2( 0, TR_vecEndPos, ret )
		
		if( 0 < target <= MAXPLAYERS )
		{
			if( is_grabbed( target, id ) ) return PLUGIN_CONTINUE
			set_grabbed( id, target )
		}
		else if( !get_pcvar_num( p_playersonly ) )
		{
			new movetype
			if( target )
			{
				movetype = pev( target, pev_movetype )
				if( !( movetype == MOVETYPE_WALK || movetype == MOVETYPE_STEP || movetype == MOVETYPE_TOSS ) )
					return PLUGIN_CONTINUE
			}
			else
			{
				new ent = engfunc( EngFunc_FindEntityInSphere, -1, ret, 12.0 )
				while( !target && ent > 0 )
				{
					movetype = pev( ent, pev_movetype )
					if( ( movetype == MOVETYPE_WALK || movetype == MOVETYPE_STEP || movetype == MOVETYPE_TOSS )
							&& ent != id  )
						target = ent
					ent = engfunc( EngFunc_FindEntityInSphere, ent, ret, 12.0 )
				}
			}
			if( target )
			{
				if( is_grabbed( target, id ) ) return PLUGIN_CONTINUE
				set_grabbed( id, target )
			}
		}
	}
	//If they've grabbed something
	if( client_data[id][GRABBED] > 0 )
	{
		new target = client_data[id][GRABBED]
		if( !pev_valid( target ) || ( pev( target, pev_health ) < 1 && pev( target, pev_max_health ) ) )
		{
			unset_grabbed( id )
			return PLUGIN_CONTINUE
		}
		 
		//Use key choke
		if( pev( id, pev_button ) & IN_USE )
			do_choke( id )
		
		//Push and pull
		if ( client_data[id][FLAGS] & CDF_IN_PULL )
			do_pull( id )
		else if ( client_data[id][FLAGS] & CDF_IN_PUSH )
			do_push( id )
		
		grab_think( id )
	}
	if( client_data[id][GRABBER] > 0 ) grab_think( client_data[id][GRABBER] )
	
	return PLUGIN_CONTINUE
}

public grab_think ( id )
{
	new target = client_data[id][GRABBED]
	
	//Keep grabbed clients from sticking to ladders
	if( pev( target, pev_movetype ) == MOVETYPE_FLY && !(pev( target, pev_button ) & IN_JUMP ) ) client_cmd( target, "+jump;wait;-jump" )
	
	//Move targeted client
	new Float:tmpvec[3], Float:tmpvec2[3], Float:dest[3], Float:torig[3], Float:tvel[3]
	new len = client_data[id][GRAB_LEN]
	
	pev( id, pev_origin, dest )
	pev( id, pev_view_ofs, tmpvec )
	velocity_by_aim( id, len, tmpvec2 )
	torig = get_target_origin_f( target )
	
	new force = get_pcvar_num( p_grabforce )
	
	for( new i = 0; i < 3; i++ )
	{
		dest[i] += tmpvec[i] + tmpvec2[i]
		tvel[i] = ( dest[i] - torig[i] ) * force
	}
	
	set_pev( target, pev_velocity, tvel )
}

stock Float:get_target_origin_f( id )
{
	new Float:orig[3]
	pev( id, pev_origin, orig )
	
	//If grabbed is not a player, move origin to center
	if( id > MAXPLAYERS )
	{
		new Float:mins[3], Float:maxs[3]
		pev( id, pev_mins, mins )
		pev( id, pev_maxs, maxs )
		
		if( !mins[2] ) orig[2] += maxs[2] / 2
	}
	
	return orig
}

public grab_toggle( id, level, cid )
{
	if( !client_data[id][GRABBED] ) grab( id, level, cid )
	else unset_grabbed( id )
	
	return PLUGIN_HANDLED
}

public grab( id, level, cid )
{
	if( !cmd_access( id, level, cid, 1 ) || !get_pcvar_num( p_enabled ) ) return PLUGIN_HANDLED
	
	if ( !client_data[id][GRABBED] ) client_data[id][GRABBED] = -1	
	screenfade_in( id )
	
	return PLUGIN_HANDLED
}

public screenfade_in( id )
{
	if( get_pcvar_num( p_fade ) )
	{
		message_begin( MSG_ONE, SVC_SCREENFADE, _, id )
		write_short( 10000 ) //duration
		write_short( 0 ) //hold
		write_short( SF_FADE_IN + SF_FADE_ONLYONE ) //flags
		write_byte( get_pcvar_num( p_glow_r ) ) //r
		write_byte( get_pcvar_num( p_glow_g ) ) //g
		write_byte( get_pcvar_num( p_glow_b ) ) //b
		write_byte( get_pcvar_num( p_glow_a ) / 2 ) //a
		message_end( )
	}
}

public throw( id )
{
	new target = client_data[id][GRABBED]
	if( target > 0 )
	{
		new Float:pVelocity[3]
		velocity_by_aim( id, get_pcvar_num(p_throwforce), pVelocity )
		set_pev( target, pev_velocity, pVelocity )
		unset_grabbed( id )
		return PLUGIN_HANDLED
	}
	return PLUGIN_CONTINUE
}

public unset_grabbed( id )
{
	new target = client_data[id][GRABBED]
	if( target > 0 && pev_valid( target ) )
	{
		set_pev( target, pev_renderfx, kRenderFxNone )
		set_pev( target, pev_rendercolor, {255.0, 255.0, 255.0} )
		set_pev( target, pev_rendermode, kRenderNormal )
		set_pev( target, pev_renderamt, 16.0 )
		
		if( 0 < target <= MAXPLAYERS )
			client_data[target][GRABBER] = 0
	}
	client_data[id][GRABBED] = 0
	
	if( get_pcvar_num( p_fade ) )
	{
		message_begin( MSG_ONE, SVC_SCREENFADE, _, id )
		write_short( 10000 ) //duration
		write_short( 0 ) //hold
		write_short( SF_FADEOUT ) //flags
		write_byte( get_pcvar_num( p_glow_r ) ) //r
		write_byte( get_pcvar_num( p_glow_g ) ) //g
		write_byte( get_pcvar_num( p_glow_b ) ) //b
		write_byte( get_pcvar_num( p_glow_a ) / 2 ) //a
		message_end( )
	}
}

//Grabs onto someone
public set_grabbed( id, target )
{
	if( get_pcvar_num( p_glow ) )
	{
		new Float:color[3]
		color[0] = get_pcvar_float( p_glow_r )
		color[1] = get_pcvar_float( p_glow_g )
		color[2] = get_pcvar_float( p_glow_b )
		set_pev( target, pev_renderfx, kRenderFxGlowShell )
		set_pev( target, pev_rendercolor, color )
		set_pev( target, pev_rendermode, kRenderTransColor )
		set_pev( target, pev_renderamt, get_pcvar_float( p_glow_a ) )
	}
	
	if( 0 < target <= MAXPLAYERS )
		client_data[target][GRABBER] = id
	client_data[id][FLAGS] = 0
	client_data[id][GRABBED] = target
	new Float:torig[3], Float:orig[3]
	pev( target, pev_origin, torig )
	pev( id, pev_origin, orig )
	client_data[id][GRAB_LEN] = floatround( get_distance_f( torig, orig ) )
	if( client_data[id][GRAB_LEN] < get_pcvar_num( p_mindist ) ) client_data[id][GRAB_LEN] = get_pcvar_num( p_mindist )
}

public push( id )
{
	client_data[id][FLAGS] ^= CDF_IN_PUSH
	return PLUGIN_HANDLED
}

public pull( id )
{
	client_data[id][FLAGS] ^= CDF_IN_PULL
	return PLUGIN_HANDLED
}

public push2( id )
{
	if( client_data[id][GRABBED] > 0 )
	{
		do_push( id )
		return PLUGIN_HANDLED
	}
	return PLUGIN_CONTINUE
}

public pull2( id )
{
	if( client_data[id][GRABBED] > 0 )
	{
		do_pull( id )
		return PLUGIN_HANDLED
	}
	return PLUGIN_CONTINUE
}

public do_push( id )
	if( client_data[id][GRAB_LEN] < 9999 )
		client_data[id][GRAB_LEN] += get_pcvar_num( p_speed )

public do_pull( id )
{
	new mindist = get_pcvar_num( p_mindist )
	new len = client_data[id][GRAB_LEN]
	
	if( len > mindist )
	{
		len -= get_pcvar_num( p_speed )
		if( len < mindist ) len = mindist
		client_data[id][GRAB_LEN] = len
	}
	else do_choke( id )
}

public do_choke( id )
{
	new target = client_data[id][GRABBED]
	if( client_data[id][FLAGS] & CDF_NO_CHOKE || id == target || target > MAXPLAYERS) return
	
	new dmg = get_pcvar_num( p_chokedmg )
	new Float:vec[3]
	get_target_origin_f( target )
	
	message_begin( MSG_ONE, SVC_SCREENSHAKE, _, target )
	write_short( 999999 ) //amount
	write_short( 9999 ) //duration
	write_short( 999 ) //frequency
	message_end( )
	
	message_begin( MSG_ONE, SVC_SCREENFADE, _, target )
	write_short( 9999 ) //duration
	write_short( 100 ) //hold
	write_short( SF_FADE_MODULATE ) //flags
	write_byte( get_pcvar_num( p_glow_r ) ) //r
	write_byte( get_pcvar_num( p_glow_g ) ) //g
	write_byte( get_pcvar_num( p_glow_b ) ) //b
	write_byte( 200 ) //a
	message_end( )
	
	message_begin( MSG_ONE, SVC_DAMAGE, _, target )
	write_byte( 0 ) //damage armor
	write_byte( dmg ) //damage health
	write_long( DMG_CRUSH ) //damage type
	write_coord( floatround( vec[0] ) ) //origin[x]
	write_coord( floatround( vec[1] ) ) //origin[y]
	write_coord( floatround( vec[2] ) ) //origin[z]
	message_end( )
		
	message_begin( MSG_BROADCAST, SVC_TEMPENTITY )
	write_byte( TE_BLOODSTREAM )
	write_coord( floatround( vec[0] ) ) //pos.x
	write_coord( floatround( vec[1] ) ) //pos.y
	write_coord( floatround( vec[2] ) + 15 ) //pos.z
	write_coord( random_num( 0, 255 ) ) //vec.x
	write_coord( random_num( 0, 255 ) ) //vec.y
	write_coord( random_num( 0, 255 ) ) //vec.z
	write_byte( 70 ) //col index
	write_byte( random_num( 50, 250 ) ) //speed
	message_end( )
	
	new health = pev( target, pev_health ) - dmg
	set_pev( target, pev_health, float( health ) )
	if( health < 1 ) dllfunc( DLLFunc_ClientKill, target )
	
	emit_sound( target, CHAN_BODY, "player/PL_PAIN2.WAV", VOL_NORM, ATTN_NORM, 0, PITCH_NORM )
	
	client_data[id][FLAGS] ^= CDF_NO_CHOKE
	set_task( get_pcvar_float( p_choketime ), "clear_no_choke", TSK_CHKE + id )
}

public clear_no_choke( tskid )
{
	new id = tskid - TSK_CHKE
	client_data[id][FLAGS] ^= CDF_NO_CHOKE
}

//Grabs the client and teleports them to the admin
public force_grab(id, level, cid)
{
	if( !cmd_access( id, level, cid, 1 ) || !get_pcvar_num( p_enabled ) ) return PLUGIN_HANDLED

	new arg[33]
	read_argv( 1, arg, 32 )

	new targetid = cmd_target( id, arg, 1 )
	
	if( is_grabbed( targetid, id ) ) return PLUGIN_HANDLED
	if( !is_user_alive( targetid ) )
	{
		client_print( id, print_console, "[AMXX] %L", id, "COULDNT" )
		return PLUGIN_HANDLED
	}
	
	//Safe to tp target to aim spot?
	new Float:tmpvec[3], Float:tmpvec2[3], Float:orig[3], Float:torig[3], Float:trace_ret[3]
	new bool:safe = false, i
	
	pev( id, pev_origin, orig )
	pev( id, pev_view_ofs, tmpvec )
	for( i = 0; i < 3; i++ ) tmpvec[i] += orig[i]
	velocity_by_aim( id, get_pcvar_num( p_mindist ), tmpvec2 )
	
	for( new j = 1; j < 11 && !safe; j++ )
	{
		for( i = 0; i < 3; i++ )
			torig[i] = tmpvec[i] + tmpvec2[i] * j
		
		engfunc( EngFunc_TraceLine, tmpvec, torig, 0, id, 0 )
		get_tr2( 0, TR_vecEndPos, trace_ret )
		
		if( get_distance_f( trace_ret, torig ) ) break
		
		engfunc( EngFunc_TraceHull, torig, torig, 0, HULL_HUMAN, 0, 0 )
		if ( !get_tr2( 0, TR_StartSolid ) && !get_tr2( 0, TR_AllSolid ) && get_tr2( 0, TR_InOpen ) )
			safe = true
	}
	
	//Still not safe? Then find another safe spot somewhere around the grabber
	new try[3]
	orig[2] += 2
	while( try[2] < 3 && !safe )
	{
		for( i = 0; i < 3; i++ )
			switch( try[i] )
			{
				case 0 : torig[i] = orig[i] + ( i == 2 ? 80 : 40 )
				case 1 : torig[i] = orig[i]
				case 2 : torig[i] = orig[i] - ( i == 2 ? 80 : 40 )
			}
		
		engfunc( EngFunc_TraceLine, tmpvec, torig, 0, id, 0 )
		get_tr2( 0, TR_vecEndPos, trace_ret )
		
		engfunc( EngFunc_TraceHull, torig, torig, 0, HULL_HUMAN, 0, 0 )
		if ( !get_tr2( 0, TR_StartSolid ) && !get_tr2( 0, TR_AllSolid ) && get_tr2( 0, TR_InOpen )
				&& !get_distance_f( trace_ret, torig ) ) safe = true
		
		try[0]++
		if( try[0] == 3 )
		{
			try[0] = 0
			try[1]++
			if( try[1] == 3 )
			{
				try[1] = 0
				try[2]++
			}
		}
	}
	
	if( safe )
	{
		set_pev( targetid, pev_origin, torig )
		set_grabbed( id, targetid )
		screenfade_in( id )	
	}
	else client_print( id, print_chat, "[AMXX] %L", id, "COULDNT" )

	return PLUGIN_HANDLED
}

public is_grabbed( target, grabber )
{
	for( new i = 1; i <= MAXPLAYERS; i++ )
		if( client_data[i][GRABBED] == target )
		{
			client_print( grabber, print_chat, "[AMXX] %L", grabber, "ALREADY" )
			unset_grabbed( grabber )
			return true
		}
	return false
}

public DeathMsg( )
	kill_grab( read_data( 2 ) )

public client_disconnect( id )
{
	kill_grab( id )
	return PLUGIN_CONTINUE
}

public kill_grab( id )
{
	//If given client has grabbed, or has a grabber, unset it
	if( client_data[id][GRABBED] )
		unset_grabbed( id )
	else if( client_data[id][GRABBER] )
		unset_grabbed( client_data[id][GRABBER] )
}

Contact
ViewVC Help
Powered by ViewVC 1.0.4