Adding planets by other mods.
It is possible in warptorio for other mods to add their own planets to the generation cycle.
Feedback on discord or the discussion would be appreciated.
Please refer to main mod page: https://mods.factorio.com/mod/warptorio2
Planet API Remote Commands
The following functions can be accessed using remote.call("warptorio","function_name",variable_x,variable_y,...)
"warp"
Input: string planet_name,
Returns: nil
Desc: Forcibly warps the platform to the specified planet.
This is useful for testing and debugging purposes.
"getplanets"
Input: nil
Returns: warptorio.Planets
This is a copy of the entire planets table at the time of being called.
"getplanet"
Input: string name,
Returns: warptorio.Planets[ name ]
This is a copy of a specific planet
"getresources"
Input: nil
Returns: A number-keyed table of all resource prototype names.
Useful for detecting mod resources.
"getglobal"
Input: string table_key,
Returns: A variable from the warptoro global table.
If there is a better way to do this please let me know.
"registerplanet"
Input: table planet_table,
Returns: nil
The use of this function is described below.
"generateplanet"
Input: string planet_name,
Returns: map_gen_settings generation of the desired planet.
This is useful for testing and debugging purposes.
"tiledefault"
Input: string tile_name,
Returns: nil
This sets a specific tile's noise probability expression to -1 million by default when spawning a new planet, including uncharted, ensuring it will never spawn unless otherwise required.
Example of this seen with the swamp planet.
Planet Table Registration
Remotes only work in on_init and on_load events, so all registrations must be made there.
First Planet
local swamp={
key="swamp", -- the internal name of the planet
name="A Swamp Planet", -- the "nice name" of the planet
desc="A Planet Flavour Text Descriptor", -- Flavourtext
zone=99, -- The warpzone at which this planet starts to appear
rng=12, -- The weighted chance for this planet to appear compared against all other eligible planets
}
local function RegisterPlanets()
remote.call("warptorio","registerplanet",swamp) -- register our planet with Warptorio
remote.call("warptorio","tiledefault","deepwater-green",false) -- Force swamp water to never spawn (see data.lua)
remote.call("warptorio","tiledefault","water-green",false) -- Force swamp water to never spawn (see data.lua)
end
script.on_init(RegisterPlanets)
script.on_load(RegisterPlanets)
Learn by example
There are a tonne of options and settings when it comes to map generation, and it can be quite difficult to understand.
In this example, we have registered our first planet, but it is the equivalent of uncharted.
Let's have a look at the full planet table and how each component works, then we can make our planet a bit more unique.
remote.call({
key="normal", name="A Normal Planet", zone=0, rng=PlanetRNG("normal"),
desc="This world reminds you of home.",
modifiers={{"nauvis"}},
gen=nil, -- The base planet map_gen_settings table
tick_speed=nil, -- =(60*60*minutes) -- runs the tick calls every X ticks
rest = false, -- flag
waterless = false, -- flag
required_controls=nil, -- {"iron-ore"} -- Mod compatability: This planet REQUIRES a certain autoplace_control.
required_tiles=nil, -- {"grass-1"} -- Mod compatability: This planet REQUIRES a certain autoplace_setting.tile *NOT WORKING*
required_ents=nil, -- {"enemy-base"} -- Mod compatability: This planet REQUIRES a certain autoplace_setting.entity *NOT WORKING*
required_decor=nil, -- {"shrub-x"} -- Mod compatability: This planet REQUIRES a certain autoplace_setting.decorative *NOT WORKING*
-- Call tables are used for remote interfaces: { "remote_interface","remote_name" }
fgen_call=nil, -- Final function calls on map_gen_settings, behaving similar to a modifier function but planet specific.
spawn_call=nil, -- Function calls after surface is created.
tick_call=nil, -- Function calls per tick *NOT WORKING*
chunk_call=nil, -- Functions called when a chunk is generated on the planet *NOT WORKING*
warpout_call=nil, -- Function called upon warpout of this planet event{oldsurface=surface,oldplanet=planet_table,newsurface=surface,newplanet=planet_table}
postwarpout_call=nil, -- Function called upon warpout of this planet event{oldsurface=surface,oldplanet=planet_table,newsurface=surface,newplanet=planet_table}
fgen=nil, -- function(map_gen_settings) end, -- planet modify function (warptorio internal)
spawn=nil, -- function(surface_object, table_of_modifier_return_values) -- planet spawn function (warptorio internal)
tick=nil, -- function(surface_object, event_variable) -- planet tick function (warptorio internal)
chunk=nil, -- function(surface_object, event_variable) -- planet on_chunk_generated function (warptorio internal)
warpout=nil, -- function(oldsurface,oldplanet,newsurface,newplanet) -- planet on warpout (warptorio internal)
postwarpout=nil, -- function(oldsurface,oldplanet,newsurface,newplanet) -- planet on warpout (warptorio internal)
})
Table components described in detail:
key : String
The internal planet name (see "getplanet")
name : String
The "nice name" of the planet, which is displayed after each warp.
Is not currently set up to use locale.
desc : String
The flavour text which describes the planet. This is displayed after each warp.
Is not currently set up to use locale.
zone : Integer
The warpzone # at which the planet will enter the planet chance table
rng : Integer
The weighted probability of the planet occurring compared against all other eligible planets in the chance table.
Normal and Uncharted planets are 12, a resource is missing is 17 and the resource specific planets are 4 for reference (by default).
With the RNG value - there is no explicit range on it and it is not a percentage.
weighted probability is not a simple thing to calculate because of how the eligible planets can change.
example: A=10, B=9, C=8, D=7.
this adds up to 10+9+8+7=34, giving each planet a chance relative to this amount.
for A at 10, this means a 29% chance to appear, D is 20% chance.
This gets more complicated as you add more planets to the list with different rng values.
So in other words, the "range" of values is more about how much relative probability you want a planet to have because you cannot explicitly set a percentage chance.
An example of why this is impossible: if planet A was at 10% chance, and only planet A was in the list, it'd actually have 100% chance.
if planet A was at 10% and planet B was at 5%, planet A would actually have a 66% chance to appear (roughly) and planet B would actually be about 33% (half of planet A's chance).
You can see how this would get confusing very quickly, and a simple weighting value would make a lot more sense.
another way to look at the weighting value is thusly: out of every (sum of total rng values) planets, your specific planet will appear (planet.rng) times.
in the earlier example a/b/c/d, out of every 34 planets, A appears 10 times, B appears 9 times, C appears 8 times etc.
you can see how this literal value ends up making a lot more sense
gen : Table
This is the base map_gen_settings applied to the map generation table after being given a "blank" map_gen_settings table by warptorio.
More on this below.
tick_speed : Integer
Determines how often tick_call should be called, in ticks.
NOT WORKING
rest : Boolean
Flag determining if the planet is a rest planet or not (no resources etc).
This is used to ensure the platform does not land on 2 rest planets in a row.
nowater : Boolean
Flag determining if the planet has water or not.
This is used to ensure the platform does not land on 2 water-less planets in a row.
required_controls, required_tiles, required_ents, required_decor
This is a table of {"prototype-1","prototype-2"} of a specific type that is required for the planet to spawn.
This helps to handle mod conflicts.
Currently only required_controls is working.
The Planet Call Functions
fgen_call, spawn_call, tick_call, chunk_call, warpout_call, postwarpout_call
These all take the same value which is a table with [1]="remote_interface_name", [2]="remote_command_name".
You will want to register the actual functions in your mod using remote.add_interface("remote_interface_name", { ["remote_command_name"]=function(map_gen_settings) return map_gen_settings end })
This remote is then called for each event, with the event table passed or other variables.
fgen means "function map_gen_settings"
fgen_call : Event
Params: map_gen_settings : Table = the map generation table (so far), chart : Boolean = if charting information should be displayed
Return: the modified map_gen_settings table.
See swamp planet for an example how to use this.
spawn_call : Event
Params: f : Surface = the new planet surface, map_gen_settings : Table = the map generation table (final), chart : Boolean = if charting information should be displayed
Return: nil
This is called immediately after the new surface is created
tick_call : Event
Params: f : Surface = the planet surface, event : defines.events.on_tick,
Return: nil
Exactly what it says on the tin, but only while this planet is the active one.
NOT WORKING
chunk_call : Event
Params: f : Surface = the planet surface, event : defines.events.on_chunk_generated,
Return: nil
Exactly what it says on the tin, but only while this planet is the active one.
warpout_call : Event
Params: f : Surface = the new planet surface, w : Table = Your planet table, c = the old planet surface, pnt = the old planet table
Return: nil
This is called immediately after your planets surface is created, but before any platform entities are transported to the new planet
postwarpout_call : Event
Params: f : Surface = the new planet surface, w : Table = Your planet table
Return: nil
This is called after warpout procedure has finished
Configuring map_gen_settings with Warptorio
There is one final variable to mention.
Please refer to control_planets.lua for a list of modifiers currently in the mod.
This will explain mostly how you need to set up your modifier table.
https://github.com/PyroFire232/warptorio2/blob/master/control_planets.lua
modifiers : Table
This entire api is aimed towards simplifying the setup of custom planets in a dynamic and compatible way.
To do this, the map_gen_settings of all maps function as a whitelist.
It starts by generating a blank table, and applying each planet modifier sequentially, effectively "building up" a map_gen_settings from various components, which i call modifiers.
An example:
modifiers={
{"nauvis",{
tiles={"grass","water","water%-green"},
ents={"tree"},
}},
{"resource_set_all",999},
{"biters",{frequency=100,size=0.1,richness=0.1}},
A lot going on there, but let's start with the structure:
{ {"modifier_name", ANY_MODIFIER_ARGUMENTS}, {"next_modifier_name", ANY_MODIFIER_ARGUMENTS} }
The arguments of a specific modifier are quite varied, and i may document those at a later time.
But perhaps the most important thing to know when reviewing the list of modifiers in control_planets.lua in the base warptorio 2 mod is how most modifiers work using a search pattern.
Using this you can build up exlusions for different settings.
What this means is:
{"tile",{"grass",10}}, {"tile",{"grass%-1",100}},
The above will set all tiles containing the string "grass" in its name to 10, and then after than change all tiles containing the string "grass-1" in the name.
The percentage sign is there because "-" is a special character in lua pattern matching. See lua's docs on string:match()
Most planets typically start with the "nauvis" modifier.
This modifier will add all the standard components of map generation to the new map_gen_settings and it will appear to be a regular, unmodded "nauvis" surface.
Mods such as alien biomes are not included in this modifier.
For that you could use the "tile" or "tile_mod" which are the same, but run on a different filtered table.