/**
|** Description:
|**   Team Fortress Classic has quad damage, invisibility to
|**   sentry guns, and godmode all as powerups you can get from
|**   map entities. This plugin makes them available on command.
|**   You can give any number of seconds, or a default of ~27 hours
|**   worth of any powerup. You can also expire anyone's powerup(s).
|**
|** Background:
|**   I had no commands on my server to give more than the what
|**   NeoTF allowed (maximum of 30 seconds) worth of these powerups.
|**   That wasn't good enough. I want to give more as needed.
|**   Especially on skill/fun maps. This plugin makes that happen.
|**
|** Internally:
|**   This creates an info_tfgoal entity with appropriate keyvals
|**   at a player's location so they can get the affects,
|**   spawning the entity, thinking it, forcing the target to
|**   fake-touch it, and then flagging it to be killed/removed.
|**
|** VERY Special Thanks To: "XxAvalanchexX" ( See am44768 )
|**
|** Idea: Control fun powerups that last the player's lifetime!
|**
|** Usage(s):
|**    amx_quad <name or #userid> [seconds] - give quad damage for seconds else lifelong
|**    amx_invul <name or #userid> [seconds] - give invulnerability for seconds else lifelong
|**    amx_invis <name or #userid> [seconds] - give SG invisibility for seconds else lifelong
|**    amx_powerups <name or #userid> [seconds] - give quad,invis,invul for seconds else lifelong
|**    ---removal commands--- (add "rem" after "amx_")
|**    ---NOTE: These are exactly the same as giving a powerup for only 1 second!
|**    amx_remquad <name or #userid> - remove a player's quad damage
|**    amx_reminvul <name or #userid> - remove a player's invulnerability
|**    amx_reminvis <name or #userid> - remove a player's SG invisibility
|**    amx_rempowerups <name or #userid> - remove a player's quad,invis,invul
|**
|** Module Required: "engine" for entity manipulation stuff.
|**
|** Changelog:
|** 2007-01-01 @ v1.4 - precache sounds used by NeoTF.
|** ...see issue at http://forums.planetneotf.net/phpBB2/viewtopic.php?t=98
|** 2006-12-22 @ v1.3 - fixed typo where remove commands failed
|** 2006-12-05 @ v1.2 - cleaned code again. Thanks Hawk.
|** 2006-11-25 @ v1.1 - sizeof directives added for safety
|** 2006-11-25 @ v1.0 - added optional number of seconds, as Ramono suggested.
|**							also cleaned up code, simplifying some things.
|** 2006-09-27 @ v0.91 - added "amx_rem*" commands to remove powerups.
|**                       Thank you to SpannerSpammer of NeoTF!
|** 2006-09-22 @ v0.9 - fixed typo in print_chat announce
|** 2006-09-22 @ v0.8 - major simplification of code via an enum, conditionals
|** 2006-09-22 @ v0.7 - fixes, optimizations, etc.
|** 2006-09-21 @ v0.6 - days of work pay off! the beast is alive!
*\*
**\
**/

#include <amxmodx>
#include <amxmisc>
#include <engine>

//Set a level of access for all commands here...
#define ACCESS ADMIN_KICK

//Set some constants to be used for internal logic...
enum {
	POWERUP_QUAD = 1, //quad damage
	POWERUP_INVUL, //invulnerability
	POWERUP_INVIS, //sentry gun invisibility
	POWERUP_ALL, //give/take ALL three of the above powerups
	ACT_GIVE, //we are giving a player a powerup
	ACT_REMOVE, //we are expiring a player's powerup
} //enum


public plugin_init()
{
	register_plugin("TFC Powerups!","1.4","jRaven");
	register_concmd("amx_quad","relayQuad",ACCESS,"<name or #userid> [seconds] - give quad damage for seconds else lifelong");
	register_concmd("amx_invul","relayInvul",ACCESS,"<name or #userid> [seconds] - give invulnerability for seconds else lifelong");
	register_concmd("amx_invis","relayInvis",ACCESS,"<name or #userid> [seconds] - give SG invisibility for seconds else lifelong");
	register_concmd("amx_powerups","relayPowerups",ACCESS,"<name or #userid> [seconds] - give quad,invis,invul for seconds else lifelong");
	//"rem"ove duplicates to remove powerups
	register_concmd("amx_remquad","relayRemQuad",ACCESS,"<name or #userid> - remove a player's quad damage");
	register_concmd("amx_reminvul","relayRemInvul",ACCESS,"<name or #userid> - remove a player's invulnerability");
	register_concmd("amx_reminvis","relayRemInvis",ACCESS,"<name or #userid> - remove a player's SG invisibility");
	register_concmd("amx_rempowerups","relayRemPowerups",ACCESS,"<name or #userid> - remove a player's quad,invis,invul");
}


