After a unit dies, a monster appears in their spot

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
Helmet
Posts: 331
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

After a unit dies, a monster appears in their spot

Post by Helmet »

I'm using [harm_unit] to cause 1 damage per turn to all units on side 1. If a unit dies from [harm_unit], I want a Fungal Monster to appear on the hex where the unit died. Other varieties of deaths should not trigger the Fungal Monster.

I expect that the solution requires fire_event.
fire_event: (default no) if yes, when a unit is killed by harming, the corresponding events are fired.
I'm not sure what "corresponding events" means.

Why doesn't this code work?

Thanks.

Code: Select all

[event] #							C A V E    O F   H A R M
	name=turn end
	first_time_only=no
	[harm_unit]
		[filter]
			side=1
			[not]
				id=Vortagh
			[/not]
		[/filter]	
			amount=1
        		[fire_event]
           			name=death_by_spore
        		[/fire_event]
	[/harm_unit]
	[event]
		name=death_by_spore
		first_time_only=no
 		[unit]
 			side=2
 			type=Fungal Monster
 			x=$x1
 			y=$y1
 			generate_name=yes
 			random_traits=yes
 		[/unit]
	[/event]
[/event]
User avatar
Ravana
Forum Moderator
Posts: 2481
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: After a unit dies, a monster appears in their spot

Post by Ravana »

[fire_event] is not subtag of [harm_unit]. That key is about usual last breath and die events.

Instead you could store the units, and check hp of each and based on that either harm or replace with monster.
User avatar
Helmet
Posts: 331
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: After a unit dies, a monster appears in their spot

Post by Helmet »

Ravana wrote: November 10th, 2020, 12:15 am [fire_event] is not subtag of [harm_unit]. That key is about usual last breath and die events.
Oh. Thanks for the info.
Ravana wrote: November 10th, 2020, 12:15 am Instead you could store the units, and check hp of each and based on that either harm or replace with monster.
I can envision the structure now. There's a problem, however. I understand the general idea behind [store_unit], but not enough to create code that works.

If somebody can post the missing [store_unit] code, that would be much appreciated.

Code: Select all

[store_unit]
	variable=unit.hitpoints
[/store_unit]

[if]  	#                      harm_unit does 1 hit point of damage to every side 1 unit per turn
	[filter]
		side=1
		unit.hitpoints = 1 #        a unit with 1 hit point will die because of harm_unit
		[not] 
			id=Vortagh
		[/not]
	[/filter]
	[then]
		[kill] #					so [kill] will remove the unit
			x,y=$x1,$y1
			animate=yes
		[/kill]		
		[unit]
 			side=2
 			type=Fungal Monster #       after a unit dies, a monster appears
 			x=$x1
 			y=$y1
 			generate_name=yes
 			random_traits=yes
 		[/unit]
	[/then]
	[else]
		[harm_unit] #	  if a unit has more than 1 hit point, they take 1 hit point of damage
			[filter]
     				side=1
			[/filter]
			amount=1
	        [/harm_unit]
	[/else]
[/if]
vghetto
Posts: 352
Joined: November 2nd, 2019, 5:12 pm

Re: After a unit dies, a monster appears in their spot

Post by vghetto »

I think there is a scenario in Genesis where the units get cold damage every turn. There is also couple in Under the burning sun where they get heat damage from the sun/lava every turn. You can check those out to see how it could be done.
I'm sure there are others but these are the ones that come to mind right now.
Pilauli
Posts: 115
Joined: August 18th, 2020, 12:56 pm

Re: After a unit dies, a monster appears in their spot

Post by Pilauli »

I would probably try this:

Code: Select all

[store_unit]
    [filter]
        side=1  # This will store all of the side 1 units in an array.
    [/filter]
    variable=target_units  # "unit" as a variable name is reserved for the unit that triggers an event, so try not to use it for other things.  It could get confusing.
