Is it possible to make ores grow?

Place to post guides, observations, things related to modding that are not mods themselves.
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Is it possible to make ores grow?

Post by Zillo7 »

I would like to make a mod where there's a single ore type that expands over time. I think I've made the recipes that I want to use, but I don't know how to make the ores grow. I've briefly looked through the API, but I'm not sure how to find tiles that have an ore on them, or how to place individual ore chunks. Is this even possible if I come up with some kind of lua script? (I've never used lua before, but I've used C#)
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Is it possible to make ores grow?

Post by bobingabout »

Tiberium!!!

As far as I know there is no native mechanic to allow such a thing, however, the scripting interface is quite versatile, though can be quite processing power hungry.

The problems you'll face is that first, you need to find out if ore exists before you can make it grow, which will require some form a map scan. This is a VERY EXPENSIVE operation to perform, so you'll want to run it very sparingly, which means you're going to want to perform the operation only once on sector generation, and store any ores found in your global table.

You'll probably need to repeat this procedure, or at least account for the possibility of someone, or another script running a regenerate_entity script (This is often used to create ores on existing maps. it was used in 0.15 to spawn uranium for example)

You then would need to perform an on_tick operation to check each piece of ore in your database and either increase it's size, or generate a new piece in an adjacent tile. Don't forget to add the new entity to your table too.

for everybody's mercy, don't iterate the entire array of saved ore every tick, that would kill the game as much as scanning every tick! You have two main options for this, either scan the entire array once every few hundred ticks, which would actually generate quite a pronounced pause, or divide your array up via a formula, and perform the operation on a small rotating fraction every tick. Guess which option I recommend.

The formula based system would likely be to iterate through your array and perform a "if tick % 3600 == index % 3600 then" where index is the current element number in your array. (Is % the correct symbol for divide and use the remainder?) This example would spread your array over 3600 ticks, which is a minute long.


As for actually increasing the yield, I've never done that before so I can't suggest code examples off the top of my head. I don't know if you can even edit the quantity of an ore resource entity directly, but if you can't you can delete and recreate it.

You'll also need to ask every piece of ore you check if it still exists or not. If it doesn't, then you need to remove it from your list using table.remove(list, index number), the problem with doing this is that it will likely screw up the order of your grow list, skipping some entities, and repeating others before the next minute, causing some to grow out of turn. There's not a whole lot you can do about that.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Re: Is it possible to make ores grow?

Post by Zillo7 »

How did you know I was trying to make Tiberium? :shock:
I think I've got the scanning parts done, but I have no idea if this would work correctly:

Code: Select all

local oreList = { }
local oreListIndex = 0
local tickSkip = 60
local tick = 0
local maxOreAmount = 5000
local growthRate = 10
local world = game.player.surface


--initial chunk scan
script.on_event(defines.events.on_chunk_generated, function(event)
    local chunk = { x = event.area.left_top.x / 32, y = event.area.left_top.y / 32 }
    local entities = game.surfaces[1].find_entities_filtered{area = chunk, name= "uranium-ore"}
    for i=0,table.getn(entities),1
    do 
       oreList.insert(oreList, entities[i])
    end
end)

--periodic scan
script.on_event(defines.events.on_tick, function(event)
    --return until ticks accumulate
    tick = tick + 1
    if tick >= tickSkip
    then
      tick = 0
    else
      return
    end
    
    --increment ore list index to work on the next ore piece
    oreListIndex = oreListIndex + 1
    if oreListIndex > table.getn(oreList)
    then oreListIndex = 0
    end

    --increase ore amount
    local ore = oreList[oreListIndex]
    if ore.amount > 0 and ore.amount < maxOreAmount
    then ore.amount = ore.amount + growthRate
    end

    --add new ores to empty adjacent squares
    local orePosition = ore.Position
    local adjacentEntity = world.find_entity('ANYTHING', orePosition)--I don't know how to search for anything at this square

    if not adjacentEntity then
    --add new ore here
    end
end)
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Is it possible to make ores grow?

Post by bobingabout »

I can definitely see your C nature in this.

I'll admit now, although I might be a big name around here in the modding community, I don't do a whole lot of scripting.

You don't need to keep track of your own tick, the game does that already, I think it's stored under game.tick. And for your for loop, it's more common to use the pairs or ipairs system instead.

Code: Select all

for i, entity in ipairs(entities) do
i is then the list index number, and entity is a pointer (usable directly) to entities.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
Rseding91
Factorio Staff
Factorio Staff
Posts: 14616
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Is it possible to make ores grow?

Post by Rseding91 »

You could just copy what the uranium ore does to glow.
If you want to get ahold of me I'm almost always on Discord.
Nexela
Smart Inserter
Smart Inserter
Posts: 1828
Joined: Wed May 25, 2016 11:09 am
Contact:

