Загрузка данных


#pragma semicolon 1

#include <amxmodx>
#include <hamsandwich>
#include <fakemeta>
#include <reapi>
#include <rezp>

const TASK_WARMUP = 1337;

new const IMMUTABLE_CVARS[][][] =
{
	{ "mp_limitteams", "0" },
	{ "mp_autoteambalance", "0" },
	{ "mp_round_infinite", "b" },
	{ "mp_roundover", "1" },

}; new g_pImmutableCVars[sizeof(IMMUTABLE_CVARS)];

new HookChain:g_iHookChain_Player_Radio_Pre;

new Array:g_aSpawnPoints;

new g_iLastSpawnId;

new g_pCVar_FreezeTime;
new g_pCVar_RoundTime;

new bool:g_bIsWarmup;
new g_iHudSync_Warmup;

new Float:mp_round_restart_delay;
new Float:rz_game_warmup_hud_pos[2];

public plugin_precache()
{
	register_plugin("[ReZP] Game Rules", REZP_VERSION_STR, "fl0wer");

	for (new i = 0; i < sizeof(IMMUTABLE_CVARS); i++)
	{
		g_pImmutableCVars[i] = get_cvar_pointer(IMMUTABLE_CVARS[i][0]);

		set_pcvar_string(g_pImmutableCVars[i], IMMUTABLE_CVARS[i][1]);
		hook_cvar_change(g_pImmutableCVars[i], "@HandleForcingCvarChange");
	}

	g_pCVar_FreezeTime = get_cvar_pointer("mp_freezetime");
	g_pCVar_RoundTime = get_cvar_pointer("mp_roundtime");

	set_pcvar_flags(g_pCVar_FreezeTime, get_pcvar_flags(g_pCVar_FreezeTime) | FCVAR_UNLOGGED);
	set_pcvar_flags(g_pCVar_RoundTime, get_pcvar_flags(g_pCVar_RoundTime) | FCVAR_UNLOGGED);

	bind_pcvar_float(get_cvar_pointer("mp_round_restart_delay"), mp_round_restart_delay);

	bind_pcvar_float(create_cvar("rz_game_warmup_hud_x", "-1.0", _, "", true, -1.0, true, 1.0), rz_game_warmup_hud_pos[0]);
	bind_pcvar_float(create_cvar("rz_game_warmup_hud_y", "0.25", _, "", true, -1.0, true, 1.0), rz_game_warmup_hud_pos[1]);

	g_aSpawnPoints = ArrayCreate(1, 0);

	if (rz_main_warmup_enabled())
	{
		g_bIsWarmup = true;
		g_iHudSync_Warmup = CreateHudSyncObj();

		set_pcvar_num(g_pCVar_FreezeTime, 0);
		set_pcvar_float(g_pCVar_RoundTime, float(rz_main_warmup_time()) / 60.0);
		
		set_task(1.0, "@Task_WarmupNotice", TASK_WARMUP, .flags = "b");
	}
	else
	{
		set_pcvar_num(g_pCVar_FreezeTime, rz_main_prepare_time());
		set_pcvar_float(g_pCVar_RoundTime, float(rz_main_round_time()) / 60.0);
	}
}

