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

[TUTORIAL] Rescue the Princess Quest v2.0

Zyntax

*WannaBe Scripter*
Joined
Jan 27, 2010
Messages
533
Reaction score
40
Location
Lua & XML Section
Hey guys!

It's time to introduce the "Rescue the Princess Quest" to you.

Updates:
v2.0
Code:
Moved the whole tutorial to TFS0.3.5(CD) 
Tested everything, 100% working!
New screenshots added

1) Location
2) Scripts you need (Startup)
2.1) The Princess
2.2) The King Herby NPC
2.3) Summon the Princess Script
2.4) Hidden paths and traps
3) Optional ideas
4) Credits


1) Let's get started! Location

First off all, I'm going to show you where the whole scenario
will take place:

pic5rf.jpg


The first room (upper left side) is the starting room.
The second room (bottom right side) is the ending room.
The path leading from left to right is the secret path, which
will open if you summon the princess after accepting the quest
from the King.

2) Scripts you need (Startup)

First off all you may need the mapArea Iterator (credits to Colandus)
Insert this script into your global.lua / functions.lua

mapArea Iterator
Lua:
-- Area iterator by Colandus @ OTFans.net
function mapArea(fromPos, toPos)
    local x, y, z = fromPos.x, fromPos.y-1, fromPos.z
    return function()
        if (y < toPos.y) then
            y = y+1
        elseif (x <= toPos.x) then
            y = fromPos.y
            x = x+1
        else
            x = fromPos.x
            y = fromPos.y
            z = z+1
        end
        if (x <= toPos.x and y <= toPos.y or z < toPos.z) then
            return x, y, z
        end
    end
end

This script will allow us to use the "mapArea" function which I built into
the KingNPC to check if the princess was actually rescued or not!

2.1) The Princess

I scripted the princess like a monster (monster.xml)
The reason therefor:
If you summon and convince the princess (like a player summon)
then no other player could attack her / neither you.
If you have a No-PvP server then she wouldn't get hit, except for other monsters
if they switch or have some AreaOfEffect spells.

put that script into your %data/monster folder
and name it princess.xml

Lua:
<?xml version="1.0" encoding="UTF-8"?>
<monster name="princess" nameDescription="the princess" race="blood" experience="0" speed="200" manacost="0">
  <health now="100" max="100"/>
  <look type="138" head="0" body="0" legs="80" feet="0" corpse="6081"/>
  <targetchange interval="1000" chance="0"/>
  <strategy attack="10" defense="0"/>
  <flags>
    <flag summonable="0"/>
    <flag attackable="1"/>
    <flag hostile="1"/>
    <flag illusionable="0"/>
    <flag convinceable="0"/>
    <flag pushable="0"/>
    <flag canpushitems="1"/>
    <flag canpushcreatures="1"/>
    <flag targetdistance="0"/>
    <flag staticattack="0"/>
    <flag runonhealth="0"/>
  </flags>
  <attacks>
  </attacks>
  <defenses armor="11" defense="11"/>
  <elements>
	<element physicalPercent="-8"/>
	<element deathPercent="-7"/>
  </elements>
  <immunities>
    <immunity lifedrain="0"/>
    <immunity paralyze="0"/>
    <immunity outfit="0"/>
    <immunity drunk="0"/>
    <immunity invisible="1"/>
  </immunities>
  <voices interval="5000" chance="50">
    <voice sentence="Please save my life!"/>
    <voice sentence="Bring me back to my King!"/>
    <voice sentence="Don't let me die!"/>
    <voice sentence="I'm the Princess! Get on your knees!"/>
  </voices>
  <loot>
  </loot>
<script>
<event name="Princess"/> 
</script>
</monster>

Maybe you noticed the <event name="Princess"/> line, here's the explanation:
If the princess dies then the player should be informed about that.
Therefor the next step is to add a script to notify the player.

Add this line into your %data/creaturescripts.xml

Lua:
<event type="death" name="Princess" event="script" value="princess.lua"/>

Next step is to add the script into your %data/creaturescripts/scripts folder
and name it princess.lua

Lua:
function onDeath(cid, corpse, Killer)
		doCreatureSay(cid, 'You let me die!\n Screw you!', 19)
end

Well, I guess that doesn't need an explanation :thumbup:
(If the sentence "Srew you!" violates any rules on the server
edit it!)

OK, we're done with the princess, let's move to the King Herby NPC.

2.2) The King Herby NPC

It's the starting point in the quest where you talk to him:

npca.jpg


Ofcourse, you can rewrite all the talking lines like you want!

And now the scripts, add this script to your %data/npc folder
and name it King Herby.xml

Lua:
<?xml version="1.0" encoding="UTF-8"?>
<npc name="King Herby" script="daughter.lua" walkinterval="2000" floorchange="0">
	<health now="100" max="100"/>
	<look type="132" head="20" body="39" legs="45" feet="7" addons="0"/>
	<parameters>
	 <parameter key="message_greet" value="Help me |PLAYERNAME|! My little Princess was captured by a magician and sealed in a statue!"/>
	</parameters>
