New macros for utils.cfg?

The place to post your WML questions and answers.

Moderator: Forum Moderators

Forum rules
  • Please use [code] BBCode tags in your posts for embedding WML snippets.
  • To keep your code readable so that others can easily help you, make sure to indent it following our conventions.
Post Reply
User avatar
turin
Lord of the East
Posts: 11662
Joined: January 11th, 2004, 7:17 pm
Location: Texas
Contact:

New macros for utils.cfg?

Post by turin »

I'd like to see a few macros added to utils.cfg. Here are the best ones, which I use in all of my UMCs:

Code: Select all

#define MOVE_UNIT_FAKE X1 Y1 XM YM X2 Y2
[store_unit]
	[filter]
	x,y={X1},{Y1}
	[/filter]
variable=temp
kill=yes
[/store_unit]
[move_unit_fake]
x={X1},{XM},{X2}
y={Y1},{YM},{Y2}
type=$temp.type
[/move_unit_fake]
[set_variable]
name=temp.x
value={X2}
[/set_variable]
[set_variable]
name=temp.y
value={Y2}
[/set_variable]
[unstore_unit]
variable=temp
[/unstore_unit]
[clear_variable]
name=temp
[/clear_variable]
[redraw]
[/redraw]
#enddef
This is used to ACTUALLY move a unit, instead of just drawing the moving sprite. You input the unit's current coordinates, then any hexes you want him to visit (if they're not on the default path), then the destination. It will store him, move_unit_fake his unit type to the new location, and then unstore him in that location. VERY useful. I use it constantly. (I haven't tested, but it might be possible to optimize it by using [teleport] instead of [store_unit], [set_variable], and [unstore_unit].)

Code: Select all

#define FORMAT VARIABLE TEMP_VARIABLE ELEMENT
[set_variable]
name={VARIABLE}_{TEMP_VARIABLE}_{ELEMENT}
to_variable={VARIABLE}[${TEMP_VARIABLE}].{ELEMENT}
[/set_variable]
#enddef

#define FOREACH_FORMAT VARIABLE TEMP_VARIABLE
{FOREACH {VARIABLE} {TEMP_VARIABLE}}
	{FORMAT {VARIABLE} {TEMP_VARIABLE} x}
	{FORMAT {VARIABLE} {TEMP_VARIABLE} y}
#enddef
Formatting variables is needed in certain situations, especially when you are storing arrays of units and then iterating over the array.
For I am Turin Turambar - Master of Doom, by doom mastered. On permanent Wesbreak. Will not respond to private messages. Sorry!
And I hate stupid people.
The World of Orbivm
toms
Posts: 1717
Joined: November 6th, 2005, 2:15 pm

Post by toms »

The first is possible shorter:

Code: Select all

#define MOVE_UNIT_FAKE X1 Y1 XM YM X2 Y2 
[hide_unit] 
   [filter] 
   x,y={X1},{Y1} 
   [/filter] 
[/store_unit]
[move_unit_fake] 
x={X1},{XM},{X2} 
y={Y1},{YM},{Y2} 
type=$temp.type 
[/move_unit_fake] 
[teleport]
x={X2}
y={Y2}
 [filter]
 x={X1}
 y={Y1}
 [/filter]
[/teleport]
[unhide_unit] 
x={X2}
y={Y2}
[/unhide_unit] 
[redraw] 
[/redraw] 
#enddef
In general, these macros could be useful, yes. :)
First read, then think. Read again, think again. And then post!
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Post by zookeeper »

Generally I'm in favour of adding as much useful macros to utils.cfg as possible. They don't really take up any space and it's somewhat dumb to have to manually copy all the useful macros to your campaign/whatever while the utils.cfg is full of mostly useless and messy macros. So, in addition to the ones below, I'd favour adding things like STORE_UNIT_VAR, PUT_TO_RECALL_LIST, and the like.

I constantly use MODIFY_UNIT. IMHO it's very useful.

Code: Select all

# MODIFY_UNIT alters a unit variable (such as unit.x, unit.type,
# unit.side), handling all the storing and unstoring.
#
# Example that flips all spearmen to side 2:
# {MODIFY_UNIT type=Spearman side 2}

