编辑“︁
StendhalScripting/Lua
”︁
跳转到导航
跳转到搜索
警告:
您没有登录。如果您进行任何编辑,您的IP地址会公开展示。如果您
登录
或
创建账号
,您的编辑会以您的用户名署名,此外还有其他益处。
反垃圾检查。
不要
加入这个!
{{Navigation for Stendhal Top|Playing}} <span style="color: red; font-style: italic;">this page is a work-in progress</span> Stendhal supports [https://www.lua.org/ Lua scripting] via the [https://sourceforge.net/projects/luaj/ LuaJ library]. 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 == By 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> == Data Types == Some common data types in Lua are ''string'', ''integer'', ''boolean'', & ''table''. Type names do not need to be declared when setting variables. Examples: <pre> -- string variable local var1 = "Hello world!" -- integer variable local var2 = 11 -- boolean variable local var3 = true -- table variable local var4 = {} </pre> === Strings === ==== String Concatenation ==== String concatenation is simple, much like Java uses a plus operator (<code>+</code>) to join strings, Lua uses two periods (<code>..</code>). Example: <pre> -- create a string variable local var = "Hello" -- append another string var = var .. " world!" print(var) -- prints "Hello world!" </pre> === Tables === A Lua table is a data type similar to a Java list or map. Tables can be indexed or use key=value pairs. ''(<span style="color:red;">IMPORTANT NOTE: Lua table indexes begin at 1, not 0</span>)'' ==== Creating Tables ==== 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> -- all of these do the same thing, that is, assigning "bar" to mytable.foo local mytable { foo = "bar", ["foo"] = "bar", } mytable.foo = "bar" mytable["foo"] = "bar" </pre> ==== Accessing Table Values ==== Square brackets (<code>[]</code>) enclosing an index number are used to access values in indexed tables (''remember that Lua table indexes start at "1" not "0"''): <pre> local mytable = {"foo", "bar"} print(mytable[1]) -- prints "foo" print(mytable[2]) -- prints "bar" </pre> In a key=value table, values can be accessed by either enclosing the key string in square brackets or concatenating the key member using a <code>.</code>: <pre> local mytable = {foo="bar"} -- using square brackets print(mytable["foo"]) -- prints "bar" -- using concatenated member print(mytable.foo) -- prints "bar" </pre> ==== Iterating Tables ==== Tables can be iterated in a <code>for</code> loop using the <code>pairs</code> or <code>ipairs</code> iterators. Loops are terminated with the <code>end</code> keyword: <pre> local mytable = {"foo", "bar"} print("indexes:") for idx in pairs(mytable) do print(idx) end print("\nvalues:") for idx, value in pairs(mytable) do print(value) end </pre> Output: <pre> indexes: 1 2 values: foo bar </pre> Using a key=value table: <pre> local mytable = { ["foo"] = "hello", ["bar"] = " world!", } print("keys:") for key in pairs(mytable) do print(key) end print("\nvalues:") for key, value in pairs(mytable) do print(value) end </pre> Output: <pre> keys: foo bar values: hello world! </pre> See also: [http://lua-users.org/wiki/TablesTutorial Lua Tables Tutorial] === 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 define functions with the <code>function</code> keyword: <pre> local function myFunction() print("Hello world!") end </pre> or <pre> local myFunction = function() print("Hello world!") end </pre> Functions can also be members of 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> == Comparison Operators == {| class="wikitable" |+ Logical Operators ! Operator !! Description !! Java Equivalent |- | and || logical ''and'' || && |- | or || logical ''or'' || <nowiki>||</nowiki> |- | not || logical ''opposite'' || ! |} {| class="wikitable" |+ Relational Operators ! Operator !! Description !! Java Equivalent |- | < || less than || < |- | > || greater than || > |- | <= || less than or equal to || <= |- | >= || greater than or equal to || >= |- | == || equal to || == |- | ~= || not equal to || != |} = Stendhal Application = == Zones == === Setting Zone === To set the zone to work with, use the <code>game</code> object: <pre> game:setZone("0_semos_city") </pre> === Create New Zone === It is recommended to create new zones in the XML configurations in {{StendhalFile|master|data/conf/zones|data/conf/zones}}. Currently creating new zones via Lua is not supported. === Add Zone Music === Music can be added to zones with the <code>game:setMusic</code> function. It supports the following arguments: * <span style="color:darkgreen; font-style:italic;>filename:</span> Basename of the OGG audio file to use stored in {{StendhalFile|master|data/music|data/music}}. * <span style="color:darkgreen; font-style:italic;>args:</span> A table of key=value integers. * Valid keys: ** <span style="color:darkblue; font-style:italic;">volume:</span> Volume level (default: 100). ** <span style="color:darkblue; font-style:italic;">x:</span> The horizontal point for the source of the music (default: 1). ** <span style="color:darkblue; font-style:italic;">y:</span> The vertical point for the source of the music (default: 1). ** <span style="color:darkblue; font-style:italic;">radius:</span> The radial range at which the music can be heard (default: 10000). Example: <pre> if game:setZone("0_semos_plains_n") then game:setMusic("pleasant_creek_loop", {volume=85, radius=100}) end </pre> == Adding Entities == === Signs === Signs can be created with <code>entities:createSign</code> and <code>entities:createShopSign</code>: <pre> local zone = "0_semos_city" if game:setZone(zone) then -- create the sign instance local sign = entities: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 </pre> === NPCs === Use the <code>entities:createSpeakerNPC</code> method to create an interactive NPC: <pre> local zone = "0_semos_city" if game:setZone(zone) then -- Use helper object to create a new NPC local npc = entities: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}, } npc:setPath(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 </pre> ==== Adding Transitions ==== A simple example of adding a chat transition can be done without any special functionality: <pre> local frank = entities:createSpeakerNPC("Frank") frank:add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES, nil, ConversationStates.ATTENDING, "Hello.", nil) </pre> This simply adds a response to saying "hello" & sets the NPC to attend to the player (equivalent of <code>frank:addGreeting("Hello")</code>). For more complicated behavior, we need to use some helper methods. If we want to check a condition we use the <code>conditions:create</code> method. The first parameter is the string name of the ChatCondition we want to instantiate. The second parameter is a table that contains the values that should be passed to the ChatCondition constructor. Example: <pre> frank:add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES, conditions:create("PlayerHasItemWithHimCondition", {"money"}), ConversationStates.ATTENDING, "Hello.", nil) </pre> In this scenario, the NPC will only respond if the player is carrying <item>money</item>. A NotCondition instance can be created with the <code>actions:notCondition</code> method: Example usage: <pre> local condition = conditions.notCondition(conditions:create("PlayerHasItemWithHimCondition", {"money"}) </pre> To add a ChatAction, we use the <code>actions:create</code> method. Its usage is identical to <code>conditions:create</code>. Example: <pre> frank:add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES, conditions:create("PlayerHasItemWithHimCondition", {"money"}), ConversationStates.ATTENDING, "Hello.", actions:create("NPCEmoteAction", {"looks greedily at your pouch of money.", false})) </pre> Lua tables can be used to add multiple conditions or actions: <pre> frank:add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES, { conditions:create("PlayerHasItemWithHimCondition", {"money"}), conditions:notCondition(conditions:create("NakedCondition")), }, ConversationStates.ATTENDING, nil, { actions:create("SayTextAction", {"Hello."}), actions:create("NPCEmoteAction", {"looks greedily at your pouch of money.", false}), }) </pre> In this scenario, the NPC will respond if the player has money & is not naked. Nested tables are supported as well: <pre> local conditions = { conditions:create("PlayerHasItemWithHimCondition", {"money"}), { conditions:notCondition(conditions:create("NakedCondition")), }, } frank:add(ConversationStates.IDLE, ConversationPhrases.GREETING_MESSAGES, conditions, ConversationStates.ATTENDING, nil, { actions:create("SayTextAction", {"Hello."}), actions:create("NPCEmoteAction", {"looks greedily at your pouch of money.", false}), }) </pre> ==== Adding Merchant Behavior ==== The <code>merchants</code> object is used for adding merchant behavior (buying/selling) to an NPC. Example of adding seller behavior to an NPC: <pre> if game:setZone("0_semos_city") then local frank = entities.createSpeakerNPC("Frank") merchants:addSeller(frank, merchants.shops:get("shopname"), true) game:add(frank) end </pre> 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: <pre> local priceList = { meat = 50, ["ham"] = 70, } </pre> Method 2: <pre> local priceList = {} priceList.meat = 50 priceList["ham"] = 70 </pre> The helper methods have special handling for underscore characters as well (the following are all the same): <pre> local priceList = { smoked_ham = 100, ["smoked ham"] = 100, } priceList.smoked_ham = 100 priceList["smoked ham"] = 100 </pre> Then add the seller behavior using the custom list: <pre> merchants:addSeller(frank, priceList, true) </pre> == System Properties == Java's system properties are exposed to Lua with the <code>properties</code> object. Examples: <pre> -- property state if properties:enabled("stendhal.testserver") then print("Test server enabled") if properties:equals("stendhal.testserver", "junk") then print("Junk enabled") else print("Junk disabled") end else print("Test server disabled") end -- property value local prop = properties:getValue("stendhal.testserver") if prop ~= nil then print("Test server enabled") if prop == "junk" then print("Junk enabled") else print("Junk disabled") end else print("Test server disabled") end </pre> == Misc == === Typecasting === Lua does not support typecasting (as far as I know), but if the class you want to cast to has a copy constructor, achieving the same functionality is quite simple. <pre> -- "entities:getItem" returns an instance of Item local bestiary = entities:getItem("bestiary") -- in order to use the bestiary's "setOwner" method, we must convert it to an "OwnedItem" instance by calling its copy constructor bestiary = luajava.newInstance("games.stendhal.server.entity.item.OwnedItem", bestiary) bestiary:setOwner("Ted") </pre> = See Also = * [[StendhalScripting/LuaAPI|Lua API]] [[Category:Stendhal]] [[Category:Documentation]] [[Category:API]] [[Category:Scripting]] [[Category:Lua]]
摘要:
请注意,所有对gamedev的贡献均可能会被其他贡献者编辑、修改或删除。如果您不希望您的文字作品被随意编辑,请不要在此提交。
您同时也向我们承诺,您提交的内容为您自己所创作,或是复制自公共领域或类似自由来源(详情请见
Gamedev:著作权
)。
未经许可,请勿提交受著作权保护的作品!
取消
编辑帮助
(在新窗口中打开)
该页面使用的模板:
Template:Br
(
编辑
)
Template:Navigation for Stendhal Top
(
编辑
)
Template:StendhalFile
(
编辑
)
Template:Stendhal menu for Builders and Hosters
(
编辑
)
Template:Stendhal menu for Contributors
(
编辑
)
Template:Stendhal menu for Developers
(
编辑
)
Template:Stendhal menu for Extenders
(
编辑
)
Template:Stendhal menu for GMs
(
编辑
)
Template:Stendhal menu for Players
(
编辑
)
Template:Stendhal menu for World
(
编辑
)
导航菜单
个人工具
未登录
讨论
贡献
创建账号
登录
命名空间
页面
讨论
不转换
不转换
简体
繁體
大陆简体
香港繁體
澳門繁體
大马简体
新加坡简体
臺灣正體
查看
阅读
编辑
查看历史
更多
搜索
导航
首页
最近更改
随机页面
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息