Help needed with a "saviour" ability

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
pipapopinguin
Posts: 22
Joined: November 3rd, 2019, 10:36 am

Help needed with a "saviour" ability

Post by pipapopinguin »

I am working on an ability to save an adjacent from a fatal blow, take the damage upon themself and let the attack go on. I wrote this code for the time being without any animations yet:

Code: Select all

#define ABILITY_GOLDENGUARD
    [dummy]
        id=goldenguard
        name= _ "goldenguard"
        female_name= _ "female^goldenguard"
        description= _ "If an adjecent unit would be dealt a fatal blow, the owner of this ability will hop in, to protect the attacked unit and take the damage."
    [/dummy]
	[/abilities]
	[event]
	    first_time_only=no
	    name=attacker hits
		[filter]
		    side=$side_number
		[/filter]
		[filter_second]
		    [filter_adjacent]
			    ability=goldenguard
				side=$other_unit.side
			[/filter_adjacent]
		[/filter_second]
		[filter_condition]
			[variable]
			    name=second_unit.hitpoints
				less_than_equal_to=0
			[/variable]
		[/filter_condition]
	        [heal_unit]
		    [filter]
			    id=$second_unit.id
			[/filter]
			amount=$damage_inflicted
		[/heal_unit]
		[harm_unit]
		    [filter]
			    ability=goldenguard
				[filter_adjacent]
				    side=$other_unit.side
					id=$second_unit.id
				[/filter_adjacent]
			[/filter]
			amount=$weapon.damage
			damage_type=$weapon.type
			alignment=$unit.alignment
		[/harm_unit]
	[/event]
...
But as I have discovered the attack gets ended without checking the units health after the event. I honestly have no clue what to do so that I can solve it, because the only attack related event before "attack hits" is name=attack and there is no such variable to see which attacks hit (unless in animationWML for some reason with the variable "hits" and no it doesn't work in abilities.cfg). So yeah that's my problem any solutions?
Author of Corpse Mod 2 and don't click here.
User avatar
WhiteWolf
Forum Moderator
Posts: 749
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Re: Help needed with a "saviour" ability

Post by WhiteWolf »

The second_unit variable is not stored at the time of event filters, so you can't use it in [filter_condition]. Automatically stored variables such as this are stored at the time they are first accessed inside the event (so not yet at filtering-time).

To get an "attack hits" event, you need to write two events, "attacker hits" and "defender hits", with the same content (just mind the switched primary and secondary unit roles).
Author of the Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
Standalone works: The Ravagers - now for 1.14, with new bugs!
User avatar
pipapopinguin
Posts: 22
Joined: November 3rd, 2019, 10:36 am

Re: Help needed with a "saviour" ability

Post by pipapopinguin »

WhiteWolf wrote: July 18th, 2021, 10:28 pm The second_unit variable is not stored at the time of event filters, so you can't use it in [filter_condition]. Automatically stored variables such as this are stored at the time they are first accessed inside the event (so not yet at filtering-time).
Are you sure? that seemed to work as it should, but anyway, I made the event with an [if] tag with the [variable] tag as condition, but the attack still gets cancelled as soon as the hitpoints drop below zero, again I am still healing it, but that doesnt change anything other than the fact it survives.

Also I only want the event to fire in the defense so no defender hits event
Author of Corpse Mod 2 and don't click here.
User avatar
WhiteWolf
Forum Moderator
Posts: 749
Joined: September 22nd, 2009, 7:48 pm
Location: Hungary

Re: Help needed with a "saviour" ability

Post by WhiteWolf »

Well, I was quoting the note at this section, and I remember it not working for me at filtering time. That was a long time ago, it may have been changed since :)


I think I recall a similar issue where hitpoints weren't tracked "live" during these events, and if it got below zero, the attack was interrupted anyway, no matter if it was healed in the event. I can't find the thread, and I'm not even sure why it would work like that, so maybe someone else can explain that, but in the meantime, the simple workaround would be to execute your code one hit earlier.
That is, in your attacker hits event, if the remaining hitpoints of the unit are <= $damage_inflicted (so could be killed with the next hit), then do your stuff, heal and do damage to the adjacent unit.

