Open main menu

System modding

Version

Outliner top.png
Please help with verifying or updating older sections of this article. At least some were last verified for version 2.6.

This article is for the PC version of Stellaris only.

This guide is for adding and modifying Solar Systems to the game.

Contents

Game Map and System CreationEdit

Stellaris appears to create the game map first using the \map files to create coordinates for the stars on the galaxy map, and then use the \star_classes file to pick what star class is at each coordinate, and then finalize the system with additional contents (planets, moons, asteroid belts) from the \system initializer files and \planet_classes files.

Star classesEdit

Star classes can be found in common/star_classes. If you want to create one from scratch, create a new file and place it in that folder.

Note that "stars" and "star classes" are two different things: individual stars are considered the same as planets in the game code, and are found in common/planet_classes, while star classes refer to the classification of a solar system as a whole and will determine lighting, the system's icon in the galaxy map, and number of individual stars in a solar system. Information about modding individual stars can be found here.

Adding new star classesEdit

Making a new star class is easy. Here's an example of a binary system can be found in 00_star_classes:

sc_binary_1 = { # X-ray Binary Star System: Blue star around a Pulsar
    class             = a_star
    icon              = e_binary_star
    planet            = {
        key = pc_a_star
        class = a_star
    }
    planet            = {
        key = pc_pulsar
        class = pulsar
    }
    spawn_odds         = 5
    num_planets     = { min = 4 max = 10 }

    pc_desert       = { spawn_odds = 0 }
    pc_tropical     = { spawn_odds = 0 }
    pc_arid         = { spawn_odds = 0 }
    pc_continental  = { spawn_odds = 0 }
    pc_ocean        = { spawn_odds = 0 }
    pc_tundra       = { spawn_odds = 0 }
    pc_arctic       = { spawn_odds = 0 }
    pc_gaia         = { spawn_odds = 0 }
    pc_alpine       = { spawn_odds = 0 }
    pc_savannah     = { spawn_odds = 0 }

    is_environmental_hazard = yes
    modifier = { ship_shield_reduction = 1.0 }
}
  • "sc_binary_1" is the name of the star class used by the code. To assign the name the player will see, see localisation modding.
  • "class" is used to determine the system's lighting. You can use an existing one or create your own via gfx modding.
  • "icon" is the icon used by this system type in the galaxy view. By default it'll search for one that matches the star name ("binary_1_star" in this case) in the gfx/map/star_classes folder, but using "icon" lets you overwrite this with whatever icon you want.
  • "planet" is the type of star used by this star class by default. If it's a unary system with just one star, you don't need to write "class" again.
  • "spawn_odds" is exactly what it sounds like: the likelihood that this star class will spawn if it's used in a random list such as rl_standard_stars. If you don't plan to put it in a list, you can use any number or leave it out entirely.
  • "num_planets" is the number of planets that can be found in these systems. The number of planets in the solar system initializer will overwrite this by default, but if a random range is used there it'll use the number from here.
  • The planets' spawn odds are for if you want to alter the likelihood that certain planet classes will spawn in these systems. Neutron Stars, for example, have the values set to 0 by default since these systems won't he hospitable for life forms.
  • "is_environmental_hazard" marks the system as a hazard, obviously. The "modifier" applies a buff or debuff to ships and stations in the system.

Vanilla star classesEdit

For reference, the existing star classes are the following:

Icon Class Star type Environmental effects
  sc_b Class B Star
  sc_a Class A Star
  sc_f Class F Star
  sc_g Class G Star
  sc_k Class K Star
  sc_m Class M Star
  sc_m_giant Class M Red Giant
  sc_t Class T Brown Dwarf
  sc_black_hole Black Hole   +50% Disengagement Chance Reduction
  +50% Emergency FTL Jump Cooldown
  sc_neutron_star Neutron Star   +50% Sublight Speed Reduction
  sc_pulsar Pulsar   +100% Shield Nullification
  sc_binary_1 Binary Stars (A, Pulsar)   +100% Shield Nullification
  sc_binary_2 Binary Stars (B, Neutron Star)   +50% Sublight Speed Reduction
  sc_binary_3 Binary Stars (M Giant, B)
  sc_binary_4 Binary Stars (M Giant, F)
  sc_binary_5 Binary Stars (B, B)
  sc_binary_6 Binary Stars (M, G)
  sc_binary_7 Binary Stars (K, F)
  sc_binary_8 Binary Stars (G, F)
  sc_binary_9 Binary Stars (A, F)
  sc_binary_10 Binary Stars (A, T)
  sc_trinary_1 Trinary Stars (G, M, K)
  sc_trinary_2 Trinary Stars (B, A, F)
  sc_trinary_3 Trinary Stars (K, F, G)
  sc_trinary_4 Trinary Stars (B, K, T)

