mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-06 12:23:21 +00:00
Bulk update
This commit is contained in:
parent
f37301cae8
commit
9adbe21719
22 changed files with 1221 additions and 103 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
plugins/l4d_reservetheserver.smx
Normal file
BIN
plugins/l4d_reservetheserver.smx
Normal file
Binary file not shown.
BIN
plugins/tf2_botcaptcha.smx
Normal file
BIN
plugins/tf2_botcaptcha.smx
Normal file
Binary file not shown.
|
@ -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,27 +102,37 @@ 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];
|
||||
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> - Requests a special to spawn at cursor", arg1);
|
||||
} else {
|
||||
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", "", "");
|
||||
}else{
|
||||
for(int i = 0; i < amount; i++) {
|
||||
int bot = CreateFakeClient("ManualDirectorBot");
|
||||
if (bot != 0) {
|
||||
ChangeClientTeam(bot, 3);
|
||||
|
@ -106,28 +140,34 @@ public Action Command_SpawnSpecialForceLocal(int client, int args) {
|
|||
}
|
||||
CheatCommand(client, g_bMdIsL4D2 ? "z_spawn_old" : "z_spawn", arg1,"");
|
||||
}
|
||||
if (g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Spawned a %s.", arg1);
|
||||
}
|
||||
if(g_cMdNotify.BoolValue) {
|
||||
ReplyToCommand(client, "[SM] Spawned %dx %s.", amount, arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
LogAction(client, -1, "\"%L\" spawned a \"%s\"", client, 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) {
|
||||
} else if (executioner <= 0) {
|
||||
ReplyToCommand(client, "[SM] Cannot spawn a %s as there are no players online.", arg1);
|
||||
} else {
|
||||
} 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);
|
||||
ReplyToCommand(client, "[SM] Spawned a %dx %s.", amount, arg1);
|
||||
}
|
||||
AnnounceSpawn(arg1);
|
||||
LogAction(client, -1, "\"%L\" spawned a \"%s\"", client, arg1);
|
||||
}
|
||||
ShowActivity(client, "forced spawned %dx \"%s\"", amount, arg1);
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
@ -166,11 +206,13 @@ 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.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,9 +146,8 @@ 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)) {
|
||||
if(existingTarget > 0 && IsPlayerAlive(existingTarget)) {
|
||||
curTarget = existingTarget;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
|
@ -172,7 +173,6 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
|
|||
curTarget = closestClient;
|
||||
return Plugin_Changed;
|
||||
}
|
||||
}
|
||||
return Plugin_Continue;
|
||||
}
|
||||
public Action L4D2_OnEntityShoved(int client, int entity, int weapon, float vecDir[3], bool bIsHighPounce) {
|
||||
|
@ -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