using System.Collections.Generic;
namespace AcDream.Core.Chat;
///
/// Translates ACE WeenieError + WeenieErrorWithString codes
/// into the human-readable templates the retail client showed. The
/// retail client baked these strings into string_table.bin; for
/// our purposes we mirror ACE's enum-doc comments
/// (references/ACE/Source/ACE.Entity/Enum/WeenieError.cs +
/// WeenieErrorWithString.cs) since they preserve the original
/// templates verbatim, including the literal _ placeholder where
/// the parameter goes.
///
///
/// Why we need this: Many of the codes ACE sends — especially
/// the high-frequency ones the user actually sees in normal play —
/// are informational, not error-level (e.g. 0x051B =
/// "You have entered the X channel.", 0x051D = "Turbine Chat
/// is enabled."). Displaying them as WeenieError 0xNNNN is
/// noisy and misleading. With the proper template they read as the
/// retail player would have seen them.
///
///
///
/// We don't translate every code — only the ~30 most likely to appear
/// in a normal session. Unknown codes fall back to the
/// WeenieError 0xNNNN[: param] form so nothing is silently
/// lost. New codes can be added in 30 seconds when the user reports
/// one.
///
///
public static class WeenieErrorMessages
{
///
/// Format a WeenieError / WeenieErrorWithString into a human-readable
/// system-message string.
///
/// The wire error code.
/// The interpolated substring (null for plain
/// WeenieError, set for WeenieErrorWithString).
public static string Format(uint errorCode, string? param)
{
// WeenieErrorWithString templates use the literal underscore
// character `_` as the placeholder for the param. We
// substitute it for `param` if present, otherwise drop it.
if (param is not null && WithStringTemplates.TryGetValue(errorCode, out var withTemplate))
{
return withTemplate.Replace("_", param);
}
if (NoParamTemplates.TryGetValue(errorCode, out var template))
{
// Some "no-param" codes do still arrive with a meaningless
// param string; ignore it.
return template;
}
// Unknown code — fall back to the raw form.
return string.IsNullOrEmpty(param)
? $"WeenieError 0x{errorCode:X4}"
: $"WeenieError 0x{errorCode:X4}: {param}";
}
///
/// Codes from WeenieError (no param). Templates copied
/// verbatim from ACE enum-doc comments.
///
private static readonly Dictionary NoParamTemplates = new()
{
// Command parser
[0x0026] = "That is not a valid command.", // ThatIsNotAValidCommand
// Tell-related
[0x052B] = "That person is not available now.", // CharacterNotAvailable
// Chat-channel related
[0x051D] = "Turbine Chat is enabled.", // TurbineChatIsEnabled
// Trade
[0x0529] = "Trade Complete!", // TradeComplete
// Allegiance / Fellowship membership errors (high-frequency
// when player isn't in either group and tries the channel)
[0x0414] = "You are not in an allegiance!", // YouAreNotInAllegiance
[0x050F] = "You do not belong to a Fellowship.", // YouDoNotBelongToAFellowship
// Allegiance
[0x0496] = "Your Allegiance has been dissolved!", // YourAllegianceHasBeenDissolved
[0x0497] = "Your patron's Allegiance to you has been broken!",
// YourPatronsAllegianceHasBeenBroken
[0x0535] = "You do not have the authority within your allegiance to do that.",
// Movement / teleport / housing
[0x0498] = "You have moved too far!", // YouHaveMovedTooFar
[0x0499] = "That is not a valid destination!", // TeleToInvalidPosition
[0x0532] = "You must wait 30 days after purchasing a house before you may purchase another with any character on the same account.",
// Fellowship
[0x0528] = "The fellowship is locked; you cannot open locked fellowships.",
// Player flavour
[0x0526] = "You chicken out.", // YouChickenOut
};
///
/// Codes from WeenieErrorWithString. Templates copied
/// verbatim from ACE enum-doc comments. The _ placeholder
/// is substituted with the param at format time.
///
private static readonly Dictionary WithStringTemplates = new()
{
// Channel join / leave (high frequency at login)
[0x051B] = "You have entered the _ channel.", // YouHaveEnteredThe_Channel
[0x051C] = "You have left the _ channel.", // YouHaveLeftThe_Channel
// Chat-server failures
[0x051E] = "_ will not receive your message, please use urgent assistance to speak with an in-game representative.",
[0x051F] = "Message Blocked: _", // MessageBlocked_
// Hear / loud-list
[0x0521] = "_ has been added to the list of people you can hear.",
[0x0522] = "_ has been removed from the list of people you can hear.",
[0x0525] = "You fail to remove _ from your loud list.",
// Snooping (admin)
[0x052C] = "You are now snooping on _.",
[0x052D] = "You are no longer snooping on _.",
[0x052E] = "You fail to snoop on _.",
[0x052F] = "_ attempted to snoop on you.",
[0x0551] = "You are not listening to the _ channel.",
// Allegiance
[0x046A] = "_ doesn't know what to do with that.",
[0x0413] = "_ is already one of your followers.",
[0x0416] = "_ cannot have any more Vassals.",
[0x03EF] = "_ is not accepting gifts right now.",
// Combat / spell failures
[0x004E] = "You fail to affect _ because you cannot affect anyone!",
[0x004F] = "You fail to affect _ because they cannot be harmed!",
[0x0050] = "You fail to affect _ because beneficial spells do not affect them!",
[0x0051] = "You fail to affect _ because you are not a player killer!",
[0x0052] = "You fail to affect _ because they are not a player killer!",
[0x0053] = "You fail to affect _ because you are not the same sort of player killer as them!",
[0x0054] = "You fail to affect _ because you are acting across a house boundary!",
// Inventory / etiquette
[0x001E] = "_ is too busy to accept gifts right now.",
[0x002B] = "_ cannot carry anymore.",
// Fellowship
[0x0517] = "_ is not close enough to your level.",
[0x0518] = "This fellowship is locked; _ cannot be recruited into the fellowship.",
// Hooks
[0x0510] = "Maximum number of _ hooked.",
[0x0514] = "Maximum number of _ hooked until one is removed.",
[0x0515] = "You no longer have the maximum number of _ hooked. You may hook additional.",
};
}