Mutually exclusive traits during recruitment

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
fmac81
Posts: 75
Joined: February 24th, 2011, 9:55 pm

Mutually exclusive traits during recruitment

Post by fmac81 »

Hello,
I have an era of custom traits that I’m building currently, and one of the features is that Dwarvish Runesmith’s have a chance to receive an arcane rune ranged attack via [trait]. This works brilliantly, but lacks variety… My conundrum is I would like to have the Runesmith's have a chance to get either arcane, ice or fire runes when recruited (but no guarantee to get a rune trait all of the time). However, I’m not sure if there’s a way to create mutually exclusive traits? I would like to ensure that if they do receive a rune trait, they do not end up with, say, fire AND arcane traits.

I know that I could do [variation] of Runesmiths, and change it up that way, with each type being applied via [trait], but this still would not solve my problem of needing them to be mutually exclusive, if that makes sense (i.e. it would be a problem if one trait was applying the arcane variation but the second trait was applying the fire variation).

Is this something that [variable] within the unit coding might solve? Or any suggestions of how I might do mutual exclusion between the three traits?

Thanks!
fmac81
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: Mutually exclusive traits during recruitment

Post by zookeeper »

You need an event-based solution. For example:

1. Let the unit type receive a dummy trait X.
2. Have a prerecruit event (or unit placed, in 1.13) which triggers whenever a unit is recruited who gets trait X.
3. Have that event randomly choose another trait (arcane, ice, fire) and replace X with it.
User avatar
fmac81
Posts: 75
Joined: February 24th, 2011, 9:55 pm

Re: Mutually exclusive traits during recruitment

Post by fmac81 »

zookeeper wrote:You need an event-based solution. For example:

1. Let the unit type receive a dummy trait X.
2. Have a prerecruit event (or unit placed, in 1.13) which triggers whenever a unit is recruited who gets trait X.
3. Have that event randomly choose another trait (arcane, ice, fire) and replace X with it.
Hi Zookeeper - thank you for the quick response. I had actually attempted to make an event based solution, much like you described, after I made the post. The dummy trait works, its just the event randomly choosing another trait that is throwing me for a loop. I had made it a "recruit" instead of "prerecruit" event, which I thought might be the problem, but the setup I was trying still didn't work after changing it to a prerecruit.
I'll post everything that corresponds to my event in a .cfg file as it was a fairly long code:
Spoiler:
*Note I forgot to remove the "none" option in {VARIABLE_OP rand ...} in the cfg file. Since the unit already has to pass a random chance of receiving {TRAIT_RUNIC}, it doesn't make sense to have {TRAIT_RUNIC} only give an effect some of the time.
Spoiler:
Runic shows up fine as a trait, its the application of overwriting it with another trait / applying the rune effect as an [object] thats proving stubborn. In the [event] I was fiddling with, I had tried to make them as [object]s that would be applied randomly, sort of like unit variations, if the unit had the Runic trait. However, I think that replacing the runic dummy trait with an already working damage rune trait (which all 3 have working traits currently) might be the better option. But I could be missing an error in my code that would prevent this way from working as it stands?

How would I tweak the event to have the traits (see cfg file) overwrite Runic? Would that be something under [modify_unit]? I think having one of the three traits overwrite {TRAIT_RUNIC} might end up being a more sensible coding option than silent [objects], no?

The assistance is much appreciated!
User avatar
zookeeper
WML Wizard
Posts: 9742
Joined: September 11th, 2004, 10:40 pm
Location: Finland

Re: Mutually exclusive traits during recruitment

Post by zookeeper »

I don't think you can really replace a trait, after all. I tried to find a good solution, but I ended up having to come up with a an [object]-based solution almost identical to what you already have.

You can't remove or completely replace a musthave trait, because then the game simply notices it's missing and will automatically add it back. What you can do is change or clear the name and description keys. Here's what I came up with for giving Vampire Bats "variations" of the feral trait (only changes the trait name, not description, but you can see how to add that):

