1
0
mirror of https://github.com/ComfyFactory/ComfyFactorio.git synced 2025-02-07 13:31:40 +02:00

Merge pull request #228 from klugemonkey/master

Initial Commit for Scrap Towny FFA Map
This commit is contained in:
MewMew 2021-02-10 09:06:38 +01:00 committed by GitHub
commit a80fa1c9af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 5491 additions and 0 deletions

View File

@ -205,6 +205,7 @@ require 'modules.autostash'
--require 'maps.cube'
--require 'maps.mountain_race.main'
--require 'maps.native_war.main'
--require 'maps.scrap_towny_ffa.main'
---------------------------------------------------------------
---------------- MORE MODULES HERE ----------------
@ -225,6 +226,7 @@ require 'modules.autostash'
--require 'terrain_layouts.scrap_02'
--require 'terrain_layouts.watery_world'
--require 'terrain_layouts.tree_01'
--require 'terrain_layouts.scrap_towny_ffa'
---------------------------------------------------------------
if _DUMP_ENV then

View File

@ -0,0 +1,139 @@
require "modules.custom_death_messages"
require "modules.flashlight_toggle_button"
require "modules.global_chat_toggle"
require "modules.worms_create_oil_patches"
require "modules.biters_yield_coins"
require "modules.scrap_towny_ffa.mining"
require "modules.scrap_towny_ffa.on_tick_schedule"
require "modules.scrap_towny_ffa.building"
require "modules.scrap_towny_ffa.town_center"
require "modules.scrap_towny_ffa.market"
require "modules.scrap_towny_ffa.slots"
require "modules.scrap_towny_ffa.wreckage_yields_scrap"
require "modules.scrap_towny_ffa.rocks_yield_ore_veins"
require "modules.scrap_towny_ffa.spawners_contain_biters"
require "modules.scrap_towny_ffa.explosives_are_explosive"
require "modules.scrap_towny_ffa.fluids_are_explosive"
require "modules.scrap_towny_ffa.trap"
require "modules.scrap_towny_ffa.turrets_drop_ammo"
require "modules.scrap_towny_ffa.combat_balance"
local Table = require "modules.scrap_towny_ffa.table"
local Nauvis = require "modules.scrap_towny_ffa.nauvis"
local Biters = require "modules.scrap_towny_ffa.biters"
local Pollution = require "modules.scrap_towny_ffa.pollution"
local Fish = require "modules.scrap_towny_ffa.fish_reproduction"
local Info = require "modules.scrap_towny_ffa.info"
local Team = require "modules.scrap_towny_ffa.team"
local Spawn = require "modules.scrap_towny_ffa.spawn"
local Radar = require "modules.scrap_towny_ffa.limited_radar"
local default_surface = "nauvis"
local function on_player_joined_game(event)
local ffatable = Table.get_table()
local player = game.players[event.player_index]
local surface = game.surfaces[default_surface]
player.game_view_settings.show_minimap = false
player.game_view_settings.show_map_view_options = false
player.game_view_settings.show_entity_info = true
--player.game_view_settings.show_side_menu = false
Info.toggle_button(player)
Info.show(player)
Team.set_player_color(player)
if player.force ~= game.forces.player then return end
-- setup outlanders
Team.set_player_to_outlander(player)
if player.online_time == 0 then
player.teleport({ 0, 0 }, game.surfaces["limbo"])
Team.give_outlander_items(player)
Team.give_key(player)
-- first time spawn point
local spawn_point = Spawn.get_spawn_point(player, surface)
Spawn.clear_spawn_point(spawn_point, surface)
player.teleport(spawn_point, surface)
return
end
if not ffatable.requests[player.index] then return end
if ffatable.requests[player.index] ~= "kill-character" then return end
if player.character then
if player.character.valid then
player.character.die()
end
end
ffatable.requests[player.index] = nil
end
local function on_player_respawned(event)
local ffatable = Table.get_table()
local player = game.players[event.player_index]
local surface = player.surface
if player.force == game.forces["rogue"] then Team.set_player_to_outlander(player) end
if player.force == game.forces["player"] then Team.give_key(player) end
-- TODO: this needs fixing!
-- 5 second cooldown
--local last_respawn = ffatable.cooldowns_last_respawn[player.name]
--if last_respawn == nil then last_respawn = 0 end
local spawn_point = Spawn.get_spawn_point(player, surface)
-- reset cooldown
ffatable.cooldowns_last_respawn[player.name] = game.tick
player.teleport(surface.find_non_colliding_position("character", spawn_point, 0, 0.5, false), surface)
end
local function on_player_died(event)
local ffatable = Table.get_table()
local player = game.players[event.player_index]
ffatable.cooldowns_last_death[player.name] = game.tick
end
local function on_init()
local ffatable = Table.get_table()
--log("on_init")
game.enemy_has_vision_on_land_mines = false
game.draw_resource_selection = true
game.disable_tutorial_triggers()
ffatable.cooldowns_last_respawn = {}
ffatable.cooldowns_last_death = {}
Nauvis.initialize()
Team.initialize()
end
local tick_actions = {
[60 * 0] = Radar.reset, -- each minute, at 00 seconds
[60 * 5] = Team.update_town_chart_tags, -- each minute, at 05 seconds
[60 * 10] = Team.set_all_player_colors, -- each minute, at 10 seconds
[60 * 15] = Fish.reproduce, -- each minute, at 15 seconds
[60 * 25] = Biters.unit_groups_start_moving, -- each minute, at 25 seconds
[60 * 30] = Radar.reset, -- each minute, at 30 seconds
[60 * 45] = Biters.validate_swarms, -- each minute, at 45 seconds
[60 * 50] = Biters.swarm, -- each minute, at 50 seconds
[60 * 55] = Pollution.market_scent -- each minute, at 55 seconds
}
local function on_nth_tick(event)
-- run each second
local tick = event.tick
local seconds = tick % 3600 -- tick will recycle minute
if not tick_actions[seconds] then return end
tick_actions[seconds]()
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.on_nth_tick(60, on_nth_tick) -- once every second
Event.add(defines.events.on_player_joined_game, on_player_joined_game)
Event.add(defines.events.on_player_respawned, on_player_respawned)
Event.add(defines.events.on_player_died, on_player_died)

View File

@ -0,0 +1,210 @@
local Public = {}
local math_random = math.random
local math_floor = math.floor
local math_sqrt = math.sqrt
local math_round = math.round
local table_size = table.size
local table_insert = table.insert
local table_remove = table.remove
local table_shuffle = table.shuffle_table
local Global = require 'utils.global'
local tick_schedule = {}
Global.register(
tick_schedule,
function(t)
tick_schedule = t
end
)
local Table = require 'modules.scrap_towny_ffa.table'
local Evolution = require "modules.scrap_towny_ffa.evolution"
local function get_commmands(target, group)
local commands = {}
local group_position = { x = group.position.x, y = group.position.y }
local step_length = 128
local target_position = target.position
local distance_to_target = math_floor(math_sqrt((target_position.x - group_position.x) ^ 2 + (target_position.y - group_position.y) ^ 2))
local steps = math_floor(distance_to_target / step_length) + 1
local vector = { math_round((target_position.x - group_position.x) / steps, 3), math_round((target_position.y - group_position.y) / steps, 3) }
for _ = 1, steps, 1 do
group_position.x = group_position.x + vector[1]
group_position.y = group_position.y + vector[2]
local position = group.surface.find_non_colliding_position("small-biter", group_position, step_length, 2)
if position then
commands[#commands + 1] = {
type = defines.command.attack_area,
destination = { x = position.x, y = position.y },
radius = 16,
distraction = defines.distraction.by_damage
}
end
end
commands[#commands + 1] = {
type = defines.command.attack_area,
destination = target.position,
radius = 12,
distraction = defines.distraction.by_enemy,
}
commands[#commands + 1] = {
type = defines.command.attack,
target = target,
distraction = defines.distraction.by_anything,
}
return commands
end
local function roll_market()
local ffatable = Table.get_table()
local town_centers = ffatable.town_centers
if town_centers == nil or table_size(town_centers) == 0 then return end
local keyset = {}
for town_name, _ in pairs(town_centers) do
table_insert(keyset, town_name)
end
local tc = math_random(1, #keyset)
return town_centers[keyset[tc]]
end
local function get_random_close_spawner(surface, market, radius)
local units = surface.find_enemy_units(market.position, radius, market.force)
if units ~= nil and #units > 0 then
-- found units, shuffle the list
table_shuffle(units)
while units[1] do
local unit = units[1]
if unit.spawner then return unit.spawner end
table_remove(units, 1)
end
end
end
local function is_swarm_valid(swarm)
local group = swarm.group
if not group then return end
if not group.valid then return end
if game.tick >= swarm.timeout then
group.destroy()
return
end
return true
end
function Public.validate_swarms()
local ffatable = Table.get_table()
for k, swarm in pairs(ffatable.swarms) do
if not is_swarm_valid(swarm) then
table_remove(ffatable.swarms, k)
end
end
end
function Public.unit_groups_start_moving()
local ffatable = Table.get_table()
for _, swarm in pairs(ffatable.swarms) do
if swarm.group then
if swarm.group.valid then
swarm.group.start_moving()
end
end
end
end
function Public.swarm(town_center, radius)
if town_center == nil then return end
local ffatable = Table.get_table()
local r = radius or 32
local tc = town_center or roll_market()
if not tc or r > 512 then return end
-- skip if town evolution < 0.25
if town_center.get_biter_evolution < 0.25 then return end
-- skip if we have to many swarms already
local count = table_size(ffatable.swarms)
local towns = table_size(ffatable.town_centers)
if count > 3 * towns then return end
local market = tc.market
local surface = market.surface
-- find a spawner
local spawner = get_random_close_spawner(surface, market, r)
if not spawner then
r = r + 16
local future = game.tick + 1
-- schedule to run this method again with a higher radius on next tick
if not tick_schedule[future] then tick_schedule[future] = {} end
tick_schedule[future][#tick_schedule[future] + 1] = {
callback = 'swarm',
params = { tc, r }
}
return
end
-- get our evolution
local evolution = 0
if spawner.name == "spitter-spawner" then
evolution = Evolution.get_biter_evolution(spawner)
else
evolution = Evolution.get_spitter_evolution(spawner)
end
-- get our target amount of enemies
local count2 = (evolution * 124) + 4
local units = spawner.surface.find_enemy_units(spawner.position, 16, market.force)
if #units < count2 then
units = spawner.surface.find_enemy_units(spawner.position, 32, market.force)
end
if #units < count2 then
units = spawner.surface.find_enemy_units(spawner.position, 64, market.force)
end
if #units < count2 then
units = spawner.surface.find_enemy_units(spawner.position, 128, market.force)
end
if not units[1] then return end
local unit_group_position = surface.find_non_colliding_position("biter-spawner", units[1].position, 256, 1)
if not unit_group_position then return end
local unit_group = surface.create_unit_group({ position = unit_group_position, force = units[1].force })
for key, unit in pairs(units) do
if key > count2 then break end
unit_group.add_member(unit)
end
unit_group.set_command({
type = defines.command.compound,
structure_type = defines.compound_command.return_last,
commands = get_commmands(market, unit_group)
})
table_insert(ffatable.swarms, { group = unit_group, timeout = game.tick + 36000 })
end
local function on_tick()
if not tick_schedule[game.tick] then return end
for _, token in pairs(tick_schedule[game.tick]) do
local callback = token.callback
local params = token.params
if callback == 'swarm' then Public.swarm(params[1], params[2]) end
end
tick_schedule[game.tick] = nil
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.swarms = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_tick, on_tick)
return Public

View File

@ -0,0 +1,269 @@
local Public = {}
local Table = require 'modules.scrap_towny_ffa.table'
local town_radius = 27
local connection_radius = 7
local neutral_whitelist = {
["wooden-chest"] = true,
["iron-chest"] = true,
["steel-chest"] = true,
["raw-fish"] = true,
}
local entity_type_whitelist = {
["accumulator"] = true,
["ammo-turret"] = true,
["arithmetic-combinator"] = true,
["artillery-turret"] = true,
["assembling-machine"] = true,
["boiler"] = true,
["constant-combinator"] = true,
["container"] = true,
["curved-rail"] = true,
["decider-combinator"] = true,
["electric-pole"] = true,
["electric-turret"] = true,
["fluid-turret"] = true,
["furnace"] = true,
["gate"] = true,
["generator"] = true,
["heat-interface"] = true,
["heat-pipe"] = true,
["infinity-container"] = true,
["infinity-pipe"] = true,
["inserter"] = true,
["lab"] = true,
["lamp"] = true,
["land-mine"] = true,
["loader"] = true,
["logistic-container"] = true,
["market"] = true,
["mining-drill"] = true,
["offshore-pump"] = true,
["pipe"] = true,
["pipe-to-ground"] = true,
["programmable-speaker"] = true,
["pump"] = true,
["radar"] = true,
["rail-chain-signal"] = true,
["rail-signal"] = true,
["reactor"] = true,
["roboport"] = true,
["rocket-silo"] = true,
["solar-panel"] = true,
["splitter"] = true,
["storage-tank"] = true,
["straight-rail"] = true,
["train-stop"] = true,
["transport-belt"] = true,
["underground-belt"] = true,
["wall"] = true,
}
local function isolated(surface, force, position)
local position_x = position.x
local position_y = position.y
local area = { { position_x - connection_radius, position_y - connection_radius }, { position_x + connection_radius, position_y + connection_radius } }
local count = 0
for _, e in pairs(surface.find_entities_filtered({ area = area, force = force.name })) do
if entity_type_whitelist[e.type] then
count = count + 1
if count > 1 then return false end -- are there more than one team entities in the area?
end
end
return true
end
local function refund_item(event, item_name)
if item_name == "blueprint" then return end
if event.player_index then
game.players[event.player_index].insert({ name = item_name, count = 1 })
return
end
if event.robot then
local inventory = event.robot.get_inventory(defines.inventory.robot_cargo)
inventory.insert({ name = item_name, count = 1 })
return
end
end
local function error_floaty(surface, position, msg)
surface.create_entity({
name = "flying-text",
position = position,
text = msg,
color = { r = 0.77, g = 0.0, b = 0.0 }
})
end
local function in_range(pos1, pos2, radius)
if pos1 == nil then return false end
if pos2 == nil then return false end
if radius < 1 then return true end
local dx = pos1.x - pos2.x
local dy = pos1.y - pos2.y
if dx ^ 2 + dy ^ 2 < radius ^ 2 then
return true
end
return false
end
-- is the position near a town?
function Public.near_town(position, surface, radius)
local ffatable = Table.get_table()
for _, town_center in pairs(ffatable.town_centers) do
if town_center ~= nil then
local market = town_center.market
if in_range(position, market.position, radius) and market.surface == surface then
return true
end
end
end
return false
end
local function in_town(force, position)
local ffatable = Table.get_table()
local town_center = ffatable.town_centers[force.name]
if town_center ~= nil then
local center = town_center.market.position
if position.x >= center.x - town_radius and position.x <= center.x + town_radius then
if position.y >= center.y - town_radius and position.y <= center.y + town_radius then
return true
end
end
end
return false
end
local function prevent_isolation_entity(event, player)
local p = player or nil
local entity = event.created_entity
local position = entity.position
if not entity.valid then return end
local entity_name = entity.name
local item = event.item
if item == nil then return end
local item_name = item.name
local force = entity.force
if force == game.forces.player then return end
if force == game.forces["rogue"] then return end
local surface = entity.surface
local error = false
if not in_town(force, position) and isolated(surface, force, position) then
error = true
entity.destroy()
if entity_name ~= "entity-ghost" and entity_name ~= "tile-ghost" then
refund_item(event, item_name)
end
--return true
end
if error == true then
if p ~= nil then
p.play_sound({ path = "utility/cannot_build", position = p.position, volume_modifier = 0.75 })
end
error_floaty(surface, position, "Building is not connected to town!")
end
end
local function prevent_isolation_tile(event, player)
local p = player or nil
local tile = event.tile
if not tile.valid then return end
local tile_name = tile.name
local surface = game.surfaces[event.surface_index]
local tiles = event.tiles
local force
if event.player_index then
force = game.players[event.player_index].force
else
force = event.robot.force
end
local error = false
local position
for _, t in pairs(tiles) do
local old_tile = t.old_tile
position = t.position
if not in_town(force, position) and isolated(surface, force, position) then
error = true
surface.set_tiles({ { name = old_tile.name, position = position } }, true)
if tile_name ~= "tile-ghost" then
if tile_name == "stone-path" then tile_name = "stone-brick" end
refund_item(event, tile_name)
end
end
end
if error == true then
if p ~= nil then
p.play_sound({ path = "utility/cannot_build", position = p.position, volume_modifier = 0.75 })
end
error_floaty(surface, position, "Tile is not connected to town!")
end
end
local function restrictions(event, player)
local p = player or nil
local entity = event.created_entity
if not entity.valid then return end
local entity_name = entity.name
local surface = entity.surface
local position = entity.position
local error = false
if entity.force == game.forces["player"] or entity.force == game.forces["rogue"] then
if Public.near_town(position, surface, 32) then
error = true
entity.destroy()
if entity_name ~= "entity-ghost" then
refund_item(event, event.stack.name)
end
else
entity.force = game.forces["neutral"]
end
return
end
if error == true then
if p ~= nil then
p.play_sound({ path = "utility/cannot_build", position = p.position, volume_modifier = 0.75 })
end
error_floaty(surface, position, "Can't build near town!")
end
if not neutral_whitelist[entity.type] then return end
entity.force = game.forces["neutral"]
end
-- called when a player places an item, or a ghost
local function on_built_entity(event)
local player = game.players[event.player_index]
if prevent_isolation_entity(event, player) then return end
restrictions(event, player)
end
local function on_robot_built_entity(event)
if prevent_isolation_entity(event) then return end
restrictions(event)
end
-- called when a player places landfill
local function on_player_built_tile(event)
local player = game.players[event.player_index]
prevent_isolation_tile(event, player)
end
local function on_robot_built_tile(event)
prevent_isolation_tile(event)
end
local Event = require 'utils.event'
Event.add(defines.events.on_built_entity, on_built_entity)
Event.add(defines.events.on_player_built_tile, on_player_built_tile)
Event.add(defines.events.on_robot_built_entity, on_robot_built_entity)
Event.add(defines.events.on_robot_built_tile, on_robot_built_tile)
return Public

View File

@ -0,0 +1,50 @@
local string_sub = string.sub
local string_len = string.len
-- ammo damage modifiers are static values that increase with research
-- modifier is multiplied by base damage and then added to damage, so a negative value will reduce base damage and a positive value will increase damage
local balance_functions = {
["land-mine"] = function(force_name)
-- landmines normally have a modifier of 0, so have them start at 25% of normal
if force_name ~= nil then
game.forces[force_name].set_ammo_damage_modifier("landmine", -0.75)
end
end,
["military-2"] = function(force_name)
-- grenades normally have a modifier of 0, so have them start at 50% of normal
if force_name ~= nil then
game.forces[force_name].set_ammo_damage_modifier("grenade", -0.5)
end
end,
["military-4"] = function(force_name)
-- cluster-grenades normally have a modifier of 0, so have them start at 50% of normal
if force_name ~= nil then
game.forces[force_name].set_ammo_damage_modifier("grenade", -0.5)
end
end,
["stronger-explosives"] = function(force_name)
-- landmines should never increase in damage with stronger explosives
if force_name ~= nil then
game.forces[force_name].set_ammo_damage_modifier("landmine", -0.75)
-- allow grenades to increase by 10%
game.forces[force_name].set_ammo_damage_modifier("grenade", game.forces[force_name].get_ammo_damage_modifier("grenade") + 0.1)
end
end,
}
local function on_research_finished(event)
local research_name = event.research.name
local force_name = event.research.force.name
local key
for b = 1, string_len(research_name), 1 do
key = string_sub(research_name, 0, b)
if balance_functions[key] then
balance_functions[key](force_name)
return
end
end
end
local Event = require 'utils.event'
Event.add(defines.events.on_research_finished, on_research_finished)

View File

@ -0,0 +1,63 @@
local Public = {}
function Public.clear_enemies(position, surface, radius)
--log("clear_enemies {" .. position.x .. "," .. position.y .. "}")
-- clear enemies
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", type = { "unit-spawner", "unit", "turret" }, position = position, radius = radius })) do
e.destroy()
end
-- clear gun turrets
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", name = { "gun-turret" }, position = position, radius = radius })) do
e.destroy()
end
end
function Public.clear_units(position, surface, radius)
--log("clear_units {" .. position.x .. "," .. position.y .. "}")
-- clear units
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", type = { "unit" }, position = position, radius = radius })) do
e.destroy()
end
end
function Public.clear_biters(position, surface, radius)
--log("clear_units {" .. position.x .. "," .. position.y .. "}")
-- clear biters
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", name = { "small-biter", "medium-biter", "big-biter", "behemoth-biter" }, position = position, radius = radius })) do
e.destroy()
end
end
function Public.clear_spitters(position, surface, radius)
--log("clear_units {" .. position.x .. "," .. position.y .. "}")
-- clear spitters
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", name = { "small-spitter", "medium-spitter", "big-spitter", "behemoth-spitter" }, position = position, radius = radius })) do
e.destroy()
end
end
function Public.clear_nests(position, surface, radius)
--log("clear_unit_spawners {" .. position.x .. "," .. position.y .. "}")
-- clear enemies
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", type = { "unit-spawner" }, position = position, radius = radius })) do
e.destroy()
end
end
function Public.clear_worms(position, surface, radius)
--log("clear_turrets {" .. position.x .. "," .. position.y .. "}")
-- clear enemies
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", type = { "turret" }, position = position, radius = radius })) do
e.destroy()
end
end
function Public.clear_gun_turrets(position, surface, radius)
--log("clear_gun_turrets {" .. position.x .. "," .. position.y .. "}")
-- clear gun turrets
for _, e in pairs(surface.find_entities_filtered({ force = "enemy", name = { "gun-turret" }, position = position, radius = radius })) do
e.destroy()
end
end
return Public

View File

