v1.18 have_unit and die event

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
Spannerbag
Posts: 760
Joined: December 18th, 2016, 6:14 pm
Location: Yes

v1.18 have_unit and die event

Post by Spannerbag »

Hi,
I'm a bit baffled and am posting this to ensure I'm not missing something obvious and/or doing something stupid.

I have a test condition that works in [show_if] but not inside a [filter_condition] of a die event.

First off the working and not-working code:

This works fine:

Code: Select all

      [objective]
        description= _ "Victory!"
        condition=win
        [show_if]
          {S15_VICTORY_TEST}
        [/show_if]
      [/objective]
But this doesn't (DEBUG_MSG never displays):

Code: Select all

  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
      {S15_VICTORY_TEST}
    [/filter_condition]
{DEBUG_MSG (_"In last wose die event, about to fire victory event")}
    {S15_VICTORY}
  [/event]
The scenario setup is rather complicated; there are 7 sides, several of which have the goto micro ai applied to some/all units.
Side 1 is player controlled and has defeat_condition=never.
Further, side 3 starts off as ai and then becomes player controlled later.
Finally, it's a b*gg*r to debug because I have to play the scenario through to the bitter end every time, there's no (easy) way to shortcut a full playthrough because of the way the scenario works.

Playing the scenario to the bitter end results in only side 3 units on the map (hence side 1 defeat condition) and when the final side 1 unit dies the player can win or lose.
If the dying unit is a leader, logic elsewhere causes the player to lose.
However otherwise the player loses that unit but wins the scenario.

Here's the macro definitions:

Code: Select all

# Defined here to ease legibility
#define S15_VICTORY_TEST_HAAG
  [have_unit]
    id=Haag
    [filter_location]
      terrain=*^Yah
    [/filter_location]
  [/have_unit]
  [or]
  [have_unit]
    id=Haag
    x,y=15,21
  [/have_unit]
  {VARIABLE_CONDITIONAL turn_number greater_than 15}
  [/or]#enddef
#
#define S15_VICTORY_TEST
[have_unit]
  side=1,2
  count=0
[/have_unit]
[and]
  {S15_VICTORY_TEST_HAAG}
[/and]#enddef
#define S15_VICTORY
[fire_event]
  name=15_victory
[/fire_event]#enddef
As well as the die event I added several others to narrow down where the issue is (one added recently and not yet tested, others have the result added as a comment). I played very specifically so that these only fired at the approriate time (i.e. when only 1 side 1 unit on map). Code below:

Code: Select all

# When last non-leader wose dies test for victory
#
# Debug tests
  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
{DEBUG_MSG (_"Last wose non-leader dies, no filter_condition")}
# FIRES OK
  [/event]
#
# Debug tests
  [event]
    name=die
    [filter]
      side=1,2
      canrecruit=no
    [/filter]
{DEBUG_MSG (_"Last non-leader side 1 or 2 dies, no filter_condition")}
# FIRES OK
  [/event]
#
  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
[have_unit]
  side=2
  count=0
[/have_unit]
    [/filter_condition]
{DEBUG_MSG (_"Last wose non-leader dies and filter_condition = no side *2* units")}
# ??? UNTESTED ???	ADDED SINCE LAST TEST RUN
  [/event]
#
  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
[have_unit]
  side=1
  count=0
[/have_unit]
    [/filter_condition]
{DEBUG_MSG (_"Last wose non-leader dies and filter_condition = no side 1 units")}
# FAIL
  [/event]
#
  [event]
    name=die
    [filter]
      side=1,2
      canrecruit=no
    [/filter]
    [filter_condition]
[have_unit]
  side=1,2
  count=0
[/have_unit]
    [/filter_condition]
{DEBUG_MSG (_"Last wose non-leader dies and filter_condition = no side 1 or 2 units")}
# FAIL
  [/event]
#
  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
  [have_unit]
    id=Haag
    [filter_location]
      terrain=*^Yah
    [/filter_location]
  [/have_unit]
  [or]
  [have_unit]
    id=Haag
    x,y=15,21
  [/have_unit]
  {VARIABLE_CONDITIONAL turn_number greater_than 15}
  [/or]
    [/filter_condition]
{DEBUG_MSG (_"Last wose non-leader dies and filter_condition = Haag safe")}
# FIRES OK
  [/event]
