Update hide and seek

This commit is contained in:
Jackzie 2022-06-18 17:56:53 -05:00
parent 04670575be
commit f6b51ee495
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
5 changed files with 222 additions and 79 deletions

Binary file not shown.

View file

@ -41,7 +41,7 @@ public Action Command_HideAndSeek(int client, int args) {
} }
Cleanup(); Cleanup();
SetupEntities(isNavBlockersEnabled, isPropsEnabled, isPortalsEnabled); SetupEntities(isNavBlockersEnabled, isPropsEnabled, isPortalsEnabled);
ReplyToCommand(client, "Set the current set to \"%s\"", currentSet); PrintToChatAll("[H&S] Map set has been changed to \"%s\"", currentSet);
return Plugin_Handled; return Plugin_Handled;
} }
} }
@ -216,9 +216,19 @@ public Action Command_HideAndSeek(int client, int args) {
} }
if(IsBotsEnabled()) ReplyToCommand(client, "Bots are enabled"); if(IsBotsEnabled()) ReplyToCommand(client, "Bots are enabled");
else ReplyToCommand(client, "Bots are disabled"); else ReplyToCommand(client, "Bots are disabled");
} else if(StrEqual(subcmd, "peek")) { } else if(StrEqual(subcmd, "peekfix")) {
SetPeekCamTarget(client); if(seekerCam == INVALID_ENT_REFERENCE) {
SetPeekCamActive(client, !IsPeekCamActive(client)); SetPeekCamTarget(client);
}
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) {
SetPeekCamActive(client, false);
SetPeekCamActive(client, false);
}
}
AcceptEntityInput(seekerCam, "Kill");
ReplyToCommand(client, "Killing active camera");
} else if(StrEqual(subcmd, "seeker")) { } else if(StrEqual(subcmd, "seeker")) {
if(args == 2) { if(args == 2) {
char arg1[32]; char arg1[32];
@ -240,8 +250,7 @@ public Action Command_HideAndSeek(int client, int args) {
ReplyToTargetError(client, target_count); ReplyToTargetError(client, target_count);
return Plugin_Handled; return Plugin_Handled;
} }
SetSlasher(target_list[0], true);
SetSlasher(target_list[0]);
ReplyToCommand(client, "Set the current seeker to %N", target_list[0]); ReplyToCommand(client, "Set the current seeker to %N", target_list[0]);
} else { } else {
ReplyToCommand(client, "The current seeker is: %N", GetSlasher()); ReplyToCommand(client, "The current seeker is: %N", GetSlasher());
@ -264,17 +273,24 @@ public Action Command_HideAndSeek(int client, int args) {
} }
return Plugin_Handled; return Plugin_Handled;
} }
ReplyToCommand(client, " - Hide & Seek Commands -"); ReplyToCommand(client, " === [ Hide & Seek Commands ] ===");
ReplyToCommand(client, "toggle <blockers/props/all>: Toggles all specified"); if(GetUserAdmin(client) != INVALID_ADMIN_ID) {
ReplyToCommand(client, "set [new set]: Change the prop set or view current"); ReplyToCommand(client, "- Dev Commands -");
ReplyToCommand(client, "clear <props/blockers/all>: Clear all specified"); ReplyToCommand(client, "r/reload [force]: Reloads map config from file");
ReplyToCommand(client, "settime [seconds]: Sets the time override for the map"); ReplyToCommand(client, "toggle <blockers/props/all>: Toggles all specified entities");
ReplyToCommand(client, "settick [tick]: Sets the current tick timer value"); ReplyToCommand(client, "clear <props/blockers/all>: Clear all specified");
ReplyToCommand(client, "setspawn: Sets the temporary spawnpoint for the map"); ReplyToCommand(client, "settime [seconds]: Sets the time override for the map");
ReplyToCommand(client, "settick [tick]: Sets the current tick timer value");
ReplyToCommand(client, "- Admin Commands -");
ReplyToCommand(client, "set [new set]: Change the prop set or view current");
ReplyToCommand(client, "setspawn: Sets the temporary spawnpoint for the map");
ReplyToCommand(client, "bots [toggle, [value]]: View if bots are enabled, or turn them on");
ReplyToCommand(client, "peekfix - Clear peek camera from all players");
ReplyToCommand(client, "seeker [new seeker]: Get the active seeker, or set a new one.");
ReplyToCommand(client, "sm_cvar hs_peekcam <0/2> - Turn the peek camera on or off");
ReplyToCommand(client, "- User Commands -");
}
ReplyToCommand(client, "stuck: Teleports you to spawn to unstuck yourself"); ReplyToCommand(client, "stuck: Teleports you to spawn to unstuck yourself");
ReplyToCommand(client, "bots [toggle, [value]]: View if bots are enabled, or turn them on");
ReplyToCommand(client, "seeker [new seeker]: Get the active seeker, or set a new one.");
ReplyToCommand(client, "peek - debug cmd");
return Plugin_Handled; return Plugin_Handled;
} }

