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>
2187 lines
75 KiB
Lua
2187 lines
75 KiB
Lua
-- ForeverUI : le journal de quetes, volet LISTE de la carte du monde (etape 2
|
|
-- du chantier docs/CARTE_ET_JOURNAL.md).
|
|
--
|
|
-- CHEZ CAMELOT, LE JOURNAL N'EST PAS UNE FENETRE. blizzard_uipanels_game.toc ne
|
|
-- charge pas QuestLogFrame pour camelot : c'est mainline/QuestMapFrame, un
|
|
-- volet de 330 accroche a droite de la carte (blizzard_worldmap.lua,
|
|
-- AttachQuestLog : TOPRIGHT (-3, -25), BOTTOMRIGHT (-3, 3), strate HIGH), et L
|
|
-- ouvre la carte avec lui (questlogownermixin.lua).
|
|
--
|
|
-- RELEVE -- mainline/questmapframe.xml / .lua, camelot/questmapframeoverrides.lua,
|
|
-- camelot/questmapframeutils.lua, sharedxml/listtemplates.xml / .lua :
|
|
-- QuestsFrame du coin haut-gauche du volet a (-22, +9) du bas-droit
|
|
-- QuestScrollFrame TOPLEFT (0, -29), BOTTOMRIGHT ; barre MinimalScrollBar
|
|
-- a (8, 2) / (8, -4) de son bord droit
|
|
-- Background QuestLog-main-background, taille de l'atlas, rognee a
|
|
-- la hauteur du cadre (ResizeBackground) ; liste vide :
|
|
-- QuestLog-empty-quest-background + EmptyText Game16Font
|
|
-- SearchBox 200 x 20 (camelot), BOTTOMLEFT sur son TOPLEFT (6, 7)
|
|
-- QuestLogCount 100 x 20 a droite de la recherche (3, 0), texte
|
|
-- GameFontNormalSmall a (-5, -5) du bord droit
|
|
-- SettingsDropdown 15 x 16, TOPRIGHT (19, 25) ; une case : objectifs
|
|
-- BorderFrame questlog-frame de (-3, 7) a (3, -6), filigrane en haut,
|
|
-- ombre questlog-frame-gradient-bottom en bas
|
|
-- Lignes, reconstruites a chaque mise a jour, empilees de haut en bas
|
|
-- (VerticalLayoutFrame) :
|
|
-- en-tete 289 x 22, a x = 9 ; ListHeaderVisualTemplate : fond
|
|
-- common-button-list-collapseExpand, texte Game15Font_Shadow
|
|
-- a (8, 0), bouton +/- 20 x 20 a RIGHT (-6) ; titre gris
|
|
-- (DISABLED_FONT_COLOR), blanc au survol
|
|
-- quete 290 de large, a x = 0 ; texte GameFontNormalLeft a
|
|
-- (31, -8) ; case de suivi 14 x 14 TOPRIGHT (0, -8) ;
|
|
-- hauteur = 8 + texte + objectifs + 6
|
|
-- objectif ObjectiveFont, tiret QUEST_DASH puis 205 de texte
|
|
-- Ecarts entre lignes (QuestLogQuests_UpdateButtonSpacing) : premier en-tete
|
|
-- 8, en-tete apres quete 4, en-tete apres en-tete 6, quete apres en-tete 2,
|
|
-- quete apres quete -3.
|
|
-- Ce que camelot change : prefixe [niveau] ou [niveau+] toujours ; "(Elite)"
|
|
-- a droite ; compteur montre ; pas d'icone de type de quete.
|
|
--
|
|
-- CE QUE 3.3.5 DONNE : GetQuestLogTitle(i) -> title, level, questTag,
|
|
-- suggestedGroup, isHeader, isCollapsed, isComplete (>0 terminee, <0 echouee),
|
|
-- isDaily. Un en-tete REPLIE retire ses quetes de la liste : pour chercher, on
|
|
-- deplie tout, puis on rend a chaque en-tete son etat -- retenu par son NOM.
|
|
--
|
|
-- LES REPERES ET LA CARTE (demande du 2026-09-25). camelot pose devant chaque
|
|
-- quete son repere (POIButton) et, au clic, montre la quete sur la carte
|
|
-- (QuestMapFrame_ShowQuestDetails : la carte passe sur celle de la quete).
|
|
-- WotLK a tout ce qu'il faut : apres WorldMapFrame_UpdateQuests, chaque quete
|
|
-- qui a un repere sur la carte affichee a son cadre WorldMapQuestFrame<n>,
|
|
-- numerote comme sur la carte ; QuestPOI_DisplayButton pose le meme repere
|
|
-- dans n'importe quel parent -- WotLK le fait pour sa propre liste ;
|
|
-- WorldMap_OpenToQuest met la carte sur la zone de la quete et la
|
|
-- selectionne, ce qui dessine sa zone d'objectif ; le survol d'une ligne
|
|
-- allume cette zone (DrawQuestBlob), comme la liste de WotLK.
|
|
--
|
|
-- LA PAGE D'UNE QUETE (etape 3, demande du 2026-09-25) : le clic sur une
|
|
-- quete remplace la liste par sa page -- texte, objectifs, recompenses -- et
|
|
-- un bouton Retour y ramene. Releve et ecarts : en tete de la section "la
|
|
-- page d'une quete", plus bas.
|
|
|
|
ForeverUI = ForeverUI or {}
|
|
|
|
local J = {}
|
|
ForeverUI.QuestLog = J
|
|
local L = ForeverUI.L
|
|
|
|
local V = {
|
|
largeur = 330, x = -3, haut = -25, bas = 3,
|
|
listeDroite = -22, listeBas = 9, listeHaut = -29,
|
|
enteteL = 289, enteteH = 22, enteteX = 9,
|
|
queteL = 290, queteTexteX = 31, queteTexteY = -8,
|
|
caseCote = 14, caseY = -8,
|
|
objectifL = 220, objectifTexteL = 205,
|
|
rechercheL = 200, rechercheH = 20, rechercheX = 6, rechercheY = 7,
|
|
compteurL = 100, compteurH = 20, compteurX = 3,
|
|
reglageL = 15, reglageH = 16, reglageX = 19, reglageY = 25,
|
|
barreX = 8, barreHaut = 2, barreBas = -4,
|
|
pas = 16,
|
|
}
|
|
|
|
-- Les ecarts de QuestLogQuests_UpdateButtonSpacing, pour les types que 3.3.5
|
|
-- connait.
|
|
local ECART = {
|
|
enteteApresRien = 8, enteteApresEntete = 6, enteteApresQuete = 4,
|
|
queteApresEntete = 2, queteApresQuete = -3,
|
|
}
|
|
|
|
-- Les couleurs de camelot : GlobalColor.db2 du client camelot, et
|
|
-- blizzard_framexmlbase/constants.lua pour la difficulte.
|
|
local COULEUR = {
|
|
objectif = { 0.8, 0.8, 0.8 }, -- QUEST_OBJECTIVE_FONT_COLOR
|
|
objectifSurvol = { 1, 1, 1 }, -- QUEST_OBJECTIVE_HIGHLIGHT_FONT_COLOR
|
|
enteteRepos = { 0.502, 0.502, 0.502 }, -- DISABLED_FONT_COLOR
|
|
enteteSurvol = { 1, 1, 1 }, -- HIGHLIGHT_FONT_COLOR
|
|
difficulte = {
|
|
trivial = { 0.50, 0.50, 0.50 }, standard = { 0.25, 0.75, 0.25 },
|
|
difficult = { 1.00, 0.82, 0.00 }, verydifficult = { 1.00, 0.50, 0.25 },
|
|
impossible = { 1.00, 0.10, 0.10 },
|
|
},
|
|
difficulteSurvol = {
|
|
trivial = { 0.70, 0.70, 0.70 }, standard = { 0.43, 0.93, 0.43 },
|
|
difficult = { 1.00, 1.00, 0.10 }, verydifficult = { 1.00, 0.75, 0.44 },
|
|
impossible = { 1.00, 0.40, 0.40 },
|
|
},
|
|
-- la page d'une quete : la matiere "Default" de GetMaterialTextColors
|
|
texte = { 0.18, 0.122, 0.059 }, -- DEFAULT_MATERIAL_TEXT_COLOR
|
|
titre = { 0, 0, 0 }, -- DEFAULT_MATERIAL_TITLETEXT_COLOR
|
|
ombreTitre = { 0.49, 0.35, 0.05 }, -- QuestFont_Shadow_Huge
|
|
objectifFait = { 0.2, 0.2, 0.2 }, -- QUEST_OBJECTIVE_COMPLETED_FONT_COLOR
|
|
recompense = { 0.902, 0.788, 0.671 }, -- QuestMapRewardsFont
|
|
communGris = { 0.659, 0.659, 0.659 }, -- COMMON_GRAY_COLOR
|
|
}
|
|
|
|
-- Les textes : ceux de 3.3.5 quand il les a, ceux de camelot sinon
|
|
-- (GlobalStrings.db2 du client camelot), dans Textes_<langue>.lua.
|
|
local TEXTE = {
|
|
recherche = L.QUESTLOG_SEARCH, -- SEARCH_QUEST_LOG
|
|
aucunResultat = L.QUESTLOG_NO_RESULTS, -- QUEST_LOG_NO_RESULTS
|
|
vide = L.QUESTLOG_EMPTY, -- QUEST_LOG_NO_QUESTS
|
|
compteur = L.QUESTLOG_COUNT, -- QUEST_LOG_COUNT_TEMPLATE
|
|
montrerObjectifs = L.QUESTLOG_SHOW_OBJECTIVES, -- QUEST_LOG_SHOW_OBJECTIVES
|
|
pret = L.QUESTLOG_READY, -- QUEST_WATCH_QUEST_READY
|
|
details = L.QUESTLOG_CLICK_DETAILS, -- CLICK_QUEST_DETAILS
|
|
nePlusSuivre = L.QUESTLOG_UNTRACK_QUEST, -- UNTRACK_QUEST
|
|
partagerChat = L.QUESTLOG_SHARE_IN_CHAT, -- SHARE_IN_CHAT
|
|
toutSuivre = L.QUESTLOG_TRACK_ALL, -- QUEST_LOG_TRACK_ALL
|
|
neRienSuivre = L.QUESTLOG_UNTRACK_ALL, -- QUEST_LOG_UNTRACK_ALL
|
|
-- la page d'une quete
|
|
nePlusSuivreCourt = L.QUESTLOG_UNTRACK, -- UNTRACK_QUEST_ABBREV
|
|
recompenses = QUEST_REWARDS, -- REWARDS (3.3.5 : QUEST_REWARDS)
|
|
titreEchec = L.QUESTLOG_TITLE_FAILED, -- QUEST_TITLE_FORMAT_FAILED
|
|
}
|
|
|
|
local POLICE = "Fonts\\FRIZQT__.TTF"
|
|
|
|
local function couleur(t, c)
|
|
t:SetTextColor(c[1], c[2], c[3])
|
|
end
|
|
|
|
-- ---------------------------------------------------------------- l'etat
|
|
-- ForeverUIDB n'existe qu'apres le chargement de nos variables.
|
|
local function reglages()
|
|
ForeverUIDB = ForeverUIDB or {}
|
|
ForeverUIDB.journal = ForeverUIDB.journal or {}
|
|
local r = ForeverUIDB.journal
|
|
if r.volet == nil then r.volet = true end -- questLogOpen
|
|
if r.objectifs == nil then r.objectifs = true end -- decision 4
|
|
return r
|
|
end
|
|
J.reglages = reglages
|
|
|
|
-- -------------------------------------------------------------- la difficulte
|
|
-- Le classement de WotLK, les couleurs de camelot.
|
|
local function cleDifficulte(niveau)
|
|
local c = GetQuestDifficultyColor and GetQuestDifficultyColor(niveau)
|
|
if c and QuestDifficultyColors then
|
|
for cle, valeur in pairs(QuestDifficultyColors) do
|
|
if valeur == c and COULEUR.difficulte[cle] then
|
|
return cle
|
|
end
|
|
end
|
|
end
|
|
return "difficult"
|
|
end
|
|
|
|
-- ------------------------------------------------------------- les donnees
|
|
-- Une entree du journal, avec ce que la ligne en affiche.
|
|
local function entree(index)
|
|
local titre, niveau, tag, groupe, estEntete, replie, termine, quotidienne, questID = GetQuestLogTitle(index)
|
|
if not titre then
|
|
return nil
|
|
end
|
|
return {
|
|
index = index, title = titre, level = niveau, questTag = tag,
|
|
isHeader = estEntete and true or false, isCollapsed = replie and true or false,
|
|
isComplete = termine, isDaily = quotidienne, questID = questID,
|
|
}
|
|
end
|
|
|
|
local function estElite(info)
|
|
return info.questTag == ELITE
|
|
end
|
|
|
|
-- QuestLogQuests_GetTitle + la surcharge camelot : "[" niveau ("+" si elite) "] ",
|
|
-- et devant, "[n] " si des membres du groupe ont la quete.
|
|
local function titreQuete(info)
|
|
local titre = "[" .. tostring(info.level) .. (estElite(info) and "+" or "") .. "] " .. info.title
|
|
local membres = 0
|
|
for i = 1, (GetNumPartyMembers and GetNumPartyMembers() or 0) do
|
|
if IsUnitOnQuest and IsUnitOnQuest(info.index, "party" .. i) then
|
|
membres = membres + 1
|
|
end
|
|
end
|
|
if membres > 0 then
|
|
titre = "[" .. membres .. "] " .. titre
|
|
end
|
|
return titre
|
|
end
|
|
|
|
-- ------------------------------------------------------------- la recherche
|
|
-- QuestSearcher : sans motif, sur le titre, le texte d'objectif et les
|
|
-- objectifs. Un en-tete replie cache ses quetes en 3.3.5 : on deplie tout le
|
|
-- temps de la recherche, et on rend a chaque en-tete son etat par son NOM.
|
|
local R = { texte = nil, etats = nil }
|
|
|
|
local function deplierTout()
|
|
R.etats = {}
|
|
for i = GetNumQuestLogEntries(), 1, -1 do
|
|
local info = entree(i)
|
|
if info and info.isHeader then
|
|
R.etats[info.title] = info.isCollapsed
|
|
if info.isCollapsed then
|
|
ExpandQuestHeader(i)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function rendreEtats()
|
|
if not R.etats then
|
|
return
|
|
end
|
|
for i = GetNumQuestLogEntries(), 1, -1 do
|
|
local info = entree(i)
|
|
if info and info.isHeader and R.etats[info.title] then
|
|
CollapseQuestHeader(i)
|
|
end
|
|
end
|
|
R.etats = nil
|
|
end
|
|
|
|
local function correspond(info)
|
|
if not R.texte then
|
|
return true
|
|
end
|
|
local cherche = R.texte
|
|
if string.find(string.lower(info.title), cherche, 1, true) then
|
|
return true
|
|
end
|
|
local selection = GetQuestLogSelection()
|
|
SelectQuestLogEntry(info.index)
|
|
local _, objectifs = GetQuestLogQuestText()
|
|
SelectQuestLogEntry(selection)
|
|
if objectifs and string.find(string.lower(objectifs), cherche, 1, true) then
|
|
return true
|
|
end
|
|
for i = 1, GetNumQuestLeaderBoards(info.index) do
|
|
local texte = GetQuestLogLeaderBoard(i, info.index)
|
|
if texte and string.find(string.lower(texte), cherche, 1, true) then
|
|
return true
|
|
end
|
|
end
|
|
return false
|
|
end
|
|
|
|
function J.chercher(texte)
|
|
if texte and texte ~= "" then
|
|
if not R.texte then
|
|
deplierTout()
|
|
end
|
|
R.texte = string.lower(texte)
|
|
else
|
|
if R.texte then
|
|
rendreEtats()
|
|
end
|
|
R.texte = nil
|
|
end
|
|
J.maj()
|
|
end
|
|
|
|
-- ------------------------------------------------------ les reperes, la carte
|
|
local PARENT_REPERES = "ForeverUIQuestScrollContents"
|
|
|
|
-- La numerotation de WotLK pour la carte affichee : WorldMapFrame_GetQuestFrame
|
|
-- compte les quetes terminees a part (QUEST_POI_COMPLETE_IN) et numerote les
|
|
-- autres (QUEST_POI_NUMERIC, index - terminees).
|
|
local function reperesDeLaCarte()
|
|
local reperes = {}
|
|
local terminees = 0
|
|
for i = 1, (WorldMapFrame and WorldMapFrame.numQuests or 0) do
|
|
local f = _G["WorldMapQuestFrame" .. i]
|
|
if f and f.questId and f.questId ~= 0 then
|
|
if f.completed then
|
|
terminees = terminees + 1
|
|
reperes[f.questId] = { QUEST_POI_COMPLETE_IN, terminees }
|
|
else
|
|
reperes[f.questId] = { QUEST_POI_NUMERIC, i - terminees }
|
|
end
|
|
end
|
|
end
|
|
return reperes
|
|
end
|
|
|
|
local function queteSelectionnee()
|
|
return WORLDMAP_SETTINGS and WORLDMAP_SETTINGS.selectedQuestId
|
|
end
|
|
|
|
-- Allumer ou eteindre la zone d'une quete sur la carte, comme la liste de
|
|
-- WotLK au survol (WorldMapQuestFrame_OnEnter / _OnLeave). La quete choisie
|
|
-- garde la sienne.
|
|
local function zone(info, allumer)
|
|
if not (WorldMapBlobFrame and WorldMapBlobFrame.DrawQuestBlob and info.questID) then
|
|
return
|
|
end
|
|
if info.isComplete and info.isComplete > 0 then
|
|
return
|
|
end
|
|
if not allumer and queteSelectionnee() == info.questID then
|
|
return
|
|
end
|
|
WorldMapBlobFrame:DrawQuestBlob(info.questID, allumer and true or false)
|
|
end
|
|
|
|
-- QuestMapFrame_ShowQuestDetails, pour sa partie carte : WorldMap_OpenToQuest
|
|
-- met la carte sur la zone de la quete et la selectionne.
|
|
local function montrerSurCarte(info)
|
|
SelectQuestLogEntry(info.index)
|
|
if info.questID and WorldMap_OpenToQuest then
|
|
WorldMap_OpenToQuest(info.questID)
|
|
end
|
|
if J.surSelection then J.surSelection(info.index) end
|
|
end
|
|
J.montrerSurCarte = montrerSurCarte
|
|
|
|
-- ------------------------------------------------------------- les actions
|
|
|
|
-- _QuestLog_ToggleQuestWatch de QuestLogFrame.lua (locale au client : recopiee)
|
|
local function basculerSuivi(index)
|
|
if IsQuestWatched(index) then
|
|
RemoveQuestWatch(index)
|
|
WatchFrame_Update()
|
|
else
|
|
if GetNumQuestWatches() >= MAX_WATCHABLE_QUESTS then
|
|
UIErrorsFrame:AddMessage(format(QUEST_WATCH_TOO_MANY, MAX_WATCHABLE_QUESTS), 1.0, 0.1, 0.1, 1.0)
|
|
return
|
|
end
|
|
AddQuestWatch(index)
|
|
WatchFrame_Update()
|
|
end
|
|
end
|
|
J.basculerSuivi = basculerSuivi
|
|
|
|
-- le bouton Abandonner de QuestLogFrame.xml
|
|
local function abandonner(index)
|
|
SelectQuestLogEntry(index)
|
|
SetAbandonQuest()
|
|
local objets = GetAbandonQuestItems()
|
|
if objets then
|
|
StaticPopup_Hide("ABANDON_QUEST")
|
|
StaticPopup_Show("ABANDON_QUEST_WITH_ITEMS", GetAbandonQuestName(), objets)
|
|
else
|
|
StaticPopup_Hide("ABANDON_QUEST_WITH_ITEMS")
|
|
StaticPopup_Show("ABANDON_QUEST", GetAbandonQuestName())
|
|
end
|
|
end
|
|
|
|
local function partager(index)
|
|
SelectQuestLogEntry(index)
|
|
QuestLogPushQuest()
|
|
PlaySound("igQuestLogOpen")
|
|
end
|
|
|
|
local function enGroupe()
|
|
return (GetNumPartyMembers and GetNumPartyMembers() > 0) or (GetNumRaidMembers and GetNumRaidMembers() > 1)
|
|
end
|
|
|
|
local function menu(ancre, liste)
|
|
if ForeverUI.WorldMap and ForeverUI.WorldMap.ouvrirMenu then
|
|
ForeverUI.WorldMap.ouvrirMenu(ancre, liste)
|
|
end
|
|
end
|
|
|
|
-- QuestMapLogTitleButton_CreateContextMenu, sans le super-suivi (absent de 3.3.5)
|
|
local function menuQuete(ligne)
|
|
local index = ligne.index
|
|
local l = {}
|
|
table.insert(l, {
|
|
text = IsQuestWatched(index) and TEXTE.nePlusSuivre or TRACK_QUEST,
|
|
func = function() basculerSuivi(index) end,
|
|
})
|
|
local partageable = GetQuestLogPushable and GetQuestLogPushable(index) and enGroupe()
|
|
table.insert(l, {
|
|
text = SHARE_QUEST,
|
|
disabled = not partageable,
|
|
func = function() partager(index) end,
|
|
})
|
|
table.insert(l, {
|
|
text = TEXTE.partagerChat,
|
|
func = function()
|
|
local lien = GetQuestLink(index)
|
|
if lien and not (ChatEdit_InsertLink and ChatEdit_InsertLink(lien)) then
|
|
ChatFrame_OpenChat(lien)
|
|
end
|
|
end,
|
|
})
|
|
table.insert(l, {
|
|
text = ABANDON_QUEST,
|
|
func = function() abandonner(index) end,
|
|
})
|
|
menu(ligne, l)
|
|
end
|
|
|
|
-- QuestMapLogHeaderButton_CreateContextMenu : suivre ou ne plus suivre les
|
|
-- quetes d'un en-tete (SetHeaderQuestsTracked)
|
|
local function suivreEntete(nomEntete, suivre)
|
|
local dedans = false
|
|
for i = 1, GetNumQuestLogEntries() do
|
|
local info = entree(i)
|
|
if info and info.isHeader then
|
|
dedans = (info.title == nomEntete)
|
|
elseif info and dedans then
|
|
local suivie = IsQuestWatched(i) and true or false
|
|
if suivre and not suivie then
|
|
if GetNumQuestWatches() >= MAX_WATCHABLE_QUESTS then
|
|
UIErrorsFrame:AddMessage(format(QUEST_WATCH_TOO_MANY, MAX_WATCHABLE_QUESTS), 1.0, 0.1, 0.1, 1.0)
|
|
break
|
|
end
|
|
AddQuestWatch(i)
|
|
elseif not suivre and suivie then
|
|
RemoveQuestWatch(i)
|
|
end
|
|
end
|
|
end
|
|
WatchFrame_Update()
|
|
J.maj()
|
|
end
|
|
|
|
-- ------------------------------------------------------------- l'infobulle
|
|
-- QuestMapLogTitleButton_OnEnter : titre, echec, texte de rendu ou texte
|
|
-- d'objectif puis objectifs (blanc, gris si remplis), argent, le rappel du
|
|
-- clic, les membres du groupe.
|
|
local function infobulle(ligne)
|
|
local info = ligne.info
|
|
GameTooltip:ClearAllPoints()
|
|
GameTooltip:SetPoint("TOPLEFT", ligne, "TOPRIGHT", 34, 0)
|
|
GameTooltip:SetOwner(ligne, "ANCHOR_PRESERVE")
|
|
GameTooltip:SetText(info.title)
|
|
local largeur = 20 + math.max(231, GameTooltipTextLeft1:GetStringWidth())
|
|
-- le bord droit de la carte, en unites de l'interface : WorldMapFrame est
|
|
-- a sa propre echelle (WorldMap.lua)
|
|
local droite = WorldMapFrame:GetRight() * WorldMapFrame:GetEffectiveScale() / UIParent:GetEffectiveScale()
|
|
if largeur > UIParent:GetRight() - droite then
|
|
GameTooltip:ClearAllPoints()
|
|
GameTooltip:SetPoint("TOPRIGHT", ligne, "TOPLEFT", -5, 0)
|
|
GameTooltip:SetOwner(ligne, "ANCHOR_PRESERVE")
|
|
GameTooltip:SetText(info.title)
|
|
end
|
|
if info.isComplete and info.isComplete < 0 then
|
|
GameTooltip:AddLine(FAILED, 1, 0.125, 0.125)
|
|
end
|
|
GameTooltip:AddLine(" ")
|
|
if info.isComplete and info.isComplete > 0 then
|
|
GameTooltip:AddLine(GetQuestLogCompletionText(info.index) or TEXTE.pret, 1, 1, 1, true)
|
|
GameTooltip:AddLine(" ")
|
|
else
|
|
local selection = GetQuestLogSelection()
|
|
SelectQuestLogEntry(info.index)
|
|
local _, objectifs = GetQuestLogQuestText()
|
|
SelectQuestLogEntry(selection)
|
|
GameTooltip:AddLine(objectifs, 1, 1, 1, true)
|
|
GameTooltip:AddLine(" ")
|
|
local separer = false
|
|
for i = 1, GetNumQuestLeaderBoards(info.index) do
|
|
local texte, _, fini = GetQuestLogLeaderBoard(i, info.index)
|
|
if texte then
|
|
local g = fini and 0.502 or 1
|
|
GameTooltip:AddLine(QUEST_DASH .. texte, g, g, g, true)
|
|
separer = true
|
|
end
|
|
end
|
|
local requis = GetQuestLogRequiredMoney(info.index)
|
|
if requis and requis > 0 then
|
|
local argent = GetMoney()
|
|
local g = 1
|
|
if requis <= argent then
|
|
argent = requis
|
|
g = 0.502
|
|
end
|
|
GameTooltip:AddLine(QUEST_DASH .. GetMoneyString(argent) .. " / " .. GetMoneyString(requis), g, g, g)
|
|
separer = true
|
|
end
|
|
if separer then
|
|
GameTooltip:AddLine(" ")
|
|
end
|
|
end
|
|
GameTooltip:AddLine(TEXTE.details, 0.098, 1, 0.098)
|
|
GameTooltip:Show()
|
|
end
|
|
|
|
-- ------------------------------------------------------ la page d'une quete
|
|
--
|
|
-- RELEVE -- mainline/questmapframe.xml, DetailsFrame (QuestLogQuestDetailsMixin) :
|
|
-- DetailsFrame 308 x 502, TOPRIGHT (0, -1) de QuestsFrame -- donc a
|
|
-- (-22, -1) du coin haut-droit du volet
|
|
-- Bg QuestDetailsBackgrounds, a la largeur du cadre, la
|
|
-- hauteur au prorata et plafonnee a 440 (rognee par
|
|
-- SetTexCoord) -- AdjustBackgroundTexture
|
|
-- BorderFrame QuestLogBorderFrameTemplate de (-3, 4) a (3, 17), niveau 100
|
|
-- BackFrame 307 x 52 en haut, questlog-reward-top-frame ; bouton
|
|
-- BACK (UIPanelButtonTemplate) 90 x 22 a LEFT (11, 4)
|
|
-- ScrollFrame 298 x 430 a (5, -43), barre a (13, 17) / (13, -27)
|
|
-- RewardsFrameContainer 307 de large, BOTTOMLEFT (0, 23), niveau 50,
|
|
-- clipChildren ; dedans RewardsFrame 307 de large :
|
|
-- questlog-reward-header-top en haut, questlog-reward-bottom
|
|
-- en bas, questlog-reward-tile-vertical entre les deux,
|
|
-- "Rewards" en QuestFont_Huge a TOP (0, -22)
|
|
-- Abandon 105 x 22 BOTTOMLEFT (-3, -2), Share 103 x 22 puis Track
|
|
-- 105 x 22 a la suite ; Share porte deux separateurs
|
|
-- UI-Frame-BtnDivMiddle, (6, 0) et (-6, 0) hors de ses bords
|
|
-- mainline/questmapframe.lua : QuestMapFrame_ShowQuestDetails,
|
|
-- _CloseQuestDetails, _ReturnFromQuestDetails, _UpdateQuestDetailsButtons,
|
|
-- SetRewardsHeight et AdjustRewardsFrameContainer.
|
|
-- mainline/questinfo.lua / .xml : QUEST_TEMPLATE_MAP_DETAILS (le texte) et
|
|
-- QUEST_TEMPLATE_MAP_REWARDS (les recompenses), MapQuestInfoRewardsFrame.
|
|
--
|
|
-- LE MOTEUR QUESTINFO N'EST PAS REPRIS : ses cadres (QuestInfoTitleHeader,
|
|
-- QuestInfoRewardsFrame...) sont uniques et partages avec la fenetre de
|
|
-- quete du PNJ, qui les re-parente a chaque affichage. La page a les siens,
|
|
-- empiles comme QuestInfo_Display les empile : chaque element en TOPLEFT
|
|
-- sur le BOTTOMLEFT du precedent, aux decalages du modele.
|
|
--
|
|
-- CE QUI DIFFERE, ET POURQUOI.
|
|
-- * clipChildren n'existe pas en 3.3.5 : le conteneur des recompenses est
|
|
-- un ScrollFrame, le seul cadre de ce client qui rogne ce qu'il porte.
|
|
-- * le fond des recompenses se repete par tuiles de 83 : SetTexCoord ne
|
|
-- repete pas une feuille d'atlas.
|
|
-- * 3.3.5 ne compte pas la hauteur d'un contenu defilant : elle est
|
|
-- additionnee element par element.
|
|
-- * absents de 3.3.5, donc absents d'ici : le portrait du donneur, les
|
|
-- boutons de chemin, le sceau de campagne, les objectifs de sort, la
|
|
-- reputation des grandes factions, les devises.
|
|
-- * 3.3.5 donne des POINTS D'ARENE en recompense, camelot n'en a plus :
|
|
-- ils prennent la forme de l'honneur, dans une section a eux.
|
|
local D = {
|
|
largeur = 308, hauteur = 502, x = -22, y = -1, fondMax = 440,
|
|
bordG = -3, bordH = 4, bordD = 3, bordB = 17,
|
|
retourL = 307, retourH = 52, boutonRetourL = 90, boutonRetourX = 11, boutonRetourY = 4,
|
|
boutonH = 22, abandonL = 105, partageL = 103, suivreL = 105, boutonsX = -3, boutonsY = -2,
|
|
separateurX = 6,
|
|
texteL = 298, texteH = 430, texteX = 5, texteY = -43,
|
|
barreX = 13, barreHaut = 17, barreBas = -27,
|
|
contenu = 289, -- contentWidth
|
|
recL = 307, recY = 23, recNiveau = 50, recMin = 124,
|
|
recHautTuile = 56, tuile = 83, libelleY = -22,
|
|
-- QUEST_TEMPLATE_MAP_REWARDS et questinfo.lua
|
|
recX = 12, recY2 = -52, recSeparation = 8, recSection = 5, recRangee = 2,
|
|
recEnPlus = 62, recSans = 59, choixL = 265,
|
|
objetL = 134, objetH = 30, icone = 30, nomL = 92, nomH = 36,
|
|
pas = 16,
|
|
}
|
|
|
|
-- Les modeles de texte de camelot, polices comprises (fontstyles.xml,
|
|
-- fonts.xml du client camelot) : QuestTitleFont = MORPHEUS 18 ombre
|
|
-- (1, -1) ; QuestFont = FRIZQT 13 ; QuestFontNormalSmall = FRIZQT 12 ;
|
|
-- QuestMapRewardsFont = FRIZQT 10 ; QuestFont_Huge = MORPHEUS 18.
|
|
local MORPHEUS = "Fonts\\MORPHEUS.ttf"
|
|
local POLICES = {
|
|
titre = { MORPHEUS, 18 }, texte = { POLICE, 13 }, petit = { POLICE, 12 },
|
|
recompense = { POLICE, 10 }, libelle = { MORPHEUS, 18 },
|
|
}
|
|
|
|
local PANNEAU = "Interface\\Buttons\\UI-Panel-Button-"
|
|
local ICONES = {
|
|
argent = "Interface\\Icons\\INV_Misc_Coin_01",
|
|
xp = "interface\\ForeverUI\\icons\\xp_icon",
|
|
titre = "Interface\\Icons\\INV_Misc_Note_02",
|
|
honneur = "interface\\ForeverUI\\icons\\pvpcurrency-honor-",
|
|
arene = "Interface\\PVPFrame\\PVP-ArenaPoints-Icon",
|
|
contour = "Interface\\ForeverUI\\common\\whiteiconframe",
|
|
}
|
|
|
|
local function police(fs, modele, c)
|
|
local p = POLICES[modele]
|
|
fs:SetFont(p[1], p[2])
|
|
if c then couleur(fs, c) end
|
|
end
|
|
|
|
-- UIPanelButtonTemplate de camelot : trois morceaux de UI-Panel-Button-*,
|
|
-- que le bouton de 3.3.5 etire d'une seule piece.
|
|
local function boutonPanneau(parent, nom, texte, largeur)
|
|
local b = CreateFrame("Button", nom, parent)
|
|
b:SetWidth(largeur)
|
|
b:SetHeight(D.boutonH)
|
|
local function morceau(u1, u2)
|
|
local t = b:CreateTexture(nil, "BACKGROUND")
|
|
t:SetTexCoord(u1, u2, 0, 0.6875)
|
|
return t
|
|
end
|
|
local g = morceau(0, 0.09375)
|
|
g:SetWidth(12)
|
|
g:SetPoint("TOPLEFT", b, "TOPLEFT", 0, 0)
|
|
g:SetPoint("BOTTOMLEFT", b, "BOTTOMLEFT", 0, 0)
|
|
local d = morceau(0.53125, 0.625)
|
|
d:SetWidth(12)
|
|
d:SetPoint("TOPRIGHT", b, "TOPRIGHT", 0, 0)
|
|
d:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 0, 0)
|
|
local m = morceau(0.09375, 0.53125)
|
|
m:SetPoint("TOPLEFT", g, "TOPRIGHT", 0, 0)
|
|
m:SetPoint("BOTTOMRIGHT", d, "BOTTOMLEFT", 0, 0)
|
|
b.morceaux = { g, m, d }
|
|
local function etat(suffixe)
|
|
for _, t in ipairs(b.morceaux) do
|
|
t:SetTexture(PANNEAU .. suffixe)
|
|
end
|
|
end
|
|
etat("Up")
|
|
local fs = b:CreateFontString(nil, "ARTWORK")
|
|
fs:SetFontObject(GameFontNormal)
|
|
fs:SetPoint("CENTER", b, "CENTER", 0, 0)
|
|
b:SetFontString(fs)
|
|
b:SetNormalFontObject(GameFontNormal)
|
|
b:SetHighlightFontObject(GameFontHighlight)
|
|
b:SetDisabledFontObject(GameFontDisable)
|
|
b:SetText(texte)
|
|
b:SetHighlightTexture(PANNEAU .. "Highlight")
|
|
local s = b:GetHighlightTexture()
|
|
if s then
|
|
s:SetTexCoord(0, 0.625, 0, 0.6875)
|
|
s:SetBlendMode("ADD")
|
|
end
|
|
b.actif = true
|
|
b:SetScript("OnMouseDown", function(self)
|
|
if self.actif then etat("Down") end
|
|
end)
|
|
b:SetScript("OnMouseUp", function(self)
|
|
if self.actif then etat("Up") end
|
|
end)
|
|
-- UIPanelButton_OnEnable / _OnDisable
|
|
function b:Activer(oui)
|
|
self.actif = oui and true or false
|
|
if oui then
|
|
self:Enable()
|
|
etat("Up")
|
|
else
|
|
self:Disable()
|
|
etat("Disabled")
|
|
end
|
|
end
|
|
return b
|
|
end
|
|
|
|
-- SmallItemButtonTemplate (+ SmallQuestRewardItemButtonTemplate) : icone
|
|
-- 30, cadre du nom QuestItemBorder a sa taille, nom 92 x 36, nombre en bas a
|
|
-- droite de l'icone, contour de qualite sur l'icone.
|
|
local function creerObjet(parent, nom)
|
|
local b = CreateFrame("Button", nom, parent)
|
|
b:SetWidth(D.objetL)
|
|
b:SetHeight(D.objetH)
|
|
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
local icone = b:CreateTexture(nil, "BACKGROUND")
|
|
icone:SetWidth(D.icone)
|
|
icone:SetHeight(D.icone)
|
|
icone:SetPoint("TOPLEFT", b, "TOPLEFT", 0, 0)
|
|
local cadre = b:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(cadre, "questitemborder")
|
|
cadre:SetPoint("LEFT", icone, "RIGHT", 2, 0)
|
|
local texte = b:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall")
|
|
texte:SetWidth(D.nomL)
|
|
texte:SetHeight(D.nomH)
|
|
texte:SetJustifyH("LEFT")
|
|
texte:SetPoint("LEFT", cadre, "LEFT", 4, 0)
|
|
local nombre = b:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmall")
|
|
nombre:SetJustifyH("RIGHT")
|
|
nombre:SetPoint("BOTTOMRIGHT", icone, "BOTTOMRIGHT", 0, 1)
|
|
local contour = b:CreateTexture(nil, "OVERLAY")
|
|
contour:SetTexture(ICONES.contour)
|
|
contour:SetAllPoints(icone)
|
|
contour:Hide()
|
|
b.Icon, b.NameFrame, b.Name, b.Count, b.IconBorder = icone, cadre, texte, nombre, contour
|
|
return b
|
|
end
|
|
|
|
-- SetItemButtonCount : le nombre ne se montre qu'au-dessus de 1
|
|
local function nombreObjet(b, n)
|
|
if n and n > 1 then
|
|
b.Count:SetText(n)
|
|
b.Count:Show()
|
|
else
|
|
b.Count:Hide()
|
|
end
|
|
end
|
|
|
|
-- L'index d'une quete dans le journal de 3.3.5, qui n'a que des index.
|
|
local function indexDeQuete(questID)
|
|
if not questID then return nil end
|
|
for i = 1, GetNumQuestLogEntries() do
|
|
local info = entree(i)
|
|
if info and not info.isHeader and info.questID == questID then
|
|
return i
|
|
end
|
|
end
|
|
return nil
|
|
end
|
|
|
|
-- Les boutons d'une recompense : infobulle et clic de QuestInfoRewardItemMixin
|
|
-- (objet) et de QuestInfoRewardSpellCodeMixin (sort).
|
|
local function survolRecompense(self)
|
|
local d = J.details
|
|
if d and d.index then SelectQuestLogEntry(d.index) end
|
|
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
|
if self.objectType == "item" then
|
|
GameTooltip:SetQuestLogItem(self.type, self:GetID())
|
|
if GameTooltip_ShowCompareItem then GameTooltip_ShowCompareItem(GameTooltip) end
|
|
elseif self.objectType == "spell" then
|
|
GameTooltip:SetQuestLogRewardSpell()
|
|
elseif self.infobulle then
|
|
GameTooltip:SetText(self.infobulle, 1, 1, 1)
|
|
else
|
|
GameTooltip:Hide()
|
|
return
|
|
end
|
|
GameTooltip:Show()
|
|
end
|
|
|
|
local function clicRecompense(self)
|
|
if not IsModifiedClick() then return end
|
|
local d = J.details
|
|
if d and d.index then SelectQuestLogEntry(d.index) end
|
|
if self.objectType == "item" then
|
|
HandleModifiedItemClick(GetQuestLogItemLink(self.type, self:GetID()))
|
|
elseif self.objectType == "spell" and IsModifiedClick("CHATLINK") then
|
|
ChatEdit_InsertLink(GetQuestLogSpellLink())
|
|
end
|
|
end
|
|
|
|
local function brancherRecompense(b)
|
|
b:SetScript("OnEnter", survolRecompense)
|
|
b:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
b:SetScript("OnClick", clicRecompense)
|
|
return b
|
|
end
|
|
|
|
-- Le fond des recompenses : l'en-tete, le bas, et entre les deux le motif
|
|
-- vertical, repete par tuiles de 83.
|
|
local function poserFondRecompenses(r, hauteur)
|
|
local e = ForeverUI.AtlasEntry("questlog-reward-tile-vertical")
|
|
local reste = hauteur - D.recHautTuile
|
|
local n = 0
|
|
while e and reste > 0 do
|
|
n = n + 1
|
|
local t = r.tuiles[n]
|
|
if not t then
|
|
t = r:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(t, "questlog-reward-tile-vertical")
|
|
r.tuiles[n] = t
|
|
end
|
|
local h = math.min(D.tuile, reste)
|
|
t:SetHeight(h)
|
|
t:SetTexCoord(e[2], e[3], e[4], e[4] + (e[5] - e[4]) * h / D.tuile)
|
|
t:ClearAllPoints()
|
|
t:SetPoint("TOPLEFT", r.haut, "BOTTOMLEFT", 0, -(n - 1) * D.tuile)
|
|
t:Show()
|
|
reste = reste - h
|
|
end
|
|
for i = n + 1, #r.tuiles do
|
|
r.tuiles[i]:Hide()
|
|
end
|
|
end
|
|
|
|
local function creerDetails(v)
|
|
local d = CreateFrame("Frame", "ForeverUIQuestDetailsFrame", v)
|
|
d:SetWidth(D.largeur)
|
|
d:SetHeight(D.hauteur)
|
|
d:SetPoint("TOPRIGHT", v, "TOPRIGHT", D.x, D.y)
|
|
d:EnableMouse(true)
|
|
|
|
-- le fond, a la largeur du cadre, plafonne a 440 (AdjustBackgroundTexture)
|
|
local fond = d:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(fond, "questdetailsbackgrounds")
|
|
local e = ForeverUI.AtlasEntry("questdetailsbackgrounds")
|
|
fond:SetPoint("TOPLEFT", d, "TOPLEFT", 0, 0)
|
|
fond:SetPoint("TOPRIGHT", d, "TOPRIGHT", 0, 0)
|
|
if e then
|
|
local voulue = e[7] * D.largeur / e[6]
|
|
if voulue > D.fondMax then
|
|
fond:SetTexCoord(e[2], e[3], e[4], e[4] + (e[5] - e[4]) * D.fondMax / voulue)
|
|
fond:SetHeight(D.fondMax)
|
|
else
|
|
fond:SetHeight(voulue)
|
|
end
|
|
end
|
|
d.fond = fond
|
|
|
|
-- le cadre (QuestLogBorderFrameTemplate), niveau 100
|
|
local bord = CreateFrame("Frame", nil, d)
|
|
bord:SetPoint("TOPLEFT", d, "TOPLEFT", D.bordG, D.bordH)
|
|
bord:SetPoint("BOTTOMRIGHT", d, "BOTTOMRIGHT", D.bordD, D.bordB)
|
|
bord:SetFrameLevel(d:GetFrameLevel() + 100)
|
|
if ForeverUI.CreateNineSlice then
|
|
ForeverUI.CreateNineSlice(bord, "questlog-frame", 53, { 0, 0, 0, 0 }, "BORDER")
|
|
end
|
|
local filigrane = bord:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(filigrane, "questlog-frame-filigree")
|
|
filigrane:SetPoint("TOP", bord, "TOP", 0, 1)
|
|
d.bord = bord
|
|
|
|
-- le bandeau du haut et le bouton Retour
|
|
local bandeau = CreateFrame("Frame", nil, d)
|
|
bandeau:SetWidth(D.retourL)
|
|
bandeau:SetHeight(D.retourH)
|
|
bandeau:SetPoint("TOPLEFT", d, "TOPLEFT", 0, 0)
|
|
local image = bandeau:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(image, "questlog-reward-top-frame")
|
|
image:SetPoint("TOPLEFT", bandeau, "TOPLEFT", 0, 0)
|
|
local retour = boutonPanneau(bandeau, "ForeverUIQuestDetailsBackButton", BACK, D.boutonRetourL)
|
|
retour:SetPoint("LEFT", bandeau, "LEFT", D.boutonRetourX, D.boutonRetourY)
|
|
retour:SetScript("OnClick", function()
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
J.revenirDeDetails()
|
|
end)
|
|
d.retour = retour
|
|
|
|
-- le texte, qui defile
|
|
local defile = CreateFrame("ScrollFrame", "ForeverUIQuestDetailsScrollFrame", d)
|
|
defile:SetWidth(D.texteL)
|
|
defile:SetHeight(D.texteH)
|
|
defile:SetPoint("TOPLEFT", d, "TOPLEFT", D.texteX, D.texteY)
|
|
local contenu = CreateFrame("Frame", "ForeverUIQuestDetailsContents", defile)
|
|
contenu:SetWidth(D.texteL)
|
|
contenu:SetHeight(1)
|
|
defile:SetScrollChild(contenu)
|
|
d.defile, d.contenu = defile, contenu
|
|
|
|
local function texte(modele, c)
|
|
local fs = contenu:CreateFontString(nil, "BACKGROUND")
|
|
police(fs, modele, c)
|
|
fs:SetJustifyH("LEFT")
|
|
fs:SetWidth(D.contenu)
|
|
return fs
|
|
end
|
|
d.titre = texte("titre", COULEUR.titre)
|
|
d.titre:SetShadowOffset(1, -1)
|
|
d.titre:SetShadowColor(COULEUR.ombreTitre[1], COULEUR.ombreTitre[2], COULEUR.ombreTitre[3], 1)
|
|
d.texteObjectifs = texte("texte", COULEUR.texte)
|
|
d.minuteur = texte("petit", COULEUR.texte)
|
|
d.groupe = texte("texte", COULEUR.texte)
|
|
d.enteteDescription = texte("titre", COULEUR.titre)
|
|
d.enteteDescription:SetShadowOffset(1, -1)
|
|
d.enteteDescription:SetShadowColor(COULEUR.ombreTitre[1], COULEUR.ombreTitre[2], COULEUR.ombreTitre[3], 1)
|
|
d.enteteDescription:SetText(QUEST_DESCRIPTION)
|
|
d.description = texte("texte", COULEUR.texte)
|
|
d.objectifs = {}
|
|
d.nouvelObjectif = function() return texte("petit", COULEUR.texte) end
|
|
|
|
-- l'argent demande : le libelle et un petit porte-monnaie fige
|
|
local argent = CreateFrame("Frame", nil, contenu)
|
|
argent:SetWidth(285)
|
|
argent:SetHeight(28)
|
|
local argentTexte = argent:CreateFontString(nil, "BACKGROUND")
|
|
police(argentTexte, "petit")
|
|
argentTexte:SetPoint("LEFT", argent, "LEFT", 0, 0)
|
|
argentTexte:SetText(REQUIRED_MONEY)
|
|
local bourse = CreateFrame("Frame", "ForeverUIQuestDetailsRequiredMoney", argent, "SmallMoneyFrameTemplate")
|
|
bourse:SetPoint("LEFT", argentTexte, "RIGHT", 10, 0)
|
|
if MoneyFrame_SetType then MoneyFrame_SetType(bourse, "STATIC") end
|
|
argent.texte, argent.bourse = argentTexte, bourse
|
|
d.argent = argent
|
|
|
|
-- le compte a rebours (QuestInfoTimerFrame_OnUpdate)
|
|
local horloge = CreateFrame("Frame", nil, contenu)
|
|
horloge:SetScript("OnUpdate", function(self, ecoule)
|
|
if self.reste then
|
|
self.reste = math.max(self.reste - ecoule, 0)
|
|
d.minuteur:SetText(TIME_REMAINING .. " " .. SecondsToTime(self.reste))
|
|
end
|
|
end)
|
|
d.horloge = horloge
|
|
|
|
-- l'espace laisse aux recompenses, en bas du texte
|
|
local espace = CreateFrame("Frame", nil, contenu)
|
|
espace:SetWidth(5)
|
|
espace:SetHeight(5)
|
|
d.espace = espace
|
|
|
|
local barre = ForeverUI.CreateScrollBar and ForeverUI.CreateScrollBar("ForeverUIQuestDetailsScrollBar", d, defile)
|
|
if barre then
|
|
barre:ClearAllPoints()
|
|
barre:SetPoint("TOPLEFT", defile, "TOPRIGHT", D.barreX, D.barreHaut)
|
|
barre:SetPoint("BOTTOMLEFT", defile, "BOTTOMRIGHT", D.barreX, D.barreBas)
|
|
barre:SetFrameLevel(bord:GetFrameLevel() + 1)
|
|
barre.surDefilement = function(pas)
|
|
J.defilerDetails(pas * D.pas)
|
|
end
|
|
d.barre = barre
|
|
end
|
|
defile:EnableMouseWheel(true)
|
|
defile:SetScript("OnMouseWheel", function(_, sens)
|
|
if d.barre and d.barre:IsShown() then
|
|
d.barre:Deplacer(d.barre.decalage - sens * 3)
|
|
end
|
|
end)
|
|
|
|
-- les recompenses : un ScrollFrame immobile, qui rogne ce qui depasse
|
|
local conteneur = CreateFrame("ScrollFrame", "ForeverUIQuestDetailsRewardsContainer", d)
|
|
conteneur:SetWidth(D.recL)
|
|
conteneur:SetHeight(100)
|
|
conteneur:SetPoint("BOTTOMLEFT", d, "BOTTOMLEFT", 0, D.recY)
|
|
conteneur:SetFrameLevel(d:GetFrameLevel() + D.recNiveau)
|
|
local r = CreateFrame("Frame", "ForeverUIQuestDetailsRewardsFrame", conteneur)
|
|
r:SetWidth(D.recL)
|
|
r:SetHeight(275)
|
|
conteneur:SetScrollChild(r)
|
|
local bas = r:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(bas, "questlog-reward-bottom")
|
|
bas:SetPoint("BOTTOMLEFT", r, "BOTTOMLEFT", 0, 0)
|
|
local haut = r:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(haut, "questlog-reward-header-top")
|
|
haut:SetPoint("TOPLEFT", r, "TOPLEFT", 0, 0)
|
|
local libelle = r:CreateFontString(nil, "ARTWORK")
|
|
police(libelle, "libelle", COULEUR.recompense)
|
|
libelle:SetPoint("TOP", r, "TOP", 0, D.libelleY)
|
|
libelle:SetText(TEXTE.recompenses)
|
|
r.haut, r.bas, r.libelle, r.tuiles = haut, bas, libelle, {}
|
|
d.conteneur, d.recompenses = conteneur, r
|
|
|
|
-- MapQuestInfoRewardsFrame, a (12, -52)
|
|
local liste = CreateFrame("Frame", nil, r)
|
|
liste:SetWidth(285)
|
|
liste:SetHeight(10)
|
|
liste:SetPoint("TOPLEFT", r, "TOPLEFT", D.recX, D.recY2)
|
|
local entete = CreateFrame("Frame", nil, liste)
|
|
entete:SetWidth(1)
|
|
entete:SetHeight(1)
|
|
entete:SetPoint("TOPLEFT", liste, "TOPLEFT", 0, 0)
|
|
local function libelleRecompense(largeur)
|
|
local fs = liste:CreateFontString(nil, "BACKGROUND")
|
|
police(fs, "recompense", COULEUR.recompense)
|
|
fs:SetJustifyH("LEFT")
|
|
if largeur then fs:SetWidth(largeur) end
|
|
return fs
|
|
end
|
|
liste.entete = entete
|
|
liste.choisir = libelleRecompense(D.choixL)
|
|
liste.recevoir = libelleRecompense()
|
|
liste.titreJoueur = libelleRecompense()
|
|
liste.titreJoueur:SetText(REWARD_TITLE)
|
|
liste.sort = libelleRecompense()
|
|
liste.objets = {}
|
|
liste.xp = brancherRecompense(creerObjet(liste))
|
|
liste.xp.Icon:SetTexture(ICONES.xp)
|
|
liste.xp.Name:SetFontObject(NumberFontNormal)
|
|
liste.argent = brancherRecompense(creerObjet(liste))
|
|
liste.argent.Icon:SetTexture(ICONES.argent)
|
|
liste.argent.Name:SetFontObject(GameFontHighlight)
|
|
liste.titre = brancherRecompense(creerObjet(liste))
|
|
liste.titre.Icon:SetTexture(ICONES.titre)
|
|
liste.honneur = brancherRecompense(creerObjet(liste))
|
|
liste.arene = brancherRecompense(creerObjet(liste))
|
|
liste.arene.Icon:SetTexture(ICONES.arene)
|
|
liste.sortBouton = brancherRecompense(creerObjet(liste))
|
|
liste.sortBouton.objectType = "spell"
|
|
d.liste = liste
|
|
|
|
-- Abandon, Share, Track
|
|
local abandon = boutonPanneau(d, "ForeverUIQuestDetailsAbandonButton", ABANDON_QUEST_ABBREV, D.abandonL)
|
|
abandon:SetPoint("BOTTOMLEFT", d, "BOTTOMLEFT", D.boutonsX, D.boutonsY)
|
|
abandon:SetScript("OnClick", function()
|
|
if d.index then abandonner(d.index) end
|
|
end)
|
|
local partage = boutonPanneau(d, "ForeverUIQuestDetailsShareButton", SHARE_QUEST_ABBREV, D.partageL)
|
|
partage:SetPoint("LEFT", abandon, "RIGHT", 0, 0)
|
|
for i, cote in ipairs({ { "RIGHT", "LEFT", D.separateurX }, { "LEFT", "RIGHT", -D.separateurX } }) do
|
|
local s = partage:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(s, "ui-frame-btndivmiddle")
|
|
s:SetPoint(cote[1], partage, cote[2], cote[3], 0)
|
|
partage["separateur" .. i] = s
|
|
end
|
|
partage:SetScript("OnClick", function()
|
|
if d.index then partager(d.index) end
|
|
end)
|
|
local suivre = boutonPanneau(d, "ForeverUIQuestDetailsTrackButton", TRACK_QUEST_ABBREV, D.suivreL)
|
|
suivre:SetPoint("LEFT", partage, "RIGHT", 0, 0)
|
|
suivre:SetScript("OnClick", function()
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
if d.index then
|
|
basculerSuivi(d.index)
|
|
J.majBoutonsDetails()
|
|
J.maj()
|
|
end
|
|
end)
|
|
d.abandon, d.partage, d.suivre = abandon, partage, suivre
|
|
|
|
d:Hide()
|
|
return d
|
|
end
|
|
|
|
-- QuestMapFrame_UpdateQuestDetailsButtons, avec les regles de 3.3.5
|
|
-- (QuestLogControlPanel_UpdateState)
|
|
function J.majBoutonsDetails()
|
|
local d = J.details
|
|
if not d or not d.index then return end
|
|
-- QuestLog_SetSelection : la quete choisie est aussi celle qu'on
|
|
-- abandonnerait, et GetAbandonQuestName la nomme si c'est permis
|
|
SelectQuestLogEntry(d.index)
|
|
SetAbandonQuest()
|
|
d.abandon:Activer(GetAbandonQuestName() and true or false)
|
|
if IsQuestWatched(d.index) then
|
|
d.suivre:SetText(TEXTE.nePlusSuivreCourt)
|
|
else
|
|
d.suivre:SetText(TRACK_QUEST_ABBREV)
|
|
end
|
|
d.partage:Activer(GetQuestLogPushable() and enGroupe() and true or false)
|
|
end
|
|
|
|
-- QuestInfo_ShowRewards, pour ce que 3.3.5 donne. Rend la hauteur de la
|
|
-- liste, ou nil s'il n'y a rien a gagner.
|
|
local function afficherRecompenses(d)
|
|
local l = d.liste
|
|
for _, b in ipairs(l.objets) do b:Hide() end
|
|
for _, f in ipairs({ l.choisir, l.recevoir, l.titreJoueur, l.sort, l.xp, l.argent,
|
|
l.titre, l.honneur, l.arene, l.sortBouton }) do
|
|
f:ClearAllPoints()
|
|
f:Hide()
|
|
end
|
|
l.lignes, l.entetes = 0, 0
|
|
|
|
local nbObjets = GetNumQuestLogRewards() or 0
|
|
local nbChoix = GetNumQuestLogChoices() or 0
|
|
local argent = GetQuestLogRewardMoney() or 0
|
|
local xp = GetQuestLogRewardXP and GetQuestLogRewardXP() or 0
|
|
local honneur = GetQuestLogRewardHonor() or 0
|
|
local arene = GetQuestLogRewardArenaPoints and GetQuestLogRewardArenaPoints() or 0
|
|
local titreJoueur = GetQuestLogRewardTitle()
|
|
local sortIcone, sortNom, sortMetier, sortAppris = GetQuestLogRewardSpell()
|
|
if nbObjets + nbChoix == 0 and argent == 0 and xp == 0 and honneur == 0 and arene == 0
|
|
and not titreJoueur and not sortIcone then
|
|
return nil
|
|
end
|
|
|
|
-- l'agencement de camelot : deux elements par rangee, une section
|
|
-- repart a gauche, un en-tete occupe sa rangee a lui seul
|
|
local total = l.entete:GetHeight()
|
|
local ancre = l.entete
|
|
local nouvelleSection, unParRangee, droitePosee = true, false, false
|
|
local function section(large)
|
|
nouvelleSection = true
|
|
unParRangee = large and true or false
|
|
end
|
|
local function ajouter(f, h)
|
|
if not nouvelleSection and not droitePosee and not unParRangee then
|
|
f:SetPoint("TOPLEFT", ancre, "TOPRIGHT", D.recSeparation, 0)
|
|
droitePosee = true
|
|
else
|
|
local ecart = nouvelleSection and D.recSection or D.recRangee
|
|
f:SetPoint("TOPLEFT", ancre, "BOTTOMLEFT", 0, -ecart)
|
|
total = total + (h or f:GetHeight()) + ecart
|
|
ancre = f
|
|
droitePosee = false
|
|
nouvelleSection = false
|
|
l.lignes = l.lignes + 1
|
|
end
|
|
f:Show()
|
|
end
|
|
local function entete(f)
|
|
l.entetes = l.entetes + 1
|
|
section(true)
|
|
ajouter(f)
|
|
end
|
|
local n = 0
|
|
local function objet(type, i, lire)
|
|
n = n + 1
|
|
local b = l.objets[n]
|
|
if not b then
|
|
b = brancherRecompense(creerObjet(l, "ForeverUIQuestDetailsRewardItem" .. n))
|
|
l.objets[n] = b
|
|
end
|
|
local nom, icone, nombre, qualite, utilisable = lire(i)
|
|
b.type, b.objectType = type, "item"
|
|
b:SetID(i)
|
|
b.Name:SetText(nom)
|
|
b.Icon:SetTexture(icone)
|
|
nombreObjet(b, nombre)
|
|
-- BAG_ITEM_QUALITY_COLORS de camelot : commun en COMMON_GRAY_COLOR,
|
|
-- au-dessus la couleur de qualite, mediocre sans contour
|
|
local c = qualite and qualite >= 2 and ITEM_QUALITY_COLORS and ITEM_QUALITY_COLORS[qualite]
|
|
if qualite == 1 then
|
|
b.IconBorder:SetVertexColor(COULEUR.communGris[1], COULEUR.communGris[2], COULEUR.communGris[3])
|
|
b.IconBorder:Show()
|
|
elseif c then
|
|
b.IconBorder:SetVertexColor(c.r, c.g, c.b)
|
|
b.IconBorder:Show()
|
|
else
|
|
b.IconBorder:Hide()
|
|
end
|
|
if utilisable then
|
|
b.Icon:SetVertexColor(1, 1, 1)
|
|
b.NameFrame:SetVertexColor(1, 1, 1)
|
|
else
|
|
b.Icon:SetVertexColor(0.9, 0, 0)
|
|
b.NameFrame:SetVertexColor(0.9, 0, 0)
|
|
end
|
|
ajouter(b, D.objetH)
|
|
end
|
|
|
|
-- au choix
|
|
if nbChoix > 0 then
|
|
l.choisir:SetText(nbChoix == 1 and REWARD_ITEMS_ONLY or REWARD_CHOICES)
|
|
entete(l.choisir)
|
|
section()
|
|
for i = 1, nbChoix do
|
|
objet("choice", i, GetQuestLogChoiceInfo)
|
|
end
|
|
end
|
|
-- le sort : 3.3.5 n'en donne qu'un
|
|
if sortIcone then
|
|
l.sort:SetText((sortMetier and REWARD_TRADESKILL_SPELL) or (not sortAppris and REWARD_AURA) or REWARD_SPELL)
|
|
entete(l.sort)
|
|
section()
|
|
l.sortBouton.Icon:SetTexture(sortIcone)
|
|
l.sortBouton.Name:SetText(sortNom)
|
|
nombreObjet(l.sortBouton, 0)
|
|
ajouter(l.sortBouton, D.objetH)
|
|
end
|
|
-- le titre
|
|
if titreJoueur then
|
|
entete(l.titreJoueur)
|
|
l.titre.Name:SetText(titreJoueur)
|
|
nombreObjet(l.titre, 0)
|
|
section()
|
|
ajouter(l.titre, D.objetH)
|
|
end
|
|
-- ce qu'on recoit de toute facon
|
|
if nbObjets > 0 or argent > 0 or xp > 0 or honneur > 0 or arene > 0 then
|
|
l.recevoir:SetText((nbChoix > 0 or sortIcone or titreJoueur) and REWARD_ITEMS or REWARD_ITEMS_ONLY)
|
|
entete(l.recevoir)
|
|
section()
|
|
if xp > 0 then
|
|
l.xp.Name:SetText(xp)
|
|
nombreObjet(l.xp, 0)
|
|
ajouter(l.xp, D.objetH)
|
|
end
|
|
if argent > 0 then
|
|
l.argent.Name:SetText(GetMoneyString(argent))
|
|
nombreObjet(l.argent, 0)
|
|
ajouter(l.argent, D.objetH)
|
|
end
|
|
section()
|
|
for i = 1, nbObjets do
|
|
objet("reward", i, GetQuestLogRewardInfo)
|
|
end
|
|
if honneur > 0 then
|
|
local faction = UnitFactionGroup("player") == "Horde" and "horde" or "alliance"
|
|
l.honneur.Icon:SetTexture(ICONES.honneur .. faction)
|
|
l.honneur.Name:SetText(HONOR)
|
|
nombreObjet(l.honneur, honneur)
|
|
l.honneur.infobulle = HONOR_POINTS
|
|
section()
|
|
ajouter(l.honneur, D.objetH)
|
|
end
|
|
if arene > 0 then
|
|
l.arene.Name:SetText(ARENA_POINTS)
|
|
nombreObjet(l.arene, arene)
|
|
l.arene.infobulle = ARENA_POINTS
|
|
section()
|
|
ajouter(l.arene, D.objetH)
|
|
end
|
|
end
|
|
l:SetHeight(total)
|
|
return total
|
|
end
|
|
|
|
-- AdjustRewardsFrameContainer : si tout le texte tient, ou s'il n'y a qu'une
|
|
-- rangee, les recompenses se montrent en entier ; sinon elles grandissent a
|
|
-- mesure qu'on descend, sans passer sous 124.
|
|
function J.ajusterRecompenses()
|
|
local d = J.details
|
|
if not d then return end
|
|
local r = d.recompenses
|
|
local hauteur = r:GetHeight()
|
|
local plage = d.plage or 0
|
|
if plage == 0 or (d.liste.lignes - d.liste.entetes) <= 1 then
|
|
d.conteneur:SetHeight(hauteur)
|
|
return
|
|
end
|
|
local h = hauteur - (plage - (d.defile:GetVerticalScroll() or 0))
|
|
if h < D.recMin then h = D.recMin end
|
|
d.conteneur:SetHeight(h)
|
|
end
|
|
|
|
function J.defilerDetails(y)
|
|
local d = J.details
|
|
if not d then return end
|
|
d.defile:SetVerticalScroll(math.min(y, d.plage or 0))
|
|
J.ajusterRecompenses()
|
|
end
|
|
|
|
-- QuestInfo_Display(QUEST_TEMPLATE_MAP_DETAILS) puis (..._MAP_REWARDS) :
|
|
-- rend faux si la quete n'est plus au journal.
|
|
local function afficherDetails(debut)
|
|
local d = J.details
|
|
local index = indexDeQuete(d.questID)
|
|
if not index then
|
|
return false
|
|
end
|
|
d.index = index
|
|
SelectQuestLogEntry(index)
|
|
local info = entree(index)
|
|
local c = d.contenu
|
|
|
|
local dernier, total = nil, 0
|
|
local function poser(region, dx, dy, h, bas)
|
|
region:ClearAllPoints()
|
|
if dernier then
|
|
region:SetPoint("TOPLEFT", dernier, "BOTTOMLEFT", dx, dy)
|
|
else
|
|
region:SetPoint("TOPLEFT", c, "TOPLEFT", dx, dy)
|
|
end
|
|
region:Show()
|
|
dernier = bas or region
|
|
total = total - dy + (h or region:GetHeight() or 0)
|
|
end
|
|
|
|
-- le titre, l'echec en plus
|
|
local titre = info.title
|
|
if info.isComplete and info.isComplete < 0 then
|
|
titre = format(TEXTE.titreEchec, titre)
|
|
end
|
|
d.titre:SetText(titre)
|
|
poser(d.titre, 5, -10)
|
|
local description, objectifs = GetQuestLogQuestText()
|
|
d.texteObjectifs:SetText(objectifs)
|
|
poser(d.texteObjectifs, 0, -5)
|
|
|
|
-- le compte a rebours
|
|
local reste = GetQuestLogTimeLeft()
|
|
d.horloge.reste = reste
|
|
if reste then
|
|
d.minuteur:SetText(TIME_REMAINING .. " " .. SecondsToTime(reste))
|
|
poser(d.minuteur, 0, -10)
|
|
else
|
|
d.minuteur:Hide()
|
|
end
|
|
|
|
-- les objectifs : remplis, ils passent au gris et disent "(Complete)"
|
|
for _, o in ipairs(d.objectifs) do o:Hide() end
|
|
local vus = 0
|
|
for i = 1, GetNumQuestLeaderBoards() do
|
|
local texte, genre, fini = GetQuestLogLeaderBoard(i)
|
|
if genre ~= "spell" and genre ~= "log" then
|
|
vus = vus + 1
|
|
local o = d.objectifs[vus]
|
|
if not o then
|
|
o = d.nouvelObjectif()
|
|
d.objectifs[vus] = o
|
|
end
|
|
if not texte or texte == "" then texte = genre end
|
|
if fini then
|
|
couleur(o, COULEUR.objectifFait)
|
|
texte = texte .. " (" .. COMPLETE .. ")"
|
|
else
|
|
couleur(o, COULEUR.texte)
|
|
end
|
|
o:SetText(texte)
|
|
poser(o, 0, vus == 1 and -10 or -2)
|
|
end
|
|
end
|
|
|
|
-- l'argent demande : noir s'il en manque, gris sinon
|
|
local requis = GetQuestLogRequiredMoney() or 0
|
|
if requis > 0 then
|
|
MoneyFrame_Update(d.argent.bourse:GetName(), requis)
|
|
if requis > GetMoney() then
|
|
couleur(d.argent.texte, { 0, 0, 0 })
|
|
if SetMoneyFrameColor then SetMoneyFrameColor(d.argent.bourse:GetName(), "red") end
|
|
else
|
|
couleur(d.argent.texte, { 0.2, 0.2, 0.2 })
|
|
if SetMoneyFrameColor then SetMoneyFrameColor(d.argent.bourse:GetName(), "white") end
|
|
end
|
|
poser(d.argent, 0, 0, 28)
|
|
else
|
|
d.argent:Hide()
|
|
end
|
|
|
|
-- le groupe conseille
|
|
local groupe = GetQuestLogGroupNum() or 0
|
|
if groupe > 0 then
|
|
d.groupe:SetText(format(QUEST_SUGGESTED_GROUP_NUM, groupe))
|
|
poser(d.groupe, 0, -10)
|
|
else
|
|
d.groupe:Hide()
|
|
end
|
|
|
|
poser(d.enteteDescription, 0, -20)
|
|
d.description:SetText(description)
|
|
poser(d.description, 0, -5)
|
|
|
|
-- les recompenses (SetRewardsHeight) : leur hauteur, plus 62, ou 59
|
|
-- sans rien ; l'espace en bas du texte leur laisse la meme place
|
|
local liste = afficherRecompenses(d)
|
|
local hauteur
|
|
if liste then
|
|
d.liste:Show()
|
|
hauteur = liste + D.recEnPlus
|
|
else
|
|
d.liste:Hide()
|
|
hauteur = D.recSans
|
|
end
|
|
d.recompenses:SetHeight(hauteur)
|
|
poserFondRecompenses(d.recompenses, hauteur)
|
|
if d.liste.lignes - d.liste.entetes > 0 then
|
|
d.recompenses.libelle:Show()
|
|
else
|
|
d.recompenses.libelle:Hide()
|
|
end
|
|
d.espace:SetHeight(hauteur)
|
|
poser(d.espace, 0, 0, hauteur)
|
|
|
|
c:SetHeight(math.max(total, 1))
|
|
d.plage = math.max(0, total - D.texteH)
|
|
if d.barre then
|
|
local lignes = math.ceil(total / D.pas)
|
|
local visibles = math.floor(D.texteH / D.pas)
|
|
local decalage = debut and 0 or math.min(d.barre.decalage or 0, math.max(0, lignes - visibles))
|
|
d.barre:Regler(lignes, visibles, decalage)
|
|
d.defile:SetVerticalScroll(math.min(decalage * D.pas, d.plage))
|
|
else
|
|
d.defile:SetVerticalScroll(0)
|
|
end
|
|
J.ajusterRecompenses()
|
|
J.majBoutonsDetails()
|
|
return true
|
|
end
|
|
|
|
function J.detailsOuverts()
|
|
return J.details and J.details:IsShown() and true or false
|
|
end
|
|
|
|
-- QuestMapFrame_ShowQuestDetails : la carte passe sur la quete (en gardant
|
|
-- celle qu'on quitte), la liste s'efface, la page se montre.
|
|
function J.ouvrirDetails(info)
|
|
local d = J.details
|
|
if not d or not info or not info.questID then
|
|
montrerSurCarte(info)
|
|
return
|
|
end
|
|
d.retourCarte = GetCurrentMapAreaID and GetCurrentMapAreaID()
|
|
d.retourEtage = GetCurrentMapDungeonLevel and GetCurrentMapDungeonLevel()
|
|
d.carte = nil
|
|
d.questID = info.questID
|
|
montrerSurCarte(info)
|
|
d.carte = GetCurrentMapAreaID and GetCurrentMapAreaID()
|
|
StaticPopup_Hide("ABANDON_QUEST")
|
|
StaticPopup_Hide("ABANDON_QUEST_WITH_ITEMS")
|
|
-- montree AVANT d'etre remplie : les textes se mesurent visibles
|
|
J.volet.liste:Hide()
|
|
if J.volet.barre then J.volet.barre:Hide() end
|
|
d:Show()
|
|
if not afficherDetails(true) then
|
|
J.fermerDetails()
|
|
end
|
|
end
|
|
|
|
-- QuestMapFrame_CloseQuestDetails
|
|
function J.fermerDetails()
|
|
local d = J.details
|
|
if not d then return end
|
|
d:Hide()
|
|
d.questID, d.index, d.carte, d.retourCarte, d.retourEtage = nil, nil, nil, nil, nil
|
|
d.horloge.reste = nil
|
|
J.volet.liste:Show()
|
|
StaticPopup_Hide("ABANDON_QUEST")
|
|
StaticPopup_Hide("ABANDON_QUEST_WITH_ITEMS")
|
|
J.maj()
|
|
end
|
|
|
|
-- QuestMapFrame_ReturnFromQuestDetails : la carte revient ou elle etait
|
|
function J.revenirDeDetails()
|
|
local d = J.details
|
|
if not d then return end
|
|
local carte, etage = d.retourCarte, d.retourEtage
|
|
if carte and SetMapByID then
|
|
SetMapByID(carte)
|
|
if etage and etage > 0 and SetDungeonMapLevel then
|
|
SetDungeonMapLevel(etage)
|
|
end
|
|
end
|
|
J.fermerDetails()
|
|
end
|
|
|
|
-- QuestLogMixin:Refresh et QuestMapFrame_UpdateAll : la page suit le
|
|
-- journal ; une quete qui en sort ramene a la liste ; une carte qui n'est
|
|
-- plus celle de la quete referme la page.
|
|
function J.majDetails()
|
|
local d = J.details
|
|
if not J.detailsOuverts() then return end
|
|
if d.carte and GetCurrentMapAreaID and GetCurrentMapAreaID() ~= d.carte then
|
|
J.fermerDetails()
|
|
return
|
|
end
|
|
if not afficherDetails(false) then
|
|
J.revenirDeDetails()
|
|
end
|
|
end
|
|
|
|
-- ------------------------------------------------------------- le volet
|
|
|
|
local function creerVolet(carte)
|
|
local v = CreateFrame("Frame", "ForeverUIQuestLogPanel", carte)
|
|
v:SetFrameStrata("HIGH")
|
|
v:EnableMouse(true)
|
|
v:SetWidth(V.largeur)
|
|
v:SetPoint("TOPRIGHT", carte, "TOPRIGHT", V.x, V.haut)
|
|
v:SetPoint("BOTTOMRIGHT", carte, "BOTTOMRIGHT", V.x, V.bas)
|
|
|
|
-- QuestsFrame, puis QuestScrollFrame
|
|
local liste = CreateFrame("ScrollFrame", "ForeverUIQuestScrollFrame", v)
|
|
liste:SetPoint("TOPLEFT", v, "TOPLEFT", 0, V.listeHaut)
|
|
liste:SetPoint("BOTTOMRIGHT", v, "BOTTOMRIGHT", V.listeDroite, V.listeBas)
|
|
v.liste = liste
|
|
|
|
local fond = liste:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(fond, "questlog-main-background-2x")
|
|
fond:SetPoint("TOPLEFT", liste, "TOPLEFT", 0, 0)
|
|
v.fond = fond
|
|
|
|
local vide = liste:CreateFontString(nil, "ARTWORK")
|
|
vide:SetFont(POLICE, 16)
|
|
vide:SetWidth(250)
|
|
vide:SetPoint("CENTER", liste, "CENTER", 0, 50)
|
|
vide:SetText(TEXTE.vide)
|
|
vide:Hide()
|
|
v.vide = vide
|
|
local aucun = liste:CreateFontString(nil, "ARTWORK")
|
|
aucun:SetFont(POLICE, 14)
|
|
aucun:SetWidth(250)
|
|
aucun:SetPoint("TOP", liste, "TOP", 0, -30)
|
|
aucun:SetText(TEXTE.aucunResultat)
|
|
aucun:Hide()
|
|
v.aucun = aucun
|
|
|
|
local contenu = CreateFrame("Frame", "ForeverUIQuestScrollContents", liste)
|
|
contenu:SetWidth(304)
|
|
contenu:SetHeight(454)
|
|
liste:SetScrollChild(contenu)
|
|
v.contenu = contenu
|
|
|
|
-- le cadre : questlog-frame etire, le filigrane en haut, l'ombre en bas
|
|
local bord = CreateFrame("Frame", nil, liste)
|
|
bord:SetPoint("TOPLEFT", liste, "TOPLEFT", -3, 7)
|
|
bord:SetPoint("BOTTOMRIGHT", liste, "BOTTOMRIGHT", 3, -6)
|
|
v.bord = bord
|
|
bord:SetFrameLevel(liste:GetFrameLevel() + 20)
|
|
-- questlog-frame est DECOUPE EN NEUF par le moteur de camelot : ses marges
|
|
-- sont dans UiTextureAtlasElementSliceData.db2 du client camelot --
|
|
-- 53 / 53 / 53 / 53 pour un element de 107 x 107 (mode 1). Etire d'une
|
|
-- seule piece, il deformait ses moulures (constate le 2026-09-25).
|
|
if ForeverUI.CreateNineSlice then
|
|
ForeverUI.CreateNineSlice(bord, "questlog-frame", 53, { 0, 0, 0, 0 }, "BORDER")
|
|
end
|
|
local filigrane = bord:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(filigrane, "questlog-frame-filigree")
|
|
filigrane:SetPoint("TOP", bord, "TOP", 0, 1)
|
|
local ombre = bord:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(ombre, "questlog-frame-gradient-bottom")
|
|
ombre:SetPoint("BOTTOM", bord, "BOTTOM", 0, 4)
|
|
v.ombre = ombre
|
|
|
|
-- la barre de defilement, par pas de 16
|
|
local barre = ForeverUI.CreateScrollBar and ForeverUI.CreateScrollBar("ForeverUIQuestScrollBar", v, liste)
|
|
if barre then
|
|
barre:ClearAllPoints()
|
|
barre:SetPoint("TOPLEFT", liste, "TOPRIGHT", V.barreX, V.barreHaut)
|
|
barre:SetPoint("BOTTOMLEFT", liste, "BOTTOMRIGHT", V.barreX, V.barreBas)
|
|
barre:SetFrameLevel(bord:GetFrameLevel() + 1)
|
|
barre.surDefilement = function(pas)
|
|
liste:SetVerticalScroll(pas * V.pas)
|
|
J.majOmbre()
|
|
end
|
|
v.barre = barre
|
|
end
|
|
liste:EnableMouseWheel(true)
|
|
liste:SetScript("OnMouseWheel", function(_, sens)
|
|
if v.barre and v.barre:IsShown() then
|
|
v.barre:Deplacer(v.barre.decalage - sens * 3)
|
|
end
|
|
end)
|
|
|
|
-- la recherche (SearchBoxTemplate)
|
|
local r = CreateFrame("EditBox", "ForeverUIQuestSearchBox", liste)
|
|
r:SetWidth(V.rechercheL)
|
|
r:SetHeight(V.rechercheH)
|
|
r:SetPoint("BOTTOMLEFT", liste, "TOPLEFT", V.rechercheX, V.rechercheY)
|
|
r:SetAutoFocus(false)
|
|
r:SetMaxLetters(60)
|
|
r:SetFontObject("GameFontHighlightSmall")
|
|
r:SetTextInsets(16, 20, 0, 0)
|
|
local function bordure(parent, prefixe)
|
|
local g = parent:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(g, prefixe .. "-left", true)
|
|
g:SetWidth(8) g:SetHeight(20)
|
|
g:SetPoint("LEFT", parent, "LEFT", -5, 0)
|
|
local d = parent:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(d, prefixe .. "-right", true)
|
|
d:SetWidth(8) d:SetHeight(20)
|
|
d:SetPoint("RIGHT", parent, "RIGHT", 0, 0)
|
|
local m = parent:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(m, prefixe .. "-middle", true)
|
|
m:SetPoint("TOPLEFT", g, "TOPRIGHT")
|
|
m:SetPoint("BOTTOMRIGHT", d, "BOTTOMLEFT")
|
|
return g, m, d
|
|
end
|
|
bordure(r, "common-search-border")
|
|
local loupe = r:CreateTexture(nil, "OVERLAY")
|
|
ForeverUI.SetAtlas(loupe, "common-search-magnifyingglass", true)
|
|
loupe:SetWidth(10) loupe:SetHeight(10)
|
|
loupe:SetPoint("LEFT", r, "LEFT", 1, -1)
|
|
local consigne = r:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall")
|
|
consigne:SetPoint("TOPLEFT", r, "TOPLEFT", 16, 0)
|
|
consigne:SetPoint("BOTTOMRIGHT", r, "BOTTOMRIGHT", -20, 0)
|
|
consigne:SetJustifyH("LEFT")
|
|
consigne:SetTextColor(0.35, 0.35, 0.35)
|
|
consigne:SetText(TEXTE.recherche)
|
|
local effacer = CreateFrame("Button", nil, r)
|
|
effacer:SetWidth(17) effacer:SetHeight(17)
|
|
effacer:SetPoint("RIGHT", r, "RIGHT", -3, 0)
|
|
local croix = effacer:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(croix, "common-search-clearbutton", true)
|
|
croix:SetWidth(10) croix:SetHeight(10)
|
|
croix:SetPoint("CENTER", effacer, "CENTER", 0, 0)
|
|
croix:SetAlpha(0.5)
|
|
effacer:SetScript("OnEnter", function() croix:SetAlpha(1) end)
|
|
effacer:SetScript("OnLeave", function() croix:SetAlpha(0.5) end)
|
|
effacer:SetScript("OnClick", function()
|
|
r:SetText("")
|
|
r:ClearFocus()
|
|
end)
|
|
effacer:Hide()
|
|
r:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
|
r:SetScript("OnEnterPressed", function(self) self:ClearFocus() end)
|
|
r:SetScript("OnEditFocusGained", function() consigne:Hide() end)
|
|
r:SetScript("OnEditFocusLost", function(self)
|
|
if self:GetText() == "" then consigne:Show() end
|
|
end)
|
|
r:SetScript("OnTextChanged", function(self)
|
|
local t = self:GetText()
|
|
if t == "" then effacer:Hide() else effacer:Show() consigne:Hide() end
|
|
J.chercher(t)
|
|
end)
|
|
v.recherche = r
|
|
|
|
-- le compteur (InputBoxVisualTemplate)
|
|
local compteur = CreateFrame("Frame", "ForeverUIQuestLogCount", liste)
|
|
compteur:SetWidth(V.compteurL)
|
|
compteur:SetHeight(V.compteurH)
|
|
compteur:SetPoint("TOPLEFT", r, "TOPRIGHT", V.compteurX, 0)
|
|
local _, _, droite = bordure(compteur, "common-search-border")
|
|
local texteCompteur = compteur:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall")
|
|
texteCompteur:SetPoint("TOPRIGHT", droite, "TOPRIGHT", -5, -5)
|
|
compteur.texte = texteCompteur
|
|
-- LE COMPTEUR DE QUOTIDIENNES (WotLK seul, conserve par decision) : camelot
|
|
-- n'a pas de place pour lui ; il vit dans l'infobulle du compteur.
|
|
compteur:EnableMouse(true)
|
|
compteur:SetScript("OnEnter", function(self)
|
|
GameTooltip:SetOwner(self, "ANCHOR_BOTTOMRIGHT")
|
|
GameTooltip:SetText(format(QUEST_LOG_DAILY_COUNT_TEMPLATE, GetDailyQuestsCompleted(), GetMaxDailyQuests()))
|
|
if QUEST_LOG_DAILY_TOOLTIP then
|
|
GameTooltip:AddLine(format(QUEST_LOG_DAILY_TOOLTIP, GetMaxDailyQuests(), SecondsToTime(GetQuestResetTime(), nil, 1)), 1, 1, 1, true)
|
|
end
|
|
GameTooltip:Show()
|
|
end)
|
|
compteur:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
|
v.compteur = compteur
|
|
|
|
-- les reglages : une case, les objectifs
|
|
local reglage = CreateFrame("Button", "ForeverUIQuestSettingsButton", liste)
|
|
reglage:SetWidth(V.reglageL)
|
|
reglage:SetHeight(V.reglageH)
|
|
reglage:SetPoint("TOPRIGHT", liste, "TOPRIGHT", V.reglageX, V.reglageY)
|
|
local icone = reglage:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(icone, "questlog-icon-setting")
|
|
icone:SetPoint("CENTER", reglage, "CENTER", 0, 0)
|
|
local survol = reglage:CreateTexture(nil, "HIGHLIGHT")
|
|
ForeverUI.SetAtlas(survol, "questlog-icon-setting")
|
|
survol:SetPoint("CENTER", reglage, "CENTER", 0, 0)
|
|
survol:SetBlendMode("ADD")
|
|
survol:SetAlpha(0.4)
|
|
reglage:SetScript("OnMouseDown", function() icone:SetPoint("CENTER", reglage, "CENTER", 1, -1) end)
|
|
reglage:SetScript("OnMouseUp", function() icone:SetPoint("CENTER", reglage, "CENTER", 0, 0) end)
|
|
reglage:SetScript("OnClick", function(self)
|
|
menu(self, { {
|
|
text = TEXTE.montrerObjectifs,
|
|
checked = reglages().objectifs,
|
|
keepShownOnClick = 1,
|
|
func = function()
|
|
reglages().objectifs = not reglages().objectifs
|
|
J.maj()
|
|
end,
|
|
} })
|
|
end)
|
|
v.reglage = reglage
|
|
|
|
v.entetes, v.quetes, v.objectifs = {}, {}, {}
|
|
J.details = creerDetails(v)
|
|
v:Hide()
|
|
return v
|
|
end
|
|
|
|
-- --------------------------------------------------------------- les lignes
|
|
|
|
local function creerEntete(v, i)
|
|
local b = CreateFrame("Button", "ForeverUIQuestLogHeader" .. i, v.contenu)
|
|
b:SetWidth(V.enteteL)
|
|
b:SetHeight(V.enteteH)
|
|
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
local fondNom = ForeverUI.AtlasEntry("common-button-list-collapseexpand")
|
|
b:SetNormalTexture(fondNom[1])
|
|
ForeverUI.SetAtlas(b:GetNormalTexture(), "common-button-list-collapseexpand", true)
|
|
b:SetHighlightTexture(fondNom[1])
|
|
local s = b:GetHighlightTexture()
|
|
ForeverUI.SetAtlas(s, "common-button-list-collapseexpand", true)
|
|
s:SetBlendMode("ADD")
|
|
s:SetAlpha(0.4)
|
|
|
|
local plus = CreateFrame("Button", nil, b)
|
|
plus:SetWidth(20) plus:SetHeight(20)
|
|
plus:SetPoint("RIGHT", b, "RIGHT", -6, 0)
|
|
plus:EnableMouse(false)
|
|
plus.Icon = plus:CreateTexture(nil, "ARTWORK")
|
|
plus.Icon:SetPoint("CENTER", plus, "CENTER", 0, 0)
|
|
b.plus = plus
|
|
|
|
local texte = b:CreateFontString(nil, "OVERLAY")
|
|
texte:SetFont(POLICE, 15)
|
|
texte:SetShadowOffset(1, -1)
|
|
texte:SetShadowColor(0, 0, 0, 1)
|
|
texte:SetJustifyH("LEFT")
|
|
texte:SetPoint("LEFT", b, "LEFT", 8, 0)
|
|
texte:SetPoint("RIGHT", plus, "LEFT", -4, 0)
|
|
b.texte = texte
|
|
|
|
b:SetScript("OnEnter", function(self) couleur(self.texte, COULEUR.enteteSurvol) end)
|
|
b:SetScript("OnLeave", function(self) couleur(self.texte, COULEUR.enteteRepos) end)
|
|
b:SetScript("OnMouseDown", function(self)
|
|
self.texte:SetPoint("LEFT", self, "LEFT", 9, -1)
|
|
self.plus.Icon:SetPoint("CENTER", self.plus, "CENTER", 1, -1)
|
|
end)
|
|
b:SetScript("OnMouseUp", function(self)
|
|
self.texte:SetPoint("LEFT", self, "LEFT", 8, 0)
|
|
self.plus.Icon:SetPoint("CENTER", self.plus, "CENTER", 0, 0)
|
|
end)
|
|
b:SetScript("OnClick", function(self, bouton)
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
if bouton == "RightButton" then
|
|
local nom = self.info.title
|
|
menu(self, {
|
|
{ text = TEXTE.toutSuivre, func = function() suivreEntete(nom, true) end },
|
|
{ text = TEXTE.neRienSuivre, func = function() suivreEntete(nom, false) end },
|
|
})
|
|
elseif self.info.isCollapsed then
|
|
ExpandQuestHeader(self.info.index)
|
|
else
|
|
CollapseQuestHeader(self.info.index)
|
|
end
|
|
end)
|
|
return b
|
|
end
|
|
|
|
local function creerQuete(v, i)
|
|
local b = CreateFrame("Button", "ForeverUIQuestLogTitle" .. i, v.contenu)
|
|
b:SetWidth(V.queteL)
|
|
b:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
|
|
|
-- la case de suivi, 14 x 14, marges de souris -10
|
|
local case = CreateFrame("Button", nil, b)
|
|
case:SetWidth(V.caseCote) case:SetHeight(V.caseCote)
|
|
case:SetPoint("TOPRIGHT", b, "TOPRIGHT", 0, V.caseY)
|
|
case:SetHitRectInsets(-10, -10, -10, -10)
|
|
local carre = case:CreateTexture(nil, "BACKGROUND")
|
|
ForeverUI.SetAtlas(carre, "questlog-icon-ticksquare")
|
|
carre:SetPoint("CENTER", case, "CENTER", 0, 0)
|
|
local coche = case:CreateTexture(nil, "ARTWORK")
|
|
ForeverUI.SetAtlas(coche, "questlog-icon-checkmark-yellow")
|
|
coche:SetPoint("CENTER", case, "CENTER", 1, 1)
|
|
local survolCase = case:CreateTexture(nil, "HIGHLIGHT")
|
|
ForeverUI.SetAtlas(survolCase, "questlog-icon-ticksquare")
|
|
survolCase:SetPoint("CENTER", case, "CENTER", 0, 0)
|
|
survolCase:SetBlendMode("ADD")
|
|
survolCase:SetAlpha(0.4)
|
|
case:SetScript("OnClick", function()
|
|
PlaySound(IsQuestWatched(b.index) and "igMainMenuOptionCheckBoxOff" or "igMainMenuOptionCheckBoxOn")
|
|
basculerSuivi(b.index)
|
|
end)
|
|
b.case, b.coche = case, coche
|
|
|
|
-- la surbrillance, sous le texte (couche BORDER)
|
|
local lueur = b:CreateTexture(nil, "BORDER")
|
|
ForeverUI.SetAtlas(lueur, "questlog-quest-glow-yellow")
|
|
lueur:Hide()
|
|
b.lueur = lueur
|
|
|
|
local texte = b:CreateFontString(nil, "ARTWORK", "GameFontNormalLeft")
|
|
texte:SetPoint("TOPLEFT", b, "TOPLEFT", V.queteTexteX, V.queteTexteY)
|
|
texte:SetJustifyH("LEFT")
|
|
b.texte = texte
|
|
local tag = b:CreateFontString(nil, "ARTWORK", "GameFontNormalLeft")
|
|
tag:SetPoint("RIGHT", case, "LEFT", -4, 0)
|
|
tag:SetPoint("TOP", texte, "TOP", 0, 0)
|
|
tag:Hide()
|
|
b.tag = tag
|
|
lueur:SetPoint("TOP", texte, "TOP", 0, 4)
|
|
lueur:SetPoint("BOTTOM", texte, "BOTTOM", 0, -4)
|
|
|
|
b:SetScript("OnEnter", function(self)
|
|
local c = COULEUR.difficulteSurvol[self.difficulte]
|
|
couleur(self.texte, c)
|
|
couleur(self.tag, c)
|
|
for _, o in ipairs(self.lignesObjectif) do
|
|
couleur(o.texte, COULEUR.objectifSurvol)
|
|
couleur(o.tiret, COULEUR.objectifSurvol)
|
|
end
|
|
self.lueur:Show()
|
|
zone(self.info, true)
|
|
infobulle(self)
|
|
end)
|
|
b:SetScript("OnLeave", function(self)
|
|
local c = COULEUR.difficulte[self.difficulte]
|
|
couleur(self.texte, c)
|
|
couleur(self.tag, c)
|
|
for _, o in ipairs(self.lignesObjectif) do
|
|
couleur(o.texte, COULEUR.objectif)
|
|
couleur(o.tiret, COULEUR.objectif)
|
|
end
|
|
self.lueur:Hide()
|
|
zone(self.info, false)
|
|
GameTooltip:Hide()
|
|
end)
|
|
b:SetScript("OnMouseDown", function(self)
|
|
self.texte:SetPoint("TOPLEFT", self, "TOPLEFT", V.queteTexteX + 1, V.queteTexteY - 1)
|
|
end)
|
|
b:SetScript("OnMouseUp", function(self)
|
|
self.texte:SetPoint("TOPLEFT", self, "TOPLEFT", V.queteTexteX, V.queteTexteY)
|
|
end)
|
|
b:SetScript("OnClick", function(self, bouton)
|
|
if IsModifiedClick("CHATLINK") and ChatEdit_InsertLink and ChatEdit_InsertLink(GetQuestLink(self.index)) then
|
|
return
|
|
end
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
if IsShiftKeyDown() then
|
|
basculerSuivi(self.index)
|
|
elseif bouton == "RightButton" then
|
|
menuQuete(self)
|
|
else
|
|
J.ouvrirDetails(self.info)
|
|
end
|
|
end)
|
|
b.lignesObjectif = {}
|
|
return b
|
|
end
|
|
|
|
local function creerObjectif(v, i)
|
|
local o = CreateFrame("Frame", nil, v.contenu)
|
|
o:SetWidth(V.objectifL)
|
|
local tiret = o:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
|
|
tiret:SetPoint("TOPLEFT", o, "TOPLEFT", 0, 0)
|
|
tiret:SetHeight(16)
|
|
tiret:SetText(QUEST_DASH)
|
|
local texte = o:CreateFontString(nil, "ARTWORK", "GameFontHighlight")
|
|
texte:SetWidth(V.objectifTexteL)
|
|
texte:SetJustifyH("LEFT")
|
|
texte:SetJustifyV("TOP")
|
|
texte:SetPoint("TOPLEFT", tiret, "TOPRIGHT", 0, 0)
|
|
o.tiret, o.texte = tiret, texte
|
|
return o
|
|
end
|
|
|
|
local function prendre(v, liste, n, fabrique)
|
|
local f = liste[n]
|
|
if not f then
|
|
f = fabrique(v, n)
|
|
liste[n] = f
|
|
end
|
|
f:ClearAllPoints()
|
|
f:Show()
|
|
return f
|
|
end
|
|
|
|
-- QuestLogQuests_AddQuestButton, pour 3.3.5
|
|
local function remplirQuete(v, b, info, compte)
|
|
b.info, b.index = info, info.index
|
|
b.difficulte = cleDifficulte(info.level)
|
|
local c = COULEUR.difficulte[b.difficulte]
|
|
b.texte:SetText(titreQuete(info))
|
|
couleur(b.texte, c)
|
|
couleur(b.tag, c)
|
|
if estElite(info) then
|
|
b.tag:SetText(format(PARENS_TEMPLATE, ELITE))
|
|
b.tag:Show()
|
|
b.texte:SetPoint("RIGHT", b.tag, "LEFT", -4, 0)
|
|
else
|
|
b.tag:Hide()
|
|
b.texte:SetPoint("RIGHT", b.case, "LEFT", -4, 0)
|
|
end
|
|
if IsQuestWatched(info.index) then b.coche:Show() else b.coche:Hide() end
|
|
b.lueur:Hide()
|
|
|
|
local hauteur = 8 + b.texte:GetHeight()
|
|
for _, o in ipairs(b.lignesObjectif) do o:Hide() end
|
|
b.lignesObjectif = {}
|
|
local function objectif(texte, precedent)
|
|
compte.o = compte.o + 1
|
|
local o = prendre(v, v.objectifs, compte.o, creerObjectif)
|
|
o.texte:SetText(texte)
|
|
couleur(o.texte, COULEUR.objectif)
|
|
couleur(o.tiret, COULEUR.objectif)
|
|
local h = o.texte:GetHeight()
|
|
o:SetHeight(h)
|
|
if precedent then
|
|
o:SetPoint("TOPLEFT", precedent, "BOTTOMLEFT", 0, -2)
|
|
h = h + 2
|
|
else
|
|
o:SetPoint("TOPLEFT", b.texte, "BOTTOMLEFT", 0, -3)
|
|
h = h + 3
|
|
end
|
|
table.insert(b.lignesObjectif, o)
|
|
hauteur = hauteur + h
|
|
return o
|
|
end
|
|
|
|
if not reglages().objectifs then
|
|
hauteur = hauteur + 4
|
|
elseif info.isComplete and info.isComplete > 0 then
|
|
objectif(GetQuestLogCompletionText(info.index) or TEXTE.pret)
|
|
else
|
|
local precedent
|
|
for i = 1, GetNumQuestLeaderBoards(info.index) do
|
|
local texte, _, fini = GetQuestLogLeaderBoard(i, info.index)
|
|
if texte and not fini then
|
|
precedent = objectif(texte, precedent)
|
|
end
|
|
end
|
|
local requis = GetQuestLogRequiredMoney(info.index)
|
|
local argent = GetMoney()
|
|
if requis and requis > argent then
|
|
objectif(GetMoneyString(argent) .. " / " .. GetMoneyString(requis), precedent)
|
|
end
|
|
end
|
|
-- le repere : celui de la carte affichee, s'il y en a un. POIButton de
|
|
-- camelot : 20 x 20 a (6, -4) ; celui de WotLK fait 32 x 32 : on le centre
|
|
-- au meme endroit.
|
|
local r = compte.reperes and info.questID and compte.reperes[info.questID]
|
|
if r and QuestPOI_DisplayButton then
|
|
local poi = QuestPOI_DisplayButton(PARENT_REPERES, r[1], r[2], info.questID)
|
|
poi:ClearAllPoints()
|
|
poi:SetPoint("CENTER", b, "TOPLEFT", 6 + 10, -4 - 10)
|
|
poi:SetFrameLevel(b:GetFrameLevel() + 2)
|
|
poi.info = info
|
|
poi:SetScript("OnClick", function(self)
|
|
PlaySound("igMainMenuOptionCheckBoxOn")
|
|
montrerSurCarte(self.info)
|
|
end)
|
|
if queteSelectionnee() == info.questID and QuestPOI_SelectButton then
|
|
QuestPOI_SelectButton(poi)
|
|
end
|
|
end
|
|
-- la place du repere de quete (+6 dans la source)
|
|
hauteur = hauteur + 6
|
|
b:SetHeight(hauteur)
|
|
end
|
|
|
|
-- QuestLogQuests_Update : tout est reconstruit a chaque passage.
|
|
function J.maj()
|
|
local v = J.volet
|
|
if not v or not v:IsShown() then
|
|
return
|
|
end
|
|
for _, f in ipairs(v.entetes) do f:Hide() end
|
|
for _, f in ipairs(v.quetes) do f:Hide() end
|
|
for _, f in ipairs(v.objectifs) do f:Hide() end
|
|
|
|
local compte = { e = 0, q = 0, o = 0, reperes = reperesDeLaCarte() }
|
|
if QuestPOI_HideAllButtons then
|
|
QuestPOI_HideAllButtons(PARENT_REPERES)
|
|
end
|
|
local haut = 0
|
|
local precedent = nil -- "entete", "quete" ou nil
|
|
local enteteCourant = nil
|
|
local enteteAffiche = false
|
|
local enAttente = nil -- un en-tete qui attend sa premiere quete
|
|
|
|
local function poser(f, type, gauche)
|
|
local ecart
|
|
if type == "entete" then
|
|
ecart = (precedent == nil and ECART.enteteApresRien)
|
|
or (precedent == "entete" and ECART.enteteApresEntete)
|
|
or ECART.enteteApresQuete
|
|
else
|
|
ecart = (precedent == "entete" and ECART.queteApresEntete) or ECART.queteApresQuete
|
|
end
|
|
haut = haut + ecart
|
|
f:SetPoint("TOPLEFT", v.contenu, "TOPLEFT", gauche, -haut)
|
|
haut = haut + f:GetHeight()
|
|
precedent = type
|
|
end
|
|
|
|
local function poserEntete(info)
|
|
compte.e = compte.e + 1
|
|
local e = prendre(v, v.entetes, compte.e, creerEntete)
|
|
e.info = info
|
|
e.texte:SetText(info.title)
|
|
couleur(e.texte, COULEUR.enteteRepos)
|
|
ForeverUI.SetAtlas(e.plus.Icon, info.isCollapsed and "common-button-list-plus" or "common-button-list-minus")
|
|
poser(e, "entete", V.enteteX)
|
|
end
|
|
|
|
local numQuetes = 0
|
|
for i = 1, GetNumQuestLogEntries() do
|
|
local info = entree(i)
|
|
if info and info.isHeader then
|
|
enteteCourant = info
|
|
-- un en-tete replie cache ses quetes : on le montre tel quel ;
|
|
-- deplie, il attend une quete a montrer (QuestLogQuests_ShouldShowHeaderButton)
|
|
if info.isCollapsed and not R.texte then
|
|
poserEntete(info)
|
|
enAttente = nil
|
|
else
|
|
enAttente = info
|
|
end
|
|
elseif info then
|
|
numQuetes = numQuetes + 1
|
|
if correspond(info) then
|
|
if enAttente then
|
|
poserEntete(enAttente)
|
|
enAttente = nil
|
|
end
|
|
compte.q = compte.q + 1
|
|
local b = prendre(v, v.quetes, compte.q, creerQuete)
|
|
remplirQuete(v, b, info, compte)
|
|
poser(b, "quete", 0)
|
|
end
|
|
end
|
|
end
|
|
|
|
v.contenu:SetHeight(math.max(haut, 1))
|
|
|
|
-- le fond : vide, ou normal ; rogne a la hauteur du cadre
|
|
local rien = (compte.q == 0 and compte.e == 0)
|
|
-- En double densite : sur l'ecran de l'utilisateur (echelle 0,64 en
|
|
-- 3840 x 1600), la variante 1x etait agrandie et se voyait pixelisee.
|
|
local atlas = (rien and not R.texte) and "questlog-empty-quest-background-2x" or "questlog-main-background-2x"
|
|
ForeverUI.SetAtlas(v.fond, atlas)
|
|
local e = ForeverUI.AtlasEntry(atlas)
|
|
local hFrame = v.liste:GetHeight() or 0
|
|
if e and hFrame > 0 and hFrame < e[7] then
|
|
v.fond:SetHeight(hFrame)
|
|
v.fond:SetTexCoord(e[2], e[3], e[4], e[4] + (e[5] - e[4]) * hFrame / e[7])
|
|
end
|
|
if rien and not R.texte then v.vide:Show() else v.vide:Hide() end
|
|
if rien and R.texte then v.aucun:Show() else v.aucun:Hide() end
|
|
if rien and not R.texte then
|
|
v.recherche:EnableMouse(false)
|
|
else
|
|
v.recherche:EnableMouse(true)
|
|
end
|
|
|
|
-- le compteur de camelot, avec le maximum de WotLK
|
|
local _, quetes = GetNumQuestLogEntries()
|
|
quetes = quetes or numQuetes
|
|
local rouge = quetes > MAX_QUESTLOG_QUESTS
|
|
v.compteur.texte:SetText(format(TEXTE.compteur, rouge and RED_FONT_COLOR_CODE or "|cffffffff", quetes, MAX_QUESTLOG_QUESTS))
|
|
|
|
-- la barre
|
|
if v.barre then
|
|
local total = math.ceil(haut / V.pas)
|
|
local visibles = math.floor(hFrame / V.pas)
|
|
local decalage = math.min(v.barre.decalage or 0, math.max(0, total - visibles))
|
|
v.barre:Regler(total, visibles, decalage)
|
|
v.liste:SetVerticalScroll(decalage * V.pas)
|
|
end
|
|
-- LE CADRE ET LE FOND SUIVENT LA BARRE (demande du 2026-09-25) : barre
|
|
-- masquee, ils s'etendent sur les 22 de sa place, jusqu'au bord du volet
|
|
-- -- le bord droit du cadre deborde alors de 3, en miroir de son bord
|
|
-- gauche ; barre montree, ils gardent la taille de camelot.
|
|
local place = (v.barre and v.barre:IsShown()) and 0 or -V.listeDroite
|
|
v.bord:ClearAllPoints()
|
|
v.bord:SetPoint("TOPLEFT", v.liste, "TOPLEFT", -3, 7)
|
|
v.bord:SetPoint("BOTTOMRIGHT", v.liste, "BOTTOMRIGHT", 3 + place, -6)
|
|
if e then
|
|
v.fond:SetWidth(e[6] + place)
|
|
end
|
|
J.majOmbre()
|
|
-- la page d'une quete est ouverte : la liste reste cachee, sa barre aussi
|
|
if J.detailsOuverts() and v.barre then
|
|
v.barre:Hide()
|
|
end
|
|
end
|
|
|
|
-- l'ombre du bas s'efface a mesure qu'on approche de la fin
|
|
function J.majOmbre()
|
|
local v = J.volet
|
|
if not v then return end
|
|
local plage = math.max(0, v.contenu:GetHeight() - (v.liste:GetHeight() or 0))
|
|
local defile = v.liste:GetVerticalScroll() or 0
|
|
local h = v.ombre:GetHeight() or 1
|
|
local alpha = (plage - defile) / (h > 0 and h or 1)
|
|
if alpha < 0 then alpha = 0 elseif alpha > 1 then alpha = 1 end
|
|
v.ombre:SetAlpha(alpha)
|
|
end
|
|
|
|
-- ------------------------------------------------------ montrer, cacher
|
|
|
|
function J.estOuvert()
|
|
return J.volet and J.volet:IsShown()
|
|
end
|
|
|
|
-- Appele par WorldMap.lua quand il pose la petite fenetre : le volet suit
|
|
-- l'etat retenu (questLogOpen).
|
|
function J.poser()
|
|
local v = J.volet
|
|
if not v then return end
|
|
-- fils de WorldMapFrame, qui est a l'echelle de la carte : l'inverse le
|
|
-- ramene a l'unite de l'interface
|
|
v:SetScale(ForeverUI.WorldMap and ForeverUI.WorldMap.inverse or 1)
|
|
if reglages().volet then v:Show() else v:Hide() end
|
|
J.maj()
|
|
end
|
|
|
|
function J.cacher()
|
|
if J.volet then J.volet:Hide() end
|
|
end
|
|
|
|
-- HandleUserActionToggleSidePanel
|
|
function J.basculerVolet()
|
|
reglages().volet = not reglages().volet
|
|
if ForeverUI.WorldMap and ForeverUI.WorldMap.poserReduit then
|
|
ForeverUI.WorldMap.poserReduit()
|
|
end
|
|
end
|
|
|
|
-- L : HandleUserActionToggleQuestLog. Carte ouverte avec le volet -> on la
|
|
-- ferme ; sinon on l'ouvre en petite fenetre, volet ouvert. WotLK garde son
|
|
-- mode de taille d'une ouverture a l'autre ; en plein ecran, on repasse en
|
|
-- petite fenetre par sa propre fonction.
|
|
function J.basculerJournal()
|
|
if WorldMapFrame:IsShown() and J.estOuvert() then
|
|
HideUIPanel(WorldMapFrame)
|
|
return
|
|
end
|
|
-- Montrer QuestLogFrame a pu fermer la carte avant nous : en mode
|
|
-- deplacable elle est un panneau "center" qui cede sa place
|
|
-- (UIParent.lua:1355). Fermee dans cette meme image avec son volet, c'est
|
|
-- que L voulait la fermer.
|
|
if J.fermeeA and J.fermeeA == GetTime() and J.fermeeAvecVolet then
|
|
J.fermeeA = nil
|
|
return
|
|
end
|
|
reglages().volet = true
|
|
if WORLDMAP_SETTINGS.size ~= WORLDMAP_WINDOWED_SIZE then
|
|
if WorldMapFrame:IsShown() then
|
|
WorldMapFrame_ToggleWindowSize()
|
|
return
|
|
end
|
|
WorldMap_ToggleSizeDown()
|
|
end
|
|
if WorldMapFrame:IsShown() then
|
|
if ForeverUI.WorldMap and ForeverUI.WorldMap.poserReduit then
|
|
ForeverUI.WorldMap.poserReduit()
|
|
end
|
|
else
|
|
ShowUIPanel(WorldMapFrame)
|
|
end
|
|
end
|
|
|
|
-- QuestMapFrame_OpenToQuestDetails, appele par le suivi de quetes : la carte
|
|
-- en petite fenetre, le volet ouvert, puis la page de la quete.
|
|
function J.ouvrirPage(index)
|
|
local info = entree(index)
|
|
if not info or info.isHeader then
|
|
return
|
|
end
|
|
reglages().volet = true
|
|
if WORLDMAP_SETTINGS.size ~= WORLDMAP_WINDOWED_SIZE then
|
|
if WorldMapFrame:IsShown() then
|
|
WorldMapFrame_ToggleWindowSize()
|
|
else
|
|
WorldMap_ToggleSizeDown()
|
|
end
|
|
end
|
|
if WorldMapFrame:IsShown() then
|
|
if ForeverUI.WorldMap and ForeverUI.WorldMap.poserReduit then
|
|
ForeverUI.WorldMap.poserReduit()
|
|
end
|
|
else
|
|
ShowUIPanel(WorldMapFrame)
|
|
end
|
|
J.ouvrirDetails(info)
|
|
end
|
|
|
|
-- -------------------------------------------------------------- l'assemblage
|
|
|
|
local function construire()
|
|
if J.volet or not WorldMapFrame then
|
|
return J.volet
|
|
end
|
|
J.volet = creerVolet(WorldMapFrame)
|
|
return J.volet
|
|
end
|
|
J.construire = construire
|
|
|
|
-- QuestLogFrame reste en place, invisible (decision 3) : ses fonctions et son
|
|
-- OnShow marchent pour les addons, mais le montrer ouvre le volet. Le greffon
|
|
-- passe APRES ShowUIPanel : on le referme dans la meme image, il n'est jamais
|
|
-- dessine.
|
|
if hooksecurefunc then
|
|
hooksecurefunc("ShowUIPanel", function(cadre)
|
|
if cadre and cadre == QuestLogFrame and QuestLogFrame:IsShown() then
|
|
HideUIPanel(QuestLogFrame)
|
|
J.basculerJournal()
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- A l'entree en jeu, camelot deplie la zone ou l'on est et replie les autres
|
|
-- (QuestMapFrame_ResetFilters). 3.3.5 ne dit pas quel en-tete est "sur la
|
|
-- carte" : c'est celui qui porte le nom de la zone.
|
|
local function replierSelonZone()
|
|
local zone = GetRealZoneText and GetRealZoneText()
|
|
if not zone or zone == "" then
|
|
return
|
|
end
|
|
for i = GetNumQuestLogEntries(), 1, -1 do
|
|
local info = entree(i)
|
|
if info and info.isHeader then
|
|
if info.title == zone then
|
|
if info.isCollapsed then ExpandQuestHeader(i) end
|
|
elseif not info.isCollapsed then
|
|
CollapseQuestHeader(i)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
J.replierSelonZone = replierSelonZone
|
|
|
|
-- WotLK refait ses reperes a chaque changement de carte ou de quete : la liste
|
|
-- reprend leurs numeros.
|
|
if hooksecurefunc and WorldMapFrame_UpdateQuests then
|
|
hooksecurefunc("WorldMapFrame_UpdateQuests", function()
|
|
if J.estOuvert() then
|
|
J.maj()
|
|
J.majDetails()
|
|
end
|
|
end)
|
|
end
|
|
|
|
if WorldMapFrame and WorldMapFrame.HookScript then
|
|
WorldMapFrame:HookScript("OnHide", function()
|
|
J.fermeeA = GetTime()
|
|
J.fermeeAvecVolet = J.estOuvert() and true or false
|
|
end)
|
|
end
|
|
|
|
local veilleur = CreateFrame("Frame")
|
|
veilleur:RegisterEvent("QUEST_LOG_UPDATE")
|
|
veilleur:RegisterEvent("UNIT_QUEST_LOG_CHANGED")
|
|
veilleur:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
|
veilleur:RegisterEvent("QUEST_WATCH_UPDATE")
|
|
veilleur:RegisterEvent("PLAYER_ENTERING_WORLD")
|
|
veilleur:SetScript("OnEvent", function(_, evenement)
|
|
if evenement == "PLAYER_ENTERING_WORLD" then
|
|
if not J.dejaReplie then
|
|
J.dejaReplie = true
|
|
replierSelonZone()
|
|
end
|
|
end
|
|
if J.estOuvert() then
|
|
J.maj()
|
|
J.majDetails()
|
|
end
|
|
end)
|
|
|
|
construire()
|
|
|
|
ForeverUI.QuestLogDebug = function()
|
|
local v = J.volet
|
|
local prefixe = "|cff66ccffForeverUI|r "
|
|
if not v then
|
|
DEFAULT_CHAT_FRAME:AddMessage(prefixe .. L.QUESTLOG_DEBUG_NOT_BUILT)
|
|
return
|
|
end
|
|
local entetes, quetes = 0, 0
|
|
for _, f in ipairs(v.entetes) do if f:IsShown() then entetes = entetes + 1 end end
|
|
for _, f in ipairs(v.quetes) do if f:IsShown() then quetes = quetes + 1 end end
|
|
DEFAULT_CHAT_FRAME:AddMessage(prefixe .. string.format(
|
|
L.QUESTLOG_DEBUG_STATE,
|
|
v:IsShown() and L.QUESTLOG_DEBUG_OPEN or L.QUESTLOG_DEBUG_CLOSED, v:GetWidth(), v:GetHeight(), entetes, quetes,
|
|
tostring(R.texte), tostring(reglages().objectifs)))
|
|
end
|