Random changes hope they work

This commit is contained in:
Jackzie 2024-03-28 12:13:30 -05:00
parent 9007092afd
commit ccc68b9935
16 changed files with 431 additions and 227 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -5,14 +5,12 @@
#define PLUGIN_VERSION "1.0" #define PLUGIN_VERSION "1.0"
#define PRECACHE_SOUNDS_COUNT 6 #define PRECACHE_SOUNDS_COUNT 4
char PRECACHE_SOUNDS[PRECACHE_SOUNDS_COUNT][] = { char PRECACHE_SOUNDS[PRECACHE_SOUNDS_COUNT][] = {
"custom/meow1.mp3",
"custom/xen_teleport.mp3", "custom/xen_teleport.mp3",
"custom/mariokartmusic.mp3", "custom/mariokartmusic.mp3",
"custom/spookyscaryskeletons.mp3", "custom/spookyscaryskeletons.mp3",
"custom/wearenumberone2.mp3", "custom/wearenumberone2.mp3",
"custom/quack.mp3"
}; };
#include <sourcemod> #include <sourcemod>
@ -101,7 +99,7 @@ public void OnPluginStart() {
if(hSVMaxPlayers != null) { if(hSVMaxPlayers != null) {
hPlayerLimit = CreateConVar("sm_player_limit", "0", "Overrides sv_maxplayers. 0 = off, > 0: limit", FCVAR_NONE, true, 0.0, false); hPlayerLimit = CreateConVar("sm_player_limit", "0", "Overrides sv_maxplayers. 0 = off, > 0: limit", FCVAR_NONE, true, 0.0, false);
hPlayerLimit.AddChangeHook(Event_PlayerLimitChange); hPlayerLimit.AddChangeHook(Event_PlayerLimitChange);
hSVMaxPlayers.IntValue = hPlayerLimit.IntValue; if(hPlayerLimit.IntValue > 0) hSVMaxPlayers.IntValue = hPlayerLimit.IntValue;
} }
hFFNotice.AddChangeHook(CVC_FFNotice); hFFNotice.AddChangeHook(CVC_FFNotice);

View file

@ -9,7 +9,8 @@ public void OnMapStart() {
PrecacheSound("custom/meow1.mp3"); PrecacheSound("custom/meow1.mp3");
AddFileToDownloadsTable("sound/custom/woof1.mp3"); AddFileToDownloadsTable("sound/custom/woof1.mp3");
PrecacheSound("custom/woof1.mp3"); PrecacheSound("custom/woof1.mp3");
AddFileToDownloadsTable("sound/custom/quack.mp3");
PrecacheSound("custom/quack.mp3");
lastButtonUser = -1; lastButtonUser = -1;
HookEntityOutput("func_button", "OnPressed", Event_ButtonPress); HookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
@ -919,7 +920,7 @@ public Action SoundHook(int clients[MAXPLAYERS], int& numClients, char sample[PL
strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav"); strcopy(sample, sizeof(sample), "player/footsteps/clown/concrete1.wav");
} else if(trollFlags & 2) { } else if(trollFlags & 2) {
strcopy(sample, sizeof(sample), "custom/quack.mp3"); strcopy(sample, sizeof(sample), "custom/quack.mp3");
// volume += 0.2; volume = 1.0;
} else if(trollFlags & 4) { } else if(trollFlags & 4) {
strcopy(sample, sizeof(sample), "custom/meow1.mp3"); strcopy(sample, sizeof(sample), "custom/meow1.mp3");
volume += 0.2; volume += 0.2;

View file

@ -211,7 +211,7 @@ enum struct EditorData {
} }
void CycleStacker(float tick) { void CycleStacker(float tick) {
if(tick - cmdThrottle[this.client] <= 0.20) return; if(tick - cmdThrottle[this.client] <= 0.10) return;
int newDirection = view_as<int>(this.stackerDirection) + 1; int newDirection = view_as<int>(this.stackerDirection) + 1;
if(newDirection == view_as<int>(Stack_Down)) newDirection = 0; if(newDirection == view_as<int>(Stack_Down)) newDirection = 0;
this.stackerDirection = view_as<StackerDirection>(newDirection); this.stackerDirection = view_as<StackerDirection>(newDirection);
@ -334,8 +334,10 @@ enum struct EditorData {
return this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError; return this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError;
} else { } else {
// Is edit, do nothing, just reset // Is edit, do nothing, just reset
PrintHintText(this.client, "Edit Complete");
this.Reset(); this.Reset();
entity = 0; entity = 0;
return Complete_EditSuccess; return Complete_EditSuccess;
} }
} }
@ -384,6 +386,7 @@ enum struct EditorData {
this.Reset(); this.Reset();
if(!isEdit) { if(!isEdit) {
id = createdWalls.Push(EntIndexToEntRef(blocker)); id = createdWalls.Push(EntIndexToEntRef(blocker));
PrintToChat(this.client, "\x04[Editor]\x01 Created wall \x05#%d\x01.", id);
} }
return true; return true;
} }
@ -430,7 +433,8 @@ enum struct EditorData {
this.origin[2] += (size[2] * sign); this.origin[2] += (size[2] * sign);
} }
} }
PrintHintText(this.client, "%s\n%s", this.classname, this.data);
// PrintToChat(this.client, "\x04[Editor]\x01 Editing copy \x05%d\x01 of entity \x05%d\x01. End with \x05/edit done\x01 or \x04/edit cancel\x01", entity, oldEntity);
// Don't kill preview until cancel // Don't kill preview until cancel
return true; return true;
} }
@ -606,7 +610,8 @@ enum struct EditorData {
TeleportEntity(this.entity, this.prevOrigin, this.prevAngles, NULL_VECTOR); TeleportEntity(this.entity, this.prevOrigin, this.prevAngles, NULL_VECTOR);
} }
this.SetMode(INACTIVE); this.SetMode(INACTIVE);
CPrintToChat(this.client, "\x04[Editor]\x01 Cancelled."); PrintHintText(this.client, "Cancelled");
// CPrintToChat(this.client, "\x04[Editor]\x01 Cancelled.");
} }
} }
EditorData Editor[MAXPLAYERS+1]; EditorData Editor[MAXPLAYERS+1];

View file

