Update some plugins to sm1.11

This commit is contained in:
Jackz 2022-07-02 21:39:36 -05:00
parent 6426e525db
commit 0907cc7735
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
6 changed files with 236 additions and 153 deletions

Binary file not shown.

Binary file not shown.

View file

@ -3,14 +3,6 @@
#endif
#define l4d2_weapons_inc_
#define GETWEAPONNAME(%0) (IsValidWeaponId(WeaponId (%0)) ? (WeaponNames[(%0)]) : "")
#define GETLONGWEAPONNAME(%0) (IsValidWeaponId(WeaponId (%0)) ? (LongWeaponNames[(%0)]) : "")
#define GETMELEEWEAPONNAME(%0) (IsValidWeaponId(MeleeWeaponId (%0)) ? (MeleeWeaponNames[(%0)]) : "")
#define GETLONGMELEEWEAPONNAME(%0) (IsValidWeaponId(MeleeWeaponId (%0)) ? (LongMeleeWeaponNames[(%0)]) : "")
#define GETWEAPONMODEL(%0) (HasValidWeaponModel(WeaponId (%0)) ? (WeaponModels[(%0)]) : "")
#define GETMELEEWEAPONMODEL(%0) (HasValidWeaponModel(MeleeWeaponId (%0)) ? (MeleeWeaponModels[(%0)]) : "")
// Weapon ID enumerations.
// These values are *NOT* arbitrary!
// They are used in game as the weaponid for weapon_spawn entities
@ -69,7 +61,8 @@ enum WeaponId {
WEPID_ROCK, // 52
WEPID_PHYSICS, // 53
WEPID_AMMO, // 54
WEPID_UPGRADE_ITEM // 55
WEPID_UPGRADE_ITEM, // 55
WEPID_COUNT
};
// These values are arbitrary
@ -89,7 +82,8 @@ enum MeleeWeaponId
WEPID_KATANA,
WEPID_MACHETE,
WEPID_RIOT_SHIELD,
WEPID_TONFA
WEPID_TONFA,
WEPID_MELEE_COUNT
};
// Weapon names for each of the weapons, used in identification.
@ -139,7 +133,7 @@ char LongWeaponNames[56][] = {
};
// Internal names for melee weapons
char MeleeWeaponNames[MeleeWeaponId][] =
char MeleeWeaponNames[WEPID_MELEE_COUNT][] =
{
"",
"knife",
@ -159,7 +153,7 @@ char MeleeWeaponNames[MeleeWeaponId][] =
};
// Long melee weapon names
char LongMeleeWeaponNames[MeleeWeaponId][] =
char LongMeleeWeaponNames[WEPID_MELEE_COUNT][] =
{
"None",
"Knife",
@ -332,13 +326,13 @@ static Handle hMeleeWeaponModelsTrie = INVALID_HANDLE;
stock void InitWeaponNamesTrie() {
hWeaponNamesTrie = CreateTrie();
for(int i = 0; i < view_as<int>(WeaponId); i++) {
for(int i = 0; i < view_as<int>(WEPID_COUNT); i++) {
SetTrieValue(hWeaponNamesTrie, WeaponNames[i], i);
}
hMeleeWeaponNamesTrie = CreateTrie();
hMeleeWeaponModelsTrie = CreateTrie();
for (int i = 0; i < view_as<int>(MeleeWeaponId); ++i)
for (int i = 0; i < view_as<int>(WEPID_MELEE_COUNT); ++i)
{
SetTrieValue(hMeleeWeaponNamesTrie, MeleeWeaponNames[i], i);
SetTrieString(hMeleeWeaponModelsTrie, MeleeWeaponModels[i], MeleeWeaponNames[i]);
@ -357,7 +351,7 @@ stock bool IsValidWeaponId(WeaponId wepid){
}
stock bool IsValidMeleeWeaponId(MeleeWeaponId wepid) {
return MeleeWeaponId:wepid >= WEPID_MELEE_NONE && MeleeWeaponId:wepid < MeleeWeaponId;
return wepid >= WEPID_MELEE_NONE && wepid < WEPID_MELEE_COUNT;
}
/**
@ -382,9 +376,7 @@ stock bool HasValidWeaponModel(WeaponId wepid) {
}
stock bool HasValidMeleeWeaponModel(MeleeWeaponId wepid) {
if (tagType == tagof(MeleeWeaponId)) {
return IsValidWeaponId(MeleeWeaponId:wepid) && MeleeWeaponModels[MeleeWeaponId:wepid][0] != '\0';
}
return IsValidMeleeWeaponId(wepid) && MeleeWeaponModels[wepid][0] != '\0';
}
/**
@ -429,11 +421,13 @@ stock int GetMeleeWeaponName(WeaponId wepid, char[] nameBuffer, int length) {
* @return Number of bytes written to buffer, or 0 for invalid weaponId.
*/
stock int GetLongWeaponName(WeaponId wepid, char[] nameBuffer, int length) {
strcopy(nameBuffer, length, GETLONGMELEEWEAPONNAME(wepid));
if(!IsValidWeaponId(wepid)) return 0;
return strcopy(nameBuffer, length, LongWeaponNames[wepid]);
}
stock int GetLongMeleeWeaponName(WeaponId wepid, char[] nameBuffer, int length) {
strcopy(nameBuffer, length, GETLONGWEAPONNAME(wepid));
stock int GetLongMeleeWeaponName(MeleeWeaponId wepid, char[] nameBuffer, int length) {
if(!IsValidMeleeWeaponId(wepid)) return 0;
return strcopy(nameBuffer, length, LongMeleeWeaponNames[wepid]);
}
/**
@ -445,12 +439,14 @@ stock int GetLongMeleeWeaponName(WeaponId wepid, char[] nameBuffer, int length)
* @param length Max length which can be written to the buffer.
* @return Number of bytes written to buffer, or 0 for invalid weaponid or no weapon model available.
*/
stock int GetWeaponModel(MeleeWeaponId wepid, char[] modelBuffer, int length) {
strcopy(modelBuffer, length, GETWEAPONMODEL(wepid));
stock int GetWeaponModel(WeaponId wepid, char[] modelBuffer, int length) {
if(!HasValidWeaponModel(wepid)) return 0;
return strcopy(modelBuffer, length, WeaponModels[wepid]);
}
stock int GetMeleeWeaponModel(MeleeWeaponId wepid, char[] modelBuffer, int length) {
strcopy(modelBuffer, length, GETMELEEWEAPONMODEL(wepid));
if(!HasValidMeleeWeaponModel(wepid)) return 0;
return strcopy(modelBuffer, length, MeleeWeaponModels[wepid]);
}
/**
@ -533,7 +529,7 @@ stock MeleeWeaponId IdentifyMeleeWeapon(int entity) {
int id;
if(GetTrieValue(hMeleeWeaponNamesTrie, sName, id)) {
return id;
return view_as<MeleeWeaponId>(id);
}
return WEPID_MELEE_NONE;
}
@ -549,14 +545,14 @@ stock MeleeWeaponId IdentifyMeleeWeapon(int entity) {
* @param model World model to use for the weapon spawn
* @return entity of the new weapon spawn, or -1 on errors.
*/
stock int ConvertWeaponSpawn(int entity, WeaponId wepid, int count = 5, const char model[] = "")
stock int ConvertWeaponSpawn(int entity, WeaponId wepid, int count = 5, const char[] model = "")
{
if(!IsValidEntity(entity)) return -1;
if(!IsValidWeaponId(wepid)) return -1;
if(model[0] == '\0' && !HasValidWeaponModel(wepid)) return -1;
new Float:origins[3], Float:angles[3];
float origins[3], angles[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origins);
GetEntPropVector(entity, Prop_Send, "m_angRotation", angles);
@ -567,7 +563,7 @@ stock int ConvertWeaponSpawn(int entity, WeaponId wepid, int count = 5, const ch
SetEntProp(entity, Prop_Send, "m_weaponID", wepid);
decl String:buf[64];
char buf[64];
if(model[0] == '\0') {
SetEntityModel(entity, model);
} else {

View file

@ -661,7 +661,7 @@ stock int L4D_GetPendingTankPlayer()
* @return True if glow was set, false if entity does not support glow.
*/
// L4D2 only.
stock bool L4D2_SetEntityGlow(int entity, L4D2GlowType type, int range, int minRange, colorOverride[3], bool flashing)
stock bool L4D2_SetEntityGlow(int entity, L4D2GlowType type, int range, int minRange, int colorOverride[3], bool flashing)
{
if (!IsValidEntity(entity))
{

View file

@ -463,15 +463,18 @@ public Action Timer_SpawnFinaleTank(Handle t, int user) {
ServerCommand("sm_forcespecial tank");
finaleStage = Stage_Inactive;
}
return Plugin_Handled;
}
public Action Timer_SpawnSplitTank(Handle t, int user) {
ServerCommand("sm_forcespecial tank");
return Plugin_Handled;
}
public Action Timer_SetHealth(Handle h, int user) {
int client = GetClientOfUserId(user);
if(client > 0 ) {
SetEntProp(client, Prop_Send, "m_iHealth", extraTankHP);
}
return Plugin_Handled;
}
public void Frame_SetExtraTankHealth(int user) {
@ -591,6 +594,7 @@ public Action Timer_CheckInventory(Handle h, int client) {
PrintToConsoleAll("[EPI] Detected mismatch inventory for %N, restoring", client);
RestoreInventory(client);
}
return Plugin_Handled;
}
public void Event_PlayerTeam(Event event, const char[] name, bool dontBroadcast) {
@ -626,6 +630,7 @@ public Action Timer_DropSurvivor(Handle h, int client) {
}
DropDroppedInventories();
}
return Plugin_Handled;
}
/*public Action Timer_DropSurvivor(Handle h, DataPack pack) {
@ -725,8 +730,10 @@ public void Frame_SetupNewClient(int client) {
if(tier2Weapons.Length > 0) {
tier2Weapons.GetString(GetRandomInt(0, tier2Weapons.Length), weaponName, sizeof(weaponName));
Format(weaponName, sizeof(weaponName), "weapon_%s", weaponName);
PrintToServer("[EPI/debug] Giving new client (%N) tier 2: %s", client, weaponName);
} else {
Format(weaponName, sizeof(weaponName), "weapon_%s", TIER1_WEAPONS[GetRandomInt(0, TIER1_WEAPON_COUNT)]);
PrintToServer("[EPI/debug] Giving new client (%N) tier 1: %s", client, weaponName);
}
int item = GivePlayerItem(client, weaponName);
if(lowestClient > 0) {
@ -744,6 +751,7 @@ public void Frame_SetupNewClient(int client) {
}
public Action Timer_RemoveInvincibility(Handle h, int client) {
SDKUnhook(client, SDKHook_OnTakeDamage, OnInvincibleDamageTaken);
return Plugin_Handled;
}
public Action OnInvincibleDamageTaken(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& weapon, float damageForce[3], float damagePosition[3]) {
damage = 0.0;

View file

@ -4,12 +4,14 @@
#define DEBUG
#define DEBUG_SHOW_POINTS
#define DEBUG_BOT_MOVE
#define DEBUG_BLOCKERS
// #define DEBUG_MOVE_ATTEMPTS
// #define DEBUG_SEEKER_PATH_CREATION 1
#define PLUGIN_VERSION "1.0"
#define BOT_MOVE_RANDOM_MIN_TIME 6.0 // The minimum random time for Timer_BotMove to activate (set per bot, per round)
#define BOT_MOVE_RANDOM_MAX_TIME 8.6 // The maximum random time for Timer_BotMove to activate (set per bot, per round)
#define BOT_MOVE_RANDOM_MIN_TIME 2.0 // The minimum random time for Timer_BotMove to activate (set per bot, per round)
#define BOT_MOVE_RANDOM_MAX_TIME 3.0 // The maximum random time for Timer_BotMove to activate (set per bot, per round)
#define BOT_MOVE_CHANCE 0.96 // The chance the bot will move each Timer_BotMove
#define BOT_MOVE_AVOID_FLOW_DIST 12.0 // The flow range of flow distance that triggers avoid
#define BOT_MOVE_AVOID_SEEKER_CHANCE 0.50 // The chance that if the bot gets too close to the seeker, it runs away
@ -18,10 +20,17 @@
#define BOT_MOVE_JUMP_CHANCE 0.001
#define BOT_MOVE_SHOVE_CHANCE 0.0015
#define BOT_MOVE_RUN_CHANCE 0.15
#define BOT_MOVE_NOT_REACHED_DISTANCE 60.0 // The distance that determines if a bot reached a point
#define BOT_MOVE_NOT_REACHED_ATTEMPT_RUNJUMP 6 // The minimum amount of attempts where bot will run or jump to dest
#define BOT_MOVE_NOT_REACHED_ATTEMPT_RETRY 9 // The minimum amount of attempts where bot gives up and picks new
#define DOOR_TOGGLE_INTERVAL 5.0 // Interval that loops throuh all doors to randomly toggle
#define DOOR_TOGGLE_CHANCE 0.01 // Chance that every Timer_DoorToggles triggers a door to toggle state
#define HIDER_SWAP_COOLDOWN 30.0 // Amount of seconds until they can swap
#define HIDER_SWAP_LIMIT 3 // Amount of times a hider can swap per round
#define FLOW_BOUND_BUFFER 200.0 // Amount to add to calculated bounds (Make it very generous)
#define HIDER_MIN_AVG_DISTANCE_AUTO_VOCALIZE 300.0 // The average minimum distance a hider is from the player that triggers auto vocalizating
#define HIDER_AUTO_VOCALIZE_GRACE_TIME 20.0 // Number of seconds between auto vocalizations
#define DEFAULT_MAP_TIME 480
#if defined DEBUG
#define SEED_TIME 1.0
@ -39,6 +48,8 @@
float DEBUG_POINT_VIEW_MIN[3] = { -5.0, -5.0, 0.0 };
float DEBUG_POINT_VIEW_MAX[3] = { 5.0, 5.0, 2.0 };
int SEEKER_GLOW_COLOR[3] = { 128, 0, 0 };
int PLAYER_GLOW_COLOR[3] = { 0, 255, 0 };
#include <sourcemod>
#include <sdktools>
@ -49,20 +60,22 @@ float DEBUG_POINT_VIEW_MAX[3] = { 5.0, 5.0, 2.0 };
#include <multicolors>
char SURVIVOR_MODELS[8][] = {
"models/survivors/survivor_gambler.mdl",
"models/survivors/survivor_producer.mdl",
"models/survivors/survivor_coach.mdl",
"models/survivors/survivor_mechanic.mdl",
"models/survivors/survivor_namvet.mdl",
"models/survivors/survivor_teenangst.mdl",
"models/survivors/survivor_biker.mdl",
"models/survivors/survivor_manager.mdl"
"models/survivors/survivor_manager.mdl",
"models/survivors/survivor_gambler.mdl",
"models/survivors/survivor_producer.mdl",
"models/survivors/survivor_coach.mdl",
"models/survivors/survivor_mechanic.mdl"
};
enum struct LocationMeta {
float pos[3];
float ang[3];
bool runto;
bool jump;
int attempts; // # of attempts player has moved until they will try to manage
}
// Game settings
@ -82,10 +95,14 @@ int currentSeeker;
bool hasBeenSeeker[MAXPLAYERS+1];
bool ignoreSeekerBalance;
int hiderSwapTime[MAXPLAYERS+1];
int hiderSwapCount[MAXPLAYERS+1];
bool isStarting;
// Temp Ent Materials & Timers
Handle spawningTimer;
Handle hiderCheckTimer;
Handle recordTimer;
Handle timesUpTimer;
Handle acquireLocationsTimer;
Handle moveTimers[MAXPLAYERS+1];
UserMsg g_FadeUserMsgId;
@ -99,7 +116,7 @@ ConVar cvar_seekerFailDamageAmount;
// Bot Movement specifics
float flowMin, flowMax;
static float seekerPos[3];
float seekerPos[3];
float seekerFlow = 0.0;
float vecLastLocation[MAXPLAYERS+1][3];
@ -166,12 +183,14 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
HookEvent("round_start", Event_RoundStart);
HookEvent("player_death", Event_PlayerDeath);
HookEvent("player_bot_replace", Event_PlayerToBot);
HookEvent("player_ledge_grab", Event_LedgeGrab);
AddCommandListener(OnGoAwayFromKeyboard, "go_away_from_keyboard");
} else if(!lateLoaded) {
UnsetCvars();
UnhookEvent("round_start", Event_RoundStart);
UnhookEvent("player_death", Event_PlayerDeath);
UnhookEvent("player_bot_replace", Event_PlayerToBot);
UnhookEvent("player_ledge_grab", Event_LedgeGrab);
Cleanup();
PrintToChatAll("[GuessWho] Gamemode unloaded but cvars have not been reset.");
RemoveCommandListener(OnGoAwayFromKeyboard, "go_away_from_keyboard");
@ -183,6 +202,13 @@ public Action OnGoAwayFromKeyboard(int client, const char[] command, int argc) {
return Plugin_Handled;
}
void Event_LedgeGrab(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
if(client > 0) {
L4D_ReviveSurvivor(client);
}
}
void Event_PlayerToBot(Event event, const char[] name, bool dontBroadcast) {
int player = GetClientOfUserId(event.GetInt("player"));
int bot = GetClientOfUserId(event.GetInt("bot"));
@ -197,8 +223,6 @@ void Event_PlayerToBot(Event event, const char[] name, bool dontBroadcast) {
}
}
int SEEKER_GLOW_COLOR[3] = { 128, 0, 0 };
int PLAYER_GLOW_COLOR[3] = { 0, 255, 0 };
void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
int client = GetClientOfUserId(event.GetInt("userid"));
@ -207,19 +231,7 @@ void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
if(client == currentSeeker) {
PrintToChatAll("The seeker, %N, has died. Hiders win!", currentSeeker);
SetState(State_HidersWin);
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsFakeClient(i)) {
if(IsFakeClient(i)) {
ClearInventory(i);
PrintToServer("PlayerDeath: Seeker kill %d", i);
KickClient(i);
} else {
L4D2_SetEntityGlow(i, L4D2Glow_Constant, 0, 20, PLAYER_GLOW_COLOR, false);
L4D2_SetPlayerSurvivorGlowState(i, true);
}
}
}
CreateTimer(5.0, Timer_ResetAll);
EndGame(State_HidersWin);
} else if(!IsFakeClient(client)) {
if(attacker == currentSeeker) {
PrintToChatAll("%N was killed", client);
@ -235,46 +247,13 @@ void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
if(GetPlayersLeftAlive() == 0) {
if(GetState() == State_Active) {
PrintToChatAll("Everyone has died. %N wins!", currentSeeker);
CreateTimer(5.0, Timer_ResetAll);
SetState(State_SeekerWon);
EndGame(State_SeekerWon);
}
}
}
Action Timer_ResetAll(Handle h) {
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) {
ForcePlayerSuicide(i);
}
}
return Plugin_Handled;
}
bool isStarting;
void StartGame() {
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i)) {
if(isPendingPlay[i]) {
ChangeClientTeam(i, 2);
} else if(IsFakeClient(i)) {
KickClient(i);
}
}
}
if(!isStarting) {
isStarting = true;
CreateTimer(5.0, Timer_Start);
}
}
void Event_RoundStart(Event event, const char[] name, bool dontBroadcast) {
StartGame();
}
Action Timer_Start(Handle h) {
if(isStarting)
InitGamemode();
return Plugin_Handled;
CreateTimer(5.0, Timer_WaitForPlayers, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
public void OnMapStart() {
@ -324,7 +303,7 @@ public void OnMapStart() {
SDKHook(i, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
}
}
CreateTimer(0.1, Timer_Start);
InitGamemode();
}
SetState(State_Unknown);
}
@ -356,25 +335,20 @@ public void OnClientPutInServer(int client) {
isPendingPlay[client] = true;
PrintToChatAll("%N will play next round", client);
TeleportToSpawn(client);
if(!IsPendingPlayers()) {
StartGame();
}
}
}
public void OnClientDisconnect(int client) {
if(!isEnabled) return;
if(client == currentSeeker) {
if(acquireLocationsTimer != null) delete acquireLocationsTimer;
PrintToChatAll("The seeker has disconnected");
CreateTimer(1.0, Timer_ResetAll);
currentSeeker = 0;
EndGame(State_HidersWin);
} else if(!IsFakeClient(client) && GetState() == State_Active) {
PrintToChatAll("A hider has left (%N)", client);
if(GetPlayersLeftAlive() == 0 && GetState() == State_Active) {
PrintToChatAll("Game Over. %N wins!", currentSeeker);
CreateTimer(5.0, Timer_ResetAll);
SetState(State_SeekerWon);
EndGame(State_SeekerWon);
}
}
}
@ -423,6 +397,7 @@ void SetCvars(bool record = false) {
SetCvarValue(cvar_sbPushScale, 0, record);
SetCvarValue(FindConVar("sb_battlestation_give_up_range_from_human"), 5000.0, record);
SetCvarValue(FindConVar("sb_max_battlestation_range_from_human"), 5000.0, record);
SetCvarValue(FindConVar("sb_enforce_proximity_range"), 10000, record);
}
void UnsetCvars() {
@ -459,11 +434,17 @@ void InitGamemode() {
ArrayList validPlayerIds = new ArrayList();
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) {
if(IsFakeClient(i)) KickClient(i);
else {
ChangeClientTeam(i, 2);
activeBotLocations[i].attempts = 0;
if(IsFakeClient(i)) {
ClearInventory(i);
KickClient(i);
} else {
if(!IsPlayerAlive(i)) {
L4D_RespawnPlayer(i);
}
hiderSwapCount[i] = 0;
distQueue[i].Clear();
ChangeClientTeam(i, 2);
if(!hasBeenSeeker[i] || ignoreSeekerBalance)
validPlayerIds.Push(GetClientUserId(i));
@ -477,11 +458,12 @@ void InitGamemode() {
ignoreSeekerBalance = false;
int newSeeker = GetClientOfUserId(validPlayerIds.Get(GetURandomInt() % validPlayerIds.Length));
delete validPlayerIds;
if(newSeeker > 0) {
if(newSeeker > 0) {
hasBeenSeeker[newSeeker] = true;
PrintToChatAll("%N is the seeker", newSeeker);
SetPlayerBlind(newSeeker, 255);
SetSeeker(newSeeker);
SetPlayerBlind(newSeeker, 255);
SetEntPropFloat(newSeeker, Prop_Send, "m_flLaggedMovementValue", 0.0);
// L4D2_SetPlayerSurvivorGlowState(newSeeker, true);
L4D2_SetEntityGlow(newSeeker, L4D2Glow_Constant, 0, 10, SEEKER_GLOW_COLOR, false);
}
@ -513,13 +495,24 @@ Action Timer_SpawnPost(Handle h) {
PrintToChatAll("Timer_SpawnPost(): activating");
bool isL4D1 = L4D2_GetSurvivorSetMap() == 1;
int remainingSeekers;
int survivorMaxIndex = isL4D1 ? 3 : 7;
int survivorIndexBot;
for(int i = 1; i <= MaxClients; i++) {
if(i != currentSeeker && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) {
if(!IsFakeClient(i)) {
int survivor;
if(IsFakeClient(i)) {
// Set bot models uniformly
survivor = survivorIndexBot;
if(++survivorIndexBot > survivorMaxIndex) {
survivorIndexBot = 0;
}
} else {
// Set hiders models randomly
survivor = GetURandomInt() % survivorMaxIndex;
if(!hasBeenSeeker[i]) {
remainingSeekers++;
}
PrintToChat(i, "You can change your model by looking at a player and pressing RELOAD");
PrintToChat(i, "You can change your model %d times by looking at a player and pressing RELOAD", HIDER_SWAP_LIMIT);
}
SDKHook(i, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
SDKHook(i, SDKHook_WeaponDrop, OnWeaponDrop);
@ -527,9 +520,10 @@ Action Timer_SpawnPost(Handle h) {
ClearInventory(i);
int item = GivePlayerItem(i, "weapon_gnome");
EquipPlayerWeapon(i, item);
int survivor = GetRandomInt(isL4D1 ? 5 : 0, 7);
SetEntityModel(i, SURVIVOR_MODELS[survivor]);
SetEntProp(i, Prop_Send, "m_survivorCharacter", isL4D1 ? (survivor - 4) : survivor);
SetEntProp(i, Prop_Send, "m_survivorCharacter", survivor);
}
}
@ -554,13 +548,15 @@ Action Timer_WaitForStart(Handle h) {
}
seekerFlow = L4D2Direct_GetFlowDistance(currentSeeker);
acquireLocationsTimer = CreateTimer(0.5, Timer_AcquireLocations, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
hiderCheckTimer = CreateTimer(5.0, Timer_CheckHiders, _, TIMER_REPEAT);
CreateTimer(DOOR_TOGGLE_INTERVAL, Timer_DoorToggles, _, TIMER_FLAG_NO_MAPCHANGE | TIMER_REPEAT);
for(int i = 1; i <= MaxClients; i++) {
if(i != currentSeeker && IsClientConnected(i) && IsClientInGame(i)) {
TeleportEntity(i, seekerPos, NULL_VECTOR, NULL_VECTOR);
if(IsFakeClient(i)) {
moveTimers[i] = CreateTimer(GetRandomFloat(BOT_MOVE_RANDOM_MIN_TIME, BOT_MOVE_RANDOM_MAX_TIME), Timer_BotMove, GetClientUserId(i), TIMER_REPEAT);
TriggerTimer(moveTimers[i]);
validLocations.GetArray(GetURandomInt() % validLocations.Length, activeBotLocations[i]);
TeleportEntity(i, activeBotLocations[i].pos, activeBotLocations[i].ang, NULL_VECTOR);
}
}
}
@ -581,10 +577,21 @@ Action Timer_StartSeeker(Handle h) {
SetPlayerBlind(currentSeeker, 0);
SetState(State_Active);
SetTick(0);
SetMapTime(1000);
SetEntPropFloat(currentSeeker, Prop_Send, "m_flLaggedMovementValue", 1.0);
if(mapConfig.mapTime == 0) {
mapConfig.mapTime = DEFAULT_MAP_TIME;
}
SetMapTime(mapConfig.mapTime);
timesUpTimer = CreateTimer(float(mapConfig.mapTime), Timer_TimesUp, _, TIMER_FLAG_NO_MAPCHANGE);
return Plugin_Continue;
}
Action Timer_TimesUp(Handle h) {
PrintToChatAll("The seeker ran out of time. Hiders win!");
EndGame(State_HidersWin);
return Plugin_Handled;
}
Action OnWeaponDrop(int client, int weapon) {
return Plugin_Handled;
}
@ -595,7 +602,7 @@ Action OnTakeDamageAlive(int victim, int& attacker, int& inflictor, float& damag
ClearInventory(victim);
if(IsFakeClient(victim)) {
PrintToChat(attacker, "That was a bot! -%.0f health", cvar_seekerFailDamageAmount.FloatValue);
SDKHooks_TakeDamage(attacker, 0, 0, cvar_seekerFailDamageAmount.FloatValue, DMG_BURN);
SDKHooks_TakeDamage(attacker, 0, 0, cvar_seekerFailDamageAmount.FloatValue, DMG_DIRECT);
}
return Plugin_Changed;
} else if(attacker > 0 && attacker <= MaxClients) {
@ -613,6 +620,7 @@ Action Timer_DoorToggles(Handle h) {
if(GetURandomFloat() < DOOR_TOGGLE_CHANCE)
AcceptEntityInput(entity, "Toggle");
}
return Plugin_Handled;
}
Action Timer_AcquireLocations(Handle h) {
@ -644,6 +652,15 @@ Action Timer_AcquireLocations(Handle h) {
return Plugin_Continue;
}
void GetMovePoint(int i) {
activeBotLocations[i].runto = GetURandomFloat() < BOT_MOVE_RUN_CHANCE;
activeBotLocations[i].attempts = 0;
validLocations.GetArray(GetURandomInt() % validLocations.Length, activeBotLocations[i]);
#if defined DEBUG_SHOW_POINTS
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, {255, 0, 255, 120}, 0);
#endif
}
Action Timer_BotMove(Handle h, int userid) {
int i = GetClientOfUserId(userid);
if(i == 0) return Plugin_Stop;
@ -659,6 +676,7 @@ Action Timer_BotMove(Handle h, int userid) {
}
float botFlow = L4D2Direct_GetFlowDistance(i);
static float pos[3];
if(botFlow < flowMin || botFlow > flowMax) {
activeBotLocations[i].runto = GetURandomFloat() > 0.90;
TE_SetupBeamLaser(i, currentSeeker, g_iLaserIndex, 0, 0, 0, 8.0, 0.5, 0.1, 0, 1.0, {255, 255, 0, 125}, 1);
@ -667,37 +685,83 @@ Action Timer_BotMove(Handle h, int userid) {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] BOT %N TOO FAR (%f) BOUNDS (%f, %f)-> Moving to seeker (%f %f %f)", i, botFlow, flowMin, flowMax, seekerPos[0], seekerPos[1], seekerPos[2]);
#endif
activeBotLocations[i].attempts = 0;
} else if(validLocations.Length > 0) {
if(mapConfig.hasSpawnpoint && FloatAbs(botFlow - seekerFlow) < BOT_MOVE_AVOID_FLOW_DIST && GetURandomFloat() < BOT_MOVE_AVOID_SEEKER_CHANCE) {
if(!FindPointAway(seekerPos, activeBotLocations[i].pos, BOT_MOVE_AVOID_MIN_DISTANCE)) {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] BOT %N TOO CLOSE -> Failed to find far point, falling back to spawn", i);
GetAbsOrigin(i, pos);
float distanceToPoint = GetVectorDistance(pos, activeBotLocations[i].pos);
if(distanceToPoint < BOT_MOVE_NOT_REACHED_DISTANCE || GetURandomFloat() < 0.20) {
activeBotLocations[i].attempts = 0;
#if defined DEBUG_BOT_MOVE
L4D2_SetPlayerSurvivorGlowState(i, false);
L4D2_RemoveEntityGlow(i);
#endif
// Has reached destination
if(mapConfig.hasSpawnpoint && FloatAbs(botFlow - seekerFlow) < BOT_MOVE_AVOID_FLOW_DIST && GetURandomFloat() < BOT_MOVE_AVOID_SEEKER_CHANCE) {
if(!FindPointAway(seekerPos, activeBotLocations[i].pos, BOT_MOVE_AVOID_MIN_DISTANCE)) {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] BOT %N TOO CLOSE -> Failed to find far point, falling back to spawn", i);
#endif
activeBotLocations[i].pos = mapConfig.spawnpoint;
} else {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] BOT %N TOO CLOSE -> Moving to far point (%f %f %f) (%f units away)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2], GetVectorDistance(seekerPos, activeBotLocations[i].pos));
#endif
}
activeBotLocations[i].runto = GetURandomFloat() < 0.75;
#if defined DEBUG_SHOW_POINTS
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.2, 0.1, 0, 0.0, {255, 255, 255, 255}, 0);
#endif
activeBotLocations[i].pos = mapConfig.spawnpoint;
} else {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] BOT %N TOO CLOSE -> Moving to far point (%f %f %f) (%f units away)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2], GetVectorDistance(seekerPos, activeBotLocations[i].pos));
#endif
GetMovePoint(i);
}
if(!L4D2_IsReachable(i, activeBotLocations[i].pos)) {
#if defined DEBUG_BOT_MOVE
PrintToChatAll("[gw/debug] POINT UNREACHABLE (Bot:%d) (%f %f %f)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
PrintToServer("[gw/debug] POINT UNREACHABLE (Bot:%d) (%f %f %f)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, view_as<float>({ 10.0, 10.0, 100.0 }), NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 400.0, 2.0, 3.0, 0, 0.0, {255, 0, 0, 255}, 0);
#endif
GetMovePoint(i);
}
activeBotLocations[i].runto = GetURandomFloat() < 0.75;
#if defined DEBUG_SHOW_POINTS
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.2, 0.1, 0, 0.0, {255, 255, 255, 255}, 0);
#endif
} else {
activeBotLocations[i].runto = GetURandomFloat() < BOT_MOVE_RUN_CHANCE;
validLocations.GetArray(GetURandomInt() % validLocations.Length, activeBotLocations[i]);
// Has not reached dest
activeBotLocations[i].attempts++;
#if defined DEBUG_MOVE_ATTEMPTS
PrintToConsoleAll("[gw/debug] Bot %d - move attempt %d - dist: %f", i, activeBotLocations[i].attempts, distanceToPoint);
#endif
if(activeBotLocations[i].attempts == BOT_MOVE_NOT_REACHED_ATTEMPT_RUNJUMP) {
if(distanceToPoint <= (BOT_MOVE_NOT_REACHED_DISTANCE * 2)) {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] Bot %d still has not reached point (%f %f %f), jumping", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
L4D2_SetPlayerSurvivorGlowState(i, true);
L4D2_SetEntityGlow(i, L4D2Glow_Constant, 0, 10, PLAYER_GLOW_COLOR, true);
#endif
activeBotLocations[i].jump = true;
} else {
activeBotLocations[i].runto = true;
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] Bot %d not reached point (%f %f %f), running", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
L4D2_SetEntityGlow(i, L4D2Glow_Constant, 0, 10, PLAYER_GLOW_COLOR, true);
L4D2_SetPlayerSurvivorGlowState(i, true);
#endif
}
} else if(activeBotLocations[i].attempts > BOT_MOVE_NOT_REACHED_ATTEMPT_RETRY) {
#if defined DEBUG_BOT_MOVE
PrintToConsoleAll("[gw/debug] Bot %d giving up at reaching point (%f %f %f)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
L4D2_SetEntityGlow(i, L4D2Glow_Constant, 0, 10, SEEKER_GLOW_COLOR, true);
L4D2_SetPlayerSurvivorGlowState(i, true);
#endif
GetMovePoint(i);
}
#if defined DEBUG_SHOW_POINTS
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, {255, 0, 255, 255}, 0);
int color[4];
color[0] = 255;
color[2] = 255;
color[3] = 120 + activeBotLocations[i].attempts * 45;
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, color, 0);
#endif
}
#if defined DEBUG_BOT_MOVE
if(!L4D2_IsReachable(i, activeBotLocations[i].pos)) {
PrintToChatAll("[gw/debug] POINT UNREACHABLE (Bot:%d) (%f %f %f)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
PrintToServer("[gw/debug] POINT UNREACHABLE (Bot:%d) (%f %f %f)", i, activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]);
Effect_DrawBeamBoxRotatableToAll(activeBotLocations[i].pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, {255, 0, 0, 255}, 0);
}
#endif
LookAtPoint(i, activeBotLocations[i].pos);
L4D2_RunScript("CommandABot({cmd=1,bot=GetPlayerFromUserID(%i),pos=Vector(%f,%f,%f)})",
GetClientUserId(i),
activeBotLocations[i].pos[0], activeBotLocations[i].pos[1], activeBotLocations[i].pos[2]
@ -709,6 +773,11 @@ Action Timer_BotMove(Handle h, int userid) {
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) {
if(!isEnabled) return Plugin_Continue;
if(IsFakeClient(client)) {
if(activeBotLocations[client].jump) {
activeBotLocations[client].jump = false;
buttons |= (IN_WALK | IN_JUMP | IN_FORWARD);
return Plugin_Changed;
}
buttons |= (activeBotLocations[client].runto ? IN_WALK : IN_SPEED);
if(GetURandomFloat() < BOT_MOVE_USE_CHANCE) {
buttons |= IN_USE;
@ -721,28 +790,35 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
}
return Plugin_Changed;
} else if(client != currentSeeker && buttons & IN_RELOAD) {
int target = GetClientAimTarget(client, true);
if(target > 0) {
int time = GetTime();
float diff = float(time - hiderSwapTime[client]);
if(diff > HIDER_SWAP_COOLDOWN) {
hiderSwapTime[client] = GetTime();
if(hiderSwapCount[client] >= HIDER_SWAP_LIMIT) {
PrintHintText(client, "Swap limit reached");
} else {
int target = GetClientAimTarget(client, true);
if(target > 0) {
int time = GetTime();
float diff = float(time - hiderSwapTime[client]);
if(diff > HIDER_SWAP_COOLDOWN) {
hiderSwapTime[client] = GetTime();
hiderSwapCount[client]++;
/*float pos[3], pos2[3];
GetClientAbsOrigin(client, pos);
GetClientEyePosition(client, pos2);
TE_SetupParticle(g_iSmokeParticle, pos, pos2, .iEntity = client);
TE_SendToAllInRange(pos, RangeType_Audibility, 0.0);*/
/*float pos[3], pos2[3];
GetClientAbsOrigin(client, pos);
GetClientEyePosition(client, pos2);
TE_SetupParticle(g_iSmokeParticle, pos, pos2, .iEntity = client);
TE_SendToAllInRange(pos, RangeType_Audibility, 0.0);*/
char modelName[64];
GetClientModel(target, modelName, sizeof(modelName));
int type = GetEntProp(target, Prop_Send, "m_survivorCharacter");
SetEntityModel(client, modelName);
SetEntProp(client, Prop_Send, "m_survivorCharacter", type);
char modelName[64];
GetClientModel(target, modelName, sizeof(modelName));
int type = GetEntProp(target, Prop_Send, "m_survivorCharacter");
SetEntityModel(client, modelName);
SetEntProp(client, Prop_Send, "m_survivorCharacter", type);
EmitSoundToAll("ui/pickup_secret01.wav", client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
} else {
PrintHintText(client, "You can swap in %.0f seconds", HIDER_SWAP_COOLDOWN - diff);
EmitSoundToAll("ui/pickup_secret01.wav", client, SNDCHAN_AUTO, SNDLEVEL_SCREAMING);
PrintHintText(client, "You have %d swaps remaining", HIDER_SWAP_LIMIT - hiderSwapCount[client]);
} else {
PrintHintText(client, "You can swap in %.0f seconds", HIDER_SWAP_COOLDOWN - diff);
}
}
}
}
@ -755,7 +831,8 @@ void ClearInventory(int client) {
int item = GetPlayerWeaponSlot(client, i);
if(item > 0) {
RemovePlayerItem(client, item);
AcceptEntityInput(item, "Kill");
RemoveEdict(item);
// AcceptEntityInput(item, "Kill");
}
}
}
@ -776,13 +853,15 @@ bool AddSurvivor() {
}
}
CreateTimer(0.2, Timer_Kick, i);
CreateTimer(0.2, Timer_Kick, GetClientUserId(i));
}
return result;
}
Action Timer_Kick(Handle h, int i) {
KickClient(i);
Action Timer_Kick(Handle h, int u) {
int i = GetClientOfUserId(u);
if(i > 0) KickClient(i);
return Plugin_Handled;
}
stock void L4D2_RunScript(const char[] sCode, any ...) {