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

NPC [TFS 1.0] Marriage System

Godely

Member
Joined
Aug 19, 2007
Messages
233
Reaction score
16
Almost 5 years since I released the Marriage System for TFS ~0.2-0.3, I took a day to remake it so that works with TFS 1.0. I still use live queries in the code since I didn't want to change any source code (and also to make it works with offline players).

Please, understand that TFS 1.0 is constantly changing and you should have the latest sources compiled to make it work (since some changes were made in events). Hope you like it!

Create a new NPC Priest.xml:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Priest" script="priest.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100"/>
    <look type="132" head="20" body="39" legs="45" feet="7" addons="0"/>
</npc>

And the corresponding lua file priest.lua:
Code:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)

function onCreatureAppear(cid)            npcHandler:onCreatureAppear(cid)            end
function onCreatureDisappear(cid)        npcHandler:onCreatureDisappear(cid)            end
function onCreatureSay(cid, type, msg)    npcHandler:onCreatureSay(cid, type, msg)    end
function onThink()                        npcHandler:onThink()                        end

local function greetCallback(cid)
    local player = Player(cid)
    local msg = 'Be welcome, ' .. player:getName() .. '.'
   
    local playerStatus = getPlayerMarriageStatus(player:getGuid())
    local playerSpouse = getPlayerSpouse(player:getGuid())
    if (playerStatus == MARRIED_STATUS) then
        msg = msg .. ' I see that you are a happily married ' .. ((player:getSex() == PLAYERSEX_FEMALE) and 'woman' or 'man') .. '. What brings you here? Looking for a {divorce}?'
    elseif (playerStatus == PROPOSED_STATUS) then
        msg = msg .. ' You are still waiting for the wedding proposal you made to {' .. (getPlayerNameById(playerSpouse)) .. '}. Would you like to {remove} it?'
    else
        msg = msg .. ' What brings you here? Wanting to {marry} someone?'
    end
    npcHandler:say(msg,cid)
    npcHandler:addFocus(cid)
    return false
end

local function tryEngage(cid, message, keywords, parameters, node)
    if(not npcHandler:isFocused(cid)) then
        return false
    end
   
    local player = Player(cid)
   
    local playerStatus = getPlayerMarriageStatus(player:getGuid())
    local playerSpouse = getPlayerSpouse(player:getGuid())
    if playerStatus == MARRIED_STATUS then
        npcHandler:say('You are already married to {' .. getPlayerNameById(playerSpouse) .. '}.', cid)
    elseif playerStatus == PROPOSED_STATUS then
        npcHandler:say('You already made a wedding proposal to {' .. getPlayerNameById(playerSpouse) .. '}. You can always remove the proposal by saying {remove} proposal.', cid)
    else
        local candidate = getPlayerGUIDByName(message)
        if candidate == 0 then
            npcHandler:say('A player with this name does not exist.', cid)
        elseif candidate == player:getGuid() then
            npcHandler:say('You can\'t marry yourself, kid.', cid)
        else
            if player:getItemCount(ITEM_WEDDING_RING) == 0 then
                npcHandler:say('As I said, you need a wedding ring in order to marry.', cid)
            else
                local candidateStatus = getPlayerMarriageStatus(candidate)
                local candidateSpouse = getPlayerSpouse(candidate)
                if candidateStatus == MARRIED_STATUS then
                    npcHandler:say('{' .. getPlayerNameById(candidate) .. '} is already married to {' .. getPlayerNameById(candidateSpouse) .. '}.', cid)
                elseif candidateStatus == PROPOSED_STATUS then
                    if candidateSpouse == player:getGuid() then
                        npcHandler:say('Since both young souls are willing to marry, I now pronounce you and {' .. getPlayerNameById(candidate) .. '} married. {' .. player:getName() .. '}, take these two engraved wedding rings and give one of them to your spouse.', cid)
                        player:removeItem(ITEM_WEDDING_RING,1)
                        local item1 = Item(doPlayerAddItem(cid,ITEM_ENGRAVED_WEDDING_RING,1))
                        local item2 = Item(doPlayerAddItem(cid,ITEM_ENGRAVED_WEDDING_RING,1))
                        item1:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, player:getName() .. ' & ' .. getPlayerNameById(candidate) .. ' forever - married on ' .. os.date('%B %d, %Y.'))
                        item2:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, player:getName() .. ' & ' .. getPlayerNameById(candidate) .. ' forever - married on ' .. os.date('%B %d, %Y.'))
                        setPlayerMarriageStatus(player:getGuid(), MARRIED_STATUS)
                        setPlayerMarriageStatus(candidate, MARRIED_STATUS)
                        setPlayerSpouse(player:getGuid(), candidate)
                    else
                        npcHandler:say('{' .. getPlayerNameById(candidate) .. '} already made a wedding proposal to {' .. getPlayerNameById(candidateSpouse) .. '}.', cid)
                    end
                else
                    npcHandler:say('Ok, now let\'s wait and see if {' ..  getPlayerNameById(candidate) .. '} accepts your proposal. I\'ll give you back your wedding ring as soon as {' ..  getPlayerNameById(candidate) .. '} accepts your proposal or you {remove} it.', cid)
                    player:removeItem(ITEM_WEDDING_RING,1)
                    setPlayerMarriageStatus(player:getGuid(), PROPOSED_STATUS)
                    setPlayerSpouse(player:getGuid(), candidate)
                end
            end
        end
    end
    keywordHandler:moveUp(3)
    return true