Re: Is it possible to make ores grow?

Post by Nexela »

@rseding He wants the patches to grow , He might also want them to glow but :)

http://lua-api.factorio.com/latest/Global.html
http://lua-api.factorio.com/latest/Data-Lifecycle.html

I recommend reading those

Code: Select all

local oreList = { }
local oreListIndex = 0
local tickSkip = 60
local tick = 0
local maxOreAmount = 5000
local growthRate = 10
local world = game.player.surface
Changing local variables between ticks will lead to desyncs in MP
Rseding91
Factorio Staff
Factorio Staff
Posts: 14616
Joined: Wed Jun 11, 2014 5:23 am
Contact:

Re: Is it possible to make ores grow?

Post by Rseding91 »

Glow.. grow.. only 1 letter difference :D
If you want to get ahold of me I'm almost always on Discord.
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Re: Is it possible to make ores grow?

Post by Zillo7 »

Nexela wrote:Changing local variables between ticks will lead to desyncs in MP
So the local variables are synchronized over the network? I don't think I would need that; just the server player could run this script and the placed ores would be synchronized instead. How could I set a variable to not be synchronized?
Nexela
Smart Inserter
Smart Inserter
Posts: 1828
Joined: Wed May 25, 2016 11:09 am
Contact:

Re: Is it possible to make ores grow?

Post by Nexela »

Zillo7 wrote:
Nexela wrote:Changing local variables between ticks will lead to desyncs in MP
So the local variables are synchronized over the network? I don't think I would need that; just the server player could run this script and the placed ores would be synchronized instead. How could I set a variable to not be synchronized?
Factorio mods have no concept of server/client every client including the server needs to do the exact same thing


doing
local a = 1
a + 1
game.print(a)

will lead to desyncs because client1 will have a=32 and newly connecting clients will have a=1 and game.print will print 2 values which puts the game out of sync and boom.
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Is it possible to make ores grow?

Post by bobingabout »

Simple solution:
change

Code: Select all

local oreList = { }
local oreListIndex = 0
local tickSkip = 60
local tick = 0
local maxOreAmount = 5000
local growthRate = 10
local world = game.player.surface
to

Code: Select all

global = {}
global.oreList = { }
global.oreListIndex = 0
global.tickSkip = 60
global.tick = 0
global.maxOreAmount = 5000
global.growthRate = 10
global.world = game.surfaces[1]
Global isn't actually global, it is LOCAL to your mod, but shared globally over all clients. it is also saved in the save game.
This simple change will result in no desyncs.

note: game.player either doesn't exist anymore, or only exists in single player games, you iterate through game.players[] instead now. So I changed your surface line to access the first surface, which is always the main world.

Note: using local variables inside a function isn't a bad thing since it is created for a function, used, and discarded, and everyone who exists within that tick will create the same local, and perform the same calculations on it. it's these "global" locals (local to a file) that break things.


Factorio multiplayer is "Lockstep", every "step" is simulated exactly the same between all clients. This means the network traffic telling you what is going on is limited only to things the player does, like moving the character and mining and placing entitites.

As a result, desyncs usually occur when someone does something, like mining an entity, or placing one, or being hit by a train, because it's only then when another client might respond with "But there was no building there to mine!" or "But that train isn't at the player yet!", and then, and ONLY then will the game realise "Hold on a moment, not everyone is simulating the same thing!" and then it desyncs.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Re: Is it possible to make ores grow?

Post by Zillo7 »

I think I've got it to place new ore next to the existing ore, is this correct?:

Code: Select all

    --add new ores to empty adjacent squares
    local orePositions = {{ ore.Position.x + 1, ore.Position.y }, { ore.Position.x - 1, ore.Position.y }, 
{ ore.Position.x, ore.Position.y + 1 }, { ore.Position.x, ore.Position.y - 1 }}

    for i=0,4,1
    do 
       local adjacentEntity = world.find_entity('ANYTHING', orePositions[i])--I don't know how to search for anything at this square

       if not adjacentEntity then
       --add new ore here
       local newOre = world.create_entity{name = "uranium-ore", position = orePositions[i], amount = 5}
       oreList.insert(oreList, newOre)
       end
    end
Also when using lua_surface.find_entity, it requires me to provide an object type to search for. Is it possible to have it return anything that happens to be on that square?
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Is it possible to make ores grow?

Post by bobingabout »

All I can really sugest is that you try it and see what happens.
Zillo7 wrote:Also when using lua_surface.find_entity, it requires me to provide an object type to search for. Is it possible to have it return anything that happens to be on that square?
Beyond my knowledge unfortunately.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
Aeternus
Filter Inserter
Filter Inserter
Posts: 835
Joined: Wed Mar 29, 2017 2:10 am
Contact:

