Xalzar's WML Headaches

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
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

So...the event

Code: Select all

unit_placed
wiki wrote:Leaders and units placed in side definitions (fired once for every unit right before prestart events)
I needed to cram some variable into all the leaders of the various sides (every leader has different variables depending on its unit type), this I have already solved with this event "linked" other, custom events.
Now I need to link these events to another one which is normally evoked during recruitment; ok no problem, another linked custom event fired from the first one. The problem is that this event needs to be fed variables normally obtained during side turns, and the unit_placed event triggers in prestart.
How can I work around this?

P.S.: I've already tried "side X turn 1" and "start" events, and they would work, if not for the fact that the events through which I insert the variables into the leader have values defined by a macro which I've put inside the unit cfg file (and that macro cannot be moved from there). If only I could add variables directly inside [unit_type]! :augh:
User avatar
Pentarctagon
Project Manager
Posts: 5564
Joined: March 22nd, 2009, 10:50 pm
Location: Earth (occasionally)

Re: Xalzar's WML Headaches

Post by Pentarctagon »

If the variables you need aren't set yet, then you could perhaps use defaults in that case? If the only case you'd need to do that for would be the prestart event, then you'd only need to account for side 1 turn 1.
99 little bugs in the code, 99 little bugs
take one down, patch it around
-2,147,483,648 little bugs in the code
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

Pentarctagon wrote: July 11th, 2019, 12:12 am If the variables you need aren't set yet, then you could perhaps use defaults in that case? If the only case you'd need to do that for would be the prestart event, then you'd only need to account for side 1 turn 1.
The major problem is that I have lots of events in my code, and I wanted to remove some of them via [remove_event] when they are no longer needed.
And guess what? The event with the predefined variables (which is brought by the units themselves) has the same id for all units so when I remove it for the first leader the other leaders lack half of the variables.
So I've tried to give an unique id for that event (linked to the unit id), and now neither the event nor the remove_event work anymore apparently. Maybe they do not appreciate substitutions very much. :doh:

More testing required...
User avatar
octalot
General Code Maintainer
Posts: 786
Joined: July 17th, 2010, 7:40 pm
Location: Austria

Re: Xalzar's WML Headaches

Post by octalot »

Sometimes the best approach to a complex debugging problem is pen, paper, pizza and not sitting in front of the PC. Don't focus on where you're getting stuck, instead write an overview of the desired behaviour. Doodle a bit and avoid thinking about the current implementation, the aim is that an easier overall design will appear.

How the pizza helps this process is unclear, but it does seem to do so.
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

octalot wrote: July 11th, 2019, 12:28 pm Sometimes the best approach to a complex debugging problem is pen, paper, pizza and not sitting in front of the PC. Don't focus on where you're getting stuck, instead write an overview of the desired behaviour. Doodle a bit and avoid thinking about the current implementation, the aim is that an easier overall design will appear.

How the pizza helps this process is unclear, but it does seem to do so.
Instructions unclear: I have a ball o' paper in my throat and I've scribbled on my pizza. :shock: Each anchovy stands for a variable. :lol:
Jokes aside, solid advice. :)

Right now, the structure is like this:

Code: Select all

