StendhalScripting/Lua: Difference between revisions

From Arianne
Jump to navigation Jump to search
Content deleted Content added
imported>AntumDeluge
Objects and Functions: some instructions on using the "luajava" object
imported>AntumDeluge
Some basics about Lua
Line 6: Line 6:


Lua scripts end in the <code>.lua</code> extension & are stored in the <code>data/script</code> directory.
Lua scripts end in the <code>.lua</code> extension & are stored in the <code>data/script</code> directory.

= Lua Basics =

For more detailed information, see the [https://www.lua.org/docs.html Lua reference manual].

== Comments ==

Lua uses double dashes (<code>--</code>) for single line comments & double dashes followed by double square brackets (<code>[[</code>) & closed with double square brackets (<code>]]</code>) for multi-line comments:
<pre>
-- a single line comment

--[[
a multi-line comment
]]
</pre>

== Variables ==

Be default, Lua variables are set in [https://en.wikipedia.org/wiki/Global_variable '''global''' scope] (meaning it is exposed to the entire Lua engine). To create a variable in [https://en.wikipedia.org/wiki/Local_variable '''local''' scope], the <code>local</code> keyword must be used:
<pre>
-- a global variable
var1 = "Hello world!"

-- a local variable
local var2 = "Hello world!"
</pre>

=== Tables ===

A Lua table is a data type similar to a list. Tables can be indexed or use key=value pairs.

''(<span style="color:red;">IMPORTANT NOTE: Lua table indexes begin at 1, not 0</span>)''

An empty table is initialized with a pair of curly braces (<code>{}</code>):
<pre>
local mytable = {}
</pre>

You can add values to indexed tables at initialization or with the <code>table.insert</code> method:
<pre>
-- create a table with values
local mytable = {
"foo"
}

-- add value
table.insert(mytable, "bar")
</pre>

To create a key=value table, any of the following methods can be used to add values:
<pre>
local mytable {
foo = "bar",
["foo"] = "bar",
}

mytable.foo = "bar"
mytable["foo"] = "bar"
</pre>

==== Iterating Tables ====

=== Functions ===

Like normal variables, functions can be declared as '''global''' or '''local''' & must be terminated with the <code>end</code> keyword.

There are two ways to declare functions:
<pre>
local function myFunction()
print("Hello world!")
end
</pre>

or
<pre>
local myFunction = function()
print("Hello world!")
end
</pre>

Functions can also be values in a table:
<pre>
local myTable = {}
function myTable.myFunction()
print("Hello world!")
end
</pre>

or
<pre>
local myTable = {}
myTable.myFunction = function()
print("Hello world!")
end
</pre>

or
<pre>
local myTable = {
myFunction = function()
print("Hello world!")
end,
}

-- execute with
myTable.myFunction()
</pre>

= Stendhal Application =


== Objects and Functions ==
== Objects and Functions ==

Revision as of 10:20, 2 April 2020


this page is a work-in progress

Stendhal supports Lua scripting via the LuaJ library.

Lua scripts end in the .lua extension & are stored in the data/script directory.

Lua Basics

For more detailed information, see the Lua reference manual.

Comments

Lua uses double dashes (--) for single line comments & double dashes followed by double square brackets ([[) & closed with double square brackets (]]) for multi-line comments:

-- a single line comment

--[[
a multi-line comment
]]

Variables

Be default, Lua variables are set in global scope (meaning it is exposed to the entire Lua engine). To create a variable in local scope, the local keyword must be used:

-- a global variable
var1 = "Hello world!"

-- a local variable
local var2 = "Hello world!"

Tables

A Lua table is a data type similar to a list. Tables can be indexed or use key=value pairs.

(IMPORTANT NOTE: Lua table indexes begin at 1, not 0)

An empty table is initialized with a pair of curly braces ({}):

local mytable = {}

You can add values to indexed tables at initialization or with the table.insert method:

-- create a table with values
local mytable = {
	"foo"
}

-- add value
table.insert(mytable, "bar")

To create a key=value table, any of the following methods can be used to add values:

local mytable {
	foo = "bar",
	["foo"] = "bar",
}

mytable.foo = "bar"
mytable["foo"] = "bar"

Iterating Tables

Functions

Like normal variables, functions can be declared as global or local & must be terminated with the end keyword.

There are two ways to declare functions:

local function myFunction()
	print("Hello world!")
end

or

local myFunction = function()
	print("Hello world!")
end

Functions can also be values in a table:

local myTable = {}
function myTable.myFunction()
	print("Hello world!")
end

or

local myTable = {}
myTable.myFunction = function()
	print("Hello world!")
end

or

local myTable = {
	myFunction = function()
		print("Hello world!")
	end,
}

-- execute with
myTable.myFunction()

Stendhal Application

Objects and Functions

The following objects & functions are exposed to the Lua engine:

luajava

This is an object of the LuajavaLib library. It can be used to coerce Java static objects to Lua or create new Java object instances.

Example of exposing a static object & enums to Lua:

-- store a Java enum in a Lua global variable
ConversationStates = luajava.bindClass("games.stendhal.server.entity.npc.ConversationStates")

-- access the enum values like so
ConversationStates.IDLE

Example of creating an object instance:

-- store instance in local variable
local dog = luajava.newInstance("games.stendhal.server.entity.npc.SilentNPC")
-- access object methods like so
dog:setEntityClass("animal/puppy")
dog:setPosition(2, 5)

-- class with constructor using parameters
local speaker = luajava.newInstance("games.stendhal.server.entity.npc.SpeakerNPC", "Frank")
speaker:setOutfit("body=0,head=0,eyes=0,hair=5,dress=5")
speaker:setPosition(2, 6)

To make scripting easier, Stendhal employs a master script & some helper objects & methods to handle the functionality mentioned above. An explanation of these objects & methods follows.

game

The main object that handles setting zone & adding entities to game.

Methods:

  • game:add(object) - Adds an object to the current zone.
  • game:setZone(name) - Sets the current zone.
  • game:createSign(visible) - Creates a new Sign instance.
  • game:createShopSign(name, title, caption, seller) - Creates a new ShopSign instance.

npcHelper

This object helps to create instances of SpeakerNPC & SilentNPC classes.

Methods:

  • npcHelper:createSpeakerNPC(name) - Creates a new SpeakerNPC.
  • npcHelper:createSilentNPC() - Creates a new SilentNPC.
  • npcHelper:setPath(npc, path, loop) - Sets the path for the specified NPC.
  • npcHelper:setPathAndPosition(npc, path, loop) - Sets the path & starting position of the specified NPC.
  • npcHelper:addMerchant(merchantType, npc, items, offer) - Adds merchant behavior to npc of either a buyer or seller defined by merchantType.
  • npcHelper:addSeller(npc, items, offer) - Adds seller merchant behavior to npc.
  • npcHelper:addBuyer(npc, items, offer) - Adds buyer merchant behavior to npc.

Setting Zone

To set the zone to work with, use the game object:

game:setZone("0_semos_city")

The logger is exposed to Lua via the logger object:

local zone = "0_semos_city"
if game:setZone(zone) then
	-- do something
else
	logger:error("Could not set zone: " .. zone)
end

Adding Entities

Signs

Signs can be created with game:createSign and game:createShopSign:

local zone = "0_semos_city"
if game:setZone(zone) then
	-- create the sign instance
	local sign = game:createSign()
	sign:setEntityClass("signpost")
	sign:setPosition(12, 55)
	sign:setText("Meet Lua!")

	-- Add it to the world
	game:add(sign)
else
	logger:error("Could not set zone: " .. zone)
end

NPCs

Use the game:createSpeakerNPC method to create an interactive NPC:

local zone = "0_semos_city"
if game:setZone(zone) then
	-- Use helper object to create a new NPC
	local npc = npcHelper:createSpeakerNPC("Lua")
	npc:setEntityClass("littlegirlnpc")
	npc:setPosition(10, 55)
	npc:setBaseSpeed(0.1)
	npc:setCollisionAction(CollisionAction.STOP)

	local nodes = {
		{10, 55},
		{11, 55},
		{11, 56},
		{10, 56},
	}

	-- Use helper object to create NPC path
	npcHelper:setPath(npc, nodes)

	-- Dialogue
	npc:addJob("Actually, I am jobless.")
	npc:addGoodbye();

	-- Add to the world
	game:add(npc)
else
	logger:error("Could not set zone: " .. zone)
end

Adding Merchant Behavior

Merchant behavior (buying/selling) can be set with one of the following helper functions:

  • npcHelper:addMerchant(merchantType, npc, prices, addOffer)
  • npcHelper:addBuyer(npc, prices, addOffer)
  • npcHelper:addSeller(npc, prices, addOffer)
    • Arguments:
      • merchantType: (string) If set to "buyer", will add buyer behavior, otherwise will be "seller" (may change type to boolean in future).
      • npc: (SpeakerNPC) The NPC to add the behavior to.
      • prices: (Map<String, Integer> or LuaTable) List of items & their prices.
      • addOffer: (boolean) If true, will add default replies for "offer".

Example of adding seller behavior to an NPC:

if game:setZone("0_semos_city") then
	local frank = npcHelper.createSpeakerNPC("Frank")
	npcHelper:addSeller(frank, shops:get("shopname"), true)

	game:add(frank)
end

To create a custom shop list, you can use a Lua table (there are multiple ways to add elements to a Lua table):

Method 1:

local priceList = {
	meat = 50,
	["ham"] = 70,
}

Method 2:

local priceList = {}
priceList.meat = 50
priceList["ham"] = 70

The helper methods have special handling for underscore characters as well (the following are all the same):

local priceList = {
	smoked_ham = 100,
	["smoked ham"] = 100,
}
priceList.smoked_ham = 100
priceList["smoked ham"] = 100

Then add the seller behavior using the custom list:

npcHelper:addSeller(frank, priceList, true)