0.1.159: Brett-Brief ueber den Freewood-Briefkasten (sichtbar, Auto-Senden), dynamisches Sendetempo, Betreff so breit wie Text

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016onJCSHLwhs9udhC9ZLzk9
This commit is contained in:
Claude
2026-10-28 23:33:28 +01:00
parent faf347129d
commit 396e446875
4 changed files with 156 additions and 7 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
## Notes: Own mailbox window: open all or selected mails safely, recent recipients, mailing lists with automatic sending, multi-item mails, gold surplus and cash on delivery.
## Notes-deDE: Eigenes Briefkasten-Fenster: alles oder Ausgewähltes sicher öffnen, letzte Empfänger, Mailinglisten mit Automatik, mehrere Items, Gold-Überschuss und Nachnahme.
## Author: Lacustat
## Version: 0.1.158
## Version: 0.1.159
## Dependencies: Freewood-OctoWoW-Core
## OptionalDeps: Freewood-OctoWoW-Creator, Freewood-OctoWoW-Brett
+20
View File
@@ -56,6 +56,16 @@ FW:AddLocale("enUS", {
MAIL_SEND_COD_NEEDS_ITEM = "Cash on delivery needs at least one item.",
MAIL_BOARD_BUSY = "A board mission is preparing a mail. Finish it in the mission window first; this window waits.",
MAIL_BUSY = "Another action is running. Please wait.",
MAIL_BOARD_TITLE = "Board mission letter",
MAIL_BOARD_FILLING = "The letter is being prepared ...",
MAIL_BOARD_READY_AUTO = "Everything is correct. The letter is sent automatically.",
MAIL_BOARD_READY_MANUAL = "Everything is correct. Click \"Send now\".",
MAIL_BOARD_LOCKED = "The letter was changed and is locked. Close the mailbox and open it again.",
MAIL_BOARD_SEND = "Send now",
MAIL_BOARD_ADD = "Add what is missing",
MAIL_BOARD_SENT = "Board letter sent.",
MAIL_SPEED_ADAPT = "Mailbox: the server is slowing down, the sending speed was adapted.",
MAIL_SET_BOARDAUTO = "Send board mission letters automatically once everything is correct",
MAIL_PICK_TITLE = "Choose items",
MAIL_PICK_LIST_TITLE = "Items for %s",
@@ -196,6 +206,16 @@ FW:AddLocale("deDE", {
MAIL_SEND_COD_NEEDS_ITEM = "Nachnahme braucht mindestens ein Item.",
MAIL_BOARD_BUSY = "Ein Brett-Auftrag bereitet gerade einen Brief vor. Erst im Auftragsfenster abschließen; dieses Fenster wartet.",
MAIL_BUSY = "Es läuft gerade eine andere Aktion. Bitte warten.",
MAIL_BOARD_TITLE = "Brief für einen Brett-Auftrag",
MAIL_BOARD_FILLING = "Der Brief wird vorbereitet ...",
MAIL_BOARD_READY_AUTO = "Alles stimmt. Der Brief wird automatisch gesendet.",
MAIL_BOARD_READY_MANUAL = "Alles stimmt. Klicke auf \"Jetzt senden\".",
MAIL_BOARD_LOCKED = "Der Brief wurde verändert und ist gesperrt. Briefkasten schließen und neu öffnen.",
MAIL_BOARD_SEND = "Jetzt senden",
MAIL_BOARD_ADD = "Fehlendes ergänzen",
MAIL_BOARD_SENT = "Brett-Brief gesendet.",
MAIL_SPEED_ADAPT = "Briefkasten: Der Server bremst, das Sendetempo wurde angepasst.",
MAIL_SET_BOARDAUTO = "Brett-Auftragsbriefe automatisch senden, sobald alles stimmt",
MAIL_PICK_TITLE = "Items auswählen",
MAIL_PICK_LIST_TITLE = "Items für %s",
+73 -4
View File
@@ -29,7 +29,10 @@ local MAX_JOBS = 120
local STEP = 0.1 -- Takt des Treibers
local INBOX_GAP = 0.5 -- Pause nach dem Nehmen
local INBOX_TIMEOUT = 2.5 -- so lange auf die Antwort des Servers warten
local SEND_GAP = 1.2 -- Pause nach jedem gesendeten Brief
local GAP_START = 0.4 -- Pause nach jedem gesendeten Brief: Start, wird dynamisch angepasst
local GAP_MIN = 0.25
local GAP_MAX = 4
local MAX_RETRY = 3 -- so oft wird ein vom Server abgelehnter Brief mit langsamerem Tempo wiederholt
local SEND_TIMEOUT = 8
local POSTAGE = 30 -- Kupfer je Brief (Schaetzung fuer den Gold-Ueberschuss)
local AUTO_DELAY = 2.5
@@ -51,7 +54,7 @@ local Mail = FW:NewModule("Mail", {
title = L.MAIL_TITLE,
description = L.MAIL_DESC,
defaults = {
settings = { replace = false, chat = true, cleanup = true, archiveDays = 0 },
settings = { replace = false, chat = true, cleanup = true, archiveDays = 0, boardAuto = true },
recipients = {},
lists = {},
archive = {}, -- entfernte Briefe, neueste zuerst
@@ -64,6 +67,7 @@ FW.Mail = Mail
Mail.open = false -- ein Briefkasten ist offen
Mail.busy = nil -- nil | "inbox" | "send"
Mail.gen = 0 -- zaehlt die Briefkasten-Oeffnungen
Mail.gap = GAP_START -- aktuelle Pause zwischen zwei Briefen (so klein wie moeglich, waechst bei Ablehnung)
local function Now() return GetTime and GetTime() or 0 end
local function After(t, fn)
@@ -360,6 +364,46 @@ function Mail:RemoveMail(m)
return true, own and "own" or "archived"
end
-- Brett-Brief: Ein Brett-Auftrag bereitet einen Brief vor (Creator befuellt das verdeckte Briefformular).
-- Mit ersetztem Briefkasten zeigt unser Fenster den Stand und sendet selbst, sobald alles stimmt.
function Mail.BoardLetter()
local C = FW.Creator
if not (C and C.GuardState and C.MailCheck) then return nil end
local ok, st = pcall(C.GuardState)
if not ok or not st or st == "off" then return nil end
local ok2, list, all = pcall(C.MailCheck)
if not ok2 then list, all = nil, false end
return { state = st, list = list or {}, all = all and true or false }
end
function Mail:BoardSend()
local bl = Mail.BoardLetter()
if not bl or bl.state ~= "armed" or not bl.all then return false end
local b = _G.SendMailMailButton
if not (b and b.Click) then return false end
if b.IsEnabled and not b:IsEnabled() then return false end
self.boardSending = true
Trace("Brett-Brief: Senden ueber den Freewood-Briefkasten")
pcall(b.Click, b)
return true
end
-- Automatisch senden, wenn alles stimmt (Einstellung "boardAuto"), hoechstens 3 Versuche je Oeffnung
function Mail:BoardAuto()
if not (self.open and self.Replacing() and self.db.settings.boardAuto) then return end
if self.boardAutoAt or (self.boardTries or 0) >= 3 then return end
local bl = Mail.BoardLetter()
if not bl or bl.state ~= "armed" or not bl.all then return end
self.boardAutoAt = true
After(0.8, function()
Mail.boardAutoAt = nil
if Mail.open and Mail.Replacing() then
Mail.boardTries = (Mail.boardTries or 0) + 1
Mail:BoardSend()
end
end)
end
-- Brief an den Absender zurueckschicken (Anhang und Gold gehen mit zurueck). Nicht moeglich bei System-/Auktionsbriefen.
function Mail.Returnable(m)
if not m or not m.canReply or m.returned then return false end
@@ -647,9 +691,24 @@ function Mail:StepSend()
if Mail.BoardBusy() then return self:FinishSend("board") end
if s.stage == "wait" then
if s.ok then
s.stage, s.nextAt = "next", now + SEND_GAP
-- Erfolg: Tempo langsam wieder erhoehen (Pause kleiner), solange der Server mitkommt
s.streak = (s.streak or 0) + 1
if s.streak >= 3 then s.streak = 0 Mail.gap = math.max(GAP_MIN, Mail.gap * 0.8) end
s.retry = 0
s.stage, s.nextAt = "next", now + Mail.gap
elseif s.err then
return self:FinishSend("error")
-- Der Server hat den Brief abgelehnt (meist zu schnell): Pause verdoppeln und denselben Brief nochmal versuchen
s.retry = (s.retry or 0) + 1
if s.retry > MAX_RETRY then return self:FinishSend("error") end
s.streak = 0
Mail.gap = math.min(GAP_MAX, Mail.gap * 2 + 0.3)
Trace(string.format("Server lehnt ab: Pause jetzt %.2f s, Versuch %d von %d fuer Brief %d", Mail.gap, s.retry, MAX_RETRY, s.i))
if not s.slowSaid then s.slowSaid = true Say(FW.L.MAIL_SPEED_ADAPT) end
pcall(ClearCursor)
ClearAttachment()
s.i = s.i - 1
s.err, s.stage, s.nextAt = false, "next", now + Mail.gap + 0.5
return
elseif now > s.deadline then
return self:FinishSend("timeout")
end
@@ -881,6 +940,7 @@ function Mail:OnMailShow()
pcall(self.Purge, self)
self.open = true
self.gen = self.gen + 1
self.boardTries, self.boardAutoAt, self.boardSending = 0, nil, nil
self.selected = {}
self:ApplyReplace()
Trace("Briefkasten geoeffnet")
@@ -904,6 +964,13 @@ function Mail:OnInboxUpdate()
end
function Mail:OnSendSuccess()
if self.boardSending then
self.boardSending = nil
local C = FW.Creator
if C then C.mailChoice = nil end -- Brett-Brief ist raus: unser Fenster ist wieder frei
Say(FW.L.MAIL_BOARD_SENT)
FW:Fire("MAIL_STATE")
end
local s = self.send
if self.lastTo then
self:AddRecipient(self.lastTo)
@@ -946,6 +1013,7 @@ function Mail:OnEnable()
FW:RegisterEvent("MAIL_INBOX_UPDATE", function() pcall(Mail.OnInboxUpdate, Mail) end, self)
FW:RegisterEvent("MAIL_SEND_SUCCESS", function() pcall(Mail.OnSendSuccess, Mail) end, self)
FW:RegisterEvent("MAIL_FAILED", function() pcall(Mail.OnSendFailed, Mail) end, self)
FW:On("CREATOR_MAIL_UPDATE", function() pcall(Mail.BoardAuto, Mail) end, self)
if not self.hooked then
self.hooked = true
-- Empfaenger merken, egal wer sendet (auch das normale Fenster und Brett-Auftraege)
@@ -974,6 +1042,7 @@ function Mail:OnDisable()
for _, ev in ipairs({ "MAIL_SHOW", "MAIL_CLOSED", "MAIL_INBOX_UPDATE", "MAIL_SEND_SUCCESS", "MAIL_FAILED" }) do
FW:UnregisterEvent(ev, self)
end
pcall(FW.Off, FW, "CREATOR_MAIL_UPDATE", self)
if self.driver then self.driver:Hide() end
self.run, self.send, self.busy = nil, nil, nil
if self.hidden then
+62 -2
View File
@@ -606,7 +606,7 @@ local function BuildSend(parent)
dd:SetPoint("LEFT", toBox, "RIGHT", 8, 0)
Heading(f, T("MAIL_SUBJECT"), 0, -54)
local subjBox = MakeEdit(f, 628, nil, 64)
local subjBox = MakeEdit(f, 616, nil, 64) -- genauso breit wie das Textfeld (dessen Rollbalken nimmt 12 ab)
subjBox:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -74)
Heading(f, T("MAIL_BODY"), 0, -108)
@@ -642,6 +642,57 @@ local function BuildSend(parent)
local send = UI.CreateButton(f, T("MAIL_SEND"), 150, 30, nil, "primary")
send:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
-- Brett-Brief: sichtbare Vorbereitung im eigenen Fenster (verdeckt das Formular, solange der Auftrag den Brief fuellt)
local bl = UI.CreatePanel(f, "bgDeep", "gold")
bl:SetPoint("TOPLEFT", f, "TOPLEFT", -8, 8)
bl:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 8, -8)
bl:SetFrameLevel(f:GetFrameLevel() + 30)
bl:EnableMouse(true)
bl:Hide()
local blTitle = UI.CreateLabel(bl, T("MAIL_BOARD_TITLE"), { font = "heading", size = 15, color = "goldLight" })
blTitle:SetPoint("TOPLEFT", bl, "TOPLEFT", 16, -14)
bl.lines = {}
for i = 1, 6 do
local l = UI.CreateLabel(bl, "", { size = 12 })
l:SetPoint("TOPLEFT", bl, "TOPLEFT", 16, -48 - (i - 1) * 24)
l:SetPoint("TOPRIGHT", bl, "TOPRIGHT", -16, -48 - (i - 1) * 24)
l:SetWordWrap(false)
bl.lines[i] = l
end
bl.status = UI.CreateLabel(bl, "", { size = 12, color = "goldLight", justifyV = "TOP" })
bl.status:SetPoint("TOPLEFT", bl, "TOPLEFT", 16, -208)
bl.status:SetPoint("TOPRIGHT", bl, "TOPRIGHT", -16, -208)
bl.status:SetHeight(48)
bl.status:SetWordWrap(true)
bl.add = UI.CreateButton(bl, T("MAIL_BOARD_ADD"), 180, 28, function()
if FW.Creator and FW.Creator.MailAdd then pcall(FW.Creator.MailAdd) end
if f.Refresh then f.Refresh() end
end, "default")
bl.add:SetPoint("BOTTOMLEFT", bl, "BOTTOMLEFT", 16, 16)
bl.now = UI.CreateButton(bl, T("MAIL_BOARD_SEND"), 160, 28, function()
Mail:BoardSend()
if f.Refresh then f.Refresh() end
end, "primary")
bl.now:SetPoint("BOTTOMRIGHT", bl, "BOTTOMRIGHT", -16, 16)
local function BoardRefresh()
local b = Mail.BoardLetter()
if not b then bl:Hide() return false end
bl:Show()
for i, l in ipairs(bl.lines) do
local c = b.list[i]
l:SetText(c and ((c.ok and "|cff6cc070[x] " or "|cffff7060[ ] ") .. c.text .. "|r") or "")
end
local auto = Mail.db.settings.boardAuto
if b.state == "locked" then bl.status:SetText("|cffff7060" .. T("MAIL_BOARD_LOCKED") .. "|r")
elseif b.state == "armed" then bl.status:SetText(auto and T("MAIL_BOARD_READY_AUTO") or T("MAIL_BOARD_READY_MANUAL"))
else bl.status:SetText(T("MAIL_BOARD_FILLING")) end
bl.now:SetShown(b.state == "armed" and b.all)
bl.add:SetShown(b.state == "filling" and not b.all)
Mail:BoardAuto()
return true
end
local function Copper()
return (tonumber(goldBox.edit:GetText()) or 0) * 10000 + (tonumber(silverBox.edit:GetText()) or 0) * 100 + (tonumber(copperBox.edit:GetText()) or 0)
end
@@ -662,6 +713,7 @@ local function BuildSend(parent)
end
function f.Refresh()
if BoardRefresh() then return end
for i, pk in ipairs(picks) do local pk, i = pk, i
local row = rows[i]
if not row then
@@ -1065,6 +1117,7 @@ local function HideWindow()
end
FW:On("MAIL_WINDOW_SHOW", function() ShowWindow() end, OWNER)
FW:On("CREATOR_MAIL_PREPARING", function() if window and window:IsShown() then SelectTab("send") end end, OWNER)
FW:On("MAIL_WINDOW_HIDE", function() HideWindow() end, OWNER)
FW:On("MAIL_STATE", function() RefreshCurrent() end, OWNER)
FW:On("MAIL_INBOX_CHANGED", function() RefreshCurrent() end, OWNER)
@@ -1078,7 +1131,7 @@ FW:On("MAIL_LISTS_CHANGED", function() RefreshCurrent() if picker and picker:IsS
if UI.RegisterSettingsSection then
UI:RegisterSettingsSection("mail", {
order = 118,
height = 190,
height = 220,
build = function(parent)
local f, stack = UI.CreateSection(parent, T("MAIL_SET_HEADER"))
local boxes = {}
@@ -1096,6 +1149,13 @@ if UI.RegisterSettingsSection then
end)
stack:Add(chat, { fit = true, gap = 4 })
boxes[#boxes + 1] = chat
local boardAuto = UI.CreateCheckbox(f, T("MAIL_SET_BOARDAUTO"), function()
return Mail.db.settings.boardAuto
end, function(value)
Mail.db.settings.boardAuto = value and true or false
end)
stack:Add(boardAuto, { fit = true, gap = 4 })
boxes[#boxes + 1] = boardAuto
local cleanup = UI.CreateCheckbox(f, T("MAIL_SET_CLEANUP"), function()
return Mail.db.settings.cleanup
end, function(value)