• 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!
  • New resources must be posted under Resources tab. A discussion thread will be created automatically, you can't open threads manually anymore.

[Canary 3.0.0][13.21]Svargrond Arena + map

Draconis

Member
Joined
Aug 11, 2023
Messages
3
Reaction score
5
GitHub
whitecrixu
Hi All script for Svargrond Arena. Tested on Canary 3.0.0
First add NPC
data-server/npc/halvar.lua
LUA:
local internalNpcName = "Halvar"
local npcType = Game.createNpcType(internalNpcName)
local npcConfig = {}

npcConfig.name = internalNpcName
npcConfig.description = internalNpcName

npcConfig.health = 100
npcConfig.maxHealth = npcConfig.health
npcConfig.walkInterval = 2000
npcConfig.walkRadius = 2

npcConfig.outfit = {
    lookType = 143,
    lookHead = 3,
    lookBody = 77,
    lookLegs = 78,
    lookFeet = 39,
    lookAddons = 1,
}

npcConfig.flags = {
    floorchange = false,
}

local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)

npcType.onThink = function(npc, interval)
    npcHandler:onThink(npc, interval)
end

npcType.onAppear = function(npc, creature)
    npcHandler:onAppear(npc, creature)
end

npcType.onDisappear = function(npc, creature)
    npcHandler:onDisappear(npc, creature)
end

npcType.onMove = function(npc, creature, fromPosition, toPosition)
    npcHandler:onMove(npc, creature, fromPosition, toPosition)
end

npcType.onSay = function(npc, creature, type, message)
    npcHandler:onSay(npc, creature, type, message)
end

npcType.onCloseChannel = function(npc, creature)
    npcHandler:onCloseChannel(npc, creature)
end

keywordHandler:addKeyword({ "rules" }, StdModule.say, { npcHandler = npcHandler, text = "What do you want to know? Something about the three different {difficulties}, the {general} rules or the {prices}? Maybe you also want to know what happens when you {die}?" })
keywordHandler:addKeyword({ "difficulties" }, StdModule.say, { npcHandler = npcHandler, text = "There are three difficulties: Greenhorn, Scrapper and Warlord. On each challenge you will be confronted with ten monsters increasing in strength." })
keywordHandler:addKeyword({ "levels" }, StdModule.say, { npcHandler = npcHandler, text = "There are three difficulties: Greenhorn, Scrapper and Warlord. On each challenge you will be confronted with ten monsters increasing in strength." })
keywordHandler:addKeyword({ "difficulty" }, StdModule.say, { npcHandler = npcHandler, text = "There are three difficulties: Greenhorn, Scrapper and Warlord. On each challenge you will be confronted with ten monsters increasing in strength." })
keywordHandler:addKeyword({ "greenhorn" }, StdModule.say, { npcHandler = npcHandler, text = "That is the easiest way in our arena. The {fee} is 1000 gold. We were setting this up for of our children to challenge some easy monsters and train them for the future." })
keywordHandler:addKeyword({ "scrapper" }, StdModule.say, { npcHandler = npcHandler, text = "The most common difficulty for us. The {fee} is 5000 gold. So if you are experienced in fighting middle class monsters this is your challenge!" })
keywordHandler:addKeyword({ "warlord" }, StdModule.say, { npcHandler = npcHandler, text = "Only the strongest among us will take this challenge. The {fee} is 10000 gold. If you pass that I promise you the respect of all citizens here. You will be a hero!" })
keywordHandler:addKeyword({ "fee" }, StdModule.say, { npcHandler = npcHandler, text = "The fee is either 1000, 5000 or 10000 gold for one try. Remember that if you {die}, it is YOUR problem and you won't be able to get back to your corpse and your backpack." })
keywordHandler:addKeyword({ "die" }, StdModule.say, { npcHandler = npcHandler, text = "It would be better not to die! In every pit there is an emergency exit, the portal to the south. If you die in a pit... well... your corpse and backpack are gone, so you enter the arena at your own risk." })
keywordHandler:addKeyword({ "general" }, StdModule.say, { npcHandler = npcHandler, text = "Basically you pay me a {fee}, and you are sent into an arena with 10 different stages. If you succeed you will be rewarded accordingly." })
keywordHandler:addKeyword({ "job" }, StdModule.say, { npcHandler = npcHandler, text = "My job is to explain about the rules and to get the fee from the competitors." })
keywordHandler:addKeyword({ "mission" }, StdModule.say, { npcHandler = npcHandler, text = "Well I would rather call it an {Ultimate Challenge} than a mission." })

