diff --git a/SaveLevel/configs/savelevel/ZE_FFVII_Mako_Reactor_V6_B08.cfg b/SaveLevel/configs/savelevel/ZE_FFVII_Mako_Reactor_V6_B08.cfg index 1304fb9..70719c2 100644 --- a/SaveLevel/configs/savelevel/ZE_FFVII_Mako_Reactor_V6_B08.cfg +++ b/SaveLevel/configs/savelevel/ZE_FFVII_Mako_Reactor_V6_B08.cfg @@ -1,5 +1,15 @@ "levels" { + "0" + { + "name" "Level 0" + "restore" + { + "DeleteOutput" "m_OnUser2 leveling_counter" + "DeleteOutput" "m_OnUser4 score10,ApplyScore" + "m_iFrags" "0" + } + } "1" { "name" "Level 1" diff --git a/SaveLevel/configs/savelevel/ze_FFXII_Feywood_b3_1.cfg b/SaveLevel/configs/savelevel/ze_FFXII_Feywood_b3_1.cfg index 2daa948..e43f9e7 100644 --- a/SaveLevel/configs/savelevel/ze_FFXII_Feywood_b3_1.cfg +++ b/SaveLevel/configs/savelevel/ze_FFXII_Feywood_b3_1.cfg @@ -1,5 +1,14 @@ "levels" { + "0" + { + "name" "Level 0" + "restore" + { + "DeleteOutput" "m_OnUser4 Map_Level_Check" + "m_iFrags" "0" + } + } "1" { "name" "Level 1" diff --git a/SaveLevel/configs/savelevel/ze_FFXII_Paramina_Rift_v1_3.cfg b/SaveLevel/configs/savelevel/ze_FFXII_Paramina_Rift_v1_3.cfg index bf759c4..5ae99de 100644 --- a/SaveLevel/configs/savelevel/ze_FFXII_Paramina_Rift_v1_3.cfg +++ b/SaveLevel/configs/savelevel/ze_FFXII_Paramina_Rift_v1_3.cfg @@ -1,5 +1,14 @@ "levels" { + "0" + { + "name" "Level 0" + "restore" + { + "DeleteOutput" "m_OnUser2 leveling_counter" + "m_iFrags" "0" + } + } "1" { "name" "Level 1" diff --git a/SaveLevel/configs/savelevel/ze_harry_potter_v1_3.cfg b/SaveLevel/configs/savelevel/ze_harry_potter_v1_3.cfg index 632a7a5..2a58576 100644 --- a/SaveLevel/configs/savelevel/ze_harry_potter_v1_3.cfg +++ b/SaveLevel/configs/savelevel/ze_harry_potter_v1_3.cfg @@ -1,5 +1,14 @@ "levels" { + "0" + { + "name" "Level 0" + "restore" + { + "DeleteOutput" "m_OnUser3 map_wandlevels" + "m_iFrags" "0" + } + } "1" { "name" "Level 1" diff --git a/SaveLevel/scripting/SaveLevel.sp b/SaveLevel/scripting/SaveLevel.sp index b84dcc0..ba5eec3 100644 --- a/SaveLevel/scripting/SaveLevel.sp +++ b/SaveLevel/scripting/SaveLevel.sp @@ -10,7 +10,7 @@ StringMap g_PlayerLevels; KeyValues g_Config; KeyValues g_PropAltNames; -#define PLUGIN_VERSION "1.1" +#define PLUGIN_VERSION "2.0" public Plugin myinfo = { name = "SaveLevel", @@ -22,8 +22,12 @@ public Plugin myinfo = public void OnPluginStart() { + LoadTranslations("common.phrases"); + g_PropAltNames = new KeyValues("PropAltNames"); g_PropAltNames.SetString("m_iName", "targetname"); + + RegAdminCmd("sm_level", Command_Level, ADMFLAG_GENERIC, "Set a players map level."); } public void OnPluginEnd() @@ -75,7 +79,7 @@ public void OnMapStart() public void OnClientPostAdminCheck(int client) { - if(!g_PlayerLevels) + if(!g_Config) return; char sSteamID[32]; @@ -85,81 +89,27 @@ public void OnClientPostAdminCheck(int client) if(g_PlayerLevels.GetString(sSteamID, sTargets, sizeof(sTargets))) { g_PlayerLevels.Remove(sSteamID); + char sNames[128]; static char asTargets[4][32]; int Split = ExplodeString(sTargets, ";", asTargets, sizeof(asTargets), sizeof(asTargets[])); - g_Config.Rewind(); + int Found = 0; for(int i = 0; i < Split; i++) { - if(!g_Config.JumpToKey(asTargets[i])) - continue; - - static char sKey[32]; - static char sValue[1024]; - if(g_Config.JumpToKey("restore")) + static char sName[32]; + if(RestoreLevel(client, asTargets[i], sName, sizeof(sName))) { - if(g_Config.GotoFirstSubKey(false)) - { - do - { - g_Config.GetSectionName(sKey, sizeof(sKey)); - g_Config.GetString(NULL_STRING, sValue, sizeof(sValue)); - if(StrEqual(sKey, "AddOutput", false)) - { - SetVariantString(sValue); - AcceptEntityInput(client, sKey, client, client); - } - else - { - PropFieldType Type; - int NumBits; - int Offset = FindDataMapInfo(client, sKey, Type, NumBits); - if(Offset != -1) - { - if(Type == PropField_Integer) - { - int Value = StringToInt(sValue); - SetEntData(client, Offset, Value, NumBits / 8, false); - } - else if(Type == PropField_Float) - { - float Value = StringToFloat(sValue); - SetEntDataFloat(client, Offset, Value, false); - } - else if(Type == PropField_String) - { - SetEntDataString(client, Offset, sValue, strlen(sValue) + 1, false); - } - else if(Type == PropField_String_T) - { - static char sAltKey[32]; - g_PropAltNames.GetString(sKey, sAltKey, sizeof(sAltKey), NULL_STRING); - if(sAltKey[0]) - DispatchKeyValue(client, sAltKey, sValue); - } - } - } - } - while(g_Config.GotoNextKey(false)); - - g_Config.GoBack(); - g_Config.GoBack(); - g_Config.GetString("name", sValue, sizeof(sValue)); - g_Config.GoBack(); - StrCat(sNames, sizeof(sNames), sValue); + if(Found) StrCat(sNames, sizeof(sNames), ", "); - } + Found++; + + StrCat(sNames, sizeof(sNames), sName); } } - int NamesLen = strlen(sNames); - if(NamesLen) - { - sNames[NamesLen - 2] = 0; // Cut off ', ' - PrintToChatAll("\x03[SaveLevel]\x01 %N has been restored to: \x04%s", client, sNames); - } - g_Config.Rewind(); + if(Found) + PrintToChatAll("\x03[SaveLevel]\x01 \x04%N\x01 has been restored to: \x04%s", client, sNames); } } @@ -168,11 +118,132 @@ public void OnClientDisconnect(int client) if(!g_Config || !g_PlayerLevels || !IsClientInGame(client)) return; + char sTargets[128]; + if(GetLevel(client, sTargets, sizeof(sTargets))) + { + char sSteamID[32]; + GetClientAuthId(client, AuthId_Steam3, sSteamID, sizeof(sSteamID)); + g_PlayerLevels.SetString(sSteamID, sTargets, true); + } +} + +bool RestoreLevel(int client, const char[] sTarget, char[] sName = NULL_STRING, int NameLen = 0) +{ + g_Config.Rewind(); + + if(!g_Config.JumpToKey(sTarget)) + return false; + + if(NameLen) + g_Config.GetString("name", sName, NameLen); + + static char sKey[32]; + static char sValue[1024]; + + if(!g_Config.JumpToKey("restore")) + return false; + + if(!g_Config.GotoFirstSubKey(false)) + return false; + + do + { + g_Config.GetSectionName(sKey, sizeof(sKey)); + g_Config.GetString(NULL_STRING, sValue, sizeof(sValue)); + if(StrEqual(sKey, "AddOutput", false)) + { + SetVariantString(sValue); + AcceptEntityInput(client, sKey, client, client); + } + else if(StrEqual(sKey, "DeleteOutput", false)) + { + int Index; + // Output (e.g. m_OnUser1) + int Target = FindCharInString(sValue, ' '); + if(Target == -1) + { + while((Index = FindOutput(client, sValue, 0)) != -1) + DeleteOutput(client, sValue, Index); + + continue; + } + sValue[Target] = 0; Target++; + while(IsCharSpace(sValue[Target])) + Target++; + + // Target (e.g. leveling_counter) + int Input = FindCharInString(sValue[Target], ','); + if(Input == -1) + { + while((Index = FindOutput(client, sValue, 0, sValue[Target])) != -1) + DeleteOutput(client, sValue, Index); + + continue; + } + sValue[Input] = 0; Input++; + + // Input (e.g. add) + int Parameter = Input + FindCharInString(sValue[Input], ','); + if(Input == -1) + { + while((Index = FindOutput(client, sValue, 0, sValue[Target], sValue[Input])) != -1) + DeleteOutput(client, sValue, Index); + + continue; + } + sValue[Parameter] = 0; Parameter++; + + // Parameter (e.g. 1) + while((Index = FindOutput(client, sValue, 0, sValue[Target], sValue[Input], sValue[Parameter])) != -1) + DeleteOutput(client, sValue, Index); + } + else + { + PropFieldType Type; + int NumBits; + int Offset = FindDataMapInfo(client, sKey, Type, NumBits); + if(Offset != -1) + { + if(Type == PropField_Integer) + { + int Value = StringToInt(sValue); + SetEntData(client, Offset, Value, NumBits / 8, false); + } + else if(Type == PropField_Float) + { + float Value = StringToFloat(sValue); + SetEntDataFloat(client, Offset, Value, false); + } + else if(Type == PropField_String) + { + SetEntDataString(client, Offset, sValue, strlen(sValue) + 1, false); + } + else if(Type == PropField_String_T) + { + static char sAltKey[32]; + g_PropAltNames.GetString(sKey, sAltKey, sizeof(sAltKey), NULL_STRING); + if(sAltKey[0]) + DispatchKeyValue(client, sAltKey, sValue); + } + } + } + } + while(g_Config.GotoNextKey(false)); + + g_Config.Rewind(); + return true; +} + +bool GetLevel(int client, char[] sTargets, int TargetsLen, char[] sNames = NULL_STRING, int NamesLen = 0) +{ + if(!g_Config || !g_PlayerLevels || !IsClientInGame(client)) + return false; + g_Config.Rewind(); g_Config.GotoFirstSubKey(); - char sTargets[128]; static char sTarget[32]; + static char sName[32]; static char sKey[32]; static char sValue[1024]; static char sOutput[1024]; @@ -180,6 +251,8 @@ public void OnClientDisconnect(int client) do { g_Config.GetSectionName(sTarget, sizeof(sTarget)); + g_Config.GetString("name", sName, sizeof(sName)); + if(!g_Config.JumpToKey("match")) continue; @@ -213,11 +286,9 @@ public void OnClientDisconnect(int client) int Count = GetOutputCount(client, sKey); for(int i = 0; i < Count; i++) { - int Len = GetOutputTarget(client, sKey, i, sOutput); - sOutput[Len] = ','; Len++; - Len += GetOutputTargetInput(client, sKey, i, sOutput[Len]); - sOutput[Len] = ','; Len++; - Len += GetOutputParameter(client, sKey, i, sOutput[Len]); + GetOutputFormatted(client, sKey, i, sOutput, sizeof(sOutput)); + sOutput[FindCharInString(sOutput, ',', true)] = 0; + sOutput[FindCharInString(sOutput, ',', true)] = 0; if(StrEqual(sValue, sOutput)) _Matches++; @@ -285,13 +356,13 @@ public void OnClientDisconnect(int client) int _Input; int _Parameter; - _Input = GetOutputTarget(client, sKey, i, sOutput[_Target]); + _Input = GetOutputTarget(client, sKey, i, sOutput[_Target], sizeof(sOutput) - _Target); sOutput[_Input] = 0; _Input++; - _Parameter = _Input + GetOutputTargetInput(client, sKey, i, sOutput[_Input]); + _Parameter = _Input + GetOutputTargetInput(client, sKey, i, sOutput[_Input], sizeof(sOutput) - _Input); sOutput[_Parameter] = 0; _Parameter++; - GetOutputParameter(client, sKey, i, sOutput[_Parameter]); + GetOutputParameter(client, sKey, i, sOutput[_Parameter], sizeof(sOutput) - _Parameter); if(!StrEqual(sOutput[_Target], sValue[Target])) continue; @@ -325,21 +396,113 @@ public void OnClientDisconnect(int client) if(CalcMatches(Matches, ExactMatches, MinMatches, MaxMatches)) { if(Found) - StrCat(sTargets, sizeof(sTargets), ";"); + { + if(TargetsLen) + StrCat(sTargets, TargetsLen, ";"); + if(NamesLen) + StrCat(sNames, NamesLen, ", "); + } Found = true; - StrCat(sTargets, sizeof(sTargets), sTarget); + if(TargetsLen) + StrCat(sTargets, TargetsLen, sTarget); + if(NamesLen) + StrCat(sNames, NamesLen, sName); } } while(g_Config.GotoNextKey()); g_Config.Rewind(); if(!Found) - return; + return false; + return true; +} - char sSteamID[32]; - GetClientAuthId(client, AuthId_Steam3, sSteamID, sizeof(sSteamID)); - g_PlayerLevels.SetString(sSteamID, sTargets, true); +public Action Command_Level(int client, int args) +{ + if(!g_Config) + { + ReplyToCommand(client, "[SM] The current map is not supported."); + return Plugin_Handled; + } + + if(args < 2) + { + ReplyToCommand(client, "[SM] Usage: sm_level "); + return Plugin_Handled; + } + + char sTarget[MAX_TARGET_LENGTH]; + char sTargetName[MAX_TARGET_LENGTH]; + int iTargets[MAXPLAYERS]; + int iTargetCount; + bool bIsML; + + GetCmdArg(1, sTarget, sizeof(sTarget)); + if((iTargetCount = ProcessTargetString(sTarget, client, iTargets, MAXPLAYERS, 0, sTargetName, sizeof(sTargetName), bIsML)) <= 0) + { + ReplyToTargetError(client, iTargetCount); + return Plugin_Handled; + } + + char sLevel[32]; + GetCmdArg(2, sLevel, sizeof(sLevel)); + + int Level; + if(!StringToIntEx(sLevel, Level)) + { + ReplyToCommand(client, "[SM] Level has to be a number."); + return Plugin_Handled; + } + IntToString(Level, sLevel, sizeof(sLevel)); + + g_Config.Rewind(); + if(!g_Config.JumpToKey("0")) + { + ReplyToCommand(client, "[SM] Setting levels on the current map is not supported."); + return Plugin_Handled; + } + g_Config.GoBack(); + + if(Level && !g_Config.JumpToKey(sLevel)) + { + ReplyToCommand(client, "[SM] Level %s could not be found.", sLevel); + return Plugin_Handled; + } + g_Config.Rewind(); + + char sPrevNames[128]; + if(iTargetCount == 1) + GetLevel(iTargets[0], sPrevNames, 0, sPrevNames, sizeof(sPrevNames)); + + char sName[32]; + for(int i = 0; i < iTargetCount; i++) + { + // Reset level first + if(Level) + { + if(!RestoreLevel(iTargets[i], "0")) + { + ReplyToCommand(client, "[SM] Failed resetting level on %L.", iTargets[i]); + return Plugin_Handled; + } + } + + if(!RestoreLevel(iTargets[i], sLevel, sName, sizeof(sName))) + { + ReplyToCommand(client, "[SM] Failed setting level to %s on %L.", sLevel, iTargets[i]); + return Plugin_Handled; + } + + LogAction(client, iTargets[i], "Set %L to %s", iTargets[i], sName); + } + + if(sPrevNames[0]) + ShowActivity2(client, "\x03[SaveLevel]\x01 ", "Set \x04%s\x01 from \x04%s\x01 to \x04%s\x01", sTargetName, sPrevNames, sName); + else + ShowActivity2(client, "\x03[SaveLevel]\x01 ", "Set \x04%s\x01 to \x04%s\x01", sTargetName, sName); + + return Plugin_Handled; } stock int CalcMatches(int Matches, int ExactMatches, int MinMatches, int MaxMatches) diff --git a/includes/outputinfo.inc b/includes/outputinfo.inc index a24b3cd..4396427 100644 --- a/includes/outputinfo.inc +++ b/includes/outputinfo.inc @@ -3,11 +3,21 @@ #endif #define _OutputInfo_Included -native GetOutputCount(int Entity, const char[] sOutput); -native GetOutputTarget(int Entity, const char[] sOutput, int Index, char[] sTarget); -native GetOutputTargetInput(int Entity, const char[] sOutput, int Index, char[] sTargetInput); -native GetOutputParameter(int Entity, const char[] sOutput, int Index, char[] sParameter); -native Float:GetOutputDelay(int Entity, const char[] sOutput, int Index); +native int GetOutputCount(int Entity, const char[] sOutput); +native int GetOutputTarget(int Entity, const char[] sOutput, int Index, char[] sTarget, int MaxLen); +native int GetOutputTargetInput(int Entity, const char[] sOutput, int Index, char[] sTargetInput, int MaxLen); +native int GetOutputParameter(int Entity, const char[] sOutput, int Index, char[] sParameter, int MaxLen); +native float GetOutputDelay(int Entity, const char[] sOutput, int Index); +native int GetOutputFormatted(int Entity, const char[] sOutput, int Index, char[] sFormatted, int MaxLen); +native int FindOutput(int Entity, const char[] sOutput, int StartIndex, + const char[] sTarget = NULL_STRING, // or NULL_STRING to ignore + const char[] sTargetInput = NULL_STRING, // or NULL_STRING to ignore + const char[] sParameter = NULL_STRING, // or NULL_STRING to ignore + float fDelay = -1.0, // or -1.0 to ignore + int TimesToFire = 0 // or 0 to ignore + ); +native int DeleteOutput(int Entity, const char[] sOutput, int Index); +native int DeleteAllOutputs(int Entity, const char[] sOutput); /** * Do not edit below this line! @@ -36,5 +46,9 @@ public __ext_outputinfo_SetNTVOptional() MarkNativeAsOptional("GetOutputTargetInput"); MarkNativeAsOptional("GetOutputParameter"); MarkNativeAsOptional("GetOutputDelay"); + MarkNativeAsOptional("GetOutputFormatted"); + MarkNativeAsOptional("FindOutput"); + MarkNativeAsOptional("DeleteOutput"); + MarkNativeAsOptional("DeleteAllOutputs"); } -#endif +#endif \ No newline at end of file