Script events (functions):

When certain things happen, such as the player colliding (touching) with the NPC, then the script of the NPC is started and can react to the collision event. You can react to the event by writing a function "function onEventname" such as

function onPlayerSays(pl) {
}

Following events exist right now:

Objects and global variables

Following objects and variables exist. Some of these are read-only. You can additionally set attributes of the objects and call functions.

NPC

The NPC object can be accessed by the identifier this. If you change a property (such as image or ani) and want it to be permanent, then call this.save(). Most attributes can also be changed by calling setATTRIBUTE(name) such as this.setchat(text). NPC functions are currently also available as global functions, so that you can call either "this.say(text)" or "say(text)", although the use of this.say is recommended. Object attributes defined in Tiled can also be accessed by script, such as this.npcclass.

Player

The player who was causing the event can be accessed with the identifier player

You can add custom variables to the player object (player.myvar = 123). These are kept until the player logouts.

setting description
soundsoff Turn off sound effects
musicoff Turn off background music
hidehome Hide the home button
hideminimap Hide the minimap (on right side)
nomobilezoom Zoom out the game (mobile)
zoom2x Zoom in the game (desktop)
hidenames Hide player names (show with N key)
hidesidekicks Hide pets which follow other players
nohouseinvites No house invitations
noclaninvites No clan invitations
nosparinvites No spar invitations
nolikemsg No like notifications
noweather Hide weather effects

Server

Server.searchplayers(options:{}) - returns an array of players which match the options. Possible combinations for options are: {id:number}, {map:string}, {clanname:string}, {clanid:integer}, {map:string, clanname:string}, {map:string, clanid:integer}, {} (full server)

function onPlayerTouchsMe(pl) {
      //Find all the players on the map with the same clan name as the player that has touched the object
    let arr = Server.searchPlayers({map:pl.map.name, clanname:pl.clanname});

      //A message to show the players it has found with the above criteria
    this.say("Found " + arr.length + " members of " + pl.clanname +
      " (" + pl.clanid + ")! List on console.");

      //Loop through all the players it has found and set their chat
    for (let i = 0; i < arr.length; i ++) {
        arr[i].chat = "Found"; //Make the player say 'Found' if they meet the criteria above
    }
}

Server.searchnpcs({map, area:{x,y,w,h}}) or alternatively {id:ID} or {name:NAME} (name search right now only returns a single NPC)

function onUpdated(pl) {
    let npcs = Server.searchnpcs({
        map: this.map,
        area:{x:this.x-20, y:this.y-20, w:40, h:40}
    });
    for (let i in npcs)
        npcs[i].scheduleevent(0, "otherevent", this);
}

//Add the onOtherEvent function to the other NPCs to see them triggered.
function onOtherEvent(caller) {
    echo("called NPC: " + this.id + " from " + caller.id);
}  

Server.getconfig(filewithoutextension: string [, indexAttribute] [, categoryAttribute]) - loads a configuration file (fast), the configuration should have the structure {filename:[objects]}, the returned object also contains ways for quick lookup: objects: array of all objects, index[name] one object, category[name] array of objects

Server.getconfig examples:

echo("default weapon: " + Server.getconfig("main").defaultweapon);
  -> sword1
echo("config skeleton: ", Server.getconfig("monsters", "type").index["skeleton"]);
  -> { type: 'skeleton', name: 'Pirate Skeleton', ...}
echo("config item nr: " + Server.getconfig("items", "itemid", "itemtype").objects.length);
  -> 591
echo("config weapon nr: " + Server.getconfig("items", "itemid", "itemtype").categories["weapon"].length);
  -> 97
echo("config sword1: ", Server.getconfig("items", "itemid", "itemtype").index["sword1"]);
  -> { itemid: 'sword1', name: 'Standard Sword', itemtype: 'weapon', ...}  

Server.message(message:string) - displays a message for all players, similar to /servermessage

Misc

Scripting example:

This adds a firework once you say three times "yes". The firework1 item must have the attributes "addbyscript":true and "addinmaps":["currentmapname"].

function onPlayerTouchsMe(pl) {
    this.say("Say 'yes' three times if you want to get a firework!");
}