public plugin_init()
{
	register_message(get_user_msgid("RoundTime"), "@MSG_RoundTime");

	RegisterHookChain(RG_RoundEnd, "@RoundEnd_Pre", false);
	RegisterHookChain(RG_RoundEnd, "@RoundEnd_Post", true);

	RegisterHookChain(RG_CSGameRules_RestartRound, "@CSGameRules_RestartRound_Pre", false);
	RegisterHookChain(RG_CSGameRules_RestartRound, "@CSGameRules_RestartRound_Post", true);
	RegisterHookChain(RG_CSGameRules_OnRoundFreezeEnd, "@CSGameRules_OnRoundFreezeEnd_Pre", false);
	RegisterHookChain(RG_CSGameRules_OnRoundFreezeEnd, "@CSGameRules_OnRoundFreezeEnd_Post", true);
	RegisterHookChain(RG_CSGameRules_CheckWinConditions, "@CSGameRules_CheckWinConditions_Pre", false);
	RegisterHookChain(RG_CSGameRules_CheckWinConditions, "@CSGameRules_CheckWinConditions_Post", true);
	RegisterHookChain(RG_CSGameRules_FPlayerCanTakeDamage, "@CSGameRules_FPlayerCanTakeDamage_Pre", false);
	RegisterHookChain(RG_CSGameRules_FPlayerCanRespawn, "@CSGameRules_FPlayerCanRespawn_Pre", false);
	RegisterHookChain(RG_CSGameRules_GetPlayerSpawnSpot, "@CSGameRules_GetPlayerSpawnSpot_Pre", false);

	DisableHookChain((g_iHookChain_Player_Radio_Pre = RegisterHookChain(RG_CBasePlayer_Radio, "@CBasePlayer_Radio_Pre", false)));

	ForceLevelInitialize();
}

@MSG_RoundTime(id, dest, player)
{
	if (!g_bIsWarmup && !(get_member_game(m_bGameStarted) && get_member_game(m_bFreezePeriod)))
		return PLUGIN_CONTINUE;

	if (!is_entity(player))
		return PLUGIN_CONTINUE;

	set_member(player, m_iHideHUD, get_member(player, m_iHideHUD) | HIDEHUD_TIMER);
	return PLUGIN_HANDLED;
}

@RoundEnd_Pre(WinStatus:status, ScenarioEventEndRound:event, Float:delay)
{
	if (g_bIsWarmup)
	{
		SetHookChainArg(2, ATYPE_INTEGER, ROUND_GAME_COMMENCE);
		SetHookChainArg(3, ATYPE_FLOAT, mp_round_restart_delay);
		return;
	}

	if (!get_member_game(m_bGameStarted))
		return;

	if (status == WINSTATUS_NONE)
		status = WINSTATUS_DRAW;

	if (status == WINSTATUS_DRAW)
	{
		if (rz_main_roundover_ct_win())
			status = WINSTATUS_CTS;
	}

	SetHookChainArg(1, ATYPE_INTEGER, status);
}

@RoundEnd_Post(WinStatus:status, ScenarioEventEndRound:event, Float:delay)
{
	if (event == ROUND_GAME_COMMENCE)
	{
		set_member_game(m_bFreezePeriod, false);
		set_member_game(m_bCompleteReset, true);

		if (get_member_game(m_iNumSpawnableTerrorist) != 0 || get_member_game(m_iNumSpawnableCT) != 0)
			set_member_game(m_bGameStarted, true);
	}
}

@CSGameRules_RestartRound_Pre()
{
	if (g_bIsWarmup)
	{
		g_bIsWarmup = false;
		remove_task(TASK_WARMUP);
	}

	set_pcvar_num(g_pCVar_FreezeTime, rz_main_prepare_time());
	set_pcvar_float(g_pCVar_RoundTime, float(rz_main_round_time()) / 60.0);
}

@CSGameRules_RestartRound_Post()
{
	ForceLevelInitialize();
}

@CSGameRules_OnRoundFreezeEnd_Pre()
{
	EnableHookChain(g_iHookChain_Player_Radio_Pre);
}

@CSGameRules_OnRoundFreezeEnd_Post()
{
	DisableHookChain(g_iHookChain_Player_Radio_Pre);

	for (new i = 1; i <= MaxClients; i++)
	{
		if (is_nullent(i))
			continue;

		set_member(i, m_bCanShootOverride, false);
	}
}

@CSGameRules_CheckWinConditions_Pre()
{
	if (g_bIsWarmup)
		return HC_SUPERCEDE;

	return HC_CONTINUE;
}

