Dynamic overlays on units with undo support

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
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Dynamic overlays on units with undo support

Post by Toranks »

WARNING: ability_type_active= time_of_day= and time_of_day_id= EFFECT FILTERS ARE CAUSING CRASHES ON 1.16.6/1.17.11 OR LOWER. OTHER FILTERS WORKS Github link: #7238
FIXED ON 1.16.7 AND 1.17.12

Suppose we want an icon that represents a unit ambush state, just like transparency does. If we create an object like this: EDIT: Added an extra filter to detect if there are still any alive adjacent enemies.

Code: Select all

		[object]
			id=aww_preambush_icon
			[effect]
				[filter]
					ability_type_active=hides
					[not]
						[filter_adjacent]
							is_enemy=yes
							formula="self.hitpoints > 0"
						[/filter_adjacent]
					[/not]
				[/filter]
				apply_to=overlay
				add="misc/aww-ambush-attack.png"
			[/effect]
		[/object]
The icon appears and disappears depending on the state of the "hides" ability, but it refreshes every turn, not when moving.
The simplest way to update this object on moving, without complex conditionals, and with undo support is this:

Code: Select all

# Reload icon when moves, to activate and deactivate on real time, with undo support
[event]
    name=moveto
    id=aww_13_icon_reload
    first_time_only=no
    [filter]
	[filter_wml]
		[modifications]
			[object]
				id=aww_preambush_icon
			[/object]
		[/modifications]
	[/filter_wml]
    [/filter]
	
    [unstore_unit]
		variable=unit
    [/unstore_unit]
    [allow_undo]
    [/allow_undo]
    [on_undo]
	[unstore_unit]
		variable=unit
	[/unstore_unit]
    [/on_undo]
[/event]
Result:
2022-12-27 16-19-32.mp4
(3.86 MiB) Downloaded 28 times
With this in mind, you can change the StandardUnitFilter

Code: Select all

[filter]
    ability_type_active=hides
	[not]
		[filter_adjacent]
			is_enemy=yes
		[/filter_adjacent]
	[/not]
[/filter]
With anything you want to change the icon's state to active. If that condition depends on actions like move, then you'll need the moveto event with undo support. The same for icons whose conditions depend on an attack (attack_end event). If the conditions update between turns, you can bypass the event that forces the unit to update, and the effect itself do the work.

The use that I am giving it is to indicate if the unit, in addition to being able to ambush normally, can do a surprise attack. Therefore, I place and remove the item as that surprise attack is available. The combination of the attack availability, with the fact of being hidden and ready to attack, is what activates the icon. You can imagine all kinds of situations and conditions playing with the object, and the effect.
Of course, you can do the same just based on events that removes and places the object constantly, but they require more lines of code to make undo support, and surely more resources.
If anyone knows of an even simpler way, I'd love to hear about it. I like to keep things simple and readable.
Last edited by Toranks on January 16th, 2023, 8:33 am, edited 7 times in total.
User avatar
Toranks
Translator
Posts: 168
Joined: October 21st, 2022, 8:59 pm
Location: Sevilla
Contact:

Re: Dynamic overlays on units with undo support

Post by Toranks »

Spoiler:
SOLVED: This code works to update dinamically the icon on death events (only if neccesary, as is the case with the hides ability, which is activated again when the surrounding enemies die), combining with formula="self.hitpoints > 0" on the [object][effect][filter_adjacent]. In formula this_unit (self) represent the filtered death unit, according to the wiki:
$other_unit: (Version 1.13.2 and later only) Within [filter_adjacent], the special variable $other_unit refers to the filtered unit from the enclosing filter, while $this_unit refers (as with all StandardUnitFilters) to the unit being filtered on.
REMEMBER: For now, ability_type_active=hides cause crashes when loading a savegame, but all works as expected ingame, so until they fix the bug, avoid using ability_type_active as StandardUnitFilter or time_of_day as StandardLocationFilter. Other filters should work as expected.

Code: Select all

# Reload icon when a unit dies, and adjacent units that have not attacked yet hides
[event]
    name=die
    id=aww_13_icon_reload_die
    first_time_only=no
    [filter]
	[filter_adjacent]
		[filter_wml]
			[modifications]
				[object]
					id=aww_preambush_icon
				[/object]
			[/modifications]
		[/filter_wml]			
	[/filter_adjacent]
	[not]
		x,y=$x2,$y2
	[/not]
    [/filter]

    [store_unit]
        variable=ambushers
        [filter]
            [filter_wml]
			[modifications]
				[object]
					id=aww_preambush_icon
				[/object]
			[/modifications]
            [/filter_wml]
            [filter_adjacent]
                x,y=$x1,$y1
                is_enemy=yes
            [/filter_adjacent]
        [/filter]
    [/store_unit]

	[foreach]
		array=ambushers
		variable=ambusher
		[do]
			[unstore_unit]
				variable=ambusher
			[/unstore_unit]
		[/do]
	[/foreach]
[/event]
Post Reply