• 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
Hello, earthlings. My name might be unfamiliar to some dev diary readers; I’ve been working on Stellaris for some time now and am in charge of scripting/content design duties for Stellaris while the eminent Goosecreature is away rearing his brood. This week’s dev diary is the first in a two-part series on modding, which you will read, enjoy, and be enlightened by. We’re here to get our hands dirty, so don’t expect any pretty screenshots! Only functional screenshots.

Stellaris is built on the Clausewitz engine, and has had a lot of functionality ported over from our other games. Since we use a random galaxy generated at game start (unless you mod in a static one) we have to approach things a bit differently than you would in a game with a pre-set map of Europe - if you’ve modded a Paradox Development Studio title before you may come across a few surprises, but you should feel right at home soon enough.

General Modding
Like our other games, Stellaris is very mod-able. Take a look in the \Stellaris\common\ folder and you’ll see. It contains mostly everything that determines how the game functions. Edicts, ethics, game rules, army attachments, name lists, country types, planet classes, modifiers, buildings and so on can all be found here. In \Stellaris\common\defines\ you will find a LUA script file that regulates a lot of basic game behaviors and settings, like the base soft cap on the number of core planets ( CORE_SECTOR_PLANET_CAP = 5 ) or the camera field-of-view ( NCamera = { FOV = 35 } ) available for easy tweaking. Most of these values come with fairly informative comments!

Scripted Triggers & Effects, Chained Event Targets
We recently inherited scripted triggers and effects from Hearts of Iron IV! They’re very good. One addition to the scripting language that originated in Stellaris and may or may not find its way to other games in the future is event target chaining. It allows us to chain targets/scopes/saved event targets together in a way not unlike how we do it in localization. For example, what was once written
Code:
from = {
    owner = {
        establish_communications = root
    }
}
can now be rendered as the much more digestible
Code:
from.owner = { establish_communications = root }
Amazing!

Anomalies
Swiftly moving on to Anomalies, the lifeblood of early game exploration in Stellaris. Incidentally, anomalies are also rather unlike the events found in our other games You can and should make your own! I will show you how.

An anomaly is made up of a minimum of four components; the anomaly category, the anomaly, the event and localization.
  1. \Stellaris\common\anomalies\00_anomaly_categories.txt
  2. \Stellaris\common\anomalies\00_anomalies.txt
  3. \Stellaris\events\00_anomaly_events.txt
  4. \Stellaris\localisation\events_l_english.yml

Anomaly categories define what planets are viable for a certain category of anomalies to spawn on. Anomalies refine this selection further and link to specific events. The event that is eventually fired… does stuff. The localization file provides the text for the event and the category window.

I feel that a picture is worth more than a thousand words, so I’m going to show you pictures of words to maximize efficiency. See if you can follow along!

Step 1 - 00_anomaly_categories
1anomalycategory.png


Step 2 - 00_anomalies
2anomaly.png


Step 3 - 00_anomaly_events
3event.png


Step 4 - events_l_english
4localization.png



And the end result!
Planet Surveyed
5categorywindow.png


Anomaly Researched
6eventwindow.png




That’s all for now, planet-dwellers. Next week, art director Aerie will explain how to get your own art into the game. Exporters! Graphics! Spaceships!
 
Last edited by a moderator:
  • 159
  • 48
Reactions:
Is it possible to add new language to the localisation category?

Secondly, is it possible for an anomaly event to act as a trigger for another anomaly or another event in general to script some anomaly "chains"?
It should not be impossible to add additional languages.

Yes, anomaly events (and even anomaly categories just spawning) can be used to trigger other anomalies. We make some use of this in the base game.
 
  • 25
Reactions:
Might be just because I am used to it but I found the old one easier to quickly understand what was in it.
There's definitely something to be said for the clarity of the old ways. Chained event targets truly shine as right-hand-side arguments though; where we would often have to do silly things like
Code:
scope = {
    scope = {
        scope = {
            effect = prevprev
        }
    }
}
we can now do
Code:
effect = correct.scope
It's kind of hard to explain without very specific examples that do not make a lot of sense out of context, but... It's good.
 
  • 21
  • 8