This will not catch very complicated other special attacks though, that may do a different amount of damage with each hit, etc. So if you go for this, it might be a good idea to append the description so that this only triggers for standard attacks.
Author of the Underness Series, consisting of 5 parts: The Desolation of Karlag, The Blind Sentinel, The Stone of the North, The Invasion Of The Western Cavalry, Fingerbone of Destiny
Standalone works: The Ravagers - now for 1.14, with new bugs!
User avatar
Celtic_Minstrel
Developer
Posts: 1817
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: Help needed with a "saviour" ability

Post by Celtic_Minstrel »

I think your filter_condition is wrong. It should be:

Code: Select all

[variable]
	name=second_unit.hitpoints
	less_than_equal_to=$damage_inflicted
[/variable]
In other words, you want the event to trigger when the hit would normally kill the second unit, not when the second unit is already dead. You'd still heal the unit for $damage_inflicted. I think there's an edge case that wouldn't work this way though, if the damage is greater than the unit's total hit points…
WhiteWolf wrote: July 18th, 2021, 10:28 pm The second_unit variable is not stored at the time of event filters, so you can't use it in [filter_condition].
I'm pretty sure this is not true. Looking at the code, the filter_condition is checked at the same time as all other filters, which is after defining the scoped unit an weapon variables.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.
User avatar
pipapopinguin
Posts: 22
Joined: November 3rd, 2019, 10:36 am

Re: Help needed with a "saviour" ability

Post by pipapopinguin »

Celtic_Minstrel wrote: July 19th, 2021, 2:00 pm I think your filter_condition is wrong. It should be:

Code: Select all

[variable]
	name=second_unit.hitpoints
	less_than_equal_to=$damage_inflicted
[/variable]
Thats exactly what WhiteWolf wanted me to do as a "workaround", but as he said, that would trigger too early (and I tested it, it does trigger to early).

But all that doesnt matter anymore since I was too bored and created this abnormality of code:

