|
| 1 | +#pragma semicolon 1 |
| 2 | +#pragma newdecls required |
| 3 | +#include <sourcemod> |
| 4 | +#include <sdktools> |
| 5 | + |
| 6 | +#define VERSION "3.1.0" |
| 7 | + |
| 8 | +ArrayList |
| 9 | + g_aMeleeScripts; |
| 10 | + |
| 11 | +ConVar |
| 12 | + g_hEnabled, |
| 13 | + g_hSpawnType, |
| 14 | + g_hRandomAmount, |
| 15 | + g_hMapBaseAmount, |
| 16 | + g_hMeleeItems[14]; |
| 17 | + |
| 18 | +int |
| 19 | + g_iRoundStart, |
| 20 | + g_iPlayerSpawn; |
| 21 | + |
| 22 | +static const char |
| 23 | + g_sMeleeModels[][] = |
| 24 | + { |
| 25 | + "models/weapons/melee/v_fireaxe.mdl", |
| 26 | + "models/weapons/melee/w_fireaxe.mdl", |
| 27 | + "models/weapons/melee/v_frying_pan.mdl", |
| 28 | + "models/weapons/melee/w_frying_pan.mdl", |
| 29 | + "models/weapons/melee/v_machete.mdl", |
| 30 | + "models/weapons/melee/w_machete.mdl", |
| 31 | + "models/weapons/melee/v_bat.mdl", |
| 32 | + "models/weapons/melee/w_bat.mdl", |
| 33 | + "models/weapons/melee/v_crowbar.mdl", |
| 34 | + "models/weapons/melee/w_crowbar.mdl", |
| 35 | + "models/weapons/melee/v_cricket_bat.mdl", |
| 36 | + "models/weapons/melee/w_cricket_bat.mdl", |
| 37 | + "models/weapons/melee/v_tonfa.mdl", |
| 38 | + "models/weapons/melee/w_tonfa.mdl", |
| 39 | + "models/weapons/melee/v_katana.mdl", |
| 40 | + "models/weapons/melee/w_katana.mdl", |
| 41 | + "models/weapons/melee/v_electric_guitar.mdl", |
| 42 | + "models/weapons/melee/w_electric_guitar.mdl", |
| 43 | + "models/v_models/v_knife_t.mdl", |
| 44 | + "models/w_models/weapons/w_knife_t.mdl", |
| 45 | + "models/weapons/melee/v_golfclub.mdl", |
| 46 | + "models/weapons/melee/w_golfclub.mdl", |
| 47 | + "models/weapons/melee/v_shovel.mdl", |
| 48 | + "models/weapons/melee/w_shovel.mdl", |
| 49 | + "models/weapons/melee/v_pitchfork.mdl", |
| 50 | + "models/weapons/melee/w_pitchfork.mdl", |
| 51 | + "models/weapons/melee/v_riotshield.mdl", |
| 52 | + "models/weapons/melee/w_riotshield.mdl" |
| 53 | + }, |
| 54 | + g_sMeleeName[][] = |
| 55 | + { |
| 56 | + "fireaxe", //斧头 |
| 57 | + "frying_pan", //平底锅 |
| 58 | + "machete", //砍刀 |
| 59 | + "baseball_bat", //棒球棒 |
| 60 | + "crowbar", //撬棍 |
| 61 | + "cricket_bat", //球拍 |
| 62 | + "tonfa", //警棍 |
| 63 | + "katana", //武士刀 |
| 64 | + "electric_guitar", //吉他 |
| 65 | + "knife", //小刀 |
| 66 | + "golfclub", //高尔夫球棍 |
| 67 | + "shovel", //铁铲 |
| 68 | + "pitchfork", //草叉 |
| 69 | + "riotshield", //盾牌 |
| 70 | + }; |
| 71 | + |
| 72 | +public Plugin myinfo = |
| 73 | +{ |
| 74 | + name = "Melee In The Saferoom", |
| 75 | + author = "$atanic $pirit, N3wton", |
| 76 | + description = "Spawns a selection of melee weapons in the saferoom, at the start of each round.", |
| 77 | + version = VERSION |
| 78 | +}; |
| 79 | + |
| 80 | +public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) |
| 81 | +{ |
| 82 | + if(GetEngineVersion() != Engine_Left4Dead2) |
| 83 | + { |
| 84 | + strcopy(error, err_max, "Melee in the Saferoom only supports Left 4 Dead 2."); |
| 85 | + return APLRes_SilentFailure; |
| 86 | + } |
| 87 | + return APLRes_Success; |
| 88 | +} |
| 89 | + |
| 90 | +public void OnPluginStart() |
| 91 | +{ |
| 92 | + g_aMeleeScripts = new ArrayList(64); |
| 93 | + |
| 94 | + CreateConVar("l4d2_mitsr_version", VERSION, "The version of Melee In The Saferoom"); |
| 95 | + g_hEnabled = CreateConVar("l4d2_mitsr_enabled", "1", "Should the plugin be enabled", _, true, 0.0, true, 1.0); |
| 96 | + g_hSpawnType = CreateConVar("l4d2_mitsr_spawn_type", "0", "0 = Custom list, 1 = Random Weapon and 2 = Map based weapons.", _, true, 0.0, true, 2.0); |
| 97 | + g_hRandomAmount = CreateConVar("l4d2_mitsr_random_amount", "4","Number of weapons to spawn if l4d2_mitsr_spawn_type is set to 1.", _, true, 0.0, true, 32.0); |
| 98 | + g_hMapBaseAmount = CreateConVar("l4d2_mitsr_mapbase_amount", "4", "Number multiple if l4d2_mitsr_spawn_type is set to 2.", _, true, 0.0, true, 32.0); |
| 99 | + |
| 100 | + g_hMeleeItems[0] = CreateConVar("l4d2_mitsr_fireaxe", "1", "Number of fireaxes to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 101 | + g_hMeleeItems[1] = CreateConVar("l4d2_mitsr_fryingpan", "0", "Number of frying pans to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 102 | + g_hMeleeItems[2] = CreateConVar("l4d2_mitsr_machete", "0", "Number of machetes to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 103 | + g_hMeleeItems[3] = CreateConVar("l4d2_mitsr_baseballbat", "0", "Number of baseball bats to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 104 | + g_hMeleeItems[4] = CreateConVar("l4d2_mitsr_crowbar", "0", "Number of crowbars to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 105 | + g_hMeleeItems[5] = CreateConVar("l4d2_mitsr_cricketbat", "0", "Number of cricket bats to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 106 | + g_hMeleeItems[6] = CreateConVar("l4d2_mitsr_tonfa", "1", "Number of tonfas to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 107 | + g_hMeleeItems[7] = CreateConVar("l4d2_mitsr_katana", "0", "Number of katanas to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 108 | + g_hMeleeItems[8] = CreateConVar("l4d2_mitsr_elecguitar", "0", "Number of electric guitars to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 109 | + g_hMeleeItems[9] = CreateConVar("l4d2_mitsr_knife", "0", "Number of knifes to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 110 | + g_hMeleeItems[10] = CreateConVar("l4d2_mitsr_golfclub", "0", "Number of golf clubs to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 111 | + g_hMeleeItems[11] = CreateConVar("l4d2_mitsr_shovel", "0", "Number of shovels to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 112 | + g_hMeleeItems[12] = CreateConVar("l4d2_mitsr_pitchfork", "0", "Number of pitchforks to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 113 | + g_hMeleeItems[13] = CreateConVar("l4d2_mitsr_riotshield", "0", "Number of tonfas to spawn (l4d2_mitsr_spawn_type must be 0)", _, true, 0.0, true, 10.0); |
| 114 | + |
| 115 | + //AutoExecConfig(true, "l4d2_melee_in_the_saferoom"); |
| 116 | + |
| 117 | + HookEvent("round_end", Event_RoundEnd, EventHookMode_PostNoCopy); |
| 118 | + HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy); |
| 119 | + HookEvent("player_spawn", Event_PlayerSpawn, EventHookMode_PostNoCopy); |
| 120 | + |
| 121 | + RegAdminCmd("sm_melee", cmdMelee, ADMFLAG_KICK, "Lists all melee weapons spawnable in current campaign"); |
| 122 | +} |
| 123 | + |
| 124 | +Action cmdMelee(int client, int args) |
| 125 | +{ |
| 126 | + if(g_iRoundStart == 0 || g_iPlayerSpawn == 0) |
| 127 | + ReplyToCommand(client, "地图尚未开始"); |
| 128 | + else |
| 129 | + { |
| 130 | + ReplyToCommand(client, "当前地图已解锁近战:"); |
| 131 | + |
| 132 | + char sScriptName[64]; |
| 133 | + int iLength = g_aMeleeScripts.Length; |
| 134 | + for(int i; i < iLength; i++) |
| 135 | + { |
| 136 | + g_aMeleeScripts.GetString(i, sScriptName, sizeof sScriptName); |
| 137 | + ReplyToCommand(client, "%d : %s", i, sScriptName); |
| 138 | + } |
| 139 | + } |
| 140 | + |
| 141 | + return Plugin_Handled; |
| 142 | +} |
| 143 | + |
| 144 | +public void OnMapStart() |
| 145 | +{ |
| 146 | + int i; |
| 147 | + int iLength = sizeof g_sMeleeModels; |
| 148 | + for(; i < iLength; i++) |
| 149 | + { |
| 150 | + if(!IsModelPrecached(g_sMeleeModels[i])) |
| 151 | + PrecacheModel(g_sMeleeModels[i], true); |
| 152 | + } |
| 153 | + |
| 154 | + iLength = sizeof g_sMeleeName; |
| 155 | + char sBuffer[64]; |
| 156 | + for(i = 0; i < iLength; i++) |
| 157 | + { |
| 158 | + FormatEx(sBuffer, sizeof sBuffer, "scripts/melee/%s.txt", g_sMeleeName[i]); |
| 159 | + if(!IsGenericPrecached(sBuffer)) |
| 160 | + PrecacheGeneric(sBuffer, true); |
| 161 | + } |
| 162 | + |
| 163 | + vGetMeleeWeaponsStringTable(); |
| 164 | +} |
| 165 | + |
| 166 | +void vGetMeleeWeaponsStringTable() |
| 167 | +{ |
| 168 | + g_aMeleeScripts.Clear(); |
| 169 | + |
| 170 | + int iTable = FindStringTable("meleeweapons"); |
| 171 | + if(iTable != INVALID_STRING_TABLE) |
| 172 | + { |
| 173 | + int iNum = GetStringTableNumStrings(iTable); |
| 174 | + char sMeleeName[64]; |
| 175 | + for(int i; i < iNum; i++) |
| 176 | + { |
| 177 | + ReadStringTable(iTable, i, sMeleeName, sizeof sMeleeName); |
| 178 | + g_aMeleeScripts.PushString(sMeleeName); |
| 179 | + } |
| 180 | + } |
| 181 | +} |
| 182 | + |
| 183 | +public void OnMapEnd() |
| 184 | +{ |
| 185 | + g_iRoundStart = 0; |
| 186 | + g_iPlayerSpawn = 0; |
| 187 | +} |
| 188 | + |
| 189 | +void Event_RoundEnd(Event event, const char[] name, bool dontBroadcast) |
| 190 | +{ |
| 191 | + OnMapEnd(); |
| 192 | +} |
| 193 | + |
| 194 | +void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) |
| 195 | +{ |
| 196 | + if(g_iRoundStart == 1 && g_iPlayerSpawn == 0) |
| 197 | + CreateTimer(1.0, tmrStartSpawnMelee, _, TIMER_FLAG_NO_MAPCHANGE); |
| 198 | + g_iPlayerSpawn = 1; |
| 199 | +} |
| 200 | + |
| 201 | +void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) |
| 202 | +{ |
| 203 | + if(g_iRoundStart == 0 && g_iPlayerSpawn == 1) |
| 204 | + CreateTimer(1.0, tmrStartSpawnMelee, _, TIMER_FLAG_NO_MAPCHANGE); |
| 205 | + g_iRoundStart = 1; |
| 206 | +} |
| 207 | + |
| 208 | +Action tmrStartSpawnMelee(Handle timer) |
| 209 | +{ |
| 210 | + vStartSpawnMelee(); |
| 211 | + return Plugin_Continue; |
| 212 | +} |
| 213 | + |
| 214 | +void vStartSpawnMelee() |
| 215 | +{ |
| 216 | + if(!g_hEnabled.BoolValue) |
| 217 | + return; |
| 218 | + |
| 219 | + int client = ivGetInGameClient(); |
| 220 | + if(!client) |
| 221 | + return; |
| 222 | + |
| 223 | + int iLimit; |
| 224 | + float vOrigin[3]; |
| 225 | + float vAngles[3]; |
| 226 | + GetClientAbsOrigin(client, vOrigin); |
| 227 | + |
| 228 | + vOrigin[2] += 20.0; |
| 229 | + vAngles[0] = 90.0; |
| 230 | + |
| 231 | + int iLength = g_aMeleeScripts.Length; |
| 232 | + if(g_hSpawnType.IntValue == 1) |
| 233 | + { |
| 234 | + static ArrayList aRandomMelee; |
| 235 | + |
| 236 | + if(bIsGameInFirstHalf()) |
| 237 | + { |
| 238 | + if(aRandomMelee != null) |
| 239 | + delete aRandomMelee; |
| 240 | + |
| 241 | + aRandomMelee = g_aMeleeScripts.Clone(); |
| 242 | + aRandomMelee.Sort(Sort_Random, Sort_String); |
| 243 | + } |
| 244 | + |
| 245 | + char sScriptName[64]; |
| 246 | + iLimit = g_hRandomAmount.IntValue; |
| 247 | + for(int i; i < iLimit; i++) |
| 248 | + { |
| 249 | + aRandomMelee.GetString(i < iLength ? i : GetRandomInt(0, iLength - 1), sScriptName, sizeof sScriptName); |
| 250 | + vSpawnMelee(sScriptName, vOrigin, vAngles); |
| 251 | + } |
| 252 | + } |
| 253 | + else if(g_hSpawnType.IntValue == 2) |
| 254 | + { |
| 255 | + char sScriptName[64]; |
| 256 | + iLimit = g_hMapBaseAmount.IntValue; |
| 257 | + for(int i; i < iLimit; i++) |
| 258 | + { |
| 259 | + g_aMeleeScripts.GetString(i < iLength ? i : i - (RoundToFloor(float(i / iLength)) * iLength), sScriptName, sizeof sScriptName); |
| 260 | + vSpawnMelee(sScriptName, vOrigin, vAngles); |
| 261 | + } |
| 262 | + } |
| 263 | + else |
| 264 | + vSpawnCustomList(vOrigin, vAngles); |
| 265 | +} |
| 266 | + |
| 267 | +void vSpawnMelee(const char[] sClass, const float vPos[3], const float vAng[3]) |
| 268 | +{ |
| 269 | + float vOrigin[3]; |
| 270 | + float vAngles[3]; |
| 271 | + vOrigin = vPos; |
| 272 | + vAngles = vAng; |
| 273 | + |
| 274 | + vOrigin[0] += (-10.0 + GetRandomFloat(0.0, 20.0)); |
| 275 | + vOrigin[1] += (-10.0 + GetRandomFloat(0.0, 20.0)); |
| 276 | + vOrigin[2] += GetRandomFloat(0.0, 10.0); |
| 277 | + vAngles[1] = GetRandomFloat(0.0, 360.0); |
| 278 | + |
| 279 | + int entity = CreateEntityByName("weapon_melee"); |
| 280 | + DispatchKeyValue(entity, "solid", "6"); |
| 281 | + DispatchKeyValue(entity, "melee_script_name", sClass); |
| 282 | + DispatchSpawn(entity); |
| 283 | + TeleportEntity(entity, vOrigin, vAngles, NULL_VECTOR); |
| 284 | + |
| 285 | + //SetEntityMoveType(entity, MOVETYPE_NONE); |
| 286 | +} |
| 287 | + |
| 288 | +void vSpawnCustomList(const float vPos[3], const float vAng[3]) |
| 289 | +{ |
| 290 | + char sScriptName[64]; |
| 291 | + int iLength = sizeof g_hMeleeItems; |
| 292 | + for(int x; x < iLength; x++) |
| 293 | + { |
| 294 | + for(int i; i < g_hMeleeItems[x].IntValue; i++) |
| 295 | + { |
| 296 | + if(g_aMeleeScripts.FindString(g_sMeleeName[x]) != -1) |
| 297 | + strcopy(sScriptName, sizeof sScriptName, g_sMeleeName[x]); |
| 298 | + else |
| 299 | + g_aMeleeScripts.GetString(GetRandomInt(0, g_aMeleeScripts.Length - 1), sScriptName, sizeof sScriptName); |
| 300 | + |
| 301 | + vSpawnMelee(sScriptName, vPos, vAng); |
| 302 | + } |
| 303 | + } |
| 304 | +} |
| 305 | + |
| 306 | +int ivGetInGameClient() |
| 307 | +{ |
| 308 | + for(int i = 1; i <= MaxClients; i++) |
| 309 | + { |
| 310 | + if(IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) |
| 311 | + return i; |
| 312 | + } |
| 313 | + return 0; |
| 314 | +} |
| 315 | + |
| 316 | +bool bIsGameInFirstHalf() |
| 317 | +{ |
| 318 | + return GameRules_GetProp("m_bInSecondHalfOfRound") ? false : true; |
| 319 | +} |
0 commit comments