Solar system initializersEdit

Solar systems are found in common/solar_system_initializers. If you want to create one from scratch, create a new file and place it in that folder.

For additional information, see example.txt inside the folder.

Unary SystemsEdit

A unary system consists of just one star and a handful of planets and moons. These are the most common types of systems in Stellaris, and we'll start our tutorial by making one.

@base_moon_distance = 10

my_system_initializer = {
    name = "My System"
    class = "rl_standard_stars"

    asteroid_belt = {
        type = rocky_asteroid_belt
        radius = 70
    }

    planet = {
        class = star
        size = { min = 25 max = 30 }
        orbit_distance = 0
        orbit_angle = 1
    }

    change_orbit = 10

    planet = {
        class = pc_arid
        orbit_distance = 30
        orbit_angle = { min = 90 max = 270 }

        init_effect = {
            prevent_anomaly = yes
            generate_primitives_on_planet = yes
        }

        change_orbit = @base_moon_distance

        moon = {
            count = { min = 0 max = 1 }
            class = pc_molten
            orbit_distance = 5
            orbit_angle = { min = 90 max = 270 }
        }
    }

    change_orbit = 30

    planet = {
        count = { min = 1 max = 4 }
        class = pc_asteroid
        orbit_distance = 0
        orbit_angle = { min = 90 max = 270 }
    }

    planet = {
        count = { min = 3 max = 6 }
        orbit_distance = 20
        orbit_angle = { min = 90 max = 270 }

        change_orbit = @base_moon_distance

        moon = {
            count = { min = 0 max = 1 }
            orbit_distance = 5
            orbit_angle = { min = 90 max = 270 }
        }
    }

    neighbor_system = {
        trigger = { num_guaranteed_colonies >= 1 }
        distance = { min = 10 max = @distance }	
        initializer = "sol_neighbor_t1_first_colony"
    }
}

As before, let's go over each element one by one.

@base_moon_distance = 10

