extensions/tf2/extension.cpp
author Ruben Gonzalez <drifter01620@gmail.com>
Thu May 22 09:49:27 2014 -0400 (2014-05-22)
changeset 4378 568f4497ef4a
parent 4188 89782d5fc91b
permissions -rw-r--r--
Update CS:GO team score gamedata.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Team Fortress 2 Extension
     5  * Copyright (C) 2004-2011 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <sourcemod_version.h>
    33 #include "extension.h"
    34 #include "util.h"
    35 #include "RegNatives.h"
    36 #include "iplayerinfo.h"
    37 #include "sm_trie_tpl.h"
    38 #include "criticals.h"
    39 #include "holiday.h"
    40 #include "conditions.h"
    41 #include "gameplayrules.h"
    42 #include "teleporter.h"
    43 #include "CDetour/detours.h"
    44 #include "ISDKHooks.h"
    45 
    46 /**
    47  * @file extension.cpp
    48  * @brief Implement extension code here.
    49  */
    50 
    51 
    52 TF2Tools g_TF2Tools;
    53 IGameConfig *g_pGameConf = NULL;
    54 
    55 IBinTools *g_pBinTools = NULL;
    56 ISDKHooks *g_pSDKHooks = NULL;
    57 
    58 SMEXT_LINK(&g_TF2Tools);
    59 
    60 ICvar *icvar = NULL;
    61 
    62 CGlobalVars *gpGlobals = NULL;
    63 
    64 sm_sendprop_info_t *playerSharedOffset;
    65 
    66 extern sp_nativeinfo_t g_TFNatives[];
    67 
    68 int g_resourceEntity;
    69 
    70 SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int , int);
    71 
    72 bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late)
    73 {
    74 	if (strcmp(g_pSM->GetGameFolderName(), "tf") != 0)
    75 	{
    76 		UTIL_Format(error, maxlength, "Cannot Load TF2 Extension on mods other than TF2");
    77 		return false;
    78 	}
    79 
    80 	ServerClass *sc = UTIL_FindServerClass("CTFPlayer");
    81 	if (sc == NULL)
    82 	{
    83 		UTIL_Format(error, maxlength, "Could not find CTFPlayer server class");
    84 		return false;
    85 	}
    86 
    87 	playerSharedOffset = new sm_sendprop_info_t;
    88 
    89 	if (!UTIL_FindDataTable(sc->m_pTable, "DT_TFPlayerShared", playerSharedOffset, 0))
    90 	{
    91 		UTIL_Format(error, maxlength, "Could not find DT_TFPlayerShared data table");
    92 		return false;
    93 	}
    94 
    95 	sharesys->AddDependency(myself, "bintools.ext", true, true);
    96 	sharesys->AddDependency(myself, "sdkhooks.ext", true, true);
    97 
    98 	char conf_error[255] = "";
    99 	if (!gameconfs->LoadGameConfigFile("sm-tf2.games", &g_pGameConf, conf_error, sizeof(conf_error)))
   100 	{
   101 		if (conf_error[0])
   102 		{
   103 			UTIL_Format(error, maxlength, "Could not read sm-tf2.games.txt: %s", conf_error);
   104 		}
   105 		return false;
   106 	}
   107 
   108 	CDetourManager::Init(g_pSM->GetScriptingEngine(), g_pGameConf);
   109 
   110 	sharesys->AddNatives(myself, g_TFNatives);
   111 	sharesys->RegisterLibrary(myself, "tf2");
   112 
   113 	plsys->AddPluginsListener(this);
   114 
   115 	playerhelpers->RegisterCommandTargetProcessor(this);
   116 	playerhelpers->AddClientListener(this);
   117 
   118 	g_critForward = forwards->CreateForward("TF2_CalcIsAttackCritical", ET_Hook, 4, NULL, Param_Cell, Param_Cell, Param_String, Param_CellByRef);
   119 	g_isHolidayForward = forwards->CreateForward("TF2_OnIsHolidayActive", ET_Event, 2, NULL, Param_Cell, Param_CellByRef);
   120 	g_addCondForward = forwards->CreateForward("TF2_OnConditionAdded", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
   121 	g_removeCondForward = forwards->CreateForward("TF2_OnConditionRemoved", ET_Ignore, 2, NULL, Param_Cell, Param_Cell);
   122 	g_waitingPlayersStartForward = forwards->CreateForward("TF2_OnWaitingForPlayersStart", ET_Ignore, 0, NULL);
   123 	g_waitingPlayersEndForward = forwards->CreateForward("TF2_OnWaitingForPlayersEnd", ET_Ignore, 0, NULL);
   124 	g_teleportForward = forwards->CreateForward("TF2_OnPlayerTeleport", ET_Hook, 3, NULL, Param_Cell, Param_Cell, Param_CellByRef);
   125 
   126 	g_pCVar = icvar;
   127 
   128 	m_CritDetoursEnabled = false;
   129 	m_IsHolidayDetourEnabled = false;
   130 	m_CondChecksEnabled = false;
   131 	m_RulesDetoursEnabled = false;
   132 	m_TeleportDetourEnabled = false;
   133 
   134 	return true;
   135 }
   136 
   137 const char *TF2Tools::GetExtensionVerString()
   138 {
   139 	return SOURCEMOD_VERSION;
   140 }
   141 
   142 const char *TF2Tools::GetExtensionDateString()
   143 {
   144 	return SOURCEMOD_BUILD_TIME;
   145 }
   146 
   147 bool TF2Tools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
   148 {
   149 	GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
   150 
   151 	gpGlobals = ismm->GetCGlobals();
   152 
   153 	SH_ADD_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true);
   154 
   155 	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
   156 
   157 	GET_V_IFACE_CURRENT(GetEngineFactory, m_GameEventManager, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
   158 	m_GameEventManager->AddListener(this, "teamplay_restart_round", true);
   159 
   160 	return true;
   161 }
   162 
   163 void TF2Tools::SDK_OnUnload()
   164 {
   165 	SH_REMOVE_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true);
   166 
   167 	g_RegNatives.UnregisterAll();
   168 	gameconfs->CloseGameConfigFile(g_pGameConf);
   169 	playerhelpers->UnregisterCommandTargetProcessor(this);
   170 	playerhelpers->RemoveClientListener(this);
   171 
   172 	plsys->RemovePluginsListener(this);
   173 
   174 	forwards->ReleaseForward(g_critForward);
   175 	forwards->ReleaseForward(g_isHolidayForward);
   176 	forwards->ReleaseForward(g_addCondForward);
   177 	forwards->ReleaseForward(g_removeCondForward);
   178 	forwards->ReleaseForward(g_waitingPlayersStartForward);
   179 	forwards->ReleaseForward(g_waitingPlayersEndForward);
   180 	forwards->ReleaseForward(g_teleportForward);
   181 
   182 	if (g_pSDKHooks != NULL)
   183 	{
   184 		g_pSDKHooks->RemoveEntityListener(&g_CritManager);
   185 	}
   186 }
   187 
   188 void TF2Tools::SDK_OnAllLoaded()
   189 {
   190 	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
   191 	SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
   192 
   193 	if (g_pSDKHooks != NULL)
   194 	{
   195 		g_pSDKHooks->AddEntityListener(&g_CritManager);
   196 	}
   197 }
   198 
   199 bool TF2Tools::RegisterConCommandBase(ConCommandBase *pVar)
   200 {
   201 	return g_SMAPI->RegisterConCommandBase(g_PLAPI, pVar);
   202 }
   203 
   204 void TF2Tools::FireGameEvent( IGameEvent *event )
   205 {
   206 	timersys->NotifyOfGameStart();
   207 	timersys->MapTimeLeftChanged();
   208 }
   209 
   210 bool TF2Tools::QueryRunning(char *error, size_t maxlength)
   211 {
   212 	SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
   213 	SM_GET_LATE_IFACE(SDKHOOKS, g_pSDKHooks);
   214 
   215 	return true;
   216 }
   217 
   218 bool TF2Tools::QueryInterfaceDrop(SMInterface *pInterface)
   219 {
   220 	if (pInterface == g_pBinTools)
   221 	{
   222 		return false;
   223 	}
   224 
   225 	if (pInterface == g_pSDKHooks)
   226 	{
   227 		return false;
   228 	}
   229 
   230 	return IExtensionInterface::QueryInterfaceDrop(pInterface);
   231 }
   232 
   233 void TF2Tools::NotifyInterfaceDrop(SMInterface *pInterface)
   234 {
   235 	g_RegNatives.UnregisterAll();
   236 }
   237 
   238 void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
   239 {
   240 	g_resourceEntity = FindResourceEntity();
   241 }
   242 
   243 bool TF2Tools::ProcessCommandTarget(cmd_target_info_t *info)
   244 {
   245 	int max_clients;
   246 	IPlayerInfo *pInfo;
   247 	unsigned int team_index = 0;
   248 	IGamePlayer *pPlayer, *pAdmin;
   249 
   250 	if ((info->flags & COMMAND_FILTER_NO_MULTI) == COMMAND_FILTER_NO_MULTI)
   251 	{
   252 		return false;
   253 	}
   254 
   255 	if (info->admin)
   256 	{
   257 		if ((pAdmin = playerhelpers->GetGamePlayer(info->admin)) == NULL)
   258 		{
   259 			return false;
   260 		}
   261 		if (!pAdmin->IsInGame())
   262 		{
   263 			return false;
   264 		}
   265 	}
   266 	else
   267 	{
   268 		pAdmin = NULL;
   269 	}
   270 
   271 	if (strcmp(info->pattern, "@red") == 0 )
   272 	{
   273 		team_index = 2;
   274 	}
   275 	else if (strcmp(info->pattern, "@blue") == 0)
   276 	{
   277 		team_index = 3;
   278 	}
   279 	else
   280 	{
   281 		return false;
   282 	}
   283 
   284 	info->num_targets = 0;
   285 
   286 	max_clients = playerhelpers->GetMaxClients();
   287 	for (int i = 1; 
   288 		 i <= max_clients && (cell_t)info->num_targets < info->max_targets; 
   289 		 i++)
   290 	{
   291 		if ((pPlayer = playerhelpers->GetGamePlayer(i)) == NULL)
   292 		{
   293 			continue;
   294 		}
   295 		if (!pPlayer->IsInGame())
   296 		{
   297 			continue;
   298 		}
   299 		if ((pInfo = pPlayer->GetPlayerInfo()) == NULL)
   300 		{
   301 			continue;
   302 		}
   303 		if (pInfo->GetTeamIndex() != (int)team_index)
   304 		{
   305 			continue;
   306 		}
   307 		if (playerhelpers->FilterCommandTarget(pAdmin, pPlayer, info->flags) 
   308 			!= COMMAND_TARGET_VALID)
   309 		{
   310 			continue;
   311 		}
   312 		info->targets[info->num_targets] = i;
   313 		info->num_targets++;
   314 	}
   315 
   316 	if (info->num_targets == 0)
   317 	{
   318 		info->reason = COMMAND_TARGET_EMPTY_FILTER;
   319 	}
   320 	else
   321 	{
   322 		info->reason = COMMAND_TARGET_VALID;
   323 	}
   324 
   325 	info->target_name_style = COMMAND_TARGETNAME_RAW;
   326 	if (team_index == 2)
   327 	{
   328 		UTIL_Format(info->target_name, info->target_name_maxlength, "Red Team");
   329 	}
   330 	else if (team_index == 3)
   331 	{
   332 		UTIL_Format(info->target_name, info->target_name_maxlength, "Blue Team");
   333 	}
   334 	
   335 	return true;
   336 }
   337 
   338 void TF2Tools::OnPluginLoaded(IPlugin *plugin)
   339 {
   340 	if (!m_CritDetoursEnabled && g_critForward->GetFunctionCount())
   341 	{
   342 		m_CritDetoursEnabled = g_CritManager.TryEnable();
   343 	}
   344 
   345 	if (!m_IsHolidayDetourEnabled && g_isHolidayForward->GetFunctionCount())
   346 	{
   347 		m_IsHolidayDetourEnabled = InitialiseIsHolidayDetour();
   348 	}
   349 
   350 	if (!m_CondChecksEnabled
   351 		&& ( g_addCondForward->GetFunctionCount() || g_removeCondForward->GetFunctionCount() )
   352 		)
   353 	{
   354 		m_CondChecksEnabled = InitialiseConditionChecks();
   355 	}
   356 
   357 	if (!m_RulesDetoursEnabled
   358 		&& ( g_waitingPlayersStartForward->GetFunctionCount() || g_waitingPlayersEndForward->GetFunctionCount() )
   359 		)
   360 	{
   361 		m_RulesDetoursEnabled = InitialiseRulesDetours();
   362 	}
   363 
   364 	if (!m_TeleportDetourEnabled && g_teleportForward->GetFunctionCount())
   365 	{
   366 		m_TeleportDetourEnabled = InitialiseTeleporterDetour();
   367 	}
   368 }
   369 
   370 void TF2Tools::OnPluginUnloaded(IPlugin *plugin)
   371 {
   372 	if (m_CritDetoursEnabled && !g_critForward->GetFunctionCount())
   373 	{
   374 		g_CritManager.Disable();
   375 		m_CritDetoursEnabled = false;
   376 	}
   377 	if (m_IsHolidayDetourEnabled && !g_isHolidayForward->GetFunctionCount())
   378 	{
   379 		RemoveIsHolidayDetour();
   380 		m_IsHolidayDetourEnabled = false;
   381 	}
   382 	if (m_CondChecksEnabled)
   383 	{
   384 		if (!g_addCondForward->GetFunctionCount() && !g_removeCondForward->GetFunctionCount())
   385 		{
   386 			RemoveConditionChecks();
   387 			m_CondChecksEnabled = false;
   388 		}
   389 	}
   390 	if (m_RulesDetoursEnabled)
   391 	{
   392 		if (!g_waitingPlayersStartForward->GetFunctionCount() && !g_waitingPlayersEndForward->GetFunctionCount())
   393 		{
   394 			RemoveRulesDetours();
   395 			m_RulesDetoursEnabled = false;
   396 		}
   397 	}
   398 	if (m_TeleportDetourEnabled && !g_teleportForward->GetFunctionCount())
   399 	{
   400 		RemoveTeleporterDetour();
   401 		m_TeleportDetourEnabled = false;
   402 	}
   403 }
   404 
   405 void TF2Tools::OnClientPutInServer(int client)
   406 {
   407 	Conditions_OnClientPutInServer(client);
   408 }
   409 
   410 int FindResourceEntity()
   411 {
   412 	return FindEntityByNetClass(-1, "CTFPlayerResource");
   413 }
   414 
   415 
   416 int FindEntityByNetClass(int start, const char *classname)
   417 {
   418 	edict_t *current;
   419 
   420 	for (int i = ((start != -1) ? start : 0); i < gpGlobals->maxEntities; i++)
   421 	{
   422 		current = engine->PEntityOfEntIndex(i);
   423 		if (current == NULL)
   424 		{
   425 			continue;
   426 		}
   427 
   428 		IServerNetworkable *network = current->GetNetworkable();
   429 
   430 		if (network == NULL)
   431 		{
   432 			continue;
   433 		}
   434 
   435 		ServerClass *sClass = network->GetServerClass();
   436 		const char *name = sClass->GetName();
   437 		
   438 
   439 		if (strcmp(name, classname) == 0)
   440 		{
   441 			return i;
   442 		}
   443 	}
   444 
   445 	return -1;
   446 }
   447 
   448 TFClassType ClassnameToType(const char *classname)
   449 {
   450 	static KTrie<TFClassType> trie;
   451 	static bool filled = false;
   452 	
   453 	if (!filled)
   454 	{
   455 		trie.insert("scout", TFClass_Scout);
   456 		trie.insert("sniper", TFClass_Sniper);
   457 		trie.insert("soldier", TFClass_Soldier);
   458 		trie.insert("demoman", TFClass_DemoMan);
   459 		trie.insert("demo", TFClass_DemoMan);
   460 		trie.insert("medic", TFClass_Medic);
   461 		trie.insert("heavy", TFClass_Heavy);
   462 		trie.insert("heavyweap", TFClass_Heavy);
   463 		trie.insert("heavyweapons", TFClass_Heavy);
   464 		trie.insert("hwg", TFClass_Heavy);
   465 		trie.insert("pyro", TFClass_Pyro);
   466 		trie.insert("spy", TFClass_Spy);
   467 		trie.insert("engineer", TFClass_Engineer);
   468 		trie.insert("engy", TFClass_Engineer);
   469 
   470 		filled = true;	
   471 	}
   472 	
   473 	TFClassType *value;
   474 
   475 	if (!(value = trie.retrieve(classname)))
   476 	{
   477 		return TFClass_Unknown;	
   478 	}
   479 
   480 	return *value;
   481 }
   482 
   483 
   484 
   485 /**
   486  * A picture of a blue crab given to me as a gift and stored here for safe keeping
   487  *
   488  * http://sourcemod.net/Clown%20car.jpg
   489  */
   490