local function creatureSayCallback(npc, creature, type, message)
    local player = Player(creature)
    local playerId = player:getId()

    if not npcHandler:checkInteraction(npc, creature) then
        return false
    end

    local arenaId = player:getStorageValue(Storage.SvargrondArena.Arena)
    if MsgContains(message, "fight") or MsgContains(message, "pit") or MsgContains(message, "challenge") or MsgContains(message, "arena") then
        if player:getStorageValue(Storage.SvargrondArena.PitDoor) == 1 then
            npcHandler:say("You already paid the fee, go and fight!", npc, creature)
            return true
        end

        if arenaId < 1 then
            arenaId = 1
            player:setStorageValue(Storage.SvargrondArena.Arena, arenaId)
        end

        if ARENA[arenaId] then
            npcHandler:say("So you agree with the {rules} and want to participate in the {challenge}? The {fee} for one try in {" .. ARENA[arenaId].name .. "} is " .. ARENA[arenaId].price .. " gold pieces. Do you really want to participate and pay the {fee}?", npc, creature)
            npcHandler:setTopic(playerId, 1)
        else
            npcHandler:say("You've already completed the arena in all {difficulty levels}.", npc, creature)
            npcHandler:setTopic(playerId, 0)
        end
    elseif npcHandler:getTopic(playerId) == 1 then
        if MsgContains(message, "yes") then
            if not ARENA[arenaId] then
                npcHandler:setTopic(playerId, 0)
                return true
            end

            if player:removeMoneyBank(ARENA[arenaId].price) then
                player:setStorageValue(Storage.SvargrondArena.PitDoor, 1)
                npcHandler:say("As you wish! You can pass the door now and enter the teleporter to the pits.", npc, creature)

                local cStorage = ARENA[arenaId].questLog
                if player:getStorageValue(cStorage) ~= 1 then
                    player:setStorageValue(cStorage, 1)
                end
            else
                npcHandler:say("You do not have enough money.", npc, creature)
            end
        else
            npcHandler:say("Come back when you are ready then.", npc, creature)
        end
        npcHandler:setTopic(playerId, 0)
    end
    return true
end

npcHandler:setMessage(MESSAGE_GREET, "Hello competitor! Do you want to {fight} in the arena or shall I explain the {rules} first?")
npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new(), npcConfig.name, true, true, true)

-- npcType registering the npcConfig table
npcType:register(npcConfig)
Now we go to data-server/scripts/actions and on quest_system.lua we add
Code:
local specialQuests = {
    [51715] = Storage.SvargrondArena.RewardGreenhorn,

    [51716] = Storage.SvargrondArena.RewardScrapper,

    [51717] = Storage.SvargrondArena.RewardWarlord,
}
If you don't have this file you can use main
Code:
local specialQuests = {
    [51715] = Storage.SvargrondArena.RewardGreenhorn,
    [51716] = Storage.SvargrondArena.RewardScrapper,
    [51717] = Storage.SvargrondArena.RewardWarlord,
}

local questsExperience = {
    [3101] = 1, -- dummy values
}

local questLog = {

}

local tutorialIds = {
    [50080] = 5,
    [50082] = 6,
    [50084] = 10,
    [50086] = 11,
}

local function copyContainerItem(originalContainer, newContainer)
    for i = 0, originalContainer:getSize() - 1 do
        local originalItem = originalContainer:getItem(i)
        local newItem = Game.createItem(originalItem.itemid, originalItem.type)
        if not newItem then
            Spdlog.error("[questSystem1.copyContainerItem] failed to create item " .. originalItem.itemid)
            return false
        end
        newItem:setActionId(originalItem:getActionId())
        newItem:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, originalItem:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION))

        if originalItem:isContainer() then
            copyContainerItem(Container(originalItem.uid), Container(newItem.uid))
        end
        newContainer:addItemEx(newItem)
    end
end

local hotaQuest = { 50950, 50951, 50952, 50953, 50954, 50955 }

local questSystem1 = Action()