@ -0,0 +1,585 @@
local Public = {}
local math_floor = math.floor
local Table = require 'modules.scrap_towny_ffa.table'
local biters = {
[1] = "small-biter",
[2] = "medium-biter",
[3] = "big-biter",
[4] = "behemoth-biter"
}
local spitters = {
[1] = "small-spitter",
[2] = "medium-spitter",
[3] = "big-spitter",
[4] = "behemoth-spitter"
}
local worms = {
[1] = "small-worm-turret",
[2] = "medium-worm-turret",
[3] = "big-worm-turret",
[4] = "behemoth-worm-turret"
}
-- evolution max distance in tiles
local max_evolution_distance = 1024
local max_pollution_behemoth = 256
local max_pollution_big = 64
local max_pollution_medium = 16
local max_factor = 0.8
-- technology weights (biter, spitter, worm)
local technology_weights = {
['advanced-electronics'] = { biter = 1, spitter = 1, worm = 1 },
['advanced-electronics-2'] = { biter = 1, spitter = 1, worm = 1 },
['advanced-material-processing'] = { biter = 1, spitter = 1, worm = 1 },
['advanced-material-processing-2'] = { biter = 1, spitter = 1, worm = 1 },
['advanced-oil-processing'] = { biter = 1, spitter = 1, worm = 1 },
['artillery']={biter=1, spitter=1, worm=1},
['artillery-shell-range-1']={biter=1, spitter=1, worm=1},
['artillery-shell-speed-1']={biter=1, spitter=1, worm=1},
['atomic-bomb']={biter=1, spitter=1, worm=1},
['automated-rail-transportation'] = { biter = 1, spitter = 1, worm = 1 },
['automation'] = { biter = 1, spitter = 1, worm = 1 },
['automation-2'] = { biter = 1, spitter = 1, worm = 1 },
['automation-3'] = { biter = 1, spitter = 1, worm = 1 },
['automobilism'] = { biter = 1, spitter = 1, worm = 1 },
['battery'] = { biter = 1, spitter = 1, worm = 1 },
['battery-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['battery-mk2-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['belt-immunity-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-1'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-2'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-3'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-4'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-5'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-6'] = { biter = 1, spitter = 1, worm = 1 },
['braking-force-7'] = { biter = 1, spitter = 1, worm = 1 },
['chemical-science-pack'] = { biter = 125, spitter = 125, worm = 125 },
['circuit-network'] = { biter = 1, spitter = 1, worm = 1 },
['cliff-explosives'] = { biter = 1, spitter = 1, worm = 1 },
['coal-liquefaction'] = { biter = 1, spitter = 1, worm = 1 },
['concrete'] = { biter = 1, spitter = 1, worm = 1 },
['construction-robotics'] = { biter = 1, spitter = 1, worm = 1 },
['defender'] = { biter = 1, spitter = 1, worm = 1 },
['destroyer'] = { biter = 1, spitter = 1, worm = 1 },
['discharge-defense-equipment'] = { biter = 5, spitter = 5, worm = 5 },
['distractor'] = { biter = 1, spitter = 1, worm = 1 },
['effect-transmission'] = { biter = 1, spitter = 1, worm = 1 },
['effectivity-module'] = { biter = 1, spitter = 1, worm = 1 },
['effectivity-module-2'] = { biter = 1, spitter = 1, worm = 1 },
['effectivity-module-3'] = { biter = 1, spitter = 1, worm = 1 },
['electric-energy-accumulators'] = { biter = 1, spitter = 1, worm = 1 },
['electric-energy-distribution-1'] = { biter = 1, spitter = 1, worm = 1 },
['electric-energy-distribution-2'] = { biter = 1, spitter = 1, worm = 1 },
['electric-engine'] = { biter = 1, spitter = 1, worm = 1 },
['electronics'] = { biter = 1, spitter = 1, worm = 1 },
['energy-shield-equipment'] = { biter = 5, spitter = 5, worm = 5 },
['energy-shield-mk2-equipment'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-1'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-2'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-3'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-4'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-5'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-6'] = { biter = 5, spitter = 5, worm = 5 },
['energy-weapons-damage-7'] = { biter = 5, spitter = 5, worm = 5 },
['engine'] = { biter = 1, spitter = 1, worm = 1 },
['exoskeleton-equipment'] = { biter = 5, spitter = 5, worm = 5 },
['explosive-rocketry']={biter=1, spitter=1, worm=1},
['explosives'] = { biter = 5, spitter = 5, worm = 5 },
['fast-inserter'] = { biter = 1, spitter = 1, worm = 1 },
['flamethrower'] = { biter = 5, spitter = 5, worm = 5 },
['flammables'] = { biter = 1, spitter = 1, worm = 1 },
['fluid-handling'] = { biter = 1, spitter = 1, worm = 1 },
['fluid-wagon'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-1'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-2'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-3'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-4'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-5'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-6'] = { biter = 1, spitter = 1, worm = 1 },
['follower-robot-count-7'] = { biter = 1, spitter = 1, worm = 1 },
['fusion-reactor-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['gate'] = { biter = 1, spitter = 1, worm = 1 },
['gun-turret'] = { biter = 1, spitter = 1, worm = 1 },
['heavy-armor'] = { biter = 5, spitter = 5, worm = 5 },
['improved-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['inserter-capacity-bonus-1'] = { biter = 1, spitter = 1, worm = 1 },
['inserter-capacity-bonus-3'] = { biter = 1, spitter = 1, worm = 1 },
['inserter-capacity-bonus-4'] = { biter = 1, spitter = 1, worm = 1 },
['inserter-capacity-bonus-5'] = { biter = 1, spitter = 1, worm = 1 },
['inserter-capacity-bonus-6'] = { biter = 1, spitter = 1, worm = 1 },
['inserter-capacity-bonus-7'] = { biter = 1, spitter = 1, worm = 1 },
['kovarex-enrichment-process'] = { biter = 1, spitter = 1, worm = 1 },
['land-mine'] = { biter = 5, spitter = 5, worm = 5 },
['landfill'] = { biter = 1, spitter = 1, worm = 1 },
['laser'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-1'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-2'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-3'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-4'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-5'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-6'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret-speed-7'] = { biter = 5, spitter = 5, worm = 5 },
['laser-turret'] = { biter = 5, spitter = 5, worm = 5 },
['logistic-robotics'] = { biter = 1, spitter = 1, worm = 1 },
['logistic-science-pack'] = { biter = 25, spitter = 25, worm = 25 },
['logistic-system'] = { biter = 1, spitter = 1, worm = 1 },
['logistics'] = { biter = 1, spitter = 1, worm = 1 },
['logistics-2'] = { biter = 1, spitter = 1, worm = 1 },
['logistics-3'] = { biter = 1, spitter = 1, worm = 1 },
['low-density-structure'] = { biter = 1, spitter = 1, worm = 1 },
['lubricant'] = { biter = 1, spitter = 1, worm = 1 },
['military'] = { biter = 5, spitter = 5, worm = 5 },
['military-2'] = { biter = 5, spitter = 5, worm = 5 },
['military-3'] = { biter = 5, spitter = 5, worm = 51 },
['military-4'] = { biter = 5, spitter = 5, worm = 5 },
['military-science-pack'] = { biter = 50, spitter = 50, worm = 50 },
['mining-productivity-1'] = { biter = 1, spitter = 1, worm = 1 },
['mining-productivity-2'] = { biter = 1, spitter = 1, worm = 1 },
['mining-productivity-3'] = { biter = 1, spitter = 1, worm = 1 },
['mining-productivity-4'] = { biter = 1, spitter = 1, worm = 1 },
['modular-armor'] = { biter = 1, spitter = 1, worm = 1 },
['modules'] = { biter = 1, spitter = 1, worm = 1 },
['night-vision-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['nuclear-fuel-reprocessing'] = { biter = 1, spitter = 1, worm = 1 },
['nuclear-power'] = { biter = 1, spitter = 1, worm = 1 },
['oil-processing'] = { biter = 1, spitter = 1, worm = 1 },
['optics'] = { biter = 1, spitter = 1, worm = 1 },
['personal-laser-defense-equipment'] = { biter = 5, spitter = 5, worm = 5 },
['personal-roboport-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['personal-roboport-mk2-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['physical-projectile-damage-1'] = { biter = 5, spitter = 5, worm = 5 },
['physical-projectile-damage-2'] = { biter = 5, spitter = 5, worm = 5 },
['physical-projectile-damage-3'] = { biter = 5, spitter = 5, worm = 5 },
['physical-projectile-damage-4'] = { biter = 5, spitter = 5, worm = 5 },
['physical-projectile-damage-5'] = { biter = 5, spitter = 5, worm = 5 },
['physical-projectile-damage-6'] = { biter = 5, spitter = 5, worm = 5 },
['physical-projectile-damage-7'] = { biter = 5, spitter = 5, worm = 5 },
['plastics'] = { biter = 1, spitter = 1, worm = 1 },
['power-armor'] = { biter = 5, spitter = 5, worm = 5 },
['power-armor-mk2'] = { biter = 5, spitter = 5, worm = 5 },
['production-science-pack'] = { biter = 250, spitter = 250, worm = 250 },
['productivity-module'] = { biter = 1, spitter = 1, worm = 1 },
['productivity-module-2'] = { biter = 1, spitter = 1, worm = 1 },
['productivity-module-3'] = { biter = 1, spitter = 1, worm = 1 },
['rail-signals'] = { biter = 1, spitter = 1, worm = 1 },
['railway'] = { biter = 1, spitter = 1, worm = 1 },
['refined-flammables-1'] = { biter = 5, spitter = 5, worm = 5 },
['refined-flammables-2'] = { biter = 5, spitter = 5, worm = 51 },
['refined-flammables-3'] = { biter = 5, spitter = 5, worm = 5 },
['refined-flammables-4'] = { biter = 5, spitter = 5, worm = 5 },
['refined-flammables-5'] = { biter = 5, spitter = 5, worm = 5 },
['refined-flammables-6'] = { biter = 5, spitter = 5, worm = 5 },
['refined-flammables-7'] = { biter = 5, spitter = 5, worm = 51 },
['research-speed-1'] = { biter = 1, spitter = 1, worm = 1 },
['research-speed-2'] = { biter = 1, spitter = 1, worm = 1 },
['research-speed-3'] = { biter = 1, spitter = 1, worm = 1 },
['research-speed-4'] = { biter = 1, spitter = 1, worm = 1 },
['research-speed-5'] = { biter = 1, spitter = 1, worm = 1 },
['research-speed-6'] = { biter = 1, spitter = 1, worm = 1 },
['robotics'] = { biter = 1, spitter = 1, worm = 1 },
['rocket-control-unit'] = { biter = 1, spitter = 1, worm = 1 },
['rocket-fuel'] = { biter = 1, spitter = 1, worm = 1 },
['rocket-silo'] = { biter = 1, spitter = 1, worm = 1 },
['rocketry']={biter=1, spitter=1, worm=1},
['solar-energy'] = { biter = 1, spitter = 1, worm = 1 },
['solar-panel-equipment'] = { biter = 1, spitter = 1, worm = 1 },
['space-science-pack'] = { biter = 1000, spitter = 1000, worm = 1000 },
['speed-module'] = { biter = 1, spitter = 1, worm = 1 },
['speed-module-2'] = { biter = 1, spitter = 1, worm = 1 },
['speed-module-3'] = { biter = 1, spitter = 1, worm = 1 },
['spidertron'] = { biter = 1, spitter = 1, worm = 1 },
['stack-inserter'] = { biter = 1, spitter = 1, worm = 1 },
['steel-axe'] = { biter = 1, spitter = 1, worm = 1 },
['steel-processing'] = { biter = 1, spitter = 1, worm = 1 },
['stone-wall'] = { biter = 1, spitter = 1, worm = 1 },
['stronger-explosives-1'] = { biter = 5, spitter = 5, worm = 5 },
['stronger-explosives-2'] = { biter = 5, spitter = 5, worm = 5 },
['stronger-explosives-3'] = { biter = 5, spitter = 5, worm = 5 },
['stronger-explosives-4'] = { biter = 5, spitter = 5, worm = 5 },
['stronger-explosives-5'] = { biter = 5, spitter = 5, worm = 5 },
['stronger-explosives-6'] = { biter = 5, spitter = 5, worm = 5 },
['stronger-explosives-7'] = { biter = 5, spitter = 5, worm = 51 },
['sulfur-processing'] = { biter = 1, spitter = 1, worm = 1 },
['tank'] = { biter = 1, spitter = 1, worm = 1 },
['toolbelt'] = { biter = 1, spitter = 1, worm = 1 },
['uranium-ammo'] = { biter = 1, spitter = 1, worm = 1 },
['uranium-processing'] = { biter = 1, spitter = 1, worm = 1 },
['utility-science-pack'] = { biter = 500, spitter = 500, worm = 500 },
['weapon-shooting-speed-1'] = { biter = 5, spitter = 5, worm = 5 },
['weapon-shooting-speed-2'] = { biter = 5, spitter = 5, worm = 5 },
['weapon-shooting-speed-3'] = { biter = 5, spitter = 5, worm = 5 },
['weapon-shooting-speed-4'] = { biter = 5, spitter = 5, worm = 5 },
['weapon-shooting-speed-5'] = { biter = 5, spitter = 5, worm = 5 },
['weapon-shooting-speed-6'] = { biter = 5, spitter = 5, worm = 5 },
['worker-robots-speed-1'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-speed-2'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-speed-3'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-speed-4'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-speed-5'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-speed-6'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-storage-1'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-storage-2'] = { biter = 1, spitter = 1, worm = 1 },
['worker-robots-storage-3'] = { biter = 1, spitter = 1, worm = 1 },
}
local max_biter_weight = 0
local max_spitter_weight = 0
local max_worm_weight = 0
for _, weight in pairs(technology_weights) do
max_biter_weight = max_biter_weight + weight.biter
max_spitter_weight = max_spitter_weight + weight.spitter
max_worm_weight = max_worm_weight + weight.worm
end
max_biter_weight = max_biter_weight * max_factor
max_spitter_weight = max_spitter_weight * max_factor
max_worm_weight = max_worm_weight * max_factor
local function get_unit_size(evolution)
-- returns a value 0-3 that represents the unit size
-- basically evo values of: 0%, 10%, 30%, 60%, 80%, 100%
-- small unit chances are 100%, 100%, 50%, 25%, 12.5%, 0%
-- medium unit chances are 0%, 0%, 50%, 25%, 12.5%, 0%
-- big unit chances are 0%, 0%, 0%, 50%, 25%, 0%
-- behemoth unit chances are 0%, 0%, 0%, 0%, 50%, 100%
-- and curve accordingly in between evo values
-- magic stuff happens here
if (evolution < 0.10) then return 1 end
if (evolution >= 0.10 and evolution < 0.40) then
local r = (evolution - 0.10) * 5
if math.random() < 0.5 then return 1 end
if math.random() < r then return 1 end
return 2
end
if (evolution >= 0.30 and evolution < 0.60) then
local r = (evolution - 0.30) * 3.3333
if math.random() < 0.5 then
if math.random() < 0.5 then
return 1
else
if math.random() < r then return 1 else return 2 end
end
else
if math.random() < r then return 2 else return 3 end
end
end
if (evolution >= 0.60 and evolution < 0.80) then
local r = (evolution - 0.60) * 5
if math.random() < 0.5 then
if math.random() < 0.5 then
if math.random() < r then return 1 else return 2 end
else
if math.random() < r then return 2 else return 3 end
end
else
if math.random() < r then return 3 else return 4 end
end
end
if (evolution >= 0.80 and evolution < 1.0) then
local r = (evolution - 0.80) * 5
if math.random() < 0.5 then
if math.random() < r then
if math.random() < r then
return 1
else return 2 end
else return 3 end
else return 4 end
end
if (evolution >= 1.0) then return 4 end
end
local function distance_squared(pos1, pos2)
-- calculate the distance squared
local dx = pos1.x - pos2.x
local dy = pos1.y - pos2.y
local d2 = dx * dx + dy * dy
return d2
end
local function get_relative_biter_evolution(position)
local ffatable = Table.get_table()
local relative_evolution = 0.0
local max_d2 = max_evolution_distance * max_evolution_distance
-- for all of the teams
local teams = ffatable.town_centers
for _, town_center in pairs(teams) do
local market_position = town_center.market.position
-- calculate the distance squared
local d2 = distance_squared(position, market_position)
if d2 < max_d2 then
-- get the distance factor (0.0-1.0)
local distance_factor = 1.0 - d2 / max_d2;
-- get the evolution factor (0.0-1.0)
if not town_center.evolution then town_center.evolution = {} end
if town_center.evolution.biters == nil then town_center.evolution.biters = 0.0 end
local evolution_factor = town_center.evolution.biters
local evo = distance_factor * evolution_factor
relative_evolution = math.max(relative_evolution, evo)
end
end
return relative_evolution
end
local function get_relative_spitter_evolution(position)
local ffatable = Table.get_table()
local relative_evolution = 0.0
local max_d2 = max_evolution_distance * max_evolution_distance
-- for all of the teams
local teams = ffatable.town_centers
for _, town_center in pairs(teams) do
local market_position = town_center.market.position
-- calculate the distance squared
local d2 = distance_squared(position, market_position)
if d2 < max_d2 then
-- get the distance factor (0.0-1.0)
local distance_factor = 1.0 - d2 / max_d2;
-- get the evolution factor (0.0-1.0)
if not town_center.evolution then town_center.evolution = {} end
if town_center.evolution.spitters == nil then town_center.evolution.spitters = 0.0 end
local evolution_factor = town_center.evolution.spitters
local evo = distance_factor * evolution_factor
relative_evolution = math.max(relative_evolution, evo)
end
end
return relative_evolution
end
local function get_relative_worm_evolution(position)
local ffatable = Table.get_table()
local relative_evolution = 0.0
local max_d2 = max_evolution_distance * max_evolution_distance
-- for all of the teams
local teams = ffatable.town_centers
for _, town_center in pairs(teams) do
local market_position = town_center.market.position
-- calculate the distance squared
local d2 = distance_squared(position, market_position)
if d2 < max_d2 then
-- get the distance factor (0.0-1.0)
local distance_factor = 1.0 - d2 / max_d2;
-- get the evolution factor (0.0-1.0)
if not town_center.evolution then town_center.evolution = {} end
if town_center.evolution.worms == nil then town_center.evolution.worms = 0.0 end
local evolution_factor = town_center.evolution.worms
local evo = distance_factor * evolution_factor
relative_evolution = math.max(relative_evolution, evo)
end
end
return relative_evolution
end
function Public.get_evolution(position)
return get_relative_biter_evolution(position)
end
function Public.get_biter_evolution(entity)
return get_relative_biter_evolution(entity.position)
end
function Public.get_spitter_evolution(entity)
return get_relative_spitter_evolution(entity.position)
end
function Public.get_worm_evolution(entity)
return get_relative_worm_evolution(entity.position)
end
local function get_nearby_location(position, surface, radius, entity_name)
return surface.find_non_colliding_position(entity_name, position, radius, 0.5, false)
end
local function set_biter_type(entity)
-- checks nearby evolution levels for bases and returns an appropriately leveled type
local position = entity.position
local evo = get_relative_biter_evolution(position)
local unit_size = get_unit_size(evo)
local entity_name = biters[unit_size]
if entity.name == entity_name then return end
local surface = entity.surface
local pollution = surface.get_pollution(position)
local behemoth = math_floor(pollution / max_pollution_behemoth)
local big = math_floor((pollution - (behemoth * max_pollution_behemoth)) / max_pollution_big)
local medium = math_floor((pollution - (behemoth * max_pollution_behemoth) - (big * max_pollution_big)) / max_pollution_medium)
local small = pollution - (behemoth * max_pollution_behemoth) - (big * max_pollution_big) - (medium * max_pollution_medium) + 1
if entity.valid then
for _ = 1, behemoth do
local e = surface.create_entity({ name = biters[4], position = get_nearby_location(position, surface, 5, biters[4]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
for _ = 1, big do
local e = surface.create_entity({ name = biters[3], position = get_nearby_location(position, surface, 5, biters[3]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
for _ = 1, medium do
local e = surface.create_entity({ name = biters[2], position = get_nearby_location(position, surface, 5, biters[2]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
for _ = 1, small do
local e = surface.create_entity({ name = biters[1], position = get_nearby_location(position, surface, 5, biters[1]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
local e = surface.create_entity({ name = entity_name, position = get_nearby_location(position, surface, 5, entity_name) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
entity.destroy()
--log("spawned " .. entity_name)
end
end
local function set_spitter_type(entity)
-- checks nearby evolution levels for bases and returns an appropriately leveled type
local position = entity.position
local evo = get_relative_spitter_evolution(position)
local unit_size = get_unit_size(evo)
local entity_name = spitters[unit_size]
if entity.name == entity_name then return end
local surface = entity.surface
local pollution = surface.get_pollution(position)
local behemoth = math_floor(pollution / max_pollution_behemoth)
local big = math_floor((pollution - (behemoth * max_pollution_behemoth)) / max_pollution_big)
local medium = math_floor((pollution - (behemoth * max_pollution_behemoth) - (big * max_pollution_big)) / max_pollution_medium)
local small = pollution - (behemoth * max_pollution_behemoth) - (big * max_pollution_big) - (medium * max_pollution_medium) + 1
if entity.valid then
for _ = 1, behemoth do
local e = surface.create_entity({ name = spitters[4], position = get_nearby_location(position, surface, 5, spitters[4]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
for _ = 1, big do
local e = surface.create_entity({ name = spitters[3], position = get_nearby_location(position, surface, 5, spitters[3]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
for _ = 1, medium do
local e = surface.create_entity({ name = spitters[2], position = get_nearby_location(position, surface, 5, spitters[2]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
for _ = 1, small do
local e = surface.create_entity({ name = spitters[1], position = get_nearby_location(position, surface, 5, spitters[1]) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
end
local e = surface.create_entity({ name = entity_name, position = get_nearby_location(position, surface, 5, entity_name) })
e.copy_settings(entity);
e.ai_settings.allow_try_return_to_spawner = true
entity.destroy()
--log("spawned " .. entity_name)
end
end
local function set_worm_type(entity)
-- checks nearby evolution levels for bases and returns an appropriately leveled type
local position = entity.position
local evo = get_relative_worm_evolution(position)
local unit_size = get_unit_size(evo)
local entity_name = worms[unit_size]
if entity.name == entity_name then return end
local surface = entity.surface
if entity.valid then
entity.destroy()
surface.create_entity({ name = entity_name, position = position })
--log("spawned " .. entity_name)
end
end
local function is_biter(entity)
if entity == nil or not entity.valid then return false end
if entity.name == 'small-biter' or entity.name == 'medium-biter' or entity.name == 'big-biter' or entity.name == 'behemoth-biter' then
return true
end
return false
end
local function is_spitter(entity)
if entity == nil or not entity.valid then return false end
if entity.name == 'small-spitter' or entity.name == 'medium-spitter' or entity.name == 'big-spitter' or entity.name == 'behemoth-spitter' then
return true
end
return false
end
local function is_worm(entity)
if entity == nil or not entity.valid then return false end
if entity.name == 'small-worm-turret' or entity.name == 'medium-worm-turret' or entity.name == 'big-worm-turret' or entity.name == 'behemoth-worm-turret' then
return true
end
return false
end
local function update_evolution(force_name, technology)
if technology == nil then return end
local ffatable = Table.get_table()
-- update evolution based on research completed (weighted)
local town_center = ffatable.town_centers[force_name]
-- town_center is a reference to a global table
if not town_center then return end
-- initialize if not already
local evo = town_center.evolution
-- get the weights for this technology
local weight = technology_weights[technology]
if weight == nil then
log("no technology_weights for " .. technology)
return
end
local biter_weight = weight.biter
local spitter_weight = weight.spitter
local worm_weight = weight.worm
-- update the evolution values (0.0 to 1.0)
local b = (biter_weight / max_biter_weight)
local s = (spitter_weight / max_spitter_weight)
local w = (worm_weight / max_worm_weight)
b = b + evo.biters
s = s + evo.spitters
w = w + evo.worms
evo.biters = b
evo.spitters = s
evo.worms = w
end
local function on_research_finished(event)
local research = event.research
local force_name = research.force.name
local technology = research.name
update_evolution(force_name, technology)
end
local function on_entity_spawned(event)
local entity = event.entity
-- check the unit type and handle appropriately
if is_biter(entity) then
set_biter_type(entity)
end
if is_spitter(entity) then
set_spitter_type(entity)
end
if is_worm(entity) then
set_worm_type(entity)
end
end
local function on_biter_base_built(event)
local entity = event.entity
if is_worm(entity) then
set_worm_type(entity)
end
end
local Event = require 'utils.event'
Event.add(defines.events.on_research_finished, on_research_finished)
Event.add(defines.events.on_entity_spawned, on_entity_spawned)
Event.add(defines.events.on_biter_base_built, on_biter_base_built)
return Public

View File

@ -0,0 +1,228 @@
--This will add a new game mechanic so that containers with explosives actually go boom when they get damaged.
--Made by MewMew
local math_min = math.min
local math_random = math.random
local Table = require 'modules.scrap_towny_ffa.table'
local Pollution = require "modules.scrap_towny_ffa.pollution"
--local damage_per_explosive = 100
local damage_per_explosive = 50
local empty_tile_damage_decay = 100
local out_of_map_tile_health = 1500
local max_volatility = 20
local explosive_items = {
["explosives"] = 1,
["land-mine"] = 1,
["grenade"] = 1,
["cluster-grenade"] = 3,
["artillery-shell"] = 5,
["cannon-shell"] = 3,
["explosive-cannon-shell"] = 5,
["explosive-uranium-cannon-shell"] = 5,
["uranium-cannon-shell"] = 5,
-- ["atomic-bomb"] = 100,
["explosive-rocket"] = 5,
["rocket"] = 2,
["flamethrower-ammo"] = 2,
["petroleum-gas-barrel"] = 2,
-- ["crude-oil-barrel"] = 2,
-- ["light-oil-barrel"] = 2,
-- ["heavy-oil-barrel"] = 2,
-- ["lubricant-barrel"] = 1,
-- ["shotgun-shell"] = 1,
-- ["piercing-shotgun-shell"] = 1,
-- ["firearm-magazine"] = 1,
-- ["piercing-rounds-magazine"] = 1,
-- ["uranium-rounds-magazine"] = 1,
["cliff-explosives"] = 2,
-- ["solid-fuel"] = 1
}
local circle_coordinates = {
[1] = { { x = 0, y = 0 } },
[2] = { { x = -1, y = -1 }, { x = 1, y = -1 }, { x = 0, y = -1 }, { x = -1, y = 0 }, { x = -1, y = 1 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 1, y = 0 } },
[3] = { { x = -2, y = -1 }, { x = -1, y = -2 }, { x = 1, y = -2 }, { x = 0, y = -2 }, { x = 2, y = -1 }, { x = -2, y = 1 }, { x = -2, y = 0 }, { x = 2, y = 1 }, { x = 2, y = 0 }, { x = -1, y = 2 }, { x = 1, y = 2 }, { x = 0, y = 2 } },
[4] = { { x = -1, y = -3 }, { x = 1, y = -3 }, { x = 0, y = -3 }, { x = -3, y = -1 }, { x = -2, y = -2 }, { x = 3, y = -1 }, { x = 2, y = -2 }, { x = -3, y = 0 }, { x = -3, y = 1 }, { x = 3, y = 1 }, { x = 3, y = 0 }, { x = -2, y = 2 }, { x = -1, y = 3 }, { x = 0, y = 3 }, { x = 1, y = 3 }, { x = 2, y = 2 } },
[5] = { { x = -3, y = -3 }, { x = -2, y = -3 }, { x = -1, y = -4 }, { x = -2, y = -4 }, { x = 1, y = -4 }, { x = 0, y = -4 }, { x = 2, y = -3 }, { x = 3, y = -3 }, { x = 2, y = -4 }, { x = -3, y = -2 }, { x = -4, y = -1 }, { x = -4, y = -2 }, { x = 3, y = -2 }, { x = 4, y = -1 }, { x = 4, y = -2 }, { x = -4, y = 1 }, { x = -4, y = 0 }, { x = 4, y = 1 }, { x = 4, y = 0 }, { x = -3, y = 3 }, { x = -3, y = 2 }, { x = -4, y = 2 }, { x = -2, y = 3 }, { x = 2, y = 3 }, { x = 3, y = 3 }, { x = 3, y = 2 }, { x = 4, y = 2 }, { x = -2, y = 4 }, { x = -1, y = 4 }, { x = 0, y = 4 }, { x = 1, y = 4 }, { x = 2, y = 4 } },
[6] = { { x = -1, y = -5 }, { x = -2, y = -5 }, { x = 1, y = -5 }, { x = 0, y = -5 }, { x = 2, y = -5 }, { x = -3, y = -4 }, { x = -4, y = -3 }, { x = 3, y = -4 }, { x = 4, y = -3 }, { x = -5, y = -1 }, { x = -5, y = -2 }, { x = 5, y = -1 }, { x = 5, y = -2 }, { x = -5, y = 1 }, { x = -5, y = 0 }, { x = 5, y = 1 }, { x = 5, y = 0 }, { x = -5, y = 2 }, { x = -4, y = 3 }, { x = 4, y = 3 }, { x = 5, y = 2 }, { x = -3, y = 4 }, { x = -2, y = 5 }, { x = -1, y = 5 }, { x = 0, y = 5 }, { x = 1, y = 5 }, { x = 3, y = 4 }, { x = 2, y = 5 } },
[7] = { { x = -4, y = -5 }, { x = -3, y = -5 }, { x = -2, y = -6 }, { x = -1, y = -6 }, { x = 0, y = -6 }, { x = 1, y = -6 }, { x = 3, y = -5 }, { x = 2, y = -6 }, { x = 4, y = -5 }, { x = -5, y = -4 }, { x = -5, y = -3 }, { x = -4, y = -4 }, { x = 4, y = -4 }, { x = 5, y = -4 }, { x = 5, y = -3 }, { x = -6, y = -1 }, { x = -6, y = -2 }, { x = 6, y = -1 }, { x = 6, y = -2 }, { x = -6, y = 1 }, { x = -6, y = 0 }, { x = 6, y = 1 }, { x = 6, y = 0 }, { x = -5, y = 3 }, { x = -6, y = 2 }, { x = 5, y = 3 }, { x = 6, y = 2 }, { x = -5, y = 4 }, { x = -4, y = 4 }, { x = -4, y = 5 }, { x = -3, y = 5 }, { x = 3, y = 5 }, { x = 4, y = 4 }, { x = 5, y = 4 }, { x = 4, y = 5 }, { x = -1, y = 6 }, { x = -2, y = 6 }, { x = 1, y = 6 }, { x = 0, y = 6 }, { x = 2, y = 6 } },
[8] = { { x = -1, y = -7 }, { x = -2, y = -7 }, { x = 1, y = -7 }, { x = 0, y = -7 }, { x = 2, y = -7 }, { x = -5, y = -5 }, { x = -4, y = -6 }, { x = -3, y = -6 }, { x = 3, y = -6 }, { x = 4, y = -6 }, { x = 5, y = -5 }, { x = -6, y = -3 }, { x = -6, y = -4 }, { x = 6, y = -4 }, { x = 6, y = -3 }, { x = -7, y = -1 }, { x = -7, y = -2 }, { x = 7, y = -1 }, { x = 7, y = -2 }, { x = -7, y = 1 }, { x = -7, y = 0 }, { x = 7, y = 1 }, { x = 7, y = 0 }, { x = -7, y = 2 }, { x = -6, y = 3 }, { x = 6, y = 3 }, { x = 7, y = 2 }, { x = -5, y = 5 }, { x = -6, y = 4 }, { x = 5, y = 5 }, { x = 6, y = 4 }, { x = -3, y = 6 }, { x = -4, y = 6 }, { x = -2, y = 7 }, { x = -1, y = 7 }, { x = 0, y = 7 }, { x = 1, y = 7 }, { x = 3, y = 6 }, { x = 2, y = 7 }, { x = 4, y = 6 } },
[9] = { { x = -4, y = -7 }, { x = -3, y = -7 }, { x = -2, y = -8 }, { x = -1, y = -8 }, { x = 0, y = -8 }, { x = 1, y = -8 }, { x = 3, y = -7 }, { x = 2, y = -8 }, { x = 4, y = -7 }, { x = -5, y = -6 }, { x = -6, y = -6 }, { x = -6, y = -5 }, { x = 5, y = -6 }, { x = 6, y = -5 }, { x = 6, y = -6 }, { x = -7, y = -4 }, { x = -7, y = -3 }, { x = 7, y = -4 }, { x = 7, y = -3 }, { x = -8, y = -2 }, { x = -8, y = -1 }, { x = 8, y = -1 }, { x = 8, y = -2 }, { x = -8, y = 0 }, { x = -8, y = 1 }, { x = 8, y = 1 }, { x = 8, y = 0 }, { x = -7, y = 3 }, { x = -8, y = 2 }, { x = 7, y = 3 }, { x = 8, y = 2 }, { x = -7, y = 4 }, { x = -6, y = 5 }, { x = 6, y = 5 }, { x = 7, y = 4 }, { x = -5, y = 6 }, { x = -6, y = 6 }, { x = -4, y = 7 }, { x = -3, y = 7 }, { x = 3, y = 7 }, { x = 5, y = 6 }, { x = 4, y = 7 }, { x = 6, y = 6 }, { x = -2, y = 8 }, { x = -1, y = 8 }, { x = 0, y = 8 }, { x = 1, y = 8 }, { x = 2, y = 8 } },
[10] = { { x = -3, y = -9 }, { x = -1, y = -9 }, { x = -2, y = -9 }, { x = 1, y = -9 }, { x = 0, y = -9 }, { x = 3, y = -9 }, { x = 2, y = -9 }, { x = -5, y = -7 }, { x = -6, y = -7 }, { x = -5, y = -8 }, { x = -4, y = -8 }, { x = -3, y = -8 }, { x = 3, y = -8 }, { x = 5, y = -7 }, { x = 5, y = -8 }, { x = 4, y = -8 }, { x = 6, y = -7 }, { x = -7, y = -5 }, { x = -7, y = -6 }, { x = -8, y = -5 }, { x = 7, y = -5 }, { x = 7, y = -6 }, { x = 8, y = -5 }, { x = -9, y = -3 }, { x = -8, y = -4 }, { x = -8, y = -3 }, { x = 8, y = -4 }, { x = 8, y = -3 }, { x = 9, y = -3 }, { x = -9, y = -1 }, { x = -9, y = -2 }, { x = 9, y = -1 }, { x = 9, y = -2 }, { x = -9, y = 1 }, { x = -9, y = 0 }, { x = 9, y = 1 }, { x = 9, y = 0 }, { x = -9, y = 3 }, { x = -9, y = 2 }, { x = -8, y = 3 }, { x = 8, y = 3 }, { x = 9, y = 3 }, { x = 9, y = 2 }, { x = -7, y = 5 }, { x = -8, y = 5 }, { x = -8, y = 4 }, { x = 7, y = 5 }, { x = 8, y = 5 }, { x = 8, y = 4 }, { x = -7, y = 6 }, { x = -6, y = 7 }, { x = -5, y = 7 }, { x = 5, y = 7 }, { x = 7, y = 6 }, { x = 6, y = 7 }, { x = -5, y = 8 }, { x = -4, y = 8 }, { x = -3, y = 8 }, { x = -3, y = 9 }, { x = -2, y = 9 }, { x = -1, y = 9 }, { x = 0, y = 9 }, { x = 1, y = 9 }, { x = 3, y = 8 }, { x = 2, y = 9 }, { x = 3, y = 9 }, { x = 5, y = 8 }, { x = 4, y = 8 } },
[11] = { { x = -5, y = -9 }, { x = -4, y = -9 }, { x = -3, y = -10 }, { x = -1, y = -10 }, { x = -2, y = -10 }, { x = 1, y = -10 }, { x = 0, y = -10 }, { x = 3, y = -10 }, { x = 2, y = -10 }, { x = 5, y = -9 }, { x = 4, y = -9 }, { x = -7, y = -7 }, { x = -6, y = -8 }, { x = 7, y = -7 }, { x = 6, y = -8 }, { x = -9, y = -5 }, { x = -8, y = -6 }, { x = 9, y = -5 }, { x = 8, y = -6 }, { x = -9, y = -4 }, { x = -10, y = -3 }, { x = 9, y = -4 }, { x = 10, y = -3 }, { x = -10, y = -2 }, { x = -10, y = -1 }, { x = 10, y = -1 }, { x = 10, y = -2 }, { x = -10, y = 0 }, { x = -10, y = 1 }, { x = 10, y = 1 }, { x = 10, y = 0 }, { x = -10, y = 2 }, { x = -10, y = 3 }, { x = 10, y = 3 }, { x = 10, y = 2 }, { x = -9, y = 4 }, { x = -9, y = 5 }, { x = 9, y = 5 }, { x = 9, y = 4 }, { x = -8, y = 6 }, { x = -7, y = 7 }, { x = 7, y = 7 }, { x = 8, y = 6 }, { x = -6, y = 8 }, { x = -5, y = 9 }, { x = -4, y = 9 }, { x = 4, y = 9 }, { x = 5, y = 9 }, { x = 6, y = 8 }, { x = -3, y = 10 }, { x = -2, y = 10 }, { x = -1, y = 10 }, { x = 0, y = 10 }, { x = 1, y = 10 }, { x = 2, y = 10 }, { x = 3, y = 10 } },
[12] = { { x = -3, y = -11 }, { x = -2, y = -11 }, { x = -1, y = -11 }, { x = 0, y = -11 }, { x = 1, y = -11 }, { x = 2, y = -11 }, { x = 3, y = -11 }, { x = -7, y = -9 }, { x = -6, y = -9 }, { x = -5, y = -10 }, { x = -4, y = -10 }, { x = 5, y = -10 }, { x = 4, y = -10 }, { x = 7, y = -9 }, { x = 6, y = -9 }, { x = -9, y = -7 }, { x = -7, y = -8 }, { x = -8, y = -8 }, { x = -8, y = -7 }, { x = 7, y = -8 }, { x = 8, y = -7 }, { x = 8, y = -8 }, { x = 9, y = -7 }, { x = -9, y = -6 }, { x = -10, y = -5 }, { x = 9, y = -6 }, { x = 10, y = -5 }, { x = -11, y = -3 }, { x = -10, y = -4 }, { x = 10, y = -4 }, { x = 11, y = -3 }, { x = -11, y = -2 }, { x = -11, y = -1 }, { x = 11, y = -1 }, { x = 11, y = -2 }, { x = -11, y = 0 }, { x = -11, y = 1 }, { x = 11, y = 1 }, { x = 11, y = 0 }, { x = -11, y = 2 }, { x = -11, y = 3 }, { x = 11, y = 3 }, { x = 11, y = 2 }, { x = -10, y = 5 }, { x = -10, y = 4 }, { x = 10, y = 5 }, { x = 10, y = 4 }, { x = -9, y = 7 }, { x = -9, y = 6 }, { x = -8, y = 7 }, { x = 8, y = 7 }, { x = 9, y = 7 }, { x = 9, y = 6 }, { x = -8, y = 8 }, { x = -7, y = 8 }, { x = -7, y = 9 }, { x = -6, y = 9 }, { x = 7, y = 8 }, { x = 7, y = 9 }, { x = 6, y = 9 }, { x = 8, y = 8 }, { x = -5, y = 10 }, { x = -4, y = 10 }, { x = -3, y = 11 }, { x = -2, y = 11 }, { x = -1, y = 11 }, { x = 0, y = 11 }, { x = 1, y = 11 }, { x = 2, y = 11 }, { x = 3, y = 11 }, { x = 4, y = 10 }, { x = 5, y = 10 } },
[13] = { { x = -5, y = -11 }, { x = -4, y = -11 }, { x = -3, y = -12 }, { x = -1, y = -12 }, { x = -2, y = -12 }, { x = 1, y = -12 }, { x = 0, y = -12 }, { x = 3, y = -12 }, { x = 2, y = -12 }, { x = 4, y = -11 }, { x = 5, y = -11 }, { x = -8, y = -9 }, { x = -7, y = -10 }, { x = -6, y = -10 }, { x = 6, y = -10 }, { x = 7, y = -10 }, { x = 8, y = -9 }, { x = -10, y = -7 }, { x = -9, y = -8 }, { x = 9, y = -8 }, { x = 10, y = -7 }, { x = -11, y = -5 }, { x = -10, y = -6 }, { x = 10, y = -6 }, { x = 11, y = -5 }, { x = -11, y = -4 }, { x = -12, y = -3 }, { x = 11, y = -4 }, { x = 12, y = -3 }, { x = -12, y = -1 }, { x = -12, y = -2 }, { x = 12, y = -1 }, { x = 12, y = -2 }, { x = -12, y = 1 }, { x = -12, y = 0 }, { x = 12, y = 1 }, { x = 12, y = 0 }, { x = -12, y = 3 }, { x = -12, y = 2 }, { x = 12, y = 3 }, { x = 12, y = 2 }, { x = -11, y = 5 }, { x = -11, y = 4 }, { x = 11, y = 4 }, { x = 11, y = 5 }, { x = -10, y = 7 }, { x = -10, y = 6 }, { x = 10, y = 6 }, { x = 10, y = 7 }, { x = -9, y = 8 }, { x = -8, y = 9 }, { x = 9, y = 8 }, { x = 8, y = 9 }, { x = -7, y = 10 }, { x = -5, y = 11 }, { x = -6, y = 10 }, { x = -4, y = 11 }, { x = 5, y = 11 }, { x = 4, y = 11 }, { x = 7, y = 10 }, { x = 6, y = 10 }, { x = -3, y = 12 }, { x = -2, y = 12 }, { x = -1, y = 12 }, { x = 0, y = 12 }, { x = 1, y = 12 }, { x = 2, y = 12 }, { x = 3, y = 12 } },
[14] = { { x = -3, y = -13 }, { x = -1, y = -13 }, { x = -2, y = -13 }, { x = 1, y = -13 }, { x = 0, y = -13 }, { x = 3, y = -13 }, { x = 2, y = -13 }, { x = -7, y = -11 }, { x = -6, y = -11 }, { x = -5, y = -12 }, { x = -6, y = -12 }, { x = -4, y = -12 }, { x = 5, y = -12 }, { x = 4, y = -12 }, { x = 7, y = -11 }, { x = 6, y = -11 }, { x = 6, y = -12 }, { x = -10, y = -9 }, { x = -9, y = -9 }, { x = -9, y = -10 }, { x = -8, y = -10 }, { x = 9, y = -9 }, { x = 9, y = -10 }, { x = 8, y = -10 }, { x = 10, y = -9 }, { x = -11, y = -7 }, { x = -10, y = -8 }, { x = 11, y = -7 }, { x = 10, y = -8 }, { x = -11, y = -6 }, { x = -12, y = -6 }, { x = -12, y = -5 }, { x = 11, y = -6 }, { x = 12, y = -6 }, { x = 12, y = -5 }, { x = -13, y = -3 }, { x = -12, y = -4 }, { x = 12, y = -4 }, { x = 13, y = -3 }, { x = -13, y = -2 }, { x = -13, y = -1 }, { x = 13, y = -1 }, { x = 13, y = -2 }, { x = -13, y = 0 }, { x = -13, y = 1 }, { x = 13, y = 1 }, { x = 13, y = 0 }, { x = -13, y = 2 }, { x = -13, y = 3 }, { x = 13, y = 3 }, { x = 13, y = 2 }, { x = -12, y = 5 }, { x = -12, y = 4 }, { x = 12, y = 5 }, { x = 12, y = 4 }, { x = -11, y = 6 }, { x = -11, y = 7 }, { x = -12, y = 6 }, { x = 11, y = 7 }, { x = 11, y = 6 }, { x = 12, y = 6 }, { x = -10, y = 8 }, { x = -10, y = 9 }, { x = -9, y = 9 }, { x = 9, y = 9 }, { x = 10, y = 9 }, { x = 10, y = 8 }, { x = -9, y = 10 }, { x = -8, y = 10 }, { x = -7, y = 11 }, { x = -6, y = 11 }, { x = 7, y = 11 }, { x = 6, y = 11 }, { x = 8, y = 10 }, { x = 9, y = 10 }, { x = -6, y = 12 }, { x = -5, y = 12 }, { x = -4, y = 12 }, { x = -3, y = 13 }, { x = -2, y = 13 }, { x = -1, y = 13 }, { x = 0, y = 13 }, { x = 1, y = 13 }, { x = 2, y = 13 }, { x = 3, y = 13 }, { x = 5, y = 12 }, { x = 4, y = 12 }, { x = 6, y = 12 } },
[15] = { { x = -5, y = -13 }, { x = -6, y = -13 }, { x = -4, y = -13 }, { x = -3, y = -14 }, { x = -1, y = -14 }, { x = -2, y = -14 }, { x = 1, y = -14 }, { x = 0, y = -14 }, { x = 3, y = -14 }, { x = 2, y = -14 }, { x = 5, y = -13 }, { x = 4, y = -13 }, { x = 6, y = -13 }, { x = -9, y = -11 }, { x = -8, y = -11 }, { x = -8, y = -12 }, { x = -7, y = -12 }, { x = 7, y = -12 }, { x = 8, y = -12 }, { x = 8, y = -11 }, { x = 9, y = -11 }, { x = -11, y = -9 }, { x = -10, y = -10 }, { x = 10, y = -10 }, { x = 11, y = -9 }, { x = -12, y = -7 }, { x = -11, y = -8 }, { x = -12, y = -8 }, { x = 11, y = -8 }, { x = 12, y = -8 }, { x = 12, y = -7 }, { x = -13, y = -5 }, { x = -13, y = -6 }, { x = 13, y = -5 }, { x = 13, y = -6 }, { x = -13, y = -4 }, { x = -14, y = -3 }, { x = 13, y = -4 }, { x = 14, y = -3 }, { x = -14, y = -2 }, { x = -14, y = -1 }, { x = 14, y = -1 }, { x = 14, y = -2 }, { x = -14, y = 0 }, { x = -14, y = 1 }, { x = 14, y = 1 }, { x = 14, y = 0 }, { x = -14, y = 2 }, { x = -14, y = 3 }, { x = 14, y = 3 }, { x = 14, y = 2 }, { x = -13, y = 4 }, { x = -13, y = 5 }, { x = 13, y = 5 }, { x = 13, y = 4 }, { x = -13, y = 6 }, { x = -12, y = 7 }, { x = 12, y = 7 }, { x = 13, y = 6 }, { x = -11, y = 9 }, { x = -11, y = 8 }, { x = -12, y = 8 }, { x = 11, y = 8 }, { x = 11, y = 9 }, { x = 12, y = 8 }, { x = -9, y = 11 }, { x = -10, y = 10 }, { x = -8, y = 11 }, { x = 9, y = 11 }, { x = 8, y = 11 }, { x = 10, y = 10 }, { x = -7, y = 12 }, { x = -8, y = 12 }, { x = -6, y = 13 }, { x = -5, y = 13 }, { x = -4, y = 13 }, { x = 5, y = 13 }, { x = 4, y = 13 }, { x = 7, y = 12 }, { x = 6, y = 13 }, { x = 8, y = 12 }, { x = -3, y = 14 }, { x = -2, y = 14 }, { x = -1, y = 14 }, { x = 0, y = 14 }, { x = 1, y = 14 }, { x = 2, y = 14 }, { x = 3, y = 14 } },
[16] = { { x = -3, y = -15 }, { x = -1, y = -15 }, { x = -2, y = -15 }, { x = 1, y = -15 }, { x = 0, y = -15 }, { x = 3, y = -15 }, { x = 2, y = -15 }, { x = -7, y = -13 }, { x = -8, y = -13 }, { x = -5, y = -14 }, { x = -6, y = -14 }, { x = -4, y = -14 }, { x = 5, y = -14 }, { x = 4, y = -14 }, { x = 7, y = -13 }, { x = 6, y = -14 }, { x = 8, y = -13 }, { x = -9, y = -12 }, { x = -10, y = -11 }, { x = 9, y = -12 }, { x = 10, y = -11 }, { x = -11, y = -10 }, { x = -12, y = -9 }, { x = 11, y = -10 }, { x = 12, y = -9 }, { x = -13, y = -7 }, { x = -13, y = -8 }, { x = 13, y = -7 }, { x = 13, y = -8 }, { x = -14, y = -6 }, { x = -14, y = -5 }, { x = 14, y = -5 }, { x = 14, y = -6 }, { x = -15, y = -3 }, { x = -14, y = -4 }, { x = 15, y = -3 }, { x = 14, y = -4 }, { x = -15, y = -2 }, { x = -15, y = -1 }, { x = 15, y = -1 }, { x = 15, y = -2 }, { x = -15, y = 0 }, { x = -15, y = 1 }, { x = 15, y = 1 }, { x = 15, y = 0 }, { x = -15, y = 2 }, { x = -15, y = 3 }, { x = 15, y = 3 }, { x = 15, y = 2 }, { x = -14, y = 5 }, { x = -14, y = 4 }, { x = 14, y = 5 }, { x = 14, y = 4 }, { x = -13, y = 7 }, { x = -14, y = 6 }, { x = 13, y = 7 }, { x = 14, y = 6 }, { x = -13, y = 8 }, { x = -12, y = 9 }, { x = 12, y = 9 }, { x = 13, y = 8 }, { x = -11, y = 10 }, { x = -10, y = 11 }, { x = 10, y = 11 }, { x = 11, y = 10 }, { x = -9, y = 12 }, { x = -8, y = 13 }, { x = -7, y = 13 }, { x = 7, y = 13 }, { x = 8, y = 13 }, { x = 9, y = 12 }, { x = -6, y = 14 }, { x = -5, y = 14 }, { x = -4, y = 14 }, { x = -3, y = 15 }, { x = -2, y = 15 }, { x = -1, y = 15 }, { x = 0, y = 15 }, { x = 1, y = 15 }, { x = 2, y = 15 }, { x = 3, y = 15 }, { x = 4, y = 14 }, { x = 5, y = 14 }, { x = 6, y = 14 } },
[17] = { { x = -5, y = -15 }, { x = -6, y = -15 }, { x = -3, y = -16 }, { x = -4, y = -16 }, { x = -4, y = -15 }, { x = -1, y = -16 }, { x = -2, y = -16 }, { x = 1, y = -16 }, { x = 0, y = -16 }, { x = 3, y = -16 }, { x = 2, y = -16 }, { x = 5, y = -15 }, { x = 4, y = -15 }, { x = 4, y = -16 }, { x = 6, y = -15 }, { x = -9, y = -13 }, { x = -10, y = -13 }, { x = -8, y = -14 }, { x = -7, y = -14 }, { x = 7, y = -14 }, { x = 9, y = -13 }, { x = 8, y = -14 }, { x = 10, y = -13 }, { x = -11, y = -12 }, { x = -11, y = -11 }, { x = -12, y = -11 }, { x = -10, y = -12 }, { x = 11, y = -11 }, { x = 11, y = -12 }, { x = 10, y = -12 }, { x = 12, y = -11 }, { x = -13, y = -10 }, { x = -13, y = -9 }, { x = -12, y = -10 }, { x = 13, y = -9 }, { x = 13, y = -10 }, { x = 12, y = -10 }, { x = -14, y = -7 }, { x = -14, y = -8 }, { x = 14, y = -7 }, { x = 14, y = -8 }, { x = -15, y = -6 }, { x = -15, y = -5 }, { x = 15, y = -5 }, { x = 15, y = -6 }, { x = -15, y = -4 }, { x = -16, y = -4 }, { x = -16, y = -3 }, { x = 15, y = -4 }, { x = 16, y = -3 }, { x = 16, y = -4 }, { x = -16, y = -2 }, { x = -16, y = -1 }, { x = 16, y = -1 }, { x = 16, y = -2 }, { x = -16, y = 0 }, { x = -16, y = 1 }, { x = 16, y = 1 }, { x = 16, y = 0 }, { x = -16, y = 2 }, { x = -16, y = 3 }, { x = 16, y = 3 }, { x = 16, y = 2 }, { x = -16, y = 4 }, { x = -15, y = 4 }, { x = -15, y = 5 }, { x = 15, y = 5 }, { x = 15, y = 4 }, { x = 16, y = 4 }, { x = -15, y = 6 }, { x = -14, y = 7 }, { x = 14, y = 7 }, { x = 15, y = 6 }, { x = -13, y = 9 }, { x = -14, y = 8 }, { x = 13, y = 9 }, { x = 14, y = 8 }, { x = -13, y = 10 }, { x = -12, y = 10 }, { x = -12, y = 11 }, { x = -11, y = 11 }, { x = 11, y = 11 }, { x = 12, y = 11 }, { x = 12, y = 10 }, { x = 13, y = 10 }, { x = -11, y = 12 }, { x = -10, y = 12 }, { x = -10, y = 13 }, { x = -9, y = 13 }, { x = 9, y = 13 }, { x = 10, y = 13 }, { x = 10, y = 12 }, { x = 11, y = 12 }, { x = -8, y = 14 }, { x = -7, y = 14 }, { x = -6, y = 15 }, { x = -5, y = 15 }, { x = -4, y = 15 }, { x = 4, y = 15 }, { x = 5, y = 15 }, { x = 7, y = 14 }, { x = 6, y = 15 }, { x = 8, y = 14 }, { x = -4, y = 16 }, { x = -3, y = 16 }, { x = -2, y = 16 }, { x = -1, y = 16 }, { x = 0, y = 16 }, { x = 1, y = 16 }, { x = 2, y = 16 }, { x = 3, y = 16 }, { x = 4, y = 16 } },
[18] = { { x = -3, y = -17 }, { x = -4, y = -17 }, { x = -1, y = -17 }, { x = -2, y = -17 }, { x = 1, y = -17 }, { x = 0, y = -17 }, { x = 3, y = -17 }, { x = 2, y = -17 }, { x = 4, y = -17 }, { x = -9, y = -15 }, { x = -8, y = -15 }, { x = -7, y = -15 }, { x = -7, y = -16 }, { x = -6, y = -16 }, { x = -5, y = -16 }, { x = 5, y = -16 }, { x = 7, y = -15 }, { x = 7, y = -16 }, { x = 6, y = -16 }, { x = 9, y = -15 }, { x = 8, y = -15 }, { x = -11, y = -13 }, { x = -10, y = -14 }, { x = -9, y = -14 }, { x = 9, y = -14 }, { x = 11, y = -13 }, { x = 10, y = -14 }, { x = -13, y = -11 }, { x = -12, y = -12 }, { x = 13, y = -11 }, { x = 12, y = -12 }, { x = -15, y = -9 }, { x = -14, y = -10 }, { x = -14, y = -9 }, { x = 14, y = -10 }, { x = 14, y = -9 }, { x = 15, y = -9 }, { x = -15, y = -8 }, { x = -15, y = -7 }, { x = -16, y = -7 }, { x = 15, y = -8 }, { x = 15, y = -7 }, { x = 16, y = -7 }, { x = -16, y = -6 }, { x = -16, y = -5 }, { x = 16, y = -5 }, { x = 16, y = -6 }, { x = -17, y = -3 }, { x = -17, y = -4 }, { x = 17, y = -3 }, { x = 17, y = -4 }, { x = -17, y = -1 }, { x = -17, y = -2 }, { x = 17, y = -1 }, { x = 17, y = -2 }, { x = -17, y = 1 }, { x = -17, y = 0 }, { x = 17, y = 1 }, { x = 17, y = 0 }, { x = -17, y = 3 }, { x = -17, y = 2 }, { x = 17, y = 3 }, { x = 17, y = 2 }, { x = -17, y = 4 }, { x = -16, y = 5 }, { x = 16, y = 5 }, { x = 17, y = 4 }, { x = -15, y = 7 }, { x = -16, y = 7 }, { x = -16, y = 6 }, { x = 15, y = 7 }, { x = 16, y = 7 }, { x = 16, y = 6 }, { x = -15, y = 9 }, { x = -15, y = 8 }, { x = -14, y = 9 }, { x = 14, y = 9 }, { x = 15, y = 9 }, { x = 15, y = 8 }, { x = -14, y = 10 }, { x = -13, y = 11 }, { x = 13, y = 11 }, { x = 14, y = 10 }, { x = -12, y = 12 }, { x = -11, y = 13 }, { x = 11, y = 13 }, { x = 12, y = 12 }, { x = -10, y = 14 }, { x = -9, y = 14 }, { x = -9, y = 15 }, { x = -8, y = 15 }, { x = -7, y = 15 }, { x = 7, y = 15 }, { x = 9, y = 14 }, { x = 9, y = 15 }, { x = 8, y = 15 }, { x = 10, y = 14 }, { x = -7, y = 16 }, { x = -6, y = 16 }, { x = -5, y = 16 }, { x = -4, y = 17 }, { x = -3, y = 17 }, { x = -2, y = 17 }, { x = -1, y = 17 }, { x = 0, y = 17 }, { x = 1, y = 17 }, { x = 2, y = 17 }, { x = 3, y = 17 }, { x = 4, y = 17 }, { x = 5, y = 16 }, { x = 6, y = 16 }, { x = 7, y = 16 } },
[19] = { { x = -7, y = -17 }, { x = -6, y = -17 }, { x = -5, y = -17 }, { x = -3, y = -18 }, { x = -4, y = -18 }, { x = -1, y = -18 }, { x = -2, y = -18 }, { x = 1, y = -18 }, { x = 0, y = -18 }, { x = 3, y = -18 }, { x = 2, y = -18 }, { x = 5, y = -17 }, { x = 4, y = -18 }, { x = 7, y = -17 }, { x = 6, y = -17 }, { x = -10, y = -15 }, { x = -9, y = -16 }, { x = -8, y = -16 }, { x = 9, y = -16 }, { x = 8, y = -16 }, { x = 10, y = -15 }, { x = -13, y = -13 }, { x = -11, y = -14 }, { x = -12, y = -14 }, { x = -12, y = -13 }, { x = 11, y = -14 }, { x = 13, y = -13 }, { x = 12, y = -13 }, { x = 12, y = -14 }, { x = -13, y = -12 }, { x = -14, y = -12 }, { x = -14, y = -11 }, { x = 13, y = -12 }, { x = 14, y = -11 }, { x = 14, y = -12 }, { x = -15, y = -10 }, { x = -16, y = -9 }, { x = 15, y = -10 }, { x = 16, y = -9 }, { x = -17, y = -7 }, { x = -16, y = -8 }, { x = 16, y = -8 }, { x = 17, y = -7 }, { x = -17, y = -5 }, { x = -17, y = -6 }, { x = 17, y = -6 }, { x = 17, y = -5 }, { x = -18, y = -3 }, { x = -18, y = -4 }, { x = 18, y = -4 }, { x = 18, y = -3 }, { x = -18, y = -1 }, { x = -18, y = -2 }, { x = 18, y = -2 }, { x = 18, y = -1 }, { x = -18, y = 1 }, { x = -18, y = 0 }, { x = 18, y = 0 }, { x = 18, y = 1 }, { x = -18, y = 3 }, { x = -18, y = 2 }, { x = 18, y = 2 }, { x = 18, y = 3 }, { x = -17, y = 5 }, { x = -18, y = 4 }, { x = 17, y = 5 }, { x = 18, y = 4 }, { x = -17, y = 7 }, { x = -17, y = 6 }, { x = 17, y = 7 }, { x = 17, y = 6 }, { x = -16, y = 9 }, { x = -16, y = 8 }, { x = 16, y = 9 }, { x = 16, y = 8 }, { x = -15, y = 10 }, { x = -14, y = 11 }, { x = 14, y = 11 }, { x = 15, y = 10 }, { x = -14, y = 12 }, { x = -13, y = 12 }, { x = -13, y = 13 }, { x = -12, y = 13 }, { x = 12, y = 13 }, { x = 13, y = 13 }, { x = 13, y = 12 }, { x = 14, y = 12 }, { x = -12, y = 14 }, { x = -11, y = 14 }, { x = -10, y = 15 }, { x = 10, y = 15 }, { x = 11, y = 14 }, { x = 12, y = 14 }, { x = -9, y = 16 }, { x = -7, y = 17 }, { x = -8, y = 16 }, { x = -5, y = 17 }, { x = -6, y = 17 }, { x = 5, y = 17 }, { x = 7, y = 17 }, { x = 6, y = 17 }, { x = 8, y = 16 }, { x = 9, y = 16 }, { x = -3, y = 18 }, { x = -4, y = 18 }, { x = -1, y = 18 }, { x = -2, y = 18 }, { x = 1, y = 18 }, { x = 0, y = 18 }, { x = 3, y = 18 }, { x = 2, y = 18 }, { x = 4, y = 18 } },
[20] = { { x = -3, y = -19 }, { x = -4, y = -19 }, { x = -1, y = -19 }, { x = -2, y = -19 }, { x = 1, y = -19 }, { x = 0, y = -19 }, { x = 3, y = -19 }, { x = 2, y = -19 }, { x = 4, y = -19 }, { x = -9, y = -17 }, { x = -7, y = -18 }, { x = -8, y = -17 }, { x = -5, y = -18 }, { x = -6, y = -18 }, { x = 5, y = -18 }, { x = 7, y = -18 }, { x = 6, y = -18 }, { x = 9, y = -17 }, { x = 8, y = -17 }, { x = -11, y = -16 }, { x = -11, y = -15 }, { x = -12, y = -15 }, { x = -10, y = -16 }, { x = 11, y = -15 }, { x = 11, y = -16 }, { x = 10, y = -16 }, { x = 12, y = -15 }, { x = -13, y = -14 }, { x = -14, y = -13 }, { x = 13, y = -14 }, { x = 14, y = -13 }, { x = -15, y = -12 }, { x = -15, y = -11 }, { x = -16, y = -11 }, { x = 15, y = -11 }, { x = 15, y = -12 }, { x = 16, y = -11 }, { x = -17, y = -9 }, { x = -16, y = -10 }, { x = 16, y = -10 }, { x = 17, y = -9 }, { x = -17, y = -8 }, { x = -18, y = -7 }, { x = 17, y = -8 }, { x = 18, y = -7 }, { x = -18, y = -6 }, { x = -18, y = -5 }, { x = 18, y = -5 }, { x = 18, y = -6 }, { x = -19, y = -4 }, { x = -19, y = -3 }, { x = 19, y = -3 }, { x = 19, y = -4 }, { x = -19, y = -2 }, { x = -19, y = -1 }, { x = 19, y = -1 }, { x = 19, y = -2 }, { x = -19, y = 0 }, { x = -19, y = 1 }, { x = 19, y = 1 }, { x = 19, y = 0 }, { x = -19, y = 2 }, { x = -19, y = 3 }, { x = 19, y = 3 }, { x = 19, y = 2 }, { x = -19, y = 4 }, { x = -18, y = 5 }, { x = 18, y = 5 }, { x = 19, y = 4 }, { x = -18, y = 7 }, { x = -18, y = 6 }, { x = 18, y = 7 }, { x = 18, y = 6 }, { x = -17, y = 9 }, { x = -17, y = 8 }, { x = 17, y = 9 }, { x = 17, y = 8 }, { x = -16, y = 10 }, { x = -16, y = 11 }, { x = -15, y = 11 }, { x = 15, y = 11 }, { x = 16, y = 11 }, { x = 16, y = 10 }, { x = -15, y = 12 }, { x = -14, y = 13 }, { x = 14, y = 13 }, { x = 15, y = 12 }, { x = -13, y = 14 }, { x = -12, y = 15 }, { x = -11, y = 15 }, { x = 11, y = 15 }, { x = 12, y = 15 }, { x = 13, y = 14 }, { x = -11, y = 16 }, { x = -10, y = 16 }, { x = -9, y = 17 }, { x = -8, y = 17 }, { x = 9, y = 17 }, { x = 8, y = 17 }, { x = 10, y = 16 }, { x = 11, y = 16 }, { x = -7, y = 18 }, { x = -5, y = 18 }, { x = -6, y = 18 }, { x = -4, y = 19 }, { x = -3, y = 19 }, { x = -2, y = 19 }, { x = -1, y = 19 }, { x = 0, y = 19 }, { x = 1, y = 19 }, { x = 2, y = 19 }, { x = 3, y = 19 }, { x = 4, y = 19 }, { x = 5, y = 18 }, { x = 7, y = 18 }, { x = 6, y = 18 } },
[21] = { { x = -7, y = -19 }, { x = -5, y = -19 }, { x = -6, y = -19 }, { x = -3, y = -20 }, { x = -4, y = -20 }, { x = -1, y = -20 }, { x = -2, y = -20 }, { x = 1, y = -20 }, { x = 0, y = -20 }, { x = 3, y = -20 }, { x = 2, y = -20 }, { x = 5, y = -19 }, { x = 4, y = -20 }, { x = 7, y = -19 }, { x = 6, y = -19 }, { x = -11, y = -17 }, { x = -10, y = -17 }, { x = -9, y = -18 }, { x = -8, y = -18 }, { x = 9, y = -18 }, { x = 8, y = -18 }, { x = 10, y = -17 }, { x = 11, y = -17 }, { x = -13, y = -15 }, { x = -14, y = -15 }, { x = -12, y = -16 }, { x = 13, y = -15 }, { x = 12, y = -16 }, { x = 14, y = -15 }, { x = -15, y = -14 }, { x = -15, y = -13 }, { x = -14, y = -14 }, { x = 15, y = -13 }, { x = 15, y = -14 }, { x = 14, y = -14 }, { x = -17, y = -11 }, { x = -16, y = -12 }, { x = 16, y = -12 }, { x = 17, y = -11 }, { x = -17, y = -10 }, { x = -18, y = -9 }, { x = 17, y = -10 }, { x = 18, y = -9 }, { x = -19, y = -7 }, { x = -18, y = -8 }, { x = 18, y = -8 }, { x = 19, y = -7 }, { x = -19, y = -6 }, { x = -19, y = -5 }, { x = 19, y = -6 }, { x = 19, y = -5 }, { x = -20, y = -4 }, { x = -20, y = -3 }, { x = 20, y = -3 }, { x = 20, y = -4 }, { x = -20, y = -2 }, { x = -20, y = -1 }, { x = 20, y = -1 }, { x = 20, y = -2 }, { x = -20, y = 0 }, { x = -20, y = 1 }, { x = 20, y = 1 }, { x = 20, y = 0 }, { x = -20, y = 2 }, { x = -20, y = 3 }, { x = 20, y = 3 }, { x = 20, y = 2 }, { x = -20, y = 4 }, { x = -19, y = 5 }, { x = 19, y = 5 }, { x = 20, y = 4 }, { x = -19, y = 7 }, { x = -19, y = 6 }, { x = 19, y = 7 }, { x = 19, y = 6 }, { x = -18, y = 9 }, { x = -18, y = 8 }, { x = 18, y = 9 }, { x = 18, y = 8 }, { x = -17, y = 11 }, { x = -17, y = 10 }, { x = 17, y = 11 }, { x = 17, y = 10 }, { x = -16, y = 12 }, { x = -15, y = 13 }, { x = 15, y = 13 }, { x = 16, y = 12 }, { x = -15, y = 14 }, { x = -14, y = 14 }, { x = -14, y = 15 }, { x = -13, y = 15 }, { x = 13, y = 15 }, { x = 14, y = 15 }, { x = 14, y = 14 }, { x = 15, y = 14 }, { x = -12, y = 16 }, { x = -11, y = 17 }, { x = -10, y = 17 }, { x = 11, y = 17 }, { x = 10, y = 17 }, { x = 12, y = 16 }, { x = -9, y = 18 }, { x = -8, y = 18 }, { x = -7, y = 19 }, { x = -5, y = 19 }, { x = -6, y = 19 }, { x = 5, y = 19 }, { x = 6, y = 19 }, { x = 7, y = 19 }, { x = 9, y = 18 }, { x = 8, y = 18 }, { x = -4, y = 20 }, { x = -3, y = 20 }, { x = -2, y = 20 }, { x = -1, y = 20 }, { x = 0, y = 20 }, { x = 1, y = 20 }, { x = 2, y = 20 }, { x = 3, y = 20 }, { x = 4, y = 20 } },
[22] = { { x = -3, y = -21 }, { x = -4, y = -21 }, { x = -1, y = -21 }, { x = -2, y = -21 }, { x = 1, y = -21 }, { x = 0, y = -21 }, { x = 3, y = -21 }, { x = 2, y = -21 }, { x = 4, y = -21 }, { x = -10, y = -19 }, { x = -9, y = -19 }, { x = -8, y = -19 }, { x = -7, y = -20 }, { x = -5, y = -20 }, { x = -6, y = -20 }, { x = 5, y = -20 }, { x = 7, y = -20 }, { x = 6, y = -20 }, { x = 9, y = -19 }, { x = 8, y = -19 }, { x = 10, y = -19 }, { x = -13, y = -17 }, { x = -12, y = -17 }, { x = -11, y = -18 }, { x = -10, y = -18 }, { x = 11, y = -18 }, { x = 10, y = -18 }, { x = 13, y = -17 }, { x = 12, y = -17 }, { x = -15, y = -15 }, { x = -13, y = -16 }, { x = -14, y = -16 }, { x = 13, y = -16 }, { x = 15, y = -15 }, { x = 14, y = -16 }, { x = -17, y = -13 }, { x = -16, y = -14 }, { x = -16, y = -13 }, { x = 17, y = -13 }, { x = 16, y = -13 }, { x = 16, y = -14 }, { x = -17, y = -12 }, { x = -18, y = -11 }, { x = 17, y = -12 }, { x = 18, y = -11 }, { x = -19, y = -10 }, { x = -19, y = -9 }, { x = -18, y = -10 }, { x = 18, y = -10 }, { x = 19, y = -10 }, { x = 19, y = -9 }, { x = -19, y = -8 }, { x = -20, y = -7 }, { x = 19, y = -8 }, { x = 20, y = -7 }, { x = -20, y = -6 }, { x = -20, y = -5 }, { x = 20, y = -6 }, { x = 20, y = -5 }, { x = -21, y = -4 }, { x = -21, y = -3 }, { x = 21, y = -3 }, { x = 21, y = -4 }, { x = -21, y = -2 }, { x = -21, y = -1 }, { x = 21, y = -1 }, { x = 21, y = -2 }, { x = -21, y = 0 }, { x = -21, y = 1 }, { x = 21, y = 1 }, { x = 21, y = 0 }, { x = -21, y = 2 }, { x = -21, y = 3 }, { x = 21, y = 3 }, { x = 21, y = 2 }, { x = -21, y = 4 }, { x = -20, y = 5 }, { x = 20, y = 5 }, { x = 21, y = 4 }, { x = -20, y = 7 }, { x = -20, y = 6 }, { x = 20, y = 7 }, { x = 20, y = 6 }, { x = -19, y = 9 }, { x = -19, y = 8 }, { x = 19, y = 9 }, { x = 19, y = 8 }, { x = -19, y = 10 }, { x = -18, y = 11 }, { x = -18, y = 10 }, { x = 18, y = 11 }, { x = 18, y = 10 }, { x = 19, y = 10 }, { x = -17, y = 13 }, { x = -17, y = 12 }, { x = -16, y = 13 }, { x = 16, y = 13 }, { x = 17, y = 13 }, { x = 17, y = 12 }, { x = -16, y = 14 }, { x = -15, y = 15 }, { x = 15, y = 15 }, { x = 16, y = 14 }, { x = -14, y = 16 }, { x = -13, y = 16 }, { x = -13, y = 17 }, { x = -12, y = 17 }, { x = 13, y = 16 }, { x = 13, y = 17 }, { x = 12, y = 17 }, { x = 14, y = 16 }, { x = -11, y = 18 }, { x = -10, y = 18 }, { x = -10, y = 19 }, { x = -9, y = 19 }, { x = -8, y = 19 }, { x = 9, y = 19 }, { x = 8, y = 19 }, { x = 11, y = 18 }, { x = 10, y = 18 }, { x = 10, y = 19 }, { x = -7, y = 20 }, { x = -6, y = 20 }, { x = -5, y = 20 }, { x = -3, y = 21 }, { x = -4, y = 21 }, { x = -1, y = 21 }, { x = -2, y = 21 }, { x = 1, y = 21 }, { x = 0, y = 21 }, { x = 3, y = 21 }, { x = 2, y = 21 }, { x = 4, y = 21 }, { x = 5, y = 20 }, { x = 7, y = 20 }, { x = 6, y = 20 } },
[23] = { { x = -8, y = -21 }, { x = -7, y = -21 }, { x = -6, y = -21 }, { x = -5, y = -21 }, { x = -3, y = -22 }, { x = -4, y = -22 }, { x = -1, y = -22 }, { x = -2, y = -22 }, { x = 1, y = -22 }, { x = 0, y = -22 }, { x = 3, y = -22 }, { x = 2, y = -22 }, { x = 5, y = -21 }, { x = 4, y = -22 }, { x = 7, y = -21 }, { x = 6, y = -21 }, { x = 8, y = -21 }, { x = -12, y = -19 }, { x = -11, y = -19 }, { x = -10, y = -20 }, { x = -9, y = -20 }, { x = -8, y = -20 }, { x = 9, y = -20 }, { x = 8, y = -20 }, { x = 11, y = -19 }, { x = 10, y = -20 }, { x = 12, y = -19 }, { x = -14, y = -17 }, { x = -13, y = -18 }, { x = -12, y = -18 }, { x = 13, y = -18 }, { x = 12, y = -18 }, { x = 14, y = -17 }, { x = -15, y = -16 }, { x = -16, y = -15 }, { x = 15, y = -16 }, { x = 16, y = -15 }, { x = -17, y = -14 }, { x = -18, y = -13 }, { x = 17, y = -14 }, { x = 18, y = -13 }, { x = -19, y = -12 }, { x = -19, y = -11 }, { x = -18, y = -12 }, { x = 18, y = -12 }, { x = 19, y = -12 }, { x = 19, y = -11 }, { x = -20, y = -10 }, { x = -20, y = -9 }, { x = 20, y = -10 }, { x = 20, y = -9 }, { x = -21, y = -8 }, { x = -21, y = -7 }, { x = -20, y = -8 }, { x = 20, y = -8 }, { x = 21, y = -8 }, { x = 21, y = -7 }, { x = -21, y = -6 }, { x = -21, y = -5 }, { x = 21, y = -6 }, { x = 21, y = -5 }, { x = -22, y = -4 }, { x = -22, y = -3 }, { x = 22, y = -3 }, { x = 22, y = -4 }, { x = -22, y = -2 }, { x = -22, y = -1 }, { x = 22, y = -1 }, { x = 22, y = -2 }, { x = -22, y = 0 }, { x = -22, y = 1 }, { x = 22, y = 1 }, { x = 22, y = 0 }, { x = -22, y = 2 }, { x = -22, y = 3 }, { x = 22, y = 3 }, { x = 22, y = 2 }, { x = -22, y = 4 }, { x = -21, y = 5 }, { x = 21, y = 5 }, { x = 22, y = 4 }, { x = -21, y = 7 }, { x = -21, y = 6 }, { x = 21, y = 7 }, { x = 21, y = 6 }, { x = -21, y = 8 }, { x = -20, y = 9 }, { x = -20, y = 8 }, { x = 20, y = 8 }, { x = 20, y = 9 }, { x = 21, y = 8 }, { x = -19, y = 11 }, { x = -20, y = 10 }, { x = 19, y = 11 }, { x = 20, y = 10 }, { x = -19, y = 12 }, { x = -18, y = 13 }, { x = -18, y = 12 }, { x = 18, y = 13 }, { x = 18, y = 12 }, { x = 19, y = 12 }, { x = -17, y = 14 }, { x = -16, y = 15 }, { x = 16, y = 15 }, { x = 17, y = 14 }, { x = -15, y = 16 }, { x = -14, y = 17 }, { x = 14, y = 17 }, { x = 15, y = 16 }, { x = -13, y = 18 }, { x = -12, y = 18 }, { x = -12, y = 19 }, { x = -11, y = 19 }, { x = 11, y = 19 }, { x = 13, y = 18 }, { x = 12, y = 18 }, { x = 12, y = 19 }, { x = -10, y = 20 }, { x = -9, y = 20 }, { x = -8, y = 20 }, { x = -8, y = 21 }, { x = -7, y = 21 }, { x = -6, y = 21 }, { x = -5, y = 21 }, { x = 5, y = 21 }, { x = 7, y = 21 }, { x = 6, y = 21 }, { x = 8, y = 20 }, { x = 9, y = 20 }, { x = 8, y = 21 }, { x = 10, y = 20 }, { x = -4, y = 22 }, { x = -3, y = 22 }, { x = -2, y = 22 }, { x = -1, y = 22 }, { x = 0, y = 22 }, { x = 1, y = 22 }, { x = 2, y = 22 }, { x = 3, y = 22 }, { x = 4, y = 22 } }
}
local function process_explosion_tile(pos, explosion_index, current_radius)
local ffatable = Table.get_table()
local surface = game.surfaces[ffatable.explosion_schedule[explosion_index].surface]
local target_entities = surface.find_entities_filtered({ area = { { pos.x - 0.5, pos.y - 0.5 }, { pos.x + 0.499, pos.y + 0.499 } } })
local explosion_animation = "explosion"
local tile = surface.get_tile(pos)
if tile.name == "out-of-map" then
if ffatable.explosion_schedule[explosion_index].damage_remaining >= out_of_map_tile_health then
explosion_animation = "big-explosion"
surface.set_tiles({ { name = "dirt-5", position = pos } }, true)
end
ffatable.explosion_schedule[explosion_index].damage_remaining = ffatable.explosion_schedule[explosion_index].damage_remaining - out_of_map_tile_health
else
local decay_explosion = true
for _, entity in pairs(target_entities) do
if entity.health then
decay_explosion = false
end
end
if decay_explosion then ffatable.explosion_schedule[explosion_index].damage_remaining = ffatable.explosion_schedule[explosion_index].damage_remaining - empty_tile_damage_decay end
end
for _, entity in pairs(target_entities) do
if entity.valid then
if entity.health then
if entity.health < ffatable.explosion_schedule[explosion_index].damage_remaining then
explosion_animation = "big-explosion"
if entity.health > 500 then explosion_animation = "big-artillery-explosion" end
ffatable.explosion_schedule[explosion_index].damage_remaining = ffatable.explosion_schedule[explosion_index].damage_remaining - entity.health
if entity.name ~= "character" then
entity.damage(2097152, "player", "explosion")
else
entity.die("player")
end
else
entity.damage(ffatable.explosion_schedule[explosion_index].damage_remaining, "player", "explosion")
if entity.valid then
ffatable.explosion_schedule[explosion_index].damage_remaining = ffatable.explosion_schedule[explosion_index].damage_remaining - entity.health
end
end
end
end
end
if ffatable.explosion_schedule[explosion_index].damage_remaining > 5000 and current_radius < 2 then
if math_random(1, 2) == 1 then
explosion_animation = "big-explosion"
else
explosion_animation = "big-artillery-explosion"
end
end
surface.create_entity({ name = explosion_animation, position = pos })
Pollution.explosion(pos, surface, explosion_animation)
if ffatable.explosion_schedule[explosion_index].damage_remaining <= 0 then return false end
return true
end
local function volatility(inventory)
local result = 0
for item, v in pairs(explosive_items) do
local c = inventory.get_item_count(item)
result = result + (c * v)
end
return math_min(max_volatility, result)
end
local function create_explosion_schedule(entity)
local ffatable = Table.get_table()
local inventory = defines.inventory.chest
if entity.type == "car" then inventory = defines.inventory.car_trunk end
local i = entity.get_inventory(inventory)
local explosives_amount = volatility(i)
if explosives_amount < 1 then return end
local center_position = entity.position
if not ffatable.explosion_schedule then ffatable.explosion_schedule = {} end
ffatable.explosion_schedule[#ffatable.explosion_schedule + 1] = {}
ffatable.explosion_schedule[#ffatable.explosion_schedule].surface = entity.surface.name
ffatable.explosion_schedule[#ffatable.explosion_schedule].damage_remaining = damage_per_explosive * explosives_amount
for current_radius = 1, 23, 1 do
ffatable.explosion_schedule[#ffatable.explosion_schedule][current_radius] = {}
ffatable.explosion_schedule[#ffatable.explosion_schedule][current_radius].trigger_tick = game.tick + (current_radius * 8)
local circle_coords = circle_coordinates[current_radius]
for index, tile_position in pairs(circle_coords) do
local pos = { x = center_position.x + tile_position.x, y = center_position.y + tile_position.y }
ffatable.explosion_schedule[#ffatable.explosion_schedule][current_radius][index] = { x = pos.x, y = pos.y }
end
end
entity.die("player")
end
local function on_entity_damaged(event)
local entity = event.entity
if not entity.valid then return end
if not entity.health then return end
if entity.health > entity.prototype.max_health * 0.75 then return end
if entity.type == "container" or entity.type == "logistic-container" then
if math_random(1, 3) == 1 or entity.health <= 0 then
create_explosion_schedule(event.entity)
return
end
end
if entity.type == "cargo-wagon" or entity.type == "car" then
if entity.health <= 0 then
create_explosion_schedule(entity)
return
end
if entity.health < 150 and math_random(1, 3) == 1 then
create_explosion_schedule(entity)
return
end
end
end
local function on_tick(event)
local ffatable = Table.get_table()
local tick = event.tick
if ffatable.explosion_schedule then
local explosion_schedule_is_alive = false
for explosion_index = 1, #ffatable.explosion_schedule, 1 do
if #ffatable.explosion_schedule[explosion_index] > 0 then
explosion_schedule_is_alive = true
for radius = 1, #ffatable.explosion_schedule[explosion_index], 1 do
if ffatable.explosion_schedule[explosion_index][radius].trigger_tick == tick then
for tile_index = 1, #ffatable.explosion_schedule[explosion_index][radius], 1 do
local continue_explosion = process_explosion_tile(ffatable.explosion_schedule[explosion_index][radius][tile_index], explosion_index, radius)
if not continue_explosion then
ffatable.explosion_schedule[explosion_index] = {}
break
end
end
if radius == #ffatable.explosion_schedule[explosion_index] then ffatable.explosion_schedule[explosion_index] = {} end
break
end
end
end
end
if not explosion_schedule_is_alive then ffatable.explosion_schedule = nil end
end
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.explosion_schedule = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
Event.add(defines.events.on_tick, on_tick)

View File

@ -0,0 +1,67 @@
local Public = {}
local math_random = math.random
local math_floor = math.floor
local Table = require 'modules.scrap_towny_ffa.table'
function Public.reproduce()
local ffatable = Table.get_table()
for _, town_center in pairs(ffatable.town_centers) do
local surface = town_center.market.surface
local position = town_center.market.position
local fishes = surface.find_entities_filtered({ name = "fish", position = position, radius = 27 })
if #fishes == 0 then return end
if #fishes >= 100 then return end
-- pick a random fish
local t = math_random(1, #fishes)
local fish = fishes[t]
-- test against all other fishes
local guppy = false
for i, f in pairs(fishes) do
if i ~= t then
if math_floor(fish.position.x) == math_floor(f.position.x) and math_floor(fish.position.y) == math_floor(f.position.y) then
guppy = true
end
end
end
if guppy == true then
--log("fish spawn {" .. fish.position.x .. "," .. fish.position.y .. "}")
surface.create_entity({ name = "water-splash", position = fish.position })
surface.create_entity({ name = "fish", position = fish.position })
end
end
end
local function on_player_used_capsule(event)
if event.item.name ~= "raw-fish" then return end
local player = game.players[event.player_index]
local surface = player.surface
local position = event.position
local tile = player.surface.get_tile(position.x, position.y)
-- return back some of the health if not healthy
if player.character.health < 250 then
player.surface.play_sound({ path = "utility/armor_insert", position = player.position, volume_modifier = 1 })
return
end
-- if using fish on water
if tile.name == "water" and tile.name == "water-green" and tile.name == "deepwater" and tile.name == "deepwater-green" then
-- get the count of fish in the water nearby and test if can be repopulated
local fishes = surface.find_entities_filtered({ name = "fish", position = position, radius = 27 })
if #fishes < 12 then
surface.create_entity({ name = "water-splash", position = position })
surface.create_entity({ name = "fish", position = position })
surface.play_sound({ path = "utility/achievement_unlocked", position = player.position, volume_modifier = 1 })
return
end
end
-- otherwise return the fish and make no sound
player.insert({ name = "raw-fish", count = 1 })
end
local Event = require 'utils.event'
Event.add(defines.events.on_player_used_capsule, on_player_used_capsule)
return Public

View File

@ -0,0 +1,194 @@
--This will add a new game mechanic so that containers with certain fluids explode when they get damaged or are destroyed.
--Made by MewMew
local math_random = math.random
local math_floor = math.floor
local Table = require 'modules.scrap_towny_ffa.table'
local Pollution = require "modules.scrap_towny_ffa.pollution"
local empty_tile_damage_decay = 50
local out_of_map_tile_health = 1500
local container_types = {
["storage-tank"] = true,
["pipe"] = true,
["pipe-to-ground"] = true
}
local fluid_damages = { -- Fluid Whitelist -- add fluid and a damage value to enable
["lubricant"] = 5,
["crude-oil"] = 5,
["gasoline"] = 8,
["heavy-oil"] = 6,
["light-oil"] = 7,
["petroleum-gas"] = 8,
}
local function shuffle(tbl)
local size = #tbl
for i = size, 1, -1 do
local rand = math_random(size)
tbl[i], tbl[rand] = tbl[rand], tbl[i]
end
return tbl
end
local function process_explosion_tile(pos, explosion_index, current_radius)
local ffatable = Table.get_table()
local surface = game.surfaces[ffatable.fluid_explosion_schedule[explosion_index].surface]
local target_entities = surface.find_entities_filtered({ area = { { pos.x - 0.5, pos.y - 0.5 }, { pos.x + 0.499, pos.y + 0.499 } } })
local explosion_animation = "explosion"
local tile = surface.get_tile(pos)
if tile.name == "out-of-map" then
if ffatable.fluid_explosion_schedule[explosion_index].damage_remaining >= out_of_map_tile_health then
explosion_animation = "big-explosion"
surface.set_tiles({ { name = "dirt-5", position = pos } }, true)
end
ffatable.fluid_explosion_schedule[explosion_index].damage_remaining = ffatable.fluid_explosion_schedule[explosion_index].damage_remaining - out_of_map_tile_health
else
local decay_explosion = true
for _, entity in pairs(target_entities) do
if entity.health then
decay_explosion = false
end
end
if decay_explosion then ffatable.fluid_explosion_schedule[explosion_index].damage_remaining = ffatable.fluid_explosion_schedule[explosion_index].damage_remaining - empty_tile_damage_decay end
end
for _, entity in pairs(target_entities) do
if entity.valid then
if entity.health then
if entity.health <= ffatable.fluid_explosion_schedule[explosion_index].damage_remaining then
explosion_animation = "big-explosion"
if entity.health > 500 then explosion_animation = "big-artillery-explosion" end
ffatable.fluid_explosion_schedule[explosion_index].damage_remaining = ffatable.fluid_explosion_schedule[explosion_index].damage_remaining - entity.health
if entity.name ~= "character" then
entity.damage(2097152, "player", "explosion")
else
entity.die("player")
end
else
entity.damage(ffatable.fluid_explosion_schedule[explosion_index].damage_remaining, "player", "explosion")
ffatable.fluid_explosion_schedule[explosion_index].damage_remaining = 0
end
end
end
end
if ffatable.fluid_explosion_schedule[explosion_index].damage_remaining > 5000 and current_radius < 2 then
if math_random(1, 2) == 1 then
explosion_animation = "big-explosion"
else
explosion_animation = "big-artillery-explosion"
end
end
surface.create_entity({ name = explosion_animation, position = pos })
Pollution.explosion(pos, surface, explosion_animation)
if ffatable.fluid_explosion_schedule[explosion_index].damage_remaining <= 0 then return false end
return true
end
local function create_explosion_schedule(entity)
local ffatable = Table.get_table()
local explosives_amount = math_floor(entity.fluidbox[1].amount)
if explosives_amount < 1 then return end
local center_position = entity.position
if not ffatable.fluid_explosion_schedule then ffatable.fluid_explosion_schedule = {} end
ffatable.fluid_explosion_schedule[#ffatable.fluid_explosion_schedule + 1] = {}
ffatable.fluid_explosion_schedule[#ffatable.fluid_explosion_schedule].surface = entity.surface.name
ffatable.fluid_explosion_schedule[#ffatable.fluid_explosion_schedule].damage_remaining = fluid_damages[entity.fluidbox[1].name] * explosives_amount
local circle_coordinates = {
[1] = { { x = 0, y = 0 } },
[2] = { { x = -1, y = -1 }, { x = 1, y = -1 }, { x = 0, y = -1 }, { x = -1, y = 0 }, { x = -1, y = 1 }, { x = 0, y = 1 }, { x = 1, y = 1 }, { x = 1, y = 0 } },
[3] = { { x = -2, y = -1 }, { x = -1, y = -2 }, { x = 1, y = -2 }, { x = 0, y = -2 }, { x = 2, y = -1 }, { x = -2, y = 1 }, { x = -2, y = 0 }, { x = 2, y = 1 }, { x = 2, y = 0 }, { x = -1, y = 2 }, { x = 1, y = 2 }, { x = 0, y = 2 } },
[4] = { { x = -1, y = -3 }, { x = 1, y = -3 }, { x = 0, y = -3 }, { x = -3, y = -1 }, { x = -2, y = -2 }, { x = 3, y = -1 }, { x = 2, y = -2 }, { x = -3, y = 0 }, { x = -3, y = 1 }, { x = 3, y = 1 }, { x = 3, y = 0 }, { x = -2, y = 2 }, { x = -1, y = 3 }, { x = 0, y = 3 }, { x = 1, y = 3 }, { x = 2, y = 2 } },
[5] = { { x = -3, y = -3 }, { x = -2, y = -3 }, { x = -1, y = -4 }, { x = -2, y = -4 }, { x = 1, y = -4 }, { x = 0, y = -4 }, { x = 2, y = -3 }, { x = 3, y = -3 }, { x = 2, y = -4 }, { x = -3, y = -2 }, { x = -4, y = -1 }, { x = -4, y = -2 }, { x = 3, y = -2 }, { x = 4, y = -1 }, { x = 4, y = -2 }, { x = -4, y = 1 }, { x = -4, y = 0 }, { x = 4, y = 1 }, { x = 4, y = 0 }, { x = -3, y = 3 }, { x = -3, y = 2 }, { x = -4, y = 2 }, { x = -2, y = 3 }, { x = 2, y = 3 }, { x = 3, y = 3 }, { x = 3, y = 2 }, { x = 4, y = 2 }, { x = -2, y = 4 }, { x = -1, y = 4 }, { x = 0, y = 4 }, { x = 1, y = 4 }, { x = 2, y = 4 } },
[6] = { { x = -1, y = -5 }, { x = -2, y = -5 }, { x = 1, y = -5 }, { x = 0, y = -5 }, { x = 2, y = -5 }, { x = -3, y = -4 }, { x = -4, y = -3 }, { x = 3, y = -4 }, { x = 4, y = -3 }, { x = -5, y = -1 }, { x = -5, y = -2 }, { x = 5, y = -1 }, { x = 5, y = -2 }, { x = -5, y = 1 }, { x = -5, y = 0 }, { x = 5, y = 1 }, { x = 5, y = 0 }, { x = -5, y = 2 }, { x = -4, y = 3 }, { x = 4, y = 3 }, { x = 5, y = 2 }, { x = -3, y = 4 }, { x = -2, y = 5 }, { x = -1, y = 5 }, { x = 0, y = 5 }, { x = 1, y = 5 }, { x = 3, y = 4 }, { x = 2, y = 5 } },
[7] = { { x = -4, y = -5 }, { x = -3, y = -5 }, { x = -2, y = -6 }, { x = -1, y = -6 }, { x = 0, y = -6 }, { x = 1, y = -6 }, { x = 3, y = -5 }, { x = 2, y = -6 }, { x = 4, y = -5 }, { x = -5, y = -4 }, { x = -5, y = -3 }, { x = -4, y = -4 }, { x = 4, y = -4 }, { x = 5, y = -4 }, { x = 5, y = -3 }, { x = -6, y = -1 }, { x = -6, y = -2 }, { x = 6, y = -1 }, { x = 6, y = -2 }, { x = -6, y = 1 }, { x = -6, y = 0 }, { x = 6, y = 1 }, { x = 6, y = 0 }, { x = -5, y = 3 }, { x = -6, y = 2 }, { x = 5, y = 3 }, { x = 6, y = 2 }, { x = -5, y = 4 }, { x = -4, y = 4 }, { x = -4, y = 5 }, { x = -3, y = 5 }, { x = 3, y = 5 }, { x = 4, y = 4 }, { x = 5, y = 4 }, { x = 4, y = 5 }, { x = -1, y = 6 }, { x = -2, y = 6 }, { x = 1, y = 6 }, { x = 0, y = 6 }, { x = 2, y = 6 } },
[8] = { { x = -1, y = -7 }, { x = -2, y = -7 }, { x = 1, y = -7 }, { x = 0, y = -7 }, { x = 2, y = -7 }, { x = -5, y = -5 }, { x = -4, y = -6 }, { x = -3, y = -6 }, { x = 3, y = -6 }, { x = 4, y = -6 }, { x = 5, y = -5 }, { x = -6, y = -3 }, { x = -6, y = -4 }, { x = 6, y = -4 }, { x = 6, y = -3 }, { x = -7, y = -1 }, { x = -7, y = -2 }, { x = 7, y = -1 }, { x = 7, y = -2 }, { x = -7, y = 1 }, { x = -7, y = 0 }, { x = 7, y = 1 }, { x = 7, y = 0 }, { x = -7, y = 2 }, { x = -6, y = 3 }, { x = 6, y = 3 }, { x = 7, y = 2 }, { x = -5, y = 5 }, { x = -6, y = 4 }, { x = 5, y = 5 }, { x = 6, y = 4 }, { x = -3, y = 6 }, { x = -4, y = 6 }, { x = -2, y = 7 }, { x = -1, y = 7 }, { x = 0, y = 7 }, { x = 1, y = 7 }, { x = 3, y = 6 }, { x = 2, y = 7 }, { x = 4, y = 6 } },
[9] = { { x = -4, y = -7 }, { x = -3, y = -7 }, { x = -2, y = -8 }, { x = -1, y = -8 }, { x = 0, y = -8 }, { x = 1, y = -8 }, { x = 3, y = -7 }, { x = 2, y = -8 }, { x = 4, y = -7 }, { x = -5, y = -6 }, { x = -6, y = -6 }, { x = -6, y = -5 }, { x = 5, y = -6 }, { x = 6, y = -5 }, { x = 6, y = -6 }, { x = -7, y = -4 }, { x = -7, y = -3 }, { x = 7, y = -4 }, { x = 7, y = -3 }, { x = -8, y = -2 }, { x = -8, y = -1 }, { x = 8, y = -1 }, { x = 8, y = -2 }, { x = -8, y = 0 }, { x = -8, y = 1 }, { x = 8, y = 1 }, { x = 8, y = 0 }, { x = -7, y = 3 }, { x = -8, y = 2 }, { x = 7, y = 3 }, { x = 8, y = 2 }, { x = -7, y = 4 }, { x = -6, y = 5 }, { x = 6, y = 5 }, { x = 7, y = 4 }, { x = -5, y = 6 }, { x = -6, y = 6 }, { x = -4, y = 7 }, { x = -3, y = 7 }, { x = 3, y = 7 }, { x = 5, y = 6 }, { x = 4, y = 7 }, { x = 6, y = 6 }, { x = -2, y = 8 }, { x = -1, y = 8 }, { x = 0, y = 8 }, { x = 1, y = 8 }, { x = 2, y = 8 } },
[10] = { { x = -3, y = -9 }, { x = -1, y = -9 }, { x = -2, y = -9 }, { x = 1, y = -9 }, { x = 0, y = -9 }, { x = 3, y = -9 }, { x = 2, y = -9 }, { x = -5, y = -7 }, { x = -6, y = -7 }, { x = -5, y = -8 }, { x = -4, y = -8 }, { x = -3, y = -8 }, { x = 3, y = -8 }, { x = 5, y = -7 }, { x = 5, y = -8 }, { x = 4, y = -8 }, { x = 6, y = -7 }, { x = -7, y = -5 }, { x = -7, y = -6 }, { x = -8, y = -5 }, { x = 7, y = -5 }, { x = 7, y = -6 }, { x = 8, y = -5 }, { x = -9, y = -3 }, { x = -8, y = -4 }, { x = -8, y = -3 }, { x = 8, y = -4 }, { x = 8, y = -3 }, { x = 9, y = -3 }, { x = -9, y = -1 }, { x = -9, y = -2 }, { x = 9, y = -1 }, { x = 9, y = -2 }, { x = -9, y = 1 }, { x = -9, y = 0 }, { x = 9, y = 1 }, { x = 9, y = 0 }, { x = -9, y = 3 }, { x = -9, y = 2 }, { x = -8, y = 3 }, { x = 8, y = 3 }, { x = 9, y = 3 }, { x = 9, y = 2 }, { x = -7, y = 5 }, { x = -8, y = 5 }, { x = -8, y = 4 }, { x = 7, y = 5 }, { x = 8, y = 5 }, { x = 8, y = 4 }, { x = -7, y = 6 }, { x = -6, y = 7 }, { x = -5, y = 7 }, { x = 5, y = 7 }, { x = 7, y = 6 }, { x = 6, y = 7 }, { x = -5, y = 8 }, { x = -4, y = 8 }, { x = -3, y = 8 }, { x = -3, y = 9 }, { x = -2, y = 9 }, { x = -1, y = 9 }, { x = 0, y = 9 }, { x = 1, y = 9 }, { x = 3, y = 8 }, { x = 2, y = 9 }, { x = 3, y = 9 }, { x = 5, y = 8 }, { x = 4, y = 8 } },
[11] = { { x = -5, y = -9 }, { x = -4, y = -9 }, { x = -3, y = -10 }, { x = -1, y = -10 }, { x = -2, y = -10 }, { x = 1, y = -10 }, { x = 0, y = -10 }, { x = 3, y = -10 }, { x = 2, y = -10 }, { x = 5, y = -9 }, { x = 4, y = -9 }, { x = -7, y = -7 }, { x = -6, y = -8 }, { x = 7, y = -7 }, { x = 6, y = -8 }, { x = -9, y = -5 }, { x = -8, y = -6 }, { x = 9, y = -5 }, { x = 8, y = -6 }, { x = -9, y = -4 }, { x = -10, y = -3 }, { x = 9, y = -4 }, { x = 10, y = -3 }, { x = -10, y = -2 }, { x = -10, y = -1 }, { x = 10, y = -1 }, { x = 10, y = -2 }, { x = -10, y = 0 }, { x = -10, y = 1 }, { x = 10, y = 1 }, { x = 10, y = 0 }, { x = -10, y = 2 }, { x = -10, y = 3 }, { x = 10, y = 3 }, { x = 10, y = 2 }, { x = -9, y = 4 }, { x = -9, y = 5 }, { x = 9, y = 5 }, { x = 9, y = 4 }, { x = -8, y = 6 }, { x = -7, y = 7 }, { x = 7, y = 7 }, { x = 8, y = 6 }, { x = -6, y = 8 }, { x = -5, y = 9 }, { x = -4, y = 9 }, { x = 4, y = 9 }, { x = 5, y = 9 }, { x = 6, y = 8 }, { x = -3, y = 10 }, { x = -2, y = 10 }, { x = -1, y = 10 }, { x = 0, y = 10 }, { x = 1, y = 10 }, { x = 2, y = 10 }, { x = 3, y = 10 } },
[12] = { { x = -3, y = -11 }, { x = -2, y = -11 }, { x = -1, y = -11 }, { x = 0, y = -11 }, { x = 1, y = -11 }, { x = 2, y = -11 }, { x = 3, y = -11 }, { x = -7, y = -9 }, { x = -6, y = -9 }, { x = -5, y = -10 }, { x = -4, y = -10 }, { x = 5, y = -10 }, { x = 4, y = -10 }, { x = 7, y = -9 }, { x = 6, y = -9 }, { x = -9, y = -7 }, { x = -7, y = -8 }, { x = -8, y = -8 }, { x = -8, y = -7 }, { x = 7, y = -8 }, { x = 8, y = -7 }, { x = 8, y = -8 }, { x = 9, y = -7 }, { x = -9, y = -6 }, { x = -10, y = -5 }, { x = 9, y = -6 }, { x = 10, y = -5 }, { x = -11, y = -3 }, { x = -10, y = -4 }, { x = 10, y = -4 }, { x = 11, y = -3 }, { x = -11, y = -2 }, { x = -11, y = -1 }, { x = 11, y = -1 }, { x = 11, y = -2 }, { x = -11, y = 0 }, { x = -11, y = 1 }, { x = 11, y = 1 }, { x = 11, y = 0 }, { x = -11, y = 2 }, { x = -11, y = 3 }, { x = 11, y = 3 }, { x = 11, y = 2 }, { x = -10, y = 5 }, { x = -10, y = 4 }, { x = 10, y = 5 }, { x = 10, y = 4 }, { x = -9, y = 7 }, { x = -9, y = 6 }, { x = -8, y = 7 }, { x = 8, y = 7 }, { x = 9, y = 7 }, { x = 9, y = 6 }, { x = -8, y = 8 }, { x = -7, y = 8 }, { x = -7, y = 9 }, { x = -6, y = 9 }, { x = 7, y = 8 }, { x = 7, y = 9 }, { x = 6, y = 9 }, { x = 8, y = 8 }, { x = -5, y = 10 }, { x = -4, y = 10 }, { x = -3, y = 11 }, { x = -2, y = 11 }, { x = -1, y = 11 }, { x = 0, y = 11 }, { x = 1, y = 11 }, { x = 2, y = 11 }, { x = 3, y = 11 }, { x = 4, y = 10 }, { x = 5, y = 10 } },
[13] = { { x = -5, y = -11 }, { x = -4, y = -11 }, { x = -3, y = -12 }, { x = -1, y = -12 }, { x = -2, y = -12 }, { x = 1, y = -12 }, { x = 0, y = -12 }, { x = 3, y = -12 }, { x = 2, y = -12 }, { x = 4, y = -11 }, { x = 5, y = -11 }, { x = -8, y = -9 }, { x = -7, y = -10 }, { x = -6, y = -10 }, { x = 6, y = -10 }, { x = 7, y = -10 }, { x = 8, y = -9 }, { x = -10, y = -7 }, { x = -9, y = -8 }, { x = 9, y = -8 }, { x = 10, y = -7 }, { x = -11, y = -5 }, { x = -10, y = -6 }, { x = 10, y = -6 }, { x = 11, y = -5 }, { x = -11, y = -4 }, { x = -12, y = -3 }, { x = 11, y = -4 }, { x = 12, y = -3 }, { x = -12, y = -1 }, { x = -12, y = -2 }, { x = 12, y = -1 }, { x = 12, y = -2 }, { x = -12, y = 1 }, { x = -12, y = 0 }, { x = 12, y = 1 }, { x = 12, y = 0 }, { x = -12, y = 3 }, { x = -12, y = 2 }, { x = 12, y = 3 }, { x = 12, y = 2 }, { x = -11, y = 5 }, { x = -11, y = 4 }, { x = 11, y = 4 }, { x = 11, y = 5 }, { x = -10, y = 7 }, { x = -10, y = 6 }, { x = 10, y = 6 }, { x = 10, y = 7 }, { x = -9, y = 8 }, { x = -8, y = 9 }, { x = 9, y = 8 }, { x = 8, y = 9 }, { x = -7, y = 10 }, { x = -5, y = 11 }, { x = -6, y = 10 }, { x = -4, y = 11 }, { x = 5, y = 11 }, { x = 4, y = 11 }, { x = 7, y = 10 }, { x = 6, y = 10 }, { x = -3, y = 12 }, { x = -2, y = 12 }, { x = -1, y = 12 }, { x = 0, y = 12 }, { x = 1, y = 12 }, { x = 2, y = 12 }, { x = 3, y = 12 } },
[14] = { { x = -3, y = -13 }, { x = -1, y = -13 }, { x = -2, y = -13 }, { x = 1, y = -13 }, { x = 0, y = -13 }, { x = 3, y = -13 }, { x = 2, y = -13 }, { x = -7, y = -11 }, { x = -6, y = -11 }, { x = -5, y = -12 }, { x = -6, y = -12 }, { x = -4, y = -12 }, { x = 5, y = -12 }, { x = 4, y = -12 }, { x = 7, y = -11 }, { x = 6, y = -11 }, { x = 6, y = -12 }, { x = -10, y = -9 }, { x = -9, y = -9 }, { x = -9, y = -10 }, { x = -8, y = -10 }, { x = 9, y = -9 }, { x = 9, y = -10 }, { x = 8, y = -10 }, { x = 10, y = -9 }, { x = -11, y = -7 }, { x = -10, y = -8 }, { x = 11, y = -7 }, { x = 10, y = -8 }, { x = -11, y = -6 }, { x = -12, y = -6 }, { x = -12, y = -5 }, { x = 11, y = -6 }, { x = 12, y = -6 }, { x = 12, y = -5 }, { x = -13, y = -3 }, { x = -12, y = -4 }, { x = 12, y = -4 }, { x = 13, y = -3 }, { x = -13, y = -2 }, { x = -13, y = -1 }, { x = 13, y = -1 }, { x = 13, y = -2 }, { x = -13, y = 0 }, { x = -13, y = 1 }, { x = 13, y = 1 }, { x = 13, y = 0 }, { x = -13, y = 2 }, { x = -13, y = 3 }, { x = 13, y = 3 }, { x = 13, y = 2 }, { x = -12, y = 5 }, { x = -12, y = 4 }, { x = 12, y = 5 }, { x = 12, y = 4 }, { x = -11, y = 6 }, { x = -11, y = 7 }, { x = -12, y = 6 }, { x = 11, y = 7 }, { x = 11, y = 6 }, { x = 12, y = 6 }, { x = -10, y = 8 }, { x = -10, y = 9 }, { x = -9, y = 9 }, { x = 9, y = 9 }, { x = 10, y = 9 }, { x = 10, y = 8 }, { x = -9, y = 10 }, { x = -8, y = 10 }, { x = -7, y = 11 }, { x = -6, y = 11 }, { x = 7, y = 11 }, { x = 6, y = 11 }, { x = 8, y = 10 }, { x = 9, y = 10 }, { x = -6, y = 12 }, { x = -5, y = 12 }, { x = -4, y = 12 }, { x = -3, y = 13 }, { x = -2, y = 13 }, { x = -1, y = 13 }, { x = 0, y = 13 }, { x = 1, y = 13 }, { x = 2, y = 13 }, { x = 3, y = 13 }, { x = 5, y = 12 }, { x = 4, y = 12 }, { x = 6, y = 12 } },
[15] = { { x = -5, y = -13 }, { x = -6, y = -13 }, { x = -4, y = -13 }, { x = -3, y = -14 }, { x = -1, y = -14 }, { x = -2, y = -14 }, { x = 1, y = -14 }, { x = 0, y = -14 }, { x = 3, y = -14 }, { x = 2, y = -14 }, { x = 5, y = -13 }, { x = 4, y = -13 }, { x = 6, y = -13 }, { x = -9, y = -11 }, { x = -8, y = -11 }, { x = -8, y = -12 }, { x = -7, y = -12 }, { x = 7, y = -12 }, { x = 8, y = -12 }, { x = 8, y = -11 }, { x = 9, y = -11 }, { x = -11, y = -9 }, { x = -10, y = -10 }, { x = 10, y = -10 }, { x = 11, y = -9 }, { x = -12, y = -7 }, { x = -11, y = -8 }, { x = -12, y = -8 }, { x = 11, y = -8 }, { x = 12, y = -8 }, { x = 12, y = -7 }, { x = -13, y = -5 }, { x = -13, y = -6 }, { x = 13, y = -5 }, { x = 13, y = -6 }, { x = -13, y = -4 }, { x = -14, y = -3 }, { x = 13, y = -4 }, { x = 14, y = -3 }, { x = -14, y = -2 }, { x = -14, y = -1 }, { x = 14, y = -1 }, { x = 14, y = -2 }, { x = -14, y = 0 }, { x = -14, y = 1 }, { x = 14, y = 1 }, { x = 14, y = 0 }, { x = -14, y = 2 }, { x = -14, y = 3 }, { x = 14, y = 3 }, { x = 14, y = 2 }, { x = -13, y = 4 }, { x = -13, y = 5 }, { x = 13, y = 5 }, { x = 13, y = 4 }, { x = -13, y = 6 }, { x = -12, y = 7 }, { x = 12, y = 7 }, { x = 13, y = 6 }, { x = -11, y = 9 }, { x = -11, y = 8 }, { x = -12, y = 8 }, { x = 11, y = 8 }, { x = 11, y = 9 }, { x = 12, y = 8 }, { x = -9, y = 11 }, { x = -10, y = 10 }, { x = -8, y = 11 }, { x = 9, y = 11 }, { x = 8, y = 11 }, { x = 10, y = 10 }, { x = -7, y = 12 }, { x = -8, y = 12 }, { x = -6, y = 13 }, { x = -5, y = 13 }, { x = -4, y = 13 }, { x = 5, y = 13 }, { x = 4, y = 13 }, { x = 7, y = 12 }, { x = 6, y = 13 }, { x = 8, y = 12 }, { x = -3, y = 14 }, { x = -2, y = 14 }, { x = -1, y = 14 }, { x = 0, y = 14 }, { x = 1, y = 14 }, { x = 2, y = 14 }, { x = 3, y = 14 } },
[16] = { { x = -3, y = -15 }, { x = -1, y = -15 }, { x = -2, y = -15 }, { x = 1, y = -15 }, { x = 0, y = -15 }, { x = 3, y = -15 }, { x = 2, y = -15 }, { x = -7, y = -13 }, { x = -8, y = -13 }, { x = -5, y = -14 }, { x = -6, y = -14 }, { x = -4, y = -14 }, { x = 5, y = -14 }, { x = 4, y = -14 }, { x = 7, y = -13 }, { x = 6, y = -14 }, { x = 8, y = -13 }, { x = -9, y = -12 }, { x = -10, y = -11 }, { x = 9, y = -12 }, { x = 10, y = -11 }, { x = -11, y = -10 }, { x = -12, y = -9 }, { x = 11, y = -10 }, { x = 12, y = -9 }, { x = -13, y = -7 }, { x = -13, y = -8 }, { x = 13, y = -7 }, { x = 13, y = -8 }, { x = -14, y = -6 }, { x = -14, y = -5 }, { x = 14, y = -5 }, { x = 14, y = -6 }, { x = -15, y = -3 }, { x = -14, y = -4 }, { x = 15, y = -3 }, { x = 14, y = -4 }, { x = -15, y = -2 }, { x = -15, y = -1 }, { x = 15, y = -1 }, { x = 15, y = -2 }, { x = -15, y = 0 }, { x = -15, y = 1 }, { x = 15, y = 1 }, { x = 15, y = 0 }, { x = -15, y = 2 }, { x = -15, y = 3 }, { x = 15, y = 3 }, { x = 15, y = 2 }, { x = -14, y = 5 }, { x = -14, y = 4 }, { x = 14, y = 5 }, { x = 14, y = 4 }, { x = -13, y = 7 }, { x = -14, y = 6 }, { x = 13, y = 7 }, { x = 14, y = 6 }, { x = -13, y = 8 }, { x = -12, y = 9 }, { x = 12, y = 9 }, { x = 13, y = 8 }, { x = -11, y = 10 }, { x = -10, y = 11 }, { x = 10, y = 11 }, { x = 11, y = 10 }, { x = -9, y = 12 }, { x = -8, y = 13 }, { x = -7, y = 13 }, { x = 7, y = 13 }, { x = 8, y = 13 }, { x = 9, y = 12 }, { x = -6, y = 14 }, { x = -5, y = 14 }, { x = -4, y = 14 }, { x = -3, y = 15 }, { x = -2, y = 15 }, { x = -1, y = 15 }, { x = 0, y = 15 }, { x = 1, y = 15 }, { x = 2, y = 15 }, { x = 3, y = 15 }, { x = 4, y = 14 }, { x = 5, y = 14 }, { x = 6, y = 14 } }
}
for current_radius = 1, 16, 1 do
ffatable.fluid_explosion_schedule[#ffatable.fluid_explosion_schedule][current_radius] = {}
ffatable.fluid_explosion_schedule[#ffatable.fluid_explosion_schedule][current_radius].trigger_tick = game.tick + (current_radius * 8)
local circle_coords = circle_coordinates[current_radius]
circle_coords = shuffle(circle_coords)
for index, tile_position in pairs(circle_coords) do
local pos = { x = center_position.x + tile_position.x, y = center_position.y + tile_position.y }
ffatable.fluid_explosion_schedule[#ffatable.fluid_explosion_schedule][current_radius][index] = { x = pos.x, y = pos.y }
end
end
entity.die("player")
end
local function on_entity_damaged(event)
local entity = event.entity
if not entity.valid then return end
if not entity.health then return end
if not container_types[entity.type] then return end
if not entity.fluidbox[1] then return end
if not fluid_damages[entity.fluidbox[1].name] then return end
if entity.health > entity.prototype.max_health * 0.75 then return end
if math.random(1, 3) == 1 or entity.health <= 0 then
create_explosion_schedule(entity)
return
end
end
local function on_tick(event)
local ffatable = Table.get_table()
local tick = event.tick
if ffatable.fluid_explosion_schedule then
local explosion_schedule_is_alive = false
for explosion_index = 1, #ffatable.fluid_explosion_schedule, 1 do
if #ffatable.fluid_explosion_schedule[explosion_index] > 0 then
explosion_schedule_is_alive = true
for radius = 1, #ffatable.fluid_explosion_schedule[explosion_index], 1 do
if ffatable.fluid_explosion_schedule[explosion_index][radius].trigger_tick == tick then
for tile_index = 1, #ffatable.fluid_explosion_schedule[explosion_index][radius], 1 do
local continue_explosion = process_explosion_tile(ffatable.fluid_explosion_schedule[explosion_index][radius][tile_index], explosion_index, radius)
if not continue_explosion then
ffatable.fluid_explosion_schedule[explosion_index] = {}
break
end
end
if radius == #ffatable.fluid_explosion_schedule[explosion_index] then ffatable.fluid_explosion_schedule[explosion_index] = {} end
break
end
end
end
end
if not explosion_schedule_is_alive then ffatable.fluid_explosion_schedule = nil end
end
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.fluid_explosion_schedule = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
Event.add(defines.events.on_tick, on_tick)

View File

@ -0,0 +1,125 @@
local Public = {}
local Table = require 'modules.scrap_towny_ffa.table'
local info = [[You are an "outlander" stuck on this god-forsaken planet with a bunch of other desolate fools. You can choose to join
an existing town if accepted, or go at it alone, building your own outpost or living as an "outlander".
The local inhabitants are indifferent to you at first, so long as you don't build or pollute, but become increasingly aggressive
by foreign technology. In fact, they get quite aggressive at the scent of it. If you were to hurt any of the natives you will be
brandished a rogue until your untimely death or until you find better digs.
To create a new town or outpost simply place a furnace down in a suitable spot that is not near any other towns or obstructed.
The world seems to be limited in size with uninhabitable zones on four sides. News towns can only be built within these
borders and you must leave room for the town's size (radius of 27) when placing a new town.
TIP: It's best to find a spot far from existing towns and pollution, as enemies will become aggressive once you form a town.
Once a town is formed, members may invite other players and teams using a raw fish. To invite another player, drop a fish
on that player (with the Z key). To accept an invite, offer a fish in return to the member. To leave a town, simply drop coal
on the market. As a member of a town, your respawn point will change to that of the town.
To form any alliance with another town, drop a fish on a member or their market. If they agree they can reciprocate with a
fish offering.
The town market is the heart of your town. If it is destroyed, your town is destroyed and you will lose all research. So
protect it well, repair it whenever possible, and if you can afford, increase its health by purchasing upgrades. If your
town falls, members will be disbanded, and all buildings will become neutral and lootable.
When building your town, note that you may only build nearby existing structures such as your town market and walls and
any other structure you have placed. Beware that biters and spitters become more aggressive towards towns that are
advanced in research. Their evolution will scale around technology progress in any nearby towns and pollution levels.
This is a FFA ("Free-For-All") world. Short of bullying and derogatory remarks, anything goes. Griefing is encouraged,
so best to setup proper defenses for your town or outpost to fend off enemies when you are there and away.
Have fun and be comfy ^.^]]
function Public.toggle_button(player)
if player.gui.top["towny_map_intro_button"] then return end
local b = player.gui.top.add({ type = "sprite-button", caption = "Towny", name = "towny_map_intro_button", tooltip = "Show Info" })
b.style.font_color = { r = 0.5, g = 0.3, b = 0.99 }
b.style.font = "heading-1"
b.style.minimal_height = 38
b.style.minimal_width = 80
b.style.top_padding = 1
b.style.left_padding = 1
b.style.right_padding = 1
b.style.bottom_padding = 1
end
function Public.show(player)
local ffatable = Table.get_table()
if player.gui.center["towny_map_intro_frame"] then player.gui.center["towny_map_intro_frame"].destroy() end
local frame = player.gui.center.add { type = "frame", name = "towny_map_intro_frame" }
frame = frame.add { type = "frame", direction = "vertical" }
local t = frame.add { type = "table", column_count = 2 }
local label = t.add { type = "label", caption = "Active Factions:" }
label.style.font = "heading-1"
label.style.font_color = { r = 0.85, g = 0.85, b = 0.85 }
label.style.right_padding = 8
t = t.add { type = "table", column_count = 4 }
local label2 = t.add { type = "label", caption = "Outlander" .. "(" .. #game.forces.player.connected_players .. ")" }
label2.style.font_color = { 170, 170, 170 }
label2.style.font = "heading-3"
label2.style.minimal_width = 80
for _, town_center in pairs(ffatable.town_centers) do
local force = town_center.market.force
local label3 = t.add { type = "label", caption = force.name .. "(" .. #force.connected_players .. ")" }
label3.style.font = "heading-3"
label3.style.minimal_width = 80
label3.style.font_color = town_center.color
end
frame.add { type = "line" }
local l = frame.add { type = "label", caption = "Instructions:" }
l.style.font = "heading-1"
l.style.font_color = { r = 0.85, g = 0.85, b = 0.85 }
local l2 = frame.add { type = "label", caption = info }
l2.style.single_line = false
l2.style.font = "heading-2"
l2.style.font_color = { r = 0.8, g = 0.7, b = 0.99 }
end
function Public.close(event)
if not event.element then return end
if not event.element.valid then return end
local parent = event.element.parent
for _ = 1, 4, 1 do
if not parent then return end
if parent.name == "towny_map_intro_frame" then
parent.destroy()
return
end
parent = parent.parent
end
end
function Public.toggle(event)
if not event.element then return end
if not event.element.valid then return end
if event.element.name == "towny_map_intro_button" then
local player = game.players[event.player_index]
if player.gui.center["towny_map_intro_frame"] then
player.gui.center["towny_map_intro_frame"].destroy()
else
Public.show(player)
end
end
end
local function on_gui_click(event)
Public.close(event)
Public.toggle(event)
end
local Event = require 'utils.event'
Event.add(defines.events.on_gui_click, on_gui_click)
return Public

View File

@ -0,0 +1,15 @@
local Public = {}
function Public.reset()
for index = 1, table.size(game.forces), 1 do
local force = game.forces[index]
if force ~= nil then
force.clear_chart("nauvis")
end
end
end
--local Event = require 'utils.event'
--Event.add(defines.events.on_chunk_charted, on_chunk_charted)
return Public

View File

@ -0,0 +1,295 @@
local table_insert = table.insert
local Table = require 'modules.scrap_towny_ffa.table'
local Town_center = require 'modules.scrap_towny_ffa.town_center'
local upgrade_functions = {
-- Upgrade Town Center Health
[1] = function(town_center, player)
local market = town_center.market
local surface = market.surface
if town_center.max_health > 500000 then return end
town_center.health = town_center.health + town_center.max_health
town_center.max_health = town_center.max_health * 2
Town_center.set_market_health(market, 0)
surface.play_sound({ path = "utility/achievement_unlocked", position = player.position, volume_modifier = 1 })
end,
-- Upgrade Backpack
[2] = function(town_center, player)
local market = town_center.market
local force = market.force
local surface = market.surface
if force.character_inventory_slots_bonus > 100 then return end
force.character_inventory_slots_bonus = force.character_inventory_slots_bonus + 5
surface.play_sound({ path = "utility/achievement_unlocked", position = player.position, volume_modifier = 1 })
end,
-- Upgrade Mining Productivity
[3] = function(town_center, player)
local market = town_center.market
local force = market.force
local surface = market.surface
if town_center.upgrades.mining_prod >= 10 then return end
town_center.upgrades.mining_prod = town_center.upgrades.mining_prod + 1
force.mining_drill_productivity_bonus = force.mining_drill_productivity_bonus + 0.1
surface.play_sound({ path = "utility/achievement_unlocked", position = player.position, volume_modifier = 1 })
end,
-- Laser Turret Slot
[4] = function(town_center, player)
local market = town_center.market
local surface = market.surface
town_center.upgrades.laser_turret.slots = town_center.upgrades.laser_turret.slots + 1
surface.play_sound({ path = "utility/new_objective", position = player.position, volume_modifier = 1 })
end,
-- Set Spawn Point
[5] = function(town_center, player)
local ffatable = Table.get_table()
local market = town_center.market
local force = market.force
local surface = market.surface
local spawn_point = force.get_spawn_position(surface)
ffatable.spawn_point[player.name] = spawn_point
surface.play_sound({ path = "utility/scenario_message", position = player.position, volume_modifier = 1 })
end,
}
local function clear_offers(market)
for _ = 1, 256, 1 do
local a = market.remove_market_item(1)
if a == false then return end
end
end
local function set_offers(town_center)
local market = town_center.market
local force = market.force
local special_offers = {}
if town_center.max_health < 500000 then
special_offers[1] = { { { "coin", town_center.max_health * 0.1 } }, "Upgrade Town Center Health" }
else
special_offers[1] = { { { "coin", 1 } }, "Maximum Health upgrades reached!" }
end
if force.character_inventory_slots_bonus <= 100 then
special_offers[2] = { { { "coin", (force.character_inventory_slots_bonus / 5 + 1) * 50 } }, "Upgrade Backpack +5 Slot" }
else
special_offers[2] = { { { "coin", 1 } }, "Maximum Backpack upgrades reached!" }
end
if town_center.upgrades.mining_prod < 10 then
special_offers[3] = { { { "coin", (town_center.upgrades.mining_prod + 1) * 400 } }, "Upgrade Mining Productivity +10%" }
else
special_offers[3] = { { { "coin", 1 } }, "Maximum Mining upgrades reached!" }
end
local laser_turret = "Laser Turret Slot [#" .. tostring(town_center.upgrades.laser_turret.slots + 1) .. "]"
special_offers[4] = { { { "coin", 1000 + (town_center.upgrades.laser_turret.slots * 50) } }, laser_turret }
local spawn_point = "Set Spawn Point"
special_offers[5] = { { { "coin", 1 } }, spawn_point }
local market_items = {}
for _, v in pairs(special_offers) do
table_insert(market_items, { price = v[1], offer = { type = 'nothing', effect_description = v[2] } })
end
-- coin purchases
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'raw-fish', count = 1 } })
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'wood', count = 6 } })
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'iron-ore', count = 6 } })
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'copper-ore', count = 6 } })
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'stone', count = 6 } })
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'coal', count = 6 } })
table_insert(market_items, { price = { { 'coin', 1 } }, offer = { type = 'give-item', item = 'uranium-ore', count = 4 } })
table_insert(market_items, { price = { { 'coin', 300 } }, offer = { type = 'give-item', item = 'loader', count = 1 } })
table_insert(market_items, { price = { { 'coin', 600 } }, offer = { type = 'give-item', item = 'fast-loader', count = 1 } })
table_insert(market_items, { price = { { 'coin', 900 } }, offer = { type = 'give-item', item = 'express-loader', count = 1 } })
-- scrap selling
table_insert(market_items, { price = { { 'wood', 7 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'iron-ore', 7 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'copper-ore', 7 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'stone', 7 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'coal', 7 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'uranium-ore', 5 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'copper-cable', 12 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'iron-gear-wheel', 3 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'iron-stick', 12 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
table_insert(market_items, { price = { { 'empty-barrel', 1 } }, offer = { type = 'give-item', item = 'coin', count = 1 } })
for _, item in pairs(market_items) do
market.add_market_item(item)
end
end
local function refresh_offers(event)
local ffatable = Table.get_table()
local market = event.entity or event.market
if not market then return end
if not market.valid then return end
if market.name ~= "market" then return end
local town_center = ffatable.town_centers[market.force.name]
if not town_center then return end
clear_offers(market)
set_offers(town_center)
end
local function offer_purchased(event)
local ffatable = Table.get_table()
local player = game.players[event.player_index]
local market = event.market
local offer_index = event.offer_index
local count = event.count
if not upgrade_functions[offer_index] then return end
local town_center = ffatable.town_centers[market.force.name]
if not town_center then return end
upgrade_functions[offer_index](town_center, player)
if count > 1 then
local offers = market.get_market_items()
local price = offers[offer_index].price[1].amount
player.insert({ name = "coin", count = price * (count - 1) })
end
end
local function on_gui_opened(event)
local gui_type = event.gui_type
if gui_type ~= defines.gui_type.entity then return end
local entity = event.entity
if entity == nil or not entity.valid then return end
if entity.type == "market" then refresh_offers(event) end
end
local function on_market_item_purchased(event)
offer_purchased(event)
refresh_offers(event)
end
local function inside(pos, area)
return pos.x >= area.left_top.x and pos.x <= area.right_bottom.x and pos.y >= area.left_top.y and pos.y <= area.right_bottom.y
end
local function on_tick(_)
local ffatable = Table.get_table()
if not ffatable.town_centers then return end
local items = { "burner-inserter", "inserter", "long-handed-inserter", "fast-inserter",
"filter-inserter", "stack-inserter", "stack-filter-inserter",
"loader", "fast-loader", "express-loader" }
for _, town_center in pairs(ffatable.town_centers) do
local market = town_center.market
local offers = market.get_market_items()
if offers == nil then set_offers(town_center) end
local s = market.surface
local force = market.force
-- get the bounding box for the market
local bb = market.bounding_box
local area = { left_top = { bb.left_top.x - 2, bb.left_top.y - 2 }, right_bottom = { bb.right_bottom.x + 2, bb.right_bottom.y + 2 } }
local entities = s.find_entities_filtered({ area = area, name = items })
for _, e in pairs(entities) do
if e.name ~= "loader" and e.name ~= "fast-loader" and e.name ~= "express-loader" then
local ppos = e.pickup_position
local dpos = e.drop_position
-- pulling an item from the market
if inside(ppos, bb) and e.drop_target then
local stack = e.held_stack
local spos = e.held_stack_position
if inside(spos, bb) then
local filter
local filter_mode = e.inserter_filter_mode
if filter_mode ~= nil then
for i = 1, e.filter_slot_count do
if e.get_filter(i) ~= nil then
filter = e.get_filter(i)
break
end
end
end
if (filter_mode == "whitelist" and filter == "coin") or (filter_mode == "blacklist" and filter == nil) or (filter_mode == nil) then
if stack.valid and town_center.coin_balance > 0 then
-- pull coins
stack.set_stack({ name = "coin", count = 1 })
town_center.coin_balance = town_center.coin_balance - 1
Town_center.update_coin_balance(force)
end
else
if filter_mode == "whitelist" and filter ~= nil and stack.valid then
-- purchased and pull items if output buffer is empty
-- buffer the output in a item buffer since the stack might be too small
-- output items are shared among the output
for _, trade in ipairs(offers) do
local type = trade.offer.type
local item = trade.offer.item
local count = trade.offer.count or 1
local cost = trade.price[1].amount
if type == "give-item" and item == filter then
if town_center.output_buffer[item] == nil then town_center.output_buffer[item] = 0 end
if town_center.output_buffer[item] == 0 then
-- fill buffer
if town_center.coin_balance >= cost then
town_center.coin_balance = town_center.coin_balance - cost
Town_center.update_coin_balance(force)
town_center.output_buffer[item] = town_center.output_buffer[item] + count
--log("output_buffer[" .. item .. "] = " .. town_center.output_buffer[item])
end
end
if town_center.output_buffer[item] > 0 and not stack.valid_for_read then
-- output the item
local amount = 1
if stack.can_set_stack({ name = item, count = amount }) then
town_center.output_buffer[item] = town_center.output_buffer[item] - amount
stack.set_stack({ name = item, count = amount })
--log("output_buffer[" .. item .. "] = " .. town_center.output_buffer[item])
end
end
break
end
end
end
end
end
end
-- pushing an item to the market (coins or scrap)
if e.pickup_target and inside(dpos, bb) then
local stack = e.held_stack
local spos = e.held_stack_position
if stack.valid_for_read and inside(spos, bb) then
local name = stack.name
local amount = stack.count
if name == "coin" then
-- push coins
e.remove_item(stack)
town_center.coin_balance = town_center.coin_balance + amount
Town_center.update_coin_balance(force)
else
-- push items to turn into coin
for _, trade in ipairs(offers) do
local type = trade.offer.type
local item = trade.price[1].name
local count = trade.price[1].amount
local cost = trade.offer.count
if type == "give-item" and name == item and item ~= "coin" then
e.remove_item(stack)
-- buffer the input in an item buffer that can be sold
if town_center.input_buffer[item] == nil then town_center.input_buffer[item] = 0 end
town_center.input_buffer[item] = town_center.input_buffer[item] + amount
--log("input_buffer[" .. item .. "] = " .. town_center.input_buffer[item])
if town_center.input_buffer[item] >= count then
town_center.input_buffer[item] = town_center.input_buffer[item] - count
town_center.coin_balance = town_center.coin_balance + cost
Town_center.update_coin_balance(force)
--log("input_buffer[" .. item .. "] = " .. town_center.input_buffer[item])
end
end
end
end
end
end
end
end
end
end
local Event = require 'utils.event'
Event.add(defines.events.on_tick, on_tick)
Event.add(defines.events.on_gui_opened, on_gui_opened)
Event.add(defines.events.on_market_item_purchased, on_market_item_purchased)

View File

@ -0,0 +1,98 @@
local Table = require 'modules.scrap_towny_ffa.table'
local crash_site = {
-- simple entity with owner
"crash-site-spaceship-wreck-small-1",
"crash-site-spaceship-wreck-small-2",
"crash-site-spaceship-wreck-small-3",
"crash-site-spaceship-wreck-small-4",
"crash-site-spaceship-wreck-small-5",
"crash-site-spaceship-wreck-small-6",
-- containers
"big-ship-wreck-1",
"big-ship-wreck-2",
"big-ship-wreck-3",
"crash-site-chest-1",
"crash-site-chest-2",
"crash-site-spaceship-wreck-medium-1",
"crash-site-spaceship-wreck-medium-2",
"crash-site-spaceship-wreck-medium-3",
"crash-site-spaceship-wreck-big-1",
"crash-site-spaceship-wreck-big-2",
"crash-site-spaceship"
}
local function is_crash_site(entity)
if not entity.valid then return false end
local f = false
for i = 1, #crash_site, 1 do
if entity.name == crash_site[i] then f = true end
end
return f
end
local function mining_sound(player)
if game.tick % 15 ~= 0 then return end
local target = player.selected
if target == nil or not target.valid then return end
local surface = target.surface
local position = target.position
local path = "entity-mining/" .. target.name
surface.play_sound({path = path, position = position, volume_modifier = 1, override_sound_type = "game-effect" })
end
local function on_tick()
local ffatable = Table.get_table()
for index, player in pairs(game.players) do
if player.character ~= nil then
local mining = player.mining_state.mining
if ffatable.mining[index] ~= mining then
ffatable.mining[index] = mining
-- state change
if mining == true then
--log(player.name .. " started mining")
local target = player.selected
if target ~= nil and target.valid then
--log("target name = " .. target.prototype.name)
--log("position = " .. serpent.block(target.position))
--log("mineable_properties = " .. serpent.block(target.prototype.mineable_properties))
if is_crash_site(target) then
-- mining crash site
mining_sound(player)
ffatable.mining_target[index] = target
end
end
else
--log(player.name .. " stopped mining")
local target = ffatable.mining_target[index]
if target ~= nil then
ffatable.mining_target[index] = nil
end
end
else
if mining == true then
local target = player.selected
if target ~= nil and target.valid then
--local progress = player.character_mining_progress
--log("progress = " .. progress)
if is_crash_site(target) then
-- mining crash site
mining_sound(player)
end
end
end
end
end
end
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.mining = {}
ffatable.mining_entity = {}
ffatable.mining_target = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_tick, on_tick)

View File

@ -0,0 +1,203 @@
local Public = {}
local math_random = math.random
local function create_limbo()
game.create_surface("limbo")
end
local function initialize_nauvis()
local surface = game.surfaces["nauvis"]
-- this overrides what is in the map_gen_settings.json file
local mgs = surface.map_gen_settings
mgs.default_enable_all_autoplace_controls = true -- don't mess with this!
mgs.autoplace_controls = {
coal = { frequency = "none", size = 1, richness = "normal" },
stone = { frequency = "none", size = 1, richness = "normal" },
["copper-ore"] = { frequency = "none", size = 1, richness = "normal" },
["iron-ore"] = { frequency = "none", size = 1, richness = "normal" },
["uranium-ore"] = { frequency = "none", size = 1, richness = "normal" },
["crude-oil"] = { frequency = "none", size = 1, richness = "normal" },
trees = { frequency = 2, size = "normal", richness = "normal" },
["enemy-base"] = { frequency = 8, size = 1, richness = "normal" }
}
mgs.autoplace_settings = {
entity = {
settings = {
["rock-huge"] = { frequency = 3, size = 12, richness = "very-high" },
["rock-big"] = { frequency = 3, size = 12, richness = "very-high" },
["sand-rock-big"] = { frequency = 3, size = 12, richness = 1, "very-high" },
}
},
decorative = {
settings = {
["rock-tiny"] = { frequency = 10, size = "normal", richness = "normal" },
["rock-small"] = { frequency = 5, size = "normal", richness = "normal" },
["rock-medium"] = { frequency = 2, size = "normal", richness = "normal" },
["sand-rock-small"] = { frequency = 10, size = "normal", richness = "normal" },
["sand-rock-medium"] = { frequency = 5, size = "normal", richness = "normal" }
}
}
}
mgs.cliff_settings = {
name = "cliff",
cliff_elevation_0 = 5,
cliff_elevation_interval = 10,
richness = 0.4
}
-- water = 0 means no water allowed
-- water = 1 means elevation is not reduced when calculating water tiles (elevation < 0)
-- water = 2 means elevation is reduced by 10 when calculating water tiles (elevation < 0)
-- or rather, the water table is 10 above the normal elevation
mgs.water = 0.5
mgs.peaceful_mode = false
mgs.starting_area = "none"
mgs.terrain_segmentation = 8
mgs.width = 2048
mgs.height = 2048
--mgs.starting_points = {
-- {x = 0, y = 0}
--}
mgs.research_queue_from_the_start = "always"
-- here we put the named noise expressions for the specific noise-layer if we want to override them
mgs.property_expression_names = {
-- here we are overriding the moisture noise-layer with a fixed value of 0 to keep moisture consistently dry across the map
-- it allows to free up the moisture noise expression
-- low moisture
--moisture = 0,
-- here we are overriding the aux noise-layer with a fixed value to keep aux consistent across the map
-- it allows to free up the aux noise expression
-- aux should be not sand, nor red sand
--aux = 0.5,
-- here we are overriding the temperature noise-layer with a fixed value to keep temperature consistent across the map
-- it allows to free up the temperature noise expression
-- temperature should be 20C or 68F
--temperature = 20,
-- here we are overriding the cliffiness noise-layer with a fixed value of 0 to disable cliffs
-- it allows to free up the cliffiness noise expression (which may or may not be useful)
-- disable cliffs
--cliffiness = 0,
-- we can disable starting lakes two ways, one by setting starting-lake-noise-amplitude = 0
-- or by making the elevation a very large number
-- make sure starting lake amplitude is 0 to disable starting lakes
["starting-lake-noise-amplitude"] = 0,
-- allow enemies to get up close on spawn
["starting-area"] = 0,
-- this accepts a string representing a named noise expression
-- or number to determine the elevation based on x, y and distance from starting points
-- we can not add a named noise expression at this point, we can only reference existing ones
-- if we have any custom noise expressions defined from a mod, we will be able to use them here
-- setting it to a fixed number would mean a flat map
-- elevation < 0 means there is water unless the water table has been changed
--elevation = -1,
--elevation = 0,
--elevation-persistence = 0,
-- testing
--["control-setting:moisture:bias"] = 0.5,
--["control-setting:moisture:frequency:multiplier"] = 0,
--["control-setting:aux:bias"] = 0.5,
--["control-setting:aux:frequency:multiplier"] = 1,
--["control-setting:temperature:bias"] = 0.01,
--["control-setting:temperature:frequency:multiplier"] = 100,
--["tile:water:probability"] = -1000,
--["tile:deep-water:probability"] = -1000,
-- a constant intensity means base distribution will be consistent with regard to distance
["enemy-base-intensity"] = 1,
-- adjust this value to set how many nests spawn per tile
["enemy-base-frequency"] = 0.2,
-- this will make and average base radius around 12 tiles
["enemy-base-radius"] = 12
}
mgs.seed = math_random(10000, 99999)
surface.map_gen_settings = mgs
surface.peaceful_mode = false
surface.always_day = false
surface.freeze_daytime = false
surface.clear(true)
surface.regenerate_entity({ "rock-huge", "rock-big", "sand-rock-big" })
surface.regenerate_decorative()
end
function Public.initialize()
-- difficulty settings
game.difficulty_settings.recipe_difficulty = defines.difficulty_settings.recipe_difficulty.normal
game.difficulty_settings.technology_difficulty = defines.difficulty_settings.technology_difficulty.normal
game.difficulty_settings.technology_price_multiplier = 0.50
-- pollution settings
game.map_settings.pollution.enabled = true
game.map_settings.pollution.diffusion_ratio = 0.02 -- amount that is diffused to neighboring chunk each second
game.map_settings.pollution.min_to_diffuse = 15 -- minimum number of pollution units on the chunk to start diffusing
game.map_settings.pollution.ageing = 1 -- percent of pollution eaten by a chunk's tiles per second
game.map_settings.pollution.expected_max_per_chunk = 150 -- anything greater than this number of pollution units is visualized similarly
game.map_settings.pollution.min_to_show_per_chunk = 50
game.map_settings.pollution.min_pollution_to_damage_trees = 60
game.map_settings.pollution.pollution_with_max_forest_damage = 150
game.map_settings.pollution.pollution_per_tree_damage = 50
game.map_settings.pollution.pollution_restored_per_tree_damage = 10
game.map_settings.pollution.max_pollution_to_restore_trees = 20
game.map_settings.pollution.enemy_attack_pollution_consumption_modifier = 1
-- enemy evolution settings
game.map_settings.enemy_evolution.enabled = true
game.map_settings.enemy_evolution.time_factor = 0.0 -- percent increase in the evolution factor per second
game.map_settings.enemy_evolution.destroy_factor = 0.0 -- percent increase in the evolution factor for each spawner destroyed
game.map_settings.enemy_evolution.pollution_factor = 0.0 -- percent increase in the evolution factor for each pollution unit
-- enemy expansion settings
game.map_settings.enemy_expansion.enabled = true
game.map_settings.enemy_expansion.max_expansion_distance = 7 -- maximum distance in chunks from the nearest base (4 = 128 tiles)
game.map_settings.enemy_expansion.friendly_base_influence_radius = 4 -- consider other nests within radius number of chunks (2 = 64 tiles)
game.map_settings.enemy_expansion.other_base_coefficient = 2.0 -- multiply by coefficient for friendly bases
game.map_settings.enemy_expansion.neighbouring_base_chunk_coefficient = 0.4 -- multiply by coefficient for friendly bases (^distance)
game.map_settings.enemy_expansion.enemy_building_influence_radius = 4 -- consider player buildings within radius number of chunks
game.map_settings.enemy_expansion.building_coefficient = 1.0 -- multiply by coefficient for player buildings
game.map_settings.enemy_expansion.neighbouring_chunk_coefficient = 0.5 -- multiply by coefficient for player buildings (^distance)
game.map_settings.enemy_expansion.max_colliding_tiles_coefficient = 0.9 -- percent of unbuildable tiles to not be considered a candidate
game.map_settings.enemy_expansion.settler_group_min_size = 4 -- min size of group for building a base (multiplied by evo factor, so need evo > 0)
game.map_settings.enemy_expansion.settler_group_max_size = 12 -- max size of group for building a base (multiplied by evo factor, so need evo > 0)
game.map_settings.enemy_expansion.min_expansion_cooldown = 1200 -- minimum time before next expansion
game.map_settings.enemy_expansion.max_expansion_cooldown = 3600 -- maximum time before next expansion
-- unit group settings
game.map_settings.unit_group.min_group_gathering_time = 600
game.map_settings.unit_group.max_group_gathering_time = 3600
game.map_settings.unit_group.max_wait_time_for_late_members = 3600
game.map_settings.unit_group.max_group_radius = 30.0
game.map_settings.unit_group.min_group_radius = 5.0
game.map_settings.unit_group.max_member_speedup_when_behind = 1.4
game.map_settings.unit_group.max_member_slowdown_when_ahead = 0.6
game.map_settings.unit_group.max_group_slowdown_factor = 0.3
game.map_settings.unit_group.max_group_member_fallback_factor = 3
game.map_settings.unit_group.member_disown_distance = 10
game.map_settings.unit_group.tick_tolerance_when_member_arrives = 60
game.map_settings.unit_group.max_gathering_unit_groups = 30
game.map_settings.unit_group.max_unit_group_size = 200
---- steering settings
--game.map_settings.steering.default.radius = 1.2
--game.map_settings.steering.default.separation_force = 0.005
--game.map_settings.steering.default.separation_factor = 1.2
--game.map_settings.steering.default.force_unit_fuzzy_goto_behavior = false
--game.map_settings.steering.moving.radius = 3
--game.map_settings.steering.moving.separation_force = 0.01
--game.map_settings.steering.moving.separation_factor = 3
--game.map_settings.steering.moving.force_unit_fuzzy_goto_behavior = false
create_limbo()
initialize_nauvis()
end
return Public

View File

@ -0,0 +1,19 @@
local Table = require 'modules.scrap_towny_ffa.table'
local function on_tick()
local ffatable = Table.get_table()
if not ffatable.on_tick_schedule[game.tick] then return end
for _, schedule in pairs(ffatable.on_tick_schedule[game.tick]) do
schedule.func(unpack(schedule.args))
end
ffatable.on_tick_schedule[game.tick] = nil
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.on_tick_schedule = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_tick, on_tick)

View File

@ -0,0 +1,99 @@
local Public = {}
local math_random = math.random
local Table = require 'modules.scrap_towny_ffa.table'
local Scrap = require 'modules.scrap_towny_ffa.scrap'
local pollution_index = {
["small-biter"] = { min = 0.1, max = 0.1 },
["medium-biter"] = { min = 0.1, max = 0.2 },
["big-biter"] = { min = 0.1, max = 0.3 },
["behemoth-biter"] = { min = 0.1, max = 0.4 },
["small-spitter"] = { min = 0.1, max = 0.1 },
["medium-spitter"] = { min = 0.1, max = 0.2 },
["big-spitter"] = { min = 0.1, max = 0.3 },
["behemoth-spitter"] = { min = 0.2, max = 0.4 },
["small-worm-turret"] = { min = 0.1, max = 0.1 },
["medium-worm-turret"] = { min = 0.1, max = 0.2 },
["big-worm-turret"] = { min = 0.1, max = 0.3 },
["behemoth-worm-turret"] = { min = 0.2, max = 0.4 },
["biter-spawner"] = { min = 0.5, max = 2.5 },
["spitter-spawner"] = { min = 0.5, max = 2.5 },
["mineable-wreckage"] = { min = 0.1, max = 0.1 },
["small-ship-wreck"] = { min = 0.1, max = 0.1 },
["medium-ship-wreck"] = { min = 0.1, max = 0.1 },
["crash-site-spaceship-wreck-small-1"] = { min = 0.1, max = 0.1 },
["crash-site-spaceship-wreck-small-2"] = { min = 0.1, max = 0.1 },
["crash-site-spaceship-wreck-small-3"] = { min = 0.1, max = 0.1 },
["crash-site-spaceship-wreck-small-4"] = { min = 0.1, max = 0.1 },
["crash-site-spaceship-wreck-small-5"] = { min = 0.1, max = 0.1 },
["crash-site-spaceship-wreck-small-6"] = { min = 0.1, max = 0.1 },
["big-ship-wreck-1"] = { min = 0.2, max = 0.4 },
["big-ship-wreck-2"] = { min = 0.2, max = 0.4 },
["big-ship-wreck-3"] = { min = 0.2, max = 0.4 },
["crash-site-chest-1"] = { min = 0.1, max = 0.2 },
["crash-site-chest-2"] = { min = 0.1, max = 0.2 },
["crash-site-spaceship-wreck-medium-1"] = { min = 0.1, max = 0.2 },
["crash-site-spaceship-wreck-medium-2"] = { min = 0.1, max = 0.2 },
["crash-site-spaceship-wreck-medium-3"] = { min = 0.1, max = 0.2 },
["crash-site-spaceship-wreck-big-1"] = { min = 0.2, max = 0.4 },
["crash-site-spaceship-wreck-big-2"] = { min = 0.2, max = 0.4 },
["crash-site-spaceship"] = { min = 0.5, max = 2.5 },
["explosion"] = { min = 0.1, max = 0.1 },
["big-explosion"] = { min = 0.2, max = 0.2 },
["big-artillery-explosion"] = { min = 0.5, max = 0.5 },
["market"] = { min = 10, max = 50 },
}
function Public.market_scent()
local ffatable = Table.get_table()
local town_centers = ffatable.town_centers
if town_centers == nil then return end
for _, town_center in pairs(town_centers) do
local market = town_center.market
local pollution = pollution_index["market"]
local amount = math_random(pollution.min, pollution.max)
market.surface.pollute(market.position, amount)
end
end
function Public.explosion(position, surface, animation)
local pollution = pollution_index[animation]
if pollution == nil then return end
local amount = math_random(pollution.min, pollution.max)
surface.pollute(position, amount)
end
local function on_player_mined_entity(event)
local entity = event.entity
if Scrap.is_scrap(entity) == true then
local pollution = pollution_index[entity.name]
local amount = math_random(pollution.min, pollution.max)
entity.surface.pollute(entity.position, amount)
end
end
local function on_entity_damaged(event)
local entity = event.entity
if not entity.valid then return end
local pollution = pollution_index[entity.name]
if pollution == nil then return end
local amount = math_random(pollution.min, pollution.max)
entity.surface.pollute(entity.position, amount)
end
local function on_entity_died(event)
local entity = event.entity
if not entity.valid then return end
local pollution = pollution_index[entity.name]
if pollution == nil then return end
local amount = math_random(pollution.min, pollution.max) * 10
entity.surface.pollute(entity.position, amount)
end
local Event = require 'utils.event'
Event.add(defines.events.on_player_mined_entity, on_player_mined_entity)
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
Event.add(defines.events.on_entity_died, on_entity_died)
return Public

View File

@ -0,0 +1,173 @@
local math_random = math.random
local math_floor = math.floor
local table_insert = table.insert
local table_shuffle = table.shuffle_table
local Table = require 'modules.scrap_towny_ffa.table'
local Evolution = require "modules.scrap_towny_ffa.evolution"
local valid_entities = {
["rock-big"] = true,
["rock-huge"] = true,
["sand-rock-big"] = true
}
local size_raffle = {
{ "giant", 128, 256 },
{ "huge", 64, 128 },
{ "big", 32, 64 },
{ "small", 16, 32 },
{ "tiny", 8, 16 },
}
local function get_chances()
local chances = {}
table_insert(chances, { "iron-ore", 25 })
table_insert(chances, { "copper-ore", 18 })
table_insert(chances, { "mixed", 15 })
table_insert(chances, { "coal", 14 })
table_insert(chances, { "stone", 8 })
table_insert(chances, { "uranium-ore", 3 })
return chances
end
local function set_raffle()
local ffatable = Table.get_table()
ffatable.rocks_yield_ore_veins.raffle = {}
for _, t in pairs(get_chances()) do
for _ = 1, t[2], 1 do
table_insert(ffatable.rocks_yield_ore_veins.raffle, t[1])
end
end
ffatable.rocks_yield_ore_veins.mixed_ores = { "iron-ore", "copper-ore", "stone", "coal" }
end
local function get_amount(position)
local base = 256
local relative_evolution = Evolution.get_evolution(position)
local tier = 4 + math_floor(relative_evolution * 16)
return (math_random(1, base) + math_random(1, 2 ^ tier))
end
local function draw_chain(surface, count, ore, ore_entities, ore_positions)
local ffatable = Table.get_table()
local vectors = { { 0, -1 }, { -1, 0 }, { 1, 0 }, { 0, 1 } }
local r = math_random(1, #ore_entities)
local position = { x = ore_entities[r].position.x, y = ore_entities[r].position.y }
for _ = 1, count, 1 do
table_shuffle(vectors)
for i = 1, 4, 1 do
local p = { x = position.x + vectors[i][1], y = position.y + vectors[i][2] }
local name = ore
if ore == "mixed" then name = ffatable.rocks_yield_ore_veins.mixed_ores[math_random(1, #ffatable.rocks_yield_ore_veins.mixed_ores)] end
if surface.can_place_entity({ name = name, position = p, amount = 1 }) then
if not ore_positions[p.x .. "_" .. p.y] then
position.x = p.x
position.y = p.y
ore_positions[p.x .. "_" .. p.y] = true
ore_entities[#ore_entities + 1] = { name = name, position = p, amount = get_amount(p) }
break
end
else
if surface.can_fast_replace({ name = name, position = p }) then
if math_random(1, 2) == 1 then
if not ore_positions[p.x .. "_" .. p.y] then
position.x = p.x
position.y = p.y
ore_positions[p.x .. "_" .. p.y] = true
ore_entities[#ore_entities + 1] = { name = name, position = p, amount = get_amount(p), fast_replace = true }
break
end
end
end
end
end
end
end
local function ore_vein(event)
local ffatable = Table.get_table()
local surface = event.entity.surface
local size = size_raffle[math_random(1, #size_raffle)]
local ore = ffatable.rocks_yield_ore_veins.raffle[math_random(1, #ffatable.rocks_yield_ore_veins.raffle)]
local icon
if game.entity_prototypes[ore] then
icon = "[img=entity/" .. ore .. "]"
else
icon = " "
end
local player = game.players[event.player_index]
for _, p in pairs(game.connected_players) do
if p.index == player.index then
p.print(
{ "rocks_yield_ore_veins.player_print",
{ "rocks_yield_ore_veins_colors." .. ore },
{ "rocks_yield_ore_veins." .. size[1] },
{ "rocks_yield_ore_veins." .. ore },
icon
},
{ r = 0.80, g = 0.80, b = 0.80 }
)
else
if p.force == player.force then
game.print(
{ "rocks_yield_ore_veins.game_print",
"[color=" .. player.chat_color.r .. "," .. player.chat_color.g .. "," .. player.chat_color.b .. "]" .. player.name .. "[/color]",
{ "rocks_yield_ore_veins." .. size[1] },
{ "rocks_yield_ore_veins." .. ore },
icon
},
{ r = 0.80, g = 0.80, b = 0.80 }
)
end
end
end
local position = event.entity.position
local ore_entities = { { name = ore, position = { x = position.x, y = position.y }, amount = get_amount(position) } }
if ore == "mixed" then
ore_entities = { { name = ffatable.rocks_yield_ore_veins.mixed_ores[math_random(1, #ffatable.rocks_yield_ore_veins.mixed_ores)], position = { x = position.x, y = position.y }, amount = get_amount(position) } }
end
local ore_positions = { [event.entity.position.x .. "_" .. event.entity.position.y] = true }
local count = math_random(size[2], size[3])
for _ = 1, 128, 1 do
local c = math_random(math_floor(size[2] * 0.25) + 1, size[2])
if count < c then c = count end
local placed_ore_count = #ore_entities
draw_chain(surface, c, ore, ore_entities, ore_positions)
count = count - (#ore_entities - placed_ore_count)
if count <= 0 then break end
end
for _, e in pairs(ore_entities) do
surface.create_entity(e)
end
end
local function on_player_mined_entity(event)
local ffatable = Table.get_table()
if not event.entity.valid then return end
if not valid_entities[event.entity.name] then return end
if math_random(1, ffatable.rocks_yield_ore_veins.chance) ~= 1 then return end
ore_vein(event)
end
local function on_init()
local ffatable = Table.get_table()
ffatable.rocks_yield_ore_veins = {}
ffatable.rocks_yield_ore_veins.raffle = {}
ffatable.rocks_yield_ore_veins.mixed_ores = {}
ffatable.rocks_yield_ore_veins.chance = 4
set_raffle()
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_player_mined_entity, on_player_mined_entity)

View File

@ -0,0 +1,36 @@
local Public = {}
local scrapable = {
-- simple entity
"small-ship-wreck",
"medium-ship-wreck",
-- simple entity with owner
"crash-site-spaceship-wreck-small-1",
"crash-site-spaceship-wreck-small-2",
"crash-site-spaceship-wreck-small-3",
"crash-site-spaceship-wreck-small-4",
"crash-site-spaceship-wreck-small-5",
"crash-site-spaceship-wreck-small-6",
"big-ship-wreck-1",
"big-ship-wreck-2",
"big-ship-wreck-3",
"crash-site-chest-1",
"crash-site-chest-2",
"crash-site-spaceship-wreck-medium-1",
"crash-site-spaceship-wreck-medium-2",
"crash-site-spaceship-wreck-medium-3",
"crash-site-spaceship-wreck-big-1",
"crash-site-spaceship-wreck-big-2",
"crash-site-spaceship"
}
function Public.is_scrap(entity)
if not entity.valid then return false end
local f = false
for i = 1, #scrapable, 1 do
if entity.name == scrapable[i] then f = true end
end
return f
end
return Public

View File

@ -0,0 +1,103 @@
local table_size = table.size
local Table = require 'modules.scrap_towny_ffa.table'
-- called whenever a player places an item
local function on_built_entity(event)
local ffatable = Table.get_table()
local entity = event.created_entity
if not entity.valid then return end
if entity.name ~= "laser-turret" then return end
local player = game.players[event.player_index]
local force = player.force
local town_center = ffatable.town_centers[force.name]
local surface = entity.surface
if force == game.forces["player"] or force == game.forces["rogue"] or town_center == nil then
surface.create_entity({
name = "flying-text",
position = entity.position,
text = "You are not acclimated to this technology!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
player.insert({ name = "laser-turret", count = 1 })
entity.destroy()
return
end
local slots = town_center.upgrades.laser_turret.slots
local locations = town_center.upgrades.laser_turret.locations
if table_size(locations) >= slots then
surface.create_entity({
name = "flying-text",
position = entity.position,
text = "You do not have enough slots!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
player.insert({ name = "laser-turret", count = 1 })
entity.destroy()
return
end
local position = entity.position
local key = tostring("{" .. position.x .. "," .. position.y .. "}")
locations[key] = true
end
-- called whenever a player places an item
local function on_robot_built_entity(event)
local ffatable = Table.get_table()
local entity = event.created_entity
if not entity.valid then return end
if entity.name ~= "laser-turret" then return end
local robot = event.robot
local force = robot.force
local town_center = ffatable.town_centers[force.name]
local surface = entity.surface
if force == game.forces["player"] or force == game.forces["rogue"] or town_center == nil then
surface.create_entity({
name = "flying-text",
position = entity.position,
text = "Robot not acclimated to this technology!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
robot.insert({ name = "laser-turret", count = 1 })
entity.destroy()
return
end
local slots = town_center.upgrades.laser_turret.slots
local locations = town_center.upgrades.laser_turret.locations
if table_size(locations) >= slots then
surface.create_entity({
name = "flying-text",
position = entity.position,
text = "Town does not have enough slots!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
robot.insert({ name = "laser-turret", count = 1 })
entity.destroy()
return
end
local position = entity.position
local key = tostring("{" .. position.x .. "," .. position.y .. "}")
locations[key] = true
end
-- called whenever a player mines an entity but before it is removed from the map
-- will have the contents of the drops
local function on_player_mined_entity(event)
local ffatable = Table.get_table()
local player = game.players[event.player_index]
local force = player.force
local entity = event.entity
if entity.name == "laser-turret" then
local town_center = ffatable.town_centers[force.name]
if force == game.forces["player"] or force == game.forces["rogue"] or town_center == nil then return end
local locations = town_center.upgrades.laser_turret.locations
local position = entity.position
local key = tostring("{" .. position.x .. "," .. position.y .. "}")
locations[key] = nil
end
end
local Event = require 'utils.event'
Event.add(defines.events.on_built_entity, on_built_entity)
Event.add(defines.events.on_robot_built_entity, on_robot_built_entity)
Event.add(defines.events.on_player_mined_entity, on_player_mined_entity)

View File

@ -0,0 +1,183 @@
local Public = {}
local table_size = table.size
local table_insert = table.insert
local math_random = math.random
local math_rad = math.rad
local math_sin = math.sin
local math_cos = math.cos
local math_floor = math.floor
local Table = require 'modules.scrap_towny_ffa.table'
local Enemy = require "modules.scrap_towny_ffa.enemy"
local Building = require "modules.scrap_towny_ffa.building"
-- don't spawn if town is within this range
local spawn_point_town_buffer = 256
-- clear enemies within this distance from spawn
local spawn_point_safety = 16
-- incremental spawn distance from existing town
-- this is how much each attempt is incremented by for checking a pollution free area
local spawn_point_incremental_distance = 16
local function force_load(position, surface, radius)
--log("is_chunk_generated = " .. tostring(surface.is_chunk_generated(position)))
surface.request_to_generate_chunks(position, radius)
--log("force load position = {" .. position.x .. "," .. position.y .. "}")
surface.force_generate_chunk_requests()
end
-- gets an area (might not be even amount)
local function get_area(position, w, h)
local x1 = math_floor(w / 2)
local x2 = w - x1
local y1 = math_floor(h / 2)
local y2 = h - y1
return { { position.x - x1, position.y - y1 }, { position.x + x2, position.y + y2 } }
end
local function clear_spawn(position, surface, w, h)
--log("clear_spawn {" .. position.x .. "," .. position.y .. "}")
local area = get_area(position, w, h)
for _, e in pairs(surface.find_entities_filtered({ area = area })) do
if e.type ~= "character" then
e.destroy()
end
end
end
-- does the position have any pollution
local function has_pollution(position, surface)
local result = surface.get_pollution(position) > 0.0
--log("has_pollution = " .. tostring(result))
return result
end
-- is the position already used
local function in_use(position)
local ffatable = Table.get_table()
local result = false
for _, v in pairs(ffatable.spawn_point) do
if v == position then result = true end
end
--log("in_use = " .. tostring(result))
return result
end
-- is the position empty
local function is_empty(position, surface)
local entity_radius = 1
local tile_radius = 1
local entities = surface.count_entities_filtered({ position = position, radius = entity_radius, collision_mask = { "object-layer", "player-layer" } })
--log("entities = " .. entities)
if entities > 0 then return false end
local tiles = surface.count_tiles_filtered({ position = position, radius = tile_radius, collision_mask = "water-tile" })
--log("water-tiles = " .. tiles)
if tiles > 0 then return false end
local result = surface.can_place_entity({ name = "character", position = position })
--log("is_empty = " .. tostring(result))
return result
end
-- finds a valid spawn point that is not near a town and not in a polluted area
local function find_valid_spawn_point(surface)
local ffatable = Table.get_table()
-- check center of map first if valid
local position = { x = 0, y = 0 }
--log("testing {" .. position.x .. "," .. position.y .. "}")
force_load(position, surface, 1)
if in_use(position) == false then
if Building.near_town(position, surface, spawn_point_town_buffer) == false then
-- force load the position
if is_empty(position, surface) == true then
--log("found valid spawn point at {" .. position.x .. "," .. position.y .. "}")
return position
end
end
end
-- otherwise find a nearby town
local keyset = {}
for town_name, _ in pairs(ffatable.town_centers) do
table_insert(keyset, town_name)
end
local count = table_size(keyset)
if count > 0 then
local town_name = keyset[math_random(1, count)]
local town_center = ffatable.town_centers[town_name]
if town_center ~= nil then
position = town_center.market.position
end
--log("town center is {" .. position.x .. "," .. position.y .. "}")
end
-- and start checking around it for a suitable spawn position
local tries = 0
local radius = spawn_point_town_buffer
local angle
while (tries < 100) do
-- 8 attempts each position
for _ = 1, 8 do
-- position on the circle radius
angle = math_random(0, 360)
local t = math_rad(angle)
local x = math_floor(position.x + math_cos(t) * radius)
local y = math_floor(position.y + math_sin(t) * radius)
local target = { x = x, y = y }
--log("testing {" .. target.x .. "," .. target.y .. "}")
force_load(position, surface, 1)
if in_use(target) == false then
if has_pollution(target, surface) == false then
if Building.near_town(target, surface, spawn_point_town_buffer) == false then
if is_empty(target, surface) == true then
--log("found valid spawn point at {" .. target.x .. "," .. target.y .. "}")
position = target
return position
end
end
end
end
end
-- near a town, increment the radius and select another angle
radius = radius + math_random(1, spawn_point_incremental_distance)
angle = math_random(0, 360)
tries = tries + 1
end
return { x = 0, y = 0 }
end
function Public.get_new_spawn_point(player, surface)
local ffatable = Table.get_table()
-- get a new spawn point
local position = find_valid_spawn_point(surface)
-- should never be invalid or blocked
ffatable.spawn_point[player.name] = position
--log("player " .. player.name .. " assigned new spawn point at {" .. position.x .. "," .. position.y .. "}")
return position
end
-- gets a new or existing spawn point for the player
function Public.get_spawn_point(player, surface)
local ffatable = Table.get_table()
if ffatable.spawn_point == nil then ffatable.spawn_point = {} end
-- test the existing spawn point
local position = ffatable.spawn_point[player.name]
if position ~= nil then
-- check that the spawn point is not blocked
if surface.can_place_entity({ name = "character", position = position }) then
--log("player " .. player.name .. "using existing spawn point at {" .. position.x .. "," .. position.y .. "}")
return position
else
position = surface.find_non_colliding_position("character", position, 16, 0.25)
if (position ~= nil) then return position end
end
end
-- otherwise get a new spawn point
return Public.get_new_spawn_point(player, surface)
end
function Public.clear_spawn_point(position, surface)
Enemy.clear_worms(position, surface, spawn_point_safety) -- behemoth worms can attack from a range of 48, clear first time only
Enemy.clear_enemies(position, surface, spawn_point_safety) -- behemoth worms can attack from a range of 48
clear_spawn(position, surface, 7, 9)
end
return Public

View File

@ -0,0 +1,33 @@
-- spawners release biters on death -- by mewmew
local math_random = math.random
local Evolution = require "modules.scrap_towny_ffa.evolution"
local biter_building_inhabitants = {
[1] = { { "small-biter", 8, 16 } },
[2] = { { "small-biter", 12, 24 } },
[3] = { { "small-biter", 8, 16 }, { "medium-biter", 1, 2 } },
[4] = { { "small-biter", 4, 8 }, { "medium-biter", 4, 8 } },
[5] = { { "small-biter", 3, 5 }, { "medium-biter", 8, 12 } },
[6] = { { "small-biter", 3, 5 }, { "medium-biter", 5, 7 }, { "big-biter", 1, 2 } },
[7] = { { "medium-biter", 6, 8 }, { "big-biter", 3, 5 } },
[8] = { { "medium-biter", 2, 4 }, { "big-biter", 6, 8 } },
[9] = { { "medium-biter", 2, 3 }, { "big-biter", 7, 9 } },
[10] = { { "big-biter", 4, 8 }, { "behemoth-biter", 3, 4 } }
}
local function on_entity_died(event)
if not event.entity.valid then return end
if event.entity.type ~= "unit-spawner" then return end
local e = math.ceil(Evolution.get_biter_evolution(event.entity) * 10)
if e < 1 then e = 1 end
for _, t in pairs(biter_building_inhabitants[e]) do
for _ = 1, math_random(t[2], t[3]), 1 do
local p = event.entity.surface.find_non_colliding_position(t[1], event.entity.position, 6, 1)
if p then event.entity.surface.create_entity { name = t[1], position = p, force = event.entity.force.name } end
end
end
end
local Event = require 'utils.event'
Event.add(defines.events.on_entity_died, on_entity_died)

View File

@ -0,0 +1,30 @@
local Public = {}
-- one table to rule them all!
local Global = require 'utils.global'
local ffatable = {}
Global.register(
ffatable,
function(tbl)
ffatable = tbl
end
)
function Public.reset_table()
for k, _ in pairs(ffatable) do
ffatable[k] = nil
end
end
function Public.get_table()
return ffatable
end
local on_init = function ()
Public.reset_table()
end
local Event = require 'utils.event'
Event.on_init(on_init)
return Public

View File

@ -0,0 +1,681 @@
local Public = {}
local table_size = table.size
local string_match = string.match
local string_lower = string.lower
local Table = require 'modules.scrap_towny_ffa.table'
local outlander_color = { 150, 150, 150 }
local outlander_chat_color = { 170, 170, 170 }
local rogue_color = { 150, 150, 150 }
local rogue_chat_color = { 170, 170, 170 }
local item_drop_radius = 1.65
local function can_force_accept_member(force)
local ffatable = Table.get_table()
local town_centers = ffatable.town_centers
local size_of_town_centers = ffatable.size_of_town_centers
local member_limit = 0
if size_of_town_centers <= 1 then return true end
for _, town in pairs(town_centers) do
member_limit = member_limit + table_size(town.market.force.connected_players)
end
member_limit = math.floor(member_limit / size_of_town_centers) + 4
if #force.connected_players >= member_limit then
game.print(">> Town " .. force.name .. " has too many settlers! Current limit (" .. member_limit .. ")", { 255, 255, 0 })
return
end
return true
end
local function is_towny(force)
if force == game.forces["player"] or force == game.forces["rogue"] then return false end
return true
end
function Public.has_key(player)
local ffatable = Table.get_table()
if player == nil then return false end
return ffatable.key[player]
end
function Public.give_key(player)
local ffatable = Table.get_table()
if player == nil then return end
ffatable.key[player] = true
end
function Public.remove_key(player)
local ffatable = Table.get_table()
if player == nil then return end
ffatable.key[player] = false
end
function Public.set_player_color(player)
local ffatable = Table.get_table()
if player.force == game.forces["player"] then
player.color = outlander_color
player.chat_color = outlander_chat_color
return
end
if player.force == game.forces["rogue"] then
player.color = rogue_color
player.chat_color = rogue_chat_color
return
end
local town_center = ffatable.town_centers[player.force.name]
if not town_center then return end
player.color = town_center.color
player.chat_color = town_center.color
end
local function set_town_color(event)
local ffatable = Table.get_table()
if event.command ~= "color" then return end
local player = game.players[event.player_index]
local force = player.force
local town_center = ffatable.town_centers[force.name]
if not town_center then
Public.set_player_color(player)
return
end
town_center.color = { player.color.r, player.color.g, player.color.b }
rendering.set_color(town_center.town_caption, town_center.color)
for _, p in pairs(force.players) do
Public.set_player_color(p)
end
end
function Public.set_all_player_colors()
for _, p in pairs(game.connected_players) do
Public.set_player_color(p)
end
end
function Public.add_player_to_town(player, town_center)
local ffatable = Table.get_table()
local market = town_center.market
local force = market.force
local surface = market.surface
player.force = market.force
Public.remove_key(player)
ffatable.spawn_point[player.name] = force.get_spawn_position(surface)
game.permissions.get_group(force.name).add_player(player)
player.tag = ""
Public.set_player_color(player)
end
function Public.give_outlander_items(player)
player.insert({ name = "stone-furnace", count = 1 })
player.insert({ name = "raw-fish", count = 3 })
player.insert({ name = "coal", count = 3 })
end
function Public.set_player_to_outlander(player)
local ffatable = Table.get_table()
player.force = game.forces.player
if ffatable.spawn_point[player.name] then
ffatable.spawn_point[player.name] = nil
end
if game.permissions.get_group("outlander") == nil then game.permissions.create_group("outlander") end
game.permissions.get_group("outlander").add_player(player)
player.tag = "[Outlander]"
Public.set_player_color(player)
Public.give_key(player)
end
local function set_player_to_rogue(player)
local ffatable = Table.get_table()
player.force = game.forces["rogue"]
if ffatable.spawn_point[player.name] then
ffatable.spawn_point[player.name] = nil
end
if game.permissions.get_group("rogue") == nil then game.permissions.create_group("rogue") end
game.permissions.get_group("rogue").add_player(player)
player.tag = "[Rogue]"
Public.set_player_color(player)
end
local function ally_outlander(player, target)
local ffatable = Table.get_table()
local requesting_force = player.force
local target_force = target.force
-- don't handle request if target is not a town
if not is_towny(requesting_force) and not is_towny(target_force) then return false end
-- don't handle request to another town if already in a town
if is_towny(requesting_force) and is_towny(target_force) then return false end
-- handle the request
if not is_towny(requesting_force) and is_towny(target_force) then
ffatable.requests[player.index] = target_force.name
local target_player = false
if target.type == "character" then
target_player = target.player
else
target_player = game.players[target_force.name]
end
if target_player then
if ffatable.requests[target_player.index] then
if ffatable.requests[target_player.index] == player.name then
if ffatable.town_centers[target_force.name] then
if not can_force_accept_member(target_force) then return true end
game.print(">> " .. player.name .. " has settled in " .. target_force.name .. "'s Town!", { 255, 255, 0 })
Public.add_player_to_town(player, ffatable.town_centers[target_force.name])
return true
end
end
end
end
game.print(">> " .. player.name .. " wants to settle in " .. target_force.name .. " Town!", { 255, 255, 0 })
return true
end
-- handle the approval
if is_towny(requesting_force) and not is_towny(target_force) then
if target.type ~= "character" then return true end
local target_player = target.player
if not target_player then return true end
ffatable.requests[player.index] = target_player.name
if ffatable.requests[target_player.index] then
if ffatable.requests[target_player.index] == player.force.name then
if not can_force_accept_member(player.force) then return true end
if player.force.name == player.name then
game.print(">> " .. player.name .. " has accepted " .. target_player.name .. " into their Town!", { 255, 255, 0 })
else
game.print(">> " .. player.name .. " has accepted " .. target_player.name .. " into" .. player.force.name .. "'s Town!", { 255, 255, 0 })
end
Public.add_player_to_town(target_player, ffatable.town_centers[player.force.name])
return true
end
end
if player.force.name == player.name then
game.print(">> " .. player.name .. " is inviting " .. target_player.name .. " into their Town!", { 255, 255, 0 })
else
game.print(">> " .. player.name .. " is inviting " .. target_player.name .. " into " .. player.force.name .. "'s Town!", { 255, 255, 0 })
end
return true
end
end
local function ally_neighbour_towns(player, target)
local requesting_force = player.force
local target_force = target.force
if target_force.get_friend(requesting_force) and requesting_force.get_friend(target_force) then return end
requesting_force.set_friend(target_force, true)
game.print(">> Town " .. requesting_force.name .. " has set " .. target_force.name .. " as their friend!", { 255, 255, 0 })
if target_force.get_friend(requesting_force) then
game.print(">> The towns " .. requesting_force.name .. " and " .. target_force.name .. " have formed an alliance!", { 255, 255, 0 })
end
end
local function ally_town(player, item)
local position = item.position
local surface = player.surface
local area = { { position.x - item_drop_radius, position.y - item_drop_radius }, { position.x + item_drop_radius, position.y + item_drop_radius } }
local requesting_force = player.force
local target = false
for _, e in pairs(surface.find_entities_filtered({ type = { "character", "market" }, area = area })) do
if e.force.name ~= requesting_force.name then
target = e
break
end
end
if not target then return end
if target.force == game.forces["enemy"] or target.force == game.forces["neutral"] then return end
if ally_outlander(player, target) then return end
ally_neighbour_towns(player, target)
end
local function declare_war(player, item)
local ffatable = Table.get_table()
local position = item.position
local surface = player.surface
local area = { { position.x - item_drop_radius, position.y - item_drop_radius }, { position.x + item_drop_radius, position.y + item_drop_radius } }
local requesting_force = player.force
local target = surface.find_entities_filtered({ type = { "character", "market" }, area = area })[1]
if not target then return end
local target_force = target.force
if not is_towny(target_force) then return end
if requesting_force.name == target_force.name then
if player.name ~= target.force.name then
Public.set_player_to_outlander(player)
game.print(">> " .. player.name .. " has abandoned " .. target_force.name .. "'s Town!", { 255, 255, 0 })
ffatable.requests[player.index] = nil
end
if player.name == target.force.name then
if target.type ~= "character" then return end
local target_player = target.player
if not target_player then return end
if target_player.index == player.index then return end
Public.set_player_to_outlander(target_player)
game.print(">> " .. player.name .. " has banished " .. target_player.name .. " from their Town!", { 255, 255, 0 })
ffatable.requests[player.index] = nil
end
return
end
if not is_towny(requesting_force) then return end
requesting_force.set_friend(target_force, false)
target_force.set_friend(requesting_force, false)
game.print(">> " .. player.name .. " has dropped the coal! Town " .. target_force.name .. " and " .. requesting_force.name .. " are now at war!", { 255, 255, 0 })
end
local function delete_chart_tag_for_all_forces(market)
local forces = game.forces
local position = market.position
local surface = market.surface
for _, force in pairs(forces) do
local tags = force.find_chart_tags(surface, { { position.x - 0.1, position.y - 0.1 }, { position.x + 0.1, position.y + 0.1 } })
local tag = tags[1]
if tag then
if tag.icon.name == "stone-furnace" then
tag.destroy()
end
end
end
end
function Public.add_chart_tag(force, market)
local position = market.position
local tags = force.find_chart_tags(market.surface, { { position.x - 0.1, position.y - 0.1 }, { position.x + 0.1, position.y + 0.1 } })
if tags[1] then return end
force.add_chart_tag(market.surface, { icon = { type = 'item', name = 'stone-furnace' }, position = position, text = market.force.name .. "'s Town" })
end
function Public.update_town_chart_tags()
local ffatable = Table.get_table()
local town_centers = ffatable.town_centers
local forces = game.forces
for _, town_center in pairs(town_centers) do
local market = town_center.market
for _, force in pairs(forces) do
if force.is_chunk_visible(market.surface, town_center.chunk_position) then
Public.add_chart_tag(force, market)
end
end
end
if game.forces["player"] ~= nil then game.forces["player"].clear_chart(game.surfaces["nauvis"]) end
if game.forces["rogue"] ~= nil then game.forces["rogue"].clear_chart(game.surfaces["nauvis"]) end
end
local function reset_permissions(permission_group)
for action_name, _ in pairs(defines.input_action) do
permission_group.set_allows_action(defines.input_action[action_name], true)
end
end
local function disable_blueprints(permission_group)
local defs = {
defines.input_action.alt_select_blueprint_entities,
defines.input_action.cancel_new_blueprint,
defines.input_action.change_blueprint_record_label,
defines.input_action.clear_selected_blueprint,
defines.input_action.create_blueprint_like,
defines.input_action.cycle_blueprint_backwards,
defines.input_action.cycle_blueprint_forwards,
defines.input_action.delete_blueprint_library,
defines.input_action.delete_blueprint_record,
defines.input_action.drop_blueprint_record,
defines.input_action.drop_to_blueprint_book,
defines.input_action.export_blueprint,
defines.input_action.grab_blueprint_record,
defines.input_action.import_blueprint,
defines.input_action.import_blueprint_string,
defines.input_action.open_blueprint_library_gui,
defines.input_action.open_blueprint_record,
defines.input_action.select_blueprint_entities,
defines.input_action.setup_blueprint,
defines.input_action.setup_single_blueprint_record,
defines.input_action.upgrade_open_blueprint,
defines.input_action.deconstruct,
defines.input_action.clear_selected_deconstruction_item,
defines.input_action.cancel_deconstruct,
defines.input_action.toggle_deconstruction_item_entity_filter_mode,
defines.input_action.toggle_deconstruction_item_tile_filter_mode,
defines.input_action.set_deconstruction_item_tile_selection_mode,
defines.input_action.set_deconstruction_item_trees_and_rocks_only,
}
for _, d in pairs(defs) do permission_group.set_allows_action(d, false) end
end
local function enable_artillery(force, permission_group)
permission_group.set_allows_action(defines.input_action.use_artillery_remote, true)
force.technologies["artillery"].enabled = true
force.technologies["artillery-shell-range-1"].enabled = false
force.technologies["artillery-shell-speed-1"].enabled = false
force.recipes["artillery-turret"].enabled = true
force.recipes["artillery-wagon"].enabled = true
force.recipes["artillery-targeting-remote"].enabled = true
force.recipes["artillery-shell"].enabled = true
end
local function disable_artillery(force, permission_group)
permission_group.set_allows_action(defines.input_action.use_artillery_remote, false)
force.technologies["artillery"].enabled = false
force.technologies["artillery-shell-range-1"].enabled = false
force.technologies["artillery-shell-speed-1"].enabled = false
force.recipes["artillery-turret"].enabled = false
force.recipes["artillery-wagon"].enabled = false
force.recipes["artillery-targeting-remote"].enabled = false
force.recipes["artillery-shell"].enabled = false
end
local function disable_spidertron(force, permission_group)
permission_group.set_allows_action(defines.input_action.send_spidertron, false)
force.technologies["spidertron"].enabled = false
force.recipes["spidertron"].enabled = false
force.recipes["spidertron-remote"].enabled = false
end
local function disable_rockets(force)
force.technologies["rocketry"].enabled = false
force.technologies["explosive-rocketry"].enabled = false
force.recipes["rocket-launcher"].enabled = false
force.recipes["rocket"].enabled = false
force.recipes["explosive-rocket"].enabled = false
end
local function disable_nukes(force)
force.technologies["atomic-bomb"].enabled = false
force.recipes["atomic-bomb"].enabled = false
end
local function disable_cluster_grenades(force)
force.recipes["cluster-grenade"].enabled = false
end
local function enable_radar(force)
force.recipes["radar"].enabled = true
force.share_chart = true
force.clear_chart("nauvis")
end
local function disable_radar(force)
force.recipes["radar"].enabled = false
force.share_chart = false
force.clear_chart("nauvis")
end
local function disable_achievements(permission_group)
permission_group.set_allows_action(defines.input_action.open_achievements_gui, false)
end
local function disable_tips_and_tricks(permission_group)
permission_group.set_allows_action(defines.input_action.open_tips_and_tricks_gui, false)
end
-- setup a team force
function Public.add_new_force(force_name)
-- disable permissions
local force = game.create_force(force_name)
local permission_group = game.permissions.create_group(force_name)
reset_permissions(permission_group)
disable_blueprints(permission_group)
enable_artillery(force, permission_group)
disable_spidertron(force, permission_group)
disable_rockets(force)
disable_nukes(force)
disable_cluster_grenades(force)
enable_radar(force)
disable_achievements(permission_group)
disable_tips_and_tricks(permission_group)
-- friendly fire
force.friendly_fire = true
-- disable technologies
force.research_queue_enabled = true
-- balance initial combat
force.set_ammo_damage_modifier("landmine", -0.75)
force.set_ammo_damage_modifier("grenade", -0.5)
end
local function kill_force(force_name)
local ffatable = Table.get_table()
local force = game.forces[force_name]
local market = ffatable.town_centers[force_name].market
local surface = market.surface
surface.create_entity({ name = "big-artillery-explosion", position = market.position })
for _, player in pairs(force.players) do
if player.character then
player.character.die()
else
ffatable.requests[player.index] = "kill-character"
end
player.force = game.forces.player
Public.set_player_color(player)
end
for _, e in pairs(surface.find_entities_filtered({ force = force_name })) do
if e.valid then
if e.type == "wall" or e.type == "gate" then
e.die()
end
end
end
game.merge_forces(force_name, "neutral")
ffatable.town_centers[force_name] = nil
ffatable.size_of_town_centers = ffatable.size_of_town_centers - 1
delete_chart_tag_for_all_forces(market)
game.print(">> " .. force_name .. "'s town has fallen! [gps=" .. math.floor(market.position.x) .. "," .. math.floor(market.position.y) .. "]", { 255, 255, 0 })
end
local player_force_disabled_recipes = { "lab", "automation-science-pack", "stone-brick", "radar" }
local player_force_enabled_recipes = { "submachine-gun", "assembling-machine-1", "small-lamp", "shotgun", "shotgun-shell", "underground-belt", "splitter", "steel-plate", "car", "cargo-wagon", "constant-combinator", "engine-unit", "green-wire", "locomotive", "rail", "train-stop", "arithmetic-combinator", "decider-combinator" }
-- setup the player force (this is the default for Outlanders)
local function setup_player_force()
local force = game.forces.player
local permission_group = game.permissions.create_group("outlander")
-- disable permissions
reset_permissions(permission_group)
disable_blueprints(permission_group)
disable_artillery(force, permission_group)
disable_spidertron(force, permission_group)
disable_rockets(force)
disable_nukes(force)
disable_cluster_grenades(force)
disable_radar(force)
disable_achievements(permission_group)
disable_tips_and_tricks(permission_group)
-- disable research
force.disable_research()
force.research_queue_enabled = false
-- friendly fire
force.friendly_fire = true
-- disable recipes
local recipes = force.recipes
for _, recipe_name in pairs(player_force_disabled_recipes) do
recipes[recipe_name].enabled = false
end
for _, recipe_name in pairs(player_force_enabled_recipes) do
recipes[recipe_name].enabled = true
end
force.set_ammo_damage_modifier("landmine", -0.75)
force.set_ammo_damage_modifier("grenade", -0.5)
end
local function setup_rogue_force()
local force_name = "rogue"
local force = game.create_force(force_name)
local permission_group = game.permissions.create_group(force_name)
-- disable permissions
reset_permissions(permission_group)
disable_blueprints(permission_group)
disable_artillery(force, permission_group)
disable_spidertron(force, permission_group)
disable_rockets(force)
disable_nukes(force)
disable_cluster_grenades(force)
disable_radar(force)
disable_achievements(permission_group)
disable_tips_and_tricks(permission_group)
-- disable research
force.disable_research()
force.research_queue_enabled = false
-- friendly fire
force.friendly_fire = true
-- disable recipes
local recipes = force.recipes
for _, recipe_name in pairs(player_force_disabled_recipes) do
recipes[recipe_name].enabled = false
end
for _, recipe_name in pairs(player_force_enabled_recipes) do
recipes[recipe_name].enabled = true
end
force.set_ammo_damage_modifier("landmine", -0.75)
force.set_ammo_damage_modifier("grenade", -0.5)
end
local function setup_enemy_force()
local e_force = game.forces["enemy"]
e_force.evolution_factor = 1 -- this should never change since we are changing biter types on spawn
e_force.set_friend(game.forces.player, true) -- outlander force (player) should not be attacked by turrets
e_force.set_cease_fire(game.forces.player, true) -- outlander force (player) should not be attacked by units
e_force.set_friend(game.forces["rogue"], false) -- rogue force (rogue) should be attacked by turrets
e_force.set_cease_fire(game.forces["rogue"], false) -- rogue force (rogue) should be attacked by units
-- note, these don't prevent an outlander or rogue from attacking a unit or spawner, we need to handle separately
end
local function on_player_dropped_item(event)
local player = game.players[event.player_index]
local entity = event.entity
if entity.stack.name == "raw-fish" then
ally_town(player, entity)
return
end
if entity.stack.name == "coal" then
declare_war(player, entity)
return
end
end
---- when a player dies, reveal their base to everyone
--local function on_player_died(event)
-- local player = game.players[event.player_index]
-- if not player.character then return end
-- if not player.character.valid then return end
-- reveal_entity_to_all(player.character)
--end
local function on_entity_damaged(event)
local entity = event.entity
if not entity.valid then return end
local cause = event.cause
local force = event.force
-- special case to handle enemies attacked by outlanders
if entity.force == game.forces["enemy"] then
if cause ~= nil then
if cause.type == "character" and force == game.forces["player"] then
local player = cause.player
if force == game.forces["player"] then
-- set the force of the player to rogue until they die or create a town
set_player_to_rogue(player)
end
end
-- cars and tanks
if cause.type == "car" or cause.type == "tank" then
local driver = cause.get_driver()
if driver ~= nil and driver.force == game.forces["player"] then
-- set the force of the player to rogue until they die or create a town
set_player_to_rogue(driver)
end
local passenger = cause.get_passenger()
if passenger ~= nil and passenger.force == game.forces["player"] then
-- set the force of the player to rogue until they die or create a town
set_player_to_rogue(passenger)
end
end
-- trains
if cause.type == "locomotive" or cause.type == "cargo-wagon" or cause.type == "fluid-wagon" or cause.type == "artillery-wagon" then
local train = cause.train
for _, passenger in pairs(train.passengers) do
if passenger ~= nil and passenger.force == game.forces["player"] then
set_player_to_rogue(passenger)
end
end
end
-- combat robots
if cause.type == "combat-robot" and force == game.forces["player"] then
local owner = cause.last_user
-- set the force of the player to rogue until they die or create a town
set_player_to_rogue(owner)
end
end
end
end
local function on_entity_died(event)
local entity = event.entity
if entity.name == "market" then
kill_force(entity.force.name)
end
end
local function on_post_entity_died(event)
local prototype = event.prototype.type
if prototype ~= "character" then return end
local entities = game.surfaces[event.surface_index].find_entities_filtered({ position = event.position, radius = 1 })
for _, e in pairs(entities) do
if e.type == "character-corpse" then
Public.remove_key(e)
end
end
end
local function on_console_command(event)
set_town_color(event)
end
local function on_console_chat(event)
local player = game.players[event.player_index]
if string_match(string_lower(event.message), "%[armor%=") then
player.clear_console()
game.print(">> " .. player.name .. " is trying to gain an unfair advantage!")
end
end
function Public.initialize()
setup_player_force()
setup_rogue_force()
setup_enemy_force()
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.key = {}
ffatable.spawn_point = {}
ffatable.requests = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_player_dropped_item, on_player_dropped_item)
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
Event.add(defines.events.on_entity_died, on_entity_died)
Event.add(defines.events.on_post_entity_died, on_post_entity_died)
Event.add(defines.events.on_console_command, on_console_command)
Event.add(defines.events.on_console_chat, on_console_chat)
return Public

View File

@ -0,0 +1,92 @@
-- timer traps -- by mewmew
local table_insert = table.insert
local math_random = math.random
local Table = require 'modules.scrap_towny_ffa.table'
local tick_tacks = { "*tick*", "*tick*", "*tack*", "*tak*", "*tik*", "*tok*" }
local kaboom_weights = {
{ name = "grenade", chance = 7 },
{ name = "cluster-grenade", chance = 1 },
{ name = "destroyer-capsule", chance = 1 },
{ name = "defender-capsule", chance = 4 },
{ name = "distractor-capsule", chance = 3 },
{ name = "poison-capsule", chance = 2 },
{ name = "explosive-uranium-cannon-projectile", chance = 3 },
{ name = "explosive-cannon-projectile", chance = 5 },
}
local kabooms = {}
for _, t in pairs(kaboom_weights) do
for _ = 1, t.chance, 1 do
table_insert(kabooms, t.name)
end
end
local function create_flying_text(surface, position, text)
surface.create_entity({
name = "flying-text",
position = position,
text = text,
color = { r = 0.75, g = 0.75, b = 0.75 }
})
if text == "..." then return end
surface.play_sound({ path = "utility/armor_insert", position = position, volume_modifier = 0.75 })
end
local function create_kaboom(surface, position, name)
local target = position
local speed = 0.5
if name == "defender-capsule" or name == "destroyer-capsule" or name == "distractor-capsule" then
surface.create_entity({
name = "flying-text",
position = position,
text = "(((Sentries Engaging Target)))",
color = { r = 0.8, g = 0.0, b = 0.0 }
})
local nearest_player_unit = surface.find_nearest_enemy({ position = position, max_distance = 128, force = "enemy" })
if nearest_player_unit then target = nearest_player_unit.position end
speed = 0.001
end
surface.create_entity({
name = name,
position = position,
force = "enemy",
target = target,
speed = speed
})
end
local function tick_tack_trap(surface, position)
local ffatable = Table.get_table()
if not surface then return end
if not position then return end
if not position.x then return end
if not position.y then return end
local tick_tack_count = math_random(5, 9)
for t = 60, tick_tack_count * 60, 60 do
if not ffatable.on_tick_schedule[game.tick + t] then ffatable.on_tick_schedule[game.tick + t] = {} end
if t < tick_tack_count * 60 then
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = create_flying_text,
args = { surface, { x = position.x, y = position.y }, tick_tacks[math_random(1, #tick_tacks)] }
}
else
if math_random(1, 10) == 1 then
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = create_flying_text,
args = { surface, { x = position.x, y = position.y }, "..." }
}
else
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = create_kaboom,
args = { surface, { x = position.x, y = position.y }, kabooms[math_random(1, #kabooms)] }
}
end
end
end
end
return tick_tack_trap

View File

@ -0,0 +1,523 @@
local Public = {}
local math_random = math.random
local table_insert = table.insert
local math_floor = math.floor
local table_shuffle = table.shuffle_table
local Table = require 'modules.scrap_towny_ffa.table'
local Team = require "modules.scrap_towny_ffa.team"
local Building = require "modules.scrap_towny_ffa.building"
local town_radius = 27
local radius_between_towns = 160
local ore_amount = 250
local colors = {}
local c1 = 250
local c2 = 210
local c3 = -40
for v = c1, c2, c3 do
table_insert(colors, { 0, 0, v })
end
for v = c1, c2, c3 do
table_insert(colors, { 0, v, 0 })
end
for v = c1, c2, c3 do
table_insert(colors, { v, 0, 0 })
end
for v = c1, c2, c3 do
table_insert(colors, { 0, v, v })
end
for v = c1, c2, c3 do
table_insert(colors, { v, v, 0 })
end
for v = c1, c2, c3 do
table_insert(colors, { v, 0, v })
end
local town_wall_vectors = {}
for x = 2, town_radius, 1 do
table_insert(town_wall_vectors, { x, town_radius })
table_insert(town_wall_vectors, { x * -1, town_radius })
table_insert(town_wall_vectors, { x, town_radius * -1 })
table_insert(town_wall_vectors, { x * -1, town_radius * -1 })
end
for y = 2, town_radius - 1, 1 do
table_insert(town_wall_vectors, { town_radius, y })
table_insert(town_wall_vectors, { town_radius, y * -1 })
table_insert(town_wall_vectors, { town_radius * -1, y })
table_insert(town_wall_vectors, { town_radius * -1, y * -1 })
end
local gate_vectors_horizontal = {}
for x = -1, 1, 1 do
table_insert(gate_vectors_horizontal, { x, town_radius })
table_insert(gate_vectors_horizontal, { x, town_radius * -1 })
end
local gate_vectors_vertical = {}
for y = -1, 1, 1 do
table_insert(gate_vectors_vertical, { town_radius, y })
table_insert(gate_vectors_vertical, { town_radius * -1, y })
end
local resource_vectors = {}
resource_vectors[1] = {}
for x = 7, 24, 1 do
for y = 7, 24, 1 do
table_insert(resource_vectors[1], { x, y })
end
end
resource_vectors[2] = {}
for _, vector in pairs(resource_vectors[1]) do table_insert(resource_vectors[2], { vector[1] * -1, vector[2] }) end
resource_vectors[3] = {}
for _, vector in pairs(resource_vectors[1]) do table_insert(resource_vectors[3], { vector[1] * -1, vector[2] * -1 }) end
resource_vectors[4] = {}
for _, vector in pairs(resource_vectors[1]) do table_insert(resource_vectors[4], { vector[1], vector[2] * -1 }) end
local additional_resource_vectors = {}
additional_resource_vectors[1] = {}
for x = 10, 22, 1 do
for y = -4, 4, 1 do
table_insert(additional_resource_vectors[1], { x, y })
end
end
additional_resource_vectors[2] = {}
for _, vector in pairs(additional_resource_vectors[1]) do table_insert(additional_resource_vectors[2], { vector[1] * -1, vector[2] }) end
additional_resource_vectors[3] = {}
for y = 10, 22, 1 do
for x = -4, 4, 1 do
table_insert(additional_resource_vectors[3], { x, y })
end
end
additional_resource_vectors[4] = {}
for _, vector in pairs(additional_resource_vectors[3]) do table_insert(additional_resource_vectors[4], { vector[1], vector[2] * -1 }) end
local clear_whitelist_types = {
["simple-entity"] = true,
["resource"] = true,
["cliff"] = true,
["tree"] = true,
}
local starter_supplies = {
{ name = "raw-fish", count = 3 },
{ name = "grenade", count = 3 },
{ name = "stone", count = 32 },
{ name = "land-mine", count = 4 },
{ name = "iron-gear-wheel", count = 16 },
{ name = "iron-plate", count = 32 },
{ name = "copper-plate", count = 16 },
{ name = "shotgun", count = 1 },
{ name = "shotgun-shell", count = 8 },
{ name = "firearm-magazine", count = 16 },
{ name = "firearm-magazine", count = 16 },
{ name = "gun-turret", count = 2 },
}
local function count_nearby_ore(surface, position, ore_name)
local count = 0
local r = town_radius + 8
for _, e in pairs(surface.find_entities_filtered({ area = { { position.x - r, position.y - r }, { position.x + r, position.y + r } }, force = "neutral", name = ore_name })) do
count = count + e.amount
end
return count
end
local function draw_town_spawn(player_name)
local ffatable = Table.get_table()
local market = ffatable.town_centers[player_name].market
local position = market.position
local surface = market.surface
local area = { { position.x - (town_radius + 1), position.y - (town_radius + 1) }, { position.x + (town_radius + 1), position.y + (town_radius + 1) } }
-- remove other than cliffs, rocks and ores and trees
for _, e in pairs(surface.find_entities_filtered({ area = area, force = "neutral" })) do
if not clear_whitelist_types[e.type] then
e.destroy()
end
end
-- create walls
for _, vector in pairs(gate_vectors_horizontal) do
local p = { position.x + vector[1], position.y + vector[2] }
--p = surface.find_non_colliding_position("gate", p, 64, 1)
if p then
surface.create_entity({ name = "gate", position = p, force = player_name, direction = 2 })
end
end
for _, vector in pairs(gate_vectors_vertical) do
local p = { position.x + vector[1], position.y + vector[2] }
--p = surface.find_non_colliding_position("gate", p, 64, 1)
if p then
surface.create_entity({ name = "gate", position = p, force = player_name, direction = 0 })
end
end
for _, vector in pairs(town_wall_vectors) do
local p = { position.x + vector[1], position.y + vector[2] }
--p = surface.find_non_colliding_position("stone-wall", p, 64, 1)
if p then
surface.create_entity({ name = "stone-wall", position = p, force = player_name })
end
end
-- ore patches
local ores = { "iron-ore", "copper-ore", "stone", "coal" }
table_shuffle(ores)
for i = 1, 4, 1 do
if count_nearby_ore(surface, position, ores[i]) < 200000 then
for _, vector in pairs(resource_vectors[i]) do
local p = { position.x + vector[1], position.y + vector[2] }
p = surface.find_non_colliding_position(ores[i], p, 64, 1)
if p then
surface.create_entity({ name = ores[i], position = p, amount = ore_amount })
end
end
end
end
-- starter chests
for _, item_stack in pairs(starter_supplies) do
local m1 = -8 + math_random(0, 16)
local m2 = -8 + math_random(0, 16)
local p = { position.x + m1, position.y + m2 }
p = surface.find_non_colliding_position("wooden-chest", p, 64, 1)
if p then
local e = surface.create_entity({ name = "wooden-chest", position = p, force = player_name })
local inventory = e.get_inventory(defines.inventory.chest)
inventory.insert(item_stack)
end
end
local vector_indexes = { 1, 2, 3, 4 }
table_shuffle(vector_indexes)
-- trees
--local tree = "tree-0" .. math_random(1, 9)
--for _, vector in pairs(additional_resource_vectors[vector_indexes[1]]) do
-- if math_random(1, 6) == 1 then
-- local p = {position.x + vector[1], position.y + vector[2]}
-- p = surface.find_non_colliding_position(tree, p, 64, 1)
-- if p then
-- surface.create_entity({name = tree, position = p})
-- end
-- end
--end
--local area = {{position.x - town_radius * 1.5, position.y - town_radius * 1.5}, {position.x + town_radius * 1.5, position.y + town_radius * 1.5}}
-- pond
for _, vector in pairs(additional_resource_vectors[vector_indexes[2]]) do
local x = position.x + vector[1]
local y = position.y + vector[2]
local p = { x = x, y = y }
if surface.get_tile(p).name ~= "out-of-map" then
surface.set_tiles({ { name = "water-green", position = p } })
end
end
-- fish
for _, vector in pairs(additional_resource_vectors[vector_indexes[2]]) do
local x = position.x + vector[1] + 0.5
local y = position.y + vector[2] + 0.5
local p = { x = x, y = y }
if math_random(1, 5) == 1 then
if surface.can_place_entity({ name = "fish", position = p }) then
surface.create_entity({ name = "water-splash", position = p })
surface.create_entity({ name = "fish", position = p })
end
end
end
-- uranium ore
--if count_nearby_ore(surface, position, "uranium-ore") < 100000 then
-- for _, vector in pairs(additional_resource_vectors[vector_indexes[3]]) do
-- local p = {position.x + vector[1], position.y + vector[2]}
-- p = surface.find_non_colliding_position("uranium-ore", p, 64, 1)
-- if p then
-- surface.create_entity({name = "uranium-ore", position = p, amount = ore_amount * 2})
-- end
-- end
--end
-- oil patches
--local vectors = additional_resource_vectors[vector_indexes[4]]
--for _ = 1, 3, 1 do
-- local vector = vectors[math_random(1, #vectors)]
-- local p = {position.x + vector[1], position.y + vector[2]}
-- p = surface.find_non_colliding_position("crude-oil", p, 64, 1)
-- if p then
-- surface.create_entity({name = "crude-oil", position = p, amount = 500000})
-- end
--end
end
local function is_valid_location(surface, position)
local ffatable = Table.get_table()
if not surface.can_place_entity({ name = "market", position = position }) then
surface.create_entity({
name = "flying-text",
position = position,
text = "Position is obstructed - no room for market!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
return false
end
for _, vector in pairs(town_wall_vectors) do
local p = { x = math_floor(position.x + vector[1]), y = math_floor(position.y + vector[2]) }
local tile = surface.get_tile(p.x, p.y)
if tile.name == "out-of-map" then
surface.create_entity({
name = "flying-text",
position = position,
text = "Town would be off-map!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
return false
end
end
if ffatable.size_of_town_centers > 48 then
surface.create_entity({
name = "flying-text",
position = position,
text = "Too many town centers on the map!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
return false
end
if Building.near_town(position, surface, radius_between_towns) then
surface.create_entity({
name = "flying-text",
position = position,
text = "Town location is too close to another town center!",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
return false
end
local area = { { position.x - town_radius, position.y - town_radius }, { position.x + town_radius, position.y + town_radius } }
local count = 0
for _, e in pairs(surface.find_entities_filtered({ area = area })) do
if e.force.name == "enemy" then
count = count + 1
end
end
if count > 1 then
surface.create_entity({
name = "flying-text",
position = position,
text = "I got a bad feeling about this! There are enemies nearby.",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
end
return true
end
function Public.set_market_health(entity, final_damage_amount)
local ffatable = Table.get_table()
local town_center = ffatable.town_centers[entity.force.name]
town_center.health = math_floor(town_center.health - final_damage_amount)
if town_center.health > town_center.max_health then town_center.health = town_center.max_health end
local m = town_center.health / town_center.max_health
entity.health = 150 * m
rendering.set_text(town_center.health_text, "HP: " .. town_center.health .. " / " .. town_center.max_health)
end
function Public.update_coin_balance(force)
local ffatable = Table.get_table()
local town_center = ffatable.town_centers[force.name]
rendering.set_text(town_center.coins_text, "Coins: " .. town_center.coin_balance)
end
local function is_color_used(color, town_centers)
for _, center in pairs(town_centers) do
if center.color then
if center.color.r == color.r and center.color.g == color.g and center.color.b == color.b then return true end
end
end
end
local function get_color()
local ffatable = Table.get_table()
local town_centers = ffatable.town_centers
local c
local shuffle_index = {}
for i = 1, #colors, 1 do shuffle_index[i] = i end
table_shuffle(shuffle_index)
for i = 1, #colors, 1 do
c = { r = colors[shuffle_index[i]][1], g = colors[shuffle_index[i]][2], b = colors[shuffle_index[i]][3], }
if not is_color_used(c, town_centers) then return c end
end
return c
end
local function found_town(event)
local entity = event.created_entity
if entity == nil or not entity.valid then return true end -- cancel, not a valid entity placed
if entity.name ~= "stone-furnace" then return false end -- cancel, player did not place a stone-furnace
local player = game.players[event.player_index]
if player.force ~= game.forces.player and player.force ~= game.forces["rogue"] then return false end -- cancel, player is in a team already
local force_name = tostring(player.name)
if game.forces[force_name] then return end -- cancel, player is mayor of town
if Team.has_key(player) == false then return false end -- cancel, player has already placed a town
local surface = entity.surface
local ffatable = Table.get_table()
if ffatable.cooldowns_town_placement[player.index] then
if game.tick < ffatable.cooldowns_town_placement[player.index] then
surface.create_entity({
name = "flying-text",
position = entity.position,
text = "Town founding is on cooldown for " .. math.ceil((ffatable.cooldowns_town_placement[player.index] - game.tick) / 3600) .. " minutes.",
color = { r = 0.77, g = 0.0, b = 0.0 }
})
player.insert({ name = "stone-furnace", count = 1 })
entity.destroy()
return true
end
end
local position = entity.position
entity.destroy()
if not is_valid_location(surface, position) then
player.insert({ name = "stone-furnace", count = 1 })
return true
end
Team.add_new_force(force_name)
ffatable.town_centers[force_name] = {}
local town_center = ffatable.town_centers[force_name]
town_center.market = surface.create_entity({ name = "market", position = position, force = force_name })
town_center.chunk_position = { math.floor(town_center.market.position.x / 32), math.floor(town_center.market.position.y / 32) }
town_center.max_health = 1000
town_center.coin_balance = 0
town_center.input_buffer = {}
town_center.output_buffer = {}
town_center.health = town_center.max_health
town_center.color = get_color()
town_center.research_counter = 1
town_center.upgrades = {}
town_center.upgrades.mining_prod = 0
town_center.upgrades.laser_turret = {}
town_center.upgrades.laser_turret.slots = 0
town_center.upgrades.laser_turret.locations = {}
town_center.evolution = {}
town_center.evolution.biters = 0
town_center.evolution.spitters = 0
town_center.evolution.worms = 0
town_center.coins_text = rendering.draw_text {
text = "Coins: " .. town_center.coin_balance,
surface = surface,
target = town_center.market,
target_offset = { 0, -2.75 },
color = { 200, 200, 200 },
scale = 1.00,
font = "default-game",
alignment = "center",
scale_with_zoom = false
}
town_center.health_text = rendering.draw_text {
text = "HP: " .. town_center.health .. " / " .. town_center.max_health,
surface = surface,
target = town_center.market,
target_offset = { 0, -3.25 },
color = { 200, 200, 200 },
scale = 1.00,
font = "default-game",
alignment = "center",
scale_with_zoom = false
}
town_center.town_caption = rendering.draw_text {
text = player.name .. "'s Town",
surface = surface,
target = town_center.market,
target_offset = { 0, -4.25 },
color = town_center.color,
scale = 1.30,
font = "default-game",
alignment = "center",
scale_with_zoom = false
}
ffatable.size_of_town_centers = ffatable.size_of_town_centers + 1
draw_town_spawn(force_name)
Team.add_player_to_town(player, town_center)
Team.add_chart_tag(game.forces.player, town_center.market)
local force = player.force
-- set the spawn point
local pos = { x = town_center.market.position.x, y = town_center.market.position.y + 4 }
--log("setting spawn point = {" .. spawn_point.x .. "," .. spawn_point.y .. "}")
force.set_spawn_position(pos, surface)
ffatable.spawn_point[player.name] = pos
ffatable.cooldowns_town_placement[player.index] = game.tick + 3600 * 15
Team.remove_key(player)
game.print(">> " .. player.name .. " has founded a new town!", { 255, 255, 0 })
return true
end
local function on_built_entity(event)
found_town(event)
end
local function on_player_repaired_entity(event)
local entity = event.entity
if entity.name == "market" then
Public.set_market_health(entity, -4)
end
end
--local function on_robot_repaired_entity(event)
-- local entity = event.entity
-- if entity.name == "market" then
-- Public.set_market_health(entity, -4)
-- end
--end
local function on_entity_damaged(event)
local entity = event.entity
if not entity.valid then return end
if entity.name == "market" then
Public.set_market_health(entity, event.final_damage_amount)
end
end
local on_init = function ()
local ffatable = Table.get_table()
ffatable.town_centers = {}
ffatable.size_of_town_centers = 0
ffatable.cooldowns_town_placement = {}
end
local Event = require 'utils.event'
Event.on_init(on_init)
Event.add(defines.events.on_built_entity, on_built_entity)
Event.add(defines.events.on_player_repaired_entity, on_player_repaired_entity)
--Event.add(defines.events.on_robot_repaired_entity, on_robot_repaired_entity)
Event.add(defines.events.on_entity_damaged, on_entity_damaged)
return Public

View File

@ -0,0 +1,176 @@
--Towny balance things by Gerkiz --
local player_ammo_starting_modifiers = {
['artillery-shell'] = -0.75,
['biological'] = -0.5,
['bullet'] = -0.25,
['cannon-shell'] = -0.75,
['capsule'] = -0.5,
['combat-robot-beam'] = -0.5,
['combat-robot-laser'] = -0.5,
['electric'] = -0.5,
['flamethrower'] = -0.75,
['grenade'] = -0.5,
['landmine'] = -0.33,
['laser-turret'] = -0.75,
['melee'] = 2,
['railgun'] = 1,
['rocket'] = -0.75,
['shotgun-shell'] = -0.20
}
local player_gun_speed_modifiers = {
['artillery-shell'] = -0.75,
['biological'] = -0.5,
['bullet'] = -0.55,
['cannon-shell'] = -0.75,
['capsule'] = -0.5,
['combat-robot-beam'] = -0.5,
['combat-robot-laser'] = -0.5,
['electric'] = -0.5,
['flamethrower'] = -0.75,
['grenade'] = -0.5,
['landmine'] = -0.33,
['laser-turret'] = -0.75,
['melee'] = 1,
['railgun'] = 0,
['rocket'] = -0.75,
['shotgun-shell'] = -0.50
}
local player_ammo_research_modifiers = {
['artillery-shell'] = -0.75,
['biological'] = -0.5,
['bullet'] = -0.5,
['cannon-shell'] = -0.85,
['capsule'] = -0.5,
['combat-robot-beam'] = -0.5,
['combat-robot-laser'] = -0.5,
['electric'] = -0.6,
['flamethrower'] = -0.75,
['grenade'] = -0.5,
['landmine'] = -0.5,
['laser-turret'] = -0.75,
['melee'] = -0.5,
['railgun'] = -0.5,
['rocket'] = -0.5,
['shotgun-shell'] = -0.20
}
local player_turrets_research_modifiers = {
['gun-turret'] = -0.75,
['laser-turret'] = -0.75,
['flamethrower-turret'] = -0.75
}
local enemy_ammo_starting_modifiers = {
['artillery-shell'] = 0,
['biological'] = 0,
['bullet'] = 0,
['cannon-shell'] = 0,
['capsule'] = 0,
['combat-robot-beam'] = 0,
['combat-robot-laser'] = 0,
['electric'] = 0,
['flamethrower'] = 0,
['grenade'] = 0,
['landmine'] = 0,
['laser-turret'] = 0,
['melee'] = 0,
['railgun'] = 0,
['rocket'] = 0,
['shotgun-shell'] = 0
}
local enemy_ammo_evolution_modifiers = {
['artillery-shell'] = 1,
['biological'] = 2,
['bullet'] = 1,
--['cannon-shell'] = 1,
--['capsule'] = 1,
--['combat-robot-beam'] = 1,
--['combat-robot-laser'] = 1,
--['electric'] = 1,
['flamethrower'] = 2,
--['grenade'] = 1,
--['landmine'] = 1,
['laser-turret'] = 2,
['melee'] = 2
--['railgun'] = 1,
--['rocket'] = 1,
--['shotgun-shell'] = 1
}
function init_player_weapon_damage(force)
for k, v in pairs(player_ammo_starting_modifiers) do
force.set_ammo_damage_modifier(k, v)
end
for k, v in pairs(player_gun_speed_modifiers) do
force.set_gun_speed_modifier(k, v)
end
end
function init_enemy_weapon_damage()
local e_force = game.forces["enemy"]
for k, v in pairs(enemy_ammo_starting_modifiers) do
e_force.set_ammo_damage_modifier(k, v)
end
end
local function enemy_weapon_damage()
local f = game.forces.enemy
local ef = f.evolution_factor
for k, v in pairs(enemy_ammo_evolution_modifiers) do
local base = enemy_ammo_starting_modifiers[k]
local new = base + v * ef
f.set_ammo_damage_modifier(k, new)
end
end
local function research_finished(event)
local r = event.research
local p_force = r.force
for _, e in ipairs(r.effects) do
local t = e.type
if t == 'ammo-damage' then
local category = e.ammo_category
local factor = player_ammo_research_modifiers[category]
if factor then
local current_m = p_force.get_ammo_damage_modifier(category)
local m = e.modifier
p_force.set_ammo_damage_modifier(category, current_m + factor * m)
end
elseif t == 'turret-attack' then
local category = e.turret_id
local factor = player_turrets_research_modifiers[category]
if factor then
local current_m = p_force.get_turret_attack_modifier(category)
local m = e.modifier
p_force.set_turret_attack_modifier(category, current_m + factor * m)
end
elseif t == 'gun-speed' then
local category = e.ammo_category
local factor = player_gun_speed_modifiers[category]
if factor then
local current_m = p_force.get_gun_speed_modifier(category)
local m = e.modifier
p_force.set_gun_speed_modifier(category, current_m + factor * m)
end
end
end
end
local Event = require 'utils.event'
Event.on_init(init_enemy_weapon_damage)
Event.on_nth_tick(18000, enemy_weapon_damage)
Event.add(defines.events.on_research_finished, research_finished)

View File

@ -0,0 +1,37 @@
local math_random = math.random
local Evolution = require "modules.scrap_towny_ffa.evolution"
local Building = require "modules.scrap_towny_ffa.building"
local Scrap = require "modules.scrap_towny_ffa.scrap"
local unearthing_worm = require "modules.scrap_towny_ffa.unearthing_worm"
local unearthing_biters = require "modules.scrap_towny_ffa.unearthing_biters"
local tick_tack_trap = require "modules.scrap_towny_ffa.tick_tack_trap"
local function trap(entity)
-- check if within 32 blocks of market
if entity.type == "tree" or Scrap.is_scrap(entity) then
if math_random(1, 1024) == 1 then
if not Building.near_town(entity.position, entity.surface, 32) then
tick_tack_trap(entity.surface, entity.position)
return
end
end
if math_random(1, 256) == 1 then
if not Building.near_town(entity.position, entity.surface, 32) then
unearthing_worm(entity.surface, entity.position, Evolution.get_worm_evolution(entity))
end
end
if math_random(1, 128) == 1 then
if not Building.near_town(entity.position, entity.surface, 32) then
unearthing_biters(entity.surface, entity.position, math_random(4, 8), Evolution.get_biter_evolution(entity))
end
end
end
end
local function on_player_mined_entity(event)
local entity = event.entity
trap(entity)
end
local Event = require 'utils.event'
Event.add(defines.events.on_player_mined_entity, on_player_mined_entity)

View File

@ -0,0 +1,17 @@
local math_random = math.random
local math_min = math.min
local function on_entity_died(event)
local entity = event.entity
local surface = entity.surface
if entity.type == "ammo-turret" and entity.force.name == "enemy" then
local min = math_min(entity.get_item_count("piercing-rounds-magazine"), 20)
if min > 0 then
surface.spill_item_stack(entity.position, { name = "piercing-rounds-magazine", count = math_random(1, min) }, true)
end
end
end
local Event = require 'utils.event'
Event.add(defines.events.on_entity_died, on_entity_died)

View File

@ -0,0 +1,84 @@
local math_random = math.random
local Table = require 'modules.scrap_towny_ffa.table'
local function create_particles(surface, position, amount)
if not surface.valid then return end
for _ = 1, amount, 1 do
local m = math_random(6, 12)
local m2 = m * 0.005
surface.create_particle({
name = "stone-particle",
position = position,
frame_speed = 0.1,
vertical_speed = 0.1,
height = 0.1,
movement = { m2 - (math_random(0, m) * 0.01), m2 - (math_random(0, m) * 0.01) }
})
end
end
local function spawn_biter(surface, position, evolution)
if not surface.valid then return end
local evo = math.floor(evolution * 1000)
local biter_chances = {
{ name = "small-biter", chance = math.floor(1000 - (evo * 1.6)) },
{ name = "small-spitter", chance = math.floor(500 - evo * 0.8) },
{ name = "medium-biter", chance = -150 + evo },
{ name = "medium-spitter", chance = -75 + math.floor(evo * 0.5) },
{ name = "big-biter", chance = math.floor((evo - 500) * 3) },
{ name = "big-spitter", chance = math.floor((evo - 500) * 2) },
{ name = "behemoth-biter", chance = math.floor((evo - 800) * 6) },
{ name = "behemoth-spitter", chance = math.floor((evo - 800) * 4) }
}
local max_chance = 0
for i = 1, 8, 1 do
if biter_chances[i].chance < 0 then biter_chances[i].chance = 0 end
max_chance = max_chance + biter_chances[i].chance
end
local r = math_random(1, max_chance)
local current_chance = 0
for i = 1, 8, 1 do
current_chance = current_chance + biter_chances[i].chance
if r <= current_chance then
local biter_name = biter_chances[i].name
local p = surface.find_non_colliding_position(biter_name, position, 10, 1)
if not p then return end
surface.create_entity({ name = biter_name, position = p, force = "enemy" })
return
end
end
end
local function unearthing_biters(surface, position, amount, relative_evolution)
local ffatable = Table.get_table()
if not surface then return end
if not position then return end
if not position.x then return end
if not position.y then return end
local ticks = amount * 30
ticks = ticks + 90
for t = 1, ticks, 1 do
if not ffatable.on_tick_schedule[game.tick + t] then ffatable.on_tick_schedule[game.tick + t] = {} end
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = create_particles,
args = { surface, { x = position.x, y = position.y }, 4 }
}
if t > 90 then
if t % 30 == 29 then
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = spawn_biter,
args = { surface, { x = position.x, y = position.y }, relative_evolution }
}
end
end
end
end
return unearthing_biters

View File

@ -0,0 +1,69 @@
local math_random = math.random
local math_ceil = math.ceil
local Table = require 'modules.scrap_towny_ffa.table'
local function create_particles(surface, position, amount)
if not surface.valid then return end
for _ = 1, amount, 1 do
local m = math_random(8, 24)
local m2 = m * 0.005
surface.create_particle({
name = "stone-particle",
position = position,
frame_speed = 0.1,
vertical_speed = 0.1,
height = 0.1,
movement = { m2 - (math_random(0, m) * 0.01), m2 - (math_random(0, m) * 0.01) }
})
end
end
local function spawn_worm(surface, position, evolution_index)
if not surface.valid then return end
local worm_raffle_table = {
[1] = { "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret" },
[2] = { "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "medium-worm-turret" },
[3] = { "small-worm-turret", "small-worm-turret", "small-worm-turret", "small-worm-turret", "medium-worm-turret", "medium-worm-turret" },
[4] = { "small-worm-turret", "small-worm-turret", "small-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret" },
[5] = { "small-worm-turret", "small-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret" },
[6] = { "small-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret" },
[7] = { "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret" },
[8] = { "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret" },
[9] = { "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret", "big-worm-turret" },
[10] = { "medium-worm-turret", "medium-worm-turret", "medium-worm-turret", "big-worm-turret", "big-worm-turret", "big-worm-turret" }
}
local raffle = worm_raffle_table[evolution_index]
local worm_name = raffle[math_random(1, #raffle)]
surface.create_entity({ name = worm_name, position = position })
end
local function unearthing_worm(surface, position, relative_evolution)
local ffatable = Table.get_table()
if not surface then return end
if not position then return end
if not position.x then return end
if not position.y then return end
local evolution_index = math.ceil(relative_evolution * 10)
if evolution_index < 1 then evolution_index = 1 end
for t = 1, 330, 1 do
if not ffatable.on_tick_schedule[game.tick + t] then ffatable.on_tick_schedule[game.tick + t] = {} end
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = create_particles,
args = { surface, { x = position.x, y = position.y }, math_ceil(t * 0.05) }
}
if t == 330 then
ffatable.on_tick_schedule[game.tick + t][#ffatable.on_tick_schedule[game.tick + t] + 1] = {
func = spawn_worm,
args = { surface, { x = position.x, y = position.y }, evolution_index }
}
end
end
end
return unearthing_worm

View File

@ -0,0 +1,159 @@
--wreckage yields scrap
local table_insert = table.insert
local Scrap = require 'modules.scrap_towny_ffa.scrap'
-- loot chances and amounts for scrap entities
local entity_loot_chance = {
{name = "advanced-circuit", chance = 5},
--{name = "artillery-shell", chance = 1},
{name = "battery", chance = 20},
{name = "cannon-shell", chance = 2},
--{name = "cluster-grenade", chance = 2},
{name = "construction-robot", chance = 1},
{name = "copper-cable", chance = 250},
{name = "copper-plate", chance = 500},
{name = "crude-oil-barrel", chance = 30},
{name = "defender-capsule", chance = 5},
{name = "destroyer-capsule", chance = 1},
{name = "distractor-capsule", chance = 2},
{name = "electric-engine-unit", chance = 2},
{name = "electronic-circuit", chance = 200},
{name = "empty-barrel", chance = 10},
{name = "engine-unit", chance = 4},
{name = "explosive-cannon-shell", chance = 2},
--{name = "explosive-rocket", chance = 3},
--{name = "explosive-uranium-cannon-shell", chance = 1},
{name = "explosives", chance = 5},
{name = "green-wire", chance = 10},
{name = "grenade", chance = 10},
{name = "heat-pipe", chance = 1},
{name = "heavy-oil-barrel", chance = 15},
{name = "iron-gear-wheel", chance = 500},
{name = "iron-plate", chance = 750},
{name = "iron-stick", chance = 50},
{name = "land-mine", chance = 3},
{name = "light-oil-barrel", chance = 15},
{name = "logistic-robot", chance = 1},
{name = "low-density-structure", chance = 1},
{name = "lubricant-barrel", chance = 20},
--{name = "nuclear-fuel", chance = 1},
{name = "petroleum-gas-barrel", chance = 15},
{name = "pipe", chance = 100},
{name = "pipe-to-ground", chance = 10},
{name = "plastic-bar", chance = 5},
{name = "processing-unit", chance = 2},
{name = "red-wire", chance = 10},
--{name = "rocket", chance = 3},
--{name = "rocket-control-unit", chance = 1},
--{name = "rocket-fuel", chance = 3},
{name = "solid-fuel", chance = 100},
{name = "steel-plate", chance = 150},
{name = "sulfuric-acid-barrel", chance = 15},
--{name = "uranium-cannon-shell", chance = 1},
--{name = "uranium-fuel-cell", chance = 1},
--{name = "used-up-uranium-fuel-cell", chance = 1},
{name = "water-barrel", chance = 10},
{name = "tank", chance = 1},
{name = "car", chance = 1}
}
local entity_loot_amounts = {
["advanced-circuit"] = 2,
--["artillery-shell"] = 0.3,
["battery"] = 2,
["cannon-shell"] = 2,
--["cluster-grenade"] = 0.3,
["construction-robot"] = 0.3,
["copper-cable"] = 24,
["copper-plate"] = 16,
["crude-oil-barrel"] = 3,
["defender-capsule"] = 2,
["destroyer-capsule"] = 0.3,
["distractor-capsule"] = 0.3,
["electric-engine-unit"] = 2,
["electronic-circuit"] = 8,
["empty-barrel"] = 3,
["engine-unit"] = 2,
["explosive-cannon-shell"] = 2,
--["explosive-rocket"] = 2,
--["explosive-uranium-cannon-shell"] = 2,
["explosives"] = 4,
["green-wire"] = 8,
["grenade"] = 2,
["heat-pipe"] = 1,
["heavy-oil-barrel"] = 3,
["iron-gear-wheel"] = 8,
["iron-plate"] = 16,
["iron-stick"] = 16,
["land-mine"] = 1,
["light-oil-barrel"] = 3,
["logistic-robot"] = 0.3,
["low-density-structure"] = 0.3,
["lubricant-barrel"] = 3,
--["nuclear-fuel"] = 0.1,
["petroleum-gas-barrel"] = 3,
["pipe"] = 8,
["pipe-to-ground"] = 1,
["plastic-bar"] = 4,
["processing-unit"] = 1,
["red-wire"] = 8,
--["rocket"] = 2,
--["rocket-control-unit"] = 0.3,
--["rocket-fuel"] = 0.3,
["solid-fuel"] = 4,
["steel-plate"] = 4,
["sulfuric-acid-barrel"] = 3,
--["uranium-cannon-shell"] = 2,
--["uranium-fuel-cell"] = 0.3,
--["used-up-uranium-fuel-cell"] = 1,
["water-barrel"] = 3,
["tank"] = 1,
["car"] = 1,
}
local scrap_raffle = {}
for _, t in pairs (entity_loot_chance) do
for _ = 1, t.chance, 1 do
table_insert(scrap_raffle, t.name)
end
end
local size_of_scrap_raffle = #scrap_raffle
local function on_player_mined_entity(event)
local entity = event.entity
if not entity.valid then return end
local position = entity.position
if Scrap.is_scrap(entity) == false then return end
if entity.name == 'crash-site-chest-1' or entity.name == 'crash-site-chest-2' then return end
-- scrap entities drop loot
event.buffer.clear()
local scrap = scrap_raffle[math.random(1, size_of_scrap_raffle)]
local amount_bonus = (game.forces.enemy.evolution_factor * 2) + (game.forces.player.mining_drill_productivity_bonus * 2)
local r1 = math.ceil(entity_loot_amounts[scrap] * (0.3 + (amount_bonus * 0.3)))
local r2 = math.ceil(entity_loot_amounts[scrap] * (1.7 + (amount_bonus * 1.7)))
local amount = math.random(r1, r2)
local player = game.players[event.player_index]
local inserted_count = player.insert({name = scrap, count = amount})
if inserted_count ~= amount then
local amount_to_spill = amount - inserted_count
entity.surface.spill_item_stack(position, {name = scrap, count = amount_to_spill}, true)
end
entity.surface.create_entity({
name = "flying-text",
position = position,
text = "+" .. amount .. " [img=item/" .. scrap .. "]",
color = {r=0.98, g=0.66, b=0.22}
})
end
local Event = require 'utils.event'
Event.add(defines.events.on_player_mined_entity, on_player_mined_entity)

View File

@ -0,0 +1,104 @@
local math_random = math.random
local Global = require 'utils.global'
local tick_schedule = {}
Global.register(
tick_schedule,
function(t)
tick_schedule = t
end
)
local death_animation_ticks = 120
local decay_ticks = 2
local worms = {
["small-worm-turret"] = { corpse="small-worm-corpse", patch_size = { min=30000, max=90000} },
["medium-worm-turret"] = { corpse="medium-worm-corpse", patch_size = { min=60000, max=120000 } },
["big-worm-turret"] = { corpse="big-worm-corpse", patch_size = { min=90000, max=300000 } },
["behemoth-worm-turret"] = { corpse="behemoth-worm-corpse", patch_size = { min=120000, max=600000 } }
}
local function destroy_worm(name, position, surface)
local entity = surface.find_entity(name, position)
if entity ~= nil and entity.valid then entity.destroy() end
local corpse = worms[name].corpse
local remains = surface.find_entity(corpse, position)
if remains ~= nil and remains.valid then
-- show an animation
if math_random(1,40) == 1 then surface.create_entity({name = "explosion", position = {x = position.x + (3 - (math_random(1,60) * 0.1)), y = position.y + (3 - (math_random(1,60) * 0.1))}}) end
if math_random(1,32) == 1 then surface.create_entity({name = "blood-explosion-huge", position = position}) end
if math_random(1,16) == 1 then surface.create_entity({name = "blood-explosion-big", position = position}) end
if math_random(1,8) == 1 then surface.create_entity({name = "blood-explosion-small", position = position}) end
end
end
local function remove_corpse(name, position, surface)
local corpse = worms[name].corpse
local remains = surface.find_entity(corpse, position)
if remains ~= nil and remains.valid then remains.destroy() end
end
-- place an oil patch at the worm location
local function create_oil_patch(name, position, surface)
local min = worms[name].patch_size.min
local max = worms[name].patch_size.max
surface.create_entity({name="crude-oil", position=position, amount=math_random(min,max)})
end
-- worms create oil patches when killed
local function process_worm(entity)
local name = entity.name
local position = entity.position
local surface = entity.surface
local tick1 = game.tick + death_animation_ticks
if not tick_schedule[tick1] then tick_schedule[tick1] = {} end
tick_schedule[tick1][#tick_schedule[tick1] + 1] = {
callback = 'destroy_worm',
params = {name, position, surface}
}
local tick2 = game.tick + death_animation_ticks + decay_ticks
if not tick_schedule[tick2] then tick_schedule[tick2] = {} end
tick_schedule[tick2][#tick_schedule[tick2] + 1] = {
callback = 'remove_corpse',
params = {name, position, surface}
}
if math_random(1,4) == 1 then
local tick3 = game.tick + death_animation_ticks + decay_ticks + 1
if not tick_schedule[tick3] then tick_schedule[tick3] = {} end
tick_schedule[tick3][#tick_schedule[tick3] + 1] = {
callback = 'create_oil_patch',
params = {name, position, surface}
}
end
end
local function on_entity_died(event)
local entity = event.entity
local test = {
["small-worm-turret"] = true,
["medium-worm-turret"] = true,
["big-worm-turret"] = true,
["behemoth-worm-turret"] = true
}
if test[entity.name] ~= nil then
process_worm(entity)
end
end
local function on_tick()
if not tick_schedule[game.tick] then return end
for _, token in pairs(tick_schedule[game.tick]) do
local callback = token.callback
local params = token.params
if callback == 'destroy_worm' then destroy_worm(params[1], params[2], params[3]) end
if callback == 'remove_corpse' then remove_corpse(params[1], params[2], params[3]) end
if callback == 'create_oil_patch' then create_oil_patch(params[1], params[2], params[3]) end
end
tick_schedule[game.tick] = nil
end
local Event = require 'utils.event'
Event.add(defines.events.on_tick, on_tick)
Event.add(defines.events.on_entity_died, on_entity_died)

View File

@ -0,0 +1,330 @@
local table_insert = table.insert
local math_random = math.random
local math_floor = math.floor
local math_abs = math.abs
local get_noise = require 'utils.get_noise'
local Scrap = require 'modules.scrap_towny_ffa.scrap'
require 'modules.no_deconstruction_of_neutral_entities'
local scrap_entities = {
-- simple entity
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "small-ship-wreck"}, -- these are not mineable normally
{name = "medium-ship-wreck"}, -- these are not mineable normally
{name = "medium-ship-wreck"}, -- these are not mineable normally
{name = "medium-ship-wreck"}, -- these are not mineable normally
{name = "medium-ship-wreck"}, -- these are not mineable normally
-- simple entity with owner
{name = "crash-site-spaceship-wreck-small-1"}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-small-1"}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-small-2"}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-small-3"}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-small-4"}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-small-5"}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-small-6"} -- these do not have mining animation
}
local scrap_entities_index = table.size(scrap_entities)
local scrap_containers = {
-- containers
{name = "big-ship-wreck-1", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-1", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-1", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-2", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-2", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-2", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-3", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-3", size = 3}, -- these are not mineable normally
{name = "big-ship-wreck-3", size = 3}, -- these are not mineable normally
{name = "crash-site-chest-1", size = 8}, -- these do not have mining animation
{name = "crash-site-chest-2", size = 8}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-1", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-1", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-1", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-1", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-2", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-2", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-2", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-2", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-3", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-3", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-3", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-medium-3", size = 1}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-big-1", size = 2}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-big-1", size = 2}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-big-1", size = 2}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-big-2", size = 2}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-big-2", size = 2}, -- these do not have mining animation
{name = "crash-site-spaceship-wreck-big-2", size = 2}, -- these do not have mining animation
}
local scrap_containers_index = table.size(scrap_containers)
-- loot chances and amounts for scrap containers
local container_loot_chance = {
{name = "advanced-circuit", chance = 5},
{name = "artillery-shell", chance = 1},
{name = "cannon-shell", chance = 2},
{name = "cliff-explosives", chance = 5},
--{name = "cluster-grenade", chance = 2},
{name = "construction-robot", chance = 1},
{name = "copper-cable", chance = 250},
{name = "copper-plate", chance = 500},
{name = "crude-oil-barrel", chance = 30},
{name = "defender-capsule", chance = 5},
{name = "destroyer-capsule", chance = 1},
{name = "distractor-capsule", chance = 2},
{name = "electric-engine-unit", chance = 2},
{name = "electronic-circuit", chance = 200},
{name = "empty-barrel", chance = 10},
{name = "engine-unit", chance = 7},
{name = "explosive-cannon-shell", chance = 2},
--{name = "explosive-rocket", chance = 3},
{name = "explosive-uranium-cannon-shell", chance = 1},
{name = "explosives", chance = 5},
{name = "green-wire", chance = 10},
{name = "grenade", chance = 10},
{name = "heat-pipe", chance = 1},
{name = "heavy-oil-barrel", chance = 15},
{name = "iron-gear-wheel", chance = 500},
{name = "iron-plate", chance = 750},
{name = "iron-stick", chance = 50},
{name = "land-mine", chance = 3},
{name = "light-oil-barrel", chance = 15},
{name = "logistic-robot", chance = 1},
{name = "low-density-structure", chance = 1},
{name = "lubricant-barrel", chance = 20},
{name = "nuclear-fuel", chance = 1},
{name = "petroleum-gas-barrel", chance = 15},
{name = "pipe", chance = 100},
{name = "pipe-to-ground", chance = 10},
{name = "plastic-bar", chance = 5},
{name = "processing-unit", chance = 2},
{name = "red-wire", chance = 10},
--{name = "rocket", chance = 3}, {name = "battery", chance = 20},
{name = "rocket-control-unit", chance = 1},
{name = "rocket-fuel", chance = 3},
{name = "solid-fuel", chance = 100},
{name = "steel-plate", chance = 150},
{name = "sulfuric-acid-barrel", chance = 15},
{name = "uranium-cannon-shell", chance = 1},
{name = "uranium-fuel-cell", chance = 1},
{name = "used-up-uranium-fuel-cell", chance = 1},
{name = "water-barrel", chance = 10}
}
local container_loot_amounts = {
["advanced-circuit"] = 2,
["artillery-shell"] = 0.3,
["battery"] = 2,
["cannon-shell"] = 2,
["cliff-explosives"] = 2,
--["cluster-grenade"] = 0.3,
["construction-robot"] = 0.3,
["copper-cable"] = 24,
["copper-plate"] = 16,
["crude-oil-barrel"] = 3,
["defender-capsule"] = 2,
["destroyer-capsule"] = 0.3,
["distractor-capsule"] = 0.3,
["electric-engine-unit"] = 2,
["electronic-circuit"] = 8,
["empty-barrel"] = 3,
["engine-unit"] = 2,
["explosive-cannon-shell"] = 2,
--["explosive-rocket"] = 2,
["explosive-uranium-cannon-shell"] = 2,
["explosives"] = 4,
["green-wire"] = 8,
["grenade"] = 2,
["heat-pipe"] = 1,
["heavy-oil-barrel"] = 3,
["iron-gear-wheel"] = 8,
["iron-plate"] = 16,
["iron-stick"] = 16,
["land-mine"] = 1,
["light-oil-barrel"] = 3,
["logistic-robot"] = 0.3,
["low-density-structure"] = 0.3,
["lubricant-barrel"] = 3,
["nuclear-fuel"] = 0.1,
["petroleum-gas-barrel"] = 3,
["pipe"] = 8,
["pipe-to-ground"] = 1,
["plastic-bar"] = 4,
["processing-unit"] = 1,
["red-wire"] = 8,
--["rocket"] = 2,
["rocket-control-unit"] = 0.3,
["rocket-fuel"] = 0.3,
["solid-fuel"] = 4,
["steel-plate"] = 4,
["sulfuric-acid-barrel"] = 3,
["uranium-cannon-shell"] = 2,
["uranium-fuel-cell"] = 0.3,
["used-up-uranium-fuel-cell"] = 1,
["water-barrel"] = 3
}
local scrap_raffle = {}
for _, t in pairs(container_loot_chance) do
for _ = 1, t.chance, 1 do
table_insert(scrap_raffle, t.name)
end
end
local size_of_scrap_raffle = #scrap_raffle
local function place_scrap(surface, position)
-- place turrets
if math_random(1, 700) == 1 then
if position.x ^ 2 + position.x ^ 2 > 4096 then
local e = surface.create_entity({name = "gun-turret", position = position, force = "enemy"})
e.minable = false
e.operable = false
e.insert({name = "piercing-rounds-magazine", count = 100})
return
end
end
-- place spaceship with loot
if math_random(1, 8192) == 1 then
local e = surface.create_entity({name = 'crash-site-spaceship', position = position, force = "neutral"})
e.minable = true
local i = e.get_inventory(defines.inventory.chest)
if i then
for _ = 1, math_random(1, 5), 1 do
local loot = scrap_raffle[math_random(1, size_of_scrap_raffle)]
local amount = container_loot_amounts[loot]
local count = math_floor(amount * math_random(5, 35) * 0.1) + 1
i.insert({name = loot, count = count})
end
end
return
end
-- place scrap containers with loot
if math_random(1, 128) == 1 then
local scrap = scrap_containers[math_random(1, scrap_containers_index)]
local e = surface.create_entity({name = scrap.name, position = position, force = "neutral"})
e.minable = true
local i = e.get_inventory(defines.inventory.chest)
if i then
local size = scrap.size
for _ = 1, math_random(1, size), 1 do
local loot = scrap_raffle[math_random(1, size_of_scrap_raffle)]
local amount = container_loot_amounts[loot]
local count = math_floor(amount * math_random(5, 35) * 0.1) + 1
i.insert({name = loot, count = count})
end
end
return
end
-- place scrap entities with loot
local scrap = scrap_entities[math_random(1, scrap_entities_index)]
local e = surface.create_entity({name = scrap.name, position = position, force = "neutral"})
e.minable = true
end
local function is_scrap_area(n)
if n > 0.5 then return true end
if n < -0.5 then return true end
end
local function move_away_biteys(surface, area)
for _, e in pairs(surface.find_entities_filtered({type = {"unit-spawner", "turret", "unit"}, area = area})) do
local position = surface.find_non_colliding_position(e.name, e.position, 96, 4)
if position then
surface.create_entity({name = e.name, position = position, force = "enemy"})
e.destroy()
end
end
end
local vectors = {{0,0}, {1,0}, {-1,0}, {0,1}, {0,-1}}
local function landfill_under(entity)
-- landfill the area under the entity
local surface = entity.surface
for _, v in pairs(vectors) do
local position = {entity.position.x + v[1], entity.position.y + v[2]}
if not surface.get_tile(position).collides_with("resource-layer") then
surface.set_tiles({{name = "landfill", position = position}}, true)
end
end
end
local function on_player_mined_entity(event)
local entity = event.entity
if not entity.valid then return end
if Scrap.is_scrap(entity) then landfill_under(entity) end
end
local function on_entity_died(event)
local entity = event.entity
if not entity.valid then return end
if Scrap.is_scrap(entity) then landfill_under(entity) end
end
--local function on_init(event)
--
--end
local function on_chunk_generated(event)
--log("scrap_towny_ffa::on_chunk_generated")
local surface = event.surface
local seed = surface.map_gen_settings.seed
local left_top_x = event.area.left_top.x
local left_top_y = event.area.left_top.y
--log(" chunk = {" .. left_top_x/32 .. ", " .. left_top_y/32 .. "}")
local position
local noise
for x = 0, 31, 1 do
for y = 0, 31, 1 do
if math_random(1, 3) > 1 then
position = {x = left_top_x + x, y = left_top_y + y}
if not surface.get_tile(position).collides_with("resource-layer") then
noise = get_noise("scrap_towny_ffa", position, seed)
if is_scrap_area(noise) then
surface.set_tiles({{name = "dirt-" .. math_floor(math_abs(noise) * 6) % 6 + 2, position = position}}, true)
place_scrap(surface, position)
end
end
end
end
end
move_away_biteys(surface, event.area)
--ffatable.chunk_generated[key] = true
end
local function on_chunk_charted(event)
local force = event.force
local surface = game.surfaces[event.surface_index]
if force.valid then
if force == game.forces["player"] or force == game.forces["rogue"] then
force.clear_chart(surface)
end
end
end
-- local on_init = function ()
-- local ffatable = Table.get_table()
-- ffatable.chunk_generated = {}
-- end
local Event = require 'utils.event'
-- Event.on_init(on_init)
Event.add(defines.events.on_chunk_generated, on_chunk_generated)
Event.add(defines.events.on_chunk_charted, on_chunk_charted)
Event.add(defines.events.on_player_mined_entity, on_player_mined_entity)
Event.add(defines.events.on_entity_died, on_entity_died)