• 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.2 - PVP Arena (Based on real tibia's new arenas)

Michael Orsino

Premium User
Premium User
Support Team
Joined
Nov 15, 2007
Messages
854
Solutions
10
Reaction score
389
Location
Santiago, Chile (Australian)
Okay so this is an NPC that I think a lot of people hosting real maps would want, but personally I'd like it for my war server.
http://tibia.wikia.com/wiki/Duelling_Arena

I've included the info quoted below, striked out everything I personally don't care about.
If someone is going to create this NPC though, they should probably create it with all the features. I guess. I just don't care about a lot of them.

Duelling arenas, introduced in Updates/10.90, are locations where players can fight in a controlled setting with little risk.

The arenas are located in Ankrahmun, Kazordoon, Thais, Edron and Rathleton.

  • Each arena fight will be set up by one One Premium account player. By talking to an NPC he picks a battle type and sets the details.
  • There are time limits for fights and the waiting periods.
  • After a fight, participants are blocked from fights for some time before they can battle again.
  • During the waiting period, players can decide against participation by leaving the waiting area. The only way out of a battle, though, is either death, victory, or a battle time out.
  • PvP features like friendly fire will match the PvP options of your game world type. However, all kills in an arena will be justified. An arena death does not count as a frag in guild wars, and the usual death penalty will not be applied in arena fights.
  • All arenas have the same size but different layouts with obstacles and different speed floor tiles.
  • Non-combatants can view the fights from a Protection Zone above the arena; Rathleton also has a PZ in the middle of the arena accessible by rope hole.
Before fights, players will have to choose a battle mode. There are two different types:
  • Last Man Standing
    • The initiator determines an entrance fee and how many players will fight.
    • He is teleported into a waiting area, other players will follow him manually. The battle starts when enough players have arrived.
    • All participants are teleported into the battle ground to fight against each other.
    • The entrance fee will be deducted from the bank accounts of participants.
    • The fight lasts until only one character is left.
    • The winner gets all the money that was deducted from everybody in the beginning, the losers will have lost the money but nothing else.
  • Team Deathmatch
    • The initiator sets the entrance fee, the team sizes, and enters the character names for each team.
    • The two teams will gather in the waiting area, each team in a separate room.
    • When everybody on the team lists has arrived, all participants are teleported into the battle ground to fight.
    • The entrance fee will be deducted from the bank accounts of participants.
    • The fight lasts until only members from one team are still alive.
    • The money that was deducted from everybody in the beginning will now be divided equally and automatically among all members of the winning team, regardless of whether they died during the fight or not. The members of the losing team will have lost the money but nothing else.
    • In this mode, specific 1 vs 1 fights are possible. To duel your friend, just set the team size to 1 and enter your friend's character name on the opponent list at the NPC.

I started writing one based on the same concept...Unfortunately I'm not a great scripter. I'll post my code below anyway. It works but was only ever going to be a very basic implementation. A first draft. I decided it's above my skill level though :p


Code:
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talkState = {}

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

function isInRange(position, fromPosition, toPosition)
  return (position.x >= fromPosition.x and position.y >= fromPosition.y and position.z >= fromPosition.z and position.x <= toPosition.x and position.y <= toPosition.y and position.z <= toPosition.z)
end

local function end_event()
    local arena_area = {
    {x=1024, y=822, z=7, stackpos = 255},
    {x=1044, y=842, z=7, stackpos = 255}
    }
    local players = Game.getPlayers()

    Game.setStorageValue(battleArenaStor, 0)

    for i = 1, #players do
        player = players[i]
        if isInRange(player:getPosition(), arena_area[1], arena_area[2]) == TRUE then
                  local newTemple = Game.getStorageValue(currentMap)
                  local pos, player = mapPositions[newTemple]
                player = players[i]
            player:teleportTo(pos)
                  player:addHealth(player:getMaxHealth())
                  player:addMana(player:getMaxMana())
                  local tmp = {CONDITION_POISON, CONDITION_FIRE, CONDITION_ENERGY, CONDITION_BLEEDING, CONDITION_PARALYZE, CONDITION_INVISIBLE, CONDITION_MANASHIELD, CONDITION_INFIGHT, CONDITION_DRUNK, CONDITION_DROWN, CONDITION_ATTRIBUTES, CONDITION_FREEZING, CONDITION_DAZZLED, CONDITION_CURSED, CONDITION_PACIFIED, CONDITION_SPELLCOOLDOWN, CONDITION_SPELLGROUPCOOLDOWN}
                  for i = 1, #tmp do
                    player:removeCondition(tmp[i])
                  end
        end
    end
    return true
end

local function start_event()
    local team1 = {
    {x=1021, y=849, z=7, stackpos = 255},
    {x=1027, y=855, z=7, stackpos = 255}
    }
    local team1Pos = {x=1033, y=832, z=7, stackpos = 255}
    local team2 = {
    {x=1040, y=849, z=7, stackpos = 255},
    {x=1046, y=855, z=7, stackpos = 255}
    }
    local team2Pos = {x=1035, y=832, z=7, stackpos = 255}
    local players = Game.getPlayers()

    for i = 1, #players do
        player = players[i]
        if isInRange(player:getPosition(), team1[1], team1[2]) == TRUE then
            player:teleportTo(team1Pos)
        end
        if isInRange(player:getPosition(), team2[1], team2[2]) == TRUE then
            player:teleportTo(team2Pos)
        end
        player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Battle has started! This battle will last 30 minutes.")
        addEvent(end_event, 1800000)      
    end
end

function creatureSayCallback(cid, type, msg)
    if(not npcHandler:isFocused(cid)) then
        return false
    end

    local talkUser = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid

    if(msgcontains(msg, 'fight') or msgcontains(msg, 'battle')) then
        selfSay('Do you want to start a team battle?', cid)
        talkState[talkUser] = 1
    elseif(msgcontains(msg, 'yes') and talkState[talkUser] == 1) then
        if Game.getStorageValue(battleArenaStor) ~= 0 then
            selfSay('A battle is currently in progress. Please wait until it ends.', cid)
            talkState[talkUser] = 0
            else
            selfSay('Okay. You have 2 minutes to prepare. Stand in the team waiting rooms.', cid)
            addEvent(start_event, 120000)
            Game.setStorageValue(battleArenaStor, 1)
        end
    talkState[talkUser] = 0
    elseif(msgcontains(msg, 'no') and isInArray({1}, talkState[talkUser]) == TRUE) then
        talkState[talkUser] = 0
        selfSay('Ok then.', cid)
    end
    return true
end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())
 