function questSystem1.onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local storage = specialQuests[item.actionid]
    if not storage then
        storage = item.uid
        if storage > 65535 then
            return false
        end
    end

    if storage == 23644 or storage == 24632 or storage == 14338 then
        player:setStorageValue(Storage.SvargrondArena.PitDoor, -1)
    end

    if player:getStorageValue(storage) > 0 and player:getGroup():getId() < GROUP_TYPE_GAMEMASTER then
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "The " .. ItemType(item.itemid):getName() .. " is empty.")
        return true
    end

    local items, reward = {}
    local size = item:isContainer() and item:getSize() or 0
    if size == 0 then
        reward = Game.createItem(item.itemid, item.type)
        if not reward then
            logger.error("[questSystem1.onUse] failed to create reward item")
            return false
        end

        local itemActionId = item:getActionId()
        if itemActionId then
            reward:setActionId(itemActionId)
        end
        local itemDescription = item:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
        if itemDescription then
            reward:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, itemDescription)
        end
    else
        local container = Container(item.uid)
        if not container then
            logger.error("[questSystem1.onUse] failed to create container")
            return false
        end
        for i = 0, container:getSize() - 1 do
            local originalItem = container:getItem(i)
            local newItem = Game.createItem(originalItem.itemid, originalItem.type)
            if not newItem then
                logger.error("[questSystem1.onUse] failed to create new item")
                return false
            end
            local newActionId = originalItem:getActionId()
            if newActionId then
                newItem:setActionId(newActionId)
            end
            local newDescription = item:getAttribute(ITEM_ATTRIBUTE_DESCRIPTION)
            if newDescription then
                newItem:setAttribute(ITEM_ATTRIBUTE_DESCRIPTION, newDescription)
            end

            if originalItem:isContainer() then
                copyContainerItem(Container(originalItem.uid), Container(newItem.uid))
            end
            items[#items + 1] = newItem
        end

        if size == 1 then
            reward = items[1]
        end
    end

    local result = ""
    if reward then
        local ret = ItemType(reward.itemid)
        if ret:isRune() then
            result = ret:getArticle() .. " " .. ret:getName() .. " (" .. reward.type .. " charges)"
        elseif ret:isStackable() and reward:getCount() > 1 then
            result = reward:getCount() .. " " .. ret:getPluralName()
        elseif ret:getArticle() ~= "" then
            result = ret:getArticle() .. " " .. ret:getName()
        else
            result = ret:getName()
        end
    else
        if size > 20 then
            reward = Game.createItem(item.itemid, 1)
        elseif size > 8 then
            reward = Game.createItem(2854, 1)
        else
            reward = Game.createItem(2853, 1)
        end

        for i = 1, size do
            local tmp = items[i]
            if reward:addItemEx(tmp) ~= RETURNVALUE_NOERROR then
                logger.warn("[questSystem1.onUse] - Could not add quest reward to container")
            end
        end
        local ret = ItemType(reward.itemid)
        result = ret:getArticle() .. " " .. ret:getName()
    end

    if player:addItemEx(reward) ~= RETURNVALUE_NOERROR then
        local weight = reward:getWeight()
        if player:getFreeCapacity() < weight then
            player:sendCancelMessage(string.format("You have found %s weighing %.2f oz. You have no capacity.", result, (weight / 100)))
        else
            player:sendCancelMessage("You have found " .. result .. ", but you have no room to take it.")
        end
        return true
    end

    if questsExperience[storage] then
        player:addExperience(questsExperience[storage], true)
    end

    if questLog[storage] then
        player:setStorageValue(questLog[storage], 1)
    end

    if tutorialIds[storage] then
        player:sendTutorial(tutorialIds[storage])
        if item.uid == 50080 then
            player:setStorageValue(Storage.RookgaardTutorialIsland.SantiagoNpcGreetStorage, 3)
        end
    end

    if table.contains(hotaQuest, item.uid) then
        if player:getStorageValue(Storage.TheAncientTombs.DefaultStart) ~= 1 then
            player:setStorageValue(Storage.TheAncientTombs.DefaultStart, 1)
        end
    end

    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You have found " .. result .. ".")
    player:setStorageValue(storage, 1)
    return true
end

for index, value in pairs(specialQuests) do
    questSystem1:aid(index)
end

questSystem1:aid(2000)
questSystem1:register()
Now we create on data-server/scripts/creaturescripts/ file arena_kill.lua
LUA:
local svargrondArenaKill = CreatureEvent("SvargrondArenaKill")
function svargrondArenaKill.onKill(creature, target)
    local targetMonster = target:getMonster()
    if not targetMonster then
        return
    end

    local player = creature:getPlayer()
    local pit = player:getStorageValue(Storage.SvargrondArena.PitDoor)
    if pit < 1 or pit > 10 then
        return
    end

    local arena = player:getStorageValue(Storage.SvargrondArena.Arena)
    if arena < 1 then
        return
    end

    if not table.contains(ARENA[arena].creatures, targetMonster:getName():lower()) then
        return
    end

    -- Remove pillar and create teleport
    local pillarTile = Tile(PITS[pit].pillar)
    if pillarTile then
        local pillarItem = pillarTile:getItemById(SvargrondArena.itemPillar)
        if pillarItem then
            pillarItem:remove()

            local teleportItem = Game.createItem(SvargrondArena.itemTeleport, 1, PITS[pit].tp)
            if teleportItem then
                teleportItem:setActionId(25200)
            end

            SvargrondArena.sendPillarEffect(pit)
        end
    end
    player:setStorageValue(Storage.SvargrondArena.PitDoor, pit + 1)
    player:say("Victory! Head through the new teleporter into the next room.", TALKTYPE_MONSTER_SAY)
    return true
end

svargrondArenaKill:register()
now we go to movements data-server/scripts/movements and create file arena_enter.lua
LUA:
local arenaEnter = MoveEvent()

function arenaEnter.onStepIn(creature, item, position, fromPosition)
    local player = creature:getPlayer()
    if not player then
        return true
    end

    local pitId = player:getStorageValue(Storage.SvargrondArena.PitDoor)
    if pitId < 1 or pitId > 10 then
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "You cannot enter without Halvar's permission.")
        player:teleportTo(fromPosition, true)
        return true
    end

    local arenaId = player:getStorageValue(Storage.SvargrondArena.Arena)
    if not (PITS[pitId] and ARENA[arenaId]) then
        player:teleportTo(fromPosition, true)
        return true
    end

    local occupant = SvargrondArena.getPitOccupant(pitId, player)
    if occupant then
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, occupant:getName() .. " is currently in the next arena pit. Please wait until " .. (occupant:getSex() == PLAYERSEX_FEMALE and "s" or "") .. "he is done fighting.")
        player:teleportTo(fromPosition, true)
        return true
    end
    SvargrondArena.resetPit(pitId)
    SvargrondArena.scheduleKickPlayer(player.uid, pitId)
    Game.createMonster(ARENA[arenaId].creatures[pitId], PITS[pitId].summon, false, true)

    player:teleportTo(PITS[pitId].center)
    player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
    player:say("FIGHT!", TALKTYPE_MONSTER_SAY)
    return true