Code: Select all

    [event]
        name=prerecruit
        first_time_only=no

        [filter]
            side=1
            type=Vampire Bat

            [filter_wml]
                [modifications]
                    [trait]
                        id=feral
                    [/trait]
                [/modifications]
            [/filter_wml]
        [/filter]

        {RANDOM fire,cold,arcane}

        [switch]
            variable=random

            [case]
                value=fire

                {VARIABLE traitname _"fire"}

                [object]
                    # ...
                [/object]
            [/case]

            [case]
                value=cold

                {VARIABLE traitname _"cold"}

                [object]
                    # ...
                [/object]
            [/case]

            [case]
                value=arcane

                {VARIABLE traitname _"arcane"}

                [object]
                    # ...
                [/object]
            [/case]
        [/switch]

        [store_unit]
            [filter]
                x,y=$x1,$y1
            [/filter]

            kill=no
            variable=stored_unit
        [/store_unit]

        # Whichever ones you need...
        {VARIABLE stored_unit.modifications.trait[0].name _"feral ($traitname|)"}
        {VARIABLE stored_unit.modifications.trait[0].male_name _"feral ($traitname|)"}
        {VARIABLE stored_unit.modifications.trait[0].female_name _"female^feral ($traitname|)"}

        [unstore_unit]
            variable=stored_unit
            find_vacant=no
        [/unstore_unit]

        {CLEAR_VARIABLE random,traitname,stored_unit}
    [/event]
Of course, clicking on a single unit's trait takes you to the help page of the dummy trait (in this case feral), not a separate page for the particular trait variation (because it's not really a different trait), so the dummy trait's description needs to detail all the different variations, but that shouldn't be a problem.
Shiki
Developer
Posts: 348
Joined: July 13th, 2015, 9:53 pm
Location: Germany

Re: Mutually exclusive traits during recruitment

Post by Shiki »

In 1.13 umc traits have their own help page, I would use help_text for the detailed explanation and a short text for description. Like

Code: Select all

#ifver WESNOTH_VERSION >= 1.13.6
    help_text= ...
    description= ...
#else
    description= ...
#endif
zookeeper, is there also no easy way to remove a not-musthave trait too?
Try out the dark board theme.
User avatar
beetlenaut
Developer
Posts: 2822
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: Mutually exclusive traits during recruitment

Post by beetlenaut »

Maybe this is a silly question, but instead of replacing a unit's trait in an event, couldn't you kill the unit and create a new unit that had the trait you wanted? I did this to copy traits from an old unit to a new one, and it worked fine. I don't see any reason why you couldn't substitute a different trait instead. That would give you an event-based solution, and the traits would work normally. (I think.)
code:
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
fmac81
Posts: 75
Joined: February 24th, 2011, 9:55 pm

Re: Mutually exclusive traits during recruitment

Post by fmac81 »

beetlenaut wrote:Maybe this is a silly question, but instead of replacing a unit's trait in an event, couldn't you kill the unit and create a new unit that had the trait you wanted? I did this to copy traits from an old unit to a new one, and it worked fine. I don't see any reason why you couldn't substitute a different trait instead. That would give you an event-based solution, and the traits would work normally. (I think.)
code:
That would be a great solution to my problem, Beetlenaut. One of my issues was overwriting just the "runic" trait though, and leaving the other one as is, if that makes sense. How would I determine if "runic" was in .modifications.trait[0] or .modifications.trait[1]? It seems like there would be a lot of filters or [if] statements to accommodate "runic" being listed first or second.

Speaking of which, is there any way to always list a specific trait first? Would make replacing it much easier.
User avatar
beetlenaut
Developer
Posts: 2822
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: Mutually exclusive traits during recruitment

Post by beetlenaut »