end

local function confirmRemoveEngage(cid, message, keywords, parameters, node)
    if(not npcHandler:isFocused(cid)) then
        return false
    end
   
    local player = Player(cid)
    local playerStatus = getPlayerMarriageStatus(player:getGuid())
    local playerSpouse = getPlayerSpouse(player:getGuid())
    if playerStatus == PROPOSED_STATUS then
        npcHandler:say('Are you sure you want to remove your wedding proposal with {' .. getPlayerNameById(playerSpouse) .. '}?', cid)
        node:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, moveup = 3, text = 'Ok, let\'s keep it then.'})
       
        local function removeEngage(cid, message, keywords, parameters, node)
            doPlayerAddItem(cid,ITEM_WEDDING_RING,1)
            setPlayerMarriageStatus(player:getGuid(), 0)
            setPlayerSpouse(player:getGuid(), -1)
            npcHandler:say(parameters.text, cid)
            keywordHandler:moveUp(parameters.moveup)
        end
        node:addChildKeyword({'yes'}, removeEngage, {moveup = 3, text = 'Ok, your marriage proposal to {' .. getPlayerNameById(playerSpouse) .. '} has been removed. Take your wedding ring back.'})
    else
        npcHandler:say('You don\'t have any pending proposal to be removed.', cid)
        keywordHandler:moveUp(2)
    end
    return true
end

local function confirmDivorce(cid, message, keywords, parameters, node)
    if(not npcHandler:isFocused(cid)) then
        return false
    end
   
    local player = Player(cid)
    local playerStatus = getPlayerMarriageStatus(player:getGuid())
    local playerSpouse = getPlayerSpouse(player:getGuid())
    if playerStatus == MARRIED_STATUS then
        npcHandler:say('Are you sure you want to divorce of {' .. getPlayerNameById(playerSpouse) .. '}?', cid)
        node:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, moveup = 3, text = 'Great! Marriages should be an eternal commitment.'})
       
        local function divorce(cid, message, keywords, parameters, node)
            local player = Player(cid)
            local spouse = getPlayerSpouse(player:getGuid())
            setPlayerMarriageStatus(player:getGuid(), 0)
            setPlayerSpouse(player:getGuid(), -1)
            setPlayerMarriageStatus(spouse, 0)
            setPlayerSpouse(spouse, -1)
            npcHandler:say(parameters.text, cid)
            keywordHandler:moveUp(parameters.moveup)
        end
        node:addChildKeyword({'yes'}, divorce, {moveup = 3, text = 'Ok, you are now divorced of {' .. getPlayerNameById(playerSpouse) .. '}. Think better next time after marrying someone.'})
    else
        npcHandler:say('You aren\'t married to get a divorce.', cid)
        keywordHandler:moveUp(2)
    end
    return true