my_system_initializer = {
    name = "My System"
    class = "rl_standard_stars"

    asteroid_belt = {
        type = rocky_asteroid_belt
        radius = 70
    }
  • "@base_moon_distance" is a variable that can be set in each solar system initializer file. It's not strictly needed, but can be useful if you want to play around with moon orbit distances en masse rather than one at a time. All vanilla solar systems use 10 by default.
  • "my_system_initializer" is, again, the name the game code uses to identify this system. No need for localisation this time; the name the player will see is right there below it (in this case, "My System").
  • "class" is, of course, the star class. You can use a specific class such as sc_b, or a random list such as rl_standard_stars, which chooses a random one based on the spawn_odds in each star's code.
  • "asteroid_belt" adds an asteroid belt at a certain distance from the center of the system -- not necessarily from the sun! We'll get to that later. "type" refers to either a rocky or icy asteroid belt, plus any others that one might mod into the game.

Now for the system's sun. Note that the star is, as I mentioned above, considered a planet by the game engine.

    planet = {
        class = star
        size = { min = 25 max = 30 }
        orbit_distance = 0
        orbit_angle = 1
    }
  • "class", in the context of a planet refers to the planet class. Using "class = star" will make it the star class that matches the star type, so if we'd used sc_b above, the star would be pc_b_star -- a Class B Star. You can use pc_b_star anyway if you want, but that can cause complications with star lighting and, in a binary/trinary system, planet naming. More on that below. Anyway, just using "class = star" for the stars is recommended unless you have a good reason not to.
  • "size" is the size of the planet. This used to refer to the number of planet tiles, but since tiles are obsolete in general and useless on stars anyway, it just makes the star appear bigger or smaller. A size range of 20-35 is recommended for stars, since smaller than that looks silly and larger can swallow up ships flying overhead.
  • "orbit_distance" is the distance from the previous element, or if no such element exists, the system's center. For the lone star in a system, you naturally want this to be 0.
  • "orbit_angle" is the orbital angle from the previous planet, so if the previous had an angle of 30, using "orbit_angle = 20" would give it an overall angle of 50. Again, for the central star, this doesn't matter so you can use any old number. Most vanilla stars use 1 for some reason, so that's what I did here.

Now that the star is done, let's move on to the first planet.

    change_orbit = 10

    planet = {
        class = pc_arid
        orbit_distance = 30
        orbit_angle = { min = 90 max = 270 }

        init_effect = {
            prevent_anomaly = yes
            generate_primitives_on_planet = yes
        }

  • "change_orbit" increases the spacing between planets (in the system scope), or between a planet and its first moon (in the planet scope).
  • "class = pc_arid", so it will be an Arid World.
  • "orbit_distance = 30" adds 30 units of space between the planet and the last element (in this case, "change_orbit = 10", so its total distance from the sun is 40 units).
  • "orbit_angle = { min = 90 max = 270 )" is pretty straightforward: a random angle, within ninety degrees of the previous element.
  • "init_effect" allows you to apply effects and scripted effects to the planet upon system generation. It can also be used in the system scope if you want to apply an effect to the system as a whole instead of just one planet.
    • "prevent_anomaly" is an effect that disables anomalies from appearing on this planet.
    • "generate_primitives_on_planet" creates a pre-FTL species on this planet.

Now for a moon.

        change_orbit = @base_moon_distance

        moon = {
            count = { min = 0 max = 1 }
            class = pc_molten
            orbit_distance = 5
            orbit_angle = { min = 90 max = 270 }
        }
    }
  • "change_orbit = @base_moon_distance" here adds 10 units of distance between the planet and its moon as indicated in the @ variable.
  • "count = { min = 0 max = 1 }" to randomize the number of moons between 0 and 1. You can go as high or as low as you want with this, though usually in vanilla you won't find more than 3 moons unless the planet is a gas giant.
  • "class = pc_molten" (for a Molten World).
  • "orbit_distance = 5" (for a total of 15, including the "change_orbit" above).
  • "orbit_angle = { min = 90 max = 270 }", for the same randomized orbit angles as used in the planet itself.
    change_orbit = 30

    planet = {
        count = { min = 1 max = 4 }
        class = pc_asteroid
        orbit_distance = 0
        orbit_angle = { min = 90 max = 270 }
    }

Time to fill out the asteroid belt. We use "@change_orbit" again, this time keeping a close eye on the number used so that the total number of space used matches the 70 defined in the asteroid belt at the top of the file. Now we add the asteroids, making sure that "orbit_distance = 0" for all of them. We want them inside the asteroid belt, after all! "orbit_angle" is a little tricky here: since the asteroids are all in the same orbit, it's possible that they might clip together. You can get away from that by directly choosing their specific orbit angles.

If your asteroid belt is icy rather than rocky, use "pc_ice_asteroid" instead of "pc_asteroid".

    planet = {
        count = { min = 3 max = 6 }
        orbit_distance = 20
        orbit_angle = { min = 90 max = 270 }

        change_orbit = @base_moon_distance

        moon = {
            count = { min = 0 max = 1 }
            orbit_distance = 5
            orbit_angle = { min = 90 max = 270 }
        }
    }

More planets! We'll leave "class = " out for these ones, allowing them to spawn as whatever the game engine wants them to be (based on the criteria spelled out in common/star_classes). The number of planets is also randomized between 3 and 6, each of which has 0 to 1 moons.

    neighbor_system = {
        trigger = {
            num_guaranteed_colonies >= 1
        }
        distance = { min = 10 max = @distance }	
        initializer = "sol_neighbor_t1_first_colony"
    }
}
  • "neighbor_system" tells the game to spawn another, specific system within a certain distance of this system, and under what criteria. Pretty self-explanatory.

Binary and Trinary SystemsEdit

Some star systems have two or three suns, respectively. Such systems can be pretty complex in real life (just ask Mintaka!) but generally there are two types of binary/trinary systems, classified as "P-Type" and "S-Type".

P-TypeEdit