Last edited:
I'm not sure that is like it that you use this functions
Code:
if isInRange(player:getPosition(), team1[1], team1[2]) == TRUE then
player:teleportTo(team1Pos)
end
if isInRange(player:getPosition(), team2[1], team2[2]) == TRUE then
player:teleportTo(team2Pos)
end
try change it for:
Code:
if isInRange(player:getPosition(), team1[1], team1[2]) then
        player:teleportTo(team1Pos)
end
if isInRange(player:getPosition(), team2[1], team2[2]) then
        player:teleportTo(team2Pos)
end

edit: I try a new attempt
Code:
local teamOne = {
    fromPosition = Position(xxx,xxx,xx),
    toPosition = Position(xxx,xxx,xx)
}
local teamTwo = {
    fromPosition = Position(xxx,xxx,xx),
    toPosition = Position(xxx,xxx,xx)
}
local keywordHandler = KeywordHandler:new()
local npcHandler = NpcHandler:new(keywordHandler)
NpcSystem.parseParameters(npcHandler)
local talkState = {}

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

function isInRange(position, fromPosition, toPosition)
return (position.x >= fromPosition.x and position.y >= fromPosition.y and position.z >= fromPosition.z and position.x <= toPosition.x and position.y <= toPosition.y and position.z <= toPosition.z)
end

