v1.18 have_unit and die event
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.
- Spannerbag
- Posts: 760
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
v1.18 have_unit and die event
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
First off the working and not-working code:
This works fine:
But this doesn't (DEBUG_MSG never displays):
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
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:
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:
As you can hopefully see, the issue seems to be within the
There are various inelegant work-arounds but I'd rather get this logic working.
The next thing to try is to remove the
Also maybe replace:
with:
So my question (finally!) is: are there any known issues, bugs or gotchas with
Otherwise I'll have to spend hours and hours replaying with slightly different tests each time.
One little wrinkle is that around the time of tthis issue there is a log error:
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
Any help very gratefully received!
Cheers!
-- Spannerbag
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]
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]
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
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]
[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]
Code: Select all
[not]
[have_unit]
side=1,2
[/have_unit]
[/not]
[have_unit]
that anyone knows about?Otherwise I'll have to spend hours and hours replaying with slightly different tests each time.

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
Re: v1.18 have_unit and die event
Even if you validate against sequence breaks you can manipulate unit max_hitpoints and max_moves and allow move after attack.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.
-
- 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
You could always edit a save file if you need to change your code without starting over from turn 0.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.
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.
EDIT2: Oh yeah, got any other die events?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.
Speak softly, and carry Doombringer.
- Spannerbag
- Posts: 760
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: v1.18 have_unit and die event
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.Ravana wrote: ↑July 31st, 2024, 10:54 pmEven if you validate against sequence breaks you can manipulate unit max_hitpoints and max_moves and allow move after attack.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.
Would that allow me to play onwards from that point with new logic?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.
If so, that would be a very useful shortcut!
Yeah, I've seen that, seems complicated but I guess I'll have to give that a go...white_haired_uncle wrote: ↑August 1st, 2024, 3:54 am And perhaps the example from Ravana about dynamically loading WML, specifically events.
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. 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]
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
Re: v1.18 have_unit and die event
If that only happens when loading a savegame, it's likely to be the unrelated #5976.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.
- Spannerbag
- Posts: 760
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: v1.18 have_unit and die event
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.octalot wrote: ↑August 1st, 2024, 3:59 pmIf that only happens when loading a savegame, it's likely to be the unrelated #5976.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.

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 
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
Re: v1.18 have_unit and die event
For that kind of event debugging I would proxy wesnoth.wml_conditionals.have_unit to log its wml, and its evaluation result.
-
- 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
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 amWould that allow me to play onwards from that point with new logic?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.
If so, that would be a very useful shortcut!
Sure, SOME of them do. But any of them could do something that causes this die to fail, or to never happen at all.Spannerbag wrote: ↑August 1st, 2024, 8:47 amYep, 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?
Speak softly, and carry Doombringer.
Re: v1.18 have_unit and die event
It seems like you've basically narrowed it down already?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.
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]
Re: v1.18 have_unit and die event
Yes, wesnoth.wml_actions.kill works by unit:erase(), instead of editing hitpoints. So [have_unit] does not have any reason to ignore it.
- Spannerbag
- Posts: 760
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: v1.18 have_unit and die event
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]
Test have_unit count=2 CORRECT
Killing first unit at 43,31
COUNT: 2
Killing second and last unit at 43,32
COUNT: 1
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
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...



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 [kill
ed or die in combat.Thanks again everyone for your help, much appreciated.
Cheers!
-- Spannerbag
Re: v1.18 have_unit and die event
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 If I'm right I think it would be helpful to note that[kill
is an exception to the exception.
I tested my code in versions 1.16, 1.14, 1.12, and 1.10 and it appears thatSpannerbag wrote: ↑August 2nd, 2024, 10:41 am Is this a change of behaviour or has[kill
always worked that way?
[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]
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.Re: v1.18 have_unit and die event
https://github.com/wesnoth/wesnoth/pull/9164
the_unit_really_is_dead_now_honest is not that useful since you dont know who died.
the_unit_really_is_dead_now_honest is not that useful since you dont know who died.
Re: v1.18 have_unit and die event
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.
That might be an issue, but in many cases you don't even need that information.
- Spannerbag
- Posts: 760
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: v1.18 have_unit and die event
Thanks for testing that, I'd kinda lost the will to live and was happy to finally understand the issue!
Cheers!
-- Spannerbag