@ -372,7 +372,7 @@ Action Command_DoAHat(int client, int args) {
if(IsFakeClient(entity) && L4D_GetIdlePlayerOfBot(entity) > 0) { if(IsFakeClient(entity) && L4D_GetIdlePlayerOfBot(entity) > 0) {
PrintToChat(client, "[Hats] Cannot hat idle bots"); PrintToChat(client, "[Hats] Cannot hat idle bots");
return Plugin_Handled; return Plugin_Handled;
} else if(GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_InfectedHats)) { } else if(!isForced && GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_InfectedHats)) {
PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous"); PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous");
return Plugin_Handled; return Plugin_Handled;
} else if(entity == EntRefToEntIndex(Editor[client].entity)) { } else if(entity == EntRefToEntIndex(Editor[client].entity)) {
@ -747,7 +747,11 @@ void EquipHat(int client, int entity, const char[] classname = "", int flags = H
} else { } else {
float mins[3]; float mins[3];
GetEntPropVector(modifyEntity, Prop_Send, "m_vecMins", mins); GetEntPropVector(modifyEntity, Prop_Send, "m_vecMins", mins);
hatData[client].offset[2] += mins[2]; if(StrContains(classname, "weapon_molotov") > -1 || StrContains(classname, "weapon_pipe_bomb") > -1 || StrContains(classname, "weapon_vomitjar") > -1) {
hatData[client].offset[2] += 7.2;
} else {
hatData[client].offset[2] += mins[2];
}
} }
if(cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_ReversedHats) && flags & view_as<int>(HAT_REVERSED)) { if(cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_ReversedHats) && flags & view_as<int>(HAT_REVERSED)) {

View file

@ -20,6 +20,21 @@ public Action Command_HideAndSeek(int client, int args) {
ReplyToCommand(client, "Error occurred while reloading map file"); ReplyToCommand(client, "Error occurred while reloading map file");
} }
return Plugin_Handled; return Plugin_Handled;
} else if(StrEqual(subcmd, "state")) {
int state = GetCmdArgInt(2);
if(state < 0 || state > view_as<int>(State_Hunting)) {
ReplyToCommand(client, "Invalid state. 0 to %d", view_as<int>(State_Hunting));
} else {
if(SetState(view_as<GameState>(state))) {
ReplyToCommand(client, "State set to %s (%d)", GAME_STATE_DEBUG[state],state);
if(view_as<GameState>(state) == State_Startup) {
StartWaiting();
}
} else {
ReplyToCommand(client, "Game not active");
}
}
return Plugin_Handled;
} else if(StrEqual(subcmd, "set", false)) { } else if(StrEqual(subcmd, "set", false)) {
char set[16]; char set[16];
if(args == 1) { if(args == 1) {
@ -207,29 +222,6 @@ public Action Command_HideAndSeek(int client, int args) {
} else if(StrEqual(subcmd, "stuck")) { } else if(StrEqual(subcmd, "stuck")) {
TeleportEntity(client, mapConfig.spawnpoint, NULL_VECTOR, NULL_VECTOR); TeleportEntity(client, mapConfig.spawnpoint, NULL_VECTOR, NULL_VECTOR);
return Plugin_Handled; return Plugin_Handled;
} else if(StrEqual(subcmd, "bots")) {
if(args == 2) {
char arg[16];
GetCmdArg(2, arg, sizeof(arg));
if(StrEqual(arg, "toggle")) {
bool newValue = !IsBotsEnabled();
SetBotsEnabled(newValue);
if(newValue) ReplyToCommand(client, "Bots are now enabled");
else ReplyToCommand(client, "Bots are now disabled");
return Plugin_Handled;
} else if(StrEqual(arg, "on") || StrEqual(arg, "true")) {
SetBotsEnabled(true);
ReplyToCommand(client, "Bots are now enabled");
return Plugin_Handled;
} else if(StrEqual(arg, "off") || StrEqual(arg, "false")) {
SetBotsEnabled(false);
ReplyToCommand(client, "Bots are now disabled");
return Plugin_Handled;
}
}
if(IsBotsEnabled()) ReplyToCommand(client, "Bots are enabled");
else ReplyToCommand(client, "Bots are disabled");
return Plugin_Handled;
} else if(StrEqual(subcmd, "peekfix")) { } else if(StrEqual(subcmd, "peekfix")) {
if(!PeekCam.Exists()) { if(!PeekCam.Exists()) {
PeekCam.Target = client; PeekCam.Target = client;
@ -272,21 +264,21 @@ public Action Command_HideAndSeek(int client, int args) {
} }
return Plugin_Handled; return Plugin_Handled;
} else if(StrEqual(subcmd, "debug")) { } else if(StrEqual(subcmd, "debug")) {
ReplyToCommand(client, "- Game Info -"); int mutationSlasher = GetSlasher();
int addSlasher = GetSlasher(); CReplyToCommand(client, "Current seeker: \x04%N(%d)", currentSeeker, currentSeeker);
ReplyToCommand(client, "Current seeker: %N(%d) (addon says %N(%d))", currentSeeker, currentSeeker, addSlasher, addSlasher); CReplyToCommand(client, "\tMutation Says: \x04%N(%d)", mutationSlasher, mutationSlasher);
ReplyToCommand(client, "State: %d | Tick: %d", view_as<int>(GetState()), GetTick()); int state = view_as<int>(GetState());
CReplyToCommand(client, "State: \x04%s(%d)\x01 | Tick: \x04%d\x01", GAME_STATE_DEBUG[state], state, GetTick());
ReplyToCommand(client, "- Map Info -"); CReplyToCommand(client, "Map: \x04%s\x01/\x05%s", g_currentMap, g_currentSet);
ReplyToCommand(client, "Map: %s (set %s)", g_currentMap, g_currentSet);
if(mapConfig.hasSpawnpoint) if(mapConfig.hasSpawnpoint)
ReplyToCommand(client, "Has Spawnpoint: yes (%f %f %f)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]); CReplyToCommand(client, "Has Spawnpoint: \x04yes\x01 (\x05%.1f %.1f %.1f\x01)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]);
else else
ReplyToCommand(client, "Has Spawnpoint: no (possibly map spawn %f %f %f)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]); CReplyToCommand(client, "Has Spawnpoint: \x04no (possibly map spawn \x05%.1f %.1f %.1f\x01)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]);
ReplyToCommand(client, "Climbing: %b", mapConfig.canClimb); CReplyToCommand(client, "Climbing: \x04%b", mapConfig.canClimb);
ReplyToCommand(client, "Buttons Auto-press: %b", mapConfig.pressButtons); CReplyToCommand(client, "Buttons Auto-press: \x04%b", mapConfig.pressButtons);
ReplyToCommand(client, "Map Time Override: %d", mapConfig.mapTime); CReplyToCommand(client, "Map Time Override: \x04%d", mapConfig.mapTime);
ReplyToCommand(client, "Your travel distance: %f", distanceTraveled[client]); CReplyToCommand(client, "Your travel distance: \x04%f", distanceTraveled[client]);
return Plugin_Handled; return Plugin_Handled;
} }
ReplyToCommand(client, "Unknown command"); ReplyToCommand(client, "Unknown command");
@ -303,7 +295,6 @@ public Action Command_HideAndSeek(int client, int args) {
ReplyToCommand(client, "- Admin Commands -"); ReplyToCommand(client, "- Admin Commands -");
ReplyToCommand(client, "set [new set]: Change the prop set or view current"); ReplyToCommand(client, "set [new set]: Change the prop set or view current");
ReplyToCommand(client, "setspawn: Sets the temporary spawnpoint for the map"); 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, "peekfix - Clear peek camera from all players");
ReplyToCommand(client, "seeker [new seeker]: Get the active seeker, or set a new one."); 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, "sm_cvar hs_peekcam <0/2> - Turn the peek camera on or off");

View file

