require "config" require "defines" require "util" remote.add_interface("oxygen", { change_oxygen_of_player = function(player_name, amount) for _,v in ipairs(global.oxygen) do if v[1] == game.get_player(player_name) then v[2] = v[2] + amount update_gui(v) end end end, set_oxygen_of_player = function(player_name, amount) for _,v in ipairs(global.oxygen) do if v[1] == game.get_player(player_name) then if amount > Config.MaxOxygen then amount = Config.MaxOxygen elseif amount < 0 then amount = 0 end v[2] = amount update_gui(v) end end end, get_oxygen_of_player = function(player_name) for _,v in ipairs(global.oxygen) do if v[1] == game.get_player(player_name) then return v[2] end end end, has_gasmask = function(player_name) return has_gasmask(game.get_player(player_name)) end }) script.on_init(function(Initialize) if global.oxygen == nil then global.oxygen = {} end if global.oxygen_dispensers == nil then global.oxygen_dispensers = {} end end) script.on_event(defines.events.on_tick, function(event) handle_players() handle_dispensers() handle_enemy_positions() end) script.on_event(defines.events.on_player_created, function(event) if game.get_player(event.player_index).controller_type ~= defines.controllers.character then return end local player = game.get_player(event.player_index) table.insert(global.oxygen, {player, Config.MaxOxygen}) local frame = player.gui.left.add({type="frame", name="oxygen-amount", direction="horizontal"}) frame.add({type="label", name="caption-label", caption={"oxygen"}}) frame.add({type="label", name="oxygen-value", caption=tostring(Config.MaxOxygen)}) player_starting_inventory(player) end) function player_starting_inventory(player) if not Config.DebugMode then player.get_inventory(defines.inventory.player_main).insert({name="big-oxygen-bottle", count=Config.StartBottles, health=1.0}) else player.get_inventory(defines.inventory.player_main).insert({name="oxygen-bottle", count=1, health=1.0}) player.get_inventory(defines.inventory.player_main).insert({name="big-oxygen-bottle", count=1, health=1.0}) player.get_inventory(defines.inventory.player_main).insert({name="oxygen-dispenser", count=4, health=1.0}) player.get_inventory(defines.inventory.player_main).insert({name="offshore-pump", count=1, health=1.0}) player.get_inventory(defines.inventory.player_main).insert({name="solar-panel", count=4, health=1.0}) player.get_inventory(defines.inventory.player_main).insert({name="chemical-plant", count=1, health=1.0}) player.get_inventory(defines.inventory.player_main).insert({name="small-electric-pole", count=4, health=1.0}) end end function update_gui(oxygen_player) oxygen_player[1].gui.left["oxygen-amount"]["oxygen-value"].caption = tostring(oxygen_player[2]) end function remove_bottle(oxygen_player) local inv = oxygen_player[1].get_inventory(defines.inventory.player_main) local removed_bottle = remove_bottle_from_inv(oxygen_player, inv) if not removed_bottle then inv = oxygen_player[1].get_inventory(defines.inventory.player_quickbar) removed_bottle = remove_bottle_from_inv(oxygen_player, inv) end return removed_bottle end function remove_bottle_from_inv(oxygen_player, inv) local removed_bottle = false if inv.get_item_count("oxygen-bottle") >= 1 then inv.remove{name="oxygen-bottle", count=1} inv.insert{name="empty-oxygen-bottle", count=1} oxygen_player[2] = oxygen_player[2] + (Config.MaxOxygen / 2) oxygen_player[1].print("Small oxygen bottle is used") -- Notify the player removed_bottle = true elseif inv.get_item_count("big-oxygen-bottle") >= 1 then inv.remove{name="big-oxygen-bottle", count=1} inv.insert{name="big-empty-oxygen-bottle", count=1} oxygen_player[2] = oxygen_player[2] + Config.MaxOxygen oxygen_player[1].print("Big oxygen bottle is used") -- Notify the player removed_bottle = true end return removed_bottle end function refill_bottles(oxygen_player) if Config.AutoBottleRefilling and game.tick % (Config.BottleRefillingSpeed * 60) == 0 then local inv = oxygen_player[1].get_inventory(defines.inventory.player_main) local refilled_bottle = refill_bottles_by_inv(oxygen_player, inv) if not refilled_bottle then inv = oxygen_player[1].get_inventory(defines.inventory.player_quickbar) refilled_bottle = refill_bottles_by_inv(oxygen_player, inv) end end return refilled_bottle end function refill_bottles_by_inv(oxygen_player, inv) local refilled_bottle = false if inv.get_item_count("empty-oxygen-bottle") > 0 then inv.remove({name="empty-oxygen-bottle", count=1}) inv.insert({name="oxygen-bottle", count=1}) refilled_bottle = true elseif inv.get_item_count("big-empty-oxygen-bottle") > 0 then inv.remove({name="big-empty-oxygen-bottle", count=1}) inv.insert({name="big-oxygen-bottle", count=1}) refilled_bottle = true end return refilled_bottle end function has_gasmask(oxygen_player) local armor = oxygen_player[1].get_inventory(defines.inventory.player_armor)[1] if armor.valid_for_read and armor.has_grid then for _,equip in pairs(armor.grid.equipment) do if equip.name == "gas-mask" then return true end end end end entityBuilt = function(event) if event.created_entity ~= nil and event.created_entity.valid and event.created_entity.name == "oxygen-dispenser" then table.insert(global.oxygen_dispensers, {event.created_entity, 0}) end end entityRemoved = function(event) if event.entity ~= nil and event.entity.valid and event.entity.name == "oxygen-dispenser" then for i,v in ipairs(global.oxygen_dispensers) do if v[1] == event.entity then table.remove(global.oxygen_dispensers, i) end end end end function handle_dispensers() if global.oxygen_dispensers == nil or game.tick % 60 ~= 0 then return end for i,v in ipairs(global.oxygen_dispensers) do -- game.player.print(i) if v[1].connected then if v[2] > 0 then local fluid = v[1].fluidbox[1] if fluid ~= nil and fluid.type == "oxygen" and fluid.amount >= 1 then fluid.amount = fluid.amount - 1 v[1].fluidbox[1] = fluid v[2] = v[2] - 1 else v[2] = 0 end end if v[2] == 0 then local fluid = v[1].fluidbox[1] if fluid ~= nil and fluid.type == "oxygen" and fluid.amount >= 20 then v[2] = 20 game.get_surface("nauvis").create_entity({name="oxygen-cloud", position=v[1].position}) end end end end end function handle_players() if game.tick % (Config.TickCheck * 60) ~= 0 then return end for _,v in ipairs(global.oxygen) do if v[1].controller_type == defines.controllers.character and v[1].connected then local pos = v[1].position -- player position local delta = 0 - Config.DeplenishingSpeed -- amount of oxygen to be added or subtracted; here it is default subtraction when player is not near dispensers if has_gasmask(v) then delta = delta / 2 end -- deplenishing with mask is halved local total_dispensers = game.get_surface("nauvis").count_entities_filtered{ area = {{pos.x - Config.OxygenRadiusEnemies, pos.y - Config.OxygenRadiusEnemies}, {pos.x + Config.OxygenRadiusEnemies, pos.y + Config.OxygenRadiusEnemies}}, name="oxygen-dispenser" } if total_dispensers > 0 then delta = delta + player_near_dispenser(v) end v[2] = v[2] + delta if v[2] >= Config.MaxOxygen then v[2] = Config.MaxOxygen if Config.AutoBottleRefilling then refill_bottles(v) end elseif v[2] <= 0 then local removed_bottle = remove_bottle(v) if not removed_bottle then v[1].character.damage(Config.ChokingDamage, v[1].force, "oxygen") v[2] = 0 if game.tick % (Config.PlayerChokingNoteSpeed * 60) then v[1].print("Player is choking") end end end v[2] = tonumber(string.format("%." .. (2) .. "f", v[2])) update_gui(v) end end end function player_near_dispenser(oxygen_player) local pos = oxygen_player[1].position -- player position local dispenser = game.get_surface("nauvis").find_entities_filtered{ area = {{pos.x - Config.OxygenRadiusEnemies, pos.y - Config.OxygenRadiusEnemies}, {pos.x + Config.OxygenRadiusEnemies, pos.y + Config.OxygenRadiusEnemies}}, name="oxygen-dispenser" } local delta = 0 for _,d in ipairs(dispenser) do local fluid = d.fluidbox[1] if fluid ~= nil and fluid.type == "oxygen" and fluid.amount >= 20 then local distance = distance(oxygen_player[1], d) delta = delta + Config.ReplenishingSpeed - (Config.ReplenishingSpeed / Config.OxygenRadiusEnemies * distance) if delta > Config.OxygenMultiplicator then delta = Config.OxygenMultiplicator end end end return delta end function handle_enemy_positions() if global.oxygen_dispensers == nil or game.tick % (Config.TickCheck * 60) ~= 0 then return end for _,v in ipairs(global.oxygen_dispensers) do if v[2] > 0 then local pos = v[1].position -- item position local enemies = game.get_surface("nauvis").find_enemy_units(pos, Config.OxygenRadiusEnemies) if #enemies > 0 then for _,e in ipairs(enemies) do e.damage(Config.DamageToEnemies, e.force, "oxygen") end end local total_spawners = game.get_surface("nauvis").count_entities_filtered{ area = {{pos.x - Config.OxygenRadiusSpawners, pos.y - Config.OxygenRadiusSpawners}, {pos.x + Config.OxygenRadiusSpawners, pos.y + Config.OxygenRadiusSpawners}}, type="unit-spawner" } if total_spawners > 0 then local spawners = game.get_surface("nauvis").find_entities_filtered{ area = {{pos.x - Config.OxygenRadiusSpawners, pos.y - Config.OxygenRadiusSpawners}, {pos.x + Config.OxygenRadiusSpawners, pos.y + Config.OxygenRadiusSpawners}}, type="unit-spawner" } for _,s in ipairs(spawners) do s.damage(Config.DamageToSpawners, s.force, "oxygen") end end end end end function distance(entity1, entity2) local distance_x = 0 local distance_y = 0 local distance = 0 if entity1.position.x > entity2.position.x then distance_x = entity1.position.x - entity2.position.x else distance_x = entity2.position.x - entity1.position.x end if entity1.position.y > entity2.position.y then distance_y = entity1.position.y - entity2.position.y else distance_y = entity2.position.y - entity1.position.y end distance = (distance_x ^ 2 + distance_y ^ 2) ^ (1/2) return tonumber(string.format("%." .. (2) .. "f", distance)) end script.on_event(defines.events.on_built_entity, entityBuilt) script.on_event(defines.events.on_robot_built_entity, entityBuilt) script.on_event(defines.events.on_preplayer_mined_item, entityRemoved) script.on_event(defines.events.on_robot_pre_mined, entityRemoved) script.on_event(defines.events.on_entity_died, entityRemoved)