Map Editor/Scripting

Fantasy Tales Online uses Javascript (JS) as its scripting engine. All the JS executing happens server-side to manipulate the character objects. The synchronization is handled by the API. This is the same flavor of JS used by web browsers without the DOM & Web APIs. Any JS language document should be applicable as long as their don't reference any DOM or Web APIs.

## The API

The best resources for scripting help is by consulting the API documentation:

Rhino Scripting API: http://varium.fantasytalesonline.com/sandbox/rhino/

If you have an issue with the API please notify the staff on the forums.

### Examples

The best way to get familiar with a new scripting API to look at some example. Here's some examples for some common behavior:

#### Spawn Location

Use the special 'prescript\_spawn\_location' to instruct where new characters should spawn.

```
function prescript_spawn_location() {
    return ["Arden1,3,0", 1200, 1696];
}

```

#### Quest Chatter

Simple chatter based on the quest progression.

```
function on_click(npc, player) {
    if (player.quest_isWorkingOnQuest("The Blobs")) {
        npc.sendMessageToPlayer(player, "Thank you kindly for helping me! the supplies are at the Winterfront village general store.");
    } else if (player.quest_hasCompletedQuest("The Blobs")) {
        npc.sendMessageToPlayer(player, "You're an amazing person! Thank you for helping me.");
    } else {
        npc.sendMessageToPlayer(player, "Ooh! a visitor... how wonderful. Please stay for a good long while. I haven't seen anyone in months.");
    }
}

```

#### Completing a quest objective

Here we have the script for a bed with an objective to set your spawn point. Clicking this object will update your spawn point and if you're working on a quest it will set the objective completed by setting the quest cookie. Note that this quest has a quest objective set to look for 'set\_spawn' in the quest editor.

```
function on_click(npc, player) {
    if ( player.quest_isWorkingOnQuest("Take A Rest")) {
        player.quest_storeCookie("Take A Rest", "set_spawn", true);
    }
    player.sendMessageToPlayer(player, "ZzZzZ");
    player.sendMessage("Spawn Location Set!");
    player.addHP(10000);
    player.setSpawnLocation(npc.getMap().getMapName(), player.getX(), player.getY());
}

```

#### Waypoint Chatter

This is the script for an NPC character with various waypoints. This will call 'on\_waypoint' and is used to script chat messages at each waypoint.

```
function on_load (npc){
        npc.setBlockable(false);
}

function on_playermapenter (npc, player){
        npc.setBlockable(false);
}

function on_click (npc, player) {
        npc.sendMessageToPlayer(player, "Argh! *snort* Raaah!");
}

function on_waypoint (npc, waypoint) {
        if (waypoint == "stop1" ) {
                npc.sendMessageToMap("Wolf. Kill. Fire. Yum!");
                npc.waitAtNextWaypoint(5000);
        }

        if (waypoint == "stop2" ) {
                npc.sendMessageToMap("*snort* FIZZLE... Boombala! *snort*");
                npc.waitAtNextWaypoint(5000);
        }

        if (waypoint == "stop3" ) {
                npc.sendMessageToMap("BBQ Troll. Yum!");
                npc.waitAtNextWaypoint(5000);
        }

        if (waypoint == "stop4" ) {
                npc.sendMessageToMap("ARGH!");
                npc.waitAtNextWaypoint(5000);
        }

        if (waypoint == "stop5" ) {
                npc.sendMessageToMap("Meep! *snort*");
                npc.waitAtNextWaypoint(5000);
        }
}

```

#### Object visibility based on quest status

This script will check if the quest status each time a players enter the map and decide how that player should view this object. In this case this object will be hidden only for the receiving player by calling |npc.setAlpha(alpha, player);|.

```
function prescript_cavein_rocks(npc) {
    var self = this;
    var questName = "Cave In Rescue Part 2";
    var cookieName = "cavein_pick";

        this.updateState = function(npc, player) {
            var isShow = !player.quest_hasReturnedQuest(questName);
            var alpha = isShow ? 100 : 0;

            npc.setAlpha(alpha, player);
        };

        this.on_playermapenter = function (npc, player) {
            self.updateState(npc, player);
        };

        this.on_quest_statuschange = function (npc, player, quest) {
            if (quest == questName) {
               self.updateState(npc, player);
            }
        };
}

```

and the rect object provides the collisions for the warp only if you have completed the quest to clear the rocks:

