├── .gitattributes ├── .gitignore ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── plugin ├── CMakeLists.txt ├── LinGe_VScripts.cpp ├── LinGe_VScripts.h ├── LinGe_VScripts.vdf ├── licenses │ ├── GPLv2.txt │ ├── GPLv3.txt │ └── LICENSE.txt └── sdkapi │ ├── MemoryUtils │ ├── MemoryUtils.cpp │ ├── MemoryUtils.h │ ├── sm_platform.h │ └── sm_symtable.h │ ├── sdkapi.cpp │ ├── sdkapi.h │ └── signature.h ├── release ├── Base-addonimage.jpg ├── Base-addoninfo.txt ├── HUD-addonimage.jpg ├── HUD-addoninfo.txt ├── Hint-addonimage.jpg ├── Hint-addoninfo.txt ├── LinGe_VScripts-addonimage.jpg ├── LinGe_VScripts-addoninfo.txt ├── MoreSI-addonimage.jpg ├── MoreSI-addoninfo.txt ├── RewardHP-addonimage.jpg ├── RewardHP-addoninfo.txt ├── plugin.bat ├── vpk.bat ├── vpk │ ├── LinGe VScripts 整合.vpk │ ├── 击杀回血 RewardHP.vpk │ ├── 基础库 Base.vpk │ ├── 多特控制 MoreSI.vpk │ ├── 排行榜、伤害统计 HUD.vpk │ ├── 标记物资、队友倒地被控提示 Hint.vpk │ └── 自杀指令 zs.vpk ├── zs-addonimage.jpg └── zs-addoninfo.txt └── vscripts ├── LinGe ├── Base.nut ├── HUD.nut ├── Hint.nut ├── MoreSI.nut ├── RewardHP.nut ├── VSLib.nut ├── VSLib │ ├── easylogic.nut │ ├── entity.nut │ ├── fileio.nut │ ├── hud.nut │ ├── player.nut │ ├── randomitemspawner.nut │ ├── responserules.nut │ ├── timer.nut │ └── utils.nut └── zs.nut ├── director_base_addon.nut └── scriptedmode_addon.nut /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !.vscode 2 | /release/* 3 | !/release/plugin.bat 4 | !/release/vpk.bat 5 | !/release/*-addoninfo.txt 6 | !/release/*-addonimage.jpg 7 | 8 | !/release/vpk/ 9 | /release/vpk/* 10 | !/release/vpk/*.vpk 11 | /release/vpk/base.vpk 12 | /release/vpk/hint.vpk 13 | /release/vpk/hud.vpk 14 | /release/vpk/linge_vscripts.vpk 15 | /release/vpk/moresi.vpk 16 | /release/vpk/rewardhp.vpk 17 | /release/vpk/zs.vpk 18 | 19 | /plugin/*-build 20 | 21 | /note.txt -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.sourceDirectory": "${workspaceFolder}/plugin", 3 | "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools", 4 | "cmake.buildDirectory": "${workspaceFolder}/plugin/${env.USER}-build" 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 LinGe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LinGe VScripts 2 | 3 | 求生之路2使用脚本实现自定义特感数量与刷新间隔、伤害与击杀统计、友伤提示、HUD(排行榜、时间、服务器名等)、玩家状态提示、物品跟踪标记等等。最初只是用在自己服务器上的一套脚本,所以这套脚本私货挺多的,不过很多东西都做成了可配置的模式。 4 | 5 | 这是一套脚本 MOD,它是运行在服务端的。本地客户端作为房主开房会生效,并且作用于房间内所有玩家,而自己进入别人的房间是没有用的。 6 | 7 | 详细说明请阅 [GitHub-Wiki](https://github.com/Lin515/L4D2_LinGe_VScripts/wiki) 或者 [Gitee-Wiki](https://gitee.com/LinGe515/L4D2_LinGe_VScripts/wikis) 8 | 9 | ## 创意工坊 10 | 11 | 本系列脚本在创意工坊分开发布为以下多个 MOD,你可以只订阅以下所有 MOD 的[整合版](https://steamcommunity.com/sharedfiles/filedetails/?id=2587952986),也可以按自己的需求分开订阅: 12 | 13 | * [基础库](https://steamcommunity.com/sharedfiles/filedetails/?id=2819659703) 14 | 不管使用下面的哪个功能性 MOD,都必须同时订阅这个。 15 | * [HUD 伤害与击杀统计](https://steamcommunity.com/sharedfiles/filedetails/?id=2819660601) 16 | 可以在所有人的屏幕上显示排行榜、服务器名、时间等等,也可以在聊天窗输出排行榜以及友伤提示。 17 | * [多特控制](https://steamcommunity.com/sharedfiles/filedetails/?id=2819716701) 18 | 可以在游戏中随时更改特感的数量上限、刷新间隔、生成种类。 19 | * [标记与提示](https://steamcommunity.com/sharedfiles/filedetails/?edit=true&id=2819717120) 20 | 玩家可以发出标记来传递信息,几乎所有物品都可以标记。 21 | 玩家遇到倒地、黑白、被控时可以发出呼救,其他玩家可以看到显示在其身上的的提示。 22 | * [自杀指令](https://steamcommunity.com/sharedfiles/filedetails/?id=2819717317) 23 | 玩家可以通过发送 !zs 指令自杀。 24 | * [击杀回血](https://steamcommunity.com/sharedfiles/filedetails/?id=2956602969) 25 | 击杀特感或丧尸时使击杀者回血,可设置回复实血或虚血。 -------------------------------------------------------------------------------- /plugin/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5) 2 | 3 | project(LinGe_VScripts LANGUAGES CXX) 4 | 5 | set(L4D2BIN ~/l4d2sv/bin) # 仅Linux下需要用到 6 | set(HL2SDKL4D2 ../../L4D2_Dev/hl2sdk-l4d2) 7 | 8 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 9 | set(CMAKE_CXX_STANDARD 11) 10 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 11 | 12 | set(HL2PUB ${HL2SDKL4D2}/public) 13 | set(HL2GAME ${HL2SDKL4D2}/game) 14 | 15 | if(WIN32) 16 | link_directories(${HL2SDKL4D2}/lib/public) 17 | set(LINK_LIBRARY 18 | tier0 19 | vstdlib 20 | tier1 21 | tier2 22 | tier3 23 | mathlib 24 | legacy_stdio_definitions # vc++2015及以上需链接此库 25 | ) 26 | add_compile_options(/source-charset:windows-1250) 27 | add_compile_options(/execution-charset:utf-8) 28 | add_compile_options(/MP) 29 | # 静态链接到CRT库 30 | string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) 31 | string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) 32 | string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) 33 | string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) 34 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:libc") 35 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:libcd") 36 | # set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NODEFAULTLIB:libcmt") # 如果动态链接到CRT库,需要忽略libcmt 37 | elseif(UNIX) 38 | link_directories(${L4D2BIN}) # 不要设置到 ${HL2SDKL4D2}/lib/linux .so需使用服务器最新 39 | get_filename_component(ABSLIB ${HL2SDKL4D2}/lib/linux ABSOLUTE) 40 | set(LINK_LIBRARY 41 | libtier0_srv.so 42 | libvstdlib_srv.so 43 | ${ABSLIB}/tier1_i486.a 44 | ${ABSLIB}/tier2_i486.a 45 | ${ABSLIB}/tier3_i486.a 46 | ${ABSLIB}/mathlib_i486.a 47 | ) 48 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LINUX -DL4D2 -m32 \ 49 | -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp \ 50 | -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf \ 51 | -D_alloca=alloca -Dstrcmpi=strcasecmp -DHAVE_STDINT_H -Wall -Wno-switch \ 52 | -Wno-error=uninitialized -Wno-unused -Wno-error=delete-non-virtual-dtor \ 53 | -Wno-class-memaccess -Wno-packed-not-aligned -mfpmath=sse -msse \ 54 | -Wno-non-virtual-dtor -fno-rtti -fno-threadsafe-statics \ 55 | -Wno-overloaded-virtual -fpermissive \ 56 | -ldl -lm -static-libgcc -static-libstdc++" 57 | ) 58 | set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -funroll-loops -pipe -fno-strict-aliasing") 59 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}") 60 | endif() 61 | 62 | # 创建库 63 | add_library(LinGe_VScripts SHARED) 64 | 65 | if(UNIX) 66 | set_target_properties(LinGe_VScripts PROPERTIES PREFIX "") # 去掉输出文件名的lib前缀 67 | endif() 68 | 69 | target_sources(LinGe_VScripts PRIVATE 70 | LinGe_VScripts.cpp 71 | sdkapi/MemoryUtils/MemoryUtils.cpp 72 | sdkapi/sdkapi.cpp 73 | ) 74 | 75 | target_include_directories(LinGe_VScripts PRIVATE 76 | ${HL2PUB} 77 | ${HL2PUB}/tier0 78 | ${HL2PUB}/tier1 79 | ${HL2PUB}/tier2 80 | ${HL2PUB}/tier3 81 | ${HL2GAME}/shared 82 | ${HL2GAME}/server 83 | ${HL2GAME}/client 84 | ${HL2SDKL4D2}/common 85 | ) 86 | 87 | target_link_libraries(LinGe_VScripts PRIVATE ${LINK_LIBRARY}) -------------------------------------------------------------------------------- /plugin/LinGe_VScripts.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * LinGe_VScripts 3 | * Copyright (C) 2021 LinGe All rights reserved. 4 | * ============================================================================= 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License, version 3.0, as published by the 8 | * Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program. If not, see . 17 | */ 18 | #include 19 | #include 20 | #include 21 | #include "LinGe_VScripts.h" 22 | #include "sdkapi/sdkapi.h" 23 | 24 | LinGe_VScripts plugin; 25 | EXPOSE_SINGLE_INTERFACE_GLOBALVAR(LinGe_VScripts, IServerPluginCallbacks, INTERFACEVERSION_ISERVERPLUGINCALLBACKS, plugin); 26 | 27 | // ConVar 28 | ConVar cv_vscriptReturn("linge_vscript_return", "", FCVAR_HIDDEN|FCVAR_SPONLY, "Return VScript values."); 29 | ConVar cv_lookPing("linge_look_ping", "1", FCVAR_NOTIFY, "PlayerPing is executed when the 'vocalize smartlook' command is issued.", true, 0.0, true, 1.0, LinGe_VScripts::OnLookPingChanged); 30 | ConVar cv_time("linge_time", "", FCVAR_PRINTABLEONLY|FCVAR_SPONLY, "Server system time."); 31 | ConVar cv_format("linge_time_format", "%Y-%m-%d %H:%M:%S", FCVAR_NONE, "linge_time format string, see also:https://www.runoob.com/cprogramming/c-function-strftime.html", false, 0.0, false, 0.0, LinGe_VScripts::OnTimeFormatChanged); 32 | char g_sTimeFormat[50] = "%Y-%m-%d %H:%M:%S"; 33 | bool g_bLookPing = true; 34 | 35 | LinGe_VScripts::LinGe_VScripts() : m_iClientCommandIndex(0), m_bPlayerPingLoaded(false) 36 | { 37 | } 38 | LinGe_VScripts::~LinGe_VScripts() {} 39 | 40 | bool LinGe_VScripts::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) 41 | { 42 | SDKAPI::Initialize(interfaceFactory, gameServerFactory); 43 | 44 | ConVar_Register(); 45 | 46 | PL_Msg("Loaded.\n"); 47 | return true; 48 | } 49 | void LinGe_VScripts::Unload(void) 50 | { 51 | SDKAPI::iGameEventManager->RemoveListener(this); 52 | 53 | ConVar_Unregister(); 54 | SDKAPI::UnInitialize(); 55 | } 56 | 57 | const char *LinGe_VScripts::GetPluginDescription(void) { 58 | return PLNAME " " PLVER " By LinGe"; 59 | } 60 | 61 | void LinGe_VScripts::GameFrame(bool simulating) 62 | { 63 | // 每 1s 更新一次 linge_time 64 | static time_t oldTime = 0, nowTime = 0; 65 | static char buffer[50]; 66 | time(&nowTime); 67 | if (nowTime - oldTime >= 1) 68 | { 69 | if (strftime(buffer, sizeof(buffer), g_sTimeFormat, localtime(&nowTime))) 70 | cv_time.SetValue(buffer); 71 | else 72 | cv_time.SetValue("ERROR"); 73 | oldTime = nowTime; 74 | } 75 | } 76 | 77 | void LinGe_VScripts::LevelInit(char const *pMapName) { 78 | SDKAPI::iGameEventManager->AddListener(this, "round_start", true); 79 | } 80 | void LinGe_VScripts::LevelShutdown(void) { 81 | SDKAPI::iGameEventManager->RemoveListener(this); 82 | } 83 | 84 | void LinGe_VScripts::FireGameEvent(IGameEvent * event) 85 | { 86 | const char *name = event->GetName(); 87 | if (Q_stricmp(name, "round_start") == 0) 88 | { 89 | // 验证根表下是否存在 LinPlayerPing 90 | SDKAPI::L4D2_RunScript("Convars.SetValue(\"linge_vscript_return\", getroottable().rawin(\"LinPlayerPing\"));"); 91 | if (cv_vscriptReturn.GetBool()) 92 | { 93 | m_bPlayerPingLoaded = true; 94 | PL_DevMsg("LinPlayerPing found.\n"); 95 | } 96 | else 97 | { 98 | m_bPlayerPingLoaded = false; 99 | PL_DevMsg("LinPlayerPing not found.\n"); 100 | } 101 | } 102 | } 103 | 104 | void LinGe_VScripts::ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) {} 105 | 106 | // 监测 vocalize smartlook 107 | PLUGIN_RESULT LinGe_VScripts::ClientCommand(edict_t *pEntity, const CCommand &args) 108 | { 109 | if ( !pEntity || pEntity->IsFree() ) 110 | return PLUGIN_CONTINUE; 111 | if (m_bPlayerPingLoaded && g_bLookPing) 112 | { 113 | if (args.ArgC() >= 2 && Q_stricmp(args[0], "vocalize") == 0 114 | && Q_stricmp(args[1], "smartlook") == 0 115 | && (args.ArgC() == 2 || Q_stricmp(args[2], "auto") != 0) ) 116 | // 游戏自动让人物发出该指令时,第三个参数会为 auto 117 | { 118 | IPlayerInfo *player = SDKAPI::iPlayerInfoManager->GetPlayerInfo(pEntity); 119 | if (player->IsPlayer() && player->GetTeamIndex() == 2 120 | && !player->IsFakeClient() && !player->IsDead()) 121 | { 122 | PL_DevMsg("%s PlayerPing\n", player->GetName()); 123 | SDKAPI::L4D2_RunScript("::LinPlayerPing(%d);", player->GetUserID()); 124 | } 125 | } 126 | } 127 | 128 | return PLUGIN_CONTINUE; 129 | } 130 | 131 | // 插件控制台变量发生改变 132 | void LinGe_VScripts::OnLookPingChanged(IConVar *var, const char *pOldValue, float flOldValue) 133 | { 134 | g_bLookPing = cv_lookPing.GetBool(); 135 | } 136 | void LinGe_VScripts::OnTimeFormatChanged(IConVar *var, const char *pOldValue, float flOldValue) 137 | { 138 | strncpy(g_sTimeFormat, cv_format.GetString(), sizeof(g_sTimeFormat) - 1); 139 | g_sTimeFormat[sizeof(g_sTimeFormat) - 1] = '\0'; 140 | } 141 | 142 | void LinGe_VScripts::Pause(void) {} 143 | void LinGe_VScripts::UnPause(void) {} 144 | void LinGe_VScripts::ClientActive(edict_t *pEntity) {} 145 | void LinGe_VScripts::ClientDisconnect(edict_t *pEntity) {} 146 | void LinGe_VScripts::OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, 147 | EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue) {} 148 | void LinGe_VScripts::ClientPutInServer(edict_t *pEntity, const char *playername) {} 149 | void LinGe_VScripts::SetCommandClient(int index) { 150 | m_iClientCommandIndex = index; 151 | } 152 | void LinGe_VScripts::ClientSettingsChanged(edict_t *pEdict) {} 153 | PLUGIN_RESULT LinGe_VScripts::ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen) { 154 | return PLUGIN_CONTINUE; 155 | } 156 | PLUGIN_RESULT LinGe_VScripts::NetworkIDValidated(const char *pszUserName, const char *pszNetworkID) { 157 | return PLUGIN_CONTINUE; 158 | } 159 | void LinGe_VScripts::OnEdictAllocated(edict_t *edict) {} 160 | void LinGe_VScripts::OnEdictFreed(const edict_t *edict) {} -------------------------------------------------------------------------------- /plugin/LinGe_VScripts.h: -------------------------------------------------------------------------------- 1 | /** 2 | * LinGe_VScripts 3 | * Copyright (C) 2021 LinGe All rights reserved. 4 | * ============================================================================= 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License, version 3.0, as published by the 8 | * Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program. If not, see . 17 | */ 18 | #pragma once 19 | #include 20 | #include 21 | #include 22 | #define PLNAME "LinGe_VScripts" 23 | #define PLVER "v2.7.0" 24 | 25 | #define PL_Msg(format, ...) Msg(PLNAME ": " format, ## __VA_ARGS__) 26 | #define PL_Warning(format, ...) Warning(PLNAME ": " format, ## __VA_ARGS__) 27 | #define PL_Error(format, ...) Error(PLNAME ": " format, ## __VA_ARGS__) 28 | #define PL_DevMsg(format, ...) DevMsg(PLNAME ": " format, ## __VA_ARGS__) 29 | 30 | class LinGe_VScripts : public IServerPluginCallbacks, public IGameEventListener2 31 | { 32 | public: 33 | LinGe_VScripts(); 34 | ~LinGe_VScripts(); 35 | 36 | // IServerPluginCallbacks methods 37 | virtual bool Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory); 38 | virtual void Unload(void); 39 | virtual void Pause(void); 40 | virtual void UnPause(void); 41 | virtual const char * GetPluginDescription(void); 42 | virtual void LevelInit(char const *pMapName); 43 | virtual void ServerActivate(edict_t *pEdictList, int edictCount, int clientMax); 44 | virtual void GameFrame(bool simulating); 45 | virtual void LevelShutdown(void); 46 | virtual void ClientActive(edict_t *pEntity); 47 | virtual void ClientDisconnect(edict_t *pEntity); 48 | virtual void ClientPutInServer(edict_t *pEntity, char const *playername); 49 | virtual void SetCommandClient(int index); 50 | virtual void ClientSettingsChanged(edict_t *pEdict); 51 | virtual PLUGIN_RESULT ClientConnect(bool *bAllowConnect, edict_t *pEntity, const char *pszName, const char *pszAddress, char *reject, int maxrejectlen); 52 | virtual PLUGIN_RESULT ClientCommand(edict_t *pEntity, const CCommand &args); 53 | virtual PLUGIN_RESULT NetworkIDValidated(const char *pszUserName, const char *pszNetworkID); 54 | virtual void OnQueryCvarValueFinished(QueryCvarCookie_t iCookie, edict_t *pPlayerEntity, EQueryCvarValueStatus eStatus, const char *pCvarName, const char *pCvarValue); 55 | 56 | // added with version 3 of the interface. 57 | virtual void OnEdictAllocated(edict_t *edict); 58 | virtual void OnEdictFreed(const edict_t *edict); 59 | 60 | // IGameEventListener Interface 61 | virtual void FireGameEvent( IGameEvent * event ); 62 | virtual int GetEventDebugID() { return EVENT_DEBUG_ID_INIT; } 63 | virtual int GetCommandIndex() { return m_iClientCommandIndex; } 64 | 65 | private: 66 | int m_iClientCommandIndex; 67 | bool m_bPlayerPingLoaded; 68 | 69 | public: 70 | static void OnLookPingChanged(IConVar *var, const char *pOldValue, float flOldValue); 71 | static void OnTimeFormatChanged(IConVar *var, const char *pOldValue, float flOldValue); 72 | }; -------------------------------------------------------------------------------- /plugin/LinGe_VScripts.vdf: -------------------------------------------------------------------------------- 1 | "Plugin" 2 | { 3 | "file" "addons/LinGe_VScripts/LinGe_VScripts" 4 | } 5 | 6 | -------------------------------------------------------------------------------- /plugin/licenses/GPLv2.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /plugin/licenses/GPLv3.txt: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /plugin/licenses/LICENSE.txt: -------------------------------------------------------------------------------- 1 | SOURCEMOD LICENSE INFORMATION 2 | VERSION: 2019-9-30 3 | ----------------------------- 4 | 5 | SourceMod is licensed under the GNU General Public License, version 3. 6 | 7 | As a special exception, AlliedModders LLC gives you permission to link the code 8 | of this program (as well as its derivative works) to "Half-Life 2," the "Source 9 | Engine" and any Game MODs that run on software by the Valve Corporation. 10 | You must obey the GNU General Public License in all respects for all other code used. 11 | Additionally, AlliedModders LLC grants this exception to all derivative works. 12 | 13 | As an additional special exception to the GNU General Public License 3.0, 14 | AlliedModders LLC permits dual-licensing of DERIVATIVE WORKS ONLY (that is, 15 | SourcePawn/SourceMod Plugins and SourceMod Extensions, or any software built 16 | from the SourceMod SDK or header files) under the GNU General Public License 17 | version 2 "or any higher version." As such, you may choose for your derivative 18 | work(s) to be compatible with the GNU General Public License version 2 as long 19 | as it is also compatible with the GNU General Public License version 3, via the 20 | "or any higher version" clause. This is intended for compatibility with other 21 | software. 22 | 23 | As a final exception to the above, any derivative works created prior to this 24 | date (July 31, 2007) may be exclusively licensed under the GNU General Public 25 | License version 2 (without an "or any higher version" clause) if and only if 26 | the work was already GNU General Public License 2.0 exclusive. This clause is 27 | provided for backwards compatibility only. 28 | 29 | A copy of the GNU General Public License 2.0 is available in GPLv2.txt. 30 | A copy of the GNU General Public License 3.0 is available in GPLv3.txt. 31 | 32 | SourcePawn is Copyright (C) 2006-2008 AlliedModders LLC. All rights reserved. 33 | SourceMod is Copyright (C) 2006-2008 AlliedModders LLC. All rights reserved. 34 | Pawn and SMALL are Copyright (C) 1997-2008 ITB CompuPhase. 35 | Source is Copyright (C) Valve Corporation. 36 | All trademarks are property of their respective owners in the US and other countries. 37 | -------------------------------------------------------------------------------- /plugin/sdkapi/MemoryUtils/MemoryUtils.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 sw=4 tw=99 noet : 3 | * ============================================================================= 4 | * SourceMod 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 . 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 . 28 | */ 29 | // 修改自 sourcemod/core/logic/MemoryUtils.cpp 30 | // https://github.com/alliedmodders/sourcemod 31 | 32 | #include "MemoryUtils.h" 33 | #ifdef PLATFORM_LINUX 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define PAGE_SIZE 4096 40 | #define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) 41 | #endif 42 | 43 | MemoryUtils::MemoryUtils(CreateInterfaceFn factory) : 44 | isAvailable(false), factory(nullptr) 45 | { 46 | if (factory) 47 | Init(factory); 48 | } 49 | 50 | bool MemoryUtils::Init(CreateInterfaceFn factory) 51 | { 52 | this->factory = factory; 53 | isAvailable = MemoryUtils::GetLibraryInfo((void *)factory, this->lib); 54 | return isAvailable; 55 | } 56 | 57 | bool MemoryUtils::IsAvailable() 58 | { 59 | return isAvailable; 60 | } 61 | 62 | void *MemoryUtils::FindPattern(const char *pattern) 63 | { 64 | if (!this->isAvailable) 65 | return nullptr; 66 | 67 | bool found; 68 | char *ptr, *end; 69 | size_t len = strlen(pattern); 70 | 71 | ptr = reinterpret_cast(lib.baseAddress); 72 | end = ptr + lib.memorySize - len; 73 | 74 | while (ptr < end) 75 | { 76 | found = true; 77 | for (register size_t i = 0; i < len; i++) 78 | { 79 | if (pattern[i] != '\x2A' && pattern[i] != ptr[i]) 80 | { 81 | found = false; 82 | break; 83 | } 84 | } 85 | 86 | if (found) 87 | return ptr; 88 | 89 | ptr++; 90 | } 91 | 92 | return nullptr; 93 | } 94 | 95 | void *MemoryUtils::ResolveSymbol(const char *symbol) 96 | { 97 | if (!this->isAvailable) 98 | return nullptr; 99 | 100 | HMODULE handle = this->lib.handle; 101 | #ifdef WIN32 102 | return GetProcAddress(handle, symbol); 103 | #elif defined PLATFORM_LINUX 104 | 105 | #ifdef PLATFORM_X86 106 | typedef Elf32_Ehdr ElfHeader; 107 | typedef Elf32_Shdr ElfSHeader; 108 | typedef Elf32_Sym ElfSymbol; 109 | #define ELF_SYM_TYPE ELF32_ST_TYPE 110 | #else 111 | typedef Elf64_Ehdr ElfHeader; 112 | typedef Elf64_Shdr ElfSHeader; 113 | typedef Elf64_Sym ElfSymbol; 114 | #define ELF_SYM_TYPE ELF64_ST_TYPE 115 | #endif 116 | 117 | struct link_map *dlmap; 118 | struct stat dlstat; 119 | int dlfile; 120 | uintptr_t map_base; 121 | ElfHeader *file_hdr; 122 | ElfSHeader *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr; 123 | ElfSymbol *symtab; 124 | const char *shstrtab, *strtab; 125 | uint16_t section_count; 126 | uint32_t symbol_count; 127 | SymbolTable *table; 128 | Symbol *symbol_entry; 129 | 130 | dlmap = (struct link_map *)handle; 131 | symtab_hdr = nullptr; 132 | strtab_hdr = nullptr; 133 | table = nullptr; 134 | 135 | /* See if we already have a symbol table for this library */ 136 | if (m_SymTable.lib_base == dlmap->l_addr) 137 | table = &m_SymTable.table; 138 | 139 | /* If we don't have a symbol table for this library, then create one */ 140 | if (table == nullptr) 141 | { 142 | m_SymTable.table.Initialize(); 143 | m_SymTable.lib_base = dlmap->l_addr; 144 | m_SymTable.last_pos = 0; 145 | table = &m_SymTable.table; 146 | } 147 | 148 | /* See if the symbol is already cached in our table */ 149 | symbol_entry = table->FindSymbol(symbol, strlen(symbol)); 150 | if (symbol_entry != nullptr) 151 | { 152 | return symbol_entry->address; 153 | } 154 | 155 | /* If symbol isn't in our table, then we have open the actual library */ 156 | dlfile = open(dlmap->l_name, O_RDONLY); 157 | if (dlfile == -1 || fstat(dlfile, &dlstat) == -1) 158 | { 159 | close(dlfile); 160 | return nullptr; 161 | } 162 | 163 | /* Map library file into memory */ 164 | file_hdr = (ElfHeader *)mmap(nullptr, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0); 165 | map_base = (uintptr_t)file_hdr; 166 | if (file_hdr == MAP_FAILED) 167 | { 168 | close(dlfile); 169 | return nullptr; 170 | } 171 | close(dlfile); 172 | 173 | if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF) 174 | { 175 | munmap(file_hdr, dlstat.st_size); 176 | return nullptr; 177 | } 178 | 179 | sections = (ElfSHeader *)(map_base + file_hdr->e_shoff); 180 | section_count = file_hdr->e_shnum; 181 | /* Get ELF section header string table */ 182 | shstrtab_hdr = §ions[file_hdr->e_shstrndx]; 183 | shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset); 184 | 185 | /* Iterate sections while looking for ELF symbol table and string table */ 186 | for (uint16_t i = 0; i < section_count; i++) 187 | { 188 | ElfSHeader &hdr = sections[i]; 189 | const char *section_name = shstrtab + hdr.sh_name; 190 | 191 | if (strcmp(section_name, ".symtab") == 0) 192 | { 193 | symtab_hdr = &hdr; 194 | } 195 | else if (strcmp(section_name, ".strtab") == 0) 196 | { 197 | strtab_hdr = &hdr; 198 | } 199 | } 200 | 201 | /* Uh oh, we don't have a symbol table or a string table */ 202 | if (symtab_hdr == nullptr || strtab_hdr == nullptr) 203 | { 204 | munmap(file_hdr, dlstat.st_size); 205 | return nullptr; 206 | } 207 | 208 | symtab = (ElfSymbol *)(map_base + symtab_hdr->sh_offset); 209 | strtab = (const char *)(map_base + strtab_hdr->sh_offset); 210 | symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize; 211 | 212 | /* Iterate symbol table starting from the position we were at last time */ 213 | for (uint32_t i = m_SymTable.last_pos; i < symbol_count; i++) 214 | { 215 | ElfSymbol &sym = symtab[i]; 216 | unsigned char sym_type = ELF_SYM_TYPE(sym.st_info); 217 | const char *sym_name = strtab + sym.st_name; 218 | Symbol *cur_sym; 219 | 220 | /* Skip symbols that are undefined or do not refer to functions or objects */ 221 | if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT)) 222 | { 223 | continue; 224 | } 225 | 226 | /* Caching symbols as we go along */ 227 | cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value)); 228 | if (strcmp(symbol, sym_name) == 0) 229 | { 230 | symbol_entry = cur_sym; 231 | m_SymTable.last_pos = ++i; 232 | break; 233 | } 234 | } 235 | 236 | munmap(file_hdr, dlstat.st_size); 237 | return symbol_entry ? symbol_entry->address : nullptr; 238 | 239 | #endif 240 | } 241 | 242 | bool MemoryUtils::GetLibraryInfo(const void *libPtr, DynLibInfo &lib) 243 | { 244 | uintptr_t baseAddr; 245 | 246 | if (libPtr == nullptr) 247 | { 248 | return false; 249 | } 250 | 251 | #ifdef WIN32 252 | 253 | #ifdef PLATFORM_X86 254 | const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_I386; 255 | const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR32_MAGIC; 256 | #else 257 | const WORD PE_FILE_MACHINE = IMAGE_FILE_MACHINE_AMD64; 258 | const WORD PE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR64_MAGIC; 259 | #endif 260 | 261 | MEMORY_BASIC_INFORMATION info; 262 | IMAGE_DOS_HEADER *dos; 263 | IMAGE_NT_HEADERS *pe; 264 | IMAGE_FILE_HEADER *file; 265 | IMAGE_OPTIONAL_HEADER *opt; 266 | 267 | if (!VirtualQuery(libPtr, &info, sizeof(MEMORY_BASIC_INFORMATION))) 268 | { 269 | return false; 270 | } 271 | 272 | baseAddr = reinterpret_cast(info.AllocationBase); 273 | 274 | /* All this is for our insane sanity checks :o */ 275 | dos = reinterpret_cast(baseAddr); 276 | pe = reinterpret_cast(baseAddr + dos->e_lfanew); 277 | file = &pe->FileHeader; 278 | opt = &pe->OptionalHeader; 279 | 280 | /* Check PE magic and signature */ 281 | if (dos->e_magic != IMAGE_DOS_SIGNATURE || pe->Signature != IMAGE_NT_SIGNATURE || opt->Magic != PE_NT_OPTIONAL_HDR_MAGIC) 282 | { 283 | return false; 284 | } 285 | 286 | /* Check architecture */ 287 | if (file->Machine != PE_FILE_MACHINE) 288 | { 289 | return false; 290 | } 291 | 292 | /* For our purposes, this must be a dynamic library */ 293 | if ((file->Characteristics & IMAGE_FILE_DLL) == 0) 294 | { 295 | return false; 296 | } 297 | 298 | /* Finally, we can do this */ 299 | lib.memorySize = opt->SizeOfImage; 300 | lib.handle = (HMODULE)info.AllocationBase; 301 | 302 | #elif defined PLATFORM_LINUX 303 | 304 | #ifdef PLATFORM_X86 305 | typedef Elf32_Ehdr ElfHeader; 306 | typedef Elf32_Phdr ElfPHeader; 307 | const unsigned char ELF_CLASS = ELFCLASS32; 308 | const uint16_t ELF_MACHINE = EM_386; 309 | #else 310 | typedef Elf64_Ehdr ElfHeader; 311 | typedef Elf64_Phdr ElfPHeader; 312 | const unsigned char ELF_CLASS = ELFCLASS64; 313 | const uint16_t ELF_MACHINE = EM_X86_64; 314 | #endif 315 | 316 | Dl_info info; 317 | ElfHeader *file; 318 | ElfPHeader *phdr; 319 | uint16_t phdrCount; 320 | 321 | if (!dladdr(libPtr, &info)) 322 | { 323 | return false; 324 | } 325 | 326 | if (!info.dli_fbase || !info.dli_fname) 327 | { 328 | return false; 329 | } 330 | 331 | /* This is for our insane sanity checks :o */ 332 | baseAddr = reinterpret_cast(info.dli_fbase); 333 | file = reinterpret_cast(baseAddr); 334 | 335 | /* Check ELF magic */ 336 | if (memcmp(ELFMAG, file->e_ident, SELFMAG) != 0) 337 | { 338 | return false; 339 | } 340 | 341 | /* Check ELF version */ 342 | if (file->e_ident[EI_VERSION] != EV_CURRENT) 343 | { 344 | return false; 345 | } 346 | 347 | /* Check ELF endianness */ 348 | if (file->e_ident[EI_DATA] != ELFDATA2LSB) 349 | { 350 | return false; 351 | } 352 | 353 | /* Check ELF architecture */ 354 | if (file->e_ident[EI_CLASS] != ELF_CLASS || file->e_machine != ELF_MACHINE) 355 | { 356 | return false; 357 | } 358 | 359 | /* For our purposes, this must be a dynamic library/shared object */ 360 | if (file->e_type != ET_DYN) 361 | { 362 | return false; 363 | } 364 | 365 | phdrCount = file->e_phnum; 366 | phdr = reinterpret_cast(baseAddr + file->e_phoff); 367 | 368 | for (uint16_t i = 0; i < phdrCount; i++) 369 | { 370 | ElfPHeader &hdr = phdr[i]; 371 | 372 | /* We only really care about the segment with executable code */ 373 | if (hdr.p_type == PT_LOAD && hdr.p_flags == (PF_X | PF_R)) 374 | { 375 | /* From glibc, elf/dl-load.c: 376 | * c->mapend = ((ph->p_vaddr + ph->p_filesz + GLRO(dl_pagesize) - 1) 377 | * & ~(GLRO(dl_pagesize) - 1)); 378 | * 379 | * In glibc, the segment file size is aligned up to the nearest page size and 380 | * added to the virtual address of the segment. We just want the size here. 381 | */ 382 | lib.memorySize = PAGE_ALIGN_UP(hdr.p_filesz); 383 | break; 384 | } 385 | } 386 | 387 | // 获取句柄 388 | HMODULE handle = dlopen(info.dli_fname, RTLD_NOW); 389 | if (!handle) 390 | return false; 391 | dlclose(handle); 392 | lib.handle = handle; 393 | 394 | #endif 395 | lib.baseAddress = reinterpret_cast(baseAddr); 396 | return true; 397 | } 398 | -------------------------------------------------------------------------------- /plugin/sdkapi/MemoryUtils/MemoryUtils.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 sw=4 tw=99 noet : 3 | * ============================================================================= 4 | * SourceMod 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 . 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 . 28 | */ 29 | // 修改自 sourcemod/core/logic/MemoryUtils.h 30 | // https://github.com/alliedmodders/sourcemod 31 | 32 | #ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ 33 | #define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ 34 | #include "sm_platform.h" 35 | #include 36 | #include 37 | 38 | #if defined PLATFORM_LINUX 39 | #include "sm_symtable.h" 40 | #endif 41 | 42 | struct VTableIndex { 43 | int Windows; 44 | int Linux; 45 | }; 46 | 47 | // 从虚函数表获取指定的虚函数 48 | template 49 | inline Fn GetVirtualFunction(void *base, VTableIndex index) 50 | { 51 | // 将 base 对象基址直接转换为指向虚函数表的指针 52 | std::uintptr_t **pVTable = (std::uintptr_t **)base; 53 | // 从虚函数表获取对应的虚函数指针 54 | #ifdef WIN32 55 | return reinterpret_cast((*pVTable)[index.Windows]); 56 | #elif defined _LINUX 57 | return reinterpret_cast((*pVTable)[index.Linux]); 58 | #endif 59 | } 60 | 61 | struct Signature { 62 | const char *Windows; 63 | const char *Linux; 64 | }; 65 | 66 | struct DynLibInfo 67 | { 68 | void *baseAddress; 69 | size_t memorySize; 70 | HMODULE handle; 71 | }; 72 | 73 | #if defined PLATFORM_LINUX 74 | struct LibSymbolTable 75 | { 76 | SymbolTable table; 77 | uintptr_t lib_base; 78 | uint32_t last_pos; 79 | }; 80 | #endif 81 | 82 | class MemoryUtils 83 | { 84 | public: 85 | MemoryUtils(CreateInterfaceFn factory = nullptr); 86 | bool Init(CreateInterfaceFn factory); 87 | bool IsAvailable(); 88 | static bool GetLibraryInfo(const void *libPtr, DynLibInfo &lib); 89 | 90 | private: 91 | bool isAvailable; 92 | CreateInterfaceFn factory; 93 | DynLibInfo lib; 94 | #ifdef PLATFORM_LINUX 95 | LibSymbolTable m_SymTable; 96 | #endif 97 | 98 | public: 99 | void *FindPattern(const char *pattern); 100 | void *ResolveSymbol(const char *symbol); 101 | 102 | template 103 | inline Fn FindSignature(Signature signature) 104 | { 105 | #ifdef WIN32 106 | return reinterpret_cast(FindPattern(signature.Windows)); 107 | #elif defined PLATFORM_LINUX 108 | if (signature.Linux[0] == '@') 109 | return reinterpret_cast(ResolveSymbol(&signature.Linux[1])); 110 | else 111 | return reinterpret_cast(FindPattern(signature.Linux)); 112 | #endif 113 | } 114 | }; 115 | 116 | #endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_ 117 | -------------------------------------------------------------------------------- /plugin/sdkapi/MemoryUtils/sm_platform.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 : 3 | * ============================================================================= 4 | * SourceMod 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 . 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 . 28 | * 29 | * Version: $Id$ 30 | */ 31 | 32 | #ifndef _INCLUDE_SOURCEMOD_PLATFORM_H_ 33 | #define _INCLUDE_SOURCEMOD_PLATFORM_H_ 34 | 35 | /** 36 | * @file sm_platform.h 37 | * @brief Contains platform-specific macros for abstraction. 38 | */ 39 | 40 | #if defined WIN32 || defined WIN64 41 | #ifndef PLATFORM_WINDOWS 42 | #define PLATFORM_WINDOWS 1 43 | #endif 44 | 45 | #if defined WIN64 || defined _WIN64 46 | #ifndef PLATFORM_X64 47 | # define PLATFORM_X64 1 48 | #endif 49 | #else 50 | #ifndef PLATFORM_X86 51 | # define PLATFORM_X86 1 52 | #endif 53 | #endif // defined WIN64 || defined _WIN64 54 | 55 | #if !defined WIN32_LEAN_AND_MEAN 56 | #define WIN32_LEAN_AND_MEAN 57 | #endif 58 | #if !defined snprintf && defined _MSC_VER && _MSC_VER < 1900 59 | #define snprintf _snprintf 60 | #endif 61 | #if !defined stat 62 | #define stat _stat 63 | #endif 64 | #define strcasecmp strcmpi 65 | #define strncasecmp strnicmp 66 | #include 67 | #include 68 | #define PLATFORM_LIB_EXT "dll" 69 | #define PLATFORM_MAX_PATH MAX_PATH 70 | #define PLATFORM_SEP_CHAR '\\' 71 | #define PLATFORM_SEP_ALTCHAR '/' 72 | #define PLATFORM_SEP "\\" 73 | #define PLATFORM_EXTERN_C extern "C" __declspec(dllexport) 74 | #elif defined __linux__ || defined __APPLE__ 75 | #if defined __linux__ 76 | # define PLATFORM_LINUX 1 77 | # define PLATFORM_LIB_EXT "so" 78 | #elif defined __APPLE__ 79 | # define PLATFORM_APPLE 1 80 | # define PLATFORM_LIB_EXT "dylib" 81 | #endif 82 | #ifndef PLATFORM_POSIX 83 | # define PLATFORM_POSIX 1 84 | #endif 85 | 86 | #if defined __x86_64__ 87 | #ifndef PLATFORM_X64 88 | # define PLATFORM_X64 1 89 | #endif 90 | #else 91 | #ifndef PLATFORM_X86 92 | # define PLATFORM_X86 1 93 | #endif 94 | #endif // defined __x86_64__ 95 | 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #if defined PLATFORM_APPLE 102 | #include 103 | #endif 104 | #define PLATFORM_MAX_PATH PATH_MAX 105 | #define PLATFORM_SEP_CHAR '/' 106 | #define PLATFORM_SEP_ALTCHAR '\\' 107 | #define PLATFORM_SEP "/" 108 | #define PLATFORM_EXTERN_C extern "C" __attribute__((visibility("default"))) 109 | #endif 110 | 111 | #if !defined SOURCEMOD_BUILD 112 | #define SOURCEMOD_BUILD 113 | #endif 114 | 115 | #if !defined SM_ARRAYSIZE 116 | #define SM_ARRAYSIZE(x) ((sizeof(x)/sizeof(0[x])) / ((size_t)(!(sizeof(x) % sizeof(0[x]))))) 117 | #endif 118 | 119 | #if defined PLATFORM_X64 120 | #define PLATFORM_ARCH_FOLDER "x64" PLATFORM_SEP 121 | #ifdef PLATFORM_WINDOWS 122 | #define PLATFORM_FOLDER "win64" PLATFORM_SEP 123 | #elif defined PLATFORM_LINUX 124 | #define PLATFORM_FOLDER "linux64" PLATFORM_SEP 125 | #elif defined PLATFORM_APPLE 126 | #define PLATFORM_FOLDER "osx64" PLATFORM_SEP 127 | #endif 128 | #else 129 | #define PLATFORM_ARCH_FOLDER "" 130 | #ifdef PLATFORM_WINDOWS 131 | #define PLATFORM_FOLDER "win32" PLATFORM_SEP 132 | #elif defined PLATFORM_LINUX 133 | #define PLATFORM_FOLDER "linux32" PLATFORM_SEP 134 | #elif defined PLATFORM_APPLE 135 | #define PLATFORM_FOLDER "osx32" PLATFORM_SEP 136 | #endif 137 | #endif // defined PLATFORM_X64 138 | 139 | #endif //_INCLUDE_SOURCEMOD_PLATFORM_H_ 140 | 141 | -------------------------------------------------------------------------------- /plugin/sdkapi/MemoryUtils/sm_symtable.h: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 sw=4 tw=99 noet : 3 | * ============================================================================= 4 | * SourceMod 5 | * Copyright (C) 2004-2009 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 . 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 . 28 | */ 29 | 30 | #ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_ 31 | #define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_ 32 | 33 | #include 34 | #include 35 | #include 36 | 37 | #define KESTRING_TABLE_START_SIZE 65536 38 | 39 | struct Symbol 40 | { 41 | size_t length; 42 | uint32_t hash; 43 | void *address; 44 | Symbol *tbl_next; 45 | 46 | inline char *buffer() 47 | { 48 | return reinterpret_cast(this + 1); 49 | } 50 | }; 51 | 52 | class SymbolTable 53 | { 54 | public: 55 | ~SymbolTable() 56 | { 57 | for (uint32_t i = 0; i < nbuckets; i++) 58 | { 59 | Symbol *sym = buckets[i]; 60 | while (sym != NULL) 61 | { 62 | Symbol *next = sym->tbl_next; 63 | free(sym); 64 | sym = next; 65 | } 66 | } 67 | free(buckets); 68 | } 69 | 70 | bool Initialize() 71 | { 72 | buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE); 73 | if (buckets == NULL) 74 | { 75 | return false; 76 | } 77 | memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE); 78 | 79 | nbuckets = KESTRING_TABLE_START_SIZE; 80 | nused = 0; 81 | bucketmask = KESTRING_TABLE_START_SIZE - 1; 82 | return true; 83 | } 84 | 85 | static inline uint32_t HashString(const char *data, size_t len) 86 | { 87 | #undef get16bits 88 | #if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \ 89 | || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__) 90 | #define get16bits(d) (*((const uint16_t *) (d))) 91 | #endif 92 | #if !defined (get16bits) 93 | #define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\ 94 | +(uint32_t)(((const uint8_t *)(d))[0]) ) 95 | #endif 96 | uint32_t hash = len, tmp; 97 | int rem; 98 | 99 | if (len <= 0 || data == NULL) 100 | { 101 | return 0; 102 | } 103 | 104 | rem = len & 3; 105 | len >>= 2; 106 | 107 | /* Main loop */ 108 | for (;len > 0; len--) { 109 | hash += get16bits (data); 110 | tmp = (get16bits (data+2) << 11) ^ hash; 111 | hash = (hash << 16) ^ tmp; 112 | data += 2 * sizeof (uint16_t); 113 | hash += hash >> 11; 114 | } 115 | 116 | /* Handle end cases */ 117 | switch (rem) { 118 | case 3: hash += get16bits (data); 119 | hash ^= hash << 16; 120 | hash ^= data[sizeof (uint16_t)] << 18; 121 | hash += hash >> 11; 122 | break; 123 | case 2: hash += get16bits (data); 124 | hash ^= hash << 11; 125 | hash += hash >> 17; 126 | break; 127 | case 1: hash += *data; 128 | hash ^= hash << 10; 129 | hash += hash >> 1; 130 | } 131 | 132 | /* Force "avalanching" of final 127 bits */ 133 | hash ^= hash << 3; 134 | hash += hash >> 5; 135 | hash ^= hash << 4; 136 | hash += hash >> 17; 137 | hash ^= hash << 25; 138 | hash += hash >> 6; 139 | 140 | return hash; 141 | 142 | #undef get16bits 143 | } 144 | 145 | Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash) 146 | { 147 | uint32_t bucket = hash & bucketmask; 148 | Symbol **pkvs = &buckets[bucket]; 149 | 150 | Symbol *kvs = *pkvs; 151 | while (kvs != NULL) 152 | { 153 | if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0) 154 | { 155 | return pkvs; 156 | } 157 | pkvs = &kvs->tbl_next; 158 | kvs = *pkvs; 159 | } 160 | 161 | return pkvs; 162 | } 163 | 164 | void ResizeSymbolTable() 165 | { 166 | uint32_t xnbuckets = nbuckets * 2; 167 | Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets); 168 | if (xbuckets == NULL) 169 | { 170 | return; 171 | } 172 | memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets); 173 | uint32_t xbucketmask = xnbuckets - 1; 174 | for (uint32_t i = 0; i < nbuckets; i++) 175 | { 176 | Symbol *sym = buckets[i]; 177 | while (sym != NULL) 178 | { 179 | Symbol *next = sym->tbl_next; 180 | uint32_t bucket = sym->hash & xbucketmask; 181 | sym->tbl_next = xbuckets[bucket]; 182 | xbuckets[bucket] = sym; 183 | sym = next; 184 | } 185 | } 186 | free(buckets); 187 | buckets = xbuckets; 188 | nbuckets = xnbuckets; 189 | bucketmask = xbucketmask; 190 | } 191 | 192 | Symbol *FindSymbol(const char *str, size_t len) 193 | { 194 | uint32_t hash = HashString(str, len); 195 | Symbol **pkvs = FindSymbolBucket(str, len, hash); 196 | return *pkvs; 197 | } 198 | 199 | Symbol *InternSymbol(const char* str, size_t len, void *address) 200 | { 201 | uint32_t hash = HashString(str, len); 202 | Symbol **pkvs = FindSymbolBucket(str, len, hash); 203 | if (*pkvs != NULL) 204 | { 205 | return *pkvs; 206 | } 207 | 208 | Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1)); 209 | kvs->length = len; 210 | kvs->hash = hash; 211 | kvs->address = address; 212 | kvs->tbl_next = NULL; 213 | memcpy(kvs + 1, str, sizeof(char) * (len + 1)); 214 | *pkvs = kvs; 215 | nused++; 216 | 217 | if (nused > nbuckets && nbuckets <= INT_MAX / 2) 218 | { 219 | ResizeSymbolTable(); 220 | } 221 | 222 | return kvs; 223 | } 224 | private: 225 | uint32_t nbuckets; 226 | uint32_t nused; 227 | uint32_t bucketmask; 228 | Symbol **buckets; 229 | }; 230 | 231 | #endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_ 232 | -------------------------------------------------------------------------------- /plugin/sdkapi/sdkapi.cpp: -------------------------------------------------------------------------------- 1 | /** 2 | * SDKAPI 3 | * Copyright (C) 2021 LinGe All rights reserved. 4 | * ============================================================================= 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License, version 3.0, as published by the 8 | * Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program. If not, see . 17 | */ 18 | #include "sdkapi.h" 19 | #include "signature.h" 20 | #include 21 | #include 22 | #include 23 | 24 | namespace SDKAPI { 25 | ICvar *iCvar = nullptr; 26 | IPlayerInfoManager *iPlayerInfoManager = nullptr; 27 | IServerGameEnts *iServerGameEnts = nullptr; 28 | IVEngineServer *iVEngineServer = nullptr; 29 | IServerTools *iServerTools = nullptr; 30 | IServerGameDLL *iServerGameDLL = nullptr; 31 | IServerPluginHelpers *iServerPluginHelpers = nullptr; 32 | IGameEventManager2 *iGameEventManager = nullptr; 33 | CGlobalVars *pGlobals = nullptr; 34 | FCGlobalEntityList *gEntList = nullptr; 35 | 36 | static MemoryUtils *mu_engine = nullptr; 37 | static MemoryUtils *mu_server = nullptr; 38 | 39 | namespace ServerSigFunc { 40 | FINDENTITYBYCLASSNAME CBaseEntity_FindEntityByClassname = nullptr; 41 | 42 | void Initialize() 43 | { 44 | CBaseEntity_FindEntityByClassname = mu_server->FindSignature(Sig_FindEntityByClassname); 45 | if (!CBaseEntity_FindEntityByClassname) 46 | SDKAPI_Warning("FindEntityByClassname signature not found!\n"); 47 | } 48 | } 49 | 50 | void Initialize(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) 51 | { 52 | ConnectTier1Libraries(&interfaceFactory, 1); 53 | ConnectTier2Libraries(&interfaceFactory, 1); 54 | // hl2sdk-l4d2 接口 55 | iCvar = reinterpret_cast(interfaceFactory(CVAR_INTERFACE_VERSION, nullptr)); 56 | if (!iCvar) 57 | SDKAPI_Warning("ICvar interface initialize failed!\n"); 58 | 59 | iPlayerInfoManager = reinterpret_cast(gameServerFactory(INTERFACEVERSION_PLAYERINFOMANAGER, nullptr)); 60 | if (!iPlayerInfoManager) 61 | SDKAPI_Warning("IPlayerInfoManager interface initialize failed!\n"); 62 | 63 | iServerGameEnts = reinterpret_cast(gameServerFactory(INTERFACEVERSION_SERVERGAMEENTS, nullptr)); 64 | if (!iServerGameEnts) 65 | SDKAPI_Warning("IServerGameEnts interface initialize failed!\n"); 66 | 67 | iVEngineServer = reinterpret_cast(interfaceFactory(INTERFACEVERSION_VENGINESERVER, nullptr)); 68 | if (!iVEngineServer) 69 | SDKAPI_Warning("IVEngineServer interface initialize failed!\n"); 70 | 71 | iServerTools = reinterpret_cast(gameServerFactory(VSERVERTOOLS_INTERFACE_VERSION, nullptr)); 72 | if (!iServerTools) 73 | SDKAPI_Warning("IServerTools interface initialize failed!\n"); 74 | 75 | iServerGameDLL = reinterpret_cast(gameServerFactory(INTERFACEVERSION_SERVERGAMEDLL, nullptr)); 76 | if (!iServerGameDLL) 77 | SDKAPI_Warning("IServerGameDLL interface initialize failed!\n"); 78 | 79 | iServerPluginHelpers = reinterpret_cast(interfaceFactory(INTERFACEVERSION_ISERVERPLUGINHELPERS, nullptr)); 80 | if (!iServerPluginHelpers) 81 | SDKAPI_Warning("IServerPluginHelpers interface initialize failed!\n"); 82 | 83 | iGameEventManager = reinterpret_cast(interfaceFactory(INTERFACEVERSION_GAMEEVENTSMANAGER2, nullptr)); 84 | if (!iGameEventManager) 85 | SDKAPI_Warning("IGameEventManager2 interface initialize failed!\n"); 86 | 87 | mu_engine = new MemoryUtils(interfaceFactory); 88 | if (!mu_engine->IsAvailable()) 89 | SDKAPI_Warning("mu_engine initialize failed!\n"); 90 | 91 | mu_server = new MemoryUtils(gameServerFactory); 92 | if (!mu_server->IsAvailable()) 93 | SDKAPI_Warning("mu_server initialize failed!\n"); 94 | else 95 | ServerSigFunc::Initialize(); 96 | 97 | // 初始化 pEntList 方法参考 sourcemod/core/HalfLife2.cpp 98 | // Win32下是通过LevelShutdown函数地址再加上偏移量获得pEntityList(指向gEntList的指针)的地址 99 | // Linux下是直接通过符号查找获得gEntList的地址 100 | if (mu_server->IsAvailable()) 101 | { 102 | void *ptr = mu_server->FindSignature(Sig_gEntList); 103 | if (!ptr) 104 | SDKAPI_Warning("gEntList signature not found!\n"); 105 | else 106 | { 107 | #ifdef WIN32 108 | ptr = *(reinterpret_cast((char *)ptr + Offset_gEntList_windows)); 109 | #endif 110 | gEntList = reinterpret_cast(ptr); 111 | } 112 | } 113 | } 114 | 115 | void UnInitialize() 116 | { 117 | delete mu_server; 118 | delete mu_engine; 119 | DisconnectTier1Libraries(); 120 | DisconnectTier2Libraries(); 121 | } 122 | 123 | // 通过向实体 logic_script 发送实体输入执行 vscripts 脚本代码 124 | // 代码参考 Silver https://forums.alliedmods.net/showthread.php?p=2657025 125 | bool L4D2_RunScript(const char *_Format, ...) 126 | { 127 | // 处理 _Format 128 | static char buffer[8192]; 129 | va_list arg_list; 130 | va_start(arg_list, _Format); 131 | vsnprintf(buffer, sizeof(buffer), _Format, arg_list); 132 | va_end(arg_list); 133 | 134 | static variant_t var; 135 | // pScriptLogic 必须每次执行时查找 因为每局游戏它应该都会变 136 | CBaseEntity *pScriptLogic = gEntList->FindEntityByClassname(nullptr, "logic_script"); 137 | edict_t *edict = iServerGameEnts->BaseEntityToEdict(pScriptLogic); 138 | if (!edict || edict->IsFree()) 139 | { 140 | pScriptLogic = reinterpret_cast(iServerTools->CreateEntityByName("logic_script")); 141 | if (!pScriptLogic) 142 | return false; 143 | iServerTools->DispatchSpawn(pScriptLogic); 144 | } 145 | castable_string_t str(buffer); 146 | var.SetString(str); 147 | return reinterpret_cast(pScriptLogic)->AcceptInput("RunScriptCode", nullptr, nullptr, var, 0); 148 | } 149 | } // namespace SDKAPI -------------------------------------------------------------------------------- /plugin/sdkapi/sdkapi.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SDKAPI 3 | * Copyright (C) 2021 LinGe All rights reserved. 4 | * ============================================================================= 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License, version 3.0, as published by the 8 | * Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program. If not, see . 17 | */ 18 | #pragma once 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include "MemoryUtils/MemoryUtils.h" 26 | #include "signature.h" 27 | 28 | #ifdef _LINUX 29 | #define __thiscall 30 | #endif 31 | 32 | #define SDKAPI_Msg(format, ...) Msg("SDKAPI: " format, ## __VA_ARGS__) 33 | #define SDKAPI_Warning(format, ...) Warning("SDKAPI: " format, ## __VA_ARGS__) 34 | #define SDKAPI_Error(format, ...) Error("SDKAPI: " format, ## __VA_ARGS__) 35 | 36 | namespace SDKAPI { 37 | // 伪 SDK 类前置声明 38 | class FCGlobalEntityList; 39 | class FCBaseEntity; 40 | 41 | // SDK API 接口 42 | extern ICvar *iCvar; 43 | extern IPlayerInfoManager *iPlayerInfoManager; 44 | extern IServerGameEnts *iServerGameEnts; 45 | extern IVEngineServer *iVEngineServer; 46 | extern IServerTools *iServerTools; 47 | extern IServerGameDLL *iServerGameDLL; 48 | extern IServerPluginHelpers *iServerPluginHelpers; 49 | extern IGameEventManager2 *iGameEventManager; 50 | extern CGlobalVars *pGlobals; 51 | extern FCGlobalEntityList *gEntList; 52 | 53 | namespace ServerSigFunc { 54 | typedef CBaseEntity *(__thiscall *FINDENTITYBYCLASSNAME)(void *, CBaseEntity *, const char *); 55 | extern FINDENTITYBYCLASSNAME CBaseEntity_FindEntityByClassname; 56 | } 57 | 58 | // 全局函数 59 | void Initialize(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory); 60 | void UnInitialize(); 61 | 62 | // 通过向实体 logic_script 发送实体输入执行 vscripts 脚本代码 63 | bool L4D2_RunScript(const char *_Format, ...); 64 | 65 | inline int IndexOfEdict(const edict_t *pEdict) 66 | { 67 | return (int)(pEdict - pGlobals->pEdicts); 68 | } 69 | inline edict_t *PEntityOfEntIndex(int iEntIndex) 70 | { 71 | if (iEntIndex >= 0 && iEntIndex < pGlobals->maxEntities) 72 | { 73 | return (edict_t *)(pGlobals->pEdicts + iEntIndex); 74 | } 75 | return nullptr; 76 | } 77 | 78 | // 通过UserID获取到实体 79 | inline edict_t *GetEntityFromUserID(int userid) 80 | { 81 | for (int i=0; imaxEntities; i++) 82 | { 83 | edict_t *pEntity = PEntityOfEntIndex(i); 84 | if (iVEngineServer->GetPlayerUserId(pEntity) == userid) 85 | return pEntity; 86 | } 87 | return nullptr; 88 | } 89 | 90 | // 伪SDK类,用于方便调用一些函数 91 | class FCGlobalEntityList 92 | { 93 | public: 94 | inline CBaseEntity *FindEntityByClassname(CBaseEntity *pStartEntity, const char *szName) 95 | { 96 | if (ServerSigFunc::CBaseEntity_FindEntityByClassname) 97 | return ServerSigFunc::CBaseEntity_FindEntityByClassname(this, pStartEntity, szName); 98 | else 99 | { 100 | SDKAPI_Error("FindEntityByClassname function pointer is nullptr!"); 101 | return nullptr; 102 | } 103 | } 104 | }; 105 | 106 | class FCBaseEntity 107 | { 108 | public: 109 | typedef bool(__thiscall *ACCEPTINPUT)(void *, const char *, CBaseEntity *, CBaseEntity *, variant_t, int); 110 | 111 | public: 112 | inline bool AcceptInput(const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID=0) 113 | { 114 | return GetVirtualFunction(this, VTI_AcceptInput) 115 | (this, szInputName, pActivator, pCaller, Value, outputID); 116 | } 117 | }; 118 | } 119 | -------------------------------------------------------------------------------- /plugin/sdkapi/signature.h: -------------------------------------------------------------------------------- 1 | /** 2 | * SDKAPI 3 | * Copyright (C) 2021 LinGe All rights reserved. 4 | * ============================================================================= 5 | * 6 | * This program is free software; you can redistribute it and/or modify it under 7 | * the terms of the GNU General Public License, version 3.0, as published by the 8 | * Free Software Foundation. 9 | * 10 | * This program is distributed in the hope that it will be useful, but WITHOUT 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 13 | * details. 14 | * 15 | * You should have received a copy of the GNU General Public License along with 16 | * this program. If not, see . 17 | */ 18 | #pragma once 19 | #include "MemoryUtils/MemoryUtils.h" 20 | 21 | constexpr Signature Sig_gEntList = { 22 | "\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xB9\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\xE8", 23 | // 此 Windows 平台签名为 LevelShutdown 函数的签名,用于定位 pEntityList 24 | "@gEntList" 25 | }; 26 | #define Offset_gEntList_windows 11 // Offset into LevelShutdown 27 | 28 | // CGlobalEntityList::FindEntityByClassname 29 | constexpr Signature Sig_FindEntityByClassname = { 30 | "\x55\x8B\xEC\x53\x56\x8B\xF1\x8B\x4D\x08\x57\x85\xC9\x74\x2A\x8B\x01\x8B\x50\x08\xFF\xD2\x8B\x00\x25\xFF\x0F\x00\x00\x40\x03\xC0\x8B\x3C\xC6\xEB\x2A\x8B\x2A\x2A\x2A\x2A\x2A\x85\xFF\x74\x2A\x8B\x5D\x0C\x8B\x37\x85\xF6\x75\x2A\x68\x2A\x2A\x2A\x2A\xFF\x2A\x2A\x2A\x2A\x2A\x83\xC4\x04\xEB\x2A\x39", 31 | "@_ZN17CGlobalEntityList21FindEntityByClassnameEP11CBaseEntityPKc" 32 | }; 33 | 34 | // CBaseEntity::AcceptInput 虚函数表索引 35 | constexpr VTableIndex VTI_AcceptInput = { 44, 45 }; -------------------------------------------------------------------------------- /release/Base-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/Base-addonimage.jpg -------------------------------------------------------------------------------- /release/Base-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "LinGe VScripts 基础库" 5 | addonDescription "LinGe VScripts 脚本基础库" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /release/HUD-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/HUD-addonimage.jpg -------------------------------------------------------------------------------- /release/HUD-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "击杀与伤害统计、友伤提示、时间显示" 5 | addonDescription "必须同时安装 LinGe VScripts Base 基础库才可使用" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /release/Hint-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/Hint-addonimage.jpg -------------------------------------------------------------------------------- /release/Hint-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "玩家状态提示与物品标记提示" 5 | addonDescription "使用 bind g +alt1 绑定快捷键可以标记物品。非对抗类模式下可用。" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /release/LinGe_VScripts-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/LinGe_VScripts-addonimage.jpg -------------------------------------------------------------------------------- /release/LinGe_VScripts-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "LinGe VScripts 全功能" 5 | addonDescription "击杀统计、多特、玩家状态提示等等" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /release/MoreSI-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/MoreSI-addonimage.jpg -------------------------------------------------------------------------------- /release/MoreSI-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "多特控制:修改特感生成数量、种类与刷新时间" 5 | addonDescription "仅战役类模式下可用" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /release/RewardHP-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/RewardHP-addonimage.jpg -------------------------------------------------------------------------------- /release/RewardHP-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "击杀回血,可设置回复虚血或实血" 5 | addonDescription "仅战役类模式下可用" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /release/plugin.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | set main=..\plugin\ 3 | set output=plugin 4 | set _7z="D:\Program Files\7-Zip\7z.exe" 5 | set linux_user=arch 6 | 7 | rd /s /q %output% 8 | mkdir %output%\addons\LinGe_VScripts 9 | 10 | :: 复制插件文件 11 | copy %main%\LinGe_VScripts.vdf %output%\addons\LinGe_VScripts.vdf 12 | copy %main%\%USER%-build\Release\LinGe_VScripts.dll %output%\addons\LinGe_VScripts\LinGe_VScripts.dll 13 | copy %main%\%linux_user%-build\Release\LinGe_VScripts.so %output%\addons\LinGe_VScripts\LinGe_VScripts.so 14 | 15 | :: 打包 zip 16 | cd %output% 17 | %_7z% a -tzip LinGe_VScripts.zip addons 18 | 19 | pause -------------------------------------------------------------------------------- /release/vpk.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk.bat -------------------------------------------------------------------------------- /release/vpk/LinGe VScripts 整合.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/LinGe VScripts 整合.vpk -------------------------------------------------------------------------------- /release/vpk/击杀回血 RewardHP.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/击杀回血 RewardHP.vpk -------------------------------------------------------------------------------- /release/vpk/基础库 Base.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/基础库 Base.vpk -------------------------------------------------------------------------------- /release/vpk/多特控制 MoreSI.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/多特控制 MoreSI.vpk -------------------------------------------------------------------------------- /release/vpk/排行榜、伤害统计 HUD.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/排行榜、伤害统计 HUD.vpk -------------------------------------------------------------------------------- /release/vpk/标记物资、队友倒地被控提示 Hint.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/标记物资、队友倒地被控提示 Hint.vpk -------------------------------------------------------------------------------- /release/vpk/自杀指令 zs.vpk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/vpk/自杀指令 zs.vpk -------------------------------------------------------------------------------- /release/zs-addonimage.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin515/L4D2_LinGe_VScripts/1418258fe2e366fe6fadc8183877dc1b49079865/release/zs-addonimage.jpg -------------------------------------------------------------------------------- /release/zs-addoninfo.txt: -------------------------------------------------------------------------------- 1 | "AddonInfo" 2 | { 3 | addonSteamAppID 550 4 | addontitle "自杀指令 !zs" 5 | addonDescription "仅战役类模式下可用" 6 | addonauthor "LinGe" 7 | addonURL0 "https://github.com/Lin515/L4D2_LinGe_VScripts" 8 | 9 | addonContent_Script 1 10 | } -------------------------------------------------------------------------------- /vscripts/LinGe/Base.nut: -------------------------------------------------------------------------------- 1 | // By LinGe https://github.com/Lin515/L4D2_LinGe_VScripts 2 | // 本系列脚本编写主要参考以下文档 3 | // L4D2脚本函数清单:https://developer.valvesoftware.com/wiki/L4D2%E8%84%9A%E6%9C%AC%E5%87%BD%E6%95%B0%E6%B8%85%E5%8D%95 4 | // L4D2 EMS/Appendix:HUD:https://developer.valvesoftware.com/wiki/L4D2_EMS/Appendix:_HUD 5 | // L4D2 Events:https://wiki.alliedmods.net/Left_4_Dead_2_Events 6 | // 以及VSLib与admin_system的脚本源码 7 | printl("[LinGe] Base 正在载入"); 8 | ::LinGe <- {}; 9 | ::LinGe.Debug <- false; 10 | 11 | ::LinGe.hostport <- Convars.GetFloat("hostport").tointeger(); 12 | printl("[LinGe] 当前服务器端口 " + ::LinGe.hostport); 13 | 14 | // 地图结束后销毁本脚本 15 | local Last_OnShutdown = g_MapScript.ScriptMode_OnShutdown.bindenv(g_MapScript); 16 | g_MapScript.ScriptMode_OnShutdown <- function (reason, nextmap) 17 | { 18 | delete ::LinGe; 19 | Last_OnShutdown(reason, nextmap); 20 | 21 | printl("[LinGe] 回合结束,脚本已卸载"); 22 | } 23 | 24 | // ---------------------------全局函数START------------------------------------------- 25 | // 主要用于调试 26 | ::LinGe.DebugPrintl <- function (str) 27 | { 28 | if (::LinGe.Debug) 29 | printl(str); 30 | } 31 | 32 | ::LinGe.DebugPrintlTable <- function (table) 33 | { 34 | if (!::LinGe.Debug) 35 | return; 36 | if (typeof table != "table" && typeof table != "array") 37 | return; 38 | foreach (key, val in table) 39 | print(key + "=" + val + " ; "); 40 | print("\n"); 41 | } 42 | 43 | // 递归深度克隆(只会对table或array的子项进行克隆) 44 | ::LinGe.DeepClone <- function (obj) 45 | { 46 | if (typeof obj == "table") 47 | { 48 | local table = clone obj; 49 | foreach (key, val in table) 50 | table[key] = DeepClone(val); 51 | return table; 52 | } 53 | if (typeof obj == "array") 54 | { 55 | local array = clone obj; 56 | foreach (index, val in array) 57 | array[index] = DeepClone(val); 58 | return array; 59 | } 60 | return obj; 61 | } 62 | 63 | // 尝试将一个字符串转换为int类型 eValue为出现异常时返回的值 64 | ::LinGe.TryStringToInt <- function (value, eValue=0) 65 | { 66 | local ret = eValue; 67 | try 68 | { 69 | ret = value.tointeger(); 70 | } 71 | catch (e) 72 | { 73 | ret = eValue; 74 | } 75 | return ret; 76 | } 77 | // 尝试将一个字符串转换为float类型 eValue为出现异常时返回的值 78 | ::LinGe.TryStringToFloat <- function (value, eValue=0.0) 79 | { 80 | local ret = eValue; 81 | try 82 | { 83 | ret = value.tofloat(); 84 | } 85 | catch (e) 86 | { 87 | ret = eValue; 88 | } 89 | return ret; 90 | } 91 | 92 | // 查找并移除找到的第一个元素 返回其索引,若未找到则返回null 93 | ::LinGe.RemoveInArray <- function (value, array) 94 | { 95 | local idx = array.find(value); 96 | if (null != idx) 97 | array.remove(idx); 98 | return idx; 99 | } 100 | 101 | // 当前模式是否是对抗模式 102 | ::LinGe.CheckVersus <- function () 103 | { 104 | if (Director.GetGameMode() == "mutation15") // 生还者对抗 105 | return true; 106 | if ("versus" == g_BaseMode) 107 | return true; 108 | if ("scavenge" == g_BaseMode) 109 | return true; 110 | return false; 111 | } 112 | ::LinGe.isVersus <- ::LinGe.CheckVersus(); 113 | 114 | // 设置某类下所有已生成实体的KeyValue 115 | ::LinGe.SetKeyValueByClassname <- function (className, key, value) 116 | { 117 | local entity = null; 118 | local func = null; 119 | 120 | switch (typeof value) 121 | { 122 | case "integer": 123 | func = @(entity, key, value) entity.__KeyValueFromInt(key, value); 124 | break; 125 | case "float": 126 | func = @(entity, key, value) entity.__KeyValueFromFloat(key, value); 127 | break; 128 | case "string": 129 | func = @(entity, key, value) entity.__KeyValueFromString(key, value); 130 | break; 131 | case "Vector": 132 | func = @(entity, key, value) entity.__KeyValueFromVector(key, value); 133 | break; 134 | default: 135 | throw "参数类型非法"; 136 | } 137 | 138 | local count = 0; 139 | while ( (entity = Entities.FindByClassname(entity, className)) != null) 140 | { 141 | func(entity, key, value); 142 | count++; 143 | } 144 | return count; 145 | } 146 | 147 | ::LinGe.SteamIDCastUniqueID <- function (steamid) 148 | { 149 | local uniqueID = ::VSLib.Utils.StringReplace(steamid, "STEAM_1:", "S"); 150 | uniqueID = ::VSLib.Utils.StringReplace(uniqueID, "STEAM_0:", "S"); 151 | uniqueID = ::VSLib.Utils.StringReplace(uniqueID, ":", ""); 152 | return uniqueID; 153 | } 154 | 155 | // 获取 targetname,并确保它在本脚本系统中独一无二 156 | ::LinGe.GetEntityTargetname <- function (entity) 157 | { 158 | local targetname = entity.GetName(); 159 | if (targetname.find("LinGe_") != 0) 160 | { 161 | targetname = "LinGe_" + UniqueString(); 162 | entity.__KeyValueFromString("targetname", targetname); 163 | } 164 | return targetname; 165 | } 166 | 167 | // 通过userid获得玩家实体索引 168 | ::LinGe.GetEntityIndexFromUserID <- function (userid) 169 | { 170 | local entity = GetPlayerFromUserID(userid); 171 | if (null == entity) 172 | return null; 173 | else 174 | return entity.GetEntityIndex(); 175 | } 176 | 177 | // 通过userid获得steamid 178 | ::LinGe.GetSteamIDFromUserID <- function (userid) 179 | { 180 | local entity = GetPlayerFromUserID(userid); 181 | if (null == entity) 182 | return null; 183 | else 184 | return entity.GetNetworkIDString(); 185 | } 186 | 187 | // 该userid是否为BOT所有 188 | ::LinGe.IsBotUserID <- function (userid) 189 | { 190 | local entity = GetPlayerFromUserID(userid); 191 | if (null == entity) 192 | return true; 193 | else 194 | return "BOT"==entity.GetNetworkIDString(); 195 | } 196 | 197 | ::LinGe.GetReviveCount <- function (player) 198 | { 199 | return NetProps.GetPropInt(player, "m_currentReviveCount"); 200 | } 201 | 202 | // 从网络属性判断一个实体是否存活 203 | ::LinGe.IsAlive <- function (ent) 204 | { 205 | return NetProps.GetPropInt(ent, "m_lifeState") == 0; 206 | } 207 | 208 | // 从bot生还者中获取其就位的生还者玩家实体 209 | // 须自己先检查是否是有效生还者bot 否则可能出错 210 | ::LinGe.GetHumanPlayer <- function (bot) 211 | { 212 | if (::LinGe.IsAlive(bot)) 213 | { 214 | local human = GetPlayerFromUserID(NetProps.GetPropInt(bot, "m_humanSpectatorUserID")); 215 | if (null != human) 216 | { 217 | if (human.IsValid()) 218 | { 219 | if ( "BOT" != human.GetNetworkIDString() 220 | && 1 == ::LinGe.GetPlayerTeam(human) ) 221 | return human; 222 | } 223 | } 224 | } 225 | return null; 226 | } 227 | 228 | // 判断玩家是否处于闲置 参数可以是玩家实体也可以是实体索引 229 | ::LinGe.IsPlayerIdle <- function (player) 230 | { 231 | local entityIndex = 0; 232 | local _player = null; 233 | // 通过类名查找玩家 234 | if ("integer" == typeof player) 235 | { 236 | entityIndex = player; 237 | _player = PlayerInstanceFromIndex(entityIndex); 238 | } 239 | else if ("instance" == typeof player) 240 | { 241 | entityIndex = player.GetEntityIndex(); 242 | _player = player; 243 | } 244 | else 245 | throw "参数类型非法"; 246 | if (!_player.IsValid()) 247 | return false; 248 | if (1 != ::LinGe.GetPlayerTeam(_player)) 249 | return false; 250 | 251 | local bot = null; 252 | while ( bot = Entities.FindByClassname(bot, "player") ) 253 | { 254 | // 判断搜索到的实体有效性 255 | if ( bot.IsValid() ) 256 | { 257 | // 判断阵营 258 | if ( bot.IsSurvivor() 259 | && "BOT" == bot.GetNetworkIDString() 260 | && ::LinGe.IsAlive(bot) ) 261 | { 262 | local human = ::LinGe.GetHumanPlayer(bot); 263 | if (human != null) 264 | { 265 | if (human.GetEntityIndex() == entityIndex) 266 | return true; 267 | } 268 | } 269 | } 270 | } 271 | return false; 272 | } 273 | 274 | // 获取所有处于闲置的玩家 275 | ::LinGe.GetIdlePlayers <- function () 276 | { 277 | local bot = null; 278 | local players = []; 279 | while ( bot = Entities.FindByClassname(bot, "player") ) 280 | { 281 | if ( bot.IsValid() ) 282 | { 283 | if ( bot.IsSurvivor() 284 | && "BOT" == bot.GetNetworkIDString() 285 | && ::LinGe.IsAlive(bot) ) 286 | { 287 | local human = ::LinGe.GetHumanPlayer(bot); 288 | if (human != null) 289 | { 290 | players.push(human); 291 | } 292 | } 293 | } 294 | } 295 | return players; 296 | } 297 | 298 | ::LinGe.GetIdlePlayerCount <- function () 299 | { 300 | local bot = null; 301 | local count = 0; 302 | while ( bot = Entities.FindByClassname(bot, "player") ) 303 | { 304 | if ( bot.IsValid() ) 305 | { 306 | if ( bot.IsSurvivor() 307 | && "BOT" == bot.GetNetworkIDString() 308 | && ::LinGe.IsAlive(bot) ) 309 | { 310 | local human = ::LinGe.GetHumanPlayer(bot); 311 | if (human != null) 312 | { 313 | count++; 314 | } 315 | } 316 | } 317 | } 318 | return count; 319 | } 320 | 321 | ::LinGe.GetMaxHealth <- function (entity) 322 | { 323 | return NetProps.GetPropInt(victim, "m_iMaxHealth"); 324 | } 325 | 326 | ::LinGe.GetPlayerTeam <- function (player) 327 | { 328 | return NetProps.GetPropInt(player, "m_iTeamNum"); 329 | } 330 | 331 | // 将 Vector 转换为 QAngle 332 | // hl2sdk-l4d2/mathlib/mathlib_base.cpp > line:506 333 | ::LinGe.QAngleFromVector <- function (forward) 334 | { 335 | local tmp, yaw, pitch; 336 | 337 | if (forward.y == 0 && forward.x == 0) 338 | { 339 | yaw = 0; 340 | if (forward.z > 0) 341 | pitch = 270; 342 | else 343 | pitch = 90; 344 | } 345 | else 346 | { 347 | yaw = (atan2(forward.y, forward.x) * 180 / PI); 348 | if (yaw < 0) 349 | yaw += 360; 350 | 351 | tmp = sqrt(forward.x*forward.x + forward.y*forward.y); 352 | pitch = (atan2(-forward.z, tmp) * 180 / PI); 353 | if (pitch < 0) 354 | pitch += 360; 355 | } 356 | return QAngle(pitch, yaw, 0.0); 357 | } 358 | 359 | // 玩家是否看着实体的位置或指定位置 360 | // VSLib/player.nut > line:1381 function VSLib::Player::CanSeeLocation 361 | ::LinGe.IsPlayerSeeHere <- function (player, location, tolerance = 50) 362 | { 363 | local _location = null; 364 | if (typeof location == "instance") 365 | _location = location.GetOrigin(); 366 | else if (typeof location == "Vector") 367 | _location = location; 368 | else 369 | throw "location 参数类型非法"; 370 | 371 | local clientPos = player.EyePosition(); 372 | local clientToTargetVec = _location - clientPos; 373 | local clientAimVector = player.EyeAngles().Forward(); 374 | 375 | local angToFind = acos( 376 | ::VSLib.Utils.VectorDotProduct(clientAimVector, clientToTargetVec) 377 | / (clientAimVector.Length() * clientToTargetVec.Length()) 378 | ) * 360 / 2 / 3.14159265; 379 | 380 | if (angToFind < tolerance) 381 | return true; 382 | else 383 | return false; 384 | } 385 | 386 | ::LinGe.TraceToLocation <- function (origin, location, mask=MASK_SHOT_HULL & (~CONTENTS_WINDOW), ignore=null) 387 | { 388 | // 获取出发点 389 | local start = null; 390 | if (typeof origin == "instance") 391 | { 392 | if ("EyePosition" in origin) 393 | start = origin.EyePosition(); // 如果对象是有眼睛的则获取眼睛位置 394 | else 395 | start = origin.GetOrigin(); 396 | } 397 | else if (typeof origin == "Vector") 398 | start = origin; 399 | else 400 | throw "origin 参数类型非法"; 401 | 402 | // 获取终点 403 | local end = null; 404 | if (typeof location == "instance") 405 | { 406 | if ("EyePosition" in location) 407 | end = location.EyePosition(); 408 | else 409 | end = location.GetOrigin(); 410 | } 411 | else if (typeof location == "Vector") 412 | end = location; 413 | else 414 | throw "location 参数类型非法"; 415 | 416 | local tr = { 417 | start = start, 418 | end = end, 419 | ignore = (ignore ? ignore : (typeof origin == "instance" ? origin : null) ), 420 | mask = mask, 421 | }; 422 | TraceLine(tr); 423 | return tr; 424 | } 425 | 426 | // player 是否注意着 entity 427 | ::LinGe.IsPlayerNoticeEntity <- function (player, entity, tolerance = 50, mask=MASK_SHOT_HULL & (~CONTENTS_WINDOW), radius=0.0) 428 | { 429 | if (!IsPlayerSeeHere(player, entity, tolerance)) 430 | return false; 431 | local tr = TraceToLocation(player, entity, mask); 432 | if (tr.rawin("enthit") && tr.enthit == entity) 433 | return true; 434 | if (radius <= 0.0) 435 | return false; 436 | // 如果不能看到指定实体,但指定了半径范围,则进行搜索 437 | local _entity = null, className = entity.GetClassname(); 438 | while ( _entity = Entities.FindByClassnameWithin(_entity, className, tr.pos, radius) ) 439 | { 440 | if (_entity == entity) 441 | return true; 442 | } 443 | return false; 444 | } 445 | 446 | // 链式射线追踪,当命中到类型为 ignoreClass 中的实体时,从其位置往前继续射线追踪 447 | // ignoreClass 中可以有 entity 的类型,判断时总会先判断定位到的是否是 entity 448 | // 如果最终能命中 entity,则返回 true 449 | ::LinGe.ChainTraceToEntity <- function (origin, entity, mask, ignoreClass, limit=4) 450 | { 451 | local tr = { 452 | start = null, 453 | end = null, 454 | ignore = null, 455 | mask = mask, 456 | }; 457 | 458 | // 获取起始点 459 | if (typeof origin == "instance") 460 | { 461 | if ("EyePosition" in origin) 462 | tr.start = origin.EyePosition(); 463 | else 464 | tr.start = origin.GetOrigin(); 465 | tr.ignore = origin; 466 | } 467 | else if (typeof origin == "Vector") 468 | tr.start = origin; 469 | else 470 | throw "origin 参数类型非法"; 471 | 472 | if ("EyePosition" in entity) 473 | tr.end = entity.EyePosition(); 474 | else 475 | tr.end = entity.GetOrigin(); 476 | if (limit < 1) 477 | limit = 4; // 不允许无限制的链式探测 478 | local start = tr.start; // 保留最初的起点 479 | 480 | local count = 0; 481 | while (true) 482 | { 483 | count++; 484 | TraceLine(tr); 485 | if (!tr.rawin("enthit")) 486 | break; 487 | if (tr.enthit == entity) 488 | return true; 489 | if (count >= limit) 490 | break; 491 | // 如果命中位置已经比目标位置要更远离起始点,则终止 492 | if ((tr.pos-start).Length() > (tr.end-start).Length()) 493 | break; 494 | if (ignoreClass.find(tr.enthit.GetClassname()) == null) 495 | break; 496 | tr.start = tr.pos; 497 | tr.ignore = tr.enthit; 498 | } 499 | return false; 500 | } 501 | 502 | // 获取玩家实体数组 503 | // team 指定要获取的队伍 可以是数组或数字 若为null则忽略队伍 504 | // humanOrBot 机器人 0:忽略是否是机器人 1:只获取玩家 2:只获取BOT 505 | // aliveOrDead 存活 0:忽略是否存货 1:只获取存活的 2:只获取死亡的 506 | ::LinGe.GetPlayers <- function (team=null, humanOrBot=0, aliveOrDead=0) 507 | { 508 | local arr = []; 509 | // 通过类名查找玩家 510 | local player = null; 511 | while ( player = Entities.FindByClassname(player, "player") ) 512 | { 513 | // 判断搜索到的实体有效性 514 | if ( player.IsValid() ) 515 | { 516 | // 判断阵营 517 | if (typeof team == "array") 518 | { 519 | if (team.find(::LinGe.GetPlayerTeam(player))==null) 520 | continue; 521 | } 522 | else if (typeof team == "integer" && team != ::LinGe.GetPlayerTeam(player)) 523 | continue; 524 | if (humanOrBot == 1) 525 | { 526 | if ("BOT" == player.GetNetworkIDString()) 527 | continue; 528 | } 529 | else if (humanOrBot == 2 && "BOT" != player.GetNetworkIDString()) 530 | continue; 531 | if (aliveOrDead == 1) 532 | { 533 | if (!::LinGe.IsAlive(player)) 534 | continue; 535 | } 536 | else if (aliveOrDead == 2 && ::LinGe.IsAlive(player)) 537 | continue; 538 | arr.append(player); 539 | } 540 | } 541 | return arr; 542 | } 543 | ::LinGe.GetPlayerCount <- function (team=null, humanOrBot=0, aliveOrDead=0) 544 | { 545 | local count = 0; 546 | // 通过类名查找玩家 547 | local player = null; 548 | while ( player = Entities.FindByClassname(player, "player") ) 549 | { 550 | // 判断搜索到的实体有效性 551 | if ( player.IsValid() ) 552 | { 553 | // 判断阵营 554 | if (typeof team == "array") 555 | { 556 | if (team.find(::LinGe.GetPlayerTeam(player))==null) 557 | continue; 558 | } 559 | else if (typeof team == "integer" && team != ::LinGe.GetPlayerTeam(player)) 560 | continue; 561 | if (humanOrBot == 1) 562 | { 563 | if ("BOT" == player.GetNetworkIDString()) 564 | continue; 565 | } 566 | else if (humanOrBot == 2 && "BOT" != player.GetNetworkIDString()) 567 | continue; 568 | if (aliveOrDead == 1) 569 | { 570 | if (!::LinGe.IsAlive(player)) 571 | continue; 572 | } 573 | else if (aliveOrDead == 2 && ::LinGe.IsAlive(player)) 574 | continue; 575 | count++; 576 | } 577 | } 578 | return count; 579 | } 580 | 581 | // 如果source中某个key在dest中也存在,则将其赋值给dest中的key 582 | // 如果 reserveKey 为 true,则dest中没用该key也会被赋值 583 | // key无视大小写 584 | ::LinGe.Merge <- function (dest, source, typeMatch=true, reserveKey=false) 585 | { 586 | if ("table" == typeof dest && "table" == typeof source) 587 | { 588 | foreach (key, val in source) 589 | { 590 | local keyIsExist = true; 591 | if (!dest.rawin(key)) 592 | { 593 | // 为什么有些保存到 Cache 会产生大小写转换?? 594 | // HUD.Config.hurt 保存到 Cache 恢复后,hurt 居然变成了 Hurt 595 | foreach (_key, _val in dest) 596 | { 597 | if (_key.tolower() == key.tolower()) 598 | { 599 | source[_key] <- source[key]; 600 | key = _key; 601 | break; 602 | } 603 | } 604 | if (!dest.rawin(key)) 605 | keyIsExist = false; 606 | } 607 | if (!keyIsExist) 608 | { 609 | if (reserveKey) 610 | dest.rawset(key, val); 611 | continue; 612 | } 613 | local type_dest = typeof dest[key]; 614 | local type_src = typeof val; 615 | // 如果指定key也是table,则进行递归 616 | if ("table" == type_dest && "table" == type_src) 617 | ::LinGe.Merge(dest[key], val, typeMatch, reserveKey); 618 | else if (type_dest != type_src) 619 | { 620 | if (!typeMatch) 621 | dest[key] = val; 622 | else if (type_dest == "bool" && type_src == "integer") // 争对某些情况下 bool 被转换成了 integer 623 | dest[key] = (val!=0); 624 | else if (type_dest == "array" && type_src == "table") // 争对某些情况下 array 被转换成了 table 原数组的顺序可能会错乱 625 | { 626 | dest[key].clear(); 627 | foreach (_val in val) 628 | dest[key].append(_val); 629 | } 630 | } 631 | else 632 | dest[key] = val; 633 | } 634 | } 635 | } 636 | // ---------------------------全局函数END------------------------------------------- 637 | 638 | // -------------------------------VSLib 改写------------------------------------------------- 639 | // 判断玩家是否为BOT时通过steamid进行判断 640 | function VSLib::Entity::IsBot() 641 | { 642 | if (!IsEntityValid()) 643 | { 644 | printl("VSLib Warning: Entity " + _idx + " is invalid."); 645 | return false; 646 | } 647 | if (IsPlayer()) 648 | return "BOT" == GetSteamID(); 649 | else 650 | return IsPlayerABot(_ent); 651 | } 652 | 653 | // 改良原函数,使其输出的文件带有缩进 654 | function VSLib::FileIO::SerializeTable(object, predicateStart = "{\n", predicateEnd = "}\n", indice = true, indent=1) 655 | { 656 | local indstr = ""; 657 | for (local i=0; i= 0) 899 | trigger[event].callback.remove(idx); 900 | return idx; 901 | }.bindenv(::LinGe.Events); 902 | 903 | // 查找函数在指定事件的函数表的索引 904 | // 事件未注册返回-1 未找到函数返回-2 905 | ::LinGe.Events.EventIndex <- function (event, func, callOf=null, reverse=true) 906 | { 907 | if (trigger.rawin(event)) 908 | { 909 | local callback = trigger[event].callback; 910 | local len = callback.len(); 911 | local i = 0; 912 | if (reverse) 913 | { 914 | for (i=len-1; i>-1; i--) 915 | { 916 | if (func == callback[i].func 917 | && callOf == callback[i].callOf ) 918 | break; 919 | } 920 | } 921 | else 922 | { 923 | for (i=0; i 0.0) 944 | ::VSLib.Timers.AddTimer(delay, false, 945 | @(params) ::LinGe.Events.trigger[event][event](params), params); 946 | else 947 | trigger[event][event](params); 948 | } 949 | }.bindenv(::LinGe.Events); 950 | 951 | ::LinEventHook <- ::LinGe.Events.EventHook.weakref(); 952 | ::LinEventUnHook <- ::LinGe.Events.EventUnHook.weakref(); 953 | ::LinEventIndex <- ::LinGe.Events.EventIndex.weakref(); 954 | ::LinEventTrigger <- ::LinGe.Events.EventTrigger.weakref(); 955 | 956 | // 只有具有FCVAR_NOTIFY flags的变量才会触发该事件 957 | //::LinGe.Events.OnGameEvent_server_cvar <- function (params) 958 | //{ 959 | // EventTrigger("cvar_" + params.cvarname, params); 960 | //} 961 | //::LinEventHook("OnGameEvent_server_cvar", ::LinGe.Events.OnGameEvent_server_cvar, ::LinGe.Events); 962 | // --------------------------事件回调函数注册END---------------------------------------- 963 | 964 | // ------------------------------Admin---START-------------------------------------- 965 | ::LinGe.Admin <- {}; 966 | ::LinGe.Admin.Config <- { 967 | enabled = false, 968 | takeOverAdminSystem = false, // 是否接管adminsystem的权限判断 969 | adminsFile = "linge/admins_simple.ini" 970 | }; 971 | ::LinGe.Config.Add("Admin", ::LinGe.Admin.Config); 972 | 973 | ::LinGe.Admin.cmdTable <- {}; // 指令表 974 | // 读取管理员列表,若文件不存在则创建 975 | ::LinGe.Admin.adminslist <- FileToString(::LinGe.Admin.Config.adminsFile); 976 | if (null == ::LinGe.Admin.adminslist) 977 | { 978 | ::LinGe.Admin.adminslist = "STEAM_1:0:64877973 // Homura Chan"; 979 | StringToFile(::LinGe.Admin.Config.adminsFile, ::LinGe.Admin.adminslist); 980 | ::LinGe.Admin.adminslist = FileToString(::LinGe.Admin.Config.adminsFile); 981 | if (null == ::LinGe.Admin.adminslist) 982 | printl("[LinGe] " + adminsFile + " 文件读取失败,无法获取管理员列表"); 983 | } 984 | 985 | /* 添加指令 若同名指令会覆盖旧指令 986 | string 指令名 987 | func 指令回调函数 988 | callOf 回调函数执行所在的表 989 | isAdminCmd 是否是管理员指令 990 | */ 991 | ::LinGe.Admin.CmdAdd <- function (command, func, callOf=null, remarks="", isAdminCmd=true, ignoreCase=true) 992 | { 993 | local _callOf = (callOf==null) ? null : callOf.weakref(); 994 | local table = { func=func.weakref(), callOf=_callOf, remarks=remarks, isAdminCmd=isAdminCmd, ignoreCase=ignoreCase }; 995 | cmdTable.rawset(command.tolower(), table); 996 | }.bindenv(::LinGe.Admin); 997 | 998 | // 删除指令 成功删除返回其值 否则返回null 999 | ::LinGe.Admin.CmdDelete <- function (command) 1000 | { 1001 | return cmdTable.rawdelete(command.tolower()); 1002 | }.bindenv(::LinGe.Admin); 1003 | ::LinCmdAdd <- ::LinGe.Admin.CmdAdd.weakref(); 1004 | ::LinCmdDelete <- ::LinGe.Admin.CmdDelete.weakref(); 1005 | 1006 | // 消息指令触发 通过 player_say 1007 | ::LinGe.Admin.OnGameEvent_player_say <- function (params) 1008 | { 1009 | local args = split(params.text, " "); 1010 | local cmd = args[0]; 1011 | if (cmd.len() < 2) 1012 | return; 1013 | local player = GetPlayerFromUserID(params.userid); 1014 | if (null == player || !player.IsValid()) 1015 | return; 1016 | local firstChar = cmd.slice(0, 1); // 取第一个字符 1017 | // 判断前缀有效性 1018 | if (firstChar != "!" 1019 | && firstChar != "/" 1020 | && firstChar != "." ) 1021 | return; 1022 | 1023 | local text = params.text.slice(1); 1024 | args = split(text, " "); 1025 | cmd = args[0].tolower(); // 设置 args 第一个元素为指令名 1026 | if (cmdTable.rawin(cmd)) 1027 | { 1028 | if (cmdTable[cmd].ignoreCase) 1029 | CmdExec(cmd, player, split(text.tolower(), " ")); 1030 | else 1031 | CmdExec(cmd, player, args); 1032 | } 1033 | } 1034 | ::LinEventHook("OnGameEvent_player_say", ::LinGe.Admin.OnGameEvent_player_say, ::LinGe.Admin); 1035 | 1036 | // scripted_user_func 指令触发 1037 | ::LinGe.Admin.OnUserCommand <- function (vplayer, args, text) 1038 | { 1039 | local _args = split(text, ","); 1040 | local cmdstr = _args[0].tolower(); 1041 | local cmdTable = ::LinGe.Admin.cmdTable; 1042 | if (cmdTable.rawin(cmdstr)) 1043 | { 1044 | if (cmdTable[cmdstr].ignoreCase) 1045 | ::LinGe.Admin.CmdExec(cmdstr, vplayer._ent, split(text.tolower(), ",")); 1046 | else 1047 | ::LinGe.Admin.CmdExec(cmdstr, vplayer._ent, _args); 1048 | } 1049 | } 1050 | ::EasyLogic.OnUserCommand.LinGeCommands <- ::LinGe.Admin.OnUserCommand.weakref(); 1051 | 1052 | // 指令调用执行 1053 | ::LinGe.Admin.CmdExec <- function (command, player, args) 1054 | { 1055 | local cmd = cmdTable[command]; 1056 | if (cmd.isAdminCmd && !IsAdmin(player)) 1057 | { // 如果是管理员指令而用户身份不是管理员,则发送权限不足提示 1058 | ClientPrint(player, 3, "\x04此条指令仅管理员可用!"); 1059 | return; 1060 | } 1061 | 1062 | if (cmd.callOf != null) 1063 | cmd.func.call(cmd.callOf, player, args); 1064 | else 1065 | cmd.func(player, args); 1066 | } 1067 | 1068 | // 判断该玩家是否是管理员 1069 | ::LinGe.Admin.IsAdmin <- function (player) 1070 | { 1071 | // 未启用权限管理则所有人视作管理员 1072 | if (!Config.enabled) 1073 | return true; 1074 | // 如果是单人游戏则直接返回true 1075 | if (Director.IsSinglePlayerGame()) 1076 | return true; 1077 | // 获取steam id 1078 | local steamID = null; 1079 | local vplayer = player; 1080 | if (typeof vplayer != "VSLIB_PLAYER") 1081 | vplayer = ::VSLib.Player(player); 1082 | if ( vplayer.IsServerHost() ) 1083 | return true; 1084 | steamID = vplayer.GetSteamID(); 1085 | if (null == steamID) 1086 | return false; 1087 | 1088 | // 通过steamID判断是否是管理员 1089 | if (null != adminslist) 1090 | { 1091 | if (null == adminslist.find(steamID)) 1092 | return false; 1093 | else 1094 | return true; 1095 | } 1096 | else 1097 | return false; 1098 | }.bindenv(::LinGe.Admin); 1099 | 1100 | // 事件:回合开始 如果启用了AdminSystem则覆盖其管理员判断指令 1101 | ::LinGe.Admin.OnGameEvent_round_start <- function (params) 1102 | { 1103 | if ("AdminSystem" in getroottable() && Config.takeOverAdminSystem) 1104 | { 1105 | ::AdminSystem.IsAdmin = ::LinGe.Admin.IsAdmin; 1106 | ::AdminSystem.IsPrivileged = ::LinGe.Admin.IsAdmin; 1107 | } 1108 | } 1109 | ::LinEventHook("OnGameEvent_round_start", ::LinGe.Admin.OnGameEvent_round_start, ::LinGe.Admin); 1110 | 1111 | ::LinGe.Admin.Cmd_setvalue <- function (player, args) 1112 | { 1113 | if (args.len() == 3) 1114 | Convars.SetValue(args[1], args[2]); 1115 | } 1116 | ::LinCmdAdd("setvalue", ::LinGe.Admin.Cmd_setvalue, ::LinGe.Admin); 1117 | 1118 | ::LinGe.Admin.Cmd_getvalue <- function (player, args) 1119 | { 1120 | if (args.len() == 2) 1121 | ClientPrint(player, 3, Convars.GetStr(args[1])); 1122 | } 1123 | ::LinCmdAdd("getvalue", ::LinGe.Admin.Cmd_getvalue, ::LinGe.Admin); 1124 | 1125 | ::LinGe.Admin.Cmd_saveconfig <- function (player, args) 1126 | { 1127 | if (args.len() == 1) 1128 | { 1129 | ::LinGe.Config.SaveAll(); 1130 | ClientPrint(player, 3, "\x04已保存当前功能设定为默认设定\n"); 1131 | ClientPrint(player, 3, "\x04配置文件: \x05 left4dead2/ems/" + FILE_CONFIG + ".tbl"); 1132 | } 1133 | else if (args.len() == 2) 1134 | { 1135 | foreach (name, tbl in ::LinGe.Config.table) 1136 | { 1137 | if (name.tolower() == args[1]) 1138 | { 1139 | ::LinGe.Config.Save(name); 1140 | ClientPrint(player, 3, "\x04已保存当前功能设定为默认设定: \x05" + name); 1141 | ClientPrint(player, 3, "\x04配置文件: \x05 left4dead2/ems/" + FILE_CONFIG + ".tbl"); 1142 | return; 1143 | } 1144 | } 1145 | ClientPrint(player, 3, "\x04未找到 \x05" + args[1]); 1146 | } 1147 | } 1148 | ::LinCmdAdd("saveconfig", ::LinGe.Admin.Cmd_saveconfig, ::LinGe.Admin); 1149 | ::LinCmdAdd("save", ::LinGe.Admin.Cmd_saveconfig, ::LinGe.Admin, "保存配置到配置文件"); 1150 | 1151 | ::LinGe.Admin.Cmd_lshelp <- function (player, args) 1152 | { 1153 | foreach (key, val in cmdTable) 1154 | { 1155 | if (val.remarks != "") 1156 | ClientPrint(player, 3, format("\x05!%s \x03%s", key, val.remarks)); 1157 | } 1158 | } 1159 | ::LinCmdAdd("lshelp", ::LinGe.Admin.Cmd_lshelp, ::LinGe.Admin, "", false); 1160 | 1161 | ::LinGe.Admin.Cmd_config <- function (player, args) 1162 | { 1163 | if (args.len() == 2) 1164 | { 1165 | local func = compilestring("return ::LinGe.Config.table." + args[1]); 1166 | try { 1167 | ClientPrint(player, 3, "\x04" + args[1] + " = \x05" + func()); 1168 | } catch (e) { 1169 | ClientPrint(player, 3, "\x04读取配置失败: \x05" + args[1]); 1170 | } 1171 | } 1172 | else if (args.len() >= 3) 1173 | { 1174 | try { 1175 | local type = compilestring("return typeof ::LinGe.Config.table." + args[1])(); 1176 | switch (type) 1177 | { 1178 | case "bool": 1179 | case "integer": 1180 | case "float": 1181 | compilestring("::LinGe.Config.table." + args[1] + " = " + args[2])(); 1182 | break; 1183 | case "string": 1184 | { 1185 | local str = ""; 1186 | for (local i=2; i= 0); 27 | local enableTime = (Config.sitime >= 0); 28 | local enableNoci = Config.sinoci; 29 | Checksionly(); 30 | local enableType = ( Config.sionly.len() > 0 ); 31 | local enableInitDelay = ( Config.initDelay >= 0 ); 32 | 33 | 34 | if (!Config.enabled) 35 | { 36 | enableNum = false; 37 | enableTime = false; 38 | enableType = false; 39 | enableNoci = false; 40 | enableInitDelay = false; 41 | } 42 | 43 | // 设置特感数量 44 | if (enableNum) 45 | { 46 | local autoNum = 0; // 额外特感数量 47 | if (Config.siauto > 0) 48 | autoNum = Config.siauto * ::LinGe.GetPlayerCount(2); 49 | 50 | local simax = Config.sibase + autoNum; 51 | if (simax < Config.simin) 52 | simax = Config.simin; 53 | else if (simax > 31) 54 | simax = 31; 55 | 56 | ::SessionOptions.rawset("cm_MaxSpecials", simax); 57 | ::SessionOptions.rawset("cm_BaseSpecialLimit", ceil(::SessionOptions.cm_MaxSpecials / 5.0) ); // 平均特感数量 58 | ::SessionOptions.rawset("DominatorLimit", ::SessionOptions.cm_MaxSpecials); 59 | } 60 | else 61 | { 62 | ::SessionOptions.rawdelete("cm_MaxSpecials"); 63 | ::SessionOptions.rawdelete("cm_BaseSpecialLimit"); 64 | ::SessionOptions.rawdelete("DominatorLimit"); 65 | } 66 | 67 | // 设置特感刷新时间 68 | if (enableTime) 69 | { 70 | ::SessionOptions.rawset("cm_SpecialRespawnInterval", Config.sitime); 71 | } 72 | else 73 | { 74 | ::SessionOptions.rawdelete("cm_SpecialRespawnInterval"); 75 | } 76 | 77 | // 特感种类控制 78 | if (enableType) 79 | { 80 | ::SessionOptions.rawset("BoomerLimit", 0); 81 | ::SessionOptions.rawset("SpitterLimit", 0); 82 | ::SessionOptions.rawset("SmokerLimit", 0); 83 | ::SessionOptions.rawset("HunterLimit", 0); 84 | ::SessionOptions.rawset("ChargerLimit", 0); 85 | ::SessionOptions.rawset("JockeyLimit", 0); 86 | 87 | local maxsi = enableNum ? ::SessionOptions.cm_MaxSpecials : 4; 88 | ::SessionOptions.rawset("cm_BaseSpecialLimit", ceil( 1.0*maxsi / Config.sionly.len() ) ); // 平均特感数量 89 | ::SessionOptions.rawset("DominatorLimit", maxsi); 90 | foreach (val in Config.sionly) 91 | ::SessionOptions.rawset(val + "Limit", ::SessionOptions.cm_BaseSpecialLimit); 92 | } 93 | else 94 | { 95 | ::SessionOptions.rawdelete("BoomerLimit"); 96 | ::SessionOptions.rawdelete("SpitterLimit"); 97 | ::SessionOptions.rawdelete("SmokerLimit"); 98 | ::SessionOptions.rawdelete("HunterLimit"); 99 | ::SessionOptions.rawdelete("ChargerLimit"); 100 | ::SessionOptions.rawdelete("JockeyLimit"); 101 | if (!enableNum) 102 | { 103 | ::SessionOptions.rawdelete("cm_BaseSpecialLimit"); 104 | ::SessionOptions.rawdelete("DominatorLimit"); 105 | } 106 | } 107 | 108 | // 设置无小僵尸 109 | if (enableNoci) 110 | { 111 | ::SessionOptions.rawset("cm_CommonLimit", 0); 112 | ::VSLib.Timers.AddTimerByName("AutoKillCI", 1.0, true, Timer_AutoKillCI); 113 | } 114 | else 115 | { 116 | ::SessionOptions.rawdelete("cm_CommonLimit"); 117 | ::VSLib.Timers.RemoveTimerByName("AutoKillCI"); 118 | } 119 | 120 | // 出门第一波特感时间 121 | if (enableInitDelay) 122 | 123 | { 124 | ::SessionOptions.rawset("SpecialInitialSpawnDelayMax", Config.initDelay); 125 | ::SessionOptions.rawset("SpecialInitialSpawnDelayMin", Config.initDelay); 126 | } 127 | else 128 | { 129 | ::SessionOptions.rawdelete("SpecialInitialSpawnDelayMax"); 130 | ::SessionOptions.rawdelete("SpecialInitialSpawnDelayMin"); 131 | } 132 | } 133 | 134 | // 检查数组sionly值的有效性 移除无效值 135 | ::LinGe.MoreSI.Checksionly <- function() 136 | { 137 | local str = ""; 138 | local firstChar = ""; 139 | if ("array" != typeof Config.sionly) 140 | Config.sionly = []; 141 | else 142 | { 143 | foreach (idx, val in Config.sionly) 144 | { 145 | // 如果找不到则将其进行字母转换,再进行查找 146 | if (null == sitypelist.find(val)) 147 | { 148 | // 首字母转为大写,其它转成小写 149 | firstChar = val.slice(0, 1).toupper(); 150 | str = val.slice(1).tolower(); 151 | str = firstChar + str; 152 | 153 | if (null == sitypelist.find(str)) 154 | Config.sionly.remove(idx); 155 | else 156 | Config.sionly[idx] = str; 157 | } 158 | } 159 | } 160 | } 161 | 162 | // 输出当前设置信息 163 | ::LinGe.MoreSI.ShowInfo <- function () 164 | { 165 | if (!Config.enabled) 166 | { 167 | ClientPrint(null, 3, "\x04多特控制:总开关\x03 关闭"); 168 | return; 169 | } 170 | 171 | local text = "\x04多特控制:"; 172 | if (Config.sibase >= 0) 173 | text += "特感数量为\x03 " + ::SessionOptions.cm_MaxSpecials + " \x04,"; 174 | else 175 | text += "数量控制\x03 关闭 \x04,"; 176 | if (Config.sitime >= 0) 177 | text += "刷新时间为\x03 " + ::SessionOptions.cm_SpecialRespawnInterval; 178 | else 179 | text += "刷新控制为\x03 关闭"; 180 | ClientPrint(null, 3, text); 181 | 182 | if (Config.sionly.len() > 0 || Config.sinoci) 183 | { 184 | text = "\x04多特控制:" 185 | if (Config.sionly.len() > 0) 186 | { 187 | local list = ""; 188 | foreach (val in Config.sionly) 189 | list += val + " "; 190 | text += "限制只生成特感 \x03" + list; 191 | } 192 | else 193 | text += "限制特感生成 \x03关闭"; 194 | if (Config.sinoci) 195 | text += "\x04,无小僵尸 \x03开启"; 196 | else 197 | text += "\x04,无小僵尸 \x03关闭"; 198 | ClientPrint(null, 3, text); 199 | } 200 | } 201 | 202 | ::LinGe.MoreSI.cache_restore <- function (params) 203 | { 204 | // 如果有有效Cache存在 则使用Cache中的配置 205 | if (params.isValidCache && ::LinGe.Cache.rawin("MoreSI_Config")) 206 | { 207 | _enabled = ::LinGe.Cache.MoreSI_Config.enabled; 208 | } 209 | Config.enabled = false; 210 | } 211 | ::LinEventHook("cache_restore", ::LinGe.MoreSI.cache_restore, ::LinGe.MoreSI); 212 | 213 | // 回合开始 214 | ::LinGe.MoreSI.OnGameEvent_round_start <- function (params) 215 | { 216 | Config.enabled = _enabled; 217 | if (Config.enabled) 218 | { 219 | ExecConfig(); 220 | ShowInfo(); 221 | } 222 | } 223 | ::LinEventHook("OnGameEvent_round_start", ::LinGe.MoreSI.OnGameEvent_round_start, ::LinGe.MoreSI); 224 | 225 | // 玩家队伍变更 调整特感数量 226 | ::LinGe.MoreSI.OnGameEvent_player_team <- function (params) 227 | { 228 | if (!params.rawin("userid")) 229 | return; 230 | // 根据生还者人数调整特感数量 231 | if ( Config.enabled && Config.sibase >= 0 && Config.siauto > 0 ) 232 | { 233 | if (2 == params.team || 2 == params.oldteam) 234 | { 235 | local oldmax = ::SessionOptions.cm_MaxSpecials; 236 | // 延迟1.2秒再更新特感数量,避免短时间内多次数量刷新 237 | ::VSLib.Timers.AddTimerByName("SIAUTO", 1.2, false, Delay_siauto, oldmax); 238 | } 239 | } 240 | } 241 | ::LinEventHook("OnGameEvent_player_team", ::LinGe.MoreSI.OnGameEvent_player_team, ::LinGe.MoreSI); 242 | 243 | ::LinGe.MoreSI.Delay_siauto <- function (oldmax) 244 | { 245 | if (Config.enabled && Config.sibase >= 0 && Config.siauto > 0) 246 | { 247 | ExecConfig(); 248 | if (oldmax != ::SessionOptions.cm_MaxSpecials) 249 | ClientPrint(null, 3, "\x04多特控制:当前特感数量已修改为\x03 " + ::SessionOptions.cm_MaxSpecials); 250 | } 251 | }.bindenv(::LinGe.MoreSI); 252 | 253 | // !si 查看当前多特控制状态 254 | ::LinGe.MoreSI.Cmd_si <- function (player, args) 255 | { 256 | ShowInfo(); 257 | } 258 | ::LinCmdAdd("si", ::LinGe.MoreSI.Cmd_si, ::LinGe.MoreSI, "", false); 259 | 260 | // !sion 打开多特控制 同时可以用来一次设置多个值 sibase siauto sitime noci sionly(限制特感类型需用逗号分隔) 261 | // 不修改的数值输入 -2 262 | // 一次正确的用法: !sion 4 1 15 -2 Hunter,Jockey 设置sibase=4,siauto=1,sitime=15,noci不变,sionly=["Hunter", "Jockey"] 263 | ::LinGe.MoreSI.Cmd_sion <- function (player, args) 264 | { 265 | local sibase = -2; 266 | local siauto = -2; 267 | local sitime = -2; 268 | local noci = -2; 269 | local sionly = -2; 270 | 271 | local argc = args.len(); 272 | if (argc > 1) 273 | { 274 | sibase = LinGe.TryStringToInt(args[1], -2); 275 | if (sibase > 31) 276 | sibase = 31; 277 | if (sibase != -2) 278 | Config.sibase = sibase; 279 | } 280 | if (argc > 2) 281 | { 282 | siauto = LinGe.TryStringToInt(args[2], -2); 283 | if (siauto < 0 && siauto!=-2) 284 | siauto = 0; 285 | else if (siauto > 7) 286 | siauto = 7; 287 | if (siauto != -2) 288 | Config.siauto = siauto; 289 | } 290 | if (argc > 3) 291 | { 292 | sitime = LinGe.TryStringToInt(args[3], -2); 293 | if (sitime != -2) 294 | Config.sitime = sitime; 295 | } 296 | if (argc > 4) 297 | { 298 | noci = args[4]; 299 | if ("on" == noci) 300 | Config.sinoci = true; 301 | else if ("off" == noci) 302 | Config.sinoci = false; 303 | else 304 | noci = -2; 305 | } 306 | if (argc > 5) 307 | { 308 | sionly = split(args[5], ","); 309 | Config.sionly = sionly; 310 | } 311 | 312 | Config.enabled = true; 313 | ExecConfig(); 314 | ShowInfo(); 315 | } 316 | ::LinCmdAdd("sion", ::LinGe.MoreSI.Cmd_sion, ::LinGe.MoreSI, "打开多特控制"); 317 | 318 | // !sioff 关闭多特控制 319 | ::LinGe.MoreSI.Cmd_sioff <- function (player, args) 320 | { 321 | if (args.len() == 1) 322 | { 323 | if (Config.enabled) 324 | { 325 | Config.enabled = false; 326 | ExecConfig(); 327 | } 328 | ShowInfo(); 329 | } 330 | } 331 | ::LinCmdAdd("sioff", ::LinGe.MoreSI.Cmd_sioff, ::LinGe.MoreSI, "关闭多特控制"); 332 | 333 | // !sibase 设置基础特感数量 334 | ::LinGe.MoreSI.Cmd_sibase <- function (player, args) 335 | { 336 | if (!Config.enabled) 337 | { 338 | ClientPrint(player, 3, "\x04多特控制:总开关\x03 关闭"); 339 | return; 340 | } 341 | 342 | local argsLen = args.len(); 343 | if (argsLen > 2) 344 | return; 345 | 346 | if (2 == argsLen) 347 | { 348 | local num = LinGe.TryStringToInt(args[1], -1); 349 | if (num > 31) 350 | { 351 | ClientPrint(player, 3, "\x04多特控制:基础特感数量不能超过\x03 31"); 352 | return; 353 | } 354 | Config.sibase = num; 355 | ExecConfig(); 356 | } 357 | if (Config.sibase >= 0) 358 | { 359 | ClientPrint(null, 3, "\x04多特控制:基础特感数量\x03 " + Config.sibase); 360 | ClientPrint(null, 3, "\x04多特控制:当前特感总数为\x03 " + ::SessionOptions.cm_MaxSpecials); 361 | } 362 | else 363 | ClientPrint(null, 3, "\x04多特控制:数量控制\x03 关闭"); 364 | } 365 | ::LinCmdAdd("sibase", ::LinGe.MoreSI.Cmd_sibase, ::LinGe.MoreSI, "设置基础特感数量"); 366 | 367 | // !siauto 设置自动增加特感数量 368 | ::LinGe.MoreSI.Cmd_siauto <- function (player, args) 369 | { 370 | if (!Config.enabled) 371 | { 372 | ClientPrint(player, 3, "\x04多特控制:总开关\x03 关闭"); 373 | return; 374 | } 375 | 376 | local argsLen = args.len(); 377 | if (argsLen > 2) 378 | return; 379 | 380 | if (2 == argsLen) 381 | { 382 | local num = LinGe.TryStringToInt(args[1], -1); 383 | if (num < 0 || num > 7) 384 | { 385 | ClientPrint(player, 3, "\x04多特控制:预设自动增加特感数量只能为\x03 0~7"); 386 | return; 387 | } 388 | Config.siauto = num; 389 | ExecConfig(); 390 | } 391 | if (Config.siauto > 0) 392 | { 393 | ClientPrint(null, 3, "\x04多特控制:每\x03 1 \x04名生还者玩家加入将增加\x03 " + Config.siauto + " \x04个特感"); 394 | ClientPrint(null, 3, "\x04多特控制:当前特感总数为\x03 " + ::SessionOptions.cm_MaxSpecials); 395 | } 396 | else 397 | ClientPrint(null, 3, "\x04多特控制:自动增加特感\x03 关闭"); 398 | } 399 | ::LinCmdAdd("siauto", ::LinGe.MoreSI.Cmd_siauto, ::LinGe.MoreSI, "设置每1名生还者加入所增加的特感数量"); 400 | 401 | // !sitime 设置特感刷新时间 402 | ::LinGe.MoreSI.Cmd_sitime <- function (player, args) 403 | { 404 | if (!Config.enabled) 405 | { 406 | ClientPrint(player, 3, "\x04多特控制:总开关\x03 关闭"); 407 | return; 408 | } 409 | 410 | local argsLen = args.len(); 411 | if (argsLen > 2) 412 | return; 413 | 414 | if (2 == argsLen) 415 | { 416 | Config.sitime = LinGe.TryStringToInt(args[1], -1); 417 | ExecConfig(); 418 | } 419 | if (Config.sitime >= 0) 420 | ClientPrint(null, 3, "\x04多特控制:特感刷新时间为\x03 " + Config.sitime); 421 | else 422 | ClientPrint(null, 3, "\x04多特控制:特感刷新控制\x03 关闭"); 423 | } 424 | ::LinCmdAdd("sitime", ::LinGe.MoreSI.Cmd_sitime, ::LinGe.MoreSI, "设置特感刷新时间"); 425 | 426 | // !sionly 限制只生成某一种特感 只能是sitypelist中的一种 427 | // 用逗号分隔多种特感,例如 !sionly Hunter,Boomer 428 | ::LinGe.MoreSI.Cmd_sionly <- function (player, args) 429 | { 430 | if (!Config.enabled) 431 | { 432 | ClientPrint(player, 3, "\x04多特控制:总开关\x03 关闭"); 433 | return; 434 | } 435 | 436 | if (args.len() > 1) 437 | { 438 | Config.sionly = split(args[1], ","); 439 | ExecConfig(); 440 | } 441 | 442 | if (Config.sionly.len() > 0) 443 | { 444 | local list = ""; 445 | foreach (val in Config.sionly) 446 | list += val + " "; 447 | ClientPrint(null, 3, "\x04多特控制:限制只生成特感 \x03" + list); 448 | // ClientPrint(player, 3, "\x04关闭方法:!sionly\x03 任意字符"); 449 | } 450 | else 451 | { 452 | ClientPrint(null, 3, "\x04多特控制:限制特感生成 \x03关闭"); 453 | // ClientPrint(player, 3, "\x04开启方法:!sionly\x03 Boomer,Spitter,Smoker,Hunter,Charger,Jockey"); 454 | } 455 | } 456 | ::LinCmdAdd("sionly", ::LinGe.MoreSI.Cmd_sionly, ::LinGe.MoreSI, "限制只生成哪些特感,例:!sionly Hunter,Jockey"); 457 | 458 | // !noci 是否设置无小僵尸 459 | ::LinGe.MoreSI.Cmd_noci <- function (player, args) 460 | { 461 | if (!Config.enabled) 462 | { 463 | ClientPrint(player, 3, "\x04多特控制:总开关\x03 关闭"); 464 | return; 465 | } 466 | 467 | if (args.len() == 2) 468 | { 469 | if (args[1] == "on") 470 | Config.sinoci = true; 471 | else if (args[1] == "off") 472 | Config.sinoci = false; 473 | ExecConfig(); 474 | } 475 | if (Config.sinoci) 476 | ClientPrint(null, 3, "\x04多特控制:无小僵尸 \x03开启"); 477 | else 478 | ClientPrint(null, 3, "\x04多特控制:无小僵尸 \x03关闭"); 479 | } 480 | ::LinCmdAdd("noci", ::LinGe.MoreSI.Cmd_noci, ::LinGe.MoreSI); 481 | ::LinCmdAdd("sinoci", ::LinGe.MoreSI.Cmd_noci, ::LinGe.MoreSI, "on/off 开启/关闭自动清除小僵尸"); 482 | 483 | ::LinGe.MoreSI.Timer_AutoKillCI <- function (params) 484 | { 485 | if ( Director.GetCommonInfectedCount() > 0 ) 486 | { 487 | local infected = null; 488 | while ( infected = Entities.FindByClassname( infected, "infected" ) ) 489 | { 490 | if ( infected.IsValid() ) 491 | infected.Kill(); 492 | } 493 | } 494 | }.bindenv(::LinGe.MoreSI); 495 | 496 | } -------------------------------------------------------------------------------- /vscripts/LinGe/RewardHP.nut: -------------------------------------------------------------------------------- 1 | // 仅在非对抗类模式生效 2 | if (!::LinGe.isVersus) { 3 | printl("[LinGe] 击杀回复血量 正在载入"); 4 | 5 | ::LinGe.RewardHP <- {}; 6 | 7 | ::LinGe.RewardHP.Config <- { 8 | mode = 0, // 0:关闭 1:回复实血 2:回复虚血 3:回复虚血,条件不满足则回复实血 9 | limit = 100, // 奖励血量上限 10 | permanent = { // 实血回复量 11 | special = 2,// 击杀一只普通特感(非Tank和Witch)回复多少实血 12 | witch = 10, // 击杀一只Witch回复多少实血 13 | common = 0,// 击杀一只丧尸回复多少实血 14 | }, 15 | temporary = { // 虚血回复量 16 | special = 4,// 击杀一只普通特感(非Tank和Witch)回复多少虚血 17 | witch = 20, // 击杀一只Witch回复多少虚血 18 | common = 0,// 击杀一只丧尸回复多少虚血 19 | } 20 | }; 21 | ::LinGe.Config.Add("RewardHP", ::LinGe.RewardHP.Config); 22 | ::LinGe.Cache.RewardHP_Config <- ::LinGe.RewardHP.Config; 23 | 24 | ::LinGe.RewardHP.OnGameEvent_player_death <- function (params) 25 | { 26 | if (Config.mode < 1 || Config.mode > 3) 27 | return; 28 | 29 | local victim = null; 30 | if (params.victimname == "Infected" || params.victimname == "Witch") 31 | { 32 | victim = Ent(params.entityid); 33 | if (!victim || !victim.IsValid()) 34 | return; 35 | } 36 | else 37 | { 38 | if (params.victimname == "Tank") 39 | return; 40 | victim = GetPlayerFromUserID(params.userid); 41 | if (!victim || !victim.IsValid() || ::LinGe.GetPlayerTeam(victim) != 3) 42 | return; 43 | } 44 | 45 | local attacker = GetPlayerFromUserID(params.attacker); 46 | if (!attacker || !attacker.IsValid() || ::LinGe.GetPlayerTeam(attacker) != 2 47 | || attacker.IsIncapacitated()) 48 | return; 49 | 50 | local hp = attacker.GetHealth(); 51 | local hpbuffer = attacker.GetHealthBuffer(); 52 | if (hp >= Config.limit) 53 | return; 54 | 55 | local reward_perm = 0, reward_temp = 0; 56 | switch (params.victimname) 57 | { 58 | case "Infected": 59 | reward_perm = Config.permanent.common; 60 | reward_temp = Config.temporary.common; 61 | break; 62 | case "Witch": 63 | reward_perm = Config.permanent.witch; 64 | reward_temp = Config.temporary.witch; 65 | break; 66 | default: 67 | reward_perm = Config.permanent.special; 68 | reward_temp = Config.temporary.special; 69 | break; 70 | } 71 | 72 | // 判断回复虚血条件是否满足(模式不为1 且 虚血回复量>0 且 回复后总血量<=上限) 73 | // 满足则回复虚血,否则回复实血 74 | if (Config.mode != 1 && reward_temp > 0 && hp + hpbuffer + reward_temp <= Config.limit) 75 | { 76 | attacker.SetHealthBuffer(hpbuffer + reward_temp); 77 | } 78 | else if (reward_perm > 0) 79 | { 80 | // 回复实血,但实血量不会超过上限 81 | if (hp + reward_perm > Config.limit) 82 | { 83 | attacker.SetHealth(Config.limit); 84 | } 85 | else 86 | { 87 | attacker.SetHealth(hp + reward_perm); 88 | } 89 | // 如果奖励后总血量超过上限,则扣除多余的虚血,但扣除量不会超过本次奖励的实血量 90 | // 相当于虚血转换为实血 91 | local excess = attacker.GetHealth() + hpbuffer - Config.limit; 92 | if (excess > 0) 93 | { 94 | local diff = attacker.GetHealth() - hp; 95 | if (excess > diff) 96 | excess = diff; 97 | attacker.SetHealthBuffer(hpbuffer - excess); 98 | } 99 | } 100 | } 101 | ::LinEventHook("OnGameEvent_player_death", ::LinGe.RewardHP.OnGameEvent_player_death, ::LinGe.RewardHP); 102 | 103 | ::LinGe.RewardHP.Cmd_rhp <- function (player, args) 104 | { 105 | if (2 == args.len()) 106 | { 107 | local mode = ::LinGe.TryStringToInt(args[1], 0); 108 | Config.mode = mode; 109 | } 110 | switch (Config.mode) 111 | { 112 | case 1: 113 | ClientPrint(null, 3, "\x04击杀回血当前模式 \x03回复实血"); 114 | break; 115 | case 2: 116 | ClientPrint(null, 3, "\x04击杀回血当前模式 \x03回复虚血"); 117 | break; 118 | case 3: 119 | ClientPrint(null, 3, "\x04击杀回血当前模式 \x03回复虚血,满血后回复实血"); 120 | break; 121 | default: 122 | ClientPrint(null, 3, "\x04击杀回血当前模式 \x03关闭"); 123 | break; 124 | } 125 | ClientPrint(player, 3, "\x04!rhp 0:关闭 1:回复实血 2:回复虚血 3:回复虚血,条件不满足则回复实血"); 126 | } 127 | ::LinCmdAdd("rhp", ::LinGe.RewardHP.Cmd_rhp, ::LinGe.RewardHP, "0:关闭 1:回复实血 2:回复虚血 3:回复虚血,条件不满足则回复实血"); 128 | 129 | } // if (!::LinGe.isVersus) -------------------------------------------------------------------------------- /vscripts/LinGe/VSLib.nut: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 LuKeM aka Neil - 119 and Rayman1103 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | ::__VSLIB_VERSION__ <- 5.0; 22 | local __VSLIB_NOTIFY_VERSION__ = false; 23 | 24 | /* 25 | * Create global namespace 26 | */ 27 | if (!("VSLib" in getroottable())) 28 | { 29 | ::VSLib <- 30 | { 31 | GlobalCache = {} 32 | GlobalCacheSession = {} 33 | } 34 | __VSLIB_NOTIFY_VERSION__ = true; 35 | } 36 | 37 | /* 38 | * Include sub-files 39 | */ 40 | IncludeScript("LinGe/VSLib/EasyLogic.nut"); 41 | IncludeScript("LinGe/VSLib/Utils.nut"); 42 | IncludeScript("LinGe/VSLib/Timer.nut"); 43 | IncludeScript("LinGe/VSLib/Entity.nut"); 44 | IncludeScript("LinGe/VSLib/Player.nut"); 45 | IncludeScript("LinGe/VSLib/FileIO.nut"); 46 | IncludeScript("LinGe/VSLib/HUD.nut"); 47 | IncludeScript("LinGe/VSLib/ResponseRules.nut"); 48 | IncludeScript("LinGe/VSLib/RandomItemSpawner.nut"); 49 | 50 | if ( __VSLIB_NOTIFY_VERSION__ ) 51 | printf( "Loaded VSLib version %f", __VSLIB_VERSION__ ); -------------------------------------------------------------------------------- /vscripts/LinGe/VSLib/fileio.nut: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 LuKeM aka Neil - 119 and Rayman1103 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | 22 | /** 23 | * File I/O functions that simplify the saving and loading of data. 24 | */ 25 | ::VSLib.FileIO <- {}; 26 | 27 | 28 | /** 29 | * Recursively serializes a table and returns the string. This command ignores all functions within 30 | * the table, saving only the primitive types (i.e. integers, floats, strings, etc with definite values). 31 | * The indexes that you use for your table need to be programmatically "clean," meaning that the index 32 | * cannot contain invalid characters like +-=!@#$%^&*() etc. Indexes that contain any kind of 33 | * invalid character is completely ignored. If you are trying to store player information, 34 | * use Player::GetUniqueID() instead of Player::GetSteamID() for the index ID. 35 | * 36 | * You probably won't need to use this function by itself. @see VSLib::FileIO::SaveTable() 37 | */ 38 | function VSLib::FileIO::SerializeTable(object, predicateStart = "{\n", predicateEnd = "}\n", indice = true) 39 | { 40 | local baseString = predicateStart; 41 | 42 | foreach (idx, val in object) 43 | { 44 | local idxType = typeof idx; 45 | 46 | if (idxType == "instance" || idxType == "class" || idxType == "function") 47 | continue; 48 | 49 | // Check for invalid characters 50 | local idxStr = idx.tostring(); 51 | local reg = regexp("^[a-zA-Z0-9_]*$"); 52 | 53 | if (!reg.match(idxStr)) 54 | { 55 | printf("VSLib Warning: Index '%s' is invalid (invalid characters found), skipping...", idxStr); 56 | continue; 57 | } 58 | 59 | // Check for numeric fields and prefix them so system can compile 60 | reg = regexp("^[0-9]+$"); 61 | if (reg.match(idxStr)) 62 | idxStr = "_vslInt_" + idxStr; 63 | 64 | 65 | local preCompileString = ((indice) ? (idxStr + " = ") : ""); 66 | 67 | switch (typeof val) 68 | { 69 | case "table": 70 | baseString += preCompileString + ::VSLib.FileIO.SerializeTable(val); 71 | break; 72 | 73 | case "string": 74 | baseString += preCompileString + "\"" + ::VSLib.Utils.StringReplace(::VSLib.Utils.StringReplace(val, "\"", "{VSQUOTE}"), @"\\", "{VSSLASH}") + "\"\n"; // " 75 | break; 76 | 77 | case "integer": 78 | baseString += preCompileString + val + "\n"; 79 | break; 80 | 81 | case "float": 82 | baseString += preCompileString + val + "\n"; 83 | break; 84 | 85 | case "array": 86 | baseString += preCompileString + ::VSLib.FileIO.SerializeTable(val, "[\n", "]\n", false); 87 | break; 88 | 89 | case "bool": 90 | baseString += preCompileString + ((val) ? "true" : "false") + "\n"; 91 | break; 92 | } 93 | } 94 | 95 | baseString += predicateEnd; 96 | 97 | return baseString; 98 | } 99 | 100 | /** 101 | * This function will serialize and save a table to the hard disk; useful for storing stats, 102 | * round times, and other important information. 103 | */ 104 | function VSLib::FileIO::SaveTable(fileName, table) 105 | { 106 | fileName += ".tbl"; 107 | return StringToFile(fileName, ::VSLib.FileIO.SerializeTable(table)); 108 | } 109 | 110 | /** 111 | * This function will clean table input. 112 | */ 113 | function VSLib::FileIO::DeserializeReviseTable(t) 114 | { 115 | foreach (idx, val in t) 116 | { 117 | if (typeof val == "string") 118 | t[idx] = ::VSLib.Utils.StringReplace(::VSLib.Utils.StringReplace(val, "{VSQUOTE}", "\""), "{VSSLASH}", @"\"); // " 119 | else if (typeof val == "table") 120 | t[idx] = DeserializeReviseTable(val); 121 | } 122 | 123 | return t; 124 | } 125 | 126 | /** 127 | * This function will deserialize and return the compiled table. 128 | * If the table does not exist, null is returned. 129 | */ 130 | function VSLib::FileIO::LoadTable(fileName) 131 | { 132 | local contents = FileToString(fileName + ".tbl"); 133 | 134 | if (!contents) 135 | return null; 136 | 137 | local t = compilestring( "return " + contents )(); 138 | 139 | foreach (idx, val in t) 140 | { 141 | local idxStr = idx.tostring(); 142 | 143 | if (idxStr.find("_vslInt_") != null) 144 | { 145 | idxStr = Utils.StringReplace(idxStr, "_vslInt_", ""); 146 | t[idxStr.tointeger()] <- val; 147 | delete t[idx]; 148 | } 149 | } 150 | 151 | t = DeserializeReviseTable(t); 152 | 153 | return t; 154 | } 155 | 156 | 157 | /** 158 | * This function will make the filename unique for each mapname. 159 | * @authors Rayman1103 160 | */ 161 | function VSLib::FileIO::MakeFileName( mapname, modename ) 162 | { 163 | return "VSLib_" + mapname + "_" + modename; 164 | } 165 | 166 | /** 167 | * This function will serialize and save a table to the hard disk from the current mapname; useful for storing stats, 168 | * round times, and other important information individually for every mapname. 169 | * @authors Rayman1103 170 | */ 171 | function VSLib::FileIO::SaveTableFileName(mapname, modename, table) 172 | { 173 | return ::VSLib.FileIO.SaveTable(::VSLib.FileIO.MakeFileName( mapname, modename ), table); 174 | } 175 | 176 | /** 177 | * This function will deserialize and return the compiled table from the current mapname. 178 | * If the table does not exist, null is returned. 179 | * @authors Rayman1103 180 | */ 181 | function VSLib::FileIO::LoadTableFileName(mapname, modename) 182 | { 183 | return ::VSLib.FileIO.LoadTable(::VSLib.FileIO.MakeFileName( mapname, modename )); 184 | } 185 | 186 | 187 | 188 | // Add a weak reference to the global table. 189 | ::FileIO <- ::VSLib.FileIO.weakref(); -------------------------------------------------------------------------------- /vscripts/LinGe/VSLib/randomitemspawner.nut: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 Rectus 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | 22 | /** 23 | * \brief Spawns random items on predefined spawnpoints. 24 | * 25 | * This class can spawn items randomly selected from a predefined list onto randomly selected spawnpoints. 26 | * 27 | * @param spawnPoints Array of vectors or VSLib entities where the items can spawn. 28 | * @param items Array of item entries the spawner chooses from. 29 | * @param flags Option flags. Currently supports RANDOM_USEPARTICLES and RANDOM_ALLOWMULTIPLEITEMS. 30 | * 31 | */ 32 | class ::VSLib.RandomItemSpawner 33 | { 34 | /* 35 | * This is a list of the currently supported items. 36 | * 37 | * ent: Classname of the item. The spawn list currently supports the entities specified below. 38 | * prob: This is the probability for the item to spawn. It's relative to the other items. 39 | * ammo: The ammo reserves primary weapons spawn with. Weapons spawn with double the value set. 40 | * Set to null on other items. 41 | * melee_type: Works the same way as on a weapon_melee_spawn. Set to null if not a melee weapon. 42 | */ 43 | static _defaultItems = 44 | [ 45 | //Entity: Probability: Ammo: Melee type: 46 | {ent = "weapon_rifle" prob = 10, ammo = 50, melee_type = null }, 47 | {ent = "weapon_shotgun_spas" prob = 10, ammo = 10, melee_type = null }, 48 | {ent = "weapon_sniper_military" prob = 10, ammo = 15, melee_type = null }, 49 | {ent = "weapon_rifle_ak47" prob = 10, ammo = 40, melee_type = null }, 50 | {ent = "weapon_autoshotgun" prob = 10, ammo = 10, melee_type = null }, 51 | {ent = "weapon_rifle_desert" prob = 10, ammo = 60, melee_type = null }, 52 | {ent = "weapon_hunting_rifle" prob = 15, ammo = 15, melee_type = null }, 53 | 54 | {ent = "weapon_rifle_m60" prob = 2, ammo = 50, melee_type = null }, 55 | {ent = "weapon_grenade_launcher" prob = 2, ammo = 50, melee_type = null }, 56 | 57 | {ent = "weapon_smg_silenced" prob = 20, ammo = 50, melee_type = null }, 58 | {ent = "weapon_smg" prob = 20, ammo = 50, melee_type = null }, 59 | {ent = "weapon_shotgun_chrome" prob = 20, ammo = 10, melee_type = null }, 60 | {ent = "weapon_pumpshotgun" prob = 20, ammo = 10, melee_type = null }, 61 | 62 | {ent = "weapon_pistol_magnum" prob = 5, ammo = null, melee_type = null }, 63 | {ent = "weapon_pistol" prob = 10, ammo = null, melee_type = null }, 64 | 65 | {ent = "weapon_adrenaline" prob = 10, ammo = null, melee_type = null }, 66 | {ent = "weapon_pain_pills" prob = 20, ammo = null, melee_type = null }, 67 | {ent = "weapon_vomitjar" prob = 3, ammo = null, melee_type = null }, 68 | {ent = "weapon_molotov" prob = 10, ammo = null, melee_type = null }, 69 | {ent = "weapon_pipe_bomb" prob = 10, ammo = null, melee_type = null }, 70 | {ent = "weapon_first_aid_kit" prob = 1, ammo = null, melee_type = null }, 71 | 72 | 73 | // Note: These items don't retain their entities when spawned, and cannot be tracked. 74 | {ent = "weapon_melee_spawn" prob = 10, ammo = null, melee_type = "any" }, 75 | {ent = "upgrade_spawn" prob = 3, ammo = null, melee_type = null }, // Laser sight 76 | {ent = "weapon_upgradepack_explosive" prob = 5, ammo = null, melee_type = null }, 77 | {ent = "weapon_upgradepack_incendiary" prob = 7, ammo = null, melee_type = null }, 78 | 79 | ]; 80 | _totalProbability = 0; 81 | _numSpawns = 0; 82 | _spawnPoints = []; 83 | _items = []; 84 | _useParticleEffects = false; 85 | _allowMultipleItemsOnPoint = false; 86 | 87 | constructor(spawnPoints, items = null, flags = 0) 88 | { 89 | if(items) 90 | _items = items; 91 | else 92 | _items = _defaultItems; 93 | 94 | _useParticleEffects = (flags & RANDOM_USEPARTICLES) 95 | _allowMultipleItemsOnPoint = (flags & RANDOM_ALLOWMULTIPLEITEMS) 96 | 97 | __FindItemSpawnPoints(spawnPoints); 98 | __CalcTotalProbability(); 99 | } 100 | 101 | function _typeof() 102 | { 103 | return "VSLIB_RANDOM_ITEM_SPAWNER"; 104 | } 105 | 106 | } 107 | 108 | /** 109 | * Global flags. 110 | */ 111 | getconsttable()["RANDOM_USEPARTICLES"] <- 1; 112 | getconsttable()["RANDOM_ALLOWMULTIPLEITEMS"] <- 2; 113 | 114 | 115 | 116 | /** 117 | * Extracts spawnpoint locations and amount from an array of vectors or entities. 118 | */ 119 | function VSLib::RandomItemSpawner::__FindItemSpawnPoints(spawns) 120 | { 121 | local spawnPoints = []; 122 | local numSpawns = 0; 123 | 124 | foreach(object in spawns) 125 | { 126 | switch(typeof object) 127 | { 128 | case "Vector": 129 | spawnPoints.push(Vector(0,0,0) + object); 130 | numSpawns++; 131 | break; 132 | 133 | case "VSLIB_ENTITY": 134 | case "VSLIB_PLAYER": 135 | spawnPoints.push(object.GetLocation()); 136 | numSpawns++; 137 | break; 138 | 139 | default: 140 | printl("VSLib Warning: Random item spawner: Invalid spawnpoint! " + object); 141 | } 142 | } 143 | 144 | if(numSpawns <= 0) 145 | printl("VSLib Error: Random item spawner: No item spawns found!"); 146 | else 147 | printl("VSLib: Random item spawner: Found " + numSpawns 148 | + " item spawns."); 149 | 150 | _spawnPoints = spawnPoints; 151 | _numSpawns = numSpawns; 152 | } 153 | 154 | /** 155 | * Calculates the combined spawn probability of all items. 156 | */ 157 | function VSLib::RandomItemSpawner::__CalcTotalProbability() 158 | { 159 | local totalProb = 0; 160 | foreach(item in _items) 161 | totalProb += item.prob; 162 | 163 | _totalProbability = totalProb; 164 | } 165 | 166 | /** 167 | * Spawns specified number of random items. 168 | * 169 | * @return Items spawned as an array of VSLib entities. 170 | */ 171 | function VSLib::RandomItemSpawner::SpawnRandomItems(amount) 172 | { 173 | local spawnedItems = []; 174 | local spawnSet = clone _spawnPoints; 175 | local entity = null; 176 | 177 | for(local i = 0; i < amount; i++) 178 | { 179 | if(spawnSet.len() < 1) 180 | { 181 | printl("VSLib Warning: Random item spawner: Ran out of spawn points!"); 182 | return spawnedItems; 183 | } 184 | 185 | local probCount = RandomInt(1, _totalProbability); 186 | local spawnIndex = RandomInt(0, spawnSet.len() -1); 187 | 188 | foreach(item in _items) 189 | { 190 | if((probCount -= item.prob) <= 0) 191 | { 192 | if(entity = __SpawnSingleItem(g_ModeScript.DuplicateTable(item), spawnSet[spawnIndex])) 193 | spawnedItems.push(entity); 194 | 195 | break; 196 | } 197 | } 198 | if(!_allowMultipleItemsOnPoint) 199 | spawnSet.remove(spawnIndex); 200 | } 201 | 202 | return spawnedItems; 203 | } 204 | 205 | 206 | /** 207 | * Generates an entity table and spawns an item of the specified type. 208 | */ 209 | function VSLib::RandomItemSpawner::__SpawnSingleItem(item, origin) 210 | { 211 | local entTable = {}; 212 | 213 | if(item.ammo != null) // Gun 214 | entTable = 215 | { 216 | targetname = "random_spawned_item" 217 | classname = item.ent 218 | ammo = item.ammo 219 | origin = origin 220 | angles = Vector(0, RandomFloat(0, 360), (RandomInt(0,1) * 180 - 90)) 221 | solid = "6" // Vphysics 222 | } 223 | else if(item.melee_type != null) // Melee weapon 224 | entTable = 225 | { 226 | targetname = "random_spawned_nontrackable" 227 | classname = item.ent 228 | origin = origin 229 | angles = Vector(0, RandomFloat(0, 360), (RandomInt(0,1) * 180 - 90)) 230 | solid = "6" // Vphysics 231 | melee_weapon = item.melee_type 232 | spawnflags = 3 233 | } 234 | else if(item.ent == "upgrade_spawn") // Laser upgrade 235 | { 236 | entTable = 237 | { 238 | targetname = "random_spawned_nontrackable" 239 | classname = item.ent 240 | origin = origin 241 | angles = Vector(0, RandomFloat(0, 360), 0) 242 | solid = "6" // Vphysics 243 | laser_sight = 1 244 | upgradepack_incendiary = 0 245 | upgradepack_explosive = 0 246 | } 247 | } 248 | else if((item.ent == "weapon_upgradepack_explosive") || (item.ent == "weapon_upgradepack_incendiary")) 249 | { 250 | entTable = 251 | { 252 | targetname = "random_spawned_nontrackable" 253 | classname = item.ent 254 | origin = origin 255 | angles = Vector(0, RandomFloat(0, 360), 0) 256 | solid = "6" // Vphysics 257 | } 258 | } 259 | else // Any other item 260 | entTable = 261 | { 262 | targetname = "random_spawned_item" 263 | classname = item.ent 264 | origin = origin 265 | angles = Vector(0, RandomFloat(0, 360), 0) 266 | solid = "6" // Vphysics 267 | } 268 | 269 | local itemEntity = g_ModeScript.CreateSingleSimpleEntityFromTable(entTable); 270 | 271 | if(itemEntity) 272 | { 273 | if(_useParticleEffects) 274 | g_ModeScript.CreateParticleSystemAt(itemEntity, Vector(0,0,-8), "mini_fireworks"); 275 | 276 | if(entTable.targetname == "random_spawned_item") 277 | return ::VSLib.Entity(itemEntity); 278 | } 279 | return null; 280 | } 281 | -------------------------------------------------------------------------------- /vscripts/LinGe/VSLib/timer.nut: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013 LuKeM aka Neil - 119 and Rayman1103 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | * and associated documentation files (the "Software"), to deal in the Software without 6 | * restriction, including without limitation the rights to use, copy, modify, merge, publish, 7 | * distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 8 | * Software is furnished to do so, subject to the following conditions: 9 | * 10 | * The above copyright notice and this permission notice shall be included in all copies or 11 | * substantial portions of the Software. 12 | * 13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | * 19 | */ 20 | 21 | 22 | /** 23 | * \brief A timer system to call a function after a certain amount of time. 24 | * 25 | * The Timer table allows the developer to easily add synchronized callbacks. 26 | */ 27 | if (!("Timers" in ::VSLib)) 28 | { 29 | ::VSLib.Timers <- 30 | { 31 | TimersList = {} 32 | TimersID = {} 33 | ClockList = {} 34 | count = 0 35 | } 36 | } 37 | 38 | /* 39 | * Constants 40 | */ 41 | 42 | // Passable constants 43 | getconsttable()["NO_TIMER_PARAMS"] <- null; /** No timer params */ 44 | 45 | // Internal constants 46 | const UPDATE_RATE = 0.1; /** Fastest possible update rate */ 47 | 48 | // Flags 49 | getconsttable()["TIMER_FLAG_KEEPALIVE"] <- (1 << 1); /** Keep timer alive even after RoundEnd is called */ 50 | getconsttable()["TIMER_FLAG_COUNTDOWN"] <- (1 << 2); /** Fire the timer the specified number of times before the timer removes itself */ 51 | getconsttable()["TIMER_FLAG_DURATION"] <- (1 << 3); /** Fire the timer each interval for the specified duration */ 52 | getconsttable()["TIMER_FLAG_DURATION_VARIANT"] <- (1 << 4); /** Fire the timer each interval for the specified duration, regardless of internal function call time loss */ 53 | 54 | 55 | /** 56 | * Creates a named timer that will be added to the timers list. If a named timer already exists, 57 | * it will be replaced. 58 | * 59 | * @return Name of the created timer 60 | */ 61 | function VSLib::Timers::AddTimerByName(strName, delay, repeat, func, paramTable = null, flags = 0, value = {}) 62 | { 63 | ::VSLib.Timers.RemoveTimerByName(strName); 64 | ::VSLib.Timers.TimersID[strName] <- ::VSLib.Timers.AddTimer(delay, repeat, func, paramTable, flags, value); 65 | return strName; 66 | } 67 | 68 | /** 69 | * Deletes a named timer. 70 | */ 71 | function VSLib::Timers::RemoveTimerByName(strName) 72 | { 73 | if (strName in ::VSLib.Timers.TimersID) 74 | { 75 | ::VSLib.Timers.RemoveTimer(::VSLib.Timers.TimersID[strName]); 76 | delete ::VSLib.Timers.TimersID[strName]; 77 | } 78 | } 79 | 80 | /** 81 | * Calls a function and passes the specified table to the callback after the specified delay. 82 | */ 83 | function VSLib::Timers::AddTimer(delay, repeat, func, paramTable = null, flags = 0, value = {}) 84 | { 85 | local TIMER_FLAG_COUNTDOWN = (1 << 2); 86 | local TIMER_FLAG_DURATION = (1 << 3); 87 | local TIMER_FLAG_DURATION_VARIANT = (1 << 4); 88 | 89 | delay = delay.tofloat(); 90 | repeat = repeat.tointeger(); 91 | 92 | local rep = (repeat > 0) ? true : false; 93 | 94 | if (delay < UPDATE_RATE) 95 | { 96 | printl("VSLib Warning: Timer delay cannot be less than " + UPDATE_RATE + " second(s). Delay has been reset to " + UPDATE_RATE + "."); 97 | delay = UPDATE_RATE; 98 | } 99 | 100 | if (paramTable == null) 101 | paramTable = {}; 102 | 103 | if (typeof value != "table") 104 | { 105 | printf("VSLib Timer Error: Illegal parameter: 'value' parameter needs to be a table."); 106 | return -1; 107 | } 108 | else if (flags & TIMER_FLAG_COUNTDOWN && !("count" in value)) 109 | { 110 | printf("VSLib Timer Error: Could not create the countdown timer because the 'count' field is missing from 'value'."); 111 | return -1; 112 | } 113 | else if ((flags & TIMER_FLAG_DURATION || flags & TIMER_FLAG_DURATION_VARIANT) && !("duration" in value)) 114 | { 115 | printf("VSLib Timer Error: Could not create the duration timer because the 'duration' field is missing from 'value'."); 116 | return -1; 117 | } 118 | 119 | // Convert the flag into countdown 120 | if (flags & TIMER_FLAG_DURATION) 121 | { 122 | flags = flags & ~TIMER_FLAG_DURATION; 123 | flags = flags | TIMER_FLAG_COUNTDOWN; 124 | 125 | value["count"] <- floor(value["duration"].tofloat() / delay); 126 | } 127 | 128 | ++count; 129 | TimersList[count] <- 130 | { 131 | _delay = delay 132 | _func = func 133 | _params = paramTable 134 | _startTime = Time() 135 | _baseTime = Time() 136 | _repeat = rep 137 | _flags = flags 138 | _opval = value 139 | } 140 | 141 | return count; 142 | } 143 | 144 | /** 145 | * Removes the specified timer. 146 | */ 147 | function VSLib::Timers::RemoveTimer(idx) 148 | { 149 | if (idx in TimersList) 150 | delete ::VSLib.Timers.TimersList[idx]; 151 | } 152 | 153 | /** 154 | * Manages VSLib timers. 155 | */ 156 | function VSLib::Timers::ManageTimer(idx, command, value = null, allowNegTimer = false) 157 | { 158 | if ( idx in ::VSLib.Timers.ClockList && value == null ) 159 | { 160 | ::VSLib.Timers.ClockList[idx]._command <- command; 161 | ::VSLib.Timers.ClockList[idx]._allowNegTimer <- allowNegTimer; 162 | } 163 | else 164 | { 165 | if ( value == null ) 166 | value = 0; 167 | 168 | ::VSLib.Timers.ClockList[idx] <- 169 | { 170 | _value = value 171 | _startTime = Time() 172 | _lastUpdateTime = Time() 173 | _command = command 174 | _allowNegTimer = allowNegTimer 175 | } 176 | } 177 | } 178 | 179 | /** 180 | * Returns the value of a VSLib timer. 181 | */ 182 | function VSLib::Timers::ReadTimer(idx) 183 | { 184 | if ( idx in ::VSLib.Timers.ClockList ) 185 | return ::VSLib.Timers.ClockList[idx]._value; 186 | 187 | return null; 188 | } 189 | 190 | /** 191 | * Returns a VSLib timer as a displayable string --:--. 192 | */ 193 | function VSLib::Timers::DisplayTime(idx) 194 | { 195 | return ::VSLib.Utils.GetDisplayTime(::VSLib.Timers.ReadTimer(idx)); 196 | } 197 | 198 | /** 199 | * Manages all timers and provides interface for custom updates. 200 | */ 201 | ::VSLib.Timers._thinkFunc <- function() 202 | { 203 | if (!("VSLib" in getroottable())) 204 | return; 205 | 206 | local TIMER_FLAG_COUNTDOWN = (1 << 2); 207 | local TIMER_FLAG_DURATION_VARIANT = (1 << 4); 208 | 209 | // current time 210 | local curtime = Time(); 211 | 212 | // Execute timers as needed 213 | foreach (idx, timer in ::VSLib.Timers.TimersList) 214 | { 215 | if ((curtime - timer._startTime) >= timer._delay) 216 | { 217 | if (timer._flags & TIMER_FLAG_COUNTDOWN) 218 | { 219 | timer._params["TimerCount"] <- timer._opval["count"]; 220 | 221 | if ((--timer._opval["count"]) <= 0) 222 | timer._repeat = false; 223 | } 224 | 225 | if (timer._flags & TIMER_FLAG_DURATION_VARIANT && (curtime - timer._baseTime) > timer._opval["duration"]) 226 | { 227 | delete ::VSLib.Timers.TimersList[idx]; 228 | continue; 229 | } 230 | 231 | try 232 | { 233 | if (timer._func(timer._params) == false) 234 | timer._repeat = false; 235 | } 236 | catch (id) 237 | { 238 | printf("VSLib Timer caught exception; closing timer %d. Error was: %s", idx, id.tostring()); 239 | local deadFunc = timer._func; 240 | local params = timer._params; 241 | delete ::VSLib.Timers.TimersList[idx]; 242 | deadFunc(params); // this will most likely throw 243 | continue; 244 | } 245 | 246 | if (timer._repeat) 247 | timer._startTime = curtime; 248 | else 249 | if (idx in ::VSLib.Timers.TimersList) // recheck-- timer may have been removed by timer callback 250 | delete ::VSLib.Timers.TimersList[idx]; 251 | } 252 | } 253 | foreach (idx, timer in ::VSLib.Timers.ClockList) 254 | { 255 | if ( Time() > timer._lastUpdateTime ) 256 | { 257 | local newTime = Time() - timer._lastUpdateTime; 258 | 259 | if ( timer._command == 1 ) 260 | timer._value += newTime; 261 | else if ( timer._command == 2 ) 262 | { 263 | if ( timer._allowNegTimer ) 264 | timer._value -= newTime; 265 | else 266 | { 267 | if ( timer._value > 0 ) 268 | timer._value -= newTime; 269 | } 270 | } 271 | 272 | timer._lastUpdateTime <- Time(); 273 | } 274 | } 275 | } 276 | 277 | /* 278 | * Create a think timer 279 | */ 280 | if (!("_thinkTimer" in ::VSLib.Timers)) 281 | { 282 | ::VSLib.Timers._thinkTimer <- SpawnEntityFromTable("info_target", { targetname = "vslib_timer" }); 283 | if (::VSLib.Timers._thinkTimer != null) 284 | { 285 | ::VSLib.Timers._thinkTimer.ValidateScriptScope(); 286 | local scrScope = ::VSLib.Timers._thinkTimer.GetScriptScope(); 287 | scrScope["ThinkTimer"] <- ::VSLib.Timers._thinkFunc; 288 | AddThinkToEnt(::VSLib.Timers._thinkTimer, "ThinkTimer"); 289 | } 290 | else 291 | throw "VSLib Error: Timer system could not be created; Could not create dummy entity"; 292 | } 293 | 294 | 295 | // Add a weakref 296 | ::Timers <- ::VSLib.Timers.weakref(); -------------------------------------------------------------------------------- /vscripts/LinGe/zs.nut: -------------------------------------------------------------------------------- 1 | // 自杀功能脚本 2 | ::LinGe.zs <- {}; 3 | 4 | ::LinGe.zs.Config <- { 5 | enabled = true, 6 | hint = true, 7 | incap = "我不想变成魔女,这个世界还有许多我想守护的东西", 8 | noIncap = "灵魂宝石会孕育出魔女的话,大家不就只有去死了吗!" 9 | }; 10 | ::LinGe.Config.Add("zs", ::LinGe.zs.Config); 11 | //::LinGe.Cache.zs_Config <- ::LinGe.zs.Config; 12 | 13 | if (!::LinGe.isVersus && ::LinGe.zs.Config.enabled) { 14 | printl("[LinGe] 自杀指令 正在载入"); 15 | // !zs 自杀指令 16 | ::LinGe.zs.Cmd_zs <- function (player, args) 17 | { 18 | if (args.len() == 1) 19 | { 20 | if (::LinGe.GetPlayerTeam(player) != 2) 21 | return; 22 | 23 | local vplayer = ::VSLib.Player(player); 24 | if (!vplayer.IsPlayerEntityValid()) 25 | return; 26 | if (!vplayer.IsAlive() || vplayer.IsDead()) 27 | return; 28 | 29 | local isIncapacitated = vplayer.IsIncapacitated(); 30 | vplayer.Kill(); 31 | if (Config.hint) // 如果开启了自杀后提示 32 | { 33 | if (!vplayer.IsAlive() || vplayer.IsDead()) // 可能不准 34 | { 35 | if (isIncapacitated) 36 | { 37 | Say(player, "\x03" + Config.incap, false); 38 | } 39 | else 40 | { 41 | Say(player, "\x03" + Config.noIncap, false); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | ::LinCmdAdd("zs", ::LinGe.zs.Cmd_zs, ::LinGe.zs, "自杀指令", false); 48 | 49 | } -------------------------------------------------------------------------------- /vscripts/director_base_addon.nut: -------------------------------------------------------------------------------- 1 | IncludeScript("LinGe/VSLib"); // 必须 VSLib库 2 | IncludeScript("LinGe/Base"); // 必须 基础库 注册事件函数,实现了玩家人数统计、命令与权限管理 3 | // 请不要更改必须库的载入顺序,否则将无法正确载入脚本 4 | IncludeScript("LinGe/HUD"); // 可选 HUD 击杀与伤害统计 友伤提示等 5 | IncludeScript("LinGe/MoreSI"); // 可选 简易的多特控制 6 | IncludeScript("LinGe/zs"); // 可选 自杀指令 7 | IncludeScript("LinGe/Hint"); // 可选 玩家状态提示与物品标记功能 8 | IncludeScript("LinGe/RewardHP"); // 可选 击杀回复血量 -------------------------------------------------------------------------------- /vscripts/scriptedmode_addon.nut: -------------------------------------------------------------------------------- 1 | // 这个只是拿AdminSystem里的同名文件改了一下函数名字 2 | // 这个文件是必须的,且文件名不能随意更改,否则脚本无法正常工作 3 | // 我不太清楚这个的具体作用,因为对求生之路的游戏机制还不是特别了解 4 | 5 | /////////////////////////////////////////////////////////////////////////////// 6 | // Scriptedmode.nut 7 | // this holds the "control logic" for all scriptmodes, and loads up the Mode 8 | // and Map specific subscripts thus it has various initialization, 9 | // default/override table merging, and a "root" manager class 10 | /////////////////////////////////////////////////////////////////////////////// 11 | 12 | LinGe_ScriptMode_Init <- ScriptMode_Init; 13 | //========================================================= 14 | // called from C++ when you try and kick off a mode to 15 | // decide whether scriptmode wants to handle it 16 | //========================================================= 17 | function ScriptMode_Init( modename, mapname ) 18 | { 19 | local bScriptedModeValid = LinGe_ScriptMode_Init( modename, mapname ); 20 | 21 | //Include server.nut for LinGe Scripts 22 | IncludeScript("server"); 23 | 24 | if ( !bScriptedModeValid ) 25 | { 26 | printl( "Enabled ScriptMode for " + modename + " and now Initializing" ); 27 | 28 | IncludeScript( mapname + "_" + modename, g_MapScript ); 29 | 30 | // Add to the spawn array 31 | MergeSessionSpawnTables(); 32 | MergeSessionStateTables(); 33 | 34 | SessionState.MapName <- mapname; 35 | SessionState.ModeName <- modename; 36 | 37 | // If not specified, start active by default 38 | if ( !( "StartActive" in SessionState ) ) 39 | { 40 | SessionState.StartActive <- true; 41 | } 42 | 43 | if ( SessionState.StartActive ) 44 | { 45 | MergeSessionOptionTables(); 46 | } 47 | 48 | // Sanitize the map 49 | if ( "SanitizeTable" in this ) 50 | { 51 | SanitizeMap( SanitizeTable ); 52 | } 53 | 54 | if ( "SessionSpawns" in getroottable() ) 55 | { 56 | EntSpawn_DoIncludes( ::SessionSpawns ); 57 | } 58 | 59 | // include all helper stuff before building the help 60 | IncludeScript( "sm_stages", g_MapScript ); 61 | 62 | // check for any scripthelp_ strings and create help entries for them 63 | AddToScriptHelp( getroottable() ); 64 | AddToScriptHelp( g_MapScript ); 65 | AddToScriptHelp( g_ModeScript ); 66 | 67 | // go ahead and call all the precache elements - the MapSpawn table ones then any explicit OnPrecache's 68 | ScriptedPrecache(); 69 | ScriptMode_SystemCall("Precache"); 70 | } 71 | 72 | return true; 73 | } --------------------------------------------------------------------------------