local function start_event()
local team1Pos = {x=1033, y=832, z=7, stackpos = 255}
local team2Pos = {x=1035, y=832, z=7, stackpos = 255}
for i = 1, #players do
player = players[i]
if isInRange(player:getPosition(), teamOne.fromPosition, teamOne.toPosition)  then
player:teleportTo(team1Pos)
end
if isInRange(player:getPosition(), teamTwo.fromPosition, teamTwo.toPosition)  then
player:teleportTo(team1Pos)
end
player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Battle has started! This battle will last 30 minutes.")
addEvent(end_event, 1800000)
end
end

local function end_event()
local arena_area = {
{x=1024, y=822, z=7, stackpos = 255},
{x=1044, y=842, z=7, stackpos = 255}
}
local players = Game.getPlayers()

Game.setStorageValue(battleArenaStor, 0)

for i = 1, #players do
player = players[i]
if isInRange(player:getPosition(), arena_area[1], arena_area[2]) == TRUE then
local newTemple = Game.getStorageValue(currentMap)
local pos, player = mapPositions[newTemple]
player:teleportTo(pos)
player:addHealth(player:getMaxHealth())
player:addMana(player:getMaxMana())
local tmp = {CONDITION_POISON, CONDITION_FIRE, CONDITION_ENERGY, CONDITION_BLEEDING, CONDITION_PARALYZE, CONDITION_INVISIBLE, CONDITION_MANASHIELD, CONDITION_INFIGHT, CONDITION_DRUNK, CONDITION_DROWN, CONDITION_ATTRIBUTES, CONDITION_FREEZING, CONDITION_DAZZLED, CONDITION_CURSED, CONDITION_PACIFIED, CONDITION_SPELLCOOLDOWN, CONDITION_SPELLGROUPCOOLDOWN}
for i = 1, #tmp do
player:removeCondition(tmp[i])
end
end
end
return true
end

function creatureSayCallback(cid, type, msg)
if(not npcHandler:isFocused(cid)) then
return false
end

local talkUser = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid

if(msgcontains(msg, 'fight') or msgcontains(msg, 'battle')) then
selfSay('Do you want to start a team battle?', cid)
talkState[talkUser] = 1
elseif(msgcontains(msg, 'yes') and talkState[talkUser] == 1) then
if Game.getStorageValue(battleArenaStor) ~= 0 then
selfSay('A battle is currently in progress. Please wait until it ends.', cid)
talkState[talkUser] = 0
else
selfSay('Okay. You have 2 minutes to prepare. Stand in the team waiting rooms.', cid)
addEvent(start_event, 120000)
Game.setStorageValue(battleArenaStor, 1)
end
talkState[talkUser] = 0
elseif(msgcontains(msg, 'no') and isInArray({1}, talkState[talkUser]) == TRUE) then
talkState[talkUser] = 0
selfSay('Ok then.', cid)
end
return true
end

npcHandler:setCallback(CALLBACK_MESSAGE_DEFAULT, creatureSayCallback)
npcHandler:addModule(FocusModule:new())


AND PLEASE FOR GOD, IDENT IT
 
Last edited:
It turns out my original script does work, I was just using the wrong keyword after I wrote it :p There was a minor error regarding the end_event function needing to be above the start_event function, but that wasn't really a big deal.
You do know my script was indented, right? I don't know how you managed to remove all the indentation :p

Thank you for taking an interest though!
What I would like to see is somebody create the full NPC like it is in real tibia - I think this would be a good contribution to the community. It's too complex for me though I think =\
I'll continue to improve on my base script now though, at least I have something to build from =]
 
holy shit, I don't know why the code tag don't keep the identation D:
later I'll try something, I have the arena maps, will try make it work, I want it too ;3
 
Anyone knows how to get this to work? The NPC will always reply with 'A battle is currently in progress. Please wait until it ends.'

Thanks in advance.
 
Back
Top