```
function on_rectobj_load(map,x,y,w,h,rect) {
  prescript_winterfrontmines_link(map, x, y, w, h);
}

function prescript_winterfrontmines_link(map, x, y, w, h) {
    var self = this;
    var questName = "Cave In Rescue Part 2";

    map.collisionFunction(x, y, w, h, function(player) {
        if (player.quest_hasReturnedQuest(questName)) {
            player.warpToOtherMap("Arden2,0,-1", 400, 1088);
        }
    }, null);
}

```

#### Puzzle block

Here's a puzzle block that will block players from moving through it. It is activated when the right trigger event is sent to this object by the switch.

```
var spriteBlocked = "image:data/sprite/dungeon/puzzleBlocker.png,64,64,0,0,0";
var spriteUnblocked = "image:data/sprite/dungeon/puzzleBlocker.png,64,64,0,64,0";
var isBlockedAtStart = true;

prescript_dungeon_blocker(npc, spriteBlocked, spriteUnblocked, isBlockedAtStart);

function prescript_dungeon_blocker(npc, spriteBlocked, spriteUnblocked, isBlockedAtStart) {
    var currentBlockedState = isBlockedAtStart;
    npc.on_trigger(npc.getSharedVar("trigger"), function() {
        currentBlockedState = !currentBlockedState;

        if (currentBlockedState) {
            npc.setSprite([spriteBlocked]);
        } else {
            npc.setSprite([spriteUnblocked]);
        }
        npc.setBlockable(currentBlockedState);
    });
    npc.setBlockable(currentBlockedState);
    npc.setTargetable(false);
}

```

#### Custom Tutorial

If you want to have a tutorial for your server you can use this model:

```
function prescript_tutorial(player) {
    var questName1 = "We Need Help";
    var questName2 = "Test Your New Weapon";

    function getWeaponInInventory(player) {
        var items = player.getInventoryList();
        for (var i = 0; i < items.length; i++) {
            if (items[i].isWeapon()) {
                return items[i];
            }
        }
        return null;
    }

    function checkNewStage(stageId) {
        var stage = player.getCookie("tutorial_stage");
        if (stageId != stage && stageId == 6) {
            player.playSound("pickup1");
            player.storeCookie("tutorial_stage", stageId);
        }
    }

    // Make sure everything is completed in order
    if (!player.getCookie("tutorial_objective_start") && !player.quest_hasReceivedQuest(questName1)) {
        checkNewStage(0);
        player.tutorialHighlightMap("Tutorial:\nTo move use the WASD keys or the mouse. Talk to Hew for your first quest.", function () {
            player.playSound("pickup1");
            player.storeCookie("tutorial_objective_start", true);
            prescript_tutorial(player);
        });
    } else if (!player.quest_hasReceivedQuest(questName1)) {
        checkNewStage(1);
        player.tutorialHighlightArrow("right", "Arden1,3,0", 1200, 1640, "Talk to Hew");
    } else if (!player.getCookie("tutorial_objective")) {
        checkNewStage(2);
        player.tutorialHighlightObjective("Your quest objective(s) will show up here.", function () {
            player.playSound("pickup1");
            player.storeCookie("tutorial_objective", true);
            prescript_tutorial(player);
        });

....

    } else if (!player.quest_hasReturnedQuest(questName2)) {
        checkNewStage(8);
        player.tutorialHighlightArrow("down", "Arden0,2,0", 1095, 1711);
        player.tutorialHighlightArrow("down", "Arden0,3,0", 1557, 269);
        player.tutorialHighlightArrow("right", "Arden0,3,0", 1800, 552);
        player.tutorialHighlightArrow("down", "Arden1,3,0", 339, 727);
        player.tutorialHighlightArrow("right", "Arden1,3,0", 722, 928, "Return the quest");
        player.tutorialHighlightArrow("up", "Arden1,3,0", 964, 706);
        player.tutorialHighlightArrow("up", "Arden1,3,1", 843, 327, "Talk to Folmar");
    } else if (!player.getCookie("tutorial_done")) {
        checkNewStage(9);
        player.tutorialHighlightMap("Now you're on your own. Follow the map and head to the mines to the east for some real combat or do some quests in town first.", function () {
            player.storeCookie("tutorial_done", true);
            player.playSound("pickup1");
            player.setAchievement("ACHIEVEMENT_EDUCATED");
            checkNewStage(10);
            prescript_tutorial(player);
        });
    }

    // Mark the current set of tutorial entry to set atomically
    player.tutorialHighlightReady();
}

```