Page 1 of 1

[HELP] Edit the data of only one entity

Posted: Thu Aug 04, 2016 1:47 am
by Chanz
Hi,

I'm new to modding Factorio and I've got a question about data (data.json) and control (control.lua).

As far I understand how it works its like this:
The data.json defines the class of an entity or changes (extends) an existing entity class.
The control.lua is the script that works on runtime.

Now my question:
Is it possible to change values like "max_speed" (defined in prototypes/entity/entities.lua) after an entity has been created?
As example I want to change only the max_speed of the locomotive the player is in.

Thanks for your help.

cya,
Chanz

Re: [HELP] Edit the data of only one entity

Posted: Thu Aug 04, 2016 7:56 am
by ShinyAfro
Its data.lua, probably a typo but i'd rather you getting called out then scratching your head for 30 minutes :P
atleast to my knowledge anyhow. The info.json and migration files should pretty much be the only jsons.
Control.lua are basically scripts, like if you place down a entity on a sand tile it turns it into something else, i used such a technique to turn sand and dirt into resources, i am yet to utilize them
anyhow, back to data.lua, yes, it is possible. Theres 3 ways of doing it, two of which are better for small changes and the last is good for total overhauls (like when you change everything including the wall of text that is the sprites)

First, for some context ill grab a random entity from the game and remove like 90% of its code to use as an example

Code: Select all

  {
    type = "assembling-machine",
    name = "assembling-machine-2",
    blah,blah,blah,
    max_health = 250,
    blah,blah,
    resistances =
    {
      {
        type = "fire",
        percent = 70
      }
    },
   blah,blah,blah
  },
