├── README.md ├── configs └── advertisements.txt ├── extensions ├── defibfix.autoload ├── defibfix.ext.dll ├── defibfix.ext.so ├── l4d2_bugfixes.autoload ├── l4d2_bugfixes.ext.dll └── l4d2_bugfixes.ext.so ├── gamedata ├── defibfix.txt ├── l4d2_bugfixes.txt ├── l4d2_selfstandup.txt ├── l4d_survivor_identity_fix.txt ├── l4dmultislots.txt ├── survivor_afk_fix.txt ├── upgradepackfix.txt └── wdnmd_fix.txt ├── scripting ├── MeleeInTheSafeRoom.sp ├── advertisements.sp ├── advertisements │ ├── chatcolors.sp │ └── topcolors.sp ├── all4dead2.sp ├── fftlite.sp ├── hostname.sp ├── include │ ├── colorvariables.inc │ └── updater.inc ├── kill_counter.sp ├── l4d2_WeaponUnlock.sp ├── l4d2_bwa_simplesupply.sp ├── l4d2_drop.sp ├── l4d2_friendlyfireinfo.sp ├── l4d2_infiniteammo.sp ├── l4d2_mapcontrol.sp ├── l4d2_riotcopheadshot.sp ├── l4d2_selfstandup.sp ├── l4d2_survivorai_triggerfix.sp ├── l4d2_upgradepackfix.sp ├── l4d_gear_transfer.sp ├── l4d_infectedhp.sp ├── l4d_kill.sp ├── l4d_nightvision.sp ├── l4d_randomize_tank_witch_settings.sp ├── l4d_stuckzombiemeleefix.sp ├── l4d_survivor_identity_fix.sp ├── l4d_survivorai_pouncedfix.sp ├── l4dcsm_a.sp ├── l4dmultislots.sp ├── lfd_both_fixUpgradePack.sp ├── playerinfo.sp ├── survivor_afk_fix.sp ├── sv_steamgroup_fixer.sp ├── tickrate.sp └── wdnmd.sp └── translations ├── chi └── gear_transfer.phrases.txt ├── da └── gear_transfer.phrases.txt ├── de └── gear_transfer.phrases.txt ├── es └── gear_transfer.phrases.txt ├── gear_transfer.phrases.txt ├── pt └── gear_transfer.phrases.txt ├── ru └── gear_transfer.phrases.txt └── zho └── gear_transfer.phrases.txt /README.md: -------------------------------------------------------------------------------- 1 | # SouceModPlugins For L4D2 2 | **L4D2 服务器搭建(Linux)** 3 | 4 | 之前 Windows 的:https://www.jianshu.com/p/52c1635876e7 5 | 6 | ## 安装 SteamCMD 7 | https://developer.valvesoftware.com/wiki/SteamCMD#Linux 8 | ``` 9 | dpkg --add-architecture i386 10 | apt update 11 | apt install lib32gcc1 -y 12 | apt install steamcmd -y 13 | ``` 14 | 15 | ## 安装/更新服务器 16 | 运行 `steamcmd` 17 | 18 | ``` 19 | login anonymous 20 | force_install_dir /data/syncthing/L4D2Server 21 | app_update 222860 validate 22 | quit 23 | ``` 24 | 25 | 其中 `/data/syncthing/L4D2Server` 为下载路径 26 | 27 | ## SourceMod、Metamod、L4DToolZ 插件 28 | ### 下载 29 | #### SourceMod 30 | SourceMod 官网:https://www.sourcemod.net/ 31 | 32 | SourceMod 稳定版下载:https://www.sourcemod.net/downloads.php?branch=stable 33 | 34 | 当然下载 Linux 版的 35 | 36 | #### Metamod 37 | Metamod官网:https://www.sourcemm.net/ 38 | 39 | 当然不要忘记生成对应游戏的VDF文件:https://www.sourcemm.net/vdf 40 | 41 | #### L4DToolZ 42 | L4DToolZ:https://forums.alliedmods.net/showthread.php?t=93600 43 | 44 | L4DToolZ的GitHub:https://github.com/ivailosp/l4dtoolz/ 45 | 46 | L4D2的是下1.0.0.9h版本 47 | 48 | **总共是4份文件** 49 | 50 | ### 安装 51 | 52 | ~~安装顺序是无所谓的~~ 53 | 54 | #### Metamod 55 | 将 `mmsource-1.10.7-git971-linux.tar.gz` 的addons解压出来与 `./left4dead2/addons/` 合并 56 | 57 | 再将之前生成的 `metamod.vdf` 覆盖addons里的 `metamod.vdf` ~~(这个文件其实就是个路径设置)~~ 58 | 59 | #### SourceMod 60 | 同理将 `sourcemod-1.10.0-git6497-linux.tar.gz` 里的 `addons` 和 `cfg` 与`./left4dead2/addons/`和 `./left4dead2/cfg/` 合并 61 | 62 | #### L4DToolZ 63 | 将 `l4dtoolz(L4D2)-1.0.0.9h.zip` 里的两个文件夹 `l4dtoolz` 和 `metamod` 放到 `./left4dead2/addons/` 里。 64 | 65 | ### 简单运行 66 | `./srcds_run -game left4dead2 -insecure +maxplayers 16 +hostport 27015 +map c1m2_streets` 67 | 68 | 命令行参数详见:https://developer.valvesoftware.com/wiki/Command_Line_Options 69 | 70 | 在 Console 里输入 `meta list` 71 | ``` 72 | meta list 73 | Listing 3 plugins: 74 | [01] SourceMod (1.10.0.6497) by AlliedModders LLC 75 | [02] L4DToolZ (1.0.0.9h-2-g7465d71b-dirty) by Ivailosp 76 | [03] SDK Tools (1.10.0.6497) by AlliedModders LLC 77 | ``` 78 | 像这样就安装成功了 79 | 80 | ### 简单更改服务器最大人数 81 | 输入命令: 82 | 83 | `sm_cvar sv_maxplayers 16;sm_cvar sv_visiblemaxplayers 16` 84 | 85 | 当然这些命令可以预先放到 `./left4dead2/cfg/server.cfg` 里。 86 | 87 | ### 简单设置权限 88 | * 在 `./left4dead2/addons/sourcemod/configs/admins_simple.ini` 里的增加一行 89 | 90 | `"STEAM_1:1:125637774" "99:z" "passwd"` 91 | 92 | 第一个引号是 steamID 或者是 Steam 个人资料名(游戏里的名字);第二个引号是权限大小;第三个引号是密码。具体说明文件里都有。 93 | 94 | * 然后到同一目录下的`core.cfg`里修改 95 | 96 | `"PassInfoVar" "_password"` 97 | 98 | * 想要成功获得服务器的权限还要在进游戏前在游戏的控制台输入 99 | 100 | `setinfo _password passwd` 101 | 102 | 当然可以放进你游戏目录里的 `./left4dead2/cfg/autoexec.cfg` 里,这样每次运行游戏时就会自动执行这条命令 103 | 104 | ### 服务器欢迎界面设置 105 | 大图:`./left4dead2/motd.txt` 106 | 107 | 小图:`./left4dead2/host.txt` 108 | 109 | ### SourceMod 插件安装 110 | 一般到 http://www.sourcemod.net/plugins.php 搜索下载,按照作者说明来就行了 111 | 112 | 推荐下载源码自己用 `./left4dead2/addons/sourcemod/scripting/compile.sh` 编译 113 | 114 | 这里用 `gettickrate` 插件演示 115 | 116 | * 找到插件并下载源码 https://forums.alliedmods.net/showthread.php?p=649755 117 | * 将 `tickrate.sp` 放入 `./left4dead2/addons/sourcemod/scripting/` 里 118 | * 运行 `./compile.sh tickrate.sp` ,插件编译成功后会在 `compiled` 文件夹里生成 `tickrate.smx` 119 | * 将 `tickrate.smx` 放到 `./left4dead2/addons/sourcemod/plugins/` 里就算安装成功了 120 | * 有些插件需要放 `data` 到指定文件夹(往往是放同时兼容 Windows/Linux 服务器的参数),自己认真看作者的插件说明。 121 | * 一般要服务器运行一次后自动生成该插件所需cfg文件到 `./left4dead2/cfg/sourcemod/`。当然这个插件功能简单就没有生成~ 122 | 123 | 输入 `sm_gettickrate`,得到返回 124 | ``` 125 | The server tickrate is 29 126 | ``` 127 | 128 | 当然你可以修改 `compile.sh` 直接编译生成到 `plugins` 里 129 | 130 | #### 服务器Tickrate修改 131 | 上次搞 Windows 服务器的时候是2017年1月,没想到论坛7月份就有接盘侠搞了个新的: 132 | https://forums.alliedmods.net/showthread.php?t=299669 133 | 134 | 下载 `tickrate_enabler.zip` 135 | 136 | * 将对应文件解压放入 `addons` 文件夹 137 | * 运行时加上参数 `-tickrate 100` 138 | 139 | 别忘 `server.cfg` 加上几个参数,比如 `sv_minrate、sv_maxrate、sv_maxupdaterate、sv_maxcmdrate、fps_max` 之类的 140 | 141 | 输入 `sm_gettickrate`,得到返回 142 | ``` 143 | The server tickrate is 100 144 | ``` 145 | 146 | #### 修改服务器名为中文名 147 | https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/hostname.sp 148 | 149 | 上面一样的方法下载编译插件,之后直接在 `/left4dead2/addons/sourcemod/configs/hostname/hostname.txt` 150 | 修改,保存为UTF-8,好像无所谓带不带BOM 151 | 152 | #### 修复 Steam 组链接错误 153 | 154 | 组 ID 大于 16777216 的话进入服务器显示封面跳转的链接会跳转到错误的组,熟悉这个数字的朋友一看就知道为什么了 155 | 156 | https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/sv_steamgroup_fixer.sp 157 | 158 | #### 其他自用插件 159 | 插件名|下载链接|描述 160 | -|-|- 161 | Melee In The Saferoom|https://forums.alliedmods.net/showpost.php?p=2719073&postcount=494|安全屋生成近战 162 | Advertisements|https://forums.alliedmods.net/showthread.php?p=592536| 163 | Director Controller (All4Dead)|https://forums.alliedmods.net/showthread.php?p=751952|自用 https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/all4dead2.sp 164 | Friendly-Fire Toolkit Lite|https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/fftlite.sp|反伤插件 165 | Infinite-Jumping|https://github.com/chanz/infinite-jumping|连跳、多段跳,编译需要 https://github.com/bcserv/smlib 166 | L4D2 Friendly-Fire info|https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/l4d2_friendlyfireinfo.sp|显示友伤信息 167 | Gear Transfer|https://forums.alliedmods.net/showthread.php?p=1294082|R 键给物品、Bot自动给物品 168 | Infected Health Gauge (Tank & Witch & Special)|https://forums.alliedmods.net/showthread.php?p=1167221|显示特感伤害 169 | Night Vision|https://forums.alliedmods.net/showthread.php?p=1534293|双击F夜视 170 | Randomize Tank Witch HP and Speed|https://forums.alliedmods.net/showthread.php?p=1076665|更改 Tank、Witch 的血量和移速 171 | Stuck Zombie Melee Fix|https://forums.alliedmods.net/showthread.php?p=932416|Bug 修复 172 | Survivor Identity Fix for 5+ Survivors|https://forums.alliedmods.net/showpost.php?p=2718792&postcount=36|Bug 修复,需要 [DHooks extension with detour support](https://forums.alliedmods.net/showpost.php?p=2588686&postcount=589) 173 | 自杀插件|https://forums.alliedmods.net/showthread.php?p=2107510|输入 !kill 或者 !explode 自杀 174 | Riot Cop (and Fallen Survivor) Head Shot|https://forums.alliedmods.net/showthread.php?p=1626951|城管正面爆头可击杀 175 | self stand up|https://forums.alliedmods.net/showthread.php?p=1795311|倒地自起,与 l4d_incapcrawl 插件冲突 176 | Survivor AI Trigger fix|https://forums.alliedmods.net/showthread.php?p=1004836|全 Bot 队伍 177 | Upgrade Pack Fixes|https://forums.alliedmods.net/showthread.php?p=2690901|多人配件 Bug 修复 178 | Weapon Unlock|https://forums.alliedmods.net/showthread.php?p=1041458|武器解锁已经不需要了,但可以修改伤害 179 | Survivor_AFK_Fix|https://forums.alliedmods.net/showthread.php?p=2714236|AFK BUG 修复,需要 [DHooks extension with detour support](https://forums.alliedmods.net/showpost.php?p=2588686&postcount=589) 180 | MultiSlots|https://forums.alliedmods.net/showpost.php?p=2715546&postcount=249|多人 Bot 管理 181 | Character Select Menu|https://forums.alliedmods.net/showthread.php?t=107121|换角色或者外观 182 | 白给插件|https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/wdnmd.sp|反编译望夜的 rygive.smxs,还需要放置 gamedata 183 | 玩家进入离开提示|https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/playerinfo.sp| 184 | l4d2_defibfix|https://github.com/Accelerator74/l4d2_defibfix|修复电击器电错人的 bug 185 | l4d2_bugfixes|https://github.com/Accelerator74/l4d2_bugfixes|修复生还者分数统计 Bug 和 Witch 攻击错人的bug 186 | Survivor Bot AI SHOOT IT FFS Fix|https://forums.alliedmods.net/showthread.php?p=893326|修复求生之路的人工智障 187 | Weapon Drop|https://forums.alliedmods.net/showthread.php?t=123098|主动丢武器 188 | kill_counter|https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/kill_counter.sp|击杀统计 189 | MapControl|https://github.com/HMBSbige/SouceModPlugins/blob/master/scripting/l4d2_mapcontrol.sp|换图 190 | Simple Supply|https://forums.alliedmods.net/showthread.php?p=1413057|安全屋正确生成补给 191 | -------------------------------------------------------------------------------- /configs/advertisements.txt: -------------------------------------------------------------------------------- 1 | // Advertisements 2.0 2 | // by Tsunami 3 | // 4 | // Types 5 | // ----- 6 | // center: Center message 7 | // chat: Chat message 8 | // hint: Hint message 9 | // menu: Menu message 10 | // top: Top message 11 | // 12 | // Flags (optional) 13 | // ----- 14 | // Accepts flags of admins that will not see the advertisement. 15 | // When omitted everyone will see the advertisement. 16 | // When left empty only admins will see the advertisement. 17 | 18 | "Advertisements" 19 | { 20 | "1" 21 | { 22 | "center" "www.domain.com" 23 | } 24 | "2" 25 | { 26 | "center" "contact@domain.com" 27 | "hint" "contact@domain.com" 28 | } 29 | "3" 30 | { 31 | "menu" "Next map is {sm_nextmap} in {timeleft} minutes." 32 | "flags" "cft" 33 | } 34 | "4" 35 | { 36 | "chat" "{green}Current {lightgreen}Map: {default}{currentmap}" 37 | "flags" "z" 38 | } 39 | "5" 40 | { 41 | "top" "{orange}Admins: friendly fire is {mp_friendlyfire}." 42 | "flags" "" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /extensions/defibfix.autoload: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMBSbige/SouceModPlugins/2fbba501b6110f0265919f98d357c3350f24c9a7/extensions/defibfix.autoload -------------------------------------------------------------------------------- /extensions/defibfix.ext.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMBSbige/SouceModPlugins/2fbba501b6110f0265919f98d357c3350f24c9a7/extensions/defibfix.ext.dll -------------------------------------------------------------------------------- /extensions/defibfix.ext.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMBSbige/SouceModPlugins/2fbba501b6110f0265919f98d357c3350f24c9a7/extensions/defibfix.ext.so -------------------------------------------------------------------------------- /extensions/l4d2_bugfixes.autoload: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMBSbige/SouceModPlugins/2fbba501b6110f0265919f98d357c3350f24c9a7/extensions/l4d2_bugfixes.autoload -------------------------------------------------------------------------------- /extensions/l4d2_bugfixes.ext.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMBSbige/SouceModPlugins/2fbba501b6110f0265919f98d357c3350f24c9a7/extensions/l4d2_bugfixes.ext.dll -------------------------------------------------------------------------------- /extensions/l4d2_bugfixes.ext.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HMBSbige/SouceModPlugins/2fbba501b6110f0265919f98d357c3350f24c9a7/extensions/l4d2_bugfixes.ext.so -------------------------------------------------------------------------------- /gamedata/defibfix.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "left4dead2" 4 | { 5 | "Signatures" 6 | { 7 | "GetPlayerByCharacter" 8 | { 9 | "library" "server" 10 | "windows" "\x55\x8b\xec\x8b\x45*\x83\xec*\x83\xf8\x08\x75*\x33\xc0\x8b\xe5\x5d\xc3" 11 | "linux" "@_ZN13CTerrorPlayer20GetPlayerByCharacterE21SurvivorCharacterType" 12 | } 13 | "DefibrillatorOnStartAction" 14 | { 15 | "library" "server" 16 | "windows" "\x55\x8B\xEC\xD9\xEE\x53\x56\x57\x8B\x7D\x0C" 17 | "linux" "@_ZN18CItemDefibrillator13OnStartActionEN17CBaseBackpackItem22BackpackItemActionTypeEP13CTerrorPlayerP11CBaseEntityf" 18 | } 19 | "DefibrillatorOnActionComplete" 20 | { 21 | "library" "server" 22 | "windows" "\x55\x8b\xec\x8b\x45*\x56\x6a\x00\x68****\x68****\x6a\x00\x50\xe8****\x8b\xf0" 23 | "linux" "@_ZN18CItemDefibrillator16OnActionCompleteEP13CTerrorPlayerP11CBaseEntity" 24 | } 25 | "CSurvivorDeathModel::Create" 26 | { 27 | "library" "server" 28 | "windows" "\x55\x8b\xec\x57\x8b\x7d\x08\x85\xff\x75*\x33\xc0\x5f\x5d\xc3\x8b\x87" 29 | "linux" "@_ZN19CSurvivorDeathModel6CreateEP13CTerrorPlayer" 30 | } 31 | "CBaseEntity::SetAbsOrigin" 32 | { 33 | "library" "server" 34 | "windows" "\x55\x8b\xec\x83\xec*\xa1****\x33\xc5\x89\x45*\x56\x57\x8b\x7d\x08\x8b\xf1\xe8****\xf3\x0f\x10\x07" 35 | "linux" "@_ZN11CBaseEntity12SetAbsOriginERK6Vector" 36 | } 37 | } 38 | } 39 | } 40 | 41 | -------------------------------------------------------------------------------- /gamedata/l4d2_bugfixes.txt: -------------------------------------------------------------------------------- 1 | /* created by V10 aka maldersoft */ 2 | "Games" 3 | { 4 | "left4dead2" 5 | { 6 | "Addresses" 7 | { 8 | "CDirector" 9 | { 10 | "windows" 11 | { 12 | "signature" "DirectorMusicBanks::OnRoundStart" 13 | "read" "12" 14 | } 15 | "linux" 16 | { 17 | "signature" "TheDirector" 18 | } 19 | } 20 | } 21 | "Offsets" 22 | { 23 | "WitchAttackCharaster" 24 | { 25 | "windows" "14" 26 | "linux" "14" 27 | } 28 | "SurvivorCounters" 29 | { 30 | "windows" "1072" 31 | "linux" "1068" 32 | } 33 | } 34 | "Signatures" 35 | { 36 | "WitchAttack::WitchAttack" 37 | { 38 | "library" "server" 39 | "windows" "\x55\x8B\xEC\x53\x56\x8B\xF1\xC7\x46\x04****\xC7\x46\x2C\x01\x00\x00\x00\x33\xDB\x33\xC0\x89\x46*\x33\xC9\x89\x4E*\x57\x33\xD2\x89\x56*\x33\xFF\x89\x5E*\x89\x5E*\x89\x5E*\x89\x5E*\x89\x5E*\x89\x5E*\x66\x89\x5E*\x89\x7E*\xC7\x06****\xC7\x46\x04****\x53" 40 | "linux" "@_ZN11WitchAttackC2EP11CBaseEntity" 41 | } 42 | "WitchAttack::GetVictim" 43 | { 44 | "library" "server" 45 | "windows" "\x8B\x41\x38\x83\xF8\x08\x75\x2A\x8B\x41\x34\x83\xF8\xFF\x74\x1F" 46 | "linux" "@_ZNK11WitchAttack9GetVictimEv" 47 | } 48 | "CCharge::HandleCustomCollision_code" 49 | { 50 | "library" "server" 51 | "windows" "\x0f\x85***\x00\xc6\x00\x01\x8b\x15****\xf3\x0f\x10\x42*\xf3\x0f\x59\xc0\x0f" 52 | "linux" "\x0F\x85**\xFF\xFF\xC6\x84****\x00\x01\xF3\x0F\x58\xC1\xA1****\xF3\x0F\x58\xC2\xF3" 53 | } 54 | "CCharge::HandleCustomCollision" 55 | { 56 | "library" "server" 57 | "windows" "\x55\x8b\xec\x81\xec**\x00\x00\xa1****\x33\xc5\x89\x45*\x8b\x45*\x53\x8b\xd9\x89\x45*\x8b\x83**\x00\x00\x56\x8b\x75" 58 | "linux" "@_ZN7CCharge21HandleCustomCollisionEP11CBaseEntityRK6VectorS4_P10CGameTraceP9CMoveData" 59 | } 60 | "CTerrorGameRules::CalculateSurvivalMultiplier" 61 | { 62 | "library" "server" 63 | "windows" "\x55\x8b\xec\x83\xec*\x80\x7d*\x00\x53\x56\x8b\xd9\x0f\x84**\x00\x00" 64 | "linux" "@_ZN16CTerrorGameRules27CalculateSurvivalMultiplierEb" 65 | } 66 | "TheDirector" 67 | { 68 | "library" "server" 69 | "linux" "@TheDirector" 70 | } 71 | "DirectorMusicBanks::OnRoundStart" 72 | { 73 | "library" "server" 74 | "windows" "\x55\x8b\xec\x83\xec*\x56\x57\x8b\xf9\x8b\x0d****\xe8****\x84\xc0\x0f\x85" 75 | } 76 | "CDirector::AreTeamsFlipped" 77 | { 78 | "library" "server" 79 | "windows" "\x57\x8b\xf9\xe8****\x84\xc0\x75*\xf7\x05*******\x00\x56\x74*\xbe" 80 | "linux" "@_ZNK9CDirector15AreTeamsFlippedEv" 81 | } 82 | "CDirector::AllowWitchesInCheckpoints" 83 | { 84 | "library" "server" 85 | "windows" "\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x84\xC0\x75\x2A\xE8" 86 | "linux" "@_ZNK9CDirector25AllowWitchesInCheckpointsEv" 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /gamedata/l4d2_selfstandup.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "left4dead2" 4 | { 5 | "Signatures" 6 | { 7 | "CTerrorPlayer::OnPummelEnded" 8 | { 9 | "library" "server" 10 | "windows" "\x55\x8B\xEC\x8B\x15\x2A\x2A\x2A\x2A\x53\x56\x8B\xF1\x8B" 11 | "linux" "@_ZN13CTerrorPlayer13OnPummelEndedEbPS_" 12 | } 13 | "CTerrorPlayer::OnPounceEnd" 14 | { 15 | "library" "server" 16 | "windows" "\x55\x8B\xEC\x51\x53\x8B\xD9\x80\xBB" 17 | "linux" "@_ZN13CTerrorPlayer13OnPounceEndedEv" 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /gamedata/l4d_survivor_identity_fix.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "left4dead" 4 | { 5 | "Signatures" 6 | { 7 | "CBasePlayer::SetModel" 8 | { 9 | "library" "server" 10 | "linux" "@_ZN11CBasePlayer8SetModelEPKc" 11 | "windows" "\x8B\x2A\x2A\x2A\x56\x57\x50\x8B\x2A\xE8\x2A\x2A\x2A\x2A\x8B\x3D" 12 | "mac" "@_ZN11CBasePlayer8SetModelEPKc" 13 | } 14 | } 15 | } 16 | "left4dead2" 17 | { 18 | "Signatures" 19 | { 20 | "CBasePlayer::SetModel" 21 | { 22 | "library" "server" 23 | "linux" "@_ZN11CBasePlayer8SetModelEPKc" 24 | "windows" "\x55\x8B\x2A\x8B\x2A\x2A\x56\x57\x50\x8B\x2A\xE8\xC0\x7B" 25 | "mac" "@_ZN11CBasePlayer8SetModelEPKc" 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /gamedata/l4dmultislots.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "left4dead" 4 | { 5 | "Signatures" 6 | { 7 | 8 | "SetHumanSpec" 9 | { 10 | "library" "server" 11 | "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" 12 | "windows" "\x53\x8B\xD9\x83\x2A\x2A\x2A\x2A\x2A\x2A\x56\x8D\x2A\x2A\x2A\x2A\x2A\x7E\x07\x5E\x32\xC0\x5B\xC2\x04\x00" 13 | } 14 | 15 | "TakeOverBot" 16 | { 17 | "library" "server" 18 | "linux" "@_ZN13CTerrorPlayer11TakeOverBotEb" 19 | "windows" "\x81\x2A\x2A\x2A\x2A\x2A\x53\x55\x56\x57\x8D\x2A\x2A\x2A\x8B\xF9\x33\xDB\x50" 20 | } 21 | } 22 | } 23 | 24 | "left4dead2" 25 | { 26 | "Signatures" 27 | { 28 | 29 | "SetHumanSpec" 30 | { 31 | "library" "server" 32 | "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" 33 | "windows" "\x55\x8B\xEC\x56\x8B\xF1\x83\xBE\x2A\x2A\x2A\x2A\x00\x7E\x07\x32\xC0\x5E\x5D\xC2\x04\x00\x8B\x0D" 34 | /* 55 8B EC 56 8B F1 83 BE 44 43 00 00 00 7E 07 32 C0 5E 5D C2 04 */ 35 | } 36 | 37 | "TakeOverBot" 38 | { 39 | "library" "server" 40 | "linux" "@_ZN13CTerrorPlayer11TakeOverBotEb" 41 | "windows" "\x55\x8B\xEC\x81\xEC\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x33\xC5\x89\x45\xFC\x53\x56\x8D\x85" 42 | /* 55 8B EC 81 EC ? ? ? ? ? ? ? ? ? ? ? ? ? ? 53 56 8D 85 */ 43 | } 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /gamedata/survivor_afk_fix.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "#default" 4 | { 5 | "Functions" 6 | { 7 | "CTerrorPlayer::GoAwayFromKeyboard" 8 | { 9 | "signature" "CTerrorPlayer::GoAwayFromKeyboard" 10 | "callconv" "thiscall" 11 | "return" "void" 12 | "this" "entity" 13 | } 14 | "SurvivorBot::SetHumanSpectator" 15 | { 16 | "signature" "SurvivorBot::SetHumanSpectator" 17 | "callconv" "thiscall" 18 | "return" "void" 19 | "this" "entity" 20 | "arguments" 21 | { 22 | "AFKPlayer" 23 | { 24 | "type" "cbaseentity" 25 | } 26 | } 27 | } 28 | } 29 | } 30 | "left4dead2" 31 | { 32 | "Signatures" 33 | { 34 | "CTerrorPlayer::GoAwayFromKeyboard" 35 | { 36 | "library" "server" 37 | "linux" "@_ZN13CTerrorPlayer18GoAwayFromKeyboardEv" 38 | "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x53\x56\x57\x8B\xF1\x8B\x06\x8B\x90\xC8\x08\x00\x00" 39 | /* ? ? ? ? ? ? 53 56 57 8B F1 8B 06 8B 90 C8 08 00 00 */ 40 | } 41 | "SurvivorBot::SetHumanSpectator" 42 | { 43 | "library" "server" 44 | "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" 45 | "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x83\xBE\x44\x43\x00\x00\x00\x7E\x2A\x32\xC0\x5E\x5D\xC2\x04\x00" 46 | /* ? ? ? ? ? ? 83 BE 44 43 00 00 00 7E ? 32 C0 5E 5D C2 04 00 */ 47 | } 48 | } 49 | "Offsets" 50 | { 51 | "CTerrorPlayer::SetObserverTarget" 52 | { 53 | "linux" "403" 54 | "windows" "402" 55 | } 56 | } 57 | } 58 | "left4dead" 59 | { 60 | "Signatures" 61 | { 62 | "CTerrorPlayer::GoAwayFromKeyboard" 63 | { 64 | "library" "server" 65 | "linux" "@_ZN13CTerrorPlayer18GoAwayFromKeyboardEv" 66 | "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x8B\xF1\x8B\x06\x8B\x90\xB8\x07\x00\x00" 67 | /* ? ? ? ? ? ? 8B F1 8B 06 8B 90 B8 07 00 00 */ 68 | } 69 | "SurvivorBot::SetHumanSpectator" 70 | { 71 | "library" "server" 72 | "linux" "@_ZN11SurvivorBot17SetHumanSpectatorEP13CTerrorPlayer" 73 | "windows" "\x2A\x2A\x2A\x2A\x2A\x2A\x2E\x00\x00\x00\x56\x8D\xB3\x80\x2E\x00\x00" 74 | /* ? ? ? ? ? ? 2E 00 00 00 56 8D B3 80 2E 00 00 */ 75 | } 76 | } 77 | "Offsets" 78 | { 79 | "CTerrorPlayer::SetObserverTarget" 80 | { 81 | "linux" "376" 82 | "windows" "375" 83 | } 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /gamedata/upgradepackfix.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "left4dead2" 4 | { 5 | "Offsets" 6 | { 7 | // found on CBaseUpgradeItem::Use 8 | // 9 | //.text:008C4543 call _ZN16CBaseUpgradeItem20MarkAsUsedBySurvivorE21SurvivorCharacterType ; CBaseUpgradeItem::MarkAsUsedBySurvivor(SurvivorCharacterType) 10 | //.text:008C4548 mov eax, [edi+1440h] 11 | //.text:008C454E sub eax, 1 12 | //.text:008C4551 mov [edi+1440h], eax 13 | 14 | "m_iUpgradePackCanUseCount" 15 | { 16 | "windows" "5188" 17 | "linux" "5196" 18 | } 19 | 20 | } 21 | "Signatures" 22 | { 23 | "CTerrorPlayer::FindUseEntity" 24 | { 25 | "library" "server" 26 | "windows" "\x55\x8B\xEC\xB8**\x00\x00\xE8****\xA1****\x33\xC5\x89\x45*\x0F\x57\xC9" 27 | "linux" "@_ZN13CTerrorPlayer13FindUseEntityEfffPbb" 28 | } 29 | } 30 | } 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /gamedata/wdnmd_fix.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | "left4dead2" 4 | { 5 | "Addresses" 6 | { 7 | "RYKnifeFix" 8 | { 9 | "windows" 10 | { 11 | "signature" "RY_Knife_Fix" 12 | } 13 | "linux" 14 | { 15 | "signature" "RY_Knife_Fix" 16 | } 17 | } 18 | } 19 | "Signatures" 20 | { 21 | "RY_Knife_Fix" 22 | { 23 | "library" "server" 24 | "windows" "\x6B\x6E\x69\x66\x65\x00" 25 | "linux" "\x6B\x6E\x69\x66\x65\x00" 26 | } 27 | "RoundRespawn" 28 | { 29 | "library" "server" 30 | "linux" "@_ZN13CTerrorPlayer12RoundRespawnEv" 31 | "windows" "\x56\x8B\xF1\xE8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0\x75" 32 | } 33 | } 34 | "Offsets" 35 | { 36 | "RoundRespawn" 37 | { 38 | "windows" "512" 39 | "linux" "513" 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /scripting/MeleeInTheSafeRoom.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | 6 | #define VERSION "2.0.7" 7 | 8 | new Handle:g_hEnabled; 9 | new Handle:g_hWeaponRandom; 10 | new Handle:g_hWeaponRandomAmount; 11 | new Handle:g_hWeaponBaseballBat; 12 | new Handle:g_hWeaponCricketBat; 13 | new Handle:g_hWeaponCrowbar; 14 | new Handle:g_hWeaponElecGuitar; 15 | new Handle:g_hWeaponFireAxe; 16 | new Handle:g_hWeaponFryingPan; 17 | new Handle:g_hWeaponGolfClub; 18 | new Handle:g_hWeaponKnife; 19 | new Handle:g_hWeaponKatana; 20 | new Handle:g_hWeaponPitchfork; 21 | new Handle:g_hWeaponShovel; 22 | new Handle:g_hWeaponMachete; 23 | new Handle:g_hWeaponRiotShield; 24 | new Handle:g_hWeaponTonfa; 25 | 26 | new bool:g_bSpawnedMelee; 27 | 28 | new g_iMeleeClassCount = 0; 29 | new g_iMeleeRandomSpawn[20]; 30 | new g_iRound = 2; 31 | 32 | new String:g_sMeleeClass[16][32]; 33 | 34 | public Plugin:myinfo = 35 | { 36 | name = "Melee In The Saferoom", 37 | author = "N3wton", 38 | description = "Spawns a selection of melee weapons in the saferoom, at the start of each round.", 39 | version = VERSION 40 | }; 41 | 42 | public OnPluginStart() 43 | { 44 | decl String:GameName[12]; 45 | GetGameFolderName(GameName, sizeof(GameName)); 46 | if( !StrEqual(GameName, "left4dead2") ) 47 | SetFailState( "Melee In The Saferoom is only supported on left 4 dead 2." ); 48 | 49 | CreateConVar( "l4d2_MITSR_Version", VERSION, "The version of Melee In The Saferoom", FCVAR_PLUGIN ); 50 | g_hEnabled = CreateConVar( "l4d2_MITSR_Enabled", "1", "Should the plugin be enabled", FCVAR_PLUGIN ); 51 | g_hWeaponRandom = CreateConVar( "l4d2_MITSR_Random", "1", "Spawn Random Weapons (1) or custom list (0)", FCVAR_PLUGIN ); 52 | g_hWeaponRandomAmount = CreateConVar( "l4d2_MITSR_Amount", "4", "Number of weapons to spawn if l4d2_MITSR_Random is 1", FCVAR_PLUGIN ); 53 | g_hWeaponBaseballBat = CreateConVar( "l4d2_MITSR_BaseballBat", "1", "Number of baseball bats to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 54 | g_hWeaponCricketBat = CreateConVar( "l4d2_MITSR_CricketBat", "1", "Number of cricket bats to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 55 | g_hWeaponCrowbar = CreateConVar( "l4d2_MITSR_Crowbar", "1", "Number of crowbars to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 56 | g_hWeaponElecGuitar = CreateConVar( "l4d2_MITSR_ElecGuitar", "1", "Number of electric guitars to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 57 | g_hWeaponFireAxe = CreateConVar( "l4d2_MITSR_FireAxe", "1", "Number of fireaxes to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 58 | g_hWeaponFryingPan = CreateConVar( "l4d2_MITSR_FryingPan", "1", "Number of frying pans to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 59 | g_hWeaponGolfClub = CreateConVar( "l4d2_MITSR_GolfClub", "1", "Number of golf clubs to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 60 | g_hWeaponKnife = CreateConVar( "l4d2_MITSR_Knife", "1", "Number of knifes to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 61 | g_hWeaponKatana = CreateConVar( "l4d2_MITSR_Katana", "1", "Number of katanas to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 62 | g_hWeaponPitchfork = CreateConVar( "l4d2_MITSR_Pitchfork", "1", "Number of pitchfork to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 63 | g_hWeaponShovel = CreateConVar( "l4d2_MITSR_Shovel", "1", "Number of shovels to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 64 | g_hWeaponMachete = CreateConVar( "l4d2_MITSR_Machete", "1", "Number of machetes to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 65 | g_hWeaponRiotShield = CreateConVar( "l4d2_MITSR_RiotShield", "1", "Number of riot shields to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 66 | g_hWeaponTonfa = CreateConVar( "l4d2_MITSR_Tonfa", "1", "Number of tonfas to spawn (l4d2_MITSR_Random must be 0)", FCVAR_PLUGIN ); 67 | AutoExecConfig( true, "[L4D2]MeleeInTheSaferoom" ); 68 | 69 | HookEvent( "round_start", Event_RoundStart ); 70 | 71 | RegAdminCmd( "sm_melee", Command_SMMelee, ADMFLAG_KICK, "Lists all melee weapons spawnable in current campaign" ); 72 | } 73 | 74 | public Action:Command_SMMelee(client, args) 75 | { 76 | for( new i = 0; i < g_iMeleeClassCount; i++ ) 77 | { 78 | PrintToChat( client, "%d : %s", i, g_sMeleeClass[i] ); 79 | } 80 | } 81 | 82 | public OnMapStart() 83 | { 84 | PrecacheModel( "models/weapons/melee/v_bat.mdl", true ); 85 | PrecacheModel( "models/weapons/melee/v_cricket_bat.mdl", true ); 86 | PrecacheModel( "models/weapons/melee/v_crowbar.mdl", true ); 87 | PrecacheModel( "models/weapons/melee/v_electric_guitar.mdl", true ); 88 | PrecacheModel( "models/weapons/melee/v_fireaxe.mdl", true ); 89 | PrecacheModel( "models/weapons/melee/v_frying_pan.mdl", true ); 90 | PrecacheModel( "models/weapons/melee/v_golfclub.mdl", true ); 91 | PrecacheModel( "models/weapons/melee/v_katana.mdl", true ); 92 | PrecacheModel( "models/weapons/melee/v_pitchfork.mdl", true ); 93 | PrecacheModel( "models/weapons/melee/v_shovel.mdl", true ); 94 | PrecacheModel( "models/weapons/melee/v_machete.mdl", true ); 95 | PrecacheModel( "models/weapons/melee/v_tonfa.mdl", true ); 96 | 97 | PrecacheModel( "models/weapons/melee/w_bat.mdl", true ); 98 | PrecacheModel( "models/weapons/melee/w_cricket_bat.mdl", true ); 99 | PrecacheModel( "models/weapons/melee/w_crowbar.mdl", true ); 100 | PrecacheModel( "models/weapons/melee/w_electric_guitar.mdl", true ); 101 | PrecacheModel( "models/weapons/melee/w_fireaxe.mdl", true ); 102 | PrecacheModel( "models/weapons/melee/w_frying_pan.mdl", true ); 103 | PrecacheModel( "models/weapons/melee/w_golfclub.mdl", true ); 104 | PrecacheModel( "models/weapons/melee/w_katana.mdl", true ); 105 | PrecacheModel( "models/weapons/melee/w_pitchfork.mdl", true ); 106 | PrecacheModel( "models/weapons/melee/w_shovel.mdl", true ); 107 | PrecacheModel( "models/weapons/melee/w_machete.mdl", true ); 108 | PrecacheModel( "models/weapons/melee/w_tonfa.mdl", true ); 109 | 110 | PrecacheGeneric( "scripts/melee/baseball_bat.txt", true ); 111 | PrecacheGeneric( "scripts/melee/cricket_bat.txt", true ); 112 | PrecacheGeneric( "scripts/melee/crowbar.txt", true ); 113 | PrecacheGeneric( "scripts/melee/electric_guitar.txt", true ); 114 | PrecacheGeneric( "scripts/melee/fireaxe.txt", true ); 115 | PrecacheGeneric( "scripts/melee/frying_pan.txt", true ); 116 | PrecacheGeneric( "scripts/melee/golfclub.txt", true ); 117 | PrecacheGeneric( "scripts/melee/katana.txt", true ); 118 | PrecacheGeneric( "scripts/melee/pitchfork.txt", true ); 119 | PrecacheGeneric( "scripts/melee/shovel.txt", true ); 120 | PrecacheGeneric( "scripts/melee/machete.txt", true ); 121 | PrecacheGeneric( "scripts/melee/tonfa.txt", true ); 122 | } 123 | 124 | public Action:Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast) 125 | { 126 | if( !GetConVarBool( g_hEnabled ) ) return Plugin_Continue; 127 | 128 | g_bSpawnedMelee = false; 129 | 130 | if( g_iRound == 2 && IsVersus() ) g_iRound = 1; else g_iRound = 2; 131 | 132 | GetMeleeClasses(); 133 | 134 | CreateTimer( 1.0, Timer_SpawnMelee ); 135 | 136 | return Plugin_Continue; 137 | } 138 | 139 | public Action:Timer_SpawnMelee( Handle:timer ) 140 | { 141 | new client = GetInGameClient(); 142 | 143 | if( client != 0 && !g_bSpawnedMelee ) 144 | { 145 | decl Float:SpawnPosition[3], Float:SpawnAngle[3]; 146 | GetClientAbsOrigin( client, SpawnPosition ); 147 | SpawnPosition[2] += 20; SpawnAngle[0] = 90.0; 148 | 149 | if( GetConVarBool( g_hWeaponRandom ) ) 150 | { 151 | new i = 0; 152 | while( i < GetConVarInt( g_hWeaponRandomAmount ) ) 153 | { 154 | new RandomMelee = GetRandomInt( 0, g_iMeleeClassCount-1 ); 155 | if( IsVersus() && g_iRound == 2 ) RandomMelee = g_iMeleeRandomSpawn[i]; 156 | SpawnMelee( g_sMeleeClass[RandomMelee], SpawnPosition, SpawnAngle ); 157 | if( IsVersus() && g_iRound == 1 ) g_iMeleeRandomSpawn[i] = RandomMelee; 158 | i++; 159 | } 160 | g_bSpawnedMelee = true; 161 | } 162 | else 163 | { 164 | SpawnCustomList( SpawnPosition, SpawnAngle ); 165 | g_bSpawnedMelee = true; 166 | } 167 | } 168 | else 169 | { 170 | if( !g_bSpawnedMelee ) CreateTimer( 1.0, Timer_SpawnMelee ); 171 | } 172 | } 173 | 174 | stock SpawnCustomList( Float:Position[3], Float:Angle[3] ) 175 | { 176 | decl String:ScriptName[32]; 177 | 178 | //Spawn Basseball Bats 179 | if( GetConVarInt( g_hWeaponBaseballBat ) > 0 ) 180 | { 181 | for( new i = 0; i < GetConVarInt( g_hWeaponBaseballBat ); i++ ) 182 | { 183 | GetScriptName( "baseball_bat", ScriptName ); 184 | SpawnMelee( ScriptName, Position, Angle ); 185 | } 186 | } 187 | 188 | //Spawn Cricket Bats 189 | if( GetConVarInt( g_hWeaponCricketBat ) > 0 ) 190 | { 191 | for( new i = 0; i < GetConVarInt( g_hWeaponCricketBat ); i++ ) 192 | { 193 | GetScriptName( "cricket_bat", ScriptName ); 194 | SpawnMelee( ScriptName, Position, Angle ); 195 | } 196 | } 197 | 198 | //Spawn Crowbars 199 | if( GetConVarInt( g_hWeaponCrowbar ) > 0 ) 200 | { 201 | for( new i = 0; i < GetConVarInt( g_hWeaponCrowbar ); i++ ) 202 | { 203 | GetScriptName( "crowbar", ScriptName ); 204 | SpawnMelee( ScriptName, Position, Angle ); 205 | } 206 | } 207 | 208 | //Spawn Electric Guitars 209 | if( GetConVarInt( g_hWeaponElecGuitar ) > 0 ) 210 | { 211 | for( new i = 0; i < GetConVarInt( g_hWeaponElecGuitar ); i++ ) 212 | { 213 | GetScriptName( "electric_guitar", ScriptName ); 214 | SpawnMelee( ScriptName, Position, Angle ); 215 | } 216 | } 217 | 218 | //Spawn Fireaxes 219 | if( GetConVarInt( g_hWeaponFireAxe ) > 0 ) 220 | { 221 | for( new i = 0; i < GetConVarInt( g_hWeaponFireAxe ); i++ ) 222 | { 223 | GetScriptName( "fireaxe", ScriptName ); 224 | SpawnMelee( ScriptName, Position, Angle ); 225 | } 226 | } 227 | 228 | //Spawn Frying Pans 229 | if( GetConVarInt( g_hWeaponFryingPan ) > 0 ) 230 | { 231 | for( new i = 0; i < GetConVarInt( g_hWeaponFryingPan ); i++ ) 232 | { 233 | GetScriptName( "frying_pan", ScriptName ); 234 | SpawnMelee( ScriptName, Position, Angle ); 235 | } 236 | } 237 | 238 | //Spawn Golfclubs 239 | if( GetConVarInt( g_hWeaponGolfClub ) > 0 ) 240 | { 241 | for( new i = 0; i < GetConVarInt( g_hWeaponGolfClub ); i++ ) 242 | { 243 | GetScriptName( "golfclub", ScriptName ); 244 | SpawnMelee( ScriptName, Position, Angle ); 245 | } 246 | } 247 | 248 | //Spawn Knifes 249 | if( GetConVarInt( g_hWeaponKnife ) > 0 ) 250 | { 251 | for( new i = 0; i < GetConVarInt( g_hWeaponKnife ); i++ ) 252 | { 253 | GetScriptName( "hunting_knife", ScriptName ); 254 | SpawnMelee( ScriptName, Position, Angle ); 255 | } 256 | } 257 | 258 | //Spawn Katanas 259 | if( GetConVarInt( g_hWeaponKatana ) > 0 ) 260 | { 261 | for( new i = 0; i < GetConVarInt( g_hWeaponKatana ); i++ ) 262 | { 263 | GetScriptName( "katana", ScriptName ); 264 | SpawnMelee( ScriptName, Position, Angle ); 265 | } 266 | } 267 | 268 | //Spawn Pitchforks 269 | if( GetConVarInt( g_hWeaponPitchfork ) > 0 ) 270 | { 271 | for( new i = 0; i < GetConVarInt( g_hWeaponPitchfork ); i++ ) 272 | { 273 | GetScriptName( "pitchfork", ScriptName ); 274 | SpawnMelee( ScriptName, Position, Angle ); 275 | } 276 | } 277 | 278 | //Spawn Shovels 279 | if( GetConVarInt( g_hWeaponShovel ) > 0 ) 280 | { 281 | for( new i = 0; i < GetConVarInt( g_hWeaponShovel ); i++ ) 282 | { 283 | GetScriptName( "shovel", ScriptName ); 284 | SpawnMelee( ScriptName, Position, Angle ); 285 | } 286 | } 287 | 288 | //Spawn Machetes 289 | if( GetConVarInt( g_hWeaponMachete ) > 0 ) 290 | { 291 | for( new i = 0; i < GetConVarInt( g_hWeaponMachete ); i++ ) 292 | { 293 | GetScriptName( "machete", ScriptName ); 294 | SpawnMelee( ScriptName, Position, Angle ); 295 | } 296 | } 297 | 298 | //Spawn RiotShields 299 | if( GetConVarInt( g_hWeaponRiotShield ) > 0 ) 300 | { 301 | for( new i = 0; i < GetConVarInt( g_hWeaponRiotShield ); i++ ) 302 | { 303 | GetScriptName( "riotshield", ScriptName ); 304 | SpawnMelee( ScriptName, Position, Angle ); 305 | } 306 | } 307 | 308 | //Spawn Tonfas 309 | if( GetConVarInt( g_hWeaponTonfa ) > 0 ) 310 | { 311 | for( new i = 0; i < GetConVarInt( g_hWeaponTonfa ); i++ ) 312 | { 313 | GetScriptName( "tonfa", ScriptName ); 314 | SpawnMelee( ScriptName, Position, Angle ); 315 | } 316 | } 317 | } 318 | 319 | stock SpawnMelee( const String:Class[32], Float:Position[3], Float:Angle[3] ) 320 | { 321 | decl Float:SpawnPosition[3], Float:SpawnAngle[3]; 322 | SpawnPosition = Position; 323 | SpawnAngle = Angle; 324 | 325 | SpawnPosition[0] += ( -10 + GetRandomInt( 0, 20 ) ); 326 | SpawnPosition[1] += ( -10 + GetRandomInt( 0, 20 ) ); 327 | SpawnPosition[2] += GetRandomInt( 0, 10 ); 328 | SpawnAngle[1] = GetRandomFloat( 0.0, 360.0 ); 329 | 330 | new MeleeSpawn = CreateEntityByName( "weapon_melee" ); 331 | DispatchKeyValue( MeleeSpawn, "melee_script_name", Class ); 332 | DispatchSpawn( MeleeSpawn ); 333 | TeleportEntity(MeleeSpawn, SpawnPosition, SpawnAngle, NULL_VECTOR ); 334 | } 335 | 336 | stock GetMeleeClasses() 337 | { 338 | new MeleeStringTable = FindStringTable( "MeleeWeapons" ); 339 | g_iMeleeClassCount = GetStringTableNumStrings( MeleeStringTable ); 340 | 341 | for( new i = 0; i < g_iMeleeClassCount; i++ ) 342 | { 343 | ReadStringTable( MeleeStringTable, i, g_sMeleeClass[i], 32 ); 344 | } 345 | } 346 | 347 | stock GetScriptName( const String:Class[32], String:ScriptName[32] ) 348 | { 349 | for( new i = 0; i < g_iMeleeClassCount; i++ ) 350 | { 351 | if( StrContains( g_sMeleeClass[i], Class, false ) == 0 ) 352 | { 353 | Format( ScriptName, 32, "%s", g_sMeleeClass[i] ); 354 | return; 355 | } 356 | } 357 | Format( ScriptName, 32, "%s", g_sMeleeClass[0] ); 358 | } 359 | 360 | stock GetInGameClient() 361 | { 362 | for( new x = 1; x <= GetClientCount( true ); x++ ) 363 | { 364 | if( IsClientInGame( x ) && GetClientTeam( x ) == 2 ) 365 | { 366 | return x; 367 | } 368 | } 369 | return 0; 370 | } 371 | 372 | stock bool:IsVersus() 373 | { 374 | new String:GameMode[32]; 375 | GetConVarString( FindConVar( "mp_gamemode" ), GameMode, 32 ); 376 | if( StrContains( GameMode, "versus", false ) != -1 ) return true; 377 | return false; 378 | } -------------------------------------------------------------------------------- /scripting/advertisements.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #undef REQUIRE_PLUGIN 3 | #include 4 | #include "advertisements/chatcolors.sp" 5 | #include "advertisements/topcolors.sp" 6 | 7 | #pragma newdecls required 8 | #pragma semicolon 1 9 | 10 | #define PL_VERSION "2.0.4" 11 | #define UPDATE_URL "http://ErikMinekus.github.io/sm-advertisements/update.txt" 12 | 13 | public Plugin myinfo = 14 | { 15 | name = "Advertisements", 16 | author = "Tsunami", 17 | description = "Display advertisements", 18 | version = PL_VERSION, 19 | url = "http://www.tsunami-productions.nl" 20 | }; 21 | 22 | 23 | /** 24 | * Globals 25 | */ 26 | KeyValues g_hAdvertisements; 27 | ConVar g_hEnabled; 28 | ConVar g_hFile; 29 | ConVar g_hInterval; 30 | Handle g_hTimer; 31 | 32 | 33 | /** 34 | * Plugin Forwards 35 | */ 36 | public void OnPluginStart() 37 | { 38 | CreateConVar("sm_advertisements_version", PL_VERSION, "Display advertisements", FCVAR_NOTIFY); 39 | g_hEnabled = CreateConVar("sm_advertisements_enabled", "1", "Enable/disable displaying advertisements."); 40 | g_hFile = CreateConVar("sm_advertisements_file", "advertisements.txt", "File to read the advertisements from."); 41 | g_hInterval = CreateConVar("sm_advertisements_interval", "30", "Amount of seconds between advertisements."); 42 | 43 | g_hFile.AddChangeHook(ConVarChange_File); 44 | g_hInterval.AddChangeHook(ConVarChange_Interval); 45 | 46 | RegServerCmd("sm_advertisements_reload", Command_ReloadAds, "Reload the advertisements"); 47 | 48 | AddChatColors(); 49 | AddTopColors(); 50 | 51 | if (LibraryExists("updater")) { 52 | Updater_AddPlugin(UPDATE_URL); 53 | } 54 | } 55 | 56 | public void OnConfigsExecuted() 57 | { 58 | ParseAds(); 59 | RestartTimer(); 60 | } 61 | 62 | public void OnLibraryAdded(const char[] name) 63 | { 64 | if (StrEqual(name, "updater")) { 65 | Updater_AddPlugin(UPDATE_URL); 66 | } 67 | } 68 | 69 | public void ConVarChange_File(ConVar convar, const char[] oldValue, const char[] newValue) 70 | { 71 | ParseAds(); 72 | } 73 | 74 | public void ConVarChange_Interval(ConVar convar, const char[] oldValue, const char[] newValue) 75 | { 76 | RestartTimer(); 77 | } 78 | 79 | 80 | /** 81 | * Commands 82 | */ 83 | public Action Command_ReloadAds(int args) 84 | { 85 | ParseAds(); 86 | return Plugin_Handled; 87 | } 88 | 89 | 90 | /** 91 | * Menu Handlers 92 | */ 93 | public int Handler_DoNothing(Menu menu, MenuAction action, int param1, int param2) {} 94 | 95 | 96 | /** 97 | * Timers 98 | */ 99 | public Action Timer_DisplayAd(Handle timer) 100 | { 101 | if (!g_hEnabled.BoolValue) { 102 | return; 103 | } 104 | 105 | char sCenter[1024], sChat[1024], sHint[1024], sMenu[1024], sTop[1024], sFlags[22]; 106 | g_hAdvertisements.GetString("center", sCenter, sizeof(sCenter)); 107 | g_hAdvertisements.GetString("chat", sChat, sizeof(sChat)); 108 | g_hAdvertisements.GetString("hint", sHint, sizeof(sHint)); 109 | g_hAdvertisements.GetString("menu", sMenu, sizeof(sMenu)); 110 | g_hAdvertisements.GetString("top", sTop, sizeof(sTop)); 111 | g_hAdvertisements.GetString("flags", sFlags, sizeof(sFlags), "none"); 112 | int iFlags = ReadFlagString(sFlags); 113 | bool bAdmins = StrEqual(sFlags, ""), 114 | bFlags = !StrEqual(sFlags, "none"); 115 | 116 | if (sCenter[0]) { 117 | ProcessVariables(sCenter); 118 | 119 | for (int i = 1; i <= MaxClients; i++) { 120 | if (IsValidClient(i, bAdmins, bFlags, iFlags)) { 121 | PrintCenterText(i, sCenter); 122 | 123 | DataPack hCenterAd; 124 | CreateDataTimer(1.0, Timer_CenterAd, hCenterAd, TIMER_FLAG_NO_MAPCHANGE|TIMER_REPEAT); 125 | hCenterAd.WriteCell(i); 126 | hCenterAd.WriteString(sCenter); 127 | } 128 | } 129 | } 130 | if (sHint[0]) { 131 | ProcessVariables(sHint); 132 | 133 | for (int i = 1; i <= MaxClients; i++) { 134 | if (IsValidClient(i, bAdmins, bFlags, iFlags)) { 135 | PrintHintText(i, sHint); 136 | } 137 | } 138 | } 139 | if (sMenu[0]) { 140 | ProcessVariables(sMenu); 141 | 142 | Panel hPl = new Panel(); 143 | hPl.DrawText(sMenu); 144 | hPl.CurrentKey = 10; 145 | 146 | for (int i = 1; i <= MaxClients; i++) { 147 | if (IsValidClient(i, bAdmins, bFlags, iFlags)) { 148 | hPl.Send(i, Handler_DoNothing, 10); 149 | } 150 | } 151 | 152 | delete hPl; 153 | } 154 | if (sChat[0]) { 155 | bool bTeamColor = StrContains(sChat, "{teamcolor}", false) != -1; 156 | 157 | char sBuffer[1024]; 158 | ProcessChatColors(sChat, sBuffer, sizeof(sBuffer)); 159 | ProcessVariables(sBuffer); 160 | 161 | for (int i = 1; i <= MaxClients; i++) { 162 | if (IsValidClient(i, bAdmins, bFlags, iFlags)) { 163 | if (bTeamColor) { 164 | SayText2(i, sBuffer); 165 | } else { 166 | PrintToChat(i, sBuffer); 167 | } 168 | } 169 | } 170 | } 171 | if (sTop[0]) { 172 | int iStart = 0, 173 | aColor[4] = {255, 255, 255, 255}; 174 | 175 | ParseTopColor(sTop, iStart, aColor); 176 | ProcessVariables(sTop[iStart]); 177 | 178 | KeyValues hKv = new KeyValues("Stuff", "title", sTop[iStart]); 179 | hKv.SetColor4("color", aColor); 180 | hKv.SetNum("level", 1); 181 | hKv.SetNum("time", 10); 182 | 183 | for (int i = 1; i <= MaxClients; i++) { 184 | if (IsValidClient(i, bAdmins, bFlags, iFlags)) { 185 | CreateDialog(i, hKv, DialogType_Msg); 186 | } 187 | } 188 | 189 | delete hKv; 190 | } 191 | 192 | if (!g_hAdvertisements.GotoNextKey()) { 193 | g_hAdvertisements.Rewind(); 194 | g_hAdvertisements.GotoFirstSubKey(); 195 | } 196 | } 197 | 198 | public Action Timer_CenterAd(Handle timer, DataPack pack) 199 | { 200 | char sCenter[1024]; 201 | static int iCount = 0; 202 | 203 | pack.Reset(); 204 | int iClient = pack.ReadCell(); 205 | pack.ReadString(sCenter, sizeof(sCenter)); 206 | 207 | if (!IsClientInGame(iClient) || ++iCount >= 5) { 208 | iCount = 0; 209 | return Plugin_Stop; 210 | } 211 | 212 | PrintCenterText(iClient, sCenter); 213 | return Plugin_Continue; 214 | } 215 | 216 | 217 | /** 218 | * Stocks 219 | */ 220 | bool IsValidClient(int iClient, bool bAdmins, bool bFlags, int iFlags) 221 | { 222 | return IsClientInGame(iClient) && !IsFakeClient(iClient) 223 | && ((!bAdmins && !(bFlags && CheckCommandAccess(iClient, "Advertisements", iFlags))) 224 | || (bAdmins && CheckCommandAccess(iClient, "Advertisements", ADMFLAG_GENERIC))); 225 | } 226 | 227 | void ParseAds() 228 | { 229 | delete g_hAdvertisements; 230 | g_hAdvertisements = new KeyValues("Advertisements"); 231 | 232 | char sFile[64], sPath[PLATFORM_MAX_PATH]; 233 | g_hFile.GetString(sFile, sizeof(sFile)); 234 | BuildPath(Path_SM, sPath, sizeof(sPath), "configs/%s", sFile); 235 | 236 | if (!FileExists(sPath)) { 237 | SetFailState("File Not Found: %s", sPath); 238 | } 239 | 240 | g_hAdvertisements.SetEscapeSequences(true); 241 | g_hAdvertisements.ImportFromFile(sPath); 242 | g_hAdvertisements.GotoFirstSubKey(); 243 | } 244 | 245 | void ProcessVariables(char sText[1024]) 246 | { 247 | char sBuffer[64]; 248 | if (StrContains(sText, "{currentmap}", false) != -1) { 249 | GetCurrentMap(sBuffer, sizeof(sBuffer)); 250 | ReplaceString(sText, sizeof(sText), "{currentmap}", sBuffer, false); 251 | } 252 | 253 | if (StrContains(sText, "{date}", false) != -1) { 254 | FormatTime(sBuffer, sizeof(sBuffer), "%m/%d/%Y"); 255 | ReplaceString(sText, sizeof(sText), "{date}", sBuffer, false); 256 | } 257 | 258 | if (StrContains(sText, "{time}", false) != -1) { 259 | FormatTime(sBuffer, sizeof(sBuffer), "%I:%M:%S%p"); 260 | ReplaceString(sText, sizeof(sText), "{time}", sBuffer, false); 261 | } 262 | 263 | if (StrContains(sText, "{time24}", false) != -1) { 264 | FormatTime(sBuffer, sizeof(sBuffer), "%H:%M:%S"); 265 | ReplaceString(sText, sizeof(sText), "{time24}", sBuffer, false); 266 | } 267 | 268 | if (StrContains(sText, "{timeleft}", false) != -1) { 269 | int iMins, iSecs, iTimeLeft; 270 | if (GetMapTimeLeft(iTimeLeft) && iTimeLeft > 0) { 271 | iMins = iTimeLeft / 60; 272 | iSecs = iTimeLeft % 60; 273 | } 274 | 275 | Format(sBuffer, sizeof(sBuffer), "%d:%02d", iMins, iSecs); 276 | ReplaceString(sText, sizeof(sText), "{timeleft}", sBuffer, false); 277 | } 278 | 279 | ConVar hConVar; 280 | char sConVar[64], sSearch[64], sReplace[256]; 281 | int iEnd = -1, iStart = StrContains(sText, "{"), iStart2; 282 | while (iStart != -1) { 283 | iEnd = StrContains(sText[iStart + 1], "}"); 284 | if (iEnd == -1) { 285 | break; 286 | } 287 | 288 | strcopy(sConVar, iEnd + 1, sText[iStart + 1]); 289 | Format(sSearch, sizeof(sSearch), "{%s}", sConVar); 290 | 291 | if ((hConVar = FindConVar(sConVar))) { 292 | hConVar.GetString(sReplace, sizeof(sReplace)); 293 | ReplaceString(sText, sizeof(sText), sSearch, sReplace, false); 294 | } 295 | 296 | iStart2 = StrContains(sText[iStart + 1], "{"); 297 | if (iStart2 == -1) { 298 | break; 299 | } 300 | 301 | iStart += iStart2 + 1; 302 | } 303 | } 304 | 305 | void RestartTimer() 306 | { 307 | delete g_hTimer; 308 | g_hTimer = CreateTimer(float(g_hInterval.IntValue), Timer_DisplayAd, _, TIMER_REPEAT); 309 | } 310 | -------------------------------------------------------------------------------- /scripting/advertisements/chatcolors.sp: -------------------------------------------------------------------------------- 1 | StringMap g_hChatColors; 2 | 3 | void AddChatColors() 4 | { 5 | if (!g_hChatColors) { 6 | g_hChatColors = new StringMap(); 7 | } 8 | 9 | AddChatColor("default", "\x01"); 10 | AddChatColor("teamcolor", "\x03"); 11 | 12 | switch (GetEngineVersion()) { 13 | case Engine_CSS, Engine_DODS, Engine_HL2DM, Engine_TF2: { 14 | AddChatColor("aliceblue", "\x07F0F8FF"); 15 | AddChatColor("allies", "\x074D7942"); 16 | AddChatColor("ancient", "\x07EB4B4B"); 17 | AddChatColor("antiquewhite", "\x07FAEBD7"); 18 | AddChatColor("aqua", "\x0700FFFF"); 19 | AddChatColor("aquamarine", "\x077FFFD4"); 20 | AddChatColor("arcana", "\x07ADE55C"); 21 | AddChatColor("axis", "\x07FF4040"); 22 | AddChatColor("azure", "\x07007FFF"); 23 | AddChatColor("beige", "\x07F5F5DC"); 24 | AddChatColor("bisque", "\x07FFE4C4"); 25 | AddChatColor("black", "\x07000000"); 26 | AddChatColor("blanchedalmond", "\x07FFEBCD"); 27 | AddChatColor("blue", "\x0799CCFF"); 28 | AddChatColor("blueviolet", "\x078A2BE2"); 29 | AddChatColor("brown", "\x07A52A2A"); 30 | AddChatColor("burlywood", "\x07DEB887"); 31 | AddChatColor("cadetblue", "\x075F9EA0"); 32 | AddChatColor("chartreuse", "\x077FFF00"); 33 | AddChatColor("chocolate", "\x07D2691E"); 34 | AddChatColor("collectors", "\x07AA0000"); 35 | AddChatColor("common", "\x07B0C3D9"); 36 | AddChatColor("community", "\x0770B04A"); 37 | AddChatColor("coral", "\x07FF7F50"); 38 | AddChatColor("cornflowerblue", "\x076495ED"); 39 | AddChatColor("cornsilk", "\x07FFF8DC"); 40 | AddChatColor("corrupted", "\x07A32C2E"); 41 | AddChatColor("crimson", "\x07DC143C"); 42 | AddChatColor("cyan", "\x0700FFFF"); 43 | AddChatColor("darkblue", "\x0700008B"); 44 | AddChatColor("darkcyan", "\x07008B8B"); 45 | AddChatColor("darkgoldenrod", "\x07B8860B"); 46 | AddChatColor("darkgray", "\x07A9A9A9"); 47 | AddChatColor("darkgrey", "\x07A9A9A9"); 48 | AddChatColor("darkgreen", "\x07006400"); 49 | AddChatColor("darkkhaki", "\x07BDB76B"); 50 | AddChatColor("darkmagenta", "\x078B008B"); 51 | AddChatColor("darkolivegreen", "\x07556B2F"); 52 | AddChatColor("darkorange", "\x07FF8C00"); 53 | AddChatColor("darkorchid", "\x079932CC"); 54 | AddChatColor("darkred", "\x078B0000"); 55 | AddChatColor("darksalmon", "\x07E9967A"); 56 | AddChatColor("darkseagreen", "\x078FBC8F"); 57 | AddChatColor("darkslateblue", "\x07483D8B"); 58 | AddChatColor("darkslategray", "\x072F4F4F"); 59 | AddChatColor("darkslategrey", "\x072F4F4F"); 60 | AddChatColor("darkturquoise", "\x0700CED1"); 61 | AddChatColor("darkviolet", "\x079400D3"); 62 | AddChatColor("deeppink", "\x07FF1493"); 63 | AddChatColor("deepskyblue", "\x0700BFFF"); 64 | AddChatColor("dimgray", "\x07696969"); 65 | AddChatColor("dimgrey", "\x07696969"); 66 | AddChatColor("dodgerblue", "\x071E90FF"); 67 | AddChatColor("exalted", "\x07CCCCCD"); 68 | AddChatColor("firebrick", "\x07B22222"); 69 | AddChatColor("floralwhite", "\x07FFFAF0"); 70 | AddChatColor("forestgreen", "\x07228B22"); 71 | AddChatColor("frozen", "\x074983B3"); 72 | AddChatColor("fuchsia", "\x07FF00FF"); 73 | AddChatColor("fullblue", "\x070000FF"); 74 | AddChatColor("fullred", "\x07FF0000"); 75 | AddChatColor("gainsboro", "\x07DCDCDC"); 76 | AddChatColor("genuine", "\x074D7455"); 77 | AddChatColor("ghostwhite", "\x07F8F8FF"); 78 | AddChatColor("gold", "\x07FFD700"); 79 | AddChatColor("goldenrod", "\x07DAA520"); 80 | AddChatColor("gray", "\x07CCCCCC"); 81 | AddChatColor("grey", "\x07CCCCCC"); 82 | AddChatColor("green", "\x073EFF3E"); 83 | AddChatColor("greenyellow", "\x07ADFF2F"); 84 | AddChatColor("haunted", "\x0738F3AB"); 85 | AddChatColor("honeydew", "\x07F0FFF0"); 86 | AddChatColor("hotpink", "\x07FF69B4"); 87 | AddChatColor("immortal", "\x07E4AE33"); 88 | AddChatColor("indianred", "\x07CD5C5C"); 89 | AddChatColor("indigo", "\x074B0082"); 90 | AddChatColor("ivory", "\x07FFFFF0"); 91 | AddChatColor("khaki", "\x07F0E68C"); 92 | AddChatColor("lavender", "\x07E6E6FA"); 93 | AddChatColor("lavenderblush", "\x07FFF0F5"); 94 | AddChatColor("lawngreen", "\x077CFC00"); 95 | AddChatColor("legendary", "\x07D32CE6"); 96 | AddChatColor("lemonchiffon", "\x07FFFACD"); 97 | AddChatColor("lightblue", "\x07ADD8E6"); 98 | AddChatColor("lightcoral", "\x07F08080"); 99 | AddChatColor("lightcyan", "\x07E0FFFF"); 100 | AddChatColor("lightgoldenrodyellow", "\x07FAFAD2"); 101 | AddChatColor("lightgray", "\x07D3D3D3"); 102 | AddChatColor("lightgrey", "\x07D3D3D3"); 103 | AddChatColor("lightgreen", "\x0799FF99"); 104 | AddChatColor("lightpink", "\x07FFB6C1"); 105 | AddChatColor("lightsalmon", "\x07FFA07A"); 106 | AddChatColor("lightseagreen", "\x0720B2AA"); 107 | AddChatColor("lightskyblue", "\x0787CEFA"); 108 | AddChatColor("lightslategray", "\x07778899"); 109 | AddChatColor("lightslategrey", "\x07778899"); 110 | AddChatColor("lightsteelblue", "\x07B0C4DE"); 111 | AddChatColor("lightyellow", "\x07FFFFE0"); 112 | AddChatColor("lime", "\x0700FF00"); 113 | AddChatColor("limegreen", "\x0732CD32"); 114 | AddChatColor("linen", "\x07FAF0E6"); 115 | AddChatColor("magenta", "\x07FF00FF"); 116 | AddChatColor("maroon", "\x07800000"); 117 | AddChatColor("mediumaquamarine", "\x0766CDAA"); 118 | AddChatColor("mediumblue", "\x070000CD"); 119 | AddChatColor("mediumorchid", "\x07BA55D3"); 120 | AddChatColor("mediumpurple", "\x079370D8"); 121 | AddChatColor("mediumseagreen", "\x073CB371"); 122 | AddChatColor("mediumslateblue", "\x077B68EE"); 123 | AddChatColor("mediumspringgreen", "\x0700FA9A"); 124 | AddChatColor("mediumturquoise", "\x0748D1CC"); 125 | AddChatColor("mediumvioletred", "\x07C71585"); 126 | AddChatColor("midnightblue", "\x07191970"); 127 | AddChatColor("mintcream", "\x07F5FFFA"); 128 | AddChatColor("mistyrose", "\x07FFE4E1"); 129 | AddChatColor("moccasin", "\x07FFE4B5"); 130 | AddChatColor("mythical", "\x078847FF"); 131 | AddChatColor("navajowhite", "\x07FFDEAD"); 132 | AddChatColor("navy", "\x07000080"); 133 | AddChatColor("normal", "\x07B2B2B2"); 134 | AddChatColor("oldlace", "\x07FDF5E6"); 135 | AddChatColor("olive", "\x079EC34F"); 136 | AddChatColor("olivedrab", "\x076B8E23"); 137 | AddChatColor("orange", "\x07FFA500"); 138 | AddChatColor("orangered", "\x07FF4500"); 139 | AddChatColor("orchid", "\x07DA70D6"); 140 | AddChatColor("palegoldenrod", "\x07EEE8AA"); 141 | AddChatColor("palegreen", "\x0798FB98"); 142 | AddChatColor("paleturquoise", "\x07AFEEEE"); 143 | AddChatColor("palevioletred", "\x07D87093"); 144 | AddChatColor("papayawhip", "\x07FFEFD5"); 145 | AddChatColor("peachpuff", "\x07FFDAB9"); 146 | AddChatColor("peru", "\x07CD853F"); 147 | AddChatColor("pink", "\x07FFC0CB"); 148 | AddChatColor("plum", "\x07DDA0DD"); 149 | AddChatColor("powderblue", "\x07B0E0E6"); 150 | AddChatColor("purple", "\x07800080"); 151 | AddChatColor("rare", "\x074B69FF"); 152 | AddChatColor("red", "\x07FF4040"); 153 | AddChatColor("rosybrown", "\x07BC8F8F"); 154 | AddChatColor("royalblue", "\x074169E1"); 155 | AddChatColor("saddlebrown", "\x078B4513"); 156 | AddChatColor("salmon", "\x07FA8072"); 157 | AddChatColor("sandybrown", "\x07F4A460"); 158 | AddChatColor("seagreen", "\x072E8B57"); 159 | AddChatColor("seashell", "\x07FFF5EE"); 160 | AddChatColor("selfmade", "\x0770B04A"); 161 | AddChatColor("sienna", "\x07A0522D"); 162 | AddChatColor("silver", "\x07C0C0C0"); 163 | AddChatColor("skyblue", "\x0787CEEB"); 164 | AddChatColor("slateblue", "\x076A5ACD"); 165 | AddChatColor("slategray", "\x07708090"); 166 | AddChatColor("slategrey", "\x07708090"); 167 | AddChatColor("snow", "\x07FFFAFA"); 168 | AddChatColor("springgreen", "\x0700FF7F"); 169 | AddChatColor("steelblue", "\x074682B4"); 170 | AddChatColor("strange", "\x07CF6A32"); 171 | AddChatColor("tan", "\x07D2B48C"); 172 | AddChatColor("teal", "\x07008080"); 173 | AddChatColor("thistle", "\x07D8BFD8"); 174 | AddChatColor("tomato", "\x07FF6347"); 175 | AddChatColor("turquoise", "\x0740E0D0"); 176 | AddChatColor("uncommon", "\x07B0C3D9"); 177 | AddChatColor("unique", "\x07FFD700"); 178 | AddChatColor("unusual", "\x078650AC"); 179 | AddChatColor("valve", "\x07A50F79"); 180 | AddChatColor("vintage", "\x07476291"); 181 | AddChatColor("violet", "\x07EE82EE"); 182 | AddChatColor("wheat", "\x07F5DEB3"); 183 | AddChatColor("white", "\x07FFFFFF"); 184 | AddChatColor("whitesmoke", "\x07F5F5F5"); 185 | AddChatColor("yellow", "\x07FFFF00"); 186 | AddChatColor("yellowgreen", "\x079ACD32"); 187 | } 188 | case Engine_Left4Dead, Engine_Left4Dead2: { 189 | AddChatColor("lightgreen", "\x03"); 190 | AddChatColor("yellow", "\x04"); 191 | AddChatColor("green", "\x05"); 192 | } 193 | default: { 194 | AddChatColor("red", "\x07"); 195 | AddChatColor("lightred", "\x0F"); 196 | AddChatColor("darkred", "\x02"); 197 | AddChatColor("bluegrey", "\x0A"); 198 | AddChatColor("blue", "\x0B"); 199 | AddChatColor("darkblue", "\x0C"); 200 | AddChatColor("purple", "\x03"); 201 | AddChatColor("orchid", "\x0E"); 202 | AddChatColor("yellow", "\x09"); 203 | AddChatColor("gold", "\x10"); 204 | AddChatColor("lightgreen", "\x05"); 205 | AddChatColor("green", "\x04"); 206 | AddChatColor("lime", "\x06"); 207 | AddChatColor("grey", "\x08"); 208 | AddChatColor("grey2", "\x0D"); 209 | } 210 | } 211 | 212 | AddChatColor("engine 1", "\x01"); 213 | AddChatColor("engine 2", "\x02"); 214 | AddChatColor("engine 3", "\x03"); 215 | AddChatColor("engine 4", "\x04"); 216 | AddChatColor("engine 5", "\x05"); 217 | AddChatColor("engine 6", "\x06"); 218 | AddChatColor("engine 7", "\x07"); 219 | AddChatColor("engine 8", "\x08"); 220 | AddChatColor("engine 9", "\x09"); 221 | AddChatColor("engine 10", "\x0A"); 222 | AddChatColor("engine 11", "\x0B"); 223 | AddChatColor("engine 12", "\x0C"); 224 | AddChatColor("engine 13", "\x0D"); 225 | AddChatColor("engine 14", "\x0E"); 226 | AddChatColor("engine 15", "\x0F"); 227 | AddChatColor("engine 16", "\x10"); 228 | } 229 | 230 | static void AddChatColor(const char[] name, const char[] color) 231 | { 232 | g_hChatColors.SetString(name, color); 233 | } 234 | 235 | static int PreFormat(char[] buffer, int maxlength) 236 | { 237 | if (GetEngineVersion() == Engine_CSGO) { 238 | return FormatEx(buffer, maxlength, " %c", 1); 239 | } 240 | 241 | return FormatEx(buffer, maxlength, "%c", 1); 242 | } 243 | 244 | void ProcessChatColors(const char[] message, char[] buffer, int maxlength) 245 | { 246 | char name[32], color[10]; 247 | int buf_idx = PreFormat(buffer, maxlength); 248 | int i, name_len; 249 | 250 | while (message[i]) { 251 | if (message[i] != '{' || (name_len = FindCharInString(message[i + 1], '}')) == -1) { 252 | buffer[buf_idx++] = message[i++]; 253 | continue; 254 | } 255 | 256 | strcopy(name, name_len + 1, message[i + 1]); 257 | 258 | if (name[0] == '#') { 259 | buf_idx += FormatEx(buffer[buf_idx], maxlength - buf_idx, "%c%s", (name_len == 9) ? 8 : 7, name[1]); 260 | } else if (g_hChatColors.GetString(name, color, sizeof(color))) { 261 | buf_idx += StrCat(buffer[buf_idx], maxlength - buf_idx, color); 262 | } else { 263 | buf_idx += FormatEx(buffer[buf_idx], maxlength - buf_idx, "{%s}", name); 264 | } 265 | 266 | i += name_len + 2; 267 | } 268 | 269 | buffer[buf_idx] = '\0'; 270 | } 271 | 272 | void SayText2(int client, const char[] message) 273 | { 274 | Handle msg = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); 275 | 276 | if (GetUserMessageType() == UM_Protobuf) { 277 | Protobuf pb = UserMessageToProtobuf(msg); 278 | pb.SetInt("ent_idx", client); 279 | pb.SetBool("chat", true); 280 | pb.SetString("msg_name", message); 281 | pb.AddString("params", ""); 282 | pb.AddString("params", ""); 283 | pb.AddString("params", ""); 284 | pb.AddString("params", ""); 285 | } else { 286 | BfWrite bf = UserMessageToBfWrite(msg); 287 | bf.WriteByte(client); 288 | bf.WriteByte(true); 289 | bf.WriteString(message); 290 | } 291 | 292 | EndMessage(); 293 | } 294 | -------------------------------------------------------------------------------- /scripting/advertisements/topcolors.sp: -------------------------------------------------------------------------------- 1 | StringMap g_hTopColors; 2 | 3 | void AddTopColors() 4 | { 5 | if (!g_hTopColors) { 6 | g_hTopColors = new StringMap(); 7 | } 8 | 9 | AddTopColor("aliceblue", "F0F8FF"); 10 | AddTopColor("allies", "4D7942"); 11 | AddTopColor("ancient", "EB4B4B"); 12 | AddTopColor("antiquewhite", "FAEBD7"); 13 | AddTopColor("aqua", "00FFFF"); 14 | AddTopColor("aquamarine", "7FFFD4"); 15 | AddTopColor("arcana", "ADE55C"); 16 | AddTopColor("axis", "FF4040"); 17 | AddTopColor("azure", "007FFF"); 18 | AddTopColor("beige", "F5F5DC"); 19 | AddTopColor("bisque", "FFE4C4"); 20 | AddTopColor("black", "000000"); 21 | AddTopColor("blanchedalmond", "FFEBCD"); 22 | AddTopColor("blue", "99CCFF"); 23 | AddTopColor("blueviolet", "8A2BE2"); 24 | AddTopColor("brown", "A52A2A"); 25 | AddTopColor("burlywood", "DEB887"); 26 | AddTopColor("cadetblue", "5F9EA0"); 27 | AddTopColor("chartreuse", "7FFF00"); 28 | AddTopColor("chocolate", "D2691E"); 29 | AddTopColor("collectors", "AA0000"); 30 | AddTopColor("common", "B0C3D9"); 31 | AddTopColor("community", "70B04A"); 32 | AddTopColor("coral", "FF7F50"); 33 | AddTopColor("cornflowerblue", "6495ED"); 34 | AddTopColor("cornsilk", "FFF8DC"); 35 | AddTopColor("corrupted", "A32C2E"); 36 | AddTopColor("crimson", "DC143C"); 37 | AddTopColor("cyan", "00FFFF"); 38 | AddTopColor("darkblue", "00008B"); 39 | AddTopColor("darkcyan", "008B8B"); 40 | AddTopColor("darkgoldenrod", "B8860B"); 41 | AddTopColor("darkgray", "A9A9A9"); 42 | AddTopColor("darkgrey", "A9A9A9"); 43 | AddTopColor("darkgreen", "006400"); 44 | AddTopColor("darkkhaki", "BDB76B"); 45 | AddTopColor("darkmagenta", "8B008B"); 46 | AddTopColor("darkolivegreen", "556B2F"); 47 | AddTopColor("darkorange", "FF8C00"); 48 | AddTopColor("darkorchid", "9932CC"); 49 | AddTopColor("darkred", "8B0000"); 50 | AddTopColor("darksalmon", "E9967A"); 51 | AddTopColor("darkseagreen", "8FBC8F"); 52 | AddTopColor("darkslateblue", "483D8B"); 53 | AddTopColor("darkslategray", "2F4F4F"); 54 | AddTopColor("darkslategrey", "2F4F4F"); 55 | AddTopColor("darkturquoise", "00CED1"); 56 | AddTopColor("darkviolet", "9400D3"); 57 | AddTopColor("deeppink", "FF1493"); 58 | AddTopColor("deepskyblue", "00BFFF"); 59 | AddTopColor("dimgray", "696969"); 60 | AddTopColor("dimgrey", "696969"); 61 | AddTopColor("dodgerblue", "1E90FF"); 62 | AddTopColor("exalted", "CCCCCD"); 63 | AddTopColor("firebrick", "B22222"); 64 | AddTopColor("floralwhite", "FFFAF0"); 65 | AddTopColor("forestgreen", "228B22"); 66 | AddTopColor("frozen", "4983B3"); 67 | AddTopColor("fuchsia", "FF00FF"); 68 | AddTopColor("fullblue", "0000FF"); 69 | AddTopColor("fullred", "FF0000"); 70 | AddTopColor("gainsboro", "DCDCDC"); 71 | AddTopColor("genuine", "4D7455"); 72 | AddTopColor("ghostwhite", "F8F8FF"); 73 | AddTopColor("gold", "FFD700"); 74 | AddTopColor("goldenrod", "DAA520"); 75 | AddTopColor("gray", "CCCCCC"); 76 | AddTopColor("grey", "CCCCCC"); 77 | AddTopColor("green", "3EFF3E"); 78 | AddTopColor("greenyellow", "ADFF2F"); 79 | AddTopColor("haunted", "38F3AB"); 80 | AddTopColor("honeydew", "F0FFF0"); 81 | AddTopColor("hotpink", "FF69B4"); 82 | AddTopColor("immortal", "E4AE33"); 83 | AddTopColor("indianred", "CD5C5C"); 84 | AddTopColor("indigo", "4B0082"); 85 | AddTopColor("ivory", "FFFFF0"); 86 | AddTopColor("khaki", "F0E68C"); 87 | AddTopColor("lavender", "E6E6FA"); 88 | AddTopColor("lavenderblush", "FFF0F5"); 89 | AddTopColor("lawngreen", "7CFC00"); 90 | AddTopColor("legendary", "D32CE6"); 91 | AddTopColor("lemonchiffon", "FFFACD"); 92 | AddTopColor("lightblue", "ADD8E6"); 93 | AddTopColor("lightcoral", "F08080"); 94 | AddTopColor("lightcyan", "E0FFFF"); 95 | AddTopColor("lightgoldenrodyellow", "FAFAD2"); 96 | AddTopColor("lightgray", "D3D3D3"); 97 | AddTopColor("lightgrey", "D3D3D3"); 98 | AddTopColor("lightgreen", "99FF99"); 99 | AddTopColor("lightpink", "FFB6C1"); 100 | AddTopColor("lightsalmon", "FFA07A"); 101 | AddTopColor("lightseagreen", "20B2AA"); 102 | AddTopColor("lightskyblue", "87CEFA"); 103 | AddTopColor("lightslategray", "778899"); 104 | AddTopColor("lightslategrey", "778899"); 105 | AddTopColor("lightsteelblue", "B0C4DE"); 106 | AddTopColor("lightyellow", "FFFFE0"); 107 | AddTopColor("lime", "00FF00"); 108 | AddTopColor("limegreen", "32CD32"); 109 | AddTopColor("linen", "FAF0E6"); 110 | AddTopColor("magenta", "FF00FF"); 111 | AddTopColor("maroon", "800000"); 112 | AddTopColor("mediumaquamarine", "66CDAA"); 113 | AddTopColor("mediumblue", "0000CD"); 114 | AddTopColor("mediumorchid", "BA55D3"); 115 | AddTopColor("mediumpurple", "9370D8"); 116 | AddTopColor("mediumseagreen", "3CB371"); 117 | AddTopColor("mediumslateblue", "7B68EE"); 118 | AddTopColor("mediumspringgreen", "00FA9A"); 119 | AddTopColor("mediumturquoise", "48D1CC"); 120 | AddTopColor("mediumvioletred", "C71585"); 121 | AddTopColor("midnightblue", "191970"); 122 | AddTopColor("mintcream", "F5FFFA"); 123 | AddTopColor("mistyrose", "FFE4E1"); 124 | AddTopColor("moccasin", "FFE4B5"); 125 | AddTopColor("mythical", "8847FF"); 126 | AddTopColor("navajowhite", "FFDEAD"); 127 | AddTopColor("navy", "000080"); 128 | AddTopColor("normal", "B2B2B2"); 129 | AddTopColor("oldlace", "FDF5E6"); 130 | AddTopColor("olive", "9EC34F"); 131 | AddTopColor("olivedrab", "6B8E23"); 132 | AddTopColor("orange", "FFA500"); 133 | AddTopColor("orangered", "FF4500"); 134 | AddTopColor("orchid", "DA70D6"); 135 | AddTopColor("palegoldenrod", "EEE8AA"); 136 | AddTopColor("palegreen", "98FB98"); 137 | AddTopColor("paleturquoise", "AFEEEE"); 138 | AddTopColor("palevioletred", "D87093"); 139 | AddTopColor("papayawhip", "FFEFD5"); 140 | AddTopColor("peachpuff", "FFDAB9"); 141 | AddTopColor("peru", "CD853F"); 142 | AddTopColor("pink", "FFC0CB"); 143 | AddTopColor("plum", "DDA0DD"); 144 | AddTopColor("powderblue", "B0E0E6"); 145 | AddTopColor("purple", "800080"); 146 | AddTopColor("rare", "4B69FF"); 147 | AddTopColor("red", "FF4040"); 148 | AddTopColor("rosybrown", "BC8F8F"); 149 | AddTopColor("royalblue", "4169E1"); 150 | AddTopColor("saddlebrown", "8B4513"); 151 | AddTopColor("salmon", "FA8072"); 152 | AddTopColor("sandybrown", "F4A460"); 153 | AddTopColor("seagreen", "2E8B57"); 154 | AddTopColor("seashell", "FFF5EE"); 155 | AddTopColor("selfmade", "70B04A"); 156 | AddTopColor("sienna", "A0522D"); 157 | AddTopColor("silver", "C0C0C0"); 158 | AddTopColor("skyblue", "87CEEB"); 159 | AddTopColor("slateblue", "6A5ACD"); 160 | AddTopColor("slategray", "708090"); 161 | AddTopColor("slategrey", "708090"); 162 | AddTopColor("snow", "FFFAFA"); 163 | AddTopColor("springgreen", "00FF7F"); 164 | AddTopColor("steelblue", "4682B4"); 165 | AddTopColor("strange", "CF6A32"); 166 | AddTopColor("tan", "D2B48C"); 167 | AddTopColor("teal", "008080"); 168 | AddTopColor("thistle", "D8BFD8"); 169 | AddTopColor("tomato", "FF6347"); 170 | AddTopColor("turquoise", "40E0D0"); 171 | AddTopColor("uncommon", "B0C3D9"); 172 | AddTopColor("unique", "FFD700"); 173 | AddTopColor("unusual", "8650AC"); 174 | AddTopColor("valve", "A50F79"); 175 | AddTopColor("vintage", "476291"); 176 | AddTopColor("violet", "EE82EE"); 177 | AddTopColor("wheat", "F5DEB3"); 178 | AddTopColor("white", "FFFFFF"); 179 | AddTopColor("whitesmoke", "F5F5F5"); 180 | AddTopColor("yellow", "FFFF00"); 181 | AddTopColor("yellowgreen", "9ACD32"); 182 | } 183 | 184 | void AddTopColor(const char[] sName, const char[] sColor) 185 | { 186 | int aColor[4]; 187 | ParseColor(sColor, aColor); 188 | 189 | g_hTopColors.SetArray(sName, aColor, sizeof(aColor)); 190 | } 191 | 192 | void ParseColor(const char[] sColor, int aColor[4]) 193 | { 194 | int iColor = StringToInt(sColor, 16); 195 | aColor[0] = iColor >> 16; 196 | aColor[1] = iColor >> 8 & 255; 197 | aColor[2] = iColor & 255; 198 | aColor[3] = 255; 199 | } 200 | 201 | void ParseTopColor(const char[] sText, int &iStart, int aColor[4]) 202 | { 203 | int iEnd = StrContains(sText, "}"); 204 | if (sText[0] != '{' || iEnd == -1) { 205 | return; 206 | } 207 | 208 | char sColor[32]; 209 | strcopy(sColor, iEnd, sText[1]); 210 | if (sColor[0] == '#') { 211 | ParseColor(sColor[1], aColor); 212 | } else { 213 | g_hTopColors.GetArray(sColor, aColor, sizeof(aColor)); 214 | } 215 | iStart = iEnd + 1; 216 | } 217 | -------------------------------------------------------------------------------- /scripting/fftlite.sp: -------------------------------------------------------------------------------- 1 | #define TEAM_SPECTATOR 1 2 | #define TEAM_SURVIVORS 2 3 | #define TEAM_INFECTED 3 4 | 5 | #define PLUGIN_VERSION "1.0" 6 | 7 | #include 8 | #include 9 | 10 | public Plugin:myinfo = { 11 | name = "Friendly-Fire Toolkit Lite", 12 | author = "HMBSbige", 13 | description = "友伤控制插件", 14 | version = PLUGIN_VERSION, 15 | url = "https://github.com/HMBSbige" 16 | } 17 | 18 | new Handle:g_FriendlyFireBots; 19 | new Handle:g_FriendlyFireAbsorb; 20 | new Handle:g_FriendlyFireReflect; 21 | new Handle:g_FriendlyFireKick; 22 | new Handle:g_FriendlyFireIncap; 23 | new friendlyFireAmount[MAXPLAYERS + 1]; 24 | 25 | public OnPluginStart() 26 | { 27 | CreateConVar("fftlite_version", PLUGIN_VERSION, "插件版本"); 28 | 29 | g_FriendlyFireAbsorb = CreateConVar("fftlite_absorb","1","1=不会受到友军伤害"); 30 | g_FriendlyFireReflect = CreateConVar("fftlite_reflect","1","1=会受到对队友造成的伤害"); 31 | g_FriendlyFireKick = CreateConVar("fftlite_kick","0","0=OFF 对队友造成多少伤害会被踢"); 32 | g_FriendlyFireIncap = CreateConVar("fftlite_incap","0","1=被反射的伤害可以击杀自己"); 33 | g_FriendlyFireBots = CreateConVar("fftlite_bots","0","1=BOT有友伤"); 34 | 35 | AutoExecConfig(true, "fftlite"); 36 | } 37 | 38 | public Action:OnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype) 39 | { 40 | if (IsClientActual(victim) && IsClientActual(attacker) && IsSameTeam(victim, attacker) && victim != attacker) 41 | { 42 | if (!IsFakeClient(attacker)) friendlyFireAmount[attacker] += RoundToFloor(damage); 43 | if (GetConVarInt(g_FriendlyFireReflect) == 1) 44 | { 45 | if (!IsFakeClient(attacker) || (IsFakeClient(attacker) && GetConVarInt(g_FriendlyFireBots) == 1)) 46 | { 47 | if (GetClientHealth(attacker) - RoundToFloor(damage) < 1) 48 | { 49 | if (GetConVarInt(g_FriendlyFireIncap) == 0) SetEntityHealth(attacker, 1); 50 | else SetEntProp(attacker, Prop_Send, "m_isIncapacitated", true, 1); 51 | } 52 | else SetEntityHealth(attacker, GetClientHealth(attacker) - RoundToFloor(damage)); 53 | } 54 | } 55 | if (GetConVarInt(g_FriendlyFireAbsorb) == 1) damage = 0.0; 56 | if (GetConVarInt(g_FriendlyFireKick) > 0 && friendlyFireAmount[attacker] > GetConVarInt(g_FriendlyFireKick)) KickClient(attacker); 57 | return Plugin_Changed; 58 | } 59 | return Plugin_Continue; 60 | } 61 | 62 | public OnConfigsExecuted() 63 | { 64 | AutoExecConfig(true, "fftlite"); 65 | } 66 | 67 | public bool:IsSameTeam(first, second) 68 | { 69 | if (GetClientTeam(first) == GetClientTeam(second)) return true; 70 | return false; 71 | } 72 | 73 | public bool:IsClientActual(client) 74 | { 75 | if (client < 1 || client > MaxClients || !IsClientInGame(client)) return false; 76 | return true; 77 | } 78 | 79 | public OnClientPostAdminCheck(client) 80 | { 81 | if (IsClientActual(client)) 82 | { 83 | SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage); 84 | friendlyFireAmount[client] = 0; 85 | } 86 | } 87 | 88 | public OnClientDisconnect(client) 89 | { 90 | if (IsClientActual(client)) 91 | { 92 | SDKUnhook(client, SDKHook_OnTakeDamage, OnTakeDamage); 93 | friendlyFireAmount[client] = 0; 94 | } 95 | } -------------------------------------------------------------------------------- /scripting/hostname.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #pragma semicolon 1 3 | 4 | public Plugin:myinfo = 5 | { 6 | name = "L4D2服务器名", 7 | author = "HMBSbige", 8 | description = "更改服务器名", 9 | version = "1.0", 10 | url = "https://github.com/HMBSbige" 11 | } 12 | public OnPluginStart() 13 | { 14 | HookEvent("round_start", CheckTheChineseName); 15 | } 16 | public CheckTheChineseName(Handle:event, const String:name[], bool:dontBroadcast) 17 | { 18 | 19 | new String:sPath[PLATFORM_MAX_PATH]; 20 | BuildPath(Path_SM, sPath, sizeof(sPath),"configs/hostname/hostname.txt"); 21 | 22 | new Handle:file = OpenFile(sPath, "r"); 23 | if(file == INVALID_HANDLE) 24 | return; 25 | 26 | new String:readData[256]; 27 | while(!IsEndOfFile(file) && ReadFileLine(file, readData, sizeof(readData))) 28 | { 29 | SetConVarString(FindConVar("hostname"),readData); 30 | } 31 | } -------------------------------------------------------------------------------- /scripting/include/updater.inc: -------------------------------------------------------------------------------- 1 | #if defined _updater_included 2 | #endinput 3 | #endif 4 | #define _updater_included 5 | 6 | /** 7 | * Adds your plugin to the updater. The URL will be updated if 8 | * your plugin was previously added. 9 | * 10 | * @param url URL to your plugin's update file. 11 | * @noreturn 12 | */ 13 | native void Updater_AddPlugin(const char[] url); 14 | 15 | /** 16 | * Removes your plugin from the updater. This does not need to 17 | * be called during OnPluginEnd. 18 | * 19 | * @noreturn 20 | */ 21 | native void Updater_RemovePlugin(); 22 | 23 | /** 24 | * Forces your plugin to be checked for updates. The behaviour 25 | * of the update is dependant on the server's configuration. 26 | * 27 | * @return True if an update was triggered. False otherwise. 28 | * @error Plugin not found in updater. 29 | */ 30 | native bool Updater_ForceUpdate(); 31 | 32 | /** 33 | * Called when your plugin is about to be checked for updates. 34 | * 35 | * @return Plugin_Handled to prevent checking, Plugin_Continue to allow it. 36 | */ 37 | forward Action Updater_OnPluginChecking(); 38 | 39 | /** 40 | * Called when your plugin is about to begin downloading an available update. 41 | * 42 | * @return Plugin_Handled to prevent downloading, Plugin_Continue to allow it. 43 | */ 44 | forward Action Updater_OnPluginDownloading(); 45 | 46 | /** 47 | * Called when your plugin's update files have been fully downloaded 48 | * and are about to write to their proper location. This should be used 49 | * to free read-only resources that require write access for your update. 50 | * 51 | * @note OnPluginUpdated will be called later during the same frame. 52 | * 53 | * @noreturn 54 | */ 55 | forward void Updater_OnPluginUpdating(); 56 | 57 | /** 58 | * Called when your plugin's update has been completed. It is safe 59 | * to reload your plugin at this time. 60 | * 61 | * @noreturn 62 | */ 63 | forward void Updater_OnPluginUpdated(); 64 | 65 | /** 66 | * @brief Reloads a plugin. 67 | * 68 | * @param plugin Plugin Handle (INVALID_HANDLE uses the calling plugin). 69 | * @noreturn 70 | */ 71 | stock void ReloadPlugin(Handle plugin = INVALID_HANDLE) 72 | { 73 | char filename[64]; 74 | GetPluginFilename(plugin, filename, sizeof(filename)); 75 | ServerCommand("sm plugins reload %s", filename); 76 | } 77 | 78 | 79 | public SharedPlugin __pl_updater = 80 | { 81 | name = "updater", 82 | file = "updater.smx", 83 | #if defined REQUIRE_PLUGIN 84 | required = 1, 85 | #else 86 | required = 0, 87 | #endif 88 | }; 89 | 90 | #if !defined REQUIRE_PLUGIN 91 | public void __pl_updater_SetNTVOptional() 92 | { 93 | MarkNativeAsOptional("Updater_AddPlugin"); 94 | MarkNativeAsOptional("Updater_RemovePlugin"); 95 | MarkNativeAsOptional("Updater_ForceUpdate"); 96 | } 97 | #endif 98 | -------------------------------------------------------------------------------- /scripting/kill_counter.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #include 3 | #include 4 | 5 | #define PLUGIN_VERSION "1.0" 6 | #define PLUGIN_PREFIX "\x03[提示] \x01" 7 | 8 | new Handle:g_hCounter = INVALID_HANDLE; 9 | new Handle:g_hInterval = INVALID_HANDLE; 10 | new Handle:g_hTimer = INVALID_HANDLE; 11 | new Handle:g_hCookie = INVALID_HANDLE; 12 | new Handle:friendlyfire=INVALID_HANDLE; 13 | new Handle:friendly=INVALID_HANDLE; 14 | new bool:g_bDisplay[MAXPLAYERS+1]; 15 | new g_iData[MAXPLAYERS+1][3]; 16 | 17 | public Plugin:myinfo = 18 | { 19 | name = "击杀统计", 20 | author = "HMBSbige", 21 | description = "统计击杀和爆头数", 22 | version = PLUGIN_VERSION, 23 | url = "https://github.com/HMBSbige" 24 | } 25 | 26 | public OnPluginStart() 27 | { 28 | //Create the necessary convars for the plugin 29 | CreateConVar("sm_killcounter_version", PLUGIN_VERSION, "Kill Counter Version", FCVAR_NONE 30 | ); 31 | g_hCounter = CreateConVar("sm_killcounter", "1", "Determines plugin functionality. (0 = Off, 1 = All Kills, 2 = Headshots Only)", FCVAR_NONE, true, 0.0, true, 2.0); 32 | g_hInterval = CreateConVar("sm_killcounter_ad_interval", "30.0", "Amount of seconds between advertisements.", FCVAR_NONE, true, 0.0); 33 | friendly = CreateConVar("sm_killcounter_f", "0", "Friendly Fire message. 0: Off 1: On",FCVAR_NONE 34 | ,true,0.0,true,1.0); 35 | friendlyfire = CreateConVar("sm_killcounter_ff", "0", "Print to attacker. 0: Off 1: Hint",FCVAR_NONE,true,0.0,true,1.0); 36 | 37 | //Generate a configuration file 38 | AutoExecConfig(true, "Kill_Counter"); 39 | 40 | //Register the death event so we can track kills 41 | HookEvent("player_death", Event_OnPlayerDeath, EventHookMode_Pre); 42 | HookEvent("player_hurt", Event_Player_Hurt, EventHookMode_Post); 43 | HookConVarChange(g_hInterval, ConVarChange_Interval); 44 | 45 | 46 | //Create the commands for the plugin 47 | RegConsoleCmd("sm_counter", Command_Counter); 48 | RegConsoleCmd("sm_kills", Command_Kills); 49 | RegConsoleCmd("sm_teamkills", Command_TeamKills); 50 | 51 | //Used in ClientPrefs, for saving counter settings 52 | g_hCookie = RegClientCookie("Kill_Counter_Status", "Display Kill Counter", CookieAccess_Protected); 53 | SetCookieMenuItem(Menu_Status, 0, "Display Kill Counter"); 54 | } 55 | 56 | //Called when the map starts 57 | public OnMapStart() 58 | { 59 | if(GetConVarFloat(g_hInterval)) 60 | 61 | g_hTimer = CreateTimer(GetConVarFloat(g_hInterval), Timer_DisplayAds, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); 62 | 63 | } 64 | public OnMapEnd() 65 | { 66 | if(g_hTimer != INVALID_HANDLE) 67 | if(CloseHandle(g_hTimer)) 68 | g_hTimer = INVALID_HANDLE; 69 | } 70 | 71 | //If for whatever reason something wiggy happens later, default the setting to on for the client first. 72 | public OnClientConnected(client) 73 | { 74 | g_bDisplay[client] = false; 75 | } 76 | 77 | //Called after the player has been authorized and fully in-game 78 | public OnClientPostAdminCheck(client) 79 | { 80 | //Create a timer to check the status of the player's cookie 81 | if(!IsFakeClient(client)) 82 | CreateTimer(0.0, Timer_Check, client, TIMER_FLAG_NO_MAPCHANGE); 83 | } 84 | 85 | //This timer will loop until the client's cookies are loaded, or until the client leaves 86 | public Action:Timer_Check(Handle:timer, any:client) 87 | { 88 | if(client) 89 | { 90 | if(AreClientCookiesCached(client)) 91 | CreateTimer(0.0, Timer_Process, client, TIMER_FLAG_NO_MAPCHANGE); 92 | else if(IsClientInGame(client)) 93 | CreateTimer(5.0, Timer_Check, client, TIMER_FLAG_NO_MAPCHANGE); 94 | } 95 | 96 | return Plugin_Continue; 97 | } 98 | 99 | //Called after a client's cookies have been processed by the server 100 | public Action:Timer_Process(Handle:timer, any:client) 101 | { 102 | //For whatever reason, make sure the client is still in game 103 | if(IsClientInGame(client)) 104 | { 105 | //Declare a temporary string and store the contents of the client's cookie 106 | decl String:g_sCookie[3] = ""; 107 | GetClientCookie(client, g_hCookie, g_sCookie, sizeof(g_sCookie)); 108 | 109 | //If the cookie is empty, throw some data into it. If the cookie is disabled, we turn off the client's setting 110 | if(StrEqual(g_sCookie, "")) 111 | SetClientCookie(client, g_hCookie, "1"); 112 | else if(StrEqual(g_sCookie, "0")) 113 | g_bDisplay[client] = false; 114 | } 115 | 116 | return Plugin_Continue; 117 | } 118 | 119 | //Repeating timer that displays a message to all clients. 120 | public Action:Timer_DisplayAds(Handle:timer) 121 | { 122 | PrintToChatAll("%s输入 \x04!counter\x01 开启/关闭击杀提示;输入 \x04!kills\x01 显示你的当前数据. 输入 \x04!teamkills\x01 显示全队当前数据.", PLUGIN_PREFIX); 123 | } 124 | 125 | //As the name implies, this is called when a player goes splat. 126 | public Action:Event_OnPlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) 127 | { 128 | //Get the attacker from the event 129 | new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); 130 | 131 | //Only process if the player is a legal attacker (i.e., a player) 132 | if(attacker && attacker <= MaxClients) 133 | Void_PrintKillInfo(attacker, GetEventBool(event, "headshot")); 134 | 135 | return Plugin_Continue; 136 | } 137 | 138 | //Define as a void since it won't return any information. Prints stuff to the client. 139 | Void_PrintKillInfo(attacker, bool:g_bHeadshot) 140 | { 141 | new g_iTemp, g_iMode = GetConVarInt(g_hCounter); 142 | 143 | switch(g_iMode) 144 | { 145 | case 1: 146 | { 147 | g_iTemp = g_iData[attacker][1]; 148 | g_iData[attacker][1]++; 149 | if(g_bDisplay[attacker]) 150 | { 151 | if(g_iTemp >= 1) 152 | PrintHintText(attacker, "击杀 +%d", g_iTemp); 153 | else 154 | PrintHintText(attacker, "击杀!"); 155 | } 156 | 157 | if(g_bHeadshot) 158 | { 159 | g_iTemp = g_iData[attacker][0]; 160 | g_iData[attacker][0]++; 161 | if(g_bDisplay[attacker]) 162 | { 163 | if(g_iTemp > 1) 164 | PrintHintText(attacker, "爆头 +%d", g_iTemp); 165 | else 166 | PrintHintText(attacker, "爆头!"); 167 | } 168 | } 169 | } 170 | case 2: 171 | { 172 | if(g_bHeadshot) 173 | { 174 | g_iTemp = g_iData[attacker][0]; 175 | g_iData[attacker][0]++; 176 | if(g_bDisplay[attacker]) 177 | { 178 | if(g_iTemp > 1) 179 | PrintHintText(attacker, "爆头 +%d", g_iTemp); 180 | else 181 | PrintHintText(attacker, "爆头!"); 182 | } 183 | } 184 | } 185 | } 186 | } 187 | 188 | //This command is fired when the user inputs sm_counter, !counter, or /counter 189 | public Action:Command_Counter(client, args) 190 | { 191 | //Their status is already saved, let's just use that to determine the setting. 192 | if(g_bDisplay[client]) 193 | { 194 | //Display is on, they want off 195 | SetClientCookie(client, g_hCookie, "0"); 196 | PrintToChat(client, "%s你已禁用击杀提示.", PLUGIN_PREFIX); 197 | } 198 | else 199 | { 200 | //Display is off, turn on 201 | SetClientCookie(client, g_hCookie, "1"); 202 | PrintToChat(client, "%s你已启用击杀提示.", PLUGIN_PREFIX); 203 | } 204 | 205 | g_bDisplay[client] = !g_bDisplay[client]; 206 | return Plugin_Handled; 207 | } 208 | 209 | //Used for showing the client their counter status should they type !settings 210 | public Menu_Status(client, CookieMenuAction:action, any:info, String:buffer[], maxlen) 211 | { 212 | switch(action) 213 | { 214 | case CookieMenuAction_DisplayOption: 215 | Format(buffer, maxlen, "显示击杀数据"); 216 | case CookieMenuAction_SelectOption: 217 | CreateMenuStatus(client); 218 | } 219 | } 220 | 221 | //Menu that appears when a user types !settings 222 | stock CreateMenuStatus(client) 223 | { 224 | new Handle:menu = CreateMenu(Menu_StatusDisplay); 225 | decl String:text[64]; 226 | 227 | //The title of the menu 228 | Format(text, sizeof(text), "击杀计数"); 229 | SetMenuTitle(menu, text); 230 | 231 | //Since their status is already saved, use it to determine the change 232 | if(g_bDisplay[client]) 233 | AddMenuItem(menu, "击杀计数", "禁用击杀计数"); 234 | else 235 | AddMenuItem(menu, "击杀计数", "启用击杀计数"); 236 | 237 | //Give the menu a back button, and make it display on the client 238 | SetMenuExitBackButton(menu, true); 239 | SetMenuExitButton(menu, true); 240 | DisplayMenu(menu, client, 15); 241 | } 242 | 243 | //Determines if the menu should be opened or closed (i.e. if the client types !settings twice) 244 | public Menu_StatusDisplay(Handle:menu, MenuAction:action, param1, param2) 245 | { 246 | switch (action) 247 | { 248 | case MenuAction_Select: 249 | { 250 | if(param2 == 1) 251 | { 252 | //Their status is already saved, let's just use that to determine the setting. 253 | if(g_bDisplay[param1]) 254 | { 255 | //Display is on, they want off 256 | SetClientCookie(param1, g_hCookie, "0"); 257 | PrintToChat(param1, "%s你已禁用击杀提示.", PLUGIN_PREFIX); 258 | } 259 | else 260 | { 261 | //Display is off, turn on 262 | SetClientCookie(param1, g_hCookie, "1"); 263 | PrintToChat(param1, "%s你已启用击杀提示.", PLUGIN_PREFIX); 264 | } 265 | 266 | g_bDisplay[param1] = !g_bDisplay[param1]; 267 | } 268 | } 269 | case MenuAction_Cancel: 270 | { 271 | switch (param2) 272 | { 273 | case MenuCancel_ExitBack: 274 | { 275 | //Client has pressed back, let's give them the Cookie menu. 276 | ShowCookieMenu(param1); 277 | } 278 | } 279 | } 280 | case MenuAction_End: 281 | { 282 | //Menu has been closed (either by another menu or client). Squish that handle! 283 | CloseHandle(menu); 284 | } 285 | } 286 | } 287 | 288 | //Called when a client accesses sm_kills, !kills, or /kills 289 | public Action:Command_Kills(client, args) 290 | { 291 | new g_fPercent, g_iZombies, g_iHeadshots, g_iKills; 292 | decl String:g_sTemp[256]; 293 | 294 | g_iZombies += g_iData[client][1]; 295 | g_iHeadshots += g_iData[client][0]; 296 | g_iKills += (g_iData[client][1] + g_iData[client][0]); 297 | 298 | new Handle:g_hPanel = CreatePanel(); 299 | SetPanelTitle(g_hPanel, "击杀计数"); 300 | DrawPanelText(g_hPanel, "-==-==-==-==-"); 301 | Format(g_sTemp, sizeof(g_sTemp), "爆头击杀: %d", g_iHeadshots); 302 | DrawPanelText(g_hPanel, g_sTemp); 303 | 304 | Format(g_sTemp, sizeof(g_sTemp), "普通击杀: %d", g_iZombies); 305 | DrawPanelText(g_hPanel, g_sTemp); 306 | 307 | Format(g_sTemp, sizeof(g_sTemp), "总数: %d", g_iKills); 308 | DrawPanelText(g_hPanel, g_sTemp); 309 | 310 | if(g_iKills) 311 | g_fPercent = 100 * g_iHeadshots / g_iKills; 312 | Format(g_sTemp, sizeof(g_sTemp), "爆头率: %d %6", g_fPercent, "%"); 313 | DrawPanelText(g_hPanel, g_sTemp); 314 | DrawPanelText(g_hPanel, "-==-==-==-==-"); 315 | 316 | DrawPanelItem(g_hPanel, "关闭"); 317 | DrawPanelItem(g_hPanel, "重置计数"); 318 | SendPanelToClient(g_hPanel, client, KillsPanelHandler, 20); 319 | CloseHandle(g_hPanel); 320 | return Plugin_Handled; 321 | } 322 | 323 | //Handles the sm_kills panel 324 | public KillsPanelHandler(Handle:menu, MenuAction:action, param1, param2) 325 | { 326 | if (action == MenuAction_Select) 327 | { 328 | if (param2 == 2) 329 | { 330 | g_iData[param1][0] = 0; 331 | g_iData[param1][1] = 0; 332 | 333 | PrintToConsole(param1, "%s你的数据已被重置.", PLUGIN_PREFIX); 334 | } 335 | } 336 | } 337 | 338 | //Called when a client accesses sm_teamkills, !teamkills, or /teamkills 339 | public Action:Command_TeamKills(client, args) 340 | { 341 | new g_iTeam = GetClientTeam(client); 342 | if(g_iTeam >= 2) 343 | { 344 | decl String:g_sTemp[256]; 345 | new g_iCount, g_iArray[64], g_iTotalZombies, g_iTotalHeadshots, g_iTotalKills, g_fTotalPercent; 346 | 347 | for(new i = 1; i <= MaxClients; i++) 348 | { 349 | if(IsClientInGame(i) && !IsFakeClient(i) && g_iTeam == GetClientTeam(i)) 350 | { 351 | g_iTotalZombies += g_iData[i][1]; 352 | g_iTotalHeadshots += g_iData[i][0]; 353 | g_iTotalKills += (g_iData[i][1] + g_iData[i][0]); 354 | 355 | g_iArray[g_iCount] = i; 356 | g_iCount++; 357 | } 358 | } 359 | 360 | new Handle:g_hPanel = CreatePanel(); 361 | SetPanelTitle(g_hPanel, "全队击杀计数"); 362 | DrawPanelText(g_hPanel, "-==-==-==-==-"); 363 | 364 | Format(g_sTemp, sizeof(g_sTemp), "普通击杀: %d", g_iTotalZombies); 365 | DrawPanelText(g_hPanel, g_sTemp); 366 | 367 | Format(g_sTemp, sizeof(g_sTemp), "爆头: %d", g_iTotalHeadshots); 368 | DrawPanelText(g_hPanel, g_sTemp); 369 | 370 | Format(g_sTemp, sizeof(g_sTemp), "总数: %d", g_iTotalKills); 371 | DrawPanelText(g_hPanel, g_sTemp); 372 | 373 | if(g_iTotalKills) 374 | g_fTotalPercent = 100 * g_iTotalHeadshots / g_iTotalKills; 375 | Format(g_sTemp, sizeof(g_sTemp), "爆头率: %d %6", g_fTotalPercent, "%"); 376 | DrawPanelText(g_hPanel, g_sTemp); 377 | if(g_iCount > 0) 378 | { 379 | decl String:g_sName[64]; 380 | DrawPanelText(g_hPanel, "-==-==-==-==-"); 381 | for(new i = 0; i < g_iCount; i++) 382 | { 383 | GetClientName(g_iArray[i], g_sName, sizeof(g_sName)); 384 | Format(g_sTemp, sizeof(g_sTemp), "%s, 击杀: %d, 爆头: %d, 总数: %d", g_sName, g_iData[g_iArray[i]][1], g_iData[g_iArray[i]][0], (g_iData[g_iArray[i]][0] + g_iData[g_iArray[i]][1])); 385 | DrawPanelText(g_hPanel, g_sTemp); 386 | } 387 | } 388 | DrawPanelText(g_hPanel, "-==-==-==-==-"); 389 | DrawPanelItem(g_hPanel, "关闭"); 390 | 391 | SendPanelToClient(g_hPanel, client, TeamKillsPanelHandler, 20); 392 | CloseHandle(g_hPanel); 393 | } 394 | 395 | return Plugin_Handled; 396 | } 397 | 398 | //Don't need to use this for anything, but it has to be defined. Handles the sm_kills panel 399 | public TeamKillsPanelHandler(Handle:menu, MenuAction:action, param1, param2) 400 | { 401 | 402 | } 403 | 404 | //Called when hooked settings are changed. 405 | public ConVarChange_Interval(Handle:convar, const String:oldValue[], const String:newValue[]) 406 | { 407 | if(convar == g_hTimer) 408 | { 409 | if(g_hTimer != INVALID_HANDLE) 410 | KillTimer(g_hTimer); 411 | 412 | if(GetConVarFloat(g_hInterval)) 413 | 414 | g_hTimer = CreateTimer(GetConVarFloat(g_hInterval), Timer_DisplayAds, _, TIMER_REPEAT|TIMER_FLAG_NO_MAPCHANGE); 415 | 416 | } 417 | } 418 | 419 | public Action:Event_Player_Hurt(Handle:event, const String:name[], bool:dontBroadcast) { 420 | 421 | new client_userid = GetEventInt(event, "userid"); 422 | new client = GetClientOfUserId(client_userid); 423 | new attacker_userid = GetEventInt(event, "attacker"); 424 | new attacker = GetClientOfUserId(attacker_userid); 425 | 426 | new ff_attack = GetConVarInt(friendlyfire); 427 | new ff_victim = GetConVarInt(friendly); 428 | 429 | //Kill everything if... 430 | if (attacker == 0 || client == 0 || GetClientTeam(attacker) != GetClientTeam(client) || (ff_attack == 0 && ff_victim == 0)) 431 | { 432 | return Plugin_Continue; 433 | } 434 | 435 | new id = g_iData[attacker][2]; 436 | g_iData[attacker][2] = client; 437 | 438 | new String:hit[32]; 439 | switch (GetEventInt(event, "hitgroup")) 440 | { 441 | case 1: 442 | { 443 | hit="的 头部"; 444 | } 445 | case 2: 446 | { 447 | hit="的 胸部"; 448 | } 449 | case 3: 450 | { 451 | hit="的 肚子"; 452 | } 453 | case 4: 454 | { 455 | hit="的 左手"; 456 | } 457 | case 5: 458 | { 459 | hit="的 右手"; 460 | } 461 | case 6: 462 | { 463 | hit="的 左脚"; 464 | } 465 | case 7: 466 | { 467 | hit="的 右脚"; 468 | } 469 | default: 470 | {} 471 | } 472 | 473 | //new String:buf[128]; 474 | //Format(buf, 128, "%N hit %N%s.", attacker, client, hit); 475 | //PrintToServer(buf); 476 | 477 | if ((ff_attack == 1) && (id != client)) 478 | { 479 | PrintHintText(attacker, "你误伤了 %N.", client); 480 | } 481 | 482 | return Plugin_Continue; 483 | } -------------------------------------------------------------------------------- /scripting/l4d2_bwa_simplesupply.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | 3 | #include 4 | #include 5 | 6 | const TEAM_NONE = 0; 7 | const TEAM_SPECTATOR = 1; 8 | const TEAM_SURVIVOR = 2; 9 | const TEAM_INFECTED = 3; 10 | 11 | const MEDKIT_SEARCH_DISTANCE = 800; 12 | 13 | #define PLUGIN_VERSION "1.0.2" 14 | 15 | public Plugin:myinfo = { 16 | 17 | name = "L4D2 -=BwA=- Simple Supplier - Missing Medkit and Weapons Fix", 18 | author = "-=BwA=- jester", 19 | description = "Handle the missing medkits for > 4 player teams or the occasional no medkits/weapons at all", 20 | version = PLUGIN_VERSION, 21 | url = "http://forums.alliedmods.net/showthread.php?t=149830" 22 | }; 23 | 24 | new Float:startLoc[3]; 25 | new Float:startKitLoc[3]; 26 | new startKitCount = 0; 27 | new Float:startAmmo[3]; 28 | new numMeleeToSpawn = 0; 29 | new Float:meleeSpawnLocation[3]; 30 | new numWeaponsToSpawn = 0; 31 | new Float:weaponSpawnLocation[3]; 32 | new meleeClassCount = 0; 33 | new String:meleeClasses[16][32]; 34 | 35 | new Handle:spawnweps; 36 | 37 | new String:logFilePath[PLATFORM_MAX_PATH]; 38 | 39 | public OnPluginStart() { 40 | 41 | decl String:ModName[64]; 42 | GetGameFolderName(ModName, sizeof(ModName)); 43 | 44 | if(!StrEqual(ModName, "left4dead2", false)) 45 | { 46 | SetFailState("Use this in Left 4 Dead (2) only."); 47 | } 48 | 49 | CreateConVar("l4d2_bwa_simplesupply_version", PLUGIN_VERSION, "L4D2 BwA Simple Supply Version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD); 50 | 51 | spawnweps = CreateConVar("l4d2_SimpleSupply_SupplyWeapons", "0", "Supply weapons along with missing medkits", FCVAR_PLUGIN, true, 0.0, true, 1.0); 52 | 53 | BuildPath(Path_SM, logFilePath, sizeof(logFilePath), "logs/l4d2_bwa_locations.log"); 54 | 55 | RegAdminCmd("sm_supply", Command_Supply, ADMFLAG_GENERIC, "Supplies medpacks and weapons if needed"); 56 | 57 | HookEvent("round_freeze_end", Event_RoundFreezeEnd); 58 | 59 | } 60 | 61 | public Event_RoundFreezeEnd(Handle:event, const String:name[], bool:dontBroadcast) { 62 | 63 | GetMeleeStringTableArray(); 64 | 65 | SupplyMissingEntities(); 66 | 67 | } 68 | 69 | stock GetMeleeStringTableArray() { 70 | 71 | new MeleeStringTable = FindStringTable( "MeleeWeapons" ); 72 | meleeClassCount = GetStringTableNumStrings( MeleeStringTable ); 73 | 74 | for( new i = 0; i < meleeClassCount; i++ ) 75 | { 76 | ReadStringTable( MeleeStringTable, i, meleeClasses[i], 32 ); 77 | } 78 | } 79 | 80 | public Action:Command_Supply(client, args) { 81 | 82 | SupplyMissingEntities(); 83 | } 84 | 85 | SupplyMissingEntities() { 86 | 87 | FindStartArea(); 88 | 89 | // Returns the count, and also gets the closest medkit location 90 | startKitCount = GetHealthPacksAtLocation(startLoc, MEDKIT_SEARCH_DISTANCE); 91 | 92 | new survivorcount = GetConVarInt(FindConVar("survivor_limit")); 93 | 94 | // If there are as many or more packs than peeps, no need to continue 95 | if (survivorcount <= startKitCount) return; 96 | 97 | new numtospawn = survivorcount - startKitCount; 98 | 99 | // If there are some kits found, then the weapons/melee are spawned ok. If there are 0, then there is usually nothing 100 | if (startKitCount > 0) 101 | { 102 | PrintToChatAll("\x03[JBSS]\x01 Found \x05%d\x01 Medkits at Start for \x05%d\x01 Survivors. Spawning \x05%d\x01 extra medkits", startKitCount, survivorcount, numtospawn); 103 | 104 | for (new i = 1; i <= numtospawn; i++) 105 | { 106 | SpawnEntityAtLocation(startKitLoc, "weapon_first_aid_kit"); 107 | } 108 | } 109 | else 110 | { 111 | PrintToChatAll("\x03[JBSS]\x01 Found NO Medkits or weapons at Start for \x05%d\x01 Survivors. Spawning \x05%d\x01 extra medkits, and guns and melee weapons", survivorcount, numtospawn); 112 | 113 | // Use an ammo pile location 114 | if (FindMedkitSpawnArea(startLoc, MEDKIT_SEARCH_DISTANCE)) 115 | { 116 | // Move the spawn a little up off the pile 117 | startAmmo[2] += 16.0; 118 | 119 | for (new i = 1; i <= numtospawn; i++) 120 | { 121 | SpawnEntityAtLocation(startAmmo, "weapon_first_aid_kit"); 122 | } 123 | } 124 | else 125 | { 126 | new client = FirstSurvivor(); 127 | 128 | if (client == -1) return; 129 | 130 | GetClientAbsOrigin(client, startAmmo); 131 | 132 | for (new i = 1; i <= numtospawn; i++) 133 | { 134 | SpawnEntityAtLocation(startAmmo, "weapon_first_aid_kit"); 135 | } 136 | 137 | } 138 | 139 | if(GetConVarBool(spawnweps)) 140 | { 141 | numWeaponsToSpawn = numtospawn; 142 | weaponSpawnLocation = startAmmo; 143 | 144 | CreateTimer( 1.0, Timer_SpawnWeapons ); 145 | 146 | numMeleeToSpawn = numtospawn - 1; 147 | meleeSpawnLocation = startAmmo; 148 | 149 | CreateTimer( 1.0, Timer_SpawnMeleeWeapons ); 150 | } 151 | } 152 | 153 | } 154 | 155 | public Action:Timer_SpawnWeapons(Handle:timer) { 156 | 157 | new numhalf = RoundToCeil(float(numWeaponsToSpawn / 2)); 158 | 159 | if (!IsThirdMapOrHigher()) 160 | { 161 | PrintToChatAll("\x03[JBSS]\x01 Spawning \x05%d\x01 smg's, pump shotguns and pistols", numhalf); 162 | 163 | for (new i = 1; i <= numhalf; i++) 164 | { 165 | SpawnEntityAtLocation(weaponSpawnLocation, "weapon_smg"); 166 | SpawnEntityAtLocation(weaponSpawnLocation, "weapon_pumpshotgun"); 167 | SpawnEntityAtLocation(weaponSpawnLocation, "weapon_pistol"); 168 | } 169 | } 170 | else 171 | { 172 | PrintToChatAll("\x03[JBSS]\x01 Spawning \x05%d\x01 smg's, pump shotguns and pistols", numhalf); 173 | 174 | for (new i = 1; i <= numhalf; i++) 175 | { 176 | SpawnEntityAtLocation(weaponSpawnLocation, "weapon_autoshotgun"); 177 | SpawnEntityAtLocation(weaponSpawnLocation, "weapon_rifle_ak47"); 178 | SpawnEntityAtLocation(weaponSpawnLocation, "weapon_pistol"); 179 | } 180 | } 181 | 182 | } 183 | 184 | public Action:Timer_SpawnMeleeWeapons( Handle:timer ) { 185 | 186 | decl Float:spawnpos[3], Float:spawnangles[3]; 187 | 188 | spawnpos = meleeSpawnLocation; 189 | 190 | spawnpos[2] += 16; spawnangles[0] = 90.0; 191 | 192 | for (new i = 0; i < numMeleeToSpawn; i++ ) 193 | { 194 | new rand = GetRandomInt( 0, meleeClassCount - 1 ); 195 | SpawnMeleeWeapons( meleeClasses[rand], spawnpos, spawnangles ); 196 | } 197 | 198 | } 199 | 200 | // Little tidbit from "Melee In The Saferoom" by N3wton 201 | stock SpawnMeleeWeapons( const String:meleeclass[32], Float:meleepos[3], Float:meleeangles[3] ) { 202 | 203 | decl Float:pos[3], Float:angles[3]; 204 | pos = meleepos; 205 | angles = meleeangles; 206 | 207 | pos[0] += ( -10 + GetRandomInt( 0, 20 ) ); 208 | pos[1] += ( -10 + GetRandomInt( 0, 20 ) ); 209 | pos[2] += GetRandomInt( 0, 10 ); 210 | angles[1] = GetRandomFloat( 0.0, 360.0 ); 211 | 212 | new wep = CreateEntityByName( "weapon_melee" ); 213 | DispatchKeyValue( wep, "melee_script_name", meleeclass ); 214 | DispatchSpawn( wep ); 215 | TeleportEntity(wep, pos, angles, NULL_VECTOR ); 216 | } 217 | 218 | // Cheesy Kludge, just look for "m1_" in the map name 219 | stock bool:IsFirstMap() { 220 | 221 | decl String:mapname[128]; 222 | GetCurrentMap(mapname, sizeof(mapname)); 223 | 224 | return (StrContains(mapname, "m1_", false) != -1); 225 | } 226 | 227 | // Cheesy Kludge, just look for "m3_" in the map name 228 | stock bool:IsThirdMapOrHigher() { 229 | 230 | decl String:mapname[128]; 231 | GetCurrentMap(mapname, sizeof(mapname)); 232 | 233 | return ((StrContains(mapname, "m3_", false) != -1) || (StrContains(mapname, "m4_", false) != -1) || (StrContains(mapname, "m5_", false) != -1)); 234 | 235 | } 236 | 237 | bool:FindStartArea() { 238 | 239 | startLoc[0] = 0.0; 240 | startLoc[1] = 0.0; 241 | startLoc[2] = 0.0; 242 | 243 | // On first map, not in safe room, just start are 244 | if (IsFirstMap()) 245 | { 246 | new ent = -1; 247 | 248 | while((ent = FindEntityByClassname(ent, "info_survivor_position")) != -1) 249 | { 250 | if(IsValidEntity(ent)) 251 | { 252 | GetEntPropVector(ent, Prop_Send, "m_vecOrigin", startLoc); 253 | return true; 254 | } 255 | } 256 | } 257 | else 258 | { 259 | new ent = -1; 260 | // Find a safe room door 261 | while((ent = FindEntityByClassname(ent, "prop_door_rotating_checkpoint")) != -1) 262 | { 263 | if(IsValidEntity(ent)) 264 | { 265 | // The start saferoom door is the locked one 266 | if(GetEntProp(ent, Prop_Send, "m_bLocked") == 1) 267 | { 268 | GetEntPropVector(ent, Prop_Send, "m_vecOrigin", startLoc); 269 | return true; 270 | } 271 | } 272 | } 273 | } 274 | 275 | return false; 276 | } 277 | 278 | GetHealthPacksAtLocation(Float:location[3], maxradius) { 279 | 280 | // Zero out the one that holds the closest pack 281 | startKitLoc[0] = 0.0; 282 | startKitLoc[1] = 0.0; 283 | startKitLoc[2] = 0.0; 284 | 285 | new Float:tmploc[3]; 286 | new Float:dist = 0.0; 287 | new Float:lastkitdist = 0.0; 288 | 289 | new count = 0; 290 | new ent = -1; 291 | 292 | while((ent = FindEntityByClassname(ent, "weapon_first_aid_kit_spawn")) != -1) 293 | { 294 | if(IsValidEntity(ent)) 295 | { 296 | GetEntPropVector(ent, Prop_Send, "m_vecOrigin", tmploc); 297 | 298 | dist = GetVectorDistance(location, tmploc, false); 299 | 300 | if (dist < maxradius) 301 | { 302 | if ((lastkitdist == 0.0) || (dist < lastkitdist)) 303 | { 304 | startKitLoc = tmploc; 305 | lastkitdist = dist; 306 | } 307 | count++; 308 | } 309 | } 310 | } 311 | 312 | return count; 313 | 314 | } 315 | 316 | bool:FindMedkitSpawnArea(Float:location[3], maxradius) { 317 | 318 | new ent = -1; 319 | 320 | new Float:tmploc[3]; 321 | 322 | startAmmo[0] = 0.0; 323 | startAmmo[1] = 0.0; 324 | startAmmo[2] = 0.0; 325 | 326 | while((ent = FindEntityByClassname(ent, "weapon_ammo_spawn")) != -1) 327 | { 328 | if(IsValidEntity(ent)) 329 | { 330 | GetEntPropVector(ent, Prop_Send, "m_vecOrigin", tmploc); 331 | 332 | if(GetVectorDistance(location, tmploc, false) < maxradius) 333 | { 334 | startAmmo = tmploc; 335 | return true; 336 | } 337 | } 338 | } 339 | 340 | return false; 341 | 342 | } 343 | 344 | stock bool:SpawnEntityAtLocation(Float:loc[3], String:entname[]) { 345 | 346 | new entity = CreateEntityByName(entname); 347 | 348 | if(entity != -1) 349 | { 350 | TeleportEntity(entity, loc, NULL_VECTOR, NULL_VECTOR); 351 | 352 | DispatchSpawn(entity); 353 | 354 | return true; 355 | } 356 | else 357 | { 358 | PrintToChatAll("\x03[JBSS]\x01 Error Creating \x04%s\x01 in [SpawnEntityAtLocation]", entname); 359 | return false; 360 | } 361 | 362 | } 363 | 364 | // Get the first survivor (player or bot, doesn't matter) 365 | stock FirstSurvivor() { 366 | 367 | for (new i = 1; i <= MaxClients; i++) 368 | { 369 | if(IsClientInGame(i) && IsClientConnected(i) && (GetClientTeam(i) == TEAM_SURVIVOR) && IsPlayerAlive(i)) 370 | { 371 | return i; 372 | } 373 | } 374 | 375 | return -1; 376 | } 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | -------------------------------------------------------------------------------- /scripting/l4d2_drop.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #pragma newdecls required 3 | 4 | #define PLUGIN_VERSION "1.6" 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | public Plugin myinfo = 12 | { 13 | name = "[L4D2] Weapon Drop", 14 | author = "HMBSbige", 15 | description = "Allows players to drop the weapon they are holding", 16 | version = PLUGIN_VERSION, 17 | url = "https://github.com/HMBSbige" 18 | }; 19 | 20 | public void OnPluginStart() 21 | { 22 | RegConsoleCmd("sm_drop", Command_Drop); 23 | CreateConVar("sm_drop_version", PLUGIN_VERSION, "[L4D2] Weapon Drop Version", FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 24 | LoadTranslations("common.phrases"); 25 | } 26 | 27 | public Action Command_Drop(int client, int args) 28 | { 29 | if (args > 2) 30 | { 31 | if (GetAdminFlag(GetUserAdmin(client), Admin_Root)) 32 | ReplyToCommand(client, "[SM] Usage: sm_drop <#userid|name> "); 33 | } 34 | else if (args == 0) 35 | { 36 | DropActiveWeapon(client); 37 | } 38 | else if (args > 0) 39 | { 40 | if (GetAdminFlag(GetUserAdmin(client), Admin_Root)) 41 | { 42 | char target[MAX_TARGET_LENGTH], arg[8]; 43 | GetCmdArg(1, target, sizeof(target)); 44 | GetCmdArg(2, arg, sizeof(arg)); 45 | int slot = StringToInt(arg); 46 | int targetid = FindTarget(client, target); 47 | if (targetid > 0 && IsClientInGame(targetid)) 48 | { 49 | if(slot > 0) 50 | DropSlot(targetid, slot); 51 | else 52 | DropActiveWeapon(targetid); 53 | 54 | return Plugin_Handled; 55 | } 56 | 57 | char target_name[MAX_TARGET_LENGTH]; 58 | int target_list[MAXPLAYERS], target_count; 59 | bool tn_is_ml; 60 | 61 | if ((target_count = ProcessTargetString( 62 | target, 63 | client, 64 | target_list, 65 | MAXPLAYERS, 66 | 0, 67 | target_name, 68 | sizeof(target_name), 69 | tn_is_ml)) <= 0) 70 | { 71 | ReplyToTargetError(client, target_count); 72 | return Plugin_Handled; 73 | } 74 | for (int i=0; i 0) 77 | DropSlot(target_list[i], slot); 78 | else 79 | DropActiveWeapon(target_list[i]); 80 | } 81 | } 82 | } 83 | return Plugin_Handled; 84 | } 85 | 86 | public void DropSlot(int client, int slot) 87 | { 88 | if (IsValidSurvivor(client) && IsPlayerAlive(client)) 89 | { 90 | slot--; 91 | int weapon = GetPlayerWeaponSlot(client, slot); 92 | if (IsValidEnt(weapon)) 93 | { 94 | DropWeapon(client, weapon); 95 | } 96 | } 97 | } 98 | 99 | void DropActiveWeapon(int client){ 100 | 101 | if (IsValidSurvivor(client) && IsPlayerAlive(client)) 102 | { 103 | int weapon = GetEntPropEnt(client, Prop_Data, "m_hActiveWeapon"); 104 | if(IsValidEnt(weapon)) 105 | DropWeapon(client, weapon); 106 | } 107 | } 108 | 109 | void DropWeapon(int client, int weapon){ 110 | 111 | int ammo = GetPlayerReserveAmmo(client, weapon); 112 | SDKHooks_DropWeapon(client, weapon); 113 | SetPlayerReserveAmmo(client, weapon, 0); 114 | SetEntProp(weapon, Prop_Send, "m_iExtraPrimaryAmmo", ammo); 115 | 116 | char classname[32]; 117 | GetEntityClassname(weapon, classname, sizeof(classname)); 118 | if (StrEqual(classname, "weapon_defibrillator")){ 119 | int modelindex = GetEntProp(weapon, Prop_Data, "m_nModelIndex"); 120 | SetEntProp(weapon, Prop_Send, "m_iWorldModelIndex", modelindex); 121 | } 122 | else if(StrEqual(classname, "weapon_rifle_m60")) 123 | { 124 | if(GetEntProp(weapon, Prop_Data, "m_iClip1") == 0) 125 | SetEntProp(weapon, Prop_Send, "m_iClip1", 1); 126 | } 127 | } 128 | 129 | //https://forums.alliedmods.net/showthread.php?t=260445 130 | stock void SetPlayerReserveAmmo(int client, int weapon, int ammo){ 131 | int ammotype = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType"); 132 | if (ammotype >= 0 ) { 133 | SetEntProp(client, Prop_Send, "m_iAmmo", ammo, _, ammotype); 134 | ChangeEdictState(client, FindDataMapInfo(client, "m_iAmmo")); 135 | } 136 | } 137 | 138 | stock int GetPlayerReserveAmmo(int client, int weapon) { 139 | int ammotype = GetEntProp(weapon, Prop_Send, "m_iPrimaryAmmoType"); 140 | if(ammotype >= 0){ 141 | return GetEntProp(client, Prop_Send, "m_iAmmo", _, ammotype); 142 | } 143 | return 0; 144 | } 145 | 146 | stock bool IsValidSpect(int client){ 147 | return (IsValidClient(client) && GetClientTeam(client) == 1 ); 148 | } 149 | 150 | stock bool IsValidSurvivor(int client){ 151 | return (IsValidClient(client) && GetClientTeam(client) == 2 ); 152 | } 153 | 154 | stock bool IsValidInfected(int client){ 155 | return (IsValidClient(client) && GetClientTeam(client) == 3 ); 156 | } 157 | 158 | stock bool IsValidClient(int client) 159 | { 160 | return (client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client)); 161 | } 162 | 163 | stock bool IsValidEnt(int entity) 164 | { 165 | return (entity > 0 && entity > MaxClients && IsValidEntity(entity) && entity != INVALID_ENT_REFERENCE); 166 | } -------------------------------------------------------------------------------- /scripting/l4d2_friendlyfireinfo.sp: -------------------------------------------------------------------------------- 1 | //fixed array out of bounds error 2 | 3 | #include 4 | #pragma semicolon 1 5 | #define VERSION "1.0" 6 | 7 | public Plugin:myinfo = { 8 | name = "L4D2 Friendly-Fire info", 9 | author = "HMBSbige", 10 | description = "击杀友伤显示插件.", 11 | version = VERSION, 12 | url = "https://github.com/HMBSbige" 13 | } 14 | 15 | new Handle:broadcast=INVALID_HANDLE; 16 | new Handle:broadcast_con=INVALID_HANDLE; 17 | new Handle:broadcast_attack=INVALID_HANDLE; 18 | new Handle:broadcast_victim=INVALID_HANDLE; 19 | new Handle:kill_timers[MAXPLAYERS+1][3]; 20 | new kill_counts[MAXPLAYERS+1][3]; 21 | 22 | public OnPluginStart() { 23 | //create new cvars 24 | broadcast = CreateConVar("l4d2_friendlyfireinfo_kill", "1", "0: Off. 1: On. 2: Headshots only.",FCVAR_REPLICATED|FCVAR_GAMEDLL|FCVAR_NOTIFY,true,0.0,true,2.0); 25 | broadcast_con = CreateConVar("l4d2_friendlyfireinfo_con", "0", "Printing Console 0: Off 1: On",FCVAR_REPLICATED|FCVAR_GAMEDLL|FCVAR_NOTIFY,true,0.0,true,1.0); 26 | broadcast_attack = CreateConVar("l4d2_friendlyfireinfo_ff", "2", "Print to attacker. 0: Off 1: Hint 2: Hint + Chat 3: Chat",FCVAR_REPLICATED|FCVAR_GAMEDLL|FCVAR_NOTIFY,true,0.0,true,3.0); 27 | broadcast_victim = CreateConVar("l4d2_friendlyfireinfo_hit", "0", "Print to victims chat. 0: Off 1: On",FCVAR_REPLICATED|FCVAR_GAMEDLL|FCVAR_NOTIFY,true,0.0,true,1.0); 28 | 29 | //hook events 30 | HookEvent("player_hurt", Event_Player_Hurt, EventHookMode_Post); 31 | HookEvent("player_death", Event_Player_Death, EventHookMode_Pre); 32 | 33 | AutoExecConfig(true,"l4d2_friendlyfireinfo"); 34 | } 35 | 36 | public Action:Event_Player_Death(Handle:event, const String:name[], bool:dontBroadcast) { 37 | new attacker_userid = GetEventInt(event, "attacker"); 38 | new attacker = GetClientOfUserId(attacker_userid); 39 | new bool:headshot = GetEventBool(event, "headshot"); 40 | 41 | if (attacker == 0 || GetClientTeam(attacker) == 1) 42 | { 43 | return Plugin_Continue; 44 | } 45 | 46 | printkillinfo(attacker, headshot); 47 | 48 | return Plugin_Continue; 49 | } 50 | 51 | printkillinfo(attacker, bool:headshot) 52 | { 53 | new intbroad=GetConVarInt(broadcast); 54 | new murder; 55 | 56 | if ((intbroad >= 1) && headshot) 57 | { 58 | murder = kill_counts[attacker][0]; 59 | 60 | if(murder>1) 61 | { 62 | PrintCenterText(attacker, "爆头! +%d", murder); 63 | KillTimer(kill_timers[attacker][0]); 64 | } 65 | else 66 | { 67 | PrintCenterText(attacker, "爆头!"); 68 | } 69 | 70 | kill_timers[attacker][0] = CreateTimer(5.0, KillCountTimer, (attacker*10)); 71 | kill_counts[attacker][0] = murder+1; 72 | } 73 | else if (intbroad == 1) 74 | { 75 | murder = kill_counts[attacker][1]; 76 | 77 | if(murder>=1) 78 | { 79 | PrintCenterText(attacker, "击杀! +%d", murder); 80 | KillTimer(kill_timers[attacker][1]); 81 | } 82 | else 83 | { 84 | PrintCenterText(attacker, "击杀!"); 85 | } 86 | 87 | kill_timers[attacker][1] = CreateTimer(5.0, KillCountTimer, ((attacker*10)+1)); 88 | kill_counts[attacker][1] = murder+1; 89 | } 90 | } 91 | 92 | public Action:KillCountTimer(Handle:timer, any:info) { 93 | new id=info-(info%10); 94 | info=info-id; 95 | id=id/10; 96 | 97 | kill_counts[id][info]=0; 98 | } 99 | 100 | public Action:Event_Player_Hurt(Handle:event, const String:name[], bool:dontBroadcast) { 101 | 102 | new client_userid = GetEventInt(event, "userid"); 103 | new client = GetClientOfUserId(client_userid); 104 | new attacker_userid = GetEventInt(event, "attacker"); 105 | new attacker = GetClientOfUserId(attacker_userid); 106 | 107 | new ff_attack = GetConVarInt(broadcast_attack); 108 | new ff_victim = GetConVarInt(broadcast_victim); 109 | new ff_con = GetConVarInt(broadcast_con); 110 | 111 | //Kill everything if... 112 | if (attacker == 0 || client == 0 || GetClientTeam(attacker) != GetClientTeam(client) || (ff_attack == 0 && ff_victim == 0 && ff_con == 0)) 113 | { 114 | return Plugin_Continue; 115 | } 116 | 117 | new id = kill_counts[attacker][2]; 118 | kill_timers[attacker][2] = CreateTimer(5.0, KillCountTimer, ((attacker*10)+2)); 119 | kill_counts[attacker][2] = client; 120 | 121 | new String:hit[32]; 122 | switch (GetEventInt(event, "hitgroup")) 123 | { 124 | case 1: 125 | { 126 | hit="的 \x04头部\x01"; 127 | } 128 | case 2: 129 | { 130 | hit="的 \x04胸部\x01"; 131 | } 132 | case 3: 133 | { 134 | hit="的 \x04肚子\x01"; 135 | } 136 | case 4: 137 | { 138 | hit="的 \x04左手\x01"; 139 | } 140 | case 5: 141 | { 142 | hit="的 \x04右手\x01"; 143 | } 144 | case 6: 145 | { 146 | hit="的 \x04左脚\x01"; 147 | } 148 | case 7: 149 | { 150 | hit="的 \x04右脚\x01"; 151 | } 152 | default: 153 | {} 154 | } 155 | 156 | 157 | if ((ff_attack == 1 || ff_attack == 2) && (id != client)) 158 | { 159 | PrintHintText(attacker, "你误伤了 %N", client); 160 | } 161 | 162 | if (ff_attack == 2 || ff_attack == 3) 163 | { 164 | PrintToChatAll("\x03%N\x01 误伤了 \x05%N\x01 %s", attacker,client, hit); 165 | } 166 | 167 | if (ff_victim == 1) 168 | { 169 | PrintToChat(client, "\x03%N\x01 误伤了你 %s", attacker, hit); 170 | } 171 | 172 | return Plugin_Continue; 173 | } 174 | -------------------------------------------------------------------------------- /scripting/l4d2_mapcontrol.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #include 3 | 4 | char sg_l4d2Map[48]; 5 | char sg_mode[24]; 6 | int ig_coop; 7 | 8 | public Plugin myinfo = 9 | { 10 | name = "MapControl", 11 | author = "HMBSbige", 12 | description = "L4D2 Coop Map Control", 13 | version = "1.0", 14 | url = "https://github.com/HMBSbige/SouceModPlugins" 15 | }; 16 | 17 | public void OnPluginStart() 18 | { 19 | HookEvent("finale_win", Event_FinalWin, EventHookMode_PostNoCopy); 20 | } 21 | 22 | public void OnMapStart() 23 | { 24 | ig_coop = 0; 25 | GetCurrentMap(sg_l4d2Map, sizeof(sg_l4d2Map) - 1); 26 | GetConVarString(FindConVar("mp_gamemode"), sg_mode, sizeof(sg_mode)-1); 27 | 28 | if (!strcmp(sg_mode, "coop", true)) 29 | { 30 | ig_coop = 1; 31 | } 32 | if (!strcmp(sg_mode, "realism", true)) 33 | { 34 | ig_coop = 1; 35 | } 36 | } 37 | 38 | public Action HxTimerNextMap(Handle timer) 39 | { 40 | if (StrContains(sg_l4d2Map, "c1m", true) != -1) 41 | { 42 | ServerCommand("changelevel c2m1_highway"); 43 | return Plugin_Continue; 44 | } 45 | 46 | if (StrContains(sg_l4d2Map, "c2m", true) != -1) 47 | { 48 | ServerCommand("changelevel c3m1_plankcountry"); 49 | return Plugin_Continue; 50 | } 51 | 52 | if (StrContains(sg_l4d2Map, "c3m", true) != -1) 53 | { 54 | ServerCommand("changelevel c4m1_milltown_a"); 55 | return Plugin_Continue; 56 | } 57 | 58 | if (StrContains(sg_l4d2Map, "c4m", true) != -1) 59 | { 60 | ServerCommand("changelevel c5m1_waterfront"); 61 | return Plugin_Continue; 62 | } 63 | 64 | if (StrContains(sg_l4d2Map, "c5m", true) != -1) 65 | { 66 | ServerCommand("changelevel c6m1_riverbank"); 67 | return Plugin_Continue; 68 | } 69 | 70 | if (StrContains(sg_l4d2Map, "c6m", true) != -1) 71 | { 72 | ServerCommand("changelevel c7m1_docks"); 73 | return Plugin_Continue; 74 | } 75 | 76 | if (StrContains(sg_l4d2Map, "c7m", true) != -1) 77 | { 78 | ServerCommand("changelevel c8m1_apartment"); 79 | return Plugin_Continue; 80 | } 81 | 82 | if (StrContains(sg_l4d2Map, "c8m", true) != -1) 83 | { 84 | ServerCommand("changelevel c9m1_alleys"); 85 | return Plugin_Continue; 86 | } 87 | 88 | if (StrContains(sg_l4d2Map, "c9m", true) != -1) 89 | { 90 | ServerCommand("changelevel c10m1_caves"); 91 | return Plugin_Continue; 92 | } 93 | 94 | if (StrContains(sg_l4d2Map, "c10m", true) != -1) 95 | { 96 | ServerCommand("changelevel c11m1_greenhouse"); 97 | return Plugin_Continue; 98 | } 99 | 100 | if (StrContains(sg_l4d2Map, "c11m", true) != -1) 101 | { 102 | ServerCommand("changelevel c12m1_hilltop"); 103 | return Plugin_Continue; 104 | } 105 | 106 | if (StrContains(sg_l4d2Map, "c12m", true) != -1) 107 | { 108 | ServerCommand("changelevel c13m1_alpinecreek"); 109 | return Plugin_Continue; 110 | } 111 | 112 | ServerCommand("changelevel c2m1_highway"); 113 | return Plugin_Continue; 114 | } 115 | 116 | public void Event_FinalWin(Event event, const char [] name, bool dontBroadcast) 117 | { 118 | if (ig_coop) 119 | { 120 | PrintToChatAll("\x03[提示]\x01 75 秒后换图..."); 121 | CreateTimer(75.0, HxTimerNextMap, _, TIMER_FLAG_NO_MAPCHANGE); 122 | } 123 | } -------------------------------------------------------------------------------- /scripting/l4d2_riotcopheadshot.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #define PLUGIN_VERSION "1.3" 3 | #define PLUGIN_NAME "L4D2 Riot Cop Head Shot" 4 | #pragma semicolon 1 5 | #include 6 | #include 7 | 8 | new Handle:g_cvarEnable; 9 | new bool:g_bEnabled; 10 | new Handle:g_cvarDebug; 11 | new g_iDebug; 12 | new Handle:g_cvarRiotCopHeadShotEnable; 13 | new g_iRiotCopHeadShot_HeadEnable; 14 | new Handle:g_cvarRiotCopBodyShotDivisor; 15 | new Float:g_fRiotCopHeadShot_BodyDivisor; 16 | new Handle:g_cvarFallenHeadShotMultiplier; 17 | new Float:g_fFallenHeadMultiplier; 18 | new Handle:g_cvarRiotPenetrationDamage; 19 | new Float:g_fPenetrationDamage; 20 | 21 | public Plugin:myinfo = 22 | { 23 | name = PLUGIN_NAME, 24 | author = "dcx2 | helped by Mr. Zero / McFlurry", 25 | description = "Kills riot cops instantly if you shoot them in the head, makes body shots hurt riot cops a little bit, multiplies damage to fallen and Jimmy Gibbs from head shots", 26 | version = PLUGIN_VERSION, 27 | url = "www.AlliedMods.net" 28 | } 29 | 30 | public OnPluginStart() 31 | { 32 | // cache my convars 33 | g_cvarEnable = CreateConVar("sm_riotcopheadshot_enable", "1.0", "Enables this plugin.", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 34 | g_cvarRiotCopHeadShotEnable = CreateConVar("sm_riotcopheadshot_riotheadenable", "1.0", "0: disabled\n1: Head shots instantly kill riot cops\n2: Head shots do 1x damage", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 35 | g_cvarRiotCopBodyShotDivisor = CreateConVar("sm_riotcopheadshot_riotbodydivisor", "40.0", "How much to divide body shot damage by (0 will disable)", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 36 | g_cvarFallenHeadShotMultiplier = CreateConVar("sm_riotcopheadshot_fallenheadmultiplier", "12.0", "How much to multiply fallen head shots by (0 will disable)", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 37 | g_cvarRiotPenetrationDamage = CreateConVar("sm_riotcopheadshot_bodypenetrationdamage", "13.0", "How much damage penetrating weapons should do to the body of riot cops", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 38 | g_cvarDebug = CreateConVar("sm_riotcopheadshot_debug", "0.0", "Print debug output.", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 39 | CreateConVar("sm_riotcopheadshot_ver", PLUGIN_VERSION, PLUGIN_NAME, FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_NOTIFY); 40 | 41 | AutoExecConfig(true, "L4D2RiotCopHeadShot"); 42 | 43 | // be nice and listen for changes 44 | HookConVarChange(g_cvarEnable, OnRCHSEnableChanged); 45 | HookConVarChange(g_cvarRiotCopHeadShotEnable, OnRCHS_RCHeadChanged); 46 | HookConVarChange(g_cvarRiotCopBodyShotDivisor, OnRCHS_RCBodyChanged); 47 | HookConVarChange(g_cvarFallenHeadShotMultiplier, OnRCHS_FHeadChanged); 48 | HookConVarChange(g_cvarRiotPenetrationDamage, OnRCHS_RiotPenDamage); 49 | HookConVarChange(g_cvarDebug, OnRCHSDebugChanged); 50 | 51 | // get cvars after AutoExecConfig 52 | g_bEnabled = GetConVarBool(g_cvarEnable); 53 | g_iRiotCopHeadShot_HeadEnable = GetConVarInt(g_cvarRiotCopHeadShotEnable); 54 | g_fRiotCopHeadShot_BodyDivisor = GetConVarFloat(g_cvarRiotCopBodyShotDivisor); 55 | g_fFallenHeadMultiplier = GetConVarFloat(g_cvarFallenHeadShotMultiplier); 56 | g_fPenetrationDamage = GetConVarFloat(g_cvarRiotPenetrationDamage); 57 | g_iDebug = GetConVarInt(g_cvarDebug); 58 | 59 | if (g_iDebug) 60 | { 61 | HookEvent("infected_hurt", Event_InfectedHurt); 62 | } 63 | } 64 | 65 | public OnRCHSEnableChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) 66 | { 67 | g_bEnabled = StringToInt(newVal) == 1; 68 | } 69 | 70 | public OnRCHSDebugChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) 71 | { 72 | g_iDebug = StringToInt(newVal); 73 | new oldDebug = StringToInt(oldVal); 74 | if (g_iDebug && !oldDebug) 75 | { 76 | HookEvent("infected_hurt", Event_InfectedHurt); 77 | } 78 | else if (oldDebug && !g_iDebug) 79 | { 80 | UnhookEvent("infected_hurt", Event_InfectedHurt); 81 | } 82 | } 83 | 84 | public OnRCHS_RCHeadChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) 85 | { 86 | g_iRiotCopHeadShot_HeadEnable = StringToInt(newVal); 87 | } 88 | 89 | public OnRCHS_RCBodyChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) 90 | { 91 | g_fRiotCopHeadShot_BodyDivisor = StringToFloat(newVal); 92 | } 93 | 94 | public OnRCHS_FHeadChanged(Handle:cvar, const String:oldVal[], const String:newVal[]) 95 | { 96 | g_fFallenHeadMultiplier = StringToFloat(newVal); 97 | } 98 | 99 | public OnRCHS_RiotPenDamage(Handle:cvar, const String:oldVal[], const String:newVal[]) 100 | { 101 | g_fPenetrationDamage = StringToFloat(newVal); 102 | } 103 | 104 | // Listen for when infected are created, then listen to them spawn 105 | public OnEntityCreated(entity, const String:classname[]) 106 | { 107 | if (entity <= 0 || entity > 2048) return; 108 | 109 | if (StrEqual(classname, "infected") || StrEqual(classname, "witch")) 110 | { 111 | SDKHook(entity, SDKHook_SpawnPost, RiotCop_SpawnPost); 112 | } 113 | } 114 | 115 | // Model name does not exist until after the uncommon is spawned 116 | public RiotCop_SpawnPost(entity) 117 | { 118 | if (isRiotCop(entity)) 119 | { 120 | SDKHook(entity, SDKHook_TraceAttack, RiotCop_TraceAttack); 121 | if (g_iDebug) PrintToChatAll("Hooked riot cop for head shot"); 122 | } 123 | else if (isFallenSurvivor(entity)) 124 | { 125 | SDKHook(entity, SDKHook_TraceAttack, Fallen_TraceAttack); 126 | if (g_iDebug) PrintToChatAll("Hooked fallen survivor for head shot"); 127 | } 128 | else if (isJimmyGibbs(entity)) 129 | { 130 | SDKHook(entity, SDKHook_TraceAttack, Fallen_TraceAttack); 131 | if (g_iDebug) PrintToChatAll("Hooked Jimmy Gibbs for head shot"); 132 | } 133 | 134 | if (g_iDebug) 135 | { 136 | // if debugging listen to OTD from all infected 137 | SDKHook(entity, SDKHook_OnTakeDamage, RiotCopOnTakeDamage); 138 | SDKHook(entity, SDKHook_TraceAttack, RiotCop_TraceAttack); 139 | } 140 | } 141 | 142 | // Based on code from Mr. Zero 143 | // TODO: DealDamage instead of SDKHooks_TakeDamage? TakeDamage seems unstable sometimes... 144 | public Action:RiotCop_TraceAttack(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup) 145 | { 146 | if (g_iDebug) PrintToChatAll("RCTA: %d %d %d %f %x %x %d %d", victim, attacker, inflictor, damage, damagetype, ammotype, hitbox, hitgroup); 147 | 148 | if (!g_bEnabled || !IsValidEntity(victim) || !isValidSurvivor(attacker)) return Plugin_Continue; 149 | 150 | new Float:newDamage = 0.0; 151 | 152 | if (g_iRiotCopHeadShot_HeadEnable > 0 && hitgroup == 1) 153 | { 154 | newDamage = damage; // default head shot damage, some guns may require multiple shots 155 | if (g_iRiotCopHeadShot_HeadEnable < 2 && newDamage < 50.0) 156 | { 157 | // newDamage = 50.0; 158 | // It seems that sometimes SDKHooks_TakeDamage causes a crash if it kills a riot cop? Switching to BecomeRagdoll... 159 | AcceptEntityInput(victim, "BecomeRagdoll"); 160 | if (g_iDebug) PrintToChatAll("TA: Riot cop ragdolled (before %f, after %f) (%x %x %x)", damage, newDamage, damagetype, ammotype, hitbox); 161 | return Plugin_Continue; 162 | } 163 | if (g_iDebug) PrintToChatAll("TA: Riot cop head shot (before %f, after %f) (%x %x %x)", damage, newDamage, damagetype, ammotype, hitbox); 164 | } 165 | else if (g_fRiotCopHeadShot_BodyDivisor > 0.9) 166 | { 167 | if (ammotype == 2 || ammotype == 9 || ammotype == 10) 168 | { 169 | // Penetrating weapons should do more damage to the body 170 | newDamage = g_fPenetrationDamage; 171 | } 172 | else 173 | { 174 | newDamage = damage / g_fRiotCopHeadShot_BodyDivisor; 175 | } 176 | if (g_iDebug) PrintToChatAll("TA: Riot cop body shot (before %f, after %f) (%x %x %x)", damage, newDamage, damagetype, ammotype, hitbox); 177 | } 178 | 179 | // Do not return Plugin_Changed, because this would then affect body shots from the back 180 | // Instead just do TakeDamage 181 | 182 | if (newDamage > 0.0) SDKHooks_TakeDamage(victim, 0, attacker, newDamage); 183 | 184 | //PrintToServer("RCTA Post"); 185 | return Plugin_Continue; 186 | } 187 | 188 | public Action:Fallen_TraceAttack(victim, &attacker, &inflictor, &Float:damage, &damagetype, &ammotype, hitbox, hitgroup) 189 | { 190 | // A multiplier of 1.0 will disable this feature 191 | if (g_bEnabled && isValidSurvivor(attacker) && IsValidEntity(victim) && hitgroup == 1 && g_fFallenHeadMultiplier > 1.0) 192 | { 193 | new Float:newDamage = damage * g_fFallenHeadMultiplier; 194 | 195 | // Jimmy Gibbs has even more health, and penetrating bullets kill him in one shot to the body 196 | // So penetrating bullets to the head will also kill him in one shot 197 | if (isJimmyGibbs(victim) && (ammotype == 2 || ammotype == 9 || ammotype == 10) && newDamage < 3000.0) 198 | { 199 | newDamage = 3000.0; 200 | } 201 | 202 | if (g_iDebug) 203 | { 204 | if (isFallenSurvivor(victim)) PrintToChatAll("TA: Fallen head shot (before %f, after %f)", damage, newDamage); 205 | else if (isJimmyGibbs(victim)) PrintToChatAll("TA: Jimmy Gibbs head shot (before %f, after %f)", damage, newDamage); 206 | } 207 | 208 | damage = newDamage; 209 | return Plugin_Changed; 210 | } 211 | 212 | return Plugin_Continue; 213 | } 214 | 215 | // If debugging, listen to IH (it will hear witches, while OTD will not) 216 | public Action:Event_InfectedHurt(Handle:event, const String:name[], bool:dontBroadcast) 217 | { 218 | if (g_iDebug) 219 | { 220 | new entityid = GetEventInt(event, "entityid"); 221 | if (isRiotCop(entityid)) PrintToChatAll("IH: Hit riot cop in the %d for %d damage (%d remaining)", GetEventInt(event, "hitgroup"), GetEventInt(event, "amount"), GetEntProp(entityid, Prop_Data, "m_iHealth")); 222 | else if (isFallenSurvivor(entityid)) PrintToChatAll("IH: Hit fallen survivor in the %d for %d damage (%d remaining)", GetEventInt(event, "hitgroup"), GetEventInt(event, "amount"), GetEntProp(entityid, Prop_Data, "m_iHealth")); 223 | else if (isJimmyGibbs(entityid)) PrintToChatAll("IH: Hit Jimmy Gibbs in the %d for %d damage (%d remaining)", GetEventInt(event, "hitgroup"), GetEventInt(event, "amount"), GetEntProp(entityid, Prop_Data, "m_iHealth")); 224 | else PrintToChatAll("IH: Hit infected in the %d for %d damage (%d remaining)", GetEventInt(event, "hitgroup"), GetEventInt(event, "amount"), GetEntProp(entityid, Prop_Data, "m_iHealth")); 225 | } 226 | } 227 | 228 | // OTD has access to different debugging data 229 | public Action:RiotCopOnTakeDamage(victim, &attacker, &inflictor, &Float:damage, &damagetype, &weapon, Float:damageForce[3], Float:damagePosition[3]) 230 | { 231 | if (g_iDebug) 232 | { 233 | decl String:victimName[MAX_TARGET_LENGTH] = "Unconnected"; 234 | decl String:attackerName[MAX_TARGET_LENGTH] = "Unconnected"; 235 | decl String:inflictorName[32] = "Invalid"; 236 | decl String:weaponName[32] = "Invalid"; 237 | 238 | if (victim > 0 && victim <= MaxClients) 239 | { 240 | if (IsClientConnected(victim)) 241 | { 242 | GetClientName(victim, victimName, sizeof(victimName)); 243 | } 244 | } 245 | else if (IsValidEntity(victim)) 246 | { 247 | GetEntityClassname(victim, victimName, sizeof(victimName)); 248 | } 249 | 250 | if (attacker > 0 && attacker <= MaxClients) 251 | { 252 | if (IsClientConnected(attacker)) 253 | { 254 | GetClientName(attacker, attackerName, sizeof(attackerName)); 255 | } 256 | } 257 | else if (IsValidEntity(attacker)) 258 | { 259 | GetEntityClassname(attacker, attackerName, sizeof(attackerName)); 260 | } 261 | 262 | if (inflictor > 0 && IsValidEntity(inflictor)) 263 | { 264 | GetEntityClassname(inflictor, inflictorName, sizeof(inflictorName)); 265 | } 266 | 267 | if (weapon > 0 && IsValidEntity(weapon)) 268 | { 269 | GetEntityClassname(weapon, weaponName, sizeof(weaponName)); 270 | } 271 | 272 | PrintToChatAll("OTD: %s hit %s with %s / %s / %x for %f", attackerName, victimName, weaponName, inflictorName, damagetype, damage); 273 | 274 | } 275 | return Plugin_Continue; 276 | } 277 | 278 | stock bool:isValidSurvivor(client) 279 | { 280 | return !(client <= 0 || client > MaxClients || !IsClientConnected(client) || !IsClientInGame(client) || GetClientTeam(client) != 2 || !IsPlayerAlive(client)); 281 | } 282 | 283 | stock bool:isRiotCop(entity) 284 | { 285 | if (entity <= 0 || entity > 2048 || !IsValidEntity(entity)) return false; 286 | decl String:model[128]; 287 | GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model)); 288 | return StrContains(model, "riot") != -1; // Common is a riot uncommon 289 | } 290 | 291 | stock bool:isFallenSurvivor(entity) 292 | { 293 | if (entity <= 0 || entity > 2048 || !IsValidEntity(entity)) return false; 294 | decl String:model[128]; 295 | GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model)); 296 | return StrContains(model, "fallen") != -1; // Common is a fallen uncommon 297 | } 298 | 299 | stock bool:isJimmyGibbs(entity) 300 | { 301 | if (entity <= 0 || entity > 2048 || !IsValidEntity(entity)) return false; 302 | decl String:model[128]; 303 | GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model)); 304 | return StrContains(model, "jimmy") != -1; // Common is a Jimmy Gibbs 305 | } 306 | -------------------------------------------------------------------------------- /scripting/l4d2_upgradepackfix.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN_VERSION "1.6" 5 | 6 | public Plugin:myinfo = 7 | { 8 | name = "[L4D2] Upgrade Packs FIXES", 9 | author = "V10", 10 | description = "Fixes bugs with upgrade packs on server more than 8 players", 11 | version = PLUGIN_VERSION, 12 | url = "http://forums.alliedmods.net/showthread.php?p=1619490" 13 | } 14 | 15 | #define MAX_UPGRADEPACKS 10 16 | #define L4D_MAXPLAYERS 32 17 | #define TEAM_SURVIVOR 2 18 | #define HARDCHECKS 1 19 | #define DEBUG 0 20 | 21 | new g_SurvivorUseMaskO=-1; 22 | new g_UpgradePackCanUseCountO = -1; 23 | 24 | new Handle:g_hFindUseEntity = INVALID_HANDLE; 25 | static Handle:IncendAmmoMultiplier = INVALID_HANDLE; 26 | static Handle:SplosiveAmmoMultiplier = INVALID_HANDLE; 27 | 28 | new Handle:g_UpgradePackResetTimers[MAX_UPGRADEPACKS]; 29 | new g_UpgradePackEntityId[MAX_UPGRADEPACKS]; 30 | new g_TotalUpgradesCount[MAX_UPGRADEPACKS]; 31 | new bool:g_UsedUpgradePack[MAX_UPGRADEPACKS][L4D_MAXPLAYERS+1]; 32 | new g_CurrentMaxPackId; 33 | new g_LastUsedUpgradePackId; 34 | 35 | #if HARDCHECKS == 0 36 | new bool:g_DelayButton[L4D_MAXPLAYERS+1]; 37 | #endif 38 | 39 | public OnPluginStart() 40 | { 41 | HookEvent("upgrade_pack_added",Event_UpgradePackAdded,EventHookMode_Pre); 42 | HookEvent("round_start",Event_RoundStart); 43 | 44 | CreateConVar("l4d2_upgradepackfix_version", PLUGIN_VERSION, "UpgradePackFix plugin version", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD); 45 | 46 | IncendAmmoMultiplier = CreateConVar("l4d2_upgradepackfix_incendammomulti", "2.0", " Multiplier for Incendiary Ammo Pickup Amount "); 47 | SplosiveAmmoMultiplier = CreateConVar("l4d2_upgradepackfix_explosiveammomulti", "1.0", " Multiplier for Explosive Ammo Pickup Amount "); 48 | 49 | g_SurvivorUseMaskO = FindSendPropInfo("CBaseUpgradeItem","m_iUsedBySurvivorsMask"); 50 | 51 | new Handle:gConf = LoadGameConfigFile("upgradepackfix"); 52 | 53 | g_UpgradePackCanUseCountO = GameConfGetOffset(gConf,"m_iUpgradePackCanUseCount"); 54 | 55 | StartPrepSDKCall(SDKCall_Player); 56 | PrepSDKCall_SetFromConf(gConf, SDKConf_Signature, "CTerrorPlayer::FindUseEntity"); 57 | PrepSDKCall_AddParameter(SDKType_Float,SDKPass_Plain); 58 | PrepSDKCall_AddParameter(SDKType_Float,SDKPass_Plain); 59 | PrepSDKCall_AddParameter(SDKType_Float,SDKPass_Plain); 60 | PrepSDKCall_AddParameter(SDKType_PlainOldData,SDKPass_Plain); 61 | PrepSDKCall_AddParameter(SDKType_Bool,SDKPass_Plain); 62 | PrepSDKCall_SetReturnInfo(SDKType_CBaseEntity,SDKPass_Pointer); 63 | g_hFindUseEntity = EndPrepSDKCall(); 64 | 65 | CloseHandle(gConf); 66 | if (g_hFindUseEntity == INVALID_HANDLE){ 67 | SetFailState("Can't get CTerrorPlayer::FindUseEntity SDKCall!"); 68 | return; 69 | } 70 | 71 | if (g_UpgradePackCanUseCountO == -1 || g_SurvivorUseMaskO == -1) 72 | SetFailState("Cannot get offsets"); 73 | 74 | } 75 | 76 | public Action:OnPlayerRunCmd(client, &buttons, &impulse, Float:vel[3], Float:angles[3], &weapon) 77 | { 78 | if (client == 0 || client > MaxClients) return Plugin_Continue; 79 | #if HARDCHECKS == 1 80 | if (buttons & IN_USE){ 81 | #else 82 | if (buttons & IN_USE && !g_DelayButton[client]){ 83 | g_DelayButton[client]=true; 84 | CreateTimer(0.2, ResetDelay, client); 85 | #endif 86 | 87 | new UseEntity = FindUseEntity(client); //GetClientAimTarget(client, false); 88 | if (!IsValidEntity(UseEntity)) 89 | return Plugin_Continue; 90 | 91 | decl String:ClassName[30]; 92 | GetEntityNetClass(UseEntity,ClassName,sizeof(ClassName)); 93 | 94 | #if DEBUG 95 | LogMessage("OnPlayerRunCmd_USE client=%d, UseEntity=%d, entclass=%s",client,UseEntity,ClassName); 96 | #endif 97 | 98 | if (!strcmp(ClassName,"CBaseUpgradeItem")){ 99 | g_LastUsedUpgradePackId = GetUpgradePackId(UseEntity); 100 | UpgradePackCheckUsable(client,g_LastUsedUpgradePackId); 101 | }else { 102 | #if HARDCHECKS == 1 103 | decl Float:PackCoords[3]; 104 | decl Float:UsedCoords[3]; 105 | GetClientAbsOrigin(client, UsedCoords); 106 | if (g_LastUsedUpgradePackId>-1){ 107 | if (IsValidEntity(g_UpgradePackEntityId[g_LastUsedUpgradePackId])){ 108 | GetEntityNetClass(g_UpgradePackEntityId[g_LastUsedUpgradePackId],ClassName,sizeof(ClassName)); 109 | if (!strcmp(ClassName,"CBaseUpgradeItem")){ 110 | GetEntPropVector(g_UpgradePackEntityId[g_LastUsedUpgradePackId], Prop_Send, "m_vecOrigin", PackCoords); 111 | new Float:dist=GetVectorDistance(PackCoords,UsedCoords); 112 | 113 | #if DEBUG 114 | LogMessage("Dist to last %f",dist); 115 | #endif 116 | 117 | if (dist < 196.0){ 118 | UpgradePackCheckUsable(client,g_LastUsedUpgradePackId); 119 | } 120 | }else{ 121 | g_LastUsedUpgradePackId=-1; 122 | } 123 | }else { 124 | g_LastUsedUpgradePackId=-1; 125 | } 126 | } 127 | #endif 128 | } 129 | 130 | } 131 | return Plugin_Continue; 132 | } 133 | public Event_UpgradePackAdded(Handle:event, const String:name[], bool:dontBroadcast) 134 | { 135 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 136 | new UseEntity = FindUseEntity(client); 137 | 138 | new upgradeid = GetEventInt(event, "upgradeid"); 139 | decl String:class[256]; 140 | GetEdictClassname(upgradeid, class, sizeof(class)); 141 | //PrintToChatAll("Upgrade caught, entity = %i, entclass: %s", upgradeid, class); 142 | 143 | if (StrEqual(class, "upgrade_laser_sight")) 144 | return; 145 | 146 | #if DEBUG 147 | LogMessage("UpgradePackAdded client=%d, UseEntity=%d",client,UseEntity); 148 | #endif 149 | 150 | if (!IsValidEntity(UseEntity)) 151 | return; 152 | 153 | new UpgradePackId = GetUpgradePackId(UseEntity); 154 | 155 | #if DEBUG 156 | LogMessage("upgrade pack used cl=%N. [%d,%d])",client,UpgradePackId,g_TotalUpgradesCount[UpgradePackId]); 157 | #endif 158 | 159 | g_UsedUpgradePack[UpgradePackId][client] = true; 160 | g_TotalUpgradesCount[UpgradePackId]--; 161 | 162 | SetEntData(UseEntity, g_UpgradePackCanUseCountO, g_TotalUpgradesCount[UpgradePackId], 1,true); 163 | if (g_UpgradePackResetTimers[UpgradePackId] == INVALID_HANDLE) 164 | g_UpgradePackResetTimers[UpgradePackId] = CreateTimer(0.2,Timer_UpgradePackReset,UpgradePackId); 165 | 166 | new ammo = GetSpecialAmmoInPlayerGun(client); 167 | new newammo; 168 | 169 | if (StrEqual(class, "upgrade_ammo_incendiary")) 170 | newammo = RoundFloat(ammo * GetConVarFloat(IncendAmmoMultiplier)); 171 | else if (StrEqual(class, "upgrade_ammo_explosive")) 172 | newammo = RoundFloat(ammo * GetConVarFloat(SplosiveAmmoMultiplier)); 173 | 174 | if (newammo > 1) 175 | SetSpecialAmmoInPlayerGun(client, newammo); 176 | 177 | // UpgradePackReset(UpgradePackId); 178 | } 179 | 180 | public Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast) 181 | { 182 | ClearUpgradePacks(); 183 | } 184 | 185 | #if HARDCHECKS == 0 186 | public Action:ResetDelay(Handle:timer, any:client) 187 | { 188 | g_DelayButton[client] = false; 189 | return Plugin_Stop; 190 | } 191 | #endif 192 | 193 | public Action:Timer_UpgradePackReset(Handle:timer, any:PackId) 194 | { 195 | if (!IsValidEntity(g_UpgradePackEntityId[PackId])) 196 | return Plugin_Stop; 197 | UpgradePackReset(PackId); 198 | g_UpgradePackResetTimers[PackId]=INVALID_HANDLE; 199 | return Plugin_Stop; 200 | } 201 | 202 | GetUpgradePackId(entityId) 203 | { 204 | for (new i; i < MAX_UPGRADEPACKS ; i++) 205 | if (g_UpgradePackEntityId[i] == entityId) 206 | return i; 207 | 208 | return CreateUpgradePack(entityId); 209 | } 210 | 211 | UpgradePackCheckUsable(client,PackId) 212 | { 213 | SetEntData(g_UpgradePackEntityId[PackId], g_SurvivorUseMaskO, (g_UsedUpgradePack[PackId][client] ? 255 : 0), 1, true); 214 | 215 | if (g_UsedUpgradePack[PackId][client] && g_UpgradePackResetTimers[PackId] == INVALID_HANDLE) 216 | g_UpgradePackResetTimers[PackId] = CreateTimer(0.2,Timer_UpgradePackReset,PackId); 217 | } 218 | 219 | CreateUpgradePack(entityId) 220 | { 221 | g_TotalUpgradesCount[g_CurrentMaxPackId] = GetTeamClientCount(TEAM_SURVIVOR); 222 | g_UpgradePackEntityId[g_CurrentMaxPackId] = entityId; 223 | 224 | #if DEBUG 225 | LogMessage("created upgrade pack id=%d, ent=%d, upgreades=%d)",g_CurrentMaxPackId,entityId,g_TotalUpgradesCount[g_CurrentMaxPackId]); 226 | #endif 227 | 228 | for (new i = 1; i <= MaxClients; i++) 229 | g_UsedUpgradePack[g_CurrentMaxPackId][i] = false; 230 | 231 | new result = g_CurrentMaxPackId; 232 | g_CurrentMaxPackId++; 233 | if (g_CurrentMaxPackId == MAX_UPGRADEPACKS) 234 | g_CurrentMaxPackId = 0; 235 | return result; 236 | } 237 | 238 | ClearUpgradePacks() 239 | { 240 | g_CurrentMaxPackId=0; 241 | g_LastUsedUpgradePackId = -1; 242 | for (new i; i < MAX_UPGRADEPACKS ; i++){ 243 | g_UpgradePackEntityId[i] = -1; 244 | g_TotalUpgradesCount[i] = 0; 245 | for (new j = 1; j <= MaxClients; j++) 246 | g_UsedUpgradePack[i][j] = false; 247 | } 248 | } 249 | 250 | UpgradePackReset(PackId) 251 | { 252 | SetEntData(g_UpgradePackEntityId[PackId], g_SurvivorUseMaskO, 0, 1,true); 253 | } 254 | 255 | FindUseEntity(client){ return SDKCall(g_hFindUseEntity,client,96.0,0.0,0.0,0,false);} 256 | 257 | 258 | 259 | stock GetSpecialAmmoInPlayerGun(client) //returns the amount of special rounds in your gun 260 | { 261 | if (!client) client = 1; 262 | new gunent = GetPlayerWeaponSlot(client, 0); 263 | if (IsValidEdict(gunent)) 264 | return GetEntProp(gunent, Prop_Send, "m_nUpgradedPrimaryAmmoLoaded", 1); 265 | else return 0; 266 | } 267 | 268 | stock SetSpecialAmmoInPlayerGun(client, amount) 269 | { 270 | if (!client) client = 1; 271 | new gunent = GetPlayerWeaponSlot(client, 0); 272 | if (IsValidEdict(gunent)) 273 | SetEntProp(gunent, Prop_Send, "m_nUpgradedPrimaryAmmoLoaded", amount, 1); 274 | } 275 | 276 | -------------------------------------------------------------------------------- /scripting/l4d_infectedhp.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #include 3 | 4 | #define PLUGIN_VERSION "1.0.2" 5 | #define INFECTED_NAMES 6 6 | #define WITCH_LEN 32 7 | #define CVAR_FLAGS FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY 8 | 9 | public Plugin:myinfo = 10 | { 11 | name = "L4D Infected HP", 12 | author = "NiCo-op", 13 | description = "L4D Infected HP", 14 | version = PLUGIN_VERSION, 15 | url = "http://nico-op.forjp.net/" 16 | }; 17 | 18 | new Handle:hPluginEnable = INVALID_HANDLE; 19 | new Handle:hBarLEN = INVALID_HANDLE; 20 | new witchCUR = 0; 21 | new witchMAX[WITCH_LEN]; 22 | new witchHP[WITCH_LEN]; 23 | new witchID[WITCH_LEN]; 24 | new prevMAX[MAXPLAYERS+1]; 25 | new prevHP[MAXPLAYERS+1]; 26 | new nCharLength; 27 | new String:sCharHealth[8] = "#"; 28 | new String:sCharDamage[8] = "="; 29 | new Handle:hCharHealth; 30 | new Handle:hCharDamage; 31 | new Handle:hShowType; 32 | new Handle:hShowNum; 33 | new Handle:hTank; 34 | new Handle:hWitch; 35 | new Handle:hWitchHealth; 36 | new Handle:hInfected[INFECTED_NAMES]; 37 | new nShowType; 38 | new nShowNum; 39 | new nShowTank; 40 | new nShowWitch; 41 | new nShowFlag[INFECTED_NAMES]; 42 | new String:sClassName[][] = { 43 | "boome", 44 | "hunter", 45 | "smoker", 46 | "jockey", 47 | "spitter", 48 | "charger" 49 | }; 50 | 51 | public OnPluginStart(){ 52 | hWitchHealth = FindConVar("z_witch_health"); 53 | 54 | CreateConVar("l4d_infectedhp_version", 55 | PLUGIN_VERSION, 56 | "L4D Infected HP version", 57 | FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_REPLICATED|FCVAR_DONTRECORD 58 | ); 59 | 60 | hPluginEnable = CreateConVar( 61 | "l4d_infectedhp", 62 | "1", 63 | "plugin on/off (on:1 / off:0)", 64 | CVAR_FLAGS, 65 | true, 66 | 0.0, 67 | true, 68 | 1.0 69 | ); 70 | 71 | hBarLEN = CreateConVar( 72 | "l4d_infectedhp_bar", 73 | "100", 74 | "length of health bar (def:100 / min:10 / max:200)", 75 | CVAR_FLAGS, 76 | true, 77 | 10.0, 78 | true, 79 | 200.0 80 | ); 81 | 82 | hCharHealth = CreateConVar( 83 | "l4d_infectedhp_health", 84 | "#", 85 | "show health character", 86 | CVAR_FLAGS 87 | ); 88 | 89 | hCharDamage = CreateConVar( 90 | "l4d_infectedhp_damage", 91 | "=", 92 | "show damage character", 93 | CVAR_FLAGS 94 | ); 95 | 96 | hShowType = CreateConVar( 97 | "l4d_infectedhp_type", 98 | "0", 99 | "health bar type (def:0 / center text:0 / hint text:1)", 100 | CVAR_FLAGS, 101 | true, 102 | 0.0, 103 | true, 104 | 1.0 105 | ); 106 | 107 | hShowNum = CreateConVar( 108 | "l4d_infectedhp_num", 109 | "0", 110 | "health value display (def:0 / hidden:0 / visible:1)", 111 | CVAR_FLAGS, 112 | true, 113 | 0.0, 114 | true, 115 | 1.0 116 | ); 117 | 118 | hTank = CreateConVar( 119 | "l4d_infectedhp_tank", 120 | "1", 121 | "show health bar (def:1 / on:1 / off:0)", 122 | CVAR_FLAGS, 123 | true, 124 | 0.0, 125 | true, 126 | 1.0 127 | ); 128 | 129 | hWitch = CreateConVar( 130 | "l4d_infectedhp_witch", 131 | "1", 132 | "show health bar (def:1 / on:1 / off:0)", 133 | CVAR_FLAGS, 134 | true, 135 | 0.0, 136 | true, 137 | 1.0 138 | ); 139 | 140 | hInfected[0] = CreateConVar( 141 | "l4d_infectedhp_boomer", 142 | "1", 143 | "show health bar (def:1 / on:1 / off:0)", 144 | CVAR_FLAGS, 145 | true, 146 | 0.0, 147 | true, 148 | 1.0 149 | ); 150 | 151 | decl String:buffers[64]; 152 | for(new i=1; i 0 271 | && IsClientConnected(client) 272 | && IsClientInGame(client) 273 | && GetClientTeam(client) == 3 274 | ){ 275 | TimerSpawn(INVALID_HANDLE, client); 276 | CreateTimer(0.5, TimerSpawn, client, TIMER_FLAG_NO_MAPCHANGE); 277 | } 278 | 279 | return Plugin_Continue; 280 | } 281 | 282 | public Action:OnInfectedDeath(Handle:event, const String:name[], bool:dontBroadcast) 283 | { 284 | if(!GetConVarBool(hPluginEnable)) return Plugin_Continue; 285 | 286 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 287 | if( client > 0 288 | && IsClientConnected(client) 289 | && IsClientInGame(client) 290 | && GetClientTeam(client) == 3 291 | ){ 292 | decl String:clName[MAX_NAME_LENGTH]; 293 | GetClientName(client, clName, sizeof(clName)); 294 | prevMAX[client] = -1; 295 | prevHP[client] = -1; 296 | if(nShowTank && StrContains(clName, "Tank", false) != -1){ 297 | new max = GetMaxClients(); 298 | for(new i=1; i<=max; i++){ 299 | if(IsClientConnected(i) 300 | && IsClientInGame(i) 301 | && !IsFakeClient(i) 302 | && GetClientTeam(i) == 2){ 303 | PrintHintText(i, "++ %s 已经死亡 ++", clName); 304 | } 305 | } 306 | } 307 | } 308 | return Plugin_Continue; 309 | } 310 | 311 | public Action:OnPlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) 312 | { 313 | if(!GetConVarBool(hPluginEnable)) return Plugin_Continue; 314 | 315 | new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); 316 | if(!attacker 317 | || !IsClientConnected(attacker) 318 | || !IsClientInGame(attacker) 319 | || GetClientTeam(attacker) != 2){ 320 | return Plugin_Continue; 321 | } 322 | new client = GetClientOfUserId(GetEventInt(event, "userid")); 323 | if(!client 324 | || !IsClientConnected(client) 325 | || !IsClientInGame(client) 326 | || !IsPlayerAlive(client) 327 | || GetClientTeam(client) != 3){ 328 | return Plugin_Continue; 329 | } 330 | 331 | decl String:class[128]; 332 | GetClientModel(client, class, sizeof(class)); 333 | new match = 0; 334 | for(new i=0; i prevHP[client]){ 354 | nowHP = prevHP[client]; 355 | } 356 | else{ 357 | prevHP[client] = nowHP; 358 | } 359 | if(maxHP < prevMAX[client]){ 360 | maxHP = prevMAX[client]; 361 | } 362 | if(maxHP < nowHP){ 363 | maxHP = nowHP; 364 | prevMAX[client] = nowHP; 365 | } 366 | if(maxHP < 1){ 367 | maxHP = 1; 368 | } 369 | decl String:clName[MAX_NAME_LENGTH]; 370 | GetClientName(client, clName, sizeof(clName)); 371 | ShowHealthGauge(attacker, maxBAR, maxHP, nowHP, clName); 372 | 373 | return Plugin_Continue; 374 | } 375 | 376 | public Action:OnWitchSpawn(Handle:event, const String:name[], bool:dontBroadcast) 377 | { 378 | GetConfig(); 379 | 380 | new entity = GetEventInt(event, "witchid"); 381 | witchID[witchCUR] = entity; 382 | 383 | new health = (hWitchHealth == INVALID_HANDLE) ? 0 : GetConVarInt(hWitchHealth); 384 | witchMAX[witchCUR] = health; 385 | witchHP[witchCUR] = health; 386 | witchCUR = (witchCUR + 1) % WITCH_LEN; 387 | 388 | return Plugin_Continue; 389 | } 390 | 391 | public Action:OnWitchKilled(Handle:event, const String:name[], bool:dontBroadcast) 392 | { 393 | new entity = GetEventInt(event, "witchid"); 394 | for(new i=0; i witchHP[i]){ 429 | nowHP = witchHP[i]; 430 | } 431 | else{ 432 | witchHP[i] = nowHP; 433 | } 434 | if(maxHP < 1){ 435 | maxHP = 1; 436 | } 437 | decl String:clName[64]; 438 | if(i == 0){ 439 | strcopy(clName, sizeof(clName), "Witch"); 440 | } 441 | else{ 442 | Format(clName, sizeof(clName), "(%d)Witch", i); 443 | } 444 | ShowHealthGauge(attacker, maxBAR, maxHP, nowHP, clName); 445 | return Plugin_Continue; 446 | } 447 | } 448 | 449 | return Plugin_Continue; 450 | } 451 | -------------------------------------------------------------------------------- /scripting/l4d_kill.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN_VERSION "1.0" 5 | 6 | public Plugin:myinfo = 7 | { 8 | name = "[L4D] Kill", 9 | author = "Danny & FlamFlam", 10 | description = "use the !kill command in chat", 11 | version = PLUGIN_VERSION, 12 | url = "" 13 | } 14 | 15 | public OnPluginStart() 16 | { 17 | RegConsoleCmd("sm_explode", Kill_Me); 18 | RegConsoleCmd("sm_kill", Kill_Me); 19 | } 20 | 21 | 22 | // kill 23 | public Action:Kill_Me(client, args) 24 | { 25 | ForcePlayerSuicide(client); 26 | } 27 | 28 | //Timed Message 29 | public bool:OnClientConnect(client, String:rejectmsg[], maxlen) 30 | 31 | { 32 | CreateTimer(60.0, Timer_Advertise, client); 33 | return true; 34 | } 35 | 36 | public Action:Timer_Advertise(Handle:timer, any:client) 37 | 38 | { 39 | if(IsClientInGame(client)) 40 | PrintToChat(client, "\x03[提示] \x01输入 \x04!kill \x01自杀"); 41 | else if (IsClientConnected(client)) 42 | CreateTimer(60.0, Timer_Advertise, client); 43 | } -------------------------------------------------------------------------------- /scripting/l4d_nightvision.sp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | new IMPULS_FLASHLIGHT = 100; 4 | new Float:PressTime[MAXPLAYERS+1]; 5 | 6 | new Mode; 7 | new bool:EnableSuvivor; 8 | new bool:EnableInfected; 9 | new Handle:l4d_nt_team; 10 | 11 | public Plugin:myinfo = 12 | { 13 | name = "Night Vision for L4D2", 14 | author = "HMBSbige", 15 | description = "L4D2 Night Vision", 16 | version = "1.0", 17 | url = "https://github.com/HMBSbige" 18 | } 19 | 20 | public OnPluginStart() 21 | { 22 | RegConsoleCmd("sm_nightvision", sm_nightvision); 23 | l4d_nt_team = CreateConVar("l4d_nt_team", "1", "0:disable, 1:enable for survivor and infected, 2:enable for survivor, 3:enable for infected", FCVAR_SS_ADDED); 24 | AutoExecConfig(true, "l4d_nightvision"); 25 | HookConVarChange(l4d_nt_team, ConVarChange); 26 | GetConVar(); 27 | 28 | } 29 | public ConVarChange(Handle:convar, const String:oldValue[], const String:newValue[]) 30 | { 31 | GetConVar(); 32 | } 33 | GetConVar() 34 | { 35 | Mode=GetConVarInt(l4d_nt_team); 36 | EnableSuvivor=(Mode==1 || Mode==2); 37 | EnableInfected=(Mode==1 || Mode==3); 38 | } 39 | public Action:sm_nightvision(client,args) 40 | { 41 | if(IsClientInGame(client)) 42 | SwitchNightVision(client); 43 | return Plugin_Handled; 44 | } 45 | //code from "Block Flashlight", 46 | public Action:OnPlayerRunCmd(client, &buttons, &impuls, Float:vel[3], Float:angles[3], &weapon) 47 | { 48 | if(Mode==0)return; 49 | if(impuls==IMPULS_FLASHLIGHT) 50 | { 51 | new team=GetClientTeam(client); 52 | if(team==2 && EnableSuvivor ) 53 | { 54 | new Float:time=GetEngineTime(); 55 | if(time-PressTime[client]<0.3) 56 | { 57 | SwitchNightVision(client); 58 | } 59 | PressTime[client]=time; 60 | 61 | } 62 | if(team==3 && EnableInfected) 63 | { 64 | new Float:time=GetEngineTime(); 65 | if(time-PressTime[client]>0.1) 66 | { 67 | SwitchNightVision(client); 68 | } 69 | PressTime[client]=time; 70 | } 71 | } 72 | } 73 | SwitchNightVision(client) 74 | { 75 | new d=GetEntProp(client, Prop_Send, "m_bNightVisionOn"); 76 | if(d==0) 77 | { 78 | SetEntProp(client, Prop_Send, "m_bNightVisionOn",1); 79 | PrintHintText(client, "夜视开启"); 80 | } 81 | else 82 | { 83 | SetEntProp(client, Prop_Send, "m_bNightVisionOn",0); 84 | PrintHintText(client, "夜视关闭"); 85 | } 86 | 87 | } -------------------------------------------------------------------------------- /scripting/l4d_randomize_tank_witch_settings.sp: -------------------------------------------------------------------------------- 1 | /* Plugin Template generated by Pawn Studio */ 2 | 3 | #include 4 | #include 5 | 6 | #define PLUGIN_VERSION "1.2" 7 | #define INFECTEDTEAM 3 8 | 9 | public Plugin:myinfo = 10 | { 11 | name = "L4D1-2 Randomize Tank and Witch Settings", 12 | author = "Thraka - Idea From gamemann", 13 | description = "Configures the tank and witch with random speed and health settings.", 14 | version = PLUGIN_VERSION, 15 | url = "http://forums.alliedmods.net/showthread.php?p=1076665" 16 | } 17 | 18 | new Handle:cvar_witch_health = INVALID_HANDLE; 19 | new Handle:cvar_witch_speed = INVALID_HANDLE; 20 | new Handle:cvar_tank_health = INVALID_HANDLE; 21 | new Handle:cvar_tank_speed = INVALID_HANDLE; 22 | 23 | new Handle:cvar_setting_tank_hp_min = INVALID_HANDLE; 24 | new Handle:cvar_setting_tank_hp_max = INVALID_HANDLE; 25 | new Handle:cvar_setting_witch_hp_min = INVALID_HANDLE; 26 | new Handle:cvar_setting_witch_hp_max = INVALID_HANDLE; 27 | 28 | new Handle:cvar_setting_tank_speed_min = INVALID_HANDLE; 29 | new Handle:cvar_setting_tank_speed_max = INVALID_HANDLE; 30 | new Handle:cvar_setting_witch_speed_min = INVALID_HANDLE; 31 | new Handle:cvar_setting_witch_speed_max = INVALID_HANDLE; 32 | 33 | new Handle:cvar_notify = INVALID_HANDLE; 34 | 35 | new _tankOriginalHp = 0; 36 | new _tankOriginalSpeed = 0; 37 | new _witchOriginalHp = 0; 38 | new _witchOriginalSpeed = 0; 39 | new _tankBotCount = 0; 40 | 41 | public OnPluginStart() 42 | { 43 | // Require Left 4 Dead 1 or 2 44 | decl String:game_name[64]; 45 | GetGameFolderName(game_name, sizeof(game_name)); 46 | if (!StrEqual(game_name, "left4dead2", false) && !StrEqual(game_name, "left4dead", false)) 47 | { 48 | SetFailState("Plugin supports Left 4 Dead 1 or 2 only."); 49 | } 50 | 51 | CreateConVar("l4d_randomize_tankwitch_ver", PLUGIN_VERSION, "Version of the randomize tank and witch settings plugin.", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY); 52 | 53 | // ============================================================ 54 | // == Get the cvars for the tank and witch 55 | cvar_tank_health = FindConVar("z_tank_health"); 56 | cvar_tank_speed = FindConVar("z_tank_speed_vs"); 57 | cvar_witch_health = FindConVar("z_witch_health"); 58 | cvar_witch_speed = FindConVar("z_witch_speed"); 59 | 60 | _tankOriginalHp = GetConVarInt(cvar_tank_health); 61 | _tankOriginalSpeed = GetConVarInt(cvar_tank_speed); 62 | _witchOriginalHp = GetConVarInt(cvar_witch_health); 63 | _witchOriginalSpeed = GetConVarInt(cvar_witch_speed); 64 | 65 | 66 | // ============================================================ 67 | // == Create cvars for the plugin 68 | cvar_setting_tank_hp_min = CreateConVar("l4d_tank_hp_min", SafeIntToString(_tankOriginalHp), "Tank's minimum health when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 69 | cvar_setting_tank_hp_max = CreateConVar("l4d_tank_hp_max", SafeIntToString(_tankOriginalHp), "Tank's maximum health when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 70 | cvar_setting_tank_speed_min = CreateConVar("l4d_tank_speed_min", SafeIntToString(_tankOriginalSpeed), "Tank's minimum speed when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 71 | cvar_setting_tank_speed_max = CreateConVar("l4d_tank_speed_max", SafeIntToString(_tankOriginalSpeed), "Tank's maximum speed when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 72 | 73 | cvar_setting_witch_hp_min = CreateConVar("l4d_witch_hp_min", SafeIntToString(_witchOriginalHp), "Witch's minimum health when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 74 | cvar_setting_witch_hp_max = CreateConVar("l4d_witch_hp_max", SafeIntToString(_witchOriginalHp), "Witch's maximum health when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 75 | cvar_setting_witch_speed_min = CreateConVar("l4d_witch_speed_min", SafeIntToString(_witchOriginalSpeed), "Witch's minimum speed when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 76 | cvar_setting_witch_speed_max = CreateConVar("l4d_witch_speed_max", SafeIntToString(_witchOriginalSpeed), "Witch's maximum speed when randomizing", FCVAR_PLUGIN|FCVAR_NOTIFY); 77 | 78 | cvar_notify = CreateConVar("l4d_randomize_tankwitch_notify", "1", "Notify the infected players of the tank and witch settings.", FCVAR_PLUGIN|FCVAR_NOTIFY); 79 | 80 | AutoExecConfig(true, "l4d_randomize_tw") 81 | 82 | // ============================================================ 83 | // == Hook events 84 | HookEvent("round_start", Event_RoundStart); 85 | HookEvent("tank_spawn", Event_TankSpawn); 86 | HookEvent("witch_spawn", Event_WitchSpawn); 87 | HookEvent("tank_killed", Event_TankKilled); 88 | 89 | // ============================================================ 90 | // == Console Commands 91 | RegConsoleCmd("l4d_randomize_tankwitch_print", Command_PrintSettings); 92 | } 93 | 94 | public OnPluginEnd() 95 | { 96 | SetConVarInt(cvar_tank_health, _tankOriginalHp); 97 | SetConVarInt(cvar_tank_speed, _tankOriginalSpeed); 98 | SetConVarInt(cvar_witch_health, _witchOriginalHp); 99 | SetConVarInt(cvar_witch_speed, _witchOriginalSpeed); 100 | } 101 | 102 | public Action:Command_PrintSettings(client, args) 103 | { 104 | PrintToConsole(client, "Tank HP Min: %i", GetConVarInt(cvar_setting_tank_hp_min)); 105 | PrintToConsole(client, "Tank HP Max: %i", GetConVarInt(cvar_setting_tank_hp_max)); 106 | PrintToConsole(client, "Tank Speed Min: %i", GetConVarInt(cvar_setting_tank_speed_min)); 107 | PrintToConsole(client, "Tank Speed Max: %i", GetConVarInt(cvar_setting_tank_speed_max)); 108 | 109 | PrintToConsole(client, "Witch HP Min: %i", GetConVarInt(cvar_setting_witch_hp_min)); 110 | PrintToConsole(client, "Witch HP Max: %i", GetConVarInt(cvar_setting_witch_hp_max)); 111 | PrintToConsole(client, "Witch Speed Min: %i", GetConVarInt(cvar_setting_witch_speed_min)); 112 | PrintToConsole(client, "Witch Speed Max: %i", GetConVarInt(cvar_setting_witch_speed_max)); 113 | } 114 | 115 | // ============================================================================================ 116 | // == Events 117 | // ============================================================================================ 118 | public Event_TankKilled(Handle:event, const String:name[], bool:dontBroadcast) 119 | { 120 | new tankClient = GetClientOfUserId(GetEventInt(event, "userid")); 121 | 122 | if (IsFakeClient(tankClient)) 123 | _tankBotCount--; 124 | 125 | if (_tankBotCount < 0) 126 | _tankBotCount = 0; 127 | } 128 | 129 | 130 | public Event_WitchSpawn(Handle:event, const String:name[], bool:dontBroadcast) 131 | { 132 | if (GetConVarBool(cvar_notify) == true) 133 | { 134 | for (new i = 1; i <= MaxClients; i++) 135 | { 136 | if (!IsClientInGame(i)) 137 | continue; 138 | 139 | if (GetClientTeam(i) == INFECTEDTEAM) 140 | PrintToChat(i, "\x03Witch \x01: \x04%i \x01血 , \x04%i \x01移速.", GetConVarInt(cvar_witch_health), GetConVarInt(cvar_witch_speed)); 141 | } 142 | } 143 | 144 | // Randomize the next tank (if one) 145 | LogMessage("Witch spawned with HP: %i Speed: %i", GetConVarInt(cvar_witch_health), GetConVarInt(cvar_witch_speed)); 146 | RandomizeWitch(); 147 | } 148 | 149 | public Event_TankSpawn(Handle:event, const String:name[], bool:dontBroadcast) 150 | { 151 | // Determine if we're a bot or not 152 | new tankUserId = GetClientOfUserId(GetEventInt(event, "userid")); 153 | 154 | if (IsFakeClient(tankUserId)) 155 | { 156 | _tankBotCount++; 157 | CreateTimer(0.5,RandomizeTankTimer, INVALID_HANDLE); 158 | return; 159 | } 160 | else 161 | { 162 | if (_tankBotCount > 0) 163 | _tankBotCount--; 164 | } 165 | 166 | RunTankLogic(); 167 | } 168 | 169 | public Action:RandomizeTankTimer(Handle:timer) 170 | { 171 | if (_tankBotCount > 0) 172 | { 173 | RunTankLogic(); 174 | } 175 | } 176 | 177 | public Event_RoundStart(Handle:event, const String:name[], bool:dontBroadcast) 178 | { 179 | LogMessage("Round Start Triggered"); 180 | 181 | RandomizeTank(); 182 | RandomizeWitch(); 183 | } 184 | 185 | RunTankLogic() 186 | { 187 | if (GetConVarBool(cvar_notify) == true) 188 | { 189 | for (new i = 1; i <= MaxClients; i++) 190 | { 191 | if (!IsClientInGame(i) || IsFakeClient(i)) 192 | continue; 193 | 194 | if (GetClientTeam(i) == INFECTEDTEAM) 195 | { 196 | new tankHP = RoundToFloor(float(GetConVarInt(cvar_tank_health)) * 1.5); 197 | PrintToChat(i, "\x03Tank \x01: \x04%i \x01血 , \x04%i \x01移速.", tankHP, GetConVarInt(cvar_tank_speed)); 198 | } 199 | } 200 | } 201 | 202 | // Randomize the next tank (if one) 203 | LogMessage("Tank spawned with HP: %i (%i) Speed: %i", GetConVarInt(cvar_tank_health), GetConVarInt(cvar_tank_health) * 1.5, GetConVarInt(cvar_tank_speed)); 204 | RandomizeTank(); 205 | } 206 | 207 | RandomizeTank() 208 | { 209 | new tank_hp[2]; 210 | new tank_speed[2]; 211 | 212 | 213 | tank_hp[0] = GetConVarInt(cvar_setting_tank_hp_min); 214 | tank_hp[1] = GetConVarInt(cvar_setting_tank_hp_max); 215 | tank_speed[0] = GetConVarInt(cvar_setting_tank_speed_min); 216 | tank_speed[1] = GetConVarInt(cvar_setting_tank_speed_max); 217 | 218 | if (tank_hp[0] > tank_hp[1]) 219 | { 220 | LogError("Randomize Tank HP has min (%i) greater than max (%i)", tank_hp[0], tank_hp[1]); 221 | } 222 | else if (tank_speed[0] > tank_speed[1]) 223 | { 224 | LogError("Randomize Tank Speed has min (%i) greater than max (%i)", tank_speed[0], tank_speed[1]); 225 | } 226 | else 227 | { 228 | LogMessage("Randomize Tank Start HP: %i-%i Speed: %i-%i", tank_hp[0], tank_hp[1], tank_speed[0], tank_speed[1]); 229 | LogMessage("Randomize Tank Current HP: %i Speed: %i", GetConVarInt(cvar_tank_health), GetConVarInt(cvar_tank_speed)); 230 | 231 | // Remove notify 232 | SetConVarFlags(cvar_tank_health, GetConVarFlags(cvar_tank_health) & ~FCVAR_NOTIFY); 233 | SetConVarFlags(cvar_tank_speed, GetConVarFlags(cvar_tank_speed) & ~FCVAR_NOTIFY); 234 | 235 | // Set con var 236 | SetConVarInt(cvar_tank_health, GetRandomInt(tank_hp[0], tank_hp[1])); 237 | SetConVarInt(cvar_tank_speed, GetRandomInt(tank_speed[0], tank_speed[1])); 238 | 239 | // Restore notify 240 | SetConVarFlags(cvar_tank_health, GetConVarFlags(cvar_tank_health) | FCVAR_NOTIFY); 241 | SetConVarFlags(cvar_tank_speed, GetConVarFlags(cvar_tank_speed) | FCVAR_NOTIFY); 242 | 243 | LogMessage("Randomize Tank New HP: %i Speed: %i", GetConVarInt(cvar_tank_health), GetConVarInt(cvar_tank_speed)); 244 | } 245 | } 246 | 247 | RandomizeWitch() 248 | { 249 | new witch_hp[2]; 250 | new witch_speed[2]; 251 | 252 | witch_hp[0] = GetConVarInt(cvar_setting_witch_hp_min); 253 | witch_hp[1] = GetConVarInt(cvar_setting_witch_hp_max); 254 | witch_speed[0] = GetConVarInt(cvar_setting_witch_speed_min); 255 | witch_speed[1] = GetConVarInt(cvar_setting_witch_speed_max); 256 | 257 | if (witch_hp[0] > witch_hp[1]) 258 | { 259 | LogError("Randomize Witch HP has min (%i) greater than max (%i)", witch_hp[0], witch_hp[1]); 260 | } 261 | else if (witch_speed[0] > witch_speed[1]) 262 | { 263 | LogError("Randomize Witch Speed has min (%i) greater than max (%i)", witch_speed[0], witch_speed[1]); 264 | } 265 | else 266 | { 267 | LogMessage("Randomize Witch Start HP: %i-%i Speed: %i-%i", witch_hp[0], witch_hp[1], witch_speed[0], witch_speed[1]); 268 | LogMessage("Randomize Witch Current HP: %i Speed: %i", GetConVarInt(cvar_witch_health), GetConVarInt(cvar_witch_speed)); 269 | 270 | 271 | // Remove notify 272 | SetConVarFlags(cvar_witch_health, GetConVarFlags(cvar_witch_health) & ~FCVAR_NOTIFY); 273 | SetConVarFlags(cvar_witch_speed, GetConVarFlags(cvar_witch_speed) & ~FCVAR_NOTIFY); 274 | 275 | // Set con var 276 | SetConVarInt(cvar_witch_health, GetRandomInt(witch_hp[0], witch_hp[1])); 277 | SetConVarInt(cvar_witch_speed, GetRandomInt(witch_speed[0], witch_speed[1])); 278 | 279 | // Restore notify 280 | SetConVarFlags(cvar_witch_health, GetConVarFlags(cvar_witch_health) | FCVAR_NOTIFY); 281 | SetConVarFlags(cvar_witch_speed, GetConVarFlags(cvar_witch_speed) | FCVAR_NOTIFY); 282 | 283 | LogMessage("Randomize Witch New HP: %i Speed: %i", GetConVarInt(cvar_witch_health), GetConVarInt(cvar_witch_speed)); 284 | } 285 | } 286 | 287 | String:SafeIntToString(value) 288 | { 289 | decl String:buffer[128] 290 | IntToString(value, buffer, sizeof(buffer)); 291 | return buffer; 292 | } 293 | -------------------------------------------------------------------------------- /scripting/l4d_stuckzombiemeleefix.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #pragma newdecls required 3 | #include 4 | #include 5 | #define DEBUG 0 6 | 7 | #define PLUGIN_VERSION "1.0.4" 8 | 9 | public Plugin myinfo = 10 | { 11 | name = "Stuck Zombie Melee Fix", 12 | author = "AtomicStryker", 13 | description = "Smash nonstaggering Zombies", 14 | version = PLUGIN_VERSION, 15 | url = "http://forums.alliedmods.net/showthread.php?p=932416" 16 | } 17 | 18 | public void OnPluginStart() 19 | { 20 | HookEvent("entity_shoved", Event_EntShoved); 21 | AddNormalSoundHook(view_as(HookSound_Callback)); //my melee hook since they didnt include an event for it 22 | 23 | CreateConVar("l4d_stuckzombiemeleefix_version", PLUGIN_VERSION, " Version of L4D Stuck Zombie Melee Fix on this server ", FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD); 24 | } 25 | 26 | bool MeleeDelay[MAXPLAYERS+1]; 27 | 28 | public Action HookSound_Callback(int Clients[64], int &NumClients, char StrSample[PLATFORM_MAX_PATH], int &Entity) 29 | { 30 | //to work only on melee sounds, its 'swish' or 'weaponswing' 31 | if (StrContains(StrSample, "Swish", false) == -1) return Plugin_Continue; 32 | //so the client has the melee sound playing. OMG HES MELEEING! 33 | 34 | if (Entity > MAXPLAYERS) return Plugin_Continue; // bugfix for some people on L4D2 35 | 36 | //add in a 1 second delay so this doesnt fire every frame 37 | if (MeleeDelay[Entity]) return Plugin_Continue; //note 'Entity' means 'client' here 38 | MeleeDelay[Entity] = true; 39 | CreateTimer(1.0, ResetMeleeDelay, Entity); 40 | 41 | #if DEBUG 42 | PrintToChatAll("Melee detected via soundhook."); 43 | #endif 44 | 45 | int entid = GetClientAimTarget(Entity, false); 46 | if (entid <= 0) return Plugin_Continue; 47 | 48 | char entclass[96]; 49 | GetEntityNetClass(entid, entclass, sizeof(entclass)); 50 | if (!StrEqual(entclass, "Infected")) return Plugin_Continue; 51 | 52 | float clientpos[3], entpos[3]; 53 | GetEntityAbsOrigin(entid, entpos); 54 | GetClientEyePosition(Entity, clientpos); 55 | if (GetVectorDistance(clientpos, entpos) < 50) return Plugin_Continue; //else you could 'jedi melee' Zombies from a distance 56 | 57 | #if DEBUG 58 | PrintToChatAll("Youre meleeing and looking at Zombie id #%i", entid); 59 | #endif 60 | 61 | //now to make this Zombie fire a event to be caught by the actual 'fix' 62 | 63 | Event newEvent = CreateEvent("entity_shoved", true); 64 | SetEventInt(newEvent, "attacker", Entity); //the client being called Entity is a bit unfortunate 65 | SetEventInt(newEvent, "entityid", entid); 66 | FireEvent(newEvent, true); 67 | 68 | return Plugin_Continue; 69 | } 70 | 71 | public Action ResetMeleeDelay(Handle timer, any client) 72 | { 73 | MeleeDelay[client] = false; 74 | } 75 | 76 | public void Event_EntShoved(Event event, const char[] name, bool dontBroadcast) 77 | { 78 | int entid = GetEventInt(event, "entityid"); //get the events shoved entity id 79 | 80 | char entclass[96]; 81 | GetEntityNetClass(entid, entclass, sizeof(entclass)); 82 | if (!StrEqual(entclass, "Infected")) return; //make sure it IS a zombie. 83 | 84 | Handle data = CreateDataPack(); //a data pack because i need multiple values saved 85 | CreateTimer(0.5, CheckForMovement, data); //0.5 seemed both long enough for a normal zombie to stumble away and for a stuck one to DIEEEEE 86 | 87 | WritePackCell(data, entid); //save the Zombie id 88 | 89 | float pos[3]; 90 | GetEntityAbsOrigin(entid, pos); //get the Zombies position 91 | WritePackFloat(data, pos[0]); //save the Zombies position 92 | WritePackFloat(data, pos[1]); 93 | WritePackFloat(data, pos[2]); 94 | 95 | #if DEBUG 96 | PrintToChatAll("Meleed Zombie detected."); 97 | #endif 98 | } 99 | 100 | public Action CheckForMovement(Handle timer, Handle data) 101 | { 102 | ResetPack(data); //this resets our 'reading' position in the data pack, to start from the beginning 103 | 104 | int zombieid = ReadPackCell(data); //get the Zombie id 105 | if (!IsValidEntity(zombieid)) return Plugin_Handled; //did the zombie get disappear somehow? 106 | 107 | char entclass[96]; 108 | GetEntityNetClass(zombieid, entclass, sizeof(entclass)); 109 | if (!StrEqual(entclass, "Infected")) return Plugin_Handled; //make sure it STILL IS a zombie. 110 | 111 | float oldpos[3]; 112 | oldpos[0] = ReadPackFloat(data); //get the old Zombie position (half a sec ago) 113 | oldpos[1] = ReadPackFloat(data); 114 | oldpos[2] = ReadPackFloat(data); 115 | 116 | CloseHandle(data); //Dispose of the Handle. It shouldn't have messed with the family 117 | 118 | float newpos[3]; 119 | GetEntityAbsOrigin(zombieid, newpos); //get the Zombies current position 120 | 121 | if (GetVectorDistance(oldpos, newpos) > 5) return Plugin_Handled; //if the positions differ, the zombie was correctly shoved and is now staggering. Plugin End 122 | 123 | #if DEBUG 124 | PrintToChatAll("Stuck meleed Zombie detected."); 125 | #endif 126 | 127 | //now i could simply slay the stuck zombie. but this would also instantkill any zombie you meleed into a corner or against a wall 128 | //so instead i coded a two-punts-it-doesnt-move-so-slay-it command 129 | 130 | int zombiehealth = GetEntProp(zombieid, Prop_Data, "m_iHealth"); 131 | int zombiehealthmax = GetConVarInt(FindConVar("z_health")); 132 | 133 | if (zombiehealth - (zombiehealthmax / 2) <= 0) // if the zombies health is less than half 134 | { 135 | //SetEntProp(zombieid, Prop_Data, "m_iHealth", 0); //CRUSH HIM!!!!!! - ragdoll bug, unused 136 | AcceptEntityInput(zombieid, "BecomeRagdoll"); //Damizean pointed this one out, Cheers to him. 137 | 138 | #if DEBUG 139 | PrintToChatAll("Slayed Stuck Zombie."); 140 | #endif 141 | } 142 | else SetEntProp(zombieid, Prop_Data, "m_iHealth", zombiehealth - (zombiehealthmax / 2)); //else remove half of its health, so the zombie dies from the next melee blow 143 | 144 | return Plugin_Handled; 145 | } 146 | 147 | //entity abs origin code from here 148 | //http://forums.alliedmods.net/showpost.php?s=e5dce96f11b8e938274902a8ad8e75e9&p=885168&postcount=3 149 | public Action GetEntityAbsOrigin(int entity, float origin[3]) 150 | { 151 | float mins[3], maxs[3]; 152 | GetEntPropVector(entity,Prop_Send,"m_vecOrigin",origin); 153 | GetEntPropVector(entity,Prop_Send,"m_vecMins",mins); 154 | GetEntPropVector(entity,Prop_Send,"m_vecMaxs",maxs); 155 | 156 | origin[0] += (mins[0] + maxs[0]) * 0.5; 157 | origin[1] += (mins[1] + maxs[1]) * 0.5; 158 | origin[2] += (mins[2] + maxs[2]) * 0.5; 159 | } -------------------------------------------------------------------------------- /scripting/l4d_survivor_identity_fix.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #pragma newdecls required 3 | 4 | #define PLUGIN_NAME "[L4D1/2] Survivor Identity Fix for 5+ Survivors" 5 | #define PLUGIN_AUTHOR "Merudo, Shadowysn" 6 | #define PLUGIN_DESC "Fix bug where a survivor will change identity when a player connects/disconnects if there are 5+ survivors" 7 | #define PLUGIN_VERSION "1.3" 8 | #define PLUGIN_URL "https://forums.alliedmods.net/showthread.php?p=2403731#post2403731" 9 | #define PLUGIN_NAME_SHORT "5+ Survivor Identity Fix" 10 | #define PLUGIN_NAME_TECH "survivor_identity_fix" 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #define TEAM_SURVIVOR 2 17 | #define TEAM_PASSING 4 18 | 19 | char g_Models[MAXPLAYERS+1][128]; 20 | 21 | #define GAMEDATA "l4d_survivor_identity_fix" 22 | 23 | Handle hConf = null; 24 | #define NAME_SetModel "CBasePlayer::SetModel" 25 | static Handle hDHookSetModel = null; 26 | 27 | #define SIG_SetModel_LINUX "@_ZN11CBasePlayer8SetModelEPKc" 28 | #define SIG_SetModel_WINDOWS "\\x55\\x8B\\x2A\\x8B\\x2A\\x2A\\x56\\x57\\x50\\x8B\\x2A\\xE8\\xC0\\x7B" 29 | 30 | #define SIG_L4D1SetModel_WINDOWS "\\x8B\\x2A\\x2A\\x2A\\x56\\x57\\x50\\x8B\\x2A\\xE8\\x2A\\x2A\\x2A\\x2A\\x8B\\x3D" 31 | 32 | public Plugin myinfo = 33 | { 34 | name = PLUGIN_NAME, 35 | author = PLUGIN_AUTHOR, 36 | description = PLUGIN_DESC, 37 | version = PLUGIN_VERSION, 38 | url = PLUGIN_URL 39 | } 40 | 41 | public void OnPluginStart() 42 | { 43 | GetGamedata(); 44 | 45 | CreateConVar("l4d_survivor_identity_fix_version", PLUGIN_VERSION, "Survivor Change Fix Version", FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD); 46 | 47 | HookEvent("player_bot_replace", Event_PlayerToBot, EventHookMode_Post); 48 | HookEvent("bot_player_replace", Event_BotToPlayer, EventHookMode_Post); 49 | } 50 | 51 | // ------------------------------------------------------------------------ 52 | // Stores the client of each survivor each time it is changed 53 | // Needed because when Event_PlayerToBot fires, it's hunter model instead 54 | // ------------------------------------------------------------------------ 55 | public MRESReturn SetModel_Pre(int client, Handle hParams) 56 | { } // We need this pre hook even though it's empty, or else the post hook will crash the game. 57 | 58 | public MRESReturn SetModel(int client, Handle hParams) 59 | { 60 | if (!IsValidClient(client) || !IsSurvivor(client)) 61 | { 62 | g_Models[client][0] = '\0'; 63 | return; 64 | } 65 | 66 | char model[128]; 67 | DHookGetParamString(hParams, 1, model, sizeof(model)); 68 | if (StrContains("models/infected", model, false) > -1) strcopy(g_Models[client], 128, model); 69 | } 70 | 71 | // ------------------------------------------------------------------------ 72 | // Models & survivor names so bots can be renamed 73 | // ------------------------------------------------------------------------ 74 | char survivor_names[8][] = { "Nick", "Rochelle", "Coach", "Ellis", "Bill", "Zoey", "Francis", "Louis"}; 75 | char survivor_models[8][] = 76 | { 77 | "models/survivors/survivor_gambler.mdl", 78 | "models/survivors/survivor_producer.mdl", 79 | "models/survivors/survivor_coach.mdl", 80 | "models/survivors/survivor_mechanic.mdl", 81 | "models/survivors/survivor_namvet.mdl", 82 | "models/survivors/survivor_teenangst.mdl", 83 | "models/survivors/survivor_biker.mdl", 84 | "models/survivors/survivor_manager.mdl" 85 | }; 86 | 87 | // -------------------------------------- 88 | // Bot replaced by player 89 | // -------------------------------------- 90 | public Action Event_BotToPlayer(Handle event, const char[] name, bool dontBroadcast) 91 | { 92 | int player = GetClientOfUserId(GetEventInt(event, "player")); 93 | int bot = GetClientOfUserId(GetEventInt(event, "bot")); 94 | 95 | if (!IsValidClient(player) || IsFakeClient(player)) return; // ignore fake players (side product of creating bots) 96 | 97 | char model[128]; 98 | GetClientModel(bot, model, sizeof(model)); 99 | SetEntityModel(player, model); 100 | SetEntProp(player, Prop_Send, "m_survivorCharacter", GetEntProp(bot, Prop_Send, "m_survivorCharacter")); 101 | } 102 | 103 | // -------------------------------------- 104 | // Player -> Bot 105 | // -------------------------------------- 106 | public Action Event_PlayerToBot(Handle event, char[] name, bool dontBroadcast) 107 | { 108 | int player = GetClientOfUserId(GetEventInt(event, "player")); 109 | int bot = GetClientOfUserId(GetEventInt(event, "bot")); 110 | 111 | if (IsFakeClient(player)) return; // ignore fake players (side product of creating bots) 112 | if (!IsValidClient(player) || !IsSurvivor(player) || IsFakeClient(player)) return; 113 | 114 | if (g_Models[player][0] != '\0') 115 | { 116 | SetEntProp(bot, Prop_Send, "m_survivorCharacter", GetEntProp(player, Prop_Send, "m_survivorCharacter")); 117 | SetEntityModel(bot, g_Models[player]); // Restore saved model. Player model is hunter at this point 118 | for (int i = 0; i < 8; i++) 119 | { 120 | if (StrEqual(g_Models[player], survivor_models[i])) SetClientInfo(bot, "name", survivor_names[i]); 121 | } 122 | } 123 | } 124 | 125 | void GetGamedata() 126 | { 127 | char filePath[PLATFORM_MAX_PATH]; 128 | BuildPath(Path_SM, filePath, sizeof(filePath), "gamedata/%s.txt", GAMEDATA); 129 | if( FileExists(filePath) ) 130 | { 131 | hConf = LoadGameConfigFile(GAMEDATA); // For some reason this doesn't return null even for invalid files, so check they exist first. 132 | } 133 | else 134 | { 135 | PrintToServer("[SM] %s plugin unable to get %i.txt gamedata file. Generating...", PLUGIN_NAME_SHORT, GAMEDATA); 136 | 137 | Handle fileHandle = OpenFile(filePath, "a+"); 138 | if (fileHandle == null) 139 | { SetFailState("[SM] Couldn't generate gamedata file!"); } 140 | 141 | WriteFileLine(fileHandle, "\"Games\""); 142 | WriteFileLine(fileHandle, "{"); 143 | WriteFileLine(fileHandle, " \"left4dead\""); 144 | WriteFileLine(fileHandle, " {"); 145 | WriteFileLine(fileHandle, " \"Signatures\""); 146 | WriteFileLine(fileHandle, " {"); 147 | WriteFileLine(fileHandle, " \"%s\"", NAME_SetModel); 148 | WriteFileLine(fileHandle, " {"); 149 | WriteFileLine(fileHandle, " \"library\" \"server\""); 150 | WriteFileLine(fileHandle, " \"linux\" \"%s\"", SIG_SetModel_LINUX); 151 | WriteFileLine(fileHandle, " \"windows\" \"%s\"", SIG_L4D1SetModel_WINDOWS); 152 | WriteFileLine(fileHandle, " \"mac\" \"%s\"", SIG_SetModel_LINUX); 153 | WriteFileLine(fileHandle, " }"); 154 | WriteFileLine(fileHandle, " }"); 155 | WriteFileLine(fileHandle, " }"); 156 | WriteFileLine(fileHandle, " \"left4dead2\""); 157 | WriteFileLine(fileHandle, " {"); 158 | WriteFileLine(fileHandle, " \"Signatures\""); 159 | WriteFileLine(fileHandle, " {"); 160 | WriteFileLine(fileHandle, " \"%s\"", NAME_SetModel); 161 | WriteFileLine(fileHandle, " {"); 162 | WriteFileLine(fileHandle, " \"library\" \"server\""); 163 | WriteFileLine(fileHandle, " \"linux\" \"%s\"", SIG_SetModel_LINUX); 164 | WriteFileLine(fileHandle, " \"windows\" \"%s\"", SIG_SetModel_WINDOWS); 165 | WriteFileLine(fileHandle, " \"mac\" \"%s\"", SIG_SetModel_LINUX); 166 | WriteFileLine(fileHandle, " }"); 167 | WriteFileLine(fileHandle, " }"); 168 | WriteFileLine(fileHandle, " }"); 169 | WriteFileLine(fileHandle, "}"); 170 | 171 | CloseHandle(fileHandle); 172 | hConf = LoadGameConfigFile(GAMEDATA); 173 | if (hConf == null) 174 | { SetFailState("[SM] Failed to load auto-generated gamedata file!"); } 175 | 176 | PrintToServer("[SM] %s successfully generated %s.txt gamedata file!", PLUGIN_NAME_SHORT, GAMEDATA); 177 | } 178 | PrepDHooks(); 179 | } 180 | 181 | void PrepDHooks() 182 | { 183 | if (hConf == null) 184 | { 185 | SetFailState("Error: Gamedata not found"); 186 | } 187 | 188 | hDHookSetModel = DHookCreateDetour(Address_Null, CallConv_THISCALL, ReturnType_Void, ThisPointer_CBaseEntity); 189 | DHookSetFromConf(hDHookSetModel, hConf, SDKConf_Signature, NAME_SetModel); 190 | DHookAddParam(hDHookSetModel, HookParamType_CharPtr); 191 | DHookEnableDetour(hDHookSetModel, false, SetModel_Pre); 192 | DHookEnableDetour(hDHookSetModel, true, SetModel); 193 | } 194 | 195 | bool IsValidClient(int client, bool replaycheck = true) 196 | { 197 | if (client <= 0 || client > MaxClients) return false; 198 | if (!IsClientInGame(client)) return false; 199 | if (replaycheck) 200 | { 201 | if (IsClientSourceTV(client) || IsClientReplay(client)) return false; 202 | } 203 | return true; 204 | } 205 | 206 | bool IsSurvivor(int client) 207 | { 208 | if (GetClientTeam(client) != TEAM_SURVIVOR && GetClientTeam(client) != TEAM_PASSING) return false; 209 | return true; 210 | } -------------------------------------------------------------------------------- /scripting/l4d_survivorai_pouncedfix.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define PLUGIN_VERSION "1.0.5" 5 | #define PLUGIN_NAME "L4D Survivor AI Pounced Fix" 6 | 7 | 8 | public Plugin:myinfo = { 9 | name = PLUGIN_NAME, 10 | author = " AtomicStryker ", 11 | description = " Fixes Survivor Bots neglecting Teammates in need ", 12 | version = PLUGIN_VERSION, 13 | url = "" 14 | }; 15 | 16 | static bool:IsL4D2 = false; 17 | 18 | 19 | public OnPluginStart() 20 | { 21 | HookEvent("player_hurt", Event_PlayerHurt); 22 | 23 | CreateConVar("l4d_survivoraipouncedfix_version", PLUGIN_VERSION, " Version of L4D Survivor AI Pounced Fix on this server ", FCVAR_PLUGIN|FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD); 24 | 25 | CheckGame(); 26 | } 27 | 28 | public Action:Event_PlayerHurt(Handle:event, const String:name[], bool:dontBroadcast) 29 | { 30 | new attacker = GetClientOfUserId(GetEventInt(event, "attacker")); 31 | new victim = GetClientOfUserId(GetEventInt(event, "userid")); 32 | 33 | if (!victim 34 | || !attacker 35 | || !IsClientInGame(attacker) 36 | || GetClientTeam(attacker) == 2) 37 | { 38 | return; 39 | } 40 | 41 | if (NeedsTeammateHelp(victim)) 42 | { 43 | decl Float:position[3]; 44 | GetClientAbsOrigin(attacker, position); 45 | 46 | CallBots(position, attacker); 47 | } 48 | } 49 | 50 | static CallBots(Float:position[3], attacker) 51 | { 52 | decl Float:targetPos[3]; 53 | 54 | for (new target = 1; target <= MaxClients; target++) 55 | { 56 | if (IsClientInGame(target)) 57 | { 58 | if (GetClientHealth(target) > 0 59 | && GetClientTeam(target) == 2 60 | && IsFakeClient(target)) // make sure target is a live Survivor Bot 61 | { 62 | GetClientAbsOrigin(target, targetPos); 63 | 64 | if (GetVectorDistance(targetPos, position) < 500) 65 | { 66 | ScriptCommand(target, "script", 67 | "CommandABot({cmd=0,bot=GetPlayerFromUserID(%i),target=GetPlayerFromUserID(%i)})", 68 | GetClientUserId(target), 69 | GetClientUserId(attacker)); 70 | } 71 | } 72 | } 73 | } 74 | } 75 | 76 | stock bool:NeedsTeammateHelp(client) 77 | { 78 | if (HasValidEnt(client, "m_tongueOwner") // Smoked 79 | || HasValidEnt(client, "m_pounceAttacker") // Huntered 80 | || (IsL4D2 81 | && HasValidEnt(client, "m_jockeyAttacker")) // Ridden 82 | || (IsL4D2 83 | && HasValidEnt(client, "m_pummelAttacker"))) // Charged 84 | { 85 | return true; 86 | } 87 | 88 | return false; 89 | } 90 | 91 | stock bool:HasValidEnt(client, const String:entprop[]) 92 | { 93 | new ent = GetEntPropEnt(client, Prop_Send, entprop); 94 | 95 | return (ent > 0 96 | && IsClientInGame(ent)); 97 | } 98 | 99 | stock ScriptCommand(client, const String:command[], const String:arguments[], any:...) 100 | { 101 | new String:vscript[PLATFORM_MAX_PATH]; 102 | VFormat(vscript, sizeof(vscript), arguments, 4); 103 | 104 | new flags = GetCommandFlags(command); 105 | SetCommandFlags(command, flags^FCVAR_CHEAT); 106 | FakeClientCommand(client, "%s %s", command, vscript); 107 | SetCommandFlags(command, flags | FCVAR_CHEAT); 108 | } 109 | 110 | static CheckGame() 111 | { 112 | decl String:game[32]; 113 | GetGameFolderName(game, sizeof(game)); 114 | 115 | if (StrEqual(game, "left4dead", false)) 116 | IsL4D2 = false; 117 | 118 | else if (StrEqual(game, "left4dead2", false)) 119 | IsL4D2 = true; 120 | 121 | else 122 | SetFailState("Plugin is for Left For Dead 1/2 only"); 123 | } -------------------------------------------------------------------------------- /scripting/lfd_both_fixUpgradePack.sp: -------------------------------------------------------------------------------- 1 | #pragma semicolon 1 2 | #include 3 | #include 4 | #include 5 | #pragma newdecls required 6 | 7 | public Plugin myinfo = 8 | { 9 | name = "Upgrade Pack Fixes", 10 | author = "bullet28, V10, Silvers", 11 | description = "Fixes upgrade packs pickup bug when using survivor model change", 12 | version = "1", 13 | url = "" 14 | } 15 | 16 | int g_UpgradePackCanUseCount; 17 | Handle usedUpgrades[MAXPLAYERS+1]; 18 | float lastSoundTime[MAXPLAYERS+1]; 19 | bool bUsingExplosive[MAXPLAYERS+1]; 20 | 21 | ConVar cvarDeniedSound; 22 | ConVar cvarBlockGlauncher; 23 | ConVar cvarIncendiaryMulti; 24 | ConVar cvarExplosiveMulti; 25 | 26 | bool cvarDeniedSoundValue; 27 | int cvarBlockGlauncherValue; 28 | float cvarIncendiaryMultiValue; 29 | float cvarExplosiveMultiValue; 30 | 31 | public void OnPluginStart() { 32 | ResetAllUsedUpgrades(); 33 | HookEvent("round_start", EventRoundStart); 34 | 35 | cvarDeniedSound = CreateConVar("upgrade_denied_sound", "1", "Play sound when ammo already used", FCVAR_NONE); 36 | cvarBlockGlauncher = CreateConVar("upgrade_block_glauncher", "1", "Block use of special ammo with grenade launcher (0 - Allow | 1 - Block any | 2 - Block incendiary | 3 - Block explosive)", FCVAR_NONE); 37 | cvarIncendiaryMulti = CreateConVar("upgrade_incendiary_multi", "1.0", "Incendiary ammo multiplier on pickup", FCVAR_NONE); 38 | cvarExplosiveMulti = CreateConVar("upgrade_explosive_multi", "1.0", "Explosive ammo multiplier on pickup", FCVAR_NONE); 39 | 40 | cvarDeniedSound.AddChangeHook(OnConVarChange); 41 | cvarBlockGlauncher.AddChangeHook(OnConVarChange); 42 | cvarIncendiaryMulti.AddChangeHook(OnConVarChange); 43 | cvarExplosiveMulti.AddChangeHook(OnConVarChange); 44 | OnConVarChange(null, "", ""); 45 | 46 | Handle hGameData = LoadGameConfigFile("upgradepackfix"); 47 | g_UpgradePackCanUseCount = GameConfGetOffset(hGameData, "m_iUpgradePackCanUseCount"); 48 | delete hGameData; 49 | } 50 | 51 | public void OnAllPluginsLoaded() { 52 | char smxFileName1[] = "l4d2_upgradepackfix.smx"; 53 | Handle hFoundPlugin1 = FindPluginByFile(smxFileName1); 54 | if (hFoundPlugin1) SetFailState("Please remove %s before using this plugin", smxFileName1); 55 | 56 | char smxFileName2[] = "l4d2_upgrade_block.smx"; 57 | Handle hFoundPlugin2 = FindPluginByFile(smxFileName2); 58 | if (hFoundPlugin2) SetFailState("Please remove %s before using this plugin", smxFileName2); 59 | } 60 | 61 | public void OnConVarChange(ConVar convar, char[] oldValue, char[] newValue) { 62 | cvarDeniedSoundValue = cvarDeniedSound.BoolValue; 63 | cvarBlockGlauncherValue = cvarBlockGlauncher.IntValue; 64 | cvarIncendiaryMultiValue = cvarIncendiaryMulti.FloatValue; 65 | cvarExplosiveMultiValue = cvarExplosiveMulti.FloatValue; 66 | } 67 | 68 | public void OnClientPostAdminCheck(int client) { 69 | ResetUsedUpgrades(client); 70 | } 71 | 72 | public Action EventRoundStart(Event event, const char[] name, bool dontBroadcast) { 73 | ResetAllUsedUpgrades(); 74 | } 75 | 76 | void ResetAllUsedUpgrades() { 77 | for (int client = 1; client <= MaxClients; client++) { 78 | ResetUsedUpgrades(client); 79 | } 80 | } 81 | 82 | void ResetUsedUpgrades(int client) { 83 | if (usedUpgrades[client] != INVALID_HANDLE) 84 | CloseHandle(usedUpgrades[client]); 85 | usedUpgrades[client] = CreateArray(); 86 | } 87 | 88 | public void OnEntityCreated(int entity, const char[] classname) { 89 | if (StrEqual(classname, "upgrade_ammo_explosive") || StrEqual(classname, "upgrade_ammo_incendiary")) { 90 | SDKHook(entity, SDKHook_Use, OnUpgradeUse); 91 | } 92 | } 93 | 94 | public Action OnUpgradeUse(int entity, int activator, int caller, UseType type, float value) { 95 | if (!isValidEntity(entity)) return Plugin_Continue; 96 | 97 | char classname[32]; 98 | GetEntityClassname(entity, classname, sizeof(classname)); 99 | if (StrContains(classname, "upgrade_ammo_") == -1) return Plugin_Continue; 100 | 101 | SetEntData(entity, g_UpgradePackCanUseCount, 4, 1, true); 102 | 103 | int client = caller; 104 | if (!isPlayerRealSurvivor(client)) return Plugin_Continue; 105 | 106 | int primaryItem = GetPlayerWeaponSlot(client, 0); 107 | if (primaryItem == -1) return Plugin_Continue; 108 | 109 | bUsingExplosive[client] = StrEqual(classname, "upgrade_ammo_explosive"); 110 | 111 | SetEntProp(entity, Prop_Send, "m_iUsedBySurvivorsMask", 0); 112 | 113 | bool bForceBlocked = ShouldBeForceBlocked(client, primaryItem); 114 | 115 | if (bForceBlocked || FindValueInArray(usedUpgrades[client], entity) != -1) { 116 | PlayDenySound(client); 117 | return Plugin_Handled; 118 | 119 | } else { 120 | //PrintToChatAll("%f: First use of %N", GetGameTime(), client); 121 | PushArrayCell(usedUpgrades[client], entity); 122 | lastSoundTime[client] = GetEngineTime(); 123 | SetUsedBySurvivor(client, entity); 124 | 125 | if ((bUsingExplosive[client] && cvarExplosiveMultiValue > 1.0) || (!bUsingExplosive[client] && cvarIncendiaryMultiValue > 1.0)) { 126 | SDKHook(client, SDKHook_PostThink, PostThinkMultiply); 127 | } 128 | } 129 | 130 | return Plugin_Continue; 131 | } 132 | 133 | public Action PostThinkMultiply(int client) { 134 | SDKUnhook(client, SDKHook_PostThink, PostThinkMultiply); 135 | 136 | if (isPlayerAliveSurvivor(client)) { 137 | int primaryItem = GetPlayerWeaponSlot(client, 0); 138 | if (primaryItem != -1) { 139 | int currentUpgradedAmmo = GetEntProp(primaryItem, Prop_Send, "m_nUpgradedPrimaryAmmoLoaded"); 140 | int targetUpgradedAmmo = RoundToFloor(currentUpgradedAmmo * (bUsingExplosive[client] ? cvarExplosiveMultiValue : cvarIncendiaryMultiValue)); 141 | if (targetUpgradedAmmo > currentUpgradedAmmo) { 142 | SetEntProp(primaryItem, Prop_Send, "m_nUpgradedPrimaryAmmoLoaded", targetUpgradedAmmo); 143 | } 144 | } 145 | } 146 | } 147 | 148 | void SetUsedBySurvivor(int client, int entity) { 149 | int usedMask = GetEntProp(entity, Prop_Send, "m_iUsedBySurvivorsMask"); 150 | bool bAlreadyUsed = !(usedMask & (1 << client - 1)); 151 | if (bAlreadyUsed) return; 152 | 153 | int newMask = usedMask | (1 << client - 1); 154 | SetEntProp(entity, Prop_Send, "m_iUsedBySurvivorsMask", newMask); 155 | } 156 | 157 | void PlayDenySound(int client) { 158 | if (cvarDeniedSoundValue) { 159 | float currentTime = GetEngineTime(); 160 | if (currentTime > lastSoundTime[client] + 2.0) { 161 | ClientCommand(client, "play buttons/button11.wav"); 162 | lastSoundTime[client] = currentTime; 163 | } 164 | } 165 | } 166 | 167 | bool ShouldBeForceBlocked(int client, int primaryItem) { 168 | if (cvarBlockGlauncherValue == 1 || (cvarBlockGlauncherValue == 2 && !bUsingExplosive[client]) || (cvarBlockGlauncherValue == 3 && bUsingExplosive[client])) { 169 | char classname[32]; 170 | GetEntityClassname(primaryItem, classname, sizeof classname); 171 | if (StrEqual(classname, "weapon_grenade_launcher")) { 172 | return true; 173 | } 174 | } 175 | 176 | return false; 177 | } 178 | 179 | /* */ 180 | bool isValidEntity(int entity) { 181 | return entity > 0 && entity <= 2048 && IsValidEdict(entity) && IsValidEntity(entity); 182 | } 183 | 184 | bool isPlayerValid(int client) { 185 | return client > 0 && client <= MaxClients && IsClientInGame(client); 186 | } 187 | 188 | bool isPlayerReal(int client) { 189 | return isPlayerValid(client) && !IsFakeClient(client); 190 | } 191 | 192 | bool isPlayerSurvivor(int client) { 193 | return isPlayerValid(client) && GetClientTeam(client) == 2; 194 | } 195 | 196 | bool isPlayerRealSurvivor(int client) { 197 | return isPlayerReal(client) && GetClientTeam(client) == 2; 198 | } 199 | 200 | bool isPlayerAliveSurvivor(int client) { 201 | return isPlayerSurvivor(client) && IsPlayerAlive(client); 202 | } 203 | -------------------------------------------------------------------------------- /scripting/playerinfo.sp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | new player_num; 4 | 5 | public Plugin:myinfo = 6 | { 7 | name = "Player/Server Notification", 8 | author = "HMBSbige", 9 | description = "", 10 | version = "1.0", 11 | url = "https://github.com/HMBSbige" 12 | }; 13 | 14 | public OnPluginStart() 15 | { 16 | HookEvent("player_team", JoinTeam); 17 | } 18 | 19 | public OnClientConnected(client) 20 | { 21 | if (IsFakeClient(client)) 22 | { 23 | return; 24 | } 25 | ++player_num; 26 | PrintToChatAll("\x03[提示] \x05%N \x01正在加入服务器, 现在的玩家总人数是 \x04%i\x01 人", client, player_num); 27 | } 28 | 29 | public OnClientDisconnect(client) 30 | { 31 | if (IsFakeClient(client)) 32 | { 33 | return; 34 | } 35 | --player_num; 36 | PrintToChatAll("\x03[提示] \x05%N \x01已经离开了服务器, 现在的玩家总人数是 \x04%i\x01 人", client, player_num); 37 | } 38 | 39 | public Action:JoinTeam(Handle:event, String:event_name[], bool:dontBroadcast) 40 | { 41 | new playerClient = GetClientOfUserId(GetEventInt(event, "userid")); 42 | new clientTeam = GetEventInt(event, "team"); 43 | if (IsFakeClient(playerClient) || !IsClientInGame(playerClient) || !IsClientConnected(playerClient)) 44 | { 45 | return Plugin_Handled; 46 | } 47 | 48 | switch (clientTeam) 49 | { 50 | case 1: 51 | { 52 | PrintToChatAll("\x03[提示] \x05%N \x01加入了旁观者", playerClient); 53 | } 54 | case 2: 55 | { 56 | PrintToChatAll("\x03[提示] \x05%N \x01加入了生还者", playerClient); 57 | } 58 | case 3: 59 | { 60 | PrintToChatAll("\x03[提示] \x05%N \x01加入了感染者", playerClient); 61 | } 62 | } 63 | 64 | return Plugin_Handled; 65 | } 66 | 67 | public OnMapEnd() 68 | { 69 | player_num = 0; 70 | } -------------------------------------------------------------------------------- /scripting/survivor_afk_fix.sp: -------------------------------------------------------------------------------- 1 | /* 2 | * Fixes for gamebreaking bugs and stupid gameplay aspects 3 | * Copyright (C) 2020 LuxLuma acceliacat@gmail.com 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | */ 18 | 19 | #pragma semicolon 1 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #pragma newdecls required 27 | 28 | 29 | #define DEBUG 0 30 | 31 | #define GAMEDATA "survivor_afk_fix" 32 | #define PLUGIN_VERSION "1.0.4" 33 | 34 | Handle hAFKSDKCall; 35 | 36 | Handle hSetHumanSpecSDKCall; 37 | Handle hSetObserverTargetSDKCall; 38 | 39 | bool g_bShouldFixAFK = false; 40 | int g_iSurvivorBot; 41 | bool g_bShouldIgnore = false; 42 | 43 | public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) 44 | { 45 | if(GetEngineVersion() != Engine_Left4Dead2 && GetEngineVersion() != Engine_Left4Dead) 46 | { 47 | strcopy(error, err_max, "Plugin only supports Left 4 Dead 1/2"); 48 | return APLRes_SilentFailure; 49 | } 50 | return APLRes_Success; 51 | } 52 | 53 | public Plugin myinfo = 54 | { 55 | name = "[L4D2]Survivor_AFK_Fix", 56 | author = "Lux", 57 | description = "Fixes survivor going AFK game function.", 58 | version = PLUGIN_VERSION, 59 | url = "https://github.com/LuxLuma/Left-4-fix/tree/master/left%204%20fix/survivors/survivor_afk_fix" 60 | }; 61 | 62 | public void OnPluginStart() 63 | { 64 | CreateConVar("survivor_afk_fix_ver", PLUGIN_VERSION, "", FCVAR_NOTIFY|FCVAR_DONTRECORD); 65 | 66 | Handle hGamedata = LoadGameConfigFile(GAMEDATA); 67 | if(hGamedata == null) 68 | SetFailState("Failed to load \"%s.txt\" gamedata.", GAMEDATA); 69 | 70 | Handle hDetour; 71 | hDetour = DHookCreateFromConf(hGamedata, "CTerrorPlayer::GoAwayFromKeyboard"); 72 | if(!hDetour) 73 | SetFailState("Failed to find 'CTerrorPlayer::GoAwayFromKeyboard' signature"); 74 | 75 | if(!DHookEnableDetour(hDetour, false, OnGoAFKPre)) 76 | SetFailState("Failed to detour 'CTerrorPlayer::GoAwayFromKeyboard'"); 77 | if(!DHookEnableDetour(hDetour, true, OnGoAFKPost)) 78 | SetFailState("Failed to detour 'CTerrorPlayer::GoAwayFromKeyboard'"); 79 | 80 | hDetour = DHookCreateFromConf(hGamedata, "SurvivorBot::SetHumanSpectator"); 81 | if(!hDetour) 82 | SetFailState("Failed to find 'SurvivorBot::SetHumanSpectator' signature"); 83 | 84 | if(!DHookEnableDetour(hDetour, false, OnSetHumanSpectatorPre)) 85 | SetFailState("Failed to detour 'SurvivorBot::SetHumanSpectator'"); 86 | 87 | StartPrepSDKCall(SDKCall_Player); 88 | if(!PrepSDKCall_SetFromConf(hGamedata, SDKConf_Signature, "SurvivorBot::SetHumanSpectator")) 89 | SetFailState("Error finding the 'SurvivorBot::SetHumanSpectator' signature."); 90 | 91 | PrepSDKCall_AddParameter(SDKType_CBasePlayer, SDKPass_Pointer); 92 | hSetHumanSpecSDKCall = EndPrepSDKCall(); 93 | if(hSetHumanSpecSDKCall == null) 94 | SetFailState("Unable to prep SDKCall 'SurvivorBot::SetHumanSpectator'"); 95 | 96 | StartPrepSDKCall(SDKCall_Player); 97 | if(!PrepSDKCall_SetFromConf(hGamedata, SDKConf_Virtual, "CTerrorPlayer::SetObserverTarget")) 98 | SetFailState("Error finding the 'CTerrorPlayer::SetObserverTargetv' offset."); 99 | 100 | PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); 101 | hSetObserverTargetSDKCall = EndPrepSDKCall(); 102 | if(hSetObserverTargetSDKCall == null) 103 | SetFailState("Unable to prep SDKCall 'CTerrorPlayer::SetObserverTarget'"); 104 | 105 | 106 | 107 | StartPrepSDKCall(SDKCall_Player); 108 | if(!PrepSDKCall_SetFromConf(hGamedata, SDKConf_Signature, "CTerrorPlayer::GoAwayFromKeyboard")) 109 | SetFailState("Error finding the 'CTerrorPlayer::GoAwayFromKeyboard' signature."); 110 | 111 | hAFKSDKCall = EndPrepSDKCall(); 112 | if(hAFKSDKCall == null) 113 | SetFailState("Unable to prep SDKCall 'CTerrorPlayer::GoAwayFromKeyboard'"); 114 | 115 | RegConsoleCmd("sm_afk", GoAwayFromKeyboard); 116 | RegConsoleCmd("sm_idle", GoAwayFromKeyboard); 117 | RegConsoleCmd("sm_spec", GoAwayFromKeyboard); 118 | RegConsoleCmd("sm_spectate", GoAwayFromKeyboard); 119 | RegConsoleCmd("sm_away", GoAwayFromKeyboard); 120 | 121 | delete hGamedata; 122 | } 123 | 124 | public Action GoAwayFromKeyboard(int client, int args) 125 | { 126 | if(client == 0) 127 | return Plugin_Handled; 128 | 129 | SDKCall(hAFKSDKCall, client); 130 | return Plugin_Handled; 131 | } 132 | 133 | public MRESReturn OnGoAFKPre(int pThis, Handle hReturn) 134 | { 135 | if(g_bShouldFixAFK) 136 | LogError("Something wentwrong here 'CTerrorPlayer::GoAwayFromKeyboard' :("); 137 | 138 | g_bShouldFixAFK = true; 139 | } 140 | 141 | //Only thing we need is the bot single threaded logic means we use the call order 142 | public void OnEntityCreated(int entity, const char[] classname) 143 | { 144 | if(!g_bShouldFixAFK) 145 | return; 146 | 147 | if(classname[0] != 's' || !StrEqual(classname, "survivor_bot", false)) 148 | return; 149 | 150 | g_iSurvivorBot = entity; 151 | } 152 | 153 | 154 | public MRESReturn OnSetHumanSpectatorPre(int pThis, Handle hParams) 155 | { 156 | if(g_bShouldIgnore) 157 | return MRES_Ignored; 158 | 159 | if(!g_bShouldFixAFK) 160 | return MRES_Ignored; 161 | 162 | if(g_iSurvivorBot < 1) 163 | return MRES_Ignored; 164 | 165 | return MRES_Supercede; 166 | } 167 | 168 | //pThis should only be CTerrorPlayer class and real players only not going to check for it 169 | public MRESReturn OnGoAFKPost(int pThis, Handle hReturn) 170 | { 171 | if(g_bShouldFixAFK && g_iSurvivorBot > 0 && IsFakeClient(g_iSurvivorBot)) 172 | { 173 | g_bShouldIgnore = true; 174 | 175 | SDKCall(hSetHumanSpecSDKCall, g_iSurvivorBot, pThis); 176 | SDKCall(hSetObserverTargetSDKCall, pThis, g_iSurvivorBot); 177 | 178 | WriteTakeoverPanel(pThis, g_iSurvivorBot); 179 | 180 | g_bShouldIgnore = false; 181 | } 182 | 183 | g_iSurvivorBot = 0; 184 | g_bShouldFixAFK = false; 185 | return MRES_Ignored; 186 | } 187 | 188 | //Thanks Leonardo for helping me with the vgui keyvalue layout 189 | //This is for rare case sometimes the takeover panel don't show. 190 | void WriteTakeoverPanel(int client, int bot) 191 | { 192 | char buf[2]; 193 | int character = GetEntProp(bot, Prop_Send, "m_survivorCharacter", 1); 194 | IntToString(character, buf, sizeof(buf)); 195 | BfWrite msg = view_as(StartMessageOne("VGUIMenu", client)); 196 | msg.WriteString("takeover_survivor_bar"); //type 197 | msg.WriteByte(true); //hide or show panel type 198 | msg.WriteByte(1); //amount of keys 199 | msg.WriteString("character"); //key name 200 | msg.WriteString(buf); //key value 201 | EndMessage(); 202 | } -------------------------------------------------------------------------------- /scripting/sv_steamgroup_fixer.sp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #pragma semicolon 1 4 | #pragma newdecls required 5 | 6 | ConVar g_hSteamGroupCvar; 7 | 8 | public void OnPluginStart() 9 | { 10 | g_hSteamGroupCvar = FindConVar("sv_steamgroup"); 11 | } 12 | 13 | public void OnConfigsExecuted() 14 | { 15 | char stringValue[128]; 16 | g_hSteamGroupCvar.GetString(stringValue, sizeof(stringValue)); 17 | 18 | int intValue = StringToInt(stringValue); 19 | 20 | LogMessage("Setting sv_steamgroup %d", intValue); 21 | 22 | g_hSteamGroupCvar.SetInt(intValue); 23 | } -------------------------------------------------------------------------------- /scripting/tickrate.sp: -------------------------------------------------------------------------------- 1 | /** 2 | * vim: set ts=4 : 3 | * ============================================================================= 4 | * Get Server Tickrate 5 | * Looks the server tickrate up. 6 | * 7 | * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. 8 | * ============================================================================= 9 | * 10 | * This program is free software; you can redistribute it and/or modify it under 11 | * the terms of the GNU General Public License, version 3.0, as published by the 12 | * Free Software Foundation. 13 | * 14 | * This program is distributed in the hope that it will be useful, but WITHOUT 15 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 16 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 17 | * details. 18 | * 19 | * You should have received a copy of the GNU General Public License along with 20 | * this program. If not, see . 21 | * 22 | * As a special exception, AlliedModders LLC gives you permission to link the 23 | * code of this program (as well as its derivative works) to "Half-Life 2," the 24 | * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software 25 | * by the Valve Corporation. You must obey the GNU General Public License in 26 | * all respects for all other code used. Additionally, AlliedModders LLC grants 27 | * this exception to all derivative works. AlliedModders LLC defines further 28 | * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), 29 | * or . 30 | * 31 | */ 32 | 33 | #pragma semicolon 1 34 | #include 35 | 36 | public Plugin:myinfo = 37 | { 38 | name = "Get TickRate", 39 | author = "Liam", 40 | description = "Looks up the current tickrate.", 41 | version = "1.0", 42 | url = "http://www.wcugaming.org" 43 | }; 44 | 45 | public OnPluginStart( ) 46 | { 47 | RegConsoleCmd("sm_gettickrate", Command_GetTickrate, "Gets the current tickrate from the server."); 48 | } 49 | 50 | public Action:Command_GetTickrate(client, args) 51 | { 52 | new Float:tickrate = 1.0 / GetTickInterval( ); 53 | 54 | ReplyToCommand(client, "The server tickrate is %d", RoundToZero(tickrate)); 55 | return Plugin_Handled; 56 | } -------------------------------------------------------------------------------- /scripting/wdnmd.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define VERSION "1.2" 5 | 6 | new String:giveorder[64]; 7 | new useridss; 8 | new Handle:hRoundRespawn; 9 | 10 | public Plugin:myinfo = 11 | { 12 | name = "Wdnmd", 13 | author = "Disappear9&HMBSbige", 14 | description = "白给插件", 15 | version = VERSION, 16 | url = "https://github.com/HMBSbige" 17 | }; 18 | 19 | public OnPluginStart() 20 | { 21 | RegAdminCmd("sm_wdnmd", WdnmdMenu, ADMFLAG_GENERIC, "Show menu"); 22 | CreateConVar("wdnmd_version", VERSION, "The version of Wdnmd", 270656); 23 | new Handle:hWdnmdCFG = LoadGameConfigFile("wdnmd_fix"); 24 | new Address:RFixAddr; 25 | if (hWdnmdCFG) 26 | { 27 | RFixAddr = GameConfGetAddress(hWdnmdCFG, "RYKnifeFix"); 28 | StartPrepSDKCall(SDKCall_Player); 29 | PrepSDKCall_SetFromConf(hWdnmdCFG, SDKFuncConfSource:1, "RoundRespawn"); 30 | hRoundRespawn = EndPrepSDKCall(); 31 | if (!hRoundRespawn) 32 | { 33 | SetFailState("复活指令无效"); 34 | } 35 | } 36 | if (RFixAddr) 37 | { 38 | if (LoadFromAddress(RFixAddr, NumberType_Int8) == 107 && LoadFromAddress(RFixAddr + view_as
(4), NumberType_Int8) == 101) 39 | { 40 | StoreToAddress(RFixAddr, 75, NumberType_Int8); 41 | StoreToAddress(RFixAddr + view_as
(4), 97, NumberType_Int8); 42 | } 43 | } 44 | CloseHandle(hWdnmdCFG); 45 | } 46 | 47 | public Action:WdnmdMenu(client, args) 48 | { 49 | if (GetUserFlagBits(client)) 50 | { 51 | Wdnmd(client); 52 | return Plugin_Handled; 53 | } 54 | ReplyToCommand(client, "[提示] 该功能只限管理员使用"); 55 | return Plugin_Handled; 56 | } 57 | 58 | public Action:Wdnmd(clientId) 59 | { 60 | new Handle:menu = CreateMenu(WdnmdMenuHandler, MenuAction:28); 61 | SetMenuTitle(menu, "白给插件"); 62 | AddMenuItem(menu, "option1", "手枪+近战", 0); 63 | AddMenuItem(menu, "option2", "微种+步枪", 0); 64 | AddMenuItem(menu, "option3", "霰弹+狙击", 0); 65 | AddMenuItem(menu, "option4", "药品+投掷", 0); 66 | AddMenuItem(menu, "option5", "其它", 0); 67 | AddMenuItem(menu, "option6", "升级附件+特殊", 0); 68 | AddMenuItem(menu, "option7", "重复上次操作", 0); 69 | AddMenuItem(menu, "option8", "服务器人数设置", 0); 70 | SetMenuExitButton(menu, true); 71 | DisplayMenu(menu, clientId, 0); 72 | return Plugin_Handled; 73 | } 74 | 75 | public WdnmdMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 76 | { 77 | if (action == MenuAction:4) 78 | { 79 | switch (itemNum) 80 | { 81 | case 0: 82 | { 83 | DisplaySMMenu(client); 84 | } 85 | case 1: 86 | { 87 | DisplaySRMenu(client); 88 | } 89 | case 2: 90 | { 91 | DisplaySSMenu(client); 92 | } 93 | case 3: 94 | { 95 | DisplayMTMenu(client); 96 | } 97 | case 4: 98 | { 99 | DisplayOTMenu(client); 100 | } 101 | case 5: 102 | { 103 | DisplayLUMenu(client); 104 | } 105 | case 6: 106 | { 107 | DisplayNLMenu(client); 108 | } 109 | case 7: 110 | { 111 | DisplaySLMenu(client); 112 | } 113 | default: 114 | { 115 | } 116 | } 117 | } 118 | return 0; 119 | } 120 | 121 | DisplaySMMenu(client) 122 | { 123 | new Handle:menu = CreateMenu(SMMenuHandler, MenuAction:28); 124 | SetMenuTitle(menu, "手枪+近战"); 125 | AddMenuItem(menu, "pistol", "小手枪", 0); 126 | AddMenuItem(menu, "pistol_magnum", "马格南", 0); 127 | AddMenuItem(menu, "fireaxe", "斧头", 0); 128 | AddMenuItem(menu, "machete", "砍刀", 0); 129 | AddMenuItem(menu, "katana", "日本刀", 0); 130 | AddMenuItem(menu, "pitchfork", "草叉", 0); 131 | AddMenuItem(menu, "shovel", "铁铲", 0); 132 | AddMenuItem(menu, "knife", "小刀", 0); 133 | AddMenuItem(menu, "baseball_bat", "棒球棍", 0); 134 | AddMenuItem(menu, "weapon_chainsaw", "电锯", 0); 135 | AddMenuItem(menu, "tonfa", "警棍", 0); 136 | SetMenuExitBackButton(menu, true); 137 | SetMenuExitButton(menu, true); 138 | DisplayMenu(menu, client, 0); 139 | return 0; 140 | } 141 | 142 | public SMMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 143 | { 144 | if (action == MenuAction:4) 145 | { 146 | new String:getitemname[64]; 147 | new style; 148 | GetMenuItem(menu, itemNum, getitemname, 64, style, "", 0); 149 | Format(giveorder, 64, "give %s", getitemname); 150 | DisplayNLMenu(client); 151 | } 152 | if (action == MenuAction_Cancel) 153 | { 154 | if (itemNum == MenuCancel_ExitBack) 155 | { 156 | Wdnmd(client); 157 | } 158 | } 159 | return 0; 160 | } 161 | 162 | DisplaySRMenu(client) 163 | { 164 | new Handle:menu = CreateMenu(SRMenuHandler, MenuAction:28); 165 | SetMenuTitle(menu, "微种+步枪"); 166 | AddMenuItem(menu, "smg", "UZI", 0); 167 | AddMenuItem(menu, "smg_silenced", "MAC", 0); 168 | AddMenuItem(menu, "weapon_smg_mp5", "MP5", 0); 169 | AddMenuItem(menu, "rifle_ak47", "AK47", 0); 170 | AddMenuItem(menu, "rifle", "M16", 0); 171 | AddMenuItem(menu, "rifle_desert", "SCAR", 0); 172 | AddMenuItem(menu, "weapon_rifle_sg552", "SG552", 0); 173 | AddMenuItem(menu, "weapon_grenade_launcher", "榴弹枪", 0); 174 | AddMenuItem(menu, "rifle_m60", "M60", 0); 175 | SetMenuExitBackButton(menu, true); 176 | SetMenuExitButton(menu, true); 177 | DisplayMenu(menu, client, 0); 178 | return 0; 179 | } 180 | 181 | public SRMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 182 | { 183 | if (action == MenuAction:4) 184 | { 185 | new String:getitemname[64]; 186 | new style; 187 | GetMenuItem(menu, itemNum, getitemname, 64, style, "", 0); 188 | Format(giveorder, 64, "give %s", getitemname); 189 | DisplayNLMenu(client); 190 | } 191 | if (action == MenuAction_Cancel) 192 | { 193 | if (itemNum == MenuCancel_ExitBack) 194 | { 195 | Wdnmd(client); 196 | } 197 | } 198 | return 0; 199 | } 200 | 201 | DisplaySSMenu(client) 202 | { 203 | new Handle:menu = CreateMenu(SSMenuHandler, MenuAction:28); 204 | SetMenuTitle(menu, "霰弹+狙击"); 205 | AddMenuItem(menu, "pumpshotgun", "M870", 0); 206 | AddMenuItem(menu, "shotgun_chrome", "Chrome", 0); 207 | AddMenuItem(menu, "autoshotgun", "M1014", 0); 208 | AddMenuItem(menu, "shotgun_spas", "SPAS", 0); 209 | AddMenuItem(menu, "hunting_rifle", "M14", 0); 210 | AddMenuItem(menu, "sniper_military", "G3SG1", 0); 211 | AddMenuItem(menu, "weapon_sniper_scout", "Scout", 0); 212 | AddMenuItem(menu, "weapon_sniper_awp", "AWP", 0); 213 | SetMenuExitBackButton(menu, true); 214 | SetMenuExitButton(menu, true); 215 | DisplayMenu(menu, client, 0); 216 | return 0; 217 | } 218 | 219 | public SSMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 220 | { 221 | if (action == MenuAction:4) 222 | { 223 | new String:getitemname[64]; 224 | new style; 225 | GetMenuItem(menu, itemNum, getitemname, 64, style, "", 0); 226 | Format(giveorder, 64, "give %s", getitemname); 227 | DisplayNLMenu(client); 228 | } 229 | if (action == MenuAction_Cancel) 230 | { 231 | if (itemNum == MenuCancel_ExitBack) 232 | { 233 | Wdnmd(client); 234 | } 235 | } 236 | return 0; 237 | } 238 | 239 | DisplayMTMenu(client) 240 | { 241 | new Handle:menu = CreateMenu(MTMenuHandler, MenuAction:28); 242 | SetMenuTitle(menu, "药品+投掷"); 243 | AddMenuItem(menu, "pain_pills", "药丸", 0); 244 | AddMenuItem(menu, "adrenaline", "肾上腺", 0); 245 | AddMenuItem(menu, "first_aid_kit", "医药包", 0); 246 | AddMenuItem(menu, "defibrillator", "电击器", 0); 247 | AddMenuItem(menu, "vomitjar", "胆汁", 0); 248 | AddMenuItem(menu, "pipe_bomb", "土制", 0); 249 | AddMenuItem(menu, "molotov", "燃烧瓶", 0); 250 | SetMenuExitBackButton(menu, true); 251 | SetMenuExitButton(menu, true); 252 | DisplayMenu(menu, client, 0); 253 | return 0; 254 | } 255 | 256 | public MTMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 257 | { 258 | if (action == MenuAction:4) 259 | { 260 | new String:getitemname[64]; 261 | new style; 262 | GetMenuItem(menu, itemNum, getitemname, 64, style, "", 0); 263 | Format(giveorder, 64, "give %s", getitemname); 264 | DisplayNLMenu(client); 265 | } 266 | if (action == MenuAction_Cancel) 267 | { 268 | if (itemNum == MenuCancel_ExitBack) 269 | { 270 | Wdnmd(client); 271 | } 272 | } 273 | return 0; 274 | } 275 | 276 | DisplayOTMenu(client) 277 | { 278 | new Handle:menu = CreateMenu(OTMenuHandler, MenuAction:28); 279 | SetMenuTitle(menu, "其它"); 280 | AddMenuItem(menu, "health", "生命", 0); 281 | AddMenuItem(menu, "ammo", "子弹", 0); 282 | AddMenuItem(menu, "weapon_upgradepack_incendiary", "燃烧弹盒", 0); 283 | AddMenuItem(menu, "weapon_upgradepack_explosive", "高爆弹盒", 0); 284 | AddMenuItem(menu, "gascan", "汽油桶", 0); 285 | AddMenuItem(menu, "propanetank", "煤气罐", 0); 286 | AddMenuItem(menu, "oxygentank", "氧气瓶", 0); 287 | AddMenuItem(menu, "weapon_fireworkcrate", "烟花", 0); 288 | AddMenuItem(menu, "weapon_gnome", "圣诞老人", 0); 289 | SetMenuExitBackButton(menu, true); 290 | SetMenuExitButton(menu, true); 291 | DisplayMenu(menu, client, 0); 292 | return 0; 293 | } 294 | 295 | public OTMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 296 | { 297 | if (action == MenuAction:4) 298 | { 299 | new String:getitemname[64]; 300 | new style; 301 | GetMenuItem(menu, itemNum, getitemname, 64, style, "", 0); 302 | Format(giveorder, 64, "give %s", getitemname); 303 | DisplayNLMenu(client); 304 | } 305 | if (action == MenuAction_Cancel) 306 | { 307 | if (itemNum == MenuCancel_ExitBack) 308 | { 309 | Wdnmd(client); 310 | } 311 | } 312 | return 0; 313 | } 314 | 315 | DisplayLUMenu(client) 316 | { 317 | new Handle:menu = CreateMenu(LUMenuHandler, MenuAction:28); 318 | SetMenuTitle(menu, "升级附件+特殊"); 319 | AddMenuItem(menu, "laser_sight", "红外线", 0); 320 | AddMenuItem(menu, "Incendiary_ammo", "燃烧子弹", 0); 321 | AddMenuItem(menu, "explosive_ammo", "高爆子弹", 0); 322 | AddMenuItem(menu, "respawns", "复活某人", 0); 323 | AddMenuItem(menu, "warp_all_survivors_heres", "传送", 0); 324 | AddMenuItem(menu, "slayinfected", "处死所有特感", 0); 325 | AddMenuItem(menu, "slayplayer", "处死所有玩家", 0); 326 | AddMenuItem(menu, "kickallbots", "踢除所有bot", 0); 327 | SetMenuExitBackButton(menu, true); 328 | SetMenuExitButton(menu, true); 329 | DisplayMenu(menu, client, 0); 330 | return 0; 331 | } 332 | 333 | public LUMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 334 | { 335 | if (action == MenuAction:4) 336 | { 337 | if (itemNum <= 2) 338 | { 339 | new String:getitemname[64]; 340 | new style; 341 | GetMenuItem(menu, itemNum, getitemname, 64, style, "", 0); 342 | Format(giveorder, 64, "upgrade_add %s", getitemname); 343 | DisplayNLMenu(client); 344 | } 345 | switch (itemNum) 346 | { 347 | case 3: 348 | { 349 | DisplayRPMenu(client); 350 | } 351 | case 4: 352 | { 353 | DisplayTEMenu(client); 354 | } 355 | case 5: 356 | { 357 | new ix = 1; 358 | while (ix <= MaxClients) 359 | { 360 | if (IsClientInGame(ix) && GetClientTeam(ix) != 2) 361 | { 362 | ForcePlayerSuicide(ix); 363 | } 364 | ix++; 365 | } 366 | } 367 | case 6: 368 | { 369 | new ix = 1; 370 | while (ix <= MaxClients) 371 | { 372 | if (IsClientInGame(ix) && GetClientTeam(ix) == 2 && IsPlayerAlive(ix)) 373 | { 374 | ForcePlayerSuicide(ix); 375 | } 376 | ix++; 377 | } 378 | } 379 | case 7: 380 | { 381 | new ix = 1; 382 | while (ix <= MaxClients) 383 | { 384 | if (IsClientInGame(ix) && GetClientTeam(ix) == 2 && IsFakeClient(ix)) 385 | { 386 | KickClient(ix, ""); 387 | } 388 | ix++; 389 | } 390 | PrintToChatAll("\x03[提示] \x01踢除所有bot."); 391 | } 392 | default: 393 | { 394 | } 395 | } 396 | } 397 | if (action == MenuAction_Cancel) 398 | { 399 | if (itemNum == MenuCancel_ExitBack) 400 | { 401 | Wdnmd(client); 402 | } 403 | } 404 | return 0; 405 | } 406 | 407 | DisplayNLMenu(client) 408 | { 409 | new String:namelist[64]; 410 | new String:nameno[4]; 411 | new nameall; 412 | new String:nallno[32]; 413 | new Handle:menu = CreateMenu(NLMenuHandler, MenuAction:28); 414 | SetMenuTitle(menu, "人物列表"); 415 | new i = 1; 416 | while (i <= MaxClients) 417 | { 418 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) 419 | { 420 | nameall += 1; 421 | } 422 | i++; 423 | } 424 | Format(nallno, 20, "所有 %i 人", nameall); 425 | new String:everybody[8]; 426 | new everno = 199; 427 | Format(everybody, 6, "%i", everno); 428 | AddMenuItem(menu, everybody, nallno, 0); 429 | i = 1; 430 | while (i <= MaxClients) 431 | { 432 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) 433 | { 434 | GetClientName(i, namelist, 64); 435 | Format(namelist, 64, "%s .(%d)", namelist, i); 436 | Format(nameno, 3, "%i", i); 437 | AddMenuItem(menu, nameno, namelist, 0); 438 | } 439 | i++; 440 | } 441 | SetMenuExitButton(menu, true); 442 | DisplayMenu(menu, client, 0); 443 | return 0; 444 | } 445 | 446 | public NLMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 447 | { 448 | if (action == MenuAction:4) 449 | { 450 | new flagsgv = GetCommandFlags("give"); 451 | SetCommandFlags("give", flagsgv & -16385); 452 | new flagsup = GetCommandFlags("upgrade_add"); 453 | SetCommandFlags("upgrade_add", flagsup & -16385); 454 | new String:clientinfos[12]; 455 | new userids; 456 | new style; 457 | GetMenuItem(menu, itemNum, clientinfos, 10, style, "", 0); 458 | userids = StringToInt(clientinfos, 10); 459 | if (userids == 199) 460 | { 461 | new ix = 1; 462 | while (ix <= MaxClients) 463 | { 464 | if (IsClientInGame(ix) && GetClientTeam(ix) == 2 && IsPlayerAlive(ix)) 465 | { 466 | FakeClientCommand(ix, giveorder); 467 | } 468 | ix++; 469 | } 470 | } 471 | else 472 | { 473 | FakeClientCommand(userids, giveorder); 474 | } 475 | SetCommandFlags("give", flagsgv | 16384); 476 | SetCommandFlags("upgrade_add", flagsup | 16384); 477 | } 478 | return 0; 479 | } 480 | 481 | DisplayRPMenu(client) 482 | { 483 | new String:namelist[64]; 484 | new String:nameno[4]; 485 | new nameall; 486 | new String:nallno[32]; 487 | new Handle:menu = CreateMenu(RPMenuHandler, MenuAction:28); 488 | SetMenuTitle(menu, "复活列表"); 489 | new i = 1; 490 | while (i <= MaxClients) 491 | { 492 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && !IsPlayerAlive(i)) 493 | { 494 | nameall += 1; 495 | } 496 | i++; 497 | } 498 | Format(nallno, 16, "所有 %i 死人", nameall); 499 | new String:everybody[8]; 500 | new everno = 199; 501 | Format(everybody, 6, "%i", everno); 502 | AddMenuItem(menu, everybody, nallno, 0); 503 | i = 1; 504 | while (i <= MaxClients) 505 | { 506 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && !IsPlayerAlive(i)) 507 | { 508 | GetClientName(i, namelist, 64); 509 | Format(namelist, 64, "%s .(%d)", namelist, i); 510 | Format(nameno, 3, "%i", i); 511 | AddMenuItem(menu, nameno, namelist, 0); 512 | } 513 | i++; 514 | } 515 | SetMenuExitButton(menu, true); 516 | DisplayMenu(menu, client, 0); 517 | return 0; 518 | } 519 | 520 | public RPMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 521 | { 522 | if (action == MenuAction:4) 523 | { 524 | new String:clientinfos[12]; 525 | new userids; 526 | new style; 527 | GetMenuItem(menu, itemNum, clientinfos, 10, style, "", 0); 528 | userids = StringToInt(clientinfos, 10); 529 | decl Float:vAngles1[3]; 530 | decl Float:vOrigin1[3]; 531 | new i = 1; 532 | while (i <= MaxClients) 533 | { 534 | if (IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && !IsFakeClient(i)) 535 | { 536 | GetClientAbsOrigin(i, vOrigin1); 537 | GetClientAbsAngles(i, vAngles1); 538 | if (userids == 199) 539 | { 540 | new ix = 1; 541 | while (ix <= MaxClients) 542 | { 543 | if (IsClientInGame(ix) && GetClientTeam(ix) == 2 && !IsPlayerAlive(ix)) 544 | { 545 | SDKCall(hRoundRespawn, ix); 546 | TeleportEntity(ix, vOrigin1, vAngles1, NULL_VECTOR); 547 | } 548 | ix++; 549 | } 550 | } 551 | else 552 | { 553 | SDKCall(hRoundRespawn, userids); 554 | TeleportEntity(userids, vOrigin1, vAngles1, NULL_VECTOR); 555 | } 556 | } 557 | i++; 558 | } 559 | if (userids == 199) 560 | { 561 | new ix = 1; 562 | while (ix <= MaxClients) 563 | { 564 | if (IsClientInGame(ix) && GetClientTeam(ix) == 2 && !IsPlayerAlive(ix)) 565 | { 566 | SDKCall(hRoundRespawn, ix); 567 | TeleportEntity(ix, vOrigin1, vAngles1, NULL_VECTOR); 568 | } 569 | ix++; 570 | } 571 | } 572 | else 573 | { 574 | SDKCall(hRoundRespawn, userids); 575 | TeleportEntity(userids, vOrigin1, vAngles1, NULL_VECTOR); 576 | } 577 | } 578 | return 0; 579 | } 580 | 581 | DisplayTEMenu(client) 582 | { 583 | new String:namelist[64]; 584 | new String:nameno[4]; 585 | new nameall; 586 | new String:nallno[32]; 587 | new Handle:menu = CreateMenu(TEMenuHandler, MenuAction:28); 588 | SetMenuTitle(menu, "传送谁"); 589 | new i = 1; 590 | while (i <= MaxClients) 591 | { 592 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) 593 | { 594 | nameall += 1; 595 | } 596 | i++; 597 | } 598 | Format(nallno, 16, "所有 %i 人", nameall); 599 | new String:everybody[8]; 600 | new everno = 199; 601 | Format(everybody, 6, "%i", everno); 602 | AddMenuItem(menu, everybody, nallno, 0); 603 | i = 1; 604 | while (i <= MaxClients) 605 | { 606 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) 607 | { 608 | GetClientName(i, namelist, 64); 609 | Format(namelist, 64, "%s .(%d)", namelist, i); 610 | Format(nameno, 3, "%i", i); 611 | AddMenuItem(menu, nameno, namelist, 0); 612 | } 613 | i++; 614 | } 615 | SetMenuExitButton(menu, true); 616 | DisplayMenu(menu, client, 0); 617 | return 0; 618 | } 619 | 620 | public TEMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 621 | { 622 | if (action == MenuAction:4) 623 | { 624 | new String:clientinfos[12]; 625 | new style; 626 | GetMenuItem(menu, itemNum, clientinfos, 10, style, "", 0); 627 | useridss = StringToInt(clientinfos, 10); 628 | DisplayTELMenu(client); 629 | } 630 | return 0; 631 | } 632 | 633 | DisplayTELMenu(client) 634 | { 635 | new String:namelist[64]; 636 | new String:nameno[4]; 637 | new Handle:menu = CreateMenu(TELMenuHandler, MenuAction:28); 638 | SetMenuTitle(menu, "传送到谁那里"); 639 | new i = 1; 640 | while (i <= MaxClients) 641 | { 642 | if (IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && i != useridss) 643 | { 644 | GetClientName(i, namelist, 64); 645 | Format(namelist, 64, "%s .(%d)", namelist, i); 646 | Format(nameno, 3, "%i", i); 647 | AddMenuItem(menu, nameno, namelist, 0); 648 | } 649 | i++; 650 | } 651 | SetMenuExitButton(menu, true); 652 | DisplayMenu(menu, client, 0); 653 | return 0; 654 | } 655 | 656 | public TELMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 657 | { 658 | if (action == MenuAction:4) 659 | { 660 | new String:clientinfos[12]; 661 | new userids; 662 | new style; 663 | GetMenuItem(menu, itemNum, clientinfos, 10, style, "", 0); 664 | userids = StringToInt(clientinfos, 10); 665 | decl Float:vAngles[3]; 666 | decl Float:vOrigin[3]; 667 | GetClientAbsOrigin(userids, vOrigin); 668 | GetClientAbsAngles(userids, vAngles); 669 | if (useridss == 199) 670 | { 671 | new ix = 1; 672 | while (ix <= MaxClients) 673 | { 674 | if (IsClientInGame(ix) && GetClientTeam(ix) == 2 && IsPlayerAlive(ix) && ix != userids) 675 | { 676 | TeleportEntity(ix, vOrigin, vAngles, NULL_VECTOR); 677 | } 678 | ix++; 679 | } 680 | } 681 | else 682 | { 683 | TeleportEntity(useridss, vOrigin, vAngles, NULL_VECTOR); 684 | } 685 | } 686 | return 0; 687 | } 688 | 689 | DisplaySLMenu(client) 690 | { 691 | new String:namelist[64]; 692 | new String:nameno[4]; 693 | new Handle:menu = CreateMenu(SLMenuHandler, MenuAction:28); 694 | SetMenuTitle(menu, "服务器人数"); 695 | new i = 1; 696 | while (i <= 16) 697 | { 698 | Format(namelist, 64, "%d 人", i); 699 | Format(nameno, 3, "%i", i); 700 | AddMenuItem(menu, nameno, namelist, 0); 701 | i++; 702 | } 703 | SetMenuExitButton(menu, true); 704 | DisplayMenu(menu, client, 0); 705 | return 0; 706 | } 707 | 708 | public SLMenuHandler(Handle:menu, MenuAction:action, client, itemNum) 709 | { 710 | if (action == MenuAction:4) 711 | { 712 | new String:clientinfos[12]; 713 | new userids; 714 | new style; 715 | GetMenuItem(menu, itemNum, clientinfos, 10, style, "", 0); 716 | userids = StringToInt(clientinfos, 10); 717 | FakeClientCommand(client, "sm_cvar sv_maxplayers %i", userids); 718 | FakeClientCommand(client, "sm_cvar sv_visiblemaxplayers %i", userids); 719 | } 720 | return 0; 721 | } 722 | -------------------------------------------------------------------------------- /translations/chi/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "chi" "拿" 6 | } 7 | "Grabbed" 8 | { 9 | "chi" "取得" 10 | } 11 | "Switched" 12 | { 13 | "chi" "更换" 14 | } 15 | "From" 16 | { 17 | "chi" "来自" 18 | } 19 | "To" 20 | { 21 | "chi" "给" 22 | } 23 | "With" 24 | { 25 | "chi" "给" 26 | } 27 | "weapon_molotov" 28 | { 29 | "chi" "燃烧瓶" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "chi" "土质炸弹" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "chi" "胆汁" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "chi" "急救包" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "chi" "止痛药" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "chi" "肾上腺素" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "chi" "高爆弹药包" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "chi" "燃烧弹药包" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "chi" "电击器" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/da/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "da" "gav" 6 | } 7 | "Grabbed" 8 | { 9 | "da" "tog" 10 | } 11 | "Switched" 12 | { 13 | "da" "skiftede" 14 | } 15 | "From" 16 | { 17 | "da" "fra" 18 | } 19 | "To" 20 | { 21 | "da" "til" 22 | } 23 | "With" 24 | { 25 | "da" "med" 26 | } 27 | "weapon_molotov" 28 | { 29 | "da" "en molotov cocktail" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "da" "en rørbombe" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "da" "et brækglas" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "da" "et førstehjælps sæt" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "da" "smertestillende piller" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "da" "adrenalin" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "da" "explosivt ammunition" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "da" "brændbar ammunition" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "da" "en hjertestarter" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/de/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "de" "gibt" 6 | } 7 | "Grabbed" 8 | { 9 | "de" "nimmt" 10 | } 11 | "Switched" 12 | { 13 | "de" "wechselt" 14 | } 15 | "From" 16 | { 17 | "de" "von" 18 | } 19 | "To" 20 | { 21 | "de" "an" 22 | } 23 | "With" 24 | { 25 | "de" "mit" 26 | } 27 | "weapon_molotov" 28 | { 29 | "de" "ein Molotowcocktail" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "de" "eine Rohrbombe" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "de" "einen Behälter mit Galle" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "de" "das Verbandszeug" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "de" "Schmerzmittel" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "de" "Adrenalin" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "de" "Explosivmunition" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "de" "Brandmunition" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "de" "ein Defibrillator" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/es/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "es" "dió" 6 | } 7 | "Grabbed" 8 | { 9 | "es" "cogió" 10 | } 11 | "Switched" 12 | { 13 | "es" "cambió" 14 | } 15 | "From" 16 | { 17 | "es" "de" 18 | } 19 | "To" 20 | { 21 | "es" "a" 22 | } 23 | "With" 24 | { 25 | "es" "con" 26 | } 27 | "weapon_molotov" 28 | { 29 | "es" "un molotov" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "es" "una bomba" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "es" "vómito" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "es" "un kit médico" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "es" "pastillas" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "es" "adrenalina" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "es" "munición explosiva" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "es" "munición incendiaria" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "es" "un desfibrilador" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "en" "gave" 6 | } 7 | "Grabbed" 8 | { 9 | "en" "grabbed" 10 | } 11 | "Switched" 12 | { 13 | "en" "switched" 14 | } 15 | "From" 16 | { 17 | "en" "from" 18 | } 19 | "To" 20 | { 21 | "en" "to" 22 | } 23 | "With" 24 | { 25 | "en" "with" 26 | } 27 | "weapon_molotov" 28 | { 29 | "en" "a molotov" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "en" "a pipebomb" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "en" "a vomitjar" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "en" "a medkit" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "en" "pain pills" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "en" "adrenaline" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "en" "explosive ammo" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "en" "incendiary ammo" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "en" "a defibrillator" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/pt/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "pt" "deu" 6 | } 7 | "Grabbed" 8 | { 9 | "pt" "levou" 10 | } 11 | "Switched" 12 | { 13 | "pt" "trocou" 14 | } 15 | "From" 16 | { 17 | "pt" "de" 18 | } 19 | "To" 20 | { 21 | "pt" "para" 22 | } 23 | "With" 24 | { 25 | "pt" "com" 26 | } 27 | "weapon_molotov" 28 | { 29 | "pt" "um molotov" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "pt" "um pipebomb" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "pt" "um vomitjar" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "pt" "um medkit" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "pt" "pain pills" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "pt" "adrenaline" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "pt" "explosive ammo" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "pt" "incendiary ammo" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "pt" "um defibrillator" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/ru/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "ru" "отдал" 6 | } 7 | "Grabbed" 8 | { 9 | "ru" "получил" 10 | } 11 | "Switched" 12 | { 13 | "ru" "обменял" 14 | } 15 | "From" 16 | { 17 | "ru" "от" 18 | } 19 | "To" 20 | { 21 | "ru" "" 22 | } 23 | "With" 24 | { 25 | "ru" "у" 26 | } 27 | "weapon_molotov" 28 | { 29 | "ru" "молотов" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "ru" "бомбу" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "ru" "желчь толстяка" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "ru" "аптечку" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "ru" "таблетки" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "ru" "адреналин" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "ru" "разрывные патроны" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "ru" "зажигательные патроны" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "ru" "дефибриллятор" 62 | } 63 | } -------------------------------------------------------------------------------- /translations/zho/gear_transfer.phrases.txt: -------------------------------------------------------------------------------- 1 | "Phrases" 2 | { 3 | "Gave" 4 | { 5 | "zho" "拿" 6 | } 7 | "Grabbed" 8 | { 9 | "zho" "取得" 10 | } 11 | "Switched" 12 | { 13 | "zho" "更換" 14 | } 15 | "From" 16 | { 17 | "zho" "來自" 18 | } 19 | "To" 20 | { 21 | "zho" "給" 22 | } 23 | "With" 24 | { 25 | "zho" "給" 26 | } 27 | "weapon_molotov" 28 | { 29 | "zho" "汽油彈" 30 | } 31 | "weapon_pipe_bomb" 32 | { 33 | "zho" "鐵管炸彈" 34 | } 35 | "weapon_vomitjar" 36 | { 37 | "zho" "膽汁罐" 38 | } 39 | "weapon_first_aid_kit" 40 | { 41 | "zho" "急救包" 42 | } 43 | "weapon_pain_pills" 44 | { 45 | "zho" "止痛藥" 46 | } 47 | "weapon_adrenaline" 48 | { 49 | "zho" "腎上腺素" 50 | } 51 | "weapon_upgradepack_explosive" 52 | { 53 | "zho" "高爆彈藥包" 54 | } 55 | "weapon_upgradepack_incendiary" 56 | { 57 | "zho" "燃燒彈藥包" 58 | } 59 | "weapon_defibrillator" 60 | { 61 | "zho" "電擊器" 62 | } 63 | } --------------------------------------------------------------------------------