Code: Select all

    [dummy]
        id=goldenguard
        name= _ "goldenguard"
        female_name= _ "female^goldenguard"
        description= _ "If an adjecent unit would be dealt a fatal blow, the owner of this ability will hop in, to protect the attacked unit and take the damage."
    [/dummy]
	[/abilities]
	[event]
	    name=attack
	    first_time_only=false
		[filter_second]
		    [filter_adjacent]
			    ability=goldenguard
				side=$other_unit.side
			[/filter_adjacent]
		[/filter_second]
	    [store_unit_defense]
		    id=$second_unit.id
			loc_x,loc_y=$x2,$y2
			variable=second_unit_defense
		[/store_unit_defense]
	    [store_unit_defense]
		    id=$unit.id
			loc_x,loc_y=$x1,$y1
			variable=first_unit_defense
		[/store_unit_defense]
		[set_variable]
		    name=first_unit_attacks_left
			value=$weapon.number
		[/set_variable]
		[set_variable]
		    name=second_unit_attacks_left
			value=$second_weapon.number
		[/set_variable]
	[/event]
	[event]
	    name=defender hits
		first_time_only=no
		[filter_second]
		    [filter_adjacent]
			    ability=goldenguard
				side=$other_unit.side
			[/filter_adjacent]
		[/filter_second]
		[set_variable]
		    name=second_unit_attacks_left
			sub=1
		[/set_variable]
	[/event]
	[event]
	    name=defender misses
		first_time_only=no
		[filter_second]
		    [filter_adjacent]
			    ability=goldenguard
				side=$other_unit.side
			[/filter_adjacent]
		[/filter_second]
		[set_variable]
		    name=second_unit_attacks_left
			sub=1
		[/set_variable]
	[/event]
	[event]
	    name=attacker misses
		first_time_only=no
		[filter_second]
		    [filter_adjacent]
			    ability=goldenguard
				side=$other_unit.side
			[/filter_adjacent]
		[/filter_second]
		[set_variable]
		    name=first_unit_attacks_left
			sub=1
		[/set_variable]
	[/event]
	[event]
	    first_time_only=no
	    name=attacker hits
		[filter]
		    side=$side_number
		[/filter]
		[filter_second]
		    [filter_adjacent]
			    ability=goldenguard
				side=$other_unit.side
			[/filter_adjacent]
		[/filter_second]
		[set_variable]
		    name=first_unit_attacks_left
			sub=1
		[/set_variable]
		[if]
			[variable]
			    name=second_unit.hitpoints
				less_than_equal_to=0
			[/variable]
			[then]
		#animations
		[if]
		    [variable]
			    name=unit.facing
				contains=e
			[/variable]
			[then]
			#animations
			[/else]
		[/if]
		[heal_unit]
		    [filter]
			    id=$second_unit.id
			[/filter]
			amount=$damage_inflicted
		[/heal_unit]
		[if]
		    [variable]
			    name=weapon.range
				equals=ranged
			[/variable]
			[then]
			    [set_variable]
				    name=damage_by_2
					formula= "$damage_inflicted / 2"
				[/set_variable]
			[/then]
		[/if]
		[harm_unit]
		    [filter]
			    ability=goldenguard
				[filter_adjacent]
				    side=$other_unit.side
					id=$second_unit.id
				[/filter_adjacent]
			[/filter]
			[filter_second]
				id=$unit.id
			[/filter_second]
			experience=no
			fire_event=yes
			amount=$damage_by_2
			damage_type=$weapon.type
			alignment=$unit.alignment
		[/harm_unit]
		[repeat]
		    times=$first_unit_attacks_left
			[do]
                [set_variable]
				    name=fight_result_attacker
					rand=1..100
				[/set_variable]
                [set_variable]
				    name=fight_result_defender
					rand=1..100
				[/set_variable]
				[sync_variable]
				    name=fight_result_attacker,fight_result_defender
				[/sync_variable]
				[if]
				    [variable]
					    name=fight_result_defender
						greater_than=$first_unit_defense
					[/variable]
				    [variable]
					    name=second_unit_attacks_left
						greater_than=0
					[/variable]
					[then]
						[harm_unit]
						    [filter]
							    id=$unit.id
							[/filter]
							[filter_second]
							    id=$second_unit.id
							[/filter_second]
							amount=$second_weapon.damage
							damage_type=$second_weapon.type
							alignment=$unit.alignment
							animate=yes
							fire_event=yes
							experience=no
							[primary_attack]
							    name=$second_weapon.name
								range=$second_weapon.range
								type=$second_weapon.type
							[/primary_attack]
						[/harm_unit]
					[/then]
				[/if]
				[set_variable]
					name=second_unit_attacks_left
					sub=1
				[/set_variable]
				[if]
				    [variable]
					    name=fight_result_attacker
						greater_than=$second_unit_defense
					[/variable]
				    [variable]
					    name=first_unit_attacks_left
						greater_than=0
					[/variable]
					[then]
						[harm_unit]
						    [filter]
							    ability=goldenguard
								[filter_adjacent]
								    side=$other_unit.side
									id=$second_unit.id
								[/filter_adjacent]
							[/filter]
							[filter_second]
							    id=$unit.id
							[/filter_second]
							experience=no
							amount=$damage_by_2
							damage_type=$weapon.type
							alignment=$unit.alignment
							animate=yes
							fire_event=yes
							[primary_attack]
							    name=$weapon.name
								range=$weapon.range
								type=$weapon.type
							[/primary_attack]
						[/harm_unit]
					[/then]
				[/if]
				[set_variable]
					name=first_unit_attacks_left
					sub=1
				[/set_variable]
			[/do]
		[/repeat]
		[repeat]
		    times=$second_unit_attacks_left
			[do]
                [set_variable]
				    name=fight_result_attacker
					rand=1..100
				[/set_variable]
                [set_variable]
				    name=fight_result_defender
					rand=1..100
				[/set_variable]
				[sync_variable]
				    name=fight_result_attacker,fight_result_defender
				[/sync_variable]
				[if]
				    [variable]
					    name=fight_result_defender
						greater_than=$first_unit_defense
					[/variable]
				    [variable]
					    name=first_unit_attacks_left
						greater_than=0
					[/variable]
					[then]
						[harm_unit]
						    [filter]
							    id=$unit.id
							[/filter]
							[filter_second]
							    id=$second_unit.id
							[/filter_second]
							amount=$second_weapon.damage
							damage_type=$second_weapon.type
							alignment=$unit.alignment
							animate=yes
							fire_event=yes
							experience=no
							[primary_attack]
							    name=$second_weapon.name
								range=$second_weapon.range
								type=$second_weapon.type
							[/primary_attack]
						[/harm_unit]
					[/then]
				[/if]
				[set_variable]
					name=second_unit_attacks_left
					sub=1
				[/set_variable]
			[/do]
		[/repeat]
		#animation stuff
		[/then]
		[/if]
	[/event]
	[event]
	    name=die
		first_time_only=no
		[filter]
		    ability=goldenguard
			[filter_adjacent]
				[not]
				    id=$second_unit.id
				[/not]
			[/filter_adjacent]
		[/filter]
		#message stuff
		[modify_unit]
		    [filter]
			    id=$second_unit.id
			[/filter]
			[effect] 
			    apply_to=experience
				increase=$($unit.level*4)
			[/effect]
		[/modify_unit]
	[/event]
	
	[event]
	    name=attack end
		first_time_only=no
		{CLEAR_VARIABLE fight_result_defender}
		{CLEAR_VARIABLE fight_result_attacker}
		{CLEAR_VARIABLE second_unit_attacks_left}
		{CLEAR_VARIABLE first_unit_attacks_left}
		{CLEAR_VARIABLE first_unit_defense}
		{CLEAR_VARIABLE second_unit_defense}
		{CLEAR_VARIABLE harm_amount}
		{CLEAR_VARIABLE heal_amount}
	[/event]
