mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-07 22:33:21 +00:00
Bulk update
This commit is contained in:
parent
f37301cae8
commit
9adbe21719
22 changed files with 1221 additions and 103 deletions
|
@ -82,10 +82,10 @@ public Action VoteStart(int client, const char[] command, int argc) {
|
|||
disableFFClient = target;
|
||||
ffDamageCount = 0;
|
||||
}
|
||||
PrintToServer("KICK VOTE STARTED | Target=%N | Caller=%N", issue, target, client);
|
||||
return Plugin_Continue;
|
||||
}
|
||||
//Kick vote started
|
||||
PrintToServer("KICK VOTE STARTED | Issue=%s Option=%s Caller=%N", issue, option, client);
|
||||
}
|
||||
}
|
||||
return Plugin_Continue; //if it wasn't handled up there I would start panicking
|
||||
|
|
|
@ -99,7 +99,6 @@ public void OnPluginStart() {
|
|||
}
|
||||
|
||||
public Action Timer_CheckPlayerPings(Handle timer) {
|
||||
//hPingDropThres
|
||||
if(hPingDropThres.IntValue != 0) {
|
||||
for (int i = 1; i <= MaxClients; i++ ) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && IsPlayerAlive(i) && GetClientTeam(i) > 1) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#define AUTOPUNISH_FLOW_MIN_DISTANCE 5000.0
|
||||
#define AUTOPUNISH_MODE_COUNT 3
|
||||
#define TROLL_MODE_COUNT 22
|
||||
#define TROLL_MODE_COUNT 23
|
||||
//
|
||||
enum trollMode {
|
||||
Troll_Reset = 0, //0
|
||||
|
@ -23,8 +23,9 @@ enum trollMode {
|
|||
Troll_TankMagnet, //17
|
||||
Troll_NoShove, //18
|
||||
Troll_DamageBoost, //19
|
||||
Troll_TempHealthQuickDrain,
|
||||
Troll_VomitPlayer
|
||||
Troll_TempHealthQuickDrain, //20
|
||||
Troll_VomitPlayer, //21
|
||||
Troll_VocalizeGag
|
||||
}
|
||||
enum TrollModifier {
|
||||
TrollMod_None = 0,
|
||||
|
@ -53,7 +54,8 @@ char TROLL_MODES_NAMES[TROLL_MODE_COUNT][32] = {
|
|||
"No Shove",
|
||||
"Damage Boost",
|
||||
"Temp Quick Drain",
|
||||
"Vomit Player"
|
||||
"Vomit Player",
|
||||
"Vocalize Gag"
|
||||
};
|
||||
char TROLL_MODES_DESCRIPTIONS[TROLL_MODE_COUNT][128] = {
|
||||
"Resets the user, removes all troll effects", //0
|
||||
|
@ -77,7 +79,8 @@ char TROLL_MODES_DESCRIPTIONS[TROLL_MODE_COUNT][128] = {
|
|||
"Prevents a player from shoving",
|
||||
"Makes a player take more damage than normal",
|
||||
"Makes a player's temporarily health drain very quickly",
|
||||
"Shortcut to sm_vomitplayer. vomits the player."
|
||||
"Shortcut to sm_vomitplayer. vomits the player.",
|
||||
"Prevents player from sending any vocalizations (even automatic)"
|
||||
};
|
||||
enum L4D2Infected
|
||||
{
|
||||
|
@ -114,7 +117,7 @@ void ApplyModeToClient(int client, int victim, trollMode mode, TrollModifier mod
|
|||
case Troll_SlowDrain: {}
|
||||
case Troll_TempHealthQuickDrain: {}
|
||||
case Troll_VomitPlayer: {
|
||||
ServerCommand("sm_vomitplayer #%d", GetClientUserId(victim));
|
||||
ClientCommand(client, "sm_vomitplayer #%d", GetClientUserId(victim));
|
||||
}
|
||||
|
||||
case Troll_Reset: {
|
||||
|
@ -216,15 +219,19 @@ void ApplyModeToClient(int client, int victim, trollMode mode, TrollModifier mod
|
|||
PrintToServer("Troll Mode #%d not implemented (%s)", mode, TROLL_MODES_NAMES[mode]);
|
||||
}
|
||||
}
|
||||
ShowActivity(client, "activated troll mode \"%s\" on %N. ", TROLL_MODES_NAMES[mode], victim);
|
||||
if(HasTrollMode(client, mode)) {
|
||||
ShowActivity(client, "deactivated troll \"%s\" on %N. ", TROLL_MODES_NAMES[mode], victim);
|
||||
}else{
|
||||
ShowActivity(client, "activated troll \"%s\" on %N. ", TROLL_MODES_NAMES[mode], victim);
|
||||
}
|
||||
//If instant fire mod not provided (aka instead of no modifiers which equals both) OR repeat turned on, set bit:
|
||||
if(modifier == TrollMod_Repeat || modifier == TrollMod_None) {
|
||||
g_iTrollUsers[victim] |= 1 << (view_as<int>(mode) - 1);
|
||||
g_iTrollUsers[victim] ^= 1 << view_as<int>(mode) -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasTrollMode(int client, trollMode mode) {
|
||||
return ((g_iTrollUsers[client] >> view_as<int>(mode) - 1) & 1) == 1 && IsClientInGame(client) && IsPlayerAlive(client);
|
||||
return ((g_iTrollUsers[client] >> view_as<int>(mode) - 1) & 1) == 1;
|
||||
}
|
||||
|
||||
void ToggleTrollMode(int client, trollMode mode) {
|
||||
|
|
294
scripting/include/l4d2_skill_detect.inc
Normal file
294
scripting/include/l4d2_skill_detect.inc
Normal file
|
@ -0,0 +1,294 @@
|
|||
#if defined _skilldetect_included_
|
||||
#endinput
|
||||
#endif
|
||||
#define _skilldetect_included_
|
||||
|
||||
|
||||
/**
|
||||
* CarAlarmTriggerReason: the 'reason' parameter in OnCarAlarmTriggered() forward
|
||||
*/
|
||||
enum CarAlarmTriggerReason {
|
||||
CarAlarmTrigger_Unknown,
|
||||
CarAlarmTrigger_Hit,
|
||||
CarAlarmTrigger_Touched,
|
||||
CarAlarmTrigger_Explosion,
|
||||
CarAlarmTrigger_Boomer
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Called whenever a true skeet with shotgun is done.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
*/
|
||||
forward void OnSkeet( int survivor, int hunter );
|
||||
|
||||
/**
|
||||
* Called whenever a true melee-skeet is done.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
*/
|
||||
forward void OnSkeetMelee( int survivor, int hunter );
|
||||
|
||||
/**
|
||||
* Called whenever a direct grenade launcher hit on a hunter connects.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
*/
|
||||
forward void OnSkeetGL( int survivor, int hunter );
|
||||
|
||||
/**
|
||||
* Called whenever a true skeeting sniper headshot landed.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
*/
|
||||
forward void OnSkeetSniper( int survivor, int hunter );
|
||||
|
||||
/**
|
||||
* Called whenever a pouncing hunter got killed with shotgun
|
||||
* when it wasn't a true skeet (chipped hunter).
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
* @param int damage damage done in the killing hit
|
||||
* @param bool isOverKill true if it would've been a skeet if the hunter hadn't been chipped
|
||||
*/
|
||||
forward void OnSkeetHurt( int survivor, int hunter, int damage, bool isOverkill );
|
||||
|
||||
/**
|
||||
* Called whenever a pouncing hunter got killed with melee
|
||||
* when it wasn't a true skeet (chipped hunter).
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
* @param int damage damage done in the killing hit
|
||||
* @param bool isOverKill true if it would've been a skeet if the hunter hadn't been chipped
|
||||
*/
|
||||
forward void OnSkeetMeleeHurt( int survivor, int hunter, int damage, bool isOverkill );
|
||||
|
||||
/**
|
||||
* Called whenever a pouncing hunter got killed with a sniper headshot
|
||||
* when it wasn't a true skeet (chipped hunter).
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
* @param int damage damage done in the killing hit
|
||||
* @param bool isOverKill true if it would've been a skeet if the hunter hadn't been chipped
|
||||
*/
|
||||
forward void OnSkeetSniperHurt( int survivor, int hunter, int damage, bool isOverkill );
|
||||
|
||||
/**
|
||||
* Called whenever a hunter is deadstopped (pouncing => m2'd).
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int hunter the infected client that underwent it
|
||||
*/
|
||||
forward void OnHunterDeadstop( int survivor, int hunter );
|
||||
|
||||
/**
|
||||
* Called whenever a boomer is killed that didn't land on anyone,
|
||||
* and didn't explode on anyone either.
|
||||
*
|
||||
* @param int survivor the survivor client that killed the boomer
|
||||
* @param int boomer the infected client that got popped
|
||||
* @param int shoveCount the amount of times the boomer got shoved, if any
|
||||
* @param Float timeAlive the time, in seconds, that the boomer lived
|
||||
*/
|
||||
forward void OnBoomerPop( int survivor, int oomer, int hoveCount, float timeAlive );
|
||||
|
||||
/**
|
||||
* Called whenever a charger is fully melee-leveled (no chip).
|
||||
* This is also called when the melee hit would've leveled if not chipped!
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int charger the infected client that underwent it
|
||||
*/
|
||||
forward void OnChargerLevel( int survivor, int charger );
|
||||
|
||||
/**
|
||||
* Called whenever a charger is melee-leveled after being chipped.
|
||||
* Only called when the melee wouldn't have killed an unchipped charger.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int charger the infected client that underwent it
|
||||
* @param int damage damage done in the killing hit
|
||||
*/
|
||||
forward void OnChargerLevelHurt( int survivor, int charger, int damage );
|
||||
|
||||
/**
|
||||
* Called whenever a witch was crowned without her being angered first.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int damage damage done in the killing hit
|
||||
*/
|
||||
forward void OnWitchCrown( int survivor, int damage );
|
||||
|
||||
/**
|
||||
* Called whenever a witch gets crowned after she got angered/triggered.
|
||||
* This is referred to (depending on the community) as a 'draw crown' or 'remote'.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int damage damage done in the killing hit
|
||||
* @param int chipdamage damage done to the witch before she got crowned
|
||||
*/
|
||||
forward void OnWitchCrownHurt( int survivor, int damage, int chipdamage );
|
||||
|
||||
/**
|
||||
* Called whenever a survivor melee-cuts a smoker tongue that was aimed for them.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int smoker the infected client that underwent it
|
||||
*/
|
||||
forward void OnTongueCut( int survivor, int smoker );
|
||||
|
||||
/**
|
||||
* Called whenever a survivor frees himself from a smoker that grabbed them,
|
||||
* either by killing it or by shoving.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int smoker the infected client that underwent it
|
||||
* @param bool withShove true if the self-clear was by a shove/m2
|
||||
*/
|
||||
forward void OnSmokerSelfClear( int survivor, int smoker, bool withShove );
|
||||
|
||||
/**
|
||||
* Called whenever a survivor shoots/melees a tank rock out of the air.
|
||||
*
|
||||
* Note: the tank param might be unreliable due to the nature of the
|
||||
* tracking. Don't do anything srs bsns with it.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int tank the infected client that underwent it
|
||||
*/
|
||||
forward void OnTankRockSkeeted( int survivor, int tank );
|
||||
|
||||
/**
|
||||
* Called whenever a tank lands a rock on a survivor.
|
||||
*
|
||||
* Note: the tank param might be unreliable due to the nature of the
|
||||
* tracking. Don't do anything srs bsns with it.
|
||||
*
|
||||
* @param int tank the infected client that performed the feat
|
||||
* @param int survivor the survivor client that underwent it
|
||||
*/
|
||||
forward void OnTankRockEaten( int tank, int survivor );
|
||||
|
||||
/**
|
||||
* Called whenever a hunter lands a high-pounce on a survivor.
|
||||
*
|
||||
* @param int hunter the infected client that performed the feat
|
||||
* @param int survivor the survivor client that underwent it
|
||||
* @param int actualDamage the actual damage the pounce did to the survivor
|
||||
* @param Float calculatedDamage how much damage (going by pounceannounce parameters) the pounce would be expected to do
|
||||
* @param Float height the vertical distance between the pounce origin and its landing
|
||||
* @param bool reportedHigh whether skill_detect considers it a high pounce for reporting purposes
|
||||
*/
|
||||
forward void OnHunterHighPounce( int hunter, int survivor, int actualDamage, float calculatedDamage, float height, bool reportedHigh );
|
||||
|
||||
/**
|
||||
* Called whenever a jockey lands a high-pounce on a survivor.
|
||||
*
|
||||
* Note: due to the nature of the tracking, it only gets the height right if a jockey actually
|
||||
* jumped or pounced from his perch. If they simple walk off and land, it may be incorrect.
|
||||
*
|
||||
* @param int jockey the infected client that performed the feat
|
||||
* @param int survivor the survivor client that underwent it
|
||||
* @param Float height the vertical distance between the pounce origin and its landing
|
||||
* @param bool reportedHigh whether skill_detect considers it a high pounce for reporting purposes
|
||||
*/
|
||||
forward void OnJockeyHighPounce( int jockey, int victim, float height, bool reportedHigh );
|
||||
|
||||
/**
|
||||
* Called whenever a charger lands a death-charge on a survivor.
|
||||
* This is called for killing the grabbed survivor, but also the ones that get impact-bumped
|
||||
* and fall to their deaths.
|
||||
*
|
||||
* Note: due to the nature of the tracking, there may be places that are technically death-
|
||||
* charge spots, but not detected by the plugin. Example: the sidewalk next to the fence near
|
||||
* the lower roof on Dead Air 1; the Death Toll 4 out-of-map deathcharge near the start
|
||||
* saferoom.
|
||||
*
|
||||
* @param int charger the infected client that performed the feat
|
||||
* @param int survivor the survivor client that underwent it
|
||||
* @param Float height the vertical distance between the grab and the survivor's death spot
|
||||
* @param Float distance the full vector distance between the grab and the survivor's death spot
|
||||
* @param bool wasCarried true if the survivor was the one that the charger grabbed
|
||||
*/
|
||||
forward void OnDeathCharge( int charger, int survivor, float height, float distance, bool wasCarried );
|
||||
|
||||
/**
|
||||
* Called whenever a survivor clears a teammate from a special infected pin.
|
||||
*
|
||||
* Note: timeB is only appliccable for smokers and chargers. For smokers it shows the
|
||||
* time from the tongue connecting to the clear. For chargers from the charge-grab to
|
||||
* the clear. For jockeys and hunters, timeB will always be -1.0.
|
||||
*
|
||||
* timeA is the time, for charger, from start of pummeling till clear (-1.0 if they
|
||||
* never started pummeling). For smokers, this is the time from the survivor being
|
||||
* fully reigned in to the smoker (-1.0 if the tongue was broken before that).
|
||||
*
|
||||
* @param int clearer the survivor client that performed the clear
|
||||
* @param int pinner the pinning infected client that got cleared (shoved off or killed)
|
||||
* @param int pinvictim the pinned survivor that was saved
|
||||
* @param int zombieClass the class (ZC_SMOKER - ZC_CHARGER) of the pinner
|
||||
* @param Float timeA time from pin till clear in seconds, -1 if never
|
||||
* @param Float timeB for charger/smoker: time from grab/tongue connect to clear
|
||||
* @param bool withShove true if the clear was done by shove/m2
|
||||
*/
|
||||
forward void OnSpecialClear( int clearer, int pinner, int pinvictim, int zombieClass, float timeA, float timeB, bool withShove );
|
||||
|
||||
/**
|
||||
* Called whenever a boomer is done vomiting, and landed his vomit on one
|
||||
* or more survivors.
|
||||
*
|
||||
* Note: this does not include or fire for boomers exploding, only vomits.
|
||||
*
|
||||
* @param int boomer the infected client that performed the feat
|
||||
* @param int amount the amount of survivors vomited on
|
||||
*/
|
||||
forward void OnBoomerVomitLanded( int boomer, int amount );
|
||||
|
||||
/**
|
||||
* Called whenever a survivor shoves a special infected (any kind).
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int infected the infected client that underwent it
|
||||
* @param int zombieClass the class type of the infected shoved
|
||||
*/
|
||||
forward void OnSpecialShoved( int survivor, int infected, int zombieClass );
|
||||
|
||||
/**
|
||||
* Called whenever a survivor lands any number of bunnyhops in a row. Called
|
||||
* afterwards.
|
||||
*
|
||||
* @param int survivor the survivor client that performed the feat
|
||||
* @param int streak the amount of hops in a row
|
||||
* @param Float maxVelocity the highest speed during any jump or jump apex
|
||||
*/
|
||||
forward void OnBunnyHopStreak( int survivor, int streak, float maxVelocity );
|
||||
|
||||
/**
|
||||
* Called whenever a car alarm is triggered (by a survivor).
|
||||
*
|
||||
* @param int survivor the survivor client that triggered the alarm (-1 or 0 if unknown)
|
||||
* @param int infected if > 0: the infected client that assisted in triggering it (boomer, smoker, jockey or charger)
|
||||
* @param int reason the reason for triggering (see CarAlarmTriggerType)
|
||||
*/
|
||||
forward void OnCarAlarmTriggered( int survivor, int infected, CarAlarmTriggerReason reason );
|
||||
|
||||
|
||||
public SharedPlugin __pl_skilldetect =
|
||||
{
|
||||
name = "skill_detect",
|
||||
file = "l4d2_skill_detect.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
54
scripting/include/l4d_info_editor.inc
Normal file
54
scripting/include/l4d_info_editor.inc
Normal file
|
@ -0,0 +1,54 @@
|
|||
#if defined _info_editor_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _info_editor_included
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the value of a specified key from the games mission info keyvalue system. "N/A" is returned when not found.
|
||||
*
|
||||
* @param pThis Enter the pThis value from OnGetMissionInfo/OnGetWeaponsInfo. Can specify 0 when reading Mission data.
|
||||
* @param keyname Key name to check.
|
||||
* @param dest Destination string buffer to copy to.
|
||||
* @param destLen Destination buffer length (includes null terminator).
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void InfoEditor_GetString(int pThis, const char[] keyname, char[] dest, int destLen);
|
||||
|
||||
/**
|
||||
* Sets the value of a specified key from the games mission info keyvalue system.
|
||||
*
|
||||
* @param pThis Enter the pThis value from OnGetMissionInfo/OnGetWeaponsInfo. Can specify 0 when writing Mission data.
|
||||
* @param keyname Key name to set.
|
||||
* @param value Value to set.
|
||||
* @param create Optionally create the keyvalue if it doesn't exist.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void InfoEditor_SetString(int pThis, const char[] keyname, const char[] value, bool create = false);
|
||||
|
||||
/**
|
||||
* Reloads the mission and weapons data configs and forces the game to reload them.
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void InfoEditor_ReloadData();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Fired multiple times when the mission info data is parsed.
|
||||
*
|
||||
* @param pThis This pointer used for InfoEditor_GetString/InfoEditor_SetString.
|
||||
*/
|
||||
forward void OnGetMissionInfo(int pThis);
|
||||
|
||||
/**
|
||||
* Fired multiple times when the weapon info data is parsed for a specific weapon classname.
|
||||
*
|
||||
* @param pThis This pointer used for InfoEditor_GetString/InfoEditor_SetString.
|
||||
* @param classname Classname of the weapon being parsed.
|
||||
*/
|
||||
forward void OnGetWeaponsInfo(int pThis, const char[] classname);
|
|
@ -8,17 +8,17 @@ enum Character {
|
|||
Character_Zoey,
|
||||
Character_Louis
|
||||
}
|
||||
native int IdentityFix_SetPlayerModel(int client, int args);
|
||||
native int IdentityFix_SetPlayerModel(int client, int args, bool keep = false);
|
||||
|
||||
|
||||
static bool nativeAvailable, nativeTested;
|
||||
bool UpdatePlayerIdentity(int client, Character character) {
|
||||
bool UpdatePlayerIdentity(int client, Character character, bool keep = false) {
|
||||
if(!nativeTested) {
|
||||
nativeTested = true;
|
||||
nativeAvailable = GetFeatureStatus(FeatureType_Native, "IdentityFix_SetPlayerModel") == FeatureStatus_Available;
|
||||
}
|
||||
if(nativeAvailable) {
|
||||
int result = IdentityFix_SetPlayerModel(client, view_as<int>(character));
|
||||
int result = IdentityFix_SetPlayerModel(client, view_as<int>(character), keep);
|
||||
return result == 0;
|
||||
}else{
|
||||
return false;
|
||||
|
|
|
@ -88,6 +88,7 @@ public void __pl_l4dh_SetNTVOptional()
|
|||
MarkNativeAsOptional("L4D_IsInFirstCheckpoint");
|
||||
MarkNativeAsOptional("L4D_IsInLastCheckpoint");
|
||||
MarkNativeAsOptional("L4D2_IsReachable");
|
||||
MarkNativeAsOptional("L4D_HasPlayerControlledZombies");
|
||||
MarkNativeAsOptional("L4D_PipeBombPrj");
|
||||
|
||||
MarkNativeAsOptional("L4D2_GetVScriptOutput");
|
||||
|
@ -241,6 +242,7 @@ public void __pl_l4dh_SetNTVOptional()
|
|||
// =========================
|
||||
MarkNativeAsOptional("L4D_CTerrorPlayer_OnVomitedUpon");
|
||||
MarkNativeAsOptional("L4D_CancelStagger");
|
||||
MarkNativeAsOptional("L4D_RespawnPlayer");
|
||||
MarkNativeAsOptional("L4D_CreateRescuableSurvivors");
|
||||
MarkNativeAsOptional("L4D_ReviveSurvivor");
|
||||
MarkNativeAsOptional("L4D_GetHighestFlowSurvivor");
|
||||
|
@ -883,9 +885,9 @@ forward void L4D2_OnWaterMove(int client);
|
|||
* @param client Client id to find an area near this player
|
||||
* @param zombieClass Special Infected class to search for a spawn position for
|
||||
* @param attempts How many tries to find a valid location
|
||||
* @param vecPos The vector location. Sometimes is 0,0,0. Use post hook for real selected position.
|
||||
* @param vecPos The vector location. Sometimes is 0,0,0. Use post hook for real selected position
|
||||
*
|
||||
* @return Plugin_Changed to change any values, Plugin_Continue otherwise.
|
||||
* @return Plugin_Changed to change any values, Plugin_Continue otherwise
|
||||
*/
|
||||
#pragma deprecated Removed because it spawns specials at 0,0,0 when modifying any value.
|
||||
forward Action L4D_OnGetRandomPZSpawnPosition(int &client, int &zombieClass, int &attempts, float vecPos[3]);
|
||||
|
@ -962,7 +964,7 @@ native int L4D_AngularVelocity(int entity, const float vecAng[3]);
|
|||
* @remarks The zombieClass does not matter but different values yield different results:
|
||||
* @remarks Using the Tank zombieClass probably searches for a larger area that's clear of objects
|
||||
*
|
||||
* @param client Client id to find an area near this player
|
||||
* @param client Client id to find an area near this player. Accepts 0 to find a random area instead
|
||||
* @param zombieClass Special Infected class to search for a spawn position for
|
||||
* @param attempts How many tries to find a valid location
|
||||
* @param vecPos The vector array to store the valid location on success
|
||||
|
@ -1032,8 +1034,9 @@ native bool L4D_IsInFirstCheckpoint(int client);
|
|||
native bool L4D_IsInLastCheckpoint(int client);
|
||||
|
||||
/**
|
||||
* @brief Checks if a world position is accessible to a player.
|
||||
* @remarks You can pass any client index into this (real or fake players, survivors or special infected).
|
||||
* @brief Checks if a world position is accessible to a Survivor bot.
|
||||
* @remarks You must pass a survivor bots client index into this, otherwise the plugin will attempt to find a bot or throw an error otherwise.
|
||||
* @remarks It appears the server will sometimes crash when passing a real players client index.
|
||||
* @remarks If the clients flow distance is too far away from the position to test it will return false.
|
||||
*
|
||||
* @param client Client id to use for testing
|
||||
|
@ -1044,6 +1047,13 @@ native bool L4D_IsInLastCheckpoint(int client);
|
|||
// L4D2 only.
|
||||
native bool L4D2_IsReachable(int client, const float vecPos[3]);
|
||||
|
||||
/**
|
||||
* @brief Returns if players can control infected
|
||||
*
|
||||
* @return True if players can control infected, false otherwise
|
||||
*/
|
||||
native bool L4D_HasPlayerControlledZombies();
|
||||
|
||||
/**
|
||||
* @brief Creates an activated PipeBomb projectile
|
||||
* @remarks Does not attach the "Fuse" or "Light" particles, see the "left4dhooks_test" plugin for example on attaching these
|
||||
|
@ -2604,6 +2614,15 @@ native void L4D2_CTerrorPlayer_Fling(int client, int attacker, float vecDir[3]);
|
|||
*/
|
||||
native void L4D_CancelStagger(int client);
|
||||
|
||||
/**
|
||||
* @brief Respawns a player from dead state.
|
||||
*
|
||||
* @param client Client ID of the person to affect
|
||||
*
|
||||
* @noreturn
|
||||
*/
|
||||
native void L4D_RespawnPlayer(int client);
|
||||
|
||||
/**
|
||||
* @brief Spawns all dead survivors in rescuable rooms.
|
||||
* @remarks L4D1: Any survivor must not be in the starting area for it to work.
|
||||
|
|
283
scripting/include/sceneprocessor.inc
Normal file
283
scripting/include/sceneprocessor.inc
Normal file
|
@ -0,0 +1,283 @@
|
|||
#if defined _sceneprocessor_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _sceneprocessor_included
|
||||
|
||||
#define MAX_SCENEFILE_LENGTH PLATFORM_MAX_PATH // Maximum length of scene files
|
||||
#define MAX_VOCALIZE_LENGTH 128 // Maximum length of vocalize strings
|
||||
|
||||
#define SCENE_INITIATOR_WORLD 0 /* All scenes created by the map (such as landmarks, "Down this way", "Through here")
|
||||
* and by the game (such as team mate actions, "Let me heal you up", "Help I'm falling")
|
||||
* are marked as started by the world, or entity index 0. */
|
||||
#define SCENE_INITIATOR_PLUGIN -1 /* All scenes started by the Scene Processor are by default marked as started by plugin or
|
||||
* entity index -1. This can be changed in the PerformScene function call. */
|
||||
|
||||
#define DEFAULT_SCENE_PREDELAY 0.0 /* By default all scenes occur the instant they are created */
|
||||
#define DEFAULT_SCENE_PITCH 1.0 /* By default all scenes have a pitch of 1.0, or as they are normally heard. 2.0 will make
|
||||
* it sounds twice as fast but in a high pitched voice. 0.5 will be half the normal speed
|
||||
* and with low pitched voice. */
|
||||
|
||||
enum SceneStages
|
||||
{
|
||||
SceneStage_Unknown = 0, /* Scene has not been created nor processed. Either something went wrong, the
|
||||
* scene is not valid, incorrectly formatted, or a round just started recently. */
|
||||
|
||||
SceneStage_Created = 1, /* When scene is created. Contains no information about the scene that is about to
|
||||
* be played out. Guaranteed to occur. */
|
||||
|
||||
SceneStage_Spawned, /* When scene is spawned. Everything is filled in but the pre-delay! Change scene
|
||||
* pitch and pre-delay here. */
|
||||
|
||||
SceneStage_SpawnedPost, /* Post scene spawned frame. Pre-delay is now filled out. Pre-delay can be changed
|
||||
* here if the scene originally has a pre-delay greater than 0.0. */
|
||||
|
||||
SceneStage_Started, /* When scene is started. Time stamp is set. */
|
||||
|
||||
SceneStage_Cancelled, /* When scene is cancelled. Happens if the Survivor was interrupted by another scene
|
||||
* or the scene was cancelled post starting. */
|
||||
|
||||
SceneStage_Completion, /* When scene is completed. Happens if the Survivor gets to fully perform the scene
|
||||
* with no interruptions or cancellation. Entity index is no longer valid but
|
||||
* information is retained. */
|
||||
|
||||
SceneStage_Killed /* When scene is killed. Entity index is no longer valid but information is retained
|
||||
* until end of forward. Guaranteed to occur */
|
||||
};
|
||||
|
||||
/**
|
||||
* Called on scene stage changed.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @param stage SceneStages value.
|
||||
* @noreturn
|
||||
*/
|
||||
forward void OnSceneStageChanged(int scene, SceneStages stage);
|
||||
|
||||
/**
|
||||
* Called on vocalize command send.
|
||||
*
|
||||
* @remarks See SCENE_INITIATOR_WORLD and SCENE_INITIATOR_PLUGIN for
|
||||
* non-client initiated vocalizes.
|
||||
*
|
||||
* @param client Index of player sending vocalize command.
|
||||
* @param vocalize String of what player wish to vocalize, as typed.
|
||||
* @param initiator Index of entity initiated vocalize command.
|
||||
* @return Plugin_Stop to stop vocalize command.
|
||||
* Plugin_Continue to allow vocalize command.
|
||||
*/
|
||||
forward Action OnVocalizationProcess(int client, const char[] vocalize, int initiator);
|
||||
|
||||
/**
|
||||
* Returns scene stage.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return SceneStages value or 0 if scene is not valid.
|
||||
*/
|
||||
native SceneStages GetSceneStage(int scene);
|
||||
|
||||
/**
|
||||
* Returns whether scene is valid as a scene.
|
||||
*
|
||||
* @remarks The scene entity index may still be invalid.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return True if a valid scene, false otherwise.
|
||||
*/
|
||||
stock bool IsValidScene(int scene)
|
||||
{
|
||||
return GetSceneStage(scene) != SceneStage_Unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns scene start time stamp, in engine time.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return Scene start engine time stamp. 0.0 if the scene has not started yet.
|
||||
*/
|
||||
native float GetSceneStartTimeStamp(int scene);
|
||||
|
||||
/**
|
||||
* Returns scene actor.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return Actor of the scene. 0 if no one is playing it.
|
||||
*/
|
||||
native int GetActorFromScene(int scene);
|
||||
|
||||
/**
|
||||
* Returns actor's scene.
|
||||
*
|
||||
* @remarks Only returns scene if it is currently being played out.
|
||||
*
|
||||
* @param actor Client index of actor.
|
||||
* @return Scene entity index. INVALID_ENT_REFERENCE if actor currently aren't playing.
|
||||
*/
|
||||
native int GetSceneFromActor(int actor);
|
||||
|
||||
/**
|
||||
* Returns whether actor is already playing a scene.
|
||||
*
|
||||
* @param actor Client index of actor.
|
||||
* @return True if actor is busy, false otherwise.
|
||||
*/
|
||||
stock bool IsActorBusy(int actor)
|
||||
{
|
||||
return GetSceneFromActor(actor) != INVALID_ENT_REFERENCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns scene initiator.
|
||||
*
|
||||
* @remarks See SCENE_INITIATOR_WORLD and SCENE_INITIATOR_PLUGIN for automated
|
||||
* scenes.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return Initiator of the scene.
|
||||
*/
|
||||
native int GetSceneInitiator(int scene);
|
||||
|
||||
/**
|
||||
* Returns scene file.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @param dest Destination string buffer to copy to.
|
||||
* @param len Destination buffer length (includes null terminator).
|
||||
* @return Number of bytes written
|
||||
*/
|
||||
native int GetSceneFile(int scene, char[] dest, int len);
|
||||
|
||||
/**
|
||||
* Returns scene vocalize.
|
||||
*
|
||||
* @remarks Will only contain the vocalize string if the scene was started by
|
||||
* the client them self. Otherwise empty.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @param dest Destination string buffer to copy to.
|
||||
* @param len Destination buffer length (includes null terminator).
|
||||
* @return Number of bytes written
|
||||
*/
|
||||
native int GetSceneVocalize(int scene, char[] dest, int len);
|
||||
|
||||
/**
|
||||
* Returns scene pre-delay.
|
||||
*
|
||||
* @remarks Sadly pre-delay is first fetched on SceneStage_SpawnedPost where
|
||||
* altering the pre-delay with SetScenePreDelay might already be too late.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return Scene pre-delay in seconds.
|
||||
*/
|
||||
native float GetScenePreDelay(int scene);
|
||||
|
||||
/**
|
||||
* Sets scene pre-delay.
|
||||
*
|
||||
* @remarks Pre-delay can be set on SceneStage_Spawned and sometimes (!) on
|
||||
* SceneStage_SpawnedPost depending on whether the scene originally has a
|
||||
* pre-delay. Once SceneStage_Started fires pre-delay is no longer obeyed.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @param preDelay Scene pre-delay in seconds.
|
||||
* @noreturn
|
||||
*/
|
||||
native void SetScenePreDelay(int scene, float preDelay);
|
||||
|
||||
/**
|
||||
* Returns scene pitch.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @return Scene pitch.
|
||||
*/
|
||||
native float GetScenePitch(int scene);
|
||||
|
||||
/**
|
||||
* Sets scene pitch
|
||||
*
|
||||
* @remarks Scene pitch can be set on SceneStage_Spawned and
|
||||
* SceneStage_SpawnedPost. Setting pitch post spawning results in weird
|
||||
* settings such as some clients hearing 1.13 as double as fast instead of 2.0.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @param pitch Scene pitch.
|
||||
* @noreturn
|
||||
*/
|
||||
native void SetScenePitch(int scene, float pitch);
|
||||
|
||||
/**
|
||||
* Cancels scene.
|
||||
*
|
||||
* @remarks Can be used at all scene stages. Scene is validated before sending
|
||||
* the cancel input.
|
||||
*
|
||||
* @param scene Scene entity index.
|
||||
* @noreturn
|
||||
*/
|
||||
native void CancelScene(int scene);
|
||||
|
||||
/**
|
||||
* Performs a scene.
|
||||
*
|
||||
* @remarks Scene file is used before vocalize string however vocalize string
|
||||
* is still saved to scene entity index and can be retrieved for later usage.
|
||||
* If vocalize string is used, it is delayed for a short while in order to
|
||||
* work if used inside of OnSceneStageChanged. See PerformSceneEx to avoid
|
||||
* this delay.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param vocalize Vocalize string.
|
||||
* @param file Scene file.
|
||||
* @param preDelay Scene pre-delay.
|
||||
* @param pitch Scene pitch.
|
||||
* @param initiator Initiator of the scene.
|
||||
* @noreturn
|
||||
*/
|
||||
native void PerformScene(int client, const char[] vocalize, const char[] file = "", float preDelay = DEFAULT_SCENE_PREDELAY, float pitch = DEFAULT_SCENE_PITCH, int initiator = SCENE_INITIATOR_PLUGIN);
|
||||
|
||||
/**
|
||||
* Performs a scene.
|
||||
*
|
||||
* @remarks Works the same way as PerformScene however there is no delay when
|
||||
* using vocalize string. Not recommend to use inside OnSceneStageChanged if
|
||||
* vocalizes needs to get through.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param vocalize Vocalize string.
|
||||
* @param file Scene file.
|
||||
* @param preDelay Scene pre-delay.
|
||||
* @param pitch Scene pitch.
|
||||
* @param initiator Initiator of the scene.
|
||||
* @noreturn
|
||||
*/
|
||||
native void PerformSceneEx(int client, const char[] vocalize, const char[] file = "", float preDelay = DEFAULT_SCENE_PREDELAY, float pitch = DEFAULT_SCENE_PITCH, int initiator = SCENE_INITIATOR_PLUGIN);
|
||||
|
||||
public SharedPlugin __pl_sceneproces =
|
||||
{
|
||||
name = "sceneprocessor",
|
||||
file = "sceneprocessor.smx",
|
||||
#if defined REQUIRE_PLUGIN
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_PLUGIN
|
||||
public void __pl_sceneproces_SetNTVOptional()
|
||||
{
|
||||
MarkNativeAsOptional("GetSceneStage");
|
||||
MarkNativeAsOptional("GetSceneStartTimeStamp");
|
||||
MarkNativeAsOptional("GetActorFromScene");
|
||||
MarkNativeAsOptional("GetSceneFromActor");
|
||||
MarkNativeAsOptional("GetSceneInitiator");
|
||||
MarkNativeAsOptional("GetSceneFile");
|
||||
MarkNativeAsOptional("GetSceneVocalize");
|
||||
MarkNativeAsOptional("GetScenePreDelay");
|
||||
MarkNativeAsOptional("SetScenePreDelay");
|
||||
MarkNativeAsOptional("GetScenePitch");
|
||||
MarkNativeAsOptional("SetScenePitch");
|
||||
MarkNativeAsOptional("CancelScene");
|
||||
MarkNativeAsOptional("PerformScene");
|
||||
MarkNativeAsOptional("PerformSceneEx");
|
||||
}
|
||||
#endif
|
32
scripting/include/smlib.inc
Normal file
32
scripting/include/smlib.inc
Normal file
|
@ -0,0 +1,32 @@
|
|||
#if defined _smlib_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _smlib_included
|
||||
|
||||
#define SMLIB_VERSION "0.9.7"
|
||||
|
||||
#include <smlib/general>
|
||||
|
||||
#include <smlib/arrays>
|
||||
#include <smlib/clients>
|
||||
#include <smlib/colors>
|
||||
#include <smlib/concommands>
|
||||
#include <smlib/convars>
|
||||
#include <smlib/crypt>
|
||||
#include <smlib/debug>
|
||||
#include <smlib/dynarrays>
|
||||
#include <smlib/edicts>
|
||||
#include <smlib/effects>
|
||||
#include <smlib/entities>
|
||||
#include <smlib/files>
|
||||
#include <smlib/game>
|
||||
#include <smlib/math>
|
||||
#include <smlib/menus>
|
||||
//#include <smlib/pluginmanager>
|
||||
#include <smlib/server>
|
||||
#include <smlib/strings>
|
||||
#include <smlib/sql>
|
||||
#include <smlib/teams>
|
||||
#include <smlib/vehicles>
|
||||
#include <smlib/weapons>
|
||||
#include <smlib/world>
|
|
@ -17,6 +17,7 @@ char g_icCurrentMap[32];
|
|||
|
||||
int g_icPlayerManager; //entid -> typically 25 (MaxClients+1)
|
||||
|
||||
static bool b_isTransitioning[MAXPLAYERS+1];
|
||||
bool g_icHealing[MAXPLAYERS+1]; //state
|
||||
bool g_icBeingHealed[MAXPLAYERS+1]; //state
|
||||
|
||||
|
@ -29,6 +30,7 @@ public Plugin myinfo =
|
|||
url = ""
|
||||
};
|
||||
|
||||
//TODO: Transition state
|
||||
|
||||
public OnPluginStart()
|
||||
{
|
||||
|
@ -45,6 +47,9 @@ public OnPluginStart()
|
|||
//HookEvent("heal_end", Event_HealStop);
|
||||
HookEvent("heal_success", Event_HealStop);
|
||||
HookEvent("heal_interrupted", Event_HealStop);
|
||||
//For transitioning:
|
||||
HookEvent("map_transition", Event_MapTransition);
|
||||
HookEvent("player_spawn", Event_PlayerSpawn);
|
||||
|
||||
//hook cvars, game info states
|
||||
FindConVar("z_difficulty").GetString(g_icDifficulty, sizeof(g_icDifficulty));
|
||||
|
@ -59,12 +64,13 @@ public OnPluginStart()
|
|||
// print info
|
||||
public Action PrintGameInfo(int client, int args) {
|
||||
//print server info
|
||||
ReplyToCommand(client, ">map,diff,mode,tempoState,totalSeconds");
|
||||
ReplyToCommand(client, ">map,diff,mode,tempoState,totalSeconds,hastank");
|
||||
int missionDuration = GetEntProp(g_icPlayerManager, Prop_Send, "m_missionDuration", 1);
|
||||
int tempoState = GetEntProp(g_icPlayerManager, Prop_Send, "m_tempoState", 1);
|
||||
ReplyToCommand(client, "%s,%s,%s,%d,%d",g_icCurrentMap,g_icDifficulty,g_icGamemode,tempoState,missionDuration);
|
||||
bool hasTank = false;
|
||||
ReplyToCommand(client, "%s,%s,%s,%d,%d,%b",g_icCurrentMap,g_icDifficulty,g_icGamemode,tempoState,missionDuration,hasTank);
|
||||
//print client info
|
||||
ReplyToCommand(client,">id,name,bot,health,status,throwSlot,kitSlot,pillSlot,survivorType,velocity,primaryWpn,secondaryWpn");
|
||||
ReplyToCommand(client,">id,transitioning,name,bot,health,status,throwSlot,kitSlot,pillSlot,survivorType,velocity,primaryWpn,secondaryWpn");
|
||||
char status[9];
|
||||
char name[32];
|
||||
char pillItem[32];
|
||||
|
@ -73,7 +79,12 @@ public Action PrintGameInfo(int client, int args) {
|
|||
char character[9];
|
||||
char primaryWeapon[32], secondaryWeapon[32];
|
||||
for (int i = 1; i <= MaxClients; i++) {
|
||||
if (!IsClientInGame(i)) continue;
|
||||
if(!IsClientConnected(i)) continue;
|
||||
if(!IsClientInGame(i)) {
|
||||
if(b_isTransitioning[i])
|
||||
ReplyToCommand(client,"%d,1", i);
|
||||
else continue;
|
||||
}
|
||||
if (GetClientTeam(i) != 2) continue;
|
||||
int hp = GetClientRealHealth(i);
|
||||
int bot = IsFakeClient(i);
|
||||
|
@ -101,6 +112,7 @@ public Action PrintGameInfo(int client, int args) {
|
|||
throwItem[0] = '\0';
|
||||
kitItem[0] = '\0';
|
||||
pillItem[0] = '\0';
|
||||
//TODO: Move all string-based stats to events
|
||||
GetItemSlotClassName(i, 0, primaryWeapon, sizeof(primaryWeapon), true);
|
||||
GetItemSlotClassName(i, 1, secondaryWeapon, sizeof(secondaryWeapon), true);
|
||||
GetItemSlotClassName(i, 2, throwItem, sizeof(throwItem), true);
|
||||
|
@ -114,7 +126,7 @@ public Action PrintGameInfo(int client, int args) {
|
|||
GetClientName(i, name, sizeof(name));
|
||||
GetModelName(i, character, sizeof(character));
|
||||
|
||||
ReplyToCommand(client,"%d,%s,%d,%d,%s,%s,%s,%s,%s,%d,%s,%s", i, name, bot, hp, status, throwItem, kitItem, pillItem, character, velocity, primaryWeapon, secondaryWeapon);
|
||||
ReplyToCommand(client,"%d,0,%s,%d,%d,%s,%s,%s,%s,%s,%d,%s,%s", i, name, bot, hp, status, throwItem, kitItem, pillItem, character, velocity, primaryWeapon, secondaryWeapon);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -122,7 +134,20 @@ public Action PrintGameInfo(int client, int args) {
|
|||
public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[] newValue) {
|
||||
cvar.GetString(g_icGamemode, sizeof(g_icGamemode));
|
||||
}
|
||||
public Action Event_MapTransition(Event event, const char[] name, bool dontBroadcast) {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2)
|
||||
b_isTransitioning[i] = true;
|
||||
}
|
||||
}
|
||||
public Action Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) {
|
||||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
if(client && b_isTransitioning[client]) {
|
||||
b_isTransitioning[client] = false;
|
||||
}
|
||||
}
|
||||
public void OnMapStart() {
|
||||
//TODO: turn off when over threshold, OR fancier logic (per player)
|
||||
GetCurrentMap(g_icCurrentMap, sizeof(g_icCurrentMap));
|
||||
//grab the player_manager
|
||||
//int playerManager;
|
||||
|
|
|
@ -14,6 +14,25 @@
|
|||
ConVar g_cMdNotify, g_cMdEnableTank, g_cMdEnableWitch, g_cMdEnableMob, g_cMdAnnounceLevel;
|
||||
bool g_bMdIsL4D2 = false;
|
||||
|
||||
int g_icSpawnStats[15];
|
||||
/*
|
||||
0 - Commons
|
||||
1 - Mob
|
||||
2 - Panics
|
||||
3 - Jockey
|
||||
4 - Hunter
|
||||
5 - Charger
|
||||
6 - Smoker
|
||||
7 - Spitter
|
||||
8 - Boomer
|
||||
9 - Witch
|
||||
10 - Tank
|
||||
11 - Weapons
|
||||
12 - Health
|
||||
13 - Throwables
|
||||
14 - Restarts (cvar?)
|
||||
*/
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = PLUGIN_NAME,
|
||||
|
@ -59,13 +78,18 @@ public void OnPluginStart()
|
|||
}
|
||||
|
||||
public Action Command_SpawnSpecial(int client, int args) {
|
||||
char arg1[32];
|
||||
char arg1[32], arg2[4];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
int amount = StringToInt(arg2);
|
||||
if(amount == 0) amount = 1;
|
||||
int executioner = GetAnyValidClient();
|
||||
if (args < 1) {
|
||||
ReplyToCommand(client, "[SM] Usage: sm_spawnspecial <hunter|smoker|boomer|spitter|charger|jockey|mob|tank|witch> - Requests a special to spawn via director", arg1);
|
||||
ReplyToCommand(client, "[SM] Usage: sm_spawnspecial <hunter|smoker|boomer|spitter|charger|jockey|mob|tank|witch> [amount] - Requests a special to spawn via director", arg1);
|
||||
} else {
|
||||
if (executioner <= 0) {
|
||||
if(amount <= 0 || amount >= MaxClients) {
|
||||
ReplyToCommand(client, "[SM] Amount specified is out of range of 1 to %d", MaxClients);
|
||||
}else if (executioner <= 0) {
|
||||
ReplyToCommand(client, "[SM] Cannot spawn a %s as there are no players online.", arg1);
|
||||
} else {
|
||||
if (StrEqual(arg1, "mob", false) && !g_cMdEnableMob.BoolValue) {
|
||||
|
@ -78,56 +102,72 @@ public Action Command_SpawnSpecial(int client, int args) {
|
|||
if(StrEqual(arg1,"panic",false)) {
|
||||
CheatCommand(executioner, "director_force_panic_event", "", "");
|
||||
}else{
|
||||
CheatCommand(executioner, g_bMdIsL4D2 ? "z_spawn_old" : "z_spawn", arg1, "auto");
|
||||
CheatCommandMultiple(executioner, amount, g_bMdIsL4D2 ? "z_spawn_old" : "z_spawn", arg1, "auto");
|
||||
}
|
||||
if (g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Director will now attempt to spawn a %s.", arg1);
|
||||
ReplyToCommand(client, "[SM] Director will now attempt to spawn %dx %s.", amount, arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
LogAction(client, -1, "\"%L\" spawned a \"%s\"", client, arg1);
|
||||
ShowActivity(client, "spawned %dx \"%s\"", amount, arg1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
public Action Command_SpawnSpecialForceLocal(int client, int args) {
|
||||
char arg1[32];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
if (args < 1) {
|
||||
ReplyToCommand(client, "[SM] Usage: sm_forcecursor <hunter|smoker|boomer|spitter|charger|jockey|mob|tank|witch> - Requests a special to spawn at cursor", arg1);
|
||||
} else {
|
||||
if(client == 0) {
|
||||
ReplyToCommand(client, "[SM] This command can only be used as a player.");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
char arg1[32], arg2[4];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
int amount = StringToInt(arg2);
|
||||
if(amount == 0) amount = 1;
|
||||
if (args < 1) {
|
||||
ReplyToCommand(client, "[SM] Usage: sm_forcecursor <hunter|smoker|boomer|spitter|charger|jockey|mob|tank|witch> [amount] - Requests a special to spawn at cursor", arg1);
|
||||
} else if(amount <= 0 || amount >= MaxClients) {
|
||||
ReplyToCommand(client, "[SM] Amount specified is out of range of 1 to %d", MaxClients);
|
||||
}else {
|
||||
if(StrEqual(arg1,"panic",false)) {
|
||||
CheatCommand(client, "director_force_panic_event", "", "");
|
||||
CheatCommand(client, "director_force_panic_event", "", "");
|
||||
}else{
|
||||
int bot = CreateFakeClient("ManualDirectorBot");
|
||||
if (bot != 0) {
|
||||
ChangeClientTeam(bot, 3);
|
||||
CreateTimer(0.1, kickbot, bot);
|
||||
}
|
||||
CheatCommand(client, g_bMdIsL4D2 ? "z_spawn_old" : "z_spawn", arg1,"");
|
||||
}
|
||||
if (g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Spawned a %s.", arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
LogAction(client, -1, "\"%L\" spawned a \"%s\"", client, arg1);
|
||||
for(int i = 0; i < amount; i++) {
|
||||
int bot = CreateFakeClient("ManualDirectorBot");
|
||||
if (bot != 0) {
|
||||
ChangeClientTeam(bot, 3);
|
||||
CreateTimer(0.1, kickbot, bot);
|
||||
}
|
||||
CheatCommand(client, g_bMdIsL4D2 ? "z_spawn_old" : "z_spawn", arg1,"");
|
||||
}
|
||||
}
|
||||
if(g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Spawned %dx %s.", amount, arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
ShowActivity(client, "cursor spawned %dx \"%s\"", amount, arg1);
|
||||
}
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public Action Command_SpawnSpecialForce(int client, int args) {
|
||||
char arg1[32];
|
||||
char arg1[32], arg2[4];
|
||||
GetCmdArg(1, arg1, sizeof(arg1));
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
int amount = StringToInt(arg2);
|
||||
if(amount == 0) amount = 1;
|
||||
int executioner = GetAnyValidClient();
|
||||
if (args < 1) {
|
||||
ReplyToCommand(client, "[SM] Usage: sm_forcespecial <hunter|smoker|boomer|spitter|charger|jockey|mob|tank|witch> - Requests a special to spawn via director", arg1);
|
||||
} else {
|
||||
if (executioner <= 0) {
|
||||
ReplyToCommand(client, "[SM] Cannot spawn a %s as there are no players online.", arg1);
|
||||
} else {
|
||||
if(StrEqual(arg1,"panic",false)) {
|
||||
CheatCommand(executioner, "director_force_panic_event", "", "");
|
||||
}else{
|
||||
} else if (executioner <= 0) {
|
||||
ReplyToCommand(client, "[SM] Cannot spawn a %s as there are no players online.", arg1);
|
||||
} else if(amount <= 0 || amount >= MaxClients) {
|
||||
ReplyToCommand(client, "[SM] Amount specified is out of range of 1 to %d", MaxClients);
|
||||
}else {
|
||||
if(StrEqual(arg1,"panic",false)) {
|
||||
CheatCommand(executioner, "director_force_panic_event", "", "");
|
||||
}else{
|
||||
for(int i = 0; i < amount; i++) {
|
||||
int bot = CreateFakeClient("ManualDirectorBot");
|
||||
if (bot != 0) {
|
||||
ChangeClientTeam(bot, 3);
|
||||
|
@ -135,12 +175,12 @@ public Action Command_SpawnSpecialForce(int client, int args) {
|
|||
}
|
||||
CheatCommand(executioner, g_bMdIsL4D2 ? "z_spawn_old" : "z_spawn", arg1, "auto");
|
||||
}
|
||||
if (g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Spawned a %s.", arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
LogAction(client, -1, "\"%L\" spawned a \"%s\"", client, arg1);
|
||||
}
|
||||
if (g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Spawned a %dx %s.", amount, arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
ShowActivity(client, "forced spawned %dx \"%s\"", amount, arg1);
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
@ -163,14 +203,16 @@ public Action ShowSpecialMenu(int client, int args) {
|
|||
menu.Display(client, 0);
|
||||
}
|
||||
public Action ShowLocalSpecialMenu(int client, int args) {
|
||||
Menu menu = new Menu(Handle_LocalSpawnMenu);
|
||||
menu.SetTitle("Manual Director - Cursor");
|
||||
menu.AddItem("common", "Single Common");
|
||||
if (g_bMdIsL4D2) {
|
||||
Menu menu = new Menu(Handle_LocalSpawnMenu);
|
||||
menu.SetTitle("Manual Director - Cursor");
|
||||
menu.AddItem("common", "Single Common");
|
||||
|
||||
if (g_bMdIsL4D2) {
|
||||
menu.AddItem("jockey", "Jockey");
|
||||
menu.AddItem("charger", "Charger");
|
||||
menu.AddItem("spitter", "Spitter");
|
||||
}
|
||||
|
||||
menu.AddItem("hunter", "Hunter");
|
||||
menu.AddItem("smoker", "Smoker");
|
||||
menu.AddItem("boomer", "Boomer");
|
||||
|
@ -229,14 +271,33 @@ stock Action kickbot(Handle timer, int client)
|
|||
if (IsFakeClient(client))KickClient(client);
|
||||
}
|
||||
}
|
||||
int FindStatIndex(const char[] type) {
|
||||
return SpawnStats
|
||||
if (StrEqual(type, "common") return 0;
|
||||
else if (StrEqual(type, "mob")) return 1;
|
||||
else if (StrEqual(type, "panic")) return 2;
|
||||
else if (StrEqual(type, "jockey")) return 3;
|
||||
else if (StrEqual(type, "hunter")) return 4;
|
||||
else if (StrEqual(type, "charger")) return 5;
|
||||
else if (StrEqual(type, "smoker")) return 6;
|
||||
else if (StrEqual(type, "spitter")) return 7;
|
||||
else if (StrEqual(type, "boomer")) return 8;
|
||||
else if (StrEqual(type, "witch")) return 9;
|
||||
else if (StrEqual(type, "tank")) return 10;
|
||||
else if (StrEqual(type, "weapon")) return 11;
|
||||
else if (StrEqual(type, "health")) return 12;
|
||||
else if (StrEqual(type, "throwable")) return 13;
|
||||
else if (StrEqual(type, "restart")) return 14;
|
||||
else return sizeof(g_icSpawnStats);
|
||||
}
|
||||
stock void UpdateIndex(char[] type) {
|
||||
int index = FindStatIndex(type);
|
||||
g_icSpawnStats[index]++;
|
||||
}
|
||||
|
||||
|
||||
stock int GetAnyValidClient()
|
||||
{
|
||||
for (int i = 1; i <= MaxClients; i++)
|
||||
{
|
||||
if (IsClientInGame(i) && !IsFakeClient(i))
|
||||
{
|
||||
stock int GetAnyValidClient() {
|
||||
for (int i = 1; i <= MaxClients; i++) {
|
||||
if (IsClientInGame(i) && !IsFakeClient(i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
@ -253,6 +314,18 @@ stock void CheatCommand(int client, const char[] command, const char[] argument1
|
|||
SetCommandFlags(command, flags);
|
||||
SetUserFlagBits(client, userFlags);
|
||||
}
|
||||
stock void CheatCommandMultiple(int client, int count, const char[] command, const char[] argument1, const char[] argument2)
|
||||
{
|
||||
int userFlags = GetUserFlagBits(client);
|
||||
SetUserFlagBits(client, ADMFLAG_ROOT);
|
||||
int flags = GetCommandFlags(command);
|
||||
SetCommandFlags(command, flags & ~FCVAR_CHEAT);
|
||||
for(int i = 0; i < count; i++) {
|
||||
FakeClientCommand(client, "%s %s %s", command, argument1, argument2);
|
||||
}
|
||||
SetCommandFlags(command, flags);
|
||||
SetUserFlagBits(client, userFlags);
|
||||
}
|
||||
|
||||
void AnnounceSpawn(const char[] type) {
|
||||
switch(g_cMdAnnounceLevel.IntValue) {
|
||||
|
|
|
@ -106,7 +106,7 @@ public Action Command_SpawnMinigunBot(int client, int args) {
|
|||
//make sure spawns a little above
|
||||
vPos[2] += 1.0;
|
||||
|
||||
int survivor = SpawnSurvivor(vPos, vAng, model, true);
|
||||
int survivor = GetClientOfUserId(SpawnSurvivor(vPos, vAng, model, true));
|
||||
if(survivor > 0) {
|
||||
GiveClientWeapon(survivor, "rifle_ak47", true);
|
||||
}else{
|
||||
|
|
|
@ -71,6 +71,7 @@ public void OnPluginStart() {
|
|||
|
||||
HookEvent("player_disconnect", Event_PlayerDisconnect);
|
||||
HookEvent("player_death", Event_PlayerDeath);
|
||||
AddNormalSoundHook(view_as<NormalSHook>(SoundHook));
|
||||
|
||||
AutoExecConfig(true, "l4d2_feedthetrolls");
|
||||
|
||||
|
@ -93,6 +94,7 @@ public void OnMapEnd() {
|
|||
public void OnMapStart() {
|
||||
HookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
|
||||
CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||
PrecacheSound("player/footsteps/clown/concrete1.wav");
|
||||
//CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
public void Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) {
|
||||
|
@ -144,34 +146,32 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
|
|||
// =========================
|
||||
if(hMagnetChance.FloatValue < GetRandomFloat()) return Plugin_Continue;
|
||||
L4D2Infected class = view_as<L4D2Infected>(GetEntProp(attacker, Prop_Send, "m_zombieClass"));
|
||||
if(class != L4D2Infected_Tank) {
|
||||
int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]);
|
||||
if(existingTarget > 0 && IsClientInGame(existingTarget) && IsPlayerAlive(existingTarget)) {
|
||||
curTarget = existingTarget;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
int existingTarget = GetClientOfUserId(g_iAttackerTarget[attacker]);
|
||||
if(existingTarget > 0 && IsPlayerAlive(existingTarget)) {
|
||||
curTarget = existingTarget;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
||||
float closestDistance, survPos[3], spPos[3];
|
||||
GetClientAbsOrigin(attacker, spPos);
|
||||
int closestClient = -1;
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
|
||||
if(class == L4D2Infected_Tank && HasTrollMode(i, Troll_TankMagnet) || (class != L4D2Infected_Tank && HasTrollMode(i, Troll_SpecialMagnet))) {
|
||||
GetClientAbsOrigin(i, survPos);
|
||||
float dist = GetVectorDistance(survPos, spPos, true);
|
||||
if(closestClient == -1 || dist < closestDistance) {
|
||||
closestDistance = dist;
|
||||
closestClient = i;
|
||||
}
|
||||
float closestDistance, survPos[3], spPos[3];
|
||||
GetClientAbsOrigin(attacker, spPos);
|
||||
int closestClient = -1;
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
|
||||
if(class == L4D2Infected_Tank && HasTrollMode(i, Troll_TankMagnet) || (class != L4D2Infected_Tank && HasTrollMode(i, Troll_SpecialMagnet))) {
|
||||
GetClientAbsOrigin(i, survPos);
|
||||
float dist = GetVectorDistance(survPos, spPos, true);
|
||||
if(closestClient == -1 || dist < closestDistance) {
|
||||
closestDistance = dist;
|
||||
closestClient = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(closestClient > 0) {
|
||||
g_iAttackerTarget[attacker] = GetClientUserId(closestClient);
|
||||
curTarget = closestClient;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
}
|
||||
|
||||
if(closestClient > 0) {
|
||||
g_iAttackerTarget[attacker] = GetClientUserId(closestClient);
|
||||
curTarget = closestClient;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
@ -193,6 +193,7 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
|
|||
char[] message = new char[length];
|
||||
ImplodeStrings(strings, 32, " ", message, length);
|
||||
CPrintToChatAll("{blue}%N {default}: %s", client, message);
|
||||
PrintToServer("%N: %s", client, sArgs);
|
||||
return Plugin_Handled;
|
||||
}else if(HasTrollMode(client, Troll_iCantSpellNoMore)) {
|
||||
int type = GetRandomInt(1, 33);
|
||||
|
@ -254,7 +255,6 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
|
|||
default:
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
int strLength = strlen(sArgs);
|
||||
char[] newMessage = new char[strLength + 20];
|
||||
int n = 0;
|
||||
|
@ -266,6 +266,7 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
|
|||
}
|
||||
n++;
|
||||
}
|
||||
PrintToServer("%N: %s", client, sArgs);
|
||||
CPrintToChatAll("{blue}%N {default}: %s", client, newMessage);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
@ -320,11 +321,25 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
return Plugin_Continue;
|
||||
}
|
||||
public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
|
||||
if(attacker > 0 && attacker <= MaxClients && HasTrollMode(attacker, Troll_DamageBoost)) {
|
||||
if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker) && HasTrollMode(attacker, Troll_DamageBoost)) {
|
||||
damage * 2;
|
||||
}
|
||||
}
|
||||
|
||||
public Action SoundHook(int[] clients, int& numClients, char sample[PLATFORM_MAX_PATH], int& entity, int& channel, float& volume, int& level, int& pitch, int& flags, char[] soundEntry, int& seed) {
|
||||
if(numClients > 0 && entity > 0 && entity <= MaxClients) {
|
||||
if(HasTrollMode(entity, Troll_Honk)) {
|
||||
if(StrContains(sample, "survivor/voice") > -1) {
|
||||
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
|
||||
return Plugin_Changed;
|
||||
}
|
||||
}else if(HasTrollMode( entity, Troll_VocalizeGag)) {
|
||||
if(StrContains(sample, "player\\survivor\\voice") > -1) {
|
||||
return Plugin_Stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Plugin_Continue;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CVAR CHANGES
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -438,9 +453,7 @@ public Action Command_ListTheTrolls(int client, int args) {
|
|||
char modeListArr[TROLL_MODE_COUNT][32];
|
||||
for(int mode = 1; mode < TROLL_MODE_COUNT; mode++) {
|
||||
//If troll mode exists:
|
||||
bool hasTrollMode = HasTrollMode(i, view_as<trollMode>(mode));
|
||||
PrintToConsole(i, "[%d]: #%d %s value: %b", modes, mode, TROLL_MODES_NAMES[mode], hasTrollMode);
|
||||
if(hasTrollMode) {
|
||||
if(HasTrollMode(i, view_as<trollMode>(mode))) {
|
||||
modeListArr[modeCount] = TROLL_MODES_NAMES[mode];
|
||||
modeCount++;
|
||||
}
|
||||
|
|
209
scripting/l4d_reservetheserver.sp
Normal file
209
scripting/l4d_reservetheserver.sp
Normal file
|
@ -0,0 +1,209 @@
|
|||
#define PLUGIN_VERSION "1.1.0"
|
||||
#define MAX_LINE_WIDTH 64
|
||||
|
||||
#define MESSAGE_FOR_PLAYERS_LINE1 ""
|
||||
#define MESSAGE_FOR_PLAYERS_LINE2 "\x04RECEIVED SERVER RESERVATION REQUEST"
|
||||
#define MESSAGE_FOR_PLAYERS_LINE3 "\x04YOU WILL BE RETURNED TO LOBBY"
|
||||
#define MESSAGE_FOR_PLAYERS_LINE4 ""
|
||||
|
||||
#pragma semicolon 1
|
||||
|
||||
#include <sourcemod>
|
||||
|
||||
#pragma newdecls required
|
||||
|
||||
ConVar PluginCvarSearchKey, PluginCvarMode, PluginCvarTimeout, PluginCvarImmuneLevel,
|
||||
SteamGroupExclusiveCvar, SearchKeyCvar, HibernationCvar;
|
||||
|
||||
int HibernationCvarValue;
|
||||
bool isMapChange = false, doRestartMap = false;
|
||||
char PluginSearchKeyString[MAX_LINE_WIDTH] = "", PluginCvarImmuneFlagString[MAX_LINE_WIDTH] = "", CurrentMapString[MAX_LINE_WIDTH] = "";
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "Reserve The Server",
|
||||
author = "Jack'lul [Edited by Dosergen]",
|
||||
description = "Frees the server from all players and reserves it.",
|
||||
version = PLUGIN_VERSION,
|
||||
url = "https://forums.alliedmods.net/showthread.php?p=2084993"
|
||||
}
|
||||
|
||||
public void OnPluginStart() {
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
if(g_Game != Engine_Left4Dead && g_Game != Engine_Left4Dead2) {
|
||||
SetFailState("This plugin is for L4D/L4D2 only.");
|
||||
}
|
||||
|
||||
CreateConVar("l4d_rts_version", PLUGIN_VERSION, "Reserve The Server plugin version", 0|FCVAR_NOTIFY|FCVAR_SPONLY|FCVAR_REPLICATED|FCVAR_DONTRECORD);
|
||||
PluginCvarMode = CreateConVar("l4d_rts_mode", "1", "0 - only remove players using lobby vote, 1 - remove players using lobby vote and then disconnect server from matchmaking", 0, true, 0.0, true, 1.0);
|
||||
PluginCvarSearchKey = CreateConVar("l4d_rts_searchkey", "", "sv_search_key will be set to this while server is reserved", 0);
|
||||
PluginCvarTimeout = CreateConVar("l4d_rts_timeout", "30", "How long will the server stay disconnected from matchmaking? 0 - never restore matchmaking connection", 0, true, 0.0, true, 300.0);
|
||||
PluginCvarImmuneLevel = CreateConVar("l4d_rts_immunelevel", "1", "Any player >= to this level will cancel the lobby vote.", 0);
|
||||
|
||||
RegAdminCmd("sm_rts", Command_MakeReservation, ADMFLAG_ROOT, "Free the server from all players, then reserve it.");
|
||||
RegAdminCmd("sm_cr", Command_CancelReservation, ADMFLAG_ROOT, "Cancel reservation and make server public again.");
|
||||
|
||||
SteamGroupExclusiveCvar = FindConVar("sv_steamgroup_exclusive");
|
||||
SearchKeyCvar = FindConVar("sv_search_key");
|
||||
HibernationCvar = FindConVar("sv_hibernate_when_empty");
|
||||
HibernationCvarValue = GetConVarInt(HibernationCvar);
|
||||
|
||||
AutoExecConfig(true, "l4d_rts");
|
||||
}
|
||||
|
||||
public void OnClientDisconnect(int client) {
|
||||
if (client == 0 || isMapChange || IsFakeClient(client))
|
||||
return;
|
||||
|
||||
if(doRestartMap == true)
|
||||
CreateTimer(1.0, MapReloadCheck);
|
||||
}
|
||||
|
||||
public void OnMapEnd() {
|
||||
isMapChange = true;
|
||||
doRestartMap = false;
|
||||
}
|
||||
|
||||
public void OnMapStart() {
|
||||
isMapChange = false;
|
||||
}
|
||||
|
||||
public Action Command_MakeReservation(int client, int args) {
|
||||
int isAdminOnline = 0, notConnected = 0, iMaxClients = MaxClients;
|
||||
for (int iClient = 1; iClient <= iMaxClients; iClient++) {
|
||||
if (IsClientConnected (iClient) && IsClientInGame (iClient)) {
|
||||
AdminId admin = GetUserAdmin(iClient);
|
||||
if (GetAdminImmunityLevel(admin) >= PluginCvarImmuneLevel.IntValue) {
|
||||
isAdminOnline = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else notConnected++;
|
||||
}
|
||||
|
||||
if(!isAdminOnline)
|
||||
{
|
||||
LogMessage("Received server reservation request.");
|
||||
if(notConnected < iMaxClients)
|
||||
{
|
||||
if(GetConVarInt(PluginCvarMode)==1)
|
||||
{
|
||||
doRestartMap = true;
|
||||
ReplyToCommand(client, "Server will be freed from all players and reserved.");
|
||||
}
|
||||
else
|
||||
ReplyToCommand(client, "Server will be freed from all players.");
|
||||
|
||||
PrintToChatAll(MESSAGE_FOR_PLAYERS_LINE1);
|
||||
PrintToChatAll(MESSAGE_FOR_PLAYERS_LINE2);
|
||||
PrintToChatAll(MESSAGE_FOR_PLAYERS_LINE3);
|
||||
PrintToChatAll(MESSAGE_FOR_PLAYERS_LINE4);
|
||||
|
||||
CreateTimer(5.0, FreeTheServer);
|
||||
}
|
||||
else if(GetConVarInt(PluginCvarMode)==1)
|
||||
{
|
||||
DisconnectFromMatchmaking();
|
||||
ReloadMap();
|
||||
}
|
||||
}
|
||||
else
|
||||
ReplyToCommand(client, "Server reservation request denied - admin is online!");
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action Command_CancelReservation(int client, int args)
|
||||
{
|
||||
CreateTimer(0.1, MakeServerPublic);
|
||||
}
|
||||
|
||||
public Action FreeTheServer(Handle timer)
|
||||
{
|
||||
CallLobbyVote();
|
||||
PassVote();
|
||||
|
||||
if(GetConVarInt(PluginCvarMode)==1)
|
||||
{
|
||||
DisconnectFromMatchmaking();
|
||||
}
|
||||
}
|
||||
|
||||
public Action MakeServerPublic(Handle timer)
|
||||
{
|
||||
ConnectToMatchmaking();
|
||||
|
||||
int notConnected = 0, iMaxClients = MaxClients;
|
||||
for (int iClient = 1; iClient <= iMaxClients; iClient++)
|
||||
{
|
||||
if (IsClientConnected (iClient) && IsClientInGame (iClient))
|
||||
break;
|
||||
else
|
||||
notConnected++;
|
||||
}
|
||||
|
||||
if(notConnected==iMaxClients)
|
||||
ReloadMap();
|
||||
|
||||
if(HibernationCvarValue != 0 && GetConVarInt(HibernationCvar) == 0)
|
||||
SetConVarInt(HibernationCvar, 1);
|
||||
}
|
||||
|
||||
public Action MapReloadCheck(Handle timer)
|
||||
{
|
||||
if (isMapChange)
|
||||
return;
|
||||
|
||||
if(doRestartMap == true)
|
||||
{
|
||||
doRestartMap = false;
|
||||
ReloadMap();
|
||||
}
|
||||
}
|
||||
|
||||
void CallLobbyVote()
|
||||
{
|
||||
for (int iClient = 1; iClient <= MaxClients; iClient++)
|
||||
{
|
||||
if (IsClientConnected (iClient) && IsClientInGame (iClient))
|
||||
{
|
||||
FakeClientCommand (iClient, "callvote returntolobby");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PassVote()
|
||||
{
|
||||
for(int iClient = 1; iClient <= MaxClients; iClient++)
|
||||
{
|
||||
if (IsClientConnected (iClient) && IsClientInGame (iClient))
|
||||
{
|
||||
FakeClientCommand(iClient, "Vote Yes");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ReloadMap()
|
||||
{
|
||||
GetCurrentMap(CurrentMapString, sizeof(CurrentMapString));
|
||||
ServerCommand("map %s", CurrentMapString);
|
||||
}
|
||||
|
||||
void DisconnectFromMatchmaking()
|
||||
{
|
||||
GetConVarString(PluginCvarSearchKey, PluginSearchKeyString, sizeof(PluginSearchKeyString));
|
||||
SetConVarInt(SteamGroupExclusiveCvar, 1);
|
||||
SetConVarString(SearchKeyCvar, PluginSearchKeyString);
|
||||
|
||||
if(HibernationCvarValue != 0)
|
||||
SetConVarInt(HibernationCvar, 0);
|
||||
|
||||
if(GetConVarFloat(PluginCvarTimeout)>0)
|
||||
CreateTimer(GetConVarFloat(PluginCvarTimeout), MakeServerPublic);
|
||||
}
|
||||
|
||||
void ConnectToMatchmaking()
|
||||
{
|
||||
SetConVarInt(SteamGroupExclusiveCvar, 0);
|
||||
SetConVarString(SearchKeyCvar, "");
|
||||
}
|
110
scripting/tf2_botcaptcha.sp
Normal file
110
scripting/tf2_botcaptcha.sp
Normal file
|
@ -0,0 +1,110 @@
|
|||
#pragma semicolon 1
|
||||
|
||||
#define MAX_CODE_SIZE 8
|
||||
#define KICK_REASON "Did not submit a valid verification code in time."
|
||||
#define VERIFICATION_MSG "Welcome! Please enter this code in chat to play: %s"
|
||||
#define VERIFICATION_SUCCESS "Thank you for verifying. Have fun!"
|
||||
#define VERIFICATION_FAIL "Invalid verification code. %d tries remaining."
|
||||
#define VERIFICATION_TIME 120.0
|
||||
|
||||
#define DEBUG
|
||||
#define PLUGIN_VERSION "0.1.0"
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <tf2>
|
||||
#include <tf2_stocks>
|
||||
//#include <sdkhooks>
|
||||
|
||||
|
||||
static char captchas[MAXPLAYERS+1][MAX_CODE_SIZE+1];
|
||||
static Handle captchaKickTimer[MAXPLAYERS+1];
|
||||
static int captchaTriesRemaining[MAXPLAYERS+1];
|
||||
static TFTeam playerTeam[MAXPLAYERS+1];
|
||||
static TFClassType playerClass[MAXPLAYERS+1];
|
||||
|
||||
public Plugin myinfo = {
|
||||
name = "TF2 Captcha",
|
||||
author = "Jackz",
|
||||
description = "",
|
||||
version = PLUGIN_VERSION,
|
||||
url = ""
|
||||
};
|
||||
|
||||
public void OnPluginStart() {
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
if(g_Game != Engine_TF2) {
|
||||
SetFailState("This plugin is for TF2 only.");
|
||||
}
|
||||
|
||||
HookEvent("player_changeclass", Event_PlayerChangeClass);
|
||||
HookEvent("player_team", Event_PlayerSwitchTeam);
|
||||
HookEvent("player_disconnect", Event_PlayerDisconnect);
|
||||
}
|
||||
|
||||
public Action Event_PlayerSwitchTeam(Event event, const char[] name, bool dontBroadcast) {
|
||||
int userid = event.GetInt("userid");
|
||||
int client = GetClientOfUserId(userid);
|
||||
if(client > 0 && captchaKickTimer[client] != INVALID_HANDLE) {
|
||||
RequestFrame(Frame_SwitchTeam, client);
|
||||
}
|
||||
}
|
||||
|
||||
public void Frame_SwitchTeam(int userid) {
|
||||
int client = GetClientOfUserId(userid);
|
||||
if(client > 0)
|
||||
TF2_ChangeClientTeam(client, TFTeam_Spectator);
|
||||
}
|
||||
|
||||
public Action Event_PlayerChangeClass(Event event, const char[] name, bool dontBroadcast) {
|
||||
int userid = event.GetInt("userid");
|
||||
int client = GetClientOfUserId(userid);
|
||||
|
||||
if(client > 0 && captchas[client][0] == '\0' && !IsFakeClient(client)) {
|
||||
playerTeam[client] = TF2_GetClientTeam(client);
|
||||
playerClass[client] = TF2_GetPlayerClass(client);
|
||||
TF2_ChangeClientTeam(client, TFTeam_Spectator);
|
||||
for(int i = 0; i < MAX_CODE_SIZE; i++) {
|
||||
captchas[client][i] = GetRandomInt(0, 9)+ '0';
|
||||
}
|
||||
captchas[client][MAX_CODE_SIZE] = '\0';
|
||||
captchaTriesRemaining[client] = 3;
|
||||
PrintToChat(client, VERIFICATION_MSG, captchas[client]);
|
||||
captchaKickTimer[client] = CreateTimer(VERIFICATION_TIME, Timer_Kick, userid);
|
||||
}
|
||||
}
|
||||
|
||||
public Action Timer_Kick(Handle handle, int userid) {
|
||||
int client = GetClientOfUserId(userid);
|
||||
if(client > 0)
|
||||
KickClient(client, KICK_REASON);
|
||||
}
|
||||
|
||||
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
|
||||
if(captchaKickTimer[client] != INVALID_HANDLE) {
|
||||
if(StrEqual(sArgs, captchas[client])) {
|
||||
CloseHandle(captchaKickTimer[client]);
|
||||
captchaKickTimer[client] = INVALID_HANDLE;
|
||||
PrintToChat(client, VERIFICATION_SUCCESS);
|
||||
TF2_ChangeClientTeam(client, playerTeam[client]);
|
||||
//TF2_SetPlayerClass(client, playerClass[client]);
|
||||
}else{
|
||||
if(--captchaTriesRemaining[client] == 0) {
|
||||
TriggerTimer(captchaKickTimer[client]);
|
||||
captchaKickTimer[client] = INVALID_HANDLE;
|
||||
}else{
|
||||
PrintToChat(client, VERIFICATION_FAIL, captchaTriesRemaining[client]);
|
||||
}
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
public void OnClientDisconnect(int client) {
|
||||
}
|
||||
|
||||
public Action Event_PlayerDisconnect(Event event, const char[] name, bool dontBroadcast) {
|
||||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
captchas[client][0] = '\0';
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue