1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-14 10:13:13 +02:00
RedMew/map_gen/maps/crash_site/outpost_builder.lua

1979 lines
53 KiB
Lua
Raw Normal View History

2019-01-22 18:05:31 +02:00
--local Random = require 'map_gen.shared.random'
local Command = require 'utils.command'
local Ranks = require 'resources.ranks'
2018-11-26 03:07:03 +02:00
local Token = require 'utils.token'
2018-07-20 23:01:34 +02:00
local Global = require 'utils.global'
local Event = require 'utils.event'
2019-01-04 22:02:55 +02:00
local Task = require 'utils.task'
local Retailer = require 'features.retailer'
local Donator = require 'features.donator'
local RS = require 'map_gen.shared.redmew_surface'
local Server = require 'features.server'
local CrashSiteToast = require 'map_gen.maps.crash_site.crash_site_toast'
local table = require 'utils.table'
2019-01-22 18:05:31 +02:00
--local next = next
local pairs = pairs
local concat = table.concat
2019-01-23 21:15:28 +02:00
local floor = math.floor
local format = string.format
local tostring = tostring
2019-03-08 19:31:00 +02:00
local draw_text = rendering.draw_text
local render_mode_game = defines.render_mode.game
2018-07-20 23:01:34 +02:00
2018-07-14 11:33:06 +02:00
local b = require 'map_gen.shared.builders'
2018-07-13 12:47:38 +02:00
local direction_bit_mask = 0xc0000000
local section_bit_mask = 0x30000000
local level_bit_mask = 0x0fffffff
2019-01-22 18:05:31 +02:00
--local not_level_bit_mask = 0xf0000000
2018-07-13 17:36:43 +02:00
local direction_bit_shift = 30
local section_bit_shift = 28
2019-01-22 18:05:31 +02:00
--local section_straight = 0
--local section_outer_corner = 1
--local section_inner_corner = 2
2018-07-13 17:36:43 +02:00
local wall_north_straight = 0x00000001
local wall_east_straight = 0x40000001
local wall_south_straight = 0x80000001
local wall_west_straight = 0xc0000001
local wall_north_outer = 0x10000001
local wall_east_outer = 0x50000001
local wall_south_outer = 0x90000001
local wall_west_outer = 0xd0000001
local wall_north_inner = 0x20000001
local wall_east_inner = 0x60000001
local wall_south_inner = 0xa0000001
local wall_west_inner = 0xe0000001
2019-01-10 00:29:51 +02:00
local default_part_size = 6
2018-07-14 11:33:06 +02:00
2019-01-24 15:08:33 +02:00
local magic_crafters_per_tick = 3
2019-01-23 21:15:28 +02:00
local magic_fluid_crafters_per_tick = 8
2018-07-20 23:01:34 +02:00
local refill_turrets = {index = 1}
local power_sources = {}
2019-01-22 18:05:31 +02:00
local turret_to_outpost = {}
2018-07-20 23:01:34 +02:00
local magic_crafters = {index = 1}
2019-01-23 21:15:28 +02:00
local magic_fluid_crafters = {index = 1}
local outposts = {}
2019-03-07 23:07:33 +02:00
local artillery_outposts = {index = 1}
2019-01-21 01:58:39 +02:00
local outpost_count = 0
local base_pollution_multiplier = 10
local pollution_multiplier = {value = 10}
2018-07-20 23:01:34 +02:00
Global.register(
{
refil_turrets = refill_turrets,
power_sources = power_sources,
2019-01-22 18:05:31 +02:00
turret_to_outpost = turret_to_outpost,
magic_crafters = magic_crafters,
2019-01-23 21:15:28 +02:00
magic_fluid_crafters = magic_fluid_crafters,
2019-03-07 23:07:33 +02:00
outposts = outposts,
artillery_outposts = artillery_outposts,
pollution_multiplier = pollution_multiplier
2018-07-20 23:01:34 +02:00
},
function(tbl)
refill_turrets = tbl.refil_turrets
power_sources = tbl.power_sources
2019-01-22 18:05:31 +02:00
turret_to_outpost = tbl.turret_to_outpost
2018-07-20 23:01:34 +02:00
magic_crafters = tbl.magic_crafters
2019-01-23 21:15:28 +02:00
magic_fluid_crafters = tbl.magic_fluid_crafters
outposts = tbl.outposts
2019-03-07 23:07:33 +02:00
artillery_outposts = tbl.artillery_outposts
pollution_multiplier = tbl.pollution_multiplier
2018-07-20 23:01:34 +02:00
end
)
2019-01-22 18:05:31 +02:00
--[[ local function get_direction(part)
2018-07-13 17:36:43 +02:00
local dir = bit32.band(part, direction_bit_mask)
return bit32.rshift(dir, direction_bit_shift - 1)
2019-01-22 18:05:31 +02:00
end ]]
2018-07-14 11:33:06 +02:00
local function get_4_way_direction(part)
local dir = bit32.band(part, direction_bit_mask)
return bit32.rshift(dir, direction_bit_shift)
end
2018-07-13 17:36:43 +02:00
local function get_section(part)
local sec = bit32.band(part, section_bit_mask)
return bit32.rshift(sec, section_bit_shift)
end
local function get_level(part)
return bit32.band(part, level_bit_mask)
end
2019-01-22 18:05:31 +02:00
--[[ local function set_level(part, level)
2018-07-13 17:36:43 +02:00
local not_level = bit32.band(part)
return not_level + level
end
2018-07-13 12:47:38 +02:00
local function set_block(tbl, x, y, value)
tbl[(y - 1) * tbl.size + x] = value
end
local function get_block(tbl, x, y)
local size = tbl.size
if x < 1 or x > size or y < 1 or y > size then
return 0
end
return tbl[(y - 1) * size + x] or 0
2019-01-22 18:05:31 +02:00
end ]]
2018-07-23 22:50:11 +02:00
local function fast_remove(tbl, index)
local count = #tbl
if index > count then
return
elseif index < count then
tbl[index] = tbl[count]
end
tbl[count] = nil
end
2018-07-13 12:47:38 +02:00
local Public = {}
Public.__index = Public
2018-07-20 23:01:34 +02:00
Public.empty_template = {}
2018-07-28 14:04:14 +02:00
function Public.new(random)
local obj = {random = random}
2018-07-13 12:47:38 +02:00
return setmetatable(obj, Public)
end
local function do_walls(self, blocks, outpost_variance, outpost_min_step)
local size = blocks.size
local random = self.random
local max_variance = size - outpost_variance + 1
local variance_step = outpost_variance + outpost_min_step
local x = random:next_int(1, outpost_variance)
local y = random:next_int(1, outpost_variance)
local start_x, start_y = x, y
2018-07-13 17:36:43 +02:00
local i = (y - 1) * size + x
local pv = -1
-- top
2018-07-13 12:47:38 +02:00
while x < size do
local tx = x + random:next_int(outpost_min_step, variance_step)
2018-07-13 17:36:43 +02:00
tx = math.min(tx, size)
if pv == 0 then
blocks[i] = wall_north_straight
elseif pv == -1 then
blocks[i] = wall_north_outer
else
2018-07-14 11:33:06 +02:00
blocks[i] = wall_east_inner
2018-07-13 17:36:43 +02:00
end
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
x = x + 1
i = i + 1
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
while x < tx do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
if x < size - outpost_min_step then
local ty = random:next_int(1, outpost_variance)
if y == ty then
pv = 0
elseif y < ty then
pv = 1
2018-07-14 11:33:06 +02:00
blocks[i] = wall_east_outer
2018-07-13 17:36:43 +02:00
y = y + 1
i = i + size
while y < ty do
blocks[i] = wall_east_straight
y = y + 1
i = i + size
end
else
pv = -1
blocks[i] = wall_north_inner
y = y - 1
i = i - size
while y > ty do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
end
else
pv = 0
end
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
pv = 1
-- right
2018-07-13 12:47:38 +02:00
while y < size do
local ty = y + random:next_int(outpost_min_step, variance_step)
2018-07-13 17:36:43 +02:00
ty = math.min(ty, size)
if pv == 0 then
blocks[i] = wall_east_straight
elseif pv == -1 then
2018-07-14 11:33:06 +02:00
blocks[i] = wall_south_inner
2018-07-13 17:36:43 +02:00
else
blocks[i] = wall_east_outer
end
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
y = y + 1
i = i + size
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
while y < ty do
blocks[i] = wall_east_straight
y = y + 1
i = i + size
end
if y < size - outpost_min_step then
local tx = random:next_int(max_variance, size)
if x == tx then
pv = 0
elseif x < tx then
pv = 1
blocks[i] = wall_east_inner
x = x + 1
i = i + 1
while x < tx do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
else
pv = -1
2018-07-14 11:33:06 +02:00
blocks[i] = wall_south_outer
2018-07-13 17:36:43 +02:00
x = x - 1
i = i - 1
while x > tx do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
end
else
pv = 0
end
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
pv = 1
-- bottom
2018-07-13 12:47:38 +02:00
while x > 1 do
local tx = x - random:next_int(outpost_min_step, variance_step)
2018-07-13 17:36:43 +02:00
tx = math.max(tx, 1)
if pv == 0 then
blocks[i] = wall_south_straight
elseif pv == -1 then
2018-07-14 11:33:06 +02:00
blocks[i] = wall_west_inner
2018-07-13 17:36:43 +02:00
else
blocks[i] = wall_south_outer
end
x = x - 1
i = i - 1
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
while x > tx do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
if x > outpost_min_step + 1 then
local ty = random:next_int(max_variance, size)
if y == ty then
pv = 0
elseif y < ty then
pv = 1
blocks[i] = wall_south_inner
y = y + 1
i = i + size
while y < ty do
blocks[i] = wall_east_straight
y = y + 1
i = i + size
end
else
pv = -1
2018-07-14 11:33:06 +02:00
blocks[i] = wall_west_outer
2018-07-13 17:36:43 +02:00
y = y - 1
i = i - size
while y > ty do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
end
else
pv = 0
end
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
pv = -1
-- left
local bottom_left_y = y
while y > start_y + variance_step do
2018-07-13 12:47:38 +02:00
local ty = y - random:next_int(outpost_min_step, variance_step)
2018-07-13 17:36:43 +02:00
ty = math.max(ty, start_y)
if pv == 0 then
blocks[i] = wall_west_straight
elseif pv == -1 then
blocks[i] = wall_west_outer
else
2018-07-14 11:33:06 +02:00
blocks[i] = wall_north_inner
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
y = y - 1
i = i - size
while y > ty do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
if y > start_y + variance_step + outpost_min_step then
local tx = random:next_int(1, outpost_variance)
if x == tx then
pv = 0
elseif x < tx then
pv = 1
2018-07-30 17:42:14 +02:00
--blocks[i] = wall_west_outer
blocks[i] = wall_north_outer
2018-07-13 17:36:43 +02:00
x = x + 1
i = i + 1
while x < tx do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
else
pv = -1
blocks[i] = wall_west_inner
x = x - 1
i = i - 1
while x > tx do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
end
else
pv = 0
end
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
-- final connection
if y == bottom_left_y then
blocks[i] = wall_west_outer
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
y = y - 1
i = i - size
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
while y > bottom_left_y - outpost_min_step do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
end
if x == start_x then
pv = 0
elseif x < start_x then
pv = 1
2018-07-14 11:33:06 +02:00
blocks[i] = wall_north_outer
2018-07-13 17:36:43 +02:00
x = x + 1
i = i + 1
while x < start_x do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
else
pv = -1
blocks[i] = wall_west_inner
x = x - 1
i = i - 1
while x > start_x do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
end
2018-07-13 12:47:38 +02:00
2018-07-13 17:36:43 +02:00
if pv == 0 then
blocks[i] = wall_west_straight
elseif pv == -1 then
blocks[i] = wall_west_outer
else
2018-07-14 11:33:06 +02:00
blocks[i] = wall_north_inner
2018-07-13 17:36:43 +02:00
end
y = y - 1
i = i - size
while y > start_y do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
2018-07-13 12:47:38 +02:00
end
end
local function fill(blocks)
local size = blocks.size
local anti_set = {size = size}
local anti_stack = {}
local y_offset = (size - 1) * size
for x = 1, size do
2018-07-13 17:36:43 +02:00
if blocks[x] == nil then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = x, y = 1}
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
if blocks[x + y_offset] == nil then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = x, y = size}
2018-07-13 12:47:38 +02:00
end
end
for y = 2, size do
y_offset = (y - 1) * size
2018-07-13 17:36:43 +02:00
if blocks[y_offset + 1] == nil then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = 1, y = y}
2018-07-13 12:47:38 +02:00
end
2018-07-13 17:36:43 +02:00
if blocks[y_offset + size] == nil then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = size, y = y}
2018-07-13 12:47:38 +02:00
end
end
while #anti_stack > 0 do
local point = table.remove(anti_stack)
local x, y = point.x, point.y
local offset = (y - 1) * size + x
2018-07-13 17:36:43 +02:00
anti_set[offset] = true
2018-07-13 12:47:38 +02:00
if x > 1 then
local x2 = x - 1
local offset2 = offset - 1
2018-07-13 17:36:43 +02:00
if not anti_set[offset2] and not blocks[offset2] then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = x2, y = y}
2018-07-13 12:47:38 +02:00
end
end
if x < size then
local x2 = x + 1
local offset2 = offset + 1
2018-07-13 17:36:43 +02:00
if not anti_set[offset2] and not blocks[offset2] then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = x2, y = y}
2018-07-13 12:47:38 +02:00
end
end
if y > 1 then
local y2 = y - 1
local offset2 = offset - size
2018-07-13 17:36:43 +02:00
if not anti_set[offset2] and not blocks[offset2] then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = x, y = y2}
2018-07-13 12:47:38 +02:00
end
end
if y < size then
local y2 = y + 1
local offset2 = offset + size
2018-07-13 17:36:43 +02:00
if not anti_set[offset2] and not blocks[offset2] then
2019-01-22 18:05:31 +02:00
anti_stack[#anti_stack + 1] = {x = x, y = y2}
2018-07-13 12:47:38 +02:00
end
end
end
for y = 1, size do
local offset = (y - 1) * size
for x = 1, size do
local i = offset + x
2018-07-13 17:36:43 +02:00
if not anti_set[i] and not blocks[i] then
blocks[i] = 2
2018-07-13 12:47:38 +02:00
end
end
end
end
local function do_levels(blocks, max_level)
local size = blocks.size
2018-07-13 17:36:43 +02:00
local level = 2
2018-07-13 12:47:38 +02:00
2018-07-24 01:45:38 +02:00
while level < max_level do
2018-07-13 17:36:43 +02:00
local next_level = level + 1
2018-07-20 23:01:34 +02:00
2018-07-13 12:47:38 +02:00
for y = 1, size do
local offset = (y - 1) * size
for x = 1, size do
local i = offset + x
2018-07-13 17:36:43 +02:00
if get_level(blocks[i] or 0) >= level then
2018-07-13 12:47:38 +02:00
local count = 0
2018-07-13 17:36:43 +02:00
if x > 1 and get_level(blocks[i - 1] or 0) >= level then
2018-07-13 12:47:38 +02:00
count = count + 1
end
2018-07-13 17:36:43 +02:00
if x < size and get_level(blocks[i + 1] or 0) >= level then
2018-07-13 12:47:38 +02:00
count = count + 1
end
2018-07-13 17:36:43 +02:00
if y > 1 and get_level(blocks[i - size] or 0) >= level then
2018-07-13 12:47:38 +02:00
count = count + 1
end
2018-07-13 17:36:43 +02:00
if y < size and get_level(blocks[i + size] or 0) >= level then
2018-07-13 12:47:38 +02:00
count = count + 1
end
if count == 4 then
blocks[i] = next_level
end
end
end
end
level = level + 1
2018-07-24 01:45:38 +02:00
end
2018-07-13 12:47:38 +02:00
2018-07-20 23:01:34 +02:00
local levels = {}
blocks.levels = levels
2018-07-13 12:47:38 +02:00
2018-07-20 23:01:34 +02:00
for i = 1, max_level do
levels[i] = {}
end
2018-07-14 11:33:06 +02:00
2018-07-20 23:01:34 +02:00
for y = 1, size do
local offset = (y - 1) * size
for x = 1, size do
local i = offset + x
local block = blocks[i]
if block then
local l = get_level(block)
2019-01-22 18:05:31 +02:00
local lvl = levels[l]
lvl[#lvl + 1] = i
2018-07-20 23:01:34 +02:00
end
2018-07-14 11:33:06 +02:00
end
2018-07-20 23:01:34 +02:00
end
end
2018-07-14 11:33:06 +02:00
2018-07-23 22:50:11 +02:00
local function get_template(random, templates, templates_count, counts)
local template
if templates_count == 0 then
return nil
elseif templates_count == 1 then
template = templates[1]
else
local ti = random:next_int(1, templates_count)
template = templates[ti]
end
if template == Public.empty_template then
return nil
end
local count = counts[template] or 0
local max_count = template.max_count
while count == max_count do
template = template.fallback
if template == nil then
return nil
end
count = counts[template] or 0
max_count = template.max_count
end
counts[template] = count + 1
return template
end
2018-07-24 01:45:38 +02:00
local function make_blocks(self, blocks, template)
2018-07-20 23:01:34 +02:00
local random = self.random
2019-01-10 00:29:51 +02:00
local counts = {}
2018-07-14 11:33:06 +02:00
2018-07-20 23:01:34 +02:00
local levels = blocks.levels
local wall_level = levels[1]
2018-07-14 11:33:06 +02:00
2018-07-24 01:45:38 +02:00
local walls = template.walls
2018-07-20 23:01:34 +02:00
local wall_template_count = #walls
2019-01-10 00:29:51 +02:00
while #wall_level > 0 do
local index = random:next_int(1, #wall_level)
local i = wall_level[index]
fast_remove(wall_level, index)
local block = get_template(random, walls, wall_template_count, counts)
2018-07-14 11:33:06 +02:00
2018-07-24 01:45:38 +02:00
if block == Public.empty_template then
2018-07-20 23:01:34 +02:00
blocks[i] = nil
else
2018-07-24 01:45:38 +02:00
local block_data = blocks[i]
2018-07-14 11:33:06 +02:00
2018-07-24 01:45:38 +02:00
local section = get_section(block_data)
local dir = get_4_way_direction(block_data)
2018-07-14 11:33:06 +02:00
2018-07-24 01:45:38 +02:00
local new_block = block[section + 1][dir + 1]
2018-07-20 23:01:34 +02:00
blocks[i] = new_block
end
end
2018-07-24 01:45:38 +02:00
local bases = template.bases
2018-07-23 22:50:11 +02:00
2018-07-20 23:01:34 +02:00
for l = 2, #levels do
local level = levels[l]
2018-07-24 01:45:38 +02:00
local base_templates = bases[l - 1]
2018-07-20 23:01:34 +02:00
if base_templates then
local base_template_count = #base_templates
2018-07-23 22:50:11 +02:00
while #level > 0 do
local index = random:next_int(1, #level)
local i = level[index]
2018-07-14 11:33:06 +02:00
2018-07-23 22:50:11 +02:00
fast_remove(level, index)
2018-07-24 01:45:38 +02:00
blocks[i] = get_template(random, base_templates, base_template_count, counts)
2018-07-20 23:01:34 +02:00
end
else
2019-01-22 18:05:31 +02:00
for index = 1, #level do
local i = level[index]
2018-07-20 23:01:34 +02:00
blocks[i] = nil
2018-07-14 11:33:06 +02:00
end
2018-07-20 23:01:34 +02:00
end
end
end
2018-07-14 11:33:06 +02:00
2018-07-23 22:50:11 +02:00
local remove_entity_types = {'tree', 'simple-entity'}
2019-01-21 01:58:39 +02:00
local function to_shape(blocks, part_size, on_init)
2019-01-10 00:29:51 +02:00
part_size = part_size or default_part_size
local inv_part_size = 1 / part_size
2018-07-20 23:01:34 +02:00
local size = blocks.size
local t_size = size * part_size
local half_t_size = t_size * 0.5
2018-07-14 11:33:06 +02:00
2019-01-21 01:58:39 +02:00
local outpost_id = outpost_count + 1
outpost_count = outpost_id
if on_init then
outposts[outpost_id] = {
outpost_id = outpost_id,
magic_crafters = {},
2019-01-23 21:15:28 +02:00
--magic_fluid_crafters = {},
2019-01-31 19:16:37 +02:00
market = nil,
2019-01-21 01:58:39 +02:00
turret_count = 0,
top_left = {nil, nil},
2019-01-23 21:15:28 +02:00
bottom_right = {nil, nil},
level = 1,
upgrade_rate = nil,
upgrade_base_cost = nil,
2019-03-07 23:07:33 +02:00
upgrade_cost_base = nil,
artillery_area = nil,
artillery_turrets = nil,
last_fire_tick = nil
2019-01-21 01:58:39 +02:00
}
end
2019-01-18 22:14:48 +02:00
local function shape(x, y, world)
2019-01-23 21:15:28 +02:00
x, y = floor(x + half_t_size), floor(y + half_t_size)
2018-07-20 23:01:34 +02:00
if x < 0 or y < 0 or x >= t_size or y >= t_size then
2018-07-28 14:04:14 +02:00
return false
2018-07-20 23:01:34 +02:00
end
2018-07-14 11:33:06 +02:00
2019-01-23 21:15:28 +02:00
local x2, y2 = floor(x * inv_part_size), floor(y * inv_part_size)
2018-07-14 11:33:06 +02:00
2018-07-20 23:01:34 +02:00
local template = blocks[y2 * size + x2 + 1]
if not template then
2018-07-28 14:04:14 +02:00
return false
2018-07-20 23:01:34 +02:00
end
2018-07-14 11:33:06 +02:00
2018-07-23 22:50:11 +02:00
local wx, wy = world.x, world.y
2019-01-22 18:05:31 +02:00
local entities =
world.surface.find_entities_filtered {
area = {{wx, wy}, {wx + 1, wy + 1}},
type = remove_entity_types
}
for i = 1, #entities do
local e = entities[i]
2018-07-23 22:50:11 +02:00
e.destroy()
end
2018-07-20 23:01:34 +02:00
local x3, y3 = x - x2 * part_size, y - y2 * part_size
2018-07-14 11:33:06 +02:00
2018-07-20 23:01:34 +02:00
local i = y3 * part_size + x3 + 1
local entry = template[i]
if not entry then
2018-07-28 14:04:14 +02:00
return false
2018-07-20 23:01:34 +02:00
end
2018-07-14 11:33:06 +02:00
2018-07-20 23:01:34 +02:00
local entity = entry.entity
local tile = entry.tile or true
if entity then
local data
local callback = entity.callback
if callback then
data = {outpost_id = outpost_id}
2018-07-20 23:01:34 +02:00
local cd = template[callback]
callback = cd.callback
data.callback_data = cd.data
2018-07-14 11:33:06 +02:00
end
2018-07-20 23:01:34 +02:00
return {
tile = tile,
entities = {
{
name = entity.name,
direction = entity.direction,
2019-01-10 00:29:51 +02:00
force = entity.force or template.force,
2018-07-20 23:01:34 +02:00
callback = callback,
2018-07-23 22:50:11 +02:00
data = data,
always_place = true
2018-07-20 23:01:34 +02:00
}
}
}
2018-07-14 11:33:06 +02:00
end
2018-07-20 23:01:34 +02:00
return tile
2018-07-14 11:33:06 +02:00
end
2019-01-18 22:14:48 +02:00
return b.change_map_gen_collision_hidden_tile(shape, 'water-tile', 'grass-1')
end
2019-01-18 22:14:48 +02:00
Public.to_shape = to_shape
2019-01-21 01:58:39 +02:00
function Public:do_outpost(template, on_init)
2018-07-24 01:45:38 +02:00
local settings = template.settings
local blocks = {size = settings.blocks}
2018-07-13 12:47:38 +02:00
2018-07-24 01:45:38 +02:00
do_walls(self, blocks, settings.variance, settings.min_step)
2018-07-13 12:47:38 +02:00
fill(blocks)
2018-07-24 01:45:38 +02:00
do_levels(blocks, settings.max_level)
make_blocks(self, blocks, template)
2018-07-20 23:01:34 +02:00
2019-01-21 01:58:39 +02:00
return to_shape(blocks, settings.part_size, on_init)
2018-07-20 23:01:34 +02:00
end
2018-07-23 22:50:11 +02:00
local function change_direction(entity, new_dir)
2018-07-20 23:01:34 +02:00
local copy = {}
2018-07-23 22:50:11 +02:00
for k, v in pairs(entity) do
copy[k] = v
2018-07-20 23:01:34 +02:00
end
2018-07-23 22:50:11 +02:00
copy.direction = new_dir
2018-07-20 23:01:34 +02:00
return copy
end
2018-07-13 12:47:38 +02:00
2018-07-20 23:01:34 +02:00
function Public.make_1_way(data)
data.__index = data
return data
2018-07-14 11:33:06 +02:00
end
2018-07-13 17:36:43 +02:00
2018-07-23 22:50:11 +02:00
local function set_tile(tbl, index, tile)
local entry = tbl[index]
if entry then
entry.tile = tile
else
tbl[index] = {tile = tile}
end
end
local function set_entity(tbl, index, entity)
local entry = tbl[index]
if entry then
entry.entity = entity
else
tbl[index] = {entity = entity}
end
end
2018-07-14 11:33:06 +02:00
function Public.make_4_way(data)
2019-01-10 00:29:51 +02:00
local part_size = data.part_size or default_part_size
local inv_part_size = 1 / part_size
2018-07-20 23:01:34 +02:00
local props = {}
2018-07-14 11:33:06 +02:00
local north = {}
local east = {}
local south = {}
local west = {}
local res = {north, east, south, west}
for i, entry in pairs(data) do
2018-07-20 23:01:34 +02:00
if type(i) == 'string' then
props[i] = entry
else
local y = math.ceil(i * inv_part_size)
local x = i - (y - 1) * part_size
local x2 = part_size - y + 1
local y2 = x
local x3 = part_size - x + 1
local y3 = part_size - y + 1
local x4 = y
local y4 = part_size - x + 1
local i2 = (y2 - 1) * part_size + x2
local i3 = (y3 - 1) * part_size + x3
local i4 = (y4 - 1) * part_size + x4
2018-07-23 22:50:11 +02:00
local tile = entry.tile
if tile then
set_tile(north, i, tile)
set_tile(east, i2, tile)
set_tile(south, i3, tile)
set_tile(west, i4, tile)
2018-07-20 23:01:34 +02:00
end
2018-07-23 22:50:11 +02:00
local entity = entry.entity
if entity then
local offset = entity.offset
if offset == 3 then
2019-01-10 00:29:51 +02:00
i = i + part_size + 1
i2 = i2 + part_size
2018-07-23 22:50:11 +02:00
i4 = i4 + 1
elseif offset == 1 then
i = i + 1
2019-01-10 00:29:51 +02:00
i2 = i2 + part_size
2018-07-23 22:50:11 +02:00
elseif offset == 2 then
2019-01-10 00:29:51 +02:00
i = i + part_size
2018-07-27 01:36:25 +02:00
i4 = i4 + 1
2018-07-23 22:50:11 +02:00
end
local dir = entity.direction or 0
2018-07-20 23:01:34 +02:00
2018-07-23 22:50:11 +02:00
set_entity(north, i, entity)
set_entity(east, i2, change_direction(entity, (dir + 2) % 8))
set_entity(south, i3, change_direction(entity, (dir + 4) % 8))
set_entity(west, i4, change_direction(entity, (dir + 6) % 8))
end
2018-07-13 17:36:43 +02:00
end
2018-07-20 23:01:34 +02:00
end
2018-07-13 17:36:43 +02:00
2018-07-20 23:01:34 +02:00
north.__index = north
east.__index = east
south.__index = south
west.__index = west
for k, v in pairs(props) do
north[k] = v
east[k] = v
south[k] = v
west[k] = v
2018-07-13 12:47:38 +02:00
end
2018-07-14 11:33:06 +02:00
return res
2018-07-13 12:47:38 +02:00
end
2019-01-10 00:29:51 +02:00
function Public.make_walls(data)
data.__index = data
return data
end
2018-07-20 23:01:34 +02:00
local function shallow_copy(tbl)
local copy = {}
for k, v in pairs(tbl) do
copy[k] = v
end
return copy
end
function Public.extend_1_way(data, tbl)
return setmetatable(shallow_copy(tbl), data)
end
function Public.extend_4_way(data, tbl)
return {
setmetatable(shallow_copy(tbl), data[1]),
setmetatable(shallow_copy(tbl), data[2]),
setmetatable(shallow_copy(tbl), data[3]),
setmetatable(shallow_copy(tbl), data[4])
}
end
function Public.extend_walls(data, tbl)
2019-01-10 00:29:51 +02:00
local copy = shallow_copy(tbl)
local base = {
Public.extend_4_way(data[1], copy),
Public.extend_4_way(data[2], copy),
Public.extend_4_way(data[3], copy)
2018-07-20 23:01:34 +02:00
}
2019-01-10 00:29:51 +02:00
base.__index = base
return setmetatable(copy, base)
2018-07-20 23:01:34 +02:00
end
2019-01-23 21:15:28 +02:00
local function update_market_upgrade_description(outpost_data)
local outpost_id = outpost_data.outpost_id
2019-01-24 02:25:19 +02:00
local upgrade_rate = outpost_data.upgrade_rate
local upgrade_base_cost = outpost_data.upgrade_base_cost
local upgrade_cost_base = outpost_data.upgrade_cost_base
2019-01-23 21:15:28 +02:00
local level = outpost_data.level
local base_outputs = outpost_data.base_outputs
local outpost_magic_crafters = outpost_data.magic_crafters
local prototype = Retailer.get_items(outpost_id)['upgrade']
prototype.price = upgrade_base_cost * #outpost_magic_crafters * upgrade_cost_base ^ (level - 1)
prototype.name_label = 'Upgrade Outpost to level ' .. tostring(level + 1)
local tooltip_str = {''}
local mapview_str = {''}
local count = 2
2019-01-23 21:15:28 +02:00
for k, v in pairs(base_outputs) do
local base_rate = v * 60
local upgrade_per_level = base_rate * upgrade_rate
local current_rate = base_rate + (level - 1) * upgrade_per_level
local next_rate = current_rate + upgrade_per_level
2019-01-25 02:14:26 +02:00
local name = game.item_prototypes[k]
if name then
tooltip_str[count] = concat {'[item=', k, ']'}
mapview_str[count] = name.localised_name
2019-01-25 02:14:26 +02:00
else
name = game.fluid_prototypes[k]
if name then
tooltip_str[count] = concat {'[fluid=', k, ']'}
mapview_str[count] = name.localised_name
2019-01-25 02:14:26 +02:00
else
tooltip_str[count] = k
mapview_str[count] = k
2019-01-25 02:14:26 +02:00
end
end
count = count + 1
2019-01-25 02:14:26 +02:00
local str = concat {': ', format('%.2f', current_rate), ' -> ', format('%.2f / sec', next_rate)}
tooltip_str[count] = str
tooltip_str[count + 1] = '\n'
mapview_str[count] = str
mapview_str[count + 1] = ', '
count = count + 2
2019-01-23 21:15:28 +02:00
end
tooltip_str[count - 1] = nil
mapview_str[count - 1] = nil
2019-01-23 21:15:28 +02:00
prototype.description = tooltip_str
2019-01-23 21:15:28 +02:00
prototype.disabled = false
prototype.mapview_description = mapview_str
2019-01-23 21:15:28 +02:00
Retailer.set_item(outpost_id, prototype)
end
local function do_outpost_upgrade(event)
if event.item.type ~= 'upgrade' then
return
end
local outpost_id = event.group_name
local outpost_data = outposts[outpost_id]
local outpost_magic_crafters = outpost_data.magic_crafters
2019-01-24 02:25:19 +02:00
local upgrade_rate = outpost_data.upgrade_rate
2019-01-23 21:15:28 +02:00
local level = outpost_data.level + 1
outpost_data.level = level
local player_name = event.player.name
2019-01-31 19:16:37 +02:00
local outpost_name = Retailer.get_market_group_label(outpost_id)
local message = concat {player_name, ' has upgraded ', outpost_name, ' to level ', level}
2019-01-31 19:16:37 +02:00
2019-03-08 19:49:06 +02:00
CrashSiteToast.do_outpost_toast(outpost_data.market, message)
2019-01-31 19:16:37 +02:00
Server.to_discord_bold(concat {'*** ', message, ' ***'})
2019-01-23 21:15:28 +02:00
for i = 1, #outpost_magic_crafters do
local crafter = outpost_magic_crafters[i]
local rate = crafter.rate
local upgrade_amount = upgrade_rate * crafter.base_rate
crafter.rate = rate + upgrade_amount
end
update_market_upgrade_description(outpost_data)
end
2019-01-24 02:25:19 +02:00
local function activate_market_upgrade(outpost_data)
local outpost_magic_crafters = outpost_data.magic_crafters
2019-01-24 02:25:19 +02:00
if #outpost_magic_crafters == 0 then
local outpost_id = outpost_data.outpost_id
2019-01-24 02:25:19 +02:00
local prototype = Retailer.get_items(outpost_id)['upgrade']
prototype.disabled_reason = 'No machines to upgrade.'
Retailer.set_item(outpost_id, prototype)
2019-01-23 21:15:28 +02:00
return
end
2019-01-23 21:15:28 +02:00
local base_outputs = {}
for i = 1, #outpost_magic_crafters do
local crafter = outpost_magic_crafters[i]
local item = crafter.item
local count = base_outputs[item] or 0
count = count + crafter.rate
base_outputs[item] = count
end
outpost_data.base_outputs = base_outputs
update_market_upgrade_description(outpost_data)
end
2019-01-24 02:25:19 +02:00
function Public.activate_market_upgrade(outpost_id)
local outpost_data = outposts[outpost_id]
activate_market_upgrade(outpost_data)
end
local function do_capture_outpost(outpost_data)
local area = {top_left = outpost_data.top_left, bottom_right = outpost_data.bottom_right}
local walls = RS.get_surface().find_entities_filtered {area = area, force = 'enemy', name = 'stone-wall'}
for i = 1, #walls do
walls[i].force = 'player'
end
local outpost_id = outpost_data.outpost_id
local name = Retailer.get_market_group_label(outpost_id)
if name == 'Market' then
return
end
local donators = Donator.get_donators_table()
2019-01-31 19:16:37 +02:00
if next(donators) then
local donator = table.get_random_dictionary_entry(donators, true)
if donator then
name = concat({donator, "'s ", name})
Retailer.set_market_group_label(outpost_id, name)
end
end
local message = 'Outpost captured: ' .. name
2019-03-08 19:49:06 +02:00
CrashSiteToast.do_outpost_toast(outpost_data.market, message)
2019-01-31 19:16:37 +02:00
Server.to_discord_bold(concat {'*** ', message, ' ***'})
2019-01-24 02:25:19 +02:00
activate_market_upgrade(outpost_data)
end
2018-07-20 23:01:34 +02:00
local function do_refill_turrets()
local index = refill_turrets.index
if index > #refill_turrets then
refill_turrets.index = 1
return
end
local turret_data = refill_turrets[index]
local turret = turret_data.turret
2018-07-20 23:01:34 +02:00
if not turret.valid then
fast_remove(refill_turrets, index)
return
end
refill_turrets.index = index + 1
local data = turret_data.data
2018-07-20 23:01:34 +02:00
if data.liquid then
turret.fluidbox[1] = data
elseif data then
turret.insert(data)
2018-07-20 23:01:34 +02:00
end
end
2019-03-07 23:07:33 +02:00
local artillery_target_entities = {
2019-05-02 17:02:53 +02:00
'character',
2019-03-07 23:07:33 +02:00
'tank',
'car',
'locomotive',
'cargo-wagon',
'fluid-wagon',
'artillery-wagon',
'spidertron'
2019-03-07 23:07:33 +02:00
}
2019-03-16 15:08:44 +02:00
local artillery_target_callback =
Token.register(
function(data)
local position = data.position
local entity = data.entity
if not entity.valid then
return
end
local tx, ty = position.x, position.y
local pos = entity.position
local x, y = pos.x, pos.y
local dx, dy = tx - x, ty - y
local d = dx * dx + dy * dy
if d >= 1024 then -- 32 ^ 2
entity.surface.create_entity {
name = 'artillery-projectile',
position = position,
target = entity,
speed = 1.5
}
if entity.name == "spidertron" then
-- fire a rocket as well as artillery-projectile since artillery-projectile doesn't damage spidertrons
-- Balance note: 1 rocket per artillery kills spidertron shield fast but takes ~ 1 minute to kill the spidertron
entity.surface.create_entity {
name = 'rocket',
position = position,
target = entity,
speed = 1.5
}
end
2019-03-16 15:08:44 +02:00
end
end
)
2019-03-07 23:07:33 +02:00
local function do_artillery_turrets_targets()
local index = artillery_outposts.index
if index > #artillery_outposts then
artillery_outposts.index = 1
return
end
artillery_outposts.index = index + 1
local outpost = artillery_outposts[index]
local now = game.tick
2019-03-16 15:08:44 +02:00
if now - outpost.last_fire_tick < 480 then
2019-03-07 23:07:33 +02:00
return
end
local turrets = outpost.artillery_turrets
for i = #turrets, 1, -1 do
local turret = turrets[i]
if not turret.valid then
fast_remove(turrets, i)
end
end
local count = #turrets
if count == 0 then
fast_remove(artillery_outposts, index)
return
end
outpost.last_fire_tick = now
local turret = turrets[1]
local area = outpost.artillery_area
local surface = turret.surface
local entities = surface.find_entities_filtered {area = area, name = artillery_target_entities}
if #entities == 0 then
return
end
2019-03-16 15:08:44 +02:00
local position = turret.position
2019-03-07 23:07:33 +02:00
for i = 1, count do
local entity = entities[math.random(#entities)]
if entity and entity.valid then
2019-03-16 15:08:44 +02:00
local data = {position = position, entity = entity}
Task.set_timeout_in_ticks(i * 60, artillery_target_callback, data)
2019-03-07 23:07:33 +02:00
end
end
end
local server_player = {name = '<server>', print = print}
local function set_pollution_multiplier(args, player)
local multiplier = tonumber(args.multiplier)
2021-02-19 17:28:14 +02:00
player = player or server_player
2021-02-19 17:30:29 +02:00
if not multiplier then
player.print("Fail")
return
2021-02-03 12:59:47 +02:00
end
2021-09-29 09:34:56 +02:00
if multiplier < base_pollution_multiplier then
if base_pollution_multiplier == pollution_multiplier.value then -- no change, so not necessary to message all admins and update the value
player.print("Magic crafter pollution is already at minimum value of " .. base_pollution_multiplier)
return
else -- update the value to the minimum and continue to message all admins
player.print("Setting magic crafter pollution multiplier to the minimum value of " .. base_pollution_multiplier)
multiplier = base_pollution_multiplier
end
2021-09-27 23:11:06 +02:00
end
local old_multiplier = pollution_multiplier.value
pollution_multiplier.value = multiplier
2021-02-08 15:00:34 +02:00
local message = player.name..' changed magic crafter pollution multiplier from '..old_multiplier..' to '..pollution_multiplier.value
for _, p in pairs(game.players) do
if p.admin then
p.print(message)
end
end
end
2021-02-08 15:49:55 +02:00
local function get_pollution_multiplier(_, player)
player = player or server_player
2021-02-05 17:24:18 +02:00
player.print('Current pollution multiplier is: '..pollution_multiplier.value)
end
2018-07-20 23:01:34 +02:00
local function do_magic_crafters()
2019-01-23 21:15:28 +02:00
local limit = #magic_crafters
if limit == 0 then
return
end
2018-07-20 23:01:34 +02:00
local index = magic_crafters.index
2019-01-23 21:15:28 +02:00
for i = 1, magic_crafters_per_tick do
if index > limit then
index = 1
end
local data = magic_crafters[index]
local entity = data.entity
if not entity.valid then
fast_remove(magic_crafters, index)
2019-03-16 15:08:44 +02:00
limit = limit - 1
if limit == 0 then
return
end
2019-01-23 21:15:28 +02:00
else
index = index + 1
local tick = game.tick
local last_tick = data.last_tick
local rate = data.rate
local count = (tick - last_tick) * rate
local fcount = floor(count)
if fcount > 0 then
local output_inv = entity.get_output_inventory()
if output_inv.can_insert(data.item) then -- No pollution if full. Taking items out of crafters makes pollution
local pollution_amount = pollution_multiplier.value * 0.01
local pollution_position = {0,0}
entity.surface.pollute(pollution_position, pollution_amount)
output_inv.insert {name = data.item, count = fcount}
end
2019-01-23 21:15:28 +02:00
data.last_tick = tick - (count - fcount) / rate
end
end
2018-07-20 23:01:34 +02:00
end
2019-01-23 21:15:28 +02:00
magic_crafters.index = index
end
2018-07-20 23:01:34 +02:00
2019-01-23 21:15:28 +02:00
local function do_magic_fluid_crafters()
local limit = #magic_fluid_crafters
if limit == 0 then
2018-07-20 23:01:34 +02:00
return
end
2019-01-23 21:15:28 +02:00
local index = magic_fluid_crafters.index
2018-07-20 23:01:34 +02:00
2019-01-23 21:15:28 +02:00
for i = 1, magic_fluid_crafters_per_tick do
if index > limit then
index = 1
end
2018-07-20 23:01:34 +02:00
2019-01-23 21:15:28 +02:00
local data = magic_fluid_crafters[index]
2018-07-20 23:01:34 +02:00
2019-01-23 21:15:28 +02:00
local entity = data.entity
if not entity.valid then
fast_remove(magic_fluid_crafters, index)
2019-03-16 15:08:44 +02:00
limit = limit - 1
if limit == 0 then
return
end
2019-01-23 21:15:28 +02:00
else
index = index + 1
2018-07-20 23:01:34 +02:00
2019-01-23 21:15:28 +02:00
local tick = game.tick
local last_tick = data.last_tick
local rate = data.rate
2018-07-20 23:01:34 +02:00
2019-01-23 21:15:28 +02:00
local count = (tick - last_tick) * rate
local fcount = floor(count)
if fcount > 0 then
local fluidbox_index = data.fluidbox_index
local fb = entity.fluidbox
local fb_data = fb[fluidbox_index] or {name = data.item, amount = 0}
fb_data.amount = fb_data.amount + fcount
fb[fluidbox_index] = fb_data
data.last_tick = tick - (count - fcount) / rate
end
2018-07-20 23:01:34 +02:00
end
end
2019-01-23 21:15:28 +02:00
magic_fluid_crafters.index = index
2018-07-20 23:01:34 +02:00
end
local function tick()
do_refill_turrets()
2019-03-07 23:07:33 +02:00
do_artillery_turrets_targets()
2018-07-20 23:01:34 +02:00
do_magic_crafters()
2019-01-23 21:15:28 +02:00
do_magic_fluid_crafters()
2018-07-20 23:01:34 +02:00
end
Public.refill_turret_callback =
Token.register(
function(turret, data)
local outpost_id = data.outpost_id
2019-01-22 18:05:31 +02:00
refill_turrets[#refill_turrets + 1] = {turret = turret, data = data.callback_data}
turret_to_outpost[turret.unit_number] = outpost_id
local outpost_data = outposts[outpost_id]
outpost_data.turret_count = outpost_data.turret_count + 1
2018-07-20 23:01:34 +02:00
end
)
Public.refill_liquid_turret_callback =
Token.register(
function(turret, data)
local callback_data = data.callback_data
callback_data.liquid = true
2018-07-20 23:01:34 +02:00
local outpost_id = data.outpost_id
2019-01-22 18:05:31 +02:00
refill_turrets[#refill_turrets + 1] = {turret = turret, data = callback_data}
turret_to_outpost[turret.unit_number] = outpost_id
2018-07-20 23:01:34 +02:00
local outpost_data = outposts[outpost_id]
outpost_data.turret_count = outpost_data.turret_count + 1
2018-07-20 23:01:34 +02:00
end
)
2019-03-07 23:07:33 +02:00
Public.refill_artillery_turret_callback =
Token.register(
function(turret, data)
local outpost_id = data.outpost_id
refill_turrets[#refill_turrets + 1] = {turret = turret, data = data.callback_data}
turret_to_outpost[turret.unit_number] = outpost_id
local outpost_data = outposts[outpost_id]
outpost_data.turret_count = outpost_data.turret_count + 1
local artillery_turrets = outpost_data.artillery_turrets
if not artillery_turrets then
artillery_turrets = {}
outpost_data.artillery_turrets = artillery_turrets
local pos = turret.position
local x, y = pos.x, pos.y
2019-03-16 15:08:44 +02:00
outpost_data.artillery_area = {{x - 112, y - 112}, {x + 112, y + 112}}
2019-03-07 23:07:33 +02:00
outpost_data.last_fire_tick = 0
artillery_outposts[#artillery_outposts + 1] = outpost_data
end
artillery_turrets[#artillery_turrets + 1] = turret
end
)
Public.power_source_callback =
2018-08-01 17:35:48 +02:00
Token.register(
2019-01-22 18:05:31 +02:00
function(turret, data)
local outpost_id = data.outpost_id
local callback_data = data.callback_data
2018-08-01 17:35:48 +02:00
local power_source =
2019-01-22 18:05:31 +02:00
turret.surface.create_entity {name = 'hidden-electric-energy-interface', position = turret.position}
power_source.electric_buffer_size = callback_data.buffer_size
power_source.power_production = callback_data.power_production
power_source.destructible = false
2018-08-01 17:35:48 +02:00
2019-01-22 18:05:31 +02:00
power_sources[turret.unit_number] = {entity = power_source}
turret_to_outpost[turret.unit_number] = outpost_id
local outpost_data = outposts[outpost_id]
outpost_data.turret_count = outpost_data.turret_count + 1
end
)
Public.worm_turret_callback =
Token.register(
function(turret, data)
local outpost_id = data.outpost_id
turret_to_outpost[turret.unit_number] = outpost_id
2018-08-01 17:35:48 +02:00
local outpost_data = outposts[outpost_id]
outpost_data.turret_count = outpost_data.turret_count + 1
2018-08-01 17:35:48 +02:00
end
)
local function add_magic_crafter_output(entity, output, distance, outpost_id)
2018-07-20 23:01:34 +02:00
local rate = output.min_rate + output.distance_factor * distance
2019-01-23 21:15:28 +02:00
local fluidbox_index = output.fluidbox_index
local data = {
entity = entity,
last_tick = game.tick,
2019-01-23 21:15:28 +02:00
base_rate = rate,
rate = rate,
item = output.item,
2019-01-23 21:15:28 +02:00
fluidbox_index = fluidbox_index
}
2019-01-23 21:15:28 +02:00
if fluidbox_index then
magic_fluid_crafters[#magic_fluid_crafters + 1] = data
else
magic_crafters[#magic_crafters + 1] = data
end
local outpost_magic_crafters = outposts[outpost_id].magic_crafters
outpost_magic_crafters[#outpost_magic_crafters + 1] = data
2018-07-20 23:01:34 +02:00
end
local set_inactive_token =
Token.register(
function(entity)
if entity.valid then
entity.active = false
end
end
)
local change_to_player_force_callback = Token.register(function(entity)
if entity.valid then
entity.force = 'player'
end
end)
2018-07-20 23:01:34 +02:00
Public.magic_item_crafting_callback =
Token.register(
function(entity, data)
local outpost_id = data.outpost_id
local callback_data = data.callback_data
2018-07-20 23:01:34 +02:00
entity.minable = false
entity.destructible = false
2018-07-24 01:45:38 +02:00
entity.operable = false
-- This is so the recipe is set for furnaces even if the player force hasn't unlocked them yet.
entity.force = 'neutral'
Task.set_timeout_in_ticks(1, change_to_player_force_callback, entity)
2018-07-20 23:01:34 +02:00
local recipe = callback_data.recipe
2021-02-05 17:24:18 +02:00
if recipe then
2018-07-20 23:01:34 +02:00
entity.set_recipe(recipe)
if not callback_data.has_fluid_output then -- to avoid trying to put an item into a fluid inventory
2021-02-05 17:24:18 +02:00
entity.get_output_inventory().insert(callback_data.output.item)
end
else
local furnace_item = callback_data.furnace_item
if furnace_item then
2018-07-20 23:01:34 +02:00
local inv = entity.get_inventory(2) -- defines.inventory.furnace_source
2021-02-05 17:26:09 +02:00
inv.insert(furnace_item)
2021-02-05 17:24:18 +02:00
entity.get_output_inventory().insert(callback_data.output.item)
2018-07-20 23:01:34 +02:00
end
end
local p = entity.position
2018-07-23 22:50:11 +02:00
local x, y = p.x, p.y
local distance = math.sqrt(x * x + y * y)
2018-07-20 23:01:34 +02:00
local output = callback_data.output
2018-07-20 23:01:34 +02:00
if #output == 0 then
add_magic_crafter_output(entity, output, distance, outpost_id)
2018-07-20 23:01:34 +02:00
else
2019-01-22 18:05:31 +02:00
for i = 1, #output do
local o = output[i]
add_magic_crafter_output(entity, o, distance, outpost_id)
2018-07-20 23:01:34 +02:00
end
end
2021-02-05 17:24:18 +02:00
if not callback_data.has_fluid_output then
2018-07-28 14:04:14 +02:00
Task.set_timeout_in_ticks(2, set_inactive_token, entity) -- causes problems with refineries.
end
2018-07-20 23:01:34 +02:00
end
)
2019-01-24 15:08:33 +02:00
Public.magic_item_crafting_callback_weighted =
Token.register(
function(entity, data)
local outpost_id = data.outpost_id
local callback_data = data.callback_data
entity.minable = false
entity.destructible = false
entity.operable = false
-- This is so the recipe is set for furnaces even if the player force hasn't unlocked them yet.
entity.force = 'neutral'
Task.set_timeout_in_ticks(1, change_to_player_force_callback, entity)
2019-01-24 15:08:33 +02:00
local weights = callback_data.weights
local loot = callback_data.loot
local i = math.random() * weights.total
local index = table.binary_search(weights, i)
if (index < 0) then
index = bit32.bnot(index)
end
local stack = loot[index].stack
if not stack then
return
end
local recipe = stack.recipe
if recipe then
entity.set_recipe(recipe)
local output_inv = entity.get_output_inventory()
output_inv.insert {name = stack.output.item, count = 200}
2019-01-24 15:08:33 +02:00
else
local furnace_item = stack.furnace_item
if furnace_item then
2019-01-24 15:08:33 +02:00
local inv = entity.get_inventory(2) -- defines.inventory.furnace_source
inv.insert {name = furnace_item, count = 200}
local output_inv = entity.get_output_inventory()
output_inv.insert {name = stack.output.item, count = 200 }
2019-01-24 15:08:33 +02:00
end
end
local p = entity.position
local x, y = p.x, p.y
local distance = math.sqrt(x * x + y * y)
local output = stack.output
if #output == 0 then
add_magic_crafter_output(entity, output, distance, outpost_id)
else
2019-01-27 19:39:47 +02:00
for o_i = 1, #output do
local o = output[o_i]
2019-01-24 15:08:33 +02:00
add_magic_crafter_output(entity, o, distance, outpost_id)
end
end
2021-02-05 17:24:18 +02:00
if not callback_data.has_fluid_output then
2019-01-24 15:08:33 +02:00
Task.set_timeout_in_ticks(2, set_inactive_token, entity) -- causes problems with refineries.
end
end
)
Public.wall_callback =
Token.register(
function(entity, data)
if not entity.valid then
return
end
local position = entity.position
local px, py = position.x, position.y
local outpost_id = data.outpost_id
local outpost_data = outposts[outpost_id]
local top_left = outpost_data.top_left
local bottom_right = outpost_data.bottom_right
local tx, ty = top_left.x, top_left.y
local bx, by = bottom_right.x, bottom_right.y
if not tx or px < tx then
top_left.x = px
end
if not ty or py < ty then
top_left.y = py
end
if not bx or px > bx then
bottom_right.x = px
end
if not by or py > by then
bottom_right.y = py
end
end
)
2018-07-20 23:01:34 +02:00
Public.deactivate_callback =
Token.register(
function(entity)
entity.active = false
entity.operable = false
entity.destructible = false
end
)
Public.scenario_chest_callback = Token.register(function(chest)
if not chest or not chest.valid then
return
end
chest.destructible = false
chest.minable = false
end)
2019-01-22 18:05:31 +02:00
local function turret_died(event)
2018-07-20 23:01:34 +02:00
local entity = event.entity
if not entity or not entity.valid then
return
end
local number = entity.unit_number
2018-07-23 22:50:11 +02:00
if not number then
return
end
2019-01-22 18:05:31 +02:00
local ps_data = power_sources[number]
if ps_data then
power_sources[number] = nil
2018-07-20 23:01:34 +02:00
2019-01-22 18:05:31 +02:00
local ps_entity = ps_data.entity
2019-01-22 18:05:31 +02:00
if ps_entity and ps_entity.valid then
ps_entity.destroy()
end
end
2019-01-22 18:05:31 +02:00
local outpost_id = turret_to_outpost[number]
if outpost_id then
local outpost_data = outposts[outpost_id]
2019-01-22 18:05:31 +02:00
local turret_count = outpost_data.turret_count - 1
outpost_data.turret_count = turret_count
2019-01-22 18:05:31 +02:00
if turret_count == 0 then
2019-01-23 21:15:28 +02:00
do_capture_outpost(outpost_data)
2019-01-22 18:05:31 +02:00
end
2018-07-20 23:01:34 +02:00
end
end
2018-07-23 22:50:11 +02:00
Public.market_set_items_callback =
Token.register(
function(entity, data)
if not entity.valid then
return
end
local callback_data = data.callback_data
2018-07-23 22:50:11 +02:00
entity.destructible = false
local market_id = data.outpost_id
2019-01-23 21:15:28 +02:00
local outpost_data = outposts[market_id]
2019-01-24 02:25:19 +02:00
local upgrade_base_cost = callback_data.upgrade_base_cost or 0
2019-01-23 21:15:28 +02:00
2019-01-31 19:16:37 +02:00
outpost_data.market = entity
2019-01-24 02:25:19 +02:00
outpost_data.upgrade_rate = callback_data.upgrade_rate
2019-01-23 21:15:28 +02:00
outpost_data.upgrade_base_cost = upgrade_base_cost
2019-01-24 02:25:19 +02:00
outpost_data.upgrade_cost_base = callback_data.upgrade_cost_base
2019-01-23 21:15:28 +02:00
Retailer.add_market(market_id, entity)
Retailer.set_market_group_label(market_id, callback_data.market_name)
2018-07-23 22:50:11 +02:00
2019-01-23 21:15:28 +02:00
Retailer.set_item(
market_id,
{
name = 'upgrade',
type = 'upgrade',
name_label = 'Upgrade Outpost',
sprite = 'item-group/production',
2019-01-24 02:25:19 +02:00
price = 0,
2019-01-23 21:15:28 +02:00
stack_limit = 1,
disabled = true,
disabled_reason = 'Outpost must be captured first.',
description = 'Increases output.'
}
)
2018-07-23 22:50:11 +02:00
local p = entity.position
local x, y = p.x, p.y
local d = math.sqrt(x * x + y * y)
for i = 1, #callback_data do
local item = callback_data[i]
2018-07-23 22:50:11 +02:00
local price = item.price
2018-08-01 17:35:48 +02:00
local df = item.distance_factor
if df then
local min_price = item.min_price or 1
price = item.price - d * df
price = math.max(price, min_price)
end
2018-07-23 22:50:11 +02:00
2019-01-14 13:10:34 +02:00
Retailer.set_item(
market_id,
{
name = item.name,
type = item.type,
price = price,
stack_limit = item.stack_limit,
name_label = item.name_label,
sprite = item.sprite,
disabled = item.disabled,
disabled_reason = item.disabled_reason,
description = item.description}
2019-01-14 13:10:34 +02:00
)
2018-07-23 22:50:11 +02:00
end
end
)
2018-07-20 23:01:34 +02:00
Public.firearm_magazine_ammo = {name = 'firearm-magazine', count = 200}
Public.piercing_rounds_magazine_ammo = {name = 'piercing-rounds-magazine', count = 200}
Public.uranium_rounds_magazine_ammo = {name = 'uranium-rounds-magazine', count = 200}
2018-07-27 01:36:25 +02:00
Public.artillery_shell_ammo = {name = 'artillery-shell', count = 15}
2018-07-20 23:01:34 +02:00
Public.light_oil_ammo = {name = 'light-oil', amount = 100}
Public.laser_turrent_power_source = {buffer_size = 2400000, power_production = 40000}
2018-07-23 22:50:11 +02:00
function Public.prepare_weighted_loot(loot)
local total = 0
local weights = {}
2019-01-22 18:05:31 +02:00
for i = 1, #loot do
local v = loot[i]
2018-07-23 22:50:11 +02:00
total = total + v.weight
2019-01-22 18:05:31 +02:00
weights[#weights + 1] = total
2018-07-23 22:50:11 +02:00
end
weights.total = total
return weights
end
function Public.do_random_loot(entity, weights, loot)
if not entity.valid then
return
end
entity.operable = false
2019-01-31 19:16:37 +02:00
--entity.destructible = false
2018-07-23 22:50:11 +02:00
local i = math.random() * weights.total
local index = table.binary_search(weights, i)
if (index < 0) then
index = bit32.bnot(index)
end
local stack = loot[index].stack
if not stack then
return
end
local df = stack.distance_factor
local count
if df then
local p = entity.position
local x, y = p.x, p.y
local d = math.sqrt(x * x + y * y)
count = stack.count + d * df
else
count = stack.count
end
entity.insert {name = stack.name, count = count}
end
2018-07-28 14:04:14 +02:00
function Public.do_random_fluid_loot(entity, weights, loot)
if not entity.valid then
return
end
entity.operable = false
entity.destructible = false
entity.force = 'player'
2018-07-28 14:04:14 +02:00
local i = math.random() * weights.total
local index = table.binary_search(weights, i)
if (index < 0) then
index = bit32.bnot(index)
end
local stack = loot[index].stack
if not stack then
return
end
local df = stack.distance_factor
local count
if df then
local p = entity.position
local x, y = p.x, p.y
local d = math.sqrt(x * x + y * y)
count = stack.count + d * df
else
count = stack.count
end
entity.fluidbox[1] = {name = stack.name, amount = count}
end
2019-01-10 00:29:51 +02:00
function Public.do_factory_loot(entity, weights, loot)
if not entity.valid then
return
end
entity.operable = false
entity.destructible = false
entity.force = 'player'
2019-01-10 00:29:51 +02:00
local i = math.random() * weights.total
local index = table.binary_search(weights, i)
if (index < 0) then
index = bit32.bnot(index)
end
local stack = loot[index].stack
if not stack then
return
end
local df = stack.distance_factor
local count
if df then
local p = entity.position
local x, y = p.x, p.y
local d = math.sqrt(x * x + y * y)
count = stack.count + d * df
else
count = stack.count
end
local name = stack.name
entity.set_recipe(name)
entity.get_output_inventory().insert {name = name, count = count}
end
2019-03-08 19:31:00 +02:00
local function market_selected(event)
local player = game.get_player(event.player_index)
if not player or not player.valid then
return
end
if player.render_mode == render_mode_game then
return
end
2019-03-08 19:31:00 +02:00
local selected = player.selected
if not selected or not selected.valid or selected.name ~= 'market' then
return
end
local group = Retailer.get_market_group_name(selected)
local prototype = Retailer.get_items(group)['upgrade']
if prototype.disabled then
return
end
local args = {
text = nil,
target = selected,
target_offset = nil,
alignment = 'center',
surface = selected.surface,
color = {1, 1, 1},
players = {player},
scale = 1.5,
scale_with_zoom = true,
time_to_live = 180
}
args.text = prototype.name_label
args.target_offset = {0, -6.5}
2019-03-08 19:31:00 +02:00
draw_text(args)
args.text = 'Price: ' .. prototype.price
args.target_offset = {0, -5}
2019-03-08 19:31:00 +02:00
draw_text(args)
args.text = prototype.mapview_description
args.target_offset = {0, -3.5}
2019-03-08 19:31:00 +02:00
draw_text(args)
end
2018-07-20 23:01:34 +02:00
Event.add(defines.events.on_tick, tick)
2019-01-22 18:05:31 +02:00
Event.add(defines.events.on_entity_died, turret_died)
2018-07-20 23:01:34 +02:00
2018-07-24 01:45:38 +02:00
Event.on_init(
function()
game.forces.neutral.recipes['steel-plate'].enabled = true
end
)
2019-01-23 21:15:28 +02:00
Event.add(Retailer.events.on_market_purchase, do_outpost_upgrade)
2019-03-08 19:31:00 +02:00
Event.add(defines.events.on_selected_entity_changed, market_selected)
Command.add(
2021-02-08 15:00:34 +02:00
'set-pollution-multiplier',
{
description = {'command_description.set_pollution_multiplier'},
arguments = {'multiplier'},
required_rank = Ranks.admin,
capture_excess_arguments = true,
allowed_by_server = true
},
set_pollution_multiplier
)
Command.add(
2021-02-08 15:00:34 +02:00
'get-pollution-multiplier',
{
description = {'command_description.get_pollution_multiplier'},
2021-02-19 17:28:14 +02:00
required_rank = Ranks.guest,
capture_excess_arguments = true,
allowed_by_server = true
},
get_pollution_multiplier
)
2018-07-13 12:47:38 +02:00
return Public