• 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.

Stellaris Dev Diary #222 - Moddability Updates in LEM

Welcome to another Stellaris Modding Dev Diary! Today, I’ll be talking you through some of the new scripting language features in the upcoming 3.1 patch.

We have already mentioned that Traditions are considerably more moddable now with the new system, with far less heavy lifting needed in the gui and loc files. I can also confirm that you can, for instance, now script in tradition trees that only become available if you make certain decisions during the game. But today, the main focus will lie on variables.

Variables

I mentioned last time that we have been looking to do more with variables. In the last patch, several more ways to save various bits of information in the game were added, but the biggest missing one was an easy way to get trigger values, like for example the number of pops on a planet. You also were still quite limited in where you could use variables, especially compared to PDS’ newer games like CK3. Also, the syntax for using them was not quite ideal, in many cases.


With 3.1, we have greatly increased the power of variables. First of all, the format: previously, when you wanted to get the value of a variable, you had to refer to… well, the variable itself, and that was all. Now, you can do a few more things:

Code:
    value = my_var                                 #gets the value of my_var variable set on the current scope
    value = from.capital_scope.my_var              #gets the value of the my_var variable set on from’s capital
    value = trigger:num_pops                       #gets the number of pops in the current scope
    value = from.capital_scope.trigger:num_pops    #gets the number of pops in from’s capital

So you can do dot scoping, which saves a lot of ugliness, and is a big improvement as it is. And as you can see, you can also refer to triggers, with trigger:<trigger>. This will support any trigger checking a number and just a number, with no { }.