@ -183,22 +183,6 @@ bool IsGameSoloOrPlayersLoading() {
return connecting > 0 || ingame == 1; return connecting > 0 || ingame == 1;
} }
//cm_NoSurvivorBots
bool SetBotsEnabled(bool value) {
static char buffer[64];
if(value)
Format(buffer, sizeof(buffer), "g_ModeScript.MutationOptions.cm_NoSurvivorBots = true");
else
Format(buffer, sizeof(buffer), "g_ModeScript.MutationOptions.cm_NoSurvivorBots = false");
return L4D2_ExecVScriptCode(buffer);
}
bool IsBotsEnabled() {
static char result[8];
L4D2_GetVScriptOutput("g_ModeScript.MutationState.cm_NoSurvivorBots", result, sizeof(result));
return StrEqual(result, "true", false);
}
stock void GetHorizontalPositionFromClient(int client, float units, float finalPosition[3]) { stock void GetHorizontalPositionFromClient(int client, float units, float finalPosition[3]) {
float pos[3], ang[3]; float pos[3], ang[3];
GetClientEyeAngles(client, ang); GetClientEyeAngles(client, ang);

View file

@ -12,13 +12,15 @@ enum SocketType {
SOCKET_RAW SOCKET_RAW
} }
#define EMPTY_HOST 1 enum {
#define NO_HOST 2 EMPTY_HOST = 1,
#define CONNECT_ERROR 3 NO_HOST,
#define SEND_ERROR 4 CONNECT_ERROR,
#define BIND_ERROR 5 SEND_ERROR,
#define RECV_ERROR 6 BIND_ERROR,
#define LISTEN_ERROR 7 RECV_ERROR,
LISTEN_ERROR
}
/*************************************************************************************************/ /*************************************************************************************************/
@ -45,7 +47,7 @@ enum SocketOption {
* @note don't forget to set your buffer sizes at least to the value passed to this function, but * @note don't forget to set your buffer sizes at least to the value passed to this function, but
* always at least to 4096 * always at least to 4096
* *
* @param cell_t 0(=default) to disable or max. chunk size including \0 terminator in bytes * @param int 0(=default) to disable or max. chunk size including \0 terminator in bytes
* @return bool true on success * @return bool true on success
*/ */
ConcatenateCallbacks = 1, ConcatenateCallbacks = 1,
@ -73,7 +75,7 @@ enum SocketOption {
* *
* @note this option will affect all sockets from all plugins, use it with caution! * @note this option will affect all sockets from all plugins, use it with caution!
* *
* @param cell_t maximum amount of callbacks per gameframe * @param int maximum amount of callbacks per gameframe
* @return bool true on success * @return bool true on success
*/ */
CallbacksPerFrame, CallbacksPerFrame,
@ -105,7 +107,7 @@ enum SocketOption {
* This option specifies how long a socket will wait if it's being closed and its send buffer is * This option specifies how long a socket will wait if it's being closed and its send buffer is
* still filled. This is a wrapper for setting SO_LINGER. * still filled. This is a wrapper for setting SO_LINGER.
* *
* @param cell_t 0 (=default) to disable or time in s * @param int 0 (=default) to disable or time in s
* @return bool true on success * @return bool true on success
*/ */
SocketLinger, SocketLinger,
@ -121,7 +123,7 @@ enum SocketOption {
* This option specifies how large the send buffer will be. This is a wrapper for setting * This option specifies how large the send buffer will be. This is a wrapper for setting
* SO_SNDBUF. * SO_SNDBUF.
* *
* @param cell_t size in bytes * @param int size in bytes
* @return bool true on success * @return bool true on success
*/ */
SocketSendBuffer, SocketSendBuffer,
@ -129,7 +131,7 @@ enum SocketOption {
* This option specifies how large the receive buffer will be. This is a wrapper for setting * This option specifies how large the receive buffer will be. This is a wrapper for setting
* SO_RCVBUF. * SO_RCVBUF.
* *
* @param cell_t size in bytes * @param int size in bytes
* @return bool true on success * @return bool true on success
*/ */
SocketReceiveBuffer, SocketReceiveBuffer,
@ -148,7 +150,7 @@ enum SocketOption {
* *
* @note this can probably block the extension, use it with caution! * @note this can probably block the extension, use it with caution!
* *
* @param cell_t size in bytes * @param int size in bytes
* @return bool true on success * @return bool true on success
*/ */
SocketReceiveLowWatermark, SocketReceiveLowWatermark,
@ -156,7 +158,7 @@ enum SocketOption {
* This option specifies how long a socket will try to receive data before it times out and * This option specifies how long a socket will try to receive data before it times out and
* processes the data. This is a wrapper for setting SO_RCVTIMEO. * processes the data. This is a wrapper for setting SO_RCVTIMEO.
* *
* @param cell_t 0 (=default) to disable or time in ms * @param int 0 (=default) to disable or time in ms
* @return bool true on success * @return bool true on success
*/ */
SocketReceiveTimeout, SocketReceiveTimeout,
@ -166,7 +168,7 @@ enum SocketOption {
* *
* @note this can probably block the extension, use it with caution! * @note this can probably block the extension, use it with caution!
* *
* @param cell_t size in bytes * @param int size in bytes
* @return bool true on success * @return bool true on success
*/ */
SocketSendLowWatermark, SocketSendLowWatermark,
@ -174,7 +176,7 @@ enum SocketOption {
* This option specifies how long a socket will try to send data before it times out and * This option specifies how long a socket will try to send data before it times out and
* retries it later. This is a wrapper for setting SO_SNDTIMEO. * retries it later. This is a wrapper for setting SO_SNDTIMEO.
* *
* @param cell_t 0 (=default) to disable or time in ms * @param int 0 (=default) to disable or time in ms
* @return bool true on success * @return bool true on success
*/ */
SocketSendTimeout, SocketSendTimeout,
@ -187,12 +189,173 @@ enum SocketOption {
DebugMode DebugMode
} }
// Methodmap
methodmap Socket < Handle {
/**
* Creates a new socket.
*
* @note this function may be relatively expensive, reuse sockets if possible
*
* @param SocketType protocol The protocol to use, SOCKET_TCP is default
* @param SocketErrorCB efunc The error callback
* @return Handle The socket handle. Returns INVALID_HANDLE on failure
*/
public native Socket(SocketType protocol=SOCKET_TCP, SocketErrorCB efunc);
/**
* Binds the socket to a local address
*
* @param String hostname The hostname (or IP) to bind the socket to.
* @param int port The port to bind the socket to.
* @return bool true on success
*/
public native bool Bind(const char[] hostname, int port);
/**
* Connects a socket
*
* @note this native is threaded, it may be still running after it executed, use the connect callback
* @note invokes the SocketError callback with errorType = CONNECT_ERROR or EMPTY_HOST if it fails
* @note invokes the SocketConnect callback if it succeeds
*
* @param SocketConnectCB cfunc The connect callback
* @param SocketReceiveCB rfunc The receive callback
* @param SocketDisconnectCB dfunc The disconnect callback
* @param String hostname The hostname (or IP) to connect to.
* @param int port The port to connect to.
*/
public native void Connect(SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port);
/**
* Disconnects a socket
*
* @note this will not close the handle, the socket will be reset to a state similar to after SocketCreate()
* @note this won't trigger any disconnect/error callbacks
*
* @return bool true on success
*/
public native bool Disconnect();
/**
* Makes a socket listen for incoming connections
*
* @param SocketIncomingCB ifunc The callback for incoming connections
* @return bool true on success
*/
public native bool Listen(SocketIncomingCB ifunc);
/**
* Sends data through the socket.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
* @note This native is threaded, it may be still running after it executed (not atomic).
* @note Use the SendqueueEmpty callback to determine when all data has been successfully sent.
* @note The socket extension will ensure that the data will be send in the correct order and split
* the data if required.
*
* @param String data The data to send.
*/
public native void Send(const char[] data, int size = -1);
/**
* Sends UDP data through the socket to a specific destination.
*
* @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included
* @note This native is threaded, it may be still running after it executed (not atomic).
* @note Use the SendqueueEmpty callback to determine when all data has been successfully sent.
* @note The socket extension will ensure that the data will be send in the correct order and split
* the data if required.
*
* @param String data The data to send.
* @param String hostname The hostname (or IP) to send to.
* @param int port The port to send to.
*/
public native void SendTo(const char[] data, int size = -1, const char[] hostname, int port);
/**
* Set a socket option.
*
* @param SocketOption option The option to modify (see enum SocketOption for details).
* @param int value The value to set the option to.
* @return int 1 on success.
*/
public native int SetOption(SocketOption option, int value);
/**
* Defines the callback function for when the socket receives data
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketConnect())
*
* @param SocketReceiveCB rfunc The receive callback
*/
public native void SetReceiveCallback(SocketReceiveCB rfunc);
/**
* Defines the callback function for when the socket sent all items in its send queue
*
* @note this must be called AFTER sending (queueing) the data
* @note if no send-data is queued this will fire the callback itself
* @note the callback is guaranteed to fire
*
* @param SocketDisconnectCB dfunc The disconnect callback
*/
public native void SetSendqueueEmptyCallback(SocketSendqueueEmptyCB sfunc);
/**
* Defines the callback function for when the socket was properly disconnected by the remote side
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketConnect())
*
* @param SocketDisconnectCB dfunc The disconnect callback
*/
public native void SetDisconnectCallback(SocketDisconnectCB dfunc);
/**
* Defines the callback function for when the socket triggered an error
*
* @note this is only useful and required for child-sockets spawned by listen-sockets
* (otherwise you already set it in SocketCreate())
*
* @param SocketErrorCB efunc The error callback
*/
public native void SetErrorCallback(SocketErrorCB efunc);
/**
* Sets the argument being passed to callbacks
*
* @param any arg The argument to set
*/
public native void SetArg(any arg);
/**
* Retrieve the local system's hostname as the command "hostname" does.
*
* @param dest Destination string buffer to copy to.
* @param destLen Destination buffer length (includes null terminator).
*
* @return 1 on success
*/
public static native int GetHostName(char[] dest, int destLen);
/**
* Returns whether a socket is connected or not.
*
* @return bool The connection status
*/
property bool Connected {
public native get();
}
}
/*************************************************************************************************/ /*************************************************************************************************/
/******************************************* callbacks *******************************************/ /******************************************* callbacks *******************************************/
/*************************************************************************************************/ /*************************************************************************************************/
/** /**
* triggered if a normal sockets finished connecting and is ready to be used * triggered if a normal sockets finished connecting and is ready to be used
* *
@ -200,26 +363,20 @@ enum SocketOption {
* @param arg The argument set by SocketSetArg() * @param arg The argument set by SocketSetArg()
* @noreturn * @noreturn
*/ */
funcenum SocketConnectCB typedef SocketConnectCB = function void (Socket socket, any arg);
{
public(Handle:socket, any:arg)
};
/** /**
* triggered if a listening socket received an incoming connection and is ready to be used * triggered if a listening socket received an incoming connection and is ready to be used
* *
* @note The child-socket won't work until receive-, disconnect-, and errorcallback for it are set. * @note The child-socket won't work until receive-, disconnect-, and errorcallback for it are set.
* *
* @param Handle socket The socket handle pointing to the calling listen-socket * @param Socket socket The socket handle pointing to the calling listen-socket
* @param Handle newSocket The socket handle to the newly spawned child socket * @param Socket newSocket The socket handle to the newly spawned child socket
* @param String remoteIP The remote IP * @param String remoteIP The remote IP
* @param any arg The argument set by SocketSetArg() for the listen-socket * @param any arg The argument set by SocketSetArg() for the listen-socket
* @noreturn * @noreturn
*/ */
funcenum SocketIncomingCB typedef SocketIncomingCB = function void (Socket socket, Socket newSocket, const char[] remoteIP, int remotePort, any arg);
{
public(Handle:socket, Handle:newSocket, const String:remoteIP[], remotePort, any:arg)
};
/** /**
* triggered if a socket receives data * triggered if a socket receives data
@ -229,59 +386,46 @@ funcenum SocketIncomingCB
* @note if not set otherwise by SocketSetOption(..., ConcatenateCallbacks, ...) receiveData will * @note if not set otherwise by SocketSetOption(..., ConcatenateCallbacks, ...) receiveData will
* never be longer than 4096 characters including \0 terminator * never be longer than 4096 characters including \0 terminator
* *
* @param Handle socket The socket handle pointing to the calling socket * @param Socket socket The socket handle pointing to the calling socket
* @param String receiveData The data which arrived, 0-terminated at receiveData[dataSize] * @param String receiveData The data which arrived, 0-terminated at receiveData[dataSize]
* @param cell_t dataSize The length of the arrived data excluding the 0-termination * @param int dataSize The length of the arrived data excluding the 0-termination
* @param any arg The argument set by SocketSetArg() for the socket * @param any arg The argument set by SocketSetArg() for the socket
* @noreturn * @noreturn
*/ */
funcenum SocketReceiveCB typedef SocketReceiveCB = function void (Socket socket, const char[] receiveData, const int dataSize, any arg);
{
public(Handle:socket, const String:receiveData[], const dataSize, any:arg)
};
/** /**
* called after a socket sent all items in its send queue successfully * called after a socket sent all items in its send queue successfully
* *
* @param Handle socket The socket handle pointing to the calling socket * @param Socket socket The socket handle pointing to the calling socket
* @param any arg The argument set by SocketSetArg() for the socket * @param any arg The argument set by SocketSetArg() for the socket
* @noreturn * @noreturn
*/ */
funcenum SocketSendqueueEmptyCB typedef SocketSendqueueEmptyCB = function void (Socket socket, any arg);
{
public(Handle:socket, any:arg)
};
/** /**
* called if a socket has been properly disconnected by the remote side * called if a socket has been properly disconnected by the remote side
* *
* @note You should call CloseHandle(socket) or reuse the socket before this function ends * @note You should call CloseHandle(socket) or reuse the socket before this function ends
* *
* @param Handle socket The socket handle pointing to the calling socket * @param Socket socket The socket handle pointing to the calling socket
* @param any arg The argument set by SocketSetArg() for the socket * @param any arg The argument set by SocketSetArg() for the socket
* @noreturn * @noreturn
*/ */
funcenum SocketDisconnectCB typedef SocketDisconnectCB = function void (Socket socket, any arg);
{
public(Handle:socket, any:arg)
};
/** /**
* called if an unrecoverable error occured, close the socket without an additional call to a disconnect callback * called if an unrecoverable error occured, close the socket without an additional call to a disconnect callback
* *
* @note You should call CloseHandle(socket) or reuse the socket before this function ends * @note You should call CloseHandle(socket) or reuse the socket before this function ends
* *
* @param Handle socket The socket handle pointing to the calling socket * @param Socket socket The socket handle pointing to the calling socket
* @param cell_t errorType The error type, see defines above * @param int errorType The error type, see defines above
* @param cell_t errorNum The errno, see errno.h for details * @param int errorNum The errno, see errno.h for details
* @param any arg The argument set by SocketSetArg() for the socket * @param any arg The argument set by SocketSetArg() for the socket
* @noreturn * @noreturn
*/ */
funcenum SocketErrorCB typedef SocketErrorCB = function void (Socket socket, const int errorType, const int errorNum, any arg);
{
public(Handle:socket, const errorType, const errorNum, any:arg)
};
/*************************************************************************************************/ /*************************************************************************************************/
/******************************************** natives ********************************************/ /******************************************** natives ********************************************/
@ -294,7 +438,7 @@ funcenum SocketErrorCB
* @param socket Socket handle to check * @param socket Socket handle to check
* @return bool The connection status * @return bool The connection status
*/ */
native bool:SocketIsConnected(Handle:socket); native bool SocketIsConnected(Handle socket);
/** /**
@ -304,18 +448,19 @@ native bool:SocketIsConnected(Handle:socket);
* *
* @param SocketType protocol The protocol to use, SOCKET_TCP is default * @param SocketType protocol The protocol to use, SOCKET_TCP is default
* @param SocketErrorCB efunc The error callback * @param SocketErrorCB efunc The error callback
* @return Handle The socket handle. Returns INVALID_HANDLE on failure * @return Socket The socket handle. Returns INVALID_HANDLE on failure
*/ */
native Handle:SocketCreate(SocketType:protocol=SOCKET_TCP, SocketErrorCB:efunc); native Socket SocketCreate(SocketType protocol=SOCKET_TCP, SocketErrorCB efunc);
/** /**
* Binds the socket to a local address * Binds the socket to a local address
* *
* @param Handle socket The handle of the socket to be used. * @param String hostname The hostname (or IP) to bind the socket to. * @param Handle socket The handle of the socket to be used.
* @param cell_t port The port to bind the socket to. * @param String hostname The hostname (or IP) to bind the socket to.
* @param int port The port to bind the socket to.
* @return bool true on success * @return bool true on success
*/ */
native bool:SocketBind(Handle:socket, const String:hostname[], port); native bool SocketBind(Handle socket, const char[] hostname, int port);
/** /**
* Connects a socket * Connects a socket
@ -327,11 +472,12 @@ native bool:SocketBind(Handle:socket, const String:hostname[], port);
* @param Handle socket The handle of the socket to be used. * @param Handle socket The handle of the socket to be used.
* @param SocketConnectCB cfunc The connect callback * @param SocketConnectCB cfunc The connect callback
* @param SocketReceiveCB rfunc The receive callback * @param SocketReceiveCB rfunc The receive callback
* @param SocketDisconnectCB dfunc The disconnect callback * @param String hostname The hostname (or IP) to connect to. * @param SocketDisconnectCB dfunc The disconnect callback
* @param cell_t port The port to connect to. * @param String hostname The hostname (or IP) to connect to.
* @param int port The port to connect to.
* @noreturn * @noreturn
*/ */
native SocketConnect(Handle:socket, SocketConnectCB:cfunc, SocketReceiveCB:rfunc, SocketDisconnectCB:dfunc, const String:hostname[], port); native void SocketConnect(Handle socket, SocketConnectCB cfunc, SocketReceiveCB rfunc, SocketDisconnectCB dfunc, const char[] hostname, int port);
/** /**
* Disconnects a socket * Disconnects a socket
@ -341,7 +487,7 @@ native SocketConnect(Handle:socket, SocketConnectCB:cfunc, SocketReceiveCB:rfunc
* *
* @noreturn * @noreturn
*/ */
native bool:SocketDisconnect(Handle:socket); native bool SocketDisconnect(Handle socket);
/** /**
* Makes a socket listen for incoming connections * Makes a socket listen for incoming connections
@ -350,7 +496,7 @@ native bool:SocketDisconnect(Handle:socket);
* @param SocketIncomingCB ifunc The callback for incoming connections * @param SocketIncomingCB ifunc The callback for incoming connections
* @return bool true on success * @return bool true on success
*/ */
native bool:SocketListen(Handle:socket, SocketIncomingCB:ifunc); native bool SocketListen(Handle socket, SocketIncomingCB ifunc);
/** /**
* Sends data through the socket. * Sends data through the socket.
@ -364,10 +510,12 @@ native bool:SocketListen(Handle:socket, SocketIncomingCB:ifunc);
* *
* @param Handle socket The handle of the socket to be used. * @param Handle socket The handle of the socket to be used.
* @param String data The data to send. * @param String data The data to send.
* @noreturn */ * @noreturn
native SocketSend(Handle:socket, const String:data[], size=-1); */
native void SocketSend(Handle socket, const char[] data, int size=-1);
/** * Sends UDP data through the socket to a specific destination. /**
* Sends UDP data through the socket to a specific destination.
* *
* @note specify size for binary safe operation * @note specify size for binary safe operation
* @note if size is not specified the \0 terminator will not be included * @note if size is not specified the \0 terminator will not be included
@ -379,9 +527,10 @@ native SocketSend(Handle:socket, const String:data[], size=-1);
* @param Handle socket The handle of the socket to be used. * @param Handle socket The handle of the socket to be used.
* @param String data The data to send. * @param String data The data to send.
* @param String hostname The hostname (or IP) to send to. * @param String hostname The hostname (or IP) to send to.
* @param cell_t port The port to send to. * @param int port The port to send to.
* @noreturn */ * @noreturn
native SocketSendTo(Handle:socket, const String:data[], size=-1, const String:hostname[], port); */
native void SocketSendTo(Handle socket, const char[] data, int size=-1, const char[] hostname, int port);
/** /**
* Set a socket option. * Set a socket option.
@ -389,8 +538,9 @@ native SocketSendTo(Handle:socket, const String:data[], size=-1, const String:ho
* @param Handle socket The handle of the socket to be used. May be INVALID_HANDLE if not essential. * @param Handle socket The handle of the socket to be used. May be INVALID_HANDLE if not essential.
* @param SocketOption option The option to modify (see enum SocketOption for details). * @param SocketOption option The option to modify (see enum SocketOption for details).
* @param cellt_ value The value to set the option to. * @param cellt_ value The value to set the option to.
* @return cell_t 1 on success. */ * @return int 1 on success.
native SocketSetOption(Handle:socket, SocketOption:option, value); */
native int SocketSetOption(Handle socket, SocketOption option, int value);
/** /**
@ -403,7 +553,7 @@ native SocketSetOption(Handle:socket, SocketOption:option, value);
* @param SocketReceiveCB rfunc The receive callback * @param SocketReceiveCB rfunc The receive callback
* @noreturn * @noreturn
*/ */
native SocketSetReceiveCallback(Handle:socket, SocketReceiveCB:rfunc); native void SocketSetReceiveCallback(Handle socket, SocketReceiveCB rfunc);
/** /**
* Defines the callback function for when the socket sent all items in its send queue * Defines the callback function for when the socket sent all items in its send queue
@ -416,7 +566,7 @@ native SocketSetReceiveCallback(Handle:socket, SocketReceiveCB:rfunc);
* @param SocketDisconnectCB dfunc The disconnect callback * @param SocketDisconnectCB dfunc The disconnect callback
* @noreturn * @noreturn
*/ */
native SocketSetSendqueueEmptyCallback(Handle:socket, SocketSendqueueEmptyCB:sfunc); native void SocketSetSendqueueEmptyCallback(Handle socket, SocketSendqueueEmptyCB sfunc);
/** /**
* Defines the callback function for when the socket was properly disconnected by the remote side * Defines the callback function for when the socket was properly disconnected by the remote side
@ -428,7 +578,7 @@ native SocketSetSendqueueEmptyCallback(Handle:socket, SocketSendqueueEmptyCB:sfu
* @param SocketDisconnectCB dfunc The disconnect callback * @param SocketDisconnectCB dfunc The disconnect callback
* @noreturn * @noreturn
*/ */
native SocketSetDisconnectCallback(Handle:socket, SocketDisconnectCB:dfunc); native void SocketSetDisconnectCallback(Handle socket, SocketDisconnectCB dfunc);
/** /**
* Defines the callback function for when the socket triggered an error * Defines the callback function for when the socket triggered an error
@ -440,7 +590,7 @@ native SocketSetDisconnectCallback(Handle:socket, SocketDisconnectCB:dfunc);
* @param SocketErrorCB efunc The error callback * @param SocketErrorCB efunc The error callback
* @noreturn * @noreturn
*/ */
native SocketSetErrorCallback(Handle:socket, SocketErrorCB:efunc); native void SocketSetErrorCallback(Handle socket, SocketErrorCB efunc);
/** /**
@ -450,7 +600,7 @@ native SocketSetErrorCallback(Handle:socket, SocketErrorCB:efunc);
* @param any arg The argument to set * @param any arg The argument to set
* @noreturn * @noreturn
*/ */
native SocketSetArg(Handle:socket, any:arg); native void SocketSetArg(Handle socket, any arg);
/** /**
* Retrieve the local system's hostname as the command "hostname" does. * Retrieve the local system's hostname as the command "hostname" does.
@ -460,12 +610,12 @@ native SocketSetArg(Handle:socket, any:arg);
* *
* @return 1 on success * @return 1 on success
*/ */
native SocketGetHostName(String:dest[], destLen); native int SocketGetHostName(char[] dest, int destLen);
/** /**
* _________________Do not edit below this line!_______________________ * _________________Do not edit below this line!_______________________
*/ */
public Extension:__ext_smsock = public Extension __ext_socket =
{ {
name = "Socket", name = "Socket",
file = "socket.ext", file = "socket.ext",
@ -480,3 +630,39 @@ public Extension:__ext_smsock =
required = 0, required = 0,
#endif #endif
}; };
#if !defined REQUIRE_EXTENSIONS
public void __ext_socket_SetNTVOptional()
{
MarkNativeAsOptional("Socket.Socket");
MarkNativeAsOptional("Socket.Bind");
MarkNativeAsOptional("Socket.Connect");
MarkNativeAsOptional("Socket.Disconnect");
MarkNativeAsOptional("Socket.Listen");
MarkNativeAsOptional("Socket.Send");
MarkNativeAsOptional("Socket.SendTo");
MarkNativeAsOptional("Socket.SetOption");
MarkNativeAsOptional("Socket.SetReceiveCallback");
MarkNativeAsOptional("Socket.SetSendqueueEmptyCallback");
MarkNativeAsOptional("Socket.SetDisconnectCallback");
MarkNativeAsOptional("Socket.SetErrorCallback");
MarkNativeAsOptional("Socket.SetArg");
MarkNativeAsOptional("Socket.GetHostName");
MarkNativeAsOptional("Socket.Connected.get");
MarkNativeAsOptional("SocketIsConnected");
MarkNativeAsOptional("SocketCreate");
MarkNativeAsOptional("SocketBind");
MarkNativeAsOptional("SocketConnect");
MarkNativeAsOptional("SocketDisconnect");
MarkNativeAsOptional("SocketListen");
MarkNativeAsOptional("SocketSend");
MarkNativeAsOptional("SocketSendTo");
MarkNativeAsOptional("SocketSetOption");
MarkNativeAsOptional("SocketSetReceiveCallback");
MarkNativeAsOptional("SocketSetSendqueueEmptyCallback");
MarkNativeAsOptional("SocketSetDisconnectCallback");
MarkNativeAsOptional("SocketSetErrorCallback");
MarkNativeAsOptional("SocketSetArg");
MarkNativeAsOptional("SocketGetHostName");
}
#endif

View file

@ -34,7 +34,8 @@
#define EXTRA_TANK_MIN_SEC 2.0 #define EXTRA_TANK_MIN_SEC 2.0
#define EXTRA_TANK_MAX_SEC 16.0 #define EXTRA_TANK_MAX_SEC 16.0
#define MAX_RANDOM_SPAWNS 12 // The map's max flow rate is divided by this. Parish Ch4 = ~16 items
#define MAX_RANDOM_SPAWNS 1700.0
#define DATE_FORMAT "%F at %I:%M %p" #define DATE_FORMAT "%F at %I:%M %p"
@ -348,6 +349,7 @@ public void OnPluginStart() {
} }
} }
g_currentChapter = L4D_GetCurrentChapter(); g_currentChapter = L4D_GetCurrentChapter();
UpdateSurvivorCount();
TryStartHud(); TryStartHud();
} }
@ -1097,7 +1099,7 @@ Action Timer_SetupNewClient(Handle h, int userid) {
PrintDebug(DEBUG_SPAWNLOGIC, "Giving new client (%N) tier 1: %s", client, weaponName); PrintDebug(DEBUG_SPAWNLOGIC, "Giving new client (%N) tier 1: %s", client, weaponName);
GiveWeapon(client, weaponName, 0.6, 0); GiveWeapon(client, weaponName, 0.6, 0);
} }
PrintDebug(DEBUG_SPAWNLOGIC, "%N: Giving random secondary / %d", secondaryWeapons.Length, client); PrintDebug(DEBUG_SPAWNLOGIC, "%N: Giving random secondary / %d", client, secondaryWeapons.Length);
if(secondaryWeapons.Length > 0) { if(secondaryWeapons.Length > 0) {
secondaryWeapons.GetString(GetRandomInt(0, secondaryWeapons.Length - 1), weaponName, sizeof(weaponName)); secondaryWeapons.GetString(GetRandomInt(0, secondaryWeapons.Length - 1), weaponName, sizeof(weaponName));
GiveWeapon(client, weaponName, 0.6, 1); GiveWeapon(client, weaponName, 0.6, 1);
@ -1371,54 +1373,6 @@ bool IsWallNearby(const float pos[3], WallCheck wall, float maxDistance = 80.0)
return TR_DidHit(); return TR_DidHit();
} }
void PopulateItemSpawns() {
ArrayList navs = new ArrayList();
L4D_GetAllNavAreas(navs);
navs.Sort(Sort_Random, Sort_Integer);
float pos[3];
float percentage = hExtraSpawnBasePercentage.FloatValue * (g_survivorCount - 4);
PrintToServer("[EPI] Populating extra item spawns based on player count (%d-4) | Percentage %.2f%%", g_survivorCount, percentage * 100);
int tier;
// On first chapter, 10% chance to give tier 2
if(g_currentChapter == 1) tier = GetRandomFloat() < 0.15 ? 1 : 0;
else tier = DiceRoll(0, 3, 2, BIAS_LEFT);
int count;
for(int i = 0; i < navs.Length; i++) {
Address nav = navs.Get(i);
int spawnFlags = L4D_GetNavArea_SpawnAttributes(nav);
int baseFlags = L4D_GetNavArea_AttributeFlags(nav);
if(!(baseFlags & (NAV_BASE_FLOW_BLOCKED)) &&
!(spawnFlags & NAV_SPAWN_ESCAPE_ROUTE|NAV_SPAWN_DESTROYED_DOOR|NAV_SPAWN_CHECKPOINT|NAV_SPAWN_NO_MOBS|NAV_SPAWN_STOP_SCAN))
{
L4D_FindRandomSpot(view_as<int>(nav), pos);
bool north = IsWallNearby(pos, Wall_North);
bool east = IsWallNearby(pos, Wall_East);
bool south = IsWallNearby(pos, Wall_South);
bool west = IsWallNearby(pos, Wall_West);
// TODO: collision check (windows like c1m1)
int wallCount = 0;
if(north) wallCount++;
if(east) wallCount++;
if(south) wallCount++;
if(west) wallCount++;
if(wallCount >= 2) {
if(GetURandomFloat() < percentage) {
int wpn;
pos[2] += 7.0;
if(GetURandomFloat() > 0.30) {
wpn = CreateWeaponSpawn(pos, "", tier);
} else {
wpn = CreateRandomMeleeSpawn(pos);
}
if(wpn == -1) continue;
if(++count > MAX_RANDOM_SPAWNS) break;
}
}
}
}
PrintToServer("[EPI] Spawned %d/%d new item spawns (tier=%d)", count, MAX_RANDOM_SPAWNS, tier);
delete navs;
}
char WEAPON_SPAWN_CLASSNAMES[32][] = { char WEAPON_SPAWN_CLASSNAMES[32][] = {
"weapon_pistol_magnum_spawn","weapon_smg_spawn","weapon_smg_silenced_spawn","weapon_pumpshotgun_spawn","weapon_shotgun_chrome_spawn","weapon_pipe_bomb_spawn","weapon_upgradepack_incendiary_spawn","weapon_upgradepack_explosive_spawn","weapon_adrenaline_spawn","weapon_smg_mp5_spawn","weapon_defibrillator_spawn","weapon_propanetank_spawn","weapon_oxygentank_spawn","weapon_chainsaw_spawn","weapon_gascan_spawn","weapon_ammo_spawn","weapon_sniper_scout_spawn","weapon_hunting_rifle_spawn","weapon_pain_pills_spawn","weapon_rifle_spawn","weapon_rifle_desert_spawn","weapon_sniper_military_spawn","weapon_autoshotgun_spawn","weapon_shotgun_spas_spawn","weapon_first_aid_kit_spawn","weapon_molotov_spawn","weapon_vomitjar_spawn","weapon_rifle_ak47_spawn","weapon_rifle_sg552_spawn","weapon_grenade_launcher_spawn","weapon_sniper_awp_spawn","weapon_rifle_m60_spawn" "weapon_pistol_magnum_spawn","weapon_smg_spawn","weapon_smg_silenced_spawn","weapon_pumpshotgun_spawn","weapon_shotgun_chrome_spawn","weapon_pipe_bomb_spawn","weapon_upgradepack_incendiary_spawn","weapon_upgradepack_explosive_spawn","weapon_adrenaline_spawn","weapon_smg_mp5_spawn","weapon_defibrillator_spawn","weapon_propanetank_spawn","weapon_oxygentank_spawn","weapon_chainsaw_spawn","weapon_gascan_spawn","weapon_ammo_spawn","weapon_sniper_scout_spawn","weapon_hunting_rifle_spawn","weapon_pain_pills_spawn","weapon_rifle_spawn","weapon_rifle_desert_spawn","weapon_sniper_military_spawn","weapon_autoshotgun_spawn","weapon_shotgun_spas_spawn","weapon_first_aid_kit_spawn","weapon_molotov_spawn","weapon_vomitjar_spawn","weapon_rifle_ak47_spawn","weapon_rifle_sg552_spawn","weapon_grenade_launcher_spawn","weapon_sniper_awp_spawn","weapon_rifle_m60_spawn"
@ -1676,7 +1630,6 @@ void UnlockDoor(int flag) {
SetVariantString("Unlock"); SetVariantString("Unlock");
AcceptEntityInput(entity, "SetAnimation"); AcceptEntityInput(entity, "SetAnimation");
g_saferoomDoorEnt = INVALID_ENT_REFERENCE; g_saferoomDoorEnt = INVALID_ENT_REFERENCE;
PopulateItems();
} }
} }
@ -1709,7 +1662,7 @@ Action Timer_UpdateHud(Handle h) {
// TODO: name scrolling // TODO: name scrolling
// TODO: name cache (hook name change event), strip out invalid // TODO: name cache (hook name change event), strip out invalid
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) { if(IsClientInGame(i) && GetClientTeam(i) == 2) {
data[0] = '\0'; data[0] = '\0';
prefix[0] = '\0'; prefix[0] = '\0';
int health = GetClientRealHealth(i); int health = GetClientRealHealth(i);
@ -1723,8 +1676,8 @@ Action Timer_UpdateHud(Handle h) {
} else { } else {
Format(prefix, HUD_NAME_LENGTH, "%s", playerData[client].nameCache[playerData[client].scrollIndex]); Format(prefix, HUD_NAME_LENGTH, "%s", playerData[client].nameCache[playerData[client].scrollIndex]);
} }
if(g_isSpeaking[i]) // if(g_isSpeaking[i])
Format(prefix, HUD_NAME_LENGTH, "🔊%s", prefix); // Format(prefix, HUD_NAME_LENGTH, "%s", prefix);
playerData[client].AdvanceScroll(); playerData[client].AdvanceScroll();
@ -1769,9 +1722,9 @@ Action Timer_UpdateHud(Handle h) {
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
void PopulateItems() { void PopulateItems() {
PrintToServer("[EPI:TEMP] PopulateItems hasRan=%b finale=%b", g_areItemsPopulated, L4D_IsMissionFinalMap(true));
if(g_areItemsPopulated) return; if(g_areItemsPopulated) return;
UpdateSurvivorCount(); UpdateSurvivorCount();
PrintToServer("[EPI:TEMP] PopulateItems hasRan=%b finale=%b willRun=%b players=%d", g_areItemsPopulated, L4D_IsMissionFinalMap(true), !g_areItemsPopulated&&IsEPIActive, g_realSurvivorCount);
if(!IsEPIActive()) return; if(!IsEPIActive()) return;
g_areItemsPopulated = true; g_areItemsPopulated = true;
@ -1799,6 +1752,7 @@ void PopulateItems() {
if(count == 4) { if(count == 4) {
// Some item spawns are only for 4 players, so here we set to # of players: // Some item spawns are only for 4 players, so here we set to # of players:
SetEntProp(i, Prop_Data, "m_itemCount", g_survivorCount); SetEntProp(i, Prop_Data, "m_itemCount", g_survivorCount);
++affected;
} else if(count > 0 && GetURandomFloat() < percentage) { } else if(count > 0 && GetURandomFloat() < percentage) {
SetEntProp(i, Prop_Data, "m_itemCount", ++count); SetEntProp(i, Prop_Data, "m_itemCount", ++count);
++affected; ++affected;
@ -1812,6 +1766,64 @@ void PopulateItems() {
PopulateCabinets(); PopulateCabinets();
} }
void PopulateItemSpawns(int minWalls = 4) {
ArrayList navs = new ArrayList();
L4D_GetAllNavAreas(navs);
navs.Sort(Sort_Random, Sort_Integer);
float pos[3];
float percentage = hExtraSpawnBasePercentage.FloatValue * (g_survivorCount - 4);
PrintToServer("[EPI] Populating extra item spawns based on player count (%d-4) | Percentage %.2f%%", g_survivorCount, percentage * 100);
int tier;
// On first chapter, 10% chance to give tier 2
if(g_currentChapter == 1) tier = GetRandomFloat() < 0.15 ? 1 : 0;
else tier = DiceRoll(0, 3, 2, BIAS_LEFT);
int count;
float mapFlowMax = L4D2Direct_GetMapMaxFlowDistance();
PrintToServer("[EPI] PopulateItemSpawns: flow[0, %f]", mapFlowMax);
int maxSpawns = RoundFloat(mapFlowMax / MAX_RANDOM_SPAWNS);
for(int i = 0; i < navs.Length; i++) {
Address nav = navs.Get(i);
int spawnFlags = L4D_GetNavArea_SpawnAttributes(nav);
int baseFlags = L4D_GetNavArea_AttributeFlags(nav);
if((!(baseFlags & NAV_BASE_FLOW_BLOCKED)) &&
!(spawnFlags & (NAV_SPAWN_ESCAPE_ROUTE|NAV_SPAWN_DESTROYED_DOOR|NAV_SPAWN_CHECKPOINT|NAV_SPAWN_NO_MOBS|NAV_SPAWN_STOP_SCAN)))
{
L4D_FindRandomSpot(view_as<int>(nav), pos);
bool north = IsWallNearby(pos, Wall_North);
bool east = IsWallNearby(pos, Wall_East);
bool south = IsWallNearby(pos, Wall_South);
bool west = IsWallNearby(pos, Wall_West);
// TODO: collision check (windows like c1m1)
int wallCount = 0;
if(north) wallCount++;
if(east) wallCount++;
if(south) wallCount++;
if(west) wallCount++;
if(wallCount >= minWalls) {
if(GetURandomFloat() < percentage) {
int wpn;
pos[2] += 7.0;
if(GetURandomFloat() > 0.30) {
wpn = CreateWeaponSpawn(pos, "", tier);
} else {
wpn = CreateRandomMeleeSpawn(pos);
}
if(wpn == -1) continue;
if(++count >= maxSpawns) break;
}
}
}
}
PrintToServer("[EPI] Spawned %d/%d new item spawns (tier=%d)", count, maxSpawns, tier);
delete navs;
// Incase there was no suitable spots, try again:
minWalls--;
if(count == 0 && minWalls > 0) {
PopulateItemSpawns(minWalls);
}
}
void PopulateCabinets() { void PopulateCabinets() {
char classname[64]; char classname[64];
//Cabinet logic //Cabinet logic

View file

@ -622,24 +622,24 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
bool isRotate; bool isRotate;
int flags = GetEntityFlags(client); int flags = GetEntityFlags(client);
if(buttons & IN_RELOAD && ~buttons & IN_ZOOM) { if(buttons & IN_RELOAD) {
if(!g_inRotate[client]) { if(!g_inRotate[client]) {
g_inRotate[client] = true; g_inRotate[client] = true;
} }
if(buttons & IN_JUMP) { if(!(oldButtons & IN_JUMP) && (buttons & IN_JUMP)) {
buttons = buttons & ~IN_JUMP; buttons &= ~IN_JUMP;
Editor[client].CycleStacker(tick); Editor[client].CycleStacker(tick);
} if(buttons & IN_SPEED) { } else if(!(oldButtons & IN_SPEED) && (buttons & IN_SPEED)) {
Editor[client].ToggleCollision(tick); Editor[client].ToggleCollision(tick);
return Plugin_Handled; return Plugin_Handled;
} else if(buttons & IN_DUCK) { } else if(!(oldButtons & IN_DUCK) && (buttons & IN_DUCK)) {
Editor[client].ToggleCollisionRotate(tick); Editor[client].ToggleCollisionRotate(tick);
return Plugin_Handled; return Plugin_Handled;
} else { } else {
PrintCenterText(client, "%.1f %.1f %.1f", Editor[client].angles[0], Editor[client].angles[1], Editor[client].angles[2]); PrintCenterText(client, "%.1f %.1f %.1f", Editor[client].angles[0], Editor[client].angles[1], Editor[client].angles[2]);
isRotate = true; isRotate = true;
SetEntityFlags(client, flags |= FL_FROZEN); SetEntityFlags(client, flags |= FL_FROZEN);
if(buttons & IN_ATTACK) Editor[client].CycleAxis(tick); if(!(oldButtons & IN_ATTACK) && (buttons & IN_ATTACK)) Editor[client].CycleAxis(tick);
else if(buttons & IN_ATTACK2) Editor[client].CycleSnapAngle(tick); else if(buttons & IN_ATTACK2) Editor[client].CycleSnapAngle(tick);
// Rotation control: // Rotation control:

View file

@ -61,6 +61,12 @@ enum GameState {
State_Restarting, State_Restarting,
State_Hunting State_Hunting
} }
char GAME_STATE_DEBUG[4][] = {
"Startup",
"Hiding",
"Restarting",
"Hunting"
};
bool isNearbyPlaying[MAXPLAYERS+1]; bool isNearbyPlaying[MAXPLAYERS+1];
bool wasThirdPersonVomitted[MAXPLAYERS+1]; bool wasThirdPersonVomitted[MAXPLAYERS+1];
@ -69,6 +75,7 @@ int currentSeeker;
int currentPlayers = 0; int currentPlayers = 0;
Handle suspenseTimer, thirdPersonTimer, peekCamStopTimer, hiderCheckTimer; Handle suspenseTimer, thirdPersonTimer, peekCamStopTimer, hiderCheckTimer;
Handle startupTimer;
int g_BeamSprite; int g_BeamSprite;
@ -134,15 +141,22 @@ public void OnClientConnected(int client) {
if(!IsFakeClient(client)) { if(!IsFakeClient(client)) {
currentPlayers++; currentPlayers++;
if(isEnabled) { if(isEnabled) {
GameState state = GetState();
// Once first player joins, wait for others to join // Once first player joins, wait for others to join
if(currentPlayers == 1 && state == State_Startup) { if(currentPlayers == 1) {
CreateTimer(10.0, Timer_KeepWaiting, _, TIMER_REPEAT); StartWaiting();
} }
} }
} }
} }
void StartWaiting(bool fireInstantly = false) {
if(GetState() == State_Startup && startupTimer != null) {
startupTimer = CreateTimer(10.0, Timer_KeepWaiting, _, TIMER_REPEAT);
if(fireInstantly)
TriggerTimer(startupTimer);
}
}
public void OnClientPutInServer(int client) { public void OnClientPutInServer(int client) {
if(isEnabled && !IsFakeClient(client)) { if(isEnabled && !IsFakeClient(client)) {
ChangeClientTeam(client, 1); ChangeClientTeam(client, 1);
@ -160,7 +174,12 @@ public Action Timer_KeepWaiting(Handle h) {
SetTick(-40); SetTick(-40);
SetState(State_Startup); SetState(State_Startup);
PrintHintTextToAll("Waiting for players to join..."); PrintHintTextToAll("Waiting for players to join...");
return IsGameSoloOrPlayersLoading() ? Plugin_Continue : Plugin_Stop; if(IsGameSoloOrPlayersLoading()) {
return Plugin_Continue;
} else {
startupTimer = null;
return Plugin_Handled;
}
} }
public void OnClientDisconnect(int client) { public void OnClientDisconnect(int client) {
@ -189,8 +208,7 @@ public void OnMapStart() {
} }
strcopy(g_currentSet, sizeof(g_currentSet), "default"); strcopy(g_currentSet, sizeof(g_currentSet), "default");
if(IsGameSoloOrPlayersLoading()) { if(IsGameSoloOrPlayersLoading()) {
Handle timer = CreateTimer(10.0, Timer_KeepWaiting, _, TIMER_REPEAT); StartWaiting(true);
TriggerTimer(timer);
PrintToServer("[H&S] Player(s) are connecting, or solo. Waiting..."); PrintToServer("[H&S] Player(s) are connecting, or solo. Waiting...");
SetState(State_Startup); SetState(State_Startup);
} }
@ -595,10 +613,11 @@ public Action Timer_Music(Handle h) {
int playerCount; int playerCount;
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && i != currentSeeker) { if(IsClientInGame(i) && i != currentSeeker) {
playerCount++; playerCount++;
// GetClientAbsOrigin(i, playerLoc); // GetClientAbsOrigin(i, playerLoc);
// float dist = GetVectorDistance(seekerLoc, playerLoc, true); // float dist = GetVectorDistance(seekerLoc, playerLoc, true);
if(currentSeeker == 0) continue;
float dist = GetFlowDistance(currentSeeker, i); float dist = GetFlowDistance(currentSeeker, i);
if(dist <= HEARTBEAT_CLOSE_DIST) { if(dist <= HEARTBEAT_CLOSE_DIST) {
StopSound(i, SNDCHAN_AUTO, SOUND_SUSPENSE_1); StopSound(i, SNDCHAN_AUTO, SOUND_SUSPENSE_1);

View file

@ -59,37 +59,41 @@ public void OnPluginStart() {
char currentMap[64]; char currentMap[64];
bool hasRan;
// TODO: on round start // TODO: on round start
public void OnMapStart() { public void OnMapStart() {
g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true); g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true);
GetCurrentMap(currentMap, sizeof(currentMap)); GetCurrentMap(currentMap, sizeof(currentMap));
if(cvarEnabled.BoolValue)
CreateTimer(5.0, Timer_Run);
} }
public void OnMapEnd() { public void OnMapEnd() {
Cleanup(); Cleanup();
} }
bool hasRan;
public void OnMapInit(const char[] map) { public void OnMapInit(const char[] map) {
if(cvarEnabled.BoolValue) { // if(cvarEnabled.BoolValue) {
if(LoadMapData(currentMap, FLAG_NONE) && g_MapData.lumpEdits.Length > 0) { // if(LoadMapData(currentMap, FLAG_NONE) && g_MapData.lumpEdits.Length > 0) {
Log("Found %d lump edits, running...", g_MapData.lumpEdits.Length); // Log("Found %d lump edits, running...", g_MapData.lumpEdits.Length);
LumpEditData lump; // LumpEditData lump;
for(int i = 0; i < g_MapData.lumpEdits.Length; i++) { // for(int i = 0; i < g_MapData.lumpEdits.Length; i++) {
g_MapData.lumpEdits.GetArray(i, lump); // g_MapData.lumpEdits.GetArray(i, lump);
lump.Trigger(); // lump.Trigger();
} // }
} // hasRan = true;
} // }
hasRan = false; // }
} }
public void OnClientPutInServer(int client) { public void OnConfigsExecuted() {
if(!hasRan) {
hasRan = true; }
if(cvarEnabled.BoolValue)
RunMap(currentMap, FLAG_NONE); Action Timer_Run(Handle h) {
} if(cvarEnabled.BoolValue)
RunMap(currentMap, FLAG_NONE);
return Plugin_Handled;
} }
stock int GetLookingEntity(int client, TraceEntityFilter filter) { stock int GetLookingEntity(int client, TraceEntityFilter filter) {
@ -438,7 +442,7 @@ public bool LoadMapData(const char[] map, int flags) {
json_cleanup_and_delete(data); json_cleanup_and_delete(data);
profiler.Stop(); profiler.Stop();
Log("Parsed map file and found %d scenes in %.4f seconds", g_MapData.scenes.Length, profiler.Time); Log("Parsed map file for %s(%d) and found %d scenes in %.4f seconds", map, flags, g_MapData.scenes.Length, profiler.Time);
delete profiler; delete profiler;
delete file; delete file;
return true; return true;