#
  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
[have_unit]
  side=1,2
  count=0
[/have_unit]
  [and]
  [have_unit]
    id=Haag
    [filter_location]
      terrain=*^Yah
    [/filter_location]
  [/have_unit]
  [or]
  [have_unit]
    id=Haag
    x,y=15,21
  [/have_unit]
  {VARIABLE_CONDITIONAL turn_number greater_than 15}
  [/or]
  [/and]
    [/filter_condition]
{DEBUG_MSG (_"Last wose non-leader dies and filter_condition = victory test in ""longhand""")}
# FAIL
  [/event]
#
  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
      {S15_VICTORY_TEST}
    [/filter_condition]
{DEBUG_MSG (_"In last wose die event, about to fire victory event")}
    {S15_VICTORY}
  [/event]
As you can hopefully see, the issue seems to be within the [have_unit] segment.

There are various inelegant work-arounds but I'd rather get this logic working.
The next thing to try is to remove the [filter_condition] and add first_time_only=no plus an [if] test.
Also maybe replace:

Code: Select all

[have_unit]
  side=1,2
  count=0
[/have_unit]
with:

Code: Select all

[not]
  [have_unit]
    side=1,2
  [/have_unit]
[/not]
So my question (finally!) is: are there any known issues, bugs or gotchas with [have_unit] that anyone knows about?
Otherwise I'll have to spend hours and hours replaying with slightly different tests each time. :augh:

One little wrinkle is that around the time of tthis issue there is a log error:
Tile at 35,1 isn't on the map, can't scroll to the tile.
I've commented those lines out but haven't had chance to test it yet... and my little brain's starting to hurt...

So I'm really hoping someone can either see what stupid mistake I've made or explain some possibly relevant issue with [have_unit]...

Any help very gratefully received!

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
Ravana
Forum Moderator
Posts: 3313
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: v1.18 have_unit and die event

Post by Ravana »

Spannerbag wrote: July 31st, 2024, 10:21 pm Finally, it's a b*gg*r to debug because I have to play the scenario through to the bitter end every time, there's no (easy) way to shortcut a full playthrough because of the way the scenario works.
Even if you validate against sequence breaks you can manipulate unit max_hitpoints and max_moves and allow move after attack.
white_haired_uncle
Posts: 1456
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

Re: v1.18 have_unit and die event

Post by white_haired_uncle »

Spannerbag wrote: July 31st, 2024, 10:21 pm
Finally, it's a b*gg*r to debug because I have to play the scenario through to the bitter end every time, there's no (easy) way to shortcut a full playthrough because of the way the scenario works.
You could always edit a save file if you need to change your code without starting over from turn 0.

And perhaps the example from Ravana about dynamically loading WML, specifically events.

One thing though, it looks like in one case you're working in a [die] event and checking to see if that side has #units==0. But is the unit in question actually dead at that point? So, do you perhaps need to use last_breath (which may not work either, IDK, but hopefully you see what I mean)?

EDIT: Hmm, this seems to imply that I'm wrong (like that'd be a shocker), but I'd still test anyway -- it could be that have_unit will not match this unit but it will still be including in count, in which case I'd be inclined to say it's borked.
die
Triggers when the primary unit is killed by the secondary unit. Note: The primary unit is not removed from the game until the end of this event. The primary unit can still be manipulated, will block other units from taking its hex, and will still be found by standard unit filters (except [have_unit]). To prevent this behavior, you can use [kill] to remove the unit immediately. However, this will stop any (still unfired) other events that also match the unit from firing afterwards, so use with caution. If you want to the primary unit to make a final [message], use name=last_breath, see above.
EDIT2: Oh yeah, got any other die events?
Speak softly, and carry Doombringer.
User avatar
Spannerbag
Posts: 760
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: v1.18 have_unit and die event

Post by Spannerbag »

Ravana wrote: July 31st, 2024, 10:54 pm
Spannerbag wrote: July 31st, 2024, 10:21 pm Finally, it's a b*gg*r to debug because I have to play the scenario through to the bitter end every time, there's no (easy) way to shortcut a full playthrough because of the way the scenario works.
Even if you validate against sequence breaks you can manipulate unit max_hitpoints and max_moves and allow move after attack.
Thanks for the advice, in this case terrain is steadily changed and that is one of the determining criteria for some of the logic involved, so changing unit attributes doesn't help unfortunately.

