• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.
Per the wiki, liege_opinion "Changes your opinion of your liege OR changes your liege's opinion of you (depending on where it is used)"; does anyone know the specific when it is one or the other?
 
What is wrong here, in relation to the highlighted validator report? This is particulaly confusing because the next modifier is vanilla code using the same node "trait", but does not seem to log an error.

1742729144840.png
More generally, how reliable is it? I'm getting a truckload of errors from vanilla files I copied. It's useful at nailing down my mistakes but they are burried by the vanilla errors.
 
Oh, I think I get it. The vanilla code is within a FROM, and unlike what the wiki claims, the ROOT in objectives is not the plotting character but a title, which is what Titletrigger mean I guess? But FROM is a character? Every time I think I'm starting to understand coding I find more sources of confusion.

Still curious on what you would have to say about my other question.
 
What is wrong here, in relation to the highlighted validator report? This is particulaly confusing because the next modifier is vanilla code using the same node "trait", but does not seem to log an error.

View attachment 1270446More generally, how reliable is it? I'm getting a truckload of errors from vanilla files I copied. It's useful at nailing down my mistakes but they are burried by the vanilla errors.
The Validator is very reliable, vanilla CK2 and its error logger are not. That's why I and a few others created CleanSlate, that has erased tons of mistakes in vanilla CK2. It's a recommended resource to base your new mods on.
 
  • 1
Reactions:
Oh, I think I get it. The vanilla code is within a FROM, and unlike what the wiki claims, the ROOT in objectives is not the plotting character but a title, which is what Titletrigger mean I guess? But FROM is a character? Every time I think I'm starting to understand coding I find more sources of confusion.