uwa

Post by Aeternus »

Question... do you want it to -grow- or -regrow-? IE do you want fields to expand beyond their initial spawned size, or simply, over time, refresh themselves? Or grow around an object, radiating outward to a max radius - similar to red-alert ore mines or C&C classic tiberium trees?
Unbridled growth isn't wise since any untapped field could expand exponentially across an entire map.
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Re: uwa

Post by Zillo7 »

Aeternus wrote:Question... do you want it to -grow- or -regrow-? IE do you want fields to expand beyond their initial spawned size, or simply, over time, refresh themselves? Or grow around an object, radiating outward to a max radius - similar to red-alert ore mines or C&C classic tiberium trees?
Unbridled growth isn't wise since any untapped field could expand exponentially across an entire map.
It should grow until it's completely harvested. If left alone it should spread over the whole map. That's kind of the point.

Also, I'm not sure where to put the global variable declarations. No matter which file I put them in, they're always null when I try to use them in the scanning functions.
Kynaro
Burner Inserter
Burner Inserter
Posts: 12
Joined: Thu May 18, 2017 2:48 pm
Contact:

Re: Is it possible to make ores grow?

Post by Kynaro »

I've found for global variables that you can do on_init, but when loading a game, it's different - so I used this code and it helped.

Code: Select all

function when_loaded_mods_changed(data)
	global.your_tiberium_list = game.surfaces[1].find_entities_filtered{name= "your_tiberium_entity_name_here"}
end
script.on_configuration_changed(when_loaded_mods_changed)
I'd also be interested to learn what you want the growing ore to be used for!
Nexela
Smart Inserter
Smart Inserter
Posts: 1828
Joined: Wed May 25, 2016 11:09 am
Contact:

Re: Is it possible to make ores grow?

Post by Nexela »

You declare your global variables inside events. Typicall on_init is used to "set up" the layout of your table.


on_configuration_changed should only be used to change the values saved in global (which stays saved with the map) if it needs it.

Code: Select all

script.on_init(function() 
global.oreList = {}
global.oreListIndex = 0
global.tick = 0
 end)
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Re: Is it possible to make ores grow?

Post by Zillo7 »

Kynaro wrote:I'd also be interested to learn what you want the growing ore to be used for!
I'm gonna use the growing ore in a new process where the end result is any of the other ores. I'm thinking it'll be something like: Tiberium Ore -> Liquid Tiberium -> [Other ores/coal/stone/crude oil/water]

I'm still getting the null reference error; it says: "attempt to index global 'script' (a nil value)". Is there an equivalent to using statements in C# that I've left out? I've put the code I've written in a file named: TiberiumScan.lua. Does it need to be named something else?
User avatar
bobingabout
Smart Inserter
Smart Inserter
Posts: 7352
Joined: Fri May 09, 2014 1:01 pm
Contact:

Re: Is it possible to make ores grow?

Post by bobingabout »

you are putting all this in the file control.lua, right?
ALL run time scripts need to be in that file. All declared global variables need to be in that file.
Creator of Bob's mods. Expanding your gameplay since version 0.9.8.
I also have a Patreon.
Zillo7
Inserter
Inserter
Posts: 22
Joined: Sun May 14, 2017 10:45 pm
Contact:

Re: Is it possible to make ores grow?

Post by Zillo7 »

bobingabout wrote:you are putting all this in the file control.lua, right?
ALL run time scripts need to be in that file. All declared global variables need to be in that file.
That worked, thanks!

After a little more trial and error, I got most of the script to run. However there's this line:

Code: Select all

local orePositions = {{ ore.Position.x + 1, ore.Position.y }, { ore.Position.x - 1, ore.Position.y }, { ore.Position.x, ore.Position.y + 1 }, { ore.Position.x, ore.Position.y - 1 }}
ore is a LuaEntity (the uranium ore piece that I've scanned for earlier), and the API says that LuaEntity inherits LuaControl which has a position field. The script fails at this line because it can't find that field. How do I get the position of the ore piece that I'm working on?
Kynaro
Burner Inserter
Burner Inserter
Posts: 12
Joined: Thu May 18, 2017 2:48 pm
Contact:

Re: Is it possible to make ores grow?

Post by Kynaro »

I'm thinking it'll be something like: Tiberium Ore -> Liquid Tiberium -> [Other ores/coal/stone/crude oil/water]
Great! I like this.
How do I get the position of the ore piece that I'm working on?
Try lower-case p instead of upper-case P? "ore.position"
Post Reply

Return to “Modding discussion”