Reactions:
So the demonstartion anomaly has an event for sucessfully surveying the anomaly, but none for eventual failures. What happens when the failure events are not existent like in this case and the anomaly survey fails?
It does have fail and crit fail events (dev_diary_fail.1 and dev_diary_crit_fail.2), I just don't show off their script.

If an anomaly has no failure events, failure will presumably be silent - there is no result.
 
  • 16
  • 2
Reactions:
I can't tell if that is a bad "Well..." or a good "Well..." :eek:

Paradox may already have my time, they may already have my wallet, but you don't have my soul!
(yet...)
I would like to think they might have made one, one of the often requested things in the ck2 modding scene is a full list of triggers, scopes and effects etc which are valid and what their uses are and then a visual way of seeing those in notepad. If not then the community will like they have done in ck2 to the best of their ability but a paradox made one would be super useful
 
How are the chance modifiers handled (Add=X and Factor=X) when multiple of each kind apply.
E.g. is
Add = 4
Factor = 5
Add = 3
Factor = 2

(4+3)*(2+5) or 4*5 + 3*2 ?
Neither. It calculates each step in order, so

base 0 = 0
add 4 = 4
factor 5 = 20
add 3 = 23
factor 2 = 46
 
  • 3
Reactions:
Neither. It calculates each step in order, so

base 0 = 0
add 4 = 4
factor 5 = 20
add 3 = 23
factor 2 = 46
Would it not be better to do all additions first before multiplication? That is how ck2 does it and it makes it easier if you want to do an addition and do not have to scroll through a bunch of modifiers to get back to before you were doing multiplication and put in the add 2 or whatever
 
But when it does them in order, neither additions or multiplications firsts, why would you have to go back if all you want to do is add 2?
Wouldn't that just be:

base 0 = 0
add 4 = 4
factor 5 = 20
add 3 = 23
factor 2 = 46
add 2 = 48

I think you lost me, do you mean add 2 to total? add 2 to a previous modifier? or something completely third that my only half awake brain can't understand?
Because there is a difference between doing it each way.
If you do (Ignoring proper order of operations obviously) 1 * 5 + 3 = 8
Which is different to 1 + 3 * 5 = 20

Also it kinda makes more sense to do all the addition first with ai chances etc so then your additions have a bigger impact as seen by my example above, it just to me logically makes more sense to do all the adding first to get your base to a big amount then multiply them all.
 
  • 2
Reactions:
I don't necessarily disagree, but i think it's kind of a preference more than a matter of what's logical, when it does each in order the way it appears to do, what exactly would be stopping you from just placing all the additions first in the code? wouldn't that produce the same effect as what you want it to do?

(genuinely asking since this is not my area of expertise in coding, the internal math and all that, so i don't have that much of a clue compared to you i'd imagine :p)
That is my point, say they are carried out in the order they are written and you want it to be addition first. You order them addition first then multipliers afterwards. If you want to then put in another addition you have to find where the last addition is and put your new one after that, this can be a pain in the arse if you have a bunch of modifiers.
Also it makes a nice consistency between the different games when you mod them
 
There is a console command to dump all available triggers and effects to a text file. Unfortunately these triggers and effects are sometimes improperly documented (or their usage has changed since the code comment was written), so you may find some misleading information in the raw text dump. I expect the wiki will rectify this shortly after release, and I hope to put in some work towards that goal myself.

We will be posting NP++ and Sublime syntax files as-is (no official support) in the coming days, it should be fairly trivial to reverse-engineer those for use with any text editor of your choice.
 
  • 3
  • 2
Reactions:
Can the "On_Spawn" be used in Tile-Blocker mod?

IE On_Spawn Volcano -> Do X (Add deposit maybe?)
Depends on what you want to do, in this case on_spawn is unique to Anomalies. I'm not familiar with this tile blocker mod, but on_spawn gives you a scope on the surveyed planet, so you can directly do stuff to the planet based on what tile blockers are on it, for example.