fmac81 wrote:is there any way to always list a specific trait first? Would make replacing it much easier.
I don't think so.
fmac81 wrote:It seems like there would be a lot of filters or [if] statements to accommodate "runic" being listed first or second.
I only count three [if] statements, and two are really short. Store -1 in a variable. If recruited_unit.modifications.trait[0] is runic, change the variable to 0. If recruited_unit.modifications.trait[1] is runic, change it to 1. Then, if the variable is more than -1, do your changes with new_unit.modifications.trait[$stored_variable].
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
User avatar
fmac81
Posts: 75
Joined: February 24th, 2011, 9:55 pm

Re: Mutually exclusive traits during recruitment

Post by fmac81 »

beetlenaut wrote: Then, if the variable is more than -1, do your changes with new_unit.modifications.trait[$stored_variable].
Hi Beetlenaut- would you mind walking through what you would do for the last part? I have variables set up to clear trait "runic" but the new ones I'm applying with {RANDOM} aren't being applied over it, and it still shows "runic" as a trait in the unit sidebar. I did :debug followed by :inspect to try to see if they were being applied. My variables aren't shown under the variables category, but are shown to be included within the [unit_type] file. Should I move around where the coding is located do you think?
This is what I'm getting under the variables tab after using :inspect :
Spoiler:
I'm sure it has to do with the code I'm using. First I tried Zookeeper's example of replacing "feral" with a new trait name, but it didn't apply the new name or add an object to a unit either, so it might even be mac-related? I tested on both 1.13.8 and 1.12.5.
Spoiler:
I tried implementing it in a campaign scenario format, and that didn't work either. Somehow my variables aren't being applied when being placed in an [event] in the [unit_type] file or when in the [scenario] coding, and {TRAIT_RUNIC} isn't cleared at all. Thoughts?
User avatar
Ravana
Forum Moderator
Posts: 2995
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Mutually exclusive traits during recruitment

Post by Ravana »

You should not compare translatable and nontranslatable strings.

More [inspect]s in code might help you find what happens.
User avatar
fmac81
Posts: 75
Joined: February 24th, 2011, 9:55 pm

Re: Mutually exclusive traits during recruitment

Post by fmac81 »

Ravana wrote:You should not compare translatable and nontranslatable strings.
More [inspect]s in code might help you find what happens.
So my error involves having a variable with " " around its value and later trying to compare it to a variable defined value=___ with no " ", is that correct?
I think it's likely to do with the {VARIABLE traitname}... I'll take a closer look. Thanks Ravana. :)
User avatar
Ravana
Forum Moderator
Posts: 2995
Joined: January 29th, 2012, 12:49 am
Location: Estonia
Contact:

Re: Mutually exclusive traits during recruitment

Post by Ravana »

It might find _"cold" translated, but it is quite unlikely to immediately break something. Other than that, "" do not change comparing here.
User avatar
beetlenaut
Developer
Posts: 2822
Joined: December 8th, 2007, 3:21 am
Location: Washington State
Contact:

Re: Mutually exclusive traits during recruitment

Post by beetlenaut »

fmac81 wrote:I'm sure it has to do with the code I'm using.
Well, yeah. Nobody writes perfect code on the first try. Your code has a lot of errors because it's a lot of code. (I don't have time to go through them all.) Start over with this and just do one part at a time. Like, first, just see if you can make an exact copy of a unit. (I would temporarily use a "moveto" event for this instead of "recruit".) Then see if you can make a copy of a unit except with one change, like changing his XP to 1000 or changing his name to "testdude". Then see if you can make a copy except with a mainline trait that your unit can't normally have. Then see if you can show a message when a unit is recruited with "runic". Etc., etc. If you fail at any step, you know where to look for the mistake. This paragraph assumes you are using my suggestion, but you should always use the same basic process whatever you are coding.
fmac81 wrote:I tried implementing it in a campaign scenario format, and that didn't work either.
The code needs to be included in the scenario, but events in [unit_type] get automatically copied into the scenario when that unit appears. So, you can actually put it in either place.
Campaigns: Dead Water,
The Founding of Borstep,
Secrets of the Ancients,
and WML Guide
Post Reply