From d9e23dca85a5fd662323bfafc7e343a1967959d0 Mon Sep 17 00:00:00 2001 From: nosoop Date: Tue, 19 Oct 2021 01:57:30 -0700 Subject: [PATCH] Implement temporary item overrides This allows plugins to temporarily equip their own items with persistence without stomping on the player's own preferences. --- scripting/cwx.sp | 12 +++++++----- scripting/cwx/loadout_entries.sp | 24 ++++++++++++++++++------ scripting/cwx/loadout_radio_menu.sp | 4 ++++ scripting/cwx_equip_commands.sp | 22 ++++++++++++++++++++++ scripting/include/cwx.inc | 4 +++- translations/cwx.phrases.txt | 4 ++++ 6 files changed, 58 insertions(+), 12 deletions(-) diff --git a/scripting/cwx.sp b/scripting/cwx.sp index e451379..e12e306 100644 --- a/scripting/cwx.sp +++ b/scripting/cwx.sp @@ -168,7 +168,7 @@ public void OnClientConnected(int client) { g_bRetrievedLoadout[client] = false; for (int c; c < NUM_PLAYER_CLASSES; c++) { for (int i; i < NUM_ITEMS; i++) { - g_CurrentLoadout[client][c][i].Clear(); + g_CurrentLoadout[client][c][i].Clear(.initialize = true); } } } @@ -267,9 +267,8 @@ void OnPlayerLoadoutUpdatedPost(UserMsg msg_id, bool sent) { int currentLoadoutItem = g_CurrentLoadout[client][playerClass][i].entity; if (g_bForceReequipItems[client] || !IsValidEntity(currentLoadoutItem) || GetEntityFlags(currentLoadoutItem) & FL_KILLME) { - // TODO validate that the player can access this item CustomItemDefinition item; - if (!GetCustomItemDefinition(g_CurrentLoadout[client][playerClass][i].uid, item)) { + if (!g_CurrentLoadout[client][playerClass][i].GetItemDefinition(item)) { continue; } @@ -408,10 +407,13 @@ bool SetClientCustomLoadoutItem(int client, int playerClass, const char[] itemui int itemSlot = item.loadoutPosition[playerClass]; if (0 <= itemSlot < NUM_ITEMS) { - g_CurrentLoadout[client][playerClass][itemSlot].SetItemUID(itemuid); - if (flags & LOADOUT_FLAG_UPDATE_BACKEND) { + // item being set as user preference; update backend and set permanent UID slot g_ItemPersistCookies[playerClass][itemSlot].Set(client, itemuid); + g_CurrentLoadout[client][playerClass][itemSlot].SetItemUID(itemuid); + } else { + // item being set temporarily; set as overload + g_CurrentLoadout[client][playerClass][itemSlot].SetOverloadItemUID(itemuid); } g_CurrentLoadout[client][playerClass][itemSlot].entity = INVALID_ENT_REFERENCE; diff --git a/scripting/cwx/loadout_entries.sp b/scripting/cwx/loadout_entries.sp index 60c26db..cd7003f 100644 --- a/scripting/cwx/loadout_entries.sp +++ b/scripting/cwx/loadout_entries.sp @@ -5,6 +5,9 @@ enum struct LoadoutEntry { char uid[MAX_ITEM_IDENTIFIER_LENGTH]; + // overload UID -- used when plugins want to take priority over user preference + char override_uid[MAX_ITEM_IDENTIFIER_LENGTH]; + // loadout entity, for persistence // note for the future: we do *not* restore this on late load since the schema may have changed int entity; @@ -13,17 +16,26 @@ enum struct LoadoutEntry { strcopy(this.uid, MAX_ITEM_IDENTIFIER_LENGTH, other_uid); } + void SetOverloadItemUID(const char[] other_uid) { + strcopy(this.override_uid, MAX_ITEM_IDENTIFIER_LENGTH, other_uid); + } + + bool GetItemDefinition(CustomItemDefinition item) { + return GetCustomItemDefinition(this.override_uid, item) + || GetCustomItemDefinition(this.uid, item); + } + bool IsEmpty() { - return !this.uid[0]; + return !(this.override_uid[0] || this.uid[0]); } - void Clear() { + void Clear(bool initialize = false) { this.entity = INVALID_ENT_REFERENCE; this.uid = ""; - } - - bool GetItemDefinition(CustomItemDefinition item) { - return GetCustomItemDefinition(this.uid, item); + + if (initialize) { + this.override_uid = ""; + } } } diff --git a/scripting/cwx/loadout_radio_menu.sp b/scripting/cwx/loadout_radio_menu.sp index 606367c..0ef15b3 100644 --- a/scripting/cwx/loadout_radio_menu.sp +++ b/scripting/cwx/loadout_radio_menu.sp @@ -354,6 +354,7 @@ static int OnEquipMenuEvent(Menu menu, MenuAction action, int param1, int param2 int menuSlot = g_iPlayerSlotInMenu[client]; bool equipped = StrEqual(g_CurrentLoadout[client][menuClass][menuSlot].uid, uid); + bool override = StrEqual(g_CurrentLoadout[client][menuClass][menuSlot].override_uid, uid); SetGlobalTransTarget(client); @@ -376,6 +377,9 @@ static int OnEquipMenuEvent(Menu menu, MenuAction action, int param1, int param2 if (equipped) { Format(itemName, sizeof(itemName), "%s %t", itemName, "QuickSwitchEquipped"); redraw = true; + } else if (uid[0] && override) { + Format(itemName, sizeof(itemName), "%s %t", itemName, "ItemForcedByServer"); + redraw = true; } SetGlobalTransTarget(LANG_SERVER); diff --git a/scripting/cwx_equip_commands.sp b/scripting/cwx_equip_commands.sp index 4dad96f..2829bb6 100644 --- a/scripting/cwx_equip_commands.sp +++ b/scripting/cwx_equip_commands.sp @@ -10,6 +10,7 @@ #pragma newdecls required #include +#include public Plugin myinfo = { name = "[TF2] Custom Weapons X - Equip Commands", @@ -24,6 +25,7 @@ public Plugin myinfo = { public void OnPluginStart() { RegAdminCmd("sm_cwx_equip", EquipItemCmd, ADMFLAG_ROOT); RegAdminCmd("sm_cwx_equip_target", EquipItemCmdTarget, ADMFLAG_ROOT); + RegAdminCmd("sm_cwx_set_loadout", PersistItemCmd, ADMFLAG_ROOT); } /** @@ -51,6 +53,26 @@ Action EquipItemCmd(int client, int argc) { return Plugin_Handled; } +Action PersistItemCmd(int client, int argc) { + if (!client) { + return Plugin_Continue; + } + + char itemuid[MAX_ITEM_IDENTIFIER_LENGTH]; + GetCmdArgString(itemuid, sizeof(itemuid)); + + StripQuotes(itemuid); + TrimString(itemuid); + + if (!CWX_IsItemUIDValid(itemuid)) { + ReplyToCommand(client, "Unknown custom item uid %s", itemuid); + } else if (!CWX_SetPlayerLoadoutItem(client, TF2_GetPlayerClass(client), itemuid)) { + ReplyToCommand(client, "Failed to set custom item uid %s", itemuid); + } + + return Plugin_Handled; +} + /** * Testing command to equip the given item uid on the specified target(s). */ diff --git a/scripting/include/cwx.inc b/scripting/include/cwx.inc index 6c49ae3..8e5222b 100644 --- a/scripting/include/cwx.inc +++ b/scripting/include/cwx.inc @@ -10,7 +10,9 @@ ***************************************************************************************/ #define LOADOUT_FLAG_UPDATE_BACKEND (1 << 0) // update the item on the backing database, in - // addition to the current session + // addition to the current session -- if this is + // not set, the item will be treated as a temporary + // override #define LOADOUT_FLAG_ATTEMPT_REGEN (1 << 1) // if the player is in a spawn room, perform // regeneration to refresh the loadout diff --git a/translations/cwx.phrases.txt b/translations/cwx.phrases.txt index bf619df..cad235f 100644 --- a/translations/cwx.phrases.txt +++ b/translations/cwx.phrases.txt @@ -933,4 +933,8 @@ { "en" "(Custom items are currently disabled by the server operator.)" } + "ItemForcedByServer" + { + "en" "(forced by server)" + } }