P-Type (or "circumbinary") systems have planets that orbit the barycenter of both (or all three) stars simultaneously. Sirius is an example of this kind of system, as is Tatooine in the Star Wars universe.

P-Types are the easiest to make in Stellaris. Instead of a single star with "orbit_distance = 0", do the following:

    planet = {
        class = star
        size = { min = 25 max = 30 }
        orbit_distance = 25
        orbit_angle = { min = 90 max = 270 }
    }
    planet = {
        class = star
        size = { min = 20 max = 25 }
        orbit_distance = 10
        orbit_angle = 180
    }

Then just add your planets as normal, change the star class to rl_binary_stars or rl_trinary_stars (or a specific class of either), and you're good to go!

  • If it's a trinary instead of a binary, just add a third star in the same manner, and change the last two to have "orbit_angle = 120" instead of 180.
  • Using "class = star" for both/all three stars will assign their class in accordance with the type of binary/trinary system: with "sc_binary_1", for instance, the first star will be A-class, and the second will be a Pulsar.
  • The orbit distances and star sizes are entirely up to you; the spacing and sizes above just look the nicest in my opinion. Feel free to experiment!

S-TypeEdit

In S-Type systems, each star has its own system of planets. Think of them as two or three unary systems that are close enough together that you can travel between them without needing a hyperdrive. Alpha Centauri is an example of such a system, as is Vulcan in the Star Trek universe.

To recap, a unary system with one sun has basically this structure:

    planet = {
        class = star
        size = { min = 25 max = 30 }
        orbit_distance = 0
        orbit_angle = 1
    }

    planet = {
        count = { min = 3 max = 6 }
        orbit_distance = 20
        orbit_angle = { min = 90 max = 270 }

        change_orbit = @base_moon_distance

        moon = {
            count = { min = 0 max = 1 }
            orbit_distance = 5
            orbit_angle = { min = 90 max = 270 }
        }
    }

The structure of an S-type star and its planets looks more like this:

    planet = {
        class = star
        size = { min = 25 max = 30 }
        orbit_distance = 0
        orbit_angle = 1
        satellite_naming_policy = upper_case_roman_numerals

        planet = {
            count = { min = 3 max = 6 }
            orbit_distance = 20
            orbit_angle = { min = 90 max = 270 }
            satellite_naming_policy = lower_case_latin_letters

            change_orbit = @base_moon_distance

            moon = {
                count = { min = 0 max = 1 }
                orbit_distance = 5
                orbit_angle = { min = 90 max = 270 }
            }
        }
    }

See the differences?

  • In a unary system, the planets are all defined in the system scope. In an S-type binary or trinary system, the planets are defined in their specific star's scope. This ensures that they will have the correct orbit lines and names.
  • "satellite_naming_policy" indicates how this star's planets (or this planet's moons) will be named. A star should use "upper_case_roman_numerals" for its planets; planets should use "lower_case_latin_letters" for their moons.

A full S-type trinary system would look like this:

    planet = {
        class = star
        size = { min = 30 max = 35 }
        orbit_distance = 0
        orbit_angle = 1
        satellite_naming_policy = upper_case_roman_numerals

        planet = {
            count = { min = 3 max = 6 }
            orbit_distance = 20
            orbit_angle = { min = 90 max = 270 }
            satellite_naming_policy = lower_case_latin_letters

            change_orbit = @base_moon_distance

            moon = {
                count = { min = 0 max = 1 }
                orbit_distance = 5
                orbit_angle = { min = 90 max = 270 }
            }
        }
    }

    planet = {
        class = star
        size = { min = 25 max = 30 }
        orbit_distance = 230
        orbit_angle = { min = 90 max = 270 }
        satellite_naming_policy = upper_case_roman_numerals

        planet = {
            count = { min = 3 max = 5 }
            orbit_distance = 20
            orbit_angle = { min = 90 max = 270 }
            satellite_naming_policy = lower_case_latin_letters

            change_orbit = @base_moon_distance

            moon = {
                count = { min = 0 max = 1 }
                orbit_distance = 5
                orbit_angle = { min = 90 max = 270 }
            }
        }
    }

    planet = {
        class = star
        size = { min = 20 max = 25 }
        orbit_distance = 0
        orbit_angle = { min = 90 max = 270 }
        satellite_naming_policy = upper_case_roman_numerals

        planet = {
            count = { min = 2 max = 4 }
            orbit_distance = 20
            orbit_angle = { min = 90 max = 270 }
            satellite_naming_policy = lower_case_latin_letters

            change_orbit = @base_moon_distance

            moon = {
                count = { min = 0 max = 1 }
                orbit_distance = 5
                orbit_angle = { min = 90 max = 270 }
            }
        }
    }
  • The second star, B, orbits 230 units away from the first, A. This is because we don't want the two systems to overlap. A has up to six planets, each orbiting at a distance of 20, which gives us a maximum system width of 120. B has up to five, giving it a maximum width of 100. 120 + 100 = 220, so we use 230 to give them a little extra space.
  • The third star, C, orbits at the same distance from A as B but at a different angle. This isn't a hard requirement, you can space it out further if you want, but all the vanilla systems do it that way and it just looks nicer in my opinion. We don't want systems to be too big, or it'll take forever to cross them at sublight speeds.

