Basics of Scripting
Introduction
This tutorial explains how to write clean script and how to make some things. Please see the Dictionary for more information about each keywords.
Clean Script
I've seen horrible scripts. So I decided to make a style guideline here.
Indent
Indenting your script makes it much more readable. Compare the following scripts:
function lol() if wut==1 then if lolwut==2 then Game.KillPlayer() end end end
and
function lol() if wut==1 then if lolwut==2 then Game.KillPlayer() end end end
Makes it easier to see if you forget an end for example. ;-)
Comments
You should comment your script so that someone who could be interested how this is done could understand the script, but don't comment too much because that makes the script messy.
... if somevar==2 then -- here we see if the player plaaplaaplaa... ...
Other
You can use ";" to join lines without linechange
This is okay:
zone1={};visited1=0"
But do not connect too many lines.
Please, do not put if and then on separate lines
if somevar!=something then ...
Instead:
if lol==1 then ...
Using the () in the if is optional:
if(lol==1)then ...
How-To Section
Here we collect how to scripts. like "How-to make an elevator?" or "How-to make a jump button?"
You can't download example levels because this wiki doesn't allow me to upload .lvl files anymore: "This file contains HTML or script code that may be erroneously be interpreted by a web browser.". I know it sucks. It's just xml with some lua.
How-to make an elevator?
What we need:
- a dynamic block
- the block id must be "blockele1"
- a zone, id "zoneele1"
The Script:
zoneele1={} function zoneele1.OnEnter() -- when we enter the zoneele it starts the elevator. h=10 --height (how much up we go) speed=2000 -- how long it takes to go there (speed depends on the h) wait=200 -- how long to wait before starting the elevator (200=2s) Game.SetDynamicBlockTranslation("blockele1",0,h,speed,wait,wait+(speed/2)) end
You can edit the variables to fit your needs.
How-to make a jump key?
This is easy, it can be done purely with script.
function OnLoad() Game.SetKeyHook("J","Jump") -- bind the J key to the Jump function below return true end function Jump() Game.AddForceToPlayer(0,10000,0,10,0) end
With that script the player can cheat and jump even when on air. We want the player only to be allowed to jump when on ground again. So we need a variable to see if the player has jumped already:
hasjumped=true --you can use 1 as well function OnLoad() Game.SetKeyHook("J","Jump") -- bind the J key to the Jump function below return true end function Jump() if hasjumped==false then hasjumped=true Game.AddForceToPlayer(0,10000,0,10,0) end end function OnWheel2Touchs(bStatus) --rearwheel if bStatus==1 then -- only when touching not when leaving the ground hasjumped=false --we touch the ground so we must be jumped. end end
How-to make zoom buttons?
Zooming is somewhat easy, but it recuires some script to do, I have this old piece of script I got from Lothar's level, I've changed it to be more configurable. You can use it as it is, just remember to leave the comments about the creators of the script there :)
--original script by Lothar --upgraded by Tuhoojabotti 18.12.2008 --settings zoomlevel = 1 --default zoom blockzoom = 0 --enable/disable zoom 0=enabled zoominbutton="I" zoomoutbutton="O" maxzoomout=4 --strokes maxzoomin=0 --strokes step=0.05 --amount of zoom per stroke function OnLoad() Game.Message("Press "..zoominbutton.." to zoom in") Game.Message("Press "..zoomoutbutton.." to zoom out") Game.SetKeyHook(zoominbutton, "ZoomIn") Game.SetKeyHook(zoomoutbutton, "ZoomOut") return true end function ZoomIn() if zoomlevel==maxzoomin then Game.ClearMessages() Game.Message("Can't zoom in any further.") else if blockzoom==0 then Game.CameraZoom(step) zoomlevel = zoomlevel-1 end end end function ZoomOut() if zoomlevel==maxzoomout then Game.ClearMessages() Game.Message("Can't zoom out any further.") else if blockzoom==0 then Game.CameraZoom(-step) zoomlevel = zoomlevel+1 end end end
How-to make readable signs?
You need:
- Entities, like: sign1, sign2, sign3, ...
- Zones, like: signz1, signz2, signz3, ...
- a variable to hold the sign texts; SignText=""
- and a keyhook for the Read function
Zones:
SignText="No signs here..." signz1={}--;signz2={};signz3={};... function OnLoad() Game.Message("Hello, you can read signs with 'R' key.") Game.SetKeyHook("R","Read") return true end function Read() --read teh sign Game.Message(SignText) end --repeat this for all zones... function signz1.OnEnter() SignText="This is the Sign1 it says: plaaplaaplaplapal..." end function signz1.OnLeave() --this is optional SignText="No signs here..." end --end repeat block
Somewhat easier way is to use Entity.Touch() event, which doesn't have leave support, but then you can dump the zones.
Entities:
SignText="No signs here..." sign1={}--;sign2={};sign3={};... function OnLoad() Game.Message("Hello, you can read signs with 'R' key.") Game.SetKeyHook("R","Read") return true end function Read() --read teh sign Game.Message(SignText) end --repeat this for all entities... function sign1.Touch() SignText="This is the Sign1 it says: plaaplaaplaplapal..." end --end repeat block
How-to make a explore script?
I found this script from aeRo - Crazy Elevator. This is pretty easy, just need:
- Zone called 'zone_explore'
- few variables:
- canexplore = false
- isexploring = false
- explored_x = 0
- explored_y = 0
- move_step = 5
- limit_right = 20
- limit_left = 0
- limit_up = 3
- limit_down = 2
- explore_zoom=0.15
Here is the script:
--EXPLORE SCRIPT --original script by aeRo --wikied + options added by tuhoojabotti 22.06.2009 --BASE zone_explore = {} --states canexplore = false isexploring = false --position explored_x = 0 explored_y = 0 --OPTIONS --how much to move on single stroke move_step = 5 --how many times u can move to x direction limit_right = 67 limit_left = 0 limit_up = 3 limit_down = 2 --zoom in explore mode explore_zoom=0.15 function OnLoad() Game.SetKeyHook("E", "explore") Game.SetKeyHook("A", "explore_left") Game.SetKeyHook("S", "explore_down") Game.SetKeyHook("D", "explore_right") Game.SetKeyHook("W", "explore_up") return true end --EXPLORE ZONE function zone_explore.OnEnter() Game.Message("Press E to explore the level.") canexplore = true end function zone_explore.OnLeave() cancel_explore() canexplore = false end function explore() if canexplore == true and isexploring == false then explored_x = 0 explored_y = 0 isexploring = true Game.CameraZoom(-explore_zoom) Game.ClearMessages() Game.Message("Press W,A,S,D to explore.") Game.Message("E again to cancel.") elseif isexploring == true then cancel_explore() end end function cancel_explore() if isexploring == true then isexploring = false Game.ClearMessages() Game.CameraMove(-explored_x, -explored_y) Game.CameraZoom(explore_zoom) end end --MOVING EXPLORE function explore_left() if isexploring == true and explored_x ~= limit_left*move_step then Game.CameraMove(-move_step, 0) explored_x = explored_x - move_step end end function explore_right() if isexploring == true and explored_x ~= limit_right*move_step then Game.CameraMove(move_step, 0) explored_x = explored_x + move_step end end function explore_up() if isexploring == true and explored_y ~= limit_up*move_step then Game.CameraMove(0, move_step) explored_y = explored_y + move_step end end function explore_down() if isexploring == true and explored_y ~= -limit_down*move_step then Game.CameraMove(0, -move_step) explored_y = explored_y - move_step end end
Just paste the script and edit the options. :)
How-to make a trainer script?
Loads of people have been asking about this, it is rather simple. All you need is:
- a keyhook
- an entity (like a sprite)
and here it is:
function OnLoad() Game.SetKeyHook("1","trainer1") -- create the keyhook on load of the level return true -- without this x-moto crashes end function trainer1() x,y=Game.GetEntityPos("entity1") Game.SetPlayerPosition(x,y,0) -- the 0 can be set to 1 if you want the player to face right after teleport end
Debugging
General
Basically debugging means figuring out what makes the script behave unwanted ways or fix crashing. It is a good way to comment lines which you think makes the script crash and then start uncommenting then line by line till you find the crash spot, then try to figure out what is wrong:
- typo (spelling error)
- invalid parameter in function call
- block not existing
- block not dynamic
- dynamic block in wrong layer
If some action doens't work but doesn't crash either try using Game.Message("debug") to see if the script is ever even executed. In X-Moto scripts the script must be in an event otherwise the script is never executed.
If you get an error with line number then to find the exact line, count the script's lines ignoring all empty lines, that is how you should be able to find the correct line, since the script parser removes empty lines before executing the script.
Err. SetDynamicBlockTranslation crashes
Check that blocks all blocks are dynamic and in the main layer. Also look for typos in script. If the level has 2 or more main layers then the block must be in the original main layer.
Err. Zone.OnEnter fails
Is the zone defined at the start of the level like: Zone={}? X-Moto don't know to call the OnEnter function if you haven't defined it.