• 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.
Showing developer posts only. Show all posts in this thread.

LordMune

Content Design Lead
26 Badges
Mar 15, 2015
142
941
  • Europa Universalis IV
  • IPO Investor
  • Stellaris: Galaxy Edition
  • Crusader Kings II
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.
 
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:
@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.
 
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)?