UsageEdit

One thing I haven't gone over is usage -- how the game knows which system to generate. There are a few ways to do this, applied in the system scope.

  • "usage = misc_system_init" tells the game to randomly generate this system somewhere in the galaxy, based on the value entered for "usage_odds". You can also use modifiers for these if you want the system to spawn (or not) in a certain area of the galaxy. There's also "max_instances = " to ensure that you don't get more than X instances of these systems. For example:
usage = misc_system_init
usage_odds = {
    base = 2000000
    modifier = {
        factor = 0
        is_bottleneck_system = yes
    }
}
max_instances = 1
  • "usage = empire_init" tells the game that this system is an empire homeworld, which either the player or the AI can end up with if they choose "Random" in the empire creation screen. If you use this, make sure the system has a planet with the following:
planet = {
    home_planet = yes
    init_effect = {
        generate_empire_home_planet = yes			
        prevent_anomaly = yes
    }
}
  • "usage = custom_empire" is mostly the same as above, except it tells the game that this system is a prescripted empire homeworld which can be chosen in the empire creation screen, like Sol and Deneb. Make sure to give the system a name and description via localisation.
  • If no usage value is used, or if "usage_odds = 0", the system will never spawn in the galaxy unless specifically called to by an event or another external means.

General AdviceEdit

  • Remember when I said that using "class = pc_b_star" is just as good as "class = star" most of the time? That's true in unary systems, but it can lead to problems with planet and star names in binary or trinary systems. If you want to hard-code a specific star class regardless of the system class, use "class = star" and then add "init_effect = { change_pc = pc_b_star }" underneath.
  • The same as above goes for giving planets specific names. If you name the third planet in the system "Joe", the fourth planet will use "StarName III" in its place. You can get around this by using "init_effect = { set_name = "Joe" }" instead.
  • All planets, ships, etc in a system will always be lit from the system's center regardless of the location of the star(s). The devs are working on a fix for this but until then we just have to live with it.
  • Asteroids and Ringworld sections don't have visible orbital lines by default, but if they're placed in the star's scope (such as in an S-type binary system) they will have lines, which looks kind of messy. Make sure you place them in the system scope whenever possible. And speaking of Ringworlds, their individual segments always face the center of the system regardless of which star they orbit.
Empire EmpireEthicsGovernments • Civics • OriginsMandatesAgendasTraditions • Ascension PerksEdictsPoliciesRelicsTechnologiesCustom Empires
Pops JobsFactions
Leaders LeadersLeader Traits
Species SpeciesSpecies Traits
Planets PlanetsPlanetary Feature • Orbital DepositBuildings • DistrictsPlanetary Decisions
Systems SystemsStarbasesMegastructuresBypassesMap
Fleets FleetsShips • Components
Land Warfare ArmiesBombardment Stance
Diplomacy Diplomacy • Federations • Galactic CommunityOpinion ModifiersCasus Belli • War Goals
Events EventsAnomaliesSpecial projectsArchaeological Sites
Gameplay GameplayDefinesResources • Economy
Dynamic modding EffectsConditionsScopesModifiersVariablesAI
Media/localisation Maya exporterGraphicsPortraitsFlagsEvent picturesInterfaceIconsMusicLocalisation
Other Console commandsSave-game editingSteam Workshop