@CSGameRules_CheckWinConditions_Post()
{
	if (g_bIsWarmup)
		return;

	if (get_member_game(m_bRoundTerminating))
		return;

	new numSpawnableTerrorist = get_member_game(m_iNumSpawnableTerrorist);
	new numSpawnableCT = get_member_game(m_iNumSpawnableCT);

	if (!numSpawnableTerrorist || !numSpawnableCT)
	{
		set_member_game(m_bNeededPlayers, true);
		set_member_game(m_bGameStarted, false);
	}

	if (!get_member_game(m_bGameStarted) && (numSpawnableTerrorist != 0 || numSpawnableCT != 0))
		rg_round_end(mp_round_restart_delay, WINSTATUS_DRAW, ROUND_GAME_COMMENCE, .trigger = true);
}

@CSGameRules_FPlayerCanTakeDamage_Pre(id, attacker)
{
	if (get_member_game(m_bRoundTerminating))
	{
		SetHookChainReturn(ATYPE_INTEGER, false);
		return HC_SUPERCEDE;
	}

	if (g_bIsWarmup)
	{
		SetHookChainReturn(ATYPE_INTEGER, false);
		return HC_SUPERCEDE;
	}
	
	return HC_CONTINUE;
}

@CSGameRules_FPlayerCanRespawn_Pre(id)
{
	if (get_member_game(m_bRoundTerminating))
	{
		SetHookChainReturn(ATYPE_INTEGER, false);
		return HC_SUPERCEDE;
	}

	if (g_bIsWarmup)
	{
		if (get_member(id, m_iJoiningState) != JOINED)
		{
			SetHookChainReturn(ATYPE_INTEGER, false);
			return HC_SUPERCEDE;
		}

		SetHookChainReturn(ATYPE_INTEGER, true);
		return HC_SUPERCEDE;
	}
	
	return HC_CONTINUE;
}

@CSGameRules_GetPlayerSpawnSpot_Pre(id)
{
	//if (!get_member_game(m_bFreezePeriod))
	//	return HC_CONTINUE;

	if (TEAM_TERRORIST > get_member(id, m_iTeam) > TEAM_CT)
		return HC_CONTINUE;

	new spot = EntSelectSpawnPoint(id);

	if (is_nullent(spot))
		return HC_CONTINUE;

	new Float:vecOrigin[3];
	new Float:vecAngles[3];

	get_entvar(spot, var_origin, vecOrigin);
	get_entvar(spot, var_angles, vecAngles);

	vecOrigin[2] += 1.0;

	set_entvar(id, var_origin, vecOrigin);
	set_entvar(id, var_v_angle, NULL_VECTOR);
	set_entvar(id, var_velocity, NULL_VECTOR);
	set_entvar(id, var_angles, vecAngles);
	set_entvar(id, var_punchangle, NULL_VECTOR);
	set_entvar(id, var_fixangle, 1);

	SetHookChainReturn(ATYPE_INTEGER, spot);
	return HC_SUPERCEDE;
}

@CBasePlayer_Radio_Pre(id, msgId[], msgVerbose[], pitch, bool:showIcon)
{
	return HC_SUPERCEDE;
}

@Task_WarmupNotice(id)
{
	if (!get_member_game(m_bRoundTerminating))
	{
		new timeleft = floatround((float(get_member_game(m_iRoundTimeSecs)) - get_gametime() + Float:get_member_game(m_fRoundStartTimeReal)));

		set_hudmessage(255, 255, 255, rz_game_warmup_hud_pos[0], rz_game_warmup_hud_pos[1], 0, 0.0, 5.0, 2.0, 0.0);

		if (timeleft > 5)
			ShowSyncHudMsg(0, g_iHudSync_Warmup, "%L", LANG_PLAYER, "RZ_WARMUP", timeleft / 60, timeleft % 60);
		else
			ShowSyncHudMsg(0, g_iHudSync_Warmup, "%L", LANG_PLAYER, "RZ_WARMUP_END", timeleft / 60, timeleft % 60);
	}
	else
	{
		set_dhudmessage(255, 0, 0, rz_game_warmup_hud_pos[0], rz_game_warmup_hud_pos[1], 0, 0.0, 5.0, 2.0, 0.0);
		ShowSyncHudMsg(0, g_iHudSync_Warmup, "%L", LANG_PLAYER, "RZ_WARMUP_START", floatround(Float:get_member_game(m_flRestartRoundTime) - get_gametime()));
	}
}

