• 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
15
Reaction score
10
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

Top