Page 1 of 2
Is it possible to make ores grow?
Posted: Mon May 15, 2017 12:37 am
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#)
Re: Is it possible to make ores grow?
Posted: Mon May 15, 2017 8:57 am
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.
Re: Is it possible to make ores grow?
Posted: Mon May 15, 2017 12:47 pm
by Zillo7
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:
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)
Re: Is it possible to make ores grow?
Posted: Mon May 15, 2017 2:44 pm
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
.
Re: Is it possible to make ores grow?
Posted: Tue May 16, 2017 3:15 am
by Rseding91
You could just copy what the uranium ore does to glow.
Re: Is it possible to make ores grow?
Posted: Tue May 16, 2017 4:46 am
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
Re: Is it possible to make ores grow?
Posted: Tue May 16, 2017 6:28 am
by Rseding91
Glow.. grow.. only 1 letter difference
Re: Is it possible to make ores grow?
Posted: Tue May 16, 2017 7:45 am
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?
Re: Is it possible to make ores grow?
Posted: Tue May 16, 2017 8:18 am
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.
Re: Is it possible to make ores grow?
Posted: Tue May 16, 2017 8:56 am
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.
Re: Is it possible to make ores grow?
Posted: Fri May 19, 2017 5:28 pm
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?
Re: Is it possible to make ores grow?
Posted: Sat May 20, 2017 11:10 pm
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.
uwa
Posted: Sun May 21, 2017 1:57 am
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.
Re: uwa
Posted: Sun May 21, 2017 1:01 pm
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.
Re: Is it possible to make ores grow?
Posted: Sun May 21, 2017 9:12 pm
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!
Re: Is it possible to make ores grow?
Posted: Sun May 21, 2017 9:48 pm
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)
Re: Is it possible to make ores grow?
Posted: Mon May 22, 2017 1:50 am
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?
Re: Is it possible to make ores grow?
Posted: Mon May 22, 2017 8:04 am
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.
Re: Is it possible to make ores grow?
Posted: Mon May 22, 2017 12:17 pm
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?
Re: Is it possible to make ores grow?
Posted: Mon May 22, 2017 2:03 pm
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"