• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

[TFS 1.3] Daily Reward

Marco Oliveira

Well-Known Member
Joined
Jan 5, 2019
Messages
76
Solutions
3
Reaction score
78
Location
Minas Gerais - Brazil
GitHub
omarcopires
Twitch
omarcopires
Hello, I'm having a little problem with my daily reward on client 12, well, it only delivers the first day reward, after that it just doesn't unlock the next day.
I for testing purposes removed the part that does the checking and it delivers all normally but so is a problem with the check lines, thank you if anyone can help me.

dailyreward.lua
Lua:
DailyRewardSystem = {
  Developer = "Westwol",
  Version = "1.1",
  lastUpdate = "04/06/2019 - 01:00"
}

local ServerPackets = {
  ShowDialog = 0xED, -- universal
  DailyRewardCollectionState = 0xDE, -- undone
  OpenRewardWall = 0xE2, -- Done
  CloseRewardWall = 0xE3, -- is it necessary?
  DailyRewardBasic = 0xE4, -- Done
  DailyRewardHistory = 0xE5, -- Done
  RestingAreaState = 0xA9 -- unodne
}

local ClientPackets = {
  OpenRewardWall = 0xD8,
  OpenRewardHistory = 0xD9,
  SelectReward = 0xDA,
}

--[[-- Constants
Please do not edit any of the next constants:
]]

--[[ Overall ]]--
local DAILY_REWARD_COUNT = 7
local REWARD_FROM_SHRINE = 0
local REWARD_FROM_PANEL = 1

--[[ Bonuses ]] --
local DAILY_REWARD_NONE = 1
local DAILY_REWARD_HP_REGENERATION = 2
local DAILY_REWARD_MP_REGENERATION = 3
local DAILY_REWARD_STAMINA_REGENERATION = 4
local DAILY_REWARD_DOUBLE_HP_REGENERATION = 5
local DAILY_REWARD_DOUBLE_MP_REGENERATION = 6
local DAILY_REWARD_SOUL_REGENERATION = 7

--[[ Reward Types ]] --

-- Server Types
local DAILY_REWARD_TYPE_RUNE_POTION = 1
local DAILY_REWARD_TYPE_STORAGE = 2
local DAILY_REWARD_TYPE_PREY_REROLL = 3
local DAILY_REWARD_TYPE_XP_BOOST = 4

-- Client Types
local DAILY_REWARD_SYSTEM_SKIP = 1
local DAILY_REWARD_SYSTEM_TYPE_ONE = 1
local DAILY_REWARD_SYSTEM_TYPE_TWO = 2
local DAILY_REWARD_SYSTEM_TYPE_OTHER = 1
local DAILY_REWARD_SYSTEM_TYPE_PREY_REROLL = 2
local DAILY_REWARD_SYSTEM_TYPE_XP_BOOST = 3

--[[ Account Status ]] --
local DAILY_REWARD_STATUS_FREE = 0
local DAILY_REWARD_STATUS_PREMIUM = 1

DailyReward = {
  testMode = false,
  serverTimeThreshold = (4 * 60),

  storages = {
    -- Player
      currentDayStreak = 14897,
      currentStreakLevel = 14898,
      nextRewardTime = 14899,
      collectionTokens = 14901,
      staminaBonus = 14902,
    -- Global
      lastServerSave = 14110,
      avoidDouble = 13412,
      notifyReset = 13413
  },

  strikeBonuses = {
  -- day
    [1] = {text = "No bonus for first day"},
    [2] = {text = "Allow Hit Point Regeneration"},
    [3] = {text = "Allow Mana Regeneration"},
    [4] = {text = "Stamina Regeneration"},
    [5] = {text = "Double Hit Point Regeneration"},
    [6] = {text = "Double Mana Regeneration"},
    [7] = {text = "Soul Points Regeneration"}
  },

  rewards = {
  -- day
    [1] = {
      type = DAILY_REWARD_TYPE_RUNE_POTION,
      systemType = DAILY_REWARD_SYSTEM_TYPE_ONE,
      freeAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 5
      },
      premiumAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 10
      }
    },
    [2] = {
      type = DAILY_REWARD_TYPE_RUNE_POTION,
      systemType = DAILY_REWARD_SYSTEM_TYPE_ONE,
      freeAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 5
      },
      premiumAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 10
      }
    },
    [3] = {
      type = DAILY_REWARD_TYPE_PREY_REROLL,
      systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
      freeAccount = {
        rerollCount = 1
      },
      premiumAccount = {
        rerollCount = 2
      }
    },
    [4] = {
      type = DAILY_REWARD_TYPE_RUNE_POTION,
      systemType = DAILY_REWARD_SYSTEM_TYPE_ONE,
      freeAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 5
      },
      premiumAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 10
      }
    },
    [5] = {
      type = DAILY_REWARD_TYPE_STORAGE,
      systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
      freeCount = 1,
      premiumCount = 2,
      freeAccount = {
        things = {
          [1] = {
              name = "task boost",
              id = 1, -- this number can't be repeated
              quantity = 1,
              storages = {
                          {storageId = 23454, value = 1},
                          {storageId = 45141, value = 2},
                          {storageId = 45141, value = 3}
                        }
          }
        }
      },
      premiumAccount = {
        things = {
          [1] = {
              name = "task boostss",
              id = 2, -- this number can't be repeated
              quantity = 1,
              storages = {
                          {storageId = 23454, value = 1}
                        }
          },
          [2] = {
              name = "another task boost",
              id = 3, -- this number can't be repeated
              quantity = 2,
              storages = {
                          {storageId = 23454, value = 1},
                          {storageId = 45141, value = 2},
                          {storageId = 45141, value = 3}
                        }
          }
        }
      }
    },
    [6] = {
      type = DAILY_REWARD_TYPE_RUNE_POTION,
      systemType = DAILY_REWARD_SYSTEM_TYPE_ONE,
      freeAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 5
      },
      premiumAccount = {
        items = {7618, 7588, 7591, 8473, 7620, 2266, 2277, 2301, 2265},
        itemsToPick = 10
      }
    },
    [7] = {
      type = DAILY_REWARD_TYPE_XP_BOOST,
      systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
      freeAccount = {
        xpminutes = 60
      },
      premiumAccount = {
        xpminutes = 120
      }
    }
  }
}

