From be442d36a0414a61dcf22e606a7ee9e6f8ce7299 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 17 Jul 2026 10:12:01 -0500 Subject: [PATCH] feat(protocol2): titles in char.profile (Part B ph.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Overlay BridgeProfile: char.profile gains a titles block (selected index, fameKarma, skill, and the raw reward-title list) read from PlayerMobile's public title accessors. No new stream, no sidecar change — it rides the existing char.profile served by GET /char. Reward entries may be a cliloc number as a string or a literal; resolve numeric ones website-side like item names. Docs: INTEGRATION.md char.profile titles field; PROTOCOL_2 ph.4 built. Part B phase 5 (Factions/VvV) remains deferred by owner decision. Verified: overlay compiles in the full ServUO Scripts tree (0 errors, 0 warnings). Live run pending. Co-Authored-By: Claude Opus 4.8 --- .../Scripts/Custom/Bridge/BridgeProfile.cs | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/overlay/Scripts/Custom/Bridge/BridgeProfile.cs b/overlay/Scripts/Custom/Bridge/BridgeProfile.cs index 7e12197..4e08ede 100644 --- a/overlay/Scripts/Custom/Bridge/BridgeProfile.cs +++ b/overlay/Scripts/Custom/Bridge/BridgeProfile.cs @@ -98,9 +98,55 @@ namespace Server.Custom.Bridge } sb.Append(']'); + WriteTitles(sb, m); + return sb.End(); } + /// + /// The titles a character holds (docs/PROTOCOL_2.md §10.3). `selected` is the index into + /// `reward` currently displayed (-1 if none). `fameKarma` and `skill` are the computed + /// display titles (may be absent). `reward` is the raw reward-title list — an entry may be + /// a cliloc number (as a string) or a literal string; resolve clilocs website-side. + /// + private static void WriteTitles(StringBuilder sb, PlayerMobile m) + { + sb.Append(",\"titles\":{\"selected\":").Append(m.SelectedTitle); + + var fameKarma = m.FameKarmaTitle; + if (!String.IsNullOrEmpty(fameKarma)) + { + sb.Append(",\"fameKarma\":"); + BridgeJson.Escape(sb, fameKarma); + } + + var skill = m.PaperdollSkillTitle; + if (!String.IsNullOrEmpty(skill)) + { + sb.Append(",\"skill\":"); + BridgeJson.Escape(sb, skill); + } + + sb.Append(",\"reward\":["); + var rewards = m.RewardTitles; + if (rewards != null) + { + bool first = true; + for (int i = 0; i < rewards.Count; i++) + { + var r = rewards[i]; + if (r == null) + continue; + + if (!first) sb.Append(','); + first = false; + + BridgeJson.Escape(sb, Convert.ToString(r, System.Globalization.CultureInfo.InvariantCulture)); + } + } + sb.Append("]}"); + } + private static bool IsGearLayer(Layer layer) { switch (layer)