end

arenaEnter:type("stepin")
arenaEnter:aid(25100)
arenaEnter:register()
and arena_pit.lua
LUA:
local condition = Condition(CONDITION_OUTFIT)
condition:setTicks(120000)
condition:setOutfit({ lookType = 111 })

local arenaPit = MoveEvent()

function arenaPit.onStepIn(creature, item, position, fromPosition)
    local player = creature:getPlayer()
    if not player then
        return true
    end

    local playerId = player.uid
    if item.actionid == 25300 then
        player:addCondition(condition)

        player:setStorageValue(Storage.SvargrondArena.PitDoor, -1)
        player:teleportTo(SvargrondArena.kickPosition)
        player:say("Coward!", TALKTYPE_MONSTER_SAY)
        SvargrondArena.cancelEvents(playerId)
        return true
    end

    local pitId = player:getStorageValue(Storage.SvargrondArena.PitDoor)
    local arenaId = player:getStorageValue(Storage.SvargrondArena.Arena)
    if pitId > 10 then
        player:teleportTo(SvargrondArena.rewardPosition)
        player:setStorageValue(Storage.SvargrondArena.PitDoor, 0)

        if arenaId == 1 then
            SvargrondArena.rewardPosition:sendMagicEffect(CONST_ME_FIREWORK_BLUE)
            player:setStorageValue(Storage.SvargrondArena.GreenhornDoor, 1)
            player:say("Welcome back, little hero!", TALKTYPE_MONSTER_SAY)
        elseif arenaId == 2 then
            SvargrondArena.rewardPosition:sendMagicEffect(CONST_ME_FIREWORK_YELLOW)
            player:setStorageValue(Storage.SvargrondArena.ScrapperDoor, 1)
            player:say("Congratulations, brave warrior!", TALKTYPE_MONSTER_SAY)
        elseif arenaId == 3 then
            SvargrondArena.rewardPosition:sendMagicEffect(CONST_ME_FIREWORK_RED)
            player:setStorageValue(Storage.SvargrondArena.WarlordDoor, 1)
            player:say("Respect and honour to you, champion!", TALKTYPE_MONSTER_SAY)
        end

        player:setStorageValue(Storage.SvargrondArena.Arena, player:getStorageValue(Storage.SvargrondArena.Arena) + 1)
        player:say("Congratulations! You completed " .. ARENA[arenaId].name .. " arena, you should take your reward now.")
        player:setStorageValue(ARENA[arenaId].questLog, 2)
        player:addAchievement(ARENA[arenaId].achievement)
        SvargrondArena.cancelEvents(playerId)
        return true
    end

    local occupant = SvargrondArena.getPitOccupant(pitId, player)
    if occupant then
        player:sendTextMessage(MESSAGE_EVENT_ADVANCE, occupant:getName() .. " is currently in the next arena pit. Please wait until " .. (occupant:getSex() == PLAYERSEX_FEMALE and "s" or "") .. "he is done fighting.")
        player:teleportTo(fromPosition, true)
        return true
    end

    SvargrondArena.cancelEvents(playerId)
    SvargrondArena.resetPit(pitId)
    SvargrondArena.scheduleKickPlayer(playerId, pitId)
    Game.createMonster(ARENA[arenaId].creatures[pitId], PITS[pitId].summon, false, true)

    player:teleportTo(PITS[pitId].center)
    player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
    player:say("Fight!", TALKTYPE_MONSTER_SAY)
    return true
