Is it possible to make ores grow?
Is it possible to make ores grow?
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#)
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Is it possible to make ores grow?
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.
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.
Re: Is it possible to make ores grow?
How did you know I was trying to make Tiberium?
I think I've got the scanning parts done, but I have no idea if this would work correctly:
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)
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Is it possible to make ores grow?
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.
i is then the list index number, and entity is a pointer (usable directly) to entities.
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
Re: Is it possible to make ores grow?
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.
Re: Is it possible to make ores grow?
@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
Changing local variables between ticks will lead to desyncs in MP
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
Re: Is it possible to make ores grow?
Glow.. grow.. only 1 letter difference
If you want to get ahold of me I'm almost always on Discord.
Re: Is it possible to make ores grow?
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 wrote:Changing local variables between ticks will lead to desyncs in MP
Re: Is it possible to make ores grow?
Factorio mods have no concept of server/client every client including the server needs to do the exact same thingZillo7 wrote: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 wrote:Changing local variables between ticks will lead to desyncs in MP
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.
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Is it possible to make ores grow?
Simple solution:
change
to
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.
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
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]
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.
Re: Is it possible to make ores grow?
I think I've got it to place new ore next to the existing ore, is this correct?:
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?
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
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Is it possible to make ores grow?
All I can really sugest is that you try it and see what happens.
Beyond my knowledge unfortunately.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?
uwa
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.
Unbridled growth isn't wise since any untapped field could expand exponentially across an entire map.
Re: uwa
It should grow until it's completely harvested. If left alone it should spread over the whole map. That's kind of the point.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.
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.
Re: Is it possible to make ores grow?
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.
I'd also be interested to learn what you want the growing ore to be used for!
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)
Re: Is it possible to make ores grow?
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.
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)
Re: Is it possible to make ores grow?
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]Kynaro wrote:I'd also be interested to learn what you want the growing ore to be used for!
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?
- bobingabout
- Smart Inserter
- Posts: 7352
- Joined: Fri May 09, 2014 1:01 pm
- Contact:
Re: Is it possible to make ores grow?
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.
ALL run time scripts need to be in that file. All declared global variables need to be in that file.
Re: Is it possible to make ores grow?
That worked, thanks!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.
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 }}
Re: Is it possible to make ores grow?
Great! I like this.I'm thinking it'll be something like: Tiberium Ore -> Liquid Tiberium -> [Other ores/coal/stone/crude oil/water]
Try lower-case p instead of upper-case P? "ore.position"How do I get the position of the ore piece that I'm working on?