• 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!

Lua Command !houseinfo

Azerty

Active Member
Joined
Apr 15, 2022
Messages
320
Solutions
4
Reaction score
34
Good morning, can someone provide a !houseinfo script for the player to obtain information on when they will pay the house rent? I use TFS 1.5 downgrade 8.6.
 
Solution
Revscripts
update!
Lua:
local config = {
    talk = "!houseinfo",
    cooldown = false, -- Set to true if the player must have a cooldown to use the command.
    premium = false -- Set to true if the player must be premium to use the command
}

local houseCache = {}
local cooldowns = {}

local talkaction = TalkAction(config.talk)

function talkaction.onSay(player, words, param)
    if config.cooldown and cooldowns[player:getId()] and os.time() - cooldowns[player:getId()] < 10 then
        player:sendCancelMessage(player:getName() .. ", you must wait 10 seconds before using this command again.")
        return false
    end

    if config.premium and not player:isPremium() then
        player:sendCancelMessage(player:getName() .. "...
Revscripts
update!
Lua:
local config = {
    talk = "!houseinfo",
    cooldown = false, -- Set to true if the player must have a cooldown to use the command.
    premium = false -- Set to true if the player must be premium to use the command
}

local houseCache = {}
local cooldowns = {}

local talkaction = TalkAction(config.talk)

function talkaction.onSay(player, words, param)
    if config.cooldown and cooldowns[player:getId()] and os.time() - cooldowns[player:getId()] < 10 then
        player:sendCancelMessage(player:getName() .. ", you must wait 10 seconds before using this command again.")
        return false
    end

    if config.premium and not player:isPremium() then
        player:sendCancelMessage(player:getName() .. ", you need to be premium to use this command.")
        return false
    end

    local house = player:getHouse()
    if not house then
        player:sendCancelMessage(player:getName() .. ", you do not currently own a house.")
        return false
    end

    local houseId = house:getId()
    if not houseCache[houseId] then
        houseCache[houseId] = {
            expirationDate = os.time() + 30 * 24 * 60 * 60 -- Set the expiration date once.
        }
    end

    -- Now retrieve the expiration date from the cache to calculate the time difference.
    local timeDifference = houseCache[houseId].expirationDate - os.time()
    
    -- Calculate total hours, minutes, and seconds
    local totalHours = math.floor(timeDifference / (60 * 60))
    local minutes = math.floor((timeDifference % (60 * 60)) / 60)
    local seconds = timeDifference % 60

    -- Format the remaining time into a string
    local remainingTime = string.format("%02d:%02d:%02d", totalHours, minutes, seconds)

    -- Store the remaining time in the cache
    houseCache[houseId].remainingTime = remainingTime

    -- Send the information to the player
    player:popupFYI(player:getName() .. ", you own " .. house:getName() .. " in " .. house:getTown():getName() .. ". The rent is " .. house:getRent() .. " gold " .. configManager.getString(configKeys.HOUSE_RENT_PERIOD) .. ".\nThis house will expire on " .. os.date("%Y-%m-%d %H:%M:%S", houseCache[houseId].expirationDate) .. ".\nTime remaining: " .. houseCache[houseId].remainingTime)

    -- Set a cooldown if configured
    if config.cooldown then
        cooldowns[player:getId()] = os.time()
    end

    return false
end

talkaction:register()
 
Last edited:
Solution
something like?

Revscripts
Lua:
local talkaction = TalkAction("!houseinfo")

function talkaction.onSay(player, words, param)
    if player:getHouse() == nil then
       player:sendCancelMessage("You do not currently own a house.")
    return false
    end
 
    local playerId = player:getGuid() --get the player database ID
    local resultId = db.storeQuery("SELECT `town_id` FROM `houses` WHERE `owner` = " .. playerId) --queries the database for the town id (a number value) based on the owner id
    if resultId ~= false then --function to only get the true query
        --define variables
        local period = configManager.getString(configKeys.HOUSE_RENT_PERIOD)
        local house = player:getHouse()
        local name = house:getName()
        local rent = house:getRent()
        local townId = result.getNumber(resultId, "town_id") --set variable to numeric value based on query result
        local town = Town(townId) --returns a string of town name from numeric value
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You own '.. name ..' in '.. town:getName(town) ..'. The rent is '.. rent ..' gold '.. period ..'.' ) --print message, no matter what you change your town name too or rent period too the message will be correct
        result.free(resultId) --free the memory associated with the query result before ending the function
    end
 
return false
end

talkaction:register()
YEA BRO!! Is it possible to show the time in hours or days when it will expire?
 
something like?

Revscripts
Lua:
local talkaction = TalkAction("!houseinfo")

function talkaction.onSay(player, words, param)
    if player:getHouse() == nil then
       player:sendCancelMessage("You do not currently own a house.")
    return false
    end
 
    local playerId = player:getGuid() --get the player database ID
    local resultId = db.storeQuery("SELECT `town_id` FROM `houses` WHERE `owner` = " .. playerId) --queries the database for the town id (a number value) based on the owner id
    if resultId ~= false then --function to only get the true query
        --define variables
        local period = configManager.getString(configKeys.HOUSE_RENT_PERIOD)
        local house = player:getHouse()
        local name = house:getName()
        local rent = house:getRent()
        local townId = result.getNumber(resultId, "town_id") --set variable to numeric value based on query result
        local town = Town(townId) --returns a string of town name from numeric value
        player:sendTextMessage(MESSAGE_INFO_DESCR, 'You own '.. name ..' in '.. town:getName(town) ..'. The rent is '.. rent ..' gold '.. period ..'.' ) --print message, no matter what you change your town name too or rent period too the message will be correct
        result.free(resultId) --free the memory associated with the query result before ending the function
    end
 
return false
end

talkaction:register()
You can use house:getTown() instead of doing a database query. And if you ever fetch anything from a db like this, always make sure to cache the results, especially for something like this where the data is static and not subject to change during live gameplay.

And by caching, i mean just create a table at the top of the file, and store the house data in the table using the house ID as the key, then you can check the cache by accessing the data via the key (house id) if it exists, and return that data instead of making a db call, which is expensive.
 
YEA BRO!! Is it possible to show the time in hours or days when it will expire?
I edited the post now. Take a look.
You can use house:getTown() instead of doing a database query. And if you ever fetch anything from a db like this, always make sure to cache the results, especially for something like this where the data is static and not subject to change during live gameplay.

And by caching, i mean just create a table at the top of the file, and store the house data in the table using the house ID as the key, then you can check the cache by accessing the data via the key (house id) if it exists, and return that data instead of making a db call, which is expensive.
When you see something wrong with the script, could you please take the script, make adaptations and corrections, and post it here? Instead of just commenting '-'
 
I edited the post now. Take a look.

When you see something wrong with the script, could you please take the script, make adaptations and corrections, and post it here? Instead of just commenting '-'
I could... but I wont.

What I said was true, and an easy adaptation. Either do it or don't do it. It's up to the OP.
 
Okay, I fixed it. I edited the post. Take a look there, please.
Much better, good job. However, I think you misunderstood what I meant by using a cache. I only meant to use a cache if you're still fetching data from the database. Since you now don't need a database query, you don't need a cache. All the house data is accessible from server memory.
 
Work, but in server save the count starts again at 30 days

This is what you're looking for. (TFS 1.4+, for 1.3 or lower, check the other solution below)
Lua:
local config = {
    talk = "!houseinfo",
    premium = false -- Set to true if the player must be premium to use the command
}

local talkaction = TalkAction(config.talk)
function talkaction.onSay(player, words, param)

    if config.premium and not player:isPremium() then
        player:sendCancelMessage(player:getName() .. ", you need to be premium to use this command.")
        return false
    end

    local house = player:getHouse()
    if not house then
        player:sendCancelMessage(string.format("%s, you do not currently own a house.", player:getName()))
        return false
    end
  
    local paidUntil = house:getPaidUntil()
    local paidUntilString = os.date("%Y-%m-%d %H:%M:%S", paidUntil)
    local remainingTime = "0 days, 0 hours, 0 minutes, 0 seconds"
  
    local timeDifference = paidUntil - os.time()
    if timeDifference > 0 then
        -- Calculate total hours, minutes, and seconds
        local days = math.max(0, math.floor(timeDifference / 86400))
        local remainder = (timeDifference % 86400)
        local hours = math.max(0, math.floor(remainder / 3600))
        local remainder = (timeDifference % 3600)
        local minutes = math.max(0, math.floor(remainder / 60))
        local seconds = math.max(0, (remainder % 60))
      
        -- Format the remaining time into a string
        remainingTime = string.format("%02d days, %02d hours, %02d minutes, %02d seconds", days, hours, minutes, seconds)
    end

    -- Send the information to the player
    player:popupFYI(
        string.format(
            "%s, you own %s in %s. The rent is %u gold %s.\nThis house will expire on %s.\nTime remaining: %s",
            player:getName(),
            house:getName(),
            house:getTown():getName(),
            house:getRent(),
            configManager.getString(configKeys.HOUSE_RENT_PERIOD),
            paidUntilString,
            remainingTime
        )
    )

    return false
end
talkaction:register()

I edited the post now. Take a look.

When you see something wrong with the script, could you please take the script, make adaptations and corrections, and post it here? Instead of just commenting '-'

The below code would be what to do in the scenario of fetching data from the database. As you can see, it runs and caches the data once on startup. Then we can just access the paidUntil data via the house Id as key. I am also checking that if the owner changes, we call the db and fetch just that specific house, and update the cache. So the code below would be ideal for an owner who is running TFS 1.2/1.3 and who doesn't know how to implement lua functions in the sources.

Lua:
local config = {
    talk = "!houseinfo",
    premium = false -- Set to true if the player must be premium to use the command
}

local housesCache = {}

local function cacheHouses(id)
    local id = id and string.format(" AND `id` = %u LIMIT 1", id) or ""

    local resultId = db.storeQuery("SELECT `id`, `paid`, `owner` FROM `houses` WHERE `owner` > 0" .. id)
    if resultId ~= false then 
        repeat 
            local houseId = result.getNumber(resultId, "id")
            local owner = result.getNumber(resultId, "owner")
          
            local paid = result.getNumber(resultId, "paid")
            local paidString = os.date("%Y-%m-%d %H:%M:%S", paid)
          
            housesCache[houseId] = {
                ownerGuid = owner,
                paidUntil = paid,
                paidUntilString = paidString
            }
        until not result.next(resultId)
        result.free(resultId)
    end
end

cacheHouses()

local talkaction = TalkAction(config.talk)
function talkaction.onSay(player, words, param)

    if config.premium and not player:isPremium() then
        player:sendCancelMessage(player:getName() .. ", you need to be premium to use this command.")
        return false
    end

    local house = player:getHouse()
    if not house then
        player:sendCancelMessage(string.format("%s, you do not currently own a house.", player:getName()))
        return false
    end
  
    local houseId = house:getId()
  
    --check and/or set cache
    local houseData = housesCache[houseId]
    if not houseData or houseData.ownerGuid ~= player:getGuid() then
        cacheHouses(houseId)
        houseData = housesCache[houseId]
    end
  
    if not houseData then
        return false
    end
  
    local remainingTime = "0 days, 0 hours, 0 minutes, 0 seconds"
    local timeDifference = houseData.paidUntil - os.time()
    if timeDifference > 0 then
        -- Calculate total hours, minutes, and seconds
        local days = math.max(0, math.floor(timeDifference / 86400))
        local remainder = (timeDifference % 86400)
        local hours = math.max(0, math.floor(remainder / 3600))
        local remainder = (timeDifference % 3600)
        local minutes = math.max(0, math.floor(remainder / 60))
        local seconds = math.max(0, (remainder % 60))
      
        -- Format the remaining time into a string
        remainingTime = string.format("%02d days, %02d hours, %02d minutes, %02d seconds", days, hours, minutes, seconds)
    end

    -- Send the information to the player
    player:popupFYI(
        string.format(
            "%s, you own %s in %s. The rent is %u gold %s.\nThis house will expire on %s.\nTime remaining: %s",
            player:getName(),
            house:getName(),
            house:getTown():getName(),
            house:getRent(),
            configManager.getString(configKeys.HOUSE_RENT_PERIOD),
            houseData.paidUntilString,
            remainingTime
        )
    )

    return false
end
talkaction:register()

(BOTH solutions untested but should work)
 
Last edited:
Back
Top