Call for Code Samples / WML Unit Tests

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.
User avatar
tekelili
Posts: 1039
Joined: August 19th, 2009, 9:28 pm

Re: Call for Code Samples / WML Unit Tests

Post by tekelili »

iceiceice wrote:Yeah so I worked slowly to the hard case, I only put the event in the unit in test 8 above. In that case it still works though.
Note that in general I had from WML always expected behavior. I used lot of nested events and events inside units without any problems. The only one causing unexpected behavior (for me) was in the halo case, because event inside unit was created and (tryed to be) fired in same recruit event and WML engine looked like have an exception there.
Be aware English is not my first language and I could have explained bad myself using wrong or just invented words.
World Conquest II
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: Call for Code Samples / WML Unit Tests

Post by iceiceice »

Hmm so it looks like event inside unit is handled differently from event in normal wml.

The normal wml events are handled by action_wml code:

https://github.com/wesnoth/wesnoth/blob ... l.cpp#L754

The "event inside unit" syntax referred to on the wiki is handled in the constructor of unit:

https://github.com/wesnoth/wesnoth/blob ... t.cpp#L328

It looks a bit different.

Also there is no similar code for when units are made from a unit_type, so I guess that it in that case the [event] inside [unit] won't work at all.

I think I would advise to avoid [event] inside [unit] where possible since it uses a different code path and probably won't be as reliable.

Edit: For instance, it appears the the "name=remove" thing might not work there, since that code doesn't appear in the second code path.
Spoiler:
In conclusion, just use events normally, imo, it will be less buggy.
User avatar
tekelili
Posts: 1039
Joined: August 19th, 2009, 9:28 pm

Re: Call for Code Samples / WML Unit Tests

Post by tekelili »

iceiceice wrote:Hmm so it looks like event inside unit is handled differently from event in normal wml.
I was quite imaginig something like that ;)
iceiceice wrote:I think I would advise to avoid [event] inside [unit] where possible since it uses a different code path and probably won't be as reliable.
I will be carefull now I am advised, but for campaigns is far more clean and comfortable use events inside units rather than write events in every scenario "just in case some unit could need it" :(
Be aware English is not my first language and I could have explained bad myself using wrong or just invented words.
World Conquest II
User avatar
iceiceice
Posts: 1056
Joined: August 23rd, 2013, 2:10 am

Re: Call for Code Samples / WML Unit Tests

Post by iceiceice »

Just posting again, so that you don't miss my repost with the spoiler:

From code inspection, it looks that currently there is a bug with modification events that will cause broken replays because they will not be fired, I assume it affects all versions.

Edit: Actually I guess that might only affect the "replay stop" button? Anyways I guess everyone knows that thing is quite buggy... :?

Edit: Okay, here's my impl of the feeding ability you posted. This is also committed, but if you want to suggest a change / post an alternative implementation feel free. For instance this doesn't test the delayed variables thing, I guess could add a version that adds according to the level.

I might separately debug the [event] inside [unit], but I'm done writing tests for today. I think the constructor of unit needs to add a line about the id of the unit for it to work but I haven't tested so I don't really know.

Code: Select all

# This unit test defines a WML object based implementation of the "feeding" ability
# and checks that it works. What is being tested here, beyond what is tested in
# test_unit_map and other scenarios that test the attack pathway, is that 
# - the die event works
# - objects attach to units by id correctly
# - abilities can be properly detected in filters
# - abilities which add other objects works
# - this impl of feeding works

#define STR_FEEDING 
foo
#enddef

#define STR_FEEDING_EFFECT 
bar
#enddef

#define STR_FEEDING_DESCRIPTION
baz
#enddef

#define TEST_FEEDING ID EXPECTED_INCREASE
    [store_unit]
        [filter]
            id={ID}
        [/filter]
        variable=Killer
    [/store_unit]

    {VARIABLE victim_x $Killer.x}
    {VARIABLE_OP victim_x sub 1}
    {VARIABLE victim_y $Killer.y}

    {VARIABLE victim_side 3}
    {VARIABLE_OP victim_side sub $Killer.side|}

    {VARIABLE Killer_start_hp $Killer.hitpoints}

    [terrain_mask]
        x,y=$victim_x|,$victim_y|
        mask="Xv"
    [/terrain_mask]
    {UNIT $victim_side| "Elvish Archer" $victim_x| $victim_y| (hitpoints=1)}
    [do_command]
        [attack]
            weapon = 0
            defender_weapon = 0
            [source]
                x,y=$Killer.x|,$Killer.y|
            [/source]
            [destination]
                x,y=$victim_x|,$victim_y|
            [/destination]
        [/attack]
    [/do_command]

    [store_unit]
        [filter]
            id={ID}
        [/filter]
        variable=Killer
    [/store_unit]

    {VARIABLE_OP Killer_start_hp add {EXPECTED_INCREASE}}

    {ASSERT ({VARIABLE_CONDITIONAL Killer.hitpoints equals $Killer_start_hp})}
#enddef

{GENERIC_UNIT_TEST "feeding" (
[event]
    id=ability_feeding_die
    name=die
    first_time_only=no
    [filter]
        [not]
            [filter_wml]
                [status]
                    not_living="yes"
                [/status]
            [/filter_wml]
        [/not]
    [/filter]
    [filter_second]
        ability=feeding
    [/filter_second]
    [unstore_unit]
        variable=second_unit
        {COLOR_HEAL}
        text= {STR_FEEDING_EFFECT}
        find_vacant=no
    [/unstore_unit]
    [object]
        silent=yes
        duration=forever
        [filter]
            x,y=$x2|,$y2|
        [/filter]
        [effect]
            apply_to=hitpoints
            increase_total=1
            increase=1
        [/effect]
    [/object]
[/event]
[event]
    name=start
    [object]
        id=feeding_object
        silent=yes
        [effect]
            apply_to=new_ability
            [abilities]
                [dummy]
                    id=feeding
                    name= {STR_FEEDING}
                    female_name= {STR_FEEDING}
                    description= {STR_FEEDING_DESCRIPTION}
                [/dummy]
            [/abilities]
        [/effect]
        [filter]
            id=bob
        [/filter]
    [/object]
[/event]
[event]
    name=start

    {TEST_FEEDING alice 0}
    {TEST_FEEDING alice 0}
    {TEST_FEEDING alice 0}

    [end_turn]
    [/end_turn]
[/event]
[event]
    name = side 2 turn 1

    {TEST_FEEDING bob 1}
    {TEST_FEEDING bob 1}
    {TEST_FEEDING bob 1}

    [store_unit]
        [filter]
            id=bob
        [/filter]
        variable=Bob
    [/store_unit]

    {VARIABLE_OP Bob.experience add 50}        

    [unstore_unit]
        variable=Bob
    [/unstore_unit]

    {TEST_FEEDING bob 1}
    {TEST_FEEDING bob 1}
    {TEST_FEEDING bob 1}

    {RETURN ([true][/true])}
[/event]
)}
Post Reply