• 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.X] Castle War Event (stand on the throne)

worthdavi

Member
Joined
Aug 17, 2019
Messages
23
Solutions
1
Reaction score
22
Location
Brazil
GitHub
worthdavi
Hello,
I made this event few years ago and since it's already free on internet because of some open source maniacs, I brought it to here
I have seen people selling it like it was of their own, so to avoid that, here it is
Let me me know if some code is missing. Too much time w/o seeing this code xD

The map position is already set and being loaded by the startup event, so you do not have to change anything.

Also I made a page to see castle info. It is compatible with gesior only. Ill upload it on this thread.


Here it is some images of the castle:

1623422569096.png
1623422581196.png
Since the arena is a simple square beside the castle, I do not have any screenshot of it xD.


In globalevents.xml
XML:
<!-- Castle -->
<globalevent name="startCastle" time="21:00" script="events/castle/start.lua" />
<globalevent name="loadEventMaps" type="startup" script="events/maps/load_maps.lua"/>

In /globalevents/scripts/events/castle/start.lua
Lua:
local config = {
    semana_mes = "semana",
    days = {1, 2, 3, 4, 5, 6, 7},
}

local function warnEvent(i, minutes)
    Game.broadcastMessage("[Castle]\nThe event will begin in ".. minutes .. " minutes! The teleport is located at event room.")
    if i > 1 then
        addEvent(warnEvent, 2 * 60 * 1000, i - 1, minutes - 2)
    end
end

local function openCastle()
    Castle:Open()
end

local function closeCastle()
    Castle:Close()
end

function onTime(interval)
local time = os.sdate("*t")
    if (config.semana_mes == "semana" and isInArray(config.days,time.wday)) or (config.semana_mes == "mes" and isInArray(config.days,time.day)) or config.semana_mes == "" then
        Game.broadcastMessage("[Castle]\nThe event will begin in 10 minutes! The teleport is located at event room.")
        addEvent(warnEvent, 2 * 60 * 1000, 4, 8) 
        addEvent(openCastle, 10 * 60 * 1000)
        addEvent(closeCastle, (10 + 10) * 60 * 1000)
    end
    return true
end

In /globalevents/scripts/events/maps/load_maps.lua
Lua:
local config = {
    [1] = {event = "Castle", map = "castle"},
}

function onStartup()
    
    for i = 1, #config do
        Game.loadMap('data/world/worldchanges/additionals/' .. config[i].map ..'.otbm')
        print('>> ['..config[i].event..'] Map ' .. config[i].map .. ' loaded.')
    end
    return true
end

In creaturescripts.xml
XML:
<!-- Castle -->
<event type="think" name="Castle" script="events/castle/castle_events.lua" />

In /creaturescripts/scripts/events/castle/castle_events.lua
Lua:
function onThink(p, interval)       
    if not p:isPlayer() or p:getPosition() ~= CASTLE_INFO.THRONE_POSITION then
        p:unregisterEvent('Castle')
        return true
    end
    local health = (p:getHealth()*100)/p:getMaxHealth()
    local pts = math.max(p:getStorageValue(CASTLE_INFO.STORAGE), 0)
    local amount = 1
    for i = 1, #CASTLE_INFO.CONDITIONS do
        if health <= CASTLE_INFO.CONDITIONS[i].HEALTH then
            amount = CASTLE_INFO.CONDITIONS[i].AMOUNT
        end
    end
    p:setStorageValue(CASTLE_INFO.STORAGE, pts + amount)
    p:say(pts, TALKTYPE_MONSTER_SAY)
    return true
end

In movements.xml
XML:
<!-- Castle -->
<movevent event="StepIn" actionid="4505" script="events/castle/castle_teleport.lua" />
<movevent event="StepOut" actionid="4505" script="events/castle/castle_teleport.lua" />

In /movements/scripts/events/castle/castle_teleport.lua
Lua:
local delay = 3

