extensions/tf2/extension.cpp
author Matt Woodrow <pred@alliedmods.net>
Sat May 24 04:08:29 2008 +0000 (2008-05-24)
changeset 2069 80d56f1d58fe
parent 1979 d36fac1a8203
child 2075 ffc871fb7cc8
permissions -rw-r--r--
Added a load-block for incorrect mods to TF2 and cstrike extensions.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod Team Fortress 2 Extension
     5  * Copyright (C) 2004-2008 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 "extension.h"
    33 #include "util.h"
    34 #include "RegNatives.h"
    35 #include "iplayerinfo.h"
    36 #include "sm_trie_tpl.h"
    37 #include "criticals.h"
    38 
    39 /**
    40  * @file extension.cpp
    41  * @brief Implement extension code here.
    42  */
    43 
    44 
    45 TF2Tools g_TF2Tools;
    46 IGameConfig *g_pGameConf = NULL;
    47 
    48 IBinTools *g_pBinTools = NULL;
    49 
    50 SMEXT_LINK(&g_TF2Tools);
    51 
    52 ICvar *icvar = NULL;
    53 
    54 CGlobalVars *gpGlobals = NULL;
    55 
    56 sm_sendprop_info_t *playerSharedOffset;
    57 
    58 extern sp_nativeinfo_t g_TFNatives[];
    59 
    60 int g_resourceEntity;
    61 
    62 SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int , int);
    63 
    64 bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late)
    65 {
    66 	if (strcmp(g_pSM->GetGameFolderName(), "tf") != 0)
    67 	{
    68 		snprintf(error, maxlength, "Cannot Load TF2 Extension on mods other than TF2");
    69 		return false;
    70 	}
    71 
    72 	ServerClass *sc = UTIL_FindServerClass("CTFPlayer");
    73 	if (sc == NULL)
    74 	{
    75 		snprintf(error, maxlength, "Could not find CTFPlayer server class");
    76 		return false;
    77 	}
    78 
    79 	playerSharedOffset = new sm_sendprop_info_t;
    80 
    81 	if (!UTIL_FindDataTable(sc->m_pTable, "DT_TFPlayerShared", playerSharedOffset, 0))
    82 	{
    83 		snprintf(error, maxlength, "Could not find DT_TFPlayerShared data table");
    84 		return false;
    85 	}
    86 
    87 	sharesys->AddDependency(myself, "bintools.ext", true, true);
    88 
    89 	char conf_error[255];
    90 	if (!gameconfs->LoadGameConfigFile("sm-tf2.games", &g_pGameConf, conf_error, sizeof(conf_error)))
    91 	{
    92 		if (conf_error)
    93 		{
    94 			snprintf(error, maxlength, "Could not read sm-tf2.games.txt: %s", conf_error);
    95 		}
    96 		return false;
    97 	}
    98 
    99 	sharesys->AddNatives(myself, g_TFNatives);
   100 	sharesys->RegisterLibrary(myself, "tf2");
   101 
   102 	playerhelpers->RegisterCommandTargetProcessor(this);
   103 
   104 	spengine = g_pSM->GetScriptingEngine();
   105 
   106 	g_pCVar = icvar;
   107 
   108 	return true;
   109 }
   110 
   111 bool TF2Tools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late)
   112 {
   113 	GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
   114 
   115 	gpGlobals = ismm->GetCGlobals();
   116 
   117 	SH_ADD_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true);
   118 
   119 	GET_V_IFACE_CURRENT(GetEngineFactory, icvar, ICvar, CVAR_INTERFACE_VERSION);
   120 
   121 	GET_V_IFACE_CURRENT(GetServerFactory, gameents, IServerGameEnts, INTERFACEVERSION_SERVERGAMEENTS);
   122 
   123 	return true;
   124 }
   125 
   126 void TF2Tools::SDK_OnUnload()
   127 {
   128 	SH_REMOVE_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true);
   129 
   130 	g_RegNatives.UnregisterAll();
   131 	gameconfs->CloseGameConfigFile(g_pGameConf);
   132 	playerhelpers->UnregisterCommandTargetProcessor(this);
   133 }
   134 
   135 void TF2Tools::SDK_OnAllLoaded()
   136 {
   137 	SM_GET_LATE_IFACE(BINTOOLS, g_pBinTools);
   138 
   139 	g_CriticalHitManager.Init();
   140 }
   141 
   142 bool TF2Tools::RegisterConCommandBase(ConCommandBase *pVar)
   143 {
   144 	return g_SMAPI->RegisterConCommandBase(g_PLAPI, pVar);
   145 }
   146 
   147 
   148 bool TF2Tools::QueryRunning(char *error, size_t maxlength)
   149 {
   150 	SM_CHECK_IFACE(BINTOOLS, g_pBinTools);
   151 
   152 	return true;
   153 }
   154 
   155 bool TF2Tools::QueryInterfaceDrop(SMInterface *pInterface)
   156 {
   157 	if (pInterface == g_pBinTools)
   158 	{
   159 		return false;
   160 	}
   161 
   162 	return IExtensionInterface::QueryInterfaceDrop(pInterface);
   163 }
   164 
   165 void TF2Tools::NotifyInterfaceDrop(SMInterface *pInterface)
   166 {
   167 	g_RegNatives.UnregisterAll();
   168 }
   169 
   170 void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax)
   171 {
   172 	g_resourceEntity = FindResourceEntity();
   173 }
   174 
   175 
   176 bool TF2Tools::ProcessCommandTarget(cmd_target_info_t *info)
   177 {
   178 	int max_clients;
   179 	IPlayerInfo *pInfo;
   180 	unsigned int team_index = 0;
   181 	IGamePlayer *pPlayer, *pAdmin;
   182 
   183 	if ((info->flags & COMMAND_FILTER_NO_MULTI) == COMMAND_FILTER_NO_MULTI)
   184 	{
   185 		return false;
   186 	}
   187 
   188 	if (info->admin)
   189 	{
   190 		if ((pAdmin = playerhelpers->GetGamePlayer(info->admin)) == NULL)
   191 		{
   192 			return false;
   193 		}
   194 		if (!pAdmin->IsInGame())
   195 		{
   196 			return false;
   197 		}
   198 	}
   199 	else
   200 	{
   201 		pAdmin = NULL;
   202 	}
   203 
   204 	if (strcmp(info->pattern, "@red") == 0 )
   205 	{
   206 		team_index = 2;
   207 	}
   208 	else if (strcmp(info->pattern, "@blue") == 0)
   209 	{
   210 		team_index = 3;
   211 	}
   212 	else
   213 	{
   214 		return false;
   215 	}
   216 
   217 	info->num_targets = 0;
   218 
   219 	max_clients = playerhelpers->GetMaxClients();
   220 	for (int i = 1; 
   221 		 i <= max_clients && (cell_t)info->num_targets < info->max_targets; 
   222 		 i++)
   223 	{
   224 		if ((pPlayer = playerhelpers->GetGamePlayer(i)) == NULL)
   225 		{
   226 			continue;
   227 		}
   228 		if (!pPlayer->IsInGame())
   229 		{
   230 			continue;
   231 		}
   232 		if ((pInfo = pPlayer->GetPlayerInfo()) == NULL)
   233 		{
   234 			continue;
   235 		}
   236 		if (pInfo->GetTeamIndex() != (int)team_index)
   237 		{
   238 			continue;
   239 		}
   240 		if (playerhelpers->FilterCommandTarget(pAdmin, pPlayer, info->flags) 
   241 			!= COMMAND_TARGET_VALID)
   242 		{
   243 			continue;
   244 		}
   245 		info->targets[info->num_targets] = i;
   246 		info->num_targets++;
   247 	}
   248 
   249 	if (info->num_targets == 0)
   250 	{
   251 		info->reason = COMMAND_TARGET_EMPTY_FILTER;
   252 	}
   253 	else
   254 	{
   255 		info->reason = COMMAND_TARGET_VALID;
   256 	}
   257 
   258 	info->target_name_style = COMMAND_TARGETNAME_RAW;
   259 	if (team_index == 2)
   260 	{
   261 		UTIL_Format(info->target_name, info->target_name_maxlength, "Red Team");
   262 	}
   263 	else if (team_index == 3)
   264 	{
   265 		UTIL_Format(info->target_name, info->target_name_maxlength, "Blue Team");
   266 	}
   267 
   268 	return true;
   269 }
   270 
   271 int FindResourceEntity()
   272 {
   273 	return FindEntityByNetClass(-1, "CTFPlayerResource");
   274 }
   275 
   276 
   277 int FindEntityByNetClass(int start, const char *classname)
   278 {
   279 	edict_t *current;
   280 
   281 	for (int i = ((start != -1) ? start : 0); i < gpGlobals->maxEntities; i++)
   282 	{
   283 		current = engine->PEntityOfEntIndex(i);
   284 		if (current == NULL)
   285 		{
   286 			continue;
   287 		}
   288 
   289 		IServerNetworkable *network = current->GetNetworkable();
   290 
   291 		if (network == NULL)
   292 		{
   293 			continue;
   294 		}
   295 
   296 		ServerClass *sClass = network->GetServerClass();
   297 		const char *name = sClass->GetName();
   298 		
   299 
   300 		if (strcmp(name, classname) == 0)
   301 		{
   302 			return i;
   303 		}
   304 	}
   305 
   306 	return -1;
   307 }
   308 
   309 TFClassType ClassnameToType(const char *classname)
   310 {
   311 	static KTrie<TFClassType> trie;
   312 	static bool filled = false;
   313 	
   314 	if (!filled)
   315 	{
   316 		trie.insert("scout", TFClass_Scout);
   317 		trie.insert("sniper", TFClass_Sniper);
   318 		trie.insert("soldier", TFClass_Soldier);
   319 		trie.insert("demoman", TFClass_DemoMan);
   320 		trie.insert("demo", TFClass_DemoMan);
   321 		trie.insert("medic", TFClass_Medic);
   322 		trie.insert("heavy", TFClass_Heavy);
   323 		trie.insert("hwg", TFClass_Heavy);
   324 		trie.insert("pyro", TFClass_Pyro);
   325 		trie.insert("spy", TFClass_Spy);
   326 		trie.insert("engineer", TFClass_Engineer);
   327 		trie.insert("engy", TFClass_Engineer);
   328 
   329 		filled = true;	
   330 	}
   331 	
   332 	TFClassType *value;
   333 
   334 	if (!(value = trie.retrieve(classname)))
   335 	{
   336 		return TFClass_Unknown;	
   337 	}
   338 
   339 	return *value;
   340 }
   341 
   342 
   343 
   344 /**
   345  * A picture of a blue crab given to me as a gift and stored here for safe keeping
   346  *
   347  * http://www.democracycellproject.net/blog/archives/Clown%20car.jpg
   348  */
   349