#define MODIFY_UNIT FILTER VAR VALUE
    [store_unit]
        [filter]
            {FILTER}
        [/filter]

        variable=MODIFY_UNIT_store
        kill=yes
    [/store_unit]

    {FOREACH MODIFY_UNIT_store MODIFY_UNIT_i}
        [set_variable]
            name=MODIFY_UNIT_store[$MODIFY_UNIT_i].{VAR}
            value={VALUE}
        [/set_variable]

        [unstore_unit]
            variable=MODIFY_UNIT_store[$MODIFY_UNIT_i]
            find_vacant=no
        [/unstore_unit]
    {NEXT MODIFY_UNIT_i}

    {CLEAR_VARIABLE MODIFY_UNIT_store}
#enddef
Also, personally I'd prefer a version of MOVE_UNIT that accepts a standard unit filter instead of only coordinates. And yes, it can be written shorter and all that, but I think description= based (for example) filters are usually somewhat cleaner to use.

Code: Select all

# Moves a unit from its current location to the given location along a
# relatively straight line displaying the movement just like [move_unit_fake]
# does.
#
# Note that setting the destination on an existing unit does not kill either
# one, but causes the unit to move to the nearest vacant hex instead.

#define MOVE_UNIT FILTER TO_X TO_Y
    [store_unit]
        [filter]
            {FILTER}
        [/filter]
 
        variable=MOVE_UNIT_temp
        kill=no
    [/store_unit]

    [scroll_to]
        x=$MOVE_UNIT_temp.x
        y=$MOVE_UNIT_temp.y
    [/scroll_to]

    [hide_unit]
        x=$MOVE_UNIT_temp.x
        y=$MOVE_UNIT_temp.y
    [/hide_unit]

    {VARIABLE_OP x_coords format ("$MOVE_UNIT_temp.x|,{TO_X}")}
    {VARIABLE_OP y_coords format ("$MOVE_UNIT_temp.y|,{TO_Y}")}

    [move_unit_fake]
        type=$MOVE_UNIT_temp.type
        x=$x_coords
        y=$y_coords
    [/move_unit_fake]

    [teleport]
        [filter]
            {FILTER}
        [/filter]

        x,y={TO_X},{TO_Y}
    [/teleport]

    [unhide_unit][/unhide_unit]

    [redraw][/redraw]
#enddef
Checking for a terrain in a certain location is also very cumbersome, so IF_TERRAIN (or some variant) would be good to have, too.

Code: Select all

# This is a way to check whether or not the terrain in the given coordinates
# is of the given type or types. Might be useful, since filtering by terrain
# isn't possible directly.
#
# You can use it for example like this:
#
# [event]
#     name=moveto
#     first_time_only=no
#
#     {IF_TERRAIN $x1 $y1 gfm (
#         [then]
#             {DEBUG_MSG "Stepped on grassland, forest or mountains!"}
#         [/then]
#     )}
# [/event]

#define IF_TERRAIN X Y TYPES CONTENTS
    [store_locations]
        x={X}
        y={Y}
        terrain={TYPES}
        variable=IF_TERRAIN_temp
    [/store_locations]
 
    [if]
        [variable]
            name=IF_TERRAIN_temp.length
            not_equals=0
        [/variable]
 
        {CONTENTS}
    [/if]
 
    {CLEAR_VARIABLE IF_TERRAIN_temp}
#enddef
User avatar
turin
Lord of the East
Posts: 11662
Joined: January 11th, 2004, 7:17 pm
Location: Texas
Contact:

Post by turin »

The X_in_between and y_in_between are often useful, so I'd like to leave them. If you don't want to use them, just have them the same as the X2, Y2...
For I am Turin Turambar - Master of Doom, by doom mastered. On permanent Wesbreak. Will not respond to private messages. Sorry!
And I hate stupid people.
The World of Orbivm
toms
Posts: 1717
Joined: November 6th, 2005, 2:15 pm

Post by toms »

Just to ensure myself:
It is possible that I add a whole list for the between coordinates, right?
First read, then think. Read again, think again. And then post!
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Post by Sapient »

Wouldn't findvacant=yes be a better default behavior? And, if it's really moving the unit, why call it fake?

Also, the FORMAT macro seems poorly named. It's not using the format feature-- it's accessing elements from arrays and re-storing them in toplevel variables. Although this may be a useful hack for avoiding situations with simple variable expansion, I wouldn't even encourage people to use it regularly since it increases variable clutter.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
Dacyn
Posts: 1855
Joined: May 1st, 2004, 9:34 am
Location: Texas

Post by Dacyn »