View file

@ -33,18 +33,22 @@ bool ReloadMapDB() {
} }
bool LoadConfigForMap(const char[] map) { bool LoadConfigForMap(const char[] map) {
kv.Rewind(); kv.Rewind();
if (kv.JumpToKey(map)) { if (kv.JumpToKey(map)) {
PrintToServer("[H&S] Loading config data for set %s on %s", currentSet, map);
MapConfig config; MapConfig config;
config.entities = new ArrayList(sizeof(EntityConfig)); config.entities = new ArrayList(sizeof(EntityConfig));
config.inputs = new ArrayList(ByteCountToCells(64)); config.inputs = new ArrayList(ByteCountToCells(64));
validSets.Clear(); validSets.Clear();
static char buffer[64];
if(StrEqual(currentSet, "default") && kv.GetString("defaultset", buffer, sizeof(buffer))) {
strcopy(currentSet, sizeof(currentSet), buffer);
}
PrintToServer("[H&S] Loading config data for set %s on %s", currentSet, map);
if(kv.JumpToKey("ents")) { if(kv.JumpToKey("ents")) {
kv.GotoFirstSubKey(); kv.GotoFirstSubKey();
char entSet[16];
do { do {
EntityConfig entCfg; EntityConfig entCfg;
kv.GetVector("origin", entCfg.origin, NULL_VECTOR); kv.GetVector("origin", entCfg.origin, NULL_VECTOR);
@ -55,17 +59,16 @@ bool LoadConfigForMap(const char[] map) {
Format(entCfg.model, sizeof(entCfg.model), "models/%s", entCfg.model); Format(entCfg.model, sizeof(entCfg.model), "models/%s", entCfg.model);
kv.GetVector("scale", entCfg.scale, DEFAULT_SCALE); kv.GetVector("scale", entCfg.scale, DEFAULT_SCALE);
kv.GetVector("offset", entCfg.offset, NULL_VECTOR); kv.GetVector("offset", entCfg.offset, NULL_VECTOR);
kv.GetString("set", entSet, sizeof(entSet), "default"); kv.GetString("set", buffer, sizeof(buffer), "default");
if(validSets.FindString(entSet) == -1) { if(validSets.FindString(buffer) == -1) {
validSets.PushString(entSet); validSets.PushString(buffer);
} }
char debug_str[64]; if(StrEqual(buffer, "default") || StrEqual(currentSet, buffer, false)) {
if(StrEqual(entSet, "default") || StrEqual(currentSet, entSet, false)) {
config.entities.PushArray(entCfg); config.entities.PushArray(entCfg);
} else { } else {
kv.GetSectionName(debug_str, sizeof(debug_str)); kv.GetSectionName(buffer, sizeof(buffer));
PrintToServer("Skipping %s", debug_str); PrintToServer("Skipping %s", buffer);
} }
} while (kv.GotoNextKey()); } while (kv.GotoNextKey());
// JumpToKey and GotoFirstSubKey both traverse, i guess, go back // JumpToKey and GotoFirstSubKey both traverse, i guess, go back
@ -74,7 +77,6 @@ bool LoadConfigForMap(const char[] map) {
} }
if(kv.JumpToKey("inputs")) { if(kv.JumpToKey("inputs")) {
kv.GotoFirstSubKey(false); kv.GotoFirstSubKey(false);
static char buffer[64];
do { do {
kv.GetSectionName(buffer, sizeof(buffer)); kv.GetSectionName(buffer, sizeof(buffer));
config.inputs.PushString(buffer); config.inputs.PushString(buffer);
@ -110,6 +112,18 @@ bool LoadConfigForMap(const char[] map) {
kv.GetString("buttons", buf, sizeof(buf)); kv.GetString("buttons", buf, sizeof(buf));
config.pressButtons = !StrEqual(buf, "no"); config.pressButtons = !StrEqual(buf, "no");
mapTime = kv.GetNum("maptime", 0); mapTime = kv.GetNum("maptime", 0);
if(kv.JumpToKey("inputs")) {
kv.GotoFirstSubKey(false);
do {
kv.GetSectionName(buffer, sizeof(buffer));
config.inputs.PushString(buffer);
kv.GetString(NULL_STRING, buffer, sizeof(buffer));
config.inputs.PushString(buffer);
} while (kv.GotoNextKey(false));
kv.GoBack();
kv.GoBack();
}
break; break;
} }
@ -165,3 +179,22 @@ bool LoadConfigForMap(const char[] map) {
return false; return false;
} }
} }
int COLOR_GREY[4] = { 194, 197, 204, 255 };
int COLOR_GREEN[4] = { 0, 128, 0, 255 };
void ShowBeacon(int target, float radius = 100.0) {
float vec[3];
GetClientAbsOrigin(target, vec);
vec[2] += 10;
if (g_BeamSprite > -1 && g_HaloSprite > -1) {
TE_SetupBeamRingPoint(vec, 10.0, radius, g_BeamSprite, g_HaloSprite, 0, 15, 0.5, 5.0, 0.0, COLOR_GREY, 10, 0);
TE_SendToAll();
TE_SetupBeamRingPoint(vec, 10.0, radius, g_BeamSprite, g_HaloSprite, 0, 10, 0.6, 10.0, 0.5, COLOR_GREEN, 10, 0);
TE_SendToAll();
}
GetClientEyePosition(target, vec);
EmitAmbientSound("buttons/button17.wav", vec, target, SNDLEVEL_RAIDSIREN);
}

View file

@ -60,7 +60,10 @@ int FindSlasher() {
return -1; return -1;
} }
void SetSlasher(int client) { void SetSlasher(int client, bool ignoreBalance = false) {
if(ignoreBalance) {
ignoreSeekerBalance = true;
}
GameState state = GetState(); GameState state = GetState();
char buf[128]; char buf[128];
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
@ -198,7 +201,21 @@ void SetParent(int child, int parent) {
AcceptEntityInput(child, "SetParent", parent); AcceptEntityInput(child, "SetParent", parent);
} }
void SetPeekCamTarget(int target, int src = 0) { void SetParentAttachment(int child, const char[] attachment, bool withOffset = false) {
SetVariantString(attachment);
if(withOffset)
AcceptEntityInput(child, "SetParentAttachmentMaintainOffset");
else
AcceptEntityInput(child, "SetParentAttachment");
}
void ClearParent(int child) {
AcceptEntityInput(child, "ClearParent");
}
static float EMPTY_ANG[3] = { 0.0, 0.0, 0.0 };
void SetPeekCamTarget(int target, bool showFPOV = false) {
if(seekerCam == INVALID_ENT_REFERENCE || !IsValidEntity(seekerCam)) { if(seekerCam == INVALID_ENT_REFERENCE || !IsValidEntity(seekerCam)) {
seekerCam = CreateEntityByName("point_viewcontrol_survivor"); seekerCam = CreateEntityByName("point_viewcontrol_survivor");
DispatchKeyValue(seekerCam, "targetname", "hscam"); DispatchKeyValue(seekerCam, "targetname", "hscam");
@ -206,24 +223,19 @@ void SetPeekCamTarget(int target, int src = 0) {
for(int i = 0; i <= MaxClients; i++) { for(int i = 0; i <= MaxClients; i++) {
isViewingCam[i] = false; isViewingCam[i] = false;
} }
PrintToServer("created new peek cam %d", seekerCam);
} }
AcceptEntityInput(seekerCam, "ClearParent"); AcceptEntityInput(seekerCam, "ClearParent");
AcceptEntityInput(seekerCam, "Disable");
float pos[3], endPos[3], ang[3]; float pos[3], endPos[3], ang[3];
GetClientEyePosition(target, pos); GetClientEyePosition(target, pos);
GetClientEyeAngles(target, ang); GetClientEyeAngles(target, ang);
if(src) { if(showFPOV) {
pos[2] += 20.0;
TeleportEntity(seekerCam, pos, ang, NULL_VECTOR); TeleportEntity(seekerCam, pos, ang, NULL_VECTOR);
// SetParent(seekerCam, src); SetParent(seekerCam, target);
SetParentAttachment(seekerCam, "primary", false);
} else { } else {
/*GetHorizontalPositionFromClient(target, -20.0, endPos);
endPos[2] += 80.0;
TeleportEntity(seekerCam, endPos, ang, NULL_VECTOR);
SetParent(seekerCam, target);*/
TR_TraceRayFilter(pos, ang, CONTENTS_PLAYERCLIP | MASK_SOLID | MASK_VISIBLE, RayType_Infinite, Filter_IgnoreAll); TR_TraceRayFilter(pos, ang, CONTENTS_PLAYERCLIP | MASK_SOLID | MASK_VISIBLE, RayType_Infinite, Filter_IgnoreAll);
if(TR_DidHit()) { if(TR_DidHit()) {
TR_GetEndPosition(endPos); TR_GetEndPosition(endPos);
@ -237,13 +249,27 @@ void SetPeekCamTarget(int target, int src = 0) {
ang[0] = RadToDeg(ArcTangent(deltaC / GetVectorDistance(endPos, pos, false) )); ang[0] = RadToDeg(ArcTangent(deltaC / GetVectorDistance(endPos, pos, false) ));
ang[1] = RadToDeg(ArcTangent2(deltaA, deltaB)); ang[1] = RadToDeg(ArcTangent2(deltaA, deltaB));
// pos[2] += 50.0;
// GetAnglesLookAt(seekerCam, target, ang);
TeleportEntity(seekerCam, endPos, ang, NULL_VECTOR); TeleportEntity(seekerCam, endPos, ang, NULL_VECTOR);
// SetParent(seekerCam, target);*/
} }
} }
bool IsPeekCamActive(int client) {
return isViewingCam[client];
}
// int GetClientsInRange(const float origin[3], ClientRangeType rangeType, int[] clients, int size)
void SetPeekCamActive(int client, bool active) {
if(seekerCam != INVALID_ENT_REFERENCE) {
AcceptEntityInput(seekerCam, "Enable", client); // Need to always activate before deactivating to fix a semi-common bug
if(!active)
AcceptEntityInput(seekerCam, "Disable", client);
} else {
PrintToServer("WARN: SetPeekCamActive(%d, %b) when seekerCam invalid", client, active);
}
isViewingCam[client] = active;
}
stock void GetAnglesLookAt(int iClient, int iTarget, float fFinalPos[3]) { stock void GetAnglesLookAt(int iClient, int iTarget, float fFinalPos[3]) {
static float fTargetPos[3]; static float fTargetPos[3];
static float fTargetAngles[3]; static float fTargetAngles[3];
@ -280,20 +306,3 @@ stock void GetViewVector(float fVecAngle[3], float fOutPut[3])
bool Filter_IgnoreAll(int entity, int mask) { bool Filter_IgnoreAll(int entity, int mask) {
return false; return false;
} }
bool IsPeekCamActive(int client) {
return isViewingCam[client];
}
// int GetClientsInRange(const float origin[3], ClientRangeType rangeType, int[] clients, int size)
void SetPeekCamActive(int client, bool active) {
if(seekerCam != INVALID_ENT_REFERENCE) {
if(active)
AcceptEntityInput(seekerCam, "Enable", client);
else
AcceptEntityInput(seekerCam, "Disable", client);
} else {
PrintToServer("warn: SetPeekCamActive(%d, %b) when seekerCam invalid", client, active);
}
isViewingCam[client] = active;
}

View file

@ -26,6 +26,11 @@ public Plugin myinfo =
url = "" url = ""
}; };
/*TODO:
2. Seeker helping
3. flare on hunted
*/
/* /*
script g_ModeScript.DeepPrintTable(g_ModeScript.MutationState) script g_ModeScript.DeepPrintTable(g_ModeScript.MutationState)
{ {
@ -44,6 +49,7 @@ script g_ModeScript.DeepPrintTable(g_ModeScript.MutationState)
#define SOUND_SUSPENSE_1 "custom/suspense1.mp3" #define SOUND_SUSPENSE_1 "custom/suspense1.mp3"
#define SOUND_SUSPENSE_1_FAST "custom/suspense1fast.mp3" #define SOUND_SUSPENSE_1_FAST "custom/suspense1fast.mp3"
#define SOUND_SHAKE "doors/gate_move1.wav"
enum GameState { enum GameState {
State_Unknown = -1, State_Unknown = -1,
@ -74,6 +80,9 @@ char nextRoundMap[64];
int seekerCam = INVALID_ENT_REFERENCE; int seekerCam = INVALID_ENT_REFERENCE;
bool isViewingCam[MAXPLAYERS+1]; bool isViewingCam[MAXPLAYERS+1];
int g_BeamSprite;
int g_HaloSprite;
enum struct EntityConfig { enum struct EntityConfig {
float origin[3]; float origin[3];
float rotation[3]; float rotation[3];
@ -97,6 +106,12 @@ MapConfig mapConfig;
ArrayList validMaps; ArrayList validMaps;
ArrayList validSets; ArrayList validSets;
bool hasBeenSeeker[MAXPLAYERS+1];
bool ignoreSeekerBalance;
ConVar cvar_peekCam;
ConVar cvar_seekerBalance;
#include <hideandseek/hscore> #include <hideandseek/hscore>
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
@ -118,8 +133,10 @@ public void OnPluginStart() {
SetFailState("Could not load entity config from data/hideandseek.cfg"); SetFailState("Could not load entity config from data/hideandseek.cfg");
} }
cvar_peekCam = CreateConVar("hs_peekcam", "3", "Controls the peek camera on events. Set bits\n0 = OFF, 1 = On Game End, 2 = Any death", FCVAR_NONE, true, 0.0, true, 3.0);
cvar_seekerBalance = CreateConVar("hs_seekerbalance", "1", "Enable or disable ensuring every player has played as seeker", FCVAR_NONE, true, 0.0, true, 1.0);
ConVar hGamemode = FindConVar("mp_gamemode"); ConVar hGamemode = FindConVar("mp_gamemode");
hGamemode.GetString(gamemode, sizeof(gamemode));
hGamemode.AddChangeHook(Event_GamemodeChange); hGamemode.AddChangeHook(Event_GamemodeChange);
Event_GamemodeChange(hGamemode, gamemode, gamemode); Event_GamemodeChange(hGamemode, gamemode, gamemode);
@ -133,6 +150,7 @@ public void OnPluginEnd() {
} }
public void OnClientConnected(int client) { public void OnClientConnected(int client) {
hasBeenSeeker[client] = false;
if(!IsFakeClient(client)) { if(!IsFakeClient(client)) {
currentPlayers++; currentPlayers++;
if(isEnabled) { if(isEnabled) {
@ -186,24 +204,29 @@ public void OnMapStart() {
#endif #endif
PrecacheSound(SOUND_SUSPENSE_1); PrecacheSound(SOUND_SUSPENSE_1);
PrecacheSound(SOUND_SUSPENSE_1_FAST); PrecacheSound(SOUND_SUSPENSE_1_FAST);
PrecacheSound(SOUND_SHAKE);
AddFileToDownloadsTable("sound/custom/suspense1.mp3"); AddFileToDownloadsTable("sound/custom/suspense1.mp3");
AddFileToDownloadsTable("sound/custom/suspense1fast.mp3"); AddFileToDownloadsTable("sound/custom/suspense1fast.mp3");
g_BeamSprite = PrecacheModel("sprites/laser.vmt");
g_HaloSprite = PrecacheModel("sprites/halo01.vmt");
PrecacheSound("buttons/button17.wav", true);
if(lateLoaded) { if(lateLoaded) {
lateLoaded = false;
SetupEntities(); SetupEntities();
int seeker = GetSlasher(); int seeker = GetSlasher();
if(seeker > -1) { if(seeker > -1) {
currentSeeker = seeker; currentSeeker = seeker;
SetPeekCamTarget(currentSeeker);
PrintToServer("[H&S] Late load, found seeker %N", currentSeeker); PrintToServer("[H&S] Late load, found seeker %N", currentSeeker);
} }
SetPeekCamTarget(currentSeeker);
if(IsGameSoloOrPlayersLoading()) { if(IsGameSoloOrPlayersLoading()) {
Handle timer = CreateTimer(10.0, Timer_KeepWaiting, _, TIMER_REPEAT); Handle timer = CreateTimer(10.0, Timer_KeepWaiting, _, TIMER_REPEAT);
TriggerTimer(timer); TriggerTimer(timer);
PrintToServer("[H&S] Late load, player(s) are connecting, or solo. Waiting..."); PrintToServer("[H&S] Late load, player(s) are connecting, or solo. Waiting...");
SetState(State_Startup); SetState(State_Startup);
} }
lateLoaded = false;
} }
} }
@ -225,13 +248,17 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
isEnabled = StrEqual(gamemode, "hideandseek", false); isEnabled = StrEqual(gamemode, "hideandseek", false);
#endif #endif
if(isEnabled) { if(isEnabled) {
PrintToChatAll("[H&S] Hide and seek gamemode activated, starting");
HookEvent("round_end", Event_RoundEnd); HookEvent("round_end", Event_RoundEnd);
HookEvent("round_start", Event_RoundStart); HookEvent("round_start", Event_RoundStart);
HookEvent("player_spawn", Event_PlayerSpawn); HookEvent("player_spawn", Event_PlayerSpawn);
HookEvent("item_pickup", Event_ItemPickup); HookEvent("item_pickup", Event_ItemPickup);
HookEvent("player_death", Event_PlayerDeath); HookEvent("player_death", Event_PlayerDeath);
SetupEntities(); // OnMapStart(); // Don't use, need to track OnMapStart
CreateTimer(12.0, Timer_RoundStart); if(lateLoaded)
CreateTimer(2.0, Timer_RoundStart);
else
CreateTimer(10.0, Timer_RoundStart);
if(suspenseTimer != null) if(suspenseTimer != null)
delete suspenseTimer; delete suspenseTimer;
suspenseTimer = CreateTimer(20.0, Timer_Music, _, TIMER_REPEAT); suspenseTimer = CreateTimer(20.0, Timer_Music, _, TIMER_REPEAT);
@ -240,8 +267,9 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
thirdPersonTimer = CreateTimer(1.0, Timer_CheckPlayers, _, TIMER_REPEAT); thirdPersonTimer = CreateTimer(1.0, Timer_CheckPlayers, _, TIMER_REPEAT);
if(!lateLoaded) { if(!lateLoaded) {
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) if(IsClientConnected(i) && IsClientInGame(i)) {
ForcePlayerSuicide(i); ForcePlayerSuicide(i);
}
} }
} }
} else if(!lateLoaded && suspenseTimer != null) { } else if(!lateLoaded && suspenseTimer != null) {
@ -258,7 +286,6 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
const float DEATH_CAM_MIN_DIST = 150.0; const float DEATH_CAM_MIN_DIST = 150.0;
public Action Timer_StopPeekCam(Handle h) { public Action Timer_StopPeekCam(Handle h) {
PrintToServer("clearing cam");
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) { if(IsClientConnected(i) && IsClientInGame(i)) {
SetPeekCamActive(i, false); SetPeekCamActive(i, false);
@ -271,37 +298,42 @@ public void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast
int attacker = GetClientOfUserId(event.GetInt("attacker")); int attacker = GetClientOfUserId(event.GetInt("attacker"));
if(!gameOver && client && GetClientTeam(client) == 2) { if(!gameOver && client && GetClientTeam(client) == 2) {
SetPeekCamTarget(attacker > 0 ? attacker : client, client); SetPeekCamTarget(attacker > 0 ? attacker : client, true);
int alive = 0; int alive = 0;
float pos[3], checkPos[3]; float pos[3], checkPos[3];
if(attacker <= 0) attacker = client;
GetClientAbsOrigin(attacker, pos); GetClientAbsOrigin(attacker, pos);
SetPeekCamActive(attacker, true); SetPeekCamActive(attacker, true);
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
if(attacker > 0 && attacker != client) { if(attacker > 0 && attacker != client) {
GetClientAbsOrigin(i, checkPos); if(cvar_peekCam.IntValue & 2) {
if(GetVectorDistance(checkPos, pos) > DEATH_CAM_MIN_DIST) { GetClientAbsOrigin(i, checkPos);
SetPeekCamActive(i, true); if(GetVectorDistance(checkPos, pos) > DEATH_CAM_MIN_DIST) {
SetPeekCamActive(i, true);
}
} }
alive++; alive++;
} }
} }
} }
if(client == currentSeeker) {
if(client == currentSeeker && alive == 1) {
PrintToChatAll("Hiders win!"); PrintToChatAll("Hiders win!");
gameOver = true; gameOver = true;
} else { } else {
if(alive == 2) { if(alive == 2) {
PrintToChatAll("One hider remains."); PrintToChatAll("One hider remains.");
} else if(alive == 1) { } else if(alive <= 0) {
// Player died and not seeker, therefore seeker killed em // Player died and not seeker, therefore seeker killed em
if(client != currentSeeker) { if(client != currentSeeker) {
PrintToChatAll("Seeker %N won!", currentSeeker); PrintToChatAll("Seeker %N won!", currentSeeker);
} else { } else {
SetPeekCamTarget(client);
PrintToChatAll("Hiders win! The last survivor was %N!", client); PrintToChatAll("Hiders win! The last survivor was %N!", client);
}
if(cvar_peekCam.IntValue & 1) {
SetPeekCamTarget(client, false);
} }
gameOver = true; gameOver = true;
return; return;
@ -343,6 +375,33 @@ public void Event_ItemPickup(Event event, const char[] name, bool dontBroadcast)
PrintToChatAll("[H&S] Seeker does not equal axe-receiver. Possible seeker: %N", client); PrintToChatAll("[H&S] Seeker does not equal axe-receiver. Possible seeker: %N", client);
} }
SetPeekCamTarget(currentSeeker); SetPeekCamTarget(currentSeeker);
if(!ignoreSeekerBalance && cvar_seekerBalance.BoolValue) {
if(hasBeenSeeker[currentSeeker]) {
ArrayList notPlayedSeekers = new ArrayList(1);
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && !hasBeenSeeker[i]) {
notPlayedSeekers.Push(i);
}
}
if(notPlayedSeekers.Length > 0) {
int newSlasher = notPlayedSeekers.Get(GetURandomInt() % notPlayedSeekers.Length);
PrintToServer("[H&S] Switching seeker to a new random seeker: %N", newSlasher);
SetSlasher(newSlasher);
return;
} else {
PrintToServer("[H&S] All players have played as seeker, resetting");
PrintToChatAll("[H&S] Everyone has played as a seeker once");
for(int i = 1; i <= MaxClients; i++) {
hasBeenSeeker[i] = false;
}
hasBeenSeeker[currentSeeker] = true;
}
delete notPlayedSeekers;
} else {
hasBeenSeeker[currentSeeker] = true;
}
}
ignoreSeekerBalance = false;
PrintToChatAll("%N is the seeker", currentSeeker); PrintToChatAll("%N is the seeker", currentSeeker);
} }
} }
@ -367,6 +426,7 @@ public void Event_RoundStart(Event event, const char[] name, bool dontBroadcast)
} }
} }
EntFire("relay_intro_start", "Kill"); EntFire("relay_intro_start", "Kill");
EntFire("outro", "Kill");
SetupEntities(); SetupEntities();
CreateTimer(15.0, Timer_RoundStart); CreateTimer(15.0, Timer_RoundStart);
} }
@ -433,6 +493,7 @@ public Action Timer_Music(Handle h) {
if(state == State_Hunting) { if(state == State_Hunting) {
if(prevState == State_Hiding) { if(prevState == State_Hiding) {
changedToHunting = true; changedToHunting = true;
ShowBeacon(currentSeeker);
SetPeekCamTarget(currentSeeker); SetPeekCamTarget(currentSeeker);
} }
EmitSoundToClient(currentSeeker, SOUND_SUSPENSE_1, currentSeeker, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, 0.2, 90, currentSeeker, seekerLoc, seekerLoc, true); EmitSoundToClient(currentSeeker, SOUND_SUSPENSE_1, currentSeeker, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_CHANGEPITCH, 0.2, 90, currentSeeker, seekerLoc, seekerLoc, true);
@ -478,10 +539,6 @@ public Action Timer_RoundStart(Handle h) {
} }
} }
entity = INVALID_ENT_REFERENCE; entity = INVALID_ENT_REFERENCE;
while ((entity = FindEntityByClassname(entity, "func_brush")) != INVALID_ENT_REFERENCE) {
AcceptEntityInput(entity, "Kill");
}
entity = INVALID_ENT_REFERENCE;
while ((entity = FindEntityByClassname(entity, "infected")) != INVALID_ENT_REFERENCE) { while ((entity = FindEntityByClassname(entity, "infected")) != INVALID_ENT_REFERENCE) {
AcceptEntityInput(entity, "Kill"); AcceptEntityInput(entity, "Kill");
} }
@ -493,9 +550,14 @@ public Action Timer_RoundStart(Handle h) {
} }
if(mapConfig.canClimb) { if(mapConfig.canClimb) {
while ((entity = FindEntityByClassname(entity, "func_simpleladder")) != INVALID_ENT_REFERENCE) { while ((entity = FindEntityByClassname(entity, "func_simpleladder")) != INVALID_ENT_REFERENCE) {
SDKHook(entity, SDKHook_TraceAttackPost, Hook_OnAttackPost);
SetEntProp(entity, Prop_Send, "m_iTeamNum", 0); SetEntProp(entity, Prop_Send, "m_iTeamNum", 0);
} }
} }
while ((entity = FindEntityByClassname(entity, "env_soundscape")) != INVALID_ENT_REFERENCE) {
AcceptEntityInput(entity, "Disable");
AcceptEntityInput(entity, "Kill");
}
if(mapConfig.mapTime > 0) { if(mapConfig.mapTime > 0) {
SetMapTime(mapConfig.mapTime); SetMapTime(mapConfig.mapTime);
} }
@ -503,6 +565,30 @@ public Action Timer_RoundStart(Handle h) {
PrintToServer("[H&S] Map time is %d seconds", GetMapTime()); PrintToServer("[H&S] Map time is %d seconds", GetMapTime());
return Plugin_Continue; return Plugin_Continue;
} }
static float SHAKE_SIZE[3] = { 40.0, 40.0, 20.0 };
static float lastShakeTime;
public void Hook_OnAttackPost(int entity, int attacker, int inflictor, float damage, int damagetype, int ammotype, int hitbox, int hitgroup) {
if(attacker == currentSeeker && attacker > 0 && GetGameTime() - lastShakeTime > 2.0) {
lastShakeTime = GetGameTime();
float min[3], max[3], origin[3], top[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", origin);
GetEntPropVector(entity, Prop_Send, "m_vecMins", min);
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", max);
PrintHintTextToAll("Shaking ladder");
top = origin;
top[2] = max[2];
origin[2] = min[2];
TR_EnumerateEntitiesHull(origin, top, min, max, PARTITION_SOLID_EDICTS, Ray_Enumerator, attacker);
EmitAmbientSound(SOUND_SHAKE, top, SOUND_FROM_WORLD, SNDLEVEL_SCREAMING, SND_NOFLAGS, SNDVOL_NORMAL, SNDPITCH_NORMAL);
}
}
bool Ray_Enumerator(int entity, int attacker) {
if(entity > 0 && entity <= MaxClients && entity != attacker) {
L4D_StaggerPlayer(entity, attacker, NULL_VECTOR);
}
return true;
}
public Action Timer_CheckWeapons(Handle h) { public Action Timer_CheckWeapons(Handle h) {
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) { if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
@ -516,4 +602,3 @@ public Action Timer_CheckWeapons(Handle h) {
} }
return Plugin_Continue; return Plugin_Continue;
} }