</npc>

Ofcourse, you can rename the script as you wish but remember to
use the same name in the next step:

Add this script into your %data/npc/scripts folder
and name it daughter.lua
(or use the same name as in the King Herby.xml line above!)

Lua:
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 creatureSayCallback(cid, type, msg)
    if (not npcHandler:isFocused(cid)) then
        return false
    end

	local talkUser = NPCHANDLER_CONVBEHAVIOR == CONVERSATION_DEFAULT and 0 or cid
	daughter = false
	
	if msgcontains(msg, 'quest') and (getPlayerStorageValue(cid, 20020) == - 1) then
		selfSay('Are you really strong enough to help me?', cid)
		talkState[talkUser] = 1
		
	elseif msgcontains(msg, 'quest') and (getPlayerStorageValue(cid, 20022) == 1) then
		selfSay('Praise you mighty warrior, my daughter is safe!', cid)
		
	elseif (msgcontains(msg, 'yes') and talkState[talkUser] == 1) and (getPlayerStorageValue(cid, 20020 == -1)) then	
		setPlayerStorageValue(cid, 20020, 1)
		selfSay('Mighty warrior, your mission is to rescue my daughter!', cid)
			
	elseif msgcontains(msg, 'quest') and (getPlayerStorageValue(cid, 20020) == 1) then
		selfSay('Did you find her?', cid)
		
	elseif msgcontains(msg, 'yes') and (getPlayerStorageValue(cid, 20021) == 1) and (getPlayerStorageValue(cid, 20022) ~= 1) then
		local fromPos = {x=546, y=529, z=7, stackpos=255}
		local toPos = {x=551, y=532, z=7, stackpos=255}
			for x, y, z in mapArea(fromPos, toPos, 255) do
			local creature = getThingfromPos({x = x, y = y, z = z, stackpos = 255})
				if isMonster(creature.uid) == TRUE and getCreatureName(creature.uid) == 'princess' then
					doRemoveCreature(creature.uid)
					doSendMagicEffect({x = x, y = y, z = z}, CONST_ME_ENERGYAREA)
					selfSay('Thank you mighty warrior, you saved her! Take this as a reward!', cid)
					setPlayerStorageValue(cid, 20022, 1)
					doPlayerAddItem(cid, 5805, 1)	
				break
				end
			end
			
		
	
	else 
		selfSay('Please help me to save my daughter!', cid)
	end

    return true
end

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

Confused by the script? I'll explain the important parts:

Every selfSay('...') line will be told by the NPC like i wrote at the beginning
of the King Herby section.
Edit them if you want him to say something else.

"mapArea" function:
Like i wrote in the beginning of the tutorial you have to add the Area Iterator
to your functions, because we will check the area around the NPC if the
princess was actually returned alive and safe!

Additionally, you have to edit the "local frompos ... " and "local topos ..." positions to your actuall map positions!

Near the end of the script it says: doPlayerAddItem(... ,1)
Please adjust this line to the reward you want to give the player!
(Just rewrite the ID of the item)

IMPORTANT:
Please make sure to use some storageValues for this quest!
If you already used mine (20020 - 20022) rewrite them also!

2.3) Summon the Princess Script

Ok, now we script the statue where the princess is sealed!

Add this line into your %data/actions/actions.xml

Lua:
<action uniqueid="4009" event="script" value="quests/daughtersummon.lua"/>

The uniqueid 4009 is the ID i gave my statue in my mapEditor!
Make sure to change it if you already used this ID anywhere!


Well, "daughtersummon" was the dumbest idea I had for the script so,
if you like to rename it then do that, but also remind the new name
in the next step:

Add this script into your %data/actions/quests
and name it daughtersummon.lua
(Or rename it like in the actions.xml above!)

Lua:
local wallpos = {x=529, y=521, z=7, stackpos=1}
local wallid = 1049
local spawnpos = {x=525, y=522, z=7}
local timetoreset = 10000

function onUse(cid, item, fromPosition, itemEx, toPosition)

local getwall = getTileItemById(wallpos, wallid).uid

	if item.itemid == 1448 and item.uid == 4009 and (getPlayerStorageValue(cid, 20020) == 1) then
		doPlayerSendTextMessage(cid, 22, 'My hero has arrived! Please bring me back to my father!')
		setPlayerStorageValue(cid, 20021, 1)
		doSummonCreature("Princess", spawnpos)
		doSendMagicEffect(wallpos, CONST_ME_ENERGYAREA)
		doRemoveItem(getwall)
		addEvent(returnwall, timetoreset)
					
	elseif (getPlayerStorageValue(cid, 20021) == 1) then
		doPlayerSendTextMessage(cid, 22, 'The princess has already been released!')
	end