public plugin_precache()
{
	//NeoTF makes use of these(?).
	//This will make sure they are ready for DM/non-DM maps.
	//See topic: http://forums.planetneotf.net/phpBB2/viewtopic.php?t=98
	precache_sound("items/itembk2.wav")
	precache_sound("fvox/hev_logon.wav")
	precache_sound("fvox/hev_shutdown.wav")
	precache_sound("items/protect.wav")
	precache_sound("items/protect2.wav")
	precache_sound("items/protect3.wav")
	precache_sound("items/inv1.wav")
	precache_sound("items/inv2.wav")
	precache_sound("items/inv3.wav")
	precache_sound("items/damage.wav")
	precache_sound("items/damage2.wav")
	precache_sound("items/damage3.wav")
}


//I don't know if this is the best way, but it will work for now...
public relayQuad(id,level,cid)
{
	give_powerup(id,level,cid,ACT_GIVE,POWERUP_QUAD);
}
public relayInvul(id,level,cid)
{
	give_powerup(id,level,cid,ACT_GIVE,POWERUP_INVUL);
}
public relayInvis(id,level,cid)
{
	give_powerup(id,level,cid,ACT_GIVE,POWERUP_INVIS);
}
public relayPowerups(id,level,cid)
{
	give_powerup(id,level,cid,ACT_GIVE,POWERUP_ALL);
}

//duplicates to remove powerups...
public relayRemQuad(id,level,cid)
{
	give_powerup(id,level,cid,ACT_REMOVE,POWERUP_QUAD);
}
public relayRemInvul(id,level,cid)
{
	give_powerup(id,level,cid,ACT_REMOVE,POWERUP_INVUL);
}
public relayRemInvis(id,level,cid)
{
	give_powerup(id,level,cid,ACT_REMOVE,POWERUP_INVIS);
}
public relayRemPowerups(id,level,cid)
{
	give_powerup(id,level,cid,ACT_REMOVE,POWERUP_ALL);
}


