#define PLUGIN_VERSION "1.33.2" #pragma semicolon 1 #pragma newdecls required #include #include #include #include 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(alVocalize.Get(i + 2)); fPitch = view_as(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]); }