eb681aa9cd
- socle : Textes.lua (ForeverUI.L) et ForeverUIGlueTextes.lua (G.L) ; les textes dans Textes_enUS / Textes_frFR (325 cles en jeu) et ForeverUIGlueTextes_enUS / _frFR (41 cles aux ecrans d'accueil) ; une cle absente prend l'anglais, une langue sans fichier lit l'anglais ; ajouter une langue = un fichier de plus - les textes que le client 3.3.5 connait se lisent dans ses globales (GlobalStrings, GlueStrings en glue) ; les textes de secours sont retires - tous les fichiers repris : libelles, infobulles, mode edition, messages et aide de /fui, erreurs internes ; .toc : Notes + Notes-frFR - selection des personnages : race et classe traduites ramenees a leur jeton par les tables de langue (GetAvailableRaces / GetAvailableClasses font planter le client hors de la creation) - tools/cartes_instances.py : noms des instances dans toutes les langues de la LibBabble-Zone de WDM (portails de la carte sur tout client) - banc : toute cle employee existe en anglais et en francais, memes cles dans les deux, bascule frFR / deDE essayee ; chaines 3.3.5 ajoutees au faux client - README : etat des sections mis a jour, langues, glue, deploiement --glue Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
502 lines
13 KiB
Lua
502 lines
13 KiB
Lua
-- ForeverUI : positions modifiables.
|
|
--
|
|
-- POURQUOI CE FICHIER EXISTE AVANT LES CADRES. Sur camelot, aucun element
|
|
-- d'interface n'a de position figee : chacun est un "systeme" que le joueur
|
|
-- deplace, et sa position est retenue. On reprend le principe ici : tout ce que
|
|
-- ForeverUI construit s'enregistre avec une position par defaut, et c'est cette
|
|
-- table qui decide ou le cadre se pose au chargement. Un cadre qui poserait
|
|
-- lui-meme son SetPoint definitif serait le seul a ne pas etre deplacable.
|
|
--
|
|
-- Tout est ancre a UIParent, jamais a un autre cadre de ForeverUI : sinon
|
|
-- deplacer un element en entrainerait un autre, et le joueur ne pourrait plus
|
|
-- defaire l'enchainement.
|
|
|
|
ForeverUI = ForeverUI or {}
|
|
|
|
-- Neutraliser un cadre du client. Le masquer ne suffit pas : son propre code
|
|
-- le reaffiche a la premiere occasion (changement de page, sortie de vehicule,
|
|
-- mise a jour de runes). On coupe donc ses evenements, on le masque, et on
|
|
-- accroche son OnShow pour qu'il se remasque si quelque chose insiste.
|
|
function ForeverUI.Suppress(frame)
|
|
if not frame or frame.foreverSuppressed then
|
|
return
|
|
end
|
|
|
|
if frame.UnregisterAllEvents then
|
|
frame:UnregisterAllEvents()
|
|
end
|
|
frame:Hide()
|
|
|
|
if frame.HookScript then
|
|
frame:HookScript("OnShow", function(self)
|
|
self:Hide()
|
|
end)
|
|
end
|
|
|
|
frame.foreverSuppressed = true
|
|
end
|
|
|
|
local Layout = {}
|
|
ForeverUI.Layout = Layout
|
|
|
|
Layout.systems = {} -- id -> { frame, label, defaults }
|
|
Layout.order = {} -- ids, dans l'ordre d'enregistrement
|
|
Layout.editing = false
|
|
|
|
local PREFIX = "|cff66ccffForeverUI|r : "
|
|
local L = ForeverUI.L
|
|
|
|
local function say(message)
|
|
DEFAULT_CHAT_FRAME:AddMessage(PREFIX .. message)
|
|
end
|
|
|
|
local function positions()
|
|
ForeverUIDB = ForeverUIDB or {}
|
|
ForeverUIDB.positions = ForeverUIDB.positions or {}
|
|
return ForeverUIDB.positions
|
|
end
|
|
|
|
-- Pose le cadre a sa position retenue, ou a sa position par defaut.
|
|
function Layout.Apply(id)
|
|
local system = Layout.systems[id]
|
|
if not system then
|
|
return false
|
|
end
|
|
|
|
local saved = positions()[id]
|
|
local p = saved or system.defaults
|
|
|
|
system.frame:ClearAllPoints()
|
|
system.frame:SetPoint(p.point, UIParent, p.relativePoint, p.x, p.y)
|
|
return true
|
|
end
|
|
|
|
function Layout.Save(id)
|
|
local system = Layout.systems[id]
|
|
if not system then
|
|
return false
|
|
end
|
|
|
|
local point, _relativeTo, relativePoint, x, y = system.frame:GetPoint(1)
|
|
if not point then
|
|
return false
|
|
end
|
|
|
|
positions()[id] = {
|
|
point = point,
|
|
relativePoint = relativePoint or point,
|
|
x = x or 0,
|
|
y = y or 0,
|
|
}
|
|
return true
|
|
end
|
|
|
|
function Layout.Reset(id)
|
|
if id then
|
|
if not Layout.systems[id] then
|
|
return false
|
|
end
|
|
positions()[id] = nil
|
|
Layout.Apply(id)
|
|
return true
|
|
end
|
|
|
|
for _, systemID in ipairs(Layout.order) do
|
|
positions()[systemID] = nil
|
|
Layout.Apply(systemID)
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- L'enregistrement fait tout : rendre le cadre deplacable, le poser, et le
|
|
-- rendre visible en mode edition.
|
|
function Layout.Register(frame, id, label, point, relativePoint, x, y)
|
|
Layout.systems[id] = {
|
|
frame = frame,
|
|
label = label,
|
|
defaults = { point = point, relativePoint = relativePoint, x = x, y = y },
|
|
}
|
|
table.insert(Layout.order, id)
|
|
|
|
frame:SetMovable(true)
|
|
frame:SetClampedToScreen(true)
|
|
Layout.Apply(id)
|
|
|
|
if Layout.editing then
|
|
Layout.ShowOverlay(id)
|
|
end
|
|
return frame
|
|
end
|
|
|
|
-- Corriger la position par defaut d'un element deja enregistre. Le bas de
|
|
-- l'ecran est une chaine : la barre d'action et les sacs se posent de part et
|
|
-- d'autre du micro-menu, dont la largeur n'est connue qu'une fois ses boutons
|
|
-- comptes. Un element que le joueur a deja deplace garde sa position.
|
|
function Layout.SetDefaults(id, point, relativePoint, x, y)
|
|
local system = Layout.systems[id]
|
|
if not system then
|
|
return false
|
|
end
|
|
|
|
system.defaults = { point = point, relativePoint = relativePoint, x = x, y = y }
|
|
if not positions()[id] then
|
|
Layout.Apply(id)
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function buildOverlay(id, system)
|
|
local overlay = CreateFrame("Frame", nil, system.frame)
|
|
overlay:SetAllPoints(system.frame)
|
|
overlay:SetFrameStrata("DIALOG")
|
|
overlay:EnableMouse(true)
|
|
overlay:RegisterForDrag("LeftButton")
|
|
|
|
local background = overlay:CreateTexture(nil, "BACKGROUND")
|
|
background:SetAllPoints(overlay)
|
|
background:SetTexture(0.1, 0.6, 1, 0.35)
|
|
|
|
local text = overlay:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
|
|
text:SetPoint("CENTER")
|
|
text:SetText(system.label)
|
|
|
|
overlay:SetScript("OnDragStart", function()
|
|
if InCombatLockdown() then
|
|
say(L.LAYOUT_NO_MOVE_IN_COMBAT)
|
|
return
|
|
end
|
|
system.frame:StartMoving()
|
|
end)
|
|
|
|
overlay:SetScript("OnDragStop", function()
|
|
system.frame:StopMovingOrSizing()
|
|
Layout.Save(id)
|
|
end)
|
|
|
|
system.overlay = overlay
|
|
return overlay
|
|
end
|
|
|
|
function Layout.ShowOverlay(id)
|
|
local system = Layout.systems[id]
|
|
if not system then
|
|
return
|
|
end
|
|
|
|
local overlay = system.overlay or buildOverlay(id, system)
|
|
overlay:Show()
|
|
end
|
|
|
|
function Layout.HideOverlay(id)
|
|
local system = Layout.systems[id]
|
|
if system and system.overlay then
|
|
system.overlay:Hide()
|
|
end
|
|
end
|
|
|
|
function Layout.SetEditMode(enabled)
|
|
if enabled and InCombatLockdown() then
|
|
say(L.LAYOUT_EDIT_MODE_COMBAT)
|
|
return false
|
|
end
|
|
|
|
Layout.editing = enabled and true or false
|
|
|
|
for _, id in ipairs(Layout.order) do
|
|
if Layout.editing then
|
|
Layout.ShowOverlay(id)
|
|
else
|
|
Layout.HideOverlay(id)
|
|
end
|
|
end
|
|
|
|
if Layout.editing then
|
|
say(L.LAYOUT_EDIT_MODE_ON)
|
|
else
|
|
say(L.LAYOUT_EDIT_MODE_OFF)
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- Le mode edition se coupe tout seul a l'entree en combat : un cadre securise
|
|
-- ne peut plus etre deplace a ce moment, et laisser les surfaces bleues
|
|
-- affichees ferait croire le contraire.
|
|
local watcher = CreateFrame("Frame")
|
|
watcher:RegisterEvent("PLAYER_LOGIN")
|
|
watcher:RegisterEvent("PLAYER_REGEN_DISABLED")
|
|
watcher:SetScript("OnEvent", function(_self, event)
|
|
if event == "PLAYER_LOGIN" then
|
|
for _, id in ipairs(Layout.order) do
|
|
Layout.Apply(id)
|
|
end
|
|
elseif event == "PLAYER_REGEN_DISABLED" and Layout.editing then
|
|
Layout.SetEditMode(false)
|
|
end
|
|
end)
|
|
|
|
-- /fui souris : tant qu'il est actif, chaque clic dit dans le chat quel cadre
|
|
-- est sous la souris (GetMouseFocus), ses parents et ses images -- pour
|
|
-- trouver d'ou vient un element de l'ecran (2026-09-25 : les portails de la
|
|
-- carte du monde, qui ne sont pas des reperes du client)
|
|
local espion = CreateFrame("Frame")
|
|
espion:Hide()
|
|
local function decrire(cadre)
|
|
if not cadre then return L.LAYOUT_SPY_NOTHING end
|
|
local nom = cadre.GetName and cadre:GetName() or nil
|
|
local type_ = cadre.GetObjectType and cadre:GetObjectType() or "?"
|
|
return (nom or L.LAYOUT_SPY_UNNAMED) .. " [" .. type_ .. "]"
|
|
end
|
|
espion:SetScript("OnUpdate", function(self)
|
|
local bas = IsMouseButtonDown("LeftButton") or IsMouseButtonDown("RightButton")
|
|
if bas and not self.enfonce then
|
|
local f = GetMouseFocus and GetMouseFocus()
|
|
say(L.LAYOUT_SPY_UNDER_MOUSE .. decrire(f))
|
|
local p, chemin = f and f:GetParent(), {}
|
|
while p and #chemin < 8 do
|
|
table.insert(chemin, decrire(p))
|
|
p = p:GetParent()
|
|
end
|
|
DEFAULT_CHAT_FRAME:AddMessage(" " .. L.LAYOUT_SPY_PARENTS .. table.concat(chemin, " < "))
|
|
if f and f.GetRegions then
|
|
for _, r in ipairs({ f:GetRegions() }) do
|
|
if r.GetTexture and r:GetTexture() then
|
|
DEFAULT_CHAT_FRAME:AddMessage(" " .. L.LAYOUT_SPY_TEXTURE .. tostring(r:GetTexture()))
|
|
elseif r.GetText and r:GetText() then
|
|
DEFAULT_CHAT_FRAME:AddMessage(" " .. L.LAYOUT_SPY_TEXT .. tostring(r:GetText()))
|
|
end
|
|
end
|
|
end
|
|
for _, k in ipairs({ "name", "mapLinkID", "description", "poiID", "instanceID", "mapID" }) do
|
|
if f and f[k] ~= nil then
|
|
DEFAULT_CHAT_FRAME:AddMessage(" ." .. k .. " = " .. tostring(f[k]))
|
|
end
|
|
end
|
|
end
|
|
self.enfonce = bas and true or false
|
|
end)
|
|
ForeverUI.SourisEspion = espion
|
|
ForeverUI.SourisDebug = function()
|
|
if espion:IsShown() then
|
|
espion:Hide()
|
|
say(L.LAYOUT_SPY_STOPPED)
|
|
else
|
|
espion.enfonce = true
|
|
espion:Show()
|
|
say(L.LAYOUT_SPY_STARTED)
|
|
end
|
|
end
|
|
|
|
SLASH_FOREVERUI1 = "/fui"
|
|
SLASH_FOREVERUI2 = "/foreverui"
|
|
|
|
SlashCmdList["FOREVERUI"] = function(message)
|
|
local command, argument = string.match(message or "", "^(%S*)%s*(.*)$")
|
|
argument = argument or ""
|
|
command = string.lower(command or "")
|
|
|
|
if command == "" or command == "edit" then
|
|
Layout.SetEditMode(not Layout.editing)
|
|
elseif command == "reset" then
|
|
if argument ~= "" then
|
|
if Layout.Reset(argument) then
|
|
say(L.LAYOUT_RESET_ONE .. argument)
|
|
else
|
|
say(L.LAYOUT_UNKNOWN_ELEMENT .. argument)
|
|
end
|
|
else
|
|
Layout.Reset()
|
|
say(L.LAYOUT_RESET_ALL)
|
|
end
|
|
elseif command == "bar" or command == "barre" then
|
|
if ForeverUI.ActionBarDebug then
|
|
ForeverUI.ActionBarDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_ACTIONBAR)
|
|
end
|
|
elseif command == "bas" then
|
|
if ForeverUI.BottomBarDebug then
|
|
ForeverUI.BottomBarDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_BOTTOM)
|
|
end
|
|
elseif command == "barres" then
|
|
if ForeverUI.StatusBarsDebug then
|
|
ForeverUI.StatusBarsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_STATUSBARS)
|
|
end
|
|
elseif command == "sacs" then
|
|
local cle, valeur = string.match(argument, "^(%S+)%s+(%S+)$")
|
|
if cle and ForeverUI.BagsSet then
|
|
ForeverUI.BagsSet(cle, valeur)
|
|
elseif ForeverUI.BagsDebug then
|
|
ForeverUI.BagsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_BAGS)
|
|
end
|
|
elseif command == "modele" then
|
|
if ForeverUI.CharacterModelTune then
|
|
ForeverUI.CharacterModelTune(argument)
|
|
else
|
|
say(L.LAYOUT_NO_MODEL_TUNE)
|
|
end
|
|
elseif command == "onglets" then
|
|
if ForeverUI.CharacterTabsDebug then
|
|
ForeverUI.CharacterTabsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_TABS)
|
|
end
|
|
elseif command == "perso" then
|
|
if ForeverUI.CharacterSheetDebug then
|
|
ForeverUI.CharacterSheetDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_SHEET)
|
|
end
|
|
elseif command == "minimap" then
|
|
if ForeverUI.MinimapDebug then
|
|
ForeverUI.MinimapDebug(argument)
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_MINIMAP)
|
|
end
|
|
elseif command == "souris" then
|
|
ForeverUI.SourisDebug()
|
|
elseif command == "carte" then
|
|
if ForeverUI.WorldMapDebug then
|
|
ForeverUI.WorldMapDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_WORLDMAP)
|
|
end
|
|
elseif command == "journal" then
|
|
if ForeverUI.QuestLogDebug then
|
|
ForeverUI.QuestLogDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_QUESTLOG)
|
|
end
|
|
elseif command == "suivi" then
|
|
if ForeverUI.ObjectiveTrackerDebug then
|
|
ForeverUI.ObjectiveTrackerDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_TRACKER)
|
|
end
|
|
elseif command == "grimoire" then
|
|
if ForeverUI.SpellBookDebug then
|
|
ForeverUI.SpellBookDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_SPELLBOOK)
|
|
end
|
|
elseif command == "micro" then
|
|
if ForeverUI.MicroDebug then
|
|
ForeverUI.MicroDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_MICROMENU)
|
|
end
|
|
elseif command == "titres" or command == "titles" then
|
|
if ForeverUI.TitlesDebug then
|
|
ForeverUI.TitlesDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_TITLES)
|
|
end
|
|
elseif command == "pvp" then
|
|
if ForeverUI.PvPDebug then
|
|
-- /fui pvp 0.35 : la jauge circulaire se pose a 35 %, pour la
|
|
-- voir sans avoir a gagner de l'honneur.
|
|
ForeverUI.PvPDebug(tonumber(argument))
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_PVP)
|
|
end
|
|
elseif command == "arene" or command == "arena" then
|
|
if ForeverUI.PvPArenaDebug then
|
|
ForeverUI.PvPArenaDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_ARENA)
|
|
end
|
|
elseif command == "tabard" then
|
|
if ForeverUI.TabardModelTune then
|
|
ForeverUI.TabardModelTune(argument)
|
|
end
|
|
elseif command == "chat" then
|
|
if ForeverUI.ChatDebug then
|
|
ForeverUI.ChatDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_CHAT)
|
|
end
|
|
elseif command == "chatlignes" then
|
|
if ForeverUI.ChatReleveLignes then
|
|
ForeverUI.ChatReleveLignes()
|
|
else
|
|
say(L.LAYOUT_NO_CHAT_LINES)
|
|
end
|
|
elseif command == "buffs" then
|
|
if ForeverUI.BuffsDebug then
|
|
ForeverUI.BuffsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_BUFFS)
|
|
end
|
|
elseif command == "chercheur" then
|
|
if ForeverUI.GroupFinderDebug then
|
|
ForeverUI.GroupFinderDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_GROUPFINDER)
|
|
end
|
|
elseif command == "social" then
|
|
if ForeverUI.SocialDebug then
|
|
ForeverUI.SocialDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_SOCIAL)
|
|
end
|
|
elseif command == "bg" then
|
|
if ForeverUI.PvPBattlegroundsDebug then
|
|
ForeverUI.PvPBattlegroundsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_BATTLEGROUNDS)
|
|
end
|
|
elseif command == "familier" then
|
|
if ForeverUI.PetDebug then
|
|
ForeverUI.PetDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_PET)
|
|
end
|
|
elseif command == "monnaie" or command == "monnaies" then
|
|
if ForeverUI.TokensDebug then
|
|
ForeverUI.TokensDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_CURRENCY)
|
|
end
|
|
elseif command == "skills" then
|
|
if ForeverUI.SkillsDebug then
|
|
ForeverUI.SkillsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_SKILLS)
|
|
end
|
|
elseif command == "reput" then
|
|
if ForeverUI.ReputationDebug then
|
|
-- /fui reput Alliance : ne garde que cette faction-la.
|
|
ForeverUI.ReputationDebug(argument ~= "" and argument or nil)
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_REPUTATION)
|
|
end
|
|
elseif command == "sets" then
|
|
if ForeverUI.EquipmentSetsDebug then
|
|
ForeverUI.EquipmentSetsDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG_SETS)
|
|
end
|
|
elseif command == "debug" then
|
|
if ForeverUI.PlayerFrameDebug then
|
|
ForeverUI.PlayerFrameDebug()
|
|
else
|
|
say(L.LAYOUT_NO_DIAG)
|
|
end
|
|
elseif command == "list" then
|
|
say(L.LAYOUT_LIST_HEADER)
|
|
for _, id in ipairs(Layout.order) do
|
|
local system = Layout.systems[id]
|
|
local saved = positions()[id]
|
|
DEFAULT_CHAT_FRAME:AddMessage(string.format(" %s (%s)%s", id, system.label,
|
|
saved and L.LAYOUT_LIST_MOVED or ""))
|
|
end
|
|
else
|
|
say(L.LAYOUT_HELP)
|
|
end
|
|
end
|