mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-02-03 13:11:21 +02:00
Update Frontier to V2 (#1420)
* Frontier V2 * Shortcuts default disabled
This commit is contained in:
parent
8ccf00fc6d
commit
a1f1b81ca4
@ -385,6 +385,8 @@ stds.factorio_control = {
|
||||
"reload_script",
|
||||
"remove_offline_players",
|
||||
"remove_path",
|
||||
"reset_game_state",
|
||||
"reset_time_played",
|
||||
"save_atlas",
|
||||
"server_save",
|
||||
"set_game_state",
|
||||
|
@ -461,6 +461,14 @@ global.config = {
|
||||
max_lifetime = 20 * 60, -- 20s
|
||||
min_length = 40, -- messages shorter than this value will still be displayed for the min_lifetime
|
||||
max_length = 92, -- messages longer than this value will be trimmed
|
||||
},
|
||||
player_shortcuts = {
|
||||
enabled = false,
|
||||
shortcuts = {
|
||||
auto_stash = true,
|
||||
clear_corpses = true,
|
||||
battery_charge = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,6 +168,9 @@ end
|
||||
if config.radio.enabled or _DEBUG then
|
||||
require 'features.gui.radio'
|
||||
end
|
||||
if config.player_shortcuts.enabled then
|
||||
require 'features.gui.shortcuts'
|
||||
end
|
||||
if config.score.enabled then
|
||||
require 'features.gui.score'
|
||||
end
|
||||
|
647
features/auto_stash.lua
Normal file
647
features/auto_stash.lua
Normal file
@ -0,0 +1,647 @@
|
||||
local Color = require 'resources.color_presets'
|
||||
local Global = require 'utils.global'
|
||||
local Event = require 'utils.event'
|
||||
|
||||
local floor = math.floor
|
||||
|
||||
local this = {
|
||||
floating_text_y_offsets = {},
|
||||
whitelist = {},
|
||||
insert_to_neutral_chests = false,
|
||||
insert_into_furnace = false,
|
||||
insert_into_wagon = false,
|
||||
bottom_button = false,
|
||||
small_radius = 2,
|
||||
limit_containers = 50,
|
||||
init_whitelist = false,
|
||||
}
|
||||
|
||||
local Public = {}
|
||||
|
||||
Global.register(this, function(tbl) this = tbl end)
|
||||
|
||||
local bps_blacklist = { ['blueprint-book'] = true, ['blueprint'] = true }
|
||||
|
||||
local function create_floaty_text(surface, position, name, count)
|
||||
if this.floating_text_y_offsets[position.x .. '_' .. position.y] then
|
||||
this.floating_text_y_offsets[position.x .. '_' .. position.y] =
|
||||
this.floating_text_y_offsets[position.x .. '_' .. position.y] - 0.5
|
||||
else
|
||||
this.floating_text_y_offsets[position.x .. '_' .. position.y] = 0
|
||||
end
|
||||
surface.create_entity({
|
||||
name = 'flying-text',
|
||||
position = { position.x, position.y + this.floating_text_y_offsets[position.x .. '_' .. position.y] },
|
||||
text = { '', '-', count, ' ', game.item_prototypes[name].localised_name },
|
||||
color = { r = 255, g = 255, b = 255 },
|
||||
})
|
||||
end
|
||||
|
||||
local function prepare_floaty_text(list, surface, position, name, count)
|
||||
local str = surface.index .. ',' .. position.x .. ',' .. position.y
|
||||
if not list[str] then
|
||||
list[str] = {}
|
||||
end
|
||||
if not list[str][name] then
|
||||
list[str][name] = { surface = surface, position = position, count = 0 }
|
||||
end
|
||||
list[str][name].count = list[str][name].count + count
|
||||
end
|
||||
|
||||
local function chest_is_valid(chest)
|
||||
for _, e in pairs(chest.surface.find_entities_filtered({
|
||||
type = { 'inserter', 'loader' },
|
||||
area = { { chest.position.x - 1, chest.position.y - 1 }, { chest.position.x + 1, chest.position.y + 1 } },
|
||||
})) do
|
||||
if e.name ~= 'long-handed-inserter' then
|
||||
if e.position.x == chest.position.x then
|
||||
if e.direction == 0 or e.direction == 4 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if e.position.y == chest.position.y then
|
||||
if e.direction == 2 or e.direction == 6 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local i1 = chest.surface.find_entity('long-handed-inserter', { chest.position.x - 2, chest.position.y })
|
||||
if i1 then
|
||||
if i1.direction == 2 or i1.direction == 6 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local i2 = chest.surface.find_entity('long-handed-inserter', { chest.position.x + 2, chest.position.y })
|
||||
if i2 then
|
||||
if i2.direction == 2 or i2.direction == 6 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
local i3 = chest.surface.find_entity('long-handed-inserter', { chest.position.x, chest.position.y - 2 })
|
||||
if i3 then
|
||||
if i3.direction == 0 or i3.direction == 4 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
local i4 = chest.surface.find_entity('long-handed-inserter', { chest.position.x, chest.position.y + 2 })
|
||||
if i4 then
|
||||
if i4.direction == 0 or i4.direction == 4 then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function sort_entities_by_distance(position, entities)
|
||||
local t = {}
|
||||
local distance
|
||||
local index
|
||||
local size_of_entities = #entities
|
||||
if size_of_entities < 2 then
|
||||
return entities
|
||||
end
|
||||
|
||||
for _, entity in pairs(entities) do
|
||||
distance = (entity.position.x - position.x) ^ 2 + (entity.position.y - position.y) ^ 2
|
||||
index = floor(distance) + 1
|
||||
if not t[index] then
|
||||
t[index] = {}
|
||||
end
|
||||
table.insert(t[index], entity)
|
||||
end
|
||||
|
||||
local i = 0
|
||||
local containers = {}
|
||||
for _, range in pairs(t) do
|
||||
for _, entity in pairs(range) do
|
||||
i = i + 1
|
||||
if i >= (this.limit_containers or 50) then
|
||||
return containers
|
||||
end
|
||||
containers[i] = entity
|
||||
end
|
||||
end
|
||||
|
||||
return containers
|
||||
end
|
||||
|
||||
local function get_nearby_chests(player, a, furnace, wagon)
|
||||
local r = player.force.character_reach_distance_bonus + 10
|
||||
local r_square = r * r
|
||||
local chests, inventories = {}, {}
|
||||
local size_of_chests = 0
|
||||
local area = { { player.position.x - r, player.position.y - r }, { player.position.x + r, player.position.y + r } }
|
||||
|
||||
area = a or area
|
||||
|
||||
local container_type = { 'container', 'logistic-container', 'linked-container' }
|
||||
local inventory_type = defines.inventory.chest
|
||||
local containers = {}
|
||||
local i = 0
|
||||
|
||||
if furnace then
|
||||
container_type = { 'furnace' }
|
||||
inventory_type = defines.inventory.furnace_source
|
||||
end
|
||||
if wagon then
|
||||
container_type = { 'cargo-wagon', 'logistic-container' }
|
||||
inventory_type = defines.inventory.cargo_wagon
|
||||
end
|
||||
|
||||
local forces = player.force
|
||||
if this.insert_to_neutral_chests then
|
||||
forces = { player.force, 'neutral' }
|
||||
end
|
||||
|
||||
for _, e in pairs(player.surface.find_entities_filtered({ type = container_type, area = area, force = forces })) do
|
||||
if ((player.position.x - e.position.x) ^ 2 + (player.position.y - e.position.y) ^ 2) <= r_square then
|
||||
i = i + 1
|
||||
containers[i] = e
|
||||
end
|
||||
end
|
||||
|
||||
containers = sort_entities_by_distance(player.position, containers)
|
||||
for _, entity in pairs(containers) do
|
||||
size_of_chests = size_of_chests + 1
|
||||
chests[size_of_chests] = entity
|
||||
inventories[size_of_chests] = entity.get_inventory(inventory_type)
|
||||
end
|
||||
return { chest = chests, inventory = inventories }
|
||||
end
|
||||
|
||||
local function insert_to_furnace(player_inventory, chests, name, count, floaty_text_list)
|
||||
local try = 0
|
||||
|
||||
local to_insert = floor(count / #chests.chest)
|
||||
if to_insert <= 0 then
|
||||
if count > 0 then
|
||||
to_insert = count
|
||||
else
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local variate = count % #chests.chest
|
||||
local chests_available = #chests.chest
|
||||
local tries = #chests.chest
|
||||
|
||||
::retry::
|
||||
|
||||
-- Attempt to store into furnaces.
|
||||
for chestnr, chest in pairs(chests.chest) do
|
||||
local chest_inventory = chests.inventory[chestnr]
|
||||
local amount = to_insert
|
||||
if variate > 0 then
|
||||
amount = amount + 1
|
||||
variate = variate - 1
|
||||
end
|
||||
if amount <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
if chest_inventory then
|
||||
if (chest.type == 'furnace' or chest.type == 'assembling-machine') then
|
||||
if name == 'stone' then
|
||||
local valid_to_insert = (amount % 2 == 0)
|
||||
if valid_to_insert then
|
||||
if chest_inventory.can_insert({ name = name, count = amount }) then
|
||||
local inserted_count = chest_inventory.insert({ name = name, count = amount })
|
||||
if inserted_count < 0 then
|
||||
return
|
||||
end
|
||||
player_inventory.remove({ name = name, count = inserted_count })
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
count = count - inserted_count
|
||||
if count <= 0 then
|
||||
return
|
||||
end
|
||||
end
|
||||
else
|
||||
try = try + 1
|
||||
if try <= tries then
|
||||
chests_available = chests_available - 1
|
||||
to_insert = floor(count / chests_available)
|
||||
variate = count % chests_available
|
||||
goto retry
|
||||
end
|
||||
end
|
||||
else
|
||||
if chest_inventory.can_insert({ name = name, count = amount }) then
|
||||
local inserted_count = chest_inventory.insert({ name = name, count = amount })
|
||||
if inserted_count < 0 then
|
||||
return
|
||||
end
|
||||
player_inventory.remove({ name = name, count = inserted_count })
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
count = count - inserted_count
|
||||
if count <= 0 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
to_insert = floor(count / #chests.chest)
|
||||
variate = count % #chests.chest
|
||||
|
||||
for _, chest in pairs(chests.chest) do -- fuel
|
||||
if chest.type == 'furnace' or chest.type == 'assembling-machine' then
|
||||
local amount = to_insert
|
||||
if variate > 0 then
|
||||
amount = amount + 1
|
||||
variate = variate - 1
|
||||
end
|
||||
if amount <= 0 then
|
||||
return
|
||||
end
|
||||
local chest_inventory = chest.get_inventory(defines.inventory.chest)
|
||||
if chest_inventory and chest_inventory.can_insert({ name = name, count = amount }) then
|
||||
local inserted_count = chest_inventory.insert({ name = name, count = amount })
|
||||
if inserted_count < 0 then
|
||||
return
|
||||
end
|
||||
player_inventory.remove({ name = name, count = inserted_count })
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
count = count - inserted_count
|
||||
if count <= 0 then
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function insert_into_wagon(stack, chests, name, floaty_text_list)
|
||||
-- Attempt to load filtered cargo wagon
|
||||
for chestnr, chest in pairs(chests.chest) do
|
||||
if chest.type == 'cargo-wagon' then
|
||||
local chest_inventory = chests.inventory[chestnr]
|
||||
if chest_inventory.can_insert(stack) then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function insert_into_wagon_filtered(stack, chests, name, floaty_text_list)
|
||||
-- Attempt to load filtered cargo wagon
|
||||
for chestnr, chest in pairs(chests.chest) do
|
||||
if chest.type == 'cargo-wagon' then
|
||||
local chest_inventory = chests.inventory[chestnr]
|
||||
for index = 1, 40 do
|
||||
if chest_inventory.can_insert(stack) then
|
||||
if chest_inventory.get_filter(index) ~= nil then
|
||||
local n = chest_inventory.get_filter(index)
|
||||
if n == name then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Attempt to load filtered slots
|
||||
for chestnr, chest in pairs(chests.chest) do
|
||||
if chest.type == 'logistic-container' then
|
||||
local chest_inventory = chests.inventory[chestnr]
|
||||
for index = 1, chest.request_slot_count do
|
||||
if chest_inventory.can_insert(stack) then
|
||||
if chest.get_request_slot(index) ~= nil then
|
||||
local n = chest.get_request_slot(index)
|
||||
if n and n.name == name then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function insert_item_into_chest(stack, chests, filtered_chests, name, floaty_text_list, previous_insert)
|
||||
local container = { ['container'] = true, ['logistic-container'] = true, ['linked-container'] = true }
|
||||
-- Attemp to store in chest that stored last same item
|
||||
if previous_insert.name == name and previous_insert.full ~= nil then
|
||||
local chest_inventory = chests.inventory[previous_insert.full]
|
||||
if chest_inventory and chest_inventory.can_insert(stack) then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chests.chest[previous_insert.full].surface,
|
||||
chests.chest[previous_insert.full].position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return previous_insert.full
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Attempt to store in req slots that are filtered
|
||||
for chestnr, chest in pairs(chests.chest) do
|
||||
if chest.type == 'logistic-container' then
|
||||
local chest_inventory = chests.inventory[chestnr]
|
||||
for index = 1, chest.request_slot_count do
|
||||
if chest_inventory.can_insert(stack) then
|
||||
if chest.get_request_slot(index) ~= nil then
|
||||
local n = chest.get_request_slot(index)
|
||||
if n and n.name == name then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Attempt to store in chests that already have the same item.
|
||||
for chestnr, chest in pairs(chests.chest) do
|
||||
if container[chest.type] then
|
||||
if chest.request_slot_count and chest.request_slot_count > 0 then
|
||||
goto continue
|
||||
end
|
||||
local chest_inventory = chests.inventory[chestnr]
|
||||
if chest_inventory and chest_inventory.find_item_stack(stack.name) then
|
||||
if chest_inventory.can_insert(stack) then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
-- Attempt to store in empty chests.
|
||||
for chestnr, chest in pairs(filtered_chests.chest) do
|
||||
if container[chest.type] then
|
||||
if chest.request_slot_count and chest.request_slot_count > 0 then
|
||||
goto continue
|
||||
end
|
||||
local chest_inventory = filtered_chests.inventory[chestnr]
|
||||
if not chest_inventory then
|
||||
break
|
||||
end
|
||||
local count = chest_inventory.get_item_count() == 0
|
||||
if count then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
local item_prototypes = game.item_prototypes
|
||||
|
||||
-- Attempt to store in chests with same item subgroup.
|
||||
local item_subgroup = game.item_prototypes[name].subgroup.name
|
||||
if item_subgroup then
|
||||
for chestnr, chest in pairs(filtered_chests.chest) do
|
||||
if chest.request_slot_count and chest.request_slot_count > 0 then
|
||||
goto continue
|
||||
end
|
||||
if container[chest.type] then
|
||||
local chest_inventory = filtered_chests.inventory[chestnr]
|
||||
if not chest_inventory then
|
||||
break
|
||||
end
|
||||
local content = chest_inventory.get_contents()
|
||||
if chest_inventory.can_insert(stack) then
|
||||
for equal_name, _ in pairs(content) do
|
||||
local t = item_prototypes[equal_name]
|
||||
if t and t.subgroup.name == item_subgroup then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
-- Attempt to store in mixed chests.
|
||||
for chestnr, chest in pairs(filtered_chests.chest) do
|
||||
if container[chest.type] then
|
||||
if chest.request_slot_count and chest.request_slot_count > 0 then
|
||||
goto continue
|
||||
end
|
||||
local chest_inventory = filtered_chests.inventory[chestnr]
|
||||
if not chest_inventory then
|
||||
break
|
||||
end
|
||||
if chest_inventory.can_insert(stack) then
|
||||
local inserted_count = chest_inventory.insert(stack)
|
||||
stack.count = stack.count - inserted_count
|
||||
prepare_floaty_text(floaty_text_list, chest.surface, chest.position, name, inserted_count)
|
||||
if stack.count <= 0 then
|
||||
return chestnr
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function whitelist()
|
||||
local resources = game.entity_prototypes
|
||||
local items = game.item_prototypes
|
||||
this.whitelist = {}
|
||||
for k, _ in pairs(resources) do
|
||||
if resources[k] and resources[k].type == 'resource' and resources[k].mineable_properties then
|
||||
if resources[k].mineable_properties.products and resources[k].mineable_properties.products[1] then
|
||||
local r = resources[k].mineable_properties.products[1].name
|
||||
this.whitelist[r] = true
|
||||
elseif resources[k].mineable_properties.products and resources[k].mineable_properties.products[2] then
|
||||
local r = resources[k].mineable_properties.products[2].name
|
||||
this.whitelist[r] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for k, _ in pairs(items) do
|
||||
if items[k] and items[k].group.name == 'resource-refining' then
|
||||
local r = items[k].name
|
||||
this.whitelist[r] = true
|
||||
end
|
||||
end
|
||||
|
||||
this.init_whitelist = true
|
||||
end
|
||||
|
||||
function Public.auto_stash(player, event)
|
||||
if not this.init_whitelist then
|
||||
whitelist()
|
||||
end
|
||||
|
||||
local button = event.button
|
||||
local ctrl = event.control
|
||||
local shift = event.shift
|
||||
if not (player and player.valid) then
|
||||
return
|
||||
end
|
||||
if not (player.character and player.character.valid) then
|
||||
player.print({'auto_stash.err_no_character'}, Color.warning)
|
||||
return
|
||||
end
|
||||
local inventory = player.get_main_inventory()
|
||||
if inventory.is_empty() then
|
||||
player.print({'auto_stash.err_no_inventory'}, Color.warning)
|
||||
return
|
||||
end
|
||||
|
||||
local floaty_text_list = {}
|
||||
local chests = { chest = {}, inventory = {} }
|
||||
local r = this.small_radius
|
||||
local area = { { player.position.x - r, player.position.y - r }, { player.position.x + r, player.position.y + r } }
|
||||
if ctrl then
|
||||
if button == defines.mouse_button_type.right and this.insert_into_furnace then
|
||||
chests = get_nearby_chests(player, nil, true, false)
|
||||
end
|
||||
elseif shift then
|
||||
if button == defines.mouse_button_type.right and this.insert_into_wagon or button == defines.mouse_button_type.left and
|
||||
this.insert_into_wagon then
|
||||
chests = get_nearby_chests(player, area, false, true)
|
||||
end
|
||||
else
|
||||
chests = get_nearby_chests(player)
|
||||
end
|
||||
|
||||
if not chests.chest or not chests.chest[1] then
|
||||
player.print({'auto_stash.err_no_container'}, Color.warning)
|
||||
return
|
||||
end
|
||||
|
||||
local filtered_chests = { chest = {}, inventory = {} }
|
||||
for index, e in pairs(chests.chest) do
|
||||
if chest_is_valid(e) then
|
||||
filtered_chests.chest[index] = e
|
||||
filtered_chests.inventory[index] = chests.inventory[index]
|
||||
end
|
||||
end
|
||||
|
||||
this.floating_text_y_offsets = {}
|
||||
|
||||
local hotbar_items = {}
|
||||
for i = 1, 100, 1 do
|
||||
local prototype = player.get_quick_bar_slot(i)
|
||||
if prototype then
|
||||
hotbar_items[prototype.name] = true
|
||||
end
|
||||
end
|
||||
|
||||
local furnaceList = { ['coal'] = 0, ['iron-ore'] = 0, ['copper-ore'] = 0, ['stone'] = 0 }
|
||||
|
||||
local full_insert = { full = nil, name = nil }
|
||||
for i = #inventory, 1, -1 do
|
||||
if not inventory[i].valid_for_read then
|
||||
goto continue
|
||||
end
|
||||
local name = inventory[i].name
|
||||
local is_resource = this.whitelist[name]
|
||||
if not hotbar_items[name] and not bps_blacklist[name] then
|
||||
if ctrl and this.insert_into_furnace then
|
||||
if button == defines.mouse_button_type.right then
|
||||
if is_resource then
|
||||
furnaceList[name] = (furnaceList[name] or 0) + inventory[i].count
|
||||
end
|
||||
end
|
||||
elseif shift and this.insert_into_wagon then -- insert into wagon
|
||||
if button == defines.mouse_button_type.right then -- insert all ores into wagon
|
||||
if is_resource then
|
||||
full_insert = { full = insert_into_wagon(inventory[i], chests, name, floaty_text_list), name = name }
|
||||
end
|
||||
end
|
||||
if button == defines.mouse_button_type.left then -- insert all filtered into wagon
|
||||
full_insert = { full = insert_into_wagon_filtered(inventory[i], chests, name, floaty_text_list), name = name }
|
||||
end
|
||||
elseif button == defines.mouse_button_type.right then -- only ores to nearby chests
|
||||
if is_resource then
|
||||
full_insert = {
|
||||
full = insert_item_into_chest(inventory[i], chests, filtered_chests, name, floaty_text_list, full_insert),
|
||||
name = name,
|
||||
}
|
||||
end
|
||||
elseif button == defines.mouse_button_type.left then -- all items to nearby chests
|
||||
full_insert = {
|
||||
full = insert_item_into_chest(inventory[i], chests, filtered_chests, name, floaty_text_list, full_insert),
|
||||
name = name,
|
||||
}
|
||||
end
|
||||
if not full_insert.success then
|
||||
hotbar_items[#hotbar_items + 1] = name
|
||||
end
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
for furnaceName, furnaceCount in pairs(furnaceList) do
|
||||
insert_to_furnace(inventory, chests, furnaceName, furnaceCount, floaty_text_list)
|
||||
end
|
||||
|
||||
for _, texts in pairs(floaty_text_list) do
|
||||
for name, text in pairs(texts) do
|
||||
create_floaty_text(text.surface, text.position, name, text.count)
|
||||
end
|
||||
end
|
||||
|
||||
local c = this.floating_text_y_offsets
|
||||
for k, _ in pairs(c) do
|
||||
this.floating_text_y_offsets[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function Public.insert_into_furnace(value)
|
||||
this.insert_into_furnace = value or false
|
||||
end
|
||||
|
||||
function Public.insert_into_wagon(value)
|
||||
this.insert_into_wagon = value or false
|
||||
end
|
||||
|
||||
function Public.limit_containers(value)
|
||||
this.limit_containers = value or 50
|
||||
end
|
||||
|
||||
function Public.insert_to_neutral_chests(value)
|
||||
this.insert_to_neutral_chests = value or false
|
||||
end
|
||||
|
||||
Event.on_configuration_changed(whitelist)
|
||||
Event.on_init(whitelist)
|
||||
|
||||
return Public
|
93
features/battery_charge.lua
Normal file
93
features/battery_charge.lua
Normal file
@ -0,0 +1,93 @@
|
||||
local Color = require 'resources.color_presets'
|
||||
local Global = require 'utils.global'
|
||||
|
||||
local this = {
|
||||
radius = 13
|
||||
}
|
||||
Global.register(this, function(tbl) this = tbl end)
|
||||
|
||||
local Public = {}
|
||||
|
||||
local function discharge_accumulators(surface, position, force, power_needs)
|
||||
local accumulators = surface.find_entities_filtered {
|
||||
name = 'accumulator',
|
||||
force = force,
|
||||
position = position,
|
||||
radius = this.radius,
|
||||
}
|
||||
local power_drained = 0
|
||||
power_needs = power_needs * 1
|
||||
for _, accu in pairs(accumulators) do
|
||||
if accu.valid then
|
||||
if accu.energy > 3000000 and power_needs > 0 then
|
||||
if power_needs >= 2000000 then
|
||||
power_drained = power_drained + 2000000
|
||||
accu.energy = accu.energy - 2000000
|
||||
power_needs = power_needs - 2000000
|
||||
else
|
||||
power_drained = power_drained + power_needs
|
||||
accu.energy = accu.energy - power_needs
|
||||
end
|
||||
elseif power_needs <= 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return power_drained / 1
|
||||
end
|
||||
|
||||
function Public.recharge(player)
|
||||
if not player.character then
|
||||
player.print({'battery_charge.err_no_character'}, Color.warning)
|
||||
return
|
||||
end
|
||||
local armor_inventory = player.get_inventory(defines.inventory.character_armor)
|
||||
if not armor_inventory.valid then
|
||||
player.print({'battery_charge.err_no_armor'}, Color.warning)
|
||||
return
|
||||
end
|
||||
local armor = armor_inventory[1]
|
||||
if not armor.valid_for_read then
|
||||
player.print({'battery_charge.err_no_armor'}, Color.warning)
|
||||
return
|
||||
end
|
||||
local grid = armor.grid
|
||||
if not grid or not grid.valid then
|
||||
player.print({'battery_charge.err_no_armor'}, Color.warning)
|
||||
return
|
||||
end
|
||||
|
||||
local entities = player.surface.find_entities_filtered {
|
||||
name = 'accumulator',
|
||||
force = player.force,
|
||||
position = player.position,
|
||||
radius = this.radius,
|
||||
}
|
||||
if not entities or not next(entities) then
|
||||
player.print({'battery_charge.err_no_accumulators'}, Color.warning)
|
||||
return
|
||||
end
|
||||
|
||||
local equip = grid.equipment
|
||||
for _, piece in pairs(equip) do
|
||||
if piece.valid and piece.generator_power == 0 then
|
||||
local energy_needs = piece.max_energy - piece.energy
|
||||
if energy_needs > 0 then
|
||||
local energy = discharge_accumulators(player.surface, player.position, player.force, energy_needs)
|
||||
if energy > 0 then
|
||||
if piece.energy + energy >= piece.max_energy then
|
||||
piece.energy = piece.max_energy
|
||||
else
|
||||
piece.energy = piece.energy + energy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Public.radius(value)
|
||||
this.radius = value or 13
|
||||
end
|
||||
|
||||
return Public
|
50
features/clear_corpses.lua
Normal file
50
features/clear_corpses.lua
Normal file
@ -0,0 +1,50 @@
|
||||
local Global = require 'utils.global'
|
||||
|
||||
local this = {
|
||||
radius = 128
|
||||
}
|
||||
Global.register(this, function(tbl) this = tbl end)
|
||||
|
||||
local Public = {}
|
||||
|
||||
function Public.clear_corpses(player, args)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local surface = player.surface
|
||||
if not surface or not surface.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local whole_surface = false
|
||||
if args and args.surface then
|
||||
local surface_arg = args.surface:lower()
|
||||
whole_surface = player.admin and (surface_arg == 's' or surface_arg == 'surface')
|
||||
end
|
||||
|
||||
local corpses
|
||||
if whole_surface then
|
||||
corpses = surface.find_entities_filtered({ type = 'corpse' })
|
||||
else
|
||||
local pos = player.position
|
||||
local area = { { pos.x - this.radius, pos.y - this.radius }, { pos.x + this.radius, pos.y + this.radius } }
|
||||
corpses = surface.find_entities_filtered({ type = 'corpse', area = area })
|
||||
end
|
||||
|
||||
for i = 1, #corpses do
|
||||
corpses[i].destroy()
|
||||
end
|
||||
|
||||
if #corpses > 0 then
|
||||
player.print({ 'clear_corpses.count', #corpses })
|
||||
else
|
||||
player.print({ 'clear_corpses.clear' })
|
||||
end
|
||||
end
|
||||
|
||||
function Public.radius(value)
|
||||
this.radius = value or 128
|
||||
end
|
||||
|
||||
return Public
|
111
features/enemy_turret.lua
Normal file
111
features/enemy_turret.lua
Normal file
@ -0,0 +1,111 @@
|
||||
local Event = require 'utils.event'
|
||||
local Global = require 'utils.global'
|
||||
local register_on_entity_destroyed = script.register_on_entity_destroyed
|
||||
|
||||
local Public = {}
|
||||
local turrets_map = {}
|
||||
local register_map = {}
|
||||
local primitives = { index = nil }
|
||||
|
||||
Global.register(
|
||||
{
|
||||
turrets_map = turrets_map,
|
||||
register_map = register_map,
|
||||
primitives = primitives,
|
||||
},
|
||||
function(tbl)
|
||||
turrets_map = tbl.turrets_map
|
||||
register_map = tbl.register_map
|
||||
primitives = tbl.primitives
|
||||
end)
|
||||
|
||||
function Public.register(entity, refill_name)
|
||||
if not (entity and entity.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
if not refill_name then
|
||||
return
|
||||
end
|
||||
|
||||
local is_item = game.item_prototypes[refill_name] and true or false
|
||||
local is_fluid = game.fluid_prototypes[refill_name] and true or false
|
||||
|
||||
if not (is_item or is_fluid )then
|
||||
return
|
||||
end
|
||||
|
||||
local destroy_id = register_on_entity_destroyed(entity)
|
||||
local unit_id = entity.unit_number
|
||||
|
||||
local data = {
|
||||
entity = entity,
|
||||
refill = refill_name,
|
||||
is_fluid = is_fluid,
|
||||
destroy_id = destroy_id
|
||||
}
|
||||
|
||||
if data.is_fluid then
|
||||
data.capacity = data.entity.fluidbox.get_capacity(1)
|
||||
else
|
||||
data.item_stack = {
|
||||
name = data.refill,
|
||||
count = game.item_prototypes[data.refill].stack_size
|
||||
}
|
||||
end
|
||||
|
||||
register_map[destroy_id] = unit_id
|
||||
turrets_map[unit_id] = data
|
||||
end
|
||||
|
||||
function Public.remove(entity)
|
||||
local unit_id = entity.unit_number
|
||||
local destroy_id = turrets_map[unit_id].destroy_id
|
||||
|
||||
register_map[destroy_id] = nil
|
||||
turrets_map[unit_id] = nil
|
||||
end
|
||||
|
||||
function Public.reset()
|
||||
for k, _ in pairs(turrets_map) do
|
||||
turrets_map[k] = nil
|
||||
end
|
||||
for k, _ in pairs(register_map) do
|
||||
register_map[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function on_entity_destroyed(event)
|
||||
local destroy_id = event.registration_number
|
||||
local unit_id = event.unit_number
|
||||
|
||||
register_map[destroy_id] = nil
|
||||
turrets_map[unit_id] = nil
|
||||
end
|
||||
Event.add(defines.events.on_entity_destroyed, on_entity_destroyed)
|
||||
|
||||
local function on_tick()
|
||||
if primitives.index ~= nil and turrets_map[primitives.index] == nil then
|
||||
primitives.index = nil
|
||||
return
|
||||
end
|
||||
|
||||
local idx, data = next(turrets_map, primitives.index)
|
||||
if not (data and data.entity and data.entity.valid) then
|
||||
primitives.index = nil
|
||||
return
|
||||
end
|
||||
|
||||
if data.is_fluid then
|
||||
local fb = data.entity.fluidbox[1]
|
||||
fb.name = data.refill
|
||||
fb.amount = data.capacity
|
||||
else
|
||||
data.entity.insert(data.item_stack)
|
||||
end
|
||||
|
||||
primitives.index = idx
|
||||
end
|
||||
Event.add(defines.events.on_tick, on_tick)
|
||||
|
||||
return Public
|
283
features/gui/shortcuts.lua
Normal file
283
features/gui/shortcuts.lua
Normal file
@ -0,0 +1,283 @@
|
||||
local Gui = require 'utils.gui'
|
||||
local Event = require 'utils.event'
|
||||
local Global = require 'utils.global'
|
||||
local Config = require 'config'.player_shortcuts
|
||||
|
||||
local AutoStash = require 'features.auto_stash'
|
||||
local ClearCorpses = require 'features.clear_corpses'
|
||||
local BatteryCharge = require 'features.battery_charge'
|
||||
|
||||
local player_preferences = {}
|
||||
Global.register(player_preferences, function(tbl) player_preferences = tbl end)
|
||||
|
||||
local main_button_name = Gui.uid_name()
|
||||
local main_frame_name = Gui.uid_name()
|
||||
local settings_button_name = Gui.uid_name()
|
||||
local checkbox_action_name = Gui.uid_name()
|
||||
local shortcut_action_name = Gui.uid_name()
|
||||
|
||||
local shortcut_buttons = {
|
||||
auto_stash = {
|
||||
name = 'auto_stash',
|
||||
caption = {'player_shortcuts.auto_stash_caption'},
|
||||
sprite = 'item/wooden-chest',
|
||||
tooltip = {'player_shortcuts.auto_stash_tooltip'},
|
||||
action = AutoStash.auto_stash,
|
||||
},
|
||||
battery_charge = {
|
||||
name = 'battery_charge',
|
||||
caption = {'player_shortcuts.battery_charge_caption'},
|
||||
sprite = 'item/battery-mk2-equipment',
|
||||
tooltip = {'player_shortcuts.battery_charge_tooltip'},
|
||||
action = BatteryCharge.recharge,
|
||||
},
|
||||
clear_corpses = {
|
||||
name = 'clear_corpses',
|
||||
caption = {'player_shortcuts.clear_corpses_caption'},
|
||||
sprite = 'entity/big-biter',
|
||||
tooltip = {'player_shortcuts.clear_corpses_tooltip'},
|
||||
action = ClearCorpses.clear_corpses,
|
||||
},
|
||||
}
|
||||
|
||||
local Public = {}
|
||||
Public.main_button_name = main_button_name
|
||||
Public.main_frame_name = main_frame_name
|
||||
|
||||
local function enabled_shortcuts()
|
||||
local shortcuts = {}
|
||||
for k, v in pairs(shortcut_buttons) do
|
||||
if Config.shortcuts[k] then
|
||||
shortcuts[k] = v
|
||||
end
|
||||
end
|
||||
return shortcuts
|
||||
end
|
||||
|
||||
local function get_player_preferences(player)
|
||||
local player_data = player_preferences[player.name]
|
||||
if not player_data then
|
||||
player_data = {}
|
||||
player_preferences[player.name] = player_data
|
||||
end
|
||||
return player_data
|
||||
end
|
||||
|
||||
local function add_shortcut_selection_row(player, parent, child)
|
||||
local player_data = get_player_preferences(player)
|
||||
if player_data[child.name] == nil then
|
||||
player_data[child.name] = true
|
||||
end
|
||||
|
||||
local row = parent.add { type = 'frame', style = 'shortcut_selection_row' }
|
||||
Gui.set_style(row, { horizontally_stretchable = true, vertically_stretchable = false })
|
||||
|
||||
local icon = row.add {
|
||||
type = 'sprite-button',
|
||||
style = 'transparent_slot',
|
||||
sprite = child.sprite,
|
||||
tooltip = child.tooltip,
|
||||
}
|
||||
Gui.set_style(icon, { width = 20, height = 20 })
|
||||
|
||||
local checkbox = row.add {
|
||||
type = 'checkbox',
|
||||
caption = child.caption,
|
||||
state = player_data[child.name],
|
||||
tags = { action = checkbox_action_name, name = child.name },
|
||||
}
|
||||
Gui.set_style(checkbox, { minimal_width = 160, horizontally_stretchable = true })
|
||||
end
|
||||
|
||||
function Public.on_player_created(player)
|
||||
if not Config.enabled then
|
||||
return
|
||||
end
|
||||
|
||||
local b = Gui.add_top_element(player, {
|
||||
type = 'sprite-button',
|
||||
name = main_button_name,
|
||||
sprite = 'utility/hand_black',
|
||||
tooltip = {'player_shortcuts.info_tooltip'},
|
||||
})
|
||||
b.style.padding = 2
|
||||
end
|
||||
|
||||
function Public.toggle_main_button(player)
|
||||
local main_frame = player.gui.screen[main_frame_name]
|
||||
if main_frame then
|
||||
main_frame.destroy()
|
||||
else
|
||||
Public.get_main_frame(player)
|
||||
end
|
||||
end
|
||||
|
||||
function Public.toggle_shortcuts_settings(player)
|
||||
local frame = Public.get_main_frame(player)
|
||||
frame.children[1].qbip.qbsp.visible = not frame.children[1].qbip.qbsp.visible
|
||||
end
|
||||
|
||||
function Public.get_main_frame(player)
|
||||
local main_frame = player.gui.screen[main_frame_name]
|
||||
if main_frame and main_frame.valid then
|
||||
return main_frame
|
||||
end
|
||||
|
||||
main_frame = player.gui.screen.add {
|
||||
type = 'frame',
|
||||
name = main_frame_name,
|
||||
direction = 'horizontal',
|
||||
style = 'quick_bar_window_frame',
|
||||
}
|
||||
main_frame.auto_center = true
|
||||
|
||||
do -- shortcuts
|
||||
local left_flow = main_frame.add { type = 'flow', direction = 'vertical' }
|
||||
Gui.set_style(left_flow, { horizontally_stretchable = true })
|
||||
|
||||
local settings_scroll_pane = left_flow
|
||||
.add {
|
||||
type = 'frame',
|
||||
name = 'qbip',
|
||||
style = 'quick_bar_inner_panel'
|
||||
}.
|
||||
add {
|
||||
type = 'scroll-pane',
|
||||
name = 'qbsp',
|
||||
style = 'shortcut_bar_selection_scroll_pane',
|
||||
}
|
||||
Gui.set_style(settings_scroll_pane, { horizontally_squashable = false, minimal_width = 40 * table_size(enabled_shortcuts()) })
|
||||
|
||||
for _, s in pairs(enabled_shortcuts()) do
|
||||
add_shortcut_selection_row(player, settings_scroll_pane, s)
|
||||
end
|
||||
settings_scroll_pane.visible = false
|
||||
|
||||
local table_frame = left_flow.add {
|
||||
type = 'frame',
|
||||
name = 'table_frame',
|
||||
direction = 'horizontal',
|
||||
style = 'quick_bar_inner_panel',
|
||||
}
|
||||
Gui.set_style(table_frame, { horizontally_stretchable = true, margin = 0 })
|
||||
|
||||
local table = table_frame.add {
|
||||
type = 'table',
|
||||
name = 'table',
|
||||
column_count = table_size(enabled_shortcuts()),
|
||||
style = 'filter_slot_table',
|
||||
}
|
||||
Gui.set_style(table, { horizontally_stretchable = true })
|
||||
|
||||
local button
|
||||
local player_data = get_player_preferences(player)
|
||||
for button_name, s in pairs(enabled_shortcuts()) do
|
||||
button = table.add {
|
||||
type = 'sprite-button',
|
||||
style = 'quick_bar_slot_button',
|
||||
sprite = s.sprite,
|
||||
hovered_sprite = s.hovered_sprite,
|
||||
tooltip = s.tooltip,
|
||||
tags = { action = shortcut_action_name, name = button_name },
|
||||
}
|
||||
Gui.set_style(button, { font_color = { 165, 165, 165 } })
|
||||
if player_data[button_name] == nil then
|
||||
player_data[button_name] = true
|
||||
end
|
||||
button.visible = player_data[button_name]
|
||||
end
|
||||
end
|
||||
|
||||
do -- settings
|
||||
local right_flow = main_frame.add {
|
||||
type = 'flow',
|
||||
direction = 'vertical',
|
||||
}
|
||||
Gui.set_style(right_flow, { horizontal_align = 'center', padding = 0 })
|
||||
right_flow.drag_target = main_frame
|
||||
|
||||
right_flow.add {
|
||||
type = 'sprite-button',
|
||||
name = settings_button_name,
|
||||
style = 'shortcut_bar_expand_button',
|
||||
sprite = 'utility/expand_dots_white',
|
||||
hovered_sprite = 'utility/expand_dots',
|
||||
clicked_sprite = 'utility/expand_dots',
|
||||
tooltip = {'player_shortcuts.settings_tooltip'},
|
||||
mouse_button_filter = { 'left' },
|
||||
auto_toggle = true,
|
||||
}
|
||||
|
||||
local widget = right_flow.add { type = 'empty-widget', style = 'draggable_space', ignored_by_interaction = true }
|
||||
Gui.set_style(widget, { vertically_stretchable = true, width = 8, margin = 0 })
|
||||
end
|
||||
|
||||
return main_frame
|
||||
end
|
||||
|
||||
Gui.allow_player_to_toggle_top_element_visibility(main_button_name)
|
||||
|
||||
Gui.on_click(main_button_name, function(event)
|
||||
Public.toggle_main_button(event.player)
|
||||
end)
|
||||
|
||||
Gui.on_click(settings_button_name, function(event)
|
||||
Public.toggle_shortcuts_settings(event.player)
|
||||
end)
|
||||
|
||||
Event.add(defines.events.on_gui_checked_state_changed, function(event)
|
||||
local element = event.element
|
||||
if not (element and element.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
local player = game.get_player(event.player_index)
|
||||
if not (player and player.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
local action_name = element.tags and element.tags.action
|
||||
if action_name and action_name == checkbox_action_name then
|
||||
local name = element.tags.name
|
||||
local frame = Public.get_main_frame(player)
|
||||
for _, button in pairs(frame.children[1].table_frame.table.children) do
|
||||
if button.tags.name == name then
|
||||
local player_data = get_player_preferences(player)
|
||||
player_data[name] = element.state
|
||||
button.visible = element.state
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Event.add(defines.events.on_gui_click, function(event)
|
||||
local element = event.element
|
||||
if not (element and element.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
local player = game.get_player(event.player_index)
|
||||
if not (player and player.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
local action_name = element.tags and element.tags.action
|
||||
if action_name and action_name == shortcut_action_name then
|
||||
local name = element.tags.name
|
||||
local shortcut = shortcut_buttons[name]
|
||||
if shortcut and shortcut.action then
|
||||
shortcut.action(player, event)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
Event.add(defines.events.on_player_created, function(event)
|
||||
local player = game.get_player(event.player_index)
|
||||
if not (player and player.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
Public.on_player_created(player)
|
||||
end)
|
||||
|
||||
return Public
|
@ -16,6 +16,7 @@ local tonumber = tonumber
|
||||
local pairs = pairs
|
||||
local floor = math.floor
|
||||
local Ranks = require 'resources.ranks'
|
||||
local ClearCorpses = require 'features.clear_corpses'
|
||||
|
||||
--- Informs the actor that there is no target. Acts as a central place where this message can be changed.
|
||||
local function print_no_target(target_name)
|
||||
@ -215,32 +216,7 @@ local function print_player_info(args, player)
|
||||
end
|
||||
|
||||
local function clear_corpses(args, player)
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local surface = player.surface
|
||||
if not surface or not surface.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local surface_arg = args.surface:lower()
|
||||
local whole_surface = player.admin and (surface_arg == 's' or surface_arg == 'surface')
|
||||
|
||||
local corpses
|
||||
if whole_surface then
|
||||
corpses = surface.find_entities_filtered({ type = 'corpse' })
|
||||
else
|
||||
local pos = player.position
|
||||
local area = { { pos.x - 128, pos.y - 128 }, { pos.x + 128, pos.y + 128 } }
|
||||
corpses = surface.find_entities_filtered({ type = 'corpse', area = area })
|
||||
end
|
||||
|
||||
for i = 1, #corpses do
|
||||
corpses[i].destroy()
|
||||
end
|
||||
|
||||
player.print({ 'redmew_commands.clear_corpses_count', #corpses })
|
||||
ClearCorpses.clear_corpses(player, args)
|
||||
end
|
||||
|
||||
-- Command registrations
|
||||
|
@ -42,7 +42,6 @@ find_player_fail_no_character=Sorry, __1__ doesn't have a character to find.
|
||||
show_rail_block_success=show_rail_block_visualisation set to __1__
|
||||
server_time_fail=Server time is not available, is this game running on a Redmew server?
|
||||
print_version_from_source=This map was created from source code, only releases (zips with names) and server saves have versions
|
||||
clear_corpses_count=__1__ corpses were removed.
|
||||
|
||||
[donator_commands]
|
||||
add_message_fail_not_string=Must enter a value to set as message.
|
||||
@ -203,4 +202,18 @@ missing_research=[technology=landfill] required before landfill can be removed w
|
||||
[spidertron_group_control]
|
||||
none_found=No [img=item.spidertron] found
|
||||
none_selected=No [img=item.spidertron] selected. Drag the planner over [img=item.spidertron] you own.
|
||||
spidertrons_selected=+__1__ [img=item.spidertron]
|
||||
spidertrons_selected=+__1__ [img=item.spidertron]
|
||||
|
||||
[auto_stash]
|
||||
err_no_character=[color=blue][Auto stash][/color] It seems that you are not in the realm of living.
|
||||
err_no_inventory=[color=blue][Auto stash][/color] Inventory is empty.
|
||||
err_no_container=[color=blue][Auto stash][/color] No valid nearby containers found.
|
||||
|
||||
[battery_charge]
|
||||
err_no_character=[color=blue][Battery recharge][/color] It seems that you are not in the realm of living.
|
||||
err_no_armor=[color=blue][Battery recharge][/color] No valid armor to charge was found.
|
||||
err_no_accumulators=[color=blue][Battery recharge][/color] No accumulators nearby.
|
||||
|
||||
[clear_corpses]
|
||||
count=[color=blue][Cleaner][/color] __1__ __plural_for_parameter_1_{1=__1__ corpse|rest=__1__ corpses}__ removed.
|
||||
clear=[color=blue][Cleaner][/color] already clear.
|
||||
|
@ -123,3 +123,13 @@ notify_tooltip=Receive a message when tasks or announcements are created or edit
|
||||
[popup]
|
||||
default_title=NOTICE!
|
||||
confirm_btn=OK
|
||||
|
||||
[player_shortcuts]
|
||||
info_tooltip=[font=default-bold]Player shortcuts[/font] - Toggle your shortcuts bar
|
||||
settings_tooltip=[font=default-bold]Settings[/font] - Customize your shortcut bar
|
||||
clear_corpses_caption=Clear corpses
|
||||
clear_corpses_tooltip=[font=default-bold]Clear corpses[/font] - Clear biter corpses around you
|
||||
battery_charge_caption=Battery recharge
|
||||
battery_charge_tooltip=[font=default-bold]Battery recharge[/font] - Recharge battery equipments in your armor from nearby accumulators.\nThey must have at least 3MJ of energy stored.
|
||||
auto_stash_caption=Auto stash
|
||||
auto_stash_tooltip=[font=default-bold]Auto stash[/font] - Sort your inventory into nearby chests.\n[color=yellow][font=default-bold]LMB[/font][/color]: Everything, excluding quickbar items.\n[color=yellow][font=default-bold]RMB[/font][/color]: Only ores to nearby chests, excluding quickbar items.\n[color=yellow][font=default-bold]CTRL + RMB[/font][/color]: Fill nearby furnaces.\n[color=yellow][font=default-bold]SHIFT + LMB[/font][/color]: Everything onto filtered slots to wagon/chests.\n[color=yellow][font=default-bold]SHIFT + RMB[/font][/color]: Only ores to wagon.
|
||||
|
@ -192,4 +192,6 @@ kraken_eat=[color=purple][Kraken][/color] ate __1__ and was delicious!
|
||||
rocket_launched=[color=blue][Mapkeeper][/color] __1__ __plural_for_parameter_1_{1=rocket|rest=rockets}__ launched, __2__ __plural_for_parameter_2_{1=rocket|rest=rockets}__ to go!
|
||||
add_rocket=Adding __1__ extra __plural_for_parameter_1_{1=launch|rest=launches}__ thanks to the death of __2__. __3__ __plural_for_parameter_3_{1=rocket|rest=rockets}__ to go!
|
||||
loot_chest=[achievement=golem] You find an hidden [color=orange]treasure[/color] beneath the enemy forces
|
||||
empty_rocket=[color=purple][Kraken][/color] The God of the Sea accepts your rocket offer and rewards you with magic fishes
|
||||
empty_rocket=[color=purple][Kraken][/color] The God of the Sea accepts your rocket offer and rewards you with magic fishes
|
||||
rockets_to_launch=Remaining rockets to launch
|
||||
restart=[color=blue][Mapkeeper][/color] Map is restarting in __1__ __plural_for_parameter_1_{1=second|rest=seconds}__
|
@ -1,6 +1,8 @@
|
||||
local b = require 'map_gen.shared.builders'
|
||||
local Color = require 'resources.color_presets'
|
||||
local Command = require 'utils.command'
|
||||
local Event = require 'utils.event'
|
||||
local EnemyTurret = require 'features.enemy_turret'
|
||||
local Global = require 'utils.global'
|
||||
local math = require 'utils.math'
|
||||
local MGSP = require 'resources.map_gen_settings'
|
||||
@ -8,6 +10,7 @@ local Noise = require 'map_gen.shared.simplex_noise'
|
||||
local PriceRaffle = require 'features.price_raffle'
|
||||
local RS = require 'map_gen.shared.redmew_surface'
|
||||
local ScenarioInfo = require 'features.gui.info'
|
||||
local ScoreTracker = require 'utils.score_tracker'
|
||||
local Sounds = require 'utils.sounds'
|
||||
local Toast = require 'features.gui.toast'
|
||||
local Token = require 'utils.token'
|
||||
@ -20,7 +23,10 @@ local math_abs = math.abs
|
||||
local math_ceil = math.ceil
|
||||
local math_floor = math.floor
|
||||
local math_clamp = math.clamp
|
||||
local math_sqrt = math.sqrt
|
||||
local simplex = Noise.d2
|
||||
local SECOND = 60
|
||||
local MINUTE = SECOND * 60
|
||||
|
||||
--[[
|
||||
Scenario info: Frontier
|
||||
@ -52,6 +58,12 @@ Your mission, should you choose to accept it, is to journey through this ribbon
|
||||
In [font=default-bold]Frontier[/font], your wits will be tested as you evolve from a mere survivor to an engineering genius capable of taming the land and launching your final escape. Build a thriving factory, and prepare to conquer both nature and the relentless horde in a race against time. But remember, the frontier waits for no one. Will you make your mark on this alien world or become another lost tale in the void of space?
|
||||
]])
|
||||
ScenarioInfo.set_new_info([[
|
||||
2024-08-10:
|
||||
- Added enemy turrets
|
||||
- Added soft reset
|
||||
- Added shortcuts gui
|
||||
- Added score tracker for rockets to win
|
||||
- Deaths no longer contribute to rocket to win, instead, a rng value is rolled at the beginning of the game
|
||||
2024-07-31:
|
||||
- Added Frontier
|
||||
]])
|
||||
@ -61,6 +73,7 @@ local Config = global.config
|
||||
Config.redmew_surface.enabled = true
|
||||
Config.market.enabled = false
|
||||
Config.player_rewards.enabled = false
|
||||
Config.player_shortcuts.enabled = true
|
||||
Config.player_create.starting_items = {
|
||||
{ name = 'burner-mining-drill', count = 1 },
|
||||
{ name = 'stone-furnace', count = 1 },
|
||||
@ -69,14 +82,16 @@ Config.player_create.starting_items = {
|
||||
{ name = 'wood', count = 1 },
|
||||
}
|
||||
|
||||
local _g = {
|
||||
local this = {
|
||||
rounds = 0,
|
||||
-- Map gen
|
||||
silo_starting_x = 1700,
|
||||
|
||||
height = 36, -- in chunks, height of the ribbon world
|
||||
left_boundary = 8, -- in chunks, distance to water body
|
||||
right_boundary = 11, -- in chunks, distance to wall/biter presence
|
||||
wall_width = 5,
|
||||
wall_width = 5, -- in tiles
|
||||
rock_richness = 1, -- how many rocks/chunk
|
||||
|
||||
ore_base_quantity = 61, -- base ore quantity, everything is scaled up from this
|
||||
ore_chunk_scale = 32, -- sets how fast the ore will increase from spawn, lower = faster
|
||||
@ -89,7 +104,7 @@ local _g = {
|
||||
-- Satellites to win
|
||||
rockets_to_win = 1,
|
||||
rockets_launched = 0,
|
||||
rockets_per_death = 1, -- how many extra launch needed for each death
|
||||
rockets_per_death = 0, -- how many extra launch needed for each death
|
||||
scenario_finished = false,
|
||||
|
||||
-- Loot chests
|
||||
@ -110,12 +125,7 @@ local _g = {
|
||||
invincible = {}
|
||||
}
|
||||
|
||||
if _DEBUG then
|
||||
_g.silo_starting_x = 30
|
||||
_g.rockets_to_win = 3
|
||||
end
|
||||
|
||||
Global.register(_g, function(tbl) _g = tbl end)
|
||||
Global.register(this, function(tbl) this = tbl end)
|
||||
|
||||
local noise_weights = {
|
||||
{ modifier = 0.0042, weight = 1.000 },
|
||||
@ -124,6 +134,96 @@ local noise_weights = {
|
||||
}
|
||||
local mixed_ores = { 'iron-ore', 'copper-ore', 'iron-ore', 'stone', 'copper-ore', 'iron-ore', 'copper-ore', 'iron-ore', 'coal', 'iron-ore', 'copper-ore', 'iron-ore', 'stone', 'copper-ore', 'coal'}
|
||||
|
||||
local Main = {
|
||||
events = {
|
||||
on_game_started = Event.generate_event_name('on_game_started'),
|
||||
on_game_finished = Event.generate_event_name('on_game_finished'),
|
||||
}
|
||||
}
|
||||
|
||||
local rocket_launches_name = 'rockets-launches-frontier'
|
||||
local global_to_show = Config.score.global_to_show
|
||||
global_to_show[#global_to_show + 1] = rocket_launches_name
|
||||
ScoreTracker.register(rocket_launches_name, {'frontier.rockets_to_launch'}, '[img=item.rocket-silo]')
|
||||
|
||||
local escape_player = false
|
||||
|
||||
-- == LOBBY ===================================================================
|
||||
|
||||
local Lobby = {}
|
||||
|
||||
Lobby.enabled = false
|
||||
Lobby.name = 'nauvis'
|
||||
Lobby.mgs = {
|
||||
water = 0,
|
||||
default_enable_all_autoplace_controls = false,
|
||||
width = 64,
|
||||
height = 64,
|
||||
peaceful_mode = true,
|
||||
}
|
||||
|
||||
function Lobby.get_surface()
|
||||
local surface = game.get_surface(Lobby.name)
|
||||
if not surface then
|
||||
surface = game.create_surface(Lobby.name, Lobby.mgs)
|
||||
end
|
||||
return surface
|
||||
end
|
||||
|
||||
function Lobby.teleport_to(player)
|
||||
for k = 1, player.get_max_inventory_index() do
|
||||
local inv = player.get_inventory(k)
|
||||
if inv and inv.valid then
|
||||
inv.clear()
|
||||
end
|
||||
end
|
||||
|
||||
local surface = Lobby.get_surface()
|
||||
local position = surface.find_non_colliding_position('character', {0, 0}, 0, 0.2)
|
||||
player.teleport(position, surface, true)
|
||||
end
|
||||
|
||||
function Lobby.teleport_from(player, destination)
|
||||
for _, stack in pairs(Config.player_create.starting_items) do
|
||||
if game.item_prototypes[stack.name] then
|
||||
player.insert(stack)
|
||||
end
|
||||
end
|
||||
local surface = RS.get_surface()
|
||||
local position = surface.find_non_colliding_position('character', destination or {0, 0}, 0, 0.2)
|
||||
player.teleport(position, surface, true)
|
||||
end
|
||||
|
||||
function Lobby.teleport_all_to()
|
||||
for _, player in pairs(game.players) do
|
||||
Lobby.teleport_to(player)
|
||||
end
|
||||
end
|
||||
|
||||
function Lobby.teleport_all_from(destination)
|
||||
for _, player in pairs(game.players) do
|
||||
Lobby.teleport_from(player, destination)
|
||||
end
|
||||
end
|
||||
|
||||
function Lobby.on_chunk_generated(event)
|
||||
local area = event.area
|
||||
local surface = event.surface
|
||||
|
||||
surface.build_checkerboard(area)
|
||||
for _, e in pairs(surface.find_entities_filtered{ area = area }) do
|
||||
if e.type ~= 'character' then
|
||||
e.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Lobby.on_init()
|
||||
local surface = Lobby.get_surface()
|
||||
surface.map_gen_settings = Lobby.mgs
|
||||
Lobby.on_chunk_generated({ area = {left_top = {-64, -64}, right_bottom = {64, 64}}, surface = surface })
|
||||
end
|
||||
|
||||
-- == MAP GEN =================================================================
|
||||
|
||||
local map, water, green_water
|
||||
@ -131,17 +231,17 @@ local map, water, green_water
|
||||
RS.set_map_gen_settings({
|
||||
{
|
||||
autoplace_controls = {
|
||||
coal = { frequency = 3, richness = 1, size = 0.75 },
|
||||
['copper-ore'] = { frequency = 3, richness = 1, size = 0.75 },
|
||||
['crude-oil'] = { frequency = 1, richness = 1, size = 0.75 },
|
||||
['enemy-base'] = { frequency = 6, richness = 1, size = 4 },
|
||||
['iron-ore'] = { frequency = 3, richness = 1, size = 0.75 },
|
||||
stone = { frequency = 3, richness = 1, size = 0.75 },
|
||||
trees = { frequency = 1, richness = 1, size = 1 },
|
||||
['uranium-ore'] = { frequency = 0.5, richness = 1, size = 0.5 },
|
||||
['coal'] = { frequency = 3, richness = 1, size = 0.75 },
|
||||
['copper-ore'] = { frequency = 3, richness = 1, size = 0.75 },
|
||||
['crude-oil'] = { frequency = 1, richness = 1, size = 0.75 },
|
||||
['enemy-base'] = { frequency = 6, richness = 1, size = 4 },
|
||||
['iron-ore'] = { frequency = 3, richness = 1, size = 0.75 },
|
||||
['stone'] = { frequency = 3, richness = 1, size = 0.75 },
|
||||
['trees'] = { frequency = 1, richness = 1, size = 1 },
|
||||
['uranium-ore'] = { frequency = 0.5, richness = 1, size = 0.5 },
|
||||
},
|
||||
cliff_settings = { name = 'cliff', cliff_elevation_0 = 20, cliff_elevation_interval = 40, richness = 1 / 3 },
|
||||
height = _g.height * 32,
|
||||
height = this.height * 32,
|
||||
property_expression_names = {
|
||||
['control-setting:aux:frequency:multiplier'] = '1.333333',
|
||||
['control-setting:moisture:bias'] = '-0.250000',
|
||||
@ -154,7 +254,7 @@ RS.set_map_gen_settings({
|
||||
})
|
||||
|
||||
local bounds = function(x, y)
|
||||
return x > (-_g.left_boundary * 32 - 320) and not ((y < -_g.height * 16) or (y > _g.height * 16))
|
||||
return x > (-this.left_boundary * 32 - 320) and not ((y < -this.height * 16) or (y > this.height * 16))
|
||||
end
|
||||
|
||||
water = b.change_tile(bounds, true, 'water')
|
||||
@ -162,12 +262,14 @@ water = b.fish(water, 0.075)
|
||||
|
||||
green_water = b.change_tile(bounds, true, 'deepwater-green')
|
||||
|
||||
map = b.choose(function(x) return x < -_g.left_boundary * 32 end, water, bounds)
|
||||
map = b.choose(function(x) return math_floor(x) == -(_g.kraken_distance + _g.left_boundary * 32 + 1) end, green_water, map)
|
||||
map = b.choose(function(x) return x < -this.left_boundary * 32 end, water, bounds)
|
||||
map = b.choose(function(x) return math_floor(x) == -(this.kraken_distance + this.left_boundary * 32 + 1) end, green_water, map)
|
||||
|
||||
-- == EVENTS ==================================================================
|
||||
-- == TERRAIN ==================================================================
|
||||
|
||||
local function noise_pattern(position, seed)
|
||||
local Terrain = {}
|
||||
|
||||
function Terrain.noise_pattern(position, seed)
|
||||
local noise, d = 0, 0
|
||||
for i = 1, #noise_weights do
|
||||
local nw = noise_weights[i]
|
||||
@ -179,8 +281,8 @@ local function noise_pattern(position, seed)
|
||||
return noise
|
||||
end
|
||||
|
||||
local function mixed_resources(surface, area)
|
||||
local left_top = { x = math_max(area.left_top.x, _g.right_boundary * 32), y = area.left_top.y }
|
||||
function Terrain.mixed_resources(surface, area)
|
||||
local left_top = { x = math_max(area.left_top.x, this.right_boundary * 32), y = area.left_top.y }
|
||||
local right_bottom = area.right_bottom
|
||||
if left_top.x >= right_bottom.x then
|
||||
return
|
||||
@ -195,19 +297,22 @@ local function mixed_resources(surface, area)
|
||||
for _, resource in pairs(find_entities_filtered{
|
||||
position = position,
|
||||
type = 'resource'
|
||||
}) do resource.destroy() end
|
||||
}) do
|
||||
if resource.name ~= 'uranium-ore' and resource.name ~= 'crude-oil' then
|
||||
resource.destroy() end
|
||||
end
|
||||
end
|
||||
|
||||
local chunks = math_clamp(math_abs((left_top.x - _g.right_boundary * 32) / _g.ore_chunk_scale), 1, 100)
|
||||
local chunks = math_clamp(math_abs((left_top.x - this.right_boundary * 32) / this.ore_chunk_scale), 1, 100)
|
||||
chunks = math_random(chunks, chunks + 4)
|
||||
for x = 0, 31 do
|
||||
for y = 0, 31 do
|
||||
local position = { x = left_top.x + x, y = left_top.y + y }
|
||||
if can_place_entity({ name = 'iron-ore', position = position }) then
|
||||
local noise = noise_pattern(position, seed)
|
||||
local noise = Terrain.noise_pattern(position, seed)
|
||||
if math_abs(noise) > 0.67 then
|
||||
local idx = math_floor(noise * 25 + math_abs(position.x) * 0.05) % #mixed_ores + 1
|
||||
local amount = _g.ore_base_quantity * chunks * 3
|
||||
local amount = this.ore_base_quantity * chunks * 3
|
||||
clear_ore(position)
|
||||
create_entity({ name = mixed_ores[idx], position = position, amount = amount })
|
||||
end
|
||||
@ -216,29 +321,61 @@ local function mixed_resources(surface, area)
|
||||
end
|
||||
end
|
||||
|
||||
local function clear_enemies_inside_wall(surface, area)
|
||||
if area.right_bottom.x < (_g.right_boundary * 32 + 96) then
|
||||
function Terrain.clear_enemies_inside_wall(surface, area)
|
||||
if area.right_bottom.x < (this.right_boundary * 32 + 96) then
|
||||
for _, entity in pairs(surface.find_entities_filtered { area = area, force = 'enemy' }) do
|
||||
entity.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function scale_resource_richness(surface, area)
|
||||
function Terrain.scale_resource_richness(surface, area)
|
||||
for _, resource in pairs(surface.find_entities_filtered { area = area, type = 'resource' }) do
|
||||
if resource.position.x > _g.right_boundary * 32 then
|
||||
local chunks = math.clamp(math_abs((resource.position.x - _g.right_boundary * 32) / _g.ore_chunk_scale), 1, 100)
|
||||
if resource.position.x > this.right_boundary * 32 then
|
||||
local chunks = math.clamp(math_abs((resource.position.x - this.right_boundary * 32) / this.ore_chunk_scale), 1, 100)
|
||||
chunks = math_random(chunks, chunks + 4)
|
||||
if resource.prototype.resource_category == 'basic-fluid' then
|
||||
resource.amount = 3000 * 3 * chunks
|
||||
elseif resource.prototype.resource_category == 'basic-solid' then
|
||||
resource.amount = _g.ore_base_quantity * chunks
|
||||
resource.amount = this.ore_base_quantity * chunks
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function set_silo_tiles(entity)
|
||||
function Terrain.rich_rocks(surface, area)
|
||||
local left_top = { x = math_max(area.left_top.x, this.right_boundary * 32), y = area.left_top.y }
|
||||
local right_bottom = area.right_bottom
|
||||
if left_top.x >= right_bottom.x then
|
||||
return
|
||||
end
|
||||
|
||||
local function place_rock(rock_name)
|
||||
local search = surface.find_non_colliding_position
|
||||
local place = surface.create_entity
|
||||
|
||||
for _ = 1, 10 do
|
||||
local x, y = math_random(1, 31) + math_random(), math_random(1, 31) + math_random()
|
||||
local rock_pos = search(rock_name, {left_top.x + x, left_top.y + y}, 4, 0.4)
|
||||
if rock_pos then
|
||||
local rock = place{
|
||||
name = rock_name,
|
||||
position = rock_pos,
|
||||
direction = math_random(1, 4)
|
||||
}
|
||||
rock.graphics_variation = math_random(16)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _ = 1, this.rock_richness do
|
||||
local rock_name = math_random() < 0.4 and 'rock-huge' or 'rock-big'
|
||||
place_rock(rock_name)
|
||||
end
|
||||
end
|
||||
|
||||
function Terrain.set_silo_tiles(entity)
|
||||
local pos = entity.position
|
||||
local surface = entity.surface
|
||||
surface.request_to_generate_chunks(pos, 1)
|
||||
@ -258,7 +395,29 @@ local function set_silo_tiles(entity)
|
||||
entity.surface.set_tiles(tiles, true)
|
||||
end
|
||||
|
||||
local function nuclear_explosion(entity)
|
||||
function Terrain.create_wall(x, w)
|
||||
local surface = RS.get_surface()
|
||||
local area = { { x, -this.height * 16 }, { x + w, this.height * 16 } }
|
||||
for _, entity in pairs(surface.find_entities_filtered { area = area, collision_mask = 'player-layer' }) do
|
||||
entity.destroy()
|
||||
end
|
||||
|
||||
for y = -this.height * 16, this.height * 16 do
|
||||
for j = 0, w do
|
||||
local e = surface.create_entity {
|
||||
name = 'stone-wall',
|
||||
position = { x + j, y },
|
||||
force = 'player',
|
||||
move_stuck_players = true,
|
||||
}
|
||||
e.destructible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- == MAIN ====================================================================
|
||||
|
||||
function Main.nuclear_explosion(entity)
|
||||
local surface = entity.surface
|
||||
local center_position = entity.position
|
||||
local force = entity.force
|
||||
@ -273,81 +432,126 @@ local function nuclear_explosion(entity)
|
||||
}
|
||||
end
|
||||
|
||||
local function spawn_enemy_wave(position)
|
||||
function Main.spawn_enemy_wave(position)
|
||||
local surface = RS.get_surface()
|
||||
local find_position = surface.find_non_colliding_position
|
||||
local spawn = surface.create_entity
|
||||
local current_tick = game.tick
|
||||
|
||||
local max_time = math_max(MINUTE, MINUTE * math_ceil(0.5 * (this.rockets_launched ^ 0.5)))
|
||||
|
||||
local radius = 20
|
||||
for _ = 1, 24 do
|
||||
local name = math_random() > 0.15 and 'behemoth-worm-turret' or 'big-worm-turret'
|
||||
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.2)
|
||||
if about then
|
||||
local worm = spawn { name = name, position = about, force = 'enemy', move_stuck_players = true }
|
||||
_g.invincible[worm.unit_number] = {
|
||||
time_to_live = current_tick + math_random(60 * 2, 60 * (4 + _g.rockets_launched))
|
||||
this.invincible[worm.unit_number] = {
|
||||
time_to_live = current_tick + math_random(MINUTE, max_time)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
radius = 32
|
||||
for _ = 1, 64 do
|
||||
for _ = 1, 20 do
|
||||
local name = math_random() > 0.3 and 'behemoth-biter' or 'behemoth-spitter'
|
||||
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.2)
|
||||
local about = find_position(name, { x = position.x + math_random(), y = position.y + math_random() }, radius, 0.6)
|
||||
if about then
|
||||
local unit = spawn { name = name, position = about, force = 'enemy', move_stuck_players = true }
|
||||
_g.invincible[unit.unit_number] = {
|
||||
time_to_live = current_tick + math_random(60 * 2, 60 * (4 + _g.rockets_launched))
|
||||
this.invincible[unit.unit_number] = {
|
||||
time_to_live = current_tick + math_random(MINUTE, max_time)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
local spawn_enemy_wave_token = Token.register(spawn_enemy_wave)
|
||||
Main.spawn_enemy_wave_token = Token.register(Main.spawn_enemy_wave)
|
||||
|
||||
local function init_wall(x, w)
|
||||
local surface = RS.get_surface()
|
||||
local area = { { x, -_g.height * 16 }, { x + w, _g.height * 16 } }
|
||||
for _, entity in pairs(surface.find_entities_filtered { area = area, collision_mask = 'player-layer' }) do
|
||||
entity.destroy()
|
||||
end
|
||||
|
||||
for y = -_g.height * 16, _g.height * 16 do
|
||||
for j = 0, w do
|
||||
local e = surface.create_entity {
|
||||
name = 'stone-wall',
|
||||
position = { x + j, y },
|
||||
force = 'player',
|
||||
move_stuck_players = true,
|
||||
}
|
||||
e.destructible = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function win()
|
||||
_g.scenario_finished = true
|
||||
game.set_game_state { game_finished = true, player_won = true, can_continue = true, victorious_force = 'player' }
|
||||
end
|
||||
|
||||
local function on_spawner_died(event)
|
||||
local entity = event.entity
|
||||
local chance = math_random()
|
||||
if chance > _g.loot_chance then
|
||||
function Main.spawn_turret_outpost(position)
|
||||
if position.x < this.right_boundary + this.wall_width then
|
||||
return
|
||||
end
|
||||
|
||||
local budget = _g.loot_budget + entity.position.x * 2.75
|
||||
local max_chance = math_clamp(0.02 * math_sqrt(position.x), 0.01, 0.04)
|
||||
if math_random() > max_chance then
|
||||
return
|
||||
end
|
||||
|
||||
local surface = RS.get_surface()
|
||||
|
||||
if escape_player then
|
||||
for _, player in pairs(surface.find_entities_filtered{type = 'character'}) do
|
||||
local pos = surface.find_non_colliding_position('character', { position.x -10, position.y }, 5, 0.5)
|
||||
if pos then
|
||||
player.teleport(pos, surface)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local evolution = game.forces.enemy.evolution_factor
|
||||
local ammo = 'firearm-magazine'
|
||||
if math_random() < evolution then
|
||||
ammo = 'piercing-rounds-magazine'
|
||||
end
|
||||
if math_random() < evolution then
|
||||
ammo = 'uranium-rounds-magazine'
|
||||
end
|
||||
|
||||
for _, v in pairs({
|
||||
{ x = -5, y = 0 },
|
||||
{ x = 5, y = 0 },
|
||||
{ x = 0, y = 5 },
|
||||
{ x = 0, y = -5 },
|
||||
}) do
|
||||
local pos = surface.find_non_colliding_position('gun-turret', { position.x + v.x, position.y + v.y }, 2, 0.5)
|
||||
if pos then
|
||||
local turret = surface.create_entity {
|
||||
name = 'gun-turret',
|
||||
position = pos,
|
||||
force = 'enemy',
|
||||
move_stuck_players = true,
|
||||
create_build_effect_smoke = true,
|
||||
}
|
||||
if turret and turret.valid then
|
||||
EnemyTurret.register(turret, ammo)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Main.win()
|
||||
this.scenario_finished = true
|
||||
game.set_game_state { game_finished = true, player_won = true, can_continue = true, victorious_force = 'player' }
|
||||
|
||||
Task.set_timeout( 1, Main.restart_message_token, 90)
|
||||
Task.set_timeout(31, Main.restart_message_token, 60)
|
||||
Task.set_timeout(61, Main.restart_message_token, 30)
|
||||
Task.set_timeout(81, Main.restart_message_token, 10)
|
||||
Task.set_timeout(86, Main.restart_message_token, 5)
|
||||
Task.set_timeout(91, Main.end_game_token)
|
||||
Task.set_timeout(92, Main.restart_game_token)
|
||||
end
|
||||
|
||||
function Main.on_spawner_died(event)
|
||||
local entity = event.entity
|
||||
local chance = math_random()
|
||||
if chance > this.loot_chance then
|
||||
return
|
||||
end
|
||||
|
||||
local budget = this.loot_budget + entity.position.x * 2.75
|
||||
budget = budget * math_random(25, 175) * 0.01
|
||||
|
||||
local player = event.cause and event.cause.player
|
||||
local player = false
|
||||
if event.cause and event.cause.type == 'character' then
|
||||
player = event.cause.player
|
||||
end
|
||||
if player and player.valid then
|
||||
budget = budget + (_g.death_contributions[player.name] or 0) * 80
|
||||
budget = budget + (this.death_contributions[player.name] or 0) * 80
|
||||
end
|
||||
|
||||
if math_random(1, 128) == 1 then budget = budget * 4 end
|
||||
if math_random(1, 256) == 1 then budget = budget * 4 end
|
||||
budget = budget * _g.loot_richness
|
||||
budget = budget * this.loot_richness
|
||||
|
||||
local chest = entity.surface.create_entity { name = 'steel-chest', position = entity.position, force = 'player', move_stuck_players = true }
|
||||
chest.destructible = false
|
||||
@ -362,14 +566,15 @@ local function on_spawner_died(event)
|
||||
end
|
||||
end
|
||||
|
||||
local function on_enemy_died(entity)
|
||||
function Main.on_enemy_died(entity)
|
||||
local uid = entity.unit_number
|
||||
local data = _g.invincible[uid]
|
||||
local data = this.invincible[uid]
|
||||
if not data then
|
||||
return
|
||||
end
|
||||
|
||||
if data.time_to_live > game.tick then
|
||||
if game.tick > data.time_to_live then
|
||||
this.invincible[uid] = nil
|
||||
return
|
||||
end
|
||||
|
||||
@ -379,27 +584,31 @@ local function on_enemy_died(entity)
|
||||
force = entity.force,
|
||||
}
|
||||
|
||||
_g.invincible[new_entity.unit_number] = {
|
||||
this.invincible[new_entity.unit_number] = {
|
||||
time_to_live = data.time_to_live,
|
||||
}
|
||||
_g.invincible[uid] = nil
|
||||
this.invincible[uid] = nil
|
||||
|
||||
if new_entity.type == 'unit' then
|
||||
new_entity.set_command(entity.command)
|
||||
end
|
||||
end
|
||||
|
||||
local play_sound_token = Token.register(Sounds.notify_all)
|
||||
Main.play_sound_token = Token.register(Sounds.notify_all)
|
||||
|
||||
local function move_silo(position)
|
||||
Main.restart_message_token = Token.register(function(seconds)
|
||||
game.print({'frontier.restart', seconds}, Color.success)
|
||||
end)
|
||||
|
||||
function Main.move_silo(position)
|
||||
local surface = RS.get_surface()
|
||||
local old_silo = _g.rocket_silo
|
||||
local old_silo = this.rocket_silo
|
||||
local old_position = old_silo and old_silo.position or { x = 0, y = 0 }
|
||||
local new_silo
|
||||
local new_position = position or { x = _g.x, y = _g.y }
|
||||
local new_position = position or { x = this.x, y = this.y }
|
||||
|
||||
if old_silo and math_abs(new_position.x - old_position.x) < _g.min_step then
|
||||
_g.move_buffer = _g.move_buffer + new_position.x - old_position.x
|
||||
if old_silo and math_abs(new_position.x - old_position.x) < this.min_step then
|
||||
this.move_buffer = this.move_buffer + new_position.x - old_position.x
|
||||
return
|
||||
end
|
||||
|
||||
@ -436,8 +645,12 @@ local function move_silo(position)
|
||||
end
|
||||
end
|
||||
game.print({'frontier.empty_rocket'})
|
||||
nuclear_explosion(chest)
|
||||
Task.set_timeout(5, spawn_enemy_wave_token, old_position)
|
||||
Main.nuclear_explosion(chest)
|
||||
Task.set_timeout(5, Main.spawn_enemy_wave_token, old_position)
|
||||
|
||||
game.forces.enemy.reset_evolution()
|
||||
local enemy_evolution = game.map_settings.enemy_evolution
|
||||
enemy_evolution.time_factor = enemy_evolution.time_factor * 1.01
|
||||
else
|
||||
new_silo = surface.create_entity { name = 'rocket-silo', position = new_position, force = 'player', move_stuck_players = true }
|
||||
end
|
||||
@ -447,11 +660,11 @@ local function move_silo(position)
|
||||
new_silo.minable = false
|
||||
new_silo.active = true
|
||||
new_silo.get_output_inventory().clear()
|
||||
_g.rocket_silo = new_silo
|
||||
_g.x = new_silo.position.x
|
||||
_g.y = new_silo.position.y
|
||||
_g.move_buffer = 0
|
||||
set_silo_tiles(new_silo)
|
||||
this.rocket_silo = new_silo
|
||||
this.x = new_silo.position.x
|
||||
this.y = new_silo.position.y
|
||||
this.move_buffer = 0
|
||||
Terrain.set_silo_tiles(new_silo)
|
||||
|
||||
local x_diff = math.round(new_position.x - old_position.x)
|
||||
if x_diff > 0 then
|
||||
@ -461,86 +674,179 @@ local function move_silo(position)
|
||||
end
|
||||
end
|
||||
end
|
||||
local move_silo_token = Token.register(move_silo)
|
||||
Main.move_silo_token = Token.register(Main.move_silo)
|
||||
|
||||
local function compute_silo_coordinates(step)
|
||||
_g.move_buffer = _g.move_buffer + (step or 0)
|
||||
function Main.compute_silo_coordinates(step)
|
||||
this.move_buffer = this.move_buffer + (step or 0)
|
||||
|
||||
if _g.x + _g.move_buffer > _g.max_distance then
|
||||
if this.x + this.move_buffer > this.max_distance then
|
||||
-- Exceeding max right direction, move to max (if not already) and add rockets to win
|
||||
local remainder = _g.x + _g.move_buffer - _g.max_distance
|
||||
local add_rockets = math_floor(remainder / _g.rocket_step)
|
||||
local remainder = this.x + this.move_buffer - this.max_distance
|
||||
local add_rockets = math_floor(remainder / this.rocket_step)
|
||||
if add_rockets > 0 then
|
||||
_g.rockets_to_win = _g.rockets_to_win + add_rockets
|
||||
game.print({'frontier.warning_max_distance', _g.rocket_step})
|
||||
this.rockets_to_win = this.rockets_to_win + add_rockets
|
||||
game.print({'frontier.warning_max_distance', this.rocket_step})
|
||||
end
|
||||
_g.x = math_min(_g.max_distance, _g.x + _g.move_buffer)
|
||||
_g.move_buffer = remainder % _g.rocket_step
|
||||
elseif _g.x + _g.move_buffer < -(_g.left_boundary * 32) + 12 then
|
||||
this.x = math_min(this.max_distance, this.x + this.move_buffer)
|
||||
this.move_buffer = remainder % this.rocket_step
|
||||
elseif this.x + this.move_buffer < -(this.left_boundary * 32) + 12 then
|
||||
-- Exceeding min left direction, move to min (if not already) and remove rockets to win
|
||||
local min_distance = -(_g.left_boundary * 32) + 12
|
||||
local remainder = _g.x + _g.move_buffer - min_distance -- this is negative
|
||||
local remove_rockets = math_floor(-remainder / _g.rocket_step)
|
||||
local min_distance = -(this.left_boundary * 32) + 12
|
||||
local remainder = this.x + this.move_buffer - min_distance -- this is negative
|
||||
local remove_rockets = math_floor(-remainder / this.rocket_step)
|
||||
if remove_rockets > 0 then
|
||||
_g.rockets_to_win = _g.rockets_to_win - remove_rockets
|
||||
if _g.rockets_to_win < 1 then _g.rockets_to_win = 1 end
|
||||
if _g.rockets_launched >= _g.rockets_to_win then
|
||||
win()
|
||||
this.rockets_to_win = this.rockets_to_win - remove_rockets
|
||||
if this.rockets_to_win < 1 then this.rockets_to_win = 1 end
|
||||
if this.rockets_launched >= this.rockets_to_win then
|
||||
Main.win()
|
||||
return
|
||||
else
|
||||
game.print({'frontier.warning_min_distance', _g.rocket_step})
|
||||
game.print({'frontier.warning_min_distance', this.rocket_step})
|
||||
end
|
||||
end
|
||||
_g.x = math_max(min_distance, _g.x + _g.move_buffer)
|
||||
_g.move_buffer = remainder % _g.rocket_step
|
||||
this.x = math_max(min_distance, this.x + this.move_buffer)
|
||||
this.move_buffer = remainder % this.rocket_step
|
||||
else
|
||||
_g.x = _g.x + _g.move_buffer
|
||||
_g.move_buffer = 0
|
||||
this.x = this.x + this.move_buffer
|
||||
this.move_buffer = 0
|
||||
end
|
||||
|
||||
local max_height = (_g.height * 16) - 16
|
||||
_g.y = math_random(-max_height, max_height)
|
||||
local max_height = (this.height * 16) - 16
|
||||
this.y = math_random(-max_height, max_height)
|
||||
end
|
||||
|
||||
Event.on_init(function()
|
||||
local ms = game.map_settings
|
||||
ms.enemy_expansion.friendly_base_influence_radius = 0
|
||||
ms.enemy_expansion.min_expansion_cooldown = 60 * 30 -- 30 seconds
|
||||
ms.enemy_expansion.max_expansion_cooldown = 60 * 60 * 4 -- 4 minutes
|
||||
ms.enemy_expansion.max_expansion_distance = 5
|
||||
ms.enemy_evolution.destroy_factor = 0.0001
|
||||
|
||||
function Main.reveal_spawn_area()
|
||||
local surface = RS.get_surface()
|
||||
local far_left, far_right = _g.kraken_distance + _g.left_boundary * 32 + 1, _g.right_boundary * 32 + _g.wall_width
|
||||
surface.request_to_generate_chunks({ x = 0, y = 0 }, math.ceil(math_max(far_left, far_right, _g.height * 32) / 32))
|
||||
local far_left, far_right = this.kraken_distance + this.left_boundary * 32 + 1, this.right_boundary * 32 + this.wall_width
|
||||
surface.request_to_generate_chunks({ x = 0, y = 0 }, math.ceil(math_max(far_left, far_right, this.height * 32) / 32))
|
||||
surface.force_generate_chunk_requests()
|
||||
|
||||
compute_silo_coordinates(_g.silo_starting_x + math_random(100))
|
||||
move_silo()
|
||||
init_wall(_g.right_boundary * 32, _g.wall_width)
|
||||
Main.compute_silo_coordinates(this.silo_starting_x + math_random(100))
|
||||
Main.move_silo()
|
||||
Terrain.create_wall(this.right_boundary * 32, this.wall_width)
|
||||
|
||||
game.forces.player.chart(surface, { { -far_left - 32, -_g.height * 16 }, { far_right + 32, _g.height * 16 } })
|
||||
game.forces.player.chart(surface, { { -far_left - 32, -this.height * 16 }, { far_right + 32, this.height * 16 } })
|
||||
end
|
||||
|
||||
function Main.on_game_started()
|
||||
local ms = game.map_settings
|
||||
ms.enemy_expansion.friendly_base_influence_radius = 0
|
||||
ms.enemy_expansion.min_expansion_cooldown = SECOND * 30
|
||||
ms.enemy_expansion.max_expansion_cooldown = MINUTE * 4
|
||||
ms.enemy_expansion.max_expansion_distance = 5
|
||||
ms.enemy_evolution.destroy_factor = 0.0001
|
||||
ms.enemy_evolution.time_factor = 0.000004
|
||||
|
||||
this.rounds = this.rounds + 1
|
||||
this.kraken_contributors = {}
|
||||
this.death_contributions = {}
|
||||
this.rockets_to_win = 3 + math_random(12 + this.rounds)
|
||||
this.rockets_launched = 0
|
||||
this.scenario_finished = false
|
||||
this.x = 0
|
||||
this.y = 0
|
||||
this.rocket_silo = nil
|
||||
this.move_buffer = 0
|
||||
this.invincible = {}
|
||||
|
||||
if _DEBUG then
|
||||
this.silo_starting_x = 30
|
||||
this.rockets_to_win = 1
|
||||
end
|
||||
|
||||
for _, force in pairs(game.forces) do
|
||||
force.reset()
|
||||
force.reset_evolution()
|
||||
end
|
||||
|
||||
game.speed = 1
|
||||
game.reset_game_state()
|
||||
game.reset_time_played()
|
||||
|
||||
ScoreTracker.reset()
|
||||
end
|
||||
|
||||
Main.restart_game_token = Token.register(function()
|
||||
script.raise_event(Main.events.on_game_started, {})
|
||||
end)
|
||||
|
||||
function Main.on_game_finished()
|
||||
Lobby.enabled = true
|
||||
Lobby.teleport_all_to()
|
||||
|
||||
local surface = RS.get_surface()
|
||||
surface.clear(true)
|
||||
surface.map_gen_settings.seed = surface.map_gen_settings.seed + 1
|
||||
end
|
||||
|
||||
Main.end_game_token = Token.register(function()
|
||||
script.raise_event(Main.events.on_game_finished, {})
|
||||
end)
|
||||
|
||||
-- == EVENTS ==================================================================
|
||||
|
||||
local function on_init()
|
||||
Lobby.on_init()
|
||||
Main.on_game_started()
|
||||
Main.reveal_spawn_area()
|
||||
|
||||
Lobby.enabled = false
|
||||
Lobby.teleport_all_from()
|
||||
end
|
||||
Event.on_init(on_init)
|
||||
|
||||
local function on_game_started()
|
||||
Main.on_game_started()
|
||||
Main.reveal_spawn_area()
|
||||
|
||||
Lobby.enabled = false
|
||||
Lobby.teleport_all_from()
|
||||
end
|
||||
Event.add(Main.events.on_game_started, on_game_started)
|
||||
|
||||
local function on_game_finished()
|
||||
Main.on_game_finished()
|
||||
end
|
||||
Event.add(Main.events.on_game_finished, on_game_finished)
|
||||
|
||||
local function on_player_created(event)
|
||||
local player = game.get_player(event.player_index)
|
||||
if not (player and player.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
if Lobby.enabled then
|
||||
Lobby.teleport_to(player)
|
||||
end
|
||||
end
|
||||
Event.add(defines.events.on_player_created, on_player_created)
|
||||
|
||||
local function on_chunk_generated(event)
|
||||
local area = event.area
|
||||
local surface = event.surface
|
||||
|
||||
if surface.name == Lobby.name then
|
||||
Lobby.on_chunk_generated(event)
|
||||
end
|
||||
|
||||
if surface.name ~= RS.get_surface_name() then
|
||||
return
|
||||
end
|
||||
|
||||
-- kill off biters inside the wall
|
||||
clear_enemies_inside_wall(surface, area)
|
||||
Terrain.clear_enemies_inside_wall(surface, area)
|
||||
|
||||
-- scale freshly generated ore by a scale factor
|
||||
scale_resource_richness(surface, area)
|
||||
Terrain.scale_resource_richness(surface, area)
|
||||
|
||||
-- add mixed patches
|
||||
mixed_resources(surface, area)
|
||||
Terrain.mixed_resources(surface, area)
|
||||
|
||||
-- add extra rocks
|
||||
Terrain.rich_rocks(surface, area)
|
||||
end
|
||||
Event.add(defines.events.on_chunk_generated, on_chunk_generated)
|
||||
|
||||
|
||||
local function on_entity_died(event)
|
||||
local entity = event.entity
|
||||
if not (entity and entity.valid) then
|
||||
@ -549,10 +855,10 @@ local function on_entity_died(event)
|
||||
|
||||
local entity_type = entity.type
|
||||
if entity_type == 'unit-spawner' then
|
||||
on_spawner_died(entity)
|
||||
Main.on_spawner_died(event)
|
||||
elseif entity_type == 'unit' or entity.type == 'turret' then
|
||||
if entity.force.name == 'enemy' then
|
||||
on_enemy_died(entity)
|
||||
Main.on_enemy_died(entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -576,22 +882,20 @@ local function on_player_died(event)
|
||||
return
|
||||
end
|
||||
|
||||
if _g.rockets_per_death <= 0 then
|
||||
if this.rockets_per_death <= 0 then
|
||||
return
|
||||
end
|
||||
|
||||
local player_name = 'a player'
|
||||
if player then
|
||||
player_name = player.name
|
||||
_g.death_contributions[player_name] = (_g.death_contributions[player_name] or 0) + 1
|
||||
this.death_contributions[player_name] = (this.death_contributions[player_name] or 0) + 1
|
||||
end
|
||||
|
||||
_g.rockets_to_win = _g.rockets_to_win + _g.rockets_per_death
|
||||
if _g.rockets_to_win < 1 then
|
||||
_g.rockets_to_win = 1
|
||||
end
|
||||
this.rockets_to_win = this.rockets_to_win + this.rockets_per_death
|
||||
ScoreTracker.set_for_global(rocket_launches_name, this.rockets_to_win - this.rocket_launched)
|
||||
|
||||
game.print({'frontier.add_rocket', _g.rockets_per_death, player_name, (_g.rockets_to_win - _g.rockets_launched)})
|
||||
game.print({'frontier.add_rocket', this.rockets_per_death, player_name, (this.rockets_to_win - this.rockets_launched)})
|
||||
end
|
||||
Event.add(defines.events.on_player_died, on_player_died)
|
||||
|
||||
@ -601,7 +905,7 @@ local function on_player_changed_position(event)
|
||||
return
|
||||
end
|
||||
|
||||
if player.position.x < (-_g.left_boundary * 32 - _g.kraken_distance) then
|
||||
if player.position.x < (-this.left_boundary * 32 - this.kraken_distance) then
|
||||
local player_name = 'a player'
|
||||
if player.character ~= nil then
|
||||
player_name = player.name
|
||||
@ -609,7 +913,7 @@ local function on_player_changed_position(event)
|
||||
game.print({'frontier.kraken_eat', player_name}, { sound_path = 'utility/game_lost' })
|
||||
if player.character ~= nil then
|
||||
player.character.die()
|
||||
_g.kraken_contributors[player_name] = true
|
||||
this.kraken_contributors[player_name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -621,32 +925,46 @@ local function on_rocket_launched(event)
|
||||
return
|
||||
end
|
||||
|
||||
if _g.scenario_finished then
|
||||
if this.scenario_finished then
|
||||
return
|
||||
end
|
||||
|
||||
_g.rockets_launched = _g.rockets_launched + 1
|
||||
if _g.rockets_launched >= _g.rockets_to_win then
|
||||
win()
|
||||
this.rockets_launched = this.rockets_launched + 1
|
||||
if this.rockets_launched >= this.rockets_to_win then
|
||||
Main.win()
|
||||
return
|
||||
end
|
||||
|
||||
game.print({'frontier.rocket_launched', _g.rockets_launched, (_g.rockets_to_win - _g.rockets_launched) })
|
||||
compute_silo_coordinates(500)
|
||||
game.print({'frontier.rocket_launched', this.rockets_launched, (this.rockets_to_win - this.rockets_launched) })
|
||||
Main.compute_silo_coordinates(500)
|
||||
|
||||
local ticks = 60
|
||||
for _, delay in pairs{60, 40, 20} do
|
||||
for i = 1, 30 do
|
||||
ticks = ticks + math_random(math_ceil(delay/5), delay)
|
||||
Task.set_timeout_in_ticks(ticks, play_sound_token, 'utility/alert_destroyed')
|
||||
Task.set_timeout_in_ticks(ticks, Main.play_sound_token, 'utility/alert_destroyed')
|
||||
end
|
||||
end
|
||||
Task.set_timeout_in_ticks(ticks + 30, move_silo_token)
|
||||
Task.set_timeout_in_ticks(ticks + 30, Main.move_silo_token)
|
||||
local silo = event.rocket_silo
|
||||
if silo then silo.active = false end
|
||||
end
|
||||
Event.add(defines.events.on_rocket_launched, on_rocket_launched)
|
||||
|
||||
local function on_entity_mined(event)
|
||||
local entity = event.entity
|
||||
if not (entity and entity.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
if entity.type == 'simple-entity' then
|
||||
Main.spawn_turret_outpost(entity.position)
|
||||
end
|
||||
end
|
||||
Event.add(defines.events.on_robot_mined_entity, on_entity_mined)
|
||||
Event.add(defines.events.on_player_mined_entity, on_entity_mined)
|
||||
|
||||
|
||||
-- == COMMANDS ================================================================
|
||||
|
||||
Command.add('ping-silo',
|
||||
|
@ -117,6 +117,84 @@ function Public.change_for_global(score_name, value)
|
||||
})
|
||||
end
|
||||
|
||||
---Sets a setting to a specific value for a player.
|
||||
---
|
||||
---@param score_name string
|
||||
---@param value number to subtract or add
|
||||
function Public.set_for_global(score_name, value)
|
||||
if not value then
|
||||
value = 0
|
||||
end
|
||||
|
||||
local setting = score_metadata[score_name]
|
||||
if not setting then
|
||||
if _DEBUG then
|
||||
error(format('Trying to set score "%s" while it has was never registered.', score_name), 2)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local previous_value = Public.get_for_global(score_name)
|
||||
if value == previous_value then
|
||||
return
|
||||
end
|
||||
|
||||
memory_global[score_name] = value
|
||||
|
||||
raise_event(on_global_score_changed, {
|
||||
score_name = score_name
|
||||
})
|
||||
end
|
||||
|
||||
---Sets a setting to a specific value for a player.
|
||||
---
|
||||
---@param player_index number
|
||||
---@param score_name string
|
||||
---@param value number to subtract or add
|
||||
function Public.set_for_player(player_index, score_name, value)
|
||||
if not value then
|
||||
value = 0
|
||||
end
|
||||
|
||||
local setting = score_metadata[score_name]
|
||||
if not setting then
|
||||
if _DEBUG then
|
||||
error(format('Trying to change score "%s" while it has was never registered.', score_name), 2)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local player_score = memory_players[player_index]
|
||||
if not player_score then
|
||||
player_score = {}
|
||||
memory_players[player_index] = player_score
|
||||
end
|
||||
|
||||
local previous_value = Public.get_for_player(player_index, score_name)
|
||||
if value == previous_value then
|
||||
return
|
||||
end
|
||||
|
||||
player_score[score_name] = (player_score[score_name] or 0) + value
|
||||
|
||||
raise_event(on_player_score_changed, {
|
||||
score_name = score_name,
|
||||
player_index = player_index
|
||||
})
|
||||
end
|
||||
|
||||
--- Resets all scores
|
||||
function Public.reset()
|
||||
for score_name, _ in pairs(memory_global) do
|
||||
Public.set_for_global(score_name, 0)
|
||||
end
|
||||
for player_index, player_memory in pairs(memory_players) do
|
||||
for score_name, _ in pairs(player_memory) do
|
||||
Public.set_for_player(player_index, score_name, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---Returns the value for this player of a specific score.
|
||||
---
|
||||
---@param player_index number
|
||||
|
Loading…
x
Reference in New Issue
Block a user