Inside the units: {MACRO OF THE VARIABLES' VALUES}, unique for every unit type

Code: Select all

Indipendent Events: Unit Placed event (for the leaders) with generic variables and fire_event=Variables event
Start event which deletes the previous event (I don't need it any more) and the Variables event (since it is renewed every recruitment)
Events Dependent on the unit macro: Prerecruit event (for recruits) with dependent variables and fire_event=Variables event
Custom Variables event with unique id and the majority of dependent variables and fire_event=Store event

Code: Select all

Custom Store event with some store_x
Custom Menu event with the message and its options
If only I could store-kill-unstore the leaders to trigger the unit_placed event, without ending the game for the death of the leader! If only I could change the victory_when_enemies_defeated line with an event/modification! :augh:

Then...While writing on pizza I've come up with an idea: using the macro values in separate, general variable instead of "unit" variables like now (like unit_stored.variables.x value={MACRO VALUE}) and then transfer those values into the latter ones, so I should be able to delete generic variables instead of whole events, and I wouldn't need to give an unique id to the event itself and keep it in the game. On to more testing! :roll:
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Xalzar's WML Headaches

Post by Ravana »

If you want to trigger unit placed event, you could just [fire_event] with that unit.
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

I've quite re-ordered my code for those events, but I still have a major problem. Let me explain better (my last post was quite unclear on rereading).
The obstacle I face is an event included as macro inside unit files, which has variable with variables set by said macro.
It's all fine and dandy when I fire it from a recruit event, but at the start I have all the different side leaders which creates it at the same time (even if I set the trigger to each side turn 1 start), and since it has an id (for removing purposes), it gains the values of the first macro (in the first unit) only.
So it's good for the first leader, e.g.:

Code: Select all

[set_variable]
			name=new_name
			value=_"John"
		[/set_variable]
But then the second leader which should get e.g.:

Code: Select all

[set_variable]
			name=new_name
			value=_"Arnold"
		[/set_variable]
doesn't get the expected value, instead it gets "John".
I know the logic of the problem but I cannot find a workaround, since trying to making the events unique by setting the event id for example as "renaming_$leadername.side" (after a store_unit variable=leadername) it causes the event to not work. Same if I use this trick on variable names.
I cannot refresh the values of that event unless maybe I store_unit kill=yes and unstore_unit each leader at the start of their turn, but then the game ends in defeat for that faction (death of the leader).

I'm now thinking the solution is removing that event from unit files, but doing that would cause the code to bloat since it's not evoked only when the unit is first appearing in the game; I would have to write a macro (so an event) with values for every single unit (they are many) and try to lighten the code using a lot of filters (which don't delete events though, so the "weight" of the written code remains.

So, before going forward, have you any more advice to resolve this conundrum without resorting to the alternative option?
:hmm:
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Xalzar's WML Headaches

Post by Ravana »

I understand original issue is slow performance then.

Do you have code in form I could try out in game?
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

Ravana wrote: July 13th, 2019, 10:50 pm I understand original issue is slow performance then.

Do you have code in form I could try out in game?
More like "preempively avoiding slow performances in the future". I have many more events to add still, I'm testing with only few units to make sure everything works before adding more.
The code is like this:

Code: Select all

{PREDEFINED (yes) (yes) (sword,bow) (sword) (crown) (5) (20)}

Code: Select all

#define PREDEFINED HERO CANRECRUIT BASE LOADOUT UPGRADES SQUADS MORALE

## Recruits Storage
	[event]
		name=prerecruit
		id=predef_prerecr
		first_time_only=no
		
		[store_unit]
			[filter]
				id=$unit.id
			[/filter]
			variable=predef
		[/store_unit]
		
		[if]
			[variable]
				name=predef.canrecruit
				equals=yes
			[/variable]
			[or]
				[variable]
					name=predef.variables.hero
					equals=yes
				[/variable]
			[/or]
			[then]
				[object]
					silent=yes
					duration=forever
					[filter]
						id=$predef.id
					[/filter]
					[effect]
						apply_to=ellipse
						ellipse="misc/ellipse-hero"
					[/effect]
				[/object]
				[if]
					[variable]
						name=predef.canrecruit
						equals=yes
					[/variable]
					[then]
						[unit_overlay]
							id=$predef.id
							image=misc/hero-icon.png
						[/unit_overlay]
					[/then]
					[else]
						[unit_overlay]
							id=$predef.id
							image=misc/loyal-icon.png
						[/unit_overlay]
					[/else]
				[/if]
			[/then]
		[/if]
		[fire_event]
			id=predef_variables
		[/fire_event]
	[/event]
## Predefined Variables
	[event]
		name=unit_variables
		id=predef_variables
		first_time_only=no

		[set_variable]
			name=predef_hero
			value={HERO}
		[/set_variable]
		[set_variable]
			name=predef_canrecruit
			value={CANRECRUIT}
		[/set_variable]
		[set_variable]
			name=predef_base
			value={BASE}
		[/set_variable]
		[set_variable]
			name=predef_loadout
			value={LOADOUT}
		[/set_variable]
		[set_variable]
			name=predef_upgrades
			value={UPGRADES}
		[/set_variable]
		[set_variable]
			name=predef_squads
			value={SQUADS}
		[/set_variable]
		[set_variable]
			name=predef_morale
			value={MORALE}
		[/set_variable]
		[unstore_unit]
			variable=predef
		[/unstore_unit]
		{CLEAR_VARIABLE "predef"}
		[fire_event]
			id=modstore #ignore this since the problem isn't there, just know it sets variables inside the unit and there is a {CLEAR_VARIABLE} which cleans up all the general variables set here
		[/fire_event]
		[remove_event]
			id=predef_prerecr,predef_variables
		[/remove_event]
	[/event]
#enddef

Code: Select all

[event]
		name=side turn 1
		id=commander_mod
		first_time_only=no
		
		[store_unit]
			[filter]
				canrecruit=yes
				side=$side_number
			[/filter]
			variable=predef
		[/store_unit]
		[set_variable]
			name=storing_id
			value=$predef.id
		[/set_variable]
		[set_variable]
			name=predef.name
			value=_"$predef.name| Commander"
		[/set_variable]
		[set_variable]
			name=predef.variables.commander
			value=yes
		[/set_variable]
		[set_variable]
			name=predef_hero
			value=yes
		[/set_variable]
		[fire_event]
			id=predef_variables
		[/fire_event]
	[/event]
As I said, it's obvious why it doesn't work right now (I'm deleting the predef_variables event), but even if I keep it the values are the ones from the first leader (because the event id is the same and cannot make it unique without overbloating my code).
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Xalzar's WML Headaches

Post by Ravana »

I put the parts together as https://github.com/ProditorMagnus/Xalzar. What is the expected behavior, and what happens instead with this code?
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

Thank you, you are doing too much! :)
Ravana wrote: July 14th, 2019, 2:25 pm I put the parts together as https://github.com/ProditorMagnus/Xalzar. What is the expected behavior, and what happens instead with this code?
Rats! I've realized only now that typing "[ code=in UNIT FILES ]" in the forum post does not work. I wrote where to put the code but alas. :doh:
The macro {PREDEFINED} is to be inserted in a unit file, the rest in modifications. I'm very sorry. :oops:

The results?
So, since I have multiple, different leaders, I can have for example:
Leader 1

Code: Select all

{PREDEFINED (yes) (yes) (sword,bow) (sword) (crown) (5) (20)}
Leader 2

Code: Select all

{PREDEFINED (no) (yes) (sword,gun) (gun) (eagle eye) (1) (30)}
...and then the event would only take the values from the first unit. That's one of the reasons to delete events, to erase the values (since the event is created - and takes the values - when the unit first appears, not when triggers following its conditions). Sadly the event can't be created anymore from a leader (since it's already in the game).

As a result I would have both units with variables values taken from the first macro. I'm saying "units" because those general variables (e.g. predef_base) are first converted in unit.variables in a later event, and then deleted. It seems a step too much but I was trying to find a workaround, pity that the event substitutes macro values on creation and not on activation.

Expected behaviour would be having the correct values for each leader unit. Forget the prerecruit event for now, the relevant ones are the side turn 1 and the unit_variables ones.
User avatar
Ravana
Forum Moderator
Posts: 3000
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Xalzar's WML Headaches

Post by Ravana »

Assuming you want to store arbitrary data with unit type, and do not want Lua, I suggest using ability. I pushed the example.

Though if you intend to have them as constant instead of variable, the mapping event is not even needed.
User avatar
octalot
General Code Maintainer
Posts: 786
Joined: July 17th, 2010, 7:40 pm
Location: Austria

Re: Xalzar's WML Headaches

Post by octalot »

Either I don't understand what you want to do, or there's a much simpler way to do it.

I think you want a side to have several leaders, all recruited units to get a buff based on which leader recruits them, and each recruit to know who their squad leader is. That can be done like this:

Code: Select all

#text_domain wesnoth-Xalzar_WML_Headaches
[scenario]
    current_time=0
    description=""
    experience_modifier=70
    id="01_Squad_Leaders"
    map_data="{multiplayer/maps/4p_Castle_Hopping_Isle.map}"
    name= _ "Squad Leaders"
    random_start_time=no
    victory_when_enemies_defeated=no
    carryover_percentage=0
    next_scenario="null"

    {DEFAULT_SCHEDULE}

    [side]
        controller="human"
        fog=no
        gold=10000
        hidden=no
        income=4
        no_leader=no
        share_vision="all"
        shroud=no
        side=1
        team_name=Heroes
        user_team_name= _ "Squad Leaders"
        id=Methor
        name= _ "General Methor"
        unrenamable=yes
        facing="ne"
        type="General"
        recruit="Bowman, Cavalryman, Heavy Infantryman, Horseman, Mage, Spearman, Footpad, Poacher, Thief, Thug"
    [/side]
    # This is a standard 4-player map, so fill in the unused sides
    [side]
        controller="null"
    [/side]
    [side]
        controller="null"
    [/side]
    [side]
        controller="null"
    [/side]

    [event]
        name=prestart

        [unit]
            x,y=14,8
            side=1
            type=Longbowman
            canrecruit=yes
            [variables]
                recruit_boost="bow"
            [/variables]
        [/unit]
        [unit]
            x,y=24,8
            side=1
            type=Swordsman
            canrecruit=yes
            [variables]
                recruit_boost="sword"
            [/variables]
        [/unit]
        [unit]
            x,y=14,13
            side=1
            type="White Mage"
            canrecruit=yes
            [variables]
                recruit_boost="holy_mace"
            [/variables]
        [/unit]
    [/event]

    [event]
        name=recruit
        first_time_only=no

        [modify_unit]
            [filter]
                x,y=$x1,$y1
            [/filter]
            [trait]
                name=_ "recruited"
                description= "The unit was recruited by $second_unit.name"
            [/trait]
        [/modify_unit]

        [switch]
            variable=second_unit.variables.recruit_boost
            [case]
                value="bow"
                [object]
                    silent=yes
                    duration=forever
                    [effect]
                        apply_to=new_attack
                        name="extra_bow"
                        description=_ "Bow"
                        damage=8
                        number=3
                        range="ranged"
                        type="pierce"
                    [/effect]
                [/object]
            [/case]
            [case]
                value="sword"
                [object]
                    silent=yes
                    duration=forever
                    [effect]
                        apply_to=new_attack
                        name="extra sword"
                        description=_ "Sword"
                        damage=9
                        number=3
                        range="melee"
                        type="blade"
                    [/effect]
                [/object]
            [/case]
            [case]
                value="holy_mace"
                [object]
                    silent=yes
                    duration=forever
                    [effect]
                        apply_to=new_attack
                        name="holy_mace"
                        description=_ "Holy Mace"
                        damage=8
                        number=2
                        range="melee"
                        type="arcane"
                    [/effect]
                [/object]
            [/case]
        [/switch]
    [/event]
[/scenario]
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

octalot wrote: July 14th, 2019, 8:14 pm Either I don't understand what you want to do, or there's a much simpler way to do it.

I think you want a side to have several leaders, all recruited units to get a buff based on which leader recruits them, and each recruit to know who their squad leader is. That can be done like this:
:augh:
I don't know how to express my ideas properly, I'm sorry! :oops:

Let's try again :eng: :
-no, no side with multiple leaders;
-no buffs to recruits dependent on leader;
-no necessity to identify the squad leader.

When I talk of multiple leaders, I mean that every side has its own at the start of the game (obviously). The problem is that each of them have events incorporated, and they overwrite themselves (actually the first one is the one who overwrites the others). This is because every side leader spawns simultaneously.
The leaders need to have some variables stored inside them, which I use for some general events or for filtering some options in some event-message-options; my objective is letting the player select some weapons/abilities for their leaders (and each leader has some, predefined options for this). These things happen in events I've not reported here, because they function properly for now.

The same happens to every recruited unit, and this works wonderfully because they do not spawn simultaneously (only one recruit at a time, obviously, and then their events would be deleted by event so there is no overlap).

To answer about squads, let me explain summarily what each variable does:
-Hero: it should change ellipse and crown, opens the option to equip them with some specific upgrades (I still need to make this work properly, a question for the future maybe - if I can't resolve the problem myself);
-Canrecruit: ok, this gives the side multiple leaders, it depends primarily on what type of unit do you recruit (the Commander is the first and proper leader, other Leaders can recruit but are otherwise no different from other Heroes);
-Base: specifies the standard equipment for the unit, while modifying the unit you can choose to keep it as it is and this is how the message gives the player information about its standard weapons;
-Loadout: specifies the obligatory weapons, the ones which cannot be changed;
-Upgrades: same but with upgrades, which are normally abilities and weapon specials;
-Squads: some units can have e.g. size 3,6,9 squads - this means you can recruit them 3,6,9 of the same (modified or not) unit at the same time (cost is multiplied obviously), Heroes are normally size 1 squad. Additionally, this squad units must remain adjacent to their squad mates to form chains/blocks of at least the minimum size lest they incur in penalties to movement and attack;
-Morale: the higher the better, every time an adjacent allied unit dies it loses 1 morale, at 0 they get maluses to movement and attack.

TL;DR: these variables are used in filtering options for unit modification or for general gameplay events. :eng:

Also, I'm using modifications so I can use this Era in any map. If I used a specific scenario, I'd have resolved my problem with the leaders' variables long ago! :lol:
User avatar
Xalzar
Posts: 310
Joined: April 4th, 2009, 10:03 pm
Location: New Saurgrath

Re: Xalzar's WML Headaches

Post by Xalzar »

Quick update: AFAIK my problem was unsolvable, so I brute-forced the solution and manually wrote the unit parameters inside [modification]. It will be a long list (the units to modify are quite a number), but macros help a lot at least visually (coding-wise, maybe I have a solution for that too).

I'm not exactly unhappy with the resolution since the more I thought about the matter, the more I realized that I was overcomplicating the code with no real benefit.
Post Reply