(Note: the previous, ugly format for copying variables across different scopes has been removed. The one where you'd specify "value = { scope = x variable = y }")

3.0 already had an effect, export_trigger_to_variable, but it only worked with fleet_power. That was the prototype; the functionality has been expanded to all such triggers. Importantly, that effect lets you get values from triggers that are a bit more complex, with { }, that are still comparing a single number:

Code:
    export_trigger_value_to_variable = {
        trigger = num_assigned_jobs
        parameters = {
            job = miner
        }
        variable = num_miner_jobs
    }

3.0 also, to mention it again, added a bunch more ways to get game values such as modifier numbers and resource stockpiles to variables. It also added a few more places where you could use them: multipliers in add_resource and add_modifier, for instance. With 3.1, we have added a lot more things that you can use a variable for:
  • As values in triggers checking single numbers, e.g. "num_pops > my_variable", "intel = { who = from value < trigger:num_pops }"
  • As values in effects using a single number, e.g. "add_experience = my_variable".
  • As a multiplier parameter in triggered resource tables (e.g. in a building):
Code:
     resources = {
        category = planet_buildings
        cost = {
            trigger = { <triggers> }
            minerals = 100
        }
        multiplier = my_var/owner.trigger:num_pops
    }
  • In MTTH/AI Chance modifiers:
Code:
     ai_chance = {
         factor = 1
         modifier = {
            add/factor = my_var/trigger:num_pops
            is_variable_set = my_var
         }
     }
  • add_modifier now has a time_multiplier as well as a multiplier parameter, you can use it there. E.g. for death cults, this is used to apply a modifier for 10 years X edict_length_mult
  • In ordered_script_lists: a feature yoinked from our newer games. I’ll let the trigger docs entry explain:
Code:
ordered_owned_fleet - Iterate through each fleet owned by the country - executes the enclosed effects on one of them for which the limit triggers return true. Picks the specific object according to the order specified (position 0, order_by = trigger:num_pops would run the effects on the X with the most pops)
ordered_owned_fleet = {
    limit = { <triggers> }
    position = <integer, starting with 0>
    order_by = <variable>/trigger:<trigger>
    inverse = yes/no (default: no - if yes, then 0 is lowest rather than highest)
    <effects>
}
Supported Scopes: country
  • If your variable is too exact a number, you can now use round_variable_to_nearest to round its value to e.g. the nearest multiple of 10.

A summary of these functionalities have been added to an information file in the events folder (and attached to this post). Also, I could well imagine further expanding on these usages of variables, so it’s quite possible there will be even more coming along these lines in future. The changes have already proven extremely useful to us, e.g.:
  • Improving Death Cult rewards: cut about 1000 lines of script and still ended up with the new version taking more factors into account to determine the adequate reward for you!
  • Fixing Golden Rule cash payouts: the previous solution was to fudge the numbers and give you an amount with a rather tenuous connection to the actual pay-in. This is no longer necessary.
  • Improving Federation Science Leadership Challenge: adding the actual number of techs and repeatable techs you have researched as a factor
  • And more.
Sprite Sheet Changes

That was already quite a lot, but there’s a few more things that I’d like to highlight. Firstly, certain older elements of the game used sprite sheets for their icons - a system where a list of icons would all be in a row on one image file, and we’d specify that we’d want to use, say, the 5th icon on the list. We had a few issues with these inhouse (the colony automation button currently accidentally being a robotic cow springs to mind), and modders have pointed out that they are a pretty bad overwriting bottleneck, since only one mod can overwrite the sprite sheet at a time, and therefore only one can add extra types of that object that add new graphics at a time.

We worked out a way to change index references to icons in sprite sheets into normal key references, which meant that we could convert these elements of the game to use the normal system (with no need for new icons to be inside a sprite sheet). This got rolled out to the likes of army types, colony automation types, bombardment stances, and (with great difficulty!) ship sizes.

An example:
Code:
    spriteType = {
        name = "GFX_ship_size_military_1"
        sprite_sheet_sprite_type = "GFX_ship_sizes"
        default_frame = 2
    }

In the case of ship sizes, it was a bit tricky, since the icon_frame index number then specified which icon it would use on multiple sprite sheets. In the end, we left that system in place for starbases (since very few tend to add a new type of starbase) and made the line “icon = ship_size_military_1” tell the game to refer to several sprite keys: GFX_text_ship_size_military_1, GFX_ship_size_military_1, GFX_ship_size_military_1_top, GFX_ship_size_military_1_top_damaged

This will need some updating for mods which change the affected objects, since the old format no longer works, but in the long term it will hopefully solve a lot of compatibility headaches!

Randomness

Some have noticed that, in certain cases, the randomness of script functions such as random_list is not very random. Specifically, events fired from on_game_start had this issue (and various other on_actions, but that was the one that hurt the most). This was pretty unfortunate, since this effectively meant that certain things that were meant to be different each game... simply were not. Relatedly, we also revisited some more longstanding issues like where if you used while loops or every_x loops, each time the effect happened within that loop, the random result would be the same. (As in 25x random_list resulting in 25x the same result rather than 25x a random result).

We fixed this quite exhaustively:
- The lack of randomness in on_actions like on_game_start is fixed. If we in future make the mistake that caused this to happen again, the game will warn us, so hopefully it is banished for good.
- While loops and every_x loops have improved randomness
- For good measure, we added a reroll_random effect

Other Cool Stuff

On another note, we can now add triggered pop modifiers to traits, so for instance, you can add a trait that gives a bonus on one planet class and a penalty on another. The potential that this unlocks is quite considerable - for instance, it allowed us to stop using the somewhat unintuitive (and eminently cheeseable) stopgap solution of giving Void Dwellers two traits, and instead giving them one that applies differently depending on what sort of planet they are on.

As some have noticed, the Clone Army origin does several cool, new things that we haven’t really explored in the game before. A lot of what we added for it could have further cool uses in the future, for instance:
  • You can now gender-lock species
  • You can set an empire limit on how many instances of a building you can build. (And alter it during the game).
  • A game rule, “should_force_decline_species”, has been added. It will make a species for which it returns true decline on a planet, triggering an alert based on whatever tooltip is specified in the game rule. It is also hooked up to stop pops from migrating/being resettled/etc to a place where they would immediately start declining.

Finally, we added a bunch of new effects, triggers and modifiers, as usual. A couple to highlight are:
  • set_visited = <system> - reveals a system to you, without you having surveyed it
  • set_saved_date - lets you save a specific date (can be in the future) so that you can use it in locs, similar to variables: [This.my_saved_date].
  • Technically, the last effect is actually adding a <scope>_flag, so the standard flag effects and triggers have been ported over to all scopes
  • You can now use [loc] commands in button effects, which apparently will be very useful for dynamic modded UIs
  • You can define descriptions for districts, buildings, jobs and special projects through desc = { text = X trigger = { Y } } now. They also now take loc commands.
  • We deleted has_non_swapped_tradition and has_tradition_swap, and consolidated them into has_active_tradition. Modders: do a search-replace!
  • Every scope that lacked script flags (e.g. country_flag) now has them. Also, variables work in all scopes now too.
  • Note for updating mods: count_diplo_ties is now count_relation, count_armies is count_owned_army or count_planet_army (depending on the case). any/every/random_mining_station/research_station have also been removed, because they were nonsense. Use simply mining_station/research_station/orbital_station scope change instead. Also, observation_outpost no longer takes a "limit", but you can say "exists = observation_outpost" as compensation.
Adding all these new functionalities has been a boon for us in the Custodian team, and we are gradually rolling them out to older parts of the game which can benefit from them. It’s something I look forward to doing more of in future, and equally, I am excited (and, I’ll admit, a tiny bit afraid) to see what modders will do with them!

One last thing: the old trigger_docs.log has now been deprecated, and instead we now have a more wieldy and more comprehensive script_documentation folder, the contents of which are attached to this post.

And as some of you are probably aware, we did some early access for Modders for the Nemesis update. We had ~10 mods update on release day, servicing around 1.6 million subscribers, overall we were very happy with the results and the community reaction, and if this continues to go well we’re looking to gradually expand this experiment to more of the Modding Community. For Lem, we’re looking to add another 10-ish Modders to the early-access experiment. If you’re interested you can fill out the Modder Early Access Request form.
 

Attachments

  • 000_how_to_use_variables_in_script.txt
    4,1 KB · Views: 0
  • effects.log
    181,4 KB · Views: 0
  • localizations.log
    4,4 KB · Views: 0
  • scopes.log
    8,1 KB · Views: 0
  • modifiers.log
    294,3 KB · Views: 0
  • triggers.log
    128,3 KB · Views: 0
  • 60Like
  • 34Love
  • 15
  • 2
  • 1
Reactions:
There are some modifiers that aren't auto-generated that I have a use case for, so I would be very happy if they were added.
Similar to shipsize_<shipsize name>_hull_mult and shipsize_<shipsize name>_hull_add:
Code:
shipsize_<shipsize name>_shield_mult
shipsize_<shipsize name>_shield_add
shipsize_<shipsize name>_armor_mult
shipsize_<shipsize name>_armor_add


Also, is there a way to create modded mutually-exclusive traditions? As in, both options start available, but if you pick one the other one becomes unpickable.
 
  • 1
Reactions:
Also, is there a way to create modded mutually-exclusive traditions? As in, both options start available, but if you pick one the other one becomes unpickable.
Some of the comming/existing tradition trees already have conditions, like Ethics and Government forms.
This would really just be a "not has Tradition Tree B" type of check.
 
Last edited:
  • 1
Reactions:
Also, is there a way to create modded mutually-exclusive traditions? As in, both options start available, but if you pick one the other one becomes unpickable.
Hopefully the ability to dynamically alter which trees are available, plus the ability to tell which trees have been adopted (which already exists though they changed the function name) will handle that just fine.

It would be obviously true in a language with a more internally consistent syntax and type system but there have occasionally been weird limitation on what filters and functions and modifiers you can use in what contexts (e.g. it at least used to be completely impossible to dynamically modify the upkeep for a particular building or even all instances of a building, because for some reason upkeep did not permit modifiers). The language has been trending better in that regard, though.
 
  • 1
Reactions:
Also, is there a way to create modded mutually-exclusive traditions? As in, both options start available, but if you pick one the other one becomes unpickable.

Yes, the potential check for traditions defaults to the country scope, so you could add

Code:
potential = { NOT = { has_tradition = tr_tree_2_adopt } }
to tree 1 and
Code:
potential = { NOT = { has_tradition = tr_tree_1_adopt } }
to tree 2 and it should work out fine.
 
  • 10
Reactions:
Do these random changes mean that events/outcomes that we've not seen in a long while might happen again? Some seem pretty random (Improbable Ceramics), but others seem to never spawn anymore (Brain Slugs), or always have the same outcome (I always get Grey Tempest, never anything else), and there are others I've never even heard of happening mentioned in this thread.
 
Do these random changes mean that events/outcomes that we've not seen in a long while might happen again? Some seem pretty random (Improbable Ceramics), but others seem to never spawn anymore (Brain Slugs), or always have the same outcome (I always get Grey Tempest, never anything else), and there are others I've never even heard of happening mentioned in this thread.
I miss Brain Slugs. A few years ago, I could reliably find them--but I haven't seen them in any of my games in at least two years.
 
  • 1
Reactions:
Do these random changes mean that events/outcomes that we've not seen in a long while might happen again? Some seem pretty random (Improbable Ceramics), but others seem to never spawn anymore (Brain Slugs), or always have the same outcome (I always get Grey Tempest, never anything else), and there are others I've never even heard of happening mentioned in this thread.
L-Cluster outcome are most definitely affected by this random outcome bug.
Slugs may be affected, but iirc they are just rare.
 
I have to ask, guys: what about getting the name lists out of the protected areas, and so letting us use name list mods without breaking achievements?
 
  • 1
Reactions:
I have to ask, guys: what about getting the name lists out of the protected areas, and so letting us use name list mods without breaking achievements?
Well, since they need to be synced between players in multiplayer, which is one of the jobs of the checksum, that's not happening.
 
  • 4
Reactions:
Well, since they need to be synced between players in multiplayer, which is one of the jobs of the checksum, that's not happening.
Oh is that the reason?
Multiplayer ruining the game for the 99% once again :mad:
 
  • 3
Reactions:
Oh is that the reason?
Multiplayer ruining the game for the 99% once again :mad:
Not allowing you to get achievements while using mods is hardly ruining the game.
 
  • 3
Reactions:
Not allowing you to get achievements while using mods is hardly ruining the game.
For mods that just change names and thus have zero impact? Literally unplayable
 
  • 1
Reactions:
At least you can rename pretty much everything and everyone in your empire by clicking the name.
 
  • 4
Reactions:
Not ships
Yes, you can rename ships:
Fleet->Find Ship->Ship Details->Click on name, same as you rename everything else in the game.

Not that it makes any sense to bother for all but the most unique ships.
 
  • 5Like
Reactions:
Hey Dev team - been with this game since day 1.
Some recommendations.

1. Since Nemesis, can no longer see enemy ship weapons and gear (it's always greyed out in ship description). Even with a lot of intel. It really detracts from the game as you can't build fleets solely to oppose enemy designs. Please remedy!

2. Caravan coinz are silly. Just use currency. I originally suggested being able to buy 10% or 20% progress on random research options via these traders (buy schematics).

3. When paying marauders I want to be able to choose the amount I pay;
with deliverables shown.
i.e. 2000.00 = get a 2k fleet to harass rival.
i.e. 10 000.00 get a 10k fleet to harass rival.
I think it would be awesome if a player could not even have a fleet and just rely on pirate muscle to do the job for them.

4. There's not enough interactivity with stagnant empires. Need some events...

5. When running envoys for subterfuge of enemy nations, there are far too few dialogue boxes (agent exposed - disavow).

6. Armies still don't matter at all in Stellaris. Can we please fix this? I think the army system has been severely ignored and it wouldn't be too hard to think up something better. It could be a full DLC.

7. Stealth is the only major sci-fi trope missing from Stellaris. It could be a done this way; stealth ships can toggle cloak (in the ship panel in the bottom left), and move between systems, then when uncloaking, have a 10 or 20 second attack period where the enemy fleet doesn't fire. You could limit the amount of stealth ships an empire can field, or limit it just to corvettes or science vessels perhaps. Stealth letting us penetrate closed borders is another option there.

8. Empire sprawl still doesn't matter. The advent of administrative buildings just patches the issue as if it doesn't matter at all! This is a problem resulting in players always choosing to just be a huge empire instead of having vassals and tributaries, etc... When become huge their needs to be a modifier that systems on the periphery start to ask to become vassals, tributaries, or fed alies.

9. Genetic uplift seems to have disappeared from the game.. Pity? This was very cool. If bringing it back, it must come with a little bit of genetic modification. JUST 1 trait you can pick.

10. Leviathans should be able to sometimes move out of their home system and cause a bit of havok. The game is too stable. Players expect to never lose anything, ever. Not a single system. Leviathans, let's face it, just sit there waiting to be molested by players when they've talked to the curator and have 30k to melt them with. make Leviathans a bit crazy, something you are scared to be close to! I'd even say, consider letting the odd leviathan go postal and roam through the whole galaxy, sacking each system of it's star base as it goes! They are not scary and they SHOULD be.

11. Allies are useless during wars. Can we please have a system that allows us to give orders to inferiors in our federation? Even simple commands like; attack this player, defend your own territory, follow this fleet.

12. Too many traditions can be opened. I know Lem is changing this, but consider that perhaps even 7 traditions is too many. It takes away from the role play of an empire type and messes with balance in mid/later game. Also, having too many traditions open makes me question why anyone min maxxing would bother with any empire type other than pure religion to get unity. There are too many bonuses on offer with a unity build. It's really silly.

13. Not being able to add and remove planets from sectors is annoying. Sometimes it really messes things up for me. It's still in the game code somewhere, can't it come back?

14. Look at the culture system in Sins of a solar empire. it was really smart. maybe Stellaris should use this. We have some systems in place that could be used at the mathematical metrics by which to assume the force and coherency of a cultural signal. This could lead to systems on your fringe being influenced by neighbours and rioting, rebelling.. etc. Some people would want to play a non military empire that is so cultural powerful that they want to enemy planets on their borders go into full scale rebellion and break away from their government. Flaking away at militarists from behind a starbase..

15. Also, planetary rebellion is broken. I have had several planets on 100% crime and they don't even attack me, I have seen this in the past but it seems to have been tuned down. The game is getting too soft. Made for sooky babies that can't handle losing a planet. That's not paradox. Punish us a bit.

16. Setting my own ships at different combat ranges helps control the spacing and visuals of combat. It's great. But the enemy AI often just swims around going crazy. if fleets could be assembled better during combat we'd have a better understanding of what's going on. Often you can't tell your ships from theirs. While that might be immersive, it's not useful for planning fleet combinations and watching effectiveness.

17. Devastation from orbital bombing needs to be 50% faster. It's a major feature of the game that has been gimped to the point it doesn't create any tension to go save the planet and really.. A fleet of 30 ships bombing a planet would really mess it up in 3 months...

Thanks Muchly.

M
 
Caravan Coinz really are silly, but that's the point. The whole thing is a parody of games in which players purchase lootboxes with a special in-game currency you buy with real money.
 
  • 1Like
Reactions: