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

Wrath of the Emperor (Mission 01) [1.X]

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,470
Solutions
27
Reaction score
844
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
Hi! Today I will share the first mission of Wrath of the Emperor, "Catering the Lion's Den". With the help @Xikini we took the video of the quest and orts datapack references to build it, and the result is a perfectly working first mission. He coded everything, I did the testings all on discord.

This is the guide video

The first thing that we scripted for the mission is the Marked Crate, this will allow you to use the crate as disguise to get throw the mission.
For this we go to actions/scripts/quests/wrath of the emperor/mission01crate.lua and paste the following:

Lua:
local useableAreas = {
    {Position(1115, 723, 12), Position(1209, 861, 12)},
    {Position(1125, 731, 13), Position(1176, 749, 13)},
}

local condition = Condition(CONDITION_OUTFIT)
condition:setOutfit({lookTypeEx = 12496})
condition:setTicks(-1)

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
    local outfit = player:getOutfit()
    if outfit.lookTypeEx ~= 12496 then
        local usuable = false
        for i = 1, 2 do
            if player:getPosition():isInRange(useableAreas[i][1], useableAreas[i][2]) then
                usuable = true
                break
            end          
        end
        if not usuable then
            player:say("This is not the time or place to use this.", TALKTYPE_MONSTER_SAY, false, player)
            return true
        end
        player:addCondition(condition)
        player:getPosition():sendMagicEffect(CONST_ME_POFF)
    end
    return true
end

Another action script we will use are the levers of the quest. This are used to turn off the lights, and to take off the wall on the lower floor.
For this we go to actions/scripts/quests/wrath of the emperor/mission01lever.lua and paste:

Lua:
local lights = {
    {11447, 11446}, -- on/off
    {11449, 11448}, -- vertical
}

local leverIds = {10044, 10045}

local levers = {
    [8030] = {
        {Position(1163, 747, 12), 1},
        {Position(1166, 747, 12), 1},
        {Position(1169, 747, 12), 1}
    },
    [8031] = {
        {Position(1154, 751, 12), 2},
        {Position(1151, 749, 12), 2}
    },
    [8032] = {
        {Position(1140, 746, 12), 2},
    },
    [8033] = {
        {Position(1149, 740, 13), 9264},
        {Position(1149, 741, 13), 9207},
        {Position(1149, 742, 13), 9209},
        {Position(1149, 743, 13), 9264}
    }
}

local positionAdjustment = {
    {-1, -1},
    {0, -1},
    {1, -1},
    {-1, 0},
    {0, 0},
    {1, 0},
    {-1, 1},
    {0, 1},
    {1, 1}
}

local function catchPlayer(player)
    player:teleportTo(Position(1155, 878, 12), false)
    player:say("The guards have spotted you. You were forcibly dragged into a small cell. It looks like you need to build another disguise.", TALKTYPE_MONSTER_SAY, false, player)
    return true
end

local function checkNineTiles(position)
    for i = 1, 9 do
        local position_ = Position(position.x + positionAdjustment[i][1], position.y + positionAdjustment[i][2], position.z)
        local creatures = Tile(position_):getCreatures()
        if creatures then
            for n = 1, #creatures do
                local player = Player(creatures[n])
                if player then
                    catchPlayer(player)
                end
            end
        end
    end  
end

function onUse(player, item, fromPosition, target, toPosition, isHotkey)
  
    local leverId = item:getId()  
    item:transform(leverId == leverIds[1] and leverIds[2] or leverIds[1])
  
    local itemActionId = item:getActionId()
  
    if table.contains({8030, 8031, 8032}, itemActionId) then
        if leverId == leverIds[1] then
            for i = 1, #levers[itemActionId] do
                Tile(levers[itemActionId][i][1]):getItemById(levers[itemActionId][i][2] == 1 and lights[1][1] or lights[2][1]):transform(levers[itemActionId][i][2] == 1 and lights[1][2] or lights[2][2])
            end
        else
            for i = 1, #levers[itemActionId] do
                Tile(levers[itemActionId][i][1]):getItemById(levers[itemActionId][i][2] == 1 and lights[1][2] or lights[2][2]):transform(levers[itemActionId][i][2] == 1 and lights[1][1] or lights[2][1])
                checkNineTiles(levers[itemActionId][i][1])
            end
        end
        return true
    end
  
    if itemActionId == 8033 then
        for i = 1, 4 do
            local wall = Tile(levers[itemActionId][i][1]):getItemById(levers[itemActionId][i][2])
            if wall then
                wall:remove()
            end
        end
        return true
    end  
    return true
    end

Then register both scripts on actions.xml:
XML:
    <!-- Wrath of the Emperor -->
    <action fromaid="8030" toaid="8033" script="quests/wrath of the emperor/mission01_levers.lua" />
    <action itemid="12284" script="quests/wrath of the emperor/Mission01Crate.lua" />

Now we have to do the moveevents to catch the player when he does a wrong action.
For this we go to movements/scripts/quests/wrath of the emperor/crate.lua and paste:
Lua:
local wallPositions = {
    {Position(1149, 740, 13), 9264},
    {Position(1149, 741, 13), 9207},
    {Position(1149, 742, 13), 9209},
    {Position(1149, 743, 13), 9264}
}

local positionAdjustment = {
    { 1,  1},
    { 0,  1},
    {-1,  1},
    { 1,  0},
    { 0,  0},
    {-1,  0},
    { 1, -1},
    { 0, -1},
    {-1, -1}
}

local function catchPlayer(player)
    player:teleportTo(Position(1155, 878, 12), false)
    player:say("The guards have spotted you. You were forcibly dragged into a small cell. It looks like you need to build another disguise.", TALKTYPE_MONSTER_SAY, false, player)
    return true
end

local function checkThreeTiles(position)
    for i = 1, 3 do
        local position_ = Position(position.x + i, position.y, position.z)
        local creatures = Tile(position_):getCreatures()
        if creatures then
            for n = 1, #creatures do
                local player = Player(creatures[n])
                if player then
                    catchPlayer(player)
                end
            end
        end
    end  
end

local function sendText(playerId, text)
    local player = Player(playerId)
    if player then
        player:say(text, TALKTYPE_MONSTER_SAY, false, player)
    end
end

function onStepIn(creature, item, position, fromPosition)
    local player = Player(creature)
    if not player then
        return true
    end
  
    local tileActionId = item:getActionId()
  
    local outfit = player:getOutfit()
  
    -- beetle hole
    if tileActionId == 8036 then
        if outfit.lookType ~= 348 then
            player:say("You are too large too fit in the hole.", TALKTYPE_MONSTER_SAY, false, player)
        else
            player:removeCondition(CONDITION_OUTFIT)
            player:teleportTo(Position(1153, 855, 12))
        end
        return true
    end
  
    -- final stairs
    if tileActionId == 8020 then
        if outfit.lookTypeEx == 12496 then
            player:removeCondition(CONDITION_OUTFIT)
            if item:getId() ~= 9023 then
                addEvent(sendText, 0, player:getId(), "On reaching the watchtower you remove your temporary disguise.")
            else
                addEvent(sendText, 0, player:getId(), "You take off your disguise, as it's not needed here.")
            end
        end
        return true
    end
  
    -- warn player of box requirement
    if tileActionId == 8015 then
        player:say("You hear guards moving behind doors in the distance. If you have any sort of disguise with you, this is the moment to use it.", TALKTYPE_MONSTER_SAY, false, player)
        return true
    end
  
    -- box check
  
    if outfit.lookTypeEx ~= 12496 then
        catchPlayer(player)
        return true
    end
  
    -- 8016 is box check only
    local playerPos = player:getPosition()
  
    if tileActionId == 8017 then
        catchPlayer(player)
        checkThreeTiles(position)
        return true
    end
  
    if tileActionId == 8018 then
        local doorOpen = Tile(Position(playerPos.x - 2, playerPos.y, playerPos.z)):getItemById(12213)
        if doorOpen then
            catchPlayer(player)
        end
        return true
    end
  
    if tileActionId == 8019 then
        local doorOpen = Tile(Position(playerPos.x - 3, playerPos.y, playerPos.z)):getItemById(12213)
        if doorOpen then
            catchPlayer(player)
        end
        return true
    end
  
    if tileActionId >= 8021 and tileActionId <= 8029 then
        local verticalLight = Tile(Position(position.x + positionAdjustment[tileActionId - 8020][1], position.y + positionAdjustment[tileActionId - 8020][2], position.z)):getItemById(11449)
        local horizontalLight = Tile(Position(position.x + positionAdjustment[tileActionId - 8020][1], position.y + positionAdjustment[tileActionId - 8020][2], position.z)):getItemById(11447)
        if verticalLight or horizontalLight then
            catchPlayer(player)
            return true
        end
    end

    if tileActionId == 8034 then
        player:say("Guards heavily patrol this area. Try to stay hidden and do not draw any attention to yourself by trying to attack.", TALKTYPE_MONSTER_SAY, false, player)
        return true
    end
  
    if tileActionId == 8035 then
        for i = 1, 4 do
            local wall = Tile(wallPositions[i][1]):getItemById(wallPositions[i][2])
            if wall then
                return true
            end
            Game.createItem(wallPositions[i][2], 1, wallPositions[i][1])
        end
        return true
    end  
    return true
end

Then register the script on movements.xml:
XML:
    <!-- Wrath of the Emperor -->
    <movevent event="StepIn" fromaid="8015" toaid="8029" script="quests/wrath of the emperor/crate.lua" />
    <movevent event="StepIn" fromaid="8034" toaid="8036" script="quests/wrath of the emperor/crate.lua" />

Now we need a globalevent, because there's some windows on the passage doors that open/closes showing up guard's eyes.
Lets go to globalevents/scripts/wrath of the emperor/spydoors.lua and paste:

Lua:
local doorIds = {12214, 12213} -- closed, open
local doorPositions = {
    Position(1179, 811, 12),
    Position(1179, 806, 12),
    Position(1179, 798, 12),
    Position(1179, 791, 12),
    Position(1179, 790, 12),
    Position(1174, 765, 12),
    Position(1174, 757, 12)
}

function catchPlayer(player)
    player:teleportTo(Position(1155, 878, 12), false)
    player:say("The guards have spotted you. You were forcibly dragged into a small cell. It looks like you need to build another disguise.", TALKTYPE_MONSTER_SAY, false, player)
    return true
end

local function checkThreeTiles(position)
    for i = 1, 3 do
        local position_ = Position(position.x + i, position.y, position.z)
        local creatures = Tile(position_):getCreatures()
        if creatures then
            for n = 1, #creatures do
                local player = Player(creatures[n])
                if player then
                    catchPlayer(player)
                end
            end
        end
    end  
end

local function wrathOfEmperorSpyDoors(index)
    local rand
    local doorClosed = Tile(doorPositions[index]):getItemById(doorIds[1])
    local doorOpen = Tile(doorPositions[index]):getItemById(doorIds[2])
    if doorOpen then
        doorOpen:transform(doorIds[1])
        if index == 4 then
            Tile(doorPositions[5]):getItemById(doorIds[2]):transform(doorIds[1])
        end
        rand = math.random(2000, 3000)
    else
        doorClosed:transform(doorIds[2])
        checkThreeTiles(doorPositions[index])
        if index == 4 then
            Tile(doorPositions[5]):getItemById(doorIds[1]):transform(doorIds[2])
            checkThreeTiles(doorPositions[5])
        end
        rand = math.random(10000, 15000)
    end
    addEvent(wrathOfEmperorSpyDoors, rand, index)
end

function onStartup()
    for i = 1, #doorPositions do
        if i ~= 5 then
            addEvent(wrathOfEmperorSpyDoors, 1000, i)
        end
    end
    return true
end

And register it to globalevents.xml with:
XML:
<globalevent type="startup" name="Spy_Doors" script="wrath of the emperor/spydoors.lua" />

Now we need the npc that will take us out of the prison (where the player goes after a wrong action).
For this we go to data/npc/scripts and create Zumtah.lua

