/* AMX Mod X
*   Force Team Win
*
* (c) Copyright 2006 by VEN
*
* This file is provided as is (no warranties)
*
*     DESCRIPTION
*       Plugin allows to force CT/T team win.
*
*     MODULES
*       engine - ONLY NEEDED for AMXX version < 1.75
*       fakemeta
*       cstrike
*
*     COMMANDS
*       team_win <1|2> - force T/CT win
*
*     NATIVES
*       cs_force_team_win(CsTeams:team) - see ftw.inc
*/

#include <amxmodx>
#include <engine> // engine module ONLY NEEDED for AMXX version < 1.75
#include <fakemeta>
#include <cstrike>
#include <amxmisc> // this is not a module!

// plugin's main information
#define PLUGIN_NAME "Force Team Win"
#define PLUGIN_VERSION "0.1"
#define PLUGIN_AUTHOR "VEN"

// command access level
#define CDM_ACCESS_LEVEL ADMIN_SLAY

// "fc" stands for "fake client"
new g_fc_net_name[] = "fake_client"
new g_fc_dmg_ent[] = "trigger_hurt"
new g_fc_killer[] = "fc_killer"
new g_fc_dmg_val[] = "1000.0"
new g_fc_dmg_type[] = "0"

new g_flags_ae[] = "ae"
new g_team_t[] = "TERRORIST"
new g_team_ct[] = "CT"

new g_ipsz_dmg_ent
new g_msgid_text
new g_msgid_death

new bool:g_round_over
new bool:g_bomb_planted

public plugin_init() {
	register_plugin(PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR)

	register_concmd("team_win", "cmd_team_win", CDM_ACCESS_LEVEL, "<1|2> - force T/CT win")

	register_event("HLTV", "event_new_round", "a", "1=0", "2=0")
	register_logevent("logevent_bomb_plant", 3, "2=Planted_The_Bomb")
	register_logevent("logevent_end_round", 2, "1=Round_End")

	g_ipsz_dmg_ent = engfunc(EngFunc_AllocString, g_fc_dmg_ent)
	g_msgid_text = get_user_msgid("TextMsg")
	g_msgid_death = get_user_msgid("DeathMsg")
}

public event_new_round() {
	g_round_over = false
	g_bomb_planted = false
}

public logevent_bomb_plant() {
	g_bomb_planted = true
}

public logevent_end_round() {
	g_round_over = true
}

public cmd_team_win(id, level, cid) {
	if (!cmd_access(id, level, cid, 2))
		return PLUGIN_HANDLED

	// find which team is specified
	new arg[2]
	read_argv(1, arg, 1)
	new CsTeams:team = CsTeams:str_to_num(arg)
	if (team != CS_TEAM_T && team != CS_TEAM_CT) { // incorrect team
		new hcmd[32], hinfo[128], hflag
		get_concmd(cid, hcmd, 31, hflag, hinfo, 127, level)
		console_print(id, "%L:	%s %s", id, "USAGE", hcmd, hinfo)

		return PLUGIN_HANDLED
	}

	team_loose(team == CS_TEAM_T ? CS_TEAM_CT : CS_TEAM_T) // force opposite team to loose

	return PLUGIN_HANDLED
}

public team_loose(CsTeams:team) {
	if (g_round_over || (g_bomb_planted && team == CS_TEAM_T))
		return 0

	// get all alive players in the team
	new player[32], num, player2[32], num2
	get_players(player, num, g_flags_ae, team == CS_TEAM_T ? g_team_t : g_team_ct)
	get_players(player2, num2, g_flags_ae, team == CS_TEAM_CT ? g_team_t : g_team_ct)
	if (!num || !num2) // no alive players in team(s)
		return 0

	// create a fake client
	new id = engfunc(EngFunc_CreateFakeClient, g_fc_net_name)
	if (!id) // if fake client not created (probably server is full)
		return 0

	// transfer players to temp team
	for (new i = 0; i < num; ++i)
		cs_set_user_team(player[i], CS_TEAM_SPECTATOR)

	// hide text like "fake_client connected", et cetera
	set_msg_block(g_msgid_text, BLOCK_SET)
	dllfunc(DLLFunc_ClientPutInServer, id) // put fc in the server

	cs_set_user_team(id, team) // set it's team
	cs_user_spawn(id) // spawn fc

	// move fc outside map (to hide dead sound/body, etc)
	engfunc(EngFunc_SetOrigin, id, Float:{8191.0, 8191.0, 8191.0})

	set_msg_block(g_msgid_text, BLOCK_NOT) // unset the text block
	set_msg_block(g_msgid_death, BLOCK_ONCE) // hide fc's death
	fc_fakedamage(id) // kill fc by dealing a fake damage

	set_msg_block(g_msgid_text, BLOCK_SET) // set the text block
	server_cmd("kick #%d", get_user_userid(id)) // kick fc
	server_exec() // force kick immediately
	set_msg_block(g_msgid_text, BLOCK_NOT) // unset the text block

	// set players' team back
	for (new i = 0; i < num; ++i)
		cs_set_user_team(player[i], team)

	return 1
}

fc_fakedamage(id) {
	new entity = engfunc(EngFunc_CreateNamedEntity, g_ipsz_dmg_ent)
	if (!entity)
		return 0

	set_dmg_ent_kvd(entity, "dmg", g_fc_dmg_val)
	set_dmg_ent_kvd(entity, "damagetype", g_fc_dmg_type)
	set_dmg_ent_kvd(entity, "origin", "8191 8191 8191")

	dllfunc(DLLFunc_Spawn, entity)
	set_pev(entity, pev_classname, g_fc_killer)
	dllfunc(DLLFunc_Touch, entity, id)
	engfunc(EngFunc_RemoveEntity, entity)

	return 1
}

set_dmg_ent_kvd(entity, key[], value[]) {
	set_kvd(0, KV_ClassName, g_fc_dmg_ent)
	set_kvd(0, KV_KeyName, key)
	set_kvd(0, KV_Value, value)
	set_kvd(0, KV_fHandled, 0)

	return dllfunc(DLLFunc_KeyValue, entity, 0)
}

// native implementation

public plugin_natives() {
	register_native("cs_force_team_win", "native_cs_force_team_win", 1)
}

public native_cs_force_team_win(CsTeams:team) {
	if (team != CS_TEAM_T && team != CS_TEAM_CT) // incorrect team
		return 0

	return team_loose(team == CS_TEAM_T ? CS_TEAM_CT : CS_TEAM_T) // force opposite team to loose
}