end

arenaPit:type("stepin")
arenaPit:aid(25200, 25300)
arenaPit:register()
and arena_trophy.lua
LUA:
local arenaTrophy = MoveEvent()

function arenaTrophy.onStepIn(creature, item, position, fromPosition)
    local player = creature:getPlayer()
    if not player then
        return true
    end

    local arenaId = ARENA_TROPHY[item.uid]
    if not arenaId then
        return true
    end

    local storage = arenaId.trophyStorage
    if player:getStorageValue(storage) == 1 then
        return true
    end

    local rewardPosition = player:getPosition()
    rewardPosition.y = rewardPosition.y - 1

    local rewardItem = Game.createItem(arenaId.trophy, 1, rewardPosition)
    if rewardItem then
        rewardItem:setDescription(string.format(arenaId.desc, player:getName()))
    end

    player:setStorageValue(storage, 1)
    player:getPosition():sendMagicEffect(CONST_ME_MAGIC_RED)
    return true
end

arenaTrophy:type("stepin")
arenaTrophy:uid(3264, 3265, 3266)
arenaTrophy:register()
now we go to data-server/startup/door_quest.lua
LUA:
    -- Svargrond arena door
    [Storage.SvargrondArena.PitDoor] = {
        itemId = false,
        itemPos = {
            { x = 5042, y = 5040, z = 7 },
            { x = 5042, y = 5041, z = 7 },
            { x = 5042, y = 5042, z = 7 },
        },
    },
    [Storage.SvargrondArena.GreenhornDoor] = {
        itemId = false,
        itemPos = { { x = 5036, y = 5008, z = 7 } },
    },
    [Storage.SvargrondArena.ScrapperDoor] = {
        itemId = false,
        itemPos = { { x = 5036, y = 5001, z = 7 } },
    },
    [Storage.SvargrondArena.WarlordDoor] = {
        itemId = false,
        itemPos = { { x = 5036, y = 4994, z = 7 } },
    },
Screenshot_2023-10-31_14-23-47.png

All scipts and map is compatibile with Canary 3.0.0
All my scripts and map you find on my github
Everything is compatibile with my maps if you want use on your own you have to configure on youself.
Any question send me PM
NOT TESTED ON TFS
 

Attachments

Last edited:
Back
Top