Getting started with LUA

Discussion of Lua and LuaWML support, development, and ideas.

Moderator: Forum Moderators

Post Reply
User avatar
Reepurr
Posts: 1088
Joined: August 29th, 2010, 5:38 pm

Getting started with LUA

Post by Reepurr »

I felt I might as well, since LUA is what WML is built upon. Unfortunately, I've managed to break LUA after changing three values.

Code: Select all

   [lua]
      code=<<
function wml_actions.steal_gold(cfg)
	local team = get_team(cfg, "[steal_gold]")
	local amount = tonumber(cfg.amount) or
		helper.wml_error "[steal_gold] missing required amount= attribute."
	team.gold = team.gold + amount
end
    >>
   [/lua]
Derived from [gold] and stuck in a scenario ([preload] event). All I've changed is gold to steal_gold to avoid identical functions. Looks like function wml_actions is only valid in core from the error message. Should I change it to local function and how do I change the name of inputs, e.g. side?

EDIT: If I do change to local function, it says that [steal_gold] is not supported. How do I make it supported?
(sorry, really really novice)
"What do you mean, "a dwarvish dragonguard with marksman is overpowered"?"

Story of a Drake Outcast | The Nonsense Era
Played HttT-Underground Channels? Thought it was rubbish? Help us develop it here!
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Getting started with LUA

Post by silene »

Reepurr wrote:Derived from [gold] and stuck in a scenario ([preload] event). All I've changed is gold to steal_gold to avoid identical functions. Looks like function wml_actions is only valid in core from the error message. Should I change it to local function and how do I change the name of inputs, e.g. side?
That's because the [gold] tag relies on things defined earlier in the file. You don't have them, so you have to replicate them:

Code: Select all

local wml_actions = wesnoth.wml_actions
local helper = wesnoth.require "lua/helper.lua"
local function get_team(side, tag)
	side = tonumber(side or 1) or
		helper.wml_error(tag .. " given a noninteger side= attribute.")
	local team = wesnoth.sides[side] or
		helper.wml_error(tag .. " given an invalid side= attribute.")
	return team
end
function wml_actions.steal_gold(cfg)
   local team = get_team(cfg, "[steal_gold]")
   local amount = tonumber(cfg.amount) or
      helper.wml_error "[steal_gold] missing required amount= attribute."
   team.gold = team.gold + amount
end
Here is the short version without error handling and without default arguments, so that things are clearer:

Code: Select all

function wesnoth.wml_actions.steal_gold(cfg)
   local team = wesnoth.sides[cfg.side]
   team.gold = team.gold + cfg.amount
end
User avatar
Reepurr
Posts: 1088
Joined: August 29th, 2010, 5:38 pm

Re: Getting started with LUA

Post by Reepurr »

Wow. I feel...stupid...now. :doh:

Given this is [steal_gold], I want it to, well, steal gold. Obviously this could be done with two [gold] tags, but I'm starting small.

I don't want to make it too overpowered, so it will work like [drain] for gold. This should work. However, I don't know how to name a string, and I think that's the only problem with my code (the name second_side is not defined anywhere...).

Code: Select all

[event]
     name=preload
     first_time_only=no

   [lua]
      code=<<
function wesnoth.wml_actions.steal_gold(cfg)
   local team = wesnoth.sides[cfg.side]
   team.gold = team.gold + cfg.amount*0.5
-- The same but with a different name and double value
   local second_team = wesnoth.sides[cfg.side]
   second_team.gold = second_team.gold - cfg.amount
end
    >>
   [/lua]
[/event]
[event]
name=turn 2
[steal_gold]
side=2
# I think this is the problem.
second_side=1
amount=10
[/steal_gold]
[/event]
"What do you mean, "a dwarvish dragonguard with marksman is overpowered"?"

Story of a Drake Outcast | The Nonsense Era
Played HttT-Underground Channels? Thought it was rubbish? Help us develop it here!
silene
Posts: 1109
Joined: August 28th, 2004, 10:02 pm

Re: Getting started with LUA

Post by silene »

Reepurr wrote:I don't know how to name a string, and I think that's the only problem with my code (the name second_side is not defined anywhere...).

Code: Select all

local second_team = wesnoth.sides[cfg.second_side]
User avatar
Elvish_Hunter
Posts: 1575
Joined: September 4th, 2009, 2:39 pm
Location: Lintanir Forest...

Re: Getting started with LUA

Post by Elvish_Hunter »

Reepurr wrote:

Code: Select all

[event]
     name=preload
     first_time_only=no

   [lua]
      code=<<
function wesnoth.wml_actions.steal_gold(cfg)
   local team = wesnoth.sides[cfg.side]
   team.gold = team.gold + cfg.amount*0.5
-- The same but with a different name and double value
   local second_team = wesnoth.sides[cfg.side]
   second_team.gold = second_team.gold - cfg.amount
end
    >>
   [/lua]
[/event]
There are two things that you may want to do, to make your life simpler:
1) You can avoid mixing Lua and WML in the same file by creating a Lua file, called wml-tags.lua, placing it in a lua folder, and changing your event to

Code: Select all

[event]
     name=preload
     first_time_only=no

   [lua]
      code=<<wesnoth.dofile ~add-ons/add-on-name/lua/wml-tags.lua>>
   [/lua]
