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
+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