sourcemod-plugins/scripting/sceneprocessor.sp

855 lines
19 KiB
SourcePawn

#define PLUGIN_VERSION "1.33.2"
#pragma semicolon 1
#pragma newdecls required
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <sceneprocessor>
int iSkippedFrames;
char sVocalizeScene[MAXPLAYERS+1][MAX_VOCALIZE_LENGTH];
bool bSceneHasInitiator[MAXPLAYERS+1], bScenesUnprocessed, bUnvocalizedCommands, bJailbreakVocalize, bIsL4D;
float fStartTimeStamp, fVocalizePreDelay[MAXPLAYERS+1], fVocalizePitch[MAXPLAYERS+1];
Handle hSceneStageForward, hVocalizeCommandForward;
ArrayList alVocalize;
ArrayStack asScene;
enum struct SceneData
{
SceneStages ssDataBit;
bool bInFakePostSpawn;
float fTimeStampData;
int iActorData;
int iInitiatorData;
char sFileData[MAX_SCENEFILE_LENGTH];
char sVocalizeData[MAX_VOCALIZE_LENGTH];
float fPreDelayData;
float fPitchData;
}
SceneData nSceneData[2048];
int iScenePlaying[MAXPLAYERS+1], iVocalizeTick[MAXPLAYERS+1], iVocalizeInitiator[MAXPLAYERS+1];
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
EngineVersion evGame = GetEngineVersion();
if (evGame == Engine_Left4Dead)
{
bIsL4D = true;
}
else if (evGame != Engine_Left4Dead2)
{
strcopy(error, err_max, "[SP] Plugin Supports L4D And L4D2 Only!");
return APLRes_Failure;
}
CreateNative("GetSceneStage", SP_GetSceneStage);
CreateNative("GetSceneStartTimeStamp", SP_GetSceneStartTimeStamp);
CreateNative("GetActorFromScene", SP_GetSceneActor);
CreateNative("GetSceneFromActor", SP_GetActorScene);
CreateNative("GetSceneInitiator", SP_GetSceneInitiator);
CreateNative("GetSceneFile", SP_GetSceneFile);
CreateNative("GetSceneVocalize", SP_GetSceneVocalize);
CreateNative("GetScenePreDelay", SP_GetScenePreDelay);
CreateNative("SetScenePreDelay", SP_SetScenePreDelay);
CreateNative("GetScenePitch", SP_GetScenePitch);
CreateNative("SetScenePitch", SP_SetScenePitch);
CreateNative("CancelScene", SP_CancelScene);
CreateNative("PerformScene", SP_PerformScene);
CreateNative("PerformSceneEx", SP_PerformSceneEx);
RegPluginLibrary("sceneprocessor");
return APLRes_Success;
}
public any SP_GetSceneStage(Handle plugin, int numParams)
{
if (numParams == 0)
{
return SceneStage_Unknown;
}
int scene = GetNativeCell(1);
if (scene < 1 || scene > 2048 || !IsValidEntity(scene))
{
return SceneStage_Unknown;
}
return nSceneData[scene].ssDataBit;
}
public any SP_GetSceneStartTimeStamp(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0.0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0.0;
}
return nSceneData[scene].fTimeStampData;
}
public int SP_GetActorScene(Handle plugin, int numParams)
{
if (numParams == 0)
{
return INVALID_ENT_REFERENCE;
}
int iActor = GetNativeCell(1);
if (iActor < 1 || iActor > MaxClients || !IsClientInGame(iActor) || GetClientTeam(iActor) != 2 || !IsPlayerAlive(iActor))
{
return INVALID_ENT_REFERENCE;
}
return iScenePlaying[iActor];
}
public int SP_GetSceneActor(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
return nSceneData[scene].iActorData;
}
public int SP_GetSceneInitiator(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
return nSceneData[scene].iInitiatorData;
}
public int SP_GetSceneFile(Handle plugin, int numParams)
{
if (numParams != 3)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
int len = GetNativeCell(3);
int bytesWritten;
SetNativeString(2, nSceneData[scene].sFileData, len, _, bytesWritten);
return bytesWritten;
}
public int SP_GetSceneVocalize(Handle plugin, int numParams)
{
if (numParams != 3)
{
return 0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0;
}
int len = GetNativeCell(3);
int bytesWritten;
SetNativeString(2, nSceneData[scene].sVocalizeData, len, _, bytesWritten);
return bytesWritten;
}
public any SP_GetScenePreDelay(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0.0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0.0;
}
return nSceneData[scene].fPreDelayData;
}
public int SP_SetScenePreDelay(Handle plugin, int numParams)
{
if (numParams != 2)
{
return;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return;
}
float fPreDelay = GetNativeCell(2);
SetEntPropFloat(scene, Prop_Data, "m_flPreDelay", fPreDelay);
nSceneData[scene].fPreDelayData = fPreDelay;
}
public any SP_GetScenePitch(Handle plugin, int numParams)
{
if (numParams == 0)
{
return 0.0;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return 0.0;
}
return nSceneData[scene].fPitchData;
}
public int SP_SetScenePitch(Handle plugin, int numParams)
{
if (numParams != 2)
{
return;
}
int scene = GetNativeCell(1);
if (!IsValidScene(scene))
{
return;
}
float fPitch = GetNativeCell(2);
SetEntPropFloat(scene, Prop_Data, "m_fPitch", fPitch);
nSceneData[scene].fPitchData = fPitch;
}
public int SP_CancelScene(Handle plugin, int numParams)
{
if (numParams == 0)
{
return;
}
int scene = GetNativeCell(1);
if (scene < 1 || scene > 2048 || !IsValidEntity(scene))
{
return;
}
SceneStages ssBit = nSceneData[scene].ssDataBit;
if (ssBit == SceneStage_Unknown)
{
return;
}
else if (ssBit == SceneStage_Started || (ssBit == SceneStage_SpawnedPost && nSceneData[scene].bInFakePostSpawn))
{
AcceptEntityInput(scene, "Cancel");
}
else if (ssBit != SceneStage_Cancelled && ssBit != SceneStage_Completion && ssBit != SceneStage_Killed)
{
AcceptEntityInput(scene, "Kill");
}
}
public int SP_PerformScene(Handle plugin, int numParams)
{
if (numParams < 2)
{
return;
}
int client = GetNativeCell(1);
if (client < 1 || client > MaxClients || !IsClientInGame(client) || GetClientTeam(client) != 2 || !IsPlayerAlive(client))
{
return;
}
static char sVocalize[MAX_VOCALIZE_LENGTH], sFile[MAX_SCENEFILE_LENGTH];
float fPreDelay = DEFAULT_SCENE_PREDELAY, fPitch = DEFAULT_SCENE_PITCH;
int iInitiator = SCENE_INITIATOR_PLUGIN;
if (GetNativeString(2, sVocalize, MAX_VOCALIZE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown Vocalize Parameter!");
return;
}
if (numParams >= 3)
{
if (GetNativeString(3, sFile, MAX_SCENEFILE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown File Parameter!");
return;
}
}
if (numParams >= 4)
{
fPreDelay = GetNativeCell(4);
}
if (numParams >= 5)
{
fPitch = GetNativeCell(5);
}
if (numParams >= 6)
{
iInitiator = GetNativeCell(6);
}
Scene_Perform(client, sVocalize, sFile, fPreDelay, fPitch, iInitiator);
}
public int SP_PerformSceneEx(Handle plugin, int numParams)
{
if (numParams < 2)
{
return;
}
int client = GetNativeCell(1);
if (client < 1 || client > MaxClients || !IsClientInGame(client) || GetClientTeam(client) != 2 || !IsPlayerAlive(client))
{
return;
}
static char sVocalize[MAX_VOCALIZE_LENGTH], sFile[MAX_SCENEFILE_LENGTH];
float fPreDelay = DEFAULT_SCENE_PREDELAY, fPitch = DEFAULT_SCENE_PITCH;
int iInitiator = SCENE_INITIATOR_PLUGIN;
if (GetNativeString(2, sVocalize, MAX_VOCALIZE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown Vocalize Parameter!");
return;
}
if (numParams >= 3)
{
if (GetNativeString(3, sFile, MAX_SCENEFILE_LENGTH) != SP_ERROR_NONE)
{
ThrowNativeError(SP_ERROR_NATIVE, "Unknown File Parameter!");
return;
}
}
if (numParams >= 4)
{
fPreDelay = GetNativeCell(4);
}
if (numParams >= 5)
{
fPitch = GetNativeCell(5);
}
if (numParams >= 6)
{
iInitiator = GetNativeCell(6);
}
Scene_Perform(client, sVocalize, sFile, fPreDelay, fPitch, iInitiator, true);
}
public Plugin myinfo =
{
name = "Scene Processor",
author = "Buster \"Mr. Zero\" Nielsen (Fork by cravenge & Dragokas)",
description = "Provides Forwards and Natives For Scenes' Manipulation.",
version = PLUGIN_VERSION,
url = "https://forums.alliedmods.net/showthread.php?t=241585"
};
public void OnPluginStart()
{
hSceneStageForward = CreateGlobalForward("OnSceneStageChanged", ET_Ignore, Param_Cell, Param_Cell);
hVocalizeCommandForward = CreateGlobalForward("OnVocalizeCommand", ET_Hook, Param_Cell, Param_String, Param_Cell);
CreateConVar("sceneprocessor_version", PLUGIN_VERSION, "Scene Processor Version", FCVAR_SPONLY|FCVAR_NOTIFY|FCVAR_DONTRECORD);
if (!bIsL4D)
{
ConVar spJailbreakVocalize = CreateConVar("sceneprocessor_jailbreak_vocalize", "1", "Enable/Disable Jailbreak Vocalizations", FCVAR_SPONLY|FCVAR_NOTIFY);
spJailbreakVocalize.AddChangeHook(OnSPCVarChanged);
bJailbreakVocalize = spJailbreakVocalize.BoolValue;
}
AddCommandListener(OnVocalizeCmd, "vocalize");
asScene = new ArrayStack();
alVocalize = new ArrayList(MAX_VOCALIZE_LENGTH);
for (int i = 1; i < 2049; i++)
{
if (IsValidEntity(i) && IsValidEdict(i))
{
SceneData_SetStage(i, SceneStage_Unknown);
}
}
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
{
ResetClientVocalizeData(i);
}
}
}
public void OnSPCVarChanged(ConVar cvar, const char[] sOldValue, const char[] sNewValue)
{
bJailbreakVocalize = cvar.BoolValue;
}
public Action OnVocalizeCmd(int client, const char[] command, int args)
{
if (client == 0 || args == 0)
{
return Plugin_Continue;
}
if (!IsClientInGame(client))
{
return Plugin_Handled;
}
static char sVocalize[128];
GetCmdArg(1, sVocalize, sizeof(sVocalize));
if (!bIsL4D && args != 2)
{
if (bJailbreakVocalize)
{
JailbreakVocalize(client, sVocalize);
}
return Plugin_Handled;
}
int iTick = GetGameTickCount();
if (!bSceneHasInitiator[client] || (iVocalizeTick[client] > 0 && iVocalizeTick[client] != iTick))
{
iVocalizeInitiator[client] = client;
if (!bIsL4D && args > 1 && StrEqual(sVocalize, "smartlook", false))
{
static char sTime[32];
GetCmdArg(2, sTime, sizeof(sTime));
if (StrEqual(sTime, "auto", false))
{
iVocalizeInitiator[client] = SCENE_INITIATOR_WORLD;
}
}
}
strcopy(sVocalizeScene[client], MAX_VOCALIZE_LENGTH, sVocalize);
iVocalizeTick[client] = iTick;
Action aResult = Plugin_Continue;
Call_StartForward(hVocalizeCommandForward);
Call_PushCell(client);
Call_PushString(sVocalize);
Call_PushCell(iVocalizeInitiator[client]);
Call_Finish(aResult);
return (aResult == Plugin_Stop) ? Plugin_Handled : Plugin_Continue;
}
public void OnPluginEnd()
{
RemoveCommandListener(OnVocalizeCmd, "vocalize");
}
public void OnMapStart()
{
iSkippedFrames = 0;
fStartTimeStamp = GetGameTime();
}
public void OnEntityCreated(int entity, const char[] classname)
{
if (entity < 1 || entity > 2048)
{
return;
}
if (StrEqual(classname, "instanced_scripted_scene"))
{
SDKHook(entity, SDKHook_SpawnPost, OnSpawnPost);
SceneData_SetStage(entity, SceneStage_Created);
}
}
public void OnSpawnPost(int entity)
{
int iActor = GetEntPropEnt(entity, Prop_Data, "m_hOwner");
nSceneData[entity].iActorData = iActor;
static char sFile[MAX_SCENEFILE_LENGTH];
GetEntPropString(entity, Prop_Data, "m_iszSceneFile", sFile, MAX_SCENEFILE_LENGTH);
strcopy(nSceneData[entity].sFileData, MAX_SCENEFILE_LENGTH, sFile);
nSceneData[entity].fPitchData = GetEntPropFloat(entity, Prop_Data, "m_fPitch");
if (iActor > 0 && iActor <= MaxClients && IsClientInGame(iActor))
{
if (iVocalizeTick[iActor] == GetGameTickCount())
{
strcopy(nSceneData[entity].sVocalizeData, MAX_VOCALIZE_LENGTH, sVocalizeScene[iActor]);
nSceneData[entity].iInitiatorData = iVocalizeInitiator[iActor];
nSceneData[entity].fPreDelayData = fVocalizePreDelay[iActor];
nSceneData[entity].fPitchData = fVocalizePitch[iActor];
}
ResetClientVocalizeData(iActor);
}
SetEntPropFloat(entity, Prop_Data, "m_fPitch", nSceneData[entity].fPitchData);
SetEntPropFloat(entity, Prop_Data, "m_flPreDelay", nSceneData[entity].fPreDelayData);
asScene.Push(entity);
bScenesUnprocessed = true;
HookSingleEntityOutput(entity, "OnStart", OnSceneStart_EntOutput);
HookSingleEntityOutput(entity, "OnCanceled", OnSceneCanceled_EntOutput);
SceneData_SetStage(entity, SceneStage_Spawned);
}
public void OnSceneStart_EntOutput(const char[] output, int caller, int activator, float delay)
{
if (caller < 1 || caller > 2048 || !IsValidEntity(caller))
{
return;
}
static char sFile[MAX_SCENEFILE_LENGTH];
strcopy(sFile, MAX_SCENEFILE_LENGTH, nSceneData[caller].sFileData);
if (!sFile[0])
{
return;
}
nSceneData[caller].fTimeStampData = GetEngineTime();
if (nSceneData[caller].ssDataBit == SceneStage_Spawned)
{
nSceneData[caller].bInFakePostSpawn = true;
SceneData_SetStage(caller, SceneStage_SpawnedPost);
}
if (nSceneData[caller].ssDataBit == SceneStage_SpawnedPost)
{
int iActor = nSceneData[caller].iActorData;
if (iActor > 0 && iActor <= MaxClients && IsClientInGame(iActor))
{
iScenePlaying[iActor] = caller;
}
SceneData_SetStage(caller, SceneStage_Started);
}
}
public void OnSceneCanceled_EntOutput(const char[] output, int caller, int activator, float delay)
{
if (caller < 1 || caller > 2048 || !IsValidEntity(caller))
{
return;
}
for (int i = 1; i <= MaxClients; i++)
{
if (iScenePlaying[i] == caller)
{
iScenePlaying[i] = INVALID_ENT_REFERENCE;
break;
}
}
SceneData_SetStage(caller, SceneStage_Cancelled);
}
public void OnEntityDestroyed(int entity)
{
if (entity < 1 || entity > 2048 || !IsValidEdict(entity))
{
return;
}
static char sEntityClass[64];
GetEdictClassname(entity, sEntityClass, sizeof(sEntityClass));
if (!StrEqual(sEntityClass, "instanced_scripted_scene"))
{
return;
}
SDKUnhook(entity, SDKHook_SpawnPost, OnSpawnPost);
SceneStages ssBit = nSceneData[entity].ssDataBit;
if (ssBit != SceneStage_Unknown)
{
if (ssBit == SceneStage_Started)
{
SceneData_SetStage(entity, SceneStage_Completion);
}
SceneData_SetStage(entity, SceneStage_Killed);
for (int i = 1; i <= MaxClients; i++)
{
if (!IsClientInGame(i) || iScenePlaying[i] != entity)
{
continue;
}
iScenePlaying[i] = INVALID_ENT_REFERENCE;
break;
}
}
SceneData_SetStage(entity, SceneStage_Unknown);
}
public void OnClientDisconnect(int client)
{
if (client == 0)
{
return;
}
iScenePlaying[client] = INVALID_ENT_REFERENCE;
}
public void OnGameFrame()
{
iSkippedFrames += 1;
if (iSkippedFrames < 3)
{
return;
}
iSkippedFrames = 1;
if (bScenesUnprocessed)
{
bScenesUnprocessed = false;
int dScene;
while (!asScene.Empty)
{
asScene.Pop(dScene);
if (dScene < 1 || dScene > 2048 || !IsValidEntity(dScene))
{
continue;
}
if (nSceneData[dScene].ssDataBit != SceneStage_Spawned)
{
continue;
}
nSceneData[dScene].fPreDelayData = GetEntPropFloat(dScene, Prop_Data, "m_flPreDelay");
nSceneData[dScene].bInFakePostSpawn = false;
SceneData_SetStage(dScene, SceneStage_SpawnedPost);
}
}
if (bUnvocalizedCommands)
{
int iArraySize = alVocalize.Length,
iCurrentTick = GetGameTickCount();
static char sVocalize[MAX_VOCALIZE_LENGTH];
float fPreDelay, fPitch;
int client, dInitiator, dTick;
for (int i = 0; i < iArraySize; i += 6)
{
dTick = alVocalize.Get(i + 5);
if (iCurrentTick != dTick)
{
continue;
}
client = alVocalize.Get(i + 0);
alVocalize.GetString(i + 1, sVocalize, MAX_VOCALIZE_LENGTH);
fPreDelay = view_as<float>(alVocalize.Get(i + 2));
fPitch = view_as<float>(alVocalize.Get(i + 3));
dInitiator = alVocalize.Get(i + 4);
Scene_Perform(client, sVocalize, _, fPreDelay, fPitch, dInitiator, true);
for (int j = 0; j < 6; j++)
{
alVocalize.Erase(i);
iArraySize -= 1;
}
}
if (iArraySize < 1)
{
alVocalize.Clear();
bUnvocalizedCommands = false;
}
}
}
public void OnMapEnd()
{
iSkippedFrames = 0;
bScenesUnprocessed = false;
bUnvocalizedCommands = false;
while (!asScene.Empty)
{
PopStack(asScene);
}
alVocalize.Clear();
for (int i = 1; i < 2049; i++)
{
if (IsValidEntity(i) && IsValidEdict(i))
{
SceneData_SetStage(i, SceneStage_Unknown);
}
}
for (int i = 1; i <= MaxClients; i++)
{
if (IsClientInGame(i))
{
iScenePlaying[i] = INVALID_ENT_REFERENCE;
}
}
}
void ResetClientVocalizeData(int client)
{
iVocalizeTick[client] = 0;
sVocalizeScene[client] = "\0";
bSceneHasInitiator[client] = false;
iVocalizeInitiator[client] = SCENE_INITIATOR_WORLD;
fVocalizePreDelay[client] = DEFAULT_SCENE_PREDELAY;
fVocalizePitch[client] = DEFAULT_SCENE_PITCH;
}
void SceneData_SetStage(int scene, SceneStages stage)
{
nSceneData[scene].ssDataBit = stage;
if (stage != SceneStage_Unknown)
{
Call_StartForward(hSceneStageForward);
Call_PushCell(scene);
Call_PushCell(stage);
Call_Finish();
}
else
{
nSceneData[scene].bInFakePostSpawn = false;
nSceneData[scene].fTimeStampData = 0.0;
nSceneData[scene].iActorData = 0;
nSceneData[scene].iInitiatorData = 0;
strcopy(nSceneData[scene].sFileData, MAX_SCENEFILE_LENGTH, "\0");
strcopy(nSceneData[scene].sVocalizeData, MAX_VOCALIZE_LENGTH, "\0");
nSceneData[scene].fPreDelayData = DEFAULT_SCENE_PREDELAY;
nSceneData[scene].fPitchData = DEFAULT_SCENE_PITCH;
}
}
void Scene_Perform(int client, const char[] sVocalizeParam, const char[] sFileParam = "", float fScenePreDelay = DEFAULT_SCENE_PREDELAY, float fScenePitch = DEFAULT_SCENE_PITCH, int iSceneInitiator = SCENE_INITIATOR_PLUGIN, bool bVocalizeNow = false)
{
if (sFileParam[0] && FileExists(sFileParam, true))
{
int iScene = CreateEntityByName("instanced_scripted_scene");
DispatchKeyValue(iScene, "SceneFile", sFileParam);
SetEntPropEnt(iScene, Prop_Data, "m_hOwner", client);
nSceneData[iScene].iActorData = client;
SetEntPropFloat(iScene, Prop_Data, "m_flPreDelay", fScenePreDelay);
nSceneData[iScene].fPreDelayData = fScenePreDelay;
SetEntPropFloat(iScene, Prop_Data, "m_fPitch", fScenePitch);
nSceneData[iScene].fPitchData = fScenePitch;
nSceneData[iScene].iInitiatorData = iSceneInitiator;
strcopy(nSceneData[iScene].sVocalizeData, MAX_VOCALIZE_LENGTH, sVocalizeParam);
DispatchSpawn(iScene);
ActivateEntity(iScene);
AcceptEntityInput(iScene, "Start", client, client);
}
else if (sVocalizeParam[0])
{
if (bVocalizeNow)
{
iVocalizeInitiator[client] = iSceneInitiator;
bSceneHasInitiator[client] = true;
fVocalizePreDelay[client] = fScenePreDelay;
fVocalizePitch[client] = fScenePitch;
if (bIsL4D)
{
FakeClientCommandEx(client, "vocalize %s", sVocalizeParam);
}
else
{
JailbreakVocalize(client, sVocalizeParam);
}
}
else
{
alVocalize.Push(client);
alVocalize.PushString(sVocalizeParam);
alVocalize.Push(fScenePreDelay);
alVocalize.Push(fScenePitch);
alVocalize.Push(iSceneInitiator);
alVocalize.Push(GetGameTickCount() + 10 - 1);
bUnvocalizedCommands = true;
}
}
}
void JailbreakVocalize(int client, const char[] sVocalize)
{
char sBuffer[2][32];
FloatToString((GetGameTime() - fStartTimeStamp) + 2.0, sBuffer[0], 32);
ExplodeString(sBuffer[0], ".", sBuffer, 2, 32);
Format(sBuffer[1], 2, "%s\0", sBuffer[1][0]);
FakeClientCommandEx(client, "vocalize %s #%s%s", sVocalize, sBuffer[0], sBuffer[1]);
}