[/store_unit]
[foreach]
    array=target_units
    [do]
        [if]
            [have_unit]
                hitpoints=1
                id=$this_item.id|
                # Or you could use the x and y coordinates: x=$this_item.x| and y=$this_item.y|.
                # it's very important that (inside of a [foreach] loop) you always make sure that your filters can only apply to exactly one unit at a time.
            [/have_unit]
            [then]
                # Kill the unit
                # Then create a fungal monster at coordinates x=$this_item.x| and y=$this_item.y|.
            [/then]
            [else]
                # Harm the unit
            [else]
        [/if]
    [/do]
[/foreach]
Disclaimer: untested code, but I think it should work.
Possible references:
https://wiki.wesnoth.org/InternalAction ... re_unit.5D (also check out the sections on [harm_unit] and [kill])
https://wiki.wesnoth.org/ConditionalAct ... foreach.5D
User avatar
Helmet
Posts: 331
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: After a unit dies, a monster appears in their spot

Post by Helmet »

Pilauli wrote: November 10th, 2020, 6:55 am I would probably try this...
Hi, Pilauli.

Your code didn't work as is, but it was very close. The comments in the code helped me find the solution, which was to replace
have_unit with variable to test that hitpoints=1.

Everything works now. Thanks for your help, Pilauli.

Code: Select all

	
[variable]
	name=this_item.hitpoints
	equals=1
[/variable]
User avatar
Helmet
Posts: 331
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: After a unit dies, a monster appears in their spot

Post by Helmet »

Playtesting revealed a problem. If a unit dies from [harm_unit] in a village, the unit "turns into" a fungal monster. This is not good. A village ought to be a safe place to die, so to speak (exactly like plague and Walking Corpses).

I tried all kinds of filters, with no success. I also tried a complicated if/then workaround, but it never worked.

Would somebody please edit the proper filter into my code? All the villages in this scenario are dwarven villages, so the terrain code is *^Vud. I need the villages filtered-out, so that if a side 1 unit is on a village, he does not "become" a fungal monster after harm_unit kills him.

However, any unit in a village should still be harmed by [harm_unit]. That code is contained in an [else] block near the bottom and it works fine.

I put a line of "############" in the vicinity of the problem.

I don't know why my [filter_location] attempts wouldn't work. I look forward to examining the solution.

Thanks.

Code: Select all

[event] # this event will turn a unit into a shroomling if they die from harm_unit
	name=turn_end
	first_time_only=no	
	[store_unit]
		[filter]
			side=1  # This will store all of the side 1 units in an array.
			[not]
				id=Vortagh
			[/not]
		[/filter]
		variable=target_units  # Do not use "unit" as a variable name, as it is reserved for the unit that triggers an event. It could get confusing.
	[/store_unit]
	[foreach]
		array=target_units
		[do]
			[if]
#				An alternative to using x,y coordinates is   id=this_item.id  
# 				It's important that inside of a [foreach] loop you always make sure that your filters can only apply to exactly one unit at a time.
				[variable]
					name=this_item.hitpoints #				If this unit's hit points...
					less_than_equal_to=$harm_damage #		are less than or equal to the damage done by harm_unit...
				[/variable]
				[then]
					[harm_unit]	# 							then kill the unit...
						[filter]
							x=$this_item.x| #				who is standing here...
							y=$this_item.y|
						[/filter]
						amount=$harm_damage #				by lethal damage from harm_unit.
						animate=yes
					[/harm_unit]
############
					[unit] # 								Now create a Shroomling on that vacant hex.
						side=2
						type=Shroomling
						x=$this_item.x|
						y=$this_item.y|
						generate_name=no
						random_traits=yes      	
					[/unit]
				[/then]
				[else] #									However, if the unit has enough hit points to survive harm_unit...
					[harm_unit] #							...use harm_unit
						[filter]
							x=$this_item.x| #				on the unit...
							y=$this_item.y|
						[/filter]
						amount=$harm_damage #				for this much damage.
					[/harm_unit]
				[/else]
			[/if]
		[/do]
	[/foreach]
[/event]

Pilauli
Posts: 115
Joined: August 18th, 2020, 12:56 pm

Re: After a unit dies, a monster appears in their spot