white_haired_uncle wrote: August 1st, 2024, 3:54 am You could always edit a save file if you need to change your code without starting over from turn 0.
Would that allow me to play onwards from that point with new logic?
If so, that would be a very useful shortcut!
white_haired_uncle wrote: August 1st, 2024, 3:54 am And perhaps the example from Ravana about dynamically loading WML, specifically events.
Yeah, I've seen that, seems complicated but I guess I'll have to give that a go...


My [have_unit] test works in my test campaign so it's something to do with the scenario/campaign I'm testing itself.
I created a player side with 2 easily killed (1hp) non leader units.
m2.jpg
m2.jpg (54.34 KiB) Viewed 2316 times
Then I added this code:

Code: Select all

  [event]
    name=die
    [filter]
      side=1
      canrecruit=no
    [/filter]
    [filter_condition]
[have_unit]
  side=1
  count=0
[/have_unit]
    [/filter_condition]
{DEBUG_MSG (_"Unit type=$unit.type at x,y=$unit.x,$unit.y found in die event")}
  [/event]
Which fires when the last (second mage) unit dies and reports the correct x,y.
white_haired_uncle wrote: August 1st, 2024, 3:54 am EDIT2: Oh yeah, got any other die events?
Yep, but when I "stacked" die events (see my test code in op) for side 1 at least some fired so I don't think that's an issue?

However, many thanks for the suggestions, I have several additional avenues to explore so will plod on...

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
octalot
General Code Maintainer
Posts: 818
Joined: July 17th, 2010, 7:40 pm
Location: Austria

Re: v1.18 have_unit and die event

Post by octalot »

Spannerbag wrote: July 31st, 2024, 10:21 pm One little wrinkle is that around the time of tthis issue there is a log error:
Tile at 35,1 isn't on the map, can't scroll to the tile.
If that only happens when loading a savegame, it's likely to be the unrelated #5976.
User avatar
Spannerbag
Posts: 760
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: v1.18 have_unit and die event

Post by Spannerbag »

octalot wrote: August 1st, 2024, 3:59 pm
Spannerbag wrote: July 31st, 2024, 10:21 pm One little wrinkle is that around the time of tthis issue there is a log error:
Tile at 35,1 isn't on the map, can't scroll to the tile.
If that only happens when loading a savegame, it's likely to be the unrelated #5976.
Nope, (or at least I assume not) it happened first time through (didn't load a save game as far as I remember) - and I'm fairly sure I was scrolling to an off-map co-ordinate. :oops:
As that scroll wasn't critical I just commented it out.
Seems fine now.
But thanks for mentioning it, appreciated.

While I'm here, a little more info.: [have_unit] works except in the scenario until near the end so it's clearly something I do specific to that scenario.
I thought maybe I'd missed off fire_event=yes from a [kill] but I hadn't.
However... [harm_unit] does work so I've just replaced the [kill]s with [harm_unit]s (damage=999 :) ) and the die events now work!?

There's a lot going on in this scenario and there's some interaction somewhere that's somehow broken something, but I've neither the time, energy nor motivation to track it down and even narrowing down what could possibly be causing this (and when) would likely take me days.
As of time of writing I've only played through with all the debug code in situ so a clean playthrough might rebreak it! But hopefully not.

Red herring alert: in the WML comments I mention disabling die events, that's separate and is only used to disable "global" leader die events in _main.cfg and these misfiring die events explicitly have canrecruit=no to exclude the leaders and also don't do the test that disables the leader die events anyway....

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
User avatar
Ravana
Forum Moderator
Posts: 3313
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: v1.18 have_unit and die event

Post by Ravana »

For that kind of event debugging I would proxy wesnoth.wml_conditionals.have_unit to log its wml, and its evaluation result.
white_haired_uncle
Posts: 1456
Joined: August 26th, 2018, 11:46 pm
Location: A country place, far outside the Wire

Re: v1.18 have_unit and die event

Post by white_haired_uncle »

Spannerbag wrote: August 1st, 2024, 8:47 am
white_haired_uncle wrote: August 1st, 2024, 3:54 am You could always edit a save file if you need to change your code without starting over from turn 0.
Would that allow me to play onwards from that point with new logic?
If so, that would be a very useful shortcut!
Sure. All your events and (not lua) stuff are stored in every single save file. That's why you have to restart from the beginning when you change WML. But if you change the save file....
Spannerbag wrote: August 1st, 2024, 8:47 am
white_haired_uncle wrote: August 1st, 2024, 3:54 am EDIT2: Oh yeah, got any other die events?
Yep, but when I "stacked" die events (see my test code in op) for side 1 at least some fired so I don't think that's an issue?
Sure, SOME of them do. But any of them could do something that causes this die to fail, or to never happen at all.
Speak softly, and carry Doombringer.
gnombat
Posts: 892
Joined: June 10th, 2010, 8:49 pm

Re: v1.18 have_unit and die event

Post by gnombat »

Spannerbag wrote: August 1st, 2024, 5:27 pm There's a lot going on in this scenario and there's some interaction somewhere that's somehow broken something, but I've neither the time, energy nor motivation to track it down and even narrowing down what could possibly be causing this (and when) would likely take me days.
It seems like you've basically narrowed it down already?

Here's a fairly minimal test case:

Code: Select all

    [label]
        x,y=1,5
        text= _ "Hex of Death"
    [/label]

    [event]
        name=moveto
        first_time_only=no
        [filter]
            side=1
            x,y=1,5
        [/filter]
        [kill]
            x,y=1,5
            fire_event=yes
        [/kill]
    [/event]

    [event]
        name=die
        [filter_condition]
            [have_unit]
                side=1
                count=0
            [/have_unit]
        [/filter_condition]
        [message]
            speaker=narrator
            message= _ "COUNT: 0"
        [/message]
    [/event]

    [event]
        name=die
        [filter_condition]
            [have_unit]
                side=1
                count=1
            [/have_unit]
        [/filter_condition]
        [message]
            speaker=narrator
            message= _ "COUNT: 1"
        [/message]
    [/event]

    [event]
        name=die
        [filter_condition]
            [have_unit]
                side=1
                count=2
            [/have_unit]
        [/filter_condition]
        [message]
            speaker=narrator
            message= _ "COUNT: 2"
        [/message]
    [/event]

    [event]
        name=die
        [filter_condition]
            [have_unit]
                side=1
                count=3
            [/have_unit]
        [/filter_condition]
        [message]
            speaker=narrator
            message= _ "COUNT: 3"
        [/message]
    [/event]
Add that code to a scenario (I used the first scenario of the WML Guide addon, but nearly any scenario should work), recruit a couple of units, then move them to the Hex of Death. For some reason, the unit which should be dead seems to be still alive and gets included in the count.
User avatar
Ravana
Forum Moderator
Posts: 3313
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: v1.18 have_unit and die event

Post by Ravana »

Yes, wesnoth.wml_actions.kill works by unit:erase(), instead of editing hitpoints. So [have_unit] does not have any reason to ignore it.
User avatar
Spannerbag
Posts: 760
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: v1.18 have_unit and die event

Post by Spannerbag »

gnombat wrote: August 1st, 2024, 6:18 pm ...It seems like you've basically narrowed it down already?...
Thanks for that, I'd assumed the error was with my code (as usual) but now I can replicate your logic in an entirely separate campaign.

I used a variant of your logic (that more closely replicates what happens in my scenario) and yes, [have_unit] seems to count the unit to which the die event applies.

Code: Select all

  [event]
    name=side 1 turn 1
    {GENERIC_UNIT 1 Mage 43 31}
    [+unit]
      hitpoints=1
    [/unit]
    {GENERIC_UNIT 1 Mage 43 32}
    [+unit]
      hitpoints=1
    [/unit]
    [if]
      [have_unit]
        side=1
        count=2
      [/have_unit]
    [then]
      {DEBUG_MSG (_"Test have_unit count=2 CORRECT")}
    [/then]
    [/if]
    {DEBUG_MSG (_"Killing first unit at 43,31")}
    [kill]
      x,y=43,31
      fire_event=yes
    [/kill]
    {DEBUG_MSG (_"Killing second and last unit at 43,32")}
    [kill]
      x,y=43,32
      fire_event=yes
    [/kill]
  [/event]
The output messages were:
Test have_unit count=2 CORRECT
Killing first unit at 43,31
COUNT: 2
Killing second and last unit at 43,32
COUNT: 1
Ravana wrote: August 1st, 2024, 6:33 pm Yes, wesnoth.wml_actions.kill works by unit:erase(), instead of editing hitpoints. So [have_unit] does not have any reason to ignore it.
Sorry to be dim, but I'm consufed.
The wiki die event says:

The primary unit is not removed from the game until the end of this event. The primary unit can still be manipulated, will block other units from taking its hex, and will still be found by standard unit filters (except [have_unit]).

Seems that last bit (in red) doesn't apply to [kill]ed units?

I tweaked my original code so that the two units were then killed in combat.
Then [have_unit] worked as I expected; when units died messages were:

COUNT: 1
COUNT: 0
Which is what I would have expected.

If I'm right I think it would be helpful to note that [kill is an exception to the exception.
It caused me no end of grief and wasted time...
:augh: :augh: :augh:

Is this a change of behaviour or has [kill always worked that way?
Oh well, at least it's an easy fix to implement... but I'll stick with [harm_unit] so [have_unit] behaves consistently when checking for last unit and said last unit can be [killed or die in combat.


Thanks again everyone for your help, much appreciated.

Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
gnombat
Posts: 892
Joined: June 10th, 2010, 8:49 pm

Re: v1.18 have_unit and die event

Post by gnombat »

Spannerbag wrote: August 2nd, 2024, 10:41 am If I'm right I think it would be helpful to note that [kill is an exception to the exception.
I agree, it seems like it would be a good idea to document this. (Currently this does not seem to be documented anywhere.)
Spannerbag wrote: August 2nd, 2024, 10:41 am Is this a change of behaviour or has [kill always worked that way?
I tested my code in versions 1.16, 1.14, 1.12, and 1.10 and it appears that [kill] has always worked that way. (I tried Wesnoth 1.8 too but my code doesn't work there because it seems count= didn't exist in that version.)

I think Wesnoth really could use another event type (because the die event is so confusing). Something like:

Code: Select all

    [event]
        name=the_unit_really_is_dead_now_honest
        ...
    [/event]
And it would fire after the die event and it wouldn't have any final speeches, any exceptions, any exceptions to exceptions... it would simply be a notification that a unit just died.
User avatar
Ravana
Forum Moderator
Posts: 3313
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: v1.18 have_unit and die event

Post by Ravana »

https://github.com/wesnoth/wesnoth/pull/9164

the_unit_really_is_dead_now_honest is not that useful since you dont know who died.
gnombat
Posts: 892
Joined: June 10th, 2010, 8:49 pm

Re: v1.18 have_unit and die event

Post by gnombat »

That appears to fix the issue, but I would be worried that there may be existing code depending on the old behavior (since it has worked that way since version 1.10 or earlier).

One of the advantages of adding a new event type is you wouldn't have to worry about existing code.
Ravana wrote: August 2nd, 2024, 2:51 pm the_unit_really_is_dead_now_honest is not that useful since you dont know who died.
That might be an issue, but in many cases you don't even need that information.
User avatar
Spannerbag
Posts: 760
Joined: December 18th, 2016, 6:14 pm
Location: Yes

Re: v1.18 have_unit and die event

Post by Spannerbag »

gnombat wrote: August 2nd, 2024, 12:03 pm ...I tested my code in versions 1.16, 1.14, 1.12, and 1.10 and it appears that [kill] has always worked that way. (I tried Wesnoth 1.8 too but my code doesn't work there because it seems count= didn't exist in that version.)...
Thanks for testing that, I'd kinda lost the will to live and was happy to finally understand the issue!
Cheers!
-- Spannerbag
SP Campaigns: After EI (v1.14) Leafsea Burning (v1.18, v1.16)
I suspect the universe is simpler than we think and stranger than we can know.
Also, I fear that beyond a certain point more intelligence does not necessarily benefit a species...
Post Reply