end

local node1 = keywordHandler:addKeyword({'marry'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, text = 'Would you like to get married? Make sure you have a wedding ring with you.'})
node1:addChildKeyword({'no'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, moveup = 1, text = 'That\'s fine.'})
local node2 = node1:addChildKeyword({'yes'}, StdModule.say, {npcHandler = npcHandler, onlyFocus = true, text = 'And who would you like to marry?'})
node2:addChildKeyword({'[%w]'}, tryEngage, {})

keywordHandler:addKeyword({'remove'}, confirmRemoveEngage, {})

keywordHandler:addKeyword({'divorce'}, confirmDivorce, {})

npcHandler:setCallback(CALLBACK_GREET, greetCallback)

npcHandler:addModule(FocusModule:new())

Now, on events/events.xml, enable the method onLook if it's not enabled. The line should be like this:
Code:
<event class="Player" method="onLook" enabled="1"/>

Continue on the next post...
 
Last edited:
Now, on events/scripts/player.lua, add the following piece of code after the local description variable is initialized in the method Player: onLook.
Code:
    if LOOK_MARRIAGE_DESCR and thing:isCreature() then
        if thing:isPlayer() then
            description = description .. self:getMarriageDescription(thing)
        end
    end

Now go on global.lua and add the following code:
Code:
PROPOSED_STATUS = 1
MARRIED_STATUS = 2
LOOK_MARRIAGE_DESCR = TRUE
ITEM_WEDDING_RING = 2121
ITEM_ENGRAVED_WEDDING_RING = 10502

function getPlayerSpouse(id)
    local resultQuery = db.storeQuery("SELECT `marriage_spouse` FROM `players` WHERE `id` = " .. db.escapeString(id))
    if resultQuery ~= false then
        local ret = result.getDataInt(resultQuery, "marriage_spouse")
        result.free(resultQuery)
        return ret
    end
    return -1
end

function setPlayerSpouse(id, val)
    db.query("UPDATE `players` SET `marriage_spouse` = " .. val .. " WHERE `id` = " .. id)
end

function getPlayerMarriageStatus(id)
    local resultQuery = db.storeQuery("SELECT `marriage_status` FROM `players` WHERE `id` = " .. db.escapeString(id))
    if resultQuery ~= false then
        local ret = result.getDataInt(resultQuery, "marriage_status")
        result.free(resultQuery)
        return ret
    end
    return -1
end

function setPlayerMarriageStatus(id, val)
    db.query("UPDATE `players` SET `marriage_status` = " .. val .. " WHERE `id` = " .. id)
end

function Player:getMarriageDescription(thing)
    local descr = ""
    if getPlayerMarriageStatus(thing:getGuid()) == MARRIED_STATUS then
        playerSpouse = getPlayerSpouse(thing:getGuid())
        if self == thing then
            descr = descr .. " You are "
        elseif thing:getSex() == PLAYERSEX_FEMALE then
            descr = descr .. " She is "
        else
            descr = descr .. " He is "
        end
        descr = descr .. "married to " .. getPlayerNameById(playerSpouse) .. '.'
    end
    return descr
end
LOOK_MESSAGE_DESCR should be set to FALSE in case you don't want the marriage info to appear in the look description of a player (e.g. You see Godely. He is married to Lalala.).