Please tell me if I did a dump mistake somewhere.
It basicly keeps track of the attacks of the units and after the attack is over, it simulates the left over attacks with harm unit and calculates the chances of them to hit. (without specials tho, maybe you can fix that)
Author of Corpse Mod 2 and don't click here.
User avatar
Celtic_Minstrel
Developer
Posts: 1817
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: Help needed with a "saviour" ability

Post by Celtic_Minstrel »

pipapopinguin wrote: July 19th, 2021, 10:09 pm Thats exactly what WhiteWolf wanted me to do as a "workaround", but as he said, that would trigger too early (and I tested it, it does trigger to early).
What exactly is it that triggers too early? Can you give me a detailed outline of what order things should happen in and also what order they happen in when you use this suggestion? I have a few ideas on how to solve the too-early issue but I need to know more about what exactly the issue is.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.
User avatar
pipapopinguin
Posts: 22
Joined: November 3rd, 2019, 10:36 am

Re: Help needed with a "saviour" ability

Post by pipapopinguin »

Celtic_Minstrel wrote: July 20th, 2021, 1:25 am
What exactly is it that triggers too early?
the event itself, including its filter.
The damage is done to the unit and the attack gets cancelled if the hp drop bellow 0, before any name=attacker hits [event]s get triggered.
I think it is intended to work that way, but there is no event name, which makes it so, so that I can modify the attack outcome, before this calculation occurs.
Author of Corpse Mod 2 and don't click here.
User avatar
beetlenaut
Developer
Posts: 2558
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: Help needed with a "saviour" ability

