• 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.
Welcome to a brief unannounced surprise bonus dev diary!

PDXCon preparations are taking up most of our time, but with attendees getting some early hands-on time with the Distant Stars Story Pack, we figured we'd give the modders among you a glimpse of some of the under-the-hood-changes coming in the update. We've discussed the changes coming to Anomalies in 2.1 'Niven' in the past, but what do they actually mean for you, the intrepid modder? Well, hopefully the reworked Anomaly back-end will make your life a lot easier.

Now strap in, we're going to get a little bit technical.

Let's take a look back at an old favorite, Anomaly category "Buried in the Sand" as writ in the olden days:
00_anomaly_categories_3.txt said:
Code:
anomaly_category = {
    key = "DES_BURIED_CAT"
    desc = "DES_BURIED_DESC"
    picture = "GFX_evt_desert"
    level = 2

    spawn_chance = {
        modifier = {
            add = 3
            is_planet_class = pc_desert
            from = {
                owner = {
                    NOT = {
                        has_country_flag = masters_writings_politics_found
                        has_country_flag = ai_admiral_found
                    }
                }
            }
        }
    }

    on_spawn = {
    }

    on_success = {
    }

    on_fail = {
        ship_event = { id = anomaly_failure.4030 }
    }
}
00_anomalies_3.txt said:
Code:
anomaly = {
    event = anomaly.4030
    category = "DES_BURIED_CAT"

    weight = 1

    potential = {
        always = yes
    }
}

anomaly = {
    event = anomaly.4135
    category = "DES_BURIED_CAT"
   
    weight = 1
   
    potential = {
        owner = {
            NOT = { has_ethic = ethic_gestalt_consciousness }
        }
    }
}
Awful, right? That's 50 lines of script split into three entries across two different files. But fear not, the future is bright!

New script in 03_anomaly_categories.txt said:
Code:
DES_BURIED_CAT = {
    picture = "GFX_evt_desert"
    level = 4
   
    spawn_chance = {
        modifier = {
            add = 3
            is_planet_class = pc_desert
        }
    }

    max_once = yes
   
    on_success = {
        1 = anomaly.4030
        1 = {
            modifier = {
                factor = 0
                owner = { has_ethic = ethic_gestalt_consciousness }
            }
            anomaly_event = anomaly.4135
        }
    }
}
Less than 25 lines of script, all in one file! Clean. Efficient. Sleek, even.

We have prepared a handy explainer in case you want to start low-key updating your event mods for 2.1 already;
Code:
an_anomaly_category = {                # Anomaly category ID key

    should_ai_use = yes/no            # Allows AI empires to generate the category. Default: no

    desc = "key"                    # Optional, if no desc is given "<category key>_desc" is assumed

    desc = {                        # Can also use triggered descs. First valid entry will be used.
        trigger = { ... }            # Scope: planet, from = ship
        text = "key"                # Localization key for description
    }
    picture = GFX_picture            # Picture displayed in category window
    level = int                        # Anomaly level, 1 to 10

    null_spawn_chance = 0.5            # Default 0. 0.0 - 1.0 (0 to 100%) chance category will NOT spawn
                                    # even if it is picked by the anomaly die roll. Used to make
                                    # categories for unusual objects (e.g. black holes) actually rare.
   
    max_once = yes/no                # default NO, if true will spawn category only once per empire
    max_once_global = yes/no        # default NO, if true will spawn category only once per game

    spawn_chance = {                # Chance for this anomaly category to spawn, 
        base = <num>                # relative to other valid categories. Default: base = 0
        modifier = {                # Spawn chance modifier
            add/factor = <num>
            <triggers>                # Scope: planet, from = ship
        }
    }

    on_spawn = { <effects> }        # Executes immediately when anomaly category is spawned. 
                                    # Scopes are this/root: planet, from: ship
                                    # NOTE: on_spawn effects will not run if category is spawned through console

    on_success = {                    # Picks anomaly event to fire; similar to random_list
        1 = {                        # Base chance
            max_once = yes            # Individual outcomes default to max_once = yes,
            max_once_global = no     # and max_once_global = no
            modifier = {            # Optional modifiers
                add/factor = <num>
                <triggers>            # Scope: ship, from: planet
            }
            anomaly_event = <id>    # New effect anomaly_event fires specified event ID. Scope: ship, from: planet           
        }                            # Can also use ship_event, though it gets different scopes:
                                    # ship, from: ship, fromfrom: planet       

        1 = <event id>                # shorthand for 1 = { anomaly_event = <event id> }
    }

    on_success = <event id>            # Shorthand for on_success = { 1 = { anomaly_event = <event id> } }
}                                    # Only use if there is only one outcome in the category

That's all for now! Keep an eye and ear out for news from PDXCon.
 
OK, let me get this straight. You actually removed separate "anomaly" entity that allowed modders to add new anomalies to existing categories and call it an improvement?
It was a calculated decision. I'm confident that you will find that the benefits far outweigh this small loss of flexibility.

@LordMune ,

Thanks for this! Can I ask that you paste a copy of the trigger docs for 2.1? Will really help us do some early debug.
There haven't been any major changes to existing trigger and effect functionality in 2.1. We're keeping the new additions as a surprise!

Will there be some kind of composition or inheritance concept for the new anomaly categories? For example, if there are two definitions of a category with different "on_success" objects, will one overwrite the other, or will the final "on_success" be a union of the members of each? If they're a union, then what would happen if you redefined something with a different weight?
You can't have duplicate anomaly category key IDs, but you can duplicate the text and triggers to make a new category appear identical to the original in-game.
 