local function doRegen(playerid, isBlock)
    local regen = addEvent(function(pid)
        local c = Creature(pid)
        if c and c:isPlayer() then
            if not isBlock then
                if Tile(c:getPosition()):getGround():getActionId() == 4505 then
                    c:addMana(c:getVocation():getManaGainAmount())
                    c:addHealth(c:getVocation():getHealthGainAmount())
                    doRegen(c:getId(), false)
                else
                    stopEvent(regen)
                end
            else
                stopEvent(regen)
            end
        end
    end, delay*1000, playerid)
end
            
function onStepIn(creature, item, position, fromPosition)
    if not creature:isPlayer() then
        return true
    end
    if position == CASTLE_INFO.THRONE_POSITION then
        Castle:onStepIn(creature)
    else
        doRegen(creature:getId(), false)
    end
    return true
end

function onStepOut(creature, item, position, fromPosition)
    if not creature:isPlayer() then
        return true
    end
    if position == CASTLE_INFO.THRONE_POSITION then
        Castle:onStepOut(creature)
    else
        doRegen(creature:getId(), true)
    end
    return true
end

In /libs/libs.lua
Lua:
dofile('data/lib/events/events.lua')
dofile('data/lib/events/castle.lua')

In /lib/events/castle.lua
Lua:
function Guild.getMembersGuid(self)
    local guildMembers = {}
    local queryStr = string.format("SELECT `players`.`name` AS 'name' FROM `players` INNER JOIN `guild_membership` ON (`players`.`id` = `guild_membership`.`player_id`) WHERE `guild_membership`.`guild_id` = %d;", self:getId())
    local resultId = db.storeQuery(queryStr)
    if resultId ~= false then
        repeat
            local val = result.getString(resultId, "name")
            table.insert(guildMembers, val)
        until not result.next(resultId)
    end
    result.free(resultId)
    return guildMembers
end

CASTLE_INFO = {
    STORAGE = 696969,
    CONDITIONS = {
        [1] = {HEALTH = 99, AMOUNT = 1},
        [2] = {HEALTH = 50, AMOUNT = 2},
        [3] = {HEALTH = 30, AMOUNT = 3}
    },
    THRONE_POSITION = Position(31369, 32657, 7),
    REWARD = {id = 15515, qnt = 15}
}

if not Castle then
    Castle = {
        open = false,       
        channel_id = 12,
        
        positionsArena = {
            fromPosition = Position(31355, 32645, 7),
            toPosition = Position(31383, 32669, 7)
        },       
        gatesArena = {
            [1] = Position(31336, 32683, 7),
            [2] = Position(31336, 32682, 7)
        },
        vortexArena = {
            [1] = Position(31337, 32682, 7),
            [2] = Position(31337, 32683, 7)
        },
        
        vortexToPosition = {
            [1] = Position(31358, 32667, 7), 
            [2] = Position(31380, 32648, 7) 
        },
        
        closedId = 5735,
        castleHouseId = 2500, -- Castle house id (important!)
            
        -- Config
        blockMC = true,
        minLevel = 0,
        warnInterval = 2 -- minutes between announce the top 1
    }
    
    function Castle:getTop(isTheLast)
        local maior = 0
        local winner = 0
        for _, player in pairs(Game.getPlayers()) do
            if isTheLast then
                player:unregisterEvent('Castle')
            end
            if player:getStorageValue(CASTLE_INFO.STORAGE) > maior then
                maior = player:getStorageValue(CASTLE_INFO.STORAGE)
                winner = player:getId()
            end
        end
        return winner
    end
    
    function Castle:warnRanks()
        if not self.open then
            return false
        end
        addEvent(function()
            local pid = self:getTop()
            local player = Player(pid)
            if player then
                Game.sendEventMessage(string.format('The player %s is winning the castle with %d points! Hurry up!', player:getName(), player:getStorageValue(CASTLE_INFO.STORAGE)))
            else
                Game.sendEventMessage(string.format('No one got any points yet! Hurry up!'))
            end
            return self:warnRanks()
        end, self.warnInterval*60*1000)
    end
    
    function Castle:Open()
        if self.open then
            return false
        end
        self.open = true       
        broadcastMessage("[Castle]\nThe event has just started!")
        Game.openEventChannel("Castle")
        self:warnRanks()
        for i = 1, #self.gatesArena do
            local closed = Tile(self.gatesArena[i]):getItemById(self.closedId)
            if closed then
                closed:transform(self.closedId - 1)
            end
        end
        for i = 1, #self.vortexArena do
            local teleport = Tile(self.vortexArena[i]):getItemById(1387)
            if not teleport then
                local item = Game.createItem(1387, 1, self.vortexArena[i])
                if item then
                    item:setDestination(self.vortexToPosition[i])
                end
            end
        end               
        return true
    end

    function Castle:Close()
        if not self.open then
            return false
        end       
        self.open = false       
        local pid = self:getTop(true)
        local winner = Player(pid)
        if winner then
            broadcastMessage(string.format("[Castle]\nThe event has ended!\nThe winner was: %s, with %d points!", winner:getName(), winner:getStorageValue(CASTLE_INFO.STORAGE)))
            setHouseOwner(self.castleHouseId, 0)
            setHouseOwner(self.castleHouseId, winner:getGuid())
            winner:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Congratulations!\nNow you are the new owner of the castle!")
            winner:addItem(CASTLE_INFO.REWARD.id, CASTLE_INFO.REWARD.qnt)
            local guild = winner:getGuild()
            if guild then
                guild:broadcastMessage("Your guild has won the castle event!", MESSAGE_EVENT_ADVANCE)
                local house = House(self.castleHouseId)
                if house then
                    local memberList = guild:getMembersGuid()
                    local inviteList = ""
                    if memberList then
                        for i = 1, #memberList do
                            inviteList = inviteList .. memberList[i] .. "\n"
                        end
                        house:setAccessList(GUEST_LIST, inviteList)
                    end   
                end
            end
        else
            broadcastMessage(string.format("[Castle]\nThe event has ended!\nNo one won the event. :("))
            setHouseOwner(self.castleHouseId, 0)
        end
        for i = 1, #self.gatesArena do
            local closed = Tile(self.gatesArena[i]):getItemById(self.closedId-1)
            if closed then
                closed:transform(self.closedId)
            end
        end
        for i = 1, #self.vortexArena do
            local teleport = Tile(self.vortexArena[i]):getItemById(1387)
            if teleport then
                teleport:remove()
            end
        end   
        return true
    end
    
    function Castle:onStepIn(creature)
        if not self.open then
            return false
        end
        creature:registerEvent('Castle')
        return true
    end
    
    function Castle:onStepOut(creature)
        creature:unregisterEvent('Castle')
        return true
    end
end

In /lib/events/events.lua
Lua:
CHANNEL_EVENTS = 12

function Game.openEventChannel(event, channelId)
    if not channelId then
        channelId = CHANNEL_EVENTS
    end
    for _, player in pairs(Game.getPlayers()) do
        player:openChannel(channelId)
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, string.format("The event %s has began.", event))
    end
    return true
end

function Game.sendEventMessage(mensagem, canal)
    if not canal then
        canal = CHANNEL_EVENTS
    end
    for _, pid in pairs(Game.getPlayers()) do
        Player(pid):sendChannelMessage("", mensagem, TALKTYPE_CHANNEL_O, canal)
    end
    return true
end

In chatchannels.xml
XML:
<channel id="12" name="Events" script="events.lua" />

In /chatchannels/scripts/events.lua
Lua:
function onSpeak(cid, type, message)
    local playerGroup = getPlayerGroupId(cid)
    if playerGroup == 1 then
        doPlayerSendCancel(cid, "You are not allowed to send messages on this channel.")
        return false
    end

    if playerGroup <= 1 then
        type = TALKTYPE_CHANNEL_Y
    elseif playerGroup > 1 and playerGroup <= 9 then
        type = TALKTYPE_CHANNEL_O
    else
        type = TALKTYPE_CHANNEL_R1
    end
    
    return type