Lua:
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 condition = Condition(CONDITION_OUTFIT)
condition:setOutfit({lookType = 348})
condition:setTicks(-1)

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

    local player = Player(cid)
    if msgcontains(msg, "exit") then
        local outfit = player:getOutfit()
        if outfit.lookType ~= 348 then
            if npcHandler.topic[cid] < 1 then
                npcHandler:say("Oh of course, may I show you around a bit before? You want to go straight to the exit? Would you please follow me. Oh right, I am terribly sorry but THERE IS NONE. Will you finally give it up please?", cid)
                npcHandler.topic[cid] = 1
            elseif npcHandler.topic[cid] == 3 then
                npcHandler.topic[cid] = 4
            elseif npcHandler.topic[cid] == 6 then
                npcHandler.topic[cid] = 7
            elseif npcHandler.topic[cid] == 10 then
                npcHandler:say("Oh, you mean - if I have ever been out of here in those 278 years? Well, I - I can't remember. No, I can't remember. Sorry.", cid)
                npcHandler.topic[cid] = 11
            elseif npcHandler.topic[cid] == 11 then
                npcHandler:say("No, I really can't remember. I enjoyed my stay here so much that I forgot how it looks outside of this hole. Outside. The air, the sky, the light. Oh well... well.", cid)
                npcHandler.topic[cid] = 12
            elseif npcHandler.topic[cid] == 12 then
                npcHandler:say("Oh yes, yes. I... I never really thought about how you creatures feel in here I guess. I... just watched all these beings die here. ...", cid)
                npcHandler.topic[cid] = 13
            elseif npcHandler.topic[cid] == 13 then
                npcHandler:say("Oh, excuse me of course, you... wanted to go. Like all... the others. I am sorry, so sorry. You... you can leave. Yes. You can go. You are free. I shall stay here and help every poor soul which ever gets thrown in here from this day onward. ...", cid)
                npcHandler.topic[cid] = 14
            elseif npcHandler.topic[cid] == 14 then
                npcHandler:say({
                    "Alright, as I said you are free now. There will not be an outside for the next three centuries, but you - go. ...",
                    "Oh and I recovered the strange crate you where hiding in, it will wait for you at the exit since you can't carry it as... a beetle, muhaha. Yes, you shall now crawl through the passage as a beetle. There you go."
                }, cid)
                npcHandler.topic[cid] = 0
                player:addCondition(condition)
            end
        else
            npcHandler:say("It's you, why did they throw you in here again? Anyway, I will just transform you once more. I also recovered your crate which will wait for you at the exit. There, feel free to go.", cid)
            player:addCondition(condition)
        end
    elseif msgcontains(msg, "no") then
        if npcHandler.topic[cid] == 1 then
            npcHandler:say("You are starting to get on my nerves. Is this the only topic you know?", cid)
            npcHandler.topic[cid] = 2
        elseif npcHandler.topic[cid] == 4 then
            npcHandler.topic[cid] = 5
        elseif npcHandler.topic[cid] == 7 then
            npcHandler.topic[cid] = 8
        end
    elseif msgcontains(msg, "yes") then
        if npcHandler.topic[cid] == 2 then
            npcHandler:say("Pesky, persistent human.", cid)
            npcHandler.topic[cid] = 3
        elseif npcHandler.topic[cid] == 5 then
            npcHandler.topic[cid] = 6
        elseif npcHandler.topic[cid] == 8 then
            npcHandler:say("Muhahaha. Then I will give you a test. How many years do you think have I been here? {89}, {164} or {278}?", cid)
            npcHandler.topic[cid] = 9
        end
    elseif msgcontains(msg, "278") and npcHandler.topic[cid] == 9 then
        npcHandler:say("Correct human, and that is not nearly how high you would need to count to tell all the lost souls I've seen dying here. I AM PERPETUAL. Muahahaha.", cid)
        npcHandler.topic[cid] = 10
    elseif (msgcontains(msg, "164") or msgcontains(msg, "89")) and npcHandler.topic[cid] == 9 then
        npcHandler:say("Wrong answer human! Muahahaha.", cid)
        npcHandler.topic[cid] = 0
    end
    return true
end

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

Create the .xml on data/npc aswell:

XML:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Zumtah" script="Zumtah.lua" walkinterval="2000" floorchange="0">
    <health now="100" max="100" />
    <look type="51" />
    <parameters>
        <parameter key="message_greet" value="Another visitor to this constricted, cosy, calm realm, perfect except for an {exit}. Muhaha." />
    </parameters>
</npc>

We also need the Lizard Tunnel Guard npc that will send us to prison if we talk nearby.
For this one we go to data/npc/scripts/Lizard Tunel Guard.lua and paste:

Lua:
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 creatureSayCallback(cid, type, msg)
    local player = Player(cid)
    player:teleportTo(Position(1155, 878, 12))
    player:say("The guards have spotted you. You were forcibly dragged into a small cell. It looks like you need to build another disguise.", TALKTYPE_MONSTER_SAY)
    return true
end

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

Then create the Lizard Tunnel Guard.xml file at data/npc.
XML:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="Lizard Tunnel Guard" script="Lizard Tunnel Guard.lua" walkinterval="0" floorchange="0">
    <health now="100" max="100" />
    <look type="338" />
</npc>

And we're done. Everything should work, we tested every possibility that could happen on the script. Now you have to import the attached map we did on the same positions to make it work. If you wish to change the positions, just match the code with your map.

A fast view to the outcome:

Again, a big thanks to @Xikini for taking the time to help me with this.
Hope you guys enjoy it, regards!
 

Attachments

Last edited:
Glad to help.

There's some small code clean-up that could be done, as well as making global functions/tables to make it a bit neater, but otherwise I'm pretty happy with the result.
 
Back
Top