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

[Lua Tut] NEW SCRIPTERS INTENDED

It's good you made it , I allowed myselfto make a part of it more readable since Im bored this minute. If you are free you can make next part and then there will be nice readable part posted here.
 
Last edited:
YOU MUST KNOW SOMETHING ABOUT THE COMMANDS

if/then/else/elseif/end


PART 1: Scripts, and setting them up.

Scripts only know what you tell them, and they have to read everything in order.
The way to set a script up correctly is:
The first if is ended last. This means:
Code:
	function
	if1
	if2
	else2
	end2
	else1
	end1
	end function

In some cases this may differ, but for basic scripts it will look like this.

PART 2: GLOBAL / LOCAL values.

A global value is a value that the script already registers. Lets say we had this function.
function onUse(cid) -- The script now ONLY knows that if the item specified in XML file is used, then run this file. Right now, it would do NOTHING! exept load an error :)--

Now the global event that is specified here is (cid). There is no value other then the server now knows (cid) is being used. It doesnt know who cid is, just that its a thing using the item.--
If we wanted to set that global value, so it registers something immidiatly, we can do this:
Lua:
        cidname = "demon"
	if not (getCreatureName(cid) == cidname) then

Know the script knows if its not a demon using the item. then immediatly end the script without doing anything (false).

You notice I put () around (getCreatureame(cid) == cidname) This is acually ONLY cutting memory usage down. It tells the script to load
(getCreatureName(cid) == cidname) instead of...getCreatureName(cid).....==......cidname.... Its nothing by itself, but with multiple scripts it will bog down.

A local value is just a value we give to the script to help us script. It would be something like this.

Lua:
	function onUse(cid)
	local vocation = getPlayerVocation(cid)   --Must be after the function because cid is unregistered until then.--
	if (vocation == 1) then
	return true
	end
	end

This is saying if its a sorc, then true. In the game this would do nothing, the player would use the item, but nothing would happen.


Now we can also do this.
Lua:
	if (vocation == 1) then
	 local money = 5000
	elseif (vocation == 2)
	 local money = 6000
	end

Now if you notice, I didnt tell the game to do anything. I just told it to get a value. Just showing this is a possibility.


PART 3: GETTING STARTED.

The first thing to do is study up on the LUA_FUNCTION that are givin. Check around Otland how some are used ect.
The next thing to do is figure out what script you need, and then how to create it.

The reason we want to think about "how" to create it first, is because we can create things to help us before starting, also we dont want to
start scripting one way and figure out it wont work.

Lets make a jailing script. First, what will we need?
1) A way to teleport them there
2) A way to teleport them out

Look how simple it seems, and if you learn the scripts, it is just as easy.

So, a way to get them there. Well, thank god for Gm's that can use talkactions. So we will make a talkaction.

So what function will tell us talkaction?

Lua:
function onSay(cid, words, param, channel)

Okay, now the server knows when I say the words specified in the XML file, start this file. (then error cuz theres nothing there.)
Lua:
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

Now, You see I put if the player says nothing, return false. This doesn't SEEM nessacary. But there are commands that require you to specify the inital value.
In this case PARAM WILL NEED TO BE SPECIFIED. As of right now its speficied as NOT nothing, because if it was nothing, it would return false.


So now that the script is at param is not nothing. We can add this.

Lua:
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")

--This is telling the script that there will be more params used. (so not just !param, it will be !param param)--

--Now how do we call the second command?--
t[1] --We use t because its specified on the server as the explode.--

--if we put  explode = string.explode(param, "") it would be-- explode[1]

--Now to make it a little easier to read then t[1] we can add this:--

t[1] = player

Now we can type player everytime we want to tell the script to call the second param said by the player.

Now we have:

Lua:
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player

Now that we have all the information that the script needs before starting the script, we can start :p


Lua:
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then


Im sure you can figure out what this is saying. You see (isPlayer(player)) The script will check and see if the second param said by the player, is acually a player.

Lua:
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			                       -- /\  Notice player is used and not CID, thats because the player we want to change is not cid (cid calls for the player used the scirpt unless specified as different as shown is PART 1)--
Storage values are one tibia scripts most loved functions. You can make anytype of storage and set a value on it.
We put jail, this is just so the storage name is jail, if we put apple it would be apple, if we put 30001, it would be the same as first player items, and probably cause an error.
That means we dont want to put storage values that are used :p

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)

Used the first local now. The script will teleport the player. NOTE: Position automatically calls for XYZ.
Thats why jailPos will work, XYZ of jailPos is specified. (MAKE SURE YOU PUT THE NAME IN CORRECT WHEN PLACING A LOCAL VALUE IN THE SCRIPT! IT IS CAP SENSORED)

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
local MSG_TYPE = MESSAGE_STATUS_CONSOLE_RED
local jailMSG = "You have been jailed"
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)
			doPlayerSendTextMessage(player, MSG_TYPE, jailedMSG)

Added a few more locals, If I thought about the script before hand, these locals would be places already. But for tutorial purposes Im doing it this way.
The player will now get a message AFTER teleported. If you put it before he would get the message before (not that it matters here) but in some cases it does.

As this next function.

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
local MSG_TYPE = MESSAGE_STATUS_CONSOLE_RED
local jailMSG = "You have been jailed"
local EFFECT_TYPE = 10
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)
			doPlayerSendTextMessage(player, MSG_TYPE, jailedMSG)
			doSendMagicEffect(jailPos, EFFECT_TYPE) -- If this was before the teleport it would send the effect before the player teleported (understand?)--
		else
			doPlayerSendCancel(cid, "This is not a player")
			return false
		end
Now we have our first else. The else is connected to the last IF used. That is why the cancel is "this is not a player" It is connected to the
(isPlayer(player))
Always make sure to return false on a else, UNLESS the else is directing the script to be true, then put return true.
Then end that if.

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
local MSG_TYPE = MESSAGE_STATUS_CONSOLE_RED
local jailMSG = "You have been jailed"
local EFFECT_TYPE = 10
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)
			doPlayerSendTextMessage(player, MSG_TYPE, jailedMSG)
			doSendMagicEffect(jailPos, EFFECT_TYPE)
		else
			doPlayerSendCancel(cid, "This is not a player")
			return false
		end
	elseif (param == "/unjail") then

The first elseif introduced. The elseif is on the (param =="jail") if. You will no what im talking about when I say "on" if you use NotePad++.

So elseif the person says "/unjail"
When you use elseif it doesnt open an IF, so there is no end needed on it. Though you may have an if in the elseif that requiers an end.

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
local MSG_TYPE = MESSAGE_STATUS_CONSOLE_RED
local jailMSG = "You have been jailed"
local EFFECT_TYPE = 10
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)
			doPlayerSendTextMessage(player, MSG_TYPE, jailedMSG)
			doSendMagicEffect(jailPos, EFFECT_TYPE)
		else
			doPlayerSendCancel(cid, "This is not a player")
			return false
		end
	elseif (param == "/unjail") then
		if (isPlayer(player)) then
			if getPlayerStorageValue(player, Jailed) == 1 then
You see I told the script to check if the player has the jaled storage. This is so if its not a jaield player, it wont do anything. We wouldn't want to
have our script send a player to the temple thats trying to hunt :/

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
local MSG_TYPE = MESSAGE_STATUS_CONSOLE_RED
local jailMSG = "You have been jailed"
local EFFECT_TYPE = 10
local templePos = {x = 1000, y = 1000, z = 7}  -- if you typed getPlayerTownId(player)  YOU WOULD GET AN ERROR! This is because its player isn't known yet to the script.--
-- You can put it in the script, look down to see how --
local unjailMSG = "You have been unjailed!"
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)
			doPlayerSendTextMessage(cid, MSG_TYPE, jailedMSG)
			doSendMagicEffect(jailPos, EFFECT_TYPE)
		else
			doPlayerSendCancel(cid, "This is not a player")
			return false
		end
	elseif (param == "/unjail") then
		if (isPlayer(player)) then
			if getPlayerStorageValue(player, Jailed) == 1 then
			local templePos = getPlayerTownId(player)   -- You would put this here instead of making the local up there. --
				doTeleportThing(player, templePos)
				doPlayerSendTextMessage(player, MSG_TYPE, unjailMSG)
				doSendMagicEffect(templePos, EFFECT_TYPE)
			else
				doPlayerSendCancel(cid, "This player is not jailed!")
			return false
			end
else
	doPlayerSendCancel(cid, "You do not have access to these commands")
return false
end


This else if connected to the Access if. You notice it is wrapped over both param scripts. This means it will ask for it for both.

We could add if (param == "!something else") then after all that if we wanted a player to be able to use a command in here. (it would be out of the access request)
But for this script we dont need players to say anything. So now we can end everything.

Lua:
local jailPos = {x = 1000, y = 1000, z = 7}
local MSG_TYPE = MESSAGE_STATUS_CONSOLE_RED
local jailMSG = "You have been jailed"
local EFFECT_TYPE = 10
local templePos = {x = 1000, y = 1000, z = 7}  
local unjailMSG = "You have been unjailed!"
		
function onSay(cid, words, param, channel)
if (param == "") then
return false
end

t = string.explode(param, "")
t[1] = player
if getPlayerAccess(cid) >= 3 then
	if (param == "/jail") then
		if (isPlayer(player)) then
			setPlayerStorageValue(player, Jailed, 1)
			doTeleportThing(player, jailPos)
			doPlayerSendTextMessage(cid, MSG_TYPE, jailedMSG)
			doSendMagicEffect(jailPos, EFFECT_TYPE)
		else
			doPlayerSendCancel(cid, "This is not a player")
			return false
		end
	elseif (param == "/unjail") then
		if (isPlayer(player)) then
			if getPlayerStorageValue(player, Jailed) == 1 then
			local templePos = getPlayerTownId(player)
				doTeleportThing(player, templePos)
				doPlayerSendTextMessage(player, MSG_TYPE, unjailMSG)
				doSendMagicEffect(templePos, EFFECT_TYPE)
			else
				doPlayerSendCancel(cid, "This player is not jailed!")
			return false
			end