end
 

Attachments

Fantastic script ... if I want to run it 3 times a day where I change it because when I repeat the event the count does not reset only increases.
 
Fantastic script ... if I want to run it 3 times a day where I change it because when I repeat the event the count does not reset only increases.
Every time the event ends, you can execute that:
Lua:
for _, creature in pairs(Game.getPlayers()) do
    if creature then
        creature:setStorageValue(CASTLE_INFO.STORAGE, 0)
    end
end
-- To work on offline players
db.query('UPDATE `player_storage` SET `value` = 0 WHERE `player_storage`.`key` = '..CASTLE_INFO.STORAGE..'')

Work in otservbr-global ? in RevScript?

I do not know anything about otservbr-global, but it probably works there either. You would change onThink, onStepIn/Out function or something like that.
 
Cada vez que o evento termina, você pode executar:
[CODE = lua] para _, criatura em pares (Game.getPlayers ()) faz
se criatura então
criatura: setStorageValue (CASTLE_INFO.STORAGE, 0)
fim
fim
- Para trabalhar em jogadores offline
db.query ('UPDATE player_storage SET` value` = 0 WHERE player_storagekey =' ..CASTLE_INFO.STORAGE .. '') [/ CODE]



Não sei nada sobre o otservbr-global, mas provavelmente também funciona lá. Você mudaria a função onThink, onStepIn / Out ou algo parecido.

100%! ty.
 
Last edited:
Cool! Are you available for jobs?
sure, in lua.

can u explain how does this event works?
ithink link is dead
Post automatically merged:

@Morrison stop loving me
basically the timed globalevent opens the castle arena gates, then the one who stands on the throne for more time wins the event.
its a "push" war, where the reward is the castle (a huge house with some features inside)
since this ot is already offline, try this one: Castle War - Easy Global (https://easyglobal.online/?castlewar)
 
sure, in lua.


basically the timed globalevent opens the castle arena gates, then the one who stands on the throne for more time wins the event.
its a "push" war, where the reward is the castle (a huge house with some features inside)
Does the owner resets or something on each event?
 
Does the owner resets or something on each event?
Depending on wich days you're running the event, it will reset the house owner to set the new winner
As long as the common event runs once a day, to reset everyone's points you can just add this line on startup.lua

Lua:
db.query('UPDATE `player_storage` SET `value` = 0 WHERE `player_storage`.`key` = '..CASTLE_INFO.STORAGE..'')

I forgot to say that on the post xD
 
hey friend, I had a small error, could you help me? I have this message in the console , grateful!
using tfs 1.4.2

Lua Script Error: [GlobalEvent Interface]
data/globalevents/scripts/events/castle/start.lua:eek:nTime
data/globalevents/scripts/events/castle/start.lua:22: attempt to call field 'sdate' (a nil value)
stack traceback:
[C]: in function 'sdate'
data/globalevents/scripts/events/castle/start.lua:22: in function <data/globalevents/scripts/events/castle/start.lua:21>


edit:error resolved by: @Mateus Robeerto , grateful brother
 
Last edited:
Does the owner resets or something on each event?
My friend, do you understand how this castle works? I know it's a battle of thrones, but I installed it correctly and I can't edit it
Post automatically merged:

sure, in lua.


basically the timed globalevent opens the castle arena gates, then the one who stands on the throne for more time wins the event.
its a "push" war, where the reward is the castle (a huge house with some features inside)
since this ot is already offline, try this one: Castle War - Easy Global (https://easyglobal.online/?castlewar)
this link doesn't work
 
Last edited:
I can't find the map with the coordinates you posted. What are the coordinates?
the map does not only appear externally, you will have to import it into your map editor for its coordinates to appear, 31494x32720 these are the coordinates but you will not find it in the map editor just if you import!
 
Back
Top