diff --git a/extensions/tf2/Makefile b/extensions/tf2/Makefile new file mode 100644 index 00000000..af829ccf --- /dev/null +++ b/extensions/tf2/Makefile @@ -0,0 +1,104 @@ +#(C)2004-2008 Metamod:Source Development Team +# Makefile written by David "BAILOPAN" Anderson + +HL2SDK_ORIG = ../../../hl2sdk +HL2SDK_OB = ../../../hl2sdk-ob +SOURCEMM14 = ../../../sourcemm-1.4 +SOURCEMM16 = ../../../sourcemm-1.6 +SRCDS_BASE = ~/srcds +SMSDK = ../.. + +##################################### +### EDIT BELOW FOR OTHER PROJECTS ### +##################################### + +PROJECT = game.tf2 + +OBJECTS = sdk/smsdk_ext.cpp extension.cpp RegNatives.cpp natives.cpp util.cpp + +############################################## +### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### +############################################## + +C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing +C_DEBUG_FLAGS = -g -ggdb3 +CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden +CPP = gcc-4.1 + +ifeq "$(ENGINE)" "original" + HL2SDK = $(HL2SDK_ORIG) + HL2PUB = $(HL2SDK_ORIG)/public + HL2LIB = $(HL2SDK_ORIG)/linux_sdk + METAMOD = $(SOURCEMM14) + INCLUDE += -I$(HL2SDK)/public/dlls + SRCDS = $(SRCDS_BASE) +endif +ifeq "$(ENGINE)" "orangebox" + HL2SDK = $(HL2SDK_OB) + HL2PUB = $(HL2SDK_OB)/public + HL2LIB = $(HL2SDK_OB)/linux_sdk + CFLAGS += -DORANGEBOX_BUILD + METAMOD = $(SOURCEMM16) + INCLUDE += -I$(HL2SDK)/public/game/server -I$(HL2SDK)/common + SRCDS = $(SRCDS_BASE)/orangebox +endif +ifeq "$(ENGINE)" "" + echo "You must supply ENGINE=orangebox or ENGINE=original" + false +endif + +LINK_HL2 = $(HL2LIB)/tier1_i486.a $(HL2LIB)/mathlib_i486.a vstdlib_i486.so tier0_i486.so + +LINK += $(LINK_HL2) -static-libgcc + +INCLUDE += -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ + -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(METAMOD) -I$(METAMOD)/sourcehook -I$(METAMOD)/sourcemm \ + -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ + +CFLAGS += -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp \ + -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -Wno-switch \ + -Wno-unused -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -m32 -Wno-uninitialized +CPPFLAGS += -Wno-non-virtual-dtor -fno-exceptions -fno-rtti -fno-threadsafe-statics + +################################################ +### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### +################################################ + +ifeq "$(DEBUG)" "true" + BIN_DIR = Debug.$(ENGINE) + CFLAGS += $(C_DEBUG_FLAGS) +else + BIN_DIR = Release.$(ENGINE) + CFLAGS += $(C_OPT_FLAGS) +endif + +GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) +ifeq "$(GCC_VERSION)" "4" + CPPFLAGS += $(CPP_GCC4_FLAGS) +endif + +BINARY = $(PROJECT).ext.so + +OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) + +$(BIN_DIR)/%.o: %.cpp + $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< + +all: + mkdir -p $(BIN_DIR)/sdk + ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so + ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so + $(MAKE) -f Makefile extension + +extension: $(OBJ_LINUX) + $(CPP) $(INCLUDE) $(OBJ_LINUX) $(LINK) -m32 -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) + +debug: + $(MAKE) -f Makefile all DEBUG=true + +default: all + +clean: + rm -rf $(BIN_DIR)/*.o + rm -rf $(BIN_DIR)/sdk/*.o + rm -rf $(BIN_DIR)/$(BINARY) diff --git a/extensions/tf2/Makefile.ep1 b/extensions/tf2/Makefile.ep1 deleted file mode 100644 index ab43177b..00000000 --- a/extensions/tf2/Makefile.ep1 +++ /dev/null @@ -1,88 +0,0 @@ -#(C)2004-2008 Metamod:Source Development Team -# Makefile written by David "BAILOPAN" Anderson - -SMSDK = ../smsdk -SRCDS = ~/srcds_l/steaminstall -SOURCEMM = ../sourcemm -HL2SDK = ../hl2sdk - -##################################### -### EDIT BELOW FOR OTHER PROJECTS ### -##################################### - -PROJECT = game.tf2 - -#Uncomment for SourceMM-enabled extensions -LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so - -OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp - -############################################## -### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### -############################################## - -C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing -C_DEBUG_FLAGS = -g -ggdb3 -CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden -CPP = gcc-4.1 - -HL2PUB = $(HL2SDK)/public -HL2LIB = $(HL2SDK)/linux_sdk - -LINK = $(LINK_HL2) -static-libgcc - -INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ - -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SOURCEMM) -I$(SOURCEMM)/sourcehook -I$(SOURCEMM)/sourcemm \ - -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ - -CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \ - -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp \ - -Wall -Werror -fPIC -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti - -################################################ -### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### -################################################ - -ifeq "$(DEBUG)" "true" - BIN_DIR = Debug - CFLAGS += $(C_DEBUG_FLAGS) -else - BIN_DIR = Release - CFLAGS += $(C_OPT_FLAGS) -endif - - -GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) -ifeq "$(GCC_VERSION)" "4" - CPPFLAGS += $(CPP_GCC4_FLAGS) -endif - -BINARY = $(PROJECT).ext.so - -OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) - -$(BIN_DIR)/%.o: %.cpp - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< - -all: - mkdir -p $(BIN_DIR)/sdk - ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so - ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so - $(MAKE) -f Makefile.ep1 extension - -extension: $(OBJ_LINUX) - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) - -debug: - $(MAKE) -f Makefile.ep1 all DEBUG=true - -default: all - -clean: - rm -rf Release/*.o - rm -rf Release/sdk/*.o - rm -rf Release/$(BINARY) - rm -rf Debug/*.o - rm -rf Debug/sdk/*.o - rm -rf Debug/$(BINARY) diff --git a/extensions/tf2/Makefile.ep2 b/extensions/tf2/Makefile.ep2 deleted file mode 100644 index 7146c611..00000000 --- a/extensions/tf2/Makefile.ep2 +++ /dev/null @@ -1,88 +0,0 @@ -#(C)2004-2008 Metamod:Source Development Team -# Makefile written by David "BAILOPAN" Anderson - -SMSDK = ../smsdk -SRCDS = ~/srcds_l/steaminstall -SOURCEMM = ../sourcemm -HL2SDK = ../hl2sdk-ob - -##################################### -### EDIT BELOW FOR OTHER PROJECTS ### -##################################### - -PROJECT = game.tf2 - -#Uncomment for SourceMM-enabled extensions -LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so - -OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp - -############################################## -### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### -############################################## - -C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing -C_DEBUG_FLAGS = -g -ggdb3 -CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden -CPP = gcc-4.1 - -HL2PUB = $(HL2SDK)/public -HL2LIB = $(HL2SDK)/linux_sdk - -LINK = $(LINK_HL2) -static-libgcc - -INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ - -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SOURCEMM) -I$(SOURCEMM)/sourcehook -I$(SOURCEMM)/sourcemm \ - -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ - -CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \ - -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp \ - -Wall -Werror -fPIC -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -DORANGEBOX_BUILD -CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti - -################################################ -### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### -################################################ - -ifeq "$(DEBUG)" "true" - BIN_DIR = Debug - CFLAGS += $(C_DEBUG_FLAGS) -else - BIN_DIR = Release - CFLAGS += $(C_OPT_FLAGS) -endif - - -GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) -ifeq "$(GCC_VERSION)" "4" - CPPFLAGS += $(CPP_GCC4_FLAGS) -endif - -BINARY = $(PROJECT).ext.so - -OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) - -$(BIN_DIR)/%.o: %.cpp - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< - -all: - mkdir -p $(BIN_DIR)/sdk - ln -sf $(SRCDS)/orangebox/bin/vstdlib_i486.so vstdlib_i486.so - ln -sf $(SRCDS)/orangebox/bin/tier0_i486.so tier0_i486.so - $(MAKE) -f Makefile.ep2 extension - -extension: $(OBJ_LINUX) - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) - -debug: - $(MAKE) -f Makefile.ep2 all DEBUG=true - -default: all - -clean: - rm -rf Release/*.o - rm -rf Release/sdk/*.o - rm -rf Release/$(BINARY) - rm -rf Debug/*.o - rm -rf Debug/sdk/*.o - rm -rf Debug/$(BINARY) diff --git a/extensions/tf2/Makefile.orig b/extensions/tf2/Makefile.orig deleted file mode 100644 index fcb92145..00000000 --- a/extensions/tf2/Makefile.orig +++ /dev/null @@ -1,88 +0,0 @@ -#(C)2004-2008 Metamod:Source Development Team -# Makefile written by David "BAILOPAN" Anderson - -SMSDK = ../smsdk -SRCDS = ~/srcds_l/steaminstall -SOURCEMM = ../sourcemm -HL2SDK = ../hl2sdk - -##################################### -### EDIT BELOW FOR OTHER PROJECTS ### -##################################### - -PROJECT = game.tf2 - -#Uncomment for SourceMM-enabled extensions -LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so - -OBJECTS = sdk/smsdk_ext.cpp extension.cpp natives.cpp RegNatives.cpp - -############################################## -### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ### -############################################## - -C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing -C_DEBUG_FLAGS = -g -ggdb3 -CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden -CPP = gcc-4.1 - -HL2PUB = $(HL2SDK)/public -HL2LIB = $(HL2SDK)/linux_sdk - -LINK = $(LINK_HL2) -static-libgcc - -INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \ - -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SOURCEMM) -I$(SOURCEMM)/sourcehook -I$(SOURCEMM)/sourcemm \ - -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \ - -CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \ - -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp \ - -Wall -Werror -fPIC -mfpmath=sse -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H -CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti - -################################################ -### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ### -################################################ - -ifeq "$(DEBUG)" "true" - BIN_DIR = Debug - CFLAGS += $(C_DEBUG_FLAGS) -else - BIN_DIR = Release - CFLAGS += $(C_OPT_FLAGS) -endif - - -GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1) -ifeq "$(GCC_VERSION)" "4" - CPPFLAGS += $(CPP_GCC4_FLAGS) -endif - -BINARY = $(PROJECT).ext.so - -OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o) - -$(BIN_DIR)/%.o: %.cpp - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $< - -all: - mkdir -p $(BIN_DIR)/sdk - ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so - ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so - $(MAKE) -f Makefile.orig extension - -extension: $(OBJ_LINUX) - $(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY) - -debug: - $(MAKE) -f Makefile.orig all DEBUG=true - -default: all - -clean: - rm -rf Release/*.o - rm -rf Release/sdk/*.o - rm -rf Release/$(BINARY) - rm -rf Debug/*.o - rm -rf Debug/sdk/*.o - rm -rf Debug/$(BINARY) diff --git a/extensions/tf2/RegNatives.cpp b/extensions/tf2/RegNatives.cpp index e663a186..03b1cce6 100644 --- a/extensions/tf2/RegNatives.cpp +++ b/extensions/tf2/RegNatives.cpp @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Counter-Strike:Source Extension + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * @@ -47,4 +47,6 @@ void RegNatives::UnregisterAll() { (*iter)->Destroy(); } + + m_List.clear(); } diff --git a/extensions/tf2/RegNatives.h b/extensions/tf2/RegNatives.h index 9ffe0669..b355dbc3 100644 --- a/extensions/tf2/RegNatives.h +++ b/extensions/tf2/RegNatives.h @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Counter-Strike:Source Extension + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * diff --git a/extensions/tf2/extension.cpp b/extensions/tf2/extension.cpp index c739a8f2..d4c09b13 100644 --- a/extensions/tf2/extension.cpp +++ b/extensions/tf2/extension.cpp @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Counter-Strike:Source Extension + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * @@ -30,8 +30,10 @@ */ #include "extension.h" +#include "util.h" #include "RegNatives.h" #include "iplayerinfo.h" +#include "sm_trie_tpl.h" /** * @file extension.cpp @@ -46,12 +48,35 @@ IBinTools *g_pBinTools = NULL; SMEXT_LINK(&g_TF2Tools); -SendProp *playerSharedOffset; +CGlobalVars *gpGlobals = NULL; + +sm_sendprop_info_t *playerSharedOffset; extern sp_nativeinfo_t g_TFNatives[]; +int g_resourceEntity; + +SH_DECL_HOOK3_void(IServerGameDLL, ServerActivate, SH_NOATTRIB, 0, edict_t *, int , int); + bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late) { + ServerClass *sc = UTIL_FindServerClass("CTFPlayer"); + if (sc == NULL) + { + snprintf(error, maxlength, "Could not find CTFPlayer server class"); + + return false; + } + + playerSharedOffset = new sm_sendprop_info_t; + + if (!UTIL_FindDataTable(sc->m_pTable, "DT_TFPlayerShared", playerSharedOffset, 0)) + { + snprintf(error, maxlength, "Could not find DT_TFPlayerShared data table"); + + return false; + } + sharesys->AddDependency(myself, "bintools.ext", true, true); char conf_error[255]; @@ -67,8 +92,6 @@ bool TF2Tools::SDK_OnLoad(char *error, size_t maxlength, bool late) sharesys->AddNatives(myself, g_TFNatives); sharesys->RegisterLibrary(myself, "tf2"); - playerSharedOffset = gamehelpers->FindInSendTable("CTFPlayer", "DT_TFPlayerShared"); - playerhelpers->RegisterCommandTargetProcessor(this); return true; @@ -78,13 +101,20 @@ bool TF2Tools::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool { GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER); + gpGlobals = ismm->GetCGlobals(); + + SH_ADD_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true); + return true; } void TF2Tools::SDK_OnUnload() { + SH_REMOVE_HOOK(IServerGameDLL, ServerActivate, gamedll, SH_STATIC(OnServerActivate), true); + g_RegNatives.UnregisterAll(); gameconfs->CloseGameConfigFile(g_pGameConf); + playerhelpers->UnregisterCommandTargetProcessor(this); } void TF2Tools::SDK_OnAllLoaded() @@ -114,24 +144,12 @@ void TF2Tools::NotifyInterfaceDrop(SMInterface *pInterface) g_RegNatives.UnregisterAll(); } -size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax) { - va_list ap; - va_start(ap, fmt); - size_t len = vsnprintf(buffer, maxlength, fmt, ap); - va_end(ap); - - if (len >= maxlength) - { - buffer[maxlength - 1] = '\0'; - return (maxlength - 1); - } - else - { - return len; - } + g_resourceEntity = FindResourceEntity(); } + bool TF2Tools::ProcessCommandTarget(cmd_target_info_t *info) { int max_clients; @@ -227,3 +245,83 @@ bool TF2Tools::ProcessCommandTarget(cmd_target_info_t *info) return true; } +int FindResourceEntity() +{ + return FindEntityByNetClass(-1, "CTFPlayerResource"); +} + + +int FindEntityByNetClass(int start, const char *classname) +{ + edict_t *current; + + for (int i = ((start != -1) ? start : 0); i < gpGlobals->maxEntities; i++) + { + current = engine->PEntityOfEntIndex(i); + if (current == NULL) + { + continue; + } + + IServerNetworkable *network = current->GetNetworkable(); + + if (network == NULL) + { + continue; + } + + ServerClass *sClass = network->GetServerClass(); + const char *name = sClass->GetName(); + + + if (strcmp(name, classname) == 0) + { + return i; + } + } + + return -1; +} + +TFClassType ClassnameToType(const char *classname) +{ + static KTrie trie; + static bool filled = false; + + if (!filled) + { + trie.insert("scout", TFClass_Scout); + trie.insert("scout", TFClass_Scout); + trie.insert("sniper", TFClass_Sniper); + trie.insert("soldier", TFClass_Soldier); + trie.insert("demoman", TFClass_DemoMan); + trie.insert("demo", TFClass_DemoMan); + trie.insert("medic", TFClass_Medic); + trie.insert("heavy", TFClass_Heavy); + trie.insert("hwg", TFClass_Heavy); + trie.insert("pyro", TFClass_Pyro); + trie.insert("spy", TFClass_Spy); + trie.insert("engineer", TFClass_Engineer); + trie.insert("engy", TFClass_Engineer); + + filled = true; + } + + TFClassType *value; + + if (!(value = trie.retrieve(classname))) + { + return TFClass_Unknown; + } + + return *value; +} + + + +/** + * A picture of a blue crab given to me as a gift and stored here for safe keeping + * + * http://www.democracycellproject.net/blog/archives/Clown%20car.jpg + */ + diff --git a/extensions/tf2/extension.h b/extensions/tf2/extension.h index 6435cf38..4a2b7adc 100644 --- a/extensions/tf2/extension.h +++ b/extensions/tf2/extension.h @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Counter-Strike:Source Extension + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * @@ -123,8 +123,32 @@ public: #endif }; +enum TFClassType +{ + TFClass_Unknown = 0, + TFClass_Scout, + TFClass_Sniper, + TFClass_Soldier, + TFClass_DemoMan, + TFClass_Medic, + TFClass_Heavy, + TFClass_Pyro, + TFClass_Spy, + TFClass_Engineer +}; + +TFClassType ClassnameToType(const char *classname); + extern IBinTools *g_pBinTools; extern IGameConfig *g_pGameConf; -extern SendProp *playerSharedOffset; +extern sm_sendprop_info_t *playerSharedOffset; + +void OnServerActivate(edict_t *pEdictList, int edictCount, int clientMax); + +int FindResourceEntity(); +int FindEntityByNetClass(int start, const char *classname); + +extern int g_resourceEntity; + #endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_ diff --git a/extensions/tf2/msvc8/tf2.sln b/extensions/tf2/msvc8/tf2.sln index 02dbd658..5aa5277e 100644 --- a/extensions/tf2/msvc8/tf2.sln +++ b/extensions/tf2/msvc8/tf2.sln @@ -5,12 +5,24 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tf2", "tf2.vcproj", "{B3E79 EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug - Episode1|Win32 = Debug - Episode1|Win32 + Debug - Old Metamod|Win32 = Debug - Old Metamod|Win32 Debug - Orange Box|Win32 = Debug - Orange Box|Win32 + Release - Episode 1|Win32 = Release - Episode 1|Win32 + Release - Old Metamod|Win32 = Release - Old Metamod|Win32 Release - Orange Box|Win32 = Release - Orange Box|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Episode1|Win32.ActiveCfg = Debug - Episode1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Episode1|Win32.Build.0 = Debug - Episode1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Old Metamod|Win32.ActiveCfg = Debug - Old Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Old Metamod|Win32.Build.0 = Debug - Old Metamod|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Orange Box|Win32.ActiveCfg = Debug - Orange Box|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug - Orange Box|Win32.Build.0 = Debug - Orange Box|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Episode 1|Win32.ActiveCfg = Release - Episode 1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Episode 1|Win32.Build.0 = Release - Episode 1|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Old Metamod|Win32.ActiveCfg = Release - Old Metamod|Win32 + {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Old Metamod|Win32.Build.0 = Release - Old Metamod|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Orange Box|Win32.ActiveCfg = Release - Orange Box|Win32 {B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release - Orange Box|Win32.Build.0 = Release - Orange Box|Win32 EndGlobalSection diff --git a/extensions/tf2/msvc8/tf2.vcproj b/extensions/tf2/msvc8/tf2.vcproj index 966841f6..320051c1 100644 --- a/extensions/tf2/msvc8/tf2.vcproj +++ b/extensions/tf2/msvc8/tf2.vcproj @@ -15,6 +15,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - GetMemSig(name, &addr)) \ - { \ - return pContext->ThrowNativeError("Failed to locate function"); \ - } \ - code; \ - g_RegNatives.Register(pWrapper); -inline CBaseEntity *GetCBaseEntity(int num, bool onlyPlayers) -{ - edict_t *pEdict = engine->PEntityOfEntIndex(num); - if (!pEdict || pEdict->IsFree()) - { - return NULL; - } - - if (num > 0 && num < playerhelpers->GetMaxClients()) - { - IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(pEdict); - if (!pPlayer || !pPlayer->IsConnected()) - { - return NULL; - } - } - else if (onlyPlayers) - { - return NULL; - } - - IServerUnknown *pUnk; - if ((pUnk=pEdict->GetUnknown()) == NULL) - { - return NULL; - } - - return pUnk->GetBaseEntity(); -} - - -// native TF2_Burn(client) +// native TF2_Burn(client, target) cell_t TF2_Burn(IPluginContext *pContext, const cell_t *params) { static ICallWrapper *pWrapper = NULL; @@ -89,26 +52,32 @@ cell_t TF2_Burn(IPluginContext *pContext, const cell_t *params) } CBaseEntity *pEntity; - if (!(pEntity=GetCBaseEntity(params[1], true))) + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) { return pContext->ThrowNativeError("Client index %d is not valid", params[1]); } - void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->GetOffset()); + CBaseEntity *pTarget; + if (!(pTarget = UTIL_GetCBaseEntity(params[2], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[2]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); unsigned char vstk[sizeof(void *) + sizeof(CBaseEntity *)]; unsigned char *vptr = vstk; *(void **)vptr = obj; vptr += sizeof(void *); - *(CBaseEntity **)vptr = pEntity; + *(CBaseEntity **)vptr = pTarget; pWrapper->Execute(vstk, NULL); return 1; } -// native TF2_Invuln(client, bool:something, bool:anothersomething) +// native TF2_Invuln(client, bool:enabled) cell_t TF2_Invuln(IPluginContext *pContext, const cell_t *params) { static ICallWrapper *pWrapper = NULL; @@ -128,32 +97,162 @@ cell_t TF2_Invuln(IPluginContext *pContext, const cell_t *params) } CBaseEntity *pEntity; - if (!(pEntity=GetCBaseEntity(params[1], true))) + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) { return pContext->ThrowNativeError("Client index %d is not valid", params[1]); } - void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->GetOffset()); + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); unsigned char vstk[sizeof(void *) + 2*sizeof(bool)]; unsigned char *vptr = vstk; *(void **)vptr = obj; - vptr += sizeof(bool); + vptr += sizeof(void *); *(bool *)vptr = !!params[2]; vptr += sizeof(bool); - *(bool *)vptr = !!params[3]; + *(bool *)vptr = true; pWrapper->Execute(vstk, NULL); return 1; } +cell_t TF2_Disguise(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayerShared::Disguise(int, int) + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("Disguise", + PassInfo pass[2]; \ + pass[0].flags = PASSFLAG_BYVAL; \ + pass[0].size = sizeof(int); \ + pass[0].type = PassType_Basic; \ + pass[1].flags = PASSFLAG_BYVAL; \ + pass[1].size = sizeof(int); \ + pass[1].type = PassType_Basic; \ + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, pass, 2)) + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); + + unsigned char vstk[sizeof(void *) + 2*sizeof(int)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = obj; + vptr += sizeof(void *); + *(int *)vptr = params[2]; + vptr += sizeof(int); + *(int *)vptr = params[3]; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_RemoveDisguise(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayerShared::RemoveDisguise() + if (!pWrapper) + { + REGISTER_NATIVE_ADDR("RemoveDisguise", + pWrapper = g_pBinTools->CreateCall(addr, CallConv_ThisCall, NULL, NULL, 0)) + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + void *obj = (void *)((uint8_t *)pEntity + playerSharedOffset->actual_offset); + + unsigned char vstk[sizeof(void *)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = obj; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_Respawn(IPluginContext *pContext, const cell_t *params) +{ + static ICallWrapper *pWrapper = NULL; + + //CTFPlayer::ForceRespawn() + + if (!pWrapper) + { + int offset; + + if (!g_pGameConf->GetOffset("ForceRespawn", &offset)) + { + return pContext->ThrowNativeError("Failed to locate function"); + } + + pWrapper = g_pBinTools->CreateVCall(offset, + 0, + 0, + NULL, + NULL, + 0); + + g_RegNatives.Register(pWrapper); + } + + CBaseEntity *pEntity; + if (!(pEntity = UTIL_GetCBaseEntity(params[1], true))) + { + return pContext->ThrowNativeError("Client index %d is not valid", params[1]); + } + + unsigned char vstk[sizeof(void *)]; + unsigned char *vptr = vstk; + + + *(void **)vptr = (void *)pEntity; + + pWrapper->Execute(vstk, NULL); + + return 1; +} + +cell_t TF2_GetResourceEntity(IPluginContext *pContext, const cell_t *params) +{ + return g_resourceEntity; +} + +cell_t TF2_GetClass(IPluginContext *pContext, const cell_t *params) +{ + char *str; + pContext->LocalToString(params[1], &str); + + return (cell_t)ClassnameToType(str); +} sp_nativeinfo_t g_TFNatives[] = { - {"TF2_Burn", TF2_Burn}, - {"TF2_Invuln", TF2_Invuln}, + {"TF2_IgnitePlayer", TF2_Burn}, + {"TF2_SetPlayerInvuln", TF2_Invuln}, + {"TF2_RespawnPlayer", TF2_Respawn}, + {"TF2_DisguisePlayer", TF2_Disguise}, + {"TF2_RemovePlayerDisguise", TF2_RemoveDisguise}, + {"TF2_GetResourceEntity", TF2_GetResourceEntity}, + {"TF2_GetClass", TF2_GetClass}, {NULL, NULL} }; diff --git a/extensions/tf2/sdk/smsdk_config.h b/extensions/tf2/sdk/smsdk_config.h index b503ca4b..7356d772 100644 --- a/extensions/tf2/sdk/smsdk_config.h +++ b/extensions/tf2/sdk/smsdk_config.h @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Counter-Strike:Source Extension + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * diff --git a/extensions/tf2/sdk/smsdk_ext.cpp b/extensions/tf2/sdk/smsdk_ext.cpp index 37733333..cc9bee0e 100644 --- a/extensions/tf2/sdk/smsdk_ext.cpp +++ b/extensions/tf2/sdk/smsdk_ext.cpp @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Base Extension Code + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * diff --git a/extensions/tf2/sdk/smsdk_ext.h b/extensions/tf2/sdk/smsdk_ext.h index 3d5a229d..f2dae105 100644 --- a/extensions/tf2/sdk/smsdk_ext.h +++ b/extensions/tf2/sdk/smsdk_ext.h @@ -1,7 +1,7 @@ /** * vim: set ts=4 : * ============================================================================= - * SourceMod Base Extension Code + * SourceMod Team Fortress 2 Extension * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. * ============================================================================= * diff --git a/extensions/tf2/svn_version.h b/extensions/tf2/svn_version.h index 5d888fd0..8873263e 100644 --- a/extensions/tf2/svn_version.h +++ b/extensions/tf2/svn_version.h @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/tf2/svn_version.tpl b/extensions/tf2/svn_version.tpl index 08a4c47d..ad458193 100644 --- a/extensions/tf2/svn_version.tpl +++ b/extensions/tf2/svn_version.tpl @@ -2,7 +2,7 @@ * vim: set ts=4 : * ============================================================================= * SourceMod SDKTools Extension - * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. * ============================================================================= * * This program is free software; you can redistribute it and/or modify it under diff --git a/extensions/tf2/tf2-test.sp b/extensions/tf2/tf2-test.sp deleted file mode 100644 index b1239543..00000000 --- a/extensions/tf2/tf2-test.sp +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include "tf2.inc" - -public Plugin:myinfo = -{ - name = "TF2 Test", - author = "pRED*", - description = "Test of Tf2 functions", - version = "1.0", - url = "www.sourcemod.net" -} - -public OnPluginStart() -{ - RegConsoleCmd("sm_burnme", Command_Burn); - RegConsoleCmd("sm_invuln", Command_Invuln); -} - -public Action:Command_Burn(client, args) -{ - if (client == 0) - { - return Plugin_Continue; - } - - TF2_Burn(client); - - return Plugin_Continue; -} - -public Action:Command_Invuln(client, args) -{ - if (client == 0) - { - return Plugin_Continue; - } - - if (args < 2) - { - return Plugin_Continue; - } - - decl String:text[10]; - decl String:text2[10]; - GetCmdArg(1, text, sizeof(text)); - GetCmdArg(2, text2, sizeof(text2)); - - new bool:one = !!StringToInt(text); - new bool:two = !!StringToInt(text2); - - TF2_Invuln(client, one, two) - - return Plugin_Continue; -} - diff --git a/extensions/tf2/tf2.inc b/extensions/tf2/tf2.inc deleted file mode 100644 index c2c4c39a..00000000 --- a/extensions/tf2/tf2.inc +++ /dev/null @@ -1,24 +0,0 @@ -#if defined _tf2_included - #endinput -#endif -#define _tf2_included - - -native TF2_Invuln(client, bool:something, bool:anothersomething); - -native TF2_Burn(client); - -/** - * Do not edit below this line! - */ -public Extension:__ext_tf2 = -{ - name = "TF2 Tools", - file = "game.tf2.ext", - autoload = 0, -#if defined REQUIRE_EXTENSIONS - required = 1, -#else - required = 0, -#endif -}; diff --git a/extensions/tf2/util.cpp b/extensions/tf2/util.cpp new file mode 100644 index 00000000..931380a7 --- /dev/null +++ b/extensions/tf2/util.cpp @@ -0,0 +1,134 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * Copyright (C) 2004-2008 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: util.cpp 1558 2007-10-14 19:34:46Z faluco $ + */ + +#include "extension.h" +#include "util.h" + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + va_end(ap); + + if (len >= maxlength) + { + buffer[maxlength - 1] = '\0'; + return (maxlength - 1); + } + else + { + return len; + } +} + +bool UTIL_FindDataTable(SendTable *pTable, + const char *name, + sm_sendprop_info_t *info, + unsigned int offset) +{ + const char *pname; + int props = pTable->GetNumProps(); + SendProp *prop; + SendTable *table; + + for (int i=0; iGetProp(i); + + if ((table = prop->GetDataTable()) != NULL) + { + pname = table->GetName(); + if (pname && strcmp(name, pname) == 0) + { + info->prop = prop; + info->actual_offset = offset + info->prop->GetOffset(); + return true; + } + + if (UTIL_FindDataTable(table, + name, + info, + offset + prop->GetOffset()) + ) + { + return true; + } + } + } + + return false; +} + +ServerClass *UTIL_FindServerClass(const char *classname) +{ + ServerClass *sc = gamedll->GetAllServerClasses(); + while (sc) + { + if (strcmp(classname, sc->GetName()) == 0) + { + return sc; + } + sc = sc->m_pNext; + } + + return NULL; +} + +CBaseEntity *UTIL_GetCBaseEntity(int num, bool onlyPlayers) +{ + edict_t *pEdict = engine->PEntityOfEntIndex(num); + if (!pEdict || pEdict->IsFree()) + { + return NULL; + } + + if (num > 0 && num < playerhelpers->GetMaxClients()) + { + IGamePlayer *pPlayer = playerhelpers->GetGamePlayer(pEdict); + if (!pPlayer || !pPlayer->IsConnected()) + { + return NULL; + } + } + else if (onlyPlayers) + { + return NULL; + } + + IServerUnknown *pUnk; + if ((pUnk=pEdict->GetUnknown()) == NULL) + { + return NULL; + } + + return pUnk->GetBaseEntity(); +} diff --git a/extensions/tf2/util.h b/extensions/tf2/util.h new file mode 100644 index 00000000..26e1eb2a --- /dev/null +++ b/extensions/tf2/util.h @@ -0,0 +1,57 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod Team Fortress 2 Extension + * Copyright (C) 2004-2008 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: util.h 1558 2007-10-14 19:34:46Z faluco $ + */ + +#ifndef _INCLUDE_TF2TOOLS_UTIL_H_ +#define _INCLUDE_TF2TOOLS_UTIL_H_ + +#define REGISTER_NATIVE_ADDR(name, code) \ + void *addr; \ + if (!g_pGameConf->GetMemSig(name, &addr) || !addr) \ + { \ + return pContext->ThrowNativeError("Failed to locate function"); \ + } \ + code; \ + g_RegNatives.Register(pWrapper); + + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); + +bool UTIL_FindDataTable(SendTable *pTable, + const char *name, + sm_sendprop_info_t *info, + unsigned int offset); + +ServerClass *UTIL_FindServerClass(const char *classname); + +CBaseEntity *UTIL_GetCBaseEntity(int num, bool onlyPlayers); + + +#endif //_INCLUDE_TF2TOOLS_UTIL_H_ diff --git a/extensions/tf2/version.rc b/extensions/tf2/version.rc index 2abaa001..37d14dad 100644 --- a/extensions/tf2/version.rc +++ b/extensions/tf2/version.rc @@ -49,7 +49,7 @@ BEGIN VALUE "FileDescription", "SourceMod CS:S Extension" VALUE "FileVersion", SVN_FULL_VERSION VALUE "InternalName", "SourceMod CS:S Extension" - VALUE "LegalCopyright", "Copyright (c) 2004-2008, AlliedModders LLC" + VALUE "LegalCopyright", "Copyright (c) 2004-2007, AlliedModders LLC" VALUE "OriginalFilename", "game.cstrike.ext.dll" VALUE "ProductName", "SourceMod CS:S Extension" VALUE "ProductVersion", SVN_FULL_VERSION diff --git a/extensions/tf2/sm-tf2.games.txt b/gamedata/sm-tf2.games.txt similarity index 51% rename from extensions/tf2/sm-tf2.games.txt rename to gamedata/sm-tf2.games.txt index 3adc88b2..c7bf3740 100644 --- a/extensions/tf2/sm-tf2.games.txt +++ b/gamedata/sm-tf2.games.txt @@ -16,6 +16,27 @@ "windows" "\x8A\x44\x24\x04\x83\xEC\x20\x56\x8B\xF1\x8B\x4E\x08\x57\x8D\x7E\x08\xC1\xE9\x05\x80\xE1\x01\x3A\xC8\x75\x32\x84\xC0" "linux" "@_ZN15CTFPlayerShared15SetInvulnerableEbb" } + "RemoveDisguise" + { + "library" "server" + "windows" "\x51\x56\x8B\xF1\x8B\x46\x08\x57\x8D\x7E\x08\x8D\x4C\x24\x08\x83\xE0\xF7" + "linux" "@_ZN15CTFPlayerShared14RemoveDisguiseEv" + } + "Disguise" + { + "library" "server" + "windows" "\x56\x8B\xF1\x8B\x4E\x7C\xE8" + "linux" "@_ZN15CTFPlayerShared8DisguiseEii" + } + + } + "Offsets" + { + "ForceRespawn" + { + "windows" "279" + "linux" "280" + } } } } \ No newline at end of file diff --git a/plugins/include/tf2.inc b/plugins/include/tf2.inc new file mode 100644 index 00000000..3019a2d8 --- /dev/null +++ b/plugins/include/tf2.inc @@ -0,0 +1,107 @@ +#if defined _tf2_included + #endinput +#endif +#define _tf2_included + +enum TFClassType +{ + TFClass_Unknown = 0, + TFClass_Scout, + TFClass_Sniper, + TFClass_Soldier, + TFClass_DemoMan, + TFClass_Medic, + TFClass_Heavy, + TFClass_Pyro, + TFClass_Spy, + TFClass_Engineer +} + +enum TFTeam +{ + TFTeam_Unassigned = 0, + TFTeam_Spectator = 1, + TFTeam_Red = 2, + TFTeam_Blue = 3 +} + +/** + * Set's a Clients invulnrability status (ubercharge effect) + * + * @param client Player's index. + * @param enabled Enable/Disable invulnrability. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_SetPlayerInvuln(client, bool:enabled); + + +/** + * Sets a client on fire for 10 seconds. + * + * @param client Player's index. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_IgnitePlayer(client, target); + +/** + * Respawns a client + * + * @param client Player's index. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_RespawnPlayer(client); + +/** + * Disguises a client to the given model and team. Only has an effect on spies. + * + * Note: This only starts the disguise process and a delay occurs before the spy is fully disguised + * + * @param client Player's index. + * @param team Team to disguise the player as (only TFTeam_Red and TFTeam_Blue have an effect) + * @param class TFClassType class to disguise the player as + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_DisguisePlayer(client, TFTeam:team, TFClassType:class); + +/** + * Removes the current disguise from a client. Only has an effect on spies. + * + * @param client Player's index. + * @noreturn + * @error Invalid client index, client not in game, or no mod support. + */ +native TF2_RemovePlayerDisguise(client); + +/** + * Retrieves the entity index of the CPlayerResource entity + * + * @return The current resource entity index. + */ +native TF2_GetResourceEntity(); + +/** + * Finds the TFClassType for a given class name. + * + * @param classname A classname string such as "sniper" or "demoman" + * @return A TFClassType constant. + */ +native TFClassType:TF2_GetClass(const String:classname[]); + +/** + * Do not edit below this line! + */ +public Extension:__ext_tf2 = +{ + name = "TF2 Tools", + file = "game.tf2.ext", + autoload = 1, +#if defined REQUIRE_EXTENSIONS + required = 1, +#else + required = 0, +#endif +}; diff --git a/plugins/include/tf2_stocks.inc b/plugins/include/tf2_stocks.inc new file mode 100644 index 00000000..1386434f --- /dev/null +++ b/plugins/include/tf2_stocks.inc @@ -0,0 +1,301 @@ +#if defined _tf2_stocks_included + #endinput +#endif +#define _tf2_stocks_included + +#include +#include + +enum TFResourceType +{ + TFResource_Ping, + TFResource_Score, + TFResource_Deaths, + TFResource_TotalScore, + TFResource_Captures, + TFResource_Defenses, + TFResource_Dominations, + TFResource_Revenge, + TFResource_BuildingsDestroyed, + TFResource_Headshots, + TFResource_Backstabs, + TFResource_HealPoints, + TFResource_Invulns, + TFResource_Teleports, + TFResource_ResupplyPoints, + TFResource_KillAssists, + TFResource_MaxHealth, + TFResource_PlayerClass +}; + +static const String:TFResourceNames[TFResourceType][] = +{ + "m_iPing", + "m_iScore", + "m_iDeaths", + "m_iTotalScore", + "m_iCaptures", + "m_iDefenses", + "m_iDominations", + "m_iRevenge", + "m_iBuildingsDestroyed", + "m_iHeadshots", + "m_iBackstabs", + "m_iHealPoints", + "m_iInvulns", + "m_iTeleports", + "m_iResupplyPoints", + "m_iKillAssists", + "m_iMaxHealth", + "m_iPlayerClass" +}; + +/** + * Get's a Clients current class. + * + * @param client Player's index. + * @param class TFClassType to change to. + * @noreturn + * @error Invalid client index. + */ +stock TFClassType:TF2_GetPlayerClass(client) +{ + return TFClassType:GetEntProp(client, Prop_Send, "m_iClass"); +} + +/** + * Set's a Clients class. + * + * @param client Player's index. + * @param class TFClassType class symbol. + * @param weapons If true, changes the players weapon set to that of the new class. + * @noreturn + * @error Invalid client index. + */ +stock TF2_SetPlayerClass(client, TFClassType:class, bool:weapons=true) +{ + SetEntProp(client, Prop_Send, "m_iClass", _:class); + SetEntProp(client, Prop_Send, "m_iDesiredPlayerClass", _:class); + TF2_SetPlayerResourceData(client, TFResource_PlayerClass, class); + + if (weapons) + { + TF2_RemoveAllWeapons(client); + TF2_EquipPlayerClassWeapons(client, class) + } +} + +/** + * Retrieves client data from the resource entity + * + * @param client Player's index. + * @param type ResourceType constant + * @return Value or -1 on failure. + * @error Invalid client index, client not in game or failed to find resource entity. + */ +stock TF2_GetPlayerResourceData(client, TFResourceType:type) +{ + if (!IsClientConnected(client)) + { + return -1; + } + + static offset; + static set = false; + + if (!set) + { + offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); + set = true; + } + + if (offset < 1) + { + return -1; + } + + new entity = TF2_GetResourceEntity(); + + if (entity == -1) + { + return -1; + } + + return GetEntData(entity, offset + (client*4)); +} + +/** + * Sets client data in the resource entity + * + * @param client Player's index. + * @param type ResourceType constant + * @param value Value to set. + * @return Value or -1 on failure. + * @error Invalid client index, client not in game or failed to find resource entity. + */ +stock bool:TF2_SetPlayerResourceData(client, TFResourceType:type, any:value) +{ + if (!IsClientConnected(client)) + { + return false; + } + + static offset; + static set = false; + + if (!set) + { + offset = FindSendPropInfo("CTFPlayerResource", TFResourceNames[type]); + set = true; + } + + if (offset < 1) + { + return false; + } + + new entity = TF2_GetResourceEntity(); + + if (entity == -1) + { + return false; + } + + SetEntData(entity, offset + (client*4), value) + + return true; +} + +/** + * Removes all weapons from a client's weapon slot + * + * @param client Player's index. + * @param slot Slot index (0-5) + * @noreturn + * @error Invalid client, invalid slot or lack of mod support + */ +stock TF2_RemoveWeaponSlot(client, slot) +{ + new weaponIndex; + while ((weaponIndex = GetPlayerWeaponSlot(client, slot)) != -1) + { + RemovePlayerItem(client, weaponIndex); + RemoveEdict(weaponIndex); + } +} + +/** + * Removes all weapons from a client + * + * @param client Player's index. + * @noreturn + */ +stock TF2_RemoveAllWeapons(client) +{ + for (new i = 0; i <= 5; i++) + { + TF2_RemoveWeaponSlot(client, i); + } +} + +/** + * Gives a named weapon to a client + * + * @param client Player's index. + * @param weapon Weapon name + * @return False if weapon could not be created, true on success + * @error Invalid client index or lack of mod support + */ +stock bool:TF2_GivePlayerWeapon(client, const String:weapon[]) +{ + new weaponIndex = GivePlayerItem(client, weapon); + if (weaponIndex == -1) + { + return false; + } + + EquipPlayerWeapon(client, weaponIndex); + + return true; +} + +/** + * Equips a client with a class's weapons. This does not remove existing weapons. + * + * Note: Some class specific items such tf_weapon_pda_engineer_build are only given + * if the client is the correct class. + * + * @param client Player's index. + * @param class TFClasssType class symbol. + * @noreturn + */ +stock TF2_EquipPlayerClassWeapons(client, TFClassType:class) +{ + switch(class) + { + case TFClass_Scout: + { + TF2_GivePlayerWeapon(client, "tf_weapon_scattergun"); + TF2_GivePlayerWeapon(client, "tf_weapon_pistol_scout"); + TF2_GivePlayerWeapon(client, "tf_weapon_bat"); + } + case TFClass_Sniper: + { + TF2_GivePlayerWeapon(client, "tf_weapon_sniperrifle"); + TF2_GivePlayerWeapon(client, "tf_weapon_smg"); + TF2_GivePlayerWeapon(client, "tf_weapon_club"); + } + case TFClass_Soldier: + { + TF2_GivePlayerWeapon(client, "tf_weapon_rocketlauncher"); + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_soldier"); + TF2_GivePlayerWeapon(client, "tf_weapon_shovel"); + } + case TFClass_DemoMan: + { + TF2_GivePlayerWeapon(client, "tf_weapon_pipebomblauncher"); + TF2_GivePlayerWeapon(client, "tf_weapon_grenadelauncher"); + TF2_GivePlayerWeapon(client, "tf_weapon_bottle"); + } + case TFClass_Medic: + { + TF2_GivePlayerWeapon(client, "tf_weapon_syringegun_medic"); + TF2_GivePlayerWeapon(client, "tf_weapon_medigun"); + TF2_GivePlayerWeapon(client, "tf_weapon_bonesaw"); + } + case TFClass_Heavy: + { + TF2_GivePlayerWeapon(client, "tf_weapon_minigun"); + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_hwg"); + TF2_GivePlayerWeapon(client, "tf_weapon_fists"); + } + case TFClass_Pyro: + { + TF2_GivePlayerWeapon(client, "tf_weapon_flamethrower"); + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_pyro"); + TF2_GivePlayerWeapon(client, "tf_weapon_fireaxe"); + } + case TFClass_Spy: + { + TF2_GivePlayerWeapon(client, "tf_weapon_revolver"); + TF2_GivePlayerWeapon(client, "tf_weapon_knife"); + + if (TF2_GetPlayerClass(client) != TFClass_Spy) + return; + + TF2_GivePlayerWeapon(client, "tf_weapon_pda_spy"); + } + case TFClass_Engineer: + { + TF2_GivePlayerWeapon(client, "tf_weapon_shotgun_primary"); + TF2_GivePlayerWeapon(client, "tf_weapon_pistol"); + TF2_GivePlayerWeapon(client, "tf_weapon_wrench"); + + if (TF2_GetPlayerClass(client) != TFClass_Engineer) + return; + + TF2_GivePlayerWeapon(client, "tf_weapon_pda_engineer_build"); + TF2_GivePlayerWeapon(client, "tf_weapon_pda_engineer_destroy"); + } + } +} \ No newline at end of file diff --git a/plugins/testsuite/tf2-test.sp b/plugins/testsuite/tf2-test.sp new file mode 100644 index 00000000..6623d33a --- /dev/null +++ b/plugins/testsuite/tf2-test.sp @@ -0,0 +1,167 @@ +#include +#include +#include +#include + +public Plugin:myinfo = +{ + name = "TF2 Test", + author = "pRED*", + description = "Test of Tf2 functions", + version = "1.0", + url = "www.sourcemod.net" +} + +public OnPluginStart() +{ + RegConsoleCmd("sm_burnme", Command_Burn); + RegConsoleCmd("sm_invuln", Command_Invuln); + RegConsoleCmd("sm_respawn", Command_Respawn); + RegConsoleCmd("sm_disguise", Command_Disguise); + RegConsoleCmd("sm_remdisguise", Command_RemDisguise); + RegConsoleCmd("sm_class", Command_Class); + RegConsoleCmd("sm_remove", Command_Remove); + RegConsoleCmd("sm_changeclass", Command_ChangeClass); +} + +public Action:Command_Class(client, args) +{ + TF2_RemoveAllWeapons(client); + + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new one = StringToInt(text); + + TF2_EquipPlayerClassWeapons(client, TFClassType:one); + + PrintToChat(client, "Test: sniper's classnum is %i (should be %i)", TF2_GetClass("sniper"), TFClass_Sniper); + + return Plugin_Handled; +} + +public Action:Command_Remove(client, args) +{ + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new one = StringToInt(text); + + TF2_RemoveWeaponSlot(client, one); + + PrintToChat(client, "Test: heavy's classnum is %i (should be %i)", TF2_GetClass("heavy"), TFClass_Heavy); + + new doms = TF2_GetPlayerResourceData(client, TFResource_Dominations); + PrintToChat(client, "Dominations read test: %i", doms); + + TF2_SetPlayerResourceData(client, TFResource_Dominations, doms + 10); + doms = TF2_GetPlayerResourceData(client, TFResource_Dominations); + PrintToChat(client, "Dominations write test: %i", doms); + + /* Note: This didn't appear to change my dominations value when I pressed tab. */ + + return Plugin_Handled; +} + +public Action:Command_ChangeClass(client, args) +{ + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new one = StringToInt(text); + + PrintToChat(client, "Current class is :%i", TF2_GetPlayerClass(client)); + + TF2_SetPlayerClass(client, TFClassType:one); + + PrintToChat(client, "New class is :%i", TF2_GetPlayerClass(client)); + + return Plugin_Handled; +} + + + +public Action:Command_Burn(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + TF2_IgnitePlayer(client, client); + + return Plugin_Handled; +} + +public Action:Command_Invuln(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + if (args < 1) + { + return Plugin_Handled; + } + + decl String:text[10]; + GetCmdArg(1, text, sizeof(text)); + + new bool:one = !!StringToInt(text); + + TF2_SetPlayerInvuln(client, one) + + return Plugin_Handled; +} + +public Action:Command_Disguise(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + if (args < 2) + { + return Plugin_Handled; + } + + decl String:text[10]; + decl String:text2[10]; + GetCmdArg(1, text, sizeof(text)); + GetCmdArg(2, text2, sizeof(text2)); + + new one = StringToInt(text); + new two = StringToInt(text2); + + TF2_DisguisePlayer(client, TFTeam:one, TFClassType:two); + + return Plugin_Handled; +} + +public Action:Command_RemDisguise(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + TF2_RemovePlayerDisguise(client); + + return Plugin_Handled; +} + + +public Action:Command_Respawn(client, args) +{ + if (client == 0) + { + return Plugin_Handled; + } + + + TF2_RespawnPlayer(client); + + return Plugin_Handled; +}