Trait awarded on advancement

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
boru
Posts: 788
Joined: November 19th, 2009, 11:02 pm

Trait awarded on advancement

Post by boru »

I created a custom trait called Swamp Savvy. I want to apply it to goblins when they advance from level 0 to 1.

Here is the trait WML. It works when I apply it to units directly.

Code: Select all

#define TRAIT_SWAMPSAVVY
    # Units with trait Swamp Savvy move quicker and have better defense in swamp terrain.
    [trait]
        id=swamp_savvy
        availability="any"
        male_name= _ "swamp savvy"
        female_name= _ "female^swamp savvy"
        description= _ "Better defense and quicker in swamp"
        [effect]
            apply_to=movement_costs
            replace=true
            [movement_costs]
				swamp=2
            [/movement_costs]
        [/effect]
        [effect]
            apply_to=defense
            replace=true
            [defense]
				swamp=50
            [/defense]
        [/effect]
    [/trait]
#enddef
The part I'm tripping over is, how to apply this trait to every unit that levels up. I tried an event but it doesn't work.

Code: Select all

    [event]
        name=post advance
        first_time_only=no
        [filter]
            type=Goblin Spearman
        [/filter]
        {MODIFY_UNIT () trait (id=swamp_savvy)}
    [/event]
I tried a few permutations of this before concluding the proper way of doing really could be miles away from what I'm trying. Thanks in advance for any help.
“It is written in my life-blood, such as that is, thick or thin; and I can no other.” - J.R.R. Tolkien

My campaign: Swamplings - Four centuries before the founding of Wesnoth, the first wolf rider emerges from a tribe of lowly swamp goblins.
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: Trait awarded on advancement

Post by zookeeper »

This seems to work for adding healthy to all advancing units, so just change the trait and add whatever event filter you want:

Code: Select all

    [event]
        name=advance
        first_time_only=no

        [set_variables]
            name=existing_traits.trait
            to_variable=unit.modifications.trait
        [/set_variables]

        [set_variables]
            name=new_traits

            [value]
                {TRAIT_HEALTHY}
            [/value]
        [/set_variables]

        [set_variables]
            name=unit.modifications.trait

            [insert_tag]
                name=value
                variable=existing_traits.trait
            [/insert_tag]

            [insert_tag]
                name=value
                variable=new_traits.trait
            [/insert_tag]
        [/set_variables]

        [unstore_unit]
            variable=unit
            find_vacant=no
            advance=no
        [/unstore_unit]

        {CLEAR_VARIABLE existing_traits,new_traits}
    [/event]
You'll want to use an advance event instead of post advance to ensure that the unit stats update correctly during leveling. If you used post advance here, the healthy trait would show up on the unit just fine but it wouldn't actually have any effect, since direct variable manipulation like that doesn't cause the units max hitpoints to actually be re-calculated.
User avatar
boru
Posts: 788
Joined: November 19th, 2009, 11:02 pm

Re: Trait awarded on advancement

Post by boru »

Thanks, that did it!

I had post advance in there for several reasons, the main one was that I had tried originally with advance and knew that wasn't working, also because I was testing by advancing units with the debugger and wasn't certain that the combination of :unit advances=1 and [event] name=advance might be at odds. But I'm unfamiliar with the [insert_tag] method and it never would have occurred to me as a way to award a trait. Thanks very much!

EDIT: Just wanted to mention, if anyone else wants to use this code, don't forget to add a filter for the intended unit, or you'll be awarding the trait to every unit that advances.
“It is written in my life-blood, such as that is, thick or thin; and I can no other.” - J.R.R. Tolkien

My campaign: Swamplings - Four centuries before the founding of Wesnoth, the first wolf rider emerges from a tribe of lowly swamp goblins.
User avatar
boru
Posts: 788
Joined: November 19th, 2009, 11:02 pm

Re: Trait awarded on advancement

Post by boru »

Okay, I'm further on in my campaign and now I want my leader to recruit some level 1 units, instead of zeroes all the time. These units ought to gain the swamp savvy trait on recruitment.

I thought I could use the same basic code as above, with a minor variation, but what happens is, the name of the trait is inserted in the sidebar description, but the trait itself does not work.

Code: Select all

