• 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.5] VIP System

Marco Oliveira

Well-Known Member
Joined
Jan 5, 2019
Messages
76
Solutions
3
Reaction score
78
Location
Minas Gerais - Brazil
GitHub
omarcopires
Twitch
omarcopires
Description:
Provides VIP functionality for players, offering exclusive features and benefits.
Includes player functions for checking VIP status, adding and removing VIP days, and getting the remaining days.
Supports talkactions for administrators to manage player VIP days and for players to check their own VIP status.
Players can purchase VIP days using in-game currency.

Usage:
Players can acquire VIP days to unlock exclusive benefits and enhance their gaming experience.
VIP benefits include outfits and mounts that are automatically added when the player becomes a VIP.
When VIP days expire, the player's benefits are removed, and they are teleported to a designated position.

Player functions:
  • player:isVIP(): Checks if the player is a VIP.
  • player:addVIP(days): Adds the specified number of VIP days to the player.
  • player:removeVIP(days): Removes the specified number of VIP days from the player.
  • player:getVIPDays(): Returns the number of remaining VIP days for the player.
  • player:getVIPExpirationDate(): Returns the expiration date of the player's VIP status.
  • player:addVIPBenefits(): Adds VIP benefits to the player if missing.
  • player:removeVIPBenefits(): Removes VIP benefits, teleports the player, and updates the town ID.
  • player:sendVIPStatus(): Sends the player's VIP status and an appropriate message.

Vip config:
  • storageKey: Must be account storage.
  • vipBenefitsKey: Avoid removing or adding VIP benefits more than once.
  • outfits: The outfit IDs granted to VIP players.
  • mounts: The mount IDs granted to VIP players.
  • townId: The town ID where the player is teleported when VIP expires.
  • vipPrice: The price in gold coins to buy VIP.
  • vipDays: The number of VIP days acquired when purchasing VIP.

Talkactions:
  • !vip: Checks the number of VIP days the player has.
  • !buyvip: Buy a specified number of VIP days configured in vipDays.

TODO:
  • Talkaction to manage the days (/vip, name, action, days).

anywhere in data/scripts add a file called vip_module.lua:
Lua:
local vipConfig = {
    storageKey = 30017,
    vipBenefitsKey = 30000,
    outfits = {963, 965, 967, 969, 971, 973, 975, 962, 964, 966, 968, 970, 972, 974},
    mounts = {168, 169, 170},
    townId = 1,
    vipPrice = 1000000,
    vipDays = 30,

    messages = {
        expired = "Your VIP has expired. Consider purchasing more VIP days.",
        remaining = "You currently have %d VIP days remaining, which will expire on %s.",
        newPlayer = "Enhance your gaming experience by acquiring VIP days and unlock exclusive benefits.",
        buySuccess = "You have bought %d days of VIP account!",
        buyFailure = "You don't have enough money, %d days VIP costs %d gold coins.",
        alreadyVIP = "You can not buy more than %d days of VIP account.",
        checkVIP = "You have %d days of VIP account."
    }
}

function Player.isVIP(self)
    local currentExpiration = self:getAccountStorageValue(vipConfig.storageKey)
    local currentTime = os.time()

    if currentExpiration and currentExpiration > currentTime then
        return true
    else
        return false
    end
end

function Player.addVIP(self, days)
    local currentExpiration = self:getAccountStorageValue(vipConfig.storageKey)
    local currentTime = os.time()

    if currentExpiration <= currentTime then
        currentExpiration = currentTime
    end

    local newExpiration = currentExpiration + (days * 24 * 60 * 60)
    self:setAccountStorageValue(vipConfig.storageKey, newExpiration)
end

function Player.removeVIP(self, days)
    local currentExpiration = self:getAccountStorageValue(vipConfig.storageKey)
    local currentTime = os.time()

    if currentExpiration > currentTime then
        local remainingSeconds = currentExpiration - currentTime
        local remainingDays = math.floor(remainingSeconds / (24 * 60 * 60))
        local newExpiration = currentExpiration - (days * 24 * 60 * 60)

        if newExpiration < currentTime then
            newExpiration = currentTime
        end

        self:setAccountStorageValue(vipConfig.storageKey, newExpiration)
    end
end

function Player.getVIPDays(self)
    local currentExpiration = self:getAccountStorageValue(vipConfig.storageKey)
    local currentTime = os.time()

    if currentExpiration > currentTime then
        local remainingSeconds = currentExpiration - currentTime
        local remainingDays = math.floor(remainingSeconds / (24 * 60 * 60))
        return remainingDays
    end

    return 0