Post by Pilauli »

I would try to create a nested [if] tag with the following condition:

Code: Select all

[have_location]
    x=$this_item.x|
    y=$this_item.y|
    terrain=!,*^V*      # Translation: "NOT (any terrain with a village of any kind)".
[/have_location]
I'm pretty sure this would work too, though:

Code: Select all

[have_unit]
    id=$this_item.id|
    [filter_location]  # You can actually (apparently) nest [filter_location] inside of any standard unit filter to filter what location the unit is on.
        [not]
            terrain=*^V*
        [/not]
    [/filter_location]
[/have_unit]
If neither of those worked, I would be very surprised and return to the wiki to try to figure out what I did wrong.

You could actually put the [not] tag in any of several places, I believe. I gave the simplest version I could think of first, but putting a location filter inside of a standard unit filter could have several possible applications.

I'd also like to suggest that maybe villages should prevent the damage entirely, since you know, they're villages and they would be healing up the unit anyway. (That would completely remove the danger of the unit dying on the village, which would only be possible if the unit took damage before the village healed him, anyway.) To do this, you would probably add a [filter_location] inside of the [filter] inside of the [store_unit].

Say! Does taking damage prevent units from rest-healing? If not, then it would make a very neat mechanic where the dangerous spores hurt you less when you are resting (because the damage is countered by the rest-healing) and not using a lot of breath to run around.
(If this works, then 1 damage per turn would let units travel across the map so long as they pause frequently to rest, 2 damage per turn would let units sit still indefinitely without dying but not be able to sit and heal up, while 3 damage per turn would mean stationary units last 3x longer but everyone will die pretty fast.)
If taking damage prevents the unit from rest-healing on its next turn, though, then of course it would be very dangerous to have units just standing around because they could die without you ever doing anything to them.

Er, that was quite the rambling set of speculation, wasn't it? Oops but I'm not sorry :D
User avatar
Helmet
Posts: 331
Joined: December 19th, 2006, 5:28 pm
Location: Florida, USA

Re: After a unit dies, a monster appears in their spot

Post by Helmet »

Pilauli wrote: November 11th, 2020, 9:56 pm I'd also like to suggest that maybe villages should prevent the damage entirely, since you know, they're villages and they would be healing up the unit anyway. (That would completely remove the danger of the unit dying on the village, which would only be possible if the unit took damage before the village healed him, anyway.) To do this, you would probably add a [filter_location] inside of the [filter] inside of the [store_unit].
That's a good idea. I almost did that (it would be easier!), but the lethality of the toxic spores in the air is essential to the concept of the cave. The spores start off doing a mere 1 hp of damage per turn. On turn 7, it becomes 2 damage. By turn 28, the spores do a whopping 11 hit points per turn. The idea is that, if you stay in the cave, you will die, even huddled in a village.
Pilauli wrote: November 11th, 2020, 9:56 pm Say! Does taking damage prevent units from rest-healing? If not, then it would make a very neat mechanic where the dangerous spores hurt you less when you are resting (because the damage is countered by the rest-healing) and not using a lot of breath to run around.
Yes, rest healing still works. But eventually, the increased damage overwhelms the 2 hp of rest healing.
Pilauli wrote: November 11th, 2020, 9:56 pm (If this works, then 1 damage per turn would let units travel across the map so long as they pause frequently to rest, 2 damage per turn would let units sit still indefinitely without dying but not be able to sit and heal up, while 3 damage per turn would mean stationary units last 3x longer but everyone will die pretty fast.)
Nice! I like clever challenges like that. For example, the first 4 scenarios of my 6 scenario campaign don't even require the player to kill the enemy leader.

I just wanted to quickly reply and thank you for the code. I'm going to plug-in your code now and do some playtesting.

EDIT: Both solutions were tested, and both worked perfectly!

Your second solution, the one with [filter_location], is the one I had spent the most time trying to make work. Instead of using [have_unit], though, I had used [filter]. Thanks for adding that second solution. I was curious where I went wrong, and now I know.

Thanks again.
Post Reply