Now, go to compat.lua and add those following functions somewhere in the code:
Code:
function getPlayerNameById(id)
    local resultName = db.storeQuery("SELECT `name` FROM `players` WHERE `id` = " .. db.escapeString(id))
    if resultName ~= false then
        local name = result.getDataString(resultName, "name")
        result.free(resultName)
        return name
    end
    return 0
end

Now, the last thing to do is execute the following command on the database:
Code:
ALTER TABLE `players` ADD `marriage_status` tinyint(1) NOT NULL DEFAULT 0, ADD `marriage_spouse` int(11) NOT NULL DEFAULT -1

Another option is to paste the following code on 18.lua, in migrations, run the server and undo it:
Code:
function onUpdateDatabase()
    print("> Updating database to version 19 (add marriage info to players table - marriage_status determines if the player is married and marriage_spouse determines to whom)")

    db.query("ALTER TABLE `players` ADD `marriage_status` tinyint(1) NOT NULL DEFAULT 0, ADD `marriage_spouse` int(11) NOT NULL DEFAULT -1")
    return false
end

That's it, the marriage system should be working on your server. To marry someone, a person with NAME1 would just say hi, marry, yes, NAME2. Then, a person with the NAME2 would say hi, marry, yes, NAME1. The other commands are divorce, to divorce a player, of course, and remove, to remove a wedding proposal you made to someone. The code is not so big, so please take a time to look into it and contribute :)
 
Last edited:
Good work! I wanted to write it in future, but you done it first. Great job!
 
Awesome, only the rings are missing and at those it should say who you married to aswell.. Good work :)
 
Code:
 npcHandler:say('Since both youngs souls are willing to marry, I now pronounce you, {' .. player:getName() .. '}, and {' .. getPlayerNameById(candidate) .. '} married.', cid)
to
Code:
 npcHandler:say('Since both young souls are willing to marry, I now pronounce you, {' .. player:getName() .. '}, and {' .. getPlayerNameById(candidate) .. '} married.', cid)
Tiny typo, you wrote 'youngs instead of 'young'

I just tested it and it works perfectly. Too bad there are no rings though
 
Fixed the bugs reported and added the ring feature.

