428 lines
14 KiB
Lua
428 lines
14 KiB
Lua
require("util.class")
|
|
require("util.table")
|
|
require("util.help")
|
|
require('util.tech')
|
|
require("classes.config")
|
|
|
|
local stat = 10000
|
|
|
|
function commandHandler(event)
|
|
local parameter = event.parameter
|
|
if parameter ~= nil then
|
|
if parameter == "kills" then
|
|
game.print{"Pollution-kills"}
|
|
if tlen(global.kills) > 0 then
|
|
for player, kills in pairs(global.kills) do
|
|
game.print(player .. " - " .. kills)
|
|
end
|
|
else
|
|
game.print{"Zero-players"}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
conf = Config()
|
|
|
|
Toxic = class(function(self)
|
|
self.name = "Toxic Pollution"
|
|
self.inventory = {
|
|
defines.inventory.character_main,
|
|
defines.inventory.character_trash
|
|
}
|
|
self.Signals = {
|
|
["yellow-gas-mask"] = {type="virtual", name="signal-yellow-gas-mask"},
|
|
["red-gas-mask"] = {type="virtual", name="signal-red-gas-mask"},
|
|
["red-armor"] = {type="virtual", name="signal-red-armor"},
|
|
["yellow-more-toxin"] = {type="virtual", name="signal-yellow-more-toxin"}
|
|
}
|
|
self.multiplier = {
|
|
time = 5 * Minute,
|
|
max = 60
|
|
}
|
|
end)
|
|
|
|
function Toxic:init()
|
|
self:initGlobals()
|
|
if (game) then
|
|
for _ , item in pairs(game.item_prototypes) do
|
|
if (item.type == "armor") then
|
|
if (global.MaxDurability < item.durability) then
|
|
global.MaxDurability = item.durability
|
|
end
|
|
if (item.resistances and item.resistances.toxin) then
|
|
global.armors[item.name] = {
|
|
base = conf:AbsorbMultiplier() * math.min(tonumber(string.format("%.2f", item.resistances.toxin.percent)), 0.9),
|
|
resist = item.resistances.toxin.percent
|
|
}
|
|
else
|
|
global.armors[item.name] = {
|
|
base = 0,
|
|
resist = 0
|
|
}
|
|
end
|
|
global.armors[item.name].current = global.armors[item.name].base
|
|
end
|
|
end
|
|
for _, force in pairs(game.forces) do
|
|
global.TechBonus[force.name] = conf:ForceBaseValue()
|
|
for i = 1, TechLevels do
|
|
local tech = force.technologies[TechName.."-"..i]
|
|
if tech then
|
|
if tech.researched == true then self:UpdateTech(tech.name, force) end
|
|
end
|
|
end
|
|
end
|
|
self:initForce()
|
|
self:initKillerFish()
|
|
self:initDataPlayers()
|
|
end
|
|
end
|
|
|
|
function Toxic:initGlobals()
|
|
if (global.MaxDurability == nil) then global.MaxDurability = 0 end
|
|
if (global.armors == nil) then global.armors = {} end
|
|
if (global.TechBonus == nil) then global.TechBonus = {} end
|
|
if (global.PlayersData == nil) then global.PlayersData = {} end
|
|
if (global.kills == nil) then
|
|
global.kills = {}
|
|
else
|
|
if type(global.kills) == "number" then global.kills = {} end
|
|
end
|
|
end
|
|
|
|
function Toxic:initForce()
|
|
if not game.forces.pollution then
|
|
game.create_force("pollution")
|
|
end
|
|
end
|
|
|
|
function Toxic:initDataPlayers()
|
|
for _, player in pairs(game.players) do
|
|
self:initDataPlayer(player.name)
|
|
end
|
|
end
|
|
|
|
function Toxic:initDataPlayer(player)
|
|
local data = global.PlayersData[player]
|
|
if data == nil then
|
|
data = { ticks = 0, multiplier = 0, pollution = 0 }
|
|
else
|
|
if data.ticks == nil then data.ticks = 0 end
|
|
if data.multiplier == nil then data.multiplier = 0 end
|
|
if data.pollution == nil then data.pollution = 0 end
|
|
end
|
|
global.PlayersData[player] = data
|
|
end
|
|
|
|
function Toxic:initCommands()
|
|
commands.add_command("pollution", "toxic pollution commands", commandHandler)
|
|
end
|
|
|
|
function Toxic:initKillerFish()
|
|
if global.killer == nil or (global.killer ~= nil and global.killer.valid == false) then
|
|
global.killer = game.surfaces[1].create_entity{name = "pollution", position = {x = 1, y = 1}, force = game.forces.pollution }
|
|
global.killer.active = false
|
|
end
|
|
end
|
|
|
|
function Toxic:migrate(version)
|
|
local Major, Minor, Patch = string.match(version, "(%d)%.(%d)%.(%d)")
|
|
Major = tonumber(Major)
|
|
Minor = tonumber(Minor)
|
|
Patch = tonumber(Patch)
|
|
if (Major == 0 and Minor >= 2 and Patch >= 7) then
|
|
if (global.armorMaxDurability ~= nil) then
|
|
global.armorMaxDurability = nil
|
|
end
|
|
if (global.armorsAbsorb ~= nil) then
|
|
global.armorsAbsorb = nil
|
|
end
|
|
if (global.techAbsorb ~= nil) then
|
|
global.techAbsorb = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
function Toxic:AddAlert(player, signal, message)
|
|
if player.character then
|
|
local alerts = player.get_alerts{entity = player.character, type = defines.alert_type.custom, surface = player.surface }
|
|
for _, alert in pairs(alerts) do
|
|
if alert.icon == self.Signals[signal] then
|
|
return
|
|
end
|
|
end
|
|
player.add_custom_alert(player.character, self.Signals[signal], message, false)
|
|
end
|
|
end
|
|
|
|
function Toxic:RemoveAlert(player, signal)
|
|
if player.character then
|
|
player.remove_alert{entity = player.character, surface = player.surface, icon = self.Signals[signal] }
|
|
end
|
|
end
|
|
|
|
function Toxic:GetPollution(player)
|
|
return math.floor(player.surface.get_pollution({player.position.x, player.position.y}))
|
|
end
|
|
|
|
function Toxic:GetPlayerArmor(player)
|
|
local inv = player.get_inventory(defines.inventory.character_armor)
|
|
local count = inv.get_item_count()
|
|
if count > 0 then
|
|
return count, inv[1]
|
|
else
|
|
return count, nil
|
|
end
|
|
end
|
|
|
|
function Toxic:GetArmorAbsorb(armor)
|
|
local a = global.armors[armor]
|
|
if a ~= nil then
|
|
return a.current
|
|
end
|
|
return 0
|
|
end
|
|
|
|
function Toxic:UpdateTech(tech, force)
|
|
local n = string.match(tech, "armor%-absorb%-(%d+)")
|
|
if n ~= nil then
|
|
local bonus = conf:ForceBaseValue() + tonumber(n) * conf:TechBonus()
|
|
global.TechBonus[force.name] = bonus
|
|
self:ReCalculateAbsorb(force.name)
|
|
return true
|
|
else
|
|
return false
|
|
end
|
|
end
|
|
|
|
function Toxic:ReCalculateAbsorb(force)
|
|
for _, armor in pairs(global.armors) do
|
|
armor.current = armor.base * global.TechBonus[force]
|
|
end
|
|
end
|
|
|
|
function Toxic:IncKills(player)
|
|
local kills = global.kills[player] or 0
|
|
kills = kills + 1
|
|
global.kills[player] = kills
|
|
end
|
|
|
|
function Toxic:CalculateDamage(player, pollution, armor)
|
|
local m = self:GetTimeMultiplier(player)
|
|
local damage = 0
|
|
if armor ~= nil then
|
|
damage = pollution/stat
|
|
damage = (damage - damage * global.armors[armor.name].resist) * m
|
|
else
|
|
damage = pollution/conf:MinPollution() * m
|
|
end
|
|
return damage
|
|
end
|
|
|
|
function Toxic:IsActiveAirFiltering()
|
|
return game.active_mods["air-filtering-patched"] ~= nil
|
|
end
|
|
|
|
function Toxic:EquipArmorFromInventory(player, armor)
|
|
if (armor.is_armor == false and conf:IsAutoEquip(player)) then
|
|
local durability = global.MaxDurability
|
|
local newArmor = {id = 0, index = 0 }
|
|
for id, inventoryType in pairs(self.inventory) do
|
|
local inventory = player.get_inventory(inventoryType)
|
|
if inventory ~= nil then
|
|
for i = 1, #inventory do
|
|
local item = inventory[i]
|
|
if (item.is_armor and item.durability <= durability) then
|
|
durability = item.durability
|
|
newArmor = {id = id, index = i }
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if newArmor.id > 0 then
|
|
armor.transfer_stack(player.get_inventory(self.inventory[newArmor.id])[newArmor.index])
|
|
end
|
|
if armor.is_armor then
|
|
player.print{"Destroyed-armor-replaced", {"item-name." .. armor.name} }
|
|
else
|
|
player.print{"Armor-destroyed" }
|
|
end
|
|
end
|
|
end
|
|
|
|
function Toxic:IncTimeMultiplier(player, ticks)
|
|
local data = global.PlayersData[player]
|
|
if data.ticks < self.multiplier.time then
|
|
data.ticks = data.ticks + ticks
|
|
data = self:UpdateTimeMultiplier(data)
|
|
end
|
|
global.PlayersData[player] = data
|
|
end
|
|
|
|
function Toxic:DecTimeMultiplier(player, ticks)
|
|
local data = global.PlayersData[player]
|
|
if data ~= nil then
|
|
data.ticks = data.ticks - ticks
|
|
if data.ticks < 0 then data.ticks = 0 end
|
|
data = self:UpdateTimeMultiplier(data)
|
|
global.PlayersData[player] = data
|
|
end
|
|
end
|
|
|
|
function Toxic:GetTimeMultiplier(player)
|
|
local data = global.PlayersData[player]
|
|
if data ~= nil then
|
|
return data.multiplier
|
|
end
|
|
return 0
|
|
end
|
|
|
|
function Toxic:UpdateTimeMultiplier(data)
|
|
local m = data.ticks / self.multiplier.time
|
|
m = self.multiplier.max * m
|
|
if m % 1 == 0 then data.multiplier = m end
|
|
return data
|
|
end
|
|
|
|
function Toxic:ClearTimeMultiplier(player)
|
|
local data = global.PlayersData[player]
|
|
data.multiplier = 0
|
|
data.pollution = 0
|
|
data.ticks = 0
|
|
global.PlayersData[player] = data
|
|
end
|
|
|
|
function Toxic:DamageForPlayer(player)
|
|
local alert = 0
|
|
local pollution = self:GetPollution(player)
|
|
local newPollution = 0
|
|
local damage = 0
|
|
local absorb = conf:MinPollution()
|
|
local armorCount, armor = self:GetPlayerArmor(player)
|
|
local data = global.PlayersData[player.name]
|
|
|
|
if armorCount > 0 then absorb = absorb + self:GetArmorAbsorb(armor.name) end
|
|
if (pollution > absorb) then
|
|
newPollution = pollution - absorb
|
|
end
|
|
if newPollution > 0 then
|
|
self:IncTimeMultiplier(player.name, conf:TickInterval())
|
|
data.pollution = newPollution
|
|
damage = self:CalculateDamage(player.name, newPollution, armor)
|
|
if damage > 20 then
|
|
alert = 2
|
|
else
|
|
alert = 1
|
|
end
|
|
else
|
|
self:DecTimeMultiplier(player.name, conf:TickInterval())
|
|
damage = self:CalculateDamage(player.name, data.pollution, armor)
|
|
if damage > 0 and alert == 0 then
|
|
alert = 4
|
|
end
|
|
end
|
|
if damage > 0 then
|
|
if armor then
|
|
if (armor.durability / game.item_prototypes[armor.name].durability < 0.25 and armorCount == 1) then
|
|
alert = 3
|
|
end
|
|
armor.drain_durability(damage)
|
|
self:EquipArmorFromInventory(player, armor)
|
|
else
|
|
if (player.character.health > damage) then
|
|
player.character.damage(damage, game.forces.pollution, "toxin")
|
|
else
|
|
self:initKillerFish()
|
|
player.character.die(game.forces.pollution, global.killer)
|
|
end
|
|
end
|
|
end
|
|
if alert == 1 then
|
|
self:AddAlert(player, "yellow-gas-mask", {"High-pollution", pollution, string.format("%.2f", damage), data.multiplier})
|
|
elseif alert == 2 then
|
|
self:AddAlert(player, "red-gas-mask", {"Very-high-pollution", pollution, string.format("%.2f", damage), data.multiplier})
|
|
elseif alert == 3 then
|
|
self:AddAlert(player, "red-armor", {"Armor-worn-out", pollution, string.format("%.2f", damage), data.multiplier})
|
|
elseif alert == 4 then
|
|
self:AddAlert(player, "yellow-more-toxin", {"Accumulated-toxins", string.format("%.2f", damage), data.multiplier})
|
|
else
|
|
self:RemoveAlert(player, "yellow-gas-mask")
|
|
self:RemoveAlert(player, "red-gas-mask")
|
|
self:RemoveAlert(player, "red-armor")
|
|
end
|
|
end
|
|
|
|
function Toxic:OnTick()
|
|
for _, player in pairs(game.players) do
|
|
if (player.connected == true and player.character ~= nil) then
|
|
self:DamageForPlayer(player)
|
|
--local alert = 0
|
|
--local pollution = self:GetPollution(player)
|
|
--local newPollution = 0
|
|
--local absorb = conf:MinPollution()
|
|
--local armorCount, armor = self:GetPlayerArmor(player)
|
|
--if armorCount > 0 then absorb = absorb + self:GetArmorAbsorb(armor.name) end
|
|
--if (pollution > absorb) then
|
|
-- newPollution = pollution - absorb
|
|
--end
|
|
--if (newPollution > 0) then
|
|
-- self:IncTimeMultiplier(player.name, conf:TickInterval())
|
|
--else
|
|
-- self:DecTimeMultiplier(player.name, conf:TickInterval())
|
|
--end
|
|
|
|
|
|
--local damage = self:CalculateDamage(player.name, newPollution, armor)
|
|
--if damage > 20 then
|
|
-- alert = 2
|
|
--else
|
|
-- alert = 1
|
|
--end
|
|
--if damage > 0 then
|
|
-- if armor then
|
|
-- if (armor.durability / game.item_prototypes[armor.name].durability < 0.25 and armorCount == 1) then
|
|
-- alert = 3
|
|
-- end
|
|
-- armor.drain_durability(damage)
|
|
-- self:EquipArmorFromInventory(player, armor)
|
|
-- else
|
|
-- alert = 2
|
|
-- damage = math.floor(newPollution / absorb)
|
|
-- if (player.character.health > damage) then
|
|
-- player.character.damage(damage, game.forces.pollution, "toxin")
|
|
-- else
|
|
-- player.character.die(game.forces.pollution, global.killer)
|
|
-- self:IncKills(player.name)
|
|
-- end
|
|
-- end
|
|
--end
|
|
--if alert == 1 then
|
|
-- self:AddAlert(player, "yellow-gas-mask", {"High-pollution", pollution, string.format("%.2f", damage)})
|
|
--elseif alert == 2 then
|
|
-- self:AddAlert(player, "red-gas-mask", {"Very-high-pollution", pollution, string.format("%.2f", damage)})
|
|
--elseif alert == 3 then
|
|
-- self:AddAlert(player, "red-armor", {"Armor-worn-out", pollution, string.format("%.2f", damage)})
|
|
--else
|
|
-- self:RemoveAlert(player, "yellow-gas-mask")
|
|
-- self:RemoveAlert(player, "red-gas-mask")
|
|
-- self:RemoveAlert(player, "red-armor")
|
|
--end
|
|
end
|
|
end
|
|
end
|
|
|
|
function Toxic:OnPlayerDied(event)
|
|
local player = game.players[event.player_index]
|
|
local entity = event.cause
|
|
if (entity ~= nil and entity.name == "pollution") then
|
|
self:IncKills(player.name)
|
|
self:ClearTimeMultiplier(player.name)
|
|
end
|
|
end
|
|
|
|
function Toxic:OnPlayerRespawned(event)
|
|
local player = game.players[event.player_index]
|
|
local inv = player.get_inventory(defines.inventory.character_ammo)
|
|
inv.insert({name="respirator", count=1})
|
|
end |