end

function Player.getVIPExpirationDate(self)
    local expirationTime = self:getAccountStorageValue(vipConfig.storageKey)

    if expirationTime > os.time() then
        local remainingSeconds = expirationTime - os.time()
        local remainingDays = math.floor(remainingSeconds / (24 * 60 * 60))
        local expirationDateTime = os.date("%m/%d/%y at %H:%M", expirationTime)
        return remainingDays, expirationDateTime
    end

    return 0, "N/A"
end

function Player.addVIPBenefits(self)
    for i, outfitId in ipairs(vipConfig.outfits) do
        if not self:hasOutfit(outfitId) then
            self:addOutfit(outfitId)
        end
    end

    for i, mountId in ipairs(vipConfig.mounts) do
        if not self:hasMount(mountId) then
            self:addMount(mountId)
        end
    end
end

function Player.removeVIPBenefits(self)
    local outfitsToDelete = vipConfig.outfits
    for i = 1, #outfitsToDelete do
        self:removeOutfit(outfitsToDelete[i])
    end

    local mountsToDelete = vipConfig.mounts
    for i = 1, #mountsToDelete do
        self:removeMount(mountsToDelete[i])
    end

    self:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
    self:setTown(vipConfig.townId)
    self:teleportTo(self:getTown():getTemplePosition())
    self:getPosition():sendMagicEffect(CONST_ME_TELEPORT)
end

function Player.getVIPBenefits(self)
    return self:getStorageValue(vipBenefitsKey) == 1
end

function Player.setVIPBenefits(self, enabled)
    if enabled then
        if not self:getVIPBenefits() then
            self:addVIPBenefits()
            self:setStorageValue(vipBenefitsKey, 1)
        end
    else
        if self:getVIPBenefits() then
            self:removeVIPBenefits()
            self:setStorageValue(vipBenefitsKey, -1)
        end
    end
end

function Player.sendVIPStatus(self)
    local daysRemaining, expirationDateTime = self:getVIPExpirationDate()

    if daysRemaining > 0 then
        self:sendTextMessage(MESSAGE_INFO_DESCR, string.format(vipConfig.messages.remaining, daysRemaining, expirationDateTime))
        self:setVIPBenefits(true)
    elseif daysRemaining == 0 then
        self:sendTextMessage(MESSAGE_STATUS_WARNING, vipConfig.messages.expired)
        self:setVIPBenefits(false)
    else
        self:sendTextMessage(MESSAGE_INFO_DESCR, vipConfig.messages.newPlayer)
    end
end

local buyVipDays = TalkAction("!buyvip")

function buyVipDays.onSay(player, words, param)
    local daysRemaining = player:getVIPExpirationDate()
    if player:isVIP() then
        player:sendCancelMessage(string.format(vipConfig.messages.alreadyVIP, daysRemaining))
        return false
    end

    local vipPrice = vipConfig.vipPrice
    local vipDays = vipConfig.vipDays
    if player:removeTotalMoney(vipPrice) then
        player:addVIP(vipDays)
        player:sendTextMessage(MESSAGE_INFO_DESCR, string.format(vipConfig.messages.buySuccess, vipDays))
    else
        player:sendCancelMessage(string.format(vipConfig.messages.buyFailure, vipDays, vipPrice))
    end

    return false
end

buyVipDays:register()

local checkVipDays = TalkAction("!vip")

function checkVipDays.onSay(player, words, param)
    local daysRemaining = player:getVIPExpirationDate()
    if player:isVIP() then
        player:sendTextMessage(MESSAGE_INFO_DESCR, string.format(vipConfig.messages.checkVIP, daysRemaining))
    else
        player:sendTextMessage(MESSAGE_INFO_DESCR, vipConfig.messages.newPlayer)
    end

    return false
end

checkVipDays:register()

Now we need to verify and send the player's information, for that we will add the following code in creaturescript login.lua

Lua:
-- Vip system
player:sendVIPStatus()

Maybe you need two extra functions, which should be added in data/lib/core/player.lua

Lua:
function Player.setAccountStorageValue(self, key, value)
    return Game.setAccountStorageValue(self:getAccountId(), key, value)
end

function Player.getAccountStorageValue(self, key)
    return Game.getAccountStorageValue(self:getAccountId(), key)
end
 
Last edited:
Back
Top