It was a calculated decision. I'm confident that you will find that the benefits far outweigh this small loss of flexibility.


There haven't been any major changes to existing trigger and effect functionality in 2.1. We're keeping the new additions as a surprise!


You can't have duplicate anomaly category key IDs, but you can duplicate the text and triggers to make a new category appear identical to the original in-game.

Ok, thanks!
 
I havnt really done much event modding (because it appears to be such a huge hassle/mess) but is this something that will be applied to other events like colony events ect or only anomalies?
 
Does being able to set max_once for a specific outcome mean anomaly category will spawn as many times as outcomes available, or does this still need to be controlled by extra triggers?
An anomaly category will now spawn only as long as the category trigger is valid and there are valid outcomes in the category. No need to manually keep track!

I havnt really done much event modding (because it appears to be such a huge hassle/mess) but is this something that will be applied to other events like colony events ect or only anomalies?
There is a minor quality of life change for script that we have yet to announce, but these specific changes only apply to anomalies. We're always pushing for better scripting capability, but major overhauls like this one take time.
 
Last edited:
When exactly will that be?

The PDXCon agenda is at https://pdxcon.paradoxplaza.com/agenda

Stellaris is at 12:30, presumably Stockholm time, on Saturday, 19th May. Wiz is usually pretty entertaining, so hopefully it'll be a good watch and if the past is any indication it'll be on Twitch - it looks like they've translated the times of the events to my local time, so hopefully they'll do that for you to, see: https://www.twitch.tv/paradoxinteractive/events :).
 
Unfortunately anomaly categories now have the same problem species_classes had from the start. It is all nice and fine to be able to get rid of a few lines of code but now two mods trying to add a new outcome to the same category or file for that matter will just override each other and one wins one loses the same way as if two mods try to add new portraits to the humanoid class for example.

It is a step backwards unfortunately.
 
Unfortunately anomaly categories now have the same problem species_classes had from the start. It is all nice and fine to be able to get rid of a few lines of code but now two mods trying to add a new outcome to the same category or file for that matter will just override each other and one wins one loses the same way as if two mods try to add new portraits to the humanoid class for example.

It is a step backwards unfortunately.
They can just make a copy of the category they want to add it to and give it a unique name. Then it will look like the same cat but will be one that activates whatever their anomalies are. That would be a pain if you wanted to make a lot of anomalies using a lot of the different base cats. But if you where just making a lot of them for 1 cat (if not more) then this looks like it would save time.
 
@LordMune If I have a category with on_success = example.100, and the event example.100 has a trigger block, will that category be spawned when I don't met the event trigger? If it does and I don't meet event trigger when I resolve the anomaly, is that category considered "spent" (so won't be spawned in this game further)?
 
@LordMune If I have a category with on_success = example.100, and the event example.100 has a trigger block, will that category be spawned when I don't met the event trigger? If it does and I don't meet event trigger when I resolve the anomaly, is that category considered "spent" (so won't be spawned in this game further)?
I would imagine trigger checks after the call and flags are set at the moment of call. So it is likely category will be spent.

I believe the proper way to handle it is by modifying weight of a specific outcome by factor of zero - indeed I stumbled upon an anomaly that has DLC-locked outcome set this way, but this raises another question - how does the game handle zero factor, especially if it changes mid-game.
 
@LordMune If I have a category with on_success = example.100, and the event example.100 has a trigger block, will that category be spawned when I don't met the event trigger? If it does and I don't meet event trigger when I resolve the anomaly, is that category considered "spent" (so won't be spawned in this game further)?
Anomaly categories don't care about any in-event triggers in its outcomes. It's recommended not to use triggers at all for anomaly events, instead using a weight factor of 0 in the category's on_success to block certain outcomes. Likewise an anomaly category only cares about "firing" an outcome, not whether it successfully executes or not; in the edge case you describe, the anomaly category will be considered spent.

I would imagine trigger checks after the call and flags are set at the moment of call. So it is likely category will be spent.

I believe the proper way to handle it is by modifying weight of a specific outcome by factor of zero - indeed I stumbled upon an anomaly that has DLC-locked outcome set this way, but this raises another question - how does the game handle zero factor, especially if it changes mid-game.
As for 0 factors, it simply multiplies the weight by 0 as expected, and on_success weights are checked when the anomaly category research is completed. It's up to the scripter to make sure the on_success weights won't all be set to 0 in the time it takes for the player to research a spawned anomaly category.
 
Anomaly categories don't care about any in-event triggers in its outcomes. It's recommended not to use triggers at all for anomaly events, instead using a weight factor of 0 in the category's on_success to block certain outcomes. Likewise an anomaly category only cares about "firing" an outcome, not whether it successfully executes or not; in the edge case you describe, the anomaly category will be considered spent.


As for 0 factors, it simply multiplies the weight by 0 as expected, and on_success weights are checked when the anomaly category research is completed. It's up to the scripter to make sure the on_success weights won't all be set to 0 in the time it takes for the player to research a spawned anomaly category.
So, here's what is still unclear:

Having 3 valid max_once =yes outcomes in anomaly means the game would know to spawn this category no more than 3 times, right? Even if you don't research them?
 
E.g. can one have a hypothetical circumstance where the anomaly has only one option, however this option would take 2 years to research so you don't research it yet, and in the meantime you find the same anomaly (assuming the anomaly category is not set to max_once)?