@HandleForcingCvarChange(pCvar, oldValue[], newValue[])
{
	for (new i = 0; i < sizeof(IMMUTABLE_CVARS); i++)
	{
		if (g_pImmutableCVars[i] != pCvar)
			continue;

		if (equal(newValue, IMMUTABLE_CVARS[i][1]))
			continue;

		set_pcvar_string(pCvar, IMMUTABLE_CVARS[i][1]);
		break;
	}
}

ForceLevelInitialize()
{
	if (!ArraySize(g_aSpawnPoints))
	{
		new entity = NULLENT;

		while ((entity = rg_find_ent_by_class(entity, "info_player_start", true)))
			ArrayPushCell(g_aSpawnPoints, entity);

		while ((entity = rg_find_ent_by_class(entity, "info_player_deathmatch", true)))
			ArrayPushCell(g_aSpawnPoints, entity);
	}

	new spawnPontsNum = ArraySize(g_aSpawnPoints);

	set_member_game(m_iSpawnPointCount_Terrorist, spawnPontsNum);
	set_member_game(m_iSpawnPointCount_CT, spawnPontsNum);

	set_member_game(m_bLevelInitialized, true);
}

EntSelectSpawnPoint(id)
{
	new spotId = g_iLastSpawnId;
	new spawnPontsNum = ArraySize(g_aSpawnPoints);
	new spot;
	new Float:vecOrigin[3];

	do
	{
		if (++spotId >= spawnPontsNum)
			spotId = 0;

		spot = ArrayGetCell(g_aSpawnPoints, spotId);

		if (is_nullent(spot))
			continue;

		get_entvar(spot, var_origin, vecOrigin);

		if (!IsHullVacant(id, vecOrigin, HULL_HUMAN))
			continue;

		break;
	}
	while (spotId != g_iLastSpawnId);

	if (is_nullent(spot))
		return 0;

	g_iLastSpawnId = spotId;

	return spot;
}

bool:IsHullVacant(id, Float:vecOrigin[3], hull)
{
	engfunc(EngFunc_TraceHull, vecOrigin, vecOrigin, 0, hull, id, 0);

	if (get_tr2(0, TR_StartSolid) || get_tr2(0, TR_AllSolid) || !get_tr2(0, TR_InOpen))
		return false;

	return true;
}

public plugin_natives()
{
	register_native("rz_game_is_warmup", "@native_game_is_warmup");
	register_native("rz_game_get_playersnum", "@native_game_get_playersnum");
	register_native("rz_game_get_alivesnum", "@native_game_get_alivesnum");
}

@native_game_is_warmup(plugin, argc)
{
	return g_bIsWarmup;
}

@native_game_get_playersnum(plugin, argc)
{
	enum { arg_team = 1 };

	new TeamName:team = any:get_param(arg_team);
	new playersNum;

	for (new i = 1; i <= MaxClients; i++)
	{
		if (!is_user_connected(i))
			continue;

		if (get_member(i, m_iTeam) != team)
			continue;

		playersNum++;
	}

	return playersNum;
}

@native_game_get_alivesnum(plugin, argc)
{
	static cachedAlivesNum;
	static Float:lastAlivesCalcTime;

	new Float:time = get_gametime();

	if (lastAlivesCalcTime != time)
	{
		lastAlivesCalcTime = time;
		cachedAlivesNum = 0;

		for (new i = 1; i <= MaxClients; i++)
		{
			if (!is_user_alive(i))
				continue;

			cachedAlivesNum++;
		}
	}
	
	return cachedAlivesNum;
}