TODO:
- Don't allow a player to get married if he has not enough space to fit the rings.
- Only allow a wedding if the counterpart is online (otherwise both rings will have to go to the current player talking to the NPC, as it's happening now)
- Think about how to handle divorce regarding the rings. It's currently not breaking since the rings can be anywhere, not necessarily with the players.
 
Awesome work. Should add outfits when marrige is accepted if they have Wedding Box when they leave the rings.
 
Now, on events/scripts/player.lua, add the following piece of code after the local description variable is initialized in the method Player: onLook.
Code:
    if LOOK_MARRIAGE_DESCR and thing:isCreature() then
        if thing:isPlayer() then
            description = description .. self:getMarriageDescription(thing)
        end
    end
My events/scripts/player.lua dont have the local variable description :( look my player.lua
Code:
function Player:onLook(thing, position, distance)
    return true
end

function Player:onLookInTrade(partner, item, distance)
    return true
end

function Player:onLookInShop(itemType, count)
    return true
end
 
You have to update your TFS 1.0 as this has been already filled with code.
 
Worked like a charm, don't forgot to add the Priest npc in spawn-world.xml :)
 
Will use this for sure, thank you.

Kind Regards,
Eldin
.
 
which line do I add the events/scripts/player.lua

Code:
   if LOOK_MARRIAGE_DESCR and thing:isCreature() then
        if thing:isPlayer() then
            description = description .. self:getMarriageDescription(thing)
        end
    end
here is mine

Code:
function Player:onBrowseField(position)
    return true
end
 
function Player:onLook(thing, position, distance)
    local description = "You see " .. thing:getDescription(distance)
    if self:getGroup():getAccess() then
        if thing:isItem() then
            description = string.format("%s\nItemID: [%d]", description, thing:getId())
 
            local actionId = thing:getActionId()
            if actionId ~= 0 then
                description = string.format("%s, ActionID: [%d]", description, actionId)
            end
           
            local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_UNIQUEID)
            if uniqueId > 0 and uniqueId < 65536 then
                description = string.format("%s, UniqueId: [%d]", description, uniqueId)
            end
           
            description = description .. "."
            local itemType = thing:getType()
           
            local transformEquipId = itemType:getTransformEquipId()
            local transformDeEquipId = itemType:getTransformDeEquipId()
            if transformEquipId ~= 0 then
                description = string.format("%s\nTransformTo: [%d] (onEquip).", description, transformEquipId)
            elseif transformDeEquipId ~= 0 then
                description = string.format("%s\nTransformTo: [%d] (onDeEquip).", description, transformDeEquipId)
            end
 
            local decayId = itemType:getDecayId()
            if decayId ~= -1 then
                description = string.format("%s\nDecayTo: [%d]", description, decayId)
            end
        elseif thing:isCreature() then
            local str = "%s\nHealth: [%d / %d]"
            if thing:getMaxMana() > 0 then
                str = string.format("%s, Mana: [%d / %d]", str, thing:getMana(), thing:getMaxMana())
            end
            description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. "."
        end
       
        local position = thing:getPosition()
        description = string.format(
            "%s\nPosition: [X: %d] [Y: %d] [Z: %d].",
            description, position.x, position.y, position.z
        )
       
        if thing:isCreature() then
            if thing:isPlayer() then
                description = string.format("%s\nIP: [%s].", description, Game.convertIpToString(thing:getIp()))
            end
        end
    end
    self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end
 
function Player:onLookInBattleList(creature, distance)
    local description = "You see " .. creature:getDescription(distance)
    if self:getGroup():getAccess() then
        local str = "%s\nHealth: [%d / %d]"
        if creature:getMaxMana() > 0 then
            str = string.format("%s, Mana: [%d / %d]", str, creature:getMana(), creature:getMaxMana())
        end
        description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. "."
 
        local position = creature:getPosition()
        description = string.format(
            "%s\nPosition: [X: %d] [Y: %d] [Z: %d].",
            description, position.x, position.y, position.z
        )
       
        if creature:isPlayer() then
            description = string.format("%s\nIP: [%s].", description, Game.convertIpToString(creature:getIp()))
        end
    end
    self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end
 
function Player:onLookInTrade(partner, item, distance)
    self:sendTextMessage(MESSAGE_INFO_DESCR, "You see " .. item:getDescription(distance))
end
 
function Player:onLookInShop(itemType, count)
    return true
end
 
function Player:onMoveItem(item, count, fromPosition, toPosition)
    return true
end
 
function Player:onMoveCreature(creature, fromPosition, toPosition)
    return true
end
 
function Player:onTurn(direction)
    return true
end
 
function Player:onTradeRequest(target, item)
    return true
end
 
function Player:onTradeAccept(target, item, targetItem)
    return true
end
 
function Player:onGainExperience(source, exp, rawExp)
    return exp
end
 
function Player:onLoseExperience(exp)
    return exp
end

...and my last question is where is global.lua located?
(Now go on global.lua and add the following code:)
 
Help Me if must i instal uniServer but now i use xampp.
Y77jhS6.png
 
I think i made something wrong, the npc is working the system is working, but when someone tries to accept the proposal it says that i've already made one to a player called "ZERO" (0)
 
hello, i just installed this but in this part
Code:
if LOOK_MARRIAGE_DESCR and thing:isCreature() then
        if thing:isPlayer() then
            description = description .. self:getMarriageDescription(thing)
        end
    end

this gives me problem in console:

Code:
Lua Script Error: [Event Interface]
data/events/scripts/player.lua
data/events/scripts/player.lua:192: attempt to index global 'thing' (a nil value)
stack traceback:
        [C]: in function '__index'
        data/events/scripts/player.lua:192: in main chunk
[Warning - Events::load] Can not load script: player.lua

any ideas? D:
 
Code:
if LOOK_MARRIAGE_DESCR and thing:isCreature() then
        if thing:isPlayer() then
            description = description .. self:getMarriageDescription(thing)
        end
    end

find where thing is set to something, its giving an error because its empty.
thing = ?
 
The error is somewhere else in the script, post more.
are you sure? because this marriage part is the line that is wrong according to the console, i'll post the whole thing just in case
Code:
-- Players cannot throw items on teleports if set to true
local blockTeleportTrashing = false

function Player:onBrowseField(position)
    return true
end

function Player:onLook(thing, position, distance)
    local description = 'You see '
    if thing:isItem() then
        if thing.actionid == 5640 then
            description = description .. 'a honeyflower patch.'
        elseif thing.actionid == 5641 then
            description = description .. 'a banana palm.'
        else
            description = description .. thing:getDescription(distance)
        end
    elseif thing:isPlayer() then
        local rebirthStorage = 99997 -- CHANGE THIS SO YOU HAVE SAME STORAGE AS IN NPC FILE
        description = description .. thing:getDescription(distance)
        description = string.format('%s %s', description, "Rebirths [" .. thing:getStorageValue(rebirthStorage) .. "].")
    else
        description = description .. thing:getDescription(distance)
    end

    if self:getGroup():getAccess() then
        if thing:isItem() then
            description = string.format('%s\nItem ID: %d', description, thing.itemid)

            local actionId = thing.actionid
            if actionId ~= 0 then
                description = string.format('%s, Action ID: %d', description, actionId)
            end

            local uniqueId = thing:getAttribute(ITEM_ATTRIBUTE_UNIQUEID)
            if uniqueId > 0 and uniqueId < 65536 then
                description = string.format('%s, Unique ID: %d', description, uniqueId)
            end

            description = description .. '.'
            local itemType = thing:getType()

            local transformEquipId = itemType:getTransformEquipId()
            local transformDeEquipId = itemType:getTransformDeEquipId()
            if transformEquipId ~= 0 then
                description = string.format('%s\nTransforms to: %d (onEquip)', description, transformEquipId)
            elseif transformDeEquipId ~= 0 then
                description = string.format('%s\nTransforms to: %d (onDeEquip)', description, transformDeEquipId)
            end

            local decayId = itemType:getDecayId()
            if decayId ~= -1 then
                description = string.format('%s\nDecays to: %d', description, decayId)
            end
        elseif thing:isCreature() then
            local str = '%s\nHealth: %d / %d'
            if thing:getMaxMana() > 0 then
                str = string.format('%s, Mana: %d / %d', str, thing:getMana(), thing:getMaxMana())
            end
            description = string.format(str, description, thing:getHealth(), thing:getMaxHealth()) .. '.'
        end

        local position = thing:getPosition()
        description = string.format(
            '%s\nPosition: %d, %d, %d',
            description, position.x, position.y, position.z
        )

        if thing:isCreature() and thing:isPlayer() then
            description = string.format('%s\nIP: %s.', description, Game.convertIpToString(thing:getIp()))
        end
    end
    self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end

function Player:onLookInBattleList(creature, distance)
    local description = 'You see '
    if creature:isPlayer() then
        local rebirthStorage = 99997 -- CHANGE THIS SO YOU HAVE SAME STORAGE AS IN NPC FILE
        description = description .. creature:getDescription(distance)
        description = string.format('%s %s', description, "Rebirths [" .. creature:getStorageValue(rebirthStorage) .. "].")
    else
        description = description .. creature:getDescription(distance)
    end
    if self:getGroup():getAccess() then
        local str = '%s\nHealth: %d / %d'
        if creature:getMaxMana() > 0 then
            str = string.format('%s, Mana: %d / %d', str, creature:getMana(), creature:getMaxMana())
        end
        description = string.format(str, description, creature:getHealth(), creature:getMaxHealth()) .. '.'

        local position = creature:getPosition()
        description = string.format(
            '%s\nPosition: %d, %d, %d',
            description, position.x, position.y, position.z
        )

        if creature:isPlayer() then
            description = string.format('%s\nIP: %s.', description, Game.convertIpToString(creature:getIp()))
        end
    end
    self:sendTextMessage(MESSAGE_INFO_DESCR, description)
end

function Player:onLookInTrade(partner, item, distance)
    self:sendTextMessage(MESSAGE_INFO_DESCR, 'You see ' .. item:getDescription(distance))
end

function Player:onLookInShop(itemType, count)
    return true
end

function Player:onMoveCreature(creature, fromPosition, toPosition)
    return true
end

function Player:onTurn(direction)
    return true
end

function Player:onTradeRequest(target, item)
    if isInArray({1738, 1740, 1747, 1748, 1749, 8766}, item.itemid) and item.actionid > 0 or item.actionid == 5640 then
        self:sendCancelMessage('Sorry, not possible.')
        return false
    end
    return true
end

function Player:onTradeAccept(target, item, targetItem)
    return true
end

local soulCondition = Condition(CONDITION_SOUL, CONDITIONID_DEFAULT)
soulCondition:setTicks(4 * 60 * 1000)
soulCondition:setParameter(CONDITION_PARAM_SOULGAIN, 1)

local function useStamina(player)
    local staminaMinutes = player:getStamina()
    if staminaMinutes == 0 then
        return
    end

    local playerId = player:getId()
    local currentTime = os.time()
    local timePassed = currentTime - nextUseStaminaTime[playerId]
    if timePassed <= 0 then
        return
    end

    if timePassed > 60 then
        if staminaMinutes > 2 then
            staminaMinutes = staminaMinutes - 2
        else
            staminaMinutes = 0
        end
        nextUseStaminaTime[playerId] = currentTime + 120
    else
        staminaMinutes = staminaMinutes - 1
        nextUseStaminaTime[playerId] = currentTime + 60
    end
    player:setStamina(staminaMinutes)
end


if LOOK_MARRIAGE_DESCR and thing:isCreature() then
        if thing:isPlayer() then
            description = description .. self:getMarriageDescription(thing)
        end
    end


function Player:onGainExperience(source, exp, rawExp)
    if not source or source:isPlayer() then
        return exp
    end

    -- Soul regeneration
    local vocation = self:getVocation()
    if self:getSoul() < vocation:getMaxSoul() and exp >= self:getLevel() then
        soulCondition:setParameter(CONDITION_PARAM_SOULTICKS, vocation:getSoulGainTicks() * 1000)
        self:addCondition(soulCondition)
    end

    -- Apply experience stage multiplier
    exp = exp * Game.getExperienceStage(self:getLevel())

    -- Stamina modifier
    if configManager.getBoolean(configKeys.STAMINA_SYSTEM) then
        useStamina(self)

        local staminaMinutes = self:getStamina()
        if staminaMinutes > 2400 and self:isPremium() then
            exp = exp * 1.5
        elseif staminaMinutes <= 840 then
            exp = exp * 0.5
        end
    end

    return exp
end

function Player:onLoseExperience(exp)
    return exp
end

function Player:onTurn(direction)
    if self:getGroup():getAccess() and self:getAccountType() == ACCOUNT_TYPE_GOD and self:getDirection() == direction then
        local nextPosition = self:getPosition()
        nextPosition:getNextPosition(direction)

        self:teleportTo(nextPosition, true)
    end

    return true
end

function Player:onGainSkillTries(skill, tries)
    if APPLY_SKILL_MULTIPLIER == false then
        return tries
    end

    if skill == SKILL_MAGLEVEL then
        return tries * configManager.getNumber(configKeys.RATE_MAGIC)
    end
    return tries * configManager.getNumber(configKeys.RATE_SKILL)
end
 
Back
Top