Rewriting macros as tags
Moderator: Forum Moderators
Re: Rewriting macros as tags
Yeah, that looks pretty nice syntax.
I recently wrote a somewhat similar [foreach_side] tag for use in the Diplomacy Era:
Arguably you don't really need the [command] tags.
I recently wrote a somewhat similar [foreach_side] tag for use in the Diplomacy Era:
Code: Select all
local function foreach_side_handler(cfg)
local iterator = cfg.iterator or helper.wml_error("[[foreach_side]] missing required iterator= attribute.")
local side_variable = cfg.side_variable or helper.wml_error("[[foreach_side]] missing required side_variable= attribute.")
local command = helper.get_child(cfg, "command")
-- TODO: use 1.9 wesnoth.sides instead
for i=1,10 do
if #wesnoth.get_units({ side = i }) > 0 then
wesnoth.set_variable(iterator, i)
wesnoth.fire("store_side", { side=i, variable=side_variable })
wesnoth.fire("command", command)
end
end
end
[event]
name=start
[foreach_side]
iterator=i
side_variable=stored_side_i
[command]
[message]
speaker=narrator
message="There's a side $i with $stored_side_i.gold in the game."
[/message]
[/command]
[/foreach_side]
[/event]
-
- Inactive Developer
- Posts: 2461
- Joined: August 15th, 2008, 8:46 pm
- Location: Germany
Re: Rewriting macros as tags
Why not ?zookeeper wrote:Arguably you don't really need the [command] tags.
Can one do wesnoth.fire for whatever tag this way (tags that are defined nowhere / assigned a function to)? The message tag could be arbitrary action wml.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
Re: Rewriting macros as tags
I'm not sure to understand what you mean, but the [command] tag is indeed superfluous. One can just as well execute all the subtags of [foreach]:Anonymissimus wrote:Why not ?zookeeper wrote:Arguably you don't really need the [command] tags.
Can one do wesnoth.fire for whatever tag this way (tags that are defined nowhere / assigned a function to)? The message tag could be arbitrary action wml.
Code: Select all
for i = 1, #cfg do
local cmd = cfg[i]
wesnoth.fire(cmd[1], cmd[2])
end
-
- Inactive Developer
- Posts: 2461
- Joined: August 15th, 2008, 8:46 pm
- Location: Germany
Re: Rewriting macros as tags
An implementation for [foreach], appears definitely nicer to me than the FOREACH macro, and supports continue and break. There is a lua error in wml_tags.lua for unknown action tags (like [invalid]).
No defaults for index and value, it might overwrite existing wml variables.
No defaults for index and value, it might overwrite existing wml variables.
Spoiler:
Spoiler:
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
-
- Posts: 462
- Joined: June 8th, 2006, 3:25 am
Re: Rewriting macros as tags
I think you may be losing some capabilities here. Consider the following:
I think this would break when used with your current code, and this pattern is actually useful in many cases.
Code: Select all
{FOREACH foo f}
{IF_VAR foo[$f].bar equals "baz" (
[then]
{CLEAR_VARIABLE foo[$f]}
{VARIABLE_OP f sub 1}
[/then]
)}
{NEXT f}
Re: Rewriting macros as tags
This pattern is not a real for-each-loop, but misuses the internal workings of the FOREACH-macro.Exasperation wrote:I think you may be losing some capabilities here. Consider the following:I think this would break when used with your current code, and this pattern is actually useful in many cases.Code: Select all
{FOREACH foo f} {IF_VAR foo[$f].bar equals "baz" ( [then] {CLEAR_VARIABLE foo[$f]} {VARIABLE_OP f sub 1} [/then] )} {NEXT f}
It may be useful, but there should be some special tag for "delete current element of foreach loop".
-
- Inactive Developer
- Posts: 2461
- Joined: August 15th, 2008, 8:46 pm
- Location: Germany
Re: Rewriting macros as tags
Surprisingly, it does not. In 1.9 there are implementations for while and switch too, in wml_tags.lua. In 1.8 I would expect that even the wml_actions[whatever_tag](cfg) doesn't work.Exasperation wrote:I think this would break when used with your current code
EDIT
Ah, the problem is modifying the array while looping over it. Doing that is critical in many languages however, there should actually be a sort of secured iterator for doing that.
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
-
- Posts: 462
- Joined: June 8th, 2006, 3:25 am
Re: Rewriting macros as tags
Yeah, that's my concern. I was just typing up a more thorough explanation when you edited your post. Modifying WML arrays in that fashion is often necessary for some of the more complicated stuff I work with, but I would be very surprised if WML arrays have anything even remotely approaching a secured iterator.
-
- Inactive Developer
- Posts: 2461
- Joined: August 15th, 2008, 8:46 pm
- Location: Germany
Re: Rewriting macros as tags
Sorry for the wasted post, I hope it wasn't finished.
Well, but even this modifying is supposed to work, since the wml array isn't touched by the lua script after retriving in the beginning. You can't modify the iterating index since it's resetted in the next step in the loop, but you don't need to.
There however seems to be a bug currently, but it's not my code I think.
http://gna.org/bugs/?16475
Well, but even this modifying is supposed to work, since the wml array isn't touched by the lua script after retriving in the beginning. You can't modify the iterating index since it's resetted in the next step in the loop, but you don't need to.
There however seems to be a bug currently, but it's not my code I think.
http://gna.org/bugs/?16475
projects (BfW 1.12):
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
A Simple Campaign: campaign draft for wml starters • Plan Your Advancements: mp mod
The Earth's Gut: sp campaign • Settlers of Wesnoth: mp scenario • Wesnoth Lua Pack: lua tags and utils
updated to 1.8 and handed over: A Gryphon's Tale: sp campaign
-
- Posts: 462
- Joined: June 8th, 2006, 3:25 am
Re: Rewriting macros as tags
The issue is that when you append/insert to or remove elements from a WML array the engine automatically re-indexes everything, but your code assumes that the original indices are still valid. So when you do {CLEAR_VARIABLE foo[$f]}, foo[$f] now references the array element that was immediately following the one you deleted, and incrementing f at the end of the loop skips over an array element that hasn't been considered yet. That's why the {VARIABLE_OP f sub 1} in my example is necessary; it adjusts the iterator so that when it gets incremented it now points to the element immediately following the deleted element, instead of the one two after it. Also, having deleted an element from the array causes array.length to be reduced by 1, but your code effectively uses a cached version of array.length for its termination condition, which will cause it to go past the end of the (now shortened) array.
Similarly, appending an element to the array will cause the loop to terminate before considering the new element. Inserting an element at or before the current index will cause the current element to be re-evaluated and an (old) element at the end to be ignored, while inserting an element after the current index but before the original end of the array will cause the new element to be evaluated but an old element to be ignored, and inserting an element after the original end of the array will be treated more or less the same as appending an element (new element ignored).
In some ways, it may help to think of WML arrays as being more like linked lists, with array[0] being the head and array[n] being what you get by traversing n steps down the list from the head. If you look at it like that, then the behavior of removing, inserting, or appending elements between FOREACH and NEXT macros is pretty straightforward (I know it's probably nothing like the implementation, but the behavior is similar).
Also, you get 'value' from the cached copy of the array, so if you have some situation where you modify array[<n>].foo (where <n> > index) during the loop then when you do get to index == <n> you will have $value.foo ~= $array[$index].foo; I don't know how intentional this is, since 'value' doesn't exist in the macro version.
Similarly, appending an element to the array will cause the loop to terminate before considering the new element. Inserting an element at or before the current index will cause the current element to be re-evaluated and an (old) element at the end to be ignored, while inserting an element after the current index but before the original end of the array will cause the new element to be evaluated but an old element to be ignored, and inserting an element after the original end of the array will be treated more or less the same as appending an element (new element ignored).
In some ways, it may help to think of WML arrays as being more like linked lists, with array[0] being the head and array[n] being what you get by traversing n steps down the list from the head. If you look at it like that, then the behavior of removing, inserting, or appending elements between FOREACH and NEXT macros is pretty straightforward (I know it's probably nothing like the implementation, but the behavior is similar).
Also, you get 'value' from the cached copy of the array, so if you have some situation where you modify array[<n>].foo (where <n> > index) during the loop then when you do get to index == <n> you will have $value.foo ~= $array[$index].foo; I don't know how intentional this is, since 'value' doesn't exist in the macro version.