[/event]
This will give you the chance to use an editor with Lua syntax highlighting, that is a great help. :)
2) Instead of using a preload event in every scenario, you can do it like in LoW _main.cfg (of course, replacing the path with your campaign path, and perhaps placing this Lua tag inside your campaign #ifdef):

Code: Select all

[lua]
    code = "wesnoth.dofile 'campaigns/Legend_of_Wesmere/lua/replace_map.lua'"
[/lua]
This way, you'll no longer need to add the preload event in every scenario.
Current maintainer of these add-ons, all on 1.16:
The Sojournings of Grog, Children of Dragons, A Rough Life, Wesnoth Lua Pack, The White Troll (co-author)
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Getting started with LUA

Post by Anonymissimus »

Elvish_Hunter wrote:1) You can avoid mixing Lua and WML in the same file by creating a Lua file, called wml-tags.lua, placing it in a lua folder, and changing your event to

Code: Select all

[event]
     name=preload
     first_time_only=no

   [lua]
      code=<<wesnoth.dofile ~add-ons/add-on-name/lua/wml-tags.lua>>
   [/lua]
[/event]
This will give you the chance to use an editor with Lua syntax highlighting, that is a great help. :)
Also, e.g. clicking "back to turn x", that is, loading a save, will be enough to load changed lua code (as opposed to mainscreen+F5 for wml). And also, it allows for syntax check via "out-of-wesnoth" execution.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
User avatar
Reepurr
Posts: 1088
Joined: August 29th, 2010, 5:38 pm

Re: Getting started with LUA

Post by Reepurr »

Wow, I had no idea you could do that. :)

This is still in a [preload] tag, inside a unit, but it's a more impressive version of [steal_gold] that's closer to the pickpocket ability, my goal.

Code: Select all

[event]
     name=preload
     first_time_only=no
   [lua]
      code=<<
-- Special [rob] that triggers whenever unit with robber attacks, stealing 2 gold.
function wesnoth.wml_actions.rob(cfg)
   W.event { name="attack",
             first_time_only="no",
             return wesnoth.unit_ability(u, "robber")
	     if rob = yes then
             W.steal_gold { side="$unit.side",
                            second_side="$second_unit.side",
			    amount="2" }
	     end
				}
end

-- steal_gold inserted inside the rob event
function wesnoth.wml_actions.steal_gold(cfg)
   local team = wesnoth.sides[cfg.side]
   team.gold = team.gold + cfg.amount*0.5
   local second_team = wesnoth.sides[cfg.second_side]
   second_team.gold = second_team.gold - cfg.amount
end
    >>
   [/lua]
[/event]
[abilities]
[robber]
id=robber
name= _ "rob"
description= _ "This unit can steal 2 gold off attacked units."
[/robber]
[/abilities]
[rob][/rob]
Unfortunately, it doesn't even recognise my work. I think the problem is my insertion of a Lua filter into a W.event. How could I do this otherwise?

Code: Select all

 W.filter { W.filter_wml { ability="rob" } }
I presume.
"What do you mean, "a dwarvish dragonguard with marksman is overpowered"?"

Story of a Drake Outcast | The Nonsense Era
Played HttT-Underground Channels? Thought it was rubbish? Help us develop it here!
Luther
Posts: 128
Joined: July 28th, 2007, 5:19 pm
Location: USA

Re: Getting started with LUA

Post by Luther »

It looks like you don't have W defined. Try something like:

Code: Select all

W = wesnoth.wml_actions
EDIT: Also, you probably shouldn't have a return statement inside a table. If it's not a syntax error, it will exit the function without executing any code after it.

Another thing: 'rob = yes' doesn't make much sense. Neither of those variables are defined, and if you're comparing them, you need '==', not '='.
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Getting started with LUA

Post by Anonymissimus »

Reepurr wrote:

Code: Select all

[event]
     name=preload
     first_time_only=no
   [lua]
      code=<<
-- Special [rob] that triggers whenever unit with robber attacks, stealing 2 gold.
function wesnoth.wml_actions.rob(cfg)
   W.event { name="attack",
             first_time_only="no",
             return wesnoth.unit_ability(u, "robber")
	     if rob = yes then
             W.steal_gold { side="$unit.side",
                            second_side="$second_unit.side",
			    amount="2" }
	     end
				}
end
    >>
   [/lua]
[/event]
I have a hard time to grasp what that function is supposed to do; maybe explain by words ? :P
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
User avatar
Reepurr
Posts: 1088
Joined: August 29th, 2010, 5:38 pm

Re: Getting started with LUA

Post by Reepurr »

Luther: LuaWML triggers a [message] with the capital W method, so I thought it was okay.
Anonymissimus wrote:I have a hard time to grasp what that function is supposed to do; maybe explain by words ? :P
Ah sorry.

Essentially, it's a tag that does this.

Code: Select all

[event]
name=attack
first_time_only=no
LUA: check attacker has robber ability, if rob(should be a -ber there oops) is yes then
    [steal_gold]
    side=$unit.side
    second_side=$second_unit.side
    amount=2
    [/steal_gold]
else nothing
[/event]
Aside from my stupid robber typo, I think the problem is inserting Lua into what's technically an [event].
"What do you mean, "a dwarvish dragonguard with marksman is overpowered"?"

Story of a Drake Outcast | The Nonsense Era
Played HttT-Underground Channels? Thought it was rubbish? Help us develop it here!
Anonymissimus
Inactive Developer
Posts: 2461
Joined: August 15th, 2008, 8:46 pm
Location: Germany

Re: Getting started with LUA

Post by Anonymissimus »

Reepurr wrote:Luther: LuaWML triggers a [message] with the capital W method, so I thought it was okay.
You need to use the helper.set_wml_tag_metatable {} thingy for that.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml startersPlan Your Advancements: mp mod
The Earth's Gut: sp campaignSettlers of Wesnoth: mp scenarioWesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
Post Reply