147 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
			
		
		
	
	
			147 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
#pragma newdecls required
 | 
						|
 | 
						|
#include <sourcemod>
 | 
						|
#include <sdktools>
 | 
						|
#include <dhooks>
 | 
						|
 | 
						|
Handle hSelectSpawnPoint;
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
public Plugin myinfo =
 | 
						|
{
 | 
						|
	name         = "RandomizeSpawns",
 | 
						|
	author       = "zaCade",
 | 
						|
	description  = "Randomize player spawns.",
 | 
						|
	version      = "1.0.0"
 | 
						|
};
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
public void OnPluginStart()
 | 
						|
{
 | 
						|
	Handle hGameConf;
 | 
						|
	if ((hGameConf = LoadGameConfigFile("RandomizeSpawns.games")) == INVALID_HANDLE)
 | 
						|
	{
 | 
						|
		SetFailState("Couldn't load \"RandomizeSpawns.games\" game config!");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	//
 | 
						|
	int iOffset;
 | 
						|
	if ((iOffset = GameConfGetOffset(hGameConf, "SelectSpawnPoint")) == -1)
 | 
						|
	{
 | 
						|
		CloseHandle(hGameConf);
 | 
						|
		SetFailState("GameConfGetOffset(hGameConf, \"SelectSpawnPoint\") failed!");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((hSelectSpawnPoint = DHookCreate(iOffset, HookType_Entity, ReturnType_CBaseEntity, ThisPointer_CBaseEntity, OnPlayerSelectSpawnPoint)) == INVALID_HANDLE)
 | 
						|
	{
 | 
						|
		CloseHandle(hGameConf);
 | 
						|
		SetFailState("DHookCreate(iOffset, HookType_Entity, ReturnType_CBaseEntity, ThisPointer_CBaseEntity, OnPlayerSelectSpawnPoint) failed!");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	// Late load.
 | 
						|
	for (int client = 1; client <= MaxClients; client++)
 | 
						|
	{
 | 
						|
		if (IsClientInGame(client))
 | 
						|
		{
 | 
						|
			OnClientPutInServer(client);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	CloseHandle(hGameConf);
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
public void OnClientPutInServer(int client)
 | 
						|
{
 | 
						|
	DHookEntity(hSelectSpawnPoint, false, client);
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
public int RandomizeSpawnPoints(int elem1, int elem2, int[] array, Handle hndl)
 | 
						|
{
 | 
						|
	return GetRandomInt(-1, 1);
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
public MRESReturn OnPlayerSelectSpawnPoint(int client, Handle hReturn)
 | 
						|
{
 | 
						|
	if (IsValidEntity(client) && !IsClientInGame(client))
 | 
						|
		return MRES_Ignored;
 | 
						|
 | 
						|
	static int spawnPoints[128];
 | 
						|
	static int spawnCount;
 | 
						|
 | 
						|
	if (!spawnCount)
 | 
						|
	{
 | 
						|
		int spawnPoint = INVALID_ENT_REFERENCE;
 | 
						|
		while ((spawnPoint = FindEntityByClassname(spawnPoint, "info_player_*")) != INVALID_ENT_REFERENCE)
 | 
						|
		{
 | 
						|
			char sClassname[64];
 | 
						|
			GetEntityClassname(spawnPoint, sClassname, sizeof(sClassname));
 | 
						|
 | 
						|
			if (StrEqual(sClassname, "info_player_terrorist", true) || StrEqual(sClassname, "info_player_counterterrorist", true))
 | 
						|
			{
 | 
						|
				spawnPoints[spawnCount++] = spawnPoint;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (spawnCount)
 | 
						|
	{
 | 
						|
		int spawnCountAttempts;
 | 
						|
		while (spawnCountAttempts >= spawnCount)
 | 
						|
		{
 | 
						|
			SortCustom1D(spawnPoints, spawnCount, RandomizeSpawnPoints);
 | 
						|
 | 
						|
			int spawnPoint = spawnPoints[0];
 | 
						|
			if (IsValidEntity(spawnPoint) && IsValidPlayerSpawn(client, spawnPoint))
 | 
						|
			{
 | 
						|
				DHookSetReturn(hReturn, spawnPoint);
 | 
						|
				return MRES_Supercede;
 | 
						|
			}
 | 
						|
 | 
						|
			spawnCountAttempts++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return MRES_Ignored;
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
stock bool IsValidPlayerSpawn(int client, int spawnPoint)
 | 
						|
{
 | 
						|
	float clientMins[3];
 | 
						|
	float clientMaxs[3];
 | 
						|
	GetClientMins(client, clientMins);
 | 
						|
	GetClientMaxs(client, clientMaxs);
 | 
						|
 | 
						|
	float spawnPointOrigin[3];
 | 
						|
	GetEntPropVector(spawnPoint, Prop_Send, "m_vecOrigin", spawnPointOrigin);
 | 
						|
 | 
						|
	TR_TraceHullFilter(spawnPointOrigin, spawnPointOrigin, clientMins, clientMaxs, MASK_PLAYERSOLID, IsValidPlayerSpawnFilter);
 | 
						|
 | 
						|
	return !TR_DidHit();
 | 
						|
}
 | 
						|
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
// Purpose:
 | 
						|
//----------------------------------------------------------------------------------------------------
 | 
						|
public bool IsValidPlayerSpawnFilter(int entity, int contentsMask)
 | 
						|
{
 | 
						|
	return view_as<bool>(entity);
 | 
						|
} |