First way, changing a value. data.raw["Type"]["Name"]["Property"] = new_value
So, if you wanted to change max health to 300 you would use data.raw["assembling-machine"]["assembling-machine-2"][max_health"] = 300
You can dig deeper, say you want to change filename - data.raw["Type"]["Name"]["Property"]["Subproperty"] = new_value
So, to change the fire resistance, it would be like this data.raw["assembling-machine"]["assembling-machine-2"]["resistances"]["fire"]["percent"] = 70
It can go on and on, as long as its a sub property you can dig all you want down.

Its to be noted this will REPLACE the last field with the new value, rather then inserting a new value into the field, this is great for changing speeds, not so much for inserting a new recipe to an existing technology.

Second method is insersion. This is especially useful paired with a migration.lua for changing existing recipes. table.insert(data.raw["Type"]["Name"]["Property"])
Say you want to add a resistance? table.insert(data.raw["assembling-machine"]["assembling-machine-2"]["resistances"],{{type = "poison",percent = 70}})
Note the "," rather then the "=". Other then that they are pretty similar, and act the same way.
Its to be noted this will keep old values, rather then replacing them, great for adding recipes to existing technologies.

Not, it is to be noted for both these processes, don't have a comma at the end of each line and they work outside of data:extend({})
so it would look like

Code: Select all

data.raw["stuff"]
data.raw["morestuff"]
data:extend({extra stuff})
Third and least elegant way is literally copy pasting the base game entity and changing all the values. I used to do this when i started out which was not too long ago actually, it leaves for a really messy file, comments much needed
And as a disclaimer, chances are some of my code won't work, however they should serve as needed as examples.

As a bonus, if you want to make a new thing that is based on another thing, you can cheat and copy the entity and change its values all in a lua file, like so

Code: Select all

ShinyEF2 = util.table.deepcopy(data.raw["furnace"]["electric-furnace"])
ShinyEF2.name = "electric-furnace-2Shiny"
ShinyEF2.icon = "__Shinys_Cross-patch__/graphics/icons/electric-furnace2.png"
ShinyEF2.minable = {mining_time = 1, result = "electric-furnace-2Shiny"}
ShinyEF2.max_health = 300
ShinyEF2.module_specification.module_slots = 4
ShinyEF2.energy_usage = "350kW"
ShinyEF2.crafting_speed = 4
ShinyEF2.animation.filename = "__Shinys_Cross-patch__/graphics/entity/electric-furnace/electric-furnace-base2.png"
The "ShinyEF2" is a variable, if that's the word, think algebra class where 1+x=3, where x is 2, and you were probably thinking "Why would anyone even do that?" well we do that now. hue.
Literally re-wrote all my entity files when i found that one out. You can also use variables as values as long as they are set somewhere before the code needs em, like if you require a filecalled config in the data.lua and set all the values there. Also if you value is a mathematical equation that works too. I sometimes do that when i am too lazy to use a calculator, or if i am scaling items off a multiplier.


As for your last part of your question, i belive that you cannot change the table after it has been created (game bootup) but you can delete and replace an entity using the control.lua when an event is triggered, using code.

Re: [HELP] Edit the data of only one entity

Posted: Thu Aug 04, 2016 8:42 am
by Chanz
ShinyAfro thank you very much for the detailed explanation! Yes the data.json is a typo, it was pretty late over here when I wrote that post. Bit it's very thoughtful and nice to clear that up.

After reading your post, everything makes a little more sense. But I still don't get why its not possible to change an entity while the game table has been created. I mean how does the exosuit change the players walk speed? I know it's a multiplier (movement_bonus), but where is the lua code to actually change the players speed or is that where the Factorio Mod API ends?

Edit: So far I understand your post now, I'll have to copy the locomotive class, change its max_speed value and replace the locomotive entity when a player gets on the train. Is that right?

Edit#2: I added your deepcopy code, created a TrainTierTwo and changed its max_speed. The function setLocomotiveMaxSpeed(entity) is called when I want to replace the normal train with my TrainTierTwo. But I don't get how I can do that. I want the cargo, fuel, schedules, ..., to remain and just upgrade the normal train by my TrainTierTwo.

Code: Select all

function setLocomotiveMaxSpeed(entity)

  -- how to replace here the entity (a locomotive) with my new TrainTierTwo?

end

script.on_event(defines.events.on_init, function(event)

  TrainTierTwo = util.table.deepcopy(data.raw["locomotive"]["diesel-locomotive"])
  TrainTierTwo.max_speed = 3.0
end

Re: [HELP] Edit the data of only one entity

Posted: Thu Aug 04, 2016 12:33 pm
by ShinyAfro
Chanz wrote:ShinyAfro thank you very much for the detailed explanation! Yes the data.json is a typo, it was pretty late over here when I wrote that post. Bit it's very thoughtful and nice to clear that up.

After reading your post, everything makes a little more sense. But I still don't get why its not possible to change an entity while the game table has been created. I mean how does the exosuit change the players walk speed? I know it's a multiplier (movement_bonus), but where is the lua code to actually change the players speed or is that where the Factorio Mod API ends?

Edit: So far I understand your post now, I'll have to copy the locomotive class, change its max_speed value and replace the locomotive entity when a player gets on the train. Is that right?

Edit#2: I added your deepcopy code, created a TrainTierTwo and changed its max_speed. The function setLocomotiveMaxSpeed(entity) is called when I want to replace the normal train with my TrainTierTwo. But I don't get how I can do that. I want the cargo, fuel, schedules, ..., to remain and just upgrade the normal train by my TrainTierTwo.

Code: Select all

function setLocomotiveMaxSpeed(entity)

  -- how to replace here the entity (a locomotive) with my new TrainTierTwo?

end

script.on_event(defines.events.on_init, function(event)

  TrainTierTwo = util.table.deepcopy(data.raw["locomotive"]["diesel-locomotive"])
  TrainTierTwo.max_speed = 3.0
end
I'm probably not going to be of much use in this part, as i said i am pretty new myself and have not tried anything similar to what you are doing. Generally you're probably going to figure out a script to read the contents and instructions and set them to the new entity if possible, unfortunately i have no idea how to do that.

As for changing things mid game, generally table stuff cannot be changed unless it has a type of command or dynamic variable coded to it, which multiplies it by the base values, for the exosuit i believe theres a function coded into the game that multiplies the players walk speed by 1.2, for each exo. Pretty sure if you want something like that it needs to be hard coded in, i remember someone trying to make turret range upgrades who had to make a script to replace all turrets when the research was complete and swap out enabled recipes (i assume). That's my understanding of it anyhow.

Alternatively, i know there is a mod that limits speed of all trains using signs, maybe you could figure out how the speed is reduced from that mod and reverse engineer it to enforce a global speed limit which is voided when a train is entered?
just an idea. I'd credit/ask him if that worked out well.

Re: [HELP] Edit the data of only one entity

Posted: Thu Aug 04, 2016 4:19 pm
by Adil
As much as ShinyAfro posts are detailed, they're not going to solve the problem in the original post.
Locomotive and car have several runtime multipliers that are applied to a single entity, see the entity api, use ctrl-f: 'modifier' to find other relevant fields.
The "replace locomotive when player gets in" is a bad way, it is only doable with silently invoking destroy() method and then spawning new entity, this may wreak havoc in other mods, that use references to those entities.

Re: [HELP] Edit the data of only one entity

Posted: Thu Aug 04, 2016 6:44 pm
by Chanz
Thank you guys very much.

I know that the replace method would be the worst way to solve this.

Now I found out, that the speed of a train can be overwritten. The mod for speed limit rail signs uses this to limit the speed. Also the mod uses a custom function to calculate the acceleration and deceleration.
I'll try to figure out if I can use this.

Still if anyone knows how to change the max speed of a locomotive or vehicle let me know. I also want to write an afterburner for all vehicles in Factorio. :-)

Re: [HELP] Edit the data of only one entity

Posted: Fri Aug 05, 2016 7:43 am
by Adil
Max speed is defined by equilibrium of vehicle accelerating_power and various friction forces imposed on it.
There's no maximum speed, there's speed to which vehicle can accelerate on its own.
You change the modifiers I've linked previously, you change how fast it can go.