Post by beetlenaut »

There may be a language or terminology issue here, because I am more confused than before. I still don't know which part of the event is happening too early. Also, filters do not trigger, so I don't understand what you mean by that statement.

I think this is what you want to have happen:

Code: Select all

Attack begins
Attacker hits
If the defender's HP drops below zero:
	Defender receives the HP it lost in the last strike
	Unit with the "saviour" ability loses that amount of HP
	Attack ends
Otherwise, attack continues normally
I'm pretty sure this is what Celtic_Minstrel meant by a detailed outline.

If these steps are not correct, modify them or rewrite them. Then explain which step is happening before you want it to, and when you want it to happen. If you can do that, we will be able to help you effectively.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
Celtic_Minstrel
Developer
Posts: 1817
Joined: August 3rd, 2012, 11:26 pm
Location: Canada
Contact:

Re: Help needed with a "saviour" ability

Post by Celtic_Minstrel »

Yeah, that's the kind of thing I'm looking for, beetlenaut. If the event is triggering "too early" there must be something you're seeing that indicates that it's too early. I want to know exactly what that something is.

Also, for the outline of what does happen, please use the filter I provided instead of the filter that compares to zero.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.
User avatar
lhybrideur
Posts: 208
Joined: July 9th, 2019, 1:46 pm

Re: Help needed with a "saviour" ability

Post by lhybrideur »

beetlenaut wrote: July 20th, 2021, 10:46 pm There may be a language or terminology issue here, because I am more confused than before. I still don't know which part of the event is happening too early. Also, filters do not trigger, so I don't understand what you mean by that statement.

I think this is what you want to have happen:

Code: Select all

Attack begins
Attacker hits
If the defender's HP drops below zero:
	Defender receives the HP it lost in the last strike
	Unit with the "saviour" ability loses that amount of HP
	Attack ends
Otherwise, attack continues normally
I'm pretty sure this is what Celtic_Minstrel meant by a detailed outline.

If these steps are not correct, modify them or rewrite them. Then explain which step is happening before you want it to, and when you want it to happen. If you can do that, we will be able to help you effectively.
From what I understand, here is what he wants

Code: Select all

1) Attack begins
2)
   a) Attacker hits
   b) If the defender's HP drops below zero:
	b') Defender receives the HP it lost in the last strike
	b'') Unit with the "saviour" ability loses that amount of HP
3) Same as 2 until attackers has no more attacks left
User avatar
pipapopinguin
Posts: 22
Joined: November 3rd, 2019, 10:36 am

Re: Help needed with a "saviour" ability

Post by pipapopinguin »

lhybrideur wrote: July 21st, 2021, 12:08 pm
beetlenaut wrote: July 20th, 2021, 10:46 pm There may be a language or terminology issue here, because I am more confused than before. I still don't know which part of the event is happening too early. Also, filters do not trigger, so I don't understand what you mean by that statement.

I think this is what you want to have happen:

Code: Select all

Attack begins
Attacker hits
If the defender's HP drops below zero:
	Defender receives the HP it lost in the last strike
	Unit with the "saviour" ability loses that amount of HP
	Attack ends
Otherwise, attack continues normally
I'm pretty sure this is what Celtic_Minstrel meant by a detailed outline.

If these steps are not correct, modify them or rewrite them. Then explain which step is happening before you want it to, and when you want it to happen. If you can do that, we will be able to help you effectively.
From what I understand, here is what he wants

Code: Select all

1) Attack begins
2)
   a) Attacker hits
   b) If the defender's HP drops below zero:
	b') Defender receives the HP it lost in the last strike
	b'') Unit with the "saviour" ability loses that amount of HP
3) Same as 2 until attackers has no more attacks left
Yes thats what I wanted, but I dont understand why this even continues, as i already am finished (see my code above), it may not be the best solution, but I actually don't need any help anymore, as it is good enough.
Author of Corpse Mod 2 and don't click here.
Post Reply