Skip to content

Plugin API

Cliven Mitchell edited this page Dec 6, 2018 · 23 revisions

What is the API?

The API is a set of properties, functions, and classes that provide scripting functionality to scripts. It acts as a bridge between Java and Kotlin, caching interpreted listeners that events will be posted to.

Every script has to have import api.predef.* as a top level declaration for importing vital scripting functions into local scope.

The rest of this section will elaborate on the specific functionality that the API provides for scripts.

Event interception functions

These kinds of functions use receivers in order to streamline code. The main event interception function is on. It does not terminate events by default. ex.

import api.predef.*

// Event will continue traversing!
on(CommandEvent::class) {
    plr.sendMessage("Command entered was $name!")
}

To terminate events explicitly, use this.terminate()

import api.predef.*

on(CommandEvent::class) {
    plr.sendMessage("Command entered was $name!")
    terminate() // Event will stop traversing!
}

Implicit terminations happen when on.condition or optimized Matcher functions are used.

import api.predef.*

on(WidgetFirstItemClickEvent::class)
    .condition { widgetId == 5068 }
    .then { ... } // 'then' do something

cmd("mypos", RIGHTS_DEV) { ... }

button(4100) { ... }

However, streamlined conditions that do not terminate the event are still possible through on.filter.

import api.predef*

// Does not terminate the event.
on(WidgetFirstItemClickEvent::class)
    .filter { widgetId == 5068 }
    .then { ... }

For more information, see the api.event package.

Helper properties & functions

Helper properties and functions are available to every script by declaring import api.predef.*. For more information, see the api.predef package.

Attribute delegates

Attributes are temporary (transient) or permanent (persistent) values assigned to mobs. Delegates allow us to access attributes as if they were properties.

The syntax for using them is as follows

import api.attr.Attr
import io.luna.model.mob.Player

var Player.myAttribute by Attr<Int>("my_attribute")

fun someFunction(plr: Player) {
    plr.myAttribute = 3
    println(plr.myAttribute)
}

A delegate also exists for creating compact attribute timers.

import api.attr.Stopwatch
import io.luna.model.mob.Player

var Player.myTimer by Stopwatch("my_timer")

fun someFunction(plr: Player) {

    // Satisfied if uninitialized or time since last reset > 2000ms
    if(plr.myTimer > 2000) {
        println("someFunction can only be called once every 2000ms")

        // Reset the timer
        plr.myTimer = -1
    }
}

Shop building

The api.shop package uses receiver functions to create a compact and elegant DSL for building shops.

A simple shop declaration with no items or open listeners looks like

shop {
    name = "Test Shop"
    buy = BuyPolicy.NONE // Shop won't buy any player's items
    restock = RestockPolicy.SLOW // Items will restock very slow
    currency = Currency.COINS // Takes coins 
}

We can stock shops with items by using sell

shop {
    name = "Test Store"
    buy = BuyPolicy.NONE
    restock = RestockPolicy.SLOW
    currency = Currency.COINS

    sell {
        item("Abyssal whip") x 10
        item("Dragon scimitar") x 15
        item("Lobster", noted = true) x 500
        ...
    }
}

And finally, we can add some event listeners using open. The properties inside are forwarded to optimized Matcher functions (and have the same names).

shop {
    name = "Test Store"
    buy = BuyPolicy.NONE
    restock = RestockPolicy.SLOW
    currency = Currency.COINS

    sell {
        item("Abyssal whip") x 10
        item("Dragon scimitar") x 15
        item("Lobster", noted = true) x 500
        ...
    }
    
    open {
        // NPC(520) second click opens this shop
        npc2 = 520

        // Object(2772) first click opens this shop
        object1 = 2772
    }
}

For more complex shop opening logic, an explicit event listener can be declared instead.


Continue to next section.