function onRecvbyte(player, msg, byte)
if (byte == ClientPackets.OpenRewardWall) then
  DailyReward.loadDailyReward(player:getId(), REWARD_FROM_PANEL)
elseif (byte == ClientPackets.OpenRewardHistory) then
  player:sendRewardHistory()
elseif (byte == ClientPackets.SelectReward) then
  player:selectDailyReward(msg)
end
end


-- Core functions
DailyReward.insertHistory = function(playerId, dayStreak, description)
  return db.query(string.format("INSERT INTO `daily_reward_history`(`player_id`, `daystreak`, `timestamp`, `description`) VALUES (%s, %s, %s, %s)", playerId, dayStreak, os.time(), db.escapeString(description)))
end

DailyReward.retrieveHistoryEntries = function(playerId)

  local player = Player(playerId)
  if not player then
    return false
  end

  local entries = {}
  local resultId = db.storeQuery("SELECT * FROM `daily_reward_history` WHERE `player_id` = " .. player:getGuid() .. " ORDER BY `timestamp` DESC LIMIT 15;")
  if resultId ~= false then
    repeat
      local entry = {
        description = result.getDataString(resultId, "description"),
        timestamp = result.getDataInt(resultId, "timestamp"),
        daystreak = result.getDataInt(resultId, "daystreak"),
      }
      table.insert(entries, entry)
    until not result.next(resultId)
    result.free(resultId)
  end
  return entries
end

DailyReward.loadDailyReward = function(playerId, source)
  local player = Player(playerId)
  if not player then
    return false
  end
  if source ~= 0 then
    source = REWARD_FROM_SHRINE
  else
    source = REWARD_FROM_PANEL
  end

  if player:getClient().os == CLIENTOS_NEW_WINDOWS then
    player:sendCollectionResource(player:getCollectionTokens())
    player:sendDailyReward()
    player:sendOpenRewardWall(source)
    player:sendDailyRewardCollectionState(false)
  else
    player:sendCancelMessage("The current client does not have support, download the latest version.")
  end
  return true
end

DailyReward.pickedReward = function(playerId)
  local player = Player(playerId)

  if not player then
    return false
  end

  -- Reset day streak to 0 when reaches last reward
  if player:getDayStreak() ~= 6 then
    player:setDayStreak(player:getDayStreak() + 1)
  else
    player:setDayStreak(0)
  end

  player:setStreakLevel(player:getStreakLevel() + 1)
  player:setStorageValue(DailyReward.storages.avoidDouble, Game.getLastServerSave())
  player:setNextRewardTime(Game.getLastServerSave() + DailyReward.serverTimeThreshold)
  player:getPosition():sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
  return true
end

DailyReward.isShrine = function(source)
  if source ~= 0 then
    return false
  else
    return true
  end
end

function Player.iterateTest(self)
    local dailyTable = DailyReward.rewards[5]
    local reward = dailyTable.premiumAccount

    for i = 1, #reward.things do
      for j = 1, #reward.things[i].storages do
        self:setStorageValue(reward.things[i].storages[j].storageId, reward.things[i].storages[j].value)
      end
    end
end

DailyReward.isRewardTaken = function(playerId)
  local player = Player(playerId)
  if not player then
    return false
  end
  local playerStorage = player:getStorageValue(DailyReward.storages.avoidDouble)
  if playerStorage == Game.getLastServerSave() then
    return true
  end
  return false
end

DailyReward.updateDailyRewardStats = function(playerId, zone)
  local player = Player(playerId)

  if not player then
    return false
  end

  local normal, protected = 0, 1
  local disabled, active = 0, 1

  if player:getTile():hasFlag(TILESTATE_PROTECTIONZONE) then
    if player:isRestingAreaBonusActive() then
      player:loadDailyRewardBonuses()
      print(string.format("> %s loaded daily reward bonuses.", player:getName()))
      player:sendRestingAreaState(protected, active)
    else
      player:sendRestingAreaState(protected, disabled)
    end
  else
    player:disableDailyRewardBonuses()
    player:sendRestingAreaState(normal, player:isRestingAreaBonusActive())
  end

end

DailyReward.init = function(playerId)
  local player = Player(playerId)

  if not player then
    return false
  end

  local rewardTime = player:getNextRewardTime() + DailyReward.serverTimeThreshold + 60 -- 1 minutes timegrace
  local nextServerSave = Game.getLastServerSave() + DailyReward.serverTimeThreshold

  if rewardTime < nextServerSave then
    if player:getStorageValue(DailyReward.storages.notifyReset) ~= Game.getLastServerSave() then
      player:setStreakLevel(0)
      player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You just lost your daily reward streak.")
      player:setStorageValue(DailyReward.storages.notifyReset, Game.getLastServerSave())
    end
  end

  DailyReward.updateDailyRewardStats(playerId)
end

DailyReward.processReward = function(playerId, source)
  DailyReward.pickedReward(playerId)
  DailyReward.loadDailyReward(playerId, source)
  DailyReward.updateDailyRewardStats(playerId)
  return true
end

function Player.sendOpenRewardWall(self, shrine)
  local msg = NetworkMessage()
  msg:addByte(ServerPackets.OpenRewardWall) -- initial packet
  msg:addByte(shrine) -- isPlayer taking bonus from reward shrine (1) - taking it from a instant bonus reward (0)
  if DailyReward.testMode then
    msg:addU32(0)
  else
    msg:addU32(self:getNextRewardTime())
  end
  msg:addByte(self:getDayStreak()) -- current reward? day = 0, day 1, ... this should be resetted to 0 every week imo
  local dailyReward_taken = 0 -- 0 / 1 / 2
  msg:addByte(dailyReward_taken) -- state (player already took reward? but just make sure noone wpe)
  if dailyReward_taken ~= 0 then
    msg:addString("Sorry, you have already taken your daily reward or you are unable to collect it.")
  end
  msg:addU32(0) -- timeLeft to pickUp reward without loosing streak // this should be 0 if reward has been already picked
  msg:addU16(self:getStreakLevel()) -- day strike
  msg:addU16(24) -- unknown
  msg:sendToPlayer(self)