Still curious on what you would have to say about my other question.
I typically (temporarily) remove all files from the relevant folder (events folder if I'm validating events) except the ones I'm specifically validating, in order to prune the excess vanilla errors from Validator's log.

Kinda wish I'd known about CleanSlate when I first started modding, but I'd have to redo a ton of stuff now to use it.
 
  • 1
Reactions:
View attachment 1270446More generally, how reliable is it? I'm getting a truckload of errors from vanilla files I copied. It's useful at nailing down my mistakes but they are burried by the vanilla errors.
My strategy is as follows:

If it's possible to override a part of a vanilla file (instead of duplicating the whole 1000-line file to change one line in the middle), do that.
--- Eg1: For events, you can override individual events instead of replacing the whole file.
--- Eg2: For localisation and defines, you can override individual lines!

If it's NOT possible:
--- Create a completely-empty text file in your mod, with the same exact name as the vanilla file (eg. "00_scripted_triggers.txt" is a new blank file)
--- Copy all blocks of code that you do NOT intend to alter into second text file in your mod (eg. "00_scripted_triggers_mymod_unaltered.txt" contains all unaltered triggers)
--- Instruct the Validator to ignore all errors generated by this second file (by inserting # Audax Validator "!" Ignore_NEXT at the top of the file)
--- Copy the few blocks of code you wish to alter into a third text file in your mod (eg. "00_scripted_triggers_mymod_altered.txt" contains the one trigger you are altering)
--- Any Validator errors generated by this third text file are genuine and need to be fixed
--- (Anyone who wishes to submod your mod or create a compatch can easily do so, by creating their own further overrides of one of the two uniquely-named files.)

This strategy also works for submods where you aren't the owner of the main mod. (Eg: If you're writing a bugfixing submod for a seemingly-abandoned total conversion.)
 
  • 3
Reactions:
Thanks everyone. I had no idea some of the things you mentionned were even possible jonjowett. That's very useful!
 
  • 1Like
Reactions:
Hi all,
When dealing with defines (defines.lua) entries can you make the effects of some definitions conditional? Say I want to set FEMALE_ATTRACTION_CUTOFF to 50, but only for attractive or groomed characters while everyone else uses the vanilla 45, is it only possible with event modifiers, or is there a cleaner approach?
 
Hi all,
When dealing with defines (defines.lua) entries can you make the effects of some definitions conditional? Say I want to set FEMALE_ATTRACTION_CUTOFF to 50, but only for attractive or groomed characters while everyone else uses the vanilla 45, is it only possible with event modifiers, or is there a cleaner approach?

It is not possible to tweak things so that the defines only apply in some cases, and the modifier approach would be messy since there's no on_45_years_old on_action to use (and a delayed on_adulthood event doesn't work for historical characters, on_yearly_pulse could be almost a year after someone's birthday, and so forth).
 
  • 1Like
Reactions:
It is not possible to tweak things so that the defines only apply in some cases, and the modifier approach would be messy since there's no on_45_years_old on_action to use (and a delayed on_adulthood event doesn't work for historical characters, on_yearly_pulse could be almost a year after someone's birthday, and so forth).
Alright, are there any workarounds then? Maybe do it in reverse? Increase the age for everyone but give negative modifiers via on_yearly_pulse to those who aren't eligible?
 
Alright, are there any workarounds then? Maybe do it in reverse? Increase the age for everyone but give negative modifiers via on_yearly_pulse to those who aren't eligible?
In short, yes, this is approximately the way I'd do it.

day_of_birth, month_of_birth, year_of_birth, day, month and year are all exportable variables. Some quick maths, and you can easily calculate the number of days/months until the character's next birthday. So, starting from an on_yearly_pulse event, you could write some (probably rather annoying) code to trigger an event on their next birthday.

(Pseudocode: Has this char got the flag birthday_search_started or birthday_events_are_set_up? if yes, do nothing and exit. if no, set the birthday_search_started flag and continue. is their birthday in more than 30 days? if yes, check everything again in 30 days' time. if no, is their birthday in more than 5 days? if yes, check everything again in 5 days' time. if no, is it in 4 days? ... 3 days? ... ... ... is it today? if yes, set up a recurring birthday event for all future time, remove the birthday_search_started flag and set the birthday_events_are_set_up flag. This recurring birthday event can do whatever you like for attractiveness etc.)

Also, note that it's not just historical characters who don't have an on_adulthood_pulse - it's also every single character that's generated by event. And there are lots of these: rebel leaders, random commanders, random women, even major plot figures like Seljuk and Temujin, etc etc etc. Some people are generated at quite old ages (eg. gurus are always 50+, and I think random theocrat successors also tend to skew quite old), so you can't assume that every newly-generated character (ie. who hasn't yet had a yearly pulse and therefore hasn't yet had any recurring birthday events) is young and attractive. However, it's not too bad if a random nobody is erroneously considered to be "attractive" for a few months, so I think my yearly-pulse strategy outlined above is acceptable.
 
Last edited:
  • 1
Reactions:
In short, yes, this is approximately the way I'd do it.

day_of_birth, month_of_birth, year_of_birth, day, month and year are all exportable variables. Some quick maths, and you can easily calculate the number of days/months until the character's next birthday. So, starting from an on_yearly_pulse event, you could write some (probably rather annoying) code to trigger an event on their next birthday.

(Pseudocode: Has this char got the flag birthday_search_started or birthday_events_are_set_up? if yes, do nothing and exit. if no, set the birthday_search_started flag and continue. is their birthday in more than 30 days? if yes, check everything again in 30 days' time. if no, is their birthday in more than 5 days? if yes, check everything again in 5 days' time. if no, is it in 4 days? ... 3 days? ... ... ... is it today? if yes, set up a recurring birthday event for all future time, remove the birthday_search_started flag and set the birthday_events_are_set_up flag. This recurring birthday event can do whatever you like for attractiveness etc.)

Also, note that it's not just historical characters who don't have an on_adulthood_pulse - it's also every single character that's generated by event. And there are lots of these: rebel leaders, random commanders, random women, even major plot figures like Seljuk and Temujin, etc etc etc. Some people are generated at quite old ages (eg. gurus are always 50+, and I think random theocrat successors also tend to skew quite old), so you can't assume that every newly-generated character (ie. who hasn't yet had a yearly pulse and therefore hasn't yet had any recurring birthday events) is young and attractive. However, it's not too bad if a random nobody is erroneously considered to be "attractive" for a few months, so I think my yearly-pulse strategy outlined above is acceptable.

And if it helps, randomly generated events of all sources can be caught with carefully constructed on_action events, as is briefly outlined on the wiki page for event modding (see on_host/employer_change).
 
  • 1
Reactions:
What happens when something doesn't have an ai_will_do/chance/whatever. Does it have a default chance to be picked or is it maybe ignored?
 
I had a look into Clean Slate, this is the ai_will_do of de_jure_county_claim.

Code:
    ai_will_do = {
        factor = 1

        trigger = {
            # AIs will not take the last counties off their liege's direct vassals
            trigger_if = {
                limit = {
                    ROOT = {
                        same_liege = FROM
                    }
                }

                FROM = {
                    num_of_count_titles > 1
                }
            }

            trigger_if = {
                limit = {
                    ROOT = {
                        has_character_flag = is_temujin
                        has_landed_title = e_mongol_empire
                        is_landed = yes
                    }
                }

                FROM = {
                    NOT = { has_landed_title = e_china_west_governor }
                }
            }
        }

        coronation_factor = yes
    }

How can this work without a modifier?
 
I had a look into Clean Slate, this is the ai_will_do of de_jure_county_claim.

Code:
    ai_will_do = {
        factor = 1

        trigger = {
            # AIs will not take the last counties off their liege's direct vassals
            trigger_if = {
                limit = {
                    ROOT = {
                        same_liege = FROM
                    }
                }

                FROM = {
                    num_of_count_titles > 1
                }
            }

            trigger_if = {
                limit = {
                    ROOT = {
                        has_character_flag = is_temujin
                        has_landed_title = e_mongol_empire
                        is_landed = yes
                    }
                }

                FROM = {
                    NOT = { has_landed_title = e_china_west_governor }
                }
            }
        }

        coronation_factor = yes
    }

How can this work without a modifier?
It's the factor = 1 that does it. Modifiers only affect the base factor.
 
  • 1
Reactions:
I do not understand what I read.

What's inside the trigger, I get it. The trigger itself I do not, I usually see it in events. Does it mean it controls if the factor = 1 is applied? Can it be used anywhere then?
 
I do not understand what I read.

What's inside the trigger, I get it. The trigger itself I do not, I usually see it in events. Does it mean it controls if the factor = 1 is applied? Can it be used anywhere then?

The factor only comes into play if trigger = {} is met. CleanSlate uses triggers instead of modifier blocks with a factor of 0, to avoid inverted logic. That makes it much easier to read, and often more concise too.

Trigger-blocks can be used anywhere factors are used, commonly called MTTH-blocks (from mean_time_to_happen, the system that used to fire most events in early Paradox games, also known as performance killers).
 
  • 1
Reactions:
What happens when something doesn't have an ai_will_do/chance/whatever. Does it have a default chance to be picked or is it maybe ignored?
It depends on the specific "something". For event options, if there is no option with AI weightings, the AI will pick a random valid option, with each option having an equal chance of being picked. (Not sure exactly how it works if some but not all options have AI weightings - this is probably not a good idea...) For decisions, omitting an AI weight means the AI will always take the decision if possible. Etc etc.
 
  • 1
Reactions:
Can I use something like is_holy_site = ROOT to check if a province has a holy site of the religion of character ROOT ?