#define SS_TRAIT_ON_RECRUITMENT TYPE
# swamp savvy trait given to level 1 units:

    [event]
        name=recruit
        first_time_only=no
 
		[filter]
			type={TYPE}
		[/filter]

        [set_variables]
            name=existing_traits.trait
            to_variable=unit.modifications.trait
        [/set_variables]

        [set_variables]
            name=new_traits

            [value]
                {TRAIT_SWAMPSAVVY}
            [/value]
        [/set_variables]

        [set_variables]
            name=unit.modifications.trait

            [insert_tag]
                name=value
                variable=existing_traits.trait
            [/insert_tag]

            [insert_tag]
                name=value
                variable=new_traits.trait
            [/insert_tag]
        [/set_variables]

        [unstore_unit]
            variable=unit
            find_vacant=no
            advance=no
        [/unstore_unit]

        {CLEAR_VARIABLE existing_traits,new_traits}
    [/event]
#enddef
I added the following line before the [/event] tag, which fixes it:

Code: Select all

{ADVANCE_UNIT x,y=$x1,$y1 {TYPE} }
however, the visual effect of a unit being recruited, then fading to white and having the XP bar advance is really weird. Is there a simpler, cleaner way to do this?
“It is written in my life-blood, such as that is, thick or thin; and I can no other.” - J.R.R. Tolkien

My campaign: Swamplings - Four centuries before the founding of Wesnoth, the first wolf rider emerges from a tribe of lowly swamp goblins.
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: Trait awarded on advancement

Post by zookeeper »

boru wrote:Okay, I'm further on in my campaign and now I want my leader to recruit some level 1 units, instead of zeroes all the time. These units ought to gain the swamp savvy trait on recruitment.

I thought I could use the same basic code as above, with a minor variation, but what happens is, the name of the trait is inserted in the sidebar description, but the trait itself does not work.
:hmm:

Try adding {CLEAR_VARIABLE unit.defense,unit.movement_costs} right before the [unstore_unit].
User avatar
boru
Posts: 788
Joined: November 19th, 2009, 11:02 pm

Re: Trait awarded on advancement

Post by boru »

You have emerged victorious!

Again, thanks.
“It is written in my life-blood, such as that is, thick or thin; and I can no other.” - J.R.R. Tolkien

My campaign: Swamplings - Four centuries before the founding of Wesnoth, the first wolf rider emerges from a tribe of lowly swamp goblins.
ravenyear
Posts: 1
Joined: October 16th, 2022, 1:04 am

Re: Trait awarded on advancement

Post by ravenyear »

I found another way to add a trait to a unit when it advances by triggering on the post_advance event.

Code: Select all

#define ADD_TRAIT_TO_UNIT_ON_EVENT TRAIT TRAIT_ID UNIT_TYPE EVENT_NAME
    [event]
        name={EVENT_NAME}
        first_time_only=no

        [filter]
            type={UNIT_TYPE}
        [/filter]

        [modify_unit]
            [filter]
                id=$unit.id
                # prevents adding trait again in case of AMLA where UNIT_TYPE advances to itself
                [not]
                    [filter_wml]
                        [modifications]
                            [trait]
                                id={TRAIT_ID}
                            [/trait]
                        [/modifications]
                    [/filter_wml]
                [/not]
            [/filter]

            # adds new trait to unit
            {TRAIT}
        [/modify_unit]
    [/event]
#enddef
Following the example that boru gave, here's how we can add the TRAIT_SWAMPSAVVY trait (assuming its trait id is swampsavvy) to a Goblin Impaler unit whenever:
1) a unit advances into a Goblin Impaler

Code: Select all

    {ADD_TRAIT_TO_UNIT_ON_EVENT {TRAIT_SWAMPSAVVY} swampsavvy (Goblin Impaler) post_advance}
2) a Golbin Impaler unit is recruited

Code: Select all

    {ADD_TRAIT_TO_UNIT_ON_EVENT {TRAIT_SWAMPSAVVY} swampsavvy (Goblin Impaler) recruit}
The reason snippet 1) triggers on the post_advance event instead of advance event is because when specifying [event]name=advance and [modify_unit] together, the advancement-choice dialog gets stuck in a loop and keeps on showing up. See issue: https://github.com/wesnoth/wesnoth/issues/5298
Post Reply