Sapient wrote:Also, the FORMAT macro seems poorly named.
It's reformatting the variable name and so that it can be used... but if anyone thinks of a better name, we can use that.
Sapient wrote:Although this may be a useful hack
It's not a hack; it's the only possible way to access the variables (i.e. the only other way is to use similar code, not using the macro).
User avatar
turin
Lord of the East
Posts: 11662
Joined: January 11th, 2004, 7:17 pm
Location: Texas
Contact:

Post by turin »

Sapient wrote:Wouldn't findvacant=yes be a better default behavior? And, if it's really moving the unit, why call it fake?
Because it is not an in-game move, it is WML moving the unit - so, fake. But, as you can see, zookeeper changed that. I don't care either way - changing it is probably better so it doesn't conflict with un-updated campaigns.

findvacant=yes isn't necessary because zookeeper's version uses [teleport], not [unstore_unit].

BTW, does this work?:

Code: Select all

    [redraw][/redraw] 
I've never used that.


Anyway, I think we should commit the macros now, argue about them later.


The modify_unit macro looks pretty useful. The if_terrain macro does too, but I don't like the syntax it uses; wouldn't this make more sense?:

Code: Select all

# This is a way to check whether or not the terrain in the given coordinates
# is of the given type or types. Might be useful, since filtering by terrain
# isn't possible directly.
#
# You can use it for example like this:
#
# [event]
#     name=moveto
#     first_time_only=no
#
#     {IF_TERRAIN $x1 $y1 gfm}
#         [then]
#             {DEBUG_MSG "Stepped on grassland, forest or mountains!"}
#         [/then]
#     {/IF_TERRAIN}
# [/event]

#define IF_TERRAIN X Y TYPES
    [store_locations]
        x={X}
        y={Y}
        terrain={TYPES}
        variable=IF_TERRAIN_temp
    [/store_locations]
 
    [if]
        [variable]
            name=IF_TERRAIN_temp.length
            not_equals=0
        [/variable]
#enddef

#define /IF_TERRAIN 
    {CLEAR_VARIABLE IF_TERRAIN_temp}
    [/if]
#enddef
For I am Turin Turambar - Master of Doom, by doom mastered. On permanent Wesbreak. Will not respond to private messages. Sorry!
And I hate stupid people.
The World of Orbivm
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Post by zookeeper »

turin wrote:BTW, does this work?:

Code: Select all

    [redraw][/redraw] 
I've never used that.
It might be redundant actually in this case...
turin wrote:Anyway, I think we should commit the macros now, argue about them later.
I can do that, unless someone else really wants to. I think I'd add MODIFY_UNIT, MOVE_UNIT, IF_TERRAIN and PUT_TO_RECALL_LIST for starters. They wouldn't be used immediately anyway, so they can be tuned more after that.
turin wrote:The modify_unit macro looks pretty useful. The if_terrain macro does too, but I don't like the syntax it uses; wouldn't this make more sense?:
I guess it's a matter of taste really - and I unsurprisingly prefer my version (and use the same () style in my own macros whenever possible, since it's pretty).

PS. What the heck does the FORMAT macro do? I couldn't really see it after a minute of pondering...
User avatar
Sapient
Inactive Developer
Posts: 4453
Joined: November 26th, 2005, 7:41 am
Contact:

Post by Sapient »

FORMAT:

Personally, I'd rather manage the temp variables myself, since I will need to clear them anyway (and might wish to re-use the same variable for subsequent calls). I noticed that the version Turin posted is a bit different than the one on the wiki.

On another note, I think it may behave unexpectedly if you pass $vars in the macro arguments. However, my main objection is its name... maybe STORE_ARRAY_VAR would explain what it is doing better?

And FOREACH_FORMAT might be renamed FOREACH_STORE_XY ?
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
User avatar
turin
Lord of the East
Posts: 11662
Joined: January 11th, 2004, 7:17 pm
Location: Texas
Contact:

Post by turin »

FORMAT is useful only because some tags don't expand variables... i.e., in some tags $unitname[$i].x is meaningless; you need to do the thing FORMAT does.
For I am Turin Turambar - Master of Doom, by doom mastered. On permanent Wesbreak. Will not respond to private messages. Sorry!
And I hate stupid people.
The World of Orbivm
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Post by zookeeper »

I committed MODIFY_UNIT, MOVE_UNIT, IF_TERRAIN and PUT_TO_RECALL_LIST. Feel free to tweak and change for example MOVE_UNIT, since it's not used anywhere yet.
Post Reply