#include "swapper.qh"

#ifdef SVQC
bool buff_Swapper_cond(entity e)
{
	return (IS_PLAYER(e) && DIFF_TEAM(e, WarpZone_SearchInRadius_otherent)
		&& !IS_DEAD(e) && !STAT(FROZEN, e) && !e.vehicle);
}
MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
{
	if (MUTATOR_RETURNVALUE || game_stopped)
		return;

	entity player = M_ARGV(0, entity);
	if (!StatusEffects_active(BUFF_SWAPPER, player))
		return;

	WarpZone_SearchInRadius_otherent = player;
	entity head = WarpZone_SearchInRadius(player.origin, autocvar_g_buffs_swapper_range, MOVE_NOTHING, buff_Swapper_cond);
	entity closest = NULL;
	float head_dist2, best_dist2 = autocvar_g_buffs_swapper_range ** 2;
	for (; head; head = head.chain)
	{
		head_dist2 = vlen2(head.WarpZone_findradius_dist);
		if (head_dist2 < best_dist2)
		{
			best_dist2 = head_dist2;
			closest = head;
		}
	}
	if (closest == NULL)
		return;

	vector my_org    = player.origin;
	vector my_center = CENTER_OF_ENT(player);
	vector my_vel    = player.velocity;
	vector my_ang    = player.angles;
	vector their_org    = closest.origin;
	vector their_center = CENTER_OF_ENT(closest);
	vector their_vel    = closest.velocity;
	vector their_ang    = closest.angles;

	Drop_Special_Items(closest);

	MUTATOR_CALLHOOK(PortalTeleport, player); // initiate flag dropper

	setorigin(player, their_org);
	setorigin(closest, my_org);

	closest.velocity = my_vel;
	closest.angles = my_ang;
	if (IS_BOT_CLIENT(closest))
	{
		closest.v_angle = closest.angles;
		bot_aim_reset(closest);
	}
	closest.fixangle = true;
	closest.oldorigin = my_org;
	closest.oldvelocity = my_vel;
	player.velocity = their_vel;
	player.angles = their_ang;
	if (IS_BOT_CLIENT(player))
	{
		player.v_angle = player.angles;
		bot_aim_reset(player);
	}
	player.fixangle = true;
	player.oldorigin = their_org;
	player.oldvelocity = their_vel;

	// set pusher so player gets the kill if they fall into void
	closest.pusher = player;
	closest.pushltime = time + autocvar_g_maxpushtime;
	closest.istypefrag = PHYS_INPUT_BUTTON_CHAT(closest);

	Send_Effect(EFFECT_SWAPPER, their_center, '0 0 0', 1);
	Send_Effect(EFFECT_SWAPPER, my_center,    '0 0 0', 1);

	sound(player,  CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
	sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);

	// TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
	buff_RemoveAll(player, STATUSEFFECT_REMOVE_NORMAL);
	return true;
}
#endif // SVQC
#ifdef MENUQC
METHOD(SwapperBuff, describe, string(SwapperBuff this))
{
	TC(SwapperBuff, this);
	PAGE_TEXT_INIT();
	PAR(_("The %s buff allows you to press %s to switch places with a nearby enemy once."), COLORED_NAME(this), strcat("^3", _("drop weapon"), "^7"));
	PAR(_("A common usage of this buff is to jump over the map's void, then swap with an enemy, to cause them to fall into the void."));
	PAR(_("The range that the buff works over is limited, so sometimes it may do nothing if there are no enemies nearby."));
	return PAGE_TEXT;
}
#endif // MENUQC
