extensions/sdktools/teamnatives.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Mon Feb 28 19:40:21 2011 -0500 (2011-02-28)
changeset 3197 6da59ea19165
parent 2838 d0b440ee7a64
child 3203 e4f91f0cb04d
permissions -rw-r--r--
Fixed SetTeamScore not updating score on client (bug 2736, r=fyren).
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod SDKTools 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 <sh_vector.h>
    34 
    35 struct TeamInfo
    36 {
    37 	const char *ClassName;
    38 	CBaseEntity *pEnt;
    39 };
    40 
    41 SourceHook::CVector<TeamInfo> g_Teams;
    42 
    43 bool FindTeamEntities(SendTable *pTable, const char *name)
    44 {
    45 	if (strcmp(pTable->GetName(), name) == 0)
    46 	{
    47 		return true;
    48 	}
    49 
    50 	int props = pTable->GetNumProps();
    51 	SendProp *prop;
    52 
    53 	for (int i=0; i<props; i++)
    54 	{
    55 		prop = pTable->GetProp(i);
    56 		if (prop->GetDataTable())
    57 		{
    58 			if (FindTeamEntities(prop->GetDataTable(), name))
    59 			{
    60 				return true;
    61 			}
    62 		}
    63 	}
    64 
    65 	return false;
    66 }
    67 
    68 void SDKTools::OnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
    69 {
    70 	g_Teams.clear();
    71 	g_Teams.resize(1);
    72 
    73 	for (int i=0; i<edictCount; i++)
    74 	{
    75 		edict_t *pEdict = PEntityOfEntIndex(i);
    76 		if (!pEdict || pEdict->IsFree())
    77 		{
    78 			continue;
    79 		}
    80 		if (!pEdict->GetNetworkable())
    81 		{
    82 			continue;
    83 		}
    84 
    85 		ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass();
    86 		if (FindTeamEntities(pClass->m_pTable, "DT_Team"))
    87 		{
    88 			SendProp *pTeamNumProp = g_pGameHelpers->FindInSendTable(pClass->GetName(), "m_iTeamNum");
    89 
    90 			if (pTeamNumProp != NULL)
    91 			{
    92 				int offset = pTeamNumProp->GetOffset();
    93 				CBaseEntity *pEnt = pEdict->GetUnknown()->GetBaseEntity();
    94 				int TeamIndex = *(int *)((unsigned char *)pEnt + offset);
    95 
    96 				if (TeamIndex >= (int)g_Teams.size())
    97 				{
    98 					g_Teams.resize(TeamIndex+1);
    99 				}
   100 				g_Teams[TeamIndex].ClassName = pClass->GetName();
   101 				g_Teams[TeamIndex].pEnt = pEnt;
   102 			}
   103 		}
   104 	}
   105 }
   106 
   107 static cell_t GetTeamCount(IPluginContext *pContext, const cell_t *params)
   108 {
   109 	return g_Teams.size();
   110 }
   111 
   112 static int g_teamname_offset = -1;
   113 
   114 const char *tools_GetTeamName(int team)
   115 {
   116 	if (size_t(team) >= g_Teams.size())
   117 		return NULL;
   118 	if (g_teamname_offset == 0)
   119 		return NULL;
   120 	if (g_teamname_offset == -1)
   121 	{
   122 		SendProp *prop = g_pGameHelpers->FindInSendTable(g_Teams[team].ClassName, "m_szTeamname");
   123 		if (prop == NULL)
   124 		{
   125 			g_teamname_offset = 0;
   126 			return NULL;
   127 		}
   128 		g_teamname_offset = prop->GetOffset();
   129 	}
   130 
   131 	return (const char *)((unsigned char *)g_Teams[team].pEnt + g_teamname_offset);
   132 }
   133 
   134 static cell_t GetTeamName(IPluginContext *pContext, const cell_t *params)
   135 {
   136 	int teamindex = params[1];
   137 	if (teamindex >= (int)g_Teams.size() || !g_Teams[teamindex].ClassName)
   138 		return pContext->ThrowNativeError("Team index %d is invalid", teamindex);
   139 
   140 	if (g_teamname_offset == 0)
   141 		return pContext->ThrowNativeError("Team names are not available on this game.");
   142 
   143 	const char *name = tools_GetTeamName(teamindex);
   144 	if (name == NULL)
   145 		return pContext->ThrowNativeError("Team names are not available on this game.");
   146 
   147 	pContext->StringToLocalUTF8(params[2], params[3], name, NULL);
   148 
   149 	return 1;
   150 }
   151 
   152 static cell_t GetTeamScore(IPluginContext *pContext, const cell_t *params)
   153 {
   154 	int teamindex = params[1];
   155 	if (teamindex >= (int)g_Teams.size() || !g_Teams[teamindex].ClassName)
   156 	{
   157 		return pContext->ThrowNativeError("Team index %d is invalid", teamindex);
   158 	}
   159 
   160 	static int offset = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "m_iScore")->GetOffset();
   161 
   162 	return *(int *)((unsigned char *)g_Teams[teamindex].pEnt + offset);
   163 }
   164 
   165 static cell_t SetTeamScore(IPluginContext *pContext, const cell_t *params)
   166 {
   167 	int teamindex = params[1];
   168 	if (teamindex >= (int)g_Teams.size() || !g_Teams[teamindex].ClassName)
   169 	{
   170 		return pContext->ThrowNativeError("Team index %d is invalid", teamindex);
   171 	}
   172 
   173 	static int offset = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "m_iScore")->GetOffset();
   174 
   175 	CBaseEntity *pTeam = g_Teams[teamindex].pEnt;
   176 	*(int *)((unsigned char *)pTeam + offset) = params[2];
   177 	gamehelpers->SetEdictStateChanged(pTeam, offset);
   178 
   179 	return 1;
   180 }
   181 
   182 static cell_t GetTeamClientCount(IPluginContext *pContext, const cell_t *params)
   183 {
   184 	int teamindex = params[1];
   185 	if (teamindex >= (int)g_Teams.size() || !g_Teams[teamindex].ClassName)
   186 	{
   187 		return pContext->ThrowNativeError("Team index %d is invalid", teamindex);
   188 	}
   189 
   190 	SendProp *pProp = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "\"player_array\"");
   191 	ArrayLengthSendProxyFn fn = pProp->GetArrayLengthProxy();
   192 
   193 	return fn(g_Teams[teamindex].pEnt, 0);
   194 }
   195 
   196 sp_nativeinfo_t g_TeamNatives[] = 
   197 {
   198 	{"GetTeamCount",			GetTeamCount},
   199 	{"GetTeamName",				GetTeamName},
   200 	{"GetTeamScore",			GetTeamScore},
   201 	{"SetTeamScore",			SetTeamScore},
   202 	{"GetTeamClientCount",		GetTeamClientCount},
   203 	{NULL,						NULL}
   204 };