So,
Code:
on_spawn = {
    if = {
        limit = {
            any_tile = { has_blocker = tb_volcano }
        }
        random_tile = {
            limit = { has_blocker = tb_volcano }
            clear_deposits = yes
            add_deposit = d_vast_mineral_deposit
        }
    }
}
would add a mineral deposit to a volcano tile, if 1) the anomaly category spawns on the planet and 2) there is a volcano tile blocker on the planet. It won't, however, always add a mineral deposit to every planet with a volcano tile blocker, you'd have to use regular events for that.

Is there an ETA on those syntax files for NP++ by chance? :p
Slight delay due to technical issues. Thanks for your continued patience!
 
  • 2
Reactions:
Hey,
I am a total beginnen in moding so i tried to understand the creation of an anomaly , but
i had a problem to understand the first step. My problem is the following:

Step 1 - 00_anomaly_categories
meaning, i don't know what it does.

modifier = {
add = 2
from {

has_ship_flag = dev_diary_flag
}
}

I know that this is a trigger for the anomaly but i have no clue what has_ship_flag and dev_diary_flag stands for.
Thanks in advance forum for our help .

Re: 00_anomaly_categories, think of an anomaly category it like a box full of events. It uses the spawn_chance modifier to see what planets it can be discovered on, and then 00_anomalies decides what event from the box should be picked, and then anomaly_events is, well, the event itself.

In the example in the original post, the anomaly category's spawn chance starts at 0, is increased to 3 if the planet is an asteroid (is_asteroid = yes | add = 3), and then the spawn chance is doubled (factor = 2) if the ship that surveys the planet (this is stored in the FROM scope) has had the "dev_diary_flag" (an arbitrary name) set by some previous event. Flags are just bits of text you assign to objects in the game to keep track of them; there are country flags, ship flags, planet flags, pop flags and so on.

That event might have looked something like this:
Code:
country_event = {
    id = dev_diary.500
    title = "Dev Diary Flag Found!"
    desc = "One of our Science Ships has found something that will make it easier to discover certain Anomalies."
    picture = GFX_evt_psionics

    trigger = {
        NOT = {
            has_country_flag = found_dev_flag
        }
        any_owned_ship = {
            is_ship_class = shipclass_science_ship
        }
    }

    mean_time_to_happen = {
        months = 24
    }

    immediate = {
        set_country_flag = found_dev_flag
    }

    option = {
        name = "Great!"
        random_owned_ship = {
            limit = {
                is_ship_class = shipclass_science_ship
            }
            set_ship_flag = dev_diary_flag
        }
    }
}
I don't know if that answers your question or is particularly helpful - modding takes some getting used to when you're just starting out. The EU4 wiki is a pretty good place to read up on how the scripting language works, but feel free to post here if you have any other questions.
 
  • 2
Reactions:
What I was looking to achieve was to add a permanent bonus on every tile that had a blocker (removed or not) to one of the 5 ressources according to the blocker's difficulty

The quickest (but not necessarily cleanest) way to do this is probably just to create an event that is fired by on_game_start in 00_on_actions. It might look something like this:

Code:
event = {
    id = blockermod.1
    hide_window = yes

    fire_only_once = yes
    is_triggered_only = yes

    every_planet = {
        every_tile = {
            limit = {
                has_blocker = yes
            }
            if = {
                limit = {
                    has_blocker = tb_noxious_swamp
                }
                clear_deposits = yes
                add_deposit = d_rich_society_deposit
            }
            if = {
                limit = {
                    has_blocker = tb_volcano
                }
                clear_deposits = yes
                add_deposit = d_vast_mineral_deposit
            }
            if = {
                [etc etc etc...]
            }
        }
    }
}
 
Right, my bad. It's not 00_anomaly_events, but anomaly_events_1 through 6. You can create anomaly_events_7.txt or anomaly_events_MyMod.txt or whatever you want.