Power Armor Enhancement
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Power Armor Enhancement
I am trying to write a mod to enhance powered armor in the game.
To do so, I need to solve several problems.
~In order to allow Power Conduit Modules, which transfer power from your standard energy network into your modular armor ~
I need to figure out how to, on game tick, determine if a player is inside a power field, and if so, figure out how to drain xx amount of power from that field. That is, If the player is currently near a power pole, I want to be able to have the player act as a power consumer.
I am unable to locate any existing method to drain power, and am unsure how you might create a dummy energy consumer.
~In order to support coal fired generators, or similar~
I need to figure out how to feed powered armor Fuel-type items. The simplest solution would be simply to search for burnable items in the inventory, but that is not ideal. I would prefer to be able to either flag items somehow, or add a new GUI slot for fuel items.
Worst case, I create a custom "Armor Fuel" Item which you can craft from various burnable stuff.
I have already figured out how to manipulate power levels of modules, so that part is easy in comparison.
To do so, I need to solve several problems.
~In order to allow Power Conduit Modules, which transfer power from your standard energy network into your modular armor ~
I need to figure out how to, on game tick, determine if a player is inside a power field, and if so, figure out how to drain xx amount of power from that field. That is, If the player is currently near a power pole, I want to be able to have the player act as a power consumer.
I am unable to locate any existing method to drain power, and am unsure how you might create a dummy energy consumer.
~In order to support coal fired generators, or similar~
I need to figure out how to feed powered armor Fuel-type items. The simplest solution would be simply to search for burnable items in the inventory, but that is not ideal. I would prefer to be able to either flag items somehow, or add a new GUI slot for fuel items.
Worst case, I create a custom "Armor Fuel" Item which you can craft from various burnable stuff.
I have already figured out how to manipulate power levels of modules, so that part is easy in comparison.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
-
- Fast Inserter
- Posts: 157
- Joined: Fri Jun 26, 2015 11:13 pm
Re: Power Armor Enhancement
The only thing I can think of is to attach an accumulator-type object to the player. It will drain energy and allow you to retrieve that energy for other purposes.
-
- Filter Inserter
- Posts: 402
- Joined: Fri May 23, 2014 8:54 am
- Contact:
Re: Power Armor Enhancement
This is the answer. Teleport an accumulator around with the player that has no sprite and a ghost collision mask. Keep the energy full and when you want to test or draw power drop the amount of energy and the accumulator will draw power naturally. For the item slot, look at the Force Field mod, Rseding91 wrote an example there for modules that you could easily adapt for coal and burnables.johanwanderer wrote:The only thing I can think of is to attach an accumulator-type object to the player. It will drain energy and allow you to retrieve that energy for other purposes.
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
That should solve both problems.
The interface is complicated, but the example should be enough.
Thanks!
The interface is complicated, but the example should be enough.
Thanks!
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
I am unable to figure out how to make the accumulator entirely invulnerable. Currently, I can shoot it, which, presumably, means that even if i set it's selection size to zero, mobs, or splash damage will still damage it. It needs to be entirely inviolate.JamesOFarrell wrote:This is the answer. Teleport an accumulator around with the player that has no sprite and a ghost collision mask. Keep the energy full and when you want to test or draw power drop the amount of energy and the accumulator will draw power naturally. For the item slot, look at the Force Field mod, Rseding91 wrote an example there for modules that you could easily adapt for coal and burnables.johanwanderer wrote:The only thing I can think of is to attach an accumulator-type object to the player. It will drain energy and allow you to retrieve that energy for other purposes.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
-
- Fast Inserter
- Posts: 157
- Joined: Fri Jun 26, 2015 11:13 pm
Re: Power Armor Enhancement
Maybe setting this to false?Ranakastrasz wrote:I am unable to figure out how to make the accumulator entirely invulnerable. Currently, I can shoot it, which, presumably, means that even if i set it's selection size to zero, mobs, or splash damage will still damage it. It needs to be entirely inviolate.
https://forums.factorio.com/wiki/inde ... structible
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
That really should have worked.
However, it doesn't seem to do so.
Setting health to zero prevents targeting with a gun, but a grenade still kills it.
Edit: Oh wait, Thats a command, not a prototype property.
Edit2: No, thats a read only property. I have no idea how to set it.
edit3: Ah, I spelled it wrong. Lol. fixed now.
However, it doesn't seem to do so.
Setting health to zero prevents targeting with a gun, but a grenade still kills it.
Edit: Oh wait, Thats a command, not a prototype property.
Edit2: No, thats a read only property. I have no idea how to set it.
edit3: Ah, I spelled it wrong. Lol. fixed now.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
This is the current script.
Appears to work perfectly for single player. However, multplayer wont work correctly.
The test items dont show up.
Also, the second player has either the original accumulator or both of them following them, and after leaving it is still bound to the second player.
--Snipped--
Appears to work perfectly for single player. However, multplayer wont work correctly.
The test items dont show up.
Also, the second player has either the original accumulator or both of them following them, and after leaving it is still bound to the second player.
--Snipped--
Last edited by Ranakastrasz on Thu Jul 23, 2015 11:47 pm, edited 1 time in total.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
-
- Fast Inserter
- Posts: 157
- Joined: Fri Jun 26, 2015 11:13 pm
Re: Power Armor Enhancement
I only looked over it briefly (and I don't know what is wrong, besides it's not working), but it seems that you're using the same table to store data for all players, i.e.
I would recommend using an array for the players, i.e.
Code: Select all
glob.modularArmor.player.unit. ...
Code: Select all
local player_thing = glob.modularArmor.players[i]; -- not sure what to call it.
if(nil == player_thing)
then
player_thing = {}
glob.modularArmor.players[i] = player_thing;
-- more inits here
end;
-- now the player_thing table contains per-player stuff, so
player_thing.unit.teleport(player.character.position);
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
That helped. At least part of the problem was that I was treating "player" as the iterator when "i" was the actual iterator.
The intention was that the iterator would act as the index for the table.
Edit:I cant do multiplayer debug messages. It crashes the game as stated here https://forums.factorio.com/forum/vie ... =41&t=5638
Print standalone does nothing, and i have no idea how to open the console.
Using that supposed solution doesn't work either.
The intention was that the iterator would act as the index for the table.
Edit:I cant do multiplayer debug messages. It crashes the game as stated here https://forums.factorio.com/forum/vie ... =41&t=5638
Print standalone does nothing, and i have no idea how to open the console.
Using that supposed solution doesn't work either.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
Debug messages solved via rk84's test mode mod's debug message function. Not entirely sure how, but it works. Also the loop actually works in multiplayer, unlike my old one.
It also seems to work perfectly in multiplayer now.
However, it causes desyncs for some of the ticks while running. Unsure why. Its not consistent either.
In Warcraft 3, I knew exactly what kind of things caused desyncs. modifying any game altering property of any handle or creating a handle inside a GetLocalPlayer() = thisPlayer block would always cause it. However, no GetLocalPlayer equivelent exists, and I'm not doing anythng specific to "player" so far as I can see. And I am pretty sure that you cant use "player" in multiplayer anyway without an error.
--Snipped--
It also seems to work perfectly in multiplayer now.
However, it causes desyncs for some of the ticks while running. Unsure why. Its not consistent either.
In Warcraft 3, I knew exactly what kind of things caused desyncs. modifying any game altering property of any handle or creating a handle inside a GetLocalPlayer() = thisPlayer block would always cause it. However, no GetLocalPlayer equivelent exists, and I'm not doing anythng specific to "player" so far as I can see. And I am pretty sure that you cant use "player" in multiplayer anyway without an error.
--Snipped--
Last edited by Ranakastrasz on Thu Jul 23, 2015 11:47 pm, edited 1 time in total.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Re: Power Armor Enhancement
You get desyncs because you're setting glob.ticking = 0 on_load and so it's not consistent between save/load and player's joining triggers save -> transfer map -> load on other peer.
If you want to get ahold of me I'm almost always on Discord.
Re: Power Armor Enhancement
Also you can use the following if you want to make debug mod interfaces that print to the calling player:
This will however only work if called from a player through the console. If another mod calls the interface or if you call it from your own mod it won't work and will thrown an error.
Code: Select all
remote.add_interface("ModularArmor", {
print = function(text)
game.local_player.print(text)
end
})
If you want to get ahold of me I'm almost always on Discord.
-
- Fast Inserter
- Posts: 157
- Joined: Fri Jun 26, 2015 11:13 pm
Re: Power Armor Enhancement
I would just loop through all the players in the game and print through any that is validRseding91 wrote:Also you can use the following if you want to make debug mod interfaces that print to the calling player:
This will however only work if called from a player through the console. If another mod calls the interface or if you call it from your own mod it won't work and will thrown an error.Code: Select all
remote.add_interface("ModularArmor", { print = function(text) game.local_player.print(text) end })
Code: Select all
-----------------------------------------------------------
-- utility functions
-----------------------------------------------------------
local function ldLC_Debug(s)
for index, player in pairs(game.players) do
if(player.valid) then
player.print(s);
end;
end
end
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
Ah. That explains it. That would be inconsistant.Rseding91 wrote:You get desyncs because you're setting glob.ticking = 0 on_load and so it's not consistent between save/load and player's joining triggers save -> transfer map -> load on other peer.
Setting it in the upper global area instead would work, correct?
~~~~
Already got a functional debug message method.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Re: Power Armor Enhancement
No, that's also run when you load the game.Ranakastrasz wrote:Ah. That explains it. That would be inconsistant.Rseding91 wrote:You get desyncs because you're setting glob.ticking = 0 on_load and so it's not consistent between save/load and player's joining triggers save -> transfer map -> load on other peer.
Setting it in the upper global area instead would work, correct?
~~~~
Already got a functional debug message method.
You need to set it in on_init and on_load but only set it if the glob.value is nil (so the first ever time the mod is loaded on that map). After the first time it will never be nil again and will get saved/loaded between connections and restarts.
If you want to get ahold of me I'm almost always on Discord.
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
That is useful information.
I am now trying to make the accumulator invisible. However, doing so is surprisingly difficult. I now have a rather less than helpful crash message, of "An unexpected error has occured"
I am now trying to make the accumulator invisible. However, doing so is surprisingly difficult. I now have a rather less than helpful crash message, of "An unexpected error has occured"
Code: Select all
data:extend(
{
{
type = "accumulator",
name = "modular-accumulator-dummy",
icon = "__base__/graphics/icons/basic-accumulator.png",
flags = {"placeable-off-grid", "not-on-map"},
-- minable = {hardness = 0.2, mining_time = 0.5, result = "basic-accumulator"},
max_health = 0,
-- corpse = "medium-remnants",
collision_box = {{0, 0}, {0, 0}},
--selection_box = {{-1, -1}, {1, 1}},
collision_mask = {"ghost-layer"},
energy_source =
{
type = "electric",
buffer_capacity = "5MJ",
usage_priority = "primary-input",
input_flow_limit = "5MW",
output_flow_limit = "0kW"
},
picture = {
filename = "",
priority = "low",
width = 0,
height = 0,
shift = {0.0, 0.0}
},
charge_animation =
{
filename = "",
width = 0,
height = 0,
line_length = 0,
frame_count = 1,
shift = {0, 0},
animation_speed = 0
},
charge_cooldown = 0,
charge_light = {intensity = 0, size = 0},
discharge_animation =
{
filename = "",
width = 0,
height = 0,
line_length = 0,
frame_count = 1,
shift = {0, -0},
animation_speed = 0
},
discharge_cooldown = 0,
discharge_light = {intensity = 0.0, size = 0},
working_sound =
{
sound =
{
filename = "",
volume = 0
},
idle_sound =
{
filename = "",
volume = 0
},
max_sounds_per_type = 0
},
}
})
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
That problem is solved. However, if I save and load the game, the global.loaded variable is still nil. This contradicts my expectations, as I expected it to remain true after loading, based on information in the wiki.
Also, I am not certain I understand multiplayer instancing correctly. When a new player joins, will they get a copy of global?
Also, I am not certain I understand multiplayer instancing correctly. When a new player joins, will they get a copy of global?
Code: Select all
require "defines"
--[[
This module handles the gameloop alteration, allowing conduit modules in power armor grid to tranfer energy between your power grid and your armor.
]]--
--[[
Charging Module Icon
Artist: Treetog ArtWork (Available for custom work)
Iconset: Junior Icons (146 icons)
License: Free for personal desktop use only.
Commercial usage: Not allowed
]]--
--[[ Gen , Size, Gen/size
Conduit : 20kw, 1x1, 20kw
Solar 1 : 15kw, 1x1, 15kw
Solar 2 : 200kw, 3x3, 22.2kw
Burner : 200kw, 2x2, 50kw
Fusion : 1Mw, 4x4, 62.5kw
Energy , duration
Wood : 4 MJ , 20
Coal : 8 MJ , 40
Fuel : 25 MJ , 125
Fusion: 112.5 MJ, 120
]]--
--local loaded
local tickRate = 1
local ticksPerSecond = 60
local tickRatio = tickRate/ticksPerSecond -- To avoid division operations in a loop
local conversionRatio = 1.0 -- Internal armor has values 1/1000th of the normal power network. As of 0.12, it is now a ratio of 10
local conversionAntiRatio = 1.0/conversionRatio -- avoid division
local accumulatorEnergyCap = 5 * 1000 * 1000 -- 100 slots, 20/slot + 80, 2080 transfer rate, 5mil should be sufficient.. This must match accumulator dummy power capacity.
local ArmorTransferRatePerGridSize = 800
local TransferRatePerConduit = 20*1000
local Debug = true
--[[local fuelValues =
{
wood = 4*1000*1000,
Coal = 8*1000*1000,
Fuel = 25*1000*1000
}]]--
--[[remote.addinterface("ModularArmor", {
reset = function()
global.ticking = nil
--global.modularArmor = {}
end
})]]--
function verifySettings()
if tickRate < 0 then
tickRate = 0
throwError("Tick rate must be >= 0.")
end
end
function onload() -- this function
globalPrint("onLoad")
if global.loaded == nil then
global.loaded = true
globalPrint("loaded")
if global.modularArmor == nil then
global.modularArmor = {}
end
if global.ticking == nil then
global.ticking = 0
game.on_event(defines.events.on_tick, ticker)
end
verifySettings()
end
end
game.on_load(onload)
game.on_init(onload)
function globalPrint(msg)
local players = game.players
for i=1, #players do
players[i].print(msg)
end
end
function tableIsEmpty(t)
if t then
for k in pairs(t) do
return false
end
end
return true
end
function ticker() -- run once per tickRate number of gameticks.
if global.ticking == 0 then
global.ticking = tickRate - 1
tick()
else
global.ticking = global.ticking - 1
end
end
function tick()
local shouldKeepTicking
local thisPlayer = nil
local players = game.players
local surface = game.surfaces['nauvis']
globalPrint("tick")
shouldKeepTicking = true -- Due to lack of any alternate method of detecting player's armor state, we have to always tick.
for i=1, #players do
thisPlayer = players[i]
--game.getplayer(1).print(i..' '..player)
local modularArmor = global.modularArmor[i]
if modularArmor == nil then
modularArmor = {} -- ensure player has data attached
global.modularArmor[i] = modularArmor
modularArmor.unit = surface.create_entity{name = "modular-accumulator-dummy", position = thisPlayer.position, force=game.forces.player}
-- attach power drain dummy.
modularArmor.unit.destructible = false -- Make dummy invulnerable.
modularArmor.unit.energy = accumulatorEnergyCap -- initialize energy levels
modularArmor.previousEnergy = accumulatorEnergyCap -- and previous energy level from last tick
if Debug == true then
game.always_day=true -- test mode stuff
thisPlayer.insert{name="basic-grenade",count=5}
thisPlayer.insert{name="energy-shield-equipment",count=20}
thisPlayer.insert{name="energy-shield-mk2-equipment",count=10}
--thisPlayer.insert{name="energy-shield-module-equipment",count=10}
--thisPlayer.insert{name="energy-shield-core-equipment",count=5}
thisPlayer.insert{name="power-conduit-equipment",count=40}
--thisPlayer.insert{name="power-conduit-module-equipment",count=10}
--thisPlayer.insert{name="power-conduit-core-equipment",count=5}
thisPlayer.insert{name="solar-panel-equipment",count=20}
thisPlayer.insert{name="solar-panel-equipment-mk2",count=10}
thisPlayer.insert{name="basic-actuator-equipment",count=20}
thisPlayer.insert{name="battery-equipment",count=5}
thisPlayer.insert{name="battery-mk2-equipment",count=5}
thisPlayer.insert{name="basic-modular-armor",count=1}
thisPlayer.insert{name="power-armor",count=1}
thisPlayer.insert{name="power-armor-mk2",count=1}
thisPlayer.insert{name="small-electric-pole",count=200}
thisPlayer.insert{name="solar-panel",count=200}
else
end
else
modularArmor.unit.teleport(thisPlayer.character.position) -- Ensure that the power drain dummy is always at the player's position.
end
local armor = thisPlayer.get_inventory(defines.inventory.player_armor)[1] -- Check for armour presence.
if armor.valid_for_read then
local grid = armor.grid
if grid ~= nil then -- Check for grid existance.
local transferRate = 0 -- Rate of transfer from external network to armor.
transferRate = transferRate + ArmorTransferRatePerGridSize*grid.width*grid.height
local energy = 0 -- Total energy and energy capacity
local energyCap = 0
-- local shieldHealth = 0 -- Total shield and shield capacity for auto-balancing.
--local shieldCap =0
for i,equipment in ipairs(grid.equipment) do -- Loop through all equipment.
if equipment.max_energy ~= 0 then
energy = energy + equipment.energy -- If it has energy, add values to total value.
energyCap = energyCap + equipment.max_energy
else
end
--if equipment.maxshield ~= 0 then
-- shieldHealth = shieldHealth + equipment.shield -- Same with shield.
-- shieldCap = shieldCap + equipment.maxshield
--else
if equipment.name == "power-conduit-equipment" then -- Also count each conduit module.
transferRate = transferRate + TransferRatePerConduit
end
end
local transferRate = transferRate * tickRatio -- transfer rate as calculated was per second, but this runs every so many game ticks.
local transferRate = math.min(transferRate,energyCap-energy) -- We cant transfer energy without space to put it into
local accumulatorEnergy = modularArmor.unit.energy - modularArmor.previousEnergy -- How much energy was accumulated.
local energyToTransfer = math.min(transferRate,accumulatorEnergy*conversionAntiRatio) -- Accumulated energy, or transfer wanted, whichever is lower.
for i,equipment in ipairs(grid.equipment) do
if equipment.max_energy ~= 0 then
local difference = equipment.max_energy - equipment.energy
if energyToTransfer > difference then
energyToTransfer = energyToTransfer - difference
equipment.energy = equipment.max_energy
else
equipment.energy = equipment.energy + energyToTransfer
energyToTransfer = 0
break
end
else
end
end
energyToTransfer = energyToTransfer * conversionRatio
modularArmor.unit.energy = accumulatorEnergyCap - transferRate*conversionRatio
modularArmor.previousEnergy = modularArmor.unit.energy - energyToTransfer*conversionRatio -- The additional accumulated energy over
else
end
else
end
end
if not shouldKeepTicking then
global.ticking = nil
game.onevent(defines.events.ontick, nil)
end
end
function activateTicker()
if not global.ticking then
global.ticking = tickRate
game.onevent(defines.events.ontick, ticker)
end
end
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Re: Power Armor Enhancement
I'm pretty sure that global is only one.
You might need to store the data per player index or something along those lines.
You might need to store the data per player index or something along those lines.
- Ranakastrasz
- Smart Inserter
- Posts: 2144
- Joined: Thu Jun 12, 2014 3:05 am
- Contact:
Re: Power Armor Enhancement
The problem being that the gameloop runs every some number of ticks, which if it isn't the same for all players, it will desync.orzelek wrote:I'm pretty sure that global is only one.
You might need to store the data per player index or something along those lines.
Also, later, I will be storing fuel items in the armor for a burner generator, which even more obviously must be the same for all players.
My Mods:
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16
Modular Armor Revamp - V16
Large Chests - V16
Agent Orange - V16
Flare - V16
Easy Refineries - V16