end

function Player.sendCollectionResource(self, value)
local msg = NetworkMessage()
msg:addByte(0xEE) -- resource byte
msg:addByte(0x14)
msg:addU64(value)
msg:sendToPlayer(self)
end

function Player.selectDailyReward(self, msg)
  local playerId = self:getId()

  if DailyReward.isRewardTaken(playerId) and not DailyReward.testMode then
    self:sendError("You have already collected your daily reward.")
    return false
  end

  local source = msg:getByte() -- 1 -> shrine / 0 -> tibia panel
  if not DailyReward.isShrine(source) then
    if self:getCollectionTokens() < 1 then
      self:sendError("You do not have enough collection tokens to proceed.")
      return false
    end
    self:setCollectionTokens(self:getCollectionTokens() - 1)
  end

  local dailyTable = DailyReward.rewards[self:getDayStreak() + 1]
  if not dailyTable then
    self:sendError("Something went wrong and we cannot process this request.")
    return false
  end

-- Items as reward
  if (dailyTable.type == DAILY_REWARD_TYPE_RUNE_POTION) then

    local items = {}

    -- Creating items table
    local columnsPicked = msg:getByte() -- Columns picked
    for i = 1, columnsPicked do
      local spriteId = msg:getU16()
      local count = msg:getByte()
      items[i] = {spriteId = spriteId, count = count}
    end

    -- Verifying if items if player is picking the correct amount
    local counter = 0
    for k, v in ipairs(items) do
      counter = counter + v.count
    end

    if self:isPremium() then
      count = dailyTable.premiumAccount.itemsToPick
    else
      count = dailyTable.freeAccount.itemsToPick
    end

    if counter > count then
      self:sendError("Something went wrong here, please restart this dialog.")
      return false
    end

    -- Adding items to store inbox
    local inbox = self:getSlotItem(CONST_SLOT_STORE_INBOX)
    if inbox and inbox:getEmptySlots() < columnsPicked then
      self:sendError("You do not have enough space in your store inbox.")
      return false
    end

    local description = ""
    for k, v in ipairs(items) do
        local item = Game.getItemIdByClientId(v.spriteId)
        inbox:addItem(item:getId(), v.count)
        if k ~= columnsPicked then
          description = description .. "" .. v.count .. "x " .. getItemName(item:getId()) .. ", "
        else
          description = description .. "" .. v.count .. "x " .. getItemName(item:getId()) .. "."
        end
    end

    -- Registering history
    DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. " .. self:getDayStreak() + 1 .. ". Picked items: " .. description)
    DailyReward.processReward(playerId, source)
  end

  local reward = nil
  if self:isPremium() then
    reward = dailyTable.premiumAccount
  else
    reward = dailyTable.freeAccount
  end

  if (dailyTable.type == DAILY_REWARD_TYPE_STORAGE) then
    local description = ""
    for i = 1, #reward.things do
      for j = 1, #reward.things[i].storages do
        self:setStorageValue(reward.things[i].storages[j].storageId, reward.things[i].storages[j].value)
      end
      if i ~= #reward.things then
        description = description .. reward.things[i].name .. ", "
      else
        description = description .. reward.things[i].name .. "."
      end
    end
    DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. " .. self:getDayStreak() + 1 .. ". Picked reward: " .. description)
    DailyReward.processReward(playerId, source)
  end

  if (dailyTable.type == DAILY_REWARD_TYPE_XP_BOOST) then


      local window = ModalWindow {
          title = 'Warning',
          message = 'You still have 20 minutes XP Boost from a previous daily reward left. If you claim your daily reward now, you will lose this remaining time.'
      }
      window:addButton('Ok', function(button, choice)
        DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. " .. self:getDayStreak() + 1 .. ". Picked reward: XP Bonus for " .. reward.xpminutes .. " minutes.")
        DailyReward.processReward(playerId, source)
      end)
      window:addButton('Cancel')
      window:sendToPlayer(self)

  --[[  self:setExpBoostStamina(self:getExpBoostStamina() + (reward.xpminutes * 60))
    self:setStoreXpBoost(50)
    DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. " .. self:getDayStreak() + 1 .. ". Picked reward: XP Bonus for " .. reward.xpminutes .. " minutes.")]]--
  end

  if (dailyTable.type == DAILY_REWARD_TYPE_PREY_REROLL) then
    self:addBonusReroll(reward.rerollCount)
    DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. " .. self:getDayStreak() + 1 .. ". Picked reward: " .. reward.rerollCount .. "x Prey bonus reroll(s)")
    DailyReward.processReward(playerId, source)
  end

return true
end

function Player.sendError(self, error)
  local msg = NetworkMessage()
  msg:addByte(ServerPackets.ShowDialog)
  msg:addByte(0x14)
  msg:addString(error)
  msg:sendToPlayer(self)
end

function Player.sendRestingAreaState(self, zone, state)
  local msg = NetworkMessage()
  if self:getClient().os == CLIENTOS_NEW_WINDOWS then
    msg:addByte(ServerPackets.RestingAreaState)
    msg:addByte(zone) -- [1 if protection zone, 0 if not]
    msg:addByte(state) -- [inactive = 0, active = 1]
    if state == 1 then
      msg:addString("Within Resting Area")
    else
      msg:addString("Resting Area (no active bonus)")
    end
    msg:sendToPlayer(self)
  end
end

function Player.sendDailyRewardCollectionState(self, state)
  local msg = NetworkMessage()
  msg:addByte(ServerPackets.DailyRewardCollectionState)
  msg:addByte(state)
  msg:sendToPlayer(self)
end

function Player.sendRewardHistory(self)
  local msg = NetworkMessage()
  msg:addByte(ServerPackets.DailyRewardHistory)

  local entries = DailyReward.retrieveHistoryEntries(self:getId())
  if #entries == 0 then
    self:sendError("You don't have any entries yet.")
    return false
  end

  msg:addByte(#entries)
  for k, entry in ipairs(entries) do
    msg:addU32(entry.timestamp)
    msg:addByte(0) -- (self:isPremium() and 0 or 0)
    msg:addString(entry.description)
    msg:addU16(entry.daystreak + 1)
  end
  msg:sendToPlayer(self)
end

function Player.readDailyReward(self, msg, currentDay, state)
  local dailyTable = DailyReward.rewards[currentDay]
  local type, systemType = dailyTable.type, dailyTable.systemType
  local rewards = nil
  if (state == DAILY_REWARD_STATUS_FREE) then
    rewards = dailyTable.freeAccount
  else
    rewards = dailyTable.premiumAccount
  end
  msg:addByte(systemType)
  if (systemType == 1) then
    if (type == DAILY_REWARD_TYPE_RUNE_POTION) then
      msg:addByte(rewards.itemsToPick)
      msg:addByte(#rewards.items)
      for i = 1, #rewards.items do
        local itemId = rewards.items[i]
        local itemType = ItemType(itemId)
        local itemName = itemType:getArticle() .. " " .. getItemName(itemId)
        local itemWeight = itemType:getWeight()
        msg:addItemId(itemId)
        msg:addString(itemName)
        msg:addU32(itemWeight)
      end
    end
  elseif (systemType == 2) then
    if (type == DAILY_REWARD_TYPE_STORAGE) then
      msg:addByte(#rewards.things)
      for i = 1, #rewards.things do
          msg:addByte(DAILY_REWARD_SYSTEM_TYPE_OTHER) -- type
          msg:addU16(rewards.things[i].id * 100)
          msg:addString(rewards.things[i].name)
          msg:addByte(rewards.things[i].quantity)
      end
    elseif (type == DAILY_REWARD_TYPE_PREY_REROLL) then
      msg:addByte(DAILY_REWARD_SYSTEM_SKIP)
      msg:addByte(DAILY_REWARD_SYSTEM_TYPE_PREY_REROLL)
      msg:addByte(rewards.rerollCount)
    elseif (type == DAILY_REWARD_TYPE_XP_BOOST) then
      msg:addByte(DAILY_REWARD_SYSTEM_SKIP)
      msg:addByte(DAILY_REWARD_SYSTEM_TYPE_XP_BOOST)
      msg:addU16(rewards.xpminutes)
    end
  end
end

function Player.sendDailyReward(self)
local msg = NetworkMessage()
msg:addByte(ServerPackets.DailyRewardBasic)
msg:addByte(DAILY_REWARD_COUNT)
for currentDay = 1, DAILY_REWARD_COUNT do
    self:readDailyReward(msg, currentDay, DAILY_REWARD_STATUS_FREE) -- Free rewards
    self:readDailyReward(msg, currentDay, DAILY_REWARD_STATUS_PREMIUM) -- Premium rewards
end
-- Resting area bonuses
local maxBonus = 7
msg:addByte(maxBonus - 1)
for i = 2, maxBonus do
  msg:addString(DailyReward.strikeBonuses[i].text)
  msg:addByte(i)
end
msg:addByte(1) -- Unknown
msg:sendToPlayer(self)
end

local items = {}
local function sendItemChoose(player, items, current)

  local playerId = player:getId()

  local dailyTable = DailyReward.rewards[player:getDayStreak() + 1]
  if not dailyTable then
    self:sendError("Something went wrong and we cannot process this request.")
    return false
  end

  if player:isPremium() then
    rewards = dailyTable.premiumAccount
  else
    rewards = dailyTable.freeAccount
  end

  local window = ModalWindow {
    title = 'Daily Reward Wall',
    message = 'Please choose '.. rewards.itemsToPick ..' items of the list.'
  }

  if not items.table then
    items.table = {} -- empty table
    for i = 1, #rewards.items do
      local itemId = rewards.items[i]
      local itemType = ItemType(itemId)
      local itemName = itemType:getArticle() .. " " .. getItemName(itemId)
      items.table[i] = {
        id = i,
        itemId = itemId,
        itemName = itemName,
        amount = 0
      }
    end
  else
    items.table = items.table
  end

  -- Adding choices
  for i = 1, #items.table do
      local id = items.table[i].itemId
      local name = items.table[i].itemName
      local itemId = items.table[i].id
      local amount = items.table[i].amount
      local choice = window:addChoice(name .. " : " .. amount)
      choice.id = id
  end

  local currentCount = 0
  for i = 1, #items.table do
    local count = items.table[i].amount
    currentCount = currentCount + count
  end

  local remainingItems = rewards.itemsToPick - currentCount

  window:addButton('<', function(button, choice)
    items.table[choice.id].amount = math.max(0, items.table[choice.id].amount - 1)
    sendItemChoose(player, items, choice)
  end)

  window:addButton('|>>', function(button, choice)
    items.table[choice.id].amount = math.max(0, items.table[choice.id].amount + remainingItems)
    sendItemChoose(player, items, choice)
  end)


  window:addButton('Confirm', function(button, choice)

  if currentCount ~= rewards.itemsToPick then
    sendItemChoose(player, items, choice)
    return false
  end

  local descount, totalCap = 0, 0
  for i = 1, #items.table do
    local item = items.table[i]
    local count = item.amount
    if count ~= 0 then
      descount = descount + 1
      totalCap = totalCap + ItemType(item.itemId):getWeight(count)
    end
  end

  if player:getFreeCapacity() < totalCap then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You do not have enough capacity to claim the reward.")
    return false
  end

  local inbox = player:getSlotItem(CONST_SLOT_STORE_INBOX)
  if inbox and inbox:getEmptySlots() < descount then
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Please make sure you have free slots in your store inbox.")
    return false
  end

  local description = ""
  local j = 1
  for i = 1, #items.table do
    local item = items.table[i]
    local count = item.amount
    if count ~= 0 then
      inbox:addItem(item.itemId, count)
      if j ~= descount then
        description = description .. "" .. item.amount .. "x " .. getItemName(item.itemId) .. ", "
      else
        description = description .. "" .. item.amount .. "x " .. getItemName(item.itemId) .. "."
      end
      j = j + 1
    end
  end
  player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have claimed " .. description)
  DailyReward.insertHistory(player:getGuid(), player:getDayStreak(), "Claimed reward no. " .. player:getDayStreak() + 1 .. ". Picked items: " .. description)
  DailyReward.pickedReward(playerId)
end)
window:addButton('Abort')
window:sendToPlayer(player)
end
 
Check out the updated version of this sctipt, it is actually working, but you need to configure some features.
 
Hello, I'm having a little problem with my daily reward on client 12, well, it only delivers the first day reward, after that it just doesn't unlock the next day.
I for testing purposes removed the part that does the checking and it delivers all normally but so is a problem with the check lines, thank you if anyone can help me.

This is an edited version that is working 100% to me:

Lua:
DailyRewardSystem = {
    Developer = "Westwol, Marcosvf132",
    Version = "1.3",
    lastUpdate = "12/10/2020 - 20:30",
    ToDo = "Move this system to CPP"
}

local ServerPackets = {
    ShowDialog = 0xED, -- universal
    DailyRewardCollectionState = 0xDE, -- undone
    OpenRewardWall = 0xE2, -- Done
    CloseRewardWall = 0xE3, -- is it necessary?
    DailyRewardBasic = 0xE4, -- Done
    DailyRewardHistory = 0xE5, -- Done
    -- RestingAreaState = 0xA9 -- Moved to cpp
}

local ClientPackets = {
    OpenRewardWall = 0xD8,
    OpenRewardHistory = 0xD9,
    SelectReward = 0xDA,
    CollectionResource = 0x14,
    JokerResource = 0x15
}

--[[-- Constants
Please do not edit any of the next constants:
    ]]

--[[ Overall ]]--
local DAILY_REWARD_COUNT = 7
local REWARD_FROM_SHRINE = 0
local REWARD_FROM_PANEL = 1

--[[ Bonuses ]] --
local DAILY_REWARD_NONE = 1
local DAILY_REWARD_HP_REGENERATION = 2
local DAILY_REWARD_MP_REGENERATION = 3
local DAILY_REWARD_STAMINA_REGENERATION = 4
local DAILY_REWARD_DOUBLE_HP_REGENERATION = 5
local DAILY_REWARD_DOUBLE_MP_REGENERATION = 6
local DAILY_REWARD_SOUL_REGENERATION = 7

--[[ Reward Types ]] --

-- Server Types
local DAILY_REWARD_TYPE_ITEM = 1
local DAILY_REWARD_TYPE_STORAGE = 2
local DAILY_REWARD_TYPE_PREY_REROLL = 3
local DAILY_REWARD_TYPE_XP_BOOST = 4

-- Client Types
local DAILY_REWARD_SYSTEM_SKIP = 1
local DAILY_REWARD_SYSTEM_TYPE_ONE = 1
local DAILY_REWARD_SYSTEM_TYPE_TWO = 2
local DAILY_REWARD_SYSTEM_TYPE_OTHER = 1
local DAILY_REWARD_SYSTEM_TYPE_PREY_REROLL = 2
local DAILY_REWARD_SYSTEM_TYPE_XP_BOOST = 3

--[[ Account Status ]] --
local DAILY_REWARD_STATUS_FREE = 0
local DAILY_REWARD_STATUS_PREMIUM = 1

local DailyRewardItems = {
    [0] = {22722}, -- God/no vocation character
    [VOCATION.BASE_ID.PALADIN] = {22722},
    [VOCATION.BASE_ID.DRUID] = {22722},
    [VOCATION.BASE_ID.SORCERER] = {22722},
    [VOCATION.BASE_ID.KNIGHT] = {22722},
}

DailyReward = {
    testMode = false,
    serverTimeThreshold = (24 * 60 * 60), -- Counting down 24hours from last server save

    storages = {
        -- Player
        currentDayStreak = 14897,
        currentStreakLevel = 14898, -- Cpp uses the same storage value on const.hpp (STORAGEVALUE_DAILYREWARD)
        nextRewardTime = 14899,
        collectionTokens = 14901,
        staminaBonus = 14902,
        jokerTokens = 14903,
        -- Global
        lastServerSave = 14110,
        avoidDouble = 13412,
        notifyReset = 13413,
        avoidDoubleJoker = 13414
    },

    strikeBonuses = {
        -- day
        [1] = {text = "No bonus for first day"},
        [2] = {text = "Allow Hit Point Regeneration"},
        [3] = {text = "Allow Mana Regeneration"},
        [4] = {text = "Stamina Regeneration"},
        [5] = {text = "Double Hit Point Regeneration"},
        [6] = {text = "Double Mana Regeneration"},
        [7] = {text = "Soul Points Regeneration"}
    },

    rewards = {
        --[1] = {
            --type = DAILY_REWARD_TYPE_ITEM,
            --systemType = DAILY_REWARD_SYSTEM_TYPE_ONE,
            --freeAccount = 5,
            --premiumAccount = 10
        --},
        --[6] = {
            --type = DAILY_REWARD_TYPE_ITEM,
            --systemType = DAILY_REWARD_SYSTEM_TYPE_ONE,
            --items = {28540, 28541, 28542, 28543, 28544, 28545},
            --freeAccount = 1,
            --premiumAccount = 2,
            --itemCharges = 50
        --},
        -- day
        [1] = {
            type = DAILY_REWARD_TYPE_PREY_REROLL,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 1,
            premiumAccount = 2
        },
        [2] = {
            type = DAILY_REWARD_TYPE_PREY_REROLL,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 1,
            premiumAccount = 2
        },
        [3] = {
            type = DAILY_REWARD_TYPE_PREY_REROLL,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 1,
            premiumAccount = 2
        },
        [4] = {
            type = DAILY_REWARD_TYPE_XP_BOOST,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 10,
            premiumAccount = 30
        }
        [5] = {
            type = DAILY_REWARD_TYPE_PREY_REROLL,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 1,
            premiumAccount = 2
        },
        [6] = {
            type = DAILY_REWARD_TYPE_PREY_REROLL,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 3,
            premiumAccount = 5
        },
        [7] = {
            type = DAILY_REWARD_TYPE_XP_BOOST,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeAccount = 20,
            premiumAccount = 60
        }
        -- Storage reward template
        --[[[5] = {
            type = DAILY_REWARD_TYPE_STORAGE,
            systemType = DAILY_REWARD_SYSTEM_TYPE_TWO,
            freeCount = 1,
            premiumCount = 2,
            freeAccount = {
                things = {
                    [1] = {
                        name = "task boost",
                        id = 1, -- this number can't be repeated
                        quantity = 1,
                        storages = {
                            {storageId = 23454, value = 1},
                            {storageId = 45141, value = 2},
                            {storageId = 45141, value = 3}
                        }
                    }
                }
            },
            premiumAccount = {
                things = {
                    [1] = {
                        name = "task boostss",
                        id = 2, -- this number can't be repeated
                        quantity = 1,
                        storages = {
                            {storageId = 23454, value = 1}
                        }
                    },
                    [2] = {
                        name = "another task boost",
                        id = 3, -- this number can't be repeated
                        quantity = 2,
                        storages = {
                            {storageId = 23454, value = 1},
                            {storageId = 45141, value = 2},
                            {storageId = 45141, value = 3}
                        }
                    }
                }
            }
        },]]
    }
}

function onRecvbyte(player, msg, byte)
    if (byte == ClientPackets.OpenRewardWall) then
        DailyReward.loadDailyReward(player:getId(), REWARD_FROM_PANEL)
    elseif (byte == ClientPackets.OpenRewardHistory) then
        player:sendRewardHistory()
    elseif (byte == ClientPackets.SelectReward) then
        player:selectDailyReward(msg)
    end
end


-- Core functions
DailyReward.insertHistory = function(playerId, dayStreak, description)
    return db.query(string.format("INSERT INTO `daily_reward_history`(`player_id`, `daystreak`, `timestamp`, \z
        `description`) VALUES (%s, %s, %s, %s)", playerId, dayStreak, os.time(), db.escapeString(description)))
end

DailyReward.retrieveHistoryEntries = function(playerId)

    local player = Player(playerId)
    if not player then
        return false
    end

    local entries = {}
    local resultId = db.storeQuery("SELECT * FROM `daily_reward_history` WHERE `player_id` = \z
        " .. player:getGuid() .. " ORDER BY `timestamp` DESC LIMIT 15;")
    if resultId ~= false then
        repeat
            local entry = {
                description = result.getString(resultId, "description"),
                timestamp = result.getNumber(resultId, "timestamp"),
                daystreak = result.getNumber(resultId, "daystreak"),
            }
            table.insert(entries, entry)
        until not result.next(resultId)
        result.free(resultId)
    end
    return entries
end

DailyReward.loadDailyReward = function(playerId, target)
    local player = Player(playerId)
    if not player then
        return false
    end
    if target ~= 0 then
        target = REWARD_FROM_SHRINE
    else
        target = REWARD_FROM_PANEL
    end

    player:sendCollectionResource(ClientPackets.JokerResource, player:getJokerTokens())
    player:sendCollectionResource(ClientPackets.CollectionResource, player:getCollectionTokens())
    player:sendDailyReward()
    player:sendOpenRewardWall(target)
    player:sendDailyRewardCollectionState(DailyReward.isRewardTaken(player:getId()) and DAILY_REWARD_COLLECTED or DAILY_REWARD_NOTCOLLECTED)
    return true
end

DailyReward.pickedReward = function(playerId)
    local player = Player(playerId)

    if not player then
        return false
    end

    -- Reset day streak to 0 when reaches last reward
    if player:getDayStreak() ~= 6 then
        player:setDayStreak(player:getDayStreak() + 1)
    else
        player:setDayStreak(0)
    end

    player:setStreakLevel(player:getStreakLevel() + 1)
    player:setStorageValue(DailyReward.storages.avoidDouble, GetDailyRewardLastServerSave())
    player:setDailyReward(DAILY_REWARD_COLLECTED)
    player:setNextRewardTime(GetDailyRewardLastServerSave() + DailyReward.serverTimeThreshold)
    player:getPosition():sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
    return true
end

DailyReward.isShrine = function(target)
    if target ~= 0 then
        return false
    else
        return true
    end
end

function Player.iterateTest(self)
    local dailyTable = DailyReward.rewards[5]
    local reward = DailyRewardItems[self:getVocation():getBaseId()]

    if not(reward) then
        reward = {}
    end

    for i = 1, #reward.things do
        for j = 1, #reward.things[i].storages do
            self:setStorageValue(reward.things[i].storages[j].storageId, reward.things[i].storages[j].value)
        end
    end
end

DailyReward.isRewardTaken = function(playerId)
    local player = Player(playerId)
    if not player then
        return false
    end
    local playerStorage = player:getStorageValue(DailyReward.storages.avoidDouble)
    if playerStorage == GetDailyRewardLastServerSave() then
        return true
    end
    return false
end

DailyReward.init = function(playerId)
    local player = Player(playerId)

    if not player then
        return false
    end

    if player:getJokerTokens() < 3 and tonumber(os.date("%m")) ~= player:getStorageValue(DailyReward.storages.avoidDoubleJoker) then
        player:setStorageValue(DailyReward.storages.avoidDoubleJoker, tonumber(os.date("%m")))
        player:setJokerTokens(player:getJokerTokens() + 1)
    end

    local timeMath = GetDailyRewardLastServerSave() - player:getNextRewardTime()
    if player:getNextRewardTime() < GetDailyRewardLastServerSave() then
        if player:getStorageValue(DailyReward.storages.notifyReset) ~= GetDailyRewardLastServerSave() then
            player:setStorageValue(DailyReward.storages.notifyReset, GetDailyRewardLastServerSave())
            timeMath = math.ceil(timeMath/(DailyReward.serverTimeThreshold))
            if player:getJokerTokens() >= timeMath then
                player:setJokerTokens(player:getJokerTokens() - timeMath)
                player:sendTextMessage(MESSAGE_LOGIN, "You lost " .. timeMath .. " joker tokens to prevent loosing your streak.")
            else
                player:setStreakLevel(0)
                if player:getLastLoginSaved() > 0 then -- message wont appear at first character login
                    player:setJokerTokens(-(player:getJokerTokens()))
                    player:sendTextMessage(MESSAGE_LOGIN, "You just lost your daily reward streak.")
                end
            end
        end
    end

    -- Daily reward golden icon
    if DailyReward.isRewardTaken(player:getId()) then
        player:sendDailyRewardCollectionState(DAILY_REWARD_COLLECTED)
        player:setDailyReward(DAILY_REWARD_COLLECTED)
    else
        player:sendDailyRewardCollectionState(DAILY_REWARD_NOTCOLLECTED)
        player:setDailyReward(DAILY_REWARD_NOTCOLLECTED)
    end
    player:loadDailyRewardBonuses()
end

DailyReward.processReward = function(playerId, target)
    DailyReward.pickedReward(playerId)
    DailyReward.loadDailyReward(playerId, target)
    local player = Player(playerId)
    if player then
        player:loadDailyRewardBonuses()
    end
    return true
end

function Player.sendOpenRewardWall(self, shrine)
    local msg = NetworkMessage()
    msg:addByte(ServerPackets.OpenRewardWall) -- initial packet
    msg:addByte(shrine) -- isPlayer taking bonus from reward shrine (1) - taking it from a instant bonus reward (0)
    if DailyReward.testMode or not(DailyReward.isRewardTaken(self:getId())) then
        msg:addU32(0)
    else
        msg:addU32(GetDailyRewardLastServerSave() + DailyReward.serverTimeThreshold)
    end
    msg:addByte(self:getDayStreak()) -- current reward? day = 0, day 1, ... this should be resetted to 0 every week imo
    if DailyReward.isRewardTaken(self:getId()) then -- state (player already took reward? but just make sure noone wpe)
        msg:addByte(1)
        msg:addString("Sorry, you have already taken your daily reward or you are unable to collect it.") -- Unknown message
        if self:getJokerTokens() > 0 then
            msg:addByte(1)
            msg:addU16(self:getJokerTokens())
        else
            msg:addByte(0)
        end
    else
        msg:addByte(0)
        msg:addByte(2)
        msg:addU32(GetDailyRewardLastServerSave() + DailyReward.serverTimeThreshold) --timeLeft to pickUp reward without loosing streak
        msg:addU16(self:getJokerTokens())
    end
    msg:addU16(self:getStreakLevel()) -- day strike
    msg:sendToPlayer(self)
end

function Player.sendCollectionResource(self, byte, value)
    -- TODO: Migrate to protocolgame.cpp
    local msg = NetworkMessage()
    msg:addByte(0xEE) -- resource byte
    msg:addByte(byte)
    msg:addU64(value)
    msg:sendToPlayer(self)
end

function Player.selectDailyReward(self, msg)
    local playerId = self:getId()

    if DailyReward.isRewardTaken(playerId) and not DailyReward.testMode then
        self:sendError("You have already collected your daily reward.")
        return false
    end

    local target = msg:getByte() -- 0 -> shrine / 1 -> tibia panel
    if not DailyReward.isShrine(target) then
        if self:getCollectionTokens() < 1 then
            self:sendError("You do not have enough collection tokens to proceed.")
            return false
        end
        self:setCollectionTokens(self:getCollectionTokens() - 1)
    end

    local dailyTable = DailyReward.rewards[self:getDayStreak() + 1]
    if not dailyTable then
        self:sendError("Something went wrong and we cannot process this request.")
        return false
    end

    -- Items as reward
    if (dailyTable.type == DAILY_REWARD_TYPE_ITEM) then

        local items = {}

        -- Creating items table
        local columnsPicked = msg:getByte() -- Columns picked
        for i = 1, columnsPicked do
            local spriteId = msg:getU16()
            local count = msg:getByte()
            items[i] = {spriteId = spriteId, count = count}
        end

        -- Verifying if items if player is picking the correct amount
        local counter = 0
        for k, v in ipairs(items) do
            counter = counter + v.count
        end

        if self:isPremium() then
            count = dailyTable.premiumAccount
        else
            count = dailyTable.freeAccount
        end

        if counter > count then
            self:sendError("Something went wrong here, please restart this dialog.")
            return false
        end

        -- Adding items to store inbox
        local inbox = self:getSlotItem(CONST_SLOT_STORE_INBOX)
        if inbox and inbox:getEmptySlots() < columnsPicked then
            self:sendError("You do not have enough space in your store inbox.")
            return false
        end

        local description = ""
        for k, v in ipairs(items) do
            if dailyTable.itemCharges then
                for i = 1, v.count do
                    inbox:addItem(v.ItemId, dailyTable.itemCharges) -- adding charges for each item
                end
            else
                inbox:addItem(v.ItemId, v.count) -- adding single item w/o charges
            end
            if k ~= columnsPicked then
                description = description .. "" .. v.count .. "x " .. ItemType(v.itemId):getName() .. ", "
            else
                description = description .. "" .. v.count .. "x " .. ItemType(v.itemId):getName() .. "."
            end
        end

        -- Registering history
        DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
            " .. self:getDayStreak() + 1 .. ". Picked items: " .. description)
        DailyReward.processReward(playerId, target)
    end

    local reward = nil
    if self:isPremium() then
        reward = dailyTable.premiumAccount
    else
        reward = dailyTable.freeAccount
    end

    -- if (dailyTable.type == DAILY_REWARD_TYPE_STORAGE) then
        -- local description = ""
        -- for i = 1, #reward.things do
            -- for j = 1, #reward.things[i].storages do
                -- self:setStorageValue(reward.things[i].storages[j].storageId, reward.things[i].storages[j].value)
            -- end
            -- if i ~= #reward.things then
                -- description = description .. reward.things[i].name .. ", "
            -- else
                -- description = description .. reward.things[i].name .. "."
            -- end
        -- end
        -- DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
            -- " .. self:getDayStreak() + 1 .. ". Picked reward: " .. description)
        -- DailyReward.processReward(playerId, target)
    -- end

    if (dailyTable.type == DAILY_REWARD_TYPE_XP_BOOST) then
        self:setExpBoostStamina(self:getExpBoostStamina() + (reward * 60))
        self:setStoreXpBoost(50)
        DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
            " .. self:getDayStreak() + 1 .. ". Picked reward: XP Bonus for " .. reward .. " minutes.")
        DailyReward.processReward(playerId, target)
    end

    if (dailyTable.type == DAILY_REWARD_TYPE_PREY_REROLL) then
        self:addPreyCards(reward)
        DailyReward.insertHistory(self:getGuid(), self:getDayStreak(), "Claimed reward no. \z
            " .. self:getDayStreak() + 1 .. ". Picked reward: " .. reward .. "x Prey bonus reroll(s)")
        DailyReward.processReward(playerId, target)
    end

    return true
end

function Player.sendError(self, error)
    local msg = NetworkMessage()
    msg:addByte(ServerPackets.ShowDialog)
    msg:addByte(0x14)
    msg:addString(error)
    msg:sendToPlayer(self)
end

function Player.sendDailyRewardCollectionState(self, state)
    local msg = NetworkMessage()
    msg:addByte(ServerPackets.DailyRewardCollectionState)
    msg:addByte(state)
    msg:sendToPlayer(self)
end

function Player.sendRewardHistory(self)
    local msg = NetworkMessage()
    msg:addByte(ServerPackets.DailyRewardHistory)

    local entries = DailyReward.retrieveHistoryEntries(self:getId())
    if #entries == 0 then
        self:sendError("You don't have any entries yet.")
        return false
    end

    msg:addByte(#entries)
    for k, entry in ipairs(entries) do
        msg:addU32(entry.timestamp)
        msg:addByte(0) -- (self:isPremium() and 0 or 0)
        msg:addString(entry.description)
        msg:addU16(entry.daystreak + 1)
    end
    msg:sendToPlayer(self)
end

function Player.readDailyReward(self, msg, currentDay, state)
    local dailyTable = DailyReward.rewards[currentDay]
    local type, systemType = dailyTable.type, dailyTable.systemType
    local rewards = nil
    local itemsToPick = 0
    if currentDay == 3 or (currentDay >= 5 and currentDay <= 7) then
        rewards = dailyTable.items
        if (state == DAILY_REWARD_STATUS_FREE) then
            itemsToPick = dailyTable.freeAccount
        else
            itemsToPick = dailyTable.premiumAccount
        end
    else
        if systemType == 1 then
            if (state == DAILY_REWARD_STATUS_FREE) then
                rewards = DailyRewardItems[self:getVocation():getBaseId()]
                itemsToPick = dailyTable.freeAccount
            else
                rewards = DailyRewardItems[self:getVocation():getBaseId()]
                itemsToPick = dailyTable.premiumAccount
            end

            if not(rewards) then
                rewards = {}
            end
        else
            if (state == DAILY_REWARD_STATUS_FREE) then
                rewards = dailyTable.freeAccount
            else
                rewards = dailyTable.premiumAccount
            end
        end
    end
    msg:addByte(systemType)
    if (systemType == 1) then
        if (type == DAILY_REWARD_TYPE_ITEM) then
            msg:addByte(itemsToPick)
            msg:addByte(#rewards)
            for i = 1, #rewards do
                local itemId = rewards[i]
                local itemType = ItemType(itemId)
                local itemName = itemType:getArticle() .. " " .. itemType:getName()
                local itemWeight = itemType:getWeight()
                msg:addU16(itemId)
                msg:addString(itemName)
                msg:addU32(itemWeight)
            end
        end
    elseif (systemType == 2) then
        if (type == DAILY_REWARD_TYPE_STORAGE) then
            -- msg:addByte(#rewards.things)
            -- for i = 1, #rewards.things do
                -- msg:addByte(DAILY_REWARD_SYSTEM_TYPE_OTHER) -- type
                -- msg:addU16(rewards.things[i].id * 100)
                -- msg:addString(rewards.things[i].name)
                -- msg:addByte(rewards.things[i].quantity)
            -- end
        elseif (type == DAILY_REWARD_TYPE_PREY_REROLL) then
            msg:addByte(DAILY_REWARD_SYSTEM_SKIP)
            msg:addByte(DAILY_REWARD_SYSTEM_TYPE_PREY_REROLL)
            msg:addByte(itemsToPick)
        elseif (type == DAILY_REWARD_TYPE_XP_BOOST) then
            msg:addByte(DAILY_REWARD_SYSTEM_SKIP)
            msg:addByte(DAILY_REWARD_SYSTEM_TYPE_XP_BOOST)
            msg:addU16(itemsToPick)
        end
    end
end

function Player.sendDailyReward(self)
    local msg = NetworkMessage()
    msg:addByte(ServerPackets.DailyRewardBasic)
    msg:addByte(DAILY_REWARD_COUNT)
    for currentDay = 1, DAILY_REWARD_COUNT do
        self:readDailyReward(msg, currentDay, DAILY_REWARD_STATUS_FREE) -- Free rewards
        self:readDailyReward(msg, currentDay, DAILY_REWARD_STATUS_PREMIUM) -- Premium rewards
    end
    -- Resting area bonuses
    local maxBonus = 7
    msg:addByte(maxBonus - 1)
    for i = 2, maxBonus do
        msg:addString(DailyReward.strikeBonuses[i].text)
        msg:addByte(i)
    end
    msg:addByte(1) -- Unknown
    msg:sendToPlayer(self)
end
This is not giving items, so I replaced those with Prey Reroll and Xp Boosts and is working 100% on OTBR Protocol 12.91. Just let a server save happen and timer will be also working. Also regen streaks are working fine.
1666804190648.png
 
Back
Top