else
	doPlayerSendCancel(cid, "You do not have access to these commands")
return false
end
return true
end

Now the script is complete! Now if you have learned something from this, or you're clever, or you've just seen this script before. You will know that WE DONT HAVE
A WAY FOR THE PLAYERS TO GET OUT. Unless a gm kicks them out.

So we need to add a kick time. The way we are going to do this is adding a global event.

It gives function onThink(intraval)

So how do we get it to kick them?

Lua:
function onThink(intraval)
for i, pid in ipairs(getPlayersOnline()) do
if getPlayerStorageValue(pid, jailed) > 0 then
	setPlayerStorageValue(pid, jailed - 1)
	doTeleportThing(pid, getPlayerTownId(pid))
	return true
end
end
end

Loops/tables will not be explained in this tutorial, You can purchase my advanced tutorials witch recover this, and alot more, including the loops/tables, and other functions of lua.

Thats it for that script! Just sets the players storage value down everytime its specified. So if you want the jail time 10 minutes, in the XML file make the intraval 600


That sums up this tutorial. I hope I helped some new scripters.

Yes I know theres a better system (i've made it) this is to help noob scripters.
 
Last edited:
Nice work :) I recommend those which want become a scripter to look into this ^^ Btw, use mediafire instead of speedyshare :)
 
Tarjei, your close mindedness will get you cut off in places in life. You have to understand some people cant grasp scripting as fast as others. For there to be more of a availability, it helps. Plus this was just to get the idea what what/how I would be explaining some things.

Anyway, I spent the last couple days creating the tutorial I am going to sell.
It gets way more in depth, and is written better.

It goes from basic, to advanced, it covers:
1)locals/globals
2)functions/commands/variables
3)How to use the functions of lua (like while)
4) how to create tables
5) how to use loops
6) It also teaches you the best way to script
Which is definitely not offered above.

Pm me if your interested (not you tarjei), its 3$ USD
 
The first thing to remember for every script is.....EVERYTHING MUST BE DETERMINED...that means the script MUST be told EVERYTHING!

A table is just a "space" with nothing in it.

That is why a table looks like this.
Lua:
local table = {}
The {} is saying that there is nothing in there. We could do this with a table.--

local table = {x = {}, y = {}}

Now the table has the values x and y
Then we could do something like this.
Lua:
if isTable(table) then
	table.x = 1
	table.y = 5
end

Now the tables x = 1 and y = 5. We can also insert values into a table this way.
Lua:
table = {}
if isTable(table) then
	table.insert(table, x)
	table.insert(table, y)
end

Now we inserted x, and y into our table.
----------------------------------------------Here is an exmaple for a tibia script.----------------
Lua:
local players = {}
if isPlayer(pid) then
	table.insert(players, pid)
end
Note: This script alone would not work...But it would put the value "pid" in the table.
Therefor we can call pid from the table. How do we do that?

There are 2 ways, 1 is calling the value specificly.
[/code]
local player = table.find(players, pid)
local position = {x = 1000, y = 1000, z = 7}
if (player == true) then --if it can find pid in the table
doTeleportThing(player, position) --teleport the pid to the position
end
[/code]

The second way, witch is the next part of the tutorial...is...LOOOOPS...

Loops are ment to repeat a script as many times as told.
So we have to tell it 2 things...
1 what to call
2 when to stop
Lua:
for _, pid in ipairs(getPlayersOnline()) do
end
Here is one of the most basic loops you will see in tibia script.

The first thing you see is: for _, pid

The _ is defined as "each" for now, it can also be any value other then numbers or symbols like * + - /

So that means it says: for each, pid in ipairs

in ipairs is pretty much saying: in the values that are in

(getPlayersOnline()) do

So in hole it would be: for each, pid in ipairs(getPlayersOnline()) do

Now lets look at a script
Lua:
for _, pid in ipairs(getPlayersOnline()) do
if isPlayer(pid) then --This acually isn't needed because pid is already registered as a player but im using it for tutorial purposes
end
end
Now the loop is saying: for each player in the function getPlayersOnline() <--Can also think of it as a table because it holds a value
IF it is a player, and nothing else then
it will do the next part of the script, otherwise it will unregister the creature...

So if we used cid instead of pid, we would call EVERY creature in the game, but if we put the
Lua:
if isPlayer(cid) then
end
It would only act upon the players again

Another way to use loops is this

lets say you call param, and param has 5 values.

That means we have param param[2] param[3] param[4] and param[5]

We can do this
Lua:
for param = 1, 5 do
	doPlayerSendTextMessage(cid, 22, "This is a param: ")
end
This will send the person 1 text for each param.

this statment says: for param = 1

that is stating that we are calling the param, and starting with the first param.

then 5

Thats saying go to param 5
Lua:
for param = 1, 5 do
	if param == "bad word" then
		doPlayerSendCancel(cid, "You shouldn't say bad words")
	end
end
This would send them a text for any bad word that they said in the 5 words.
 
Last edited:
Back
Top