end

function returnwall()
doCreateItem(wallid, wallpos)
end

IMPORTANT:
Please edit the positions to fit your map positions!
If you don't need a hidden path or something then just erase the lines
where the walls are written.

What's the script doing?
I'll show it to you:

princ1.jpg


Explainings:
This script summons the princess to the written "spawnpos" and removes
the wall to the hidden path.

OK, now to the next step!

2.4) Hidden paths and traps

In this section I'll explain the "traps" which I built in this map.

It looks like this:

princ3eee.jpg


You got 3 tiles to chose from, if you make the wrong decision a monster
will spawn and try to kill you!

For the scripts, I used a movement script.
Before I explain the script, if you don't want any traps or something
then don't mind this section!

Add this line into your %data/movement.xml

Lua:
<movevent type="StepIn" actionid="4016" event="script" value="trap1.lua"/>

It's named "trap1.lua" because I made another script that does exactly the same
(spawn a monster) but on different spawnpositions.

IMPORTANT:
Make sure to set the ACTION ID = 4016 on the specific tile so the script can be
executed if a player steps on it.

Add this script into your %data/movements/scripts
and name it trap1.lua

Lua:
local spawnpos = {x=540, y=521, z=7}

function onStepIn(cid, item, pos, fromPos)

	if item.actionid == 4016 then
	 if isPlayer(cid) then
		doSummonCreature("Hero", spawnpos)
		doSendMagicEffect(spawnpos, CONST_ME_ENERGYAREA)
		doTransformItem(item.uid, item.itemid -1)
		doPlayerSendTextMessage(cid, 22, "You made the wrong choice!\n A guard tries to kill the princess!")
	 end
	end
end

Explanations:
Like the picture above shows, this script spawns a monster if you step on the tile.
Now again, ADJUST THE SPAWNPOSITION and the MONSTER if you want something
else.

Now for the right tiles, this will happen:

princ4.jpg


If you chose the right tile to step on, the hidden path will continue!

Again, a movement script, looks like this

Add this line into your %data/movements.xml

Lua:
<movevent type="StepIn" actionid="4014" event="script" value="secret1.lua"/>

Again, rename "secret1.lua" to the script you will use in the next step:

Add this script into your %data/movements/scripts
and name it secret1.lua

Lua:
local config = {
				wallpos = {x=543, y=524, z=7, stackpos=1},
    			wallid = 1049,
				reset = 10
			   }

function onStepIn(cid, item, pos, fromPos)

    if item.actionid == 4014 then
	 if isPlayer(cid) == TRUE then
		doRemoveItem(getThingFromPos(config.wallpos).uid)
		doTransformItem(item.uid, item.itemid -1)
		doSendMagicEffect(config.wallpos, CONST_ME_ENERGYAREA)
		doPlayerSendTextMessage(cid, 22, "The secret path continues. It will close in 10 seconds.")
		addEvent(resetsecret1, config.reset * 1000, item)
	  end
	end
end

function resetsecret1()
doCreateItem(config.wallid, config.wallpos)
end

This script removes the wall and resets it after 10 seconds.

IMPORTANT:

As always, adjust the positions and wallid to your needs!

If you chose the right tiles, or defeated the horrible monsters and you finally reached
the King, talk to him again.

princ5.jpg


And if you followed the steps above correctly, then this will happen:

princ6.jpg


You did it! Congratulations! :thumbup:

And remind yourself to NEVER let the princess die!
You can UH her, throw a potion at her and so on.. otherwise...

princ8.jpg



3) Optional Ideas

Well, that's the Rescue the Princess Quest!

pic5rf.jpg


As you can see at the picture above, I made this secret path with traps.
If you got any other ideas then please adjust the quest to your needs!
I tried to provide as many scripting ideas as possible
(movement -> summon / movement -> Create/Remove / Action -> Summon / NPC script / ...)
Just use the forum to search for ideas / scripts to make your quest unique!

IMPORTANT TIPS:

I'm not a super-pro-Coder ( :p ) therefor
make sure to add the KingNPC and the princess on the same floorlevel.
The reason is simple, a monster can't follow you Up- and DownStairs!
If you know a way to adjust the princess to follow you up and down feel
free to contact me or post a reply!

ALWAYS make sure to REWRITE all the positions, WallIDs, selfSay, Messages
and so on.

If you get any errors while you adjust your script, then feel free to ask!
I hope I can help you with your problems :D

4) Credits


Since i only used the Area Iterator by Colandus, here ya go:

Credits to Colandus -> Area Iterator

Well, this is my very first tutorial!
Please rate it, comment it, flame it? :eek:

If you find bugs or something which doesn't look right please bring it right up
and post a reply or send me a PM!



So far, thanks for reading ;)

Regards,

Zyntax
 
Last edited:
Back
Top