local tasksWindow local tasksTopButton local tasksOpcode = 243 local actualTasks = {} local completedTasks = {} local taskPoints = 0 local dailyTasksData = { rotationTime = 0, tasks = {}, ids = {} } local function getDailyStateById(taskId) if not taskId then return nil end for _, state in ipairs(dailyTasksData.tasks or {}) do if state.id == taskId then return state end end return nil end local lastFocusedTaskWidget = nil dofile("tasks_db.lua") dofile("daily_task_overrides.lua") local function normalizeTaskRepeatableFlags() for _, task in pairs(tasks_db or {}) do if task then local diff = task.difficulty or 0 if (diff >= 1 and diff <= 5) or diff == 7 or diff == 8 then task.norepeatable = false end end end end local function applyServerRewardUpdates(updates) if type(updates) ~= "table" then return end for _, update in ipairs(updates) do local taskId = tonumber(update.id) if taskId and tasks_db[taskId] and type(update.rewards) == "table" then tasks_db[taskId].rewards = update.rewards end end end local function applyServerTasks(serverTasks) if type(serverTasks) ~= "table" then return end local updatedTasks = {} for _, task in ipairs(serverTasks) do local taskId = tonumber(task.id) if taskId then updatedTasks[taskId] = task end end if next(updatedTasks) then tasks_db = updatedTasks normalizeTaskRepeatableFlags() end end normalizeTaskRepeatableFlags() local DAILY_REROLL_DEFAULT_COST = 5 local function deepCopyTable(value) if type(value) ~= "table" then return value end local result = {} for key, nested in pairs(value) do result[key] = deepCopyTable(nested) end return result end local function applyClientDailyOverrides(state) if not state or not state.id then return end local taskId = tonumber(state.id) if not taskId then return end local override = dailyTaskClientOverrides and dailyTaskClientOverrides[taskId] local taskInfo = tasks_db and tasks_db[taskId] if override and override.killsRequired ~= nil then state.killsRequired = override.killsRequired end local rewardsSource if override and override.rewards then rewardsSource = override.rewards elseif taskInfo and taskInfo.rewards then rewardsSource = taskInfo.rewards end if rewardsSource then local copiedRewards = deepCopyTable(rewardsSource) state.rewards = copiedRewards if state.base then state.base.rewards = deepCopyTable(rewardsSource) end end if override and override.rerollCost ~= nil then state.rerollCost = override.rerollCost end if not state.rerollCost then state.rerollCost = override and override.rerollCost or DAILY_REROLL_DEFAULT_COST end state.id = taskId end local taskRepeatLimits = { normal = 3, boss = 2, special = 2 } local repeatStorageKey = 'game_tasks_repeat_counts' local taskRepeatCounts = g_settings.getNode(repeatStorageKey) or {} local function safeToString(value) if value == nil then return "nil" end return tostring(value) end local function saveTaskRepeatCounts() g_settings.setNode(repeatStorageKey, taskRepeatCounts) g_settings.save() end local function resetTaskRepeatCounts() taskRepeatCounts = {} saveTaskRepeatCounts() end local function getTaskCategory(task) if not task then return 'normal' end local diff = task.difficulty or 0 if diff == 1 then return 'hunt1' elseif diff >= 2 and diff <= 5 then return 'normal' elseif diff == 7 then return 'boss' elseif diff == 8 then return 'special' else return 'normal' end end local function getTaskRepeatLimit(task) if not task then return taskRepeatLimits.normal end local diff = task.difficulty or 0 -- Tasks de dificuldade 1 podem ser repetidas apenas 1 vez if diff == 1 then return 1 end return taskRepeatLimits[getTaskCategory(task)] end local function getTaskRepeatCount(index) return taskRepeatCounts[tostring(index)] or 0 end local function setTaskRepeatCount(index, value) taskRepeatCounts[tostring(index)] = value saveTaskRepeatCounts() end local function incrementTaskRepeatCount(index) setTaskRepeatCount(index, getTaskRepeatCount(index) + 1) end local function formatTime(seconds) local hours = math.floor(seconds / 3600) local minutes = math.floor((seconds % 3600) / 60) local secs = seconds % 60 return string.format("%02dh%02dm%02ds", hours, minutes, secs) end local function formatExpValue(value) value = value or 0 if value >= 1000000000000 then return string.format("%.1fT", value / 1000000000000) elseif value >= 1000000000 then return string.format("%.1fB", value / 1000000000) elseif value >= 1000000 then return string.format("%.1fM", value / 1000000) elseif value >= 1000 then return string.format("%.1fK", value / 1000) end return tostring(value) end local function extractRewardInfo(rewards) local points, exp for _, reward in ipairs(rewards or {}) do if reward.type == "points" and reward.value then points = reward.value[1] elseif reward.type == "exp" and reward.value then exp = reward.value[1] end end return points, exp end local function getRewardItemClientId(itemData) if type(itemData) ~= "table" then return tonumber(itemData) or 0 end local serverId = tonumber(itemData.id or itemData[1] or itemData["1"]) or 0 return tonumber(itemData.displayId or itemData.displayid or itemData.clientId or itemData.clientid or itemData[3] or itemData["3"] or (taskRewardClientIds and taskRewardClientIds[serverId]) or serverId) or serverId end local function getRewardItemCount(itemData) if type(itemData) ~= "table" then return 1 end return tonumber(itemData.count or itemData[2] or itemData["2"]) or 1 end local function isDailyTaskId(taskId) for _, id in ipairs(dailyTasksData.ids or {}) do if id == taskId then return true end end return false end local function shouldDisplayTask(task, selectedFilter) if not selectedFilter then return true end if selectedFilter == 6 then return false elseif selectedFilter == 7 then return getTaskCategory(task) == 'boss' elseif selectedFilter == 8 then return getTaskCategory(task) == 'special' else return task.difficulty == selectedFilter end end local function setupWindows(window) local resetsPanel = window.resetsPanel.resetsFilter resetsPanel:getChildByIndex(1):setOn(true) for _, child in pairs(resetsPanel:getChildren()) do child.onClick = function(self) if self:isOn() then self:setOn(false) else self:setOn(true) end local childs = resetsPanel:getChildren() table.remove(childs, resetsPanel:getChildIndex(self)) for _, button in pairs(childs) do button:setOn(false) end displayTasks(tasksWindow.Monsters.monsterList) end end window.onVisibilityChange = function(self, visible) if visible then local data = { action = "Open" } g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode(data)) displayTasks(tasksWindow.Monsters.monsterList) end end end function toggle() if tasksWindow:isVisible() then tasksWindow:hide() else tasksWindow:show() tasksWindow:raise() tasksWindow:focus() end end function getDifficultySelected() for _, child in pairs(tasksWindow.resetsPanel.resetsFilter:getChildren()) do if child:isOn() then return tasksWindow.resetsPanel.resetsFilter:getChildIndex(child) end end return nil end function readjustButtonByFocus(window) local focused = window:getFocusedChild() if focused then lastFocusedTaskWidget = focused end local startButton = tasksWindow.bottomPanel.startTask local rerollButton = tasksWindow.bottomPanel.rerollTask local teleportButton = tasksWindow.bottomPanel.teleportTask if rerollButton then rerollButton:hide() rerollButton:setEnabled(false) end if not (focused and focused.taskName) then startButton:setText("Start") startButton:setColor("#00FF00") if teleportButton then teleportButton:hide() end return end if focused.isDaily then local state = focused.dailyState if not state then return end if state.isStarted then if state.isCompleted then startButton:setText("Withdraw") startButton:setColor("yellow") startButton:setEnabled(true) else startButton:setText("Cancel") startButton:setColor("red") startButton:setEnabled(true) end else if state.canStart then startButton:setText("Start") startButton:setColor("green") startButton:setEnabled(true) else startButton:setText("Cooldown") startButton:setColor("gray") startButton:setEnabled(false) end end if teleportButton then if state.canTeleport then teleportButton:show() else teleportButton:hide() end end if rerollButton then local rerollCost = state.rerollCost or DAILY_REROLL_DEFAULT_COST -- esconde se já usou o reroll ou se não tem repetição disponível if state.repeatCount and state.repeatCount > 1 then rerollButton:hide() else local hasCompletedOnce = (state.repeatCount and state.repeatCount > 0) or state.isCompleted if hasCompletedOnce then local hasPoints = taskPoints >= rerollCost local enabled = state.canReroll and hasPoints rerollButton:setText(string.format("Reroll for %d t.p.", rerollCost)) rerollButton:setColor(enabled and "#dcffff" or "#888888") rerollButton:setEnabled(enabled) rerollButton.onClick = function() rerollTask() end rerollButton:show() else rerollButton:hide() end end end return end -- Usar originalName se existir, caso contrário usar o texto do taskName (removendo tags HTML) local taskName = focused.originalName if not taskName then taskName = focused.taskName:getText() -- Remover tags HTML se houver taskName = taskName:gsub("<[^>]+>", "") taskName = taskName:gsub("%[Daily%]%s*", "") -- Remover prefixo [Daily] se houver taskName = taskName:match("^%s*(.-)%s*$") -- Trim whitespace end local taskIndex = getTaskIndexByName(taskName) local taskInfo = tasks_db[taskIndex] local limitReached = false if taskInfo then local limit = getTaskRepeatLimit(taskInfo) if limit and limit > 0 and getTaskRepeatCount(taskIndex) >= limit then limitReached = true end end if table.find(actualTasks, taskIndex) and not table.find(completedTasks, taskIndex) then startButton:setText("Cancel") startButton:setColor("red") startButton:setEnabled(true) elseif table.find(completedTasks, taskIndex) then startButton:setText("Withdraw") startButton:setColor("yellow") startButton:setEnabled(true) else if limitReached then startButton:setText("Limit reached") startButton:setColor("gray") startButton:setEnabled(false) else startButton:setText("Start") startButton:setColor("green") startButton:setEnabled(true) end end if teleportButton then if taskInfo and taskInfo.canTeleport then teleportButton:show() else teleportButton:hide() end end end function teleportToTask() local focused = tasksWindow.Monsters.monsterList:getFocusedChild() if not focused or not focused.taskName then return end if focused.isDaily then local state = focused.dailyState if not state or not state.canTeleport then return end local data = { action = "teleport", name = state.name } g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode(data)) return end -- Usar originalName se existir, caso contrário usar o texto do taskName (removendo tags HTML) local taskName = focused.originalName if not taskName then taskName = focused.taskName:getText() -- Remover tags HTML se houver taskName = taskName:gsub("<[^>]+>", "") taskName = taskName:gsub("%[Daily%]%s*", "") -- Remover prefixo [Daily] se houver taskName = taskName:match("^%s*(.-)%s*$") -- Trim whitespace end local taskIndex = getTaskIndexByName(taskName) if not taskIndex or not tasks_db[taskIndex] or not tasks_db[taskIndex].canTeleport then return end local data = { action = "teleport", name = taskName } g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode(data)) end local function displayDailyTasks(window) local prevFocused = window:getFocusedChild() local prevDailyId = nil local prevDailyName = nil if prevFocused and prevFocused.isDaily and prevFocused.dailyState then prevDailyId = prevFocused.dailyState.id prevDailyName = prevFocused.dailyState.name elseif prevFocused and prevFocused.taskName then prevDailyName = prevFocused.taskName:getText() end window:destroyChildren() local tasksList = dailyTasksData.tasks or {} if #tasksList == 0 then local emptyLabel = g_ui.createWidget("MonsterPanel", window) emptyLabel:setEnabled(false) emptyLabel.taskName:setText(tr("No daily tasks available.")) emptyLabel.taskDone:setVisible(false) emptyLabel.count:setVisible(false) emptyLabel.taskPointsRW:setVisible(false) emptyLabel.expReward:setVisible(false) emptyLabel.rewardsLabel:setVisible(false) emptyLabel.rewardsPanel:setVisible(false) emptyLabel.dailyTimer:setVisible(false) readjustButtonByFocus(window) return end local firstChild = nil local focusTarget = nil for _, state in ipairs(tasksList) do local taskLabel = g_ui.createWidget("MonsterPanel", window) if not firstChild then firstChild = taskLabel end taskLabel.isDaily = true taskLabel.dailyState = state taskLabel.taskName:setText(state.name, false) taskLabel.taskDone:setVisible(false) taskLabel.taskName:setVisible(true) taskLabel.taskName:setMarginTop(10) if state.type then taskLabel.creatureType:setOutfit({ type = state.type }) end local killsRequired = state.killsRequired or 0 local playerKills = state.playerKills or state.currentKills or 0 taskLabel.count:setText(string.format("Kills: %d", killsRequired)) local pointsReward, expReward = extractRewardInfo(state.rewards) taskLabel.taskPointsRW:setText("Task Points: " .. (pointsReward and tostring(pointsReward) or "--")) if expReward and expReward > 0 then taskLabel.expReward:setVisible(true) taskLabel.expReward:setText(tr("EXP: %s", formatExpValue(expReward))) else taskLabel.expReward:setVisible(false) end taskLabel.rewardsPanel.rewardsList:destroyChildren() for _, reward in ipairs(state.rewards or {}) do if reward.type == "item" then for _, itemData in ipairs(reward.value or {}) do local item = g_ui.createWidget("RewardItem", taskLabel.rewardsPanel.rewardsList) item:setItemId(getRewardItemClientId(itemData)) item:setItemCount(1) item.itemCount:setText(getRewardItemCount(itemData) .. "x") end end end local cooldown = state.cooldown or 0 local rotation = state.rotation or dailyTasksData.rotationTime or 0 if cooldown > 0 then taskLabel.dailyTimer:setText(tr("Cooldown: %s", formatTime(cooldown))) taskLabel.dailyTimer:setVisible(true) local timerValue = cooldown taskLabel.dailyScheduleEvent = cycleEvent(function() if timerValue > 0 then timerValue = timerValue - 1 if timerValue > 0 then taskLabel.dailyTimer:setText(tr("Cooldown: %s", formatTime(timerValue))) else taskLabel.dailyTimer:setText(tr("Rotation: %s", formatTime(rotation))) taskLabel.dailyTimer:setVisible(rotation > 0) removeEvent(taskLabel.dailyScheduleEvent) end end end, 1000) elseif rotation > 0 then taskLabel.dailyTimer:setText(tr("Rotation: %s", formatTime(rotation))) taskLabel.dailyTimer:setVisible(true) local timerValue = rotation taskLabel.dailyScheduleEvent = cycleEvent(function() if timerValue > 0 then timerValue = timerValue - 1 if timerValue > 0 then taskLabel.dailyTimer:setText(tr("Rotation: %s", formatTime(timerValue))) else taskLabel.dailyTimer:setVisible(false) removeEvent(taskLabel.dailyScheduleEvent) end end end, 1000) else taskLabel.dailyTimer:setVisible(false) end if state.isCompleted then taskLabel.background:setBackgroundColor("#225522") taskLabel.background:setOpacity(0.4) taskLabel.taskName:setColor("#FFA500") elseif state.isStarted then taskLabel.background:setBackgroundColor("#002200") taskLabel.background:setOpacity(0.1) taskLabel.taskName:setColor("green") else taskLabel.background:setBackgroundColor("alpha") taskLabel.background:setOpacity(0.1) taskLabel.taskName:setColor("white") end local tooltipLines = {} tooltipLines[#tooltipLines + 1] = tr("Monsters Available:") for _, creatureName in ipairs(state.creatures or {}) do tooltipLines[#tooltipLines + 1] = " - " .. creatureName end tooltipLines[#tooltipLines + 1] = "" tooltipLines[#tooltipLines + 1] = tr("Kills Required: %d", killsRequired) tooltipLines[#tooltipLines + 1] = tr("Kills Progress: %d/%d", math.min(playerKills, killsRequired), killsRequired) if pointsReward then tooltipLines[#tooltipLines + 1] = tr("Task Points Reward: %d", pointsReward) end if expReward and expReward > 0 then tooltipLines[#tooltipLines + 1] = tr("EXP Reward: %s", tostring(expReward)) end if state.rerollCost then tooltipLines[#tooltipLines + 1] = tr("Reroll Cost: %d points", state.rerollCost) end if rotation > 0 then tooltipLines[#tooltipLines + 1] = tr("Next rotation in:") .. " " .. formatTime(rotation) end taskLabel.taskName:setTooltip(table.concat(tooltipLines, "\n")) if not focusTarget then if prevDailyId and state.id == prevDailyId then focusTarget = taskLabel elseif not prevDailyId and prevDailyName and state.name == prevDailyName then focusTarget = taskLabel end end end if focusTarget then focusTarget:focus() elseif firstChild then firstChild:focus() end readjustButtonByFocus(window) window.onChildFocusChange = function(self, focused) if focused and focused.taskName then readjustButtonByFocus(window) end end -- Forçar atualização imediata das cores após renderizar scheduleEvent(function() readjustButtonByFocus(window) end, 50) end function displayTasks(window) for _, child in ipairs(window:getChildren()) do if child.dailyScheduleEvent then removeEvent(child.dailyScheduleEvent) end end window:destroyChildren() local selectedDifficulty = getDifficultySelected() if selectedDifficulty == 6 then displayDailyTasks(window) return end for _, task in ipairs(tasks_db) do if shouldDisplayTask(task, selectedDifficulty) then local taskLabel = g_ui.createWidget("MonsterPanel", window) taskLabel.isDaily = false taskLabel.originalName = task.raceName taskLabel.creatureType:setOutfit({ type = task.type }) local taskIndex = getTaskIndexByName(task.raceName) local isDailyActive = taskIndex and isDailyTaskId(taskIndex) local dailyState = isDailyActive and getDailyStateById(taskIndex) or nil local limit = getTaskRepeatLimit(task) local repeats = taskIndex and getTaskRepeatCount(taskIndex) or 0 if limit and limit > 0 then taskLabel.taskDone:setText(string.format("Task Done: %d/%d", math.min(repeats, limit), limit)) else taskLabel.taskDone:setText("Task Done: --") end local displayKills = task.killsRequired taskLabel.count:setText("Kills: " .. displayKills) taskLabel.creatureType:setTooltip("Monsters Avaiable: \n" .. table.concat(task.creatures, "\n")) local effectiveRewards = task.rewards local points local expReward = nil if effectiveRewards then for _, reward in ipairs(effectiveRewards) do if reward.type == "points" and reward.value then points = reward.value[1] elseif reward.type == "exp" and reward.value then expReward = reward.value[1] end end end taskLabel.dailyTimer:setVisible(false) -- Task daily: adicionar prefixo [Daily] ao nome na mesma linha local isStarted = taskIndex and table.find(actualTasks, taskIndex) if isDailyActive then local displayName = "[Daily] " .. task.raceName taskLabel.taskName:setText(displayName, false) if isStarted then taskLabel.taskName:setColor("#00FF00") else taskLabel.taskName:setColor("#FF6666") end else taskLabel.taskName:setText(task.raceName, false) if isStarted then taskLabel.taskName:setColor("#00FF00") else taskLabel.taskName:setColor("#FFFFFF") end end if taskIndex and table.find(completedTasks, taskIndex) then taskLabel.background:setBackgroundColor("#004000") taskLabel.background:setOpacity(0.4) else taskLabel.background:setBackgroundColor("alpha") taskLabel.background:setOpacity(0.1) end taskLabel.rewardsPanel.rewardsList:destroyChildren() taskLabel.taskPointsRW:setText("Task Points: " .. (points and tostring(points) or "--")) if effectiveRewards then for _, reward in ipairs(effectiveRewards) do if reward.type == "item" and reward.value then for _, itemData in ipairs(reward.value) do local item = g_ui.createWidget("RewardItem", taskLabel.rewardsPanel.rewardsList) item:setItemId(getRewardItemClientId(itemData)) item:setItemCount(1) item.itemCount:setText(getRewardItemCount(itemData) .. "x") end end end end if expReward and expReward > 0 then taskLabel.expReward:setVisible(true) taskLabel.expReward:setText(tr("EXP: %s", formatExpValue(expReward))) else taskLabel.expReward:setVisible(false) end end end readjustButtonByFocus(window) window.onChildFocusChange = function(self, focused) if focused and focused.taskName then readjustButtonByFocus(window) end end end function getTaskIndexByName(name) for _, task in pairs(tasks_db) do if task.raceName:lower() == name:lower() then return _ end end return nil end local function showCancelConfirmation(taskName, confirmCallback) local cancelDialog cancelDialog = displayGeneralBox(tr("Cancel Task"), tr("Are you sure you want to cancel the task %s? Your progress will be lost.", taskName or "?"), { { text = tr("Yes"), callback = function() if confirmCallback then confirmCallback() end if cancelDialog then cancelDialog:destroy() cancelDialog = nil end end }, { text = tr("No"), callback = function() if cancelDialog then cancelDialog:destroy() cancelDialog = nil end end } }) end function task_sender() local focusedTask = tasksWindow.Monsters.monsterList:getFocusedChild() if focusedTask then local startButton = tasksWindow and tasksWindow.bottomPanel and tasksWindow.bottomPanel.startTask local currentLabel = startButton and startButton:getText() or "Start" if focusedTask.isDaily then local state = focusedTask.dailyState if state then local action if currentLabel == "Start" then action = "startDaily" elseif currentLabel == "Cancel" then action = "cancelDaily" elseif currentLabel == "Withdraw" then action = "completeDaily" end if action then if action == "cancelDaily" then showCancelConfirmation(state.name, function() g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode({ action = action, name = state.name })) end) else g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode({ action = action, name = state.name })) end end end else -- Usar originalName se existir, caso contrário usar o texto do taskName (removendo tags HTML) local t_name = focusedTask.originalName if not t_name then t_name = focusedTask.taskName:getText() -- Remover tags HTML se houver t_name = t_name:gsub("<[^>]+>", "") t_name = t_name:gsub("%[Daily%]%s*", "") -- Remover prefixo [Daily] se houver t_name = t_name:match("^%s*(.-)%s*$") -- Trim whitespace end local t_index = getTaskIndexByName(t_name) if t_name and t_index then if currentLabel == "Cancel" then showCancelConfirmation(t_name, function() g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode({ action = "cancel", name = t_name })) end) elseif currentLabel == "Withdraw" then g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode({ action = "complete", name = t_name })) else local info = tasks_db[t_index] local difficulty = info and info.difficulty or 0 if difficulty >= 1 and difficulty <= 5 then local normalActive = 0 for _, activeIndex in ipairs(actualTasks) do local activeInfo = tasks_db[activeIndex] if activeInfo and activeInfo.difficulty >= 1 and activeInfo.difficulty <= 5 then normalActive = normalActive + 1 end end if normalActive >= 3 then local defaultTab = modules.game_console and modules.game_console.defaultTab local tabName = (defaultTab and defaultTab:getText()) or tr('Default') modules.game_console.addText("You already have 3 normal tasks active.", modules.game_console.SpeakTypesSettings.privatePlayerToPlayer, tabName) return end end local limit = getTaskRepeatLimit(info) if limit and limit > 0 and getTaskRepeatCount(t_index) >= limit then local defaultTab = modules.game_console and modules.game_console.defaultTab local tabName = (defaultTab and defaultTab:getText()) or tr('Default') modules.game_console.addText("You have reached the repeat limit for this task.", modules.game_console.SpeakTypesSettings.privatePlayerToPlayer, tabName) return end g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode({ action = "start", name = t_name })) end end end end end function readjustTaskPoints(p) return tasksWindow.bottomPanel.taskPoints:setText("Task Points: " .. p) end function rerollTask() print("[rerollTask] function called") if not tasksWindow or not tasksWindow.Monsters then print("[rerollTask] no tasksWindow") return end local focused = tasksWindow.Monsters.monsterList:getFocusedChild() if not focused or not focused.taskName then focused = lastFocusedTaskWidget end if not focused or not focused.taskName or not focused.isDaily then print(string.format("[rerollTask] no valid focused task focused=%s isDaily=%s", safeToString(focused), safeToString(focused and focused.isDaily))) return end local state = focused.dailyState if not state then print("[rerollTask] no dailyState") return end print(string.format("[rerollTask] click name=%s canReroll=%s repeat=%s points=%d", safeToString(state.name), safeToString(state.canReroll), safeToString(state.repeatCount), taskPoints)) if not state.canReroll then local defaultTab = modules.game_console and modules.game_console.defaultTab local tabName = (defaultTab and defaultTab:getText()) or tr('Default') modules.game_console.addText("You cannot reroll this daily task right now.", modules.game_console.SpeakTypesSettings.privatePlayerToPlayer, tabName) return end local rerollCost = state.rerollCost or DAILY_REROLL_DEFAULT_COST if taskPoints < rerollCost then local defaultTab = modules.game_console and modules.game_console.defaultTab local tabName = (defaultTab and defaultTab:getText()) or tr('Default') modules.game_console.addText("You do not have enough task points to reroll this task.", modules.game_console.SpeakTypesSettings.privatePlayerToPlayer, tabName) return end local function sendReroll() local data = { action = "reroll", name = state.name, cost = rerollCost } g_game.getProtocolGame():sendExtendedOpcode(tasksOpcode, json.encode(data)) end local rerollDialog rerollDialog = displayGeneralBox(tr("Reroll Daily Task"), tr("Do you want to spend %d task points to reroll %s?", rerollCost, state.name), { { text = tr("Yes"), callback = function() print("[rerollTask] confirming reroll") sendReroll() if rerollDialog then rerollDialog:destroy() rerollDialog = nil end end }, { text = tr("No"), callback = function() if rerollDialog then rerollDialog:destroy() rerollDialog = nil end end } }) end function init() if g_ui.getRootWidget():getChildById("TasksWindow") then g_ui.getRootWidget():getChildById("TasksWindow"):destroy() end tasksWindow = g_ui.loadUI('tasks', g_ui.getRootWidget()) tasksWindow:setId("TasksWindow") setupWindows(tasksWindow) displayTasks(tasksWindow.Monsters.monsterList) readjustButtonByFocus(tasksWindow.Monsters.monsterList) readjustTaskPoints(taskPoints) if tasksWindow.bottomPanel and tasksWindow.bottomPanel.rerollTask then tasksWindow.bottomPanel.rerollTask:hide() tasksWindow.bottomPanel.rerollTask:setEnabled(false) end if not tasksTopButton then tasksTopButton = modules.client_topmenu.addRightGameToggleButton('tasksButton', tr('Tasks'), '/images/topbuttons/tasks', toggle, false, 6) end ProtocolGame.registerExtendedOpcode(243, opcodeBuffer) end function terminate() ProtocolGame.unregisterExtendedOpcode(243) if tasksTopButton then tasksTopButton:destroy() end -- Limpar todos os eventos ao terminar o módulo if tasksWindow and tasksWindow.Monsters and tasksWindow.Monsters.monsterList then for _, child in ipairs(tasksWindow.Monsters.monsterList:getChildren()) do if child.dailyScheduleEvent then removeEvent(child.dailyScheduleEvent) end end end end function opcodeBuffer(self, opcode, buffer) local data = json.decode(buffer) if data.action == "informations" then applyServerRewardUpdates(data.taskRewards) actualTasks = data.startedTasks or {} completedTasks = data.completedTasks or {} taskPoints = data.taskPoints or 0 dailyTasksData.rotationTime = data.dailyRotationTime or 0 dailyTasksData.ids = data.dailyTaskIds or {} dailyTasksData.tasks = data.dailyTasks or {} if data.repeatCounts then taskRepeatCounts = {} for index, count in pairs(data.repeatCounts) do taskRepeatCounts[tostring(index)] = count end saveTaskRepeatCounts() end displayTasks(tasksWindow.Monsters.monsterList) readjustButtonByFocus(tasksWindow.Monsters.monsterList) readjustTaskPoints(taskPoints) elseif data.action == "taskRewards" then applyServerRewardUpdates(data.updates) displayTasks(tasksWindow.Monsters.monsterList) readjustButtonByFocus(tasksWindow.Monsters.monsterList) elseif data.action == "resetRepeats" then resetTaskRepeatCounts() displayTasks(tasksWindow.Monsters.monsterList) end end