function onPlayerSays(pl) {
    if (player.chat == "yes") {
        player.saycounter = (player.saycounter? player.saycounter+1 : 1);
        if (player.saycounter < 3)
            this.say("Say 'yes' " + (3-player.saycounter) + " more time(s)!");
        else {
            player.saycounter = 0;
            if (player.hasitem("firework1"))
                this.say("You already have that!");
            else if (player.additem("firework1"))
                this.say("There it is!");
            else
                this.say("There was a problem adding the item!");
        }
    }
}  

Scheduling a timeout or a scheduled event

function onPlayerTouchsMe(pl) {
    if (!this.touched)
      this.touched = 0;
    this.touched++;
    this.say("check: " + pl.name + " - " + this.touched + " - " + pl.x);

    this.settimeout(2); //Start the timeout
    this.scheduleevent(1, "myevent", 123); //Or start a scheduled event
}

//After 2 seconds the timeout function is called
function onTimeout() {
    this.say("Timeout!");
}

//After 1 second the scheduled event is called
function onMyEvent(testvar) {
    this.say("MyEvent: " + testvar + "!");
}  

Copy and NPC Movement

//If the player says copy, the NPC will look exactly like the player
function onPlayerSays(pl) {
    switch (pl.chat) {
        case "copy": {
            this.setani("player_idle"); // pl.ani);
            this.sethead(pl.head);
            this.setbody(pl.body);
            this.sethat(pl.hat);
            this.setweapon(null); // pl.weapon);
            this.setmount(null); // pl.mount);
            this.setbow(pl.bow);
            this.save();
            this.say("Copied you!");
            break;
        }
        case "come": {  
            let time = 1;
            this.scheduleevent(time, "movefinished", this.ani); //Invoke the MoveFinished event once it arrives at the destination
            this.setani("player_walk"); //Act as though the object is moving
            this.move(time, player.x, player.y); //Move the object to the location of the player
            break;
        }
    }
}

//Created by the scheduleevent above and is called once the object has finished moving
function onMoveFinished(newani) {
    this.setani(newani);
}  

GUI Controls

Gui Controls are used to pop up a window on the players screen, on client-side. The functions that are used are:

Example: GUI-Controls

DB

Database tables must be created manually be the server admin. Following function exist to access the database:

Example: Database

PMs

Send a simple PM:

player.showpm("Hello!");

Send a PM with name and head icon:

player.showpm("Hello!", {name:"Mario", isadmin:true, isonline:true, head:"head2", hat:"hat5"});

Send a PM and react to the reply of the player:

let sender = {name:"Puzzle", isonline:true};
player.showpm("What is 2+2? Tell me the answer!", sender, function(player, msg) {
  if (msg == "4")
    player.showpm("That's correct!", sender);
  else
    player.showpm("Sorry that's wrong!", sender);
});

Send a PM with story as invitation (using the optional third data parameter):

player.showpm(message, null, {type:"invitation", storyid:1807});

Send a PM with map markers:

player.showpm("Hello!", {head:"1", name:"Go here to find food!"}, {mapmarkers:[
  { "x":375, "y":193, "text":"Trash", "icon":"job_trash-bottle.png", "blink":true}
]});

Send a PM on touch which automatically opens, by setting show:true in the data parameter. Additional advantage: the player can easily translate the text:

function onPlayerTouchsme(pl) {
    pl.showpm("Did you know you can change your name with /setname?",
        {head:"1", name:"Guide"},
        {show:true});
}

Music

Client-side juke-box, use commands play1, play2, play3, play radio and stop music

function onPlayerSays(pl) {
    switch (pl.chat) {
        case "play1": { this.setmusic("egyptmusic.mp3"); break; }
        case "play2": { this.setmusic("dungeon_music1.mp3"); break; }
        case "play3": { this.setmusic("diningmusic.mp3"); break; }
        case "play radio": { this.setmusic("http://streams.antennemv.de/antennemv-live/mp3-128/listenlive/play.m3u"); break; }
        case "stop music": { this.stopmusic(); break; }
    }
}

Map Properties