//this is where all the work is done...
public give_powerup(id,level,cid,act_type,powerup_type)
{

	if ( ! cmd_access(id,level,cid,2) ) //make sure they can use this function...
		return PLUGIN_HANDLED;

	new arg[32];
	read_argv(1,arg,31);
	new target = cmd_target(id,arg,7); //7=obey immunity(1)+allow self(2)+must be alive(4)
	if ( ! target )
		return PLUGIN_HANDLED;

	//grab the optional arg of: number of seconds to enable powerups for...
	//re-using arg variable to keep optional number of seconds
	read_argv(2,arg,31);
	if ( str_to_num(arg) < 1 ) //use 1 to expire, else whatever you want
		arg = "99999"; //~27 hour default

	//vars for caller and target names+authids
	new caller_authid[32],caller_name[32];
	new target_authid[32],target_name[32];

	//fill in caller and target names+authids
	get_user_authid(id,caller_authid,sizeof caller_authid - 1);
	get_user_authid(target,target_authid,sizeof target_authid - 1);
	get_user_name(id,caller_name,sizeof caller_name - 1);
	get_user_name(target,target_name,sizeof target_name - 1);

	// create the powerup entity
	new entity = create_entity("info_tfgoal");


	// bail out if we cannot create the entity we need to do this
	if ( ! entity )
	{
		log_amx("TFC-Powerup: create_entity() failed");
		return PLUGIN_HANDLED;
	}


	// set it to be at the target player's location
	new Float:origin[3];
	entity_get_vector(target,EV_VEC_origin,origin); //grab their location
	entity_set_vector(entity,EV_VEC_origin,origin); //put entity at their location

	// spawn it and set all needed parameters
	entity_set_size(entity,Float:{-1.0,-1.0,-1.0},Float:{1.0,1.0,1.0}); // size for touch
	DispatchKeyValue(entity,"g_a","1"); //player touch activates
	DispatchKeyValue(entity,"g_e","1"); //affects AP only
	DispatchKeyValue(entity,"goal_state","2"); //active goal
	//DEV-NOTE: the tfc "wait" keyval is a good idea but would break this functionality. Don't bother.

	//Is it better to have an if-else block for act_type or will the following be equivalent after optimization?
	//GIVE powerups...
	if ( act_type == ACT_GIVE && ( powerup_type == POWERUP_QUAD || powerup_type == POWERUP_ALL ) ) //if quad should be given
		DispatchKeyValue(entity,"super_damage_finished",arg); //give quad
	if ( act_type == ACT_GIVE && ( powerup_type == POWERUP_INVUL || powerup_type == POWERUP_ALL ) ) //if invul should be given
		DispatchKeyValue(entity,"invincible_finished",arg);
	if ( act_type == ACT_GIVE && ( powerup_type == POWERUP_INVIS || powerup_type == POWERUP_ALL ) ) //if invis should be given
		DispatchKeyValue(entity,"invisible_finished",arg);

	//REMOVE powerups...
	if ( act_type == ACT_REMOVE && ( powerup_type == POWERUP_QUAD || powerup_type == POWERUP_ALL ) ) //if quad should be removed
		DispatchKeyValue(entity,"super_damage_finished","1"); //expire powerup
	if ( act_type == ACT_REMOVE && ( powerup_type == POWERUP_INVUL || powerup_type == POWERUP_ALL ) ) //if invul should be removed
		DispatchKeyValue(entity,"invincible_finished","1"); //expire powerup
	if ( act_type == ACT_REMOVE && ( powerup_type == POWERUP_INVIS || powerup_type == POWERUP_ALL ) ) //if invis should be removed
		DispatchKeyValue(entity,"invisible_finished","1"); //expire powerup

	// spawn the entity
	DispatchSpawn(entity);

	// I'm guessing info_tfgoal needs a time slice of sorts.
	call_think(entity);

	// force the user to touch it
	fake_touch(entity,target);

	// get rid of it
	set_entity_flags(entity,FL_KILLME,1); //turn killme flag on

	// get an "act" string ready for logging, informational purpose
	// get a powerup "act" string ready for logging, informational purpose
	// also make a direction phrase
	new act[16]; //set to "gave" or "removed" (4 or 7 slots, 16 alloc?)
	new powerup_act[16]; //set to "QUAD","INVUL","INVIS", or "ALL-POWERUPS"...
	new direction[8]; //set to "to" or "from"

	// set appropriate act_type string
	if (act_type == ACT_GIVE) {
		act = "gave";
		direction = "to";
	} else {
		act = "removed";
		direction = "from";
	} //if.act_type


	//set appropriate powerup_type string for notifications
	switch (powerup_type)
	{
		case POWERUP_QUAD:
			powerup_act = "QUAD";
		case POWERUP_INVUL:
			powerup_act = "INVUL";
		case POWERUP_INVIS:
			powerup_act = "INVIS";
		case POWERUP_ALL:
			powerup_act = "ALL-POWERUPS";
	}

	// for logging and activity purposes, I'm going to leave the number of
	// seconds as 99999 if it is defaulted to that value.

	// Also, I will replace the seconds string with a more informative value
	// for the case of the removal action with "---".
	if (act_type == ACT_REMOVE)
		arg = "---"; //set to something less confusing


    // log an event similar in format to amx_kick
	log_amx("TFC-Powerup: ^"%s<%d><%s>^" %s %s %s (seconds=%s) ^"%s<%d><%s>^"",
		caller_name,
		get_user_userid(id),
		caller_authid,
		act, //gave|removed
		powerup_act, //ex: QUAD|INVIS|etc
		direction, //to|from
		target_name,
		arg,
		get_user_userid(target),
		target_authid
	);

	// tell the caller that it worked...
	client_print(id,print_console,"[AMXX]: You %s %s %s %s (for %s seconds)",act,powerup_act,direction,target_name,arg)


    // tell the world about this act?...
	//ex: ADMIN: gave|removed POWERUP to|from player TARGET_NAME (for 600 seconds)
	show_activity(id,caller_name,"%s %s %s player %s (for %s seconds)",act,powerup_act,direction,target_name,arg)

	return PLUGIN_HANDLED;
}




