diff --git a/extensions/sdktools/extension.cpp b/extensions/sdktools/extension.cpp index 9a3a26b2..7afefba0 100644 --- a/extensions/sdktools/extension.cpp +++ b/extensions/sdktools/extension.cpp @@ -48,6 +48,7 @@ */ SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); +SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int, int); SDKTools g_SdkTools; /**< Global singleton for extension's main interface */ IServerGameEnts *gameents = NULL; @@ -73,6 +74,7 @@ extern sp_nativeinfo_t g_TRNatives[]; extern sp_nativeinfo_t g_StringTableNatives[]; extern sp_nativeinfo_t g_VoiceNatives[]; extern sp_nativeinfo_t g_EntInputNatives[]; +extern sp_nativeinfo_t g_TeamNatives[]; bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) { @@ -85,6 +87,7 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) sharesys->AddNatives(myself, g_StringTableNatives); sharesys->AddNatives(myself, g_VoiceNatives); sharesys->AddNatives(myself, g_EntInputNatives); + sharesys->AddNatives(myself, g_TeamNatives); SM_GET_IFACE(GAMEHELPERS, g_pGameHelpers); @@ -103,6 +106,7 @@ bool SDKTools::SDK_OnLoad(char *error, size_t maxlength, bool late) CONVAR_REGISTER(this); SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true); + SH_ADD_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &SDKTools::OnServerActivate, false); MathLib_Init(2.2f, 2.2f, 0.0f, 2); @@ -146,6 +150,7 @@ void SDKTools::SDK_OnUnload() playerhelpers->RemoveClientListener(&g_SdkTools); SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SDKTools::LevelInit, true); + SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, ServerActivate, gamedll, this, &SDKTools::OnServerActivate, false); } bool SDKTools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool late) diff --git a/extensions/sdktools/extension.h b/extensions/sdktools/extension.h index 81060576..2556a01f 100644 --- a/extensions/sdktools/extension.h +++ b/extensions/sdktools/extension.h @@ -82,6 +82,7 @@ public: // IVoiceServer bool OnSetClientListening(int iReceiver, int iSender, bool bListen); public: bool LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background); + void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); }; extern SDKTools g_SdkTools; diff --git a/extensions/sdktools/msvc8/sdktools.vcproj b/extensions/sdktools/msvc8/sdktools.vcproj index 04c5ee9f..4eeee64a 100644 --- a/extensions/sdktools/msvc8/sdktools.vcproj +++ b/extensions/sdktools/msvc8/sdktools.vcproj @@ -680,6 +680,10 @@ RelativePath="..\inputnatives.cpp" > + + diff --git a/extensions/sdktools/teamnatives.cpp b/extensions/sdktools/teamnatives.cpp new file mode 100644 index 00000000..a3de00f5 --- /dev/null +++ b/extensions/sdktools/teamnatives.cpp @@ -0,0 +1,171 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod SDKTools Extension + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include "extension.h" +#include + +struct TeamInfo +{ + const char *ClassName; + CBaseEntity *pEnt; +}; + +SourceHook::CVector g_Teams; + +bool FindTeamEntities(SendTable *pTable, const char *name) +{ + int props = pTable->GetNumProps(); + SendProp *prop; + + for (int i=0; iGetProp(i); + if (prop->GetDataTable()) + { + if (strcmp(prop->GetDataTable()->GetName(), name) == 0) + { + return true; + } + if (FindTeamEntities(prop->GetDataTable(), name)) + { + return true; + } + } + } + + return false; +} + +void SDKTools::OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) +{ + g_Teams.clear(); + g_Teams.resize(1); + + for (int i=0; iPEntityOfEntIndex(i); + if (!pEdict || pEdict->IsFree()) + { + continue; + } + if (!pEdict->GetNetworkable()) + { + continue; + } + + ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass(); + if (FindTeamEntities(pClass->m_pTable, "DT_Team")) + { + static int offset = g_pGameHelpers->FindInSendTable(pClass->GetName(), "m_iTeamNum")->GetOffset(); + CBaseEntity *pEnt = pEdict->GetUnknown()->GetBaseEntity(); + int TeamIndex = *(int *)((unsigned char *)pEnt + offset); + + if (TeamIndex >= (int)g_Teams.size()) + { + g_Teams.resize(TeamIndex+1); + } + g_Teams[TeamIndex].ClassName = pClass->GetName(); + g_Teams[TeamIndex].pEnt = pEnt; + } + } +} + +static cell_t GetTeamCount(IPluginContext *pContext, const cell_t *params) +{ + return g_Teams.size(); +} + +static cell_t GetTeamName(IPluginContext *pContext, const cell_t *params) +{ + int teamindex = params[1]; + if (teamindex > (int)g_Teams.size()) + { + pContext->ThrowNativeError("Team index %d is invalid", teamindex); + } + + static int offset = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "m_szTeamname")->GetOffset(); + char *name = (char *)((unsigned char *)g_Teams[teamindex].pEnt + offset); + + pContext->StringToLocalUTF8(params[2], params[3], name, NULL); + + return 1; +} + +static cell_t GetTeamScore(IPluginContext *pContext, const cell_t *params) +{ + int teamindex = params[1]; + if (teamindex > (int)g_Teams.size()) + { + pContext->ThrowNativeError("Team index %d is invalid", teamindex); + } + + static int offset = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "m_iScore")->GetOffset(); + + return *(int *)((unsigned char *)g_Teams[teamindex].pEnt + offset); +} + +static cell_t SetTeamScore(IPluginContext *pContext, const cell_t *params) +{ + int teamindex = params[1]; + if (teamindex > (int)g_Teams.size()) + { + pContext->ThrowNativeError("Team index %d is invalid", teamindex); + } + + static int offset = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "m_iScore")->GetOffset(); + *(int *)((unsigned char *)g_Teams[teamindex].pEnt + offset) = params[2]; + + return 1; +} + +static cell_t GetTeamClientCount(IPluginContext *pContext, const cell_t *params) +{ + int teamindex = params[1]; + if (teamindex > (int)g_Teams.size()) + { + pContext->ThrowNativeError("Team index %d is invalid", teamindex); + } + + SendProp *pProp = g_pGameHelpers->FindInSendTable(g_Teams[teamindex].ClassName, "\"player_array\""); + ArrayLengthSendProxyFn fn = pProp->GetArrayLengthProxy(); + + return fn(g_Teams[teamindex].pEnt, 0); +} + +sp_nativeinfo_t g_TeamNatives[] = +{ + {"GetTeamCount", GetTeamCount}, + {"GetTeamName", GetTeamName}, + {"GetTeamScore", GetTeamScore}, + {"SetTeamScore", SetTeamScore}, + {"GetTeamClientCount", GetTeamClientCount}, + {NULL, NULL} +}; diff --git a/plugins/include/sdktools_functions.inc b/plugins/include/sdktools_functions.inc index e126611c..3718bcae 100644 --- a/plugins/include/sdktools_functions.inc +++ b/plugins/include/sdktools_functions.inc @@ -217,6 +217,51 @@ native bool:DispatchKeyValueVector(entity, const String:keyName[], const Float:v */ native GetClientAimTarget(client, bool:only_clients=true); +/** + * Returns the total number of teams in a game. + * + * @return Total number of teams. + */ +native GetTeamCount(); + +/** + * Retrieves the team name based on a team index. + * + * @param index Team index. + * @param name Buffer to store string in. + * @param maxlength Maximum length of string buffer. + * @noreturn + * @error Invalid team index. + */ +native GetTeamName(index, String:name[], maxlength); + +/** + * Returns the score of a team based on a team index. + * + * @param index Team index. + * @return Score. + * @error Invalid team index. + */ +native GetTeamScore(index); + +/** + * Sets the score of a team based on a team index. + * + * @param index Team index. + * @return Score. + * @error Invalid team index. + */ +native SetTeamScore(index); + +/** + * Retrieves the number of players in a certain team. + * + * @param index Team index. + * @return Number of players in the team. + * @error Invalid team index. + */ +native GetTeamClientCount(index); + /** * @deprecated */